capnweb 0.0.0-aa4fe30 → 0.0.0-c2bb17b

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.
@@ -23,15 +23,15 @@ function _interopNamespace(e) {
23
23
  var cfw__namespace = /*#__PURE__*/_interopNamespace(cfw);
24
24
 
25
25
  // src/symbols.ts
26
- var WORKERS_MODULE_SYMBOL = Symbol("workers-module");
26
+ var WORKERS_MODULE_SYMBOL = /* @__PURE__ */ Symbol("workers-module");
27
27
  globalThis[WORKERS_MODULE_SYMBOL] = cfw__namespace;
28
28
 
29
29
  // src/core.ts
30
30
  if (!Symbol.dispose) {
31
- Symbol.dispose = Symbol.for("dispose");
31
+ Symbol.dispose = /* @__PURE__ */ Symbol.for("dispose");
32
32
  }
33
33
  if (!Symbol.asyncDispose) {
34
- Symbol.asyncDispose = Symbol.for("asyncDispose");
34
+ Symbol.asyncDispose = /* @__PURE__ */ Symbol.for("asyncDispose");
35
35
  }
36
36
  if (!Promise.withResolvers) {
37
37
  Promise.withResolvers = function() {
@@ -47,6 +47,8 @@ if (!Promise.withResolvers) {
47
47
  var workersModule = globalThis[WORKERS_MODULE_SYMBOL];
48
48
  var RpcTarget = workersModule ? workersModule.RpcTarget : class {
49
49
  };
50
+ var AsyncFunction = (async function() {
51
+ }).constructor;
50
52
  function typeForRpc(value) {
51
53
  switch (typeof value) {
52
54
  case "boolean":
@@ -71,6 +73,7 @@ function typeForRpc(value) {
71
73
  case Object.prototype:
72
74
  return "object";
73
75
  case Function.prototype:
76
+ case AsyncFunction.prototype:
74
77
  return "function";
75
78
  case Array.prototype:
76
79
  return "array";
@@ -78,6 +81,10 @@ function typeForRpc(value) {
78
81
  return "date";
79
82
  case Uint8Array.prototype:
80
83
  return "bytes";
84
+ case WritableStream.prototype:
85
+ return "writable";
86
+ case ReadableStream.prototype:
87
+ return "readable";
81
88
  // TODO: All other structured clone types.
82
89
  case RpcStub.prototype:
83
90
  return "stub";
@@ -105,7 +112,34 @@ function mapNotLoaded() {
105
112
  throw new Error("RPC map() implementation was not loaded.");
106
113
  }
107
114
  var mapImpl = { applyMap: mapNotLoaded, sendMap: mapNotLoaded };
115
+ function streamNotLoaded() {
116
+ throw new Error("Stream implementation was not loaded.");
117
+ }
118
+ var streamImpl = {
119
+ createWritableStreamHook: streamNotLoaded,
120
+ createWritableStreamFromHook: streamNotLoaded,
121
+ createReadableStreamHook: streamNotLoaded
122
+ };
108
123
  var StubHook = class {
124
+ // Like call(), but designed for streaming calls (e.g. WritableStream writes). Returns:
125
+ // - promise: A Promise<void> for the completion of the call.
126
+ // - size: If the call was remote, the byte size of the serialized message. For local calls,
127
+ // undefined is returned, indicating the caller should await the promise to serialize writes
128
+ // (no overlapping).
129
+ stream(path, args) {
130
+ let hook = this.call(path, args);
131
+ let pulled = hook.pull();
132
+ let promise;
133
+ if (pulled instanceof Promise) {
134
+ promise = pulled.then((p) => {
135
+ p.dispose();
136
+ });
137
+ } else {
138
+ pulled.dispose();
139
+ promise = Promise.resolve();
140
+ }
141
+ return { promise };
142
+ }
109
143
  };
110
144
  var ErrorStubHook = class extends StubHook {
111
145
  constructor(error) {
@@ -154,7 +188,7 @@ function withCallInterceptor(interceptor, callback) {
154
188
  doCall = oldValue;
155
189
  }
156
190
  }
157
- var RAW_STUB = Symbol("realStub");
191
+ var RAW_STUB = /* @__PURE__ */ Symbol("realStub");
158
192
  var PROXY_HANDLERS = {
159
193
  apply(target, thisArg, argumentsList) {
160
194
  let stub = target.raw;
@@ -330,10 +364,10 @@ async function pullPromise(promise) {
330
364
  }
331
365
  var RpcPayload = class _RpcPayload {
332
366
  // Private constructor; use factory functions above to construct.
333
- constructor(value, source, stubs, promises) {
367
+ constructor(value, source, hooks, promises) {
334
368
  this.value = value;
335
369
  this.source = source;
336
- this.stubs = stubs;
370
+ this.hooks = hooks;
337
371
  this.promises = promises;
338
372
  }
339
373
  // Create a payload from a value passed as params to an RPC from the app.
@@ -358,13 +392,13 @@ var RpcPayload = class _RpcPayload {
358
392
  // stubs is transferred from the inputs to the outputs, hence if the output is disposed, the
359
393
  // inputs should not be. (In case of exception, nothing is disposed, though.)
360
394
  static fromArray(array) {
361
- let stubs = [];
395
+ let hooks = [];
362
396
  let promises = [];
363
397
  let resultArray = [];
364
398
  for (let payload of array) {
365
399
  payload.ensureDeepCopied();
366
- for (let stub of payload.stubs) {
367
- stubs.push(stub);
400
+ for (let hook of payload.hooks) {
401
+ hooks.push(hook);
368
402
  }
369
403
  for (let promise of payload.promises) {
370
404
  if (promise.parent === payload) {
@@ -378,12 +412,12 @@ var RpcPayload = class _RpcPayload {
378
412
  }
379
413
  resultArray.push(payload.value);
380
414
  }
381
- return new _RpcPayload(resultArray, "owned", stubs, promises);
415
+ return new _RpcPayload(resultArray, "owned", hooks, promises);
382
416
  }
383
417
  // Create a payload from a value parsed off the wire using Evaluator.evaluate().
384
418
  //
385
- // A payload is constructed with a null value and the given stubs and promises arrays. The value
386
- // is expected to be filled in by the evaluator, and the stubs and promises arrays are expected
419
+ // A payload is constructed with a null value and the given hooks and promises arrays. The value
420
+ // is expected to be filled in by the evaluator, and the hooks and promises arrays are expected
387
421
  // to be extended with stubs found during parsing. (This weird usage model is necessary so that
388
422
  // if the root value turns out to be a promise, its `parent` in `promises` can be the payload
389
423
  // object itself.)
@@ -391,8 +425,8 @@ var RpcPayload = class _RpcPayload {
391
425
  // When done, the payload takes ownership of the final value and all the stubs within. It may
392
426
  // modify the value in preparation for delivery, and may deliver the value directly to the app
393
427
  // without copying.
394
- static forEvaluate(stubs, promises) {
395
- return new _RpcPayload(null, "owned", stubs, promises);
428
+ static forEvaluate(hooks, promises) {
429
+ return new _RpcPayload(null, "owned", hooks, promises);
396
430
  }
397
431
  // Deep-copy the given value, including dup()ing all stubs.
398
432
  //
@@ -414,14 +448,20 @@ var RpcPayload = class _RpcPayload {
414
448
  return result;
415
449
  }
416
450
  // For `source === "return"` payloads only, this tracks any StubHooks created around RpcTargets
417
- // found in the payload at the time that it is serialized (or deep-copied) for return, so that we
418
- // can make sure they are not disposed before the pipeline ends.
451
+ // or WritableStreams found in the payload at the time that it is serialized (or deep-copied) for
452
+ // return, so that we can make sure they are not disposed before the pipeline ends.
419
453
  //
420
454
  // This is initialized on first use.
421
455
  rpcTargets;
422
456
  // Get the StubHook representing the given RpcTarget found inside this payload.
423
457
  getHookForRpcTarget(target, parent, dupStubs = true) {
424
458
  if (this.source === "params") {
459
+ if (dupStubs) {
460
+ let dupable = target;
461
+ if (typeof dupable.dup === "function") {
462
+ target = dupable.dup();
463
+ }
464
+ }
425
465
  return TargetStubHook.create(target, parent);
426
466
  } else if (this.source === "return") {
427
467
  let hook = this.rpcTargets?.get(target);
@@ -448,6 +488,64 @@ var RpcPayload = class _RpcPayload {
448
488
  throw new Error("owned payload shouldn't contain raw RpcTargets");
449
489
  }
450
490
  }
491
+ // Get the StubHook representing the given WritableStream found inside this payload.
492
+ getHookForWritableStream(stream, parent, dupStubs = true) {
493
+ if (this.source === "params") {
494
+ return streamImpl.createWritableStreamHook(stream);
495
+ } else if (this.source === "return") {
496
+ let hook = this.rpcTargets?.get(stream);
497
+ if (hook) {
498
+ if (dupStubs) {
499
+ return hook.dup();
500
+ } else {
501
+ this.rpcTargets?.delete(stream);
502
+ return hook;
503
+ }
504
+ } else {
505
+ hook = streamImpl.createWritableStreamHook(stream);
506
+ if (dupStubs) {
507
+ if (!this.rpcTargets) {
508
+ this.rpcTargets = /* @__PURE__ */ new Map();
509
+ }
510
+ this.rpcTargets.set(stream, hook);
511
+ return hook.dup();
512
+ } else {
513
+ return hook;
514
+ }
515
+ }
516
+ } else {
517
+ throw new Error("owned payload shouldn't contain raw WritableStreams");
518
+ }
519
+ }
520
+ // Get the StubHook representing the given ReadableStream found inside this payload.
521
+ getHookForReadableStream(stream, parent, dupStubs = true) {
522
+ if (this.source === "params") {
523
+ return streamImpl.createReadableStreamHook(stream);
524
+ } else if (this.source === "return") {
525
+ let hook = this.rpcTargets?.get(stream);
526
+ if (hook) {
527
+ if (dupStubs) {
528
+ return hook.dup();
529
+ } else {
530
+ this.rpcTargets?.delete(stream);
531
+ return hook;
532
+ }
533
+ } else {
534
+ hook = streamImpl.createReadableStreamHook(stream);
535
+ if (dupStubs) {
536
+ if (!this.rpcTargets) {
537
+ this.rpcTargets = /* @__PURE__ */ new Map();
538
+ }
539
+ this.rpcTargets.set(stream, hook);
540
+ return hook.dup();
541
+ } else {
542
+ return hook;
543
+ }
544
+ }
545
+ } else {
546
+ throw new Error("owned payload shouldn't contain raw ReadableStreams");
547
+ }
548
+ }
451
549
  deepCopy(value, oldParent, property, parent, dupStubs, owner) {
452
550
  let kind = typeForRpc(value);
453
551
  switch (kind) {
@@ -491,22 +589,21 @@ var RpcPayload = class _RpcPayload {
491
589
  this.promises.push({ parent, property, promise });
492
590
  return promise;
493
591
  } else {
494
- let newStub = new RpcStub(hook);
495
- this.stubs.push(newStub);
496
- return newStub;
592
+ this.hooks.push(hook);
593
+ return new RpcStub(hook);
497
594
  }
498
595
  }
499
596
  case "function":
500
597
  case "rpc-target": {
501
598
  let target = value;
502
- let stub;
599
+ let hook;
503
600
  if (owner) {
504
- stub = new RpcStub(owner.getHookForRpcTarget(target, oldParent, dupStubs));
601
+ hook = owner.getHookForRpcTarget(target, oldParent, dupStubs);
505
602
  } else {
506
- stub = new RpcStub(TargetStubHook.create(target, oldParent));
603
+ hook = TargetStubHook.create(target, oldParent);
507
604
  }
508
- this.stubs.push(stub);
509
- return stub;
605
+ this.hooks.push(hook);
606
+ return new RpcStub(hook);
510
607
  }
511
608
  case "rpc-thenable": {
512
609
  let target = value;
@@ -519,6 +616,28 @@ var RpcPayload = class _RpcPayload {
519
616
  this.promises.push({ parent, property, promise });
520
617
  return promise;
521
618
  }
619
+ case "writable": {
620
+ let stream = value;
621
+ let hook;
622
+ if (owner) {
623
+ hook = owner.getHookForWritableStream(stream, oldParent, dupStubs);
624
+ } else {
625
+ hook = streamImpl.createWritableStreamHook(stream);
626
+ }
627
+ this.hooks.push(hook);
628
+ return stream;
629
+ }
630
+ case "readable": {
631
+ let stream = value;
632
+ let hook;
633
+ if (owner) {
634
+ hook = owner.getHookForReadableStream(stream, oldParent, dupStubs);
635
+ } else {
636
+ hook = streamImpl.createReadableStreamHook(stream);
637
+ }
638
+ this.hooks.push(hook);
639
+ return stream;
640
+ }
522
641
  default:
523
642
  throw new Error("unreachable");
524
643
  }
@@ -528,12 +647,12 @@ var RpcPayload = class _RpcPayload {
528
647
  ensureDeepCopied() {
529
648
  if (this.source !== "owned") {
530
649
  let dupStubs = this.source === "params";
531
- this.stubs = [];
650
+ this.hooks = [];
532
651
  this.promises = [];
533
652
  try {
534
653
  this.value = this.deepCopy(this.value, void 0, "value", this, dupStubs, this);
535
654
  } catch (err) {
536
- this.stubs = void 0;
655
+ this.hooks = void 0;
537
656
  this.promises = void 0;
538
657
  throw err;
539
658
  }
@@ -636,7 +755,7 @@ var RpcPayload = class _RpcPayload {
636
755
  }
637
756
  dispose() {
638
757
  if (this.source === "owned") {
639
- this.stubs.forEach((stub) => stub[Symbol.dispose]());
758
+ this.hooks.forEach((hook) => hook.dispose());
640
759
  this.promises.forEach((promise) => promise.promise[Symbol.dispose]());
641
760
  } else if (this.source === "return") {
642
761
  this.disposeImpl(this.value, void 0);
@@ -645,7 +764,7 @@ var RpcPayload = class _RpcPayload {
645
764
  }
646
765
  } else ;
647
766
  this.source = "owned";
648
- this.stubs = [];
767
+ this.hooks = [];
649
768
  this.promises = [];
650
769
  }
651
770
  // Recursive dispose, called only when `source` is "return".
@@ -698,6 +817,28 @@ var RpcPayload = class _RpcPayload {
698
817
  }
699
818
  case "rpc-thenable":
700
819
  return;
820
+ case "writable": {
821
+ let stream = value;
822
+ let hook = this.rpcTargets?.get(stream);
823
+ if (hook) {
824
+ this.rpcTargets.delete(stream);
825
+ } else {
826
+ hook = streamImpl.createWritableStreamHook(stream);
827
+ }
828
+ hook.dispose();
829
+ return;
830
+ }
831
+ case "readable": {
832
+ let stream = value;
833
+ let hook = this.rpcTargets?.get(stream);
834
+ if (hook) {
835
+ this.rpcTargets.delete(stream);
836
+ } else {
837
+ hook = streamImpl.createReadableStreamHook(stream);
838
+ }
839
+ hook.dispose();
840
+ return;
841
+ }
701
842
  default:
702
843
  return;
703
844
  }
@@ -706,9 +847,9 @@ var RpcPayload = class _RpcPayload {
706
847
  // *would* be awaited if this payload were to be delivered. See the similarly-named method of
707
848
  // StubHook for explanation.
708
849
  ignoreUnhandledRejections() {
709
- if (this.stubs) {
710
- this.stubs.forEach((stub) => {
711
- unwrapStubOrParent(stub).ignoreUnhandledRejections();
850
+ if (this.hooks) {
851
+ this.hooks.forEach((hook) => {
852
+ hook.ignoreUnhandledRejections();
712
853
  });
713
854
  this.promises.forEach(
714
855
  (promise) => unwrapStubOrParent(promise.promise).ignoreUnhandledRejections()
@@ -729,6 +870,8 @@ var RpcPayload = class _RpcPayload {
729
870
  case "undefined":
730
871
  case "function":
731
872
  case "rpc-target":
873
+ case "writable":
874
+ case "readable":
732
875
  return;
733
876
  case "array": {
734
877
  let array = value;
@@ -801,6 +944,12 @@ function followPath(value, parent, path, owner) {
801
944
  let { hook, pathIfPromise } = unwrapStubAndPath(value);
802
945
  return { hook, remainingPath: pathIfPromise ? pathIfPromise.concat(path.slice(i)) : path.slice(i) };
803
946
  }
947
+ case "writable":
948
+ value = void 0;
949
+ break;
950
+ case "readable":
951
+ value = void 0;
952
+ break;
804
953
  case "primitive":
805
954
  case "bigint":
806
955
  case "bytes":
@@ -1040,6 +1189,14 @@ var PromiseStubHook = class _PromiseStubHook extends StubHook {
1040
1189
  args.ensureDeepCopied();
1041
1190
  return new _PromiseStubHook(this.promise.then((hook) => hook.call(path, args)));
1042
1191
  }
1192
+ stream(path, args) {
1193
+ args.ensureDeepCopied();
1194
+ let promise = this.promise.then((hook) => {
1195
+ let result = hook.stream(path, args);
1196
+ return result.promise;
1197
+ });
1198
+ return { promise };
1199
+ }
1043
1200
  map(path, captures, instructions) {
1044
1201
  return new _PromiseStubHook(this.promise.then(
1045
1202
  (hook) => hook.map(path, captures, instructions),
@@ -1112,6 +1269,9 @@ var NullExporter = class {
1112
1269
  }
1113
1270
  unexport(ids) {
1114
1271
  }
1272
+ createPipe(readable) {
1273
+ throw new Error("Cannot create pipes without an RPC session.");
1274
+ }
1115
1275
  onSendError(error) {
1116
1276
  }
1117
1277
  };
@@ -1270,6 +1430,22 @@ var Devaluator = class _Devaluator {
1270
1430
  let hook = this.source.getHookForRpcTarget(value, parent);
1271
1431
  return this.devaluateHook("promise", hook);
1272
1432
  }
1433
+ case "writable": {
1434
+ if (!this.source) {
1435
+ throw new Error("Can't serialize WritableStream in this context.");
1436
+ }
1437
+ let hook = this.source.getHookForWritableStream(value, parent);
1438
+ return this.devaluateHook("writable", hook);
1439
+ }
1440
+ case "readable": {
1441
+ if (!this.source) {
1442
+ throw new Error("Can't serialize ReadableStream in this context.");
1443
+ }
1444
+ let ws = value;
1445
+ let hook = this.source.getHookForReadableStream(ws, parent);
1446
+ let importId = this.exporter.createPipe(ws, hook);
1447
+ return ["readable", importId];
1448
+ }
1273
1449
  default:
1274
1450
  throw new Error("unreachable");
1275
1451
  }
@@ -1294,16 +1470,19 @@ var NullImporter = class {
1294
1470
  getExport(idx) {
1295
1471
  return void 0;
1296
1472
  }
1473
+ getPipeReadable(exportId) {
1474
+ throw new Error("Cannot retrieve pipe readable without an RPC session.");
1475
+ }
1297
1476
  };
1298
1477
  var NULL_IMPORTER = new NullImporter();
1299
1478
  var Evaluator = class _Evaluator {
1300
1479
  constructor(importer) {
1301
1480
  this.importer = importer;
1302
1481
  }
1303
- stubs = [];
1482
+ hooks = [];
1304
1483
  promises = [];
1305
1484
  evaluate(value) {
1306
- let payload = RpcPayload.forEvaluate(this.stubs, this.promises);
1485
+ let payload = RpcPayload.forEvaluate(this.hooks, this.promises);
1307
1486
  try {
1308
1487
  payload.value = this.evaluateImpl(value, payload, "value");
1309
1488
  return payload;
@@ -1392,9 +1571,8 @@ var Evaluator = class _Evaluator {
1392
1571
  this.promises.push({ promise, parent, property });
1393
1572
  return promise;
1394
1573
  } else {
1395
- let stub = new RpcPromise(hook2, []);
1396
- this.stubs.push(stub);
1397
- return stub;
1574
+ this.hooks.push(hook2);
1575
+ return new RpcPromise(hook2, []);
1398
1576
  }
1399
1577
  };
1400
1578
  if (value.length == 2) {
@@ -1472,12 +1650,27 @@ var Evaluator = class _Evaluator {
1472
1650
  return promise;
1473
1651
  } else {
1474
1652
  let hook = this.importer.importStub(value[1]);
1475
- let stub = new RpcStub(hook);
1476
- this.stubs.push(stub);
1477
- return stub;
1653
+ this.hooks.push(hook);
1654
+ return new RpcStub(hook);
1478
1655
  }
1479
1656
  }
1480
1657
  break;
1658
+ case "writable":
1659
+ if (typeof value[1] == "number") {
1660
+ let hook = this.importer.importStub(value[1]);
1661
+ let stream = streamImpl.createWritableStreamFromHook(hook);
1662
+ this.hooks.push(hook);
1663
+ return stream;
1664
+ }
1665
+ break;
1666
+ case "readable":
1667
+ if (typeof value[1] == "number") {
1668
+ let stream = this.importer.getPipeReadable(value[1]);
1669
+ let hook = streamImpl.createReadableStreamHook(stream);
1670
+ this.hooks.push(hook);
1671
+ return stream;
1672
+ }
1673
+ break;
1481
1674
  }
1482
1675
  throw new TypeError(`unknown special value: ${JSON.stringify(value)}`);
1483
1676
  } else if (value instanceof Object) {
@@ -1617,6 +1810,14 @@ var RpcImportHook = class _RpcImportHook extends StubHook {
1617
1810
  return entry.session.sendCall(entry.importId, path, args);
1618
1811
  }
1619
1812
  }
1813
+ stream(path, args) {
1814
+ let entry = this.getEntry();
1815
+ if (entry.resolution) {
1816
+ return entry.resolution.stream(path, args);
1817
+ } else {
1818
+ return entry.session.sendStream(entry.importId, path, args);
1819
+ }
1820
+ }
1620
1821
  map(path, captures, instructions) {
1621
1822
  let entry;
1622
1823
  try {
@@ -1789,19 +1990,23 @@ var RpcSessionImpl = class {
1789
1990
  return payload;
1790
1991
  }
1791
1992
  };
1993
+ let autoRelease = exp.autoRelease;
1792
1994
  ++this.pullCount;
1793
1995
  exp.pull = resolve().then(
1794
1996
  (payload) => {
1795
1997
  let value = Devaluator.devaluate(payload.value, void 0, this, payload);
1796
1998
  this.send(["resolve", exportId, value]);
1999
+ if (autoRelease) this.releaseExport(exportId, 1);
1797
2000
  },
1798
2001
  (error) => {
1799
2002
  this.send(["reject", exportId, Devaluator.devaluate(error, void 0, this)]);
2003
+ if (autoRelease) this.releaseExport(exportId, 1);
1800
2004
  }
1801
2005
  ).catch(
1802
2006
  (error) => {
1803
2007
  try {
1804
2008
  this.send(["reject", exportId, Devaluator.devaluate(error, void 0, this)]);
2009
+ if (autoRelease) this.releaseExport(exportId, 1);
1805
2010
  } catch (error2) {
1806
2011
  this.abort(error2);
1807
2012
  }
@@ -1853,9 +2058,35 @@ var RpcSessionImpl = class {
1853
2058
  getExport(idx) {
1854
2059
  return this.exports[idx]?.hook;
1855
2060
  }
2061
+ getPipeReadable(exportId) {
2062
+ let entry = this.exports[exportId];
2063
+ if (!entry || !entry.pipeReadable) {
2064
+ throw new Error(`Export ${exportId} is not a pipe or its readable end was already consumed.`);
2065
+ }
2066
+ let readable = entry.pipeReadable;
2067
+ entry.pipeReadable = void 0;
2068
+ return readable;
2069
+ }
2070
+ createPipe(readable, readableHook) {
2071
+ if (this.abortReason) throw this.abortReason;
2072
+ this.send(["pipe"]);
2073
+ let importId = this.imports.length;
2074
+ let entry = new ImportTableEntry(this, importId, false);
2075
+ this.imports.push(entry);
2076
+ let hook = new RpcImportHook(
2077
+ /*isPromise=*/
2078
+ false,
2079
+ entry
2080
+ );
2081
+ let writable = streamImpl.createWritableStreamFromHook(hook);
2082
+ readable.pipeTo(writable).catch(() => {
2083
+ }).finally(() => readableHook.dispose());
2084
+ return importId;
2085
+ }
2086
+ // Serializes and sends a message. Returns the byte length of the serialized message.
1856
2087
  send(msg) {
1857
2088
  if (this.abortReason !== void 0) {
1858
- return;
2089
+ return 0;
1859
2090
  }
1860
2091
  let msgText;
1861
2092
  try {
@@ -1868,6 +2099,7 @@ var RpcSessionImpl = class {
1868
2099
  throw err;
1869
2100
  }
1870
2101
  this.transport.send(msgText).catch((err) => this.abort(err, false));
2102
+ return msgText.length;
1871
2103
  }
1872
2104
  sendCall(id, path, args) {
1873
2105
  if (this.abortReason) throw this.abortReason;
@@ -1885,6 +2117,34 @@ var RpcSessionImpl = class {
1885
2117
  entry
1886
2118
  );
1887
2119
  }
2120
+ sendStream(id, path, args) {
2121
+ if (this.abortReason) throw this.abortReason;
2122
+ let value = ["pipeline", id, path];
2123
+ let devalue = Devaluator.devaluate(args.value, void 0, this, args);
2124
+ value.push(devalue[0]);
2125
+ let size = this.send(["stream", value]);
2126
+ let importId = this.imports.length;
2127
+ let entry = new ImportTableEntry(
2128
+ this,
2129
+ importId,
2130
+ /*pulling=*/
2131
+ true
2132
+ );
2133
+ entry.remoteRefcount = 0;
2134
+ entry.localRefcount = 1;
2135
+ this.imports.push(entry);
2136
+ let promise = entry.awaitResolution().then(
2137
+ (p) => {
2138
+ p.dispose();
2139
+ delete this.imports[importId];
2140
+ },
2141
+ (err) => {
2142
+ delete this.imports[importId];
2143
+ throw err;
2144
+ }
2145
+ );
2146
+ return { promise, size };
2147
+ }
1888
2148
  sendMap(id, path, captures, instructions) {
1889
2149
  if (this.abortReason) {
1890
2150
  for (let cap of captures) {
@@ -1972,6 +2232,24 @@ var RpcSessionImpl = class {
1972
2232
  continue;
1973
2233
  }
1974
2234
  break;
2235
+ case "stream": {
2236
+ if (msg.length > 1) {
2237
+ let payload = new Evaluator(this).evaluate(msg[1]);
2238
+ let hook = new PayloadStubHook(payload);
2239
+ hook.ignoreUnhandledRejections();
2240
+ let exportId = this.exports.length;
2241
+ this.exports.push({ hook, refcount: 1, autoRelease: true });
2242
+ this.ensureResolvingExport(exportId);
2243
+ continue;
2244
+ }
2245
+ break;
2246
+ }
2247
+ case "pipe": {
2248
+ let { readable, writable } = new TransformStream();
2249
+ let hook = streamImpl.createWritableStreamHook(writable);
2250
+ this.exports.push({ hook, refcount: 1, pipeReadable: readable });
2251
+ continue;
2252
+ }
1975
2253
  case "pull": {
1976
2254
  let exportId = msg[1];
1977
2255
  if (typeof exportId == "number") {
@@ -2467,6 +2745,9 @@ var MapBuilder = class {
2467
2745
  }
2468
2746
  unexport(ids) {
2469
2747
  }
2748
+ createPipe(readable) {
2749
+ throw new Error("Cannot send ReadableStream inside a mapper function.");
2750
+ }
2470
2751
  onSendError(error) {
2471
2752
  }
2472
2753
  };
@@ -2576,6 +2857,9 @@ var MapApplicator = class {
2576
2857
  return this.variables[idx];
2577
2858
  }
2578
2859
  }
2860
+ getPipeReadable(exportId) {
2861
+ throw new Error("A mapper function cannot use pipe readables.");
2862
+ }
2579
2863
  };
2580
2864
  function applyMapToElement(input, parent, owner, captures, instructions) {
2581
2865
  let inputHook = new PayloadStubHook(RpcPayload.deepCopyFrom(input, parent, owner));
@@ -2616,6 +2900,333 @@ mapImpl.applyMap = (input, parent, owner, captures, instructions) => {
2616
2900
  }
2617
2901
  }
2618
2902
  };
2903
+
2904
+ // src/streams.ts
2905
+ var WritableStreamStubHook = class _WritableStreamStubHook extends StubHook {
2906
+ state;
2907
+ // undefined when disposed
2908
+ // Creates a new WritableStreamStubHook that is not duplicated from an existing hook.
2909
+ static create(stream) {
2910
+ let writer = stream.getWriter();
2911
+ return new _WritableStreamStubHook({ refcount: 1, writer, closed: false });
2912
+ }
2913
+ constructor(state, dupFrom) {
2914
+ super();
2915
+ this.state = state;
2916
+ if (dupFrom) {
2917
+ ++state.refcount;
2918
+ }
2919
+ }
2920
+ getState() {
2921
+ if (this.state) {
2922
+ return this.state;
2923
+ } else {
2924
+ throw new Error("Attempted to use a WritableStreamStubHook after it was disposed.");
2925
+ }
2926
+ }
2927
+ call(path, args) {
2928
+ try {
2929
+ let state = this.getState();
2930
+ if (path.length !== 1 || typeof path[0] !== "string") {
2931
+ throw new Error("WritableStream stub only supports direct method calls");
2932
+ }
2933
+ const method = path[0];
2934
+ if (method !== "write" && method !== "close" && method !== "abort") {
2935
+ args.dispose();
2936
+ throw new Error(`Unknown WritableStream method: ${method}`);
2937
+ }
2938
+ if (method === "close" || method === "abort") {
2939
+ state.closed = true;
2940
+ }
2941
+ let func = state.writer[method];
2942
+ let promise = args.deliverCall(func, state.writer);
2943
+ return new PromiseStubHook(promise.then((payload) => new PayloadStubHook(payload)));
2944
+ } catch (err) {
2945
+ return new ErrorStubHook(err);
2946
+ }
2947
+ }
2948
+ map(path, captures, instructions) {
2949
+ for (let cap of captures) {
2950
+ cap.dispose();
2951
+ }
2952
+ return new ErrorStubHook(new Error("Cannot use map() on a WritableStream"));
2953
+ }
2954
+ get(path) {
2955
+ return new ErrorStubHook(new Error("Cannot access properties on a WritableStream stub"));
2956
+ }
2957
+ dup() {
2958
+ let state = this.getState();
2959
+ return new _WritableStreamStubHook(state, this);
2960
+ }
2961
+ pull() {
2962
+ return Promise.reject(new Error("Cannot pull a WritableStream stub"));
2963
+ }
2964
+ ignoreUnhandledRejections() {
2965
+ }
2966
+ dispose() {
2967
+ let state = this.state;
2968
+ this.state = void 0;
2969
+ if (state) {
2970
+ if (--state.refcount === 0) {
2971
+ if (!state.closed) {
2972
+ state.writer.abort(new Error("WritableStream RPC stub was disposed without calling close()")).catch(() => {
2973
+ });
2974
+ }
2975
+ state.writer.releaseLock();
2976
+ }
2977
+ }
2978
+ }
2979
+ onBroken(callback) {
2980
+ }
2981
+ };
2982
+ var INITIAL_WINDOW = 256 * 1024;
2983
+ var MAX_WINDOW = 1024 * 1024 * 1024;
2984
+ var MIN_WINDOW = 64 * 1024;
2985
+ var STARTUP_GROWTH_FACTOR = 2;
2986
+ var STEADY_GROWTH_FACTOR = 1.25;
2987
+ var DECAY_FACTOR = 0.9;
2988
+ var STARTUP_EXIT_ROUNDS = 3;
2989
+ var FlowController = class {
2990
+ constructor(now) {
2991
+ this.now = now;
2992
+ }
2993
+ // The current window size in bytes. The sender blocks when bytesInFlight >= window.
2994
+ window = INITIAL_WINDOW;
2995
+ // Total bytes currently in flight (sent but not yet acked).
2996
+ bytesInFlight = 0;
2997
+ // Whether we're still in the startup phase.
2998
+ inStartupPhase = true;
2999
+ // ----- BDP estimation state (private) -----
3000
+ // Total bytes acked so far.
3001
+ delivered = 0;
3002
+ // Time of most recent ack.
3003
+ deliveredTime = 0;
3004
+ // Time when the very first ack was received.
3005
+ firstAckTime = 0;
3006
+ firstAckDelivered = 0;
3007
+ // Global minimum RTT observed (milliseconds).
3008
+ minRtt = Infinity;
3009
+ // For startup exit: count of consecutive RTT rounds where the window didn't meaningfully grow.
3010
+ roundsWithoutIncrease = 0;
3011
+ // Window size at the start of the current round, for startup exit detection.
3012
+ lastRoundWindow = 0;
3013
+ // Time when the current round started.
3014
+ roundStartTime = 0;
3015
+ // Called when a write of `size` bytes is about to be sent. Returns a token that must be
3016
+ // passed to onAck() when the ack arrives, and whether the sender should block (window full).
3017
+ onSend(size) {
3018
+ this.bytesInFlight += size;
3019
+ let token = {
3020
+ sentTime: this.now(),
3021
+ size,
3022
+ deliveredAtSend: this.delivered,
3023
+ deliveredTimeAtSend: this.deliveredTime,
3024
+ windowAtSend: this.window,
3025
+ windowFullAtSend: this.bytesInFlight >= this.window
3026
+ };
3027
+ return { token, shouldBlock: token.windowFullAtSend };
3028
+ }
3029
+ // Called when a previously-sent write fails. Restores bytesInFlight without updating
3030
+ // any BDP estimates.
3031
+ onError(token) {
3032
+ this.bytesInFlight -= token.size;
3033
+ }
3034
+ // Called when an ack is received for a previously-sent write. Updates BDP estimates and
3035
+ // the window. Returns whether a blocked sender should now unblock.
3036
+ onAck(token) {
3037
+ let ackTime = this.now();
3038
+ this.delivered += token.size;
3039
+ this.deliveredTime = ackTime;
3040
+ this.bytesInFlight -= token.size;
3041
+ let rtt = ackTime - token.sentTime;
3042
+ this.minRtt = Math.min(this.minRtt, rtt);
3043
+ if (this.firstAckTime === 0) {
3044
+ this.firstAckTime = ackTime;
3045
+ this.firstAckDelivered = this.delivered;
3046
+ } else {
3047
+ let baseTime;
3048
+ let baseDelivered;
3049
+ if (token.deliveredTimeAtSend === 0) {
3050
+ baseTime = this.firstAckTime;
3051
+ baseDelivered = this.firstAckDelivered;
3052
+ } else {
3053
+ baseTime = token.deliveredTimeAtSend;
3054
+ baseDelivered = token.deliveredAtSend;
3055
+ }
3056
+ let interval = ackTime - baseTime;
3057
+ let bytes = this.delivered - baseDelivered;
3058
+ let bandwidth = bytes / interval;
3059
+ let growthFactor = this.inStartupPhase ? STARTUP_GROWTH_FACTOR : STEADY_GROWTH_FACTOR;
3060
+ let newWindow = bandwidth * this.minRtt * growthFactor;
3061
+ newWindow = Math.min(newWindow, token.windowAtSend * growthFactor);
3062
+ if (token.windowFullAtSend) {
3063
+ newWindow = Math.max(newWindow, token.windowAtSend * DECAY_FACTOR);
3064
+ } else {
3065
+ newWindow = Math.max(newWindow, this.window);
3066
+ }
3067
+ this.window = Math.max(Math.min(newWindow, MAX_WINDOW), MIN_WINDOW);
3068
+ if (this.inStartupPhase && token.sentTime >= this.roundStartTime) {
3069
+ if (this.window > this.lastRoundWindow * STEADY_GROWTH_FACTOR) {
3070
+ this.roundsWithoutIncrease = 0;
3071
+ } else {
3072
+ if (++this.roundsWithoutIncrease >= STARTUP_EXIT_ROUNDS) {
3073
+ this.inStartupPhase = false;
3074
+ }
3075
+ }
3076
+ this.roundStartTime = ackTime;
3077
+ this.lastRoundWindow = this.window;
3078
+ }
3079
+ }
3080
+ return this.bytesInFlight < this.window;
3081
+ }
3082
+ };
3083
+ function createWritableStreamFromHook(hook) {
3084
+ let pendingError = void 0;
3085
+ let hookDisposed = false;
3086
+ let fc = new FlowController(() => performance.now());
3087
+ let windowResolve;
3088
+ let windowReject;
3089
+ const disposeHook = () => {
3090
+ if (!hookDisposed) {
3091
+ hookDisposed = true;
3092
+ hook.dispose();
3093
+ }
3094
+ };
3095
+ return new WritableStream({
3096
+ write(chunk, controller) {
3097
+ if (pendingError !== void 0) {
3098
+ throw pendingError;
3099
+ }
3100
+ const payload = RpcPayload.fromAppParams([chunk]);
3101
+ const { promise, size } = hook.stream(["write"], payload);
3102
+ if (size === void 0) {
3103
+ return promise.catch((err) => {
3104
+ if (pendingError === void 0) {
3105
+ pendingError = err;
3106
+ }
3107
+ throw err;
3108
+ });
3109
+ } else {
3110
+ let { token, shouldBlock } = fc.onSend(size);
3111
+ promise.then(() => {
3112
+ let hasCapacity = fc.onAck(token);
3113
+ if (hasCapacity && windowResolve) {
3114
+ windowResolve();
3115
+ windowResolve = void 0;
3116
+ windowReject = void 0;
3117
+ }
3118
+ }, (err) => {
3119
+ fc.onError(token);
3120
+ if (pendingError === void 0) {
3121
+ pendingError = err;
3122
+ controller.error(err);
3123
+ disposeHook();
3124
+ }
3125
+ if (windowReject) {
3126
+ windowReject(err);
3127
+ windowResolve = void 0;
3128
+ windowReject = void 0;
3129
+ }
3130
+ });
3131
+ if (shouldBlock) {
3132
+ return new Promise((resolve, reject) => {
3133
+ windowResolve = resolve;
3134
+ windowReject = reject;
3135
+ });
3136
+ }
3137
+ }
3138
+ },
3139
+ async close() {
3140
+ if (pendingError !== void 0) {
3141
+ disposeHook();
3142
+ throw pendingError;
3143
+ }
3144
+ const { promise } = hook.stream(["close"], RpcPayload.fromAppParams([]));
3145
+ try {
3146
+ await promise;
3147
+ } catch (err) {
3148
+ throw pendingError ?? err;
3149
+ } finally {
3150
+ disposeHook();
3151
+ }
3152
+ },
3153
+ abort(reason) {
3154
+ if (pendingError !== void 0) {
3155
+ return;
3156
+ }
3157
+ pendingError = reason ?? new Error("WritableStream was aborted");
3158
+ if (windowReject) {
3159
+ windowReject(pendingError);
3160
+ windowResolve = void 0;
3161
+ windowReject = void 0;
3162
+ }
3163
+ const { promise } = hook.stream(["abort"], RpcPayload.fromAppParams([reason]));
3164
+ promise.then(() => disposeHook(), () => disposeHook());
3165
+ }
3166
+ });
3167
+ }
3168
+ var ReadableStreamStubHook = class _ReadableStreamStubHook extends StubHook {
3169
+ state;
3170
+ // undefined when disposed
3171
+ // Creates a new ReadableStreamStubHook.
3172
+ static create(stream) {
3173
+ return new _ReadableStreamStubHook({ refcount: 1, stream, canceled: false });
3174
+ }
3175
+ constructor(state, dupFrom) {
3176
+ super();
3177
+ this.state = state;
3178
+ if (dupFrom) {
3179
+ ++state.refcount;
3180
+ }
3181
+ }
3182
+ call(path, args) {
3183
+ args.dispose();
3184
+ return new ErrorStubHook(new Error("Cannot call methods on a ReadableStream stub"));
3185
+ }
3186
+ map(path, captures, instructions) {
3187
+ for (let cap of captures) {
3188
+ cap.dispose();
3189
+ }
3190
+ return new ErrorStubHook(new Error("Cannot use map() on a ReadableStream"));
3191
+ }
3192
+ get(path) {
3193
+ return new ErrorStubHook(new Error("Cannot access properties on a ReadableStream stub"));
3194
+ }
3195
+ dup() {
3196
+ let state = this.state;
3197
+ if (!state) {
3198
+ throw new Error("Attempted to dup a ReadableStreamStubHook after it was disposed.");
3199
+ }
3200
+ return new _ReadableStreamStubHook(state, this);
3201
+ }
3202
+ pull() {
3203
+ return Promise.reject(new Error("Cannot pull a ReadableStream stub"));
3204
+ }
3205
+ ignoreUnhandledRejections() {
3206
+ }
3207
+ dispose() {
3208
+ let state = this.state;
3209
+ this.state = void 0;
3210
+ if (state) {
3211
+ if (--state.refcount === 0) {
3212
+ if (!state.canceled) {
3213
+ state.canceled = true;
3214
+ if (!state.stream.locked) {
3215
+ state.stream.cancel(
3216
+ new Error("ReadableStream RPC stub was disposed without being consumed")
3217
+ ).catch(() => {
3218
+ });
3219
+ }
3220
+ }
3221
+ }
3222
+ }
3223
+ }
3224
+ onBroken(callback) {
3225
+ }
3226
+ };
3227
+ streamImpl.createWritableStreamHook = WritableStreamStubHook.create;
3228
+ streamImpl.createWritableStreamFromHook = createWritableStreamFromHook;
3229
+ streamImpl.createReadableStreamHook = ReadableStreamStubHook.create;
2619
3230
  var RpcStub2 = RpcStub;
2620
3231
  var RpcPromise2 = RpcPromise;
2621
3232
  var RpcSession2 = RpcSession;