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