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