@zlink-systems/stream-connector 0.25.0 → 0.27.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.
@@ -43,6 +43,10 @@ var ZlinkStreamConnectorBundle = (() => {
43
43
  });
44
44
 
45
45
  // packages/stream-wire/src/lz4-pickle.ts
46
+ var LZ4_MIN_MATCH_LENGTH = 4;
47
+ var LZ4_MATCH_OFFSET_BYTES = 2;
48
+ var LZ4_EXTENDED_LENGTH_NIBBLE = 15;
49
+ var LZ4_EXTENDED_LENGTH_BYTE = 255;
46
50
  var defaultMaxDecompressedPayloadSize = 64 * 1024;
47
51
  function lz4PickleUncompressed(payload) {
48
52
  if (payload.length === 0) {
@@ -53,11 +57,7 @@ var ZlinkStreamConnectorBundle = (() => {
53
57
  pickled.set(payload, 1);
54
58
  return pickled;
55
59
  }
56
- function lz4UnpicklePayload(payload, maxSize) {
57
- const maxDecompressedSize = maxSize != null ? maxSize : defaultMaxDecompressedPayloadSize;
58
- if (payload.length === 0) {
59
- return new Uint8Array();
60
- }
60
+ function readLz4Pickle(payload) {
61
61
  const header = payload[0];
62
62
  if ((header & 7) !== 0) {
63
63
  throw new Error("Unexpected LZ4 pickle version.");
@@ -69,7 +69,17 @@ var ZlinkStreamConnectorBundle = (() => {
69
69
  }
70
70
  const data = payload.subarray(dataOffset);
71
71
  const resultDiff = sizeOfDiff === 0 ? 0 : readLittleEndian(payload, 1, sizeOfDiff);
72
- const resultLength = data.length + resultDiff;
72
+ return { data, resultDiff, resultLength: data.length + resultDiff };
73
+ }
74
+ function lz4PickledLength(payload) {
75
+ return payload.length === 0 ? 0 : readLz4Pickle(payload).resultLength;
76
+ }
77
+ function lz4UnpicklePayload(payload, maxSize) {
78
+ const maxDecompressedSize = maxSize != null ? maxSize : defaultMaxDecompressedPayloadSize;
79
+ if (payload.length === 0) {
80
+ return new Uint8Array();
81
+ }
82
+ const { data, resultDiff, resultLength } = readLz4Pickle(payload);
73
83
  if (resultLength > maxDecompressedSize) {
74
84
  throw new Error("LZ4 decoded payload exceeds maximum stream payload size.");
75
85
  }
@@ -112,15 +122,15 @@ var ZlinkStreamConnectorBundle = (() => {
112
122
  if (sourceOffset >= source.length) {
113
123
  break;
114
124
  }
115
- if (source.length - sourceOffset < 2) {
125
+ if (source.length - sourceOffset < LZ4_MATCH_OFFSET_BYTES) {
116
126
  throw new Error("LZ4 match offset is incomplete.");
117
127
  }
118
128
  const matchOffset = source[sourceOffset] | source[sourceOffset + 1] << 8;
119
- sourceOffset += 2;
129
+ sourceOffset += LZ4_MATCH_OFFSET_BYTES;
120
130
  if (matchOffset === 0 || matchOffset > targetOffset) {
121
131
  throw new Error("LZ4 match offset is invalid.");
122
132
  }
123
- const matchLength = readLz4Length(source, token & 15, () => sourceOffset++) + 4;
133
+ const matchLength = readLz4Length(source, token & 15, () => sourceOffset++) + LZ4_MIN_MATCH_LENGTH;
124
134
  if (target.length - targetOffset < matchLength) {
125
135
  throw new Error("LZ4 match run exceeds output size.");
126
136
  }
@@ -136,7 +146,7 @@ var ZlinkStreamConnectorBundle = (() => {
136
146
  }
137
147
  function readLz4Length(source, nibble, nextOffset) {
138
148
  let length = nibble;
139
- if (length !== 15) {
149
+ if (length !== LZ4_EXTENDED_LENGTH_NIBBLE) {
140
150
  return length;
141
151
  }
142
152
  for (; ; ) {
@@ -146,7 +156,7 @@ var ZlinkStreamConnectorBundle = (() => {
146
156
  }
147
157
  const value = source[offset];
148
158
  length += value;
149
- if (value !== 255) {
159
+ if (value !== LZ4_EXTENDED_LENGTH_BYTE) {
150
160
  return length;
151
161
  }
152
162
  }
@@ -160,54 +170,200 @@ var ZlinkStreamConnectorBundle = (() => {
160
170
  ZlinkStreamCodec2[ZlinkStreamCodec2["Protobuf"] = 3] = "Protobuf";
161
171
  return ZlinkStreamCodec2;
162
172
  })(ZlinkStreamCodec || {});
173
+ var ZlinkStreamMessageKind = /* @__PURE__ */ ((ZlinkStreamMessageKind2) => {
174
+ ZlinkStreamMessageKind2[ZlinkStreamMessageKind2["Send"] = 1] = "Send";
175
+ ZlinkStreamMessageKind2[ZlinkStreamMessageKind2["Request"] = 2] = "Request";
176
+ ZlinkStreamMessageKind2[ZlinkStreamMessageKind2["Response"] = 3] = "Response";
177
+ ZlinkStreamMessageKind2[ZlinkStreamMessageKind2["Error"] = 4] = "Error";
178
+ ZlinkStreamMessageKind2[ZlinkStreamMessageKind2["Control"] = 5] = "Control";
179
+ return ZlinkStreamMessageKind2;
180
+ })(ZlinkStreamMessageKind || {});
181
+ var ZlinkStreamHeaderFlags = /* @__PURE__ */ ((ZlinkStreamHeaderFlags2) => {
182
+ ZlinkStreamHeaderFlags2[ZlinkStreamHeaderFlags2["None"] = 0] = "None";
183
+ ZlinkStreamHeaderFlags2[ZlinkStreamHeaderFlags2["HasRequestSeq"] = 1] = "HasRequestSeq";
184
+ ZlinkStreamHeaderFlags2[ZlinkStreamHeaderFlags2["HasMetadata"] = 2] = "HasMetadata";
185
+ ZlinkStreamHeaderFlags2[ZlinkStreamHeaderFlags2["PayloadCompressed"] = 4] = "PayloadCompressed";
186
+ ZlinkStreamHeaderFlags2[ZlinkStreamHeaderFlags2["HasCorrelationId"] = 8] = "HasCorrelationId";
187
+ ZlinkStreamHeaderFlags2[ZlinkStreamHeaderFlags2["HasFlowId"] = 16] = "HasFlowId";
188
+ ZlinkStreamHeaderFlags2[ZlinkStreamHeaderFlags2["HasActorSlot"] = 32] = "HasActorSlot";
189
+ return ZlinkStreamHeaderFlags2;
190
+ })(ZlinkStreamHeaderFlags || {});
191
+ var ZlinkStreamCloseReasonCode = /* @__PURE__ */ ((ZlinkStreamCloseReasonCode2) => {
192
+ ZlinkStreamCloseReasonCode2[ZlinkStreamCloseReasonCode2["ClientClose"] = 1] = "ClientClose";
193
+ ZlinkStreamCloseReasonCode2[ZlinkStreamCloseReasonCode2["IdleTimeout"] = 2] = "IdleTimeout";
194
+ ZlinkStreamCloseReasonCode2[ZlinkStreamCloseReasonCode2["HeartbeatTimeout"] = 3] = "HeartbeatTimeout";
195
+ ZlinkStreamCloseReasonCode2[ZlinkStreamCloseReasonCode2["ServerDrain"] = 4] = "ServerDrain";
196
+ ZlinkStreamCloseReasonCode2[ZlinkStreamCloseReasonCode2["ProtocolError"] = 5] = "ProtocolError";
197
+ ZlinkStreamCloseReasonCode2[ZlinkStreamCloseReasonCode2["TransportError"] = 6] = "TransportError";
198
+ return ZlinkStreamCloseReasonCode2;
199
+ })(ZlinkStreamCloseReasonCode || {});
200
+ var unicodeWhiteSpaceOnly = /^\p{White_Space}*$/u;
201
+ var validMessageKinds = new Set(
202
+ Object.values(ZlinkStreamMessageKind).filter((value) => typeof value === "number")
203
+ );
204
+ var validCodecs = new Set(
205
+ Object.values(ZlinkStreamCodec).filter((value) => typeof value === "number")
206
+ );
207
+ function isStreamWireMessageKind(value) {
208
+ return validMessageKinds.has(value);
209
+ }
210
+ function isStreamWireCodec(value) {
211
+ return validCodecs.has(value);
212
+ }
213
+ var UTF8_TWO_BYTE_MIN = 128;
214
+ var UTF8_THREE_BYTE_MIN = 2048;
215
+ var UTF16_HIGH_SURROGATE_MIN = 55296;
216
+ var UTF16_HIGH_SURROGATE_MAX = 56319;
217
+ var UTF16_LOW_SURROGATE_MIN = 56320;
218
+ var UTF16_LOW_SURROGATE_MAX = 57343;
219
+ var UINT8_MAX = 255;
220
+ var UINT16_MAX = 65535;
221
+ var UINT16_BYTES = 2;
222
+ var UINT32_BYTES = 4;
223
+ var UINT64_BYTES = 8;
224
+ var UINT64_MAX = 0xffffffffffffffffn;
225
+ var UINT32_MAX = 4294967295;
226
+ var ZLINK_STREAM_FRAME_PREFIX_BYTES = UINT16_BYTES + UINT32_BYTES;
227
+ var ZLINK_STREAM_MAX_PACKET_NAME_BYTES = UINT8_MAX;
228
+ var ZLINK_STREAM_MAX_METADATA_BYTES = 1024;
229
+ var FLOW_ID_BYTES = 36;
230
+ var FLOW_FIELDS_BYTES = FLOW_ID_BYTES + 1;
231
+ var HEADER_MIN_BYTES = 5;
232
+ var HEADER_FLAG_MASK = 1 /* HasRequestSeq */ | 2 /* HasMetadata */ | 4 /* PayloadCompressed */ | 8 /* HasCorrelationId */ | 16 /* HasFlowId */ | 32 /* HasActorSlot */;
233
+ var CONTROL_PAYLOAD_VERSION = 1;
234
+ var ACTOR_SLOT_OFFSET = 1;
235
+ var ACTOR_ID_LENGTH_OFFSET = ACTOR_SLOT_OFFSET + UINT16_BYTES;
236
+ var ACTOR_BOUND_PREFIX_BYTES = ACTOR_ID_LENGTH_OFFSET + 1;
237
+ var ACTOR_UNBOUND_BYTES = ACTOR_SLOT_OFFSET + UINT16_BYTES;
238
+ var CLOSING_DIAGNOSTIC_LENGTH_OFFSET = 2;
239
+ var CLOSING_PREFIX_BYTES = CLOSING_DIAGNOSTIC_LENGTH_OFFSET + UINT16_BYTES;
240
+ var MAX_CLOSING_DIAGNOSTIC_BYTES = 512;
241
+ function decodeStreamWireActorBoundPayload(payload) {
242
+ if (payload.length < ACTOR_BOUND_PREFIX_BYTES + 1 || payload[0] !== CONTROL_PAYLOAD_VERSION) {
243
+ throw new Error("Actor bound payload is invalid.");
244
+ }
245
+ const slot = readUInt16BE(payload, ACTOR_SLOT_OFFSET);
246
+ const idLength = payload[ACTOR_ID_LENGTH_OFFSET];
247
+ if (slot === 0 || idLength === 0 || payload.length !== ACTOR_BOUND_PREFIX_BYTES + idLength) {
248
+ throw new Error("Actor bound payload is invalid.");
249
+ }
250
+ try {
251
+ return { slot, actorId: decodeControlText(payload.subarray(ACTOR_BOUND_PREFIX_BYTES)) };
252
+ } catch (cause) {
253
+ throw new Error("Actor id is not valid UTF-8.", { cause });
254
+ }
255
+ }
256
+ function decodeStreamWireActorUnboundPayload(payload) {
257
+ if (payload.length !== ACTOR_UNBOUND_BYTES || payload[0] !== CONTROL_PAYLOAD_VERSION) {
258
+ throw new Error("Actor unbound payload is invalid.");
259
+ }
260
+ return readUInt16BE(payload, ACTOR_SLOT_OFFSET);
261
+ }
262
+ function decodeStreamWireSessionClosing(payload) {
263
+ if (payload.length < CLOSING_PREFIX_BYTES || payload[0] !== CONTROL_PAYLOAD_VERSION) {
264
+ throw new Error("Unsupported session-closing version.");
265
+ }
266
+ const closeReason = ZlinkStreamCloseReasonCode[payload[1]];
267
+ if (closeReason === void 0) throw new Error("Unknown session-closing reason.");
268
+ const length = readUInt16BE(payload, CLOSING_DIAGNOSTIC_LENGTH_OFFSET);
269
+ if (length > MAX_CLOSING_DIAGNOSTIC_BYTES || payload.length !== CLOSING_PREFIX_BYTES + length) {
270
+ throw new Error("Invalid session-closing diagnostic length.");
271
+ }
272
+ const diagnostic = length === 0 ? void 0 : decodeControlText(payload.subarray(CLOSING_PREFIX_BYTES));
273
+ return { closeReason, diagnostic };
274
+ }
275
+ function decodeControlText(value) {
276
+ return new TextDecoder("utf-8", { fatal: true }).decode(value);
277
+ }
278
+ function splitStreamWireFrames(chunk) {
279
+ if (chunk.length === 0) throw new Error("Stream frame prefix is incomplete.");
280
+ const frames = [];
281
+ let offset = 0;
282
+ while (offset < chunk.length) {
283
+ const remaining = chunk.length - offset;
284
+ if (remaining < ZLINK_STREAM_FRAME_PREFIX_BYTES) {
285
+ throw new Error("Stream frame prefix is incomplete.");
286
+ }
287
+ const headerLength = readUInt16BE(chunk, offset);
288
+ const payloadLength = readUInt32BE(chunk, offset + UINT16_BYTES);
289
+ const frameLength = ZLINK_STREAM_FRAME_PREFIX_BYTES + headerLength + payloadLength;
290
+ if (frameLength > remaining) throw new Error("Frame length does not match prefix.");
291
+ frames.push(chunk.subarray(offset, offset + frameLength));
292
+ offset += frameLength;
293
+ }
294
+ return frames;
295
+ }
296
+ var ZLINK_STREAM_RESERVED_PACKET_NAME_PREFIX = "$zlink.";
297
+ var ZlinkStreamControlPacket = Object.freeze({
298
+ HeartbeatPing: `${ZLINK_STREAM_RESERVED_PACKET_NAME_PREFIX}heartbeat.ping`,
299
+ HeartbeatPong: `${ZLINK_STREAM_RESERVED_PACKET_NAME_PREFIX}heartbeat.pong`,
300
+ ActorBound: `${ZLINK_STREAM_RESERVED_PACKET_NAME_PREFIX}actor.bound`,
301
+ ActorUnbound: `${ZLINK_STREAM_RESERVED_PACKET_NAME_PREFIX}actor.unbound`,
302
+ SessionClosing: "session-closing"
303
+ });
304
+ var ZlinkStreamContentType = Object.freeze({
305
+ Raw: "application/octet-stream",
306
+ Json: "application/json",
307
+ MessagePack: "application/x-msgpack",
308
+ Protobuf: "application/x-protobuf"
309
+ });
310
+ var contentTypesByCodec = /* @__PURE__ */ new Map([
311
+ [0 /* Raw */, ZlinkStreamContentType.Raw],
312
+ [1 /* Json */, ZlinkStreamContentType.Json],
313
+ [2 /* MessagePack */, ZlinkStreamContentType.MessagePack],
314
+ [3 /* Protobuf */, ZlinkStreamContentType.Protobuf]
315
+ ]);
316
+ var codecsByContentType = new Map(
317
+ Array.from(contentTypesByCodec, ([codec, contentType]) => [contentType, codec])
318
+ );
163
319
  var defaultHeaderFlags = {
164
- hasRequestSeq: 1,
165
- hasMetadata: 2,
166
- hasCorrelationId: 8,
167
- hasFlowId: 16,
168
- hasActorSlot: 32
320
+ hasRequestSeq: 1 /* HasRequestSeq */,
321
+ hasMetadata: 2 /* HasMetadata */,
322
+ hasCorrelationId: 8 /* HasCorrelationId */,
323
+ hasFlowId: 16 /* HasFlowId */,
324
+ hasActorSlot: 32 /* HasActorSlot */
169
325
  };
170
326
  var ZLINK_STREAM_FORMAT_MARKER = 242;
171
- var ZLINK_STREAM_RESPONSE_KIND = 3;
172
- var ZLINK_STREAM_ERROR_KIND = 4;
173
327
  function encodeStreamWireFrame(header, payload) {
174
- if (header.length > 65535) {
328
+ if (header.length > UINT16_MAX) {
175
329
  throw new Error("Stream header is too large.");
176
330
  }
177
- if (payload.length > 4294967295) {
331
+ if (payload.length > UINT32_MAX) {
178
332
  throw new Error("Stream payload is too large.");
179
333
  }
180
- const frame = new Uint8Array(6 + header.length + payload.length);
334
+ const frame = new Uint8Array(ZLINK_STREAM_FRAME_PREFIX_BYTES + header.length + payload.length);
181
335
  writeUInt16BE(frame, 0, header.length);
182
- writeUInt32BE(frame, 2, payload.length);
183
- frame.set(header, 6);
184
- frame.set(payload, 6 + header.length);
336
+ writeUInt32BE(frame, UINT16_BYTES, payload.length);
337
+ frame.set(header, ZLINK_STREAM_FRAME_PREFIX_BYTES);
338
+ frame.set(payload, ZLINK_STREAM_FRAME_PREFIX_BYTES + header.length);
185
339
  return frame;
186
340
  }
187
341
  function decodeStreamWireFrame(frame) {
188
- if (frame.length < 6) {
342
+ if (frame.length < ZLINK_STREAM_FRAME_PREFIX_BYTES) {
189
343
  throw new Error("Stream frame prefix is incomplete.");
190
344
  }
191
345
  const headerLength = readUInt16BE(frame, 0);
192
- const payloadLength = readUInt32BE(frame, 2);
193
- if (frame.length !== 6 + headerLength + payloadLength) {
346
+ const payloadLength = readUInt32BE(frame, UINT16_BYTES);
347
+ if (frame.length !== ZLINK_STREAM_FRAME_PREFIX_BYTES + headerLength + payloadLength) {
194
348
  throw new Error("Stream frame length does not match prefix.");
195
349
  }
196
350
  return {
197
- header: frame.slice(6, 6 + headerLength),
198
- payload: frame.slice(6 + headerLength)
351
+ header: frame.slice(
352
+ ZLINK_STREAM_FRAME_PREFIX_BYTES,
353
+ ZLINK_STREAM_FRAME_PREFIX_BYTES + headerLength
354
+ ),
355
+ payload: frame.slice(ZLINK_STREAM_FRAME_PREFIX_BYTES + headerLength)
199
356
  };
200
357
  }
201
358
  function encodeStreamWireHeader(header, flagOverrides) {
202
359
  const flags = flagOverrides != null ? flagOverrides : defaultHeaderFlags;
203
360
  const reply = isReplyKind(header.kind);
204
361
  const packetName = reply ? "" : header.name;
205
- if (!reply) validateStreamWirePacketName(packetName);
206
- const nameBytes = utf8Encode(packetName);
362
+ const nameBytes = reply ? new Uint8Array() : validateStreamWirePacketName(packetName);
207
363
  const hasRequestSeq = header.requestSeq !== void 0;
208
364
  const hasMetadata = header.metadata.size > 0;
209
365
  const correlationBytes = header.correlationId !== void 0 && header.correlationId.length > 0 ? utf8Encode(header.correlationId) : void 0;
210
- if (correlationBytes !== void 0 && correlationBytes.length > 255) {
366
+ if (correlationBytes !== void 0 && correlationBytes.length > UINT8_MAX) {
211
367
  throw new Error("Stream correlation id is too large.");
212
368
  }
213
369
  const hasCorrelation = correlationBytes !== void 0;
@@ -220,7 +376,7 @@ var ZlinkStreamConnectorBundle = (() => {
220
376
  if (header.flowOrigin !== void 0 && ![1, 2, 3, 4].includes(header.flowOrigin)) {
221
377
  throw new Error("Stream flow origin is invalid.");
222
378
  }
223
- if (header.actorSlot !== void 0 && (!Number.isInteger(header.actorSlot) || header.actorSlot < 1 || header.actorSlot > 65535)) {
379
+ if (header.actorSlot !== void 0 && (!Number.isInteger(header.actorSlot) || header.actorSlot < 1 || header.actorSlot > UINT16_MAX)) {
224
380
  throw new Error("Stream actor slot is invalid.");
225
381
  }
226
382
  let headerFlags = header.flags;
@@ -230,7 +386,7 @@ var ZlinkStreamConnectorBundle = (() => {
230
386
  headerFlags = hasFlow ? headerFlags | flags.hasFlowId : headerFlags & ~flags.hasFlowId;
231
387
  headerFlags = hasActorSlot ? headerFlags | flags.hasActorSlot : headerFlags & ~flags.hasActorSlot;
232
388
  const metadataBytes = hasMetadata ? encodeStreamWireMetadata(header.metadata) : new Uint8Array();
233
- 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);
389
+ const size = 4 + (hasRequestSeq ? UINT64_BYTES : 0) + 1 + nameBytes.length + (hasMetadata ? UINT16_BYTES + metadataBytes.length : 0) + (hasCorrelation ? 1 + correlationBytes.length : 0) + (hasFlow ? FLOW_FIELDS_BYTES : 0) + (hasActorSlot ? UINT16_BYTES : 0);
234
390
  const buffer = new Uint8Array(size);
235
391
  let offset = 0;
236
392
  buffer[offset++] = ZLINK_STREAM_FORMAT_MARKER;
@@ -242,14 +398,14 @@ var ZlinkStreamConnectorBundle = (() => {
242
398
  throw new Error("Request sequence must not be zero.");
243
399
  }
244
400
  writeBigUInt64BE(buffer, offset, header.requestSeq);
245
- offset += 8;
401
+ offset += UINT64_BYTES;
246
402
  }
247
403
  buffer[offset++] = nameBytes.length;
248
404
  buffer.set(nameBytes, offset);
249
405
  offset += nameBytes.length;
250
406
  if (hasMetadata) {
251
407
  writeUInt16BE(buffer, offset, metadataBytes.length);
252
- offset += 2;
408
+ offset += UINT16_BYTES;
253
409
  buffer.set(metadataBytes, offset);
254
410
  offset += metadataBytes.length;
255
411
  }
@@ -260,7 +416,7 @@ var ZlinkStreamConnectorBundle = (() => {
260
416
  }
261
417
  if (hasFlow) {
262
418
  buffer.set(asciiEncode(header.flowId), offset);
263
- offset += 36;
419
+ offset += FLOW_ID_BYTES;
264
420
  buffer[offset++] = header.flowOrigin;
265
421
  }
266
422
  if (hasActorSlot) {
@@ -271,7 +427,7 @@ var ZlinkStreamConnectorBundle = (() => {
271
427
  function decodeStreamWireHeader(header, flagOverrides, includeFlow = true) {
272
428
  const flags = flagOverrides != null ? flagOverrides : defaultHeaderFlags;
273
429
  let offset = 0;
274
- if (header.length < 5) {
430
+ if (header.length < HEADER_MIN_BYTES) {
275
431
  throw new Error("Stream header is incomplete.");
276
432
  }
277
433
  if (header[offset++] !== ZLINK_STREAM_FORMAT_MARKER) {
@@ -285,29 +441,28 @@ var ZlinkStreamConnectorBundle = (() => {
285
441
  const hasCorrelation = (headerFlags & flags.hasCorrelationId) !== 0;
286
442
  const hasFlow = (headerFlags & flags.hasFlowId) !== 0;
287
443
  const hasActorSlot = (headerFlags & flags.hasActorSlot) !== 0;
288
- if ((headerFlags & ~63) !== 0) {
444
+ if ((headerFlags & ~HEADER_FLAG_MASK) !== 0) {
289
445
  throw new Error("Unknown mandatory stream header flag.");
290
446
  }
291
447
  let requestSeq;
292
448
  if (hasRequestSeq) {
293
- if (header.length - offset < 8) {
449
+ if (header.length - offset < UINT64_BYTES) {
294
450
  throw new Error("Stream request sequence is incomplete.");
295
451
  }
296
452
  requestSeq = readBigUInt64BE(header, offset);
297
453
  if (requestSeq === 0n) {
298
454
  throw new Error("Request sequence must not be zero.");
299
455
  }
300
- offset += 8;
456
+ offset += UINT64_BYTES;
301
457
  }
302
458
  if (header.length - offset < 1) {
303
459
  throw new Error("Stream packet name length is missing.");
304
460
  }
305
461
  const nameLength = header[offset++];
306
- if (!isReplyKind(kind) && nameLength === 0 || header.length - offset < nameLength) {
462
+ if ((isReplyKind(kind) ? nameLength !== 0 : nameLength === 0) || header.length - offset < nameLength) {
307
463
  throw new Error("Stream packet name is invalid.");
308
464
  }
309
- const decodedName = utf8Decode(header.subarray(offset, offset + nameLength));
310
- const name = isReplyKind(kind) ? "" : decodedName;
465
+ const name = utf8Decode(header.subarray(offset, offset + nameLength));
311
466
  offset += nameLength;
312
467
  const decodedMetadata = hasMetadata ? decodeStreamWireHeaderMetadata(header, offset) : { metadata: /* @__PURE__ */ new Map(), offset };
313
468
  offset = decodedMetadata.offset;
@@ -326,14 +481,14 @@ var ZlinkStreamConnectorBundle = (() => {
326
481
  let flowId;
327
482
  let flowOrigin;
328
483
  if (hasFlow) {
329
- if (header.length - offset < 37) {
484
+ if (header.length - offset < FLOW_FIELDS_BYTES) {
330
485
  throw new Error("Stream flow fields are incomplete.");
331
486
  }
332
487
  if (includeFlow) {
333
- flowId = asciiDecode(header.subarray(offset, offset + 36));
488
+ flowId = asciiDecode(header.subarray(offset, offset + FLOW_ID_BYTES));
334
489
  validateFlowId(flowId);
335
490
  }
336
- offset += 36;
491
+ offset += FLOW_ID_BYTES;
337
492
  const decodedFlowOrigin = header[offset++];
338
493
  if (includeFlow && ![1, 2, 3, 4].includes(decodedFlowOrigin)) {
339
494
  throw new Error("Stream flow origin is invalid.");
@@ -342,14 +497,14 @@ var ZlinkStreamConnectorBundle = (() => {
342
497
  }
343
498
  let actorSlot;
344
499
  if (hasActorSlot) {
345
- if (header.length - offset < 2) {
500
+ if (header.length - offset < UINT16_BYTES) {
346
501
  throw new Error("Stream actor slot is incomplete.");
347
502
  }
348
503
  actorSlot = readUInt16BE(header, offset);
349
504
  if (actorSlot === 0) {
350
505
  throw new Error("Stream actor slot must not be zero.");
351
506
  }
352
- offset += 2;
507
+ offset += UINT16_BYTES;
353
508
  }
354
509
  if (offset !== header.length) {
355
510
  throw new Error("Stream header has trailing bytes.");
@@ -379,47 +534,47 @@ var ZlinkStreamConnectorBundle = (() => {
379
534
  if (value.some((byte) => byte > 127)) throw new Error("Stream flow id must be ASCII.");
380
535
  return String.fromCharCode(...value);
381
536
  }
382
- function encodeStreamWireMetadata(metadata) {
383
- if (metadata.size > 255) {
537
+ function streamWireMetadataSize(metadata) {
538
+ if (metadata.size > UINT8_MAX) {
384
539
  throw new Error("Metadata entry count must not exceed 255.");
385
540
  }
386
541
  let size = 1;
387
- const encoded = [...metadata].map(([key, value]) => {
388
- const keyBytes = utf8Encode(key);
389
- const valueBytes = utf8Encode(value);
390
- if (keyBytes.length === 0 || keyBytes.length > 255) {
542
+ for (const [key, value] of metadata) {
543
+ const keySize = utf8Size(key);
544
+ const valueSize = utf8Size(value);
545
+ if (keySize === 0 || keySize > UINT8_MAX) {
391
546
  throw new Error("Metadata key length is invalid.");
392
547
  }
393
- if (valueBytes.length > 65535) {
548
+ if (valueSize > UINT16_MAX) {
394
549
  throw new Error("Metadata value is too large.");
395
550
  }
396
- size += 1 + keyBytes.length + 2 + valueBytes.length;
397
- return { keyBytes, valueBytes };
398
- });
399
- const buffer = new Uint8Array(size);
551
+ size += 1 + keySize + UINT16_BYTES + valueSize;
552
+ }
553
+ return size;
554
+ }
555
+ function encodeStreamWireMetadata(metadata) {
556
+ const buffer = new Uint8Array(streamWireMetadataSize(metadata));
400
557
  let offset = 0;
401
558
  buffer[offset++] = metadata.size;
402
- for (const { keyBytes, valueBytes } of encoded) {
559
+ for (const [key, value] of metadata) {
560
+ const keyBytes = utf8Encode(key);
561
+ const valueBytes = utf8Encode(value);
403
562
  buffer[offset++] = keyBytes.length;
404
563
  buffer.set(keyBytes, offset);
405
564
  offset += keyBytes.length;
406
565
  writeUInt16BE(buffer, offset, valueBytes.length);
407
- offset += 2;
566
+ offset += UINT16_BYTES;
408
567
  buffer.set(valueBytes, offset);
409
568
  offset += valueBytes.length;
410
569
  }
411
570
  return buffer;
412
571
  }
413
- function decodeStreamWireMetadata(metadata) {
414
- const decoded = decodeStreamWireMetadataAt(metadata, 0, metadata.length);
415
- if (decoded.offset !== metadata.length) {
416
- throw new Error("Stream metadata payload has trailing bytes.");
417
- }
418
- return decoded.metadata;
419
- }
420
572
  function lz4PickleUncompressed2(payload) {
421
573
  return lz4PickleUncompressed(payload);
422
574
  }
575
+ function lz4PickledLength2(payload) {
576
+ return lz4PickledLength(payload);
577
+ }
423
578
  function lz4UnpicklePayload2(payload, maxDecompressedSize) {
424
579
  return lz4UnpicklePayload(payload, maxDecompressedSize != null ? maxDecompressedSize : defaultMaxDecompressedPayloadSize);
425
580
  }
@@ -430,11 +585,11 @@ var ZlinkStreamConnectorBundle = (() => {
430
585
  return new TextDecoder().decode(value);
431
586
  }
432
587
  function decodeStreamWireHeaderMetadata(header, offset) {
433
- if (header.length - offset < 2) {
588
+ if (header.length - offset < UINT16_BYTES) {
434
589
  throw new Error("Stream metadata section is incomplete.");
435
590
  }
436
591
  const metadataLength = readUInt16BE(header, offset);
437
- offset += 2;
592
+ offset += UINT16_BYTES;
438
593
  if (header.length - offset < metadataLength) {
439
594
  throw new Error("Stream metadata payload is incomplete.");
440
595
  }
@@ -460,7 +615,7 @@ var ZlinkStreamConnectorBundle = (() => {
460
615
  throw new Error("Stream metadata value length is missing.");
461
616
  }
462
617
  const valueLength = readUInt16BE(source, offset);
463
- offset += 2;
618
+ offset += UINT16_BYTES;
464
619
  if (end - offset < valueLength) {
465
620
  throw new Error("Stream metadata value is incomplete.");
466
621
  }
@@ -477,16 +632,17 @@ var ZlinkStreamConnectorBundle = (() => {
477
632
  }
478
633
  function validateStreamWirePacketName(name) {
479
634
  const nameBytes = utf8Encode(name);
480
- if (name.trim().length === 0 || nameBytes.length > 255) {
635
+ if (unicodeWhiteSpaceOnly.test(name) || nameBytes.length > ZLINK_STREAM_MAX_PACKET_NAME_BYTES) {
481
636
  throw new Error("Stream packet name is invalid.");
482
637
  }
638
+ return nameBytes;
483
639
  }
484
640
  function isReplyKind(kind) {
485
- return kind === ZLINK_STREAM_RESPONSE_KIND || kind === ZLINK_STREAM_ERROR_KIND;
641
+ return kind === 3 /* Response */ || kind === 4 /* Error */;
486
642
  }
487
643
  function writeUInt16BE(buffer, offset, value) {
488
- buffer[offset] = value >>> 8 & 255;
489
- buffer[offset + 1] = value & 255;
644
+ buffer[offset] = value >>> 8 & UINT8_MAX;
645
+ buffer[offset + 1] = value & UINT8_MAX;
490
646
  }
491
647
  function readUInt16BE(buffer, offset) {
492
648
  return buffer[offset] << 8 | buffer[offset + 1];
@@ -495,10 +651,10 @@ var ZlinkStreamConnectorBundle = (() => {
495
651
  return buffer[offset] * 16777216 + (buffer[offset + 1] << 16 | buffer[offset + 2] << 8 | buffer[offset + 3]);
496
652
  }
497
653
  function writeUInt32BE(buffer, offset, value) {
498
- buffer[offset] = value >>> 24 & 255;
499
- buffer[offset + 1] = value >>> 16 & 255;
500
- buffer[offset + 2] = value >>> 8 & 255;
501
- buffer[offset + 3] = value & 255;
654
+ buffer[offset] = value >>> 24 & UINT8_MAX;
655
+ buffer[offset + 1] = value >>> 16 & UINT8_MAX;
656
+ buffer[offset + 2] = value >>> 8 & UINT8_MAX;
657
+ buffer[offset + 3] = value & UINT8_MAX;
502
658
  }
503
659
  function writeBigUInt64BE(buffer, offset, value) {
504
660
  for (let index = 7; index >= 0; index -= 1) {
@@ -513,6 +669,19 @@ var ZlinkStreamConnectorBundle = (() => {
513
669
  }
514
670
  return value;
515
671
  }
672
+ function utf8Size(value) {
673
+ let size = 0;
674
+ for (let index = 0; index < value.length; index += 1) {
675
+ const code = value.charCodeAt(index);
676
+ if (code < UTF8_TWO_BYTE_MIN) size += 1;
677
+ else if (code < UTF8_THREE_BYTE_MIN) size += 2;
678
+ else if (code >= UTF16_HIGH_SURROGATE_MIN && code <= UTF16_HIGH_SURROGATE_MAX && index + 1 < value.length && value.charCodeAt(index + 1) >= UTF16_LOW_SURROGATE_MIN && value.charCodeAt(index + 1) <= UTF16_LOW_SURROGATE_MAX) {
679
+ size += 4;
680
+ index += 1;
681
+ } else size += 3;
682
+ }
683
+ return size;
684
+ }
516
685
 
517
686
  // packages/stream-connector/src/Contracts/ZlinkStreamEnums.ts
518
687
  var ZlinkStreamTransport = /* @__PURE__ */ ((ZlinkStreamTransport2) => {
@@ -530,24 +699,6 @@ var ZlinkStreamConnectorBundle = (() => {
530
699
  ZlinkStreamDispatchMode2["Immediate"] = "immediate";
531
700
  return ZlinkStreamDispatchMode2;
532
701
  })(ZlinkStreamDispatchMode || {});
533
- var ZlinkStreamMessageKind = /* @__PURE__ */ ((ZlinkStreamMessageKind2) => {
534
- ZlinkStreamMessageKind2[ZlinkStreamMessageKind2["Send"] = 1] = "Send";
535
- ZlinkStreamMessageKind2[ZlinkStreamMessageKind2["Request"] = 2] = "Request";
536
- ZlinkStreamMessageKind2[ZlinkStreamMessageKind2["Response"] = 3] = "Response";
537
- ZlinkStreamMessageKind2[ZlinkStreamMessageKind2["Error"] = 4] = "Error";
538
- ZlinkStreamMessageKind2[ZlinkStreamMessageKind2["Control"] = 5] = "Control";
539
- return ZlinkStreamMessageKind2;
540
- })(ZlinkStreamMessageKind || {});
541
- var ZlinkStreamHeaderFlags = /* @__PURE__ */ ((ZlinkStreamHeaderFlags2) => {
542
- ZlinkStreamHeaderFlags2[ZlinkStreamHeaderFlags2["None"] = 0] = "None";
543
- ZlinkStreamHeaderFlags2[ZlinkStreamHeaderFlags2["HasRequestSeq"] = 1] = "HasRequestSeq";
544
- ZlinkStreamHeaderFlags2[ZlinkStreamHeaderFlags2["HasMetadata"] = 2] = "HasMetadata";
545
- ZlinkStreamHeaderFlags2[ZlinkStreamHeaderFlags2["PayloadCompressed"] = 4] = "PayloadCompressed";
546
- ZlinkStreamHeaderFlags2[ZlinkStreamHeaderFlags2["HasCorrelationId"] = 8] = "HasCorrelationId";
547
- ZlinkStreamHeaderFlags2[ZlinkStreamHeaderFlags2["HasFlowId"] = 16] = "HasFlowId";
548
- ZlinkStreamHeaderFlags2[ZlinkStreamHeaderFlags2["HasActorSlot"] = 32] = "HasActorSlot";
549
- return ZlinkStreamHeaderFlags2;
550
- })(ZlinkStreamHeaderFlags || {});
551
702
  var ZlinkStreamErrorCode = /* @__PURE__ */ ((ZlinkStreamErrorCode2) => {
552
703
  ZlinkStreamErrorCode2["Disconnected"] = "disconnected";
553
704
  ZlinkStreamErrorCode2["ConfigurationError"] = "configurationError";
@@ -559,6 +710,7 @@ var ZlinkStreamConnectorBundle = (() => {
559
710
  ZlinkStreamErrorCode2["SendFailed"] = "sendFailed";
560
711
  ZlinkStreamErrorCode2["CompressionFailed"] = "compressionFailed";
561
712
  ZlinkStreamErrorCode2["DecompressionFailed"] = "decompressionFailed";
713
+ ZlinkStreamErrorCode2["TlsValidationFailed"] = "tlsValidationFailed";
562
714
  ZlinkStreamErrorCode2["UserCallbackFailed"] = "userCallbackFailed";
563
715
  ZlinkStreamErrorCode2["RemoteError"] = "remoteError";
564
716
  return ZlinkStreamErrorCode2;
@@ -573,6 +725,15 @@ var ZlinkStreamConnectorBundle = (() => {
573
725
  return ZlinkStreamConnectionState3;
574
726
  })(ZlinkStreamConnectionState || {});
575
727
 
728
+ // packages/stream-connector/src/Contracts/ZlinkStreamModels.ts
729
+ var ZlinkStreamException = class extends Error {
730
+ constructor(error) {
731
+ super(error.message);
732
+ this.error = error;
733
+ this.name = "ZlinkStreamException";
734
+ }
735
+ };
736
+
576
737
  // packages/stream-connector/src/Contracts/ZlinkStreamMetadata.ts
577
738
  var _ZlinkStreamMetadataMap = class _ZlinkStreamMetadataMap {
578
739
  constructor(values) {
@@ -606,25 +767,13 @@ var ZlinkStreamConnectorBundle = (() => {
606
767
  var ZlinkStreamMetadataMap = _ZlinkStreamMetadataMap;
607
768
  function validateMetadataKey(key) {
608
769
  if (key.length === 0) {
609
- throw new Error("Metadata key must not be empty.");
610
- }
611
- for (let index = 0; index < key.length; index++) {
612
- const code = key.charCodeAt(index);
613
- if (code < 32 || code > 126 || key[index] === "=") {
614
- throw new Error('Metadata key must contain printable ASCII characters except "=".');
615
- }
770
+ throw new ZlinkStreamException({
771
+ code: "validationFailed" /* ValidationFailed */,
772
+ message: "Metadata key must not be empty."
773
+ });
616
774
  }
617
775
  }
618
776
 
619
- // packages/stream-connector/src/Contracts/ZlinkStreamModels.ts
620
- var ZlinkStreamException = class extends Error {
621
- constructor(error) {
622
- super(error.message);
623
- this.error = error;
624
- this.name = "ZlinkStreamException";
625
- }
626
- };
627
-
628
777
  // packages/stream-connector/src/Contracts/ZlinkStreamJsonCodec.ts
629
778
  var zlinkStreamJsonCodecName = "json";
630
779
  var codecOptions = {};
@@ -677,6 +826,10 @@ var ZlinkStreamConnectorBundle = (() => {
677
826
  }
678
827
 
679
828
  // packages/stream-connector/src/Runtime/ZlinkStreamSupport.ts
829
+ var BACKING_ARRAY_COMPACTION_MIN_HEAD = 1024;
830
+ function shouldCompactBackingArray(head, length) {
831
+ return head >= BACKING_ARRAY_COMPACTION_MIN_HEAD && head * 2 >= length;
832
+ }
680
833
  function connectorError(code, message, cause) {
681
834
  return new ZlinkStreamException({ code, message, cause });
682
835
  }
@@ -690,15 +843,21 @@ var ZlinkStreamConnectorBundle = (() => {
690
843
  if (error instanceof ZlinkStreamException) {
691
844
  return error.error;
692
845
  }
693
- return {
694
- code: "remoteError" /* RemoteError */,
695
- message: error instanceof Error ? error.message : String(error),
696
- cause: error
697
- };
846
+ throw error;
698
847
  }
699
848
  function subscription(dispose) {
700
849
  return { dispose };
701
850
  }
851
+ function* currentRegistrations(registrations, snapshot = Array.from(registrations)) {
852
+ for (const registration of snapshot) {
853
+ if (registrations.has(registration)) yield registration;
854
+ }
855
+ }
856
+ function registerHandler(handlers, handler) {
857
+ const registration = { handler };
858
+ handlers.add(registration);
859
+ return subscription(() => handlers.delete(registration));
860
+ }
702
861
  function throwIfAborted(signal) {
703
862
  if ((signal == null ? void 0 : signal.aborted) === true) {
704
863
  throw connectorError("disconnected" /* Disconnected */, "Operation canceled.");
@@ -718,9 +877,6 @@ var ZlinkStreamConnectorBundle = (() => {
718
877
  signal == null ? void 0 : signal.addEventListener("abort", onAbort, { once: true });
719
878
  });
720
879
  }
721
- function utf8Encode2(value) {
722
- return new TextEncoder().encode(value);
723
- }
724
880
  function utf8Decode2(value) {
725
881
  return new TextDecoder().decode(value);
726
882
  }
@@ -739,59 +895,48 @@ var ZlinkStreamConnectorBundle = (() => {
739
895
  }
740
896
  },
741
897
  async expectFailure(action, errorKind) {
742
- let failure;
743
898
  try {
744
899
  await action();
745
- } catch (error) {
746
- failure = error;
747
- }
748
- if (failure === void 0) {
749
- throw connectorError("validationFailed" /* ValidationFailed */, "Expected action to fail.");
750
- }
751
- const streamError = unwrapStreamError(failure);
752
- if (errorKind !== void 0 && streamError.code !== errorKind) {
753
- throw connectorError(
754
- "validationFailed" /* ValidationFailed */,
755
- `Expected failure kind '${errorKind}', got '${streamError.code}'.`,
756
- failure
757
- );
900
+ } catch (failure) {
901
+ if (!(failure instanceof ZlinkStreamException)) throw failure;
902
+ const streamError = failure.error;
903
+ if (errorKind !== void 0 && streamError.code !== errorKind) {
904
+ throw connectorError(
905
+ "validationFailed" /* ValidationFailed */,
906
+ `Expected failure kind '${errorKind}', got '${streamError.code}'.`,
907
+ failure
908
+ );
909
+ }
910
+ return streamError;
758
911
  }
759
- return streamError;
912
+ throw connectorError("validationFailed" /* ValidationFailed */, "Expected action to fail.");
760
913
  },
761
914
  async expectTimeout(action) {
762
- let failure;
763
915
  try {
764
916
  await action();
765
- } catch (error) {
766
- failure = error;
767
- }
768
- if (failure === void 0) {
769
- throw connectorError("validationFailed" /* ValidationFailed */, "Expected action to time out.");
770
- }
771
- const code = unwrapStreamError(failure).code;
772
- if (code !== "requestTimeout" /* RequestTimeout */ && code !== "connectTimeout" /* ConnectTimeout */) {
773
- throw failure;
917
+ } catch (failure) {
918
+ if (!(failure instanceof ZlinkStreamException) || failure.error.code !== "requestTimeout" /* RequestTimeout */ && failure.error.code !== "connectTimeout" /* ConnectTimeout */) {
919
+ throw failure;
920
+ }
921
+ return;
774
922
  }
923
+ throw connectorError("validationFailed" /* ValidationFailed */, "Expected action to time out.");
775
924
  }
776
925
  };
777
926
 
778
927
  // packages/stream-connector/src/Runtime/Protocol/ZlinkStreamPacketNameValidator.ts
779
928
  function validateName(name, allowReserved = false) {
780
- if (name.length === 0) {
781
- throw connectorError("validationFailed" /* ValidationFailed */, "Message name must not be empty.");
929
+ try {
930
+ validateStreamWirePacketName(name);
931
+ } catch (cause) {
932
+ throw connectorError("validationFailed" /* ValidationFailed */, "Message name is invalid.", cause);
782
933
  }
783
- if (!allowReserved && name.startsWith("$zlink.")) {
934
+ if (!allowReserved && name.startsWith(ZLINK_STREAM_RESERVED_PACKET_NAME_PREFIX)) {
784
935
  throw connectorError(
785
936
  "validationFailed" /* ValidationFailed */,
786
937
  "Message name uses a reserved zlink prefix."
787
938
  );
788
939
  }
789
- if (utf8Encode2(name).length > 255) {
790
- throw connectorError(
791
- "validationFailed" /* ValidationFailed */,
792
- "Message name must not exceed 255 UTF-8 bytes."
793
- );
794
- }
795
940
  }
796
941
 
797
942
  // packages/stream-connector/src/Runtime/Calls/ZlinkStreamCallBuilders.ts
@@ -864,9 +1009,10 @@ var ZlinkStreamConnectorBundle = (() => {
864
1009
  }
865
1010
  };
866
1011
  var ZlinkStreamRequestBuilder = class {
867
- constructor(connector, name, payload, actorSlot, validateActor) {
1012
+ constructor(connector, name, payload, enqueueCallback, actorSlot, validateActor) {
868
1013
  this.connector = connector;
869
1014
  this.payload = payload;
1015
+ this.enqueueCallback = enqueueCallback;
870
1016
  __publicField(this, "state");
871
1017
  this.state = new ZlinkStreamCallBuilderState(name, actorSlot, validateActor);
872
1018
  }
@@ -901,8 +1047,10 @@ var ZlinkStreamConnectorBundle = (() => {
901
1047
  );
902
1048
  if (typeof signalOrCallback === "function") {
903
1049
  operation.then(
904
- (value) => signalOrCallback({ isSuccess: true, value }),
905
- (error) => signalOrCallback({ isSuccess: false, error: unwrapStreamError(error) })
1050
+ (value) => this.enqueueCallback(() => signalOrCallback({ isSuccess: true, value })),
1051
+ (error) => this.enqueueCallback(
1052
+ () => signalOrCallback({ isSuccess: false, error: unwrapStreamError(error) })
1053
+ )
906
1054
  );
907
1055
  return;
908
1056
  }
@@ -1113,6 +1261,12 @@ var ZlinkStreamConnectorBundle = (() => {
1113
1261
  return lz4PickleUncompressed2(payload);
1114
1262
  },
1115
1263
  decompress(payload, maxDecompressedSize) {
1264
+ if (lz4PickledLength2(payload) > maxDecompressedSize) {
1265
+ throw connectorError(
1266
+ "frameTooLarge" /* FrameTooLarge */,
1267
+ "LZ4 decoded payload exceeds MaxReceivePayloadSize."
1268
+ );
1269
+ }
1116
1270
  return lz4UnpicklePayload2(payload, maxDecompressedSize);
1117
1271
  }
1118
1272
  };
@@ -1124,7 +1278,11 @@ var ZlinkStreamConnectorBundle = (() => {
1124
1278
  "Compression codec is not configured."
1125
1279
  );
1126
1280
  }
1127
- return codec.compress(payload);
1281
+ try {
1282
+ return codec.compress(payload);
1283
+ } catch (cause) {
1284
+ throw connectorError("compressionFailed" /* CompressionFailed */, "Compression failed.", cause);
1285
+ }
1128
1286
  }
1129
1287
  function decompressIfNeeded(header, payload, compression, compressionCodec, maxDecompressedSize) {
1130
1288
  if ((header.flags & 4 /* PayloadCompressed */) === 0) {
@@ -1137,15 +1295,20 @@ var ZlinkStreamConnectorBundle = (() => {
1137
1295
  "Compression codec is not configured."
1138
1296
  );
1139
1297
  }
1298
+ let decompressed;
1140
1299
  try {
1141
- const decompressed = codec.decompress(payload, maxDecompressedSize);
1142
- if (decompressed.length > maxDecompressedSize) {
1143
- throw new Error("Decoded payload exceeds MaxReceivePayloadSize.");
1144
- }
1145
- return decompressed;
1300
+ decompressed = codec.decompress(payload, maxDecompressedSize);
1146
1301
  } catch (cause) {
1302
+ if (cause instanceof ZlinkStreamException) throw cause;
1147
1303
  throw connectorError("decompressionFailed" /* DecompressionFailed */, "Decompression failed.", cause);
1148
1304
  }
1305
+ if (decompressed.length > maxDecompressedSize) {
1306
+ throw connectorError(
1307
+ "frameTooLarge" /* FrameTooLarge */,
1308
+ "Decompressed payload exceeds MaxReceivePayloadSize."
1309
+ );
1310
+ }
1311
+ return decompressed;
1149
1312
  }
1150
1313
  function resolveCompressionCodec(compression, compressionCodec) {
1151
1314
  if (compression === "none" /* None */) {
@@ -1154,9 +1317,165 @@ var ZlinkStreamConnectorBundle = (() => {
1154
1317
  return compressionCodec != null ? compressionCodec : zlinkStreamLz4CompressionCodec;
1155
1318
  }
1156
1319
 
1320
+ // packages/stream-connector/src/Contracts/ZlinkStreamConnectorOptions.ts
1321
+ var ZLINK_STREAM_DEFAULT_PAYLOAD_BYTES = 64 * 1024;
1322
+
1323
+ // packages/stream-connector/src/Runtime/Transport/ZlinkStreamEndpoint.ts
1324
+ function inferTransport(endpoint) {
1325
+ const url = parseEndpoint(endpoint);
1326
+ switch (url.protocol) {
1327
+ case "ws:":
1328
+ return "webSocket" /* WebSocket */;
1329
+ case "wss:":
1330
+ return "webSocketSecure" /* WebSocketSecure */;
1331
+ default:
1332
+ throw connectorError(
1333
+ "configurationError" /* ConfigurationError */,
1334
+ "The TypeScript Stream Connector supports only ws:// and wss:// endpoints."
1335
+ );
1336
+ }
1337
+ }
1338
+ function parseEndpoint(endpoint) {
1339
+ try {
1340
+ return new URL(endpoint);
1341
+ } catch (cause) {
1342
+ throw connectorError("configurationError" /* ConfigurationError */, "Endpoint is invalid.", cause);
1343
+ }
1344
+ }
1345
+
1346
+ // packages/stream-connector/src/Runtime/ZlinkStreamConnectorOptions.ts
1347
+ function normalizeOptions(options, defaultTransportFactory) {
1348
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z;
1349
+ const endpoint = options.endpoint;
1350
+ if (endpoint.trim().length === 0) {
1351
+ throw connectorError("configurationError" /* ConfigurationError */, "Endpoint must not be empty.");
1352
+ }
1353
+ const inferredTransport = inferTransport(endpoint);
1354
+ if (options.transport !== void 0 && options.transport !== inferredTransport) {
1355
+ throw connectorError(
1356
+ "configurationError" /* ConfigurationError */,
1357
+ "Configured transport conflicts with endpoint scheme."
1358
+ );
1359
+ }
1360
+ const normalized = {
1361
+ endpoint,
1362
+ transport: inferredTransport,
1363
+ connectTimeoutMs: (_a = options.connectTimeoutMs) != null ? _a : 5e3,
1364
+ requestTimeoutMs: (_b = options.requestTimeoutMs) != null ? _b : 3e4,
1365
+ waitTimeoutMs: (_c = options.waitTimeoutMs) != null ? _c : 5e3,
1366
+ heartbeat: {
1367
+ enabled: (_e = (_d = options.heartbeat) == null ? void 0 : _d.enabled) != null ? _e : true,
1368
+ intervalMs: (_g = (_f = options.heartbeat) == null ? void 0 : _f.intervalMs) != null ? _g : 1e3,
1369
+ timeoutMs: (_i = (_h = options.heartbeat) == null ? void 0 : _h.timeoutMs) != null ? _i : 5e3
1370
+ },
1371
+ reconnect: {
1372
+ enabled: (_k = (_j = options.reconnect) == null ? void 0 : _j.enabled) != null ? _k : true,
1373
+ initialDelayMs: (_m = (_l = options.reconnect) == null ? void 0 : _l.initialDelayMs) != null ? _m : 250,
1374
+ maxDelayMs: (_o = (_n = options.reconnect) == null ? void 0 : _n.maxDelayMs) != null ? _o : 5e3,
1375
+ backoffFactor: (_q = (_p = options.reconnect) == null ? void 0 : _p.backoffFactor) != null ? _q : 2,
1376
+ maxAttempts: ((_r = options.reconnect) == null ? void 0 : _r.maxAttempts) === void 0 ? 3 : options.reconnect.maxAttempts
1377
+ },
1378
+ maxSendPayloadSize: (_s = options.maxSendPayloadSize) != null ? _s : ZLINK_STREAM_DEFAULT_PAYLOAD_BYTES,
1379
+ maxReceivePayloadSize: (_t = options.maxReceivePayloadSize) != null ? _t : ZLINK_STREAM_DEFAULT_PAYLOAD_BYTES,
1380
+ dispatchMode: (_u = options.dispatchMode) != null ? _u : "manual" /* Manual */,
1381
+ compression: (_v = options.compression) != null ? _v : "lz4" /* Lz4 */,
1382
+ compressionCodec: options.compressionCodec,
1383
+ nameResolver: (_w = options.nameResolver) != null ? _w : defaultPacketNameResolver,
1384
+ transportFactory: (_x = options.transportFactory) != null ? _x : defaultTransportFactory,
1385
+ codec: options.codec
1386
+ };
1387
+ validatePositive(normalized.connectTimeoutMs, "ConnectTimeout");
1388
+ validatePositive(normalized.requestTimeoutMs, "RequestTimeout");
1389
+ validatePositive(normalized.waitTimeoutMs, "WaitTimeout");
1390
+ validatePositive(normalized.maxSendPayloadSize, "MaxSendPayloadSize");
1391
+ validatePositive(normalized.maxReceivePayloadSize, "MaxReceivePayloadSize");
1392
+ validateHeartbeat(normalized.heartbeat);
1393
+ validateReconnect(normalized.reconnect);
1394
+ if (((_y = options.heartbeat) == null ? void 0 : _y.enabled) !== void 0 && typeof options.heartbeat.enabled !== "boolean") {
1395
+ throw connectorError(
1396
+ "validationFailed" /* ValidationFailed */,
1397
+ "Heartbeat enabled must be boolean."
1398
+ );
1399
+ }
1400
+ if (((_z = options.reconnect) == null ? void 0 : _z.enabled) !== void 0 && typeof options.reconnect.enabled !== "boolean") {
1401
+ throw connectorError(
1402
+ "validationFailed" /* ValidationFailed */,
1403
+ "Reconnect enabled must be boolean."
1404
+ );
1405
+ }
1406
+ if (options.compressionCodec !== void 0 && !hasMethods(options.compressionCodec, "compress", "decompress")) {
1407
+ throw connectorError("validationFailed" /* ValidationFailed */, "Compression codec is invalid.");
1408
+ }
1409
+ if (options.codec !== void 0 && !hasMethods(options.codec, "encode", "decode")) {
1410
+ throw connectorError("validationFailed" /* ValidationFailed */, "Payload codec is invalid.");
1411
+ }
1412
+ if (options.nameResolver !== void 0 && !hasMethods(options.nameResolver, "resolve")) {
1413
+ throw connectorError("validationFailed" /* ValidationFailed */, "Packet name resolver is invalid.");
1414
+ }
1415
+ if (options.transportFactory !== void 0 && !hasMethods(options.transportFactory, "connect")) {
1416
+ throw connectorError("validationFailed" /* ValidationFailed */, "Transport factory is invalid.");
1417
+ }
1418
+ if (!Object.values(ZlinkStreamDispatchMode).includes(normalized.dispatchMode)) {
1419
+ throw connectorError("validationFailed" /* ValidationFailed */, "DispatchMode is invalid.");
1420
+ }
1421
+ if (!Object.values(ZlinkStreamCompression).includes(normalized.compression)) {
1422
+ throw connectorError("validationFailed" /* ValidationFailed */, "Compression is invalid.");
1423
+ }
1424
+ validateCompressionCodec(normalized);
1425
+ return normalized;
1426
+ }
1427
+ var defaultPacketNameResolver = {
1428
+ resolve(payloadType) {
1429
+ const declared = payloadType.packetName;
1430
+ if (typeof declared === "string" && declared.length > 0) {
1431
+ return declared;
1432
+ }
1433
+ return payloadType.name;
1434
+ }
1435
+ };
1436
+ function validateCompressionCodec(options) {
1437
+ const compression = options.compression;
1438
+ if (compression === "none" /* None */) {
1439
+ if (options.compressionCodec !== void 0) {
1440
+ throw connectorError(
1441
+ "configurationError" /* ConfigurationError */,
1442
+ "compressionCodec cannot be set when compression is none."
1443
+ );
1444
+ }
1445
+ }
1446
+ }
1447
+ function validatePositive(value, name) {
1448
+ if (!Number.isFinite(value) || value <= 0) {
1449
+ throw connectorError("validationFailed" /* ValidationFailed */, `${name} must be positive.`);
1450
+ }
1451
+ }
1452
+ function hasMethods(value, ...names) {
1453
+ if (value === null || typeof value !== "object") return false;
1454
+ const candidate = value;
1455
+ return names.every((name) => typeof candidate[name] === "function");
1456
+ }
1457
+ function validateHeartbeat(options) {
1458
+ const intervalMs = options.intervalMs;
1459
+ const timeoutMs = options.timeoutMs;
1460
+ validatePositive(intervalMs, "Heartbeat interval");
1461
+ validatePositive(timeoutMs, "Heartbeat timeout");
1462
+ }
1463
+ function validateReconnect(options) {
1464
+ validatePositive(options.initialDelayMs, "Reconnect InitialDelay");
1465
+ validatePositive(options.maxDelayMs, "Reconnect MaxDelay");
1466
+ validatePositive(options.backoffFactor, "Reconnect BackoffFactor");
1467
+ const maxAttempts = options.maxAttempts;
1468
+ if (maxAttempts !== null && !(Number.isFinite(maxAttempts) && maxAttempts > 0)) {
1469
+ throw connectorError(
1470
+ "validationFailed" /* ValidationFailed */,
1471
+ "Reconnect MaxAttempts must be null or positive."
1472
+ );
1473
+ }
1474
+ }
1475
+
1157
1476
  // packages/stream-connector/src/Runtime/Protocol/ZlinkStreamFrameCodec.ts
1158
1477
  var ZlinkStreamFrameCodec = class {
1159
- static encode(header, payload, maxPayloadSize = 64 * 1024) {
1478
+ static encode(header, payload, maxPayloadSize = ZLINK_STREAM_DEFAULT_PAYLOAD_BYTES) {
1160
1479
  validatePayload(payload.length, maxPayloadSize);
1161
1480
  try {
1162
1481
  return encodeStreamWireFrame(header, payload);
@@ -1177,35 +1496,14 @@ var ZlinkStreamConnectorBundle = (() => {
1177
1496
  }
1178
1497
  };
1179
1498
  function splitZlinkStreamFrames(chunk) {
1180
- if (chunk.length === 0) {
1499
+ try {
1500
+ return splitStreamWireFrames(chunk);
1501
+ } catch (cause) {
1181
1502
  throw connectorError(
1182
1503
  "frameDecodeFailed" /* FrameDecodeFailed */,
1183
- "Stream frame prefix is incomplete."
1504
+ cause instanceof Error ? cause.message : "Frame length does not match prefix."
1184
1505
  );
1185
1506
  }
1186
- const frames = [];
1187
- let offset = 0;
1188
- while (offset < chunk.length) {
1189
- const remaining = chunk.length - offset;
1190
- if (remaining < 6) {
1191
- throw connectorError(
1192
- "frameDecodeFailed" /* FrameDecodeFailed */,
1193
- "Stream frame prefix is incomplete."
1194
- );
1195
- }
1196
- const headerLength = chunk[offset] << 8 | chunk[offset + 1];
1197
- const payloadLength = chunk[offset + 2] * 16777216 + (chunk[offset + 3] << 16) + (chunk[offset + 4] << 8) + chunk[offset + 5];
1198
- const frameLength = 6 + headerLength + payloadLength;
1199
- if (frameLength > remaining) {
1200
- throw connectorError(
1201
- "frameDecodeFailed" /* FrameDecodeFailed */,
1202
- "Frame length does not match prefix."
1203
- );
1204
- }
1205
- frames.push(chunk.subarray(offset, offset + frameLength));
1206
- offset += frameLength;
1207
- }
1208
- return frames;
1209
1507
  }
1210
1508
  function validatePayload(payloadLength, maxPayloadSize) {
1211
1509
  if (payloadLength > maxPayloadSize) {
@@ -1217,59 +1515,34 @@ var ZlinkStreamConnectorBundle = (() => {
1217
1515
  }
1218
1516
 
1219
1517
  // packages/stream-connector/src/Runtime/Protocol/ZlinkStreamMetadataCodec.ts
1220
- var ZLINK_STREAM_MAX_METADATA_BYTES = 1024;
1221
1518
  var ZlinkStreamMetadataCodec = class {
1222
1519
  static size(metadata) {
1520
+ let size;
1223
1521
  try {
1224
- const size = metadata.count === 0 ? 0 : encodeStreamWireMetadata(metadata.values).length;
1225
- if (size > ZLINK_STREAM_MAX_METADATA_BYTES) {
1226
- throw connectorError(
1227
- "validationFailed" /* ValidationFailed */,
1228
- `Metadata must not exceed ${ZLINK_STREAM_MAX_METADATA_BYTES} bytes.`
1229
- );
1230
- }
1231
- return size;
1522
+ size = metadata.count === 0 ? 0 : streamWireMetadataSize(metadata.values);
1232
1523
  } catch (cause) {
1233
1524
  throw connectorError(
1234
1525
  "validationFailed" /* ValidationFailed */,
1235
- streamWireErrorMessage(cause),
1526
+ cause instanceof Error ? cause.message : "Metadata is invalid.",
1236
1527
  cause
1237
1528
  );
1238
1529
  }
1239
- }
1240
- static write(metadata, destination) {
1241
- try {
1242
- destination.set(encodeStreamWireMetadata(metadata.values));
1243
- } catch (cause) {
1530
+ if (size > ZLINK_STREAM_MAX_METADATA_BYTES) {
1244
1531
  throw connectorError(
1245
1532
  "validationFailed" /* ValidationFailed */,
1246
- streamWireErrorMessage(cause),
1247
- cause
1248
- );
1249
- }
1250
- }
1251
- static decode(metadata) {
1252
- try {
1253
- const values = decodeStreamWireMetadata(metadata);
1254
- return values.size === 0 ? ZlinkStreamMetadataMap.empty : ZlinkStreamMetadataMap.from(values);
1255
- } catch (cause) {
1256
- throw connectorError(
1257
- "frameDecodeFailed" /* FrameDecodeFailed */,
1258
- streamWireErrorMessage(cause),
1259
- cause
1533
+ `Metadata must not exceed ${ZLINK_STREAM_MAX_METADATA_BYTES} bytes.`
1260
1534
  );
1261
1535
  }
1536
+ return size;
1262
1537
  }
1263
1538
  };
1264
- function streamWireErrorMessage(cause) {
1265
- return cause instanceof Error ? cause.message : "Metadata is invalid.";
1266
- }
1267
1539
 
1268
1540
  // packages/stream-connector/src/Runtime/Protocol/ZlinkStreamHeaderCodec.ts
1269
1541
  var ZlinkStreamHeaderCodec = class {
1270
1542
  static encode(header) {
1271
1543
  const reply = isReplyKind2(header.kind);
1272
1544
  if (!reply) validateName(header.name, header.kind === 5 /* Control */);
1545
+ validateEncodeFlags(header.flags);
1273
1546
  validateHeaderSemantics(header);
1274
1547
  ZlinkStreamMetadataCodec.size(header.metadata);
1275
1548
  try {
@@ -1286,7 +1559,7 @@ var ZlinkStreamConnectorBundle = (() => {
1286
1559
  } catch (cause) {
1287
1560
  throw connectorError(
1288
1561
  "validationFailed" /* ValidationFailed */,
1289
- streamWireErrorMessage2(cause),
1562
+ streamWireErrorMessage(cause),
1290
1563
  cause
1291
1564
  );
1292
1565
  }
@@ -1306,25 +1579,24 @@ var ZlinkStreamConnectorBundle = (() => {
1306
1579
  correlationId: wire.correlationId,
1307
1580
  actorSlot: wire.actorSlot
1308
1581
  };
1582
+ if (!isReplyKind2(decoded.kind)) {
1583
+ validateName(decoded.name, decoded.kind === 5 /* Control */);
1584
+ }
1585
+ validateHeaderSemantics(decoded);
1309
1586
  } catch (cause) {
1310
1587
  throw connectorError(
1311
1588
  "frameDecodeFailed" /* FrameDecodeFailed */,
1312
- streamWireErrorMessage2(cause),
1589
+ streamWireErrorMessage(cause),
1313
1590
  cause
1314
1591
  );
1315
1592
  }
1316
- validateEnum(decoded.kind, decoded.codec, decoded.flags);
1317
- if (!isReplyKind2(decoded.kind)) {
1318
- validateName(decoded.name, decoded.kind === 5 /* Control */);
1319
- }
1320
- validateHeaderSemantics(decoded);
1321
1593
  return decoded;
1322
1594
  }
1323
1595
  };
1324
1596
  function isReplyKind2(kind) {
1325
1597
  return kind === 3 /* Response */ || kind === 4 /* Error */;
1326
1598
  }
1327
- function streamWireErrorMessage2(cause) {
1599
+ function streamWireErrorMessage(cause) {
1328
1600
  return cause instanceof Error ? cause.message : "Stream header is invalid.";
1329
1601
  }
1330
1602
  function buildHeader(kind, name, codec, metadata, compress, requestSeq, correlationId, actorSlot) {
@@ -1354,7 +1626,7 @@ var ZlinkStreamConnectorBundle = (() => {
1354
1626
  };
1355
1627
  }
1356
1628
  function validateHeaderSemantics(header) {
1357
- validateEnum(header.kind, header.codec, header.flags);
1629
+ validateEnum(header.kind, header.codec);
1358
1630
  const hasRequestSeq = header.requestSeq !== void 0 || (header.flags & 1 /* HasRequestSeq */) !== 0;
1359
1631
  const hasMetadata = header.metadata.count > 0 || (header.flags & 2 /* HasMetadata */) !== 0;
1360
1632
  if (header.kind === 1 /* Send */ && hasRequestSeq) {
@@ -1387,13 +1659,15 @@ var ZlinkStreamConnectorBundle = (() => {
1387
1659
  }
1388
1660
  }
1389
1661
  }
1390
- function validateEnum(kind, codec, flags) {
1391
- if (![1, 2, 3, 4, 5].includes(kind)) {
1662
+ function validateEnum(kind, codec) {
1663
+ if (!isStreamWireMessageKind(kind)) {
1392
1664
  throw connectorError("frameDecodeFailed" /* FrameDecodeFailed */, "Unknown stream message kind.");
1393
1665
  }
1394
- if (![0, 1, 2, 3].includes(codec)) {
1666
+ if (!isStreamWireCodec(codec)) {
1395
1667
  throw connectorError("frameDecodeFailed" /* FrameDecodeFailed */, "Unknown stream codec.");
1396
1668
  }
1669
+ }
1670
+ function validateEncodeFlags(flags) {
1397
1671
  const known = 1 /* HasRequestSeq */ | 2 /* HasMetadata */ | 4 /* PayloadCompressed */ | 8 /* HasCorrelationId */ | 16 /* HasFlowId */ | 32 /* HasActorSlot */;
1398
1672
  if ((flags & ~known) !== 0) {
1399
1673
  throw connectorError("frameDecodeFailed" /* FrameDecodeFailed */, "Unknown stream header flag.");
@@ -1401,8 +1675,8 @@ var ZlinkStreamConnectorBundle = (() => {
1401
1675
  }
1402
1676
 
1403
1677
  // packages/stream-connector/src/Runtime/Protocol/ZlinkStreamFrameProtocol.ts
1404
- var ZLINK_STREAM_HEARTBEAT_PING = "$zlink.heartbeat.ping";
1405
- var ZLINK_STREAM_HEARTBEAT_PONG = "$zlink.heartbeat.pong";
1678
+ var ZLINK_STREAM_HEARTBEAT_PING = ZlinkStreamControlPacket.HeartbeatPing;
1679
+ var ZLINK_STREAM_HEARTBEAT_PONG = ZlinkStreamControlPacket.HeartbeatPong;
1406
1680
  var ZlinkStreamFrameProtocol = class {
1407
1681
  constructor(options) {
1408
1682
  this.options = options;
@@ -1470,178 +1744,39 @@ var ZlinkStreamConnectorBundle = (() => {
1470
1744
  }
1471
1745
  };
1472
1746
 
1473
- // packages/stream-connector/src/Runtime/Transport/ZlinkStreamEndpoint.ts
1474
- function inferTransport(endpoint) {
1475
- const url = parseEndpoint(endpoint);
1476
- switch (url.protocol) {
1477
- case "ws:":
1478
- return "webSocket" /* WebSocket */;
1479
- case "wss:":
1480
- return "webSocketSecure" /* WebSocketSecure */;
1481
- default:
1482
- throw connectorError(
1483
- "configurationError" /* ConfigurationError */,
1484
- "The TypeScript Stream Connector supports only ws:// and wss:// endpoints."
1485
- );
1486
- }
1487
- }
1488
- function parseEndpoint(endpoint) {
1489
- try {
1490
- return new URL(endpoint);
1491
- } catch (cause) {
1492
- throw connectorError("configurationError" /* ConfigurationError */, "Endpoint is invalid.", cause);
1493
- }
1494
- }
1495
-
1496
- // packages/stream-connector/src/Runtime/ZlinkStreamConnectorOptions.ts
1497
- function normalizeOptions(options, defaultTransportFactory) {
1498
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C;
1499
- const endpoint = options.endpoint;
1500
- if (endpoint.trim().length === 0) {
1501
- throw connectorError("configurationError" /* ConfigurationError */, "Endpoint must not be empty.");
1502
- }
1503
- const inferredTransport = inferTransport(endpoint);
1504
- if (options.transport !== void 0 && options.transport !== inferredTransport) {
1505
- throw connectorError(
1506
- "configurationError" /* ConfigurationError */,
1507
- "Configured transport conflicts with endpoint scheme."
1508
- );
1509
- }
1510
- validatePositive((_a = options.connectTimeoutMs) != null ? _a : 5e3, "ConnectTimeout");
1511
- validatePositive((_b = options.requestTimeoutMs) != null ? _b : 3e4, "RequestTimeout");
1512
- validatePositive((_c = options.waitTimeoutMs) != null ? _c : 5e3, "WaitTimeout");
1513
- validatePositive((_d = options.maxSendPayloadSize) != null ? _d : 64 * 1024, "MaxSendPayloadSize");
1514
- validatePositive((_e = options.maxReceivePayloadSize) != null ? _e : 64 * 1024, "MaxReceivePayloadSize");
1515
- validateHeartbeat(options.heartbeat);
1516
- validateReconnect(options.reconnect);
1517
- return {
1518
- endpoint,
1519
- transport: inferredTransport,
1520
- connectTimeoutMs: (_f = options.connectTimeoutMs) != null ? _f : 5e3,
1521
- requestTimeoutMs: (_g = options.requestTimeoutMs) != null ? _g : 3e4,
1522
- waitTimeoutMs: (_h = options.waitTimeoutMs) != null ? _h : 5e3,
1523
- heartbeat: {
1524
- enabled: (_j = (_i = options.heartbeat) == null ? void 0 : _i.enabled) != null ? _j : true,
1525
- intervalMs: (_l = (_k = options.heartbeat) == null ? void 0 : _k.intervalMs) != null ? _l : 1e3,
1526
- timeoutMs: (_n = (_m = options.heartbeat) == null ? void 0 : _m.timeoutMs) != null ? _n : 5e3
1527
- },
1528
- reconnect: {
1529
- enabled: (_p = (_o = options.reconnect) == null ? void 0 : _o.enabled) != null ? _p : true,
1530
- initialDelayMs: (_r = (_q = options.reconnect) == null ? void 0 : _q.initialDelayMs) != null ? _r : 250,
1531
- maxDelayMs: (_t = (_s = options.reconnect) == null ? void 0 : _s.maxDelayMs) != null ? _t : 5e3,
1532
- backoffFactor: (_v = (_u = options.reconnect) == null ? void 0 : _u.backoffFactor) != null ? _v : 2,
1533
- maxAttempts: ((_w = options.reconnect) == null ? void 0 : _w.maxAttempts) === void 0 ? 3 : options.reconnect.maxAttempts
1534
- },
1535
- maxSendPayloadSize: (_x = options.maxSendPayloadSize) != null ? _x : 64 * 1024,
1536
- maxReceivePayloadSize: (_y = options.maxReceivePayloadSize) != null ? _y : 64 * 1024,
1537
- dispatchMode: (_z = options.dispatchMode) != null ? _z : "manual" /* Manual */,
1538
- compression: (_A = options.compression) != null ? _A : "lz4" /* Lz4 */,
1539
- compressionCodec: resolveCompressionCodec2(options),
1540
- nameResolver: (_B = options.nameResolver) != null ? _B : defaultPacketNameResolver,
1541
- transportFactory: (_C = options.transportFactory) != null ? _C : defaultTransportFactory,
1542
- codec: options.codec
1543
- };
1544
- }
1545
- var defaultPacketNameResolver = {
1546
- resolve(payloadType) {
1547
- const declared = payloadType.packetName;
1548
- if (typeof declared === "string" && declared.length > 0) {
1549
- return declared;
1550
- }
1551
- return payloadType.name;
1552
- }
1553
- };
1554
- function resolveCompressionCodec2(options) {
1555
- var _a;
1556
- const compression = (_a = options.compression) != null ? _a : "lz4" /* Lz4 */;
1557
- if (compression === "none" /* None */) {
1558
- if (options.compressionCodec !== void 0) {
1559
- throw connectorError(
1560
- "configurationError" /* ConfigurationError */,
1561
- "compressionCodec cannot be set when compression is none."
1562
- );
1563
- }
1564
- return void 0;
1565
- }
1566
- return options.compressionCodec;
1567
- }
1568
- function validatePositive(value, name) {
1569
- if (value <= 0) {
1570
- throw connectorError("validationFailed" /* ValidationFailed */, `${name} must be positive.`);
1571
- }
1572
- }
1573
- function validateHeartbeat(options) {
1574
- var _a, _b, _c;
1575
- const enabled = (_a = options == null ? void 0 : options.enabled) != null ? _a : true;
1576
- const intervalMs = (_b = options == null ? void 0 : options.intervalMs) != null ? _b : 1e3;
1577
- const timeoutMs = (_c = options == null ? void 0 : options.timeoutMs) != null ? _c : 5e3;
1578
- if (!enabled) {
1579
- return;
1580
- }
1581
- validatePositive(intervalMs, "Heartbeat interval");
1582
- validatePositive(timeoutMs, "Heartbeat timeout");
1583
- if (timeoutMs <= intervalMs) {
1584
- throw connectorError(
1585
- "validationFailed" /* ValidationFailed */,
1586
- "Heartbeat timeout must be greater than the heartbeat interval."
1587
- );
1588
- }
1589
- }
1590
- function validateReconnect(options) {
1591
- var _a, _b, _c, _d;
1592
- const enabled = (_a = options == null ? void 0 : options.enabled) != null ? _a : true;
1593
- if (!enabled) {
1594
- return;
1595
- }
1596
- validatePositive((_b = options == null ? void 0 : options.initialDelayMs) != null ? _b : 250, "Reconnect InitialDelay");
1597
- validatePositive((_c = options == null ? void 0 : options.maxDelayMs) != null ? _c : 5e3, "Reconnect MaxDelay");
1598
- if (((_d = options == null ? void 0 : options.backoffFactor) != null ? _d : 2) < 1) {
1599
- throw connectorError(
1600
- "validationFailed" /* ValidationFailed */,
1601
- "Reconnect BackoffFactor must be at least 1.0."
1602
- );
1603
- }
1604
- const maxAttempts = (options == null ? void 0 : options.maxAttempts) === void 0 ? 3 : options.maxAttempts;
1605
- if (maxAttempts !== null && !(Number.isFinite(maxAttempts) && maxAttempts > 0)) {
1606
- throw connectorError(
1607
- "validationFailed" /* ValidationFailed */,
1608
- "Reconnect MaxAttempts must be null or positive."
1609
- );
1610
- }
1611
- }
1612
-
1613
1747
  // packages/stream-connector/src/Runtime/ZlinkStreamPendingRequests.ts
1614
1748
  var ZlinkStreamPendingRequests = class {
1615
1749
  constructor() {
1616
1750
  __publicField(this, "nextRequestSeq", 1n);
1617
1751
  __publicField(this, "active", /* @__PURE__ */ new Map());
1618
1752
  }
1619
- get count() {
1620
- return this.active.size;
1621
- }
1622
1753
  create(packetName, timeoutMs) {
1754
+ if (this.nextRequestSeq > UINT64_MAX) {
1755
+ throw connectorError("sendFailed" /* SendFailed */, "Request sequence is exhausted.");
1756
+ }
1623
1757
  const requestSeq = this.nextRequestSeq++;
1624
1758
  let timeout;
1625
1759
  let resolvePending;
1626
1760
  let rejectPending;
1627
1761
  const promise = new Promise(
1628
1762
  (resolve, reject) => {
1629
- timeout = setTimeout(() => {
1630
- this.active.delete(requestSeq);
1631
- reject(
1632
- connectorError(
1633
- "requestTimeout" /* RequestTimeout */,
1634
- `Request '${packetName}' timed out.`
1635
- )
1636
- );
1637
- }, timeoutMs);
1638
1763
  resolvePending = resolve;
1639
1764
  rejectPending = (error) => reject(connectorError(error.code, error.message, error.cause));
1640
1765
  }
1641
1766
  );
1642
- this.active.set(requestSeq, {
1767
+ const tracked = {
1643
1768
  packetName,
1644
1769
  promise,
1770
+ startTimeout: () => {
1771
+ if (timeout !== void 0 || this.active.get(requestSeq) !== tracked) return;
1772
+ timeout = setTimeout(() => {
1773
+ this.active.delete(requestSeq);
1774
+ rejectPending({
1775
+ code: "requestTimeout" /* RequestTimeout */,
1776
+ message: `Request '${packetName}' timed out.`
1777
+ });
1778
+ }, timeoutMs);
1779
+ },
1645
1780
  resolve: (value) => {
1646
1781
  if (timeout !== void 0) {
1647
1782
  clearTimeout(timeout);
@@ -1659,8 +1794,9 @@ var ZlinkStreamConnectorBundle = (() => {
1659
1794
  clearTimeout(timeout);
1660
1795
  }
1661
1796
  }
1662
- });
1663
- return { requestSeq, promise };
1797
+ };
1798
+ this.active.set(requestSeq, tracked);
1799
+ return { requestSeq, promise, startTimeout: tracked.startTimeout };
1664
1800
  }
1665
1801
  /* stream connector spec §5.2: a pending request is matched by request_seq alone. */
1666
1802
  resolve(requestSeq, value, metadata) {
@@ -1668,8 +1804,9 @@ var ZlinkStreamConnectorBundle = (() => {
1668
1804
  if (pending === void 0) {
1669
1805
  return false;
1670
1806
  }
1807
+ const payload = value();
1671
1808
  this.active.delete(requestSeq);
1672
- pending.resolve({ name: pending.packetName, metadata, payload: value });
1809
+ pending.resolve({ name: pending.packetName, metadata, payload });
1673
1810
  return true;
1674
1811
  }
1675
1812
  reject(requestSeq, error) {
@@ -1697,7 +1834,156 @@ var ZlinkStreamConnectorBundle = (() => {
1697
1834
  }
1698
1835
  };
1699
1836
 
1837
+ // packages/stream-connector/src/Runtime/ZlinkStreamActors.ts
1838
+ var ACTOR_BOUND = ZlinkStreamControlPacket.ActorBound;
1839
+ var ACTOR_UNBOUND = ZlinkStreamControlPacket.ActorUnbound;
1840
+ var zlinkStreamActorBinding = Symbol("zlink.stream.actorBinding");
1841
+ var DefaultZlinkStreamActor = class {
1842
+ constructor(connector, actorId, slot) {
1843
+ this.connector = connector;
1844
+ this.actorId = actorId;
1845
+ this.slot = slot;
1846
+ __publicField(this, "bound", true);
1847
+ }
1848
+ get isBound() {
1849
+ return this.bound;
1850
+ }
1851
+ send(payload, messageType) {
1852
+ this.ensureBound();
1853
+ return this.connector.sendForActor(this, payload, messageType);
1854
+ }
1855
+ request(payload, messageType) {
1856
+ this.ensureBound();
1857
+ return this.connector.requestForActor(this, payload, messageType);
1858
+ }
1859
+ on(nameOrType, handler, messageType) {
1860
+ return this.connector.onActorMessage(this, nameOrType, handler, messageType);
1861
+ }
1862
+ ensureBound() {
1863
+ if (!this.bound) {
1864
+ throw connectorError(
1865
+ "validationFailed" /* ValidationFailed */,
1866
+ `Actor '${this.actorId}' is no longer bound.`
1867
+ );
1868
+ }
1869
+ }
1870
+ close() {
1871
+ this.bound = false;
1872
+ }
1873
+ };
1874
+ var ZlinkStreamActors = class {
1875
+ constructor(connector, receivedMessages, events) {
1876
+ this.connector = connector;
1877
+ this.receivedMessages = receivedMessages;
1878
+ this.events = events;
1879
+ __publicField(this, "bySlot", /* @__PURE__ */ new Map());
1880
+ __publicField(this, "byId", /* @__PURE__ */ new Map());
1881
+ __publicField(this, "boundHandlers", /* @__PURE__ */ new Set());
1882
+ __publicField(this, "unboundHandlers", /* @__PURE__ */ new Set());
1883
+ }
1884
+ get snapshot() {
1885
+ return Object.freeze(Array.from(this.bySlot.values()));
1886
+ }
1887
+ find(actorId) {
1888
+ return this.byId.get(actorId);
1889
+ }
1890
+ onBound(handler) {
1891
+ return registerHandler(this.boundHandlers, handler);
1892
+ }
1893
+ onUnbound(handler) {
1894
+ return registerHandler(this.unboundHandlers, handler);
1895
+ }
1896
+ processControl(name, payload, signal) {
1897
+ if (name === ACTOR_BOUND) {
1898
+ this.bind(payload, signal);
1899
+ return true;
1900
+ }
1901
+ if (name === ACTOR_UNBOUND) {
1902
+ this.unbind(payload, signal);
1903
+ return true;
1904
+ }
1905
+ return false;
1906
+ }
1907
+ resolve(slot) {
1908
+ const actor = this.bySlot.get(slot);
1909
+ if (actor === void 0) {
1910
+ throw connectorError(
1911
+ "frameDecodeFailed" /* FrameDecodeFailed */,
1912
+ `Actor slot '${slot}' is not bound.`
1913
+ );
1914
+ }
1915
+ return actor;
1916
+ }
1917
+ closeAll(signal) {
1918
+ for (const actor of this.bySlot.values()) {
1919
+ this.bySlot.delete(actor.slot);
1920
+ this.byId.delete(actor.actorId);
1921
+ actor.close();
1922
+ this.queue(this.unboundHandlers, actor, signal);
1923
+ }
1924
+ }
1925
+ bind(payload, signal) {
1926
+ let binding;
1927
+ try {
1928
+ binding = decodeStreamWireActorBoundPayload(payload);
1929
+ } catch (cause) {
1930
+ throw connectorError(
1931
+ "frameDecodeFailed" /* FrameDecodeFailed */,
1932
+ cause instanceof Error ? cause.message : "Actor bound payload is invalid.",
1933
+ cause instanceof Error ? cause.cause : void 0
1934
+ );
1935
+ }
1936
+ const { slot, actorId } = binding;
1937
+ if (actorId.length === 0 || this.bySlot.has(slot) || this.byId.has(actorId)) {
1938
+ throw invalidControl("Actor bound identity is already in use.");
1939
+ }
1940
+ const actor = new DefaultZlinkStreamActor(this.connector, actorId, slot);
1941
+ this.bySlot.set(slot, actor);
1942
+ this.byId.set(actorId, actor);
1943
+ this.queue(this.boundHandlers, actor, signal);
1944
+ }
1945
+ unbind(payload, signal) {
1946
+ let slot;
1947
+ try {
1948
+ slot = decodeStreamWireActorUnboundPayload(payload);
1949
+ } catch (cause) {
1950
+ throw connectorError(
1951
+ "frameDecodeFailed" /* FrameDecodeFailed */,
1952
+ cause instanceof Error ? cause.message : "Actor unbound payload is invalid."
1953
+ );
1954
+ }
1955
+ const actor = this.bySlot.get(slot);
1956
+ if (slot === 0 || actor === void 0) {
1957
+ throw invalidControl(`Actor slot '${slot}' is not bound.`);
1958
+ }
1959
+ this.bySlot.delete(slot);
1960
+ this.byId.delete(actor.actorId);
1961
+ actor.close();
1962
+ this.queue(this.unboundHandlers, actor, signal);
1963
+ }
1964
+ queue(handlers, actor, signal) {
1965
+ this.receivedMessages.enqueueCallback(
1966
+ () => {
1967
+ for (const { handler } of currentRegistrations(handlers)) {
1968
+ this.events.runUserCallback(
1969
+ () => handler(actor, signal),
1970
+ "Actor lifecycle handler failed.",
1971
+ signal
1972
+ );
1973
+ }
1974
+ },
1975
+ () => handlers.size
1976
+ );
1977
+ }
1978
+ };
1979
+ function invalidControl(message) {
1980
+ return connectorError("frameDecodeFailed" /* FrameDecodeFailed */, message);
1981
+ }
1982
+
1700
1983
  // packages/stream-connector/src/Runtime/ZlinkStreamReceivedMessages.ts
1984
+ function receives(registration, message) {
1985
+ return registration.actor === void 0 || registration.actor.isBound && registration.actor === message[zlinkStreamActorBinding];
1986
+ }
1701
1987
  var ZlinkStreamReceivedMessages = class {
1702
1988
  /**
1703
1989
  * @param deliverOnArrival `Immediate` runs registered handlers on the receive
@@ -1714,10 +2000,10 @@ var ZlinkStreamConnectorBundle = (() => {
1714
2000
  // queue is not a simple FIFO. Tombstones let us remove a deliverable entry
1715
2001
  // without shifting every later message on the hot receive path.
1716
2002
  __publicField(this, "queue", []);
2003
+ __publicField(this, "deliverable", []);
1717
2004
  __publicField(this, "queueHead", 0);
1718
2005
  __publicField(this, "queuedCount", 0);
1719
- __publicField(this, "drainTask");
1720
- // True for as long as `drain` is on the stack, handler awaits included. It
2006
+ // True for as long as `pump` is on the stack. It
1721
2007
  // marks the execution context a registered handler runs in, so a `dispatch`
1722
2008
  // made from inside a handler is recognised as re-entry rather than a fresh
1723
2009
  // pump. It is not a lock: a single event loop admits no second thread, and
@@ -1728,19 +2014,32 @@ var ZlinkStreamConnectorBundle = (() => {
1728
2014
  // so consuming does not lower it and the dispatch mode does not change it.
1729
2015
  __publicField(this, "receivedCounts", /* @__PURE__ */ new Map());
1730
2016
  }
1731
- on(name, handler) {
2017
+ /**
2018
+ * @param actor The Actor handle that registers the handler, if any. Its
2019
+ * handler receives only that Actor's packets.
2020
+ */
2021
+ on(name, handler, actor) {
1732
2022
  validateName(name);
1733
2023
  let set = this.handlers.get(name);
1734
2024
  if (set === void 0) {
1735
2025
  set = /* @__PURE__ */ new Set();
1736
2026
  this.handlers.set(name, set);
1737
2027
  }
1738
- set.add(handler);
1739
- if (this.deliverOnArrival && this.hasQueuedMessage(name)) {
1740
- queueMicrotask(() => this.scheduleDrain());
2028
+ const registration = { handle: handler, actor };
2029
+ set.add(registration);
2030
+ let newlyDeliverable = false;
2031
+ for (let index = this.queueHead; index < this.queue.length; index += 1) {
2032
+ const queued = this.queue[index];
2033
+ if ((queued == null ? void 0 : queued.kind) === "message" && queued.indexed !== true && queued.message.name === name && receives(registration, queued.message)) {
2034
+ this.indexDeliverable(index);
2035
+ newlyDeliverable = true;
2036
+ }
2037
+ }
2038
+ if (this.deliverOnArrival && newlyDeliverable) {
2039
+ queueMicrotask(() => this.pump());
1741
2040
  }
1742
2041
  return subscription(() => {
1743
- set.delete(handler);
2042
+ set.delete(registration);
1744
2043
  if (set.size === 0 && this.handlers.get(name) === set) {
1745
2044
  this.handlers.delete(name);
1746
2045
  }
@@ -1812,6 +2111,11 @@ var ZlinkStreamConnectorBundle = (() => {
1812
2111
  this.queue.push(...submittedCallbacks);
1813
2112
  this.queueHead = 0;
1814
2113
  this.queuedCount = submittedCallbacks.length;
2114
+ this.deliverable.length = 0;
2115
+ for (let index = 0; index < this.queue.length; index += 1) {
2116
+ this.queue[index].indexed = false;
2117
+ this.indexDeliverable(index);
2118
+ }
1815
2119
  }
1816
2120
  /**
1817
2121
  * Releases every registered wait surface because the connection it was
@@ -1843,60 +2147,38 @@ var ZlinkStreamConnectorBundle = (() => {
1843
2147
  }
1844
2148
  this.queue.push({ kind: "message", message, signal });
1845
2149
  this.queuedCount += 1;
2150
+ this.indexDeliverable(this.queue.length - 1);
1846
2151
  if (this.deliverOnArrival) {
1847
- this.scheduleDrain();
2152
+ this.pump();
1848
2153
  }
1849
2154
  }
1850
- enqueueCallback(callback) {
1851
- this.queue.push({ kind: "callback", callback });
2155
+ /**
2156
+ * @param callbacks The number of handler calls `callback` makes when it runs
2157
+ * with the handlers registered at that moment; a callback that runs a set
2158
+ * of handlers reads the set's size. One callback by default.
2159
+ */
2160
+ enqueueCallback(callback, callbacks = () => 1) {
2161
+ this.queue.push({ kind: "callback", callback, callbacks });
1852
2162
  this.queuedCount += 1;
2163
+ this.indexDeliverable(this.queue.length - 1);
1853
2164
  if (this.deliverOnArrival) {
1854
- this.scheduleDrain();
2165
+ this.pump();
1855
2166
  }
1856
2167
  }
1857
2168
  /**
1858
2169
  * Runs the registered handlers the receive path left queued. `Manual` calls
1859
- * this from `dispatch`; `Immediate` has already drained on arrival.
2170
+ * this from `dispatch`; `Immediate` drains on arrival.
1860
2171
  *
1861
- * A handler that calls `dispatch` arrives back here from inside the drain it
1862
- * was started by. `scheduleDrain` would find `drainTask` already set and
1863
- * return, and the await below would then be the drain waiting on itself —
1864
- * a deadlock with neither timeout nor error. The drain loop already takes
1865
- * every message a handler exists for, so there is nothing a second drain
1866
- * would deliver and returning is the whole of the correct behaviour.
2172
+ * The drain is synchronous: the connector does not wait for a handler
2173
+ * (spec stream-connector 32 §7), so nothing inside it awaits. A handler that
2174
+ * calls `dispatch` arrives back here from inside the drain it was started by;
2175
+ * the running loop already takes every deliverable entry, so returning is the
2176
+ * whole of the correct behaviour.
1867
2177
  */
1868
- async pump() {
2178
+ pump() {
1869
2179
  if (this.draining) {
1870
2180
  return;
1871
2181
  }
1872
- this.scheduleDrain();
1873
- await this.drainTask;
1874
- }
1875
- offerQueued(name, registration) {
1876
- for (let index = this.queueHead; index < this.queue.length; index += 1) {
1877
- const queued = this.queue[index];
1878
- if (queued === void 0 || queued.kind !== "message" || queued.message.name !== name) {
1879
- continue;
1880
- }
1881
- if (!registration.consume(queued.message)) {
1882
- continue;
1883
- }
1884
- this.removeAt(index);
1885
- return;
1886
- }
1887
- }
1888
- scheduleDrain() {
1889
- if (this.drainTask !== void 0) {
1890
- return;
1891
- }
1892
- this.drainTask = this.drain().finally(() => {
1893
- this.drainTask = void 0;
1894
- if (this.deliverOnArrival && this.findDeliverableIndex() >= 0) {
1895
- this.scheduleDrain();
1896
- }
1897
- });
1898
- }
1899
- async drain() {
1900
2182
  this.draining = true;
1901
2183
  try {
1902
2184
  for (let index = this.findDeliverableIndex(); index >= 0; index = this.findDeliverableIndex()) {
@@ -1904,30 +2186,53 @@ var ZlinkStreamConnectorBundle = (() => {
1904
2186
  if (queued === void 0) continue;
1905
2187
  this.removeAt(index);
1906
2188
  if (queued.kind === "callback") {
1907
- await queued.callback();
2189
+ this.events.runUserCallback(queued.callback, "Connector callback failed.");
1908
2190
  continue;
1909
2191
  }
1910
2192
  const { message, signal } = queued;
1911
- const handlers = Array.from(this.handlers.get(message.name));
1912
- for (const handler of handlers) {
1913
- try {
1914
- await handler(message, signal);
1915
- } catch (cause) {
1916
- await this.events.publishError(
1917
- {
1918
- code: "userCallbackFailed" /* UserCallbackFailed */,
1919
- message: "Typed message handler failed.",
1920
- cause
1921
- },
1922
- signal
1923
- );
1924
- }
2193
+ const handlers = this.receiversOf(message);
2194
+ for (const handler of currentRegistrations(this.handlers.get(message.name), handlers)) {
2195
+ if (!receives(handler, message)) continue;
2196
+ this.events.runUserCallback(
2197
+ () => handler.handle(message, signal),
2198
+ "Typed message handler failed.",
2199
+ signal
2200
+ );
1925
2201
  }
1926
2202
  }
1927
2203
  } finally {
1928
2204
  this.draining = false;
1929
2205
  }
1930
2206
  }
2207
+ /**
2208
+ * True while a registered callback runs from {@link pump}: the execution
2209
+ * context spec stream-connector 32 §7 calls "inside a handler".
2210
+ */
2211
+ get dispatching() {
2212
+ return this.draining;
2213
+ }
2214
+ get pendingCallbacks() {
2215
+ let count = 0;
2216
+ for (let index = this.queueHead; index < this.queue.length; index += 1) {
2217
+ const queued = this.queue[index];
2218
+ if ((queued == null ? void 0 : queued.kind) === "callback" && queued.callbacks() > 0) count += 1;
2219
+ if ((queued == null ? void 0 : queued.kind) === "message" && this.receiversOf(queued.message).length > 0) count += 1;
2220
+ }
2221
+ return count;
2222
+ }
2223
+ offerQueued(name, registration) {
2224
+ for (let index = this.queueHead; index < this.queue.length; index += 1) {
2225
+ const queued = this.queue[index];
2226
+ if (queued === void 0 || queued.kind !== "message" || queued.message.name !== name) {
2227
+ continue;
2228
+ }
2229
+ if (!registration.consume(queued.message)) {
2230
+ continue;
2231
+ }
2232
+ this.removeAt(index);
2233
+ return;
2234
+ }
2235
+ }
1931
2236
  removeAt(index) {
1932
2237
  this.queue[index] = void 0;
1933
2238
  this.queuedCount -= 1;
@@ -1935,21 +2240,60 @@ var ZlinkStreamConnectorBundle = (() => {
1935
2240
  this.compactQueue();
1936
2241
  }
1937
2242
  findDeliverableIndex() {
1938
- var _a, _b;
1939
- for (let index = this.queueHead; index < this.queue.length; index += 1) {
2243
+ while (this.deliverable.length > 0) {
2244
+ const index = this.deliverable[0];
1940
2245
  const queued = this.queue[index];
1941
- if (queued !== void 0 && (queued.kind === "callback" || ((_b = (_a = this.handlers.get(queued.message.name)) == null ? void 0 : _a.size) != null ? _b : 0) > 0)) {
2246
+ if (this.isDeliverable(queued)) {
1942
2247
  return index;
1943
2248
  }
2249
+ if (queued !== void 0) queued.indexed = false;
2250
+ this.removeDeliverable();
1944
2251
  }
1945
2252
  return -1;
1946
2253
  }
1947
- hasQueuedMessage(name) {
1948
- for (let index = this.queueHead; index < this.queue.length; index += 1) {
1949
- const queued = this.queue[index];
1950
- if ((queued == null ? void 0 : queued.kind) === "message" && queued.message.name === name) return true;
2254
+ indexDeliverable(index) {
2255
+ const queued = this.queue[index];
2256
+ if (queued === void 0 || !this.isDeliverable(queued) || queued.indexed === true) return;
2257
+ queued.indexed = true;
2258
+ let position = this.deliverable.length;
2259
+ this.deliverable.push(index);
2260
+ while (position > 0) {
2261
+ const parent = Math.floor((position - 1) / 2);
2262
+ if (this.deliverable[parent] <= index) break;
2263
+ this.deliverable[position] = this.deliverable[parent];
2264
+ position = parent;
1951
2265
  }
1952
- return false;
2266
+ this.deliverable[position] = index;
2267
+ }
2268
+ isDeliverable(queued) {
2269
+ return (queued == null ? void 0 : queued.kind) === "callback" || (queued == null ? void 0 : queued.kind) === "message" && this.receiversOf(queued.message).length > 0;
2270
+ }
2271
+ /**
2272
+ * Spec stream-connector 32 §7 and §10: the handlers that receive `message`
2273
+ * are the connector handlers for its name and the handle handlers of the
2274
+ * Actor it carries. A packet no handler receives stays in the queue for the
2275
+ * wait surfaces. This is the one place that decides it.
2276
+ */
2277
+ receiversOf(message) {
2278
+ const set = this.handlers.get(message.name);
2279
+ if (set === void 0) return [];
2280
+ return Array.from(set).filter((registration) => receives(registration, message));
2281
+ }
2282
+ removeDeliverable() {
2283
+ if (this.deliverable.length === 0) return;
2284
+ const last = this.deliverable.pop();
2285
+ if (this.deliverable.length === 0) return;
2286
+ let position = 0;
2287
+ for (; ; ) {
2288
+ const left = position * 2 + 1;
2289
+ if (left >= this.deliverable.length) break;
2290
+ const right = left + 1;
2291
+ const child = right < this.deliverable.length && this.deliverable[right] < this.deliverable[left] ? right : left;
2292
+ if (this.deliverable[child] >= last) break;
2293
+ this.deliverable[position] = this.deliverable[child];
2294
+ position = child;
2295
+ }
2296
+ this.deliverable[position] = last;
1953
2297
  }
1954
2298
  advanceHead() {
1955
2299
  while (this.queueHead < this.queue.length && this.queue[this.queueHead] === void 0) {
@@ -1960,22 +2304,106 @@ var ZlinkStreamConnectorBundle = (() => {
1960
2304
  if (this.queuedCount === 0) {
1961
2305
  this.queue.length = 0;
1962
2306
  this.queueHead = 0;
2307
+ this.deliverable.length = 0;
1963
2308
  return;
1964
2309
  }
1965
- if (this.queueHead >= 1024 && this.queueHead * 2 >= this.queue.length) {
1966
- this.queue.splice(0, this.queueHead);
2310
+ const removed = this.queue.length - this.queuedCount;
2311
+ if (shouldCompactBackingArray(removed, this.queue.length)) {
2312
+ let destination = 0;
2313
+ for (let source = this.queueHead; source < this.queue.length; source += 1) {
2314
+ const queued = this.queue[source];
2315
+ if (queued !== void 0) this.queue[destination++] = queued;
2316
+ }
2317
+ this.queue.length = destination;
1967
2318
  this.queueHead = 0;
2319
+ this.deliverable.length = 0;
2320
+ for (let index = 0; index < this.queue.length; index += 1) {
2321
+ const queued = this.queue[index];
2322
+ if (queued === void 0) continue;
2323
+ queued.indexed = false;
2324
+ this.indexDeliverable(index);
2325
+ }
1968
2326
  }
1969
2327
  }
1970
2328
  };
1971
2329
 
1972
2330
  // packages/stream-connector/src/Runtime/ZlinkStreamFrameSender.ts
2331
+ var ZlinkStreamConnectionWriteQueue = class {
2332
+ /**
2333
+ * @param writeFailed Ends the connection whose transport write failed (spec
2334
+ * stream-connector 32 §9: a transport write failure ends the connection as
2335
+ * `TransportError`).
2336
+ */
2337
+ constructor(connection, writeFailed) {
2338
+ this.connection = connection;
2339
+ this.writeFailed = writeFailed;
2340
+ __publicField(this, "queue", /* @__PURE__ */ new Set());
2341
+ __publicField(this, "active");
2342
+ }
2343
+ enqueue(operation) {
2344
+ this.queue.add(operation);
2345
+ this.advance();
2346
+ }
2347
+ cancel(operation, error) {
2348
+ if (this.queue.delete(operation) || this.active === operation) operation.fail(error);
2349
+ }
2350
+ /**
2351
+ * Spec stream-connector 32 §7: when the connection ends, frames that have not
2352
+ * reached the transport are not written and the frame being written is not
2353
+ * waited for. The operations of both fail with `error`.
2354
+ */
2355
+ failAll(error) {
2356
+ const operations = Array.from(this.queue);
2357
+ if (this.active !== void 0) operations.unshift(this.active);
2358
+ this.queue.clear();
2359
+ this.active = void 0;
2360
+ for (const operation of operations) operation.fail(error);
2361
+ }
2362
+ advance() {
2363
+ if (this.active !== void 0) return;
2364
+ const next = this.queue.values().next().value;
2365
+ if (next === void 0) return;
2366
+ this.queue.delete(next);
2367
+ this.active = next;
2368
+ let write;
2369
+ try {
2370
+ write = Promise.resolve(this.connection.write(next.frame));
2371
+ } catch (error) {
2372
+ write = Promise.reject(error);
2373
+ }
2374
+ void write.then(
2375
+ () => next.complete(),
2376
+ (cause) => this.failWrite(next, cause)
2377
+ ).finally(() => {
2378
+ if (this.active !== next) return;
2379
+ this.active = void 0;
2380
+ this.advance();
2381
+ });
2382
+ }
2383
+ /**
2384
+ * Spec stream-connector 32 §9: a transport write failure is `SendFailed` for
2385
+ * the operation of that write, and it ends the connection. The ending fails
2386
+ * every other operation of the connection with `Disconnected`. A write that
2387
+ * fails after the connection already ended belongs to that ending, which has
2388
+ * already failed its operation with `Disconnected`.
2389
+ */
2390
+ failWrite(operation, cause) {
2391
+ if (this.active !== operation) return;
2392
+ const error = {
2393
+ code: "sendFailed" /* SendFailed */,
2394
+ message: `Frame write failed: ${cause instanceof Error ? cause.message : String(cause)}`,
2395
+ cause
2396
+ };
2397
+ operation.fail(new ZlinkStreamException(error));
2398
+ this.writeFailed(error);
2399
+ }
2400
+ };
1973
2401
  var ZlinkStreamFrameSender = class {
1974
2402
  constructor(protocol) {
1975
2403
  this.protocol = protocol;
1976
- __publicField(this, "pendingWrites", /* @__PURE__ */ new Set());
2404
+ __publicField(this, "queues", /* @__PURE__ */ new Map());
1977
2405
  }
1978
- async send(connection, kind, name, payload, metadata, compress, requestSeq, signal, correlationId, actorSlot) {
2406
+ async send(connection, kind, name, payload, metadata, compress, requestSeq, signal, correlationId, actorSlot, expiry, onAccepted) {
1979
2407
  throwIfAborted(signal);
1980
2408
  await this.write(
1981
2409
  connection,
@@ -1987,224 +2415,96 @@ var ZlinkStreamConnectorBundle = (() => {
1987
2415
  compress,
1988
2416
  requestSeq,
1989
2417
  correlationId,
1990
- actorSlot
1991
- ),
1992
- signal
1993
- );
1994
- }
1995
- async sendControl(connection, name, signal) {
1996
- await this.write(connection, this.protocol.encodeControl(name), signal);
1997
- }
1998
- async drain(signal) {
1999
- while (this.pendingWrites.size > 0) {
2000
- throwIfAborted(signal);
2001
- await Promise.allSettled(Array.from(this.pendingWrites));
2002
- }
2003
- }
2004
- async write(connection, frame, signal) {
2005
- const write = connection.write(frame, signal);
2006
- this.pendingWrites.add(write);
2007
- try {
2008
- await write;
2009
- } finally {
2010
- this.pendingWrites.delete(write);
2011
- }
2012
- }
2013
- };
2014
-
2015
- // packages/stream-connector/src/Runtime/Protocol/ZlinkSessionClosing.ts
2016
- var ZLINK_SESSION_CLOSING = "session-closing";
2017
- var reasons = {
2018
- 1: "ClientClose",
2019
- 2: "IdleTimeout",
2020
- 3: "HeartbeatTimeout",
2021
- 4: "ServerDrain",
2022
- 5: "ProtocolError",
2023
- 6: "TransportError"
2024
- };
2025
- function decodeSessionClosing(payload) {
2026
- if (payload.length < 4 || payload[0] !== 1)
2027
- throw new Error("Unsupported session-closing version.");
2028
- const closeReason = reasons[payload[1]];
2029
- if (closeReason === void 0) throw new Error("Unknown session-closing reason.");
2030
- const length = payload[2] << 8 | payload[3];
2031
- if (length > 512 || payload.length !== 4 + length)
2032
- throw new Error("Invalid session-closing diagnostic length.");
2033
- const diagnostic = length === 0 ? void 0 : new TextDecoder("utf-8", { fatal: true }).decode(payload.subarray(4));
2034
- return { closeReason, diagnostic };
2035
- }
2036
-
2037
- // packages/stream-connector/src/Runtime/ZlinkStreamActors.ts
2038
- var ACTOR_BOUND = "$zlink.actor.bound";
2039
- var ACTOR_UNBOUND = "$zlink.actor.unbound";
2040
- var zlinkStreamActorBinding = Symbol("zlink.stream.actorBinding");
2041
- var DefaultZlinkStreamActor = class {
2042
- constructor(connector, actorId, slot) {
2043
- this.connector = connector;
2044
- this.actorId = actorId;
2045
- this.slot = slot;
2046
- __publicField(this, "bound", true);
2047
- }
2048
- get isBound() {
2049
- return this.bound;
2050
- }
2051
- send(payload, messageType) {
2052
- this.ensureBound();
2053
- return this.connector.sendForActor(this, payload, messageType);
2054
- }
2055
- request(payload, messageType) {
2056
- this.ensureBound();
2057
- return this.connector.requestForActor(this, payload, messageType);
2058
- }
2059
- on(nameOrType, handler, messageType) {
2060
- return this.connector.onActorMessage(this, nameOrType, handler, messageType);
2061
- }
2062
- ensureBound() {
2063
- if (!this.bound) {
2064
- throw connectorError(
2065
- "validationFailed" /* ValidationFailed */,
2066
- `Actor '${this.actorId}' is no longer bound.`
2067
- );
2068
- }
2069
- }
2070
- close() {
2071
- this.bound = false;
2072
- }
2073
- };
2074
- var ZlinkStreamActors = class {
2075
- constructor(connector, receivedMessages, events) {
2076
- this.connector = connector;
2077
- this.receivedMessages = receivedMessages;
2078
- this.events = events;
2079
- __publicField(this, "bySlot", /* @__PURE__ */ new Map());
2080
- __publicField(this, "byId", /* @__PURE__ */ new Map());
2081
- __publicField(this, "issued", []);
2082
- __publicField(this, "boundHandlers", /* @__PURE__ */ new Set());
2083
- __publicField(this, "unboundHandlers", /* @__PURE__ */ new Set());
2084
- }
2085
- get snapshot() {
2086
- return Object.freeze(Array.from(this.bySlot.values()));
2087
- }
2088
- find(actorId) {
2089
- return this.byId.get(actorId);
2090
- }
2091
- onBound(handler) {
2092
- this.boundHandlers.add(handler);
2093
- return subscription(() => this.boundHandlers.delete(handler));
2094
- }
2095
- onUnbound(handler) {
2096
- this.unboundHandlers.add(handler);
2097
- return subscription(() => this.unboundHandlers.delete(handler));
2098
- }
2099
- processControl(name, payload, signal) {
2100
- if (name === ACTOR_BOUND) {
2101
- this.bind(payload, signal);
2102
- return true;
2103
- }
2104
- if (name === ACTOR_UNBOUND) {
2105
- this.unbind(payload, signal);
2106
- return true;
2107
- }
2108
- return false;
2109
- }
2110
- resolve(slot) {
2111
- const actor = this.bySlot.get(slot);
2112
- if (actor === void 0) {
2113
- throw connectorError(
2114
- "frameDecodeFailed" /* FrameDecodeFailed */,
2115
- `Actor slot '${slot}' is not bound.`
2116
- );
2117
- }
2118
- return actor;
2119
- }
2120
- closeAll(signal) {
2121
- for (const actor of this.issued) {
2122
- if (!actor.isBound) continue;
2123
- this.bySlot.delete(actor.slot);
2124
- this.byId.delete(actor.actorId);
2125
- actor.close();
2126
- this.queue(this.unboundHandlers, actor, signal);
2127
- }
2128
- this.issued.length = 0;
2129
- }
2130
- bind(payload, signal) {
2131
- if (payload.length < 5 || payload[0] !== 1) {
2132
- throw invalidControl("Actor bound payload is invalid.");
2133
- }
2134
- const slot = payload[1] << 8 | payload[2];
2135
- const idLength = payload[3];
2136
- if (slot === 0 || idLength === 0 || payload.length !== 4 + idLength) {
2137
- throw invalidControl("Actor bound payload is invalid.");
2138
- }
2139
- let actorId;
2140
- try {
2141
- actorId = new TextDecoder("utf-8", { fatal: true }).decode(payload.subarray(4));
2142
- } catch (cause) {
2143
- throw connectorError(
2144
- "frameDecodeFailed" /* FrameDecodeFailed */,
2145
- "Actor id is not valid UTF-8.",
2146
- cause
2147
- );
2148
- }
2149
- if (actorId.length === 0 || this.bySlot.has(slot) || this.byId.has(actorId)) {
2150
- throw invalidControl("Actor bound identity is already in use.");
2151
- }
2152
- const actor = new DefaultZlinkStreamActor(this.connector, actorId, slot);
2153
- this.bySlot.set(slot, actor);
2154
- this.byId.set(actorId, actor);
2155
- this.issued.push(actor);
2156
- this.queue(this.boundHandlers, actor, signal);
2157
- }
2158
- unbind(payload, signal) {
2159
- if (payload.length !== 3 || payload[0] !== 1) {
2160
- throw invalidControl("Actor unbound payload is invalid.");
2161
- }
2162
- const slot = payload[1] << 8 | payload[2];
2163
- const actor = this.bySlot.get(slot);
2164
- if (slot === 0 || actor === void 0) {
2165
- throw invalidControl(`Actor slot '${slot}' is not bound.`);
2166
- }
2167
- this.bySlot.delete(slot);
2168
- this.byId.delete(actor.actorId);
2169
- actor.close();
2170
- this.queue(this.unboundHandlers, actor, signal);
2418
+ actorSlot
2419
+ ),
2420
+ signal,
2421
+ expiry,
2422
+ onAccepted
2423
+ );
2171
2424
  }
2172
- queue(handlers, actor, signal) {
2173
- this.receivedMessages.enqueueCallback(() => {
2174
- for (const handler of Array.from(handlers)) {
2175
- this.invoke(handler, actor, signal);
2176
- }
2425
+ /**
2426
+ * Writes a control frame (heartbeat ping or pong). A control frame belongs to
2427
+ * no operation: its write failure ends the connection through the write
2428
+ * queue like any other write (spec stream-connector 32 §9), and a connection
2429
+ * that has already ended does not write it. The promise settles when the
2430
+ * write has ended either way.
2431
+ */
2432
+ sendControl(connection, name) {
2433
+ const queue = this.queues.get(connection);
2434
+ if (queue === void 0) return Promise.resolve();
2435
+ const frame = this.protocol.encodeControl(name);
2436
+ return new Promise((resolve) => {
2437
+ queue.enqueue({ frame, complete: resolve, fail: () => resolve() });
2177
2438
  });
2178
2439
  }
2179
- invoke(handler, actor, signal) {
2180
- try {
2181
- Promise.resolve(handler(actor, signal)).catch((cause) => {
2182
- void this.events.publishError(
2183
- {
2184
- code: "userCallbackFailed" /* UserCallbackFailed */,
2185
- message: "Actor lifecycle handler failed.",
2186
- cause
2187
- },
2188
- signal
2189
- );
2190
- });
2191
- } catch (cause) {
2192
- void this.events.publishError(
2193
- {
2194
- code: "userCallbackFailed" /* UserCallbackFailed */,
2195
- message: "Actor lifecycle handler failed.",
2196
- cause
2197
- },
2198
- signal
2199
- );
2440
+ /**
2441
+ * Gives a connection that has just been established its own write queue.
2442
+ * `writeFailed` ends that connection when one of its transport writes fails.
2443
+ */
2444
+ open(connection, writeFailed) {
2445
+ this.queues.set(connection, new ZlinkStreamConnectionWriteQueue(connection, writeFailed));
2446
+ }
2447
+ /**
2448
+ * Ends the write queue of a connection that has ended, by close and by
2449
+ * transport loss alike. Every operation still in it fails with `error`.
2450
+ */
2451
+ failUnwritten(connection, error) {
2452
+ const queue = this.queues.get(connection);
2453
+ if (queue === void 0) return;
2454
+ this.queues.delete(connection);
2455
+ queue.failAll(error);
2456
+ }
2457
+ write(connection, frame, signal, expiry, onAccepted) {
2458
+ throwIfAborted(signal);
2459
+ const queue = this.queues.get(connection);
2460
+ if (queue === void 0) {
2461
+ throw connectorError("disconnected" /* Disconnected */, "Connector is not connected.");
2200
2462
  }
2463
+ let operation;
2464
+ let settled = false;
2465
+ const promise = new Promise((resolve, reject) => {
2466
+ const cleanup = () => signal == null ? void 0 : signal.removeEventListener("abort", onAbort);
2467
+ const onAbort = () => queue.cancel(
2468
+ operation,
2469
+ connectorError("disconnected" /* Disconnected */, "Operation canceled.")
2470
+ );
2471
+ operation = {
2472
+ frame,
2473
+ complete: () => {
2474
+ if (settled) return;
2475
+ settled = true;
2476
+ cleanup();
2477
+ resolve();
2478
+ },
2479
+ fail: (error) => {
2480
+ if (settled) return;
2481
+ settled = true;
2482
+ cleanup();
2483
+ reject(error);
2484
+ }
2485
+ };
2486
+ signal == null ? void 0 : signal.addEventListener("abort", onAbort, { once: true });
2487
+ onAccepted == null ? void 0 : onAccepted();
2488
+ expiry == null ? void 0 : expiry.then(void 0, (error) => queue.cancel(operation, error));
2489
+ queue.enqueue(operation);
2490
+ });
2491
+ return promise;
2201
2492
  }
2202
2493
  };
2203
- function invalidControl(message) {
2204
- return connectorError("frameDecodeFailed" /* FrameDecodeFailed */, message);
2205
- }
2494
+
2495
+ // packages/stream-connector/src/Runtime/Protocol/ZlinkSessionClosing.ts
2496
+ var ZLINK_SESSION_CLOSING = ZlinkStreamControlPacket.SessionClosing;
2206
2497
 
2207
2498
  // packages/stream-connector/src/Runtime/ZlinkStreamReceiveDispatcher.ts
2499
+ function closeReasonFor(error) {
2500
+ return error.code === "frameDecodeFailed" /* FrameDecodeFailed */ || error.code === "frameTooLarge" /* FrameTooLarge */ ? "ProtocolError" : "TransportError";
2501
+ }
2502
+ var ZlinkStreamConnectionEnd = class extends Error {
2503
+ constructor(error) {
2504
+ super(error.message);
2505
+ this.error = error;
2506
+ }
2507
+ };
2208
2508
  var ZlinkStreamReceiveDispatcher = class {
2209
2509
  constructor(protocol, pendingRequests, receivedMessages, frameSender, events, actors, serverClosing) {
2210
2510
  this.protocol = protocol;
@@ -2224,15 +2524,20 @@ var ZlinkStreamConnectorBundle = (() => {
2224
2524
  * the recheck the rest of a dead connection's batch lands on the new
2225
2525
  * connection's state, and the §10 arrival counts, which start at 0 when a
2226
2526
  * connection is established, take the stale frames on top.
2227
- * @param connectionForSend Resolves the connection a reply belongs on at the
2228
- * moment it is written. The captured `connection` is the one the batch was
2229
- * read from, which a reconnect may already have replaced.
2230
2527
  */
2231
- async readAndDispatch(connection, signal, isCurrent, connectionForSend) {
2528
+ async readAndDispatch(connection, signal, isCurrent) {
2232
2529
  if ((connection == null ? void 0 : connection.read) === void 0) {
2233
2530
  return { available: false, inbound: false };
2234
2531
  }
2235
- const frameBytes = await connection.read(signal);
2532
+ let frameBytes;
2533
+ try {
2534
+ frameBytes = await connection.read(signal);
2535
+ } catch (cause) {
2536
+ if ((signal == null ? void 0 : signal.aborted) === true) throw cause;
2537
+ throw new ZlinkStreamConnectionEnd(
2538
+ toStreamError(cause, "disconnected" /* Disconnected */, "Transport read failed.")
2539
+ );
2540
+ }
2236
2541
  if (isCurrent !== void 0 && !isCurrent()) {
2237
2542
  return { available: false, inbound: false };
2238
2543
  }
@@ -2243,87 +2548,96 @@ var ZlinkStreamConnectorBundle = (() => {
2243
2548
  try {
2244
2549
  frames = this.protocol.decodeFrames(frameBytes);
2245
2550
  } catch (cause) {
2246
- throw cause;
2551
+ throw new ZlinkStreamConnectionEnd(
2552
+ toStreamError(cause, "frameDecodeFailed" /* FrameDecodeFailed */, "Frame decode failed.")
2553
+ );
2247
2554
  }
2248
2555
  for (const frame of frames) {
2249
2556
  if (isCurrent !== void 0 && !isCurrent()) {
2250
2557
  break;
2251
2558
  }
2252
2559
  try {
2253
- await this.dispatch(connection, frame.header, frame.payload, signal, connectionForSend);
2560
+ await this.dispatch(connection, frame.header, frame.payload, signal);
2254
2561
  } catch (cause) {
2255
- if (frame.header.kind === 5 /* Control */ && frame.header.name === ZLINK_STREAM_HEARTBEAT_PING) {
2256
- throw cause;
2257
- }
2562
+ if (cause instanceof ZlinkStreamConnectionEnd) throw cause;
2258
2563
  const error = toStreamError(
2259
2564
  cause,
2260
2565
  "frameDecodeFailed" /* FrameDecodeFailed */,
2261
2566
  "Frame dispatch failed."
2262
2567
  );
2263
2568
  if (error.code === "frameDecodeFailed" /* FrameDecodeFailed */) {
2264
- throw cause;
2569
+ throw new ZlinkStreamConnectionEnd(error);
2265
2570
  }
2266
- await this.events.publishError(error, signal);
2571
+ this.events.publishError(error, signal);
2267
2572
  }
2268
2573
  }
2269
2574
  return { available: true, inbound: true };
2270
2575
  }
2271
- async dispatch(connection, header, payload, signal, connectionForSend) {
2576
+ /**
2577
+ * Spec stream-connector 32 §4.7 and §9: a decompressed payload over the
2578
+ * receive limit is `FrameTooLarge` and ends the connection as a protocol
2579
+ * error, like a wire payload over the limit. A payload that does not
2580
+ * decompress fails only its packet.
2581
+ */
2582
+ decodePayload(header, payload) {
2583
+ try {
2584
+ return this.protocol.decodePayload(header, payload);
2585
+ } catch (cause) {
2586
+ const error = toStreamError(
2587
+ cause,
2588
+ "decompressionFailed" /* DecompressionFailed */,
2589
+ "Decompression failed."
2590
+ );
2591
+ if (error.code === "frameTooLarge" /* FrameTooLarge */) {
2592
+ throw new ZlinkStreamConnectionEnd(error);
2593
+ }
2594
+ throw cause;
2595
+ }
2596
+ }
2597
+ async dispatch(connection, header, payload, signal) {
2272
2598
  const actor = header.actorSlot === void 0 ? void 0 : this.actors.resolve(header.actorSlot);
2273
2599
  if (header.kind === 3 /* Response */ && header.requestSeq !== void 0) {
2274
2600
  try {
2275
- if (!this.pendingRequests.resolve(
2601
+ this.pendingRequests.resolve(
2276
2602
  header.requestSeq,
2277
- {
2603
+ () => ({
2278
2604
  codec: header.codec,
2279
- payload: this.protocol.decodePayload(header, payload)
2280
- },
2605
+ payload: this.decodePayload(header, payload)
2606
+ }),
2281
2607
  header.metadata
2282
- )) {
2283
- await this.events.publishError(
2284
- {
2285
- code: "frameDecodeFailed" /* FrameDecodeFailed */,
2286
- message: `Response request sequence '${header.requestSeq}' has no pending request.`
2287
- },
2288
- signal
2289
- );
2290
- }
2608
+ );
2291
2609
  } catch (cause) {
2610
+ if (cause instanceof ZlinkStreamConnectionEnd) throw cause;
2292
2611
  const decodeError = toStreamError(
2293
2612
  cause,
2294
2613
  "decompressionFailed" /* DecompressionFailed */,
2295
2614
  "Decompression failed."
2296
2615
  );
2297
2616
  if (!this.pendingRequests.reject(header.requestSeq, decodeError)) {
2298
- await this.events.publishError(decodeError, signal);
2617
+ this.events.publishError(decodeError, signal);
2299
2618
  }
2300
2619
  }
2301
2620
  return;
2302
2621
  }
2303
- if (header.kind === 4 /* Error */ && header.requestSeq !== void 0) {
2622
+ if (header.kind === 4 /* Error */) {
2623
+ let error;
2304
2624
  try {
2305
- const remoteError = decodeRemoteError(this.protocol, header, payload);
2306
- if (!this.pendingRequests.reject(header.requestSeq, remoteError)) {
2307
- await this.events.publishError(remoteError, signal);
2308
- }
2625
+ error = decodeRemoteError(this.decodePayload(header, payload));
2309
2626
  } catch (cause) {
2310
- const decodeError = toStreamError(
2627
+ if (cause instanceof ZlinkStreamConnectionEnd) throw cause;
2628
+ error = toStreamError(
2311
2629
  cause,
2312
2630
  "frameDecodeFailed" /* FrameDecodeFailed */,
2313
2631
  "Remote error payload is invalid."
2314
2632
  );
2315
- if (!this.pendingRequests.reject(header.requestSeq, decodeError)) {
2316
- await this.events.publishError(decodeError, signal);
2317
- }
2318
2633
  }
2319
- return;
2320
- }
2321
- if (header.kind === 4 /* Error */) {
2322
- await this.events.publishError(decodeRemoteError(this.protocol, header, payload), signal);
2634
+ if (header.requestSeq === void 0 || !this.pendingRequests.reject(header.requestSeq, error)) {
2635
+ this.events.publishError(error, signal);
2636
+ }
2323
2637
  return;
2324
2638
  }
2325
2639
  if (header.kind === 5 /* Control */) {
2326
- await this.dispatchControl(connection, header, payload, signal, connectionForSend);
2640
+ await this.dispatchControl(connection, header, payload, signal);
2327
2641
  return;
2328
2642
  }
2329
2643
  if (header.kind === 1 /* Send */) {
@@ -2331,7 +2645,7 @@ var ZlinkStreamConnectorBundle = (() => {
2331
2645
  {
2332
2646
  name: header.name,
2333
2647
  metadata: header.metadata,
2334
- payload: { codec: header.codec, payload: this.protocol.decodePayload(header, payload) },
2648
+ payload: { codec: header.codec, payload: this.decodePayload(header, payload) },
2335
2649
  actorId: actor == null ? void 0 : actor.actorId,
2336
2650
  [zlinkStreamActorBinding]: actor
2337
2651
  },
@@ -2339,13 +2653,13 @@ var ZlinkStreamConnectorBundle = (() => {
2339
2653
  );
2340
2654
  }
2341
2655
  }
2342
- async dispatchControl(connection, header, payload, signal, connectionForSend) {
2343
- var _a, _b;
2656
+ async dispatchControl(connection, header, payload, signal) {
2657
+ var _a;
2344
2658
  if (this.actors.processControl(header.name, payload, signal)) {
2345
2659
  return;
2346
2660
  }
2347
2661
  if (header.name === ZLINK_SESSION_CLOSING) {
2348
- const closing = decodeSessionClosing(payload);
2662
+ const closing = decodeStreamWireSessionClosing(payload);
2349
2663
  await ((_a = this.serverClosing) == null ? void 0 : _a.call(this, closing.closeReason));
2350
2664
  return;
2351
2665
  }
@@ -2356,18 +2670,7 @@ var ZlinkStreamConnectorBundle = (() => {
2356
2670
  );
2357
2671
  }
2358
2672
  if (header.name === ZLINK_STREAM_HEARTBEAT_PING) {
2359
- try {
2360
- await this.frameSender.sendControl(
2361
- (_b = connectionForSend == null ? void 0 : connectionForSend()) != null ? _b : connection,
2362
- ZLINK_STREAM_HEARTBEAT_PONG,
2363
- signal
2364
- );
2365
- } catch (cause) {
2366
- throw connectorError(
2367
- "sendFailed" /* SendFailed */,
2368
- cause instanceof Error ? cause.message : "Heartbeat pong send failed."
2369
- );
2370
- }
2673
+ await this.frameSender.sendControl(connection, ZLINK_STREAM_HEARTBEAT_PONG);
2371
2674
  return;
2372
2675
  }
2373
2676
  if (header.name !== ZLINK_STREAM_HEARTBEAT_PONG) {
@@ -2375,8 +2678,7 @@ var ZlinkStreamConnectorBundle = (() => {
2375
2678
  }
2376
2679
  }
2377
2680
  };
2378
- function decodeRemoteError(protocol, header, payload) {
2379
- const decodedPayload = protocol.decodePayload(header, payload);
2681
+ function decodeRemoteError(decodedPayload) {
2380
2682
  let decoded;
2381
2683
  try {
2382
2684
  decoded = JSON.parse(utf8Decode2(decodedPayload));
@@ -2398,8 +2700,11 @@ var ZlinkStreamConnectorBundle = (() => {
2398
2700
  }
2399
2701
 
2400
2702
  // packages/stream-connector/src/Runtime/ZlinkStreamConnectorLifecycle.ts
2703
+ var RECONNECT_JITTER_FLOOR = 0.5;
2401
2704
  function randomizedDelay(baseDelayMs) {
2402
- return Math.round(baseDelayMs * (0.5 + Math.random() * 0.5));
2705
+ return Math.round(
2706
+ baseDelayMs * (RECONNECT_JITTER_FLOOR + Math.random() * (1 - RECONNECT_JITTER_FLOOR))
2707
+ );
2403
2708
  }
2404
2709
  var ZlinkStreamConnectorLifecycle = class {
2405
2710
  constructor(options, pendingRequests, frameSender, receiveDispatcher, receivedMessages, actors, events) {
@@ -2422,11 +2727,11 @@ var ZlinkStreamConnectorBundle = (() => {
2422
2727
  __publicField(this, "lastInboundAt", 0);
2423
2728
  __publicField(this, "closeTask");
2424
2729
  __publicField(this, "connectTask");
2730
+ __publicField(this, "connectAbort");
2425
2731
  __publicField(this, "disconnectTask");
2426
2732
  __publicField(this, "closeRequested", false);
2427
2733
  __publicField(this, "disconnectedPublished", false);
2428
2734
  __publicField(this, "closeReasonValue");
2429
- __publicField(this, "lateConnectCleanupError");
2430
2735
  }
2431
2736
  get isConnected() {
2432
2737
  return this.currentState === "connected" /* Connected */;
@@ -2455,18 +2760,22 @@ var ZlinkStreamConnectorBundle = (() => {
2455
2760
  });
2456
2761
  return await this.connectTask;
2457
2762
  }
2763
+ /**
2764
+ * Spec stream-connector 32 §7: close does not wait for a connect attempt or a
2765
+ * reconnect delay to run its course. The attempts listen to one controller
2766
+ * the lifecycle owns; close aborts it, and the caller's signal is forwarded
2767
+ * to it.
2768
+ */
2458
2769
  async connectOnce(signal) {
2459
- var _a;
2460
- await this.setState("connecting" /* Connecting */, void 0, signal);
2770
+ const attempts = new AbortController();
2771
+ const forwardAbort = () => attempts.abort();
2772
+ signal == null ? void 0 : signal.addEventListener("abort", forwardAbort, { once: true });
2773
+ this.connectAbort = attempts;
2774
+ this.setState("connecting" /* Connecting */, void 0, signal);
2461
2775
  try {
2462
- const connection = await this.connectWithReconnect(signal);
2776
+ const connection = await this.connectWithReconnect(attempts.signal);
2463
2777
  if (this.closeRequested) {
2464
- try {
2465
- await connection.close(signal);
2466
- } catch (error) {
2467
- this.lateConnectCleanupError = error;
2468
- throw error;
2469
- }
2778
+ await this.closeTransport(connection, void 0, signal);
2470
2779
  throw connectorError(
2471
2780
  "disconnected" /* Disconnected */,
2472
2781
  "Connector closed while connecting."
@@ -2474,41 +2783,62 @@ var ZlinkStreamConnectorBundle = (() => {
2474
2783
  }
2475
2784
  this.currentConnection = connection;
2476
2785
  this.connectionGeneration += 1;
2786
+ const generation = this.connectionGeneration;
2787
+ this.frameSender.open(connection, (error) => {
2788
+ void this.disconnectForTransportFailure(error, connection, generation);
2789
+ });
2477
2790
  this.disconnectedPublished = false;
2478
2791
  this.receivedMessages.resetForNewConnection();
2479
2792
  this.lastInboundAt = Date.now();
2480
- await this.setState("connected" /* Connected */, void 0, signal);
2793
+ this.setState("connected" /* Connected */, void 0, signal);
2481
2794
  this.startHeartbeat();
2482
2795
  this.startReceiveLoop();
2483
2796
  } catch (cause) {
2484
2797
  if (this.closeRequested) {
2485
2798
  const message = cause instanceof Error ? cause.message : "Connector closed while connecting.";
2486
- const error2 = toStreamError(cause, "disconnected" /* Disconnected */, message);
2487
- throw new ZlinkStreamException(error2);
2799
+ throw connectorError("disconnected" /* Disconnected */, message, cause);
2800
+ }
2801
+ if ((signal == null ? void 0 : signal.aborted) === true) {
2802
+ this.setState("disconnected" /* Disconnected */, void 0, signal);
2803
+ throwIfAborted(signal);
2488
2804
  }
2489
2805
  const error = toStreamError(cause, "connectTimeout" /* ConnectTimeout */, "Connect failed.");
2490
- (_a = this.closeReasonValue) != null ? _a : this.closeReasonValue = "TransportError";
2491
- void this.setState("disconnected" /* Disconnected */, error, signal);
2492
- this.publishDisconnectedWithoutWaiting(signal);
2806
+ this.closeReasonValue = "TransportError";
2807
+ this.setState("disconnected" /* Disconnected */, error, signal);
2808
+ this.disconnectedPublished = false;
2809
+ this.publishDisconnected(signal);
2493
2810
  throw new ZlinkStreamException(error);
2811
+ } finally {
2812
+ signal == null ? void 0 : signal.removeEventListener("abort", forwardAbort);
2813
+ this.connectAbort = void 0;
2494
2814
  }
2495
2815
  }
2816
+ /**
2817
+ * Spec stream-connector 32 §7: a `close` called outside the registered
2818
+ * handlers and callbacks returns once the close work has ended. One called
2819
+ * from inside them returns right after starting it; the result goes to the
2820
+ * outside caller, so a callback never waits for the close of the path that
2821
+ * is running it.
2822
+ */
2496
2823
  async close(signal) {
2497
- this.closeReasonValue = "ClientClose";
2498
- this.closeRequested = true;
2499
- if (this.closeTask !== void 0) {
2500
- return await this.closeTask;
2824
+ var _a;
2825
+ if (this.currentConnection !== void 0 || this.closeReasonValue === void 0) {
2826
+ this.closeReasonValue = "ClientClose";
2501
2827
  }
2502
- if (this.currentState === "closed" /* Closed */) {
2828
+ this.closeRequested = true;
2829
+ if (this.closeTask === void 0 && this.currentState === "closed" /* Closed */) {
2503
2830
  return;
2504
2831
  }
2505
- this.closeTask = this.closeOnce(signal).finally(() => {
2832
+ const closeTask = (_a = this.closeTask) != null ? _a : this.closeTask = this.closeOnce(signal).finally(() => {
2506
2833
  this.closeTask = void 0;
2507
2834
  });
2508
- return await this.closeTask;
2835
+ if (this.receivedMessages.dispatching) {
2836
+ void closeTask.catch(() => void 0);
2837
+ return;
2838
+ }
2839
+ return await closeTask;
2509
2840
  }
2510
2841
  async serverClosing(reason) {
2511
- this.closeReasonValue = reason;
2512
2842
  const error = {
2513
2843
  code: "disconnected" /* Disconnected */,
2514
2844
  message: `Server closed the session: ${reason}.`
@@ -2516,42 +2846,19 @@ var ZlinkStreamConnectorBundle = (() => {
2516
2846
  await this.disconnectForTransportFailure(
2517
2847
  error,
2518
2848
  this.currentConnection,
2519
- this.connectionGeneration
2849
+ this.connectionGeneration,
2850
+ reason
2520
2851
  );
2521
2852
  }
2522
2853
  async closeOnce(signal) {
2523
- var _a, _b;
2524
- await ((_a = this.connectTask) == null ? void 0 : _a.catch(() => void 0));
2525
- await ((_b = this.disconnectTask) == null ? void 0 : _b.catch(() => void 0));
2526
- const connection = this.currentConnection;
2527
- this.stopHeartbeat();
2528
- this.stopReceiveLoop();
2529
- this.currentConnection = void 0;
2530
- const errors = [];
2531
- if (this.lateConnectCleanupError !== void 0) {
2532
- errors.push(this.lateConnectCleanupError);
2533
- this.lateConnectCleanupError = void 0;
2534
- }
2535
- try {
2536
- await this.frameSender.drain(signal);
2537
- } catch (error) {
2538
- errors.push(error);
2539
- }
2540
- try {
2541
- await (connection == null ? void 0 : connection.close(signal));
2542
- } catch (error) {
2543
- errors.push(error);
2544
- }
2545
- this.pendingRequests.failAll({
2546
- code: "disconnected" /* Disconnected */,
2547
- message: "Connector closed."
2548
- });
2549
- this.receivedMessages.connectionEnded();
2550
- this.actors.closeAll(signal);
2551
- this.queueState("closed" /* Closed */, void 0, signal);
2552
- this.queueDisconnected(signal);
2553
- if (errors.length === 1) throw errors[0];
2554
- if (errors.length > 1) throw new AggregateError(errors, "Stream connector close failed.");
2854
+ var _a, _b, _c;
2855
+ (_a = this.connectAbort) == null ? void 0 : _a.abort();
2856
+ await ((_b = this.connectTask) == null ? void 0 : _b.catch(() => void 0));
2857
+ await ((_c = this.disconnectTask) == null ? void 0 : _c.catch(() => void 0));
2858
+ await this.tearDownConnection(
2859
+ { code: "disconnected" /* Disconnected */, message: "Connector closed." },
2860
+ signal
2861
+ );
2555
2862
  }
2556
2863
  /**
2557
2864
  * Spec stream-connector 32 §7: `dispatch` runs the callbacks the receive loop
@@ -2567,7 +2874,7 @@ var ZlinkStreamConnectorBundle = (() => {
2567
2874
  if (this.options.dispatchMode !== "immediate" /* Immediate */) {
2568
2875
  await this.settleReceiveLoop();
2569
2876
  }
2570
- await this.receivedMessages.pump();
2877
+ this.receivedMessages.pump();
2571
2878
  }
2572
2879
  connectionForSend() {
2573
2880
  if (this.currentConnection === void 0 || this.currentState !== "connected" /* Connected */) {
@@ -2580,8 +2887,7 @@ var ZlinkStreamConnectorBundle = (() => {
2580
2887
  const result = await this.receiveDispatcher.readAndDispatch(
2581
2888
  connection,
2582
2889
  signal,
2583
- () => this.isCurrentConnection(connection, generation),
2584
- () => this.connectionForSend()
2890
+ () => this.isCurrentConnection(connection, generation)
2585
2891
  );
2586
2892
  if (result.inbound && this.isCurrentConnection(connection, generation)) {
2587
2893
  this.lastInboundAt = Date.now();
@@ -2590,7 +2896,10 @@ var ZlinkStreamConnectorBundle = (() => {
2590
2896
  }
2591
2897
  async connectWithReconnect(signal) {
2592
2898
  let attempt = 0;
2593
- let delayMs = this.options.reconnect.initialDelayMs;
2899
+ let delayMs = Math.min(
2900
+ this.options.reconnect.initialDelayMs,
2901
+ this.options.reconnect.maxDelayMs
2902
+ );
2594
2903
  let lastError;
2595
2904
  const maxAttempts = this.options.reconnect.enabled ? this.options.reconnect.maxAttempts : 1;
2596
2905
  const unlimited = maxAttempts === null;
@@ -2600,10 +2909,10 @@ var ZlinkStreamConnectorBundle = (() => {
2600
2909
  return await this.options.transportFactory.connect(this.options, signal);
2601
2910
  } catch (cause) {
2602
2911
  lastError = toStreamError(cause, "connectTimeout" /* ConnectTimeout */, "Connect failed.");
2603
- if (!this.options.reconnect.enabled || !unlimited && attempt >= maxAttempts) {
2912
+ if (this.closeRequested || !this.options.reconnect.enabled || !unlimited && attempt >= maxAttempts) {
2604
2913
  break;
2605
2914
  }
2606
- await this.setState("reconnecting" /* Reconnecting */, lastError, signal);
2915
+ this.setState("reconnecting" /* Reconnecting */, lastError, signal);
2607
2916
  await delay(randomizedDelay(delayMs), signal);
2608
2917
  delayMs = Math.min(
2609
2918
  this.options.reconnect.maxDelayMs,
@@ -2673,12 +2982,8 @@ var ZlinkStreamConnectorBundle = (() => {
2673
2982
  }
2674
2983
  } catch (cause) {
2675
2984
  if (signal.aborted) return;
2676
- const error = toStreamError(
2677
- cause,
2678
- "frameDecodeFailed" /* FrameDecodeFailed */,
2679
- "Receive loop failed."
2680
- );
2681
- await this.disconnectForTransportFailure(error, connection, generation);
2985
+ if (!(cause instanceof ZlinkStreamConnectionEnd)) throw cause;
2986
+ await this.disconnectForTransportFailure(cause.error, connection, generation);
2682
2987
  } finally {
2683
2988
  this.receiveLoopSleeping = false;
2684
2989
  this.releaseReceiveLoopSettled();
@@ -2735,57 +3040,97 @@ var ZlinkStreamConnectorBundle = (() => {
2735
3040
  return;
2736
3041
  }
2737
3042
  if (Date.now() - this.lastInboundAt > this.options.heartbeat.timeoutMs) {
2738
- this.closeReasonValue = "HeartbeatTimeout";
2739
3043
  const error = { code: "disconnected" /* Disconnected */, message: "Heartbeat timed out." };
2740
3044
  await this.disconnectForTransportFailure(
2741
3045
  error,
2742
3046
  this.currentConnection,
2743
- this.connectionGeneration
3047
+ this.connectionGeneration,
3048
+ "HeartbeatTimeout"
2744
3049
  );
2745
3050
  return;
2746
3051
  }
2747
- const connection = this.currentConnection;
2748
- const generation = this.connectionGeneration;
2749
- try {
2750
- await this.frameSender.sendControl(this.connectionForSend(), ZLINK_STREAM_HEARTBEAT_PING);
2751
- } catch (cause) {
2752
- const error = toStreamError(cause, "sendFailed" /* SendFailed */, "Heartbeat send failed.");
2753
- await this.disconnectForTransportFailure(error, connection, generation);
2754
- }
3052
+ await this.frameSender.sendControl(this.connectionForSend(), ZLINK_STREAM_HEARTBEAT_PING);
2755
3053
  }
2756
- async disconnectForTransportFailure(error, origin, generation) {
2757
- var _a;
2758
- (_a = this.closeReasonValue) != null ? _a : this.closeReasonValue = "TransportError";
3054
+ /**
3055
+ * @param reason Given only where the reason is not read from `error`: a
3056
+ * server `session-closing` and the heartbeat timeout. Every other ending
3057
+ * takes it from {@link closeReasonFor}.
3058
+ */
3059
+ async disconnectForTransportFailure(error, origin, generation, reason = closeReasonFor(error)) {
2759
3060
  if (this.closeRequested || this.currentState === "closed" /* Closed */) {
2760
3061
  return;
2761
3062
  }
2762
3063
  if (origin !== void 0 && !this.isCurrentConnection(origin, generation)) {
2763
3064
  return;
2764
3065
  }
3066
+ this.closeReasonValue = reason;
2765
3067
  if (this.disconnectTask !== void 0) {
2766
3068
  return await this.disconnectTask;
2767
3069
  }
2768
- this.disconnectTask = this.tearDownConnection(error).finally(() => {
2769
- this.disconnectTask = void 0;
3070
+ let resolve;
3071
+ let reject;
3072
+ const pending = new Promise((complete, fail) => {
3073
+ resolve = complete;
3074
+ reject = fail;
2770
3075
  });
2771
- await this.disconnectTask;
2772
- await this.announceDisconnect(error);
3076
+ const task = pending.finally(() => {
3077
+ if (this.disconnectTask === task) this.disconnectTask = void 0;
3078
+ });
3079
+ this.disconnectTask = task;
3080
+ void this.tearDownConnection(error).then(resolve, reject);
3081
+ await task;
3082
+ this.announceDisconnect();
2773
3083
  }
2774
3084
  isCurrentConnection(connection, generation) {
2775
3085
  return !this.closeRequested && this.currentConnection === connection && this.connectionGeneration === generation;
2776
3086
  }
2777
- /** Transport teardown only — no application callback runs from here. */
2778
- async tearDownConnection(error) {
3087
+ /**
3088
+ * Ends the current connection, for close and for transport loss alike. No
3089
+ * application callback runs before terminal operations settle. Spec stream-connector 32 §7 and §9:
3090
+ * every operation the ending connection fails (the frames it has not
3091
+ * written, the one it is writing and the pending requests) fails with
3092
+ * `Disconnected`, whatever ended it; the cause stays in the close reason.
3093
+ * The transport is closed without waiting for the frames.
3094
+ */
3095
+ async tearDownConnection(error, signal) {
2779
3096
  this.stopHeartbeat();
2780
3097
  this.stopReceiveLoop();
2781
3098
  const connection = this.currentConnection;
2782
3099
  this.currentConnection = void 0;
2783
- this.pendingRequests.failAll(error);
3100
+ const disconnected = { code: "disconnected" /* Disconnected */, message: error.message };
3101
+ if (connection !== void 0) {
3102
+ this.frameSender.failUnwritten(
3103
+ connection,
3104
+ connectorError(disconnected.code, disconnected.message)
3105
+ );
3106
+ }
3107
+ this.pendingRequests.failAll(disconnected);
2784
3108
  this.receivedMessages.connectionEnded();
2785
- this.actors.closeAll();
3109
+ this.actors.closeAll(signal);
3110
+ await this.closeTransport(connection, error, signal);
3111
+ }
3112
+ async closeTransport(connection, error, signal) {
2786
3113
  try {
2787
- await (connection == null ? void 0 : connection.close());
2788
- } catch {
3114
+ try {
3115
+ await (connection == null ? void 0 : connection.close(signal));
3116
+ } finally {
3117
+ this.setState(
3118
+ this.closeRequested ? "closed" /* Closed */ : "disconnected" /* Disconnected */,
3119
+ this.closeRequested ? void 0 : error,
3120
+ signal
3121
+ );
3122
+ }
3123
+ } catch (cause) {
3124
+ this.events.publishError(
3125
+ {
3126
+ code: "disconnected" /* Disconnected */,
3127
+ message: `Transport close failed: ${cause instanceof Error ? cause.message : String(cause)}`,
3128
+ cause
3129
+ },
3130
+ signal
3131
+ );
3132
+ } finally {
3133
+ this.publishDisconnected(signal);
2789
3134
  }
2790
3135
  }
2791
3136
  /**
@@ -2796,10 +3141,7 @@ var ZlinkStreamConnectorBundle = (() => {
2796
3141
  * handler that is slow — or whose promise never settles at all — must not
2797
3142
  * cost the connector the attempt.
2798
3143
  */
2799
- async announceDisconnect(error) {
2800
- if (this.closeRequested) return;
2801
- this.queueState("disconnected" /* Disconnected */, error);
2802
- this.queueDisconnected();
3144
+ announceDisconnect() {
2803
3145
  if (this.shouldReconnect()) {
2804
3146
  queueMicrotask(() => {
2805
3147
  void this.connect().catch(() => void 0);
@@ -2809,112 +3151,127 @@ var ZlinkStreamConnectorBundle = (() => {
2809
3151
  shouldReconnect() {
2810
3152
  return this.options.reconnect.enabled && !this.closeRequested;
2811
3153
  }
2812
- // Synchronous test-and-set, taken before any await, so the single disconnect
2813
- // notification the spec promises is claimed by exactly one caller even when
2814
- // the publishing itself is deferred.
2815
- claimDisconnectedPublish() {
2816
- if (this.disconnectedPublished) return false;
2817
- this.disconnectedPublished = true;
2818
- return true;
2819
- }
2820
- async publishDisconnectedOnce(signal) {
2821
- if (!this.claimDisconnectedPublish()) return;
2822
- await this.events.publishDisconnected(signal);
2823
- }
2824
3154
  /**
2825
- * Spec stream-connector 32 §7: the connector runs the registered handler, it
2826
- * does not wait for it to finish. `close` returns once its own work is done —
2827
- * the drain, the transport close, the pending requests — having run the
2828
- * disconnect handler but without looking at whether that handler has ended.
2829
- *
2830
- * Starting the publish without awaiting it still runs every handler right
2831
- * here: an `async` function body runs synchronously up to its first `await`,
2832
- * and `publishDisconnected` reaches each handler before that point. So the
2833
- * handler has run by the time `close` returns, which is what the spec asks
2834
- * for, while a handler that calls `close` no longer waits for the very
2835
- * `closeTask` it is running inside. Java and C++ hand the handler to a queue
2836
- * and return the same way.
2837
- *
2838
- * `claimDisconnectedPublish` is taken by the same call and before any await,
2839
- * so deferring the completion never turns the one notification into two.
2840
- *
2841
- * Nothing awaits the promise, so a rejection would reach the process as an
2842
- * unhandled rejection and kill it. Handler failures are already contained
2843
- * where they were before this call stopped waiting — the `Promise.allSettled`
2844
- * in `publishDisconnected` — and this `catch` covers what is left rather than
2845
- * reporting the same failure a second time on the error surface.
3155
+ * Spec stream-connector 32 §6 and §7: one disconnect notification per
3156
+ * lifecycle event, handed to the dispatch queue. The connector does not wait
3157
+ * for the handler; `Manual` runs it when the application pumps dispatch.
3158
+ * The flag is tested and set synchronously, so concurrent callers for the
3159
+ * same event claim it once.
2846
3160
  */
2847
- publishDisconnectedWithoutWaiting(signal) {
2848
- void this.publishDisconnectedOnce(signal).catch(() => void 0);
2849
- }
2850
- queueDisconnected(signal) {
2851
- if (!this.claimDisconnectedPublish()) return;
2852
- this.receivedMessages.enqueueCallback(() => {
2853
- void this.events.publishDisconnected(signal).catch(() => void 0);
2854
- });
2855
- }
2856
- queueState(current, error, signal) {
2857
- const change = this.transitionState(current, error);
2858
- if (change === void 0) return;
2859
- this.receivedMessages.enqueueCallback(() => {
2860
- void this.publishStateChange(change, signal).catch(() => void 0);
2861
- });
2862
- }
2863
- async setState(current, error, signal) {
2864
- const change = this.transitionState(current, error);
2865
- if (change === void 0) return;
2866
- await this.publishStateChange(change, signal);
3161
+ publishDisconnected(signal) {
3162
+ if (this.disconnectedPublished) return;
3163
+ this.disconnectedPublished = true;
3164
+ this.events.publishDisconnected(signal);
2867
3165
  }
2868
- transitionState(current, error) {
3166
+ setState(current, error, signal) {
2869
3167
  const previous = this.currentState;
2870
3168
  this.currentState = current;
2871
- if (previous === current && error === void 0) {
2872
- return void 0;
2873
- }
2874
- return { previous, current, error };
2875
- }
2876
- async publishStateChange(change, signal) {
2877
- await this.events.publishStateChanged(change, signal);
2878
- if (change.error !== void 0) await this.events.publishError(change.error, signal);
3169
+ if (previous === current && error === void 0) return;
3170
+ this.events.publishStateChanged({ previous, current, error }, signal);
3171
+ if (error !== void 0) this.events.publishError(error, signal);
2879
3172
  }
2880
3173
  };
2881
3174
 
2882
3175
  // packages/stream-connector/src/Runtime/ZlinkStreamConnectorEvents.ts
2883
3176
  var ZlinkStreamConnectorEvents = class {
2884
- constructor() {
3177
+ /**
3178
+ * @param enqueueCallback Queues a callback that calls the number of handlers
3179
+ * `callbacks` reports for the handlers registered at that moment.
3180
+ */
3181
+ constructor(enqueueCallback) {
3182
+ this.enqueueCallback = enqueueCallback;
2885
3183
  __publicField(this, "errorHandlers", /* @__PURE__ */ new Set());
2886
3184
  __publicField(this, "disconnectedHandlers", /* @__PURE__ */ new Set());
2887
3185
  __publicField(this, "stateHandlers", /* @__PURE__ */ new Set());
2888
3186
  }
2889
3187
  onError(handler) {
2890
- this.errorHandlers.add(handler);
2891
- return subscription(() => this.errorHandlers.delete(handler));
3188
+ return registerHandler(this.errorHandlers, handler);
2892
3189
  }
2893
3190
  onDisconnected(handler) {
2894
- this.disconnectedHandlers.add(handler);
2895
- return subscription(() => this.disconnectedHandlers.delete(handler));
3191
+ return registerHandler(this.disconnectedHandlers, handler);
2896
3192
  }
2897
3193
  onStateChanged(handler) {
2898
- this.stateHandlers.add(handler);
2899
- return subscription(() => this.stateHandlers.delete(handler));
3194
+ return registerHandler(this.stateHandlers, handler);
3195
+ }
3196
+ publishError(error, signal) {
3197
+ this.publish(this.errorHandlers, (handler) => handler(error, signal), signal);
2900
3198
  }
2901
- async publishError(error, signal) {
2902
- await this.publish(
2903
- Array.from(this.errorHandlers).map((handler) => () => handler(error, signal))
3199
+ publishDisconnected(signal) {
3200
+ this.publish(this.disconnectedHandlers, (handler) => handler(signal), signal);
3201
+ }
3202
+ publishStateChanged(change, signal) {
3203
+ this.publish(this.stateHandlers, (handler) => handler(change, signal), signal);
3204
+ }
3205
+ /**
3206
+ * Spec stream-connector 32 §7: the connector runs a registered callback and
3207
+ * does not wait for it to finish. A thrown or rejected failure reaches the
3208
+ * error handlers as `UserCallbackFailed`.
3209
+ */
3210
+ runUserCallback(run, failureMessage, signal) {
3211
+ this.invoke(
3212
+ run,
3213
+ (cause) => this.publishError(
3214
+ { code: "userCallbackFailed" /* UserCallbackFailed */, message: failureMessage, cause },
3215
+ signal
3216
+ )
2904
3217
  );
2905
3218
  }
2906
- async publishDisconnected(signal) {
2907
- await this.publish(
2908
- Array.from(this.disconnectedHandlers).map((handler) => () => handler(signal))
3219
+ publish(handlers, invoke, signal) {
3220
+ this.enqueueCallback(
3221
+ () => {
3222
+ for (const handler of currentRegistrations(handlers)) {
3223
+ const report = (cause) => this.reportFailure(
3224
+ cause,
3225
+ signal,
3226
+ handlers === this.errorHandlers ? handler : void 0
3227
+ );
3228
+ this.invoke(() => invoke(handler.handler), report);
3229
+ }
3230
+ },
3231
+ () => handlers.size
2909
3232
  );
2910
3233
  }
2911
- async publishStateChanged(change, signal) {
2912
- await this.publish(
2913
- Array.from(this.stateHandlers).map((handler) => () => handler(change, signal))
3234
+ reportFailure(cause, signal, failedHandler) {
3235
+ const error = {
3236
+ code: "userCallbackFailed" /* UserCallbackFailed */,
3237
+ message: "Connector event handler failed.",
3238
+ cause
3239
+ };
3240
+ if (failedHandler === void 0) {
3241
+ this.publishError(error, signal);
3242
+ return;
3243
+ }
3244
+ this.reportToRemaining(error, signal, /* @__PURE__ */ new Set([failedHandler]));
3245
+ }
3246
+ reportToRemaining(error, signal, attempted) {
3247
+ const remaining = Array.from(this.errorHandlers).filter(
3248
+ (candidate) => !attempted.has(candidate)
3249
+ );
3250
+ if (remaining.length === 0) return;
3251
+ const nextAttempted = new Set(attempted);
3252
+ for (const handler of remaining) nextAttempted.add(handler);
3253
+ this.enqueueCallback(
3254
+ () => {
3255
+ for (const handler of currentRegistrations(this.errorHandlers, remaining)) {
3256
+ const report = (cause) => this.reportToRemaining({ ...error, cause }, signal, nextAttempted);
3257
+ const callback = handler.handler;
3258
+ this.invoke(() => callback(error, signal), report);
3259
+ }
3260
+ },
3261
+ () => {
3262
+ let count = 0;
3263
+ const registrations = currentRegistrations(this.errorHandlers, remaining);
3264
+ while (registrations.next().done !== true) count += 1;
3265
+ return count;
3266
+ }
2914
3267
  );
2915
3268
  }
2916
- async publish(handlers) {
2917
- await Promise.allSettled(handlers.map(async (handler) => handler()));
3269
+ invoke(run, report) {
3270
+ try {
3271
+ Promise.resolve(run()).catch(report);
3272
+ } catch (cause) {
3273
+ report(cause);
3274
+ }
2918
3275
  }
2919
3276
  };
2920
3277
 
@@ -2985,11 +3342,7 @@ var ZlinkStreamConnectorBundle = (() => {
2985
3342
  if (this.closed || this.socket.readyState !== 1) {
2986
3343
  throw connectorError("disconnected" /* Disconnected */, "Remote stream is not connected.");
2987
3344
  }
2988
- try {
2989
- this.socket.send(frame);
2990
- } catch (cause) {
2991
- throw connectorError("sendFailed" /* SendFailed */, "Send failed.", cause);
2992
- }
3345
+ this.socket.send(frame);
2993
3346
  }
2994
3347
  async read(signal) {
2995
3348
  throwIfAborted(signal);
@@ -3007,18 +3360,19 @@ var ZlinkStreamConnectorBundle = (() => {
3007
3360
  await this.waitForMessage(signal);
3008
3361
  }
3009
3362
  }
3363
+ /**
3364
+ * Spec stream-connector 32 §7: closing does not wait for the peer to read or
3365
+ * answer. `WebSocket.close` sends the close frame after the data already
3366
+ * handed to `send`, so a frame whose write completed is not torn.
3367
+ */
3010
3368
  async close(signal) {
3011
3369
  throwIfAborted(signal);
3370
+ this.removeListeners();
3012
3371
  if (!this.closed) {
3013
3372
  this.closed = true;
3014
3373
  this.socket.close();
3015
- this.wakeReader();
3016
- }
3017
- try {
3018
- await waitForClose(this.socket, signal);
3019
- } finally {
3020
- this.removeListeners();
3021
3374
  }
3375
+ this.wakeReader();
3022
3376
  }
3023
3377
  waitForMessage(signal) {
3024
3378
  if (this.readWaiter !== void 0) {
@@ -3057,28 +3411,13 @@ var ZlinkStreamConnectorBundle = (() => {
3057
3411
  const message = this.messages[this.messageHead];
3058
3412
  this.messages[this.messageHead] = void 0;
3059
3413
  this.messageHead += 1;
3060
- if (this.messageHead >= 1024 && this.messageHead * 2 >= this.messages.length) {
3414
+ if (shouldCompactBackingArray(this.messageHead, this.messages.length)) {
3061
3415
  this.messages.splice(0, this.messageHead);
3062
3416
  this.messageHead = 0;
3063
3417
  }
3064
3418
  return message;
3065
3419
  }
3066
3420
  };
3067
- function waitForClose(socket, signal) {
3068
- if (socket.readyState === 3) return Promise.resolve();
3069
- return new Promise((resolve, reject) => {
3070
- const onClose = () => finish();
3071
- const onAbort = () => finish(connectorError("disconnected" /* Disconnected */, "Close canceled."));
3072
- const finish = (error) => {
3073
- socket.removeEventListener("close", onClose);
3074
- signal == null ? void 0 : signal.removeEventListener("abort", onAbort);
3075
- if (error === void 0) resolve();
3076
- else reject(error);
3077
- };
3078
- socket.addEventListener("close", onClose, { once: true });
3079
- signal == null ? void 0 : signal.addEventListener("abort", onAbort, { once: true });
3080
- });
3081
- }
3082
3421
  async function waitForOpen(socket, connectTimeoutMs, signal) {
3083
3422
  throwIfAborted(signal);
3084
3423
  await new Promise((resolve, reject) => {
@@ -3087,8 +3426,8 @@ var ZlinkStreamConnectorBundle = (() => {
3087
3426
  connectTimeoutMs
3088
3427
  );
3089
3428
  const onOpen = () => finish();
3090
- const onClose = () => finish(connectorError("connectTimeout" /* ConnectTimeout */, "Connect closed before opening."));
3091
- const onError = () => finish(connectorError("connectTimeout" /* ConnectTimeout */, "Connect failed."));
3429
+ const onClose = () => finish(connectorError("disconnected" /* Disconnected */, "Connect closed before opening."));
3430
+ const onError = () => finish(connectorError("disconnected" /* Disconnected */, "Connect failed."));
3092
3431
  const onAbort = () => finish(connectorError("disconnected" /* Disconnected */, "Connect canceled."));
3093
3432
  const finish = (error) => {
3094
3433
  clearTimeout(timeout);
@@ -3127,7 +3466,9 @@ var ZlinkStreamConnectorBundle = (() => {
3127
3466
  constructor(options) {
3128
3467
  __publicField(this, "receivedMessages");
3129
3468
  __publicField(this, "lifecycle");
3130
- __publicField(this, "events", new ZlinkStreamConnectorEvents());
3469
+ __publicField(this, "events", new ZlinkStreamConnectorEvents(
3470
+ (callback, callbacks) => this.receivedMessages.enqueueCallback(callback, callbacks)
3471
+ ));
3131
3472
  __publicField(this, "correlationCounter", 0n);
3132
3473
  __publicField(this, "pendingRequests", new ZlinkStreamPendingRequests());
3133
3474
  __publicField(this, "frameSender");
@@ -3173,7 +3514,7 @@ var ZlinkStreamConnectorBundle = (() => {
3173
3514
  return this.lifecycle.state;
3174
3515
  }
3175
3516
  get pendingDispatchCount() {
3176
- return this.pendingRequests.count;
3517
+ return this.receivedMessages.pendingCallbacks;
3177
3518
  }
3178
3519
  get actors() {
3179
3520
  return this.boundActors.snapshot;
@@ -3208,12 +3549,10 @@ var ZlinkStreamConnectorBundle = (() => {
3208
3549
  return this.events.onStateChanged(handler);
3209
3550
  }
3210
3551
  onRequestSending(handler) {
3211
- this.requestSendingHandlers.add(handler);
3212
- return subscription(() => this.requestSendingHandlers.delete(handler));
3552
+ return registerHandler(this.requestSendingHandlers, handler);
3213
3553
  }
3214
3554
  onReplyReceived(handler) {
3215
- this.replyReceivedHandlers.add(handler);
3216
- return subscription(() => this.replyReceivedHandlers.delete(handler));
3555
+ return registerHandler(this.replyReceivedHandlers, handler);
3217
3556
  }
3218
3557
  async connect(signal) {
3219
3558
  await this.lifecycle.connect(signal);
@@ -3230,7 +3569,12 @@ var ZlinkStreamConnectorBundle = (() => {
3230
3569
  }
3231
3570
  request(payload, messageType) {
3232
3571
  const encoded = this.encodePayload(payload, messageType);
3233
- return new ZlinkStreamRequestBuilder(this, this.resolveNameOrDefault(encoded), encoded);
3572
+ return new ZlinkStreamRequestBuilder(
3573
+ this,
3574
+ this.resolveNameOrDefault(encoded),
3575
+ encoded,
3576
+ (callback) => this.receivedMessages.enqueueCallback(callback)
3577
+ );
3234
3578
  }
3235
3579
  on(nameOrType, handler, messageType) {
3236
3580
  const encodedHandler = (message, signal) => handler(
@@ -3263,29 +3607,25 @@ var ZlinkStreamConnectorBundle = (() => {
3263
3607
  this,
3264
3608
  this.resolveNameOrDefault(encoded),
3265
3609
  encoded,
3610
+ (callback) => this.receivedMessages.enqueueCallback(callback),
3266
3611
  actor.slot,
3267
3612
  () => actor.ensureBound()
3268
3613
  );
3269
3614
  }
3270
3615
  onActorMessage(actor, nameOrType, handler, messageType) {
3271
- const encodedHandler = (message, signal) => {
3272
- if (message[zlinkStreamActorBinding] !== actor) {
3273
- return;
3274
- }
3275
- return handler(
3276
- {
3277
- name: message.name,
3278
- metadata: message.metadata,
3279
- payload: this.decodePayload(
3280
- message.payload,
3281
- messageType != null ? messageType : typeof nameOrType === "function" ? nameOrType : void 0
3282
- ),
3283
- actorId: message.actorId
3284
- },
3285
- signal
3286
- );
3287
- };
3288
- return this.receivedMessages.on(this.observedName(nameOrType), encodedHandler);
3616
+ const encodedHandler = (message, signal) => handler(
3617
+ {
3618
+ name: message.name,
3619
+ metadata: message.metadata,
3620
+ payload: this.decodePayload(
3621
+ message.payload,
3622
+ messageType != null ? messageType : typeof nameOrType === "function" ? nameOrType : void 0
3623
+ ),
3624
+ actorId: message.actorId
3625
+ },
3626
+ signal
3627
+ );
3628
+ return this.receivedMessages.on(this.observedName(nameOrType), encodedHandler, actor);
3289
3629
  }
3290
3630
  waitFor(nameOrType) {
3291
3631
  return new ZlinkStreamWaitBuilder(this, this.observedName(nameOrType));
@@ -3410,7 +3750,7 @@ var ZlinkStreamConnectorBundle = (() => {
3410
3750
  }
3411
3751
  return payload;
3412
3752
  }
3413
- async sendEncoded(kind, name, payload, metadata, compress, requestSeq, signal, correlationId, actorSlot) {
3753
+ async sendEncoded(kind, name, payload, metadata, compress, requestSeq, signal, correlationId, actorSlot, expiry, onAccepted) {
3414
3754
  await this.frameSender.send(
3415
3755
  this.lifecycle.connectionForSend(),
3416
3756
  kind,
@@ -3421,7 +3761,9 @@ var ZlinkStreamConnectorBundle = (() => {
3421
3761
  requestSeq,
3422
3762
  signal,
3423
3763
  correlationId,
3424
- actorSlot
3764
+ actorSlot,
3765
+ expiry,
3766
+ onAccepted
3425
3767
  );
3426
3768
  }
3427
3769
  /**
@@ -3444,37 +3786,48 @@ var ZlinkStreamConnectorBundle = (() => {
3444
3786
  }
3445
3787
  };
3446
3788
  let pending;
3789
+ let stopCancellation;
3447
3790
  try {
3448
3791
  throwIfAborted(signal);
3449
- for (const handler of Array.from(this.requestSendingHandlers)) {
3792
+ for (const { handler } of currentRegistrations(this.requestSendingHandlers)) {
3450
3793
  try {
3451
3794
  handler(sendingContext);
3452
3795
  } catch (cause) {
3453
- queueMicrotask(() => {
3454
- void this.events.publishError(
3455
- toStreamError(
3456
- cause,
3457
- "userCallbackFailed" /* UserCallbackFailed */,
3458
- "Request sending hook failed."
3459
- ),
3460
- signal
3461
- );
3462
- });
3796
+ this.events.publishError(
3797
+ {
3798
+ code: "userCallbackFailed" /* UserCallbackFailed */,
3799
+ message: "Request sending hook failed.",
3800
+ cause
3801
+ },
3802
+ signal
3803
+ );
3463
3804
  }
3464
3805
  }
3465
3806
  pending = this.pendingRequests.create(name, timeoutMs);
3466
- await this.sendEncoded(
3807
+ const accepted = pending;
3808
+ const write = this.sendEncoded(
3467
3809
  2 /* Request */,
3468
3810
  name,
3469
3811
  payload,
3470
3812
  requestMetadata,
3471
3813
  compress,
3472
- pending.requestSeq,
3814
+ accepted.requestSeq,
3473
3815
  signal,
3474
3816
  this.nextCorrelationId(),
3475
- actorSlot
3817
+ actorSlot,
3818
+ accepted.promise,
3819
+ accepted.startTimeout
3476
3820
  );
3477
- const reply = await pending.promise;
3821
+ const canceled = new Promise((_, reject) => {
3822
+ const onAbort = () => reject(connectorError("disconnected" /* Disconnected */, "Operation canceled."));
3823
+ signal == null ? void 0 : signal.addEventListener("abort", onAbort, { once: true });
3824
+ stopCancellation = () => signal == null ? void 0 : signal.removeEventListener("abort", onAbort);
3825
+ });
3826
+ const reply = await Promise.race([
3827
+ write.then(() => accepted.promise),
3828
+ accepted.promise,
3829
+ canceled
3830
+ ]);
3478
3831
  this.publishReplyReceived(
3479
3832
  {
3480
3833
  requestPacketName: name,
@@ -3488,6 +3841,7 @@ var ZlinkStreamConnectorBundle = (() => {
3488
3841
  return reply.payload;
3489
3842
  } catch (error) {
3490
3843
  if (pending !== void 0) this.pendingRequests.cancel(pending.requestSeq);
3844
+ if ((signal == null ? void 0 : signal.aborted) === true) throw error;
3491
3845
  this.publishReplyReceived(
3492
3846
  {
3493
3847
  requestPacketName: name,
@@ -3499,26 +3853,24 @@ var ZlinkStreamConnectorBundle = (() => {
3499
3853
  signal
3500
3854
  );
3501
3855
  throw error;
3856
+ } finally {
3857
+ stopCancellation == null ? void 0 : stopCancellation();
3502
3858
  }
3503
3859
  }
3504
3860
  publishReplyReceived(context, signal) {
3505
3861
  if (this.replyReceivedHandlers.size === 0) return;
3506
- this.receivedMessages.enqueueCallback(async () => {
3507
- for (const handler of Array.from(this.replyReceivedHandlers)) {
3508
- try {
3509
- await handler(context, signal);
3510
- } catch (cause) {
3511
- await this.events.publishError(
3512
- toStreamError(
3513
- cause,
3514
- "userCallbackFailed" /* UserCallbackFailed */,
3515
- "Reply received hook failed."
3516
- ),
3862
+ this.receivedMessages.enqueueCallback(
3863
+ () => {
3864
+ for (const { handler } of currentRegistrations(this.replyReceivedHandlers)) {
3865
+ this.events.runUserCallback(
3866
+ () => handler(context, signal),
3867
+ "Reply received hook failed.",
3517
3868
  signal
3518
3869
  );
3519
3870
  }
3520
- }
3521
- });
3871
+ },
3872
+ () => this.replyReceivedHandlers.size
3873
+ );
3522
3874
  }
3523
3875
  resolveNameOrDefault(payload) {
3524
3876
  if (payload.messageType === void 0) {