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-workers.cjs
CHANGED
|
@@ -23,15 +23,15 @@ function _interopNamespace(e) {
|
|
|
23
23
|
var cfw__namespace = /*#__PURE__*/_interopNamespace(cfw);
|
|
24
24
|
|
|
25
25
|
// src/symbols.ts
|
|
26
|
-
var WORKERS_MODULE_SYMBOL = Symbol("workers-module");
|
|
26
|
+
var WORKERS_MODULE_SYMBOL = /* @__PURE__ */ Symbol("workers-module");
|
|
27
27
|
globalThis[WORKERS_MODULE_SYMBOL] = cfw__namespace;
|
|
28
28
|
|
|
29
29
|
// src/core.ts
|
|
30
30
|
if (!Symbol.dispose) {
|
|
31
|
-
Symbol.dispose = Symbol.for("dispose");
|
|
31
|
+
Symbol.dispose = /* @__PURE__ */ Symbol.for("dispose");
|
|
32
32
|
}
|
|
33
33
|
if (!Symbol.asyncDispose) {
|
|
34
|
-
Symbol.asyncDispose = Symbol.for("asyncDispose");
|
|
34
|
+
Symbol.asyncDispose = /* @__PURE__ */ Symbol.for("asyncDispose");
|
|
35
35
|
}
|
|
36
36
|
if (!Promise.withResolvers) {
|
|
37
37
|
Promise.withResolvers = function() {
|
|
@@ -47,6 +47,8 @@ if (!Promise.withResolvers) {
|
|
|
47
47
|
var workersModule = globalThis[WORKERS_MODULE_SYMBOL];
|
|
48
48
|
var RpcTarget = workersModule ? workersModule.RpcTarget : class {
|
|
49
49
|
};
|
|
50
|
+
var AsyncFunction = (async function() {
|
|
51
|
+
}).constructor;
|
|
50
52
|
function typeForRpc(value) {
|
|
51
53
|
switch (typeof value) {
|
|
52
54
|
case "boolean":
|
|
@@ -71,6 +73,7 @@ function typeForRpc(value) {
|
|
|
71
73
|
case Object.prototype:
|
|
72
74
|
return "object";
|
|
73
75
|
case Function.prototype:
|
|
76
|
+
case AsyncFunction.prototype:
|
|
74
77
|
return "function";
|
|
75
78
|
case Array.prototype:
|
|
76
79
|
return "array";
|
|
@@ -78,6 +81,16 @@ function typeForRpc(value) {
|
|
|
78
81
|
return "date";
|
|
79
82
|
case Uint8Array.prototype:
|
|
80
83
|
return "bytes";
|
|
84
|
+
case WritableStream.prototype:
|
|
85
|
+
return "writable";
|
|
86
|
+
case ReadableStream.prototype:
|
|
87
|
+
return "readable";
|
|
88
|
+
case Headers.prototype:
|
|
89
|
+
return "headers";
|
|
90
|
+
case Request.prototype:
|
|
91
|
+
return "request";
|
|
92
|
+
case Response.prototype:
|
|
93
|
+
return "response";
|
|
81
94
|
// TODO: All other structured clone types.
|
|
82
95
|
case RpcStub.prototype:
|
|
83
96
|
return "stub";
|
|
@@ -105,7 +118,34 @@ function mapNotLoaded() {
|
|
|
105
118
|
throw new Error("RPC map() implementation was not loaded.");
|
|
106
119
|
}
|
|
107
120
|
var mapImpl = { applyMap: mapNotLoaded, sendMap: mapNotLoaded };
|
|
121
|
+
function streamNotLoaded() {
|
|
122
|
+
throw new Error("Stream implementation was not loaded.");
|
|
123
|
+
}
|
|
124
|
+
var streamImpl = {
|
|
125
|
+
createWritableStreamHook: streamNotLoaded,
|
|
126
|
+
createWritableStreamFromHook: streamNotLoaded,
|
|
127
|
+
createReadableStreamHook: streamNotLoaded
|
|
128
|
+
};
|
|
108
129
|
var StubHook = class {
|
|
130
|
+
// Like call(), but designed for streaming calls (e.g. WritableStream writes). Returns:
|
|
131
|
+
// - promise: A Promise<void> for the completion of the call.
|
|
132
|
+
// - size: If the call was remote, the byte size of the serialized message. For local calls,
|
|
133
|
+
// undefined is returned, indicating the caller should await the promise to serialize writes
|
|
134
|
+
// (no overlapping).
|
|
135
|
+
stream(path, args) {
|
|
136
|
+
let hook = this.call(path, args);
|
|
137
|
+
let pulled = hook.pull();
|
|
138
|
+
let promise;
|
|
139
|
+
if (pulled instanceof Promise) {
|
|
140
|
+
promise = pulled.then((p) => {
|
|
141
|
+
p.dispose();
|
|
142
|
+
});
|
|
143
|
+
} else {
|
|
144
|
+
pulled.dispose();
|
|
145
|
+
promise = Promise.resolve();
|
|
146
|
+
}
|
|
147
|
+
return { promise };
|
|
148
|
+
}
|
|
109
149
|
};
|
|
110
150
|
var ErrorStubHook = class extends StubHook {
|
|
111
151
|
constructor(error) {
|
|
@@ -154,7 +194,7 @@ function withCallInterceptor(interceptor, callback) {
|
|
|
154
194
|
doCall = oldValue;
|
|
155
195
|
}
|
|
156
196
|
}
|
|
157
|
-
var RAW_STUB = Symbol("realStub");
|
|
197
|
+
var RAW_STUB = /* @__PURE__ */ Symbol("realStub");
|
|
158
198
|
var PROXY_HANDLERS = {
|
|
159
199
|
apply(target, thisArg, argumentsList) {
|
|
160
200
|
let stub = target.raw;
|
|
@@ -330,10 +370,10 @@ async function pullPromise(promise) {
|
|
|
330
370
|
}
|
|
331
371
|
var RpcPayload = class _RpcPayload {
|
|
332
372
|
// Private constructor; use factory functions above to construct.
|
|
333
|
-
constructor(value, source,
|
|
373
|
+
constructor(value, source, hooks, promises) {
|
|
334
374
|
this.value = value;
|
|
335
375
|
this.source = source;
|
|
336
|
-
this.
|
|
376
|
+
this.hooks = hooks;
|
|
337
377
|
this.promises = promises;
|
|
338
378
|
}
|
|
339
379
|
// Create a payload from a value passed as params to an RPC from the app.
|
|
@@ -358,13 +398,13 @@ var RpcPayload = class _RpcPayload {
|
|
|
358
398
|
// stubs is transferred from the inputs to the outputs, hence if the output is disposed, the
|
|
359
399
|
// inputs should not be. (In case of exception, nothing is disposed, though.)
|
|
360
400
|
static fromArray(array) {
|
|
361
|
-
let
|
|
401
|
+
let hooks = [];
|
|
362
402
|
let promises = [];
|
|
363
403
|
let resultArray = [];
|
|
364
404
|
for (let payload of array) {
|
|
365
405
|
payload.ensureDeepCopied();
|
|
366
|
-
for (let
|
|
367
|
-
|
|
406
|
+
for (let hook of payload.hooks) {
|
|
407
|
+
hooks.push(hook);
|
|
368
408
|
}
|
|
369
409
|
for (let promise of payload.promises) {
|
|
370
410
|
if (promise.parent === payload) {
|
|
@@ -378,12 +418,12 @@ var RpcPayload = class _RpcPayload {
|
|
|
378
418
|
}
|
|
379
419
|
resultArray.push(payload.value);
|
|
380
420
|
}
|
|
381
|
-
return new _RpcPayload(resultArray, "owned",
|
|
421
|
+
return new _RpcPayload(resultArray, "owned", hooks, promises);
|
|
382
422
|
}
|
|
383
423
|
// Create a payload from a value parsed off the wire using Evaluator.evaluate().
|
|
384
424
|
//
|
|
385
|
-
// A payload is constructed with a null value and the given
|
|
386
|
-
// is expected to be filled in by the evaluator, and the
|
|
425
|
+
// A payload is constructed with a null value and the given hooks and promises arrays. The value
|
|
426
|
+
// is expected to be filled in by the evaluator, and the hooks and promises arrays are expected
|
|
387
427
|
// to be extended with stubs found during parsing. (This weird usage model is necessary so that
|
|
388
428
|
// if the root value turns out to be a promise, its `parent` in `promises` can be the payload
|
|
389
429
|
// object itself.)
|
|
@@ -391,8 +431,8 @@ var RpcPayload = class _RpcPayload {
|
|
|
391
431
|
// When done, the payload takes ownership of the final value and all the stubs within. It may
|
|
392
432
|
// modify the value in preparation for delivery, and may deliver the value directly to the app
|
|
393
433
|
// without copying.
|
|
394
|
-
static forEvaluate(
|
|
395
|
-
return new _RpcPayload(null, "owned",
|
|
434
|
+
static forEvaluate(hooks, promises) {
|
|
435
|
+
return new _RpcPayload(null, "owned", hooks, promises);
|
|
396
436
|
}
|
|
397
437
|
// Deep-copy the given value, including dup()ing all stubs.
|
|
398
438
|
//
|
|
@@ -414,14 +454,20 @@ var RpcPayload = class _RpcPayload {
|
|
|
414
454
|
return result;
|
|
415
455
|
}
|
|
416
456
|
// For `source === "return"` payloads only, this tracks any StubHooks created around RpcTargets
|
|
417
|
-
// found in the payload at the time that it is serialized (or deep-copied) for
|
|
418
|
-
// can make sure they are not disposed before the pipeline ends.
|
|
457
|
+
// or WritableStreams found in the payload at the time that it is serialized (or deep-copied) for
|
|
458
|
+
// return, so that we can make sure they are not disposed before the pipeline ends.
|
|
419
459
|
//
|
|
420
460
|
// This is initialized on first use.
|
|
421
461
|
rpcTargets;
|
|
422
462
|
// Get the StubHook representing the given RpcTarget found inside this payload.
|
|
423
463
|
getHookForRpcTarget(target, parent, dupStubs = true) {
|
|
424
464
|
if (this.source === "params") {
|
|
465
|
+
if (dupStubs) {
|
|
466
|
+
let dupable = target;
|
|
467
|
+
if (typeof dupable.dup === "function") {
|
|
468
|
+
target = dupable.dup();
|
|
469
|
+
}
|
|
470
|
+
}
|
|
425
471
|
return TargetStubHook.create(target, parent);
|
|
426
472
|
} else if (this.source === "return") {
|
|
427
473
|
let hook = this.rpcTargets?.get(target);
|
|
@@ -448,6 +494,64 @@ var RpcPayload = class _RpcPayload {
|
|
|
448
494
|
throw new Error("owned payload shouldn't contain raw RpcTargets");
|
|
449
495
|
}
|
|
450
496
|
}
|
|
497
|
+
// Get the StubHook representing the given WritableStream found inside this payload.
|
|
498
|
+
getHookForWritableStream(stream, parent, dupStubs = true) {
|
|
499
|
+
if (this.source === "params") {
|
|
500
|
+
return streamImpl.createWritableStreamHook(stream);
|
|
501
|
+
} else if (this.source === "return") {
|
|
502
|
+
let hook = this.rpcTargets?.get(stream);
|
|
503
|
+
if (hook) {
|
|
504
|
+
if (dupStubs) {
|
|
505
|
+
return hook.dup();
|
|
506
|
+
} else {
|
|
507
|
+
this.rpcTargets?.delete(stream);
|
|
508
|
+
return hook;
|
|
509
|
+
}
|
|
510
|
+
} else {
|
|
511
|
+
hook = streamImpl.createWritableStreamHook(stream);
|
|
512
|
+
if (dupStubs) {
|
|
513
|
+
if (!this.rpcTargets) {
|
|
514
|
+
this.rpcTargets = /* @__PURE__ */ new Map();
|
|
515
|
+
}
|
|
516
|
+
this.rpcTargets.set(stream, hook);
|
|
517
|
+
return hook.dup();
|
|
518
|
+
} else {
|
|
519
|
+
return hook;
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
} else {
|
|
523
|
+
throw new Error("owned payload shouldn't contain raw WritableStreams");
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
// Get the StubHook representing the given ReadableStream found inside this payload.
|
|
527
|
+
getHookForReadableStream(stream, parent, dupStubs = true) {
|
|
528
|
+
if (this.source === "params") {
|
|
529
|
+
return streamImpl.createReadableStreamHook(stream);
|
|
530
|
+
} else if (this.source === "return") {
|
|
531
|
+
let hook = this.rpcTargets?.get(stream);
|
|
532
|
+
if (hook) {
|
|
533
|
+
if (dupStubs) {
|
|
534
|
+
return hook.dup();
|
|
535
|
+
} else {
|
|
536
|
+
this.rpcTargets?.delete(stream);
|
|
537
|
+
return hook;
|
|
538
|
+
}
|
|
539
|
+
} else {
|
|
540
|
+
hook = streamImpl.createReadableStreamHook(stream);
|
|
541
|
+
if (dupStubs) {
|
|
542
|
+
if (!this.rpcTargets) {
|
|
543
|
+
this.rpcTargets = /* @__PURE__ */ new Map();
|
|
544
|
+
}
|
|
545
|
+
this.rpcTargets.set(stream, hook);
|
|
546
|
+
return hook.dup();
|
|
547
|
+
} else {
|
|
548
|
+
return hook;
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
} else {
|
|
552
|
+
throw new Error("owned payload shouldn't contain raw ReadableStreams");
|
|
553
|
+
}
|
|
554
|
+
}
|
|
451
555
|
deepCopy(value, oldParent, property, parent, dupStubs, owner) {
|
|
452
556
|
let kind = typeForRpc(value);
|
|
453
557
|
switch (kind) {
|
|
@@ -491,22 +595,21 @@ var RpcPayload = class _RpcPayload {
|
|
|
491
595
|
this.promises.push({ parent, property, promise });
|
|
492
596
|
return promise;
|
|
493
597
|
} else {
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
return newStub;
|
|
598
|
+
this.hooks.push(hook);
|
|
599
|
+
return new RpcStub(hook);
|
|
497
600
|
}
|
|
498
601
|
}
|
|
499
602
|
case "function":
|
|
500
603
|
case "rpc-target": {
|
|
501
604
|
let target = value;
|
|
502
|
-
let
|
|
605
|
+
let hook;
|
|
503
606
|
if (owner) {
|
|
504
|
-
|
|
607
|
+
hook = owner.getHookForRpcTarget(target, oldParent, dupStubs);
|
|
505
608
|
} else {
|
|
506
|
-
|
|
609
|
+
hook = TargetStubHook.create(target, oldParent);
|
|
507
610
|
}
|
|
508
|
-
this.
|
|
509
|
-
return
|
|
611
|
+
this.hooks.push(hook);
|
|
612
|
+
return new RpcStub(hook);
|
|
510
613
|
}
|
|
511
614
|
case "rpc-thenable": {
|
|
512
615
|
let target = value;
|
|
@@ -519,6 +622,44 @@ var RpcPayload = class _RpcPayload {
|
|
|
519
622
|
this.promises.push({ parent, property, promise });
|
|
520
623
|
return promise;
|
|
521
624
|
}
|
|
625
|
+
case "writable": {
|
|
626
|
+
let stream = value;
|
|
627
|
+
let hook;
|
|
628
|
+
if (owner) {
|
|
629
|
+
hook = owner.getHookForWritableStream(stream, oldParent, dupStubs);
|
|
630
|
+
} else {
|
|
631
|
+
hook = streamImpl.createWritableStreamHook(stream);
|
|
632
|
+
}
|
|
633
|
+
this.hooks.push(hook);
|
|
634
|
+
return stream;
|
|
635
|
+
}
|
|
636
|
+
case "readable": {
|
|
637
|
+
let stream = value;
|
|
638
|
+
let hook;
|
|
639
|
+
if (owner) {
|
|
640
|
+
hook = owner.getHookForReadableStream(stream, oldParent, dupStubs);
|
|
641
|
+
} else {
|
|
642
|
+
hook = streamImpl.createReadableStreamHook(stream);
|
|
643
|
+
}
|
|
644
|
+
this.hooks.push(hook);
|
|
645
|
+
return stream;
|
|
646
|
+
}
|
|
647
|
+
case "headers":
|
|
648
|
+
return new Headers(value);
|
|
649
|
+
case "request": {
|
|
650
|
+
let req = value;
|
|
651
|
+
if (req.body) {
|
|
652
|
+
this.deepCopy(req.body, req, "body", req, dupStubs, owner);
|
|
653
|
+
}
|
|
654
|
+
return new Request(req);
|
|
655
|
+
}
|
|
656
|
+
case "response": {
|
|
657
|
+
let resp = value;
|
|
658
|
+
if (resp.body) {
|
|
659
|
+
this.deepCopy(resp.body, resp, "body", resp, dupStubs, owner);
|
|
660
|
+
}
|
|
661
|
+
return new Response(resp.body, resp);
|
|
662
|
+
}
|
|
522
663
|
default:
|
|
523
664
|
throw new Error("unreachable");
|
|
524
665
|
}
|
|
@@ -528,12 +669,12 @@ var RpcPayload = class _RpcPayload {
|
|
|
528
669
|
ensureDeepCopied() {
|
|
529
670
|
if (this.source !== "owned") {
|
|
530
671
|
let dupStubs = this.source === "params";
|
|
531
|
-
this.
|
|
672
|
+
this.hooks = [];
|
|
532
673
|
this.promises = [];
|
|
533
674
|
try {
|
|
534
675
|
this.value = this.deepCopy(this.value, void 0, "value", this, dupStubs, this);
|
|
535
676
|
} catch (err) {
|
|
536
|
-
this.
|
|
677
|
+
this.hooks = void 0;
|
|
537
678
|
this.promises = void 0;
|
|
538
679
|
throw err;
|
|
539
680
|
}
|
|
@@ -636,7 +777,7 @@ var RpcPayload = class _RpcPayload {
|
|
|
636
777
|
}
|
|
637
778
|
dispose() {
|
|
638
779
|
if (this.source === "owned") {
|
|
639
|
-
this.
|
|
780
|
+
this.hooks.forEach((hook) => hook.dispose());
|
|
640
781
|
this.promises.forEach((promise) => promise.promise[Symbol.dispose]());
|
|
641
782
|
} else if (this.source === "return") {
|
|
642
783
|
this.disposeImpl(this.value, void 0);
|
|
@@ -645,7 +786,7 @@ var RpcPayload = class _RpcPayload {
|
|
|
645
786
|
}
|
|
646
787
|
} else ;
|
|
647
788
|
this.source = "owned";
|
|
648
|
-
this.
|
|
789
|
+
this.hooks = [];
|
|
649
790
|
this.promises = [];
|
|
650
791
|
}
|
|
651
792
|
// Recursive dispose, called only when `source` is "return".
|
|
@@ -698,6 +839,40 @@ var RpcPayload = class _RpcPayload {
|
|
|
698
839
|
}
|
|
699
840
|
case "rpc-thenable":
|
|
700
841
|
return;
|
|
842
|
+
case "headers":
|
|
843
|
+
return;
|
|
844
|
+
case "request": {
|
|
845
|
+
let req = value;
|
|
846
|
+
if (req.body) this.disposeImpl(req.body, req);
|
|
847
|
+
return;
|
|
848
|
+
}
|
|
849
|
+
case "response": {
|
|
850
|
+
let resp = value;
|
|
851
|
+
if (resp.body) this.disposeImpl(resp.body, resp);
|
|
852
|
+
return;
|
|
853
|
+
}
|
|
854
|
+
case "writable": {
|
|
855
|
+
let stream = value;
|
|
856
|
+
let hook = this.rpcTargets?.get(stream);
|
|
857
|
+
if (hook) {
|
|
858
|
+
this.rpcTargets.delete(stream);
|
|
859
|
+
} else {
|
|
860
|
+
hook = streamImpl.createWritableStreamHook(stream);
|
|
861
|
+
}
|
|
862
|
+
hook.dispose();
|
|
863
|
+
return;
|
|
864
|
+
}
|
|
865
|
+
case "readable": {
|
|
866
|
+
let stream = value;
|
|
867
|
+
let hook = this.rpcTargets?.get(stream);
|
|
868
|
+
if (hook) {
|
|
869
|
+
this.rpcTargets.delete(stream);
|
|
870
|
+
} else {
|
|
871
|
+
hook = streamImpl.createReadableStreamHook(stream);
|
|
872
|
+
}
|
|
873
|
+
hook.dispose();
|
|
874
|
+
return;
|
|
875
|
+
}
|
|
701
876
|
default:
|
|
702
877
|
return;
|
|
703
878
|
}
|
|
@@ -706,9 +881,9 @@ var RpcPayload = class _RpcPayload {
|
|
|
706
881
|
// *would* be awaited if this payload were to be delivered. See the similarly-named method of
|
|
707
882
|
// StubHook for explanation.
|
|
708
883
|
ignoreUnhandledRejections() {
|
|
709
|
-
if (this.
|
|
710
|
-
this.
|
|
711
|
-
|
|
884
|
+
if (this.hooks) {
|
|
885
|
+
this.hooks.forEach((hook) => {
|
|
886
|
+
hook.ignoreUnhandledRejections();
|
|
712
887
|
});
|
|
713
888
|
this.promises.forEach(
|
|
714
889
|
(promise) => unwrapStubOrParent(promise.promise).ignoreUnhandledRejections()
|
|
@@ -729,6 +904,11 @@ var RpcPayload = class _RpcPayload {
|
|
|
729
904
|
case "undefined":
|
|
730
905
|
case "function":
|
|
731
906
|
case "rpc-target":
|
|
907
|
+
case "writable":
|
|
908
|
+
case "readable":
|
|
909
|
+
case "headers":
|
|
910
|
+
case "request":
|
|
911
|
+
case "response":
|
|
732
912
|
return;
|
|
733
913
|
case "array": {
|
|
734
914
|
let array = value;
|
|
@@ -801,11 +981,20 @@ function followPath(value, parent, path, owner) {
|
|
|
801
981
|
let { hook, pathIfPromise } = unwrapStubAndPath(value);
|
|
802
982
|
return { hook, remainingPath: pathIfPromise ? pathIfPromise.concat(path.slice(i)) : path.slice(i) };
|
|
803
983
|
}
|
|
984
|
+
case "writable":
|
|
985
|
+
value = void 0;
|
|
986
|
+
break;
|
|
987
|
+
case "readable":
|
|
988
|
+
value = void 0;
|
|
989
|
+
break;
|
|
804
990
|
case "primitive":
|
|
805
991
|
case "bigint":
|
|
806
992
|
case "bytes":
|
|
807
993
|
case "date":
|
|
808
994
|
case "error":
|
|
995
|
+
case "headers":
|
|
996
|
+
case "request":
|
|
997
|
+
case "response":
|
|
809
998
|
value = void 0;
|
|
810
999
|
break;
|
|
811
1000
|
case "undefined":
|
|
@@ -1040,6 +1229,14 @@ var PromiseStubHook = class _PromiseStubHook extends StubHook {
|
|
|
1040
1229
|
args.ensureDeepCopied();
|
|
1041
1230
|
return new _PromiseStubHook(this.promise.then((hook) => hook.call(path, args)));
|
|
1042
1231
|
}
|
|
1232
|
+
stream(path, args) {
|
|
1233
|
+
args.ensureDeepCopied();
|
|
1234
|
+
let promise = this.promise.then((hook) => {
|
|
1235
|
+
let result = hook.stream(path, args);
|
|
1236
|
+
return result.promise;
|
|
1237
|
+
});
|
|
1238
|
+
return { promise };
|
|
1239
|
+
}
|
|
1043
1240
|
map(path, captures, instructions) {
|
|
1044
1241
|
return new _PromiseStubHook(this.promise.then(
|
|
1045
1242
|
(hook) => hook.map(path, captures, instructions),
|
|
@@ -1112,6 +1309,9 @@ var NullExporter = class {
|
|
|
1112
1309
|
}
|
|
1113
1310
|
unexport(ids) {
|
|
1114
1311
|
}
|
|
1312
|
+
createPipe(readable) {
|
|
1313
|
+
throw new Error("Cannot create pipes without an RPC session.");
|
|
1314
|
+
}
|
|
1115
1315
|
onSendError(error) {
|
|
1116
1316
|
}
|
|
1117
1317
|
};
|
|
@@ -1216,6 +1416,73 @@ var Devaluator = class _Devaluator {
|
|
|
1216
1416
|
];
|
|
1217
1417
|
}
|
|
1218
1418
|
}
|
|
1419
|
+
case "headers":
|
|
1420
|
+
return ["headers", [...value]];
|
|
1421
|
+
case "request": {
|
|
1422
|
+
let req = value;
|
|
1423
|
+
let init = {};
|
|
1424
|
+
if (req.method !== "GET") init.method = req.method;
|
|
1425
|
+
let headers = [...req.headers];
|
|
1426
|
+
if (headers.length > 0) {
|
|
1427
|
+
init.headers = headers;
|
|
1428
|
+
}
|
|
1429
|
+
if (req.body) {
|
|
1430
|
+
init.body = this.devaluateImpl(req.body, req, depth + 1);
|
|
1431
|
+
init.duplex = req.duplex || "half";
|
|
1432
|
+
} else if (req.body === void 0 && !["GET", "HEAD", "OPTIONS", "TRACE", "DELETE"].includes(req.method)) {
|
|
1433
|
+
let bodyPromise = req.arrayBuffer();
|
|
1434
|
+
let readable = new ReadableStream({
|
|
1435
|
+
async start(controller) {
|
|
1436
|
+
try {
|
|
1437
|
+
controller.enqueue(new Uint8Array(await bodyPromise));
|
|
1438
|
+
controller.close();
|
|
1439
|
+
} catch (err) {
|
|
1440
|
+
controller.error(err);
|
|
1441
|
+
}
|
|
1442
|
+
}
|
|
1443
|
+
});
|
|
1444
|
+
let hook = streamImpl.createReadableStreamHook(readable);
|
|
1445
|
+
let importId = this.exporter.createPipe(readable, hook);
|
|
1446
|
+
init.body = ["readable", importId];
|
|
1447
|
+
init.duplex = req.duplex || "half";
|
|
1448
|
+
}
|
|
1449
|
+
if (req.cache && req.cache !== "default") init.cache = req.cache;
|
|
1450
|
+
if (req.redirect !== "follow") init.redirect = req.redirect;
|
|
1451
|
+
if (req.integrity) init.integrity = req.integrity;
|
|
1452
|
+
if (req.mode && req.mode !== "cors") init.mode = req.mode;
|
|
1453
|
+
if (req.credentials && req.credentials !== "same-origin") {
|
|
1454
|
+
init.credentials = req.credentials;
|
|
1455
|
+
}
|
|
1456
|
+
if (req.referrer && req.referrer !== "about:client") init.referrer = req.referrer;
|
|
1457
|
+
if (req.referrerPolicy) init.referrerPolicy = req.referrerPolicy;
|
|
1458
|
+
if (req.keepalive) init.keepalive = req.keepalive;
|
|
1459
|
+
let cfReq = req;
|
|
1460
|
+
if (cfReq.cf) init.cf = cfReq.cf;
|
|
1461
|
+
if (cfReq.encodeResponseBody && cfReq.encodeResponseBody !== "automatic") {
|
|
1462
|
+
init.encodeResponseBody = cfReq.encodeResponseBody;
|
|
1463
|
+
}
|
|
1464
|
+
return ["request", req.url, init];
|
|
1465
|
+
}
|
|
1466
|
+
case "response": {
|
|
1467
|
+
let resp = value;
|
|
1468
|
+
let body = this.devaluateImpl(resp.body, resp, depth + 1);
|
|
1469
|
+
let init = {};
|
|
1470
|
+
if (resp.status !== 200) init.status = resp.status;
|
|
1471
|
+
if (resp.statusText) init.statusText = resp.statusText;
|
|
1472
|
+
let headers = [...resp.headers];
|
|
1473
|
+
if (headers.length > 0) {
|
|
1474
|
+
init.headers = headers;
|
|
1475
|
+
}
|
|
1476
|
+
let cfResp = resp;
|
|
1477
|
+
if (cfResp.cf) init.cf = cfResp.cf;
|
|
1478
|
+
if (cfResp.encodeBody && cfResp.encodeBody !== "automatic") {
|
|
1479
|
+
init.encodeBody = cfResp.encodeBody;
|
|
1480
|
+
}
|
|
1481
|
+
if (cfResp.webSocket) {
|
|
1482
|
+
throw new TypeError("Can't serialize a Response containing a webSocket.");
|
|
1483
|
+
}
|
|
1484
|
+
return ["response", body, init];
|
|
1485
|
+
}
|
|
1219
1486
|
case "error": {
|
|
1220
1487
|
let e = value;
|
|
1221
1488
|
let rewritten = this.exporter.onSendError(e);
|
|
@@ -1270,6 +1537,22 @@ var Devaluator = class _Devaluator {
|
|
|
1270
1537
|
let hook = this.source.getHookForRpcTarget(value, parent);
|
|
1271
1538
|
return this.devaluateHook("promise", hook);
|
|
1272
1539
|
}
|
|
1540
|
+
case "writable": {
|
|
1541
|
+
if (!this.source) {
|
|
1542
|
+
throw new Error("Can't serialize WritableStream in this context.");
|
|
1543
|
+
}
|
|
1544
|
+
let hook = this.source.getHookForWritableStream(value, parent);
|
|
1545
|
+
return this.devaluateHook("writable", hook);
|
|
1546
|
+
}
|
|
1547
|
+
case "readable": {
|
|
1548
|
+
if (!this.source) {
|
|
1549
|
+
throw new Error("Can't serialize ReadableStream in this context.");
|
|
1550
|
+
}
|
|
1551
|
+
let ws = value;
|
|
1552
|
+
let hook = this.source.getHookForReadableStream(ws, parent);
|
|
1553
|
+
let importId = this.exporter.createPipe(ws, hook);
|
|
1554
|
+
return ["readable", importId];
|
|
1555
|
+
}
|
|
1273
1556
|
default:
|
|
1274
1557
|
throw new Error("unreachable");
|
|
1275
1558
|
}
|
|
@@ -1294,16 +1577,27 @@ var NullImporter = class {
|
|
|
1294
1577
|
getExport(idx) {
|
|
1295
1578
|
return void 0;
|
|
1296
1579
|
}
|
|
1580
|
+
getPipeReadable(exportId) {
|
|
1581
|
+
throw new Error("Cannot retrieve pipe readable without an RPC session.");
|
|
1582
|
+
}
|
|
1297
1583
|
};
|
|
1298
1584
|
var NULL_IMPORTER = new NullImporter();
|
|
1585
|
+
function fixBrokenRequestBody(request, body) {
|
|
1586
|
+
let promise = new Response(body).arrayBuffer().then((arrayBuffer) => {
|
|
1587
|
+
let bytes = new Uint8Array(arrayBuffer);
|
|
1588
|
+
let result = new Request(request, { body: bytes });
|
|
1589
|
+
return new PayloadStubHook(RpcPayload.fromAppReturn(result));
|
|
1590
|
+
});
|
|
1591
|
+
return new RpcPromise(new PromiseStubHook(promise), []);
|
|
1592
|
+
}
|
|
1299
1593
|
var Evaluator = class _Evaluator {
|
|
1300
1594
|
constructor(importer) {
|
|
1301
1595
|
this.importer = importer;
|
|
1302
1596
|
}
|
|
1303
|
-
|
|
1597
|
+
hooks = [];
|
|
1304
1598
|
promises = [];
|
|
1305
1599
|
evaluate(value) {
|
|
1306
|
-
let payload = RpcPayload.forEvaluate(this.
|
|
1600
|
+
let payload = RpcPayload.forEvaluate(this.hooks, this.promises);
|
|
1307
1601
|
try {
|
|
1308
1602
|
payload.value = this.evaluateImpl(value, payload, "value");
|
|
1309
1603
|
return payload;
|
|
@@ -1373,6 +1667,56 @@ var Evaluator = class _Evaluator {
|
|
|
1373
1667
|
return -Infinity;
|
|
1374
1668
|
case "nan":
|
|
1375
1669
|
return NaN;
|
|
1670
|
+
case "headers":
|
|
1671
|
+
if (value.length === 2 && value[1] instanceof Array) {
|
|
1672
|
+
return new Headers(value[1]);
|
|
1673
|
+
}
|
|
1674
|
+
break;
|
|
1675
|
+
case "request": {
|
|
1676
|
+
if (value.length !== 3 || typeof value[1] !== "string") break;
|
|
1677
|
+
let url = value[1];
|
|
1678
|
+
let init = value[2];
|
|
1679
|
+
if (typeof init !== "object" || init === null) break;
|
|
1680
|
+
if (init.body) {
|
|
1681
|
+
init.body = this.evaluateImpl(init.body, init, "body");
|
|
1682
|
+
if (init.body === null || typeof init.body === "string" || init.body instanceof Uint8Array || init.body instanceof ReadableStream) ; else {
|
|
1683
|
+
throw new TypeError("Request body must be of type ReadableStream.");
|
|
1684
|
+
}
|
|
1685
|
+
}
|
|
1686
|
+
if (init.signal) {
|
|
1687
|
+
init.signal = this.evaluateImpl(init.signal, init, "signal");
|
|
1688
|
+
if (!(init.signal instanceof AbortSignal)) {
|
|
1689
|
+
throw new TypeError("Request siganl must be of type AbortSignal.");
|
|
1690
|
+
}
|
|
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
|
+
let result = new Request(url, init);
|
|
1696
|
+
if (init.body instanceof ReadableStream && result.body === void 0) {
|
|
1697
|
+
let promise = fixBrokenRequestBody(result, init.body);
|
|
1698
|
+
this.promises.push({ promise, parent, property });
|
|
1699
|
+
return promise;
|
|
1700
|
+
} else {
|
|
1701
|
+
return result;
|
|
1702
|
+
}
|
|
1703
|
+
}
|
|
1704
|
+
case "response": {
|
|
1705
|
+
if (value.length !== 3) break;
|
|
1706
|
+
let body = this.evaluateImpl(value[1], parent, property);
|
|
1707
|
+
if (body === null || typeof body === "string" || body instanceof Uint8Array || body instanceof ReadableStream) ; else {
|
|
1708
|
+
throw new TypeError("Response body must be of type ReadableStream.");
|
|
1709
|
+
}
|
|
1710
|
+
let init = value[2];
|
|
1711
|
+
if (typeof init !== "object" || init === null) break;
|
|
1712
|
+
if (init.webSocket) {
|
|
1713
|
+
throw new TypeError("Can't deserialize a Response containing a webSocket.");
|
|
1714
|
+
}
|
|
1715
|
+
if (init.headers && !(init.headers instanceof Array)) {
|
|
1716
|
+
throw new TypeError("Request headers must be serialized as an array of pairs.");
|
|
1717
|
+
}
|
|
1718
|
+
return new Response(body, init);
|
|
1719
|
+
}
|
|
1376
1720
|
case "import":
|
|
1377
1721
|
case "pipeline": {
|
|
1378
1722
|
if (value.length < 2 || value.length > 4) {
|
|
@@ -1392,9 +1736,8 @@ var Evaluator = class _Evaluator {
|
|
|
1392
1736
|
this.promises.push({ promise, parent, property });
|
|
1393
1737
|
return promise;
|
|
1394
1738
|
} else {
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
return stub;
|
|
1739
|
+
this.hooks.push(hook2);
|
|
1740
|
+
return new RpcPromise(hook2, []);
|
|
1398
1741
|
}
|
|
1399
1742
|
};
|
|
1400
1743
|
if (value.length == 2) {
|
|
@@ -1472,12 +1815,27 @@ var Evaluator = class _Evaluator {
|
|
|
1472
1815
|
return promise;
|
|
1473
1816
|
} else {
|
|
1474
1817
|
let hook = this.importer.importStub(value[1]);
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
return stub;
|
|
1818
|
+
this.hooks.push(hook);
|
|
1819
|
+
return new RpcStub(hook);
|
|
1478
1820
|
}
|
|
1479
1821
|
}
|
|
1480
1822
|
break;
|
|
1823
|
+
case "writable":
|
|
1824
|
+
if (typeof value[1] == "number") {
|
|
1825
|
+
let hook = this.importer.importStub(value[1]);
|
|
1826
|
+
let stream = streamImpl.createWritableStreamFromHook(hook);
|
|
1827
|
+
this.hooks.push(hook);
|
|
1828
|
+
return stream;
|
|
1829
|
+
}
|
|
1830
|
+
break;
|
|
1831
|
+
case "readable":
|
|
1832
|
+
if (typeof value[1] == "number") {
|
|
1833
|
+
let stream = this.importer.getPipeReadable(value[1]);
|
|
1834
|
+
let hook = streamImpl.createReadableStreamHook(stream);
|
|
1835
|
+
this.hooks.push(hook);
|
|
1836
|
+
return stream;
|
|
1837
|
+
}
|
|
1838
|
+
break;
|
|
1481
1839
|
}
|
|
1482
1840
|
throw new TypeError(`unknown special value: ${JSON.stringify(value)}`);
|
|
1483
1841
|
} else if (value instanceof Object) {
|
|
@@ -1617,6 +1975,14 @@ var RpcImportHook = class _RpcImportHook extends StubHook {
|
|
|
1617
1975
|
return entry.session.sendCall(entry.importId, path, args);
|
|
1618
1976
|
}
|
|
1619
1977
|
}
|
|
1978
|
+
stream(path, args) {
|
|
1979
|
+
let entry = this.getEntry();
|
|
1980
|
+
if (entry.resolution) {
|
|
1981
|
+
return entry.resolution.stream(path, args);
|
|
1982
|
+
} else {
|
|
1983
|
+
return entry.session.sendStream(entry.importId, path, args);
|
|
1984
|
+
}
|
|
1985
|
+
}
|
|
1620
1986
|
map(path, captures, instructions) {
|
|
1621
1987
|
let entry;
|
|
1622
1988
|
try {
|
|
@@ -1789,19 +2155,23 @@ var RpcSessionImpl = class {
|
|
|
1789
2155
|
return payload;
|
|
1790
2156
|
}
|
|
1791
2157
|
};
|
|
2158
|
+
let autoRelease = exp.autoRelease;
|
|
1792
2159
|
++this.pullCount;
|
|
1793
2160
|
exp.pull = resolve().then(
|
|
1794
2161
|
(payload) => {
|
|
1795
2162
|
let value = Devaluator.devaluate(payload.value, void 0, this, payload);
|
|
1796
2163
|
this.send(["resolve", exportId, value]);
|
|
2164
|
+
if (autoRelease) this.releaseExport(exportId, 1);
|
|
1797
2165
|
},
|
|
1798
2166
|
(error) => {
|
|
1799
2167
|
this.send(["reject", exportId, Devaluator.devaluate(error, void 0, this)]);
|
|
2168
|
+
if (autoRelease) this.releaseExport(exportId, 1);
|
|
1800
2169
|
}
|
|
1801
2170
|
).catch(
|
|
1802
2171
|
(error) => {
|
|
1803
2172
|
try {
|
|
1804
2173
|
this.send(["reject", exportId, Devaluator.devaluate(error, void 0, this)]);
|
|
2174
|
+
if (autoRelease) this.releaseExport(exportId, 1);
|
|
1805
2175
|
} catch (error2) {
|
|
1806
2176
|
this.abort(error2);
|
|
1807
2177
|
}
|
|
@@ -1853,9 +2223,35 @@ var RpcSessionImpl = class {
|
|
|
1853
2223
|
getExport(idx) {
|
|
1854
2224
|
return this.exports[idx]?.hook;
|
|
1855
2225
|
}
|
|
2226
|
+
getPipeReadable(exportId) {
|
|
2227
|
+
let entry = this.exports[exportId];
|
|
2228
|
+
if (!entry || !entry.pipeReadable) {
|
|
2229
|
+
throw new Error(`Export ${exportId} is not a pipe or its readable end was already consumed.`);
|
|
2230
|
+
}
|
|
2231
|
+
let readable = entry.pipeReadable;
|
|
2232
|
+
entry.pipeReadable = void 0;
|
|
2233
|
+
return readable;
|
|
2234
|
+
}
|
|
2235
|
+
createPipe(readable, readableHook) {
|
|
2236
|
+
if (this.abortReason) throw this.abortReason;
|
|
2237
|
+
this.send(["pipe"]);
|
|
2238
|
+
let importId = this.imports.length;
|
|
2239
|
+
let entry = new ImportTableEntry(this, importId, false);
|
|
2240
|
+
this.imports.push(entry);
|
|
2241
|
+
let hook = new RpcImportHook(
|
|
2242
|
+
/*isPromise=*/
|
|
2243
|
+
false,
|
|
2244
|
+
entry
|
|
2245
|
+
);
|
|
2246
|
+
let writable = streamImpl.createWritableStreamFromHook(hook);
|
|
2247
|
+
readable.pipeTo(writable).catch(() => {
|
|
2248
|
+
}).finally(() => readableHook.dispose());
|
|
2249
|
+
return importId;
|
|
2250
|
+
}
|
|
2251
|
+
// Serializes and sends a message. Returns the byte length of the serialized message.
|
|
1856
2252
|
send(msg) {
|
|
1857
2253
|
if (this.abortReason !== void 0) {
|
|
1858
|
-
return;
|
|
2254
|
+
return 0;
|
|
1859
2255
|
}
|
|
1860
2256
|
let msgText;
|
|
1861
2257
|
try {
|
|
@@ -1868,6 +2264,7 @@ var RpcSessionImpl = class {
|
|
|
1868
2264
|
throw err;
|
|
1869
2265
|
}
|
|
1870
2266
|
this.transport.send(msgText).catch((err) => this.abort(err, false));
|
|
2267
|
+
return msgText.length;
|
|
1871
2268
|
}
|
|
1872
2269
|
sendCall(id, path, args) {
|
|
1873
2270
|
if (this.abortReason) throw this.abortReason;
|
|
@@ -1885,6 +2282,34 @@ var RpcSessionImpl = class {
|
|
|
1885
2282
|
entry
|
|
1886
2283
|
);
|
|
1887
2284
|
}
|
|
2285
|
+
sendStream(id, path, args) {
|
|
2286
|
+
if (this.abortReason) throw this.abortReason;
|
|
2287
|
+
let value = ["pipeline", id, path];
|
|
2288
|
+
let devalue = Devaluator.devaluate(args.value, void 0, this, args);
|
|
2289
|
+
value.push(devalue[0]);
|
|
2290
|
+
let size = this.send(["stream", value]);
|
|
2291
|
+
let importId = this.imports.length;
|
|
2292
|
+
let entry = new ImportTableEntry(
|
|
2293
|
+
this,
|
|
2294
|
+
importId,
|
|
2295
|
+
/*pulling=*/
|
|
2296
|
+
true
|
|
2297
|
+
);
|
|
2298
|
+
entry.remoteRefcount = 0;
|
|
2299
|
+
entry.localRefcount = 1;
|
|
2300
|
+
this.imports.push(entry);
|
|
2301
|
+
let promise = entry.awaitResolution().then(
|
|
2302
|
+
(p) => {
|
|
2303
|
+
p.dispose();
|
|
2304
|
+
delete this.imports[importId];
|
|
2305
|
+
},
|
|
2306
|
+
(err) => {
|
|
2307
|
+
delete this.imports[importId];
|
|
2308
|
+
throw err;
|
|
2309
|
+
}
|
|
2310
|
+
);
|
|
2311
|
+
return { promise, size };
|
|
2312
|
+
}
|
|
1888
2313
|
sendMap(id, path, captures, instructions) {
|
|
1889
2314
|
if (this.abortReason) {
|
|
1890
2315
|
for (let cap of captures) {
|
|
@@ -1972,6 +2397,24 @@ var RpcSessionImpl = class {
|
|
|
1972
2397
|
continue;
|
|
1973
2398
|
}
|
|
1974
2399
|
break;
|
|
2400
|
+
case "stream": {
|
|
2401
|
+
if (msg.length > 1) {
|
|
2402
|
+
let payload = new Evaluator(this).evaluate(msg[1]);
|
|
2403
|
+
let hook = new PayloadStubHook(payload);
|
|
2404
|
+
hook.ignoreUnhandledRejections();
|
|
2405
|
+
let exportId = this.exports.length;
|
|
2406
|
+
this.exports.push({ hook, refcount: 1, autoRelease: true });
|
|
2407
|
+
this.ensureResolvingExport(exportId);
|
|
2408
|
+
continue;
|
|
2409
|
+
}
|
|
2410
|
+
break;
|
|
2411
|
+
}
|
|
2412
|
+
case "pipe": {
|
|
2413
|
+
let { readable, writable } = new TransformStream();
|
|
2414
|
+
let hook = streamImpl.createWritableStreamHook(writable);
|
|
2415
|
+
this.exports.push({ hook, refcount: 1, pipeReadable: readable });
|
|
2416
|
+
continue;
|
|
2417
|
+
}
|
|
1975
2418
|
case "pull": {
|
|
1976
2419
|
let exportId = msg[1];
|
|
1977
2420
|
if (typeof exportId == "number") {
|
|
@@ -2467,6 +2910,9 @@ var MapBuilder = class {
|
|
|
2467
2910
|
}
|
|
2468
2911
|
unexport(ids) {
|
|
2469
2912
|
}
|
|
2913
|
+
createPipe(readable) {
|
|
2914
|
+
throw new Error("Cannot send ReadableStream inside a mapper function.");
|
|
2915
|
+
}
|
|
2470
2916
|
onSendError(error) {
|
|
2471
2917
|
}
|
|
2472
2918
|
};
|
|
@@ -2576,6 +3022,9 @@ var MapApplicator = class {
|
|
|
2576
3022
|
return this.variables[idx];
|
|
2577
3023
|
}
|
|
2578
3024
|
}
|
|
3025
|
+
getPipeReadable(exportId) {
|
|
3026
|
+
throw new Error("A mapper function cannot use pipe readables.");
|
|
3027
|
+
}
|
|
2579
3028
|
};
|
|
2580
3029
|
function applyMapToElement(input, parent, owner, captures, instructions) {
|
|
2581
3030
|
let inputHook = new PayloadStubHook(RpcPayload.deepCopyFrom(input, parent, owner));
|
|
@@ -2616,6 +3065,333 @@ mapImpl.applyMap = (input, parent, owner, captures, instructions) => {
|
|
|
2616
3065
|
}
|
|
2617
3066
|
}
|
|
2618
3067
|
};
|
|
3068
|
+
|
|
3069
|
+
// src/streams.ts
|
|
3070
|
+
var WritableStreamStubHook = class _WritableStreamStubHook extends StubHook {
|
|
3071
|
+
state;
|
|
3072
|
+
// undefined when disposed
|
|
3073
|
+
// Creates a new WritableStreamStubHook that is not duplicated from an existing hook.
|
|
3074
|
+
static create(stream) {
|
|
3075
|
+
let writer = stream.getWriter();
|
|
3076
|
+
return new _WritableStreamStubHook({ refcount: 1, writer, closed: false });
|
|
3077
|
+
}
|
|
3078
|
+
constructor(state, dupFrom) {
|
|
3079
|
+
super();
|
|
3080
|
+
this.state = state;
|
|
3081
|
+
if (dupFrom) {
|
|
3082
|
+
++state.refcount;
|
|
3083
|
+
}
|
|
3084
|
+
}
|
|
3085
|
+
getState() {
|
|
3086
|
+
if (this.state) {
|
|
3087
|
+
return this.state;
|
|
3088
|
+
} else {
|
|
3089
|
+
throw new Error("Attempted to use a WritableStreamStubHook after it was disposed.");
|
|
3090
|
+
}
|
|
3091
|
+
}
|
|
3092
|
+
call(path, args) {
|
|
3093
|
+
try {
|
|
3094
|
+
let state = this.getState();
|
|
3095
|
+
if (path.length !== 1 || typeof path[0] !== "string") {
|
|
3096
|
+
throw new Error("WritableStream stub only supports direct method calls");
|
|
3097
|
+
}
|
|
3098
|
+
const method = path[0];
|
|
3099
|
+
if (method !== "write" && method !== "close" && method !== "abort") {
|
|
3100
|
+
args.dispose();
|
|
3101
|
+
throw new Error(`Unknown WritableStream method: ${method}`);
|
|
3102
|
+
}
|
|
3103
|
+
if (method === "close" || method === "abort") {
|
|
3104
|
+
state.closed = true;
|
|
3105
|
+
}
|
|
3106
|
+
let func = state.writer[method];
|
|
3107
|
+
let promise = args.deliverCall(func, state.writer);
|
|
3108
|
+
return new PromiseStubHook(promise.then((payload) => new PayloadStubHook(payload)));
|
|
3109
|
+
} catch (err) {
|
|
3110
|
+
return new ErrorStubHook(err);
|
|
3111
|
+
}
|
|
3112
|
+
}
|
|
3113
|
+
map(path, captures, instructions) {
|
|
3114
|
+
for (let cap of captures) {
|
|
3115
|
+
cap.dispose();
|
|
3116
|
+
}
|
|
3117
|
+
return new ErrorStubHook(new Error("Cannot use map() on a WritableStream"));
|
|
3118
|
+
}
|
|
3119
|
+
get(path) {
|
|
3120
|
+
return new ErrorStubHook(new Error("Cannot access properties on a WritableStream stub"));
|
|
3121
|
+
}
|
|
3122
|
+
dup() {
|
|
3123
|
+
let state = this.getState();
|
|
3124
|
+
return new _WritableStreamStubHook(state, this);
|
|
3125
|
+
}
|
|
3126
|
+
pull() {
|
|
3127
|
+
return Promise.reject(new Error("Cannot pull a WritableStream stub"));
|
|
3128
|
+
}
|
|
3129
|
+
ignoreUnhandledRejections() {
|
|
3130
|
+
}
|
|
3131
|
+
dispose() {
|
|
3132
|
+
let state = this.state;
|
|
3133
|
+
this.state = void 0;
|
|
3134
|
+
if (state) {
|
|
3135
|
+
if (--state.refcount === 0) {
|
|
3136
|
+
if (!state.closed) {
|
|
3137
|
+
state.writer.abort(new Error("WritableStream RPC stub was disposed without calling close()")).catch(() => {
|
|
3138
|
+
});
|
|
3139
|
+
}
|
|
3140
|
+
state.writer.releaseLock();
|
|
3141
|
+
}
|
|
3142
|
+
}
|
|
3143
|
+
}
|
|
3144
|
+
onBroken(callback) {
|
|
3145
|
+
}
|
|
3146
|
+
};
|
|
3147
|
+
var INITIAL_WINDOW = 256 * 1024;
|
|
3148
|
+
var MAX_WINDOW = 1024 * 1024 * 1024;
|
|
3149
|
+
var MIN_WINDOW = 64 * 1024;
|
|
3150
|
+
var STARTUP_GROWTH_FACTOR = 2;
|
|
3151
|
+
var STEADY_GROWTH_FACTOR = 1.25;
|
|
3152
|
+
var DECAY_FACTOR = 0.9;
|
|
3153
|
+
var STARTUP_EXIT_ROUNDS = 3;
|
|
3154
|
+
var FlowController = class {
|
|
3155
|
+
constructor(now) {
|
|
3156
|
+
this.now = now;
|
|
3157
|
+
}
|
|
3158
|
+
// The current window size in bytes. The sender blocks when bytesInFlight >= window.
|
|
3159
|
+
window = INITIAL_WINDOW;
|
|
3160
|
+
// Total bytes currently in flight (sent but not yet acked).
|
|
3161
|
+
bytesInFlight = 0;
|
|
3162
|
+
// Whether we're still in the startup phase.
|
|
3163
|
+
inStartupPhase = true;
|
|
3164
|
+
// ----- BDP estimation state (private) -----
|
|
3165
|
+
// Total bytes acked so far.
|
|
3166
|
+
delivered = 0;
|
|
3167
|
+
// Time of most recent ack.
|
|
3168
|
+
deliveredTime = 0;
|
|
3169
|
+
// Time when the very first ack was received.
|
|
3170
|
+
firstAckTime = 0;
|
|
3171
|
+
firstAckDelivered = 0;
|
|
3172
|
+
// Global minimum RTT observed (milliseconds).
|
|
3173
|
+
minRtt = Infinity;
|
|
3174
|
+
// For startup exit: count of consecutive RTT rounds where the window didn't meaningfully grow.
|
|
3175
|
+
roundsWithoutIncrease = 0;
|
|
3176
|
+
// Window size at the start of the current round, for startup exit detection.
|
|
3177
|
+
lastRoundWindow = 0;
|
|
3178
|
+
// Time when the current round started.
|
|
3179
|
+
roundStartTime = 0;
|
|
3180
|
+
// Called when a write of `size` bytes is about to be sent. Returns a token that must be
|
|
3181
|
+
// passed to onAck() when the ack arrives, and whether the sender should block (window full).
|
|
3182
|
+
onSend(size) {
|
|
3183
|
+
this.bytesInFlight += size;
|
|
3184
|
+
let token = {
|
|
3185
|
+
sentTime: this.now(),
|
|
3186
|
+
size,
|
|
3187
|
+
deliveredAtSend: this.delivered,
|
|
3188
|
+
deliveredTimeAtSend: this.deliveredTime,
|
|
3189
|
+
windowAtSend: this.window,
|
|
3190
|
+
windowFullAtSend: this.bytesInFlight >= this.window
|
|
3191
|
+
};
|
|
3192
|
+
return { token, shouldBlock: token.windowFullAtSend };
|
|
3193
|
+
}
|
|
3194
|
+
// Called when a previously-sent write fails. Restores bytesInFlight without updating
|
|
3195
|
+
// any BDP estimates.
|
|
3196
|
+
onError(token) {
|
|
3197
|
+
this.bytesInFlight -= token.size;
|
|
3198
|
+
}
|
|
3199
|
+
// Called when an ack is received for a previously-sent write. Updates BDP estimates and
|
|
3200
|
+
// the window. Returns whether a blocked sender should now unblock.
|
|
3201
|
+
onAck(token) {
|
|
3202
|
+
let ackTime = this.now();
|
|
3203
|
+
this.delivered += token.size;
|
|
3204
|
+
this.deliveredTime = ackTime;
|
|
3205
|
+
this.bytesInFlight -= token.size;
|
|
3206
|
+
let rtt = ackTime - token.sentTime;
|
|
3207
|
+
this.minRtt = Math.min(this.minRtt, rtt);
|
|
3208
|
+
if (this.firstAckTime === 0) {
|
|
3209
|
+
this.firstAckTime = ackTime;
|
|
3210
|
+
this.firstAckDelivered = this.delivered;
|
|
3211
|
+
} else {
|
|
3212
|
+
let baseTime;
|
|
3213
|
+
let baseDelivered;
|
|
3214
|
+
if (token.deliveredTimeAtSend === 0) {
|
|
3215
|
+
baseTime = this.firstAckTime;
|
|
3216
|
+
baseDelivered = this.firstAckDelivered;
|
|
3217
|
+
} else {
|
|
3218
|
+
baseTime = token.deliveredTimeAtSend;
|
|
3219
|
+
baseDelivered = token.deliveredAtSend;
|
|
3220
|
+
}
|
|
3221
|
+
let interval = ackTime - baseTime;
|
|
3222
|
+
let bytes = this.delivered - baseDelivered;
|
|
3223
|
+
let bandwidth = bytes / interval;
|
|
3224
|
+
let growthFactor = this.inStartupPhase ? STARTUP_GROWTH_FACTOR : STEADY_GROWTH_FACTOR;
|
|
3225
|
+
let newWindow = bandwidth * this.minRtt * growthFactor;
|
|
3226
|
+
newWindow = Math.min(newWindow, token.windowAtSend * growthFactor);
|
|
3227
|
+
if (token.windowFullAtSend) {
|
|
3228
|
+
newWindow = Math.max(newWindow, token.windowAtSend * DECAY_FACTOR);
|
|
3229
|
+
} else {
|
|
3230
|
+
newWindow = Math.max(newWindow, this.window);
|
|
3231
|
+
}
|
|
3232
|
+
this.window = Math.max(Math.min(newWindow, MAX_WINDOW), MIN_WINDOW);
|
|
3233
|
+
if (this.inStartupPhase && token.sentTime >= this.roundStartTime) {
|
|
3234
|
+
if (this.window > this.lastRoundWindow * STEADY_GROWTH_FACTOR) {
|
|
3235
|
+
this.roundsWithoutIncrease = 0;
|
|
3236
|
+
} else {
|
|
3237
|
+
if (++this.roundsWithoutIncrease >= STARTUP_EXIT_ROUNDS) {
|
|
3238
|
+
this.inStartupPhase = false;
|
|
3239
|
+
}
|
|
3240
|
+
}
|
|
3241
|
+
this.roundStartTime = ackTime;
|
|
3242
|
+
this.lastRoundWindow = this.window;
|
|
3243
|
+
}
|
|
3244
|
+
}
|
|
3245
|
+
return this.bytesInFlight < this.window;
|
|
3246
|
+
}
|
|
3247
|
+
};
|
|
3248
|
+
function createWritableStreamFromHook(hook) {
|
|
3249
|
+
let pendingError = void 0;
|
|
3250
|
+
let hookDisposed = false;
|
|
3251
|
+
let fc = new FlowController(() => performance.now());
|
|
3252
|
+
let windowResolve;
|
|
3253
|
+
let windowReject;
|
|
3254
|
+
const disposeHook = () => {
|
|
3255
|
+
if (!hookDisposed) {
|
|
3256
|
+
hookDisposed = true;
|
|
3257
|
+
hook.dispose();
|
|
3258
|
+
}
|
|
3259
|
+
};
|
|
3260
|
+
return new WritableStream({
|
|
3261
|
+
write(chunk, controller) {
|
|
3262
|
+
if (pendingError !== void 0) {
|
|
3263
|
+
throw pendingError;
|
|
3264
|
+
}
|
|
3265
|
+
const payload = RpcPayload.fromAppParams([chunk]);
|
|
3266
|
+
const { promise, size } = hook.stream(["write"], payload);
|
|
3267
|
+
if (size === void 0) {
|
|
3268
|
+
return promise.catch((err) => {
|
|
3269
|
+
if (pendingError === void 0) {
|
|
3270
|
+
pendingError = err;
|
|
3271
|
+
}
|
|
3272
|
+
throw err;
|
|
3273
|
+
});
|
|
3274
|
+
} else {
|
|
3275
|
+
let { token, shouldBlock } = fc.onSend(size);
|
|
3276
|
+
promise.then(() => {
|
|
3277
|
+
let hasCapacity = fc.onAck(token);
|
|
3278
|
+
if (hasCapacity && windowResolve) {
|
|
3279
|
+
windowResolve();
|
|
3280
|
+
windowResolve = void 0;
|
|
3281
|
+
windowReject = void 0;
|
|
3282
|
+
}
|
|
3283
|
+
}, (err) => {
|
|
3284
|
+
fc.onError(token);
|
|
3285
|
+
if (pendingError === void 0) {
|
|
3286
|
+
pendingError = err;
|
|
3287
|
+
controller.error(err);
|
|
3288
|
+
disposeHook();
|
|
3289
|
+
}
|
|
3290
|
+
if (windowReject) {
|
|
3291
|
+
windowReject(err);
|
|
3292
|
+
windowResolve = void 0;
|
|
3293
|
+
windowReject = void 0;
|
|
3294
|
+
}
|
|
3295
|
+
});
|
|
3296
|
+
if (shouldBlock) {
|
|
3297
|
+
return new Promise((resolve, reject) => {
|
|
3298
|
+
windowResolve = resolve;
|
|
3299
|
+
windowReject = reject;
|
|
3300
|
+
});
|
|
3301
|
+
}
|
|
3302
|
+
}
|
|
3303
|
+
},
|
|
3304
|
+
async close() {
|
|
3305
|
+
if (pendingError !== void 0) {
|
|
3306
|
+
disposeHook();
|
|
3307
|
+
throw pendingError;
|
|
3308
|
+
}
|
|
3309
|
+
const { promise } = hook.stream(["close"], RpcPayload.fromAppParams([]));
|
|
3310
|
+
try {
|
|
3311
|
+
await promise;
|
|
3312
|
+
} catch (err) {
|
|
3313
|
+
throw pendingError ?? err;
|
|
3314
|
+
} finally {
|
|
3315
|
+
disposeHook();
|
|
3316
|
+
}
|
|
3317
|
+
},
|
|
3318
|
+
abort(reason) {
|
|
3319
|
+
if (pendingError !== void 0) {
|
|
3320
|
+
return;
|
|
3321
|
+
}
|
|
3322
|
+
pendingError = reason ?? new Error("WritableStream was aborted");
|
|
3323
|
+
if (windowReject) {
|
|
3324
|
+
windowReject(pendingError);
|
|
3325
|
+
windowResolve = void 0;
|
|
3326
|
+
windowReject = void 0;
|
|
3327
|
+
}
|
|
3328
|
+
const { promise } = hook.stream(["abort"], RpcPayload.fromAppParams([reason]));
|
|
3329
|
+
promise.then(() => disposeHook(), () => disposeHook());
|
|
3330
|
+
}
|
|
3331
|
+
});
|
|
3332
|
+
}
|
|
3333
|
+
var ReadableStreamStubHook = class _ReadableStreamStubHook extends StubHook {
|
|
3334
|
+
state;
|
|
3335
|
+
// undefined when disposed
|
|
3336
|
+
// Creates a new ReadableStreamStubHook.
|
|
3337
|
+
static create(stream) {
|
|
3338
|
+
return new _ReadableStreamStubHook({ refcount: 1, stream, canceled: false });
|
|
3339
|
+
}
|
|
3340
|
+
constructor(state, dupFrom) {
|
|
3341
|
+
super();
|
|
3342
|
+
this.state = state;
|
|
3343
|
+
if (dupFrom) {
|
|
3344
|
+
++state.refcount;
|
|
3345
|
+
}
|
|
3346
|
+
}
|
|
3347
|
+
call(path, args) {
|
|
3348
|
+
args.dispose();
|
|
3349
|
+
return new ErrorStubHook(new Error("Cannot call methods on a ReadableStream stub"));
|
|
3350
|
+
}
|
|
3351
|
+
map(path, captures, instructions) {
|
|
3352
|
+
for (let cap of captures) {
|
|
3353
|
+
cap.dispose();
|
|
3354
|
+
}
|
|
3355
|
+
return new ErrorStubHook(new Error("Cannot use map() on a ReadableStream"));
|
|
3356
|
+
}
|
|
3357
|
+
get(path) {
|
|
3358
|
+
return new ErrorStubHook(new Error("Cannot access properties on a ReadableStream stub"));
|
|
3359
|
+
}
|
|
3360
|
+
dup() {
|
|
3361
|
+
let state = this.state;
|
|
3362
|
+
if (!state) {
|
|
3363
|
+
throw new Error("Attempted to dup a ReadableStreamStubHook after it was disposed.");
|
|
3364
|
+
}
|
|
3365
|
+
return new _ReadableStreamStubHook(state, this);
|
|
3366
|
+
}
|
|
3367
|
+
pull() {
|
|
3368
|
+
return Promise.reject(new Error("Cannot pull a ReadableStream stub"));
|
|
3369
|
+
}
|
|
3370
|
+
ignoreUnhandledRejections() {
|
|
3371
|
+
}
|
|
3372
|
+
dispose() {
|
|
3373
|
+
let state = this.state;
|
|
3374
|
+
this.state = void 0;
|
|
3375
|
+
if (state) {
|
|
3376
|
+
if (--state.refcount === 0) {
|
|
3377
|
+
if (!state.canceled) {
|
|
3378
|
+
state.canceled = true;
|
|
3379
|
+
if (!state.stream.locked) {
|
|
3380
|
+
state.stream.cancel(
|
|
3381
|
+
new Error("ReadableStream RPC stub was disposed without being consumed")
|
|
3382
|
+
).catch(() => {
|
|
3383
|
+
});
|
|
3384
|
+
}
|
|
3385
|
+
}
|
|
3386
|
+
}
|
|
3387
|
+
}
|
|
3388
|
+
}
|
|
3389
|
+
onBroken(callback) {
|
|
3390
|
+
}
|
|
3391
|
+
};
|
|
3392
|
+
streamImpl.createWritableStreamHook = WritableStreamStubHook.create;
|
|
3393
|
+
streamImpl.createWritableStreamFromHook = createWritableStreamFromHook;
|
|
3394
|
+
streamImpl.createReadableStreamHook = ReadableStreamStubHook.create;
|
|
2619
3395
|
var RpcStub2 = RpcStub;
|
|
2620
3396
|
var RpcPromise2 = RpcPromise;
|
|
2621
3397
|
var RpcSession2 = RpcSession;
|