@zlink-systems/stream-connector 0.26.0 → 0.28.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,8 @@
1
1
  // packages/stream-wire/src/lz4-pickle.ts
2
+ var LZ4_MIN_MATCH_LENGTH = 4;
3
+ var LZ4_MATCH_OFFSET_BYTES = 2;
4
+ var LZ4_EXTENDED_LENGTH_NIBBLE = 15;
5
+ var LZ4_EXTENDED_LENGTH_BYTE = 255;
2
6
  var defaultMaxDecompressedPayloadSize = 64 * 1024;
3
7
  function lz4PickleUncompressed(payload) {
4
8
  if (payload.length === 0) {
@@ -74,15 +78,15 @@ function decodeLz4Block(source, resultLength) {
74
78
  if (sourceOffset >= source.length) {
75
79
  break;
76
80
  }
77
- if (source.length - sourceOffset < 2) {
81
+ if (source.length - sourceOffset < LZ4_MATCH_OFFSET_BYTES) {
78
82
  throw new Error("LZ4 match offset is incomplete.");
79
83
  }
80
84
  const matchOffset = source[sourceOffset] | source[sourceOffset + 1] << 8;
81
- sourceOffset += 2;
85
+ sourceOffset += LZ4_MATCH_OFFSET_BYTES;
82
86
  if (matchOffset === 0 || matchOffset > targetOffset) {
83
87
  throw new Error("LZ4 match offset is invalid.");
84
88
  }
85
- const matchLength = readLz4Length(source, token & 15, () => sourceOffset++) + 4;
89
+ const matchLength = readLz4Length(source, token & 15, () => sourceOffset++) + LZ4_MIN_MATCH_LENGTH;
86
90
  if (target.length - targetOffset < matchLength) {
87
91
  throw new Error("LZ4 match run exceeds output size.");
88
92
  }
@@ -98,7 +102,7 @@ function decodeLz4Block(source, resultLength) {
98
102
  }
99
103
  function readLz4Length(source, nibble, nextOffset) {
100
104
  let length = nibble;
101
- if (length !== 15) {
105
+ if (length !== LZ4_EXTENDED_LENGTH_NIBBLE) {
102
106
  return length;
103
107
  }
104
108
  for (; ; ) {
@@ -108,7 +112,7 @@ function readLz4Length(source, nibble, nextOffset) {
108
112
  }
109
113
  const value = source[offset];
110
114
  length += value;
111
- if (value !== 255) {
115
+ if (value !== LZ4_EXTENDED_LENGTH_BYTE) {
112
116
  return length;
113
117
  }
114
118
  }
@@ -122,54 +126,200 @@ var ZlinkStreamCodec = /* @__PURE__ */ ((ZlinkStreamCodec2) => {
122
126
  ZlinkStreamCodec2[ZlinkStreamCodec2["Protobuf"] = 3] = "Protobuf";
123
127
  return ZlinkStreamCodec2;
124
128
  })(ZlinkStreamCodec || {});
129
+ var ZlinkStreamMessageKind = /* @__PURE__ */ ((ZlinkStreamMessageKind2) => {
130
+ ZlinkStreamMessageKind2[ZlinkStreamMessageKind2["Send"] = 1] = "Send";
131
+ ZlinkStreamMessageKind2[ZlinkStreamMessageKind2["Request"] = 2] = "Request";
132
+ ZlinkStreamMessageKind2[ZlinkStreamMessageKind2["Response"] = 3] = "Response";
133
+ ZlinkStreamMessageKind2[ZlinkStreamMessageKind2["Error"] = 4] = "Error";
134
+ ZlinkStreamMessageKind2[ZlinkStreamMessageKind2["Control"] = 5] = "Control";
135
+ return ZlinkStreamMessageKind2;
136
+ })(ZlinkStreamMessageKind || {});
137
+ var ZlinkStreamHeaderFlags = /* @__PURE__ */ ((ZlinkStreamHeaderFlags2) => {
138
+ ZlinkStreamHeaderFlags2[ZlinkStreamHeaderFlags2["None"] = 0] = "None";
139
+ ZlinkStreamHeaderFlags2[ZlinkStreamHeaderFlags2["HasRequestSeq"] = 1] = "HasRequestSeq";
140
+ ZlinkStreamHeaderFlags2[ZlinkStreamHeaderFlags2["HasMetadata"] = 2] = "HasMetadata";
141
+ ZlinkStreamHeaderFlags2[ZlinkStreamHeaderFlags2["PayloadCompressed"] = 4] = "PayloadCompressed";
142
+ ZlinkStreamHeaderFlags2[ZlinkStreamHeaderFlags2["HasCorrelationId"] = 8] = "HasCorrelationId";
143
+ ZlinkStreamHeaderFlags2[ZlinkStreamHeaderFlags2["HasFlowId"] = 16] = "HasFlowId";
144
+ ZlinkStreamHeaderFlags2[ZlinkStreamHeaderFlags2["HasActorSlot"] = 32] = "HasActorSlot";
145
+ return ZlinkStreamHeaderFlags2;
146
+ })(ZlinkStreamHeaderFlags || {});
147
+ var ZlinkStreamCloseReasonCode = /* @__PURE__ */ ((ZlinkStreamCloseReasonCode2) => {
148
+ ZlinkStreamCloseReasonCode2[ZlinkStreamCloseReasonCode2["ClientClose"] = 1] = "ClientClose";
149
+ ZlinkStreamCloseReasonCode2[ZlinkStreamCloseReasonCode2["IdleTimeout"] = 2] = "IdleTimeout";
150
+ ZlinkStreamCloseReasonCode2[ZlinkStreamCloseReasonCode2["HeartbeatTimeout"] = 3] = "HeartbeatTimeout";
151
+ ZlinkStreamCloseReasonCode2[ZlinkStreamCloseReasonCode2["ServerDrain"] = 4] = "ServerDrain";
152
+ ZlinkStreamCloseReasonCode2[ZlinkStreamCloseReasonCode2["ProtocolError"] = 5] = "ProtocolError";
153
+ ZlinkStreamCloseReasonCode2[ZlinkStreamCloseReasonCode2["TransportError"] = 6] = "TransportError";
154
+ return ZlinkStreamCloseReasonCode2;
155
+ })(ZlinkStreamCloseReasonCode || {});
156
+ var unicodeWhiteSpaceOnly = /^\p{White_Space}*$/u;
157
+ var validMessageKinds = new Set(
158
+ Object.values(ZlinkStreamMessageKind).filter((value) => typeof value === "number")
159
+ );
160
+ var validCodecs = new Set(
161
+ Object.values(ZlinkStreamCodec).filter((value) => typeof value === "number")
162
+ );
163
+ function isStreamWireMessageKind(value) {
164
+ return validMessageKinds.has(value);
165
+ }
166
+ function isStreamWireCodec(value) {
167
+ return validCodecs.has(value);
168
+ }
169
+ var UTF8_TWO_BYTE_MIN = 128;
170
+ var UTF8_THREE_BYTE_MIN = 2048;
171
+ var UTF16_HIGH_SURROGATE_MIN = 55296;
172
+ var UTF16_HIGH_SURROGATE_MAX = 56319;
173
+ var UTF16_LOW_SURROGATE_MIN = 56320;
174
+ var UTF16_LOW_SURROGATE_MAX = 57343;
175
+ var UINT8_MAX = 255;
176
+ var UINT16_MAX = 65535;
177
+ var UINT16_BYTES = 2;
178
+ var UINT32_BYTES = 4;
179
+ var UINT64_BYTES = 8;
180
+ var UINT64_MAX = 0xffffffffffffffffn;
181
+ var UINT32_MAX = 4294967295;
182
+ var ZLINK_STREAM_FRAME_PREFIX_BYTES = UINT16_BYTES + UINT32_BYTES;
183
+ var ZLINK_STREAM_MAX_PACKET_NAME_BYTES = UINT8_MAX;
184
+ var ZLINK_STREAM_MAX_METADATA_BYTES = 1024;
185
+ var FLOW_ID_BYTES = 36;
186
+ var FLOW_FIELDS_BYTES = FLOW_ID_BYTES + 1;
187
+ var HEADER_MIN_BYTES = 5;
188
+ var HEADER_FLAG_MASK = 1 /* HasRequestSeq */ | 2 /* HasMetadata */ | 4 /* PayloadCompressed */ | 8 /* HasCorrelationId */ | 16 /* HasFlowId */ | 32 /* HasActorSlot */;
189
+ var CONTROL_PAYLOAD_VERSION = 1;
190
+ var ACTOR_SLOT_OFFSET = 1;
191
+ var ACTOR_ID_LENGTH_OFFSET = ACTOR_SLOT_OFFSET + UINT16_BYTES;
192
+ var ACTOR_BOUND_PREFIX_BYTES = ACTOR_ID_LENGTH_OFFSET + 1;
193
+ var ACTOR_UNBOUND_BYTES = ACTOR_SLOT_OFFSET + UINT16_BYTES;
194
+ var CLOSING_DIAGNOSTIC_LENGTH_OFFSET = 2;
195
+ var CLOSING_PREFIX_BYTES = CLOSING_DIAGNOSTIC_LENGTH_OFFSET + UINT16_BYTES;
196
+ var MAX_CLOSING_DIAGNOSTIC_BYTES = 512;
197
+ function decodeStreamWireActorBoundPayload(payload) {
198
+ if (payload.length < ACTOR_BOUND_PREFIX_BYTES + 1 || payload[0] !== CONTROL_PAYLOAD_VERSION) {
199
+ throw new Error("Actor bound payload is invalid.");
200
+ }
201
+ const slot = readUInt16BE(payload, ACTOR_SLOT_OFFSET);
202
+ const idLength = payload[ACTOR_ID_LENGTH_OFFSET];
203
+ if (slot === 0 || idLength === 0 || payload.length !== ACTOR_BOUND_PREFIX_BYTES + idLength) {
204
+ throw new Error("Actor bound payload is invalid.");
205
+ }
206
+ try {
207
+ return { slot, actorId: decodeControlText(payload.subarray(ACTOR_BOUND_PREFIX_BYTES)) };
208
+ } catch (cause) {
209
+ throw new Error("Actor id is not valid UTF-8.", { cause });
210
+ }
211
+ }
212
+ function decodeStreamWireActorUnboundPayload(payload) {
213
+ if (payload.length !== ACTOR_UNBOUND_BYTES || payload[0] !== CONTROL_PAYLOAD_VERSION) {
214
+ throw new Error("Actor unbound payload is invalid.");
215
+ }
216
+ return readUInt16BE(payload, ACTOR_SLOT_OFFSET);
217
+ }
218
+ function decodeStreamWireSessionClosing(payload) {
219
+ if (payload.length < CLOSING_PREFIX_BYTES || payload[0] !== CONTROL_PAYLOAD_VERSION) {
220
+ throw new Error("Unsupported session-closing version.");
221
+ }
222
+ const closeReason = ZlinkStreamCloseReasonCode[payload[1]];
223
+ if (closeReason === void 0) throw new Error("Unknown session-closing reason.");
224
+ const length = readUInt16BE(payload, CLOSING_DIAGNOSTIC_LENGTH_OFFSET);
225
+ if (length > MAX_CLOSING_DIAGNOSTIC_BYTES || payload.length !== CLOSING_PREFIX_BYTES + length) {
226
+ throw new Error("Invalid session-closing diagnostic length.");
227
+ }
228
+ const diagnostic = length === 0 ? void 0 : decodeControlText(payload.subarray(CLOSING_PREFIX_BYTES));
229
+ return { closeReason, diagnostic };
230
+ }
231
+ function decodeControlText(value) {
232
+ return new TextDecoder("utf-8", { fatal: true }).decode(value);
233
+ }
234
+ function splitStreamWireFrames(chunk) {
235
+ if (chunk.length === 0) throw new Error("Stream frame prefix is incomplete.");
236
+ const frames = [];
237
+ let offset = 0;
238
+ while (offset < chunk.length) {
239
+ const remaining = chunk.length - offset;
240
+ if (remaining < ZLINK_STREAM_FRAME_PREFIX_BYTES) {
241
+ throw new Error("Stream frame prefix is incomplete.");
242
+ }
243
+ const headerLength = readUInt16BE(chunk, offset);
244
+ const payloadLength = readUInt32BE(chunk, offset + UINT16_BYTES);
245
+ const frameLength = ZLINK_STREAM_FRAME_PREFIX_BYTES + headerLength + payloadLength;
246
+ if (frameLength > remaining) throw new Error("Frame length does not match prefix.");
247
+ frames.push(chunk.subarray(offset, offset + frameLength));
248
+ offset += frameLength;
249
+ }
250
+ return frames;
251
+ }
252
+ var ZLINK_STREAM_RESERVED_PACKET_NAME_PREFIX = "$zlink.";
253
+ var ZlinkStreamControlPacket = Object.freeze({
254
+ HeartbeatPing: `${ZLINK_STREAM_RESERVED_PACKET_NAME_PREFIX}heartbeat.ping`,
255
+ HeartbeatPong: `${ZLINK_STREAM_RESERVED_PACKET_NAME_PREFIX}heartbeat.pong`,
256
+ ActorBound: `${ZLINK_STREAM_RESERVED_PACKET_NAME_PREFIX}actor.bound`,
257
+ ActorUnbound: `${ZLINK_STREAM_RESERVED_PACKET_NAME_PREFIX}actor.unbound`,
258
+ SessionClosing: "session-closing"
259
+ });
260
+ var ZlinkStreamContentType = Object.freeze({
261
+ Raw: "application/octet-stream",
262
+ Json: "application/json",
263
+ MessagePack: "application/x-msgpack",
264
+ Protobuf: "application/x-protobuf"
265
+ });
266
+ var contentTypesByCodec = /* @__PURE__ */ new Map([
267
+ [0 /* Raw */, ZlinkStreamContentType.Raw],
268
+ [1 /* Json */, ZlinkStreamContentType.Json],
269
+ [2 /* MessagePack */, ZlinkStreamContentType.MessagePack],
270
+ [3 /* Protobuf */, ZlinkStreamContentType.Protobuf]
271
+ ]);
272
+ var codecsByContentType = new Map(
273
+ Array.from(contentTypesByCodec, ([codec, contentType]) => [contentType, codec])
274
+ );
125
275
  var defaultHeaderFlags = {
126
- hasRequestSeq: 1,
127
- hasMetadata: 2,
128
- hasCorrelationId: 8,
129
- hasFlowId: 16,
130
- hasActorSlot: 32
276
+ hasRequestSeq: 1 /* HasRequestSeq */,
277
+ hasMetadata: 2 /* HasMetadata */,
278
+ hasCorrelationId: 8 /* HasCorrelationId */,
279
+ hasFlowId: 16 /* HasFlowId */,
280
+ hasActorSlot: 32 /* HasActorSlot */
131
281
  };
132
282
  var ZLINK_STREAM_FORMAT_MARKER = 242;
133
- var ZLINK_STREAM_RESPONSE_KIND = 3;
134
- var ZLINK_STREAM_ERROR_KIND = 4;
135
283
  function encodeStreamWireFrame(header, payload) {
136
- if (header.length > 65535) {
284
+ if (header.length > UINT16_MAX) {
137
285
  throw new Error("Stream header is too large.");
138
286
  }
139
- if (payload.length > 4294967295) {
287
+ if (payload.length > UINT32_MAX) {
140
288
  throw new Error("Stream payload is too large.");
141
289
  }
142
- const frame = new Uint8Array(6 + header.length + payload.length);
290
+ const frame = new Uint8Array(ZLINK_STREAM_FRAME_PREFIX_BYTES + header.length + payload.length);
143
291
  writeUInt16BE(frame, 0, header.length);
144
- writeUInt32BE(frame, 2, payload.length);
145
- frame.set(header, 6);
146
- frame.set(payload, 6 + header.length);
292
+ writeUInt32BE(frame, UINT16_BYTES, payload.length);
293
+ frame.set(header, ZLINK_STREAM_FRAME_PREFIX_BYTES);
294
+ frame.set(payload, ZLINK_STREAM_FRAME_PREFIX_BYTES + header.length);
147
295
  return frame;
148
296
  }
149
297
  function decodeStreamWireFrame(frame) {
150
- if (frame.length < 6) {
298
+ if (frame.length < ZLINK_STREAM_FRAME_PREFIX_BYTES) {
151
299
  throw new Error("Stream frame prefix is incomplete.");
152
300
  }
153
301
  const headerLength = readUInt16BE(frame, 0);
154
- const payloadLength = readUInt32BE(frame, 2);
155
- if (frame.length !== 6 + headerLength + payloadLength) {
302
+ const payloadLength = readUInt32BE(frame, UINT16_BYTES);
303
+ if (frame.length !== ZLINK_STREAM_FRAME_PREFIX_BYTES + headerLength + payloadLength) {
156
304
  throw new Error("Stream frame length does not match prefix.");
157
305
  }
158
306
  return {
159
- header: frame.slice(6, 6 + headerLength),
160
- payload: frame.slice(6 + headerLength)
307
+ header: frame.slice(
308
+ ZLINK_STREAM_FRAME_PREFIX_BYTES,
309
+ ZLINK_STREAM_FRAME_PREFIX_BYTES + headerLength
310
+ ),
311
+ payload: frame.slice(ZLINK_STREAM_FRAME_PREFIX_BYTES + headerLength)
161
312
  };
162
313
  }
163
314
  function encodeStreamWireHeader(header, flagOverrides) {
164
315
  const flags = flagOverrides ?? defaultHeaderFlags;
165
316
  const reply = isReplyKind(header.kind);
166
317
  const packetName = reply ? "" : header.name;
167
- if (!reply) validateStreamWirePacketName(packetName);
168
- const nameBytes = utf8Encode(packetName);
318
+ const nameBytes = reply ? new Uint8Array() : validateStreamWirePacketName(packetName);
169
319
  const hasRequestSeq = header.requestSeq !== void 0;
170
320
  const hasMetadata = header.metadata.size > 0;
171
321
  const correlationBytes = header.correlationId !== void 0 && header.correlationId.length > 0 ? utf8Encode(header.correlationId) : void 0;
172
- if (correlationBytes !== void 0 && correlationBytes.length > 255) {
322
+ if (correlationBytes !== void 0 && correlationBytes.length > UINT8_MAX) {
173
323
  throw new Error("Stream correlation id is too large.");
174
324
  }
175
325
  const hasCorrelation = correlationBytes !== void 0;
@@ -182,7 +332,7 @@ function encodeStreamWireHeader(header, flagOverrides) {
182
332
  if (header.flowOrigin !== void 0 && ![1, 2, 3, 4].includes(header.flowOrigin)) {
183
333
  throw new Error("Stream flow origin is invalid.");
184
334
  }
185
- if (header.actorSlot !== void 0 && (!Number.isInteger(header.actorSlot) || header.actorSlot < 1 || header.actorSlot > 65535)) {
335
+ if (header.actorSlot !== void 0 && (!Number.isInteger(header.actorSlot) || header.actorSlot < 1 || header.actorSlot > UINT16_MAX)) {
186
336
  throw new Error("Stream actor slot is invalid.");
187
337
  }
188
338
  let headerFlags = header.flags;
@@ -192,7 +342,7 @@ function encodeStreamWireHeader(header, flagOverrides) {
192
342
  headerFlags = hasFlow ? headerFlags | flags.hasFlowId : headerFlags & ~flags.hasFlowId;
193
343
  headerFlags = hasActorSlot ? headerFlags | flags.hasActorSlot : headerFlags & ~flags.hasActorSlot;
194
344
  const metadataBytes = hasMetadata ? encodeStreamWireMetadata(header.metadata) : new Uint8Array();
195
- 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);
345
+ 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);
196
346
  const buffer = new Uint8Array(size);
197
347
  let offset = 0;
198
348
  buffer[offset++] = ZLINK_STREAM_FORMAT_MARKER;
@@ -204,14 +354,14 @@ function encodeStreamWireHeader(header, flagOverrides) {
204
354
  throw new Error("Request sequence must not be zero.");
205
355
  }
206
356
  writeBigUInt64BE(buffer, offset, header.requestSeq);
207
- offset += 8;
357
+ offset += UINT64_BYTES;
208
358
  }
209
359
  buffer[offset++] = nameBytes.length;
210
360
  buffer.set(nameBytes, offset);
211
361
  offset += nameBytes.length;
212
362
  if (hasMetadata) {
213
363
  writeUInt16BE(buffer, offset, metadataBytes.length);
214
- offset += 2;
364
+ offset += UINT16_BYTES;
215
365
  buffer.set(metadataBytes, offset);
216
366
  offset += metadataBytes.length;
217
367
  }
@@ -222,7 +372,7 @@ function encodeStreamWireHeader(header, flagOverrides) {
222
372
  }
223
373
  if (hasFlow) {
224
374
  buffer.set(asciiEncode(header.flowId), offset);
225
- offset += 36;
375
+ offset += FLOW_ID_BYTES;
226
376
  buffer[offset++] = header.flowOrigin;
227
377
  }
228
378
  if (hasActorSlot) {
@@ -233,7 +383,7 @@ function encodeStreamWireHeader(header, flagOverrides) {
233
383
  function decodeStreamWireHeader(header, flagOverrides, includeFlow = true) {
234
384
  const flags = flagOverrides ?? defaultHeaderFlags;
235
385
  let offset = 0;
236
- if (header.length < 5) {
386
+ if (header.length < HEADER_MIN_BYTES) {
237
387
  throw new Error("Stream header is incomplete.");
238
388
  }
239
389
  if (header[offset++] !== ZLINK_STREAM_FORMAT_MARKER) {
@@ -247,29 +397,28 @@ function decodeStreamWireHeader(header, flagOverrides, includeFlow = true) {
247
397
  const hasCorrelation = (headerFlags & flags.hasCorrelationId) !== 0;
248
398
  const hasFlow = (headerFlags & flags.hasFlowId) !== 0;
249
399
  const hasActorSlot = (headerFlags & flags.hasActorSlot) !== 0;
250
- if ((headerFlags & ~63) !== 0) {
400
+ if ((headerFlags & ~HEADER_FLAG_MASK) !== 0) {
251
401
  throw new Error("Unknown mandatory stream header flag.");
252
402
  }
253
403
  let requestSeq;
254
404
  if (hasRequestSeq) {
255
- if (header.length - offset < 8) {
405
+ if (header.length - offset < UINT64_BYTES) {
256
406
  throw new Error("Stream request sequence is incomplete.");
257
407
  }
258
408
  requestSeq = readBigUInt64BE(header, offset);
259
409
  if (requestSeq === 0n) {
260
410
  throw new Error("Request sequence must not be zero.");
261
411
  }
262
- offset += 8;
412
+ offset += UINT64_BYTES;
263
413
  }
264
414
  if (header.length - offset < 1) {
265
415
  throw new Error("Stream packet name length is missing.");
266
416
  }
267
417
  const nameLength = header[offset++];
268
- if (!isReplyKind(kind) && nameLength === 0 || header.length - offset < nameLength) {
418
+ if ((isReplyKind(kind) ? nameLength !== 0 : nameLength === 0) || header.length - offset < nameLength) {
269
419
  throw new Error("Stream packet name is invalid.");
270
420
  }
271
- const decodedName = utf8Decode(header.subarray(offset, offset + nameLength));
272
- const name = isReplyKind(kind) ? "" : decodedName;
421
+ const name = utf8Decode(header.subarray(offset, offset + nameLength));
273
422
  offset += nameLength;
274
423
  const decodedMetadata = hasMetadata ? decodeStreamWireHeaderMetadata(header, offset) : { metadata: /* @__PURE__ */ new Map(), offset };
275
424
  offset = decodedMetadata.offset;
@@ -288,14 +437,14 @@ function decodeStreamWireHeader(header, flagOverrides, includeFlow = true) {
288
437
  let flowId;
289
438
  let flowOrigin;
290
439
  if (hasFlow) {
291
- if (header.length - offset < 37) {
440
+ if (header.length - offset < FLOW_FIELDS_BYTES) {
292
441
  throw new Error("Stream flow fields are incomplete.");
293
442
  }
294
443
  if (includeFlow) {
295
- flowId = asciiDecode(header.subarray(offset, offset + 36));
444
+ flowId = asciiDecode(header.subarray(offset, offset + FLOW_ID_BYTES));
296
445
  validateFlowId(flowId);
297
446
  }
298
- offset += 36;
447
+ offset += FLOW_ID_BYTES;
299
448
  const decodedFlowOrigin = header[offset++];
300
449
  if (includeFlow && ![1, 2, 3, 4].includes(decodedFlowOrigin)) {
301
450
  throw new Error("Stream flow origin is invalid.");
@@ -304,14 +453,14 @@ function decodeStreamWireHeader(header, flagOverrides, includeFlow = true) {
304
453
  }
305
454
  let actorSlot;
306
455
  if (hasActorSlot) {
307
- if (header.length - offset < 2) {
456
+ if (header.length - offset < UINT16_BYTES) {
308
457
  throw new Error("Stream actor slot is incomplete.");
309
458
  }
310
459
  actorSlot = readUInt16BE(header, offset);
311
460
  if (actorSlot === 0) {
312
461
  throw new Error("Stream actor slot must not be zero.");
313
462
  }
314
- offset += 2;
463
+ offset += UINT16_BYTES;
315
464
  }
316
465
  if (offset !== header.length) {
317
466
  throw new Error("Stream header has trailing bytes.");
@@ -341,44 +490,41 @@ function asciiDecode(value) {
341
490
  if (value.some((byte) => byte > 127)) throw new Error("Stream flow id must be ASCII.");
342
491
  return String.fromCharCode(...value);
343
492
  }
344
- function encodeStreamWireMetadata(metadata) {
345
- if (metadata.size > 255) {
493
+ function streamWireMetadataSize(metadata) {
494
+ if (metadata.size > UINT8_MAX) {
346
495
  throw new Error("Metadata entry count must not exceed 255.");
347
496
  }
348
497
  let size = 1;
349
- const encoded = [...metadata].map(([key, value]) => {
350
- const keyBytes = utf8Encode(key);
351
- const valueBytes = utf8Encode(value);
352
- if (keyBytes.length === 0 || keyBytes.length > 255) {
498
+ for (const [key, value] of metadata) {
499
+ const keySize = utf8Size(key);
500
+ const valueSize = utf8Size(value);
501
+ if (keySize === 0 || keySize > UINT8_MAX) {
353
502
  throw new Error("Metadata key length is invalid.");
354
503
  }
355
- if (valueBytes.length > 65535) {
504
+ if (valueSize > UINT16_MAX) {
356
505
  throw new Error("Metadata value is too large.");
357
506
  }
358
- size += 1 + keyBytes.length + 2 + valueBytes.length;
359
- return { keyBytes, valueBytes };
360
- });
361
- const buffer = new Uint8Array(size);
507
+ size += 1 + keySize + UINT16_BYTES + valueSize;
508
+ }
509
+ return size;
510
+ }
511
+ function encodeStreamWireMetadata(metadata) {
512
+ const buffer = new Uint8Array(streamWireMetadataSize(metadata));
362
513
  let offset = 0;
363
514
  buffer[offset++] = metadata.size;
364
- for (const { keyBytes, valueBytes } of encoded) {
515
+ for (const [key, value] of metadata) {
516
+ const keyBytes = utf8Encode(key);
517
+ const valueBytes = utf8Encode(value);
365
518
  buffer[offset++] = keyBytes.length;
366
519
  buffer.set(keyBytes, offset);
367
520
  offset += keyBytes.length;
368
521
  writeUInt16BE(buffer, offset, valueBytes.length);
369
- offset += 2;
522
+ offset += UINT16_BYTES;
370
523
  buffer.set(valueBytes, offset);
371
524
  offset += valueBytes.length;
372
525
  }
373
526
  return buffer;
374
527
  }
375
- function decodeStreamWireMetadata(metadata) {
376
- const decoded = decodeStreamWireMetadataAt(metadata, 0, metadata.length);
377
- if (decoded.offset !== metadata.length) {
378
- throw new Error("Stream metadata payload has trailing bytes.");
379
- }
380
- return decoded.metadata;
381
- }
382
528
  function lz4PickleUncompressed2(payload) {
383
529
  return lz4PickleUncompressed(payload);
384
530
  }
@@ -395,11 +541,11 @@ function utf8Decode(value) {
395
541
  return new TextDecoder().decode(value);
396
542
  }
397
543
  function decodeStreamWireHeaderMetadata(header, offset) {
398
- if (header.length - offset < 2) {
544
+ if (header.length - offset < UINT16_BYTES) {
399
545
  throw new Error("Stream metadata section is incomplete.");
400
546
  }
401
547
  const metadataLength = readUInt16BE(header, offset);
402
- offset += 2;
548
+ offset += UINT16_BYTES;
403
549
  if (header.length - offset < metadataLength) {
404
550
  throw new Error("Stream metadata payload is incomplete.");
405
551
  }
@@ -425,7 +571,7 @@ function decodeStreamWireMetadataAt(source, offset, end) {
425
571
  throw new Error("Stream metadata value length is missing.");
426
572
  }
427
573
  const valueLength = readUInt16BE(source, offset);
428
- offset += 2;
574
+ offset += UINT16_BYTES;
429
575
  if (end - offset < valueLength) {
430
576
  throw new Error("Stream metadata value is incomplete.");
431
577
  }
@@ -442,16 +588,17 @@ function decodeStreamWireMetadataAt(source, offset, end) {
442
588
  }
443
589
  function validateStreamWirePacketName(name) {
444
590
  const nameBytes = utf8Encode(name);
445
- if (name.trim().length === 0 || nameBytes.length > 255) {
591
+ if (unicodeWhiteSpaceOnly.test(name) || nameBytes.length > ZLINK_STREAM_MAX_PACKET_NAME_BYTES) {
446
592
  throw new Error("Stream packet name is invalid.");
447
593
  }
594
+ return nameBytes;
448
595
  }
449
596
  function isReplyKind(kind) {
450
- return kind === ZLINK_STREAM_RESPONSE_KIND || kind === ZLINK_STREAM_ERROR_KIND;
597
+ return kind === 3 /* Response */ || kind === 4 /* Error */;
451
598
  }
452
599
  function writeUInt16BE(buffer, offset, value) {
453
- buffer[offset] = value >>> 8 & 255;
454
- buffer[offset + 1] = value & 255;
600
+ buffer[offset] = value >>> 8 & UINT8_MAX;
601
+ buffer[offset + 1] = value & UINT8_MAX;
455
602
  }
456
603
  function readUInt16BE(buffer, offset) {
457
604
  return buffer[offset] << 8 | buffer[offset + 1];
@@ -460,10 +607,10 @@ function readUInt32BE(buffer, offset) {
460
607
  return buffer[offset] * 16777216 + (buffer[offset + 1] << 16 | buffer[offset + 2] << 8 | buffer[offset + 3]);
461
608
  }
462
609
  function writeUInt32BE(buffer, offset, value) {
463
- buffer[offset] = value >>> 24 & 255;
464
- buffer[offset + 1] = value >>> 16 & 255;
465
- buffer[offset + 2] = value >>> 8 & 255;
466
- buffer[offset + 3] = value & 255;
610
+ buffer[offset] = value >>> 24 & UINT8_MAX;
611
+ buffer[offset + 1] = value >>> 16 & UINT8_MAX;
612
+ buffer[offset + 2] = value >>> 8 & UINT8_MAX;
613
+ buffer[offset + 3] = value & UINT8_MAX;
467
614
  }
468
615
  function writeBigUInt64BE(buffer, offset, value) {
469
616
  for (let index = 7; index >= 0; index -= 1) {
@@ -478,6 +625,19 @@ function readBigUInt64BE(buffer, offset) {
478
625
  }
479
626
  return value;
480
627
  }
628
+ function utf8Size(value) {
629
+ let size = 0;
630
+ for (let index = 0; index < value.length; index += 1) {
631
+ const code = value.charCodeAt(index);
632
+ if (code < UTF8_TWO_BYTE_MIN) size += 1;
633
+ else if (code < UTF8_THREE_BYTE_MIN) size += 2;
634
+ 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) {
635
+ size += 4;
636
+ index += 1;
637
+ } else size += 3;
638
+ }
639
+ return size;
640
+ }
481
641
 
482
642
  // packages/stream-connector/src/Contracts/ZlinkStreamEnums.ts
483
643
  var ZlinkStreamTransport = /* @__PURE__ */ ((ZlinkStreamTransport2) => {
@@ -495,24 +655,6 @@ var ZlinkStreamDispatchMode = /* @__PURE__ */ ((ZlinkStreamDispatchMode2) => {
495
655
  ZlinkStreamDispatchMode2["Immediate"] = "immediate";
496
656
  return ZlinkStreamDispatchMode2;
497
657
  })(ZlinkStreamDispatchMode || {});
498
- var ZlinkStreamMessageKind = /* @__PURE__ */ ((ZlinkStreamMessageKind2) => {
499
- ZlinkStreamMessageKind2[ZlinkStreamMessageKind2["Send"] = 1] = "Send";
500
- ZlinkStreamMessageKind2[ZlinkStreamMessageKind2["Request"] = 2] = "Request";
501
- ZlinkStreamMessageKind2[ZlinkStreamMessageKind2["Response"] = 3] = "Response";
502
- ZlinkStreamMessageKind2[ZlinkStreamMessageKind2["Error"] = 4] = "Error";
503
- ZlinkStreamMessageKind2[ZlinkStreamMessageKind2["Control"] = 5] = "Control";
504
- return ZlinkStreamMessageKind2;
505
- })(ZlinkStreamMessageKind || {});
506
- var ZlinkStreamHeaderFlags = /* @__PURE__ */ ((ZlinkStreamHeaderFlags2) => {
507
- ZlinkStreamHeaderFlags2[ZlinkStreamHeaderFlags2["None"] = 0] = "None";
508
- ZlinkStreamHeaderFlags2[ZlinkStreamHeaderFlags2["HasRequestSeq"] = 1] = "HasRequestSeq";
509
- ZlinkStreamHeaderFlags2[ZlinkStreamHeaderFlags2["HasMetadata"] = 2] = "HasMetadata";
510
- ZlinkStreamHeaderFlags2[ZlinkStreamHeaderFlags2["PayloadCompressed"] = 4] = "PayloadCompressed";
511
- ZlinkStreamHeaderFlags2[ZlinkStreamHeaderFlags2["HasCorrelationId"] = 8] = "HasCorrelationId";
512
- ZlinkStreamHeaderFlags2[ZlinkStreamHeaderFlags2["HasFlowId"] = 16] = "HasFlowId";
513
- ZlinkStreamHeaderFlags2[ZlinkStreamHeaderFlags2["HasActorSlot"] = 32] = "HasActorSlot";
514
- return ZlinkStreamHeaderFlags2;
515
- })(ZlinkStreamHeaderFlags || {});
516
658
  var ZlinkStreamErrorCode = /* @__PURE__ */ ((ZlinkStreamErrorCode2) => {
517
659
  ZlinkStreamErrorCode2["Disconnected"] = "disconnected";
518
660
  ZlinkStreamErrorCode2["ConfigurationError"] = "configurationError";
@@ -524,6 +666,7 @@ var ZlinkStreamErrorCode = /* @__PURE__ */ ((ZlinkStreamErrorCode2) => {
524
666
  ZlinkStreamErrorCode2["SendFailed"] = "sendFailed";
525
667
  ZlinkStreamErrorCode2["CompressionFailed"] = "compressionFailed";
526
668
  ZlinkStreamErrorCode2["DecompressionFailed"] = "decompressionFailed";
669
+ ZlinkStreamErrorCode2["TlsValidationFailed"] = "tlsValidationFailed";
527
670
  ZlinkStreamErrorCode2["UserCallbackFailed"] = "userCallbackFailed";
528
671
  ZlinkStreamErrorCode2["RemoteError"] = "remoteError";
529
672
  return ZlinkStreamErrorCode2;
@@ -538,6 +681,15 @@ var ZlinkStreamConnectionState = /* @__PURE__ */ ((ZlinkStreamConnectionState3)
538
681
  return ZlinkStreamConnectionState3;
539
682
  })(ZlinkStreamConnectionState || {});
540
683
 
684
+ // packages/stream-connector/src/Contracts/ZlinkStreamModels.ts
685
+ var ZlinkStreamException = class extends Error {
686
+ constructor(error) {
687
+ super(error.message);
688
+ this.error = error;
689
+ this.name = "ZlinkStreamException";
690
+ }
691
+ };
692
+
541
693
  // packages/stream-connector/src/Contracts/ZlinkStreamMetadata.ts
542
694
  var ZlinkStreamMetadataMap = class _ZlinkStreamMetadataMap {
543
695
  constructor(values) {
@@ -570,25 +722,13 @@ var ZlinkStreamMetadataMap = class _ZlinkStreamMetadataMap {
570
722
  };
571
723
  function validateMetadataKey(key) {
572
724
  if (key.length === 0) {
573
- throw new Error("Metadata key must not be empty.");
574
- }
575
- for (let index = 0; index < key.length; index++) {
576
- const code = key.charCodeAt(index);
577
- if (code < 32 || code > 126 || key[index] === "=") {
578
- throw new Error('Metadata key must contain printable ASCII characters except "=".');
579
- }
725
+ throw new ZlinkStreamException({
726
+ code: "validationFailed" /* ValidationFailed */,
727
+ message: "Metadata key must not be empty."
728
+ });
580
729
  }
581
730
  }
582
731
 
583
- // packages/stream-connector/src/Contracts/ZlinkStreamModels.ts
584
- var ZlinkStreamException = class extends Error {
585
- constructor(error) {
586
- super(error.message);
587
- this.error = error;
588
- this.name = "ZlinkStreamException";
589
- }
590
- };
591
-
592
732
  // packages/stream-connector/src/Contracts/ZlinkStreamJsonCodec.ts
593
733
  var zlinkStreamJsonCodecName = "json";
594
734
  var codecOptions = {};
@@ -640,6 +780,10 @@ function isPrototypeKey(key) {
640
780
  }
641
781
 
642
782
  // packages/stream-connector/src/Runtime/ZlinkStreamSupport.ts
783
+ var BACKING_ARRAY_COMPACTION_MIN_HEAD = 1024;
784
+ function shouldCompactBackingArray(head, length) {
785
+ return head >= BACKING_ARRAY_COMPACTION_MIN_HEAD && head * 2 >= length;
786
+ }
643
787
  function connectorError(code, message, cause) {
644
788
  return new ZlinkStreamException({ code, message, cause });
645
789
  }
@@ -653,15 +797,21 @@ function unwrapStreamError(error) {
653
797
  if (error instanceof ZlinkStreamException) {
654
798
  return error.error;
655
799
  }
656
- return {
657
- code: "remoteError" /* RemoteError */,
658
- message: error instanceof Error ? error.message : String(error),
659
- cause: error
660
- };
800
+ throw error;
661
801
  }
662
802
  function subscription(dispose) {
663
803
  return { dispose };
664
804
  }
805
+ function* currentRegistrations(registrations, snapshot = Array.from(registrations)) {
806
+ for (const registration of snapshot) {
807
+ if (registrations.has(registration)) yield registration;
808
+ }
809
+ }
810
+ function registerHandler(handlers, handler) {
811
+ const registration = { handler };
812
+ handlers.add(registration);
813
+ return subscription(() => handlers.delete(registration));
814
+ }
665
815
  function throwIfAborted(signal) {
666
816
  if (signal?.aborted === true) {
667
817
  throw connectorError("disconnected" /* Disconnected */, "Operation canceled.");
@@ -681,9 +831,6 @@ function delay(delayMs, signal) {
681
831
  signal?.addEventListener("abort", onAbort, { once: true });
682
832
  });
683
833
  }
684
- function utf8Encode2(value) {
685
- return new TextEncoder().encode(value);
686
- }
687
834
  function utf8Decode2(value) {
688
835
  return new TextDecoder().decode(value);
689
836
  }
@@ -702,59 +849,48 @@ var zlinkStreamAssert = {
702
849
  }
703
850
  },
704
851
  async expectFailure(action, errorKind) {
705
- let failure;
706
852
  try {
707
853
  await action();
708
- } catch (error) {
709
- failure = error;
710
- }
711
- if (failure === void 0) {
712
- throw connectorError("validationFailed" /* ValidationFailed */, "Expected action to fail.");
713
- }
714
- const streamError = unwrapStreamError(failure);
715
- if (errorKind !== void 0 && streamError.code !== errorKind) {
716
- throw connectorError(
717
- "validationFailed" /* ValidationFailed */,
718
- `Expected failure kind '${errorKind}', got '${streamError.code}'.`,
719
- failure
720
- );
854
+ } catch (failure) {
855
+ if (!(failure instanceof ZlinkStreamException)) throw failure;
856
+ const streamError = failure.error;
857
+ if (errorKind !== void 0 && streamError.code !== errorKind) {
858
+ throw connectorError(
859
+ "validationFailed" /* ValidationFailed */,
860
+ `Expected failure kind '${errorKind}', got '${streamError.code}'.`,
861
+ failure
862
+ );
863
+ }
864
+ return streamError;
721
865
  }
722
- return streamError;
866
+ throw connectorError("validationFailed" /* ValidationFailed */, "Expected action to fail.");
723
867
  },
724
868
  async expectTimeout(action) {
725
- let failure;
726
869
  try {
727
870
  await action();
728
- } catch (error) {
729
- failure = error;
730
- }
731
- if (failure === void 0) {
732
- throw connectorError("validationFailed" /* ValidationFailed */, "Expected action to time out.");
733
- }
734
- const code = unwrapStreamError(failure).code;
735
- if (code !== "requestTimeout" /* RequestTimeout */ && code !== "connectTimeout" /* ConnectTimeout */) {
736
- throw failure;
871
+ } catch (failure) {
872
+ if (!(failure instanceof ZlinkStreamException) || failure.error.code !== "requestTimeout" /* RequestTimeout */ && failure.error.code !== "connectTimeout" /* ConnectTimeout */) {
873
+ throw failure;
874
+ }
875
+ return;
737
876
  }
877
+ throw connectorError("validationFailed" /* ValidationFailed */, "Expected action to time out.");
738
878
  }
739
879
  };
740
880
 
741
881
  // packages/stream-connector/src/Runtime/Protocol/ZlinkStreamPacketNameValidator.ts
742
882
  function validateName(name, allowReserved = false) {
743
- if (name.length === 0) {
744
- throw connectorError("validationFailed" /* ValidationFailed */, "Message name must not be empty.");
883
+ try {
884
+ validateStreamWirePacketName(name);
885
+ } catch (cause) {
886
+ throw connectorError("validationFailed" /* ValidationFailed */, "Message name is invalid.", cause);
745
887
  }
746
- if (!allowReserved && name.startsWith("$zlink.")) {
888
+ if (!allowReserved && name.startsWith(ZLINK_STREAM_RESERVED_PACKET_NAME_PREFIX)) {
747
889
  throw connectorError(
748
890
  "validationFailed" /* ValidationFailed */,
749
891
  "Message name uses a reserved zlink prefix."
750
892
  );
751
893
  }
752
- if (utf8Encode2(name).length > 255) {
753
- throw connectorError(
754
- "validationFailed" /* ValidationFailed */,
755
- "Message name must not exceed 255 UTF-8 bytes."
756
- );
757
- }
758
894
  }
759
895
 
760
896
  // packages/stream-connector/src/Runtime/Calls/ZlinkStreamCallBuilders.ts
@@ -1127,9 +1263,164 @@ function resolveCompressionCodec(compression, compressionCodec) {
1127
1263
  return compressionCodec ?? zlinkStreamLz4CompressionCodec;
1128
1264
  }
1129
1265
 
1266
+ // packages/stream-connector/src/Contracts/ZlinkStreamConnectorOptions.ts
1267
+ var ZLINK_STREAM_DEFAULT_PAYLOAD_BYTES = 64 * 1024;
1268
+
1269
+ // packages/stream-connector/src/Runtime/Transport/ZlinkStreamEndpoint.ts
1270
+ function inferTransport(endpoint) {
1271
+ const url = parseEndpoint(endpoint);
1272
+ switch (url.protocol) {
1273
+ case "ws:":
1274
+ return "webSocket" /* WebSocket */;
1275
+ case "wss:":
1276
+ return "webSocketSecure" /* WebSocketSecure */;
1277
+ default:
1278
+ throw connectorError(
1279
+ "configurationError" /* ConfigurationError */,
1280
+ "The TypeScript Stream Connector supports only ws:// and wss:// endpoints."
1281
+ );
1282
+ }
1283
+ }
1284
+ function parseEndpoint(endpoint) {
1285
+ try {
1286
+ return new URL(endpoint);
1287
+ } catch (cause) {
1288
+ throw connectorError("configurationError" /* ConfigurationError */, "Endpoint is invalid.", cause);
1289
+ }
1290
+ }
1291
+
1292
+ // packages/stream-connector/src/Runtime/ZlinkStreamConnectorOptions.ts
1293
+ function normalizeOptions(options, defaultTransportFactory) {
1294
+ const endpoint = options.endpoint;
1295
+ if (endpoint.trim().length === 0) {
1296
+ throw connectorError("configurationError" /* ConfigurationError */, "Endpoint must not be empty.");
1297
+ }
1298
+ const inferredTransport = inferTransport(endpoint);
1299
+ if (options.transport !== void 0 && options.transport !== inferredTransport) {
1300
+ throw connectorError(
1301
+ "configurationError" /* ConfigurationError */,
1302
+ "Configured transport conflicts with endpoint scheme."
1303
+ );
1304
+ }
1305
+ const normalized = {
1306
+ endpoint,
1307
+ transport: inferredTransport,
1308
+ connectTimeoutMs: options.connectTimeoutMs ?? 5e3,
1309
+ requestTimeoutMs: options.requestTimeoutMs ?? 3e4,
1310
+ waitTimeoutMs: options.waitTimeoutMs ?? 5e3,
1311
+ heartbeat: {
1312
+ enabled: options.heartbeat?.enabled ?? true,
1313
+ intervalMs: options.heartbeat?.intervalMs ?? 1e3,
1314
+ timeoutMs: options.heartbeat?.timeoutMs ?? 5e3
1315
+ },
1316
+ reconnect: {
1317
+ enabled: options.reconnect?.enabled ?? true,
1318
+ initialDelayMs: options.reconnect?.initialDelayMs ?? 250,
1319
+ maxDelayMs: options.reconnect?.maxDelayMs ?? 5e3,
1320
+ backoffFactor: options.reconnect?.backoffFactor ?? 2,
1321
+ maxAttempts: options.reconnect?.maxAttempts === void 0 ? 3 : options.reconnect.maxAttempts
1322
+ },
1323
+ maxSendPayloadSize: options.maxSendPayloadSize ?? ZLINK_STREAM_DEFAULT_PAYLOAD_BYTES,
1324
+ maxReceivePayloadSize: options.maxReceivePayloadSize ?? ZLINK_STREAM_DEFAULT_PAYLOAD_BYTES,
1325
+ dispatchMode: options.dispatchMode ?? "manual" /* Manual */,
1326
+ compression: options.compression ?? "lz4" /* Lz4 */,
1327
+ compressionCodec: options.compressionCodec,
1328
+ nameResolver: options.nameResolver ?? defaultPacketNameResolver,
1329
+ transportFactory: options.transportFactory ?? defaultTransportFactory,
1330
+ codec: options.codec
1331
+ };
1332
+ validatePositive(normalized.connectTimeoutMs, "ConnectTimeout");
1333
+ validatePositive(normalized.requestTimeoutMs, "RequestTimeout");
1334
+ validatePositive(normalized.waitTimeoutMs, "WaitTimeout");
1335
+ validatePositive(normalized.maxSendPayloadSize, "MaxSendPayloadSize");
1336
+ validatePositive(normalized.maxReceivePayloadSize, "MaxReceivePayloadSize");
1337
+ validateHeartbeat(normalized.heartbeat);
1338
+ validateReconnect(normalized.reconnect);
1339
+ if (options.heartbeat?.enabled !== void 0 && typeof options.heartbeat.enabled !== "boolean") {
1340
+ throw connectorError(
1341
+ "validationFailed" /* ValidationFailed */,
1342
+ "Heartbeat enabled must be boolean."
1343
+ );
1344
+ }
1345
+ if (options.reconnect?.enabled !== void 0 && typeof options.reconnect.enabled !== "boolean") {
1346
+ throw connectorError(
1347
+ "validationFailed" /* ValidationFailed */,
1348
+ "Reconnect enabled must be boolean."
1349
+ );
1350
+ }
1351
+ if (options.compressionCodec !== void 0 && !hasMethods(options.compressionCodec, "compress", "decompress")) {
1352
+ throw connectorError("validationFailed" /* ValidationFailed */, "Compression codec is invalid.");
1353
+ }
1354
+ if (options.codec !== void 0 && !hasMethods(options.codec, "encode", "decode")) {
1355
+ throw connectorError("validationFailed" /* ValidationFailed */, "Payload codec is invalid.");
1356
+ }
1357
+ if (options.nameResolver !== void 0 && !hasMethods(options.nameResolver, "resolve")) {
1358
+ throw connectorError("validationFailed" /* ValidationFailed */, "Packet name resolver is invalid.");
1359
+ }
1360
+ if (options.transportFactory !== void 0 && !hasMethods(options.transportFactory, "connect")) {
1361
+ throw connectorError("validationFailed" /* ValidationFailed */, "Transport factory is invalid.");
1362
+ }
1363
+ if (!Object.values(ZlinkStreamDispatchMode).includes(normalized.dispatchMode)) {
1364
+ throw connectorError("validationFailed" /* ValidationFailed */, "DispatchMode is invalid.");
1365
+ }
1366
+ if (!Object.values(ZlinkStreamCompression).includes(normalized.compression)) {
1367
+ throw connectorError("validationFailed" /* ValidationFailed */, "Compression is invalid.");
1368
+ }
1369
+ validateCompressionCodec(normalized);
1370
+ return normalized;
1371
+ }
1372
+ var defaultPacketNameResolver = {
1373
+ resolve(payloadType) {
1374
+ const declared = payloadType.packetName;
1375
+ if (typeof declared === "string" && declared.length > 0) {
1376
+ return declared;
1377
+ }
1378
+ return payloadType.name;
1379
+ }
1380
+ };
1381
+ function validateCompressionCodec(options) {
1382
+ const compression = options.compression;
1383
+ if (compression === "none" /* None */) {
1384
+ if (options.compressionCodec !== void 0) {
1385
+ throw connectorError(
1386
+ "configurationError" /* ConfigurationError */,
1387
+ "compressionCodec cannot be set when compression is none."
1388
+ );
1389
+ }
1390
+ }
1391
+ }
1392
+ function validatePositive(value, name) {
1393
+ if (!Number.isFinite(value) || value <= 0) {
1394
+ throw connectorError("validationFailed" /* ValidationFailed */, `${name} must be positive.`);
1395
+ }
1396
+ }
1397
+ function hasMethods(value, ...names) {
1398
+ if (value === null || typeof value !== "object") return false;
1399
+ const candidate = value;
1400
+ return names.every((name) => typeof candidate[name] === "function");
1401
+ }
1402
+ function validateHeartbeat(options) {
1403
+ const intervalMs = options.intervalMs;
1404
+ const timeoutMs = options.timeoutMs;
1405
+ validatePositive(intervalMs, "Heartbeat interval");
1406
+ validatePositive(timeoutMs, "Heartbeat timeout");
1407
+ }
1408
+ function validateReconnect(options) {
1409
+ validatePositive(options.initialDelayMs, "Reconnect InitialDelay");
1410
+ validatePositive(options.maxDelayMs, "Reconnect MaxDelay");
1411
+ validatePositive(options.backoffFactor, "Reconnect BackoffFactor");
1412
+ const maxAttempts = options.maxAttempts;
1413
+ if (maxAttempts !== null && !(Number.isFinite(maxAttempts) && maxAttempts > 0)) {
1414
+ throw connectorError(
1415
+ "validationFailed" /* ValidationFailed */,
1416
+ "Reconnect MaxAttempts must be null or positive."
1417
+ );
1418
+ }
1419
+ }
1420
+
1130
1421
  // packages/stream-connector/src/Runtime/Protocol/ZlinkStreamFrameCodec.ts
1131
1422
  var ZlinkStreamFrameCodec = class {
1132
- static encode(header, payload, maxPayloadSize = 64 * 1024) {
1423
+ static encode(header, payload, maxPayloadSize = ZLINK_STREAM_DEFAULT_PAYLOAD_BYTES) {
1133
1424
  validatePayload(payload.length, maxPayloadSize);
1134
1425
  try {
1135
1426
  return encodeStreamWireFrame(header, payload);
@@ -1150,35 +1441,14 @@ var ZlinkStreamFrameCodec = class {
1150
1441
  }
1151
1442
  };
1152
1443
  function splitZlinkStreamFrames(chunk) {
1153
- if (chunk.length === 0) {
1444
+ try {
1445
+ return splitStreamWireFrames(chunk);
1446
+ } catch (cause) {
1154
1447
  throw connectorError(
1155
1448
  "frameDecodeFailed" /* FrameDecodeFailed */,
1156
- "Stream frame prefix is incomplete."
1449
+ cause instanceof Error ? cause.message : "Frame length does not match prefix."
1157
1450
  );
1158
1451
  }
1159
- const frames = [];
1160
- let offset = 0;
1161
- while (offset < chunk.length) {
1162
- const remaining = chunk.length - offset;
1163
- if (remaining < 6) {
1164
- throw connectorError(
1165
- "frameDecodeFailed" /* FrameDecodeFailed */,
1166
- "Stream frame prefix is incomplete."
1167
- );
1168
- }
1169
- const headerLength = chunk[offset] << 8 | chunk[offset + 1];
1170
- const payloadLength = chunk[offset + 2] * 16777216 + (chunk[offset + 3] << 16) + (chunk[offset + 4] << 8) + chunk[offset + 5];
1171
- const frameLength = 6 + headerLength + payloadLength;
1172
- if (frameLength > remaining) {
1173
- throw connectorError(
1174
- "frameDecodeFailed" /* FrameDecodeFailed */,
1175
- "Frame length does not match prefix."
1176
- );
1177
- }
1178
- frames.push(chunk.subarray(offset, offset + frameLength));
1179
- offset += frameLength;
1180
- }
1181
- return frames;
1182
1452
  }
1183
1453
  function validatePayload(payloadLength, maxPayloadSize) {
1184
1454
  if (payloadLength > maxPayloadSize) {
@@ -1190,59 +1460,34 @@ function validatePayload(payloadLength, maxPayloadSize) {
1190
1460
  }
1191
1461
 
1192
1462
  // packages/stream-connector/src/Runtime/Protocol/ZlinkStreamMetadataCodec.ts
1193
- var ZLINK_STREAM_MAX_METADATA_BYTES = 1024;
1194
1463
  var ZlinkStreamMetadataCodec = class {
1195
1464
  static size(metadata) {
1465
+ let size;
1196
1466
  try {
1197
- const size = metadata.count === 0 ? 0 : encodeStreamWireMetadata(metadata.values).length;
1198
- if (size > ZLINK_STREAM_MAX_METADATA_BYTES) {
1199
- throw connectorError(
1200
- "validationFailed" /* ValidationFailed */,
1201
- `Metadata must not exceed ${ZLINK_STREAM_MAX_METADATA_BYTES} bytes.`
1202
- );
1203
- }
1204
- return size;
1467
+ size = metadata.count === 0 ? 0 : streamWireMetadataSize(metadata.values);
1205
1468
  } catch (cause) {
1206
1469
  throw connectorError(
1207
1470
  "validationFailed" /* ValidationFailed */,
1208
- streamWireErrorMessage(cause),
1471
+ cause instanceof Error ? cause.message : "Metadata is invalid.",
1209
1472
  cause
1210
1473
  );
1211
1474
  }
1212
- }
1213
- static write(metadata, destination) {
1214
- try {
1215
- destination.set(encodeStreamWireMetadata(metadata.values));
1216
- } catch (cause) {
1475
+ if (size > ZLINK_STREAM_MAX_METADATA_BYTES) {
1217
1476
  throw connectorError(
1218
1477
  "validationFailed" /* ValidationFailed */,
1219
- streamWireErrorMessage(cause),
1220
- cause
1221
- );
1222
- }
1223
- }
1224
- static decode(metadata) {
1225
- try {
1226
- const values = decodeStreamWireMetadata(metadata);
1227
- return values.size === 0 ? ZlinkStreamMetadataMap.empty : ZlinkStreamMetadataMap.from(values);
1228
- } catch (cause) {
1229
- throw connectorError(
1230
- "frameDecodeFailed" /* FrameDecodeFailed */,
1231
- streamWireErrorMessage(cause),
1232
- cause
1478
+ `Metadata must not exceed ${ZLINK_STREAM_MAX_METADATA_BYTES} bytes.`
1233
1479
  );
1234
1480
  }
1481
+ return size;
1235
1482
  }
1236
1483
  };
1237
- function streamWireErrorMessage(cause) {
1238
- return cause instanceof Error ? cause.message : "Metadata is invalid.";
1239
- }
1240
1484
 
1241
1485
  // packages/stream-connector/src/Runtime/Protocol/ZlinkStreamHeaderCodec.ts
1242
1486
  var ZlinkStreamHeaderCodec = class {
1243
1487
  static encode(header) {
1244
1488
  const reply = isReplyKind2(header.kind);
1245
1489
  if (!reply) validateName(header.name, header.kind === 5 /* Control */);
1490
+ validateEncodeFlags(header.flags);
1246
1491
  validateHeaderSemantics(header);
1247
1492
  ZlinkStreamMetadataCodec.size(header.metadata);
1248
1493
  try {
@@ -1259,7 +1504,7 @@ var ZlinkStreamHeaderCodec = class {
1259
1504
  } catch (cause) {
1260
1505
  throw connectorError(
1261
1506
  "validationFailed" /* ValidationFailed */,
1262
- streamWireErrorMessage2(cause),
1507
+ streamWireErrorMessage(cause),
1263
1508
  cause
1264
1509
  );
1265
1510
  }
@@ -1279,25 +1524,24 @@ var ZlinkStreamHeaderCodec = class {
1279
1524
  correlationId: wire.correlationId,
1280
1525
  actorSlot: wire.actorSlot
1281
1526
  };
1527
+ if (!isReplyKind2(decoded.kind)) {
1528
+ validateName(decoded.name, decoded.kind === 5 /* Control */);
1529
+ }
1530
+ validateHeaderSemantics(decoded);
1282
1531
  } catch (cause) {
1283
1532
  throw connectorError(
1284
1533
  "frameDecodeFailed" /* FrameDecodeFailed */,
1285
- streamWireErrorMessage2(cause),
1534
+ streamWireErrorMessage(cause),
1286
1535
  cause
1287
1536
  );
1288
1537
  }
1289
- validateEnum(decoded.kind, decoded.codec, decoded.flags);
1290
- if (!isReplyKind2(decoded.kind)) {
1291
- validateName(decoded.name, decoded.kind === 5 /* Control */);
1292
- }
1293
- validateHeaderSemantics(decoded);
1294
1538
  return decoded;
1295
1539
  }
1296
1540
  };
1297
1541
  function isReplyKind2(kind) {
1298
1542
  return kind === 3 /* Response */ || kind === 4 /* Error */;
1299
1543
  }
1300
- function streamWireErrorMessage2(cause) {
1544
+ function streamWireErrorMessage(cause) {
1301
1545
  return cause instanceof Error ? cause.message : "Stream header is invalid.";
1302
1546
  }
1303
1547
  function buildHeader(kind, name, codec, metadata, compress, requestSeq, correlationId, actorSlot) {
@@ -1327,7 +1571,7 @@ function buildHeader(kind, name, codec, metadata, compress, requestSeq, correlat
1327
1571
  };
1328
1572
  }
1329
1573
  function validateHeaderSemantics(header) {
1330
- validateEnum(header.kind, header.codec, header.flags);
1574
+ validateEnum(header.kind, header.codec);
1331
1575
  const hasRequestSeq = header.requestSeq !== void 0 || (header.flags & 1 /* HasRequestSeq */) !== 0;
1332
1576
  const hasMetadata = header.metadata.count > 0 || (header.flags & 2 /* HasMetadata */) !== 0;
1333
1577
  if (header.kind === 1 /* Send */ && hasRequestSeq) {
@@ -1360,13 +1604,15 @@ function validateHeaderSemantics(header) {
1360
1604
  }
1361
1605
  }
1362
1606
  }
1363
- function validateEnum(kind, codec, flags) {
1364
- if (![1, 2, 3, 4, 5].includes(kind)) {
1607
+ function validateEnum(kind, codec) {
1608
+ if (!isStreamWireMessageKind(kind)) {
1365
1609
  throw connectorError("frameDecodeFailed" /* FrameDecodeFailed */, "Unknown stream message kind.");
1366
1610
  }
1367
- if (![0, 1, 2, 3].includes(codec)) {
1611
+ if (!isStreamWireCodec(codec)) {
1368
1612
  throw connectorError("frameDecodeFailed" /* FrameDecodeFailed */, "Unknown stream codec.");
1369
1613
  }
1614
+ }
1615
+ function validateEncodeFlags(flags) {
1370
1616
  const known = 1 /* HasRequestSeq */ | 2 /* HasMetadata */ | 4 /* PayloadCompressed */ | 8 /* HasCorrelationId */ | 16 /* HasFlowId */ | 32 /* HasActorSlot */;
1371
1617
  if ((flags & ~known) !== 0) {
1372
1618
  throw connectorError("frameDecodeFailed" /* FrameDecodeFailed */, "Unknown stream header flag.");
@@ -1374,8 +1620,8 @@ function validateEnum(kind, codec, flags) {
1374
1620
  }
1375
1621
 
1376
1622
  // packages/stream-connector/src/Runtime/Protocol/ZlinkStreamFrameProtocol.ts
1377
- var ZLINK_STREAM_HEARTBEAT_PING = "$zlink.heartbeat.ping";
1378
- var ZLINK_STREAM_HEARTBEAT_PONG = "$zlink.heartbeat.pong";
1623
+ var ZLINK_STREAM_HEARTBEAT_PING = ZlinkStreamControlPacket.HeartbeatPing;
1624
+ var ZLINK_STREAM_HEARTBEAT_PONG = ZlinkStreamControlPacket.HeartbeatPong;
1379
1625
  var ZlinkStreamFrameProtocol = class {
1380
1626
  constructor(options) {
1381
1627
  this.options = options;
@@ -1443,168 +1689,12 @@ var ZlinkStreamFrameProtocol = class {
1443
1689
  }
1444
1690
  };
1445
1691
 
1446
- // packages/stream-connector/src/Runtime/Transport/ZlinkStreamEndpoint.ts
1447
- function inferTransport(endpoint) {
1448
- const url = parseEndpoint(endpoint);
1449
- switch (url.protocol) {
1450
- case "ws:":
1451
- return "webSocket" /* WebSocket */;
1452
- case "wss:":
1453
- return "webSocketSecure" /* WebSocketSecure */;
1454
- default:
1455
- throw connectorError(
1456
- "configurationError" /* ConfigurationError */,
1457
- "The TypeScript Stream Connector supports only ws:// and wss:// endpoints."
1458
- );
1459
- }
1460
- }
1461
- function parseEndpoint(endpoint) {
1462
- try {
1463
- return new URL(endpoint);
1464
- } catch (cause) {
1465
- throw connectorError("configurationError" /* ConfigurationError */, "Endpoint is invalid.", cause);
1466
- }
1467
- }
1468
-
1469
- // packages/stream-connector/src/Runtime/ZlinkStreamConnectorOptions.ts
1470
- function normalizeOptions(options, defaultTransportFactory) {
1471
- const endpoint = options.endpoint;
1472
- if (endpoint.trim().length === 0) {
1473
- throw connectorError("configurationError" /* ConfigurationError */, "Endpoint must not be empty.");
1474
- }
1475
- const inferredTransport = inferTransport(endpoint);
1476
- if (options.transport !== void 0 && options.transport !== inferredTransport) {
1477
- throw connectorError(
1478
- "configurationError" /* ConfigurationError */,
1479
- "Configured transport conflicts with endpoint scheme."
1480
- );
1481
- }
1482
- validatePositive(options.connectTimeoutMs ?? 5e3, "ConnectTimeout");
1483
- validatePositive(options.requestTimeoutMs ?? 3e4, "RequestTimeout");
1484
- validatePositive(options.waitTimeoutMs ?? 5e3, "WaitTimeout");
1485
- validatePositive(options.maxSendPayloadSize ?? 64 * 1024, "MaxSendPayloadSize");
1486
- validatePositive(options.maxReceivePayloadSize ?? 64 * 1024, "MaxReceivePayloadSize");
1487
- validateHeartbeat(options.heartbeat);
1488
- validateReconnect(options.reconnect);
1489
- if (options.heartbeat?.enabled !== void 0 && typeof options.heartbeat.enabled !== "boolean") {
1490
- throw connectorError(
1491
- "validationFailed" /* ValidationFailed */,
1492
- "Heartbeat enabled must be boolean."
1493
- );
1494
- }
1495
- if (options.reconnect?.enabled !== void 0 && typeof options.reconnect.enabled !== "boolean") {
1496
- throw connectorError(
1497
- "validationFailed" /* ValidationFailed */,
1498
- "Reconnect enabled must be boolean."
1499
- );
1500
- }
1501
- if (options.compressionCodec !== void 0 && !hasMethods(options.compressionCodec, "compress", "decompress")) {
1502
- throw connectorError("validationFailed" /* ValidationFailed */, "Compression codec is invalid.");
1503
- }
1504
- if (options.codec !== void 0 && !hasMethods(options.codec, "encode", "decode")) {
1505
- throw connectorError("validationFailed" /* ValidationFailed */, "Payload codec is invalid.");
1506
- }
1507
- if (options.nameResolver !== void 0 && !hasMethods(options.nameResolver, "resolve")) {
1508
- throw connectorError("validationFailed" /* ValidationFailed */, "Packet name resolver is invalid.");
1509
- }
1510
- if (options.transportFactory !== void 0 && !hasMethods(options.transportFactory, "connect")) {
1511
- throw connectorError("validationFailed" /* ValidationFailed */, "Transport factory is invalid.");
1512
- }
1513
- if (!Object.values(ZlinkStreamDispatchMode).includes(
1514
- options.dispatchMode ?? "manual" /* Manual */
1515
- )) {
1516
- throw connectorError("validationFailed" /* ValidationFailed */, "DispatchMode is invalid.");
1517
- }
1518
- if (!Object.values(ZlinkStreamCompression).includes(
1519
- options.compression ?? "lz4" /* Lz4 */
1520
- )) {
1521
- throw connectorError("validationFailed" /* ValidationFailed */, "Compression is invalid.");
1522
- }
1523
- return {
1524
- endpoint,
1525
- transport: inferredTransport,
1526
- connectTimeoutMs: options.connectTimeoutMs ?? 5e3,
1527
- requestTimeoutMs: options.requestTimeoutMs ?? 3e4,
1528
- waitTimeoutMs: options.waitTimeoutMs ?? 5e3,
1529
- heartbeat: {
1530
- enabled: options.heartbeat?.enabled ?? true,
1531
- intervalMs: options.heartbeat?.intervalMs ?? 1e3,
1532
- timeoutMs: options.heartbeat?.timeoutMs ?? 5e3
1533
- },
1534
- reconnect: {
1535
- enabled: options.reconnect?.enabled ?? true,
1536
- initialDelayMs: options.reconnect?.initialDelayMs ?? 250,
1537
- maxDelayMs: options.reconnect?.maxDelayMs ?? 5e3,
1538
- backoffFactor: options.reconnect?.backoffFactor ?? 2,
1539
- maxAttempts: options.reconnect?.maxAttempts === void 0 ? 3 : options.reconnect.maxAttempts
1540
- },
1541
- maxSendPayloadSize: options.maxSendPayloadSize ?? 64 * 1024,
1542
- maxReceivePayloadSize: options.maxReceivePayloadSize ?? 64 * 1024,
1543
- dispatchMode: options.dispatchMode ?? "manual" /* Manual */,
1544
- compression: options.compression ?? "lz4" /* Lz4 */,
1545
- compressionCodec: resolveCompressionCodec2(options),
1546
- nameResolver: options.nameResolver ?? defaultPacketNameResolver,
1547
- transportFactory: options.transportFactory ?? defaultTransportFactory,
1548
- codec: options.codec
1549
- };
1550
- }
1551
- var defaultPacketNameResolver = {
1552
- resolve(payloadType) {
1553
- const declared = payloadType.packetName;
1554
- if (typeof declared === "string" && declared.length > 0) {
1555
- return declared;
1556
- }
1557
- return payloadType.name;
1558
- }
1559
- };
1560
- function resolveCompressionCodec2(options) {
1561
- const compression = options.compression ?? "lz4" /* Lz4 */;
1562
- if (compression === "none" /* None */) {
1563
- if (options.compressionCodec !== void 0) {
1564
- throw connectorError(
1565
- "configurationError" /* ConfigurationError */,
1566
- "compressionCodec cannot be set when compression is none."
1567
- );
1568
- }
1569
- return void 0;
1570
- }
1571
- return options.compressionCodec;
1572
- }
1573
- function validatePositive(value, name) {
1574
- if (!Number.isFinite(value) || value <= 0) {
1575
- throw connectorError("validationFailed" /* ValidationFailed */, `${name} must be positive.`);
1576
- }
1577
- }
1578
- function hasMethods(value, ...names) {
1579
- if (value === null || typeof value !== "object") return false;
1580
- const candidate = value;
1581
- return names.every((name) => typeof candidate[name] === "function");
1582
- }
1583
- function validateHeartbeat(options) {
1584
- const intervalMs = options?.intervalMs ?? 1e3;
1585
- const timeoutMs = options?.timeoutMs ?? 5e3;
1586
- validatePositive(intervalMs, "Heartbeat interval");
1587
- validatePositive(timeoutMs, "Heartbeat timeout");
1588
- }
1589
- function validateReconnect(options) {
1590
- validatePositive(options?.initialDelayMs ?? 250, "Reconnect InitialDelay");
1591
- validatePositive(options?.maxDelayMs ?? 5e3, "Reconnect MaxDelay");
1592
- validatePositive(options?.backoffFactor ?? 2, "Reconnect BackoffFactor");
1593
- const maxAttempts = options?.maxAttempts === void 0 ? 3 : options.maxAttempts;
1594
- if (maxAttempts !== null && !(Number.isFinite(maxAttempts) && maxAttempts > 0)) {
1595
- throw connectorError(
1596
- "validationFailed" /* ValidationFailed */,
1597
- "Reconnect MaxAttempts must be null or positive."
1598
- );
1599
- }
1600
- }
1601
-
1602
1692
  // packages/stream-connector/src/Runtime/ZlinkStreamPendingRequests.ts
1603
1693
  var ZlinkStreamPendingRequests = class {
1604
1694
  nextRequestSeq = 1n;
1605
1695
  active = /* @__PURE__ */ new Map();
1606
1696
  create(packetName, timeoutMs) {
1607
- if (this.nextRequestSeq > 0xffffffffffffffffn) {
1697
+ if (this.nextRequestSeq > UINT64_MAX) {
1608
1698
  throw connectorError("sendFailed" /* SendFailed */, "Request sequence is exhausted.");
1609
1699
  }
1610
1700
  const requestSeq = this.nextRequestSeq++;
@@ -1688,8 +1778,8 @@ var ZlinkStreamPendingRequests = class {
1688
1778
  };
1689
1779
 
1690
1780
  // packages/stream-connector/src/Runtime/ZlinkStreamActors.ts
1691
- var ACTOR_BOUND = "$zlink.actor.bound";
1692
- var ACTOR_UNBOUND = "$zlink.actor.unbound";
1781
+ var ACTOR_BOUND = ZlinkStreamControlPacket.ActorBound;
1782
+ var ACTOR_UNBOUND = ZlinkStreamControlPacket.ActorUnbound;
1693
1783
  var zlinkStreamActorBinding = Symbol("zlink.stream.actorBinding");
1694
1784
  var DefaultZlinkStreamActor = class {
1695
1785
  constructor(connector, actorId, slot) {
@@ -1732,7 +1822,6 @@ var ZlinkStreamActors = class {
1732
1822
  }
1733
1823
  bySlot = /* @__PURE__ */ new Map();
1734
1824
  byId = /* @__PURE__ */ new Map();
1735
- issued = [];
1736
1825
  boundHandlers = /* @__PURE__ */ new Set();
1737
1826
  unboundHandlers = /* @__PURE__ */ new Set();
1738
1827
  get snapshot() {
@@ -1742,12 +1831,10 @@ var ZlinkStreamActors = class {
1742
1831
  return this.byId.get(actorId);
1743
1832
  }
1744
1833
  onBound(handler) {
1745
- this.boundHandlers.add(handler);
1746
- return subscription(() => this.boundHandlers.delete(handler));
1834
+ return registerHandler(this.boundHandlers, handler);
1747
1835
  }
1748
1836
  onUnbound(handler) {
1749
- this.unboundHandlers.add(handler);
1750
- return subscription(() => this.unboundHandlers.delete(handler));
1837
+ return registerHandler(this.unboundHandlers, handler);
1751
1838
  }
1752
1839
  processControl(name, payload, signal) {
1753
1840
  if (name === ACTOR_BOUND) {
@@ -1771,48 +1858,43 @@ var ZlinkStreamActors = class {
1771
1858
  return actor;
1772
1859
  }
1773
1860
  closeAll(signal) {
1774
- for (const actor of this.issued) {
1775
- if (!actor.isBound) continue;
1861
+ for (const actor of this.bySlot.values()) {
1776
1862
  this.bySlot.delete(actor.slot);
1777
1863
  this.byId.delete(actor.actorId);
1778
1864
  actor.close();
1779
1865
  this.queue(this.unboundHandlers, actor, signal);
1780
1866
  }
1781
- this.issued.length = 0;
1782
1867
  }
1783
1868
  bind(payload, signal) {
1784
- if (payload.length < 5 || payload[0] !== 1) {
1785
- throw invalidControl("Actor bound payload is invalid.");
1786
- }
1787
- const slot = payload[1] << 8 | payload[2];
1788
- const idLength = payload[3];
1789
- if (slot === 0 || idLength === 0 || payload.length !== 4 + idLength) {
1790
- throw invalidControl("Actor bound payload is invalid.");
1791
- }
1792
- let actorId;
1869
+ let binding;
1793
1870
  try {
1794
- actorId = new TextDecoder("utf-8", { fatal: true }).decode(payload.subarray(4));
1871
+ binding = decodeStreamWireActorBoundPayload(payload);
1795
1872
  } catch (cause) {
1796
1873
  throw connectorError(
1797
1874
  "frameDecodeFailed" /* FrameDecodeFailed */,
1798
- "Actor id is not valid UTF-8.",
1799
- cause
1875
+ cause instanceof Error ? cause.message : "Actor bound payload is invalid.",
1876
+ cause instanceof Error ? cause.cause : void 0
1800
1877
  );
1801
1878
  }
1879
+ const { slot, actorId } = binding;
1802
1880
  if (actorId.length === 0 || this.bySlot.has(slot) || this.byId.has(actorId)) {
1803
1881
  throw invalidControl("Actor bound identity is already in use.");
1804
1882
  }
1805
1883
  const actor = new DefaultZlinkStreamActor(this.connector, actorId, slot);
1806
1884
  this.bySlot.set(slot, actor);
1807
1885
  this.byId.set(actorId, actor);
1808
- this.issued.push(actor);
1809
1886
  this.queue(this.boundHandlers, actor, signal);
1810
1887
  }
1811
1888
  unbind(payload, signal) {
1812
- if (payload.length !== 3 || payload[0] !== 1) {
1813
- throw invalidControl("Actor unbound payload is invalid.");
1889
+ let slot;
1890
+ try {
1891
+ slot = decodeStreamWireActorUnboundPayload(payload);
1892
+ } catch (cause) {
1893
+ throw connectorError(
1894
+ "frameDecodeFailed" /* FrameDecodeFailed */,
1895
+ cause instanceof Error ? cause.message : "Actor unbound payload is invalid."
1896
+ );
1814
1897
  }
1815
- const slot = payload[1] << 8 | payload[2];
1816
1898
  const actor = this.bySlot.get(slot);
1817
1899
  if (slot === 0 || actor === void 0) {
1818
1900
  throw invalidControl(`Actor slot '${slot}' is not bound.`);
@@ -1825,7 +1907,7 @@ var ZlinkStreamActors = class {
1825
1907
  queue(handlers, actor, signal) {
1826
1908
  this.receivedMessages.enqueueCallback(
1827
1909
  () => {
1828
- for (const handler of Array.from(handlers)) {
1910
+ for (const { handler } of currentRegistrations(handlers)) {
1829
1911
  this.events.runUserCallback(
1830
1912
  () => handler(actor, signal),
1831
1913
  "Actor lifecycle handler failed.",
@@ -1843,7 +1925,7 @@ function invalidControl(message) {
1843
1925
 
1844
1926
  // packages/stream-connector/src/Runtime/ZlinkStreamReceivedMessages.ts
1845
1927
  function receives(registration, message) {
1846
- return registration.actor === void 0 || registration.actor === message[zlinkStreamActorBinding];
1928
+ return registration.actor === void 0 || registration.actor.isBound && registration.actor === message[zlinkStreamActorBinding];
1847
1929
  }
1848
1930
  var ZlinkStreamReceivedMessages = class {
1849
1931
  /**
@@ -2049,7 +2131,8 @@ var ZlinkStreamReceivedMessages = class {
2049
2131
  }
2050
2132
  const { message, signal } = queued;
2051
2133
  const handlers = this.receiversOf(message);
2052
- for (const handler of handlers) {
2134
+ for (const handler of currentRegistrations(this.handlers.get(message.name), handlers)) {
2135
+ if (!receives(handler, message)) continue;
2053
2136
  this.events.runUserCallback(
2054
2137
  () => handler.handle(message, signal),
2055
2138
  "Typed message handler failed.",
@@ -2164,8 +2247,14 @@ var ZlinkStreamReceivedMessages = class {
2164
2247
  this.deliverable.length = 0;
2165
2248
  return;
2166
2249
  }
2167
- if (this.queueHead >= 1024 && this.queueHead * 2 >= this.queue.length) {
2168
- this.queue.splice(0, this.queueHead);
2250
+ const removed = this.queue.length - this.queuedCount;
2251
+ if (shouldCompactBackingArray(removed, this.queue.length)) {
2252
+ let destination = 0;
2253
+ for (let source = this.queueHead; source < this.queue.length; source += 1) {
2254
+ const queued = this.queue[source];
2255
+ if (queued !== void 0) this.queue[destination++] = queued;
2256
+ }
2257
+ this.queue.length = destination;
2169
2258
  this.queueHead = 0;
2170
2259
  this.deliverable.length = 0;
2171
2260
  for (let index = 0; index < this.queue.length; index += 1) {
@@ -2196,7 +2285,7 @@ var ZlinkStreamConnectionWriteQueue = class {
2196
2285
  this.advance();
2197
2286
  }
2198
2287
  cancel(operation, error) {
2199
- if (this.queue.has(operation) || this.active === operation) operation.fail(error);
2288
+ if (this.queue.delete(operation) || this.active === operation) operation.fail(error);
2200
2289
  }
2201
2290
  /**
2202
2291
  * Spec stream-connector 32 §7: when the connection ends, frames that have not
@@ -2204,7 +2293,8 @@ var ZlinkStreamConnectionWriteQueue = class {
2204
2293
  * waited for. The operations of both fail with `error`.
2205
2294
  */
2206
2295
  failAll(error) {
2207
- const operations = this.active === void 0 ? [...this.queue] : [this.active, ...this.queue];
2296
+ const operations = Array.from(this.queue);
2297
+ if (this.active !== void 0) operations.unshift(this.active);
2208
2298
  this.queue.clear();
2209
2299
  this.active = void 0;
2210
2300
  for (const operation of operations) operation.fail(error);
@@ -2343,26 +2433,7 @@ var ZlinkStreamFrameSender = class {
2343
2433
  };
2344
2434
 
2345
2435
  // packages/stream-connector/src/Runtime/Protocol/ZlinkSessionClosing.ts
2346
- var ZLINK_SESSION_CLOSING = "session-closing";
2347
- var reasons = {
2348
- 1: "ClientClose",
2349
- 2: "IdleTimeout",
2350
- 3: "HeartbeatTimeout",
2351
- 4: "ServerDrain",
2352
- 5: "ProtocolError",
2353
- 6: "TransportError"
2354
- };
2355
- function decodeSessionClosing(payload) {
2356
- if (payload.length < 4 || payload[0] !== 1)
2357
- throw new Error("Unsupported session-closing version.");
2358
- const closeReason = reasons[payload[1]];
2359
- if (closeReason === void 0) throw new Error("Unknown session-closing reason.");
2360
- const length = payload[2] << 8 | payload[3];
2361
- if (length > 512 || payload.length !== 4 + length)
2362
- throw new Error("Invalid session-closing diagnostic length.");
2363
- const diagnostic = length === 0 ? void 0 : new TextDecoder("utf-8", { fatal: true }).decode(payload.subarray(4));
2364
- return { closeReason, diagnostic };
2365
- }
2436
+ var ZLINK_SESSION_CLOSING = ZlinkStreamControlPacket.SessionClosing;
2366
2437
 
2367
2438
  // packages/stream-connector/src/Runtime/ZlinkStreamReceiveDispatcher.ts
2368
2439
  function closeReasonFor(error) {
@@ -2488,27 +2559,21 @@ var ZlinkStreamReceiveDispatcher = class {
2488
2559
  }
2489
2560
  return;
2490
2561
  }
2491
- if (header.kind === 4 /* Error */ && header.requestSeq !== void 0) {
2562
+ if (header.kind === 4 /* Error */) {
2563
+ let error;
2492
2564
  try {
2493
- const remoteError = decodeRemoteError(this.decodePayload(header, payload));
2494
- if (!this.pendingRequests.reject(header.requestSeq, remoteError)) {
2495
- this.events.publishError(remoteError, signal);
2496
- }
2565
+ error = decodeRemoteError(this.decodePayload(header, payload));
2497
2566
  } catch (cause) {
2498
2567
  if (cause instanceof ZlinkStreamConnectionEnd) throw cause;
2499
- const decodeError = toStreamError(
2568
+ error = toStreamError(
2500
2569
  cause,
2501
2570
  "frameDecodeFailed" /* FrameDecodeFailed */,
2502
2571
  "Remote error payload is invalid."
2503
2572
  );
2504
- if (!this.pendingRequests.reject(header.requestSeq, decodeError)) {
2505
- this.events.publishError(decodeError, signal);
2506
- }
2507
2573
  }
2508
- return;
2509
- }
2510
- if (header.kind === 4 /* Error */) {
2511
- this.events.publishError(decodeRemoteError(this.decodePayload(header, payload)), signal);
2574
+ if (header.requestSeq === void 0 || !this.pendingRequests.reject(header.requestSeq, error)) {
2575
+ this.events.publishError(error, signal);
2576
+ }
2512
2577
  return;
2513
2578
  }
2514
2579
  if (header.kind === 5 /* Control */) {
@@ -2533,7 +2598,7 @@ var ZlinkStreamReceiveDispatcher = class {
2533
2598
  return;
2534
2599
  }
2535
2600
  if (header.name === ZLINK_SESSION_CLOSING) {
2536
- const closing = decodeSessionClosing(payload);
2601
+ const closing = decodeStreamWireSessionClosing(payload);
2537
2602
  await this.serverClosing?.(closing.closeReason);
2538
2603
  return;
2539
2604
  }
@@ -2574,8 +2639,11 @@ function decodeRemoteError(decodedPayload) {
2574
2639
  }
2575
2640
 
2576
2641
  // packages/stream-connector/src/Runtime/ZlinkStreamConnectorLifecycle.ts
2642
+ var RECONNECT_JITTER_FLOOR = 0.5;
2577
2643
  function randomizedDelay(baseDelayMs) {
2578
- return Math.round(baseDelayMs * (0.5 + Math.random() * 0.5));
2644
+ return Math.round(
2645
+ baseDelayMs * (RECONNECT_JITTER_FLOOR + Math.random() * (1 - RECONNECT_JITTER_FLOOR))
2646
+ );
2579
2647
  }
2580
2648
  var ZlinkStreamConnectorLifecycle = class {
2581
2649
  constructor(options, pendingRequests, frameSender, receiveDispatcher, receivedMessages, actors, events) {
@@ -2604,7 +2672,6 @@ var ZlinkStreamConnectorLifecycle = class {
2604
2672
  closeRequested = false;
2605
2673
  disconnectedPublished = false;
2606
2674
  closeReasonValue;
2607
- lateConnectCleanupError;
2608
2675
  get isConnected() {
2609
2676
  return this.currentState === "connected" /* Connected */;
2610
2677
  }
@@ -2646,12 +2713,7 @@ var ZlinkStreamConnectorLifecycle = class {
2646
2713
  try {
2647
2714
  const connection = await this.connectWithReconnect(attempts.signal);
2648
2715
  if (this.closeRequested) {
2649
- try {
2650
- await connection.close(signal);
2651
- } catch (error) {
2652
- this.lateConnectCleanupError = error;
2653
- throw error;
2654
- }
2716
+ await this.closeTransport(connection, void 0, signal);
2655
2717
  throw connectorError(
2656
2718
  "disconnected" /* Disconnected */,
2657
2719
  "Connector closed while connecting."
@@ -2729,23 +2791,10 @@ var ZlinkStreamConnectorLifecycle = class {
2729
2791
  this.connectAbort?.abort();
2730
2792
  await this.connectTask?.catch(() => void 0);
2731
2793
  await this.disconnectTask?.catch(() => void 0);
2732
- const errors = [];
2733
- if (this.lateConnectCleanupError !== void 0) {
2734
- errors.push(this.lateConnectCleanupError);
2735
- this.lateConnectCleanupError = void 0;
2736
- }
2737
- try {
2738
- await this.tearDownConnection(
2739
- { code: "disconnected" /* Disconnected */, message: "Connector closed." },
2740
- signal
2741
- );
2742
- } catch (error) {
2743
- errors.push(error);
2744
- }
2745
- this.setState("closed" /* Closed */, void 0, signal);
2746
- this.publishDisconnected(signal);
2747
- if (errors.length === 1) throw errors[0];
2748
- if (errors.length > 1) throw new AggregateError(errors, "Stream connector close failed.");
2794
+ await this.tearDownConnection(
2795
+ { code: "disconnected" /* Disconnected */, message: "Connector closed." },
2796
+ signal
2797
+ );
2749
2798
  }
2750
2799
  /**
2751
2800
  * Spec stream-connector 32 §7: `dispatch` runs the callbacks the receive loop
@@ -2951,19 +3000,26 @@ var ZlinkStreamConnectorLifecycle = class {
2951
3000
  if (this.disconnectTask !== void 0) {
2952
3001
  return await this.disconnectTask;
2953
3002
  }
2954
- this.disconnectTask = this.tearDownConnection(error).catch(() => {
2955
- }).finally(() => {
2956
- this.disconnectTask = void 0;
3003
+ let resolve;
3004
+ let reject;
3005
+ const pending = new Promise((complete, fail) => {
3006
+ resolve = complete;
3007
+ reject = fail;
3008
+ });
3009
+ const task = pending.finally(() => {
3010
+ if (this.disconnectTask === task) this.disconnectTask = void 0;
2957
3011
  });
2958
- await this.disconnectTask;
2959
- await this.announceDisconnect(error);
3012
+ this.disconnectTask = task;
3013
+ void this.tearDownConnection(error).then(resolve, reject);
3014
+ await task;
3015
+ this.announceDisconnect();
2960
3016
  }
2961
3017
  isCurrentConnection(connection, generation) {
2962
3018
  return !this.closeRequested && this.currentConnection === connection && this.connectionGeneration === generation;
2963
3019
  }
2964
3020
  /**
2965
3021
  * Ends the current connection, for close and for transport loss alike. No
2966
- * application callback runs from here. Spec stream-connector 32 §7 and §9:
3022
+ * application callback runs before terminal operations settle. Spec stream-connector 32 §7 and §9:
2967
3023
  * every operation the ending connection fails (the frames it has not
2968
3024
  * written, the one it is writing and the pending requests) fails with
2969
3025
  * `Disconnected`, whatever ended it; the cause stays in the close reason.
@@ -2984,7 +3040,31 @@ var ZlinkStreamConnectorLifecycle = class {
2984
3040
  this.pendingRequests.failAll(disconnected);
2985
3041
  this.receivedMessages.connectionEnded();
2986
3042
  this.actors.closeAll(signal);
2987
- await connection?.close(signal);
3043
+ await this.closeTransport(connection, error, signal);
3044
+ }
3045
+ async closeTransport(connection, error, signal) {
3046
+ try {
3047
+ try {
3048
+ await connection?.close(signal);
3049
+ } finally {
3050
+ this.setState(
3051
+ this.closeRequested ? "closed" /* Closed */ : "disconnected" /* Disconnected */,
3052
+ this.closeRequested ? void 0 : error,
3053
+ signal
3054
+ );
3055
+ }
3056
+ } catch (cause) {
3057
+ this.events.publishError(
3058
+ {
3059
+ code: "disconnected" /* Disconnected */,
3060
+ message: `Transport close failed: ${cause instanceof Error ? cause.message : String(cause)}`,
3061
+ cause
3062
+ },
3063
+ signal
3064
+ );
3065
+ } finally {
3066
+ this.publishDisconnected(signal);
3067
+ }
2988
3068
  }
2989
3069
  /**
2990
3070
  * Runs once the teardown promise has settled, so a handler reached from here
@@ -2994,10 +3074,7 @@ var ZlinkStreamConnectorLifecycle = class {
2994
3074
  * handler that is slow — or whose promise never settles at all — must not
2995
3075
  * cost the connector the attempt.
2996
3076
  */
2997
- async announceDisconnect(error) {
2998
- if (this.closeRequested) return;
2999
- this.setState("disconnected" /* Disconnected */, error);
3000
- this.publishDisconnected();
3077
+ announceDisconnect() {
3001
3078
  if (this.shouldReconnect()) {
3002
3079
  queueMicrotask(() => {
3003
3080
  void this.connect().catch(() => void 0);
@@ -3041,16 +3118,13 @@ var ZlinkStreamConnectorEvents = class {
3041
3118
  disconnectedHandlers = /* @__PURE__ */ new Set();
3042
3119
  stateHandlers = /* @__PURE__ */ new Set();
3043
3120
  onError(handler) {
3044
- this.errorHandlers.add(handler);
3045
- return subscription(() => this.errorHandlers.delete(handler));
3121
+ return registerHandler(this.errorHandlers, handler);
3046
3122
  }
3047
3123
  onDisconnected(handler) {
3048
- this.disconnectedHandlers.add(handler);
3049
- return subscription(() => this.disconnectedHandlers.delete(handler));
3124
+ return registerHandler(this.disconnectedHandlers, handler);
3050
3125
  }
3051
3126
  onStateChanged(handler) {
3052
- this.stateHandlers.add(handler);
3053
- return subscription(() => this.stateHandlers.delete(handler));
3127
+ return registerHandler(this.stateHandlers, handler);
3054
3128
  }
3055
3129
  publishError(error, signal) {
3056
3130
  this.publish(this.errorHandlers, (handler) => handler(error, signal), signal);
@@ -3078,13 +3152,13 @@ var ZlinkStreamConnectorEvents = class {
3078
3152
  publish(handlers, invoke, signal) {
3079
3153
  this.enqueueCallback(
3080
3154
  () => {
3081
- for (const handler of Array.from(handlers)) {
3155
+ for (const handler of currentRegistrations(handlers)) {
3082
3156
  const report = (cause) => this.reportFailure(
3083
3157
  cause,
3084
3158
  signal,
3085
3159
  handlers === this.errorHandlers ? handler : void 0
3086
3160
  );
3087
- this.invoke(() => invoke(handler), report);
3161
+ this.invoke(() => invoke(handler.handler), report);
3088
3162
  }
3089
3163
  },
3090
3164
  () => handlers.size
@@ -3107,15 +3181,22 @@ var ZlinkStreamConnectorEvents = class {
3107
3181
  (candidate) => !attempted.has(candidate)
3108
3182
  );
3109
3183
  if (remaining.length === 0) return;
3110
- const nextAttempted = /* @__PURE__ */ new Set([...attempted, ...remaining]);
3184
+ const nextAttempted = new Set(attempted);
3185
+ for (const handler of remaining) nextAttempted.add(handler);
3111
3186
  this.enqueueCallback(
3112
3187
  () => {
3113
- for (const handler of remaining) {
3188
+ for (const handler of currentRegistrations(this.errorHandlers, remaining)) {
3114
3189
  const report = (cause) => this.reportToRemaining({ ...error, cause }, signal, nextAttempted);
3115
- this.invoke(() => handler(error, signal), report);
3190
+ const callback = handler.handler;
3191
+ this.invoke(() => callback(error, signal), report);
3116
3192
  }
3117
3193
  },
3118
- () => remaining.length
3194
+ () => {
3195
+ let count = 0;
3196
+ const registrations = currentRegistrations(this.errorHandlers, remaining);
3197
+ while (registrations.next().done !== true) count += 1;
3198
+ return count;
3199
+ }
3119
3200
  );
3120
3201
  }
3121
3202
  invoke(run, report) {
@@ -3262,7 +3343,7 @@ var BrowserWebSocketConnection = class {
3262
3343
  const message = this.messages[this.messageHead];
3263
3344
  this.messages[this.messageHead] = void 0;
3264
3345
  this.messageHead += 1;
3265
- if (this.messageHead >= 1024 && this.messageHead * 2 >= this.messages.length) {
3346
+ if (shouldCompactBackingArray(this.messageHead, this.messages.length)) {
3266
3347
  this.messages.splice(0, this.messageHead);
3267
3348
  this.messageHead = 0;
3268
3349
  }
@@ -3277,8 +3358,8 @@ async function waitForOpen(socket, connectTimeoutMs, signal) {
3277
3358
  connectTimeoutMs
3278
3359
  );
3279
3360
  const onOpen = () => finish();
3280
- const onClose = () => finish(connectorError("connectTimeout" /* ConnectTimeout */, "Connect closed before opening."));
3281
- const onError = () => finish(connectorError("connectTimeout" /* ConnectTimeout */, "Connect failed."));
3361
+ const onClose = () => finish(connectorError("disconnected" /* Disconnected */, "Connect closed before opening."));
3362
+ const onError = () => finish(connectorError("disconnected" /* Disconnected */, "Connect failed."));
3282
3363
  const onAbort = () => finish(connectorError("disconnected" /* Disconnected */, "Connect canceled."));
3283
3364
  const finish = (error) => {
3284
3365
  clearTimeout(timeout);
@@ -3402,12 +3483,10 @@ var DefaultZlinkStreamConnector = class {
3402
3483
  return this.events.onStateChanged(handler);
3403
3484
  }
3404
3485
  onRequestSending(handler) {
3405
- this.requestSendingHandlers.add(handler);
3406
- return subscription(() => this.requestSendingHandlers.delete(handler));
3486
+ return registerHandler(this.requestSendingHandlers, handler);
3407
3487
  }
3408
3488
  onReplyReceived(handler) {
3409
- this.replyReceivedHandlers.add(handler);
3410
- return subscription(() => this.replyReceivedHandlers.delete(handler));
3489
+ return registerHandler(this.replyReceivedHandlers, handler);
3411
3490
  }
3412
3491
  async connect(signal) {
3413
3492
  await this.lifecycle.connect(signal);
@@ -3641,7 +3720,7 @@ var DefaultZlinkStreamConnector = class {
3641
3720
  let stopCancellation;
3642
3721
  try {
3643
3722
  throwIfAborted(signal);
3644
- for (const handler of Array.from(this.requestSendingHandlers)) {
3723
+ for (const { handler } of currentRegistrations(this.requestSendingHandlers)) {
3645
3724
  try {
3646
3725
  handler(sendingContext);
3647
3726
  } catch (cause) {
@@ -3713,7 +3792,7 @@ var DefaultZlinkStreamConnector = class {
3713
3792
  if (this.replyReceivedHandlers.size === 0) return;
3714
3793
  this.receivedMessages.enqueueCallback(
3715
3794
  () => {
3716
- for (const handler of Array.from(this.replyReceivedHandlers)) {
3795
+ for (const { handler } of currentRegistrations(this.replyReceivedHandlers)) {
3717
3796
  this.events.runUserCallback(
3718
3797
  () => handler(context, signal),
3719
3798
  "Reply received hook failed.",