posipaki 0.45.1 → 0.46.1

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/dist/index.d.ts CHANGED
@@ -20,7 +20,7 @@ declare function defineActor<Args, InternalState, InMsg extends Message, OutMsg
20
20
  //#endregion
21
21
  //#region src/version.d.ts
22
22
  /** posipaki's release version. Must equal package.json's `version`. */
23
- declare const LIB_VERSION = "0.45.1";
23
+ declare const LIB_VERSION = "0.46.1";
24
24
  //#endregion
25
25
  export { type ActorConfig, type ActorContext, type ActorDecorated, type ActorDefinition, type ActorPlugin, type ActorReflection, type AnyProcess, AsyncProcess, type AsyncProcessFn, type ExitMessage, type HandlerFn, type HandlerOptions, type HookResult, LIB_VERSION, type Message, type MethodOptions, type PluginTransform, Process, type ProcessCtx, type ProcessFn, type SenderInfo, type SenderOrigin, type SpawnedFrom, type StopMessage, type WithSender, type WithoutSender, asyncify, callHook, chainHook, defineActor, defineMessages, mergeConfigs, propagateError, runDispatch, runDispatchAsync, spawn, spawnAsync, stopPropagation };
26
26
  //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
@@ -2,7 +2,7 @@ import { i as runDispatch } from "./util-Brtfgv68.js";
2
2
  import { a as spawnAsync, i as runDispatchAsync, o as asyncify, t as AsyncProcess } from "./process.async-B1FqZyD1.js";
3
3
  import { n as chainHook, o as propagateError, r as mergeConfigs, s as stopPropagation, t as callHook } from "./hooks-CgXhmY4r.js";
4
4
  import { n as defineMessages, t as defineActor } from "./define-actor-DR1P1PA5.js";
5
- import { t as LIB_VERSION } from "./version-COXVfzR6.js";
5
+ import { t as LIB_VERSION } from "./version-BYC8xwip.js";
6
6
  //#region src/process.ts
7
7
  /** @deprecated Use {@link spawnAsync} instead. */
8
8
  function spawn(fn, pname, tp) {
@@ -438,45 +438,6 @@ var RemoteBlob = class {
438
438
  }
439
439
  };
440
440
  /**
441
- * Bytes that crossed a connection: the sender's array, taken apart into a stream and put back
442
- * together here as the chunks arrive. Not lazy — the sender was asked the moment the reference
443
- * arrived — so awaiting this is waiting for the last chunk, not for a read to start.
444
- */
445
- var RemoteBytes = class {
446
- constructor(body, size) {
447
- this.filling = null;
448
- this.body = body;
449
- this.size = size;
450
- }
451
- /** Start re-assembling. Called by the store once its record for this stream is in place. */
452
- start() {
453
- this.bytes().catch(() => {});
454
- }
455
- /** The octets, once they are all here. */
456
- bytes() {
457
- this.filling ??= this.pvtFill();
458
- return this.filling;
459
- }
460
- /** The same octets as an array's buffer, for a caller that wants the platform's shape. */
461
- async arrayBuffer() {
462
- return (await this.bytes()).buffer;
463
- }
464
- then(onfulfilled, onrejected) {
465
- return this.bytes().then(onfulfilled, onrejected);
466
- }
467
- async pvtFill() {
468
- const all = new Uint8Array(this.size);
469
- let at = 0;
470
- for await (const chunk of this.body) {
471
- if (at + chunk.length > all.length) throw new Error(`the array is longer than the ${this.size} bytes it stated`);
472
- all.set(chunk, at);
473
- at += chunk.length;
474
- }
475
- if (at !== all.length) throw new Error(`the array is short: ${at} of ${this.size} octets arrived`);
476
- return all;
477
- }
478
- };
479
- /**
480
441
  * One connection's streams, as this side sees them.
481
442
  *
482
443
  * Both directions are in one table, because both are the same numbering: what this side offers
@@ -490,6 +451,7 @@ var StreamStore = class {
490
451
  this.pvtRefused = /* @__PURE__ */ new Map();
491
452
  this.pvtNamesOut = /* @__PURE__ */ new Map();
492
453
  this.pvtNamesIn = /* @__PURE__ */ new Map();
454
+ this.pvtPending = [];
493
455
  this.pvtNamedListeners = /* @__PURE__ */ new Set();
494
456
  this.pvtSegmentOff = null;
495
457
  this.pvtClosed = false;
@@ -532,14 +494,18 @@ var StreamStore = class {
532
494
  } };
533
495
  }
534
496
  /**
535
- * Offer bytes this side already holds. The reference states the length, so the far side can
536
- * check it against its bound and size the array before the first chunk arrives — a typed array
537
- * is one piece, so the wire carries it as a stream of one.
497
+ * Offer bytes this side already holds. The reference states the length, so the far side can check
498
+ * it against its bound and make room before the first chunk arrives — and, when the value is a typed
499
+ * array, the element kind and count too, so the same kind of array is made on the other side. The
500
+ * octets are one piece, and the wire carries them as a stream of one.
538
501
  */
539
- offerBytes(bytes) {
502
+ offerBytes(value) {
503
+ const { bytes, type, length } = octetsOf(value);
540
504
  return { $bytes: {
541
505
  id: this.pvtAnnounce(this.pvtOnePiece(bytes)),
542
- size: bytes.length
506
+ size: bytes.length,
507
+ ...type === void 0 ? {} : { type },
508
+ ...length === void 0 ? {} : { length }
543
509
  } };
544
510
  }
545
511
  pvtAnnounce(source, name) {
@@ -583,8 +549,22 @@ var StreamStore = class {
583
549
  }
584
550
  /** A value just read: every reference in it becomes something this side can read. */
585
551
  decode(value) {
552
+ this.pvtPending = [];
586
553
  return this.pvtDecode(value, /* @__PURE__ */ new Set());
587
554
  }
555
+ /**
556
+ * What the octets of a just-decoded value still owe. A message is handed to its process only once
557
+ * this has settled, so a typed array in a body is whole when the handler reads it; a stream, a blob
558
+ * and a plain value carry no octets of their own and settle at once.
559
+ */
560
+ owed() {
561
+ if (this.pvtPending.length === 0) return null;
562
+ return Promise.all(this.pvtPending).then(() => void 0);
563
+ }
564
+ /** The same question as a promise, for a caller that would rather always await. */
565
+ settled() {
566
+ return this.owed() ?? Promise.resolve();
567
+ }
588
568
  /** Drop every stream of this connection, in both directions. Called when it ends. */
589
569
  close() {
590
570
  if (this.pvtClosed) return;
@@ -650,7 +630,7 @@ var StreamStore = class {
650
630
  if (seen.has(value)) return value;
651
631
  seen.add(value);
652
632
  if (Array.isArray(value)) return value.map((item) => this.pvtEncode(item, seen));
653
- if (ArrayBuffer.isView(value) || value instanceof ArrayBuffer) return this.offerBytes(asOctets(value));
633
+ if (ArrayBuffer.isView(value) || value instanceof ArrayBuffer) return this.offerBytes(value);
654
634
  if (!isPlainObject(value)) return value;
655
635
  const copy = {};
656
636
  for (const [key, item] of Object.entries(value)) copy[key] = this.pvtEncode(item, seen);
@@ -738,7 +718,7 @@ var StreamStore = class {
738
718
  }
739
719
  pvtDecode(value, seen) {
740
720
  if (typeof value !== "object" || value === null) return value;
741
- if (isBytesRef(value)) return this.pvtValueFor(value.$bytes.id, "bytes", { size: value.$bytes.size });
721
+ if (isBytesRef(value)) return this.pvtValueFor(value.$bytes.id, "bytes", value.$bytes);
742
722
  if (isBlobRef(value)) {
743
723
  const { id, size, type, name } = value.$blob;
744
724
  return this.pvtValueFor(id, "blob", {
@@ -774,7 +754,6 @@ var StreamStore = class {
774
754
  }
775
755
  if (incoming.value) return incoming.value;
776
756
  incoming.form = form;
777
- const value = incoming.value = this.pvtBuild(incoming.reader, form, facts);
778
757
  if (facts !== void 0 && facts.size > this.maxBytes) {
779
758
  const reason = `stream ${id} is ${facts.size} bytes, over this side's bound of ${this.maxBytes}`;
780
759
  incoming.done = true;
@@ -785,8 +764,7 @@ var StreamStore = class {
785
764
  reason: "over the reader's bound"
786
765
  } });
787
766
  }
788
- if (value instanceof RemoteBytes) value.start();
789
- return value;
767
+ return incoming.value = this.pvtBuild(incoming.reader, form, facts);
790
768
  }
791
769
  /** The value a name the far side announced stands for — or one that says it was never announced. */
792
770
  pvtValueForNamed(name) {
@@ -801,10 +779,27 @@ var StreamStore = class {
801
779
  return failed;
802
780
  }
803
781
  pvtBuild(reader, form, facts) {
804
- if (form === "blob" && facts !== void 0) return new RemoteBlob(reader, facts);
805
- if (form === "bytes" && facts !== void 0) return new RemoteBytes(reader, facts.size);
782
+ if (facts === void 0) return reader;
783
+ if (form === "blob") return new RemoteBlob(reader, {
784
+ size: facts.size,
785
+ type: facts.type,
786
+ name: "name" in facts ? facts.name : void 0
787
+ });
788
+ if (form === "bytes") return this.pvtArray(reader, facts);
806
789
  return reader;
807
790
  }
791
+ /**
792
+ * The array the far side is sending: the kind it was, made here at the size its reference stated,
793
+ * and filled as the octets land. The fill loop is the stream's one consumer, so the credit
794
+ * machinery asks for exactly what can be stored and the array is complete before `settled` resolves.
795
+ */
796
+ pvtArray(reader, facts) {
797
+ const value = facts.size > this.maxBytes ? /* @__PURE__ */ new Uint8Array(0) : allocateBytes(facts.size, facts.type, "length" in facts ? facts.length : void 0);
798
+ const filling = fillArray(value, reader, facts.size);
799
+ filling.catch(() => {});
800
+ this.pvtPending.push(filling);
801
+ return value;
802
+ }
808
803
  pvtAsk(incoming) {
809
804
  if (incoming.done || this.pvtClosed) return;
810
805
  const outstanding = incoming.asked - incoming.consumed;
@@ -962,9 +957,70 @@ var StreamStore = class {
962
957
  }
963
958
  };
964
959
  /** A typed array or an `ArrayBuffer` as the octets the wire carries. */
965
- function asOctets(value) {
966
- if (ArrayBuffer.isView(value)) return new Uint8Array(value.buffer, value.byteOffset, value.byteLength);
967
- return new Uint8Array(value);
960
+ /** How many octets an element of each kind takes. A name that came off the wire is looked up here
961
+ * rather than handed to `globalThis`, so a peer cannot name a constructor this side would run. */
962
+ const TYPED_ARRAY_STRIDE = /* @__PURE__ */ new Map([
963
+ ["Int8Array", 1],
964
+ ["Uint8Array", 1],
965
+ ["Uint8ClampedArray", 1],
966
+ ["Int16Array", 2],
967
+ ["Uint16Array", 2],
968
+ ["Int32Array", 4],
969
+ ["Uint32Array", 4],
970
+ ["Float32Array", 4],
971
+ ["Float64Array", 8],
972
+ ["BigInt64Array", 8],
973
+ ["BigUint64Array", 8]
974
+ ]);
975
+ function isTypedArrayName(name) {
976
+ return TYPED_ARRAY_STRIDE.has(name);
977
+ }
978
+ /** The octets of a value about to cross — and, for a typed array, what they are made of. */
979
+ function octetsOf(value) {
980
+ if (!ArrayBuffer.isView(value)) return { bytes: new Uint8Array(value) };
981
+ const bytes = new Uint8Array(value.buffer, value.byteOffset, value.byteLength);
982
+ if (value instanceof DataView) return { bytes };
983
+ const name = Object.prototype.toString.call(value).slice(8, -1);
984
+ if (!isTypedArrayName(name)) return { bytes };
985
+ const stride = TYPED_ARRAY_STRIDE.get(name) ?? 1;
986
+ if (bytes.length % stride !== 0) return { bytes };
987
+ return {
988
+ bytes,
989
+ type: name,
990
+ length: bytes.length / stride
991
+ };
992
+ }
993
+ /** The sender's kind of array, made at the element count its reference stated. */
994
+ function allocateBytes(size, type, length) {
995
+ if (type === void 0 || !isTypedArrayName(type)) return new Uint8Array(size);
996
+ const stride = TYPED_ARRAY_STRIDE.get(type) ?? 1;
997
+ if (size % stride !== 0) return new Uint8Array(size);
998
+ const count = length !== void 0 && length * stride === size ? length : size / stride;
999
+ switch (type) {
1000
+ case "Int8Array": return new Int8Array(count);
1001
+ case "Uint8Array": return new Uint8Array(count);
1002
+ case "Uint8ClampedArray": return new Uint8ClampedArray(count);
1003
+ case "Int16Array": return new Int16Array(count);
1004
+ case "Uint16Array": return new Uint16Array(count);
1005
+ case "Int32Array": return new Int32Array(count);
1006
+ case "Uint32Array": return new Uint32Array(count);
1007
+ case "Float32Array": return new Float32Array(count);
1008
+ case "Float64Array": return new Float64Array(count);
1009
+ case "BigInt64Array": return new BigInt64Array(count);
1010
+ case "BigUint64Array": return new BigUint64Array(count);
1011
+ }
1012
+ }
1013
+ /** Fill the array as its octets arrive. A view of the same memory is how every element kind is
1014
+ * written the same way, and how a `BigInt64Array` is filled without mixing element types. */
1015
+ async function fillArray(value, body, size) {
1016
+ const octets = new Uint8Array(value.buffer, value.byteOffset, value.byteLength);
1017
+ let at = 0;
1018
+ for await (const chunk of body) {
1019
+ if (at + chunk.length > octets.length) throw new Error(`the array is longer than the ${size} bytes it stated`);
1020
+ octets.set(chunk, at);
1021
+ at += chunk.length;
1022
+ }
1023
+ if (at !== octets.length) throw new Error(`the array is short: ${at} of ${size} octets arrived`);
968
1024
  }
969
1025
  function reasonOf(error) {
970
1026
  return error instanceof Error ? error.message : String(error);
@@ -1111,13 +1167,14 @@ var LineTransport = class {
1111
1167
  this.pvtOnMessage = null;
1112
1168
  this.pvtOnBytes = null;
1113
1169
  this.pvtOnClose = null;
1170
+ this.pvtSaid = false;
1114
1171
  this.pvtClosed = false;
1115
1172
  this.pvtClosing = null;
1116
1173
  this.streams = streams;
1117
1174
  readParts(streams.read, (line) => this.pvtClosed ? void 0 : this.pvtOnMessage?.(line), (bytes) => {
1118
1175
  if (!this.pvtClosed) this.pvtOnBytes?.(bytes);
1119
1176
  }, () => {
1120
- this.pvtOnClose?.();
1177
+ this.pvtSayClosed();
1121
1178
  this.close();
1122
1179
  });
1123
1180
  streams.read.on("error", () => {
@@ -1176,6 +1233,12 @@ var LineTransport = class {
1176
1233
  this.pvtClosing ??= this.pvtClose();
1177
1234
  await this.pvtClosing;
1178
1235
  }
1236
+ /** Say the wire is over, once: the reader's end and a close here are one ending. */
1237
+ pvtSayClosed() {
1238
+ if (this.pvtSaid) return;
1239
+ this.pvtSaid = true;
1240
+ this.pvtOnClose?.();
1241
+ }
1179
1242
  async pvtClose() {
1180
1243
  await Promise.resolve();
1181
1244
  this.pvtClosed = true;
@@ -1185,6 +1248,7 @@ var LineTransport = class {
1185
1248
  try {
1186
1249
  if (!this.streams.write.writableEnded) this.streams.write.end();
1187
1250
  } catch {}
1251
+ this.pvtSayClosed();
1188
1252
  }
1189
1253
  };
1190
1254
  //#endregion
@@ -1197,6 +1261,7 @@ var FifoUtf8NlineTransport = class FifoUtf8NlineTransport {
1197
1261
  this.closed = false;
1198
1262
  this.closingPromise = null;
1199
1263
  this.pvtError = null;
1264
+ this.pvtSaid = false;
1200
1265
  this.readFd = opts.readFd ?? null;
1201
1266
  this.writeFd = opts.writeFd ?? null;
1202
1267
  if (this.readFd) {
@@ -1204,7 +1269,7 @@ var FifoUtf8NlineTransport = class FifoUtf8NlineTransport {
1204
1269
  this.reader = readParts(this.rs, (line) => this.closed ? void 0 : this.pvtOnMessage?.(line), (bytes) => {
1205
1270
  if (!this.closed) this.pvtOnBytes?.(bytes);
1206
1271
  }, () => {
1207
- this.pvtOnClose?.();
1272
+ this.pvtSayClosed();
1208
1273
  this.close();
1209
1274
  });
1210
1275
  this.rs.on("error", (err) => {
@@ -1312,6 +1377,12 @@ var FifoUtf8NlineTransport = class FifoUtf8NlineTransport {
1312
1377
  await this.closingPromise;
1313
1378
  this.closed = true;
1314
1379
  }
1380
+ /** Say the wire is over, once: the reader's end and a close here are one ending. */
1381
+ pvtSayClosed() {
1382
+ if (this.pvtSaid) return;
1383
+ this.pvtSaid = true;
1384
+ this.pvtOnClose?.();
1385
+ }
1315
1386
  async pvtClose() {
1316
1387
  await Promise.resolve();
1317
1388
  if (this.reader) {
@@ -1344,6 +1415,7 @@ var FifoUtf8NlineTransport = class FifoUtf8NlineTransport {
1344
1415
  } catch {}
1345
1416
  this.writeFd = null;
1346
1417
  }
1418
+ this.pvtSayClosed();
1347
1419
  }
1348
1420
  };
1349
1421
  //#endregion