@statewalker/webrun-http-browser 0.12.1 → 0.12.3
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/index.js +98 -64
- package/dist/link/http-link.d.ts.map +1 -1
- package/dist/relay-sw.js +72 -45
- package/dist/relay-worker.js +72 -45
- package/dist/sw/worker-service.d.ts.map +1 -1
- package/dist/sw-worker.js +72 -45
- package/dist/sw.js +98 -64
- package/dist/worker.js +98 -64
- package/dist/ws/frames.d.ts +6 -1
- package/dist/ws/frames.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/link/http-link.ts +41 -26
- package/src/sw/worker-service.ts +12 -1
- package/src/ws/frames.ts +18 -12
package/dist/relay-worker.js
CHANGED
|
@@ -1137,7 +1137,10 @@ async function httpFetch(call, env, body, options = {}) {
|
|
|
1137
1137
|
}
|
|
1138
1138
|
const onAbort = () => void release();
|
|
1139
1139
|
signal?.addEventListener("abort", onAbort, { once: true });
|
|
1140
|
-
|
|
1140
|
+
options.keepAlive;
|
|
1141
|
+
drain(output).finally(() => {
|
|
1142
|
+
signal?.removeEventListener("abort", onAbort);
|
|
1143
|
+
});
|
|
1141
1144
|
};
|
|
1142
1145
|
let decoded;
|
|
1143
1146
|
try {
|
|
@@ -1387,7 +1390,8 @@ async function fetchOverDuplex(call, request, options = {}) {
|
|
|
1387
1390
|
}
|
|
1388
1391
|
const { envelope, body: respBody, release, finish } = await httpFetch(call, env, body, {
|
|
1389
1392
|
...options,
|
|
1390
|
-
signal: request.signal ?? void 0
|
|
1393
|
+
signal: request.signal ?? void 0,
|
|
1394
|
+
keepAlive: request
|
|
1391
1395
|
});
|
|
1392
1396
|
const responseInit = {
|
|
1393
1397
|
status: envelope.status,
|
|
@@ -1399,7 +1403,7 @@ async function fetchOverDuplex(call, request, options = {}) {
|
|
|
1399
1403
|
else await release?.();
|
|
1400
1404
|
return new Response(null, responseInit);
|
|
1401
1405
|
}
|
|
1402
|
-
return new Response(responseBody(respBody, request
|
|
1406
|
+
return new Response(responseBody(respBody, request, release), responseInit);
|
|
1403
1407
|
}
|
|
1404
1408
|
/**
|
|
1405
1409
|
* How long a cancelled body waits for the read in flight before it abandons the call anyway.
|
|
@@ -1422,7 +1426,9 @@ const CANCEL_GRACE_MS = 1e3;
|
|
|
1422
1426
|
* A cancel abandons the call too — unless the read in flight comes back with the
|
|
1423
1427
|
* body's end, which finishes it instead (see `cancel`).
|
|
1424
1428
|
*/
|
|
1425
|
-
function responseBody(body,
|
|
1429
|
+
function responseBody(body, request, release) {
|
|
1430
|
+
const keep = { request };
|
|
1431
|
+
const signal = request.signal ?? void 0;
|
|
1426
1432
|
const it = body[Symbol.asyncIterator]();
|
|
1427
1433
|
let controller;
|
|
1428
1434
|
let ended = false;
|
|
@@ -1430,6 +1436,7 @@ function responseBody(body, signal, release) {
|
|
|
1430
1436
|
const end = () => {
|
|
1431
1437
|
ended = true;
|
|
1432
1438
|
signal?.removeEventListener("abort", onAbort);
|
|
1439
|
+
keep.request = void 0;
|
|
1433
1440
|
};
|
|
1434
1441
|
const onAbort = () => {
|
|
1435
1442
|
if (ended) return;
|
|
@@ -2393,12 +2400,6 @@ async function sendChunks(port, channelName, output, { maxMessageSize, log }, si
|
|
|
2393
2400
|
const producer = output;
|
|
2394
2401
|
const returnProducer = () => void Promise.resolve(producer.return?.()).catch(() => {});
|
|
2395
2402
|
if (framed !== output) signal.addEventListener("abort", returnProducer, { once: true });
|
|
2396
|
-
let onAborted = () => {};
|
|
2397
|
-
const aborted = new Promise((resolve) => {
|
|
2398
|
-
onAborted = () => resolve();
|
|
2399
|
-
});
|
|
2400
|
-
if (signal.aborted) onAborted();
|
|
2401
|
-
else signal.addEventListener("abort", onAborted, { once: true });
|
|
2402
2403
|
try {
|
|
2403
2404
|
await sendIterator(async ({ done, value, error }) => {
|
|
2404
2405
|
if (signal.aborted) return;
|
|
@@ -2420,7 +2421,7 @@ async function sendChunks(port, channelName, output, { maxMessageSize, log }, si
|
|
|
2420
2421
|
});
|
|
2421
2422
|
touch();
|
|
2422
2423
|
if (done && !error) onSent();
|
|
2423
|
-
if (portBufferedAmount(port) > 0) await
|
|
2424
|
+
if (portBufferedAmount(port) > 0) await whenReadyOrAborted(port, signal);
|
|
2424
2425
|
return;
|
|
2425
2426
|
}
|
|
2426
2427
|
await callPort(port, chunk, {
|
|
@@ -2436,10 +2437,25 @@ async function sendChunks(port, channelName, output, { maxMessageSize, log }, si
|
|
|
2436
2437
|
throw err;
|
|
2437
2438
|
} finally {
|
|
2438
2439
|
signal.removeEventListener("abort", returnProducer);
|
|
2439
|
-
signal.removeEventListener("abort", onAborted);
|
|
2440
2440
|
}
|
|
2441
2441
|
}
|
|
2442
2442
|
/**
|
|
2443
|
+
* A pipelined sender waits only for room in the window, or for the abort. The
|
|
2444
|
+
* abort listener lives for this one wait: a promise held for the whole stream
|
|
2445
|
+
* would keep one reaction per wait until the stream ends.
|
|
2446
|
+
*/
|
|
2447
|
+
function whenReadyOrAborted(port, signal) {
|
|
2448
|
+
if (signal.aborted) return Promise.resolve();
|
|
2449
|
+
return new Promise((resolve) => {
|
|
2450
|
+
const settle = () => {
|
|
2451
|
+
signal.removeEventListener("abort", settle);
|
|
2452
|
+
resolve();
|
|
2453
|
+
};
|
|
2454
|
+
signal.addEventListener("abort", settle, { once: true });
|
|
2455
|
+
whenPortReady(port).then(settle, settle);
|
|
2456
|
+
});
|
|
2457
|
+
}
|
|
2458
|
+
/**
|
|
2443
2459
|
* One virtual port.
|
|
2444
2460
|
*
|
|
2445
2461
|
* `deliver` and `markClosed` are deliberately not on `port`: the consumer holds
|
|
@@ -3365,7 +3381,12 @@ function trackedLink(send, release) {
|
|
|
3365
3381
|
finish();
|
|
3366
3382
|
return response;
|
|
3367
3383
|
}
|
|
3368
|
-
|
|
3384
|
+
failers.delete(fail);
|
|
3385
|
+
const body = guardBody(response.body, finish, request);
|
|
3386
|
+
fail = body.fail;
|
|
3387
|
+
if (closed) fail(lostReason);
|
|
3388
|
+
else if (!finished) failers.add(fail);
|
|
3389
|
+
return new Response(body.stream, {
|
|
3369
3390
|
status: response.status,
|
|
3370
3391
|
statusText: response.statusText,
|
|
3371
3392
|
headers: response.headers
|
|
@@ -3384,56 +3405,62 @@ function trackedLink(send, release) {
|
|
|
3384
3405
|
return asyncDisposable(link, () => link.close());
|
|
3385
3406
|
}
|
|
3386
3407
|
/**
|
|
3387
|
-
* A response body that reports its end (done, cancelled, failed or aborted)
|
|
3388
|
-
*
|
|
3389
|
-
*
|
|
3390
|
-
*
|
|
3408
|
+
* A response body that reports its end (done, cancelled, failed or aborted).
|
|
3409
|
+
* `fail(error)` ends it with `error` at once — the link calls it when it is lost
|
|
3410
|
+
* mid-stream. An abort of the request's signal does the same with the signal's
|
|
3411
|
+
* reason, read or not: the exchange is over (the layer below has given its port
|
|
3412
|
+
* back), so the request leaves `inflight` then. A read waits on the reader
|
|
3413
|
+
* alone, so nothing outlives the chunk it brings.
|
|
3391
3414
|
*/
|
|
3392
|
-
function guardBody(body,
|
|
3415
|
+
function guardBody(body, finish, request) {
|
|
3416
|
+
const keep = { request };
|
|
3417
|
+
const signal = request.signal ?? void 0;
|
|
3393
3418
|
const reader = body.getReader();
|
|
3394
3419
|
let controller;
|
|
3395
3420
|
let ended = false;
|
|
3396
3421
|
const end = () => {
|
|
3397
3422
|
ended = true;
|
|
3398
3423
|
signal?.removeEventListener("abort", onAbort);
|
|
3424
|
+
keep.request = void 0;
|
|
3399
3425
|
finish();
|
|
3400
3426
|
};
|
|
3401
|
-
const
|
|
3427
|
+
const fail = (error) => {
|
|
3402
3428
|
if (ended) return;
|
|
3403
3429
|
end();
|
|
3404
3430
|
reader.cancel().catch(() => {});
|
|
3405
3431
|
try {
|
|
3406
|
-
controller.error(
|
|
3432
|
+
controller.error(error);
|
|
3407
3433
|
} catch {}
|
|
3408
3434
|
};
|
|
3409
|
-
|
|
3410
|
-
|
|
3411
|
-
|
|
3412
|
-
|
|
3413
|
-
|
|
3414
|
-
|
|
3415
|
-
|
|
3416
|
-
|
|
3417
|
-
|
|
3418
|
-
|
|
3419
|
-
|
|
3420
|
-
|
|
3421
|
-
|
|
3422
|
-
|
|
3435
|
+
const onAbort = () => fail(abortError(signal));
|
|
3436
|
+
return {
|
|
3437
|
+
stream: new ReadableStream({
|
|
3438
|
+
start(c) {
|
|
3439
|
+
controller = c;
|
|
3440
|
+
if (signal?.aborted) onAbort();
|
|
3441
|
+
else signal?.addEventListener("abort", onAbort, { once: true });
|
|
3442
|
+
},
|
|
3443
|
+
async pull(controller) {
|
|
3444
|
+
try {
|
|
3445
|
+
const { done, value } = await reader.read();
|
|
3446
|
+
if (ended) return;
|
|
3447
|
+
if (done) {
|
|
3448
|
+
end();
|
|
3449
|
+
controller.close();
|
|
3450
|
+
return;
|
|
3451
|
+
}
|
|
3452
|
+
controller.enqueue(value);
|
|
3453
|
+
} catch (error) {
|
|
3454
|
+
fail(error);
|
|
3423
3455
|
}
|
|
3424
|
-
|
|
3425
|
-
|
|
3426
|
-
if (ended) return;
|
|
3456
|
+
},
|
|
3457
|
+
cancel(why) {
|
|
3427
3458
|
end();
|
|
3428
|
-
reader.cancel().catch(() => {});
|
|
3429
|
-
controller.error(reason() ?? error);
|
|
3459
|
+
setTimeout(() => void reader.cancel(why).catch(() => {}), 0);
|
|
3430
3460
|
}
|
|
3431
|
-
},
|
|
3432
|
-
|
|
3433
|
-
|
|
3434
|
-
await reader.cancel(why).catch(() => {});
|
|
3435
|
-
}
|
|
3436
|
-
});
|
|
3461
|
+
}),
|
|
3462
|
+
fail
|
|
3463
|
+
};
|
|
3437
3464
|
}
|
|
3438
3465
|
/** The signal's reason as an `Error` (`AbortError` when it gave none). */
|
|
3439
3466
|
function abortError(signal) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"worker-service.d.ts","sourceRoot":"","sources":["../../src/sw/worker-service.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,KAAK,kBAAkB,EACvB,KAAK,qBAAqB,EAC1B,KAAK,mBAAmB,EACzB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,KAAK,YAAY,EAEjB,KAAK,sBAAsB,EAC5B,MAAM,uBAAuB,CAAC;AAG/B,MAAM,WAAW,wBACf,SAAQ,IAAI,CAAC,sBAAsB,EAAE,eAAe,GAAG,WAAW,CAAC;IACnE,mFAAmF;IACnF,KAAK,CAAC,EAAE,IAAI,CAAC,WAAW,EAAE,kBAAkB,GAAG,qBAAqB,CAAC,CAAC;IACtE,8DAA8D;IAC9D,SAAS,CAAC,EAAE,qBAAqB,CAAC;CACnC;AAED,yDAAyD;AACzD,MAAM,WAAW,iBAAiB;IAChC;;;;;;OAMG;IACH,KAAK,CAAC,KAAK,EAAE,WAAW,GAAG,GAAG,EAAE,IAAI,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IACvE;;;OAGG;IACH,gBAAgB,CACd,GAAG,EAAE,MAAM,GAAG,GAAG,EACjB,SAAS,CAAC,EAAE,MAAM,EAAE,EACpB,OAAO,CAAC,EAAE,WAAW,GACpB,OAAO,CAAC,mBAAmB,CAAC,CAAC;IAChC,0DAA0D;IAC1D,QAAQ,CAAC,SAAS,EAAE,kBAAkB,CAAC;IACvC,0CAA0C;IAC1C,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,8CAA8C;IAC9C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,YAAY,EACrB,OAAO,GAAE,wBAA6B,GACrC,iBAAiB,
|
|
1
|
+
{"version":3,"file":"worker-service.d.ts","sourceRoot":"","sources":["../../src/sw/worker-service.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,KAAK,kBAAkB,EACvB,KAAK,qBAAqB,EAC1B,KAAK,mBAAmB,EACzB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,KAAK,YAAY,EAEjB,KAAK,sBAAsB,EAC5B,MAAM,uBAAuB,CAAC;AAG/B,MAAM,WAAW,wBACf,SAAQ,IAAI,CAAC,sBAAsB,EAAE,eAAe,GAAG,WAAW,CAAC;IACnE,mFAAmF;IACnF,KAAK,CAAC,EAAE,IAAI,CAAC,WAAW,EAAE,kBAAkB,GAAG,qBAAqB,CAAC,CAAC;IACtE,8DAA8D;IAC9D,SAAS,CAAC,EAAE,qBAAqB,CAAC;CACnC;AAED,yDAAyD;AACzD,MAAM,WAAW,iBAAiB;IAChC;;;;;;OAMG;IACH,KAAK,CAAC,KAAK,EAAE,WAAW,GAAG,GAAG,EAAE,IAAI,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IACvE;;;OAGG;IACH,gBAAgB,CACd,GAAG,EAAE,MAAM,GAAG,GAAG,EACjB,SAAS,CAAC,EAAE,MAAM,EAAE,EACpB,OAAO,CAAC,EAAE,WAAW,GACpB,OAAO,CAAC,mBAAmB,CAAC,CAAC;IAChC,0DAA0D;IAC1D,QAAQ,CAAC,SAAS,EAAE,kBAAkB,CAAC;IACvC,0CAA0C;IAC1C,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,8CAA8C;IAC9C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,YAAY,EACrB,OAAO,GAAE,wBAA6B,GACrC,iBAAiB,CA+FnB"}
|
package/dist/sw-worker.js
CHANGED
|
@@ -1312,7 +1312,10 @@
|
|
|
1312
1312
|
}
|
|
1313
1313
|
const onAbort = () => void release();
|
|
1314
1314
|
signal?.addEventListener("abort", onAbort, { once: true });
|
|
1315
|
-
|
|
1315
|
+
options.keepAlive;
|
|
1316
|
+
drain(output).finally(() => {
|
|
1317
|
+
signal?.removeEventListener("abort", onAbort);
|
|
1318
|
+
});
|
|
1316
1319
|
};
|
|
1317
1320
|
let decoded;
|
|
1318
1321
|
try {
|
|
@@ -1675,7 +1678,8 @@
|
|
|
1675
1678
|
}
|
|
1676
1679
|
const { envelope, body: respBody, release, finish } = await httpFetch(call, env, body, {
|
|
1677
1680
|
...options,
|
|
1678
|
-
signal: request.signal ?? void 0
|
|
1681
|
+
signal: request.signal ?? void 0,
|
|
1682
|
+
keepAlive: request
|
|
1679
1683
|
});
|
|
1680
1684
|
const responseInit = {
|
|
1681
1685
|
status: envelope.status,
|
|
@@ -1687,7 +1691,7 @@
|
|
|
1687
1691
|
else await release?.();
|
|
1688
1692
|
return new Response(null, responseInit);
|
|
1689
1693
|
}
|
|
1690
|
-
return new Response(responseBody(respBody, request
|
|
1694
|
+
return new Response(responseBody(respBody, request, release), responseInit);
|
|
1691
1695
|
}
|
|
1692
1696
|
/**
|
|
1693
1697
|
* Wrap a `(Request) => Promise<Response>` handler as a `Duplex` so it can be
|
|
@@ -1840,7 +1844,9 @@
|
|
|
1840
1844
|
* A cancel abandons the call too — unless the read in flight comes back with the
|
|
1841
1845
|
* body's end, which finishes it instead (see `cancel`).
|
|
1842
1846
|
*/
|
|
1843
|
-
function responseBody(body,
|
|
1847
|
+
function responseBody(body, request, release) {
|
|
1848
|
+
const keep = { request };
|
|
1849
|
+
const signal = request.signal ?? void 0;
|
|
1844
1850
|
const it = body[Symbol.asyncIterator]();
|
|
1845
1851
|
let controller;
|
|
1846
1852
|
let ended = false;
|
|
@@ -1848,6 +1854,7 @@
|
|
|
1848
1854
|
const end = () => {
|
|
1849
1855
|
ended = true;
|
|
1850
1856
|
signal?.removeEventListener("abort", onAbort);
|
|
1857
|
+
keep.request = void 0;
|
|
1851
1858
|
};
|
|
1852
1859
|
const onAbort = () => {
|
|
1853
1860
|
if (ended) return;
|
|
@@ -2879,12 +2886,6 @@
|
|
|
2879
2886
|
const producer = output;
|
|
2880
2887
|
const returnProducer = () => void Promise.resolve(producer.return?.()).catch(() => {});
|
|
2881
2888
|
if (framed !== output) signal.addEventListener("abort", returnProducer, { once: true });
|
|
2882
|
-
let onAborted = () => {};
|
|
2883
|
-
const aborted = new Promise((resolve) => {
|
|
2884
|
-
onAborted = () => resolve();
|
|
2885
|
-
});
|
|
2886
|
-
if (signal.aborted) onAborted();
|
|
2887
|
-
else signal.addEventListener("abort", onAborted, { once: true });
|
|
2888
2889
|
try {
|
|
2889
2890
|
await sendIterator(async ({ done, value, error }) => {
|
|
2890
2891
|
if (signal.aborted) return;
|
|
@@ -2906,7 +2907,7 @@
|
|
|
2906
2907
|
});
|
|
2907
2908
|
touch();
|
|
2908
2909
|
if (done && !error) onSent();
|
|
2909
|
-
if (portBufferedAmount(port) > 0) await
|
|
2910
|
+
if (portBufferedAmount(port) > 0) await whenReadyOrAborted(port, signal);
|
|
2910
2911
|
return;
|
|
2911
2912
|
}
|
|
2912
2913
|
await callPort(port, chunk, {
|
|
@@ -2922,10 +2923,25 @@
|
|
|
2922
2923
|
throw err;
|
|
2923
2924
|
} finally {
|
|
2924
2925
|
signal.removeEventListener("abort", returnProducer);
|
|
2925
|
-
signal.removeEventListener("abort", onAborted);
|
|
2926
2926
|
}
|
|
2927
2927
|
}
|
|
2928
2928
|
/**
|
|
2929
|
+
* A pipelined sender waits only for room in the window, or for the abort. The
|
|
2930
|
+
* abort listener lives for this one wait: a promise held for the whole stream
|
|
2931
|
+
* would keep one reaction per wait until the stream ends.
|
|
2932
|
+
*/
|
|
2933
|
+
function whenReadyOrAborted(port, signal) {
|
|
2934
|
+
if (signal.aborted) return Promise.resolve();
|
|
2935
|
+
return new Promise((resolve) => {
|
|
2936
|
+
const settle = () => {
|
|
2937
|
+
signal.removeEventListener("abort", settle);
|
|
2938
|
+
resolve();
|
|
2939
|
+
};
|
|
2940
|
+
signal.addEventListener("abort", settle, { once: true });
|
|
2941
|
+
whenPortReady(port).then(settle, settle);
|
|
2942
|
+
});
|
|
2943
|
+
}
|
|
2944
|
+
/**
|
|
2929
2945
|
* One virtual port.
|
|
2930
2946
|
*
|
|
2931
2947
|
* `deliver` and `markClosed` are deliberately not on `port`: the consumer holds
|
|
@@ -3923,7 +3939,12 @@
|
|
|
3923
3939
|
finish();
|
|
3924
3940
|
return response;
|
|
3925
3941
|
}
|
|
3926
|
-
|
|
3942
|
+
failers.delete(fail);
|
|
3943
|
+
const body = guardBody(response.body, finish, request);
|
|
3944
|
+
fail = body.fail;
|
|
3945
|
+
if (closed) fail(lostReason);
|
|
3946
|
+
else if (!finished) failers.add(fail);
|
|
3947
|
+
return new Response(body.stream, {
|
|
3927
3948
|
status: response.status,
|
|
3928
3949
|
statusText: response.statusText,
|
|
3929
3950
|
headers: response.headers
|
|
@@ -3942,56 +3963,62 @@
|
|
|
3942
3963
|
return asyncDisposable(link, () => link.close());
|
|
3943
3964
|
}
|
|
3944
3965
|
/**
|
|
3945
|
-
* A response body that reports its end (done, cancelled, failed or aborted)
|
|
3946
|
-
*
|
|
3947
|
-
*
|
|
3948
|
-
*
|
|
3966
|
+
* A response body that reports its end (done, cancelled, failed or aborted).
|
|
3967
|
+
* `fail(error)` ends it with `error` at once — the link calls it when it is lost
|
|
3968
|
+
* mid-stream. An abort of the request's signal does the same with the signal's
|
|
3969
|
+
* reason, read or not: the exchange is over (the layer below has given its port
|
|
3970
|
+
* back), so the request leaves `inflight` then. A read waits on the reader
|
|
3971
|
+
* alone, so nothing outlives the chunk it brings.
|
|
3949
3972
|
*/
|
|
3950
|
-
function guardBody(body,
|
|
3973
|
+
function guardBody(body, finish, request) {
|
|
3974
|
+
const keep = { request };
|
|
3975
|
+
const signal = request.signal ?? void 0;
|
|
3951
3976
|
const reader = body.getReader();
|
|
3952
3977
|
let controller;
|
|
3953
3978
|
let ended = false;
|
|
3954
3979
|
const end = () => {
|
|
3955
3980
|
ended = true;
|
|
3956
3981
|
signal?.removeEventListener("abort", onAbort);
|
|
3982
|
+
keep.request = void 0;
|
|
3957
3983
|
finish();
|
|
3958
3984
|
};
|
|
3959
|
-
const
|
|
3985
|
+
const fail = (error) => {
|
|
3960
3986
|
if (ended) return;
|
|
3961
3987
|
end();
|
|
3962
3988
|
reader.cancel().catch(() => {});
|
|
3963
3989
|
try {
|
|
3964
|
-
controller.error(
|
|
3990
|
+
controller.error(error);
|
|
3965
3991
|
} catch {}
|
|
3966
3992
|
};
|
|
3967
|
-
|
|
3968
|
-
|
|
3969
|
-
|
|
3970
|
-
|
|
3971
|
-
|
|
3972
|
-
|
|
3973
|
-
|
|
3974
|
-
|
|
3975
|
-
|
|
3976
|
-
|
|
3977
|
-
|
|
3978
|
-
|
|
3979
|
-
|
|
3980
|
-
|
|
3993
|
+
const onAbort = () => fail(abortError(signal));
|
|
3994
|
+
return {
|
|
3995
|
+
stream: new ReadableStream({
|
|
3996
|
+
start(c) {
|
|
3997
|
+
controller = c;
|
|
3998
|
+
if (signal?.aborted) onAbort();
|
|
3999
|
+
else signal?.addEventListener("abort", onAbort, { once: true });
|
|
4000
|
+
},
|
|
4001
|
+
async pull(controller) {
|
|
4002
|
+
try {
|
|
4003
|
+
const { done, value } = await reader.read();
|
|
4004
|
+
if (ended) return;
|
|
4005
|
+
if (done) {
|
|
4006
|
+
end();
|
|
4007
|
+
controller.close();
|
|
4008
|
+
return;
|
|
4009
|
+
}
|
|
4010
|
+
controller.enqueue(value);
|
|
4011
|
+
} catch (error) {
|
|
4012
|
+
fail(error);
|
|
3981
4013
|
}
|
|
3982
|
-
|
|
3983
|
-
|
|
3984
|
-
if (ended) return;
|
|
4014
|
+
},
|
|
4015
|
+
cancel(why) {
|
|
3985
4016
|
end();
|
|
3986
|
-
reader.cancel().catch(() => {});
|
|
3987
|
-
controller.error(reason() ?? error);
|
|
4017
|
+
setTimeout(() => void reader.cancel(why).catch(() => {}), 0);
|
|
3988
4018
|
}
|
|
3989
|
-
},
|
|
3990
|
-
|
|
3991
|
-
|
|
3992
|
-
await reader.cancel(why).catch(() => {});
|
|
3993
|
-
}
|
|
3994
|
-
});
|
|
4019
|
+
}),
|
|
4020
|
+
fail
|
|
4021
|
+
};
|
|
3995
4022
|
}
|
|
3996
4023
|
/** The signal's reason as an `Error` (`AbortError` when it gave none). */
|
|
3997
4024
|
function abortError(signal) {
|