@zlink-systems/stream-connector 0.22.0 → 0.24.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.
@@ -120,7 +120,8 @@ var defaultHeaderFlags = {
120
120
  hasRequestSeq: 1,
121
121
  hasMetadata: 2,
122
122
  hasCorrelationId: 8,
123
- hasFlowId: 16
123
+ hasFlowId: 16,
124
+ hasActorSlot: 32
124
125
  };
125
126
  var ZLINK_STREAM_FORMAT_MARKER = 242;
126
127
  var ZLINK_STREAM_RESPONSE_KIND = 3;
@@ -167,6 +168,7 @@ function encodeStreamWireHeader(header, flagOverrides) {
167
168
  }
168
169
  const hasCorrelation = correlationBytes !== void 0;
169
170
  const hasFlow = header.flowId !== void 0 || header.flowOrigin !== void 0;
171
+ const hasActorSlot = header.actorSlot !== void 0;
170
172
  if (hasFlow && (header.flowId === void 0 || header.flowOrigin === void 0)) {
171
173
  throw new Error("Stream flow id and origin must be provided together.");
172
174
  }
@@ -174,13 +176,17 @@ function encodeStreamWireHeader(header, flagOverrides) {
174
176
  if (header.flowOrigin !== void 0 && ![1, 2, 3, 4].includes(header.flowOrigin)) {
175
177
  throw new Error("Stream flow origin is invalid.");
176
178
  }
179
+ if (header.actorSlot !== void 0 && (!Number.isInteger(header.actorSlot) || header.actorSlot < 1 || header.actorSlot > 65535)) {
180
+ throw new Error("Stream actor slot is invalid.");
181
+ }
177
182
  let headerFlags = header.flags;
178
183
  headerFlags = hasRequestSeq ? headerFlags | flags.hasRequestSeq : headerFlags & ~flags.hasRequestSeq;
179
184
  headerFlags = hasMetadata ? headerFlags | flags.hasMetadata : headerFlags & ~flags.hasMetadata;
180
185
  headerFlags = hasCorrelation ? headerFlags | flags.hasCorrelationId : headerFlags & ~flags.hasCorrelationId;
181
186
  headerFlags = hasFlow ? headerFlags | flags.hasFlowId : headerFlags & ~flags.hasFlowId;
187
+ headerFlags = hasActorSlot ? headerFlags | flags.hasActorSlot : headerFlags & ~flags.hasActorSlot;
182
188
  const metadataBytes = hasMetadata ? encodeStreamWireMetadata(header.metadata) : new Uint8Array();
183
- const size = 4 + (hasRequestSeq ? 8 : 0) + 1 + nameBytes.length + (hasMetadata ? 2 + metadataBytes.length : 0) + (hasCorrelation ? 1 + correlationBytes.length : 0) + (hasFlow ? 37 : 0);
189
+ const size = 4 + (hasRequestSeq ? 8 : 0) + 1 + nameBytes.length + (hasMetadata ? 2 + metadataBytes.length : 0) + (hasCorrelation ? 1 + correlationBytes.length : 0) + (hasFlow ? 37 : 0) + (hasActorSlot ? 2 : 0);
184
190
  const buffer = new Uint8Array(size);
185
191
  let offset = 0;
186
192
  buffer[offset++] = ZLINK_STREAM_FORMAT_MARKER;
@@ -213,6 +219,9 @@ function encodeStreamWireHeader(header, flagOverrides) {
213
219
  offset += 36;
214
220
  buffer[offset++] = header.flowOrigin;
215
221
  }
222
+ if (hasActorSlot) {
223
+ writeUInt16BE(buffer, offset, header.actorSlot);
224
+ }
216
225
  return buffer;
217
226
  }
218
227
  function decodeStreamWireHeader(header, flagOverrides, includeFlow = true) {
@@ -231,7 +240,8 @@ function decodeStreamWireHeader(header, flagOverrides, includeFlow = true) {
231
240
  const hasMetadata = (headerFlags & flags.hasMetadata) !== 0;
232
241
  const hasCorrelation = (headerFlags & flags.hasCorrelationId) !== 0;
233
242
  const hasFlow = (headerFlags & flags.hasFlowId) !== 0;
234
- if ((headerFlags & ~31) !== 0) {
243
+ const hasActorSlot = (headerFlags & flags.hasActorSlot) !== 0;
244
+ if ((headerFlags & ~63) !== 0) {
235
245
  throw new Error("Unknown mandatory stream header flag.");
236
246
  }
237
247
  let requestSeq;
@@ -286,6 +296,17 @@ function decodeStreamWireHeader(header, flagOverrides, includeFlow = true) {
286
296
  }
287
297
  flowOrigin = includeFlow ? decodedFlowOrigin : void 0;
288
298
  }
299
+ let actorSlot;
300
+ if (hasActorSlot) {
301
+ if (header.length - offset < 2) {
302
+ throw new Error("Stream actor slot is incomplete.");
303
+ }
304
+ actorSlot = readUInt16BE(header, offset);
305
+ if (actorSlot === 0) {
306
+ throw new Error("Stream actor slot must not be zero.");
307
+ }
308
+ offset += 2;
309
+ }
289
310
  if (offset !== header.length) {
290
311
  throw new Error("Stream header has trailing bytes.");
291
312
  }
@@ -298,7 +319,8 @@ function decodeStreamWireHeader(header, flagOverrides, includeFlow = true) {
298
319
  metadata: decodedMetadata.metadata,
299
320
  correlationId,
300
321
  flowId,
301
- flowOrigin
322
+ flowOrigin,
323
+ actorSlot
302
324
  };
303
325
  }
304
326
  function validateFlowId(flowId) {
@@ -464,13 +486,6 @@ var ZlinkStreamDispatchMode = /* @__PURE__ */ ((ZlinkStreamDispatchMode2) => {
464
486
  ZlinkStreamDispatchMode2["Immediate"] = "immediate";
465
487
  return ZlinkStreamDispatchMode2;
466
488
  })(ZlinkStreamDispatchMode || {});
467
- var ZlinkStreamDiagnosticsLevel = /* @__PURE__ */ ((ZlinkStreamDiagnosticsLevel4) => {
468
- ZlinkStreamDiagnosticsLevel4["Off"] = "off";
469
- ZlinkStreamDiagnosticsLevel4["Errors"] = "errors";
470
- ZlinkStreamDiagnosticsLevel4["Normal"] = "normal";
471
- ZlinkStreamDiagnosticsLevel4["Detailed"] = "detailed";
472
- return ZlinkStreamDiagnosticsLevel4;
473
- })(ZlinkStreamDiagnosticsLevel || {});
474
489
  var ZlinkStreamMessageKind = /* @__PURE__ */ ((ZlinkStreamMessageKind2) => {
475
490
  ZlinkStreamMessageKind2[ZlinkStreamMessageKind2["Send"] = 1] = "Send";
476
491
  ZlinkStreamMessageKind2[ZlinkStreamMessageKind2["Request"] = 2] = "Request";
@@ -486,6 +501,7 @@ var ZlinkStreamHeaderFlags = /* @__PURE__ */ ((ZlinkStreamHeaderFlags2) => {
486
501
  ZlinkStreamHeaderFlags2[ZlinkStreamHeaderFlags2["PayloadCompressed"] = 4] = "PayloadCompressed";
487
502
  ZlinkStreamHeaderFlags2[ZlinkStreamHeaderFlags2["HasCorrelationId"] = 8] = "HasCorrelationId";
488
503
  ZlinkStreamHeaderFlags2[ZlinkStreamHeaderFlags2["HasFlowId"] = 16] = "HasFlowId";
504
+ ZlinkStreamHeaderFlags2[ZlinkStreamHeaderFlags2["HasActorSlot"] = 32] = "HasActorSlot";
489
505
  return ZlinkStreamHeaderFlags2;
490
506
  })(ZlinkStreamHeaderFlags || {});
491
507
  var ZlinkStreamErrorCode = /* @__PURE__ */ ((ZlinkStreamErrorCode2) => {
@@ -734,15 +750,16 @@ function validateName(name, allowReserved = false) {
734
750
 
735
751
  // packages/stream-connector/src/Runtime/Calls/ZlinkStreamCallBuilders.ts
736
752
  var ZlinkStreamCallBuilderState = class {
753
+ constructor(name, actorSlot, validateActor) {
754
+ this.actorSlot = actorSlot;
755
+ this.validateActor = validateActor;
756
+ this.name = name;
757
+ }
737
758
  executed = false;
738
759
  name;
739
760
  metadata = ZlinkStreamMetadataMap.empty;
740
761
  timeoutMs;
741
762
  compress = false;
742
- flow;
743
- constructor(name) {
744
- this.name = name;
745
- }
746
763
  ensureNotExecuted() {
747
764
  if (this.executed) {
748
765
  throw connectorError(
@@ -751,6 +768,7 @@ var ZlinkStreamCallBuilderState = class {
751
768
  );
752
769
  }
753
770
  this.executed = true;
771
+ this.validateActor?.();
754
772
  }
755
773
  resolveMessageName() {
756
774
  if (this.name === void 0) {
@@ -763,10 +781,10 @@ var ZlinkStreamCallBuilderState = class {
763
781
  }
764
782
  };
765
783
  var ZlinkStreamSendBuilder = class {
766
- constructor(connector, name, payload) {
784
+ constructor(connector, name, payload, actorSlot, validateActor) {
767
785
  this.connector = connector;
768
786
  this.payload = payload;
769
- this.state = new ZlinkStreamCallBuilderState(name);
787
+ this.state = new ZlinkStreamCallBuilderState(name, actorSlot, validateActor);
770
788
  }
771
789
  state;
772
790
  packetName(name) {
@@ -782,10 +800,6 @@ var ZlinkStreamSendBuilder = class {
782
800
  this.state.compress = true;
783
801
  return this;
784
802
  }
785
- flowFrom(flow) {
786
- this.state.flow = flow;
787
- return this;
788
- }
789
803
  async submit(signal) {
790
804
  throwIfAborted(signal);
791
805
  this.state.ensureNotExecuted();
@@ -797,15 +811,16 @@ var ZlinkStreamSendBuilder = class {
797
811
  this.state.compress,
798
812
  void 0,
799
813
  signal,
800
- this.state.flow
814
+ void 0,
815
+ this.state.actorSlot
801
816
  );
802
817
  }
803
818
  };
804
819
  var ZlinkStreamRequestBuilder = class {
805
- constructor(connector, name, payload) {
820
+ constructor(connector, name, payload, actorSlot, validateActor) {
806
821
  this.connector = connector;
807
822
  this.payload = payload;
808
- this.state = new ZlinkStreamCallBuilderState(name);
823
+ this.state = new ZlinkStreamCallBuilderState(name, actorSlot, validateActor);
809
824
  }
810
825
  state;
811
826
  packetName(name) {
@@ -825,10 +840,6 @@ var ZlinkStreamRequestBuilder = class {
825
840
  this.state.compress = true;
826
841
  return this;
827
842
  }
828
- flowFrom(flow) {
829
- this.state.flow = flow;
830
- return this;
831
- }
832
843
  submit(signalOrCallback) {
833
844
  this.state.ensureNotExecuted();
834
845
  const operation = this.connector.requestEncoded(
@@ -838,7 +849,7 @@ var ZlinkStreamRequestBuilder = class {
838
849
  this.state.compress,
839
850
  this.state.timeoutMs ?? this.connector.options.requestTimeoutMs,
840
851
  typeof signalOrCallback === "function" ? void 0 : signalOrCallback,
841
- this.state.flow
852
+ this.state.actorSlot
842
853
  );
843
854
  if (typeof signalOrCallback === "function") {
844
855
  operation.then(
@@ -860,7 +871,7 @@ var ZlinkStreamRequestBuilder = class {
860
871
  this.state.compress,
861
872
  this.state.timeoutMs ?? this.connector.options.requestTimeoutMs,
862
873
  signal,
863
- this.state.flow
874
+ this.state.actorSlot
864
875
  );
865
876
  }
866
877
  };
@@ -1216,8 +1227,7 @@ var ZlinkStreamHeaderCodec = class {
1216
1227
  name: header.name,
1217
1228
  metadata: header.metadata.values,
1218
1229
  correlationId: header.correlationId,
1219
- flowId: header.flowId,
1220
- flowOrigin: encodeFlowOrigin(header.flowOrigin)
1230
+ actorSlot: header.actorSlot
1221
1231
  });
1222
1232
  } catch (cause) {
1223
1233
  throw connectorError(
@@ -1227,15 +1237,10 @@ var ZlinkStreamHeaderCodec = class {
1227
1237
  );
1228
1238
  }
1229
1239
  }
1230
- /**
1231
- * `includeFlow=false` (diagnostics Off, spec 27 §4) skips reading and
1232
- * validating the inbound flow fields while the structural length checks in
1233
- * the wire decoder are preserved.
1234
- */
1235
- static decode(header, includeFlow = true) {
1240
+ static decode(header) {
1236
1241
  let decoded;
1237
1242
  try {
1238
- const wire = decodeStreamWireHeader(header, void 0, includeFlow);
1243
+ const wire = decodeStreamWireHeader(header, void 0, false);
1239
1244
  const metadata = wire.metadata.size === 0 ? ZlinkStreamMetadataMap.empty : ZlinkStreamMetadataMap.from(wire.metadata);
1240
1245
  decoded = {
1241
1246
  kind: wire.kind,
@@ -1245,8 +1250,7 @@ var ZlinkStreamHeaderCodec = class {
1245
1250
  name: wire.name,
1246
1251
  metadata,
1247
1252
  correlationId: wire.correlationId,
1248
- flowId: wire.flowId,
1249
- flowOrigin: decodeFlowOrigin(wire.flowOrigin)
1253
+ actorSlot: wire.actorSlot
1250
1254
  };
1251
1255
  } catch (cause) {
1252
1256
  throw connectorError(
@@ -1269,7 +1273,7 @@ function isReplyKind2(kind) {
1269
1273
  function streamWireErrorMessage2(cause) {
1270
1274
  return cause instanceof Error ? cause.message : "Stream header is invalid.";
1271
1275
  }
1272
- function buildHeader(kind, name, codec, metadata, compress, requestSeq, correlationId, flowId, flowOrigin) {
1276
+ function buildHeader(kind, name, codec, metadata, compress, requestSeq, correlationId, actorSlot) {
1273
1277
  let flags = 0 /* None */;
1274
1278
  if (requestSeq !== void 0) {
1275
1279
  flags |= 1 /* HasRequestSeq */;
@@ -1283,8 +1287,17 @@ function buildHeader(kind, name, codec, metadata, compress, requestSeq, correlat
1283
1287
  if (correlationId !== void 0 && correlationId.length > 0) {
1284
1288
  flags |= 8 /* HasCorrelationId */;
1285
1289
  }
1286
- if (flowId !== void 0) flags |= 16 /* HasFlowId */;
1287
- return { kind, codec, flags, requestSeq, name, metadata, correlationId, flowId, flowOrigin };
1290
+ if (actorSlot !== void 0) flags |= 32 /* HasActorSlot */;
1291
+ return {
1292
+ kind,
1293
+ codec,
1294
+ flags,
1295
+ requestSeq,
1296
+ name,
1297
+ metadata,
1298
+ correlationId,
1299
+ actorSlot
1300
+ };
1288
1301
  }
1289
1302
  function validateHeaderSemantics(header) {
1290
1303
  validateEnum(header.kind, header.codec, header.flags);
@@ -1310,8 +1323,9 @@ function validateHeaderSemantics(header) {
1310
1323
  }
1311
1324
  if (header.kind === 5 /* Control */) {
1312
1325
  const hasCorrelation = header.correlationId !== void 0 && header.correlationId.length > 0 || (header.flags & 8 /* HasCorrelationId */) !== 0;
1313
- const hasFlow = header.flowId !== void 0 || header.flowOrigin !== void 0 || (header.flags & 16 /* HasFlowId */) !== 0;
1314
- if (header.flags !== 0 /* None */ || hasRequestSeq || hasMetadata || hasCorrelation || hasFlow || header.codec !== 0 /* Raw */) {
1326
+ const hasFlow = (header.flags & 16 /* HasFlowId */) !== 0;
1327
+ const hasActorSlot = header.actorSlot !== void 0 || (header.flags & 32 /* HasActorSlot */) !== 0;
1328
+ if (header.flags !== 0 /* None */ || hasRequestSeq || hasMetadata || hasCorrelation || hasFlow || hasActorSlot || header.codec !== 0 /* Raw */) {
1315
1329
  throw connectorError(
1316
1330
  "frameDecodeFailed" /* FrameDecodeFailed */,
1317
1331
  "Control packet must use raw codec and must not contain flags."
@@ -1326,17 +1340,11 @@ function validateEnum(kind, codec, flags) {
1326
1340
  if (![0, 1, 2, 3].includes(codec)) {
1327
1341
  throw connectorError("frameDecodeFailed" /* FrameDecodeFailed */, "Unknown stream codec.");
1328
1342
  }
1329
- const known = 1 /* HasRequestSeq */ | 2 /* HasMetadata */ | 4 /* PayloadCompressed */ | 8 /* HasCorrelationId */ | 16 /* HasFlowId */;
1343
+ const known = 1 /* HasRequestSeq */ | 2 /* HasMetadata */ | 4 /* PayloadCompressed */ | 8 /* HasCorrelationId */ | 16 /* HasFlowId */ | 32 /* HasActorSlot */;
1330
1344
  if ((flags & ~known) !== 0) {
1331
1345
  throw connectorError("frameDecodeFailed" /* FrameDecodeFailed */, "Unknown stream header flag.");
1332
1346
  }
1333
1347
  }
1334
- function encodeFlowOrigin(origin) {
1335
- return origin === void 0 ? void 0 : { Inbound: 1, Timer: 2, Application: 3, Lifecycle: 4 }[origin];
1336
- }
1337
- function decodeFlowOrigin(origin) {
1338
- return origin === void 0 ? void 0 : { 1: "Inbound", 2: "Timer", 3: "Application", 4: "Lifecycle" }[origin];
1339
- }
1340
1348
 
1341
1349
  // packages/stream-connector/src/Runtime/Protocol/ZlinkStreamFrameProtocol.ts
1342
1350
  var ZLINK_STREAM_HEARTBEAT_PING = "$zlink.heartbeat.ping";
@@ -1345,7 +1353,7 @@ var ZlinkStreamFrameProtocol = class {
1345
1353
  constructor(options) {
1346
1354
  this.options = options;
1347
1355
  }
1348
- encode(kind, name, payload, metadata, compress, requestSeq, correlationId, flowId, flowOrigin) {
1356
+ encode(kind, name, payload, metadata, compress, requestSeq, correlationId, actorSlot) {
1349
1357
  const payloadBytes = compress ? compressPayload(payload.payload, this.options.compression, this.options.compressionCodec) : payload.payload;
1350
1358
  const header = buildHeader(
1351
1359
  kind,
@@ -1355,8 +1363,7 @@ var ZlinkStreamFrameProtocol = class {
1355
1363
  compress,
1356
1364
  requestSeq,
1357
1365
  correlationId,
1358
- flowId,
1359
- flowOrigin
1366
+ actorSlot
1360
1367
  );
1361
1368
  return this.encodeFrame(header, payloadBytes);
1362
1369
  }
@@ -1372,21 +1379,16 @@ var ZlinkStreamFrameProtocol = class {
1372
1379
  payload
1373
1380
  );
1374
1381
  }
1375
- decode(frameBytes, flowEnabled = this.flowEnabled()) {
1382
+ decode(frameBytes) {
1376
1383
  const frame = ZlinkStreamFrameCodec.decode(frameBytes);
1377
1384
  return {
1378
- // Spec 27 §4: with diagnostics Off the inbound flow fields are neither
1379
- // read nor validated (structural length checks are preserved).
1380
- header: ZlinkStreamHeaderCodec.decode(frame.header, flowEnabled),
1385
+ header: ZlinkStreamHeaderCodec.decode(frame.header),
1381
1386
  payload: frame.payload
1382
1387
  };
1383
1388
  }
1384
- flowEnabled() {
1385
- return this.options.diagnosticsLevel !== "off" /* Off */;
1386
- }
1387
- decodeFrames(chunk, flowEnabled = this.flowEnabled()) {
1389
+ decodeFrames(chunk) {
1388
1390
  return splitZlinkStreamFrames(chunk).map((frame) => {
1389
- const decoded = this.decode(frame, flowEnabled);
1391
+ const decoded = this.decode(frame);
1390
1392
  if (decoded.payload.length > this.options.maxReceivePayloadSize) {
1391
1393
  throw connectorError(
1392
1394
  "frameTooLarge" /* FrameTooLarge */,
@@ -1438,12 +1440,6 @@ function parseEndpoint(endpoint) {
1438
1440
  }
1439
1441
 
1440
1442
  // packages/stream-connector/src/Runtime/ZlinkStreamConnectorOptions.ts
1441
- var validDiagnosticsLevels = /* @__PURE__ */ new Set([
1442
- "off" /* Off */,
1443
- "errors" /* Errors */,
1444
- "normal" /* Normal */,
1445
- "detailed" /* Detailed */
1446
- ]);
1447
1443
  function normalizeOptions(options, defaultTransportFactory) {
1448
1444
  const endpoint = options.endpoint;
1449
1445
  if (endpoint.trim().length === 0) {
@@ -1463,7 +1459,6 @@ function normalizeOptions(options, defaultTransportFactory) {
1463
1459
  validatePositive(options.maxReceivePayloadSize ?? 64 * 1024, "MaxReceivePayloadSize");
1464
1460
  validateHeartbeat(options.heartbeat);
1465
1461
  validateReconnect(options.reconnect);
1466
- validateDiagnosticsLevel(options.diagnosticsLevel);
1467
1462
  return {
1468
1463
  endpoint,
1469
1464
  transport: inferredTransport,
@@ -1489,10 +1484,7 @@ function normalizeOptions(options, defaultTransportFactory) {
1489
1484
  compressionCodec: resolveCompressionCodec2(options),
1490
1485
  nameResolver: options.nameResolver ?? defaultPacketNameResolver,
1491
1486
  transportFactory: options.transportFactory ?? defaultTransportFactory,
1492
- codec: options.codec,
1493
- // Spec 26 §4: the default diagnostics level is Errors, which preserves
1494
- // the connector's established wire behavior.
1495
- diagnosticsLevel: options.diagnosticsLevel ?? "errors" /* Errors */
1487
+ codec: options.codec
1496
1488
  };
1497
1489
  }
1498
1490
  var defaultPacketNameResolver = {
@@ -1517,11 +1509,6 @@ function resolveCompressionCodec2(options) {
1517
1509
  }
1518
1510
  return options.compressionCodec;
1519
1511
  }
1520
- function validateDiagnosticsLevel(level) {
1521
- if (level !== void 0 && !validDiagnosticsLevels.has(level)) {
1522
- throw connectorError("configurationError" /* ConfigurationError */, "DiagnosticsLevel is invalid.");
1523
- }
1524
- }
1525
1512
  function validatePositive(value, name) {
1526
1513
  if (value <= 0) {
1527
1514
  throw connectorError("validationFailed" /* ValidationFailed */, `${name} must be positive.`);
@@ -1565,25 +1552,6 @@ function validateReconnect(options) {
1565
1552
  }
1566
1553
  }
1567
1554
 
1568
- // packages/stream-connector/src/Runtime/ZlinkStreamDiagnosticsLevelCell.ts
1569
- var ZlinkStreamDiagnosticsLevelCell = class {
1570
- current;
1571
- constructor(initial) {
1572
- this.current = initial;
1573
- }
1574
- get level() {
1575
- return this.current;
1576
- }
1577
- set(level) {
1578
- const candidate = level;
1579
- if (candidate === void 0 || candidate === null) {
1580
- throw connectorError("configurationError" /* ConfigurationError */, "DiagnosticsLevel is invalid.");
1581
- }
1582
- validateDiagnosticsLevel(level);
1583
- this.current = level;
1584
- }
1585
- };
1586
-
1587
1555
  // packages/stream-connector/src/Runtime/ZlinkStreamPendingRequests.ts
1588
1556
  var ZlinkStreamPendingRequests = class {
1589
1557
  nextRequestSeq = 1n;
@@ -1596,16 +1564,21 @@ var ZlinkStreamPendingRequests = class {
1596
1564
  let timeout;
1597
1565
  let resolvePending;
1598
1566
  let rejectPending;
1599
- const promise = new Promise((resolve, reject) => {
1600
- timeout = setTimeout(() => {
1601
- this.active.delete(requestSeq);
1602
- reject(
1603
- connectorError("requestTimeout" /* RequestTimeout */, `Request '${packetName}' timed out.`)
1604
- );
1605
- }, timeoutMs);
1606
- resolvePending = resolve;
1607
- rejectPending = (error) => reject(connectorError(error.code, error.message, error.cause));
1608
- });
1567
+ const promise = new Promise(
1568
+ (resolve, reject) => {
1569
+ timeout = setTimeout(() => {
1570
+ this.active.delete(requestSeq);
1571
+ reject(
1572
+ connectorError(
1573
+ "requestTimeout" /* RequestTimeout */,
1574
+ `Request '${packetName}' timed out.`
1575
+ )
1576
+ );
1577
+ }, timeoutMs);
1578
+ resolvePending = resolve;
1579
+ rejectPending = (error) => reject(connectorError(error.code, error.message, error.cause));
1580
+ }
1581
+ );
1609
1582
  this.active.set(requestSeq, {
1610
1583
  packetName,
1611
1584
  promise,
@@ -1629,15 +1602,14 @@ var ZlinkStreamPendingRequests = class {
1629
1602
  });
1630
1603
  return { requestSeq, promise };
1631
1604
  }
1632
- /* stream connector spec §5.2: a pending request is matched by request_seq alone. Diagnostics
1633
- * use the original request name retained by this registry, never a legacy reply name. */
1634
- resolve(requestSeq, value) {
1605
+ /* stream connector spec §5.2: a pending request is matched by request_seq alone. */
1606
+ resolve(requestSeq, value, metadata) {
1635
1607
  const pending = this.active.get(requestSeq);
1636
1608
  if (pending === void 0) {
1637
1609
  return false;
1638
1610
  }
1639
1611
  this.active.delete(requestSeq);
1640
- pending.resolve(value);
1612
+ pending.resolve({ name: pending.packetName, metadata, payload: value });
1641
1613
  return true;
1642
1614
  }
1643
1615
  reject(requestSeq, error) {
@@ -1773,9 +1745,11 @@ var ZlinkStreamReceivedMessages = class {
1773
1745
  */
1774
1746
  resetForNewConnection() {
1775
1747
  this.receivedCounts.clear();
1748
+ const submittedCallbacks = this.queue.slice(this.queueHead).filter((item) => item?.kind === "callback");
1776
1749
  this.queue.length = 0;
1750
+ this.queue.push(...submittedCallbacks);
1777
1751
  this.queueHead = 0;
1778
- this.queuedCount = 0;
1752
+ this.queuedCount = submittedCallbacks.length;
1779
1753
  }
1780
1754
  /**
1781
1755
  * Releases every registered wait surface because the connection it was
@@ -1791,7 +1765,7 @@ var ZlinkStreamReceivedMessages = class {
1791
1765
  if (this.observers.size === 0) {
1792
1766
  return;
1793
1767
  }
1794
- const abandoned = [...this.observers.values()].flatMap((set) => [...set]);
1768
+ const abandoned = Array.from(this.observers.values()).flatMap((set) => Array.from(set));
1795
1769
  this.observers.clear();
1796
1770
  for (const registration of abandoned) {
1797
1771
  registration.onConnectionEnded();
@@ -1799,12 +1773,19 @@ var ZlinkStreamReceivedMessages = class {
1799
1773
  }
1800
1774
  enqueue(message, signal) {
1801
1775
  this.receivedCounts.set(message.name, (this.receivedCounts.get(message.name) ?? 0) + 1);
1802
- for (const registration of [...this.observers.get(message.name) ?? []]) {
1776
+ for (const registration of Array.from(this.observers.get(message.name) ?? [])) {
1803
1777
  if (registration.consume(message)) {
1804
1778
  return;
1805
1779
  }
1806
1780
  }
1807
- this.queue.push({ message, signal });
1781
+ this.queue.push({ kind: "message", message, signal });
1782
+ this.queuedCount += 1;
1783
+ if (this.deliverOnArrival) {
1784
+ this.scheduleDrain();
1785
+ }
1786
+ }
1787
+ enqueueCallback(callback) {
1788
+ this.queue.push({ kind: "callback", callback });
1808
1789
  this.queuedCount += 1;
1809
1790
  if (this.deliverOnArrival) {
1810
1791
  this.scheduleDrain();
@@ -1831,7 +1812,7 @@ var ZlinkStreamReceivedMessages = class {
1831
1812
  offerQueued(name, registration) {
1832
1813
  for (let index = this.queueHead; index < this.queue.length; index += 1) {
1833
1814
  const queued = this.queue[index];
1834
- if (queued === void 0 || queued.message.name !== name) {
1815
+ if (queued === void 0 || queued.kind !== "message" || queued.message.name !== name) {
1835
1816
  continue;
1836
1817
  }
1837
1818
  if (!registration.consume(queued.message)) {
@@ -1859,8 +1840,12 @@ var ZlinkStreamReceivedMessages = class {
1859
1840
  const queued = this.queue[index];
1860
1841
  if (queued === void 0) continue;
1861
1842
  this.removeAt(index);
1843
+ if (queued.kind === "callback") {
1844
+ await queued.callback();
1845
+ continue;
1846
+ }
1862
1847
  const { message, signal } = queued;
1863
- const handlers = [...this.handlers.get(message.name)];
1848
+ const handlers = Array.from(this.handlers.get(message.name));
1864
1849
  for (const handler of handlers) {
1865
1850
  try {
1866
1851
  await handler(message, signal);
@@ -1889,7 +1874,7 @@ var ZlinkStreamReceivedMessages = class {
1889
1874
  findDeliverableIndex() {
1890
1875
  for (let index = this.queueHead; index < this.queue.length; index += 1) {
1891
1876
  const queued = this.queue[index];
1892
- if (queued !== void 0 && (this.handlers.get(queued.message.name)?.size ?? 0) > 0) {
1877
+ if (queued !== void 0 && (queued.kind === "callback" || (this.handlers.get(queued.message.name)?.size ?? 0) > 0)) {
1893
1878
  return index;
1894
1879
  }
1895
1880
  }
@@ -1897,7 +1882,8 @@ var ZlinkStreamReceivedMessages = class {
1897
1882
  }
1898
1883
  hasQueuedMessage(name) {
1899
1884
  for (let index = this.queueHead; index < this.queue.length; index += 1) {
1900
- if (this.queue[index]?.message.name === name) return true;
1885
+ const queued = this.queue[index];
1886
+ if (queued?.kind === "message" && queued.message.name === name) return true;
1901
1887
  }
1902
1888
  return false;
1903
1889
  }
@@ -1921,14 +1907,12 @@ var ZlinkStreamReceivedMessages = class {
1921
1907
 
1922
1908
  // packages/stream-connector/src/Runtime/ZlinkStreamFrameSender.ts
1923
1909
  var ZlinkStreamFrameSender = class {
1924
- constructor(protocol, flowContext) {
1910
+ constructor(protocol) {
1925
1911
  this.protocol = protocol;
1926
- this.flowContext = flowContext;
1927
1912
  }
1928
1913
  pendingWrites = /* @__PURE__ */ new Set();
1929
- async send(connection, kind, name, payload, metadata, compress, requestSeq, signal, correlationId, explicitFlow) {
1914
+ async send(connection, kind, name, payload, metadata, compress, requestSeq, signal, correlationId, actorSlot) {
1930
1915
  throwIfAborted(signal);
1931
- const flow = this.protocol.flowEnabled() ? this.flowContext.currentOrCreate(explicitFlow) : void 0;
1932
1916
  await this.write(
1933
1917
  connection,
1934
1918
  this.protocol.encode(
@@ -1939,8 +1923,7 @@ var ZlinkStreamFrameSender = class {
1939
1923
  compress,
1940
1924
  requestSeq,
1941
1925
  correlationId,
1942
- flow?.flowId,
1943
- flow?.flowOrigin
1926
+ actorSlot
1944
1927
  ),
1945
1928
  signal
1946
1929
  );
@@ -1951,7 +1934,7 @@ var ZlinkStreamFrameSender = class {
1951
1934
  async drain(signal) {
1952
1935
  while (this.pendingWrites.size > 0) {
1953
1936
  throwIfAborted(signal);
1954
- await Promise.allSettled([...this.pendingWrites]);
1937
+ await Promise.allSettled(Array.from(this.pendingWrites));
1955
1938
  }
1956
1939
  }
1957
1940
  async write(connection, frame, signal) {
@@ -1987,15 +1970,185 @@ function decodeSessionClosing(payload) {
1987
1970
  return { closeReason, diagnostic };
1988
1971
  }
1989
1972
 
1973
+ // packages/stream-connector/src/Runtime/ZlinkStreamActors.ts
1974
+ var ACTOR_BOUND = "$zlink.actor.bound";
1975
+ var ACTOR_UNBOUND = "$zlink.actor.unbound";
1976
+ var zlinkStreamActorBinding = Symbol("zlink.stream.actorBinding");
1977
+ var DefaultZlinkStreamActor = class {
1978
+ constructor(connector, actorId, slot) {
1979
+ this.connector = connector;
1980
+ this.actorId = actorId;
1981
+ this.slot = slot;
1982
+ }
1983
+ bound = true;
1984
+ get isBound() {
1985
+ return this.bound;
1986
+ }
1987
+ send(payload, messageType) {
1988
+ this.ensureBound();
1989
+ return this.connector.sendForActor(this, payload, messageType);
1990
+ }
1991
+ request(payload, messageType) {
1992
+ this.ensureBound();
1993
+ return this.connector.requestForActor(this, payload, messageType);
1994
+ }
1995
+ on(nameOrType, handler, messageType) {
1996
+ return this.connector.onActorMessage(this, nameOrType, handler, messageType);
1997
+ }
1998
+ ensureBound() {
1999
+ if (!this.bound) {
2000
+ throw connectorError(
2001
+ "validationFailed" /* ValidationFailed */,
2002
+ `Actor '${this.actorId}' is no longer bound.`
2003
+ );
2004
+ }
2005
+ }
2006
+ close() {
2007
+ this.bound = false;
2008
+ }
2009
+ };
2010
+ var ZlinkStreamActors = class {
2011
+ constructor(connector, receivedMessages, events) {
2012
+ this.connector = connector;
2013
+ this.receivedMessages = receivedMessages;
2014
+ this.events = events;
2015
+ }
2016
+ bySlot = /* @__PURE__ */ new Map();
2017
+ byId = /* @__PURE__ */ new Map();
2018
+ issued = [];
2019
+ boundHandlers = /* @__PURE__ */ new Set();
2020
+ unboundHandlers = /* @__PURE__ */ new Set();
2021
+ get snapshot() {
2022
+ return Object.freeze(Array.from(this.bySlot.values()));
2023
+ }
2024
+ find(actorId) {
2025
+ return this.byId.get(actorId);
2026
+ }
2027
+ onBound(handler) {
2028
+ this.boundHandlers.add(handler);
2029
+ return subscription(() => this.boundHandlers.delete(handler));
2030
+ }
2031
+ onUnbound(handler) {
2032
+ this.unboundHandlers.add(handler);
2033
+ return subscription(() => this.unboundHandlers.delete(handler));
2034
+ }
2035
+ processControl(name, payload, signal) {
2036
+ if (name === ACTOR_BOUND) {
2037
+ this.bind(payload, signal);
2038
+ return true;
2039
+ }
2040
+ if (name === ACTOR_UNBOUND) {
2041
+ this.unbind(payload, signal);
2042
+ return true;
2043
+ }
2044
+ return false;
2045
+ }
2046
+ resolve(slot) {
2047
+ const actor = this.bySlot.get(slot);
2048
+ if (actor === void 0) {
2049
+ throw connectorError(
2050
+ "frameDecodeFailed" /* FrameDecodeFailed */,
2051
+ `Actor slot '${slot}' is not bound.`
2052
+ );
2053
+ }
2054
+ return actor;
2055
+ }
2056
+ closeAll(signal) {
2057
+ for (const actor of this.issued) {
2058
+ if (!actor.isBound) continue;
2059
+ this.bySlot.delete(actor.slot);
2060
+ this.byId.delete(actor.actorId);
2061
+ actor.close();
2062
+ this.queue(this.unboundHandlers, actor, signal);
2063
+ }
2064
+ this.issued.length = 0;
2065
+ }
2066
+ bind(payload, signal) {
2067
+ if (payload.length < 5 || payload[0] !== 1) {
2068
+ throw invalidControl("Actor bound payload is invalid.");
2069
+ }
2070
+ const slot = payload[1] << 8 | payload[2];
2071
+ const idLength = payload[3];
2072
+ if (slot === 0 || idLength === 0 || payload.length !== 4 + idLength) {
2073
+ throw invalidControl("Actor bound payload is invalid.");
2074
+ }
2075
+ let actorId;
2076
+ try {
2077
+ actorId = new TextDecoder("utf-8", { fatal: true }).decode(payload.subarray(4));
2078
+ } catch (cause) {
2079
+ throw connectorError(
2080
+ "frameDecodeFailed" /* FrameDecodeFailed */,
2081
+ "Actor id is not valid UTF-8.",
2082
+ cause
2083
+ );
2084
+ }
2085
+ if (actorId.length === 0 || this.bySlot.has(slot) || this.byId.has(actorId)) {
2086
+ throw invalidControl("Actor bound identity is already in use.");
2087
+ }
2088
+ const actor = new DefaultZlinkStreamActor(this.connector, actorId, slot);
2089
+ this.bySlot.set(slot, actor);
2090
+ this.byId.set(actorId, actor);
2091
+ this.issued.push(actor);
2092
+ this.queue(this.boundHandlers, actor, signal);
2093
+ }
2094
+ unbind(payload, signal) {
2095
+ if (payload.length !== 3 || payload[0] !== 1) {
2096
+ throw invalidControl("Actor unbound payload is invalid.");
2097
+ }
2098
+ const slot = payload[1] << 8 | payload[2];
2099
+ const actor = this.bySlot.get(slot);
2100
+ if (slot === 0 || actor === void 0) {
2101
+ throw invalidControl(`Actor slot '${slot}' is not bound.`);
2102
+ }
2103
+ this.bySlot.delete(slot);
2104
+ this.byId.delete(actor.actorId);
2105
+ actor.close();
2106
+ this.queue(this.unboundHandlers, actor, signal);
2107
+ }
2108
+ queue(handlers, actor, signal) {
2109
+ this.receivedMessages.enqueueCallback(() => {
2110
+ for (const handler of Array.from(handlers)) {
2111
+ this.invoke(handler, actor, signal);
2112
+ }
2113
+ });
2114
+ }
2115
+ invoke(handler, actor, signal) {
2116
+ try {
2117
+ Promise.resolve(handler(actor, signal)).catch((cause) => {
2118
+ void this.events.publishError(
2119
+ {
2120
+ code: "userCallbackFailed" /* UserCallbackFailed */,
2121
+ message: "Actor lifecycle handler failed.",
2122
+ cause
2123
+ },
2124
+ signal
2125
+ );
2126
+ });
2127
+ } catch (cause) {
2128
+ void this.events.publishError(
2129
+ {
2130
+ code: "userCallbackFailed" /* UserCallbackFailed */,
2131
+ message: "Actor lifecycle handler failed.",
2132
+ cause
2133
+ },
2134
+ signal
2135
+ );
2136
+ }
2137
+ }
2138
+ };
2139
+ function invalidControl(message) {
2140
+ return connectorError("frameDecodeFailed" /* FrameDecodeFailed */, message);
2141
+ }
2142
+
1990
2143
  // packages/stream-connector/src/Runtime/ZlinkStreamReceiveDispatcher.ts
1991
2144
  var ZlinkStreamReceiveDispatcher = class {
1992
- constructor(protocol, pendingRequests, receivedMessages, frameSender, events, flowContext, serverClosing) {
2145
+ constructor(protocol, pendingRequests, receivedMessages, frameSender, events, actors, serverClosing) {
1993
2146
  this.protocol = protocol;
1994
2147
  this.pendingRequests = pendingRequests;
1995
2148
  this.receivedMessages = receivedMessages;
1996
2149
  this.frameSender = frameSender;
1997
2150
  this.events = events;
1998
- this.flowContext = flowContext;
2151
+ this.actors = actors;
1999
2152
  this.serverClosing = serverClosing;
2000
2153
  }
2001
2154
  /**
@@ -2022,49 +2175,47 @@ var ZlinkStreamReceiveDispatcher = class {
2022
2175
  if (frameBytes === void 0) {
2023
2176
  return { available: false, inbound: false };
2024
2177
  }
2025
- const flowEnabled = this.protocol.flowEnabled();
2026
2178
  let frames;
2027
2179
  try {
2028
- frames = this.protocol.decodeFrames(frameBytes, flowEnabled);
2180
+ frames = this.protocol.decodeFrames(frameBytes);
2029
2181
  } catch (cause) {
2030
- await this.events.publishError(
2031
- toStreamError(cause, "frameDecodeFailed" /* FrameDecodeFailed */, "Frame decode failed."),
2032
- signal
2033
- );
2034
- return { available: true, inbound: false };
2182
+ throw cause;
2035
2183
  }
2036
2184
  for (const frame of frames) {
2037
2185
  if (isCurrent !== void 0 && !isCurrent()) {
2038
2186
  break;
2039
2187
  }
2040
2188
  try {
2041
- await this.dispatch(
2042
- connection,
2043
- frame.header,
2044
- frame.payload,
2045
- signal,
2046
- flowEnabled,
2047
- connectionForSend
2048
- );
2189
+ await this.dispatch(connection, frame.header, frame.payload, signal, connectionForSend);
2049
2190
  } catch (cause) {
2050
2191
  if (frame.header.kind === 5 /* Control */ && frame.header.name === ZLINK_STREAM_HEARTBEAT_PING) {
2051
2192
  throw cause;
2052
2193
  }
2053
- await this.events.publishError(
2054
- toStreamError(cause, "frameDecodeFailed" /* FrameDecodeFailed */, "Frame dispatch failed."),
2055
- signal
2194
+ const error = toStreamError(
2195
+ cause,
2196
+ "frameDecodeFailed" /* FrameDecodeFailed */,
2197
+ "Frame dispatch failed."
2056
2198
  );
2199
+ if (error.code === "frameDecodeFailed" /* FrameDecodeFailed */) {
2200
+ throw cause;
2201
+ }
2202
+ await this.events.publishError(error, signal);
2057
2203
  }
2058
2204
  }
2059
2205
  return { available: true, inbound: true };
2060
2206
  }
2061
- async dispatch(connection, header, payload, signal, flowEnabled, connectionForSend) {
2207
+ async dispatch(connection, header, payload, signal, connectionForSend) {
2208
+ const actor = header.actorSlot === void 0 ? void 0 : this.actors.resolve(header.actorSlot);
2062
2209
  if (header.kind === 3 /* Response */ && header.requestSeq !== void 0) {
2063
2210
  try {
2064
- if (!this.pendingRequests.resolve(header.requestSeq, {
2065
- codec: header.codec,
2066
- payload: this.protocol.decodePayload(header, payload)
2067
- })) {
2211
+ if (!this.pendingRequests.resolve(
2212
+ header.requestSeq,
2213
+ {
2214
+ codec: header.codec,
2215
+ payload: this.protocol.decodePayload(header, payload)
2216
+ },
2217
+ header.metadata
2218
+ )) {
2068
2219
  await this.events.publishError(
2069
2220
  {
2070
2221
  code: "frameDecodeFailed" /* FrameDecodeFailed */,
@@ -2112,20 +2263,22 @@ var ZlinkStreamReceiveDispatcher = class {
2112
2263
  return;
2113
2264
  }
2114
2265
  if (header.kind === 1 /* Send */) {
2115
- const flow = flowEnabled ? this.flowContext.createInbound(header.flowId, header.flowOrigin) : void 0;
2116
2266
  this.receivedMessages.enqueue(
2117
2267
  {
2118
2268
  name: header.name,
2119
2269
  metadata: header.metadata,
2120
2270
  payload: { codec: header.codec, payload: this.protocol.decodePayload(header, payload) },
2121
- flowId: flow?.flowId,
2122
- flowOrigin: flow?.flowOrigin
2271
+ actorId: actor?.actorId,
2272
+ [zlinkStreamActorBinding]: actor
2123
2273
  },
2124
2274
  signal
2125
2275
  );
2126
2276
  }
2127
2277
  }
2128
2278
  async dispatchControl(connection, header, payload, signal, connectionForSend) {
2279
+ if (this.actors.processControl(header.name, payload, signal)) {
2280
+ return;
2281
+ }
2129
2282
  if (header.name === ZLINK_SESSION_CLOSING) {
2130
2283
  const closing = decodeSessionClosing(payload);
2131
2284
  await this.serverClosing?.(closing.closeReason);
@@ -2184,12 +2337,13 @@ function randomizedDelay(baseDelayMs) {
2184
2337
  return Math.round(baseDelayMs * (0.5 + Math.random() * 0.5));
2185
2338
  }
2186
2339
  var ZlinkStreamConnectorLifecycle = class {
2187
- constructor(options, pendingRequests, frameSender, receiveDispatcher, receivedMessages, events) {
2340
+ constructor(options, pendingRequests, frameSender, receiveDispatcher, receivedMessages, actors, events) {
2188
2341
  this.options = options;
2189
2342
  this.pendingRequests = pendingRequests;
2190
2343
  this.frameSender = frameSender;
2191
2344
  this.receiveDispatcher = receiveDispatcher;
2192
2345
  this.receivedMessages = receivedMessages;
2346
+ this.actors = actors;
2193
2347
  this.events = events;
2194
2348
  }
2195
2349
  receiveLoopAbort;
@@ -2325,8 +2479,9 @@ var ZlinkStreamConnectorLifecycle = class {
2325
2479
  message: "Connector closed."
2326
2480
  });
2327
2481
  this.receivedMessages.connectionEnded();
2328
- void this.setState("closed" /* Closed */, void 0, signal);
2329
- this.publishDisconnectedWithoutWaiting(signal);
2482
+ this.actors.closeAll(signal);
2483
+ this.queueState("closed" /* Closed */, void 0, signal);
2484
+ this.queueDisconnected(signal);
2330
2485
  if (errors.length === 1) throw errors[0];
2331
2486
  if (errors.length > 1) throw new AggregateError(errors, "Stream connector close failed.");
2332
2487
  }
@@ -2555,6 +2710,7 @@ var ZlinkStreamConnectorLifecycle = class {
2555
2710
  this.currentConnection = void 0;
2556
2711
  this.pendingRequests.failAll(error);
2557
2712
  this.receivedMessages.connectionEnded();
2713
+ this.actors.closeAll();
2558
2714
  try {
2559
2715
  await connection?.close();
2560
2716
  } catch {
@@ -2570,11 +2726,8 @@ var ZlinkStreamConnectorLifecycle = class {
2570
2726
  */
2571
2727
  async announceDisconnect(error) {
2572
2728
  if (this.closeRequested) return;
2573
- const announce = this.claimDisconnectedPublish();
2574
- void this.setState("disconnected" /* Disconnected */, error);
2575
- if (announce) {
2576
- void this.events.publishDisconnected().catch(() => void 0);
2577
- }
2729
+ this.queueState("disconnected" /* Disconnected */, error);
2730
+ this.queueDisconnected();
2578
2731
  if (this.shouldReconnect()) {
2579
2732
  queueMicrotask(() => {
2580
2733
  void this.connect().catch(() => void 0);
@@ -2622,16 +2775,35 @@ var ZlinkStreamConnectorLifecycle = class {
2622
2775
  publishDisconnectedWithoutWaiting(signal) {
2623
2776
  void this.publishDisconnectedOnce(signal).catch(() => void 0);
2624
2777
  }
2778
+ queueDisconnected(signal) {
2779
+ if (!this.claimDisconnectedPublish()) return;
2780
+ this.receivedMessages.enqueueCallback(() => {
2781
+ void this.events.publishDisconnected(signal).catch(() => void 0);
2782
+ });
2783
+ }
2784
+ queueState(current, error, signal) {
2785
+ const change = this.transitionState(current, error);
2786
+ if (change === void 0) return;
2787
+ this.receivedMessages.enqueueCallback(() => {
2788
+ void this.publishStateChange(change, signal).catch(() => void 0);
2789
+ });
2790
+ }
2625
2791
  async setState(current, error, signal) {
2792
+ const change = this.transitionState(current, error);
2793
+ if (change === void 0) return;
2794
+ await this.publishStateChange(change, signal);
2795
+ }
2796
+ transitionState(current, error) {
2626
2797
  const previous = this.currentState;
2627
2798
  this.currentState = current;
2628
2799
  if (previous === current && error === void 0) {
2629
- return;
2630
- }
2631
- await this.events.publishStateChanged({ previous, current, error }, signal);
2632
- if (error !== void 0) {
2633
- await this.events.publishError(error, signal);
2800
+ return void 0;
2634
2801
  }
2802
+ return { previous, current, error };
2803
+ }
2804
+ async publishStateChange(change, signal) {
2805
+ await this.events.publishStateChanged(change, signal);
2806
+ if (change.error !== void 0) await this.events.publishError(change.error, signal);
2635
2807
  }
2636
2808
  };
2637
2809
 
@@ -2653,49 +2825,25 @@ var ZlinkStreamConnectorEvents = class {
2653
2825
  return subscription(() => this.stateHandlers.delete(handler));
2654
2826
  }
2655
2827
  async publishError(error, signal) {
2656
- await this.publish([...this.errorHandlers].map((handler) => () => handler(error, signal)));
2828
+ await this.publish(
2829
+ Array.from(this.errorHandlers).map((handler) => () => handler(error, signal))
2830
+ );
2657
2831
  }
2658
2832
  async publishDisconnected(signal) {
2659
- await this.publish([...this.disconnectedHandlers].map((handler) => () => handler(signal)));
2833
+ await this.publish(
2834
+ Array.from(this.disconnectedHandlers).map((handler) => () => handler(signal))
2835
+ );
2660
2836
  }
2661
2837
  async publishStateChanged(change, signal) {
2662
- await this.publish([...this.stateHandlers].map((handler) => () => handler(change, signal)));
2838
+ await this.publish(
2839
+ Array.from(this.stateHandlers).map((handler) => () => handler(change, signal))
2840
+ );
2663
2841
  }
2664
2842
  async publish(handlers) {
2665
2843
  await Promise.allSettled(handlers.map(async (handler) => handler()));
2666
2844
  }
2667
2845
  };
2668
2846
 
2669
- // packages/stream-connector/src/Runtime/ZlinkFlowContext.ts
2670
- var BrowserZlinkFlowContext = class {
2671
- currentOrCreate(explicit) {
2672
- return explicit ?? { flowId: this.createUuidV7(), flowOrigin: "Application" };
2673
- }
2674
- createInbound(flowId, flowOrigin) {
2675
- return { flowId: flowId ?? this.createUuidV7(), flowOrigin: flowOrigin ?? "Inbound" };
2676
- }
2677
- createUuidV7() {
2678
- const crypto = globalThis.crypto;
2679
- if (crypto === void 0) {
2680
- throw connectorError(
2681
- "configurationError" /* ConfigurationError */,
2682
- "The browser entrypoint requires the platform Web Crypto API."
2683
- );
2684
- }
2685
- return formatUuidV7(crypto.getRandomValues(new Uint8Array(16)));
2686
- }
2687
- };
2688
- function formatUuidV7(bytes) {
2689
- const timestamp = BigInt(Date.now());
2690
- for (let index = 5; index >= 0; index -= 1) {
2691
- bytes[index] = Number(timestamp >> BigInt((5 - index) * 8) & 0xffn);
2692
- }
2693
- bytes[6] = 112 | bytes[6] & 15;
2694
- bytes[8] = 128 | bytes[8] & 63;
2695
- const hex = [...bytes].map((byte) => byte.toString(16).padStart(2, "0")).join("");
2696
- return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
2697
- }
2698
-
2699
2847
  // packages/stream-connector/src/Runtime/Transport/BrowserWebSocketConnection.ts
2700
2848
  var BrowserStreamTransportFactory = class {
2701
2849
  async connect(options, signal) {
@@ -2910,30 +3058,26 @@ var DefaultZlinkStreamConnector = class {
2910
3058
  pendingRequests = new ZlinkStreamPendingRequests();
2911
3059
  frameSender;
2912
3060
  receiveDispatcher;
2913
- diagnosticsLevelCell;
3061
+ requestSendingHandlers = /* @__PURE__ */ new Set();
3062
+ replyReceivedHandlers = /* @__PURE__ */ new Set();
3063
+ boundActors;
2914
3064
  options;
2915
3065
  constructor(options) {
2916
- const flowContext = new BrowserZlinkFlowContext();
2917
3066
  this.options = normalizeOptions(options, new BrowserStreamTransportFactory());
2918
- this.diagnosticsLevelCell = new ZlinkStreamDiagnosticsLevelCell(this.options.diagnosticsLevel);
2919
- Object.defineProperty(this.options, "diagnosticsLevel", {
2920
- enumerable: true,
2921
- configurable: true,
2922
- get: () => this.diagnosticsLevelCell.level
2923
- });
2924
3067
  const protocol = new ZlinkStreamFrameProtocol(this.options);
2925
- this.frameSender = new ZlinkStreamFrameSender(protocol, flowContext);
3068
+ this.frameSender = new ZlinkStreamFrameSender(protocol);
2926
3069
  this.receivedMessages = new ZlinkStreamReceivedMessages(
2927
3070
  this.events,
2928
3071
  this.options.dispatchMode === "immediate" /* Immediate */
2929
3072
  );
3073
+ this.boundActors = new ZlinkStreamActors(this, this.receivedMessages, this.events);
2930
3074
  this.receiveDispatcher = new ZlinkStreamReceiveDispatcher(
2931
3075
  protocol,
2932
3076
  this.pendingRequests,
2933
3077
  this.receivedMessages,
2934
3078
  this.frameSender,
2935
3079
  this.events,
2936
- flowContext,
3080
+ this.boundActors,
2937
3081
  (reason) => this.lifecycle.serverClosing(reason)
2938
3082
  );
2939
3083
  this.lifecycle = new ZlinkStreamConnectorLifecycle(
@@ -2942,6 +3086,7 @@ var DefaultZlinkStreamConnector = class {
2942
3086
  this.frameSender,
2943
3087
  this.receiveDispatcher,
2944
3088
  this.receivedMessages,
3089
+ this.boundActors,
2945
3090
  this.events
2946
3091
  );
2947
3092
  }
@@ -2957,6 +3102,18 @@ var DefaultZlinkStreamConnector = class {
2957
3102
  get pendingDispatchCount() {
2958
3103
  return this.pendingRequests.count;
2959
3104
  }
3105
+ get actors() {
3106
+ return this.boundActors.snapshot;
3107
+ }
3108
+ actor(actorId) {
3109
+ return this.boundActors.find(actorId);
3110
+ }
3111
+ onActorBound(handler) {
3112
+ return this.boundActors.onBound(handler);
3113
+ }
3114
+ onActorUnbound(handler) {
3115
+ return this.boundActors.onUnbound(handler);
3116
+ }
2960
3117
  /**
2961
3118
  * Spec stream-connector 32 §10: how many packets carrying `name` arrived on
2962
3119
  * the current connection. Arrivals are what is counted, so a message a
@@ -2968,37 +3125,6 @@ var DefaultZlinkStreamConnector = class {
2968
3125
  validateName(name);
2969
3126
  return this.receivedMessages.receivedCount(name);
2970
3127
  }
2971
- /**
2972
- * Current diagnostics level (spec 26 §4.1, spec stream-connector 32 §13).
2973
- * Reflects the level set by the most recent {@link setDiagnosticsLevel}
2974
- * call, or the construction-time option (default
2975
- * {@link ZlinkStreamDiagnosticsLevel.Errors}) if it was never changed.
2976
- */
2977
- get diagnosticsLevel() {
2978
- return this.diagnosticsLevelCell.level;
2979
- }
2980
- /**
2981
- * Changes the diagnostics level in place without recreating the connector
2982
- * (spec 26 §4.1, spec stream-connector 32 §13). The change is an atomic
2983
- * state update: it applies to processing points that read the level after
2984
- * this call returns and is never applied retroactively to frames already
2985
- * built. Rejects unknown values with {@link ZlinkStreamErrorCode.ConfigurationError}.
2986
- * Spec stream-connector 32 §13: this surface changes the value without
2987
- * waiting for anything; it is not a blocking call over the asynchronous pair,
2988
- * which a receive callback would otherwise make wait for its own completion.
2989
- */
2990
- setDiagnosticsLevel(level) {
2991
- this.diagnosticsLevelCell.set(level);
2992
- }
2993
- /**
2994
- * Asynchronous counterpart of {@link setDiagnosticsLevel} (spec
2995
- * stream-connector 32 §13). It changes the same value; awaiting it is how a
2996
- * caller observes the change, and it never replaces the synchronous surface.
2997
- */
2998
- setDiagnosticsLevelAsync(level) {
2999
- this.setDiagnosticsLevel(level);
3000
- return Promise.resolve();
3001
- }
3002
3128
  onErrorReceived(handler) {
3003
3129
  return this.events.onError(handler);
3004
3130
  }
@@ -3008,6 +3134,14 @@ var DefaultZlinkStreamConnector = class {
3008
3134
  onConnectionStateChanged(handler) {
3009
3135
  return this.events.onStateChanged(handler);
3010
3136
  }
3137
+ onRequestSending(handler) {
3138
+ this.requestSendingHandlers.add(handler);
3139
+ return subscription(() => this.requestSendingHandlers.delete(handler));
3140
+ }
3141
+ onReplyReceived(handler) {
3142
+ this.replyReceivedHandlers.add(handler);
3143
+ return subscription(() => this.replyReceivedHandlers.delete(handler));
3144
+ }
3011
3145
  async connect(signal) {
3012
3146
  await this.lifecycle.connect(signal);
3013
3147
  }
@@ -3025,18 +3159,60 @@ var DefaultZlinkStreamConnector = class {
3025
3159
  const encoded = this.encodePayload(payload, messageType);
3026
3160
  return new ZlinkStreamRequestBuilder(this, this.resolveNameOrDefault(encoded), encoded);
3027
3161
  }
3028
- on(name, handler, messageType) {
3162
+ on(nameOrType, handler, messageType) {
3029
3163
  const encodedHandler = (message, signal) => handler(
3030
3164
  {
3031
3165
  name: message.name,
3032
3166
  metadata: message.metadata,
3033
- payload: this.decodePayload(message.payload, messageType),
3034
- flowId: message.flowId,
3035
- flowOrigin: message.flowOrigin
3167
+ payload: this.decodePayload(
3168
+ message.payload,
3169
+ messageType ?? (typeof nameOrType === "function" ? nameOrType : void 0)
3170
+ ),
3171
+ actorId: message.actorId
3036
3172
  },
3037
3173
  signal
3038
3174
  );
3039
- return this.receivedMessages.on(name, encodedHandler);
3175
+ return this.receivedMessages.on(this.observedName(nameOrType), encodedHandler);
3176
+ }
3177
+ sendForActor(actor, payload, messageType) {
3178
+ const encoded = this.encodePayload(payload, messageType);
3179
+ return new ZlinkStreamSendBuilder(
3180
+ this,
3181
+ this.resolveNameOrDefault(encoded),
3182
+ encoded,
3183
+ actor.slot,
3184
+ () => actor.ensureBound()
3185
+ );
3186
+ }
3187
+ requestForActor(actor, payload, messageType) {
3188
+ const encoded = this.encodePayload(payload, messageType);
3189
+ return new ZlinkStreamRequestBuilder(
3190
+ this,
3191
+ this.resolveNameOrDefault(encoded),
3192
+ encoded,
3193
+ actor.slot,
3194
+ () => actor.ensureBound()
3195
+ );
3196
+ }
3197
+ onActorMessage(actor, nameOrType, handler, messageType) {
3198
+ const encodedHandler = (message, signal) => {
3199
+ if (message[zlinkStreamActorBinding] !== actor) {
3200
+ return;
3201
+ }
3202
+ return handler(
3203
+ {
3204
+ name: message.name,
3205
+ metadata: message.metadata,
3206
+ payload: this.decodePayload(
3207
+ message.payload,
3208
+ messageType ?? (typeof nameOrType === "function" ? nameOrType : void 0)
3209
+ ),
3210
+ actorId: message.actorId
3211
+ },
3212
+ signal
3213
+ );
3214
+ };
3215
+ return this.receivedMessages.on(this.observedName(nameOrType), encodedHandler);
3040
3216
  }
3041
3217
  waitFor(nameOrType) {
3042
3218
  return new ZlinkStreamWaitBuilder(this, this.observedName(nameOrType));
@@ -3119,8 +3295,7 @@ var DefaultZlinkStreamConnector = class {
3119
3295
  name: message.name,
3120
3296
  metadata: message.metadata,
3121
3297
  payload: this.decodeWaitPayload(message.payload),
3122
- flowId: message.flowId,
3123
- flowOrigin: message.flowOrigin
3298
+ actorId: message.actorId
3124
3299
  };
3125
3300
  if (!predicate(decoded)) {
3126
3301
  return false;
@@ -3159,7 +3334,7 @@ var DefaultZlinkStreamConnector = class {
3159
3334
  }
3160
3335
  return payload;
3161
3336
  }
3162
- async sendEncoded(kind, name, payload, metadata, compress, requestSeq, signal, flow, correlationId) {
3337
+ async sendEncoded(kind, name, payload, metadata, compress, requestSeq, signal, correlationId, actorSlot) {
3163
3338
  await this.frameSender.send(
3164
3339
  this.lifecycle.connectionForSend(),
3165
3340
  kind,
@@ -3170,37 +3345,105 @@ var DefaultZlinkStreamConnector = class {
3170
3345
  requestSeq,
3171
3346
  signal,
3172
3347
  correlationId,
3173
- flow
3348
+ actorSlot
3174
3349
  );
3175
3350
  }
3176
3351
  /**
3177
3352
  * Per-connector monotonic correlation id (hex). The client generates it on each request
3178
- * and the server echoes it back on the reply, so flows can be joined across the wire.
3353
+ * and the server echoes it back on the reply.
3179
3354
  */
3180
3355
  nextCorrelationId() {
3181
3356
  this.correlationCounter += 1n;
3182
3357
  return this.correlationCounter.toString(16);
3183
3358
  }
3184
- async requestEncoded(name, payload, metadata, compress, timeoutMs, signal, flow) {
3185
- const pending = this.pendingRequests.create(name, timeoutMs);
3359
+ async requestEncoded(name, payload, metadata, compress, timeoutMs, signal, actorSlot) {
3360
+ const startedAt = Date.now();
3361
+ const actorId = actorSlot === void 0 ? void 0 : this.boundActors.resolve(actorSlot).actorId;
3362
+ let requestMetadata = metadata;
3363
+ const sendingContext = {
3364
+ requestPacketName: name,
3365
+ actorId,
3366
+ setMetadata(key, value) {
3367
+ requestMetadata = requestMetadata.with(key, value);
3368
+ }
3369
+ };
3370
+ let pending;
3186
3371
  try {
3372
+ throwIfAborted(signal);
3373
+ for (const handler of Array.from(this.requestSendingHandlers)) {
3374
+ try {
3375
+ handler(sendingContext);
3376
+ } catch (cause) {
3377
+ queueMicrotask(() => {
3378
+ void this.events.publishError(
3379
+ toStreamError(
3380
+ cause,
3381
+ "userCallbackFailed" /* UserCallbackFailed */,
3382
+ "Request sending hook failed."
3383
+ ),
3384
+ signal
3385
+ );
3386
+ });
3387
+ }
3388
+ }
3389
+ pending = this.pendingRequests.create(name, timeoutMs);
3187
3390
  await this.sendEncoded(
3188
3391
  2 /* Request */,
3189
3392
  name,
3190
3393
  payload,
3191
- metadata,
3394
+ requestMetadata,
3192
3395
  compress,
3193
3396
  pending.requestSeq,
3194
3397
  signal,
3195
- flow,
3196
- this.nextCorrelationId()
3398
+ this.nextCorrelationId(),
3399
+ actorSlot
3400
+ );
3401
+ const reply = await pending.promise;
3402
+ this.publishReplyReceived(
3403
+ {
3404
+ requestPacketName: name,
3405
+ actorId,
3406
+ succeeded: true,
3407
+ reply: { ...reply, actorId },
3408
+ elapsed: Date.now() - startedAt
3409
+ },
3410
+ signal
3197
3411
  );
3198
- return await pending.promise;
3412
+ return reply.payload;
3199
3413
  } catch (error) {
3200
- this.pendingRequests.cancel(pending.requestSeq);
3414
+ if (pending !== void 0) this.pendingRequests.cancel(pending.requestSeq);
3415
+ this.publishReplyReceived(
3416
+ {
3417
+ requestPacketName: name,
3418
+ actorId,
3419
+ succeeded: false,
3420
+ error: unwrapStreamError(error),
3421
+ elapsed: Date.now() - startedAt
3422
+ },
3423
+ signal
3424
+ );
3201
3425
  throw error;
3202
3426
  }
3203
3427
  }
3428
+ publishReplyReceived(context, signal) {
3429
+ if (this.replyReceivedHandlers.size === 0) return;
3430
+ this.receivedMessages.enqueueCallback(async () => {
3431
+ for (const handler of Array.from(this.replyReceivedHandlers)) {
3432
+ try {
3433
+ await handler(context, signal);
3434
+ } catch (cause) {
3435
+ await this.events.publishError(
3436
+ toStreamError(
3437
+ cause,
3438
+ "userCallbackFailed" /* UserCallbackFailed */,
3439
+ "Reply received hook failed."
3440
+ ),
3441
+ signal
3442
+ );
3443
+ }
3444
+ }
3445
+ });
3446
+ }
3204
3447
  resolveNameOrDefault(payload) {
3205
3448
  if (payload.messageType === void 0) {
3206
3449
  return void 0;
@@ -3226,7 +3469,6 @@ export {
3226
3469
  ZlinkStreamCodec,
3227
3470
  ZlinkStreamCompression,
3228
3471
  ZlinkStreamConnectionState,
3229
- ZlinkStreamDiagnosticsLevel,
3230
3472
  ZlinkStreamDispatchMode,
3231
3473
  ZlinkStreamErrorCode,
3232
3474
  ZlinkStreamException,