posipaki 0.45.0 → 0.46.0

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.
@@ -1,5 +1,5 @@
1
1
  import { c as SenderInfo } from "../types-U3NvKgpg.js";
2
- import { $ as isInit, A as BlobSource, B as isBytesRef, C as Init, D as Blob, E as Spawner, F as Stream, G as StringTransport, H as BAD_PREFIX_LIMIT, I as StreamRef, J as errorFrame, K as badFrame, L as StreamStore, M as RemoteBlob, N as RemoteBytes, O as BlobFacts, P as RemoteStream, Q as isExit, R as StreamStoreOptions, S as serveRemoteActor, T as ServedProcess, U as Channel, V as isStreamRef, W as Frame, X as isBad, Y as errorReason, Z as isError, _ as ServedConnection, a as ClientContext, at as isState, b as oneConnection, c as remoteClient, ct as ProcessRef, d as stderrSink, dt as FrameSink, et as isMsg, f as AnyActorDefinition, ft as RemoteMessage, g as ReactorOptions, h as Reactor, i as CHANNEL_LOST, it as isResume, j as BytesRef, k as BlobRef, l as OutputSink, lt as isRemoteProcess, m as Listener, n as WebSocketLike, nt as isProto, o as ClientSpawner, ot as isStop, p as Connection, pt as RemoteProcess, q as badReason, r as WebSocketTransport, rt as isRelease, s as RemoteClientOptions, st as PROCESS_REF, t as WS_OPEN, tt as isPause, u as pumpOutput, ut as rootIdFor, v as Session, w as Served, x as reactor, y as SessionFactory, z as isBlobRef } from "../websocket-DT8zKD34.js";
2
+ import { $ as isError, A as BlobSource, B as TypedArrayName, C as Init, D as Blob, E as Spawner, F as RemoteStream, G as Channel, H as isBytesRef, I as Stream, J as badFrame, K as Frame, L as StreamRef, M as BytesRef, N as RemoteArray, O as BlobFacts, P as RemoteBlob, Q as isBad, R as StreamStore, S as serveRemoteActor, T as ServedProcess, U as isStreamRef, V as isBlobRef, W as BAD_PREFIX_LIMIT, X as errorFrame, Y as badReason, Z as errorReason, _ as ServedConnection, a as ClientContext, at as isRelease, b as oneConnection, c as remoteClient, ct as isStop, d as stderrSink, dt as isRemoteProcess, et as isExit, f as AnyActorDefinition, ft as rootIdFor, g as ReactorOptions, h as Reactor, ht as RemoteProcess, i as CHANNEL_LOST, it as isProto, j as BytesFacts, k as BlobRef, l as OutputSink, lt as PROCESS_REF, m as Listener, mt as RemoteMessage, n as WebSocketLike, nt as isMsg, o as ClientSpawner, ot as isResume, p as Connection, pt as FrameSink, q as StringTransport, r as WebSocketTransport, rt as isPause, s as RemoteClientOptions, st as isState, t as WS_OPEN, tt as isInit, u as pumpOutput, ut as ProcessRef, v as Session, w as Served, x as reactor, y as SessionFactory, z as StreamStoreOptions } from "../websocket-GFSUt3YC.js";
3
3
  //#region src/remote/sender.d.ts
4
4
  declare function makeSender(fromName: string, parentName: string | null, parentId: symbol | null): SenderInfo;
5
5
  //#endregion
@@ -114,5 +114,5 @@ declare function workerClientSpawner<Args = unknown>(url: string | ((args: Args)
114
114
  //#region src/remote/spawners/worker-self.d.ts
115
115
  declare function workerSelfSpawner(selfScope?: WorkerLike): Spawner;
116
116
  //#endregion
117
- export { type AnyActorDefinition, BAD_PREFIX_LIMIT, type Blob, type BlobFacts, type BlobRef, type BlobSource, type BunServerWebSocketLike, type BytesRef, CHANNEL_LOST, type Channel, type ClientContext, type ClientSpawner, type Connection, type Frame, type FrameSink, type Init, type Listener, type OpenedWebSocket, type OutputSink, PROCESS_REF, type ProcessRef, type Reactor, type ReactorOptions, RemoteBlob, RemoteBytes, type RemoteClientOptions, type RemoteMessage, RemoteProcess, RemoteStream, type Served, type ServedConnection, type ServedProcess, type Session, type SessionFactory, type Spawner, type Stream, type StreamRef, StreamStore, type StreamStoreOptions, type StringTransport, VERSION, WORKER_VERSION, WS_OPEN, type WebSocketClientOptions, type WebSocketCtor, type WebSocketLike, type WebSocketOpener, WebSocketTransport, type WorkerCtor, type WorkerLike, WorkerTransport, badFrame, badReason, bunServerWebSocket, decode, encode, errorFrame, errorReason, isBad, isBlobRef, isBytesRef, isError, isExit, isInit, isMsg, isPause, isProto, isRelease, isRemoteProcess, isResume, isState, isStop, isStreamRef, json1Channel, makeSender, oneConnection, pumpOutput, reactor, readFrame, remoteClient, rootIdFor, serveRemoteActor, stderrSink, workerClientSpawner, workerSelfSpawner, wsClientSpawner, wsServerSpawner };
117
+ export { type AnyActorDefinition, BAD_PREFIX_LIMIT, type Blob, type BlobFacts, type BlobRef, type BlobSource, type BunServerWebSocketLike, type BytesFacts, type BytesRef, CHANNEL_LOST, type Channel, type ClientContext, type ClientSpawner, type Connection, type Frame, type FrameSink, type Init, type Listener, type OpenedWebSocket, type OutputSink, PROCESS_REF, type ProcessRef, type Reactor, type ReactorOptions, type RemoteArray, RemoteBlob, type RemoteClientOptions, type RemoteMessage, RemoteProcess, RemoteStream, type Served, type ServedConnection, type ServedProcess, type Session, type SessionFactory, type Spawner, type Stream, type StreamRef, StreamStore, type StreamStoreOptions, type StringTransport, type TypedArrayName, VERSION, WORKER_VERSION, WS_OPEN, type WebSocketClientOptions, type WebSocketCtor, type WebSocketLike, type WebSocketOpener, WebSocketTransport, type WorkerCtor, type WorkerLike, WorkerTransport, badFrame, badReason, bunServerWebSocket, decode, encode, errorFrame, errorReason, isBad, isBlobRef, isBytesRef, isError, isExit, isInit, isMsg, isPause, isProto, isRelease, isRemoteProcess, isResume, isState, isStop, isStreamRef, json1Channel, makeSender, oneConnection, pumpOutput, reactor, readFrame, remoteClient, rootIdFor, serveRemoteActor, stderrSink, workerClientSpawner, workerSelfSpawner, wsClientSpawner, wsServerSpawner };
118
118
  //# sourceMappingURL=index.d.ts.map
@@ -1,4 +1,4 @@
1
- import { A as errorReason, B as isResume, C as json1Channel, D as badReason, E as badFrame, F as isInit, H as isStop, I as isMsg, K as rootIdFor, L as isPause, M as isBad, N as isError, P as isExit, R as isProto, S as encode, T as BAD_PREFIX_LIMIT, U as PROCESS_REF, V as isState, W as isRemoteProcess, _ as isStreamRef, a as remoteClient, b as VERSION, c as oneConnection, d as RemoteBlob, f as RemoteBytes, g as isBytesRef, h as isBlobRef, i as CHANNEL_LOST, j as frameReaders, k as errorFrame, l as reactor, m as StreamStore, n as WebSocketTransport, o as pumpOutput, p as RemoteStream, s as stderrSink, t as WS_OPEN, u as serveRemoteActor, v as makeSender, w as readFrame, x as decode, y as RemoteProcess, z as isRelease } from "../websocket-DkDAHMFm.js";
1
+ import { A as frameReaders, B as isState, C as readFrame, E as badReason, F as isMsg, G as rootIdFor, H as PROCESS_REF, I as isPause, L as isProto, M as isError, N as isExit, O as errorFrame, P as isInit, R as isRelease, S as json1Channel, T as badFrame, U as isRemoteProcess, V as isStop, _ as makeSender, a as remoteClient, b as decode, c as oneConnection, d as RemoteBlob, f as RemoteStream, g as isStreamRef, h as isBytesRef, i as CHANNEL_LOST, j as isBad, k as errorReason, l as reactor, m as isBlobRef, n as WebSocketTransport, o as pumpOutput, p as StreamStore, s as stderrSink, t as WS_OPEN, u as serveRemoteActor, v as RemoteProcess, w as BAD_PREFIX_LIMIT, x as encode, y as VERSION, z as isResume } from "../websocket-1DAD3oDx.js";
2
2
  //#region src/remote/transports/worker.ts
3
3
  /** The worker encoding: native structured clone (no JSON). */
4
4
  const WORKER_VERSION = "clone.v1";
@@ -152,6 +152,6 @@ function workerSelfSpawner(selfScope = globalThis) {
152
152
  };
153
153
  }
154
154
  //#endregion
155
- export { BAD_PREFIX_LIMIT, CHANNEL_LOST, PROCESS_REF, RemoteBlob, RemoteBytes, RemoteProcess, RemoteStream, StreamStore, VERSION, WORKER_VERSION, WS_OPEN, WebSocketTransport, WorkerTransport, badFrame, badReason, bunServerWebSocket, decode, encode, errorFrame, errorReason, isBad, isBlobRef, isBytesRef, isError, isExit, isInit, isMsg, isPause, isProto, isRelease, isRemoteProcess, isResume, isState, isStop, isStreamRef, json1Channel, makeSender, oneConnection, pumpOutput, reactor, readFrame, remoteClient, rootIdFor, serveRemoteActor, stderrSink, workerClientSpawner, workerSelfSpawner, wsClientSpawner, wsServerSpawner };
155
+ export { BAD_PREFIX_LIMIT, CHANNEL_LOST, PROCESS_REF, RemoteBlob, RemoteProcess, RemoteStream, StreamStore, VERSION, WORKER_VERSION, WS_OPEN, WebSocketTransport, WorkerTransport, badFrame, badReason, bunServerWebSocket, decode, encode, errorFrame, errorReason, isBad, isBlobRef, isBytesRef, isError, isExit, isInit, isMsg, isPause, isProto, isRelease, isRemoteProcess, isResume, isState, isStop, isStreamRef, json1Channel, makeSender, oneConnection, pumpOutput, reactor, readFrame, remoteClient, rootIdFor, serveRemoteActor, stderrSink, workerClientSpawner, workerSelfSpawner, wsClientSpawner, wsServerSpawner };
156
156
 
157
157
  //# sourceMappingURL=index.js.map
@@ -1,6 +1,6 @@
1
1
  import { a as Message } from "../types-U3NvKgpg.js";
2
2
  import { h as MethodOptions, l as ActorDefinition, p as HandlerOptions, v as ReflectionOptions } from "../hooks-DO-efRM_.js";
3
- import { G as StringTransport, U as Channel, d as stderrSink, l as OutputSink, m as Listener, n as WebSocketLike, o as ClientSpawner, u as pumpOutput } from "../websocket-DT8zKD34.js";
3
+ import { G as Channel, d as stderrSink, l as OutputSink, m as Listener, n as WebSocketLike, o as ClientSpawner, q as StringTransport, u as pumpOutput } from "../websocket-GFSUt3YC.js";
4
4
  import { FileHandle } from "node:fs/promises";
5
5
  import { ChildProcess, StdioOptions } from "node:child_process";
6
6
  import { Duplex, Readable, Writable } from "node:stream";
@@ -1,5 +1,5 @@
1
- import { t as LIB_VERSION } from "../version-yonmO5bG.js";
2
- import { A as errorReason$1, C as json1Channel, G as lowBand, O as channelThrough, R as isProto, a as remoteClient, b as VERSION, k as errorFrame$1, m as StreamStore, n as WebSocketTransport, o as pumpOutput, r as readParts, s as stderrSink, u as serveRemoteActor } from "../websocket-DkDAHMFm.js";
1
+ import { t as LIB_VERSION } from "../version-DAQCfED6.js";
2
+ import { D as channelThrough, L as isProto, O as errorFrame$1, S as json1Channel, W as lowBand, a as remoteClient, k as errorReason$1, n as WebSocketTransport, o as pumpOutput, p as StreamStore, r as readParts, s as stderrSink, u as serveRemoteActor, y as VERSION } from "../websocket-1DAD3oDx.js";
3
3
  import { chmod, mkdir, mkdtemp, open, readFile, rm, stat, unlink } from "node:fs/promises";
4
4
  import { execFile, spawn } from "node:child_process";
5
5
  import { createHash, randomUUID } from "node:crypto";
@@ -1,7 +1,7 @@
1
1
  //#region src/version.ts
2
2
  /** posipaki's release version. Must equal package.json's `version`. */
3
- const LIB_VERSION = "0.45.0";
3
+ const LIB_VERSION = "0.46.0";
4
4
  //#endregion
5
5
  export { LIB_VERSION as t };
6
6
 
7
- //# sourceMappingURL=version-yonmO5bG.js.map
7
+ //# sourceMappingURL=version-DAQCfED6.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"version-yonmO5bG.js","names":[],"sources":["../src/version.ts"],"sourcesContent":["// ── Library identity ───────────────────────────────────────────────────────\n//\n// posipaki's own release version, as a plain inlined string. A consumer that\n// stages artifacts onto a host it knows nothing about has to name those\n// artifacts after which posipaki they speak, and the bundle that runs there has\n// no node_modules and no posipaki on disk — it can never read a file to find out.\n//\n// It is not the protocol version: that is `VERSION` in ./remote (`json.v1`), and\n// it does not move between releases. The two answer different questions.\n//\n// version.test.ts pins this to package.json, so a release that forgets to bump it\n// fails the suite rather than shipping a lie.\n\n/** posipaki's release version. Must equal package.json's `version`. */\nexport const LIB_VERSION = \"0.45.0\";\n"],"mappings":";;AAcA,MAAa,cAAc"}
1
+ {"version":3,"file":"version-DAQCfED6.js","names":[],"sources":["../src/version.ts"],"sourcesContent":["// ── Library identity ───────────────────────────────────────────────────────\n//\n// posipaki's own release version, as a plain inlined string. A consumer that\n// stages artifacts onto a host it knows nothing about has to name those\n// artifacts after which posipaki they speak, and the bundle that runs there has\n// no node_modules and no posipaki on disk — it can never read a file to find out.\n//\n// It is not the protocol version: that is `VERSION` in ./remote (`json.v1`), and\n// it does not move between releases. The two answer different questions.\n//\n// version.test.ts pins this to package.json, so a release that forgets to bump it\n// fails the suite rather than shipping a lie.\n\n/** posipaki's release version. Must equal package.json's `version`. */\nexport const LIB_VERSION = \"0.46.0\";\n"],"mappings":";;AAcA,MAAa,cAAc"}
@@ -517,6 +517,14 @@ function announcedOctets(frame) {
517
517
  function json1Channel(transport) {
518
518
  const frameReaders = /* @__PURE__ */ new Set();
519
519
  const segmentReaders = /* @__PURE__ */ new Set();
520
+ const closeReaders = /* @__PURE__ */ new Set();
521
+ /** The wire goes once, whoever ends it: the peer hanging up, or this side closing it. */
522
+ let closed = false;
523
+ const sayClosed = () => {
524
+ if (closed) return;
525
+ closed = true;
526
+ for (const reader of [...closeReaders]) reader();
527
+ };
520
528
  /** The head whose octets are on their way: set between the line and the run it announced. */
521
529
  let expecting = null;
522
530
  const deliver = (frame) => {
@@ -541,6 +549,7 @@ function json1Channel(transport) {
541
549
  }
542
550
  for (const reader of [...segmentReaders]) reader(frame, bytes);
543
551
  });
552
+ transport.onClose(sayClosed);
544
553
  return {
545
554
  send(frame) {
546
555
  return transport.send(encode(frame));
@@ -562,10 +571,11 @@ function json1Channel(transport) {
562
571
  };
563
572
  },
564
573
  onClose(handler) {
565
- transport.onClose(handler);
574
+ closeReaders.add(handler);
566
575
  },
567
- close() {
568
- return transport.close();
576
+ async close() {
577
+ sayClosed();
578
+ await transport.close();
569
579
  }
570
580
  };
571
581
  }
@@ -1445,45 +1455,6 @@ var RemoteBlob = class {
1445
1455
  }
1446
1456
  };
1447
1457
  /**
1448
- * Bytes that crossed a connection: the sender's array, taken apart into a stream and put back
1449
- * together here as the chunks arrive. Not lazy — the sender was asked the moment the reference
1450
- * arrived — so awaiting this is waiting for the last chunk, not for a read to start.
1451
- */
1452
- var RemoteBytes = class {
1453
- constructor(body, size) {
1454
- this.filling = null;
1455
- this.body = body;
1456
- this.size = size;
1457
- }
1458
- /** Start re-assembling. Called by the store once its record for this stream is in place. */
1459
- start() {
1460
- this.bytes().catch(() => {});
1461
- }
1462
- /** The octets, once they are all here. */
1463
- bytes() {
1464
- this.filling ??= this.pvtFill();
1465
- return this.filling;
1466
- }
1467
- /** The same octets as an array's buffer, for a caller that wants the platform's shape. */
1468
- async arrayBuffer() {
1469
- return (await this.bytes()).buffer;
1470
- }
1471
- then(onfulfilled, onrejected) {
1472
- return this.bytes().then(onfulfilled, onrejected);
1473
- }
1474
- async pvtFill() {
1475
- const all = new Uint8Array(this.size);
1476
- let at = 0;
1477
- for await (const chunk of this.body) {
1478
- if (at + chunk.length > all.length) throw new Error(`the array is longer than the ${this.size} bytes it stated`);
1479
- all.set(chunk, at);
1480
- at += chunk.length;
1481
- }
1482
- if (at !== all.length) throw new Error(`the array is short: ${at} of ${this.size} octets arrived`);
1483
- return all;
1484
- }
1485
- };
1486
- /**
1487
1458
  * One connection's streams, as this side sees them.
1488
1459
  *
1489
1460
  * Both directions are in one table, because both are the same numbering: what this side offers
@@ -1497,6 +1468,7 @@ var StreamStore = class {
1497
1468
  this.pvtRefused = /* @__PURE__ */ new Map();
1498
1469
  this.pvtNamesOut = /* @__PURE__ */ new Map();
1499
1470
  this.pvtNamesIn = /* @__PURE__ */ new Map();
1471
+ this.pvtPending = [];
1500
1472
  this.pvtNamedListeners = /* @__PURE__ */ new Set();
1501
1473
  this.pvtSegmentOff = null;
1502
1474
  this.pvtClosed = false;
@@ -1539,14 +1511,18 @@ var StreamStore = class {
1539
1511
  } };
1540
1512
  }
1541
1513
  /**
1542
- * Offer bytes this side already holds. The reference states the length, so the far side can
1543
- * check it against its bound and size the array before the first chunk arrives — a typed array
1544
- * is one piece, so the wire carries it as a stream of one.
1514
+ * Offer bytes this side already holds. The reference states the length, so the far side can check
1515
+ * it against its bound and make room before the first chunk arrives — and, when the value is a typed
1516
+ * array, the element kind and count too, so the same kind of array is made on the other side. The
1517
+ * octets are one piece, and the wire carries them as a stream of one.
1545
1518
  */
1546
- offerBytes(bytes) {
1519
+ offerBytes(value) {
1520
+ const { bytes, type, length } = octetsOf$1(value);
1547
1521
  return { $bytes: {
1548
1522
  id: this.pvtAnnounce(this.pvtOnePiece(bytes)),
1549
- size: bytes.length
1523
+ size: bytes.length,
1524
+ ...type === void 0 ? {} : { type },
1525
+ ...length === void 0 ? {} : { length }
1550
1526
  } };
1551
1527
  }
1552
1528
  pvtAnnounce(source, name) {
@@ -1590,8 +1566,22 @@ var StreamStore = class {
1590
1566
  }
1591
1567
  /** A value just read: every reference in it becomes something this side can read. */
1592
1568
  decode(value) {
1569
+ this.pvtPending = [];
1593
1570
  return this.pvtDecode(value, /* @__PURE__ */ new Set());
1594
1571
  }
1572
+ /**
1573
+ * What the octets of a just-decoded value still owe. A message is handed to its process only once
1574
+ * this has settled, so a typed array in a body is whole when the handler reads it; a stream, a blob
1575
+ * and a plain value carry no octets of their own and settle at once.
1576
+ */
1577
+ owed() {
1578
+ if (this.pvtPending.length === 0) return null;
1579
+ return Promise.all(this.pvtPending).then(() => void 0);
1580
+ }
1581
+ /** The same question as a promise, for a caller that would rather always await. */
1582
+ settled() {
1583
+ return this.owed() ?? Promise.resolve();
1584
+ }
1595
1585
  /** Drop every stream of this connection, in both directions. Called when it ends. */
1596
1586
  close() {
1597
1587
  if (this.pvtClosed) return;
@@ -1600,6 +1590,7 @@ var StreamStore = class {
1600
1590
  this.pvtSegmentOff?.();
1601
1591
  for (const offered of this.pvtOffers.values()) {
1602
1592
  offered.dropped = true;
1593
+ Promise.resolve(this.channel.send({ $streamDone: { id: offered.id } })).catch(() => {});
1603
1594
  offered.source.return?.();
1604
1595
  }
1605
1596
  this.pvtOffers.clear();
@@ -1656,7 +1647,7 @@ var StreamStore = class {
1656
1647
  if (seen.has(value)) return value;
1657
1648
  seen.add(value);
1658
1649
  if (Array.isArray(value)) return value.map((item) => this.pvtEncode(item, seen));
1659
- if (ArrayBuffer.isView(value) || value instanceof ArrayBuffer) return this.offerBytes(asOctets(value));
1650
+ if (ArrayBuffer.isView(value) || value instanceof ArrayBuffer) return this.offerBytes(value);
1660
1651
  if (!isPlainObject(value)) return value;
1661
1652
  const copy = {};
1662
1653
  for (const [key, item] of Object.entries(value)) copy[key] = this.pvtEncode(item, seen);
@@ -1744,7 +1735,7 @@ var StreamStore = class {
1744
1735
  }
1745
1736
  pvtDecode(value, seen) {
1746
1737
  if (typeof value !== "object" || value === null) return value;
1747
- if (isBytesRef(value)) return this.pvtValueFor(value.$bytes.id, "bytes", { size: value.$bytes.size });
1738
+ if (isBytesRef(value)) return this.pvtValueFor(value.$bytes.id, "bytes", value.$bytes);
1748
1739
  if (isBlobRef(value)) {
1749
1740
  const { id, size, type, name } = value.$blob;
1750
1741
  return this.pvtValueFor(id, "blob", {
@@ -1780,7 +1771,6 @@ var StreamStore = class {
1780
1771
  }
1781
1772
  if (incoming.value) return incoming.value;
1782
1773
  incoming.form = form;
1783
- const value = incoming.value = this.pvtBuild(incoming.reader, form, facts);
1784
1774
  if (facts !== void 0 && facts.size > this.maxBytes) {
1785
1775
  const reason = `stream ${id} is ${facts.size} bytes, over this side's bound of ${this.maxBytes}`;
1786
1776
  incoming.done = true;
@@ -1791,8 +1781,7 @@ var StreamStore = class {
1791
1781
  reason: "over the reader's bound"
1792
1782
  } });
1793
1783
  }
1794
- if (value instanceof RemoteBytes) value.start();
1795
- return value;
1784
+ return incoming.value = this.pvtBuild(incoming.reader, form, facts);
1796
1785
  }
1797
1786
  /** The value a name the far side announced stands for — or one that says it was never announced. */
1798
1787
  pvtValueForNamed(name) {
@@ -1807,10 +1796,27 @@ var StreamStore = class {
1807
1796
  return failed;
1808
1797
  }
1809
1798
  pvtBuild(reader, form, facts) {
1810
- if (form === "blob" && facts !== void 0) return new RemoteBlob(reader, facts);
1811
- if (form === "bytes" && facts !== void 0) return new RemoteBytes(reader, facts.size);
1799
+ if (facts === void 0) return reader;
1800
+ if (form === "blob") return new RemoteBlob(reader, {
1801
+ size: facts.size,
1802
+ type: facts.type,
1803
+ name: "name" in facts ? facts.name : void 0
1804
+ });
1805
+ if (form === "bytes") return this.pvtArray(reader, facts);
1812
1806
  return reader;
1813
1807
  }
1808
+ /**
1809
+ * The array the far side is sending: the kind it was, made here at the size its reference stated,
1810
+ * and filled as the octets land. The fill loop is the stream's one consumer, so the credit
1811
+ * machinery asks for exactly what can be stored and the array is complete before `settled` resolves.
1812
+ */
1813
+ pvtArray(reader, facts) {
1814
+ const value = facts.size > this.maxBytes ? /* @__PURE__ */ new Uint8Array(0) : allocateBytes(facts.size, facts.type, "length" in facts ? facts.length : void 0);
1815
+ const filling = fillArray(value, reader, facts.size);
1816
+ filling.catch(() => {});
1817
+ this.pvtPending.push(filling);
1818
+ return value;
1819
+ }
1814
1820
  pvtAsk(incoming) {
1815
1821
  if (incoming.done || this.pvtClosed) return;
1816
1822
  const outstanding = incoming.asked - incoming.consumed;
@@ -1968,9 +1974,70 @@ var StreamStore = class {
1968
1974
  }
1969
1975
  };
1970
1976
  /** A typed array or an `ArrayBuffer` as the octets the wire carries. */
1971
- function asOctets(value) {
1972
- if (ArrayBuffer.isView(value)) return new Uint8Array(value.buffer, value.byteOffset, value.byteLength);
1973
- return new Uint8Array(value);
1977
+ /** How many octets an element of each kind takes. A name that came off the wire is looked up here
1978
+ * rather than handed to `globalThis`, so a peer cannot name a constructor this side would run. */
1979
+ const TYPED_ARRAY_STRIDE = /* @__PURE__ */ new Map([
1980
+ ["Int8Array", 1],
1981
+ ["Uint8Array", 1],
1982
+ ["Uint8ClampedArray", 1],
1983
+ ["Int16Array", 2],
1984
+ ["Uint16Array", 2],
1985
+ ["Int32Array", 4],
1986
+ ["Uint32Array", 4],
1987
+ ["Float32Array", 4],
1988
+ ["Float64Array", 8],
1989
+ ["BigInt64Array", 8],
1990
+ ["BigUint64Array", 8]
1991
+ ]);
1992
+ function isTypedArrayName(name) {
1993
+ return TYPED_ARRAY_STRIDE.has(name);
1994
+ }
1995
+ /** The octets of a value about to cross — and, for a typed array, what they are made of. */
1996
+ function octetsOf$1(value) {
1997
+ if (!ArrayBuffer.isView(value)) return { bytes: new Uint8Array(value) };
1998
+ const bytes = new Uint8Array(value.buffer, value.byteOffset, value.byteLength);
1999
+ if (value instanceof DataView) return { bytes };
2000
+ const name = Object.prototype.toString.call(value).slice(8, -1);
2001
+ if (!isTypedArrayName(name)) return { bytes };
2002
+ const stride = TYPED_ARRAY_STRIDE.get(name) ?? 1;
2003
+ if (bytes.length % stride !== 0) return { bytes };
2004
+ return {
2005
+ bytes,
2006
+ type: name,
2007
+ length: bytes.length / stride
2008
+ };
2009
+ }
2010
+ /** The sender's kind of array, made at the element count its reference stated. */
2011
+ function allocateBytes(size, type, length) {
2012
+ if (type === void 0 || !isTypedArrayName(type)) return new Uint8Array(size);
2013
+ const stride = TYPED_ARRAY_STRIDE.get(type) ?? 1;
2014
+ if (size % stride !== 0) return new Uint8Array(size);
2015
+ const count = length !== void 0 && length * stride === size ? length : size / stride;
2016
+ switch (type) {
2017
+ case "Int8Array": return new Int8Array(count);
2018
+ case "Uint8Array": return new Uint8Array(count);
2019
+ case "Uint8ClampedArray": return new Uint8ClampedArray(count);
2020
+ case "Int16Array": return new Int16Array(count);
2021
+ case "Uint16Array": return new Uint16Array(count);
2022
+ case "Int32Array": return new Int32Array(count);
2023
+ case "Uint32Array": return new Uint32Array(count);
2024
+ case "Float32Array": return new Float32Array(count);
2025
+ case "Float64Array": return new Float64Array(count);
2026
+ case "BigInt64Array": return new BigInt64Array(count);
2027
+ case "BigUint64Array": return new BigUint64Array(count);
2028
+ }
2029
+ }
2030
+ /** Fill the array as its octets arrive. A view of the same memory is how every element kind is
2031
+ * written the same way, and how a `BigInt64Array` is filled without mixing element types. */
2032
+ async function fillArray(value, body, size) {
2033
+ const octets = new Uint8Array(value.buffer, value.byteOffset, value.byteLength);
2034
+ let at = 0;
2035
+ for await (const chunk of body) {
2036
+ if (at + chunk.length > octets.length) throw new Error(`the array is longer than the ${size} bytes it stated`);
2037
+ octets.set(chunk, at);
2038
+ at += chunk.length;
2039
+ }
2040
+ if (at !== octets.length) throw new Error(`the array is short: ${at} of ${size} octets arrived`);
1974
2041
  }
1975
2042
  function reasonOf(error) {
1976
2043
  return error instanceof Error ? error.message : String(error);
@@ -2050,6 +2117,7 @@ async function serveChannel(channel, makeProc, onSpawned, streamOptions) {
2050
2117
  throw new Error(`serveRemoteActor: expected $init (${initProblem})`);
2051
2118
  }
2052
2119
  const initFrame = decodeFrame(firstFrame, handleFor, byteStreams);
2120
+ await byteStreams.settled();
2053
2121
  if (!isInit(initFrame)) throw new Error("serveRemoteActor: expected $init");
2054
2122
  const init = initFrame.$init;
2055
2123
  const stated = init.rootName;
@@ -2101,13 +2169,29 @@ async function serveChannel(channel, makeProc, onSpawned, streamOptions) {
2101
2169
  } catch {}
2102
2170
  await end();
2103
2171
  };
2104
- function dispatch(raw) {
2172
+ /**
2173
+ * Take one frame as far as it goes now. A frame that carries nothing to wait for is handled
2174
+ * before this returns, as it always was; one that carries a typed array answers with the promise
2175
+ * its octets owe, and the queue below keeps whatever came after it behind it.
2176
+ */
2177
+ function process(raw) {
2105
2178
  const wireProblem = badReason(raw) ?? errorReason(raw);
2106
2179
  if (wireProblem !== null) {
2107
2180
  endUnreadable(wireProblem);
2108
- return;
2181
+ return null;
2109
2182
  }
2110
2183
  const frame = decodeFrame(raw, handleFor, byteStreams);
2184
+ const owed = byteStreams.owed();
2185
+ if (owed === null) {
2186
+ deliver(frame);
2187
+ return null;
2188
+ }
2189
+ return owed.then(() => {
2190
+ deliver(frame);
2191
+ });
2192
+ }
2193
+ /** What a frame means, and the octets it carried are already there when this runs. */
2194
+ function deliver(frame) {
2111
2195
  if (calls.settle(frame)) return;
2112
2196
  const to = frameTo(frame);
2113
2197
  if (to === null) return;
@@ -2158,8 +2242,42 @@ async function serveChannel(channel, makeProc, onSpawned, streamOptions) {
2158
2242
  if (call) answerCall(call, mine, write, table, byteStreams);
2159
2243
  }
2160
2244
  stopCollecting();
2161
- channel.onMessage(dispatch);
2162
- for (const frame of waiting.splice(0)) dispatch(frame);
2245
+ const later = [];
2246
+ let busy = false;
2247
+ const report = (error) => {
2248
+ if (pvtWindDown) return;
2249
+ const message = error instanceof Error ? error.message : String(error);
2250
+ console.warn(`a frame from the far side could not be handled: ${message}`);
2251
+ };
2252
+ const pump = () => {
2253
+ if (busy) return;
2254
+ busy = true;
2255
+ for (;;) {
2256
+ const next = later.shift();
2257
+ if (next === void 0) {
2258
+ busy = false;
2259
+ return;
2260
+ }
2261
+ const outcome = process(next);
2262
+ if (outcome !== null) {
2263
+ outcome.then(() => {
2264
+ busy = false;
2265
+ pump();
2266
+ }, (error) => {
2267
+ busy = false;
2268
+ report(error);
2269
+ pump();
2270
+ });
2271
+ return;
2272
+ }
2273
+ }
2274
+ };
2275
+ const schedule = (raw) => {
2276
+ later.push(raw);
2277
+ pump();
2278
+ };
2279
+ channel.onMessage(schedule);
2280
+ for (const frame of waiting.splice(0)) schedule(frame);
2163
2281
  let code = 0;
2164
2282
  const procEnded = proc.wait().then(() => void 0, (err) => {
2165
2283
  console.error("server actor error:", err);
@@ -2481,13 +2599,29 @@ function remoteClient(name, spawner, options = {}) {
2481
2599
  pvtWindDown = true;
2482
2600
  this.exit(CHANNEL_LOST);
2483
2601
  };
2484
- channel.onMessage((raw) => {
2602
+ /**
2603
+ * Take one frame as far as it goes now. A frame that carries nothing to wait for is handled
2604
+ * before this returns, as it always was; one that carries a typed array answers with the
2605
+ * promise its octets owe, and the queue below keeps whatever came after it behind it.
2606
+ */
2607
+ const process = (raw) => {
2485
2608
  if ((badReason(raw) ?? errorReason(raw)) !== null) {
2486
2609
  channel.close();
2487
2610
  wireGone();
2488
- return;
2611
+ return null;
2489
2612
  }
2490
2613
  const frame = decodeFrame(raw, handleFor, byteStreams);
2614
+ const owed = byteStreams.owed();
2615
+ if (owed === null) {
2616
+ deliver(frame);
2617
+ return null;
2618
+ }
2619
+ return owed.then(() => {
2620
+ deliver(frame);
2621
+ });
2622
+ };
2623
+ /** What a frame means, and the octets it carried are already there when this runs. */
2624
+ const deliver = (frame) => {
2491
2625
  if (calls.settle(frame)) return;
2492
2626
  const to = frameTo(frame);
2493
2627
  if (to === null) return;
@@ -2537,6 +2671,40 @@ function remoteClient(name, spawner, options = {}) {
2537
2671
  }
2538
2672
  const call = asReflectionCall(frame);
2539
2673
  if (call) answerCall(call, mine, write, table, byteStreams);
2674
+ };
2675
+ const later = [];
2676
+ let busy = false;
2677
+ const report = (error) => {
2678
+ if (pvtWindDown) return;
2679
+ const message = error instanceof Error ? error.message : String(error);
2680
+ console.warn(`a frame from the far side could not be handled: ${message}`);
2681
+ };
2682
+ const pump = () => {
2683
+ if (busy) return;
2684
+ busy = true;
2685
+ for (;;) {
2686
+ const next = later.shift();
2687
+ if (next === void 0) {
2688
+ busy = false;
2689
+ return;
2690
+ }
2691
+ const outcome = process(next);
2692
+ if (outcome !== null) {
2693
+ outcome.then(() => {
2694
+ busy = false;
2695
+ pump();
2696
+ }, (error) => {
2697
+ busy = false;
2698
+ report(error);
2699
+ pump();
2700
+ });
2701
+ return;
2702
+ }
2703
+ }
2704
+ };
2705
+ channel.onMessage((raw) => {
2706
+ later.push(raw);
2707
+ pump();
2540
2708
  });
2541
2709
  channel.onClose(() => wireGone());
2542
2710
  await start;
@@ -2660,10 +2828,14 @@ function readChunks(stream, onChunk, onEnd) {
2660
2828
  };
2661
2829
  stream.on("data", onData);
2662
2830
  stream.once("end", finish);
2831
+ stream.once("close", finish);
2832
+ stream.once("error", finish);
2663
2833
  return { stop() {
2664
2834
  stopped = true;
2665
2835
  stream.off("data", onData);
2666
2836
  stream.off("end", finish);
2837
+ stream.off("close", finish);
2838
+ stream.off("error", finish);
2667
2839
  } };
2668
2840
  }
2669
2841
  //#endregion
@@ -2745,6 +2917,6 @@ var WebSocketTransport = class {
2745
2917
  }
2746
2918
  };
2747
2919
  //#endregion
2748
- export { errorReason as A, isResume as B, json1Channel as C, badReason as D, badFrame as E, isInit as F, lowBand as G, isStop as H, isMsg as I, rootIdFor as K, isPause as L, isBad as M, isError as N, channelThrough as O, isExit as P, isProto as R, encode as S, BAD_PREFIX_LIMIT as T, PROCESS_REF as U, isState as V, isRemoteProcess as W, isStreamRef as _, remoteClient as a, VERSION as b, oneConnection as c, RemoteBlob as d, RemoteBytes as f, isBytesRef as g, isBlobRef as h, CHANNEL_LOST as i, frameReaders as j, errorFrame as k, reactor as l, StreamStore as m, WebSocketTransport as n, pumpOutput as o, RemoteStream as p, readParts as r, stderrSink as s, WS_OPEN as t, serveRemoteActor as u, makeSender as v, readFrame as w, decode as x, RemoteProcess as y, isRelease as z };
2920
+ export { frameReaders as A, isState as B, readFrame as C, channelThrough as D, badReason as E, isMsg as F, rootIdFor as G, PROCESS_REF as H, isPause as I, isProto as L, isError as M, isExit as N, errorFrame as O, isInit as P, isRelease as R, json1Channel as S, badFrame as T, isRemoteProcess as U, isStop as V, lowBand as W, makeSender as _, remoteClient as a, decode as b, oneConnection as c, RemoteBlob as d, RemoteStream as f, isStreamRef as g, isBytesRef as h, CHANNEL_LOST as i, isBad as j, errorReason as k, reactor as l, isBlobRef as m, WebSocketTransport as n, pumpOutput as o, StreamStore as p, readParts as r, stderrSink as s, WS_OPEN as t, serveRemoteActor as u, RemoteProcess as v, BAD_PREFIX_LIMIT as w, encode as x, VERSION as y, isResume as z };
2749
2921
 
2750
- //# sourceMappingURL=websocket-DkDAHMFm.js.map
2922
+ //# sourceMappingURL=websocket-1DAD3oDx.js.map