@ricsam/isolate-fetch 0.0.1 → 0.1.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.
@@ -0,0 +1,1800 @@
1
+ // @bun @bun-cjs
2
+ (function(exports, require, module, __filename, __dirname) {var __create = Object.create;
3
+ var __getProtoOf = Object.getPrototypeOf;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __toESM = (mod, isNodeMode, target) => {
9
+ target = mod != null ? __create(__getProtoOf(mod)) : {};
10
+ const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
11
+ for (let key of __getOwnPropNames(mod))
12
+ if (!__hasOwnProp.call(to, key))
13
+ __defProp(to, key, {
14
+ get: () => mod[key],
15
+ enumerable: true
16
+ });
17
+ return to;
18
+ };
19
+ var __moduleCache = /* @__PURE__ */ new WeakMap;
20
+ var __toCommonJS = (from) => {
21
+ var entry = __moduleCache.get(from), desc;
22
+ if (entry)
23
+ return entry;
24
+ entry = __defProp({}, "__esModule", { value: true });
25
+ if (from && typeof from === "object" || typeof from === "function")
26
+ __getOwnPropNames(from).map((key) => !__hasOwnProp.call(entry, key) && __defProp(entry, key, {
27
+ get: () => from[key],
28
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
29
+ }));
30
+ __moduleCache.set(from, entry);
31
+ return entry;
32
+ };
33
+ var __export = (target, all) => {
34
+ for (var name in all)
35
+ __defProp(target, name, {
36
+ get: all[name],
37
+ enumerable: true,
38
+ configurable: true,
39
+ set: (newValue) => all[name] = () => newValue
40
+ });
41
+ };
42
+
43
+ // packages/fetch/src/index.ts
44
+ var exports_src = {};
45
+ __export(exports_src, {
46
+ setupFetch: () => setupFetch,
47
+ clearAllInstanceState: () => import_isolate_core.clearAllInstanceState
48
+ });
49
+ module.exports = __toCommonJS(exports_src);
50
+ var import_isolated_vm = __toESM(require("isolated-vm"));
51
+ var import_isolate_core = require("@ricsam/isolate-core");
52
+ var import_stream_state = require("./stream-state.cjs");
53
+ var instanceStateMap = new WeakMap;
54
+ var nextInstanceId = 1;
55
+ function getInstanceStateMapForContext(context) {
56
+ let map = instanceStateMap.get(context);
57
+ if (!map) {
58
+ map = new Map;
59
+ instanceStateMap.set(context, map);
60
+ }
61
+ return map;
62
+ }
63
+ var headersCode = `
64
+ (function() {
65
+ class Headers {
66
+ #headers = new Map(); // lowercase key -> [originalCase, values[]]
67
+
68
+ constructor(init) {
69
+ if (init instanceof Headers) {
70
+ init.forEach((value, key) => this.append(key, value));
71
+ } else if (Array.isArray(init)) {
72
+ for (const pair of init) {
73
+ if (Array.isArray(pair) && pair.length >= 2) {
74
+ this.append(pair[0], pair[1]);
75
+ }
76
+ }
77
+ } else if (init && typeof init === 'object') {
78
+ for (const [key, value] of Object.entries(init)) {
79
+ this.append(key, value);
80
+ }
81
+ }
82
+ }
83
+
84
+ append(name, value) {
85
+ const key = String(name).toLowerCase();
86
+ const valueStr = String(value);
87
+ const existing = this.#headers.get(key);
88
+ if (existing) {
89
+ existing[1].push(valueStr);
90
+ } else {
91
+ this.#headers.set(key, [String(name), [valueStr]]);
92
+ }
93
+ }
94
+
95
+ delete(name) {
96
+ this.#headers.delete(String(name).toLowerCase());
97
+ }
98
+
99
+ get(name) {
100
+ const entry = this.#headers.get(String(name).toLowerCase());
101
+ return entry ? entry[1].join(', ') : null;
102
+ }
103
+
104
+ getSetCookie() {
105
+ const entry = this.#headers.get('set-cookie');
106
+ return entry ? [...entry[1]] : [];
107
+ }
108
+
109
+ has(name) {
110
+ return this.#headers.has(String(name).toLowerCase());
111
+ }
112
+
113
+ set(name, value) {
114
+ const key = String(name).toLowerCase();
115
+ this.#headers.set(key, [String(name), [String(value)]]);
116
+ }
117
+
118
+ forEach(callback, thisArg) {
119
+ for (const [key, [originalName, values]] of this.#headers) {
120
+ callback.call(thisArg, values.join(', '), originalName, this);
121
+ }
122
+ }
123
+
124
+ *entries() {
125
+ for (const [key, [name, values]] of this.#headers) {
126
+ yield [name, values.join(', ')];
127
+ }
128
+ }
129
+
130
+ *keys() {
131
+ for (const [key, [name]] of this.#headers) {
132
+ yield name;
133
+ }
134
+ }
135
+
136
+ *values() {
137
+ for (const [key, [name, values]] of this.#headers) {
138
+ yield values.join(', ');
139
+ }
140
+ }
141
+
142
+ [Symbol.iterator]() {
143
+ return this.entries();
144
+ }
145
+ }
146
+
147
+ globalThis.Headers = Headers;
148
+ })();
149
+ `;
150
+ var formDataCode = `
151
+ (function() {
152
+ class FormData {
153
+ #entries = []; // Array of [name, value]
154
+
155
+ append(name, value, filename) {
156
+ let finalValue = value;
157
+ if (value instanceof Blob && !(value instanceof File)) {
158
+ if (filename !== undefined) {
159
+ finalValue = new File([value], String(filename), { type: value.type });
160
+ }
161
+ } else if (value instanceof File && filename !== undefined) {
162
+ finalValue = new File([value], String(filename), {
163
+ type: value.type,
164
+ lastModified: value.lastModified
165
+ });
166
+ }
167
+ this.#entries.push([String(name), finalValue]);
168
+ }
169
+
170
+ delete(name) {
171
+ const nameStr = String(name);
172
+ this.#entries = this.#entries.filter(([n]) => n !== nameStr);
173
+ }
174
+
175
+ get(name) {
176
+ const nameStr = String(name);
177
+ const entry = this.#entries.find(([n]) => n === nameStr);
178
+ return entry ? entry[1] : null;
179
+ }
180
+
181
+ getAll(name) {
182
+ const nameStr = String(name);
183
+ return this.#entries.filter(([n]) => n === nameStr).map(([, v]) => v);
184
+ }
185
+
186
+ has(name) {
187
+ return this.#entries.some(([n]) => n === String(name));
188
+ }
189
+
190
+ set(name, value, filename) {
191
+ const nameStr = String(name);
192
+ this.delete(nameStr);
193
+ this.append(nameStr, value, filename);
194
+ }
195
+
196
+ *entries() {
197
+ for (const [name, value] of this.#entries) {
198
+ yield [name, value];
199
+ }
200
+ }
201
+
202
+ *keys() {
203
+ for (const [name] of this.#entries) {
204
+ yield name;
205
+ }
206
+ }
207
+
208
+ *values() {
209
+ for (const [, value] of this.#entries) {
210
+ yield value;
211
+ }
212
+ }
213
+
214
+ forEach(callback, thisArg) {
215
+ for (const [name, value] of this.#entries) {
216
+ callback.call(thisArg, value, name, this);
217
+ }
218
+ }
219
+
220
+ [Symbol.iterator]() {
221
+ return this.entries();
222
+ }
223
+ }
224
+
225
+ globalThis.FormData = FormData;
226
+ })();
227
+ `;
228
+ var multipartCode = `
229
+ (function() {
230
+ // Find byte sequence in Uint8Array
231
+ function findSequence(haystack, needle, start = 0) {
232
+ outer: for (let i = start; i <= haystack.length - needle.length; i++) {
233
+ for (let j = 0; j < needle.length; j++) {
234
+ if (haystack[i + j] !== needle[j]) continue outer;
235
+ }
236
+ return i;
237
+ }
238
+ return -1;
239
+ }
240
+
241
+ // Parse header lines into object
242
+ function parseHeaders(text) {
243
+ const headers = {};
244
+ for (const line of text.split(/\\r?\\n/)) {
245
+ const colonIdx = line.indexOf(':');
246
+ if (colonIdx > 0) {
247
+ const name = line.slice(0, colonIdx).trim().toLowerCase();
248
+ const value = line.slice(colonIdx + 1).trim();
249
+ headers[name] = value;
250
+ }
251
+ }
252
+ return headers;
253
+ }
254
+
255
+ // Parse multipart/form-data body into FormData
256
+ globalThis.__parseMultipartFormData = function(bodyBytes, contentType) {
257
+ const formData = new FormData();
258
+
259
+ // Extract boundary from Content-Type
260
+ const boundaryMatch = contentType.match(/boundary=([^;]+)/i);
261
+ if (!boundaryMatch) return formData;
262
+
263
+ const boundary = boundaryMatch[1].replace(/^["']|["']$/g, '');
264
+ const encoder = new TextEncoder();
265
+ const decoder = new TextDecoder();
266
+ const boundaryBytes = encoder.encode('--' + boundary);
267
+
268
+ // Find first boundary
269
+ let pos = findSequence(bodyBytes, boundaryBytes, 0);
270
+ if (pos === -1) return formData;
271
+ pos += boundaryBytes.length;
272
+
273
+ while (pos < bodyBytes.length) {
274
+ // Skip CRLF after boundary
275
+ if (bodyBytes[pos] === 0x0d && bodyBytes[pos + 1] === 0x0a) pos += 2;
276
+ else if (bodyBytes[pos] === 0x0a) pos += 1;
277
+
278
+ // Check for closing boundary (--)
279
+ if (bodyBytes[pos] === 0x2d && bodyBytes[pos + 1] === 0x2d) break;
280
+
281
+ // Find header/body separator (CRLFCRLF)
282
+ const crlfcrlf = encoder.encode('\\r\\n\\r\\n');
283
+ const headersEnd = findSequence(bodyBytes, crlfcrlf, pos);
284
+ if (headersEnd === -1) break;
285
+
286
+ // Parse headers
287
+ const headersText = decoder.decode(bodyBytes.slice(pos, headersEnd));
288
+ const headers = parseHeaders(headersText);
289
+ pos = headersEnd + 4;
290
+
291
+ // Find next boundary
292
+ const nextBoundary = findSequence(bodyBytes, boundaryBytes, pos);
293
+ if (nextBoundary === -1) break;
294
+
295
+ // Extract content (minus trailing CRLF)
296
+ let contentEnd = nextBoundary;
297
+ if (contentEnd > 0 && bodyBytes[contentEnd - 1] === 0x0a) contentEnd--;
298
+ if (contentEnd > 0 && bodyBytes[contentEnd - 1] === 0x0d) contentEnd--;
299
+ const content = bodyBytes.slice(pos, contentEnd);
300
+
301
+ // Parse Content-Disposition
302
+ const disposition = headers['content-disposition'] || '';
303
+ const nameMatch = disposition.match(/name="([^"]+)"/);
304
+ const filenameMatch = disposition.match(/filename="([^"]+)"/);
305
+
306
+ if (nameMatch) {
307
+ const name = nameMatch[1];
308
+ if (filenameMatch) {
309
+ const filename = filenameMatch[1];
310
+ const mimeType = headers['content-type'] || 'application/octet-stream';
311
+ const file = new File([content], filename, { type: mimeType });
312
+ formData.append(name, file);
313
+ } else {
314
+ formData.append(name, decoder.decode(content));
315
+ }
316
+ }
317
+
318
+ pos = nextBoundary + boundaryBytes.length;
319
+ }
320
+
321
+ return formData;
322
+ };
323
+
324
+ // Serialize FormData to multipart/form-data format
325
+ globalThis.__serializeFormData = function(formData) {
326
+ const boundary = '----FormDataBoundary' + Math.random().toString(36).slice(2) +
327
+ Math.random().toString(36).slice(2);
328
+ const encoder = new TextEncoder();
329
+ const parts = [];
330
+
331
+ for (const [name, value] of formData.entries()) {
332
+ if (value instanceof File) {
333
+ const header = [
334
+ '--' + boundary,
335
+ 'Content-Disposition: form-data; name="' + name + '"; filename="' + value.name + '"',
336
+ 'Content-Type: ' + (value.type || 'application/octet-stream'),
337
+ '',
338
+ ''
339
+ ].join('\\r\\n');
340
+ parts.push(encoder.encode(header));
341
+ // Use existing __Blob_bytes callback (File extends Blob)
342
+ parts.push(__Blob_bytes(value._getInstanceId()));
343
+ parts.push(encoder.encode('\\r\\n'));
344
+ } else if (value instanceof Blob) {
345
+ const header = [
346
+ '--' + boundary,
347
+ 'Content-Disposition: form-data; name="' + name + '"; filename="blob"',
348
+ 'Content-Type: ' + (value.type || 'application/octet-stream'),
349
+ '',
350
+ ''
351
+ ].join('\\r\\n');
352
+ parts.push(encoder.encode(header));
353
+ parts.push(__Blob_bytes(value._getInstanceId()));
354
+ parts.push(encoder.encode('\\r\\n'));
355
+ } else {
356
+ const header = [
357
+ '--' + boundary,
358
+ 'Content-Disposition: form-data; name="' + name + '"',
359
+ '',
360
+ ''
361
+ ].join('\\r\\n');
362
+ parts.push(encoder.encode(header));
363
+ parts.push(encoder.encode(String(value)));
364
+ parts.push(encoder.encode('\\r\\n'));
365
+ }
366
+ }
367
+
368
+ // Closing boundary
369
+ parts.push(encoder.encode('--' + boundary + '--\\r\\n'));
370
+
371
+ // Concatenate all parts
372
+ const totalLength = parts.reduce((sum, p) => sum + p.length, 0);
373
+ const body = new Uint8Array(totalLength);
374
+ let offset = 0;
375
+ for (const part of parts) {
376
+ body.set(part, offset);
377
+ offset += part.length;
378
+ }
379
+
380
+ return {
381
+ body: body,
382
+ contentType: 'multipart/form-data; boundary=' + boundary
383
+ };
384
+ };
385
+ })();
386
+ `;
387
+ function setupStreamCallbacks(context, streamRegistry) {
388
+ const global = context.global;
389
+ global.setSync("__Stream_create", new import_isolated_vm.default.Callback(() => {
390
+ return streamRegistry.create();
391
+ }));
392
+ global.setSync("__Stream_push", new import_isolated_vm.default.Callback((streamId, chunkArray) => {
393
+ const chunk = new Uint8Array(chunkArray);
394
+ return streamRegistry.push(streamId, chunk);
395
+ }));
396
+ global.setSync("__Stream_close", new import_isolated_vm.default.Callback((streamId) => {
397
+ streamRegistry.close(streamId);
398
+ }));
399
+ global.setSync("__Stream_error", new import_isolated_vm.default.Callback((streamId, message) => {
400
+ streamRegistry.error(streamId, new Error(message));
401
+ }));
402
+ global.setSync("__Stream_isQueueFull", new import_isolated_vm.default.Callback((streamId) => {
403
+ return streamRegistry.isQueueFull(streamId);
404
+ }));
405
+ const pullRef = new import_isolated_vm.default.Reference(async (streamId) => {
406
+ const result = await streamRegistry.pull(streamId);
407
+ if (result.done) {
408
+ return JSON.stringify({ done: true });
409
+ }
410
+ return JSON.stringify({ done: false, value: Array.from(result.value) });
411
+ });
412
+ global.setSync("__Stream_pull_ref", pullRef);
413
+ }
414
+ var hostBackedStreamCode = `
415
+ (function() {
416
+ const _streamIds = new WeakMap();
417
+
418
+ class HostBackedReadableStream {
419
+ constructor(streamId) {
420
+ if (streamId === undefined) {
421
+ streamId = __Stream_create();
422
+ }
423
+ _streamIds.set(this, streamId);
424
+ }
425
+
426
+ _getStreamId() {
427
+ return _streamIds.get(this);
428
+ }
429
+
430
+ getReader() {
431
+ const streamId = this._getStreamId();
432
+ let released = false;
433
+
434
+ return {
435
+ read: async () => {
436
+ if (released) {
437
+ throw new TypeError("Reader has been released");
438
+ }
439
+ const resultJson = __Stream_pull_ref.applySyncPromise(undefined, [streamId]);
440
+ const result = JSON.parse(resultJson);
441
+
442
+ if (result.done) {
443
+ return { done: true, value: undefined };
444
+ }
445
+ return { done: false, value: new Uint8Array(result.value) };
446
+ },
447
+
448
+ releaseLock: () => {
449
+ released = true;
450
+ },
451
+
452
+ get closed() {
453
+ return new Promise(() => {});
454
+ },
455
+
456
+ cancel: async (reason) => {
457
+ __Stream_error(streamId, String(reason || "cancelled"));
458
+ }
459
+ };
460
+ }
461
+
462
+ async cancel(reason) {
463
+ __Stream_error(this._getStreamId(), String(reason || "cancelled"));
464
+ }
465
+
466
+ get locked() {
467
+ return false;
468
+ }
469
+
470
+ // Static method to create from existing stream ID
471
+ static _fromStreamId(streamId) {
472
+ return new HostBackedReadableStream(streamId);
473
+ }
474
+ }
475
+
476
+ globalThis.HostBackedReadableStream = HostBackedReadableStream;
477
+ })();
478
+ `;
479
+ function setupResponse(context, stateMap) {
480
+ const global = context.global;
481
+ global.setSync("__Response_construct", new import_isolated_vm.default.Callback((bodyBytes, status, statusText, headers) => {
482
+ const instanceId = nextInstanceId++;
483
+ const body = bodyBytes ? new Uint8Array(bodyBytes) : null;
484
+ const state = {
485
+ status,
486
+ statusText,
487
+ headers,
488
+ body,
489
+ bodyUsed: false,
490
+ type: "default",
491
+ url: "",
492
+ redirected: false,
493
+ streamId: null
494
+ };
495
+ stateMap.set(instanceId, state);
496
+ return instanceId;
497
+ }));
498
+ global.setSync("__Response_constructStreaming", new import_isolated_vm.default.Callback((streamId, status, statusText, headers) => {
499
+ const instanceId = nextInstanceId++;
500
+ const state = {
501
+ status,
502
+ statusText,
503
+ headers,
504
+ body: null,
505
+ bodyUsed: false,
506
+ type: "default",
507
+ url: "",
508
+ redirected: false,
509
+ streamId
510
+ };
511
+ stateMap.set(instanceId, state);
512
+ return instanceId;
513
+ }));
514
+ global.setSync("__Response_constructFromFetch", new import_isolated_vm.default.Callback((bodyBytes, status, statusText, headers, url, redirected) => {
515
+ const instanceId = nextInstanceId++;
516
+ const body = bodyBytes ? new Uint8Array(bodyBytes) : null;
517
+ const state = {
518
+ status,
519
+ statusText,
520
+ headers,
521
+ body,
522
+ bodyUsed: false,
523
+ type: "default",
524
+ url,
525
+ redirected,
526
+ streamId: null
527
+ };
528
+ stateMap.set(instanceId, state);
529
+ return instanceId;
530
+ }));
531
+ global.setSync("__Response_get_status", new import_isolated_vm.default.Callback((instanceId) => {
532
+ const state = stateMap.get(instanceId);
533
+ return state?.status ?? 200;
534
+ }));
535
+ global.setSync("__Response_get_statusText", new import_isolated_vm.default.Callback((instanceId) => {
536
+ const state = stateMap.get(instanceId);
537
+ return state?.statusText ?? "";
538
+ }));
539
+ global.setSync("__Response_get_headers", new import_isolated_vm.default.Callback((instanceId) => {
540
+ const state = stateMap.get(instanceId);
541
+ return state?.headers ?? [];
542
+ }));
543
+ global.setSync("__Response_get_bodyUsed", new import_isolated_vm.default.Callback((instanceId) => {
544
+ const state = stateMap.get(instanceId);
545
+ return state?.bodyUsed ?? false;
546
+ }));
547
+ global.setSync("__Response_get_url", new import_isolated_vm.default.Callback((instanceId) => {
548
+ const state = stateMap.get(instanceId);
549
+ return state?.url ?? "";
550
+ }));
551
+ global.setSync("__Response_get_redirected", new import_isolated_vm.default.Callback((instanceId) => {
552
+ const state = stateMap.get(instanceId);
553
+ return state?.redirected ?? false;
554
+ }));
555
+ global.setSync("__Response_get_type", new import_isolated_vm.default.Callback((instanceId) => {
556
+ const state = stateMap.get(instanceId);
557
+ return state?.type ?? "default";
558
+ }));
559
+ global.setSync("__Response_setType", new import_isolated_vm.default.Callback((instanceId, type) => {
560
+ const state = stateMap.get(instanceId);
561
+ if (state) {
562
+ state.type = type;
563
+ }
564
+ }));
565
+ global.setSync("__Response_markBodyUsed", new import_isolated_vm.default.Callback((instanceId) => {
566
+ const state = stateMap.get(instanceId);
567
+ if (state) {
568
+ if (state.bodyUsed) {
569
+ throw new Error("[TypeError]Body has already been consumed");
570
+ }
571
+ state.bodyUsed = true;
572
+ }
573
+ }));
574
+ global.setSync("__Response_text", new import_isolated_vm.default.Callback((instanceId) => {
575
+ const state = stateMap.get(instanceId);
576
+ if (!state || !state.body)
577
+ return "";
578
+ return new TextDecoder().decode(state.body);
579
+ }));
580
+ global.setSync("__Response_arrayBuffer", new import_isolated_vm.default.Callback((instanceId) => {
581
+ const state = stateMap.get(instanceId);
582
+ if (!state || !state.body) {
583
+ return new import_isolated_vm.default.ExternalCopy(new ArrayBuffer(0)).copyInto();
584
+ }
585
+ return new import_isolated_vm.default.ExternalCopy(state.body.buffer.slice(state.body.byteOffset, state.body.byteOffset + state.body.byteLength)).copyInto();
586
+ }));
587
+ global.setSync("__Response_clone", new import_isolated_vm.default.Callback((instanceId) => {
588
+ const state = stateMap.get(instanceId);
589
+ if (!state) {
590
+ throw new Error("[TypeError]Cannot clone invalid Response");
591
+ }
592
+ const newId = nextInstanceId++;
593
+ const newState = {
594
+ ...state,
595
+ body: state.body ? new Uint8Array(state.body) : null,
596
+ bodyUsed: false
597
+ };
598
+ stateMap.set(newId, newState);
599
+ return newId;
600
+ }));
601
+ global.setSync("__Response_getStreamId", new import_isolated_vm.default.Callback((instanceId) => {
602
+ const state = stateMap.get(instanceId);
603
+ return state?.streamId ?? null;
604
+ }));
605
+ const responseCode = `
606
+ (function() {
607
+ const _responseInstanceIds = new WeakMap();
608
+
609
+ function __decodeError(err) {
610
+ if (!(err instanceof Error)) return err;
611
+ const match = err.message.match(/^\\[(TypeError|RangeError|SyntaxError|ReferenceError|URIError|EvalError|Error)\\](.*)$/);
612
+ if (match) {
613
+ const ErrorType = globalThis[match[1]] || Error;
614
+ return new ErrorType(match[2]);
615
+ }
616
+ return err;
617
+ }
618
+
619
+ function __prepareBody(body) {
620
+ if (body === null || body === undefined) return null;
621
+ if (typeof body === 'string') {
622
+ const encoder = new TextEncoder();
623
+ return Array.from(encoder.encode(body));
624
+ }
625
+ if (body instanceof ArrayBuffer) {
626
+ return Array.from(new Uint8Array(body));
627
+ }
628
+ if (body instanceof Uint8Array) {
629
+ return Array.from(body);
630
+ }
631
+ if (ArrayBuffer.isView(body)) {
632
+ return Array.from(new Uint8Array(body.buffer, body.byteOffset, body.byteLength));
633
+ }
634
+ if (body instanceof Blob) {
635
+ // Mark as needing async Blob handling - will be read in constructor
636
+ return { __isBlob: true, blob: body };
637
+ }
638
+ // Handle ReadableStream (both native and host-backed)
639
+ if (body instanceof ReadableStream || body instanceof HostBackedReadableStream) {
640
+ return { __isStream: true, stream: body };
641
+ }
642
+ // Try to convert to string
643
+ return Array.from(new TextEncoder().encode(String(body)));
644
+ }
645
+
646
+ class Response {
647
+ #instanceId;
648
+ #headers;
649
+ #streamId = null;
650
+ #blobInitPromise = null; // For async Blob body initialization
651
+
652
+ constructor(body, init = {}) {
653
+ // Handle internal construction from instance ID
654
+ if (typeof body === 'number' && init === null) {
655
+ this.#instanceId = body;
656
+ this.#headers = new Headers(__Response_get_headers(body));
657
+ this.#streamId = __Response_getStreamId(body);
658
+ return;
659
+ }
660
+
661
+ const preparedBody = __prepareBody(body);
662
+
663
+ // Handle Blob body - create streaming response and push blob data
664
+ if (preparedBody && preparedBody.__isBlob) {
665
+ this.#streamId = __Stream_create();
666
+ const status = init.status ?? 200;
667
+ const statusText = init.statusText ?? '';
668
+ const headers = new Headers(init.headers);
669
+ const headersArray = Array.from(headers.entries());
670
+
671
+ this.#instanceId = __Response_constructStreaming(
672
+ this.#streamId,
673
+ status,
674
+ statusText,
675
+ headersArray
676
+ );
677
+ this.#headers = headers;
678
+
679
+ // Start async blob initialization and stream pumping
680
+ const streamId = this.#streamId;
681
+ const blob = preparedBody.blob;
682
+ this.#blobInitPromise = (async () => {
683
+ try {
684
+ const buffer = await blob.arrayBuffer();
685
+ __Stream_push(streamId, Array.from(new Uint8Array(buffer)));
686
+ __Stream_close(streamId);
687
+ } catch (error) {
688
+ __Stream_error(streamId, String(error));
689
+ }
690
+ })();
691
+ return;
692
+ }
693
+
694
+ // Handle streaming body
695
+ if (preparedBody && preparedBody.__isStream) {
696
+ this.#streamId = __Stream_create();
697
+ const status = init.status ?? 200;
698
+ const statusText = init.statusText ?? '';
699
+ const headers = new Headers(init.headers);
700
+ const headersArray = Array.from(headers.entries());
701
+
702
+ this.#instanceId = __Response_constructStreaming(
703
+ this.#streamId,
704
+ status,
705
+ statusText,
706
+ headersArray
707
+ );
708
+ this.#headers = headers;
709
+
710
+ // Start pumping the source stream to host queue (fire-and-forget)
711
+ this._startStreamPump(preparedBody.stream);
712
+ return;
713
+ }
714
+
715
+ // Existing buffered body handling
716
+ const bodyBytes = preparedBody;
717
+ const status = init.status ?? 200;
718
+ const statusText = init.statusText ?? '';
719
+ const headersInit = init.headers;
720
+ const headers = new Headers(headersInit);
721
+ const headersArray = Array.from(headers.entries());
722
+
723
+ this.#instanceId = __Response_construct(bodyBytes, status, statusText, headersArray);
724
+ this.#headers = headers;
725
+ }
726
+
727
+ async _startStreamPump(sourceStream) {
728
+ const streamId = this.#streamId;
729
+ try {
730
+ const reader = sourceStream.getReader();
731
+ while (true) {
732
+ // Check backpressure - wait if queue is full
733
+ while (__Stream_isQueueFull(streamId)) {
734
+ await new Promise(r => setTimeout(r, 1));
735
+ }
736
+
737
+ const { done, value } = await reader.read();
738
+ if (done) {
739
+ __Stream_close(streamId);
740
+ break;
741
+ }
742
+ if (value) {
743
+ __Stream_push(streamId, Array.from(value));
744
+ }
745
+ }
746
+ } catch (error) {
747
+ __Stream_error(streamId, String(error));
748
+ }
749
+ }
750
+
751
+ _getInstanceId() {
752
+ return this.#instanceId;
753
+ }
754
+
755
+ static _fromInstanceId(instanceId) {
756
+ return new Response(instanceId, null);
757
+ }
758
+
759
+ get status() {
760
+ return __Response_get_status(this.#instanceId);
761
+ }
762
+
763
+ get statusText() {
764
+ return __Response_get_statusText(this.#instanceId);
765
+ }
766
+
767
+ get ok() {
768
+ const status = this.status;
769
+ return status >= 200 && status < 300;
770
+ }
771
+
772
+ get headers() {
773
+ return this.#headers;
774
+ }
775
+
776
+ get bodyUsed() {
777
+ return __Response_get_bodyUsed(this.#instanceId);
778
+ }
779
+
780
+ get url() {
781
+ return __Response_get_url(this.#instanceId);
782
+ }
783
+
784
+ get redirected() {
785
+ return __Response_get_redirected(this.#instanceId);
786
+ }
787
+
788
+ get type() {
789
+ return __Response_get_type(this.#instanceId);
790
+ }
791
+
792
+ get body() {
793
+ const streamId = __Response_getStreamId(this.#instanceId);
794
+ if (streamId !== null) {
795
+ return HostBackedReadableStream._fromStreamId(streamId);
796
+ }
797
+
798
+ // Fallback: create host-backed stream from buffered body
799
+ const instanceId = this.#instanceId;
800
+ const newStreamId = __Stream_create();
801
+ const buffer = __Response_arrayBuffer(instanceId);
802
+
803
+ if (buffer.byteLength > 0) {
804
+ __Stream_push(newStreamId, Array.from(new Uint8Array(buffer)));
805
+ }
806
+ __Stream_close(newStreamId);
807
+
808
+ return HostBackedReadableStream._fromStreamId(newStreamId);
809
+ }
810
+
811
+ async text() {
812
+ try {
813
+ __Response_markBodyUsed(this.#instanceId);
814
+ } catch (err) {
815
+ throw __decodeError(err);
816
+ }
817
+ return __Response_text(this.#instanceId);
818
+ }
819
+
820
+ async json() {
821
+ const text = await this.text();
822
+ return JSON.parse(text);
823
+ }
824
+
825
+ async arrayBuffer() {
826
+ try {
827
+ __Response_markBodyUsed(this.#instanceId);
828
+ } catch (err) {
829
+ throw __decodeError(err);
830
+ }
831
+
832
+ // For streaming responses (including Blob bodies), consume the stream
833
+ if (this.#streamId !== null) {
834
+ // Wait for blob init to complete if needed
835
+ if (this.#blobInitPromise) {
836
+ await this.#blobInitPromise;
837
+ this.#blobInitPromise = null;
838
+ }
839
+
840
+ const reader = this.body.getReader();
841
+ const chunks = [];
842
+ while (true) {
843
+ const { done, value } = await reader.read();
844
+ if (done) break;
845
+ if (value) chunks.push(value);
846
+ }
847
+ // Concatenate all chunks
848
+ const totalLength = chunks.reduce((acc, chunk) => acc + chunk.length, 0);
849
+ const result = new Uint8Array(totalLength);
850
+ let offset = 0;
851
+ for (const chunk of chunks) {
852
+ result.set(chunk, offset);
853
+ offset += chunk.length;
854
+ }
855
+ return result.buffer;
856
+ }
857
+
858
+ return __Response_arrayBuffer(this.#instanceId);
859
+ }
860
+
861
+ async blob() {
862
+ const buffer = await this.arrayBuffer();
863
+ const contentType = this.headers.get('content-type') || '';
864
+ return new Blob([buffer], { type: contentType });
865
+ }
866
+
867
+ async formData() {
868
+ const contentType = this.headers.get('content-type') || '';
869
+
870
+ // Parse multipart/form-data
871
+ if (contentType.includes('multipart/form-data')) {
872
+ const buffer = await this.arrayBuffer();
873
+ return __parseMultipartFormData(new Uint8Array(buffer), contentType);
874
+ }
875
+
876
+ // Parse application/x-www-form-urlencoded
877
+ if (contentType.includes('application/x-www-form-urlencoded')) {
878
+ const text = await this.text();
879
+ const formData = new FormData();
880
+ const params = new URLSearchParams(text);
881
+ for (const [key, value] of params) {
882
+ formData.append(key, value);
883
+ }
884
+ return formData;
885
+ }
886
+
887
+ throw new TypeError('Unsupported content type for formData()');
888
+ }
889
+
890
+ clone() {
891
+ if (this.bodyUsed) {
892
+ throw new TypeError('Cannot clone a Response that has already been used');
893
+ }
894
+ const newId = __Response_clone(this.#instanceId);
895
+ const cloned = Response._fromInstanceId(newId);
896
+ return cloned;
897
+ }
898
+
899
+ static json(data, init = {}) {
900
+ const body = JSON.stringify(data);
901
+ const headers = new Headers(init.headers);
902
+ if (!headers.has('content-type')) {
903
+ headers.set('content-type', 'application/json');
904
+ }
905
+ return new Response(body, { ...init, headers });
906
+ }
907
+
908
+ static redirect(url, status = 302) {
909
+ if (![301, 302, 303, 307, 308].includes(status)) {
910
+ throw new RangeError('Invalid redirect status code');
911
+ }
912
+ const headers = new Headers({ Location: String(url) });
913
+ return new Response(null, { status, headers });
914
+ }
915
+
916
+ static error() {
917
+ const response = new Response(null, { status: 0, statusText: '' });
918
+ __Response_setType(response._getInstanceId(), 'error');
919
+ return response;
920
+ }
921
+ }
922
+
923
+ globalThis.Response = Response;
924
+ })();
925
+ `;
926
+ context.evalSync(responseCode);
927
+ }
928
+ function setupRequest(context, stateMap) {
929
+ const global = context.global;
930
+ global.setSync("__Request_construct", new import_isolated_vm.default.Callback((url, method, headers, bodyBytes, mode, credentials, cache, redirect, referrer, integrity) => {
931
+ const instanceId = nextInstanceId++;
932
+ const body = bodyBytes ? new Uint8Array(bodyBytes) : null;
933
+ const state = {
934
+ url,
935
+ method,
936
+ headers,
937
+ body,
938
+ bodyUsed: false,
939
+ streamId: null,
940
+ mode,
941
+ credentials,
942
+ cache,
943
+ redirect,
944
+ referrer,
945
+ integrity
946
+ };
947
+ stateMap.set(instanceId, state);
948
+ return instanceId;
949
+ }));
950
+ global.setSync("__Request_get_method", new import_isolated_vm.default.Callback((instanceId) => {
951
+ const state = stateMap.get(instanceId);
952
+ return state?.method ?? "GET";
953
+ }));
954
+ global.setSync("__Request_get_url", new import_isolated_vm.default.Callback((instanceId) => {
955
+ const state = stateMap.get(instanceId);
956
+ return state?.url ?? "";
957
+ }));
958
+ global.setSync("__Request_get_headers", new import_isolated_vm.default.Callback((instanceId) => {
959
+ const state = stateMap.get(instanceId);
960
+ return state?.headers ?? [];
961
+ }));
962
+ global.setSync("__Request_get_bodyUsed", new import_isolated_vm.default.Callback((instanceId) => {
963
+ const state = stateMap.get(instanceId);
964
+ return state?.bodyUsed ?? false;
965
+ }));
966
+ global.setSync("__Request_get_mode", new import_isolated_vm.default.Callback((instanceId) => {
967
+ const state = stateMap.get(instanceId);
968
+ return state?.mode ?? "cors";
969
+ }));
970
+ global.setSync("__Request_get_credentials", new import_isolated_vm.default.Callback((instanceId) => {
971
+ const state = stateMap.get(instanceId);
972
+ return state?.credentials ?? "same-origin";
973
+ }));
974
+ global.setSync("__Request_get_cache", new import_isolated_vm.default.Callback((instanceId) => {
975
+ const state = stateMap.get(instanceId);
976
+ return state?.cache ?? "default";
977
+ }));
978
+ global.setSync("__Request_get_redirect", new import_isolated_vm.default.Callback((instanceId) => {
979
+ const state = stateMap.get(instanceId);
980
+ return state?.redirect ?? "follow";
981
+ }));
982
+ global.setSync("__Request_get_referrer", new import_isolated_vm.default.Callback((instanceId) => {
983
+ const state = stateMap.get(instanceId);
984
+ return state?.referrer ?? "about:client";
985
+ }));
986
+ global.setSync("__Request_get_integrity", new import_isolated_vm.default.Callback((instanceId) => {
987
+ const state = stateMap.get(instanceId);
988
+ return state?.integrity ?? "";
989
+ }));
990
+ global.setSync("__Request_markBodyUsed", new import_isolated_vm.default.Callback((instanceId) => {
991
+ const state = stateMap.get(instanceId);
992
+ if (state) {
993
+ if (state.bodyUsed) {
994
+ throw new Error("[TypeError]Body has already been consumed");
995
+ }
996
+ state.bodyUsed = true;
997
+ }
998
+ }));
999
+ global.setSync("__Request_text", new import_isolated_vm.default.Callback((instanceId) => {
1000
+ const state = stateMap.get(instanceId);
1001
+ if (!state || !state.body)
1002
+ return "";
1003
+ return new TextDecoder().decode(state.body);
1004
+ }));
1005
+ global.setSync("__Request_arrayBuffer", new import_isolated_vm.default.Callback((instanceId) => {
1006
+ const state = stateMap.get(instanceId);
1007
+ if (!state || !state.body) {
1008
+ return new import_isolated_vm.default.ExternalCopy(new ArrayBuffer(0)).copyInto();
1009
+ }
1010
+ return new import_isolated_vm.default.ExternalCopy(state.body.buffer.slice(state.body.byteOffset, state.body.byteOffset + state.body.byteLength)).copyInto();
1011
+ }));
1012
+ global.setSync("__Request_getBodyBytes", new import_isolated_vm.default.Callback((instanceId) => {
1013
+ const state = stateMap.get(instanceId);
1014
+ if (!state || !state.body)
1015
+ return null;
1016
+ return Array.from(state.body);
1017
+ }));
1018
+ global.setSync("__Request_clone", new import_isolated_vm.default.Callback((instanceId) => {
1019
+ const state = stateMap.get(instanceId);
1020
+ if (!state) {
1021
+ throw new Error("[TypeError]Cannot clone invalid Request");
1022
+ }
1023
+ const newId = nextInstanceId++;
1024
+ const newState = {
1025
+ ...state,
1026
+ body: state.body ? new Uint8Array(state.body) : null,
1027
+ bodyUsed: false
1028
+ };
1029
+ stateMap.set(newId, newState);
1030
+ return newId;
1031
+ }));
1032
+ global.setSync("__Request_getStreamId", new import_isolated_vm.default.Callback((instanceId) => {
1033
+ const state = stateMap.get(instanceId);
1034
+ return state?.streamId ?? null;
1035
+ }));
1036
+ const requestCode = `
1037
+ (function() {
1038
+ function __decodeError(err) {
1039
+ if (!(err instanceof Error)) return err;
1040
+ const match = err.message.match(/^\\[(TypeError|RangeError|SyntaxError|ReferenceError|URIError|EvalError|Error)\\](.*)$/);
1041
+ if (match) {
1042
+ const ErrorType = globalThis[match[1]] || Error;
1043
+ return new ErrorType(match[2]);
1044
+ }
1045
+ return err;
1046
+ }
1047
+
1048
+ function __prepareBody(body) {
1049
+ if (body === null || body === undefined) return null;
1050
+ if (typeof body === 'string') {
1051
+ const encoder = new TextEncoder();
1052
+ return Array.from(encoder.encode(body));
1053
+ }
1054
+ if (body instanceof ArrayBuffer) {
1055
+ return Array.from(new Uint8Array(body));
1056
+ }
1057
+ if (body instanceof Uint8Array) {
1058
+ return Array.from(body);
1059
+ }
1060
+ if (ArrayBuffer.isView(body)) {
1061
+ return Array.from(new Uint8Array(body.buffer, body.byteOffset, body.byteLength));
1062
+ }
1063
+ if (body instanceof URLSearchParams) {
1064
+ return Array.from(new TextEncoder().encode(body.toString()));
1065
+ }
1066
+ if (body instanceof FormData) {
1067
+ // Check if FormData has any File/Blob entries
1068
+ let hasFiles = false;
1069
+ for (const [, value] of body.entries()) {
1070
+ if (value instanceof File || value instanceof Blob) {
1071
+ hasFiles = true;
1072
+ break;
1073
+ }
1074
+ }
1075
+
1076
+ if (hasFiles) {
1077
+ // Serialize as multipart/form-data
1078
+ const { body: bytes, contentType } = __serializeFormData(body);
1079
+ globalThis.__pendingFormDataContentType = contentType;
1080
+ return Array.from(bytes);
1081
+ }
1082
+
1083
+ // URL-encoded for string-only FormData
1084
+ const parts = [];
1085
+ body.forEach((value, key) => {
1086
+ if (typeof value === 'string') {
1087
+ parts.push(encodeURIComponent(key) + '=' + encodeURIComponent(value));
1088
+ }
1089
+ });
1090
+ return Array.from(new TextEncoder().encode(parts.join('&')));
1091
+ }
1092
+ // Try to convert to string
1093
+ return Array.from(new TextEncoder().encode(String(body)));
1094
+ }
1095
+
1096
+ // Helper to consume a HostBackedReadableStream and concatenate all chunks
1097
+ async function __consumeStream(stream) {
1098
+ const reader = stream.getReader();
1099
+ const chunks = [];
1100
+ let totalLength = 0;
1101
+
1102
+ while (true) {
1103
+ const { done, value } = await reader.read();
1104
+ if (done) break;
1105
+ chunks.push(value);
1106
+ totalLength += value.length;
1107
+ }
1108
+
1109
+ // Concatenate all chunks
1110
+ const result = new Uint8Array(totalLength);
1111
+ let offset = 0;
1112
+ for (const chunk of chunks) {
1113
+ result.set(chunk, offset);
1114
+ offset += chunk.length;
1115
+ }
1116
+ return result;
1117
+ }
1118
+
1119
+ class Request {
1120
+ #instanceId;
1121
+ #headers;
1122
+ #signal;
1123
+ #streamId;
1124
+ #cachedBody = null;
1125
+
1126
+ constructor(input, init = {}) {
1127
+ // Handle internal construction from instance ID
1128
+ if (typeof input === 'number' && init === null) {
1129
+ this.#instanceId = input;
1130
+ this.#headers = new Headers(__Request_get_headers(input));
1131
+ this.#signal = null;
1132
+ this.#streamId = __Request_getStreamId(input);
1133
+ return;
1134
+ }
1135
+
1136
+ let url;
1137
+ let method = 'GET';
1138
+ let headers;
1139
+ let body = null;
1140
+ let signal = null;
1141
+ let mode = 'cors';
1142
+ let credentials = 'same-origin';
1143
+ let cache = 'default';
1144
+ let redirect = 'follow';
1145
+ let referrer = 'about:client';
1146
+ let integrity = '';
1147
+
1148
+ if (input instanceof Request) {
1149
+ url = input.url;
1150
+ method = input.method;
1151
+ headers = new Headers(input.headers);
1152
+ signal = input.signal;
1153
+ mode = input.mode;
1154
+ credentials = input.credentials;
1155
+ cache = input.cache;
1156
+ redirect = input.redirect;
1157
+ referrer = input.referrer;
1158
+ integrity = input.integrity;
1159
+ // Note: We don't copy the body from the input Request
1160
+ } else {
1161
+ url = String(input);
1162
+ headers = new Headers();
1163
+ }
1164
+
1165
+ // Apply init overrides
1166
+ if (init.method !== undefined) method = String(init.method).toUpperCase();
1167
+ if (init.headers !== undefined) headers = new Headers(init.headers);
1168
+ if (init.body !== undefined) body = init.body;
1169
+ if (init.signal !== undefined) signal = init.signal;
1170
+ if (init.mode !== undefined) mode = init.mode;
1171
+ if (init.credentials !== undefined) credentials = init.credentials;
1172
+ if (init.cache !== undefined) cache = init.cache;
1173
+ if (init.redirect !== undefined) redirect = init.redirect;
1174
+ if (init.referrer !== undefined) referrer = init.referrer;
1175
+ if (init.integrity !== undefined) integrity = init.integrity;
1176
+
1177
+ // Validate: body with GET/HEAD
1178
+ if (body !== null && (method === 'GET' || method === 'HEAD')) {
1179
+ throw new TypeError('Request with GET/HEAD method cannot have body');
1180
+ }
1181
+
1182
+ const bodyBytes = __prepareBody(body);
1183
+
1184
+ // Handle Content-Type for FormData
1185
+ if (globalThis.__pendingFormDataContentType) {
1186
+ headers.set('content-type', globalThis.__pendingFormDataContentType);
1187
+ delete globalThis.__pendingFormDataContentType;
1188
+ } else if (body instanceof FormData && !headers.has('content-type')) {
1189
+ headers.set('content-type', 'application/x-www-form-urlencoded');
1190
+ }
1191
+
1192
+ const headersArray = Array.from(headers.entries());
1193
+
1194
+ this.#instanceId = __Request_construct(
1195
+ url, method, headersArray, bodyBytes,
1196
+ mode, credentials, cache, redirect, referrer, integrity
1197
+ );
1198
+ this.#headers = headers;
1199
+ this.#signal = signal;
1200
+ this.#streamId = null;
1201
+ }
1202
+
1203
+ _getInstanceId() {
1204
+ return this.#instanceId;
1205
+ }
1206
+
1207
+ static _fromInstanceId(instanceId) {
1208
+ return new Request(instanceId, null);
1209
+ }
1210
+
1211
+ get method() {
1212
+ return __Request_get_method(this.#instanceId);
1213
+ }
1214
+
1215
+ get url() {
1216
+ return __Request_get_url(this.#instanceId);
1217
+ }
1218
+
1219
+ get headers() {
1220
+ return this.#headers;
1221
+ }
1222
+
1223
+ get bodyUsed() {
1224
+ return __Request_get_bodyUsed(this.#instanceId);
1225
+ }
1226
+
1227
+ get signal() {
1228
+ return this.#signal;
1229
+ }
1230
+
1231
+ get mode() {
1232
+ return __Request_get_mode(this.#instanceId);
1233
+ }
1234
+
1235
+ get credentials() {
1236
+ return __Request_get_credentials(this.#instanceId);
1237
+ }
1238
+
1239
+ get cache() {
1240
+ return __Request_get_cache(this.#instanceId);
1241
+ }
1242
+
1243
+ get redirect() {
1244
+ return __Request_get_redirect(this.#instanceId);
1245
+ }
1246
+
1247
+ get referrer() {
1248
+ return __Request_get_referrer(this.#instanceId);
1249
+ }
1250
+
1251
+ get integrity() {
1252
+ return __Request_get_integrity(this.#instanceId);
1253
+ }
1254
+
1255
+ get body() {
1256
+ // Return cached body if available
1257
+ if (this.#cachedBody !== null) {
1258
+ return this.#cachedBody;
1259
+ }
1260
+
1261
+ // If we have a stream ID, create and cache the stream
1262
+ if (this.#streamId !== null) {
1263
+ this.#cachedBody = HostBackedReadableStream._fromStreamId(this.#streamId);
1264
+ return this.#cachedBody;
1265
+ }
1266
+
1267
+ // Create stream from buffered body
1268
+ const newStreamId = __Stream_create();
1269
+ const buffer = __Request_arrayBuffer(this.#instanceId);
1270
+ if (buffer.byteLength > 0) {
1271
+ __Stream_push(newStreamId, Array.from(new Uint8Array(buffer)));
1272
+ }
1273
+ __Stream_close(newStreamId);
1274
+
1275
+ this.#cachedBody = HostBackedReadableStream._fromStreamId(newStreamId);
1276
+ return this.#cachedBody;
1277
+ }
1278
+
1279
+ async text() {
1280
+ try {
1281
+ __Request_markBodyUsed(this.#instanceId);
1282
+ } catch (err) {
1283
+ throw __decodeError(err);
1284
+ }
1285
+
1286
+ // If streaming, consume the stream
1287
+ if (this.#streamId !== null) {
1288
+ const bytes = await __consumeStream(this.body);
1289
+ return new TextDecoder().decode(bytes);
1290
+ }
1291
+
1292
+ // Fallback to host callback for buffered body
1293
+ return __Request_text(this.#instanceId);
1294
+ }
1295
+
1296
+ async json() {
1297
+ const text = await this.text();
1298
+ return JSON.parse(text);
1299
+ }
1300
+
1301
+ async arrayBuffer() {
1302
+ try {
1303
+ __Request_markBodyUsed(this.#instanceId);
1304
+ } catch (err) {
1305
+ throw __decodeError(err);
1306
+ }
1307
+
1308
+ // If streaming, consume the stream
1309
+ if (this.#streamId !== null) {
1310
+ const bytes = await __consumeStream(this.body);
1311
+ return bytes.buffer;
1312
+ }
1313
+
1314
+ return __Request_arrayBuffer(this.#instanceId);
1315
+ }
1316
+
1317
+ async blob() {
1318
+ const buffer = await this.arrayBuffer();
1319
+ const contentType = this.headers.get('content-type') || '';
1320
+ return new Blob([buffer], { type: contentType });
1321
+ }
1322
+
1323
+ async formData() {
1324
+ const contentType = this.headers.get('content-type') || '';
1325
+
1326
+ // Parse multipart/form-data
1327
+ if (contentType.includes('multipart/form-data')) {
1328
+ const buffer = await this.arrayBuffer();
1329
+ return __parseMultipartFormData(new Uint8Array(buffer), contentType);
1330
+ }
1331
+
1332
+ // Parse application/x-www-form-urlencoded
1333
+ if (contentType.includes('application/x-www-form-urlencoded')) {
1334
+ const text = await this.text();
1335
+ const formData = new FormData();
1336
+ const params = new URLSearchParams(text);
1337
+ for (const [key, value] of params) {
1338
+ formData.append(key, value);
1339
+ }
1340
+ return formData;
1341
+ }
1342
+
1343
+ throw new TypeError('Unsupported content type for formData()');
1344
+ }
1345
+
1346
+ clone() {
1347
+ if (this.bodyUsed) {
1348
+ throw new TypeError('Cannot clone a Request that has already been used');
1349
+ }
1350
+ const newId = __Request_clone(this.#instanceId);
1351
+ const cloned = Request._fromInstanceId(newId);
1352
+ cloned.#signal = this.#signal;
1353
+ return cloned;
1354
+ }
1355
+
1356
+ _getBodyBytes() {
1357
+ return __Request_getBodyBytes(this.#instanceId);
1358
+ }
1359
+ }
1360
+
1361
+ globalThis.Request = Request;
1362
+ })();
1363
+ `;
1364
+ context.evalSync(requestCode);
1365
+ }
1366
+ function setupFetchFunction(context, stateMap, options) {
1367
+ const global = context.global;
1368
+ const fetchRef = new import_isolated_vm.default.Reference(async (url, method, headersJson, bodyJson, signalAborted) => {
1369
+ if (signalAborted) {
1370
+ throw new Error("[AbortError]The operation was aborted.");
1371
+ }
1372
+ const headers = JSON.parse(headersJson);
1373
+ const bodyBytes = bodyJson ? JSON.parse(bodyJson) : null;
1374
+ const body = bodyBytes ? new Uint8Array(bodyBytes) : null;
1375
+ const nativeRequest = new Request(url, {
1376
+ method,
1377
+ headers,
1378
+ body
1379
+ });
1380
+ const onFetch = options?.onFetch ?? fetch;
1381
+ const nativeResponse = await onFetch(nativeRequest);
1382
+ const responseBody = await nativeResponse.arrayBuffer();
1383
+ const responseBodyArray = Array.from(new Uint8Array(responseBody));
1384
+ const instanceId = nextInstanceId++;
1385
+ const state = {
1386
+ status: nativeResponse.status,
1387
+ statusText: nativeResponse.statusText,
1388
+ headers: Array.from(nativeResponse.headers.entries()),
1389
+ body: new Uint8Array(responseBodyArray),
1390
+ bodyUsed: false,
1391
+ type: "default",
1392
+ url: nativeResponse.url,
1393
+ redirected: nativeResponse.redirected,
1394
+ streamId: null
1395
+ };
1396
+ stateMap.set(instanceId, state);
1397
+ return instanceId;
1398
+ });
1399
+ global.setSync("__fetch_ref", fetchRef);
1400
+ const fetchCode = `
1401
+ (function() {
1402
+ function __decodeError(err) {
1403
+ if (!(err instanceof Error)) return err;
1404
+ const match = err.message.match(/^\\[(TypeError|RangeError|AbortError|Error)\\](.*)$/);
1405
+ if (match) {
1406
+ if (match[1] === 'AbortError') {
1407
+ return new DOMException(match[2], 'AbortError');
1408
+ }
1409
+ const ErrorType = globalThis[match[1]] || Error;
1410
+ return new ErrorType(match[2]);
1411
+ }
1412
+ return err;
1413
+ }
1414
+
1415
+ globalThis.fetch = function(input, init = {}) {
1416
+ // Create Request from input
1417
+ const request = input instanceof Request ? input : new Request(input, init);
1418
+
1419
+ // Get signal info
1420
+ const signal = init.signal ?? request.signal;
1421
+ const signalAborted = signal?.aborted ?? false;
1422
+
1423
+ // Serialize headers and body to JSON for transfer
1424
+ const headersJson = JSON.stringify(Array.from(request.headers.entries()));
1425
+ const bodyBytes = request._getBodyBytes();
1426
+ const bodyJson = bodyBytes ? JSON.stringify(bodyBytes) : null;
1427
+
1428
+ // Call host - returns just the response instance ID
1429
+ try {
1430
+ const instanceId = __fetch_ref.applySyncPromise(undefined, [
1431
+ request.url,
1432
+ request.method,
1433
+ headersJson,
1434
+ bodyJson,
1435
+ signalAborted
1436
+ ]);
1437
+
1438
+ // Construct Response from the instance ID
1439
+ return Response._fromInstanceId(instanceId);
1440
+ } catch (err) {
1441
+ throw __decodeError(err);
1442
+ }
1443
+ };
1444
+ })();
1445
+ `;
1446
+ context.evalSync(fetchCode);
1447
+ }
1448
+ function setupServer(context, serveState) {
1449
+ const global = context.global;
1450
+ context.evalSync(`
1451
+ globalThis.__upgradeRegistry__ = new Map();
1452
+ globalThis.__upgradeIdCounter__ = 0;
1453
+ `);
1454
+ global.setSync("__setPendingUpgrade__", new import_isolated_vm.default.Callback((connectionId) => {
1455
+ serveState.pendingUpgrade = { requested: true, connectionId };
1456
+ }));
1457
+ context.evalSync(`
1458
+ (function() {
1459
+ class Server {
1460
+ upgrade(request, options) {
1461
+ const data = options?.data;
1462
+ const connectionId = String(++globalThis.__upgradeIdCounter__);
1463
+ globalThis.__upgradeRegistry__.set(connectionId, data);
1464
+ __setPendingUpgrade__(connectionId);
1465
+ return true;
1466
+ }
1467
+ }
1468
+ globalThis.__Server__ = Server;
1469
+ })();
1470
+ `);
1471
+ }
1472
+ function setupServerWebSocket(context, wsCommandCallbacks) {
1473
+ const global = context.global;
1474
+ global.setSync("__ServerWebSocket_send", new import_isolated_vm.default.Callback((connectionId, data) => {
1475
+ const cmd = { type: "message", connectionId, data };
1476
+ for (const cb of wsCommandCallbacks)
1477
+ cb(cmd);
1478
+ }));
1479
+ global.setSync("__ServerWebSocket_close", new import_isolated_vm.default.Callback((connectionId, code, reason) => {
1480
+ const cmd = { type: "close", connectionId, code, reason };
1481
+ for (const cb of wsCommandCallbacks)
1482
+ cb(cmd);
1483
+ }));
1484
+ context.evalSync(`
1485
+ (function() {
1486
+ const _wsInstanceData = new WeakMap();
1487
+
1488
+ class ServerWebSocket {
1489
+ constructor(connectionId) {
1490
+ _wsInstanceData.set(this, { connectionId, readyState: 1 });
1491
+ }
1492
+
1493
+ get data() {
1494
+ const state = _wsInstanceData.get(this);
1495
+ return globalThis.__upgradeRegistry__.get(state.connectionId);
1496
+ }
1497
+
1498
+ get readyState() {
1499
+ return _wsInstanceData.get(this).readyState;
1500
+ }
1501
+
1502
+ send(message) {
1503
+ const state = _wsInstanceData.get(this);
1504
+ if (state.readyState !== 1) throw new Error("WebSocket is not open");
1505
+ // Convert ArrayBuffer/Uint8Array to string for transfer
1506
+ let data = message;
1507
+ if (message instanceof ArrayBuffer) {
1508
+ data = new TextDecoder().decode(message);
1509
+ } else if (message instanceof Uint8Array) {
1510
+ data = new TextDecoder().decode(message);
1511
+ }
1512
+ __ServerWebSocket_send(state.connectionId, data);
1513
+ }
1514
+
1515
+ close(code, reason) {
1516
+ const state = _wsInstanceData.get(this);
1517
+ if (state.readyState === 3) return;
1518
+ state.readyState = 2; // CLOSING
1519
+ __ServerWebSocket_close(state.connectionId, code, reason);
1520
+ }
1521
+
1522
+ _setReadyState(readyState) {
1523
+ _wsInstanceData.get(this).readyState = readyState;
1524
+ }
1525
+ }
1526
+
1527
+ globalThis.__ServerWebSocket__ = ServerWebSocket;
1528
+ })();
1529
+ `);
1530
+ }
1531
+ function setupServe(context) {
1532
+ context.evalSync(`
1533
+ (function() {
1534
+ globalThis.__serveOptions__ = null;
1535
+
1536
+ function serve(options) {
1537
+ globalThis.__serveOptions__ = options;
1538
+ }
1539
+
1540
+ globalThis.serve = serve;
1541
+ })();
1542
+ `);
1543
+ }
1544
+ async function setupFetch(context, options) {
1545
+ await import_isolate_core.setupCore(context);
1546
+ const stateMap = getInstanceStateMapForContext(context);
1547
+ const streamRegistry = import_stream_state.getStreamRegistryForContext(context);
1548
+ context.evalSync(headersCode);
1549
+ context.evalSync(formDataCode);
1550
+ context.evalSync(multipartCode);
1551
+ setupStreamCallbacks(context, streamRegistry);
1552
+ context.evalSync(hostBackedStreamCode);
1553
+ setupResponse(context, stateMap);
1554
+ setupRequest(context, stateMap);
1555
+ setupFetchFunction(context, stateMap, options);
1556
+ const serveState = {
1557
+ pendingUpgrade: null,
1558
+ activeConnections: new Map
1559
+ };
1560
+ const wsCommandCallbacks = new Set;
1561
+ setupServer(context, serveState);
1562
+ setupServerWebSocket(context, wsCommandCallbacks);
1563
+ setupServe(context);
1564
+ return {
1565
+ dispose() {
1566
+ stateMap.clear();
1567
+ context.evalSync(`globalThis.__upgradeRegistry__.clear()`);
1568
+ serveState.activeConnections.clear();
1569
+ serveState.pendingUpgrade = null;
1570
+ },
1571
+ async dispatchRequest(request, dispatchOptions) {
1572
+ const tick = dispatchOptions?.tick;
1573
+ if (serveState.pendingUpgrade) {
1574
+ const oldConnectionId = serveState.pendingUpgrade.connectionId;
1575
+ context.evalSync(`globalThis.__upgradeRegistry__.delete("${oldConnectionId}")`);
1576
+ serveState.pendingUpgrade = null;
1577
+ }
1578
+ const hasHandler = context.evalSync(`!!globalThis.__serveOptions__?.fetch`);
1579
+ if (!hasHandler) {
1580
+ throw new Error("No serve() handler registered");
1581
+ }
1582
+ let requestStreamId = null;
1583
+ let streamCleanup = null;
1584
+ if (request.body) {
1585
+ requestStreamId = streamRegistry.create();
1586
+ streamCleanup = import_stream_state.startNativeStreamReader(request.body, requestStreamId, streamRegistry);
1587
+ }
1588
+ try {
1589
+ const headersArray = Array.from(request.headers.entries());
1590
+ const requestInstanceId = nextInstanceId++;
1591
+ const requestState = {
1592
+ url: request.url,
1593
+ method: request.method,
1594
+ headers: headersArray,
1595
+ body: null,
1596
+ bodyUsed: false,
1597
+ streamId: requestStreamId,
1598
+ mode: request.mode,
1599
+ credentials: request.credentials,
1600
+ cache: request.cache,
1601
+ redirect: request.redirect,
1602
+ referrer: request.referrer,
1603
+ integrity: request.integrity
1604
+ };
1605
+ stateMap.set(requestInstanceId, requestState);
1606
+ const responseInstanceId = await context.eval(`
1607
+ (async function() {
1608
+ const request = Request._fromInstanceId(${requestInstanceId});
1609
+ const server = new __Server__();
1610
+ const response = await Promise.resolve(__serveOptions__.fetch(request, server));
1611
+ return response._getInstanceId();
1612
+ })()
1613
+ `, { promise: true });
1614
+ const responseState = stateMap.get(responseInstanceId);
1615
+ if (!responseState) {
1616
+ throw new Error("Response state not found");
1617
+ }
1618
+ if (responseState.streamId !== null) {
1619
+ const responseStreamId = responseState.streamId;
1620
+ let streamDone = false;
1621
+ const pumpedStream = new ReadableStream({
1622
+ async pull(controller) {
1623
+ if (streamDone)
1624
+ return;
1625
+ while (!streamDone) {
1626
+ if (tick) {
1627
+ await tick();
1628
+ }
1629
+ const state = streamRegistry.get(responseStreamId);
1630
+ if (!state) {
1631
+ controller.close();
1632
+ streamDone = true;
1633
+ return;
1634
+ }
1635
+ if (state.queue.length > 0 || state.closed || state.errored) {
1636
+ break;
1637
+ }
1638
+ await new Promise((r) => setTimeout(r, 1));
1639
+ }
1640
+ try {
1641
+ const result = await streamRegistry.pull(responseStreamId);
1642
+ if (result.done) {
1643
+ controller.close();
1644
+ streamDone = true;
1645
+ streamRegistry.delete(responseStreamId);
1646
+ return;
1647
+ }
1648
+ controller.enqueue(result.value);
1649
+ } catch (error) {
1650
+ controller.error(error);
1651
+ streamDone = true;
1652
+ streamRegistry.delete(responseStreamId);
1653
+ }
1654
+ },
1655
+ cancel() {
1656
+ streamDone = true;
1657
+ streamRegistry.error(responseStreamId, new Error("Stream cancelled"));
1658
+ streamRegistry.delete(responseStreamId);
1659
+ }
1660
+ });
1661
+ const responseHeaders2 = new Headers(responseState.headers);
1662
+ const status2 = responseState.status === 101 ? 200 : responseState.status;
1663
+ const response2 = new Response(pumpedStream, {
1664
+ status: status2,
1665
+ statusText: responseState.statusText,
1666
+ headers: responseHeaders2
1667
+ });
1668
+ response2._originalStatus = responseState.status;
1669
+ return response2;
1670
+ }
1671
+ const responseHeaders = new Headers(responseState.headers);
1672
+ const responseBody = responseState.body;
1673
+ const status = responseState.status === 101 ? 200 : responseState.status;
1674
+ const response = new Response(responseBody, {
1675
+ status,
1676
+ statusText: responseState.statusText,
1677
+ headers: responseHeaders
1678
+ });
1679
+ response._originalStatus = responseState.status;
1680
+ return response;
1681
+ } finally {
1682
+ if (streamCleanup) {
1683
+ await streamCleanup();
1684
+ }
1685
+ if (requestStreamId !== null) {
1686
+ streamRegistry.delete(requestStreamId);
1687
+ }
1688
+ }
1689
+ },
1690
+ getUpgradeRequest() {
1691
+ const result = serveState.pendingUpgrade;
1692
+ return result;
1693
+ },
1694
+ dispatchWebSocketOpen(connectionId) {
1695
+ const hasOpenHandler = context.evalSync(`!!globalThis.__serveOptions__?.websocket?.open`);
1696
+ if (!hasOpenHandler) {
1697
+ context.evalSync(`globalThis.__upgradeRegistry__.delete("${connectionId}")`);
1698
+ return;
1699
+ }
1700
+ serveState.activeConnections.set(connectionId, { connectionId });
1701
+ context.evalSync(`
1702
+ (function() {
1703
+ const ws = new __ServerWebSocket__("${connectionId}");
1704
+ globalThis.__activeWs_${connectionId}__ = ws;
1705
+ __serveOptions__.websocket.open(ws);
1706
+ })()
1707
+ `);
1708
+ if (serveState.pendingUpgrade?.connectionId === connectionId) {
1709
+ serveState.pendingUpgrade = null;
1710
+ }
1711
+ },
1712
+ dispatchWebSocketMessage(connectionId, message) {
1713
+ if (!serveState.activeConnections.has(connectionId)) {
1714
+ return;
1715
+ }
1716
+ const hasMessageHandler = context.evalSync(`!!globalThis.__serveOptions__?.websocket?.message`);
1717
+ if (!hasMessageHandler) {
1718
+ return;
1719
+ }
1720
+ if (typeof message === "string") {
1721
+ context.evalSync(`
1722
+ (function() {
1723
+ const ws = globalThis.__activeWs_${connectionId}__;
1724
+ if (ws) __serveOptions__.websocket.message(ws, "${message.replace(/\\/g, "\\\\").replace(/"/g, "\\\"").replace(/\n/g, "\\n")}");
1725
+ })()
1726
+ `);
1727
+ } else {
1728
+ const bytes = Array.from(new Uint8Array(message));
1729
+ context.evalSync(`
1730
+ (function() {
1731
+ const ws = globalThis.__activeWs_${connectionId}__;
1732
+ if (ws) {
1733
+ const bytes = new Uint8Array([${bytes.join(",")}]);
1734
+ __serveOptions__.websocket.message(ws, bytes.buffer);
1735
+ }
1736
+ })()
1737
+ `);
1738
+ }
1739
+ },
1740
+ dispatchWebSocketClose(connectionId, code, reason) {
1741
+ if (!serveState.activeConnections.has(connectionId)) {
1742
+ return;
1743
+ }
1744
+ context.evalSync(`
1745
+ (function() {
1746
+ const ws = globalThis.__activeWs_${connectionId}__;
1747
+ if (ws) ws._setReadyState(3);
1748
+ })()
1749
+ `);
1750
+ const hasCloseHandler = context.evalSync(`!!globalThis.__serveOptions__?.websocket?.close`);
1751
+ if (hasCloseHandler) {
1752
+ const safeReason = reason.replace(/\\/g, "\\\\").replace(/"/g, "\\\"").replace(/\n/g, "\\n");
1753
+ context.evalSync(`
1754
+ (function() {
1755
+ const ws = globalThis.__activeWs_${connectionId}__;
1756
+ if (ws) __serveOptions__.websocket.close(ws, ${code}, "${safeReason}");
1757
+ })()
1758
+ `);
1759
+ }
1760
+ context.evalSync(`
1761
+ delete globalThis.__activeWs_${connectionId}__;
1762
+ globalThis.__upgradeRegistry__.delete("${connectionId}");
1763
+ `);
1764
+ serveState.activeConnections.delete(connectionId);
1765
+ },
1766
+ dispatchWebSocketError(connectionId, error) {
1767
+ if (!serveState.activeConnections.has(connectionId)) {
1768
+ return;
1769
+ }
1770
+ const hasErrorHandler = context.evalSync(`!!globalThis.__serveOptions__?.websocket?.error`);
1771
+ if (!hasErrorHandler) {
1772
+ return;
1773
+ }
1774
+ const safeName = error.name.replace(/\\/g, "\\\\").replace(/"/g, "\\\"");
1775
+ const safeMessage = error.message.replace(/\\/g, "\\\\").replace(/"/g, "\\\"").replace(/\n/g, "\\n");
1776
+ context.evalSync(`
1777
+ (function() {
1778
+ const ws = globalThis.__activeWs_${connectionId}__;
1779
+ if (ws) {
1780
+ const error = { name: "${safeName}", message: "${safeMessage}" };
1781
+ __serveOptions__.websocket.error(ws, error);
1782
+ }
1783
+ })()
1784
+ `);
1785
+ },
1786
+ onWebSocketCommand(callback) {
1787
+ wsCommandCallbacks.add(callback);
1788
+ return () => wsCommandCallbacks.delete(callback);
1789
+ },
1790
+ hasServeHandler() {
1791
+ return context.evalSync(`!!globalThis.__serveOptions__?.fetch`);
1792
+ },
1793
+ hasActiveConnections() {
1794
+ return serveState.activeConnections.size > 0;
1795
+ }
1796
+ };
1797
+ }
1798
+ })
1799
+
1800
+ //# debugId=D6B21F115A1DCB5264756E2164756E21