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