@ricsam/isolate-fetch 0.1.8 → 0.1.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/index.cjs +120 -9
- package/dist/cjs/index.cjs.map +3 -3
- package/dist/cjs/package.json +1 -1
- package/dist/cjs/stream-state.cjs +2 -4
- package/dist/cjs/stream-state.cjs.map +2 -2
- package/dist/mjs/index.mjs +119 -7
- package/dist/mjs/index.mjs.map +3 -3
- package/dist/mjs/package.json +1 -1
- package/dist/mjs/stream-state.mjs +1 -2
- package/dist/mjs/stream-state.mjs.map +2 -2
- package/package.json +1 -1
package/dist/mjs/index.mjs
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
// @bun
|
|
2
1
|
// packages/fetch/src/index.ts
|
|
3
2
|
import ivm from "isolated-vm";
|
|
4
3
|
import { setupCore, clearAllInstanceState } from "@ricsam/isolate-core";
|
|
@@ -7,6 +6,7 @@ import {
|
|
|
7
6
|
startNativeStreamReader
|
|
8
7
|
} from "./stream-state.mjs";
|
|
9
8
|
var instanceStateMap = new WeakMap;
|
|
9
|
+
var passthruBodies = new WeakMap;
|
|
10
10
|
var nextInstanceId = 1;
|
|
11
11
|
function getInstanceStateMapForContext(context) {
|
|
12
12
|
let map = instanceStateMap.get(context);
|
|
@@ -16,6 +16,14 @@ function getInstanceStateMapForContext(context) {
|
|
|
16
16
|
}
|
|
17
17
|
return map;
|
|
18
18
|
}
|
|
19
|
+
function getPassthruBodiesForContext(context) {
|
|
20
|
+
let map = passthruBodies.get(context);
|
|
21
|
+
if (!map) {
|
|
22
|
+
map = new Map;
|
|
23
|
+
passthruBodies.set(context, map);
|
|
24
|
+
}
|
|
25
|
+
return map;
|
|
26
|
+
}
|
|
19
27
|
var headersCode = `
|
|
20
28
|
(function() {
|
|
21
29
|
class Headers {
|
|
@@ -604,8 +612,12 @@ function setupResponse(context, stateMap) {
|
|
|
604
612
|
// Mark as needing async Blob handling - will be read in constructor
|
|
605
613
|
return { __isBlob: true, blob: body };
|
|
606
614
|
}
|
|
607
|
-
// Handle
|
|
608
|
-
if (body instanceof
|
|
615
|
+
// Handle HostBackedReadableStream specially - preserve streamId
|
|
616
|
+
if (body instanceof HostBackedReadableStream) {
|
|
617
|
+
return { __isHostStream: true, stream: body, streamId: body._getStreamId() };
|
|
618
|
+
}
|
|
619
|
+
// Handle native ReadableStream
|
|
620
|
+
if (body instanceof ReadableStream) {
|
|
609
621
|
return { __isStream: true, stream: body };
|
|
610
622
|
}
|
|
611
623
|
// Try to convert to string
|
|
@@ -660,7 +672,27 @@ function setupResponse(context, stateMap) {
|
|
|
660
672
|
return;
|
|
661
673
|
}
|
|
662
674
|
|
|
663
|
-
// Handle
|
|
675
|
+
// Handle HostBackedReadableStream - reuse existing streamId for pass-through
|
|
676
|
+
if (preparedBody && preparedBody.__isHostStream) {
|
|
677
|
+
// Reuse the existing streamId to preserve the pass-through body mapping
|
|
678
|
+
this.#streamId = preparedBody.streamId;
|
|
679
|
+
const status = init.status ?? 200;
|
|
680
|
+
const statusText = init.statusText ?? '';
|
|
681
|
+
const headers = new Headers(init.headers);
|
|
682
|
+
const headersArray = Array.from(headers.entries());
|
|
683
|
+
|
|
684
|
+
this.#instanceId = __Response_constructStreaming(
|
|
685
|
+
this.#streamId,
|
|
686
|
+
status,
|
|
687
|
+
statusText,
|
|
688
|
+
headersArray
|
|
689
|
+
);
|
|
690
|
+
this.#headers = headers;
|
|
691
|
+
// Don't pump - the body is already backed by this streamId
|
|
692
|
+
return;
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
// Handle native ReadableStream body
|
|
664
696
|
if (preparedBody && preparedBody.__isStream) {
|
|
665
697
|
this.#streamId = __Stream_create();
|
|
666
698
|
const status = init.status ?? 200;
|
|
@@ -1341,7 +1373,8 @@ function setupRequest(context, stateMap) {
|
|
|
1341
1373
|
`;
|
|
1342
1374
|
context.evalSync(requestCode);
|
|
1343
1375
|
}
|
|
1344
|
-
|
|
1376
|
+
var FETCH_STREAM_THRESHOLD = 64 * 1024;
|
|
1377
|
+
function setupFetchFunction(context, stateMap, streamRegistry, options) {
|
|
1345
1378
|
const global = context.global;
|
|
1346
1379
|
const fetchRef = new ivm.Reference(async (url, method, headersJson, bodyJson, signalAborted) => {
|
|
1347
1380
|
if (signalAborted) {
|
|
@@ -1357,6 +1390,69 @@ function setupFetchFunction(context, stateMap, options) {
|
|
|
1357
1390
|
});
|
|
1358
1391
|
const onFetch = options?.onFetch ?? fetch;
|
|
1359
1392
|
const nativeResponse = await onFetch(nativeRequest);
|
|
1393
|
+
const contentLength = nativeResponse.headers.get("content-length");
|
|
1394
|
+
const knownSize = contentLength ? parseInt(contentLength, 10) : null;
|
|
1395
|
+
const isCallbackStream = nativeResponse.__isCallbackStream;
|
|
1396
|
+
const isNetworkResponse = nativeResponse.url && (nativeResponse.url.startsWith("http://") || nativeResponse.url.startsWith("https://"));
|
|
1397
|
+
const shouldStream = nativeResponse.body && (isCallbackStream || isNetworkResponse && (knownSize === null || knownSize > FETCH_STREAM_THRESHOLD));
|
|
1398
|
+
if (shouldStream && nativeResponse.body) {
|
|
1399
|
+
if (isCallbackStream) {
|
|
1400
|
+
const streamId2 = streamRegistry.create();
|
|
1401
|
+
const passthruMap = getPassthruBodiesForContext(context);
|
|
1402
|
+
passthruMap.set(streamId2, nativeResponse.body);
|
|
1403
|
+
const instanceId3 = nextInstanceId++;
|
|
1404
|
+
const state3 = {
|
|
1405
|
+
status: nativeResponse.status,
|
|
1406
|
+
statusText: nativeResponse.statusText,
|
|
1407
|
+
headers: Array.from(nativeResponse.headers.entries()),
|
|
1408
|
+
body: new Uint8Array(0),
|
|
1409
|
+
bodyUsed: false,
|
|
1410
|
+
type: "default",
|
|
1411
|
+
url: nativeResponse.url,
|
|
1412
|
+
redirected: nativeResponse.redirected,
|
|
1413
|
+
streamId: streamId2
|
|
1414
|
+
};
|
|
1415
|
+
stateMap.set(instanceId3, state3);
|
|
1416
|
+
return instanceId3;
|
|
1417
|
+
}
|
|
1418
|
+
const streamId = streamRegistry.create();
|
|
1419
|
+
const instanceId2 = nextInstanceId++;
|
|
1420
|
+
const state2 = {
|
|
1421
|
+
status: nativeResponse.status,
|
|
1422
|
+
statusText: nativeResponse.statusText,
|
|
1423
|
+
headers: Array.from(nativeResponse.headers.entries()),
|
|
1424
|
+
body: new Uint8Array(0),
|
|
1425
|
+
bodyUsed: false,
|
|
1426
|
+
type: "default",
|
|
1427
|
+
url: nativeResponse.url,
|
|
1428
|
+
redirected: nativeResponse.redirected,
|
|
1429
|
+
streamId
|
|
1430
|
+
};
|
|
1431
|
+
stateMap.set(instanceId2, state2);
|
|
1432
|
+
const reader = nativeResponse.body.getReader();
|
|
1433
|
+
(async () => {
|
|
1434
|
+
try {
|
|
1435
|
+
while (true) {
|
|
1436
|
+
const { done, value } = await reader.read();
|
|
1437
|
+
if (done) {
|
|
1438
|
+
streamRegistry.close(streamId);
|
|
1439
|
+
break;
|
|
1440
|
+
}
|
|
1441
|
+
if (value) {
|
|
1442
|
+
while (streamRegistry.isQueueFull(streamId)) {
|
|
1443
|
+
await new Promise((r) => setTimeout(r, 1));
|
|
1444
|
+
}
|
|
1445
|
+
streamRegistry.push(streamId, value);
|
|
1446
|
+
}
|
|
1447
|
+
}
|
|
1448
|
+
} catch (err) {
|
|
1449
|
+
streamRegistry.error(streamId, err);
|
|
1450
|
+
} finally {
|
|
1451
|
+
reader.releaseLock();
|
|
1452
|
+
}
|
|
1453
|
+
})();
|
|
1454
|
+
return instanceId2;
|
|
1455
|
+
}
|
|
1360
1456
|
const responseBody = await nativeResponse.arrayBuffer();
|
|
1361
1457
|
const responseBodyArray = Array.from(new Uint8Array(responseBody));
|
|
1362
1458
|
const instanceId = nextInstanceId++;
|
|
@@ -1530,7 +1626,7 @@ async function setupFetch(context, options) {
|
|
|
1530
1626
|
context.evalSync(hostBackedStreamCode);
|
|
1531
1627
|
setupResponse(context, stateMap);
|
|
1532
1628
|
setupRequest(context, stateMap);
|
|
1533
|
-
setupFetchFunction(context, stateMap, options);
|
|
1629
|
+
setupFetchFunction(context, stateMap, streamRegistry, options);
|
|
1534
1630
|
const serveState = {
|
|
1535
1631
|
pendingUpgrade: null,
|
|
1536
1632
|
activeConnections: new Map
|
|
@@ -1593,6 +1689,22 @@ async function setupFetch(context, options) {
|
|
|
1593
1689
|
if (!responseState) {
|
|
1594
1690
|
throw new Error("Response state not found");
|
|
1595
1691
|
}
|
|
1692
|
+
if (responseState.streamId !== null) {
|
|
1693
|
+
const passthruMap = getPassthruBodiesForContext(context);
|
|
1694
|
+
const passthruBody = passthruMap.get(responseState.streamId);
|
|
1695
|
+
if (passthruBody) {
|
|
1696
|
+
passthruMap.delete(responseState.streamId);
|
|
1697
|
+
const responseHeaders2 = new Headers(responseState.headers);
|
|
1698
|
+
const status2 = responseState.status === 101 ? 200 : responseState.status;
|
|
1699
|
+
const response2 = new Response(passthruBody, {
|
|
1700
|
+
status: status2,
|
|
1701
|
+
statusText: responseState.statusText,
|
|
1702
|
+
headers: responseHeaders2
|
|
1703
|
+
});
|
|
1704
|
+
response2._originalStatus = responseState.status;
|
|
1705
|
+
return response2;
|
|
1706
|
+
}
|
|
1707
|
+
}
|
|
1596
1708
|
if (responseState.streamId !== null) {
|
|
1597
1709
|
const responseStreamId = responseState.streamId;
|
|
1598
1710
|
let streamDone = false;
|
|
@@ -1778,4 +1890,4 @@ export {
|
|
|
1778
1890
|
clearAllInstanceState
|
|
1779
1891
|
};
|
|
1780
1892
|
|
|
1781
|
-
//# debugId=
|
|
1893
|
+
//# debugId=DA9402429BBB147864756E2164756E21
|