@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/index.js
CHANGED
|
@@ -1747,7 +1747,7 @@ const LAST_CHUNK = /* @__PURE__ */ new Uint8Array([
|
|
|
1747
1747
|
13,
|
|
1748
1748
|
10
|
|
1749
1749
|
]);
|
|
1750
|
-
const encoder = /* @__PURE__ */ new TextEncoder();
|
|
1750
|
+
const encoder$2 = /* @__PURE__ */ new TextEncoder();
|
|
1751
1751
|
/**
|
|
1752
1752
|
* Chunk sizes are written in HEXADECIMAL — a 21-byte chunk is `15`. Writing
|
|
1753
1753
|
* them in decimal is the defect note 15 found in @libp2p/http, and it is the
|
|
@@ -1760,7 +1760,7 @@ const encoder = /* @__PURE__ */ new TextEncoder();
|
|
|
1760
1760
|
async function* encodeChunked(body) {
|
|
1761
1761
|
for await (const chunk of body) {
|
|
1762
1762
|
if (chunk.byteLength === 0) continue;
|
|
1763
|
-
yield encoder.encode(`${chunk.byteLength.toString(16)}\r\n`);
|
|
1763
|
+
yield encoder$2.encode(`${chunk.byteLength.toString(16)}\r\n`);
|
|
1764
1764
|
yield chunk;
|
|
1765
1765
|
yield CRLF;
|
|
1766
1766
|
}
|
|
@@ -2230,7 +2230,10 @@ async function httpFetch(call, env, body, options = {}) {
|
|
|
2230
2230
|
}
|
|
2231
2231
|
const onAbort = () => void release();
|
|
2232
2232
|
signal?.addEventListener("abort", onAbort, { once: true });
|
|
2233
|
-
|
|
2233
|
+
options.keepAlive;
|
|
2234
|
+
drain(output).finally(() => {
|
|
2235
|
+
signal?.removeEventListener("abort", onAbort);
|
|
2236
|
+
});
|
|
2234
2237
|
};
|
|
2235
2238
|
let decoded;
|
|
2236
2239
|
try {
|
|
@@ -2626,7 +2629,8 @@ async function fetchOverDuplex(call, request, options = {}) {
|
|
|
2626
2629
|
}
|
|
2627
2630
|
const { envelope, body: respBody, release, finish } = await httpFetch(call, env, body, {
|
|
2628
2631
|
...options,
|
|
2629
|
-
signal: request.signal ?? void 0
|
|
2632
|
+
signal: request.signal ?? void 0,
|
|
2633
|
+
keepAlive: request
|
|
2630
2634
|
});
|
|
2631
2635
|
const responseInit = {
|
|
2632
2636
|
status: envelope.status,
|
|
@@ -2638,7 +2642,7 @@ async function fetchOverDuplex(call, request, options = {}) {
|
|
|
2638
2642
|
else await release?.();
|
|
2639
2643
|
return new Response(null, responseInit);
|
|
2640
2644
|
}
|
|
2641
|
-
return new Response(responseBody(respBody, request
|
|
2645
|
+
return new Response(responseBody(respBody, request, release), responseInit);
|
|
2642
2646
|
}
|
|
2643
2647
|
/**
|
|
2644
2648
|
* Wrap a `(Request) => Promise<Response>` handler as a `Duplex` so it can be
|
|
@@ -2791,7 +2795,9 @@ const CANCEL_GRACE_MS = 1e3;
|
|
|
2791
2795
|
* A cancel abandons the call too — unless the read in flight comes back with the
|
|
2792
2796
|
* body's end, which finishes it instead (see `cancel`).
|
|
2793
2797
|
*/
|
|
2794
|
-
function responseBody(body,
|
|
2798
|
+
function responseBody(body, request, release) {
|
|
2799
|
+
const keep = { request };
|
|
2800
|
+
const signal = request.signal ?? void 0;
|
|
2795
2801
|
const it = body[Symbol.asyncIterator]();
|
|
2796
2802
|
let controller;
|
|
2797
2803
|
let ended = false;
|
|
@@ -2799,6 +2805,7 @@ function responseBody(body, signal, release) {
|
|
|
2799
2805
|
const end = () => {
|
|
2800
2806
|
ended = true;
|
|
2801
2807
|
signal?.removeEventListener("abort", onAbort);
|
|
2808
|
+
keep.request = void 0;
|
|
2802
2809
|
};
|
|
2803
2810
|
const onAbort = () => {
|
|
2804
2811
|
if (ended) return;
|
|
@@ -3331,7 +3338,7 @@ const STREAM_ABORT = "webrun-rpc:stream-abort";
|
|
|
3331
3338
|
* request, sent only on a port where both ends agreed `pipeline`. The window's
|
|
3332
3339
|
* credit is its confirmation.
|
|
3333
3340
|
*/
|
|
3334
|
-
const CHUNK = "webrun-rpc:chunk";
|
|
3341
|
+
const CHUNK$1 = "webrun-rpc:chunk";
|
|
3335
3342
|
/**
|
|
3336
3343
|
* What a pipelined chunk counts beyond its bytes, against the window, on the
|
|
3337
3344
|
* receiving side. Both codecs' windows count more for the chunk's envelope
|
|
@@ -3662,7 +3669,7 @@ function receiveChunks(port, channelName, controller, touch, notice) {
|
|
|
3662
3669
|
const watcher = (event) => {
|
|
3663
3670
|
const data = event.data;
|
|
3664
3671
|
if (data?.channelName !== channelName) return;
|
|
3665
|
-
const chunk = data.type === CHUNK ? data.chunk : data.type === "request" ? data.params : void 0;
|
|
3672
|
+
const chunk = data.type === CHUNK$1 ? data.chunk : data.type === "request" ? data.params : void 0;
|
|
3666
3673
|
if (!chunk) return;
|
|
3667
3674
|
if (!watchPeerEnd()) {
|
|
3668
3675
|
port.removeEventListener("message", watcher);
|
|
@@ -3697,7 +3704,7 @@ function receiveChunks(port, channelName, controller, touch, notice) {
|
|
|
3697
3704
|
}, { channelName });
|
|
3698
3705
|
const onChunk = (event) => {
|
|
3699
3706
|
const data = event.data;
|
|
3700
|
-
if (data?.type !== CHUNK || data.channelName !== channelName || !data.chunk) return;
|
|
3707
|
+
if (data?.type !== CHUNK$1 || data.channelName !== channelName || !data.chunk) return;
|
|
3701
3708
|
if (poison) return;
|
|
3702
3709
|
const agreement = portAgreement(port);
|
|
3703
3710
|
if (!agreement?.caps.has("pipeline")) {
|
|
@@ -3789,12 +3796,6 @@ async function sendChunks(port, channelName, output, { maxMessageSize, log }, si
|
|
|
3789
3796
|
const producer = output;
|
|
3790
3797
|
const returnProducer = () => void Promise.resolve(producer.return?.()).catch(() => {});
|
|
3791
3798
|
if (framed !== output) signal.addEventListener("abort", returnProducer, { once: true });
|
|
3792
|
-
let onAborted = () => {};
|
|
3793
|
-
const aborted = new Promise((resolve) => {
|
|
3794
|
-
onAborted = () => resolve();
|
|
3795
|
-
});
|
|
3796
|
-
if (signal.aborted) onAborted();
|
|
3797
|
-
else signal.addEventListener("abort", onAborted, { once: true });
|
|
3798
3799
|
try {
|
|
3799
3800
|
await sendIterator(async ({ done, value, error }) => {
|
|
3800
3801
|
if (signal.aborted) return;
|
|
@@ -3810,13 +3811,13 @@ async function sendChunks(port, channelName, output, { maxMessageSize, log }, si
|
|
|
3810
3811
|
});
|
|
3811
3812
|
if (mayPipeline(port)) {
|
|
3812
3813
|
port.postMessage({
|
|
3813
|
-
type: CHUNK,
|
|
3814
|
+
type: CHUNK$1,
|
|
3814
3815
|
channelName,
|
|
3815
3816
|
chunk
|
|
3816
3817
|
});
|
|
3817
3818
|
touch();
|
|
3818
3819
|
if (done && !error) onSent();
|
|
3819
|
-
if (portBufferedAmount(port) > 0) await
|
|
3820
|
+
if (portBufferedAmount(port) > 0) await whenReadyOrAborted(port, signal);
|
|
3820
3821
|
return;
|
|
3821
3822
|
}
|
|
3822
3823
|
await callPort(port, chunk, {
|
|
@@ -3832,10 +3833,25 @@ async function sendChunks(port, channelName, output, { maxMessageSize, log }, si
|
|
|
3832
3833
|
throw err;
|
|
3833
3834
|
} finally {
|
|
3834
3835
|
signal.removeEventListener("abort", returnProducer);
|
|
3835
|
-
signal.removeEventListener("abort", onAborted);
|
|
3836
3836
|
}
|
|
3837
3837
|
}
|
|
3838
3838
|
/**
|
|
3839
|
+
* A pipelined sender waits only for room in the window, or for the abort. The
|
|
3840
|
+
* abort listener lives for this one wait: a promise held for the whole stream
|
|
3841
|
+
* would keep one reaction per wait until the stream ends.
|
|
3842
|
+
*/
|
|
3843
|
+
function whenReadyOrAborted(port, signal) {
|
|
3844
|
+
if (signal.aborted) return Promise.resolve();
|
|
3845
|
+
return new Promise((resolve) => {
|
|
3846
|
+
const settle = () => {
|
|
3847
|
+
signal.removeEventListener("abort", settle);
|
|
3848
|
+
resolve();
|
|
3849
|
+
};
|
|
3850
|
+
signal.addEventListener("abort", settle, { once: true });
|
|
3851
|
+
whenPortReady(port).then(settle, settle);
|
|
3852
|
+
});
|
|
3853
|
+
}
|
|
3854
|
+
/**
|
|
3839
3855
|
* One virtual port.
|
|
3840
3856
|
*
|
|
3841
3857
|
* `deliver` and `markClosed` are deliberately not on `port`: the consumer holds
|
|
@@ -4833,7 +4849,12 @@ function trackedLink(send, release) {
|
|
|
4833
4849
|
finish();
|
|
4834
4850
|
return response;
|
|
4835
4851
|
}
|
|
4836
|
-
|
|
4852
|
+
failers.delete(fail);
|
|
4853
|
+
const body = guardBody(response.body, finish, request);
|
|
4854
|
+
fail = body.fail;
|
|
4855
|
+
if (closed) fail(lostReason);
|
|
4856
|
+
else if (!finished) failers.add(fail);
|
|
4857
|
+
return new Response(body.stream, {
|
|
4837
4858
|
status: response.status,
|
|
4838
4859
|
statusText: response.statusText,
|
|
4839
4860
|
headers: response.headers
|
|
@@ -4852,56 +4873,62 @@ function trackedLink(send, release) {
|
|
|
4852
4873
|
return asyncDisposable(link, () => link.close());
|
|
4853
4874
|
}
|
|
4854
4875
|
/**
|
|
4855
|
-
* A response body that reports its end (done, cancelled, failed or aborted)
|
|
4856
|
-
*
|
|
4857
|
-
*
|
|
4858
|
-
*
|
|
4876
|
+
* A response body that reports its end (done, cancelled, failed or aborted).
|
|
4877
|
+
* `fail(error)` ends it with `error` at once — the link calls it when it is lost
|
|
4878
|
+
* mid-stream. An abort of the request's signal does the same with the signal's
|
|
4879
|
+
* reason, read or not: the exchange is over (the layer below has given its port
|
|
4880
|
+
* back), so the request leaves `inflight` then. A read waits on the reader
|
|
4881
|
+
* alone, so nothing outlives the chunk it brings.
|
|
4859
4882
|
*/
|
|
4860
|
-
function guardBody(body,
|
|
4883
|
+
function guardBody(body, finish, request) {
|
|
4884
|
+
const keep = { request };
|
|
4885
|
+
const signal = request.signal ?? void 0;
|
|
4861
4886
|
const reader = body.getReader();
|
|
4862
4887
|
let controller;
|
|
4863
4888
|
let ended = false;
|
|
4864
4889
|
const end = () => {
|
|
4865
4890
|
ended = true;
|
|
4866
4891
|
signal?.removeEventListener("abort", onAbort);
|
|
4892
|
+
keep.request = void 0;
|
|
4867
4893
|
finish();
|
|
4868
4894
|
};
|
|
4869
|
-
const
|
|
4895
|
+
const fail = (error) => {
|
|
4870
4896
|
if (ended) return;
|
|
4871
4897
|
end();
|
|
4872
4898
|
reader.cancel().catch(() => {});
|
|
4873
4899
|
try {
|
|
4874
|
-
controller.error(
|
|
4900
|
+
controller.error(error);
|
|
4875
4901
|
} catch {}
|
|
4876
4902
|
};
|
|
4877
|
-
|
|
4878
|
-
|
|
4879
|
-
|
|
4880
|
-
|
|
4881
|
-
|
|
4882
|
-
|
|
4883
|
-
|
|
4884
|
-
|
|
4885
|
-
|
|
4886
|
-
|
|
4887
|
-
|
|
4888
|
-
|
|
4889
|
-
|
|
4890
|
-
|
|
4903
|
+
const onAbort = () => fail(abortError(signal));
|
|
4904
|
+
return {
|
|
4905
|
+
stream: new ReadableStream({
|
|
4906
|
+
start(c) {
|
|
4907
|
+
controller = c;
|
|
4908
|
+
if (signal?.aborted) onAbort();
|
|
4909
|
+
else signal?.addEventListener("abort", onAbort, { once: true });
|
|
4910
|
+
},
|
|
4911
|
+
async pull(controller) {
|
|
4912
|
+
try {
|
|
4913
|
+
const { done, value } = await reader.read();
|
|
4914
|
+
if (ended) return;
|
|
4915
|
+
if (done) {
|
|
4916
|
+
end();
|
|
4917
|
+
controller.close();
|
|
4918
|
+
return;
|
|
4919
|
+
}
|
|
4920
|
+
controller.enqueue(value);
|
|
4921
|
+
} catch (error) {
|
|
4922
|
+
fail(error);
|
|
4891
4923
|
}
|
|
4892
|
-
|
|
4893
|
-
|
|
4894
|
-
if (ended) return;
|
|
4924
|
+
},
|
|
4925
|
+
cancel(why) {
|
|
4895
4926
|
end();
|
|
4896
|
-
reader.cancel().catch(() => {});
|
|
4897
|
-
controller.error(reason() ?? error);
|
|
4927
|
+
setTimeout(() => void reader.cancel(why).catch(() => {}), 0);
|
|
4898
4928
|
}
|
|
4899
|
-
},
|
|
4900
|
-
|
|
4901
|
-
|
|
4902
|
-
await reader.cancel(why).catch(() => {});
|
|
4903
|
-
}
|
|
4904
|
-
});
|
|
4929
|
+
}),
|
|
4930
|
+
fail
|
|
4931
|
+
};
|
|
4905
4932
|
}
|
|
4906
4933
|
/** The signal's reason as an `Error` (`AbortError` when it gave none). */
|
|
4907
4934
|
function abortError(signal) {
|
|
@@ -5104,20 +5131,24 @@ function postFrame(port, frame) {
|
|
|
5104
5131
|
function messageSize(data) {
|
|
5105
5132
|
return typeof data === "string" ? utf8Length(data) : data.byteLength;
|
|
5106
5133
|
}
|
|
5107
|
-
|
|
5134
|
+
const encoder = new TextEncoder();
|
|
5135
|
+
/** Characters encoded per `encodeInto` call: at most 3 bytes each, so the scratch stays at 96 KiB. */
|
|
5136
|
+
const CHUNK = 32768;
|
|
5137
|
+
const scratch = new Uint8Array(CHUNK * 3);
|
|
5138
|
+
/**
|
|
5139
|
+
* The UTF-8 length of `text`, as `TextEncoder` would encode it (a lone surrogate counts as the 3
|
|
5140
|
+
* bytes of U+FFFD). Every message is measured on both ends (`bufferedAmount` and the byte acks), so
|
|
5141
|
+
* this runs natively: `encodeInto` a reused buffer, a chunk at a time, never splitting a surrogate
|
|
5142
|
+
* pair across two chunks. A loop over the characters in JavaScript took about 30 times as long.
|
|
5143
|
+
*/
|
|
5108
5144
|
function utf8Length(text) {
|
|
5109
5145
|
let length = 0;
|
|
5110
|
-
for (let
|
|
5111
|
-
|
|
5112
|
-
|
|
5113
|
-
|
|
5114
|
-
|
|
5115
|
-
|
|
5116
|
-
if (next >= 56320 && next <= 57343) {
|
|
5117
|
-
length += 4;
|
|
5118
|
-
i++;
|
|
5119
|
-
} else length += 3;
|
|
5120
|
-
} else length += 3;
|
|
5146
|
+
for (let start = 0; start < text.length;) {
|
|
5147
|
+
let end = Math.min(start + CHUNK, text.length);
|
|
5148
|
+
const last = text.charCodeAt(end - 1);
|
|
5149
|
+
if (end < text.length && last >= 55296 && last <= 56319) end--;
|
|
5150
|
+
length += encoder.encodeInto(text.slice(start, end), scratch).written;
|
|
5151
|
+
start = end;
|
|
5121
5152
|
}
|
|
5122
5153
|
return length;
|
|
5123
5154
|
}
|
|
@@ -8073,7 +8104,10 @@ function serveHttpInWorker(handler, options = {}) {
|
|
|
8073
8104
|
let WebSocketClass;
|
|
8074
8105
|
return {
|
|
8075
8106
|
fetch(input, init) {
|
|
8076
|
-
const request = input instanceof Request && init === void 0 ? input : new Request(input instanceof Request ? input : new URL(`${input}`, baseUrl()),
|
|
8107
|
+
const request = input instanceof Request && init === void 0 ? input : new Request(input instanceof Request ? input : new URL(`${input}`, baseUrl()), {
|
|
8108
|
+
...init,
|
|
8109
|
+
signal: init && "signal" in init ? init.signal : input instanceof Request ? input.signal : void 0
|
|
8110
|
+
});
|
|
8077
8111
|
return endpoint.fetch(request);
|
|
8078
8112
|
},
|
|
8079
8113
|
connectWebSocket,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http-link.d.ts","sourceRoot":"","sources":["../../src/link/http-link.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,kBAAkB,uBAAuB,CAAC;AAEvD,MAAM,WAAW,eAAe;IAC9B;;;;OAIG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;;OAKG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;;;;;;OAQG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAKD,iEAAiE;AACjE,MAAM,WAAW,QAAQ;IACvB,0EAA0E;IAC1E,IAAI,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC1C;;;OAGG;IACH,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,2CAA2C;IAC3C,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1B;;;OAGG;IACH,KAAK,CAAC,MAAM,CAAC,EAAE,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACrC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;CAC1B;AAED;;;;GAIG;AACH,qBAAa,aAAc,SAAQ,KAAK;IACtC,YAAY,OAAO,SAAuD,EAGzE;CACF;AASD,qEAAqE;AACrE,wBAAsB,eAAe,CACnC,IAAI,EAAE,WAAW,EACjB,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAiC,EAAE,GAAE,eAAoB,GACnF,OAAO,CAAC,QAAQ,CAAC,CAcnB;AAED;;;;GAIG;AACH,wBAAsB,aAAa,CACjC,IAAI,EAAE,WAAW,EACjB,OAAO,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,EAC3D,EAAE,aAAa,EAAE,QAAQ,EAAE,aAAa,EAAE,GAAE,eAAoB,GAC/D,OAAO,CAAC,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,CAiB9B;AAED;;;GAGG;AACH,wBAAgB,WAAW,CACzB,IAAI,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,EAC7C,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,GAClC,QAAQ,
|
|
1
|
+
{"version":3,"file":"http-link.d.ts","sourceRoot":"","sources":["../../src/link/http-link.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,kBAAkB,uBAAuB,CAAC;AAEvD,MAAM,WAAW,eAAe;IAC9B;;;;OAIG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;;OAKG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;;;;;;OAQG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAKD,iEAAiE;AACjE,MAAM,WAAW,QAAQ;IACvB,0EAA0E;IAC1E,IAAI,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC1C;;;OAGG;IACH,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,2CAA2C;IAC3C,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1B;;;OAGG;IACH,KAAK,CAAC,MAAM,CAAC,EAAE,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACrC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;CAC1B;AAED;;;;GAIG;AACH,qBAAa,aAAc,SAAQ,KAAK;IACtC,YAAY,OAAO,SAAuD,EAGzE;CACF;AASD,qEAAqE;AACrE,wBAAsB,eAAe,CACnC,IAAI,EAAE,WAAW,EACjB,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAiC,EAAE,GAAE,eAAoB,GACnF,OAAO,CAAC,QAAQ,CAAC,CAcnB;AAED;;;;GAIG;AACH,wBAAsB,aAAa,CACjC,IAAI,EAAE,WAAW,EACjB,OAAO,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,EAC3D,EAAE,aAAa,EAAE,QAAQ,EAAE,aAAa,EAAE,GAAE,eAAoB,GAC/D,OAAO,CAAC,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,CAiB9B;AAED;;;GAGG;AACH,wBAAgB,WAAW,CACzB,IAAI,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,EAC7C,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,GAClC,QAAQ,CA4EV"}
|
package/dist/relay-sw.js
CHANGED
|
@@ -1138,7 +1138,10 @@
|
|
|
1138
1138
|
}
|
|
1139
1139
|
const onAbort = () => void release();
|
|
1140
1140
|
signal?.addEventListener("abort", onAbort, { once: true });
|
|
1141
|
-
|
|
1141
|
+
options.keepAlive;
|
|
1142
|
+
drain(output).finally(() => {
|
|
1143
|
+
signal?.removeEventListener("abort", onAbort);
|
|
1144
|
+
});
|
|
1142
1145
|
};
|
|
1143
1146
|
let decoded;
|
|
1144
1147
|
try {
|
|
@@ -1388,7 +1391,8 @@
|
|
|
1388
1391
|
}
|
|
1389
1392
|
const { envelope, body: respBody, release, finish } = await httpFetch(call, env, body, {
|
|
1390
1393
|
...options,
|
|
1391
|
-
signal: request.signal ?? void 0
|
|
1394
|
+
signal: request.signal ?? void 0,
|
|
1395
|
+
keepAlive: request
|
|
1392
1396
|
});
|
|
1393
1397
|
const responseInit = {
|
|
1394
1398
|
status: envelope.status,
|
|
@@ -1400,7 +1404,7 @@
|
|
|
1400
1404
|
else await release?.();
|
|
1401
1405
|
return new Response(null, responseInit);
|
|
1402
1406
|
}
|
|
1403
|
-
return new Response(responseBody(respBody, request
|
|
1407
|
+
return new Response(responseBody(respBody, request, release), responseInit);
|
|
1404
1408
|
}
|
|
1405
1409
|
/**
|
|
1406
1410
|
* How long a cancelled body waits for the read in flight before it abandons the call anyway.
|
|
@@ -1423,7 +1427,9 @@
|
|
|
1423
1427
|
* A cancel abandons the call too — unless the read in flight comes back with the
|
|
1424
1428
|
* body's end, which finishes it instead (see `cancel`).
|
|
1425
1429
|
*/
|
|
1426
|
-
function responseBody(body,
|
|
1430
|
+
function responseBody(body, request, release) {
|
|
1431
|
+
const keep = { request };
|
|
1432
|
+
const signal = request.signal ?? void 0;
|
|
1427
1433
|
const it = body[Symbol.asyncIterator]();
|
|
1428
1434
|
let controller;
|
|
1429
1435
|
let ended = false;
|
|
@@ -1431,6 +1437,7 @@
|
|
|
1431
1437
|
const end = () => {
|
|
1432
1438
|
ended = true;
|
|
1433
1439
|
signal?.removeEventListener("abort", onAbort);
|
|
1440
|
+
keep.request = void 0;
|
|
1434
1441
|
};
|
|
1435
1442
|
const onAbort = () => {
|
|
1436
1443
|
if (ended) return;
|
|
@@ -2394,12 +2401,6 @@
|
|
|
2394
2401
|
const producer = output;
|
|
2395
2402
|
const returnProducer = () => void Promise.resolve(producer.return?.()).catch(() => {});
|
|
2396
2403
|
if (framed !== output) signal.addEventListener("abort", returnProducer, { once: true });
|
|
2397
|
-
let onAborted = () => {};
|
|
2398
|
-
const aborted = new Promise((resolve) => {
|
|
2399
|
-
onAborted = () => resolve();
|
|
2400
|
-
});
|
|
2401
|
-
if (signal.aborted) onAborted();
|
|
2402
|
-
else signal.addEventListener("abort", onAborted, { once: true });
|
|
2403
2404
|
try {
|
|
2404
2405
|
await sendIterator(async ({ done, value, error }) => {
|
|
2405
2406
|
if (signal.aborted) return;
|
|
@@ -2421,7 +2422,7 @@
|
|
|
2421
2422
|
});
|
|
2422
2423
|
touch();
|
|
2423
2424
|
if (done && !error) onSent();
|
|
2424
|
-
if (portBufferedAmount(port) > 0) await
|
|
2425
|
+
if (portBufferedAmount(port) > 0) await whenReadyOrAborted(port, signal);
|
|
2425
2426
|
return;
|
|
2426
2427
|
}
|
|
2427
2428
|
await callPort(port, chunk, {
|
|
@@ -2437,10 +2438,25 @@
|
|
|
2437
2438
|
throw err;
|
|
2438
2439
|
} finally {
|
|
2439
2440
|
signal.removeEventListener("abort", returnProducer);
|
|
2440
|
-
signal.removeEventListener("abort", onAborted);
|
|
2441
2441
|
}
|
|
2442
2442
|
}
|
|
2443
2443
|
/**
|
|
2444
|
+
* A pipelined sender waits only for room in the window, or for the abort. The
|
|
2445
|
+
* abort listener lives for this one wait: a promise held for the whole stream
|
|
2446
|
+
* would keep one reaction per wait until the stream ends.
|
|
2447
|
+
*/
|
|
2448
|
+
function whenReadyOrAborted(port, signal) {
|
|
2449
|
+
if (signal.aborted) return Promise.resolve();
|
|
2450
|
+
return new Promise((resolve) => {
|
|
2451
|
+
const settle = () => {
|
|
2452
|
+
signal.removeEventListener("abort", settle);
|
|
2453
|
+
resolve();
|
|
2454
|
+
};
|
|
2455
|
+
signal.addEventListener("abort", settle, { once: true });
|
|
2456
|
+
whenPortReady(port).then(settle, settle);
|
|
2457
|
+
});
|
|
2458
|
+
}
|
|
2459
|
+
/**
|
|
2444
2460
|
* One virtual port.
|
|
2445
2461
|
*
|
|
2446
2462
|
* `deliver` and `markClosed` are deliberately not on `port`: the consumer holds
|
|
@@ -3366,7 +3382,12 @@
|
|
|
3366
3382
|
finish();
|
|
3367
3383
|
return response;
|
|
3368
3384
|
}
|
|
3369
|
-
|
|
3385
|
+
failers.delete(fail);
|
|
3386
|
+
const body = guardBody(response.body, finish, request);
|
|
3387
|
+
fail = body.fail;
|
|
3388
|
+
if (closed) fail(lostReason);
|
|
3389
|
+
else if (!finished) failers.add(fail);
|
|
3390
|
+
return new Response(body.stream, {
|
|
3370
3391
|
status: response.status,
|
|
3371
3392
|
statusText: response.statusText,
|
|
3372
3393
|
headers: response.headers
|
|
@@ -3385,56 +3406,62 @@
|
|
|
3385
3406
|
return asyncDisposable(link, () => link.close());
|
|
3386
3407
|
}
|
|
3387
3408
|
/**
|
|
3388
|
-
* A response body that reports its end (done, cancelled, failed or aborted)
|
|
3389
|
-
*
|
|
3390
|
-
*
|
|
3391
|
-
*
|
|
3409
|
+
* A response body that reports its end (done, cancelled, failed or aborted).
|
|
3410
|
+
* `fail(error)` ends it with `error` at once — the link calls it when it is lost
|
|
3411
|
+
* mid-stream. An abort of the request's signal does the same with the signal's
|
|
3412
|
+
* reason, read or not: the exchange is over (the layer below has given its port
|
|
3413
|
+
* back), so the request leaves `inflight` then. A read waits on the reader
|
|
3414
|
+
* alone, so nothing outlives the chunk it brings.
|
|
3392
3415
|
*/
|
|
3393
|
-
function guardBody(body,
|
|
3416
|
+
function guardBody(body, finish, request) {
|
|
3417
|
+
const keep = { request };
|
|
3418
|
+
const signal = request.signal ?? void 0;
|
|
3394
3419
|
const reader = body.getReader();
|
|
3395
3420
|
let controller;
|
|
3396
3421
|
let ended = false;
|
|
3397
3422
|
const end = () => {
|
|
3398
3423
|
ended = true;
|
|
3399
3424
|
signal?.removeEventListener("abort", onAbort);
|
|
3425
|
+
keep.request = void 0;
|
|
3400
3426
|
finish();
|
|
3401
3427
|
};
|
|
3402
|
-
const
|
|
3428
|
+
const fail = (error) => {
|
|
3403
3429
|
if (ended) return;
|
|
3404
3430
|
end();
|
|
3405
3431
|
reader.cancel().catch(() => {});
|
|
3406
3432
|
try {
|
|
3407
|
-
controller.error(
|
|
3433
|
+
controller.error(error);
|
|
3408
3434
|
} catch {}
|
|
3409
3435
|
};
|
|
3410
|
-
|
|
3411
|
-
|
|
3412
|
-
|
|
3413
|
-
|
|
3414
|
-
|
|
3415
|
-
|
|
3416
|
-
|
|
3417
|
-
|
|
3418
|
-
|
|
3419
|
-
|
|
3420
|
-
|
|
3421
|
-
|
|
3422
|
-
|
|
3423
|
-
|
|
3436
|
+
const onAbort = () => fail(abortError(signal));
|
|
3437
|
+
return {
|
|
3438
|
+
stream: new ReadableStream({
|
|
3439
|
+
start(c) {
|
|
3440
|
+
controller = c;
|
|
3441
|
+
if (signal?.aborted) onAbort();
|
|
3442
|
+
else signal?.addEventListener("abort", onAbort, { once: true });
|
|
3443
|
+
},
|
|
3444
|
+
async pull(controller) {
|
|
3445
|
+
try {
|
|
3446
|
+
const { done, value } = await reader.read();
|
|
3447
|
+
if (ended) return;
|
|
3448
|
+
if (done) {
|
|
3449
|
+
end();
|
|
3450
|
+
controller.close();
|
|
3451
|
+
return;
|
|
3452
|
+
}
|
|
3453
|
+
controller.enqueue(value);
|
|
3454
|
+
} catch (error) {
|
|
3455
|
+
fail(error);
|
|
3424
3456
|
}
|
|
3425
|
-
|
|
3426
|
-
|
|
3427
|
-
if (ended) return;
|
|
3457
|
+
},
|
|
3458
|
+
cancel(why) {
|
|
3428
3459
|
end();
|
|
3429
|
-
reader.cancel().catch(() => {});
|
|
3430
|
-
controller.error(reason() ?? error);
|
|
3460
|
+
setTimeout(() => void reader.cancel(why).catch(() => {}), 0);
|
|
3431
3461
|
}
|
|
3432
|
-
},
|
|
3433
|
-
|
|
3434
|
-
|
|
3435
|
-
await reader.cancel(why).catch(() => {});
|
|
3436
|
-
}
|
|
3437
|
-
});
|
|
3462
|
+
}),
|
|
3463
|
+
fail
|
|
3464
|
+
};
|
|
3438
3465
|
}
|
|
3439
3466
|
/** The signal's reason as an `Error` (`AbortError` when it gave none). */
|
|
3440
3467
|
function abortError(signal) {
|