1pub const NODE_HTTP_JS: &str = r#"
10import EventEmitter from "node:events";
11
12// ─── STATUS_CODES ────────────────────────────────────────────────────────────
13
14const STATUS_CODES = {
15 200: 'OK', 201: 'Created', 204: 'No Content',
16 301: 'Moved Permanently', 302: 'Found', 304: 'Not Modified',
17 400: 'Bad Request', 401: 'Unauthorized', 403: 'Forbidden',
18 404: 'Not Found', 405: 'Method Not Allowed', 408: 'Request Timeout',
19 500: 'Internal Server Error', 502: 'Bad Gateway', 503: 'Service Unavailable',
20};
21
22const METHODS = [
23 'GET', 'HEAD', 'POST', 'PUT', 'DELETE', 'CONNECT',
24 'OPTIONS', 'TRACE', 'PATCH',
25];
26
27// ─── IncomingMessage ─────────────────────────────────────────────────────────
28
29class IncomingMessage extends EventEmitter {
30 constructor(statusCode, headers, body) {
31 super();
32 this.statusCode = statusCode;
33 this.statusMessage = STATUS_CODES[statusCode] || 'Unknown';
34 this.headers = headers || {};
35 this._body = body || '';
36 this.complete = false;
37 this.httpVersion = '1.1';
38 this.method = null;
39 this.url = '';
40 }
41
42 _deliver() {
43 if (this._body && this._body.length > 0) {
44 this.emit('data', this._body);
45 }
46 this.complete = true;
47 this.emit('end');
48 }
49
50 setEncoding(_encoding) { return this; }
51 resume() { return this; }
52 pause() { return this; }
53 destroy() { this.emit('close'); }
54}
55
56// ─── ClientRequest ───────────────────────────────────────────────────────────
57
58class ClientRequest extends EventEmitter {
59 constructor(options, callback) {
60 super();
61 this._options = options;
62 this._body = [];
63 this._ended = false;
64 this._aborted = false;
65 this.socket = { remoteAddress: '127.0.0.1', remotePort: 0 };
66 this.method = options.method || 'GET';
67 this.path = options.path || '/';
68
69 if (typeof callback === 'function') {
70 this.once('response', callback);
71 }
72 }
73
74 write(chunk) {
75 if (!this._ended && !this._aborted) {
76 this._body.push(typeof chunk === 'string' ? chunk : String(chunk));
77 }
78 return true;
79 }
80
81 end(chunk, _encoding, callback) {
82 if (typeof chunk === 'function') { callback = chunk; chunk = undefined; }
83 if (typeof _encoding === 'function') { callback = _encoding; }
84 if (chunk) this.write(chunk);
85 if (typeof callback === 'function') this.once('finish', callback);
86
87 this._ended = true;
88 this._send();
89 return this;
90 }
91
92 abort() {
93 this._aborted = true;
94 this.emit('abort');
95 this.destroy();
96 }
97
98 destroy(error) {
99 this._aborted = true;
100 if (error) this.emit('error', error);
101 this.emit('close');
102 return this;
103 }
104
105 setTimeout(ms, callback) {
106 if (typeof callback === 'function') this.once('timeout', callback);
107 this._timeoutMs = ms;
108 return this;
109 }
110
111 setNoDelay() { return this; }
112 setSocketKeepAlive() { return this; }
113 flushHeaders() {}
114 getHeader(_name) { return undefined; }
115 setHeader(_name, _value) { return this; }
116 removeHeader(_name) {}
117
118 _send() {
119 const opts = this._options;
120 const protocol = opts.protocol || 'http:';
121 const hostname = opts.hostname || opts.host || 'localhost';
122 const port = opts.port ? `:${opts.port}` : '';
123 const path = opts.path || '/';
124 const url = `${protocol}//${hostname}${port}${path}`;
125
126 const headers = {};
127 if (opts.headers) {
128 for (const [k, v] of Object.entries(opts.headers)) {
129 headers[k.toLowerCase()] = String(v);
130 }
131 }
132
133 const body = this._body.length > 0 ? this._body.join('') : undefined;
134 const method = (opts.method || 'GET').toUpperCase();
135
136 const request = { url, method, headers };
137 if (body) request.body = body;
138 if (this._timeoutMs) request.timeout = this._timeoutMs;
139
140 // Use pi.http() hostcall if available
141 if (typeof globalThis.pi === 'object' && typeof globalThis.pi.http === 'function') {
142 try {
143 const promise = globalThis.pi.http(request);
144 if (promise && typeof promise.then === 'function') {
145 promise.then(
146 (result) => this._handleResponse(result),
147 (err) => this.emit('error', typeof err === 'string' ? new Error(err) : err)
148 );
149 } else {
150 this._handleResponse(promise);
151 }
152 } catch (err) {
153 this.emit('error', err);
154 }
155 } else {
156 // No pi.http available — emit error
157 this.emit('error', new Error('HTTP requests require pi.http() hostcall'));
158 }
159
160 this.emit('finish');
161 }
162
163 _handleResponse(result) {
164 if (!result || typeof result !== 'object') {
165 this.emit('error', new Error('Invalid HTTP response from hostcall'));
166 return;
167 }
168
169 const statusCode = result.status || result.statusCode || 200;
170 const headers = result.headers || {};
171 const body = result.body || result.data || '';
172
173 const res = new IncomingMessage(statusCode, headers, body);
174 this.emit('response', res);
175 // Deliver body asynchronously (in next microtask)
176 Promise.resolve().then(() => res._deliver());
177 }
178}
179
180// ─── Module API ──────────────────────────────────────────────────────────────
181
182function _parseOptions(input, options) {
183 if (typeof input === 'string') {
184 try {
185 const url = new URL(input);
186 return {
187 protocol: url.protocol,
188 hostname: url.hostname,
189 port: url.port || undefined,
190 path: url.pathname + url.search,
191 ...(options || {}),
192 };
193 } catch (_e) {
194 return { path: input, ...(options || {}) };
195 }
196 }
197 if (input && typeof input === 'object' && !(input instanceof URL)) {
198 return input;
199 }
200 if (input instanceof URL) {
201 return {
202 protocol: input.protocol,
203 hostname: input.hostname,
204 port: input.port || undefined,
205 path: input.pathname + input.search,
206 ...(options || {}),
207 };
208 }
209 return options || {};
210}
211
212export function request(input, optionsOrCallback, callback) {
213 let options;
214 if (typeof optionsOrCallback === 'function') {
215 callback = optionsOrCallback;
216 options = _parseOptions(input);
217 } else {
218 options = _parseOptions(input, optionsOrCallback);
219 }
220 if (!options.protocol) options.protocol = 'http:';
221 return new ClientRequest(options, callback);
222}
223
224export function get(input, optionsOrCallback, callback) {
225 const req = request(input, optionsOrCallback, callback);
226 req.end();
227 return req;
228}
229
230export function createServer() {
231 throw new Error('node:http.createServer is not available in PiJS');
232}
233
234export { STATUS_CODES, METHODS, IncomingMessage, ClientRequest };
235export default { request, get, createServer, STATUS_CODES, METHODS, IncomingMessage, ClientRequest };
236"#;
237
238pub const NODE_HTTPS_JS: &str = r#"
240import EventEmitter from "node:events";
241import * as http from "node:http";
242
243export function request(input, optionsOrCallback, callback) {
244 let options;
245 if (typeof optionsOrCallback === 'function') {
246 callback = optionsOrCallback;
247 options = typeof input === 'string' || input instanceof URL
248 ? { ...(typeof input === 'string' ? (() => { try { const u = new URL(input); return { protocol: u.protocol, hostname: u.hostname, port: u.port, path: u.pathname + u.search }; } catch(_) { return { path: input }; } })() : { protocol: input.protocol, hostname: input.hostname, port: input.port, path: input.pathname + input.search }) }
249 : (input || {});
250 } else {
251 options = typeof input === 'string' || input instanceof URL
252 ? { ...(typeof input === 'string' ? (() => { try { const u = new URL(input); return { protocol: u.protocol, hostname: u.hostname, port: u.port, path: u.pathname + u.search }; } catch(_) { return { path: input }; } })() : { protocol: input.protocol, hostname: input.hostname, port: input.port, path: input.pathname + input.search }), ...(optionsOrCallback || {}) }
253 : { ...(input || {}), ...(optionsOrCallback || {}) };
254 }
255 if (!options.protocol) options.protocol = 'https:';
256 return http.request(options, callback);
257}
258
259export function get(input, optionsOrCallback, callback) {
260 const req = request(input, optionsOrCallback, callback);
261 req.end();
262 return req;
263}
264
265export function createServer() {
266 throw new Error('node:https.createServer is not available in PiJS');
267}
268
269export const globalAgent = {};
270
271export default { request, get, createServer, globalAgent };
272"#;