@secure-exec/core 0.1.1-rc.3 → 0.2.0-rc.2

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 +24 -5
  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 +2 -2
  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 +145 -6
  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 +2868 -494
  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 +78 -19
  22. package/dist/isolate-runtime/setup-fs-facade.js +62 -23
  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 +122 -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 +1393 -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 +312 -0
  52. package/dist/kernel/socket-table.js +1188 -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 +349 -22
  70. package/dist/shared/bridge-contract.js +62 -5
  71. package/dist/shared/console-formatter.js +8 -4
  72. package/dist/shared/global-exposure.js +364 -19
  73. package/dist/shared/in-memory-fs.d.ts +33 -11
  74. package/dist/shared/in-memory-fs.js +439 -130
  75. package/dist/shared/permissions.d.ts +4 -6
  76. package/dist/shared/permissions.js +19 -39
  77. package/dist/types.d.ts +8 -159
  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 -670
  84. package/dist/bridge/fs.d.ts +0 -281
  85. package/dist/bridge/fs.js +0 -2235
  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 -308
  90. package/dist/bridge/network.d.ts +0 -350
  91. package/dist/bridge/network.js +0 -2050
  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 -1015
  98. package/dist/bridge.js +0 -12496
  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,2050 +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(input, 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
- // Extract URL and options from Request object (used by axios fetch adapter)
13
- let resolvedUrl;
14
- if (input instanceof Request) {
15
- resolvedUrl = input.url;
16
- options = {
17
- method: input.method,
18
- headers: Object.fromEntries(input.headers.entries()),
19
- body: input.body,
20
- ...options,
21
- };
22
- }
23
- else {
24
- resolvedUrl = String(input);
25
- }
26
- const optionsJson = JSON.stringify({
27
- method: options.method || "GET",
28
- headers: options.headers || {},
29
- body: options.body || null,
30
- });
31
- const responseJson = await _networkFetchRaw.apply(undefined, [resolvedUrl, optionsJson], {
32
- result: { promise: true },
33
- });
34
- const response = JSON.parse(responseJson);
35
- // Create Response-like object
36
- return {
37
- ok: response.ok,
38
- status: response.status,
39
- statusText: response.statusText,
40
- headers: new Map(Object.entries(response.headers || {})),
41
- url: response.url || resolvedUrl,
42
- redirected: response.redirected || false,
43
- type: "basic",
44
- async text() {
45
- return response.body || "";
46
- },
47
- async json() {
48
- return JSON.parse(response.body || "{}");
49
- },
50
- async arrayBuffer() {
51
- // Not fully supported - return empty buffer
52
- return new ArrayBuffer(0);
53
- },
54
- async blob() {
55
- throw new Error("Blob not supported in sandbox");
56
- },
57
- clone() {
58
- return { ...this };
59
- },
60
- };
61
- }
62
- // Headers class
63
- export class Headers {
64
- _headers = {};
65
- constructor(init) {
66
- if (init && init !== null) {
67
- if (init instanceof Headers) {
68
- this._headers = { ...init._headers };
69
- }
70
- else if (Array.isArray(init)) {
71
- init.forEach(([key, value]) => {
72
- this._headers[key.toLowerCase()] = value;
73
- });
74
- }
75
- else if (typeof init === "object") {
76
- Object.entries(init).forEach(([key, value]) => {
77
- this._headers[key.toLowerCase()] = value;
78
- });
79
- }
80
- }
81
- }
82
- get(name) {
83
- return this._headers[name.toLowerCase()] || null;
84
- }
85
- set(name, value) {
86
- this._headers[name.toLowerCase()] = value;
87
- }
88
- has(name) {
89
- return name.toLowerCase() in this._headers;
90
- }
91
- delete(name) {
92
- delete this._headers[name.toLowerCase()];
93
- }
94
- entries() {
95
- return Object.entries(this._headers)[Symbol.iterator]();
96
- }
97
- [Symbol.iterator]() {
98
- return this.entries();
99
- }
100
- keys() {
101
- return Object.keys(this._headers)[Symbol.iterator]();
102
- }
103
- values() {
104
- return Object.values(this._headers)[Symbol.iterator]();
105
- }
106
- forEach(callback) {
107
- Object.entries(this._headers).forEach(([k, v]) => callback(v, k, this));
108
- }
109
- }
110
- // Request class
111
- export class Request {
112
- url;
113
- method;
114
- headers;
115
- body;
116
- mode;
117
- credentials;
118
- cache;
119
- redirect;
120
- referrer;
121
- integrity;
122
- constructor(input, init = {}) {
123
- this.url = typeof input === "string" ? input : input.url;
124
- this.method = init.method || (typeof input !== "string" ? input.method : undefined) || "GET";
125
- this.headers = new Headers(init.headers || (typeof input !== "string" ? input.headers : undefined));
126
- this.body = init.body || null;
127
- this.mode = init.mode || "cors";
128
- this.credentials = init.credentials || "same-origin";
129
- this.cache = init.cache || "default";
130
- this.redirect = init.redirect || "follow";
131
- this.referrer = init.referrer || "about:client";
132
- this.integrity = init.integrity || "";
133
- }
134
- clone() {
135
- return new Request(this.url, this);
136
- }
137
- }
138
- // Response class
139
- export class Response {
140
- _body;
141
- status;
142
- statusText;
143
- headers;
144
- ok;
145
- type;
146
- url;
147
- redirected;
148
- constructor(body, init = {}) {
149
- this._body = body || null;
150
- this.status = init.status || 200;
151
- this.statusText = init.statusText || "OK";
152
- this.headers = new Headers(init.headers);
153
- this.ok = this.status >= 200 && this.status < 300;
154
- this.type = "default";
155
- this.url = "";
156
- this.redirected = false;
157
- }
158
- async text() {
159
- return String(this._body || "");
160
- }
161
- async json() {
162
- return JSON.parse(this._body || "{}");
163
- }
164
- clone() {
165
- return new Response(this._body, { status: this.status, statusText: this.statusText });
166
- }
167
- static error() {
168
- return new Response(null, { status: 0, statusText: "" });
169
- }
170
- static redirect(url, status = 302) {
171
- return new Response(null, { status, headers: { Location: url } });
172
- }
173
- }
174
- // DNS module polyfill
175
- export const dns = {
176
- lookup(hostname, options, callback) {
177
- let cb = callback;
178
- if (typeof options === "function") {
179
- cb = options;
180
- }
181
- _networkDnsLookupRaw
182
- .apply(undefined, [hostname], { result: { promise: true } })
183
- .then((resultJson) => {
184
- const result = JSON.parse(resultJson);
185
- if (result.error) {
186
- const err = new Error(result.error);
187
- err.code = result.code || "ENOTFOUND";
188
- cb?.(err);
189
- }
190
- else {
191
- cb?.(null, result.address, result.family);
192
- }
193
- })
194
- .catch((err) => {
195
- cb?.(err);
196
- });
197
- },
198
- resolve(hostname, rrtype, callback) {
199
- let cb = callback;
200
- if (typeof rrtype === "function") {
201
- cb = rrtype;
202
- }
203
- // Simplified - just do lookup for A records
204
- dns.lookup(hostname, (err, address) => {
205
- if (err) {
206
- cb?.(err);
207
- }
208
- else {
209
- cb?.(null, address ? [address] : []);
210
- }
211
- });
212
- },
213
- resolve4(hostname, callback) {
214
- dns.resolve(hostname, "A", callback);
215
- },
216
- resolve6(hostname, callback) {
217
- dns.resolve(hostname, "AAAA", callback);
218
- },
219
- promises: {
220
- lookup(hostname, _options) {
221
- return new Promise((resolve, reject) => {
222
- dns.lookup(hostname, _options, (err, address, family) => {
223
- if (err)
224
- reject(err);
225
- else
226
- resolve({ address: address || "", family: family || 4 });
227
- });
228
- });
229
- },
230
- resolve(hostname, rrtype) {
231
- return new Promise((resolve, reject) => {
232
- dns.resolve(hostname, rrtype || "A", (err, addresses) => {
233
- if (err)
234
- reject(err);
235
- else
236
- resolve(addresses || []);
237
- });
238
- });
239
- },
240
- },
241
- };
242
- // Module-level globalAgent used by ClientRequest when no agent option is provided.
243
- // Initialized lazily after Agent class is defined; set by createHttpModule().
244
- let _moduleGlobalAgent = null;
245
- /**
246
- * Polyfill of Node.js `http.IncomingMessage` (client-side response). Buffers
247
- * the response body eagerly and emits `data`/`end` events on listener
248
- * registration (flowing mode). Supports base64 binary decoding via
249
- * `x-body-encoding` header.
250
- */
251
- export class IncomingMessage {
252
- headers;
253
- rawHeaders;
254
- trailers;
255
- rawTrailers;
256
- httpVersion;
257
- httpVersionMajor;
258
- httpVersionMinor;
259
- method;
260
- url;
261
- statusCode;
262
- statusMessage;
263
- _body;
264
- _isBinary;
265
- _listeners;
266
- complete;
267
- aborted;
268
- socket;
269
- _bodyConsumed;
270
- _ended;
271
- _flowing;
272
- readable;
273
- readableEnded;
274
- readableFlowing;
275
- destroyed;
276
- _encoding;
277
- constructor(response) {
278
- this.headers = response?.headers || {};
279
- this.rawHeaders = [];
280
- if (this.headers && typeof this.headers === "object") {
281
- Object.entries(this.headers).forEach(([k, v]) => {
282
- this.rawHeaders.push(k, v);
283
- });
284
- }
285
- // Populate trailers if provided
286
- if (response?.trailers && typeof response.trailers === "object") {
287
- this.trailers = response.trailers;
288
- this.rawTrailers = [];
289
- Object.entries(response.trailers).forEach(([k, v]) => {
290
- this.rawTrailers.push(k, v);
291
- });
292
- }
293
- else {
294
- this.trailers = {};
295
- this.rawTrailers = [];
296
- }
297
- this.httpVersion = "1.1";
298
- this.httpVersionMajor = 1;
299
- this.httpVersionMinor = 1;
300
- this.method = null;
301
- this.url = response?.url || "";
302
- this.statusCode = response?.status;
303
- this.statusMessage = response?.statusText;
304
- // Decode base64 body if x-body-encoding header is set
305
- const bodyEncoding = this.headers['x-body-encoding'];
306
- if (bodyEncoding === 'base64' && response?.body && typeof Buffer !== 'undefined') {
307
- this._body = Buffer.from(response.body, 'base64').toString('binary');
308
- this._isBinary = true;
309
- }
310
- else {
311
- this._body = response?.body || "";
312
- this._isBinary = false;
313
- }
314
- this._listeners = {};
315
- this.complete = false;
316
- this.aborted = false;
317
- this.socket = null;
318
- this._bodyConsumed = false;
319
- this._ended = false;
320
- this._flowing = false;
321
- this.readable = true;
322
- this.readableEnded = false;
323
- this.readableFlowing = null;
324
- this.destroyed = false;
325
- }
326
- on(event, listener) {
327
- if (!this._listeners[event])
328
- this._listeners[event] = [];
329
- this._listeners[event].push(listener);
330
- // When 'data' listener is added, start flowing mode
331
- // Note: We check for non-empty body (this._body.length > 0) because we need to
332
- // emit 'end' even for empty responses, but only emit 'data' if there's actual data
333
- if (event === "data" && !this._bodyConsumed) {
334
- this._flowing = true;
335
- this.readableFlowing = true;
336
- // Emit data in next microtask
337
- Promise.resolve().then(() => {
338
- if (!this._bodyConsumed) {
339
- this._bodyConsumed = true;
340
- // Only emit data if there's actual content
341
- if (this._body && this._body.length > 0) {
342
- let buf;
343
- if (typeof Buffer !== "undefined") {
344
- // For binary data, use 'binary' encoding to preserve bytes
345
- buf = this._isBinary ? Buffer.from(this._body, 'binary') : Buffer.from(this._body);
346
- }
347
- else {
348
- buf = this._body;
349
- }
350
- this.emit("data", buf);
351
- }
352
- // Always emit end after data (even if no data was emitted)
353
- Promise.resolve().then(() => {
354
- if (!this._ended) {
355
- this._ended = true;
356
- this.complete = true;
357
- this.readable = false;
358
- this.readableEnded = true;
359
- this.emit("end");
360
- }
361
- });
362
- }
363
- });
364
- }
365
- // If 'end' listener is added after data was already consumed, emit end
366
- if (event === "end" && this._bodyConsumed && !this._ended) {
367
- Promise.resolve().then(() => {
368
- if (!this._ended) {
369
- this._ended = true;
370
- this.complete = true;
371
- this.readable = false;
372
- this.readableEnded = true;
373
- listener();
374
- }
375
- });
376
- }
377
- return this;
378
- }
379
- once(event, listener) {
380
- const wrapper = (...args) => {
381
- this.off(event, wrapper);
382
- listener(...args);
383
- };
384
- wrapper._originalListener = listener;
385
- return this.on(event, wrapper);
386
- }
387
- off(event, listener) {
388
- if (this._listeners[event]) {
389
- const idx = this._listeners[event].findIndex((fn) => fn === listener || fn._originalListener === listener);
390
- if (idx !== -1)
391
- this._listeners[event].splice(idx, 1);
392
- }
393
- return this;
394
- }
395
- removeListener(event, listener) {
396
- return this.off(event, listener);
397
- }
398
- removeAllListeners(event) {
399
- if (event) {
400
- delete this._listeners[event];
401
- }
402
- else {
403
- this._listeners = {};
404
- }
405
- return this;
406
- }
407
- emit(event, ...args) {
408
- const handlers = this._listeners[event];
409
- if (handlers) {
410
- handlers.slice().forEach((fn) => fn(...args));
411
- }
412
- return handlers !== undefined && handlers.length > 0;
413
- }
414
- setEncoding(encoding) {
415
- this._encoding = encoding;
416
- return this;
417
- }
418
- read(_size) {
419
- if (this._bodyConsumed)
420
- return null;
421
- this._bodyConsumed = true;
422
- let buf;
423
- if (typeof Buffer !== "undefined") {
424
- buf = this._isBinary ? Buffer.from(this._body, 'binary') : Buffer.from(this._body);
425
- }
426
- else {
427
- buf = this._body;
428
- }
429
- // Schedule end event
430
- Promise.resolve().then(() => {
431
- if (!this._ended) {
432
- this._ended = true;
433
- this.complete = true;
434
- this.readable = false;
435
- this.readableEnded = true;
436
- this.emit("end");
437
- }
438
- });
439
- return buf;
440
- }
441
- pipe(dest) {
442
- let buf;
443
- if (typeof Buffer !== "undefined") {
444
- buf = this._isBinary ? Buffer.from(this._body || "", 'binary') : Buffer.from(this._body || "");
445
- }
446
- else {
447
- buf = this._body || "";
448
- }
449
- if (typeof dest.write === "function" && (typeof buf === "string" ? buf.length : buf.length) > 0) {
450
- dest.write(buf);
451
- }
452
- if (typeof dest.end === "function") {
453
- Promise.resolve().then(() => dest.end());
454
- }
455
- this._bodyConsumed = true;
456
- this._ended = true;
457
- this.complete = true;
458
- this.readable = false;
459
- this.readableEnded = true;
460
- return dest;
461
- }
462
- pause() {
463
- this._flowing = false;
464
- this.readableFlowing = false;
465
- return this;
466
- }
467
- resume() {
468
- this._flowing = true;
469
- this.readableFlowing = true;
470
- if (!this._bodyConsumed && this._body) {
471
- Promise.resolve().then(() => {
472
- if (!this._bodyConsumed) {
473
- this._bodyConsumed = true;
474
- let buf;
475
- if (typeof Buffer !== "undefined") {
476
- buf = this._isBinary ? Buffer.from(this._body, 'binary') : Buffer.from(this._body);
477
- }
478
- else {
479
- buf = this._body;
480
- }
481
- this.emit("data", buf);
482
- Promise.resolve().then(() => {
483
- if (!this._ended) {
484
- this._ended = true;
485
- this.complete = true;
486
- this.readable = false;
487
- this.readableEnded = true;
488
- this.emit("end");
489
- }
490
- });
491
- }
492
- });
493
- }
494
- return this;
495
- }
496
- unpipe(_dest) {
497
- return this;
498
- }
499
- destroy(err) {
500
- this.destroyed = true;
501
- this.readable = false;
502
- if (err)
503
- this.emit("error", err);
504
- this.emit("close");
505
- return this;
506
- }
507
- [Symbol.asyncIterator]() {
508
- const self = this;
509
- let dataEmitted = false;
510
- let ended = false;
511
- return {
512
- async next() {
513
- if (ended || self._ended) {
514
- return { done: true, value: undefined };
515
- }
516
- if (!dataEmitted && !self._bodyConsumed) {
517
- dataEmitted = true;
518
- self._bodyConsumed = true;
519
- let buf;
520
- if (typeof Buffer !== "undefined") {
521
- buf = self._isBinary ? Buffer.from(self._body || "", 'binary') : Buffer.from(self._body || "");
522
- }
523
- else {
524
- buf = self._body || "";
525
- }
526
- return { done: false, value: buf };
527
- }
528
- ended = true;
529
- self._ended = true;
530
- self.complete = true;
531
- self.readable = false;
532
- self.readableEnded = true;
533
- return { done: true, value: undefined };
534
- },
535
- return() {
536
- ended = true;
537
- return Promise.resolve({ done: true, value: undefined });
538
- },
539
- throw(err) {
540
- ended = true;
541
- self.emit("error", err);
542
- return Promise.resolve({ done: true, value: undefined });
543
- },
544
- };
545
- }
546
- }
547
- /**
548
- * Polyfill of Node.js `http.ClientRequest`. Executes the request asynchronously
549
- * via the `_networkHttpRequestRaw` bridge and emits a `response` event with
550
- * an IncomingMessage. Supports Agent-based connection pooling, socket events,
551
- * HTTP upgrade (101), and trailer headers.
552
- */
553
- export class ClientRequest {
554
- _options;
555
- _callback;
556
- _listeners = {};
557
- _body = "";
558
- _bodyBytes = 0;
559
- _ended = false;
560
- _agent;
561
- _hostKey;
562
- socket;
563
- finished = false;
564
- aborted = false;
565
- constructor(options, callback) {
566
- this._options = options;
567
- this._callback = callback;
568
- // Resolve agent: false = no agent, undefined = globalAgent, or explicit Agent
569
- const agentOpt = options.agent;
570
- if (agentOpt === false) {
571
- this._agent = null;
572
- }
573
- else if (agentOpt instanceof Agent) {
574
- this._agent = agentOpt;
575
- }
576
- else {
577
- this._agent = _moduleGlobalAgent;
578
- }
579
- this._hostKey = this._agent ? this._agent._getHostKey(options) : "";
580
- // Create socket-like object and emit 'socket' event
581
- this.socket = new FakeSocket({
582
- host: (options.hostname || options.host || "localhost"),
583
- port: Number(options.port) || 80,
584
- });
585
- Promise.resolve().then(() => this._emit("socket", this.socket));
586
- // Execute request asynchronously
587
- Promise.resolve().then(() => this._execute());
588
- }
589
- async _execute() {
590
- // Acquire agent slot before executing
591
- if (this._agent) {
592
- await this._agent._acquireSlot(this._hostKey);
593
- }
594
- try {
595
- if (typeof _networkHttpRequestRaw === 'undefined') {
596
- console.error('http/https request requires NetworkAdapter to be configured');
597
- throw new Error('http/https request requires NetworkAdapter to be configured');
598
- }
599
- const url = this._buildUrl();
600
- const tls = {};
601
- if (this._options.rejectUnauthorized !== undefined) {
602
- tls.rejectUnauthorized = this._options.rejectUnauthorized;
603
- }
604
- const optionsJson = JSON.stringify({
605
- method: this._options.method || "GET",
606
- headers: this._options.headers || {},
607
- body: this._body || null,
608
- ...tls,
609
- });
610
- const responseJson = await _networkHttpRequestRaw.apply(undefined, [url, optionsJson], {
611
- result: { promise: true },
612
- });
613
- const response = JSON.parse(responseJson);
614
- this.finished = true;
615
- // 101 Switching Protocols → fire 'upgrade' event
616
- if (response.status === 101) {
617
- const res = new IncomingMessage(response);
618
- // Use UpgradeSocket for bidirectional data relay when socketId is available
619
- let socket = this.socket;
620
- if (response.upgradeSocketId != null) {
621
- socket = new UpgradeSocket(response.upgradeSocketId, {
622
- host: this._options.hostname,
623
- port: Number(this._options.port) || 80,
624
- });
625
- upgradeSocketInstances.set(response.upgradeSocketId, socket);
626
- }
627
- const head = typeof Buffer !== "undefined"
628
- ? (response.body ? Buffer.from(response.body, "base64") : Buffer.alloc(0))
629
- : new Uint8Array(0);
630
- this._emit("upgrade", res, socket, head);
631
- return;
632
- }
633
- const res = new IncomingMessage(response);
634
- if (this._callback) {
635
- this._callback(res);
636
- }
637
- this._emit("response", res);
638
- }
639
- catch (err) {
640
- this._emit("error", err);
641
- }
642
- finally {
643
- // Release agent slot
644
- if (this._agent) {
645
- this._agent._releaseSlot(this._hostKey);
646
- }
647
- }
648
- }
649
- _buildUrl() {
650
- const opts = this._options;
651
- const protocol = opts.protocol || (opts.port === 443 ? "https:" : "http:");
652
- const host = opts.hostname || opts.host || "localhost";
653
- const port = opts.port ? ":" + opts.port : "";
654
- const path = opts.path || "/";
655
- return protocol + "//" + host + port + path;
656
- }
657
- on(event, listener) {
658
- if (!this._listeners[event])
659
- this._listeners[event] = [];
660
- this._listeners[event].push(listener);
661
- return this;
662
- }
663
- once(event, listener) {
664
- const wrapper = (...args) => {
665
- this.off(event, wrapper);
666
- listener(...args);
667
- };
668
- return this.on(event, wrapper);
669
- }
670
- off(event, listener) {
671
- if (this._listeners[event]) {
672
- const idx = this._listeners[event].indexOf(listener);
673
- if (idx !== -1)
674
- this._listeners[event].splice(idx, 1);
675
- }
676
- return this;
677
- }
678
- _emit(event, ...args) {
679
- if (this._listeners[event]) {
680
- this._listeners[event].forEach((fn) => fn(...args));
681
- }
682
- }
683
- write(data) {
684
- const addedBytes = typeof Buffer !== "undefined" ? Buffer.byteLength(data) : data.length;
685
- if (this._bodyBytes + addedBytes > MAX_HTTP_BODY_BYTES) {
686
- throw new Error("ERR_HTTP_BODY_TOO_LARGE: request body exceeds " + MAX_HTTP_BODY_BYTES + " byte limit");
687
- }
688
- this._body += data;
689
- this._bodyBytes += addedBytes;
690
- return true;
691
- }
692
- end(data) {
693
- if (data)
694
- this.write(data);
695
- this._ended = true;
696
- return this;
697
- }
698
- abort() {
699
- this.aborted = true;
700
- }
701
- setTimeout(_timeout) {
702
- return this;
703
- }
704
- setNoDelay() {
705
- return this;
706
- }
707
- setSocketKeepAlive() {
708
- return this;
709
- }
710
- flushHeaders() {
711
- // no-op
712
- }
713
- }
714
- // Minimal socket-like object emitted by ClientRequest 'socket' event
715
- class FakeSocket {
716
- remoteAddress;
717
- remotePort;
718
- localAddress = "127.0.0.1";
719
- localPort = 0;
720
- connecting = false;
721
- destroyed = false;
722
- writable = true;
723
- readable = true;
724
- _listeners = {};
725
- constructor(options) {
726
- this.remoteAddress = options?.host || "127.0.0.1";
727
- this.remotePort = options?.port || 80;
728
- }
729
- setTimeout(_ms, _cb) { return this; }
730
- setNoDelay(_noDelay) { return this; }
731
- setKeepAlive(_enable, _delay) { return this; }
732
- on(event, listener) {
733
- if (!this._listeners[event])
734
- this._listeners[event] = [];
735
- this._listeners[event].push(listener);
736
- return this;
737
- }
738
- once(event, listener) {
739
- const wrapper = (...args) => {
740
- this.off(event, wrapper);
741
- listener(...args);
742
- };
743
- return this.on(event, wrapper);
744
- }
745
- off(event, listener) {
746
- if (this._listeners[event]) {
747
- const idx = this._listeners[event].indexOf(listener);
748
- if (idx !== -1)
749
- this._listeners[event].splice(idx, 1);
750
- }
751
- return this;
752
- }
753
- removeListener(event, listener) {
754
- return this.off(event, listener);
755
- }
756
- emit(event, ...args) {
757
- const handlers = this._listeners[event];
758
- if (handlers)
759
- handlers.slice().forEach((fn) => fn(...args));
760
- return handlers !== undefined && handlers.length > 0;
761
- }
762
- write(_data) { return true; }
763
- end() { return this; }
764
- destroy() {
765
- this.destroyed = true;
766
- this.writable = false;
767
- this.readable = false;
768
- return this;
769
- }
770
- }
771
- // HTTP Agent with connection pooling via maxSockets
772
- class Agent {
773
- maxSockets;
774
- maxFreeSockets;
775
- keepAlive;
776
- keepAliveMsecs;
777
- timeout;
778
- requests;
779
- sockets;
780
- freeSockets;
781
- // Per-host active count and pending queue
782
- _activeCounts = new Map();
783
- _queues = new Map();
784
- constructor(options) {
785
- this.keepAlive = options?.keepAlive ?? false;
786
- this.keepAliveMsecs = options?.keepAliveMsecs ?? 1000;
787
- this.maxSockets = options?.maxSockets ?? Infinity;
788
- this.maxFreeSockets = options?.maxFreeSockets ?? 256;
789
- this.timeout = options?.timeout ?? -1;
790
- this.requests = {};
791
- this.sockets = {};
792
- this.freeSockets = {};
793
- }
794
- _getHostKey(options) {
795
- const host = options.hostname || options.host || "localhost";
796
- const port = options.port || 80;
797
- return `${host}:${port}`;
798
- }
799
- // Wait for an available slot; resolves immediately if under maxSockets
800
- _acquireSlot(hostKey) {
801
- const active = this._activeCounts.get(hostKey) || 0;
802
- if (active < this.maxSockets) {
803
- this._activeCounts.set(hostKey, active + 1);
804
- return Promise.resolve();
805
- }
806
- return new Promise((resolve) => {
807
- let queue = this._queues.get(hostKey);
808
- if (!queue) {
809
- queue = [];
810
- this._queues.set(hostKey, queue);
811
- }
812
- queue.push(resolve);
813
- });
814
- }
815
- // Release a slot; dequeues next pending request if any
816
- _releaseSlot(hostKey) {
817
- const queue = this._queues.get(hostKey);
818
- if (queue && queue.length > 0) {
819
- const next = queue.shift();
820
- if (queue.length === 0)
821
- this._queues.delete(hostKey);
822
- next();
823
- }
824
- else {
825
- const active = this._activeCounts.get(hostKey) || 1;
826
- const next = active - 1;
827
- if (next <= 0)
828
- this._activeCounts.delete(hostKey);
829
- else
830
- this._activeCounts.set(hostKey, next);
831
- }
832
- }
833
- destroy() {
834
- this._activeCounts.clear();
835
- for (const [, queue] of this._queues) {
836
- queue.length = 0;
837
- }
838
- this._queues.clear();
839
- }
840
- }
841
- let nextServerId = 1;
842
- const serverRequestListeners = new Map();
843
- // Server instances indexed by serverId — used by upgrade dispatch to emit 'upgrade' events
844
- const serverInstances = new Map();
845
- class ServerIncomingMessage {
846
- headers;
847
- rawHeaders;
848
- method;
849
- url;
850
- socket;
851
- connection;
852
- rawBody;
853
- destroyed = false;
854
- errored;
855
- readable = true;
856
- httpVersion = "1.1";
857
- httpVersionMajor = 1;
858
- httpVersionMinor = 1;
859
- complete = true;
860
- // Readable stream state stub for frameworks that inspect internal state
861
- _readableState = { flowing: null, length: 0, ended: false, objectMode: false };
862
- _listeners = {};
863
- constructor(request) {
864
- this.headers = request.headers || {};
865
- this.rawHeaders = request.rawHeaders || [];
866
- if (!Array.isArray(this.rawHeaders) || this.rawHeaders.length % 2 !== 0) {
867
- this.rawHeaders = [];
868
- }
869
- this.method = request.method || "GET";
870
- this.url = request.url || "/";
871
- const fakeSocket = {
872
- encrypted: false,
873
- remoteAddress: "127.0.0.1",
874
- remotePort: 0,
875
- writable: true,
876
- on() { return fakeSocket; },
877
- once() { return fakeSocket; },
878
- removeListener() { return fakeSocket; },
879
- destroy() { },
880
- end() { },
881
- };
882
- this.socket = fakeSocket;
883
- this.connection = fakeSocket;
884
- const rawHost = this.headers.host;
885
- if (typeof rawHost === "string" && rawHost.includes(",")) {
886
- this.headers.host = rawHost.split(",")[0].trim();
887
- }
888
- if (!this.headers.host) {
889
- this.headers.host = "127.0.0.1";
890
- }
891
- if (this.rawHeaders.length === 0) {
892
- Object.entries(this.headers).forEach(([key, value]) => {
893
- this.rawHeaders.push(key, value);
894
- });
895
- }
896
- if (request.bodyBase64 && typeof Buffer !== "undefined") {
897
- this.rawBody = Buffer.from(request.bodyBase64, "base64");
898
- }
899
- }
900
- on(event, listener) {
901
- if (!this._listeners[event])
902
- this._listeners[event] = [];
903
- this._listeners[event].push(listener);
904
- return this;
905
- }
906
- once(event, listener) {
907
- const wrapped = (...args) => {
908
- this.off(event, wrapped);
909
- listener(...args);
910
- };
911
- return this.on(event, wrapped);
912
- }
913
- off(event, listener) {
914
- const listeners = this._listeners[event];
915
- if (!listeners)
916
- return this;
917
- const index = listeners.indexOf(listener);
918
- if (index !== -1)
919
- listeners.splice(index, 1);
920
- return this;
921
- }
922
- removeListener(event, listener) {
923
- return this.off(event, listener);
924
- }
925
- emit(event, ...args) {
926
- const listeners = this._listeners[event];
927
- if (!listeners || listeners.length === 0)
928
- return false;
929
- listeners.slice().forEach((fn) => fn(...args));
930
- return true;
931
- }
932
- // Readable stream stubs for framework compatibility
933
- unpipe() { return this; }
934
- pause() { return this; }
935
- resume() { return this; }
936
- read() { return null; }
937
- pipe(dest) { return dest; }
938
- isPaused() { return false; }
939
- setEncoding() { return this; }
940
- destroy(err) {
941
- this.destroyed = true;
942
- this.errored = err;
943
- if (err) {
944
- this.emit("error", err);
945
- }
946
- this.emit("close");
947
- return this;
948
- }
949
- }
950
- /**
951
- * Sandbox-side response writer for HTTP server requests. Collects headers and
952
- * body chunks, then serializes to JSON for transfer back to the host.
953
- */
954
- class ServerResponseBridge {
955
- statusCode = 200;
956
- statusMessage = "OK";
957
- headersSent = false;
958
- writable = true;
959
- writableFinished = false;
960
- _headers = new Map();
961
- _chunks = [];
962
- _chunksBytes = 0;
963
- _listeners = {};
964
- _closedPromise;
965
- _resolveClosed = null;
966
- constructor() {
967
- this._closedPromise = new Promise((resolve) => {
968
- this._resolveClosed = resolve;
969
- });
970
- }
971
- on(event, listener) {
972
- if (!this._listeners[event])
973
- this._listeners[event] = [];
974
- this._listeners[event].push(listener);
975
- return this;
976
- }
977
- once(event, listener) {
978
- const wrapped = (...args) => {
979
- this.off(event, wrapped);
980
- listener(...args);
981
- };
982
- return this.on(event, wrapped);
983
- }
984
- off(event, listener) {
985
- const listeners = this._listeners[event];
986
- if (!listeners)
987
- return this;
988
- const index = listeners.indexOf(listener);
989
- if (index !== -1)
990
- listeners.splice(index, 1);
991
- return this;
992
- }
993
- removeListener(event, listener) {
994
- return this.off(event, listener);
995
- }
996
- emit(event, ...args) {
997
- const listeners = this._listeners[event];
998
- if (!listeners || listeners.length === 0)
999
- return false;
1000
- listeners.slice().forEach((fn) => fn(...args));
1001
- return true;
1002
- }
1003
- _emit(event, ...args) {
1004
- this.emit(event, ...args);
1005
- }
1006
- writeHead(statusCode, headers) {
1007
- this.statusCode = statusCode;
1008
- if (headers) {
1009
- if (Array.isArray(headers)) {
1010
- headers.forEach(([key, value]) => this.setHeader(key, value));
1011
- }
1012
- else {
1013
- Object.entries(headers).forEach(([key, value]) => this.setHeader(key, value));
1014
- }
1015
- }
1016
- this.headersSent = true;
1017
- return this;
1018
- }
1019
- setHeader(name, value) {
1020
- const normalized = Array.isArray(value) ? value.join(", ") : String(value);
1021
- this._headers.set(name.toLowerCase(), normalized);
1022
- return this;
1023
- }
1024
- getHeader(name) {
1025
- return this._headers.get(name.toLowerCase());
1026
- }
1027
- hasHeader(name) {
1028
- return this._headers.has(name.toLowerCase());
1029
- }
1030
- removeHeader(name) {
1031
- this._headers.delete(name.toLowerCase());
1032
- }
1033
- write(chunk) {
1034
- if (chunk == null)
1035
- return true;
1036
- this.headersSent = true;
1037
- const buf = typeof chunk === "string" ? Buffer.from(chunk) : chunk;
1038
- if (this._chunksBytes + buf.byteLength > MAX_HTTP_BODY_BYTES) {
1039
- throw new Error("ERR_HTTP_BODY_TOO_LARGE: response body exceeds " + MAX_HTTP_BODY_BYTES + " byte limit");
1040
- }
1041
- this._chunks.push(buf);
1042
- this._chunksBytes += buf.byteLength;
1043
- return true;
1044
- }
1045
- end(chunk) {
1046
- if (chunk != null) {
1047
- this.write(chunk);
1048
- }
1049
- this._finalize();
1050
- return this;
1051
- }
1052
- getHeaderNames() {
1053
- return Array.from(this._headers.keys());
1054
- }
1055
- getHeaders() {
1056
- const result = {};
1057
- for (const [key, value] of this._headers)
1058
- result[key] = value;
1059
- return result;
1060
- }
1061
- // Writable stream state stub for frameworks that inspect internal state
1062
- _writableState = { length: 0, ended: false, finished: false, objectMode: false, corked: 0 };
1063
- // Fake socket for frameworks that access res.socket/res.connection
1064
- socket = {
1065
- writable: true,
1066
- on: () => this.socket,
1067
- once: () => this.socket,
1068
- removeListener: () => this.socket,
1069
- destroy: () => { },
1070
- end: () => { },
1071
- cork: () => { },
1072
- uncork: () => { },
1073
- write: () => true,
1074
- };
1075
- connection = this.socket;
1076
- // Node.js http.ServerResponse socket/stream compatibility stubs
1077
- assignSocket() { }
1078
- detachSocket() { }
1079
- writeContinue() { }
1080
- writeProcessing() { }
1081
- addTrailers() { }
1082
- cork() { }
1083
- uncork() { }
1084
- setTimeout(_msecs) { return this; }
1085
- flushHeaders() {
1086
- this.headersSent = true;
1087
- }
1088
- destroy(err) {
1089
- if (err) {
1090
- this._emit("error", err);
1091
- }
1092
- this._finalize();
1093
- }
1094
- async waitForClose() {
1095
- await this._closedPromise;
1096
- }
1097
- serialize() {
1098
- const bodyBuffer = this._chunks.length > 0 ? Buffer.concat(this._chunks) : Buffer.alloc(0);
1099
- return {
1100
- status: this.statusCode,
1101
- headers: Array.from(this._headers.entries()),
1102
- body: bodyBuffer.toString("base64"),
1103
- bodyEncoding: "base64",
1104
- };
1105
- }
1106
- _finalize() {
1107
- if (this.writableFinished) {
1108
- return;
1109
- }
1110
- this.writableFinished = true;
1111
- this.writable = false;
1112
- this._emit("finish");
1113
- this._emit("close");
1114
- this._resolveClosed?.();
1115
- this._resolveClosed = null;
1116
- }
1117
- }
1118
- /**
1119
- * Polyfill of Node.js `http.Server`. Delegates actual listening to the host
1120
- * via the `_networkHttpServerListenRaw` bridge. Incoming requests are
1121
- * dispatched through `_httpServerDispatch` which invokes the request listener
1122
- * inside the isolate. Registers an active handle to keep the sandbox alive.
1123
- */
1124
- class Server {
1125
- listening = false;
1126
- _listeners = {};
1127
- _serverId;
1128
- _listenPromise = null;
1129
- _address = null;
1130
- _handleId = null;
1131
- constructor(requestListener) {
1132
- this._serverId = nextServerId++;
1133
- if (requestListener) {
1134
- serverRequestListeners.set(this._serverId, requestListener);
1135
- }
1136
- else {
1137
- serverRequestListeners.set(this._serverId, () => undefined);
1138
- }
1139
- serverInstances.set(this._serverId, this);
1140
- }
1141
- /** @internal Emit an event — used by upgrade dispatch to fire 'upgrade' events. */
1142
- _emit(event, ...args) {
1143
- const listeners = this._listeners[event];
1144
- if (!listeners || listeners.length === 0)
1145
- return;
1146
- listeners.slice().forEach((listener) => listener(...args));
1147
- }
1148
- async _start(port, hostname) {
1149
- if (typeof _networkHttpServerListenRaw === "undefined") {
1150
- throw new Error("http.createServer requires NetworkAdapter.httpServerListen support");
1151
- }
1152
- const resultJson = await _networkHttpServerListenRaw.apply(undefined, [JSON.stringify({ serverId: this._serverId, port, hostname })], { result: { promise: true } });
1153
- const result = JSON.parse(resultJson);
1154
- this._address = result.address;
1155
- this.listening = true;
1156
- this._handleId = `http-server:${this._serverId}`;
1157
- if (typeof _registerHandle === "function") {
1158
- _registerHandle(this._handleId, "http server");
1159
- }
1160
- }
1161
- listen(portOrCb, hostOrCb, cb) {
1162
- const port = typeof portOrCb === "number" ? portOrCb : undefined;
1163
- const hostname = typeof hostOrCb === "string" ? hostOrCb : undefined;
1164
- const callback = typeof cb === "function"
1165
- ? cb
1166
- : typeof hostOrCb === "function"
1167
- ? hostOrCb
1168
- : typeof portOrCb === "function"
1169
- ? portOrCb
1170
- : undefined;
1171
- if (!this._listenPromise) {
1172
- this._listenPromise = this._start(port, hostname)
1173
- .then(() => {
1174
- this._emit("listening");
1175
- callback?.();
1176
- })
1177
- .catch((error) => {
1178
- this._emit("error", error);
1179
- });
1180
- }
1181
- return this;
1182
- }
1183
- close(cb) {
1184
- const run = async () => {
1185
- try {
1186
- if (this._listenPromise) {
1187
- await this._listenPromise;
1188
- }
1189
- if (this.listening && typeof _networkHttpServerCloseRaw !== "undefined") {
1190
- await _networkHttpServerCloseRaw.apply(undefined, [this._serverId], {
1191
- result: { promise: true },
1192
- });
1193
- }
1194
- this.listening = false;
1195
- this._address = null;
1196
- serverInstances.delete(this._serverId);
1197
- if (this._handleId && typeof _unregisterHandle === "function") {
1198
- _unregisterHandle(this._handleId);
1199
- }
1200
- this._handleId = null;
1201
- cb?.();
1202
- this._emit("close");
1203
- }
1204
- catch (err) {
1205
- const error = err instanceof Error ? err : new Error(String(err));
1206
- cb?.(error);
1207
- this._emit("error", error);
1208
- }
1209
- };
1210
- void run();
1211
- return this;
1212
- }
1213
- address() {
1214
- return this._address;
1215
- }
1216
- on(event, listener) {
1217
- if (!this._listeners[event])
1218
- this._listeners[event] = [];
1219
- this._listeners[event].push(listener);
1220
- return this;
1221
- }
1222
- once(event, listener) {
1223
- const wrapped = (...args) => {
1224
- this.off(event, wrapped);
1225
- listener(...args);
1226
- };
1227
- return this.on(event, wrapped);
1228
- }
1229
- off(event, listener) {
1230
- const listeners = this._listeners[event];
1231
- if (!listeners)
1232
- return this;
1233
- const index = listeners.indexOf(listener);
1234
- if (index !== -1)
1235
- listeners.splice(index, 1);
1236
- return this;
1237
- }
1238
- removeListener(event, listener) {
1239
- return this.off(event, listener);
1240
- }
1241
- removeAllListeners(event) {
1242
- if (event) {
1243
- delete this._listeners[event];
1244
- }
1245
- else {
1246
- this._listeners = {};
1247
- }
1248
- return this;
1249
- }
1250
- // Node.js Server timeout properties (no-op in sandbox)
1251
- keepAliveTimeout = 5000;
1252
- requestTimeout = 300000;
1253
- headersTimeout = 60000;
1254
- timeout = 0;
1255
- maxRequestsPerSocket = 0;
1256
- setTimeout(_msecs, _callback) {
1257
- if (typeof _msecs === "number")
1258
- this.timeout = _msecs;
1259
- return this;
1260
- }
1261
- ref() {
1262
- return this;
1263
- }
1264
- unref() {
1265
- return this;
1266
- }
1267
- }
1268
- /** Route an incoming HTTP request to the server's request listener and return the serialized response. */
1269
- async function dispatchServerRequest(serverId, requestJson) {
1270
- const listener = serverRequestListeners.get(serverId);
1271
- if (!listener) {
1272
- throw new Error(`Unknown HTTP server: ${serverId}`);
1273
- }
1274
- const request = JSON.parse(requestJson);
1275
- const incoming = new ServerIncomingMessage(request);
1276
- const outgoing = new ServerResponseBridge();
1277
- try {
1278
- // Call listener synchronously — frameworks register event handlers here
1279
- const listenerResult = listener(incoming, outgoing);
1280
- // Emit readable stream events so body-parsing middleware (e.g. express.json()) can proceed
1281
- if (incoming.rawBody && incoming.rawBody.length > 0) {
1282
- incoming.emit("data", incoming.rawBody);
1283
- }
1284
- incoming.emit("end");
1285
- await Promise.resolve(listenerResult);
1286
- }
1287
- catch (err) {
1288
- outgoing.statusCode = 500;
1289
- try {
1290
- outgoing.end(err instanceof Error ? `Error: ${err.message}` : "Error");
1291
- }
1292
- catch {
1293
- // Body cap may prevent writing error — finalize without data
1294
- if (!outgoing.writableFinished)
1295
- outgoing.end();
1296
- }
1297
- }
1298
- if (!outgoing.writableFinished) {
1299
- outgoing.end();
1300
- }
1301
- await outgoing.waitForClose();
1302
- return JSON.stringify(outgoing.serialize());
1303
- }
1304
- // Upgrade socket for bidirectional data relay through the host bridge
1305
- const upgradeSocketInstances = new Map();
1306
- class UpgradeSocket {
1307
- remoteAddress;
1308
- remotePort;
1309
- localAddress = "127.0.0.1";
1310
- localPort = 0;
1311
- connecting = false;
1312
- destroyed = false;
1313
- writable = true;
1314
- readable = true;
1315
- readyState = "open";
1316
- bytesWritten = 0;
1317
- _listeners = {};
1318
- _socketId;
1319
- // Readable stream state stub for ws compatibility (socketOnClose checks _readableState.endEmitted)
1320
- _readableState = { endEmitted: false };
1321
- _writableState = { finished: false, errorEmitted: false };
1322
- constructor(socketId, options) {
1323
- this._socketId = socketId;
1324
- this.remoteAddress = options?.host || "127.0.0.1";
1325
- this.remotePort = options?.port || 80;
1326
- }
1327
- setTimeout(_ms, _cb) { return this; }
1328
- setNoDelay(_noDelay) { return this; }
1329
- setKeepAlive(_enable, _delay) { return this; }
1330
- ref() { return this; }
1331
- unref() { return this; }
1332
- cork() { }
1333
- uncork() { }
1334
- pause() { return this; }
1335
- resume() { return this; }
1336
- address() {
1337
- return { address: this.localAddress, family: "IPv4", port: this.localPort };
1338
- }
1339
- on(event, listener) {
1340
- if (!this._listeners[event])
1341
- this._listeners[event] = [];
1342
- this._listeners[event].push(listener);
1343
- return this;
1344
- }
1345
- addListener(event, listener) {
1346
- return this.on(event, listener);
1347
- }
1348
- once(event, listener) {
1349
- const wrapper = (...args) => {
1350
- this.off(event, wrapper);
1351
- listener(...args);
1352
- };
1353
- return this.on(event, wrapper);
1354
- }
1355
- off(event, listener) {
1356
- if (this._listeners[event]) {
1357
- const idx = this._listeners[event].indexOf(listener);
1358
- if (idx !== -1)
1359
- this._listeners[event].splice(idx, 1);
1360
- }
1361
- return this;
1362
- }
1363
- removeListener(event, listener) {
1364
- return this.off(event, listener);
1365
- }
1366
- removeAllListeners(event) {
1367
- if (event) {
1368
- delete this._listeners[event];
1369
- }
1370
- else {
1371
- this._listeners = {};
1372
- }
1373
- return this;
1374
- }
1375
- emit(event, ...args) {
1376
- const handlers = this._listeners[event];
1377
- if (handlers)
1378
- handlers.slice().forEach((fn) => fn.call(this, ...args));
1379
- return handlers !== undefined && handlers.length > 0;
1380
- }
1381
- listenerCount(event) {
1382
- return this._listeners[event]?.length || 0;
1383
- }
1384
- write(data, encodingOrCb, cb) {
1385
- if (this.destroyed)
1386
- return false;
1387
- const callback = typeof encodingOrCb === "function" ? encodingOrCb : cb;
1388
- if (typeof _upgradeSocketWriteRaw !== "undefined") {
1389
- let base64;
1390
- if (typeof Buffer !== "undefined" && Buffer.isBuffer(data)) {
1391
- base64 = data.toString("base64");
1392
- }
1393
- else if (typeof data === "string") {
1394
- base64 = typeof Buffer !== "undefined" ? Buffer.from(data).toString("base64") : btoa(data);
1395
- }
1396
- else if (data instanceof Uint8Array) {
1397
- base64 = typeof Buffer !== "undefined" ? Buffer.from(data).toString("base64") : btoa(String.fromCharCode(...data));
1398
- }
1399
- else {
1400
- base64 = typeof Buffer !== "undefined" ? Buffer.from(String(data)).toString("base64") : btoa(String(data));
1401
- }
1402
- this.bytesWritten += base64.length;
1403
- _upgradeSocketWriteRaw.applySync(undefined, [this._socketId, base64]);
1404
- }
1405
- if (callback)
1406
- callback();
1407
- return true;
1408
- }
1409
- end(data) {
1410
- if (data)
1411
- this.write(data);
1412
- if (typeof _upgradeSocketEndRaw !== "undefined" && !this.destroyed) {
1413
- _upgradeSocketEndRaw.applySync(undefined, [this._socketId]);
1414
- }
1415
- this.writable = false;
1416
- this.emit("finish");
1417
- return this;
1418
- }
1419
- destroy(err) {
1420
- if (this.destroyed)
1421
- return this;
1422
- this.destroyed = true;
1423
- this.writable = false;
1424
- this.readable = false;
1425
- this._readableState.endEmitted = true;
1426
- this._writableState.finished = true;
1427
- if (typeof _upgradeSocketDestroyRaw !== "undefined") {
1428
- _upgradeSocketDestroyRaw.applySync(undefined, [this._socketId]);
1429
- }
1430
- upgradeSocketInstances.delete(this._socketId);
1431
- if (err)
1432
- this.emit("error", err);
1433
- this.emit("close", false);
1434
- return this;
1435
- }
1436
- // Push data received from the host into this socket
1437
- _pushData(data) {
1438
- this.emit("data", data);
1439
- }
1440
- // Signal end-of-stream from the host
1441
- _pushEnd() {
1442
- this.readable = false;
1443
- this._readableState.endEmitted = true;
1444
- this._writableState.finished = true;
1445
- this.emit("end");
1446
- this.emit("close", false);
1447
- upgradeSocketInstances.delete(this._socketId);
1448
- }
1449
- }
1450
- /** Route an incoming HTTP upgrade to the server's 'upgrade' event listeners. */
1451
- function dispatchUpgradeRequest(serverId, requestJson, headBase64, socketId) {
1452
- const server = serverInstances.get(serverId);
1453
- if (!server) {
1454
- throw new Error(`Unknown HTTP server for upgrade: ${serverId}`);
1455
- }
1456
- const request = JSON.parse(requestJson);
1457
- const incoming = new ServerIncomingMessage(request);
1458
- const head = typeof Buffer !== "undefined" ? Buffer.from(headBase64, "base64") : new Uint8Array(0);
1459
- const socket = new UpgradeSocket(socketId, {
1460
- host: incoming.headers["host"]?.split(":")[0] || "127.0.0.1",
1461
- });
1462
- upgradeSocketInstances.set(socketId, socket);
1463
- // Emit 'upgrade' on the server — ws.WebSocketServer listens for this
1464
- server._emit("upgrade", incoming, socket, head);
1465
- }
1466
- /** Push data from host to an upgrade socket. */
1467
- function onUpgradeSocketData(socketId, dataBase64) {
1468
- const socket = upgradeSocketInstances.get(socketId);
1469
- if (socket) {
1470
- const data = typeof Buffer !== "undefined" ? Buffer.from(dataBase64, "base64") : new Uint8Array(0);
1471
- socket._pushData(data);
1472
- }
1473
- }
1474
- /** Signal end-of-stream from host to an upgrade socket. */
1475
- function onUpgradeSocketEnd(socketId) {
1476
- const socket = upgradeSocketInstances.get(socketId);
1477
- if (socket) {
1478
- socket._pushEnd();
1479
- }
1480
- }
1481
- // Function-based ServerResponse constructor — allows .call() inheritance
1482
- // used by light-my-request (Fastify's inject), which does
1483
- // http.ServerResponse.call(this, req) + util.inherits(Response, http.ServerResponse)
1484
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
1485
- function ServerResponseCallable() {
1486
- this.statusCode = 200;
1487
- this.statusMessage = "OK";
1488
- this.headersSent = false;
1489
- this.writable = true;
1490
- this.writableFinished = false;
1491
- this._headers = new Map();
1492
- this._chunks = [];
1493
- this._chunksBytes = 0;
1494
- this._listeners = {};
1495
- this._closedPromise = new Promise((resolve) => {
1496
- this._resolveClosed = resolve;
1497
- });
1498
- // Writable stream state stub
1499
- this._writableState = { length: 0, ended: false, finished: false, objectMode: false, corked: 0 };
1500
- // Fake socket for frameworks/inject libraries that access res.socket
1501
- const fakeSocket = {
1502
- writable: true,
1503
- on() { return fakeSocket; },
1504
- once() { return fakeSocket; },
1505
- removeListener() { return fakeSocket; },
1506
- destroy() { },
1507
- end() { },
1508
- cork() { },
1509
- uncork() { },
1510
- write() { return true; },
1511
- };
1512
- this.socket = fakeSocket;
1513
- this.connection = fakeSocket;
1514
- }
1515
- ServerResponseCallable.prototype = Object.create(ServerResponseBridge.prototype, {
1516
- constructor: { value: ServerResponseCallable, writable: true, configurable: true },
1517
- });
1518
- // Create HTTP module
1519
- function createHttpModule(protocol) {
1520
- const defaultProtocol = protocol === "https" ? "https:" : "http:";
1521
- const moduleAgent = new Agent({ keepAlive: false });
1522
- // Set module-level globalAgent so ClientRequest defaults to it
1523
- _moduleGlobalAgent = moduleAgent;
1524
- // Ensure protocol is set on request options (defaults to module protocol)
1525
- function ensureProtocol(opts) {
1526
- if (!opts.protocol)
1527
- return { ...opts, protocol: defaultProtocol };
1528
- return opts;
1529
- }
1530
- return {
1531
- request(options, callback) {
1532
- let opts;
1533
- if (typeof options === "string") {
1534
- const url = new URL(options);
1535
- opts = {
1536
- protocol: url.protocol,
1537
- hostname: url.hostname,
1538
- port: url.port,
1539
- path: url.pathname + url.search,
1540
- };
1541
- }
1542
- else if (options instanceof URL) {
1543
- opts = {
1544
- protocol: options.protocol,
1545
- hostname: options.hostname,
1546
- port: options.port,
1547
- path: options.pathname + options.search,
1548
- };
1549
- }
1550
- else {
1551
- opts = options;
1552
- }
1553
- return new ClientRequest(ensureProtocol(opts), callback);
1554
- },
1555
- get(options, callback) {
1556
- let opts;
1557
- if (typeof options === "string") {
1558
- const url = new URL(options);
1559
- opts = {
1560
- protocol: url.protocol,
1561
- hostname: url.hostname,
1562
- port: url.port,
1563
- path: url.pathname + url.search,
1564
- method: "GET",
1565
- };
1566
- }
1567
- else if (options instanceof URL) {
1568
- opts = {
1569
- protocol: options.protocol,
1570
- hostname: options.hostname,
1571
- port: options.port,
1572
- path: options.pathname + options.search,
1573
- method: "GET",
1574
- };
1575
- }
1576
- else {
1577
- opts = { ...options, method: "GET" };
1578
- }
1579
- const req = new ClientRequest(ensureProtocol(opts), callback);
1580
- req.end();
1581
- return req;
1582
- },
1583
- createServer(_optionsOrListener, maybeListener) {
1584
- const listener = typeof _optionsOrListener === "function"
1585
- ? _optionsOrListener
1586
- : maybeListener;
1587
- return new Server(listener);
1588
- },
1589
- Agent,
1590
- globalAgent: moduleAgent,
1591
- Server: Server,
1592
- ServerResponse: ServerResponseCallable,
1593
- IncomingMessage: IncomingMessage,
1594
- ClientRequest: ClientRequest,
1595
- METHODS: ["GET", "POST", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS"],
1596
- STATUS_CODES: {
1597
- 200: "OK",
1598
- 201: "Created",
1599
- 204: "No Content",
1600
- 301: "Moved Permanently",
1601
- 302: "Found",
1602
- 304: "Not Modified",
1603
- 400: "Bad Request",
1604
- 401: "Unauthorized",
1605
- 403: "Forbidden",
1606
- 404: "Not Found",
1607
- 500: "Internal Server Error",
1608
- },
1609
- };
1610
- }
1611
- export const http = createHttpModule("http");
1612
- export const https = createHttpModule("https");
1613
- export const http2 = {
1614
- Http2ServerRequest: class Http2ServerRequest {
1615
- },
1616
- Http2ServerResponse: class Http2ServerResponse {
1617
- },
1618
- createServer() {
1619
- throw new Error("http2.createServer is not supported in sandbox");
1620
- },
1621
- createSecureServer() {
1622
- throw new Error("http2.createSecureServer is not supported in sandbox");
1623
- },
1624
- };
1625
- // ----------------------------------------------------------------
1626
- // net module — TCP socket bridge
1627
- // ----------------------------------------------------------------
1628
- const netSocketInstances = new Map();
1629
- class NetSocket {
1630
- remoteAddress = "";
1631
- remotePort = 0;
1632
- remoteFamily = "";
1633
- localAddress = "0.0.0.0";
1634
- localPort = 0;
1635
- connecting = true;
1636
- pending = true;
1637
- destroyed = false;
1638
- writable = true;
1639
- readable = true;
1640
- readyState = "opening";
1641
- bytesRead = 0;
1642
- bytesWritten = 0;
1643
- _listeners = {};
1644
- /** @internal socket ID shared with TLS upgrade bridge */
1645
- _socketId = -1;
1646
- _connectHost = "";
1647
- _connectPort = 0;
1648
- // Stream state stubs for compatibility (ssh2 checks _readableState.ended)
1649
- _readableState = { endEmitted: false, ended: false };
1650
- _writableState = { finished: false, errorEmitted: false, ended: false };
1651
- constructor(_options) {
1652
- // Options like { allowHalfOpen } are accepted but ignored
1653
- }
1654
- connect(...args) {
1655
- // Parse overloaded signatures: connect(port, host?, cb?) or connect({port, host}, cb?)
1656
- let port;
1657
- let host;
1658
- let connectListener;
1659
- if (typeof args[0] === "object" && args[0] !== null) {
1660
- const opts = args[0];
1661
- port = Number(opts.port);
1662
- host = String(opts.host || "127.0.0.1");
1663
- if (typeof args[1] === "function")
1664
- connectListener = args[1];
1665
- }
1666
- else {
1667
- port = Number(args[0]);
1668
- host = typeof args[1] === "string" ? args[1] : "127.0.0.1";
1669
- if (typeof args[1] === "function") {
1670
- connectListener = args[1];
1671
- host = "127.0.0.1";
1672
- }
1673
- else if (typeof args[2] === "function") {
1674
- connectListener = args[2];
1675
- }
1676
- }
1677
- this._connectHost = host;
1678
- this._connectPort = port;
1679
- if (connectListener)
1680
- this.once("connect", connectListener);
1681
- if (typeof _netSocketConnectRaw === "undefined") {
1682
- // Schedule error emission asynchronously like real Node
1683
- Promise.resolve().then(() => {
1684
- const err = new Error("net.Socket requires NetworkAdapter to be configured");
1685
- this._onError(err.message);
1686
- });
1687
- return this;
1688
- }
1689
- // Register active handle
1690
- if (typeof _registerHandle !== "undefined") {
1691
- _registerHandle(`net.socket:${host}:${port}`, `TCP connection to ${host}:${port}`);
1692
- }
1693
- // Synchronous call: host creates socket, starts connecting, returns socketId
1694
- this._socketId = _netSocketConnectRaw.applySync(undefined, [host, port]);
1695
- netSocketInstances.set(this._socketId, this);
1696
- return this;
1697
- }
1698
- setTimeout(_ms, _cb) { return this; }
1699
- setNoDelay(_noDelay) { return this; }
1700
- setKeepAlive(_enable, _delay) { return this; }
1701
- setMaxListeners(_n) { return this; }
1702
- getMaxListeners() { return 10; }
1703
- ref() { return this; }
1704
- unref() { return this; }
1705
- cork() { }
1706
- uncork() { }
1707
- pause() { return this; }
1708
- resume() { return this; }
1709
- pipe(destination) { return destination; }
1710
- address() {
1711
- return { address: this.localAddress, family: "IPv4", port: this.localPort };
1712
- }
1713
- listeners(event) {
1714
- return (this._listeners[event] || []).slice();
1715
- }
1716
- rawListeners(event) {
1717
- return this.listeners(event);
1718
- }
1719
- eventNames() {
1720
- return Object.keys(this._listeners).filter((k) => (this._listeners[k]?.length ?? 0) > 0);
1721
- }
1722
- prependListener(event, listener) {
1723
- if (!this._listeners[event])
1724
- this._listeners[event] = [];
1725
- this._listeners[event].unshift(listener);
1726
- return this;
1727
- }
1728
- prependOnceListener(event, listener) {
1729
- const wrapper = (...args) => {
1730
- this.off(event, wrapper);
1731
- listener(...args);
1732
- };
1733
- return this.prependListener(event, wrapper);
1734
- }
1735
- on(event, listener) {
1736
- if (!this._listeners[event])
1737
- this._listeners[event] = [];
1738
- this._listeners[event].push(listener);
1739
- return this;
1740
- }
1741
- addListener(event, listener) { return this.on(event, listener); }
1742
- once(event, listener) {
1743
- const wrapper = (...args) => {
1744
- this.off(event, wrapper);
1745
- listener(...args);
1746
- };
1747
- return this.on(event, wrapper);
1748
- }
1749
- off(event, listener) {
1750
- if (this._listeners[event]) {
1751
- const idx = this._listeners[event].indexOf(listener);
1752
- if (idx !== -1)
1753
- this._listeners[event].splice(idx, 1);
1754
- }
1755
- return this;
1756
- }
1757
- removeListener(event, listener) { return this.off(event, listener); }
1758
- removeAllListeners(event) {
1759
- if (event) {
1760
- delete this._listeners[event];
1761
- }
1762
- else {
1763
- this._listeners = {};
1764
- }
1765
- return this;
1766
- }
1767
- emit(event, ...args) {
1768
- const handlers = this._listeners[event];
1769
- if (handlers)
1770
- handlers.slice().forEach((fn) => fn.call(this, ...args));
1771
- return handlers !== undefined && handlers.length > 0;
1772
- }
1773
- listenerCount(event) {
1774
- return this._listeners[event]?.length || 0;
1775
- }
1776
- write(data, encodingOrCb, cb) {
1777
- if (this.destroyed)
1778
- return false;
1779
- const callback = typeof encodingOrCb === "function" ? encodingOrCb : cb;
1780
- if (typeof _netSocketWriteRaw !== "undefined" && this._socketId >= 0) {
1781
- let base64;
1782
- if (typeof Buffer !== "undefined" && Buffer.isBuffer(data)) {
1783
- base64 = data.toString("base64");
1784
- }
1785
- else if (typeof data === "string") {
1786
- const encoding = typeof encodingOrCb === "string" ? encodingOrCb : "utf8";
1787
- base64 = typeof Buffer !== "undefined" ? Buffer.from(data, encoding).toString("base64") : btoa(data);
1788
- }
1789
- else if (data instanceof Uint8Array) {
1790
- base64 = typeof Buffer !== "undefined" ? Buffer.from(data).toString("base64") : btoa(String.fromCharCode(...data));
1791
- }
1792
- else {
1793
- base64 = typeof Buffer !== "undefined" ? Buffer.from(String(data)).toString("base64") : btoa(String(data));
1794
- }
1795
- this.bytesWritten += base64.length;
1796
- _netSocketWriteRaw.applySync(undefined, [this._socketId, base64]);
1797
- }
1798
- if (callback)
1799
- callback();
1800
- return true;
1801
- }
1802
- end(data, encodingOrCb, cb) {
1803
- if (data !== undefined && data !== null)
1804
- this.write(data, encodingOrCb, cb);
1805
- if (typeof _netSocketEndRaw !== "undefined" && this._socketId >= 0 && !this.destroyed) {
1806
- _netSocketEndRaw.applySync(undefined, [this._socketId]);
1807
- }
1808
- this.writable = false;
1809
- this.readyState = this.readable ? "readOnly" : "closed";
1810
- this.emit("finish");
1811
- return this;
1812
- }
1813
- destroy(err) {
1814
- if (this.destroyed)
1815
- return this;
1816
- this.destroyed = true;
1817
- this.writable = false;
1818
- this.readable = false;
1819
- this.readyState = "closed";
1820
- this._readableState.endEmitted = true;
1821
- this._writableState.finished = true;
1822
- if (typeof _netSocketDestroyRaw !== "undefined" && this._socketId >= 0) {
1823
- _netSocketDestroyRaw.applySync(undefined, [this._socketId]);
1824
- }
1825
- this._cleanup();
1826
- if (err)
1827
- this.emit("error", err);
1828
- this.emit("close", !!err);
1829
- return this;
1830
- }
1831
- // Host→Guest event dispatch handlers
1832
- _onConnect() {
1833
- this.connecting = false;
1834
- this.pending = false;
1835
- this.remoteAddress = this._connectHost;
1836
- this.remotePort = this._connectPort;
1837
- this.remoteFamily = "IPv4";
1838
- this.readyState = "open";
1839
- this.emit("connect");
1840
- this.emit("ready");
1841
- }
1842
- _onData(dataBase64) {
1843
- const buf = typeof Buffer !== "undefined" ? Buffer.from(dataBase64, "base64") : new Uint8Array(0);
1844
- this.bytesRead += buf.length;
1845
- this.emit("data", buf);
1846
- }
1847
- _onEnd() {
1848
- this.readable = false;
1849
- this._readableState.endEmitted = true;
1850
- this._readableState.ended = true;
1851
- this.readyState = this.writable ? "writeOnly" : "closed";
1852
- this.emit("end");
1853
- }
1854
- _onError(message) {
1855
- const err = new Error(message);
1856
- this.destroy(err);
1857
- }
1858
- _onClose(hadError) {
1859
- this._cleanup();
1860
- if (!this.destroyed) {
1861
- this.destroyed = true;
1862
- this.readable = false;
1863
- this.writable = false;
1864
- this.readyState = "closed";
1865
- this.emit("close", hadError);
1866
- }
1867
- }
1868
- _cleanup() {
1869
- if (this._socketId >= 0) {
1870
- netSocketInstances.delete(this._socketId);
1871
- if (typeof _unregisterHandle !== "undefined") {
1872
- _unregisterHandle(`net.socket:${this._connectHost}:${this._connectPort}`);
1873
- }
1874
- }
1875
- }
1876
- }
1877
- /** Dispatch events from host to guest net sockets. */
1878
- function onNetSocketDispatch(socketId, type, data) {
1879
- const socket = netSocketInstances.get(socketId);
1880
- if (!socket)
1881
- return;
1882
- switch (type) {
1883
- case "connect":
1884
- socket._onConnect();
1885
- break;
1886
- case "data":
1887
- socket._onData(data);
1888
- break;
1889
- case "end":
1890
- socket._onEnd();
1891
- break;
1892
- case "error":
1893
- socket._onError(data);
1894
- break;
1895
- case "close":
1896
- socket._onClose(data === "1");
1897
- break;
1898
- case "secureConnect":
1899
- socket.emit("secureConnect");
1900
- break;
1901
- }
1902
- }
1903
- // Validate IP address format
1904
- function netIsIP(input) {
1905
- if (typeof input !== "string")
1906
- return 0;
1907
- // IPv4: four octets 0-255
1908
- if (/^(\d{1,3}\.){3}\d{1,3}$/.test(input)) {
1909
- const parts = input.split(".");
1910
- if (parts.every((p) => { const n = Number(p); return n >= 0 && n <= 255; }))
1911
- return 4;
1912
- }
1913
- // IPv6: simplified check
1914
- if (/^(::)?([0-9a-fA-F]{1,4}(::?)){0,7}([0-9a-fA-F]{1,4})?$/.test(input))
1915
- return 6;
1916
- if (/^::ffff:\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.test(input))
1917
- return 6;
1918
- return 0;
1919
- }
1920
- export const net = {
1921
- Socket: NetSocket,
1922
- connect(portOrOpts, hostOrCb, cb) {
1923
- const socket = new NetSocket();
1924
- socket.connect(portOrOpts, hostOrCb, cb);
1925
- return socket;
1926
- },
1927
- createConnection(portOrOpts, hostOrCb, cb) {
1928
- return net.connect(portOrOpts, hostOrCb, cb);
1929
- },
1930
- createServer() {
1931
- throw new Error("net.createServer is not supported in sandbox");
1932
- },
1933
- isIP: netIsIP,
1934
- isIPv4(input) { return netIsIP(input) === 4; },
1935
- isIPv6(input) { return netIsIP(input) === 6; },
1936
- };
1937
- // ----------------------------------------------------------------
1938
- // tls module — TLS socket upgrade bridge
1939
- // ----------------------------------------------------------------
1940
- /** TLS socket that wraps an existing NetSocket after host-side TLS upgrade. */
1941
- class TLSSocket extends NetSocket {
1942
- encrypted = true;
1943
- authorized = false;
1944
- authorizationError = null;
1945
- alpnProtocol = false;
1946
- _wrappedSocket = null;
1947
- constructor(originalSocket) {
1948
- super();
1949
- this._wrappedSocket = originalSocket;
1950
- // Copy connection state from original socket
1951
- this.remoteAddress = originalSocket.remoteAddress;
1952
- this.remotePort = originalSocket.remotePort;
1953
- this.remoteFamily = originalSocket.remoteFamily;
1954
- this.localAddress = originalSocket.localAddress;
1955
- this.localPort = originalSocket.localPort;
1956
- this.connecting = false;
1957
- this.pending = false;
1958
- this.readyState = "open";
1959
- // Share the same socketId — bridge events route here after upgrade
1960
- this._socketId = originalSocket._socketId;
1961
- // Copy private connect info so _cleanup unregisters the correct handle
1962
- this._connectHost = originalSocket._connectHost;
1963
- this._connectPort = originalSocket._connectPort;
1964
- netSocketInstances.set(this._socketId, this);
1965
- }
1966
- _onSecureConnect() {
1967
- this.authorized = true;
1968
- this.emit("secureConnect");
1969
- }
1970
- // Forward end/close to the wrapped raw socket — Node.js tls.TLSSocket
1971
- // closes the underlying socket, which fires its 'close' event. Libraries
1972
- // like pg rely on the original socket's 'close' listener to detect shutdown.
1973
- _onEnd() {
1974
- super._onEnd();
1975
- if (this._wrappedSocket)
1976
- this._wrappedSocket._onEnd();
1977
- }
1978
- _onClose(hadError) {
1979
- super._onClose(hadError);
1980
- if (this._wrappedSocket) {
1981
- this._wrappedSocket._onClose(hadError);
1982
- this._wrappedSocket = null;
1983
- }
1984
- }
1985
- }
1986
- export const tlsModule = {
1987
- TLSSocket: TLSSocket,
1988
- connect(options) {
1989
- const existingSocket = options.socket;
1990
- if (!existingSocket || existingSocket._socketId < 0) {
1991
- throw new Error("tls.connect requires an existing connected socket via options.socket");
1992
- }
1993
- // Create TLS socket wrapper on sandbox side
1994
- const tlsSocket = new TLSSocket(existingSocket);
1995
- if (typeof _netSocketUpgradeTlsRaw === "undefined") {
1996
- Promise.resolve().then(() => {
1997
- tlsSocket._onError("tls.connect requires NetworkAdapter TLS support");
1998
- });
1999
- return tlsSocket;
2000
- }
2001
- // Tell host to wrap the underlying TCP socket with TLS
2002
- _netSocketUpgradeTlsRaw.applySync(undefined, [
2003
- existingSocket._socketId,
2004
- JSON.stringify({
2005
- rejectUnauthorized: options.rejectUnauthorized ?? true,
2006
- servername: options.servername,
2007
- }),
2008
- ]);
2009
- return tlsSocket;
2010
- },
2011
- createSecureContext(_options) {
2012
- return {};
2013
- },
2014
- };
2015
- // Export modules and make them available as globals for require()
2016
- exposeCustomGlobal("_httpModule", http);
2017
- exposeCustomGlobal("_httpsModule", https);
2018
- exposeCustomGlobal("_http2Module", http2);
2019
- exposeCustomGlobal("_dnsModule", dns);
2020
- exposeCustomGlobal("_netModule", net);
2021
- exposeCustomGlobal("_tlsModule", tlsModule);
2022
- exposeCustomGlobal("_httpServerDispatch", dispatchServerRequest);
2023
- exposeCustomGlobal("_httpServerUpgradeDispatch", dispatchUpgradeRequest);
2024
- exposeCustomGlobal("_upgradeSocketData", onUpgradeSocketData);
2025
- exposeCustomGlobal("_upgradeSocketEnd", onUpgradeSocketEnd);
2026
- exposeCustomGlobal("_netSocketDispatch", onNetSocketDispatch);
2027
- // Harden fetch API globals (non-writable, non-configurable)
2028
- exposeCustomGlobal("fetch", fetch);
2029
- exposeCustomGlobal("Headers", Headers);
2030
- exposeCustomGlobal("Request", Request);
2031
- exposeCustomGlobal("Response", Response);
2032
- if (typeof globalThis.Blob === "undefined") {
2033
- // Minimal Blob stub used by server frameworks for instanceof checks.
2034
- exposeCustomGlobal("Blob", class BlobStub {
2035
- });
2036
- }
2037
- export default {
2038
- fetch,
2039
- Headers,
2040
- Request,
2041
- Response,
2042
- dns,
2043
- http,
2044
- https,
2045
- http2,
2046
- net,
2047
- tls: tlsModule,
2048
- IncomingMessage,
2049
- ClientRequest,
2050
- };