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