@secure-exec/core 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.
Files changed (81) hide show
  1. package/LICENSE +191 -0
  2. package/README.md +7 -0
  3. package/dist/bridge/active-handles.d.ts +21 -0
  4. package/dist/bridge/active-handles.js +60 -0
  5. package/dist/bridge/child-process.d.ts +90 -0
  6. package/dist/bridge/child-process.js +606 -0
  7. package/dist/bridge/fs.d.ts +281 -0
  8. package/dist/bridge/fs.js +2151 -0
  9. package/dist/bridge/index.d.ts +10 -0
  10. package/dist/bridge/index.js +41 -0
  11. package/dist/bridge/module.d.ts +75 -0
  12. package/dist/bridge/module.js +308 -0
  13. package/dist/bridge/network.d.ts +249 -0
  14. package/dist/bridge/network.js +1416 -0
  15. package/dist/bridge/os.d.ts +13 -0
  16. package/dist/bridge/os.js +256 -0
  17. package/dist/bridge/polyfills.d.ts +2 -0
  18. package/dist/bridge/polyfills.js +11 -0
  19. package/dist/bridge/process.d.ts +86 -0
  20. package/dist/bridge/process.js +938 -0
  21. package/dist/bridge-setup.d.ts +6 -0
  22. package/dist/bridge-setup.js +9 -0
  23. package/dist/bridge.js +11538 -0
  24. package/dist/esm-compiler.d.ts +14 -0
  25. package/dist/esm-compiler.js +68 -0
  26. package/dist/fs-helpers.d.ts +23 -0
  27. package/dist/fs-helpers.js +41 -0
  28. package/dist/generated/isolate-runtime.d.ts +19 -0
  29. package/dist/generated/isolate-runtime.js +21 -0
  30. package/dist/generated/polyfills.d.ts +82 -0
  31. package/dist/generated/polyfills.js +82 -0
  32. package/dist/index.d.ts +30 -0
  33. package/dist/index.js +25 -0
  34. package/dist/isolate-runtime/apply-custom-global-policy.js +54 -0
  35. package/dist/isolate-runtime/apply-timing-mitigation-freeze.js +44 -0
  36. package/dist/isolate-runtime/apply-timing-mitigation-off.js +14 -0
  37. package/dist/isolate-runtime/bridge-attach.js +29 -0
  38. package/dist/isolate-runtime/bridge-initial-globals.js +246 -0
  39. package/dist/isolate-runtime/eval-script-result.js +8 -0
  40. package/dist/isolate-runtime/global-exposure-helpers.js +36 -0
  41. package/dist/isolate-runtime/init-commonjs-module-globals.js +28 -0
  42. package/dist/isolate-runtime/override-process-cwd.js +8 -0
  43. package/dist/isolate-runtime/override-process-env.js +8 -0
  44. package/dist/isolate-runtime/require-setup.js +650 -0
  45. package/dist/isolate-runtime/set-commonjs-file-globals.js +36 -0
  46. package/dist/isolate-runtime/set-stdin-data.js +10 -0
  47. package/dist/isolate-runtime/setup-dynamic-import.js +64 -0
  48. package/dist/isolate-runtime/setup-fs-facade.js +48 -0
  49. package/dist/module-resolver.d.ts +25 -0
  50. package/dist/module-resolver.js +264 -0
  51. package/dist/package-bundler.d.ts +36 -0
  52. package/dist/package-bundler.js +497 -0
  53. package/dist/python-runtime.d.ts +16 -0
  54. package/dist/python-runtime.js +45 -0
  55. package/dist/runtime-driver.d.ts +62 -0
  56. package/dist/runtime-driver.js +1 -0
  57. package/dist/runtime.d.ts +31 -0
  58. package/dist/runtime.js +69 -0
  59. package/dist/shared/api-types.d.ts +71 -0
  60. package/dist/shared/api-types.js +1 -0
  61. package/dist/shared/bridge-contract.d.ts +302 -0
  62. package/dist/shared/bridge-contract.js +82 -0
  63. package/dist/shared/console-formatter.d.ts +22 -0
  64. package/dist/shared/console-formatter.js +157 -0
  65. package/dist/shared/constants.d.ts +3 -0
  66. package/dist/shared/constants.js +3 -0
  67. package/dist/shared/errors.d.ts +16 -0
  68. package/dist/shared/errors.js +21 -0
  69. package/dist/shared/esm-utils.d.ts +28 -0
  70. package/dist/shared/esm-utils.js +97 -0
  71. package/dist/shared/global-exposure.d.ts +38 -0
  72. package/dist/shared/global-exposure.js +406 -0
  73. package/dist/shared/in-memory-fs.d.ts +42 -0
  74. package/dist/shared/in-memory-fs.js +341 -0
  75. package/dist/shared/permissions.d.ts +38 -0
  76. package/dist/shared/permissions.js +283 -0
  77. package/dist/shared/require-setup.d.ts +6 -0
  78. package/dist/shared/require-setup.js +9 -0
  79. package/dist/types.d.ts +206 -0
  80. package/dist/types.js +1 -0
  81. package/package.json +107 -0
@@ -0,0 +1,1416 @@
1
+ // Network module polyfill for isolated-vm
2
+ // Provides fetch, http, https, and dns module emulation that bridges to host
3
+ import { exposeCustomGlobal } from "../shared/global-exposure.js";
4
+ // Fetch polyfill
5
+ export async function fetch(url, options = {}) {
6
+ if (typeof _networkFetchRaw === 'undefined') {
7
+ console.error('fetch requires NetworkAdapter to be configured');
8
+ throw new Error('fetch requires NetworkAdapter to be configured');
9
+ }
10
+ const optionsJson = JSON.stringify({
11
+ method: options.method || "GET",
12
+ headers: options.headers || {},
13
+ body: options.body || null,
14
+ });
15
+ const responseJson = await _networkFetchRaw.apply(undefined, [String(url), optionsJson], {
16
+ result: { promise: true },
17
+ });
18
+ const response = JSON.parse(responseJson);
19
+ // Create Response-like object
20
+ return {
21
+ ok: response.ok,
22
+ status: response.status,
23
+ statusText: response.statusText,
24
+ headers: new Map(Object.entries(response.headers || {})),
25
+ url: response.url || String(url),
26
+ redirected: response.redirected || false,
27
+ type: "basic",
28
+ async text() {
29
+ return response.body || "";
30
+ },
31
+ async json() {
32
+ return JSON.parse(response.body || "{}");
33
+ },
34
+ async arrayBuffer() {
35
+ // Not fully supported - return empty buffer
36
+ return new ArrayBuffer(0);
37
+ },
38
+ async blob() {
39
+ throw new Error("Blob not supported in sandbox");
40
+ },
41
+ clone() {
42
+ return { ...this };
43
+ },
44
+ };
45
+ }
46
+ // Headers class
47
+ export class Headers {
48
+ _headers = {};
49
+ constructor(init) {
50
+ if (init && init !== null) {
51
+ if (init instanceof Headers) {
52
+ this._headers = { ...init._headers };
53
+ }
54
+ else if (Array.isArray(init)) {
55
+ init.forEach(([key, value]) => {
56
+ this._headers[key.toLowerCase()] = value;
57
+ });
58
+ }
59
+ else if (typeof init === "object") {
60
+ Object.entries(init).forEach(([key, value]) => {
61
+ this._headers[key.toLowerCase()] = value;
62
+ });
63
+ }
64
+ }
65
+ }
66
+ get(name) {
67
+ return this._headers[name.toLowerCase()] || null;
68
+ }
69
+ set(name, value) {
70
+ this._headers[name.toLowerCase()] = value;
71
+ }
72
+ has(name) {
73
+ return name.toLowerCase() in this._headers;
74
+ }
75
+ delete(name) {
76
+ delete this._headers[name.toLowerCase()];
77
+ }
78
+ entries() {
79
+ return Object.entries(this._headers)[Symbol.iterator]();
80
+ }
81
+ [Symbol.iterator]() {
82
+ return this.entries();
83
+ }
84
+ keys() {
85
+ return Object.keys(this._headers)[Symbol.iterator]();
86
+ }
87
+ values() {
88
+ return Object.values(this._headers)[Symbol.iterator]();
89
+ }
90
+ forEach(callback) {
91
+ Object.entries(this._headers).forEach(([k, v]) => callback(v, k, this));
92
+ }
93
+ }
94
+ // Request class
95
+ export class Request {
96
+ url;
97
+ method;
98
+ headers;
99
+ body;
100
+ mode;
101
+ credentials;
102
+ cache;
103
+ redirect;
104
+ referrer;
105
+ integrity;
106
+ constructor(input, init = {}) {
107
+ this.url = typeof input === "string" ? input : input.url;
108
+ this.method = init.method || (typeof input !== "string" ? input.method : undefined) || "GET";
109
+ this.headers = new Headers(init.headers || (typeof input !== "string" ? input.headers : undefined));
110
+ this.body = init.body || null;
111
+ this.mode = init.mode || "cors";
112
+ this.credentials = init.credentials || "same-origin";
113
+ this.cache = init.cache || "default";
114
+ this.redirect = init.redirect || "follow";
115
+ this.referrer = init.referrer || "about:client";
116
+ this.integrity = init.integrity || "";
117
+ }
118
+ clone() {
119
+ return new Request(this.url, this);
120
+ }
121
+ }
122
+ // Response class
123
+ export class Response {
124
+ _body;
125
+ status;
126
+ statusText;
127
+ headers;
128
+ ok;
129
+ type;
130
+ url;
131
+ redirected;
132
+ constructor(body, init = {}) {
133
+ this._body = body || null;
134
+ this.status = init.status || 200;
135
+ this.statusText = init.statusText || "OK";
136
+ this.headers = new Headers(init.headers);
137
+ this.ok = this.status >= 200 && this.status < 300;
138
+ this.type = "default";
139
+ this.url = "";
140
+ this.redirected = false;
141
+ }
142
+ async text() {
143
+ return String(this._body || "");
144
+ }
145
+ async json() {
146
+ return JSON.parse(this._body || "{}");
147
+ }
148
+ clone() {
149
+ return new Response(this._body, { status: this.status, statusText: this.statusText });
150
+ }
151
+ static error() {
152
+ return new Response(null, { status: 0, statusText: "" });
153
+ }
154
+ static redirect(url, status = 302) {
155
+ return new Response(null, { status, headers: { Location: url } });
156
+ }
157
+ }
158
+ // DNS module polyfill
159
+ export const dns = {
160
+ lookup(hostname, options, callback) {
161
+ let cb = callback;
162
+ if (typeof options === "function") {
163
+ cb = options;
164
+ }
165
+ _networkDnsLookupRaw
166
+ .apply(undefined, [hostname], { result: { promise: true } })
167
+ .then((resultJson) => {
168
+ const result = JSON.parse(resultJson);
169
+ if (result.error) {
170
+ const err = new Error(result.error);
171
+ err.code = result.code || "ENOTFOUND";
172
+ cb?.(err);
173
+ }
174
+ else {
175
+ cb?.(null, result.address, result.family);
176
+ }
177
+ })
178
+ .catch((err) => {
179
+ cb?.(err);
180
+ });
181
+ },
182
+ resolve(hostname, rrtype, callback) {
183
+ let cb = callback;
184
+ if (typeof rrtype === "function") {
185
+ cb = rrtype;
186
+ }
187
+ // Simplified - just do lookup for A records
188
+ dns.lookup(hostname, (err, address) => {
189
+ if (err) {
190
+ cb?.(err);
191
+ }
192
+ else {
193
+ cb?.(null, address ? [address] : []);
194
+ }
195
+ });
196
+ },
197
+ resolve4(hostname, callback) {
198
+ dns.resolve(hostname, "A", callback);
199
+ },
200
+ resolve6(hostname, callback) {
201
+ dns.resolve(hostname, "AAAA", callback);
202
+ },
203
+ promises: {
204
+ lookup(hostname, _options) {
205
+ return new Promise((resolve, reject) => {
206
+ dns.lookup(hostname, _options, (err, address, family) => {
207
+ if (err)
208
+ reject(err);
209
+ else
210
+ resolve({ address: address || "", family: family || 4 });
211
+ });
212
+ });
213
+ },
214
+ resolve(hostname, rrtype) {
215
+ return new Promise((resolve, reject) => {
216
+ dns.resolve(hostname, rrtype || "A", (err, addresses) => {
217
+ if (err)
218
+ reject(err);
219
+ else
220
+ resolve(addresses || []);
221
+ });
222
+ });
223
+ },
224
+ },
225
+ };
226
+ // Module-level globalAgent used by ClientRequest when no agent option is provided.
227
+ // Initialized lazily after Agent class is defined; set by createHttpModule().
228
+ let _moduleGlobalAgent = null;
229
+ /**
230
+ * Polyfill of Node.js `http.IncomingMessage` (client-side response). Buffers
231
+ * the response body eagerly and emits `data`/`end` events on listener
232
+ * registration (flowing mode). Supports base64 binary decoding via
233
+ * `x-body-encoding` header.
234
+ */
235
+ export class IncomingMessage {
236
+ headers;
237
+ rawHeaders;
238
+ trailers;
239
+ rawTrailers;
240
+ httpVersion;
241
+ httpVersionMajor;
242
+ httpVersionMinor;
243
+ method;
244
+ url;
245
+ statusCode;
246
+ statusMessage;
247
+ _body;
248
+ _isBinary;
249
+ _listeners;
250
+ complete;
251
+ aborted;
252
+ socket;
253
+ _bodyConsumed;
254
+ _ended;
255
+ _flowing;
256
+ readable;
257
+ readableEnded;
258
+ readableFlowing;
259
+ destroyed;
260
+ _encoding;
261
+ constructor(response) {
262
+ this.headers = response?.headers || {};
263
+ this.rawHeaders = [];
264
+ if (this.headers && typeof this.headers === "object") {
265
+ Object.entries(this.headers).forEach(([k, v]) => {
266
+ this.rawHeaders.push(k, v);
267
+ });
268
+ }
269
+ // Populate trailers if provided
270
+ if (response?.trailers && typeof response.trailers === "object") {
271
+ this.trailers = response.trailers;
272
+ this.rawTrailers = [];
273
+ Object.entries(response.trailers).forEach(([k, v]) => {
274
+ this.rawTrailers.push(k, v);
275
+ });
276
+ }
277
+ else {
278
+ this.trailers = {};
279
+ this.rawTrailers = [];
280
+ }
281
+ this.httpVersion = "1.1";
282
+ this.httpVersionMajor = 1;
283
+ this.httpVersionMinor = 1;
284
+ this.method = null;
285
+ this.url = response?.url || "";
286
+ this.statusCode = response?.status;
287
+ this.statusMessage = response?.statusText;
288
+ // Decode base64 body if x-body-encoding header is set
289
+ const bodyEncoding = this.headers['x-body-encoding'];
290
+ if (bodyEncoding === 'base64' && response?.body && typeof Buffer !== 'undefined') {
291
+ this._body = Buffer.from(response.body, 'base64').toString('binary');
292
+ this._isBinary = true;
293
+ }
294
+ else {
295
+ this._body = response?.body || "";
296
+ this._isBinary = false;
297
+ }
298
+ this._listeners = {};
299
+ this.complete = false;
300
+ this.aborted = false;
301
+ this.socket = null;
302
+ this._bodyConsumed = false;
303
+ this._ended = false;
304
+ this._flowing = false;
305
+ this.readable = true;
306
+ this.readableEnded = false;
307
+ this.readableFlowing = null;
308
+ this.destroyed = false;
309
+ }
310
+ on(event, listener) {
311
+ if (!this._listeners[event])
312
+ this._listeners[event] = [];
313
+ this._listeners[event].push(listener);
314
+ // When 'data' listener is added, start flowing mode
315
+ // Note: We check for non-empty body (this._body.length > 0) because we need to
316
+ // emit 'end' even for empty responses, but only emit 'data' if there's actual data
317
+ if (event === "data" && !this._bodyConsumed) {
318
+ this._flowing = true;
319
+ this.readableFlowing = true;
320
+ // Emit data in next microtask
321
+ Promise.resolve().then(() => {
322
+ if (!this._bodyConsumed) {
323
+ this._bodyConsumed = true;
324
+ // Only emit data if there's actual content
325
+ if (this._body && this._body.length > 0) {
326
+ let buf;
327
+ if (typeof Buffer !== "undefined") {
328
+ // For binary data, use 'binary' encoding to preserve bytes
329
+ buf = this._isBinary ? Buffer.from(this._body, 'binary') : Buffer.from(this._body);
330
+ }
331
+ else {
332
+ buf = this._body;
333
+ }
334
+ this.emit("data", buf);
335
+ }
336
+ // Always emit end after data (even if no data was emitted)
337
+ Promise.resolve().then(() => {
338
+ if (!this._ended) {
339
+ this._ended = true;
340
+ this.complete = true;
341
+ this.readable = false;
342
+ this.readableEnded = true;
343
+ this.emit("end");
344
+ }
345
+ });
346
+ }
347
+ });
348
+ }
349
+ // If 'end' listener is added after data was already consumed, emit end
350
+ if (event === "end" && this._bodyConsumed && !this._ended) {
351
+ Promise.resolve().then(() => {
352
+ if (!this._ended) {
353
+ this._ended = true;
354
+ this.complete = true;
355
+ this.readable = false;
356
+ this.readableEnded = true;
357
+ listener();
358
+ }
359
+ });
360
+ }
361
+ return this;
362
+ }
363
+ once(event, listener) {
364
+ const wrapper = (...args) => {
365
+ this.off(event, wrapper);
366
+ listener(...args);
367
+ };
368
+ wrapper._originalListener = listener;
369
+ return this.on(event, wrapper);
370
+ }
371
+ off(event, listener) {
372
+ if (this._listeners[event]) {
373
+ const idx = this._listeners[event].findIndex((fn) => fn === listener || fn._originalListener === listener);
374
+ if (idx !== -1)
375
+ this._listeners[event].splice(idx, 1);
376
+ }
377
+ return this;
378
+ }
379
+ removeListener(event, listener) {
380
+ return this.off(event, listener);
381
+ }
382
+ removeAllListeners(event) {
383
+ if (event) {
384
+ delete this._listeners[event];
385
+ }
386
+ else {
387
+ this._listeners = {};
388
+ }
389
+ return this;
390
+ }
391
+ emit(event, ...args) {
392
+ const handlers = this._listeners[event];
393
+ if (handlers) {
394
+ handlers.slice().forEach((fn) => fn(...args));
395
+ }
396
+ return handlers !== undefined && handlers.length > 0;
397
+ }
398
+ setEncoding(encoding) {
399
+ this._encoding = encoding;
400
+ return this;
401
+ }
402
+ read(_size) {
403
+ if (this._bodyConsumed)
404
+ return null;
405
+ this._bodyConsumed = true;
406
+ let buf;
407
+ if (typeof Buffer !== "undefined") {
408
+ buf = this._isBinary ? Buffer.from(this._body, 'binary') : Buffer.from(this._body);
409
+ }
410
+ else {
411
+ buf = this._body;
412
+ }
413
+ // Schedule end event
414
+ Promise.resolve().then(() => {
415
+ if (!this._ended) {
416
+ this._ended = true;
417
+ this.complete = true;
418
+ this.readable = false;
419
+ this.readableEnded = true;
420
+ this.emit("end");
421
+ }
422
+ });
423
+ return buf;
424
+ }
425
+ pipe(dest) {
426
+ let buf;
427
+ if (typeof Buffer !== "undefined") {
428
+ buf = this._isBinary ? Buffer.from(this._body || "", 'binary') : Buffer.from(this._body || "");
429
+ }
430
+ else {
431
+ buf = this._body || "";
432
+ }
433
+ if (typeof dest.write === "function" && (typeof buf === "string" ? buf.length : buf.length) > 0) {
434
+ dest.write(buf);
435
+ }
436
+ if (typeof dest.end === "function") {
437
+ Promise.resolve().then(() => dest.end());
438
+ }
439
+ this._bodyConsumed = true;
440
+ this._ended = true;
441
+ this.complete = true;
442
+ this.readable = false;
443
+ this.readableEnded = true;
444
+ return dest;
445
+ }
446
+ pause() {
447
+ this._flowing = false;
448
+ this.readableFlowing = false;
449
+ return this;
450
+ }
451
+ resume() {
452
+ this._flowing = true;
453
+ this.readableFlowing = true;
454
+ if (!this._bodyConsumed && this._body) {
455
+ Promise.resolve().then(() => {
456
+ if (!this._bodyConsumed) {
457
+ this._bodyConsumed = true;
458
+ let buf;
459
+ if (typeof Buffer !== "undefined") {
460
+ buf = this._isBinary ? Buffer.from(this._body, 'binary') : Buffer.from(this._body);
461
+ }
462
+ else {
463
+ buf = this._body;
464
+ }
465
+ this.emit("data", buf);
466
+ Promise.resolve().then(() => {
467
+ if (!this._ended) {
468
+ this._ended = true;
469
+ this.complete = true;
470
+ this.readable = false;
471
+ this.readableEnded = true;
472
+ this.emit("end");
473
+ }
474
+ });
475
+ }
476
+ });
477
+ }
478
+ return this;
479
+ }
480
+ unpipe(_dest) {
481
+ return this;
482
+ }
483
+ destroy(err) {
484
+ this.destroyed = true;
485
+ this.readable = false;
486
+ if (err)
487
+ this.emit("error", err);
488
+ this.emit("close");
489
+ return this;
490
+ }
491
+ [Symbol.asyncIterator]() {
492
+ const self = this;
493
+ let dataEmitted = false;
494
+ let ended = false;
495
+ return {
496
+ async next() {
497
+ if (ended || self._ended) {
498
+ return { done: true, value: undefined };
499
+ }
500
+ if (!dataEmitted && !self._bodyConsumed) {
501
+ dataEmitted = true;
502
+ self._bodyConsumed = true;
503
+ let buf;
504
+ if (typeof Buffer !== "undefined") {
505
+ buf = self._isBinary ? Buffer.from(self._body || "", 'binary') : Buffer.from(self._body || "");
506
+ }
507
+ else {
508
+ buf = self._body || "";
509
+ }
510
+ return { done: false, value: buf };
511
+ }
512
+ ended = true;
513
+ self._ended = true;
514
+ self.complete = true;
515
+ self.readable = false;
516
+ self.readableEnded = true;
517
+ return { done: true, value: undefined };
518
+ },
519
+ return() {
520
+ ended = true;
521
+ return Promise.resolve({ done: true, value: undefined });
522
+ },
523
+ throw(err) {
524
+ ended = true;
525
+ self.emit("error", err);
526
+ return Promise.resolve({ done: true, value: undefined });
527
+ },
528
+ };
529
+ }
530
+ }
531
+ /**
532
+ * Polyfill of Node.js `http.ClientRequest`. Executes the request asynchronously
533
+ * via the `_networkHttpRequestRaw` bridge and emits a `response` event with
534
+ * an IncomingMessage. Supports Agent-based connection pooling, socket events,
535
+ * HTTP upgrade (101), and trailer headers.
536
+ */
537
+ export class ClientRequest {
538
+ _options;
539
+ _callback;
540
+ _listeners = {};
541
+ _body = "";
542
+ _ended = false;
543
+ _agent;
544
+ _hostKey;
545
+ socket;
546
+ finished = false;
547
+ aborted = false;
548
+ constructor(options, callback) {
549
+ this._options = options;
550
+ this._callback = callback;
551
+ // Resolve agent: false = no agent, undefined = globalAgent, or explicit Agent
552
+ const agentOpt = options.agent;
553
+ if (agentOpt === false) {
554
+ this._agent = null;
555
+ }
556
+ else if (agentOpt instanceof Agent) {
557
+ this._agent = agentOpt;
558
+ }
559
+ else {
560
+ this._agent = _moduleGlobalAgent;
561
+ }
562
+ this._hostKey = this._agent ? this._agent._getHostKey(options) : "";
563
+ // Create socket-like object and emit 'socket' event
564
+ this.socket = new FakeSocket({
565
+ host: (options.hostname || options.host || "localhost"),
566
+ port: Number(options.port) || 80,
567
+ });
568
+ Promise.resolve().then(() => this._emit("socket", this.socket));
569
+ // Execute request asynchronously
570
+ Promise.resolve().then(() => this._execute());
571
+ }
572
+ async _execute() {
573
+ // Acquire agent slot before executing
574
+ if (this._agent) {
575
+ await this._agent._acquireSlot(this._hostKey);
576
+ }
577
+ try {
578
+ if (typeof _networkHttpRequestRaw === 'undefined') {
579
+ console.error('http/https request requires NetworkAdapter to be configured');
580
+ throw new Error('http/https request requires NetworkAdapter to be configured');
581
+ }
582
+ const url = this._buildUrl();
583
+ const optionsJson = JSON.stringify({
584
+ method: this._options.method || "GET",
585
+ headers: this._options.headers || {},
586
+ body: this._body || null,
587
+ });
588
+ const responseJson = await _networkHttpRequestRaw.apply(undefined, [url, optionsJson], {
589
+ result: { promise: true },
590
+ });
591
+ const response = JSON.parse(responseJson);
592
+ this.finished = true;
593
+ // 101 Switching Protocols → fire 'upgrade' event
594
+ if (response.status === 101) {
595
+ const res = new IncomingMessage(response);
596
+ const head = typeof Buffer !== "undefined" ? Buffer.alloc(0) : new Uint8Array(0);
597
+ this._emit("upgrade", res, this.socket, head);
598
+ return;
599
+ }
600
+ const res = new IncomingMessage(response);
601
+ if (this._callback) {
602
+ this._callback(res);
603
+ }
604
+ this._emit("response", res);
605
+ }
606
+ catch (err) {
607
+ this._emit("error", err);
608
+ }
609
+ finally {
610
+ // Release agent slot
611
+ if (this._agent) {
612
+ this._agent._releaseSlot(this._hostKey);
613
+ }
614
+ }
615
+ }
616
+ _buildUrl() {
617
+ const opts = this._options;
618
+ const protocol = opts.protocol || (opts.port === 443 ? "https:" : "http:");
619
+ const host = opts.hostname || opts.host || "localhost";
620
+ const port = opts.port ? ":" + opts.port : "";
621
+ const path = opts.path || "/";
622
+ return protocol + "//" + host + port + path;
623
+ }
624
+ on(event, listener) {
625
+ if (!this._listeners[event])
626
+ this._listeners[event] = [];
627
+ this._listeners[event].push(listener);
628
+ return this;
629
+ }
630
+ once(event, listener) {
631
+ const wrapper = (...args) => {
632
+ this.off(event, wrapper);
633
+ listener(...args);
634
+ };
635
+ return this.on(event, wrapper);
636
+ }
637
+ off(event, listener) {
638
+ if (this._listeners[event]) {
639
+ const idx = this._listeners[event].indexOf(listener);
640
+ if (idx !== -1)
641
+ this._listeners[event].splice(idx, 1);
642
+ }
643
+ return this;
644
+ }
645
+ _emit(event, ...args) {
646
+ if (this._listeners[event]) {
647
+ this._listeners[event].forEach((fn) => fn(...args));
648
+ }
649
+ }
650
+ write(data) {
651
+ this._body += data;
652
+ return true;
653
+ }
654
+ end(data) {
655
+ if (data)
656
+ this._body += data;
657
+ this._ended = true;
658
+ return this;
659
+ }
660
+ abort() {
661
+ this.aborted = true;
662
+ }
663
+ setTimeout(_timeout) {
664
+ return this;
665
+ }
666
+ setNoDelay() {
667
+ return this;
668
+ }
669
+ setSocketKeepAlive() {
670
+ return this;
671
+ }
672
+ flushHeaders() {
673
+ // no-op
674
+ }
675
+ }
676
+ // Minimal socket-like object emitted by ClientRequest 'socket' event
677
+ class FakeSocket {
678
+ remoteAddress;
679
+ remotePort;
680
+ localAddress = "127.0.0.1";
681
+ localPort = 0;
682
+ connecting = false;
683
+ destroyed = false;
684
+ writable = true;
685
+ readable = true;
686
+ _listeners = {};
687
+ constructor(options) {
688
+ this.remoteAddress = options?.host || "127.0.0.1";
689
+ this.remotePort = options?.port || 80;
690
+ }
691
+ setTimeout(_ms, _cb) { return this; }
692
+ setNoDelay(_noDelay) { return this; }
693
+ setKeepAlive(_enable, _delay) { return this; }
694
+ on(event, listener) {
695
+ if (!this._listeners[event])
696
+ this._listeners[event] = [];
697
+ this._listeners[event].push(listener);
698
+ return this;
699
+ }
700
+ once(event, listener) {
701
+ const wrapper = (...args) => {
702
+ this.off(event, wrapper);
703
+ listener(...args);
704
+ };
705
+ return this.on(event, wrapper);
706
+ }
707
+ off(event, listener) {
708
+ if (this._listeners[event]) {
709
+ const idx = this._listeners[event].indexOf(listener);
710
+ if (idx !== -1)
711
+ this._listeners[event].splice(idx, 1);
712
+ }
713
+ return this;
714
+ }
715
+ removeListener(event, listener) {
716
+ return this.off(event, listener);
717
+ }
718
+ emit(event, ...args) {
719
+ const handlers = this._listeners[event];
720
+ if (handlers)
721
+ handlers.slice().forEach((fn) => fn(...args));
722
+ return handlers !== undefined && handlers.length > 0;
723
+ }
724
+ write(_data) { return true; }
725
+ end() { return this; }
726
+ destroy() {
727
+ this.destroyed = true;
728
+ this.writable = false;
729
+ this.readable = false;
730
+ return this;
731
+ }
732
+ }
733
+ // HTTP Agent with connection pooling via maxSockets
734
+ class Agent {
735
+ maxSockets;
736
+ maxFreeSockets;
737
+ keepAlive;
738
+ keepAliveMsecs;
739
+ timeout;
740
+ requests;
741
+ sockets;
742
+ freeSockets;
743
+ // Per-host active count and pending queue
744
+ _activeCounts = new Map();
745
+ _queues = new Map();
746
+ constructor(options) {
747
+ this.keepAlive = options?.keepAlive ?? false;
748
+ this.keepAliveMsecs = options?.keepAliveMsecs ?? 1000;
749
+ this.maxSockets = options?.maxSockets ?? Infinity;
750
+ this.maxFreeSockets = options?.maxFreeSockets ?? 256;
751
+ this.timeout = options?.timeout ?? -1;
752
+ this.requests = {};
753
+ this.sockets = {};
754
+ this.freeSockets = {};
755
+ }
756
+ _getHostKey(options) {
757
+ const host = options.hostname || options.host || "localhost";
758
+ const port = options.port || 80;
759
+ return `${host}:${port}`;
760
+ }
761
+ // Wait for an available slot; resolves immediately if under maxSockets
762
+ _acquireSlot(hostKey) {
763
+ const active = this._activeCounts.get(hostKey) || 0;
764
+ if (active < this.maxSockets) {
765
+ this._activeCounts.set(hostKey, active + 1);
766
+ return Promise.resolve();
767
+ }
768
+ return new Promise((resolve) => {
769
+ let queue = this._queues.get(hostKey);
770
+ if (!queue) {
771
+ queue = [];
772
+ this._queues.set(hostKey, queue);
773
+ }
774
+ queue.push(resolve);
775
+ });
776
+ }
777
+ // Release a slot; dequeues next pending request if any
778
+ _releaseSlot(hostKey) {
779
+ const queue = this._queues.get(hostKey);
780
+ if (queue && queue.length > 0) {
781
+ const next = queue.shift();
782
+ if (queue.length === 0)
783
+ this._queues.delete(hostKey);
784
+ next();
785
+ }
786
+ else {
787
+ const active = this._activeCounts.get(hostKey) || 1;
788
+ const next = active - 1;
789
+ if (next <= 0)
790
+ this._activeCounts.delete(hostKey);
791
+ else
792
+ this._activeCounts.set(hostKey, next);
793
+ }
794
+ }
795
+ destroy() {
796
+ this._activeCounts.clear();
797
+ for (const [, queue] of this._queues) {
798
+ queue.length = 0;
799
+ }
800
+ this._queues.clear();
801
+ }
802
+ }
803
+ let nextServerId = 1;
804
+ const serverRequestListeners = new Map();
805
+ class ServerIncomingMessage {
806
+ headers;
807
+ rawHeaders;
808
+ method;
809
+ url;
810
+ socket;
811
+ connection;
812
+ rawBody;
813
+ destroyed = false;
814
+ errored;
815
+ readable = true;
816
+ httpVersion = "1.1";
817
+ httpVersionMajor = 1;
818
+ httpVersionMinor = 1;
819
+ complete = true;
820
+ // Readable stream state stub for frameworks that inspect internal state
821
+ _readableState = { flowing: null, length: 0, ended: false, objectMode: false };
822
+ _listeners = {};
823
+ constructor(request) {
824
+ this.headers = request.headers || {};
825
+ this.rawHeaders = request.rawHeaders || [];
826
+ if (!Array.isArray(this.rawHeaders) || this.rawHeaders.length % 2 !== 0) {
827
+ this.rawHeaders = [];
828
+ }
829
+ this.method = request.method || "GET";
830
+ this.url = request.url || "/";
831
+ const fakeSocket = {
832
+ encrypted: false,
833
+ remoteAddress: "127.0.0.1",
834
+ remotePort: 0,
835
+ writable: true,
836
+ on() { return fakeSocket; },
837
+ once() { return fakeSocket; },
838
+ removeListener() { return fakeSocket; },
839
+ destroy() { },
840
+ end() { },
841
+ };
842
+ this.socket = fakeSocket;
843
+ this.connection = fakeSocket;
844
+ const rawHost = this.headers.host;
845
+ if (typeof rawHost === "string" && rawHost.includes(",")) {
846
+ this.headers.host = rawHost.split(",")[0].trim();
847
+ }
848
+ if (!this.headers.host) {
849
+ this.headers.host = "127.0.0.1";
850
+ }
851
+ if (this.rawHeaders.length === 0) {
852
+ Object.entries(this.headers).forEach(([key, value]) => {
853
+ this.rawHeaders.push(key, value);
854
+ });
855
+ }
856
+ if (request.bodyBase64 && typeof Buffer !== "undefined") {
857
+ this.rawBody = Buffer.from(request.bodyBase64, "base64");
858
+ }
859
+ }
860
+ on(event, listener) {
861
+ if (!this._listeners[event])
862
+ this._listeners[event] = [];
863
+ this._listeners[event].push(listener);
864
+ return this;
865
+ }
866
+ once(event, listener) {
867
+ const wrapped = (...args) => {
868
+ this.off(event, wrapped);
869
+ listener(...args);
870
+ };
871
+ return this.on(event, wrapped);
872
+ }
873
+ off(event, listener) {
874
+ const listeners = this._listeners[event];
875
+ if (!listeners)
876
+ return this;
877
+ const index = listeners.indexOf(listener);
878
+ if (index !== -1)
879
+ listeners.splice(index, 1);
880
+ return this;
881
+ }
882
+ removeListener(event, listener) {
883
+ return this.off(event, listener);
884
+ }
885
+ emit(event, ...args) {
886
+ const listeners = this._listeners[event];
887
+ if (!listeners || listeners.length === 0)
888
+ return false;
889
+ listeners.slice().forEach((fn) => fn(...args));
890
+ return true;
891
+ }
892
+ // Readable stream stubs for framework compatibility
893
+ unpipe() { return this; }
894
+ pause() { return this; }
895
+ resume() { return this; }
896
+ read() { return null; }
897
+ pipe(dest) { return dest; }
898
+ isPaused() { return false; }
899
+ setEncoding() { return this; }
900
+ destroy(err) {
901
+ this.destroyed = true;
902
+ this.errored = err;
903
+ if (err) {
904
+ this.emit("error", err);
905
+ }
906
+ this.emit("close");
907
+ return this;
908
+ }
909
+ }
910
+ /**
911
+ * Sandbox-side response writer for HTTP server requests. Collects headers and
912
+ * body chunks, then serializes to JSON for transfer back to the host.
913
+ */
914
+ class ServerResponseBridge {
915
+ statusCode = 200;
916
+ statusMessage = "OK";
917
+ headersSent = false;
918
+ writable = true;
919
+ writableFinished = false;
920
+ _headers = new Map();
921
+ _chunks = [];
922
+ _listeners = {};
923
+ _closedPromise;
924
+ _resolveClosed = null;
925
+ constructor() {
926
+ this._closedPromise = new Promise((resolve) => {
927
+ this._resolveClosed = resolve;
928
+ });
929
+ }
930
+ on(event, listener) {
931
+ if (!this._listeners[event])
932
+ this._listeners[event] = [];
933
+ this._listeners[event].push(listener);
934
+ return this;
935
+ }
936
+ once(event, listener) {
937
+ const wrapped = (...args) => {
938
+ this.off(event, wrapped);
939
+ listener(...args);
940
+ };
941
+ return this.on(event, wrapped);
942
+ }
943
+ off(event, listener) {
944
+ const listeners = this._listeners[event];
945
+ if (!listeners)
946
+ return this;
947
+ const index = listeners.indexOf(listener);
948
+ if (index !== -1)
949
+ listeners.splice(index, 1);
950
+ return this;
951
+ }
952
+ removeListener(event, listener) {
953
+ return this.off(event, listener);
954
+ }
955
+ emit(event, ...args) {
956
+ const listeners = this._listeners[event];
957
+ if (!listeners || listeners.length === 0)
958
+ return false;
959
+ listeners.slice().forEach((fn) => fn(...args));
960
+ return true;
961
+ }
962
+ _emit(event, ...args) {
963
+ this.emit(event, ...args);
964
+ }
965
+ writeHead(statusCode, headers) {
966
+ this.statusCode = statusCode;
967
+ if (headers) {
968
+ if (Array.isArray(headers)) {
969
+ headers.forEach(([key, value]) => this.setHeader(key, value));
970
+ }
971
+ else {
972
+ Object.entries(headers).forEach(([key, value]) => this.setHeader(key, value));
973
+ }
974
+ }
975
+ this.headersSent = true;
976
+ return this;
977
+ }
978
+ setHeader(name, value) {
979
+ const normalized = Array.isArray(value) ? value.join(", ") : String(value);
980
+ this._headers.set(name.toLowerCase(), normalized);
981
+ return this;
982
+ }
983
+ getHeader(name) {
984
+ return this._headers.get(name.toLowerCase());
985
+ }
986
+ hasHeader(name) {
987
+ return this._headers.has(name.toLowerCase());
988
+ }
989
+ removeHeader(name) {
990
+ this._headers.delete(name.toLowerCase());
991
+ }
992
+ write(chunk) {
993
+ if (chunk == null)
994
+ return true;
995
+ this.headersSent = true;
996
+ if (typeof chunk === "string") {
997
+ this._chunks.push(Buffer.from(chunk));
998
+ }
999
+ else {
1000
+ this._chunks.push(chunk);
1001
+ }
1002
+ return true;
1003
+ }
1004
+ end(chunk) {
1005
+ if (chunk != null) {
1006
+ this.write(chunk);
1007
+ }
1008
+ this._finalize();
1009
+ return this;
1010
+ }
1011
+ getHeaderNames() {
1012
+ return Array.from(this._headers.keys());
1013
+ }
1014
+ getHeaders() {
1015
+ const result = {};
1016
+ for (const [key, value] of this._headers)
1017
+ result[key] = value;
1018
+ return result;
1019
+ }
1020
+ // Writable stream state stub for frameworks that inspect internal state
1021
+ _writableState = { length: 0, ended: false, finished: false, objectMode: false, corked: 0 };
1022
+ // Fake socket for frameworks that access res.socket/res.connection
1023
+ socket = {
1024
+ writable: true,
1025
+ on: () => this.socket,
1026
+ once: () => this.socket,
1027
+ removeListener: () => this.socket,
1028
+ destroy: () => { },
1029
+ end: () => { },
1030
+ cork: () => { },
1031
+ uncork: () => { },
1032
+ write: () => true,
1033
+ };
1034
+ connection = this.socket;
1035
+ // Node.js http.ServerResponse socket/stream compatibility stubs
1036
+ assignSocket() { }
1037
+ detachSocket() { }
1038
+ writeContinue() { }
1039
+ writeProcessing() { }
1040
+ addTrailers() { }
1041
+ cork() { }
1042
+ uncork() { }
1043
+ setTimeout(_msecs) { return this; }
1044
+ flushHeaders() {
1045
+ this.headersSent = true;
1046
+ }
1047
+ destroy(err) {
1048
+ if (err) {
1049
+ this._emit("error", err);
1050
+ }
1051
+ this._finalize();
1052
+ }
1053
+ async waitForClose() {
1054
+ await this._closedPromise;
1055
+ }
1056
+ serialize() {
1057
+ const bodyBuffer = this._chunks.length > 0 ? Buffer.concat(this._chunks) : Buffer.alloc(0);
1058
+ return {
1059
+ status: this.statusCode,
1060
+ headers: Array.from(this._headers.entries()),
1061
+ body: bodyBuffer.toString("base64"),
1062
+ bodyEncoding: "base64",
1063
+ };
1064
+ }
1065
+ _finalize() {
1066
+ if (this.writableFinished) {
1067
+ return;
1068
+ }
1069
+ this.writableFinished = true;
1070
+ this.writable = false;
1071
+ this._emit("finish");
1072
+ this._emit("close");
1073
+ this._resolveClosed?.();
1074
+ this._resolveClosed = null;
1075
+ }
1076
+ }
1077
+ /**
1078
+ * Polyfill of Node.js `http.Server`. Delegates actual listening to the host
1079
+ * via the `_networkHttpServerListenRaw` bridge. Incoming requests are
1080
+ * dispatched through `_httpServerDispatch` which invokes the request listener
1081
+ * inside the isolate. Registers an active handle to keep the sandbox alive.
1082
+ */
1083
+ class Server {
1084
+ listening = false;
1085
+ _listeners = {};
1086
+ _serverId;
1087
+ _listenPromise = null;
1088
+ _address = null;
1089
+ _handleId = null;
1090
+ constructor(requestListener) {
1091
+ this._serverId = nextServerId++;
1092
+ if (requestListener) {
1093
+ serverRequestListeners.set(this._serverId, requestListener);
1094
+ }
1095
+ else {
1096
+ serverRequestListeners.set(this._serverId, () => undefined);
1097
+ }
1098
+ }
1099
+ _emit(event, ...args) {
1100
+ const listeners = this._listeners[event];
1101
+ if (!listeners || listeners.length === 0)
1102
+ return;
1103
+ listeners.slice().forEach((listener) => listener(...args));
1104
+ }
1105
+ async _start(port, hostname) {
1106
+ if (typeof _networkHttpServerListenRaw === "undefined") {
1107
+ throw new Error("http.createServer requires NetworkAdapter.httpServerListen support");
1108
+ }
1109
+ const resultJson = await _networkHttpServerListenRaw.apply(undefined, [JSON.stringify({ serverId: this._serverId, port, hostname })], { result: { promise: true } });
1110
+ const result = JSON.parse(resultJson);
1111
+ this._address = result.address;
1112
+ this.listening = true;
1113
+ this._handleId = `http-server:${this._serverId}`;
1114
+ if (typeof _registerHandle === "function") {
1115
+ _registerHandle(this._handleId, "http server");
1116
+ }
1117
+ }
1118
+ listen(portOrCb, hostOrCb, cb) {
1119
+ const port = typeof portOrCb === "number" ? portOrCb : undefined;
1120
+ const hostname = typeof hostOrCb === "string" ? hostOrCb : undefined;
1121
+ const callback = typeof cb === "function"
1122
+ ? cb
1123
+ : typeof hostOrCb === "function"
1124
+ ? hostOrCb
1125
+ : typeof portOrCb === "function"
1126
+ ? portOrCb
1127
+ : undefined;
1128
+ if (!this._listenPromise) {
1129
+ this._listenPromise = this._start(port, hostname)
1130
+ .then(() => {
1131
+ this._emit("listening");
1132
+ callback?.();
1133
+ })
1134
+ .catch((error) => {
1135
+ this._emit("error", error);
1136
+ });
1137
+ }
1138
+ return this;
1139
+ }
1140
+ close(cb) {
1141
+ const run = async () => {
1142
+ try {
1143
+ if (this._listenPromise) {
1144
+ await this._listenPromise;
1145
+ }
1146
+ if (this.listening && typeof _networkHttpServerCloseRaw !== "undefined") {
1147
+ await _networkHttpServerCloseRaw.apply(undefined, [this._serverId], {
1148
+ result: { promise: true },
1149
+ });
1150
+ }
1151
+ this.listening = false;
1152
+ this._address = null;
1153
+ if (this._handleId && typeof _unregisterHandle === "function") {
1154
+ _unregisterHandle(this._handleId);
1155
+ }
1156
+ this._handleId = null;
1157
+ cb?.();
1158
+ this._emit("close");
1159
+ }
1160
+ catch (err) {
1161
+ const error = err instanceof Error ? err : new Error(String(err));
1162
+ cb?.(error);
1163
+ this._emit("error", error);
1164
+ }
1165
+ };
1166
+ void run();
1167
+ return this;
1168
+ }
1169
+ address() {
1170
+ return this._address;
1171
+ }
1172
+ on(event, listener) {
1173
+ if (!this._listeners[event])
1174
+ this._listeners[event] = [];
1175
+ this._listeners[event].push(listener);
1176
+ return this;
1177
+ }
1178
+ once(event, listener) {
1179
+ const wrapped = (...args) => {
1180
+ this.off(event, wrapped);
1181
+ listener(...args);
1182
+ };
1183
+ return this.on(event, wrapped);
1184
+ }
1185
+ off(event, listener) {
1186
+ const listeners = this._listeners[event];
1187
+ if (!listeners)
1188
+ return this;
1189
+ const index = listeners.indexOf(listener);
1190
+ if (index !== -1)
1191
+ listeners.splice(index, 1);
1192
+ return this;
1193
+ }
1194
+ removeListener(event, listener) {
1195
+ return this.off(event, listener);
1196
+ }
1197
+ removeAllListeners(event) {
1198
+ if (event) {
1199
+ delete this._listeners[event];
1200
+ }
1201
+ else {
1202
+ this._listeners = {};
1203
+ }
1204
+ return this;
1205
+ }
1206
+ // Node.js Server timeout properties (no-op in sandbox)
1207
+ keepAliveTimeout = 5000;
1208
+ requestTimeout = 300000;
1209
+ headersTimeout = 60000;
1210
+ timeout = 0;
1211
+ maxRequestsPerSocket = 0;
1212
+ setTimeout(_msecs, _callback) {
1213
+ if (typeof _msecs === "number")
1214
+ this.timeout = _msecs;
1215
+ return this;
1216
+ }
1217
+ ref() {
1218
+ return this;
1219
+ }
1220
+ unref() {
1221
+ return this;
1222
+ }
1223
+ }
1224
+ /** Route an incoming HTTP request to the server's request listener and return the serialized response. */
1225
+ async function dispatchServerRequest(serverId, requestJson) {
1226
+ const listener = serverRequestListeners.get(serverId);
1227
+ if (!listener) {
1228
+ throw new Error(`Unknown HTTP server: ${serverId}`);
1229
+ }
1230
+ const request = JSON.parse(requestJson);
1231
+ const incoming = new ServerIncomingMessage(request);
1232
+ const outgoing = new ServerResponseBridge();
1233
+ try {
1234
+ // Call listener synchronously — frameworks register event handlers here
1235
+ const listenerResult = listener(incoming, outgoing);
1236
+ // Emit readable stream events so body-parsing middleware (e.g. express.json()) can proceed
1237
+ if (incoming.rawBody && incoming.rawBody.length > 0) {
1238
+ incoming.emit("data", incoming.rawBody);
1239
+ }
1240
+ incoming.emit("end");
1241
+ await Promise.resolve(listenerResult);
1242
+ }
1243
+ catch (err) {
1244
+ outgoing.statusCode = 500;
1245
+ outgoing.end(err instanceof Error ? `Error: ${err.message}` : "Error");
1246
+ }
1247
+ if (!outgoing.writableFinished) {
1248
+ outgoing.end();
1249
+ }
1250
+ await outgoing.waitForClose();
1251
+ return JSON.stringify(outgoing.serialize());
1252
+ }
1253
+ // Function-based ServerResponse constructor — allows .call() inheritance
1254
+ // used by light-my-request (Fastify's inject), which does
1255
+ // http.ServerResponse.call(this, req) + util.inherits(Response, http.ServerResponse)
1256
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1257
+ function ServerResponseCallable() {
1258
+ this.statusCode = 200;
1259
+ this.statusMessage = "OK";
1260
+ this.headersSent = false;
1261
+ this.writable = true;
1262
+ this.writableFinished = false;
1263
+ this._headers = new Map();
1264
+ this._chunks = [];
1265
+ this._listeners = {};
1266
+ this._closedPromise = new Promise((resolve) => {
1267
+ this._resolveClosed = resolve;
1268
+ });
1269
+ // Writable stream state stub
1270
+ this._writableState = { length: 0, ended: false, finished: false, objectMode: false, corked: 0 };
1271
+ // Fake socket for frameworks/inject libraries that access res.socket
1272
+ const fakeSocket = {
1273
+ writable: true,
1274
+ on() { return fakeSocket; },
1275
+ once() { return fakeSocket; },
1276
+ removeListener() { return fakeSocket; },
1277
+ destroy() { },
1278
+ end() { },
1279
+ cork() { },
1280
+ uncork() { },
1281
+ write() { return true; },
1282
+ };
1283
+ this.socket = fakeSocket;
1284
+ this.connection = fakeSocket;
1285
+ }
1286
+ ServerResponseCallable.prototype = Object.create(ServerResponseBridge.prototype, {
1287
+ constructor: { value: ServerResponseCallable, writable: true, configurable: true },
1288
+ });
1289
+ // Create HTTP module
1290
+ function createHttpModule(_protocol) {
1291
+ const moduleAgent = new Agent({ keepAlive: false });
1292
+ // Set module-level globalAgent so ClientRequest defaults to it
1293
+ _moduleGlobalAgent = moduleAgent;
1294
+ return {
1295
+ request(options, callback) {
1296
+ let opts;
1297
+ if (typeof options === "string") {
1298
+ const url = new URL(options);
1299
+ opts = {
1300
+ protocol: url.protocol,
1301
+ hostname: url.hostname,
1302
+ port: url.port,
1303
+ path: url.pathname + url.search,
1304
+ };
1305
+ }
1306
+ else if (options instanceof URL) {
1307
+ opts = {
1308
+ protocol: options.protocol,
1309
+ hostname: options.hostname,
1310
+ port: options.port,
1311
+ path: options.pathname + options.search,
1312
+ };
1313
+ }
1314
+ else {
1315
+ opts = options;
1316
+ }
1317
+ return new ClientRequest(opts, callback);
1318
+ },
1319
+ get(options, callback) {
1320
+ let opts;
1321
+ if (typeof options === "string") {
1322
+ const url = new URL(options);
1323
+ opts = {
1324
+ protocol: url.protocol,
1325
+ hostname: url.hostname,
1326
+ port: url.port,
1327
+ path: url.pathname + url.search,
1328
+ method: "GET",
1329
+ };
1330
+ }
1331
+ else if (options instanceof URL) {
1332
+ opts = {
1333
+ protocol: options.protocol,
1334
+ hostname: options.hostname,
1335
+ port: options.port,
1336
+ path: options.pathname + options.search,
1337
+ method: "GET",
1338
+ };
1339
+ }
1340
+ else {
1341
+ opts = { ...options, method: "GET" };
1342
+ }
1343
+ const req = new ClientRequest(opts, callback);
1344
+ req.end();
1345
+ return req;
1346
+ },
1347
+ createServer(_optionsOrListener, maybeListener) {
1348
+ const listener = typeof _optionsOrListener === "function"
1349
+ ? _optionsOrListener
1350
+ : maybeListener;
1351
+ return new Server(listener);
1352
+ },
1353
+ Agent,
1354
+ globalAgent: moduleAgent,
1355
+ Server: Server,
1356
+ ServerResponse: ServerResponseCallable,
1357
+ IncomingMessage: IncomingMessage,
1358
+ ClientRequest: ClientRequest,
1359
+ METHODS: ["GET", "POST", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS"],
1360
+ STATUS_CODES: {
1361
+ 200: "OK",
1362
+ 201: "Created",
1363
+ 204: "No Content",
1364
+ 301: "Moved Permanently",
1365
+ 302: "Found",
1366
+ 304: "Not Modified",
1367
+ 400: "Bad Request",
1368
+ 401: "Unauthorized",
1369
+ 403: "Forbidden",
1370
+ 404: "Not Found",
1371
+ 500: "Internal Server Error",
1372
+ },
1373
+ };
1374
+ }
1375
+ export const http = createHttpModule("http");
1376
+ export const https = createHttpModule("https");
1377
+ export const http2 = {
1378
+ Http2ServerRequest: class Http2ServerRequest {
1379
+ },
1380
+ Http2ServerResponse: class Http2ServerResponse {
1381
+ },
1382
+ createServer() {
1383
+ throw new Error("http2.createServer is not supported in sandbox");
1384
+ },
1385
+ createSecureServer() {
1386
+ throw new Error("http2.createSecureServer is not supported in sandbox");
1387
+ },
1388
+ };
1389
+ // Export modules and make them available as globals for require()
1390
+ exposeCustomGlobal("_httpModule", http);
1391
+ exposeCustomGlobal("_httpsModule", https);
1392
+ exposeCustomGlobal("_http2Module", http2);
1393
+ exposeCustomGlobal("_dnsModule", dns);
1394
+ exposeCustomGlobal("_httpServerDispatch", dispatchServerRequest);
1395
+ // Make fetch API available globally
1396
+ globalThis.fetch = fetch;
1397
+ globalThis.Headers = Headers;
1398
+ globalThis.Request = Request;
1399
+ globalThis.Response = Response;
1400
+ if (typeof globalThis.Blob === "undefined") {
1401
+ // Minimal Blob stub used by server frameworks for instanceof checks.
1402
+ globalThis.Blob = class BlobStub {
1403
+ };
1404
+ }
1405
+ export default {
1406
+ fetch,
1407
+ Headers,
1408
+ Request,
1409
+ Response,
1410
+ dns,
1411
+ http,
1412
+ https,
1413
+ http2,
1414
+ IncomingMessage,
1415
+ ClientRequest,
1416
+ };