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-workers.cjs
CHANGED
|
@@ -49,6 +49,7 @@ var RpcTarget = workersModule ? workersModule.RpcTarget : class {
|
|
|
49
49
|
};
|
|
50
50
|
var AsyncFunction = (async function() {
|
|
51
51
|
}).constructor;
|
|
52
|
+
var BUFFER_PROTOTYPE = typeof Buffer !== "undefined" ? Buffer.prototype : void 0;
|
|
52
53
|
function typeForRpc(value) {
|
|
53
54
|
switch (typeof value) {
|
|
54
55
|
case "boolean":
|
|
@@ -80,7 +81,18 @@ function typeForRpc(value) {
|
|
|
80
81
|
case Date.prototype:
|
|
81
82
|
return "date";
|
|
82
83
|
case Uint8Array.prototype:
|
|
84
|
+
case BUFFER_PROTOTYPE:
|
|
83
85
|
return "bytes";
|
|
86
|
+
case WritableStream.prototype:
|
|
87
|
+
return "writable";
|
|
88
|
+
case ReadableStream.prototype:
|
|
89
|
+
return "readable";
|
|
90
|
+
case Headers.prototype:
|
|
91
|
+
return "headers";
|
|
92
|
+
case Request.prototype:
|
|
93
|
+
return "request";
|
|
94
|
+
case Response.prototype:
|
|
95
|
+
return "response";
|
|
84
96
|
// TODO: All other structured clone types.
|
|
85
97
|
case RpcStub.prototype:
|
|
86
98
|
return "stub";
|
|
@@ -108,7 +120,34 @@ function mapNotLoaded() {
|
|
|
108
120
|
throw new Error("RPC map() implementation was not loaded.");
|
|
109
121
|
}
|
|
110
122
|
var mapImpl = { applyMap: mapNotLoaded, sendMap: mapNotLoaded };
|
|
123
|
+
function streamNotLoaded() {
|
|
124
|
+
throw new Error("Stream implementation was not loaded.");
|
|
125
|
+
}
|
|
126
|
+
var streamImpl = {
|
|
127
|
+
createWritableStreamHook: streamNotLoaded,
|
|
128
|
+
createWritableStreamFromHook: streamNotLoaded,
|
|
129
|
+
createReadableStreamHook: streamNotLoaded
|
|
130
|
+
};
|
|
111
131
|
var StubHook = class {
|
|
132
|
+
// Like call(), but designed for streaming calls (e.g. WritableStream writes). Returns:
|
|
133
|
+
// - promise: A Promise<void> for the completion of the call.
|
|
134
|
+
// - size: If the call was remote, the byte size of the serialized message. For local calls,
|
|
135
|
+
// undefined is returned, indicating the caller should await the promise to serialize writes
|
|
136
|
+
// (no overlapping).
|
|
137
|
+
stream(path, args) {
|
|
138
|
+
let hook = this.call(path, args);
|
|
139
|
+
let pulled = hook.pull();
|
|
140
|
+
let promise;
|
|
141
|
+
if (pulled instanceof Promise) {
|
|
142
|
+
promise = pulled.then((p) => {
|
|
143
|
+
p.dispose();
|
|
144
|
+
});
|
|
145
|
+
} else {
|
|
146
|
+
pulled.dispose();
|
|
147
|
+
promise = Promise.resolve();
|
|
148
|
+
}
|
|
149
|
+
return { promise };
|
|
150
|
+
}
|
|
112
151
|
};
|
|
113
152
|
var ErrorStubHook = class extends StubHook {
|
|
114
153
|
constructor(error) {
|
|
@@ -333,10 +372,10 @@ async function pullPromise(promise) {
|
|
|
333
372
|
}
|
|
334
373
|
var RpcPayload = class _RpcPayload {
|
|
335
374
|
// Private constructor; use factory functions above to construct.
|
|
336
|
-
constructor(value, source,
|
|
375
|
+
constructor(value, source, hooks, promises) {
|
|
337
376
|
this.value = value;
|
|
338
377
|
this.source = source;
|
|
339
|
-
this.
|
|
378
|
+
this.hooks = hooks;
|
|
340
379
|
this.promises = promises;
|
|
341
380
|
}
|
|
342
381
|
// Create a payload from a value passed as params to an RPC from the app.
|
|
@@ -361,13 +400,13 @@ var RpcPayload = class _RpcPayload {
|
|
|
361
400
|
// stubs is transferred from the inputs to the outputs, hence if the output is disposed, the
|
|
362
401
|
// inputs should not be. (In case of exception, nothing is disposed, though.)
|
|
363
402
|
static fromArray(array) {
|
|
364
|
-
let
|
|
403
|
+
let hooks = [];
|
|
365
404
|
let promises = [];
|
|
366
405
|
let resultArray = [];
|
|
367
406
|
for (let payload of array) {
|
|
368
407
|
payload.ensureDeepCopied();
|
|
369
|
-
for (let
|
|
370
|
-
|
|
408
|
+
for (let hook of payload.hooks) {
|
|
409
|
+
hooks.push(hook);
|
|
371
410
|
}
|
|
372
411
|
for (let promise of payload.promises) {
|
|
373
412
|
if (promise.parent === payload) {
|
|
@@ -381,12 +420,12 @@ var RpcPayload = class _RpcPayload {
|
|
|
381
420
|
}
|
|
382
421
|
resultArray.push(payload.value);
|
|
383
422
|
}
|
|
384
|
-
return new _RpcPayload(resultArray, "owned",
|
|
423
|
+
return new _RpcPayload(resultArray, "owned", hooks, promises);
|
|
385
424
|
}
|
|
386
425
|
// Create a payload from a value parsed off the wire using Evaluator.evaluate().
|
|
387
426
|
//
|
|
388
|
-
// A payload is constructed with a null value and the given
|
|
389
|
-
// is expected to be filled in by the evaluator, and the
|
|
427
|
+
// A payload is constructed with a null value and the given hooks and promises arrays. The value
|
|
428
|
+
// is expected to be filled in by the evaluator, and the hooks and promises arrays are expected
|
|
390
429
|
// to be extended with stubs found during parsing. (This weird usage model is necessary so that
|
|
391
430
|
// if the root value turns out to be a promise, its `parent` in `promises` can be the payload
|
|
392
431
|
// object itself.)
|
|
@@ -394,8 +433,8 @@ var RpcPayload = class _RpcPayload {
|
|
|
394
433
|
// When done, the payload takes ownership of the final value and all the stubs within. It may
|
|
395
434
|
// modify the value in preparation for delivery, and may deliver the value directly to the app
|
|
396
435
|
// without copying.
|
|
397
|
-
static forEvaluate(
|
|
398
|
-
return new _RpcPayload(null, "owned",
|
|
436
|
+
static forEvaluate(hooks, promises) {
|
|
437
|
+
return new _RpcPayload(null, "owned", hooks, promises);
|
|
399
438
|
}
|
|
400
439
|
// Deep-copy the given value, including dup()ing all stubs.
|
|
401
440
|
//
|
|
@@ -417,14 +456,20 @@ var RpcPayload = class _RpcPayload {
|
|
|
417
456
|
return result;
|
|
418
457
|
}
|
|
419
458
|
// For `source === "return"` payloads only, this tracks any StubHooks created around RpcTargets
|
|
420
|
-
// found in the payload at the time that it is serialized (or deep-copied) for
|
|
421
|
-
// can make sure they are not disposed before the pipeline ends.
|
|
459
|
+
// or WritableStreams found in the payload at the time that it is serialized (or deep-copied) for
|
|
460
|
+
// return, so that we can make sure they are not disposed before the pipeline ends.
|
|
422
461
|
//
|
|
423
462
|
// This is initialized on first use.
|
|
424
463
|
rpcTargets;
|
|
425
464
|
// Get the StubHook representing the given RpcTarget found inside this payload.
|
|
426
465
|
getHookForRpcTarget(target, parent, dupStubs = true) {
|
|
427
466
|
if (this.source === "params") {
|
|
467
|
+
if (dupStubs) {
|
|
468
|
+
let dupable = target;
|
|
469
|
+
if (typeof dupable.dup === "function") {
|
|
470
|
+
target = dupable.dup();
|
|
471
|
+
}
|
|
472
|
+
}
|
|
428
473
|
return TargetStubHook.create(target, parent);
|
|
429
474
|
} else if (this.source === "return") {
|
|
430
475
|
let hook = this.rpcTargets?.get(target);
|
|
@@ -451,6 +496,64 @@ var RpcPayload = class _RpcPayload {
|
|
|
451
496
|
throw new Error("owned payload shouldn't contain raw RpcTargets");
|
|
452
497
|
}
|
|
453
498
|
}
|
|
499
|
+
// Get the StubHook representing the given WritableStream found inside this payload.
|
|
500
|
+
getHookForWritableStream(stream, parent, dupStubs = true) {
|
|
501
|
+
if (this.source === "params") {
|
|
502
|
+
return streamImpl.createWritableStreamHook(stream);
|
|
503
|
+
} else if (this.source === "return") {
|
|
504
|
+
let hook = this.rpcTargets?.get(stream);
|
|
505
|
+
if (hook) {
|
|
506
|
+
if (dupStubs) {
|
|
507
|
+
return hook.dup();
|
|
508
|
+
} else {
|
|
509
|
+
this.rpcTargets?.delete(stream);
|
|
510
|
+
return hook;
|
|
511
|
+
}
|
|
512
|
+
} else {
|
|
513
|
+
hook = streamImpl.createWritableStreamHook(stream);
|
|
514
|
+
if (dupStubs) {
|
|
515
|
+
if (!this.rpcTargets) {
|
|
516
|
+
this.rpcTargets = /* @__PURE__ */ new Map();
|
|
517
|
+
}
|
|
518
|
+
this.rpcTargets.set(stream, hook);
|
|
519
|
+
return hook.dup();
|
|
520
|
+
} else {
|
|
521
|
+
return hook;
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
} else {
|
|
525
|
+
throw new Error("owned payload shouldn't contain raw WritableStreams");
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
// Get the StubHook representing the given ReadableStream found inside this payload.
|
|
529
|
+
getHookForReadableStream(stream, parent, dupStubs = true) {
|
|
530
|
+
if (this.source === "params") {
|
|
531
|
+
return streamImpl.createReadableStreamHook(stream);
|
|
532
|
+
} else if (this.source === "return") {
|
|
533
|
+
let hook = this.rpcTargets?.get(stream);
|
|
534
|
+
if (hook) {
|
|
535
|
+
if (dupStubs) {
|
|
536
|
+
return hook.dup();
|
|
537
|
+
} else {
|
|
538
|
+
this.rpcTargets?.delete(stream);
|
|
539
|
+
return hook;
|
|
540
|
+
}
|
|
541
|
+
} else {
|
|
542
|
+
hook = streamImpl.createReadableStreamHook(stream);
|
|
543
|
+
if (dupStubs) {
|
|
544
|
+
if (!this.rpcTargets) {
|
|
545
|
+
this.rpcTargets = /* @__PURE__ */ new Map();
|
|
546
|
+
}
|
|
547
|
+
this.rpcTargets.set(stream, hook);
|
|
548
|
+
return hook.dup();
|
|
549
|
+
} else {
|
|
550
|
+
return hook;
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
} else {
|
|
554
|
+
throw new Error("owned payload shouldn't contain raw ReadableStreams");
|
|
555
|
+
}
|
|
556
|
+
}
|
|
454
557
|
deepCopy(value, oldParent, property, parent, dupStubs, owner) {
|
|
455
558
|
let kind = typeForRpc(value);
|
|
456
559
|
switch (kind) {
|
|
@@ -494,22 +597,21 @@ var RpcPayload = class _RpcPayload {
|
|
|
494
597
|
this.promises.push({ parent, property, promise });
|
|
495
598
|
return promise;
|
|
496
599
|
} else {
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
return newStub;
|
|
600
|
+
this.hooks.push(hook);
|
|
601
|
+
return new RpcStub(hook);
|
|
500
602
|
}
|
|
501
603
|
}
|
|
502
604
|
case "function":
|
|
503
605
|
case "rpc-target": {
|
|
504
606
|
let target = value;
|
|
505
|
-
let
|
|
607
|
+
let hook;
|
|
506
608
|
if (owner) {
|
|
507
|
-
|
|
609
|
+
hook = owner.getHookForRpcTarget(target, oldParent, dupStubs);
|
|
508
610
|
} else {
|
|
509
|
-
|
|
611
|
+
hook = TargetStubHook.create(target, oldParent);
|
|
510
612
|
}
|
|
511
|
-
this.
|
|
512
|
-
return
|
|
613
|
+
this.hooks.push(hook);
|
|
614
|
+
return new RpcStub(hook);
|
|
513
615
|
}
|
|
514
616
|
case "rpc-thenable": {
|
|
515
617
|
let target = value;
|
|
@@ -522,6 +624,44 @@ var RpcPayload = class _RpcPayload {
|
|
|
522
624
|
this.promises.push({ parent, property, promise });
|
|
523
625
|
return promise;
|
|
524
626
|
}
|
|
627
|
+
case "writable": {
|
|
628
|
+
let stream = value;
|
|
629
|
+
let hook;
|
|
630
|
+
if (owner) {
|
|
631
|
+
hook = owner.getHookForWritableStream(stream, oldParent, dupStubs);
|
|
632
|
+
} else {
|
|
633
|
+
hook = streamImpl.createWritableStreamHook(stream);
|
|
634
|
+
}
|
|
635
|
+
this.hooks.push(hook);
|
|
636
|
+
return stream;
|
|
637
|
+
}
|
|
638
|
+
case "readable": {
|
|
639
|
+
let stream = value;
|
|
640
|
+
let hook;
|
|
641
|
+
if (owner) {
|
|
642
|
+
hook = owner.getHookForReadableStream(stream, oldParent, dupStubs);
|
|
643
|
+
} else {
|
|
644
|
+
hook = streamImpl.createReadableStreamHook(stream);
|
|
645
|
+
}
|
|
646
|
+
this.hooks.push(hook);
|
|
647
|
+
return stream;
|
|
648
|
+
}
|
|
649
|
+
case "headers":
|
|
650
|
+
return new Headers(value);
|
|
651
|
+
case "request": {
|
|
652
|
+
let req = value;
|
|
653
|
+
if (req.body) {
|
|
654
|
+
this.deepCopy(req.body, req, "body", req, dupStubs, owner);
|
|
655
|
+
}
|
|
656
|
+
return new Request(req);
|
|
657
|
+
}
|
|
658
|
+
case "response": {
|
|
659
|
+
let resp = value;
|
|
660
|
+
if (resp.body) {
|
|
661
|
+
this.deepCopy(resp.body, resp, "body", resp, dupStubs, owner);
|
|
662
|
+
}
|
|
663
|
+
return new Response(resp.body, resp);
|
|
664
|
+
}
|
|
525
665
|
default:
|
|
526
666
|
throw new Error("unreachable");
|
|
527
667
|
}
|
|
@@ -531,12 +671,12 @@ var RpcPayload = class _RpcPayload {
|
|
|
531
671
|
ensureDeepCopied() {
|
|
532
672
|
if (this.source !== "owned") {
|
|
533
673
|
let dupStubs = this.source === "params";
|
|
534
|
-
this.
|
|
674
|
+
this.hooks = [];
|
|
535
675
|
this.promises = [];
|
|
536
676
|
try {
|
|
537
677
|
this.value = this.deepCopy(this.value, void 0, "value", this, dupStubs, this);
|
|
538
678
|
} catch (err) {
|
|
539
|
-
this.
|
|
679
|
+
this.hooks = void 0;
|
|
540
680
|
this.promises = void 0;
|
|
541
681
|
throw err;
|
|
542
682
|
}
|
|
@@ -639,7 +779,7 @@ var RpcPayload = class _RpcPayload {
|
|
|
639
779
|
}
|
|
640
780
|
dispose() {
|
|
641
781
|
if (this.source === "owned") {
|
|
642
|
-
this.
|
|
782
|
+
this.hooks.forEach((hook) => hook.dispose());
|
|
643
783
|
this.promises.forEach((promise) => promise.promise[Symbol.dispose]());
|
|
644
784
|
} else if (this.source === "return") {
|
|
645
785
|
this.disposeImpl(this.value, void 0);
|
|
@@ -648,7 +788,7 @@ var RpcPayload = class _RpcPayload {
|
|
|
648
788
|
}
|
|
649
789
|
} else ;
|
|
650
790
|
this.source = "owned";
|
|
651
|
-
this.
|
|
791
|
+
this.hooks = [];
|
|
652
792
|
this.promises = [];
|
|
653
793
|
}
|
|
654
794
|
// Recursive dispose, called only when `source` is "return".
|
|
@@ -701,6 +841,40 @@ var RpcPayload = class _RpcPayload {
|
|
|
701
841
|
}
|
|
702
842
|
case "rpc-thenable":
|
|
703
843
|
return;
|
|
844
|
+
case "headers":
|
|
845
|
+
return;
|
|
846
|
+
case "request": {
|
|
847
|
+
let req = value;
|
|
848
|
+
if (req.body) this.disposeImpl(req.body, req);
|
|
849
|
+
return;
|
|
850
|
+
}
|
|
851
|
+
case "response": {
|
|
852
|
+
let resp = value;
|
|
853
|
+
if (resp.body) this.disposeImpl(resp.body, resp);
|
|
854
|
+
return;
|
|
855
|
+
}
|
|
856
|
+
case "writable": {
|
|
857
|
+
let stream = value;
|
|
858
|
+
let hook = this.rpcTargets?.get(stream);
|
|
859
|
+
if (hook) {
|
|
860
|
+
this.rpcTargets.delete(stream);
|
|
861
|
+
} else {
|
|
862
|
+
hook = streamImpl.createWritableStreamHook(stream);
|
|
863
|
+
}
|
|
864
|
+
hook.dispose();
|
|
865
|
+
return;
|
|
866
|
+
}
|
|
867
|
+
case "readable": {
|
|
868
|
+
let stream = value;
|
|
869
|
+
let hook = this.rpcTargets?.get(stream);
|
|
870
|
+
if (hook) {
|
|
871
|
+
this.rpcTargets.delete(stream);
|
|
872
|
+
} else {
|
|
873
|
+
hook = streamImpl.createReadableStreamHook(stream);
|
|
874
|
+
}
|
|
875
|
+
hook.dispose();
|
|
876
|
+
return;
|
|
877
|
+
}
|
|
704
878
|
default:
|
|
705
879
|
return;
|
|
706
880
|
}
|
|
@@ -709,9 +883,9 @@ var RpcPayload = class _RpcPayload {
|
|
|
709
883
|
// *would* be awaited if this payload were to be delivered. See the similarly-named method of
|
|
710
884
|
// StubHook for explanation.
|
|
711
885
|
ignoreUnhandledRejections() {
|
|
712
|
-
if (this.
|
|
713
|
-
this.
|
|
714
|
-
|
|
886
|
+
if (this.hooks) {
|
|
887
|
+
this.hooks.forEach((hook) => {
|
|
888
|
+
hook.ignoreUnhandledRejections();
|
|
715
889
|
});
|
|
716
890
|
this.promises.forEach(
|
|
717
891
|
(promise) => unwrapStubOrParent(promise.promise).ignoreUnhandledRejections()
|
|
@@ -732,6 +906,11 @@ var RpcPayload = class _RpcPayload {
|
|
|
732
906
|
case "undefined":
|
|
733
907
|
case "function":
|
|
734
908
|
case "rpc-target":
|
|
909
|
+
case "writable":
|
|
910
|
+
case "readable":
|
|
911
|
+
case "headers":
|
|
912
|
+
case "request":
|
|
913
|
+
case "response":
|
|
735
914
|
return;
|
|
736
915
|
case "array": {
|
|
737
916
|
let array = value;
|
|
@@ -804,11 +983,20 @@ function followPath(value, parent, path, owner) {
|
|
|
804
983
|
let { hook, pathIfPromise } = unwrapStubAndPath(value);
|
|
805
984
|
return { hook, remainingPath: pathIfPromise ? pathIfPromise.concat(path.slice(i)) : path.slice(i) };
|
|
806
985
|
}
|
|
986
|
+
case "writable":
|
|
987
|
+
value = void 0;
|
|
988
|
+
break;
|
|
989
|
+
case "readable":
|
|
990
|
+
value = void 0;
|
|
991
|
+
break;
|
|
807
992
|
case "primitive":
|
|
808
993
|
case "bigint":
|
|
809
994
|
case "bytes":
|
|
810
995
|
case "date":
|
|
811
996
|
case "error":
|
|
997
|
+
case "headers":
|
|
998
|
+
case "request":
|
|
999
|
+
case "response":
|
|
812
1000
|
value = void 0;
|
|
813
1001
|
break;
|
|
814
1002
|
case "undefined":
|
|
@@ -1043,6 +1231,14 @@ var PromiseStubHook = class _PromiseStubHook extends StubHook {
|
|
|
1043
1231
|
args.ensureDeepCopied();
|
|
1044
1232
|
return new _PromiseStubHook(this.promise.then((hook) => hook.call(path, args)));
|
|
1045
1233
|
}
|
|
1234
|
+
stream(path, args) {
|
|
1235
|
+
args.ensureDeepCopied();
|
|
1236
|
+
let promise = this.promise.then((hook) => {
|
|
1237
|
+
let result = hook.stream(path, args);
|
|
1238
|
+
return result.promise;
|
|
1239
|
+
});
|
|
1240
|
+
return { promise };
|
|
1241
|
+
}
|
|
1046
1242
|
map(path, captures, instructions) {
|
|
1047
1243
|
return new _PromiseStubHook(this.promise.then(
|
|
1048
1244
|
(hook) => hook.map(path, captures, instructions),
|
|
@@ -1115,6 +1311,9 @@ var NullExporter = class {
|
|
|
1115
1311
|
}
|
|
1116
1312
|
unexport(ids) {
|
|
1117
1313
|
}
|
|
1314
|
+
createPipe(readable) {
|
|
1315
|
+
throw new Error("Cannot create pipes without an RPC session.");
|
|
1316
|
+
}
|
|
1118
1317
|
onSendError(error) {
|
|
1119
1318
|
}
|
|
1120
1319
|
};
|
|
@@ -1212,12 +1411,86 @@ var Devaluator = class _Devaluator {
|
|
|
1212
1411
|
let bytes = value;
|
|
1213
1412
|
if (bytes.toBase64) {
|
|
1214
1413
|
return ["bytes", bytes.toBase64({ omitPadding: true })];
|
|
1414
|
+
}
|
|
1415
|
+
let b64;
|
|
1416
|
+
if (typeof Buffer !== "undefined") {
|
|
1417
|
+
let buf = bytes instanceof Buffer ? bytes : Buffer.from(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
1418
|
+
b64 = buf.toString("base64");
|
|
1215
1419
|
} else {
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1420
|
+
let binary = "";
|
|
1421
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
1422
|
+
binary += String.fromCharCode(bytes[i]);
|
|
1423
|
+
}
|
|
1424
|
+
b64 = btoa(binary);
|
|
1425
|
+
}
|
|
1426
|
+
return ["bytes", b64.replace(/=+$/, "")];
|
|
1427
|
+
}
|
|
1428
|
+
case "headers":
|
|
1429
|
+
return ["headers", [...value]];
|
|
1430
|
+
case "request": {
|
|
1431
|
+
let req = value;
|
|
1432
|
+
let init = {};
|
|
1433
|
+
if (req.method !== "GET") init.method = req.method;
|
|
1434
|
+
let headers = [...req.headers];
|
|
1435
|
+
if (headers.length > 0) {
|
|
1436
|
+
init.headers = headers;
|
|
1220
1437
|
}
|
|
1438
|
+
if (req.body) {
|
|
1439
|
+
init.body = this.devaluateImpl(req.body, req, depth + 1);
|
|
1440
|
+
init.duplex = req.duplex || "half";
|
|
1441
|
+
} else if (req.body === void 0 && !["GET", "HEAD", "OPTIONS", "TRACE", "DELETE"].includes(req.method)) {
|
|
1442
|
+
let bodyPromise = req.arrayBuffer();
|
|
1443
|
+
let readable = new ReadableStream({
|
|
1444
|
+
async start(controller) {
|
|
1445
|
+
try {
|
|
1446
|
+
controller.enqueue(new Uint8Array(await bodyPromise));
|
|
1447
|
+
controller.close();
|
|
1448
|
+
} catch (err) {
|
|
1449
|
+
controller.error(err);
|
|
1450
|
+
}
|
|
1451
|
+
}
|
|
1452
|
+
});
|
|
1453
|
+
let hook = streamImpl.createReadableStreamHook(readable);
|
|
1454
|
+
let importId = this.exporter.createPipe(readable, hook);
|
|
1455
|
+
init.body = ["readable", importId];
|
|
1456
|
+
init.duplex = req.duplex || "half";
|
|
1457
|
+
}
|
|
1458
|
+
if (req.cache && req.cache !== "default") init.cache = req.cache;
|
|
1459
|
+
if (req.redirect !== "follow") init.redirect = req.redirect;
|
|
1460
|
+
if (req.integrity) init.integrity = req.integrity;
|
|
1461
|
+
if (req.mode && req.mode !== "cors") init.mode = req.mode;
|
|
1462
|
+
if (req.credentials && req.credentials !== "same-origin") {
|
|
1463
|
+
init.credentials = req.credentials;
|
|
1464
|
+
}
|
|
1465
|
+
if (req.referrer && req.referrer !== "about:client") init.referrer = req.referrer;
|
|
1466
|
+
if (req.referrerPolicy) init.referrerPolicy = req.referrerPolicy;
|
|
1467
|
+
if (req.keepalive) init.keepalive = req.keepalive;
|
|
1468
|
+
let cfReq = req;
|
|
1469
|
+
if (cfReq.cf) init.cf = cfReq.cf;
|
|
1470
|
+
if (cfReq.encodeResponseBody && cfReq.encodeResponseBody !== "automatic") {
|
|
1471
|
+
init.encodeResponseBody = cfReq.encodeResponseBody;
|
|
1472
|
+
}
|
|
1473
|
+
return ["request", req.url, init];
|
|
1474
|
+
}
|
|
1475
|
+
case "response": {
|
|
1476
|
+
let resp = value;
|
|
1477
|
+
let body = this.devaluateImpl(resp.body, resp, depth + 1);
|
|
1478
|
+
let init = {};
|
|
1479
|
+
if (resp.status !== 200) init.status = resp.status;
|
|
1480
|
+
if (resp.statusText) init.statusText = resp.statusText;
|
|
1481
|
+
let headers = [...resp.headers];
|
|
1482
|
+
if (headers.length > 0) {
|
|
1483
|
+
init.headers = headers;
|
|
1484
|
+
}
|
|
1485
|
+
let cfResp = resp;
|
|
1486
|
+
if (cfResp.cf) init.cf = cfResp.cf;
|
|
1487
|
+
if (cfResp.encodeBody && cfResp.encodeBody !== "automatic") {
|
|
1488
|
+
init.encodeBody = cfResp.encodeBody;
|
|
1489
|
+
}
|
|
1490
|
+
if (cfResp.webSocket) {
|
|
1491
|
+
throw new TypeError("Can't serialize a Response containing a webSocket.");
|
|
1492
|
+
}
|
|
1493
|
+
return ["response", body, init];
|
|
1221
1494
|
}
|
|
1222
1495
|
case "error": {
|
|
1223
1496
|
let e = value;
|
|
@@ -1273,6 +1546,22 @@ var Devaluator = class _Devaluator {
|
|
|
1273
1546
|
let hook = this.source.getHookForRpcTarget(value, parent);
|
|
1274
1547
|
return this.devaluateHook("promise", hook);
|
|
1275
1548
|
}
|
|
1549
|
+
case "writable": {
|
|
1550
|
+
if (!this.source) {
|
|
1551
|
+
throw new Error("Can't serialize WritableStream in this context.");
|
|
1552
|
+
}
|
|
1553
|
+
let hook = this.source.getHookForWritableStream(value, parent);
|
|
1554
|
+
return this.devaluateHook("writable", hook);
|
|
1555
|
+
}
|
|
1556
|
+
case "readable": {
|
|
1557
|
+
if (!this.source) {
|
|
1558
|
+
throw new Error("Can't serialize ReadableStream in this context.");
|
|
1559
|
+
}
|
|
1560
|
+
let ws = value;
|
|
1561
|
+
let hook = this.source.getHookForReadableStream(ws, parent);
|
|
1562
|
+
let importId = this.exporter.createPipe(ws, hook);
|
|
1563
|
+
return ["readable", importId];
|
|
1564
|
+
}
|
|
1276
1565
|
default:
|
|
1277
1566
|
throw new Error("unreachable");
|
|
1278
1567
|
}
|
|
@@ -1297,16 +1586,27 @@ var NullImporter = class {
|
|
|
1297
1586
|
getExport(idx) {
|
|
1298
1587
|
return void 0;
|
|
1299
1588
|
}
|
|
1589
|
+
getPipeReadable(exportId) {
|
|
1590
|
+
throw new Error("Cannot retrieve pipe readable without an RPC session.");
|
|
1591
|
+
}
|
|
1300
1592
|
};
|
|
1301
1593
|
var NULL_IMPORTER = new NullImporter();
|
|
1594
|
+
function fixBrokenRequestBody(request, body) {
|
|
1595
|
+
let promise = new Response(body).arrayBuffer().then((arrayBuffer) => {
|
|
1596
|
+
let bytes = new Uint8Array(arrayBuffer);
|
|
1597
|
+
let result = new Request(request, { body: bytes });
|
|
1598
|
+
return new PayloadStubHook(RpcPayload.fromAppReturn(result));
|
|
1599
|
+
});
|
|
1600
|
+
return new RpcPromise(new PromiseStubHook(promise), []);
|
|
1601
|
+
}
|
|
1302
1602
|
var Evaluator = class _Evaluator {
|
|
1303
1603
|
constructor(importer) {
|
|
1304
1604
|
this.importer = importer;
|
|
1305
1605
|
}
|
|
1306
|
-
|
|
1606
|
+
hooks = [];
|
|
1307
1607
|
promises = [];
|
|
1308
1608
|
evaluate(value) {
|
|
1309
|
-
let payload = RpcPayload.forEvaluate(this.
|
|
1609
|
+
let payload = RpcPayload.forEvaluate(this.hooks, this.promises);
|
|
1310
1610
|
try {
|
|
1311
1611
|
payload.value = this.evaluateImpl(value, payload, "value");
|
|
1312
1612
|
return payload;
|
|
@@ -1339,10 +1639,11 @@ var Evaluator = class _Evaluator {
|
|
|
1339
1639
|
}
|
|
1340
1640
|
break;
|
|
1341
1641
|
case "bytes": {
|
|
1342
|
-
let b64 = Uint8Array;
|
|
1343
1642
|
if (typeof value[1] == "string") {
|
|
1344
|
-
if (
|
|
1345
|
-
return
|
|
1643
|
+
if (typeof Buffer !== "undefined") {
|
|
1644
|
+
return Buffer.from(value[1], "base64");
|
|
1645
|
+
} else if (Uint8Array.fromBase64) {
|
|
1646
|
+
return Uint8Array.fromBase64(value[1]);
|
|
1346
1647
|
} else {
|
|
1347
1648
|
let bs = atob(value[1]);
|
|
1348
1649
|
let len = bs.length;
|
|
@@ -1376,6 +1677,56 @@ var Evaluator = class _Evaluator {
|
|
|
1376
1677
|
return -Infinity;
|
|
1377
1678
|
case "nan":
|
|
1378
1679
|
return NaN;
|
|
1680
|
+
case "headers":
|
|
1681
|
+
if (value.length === 2 && value[1] instanceof Array) {
|
|
1682
|
+
return new Headers(value[1]);
|
|
1683
|
+
}
|
|
1684
|
+
break;
|
|
1685
|
+
case "request": {
|
|
1686
|
+
if (value.length !== 3 || typeof value[1] !== "string") break;
|
|
1687
|
+
let url = value[1];
|
|
1688
|
+
let init = value[2];
|
|
1689
|
+
if (typeof init !== "object" || init === null) break;
|
|
1690
|
+
if (init.body) {
|
|
1691
|
+
init.body = this.evaluateImpl(init.body, init, "body");
|
|
1692
|
+
if (init.body === null || typeof init.body === "string" || init.body instanceof Uint8Array || init.body instanceof ReadableStream) ; else {
|
|
1693
|
+
throw new TypeError("Request body must be of type ReadableStream.");
|
|
1694
|
+
}
|
|
1695
|
+
}
|
|
1696
|
+
if (init.signal) {
|
|
1697
|
+
init.signal = this.evaluateImpl(init.signal, init, "signal");
|
|
1698
|
+
if (!(init.signal instanceof AbortSignal)) {
|
|
1699
|
+
throw new TypeError("Request siganl must be of type AbortSignal.");
|
|
1700
|
+
}
|
|
1701
|
+
}
|
|
1702
|
+
if (init.headers && !(init.headers instanceof Array)) {
|
|
1703
|
+
throw new TypeError("Request headers must be serialized as an array of pairs.");
|
|
1704
|
+
}
|
|
1705
|
+
let result = new Request(url, init);
|
|
1706
|
+
if (init.body instanceof ReadableStream && result.body === void 0) {
|
|
1707
|
+
let promise = fixBrokenRequestBody(result, init.body);
|
|
1708
|
+
this.promises.push({ promise, parent, property });
|
|
1709
|
+
return promise;
|
|
1710
|
+
} else {
|
|
1711
|
+
return result;
|
|
1712
|
+
}
|
|
1713
|
+
}
|
|
1714
|
+
case "response": {
|
|
1715
|
+
if (value.length !== 3) break;
|
|
1716
|
+
let body = this.evaluateImpl(value[1], parent, property);
|
|
1717
|
+
if (body === null || typeof body === "string" || body instanceof Uint8Array || body instanceof ReadableStream) ; else {
|
|
1718
|
+
throw new TypeError("Response body must be of type ReadableStream.");
|
|
1719
|
+
}
|
|
1720
|
+
let init = value[2];
|
|
1721
|
+
if (typeof init !== "object" || init === null) break;
|
|
1722
|
+
if (init.webSocket) {
|
|
1723
|
+
throw new TypeError("Can't deserialize a Response containing a webSocket.");
|
|
1724
|
+
}
|
|
1725
|
+
if (init.headers && !(init.headers instanceof Array)) {
|
|
1726
|
+
throw new TypeError("Request headers must be serialized as an array of pairs.");
|
|
1727
|
+
}
|
|
1728
|
+
return new Response(body, init);
|
|
1729
|
+
}
|
|
1379
1730
|
case "import":
|
|
1380
1731
|
case "pipeline": {
|
|
1381
1732
|
if (value.length < 2 || value.length > 4) {
|
|
@@ -1395,9 +1746,8 @@ var Evaluator = class _Evaluator {
|
|
|
1395
1746
|
this.promises.push({ promise, parent, property });
|
|
1396
1747
|
return promise;
|
|
1397
1748
|
} else {
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
return stub;
|
|
1749
|
+
this.hooks.push(hook2);
|
|
1750
|
+
return new RpcPromise(hook2, []);
|
|
1401
1751
|
}
|
|
1402
1752
|
};
|
|
1403
1753
|
if (value.length == 2) {
|
|
@@ -1475,12 +1825,27 @@ var Evaluator = class _Evaluator {
|
|
|
1475
1825
|
return promise;
|
|
1476
1826
|
} else {
|
|
1477
1827
|
let hook = this.importer.importStub(value[1]);
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
return stub;
|
|
1828
|
+
this.hooks.push(hook);
|
|
1829
|
+
return new RpcStub(hook);
|
|
1481
1830
|
}
|
|
1482
1831
|
}
|
|
1483
1832
|
break;
|
|
1833
|
+
case "writable":
|
|
1834
|
+
if (typeof value[1] == "number") {
|
|
1835
|
+
let hook = this.importer.importStub(value[1]);
|
|
1836
|
+
let stream = streamImpl.createWritableStreamFromHook(hook);
|
|
1837
|
+
this.hooks.push(hook);
|
|
1838
|
+
return stream;
|
|
1839
|
+
}
|
|
1840
|
+
break;
|
|
1841
|
+
case "readable":
|
|
1842
|
+
if (typeof value[1] == "number") {
|
|
1843
|
+
let stream = this.importer.getPipeReadable(value[1]);
|
|
1844
|
+
let hook = streamImpl.createReadableStreamHook(stream);
|
|
1845
|
+
this.hooks.push(hook);
|
|
1846
|
+
return stream;
|
|
1847
|
+
}
|
|
1848
|
+
break;
|
|
1484
1849
|
}
|
|
1485
1850
|
throw new TypeError(`unknown special value: ${JSON.stringify(value)}`);
|
|
1486
1851
|
} else if (value instanceof Object) {
|
|
@@ -1620,6 +1985,14 @@ var RpcImportHook = class _RpcImportHook extends StubHook {
|
|
|
1620
1985
|
return entry.session.sendCall(entry.importId, path, args);
|
|
1621
1986
|
}
|
|
1622
1987
|
}
|
|
1988
|
+
stream(path, args) {
|
|
1989
|
+
let entry = this.getEntry();
|
|
1990
|
+
if (entry.resolution) {
|
|
1991
|
+
return entry.resolution.stream(path, args);
|
|
1992
|
+
} else {
|
|
1993
|
+
return entry.session.sendStream(entry.importId, path, args);
|
|
1994
|
+
}
|
|
1995
|
+
}
|
|
1623
1996
|
map(path, captures, instructions) {
|
|
1624
1997
|
let entry;
|
|
1625
1998
|
try {
|
|
@@ -1792,19 +2165,23 @@ var RpcSessionImpl = class {
|
|
|
1792
2165
|
return payload;
|
|
1793
2166
|
}
|
|
1794
2167
|
};
|
|
2168
|
+
let autoRelease = exp.autoRelease;
|
|
1795
2169
|
++this.pullCount;
|
|
1796
2170
|
exp.pull = resolve().then(
|
|
1797
2171
|
(payload) => {
|
|
1798
2172
|
let value = Devaluator.devaluate(payload.value, void 0, this, payload);
|
|
1799
2173
|
this.send(["resolve", exportId, value]);
|
|
2174
|
+
if (autoRelease) this.releaseExport(exportId, 1);
|
|
1800
2175
|
},
|
|
1801
2176
|
(error) => {
|
|
1802
2177
|
this.send(["reject", exportId, Devaluator.devaluate(error, void 0, this)]);
|
|
2178
|
+
if (autoRelease) this.releaseExport(exportId, 1);
|
|
1803
2179
|
}
|
|
1804
2180
|
).catch(
|
|
1805
2181
|
(error) => {
|
|
1806
2182
|
try {
|
|
1807
2183
|
this.send(["reject", exportId, Devaluator.devaluate(error, void 0, this)]);
|
|
2184
|
+
if (autoRelease) this.releaseExport(exportId, 1);
|
|
1808
2185
|
} catch (error2) {
|
|
1809
2186
|
this.abort(error2);
|
|
1810
2187
|
}
|
|
@@ -1856,9 +2233,35 @@ var RpcSessionImpl = class {
|
|
|
1856
2233
|
getExport(idx) {
|
|
1857
2234
|
return this.exports[idx]?.hook;
|
|
1858
2235
|
}
|
|
2236
|
+
getPipeReadable(exportId) {
|
|
2237
|
+
let entry = this.exports[exportId];
|
|
2238
|
+
if (!entry || !entry.pipeReadable) {
|
|
2239
|
+
throw new Error(`Export ${exportId} is not a pipe or its readable end was already consumed.`);
|
|
2240
|
+
}
|
|
2241
|
+
let readable = entry.pipeReadable;
|
|
2242
|
+
entry.pipeReadable = void 0;
|
|
2243
|
+
return readable;
|
|
2244
|
+
}
|
|
2245
|
+
createPipe(readable, readableHook) {
|
|
2246
|
+
if (this.abortReason) throw this.abortReason;
|
|
2247
|
+
this.send(["pipe"]);
|
|
2248
|
+
let importId = this.imports.length;
|
|
2249
|
+
let entry = new ImportTableEntry(this, importId, false);
|
|
2250
|
+
this.imports.push(entry);
|
|
2251
|
+
let hook = new RpcImportHook(
|
|
2252
|
+
/*isPromise=*/
|
|
2253
|
+
false,
|
|
2254
|
+
entry
|
|
2255
|
+
);
|
|
2256
|
+
let writable = streamImpl.createWritableStreamFromHook(hook);
|
|
2257
|
+
readable.pipeTo(writable).catch(() => {
|
|
2258
|
+
}).finally(() => readableHook.dispose());
|
|
2259
|
+
return importId;
|
|
2260
|
+
}
|
|
2261
|
+
// Serializes and sends a message. Returns the byte length of the serialized message.
|
|
1859
2262
|
send(msg) {
|
|
1860
2263
|
if (this.abortReason !== void 0) {
|
|
1861
|
-
return;
|
|
2264
|
+
return 0;
|
|
1862
2265
|
}
|
|
1863
2266
|
let msgText;
|
|
1864
2267
|
try {
|
|
@@ -1871,6 +2274,7 @@ var RpcSessionImpl = class {
|
|
|
1871
2274
|
throw err;
|
|
1872
2275
|
}
|
|
1873
2276
|
this.transport.send(msgText).catch((err) => this.abort(err, false));
|
|
2277
|
+
return msgText.length;
|
|
1874
2278
|
}
|
|
1875
2279
|
sendCall(id, path, args) {
|
|
1876
2280
|
if (this.abortReason) throw this.abortReason;
|
|
@@ -1888,6 +2292,34 @@ var RpcSessionImpl = class {
|
|
|
1888
2292
|
entry
|
|
1889
2293
|
);
|
|
1890
2294
|
}
|
|
2295
|
+
sendStream(id, path, args) {
|
|
2296
|
+
if (this.abortReason) throw this.abortReason;
|
|
2297
|
+
let value = ["pipeline", id, path];
|
|
2298
|
+
let devalue = Devaluator.devaluate(args.value, void 0, this, args);
|
|
2299
|
+
value.push(devalue[0]);
|
|
2300
|
+
let size = this.send(["stream", value]);
|
|
2301
|
+
let importId = this.imports.length;
|
|
2302
|
+
let entry = new ImportTableEntry(
|
|
2303
|
+
this,
|
|
2304
|
+
importId,
|
|
2305
|
+
/*pulling=*/
|
|
2306
|
+
true
|
|
2307
|
+
);
|
|
2308
|
+
entry.remoteRefcount = 0;
|
|
2309
|
+
entry.localRefcount = 1;
|
|
2310
|
+
this.imports.push(entry);
|
|
2311
|
+
let promise = entry.awaitResolution().then(
|
|
2312
|
+
(p) => {
|
|
2313
|
+
p.dispose();
|
|
2314
|
+
delete this.imports[importId];
|
|
2315
|
+
},
|
|
2316
|
+
(err) => {
|
|
2317
|
+
delete this.imports[importId];
|
|
2318
|
+
throw err;
|
|
2319
|
+
}
|
|
2320
|
+
);
|
|
2321
|
+
return { promise, size };
|
|
2322
|
+
}
|
|
1891
2323
|
sendMap(id, path, captures, instructions) {
|
|
1892
2324
|
if (this.abortReason) {
|
|
1893
2325
|
for (let cap of captures) {
|
|
@@ -1975,6 +2407,24 @@ var RpcSessionImpl = class {
|
|
|
1975
2407
|
continue;
|
|
1976
2408
|
}
|
|
1977
2409
|
break;
|
|
2410
|
+
case "stream": {
|
|
2411
|
+
if (msg.length > 1) {
|
|
2412
|
+
let payload = new Evaluator(this).evaluate(msg[1]);
|
|
2413
|
+
let hook = new PayloadStubHook(payload);
|
|
2414
|
+
hook.ignoreUnhandledRejections();
|
|
2415
|
+
let exportId = this.exports.length;
|
|
2416
|
+
this.exports.push({ hook, refcount: 1, autoRelease: true });
|
|
2417
|
+
this.ensureResolvingExport(exportId);
|
|
2418
|
+
continue;
|
|
2419
|
+
}
|
|
2420
|
+
break;
|
|
2421
|
+
}
|
|
2422
|
+
case "pipe": {
|
|
2423
|
+
let { readable, writable } = new TransformStream();
|
|
2424
|
+
let hook = streamImpl.createWritableStreamHook(writable);
|
|
2425
|
+
this.exports.push({ hook, refcount: 1, pipeReadable: readable });
|
|
2426
|
+
continue;
|
|
2427
|
+
}
|
|
1978
2428
|
case "pull": {
|
|
1979
2429
|
let exportId = msg[1];
|
|
1980
2430
|
if (typeof exportId == "number") {
|
|
@@ -2470,6 +2920,9 @@ var MapBuilder = class {
|
|
|
2470
2920
|
}
|
|
2471
2921
|
unexport(ids) {
|
|
2472
2922
|
}
|
|
2923
|
+
createPipe(readable) {
|
|
2924
|
+
throw new Error("Cannot send ReadableStream inside a mapper function.");
|
|
2925
|
+
}
|
|
2473
2926
|
onSendError(error) {
|
|
2474
2927
|
}
|
|
2475
2928
|
};
|
|
@@ -2579,6 +3032,9 @@ var MapApplicator = class {
|
|
|
2579
3032
|
return this.variables[idx];
|
|
2580
3033
|
}
|
|
2581
3034
|
}
|
|
3035
|
+
getPipeReadable(exportId) {
|
|
3036
|
+
throw new Error("A mapper function cannot use pipe readables.");
|
|
3037
|
+
}
|
|
2582
3038
|
};
|
|
2583
3039
|
function applyMapToElement(input, parent, owner, captures, instructions) {
|
|
2584
3040
|
let inputHook = new PayloadStubHook(RpcPayload.deepCopyFrom(input, parent, owner));
|
|
@@ -2619,6 +3075,333 @@ mapImpl.applyMap = (input, parent, owner, captures, instructions) => {
|
|
|
2619
3075
|
}
|
|
2620
3076
|
}
|
|
2621
3077
|
};
|
|
3078
|
+
|
|
3079
|
+
// src/streams.ts
|
|
3080
|
+
var WritableStreamStubHook = class _WritableStreamStubHook extends StubHook {
|
|
3081
|
+
state;
|
|
3082
|
+
// undefined when disposed
|
|
3083
|
+
// Creates a new WritableStreamStubHook that is not duplicated from an existing hook.
|
|
3084
|
+
static create(stream) {
|
|
3085
|
+
let writer = stream.getWriter();
|
|
3086
|
+
return new _WritableStreamStubHook({ refcount: 1, writer, closed: false });
|
|
3087
|
+
}
|
|
3088
|
+
constructor(state, dupFrom) {
|
|
3089
|
+
super();
|
|
3090
|
+
this.state = state;
|
|
3091
|
+
if (dupFrom) {
|
|
3092
|
+
++state.refcount;
|
|
3093
|
+
}
|
|
3094
|
+
}
|
|
3095
|
+
getState() {
|
|
3096
|
+
if (this.state) {
|
|
3097
|
+
return this.state;
|
|
3098
|
+
} else {
|
|
3099
|
+
throw new Error("Attempted to use a WritableStreamStubHook after it was disposed.");
|
|
3100
|
+
}
|
|
3101
|
+
}
|
|
3102
|
+
call(path, args) {
|
|
3103
|
+
try {
|
|
3104
|
+
let state = this.getState();
|
|
3105
|
+
if (path.length !== 1 || typeof path[0] !== "string") {
|
|
3106
|
+
throw new Error("WritableStream stub only supports direct method calls");
|
|
3107
|
+
}
|
|
3108
|
+
const method = path[0];
|
|
3109
|
+
if (method !== "write" && method !== "close" && method !== "abort") {
|
|
3110
|
+
args.dispose();
|
|
3111
|
+
throw new Error(`Unknown WritableStream method: ${method}`);
|
|
3112
|
+
}
|
|
3113
|
+
if (method === "close" || method === "abort") {
|
|
3114
|
+
state.closed = true;
|
|
3115
|
+
}
|
|
3116
|
+
let func = state.writer[method];
|
|
3117
|
+
let promise = args.deliverCall(func, state.writer);
|
|
3118
|
+
return new PromiseStubHook(promise.then((payload) => new PayloadStubHook(payload)));
|
|
3119
|
+
} catch (err) {
|
|
3120
|
+
return new ErrorStubHook(err);
|
|
3121
|
+
}
|
|
3122
|
+
}
|
|
3123
|
+
map(path, captures, instructions) {
|
|
3124
|
+
for (let cap of captures) {
|
|
3125
|
+
cap.dispose();
|
|
3126
|
+
}
|
|
3127
|
+
return new ErrorStubHook(new Error("Cannot use map() on a WritableStream"));
|
|
3128
|
+
}
|
|
3129
|
+
get(path) {
|
|
3130
|
+
return new ErrorStubHook(new Error("Cannot access properties on a WritableStream stub"));
|
|
3131
|
+
}
|
|
3132
|
+
dup() {
|
|
3133
|
+
let state = this.getState();
|
|
3134
|
+
return new _WritableStreamStubHook(state, this);
|
|
3135
|
+
}
|
|
3136
|
+
pull() {
|
|
3137
|
+
return Promise.reject(new Error("Cannot pull a WritableStream stub"));
|
|
3138
|
+
}
|
|
3139
|
+
ignoreUnhandledRejections() {
|
|
3140
|
+
}
|
|
3141
|
+
dispose() {
|
|
3142
|
+
let state = this.state;
|
|
3143
|
+
this.state = void 0;
|
|
3144
|
+
if (state) {
|
|
3145
|
+
if (--state.refcount === 0) {
|
|
3146
|
+
if (!state.closed) {
|
|
3147
|
+
state.writer.abort(new Error("WritableStream RPC stub was disposed without calling close()")).catch(() => {
|
|
3148
|
+
});
|
|
3149
|
+
}
|
|
3150
|
+
state.writer.releaseLock();
|
|
3151
|
+
}
|
|
3152
|
+
}
|
|
3153
|
+
}
|
|
3154
|
+
onBroken(callback) {
|
|
3155
|
+
}
|
|
3156
|
+
};
|
|
3157
|
+
var INITIAL_WINDOW = 256 * 1024;
|
|
3158
|
+
var MAX_WINDOW = 1024 * 1024 * 1024;
|
|
3159
|
+
var MIN_WINDOW = 64 * 1024;
|
|
3160
|
+
var STARTUP_GROWTH_FACTOR = 2;
|
|
3161
|
+
var STEADY_GROWTH_FACTOR = 1.25;
|
|
3162
|
+
var DECAY_FACTOR = 0.9;
|
|
3163
|
+
var STARTUP_EXIT_ROUNDS = 3;
|
|
3164
|
+
var FlowController = class {
|
|
3165
|
+
constructor(now) {
|
|
3166
|
+
this.now = now;
|
|
3167
|
+
}
|
|
3168
|
+
// The current window size in bytes. The sender blocks when bytesInFlight >= window.
|
|
3169
|
+
window = INITIAL_WINDOW;
|
|
3170
|
+
// Total bytes currently in flight (sent but not yet acked).
|
|
3171
|
+
bytesInFlight = 0;
|
|
3172
|
+
// Whether we're still in the startup phase.
|
|
3173
|
+
inStartupPhase = true;
|
|
3174
|
+
// ----- BDP estimation state (private) -----
|
|
3175
|
+
// Total bytes acked so far.
|
|
3176
|
+
delivered = 0;
|
|
3177
|
+
// Time of most recent ack.
|
|
3178
|
+
deliveredTime = 0;
|
|
3179
|
+
// Time when the very first ack was received.
|
|
3180
|
+
firstAckTime = 0;
|
|
3181
|
+
firstAckDelivered = 0;
|
|
3182
|
+
// Global minimum RTT observed (milliseconds).
|
|
3183
|
+
minRtt = Infinity;
|
|
3184
|
+
// For startup exit: count of consecutive RTT rounds where the window didn't meaningfully grow.
|
|
3185
|
+
roundsWithoutIncrease = 0;
|
|
3186
|
+
// Window size at the start of the current round, for startup exit detection.
|
|
3187
|
+
lastRoundWindow = 0;
|
|
3188
|
+
// Time when the current round started.
|
|
3189
|
+
roundStartTime = 0;
|
|
3190
|
+
// Called when a write of `size` bytes is about to be sent. Returns a token that must be
|
|
3191
|
+
// passed to onAck() when the ack arrives, and whether the sender should block (window full).
|
|
3192
|
+
onSend(size) {
|
|
3193
|
+
this.bytesInFlight += size;
|
|
3194
|
+
let token = {
|
|
3195
|
+
sentTime: this.now(),
|
|
3196
|
+
size,
|
|
3197
|
+
deliveredAtSend: this.delivered,
|
|
3198
|
+
deliveredTimeAtSend: this.deliveredTime,
|
|
3199
|
+
windowAtSend: this.window,
|
|
3200
|
+
windowFullAtSend: this.bytesInFlight >= this.window
|
|
3201
|
+
};
|
|
3202
|
+
return { token, shouldBlock: token.windowFullAtSend };
|
|
3203
|
+
}
|
|
3204
|
+
// Called when a previously-sent write fails. Restores bytesInFlight without updating
|
|
3205
|
+
// any BDP estimates.
|
|
3206
|
+
onError(token) {
|
|
3207
|
+
this.bytesInFlight -= token.size;
|
|
3208
|
+
}
|
|
3209
|
+
// Called when an ack is received for a previously-sent write. Updates BDP estimates and
|
|
3210
|
+
// the window. Returns whether a blocked sender should now unblock.
|
|
3211
|
+
onAck(token) {
|
|
3212
|
+
let ackTime = this.now();
|
|
3213
|
+
this.delivered += token.size;
|
|
3214
|
+
this.deliveredTime = ackTime;
|
|
3215
|
+
this.bytesInFlight -= token.size;
|
|
3216
|
+
let rtt = ackTime - token.sentTime;
|
|
3217
|
+
this.minRtt = Math.min(this.minRtt, rtt);
|
|
3218
|
+
if (this.firstAckTime === 0) {
|
|
3219
|
+
this.firstAckTime = ackTime;
|
|
3220
|
+
this.firstAckDelivered = this.delivered;
|
|
3221
|
+
} else {
|
|
3222
|
+
let baseTime;
|
|
3223
|
+
let baseDelivered;
|
|
3224
|
+
if (token.deliveredTimeAtSend === 0) {
|
|
3225
|
+
baseTime = this.firstAckTime;
|
|
3226
|
+
baseDelivered = this.firstAckDelivered;
|
|
3227
|
+
} else {
|
|
3228
|
+
baseTime = token.deliveredTimeAtSend;
|
|
3229
|
+
baseDelivered = token.deliveredAtSend;
|
|
3230
|
+
}
|
|
3231
|
+
let interval = ackTime - baseTime;
|
|
3232
|
+
let bytes = this.delivered - baseDelivered;
|
|
3233
|
+
let bandwidth = bytes / interval;
|
|
3234
|
+
let growthFactor = this.inStartupPhase ? STARTUP_GROWTH_FACTOR : STEADY_GROWTH_FACTOR;
|
|
3235
|
+
let newWindow = bandwidth * this.minRtt * growthFactor;
|
|
3236
|
+
newWindow = Math.min(newWindow, token.windowAtSend * growthFactor);
|
|
3237
|
+
if (token.windowFullAtSend) {
|
|
3238
|
+
newWindow = Math.max(newWindow, token.windowAtSend * DECAY_FACTOR);
|
|
3239
|
+
} else {
|
|
3240
|
+
newWindow = Math.max(newWindow, this.window);
|
|
3241
|
+
}
|
|
3242
|
+
this.window = Math.max(Math.min(newWindow, MAX_WINDOW), MIN_WINDOW);
|
|
3243
|
+
if (this.inStartupPhase && token.sentTime >= this.roundStartTime) {
|
|
3244
|
+
if (this.window > this.lastRoundWindow * STEADY_GROWTH_FACTOR) {
|
|
3245
|
+
this.roundsWithoutIncrease = 0;
|
|
3246
|
+
} else {
|
|
3247
|
+
if (++this.roundsWithoutIncrease >= STARTUP_EXIT_ROUNDS) {
|
|
3248
|
+
this.inStartupPhase = false;
|
|
3249
|
+
}
|
|
3250
|
+
}
|
|
3251
|
+
this.roundStartTime = ackTime;
|
|
3252
|
+
this.lastRoundWindow = this.window;
|
|
3253
|
+
}
|
|
3254
|
+
}
|
|
3255
|
+
return this.bytesInFlight < this.window;
|
|
3256
|
+
}
|
|
3257
|
+
};
|
|
3258
|
+
function createWritableStreamFromHook(hook) {
|
|
3259
|
+
let pendingError = void 0;
|
|
3260
|
+
let hookDisposed = false;
|
|
3261
|
+
let fc = new FlowController(() => performance.now());
|
|
3262
|
+
let windowResolve;
|
|
3263
|
+
let windowReject;
|
|
3264
|
+
const disposeHook = () => {
|
|
3265
|
+
if (!hookDisposed) {
|
|
3266
|
+
hookDisposed = true;
|
|
3267
|
+
hook.dispose();
|
|
3268
|
+
}
|
|
3269
|
+
};
|
|
3270
|
+
return new WritableStream({
|
|
3271
|
+
write(chunk, controller) {
|
|
3272
|
+
if (pendingError !== void 0) {
|
|
3273
|
+
throw pendingError;
|
|
3274
|
+
}
|
|
3275
|
+
const payload = RpcPayload.fromAppParams([chunk]);
|
|
3276
|
+
const { promise, size } = hook.stream(["write"], payload);
|
|
3277
|
+
if (size === void 0) {
|
|
3278
|
+
return promise.catch((err) => {
|
|
3279
|
+
if (pendingError === void 0) {
|
|
3280
|
+
pendingError = err;
|
|
3281
|
+
}
|
|
3282
|
+
throw err;
|
|
3283
|
+
});
|
|
3284
|
+
} else {
|
|
3285
|
+
let { token, shouldBlock } = fc.onSend(size);
|
|
3286
|
+
promise.then(() => {
|
|
3287
|
+
let hasCapacity = fc.onAck(token);
|
|
3288
|
+
if (hasCapacity && windowResolve) {
|
|
3289
|
+
windowResolve();
|
|
3290
|
+
windowResolve = void 0;
|
|
3291
|
+
windowReject = void 0;
|
|
3292
|
+
}
|
|
3293
|
+
}, (err) => {
|
|
3294
|
+
fc.onError(token);
|
|
3295
|
+
if (pendingError === void 0) {
|
|
3296
|
+
pendingError = err;
|
|
3297
|
+
controller.error(err);
|
|
3298
|
+
disposeHook();
|
|
3299
|
+
}
|
|
3300
|
+
if (windowReject) {
|
|
3301
|
+
windowReject(err);
|
|
3302
|
+
windowResolve = void 0;
|
|
3303
|
+
windowReject = void 0;
|
|
3304
|
+
}
|
|
3305
|
+
});
|
|
3306
|
+
if (shouldBlock) {
|
|
3307
|
+
return new Promise((resolve, reject) => {
|
|
3308
|
+
windowResolve = resolve;
|
|
3309
|
+
windowReject = reject;
|
|
3310
|
+
});
|
|
3311
|
+
}
|
|
3312
|
+
}
|
|
3313
|
+
},
|
|
3314
|
+
async close() {
|
|
3315
|
+
if (pendingError !== void 0) {
|
|
3316
|
+
disposeHook();
|
|
3317
|
+
throw pendingError;
|
|
3318
|
+
}
|
|
3319
|
+
const { promise } = hook.stream(["close"], RpcPayload.fromAppParams([]));
|
|
3320
|
+
try {
|
|
3321
|
+
await promise;
|
|
3322
|
+
} catch (err) {
|
|
3323
|
+
throw pendingError ?? err;
|
|
3324
|
+
} finally {
|
|
3325
|
+
disposeHook();
|
|
3326
|
+
}
|
|
3327
|
+
},
|
|
3328
|
+
abort(reason) {
|
|
3329
|
+
if (pendingError !== void 0) {
|
|
3330
|
+
return;
|
|
3331
|
+
}
|
|
3332
|
+
pendingError = reason ?? new Error("WritableStream was aborted");
|
|
3333
|
+
if (windowReject) {
|
|
3334
|
+
windowReject(pendingError);
|
|
3335
|
+
windowResolve = void 0;
|
|
3336
|
+
windowReject = void 0;
|
|
3337
|
+
}
|
|
3338
|
+
const { promise } = hook.stream(["abort"], RpcPayload.fromAppParams([reason]));
|
|
3339
|
+
promise.then(() => disposeHook(), () => disposeHook());
|
|
3340
|
+
}
|
|
3341
|
+
});
|
|
3342
|
+
}
|
|
3343
|
+
var ReadableStreamStubHook = class _ReadableStreamStubHook extends StubHook {
|
|
3344
|
+
state;
|
|
3345
|
+
// undefined when disposed
|
|
3346
|
+
// Creates a new ReadableStreamStubHook.
|
|
3347
|
+
static create(stream) {
|
|
3348
|
+
return new _ReadableStreamStubHook({ refcount: 1, stream, canceled: false });
|
|
3349
|
+
}
|
|
3350
|
+
constructor(state, dupFrom) {
|
|
3351
|
+
super();
|
|
3352
|
+
this.state = state;
|
|
3353
|
+
if (dupFrom) {
|
|
3354
|
+
++state.refcount;
|
|
3355
|
+
}
|
|
3356
|
+
}
|
|
3357
|
+
call(path, args) {
|
|
3358
|
+
args.dispose();
|
|
3359
|
+
return new ErrorStubHook(new Error("Cannot call methods on a ReadableStream stub"));
|
|
3360
|
+
}
|
|
3361
|
+
map(path, captures, instructions) {
|
|
3362
|
+
for (let cap of captures) {
|
|
3363
|
+
cap.dispose();
|
|
3364
|
+
}
|
|
3365
|
+
return new ErrorStubHook(new Error("Cannot use map() on a ReadableStream"));
|
|
3366
|
+
}
|
|
3367
|
+
get(path) {
|
|
3368
|
+
return new ErrorStubHook(new Error("Cannot access properties on a ReadableStream stub"));
|
|
3369
|
+
}
|
|
3370
|
+
dup() {
|
|
3371
|
+
let state = this.state;
|
|
3372
|
+
if (!state) {
|
|
3373
|
+
throw new Error("Attempted to dup a ReadableStreamStubHook after it was disposed.");
|
|
3374
|
+
}
|
|
3375
|
+
return new _ReadableStreamStubHook(state, this);
|
|
3376
|
+
}
|
|
3377
|
+
pull() {
|
|
3378
|
+
return Promise.reject(new Error("Cannot pull a ReadableStream stub"));
|
|
3379
|
+
}
|
|
3380
|
+
ignoreUnhandledRejections() {
|
|
3381
|
+
}
|
|
3382
|
+
dispose() {
|
|
3383
|
+
let state = this.state;
|
|
3384
|
+
this.state = void 0;
|
|
3385
|
+
if (state) {
|
|
3386
|
+
if (--state.refcount === 0) {
|
|
3387
|
+
if (!state.canceled) {
|
|
3388
|
+
state.canceled = true;
|
|
3389
|
+
if (!state.stream.locked) {
|
|
3390
|
+
state.stream.cancel(
|
|
3391
|
+
new Error("ReadableStream RPC stub was disposed without being consumed")
|
|
3392
|
+
).catch(() => {
|
|
3393
|
+
});
|
|
3394
|
+
}
|
|
3395
|
+
}
|
|
3396
|
+
}
|
|
3397
|
+
}
|
|
3398
|
+
}
|
|
3399
|
+
onBroken(callback) {
|
|
3400
|
+
}
|
|
3401
|
+
};
|
|
3402
|
+
streamImpl.createWritableStreamHook = WritableStreamStubHook.create;
|
|
3403
|
+
streamImpl.createWritableStreamFromHook = createWritableStreamFromHook;
|
|
3404
|
+
streamImpl.createReadableStreamHook = ReadableStreamStubHook.create;
|
|
2622
3405
|
var RpcStub2 = RpcStub;
|
|
2623
3406
|
var RpcPromise2 = RpcPromise;
|
|
2624
3407
|
var RpcSession2 = RpcSession;
|