capnweb 0.0.0-d21e4ca → 0.0.0-e0d2f1d
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/README.md +18 -2
- package/dist/index-workers.cjs +816 -40
- package/dist/index-workers.cjs.map +1 -1
- package/dist/index-workers.js +816 -40
- package/dist/index-workers.js.map +1 -1
- package/dist/index.cjs +816 -40
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +816 -40
- package/dist/index.js.map +1 -1
- package/package.json +8 -8
package/dist/index.cjs
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
// src/symbols.ts
|
|
4
|
-
var WORKERS_MODULE_SYMBOL = Symbol("workers-module");
|
|
4
|
+
var WORKERS_MODULE_SYMBOL = /* @__PURE__ */ Symbol("workers-module");
|
|
5
5
|
|
|
6
6
|
// src/core.ts
|
|
7
7
|
if (!Symbol.dispose) {
|
|
8
|
-
Symbol.dispose = Symbol.for("dispose");
|
|
8
|
+
Symbol.dispose = /* @__PURE__ */ Symbol.for("dispose");
|
|
9
9
|
}
|
|
10
10
|
if (!Symbol.asyncDispose) {
|
|
11
|
-
Symbol.asyncDispose = Symbol.for("asyncDispose");
|
|
11
|
+
Symbol.asyncDispose = /* @__PURE__ */ Symbol.for("asyncDispose");
|
|
12
12
|
}
|
|
13
13
|
if (!Promise.withResolvers) {
|
|
14
14
|
Promise.withResolvers = function() {
|
|
@@ -24,6 +24,8 @@ if (!Promise.withResolvers) {
|
|
|
24
24
|
var workersModule = globalThis[WORKERS_MODULE_SYMBOL];
|
|
25
25
|
var RpcTarget = workersModule ? workersModule.RpcTarget : class {
|
|
26
26
|
};
|
|
27
|
+
var AsyncFunction = (async function() {
|
|
28
|
+
}).constructor;
|
|
27
29
|
function typeForRpc(value) {
|
|
28
30
|
switch (typeof value) {
|
|
29
31
|
case "boolean":
|
|
@@ -48,6 +50,7 @@ function typeForRpc(value) {
|
|
|
48
50
|
case Object.prototype:
|
|
49
51
|
return "object";
|
|
50
52
|
case Function.prototype:
|
|
53
|
+
case AsyncFunction.prototype:
|
|
51
54
|
return "function";
|
|
52
55
|
case Array.prototype:
|
|
53
56
|
return "array";
|
|
@@ -55,6 +58,16 @@ function typeForRpc(value) {
|
|
|
55
58
|
return "date";
|
|
56
59
|
case Uint8Array.prototype:
|
|
57
60
|
return "bytes";
|
|
61
|
+
case WritableStream.prototype:
|
|
62
|
+
return "writable";
|
|
63
|
+
case ReadableStream.prototype:
|
|
64
|
+
return "readable";
|
|
65
|
+
case Headers.prototype:
|
|
66
|
+
return "headers";
|
|
67
|
+
case Request.prototype:
|
|
68
|
+
return "request";
|
|
69
|
+
case Response.prototype:
|
|
70
|
+
return "response";
|
|
58
71
|
// TODO: All other structured clone types.
|
|
59
72
|
case RpcStub.prototype:
|
|
60
73
|
return "stub";
|
|
@@ -82,7 +95,34 @@ function mapNotLoaded() {
|
|
|
82
95
|
throw new Error("RPC map() implementation was not loaded.");
|
|
83
96
|
}
|
|
84
97
|
var mapImpl = { applyMap: mapNotLoaded, sendMap: mapNotLoaded };
|
|
98
|
+
function streamNotLoaded() {
|
|
99
|
+
throw new Error("Stream implementation was not loaded.");
|
|
100
|
+
}
|
|
101
|
+
var streamImpl = {
|
|
102
|
+
createWritableStreamHook: streamNotLoaded,
|
|
103
|
+
createWritableStreamFromHook: streamNotLoaded,
|
|
104
|
+
createReadableStreamHook: streamNotLoaded
|
|
105
|
+
};
|
|
85
106
|
var StubHook = class {
|
|
107
|
+
// Like call(), but designed for streaming calls (e.g. WritableStream writes). Returns:
|
|
108
|
+
// - promise: A Promise<void> for the completion of the call.
|
|
109
|
+
// - size: If the call was remote, the byte size of the serialized message. For local calls,
|
|
110
|
+
// undefined is returned, indicating the caller should await the promise to serialize writes
|
|
111
|
+
// (no overlapping).
|
|
112
|
+
stream(path, args) {
|
|
113
|
+
let hook = this.call(path, args);
|
|
114
|
+
let pulled = hook.pull();
|
|
115
|
+
let promise;
|
|
116
|
+
if (pulled instanceof Promise) {
|
|
117
|
+
promise = pulled.then((p) => {
|
|
118
|
+
p.dispose();
|
|
119
|
+
});
|
|
120
|
+
} else {
|
|
121
|
+
pulled.dispose();
|
|
122
|
+
promise = Promise.resolve();
|
|
123
|
+
}
|
|
124
|
+
return { promise };
|
|
125
|
+
}
|
|
86
126
|
};
|
|
87
127
|
var ErrorStubHook = class extends StubHook {
|
|
88
128
|
constructor(error) {
|
|
@@ -131,7 +171,7 @@ function withCallInterceptor(interceptor, callback) {
|
|
|
131
171
|
doCall = oldValue;
|
|
132
172
|
}
|
|
133
173
|
}
|
|
134
|
-
var RAW_STUB = Symbol("realStub");
|
|
174
|
+
var RAW_STUB = /* @__PURE__ */ Symbol("realStub");
|
|
135
175
|
var PROXY_HANDLERS = {
|
|
136
176
|
apply(target, thisArg, argumentsList) {
|
|
137
177
|
let stub = target.raw;
|
|
@@ -307,10 +347,10 @@ async function pullPromise(promise) {
|
|
|
307
347
|
}
|
|
308
348
|
var RpcPayload = class _RpcPayload {
|
|
309
349
|
// Private constructor; use factory functions above to construct.
|
|
310
|
-
constructor(value, source,
|
|
350
|
+
constructor(value, source, hooks, promises) {
|
|
311
351
|
this.value = value;
|
|
312
352
|
this.source = source;
|
|
313
|
-
this.
|
|
353
|
+
this.hooks = hooks;
|
|
314
354
|
this.promises = promises;
|
|
315
355
|
}
|
|
316
356
|
// Create a payload from a value passed as params to an RPC from the app.
|
|
@@ -335,13 +375,13 @@ var RpcPayload = class _RpcPayload {
|
|
|
335
375
|
// stubs is transferred from the inputs to the outputs, hence if the output is disposed, the
|
|
336
376
|
// inputs should not be. (In case of exception, nothing is disposed, though.)
|
|
337
377
|
static fromArray(array) {
|
|
338
|
-
let
|
|
378
|
+
let hooks = [];
|
|
339
379
|
let promises = [];
|
|
340
380
|
let resultArray = [];
|
|
341
381
|
for (let payload of array) {
|
|
342
382
|
payload.ensureDeepCopied();
|
|
343
|
-
for (let
|
|
344
|
-
|
|
383
|
+
for (let hook of payload.hooks) {
|
|
384
|
+
hooks.push(hook);
|
|
345
385
|
}
|
|
346
386
|
for (let promise of payload.promises) {
|
|
347
387
|
if (promise.parent === payload) {
|
|
@@ -355,12 +395,12 @@ var RpcPayload = class _RpcPayload {
|
|
|
355
395
|
}
|
|
356
396
|
resultArray.push(payload.value);
|
|
357
397
|
}
|
|
358
|
-
return new _RpcPayload(resultArray, "owned",
|
|
398
|
+
return new _RpcPayload(resultArray, "owned", hooks, promises);
|
|
359
399
|
}
|
|
360
400
|
// Create a payload from a value parsed off the wire using Evaluator.evaluate().
|
|
361
401
|
//
|
|
362
|
-
// A payload is constructed with a null value and the given
|
|
363
|
-
// is expected to be filled in by the evaluator, and the
|
|
402
|
+
// A payload is constructed with a null value and the given hooks and promises arrays. The value
|
|
403
|
+
// is expected to be filled in by the evaluator, and the hooks and promises arrays are expected
|
|
364
404
|
// to be extended with stubs found during parsing. (This weird usage model is necessary so that
|
|
365
405
|
// if the root value turns out to be a promise, its `parent` in `promises` can be the payload
|
|
366
406
|
// object itself.)
|
|
@@ -368,8 +408,8 @@ var RpcPayload = class _RpcPayload {
|
|
|
368
408
|
// When done, the payload takes ownership of the final value and all the stubs within. It may
|
|
369
409
|
// modify the value in preparation for delivery, and may deliver the value directly to the app
|
|
370
410
|
// without copying.
|
|
371
|
-
static forEvaluate(
|
|
372
|
-
return new _RpcPayload(null, "owned",
|
|
411
|
+
static forEvaluate(hooks, promises) {
|
|
412
|
+
return new _RpcPayload(null, "owned", hooks, promises);
|
|
373
413
|
}
|
|
374
414
|
// Deep-copy the given value, including dup()ing all stubs.
|
|
375
415
|
//
|
|
@@ -391,14 +431,20 @@ var RpcPayload = class _RpcPayload {
|
|
|
391
431
|
return result;
|
|
392
432
|
}
|
|
393
433
|
// For `source === "return"` payloads only, this tracks any StubHooks created around RpcTargets
|
|
394
|
-
// found in the payload at the time that it is serialized (or deep-copied) for
|
|
395
|
-
// can make sure they are not disposed before the pipeline ends.
|
|
434
|
+
// or WritableStreams found in the payload at the time that it is serialized (or deep-copied) for
|
|
435
|
+
// return, so that we can make sure they are not disposed before the pipeline ends.
|
|
396
436
|
//
|
|
397
437
|
// This is initialized on first use.
|
|
398
438
|
rpcTargets;
|
|
399
439
|
// Get the StubHook representing the given RpcTarget found inside this payload.
|
|
400
440
|
getHookForRpcTarget(target, parent, dupStubs = true) {
|
|
401
441
|
if (this.source === "params") {
|
|
442
|
+
if (dupStubs) {
|
|
443
|
+
let dupable = target;
|
|
444
|
+
if (typeof dupable.dup === "function") {
|
|
445
|
+
target = dupable.dup();
|
|
446
|
+
}
|
|
447
|
+
}
|
|
402
448
|
return TargetStubHook.create(target, parent);
|
|
403
449
|
} else if (this.source === "return") {
|
|
404
450
|
let hook = this.rpcTargets?.get(target);
|
|
@@ -425,6 +471,64 @@ var RpcPayload = class _RpcPayload {
|
|
|
425
471
|
throw new Error("owned payload shouldn't contain raw RpcTargets");
|
|
426
472
|
}
|
|
427
473
|
}
|
|
474
|
+
// Get the StubHook representing the given WritableStream found inside this payload.
|
|
475
|
+
getHookForWritableStream(stream, parent, dupStubs = true) {
|
|
476
|
+
if (this.source === "params") {
|
|
477
|
+
return streamImpl.createWritableStreamHook(stream);
|
|
478
|
+
} else if (this.source === "return") {
|
|
479
|
+
let hook = this.rpcTargets?.get(stream);
|
|
480
|
+
if (hook) {
|
|
481
|
+
if (dupStubs) {
|
|
482
|
+
return hook.dup();
|
|
483
|
+
} else {
|
|
484
|
+
this.rpcTargets?.delete(stream);
|
|
485
|
+
return hook;
|
|
486
|
+
}
|
|
487
|
+
} else {
|
|
488
|
+
hook = streamImpl.createWritableStreamHook(stream);
|
|
489
|
+
if (dupStubs) {
|
|
490
|
+
if (!this.rpcTargets) {
|
|
491
|
+
this.rpcTargets = /* @__PURE__ */ new Map();
|
|
492
|
+
}
|
|
493
|
+
this.rpcTargets.set(stream, hook);
|
|
494
|
+
return hook.dup();
|
|
495
|
+
} else {
|
|
496
|
+
return hook;
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
} else {
|
|
500
|
+
throw new Error("owned payload shouldn't contain raw WritableStreams");
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
// Get the StubHook representing the given ReadableStream found inside this payload.
|
|
504
|
+
getHookForReadableStream(stream, parent, dupStubs = true) {
|
|
505
|
+
if (this.source === "params") {
|
|
506
|
+
return streamImpl.createReadableStreamHook(stream);
|
|
507
|
+
} else if (this.source === "return") {
|
|
508
|
+
let hook = this.rpcTargets?.get(stream);
|
|
509
|
+
if (hook) {
|
|
510
|
+
if (dupStubs) {
|
|
511
|
+
return hook.dup();
|
|
512
|
+
} else {
|
|
513
|
+
this.rpcTargets?.delete(stream);
|
|
514
|
+
return hook;
|
|
515
|
+
}
|
|
516
|
+
} else {
|
|
517
|
+
hook = streamImpl.createReadableStreamHook(stream);
|
|
518
|
+
if (dupStubs) {
|
|
519
|
+
if (!this.rpcTargets) {
|
|
520
|
+
this.rpcTargets = /* @__PURE__ */ new Map();
|
|
521
|
+
}
|
|
522
|
+
this.rpcTargets.set(stream, hook);
|
|
523
|
+
return hook.dup();
|
|
524
|
+
} else {
|
|
525
|
+
return hook;
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
} else {
|
|
529
|
+
throw new Error("owned payload shouldn't contain raw ReadableStreams");
|
|
530
|
+
}
|
|
531
|
+
}
|
|
428
532
|
deepCopy(value, oldParent, property, parent, dupStubs, owner) {
|
|
429
533
|
let kind = typeForRpc(value);
|
|
430
534
|
switch (kind) {
|
|
@@ -468,22 +572,21 @@ var RpcPayload = class _RpcPayload {
|
|
|
468
572
|
this.promises.push({ parent, property, promise });
|
|
469
573
|
return promise;
|
|
470
574
|
} else {
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
return newStub;
|
|
575
|
+
this.hooks.push(hook);
|
|
576
|
+
return new RpcStub(hook);
|
|
474
577
|
}
|
|
475
578
|
}
|
|
476
579
|
case "function":
|
|
477
580
|
case "rpc-target": {
|
|
478
581
|
let target = value;
|
|
479
|
-
let
|
|
582
|
+
let hook;
|
|
480
583
|
if (owner) {
|
|
481
|
-
|
|
584
|
+
hook = owner.getHookForRpcTarget(target, oldParent, dupStubs);
|
|
482
585
|
} else {
|
|
483
|
-
|
|
586
|
+
hook = TargetStubHook.create(target, oldParent);
|
|
484
587
|
}
|
|
485
|
-
this.
|
|
486
|
-
return
|
|
588
|
+
this.hooks.push(hook);
|
|
589
|
+
return new RpcStub(hook);
|
|
487
590
|
}
|
|
488
591
|
case "rpc-thenable": {
|
|
489
592
|
let target = value;
|
|
@@ -496,6 +599,44 @@ var RpcPayload = class _RpcPayload {
|
|
|
496
599
|
this.promises.push({ parent, property, promise });
|
|
497
600
|
return promise;
|
|
498
601
|
}
|
|
602
|
+
case "writable": {
|
|
603
|
+
let stream = value;
|
|
604
|
+
let hook;
|
|
605
|
+
if (owner) {
|
|
606
|
+
hook = owner.getHookForWritableStream(stream, oldParent, dupStubs);
|
|
607
|
+
} else {
|
|
608
|
+
hook = streamImpl.createWritableStreamHook(stream);
|
|
609
|
+
}
|
|
610
|
+
this.hooks.push(hook);
|
|
611
|
+
return stream;
|
|
612
|
+
}
|
|
613
|
+
case "readable": {
|
|
614
|
+
let stream = value;
|
|
615
|
+
let hook;
|
|
616
|
+
if (owner) {
|
|
617
|
+
hook = owner.getHookForReadableStream(stream, oldParent, dupStubs);
|
|
618
|
+
} else {
|
|
619
|
+
hook = streamImpl.createReadableStreamHook(stream);
|
|
620
|
+
}
|
|
621
|
+
this.hooks.push(hook);
|
|
622
|
+
return stream;
|
|
623
|
+
}
|
|
624
|
+
case "headers":
|
|
625
|
+
return new Headers(value);
|
|
626
|
+
case "request": {
|
|
627
|
+
let req = value;
|
|
628
|
+
if (req.body) {
|
|
629
|
+
this.deepCopy(req.body, req, "body", req, dupStubs, owner);
|
|
630
|
+
}
|
|
631
|
+
return new Request(req);
|
|
632
|
+
}
|
|
633
|
+
case "response": {
|
|
634
|
+
let resp = value;
|
|
635
|
+
if (resp.body) {
|
|
636
|
+
this.deepCopy(resp.body, resp, "body", resp, dupStubs, owner);
|
|
637
|
+
}
|
|
638
|
+
return new Response(resp.body, resp);
|
|
639
|
+
}
|
|
499
640
|
default:
|
|
500
641
|
throw new Error("unreachable");
|
|
501
642
|
}
|
|
@@ -505,12 +646,12 @@ var RpcPayload = class _RpcPayload {
|
|
|
505
646
|
ensureDeepCopied() {
|
|
506
647
|
if (this.source !== "owned") {
|
|
507
648
|
let dupStubs = this.source === "params";
|
|
508
|
-
this.
|
|
649
|
+
this.hooks = [];
|
|
509
650
|
this.promises = [];
|
|
510
651
|
try {
|
|
511
652
|
this.value = this.deepCopy(this.value, void 0, "value", this, dupStubs, this);
|
|
512
653
|
} catch (err) {
|
|
513
|
-
this.
|
|
654
|
+
this.hooks = void 0;
|
|
514
655
|
this.promises = void 0;
|
|
515
656
|
throw err;
|
|
516
657
|
}
|
|
@@ -613,7 +754,7 @@ var RpcPayload = class _RpcPayload {
|
|
|
613
754
|
}
|
|
614
755
|
dispose() {
|
|
615
756
|
if (this.source === "owned") {
|
|
616
|
-
this.
|
|
757
|
+
this.hooks.forEach((hook) => hook.dispose());
|
|
617
758
|
this.promises.forEach((promise) => promise.promise[Symbol.dispose]());
|
|
618
759
|
} else if (this.source === "return") {
|
|
619
760
|
this.disposeImpl(this.value, void 0);
|
|
@@ -622,7 +763,7 @@ var RpcPayload = class _RpcPayload {
|
|
|
622
763
|
}
|
|
623
764
|
} else ;
|
|
624
765
|
this.source = "owned";
|
|
625
|
-
this.
|
|
766
|
+
this.hooks = [];
|
|
626
767
|
this.promises = [];
|
|
627
768
|
}
|
|
628
769
|
// Recursive dispose, called only when `source` is "return".
|
|
@@ -675,6 +816,40 @@ var RpcPayload = class _RpcPayload {
|
|
|
675
816
|
}
|
|
676
817
|
case "rpc-thenable":
|
|
677
818
|
return;
|
|
819
|
+
case "headers":
|
|
820
|
+
return;
|
|
821
|
+
case "request": {
|
|
822
|
+
let req = value;
|
|
823
|
+
if (req.body) this.disposeImpl(req.body, req);
|
|
824
|
+
return;
|
|
825
|
+
}
|
|
826
|
+
case "response": {
|
|
827
|
+
let resp = value;
|
|
828
|
+
if (resp.body) this.disposeImpl(resp.body, resp);
|
|
829
|
+
return;
|
|
830
|
+
}
|
|
831
|
+
case "writable": {
|
|
832
|
+
let stream = value;
|
|
833
|
+
let hook = this.rpcTargets?.get(stream);
|
|
834
|
+
if (hook) {
|
|
835
|
+
this.rpcTargets.delete(stream);
|
|
836
|
+
} else {
|
|
837
|
+
hook = streamImpl.createWritableStreamHook(stream);
|
|
838
|
+
}
|
|
839
|
+
hook.dispose();
|
|
840
|
+
return;
|
|
841
|
+
}
|
|
842
|
+
case "readable": {
|
|
843
|
+
let stream = value;
|
|
844
|
+
let hook = this.rpcTargets?.get(stream);
|
|
845
|
+
if (hook) {
|
|
846
|
+
this.rpcTargets.delete(stream);
|
|
847
|
+
} else {
|
|
848
|
+
hook = streamImpl.createReadableStreamHook(stream);
|
|
849
|
+
}
|
|
850
|
+
hook.dispose();
|
|
851
|
+
return;
|
|
852
|
+
}
|
|
678
853
|
default:
|
|
679
854
|
return;
|
|
680
855
|
}
|
|
@@ -683,9 +858,9 @@ var RpcPayload = class _RpcPayload {
|
|
|
683
858
|
// *would* be awaited if this payload were to be delivered. See the similarly-named method of
|
|
684
859
|
// StubHook for explanation.
|
|
685
860
|
ignoreUnhandledRejections() {
|
|
686
|
-
if (this.
|
|
687
|
-
this.
|
|
688
|
-
|
|
861
|
+
if (this.hooks) {
|
|
862
|
+
this.hooks.forEach((hook) => {
|
|
863
|
+
hook.ignoreUnhandledRejections();
|
|
689
864
|
});
|
|
690
865
|
this.promises.forEach(
|
|
691
866
|
(promise) => unwrapStubOrParent(promise.promise).ignoreUnhandledRejections()
|
|
@@ -706,6 +881,11 @@ var RpcPayload = class _RpcPayload {
|
|
|
706
881
|
case "undefined":
|
|
707
882
|
case "function":
|
|
708
883
|
case "rpc-target":
|
|
884
|
+
case "writable":
|
|
885
|
+
case "readable":
|
|
886
|
+
case "headers":
|
|
887
|
+
case "request":
|
|
888
|
+
case "response":
|
|
709
889
|
return;
|
|
710
890
|
case "array": {
|
|
711
891
|
let array = value;
|
|
@@ -778,11 +958,20 @@ function followPath(value, parent, path, owner) {
|
|
|
778
958
|
let { hook, pathIfPromise } = unwrapStubAndPath(value);
|
|
779
959
|
return { hook, remainingPath: pathIfPromise ? pathIfPromise.concat(path.slice(i)) : path.slice(i) };
|
|
780
960
|
}
|
|
961
|
+
case "writable":
|
|
962
|
+
value = void 0;
|
|
963
|
+
break;
|
|
964
|
+
case "readable":
|
|
965
|
+
value = void 0;
|
|
966
|
+
break;
|
|
781
967
|
case "primitive":
|
|
782
968
|
case "bigint":
|
|
783
969
|
case "bytes":
|
|
784
970
|
case "date":
|
|
785
971
|
case "error":
|
|
972
|
+
case "headers":
|
|
973
|
+
case "request":
|
|
974
|
+
case "response":
|
|
786
975
|
value = void 0;
|
|
787
976
|
break;
|
|
788
977
|
case "undefined":
|
|
@@ -1017,6 +1206,14 @@ var PromiseStubHook = class _PromiseStubHook extends StubHook {
|
|
|
1017
1206
|
args.ensureDeepCopied();
|
|
1018
1207
|
return new _PromiseStubHook(this.promise.then((hook) => hook.call(path, args)));
|
|
1019
1208
|
}
|
|
1209
|
+
stream(path, args) {
|
|
1210
|
+
args.ensureDeepCopied();
|
|
1211
|
+
let promise = this.promise.then((hook) => {
|
|
1212
|
+
let result = hook.stream(path, args);
|
|
1213
|
+
return result.promise;
|
|
1214
|
+
});
|
|
1215
|
+
return { promise };
|
|
1216
|
+
}
|
|
1020
1217
|
map(path, captures, instructions) {
|
|
1021
1218
|
return new _PromiseStubHook(this.promise.then(
|
|
1022
1219
|
(hook) => hook.map(path, captures, instructions),
|
|
@@ -1089,6 +1286,9 @@ var NullExporter = class {
|
|
|
1089
1286
|
}
|
|
1090
1287
|
unexport(ids) {
|
|
1091
1288
|
}
|
|
1289
|
+
createPipe(readable) {
|
|
1290
|
+
throw new Error("Cannot create pipes without an RPC session.");
|
|
1291
|
+
}
|
|
1092
1292
|
onSendError(error) {
|
|
1093
1293
|
}
|
|
1094
1294
|
};
|
|
@@ -1193,6 +1393,73 @@ var Devaluator = class _Devaluator {
|
|
|
1193
1393
|
];
|
|
1194
1394
|
}
|
|
1195
1395
|
}
|
|
1396
|
+
case "headers":
|
|
1397
|
+
return ["headers", [...value]];
|
|
1398
|
+
case "request": {
|
|
1399
|
+
let req = value;
|
|
1400
|
+
let init = {};
|
|
1401
|
+
if (req.method !== "GET") init.method = req.method;
|
|
1402
|
+
let headers = [...req.headers];
|
|
1403
|
+
if (headers.length > 0) {
|
|
1404
|
+
init.headers = headers;
|
|
1405
|
+
}
|
|
1406
|
+
if (req.body) {
|
|
1407
|
+
init.body = this.devaluateImpl(req.body, req, depth + 1);
|
|
1408
|
+
init.duplex = req.duplex || "half";
|
|
1409
|
+
} else if (req.body === void 0 && !["GET", "HEAD", "OPTIONS", "TRACE", "DELETE"].includes(req.method)) {
|
|
1410
|
+
let bodyPromise = req.arrayBuffer();
|
|
1411
|
+
let readable = new ReadableStream({
|
|
1412
|
+
async start(controller) {
|
|
1413
|
+
try {
|
|
1414
|
+
controller.enqueue(new Uint8Array(await bodyPromise));
|
|
1415
|
+
controller.close();
|
|
1416
|
+
} catch (err) {
|
|
1417
|
+
controller.error(err);
|
|
1418
|
+
}
|
|
1419
|
+
}
|
|
1420
|
+
});
|
|
1421
|
+
let hook = streamImpl.createReadableStreamHook(readable);
|
|
1422
|
+
let importId = this.exporter.createPipe(readable, hook);
|
|
1423
|
+
init.body = ["readable", importId];
|
|
1424
|
+
init.duplex = req.duplex || "half";
|
|
1425
|
+
}
|
|
1426
|
+
if (req.cache && req.cache !== "default") init.cache = req.cache;
|
|
1427
|
+
if (req.redirect !== "follow") init.redirect = req.redirect;
|
|
1428
|
+
if (req.integrity) init.integrity = req.integrity;
|
|
1429
|
+
if (req.mode && req.mode !== "cors") init.mode = req.mode;
|
|
1430
|
+
if (req.credentials && req.credentials !== "same-origin") {
|
|
1431
|
+
init.credentials = req.credentials;
|
|
1432
|
+
}
|
|
1433
|
+
if (req.referrer && req.referrer !== "about:client") init.referrer = req.referrer;
|
|
1434
|
+
if (req.referrerPolicy) init.referrerPolicy = req.referrerPolicy;
|
|
1435
|
+
if (req.keepalive) init.keepalive = req.keepalive;
|
|
1436
|
+
let cfReq = req;
|
|
1437
|
+
if (cfReq.cf) init.cf = cfReq.cf;
|
|
1438
|
+
if (cfReq.encodeResponseBody && cfReq.encodeResponseBody !== "automatic") {
|
|
1439
|
+
init.encodeResponseBody = cfReq.encodeResponseBody;
|
|
1440
|
+
}
|
|
1441
|
+
return ["request", req.url, init];
|
|
1442
|
+
}
|
|
1443
|
+
case "response": {
|
|
1444
|
+
let resp = value;
|
|
1445
|
+
let body = this.devaluateImpl(resp.body, resp, depth + 1);
|
|
1446
|
+
let init = {};
|
|
1447
|
+
if (resp.status !== 200) init.status = resp.status;
|
|
1448
|
+
if (resp.statusText) init.statusText = resp.statusText;
|
|
1449
|
+
let headers = [...resp.headers];
|
|
1450
|
+
if (headers.length > 0) {
|
|
1451
|
+
init.headers = headers;
|
|
1452
|
+
}
|
|
1453
|
+
let cfResp = resp;
|
|
1454
|
+
if (cfResp.cf) init.cf = cfResp.cf;
|
|
1455
|
+
if (cfResp.encodeBody && cfResp.encodeBody !== "automatic") {
|
|
1456
|
+
init.encodeBody = cfResp.encodeBody;
|
|
1457
|
+
}
|
|
1458
|
+
if (cfResp.webSocket) {
|
|
1459
|
+
throw new TypeError("Can't serialize a Response containing a webSocket.");
|
|
1460
|
+
}
|
|
1461
|
+
return ["response", body, init];
|
|
1462
|
+
}
|
|
1196
1463
|
case "error": {
|
|
1197
1464
|
let e = value;
|
|
1198
1465
|
let rewritten = this.exporter.onSendError(e);
|
|
@@ -1247,6 +1514,22 @@ var Devaluator = class _Devaluator {
|
|
|
1247
1514
|
let hook = this.source.getHookForRpcTarget(value, parent);
|
|
1248
1515
|
return this.devaluateHook("promise", hook);
|
|
1249
1516
|
}
|
|
1517
|
+
case "writable": {
|
|
1518
|
+
if (!this.source) {
|
|
1519
|
+
throw new Error("Can't serialize WritableStream in this context.");
|
|
1520
|
+
}
|
|
1521
|
+
let hook = this.source.getHookForWritableStream(value, parent);
|
|
1522
|
+
return this.devaluateHook("writable", hook);
|
|
1523
|
+
}
|
|
1524
|
+
case "readable": {
|
|
1525
|
+
if (!this.source) {
|
|
1526
|
+
throw new Error("Can't serialize ReadableStream in this context.");
|
|
1527
|
+
}
|
|
1528
|
+
let ws = value;
|
|
1529
|
+
let hook = this.source.getHookForReadableStream(ws, parent);
|
|
1530
|
+
let importId = this.exporter.createPipe(ws, hook);
|
|
1531
|
+
return ["readable", importId];
|
|
1532
|
+
}
|
|
1250
1533
|
default:
|
|
1251
1534
|
throw new Error("unreachable");
|
|
1252
1535
|
}
|
|
@@ -1271,16 +1554,27 @@ var NullImporter = class {
|
|
|
1271
1554
|
getExport(idx) {
|
|
1272
1555
|
return void 0;
|
|
1273
1556
|
}
|
|
1557
|
+
getPipeReadable(exportId) {
|
|
1558
|
+
throw new Error("Cannot retrieve pipe readable without an RPC session.");
|
|
1559
|
+
}
|
|
1274
1560
|
};
|
|
1275
1561
|
var NULL_IMPORTER = new NullImporter();
|
|
1562
|
+
function fixBrokenRequestBody(request, body) {
|
|
1563
|
+
let promise = new Response(body).arrayBuffer().then((arrayBuffer) => {
|
|
1564
|
+
let bytes = new Uint8Array(arrayBuffer);
|
|
1565
|
+
let result = new Request(request, { body: bytes });
|
|
1566
|
+
return new PayloadStubHook(RpcPayload.fromAppReturn(result));
|
|
1567
|
+
});
|
|
1568
|
+
return new RpcPromise(new PromiseStubHook(promise), []);
|
|
1569
|
+
}
|
|
1276
1570
|
var Evaluator = class _Evaluator {
|
|
1277
1571
|
constructor(importer) {
|
|
1278
1572
|
this.importer = importer;
|
|
1279
1573
|
}
|
|
1280
|
-
|
|
1574
|
+
hooks = [];
|
|
1281
1575
|
promises = [];
|
|
1282
1576
|
evaluate(value) {
|
|
1283
|
-
let payload = RpcPayload.forEvaluate(this.
|
|
1577
|
+
let payload = RpcPayload.forEvaluate(this.hooks, this.promises);
|
|
1284
1578
|
try {
|
|
1285
1579
|
payload.value = this.evaluateImpl(value, payload, "value");
|
|
1286
1580
|
return payload;
|
|
@@ -1350,6 +1644,56 @@ var Evaluator = class _Evaluator {
|
|
|
1350
1644
|
return -Infinity;
|
|
1351
1645
|
case "nan":
|
|
1352
1646
|
return NaN;
|
|
1647
|
+
case "headers":
|
|
1648
|
+
if (value.length === 2 && value[1] instanceof Array) {
|
|
1649
|
+
return new Headers(value[1]);
|
|
1650
|
+
}
|
|
1651
|
+
break;
|
|
1652
|
+
case "request": {
|
|
1653
|
+
if (value.length !== 3 || typeof value[1] !== "string") break;
|
|
1654
|
+
let url = value[1];
|
|
1655
|
+
let init = value[2];
|
|
1656
|
+
if (typeof init !== "object" || init === null) break;
|
|
1657
|
+
if (init.body) {
|
|
1658
|
+
init.body = this.evaluateImpl(init.body, init, "body");
|
|
1659
|
+
if (init.body === null || typeof init.body === "string" || init.body instanceof Uint8Array || init.body instanceof ReadableStream) ; else {
|
|
1660
|
+
throw new TypeError("Request body must be of type ReadableStream.");
|
|
1661
|
+
}
|
|
1662
|
+
}
|
|
1663
|
+
if (init.signal) {
|
|
1664
|
+
init.signal = this.evaluateImpl(init.signal, init, "signal");
|
|
1665
|
+
if (!(init.signal instanceof AbortSignal)) {
|
|
1666
|
+
throw new TypeError("Request siganl must be of type AbortSignal.");
|
|
1667
|
+
}
|
|
1668
|
+
}
|
|
1669
|
+
if (init.headers && !(init.headers instanceof Array)) {
|
|
1670
|
+
throw new TypeError("Request headers must be serialized as an array of pairs.");
|
|
1671
|
+
}
|
|
1672
|
+
let result = new Request(url, init);
|
|
1673
|
+
if (init.body instanceof ReadableStream && result.body === void 0) {
|
|
1674
|
+
let promise = fixBrokenRequestBody(result, init.body);
|
|
1675
|
+
this.promises.push({ promise, parent, property });
|
|
1676
|
+
return promise;
|
|
1677
|
+
} else {
|
|
1678
|
+
return result;
|
|
1679
|
+
}
|
|
1680
|
+
}
|
|
1681
|
+
case "response": {
|
|
1682
|
+
if (value.length !== 3) break;
|
|
1683
|
+
let body = this.evaluateImpl(value[1], parent, property);
|
|
1684
|
+
if (body === null || typeof body === "string" || body instanceof Uint8Array || body instanceof ReadableStream) ; else {
|
|
1685
|
+
throw new TypeError("Response body must be of type ReadableStream.");
|
|
1686
|
+
}
|
|
1687
|
+
let init = value[2];
|
|
1688
|
+
if (typeof init !== "object" || init === null) break;
|
|
1689
|
+
if (init.webSocket) {
|
|
1690
|
+
throw new TypeError("Can't deserialize a Response containing a webSocket.");
|
|
1691
|
+
}
|
|
1692
|
+
if (init.headers && !(init.headers instanceof Array)) {
|
|
1693
|
+
throw new TypeError("Request headers must be serialized as an array of pairs.");
|
|
1694
|
+
}
|
|
1695
|
+
return new Response(body, init);
|
|
1696
|
+
}
|
|
1353
1697
|
case "import":
|
|
1354
1698
|
case "pipeline": {
|
|
1355
1699
|
if (value.length < 2 || value.length > 4) {
|
|
@@ -1369,9 +1713,8 @@ var Evaluator = class _Evaluator {
|
|
|
1369
1713
|
this.promises.push({ promise, parent, property });
|
|
1370
1714
|
return promise;
|
|
1371
1715
|
} else {
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
return stub;
|
|
1716
|
+
this.hooks.push(hook2);
|
|
1717
|
+
return new RpcPromise(hook2, []);
|
|
1375
1718
|
}
|
|
1376
1719
|
};
|
|
1377
1720
|
if (value.length == 2) {
|
|
@@ -1449,12 +1792,27 @@ var Evaluator = class _Evaluator {
|
|
|
1449
1792
|
return promise;
|
|
1450
1793
|
} else {
|
|
1451
1794
|
let hook = this.importer.importStub(value[1]);
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
return stub;
|
|
1795
|
+
this.hooks.push(hook);
|
|
1796
|
+
return new RpcStub(hook);
|
|
1455
1797
|
}
|
|
1456
1798
|
}
|
|
1457
1799
|
break;
|
|
1800
|
+
case "writable":
|
|
1801
|
+
if (typeof value[1] == "number") {
|
|
1802
|
+
let hook = this.importer.importStub(value[1]);
|
|
1803
|
+
let stream = streamImpl.createWritableStreamFromHook(hook);
|
|
1804
|
+
this.hooks.push(hook);
|
|
1805
|
+
return stream;
|
|
1806
|
+
}
|
|
1807
|
+
break;
|
|
1808
|
+
case "readable":
|
|
1809
|
+
if (typeof value[1] == "number") {
|
|
1810
|
+
let stream = this.importer.getPipeReadable(value[1]);
|
|
1811
|
+
let hook = streamImpl.createReadableStreamHook(stream);
|
|
1812
|
+
this.hooks.push(hook);
|
|
1813
|
+
return stream;
|
|
1814
|
+
}
|
|
1815
|
+
break;
|
|
1458
1816
|
}
|
|
1459
1817
|
throw new TypeError(`unknown special value: ${JSON.stringify(value)}`);
|
|
1460
1818
|
} else if (value instanceof Object) {
|
|
@@ -1594,6 +1952,14 @@ var RpcImportHook = class _RpcImportHook extends StubHook {
|
|
|
1594
1952
|
return entry.session.sendCall(entry.importId, path, args);
|
|
1595
1953
|
}
|
|
1596
1954
|
}
|
|
1955
|
+
stream(path, args) {
|
|
1956
|
+
let entry = this.getEntry();
|
|
1957
|
+
if (entry.resolution) {
|
|
1958
|
+
return entry.resolution.stream(path, args);
|
|
1959
|
+
} else {
|
|
1960
|
+
return entry.session.sendStream(entry.importId, path, args);
|
|
1961
|
+
}
|
|
1962
|
+
}
|
|
1597
1963
|
map(path, captures, instructions) {
|
|
1598
1964
|
let entry;
|
|
1599
1965
|
try {
|
|
@@ -1766,19 +2132,23 @@ var RpcSessionImpl = class {
|
|
|
1766
2132
|
return payload;
|
|
1767
2133
|
}
|
|
1768
2134
|
};
|
|
2135
|
+
let autoRelease = exp.autoRelease;
|
|
1769
2136
|
++this.pullCount;
|
|
1770
2137
|
exp.pull = resolve().then(
|
|
1771
2138
|
(payload) => {
|
|
1772
2139
|
let value = Devaluator.devaluate(payload.value, void 0, this, payload);
|
|
1773
2140
|
this.send(["resolve", exportId, value]);
|
|
2141
|
+
if (autoRelease) this.releaseExport(exportId, 1);
|
|
1774
2142
|
},
|
|
1775
2143
|
(error) => {
|
|
1776
2144
|
this.send(["reject", exportId, Devaluator.devaluate(error, void 0, this)]);
|
|
2145
|
+
if (autoRelease) this.releaseExport(exportId, 1);
|
|
1777
2146
|
}
|
|
1778
2147
|
).catch(
|
|
1779
2148
|
(error) => {
|
|
1780
2149
|
try {
|
|
1781
2150
|
this.send(["reject", exportId, Devaluator.devaluate(error, void 0, this)]);
|
|
2151
|
+
if (autoRelease) this.releaseExport(exportId, 1);
|
|
1782
2152
|
} catch (error2) {
|
|
1783
2153
|
this.abort(error2);
|
|
1784
2154
|
}
|
|
@@ -1830,9 +2200,35 @@ var RpcSessionImpl = class {
|
|
|
1830
2200
|
getExport(idx) {
|
|
1831
2201
|
return this.exports[idx]?.hook;
|
|
1832
2202
|
}
|
|
2203
|
+
getPipeReadable(exportId) {
|
|
2204
|
+
let entry = this.exports[exportId];
|
|
2205
|
+
if (!entry || !entry.pipeReadable) {
|
|
2206
|
+
throw new Error(`Export ${exportId} is not a pipe or its readable end was already consumed.`);
|
|
2207
|
+
}
|
|
2208
|
+
let readable = entry.pipeReadable;
|
|
2209
|
+
entry.pipeReadable = void 0;
|
|
2210
|
+
return readable;
|
|
2211
|
+
}
|
|
2212
|
+
createPipe(readable, readableHook) {
|
|
2213
|
+
if (this.abortReason) throw this.abortReason;
|
|
2214
|
+
this.send(["pipe"]);
|
|
2215
|
+
let importId = this.imports.length;
|
|
2216
|
+
let entry = new ImportTableEntry(this, importId, false);
|
|
2217
|
+
this.imports.push(entry);
|
|
2218
|
+
let hook = new RpcImportHook(
|
|
2219
|
+
/*isPromise=*/
|
|
2220
|
+
false,
|
|
2221
|
+
entry
|
|
2222
|
+
);
|
|
2223
|
+
let writable = streamImpl.createWritableStreamFromHook(hook);
|
|
2224
|
+
readable.pipeTo(writable).catch(() => {
|
|
2225
|
+
}).finally(() => readableHook.dispose());
|
|
2226
|
+
return importId;
|
|
2227
|
+
}
|
|
2228
|
+
// Serializes and sends a message. Returns the byte length of the serialized message.
|
|
1833
2229
|
send(msg) {
|
|
1834
2230
|
if (this.abortReason !== void 0) {
|
|
1835
|
-
return;
|
|
2231
|
+
return 0;
|
|
1836
2232
|
}
|
|
1837
2233
|
let msgText;
|
|
1838
2234
|
try {
|
|
@@ -1845,6 +2241,7 @@ var RpcSessionImpl = class {
|
|
|
1845
2241
|
throw err;
|
|
1846
2242
|
}
|
|
1847
2243
|
this.transport.send(msgText).catch((err) => this.abort(err, false));
|
|
2244
|
+
return msgText.length;
|
|
1848
2245
|
}
|
|
1849
2246
|
sendCall(id, path, args) {
|
|
1850
2247
|
if (this.abortReason) throw this.abortReason;
|
|
@@ -1862,6 +2259,34 @@ var RpcSessionImpl = class {
|
|
|
1862
2259
|
entry
|
|
1863
2260
|
);
|
|
1864
2261
|
}
|
|
2262
|
+
sendStream(id, path, args) {
|
|
2263
|
+
if (this.abortReason) throw this.abortReason;
|
|
2264
|
+
let value = ["pipeline", id, path];
|
|
2265
|
+
let devalue = Devaluator.devaluate(args.value, void 0, this, args);
|
|
2266
|
+
value.push(devalue[0]);
|
|
2267
|
+
let size = this.send(["stream", value]);
|
|
2268
|
+
let importId = this.imports.length;
|
|
2269
|
+
let entry = new ImportTableEntry(
|
|
2270
|
+
this,
|
|
2271
|
+
importId,
|
|
2272
|
+
/*pulling=*/
|
|
2273
|
+
true
|
|
2274
|
+
);
|
|
2275
|
+
entry.remoteRefcount = 0;
|
|
2276
|
+
entry.localRefcount = 1;
|
|
2277
|
+
this.imports.push(entry);
|
|
2278
|
+
let promise = entry.awaitResolution().then(
|
|
2279
|
+
(p) => {
|
|
2280
|
+
p.dispose();
|
|
2281
|
+
delete this.imports[importId];
|
|
2282
|
+
},
|
|
2283
|
+
(err) => {
|
|
2284
|
+
delete this.imports[importId];
|
|
2285
|
+
throw err;
|
|
2286
|
+
}
|
|
2287
|
+
);
|
|
2288
|
+
return { promise, size };
|
|
2289
|
+
}
|
|
1865
2290
|
sendMap(id, path, captures, instructions) {
|
|
1866
2291
|
if (this.abortReason) {
|
|
1867
2292
|
for (let cap of captures) {
|
|
@@ -1949,6 +2374,24 @@ var RpcSessionImpl = class {
|
|
|
1949
2374
|
continue;
|
|
1950
2375
|
}
|
|
1951
2376
|
break;
|
|
2377
|
+
case "stream": {
|
|
2378
|
+
if (msg.length > 1) {
|
|
2379
|
+
let payload = new Evaluator(this).evaluate(msg[1]);
|
|
2380
|
+
let hook = new PayloadStubHook(payload);
|
|
2381
|
+
hook.ignoreUnhandledRejections();
|
|
2382
|
+
let exportId = this.exports.length;
|
|
2383
|
+
this.exports.push({ hook, refcount: 1, autoRelease: true });
|
|
2384
|
+
this.ensureResolvingExport(exportId);
|
|
2385
|
+
continue;
|
|
2386
|
+
}
|
|
2387
|
+
break;
|
|
2388
|
+
}
|
|
2389
|
+
case "pipe": {
|
|
2390
|
+
let { readable, writable } = new TransformStream();
|
|
2391
|
+
let hook = streamImpl.createWritableStreamHook(writable);
|
|
2392
|
+
this.exports.push({ hook, refcount: 1, pipeReadable: readable });
|
|
2393
|
+
continue;
|
|
2394
|
+
}
|
|
1952
2395
|
case "pull": {
|
|
1953
2396
|
let exportId = msg[1];
|
|
1954
2397
|
if (typeof exportId == "number") {
|
|
@@ -2444,6 +2887,9 @@ var MapBuilder = class {
|
|
|
2444
2887
|
}
|
|
2445
2888
|
unexport(ids) {
|
|
2446
2889
|
}
|
|
2890
|
+
createPipe(readable) {
|
|
2891
|
+
throw new Error("Cannot send ReadableStream inside a mapper function.");
|
|
2892
|
+
}
|
|
2447
2893
|
onSendError(error) {
|
|
2448
2894
|
}
|
|
2449
2895
|
};
|
|
@@ -2553,6 +2999,9 @@ var MapApplicator = class {
|
|
|
2553
2999
|
return this.variables[idx];
|
|
2554
3000
|
}
|
|
2555
3001
|
}
|
|
3002
|
+
getPipeReadable(exportId) {
|
|
3003
|
+
throw new Error("A mapper function cannot use pipe readables.");
|
|
3004
|
+
}
|
|
2556
3005
|
};
|
|
2557
3006
|
function applyMapToElement(input, parent, owner, captures, instructions) {
|
|
2558
3007
|
let inputHook = new PayloadStubHook(RpcPayload.deepCopyFrom(input, parent, owner));
|
|
@@ -2593,6 +3042,333 @@ mapImpl.applyMap = (input, parent, owner, captures, instructions) => {
|
|
|
2593
3042
|
}
|
|
2594
3043
|
}
|
|
2595
3044
|
};
|
|
3045
|
+
|
|
3046
|
+
// src/streams.ts
|
|
3047
|
+
var WritableStreamStubHook = class _WritableStreamStubHook extends StubHook {
|
|
3048
|
+
state;
|
|
3049
|
+
// undefined when disposed
|
|
3050
|
+
// Creates a new WritableStreamStubHook that is not duplicated from an existing hook.
|
|
3051
|
+
static create(stream) {
|
|
3052
|
+
let writer = stream.getWriter();
|
|
3053
|
+
return new _WritableStreamStubHook({ refcount: 1, writer, closed: false });
|
|
3054
|
+
}
|
|
3055
|
+
constructor(state, dupFrom) {
|
|
3056
|
+
super();
|
|
3057
|
+
this.state = state;
|
|
3058
|
+
if (dupFrom) {
|
|
3059
|
+
++state.refcount;
|
|
3060
|
+
}
|
|
3061
|
+
}
|
|
3062
|
+
getState() {
|
|
3063
|
+
if (this.state) {
|
|
3064
|
+
return this.state;
|
|
3065
|
+
} else {
|
|
3066
|
+
throw new Error("Attempted to use a WritableStreamStubHook after it was disposed.");
|
|
3067
|
+
}
|
|
3068
|
+
}
|
|
3069
|
+
call(path, args) {
|
|
3070
|
+
try {
|
|
3071
|
+
let state = this.getState();
|
|
3072
|
+
if (path.length !== 1 || typeof path[0] !== "string") {
|
|
3073
|
+
throw new Error("WritableStream stub only supports direct method calls");
|
|
3074
|
+
}
|
|
3075
|
+
const method = path[0];
|
|
3076
|
+
if (method !== "write" && method !== "close" && method !== "abort") {
|
|
3077
|
+
args.dispose();
|
|
3078
|
+
throw new Error(`Unknown WritableStream method: ${method}`);
|
|
3079
|
+
}
|
|
3080
|
+
if (method === "close" || method === "abort") {
|
|
3081
|
+
state.closed = true;
|
|
3082
|
+
}
|
|
3083
|
+
let func = state.writer[method];
|
|
3084
|
+
let promise = args.deliverCall(func, state.writer);
|
|
3085
|
+
return new PromiseStubHook(promise.then((payload) => new PayloadStubHook(payload)));
|
|
3086
|
+
} catch (err) {
|
|
3087
|
+
return new ErrorStubHook(err);
|
|
3088
|
+
}
|
|
3089
|
+
}
|
|
3090
|
+
map(path, captures, instructions) {
|
|
3091
|
+
for (let cap of captures) {
|
|
3092
|
+
cap.dispose();
|
|
3093
|
+
}
|
|
3094
|
+
return new ErrorStubHook(new Error("Cannot use map() on a WritableStream"));
|
|
3095
|
+
}
|
|
3096
|
+
get(path) {
|
|
3097
|
+
return new ErrorStubHook(new Error("Cannot access properties on a WritableStream stub"));
|
|
3098
|
+
}
|
|
3099
|
+
dup() {
|
|
3100
|
+
let state = this.getState();
|
|
3101
|
+
return new _WritableStreamStubHook(state, this);
|
|
3102
|
+
}
|
|
3103
|
+
pull() {
|
|
3104
|
+
return Promise.reject(new Error("Cannot pull a WritableStream stub"));
|
|
3105
|
+
}
|
|
3106
|
+
ignoreUnhandledRejections() {
|
|
3107
|
+
}
|
|
3108
|
+
dispose() {
|
|
3109
|
+
let state = this.state;
|
|
3110
|
+
this.state = void 0;
|
|
3111
|
+
if (state) {
|
|
3112
|
+
if (--state.refcount === 0) {
|
|
3113
|
+
if (!state.closed) {
|
|
3114
|
+
state.writer.abort(new Error("WritableStream RPC stub was disposed without calling close()")).catch(() => {
|
|
3115
|
+
});
|
|
3116
|
+
}
|
|
3117
|
+
state.writer.releaseLock();
|
|
3118
|
+
}
|
|
3119
|
+
}
|
|
3120
|
+
}
|
|
3121
|
+
onBroken(callback) {
|
|
3122
|
+
}
|
|
3123
|
+
};
|
|
3124
|
+
var INITIAL_WINDOW = 256 * 1024;
|
|
3125
|
+
var MAX_WINDOW = 1024 * 1024 * 1024;
|
|
3126
|
+
var MIN_WINDOW = 64 * 1024;
|
|
3127
|
+
var STARTUP_GROWTH_FACTOR = 2;
|
|
3128
|
+
var STEADY_GROWTH_FACTOR = 1.25;
|
|
3129
|
+
var DECAY_FACTOR = 0.9;
|
|
3130
|
+
var STARTUP_EXIT_ROUNDS = 3;
|
|
3131
|
+
var FlowController = class {
|
|
3132
|
+
constructor(now) {
|
|
3133
|
+
this.now = now;
|
|
3134
|
+
}
|
|
3135
|
+
// The current window size in bytes. The sender blocks when bytesInFlight >= window.
|
|
3136
|
+
window = INITIAL_WINDOW;
|
|
3137
|
+
// Total bytes currently in flight (sent but not yet acked).
|
|
3138
|
+
bytesInFlight = 0;
|
|
3139
|
+
// Whether we're still in the startup phase.
|
|
3140
|
+
inStartupPhase = true;
|
|
3141
|
+
// ----- BDP estimation state (private) -----
|
|
3142
|
+
// Total bytes acked so far.
|
|
3143
|
+
delivered = 0;
|
|
3144
|
+
// Time of most recent ack.
|
|
3145
|
+
deliveredTime = 0;
|
|
3146
|
+
// Time when the very first ack was received.
|
|
3147
|
+
firstAckTime = 0;
|
|
3148
|
+
firstAckDelivered = 0;
|
|
3149
|
+
// Global minimum RTT observed (milliseconds).
|
|
3150
|
+
minRtt = Infinity;
|
|
3151
|
+
// For startup exit: count of consecutive RTT rounds where the window didn't meaningfully grow.
|
|
3152
|
+
roundsWithoutIncrease = 0;
|
|
3153
|
+
// Window size at the start of the current round, for startup exit detection.
|
|
3154
|
+
lastRoundWindow = 0;
|
|
3155
|
+
// Time when the current round started.
|
|
3156
|
+
roundStartTime = 0;
|
|
3157
|
+
// Called when a write of `size` bytes is about to be sent. Returns a token that must be
|
|
3158
|
+
// passed to onAck() when the ack arrives, and whether the sender should block (window full).
|
|
3159
|
+
onSend(size) {
|
|
3160
|
+
this.bytesInFlight += size;
|
|
3161
|
+
let token = {
|
|
3162
|
+
sentTime: this.now(),
|
|
3163
|
+
size,
|
|
3164
|
+
deliveredAtSend: this.delivered,
|
|
3165
|
+
deliveredTimeAtSend: this.deliveredTime,
|
|
3166
|
+
windowAtSend: this.window,
|
|
3167
|
+
windowFullAtSend: this.bytesInFlight >= this.window
|
|
3168
|
+
};
|
|
3169
|
+
return { token, shouldBlock: token.windowFullAtSend };
|
|
3170
|
+
}
|
|
3171
|
+
// Called when a previously-sent write fails. Restores bytesInFlight without updating
|
|
3172
|
+
// any BDP estimates.
|
|
3173
|
+
onError(token) {
|
|
3174
|
+
this.bytesInFlight -= token.size;
|
|
3175
|
+
}
|
|
3176
|
+
// Called when an ack is received for a previously-sent write. Updates BDP estimates and
|
|
3177
|
+
// the window. Returns whether a blocked sender should now unblock.
|
|
3178
|
+
onAck(token) {
|
|
3179
|
+
let ackTime = this.now();
|
|
3180
|
+
this.delivered += token.size;
|
|
3181
|
+
this.deliveredTime = ackTime;
|
|
3182
|
+
this.bytesInFlight -= token.size;
|
|
3183
|
+
let rtt = ackTime - token.sentTime;
|
|
3184
|
+
this.minRtt = Math.min(this.minRtt, rtt);
|
|
3185
|
+
if (this.firstAckTime === 0) {
|
|
3186
|
+
this.firstAckTime = ackTime;
|
|
3187
|
+
this.firstAckDelivered = this.delivered;
|
|
3188
|
+
} else {
|
|
3189
|
+
let baseTime;
|
|
3190
|
+
let baseDelivered;
|
|
3191
|
+
if (token.deliveredTimeAtSend === 0) {
|
|
3192
|
+
baseTime = this.firstAckTime;
|
|
3193
|
+
baseDelivered = this.firstAckDelivered;
|
|
3194
|
+
} else {
|
|
3195
|
+
baseTime = token.deliveredTimeAtSend;
|
|
3196
|
+
baseDelivered = token.deliveredAtSend;
|
|
3197
|
+
}
|
|
3198
|
+
let interval = ackTime - baseTime;
|
|
3199
|
+
let bytes = this.delivered - baseDelivered;
|
|
3200
|
+
let bandwidth = bytes / interval;
|
|
3201
|
+
let growthFactor = this.inStartupPhase ? STARTUP_GROWTH_FACTOR : STEADY_GROWTH_FACTOR;
|
|
3202
|
+
let newWindow = bandwidth * this.minRtt * growthFactor;
|
|
3203
|
+
newWindow = Math.min(newWindow, token.windowAtSend * growthFactor);
|
|
3204
|
+
if (token.windowFullAtSend) {
|
|
3205
|
+
newWindow = Math.max(newWindow, token.windowAtSend * DECAY_FACTOR);
|
|
3206
|
+
} else {
|
|
3207
|
+
newWindow = Math.max(newWindow, this.window);
|
|
3208
|
+
}
|
|
3209
|
+
this.window = Math.max(Math.min(newWindow, MAX_WINDOW), MIN_WINDOW);
|
|
3210
|
+
if (this.inStartupPhase && token.sentTime >= this.roundStartTime) {
|
|
3211
|
+
if (this.window > this.lastRoundWindow * STEADY_GROWTH_FACTOR) {
|
|
3212
|
+
this.roundsWithoutIncrease = 0;
|
|
3213
|
+
} else {
|
|
3214
|
+
if (++this.roundsWithoutIncrease >= STARTUP_EXIT_ROUNDS) {
|
|
3215
|
+
this.inStartupPhase = false;
|
|
3216
|
+
}
|
|
3217
|
+
}
|
|
3218
|
+
this.roundStartTime = ackTime;
|
|
3219
|
+
this.lastRoundWindow = this.window;
|
|
3220
|
+
}
|
|
3221
|
+
}
|
|
3222
|
+
return this.bytesInFlight < this.window;
|
|
3223
|
+
}
|
|
3224
|
+
};
|
|
3225
|
+
function createWritableStreamFromHook(hook) {
|
|
3226
|
+
let pendingError = void 0;
|
|
3227
|
+
let hookDisposed = false;
|
|
3228
|
+
let fc = new FlowController(() => performance.now());
|
|
3229
|
+
let windowResolve;
|
|
3230
|
+
let windowReject;
|
|
3231
|
+
const disposeHook = () => {
|
|
3232
|
+
if (!hookDisposed) {
|
|
3233
|
+
hookDisposed = true;
|
|
3234
|
+
hook.dispose();
|
|
3235
|
+
}
|
|
3236
|
+
};
|
|
3237
|
+
return new WritableStream({
|
|
3238
|
+
write(chunk, controller) {
|
|
3239
|
+
if (pendingError !== void 0) {
|
|
3240
|
+
throw pendingError;
|
|
3241
|
+
}
|
|
3242
|
+
const payload = RpcPayload.fromAppParams([chunk]);
|
|
3243
|
+
const { promise, size } = hook.stream(["write"], payload);
|
|
3244
|
+
if (size === void 0) {
|
|
3245
|
+
return promise.catch((err) => {
|
|
3246
|
+
if (pendingError === void 0) {
|
|
3247
|
+
pendingError = err;
|
|
3248
|
+
}
|
|
3249
|
+
throw err;
|
|
3250
|
+
});
|
|
3251
|
+
} else {
|
|
3252
|
+
let { token, shouldBlock } = fc.onSend(size);
|
|
3253
|
+
promise.then(() => {
|
|
3254
|
+
let hasCapacity = fc.onAck(token);
|
|
3255
|
+
if (hasCapacity && windowResolve) {
|
|
3256
|
+
windowResolve();
|
|
3257
|
+
windowResolve = void 0;
|
|
3258
|
+
windowReject = void 0;
|
|
3259
|
+
}
|
|
3260
|
+
}, (err) => {
|
|
3261
|
+
fc.onError(token);
|
|
3262
|
+
if (pendingError === void 0) {
|
|
3263
|
+
pendingError = err;
|
|
3264
|
+
controller.error(err);
|
|
3265
|
+
disposeHook();
|
|
3266
|
+
}
|
|
3267
|
+
if (windowReject) {
|
|
3268
|
+
windowReject(err);
|
|
3269
|
+
windowResolve = void 0;
|
|
3270
|
+
windowReject = void 0;
|
|
3271
|
+
}
|
|
3272
|
+
});
|
|
3273
|
+
if (shouldBlock) {
|
|
3274
|
+
return new Promise((resolve, reject) => {
|
|
3275
|
+
windowResolve = resolve;
|
|
3276
|
+
windowReject = reject;
|
|
3277
|
+
});
|
|
3278
|
+
}
|
|
3279
|
+
}
|
|
3280
|
+
},
|
|
3281
|
+
async close() {
|
|
3282
|
+
if (pendingError !== void 0) {
|
|
3283
|
+
disposeHook();
|
|
3284
|
+
throw pendingError;
|
|
3285
|
+
}
|
|
3286
|
+
const { promise } = hook.stream(["close"], RpcPayload.fromAppParams([]));
|
|
3287
|
+
try {
|
|
3288
|
+
await promise;
|
|
3289
|
+
} catch (err) {
|
|
3290
|
+
throw pendingError ?? err;
|
|
3291
|
+
} finally {
|
|
3292
|
+
disposeHook();
|
|
3293
|
+
}
|
|
3294
|
+
},
|
|
3295
|
+
abort(reason) {
|
|
3296
|
+
if (pendingError !== void 0) {
|
|
3297
|
+
return;
|
|
3298
|
+
}
|
|
3299
|
+
pendingError = reason ?? new Error("WritableStream was aborted");
|
|
3300
|
+
if (windowReject) {
|
|
3301
|
+
windowReject(pendingError);
|
|
3302
|
+
windowResolve = void 0;
|
|
3303
|
+
windowReject = void 0;
|
|
3304
|
+
}
|
|
3305
|
+
const { promise } = hook.stream(["abort"], RpcPayload.fromAppParams([reason]));
|
|
3306
|
+
promise.then(() => disposeHook(), () => disposeHook());
|
|
3307
|
+
}
|
|
3308
|
+
});
|
|
3309
|
+
}
|
|
3310
|
+
var ReadableStreamStubHook = class _ReadableStreamStubHook extends StubHook {
|
|
3311
|
+
state;
|
|
3312
|
+
// undefined when disposed
|
|
3313
|
+
// Creates a new ReadableStreamStubHook.
|
|
3314
|
+
static create(stream) {
|
|
3315
|
+
return new _ReadableStreamStubHook({ refcount: 1, stream, canceled: false });
|
|
3316
|
+
}
|
|
3317
|
+
constructor(state, dupFrom) {
|
|
3318
|
+
super();
|
|
3319
|
+
this.state = state;
|
|
3320
|
+
if (dupFrom) {
|
|
3321
|
+
++state.refcount;
|
|
3322
|
+
}
|
|
3323
|
+
}
|
|
3324
|
+
call(path, args) {
|
|
3325
|
+
args.dispose();
|
|
3326
|
+
return new ErrorStubHook(new Error("Cannot call methods on a ReadableStream stub"));
|
|
3327
|
+
}
|
|
3328
|
+
map(path, captures, instructions) {
|
|
3329
|
+
for (let cap of captures) {
|
|
3330
|
+
cap.dispose();
|
|
3331
|
+
}
|
|
3332
|
+
return new ErrorStubHook(new Error("Cannot use map() on a ReadableStream"));
|
|
3333
|
+
}
|
|
3334
|
+
get(path) {
|
|
3335
|
+
return new ErrorStubHook(new Error("Cannot access properties on a ReadableStream stub"));
|
|
3336
|
+
}
|
|
3337
|
+
dup() {
|
|
3338
|
+
let state = this.state;
|
|
3339
|
+
if (!state) {
|
|
3340
|
+
throw new Error("Attempted to dup a ReadableStreamStubHook after it was disposed.");
|
|
3341
|
+
}
|
|
3342
|
+
return new _ReadableStreamStubHook(state, this);
|
|
3343
|
+
}
|
|
3344
|
+
pull() {
|
|
3345
|
+
return Promise.reject(new Error("Cannot pull a ReadableStream stub"));
|
|
3346
|
+
}
|
|
3347
|
+
ignoreUnhandledRejections() {
|
|
3348
|
+
}
|
|
3349
|
+
dispose() {
|
|
3350
|
+
let state = this.state;
|
|
3351
|
+
this.state = void 0;
|
|
3352
|
+
if (state) {
|
|
3353
|
+
if (--state.refcount === 0) {
|
|
3354
|
+
if (!state.canceled) {
|
|
3355
|
+
state.canceled = true;
|
|
3356
|
+
if (!state.stream.locked) {
|
|
3357
|
+
state.stream.cancel(
|
|
3358
|
+
new Error("ReadableStream RPC stub was disposed without being consumed")
|
|
3359
|
+
).catch(() => {
|
|
3360
|
+
});
|
|
3361
|
+
}
|
|
3362
|
+
}
|
|
3363
|
+
}
|
|
3364
|
+
}
|
|
3365
|
+
}
|
|
3366
|
+
onBroken(callback) {
|
|
3367
|
+
}
|
|
3368
|
+
};
|
|
3369
|
+
streamImpl.createWritableStreamHook = WritableStreamStubHook.create;
|
|
3370
|
+
streamImpl.createWritableStreamFromHook = createWritableStreamFromHook;
|
|
3371
|
+
streamImpl.createReadableStreamHook = ReadableStreamStubHook.create;
|
|
2596
3372
|
var RpcStub2 = RpcStub;
|
|
2597
3373
|
var RpcPromise2 = RpcPromise;
|
|
2598
3374
|
var RpcSession2 = RpcSession;
|