secure-exec 0.0.1 → 0.1.0-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +191 -0
- package/README.md +7 -0
- package/dist/bridge/active-handles.d.ts +21 -0
- package/dist/bridge/active-handles.js +60 -0
- package/dist/bridge/child-process.d.ts +87 -0
- package/dist/bridge/child-process.js +523 -0
- package/dist/bridge/fs.d.ts +227 -0
- package/dist/bridge/fs.js +1572 -0
- package/dist/bridge/index.d.ts +10 -0
- package/dist/bridge/index.js +41 -0
- package/dist/bridge/module.d.ts +73 -0
- package/dist/bridge/module.js +329 -0
- package/dist/bridge/network.d.ts +208 -0
- package/dist/bridge/network.js +1117 -0
- package/dist/bridge/os.d.ts +13 -0
- package/dist/bridge/os.js +257 -0
- package/dist/bridge/polyfills.d.ts +2 -0
- package/dist/bridge/polyfills.js +12 -0
- package/dist/bridge/process.d.ts +64 -0
- package/dist/bridge/process.js +916 -0
- package/dist/bridge-loader.d.ts +1 -0
- package/dist/bridge-loader.js +2 -0
- package/dist/bridge-setup.d.ts +1 -0
- package/dist/bridge-setup.js +2 -0
- package/dist/bridge.js +10586 -0
- package/dist/browser/driver.d.ts +42 -0
- package/dist/browser/driver.js +263 -0
- package/dist/browser/index.d.ts +5 -0
- package/dist/browser/index.js +4 -0
- package/dist/browser/worker.d.ts +1 -0
- package/dist/browser/worker.js +3 -0
- package/dist/browser-runtime.d.ts +6 -0
- package/dist/browser-runtime.js +4 -0
- package/dist/esm-compiler.d.ts +1 -0
- package/dist/esm-compiler.js +2 -0
- package/dist/execution.d.ts +1 -0
- package/dist/execution.js +2 -0
- package/dist/fs-helpers.d.ts +2 -0
- package/dist/fs-helpers.js +1 -0
- package/dist/generated/isolate-runtime.d.ts +19 -0
- package/dist/generated/isolate-runtime.js +21 -0
- package/dist/generated/polyfills.d.ts +82 -0
- package/dist/generated/polyfills.js +82 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.js +11 -0
- package/dist/isolate-runtime/apply-custom-global-policy.js +54 -0
- package/dist/isolate-runtime/apply-timing-mitigation-freeze.js +44 -0
- package/dist/isolate-runtime/apply-timing-mitigation-off.js +14 -0
- package/dist/isolate-runtime/bridge-attach.js +29 -0
- package/dist/isolate-runtime/bridge-initial-globals.js +78 -0
- package/dist/isolate-runtime/eval-script-result.js +8 -0
- package/dist/isolate-runtime/global-exposure-helpers.js +36 -0
- package/dist/isolate-runtime/init-commonjs-module-globals.js +28 -0
- package/dist/isolate-runtime/override-process-cwd.js +8 -0
- package/dist/isolate-runtime/override-process-env.js +8 -0
- package/dist/isolate-runtime/require-setup.js +606 -0
- package/dist/isolate-runtime/set-commonjs-file-globals.js +36 -0
- package/dist/isolate-runtime/set-stdin-data.js +10 -0
- package/dist/isolate-runtime/setup-dynamic-import.js +64 -0
- package/dist/isolate-runtime/setup-fs-facade.js +40 -0
- package/dist/isolate.d.ts +1 -0
- package/dist/isolate.js +2 -0
- package/dist/module-resolver.d.ts +1 -0
- package/dist/module-resolver.js +2 -0
- package/dist/node/bridge-setup.d.ts +1 -0
- package/dist/node/bridge-setup.js +2 -0
- package/dist/node/driver.d.ts +2 -0
- package/dist/node/driver.js +2 -0
- package/dist/node/esm-compiler.d.ts +1 -0
- package/dist/node/esm-compiler.js +2 -0
- package/dist/node/execution-driver.d.ts +2 -0
- package/dist/node/execution-driver.js +2 -0
- package/dist/node/execution-lifecycle.d.ts +1 -0
- package/dist/node/execution-lifecycle.js +2 -0
- package/dist/node/isolate-bootstrap.d.ts +2 -0
- package/dist/node/isolate-bootstrap.js +1 -0
- package/dist/node/module-access.d.ts +2 -0
- package/dist/node/module-access.js +2 -0
- package/dist/node/module-resolver.d.ts +1 -0
- package/dist/node/module-resolver.js +2 -0
- package/dist/package-bundler.d.ts +2 -0
- package/dist/package-bundler.js +1 -0
- package/dist/polyfills.d.ts +1 -0
- package/dist/polyfills.js +2 -0
- package/dist/python-runtime.d.ts +2 -0
- package/dist/python-runtime.js +2 -0
- package/dist/runtime-driver.d.ts +1 -0
- package/dist/runtime-driver.js +1 -0
- package/dist/runtime.d.ts +2 -0
- package/dist/runtime.js +2 -0
- package/dist/shared/api-types.d.ts +1 -0
- package/dist/shared/api-types.js +1 -0
- package/dist/shared/bridge-contract.d.ts +2 -0
- package/dist/shared/bridge-contract.js +1 -0
- package/dist/shared/console-formatter.d.ts +2 -0
- package/dist/shared/console-formatter.js +1 -0
- package/dist/shared/errors.d.ts +2 -0
- package/dist/shared/errors.js +1 -0
- package/dist/shared/esm-utils.d.ts +1 -0
- package/dist/shared/esm-utils.js +2 -0
- package/dist/shared/global-exposure.d.ts +2 -0
- package/dist/shared/global-exposure.js +1 -0
- package/dist/shared/in-memory-fs.d.ts +1 -0
- package/dist/shared/in-memory-fs.js +2 -0
- package/dist/shared/permissions.d.ts +1 -0
- package/dist/shared/permissions.js +2 -0
- package/dist/shared/require-setup.d.ts +1 -0
- package/dist/shared/require-setup.js +2 -0
- package/dist/types.d.ts +2 -0
- package/dist/types.js +1 -0
- package/package.json +51 -4
- package/index.js +0 -1
|
@@ -0,0 +1,1117 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
// Network module polyfill for isolated-vm
|
|
3
|
+
// Provides fetch, http, https, and dns module emulation that bridges to host
|
|
4
|
+
import { exposeCustomGlobal } from "../shared/global-exposure.js";
|
|
5
|
+
// Fetch polyfill
|
|
6
|
+
export async function fetch(url, options = {}) {
|
|
7
|
+
if (typeof _networkFetchRaw === 'undefined') {
|
|
8
|
+
console.error('fetch requires NetworkAdapter to be configured');
|
|
9
|
+
throw new Error('fetch requires NetworkAdapter to be configured');
|
|
10
|
+
}
|
|
11
|
+
const optionsJson = JSON.stringify({
|
|
12
|
+
method: options.method || "GET",
|
|
13
|
+
headers: options.headers || {},
|
|
14
|
+
body: options.body || null,
|
|
15
|
+
});
|
|
16
|
+
const responseJson = await _networkFetchRaw.apply(undefined, [String(url), optionsJson], {
|
|
17
|
+
result: { promise: true },
|
|
18
|
+
});
|
|
19
|
+
const response = JSON.parse(responseJson);
|
|
20
|
+
// Create Response-like object
|
|
21
|
+
return {
|
|
22
|
+
ok: response.ok,
|
|
23
|
+
status: response.status,
|
|
24
|
+
statusText: response.statusText,
|
|
25
|
+
headers: new Map(Object.entries(response.headers || {})),
|
|
26
|
+
url: response.url || String(url),
|
|
27
|
+
redirected: response.redirected || false,
|
|
28
|
+
type: "basic",
|
|
29
|
+
async text() {
|
|
30
|
+
return response.body || "";
|
|
31
|
+
},
|
|
32
|
+
async json() {
|
|
33
|
+
return JSON.parse(response.body || "{}");
|
|
34
|
+
},
|
|
35
|
+
async arrayBuffer() {
|
|
36
|
+
// Not fully supported - return empty buffer
|
|
37
|
+
return new ArrayBuffer(0);
|
|
38
|
+
},
|
|
39
|
+
async blob() {
|
|
40
|
+
throw new Error("Blob not supported in sandbox");
|
|
41
|
+
},
|
|
42
|
+
clone() {
|
|
43
|
+
return { ...this };
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
// Headers class
|
|
48
|
+
export class Headers {
|
|
49
|
+
_headers = {};
|
|
50
|
+
constructor(init) {
|
|
51
|
+
if (init && init !== null) {
|
|
52
|
+
if (init instanceof Headers) {
|
|
53
|
+
this._headers = { ...init._headers };
|
|
54
|
+
}
|
|
55
|
+
else if (Array.isArray(init)) {
|
|
56
|
+
init.forEach(([key, value]) => {
|
|
57
|
+
this._headers[key.toLowerCase()] = value;
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
else if (typeof init === "object") {
|
|
61
|
+
Object.entries(init).forEach(([key, value]) => {
|
|
62
|
+
this._headers[key.toLowerCase()] = value;
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
get(name) {
|
|
68
|
+
return this._headers[name.toLowerCase()] || null;
|
|
69
|
+
}
|
|
70
|
+
set(name, value) {
|
|
71
|
+
this._headers[name.toLowerCase()] = value;
|
|
72
|
+
}
|
|
73
|
+
has(name) {
|
|
74
|
+
return name.toLowerCase() in this._headers;
|
|
75
|
+
}
|
|
76
|
+
delete(name) {
|
|
77
|
+
delete this._headers[name.toLowerCase()];
|
|
78
|
+
}
|
|
79
|
+
entries() {
|
|
80
|
+
return Object.entries(this._headers)[Symbol.iterator]();
|
|
81
|
+
}
|
|
82
|
+
[Symbol.iterator]() {
|
|
83
|
+
return this.entries();
|
|
84
|
+
}
|
|
85
|
+
keys() {
|
|
86
|
+
return Object.keys(this._headers)[Symbol.iterator]();
|
|
87
|
+
}
|
|
88
|
+
values() {
|
|
89
|
+
return Object.values(this._headers)[Symbol.iterator]();
|
|
90
|
+
}
|
|
91
|
+
forEach(callback) {
|
|
92
|
+
Object.entries(this._headers).forEach(([k, v]) => callback(v, k, this));
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
// Request class
|
|
96
|
+
export class Request {
|
|
97
|
+
url;
|
|
98
|
+
method;
|
|
99
|
+
headers;
|
|
100
|
+
body;
|
|
101
|
+
mode;
|
|
102
|
+
credentials;
|
|
103
|
+
cache;
|
|
104
|
+
redirect;
|
|
105
|
+
referrer;
|
|
106
|
+
integrity;
|
|
107
|
+
constructor(input, init = {}) {
|
|
108
|
+
this.url = typeof input === "string" ? input : input.url;
|
|
109
|
+
this.method = init.method || (typeof input !== "string" ? input.method : undefined) || "GET";
|
|
110
|
+
this.headers = new Headers(init.headers || (typeof input !== "string" ? input.headers : undefined));
|
|
111
|
+
this.body = init.body || null;
|
|
112
|
+
this.mode = init.mode || "cors";
|
|
113
|
+
this.credentials = init.credentials || "same-origin";
|
|
114
|
+
this.cache = init.cache || "default";
|
|
115
|
+
this.redirect = init.redirect || "follow";
|
|
116
|
+
this.referrer = init.referrer || "about:client";
|
|
117
|
+
this.integrity = init.integrity || "";
|
|
118
|
+
}
|
|
119
|
+
clone() {
|
|
120
|
+
return new Request(this.url, this);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
// Response class
|
|
124
|
+
export class Response {
|
|
125
|
+
_body;
|
|
126
|
+
status;
|
|
127
|
+
statusText;
|
|
128
|
+
headers;
|
|
129
|
+
ok;
|
|
130
|
+
type;
|
|
131
|
+
url;
|
|
132
|
+
redirected;
|
|
133
|
+
constructor(body, init = {}) {
|
|
134
|
+
this._body = body || null;
|
|
135
|
+
this.status = init.status || 200;
|
|
136
|
+
this.statusText = init.statusText || "OK";
|
|
137
|
+
this.headers = new Headers(init.headers);
|
|
138
|
+
this.ok = this.status >= 200 && this.status < 300;
|
|
139
|
+
this.type = "default";
|
|
140
|
+
this.url = "";
|
|
141
|
+
this.redirected = false;
|
|
142
|
+
}
|
|
143
|
+
async text() {
|
|
144
|
+
return String(this._body || "");
|
|
145
|
+
}
|
|
146
|
+
async json() {
|
|
147
|
+
return JSON.parse(this._body || "{}");
|
|
148
|
+
}
|
|
149
|
+
clone() {
|
|
150
|
+
return new Response(this._body, this);
|
|
151
|
+
}
|
|
152
|
+
static error() {
|
|
153
|
+
return new Response(null, { status: 0, statusText: "" });
|
|
154
|
+
}
|
|
155
|
+
static redirect(url, status = 302) {
|
|
156
|
+
return new Response(null, { status, headers: { Location: url } });
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
// DNS module polyfill
|
|
160
|
+
export const dns = {
|
|
161
|
+
lookup(hostname, options, callback) {
|
|
162
|
+
let cb = callback;
|
|
163
|
+
if (typeof options === "function") {
|
|
164
|
+
cb = options;
|
|
165
|
+
}
|
|
166
|
+
_networkDnsLookupRaw
|
|
167
|
+
.apply(undefined, [hostname], { result: { promise: true } })
|
|
168
|
+
.then((resultJson) => {
|
|
169
|
+
const result = JSON.parse(resultJson);
|
|
170
|
+
if (result.error) {
|
|
171
|
+
const err = new Error(result.error);
|
|
172
|
+
err.code = result.code || "ENOTFOUND";
|
|
173
|
+
cb?.(err);
|
|
174
|
+
}
|
|
175
|
+
else {
|
|
176
|
+
cb?.(null, result.address, result.family);
|
|
177
|
+
}
|
|
178
|
+
})
|
|
179
|
+
.catch((err) => {
|
|
180
|
+
cb?.(err);
|
|
181
|
+
});
|
|
182
|
+
},
|
|
183
|
+
resolve(hostname, rrtype, callback) {
|
|
184
|
+
let cb = callback;
|
|
185
|
+
if (typeof rrtype === "function") {
|
|
186
|
+
cb = rrtype;
|
|
187
|
+
}
|
|
188
|
+
// Simplified - just do lookup for A records
|
|
189
|
+
dns.lookup(hostname, (err, address) => {
|
|
190
|
+
if (err) {
|
|
191
|
+
cb?.(err);
|
|
192
|
+
}
|
|
193
|
+
else {
|
|
194
|
+
cb?.(null, address ? [address] : []);
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
},
|
|
198
|
+
resolve4(hostname, callback) {
|
|
199
|
+
dns.resolve(hostname, "A", callback);
|
|
200
|
+
},
|
|
201
|
+
resolve6(hostname, callback) {
|
|
202
|
+
dns.resolve(hostname, "AAAA", callback);
|
|
203
|
+
},
|
|
204
|
+
promises: {
|
|
205
|
+
lookup(hostname, _options) {
|
|
206
|
+
return new Promise((resolve, reject) => {
|
|
207
|
+
dns.lookup(hostname, _options, (err, address, family) => {
|
|
208
|
+
if (err)
|
|
209
|
+
reject(err);
|
|
210
|
+
else
|
|
211
|
+
resolve({ address: address || "", family: family || 4 });
|
|
212
|
+
});
|
|
213
|
+
});
|
|
214
|
+
},
|
|
215
|
+
resolve(hostname, rrtype) {
|
|
216
|
+
return new Promise((resolve, reject) => {
|
|
217
|
+
dns.resolve(hostname, rrtype || "A", (err, addresses) => {
|
|
218
|
+
if (err)
|
|
219
|
+
reject(err);
|
|
220
|
+
else
|
|
221
|
+
resolve(addresses || []);
|
|
222
|
+
});
|
|
223
|
+
});
|
|
224
|
+
},
|
|
225
|
+
},
|
|
226
|
+
};
|
|
227
|
+
// IncomingMessage class
|
|
228
|
+
export class IncomingMessage {
|
|
229
|
+
headers;
|
|
230
|
+
rawHeaders;
|
|
231
|
+
trailers;
|
|
232
|
+
rawTrailers;
|
|
233
|
+
httpVersion;
|
|
234
|
+
httpVersionMajor;
|
|
235
|
+
httpVersionMinor;
|
|
236
|
+
method;
|
|
237
|
+
url;
|
|
238
|
+
statusCode;
|
|
239
|
+
statusMessage;
|
|
240
|
+
_body;
|
|
241
|
+
_isBinary;
|
|
242
|
+
_listeners;
|
|
243
|
+
complete;
|
|
244
|
+
aborted;
|
|
245
|
+
socket;
|
|
246
|
+
_bodyConsumed;
|
|
247
|
+
_ended;
|
|
248
|
+
_flowing;
|
|
249
|
+
readable;
|
|
250
|
+
readableEnded;
|
|
251
|
+
readableFlowing;
|
|
252
|
+
destroyed;
|
|
253
|
+
_encoding;
|
|
254
|
+
constructor(response) {
|
|
255
|
+
this.headers = response?.headers || {};
|
|
256
|
+
this.rawHeaders = [];
|
|
257
|
+
if (this.headers && typeof this.headers === "object") {
|
|
258
|
+
Object.entries(this.headers).forEach(([k, v]) => {
|
|
259
|
+
this.rawHeaders.push(k, v);
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
this.trailers = {};
|
|
263
|
+
this.rawTrailers = [];
|
|
264
|
+
this.httpVersion = "1.1";
|
|
265
|
+
this.httpVersionMajor = 1;
|
|
266
|
+
this.httpVersionMinor = 1;
|
|
267
|
+
this.method = null;
|
|
268
|
+
this.url = response?.url || "";
|
|
269
|
+
this.statusCode = response?.status;
|
|
270
|
+
this.statusMessage = response?.statusText;
|
|
271
|
+
// Decode base64 body if x-body-encoding header is set
|
|
272
|
+
const bodyEncoding = this.headers['x-body-encoding'];
|
|
273
|
+
if (bodyEncoding === 'base64' && response?.body && typeof Buffer !== 'undefined') {
|
|
274
|
+
this._body = Buffer.from(response.body, 'base64').toString('binary');
|
|
275
|
+
this._isBinary = true;
|
|
276
|
+
}
|
|
277
|
+
else {
|
|
278
|
+
this._body = response?.body || "";
|
|
279
|
+
this._isBinary = false;
|
|
280
|
+
}
|
|
281
|
+
this._listeners = {};
|
|
282
|
+
this.complete = false;
|
|
283
|
+
this.aborted = false;
|
|
284
|
+
this.socket = null;
|
|
285
|
+
this._bodyConsumed = false;
|
|
286
|
+
this._ended = false;
|
|
287
|
+
this._flowing = false;
|
|
288
|
+
this.readable = true;
|
|
289
|
+
this.readableEnded = false;
|
|
290
|
+
this.readableFlowing = null;
|
|
291
|
+
this.destroyed = false;
|
|
292
|
+
}
|
|
293
|
+
on(event, listener) {
|
|
294
|
+
if (!this._listeners[event])
|
|
295
|
+
this._listeners[event] = [];
|
|
296
|
+
this._listeners[event].push(listener);
|
|
297
|
+
// When 'data' listener is added, start flowing mode
|
|
298
|
+
// Note: We check for non-empty body (this._body.length > 0) because we need to
|
|
299
|
+
// emit 'end' even for empty responses, but only emit 'data' if there's actual data
|
|
300
|
+
if (event === "data" && !this._bodyConsumed) {
|
|
301
|
+
this._flowing = true;
|
|
302
|
+
this.readableFlowing = true;
|
|
303
|
+
// Emit data in next microtask
|
|
304
|
+
Promise.resolve().then(() => {
|
|
305
|
+
if (!this._bodyConsumed) {
|
|
306
|
+
this._bodyConsumed = true;
|
|
307
|
+
// Only emit data if there's actual content
|
|
308
|
+
if (this._body && this._body.length > 0) {
|
|
309
|
+
let buf;
|
|
310
|
+
if (typeof Buffer !== "undefined") {
|
|
311
|
+
// For binary data, use 'binary' encoding to preserve bytes
|
|
312
|
+
buf = this._isBinary ? Buffer.from(this._body, 'binary') : Buffer.from(this._body);
|
|
313
|
+
}
|
|
314
|
+
else {
|
|
315
|
+
buf = this._body;
|
|
316
|
+
}
|
|
317
|
+
this.emit("data", buf);
|
|
318
|
+
}
|
|
319
|
+
// Always emit end after data (even if no data was emitted)
|
|
320
|
+
Promise.resolve().then(() => {
|
|
321
|
+
if (!this._ended) {
|
|
322
|
+
this._ended = true;
|
|
323
|
+
this.complete = true;
|
|
324
|
+
this.readable = false;
|
|
325
|
+
this.readableEnded = true;
|
|
326
|
+
this.emit("end");
|
|
327
|
+
}
|
|
328
|
+
});
|
|
329
|
+
}
|
|
330
|
+
});
|
|
331
|
+
}
|
|
332
|
+
// If 'end' listener is added after data was already consumed, emit end
|
|
333
|
+
if (event === "end" && this._bodyConsumed && !this._ended) {
|
|
334
|
+
Promise.resolve().then(() => {
|
|
335
|
+
if (!this._ended) {
|
|
336
|
+
this._ended = true;
|
|
337
|
+
this.complete = true;
|
|
338
|
+
this.readable = false;
|
|
339
|
+
this.readableEnded = true;
|
|
340
|
+
listener();
|
|
341
|
+
}
|
|
342
|
+
});
|
|
343
|
+
}
|
|
344
|
+
return this;
|
|
345
|
+
}
|
|
346
|
+
once(event, listener) {
|
|
347
|
+
const wrapper = (...args) => {
|
|
348
|
+
this.off(event, wrapper);
|
|
349
|
+
listener(...args);
|
|
350
|
+
};
|
|
351
|
+
wrapper._originalListener = listener;
|
|
352
|
+
return this.on(event, wrapper);
|
|
353
|
+
}
|
|
354
|
+
off(event, listener) {
|
|
355
|
+
if (this._listeners[event]) {
|
|
356
|
+
const idx = this._listeners[event].findIndex((fn) => fn === listener || fn._originalListener === listener);
|
|
357
|
+
if (idx !== -1)
|
|
358
|
+
this._listeners[event].splice(idx, 1);
|
|
359
|
+
}
|
|
360
|
+
return this;
|
|
361
|
+
}
|
|
362
|
+
removeListener(event, listener) {
|
|
363
|
+
return this.off(event, listener);
|
|
364
|
+
}
|
|
365
|
+
removeAllListeners(event) {
|
|
366
|
+
if (event) {
|
|
367
|
+
delete this._listeners[event];
|
|
368
|
+
}
|
|
369
|
+
else {
|
|
370
|
+
this._listeners = {};
|
|
371
|
+
}
|
|
372
|
+
return this;
|
|
373
|
+
}
|
|
374
|
+
emit(event, ...args) {
|
|
375
|
+
const handlers = this._listeners[event];
|
|
376
|
+
if (handlers) {
|
|
377
|
+
handlers.slice().forEach((fn) => fn(...args));
|
|
378
|
+
}
|
|
379
|
+
return handlers !== undefined && handlers.length > 0;
|
|
380
|
+
}
|
|
381
|
+
setEncoding(encoding) {
|
|
382
|
+
this._encoding = encoding;
|
|
383
|
+
return this;
|
|
384
|
+
}
|
|
385
|
+
read(_size) {
|
|
386
|
+
if (this._bodyConsumed)
|
|
387
|
+
return null;
|
|
388
|
+
this._bodyConsumed = true;
|
|
389
|
+
let buf;
|
|
390
|
+
if (typeof Buffer !== "undefined") {
|
|
391
|
+
buf = this._isBinary ? Buffer.from(this._body, 'binary') : Buffer.from(this._body);
|
|
392
|
+
}
|
|
393
|
+
else {
|
|
394
|
+
buf = this._body;
|
|
395
|
+
}
|
|
396
|
+
// Schedule end event
|
|
397
|
+
Promise.resolve().then(() => {
|
|
398
|
+
if (!this._ended) {
|
|
399
|
+
this._ended = true;
|
|
400
|
+
this.complete = true;
|
|
401
|
+
this.readable = false;
|
|
402
|
+
this.readableEnded = true;
|
|
403
|
+
this.emit("end");
|
|
404
|
+
}
|
|
405
|
+
});
|
|
406
|
+
return buf;
|
|
407
|
+
}
|
|
408
|
+
pipe(dest) {
|
|
409
|
+
let buf;
|
|
410
|
+
if (typeof Buffer !== "undefined") {
|
|
411
|
+
buf = this._isBinary ? Buffer.from(this._body || "", 'binary') : Buffer.from(this._body || "");
|
|
412
|
+
}
|
|
413
|
+
else {
|
|
414
|
+
buf = this._body || "";
|
|
415
|
+
}
|
|
416
|
+
if (typeof dest.write === "function" && (typeof buf === "string" ? buf.length : buf.length) > 0) {
|
|
417
|
+
dest.write(buf);
|
|
418
|
+
}
|
|
419
|
+
if (typeof dest.end === "function") {
|
|
420
|
+
Promise.resolve().then(() => dest.end());
|
|
421
|
+
}
|
|
422
|
+
this._bodyConsumed = true;
|
|
423
|
+
this._ended = true;
|
|
424
|
+
this.complete = true;
|
|
425
|
+
this.readable = false;
|
|
426
|
+
this.readableEnded = true;
|
|
427
|
+
return dest;
|
|
428
|
+
}
|
|
429
|
+
pause() {
|
|
430
|
+
this._flowing = false;
|
|
431
|
+
this.readableFlowing = false;
|
|
432
|
+
return this;
|
|
433
|
+
}
|
|
434
|
+
resume() {
|
|
435
|
+
this._flowing = true;
|
|
436
|
+
this.readableFlowing = true;
|
|
437
|
+
if (!this._bodyConsumed && this._body) {
|
|
438
|
+
Promise.resolve().then(() => {
|
|
439
|
+
if (!this._bodyConsumed) {
|
|
440
|
+
this._bodyConsumed = true;
|
|
441
|
+
let buf;
|
|
442
|
+
if (typeof Buffer !== "undefined") {
|
|
443
|
+
buf = this._isBinary ? Buffer.from(this._body, 'binary') : Buffer.from(this._body);
|
|
444
|
+
}
|
|
445
|
+
else {
|
|
446
|
+
buf = this._body;
|
|
447
|
+
}
|
|
448
|
+
this.emit("data", buf);
|
|
449
|
+
Promise.resolve().then(() => {
|
|
450
|
+
if (!this._ended) {
|
|
451
|
+
this._ended = true;
|
|
452
|
+
this.complete = true;
|
|
453
|
+
this.readable = false;
|
|
454
|
+
this.readableEnded = true;
|
|
455
|
+
this.emit("end");
|
|
456
|
+
}
|
|
457
|
+
});
|
|
458
|
+
}
|
|
459
|
+
});
|
|
460
|
+
}
|
|
461
|
+
return this;
|
|
462
|
+
}
|
|
463
|
+
unpipe(_dest) {
|
|
464
|
+
return this;
|
|
465
|
+
}
|
|
466
|
+
destroy(err) {
|
|
467
|
+
this.destroyed = true;
|
|
468
|
+
this.readable = false;
|
|
469
|
+
if (err)
|
|
470
|
+
this.emit("error", err);
|
|
471
|
+
this.emit("close");
|
|
472
|
+
return this;
|
|
473
|
+
}
|
|
474
|
+
[Symbol.asyncIterator]() {
|
|
475
|
+
const self = this;
|
|
476
|
+
let dataEmitted = false;
|
|
477
|
+
let ended = false;
|
|
478
|
+
return {
|
|
479
|
+
async next() {
|
|
480
|
+
if (ended || self._ended) {
|
|
481
|
+
return { done: true, value: undefined };
|
|
482
|
+
}
|
|
483
|
+
if (!dataEmitted && !self._bodyConsumed) {
|
|
484
|
+
dataEmitted = true;
|
|
485
|
+
self._bodyConsumed = true;
|
|
486
|
+
let buf;
|
|
487
|
+
if (typeof Buffer !== "undefined") {
|
|
488
|
+
buf = self._isBinary ? Buffer.from(self._body || "", 'binary') : Buffer.from(self._body || "");
|
|
489
|
+
}
|
|
490
|
+
else {
|
|
491
|
+
buf = self._body || "";
|
|
492
|
+
}
|
|
493
|
+
return { done: false, value: buf };
|
|
494
|
+
}
|
|
495
|
+
ended = true;
|
|
496
|
+
self._ended = true;
|
|
497
|
+
self.complete = true;
|
|
498
|
+
self.readable = false;
|
|
499
|
+
self.readableEnded = true;
|
|
500
|
+
return { done: true, value: undefined };
|
|
501
|
+
},
|
|
502
|
+
return() {
|
|
503
|
+
ended = true;
|
|
504
|
+
return Promise.resolve({ done: true, value: undefined });
|
|
505
|
+
},
|
|
506
|
+
throw(err) {
|
|
507
|
+
ended = true;
|
|
508
|
+
self.emit("error", err);
|
|
509
|
+
return Promise.resolve({ done: true, value: undefined });
|
|
510
|
+
},
|
|
511
|
+
};
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
// ClientRequest class
|
|
515
|
+
export class ClientRequest {
|
|
516
|
+
_options;
|
|
517
|
+
_callback;
|
|
518
|
+
_listeners = {};
|
|
519
|
+
_body = "";
|
|
520
|
+
_ended = false;
|
|
521
|
+
socket = null;
|
|
522
|
+
finished = false;
|
|
523
|
+
aborted = false;
|
|
524
|
+
constructor(options, callback) {
|
|
525
|
+
this._options = options;
|
|
526
|
+
this._callback = callback;
|
|
527
|
+
// Execute request asynchronously using Promise microtask
|
|
528
|
+
Promise.resolve().then(() => this._execute());
|
|
529
|
+
}
|
|
530
|
+
async _execute() {
|
|
531
|
+
try {
|
|
532
|
+
if (typeof _networkHttpRequestRaw === 'undefined') {
|
|
533
|
+
console.error('http/https request requires NetworkAdapter to be configured');
|
|
534
|
+
throw new Error('http/https request requires NetworkAdapter to be configured');
|
|
535
|
+
}
|
|
536
|
+
const url = this._buildUrl();
|
|
537
|
+
const optionsJson = JSON.stringify({
|
|
538
|
+
method: this._options.method || "GET",
|
|
539
|
+
headers: this._options.headers || {},
|
|
540
|
+
body: this._body || null,
|
|
541
|
+
});
|
|
542
|
+
const responseJson = await _networkHttpRequestRaw.apply(undefined, [url, optionsJson], {
|
|
543
|
+
result: { promise: true },
|
|
544
|
+
});
|
|
545
|
+
const response = JSON.parse(responseJson);
|
|
546
|
+
const res = new IncomingMessage(response);
|
|
547
|
+
this.finished = true;
|
|
548
|
+
if (this._callback) {
|
|
549
|
+
this._callback(res);
|
|
550
|
+
}
|
|
551
|
+
this._emit("response", res);
|
|
552
|
+
}
|
|
553
|
+
catch (err) {
|
|
554
|
+
this._emit("error", err);
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
_buildUrl() {
|
|
558
|
+
const opts = this._options;
|
|
559
|
+
const protocol = opts.protocol || (opts.port === 443 ? "https:" : "http:");
|
|
560
|
+
const host = opts.hostname || opts.host || "localhost";
|
|
561
|
+
const port = opts.port ? ":" + opts.port : "";
|
|
562
|
+
const path = opts.path || "/";
|
|
563
|
+
return protocol + "//" + host + port + path;
|
|
564
|
+
}
|
|
565
|
+
on(event, listener) {
|
|
566
|
+
if (!this._listeners[event])
|
|
567
|
+
this._listeners[event] = [];
|
|
568
|
+
this._listeners[event].push(listener);
|
|
569
|
+
return this;
|
|
570
|
+
}
|
|
571
|
+
once(event, listener) {
|
|
572
|
+
const wrapper = (...args) => {
|
|
573
|
+
this.off(event, wrapper);
|
|
574
|
+
listener(...args);
|
|
575
|
+
};
|
|
576
|
+
return this.on(event, wrapper);
|
|
577
|
+
}
|
|
578
|
+
off(event, listener) {
|
|
579
|
+
if (this._listeners[event]) {
|
|
580
|
+
const idx = this._listeners[event].indexOf(listener);
|
|
581
|
+
if (idx !== -1)
|
|
582
|
+
this._listeners[event].splice(idx, 1);
|
|
583
|
+
}
|
|
584
|
+
return this;
|
|
585
|
+
}
|
|
586
|
+
_emit(event, ...args) {
|
|
587
|
+
if (this._listeners[event]) {
|
|
588
|
+
this._listeners[event].forEach((fn) => fn(...args));
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
write(data) {
|
|
592
|
+
this._body += data;
|
|
593
|
+
return true;
|
|
594
|
+
}
|
|
595
|
+
end(data) {
|
|
596
|
+
if (data)
|
|
597
|
+
this._body += data;
|
|
598
|
+
this._ended = true;
|
|
599
|
+
return this;
|
|
600
|
+
}
|
|
601
|
+
abort() {
|
|
602
|
+
this.aborted = true;
|
|
603
|
+
}
|
|
604
|
+
setTimeout(_timeout) {
|
|
605
|
+
return this;
|
|
606
|
+
}
|
|
607
|
+
setNoDelay() {
|
|
608
|
+
return this;
|
|
609
|
+
}
|
|
610
|
+
setSocketKeepAlive() {
|
|
611
|
+
return this;
|
|
612
|
+
}
|
|
613
|
+
flushHeaders() {
|
|
614
|
+
// no-op
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
// Agent class - no-op stub (connection pooling not applicable with fetch-based implementation)
|
|
618
|
+
class Agent {
|
|
619
|
+
maxSockets;
|
|
620
|
+
maxFreeSockets;
|
|
621
|
+
keepAlive;
|
|
622
|
+
keepAliveMsecs;
|
|
623
|
+
timeout;
|
|
624
|
+
constructor(options) {
|
|
625
|
+
// Accept options but ignore them - our fetch-based implementation doesn't use connection pooling
|
|
626
|
+
this.keepAlive = options?.keepAlive ?? false;
|
|
627
|
+
this.keepAliveMsecs = options?.keepAliveMsecs ?? 1000;
|
|
628
|
+
this.maxSockets = options?.maxSockets ?? Infinity;
|
|
629
|
+
this.maxFreeSockets = options?.maxFreeSockets ?? 256;
|
|
630
|
+
this.timeout = options?.timeout ?? -1;
|
|
631
|
+
}
|
|
632
|
+
destroy() {
|
|
633
|
+
// no-op
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
let nextServerId = 1;
|
|
637
|
+
const serverRequestListeners = new Map();
|
|
638
|
+
class ServerIncomingMessage {
|
|
639
|
+
headers;
|
|
640
|
+
rawHeaders;
|
|
641
|
+
method;
|
|
642
|
+
url;
|
|
643
|
+
socket;
|
|
644
|
+
rawBody;
|
|
645
|
+
destroyed = false;
|
|
646
|
+
errored;
|
|
647
|
+
_listeners = {};
|
|
648
|
+
constructor(request) {
|
|
649
|
+
this.headers = request.headers || {};
|
|
650
|
+
this.rawHeaders = request.rawHeaders || [];
|
|
651
|
+
if (!Array.isArray(this.rawHeaders) || this.rawHeaders.length % 2 !== 0) {
|
|
652
|
+
this.rawHeaders = [];
|
|
653
|
+
}
|
|
654
|
+
this.method = request.method || "GET";
|
|
655
|
+
this.url = request.url || "/";
|
|
656
|
+
this.socket = { encrypted: false };
|
|
657
|
+
const rawHost = this.headers.host;
|
|
658
|
+
if (typeof rawHost === "string" && rawHost.includes(",")) {
|
|
659
|
+
this.headers.host = rawHost.split(",")[0].trim();
|
|
660
|
+
}
|
|
661
|
+
if (!this.headers.host) {
|
|
662
|
+
this.headers.host = "127.0.0.1";
|
|
663
|
+
}
|
|
664
|
+
if (this.rawHeaders.length === 0) {
|
|
665
|
+
Object.entries(this.headers).forEach(([key, value]) => {
|
|
666
|
+
this.rawHeaders.push(key, value);
|
|
667
|
+
});
|
|
668
|
+
}
|
|
669
|
+
if (request.bodyBase64 && typeof Buffer !== "undefined") {
|
|
670
|
+
this.rawBody = Buffer.from(request.bodyBase64, "base64");
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
on(event, listener) {
|
|
674
|
+
if (!this._listeners[event])
|
|
675
|
+
this._listeners[event] = [];
|
|
676
|
+
this._listeners[event].push(listener);
|
|
677
|
+
if (event === "end") {
|
|
678
|
+
Promise.resolve().then(() => listener());
|
|
679
|
+
}
|
|
680
|
+
return this;
|
|
681
|
+
}
|
|
682
|
+
once(event, listener) {
|
|
683
|
+
const wrapped = (...args) => {
|
|
684
|
+
this.off(event, wrapped);
|
|
685
|
+
listener(...args);
|
|
686
|
+
};
|
|
687
|
+
return this.on(event, wrapped);
|
|
688
|
+
}
|
|
689
|
+
off(event, listener) {
|
|
690
|
+
const listeners = this._listeners[event];
|
|
691
|
+
if (!listeners)
|
|
692
|
+
return this;
|
|
693
|
+
const index = listeners.indexOf(listener);
|
|
694
|
+
if (index !== -1)
|
|
695
|
+
listeners.splice(index, 1);
|
|
696
|
+
return this;
|
|
697
|
+
}
|
|
698
|
+
removeListener(event, listener) {
|
|
699
|
+
return this.off(event, listener);
|
|
700
|
+
}
|
|
701
|
+
emit(event, ...args) {
|
|
702
|
+
const listeners = this._listeners[event];
|
|
703
|
+
if (!listeners || listeners.length === 0)
|
|
704
|
+
return false;
|
|
705
|
+
listeners.slice().forEach((fn) => fn(...args));
|
|
706
|
+
return true;
|
|
707
|
+
}
|
|
708
|
+
destroy(err) {
|
|
709
|
+
this.destroyed = true;
|
|
710
|
+
this.errored = err;
|
|
711
|
+
if (err) {
|
|
712
|
+
this.emit("error", err);
|
|
713
|
+
}
|
|
714
|
+
this.emit("close");
|
|
715
|
+
return this;
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
class ServerResponseBridge {
|
|
719
|
+
statusCode = 200;
|
|
720
|
+
statusMessage = "OK";
|
|
721
|
+
headersSent = false;
|
|
722
|
+
writable = true;
|
|
723
|
+
writableFinished = false;
|
|
724
|
+
_headers = new Map();
|
|
725
|
+
_chunks = [];
|
|
726
|
+
_listeners = {};
|
|
727
|
+
_closedPromise;
|
|
728
|
+
_resolveClosed = null;
|
|
729
|
+
constructor() {
|
|
730
|
+
this._closedPromise = new Promise((resolve) => {
|
|
731
|
+
this._resolveClosed = resolve;
|
|
732
|
+
});
|
|
733
|
+
}
|
|
734
|
+
on(event, listener) {
|
|
735
|
+
if (!this._listeners[event])
|
|
736
|
+
this._listeners[event] = [];
|
|
737
|
+
this._listeners[event].push(listener);
|
|
738
|
+
return this;
|
|
739
|
+
}
|
|
740
|
+
once(event, listener) {
|
|
741
|
+
const wrapped = (...args) => {
|
|
742
|
+
this.off(event, wrapped);
|
|
743
|
+
listener(...args);
|
|
744
|
+
};
|
|
745
|
+
return this.on(event, wrapped);
|
|
746
|
+
}
|
|
747
|
+
off(event, listener) {
|
|
748
|
+
const listeners = this._listeners[event];
|
|
749
|
+
if (!listeners)
|
|
750
|
+
return this;
|
|
751
|
+
const index = listeners.indexOf(listener);
|
|
752
|
+
if (index !== -1)
|
|
753
|
+
listeners.splice(index, 1);
|
|
754
|
+
return this;
|
|
755
|
+
}
|
|
756
|
+
removeListener(event, listener) {
|
|
757
|
+
return this.off(event, listener);
|
|
758
|
+
}
|
|
759
|
+
_emit(event, ...args) {
|
|
760
|
+
const listeners = this._listeners[event];
|
|
761
|
+
if (!listeners)
|
|
762
|
+
return;
|
|
763
|
+
listeners.slice().forEach((fn) => fn(...args));
|
|
764
|
+
}
|
|
765
|
+
writeHead(statusCode, headers) {
|
|
766
|
+
this.statusCode = statusCode;
|
|
767
|
+
if (headers) {
|
|
768
|
+
if (Array.isArray(headers)) {
|
|
769
|
+
headers.forEach(([key, value]) => this.setHeader(key, value));
|
|
770
|
+
}
|
|
771
|
+
else {
|
|
772
|
+
Object.entries(headers).forEach(([key, value]) => this.setHeader(key, value));
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
this.headersSent = true;
|
|
776
|
+
return this;
|
|
777
|
+
}
|
|
778
|
+
setHeader(name, value) {
|
|
779
|
+
const normalized = Array.isArray(value) ? value.join(", ") : String(value);
|
|
780
|
+
this._headers.set(name.toLowerCase(), normalized);
|
|
781
|
+
return this;
|
|
782
|
+
}
|
|
783
|
+
getHeader(name) {
|
|
784
|
+
return this._headers.get(name.toLowerCase());
|
|
785
|
+
}
|
|
786
|
+
hasHeader(name) {
|
|
787
|
+
return this._headers.has(name.toLowerCase());
|
|
788
|
+
}
|
|
789
|
+
removeHeader(name) {
|
|
790
|
+
this._headers.delete(name.toLowerCase());
|
|
791
|
+
}
|
|
792
|
+
write(chunk) {
|
|
793
|
+
this.headersSent = true;
|
|
794
|
+
if (typeof chunk === "string") {
|
|
795
|
+
this._chunks.push(Buffer.from(chunk));
|
|
796
|
+
}
|
|
797
|
+
else {
|
|
798
|
+
this._chunks.push(chunk);
|
|
799
|
+
}
|
|
800
|
+
return true;
|
|
801
|
+
}
|
|
802
|
+
end(chunk) {
|
|
803
|
+
if (chunk !== undefined) {
|
|
804
|
+
this.write(chunk);
|
|
805
|
+
}
|
|
806
|
+
this._finalize();
|
|
807
|
+
return this;
|
|
808
|
+
}
|
|
809
|
+
flushHeaders() {
|
|
810
|
+
this.headersSent = true;
|
|
811
|
+
}
|
|
812
|
+
destroy(err) {
|
|
813
|
+
if (err) {
|
|
814
|
+
this._emit("error", err);
|
|
815
|
+
}
|
|
816
|
+
this._finalize();
|
|
817
|
+
}
|
|
818
|
+
async waitForClose() {
|
|
819
|
+
await this._closedPromise;
|
|
820
|
+
}
|
|
821
|
+
serialize() {
|
|
822
|
+
const bodyBuffer = this._chunks.length > 0 ? Buffer.concat(this._chunks) : Buffer.alloc(0);
|
|
823
|
+
return {
|
|
824
|
+
status: this.statusCode,
|
|
825
|
+
headers: Array.from(this._headers.entries()),
|
|
826
|
+
body: bodyBuffer.toString("base64"),
|
|
827
|
+
bodyEncoding: "base64",
|
|
828
|
+
};
|
|
829
|
+
}
|
|
830
|
+
_finalize() {
|
|
831
|
+
if (this.writableFinished) {
|
|
832
|
+
return;
|
|
833
|
+
}
|
|
834
|
+
this.writableFinished = true;
|
|
835
|
+
this.writable = false;
|
|
836
|
+
this._emit("finish");
|
|
837
|
+
this._emit("close");
|
|
838
|
+
this._resolveClosed?.();
|
|
839
|
+
this._resolveClosed = null;
|
|
840
|
+
}
|
|
841
|
+
}
|
|
842
|
+
class Server {
|
|
843
|
+
listening = false;
|
|
844
|
+
_listeners = {};
|
|
845
|
+
_serverId;
|
|
846
|
+
_listenPromise = null;
|
|
847
|
+
_address = null;
|
|
848
|
+
_handleId = null;
|
|
849
|
+
constructor(requestListener) {
|
|
850
|
+
this._serverId = nextServerId++;
|
|
851
|
+
if (requestListener) {
|
|
852
|
+
serverRequestListeners.set(this._serverId, requestListener);
|
|
853
|
+
}
|
|
854
|
+
else {
|
|
855
|
+
serverRequestListeners.set(this._serverId, () => undefined);
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
_emit(event, ...args) {
|
|
859
|
+
const listeners = this._listeners[event];
|
|
860
|
+
if (!listeners || listeners.length === 0)
|
|
861
|
+
return;
|
|
862
|
+
listeners.slice().forEach((listener) => listener(...args));
|
|
863
|
+
}
|
|
864
|
+
async _start(port, hostname) {
|
|
865
|
+
if (typeof _networkHttpServerListenRaw === "undefined") {
|
|
866
|
+
throw new Error("http.createServer requires NetworkAdapter.httpServerListen support");
|
|
867
|
+
}
|
|
868
|
+
const resultJson = await _networkHttpServerListenRaw.apply(undefined, [JSON.stringify({ serverId: this._serverId, port, hostname })], { result: { promise: true } });
|
|
869
|
+
const result = JSON.parse(resultJson);
|
|
870
|
+
this._address = result.address;
|
|
871
|
+
this.listening = true;
|
|
872
|
+
this._handleId = `http-server:${this._serverId}`;
|
|
873
|
+
if (typeof _registerHandle === "function") {
|
|
874
|
+
_registerHandle(this._handleId, "http server");
|
|
875
|
+
}
|
|
876
|
+
}
|
|
877
|
+
listen(portOrCb, hostOrCb, cb) {
|
|
878
|
+
const port = typeof portOrCb === "number" ? portOrCb : undefined;
|
|
879
|
+
const hostname = typeof hostOrCb === "string" ? hostOrCb : undefined;
|
|
880
|
+
const callback = typeof cb === "function"
|
|
881
|
+
? cb
|
|
882
|
+
: typeof hostOrCb === "function"
|
|
883
|
+
? hostOrCb
|
|
884
|
+
: typeof portOrCb === "function"
|
|
885
|
+
? portOrCb
|
|
886
|
+
: undefined;
|
|
887
|
+
if (!this._listenPromise) {
|
|
888
|
+
this._listenPromise = this._start(port, hostname)
|
|
889
|
+
.then(() => {
|
|
890
|
+
this._emit("listening");
|
|
891
|
+
callback?.();
|
|
892
|
+
})
|
|
893
|
+
.catch((error) => {
|
|
894
|
+
this._emit("error", error);
|
|
895
|
+
});
|
|
896
|
+
}
|
|
897
|
+
return this;
|
|
898
|
+
}
|
|
899
|
+
close(cb) {
|
|
900
|
+
const run = async () => {
|
|
901
|
+
try {
|
|
902
|
+
if (this._listenPromise) {
|
|
903
|
+
await this._listenPromise;
|
|
904
|
+
}
|
|
905
|
+
if (this.listening && typeof _networkHttpServerCloseRaw !== "undefined") {
|
|
906
|
+
await _networkHttpServerCloseRaw.apply(undefined, [this._serverId], {
|
|
907
|
+
result: { promise: true },
|
|
908
|
+
});
|
|
909
|
+
}
|
|
910
|
+
this.listening = false;
|
|
911
|
+
this._address = null;
|
|
912
|
+
if (this._handleId && typeof _unregisterHandle === "function") {
|
|
913
|
+
_unregisterHandle(this._handleId);
|
|
914
|
+
}
|
|
915
|
+
this._handleId = null;
|
|
916
|
+
cb?.();
|
|
917
|
+
this._emit("close");
|
|
918
|
+
}
|
|
919
|
+
catch (err) {
|
|
920
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
921
|
+
cb?.(error);
|
|
922
|
+
this._emit("error", error);
|
|
923
|
+
}
|
|
924
|
+
};
|
|
925
|
+
void run();
|
|
926
|
+
return this;
|
|
927
|
+
}
|
|
928
|
+
address() {
|
|
929
|
+
return this._address;
|
|
930
|
+
}
|
|
931
|
+
on(event, listener) {
|
|
932
|
+
if (!this._listeners[event])
|
|
933
|
+
this._listeners[event] = [];
|
|
934
|
+
this._listeners[event].push(listener);
|
|
935
|
+
return this;
|
|
936
|
+
}
|
|
937
|
+
once(event, listener) {
|
|
938
|
+
const wrapped = (...args) => {
|
|
939
|
+
this.off(event, wrapped);
|
|
940
|
+
listener(...args);
|
|
941
|
+
};
|
|
942
|
+
return this.on(event, wrapped);
|
|
943
|
+
}
|
|
944
|
+
off(event, listener) {
|
|
945
|
+
const listeners = this._listeners[event];
|
|
946
|
+
if (!listeners)
|
|
947
|
+
return this;
|
|
948
|
+
const index = listeners.indexOf(listener);
|
|
949
|
+
if (index !== -1)
|
|
950
|
+
listeners.splice(index, 1);
|
|
951
|
+
return this;
|
|
952
|
+
}
|
|
953
|
+
removeListener(event, listener) {
|
|
954
|
+
return this.off(event, listener);
|
|
955
|
+
}
|
|
956
|
+
removeAllListeners(event) {
|
|
957
|
+
if (event) {
|
|
958
|
+
delete this._listeners[event];
|
|
959
|
+
}
|
|
960
|
+
else {
|
|
961
|
+
this._listeners = {};
|
|
962
|
+
}
|
|
963
|
+
return this;
|
|
964
|
+
}
|
|
965
|
+
ref() {
|
|
966
|
+
return this;
|
|
967
|
+
}
|
|
968
|
+
unref() {
|
|
969
|
+
return this;
|
|
970
|
+
}
|
|
971
|
+
}
|
|
972
|
+
async function dispatchServerRequest(serverId, requestJson) {
|
|
973
|
+
const listener = serverRequestListeners.get(serverId);
|
|
974
|
+
if (!listener) {
|
|
975
|
+
throw new Error(`Unknown HTTP server: ${serverId}`);
|
|
976
|
+
}
|
|
977
|
+
const request = JSON.parse(requestJson);
|
|
978
|
+
const incoming = new ServerIncomingMessage(request);
|
|
979
|
+
const outgoing = new ServerResponseBridge();
|
|
980
|
+
try {
|
|
981
|
+
await Promise.resolve(listener(incoming, outgoing));
|
|
982
|
+
}
|
|
983
|
+
catch (err) {
|
|
984
|
+
outgoing.statusCode = 500;
|
|
985
|
+
outgoing.end(err instanceof Error ? `Error: ${err.message}` : "Error");
|
|
986
|
+
}
|
|
987
|
+
if (!outgoing.writableFinished) {
|
|
988
|
+
outgoing.end();
|
|
989
|
+
}
|
|
990
|
+
await outgoing.waitForClose();
|
|
991
|
+
return JSON.stringify(outgoing.serialize());
|
|
992
|
+
}
|
|
993
|
+
// Create HTTP module
|
|
994
|
+
function createHttpModule(_protocol) {
|
|
995
|
+
return {
|
|
996
|
+
request(options, callback) {
|
|
997
|
+
let opts;
|
|
998
|
+
if (typeof options === "string") {
|
|
999
|
+
const url = new URL(options);
|
|
1000
|
+
opts = {
|
|
1001
|
+
protocol: url.protocol,
|
|
1002
|
+
hostname: url.hostname,
|
|
1003
|
+
port: url.port,
|
|
1004
|
+
path: url.pathname + url.search,
|
|
1005
|
+
};
|
|
1006
|
+
}
|
|
1007
|
+
else if (options instanceof URL) {
|
|
1008
|
+
opts = {
|
|
1009
|
+
protocol: options.protocol,
|
|
1010
|
+
hostname: options.hostname,
|
|
1011
|
+
port: options.port,
|
|
1012
|
+
path: options.pathname + options.search,
|
|
1013
|
+
};
|
|
1014
|
+
}
|
|
1015
|
+
else {
|
|
1016
|
+
opts = options;
|
|
1017
|
+
}
|
|
1018
|
+
return new ClientRequest(opts, callback);
|
|
1019
|
+
},
|
|
1020
|
+
get(options, callback) {
|
|
1021
|
+
let opts;
|
|
1022
|
+
if (typeof options === "string") {
|
|
1023
|
+
const url = new URL(options);
|
|
1024
|
+
opts = {
|
|
1025
|
+
protocol: url.protocol,
|
|
1026
|
+
hostname: url.hostname,
|
|
1027
|
+
port: url.port,
|
|
1028
|
+
path: url.pathname + url.search,
|
|
1029
|
+
method: "GET",
|
|
1030
|
+
};
|
|
1031
|
+
}
|
|
1032
|
+
else if (options instanceof URL) {
|
|
1033
|
+
opts = {
|
|
1034
|
+
protocol: options.protocol,
|
|
1035
|
+
hostname: options.hostname,
|
|
1036
|
+
port: options.port,
|
|
1037
|
+
path: options.pathname + options.search,
|
|
1038
|
+
method: "GET",
|
|
1039
|
+
};
|
|
1040
|
+
}
|
|
1041
|
+
else {
|
|
1042
|
+
opts = { ...options, method: "GET" };
|
|
1043
|
+
}
|
|
1044
|
+
const req = new ClientRequest(opts, callback);
|
|
1045
|
+
req.end();
|
|
1046
|
+
return req;
|
|
1047
|
+
},
|
|
1048
|
+
createServer(_optionsOrListener, maybeListener) {
|
|
1049
|
+
const listener = typeof _optionsOrListener === "function"
|
|
1050
|
+
? _optionsOrListener
|
|
1051
|
+
: maybeListener;
|
|
1052
|
+
return new Server(listener);
|
|
1053
|
+
},
|
|
1054
|
+
Agent,
|
|
1055
|
+
globalAgent: new Agent({ keepAlive: false }),
|
|
1056
|
+
Server: Server,
|
|
1057
|
+
ServerResponse: ServerResponseBridge,
|
|
1058
|
+
IncomingMessage: IncomingMessage,
|
|
1059
|
+
ClientRequest: ClientRequest,
|
|
1060
|
+
METHODS: ["GET", "POST", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS"],
|
|
1061
|
+
STATUS_CODES: {
|
|
1062
|
+
200: "OK",
|
|
1063
|
+
201: "Created",
|
|
1064
|
+
204: "No Content",
|
|
1065
|
+
301: "Moved Permanently",
|
|
1066
|
+
302: "Found",
|
|
1067
|
+
304: "Not Modified",
|
|
1068
|
+
400: "Bad Request",
|
|
1069
|
+
401: "Unauthorized",
|
|
1070
|
+
403: "Forbidden",
|
|
1071
|
+
404: "Not Found",
|
|
1072
|
+
500: "Internal Server Error",
|
|
1073
|
+
},
|
|
1074
|
+
};
|
|
1075
|
+
}
|
|
1076
|
+
export const http = createHttpModule("http");
|
|
1077
|
+
export const https = createHttpModule("https");
|
|
1078
|
+
export const http2 = {
|
|
1079
|
+
Http2ServerRequest: class Http2ServerRequest {
|
|
1080
|
+
},
|
|
1081
|
+
Http2ServerResponse: class Http2ServerResponse {
|
|
1082
|
+
},
|
|
1083
|
+
createServer() {
|
|
1084
|
+
throw new Error("http2.createServer is not supported in sandbox");
|
|
1085
|
+
},
|
|
1086
|
+
createSecureServer() {
|
|
1087
|
+
throw new Error("http2.createSecureServer is not supported in sandbox");
|
|
1088
|
+
},
|
|
1089
|
+
};
|
|
1090
|
+
// Export modules and make them available as globals for require()
|
|
1091
|
+
exposeCustomGlobal("_httpModule", http);
|
|
1092
|
+
exposeCustomGlobal("_httpsModule", https);
|
|
1093
|
+
exposeCustomGlobal("_http2Module", http2);
|
|
1094
|
+
exposeCustomGlobal("_dnsModule", dns);
|
|
1095
|
+
exposeCustomGlobal("_httpServerDispatch", dispatchServerRequest);
|
|
1096
|
+
// Make fetch API available globally
|
|
1097
|
+
globalThis.fetch = fetch;
|
|
1098
|
+
globalThis.Headers = Headers;
|
|
1099
|
+
globalThis.Request = Request;
|
|
1100
|
+
globalThis.Response = Response;
|
|
1101
|
+
if (typeof globalThis.Blob === "undefined") {
|
|
1102
|
+
// Minimal Blob stub used by server frameworks for instanceof checks.
|
|
1103
|
+
globalThis.Blob = class BlobStub {
|
|
1104
|
+
};
|
|
1105
|
+
}
|
|
1106
|
+
export default {
|
|
1107
|
+
fetch,
|
|
1108
|
+
Headers,
|
|
1109
|
+
Request,
|
|
1110
|
+
Response,
|
|
1111
|
+
dns,
|
|
1112
|
+
http,
|
|
1113
|
+
https,
|
|
1114
|
+
http2,
|
|
1115
|
+
IncomingMessage,
|
|
1116
|
+
ClientRequest,
|
|
1117
|
+
};
|