@zlink-systems/stream-connector 0.26.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.
- package/dist/browser/Contracts/ZlinkStreamConnectorOptions.d.ts +1 -0
- package/dist/browser/Contracts/ZlinkStreamEnums.d.ts +3 -17
- package/dist/browser/Contracts/index.d.ts +1 -1
- package/dist/browser/Runtime/Protocol/ZlinkSessionClosing.d.ts +2 -7
- package/dist/browser/Runtime/Protocol/ZlinkStreamFrameProtocol.d.ts +3 -4
- package/dist/browser/Runtime/Protocol/ZlinkStreamMetadataCodec.d.ts +1 -3
- package/dist/browser/Runtime/Transport/BrowserWebSocketConnection.d.ts +1 -2
- package/dist/browser/Runtime/ZlinkStreamActors.d.ts +2 -3
- package/dist/browser/Runtime/ZlinkStreamConnector.d.ts +3 -3
- package/dist/browser/Runtime/ZlinkStreamConnectorLifecycle.d.ts +4 -6
- package/dist/browser/Runtime/ZlinkStreamConnectorOptions.d.ts +1 -0
- package/dist/browser/Runtime/ZlinkStreamReceivedMessages.d.ts +2 -1
- package/dist/browser/Runtime/ZlinkStreamSupport.d.ts +8 -7
- package/dist/browser/index.global.js +583 -507
- package/dist/browser/index.mjs +582 -503
- package/package.json +2 -2
package/dist/browser/index.mjs
CHANGED
|
@@ -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 <
|
|
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 +=
|
|
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++) +
|
|
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 !==
|
|
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 !==
|
|
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 >
|
|
284
|
+
if (header.length > UINT16_MAX) {
|
|
137
285
|
throw new Error("Stream header is too large.");
|
|
138
286
|
}
|
|
139
|
-
if (payload.length >
|
|
287
|
+
if (payload.length > UINT32_MAX) {
|
|
140
288
|
throw new Error("Stream payload is too large.");
|
|
141
289
|
}
|
|
142
|
-
const frame = new Uint8Array(
|
|
290
|
+
const frame = new Uint8Array(ZLINK_STREAM_FRAME_PREFIX_BYTES + header.length + payload.length);
|
|
143
291
|
writeUInt16BE(frame, 0, header.length);
|
|
144
|
-
writeUInt32BE(frame,
|
|
145
|
-
frame.set(header,
|
|
146
|
-
frame.set(payload,
|
|
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 <
|
|
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,
|
|
155
|
-
if (frame.length !==
|
|
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(
|
|
160
|
-
|
|
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
|
-
|
|
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 >
|
|
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 >
|
|
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 ?
|
|
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 +=
|
|
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 +=
|
|
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 +=
|
|
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 <
|
|
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 & ~
|
|
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 <
|
|
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 +=
|
|
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 (
|
|
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
|
|
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 <
|
|
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 +
|
|
444
|
+
flowId = asciiDecode(header.subarray(offset, offset + FLOW_ID_BYTES));
|
|
296
445
|
validateFlowId(flowId);
|
|
297
446
|
}
|
|
298
|
-
offset +=
|
|
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 <
|
|
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 +=
|
|
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
|
|
345
|
-
if (metadata.size >
|
|
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
|
|
350
|
-
const
|
|
351
|
-
const
|
|
352
|
-
if (
|
|
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 (
|
|
504
|
+
if (valueSize > UINT16_MAX) {
|
|
356
505
|
throw new Error("Metadata value is too large.");
|
|
357
506
|
}
|
|
358
|
-
size += 1 +
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
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
|
|
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 +=
|
|
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 <
|
|
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 +=
|
|
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 +=
|
|
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 (
|
|
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 ===
|
|
597
|
+
return kind === 3 /* Response */ || kind === 4 /* Error */;
|
|
451
598
|
}
|
|
452
599
|
function writeUInt16BE(buffer, offset, value) {
|
|
453
|
-
buffer[offset] = value >>> 8 &
|
|
454
|
-
buffer[offset + 1] = value &
|
|
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 &
|
|
464
|
-
buffer[offset + 1] = value >>> 16 &
|
|
465
|
-
buffer[offset + 2] = value >>> 8 &
|
|
466
|
-
buffer[offset + 3] = value &
|
|
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
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
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
|
-
|
|
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 (
|
|
709
|
-
failure
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
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
|
-
|
|
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 (
|
|
729
|
-
failure
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
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
|
-
|
|
744
|
-
|
|
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(
|
|
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 =
|
|
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
|
-
|
|
1444
|
+
try {
|
|
1445
|
+
return splitStreamWireFrames(chunk);
|
|
1446
|
+
} catch (cause) {
|
|
1154
1447
|
throw connectorError(
|
|
1155
1448
|
"frameDecodeFailed" /* FrameDecodeFailed */,
|
|
1156
|
-
"
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
1364
|
-
if (!
|
|
1607
|
+
function validateEnum(kind, codec) {
|
|
1608
|
+
if (!isStreamWireMessageKind(kind)) {
|
|
1365
1609
|
throw connectorError("frameDecodeFailed" /* FrameDecodeFailed */, "Unknown stream message kind.");
|
|
1366
1610
|
}
|
|
1367
|
-
if (!
|
|
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 =
|
|
1378
|
-
var ZLINK_STREAM_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 >
|
|
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 =
|
|
1692
|
-
var 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
|
|
1746
|
-
return subscription(() => this.boundHandlers.delete(handler));
|
|
1834
|
+
return registerHandler(this.boundHandlers, handler);
|
|
1747
1835
|
}
|
|
1748
1836
|
onUnbound(handler) {
|
|
1749
|
-
this.unboundHandlers
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
1871
|
+
binding = decodeStreamWireActorBoundPayload(payload);
|
|
1795
1872
|
} catch (cause) {
|
|
1796
1873
|
throw connectorError(
|
|
1797
1874
|
"frameDecodeFailed" /* FrameDecodeFailed */,
|
|
1798
|
-
"Actor
|
|
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
|
-
|
|
1813
|
-
|
|
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
|
|
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
|
-
|
|
2168
|
-
|
|
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.
|
|
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 =
|
|
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 =
|
|
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 */
|
|
2562
|
+
if (header.kind === 4 /* Error */) {
|
|
2563
|
+
let error;
|
|
2492
2564
|
try {
|
|
2493
|
-
|
|
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
|
-
|
|
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
|
-
|
|
2509
|
-
|
|
2510
|
-
|
|
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 =
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
2733
|
-
|
|
2734
|
-
|
|
2735
|
-
|
|
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
|
-
|
|
2955
|
-
|
|
2956
|
-
|
|
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
|
-
|
|
2959
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
3045
|
-
return subscription(() => this.errorHandlers.delete(handler));
|
|
3121
|
+
return registerHandler(this.errorHandlers, handler);
|
|
3046
3122
|
}
|
|
3047
3123
|
onDisconnected(handler) {
|
|
3048
|
-
this.disconnectedHandlers
|
|
3049
|
-
return subscription(() => this.disconnectedHandlers.delete(handler));
|
|
3124
|
+
return registerHandler(this.disconnectedHandlers, handler);
|
|
3050
3125
|
}
|
|
3051
3126
|
onStateChanged(handler) {
|
|
3052
|
-
this.stateHandlers
|
|
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
|
|
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 =
|
|
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
|
-
|
|
3190
|
+
const callback = handler.handler;
|
|
3191
|
+
this.invoke(() => callback(error, signal), report);
|
|
3116
3192
|
}
|
|
3117
3193
|
},
|
|
3118
|
-
() =>
|
|
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
|
|
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("
|
|
3281
|
-
const onError = () => finish(connectorError("
|
|
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
|
|
3406
|
-
return subscription(() => this.requestSendingHandlers.delete(handler));
|
|
3486
|
+
return registerHandler(this.requestSendingHandlers, handler);
|
|
3407
3487
|
}
|
|
3408
3488
|
onReplyReceived(handler) {
|
|
3409
|
-
this.replyReceivedHandlers
|
|
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
|
|
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
|
|
3795
|
+
for (const { handler } of currentRegistrations(this.replyReceivedHandlers)) {
|
|
3717
3796
|
this.events.runUserCallback(
|
|
3718
3797
|
() => handler(context, signal),
|
|
3719
3798
|
"Reply received hook failed.",
|