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