@zlink-systems/stream-wire 0.26.0 → 0.28.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/index.d.ts +68 -0
- package/dist/esm/index.mjs +309 -73
- package/dist/index.d.ts +68 -0
- package/dist/index.js +304 -72
- package/dist/lz4-pickle.js +9 -5
- package/package.json +1 -1
package/dist/esm/index.mjs
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
// packages/stream-wire/src/lz4-pickle.ts
|
|
2
|
+
var LZ4_MIN_MATCH_LENGTH = 4;
|
|
3
|
+
var LZ4_MATCH_OFFSET_BYTES = 2;
|
|
4
|
+
var LZ4_EXTENDED_LENGTH_NIBBLE = 15;
|
|
5
|
+
var LZ4_EXTENDED_LENGTH_BYTE = 255;
|
|
2
6
|
var defaultMaxDecompressedPayloadSize = 64 * 1024;
|
|
3
7
|
function lz4PickleUncompressed(payload) {
|
|
4
8
|
if (payload.length === 0) {
|
|
@@ -74,15 +78,15 @@ function decodeLz4Block(source, resultLength) {
|
|
|
74
78
|
if (sourceOffset >= source.length) {
|
|
75
79
|
break;
|
|
76
80
|
}
|
|
77
|
-
if (source.length - sourceOffset <
|
|
81
|
+
if (source.length - sourceOffset < LZ4_MATCH_OFFSET_BYTES) {
|
|
78
82
|
throw new Error("LZ4 match offset is incomplete.");
|
|
79
83
|
}
|
|
80
84
|
const matchOffset = source[sourceOffset] | source[sourceOffset + 1] << 8;
|
|
81
|
-
sourceOffset +=
|
|
85
|
+
sourceOffset += LZ4_MATCH_OFFSET_BYTES;
|
|
82
86
|
if (matchOffset === 0 || matchOffset > targetOffset) {
|
|
83
87
|
throw new Error("LZ4 match offset is invalid.");
|
|
84
88
|
}
|
|
85
|
-
const matchLength = readLz4Length(source, token & 15, () => sourceOffset++) +
|
|
89
|
+
const matchLength = readLz4Length(source, token & 15, () => sourceOffset++) + LZ4_MIN_MATCH_LENGTH;
|
|
86
90
|
if (target.length - targetOffset < matchLength) {
|
|
87
91
|
throw new Error("LZ4 match run exceeds output size.");
|
|
88
92
|
}
|
|
@@ -98,7 +102,7 @@ function decodeLz4Block(source, resultLength) {
|
|
|
98
102
|
}
|
|
99
103
|
function readLz4Length(source, nibble, nextOffset) {
|
|
100
104
|
let length = nibble;
|
|
101
|
-
if (length !==
|
|
105
|
+
if (length !== LZ4_EXTENDED_LENGTH_NIBBLE) {
|
|
102
106
|
return length;
|
|
103
107
|
}
|
|
104
108
|
for (; ; ) {
|
|
@@ -108,7 +112,7 @@ function readLz4Length(source, nibble, nextOffset) {
|
|
|
108
112
|
}
|
|
109
113
|
const value = source[offset];
|
|
110
114
|
length += value;
|
|
111
|
-
if (value !==
|
|
115
|
+
if (value !== LZ4_EXTENDED_LENGTH_BYTE) {
|
|
112
116
|
return length;
|
|
113
117
|
}
|
|
114
118
|
}
|
|
@@ -122,68 +126,257 @@ var ZlinkStreamCodec = /* @__PURE__ */ ((ZlinkStreamCodec2) => {
|
|
|
122
126
|
ZlinkStreamCodec2[ZlinkStreamCodec2["Protobuf"] = 3] = "Protobuf";
|
|
123
127
|
return ZlinkStreamCodec2;
|
|
124
128
|
})(ZlinkStreamCodec || {});
|
|
129
|
+
var ZlinkStreamMessageKind = /* @__PURE__ */ ((ZlinkStreamMessageKind2) => {
|
|
130
|
+
ZlinkStreamMessageKind2[ZlinkStreamMessageKind2["Send"] = 1] = "Send";
|
|
131
|
+
ZlinkStreamMessageKind2[ZlinkStreamMessageKind2["Request"] = 2] = "Request";
|
|
132
|
+
ZlinkStreamMessageKind2[ZlinkStreamMessageKind2["Response"] = 3] = "Response";
|
|
133
|
+
ZlinkStreamMessageKind2[ZlinkStreamMessageKind2["Error"] = 4] = "Error";
|
|
134
|
+
ZlinkStreamMessageKind2[ZlinkStreamMessageKind2["Control"] = 5] = "Control";
|
|
135
|
+
return ZlinkStreamMessageKind2;
|
|
136
|
+
})(ZlinkStreamMessageKind || {});
|
|
137
|
+
var ZlinkStreamHeaderFlags = /* @__PURE__ */ ((ZlinkStreamHeaderFlags2) => {
|
|
138
|
+
ZlinkStreamHeaderFlags2[ZlinkStreamHeaderFlags2["None"] = 0] = "None";
|
|
139
|
+
ZlinkStreamHeaderFlags2[ZlinkStreamHeaderFlags2["HasRequestSeq"] = 1] = "HasRequestSeq";
|
|
140
|
+
ZlinkStreamHeaderFlags2[ZlinkStreamHeaderFlags2["HasMetadata"] = 2] = "HasMetadata";
|
|
141
|
+
ZlinkStreamHeaderFlags2[ZlinkStreamHeaderFlags2["PayloadCompressed"] = 4] = "PayloadCompressed";
|
|
142
|
+
ZlinkStreamHeaderFlags2[ZlinkStreamHeaderFlags2["HasCorrelationId"] = 8] = "HasCorrelationId";
|
|
143
|
+
ZlinkStreamHeaderFlags2[ZlinkStreamHeaderFlags2["HasFlowId"] = 16] = "HasFlowId";
|
|
144
|
+
ZlinkStreamHeaderFlags2[ZlinkStreamHeaderFlags2["HasActorSlot"] = 32] = "HasActorSlot";
|
|
145
|
+
return ZlinkStreamHeaderFlags2;
|
|
146
|
+
})(ZlinkStreamHeaderFlags || {});
|
|
147
|
+
var ZlinkStreamCloseReasonCode = /* @__PURE__ */ ((ZlinkStreamCloseReasonCode2) => {
|
|
148
|
+
ZlinkStreamCloseReasonCode2[ZlinkStreamCloseReasonCode2["ClientClose"] = 1] = "ClientClose";
|
|
149
|
+
ZlinkStreamCloseReasonCode2[ZlinkStreamCloseReasonCode2["IdleTimeout"] = 2] = "IdleTimeout";
|
|
150
|
+
ZlinkStreamCloseReasonCode2[ZlinkStreamCloseReasonCode2["HeartbeatTimeout"] = 3] = "HeartbeatTimeout";
|
|
151
|
+
ZlinkStreamCloseReasonCode2[ZlinkStreamCloseReasonCode2["ServerDrain"] = 4] = "ServerDrain";
|
|
152
|
+
ZlinkStreamCloseReasonCode2[ZlinkStreamCloseReasonCode2["ProtocolError"] = 5] = "ProtocolError";
|
|
153
|
+
ZlinkStreamCloseReasonCode2[ZlinkStreamCloseReasonCode2["TransportError"] = 6] = "TransportError";
|
|
154
|
+
return ZlinkStreamCloseReasonCode2;
|
|
155
|
+
})(ZlinkStreamCloseReasonCode || {});
|
|
156
|
+
var unicodeWhiteSpaceOnly = /^\p{White_Space}*$/u;
|
|
157
|
+
var validMessageKinds = new Set(
|
|
158
|
+
Object.values(ZlinkStreamMessageKind).filter((value) => typeof value === "number")
|
|
159
|
+
);
|
|
160
|
+
var validCodecs = new Set(
|
|
161
|
+
Object.values(ZlinkStreamCodec).filter((value) => typeof value === "number")
|
|
162
|
+
);
|
|
163
|
+
function isStreamWireMessageKind(value) {
|
|
164
|
+
return validMessageKinds.has(value);
|
|
165
|
+
}
|
|
166
|
+
function isStreamWireCodec(value) {
|
|
167
|
+
return validCodecs.has(value);
|
|
168
|
+
}
|
|
169
|
+
var UTF8_TWO_BYTE_MIN = 128;
|
|
170
|
+
var UTF8_THREE_BYTE_MIN = 2048;
|
|
171
|
+
var UTF16_HIGH_SURROGATE_MIN = 55296;
|
|
172
|
+
var UTF16_HIGH_SURROGATE_MAX = 56319;
|
|
173
|
+
var UTF16_LOW_SURROGATE_MIN = 56320;
|
|
174
|
+
var UTF16_LOW_SURROGATE_MAX = 57343;
|
|
175
|
+
var UINT8_MAX = 255;
|
|
176
|
+
var UINT16_MAX = 65535;
|
|
177
|
+
var UINT16_BYTES = 2;
|
|
178
|
+
var UINT32_BYTES = 4;
|
|
179
|
+
var UINT64_BYTES = 8;
|
|
180
|
+
var UINT64_MAX = 0xffffffffffffffffn;
|
|
181
|
+
var UINT32_MAX = 4294967295;
|
|
182
|
+
var ZLINK_STREAM_FRAME_PREFIX_BYTES = UINT16_BYTES + UINT32_BYTES;
|
|
183
|
+
var ZLINK_STREAM_MAX_PACKET_NAME_BYTES = UINT8_MAX;
|
|
184
|
+
var ZLINK_STREAM_MAX_METADATA_BYTES = 1024;
|
|
185
|
+
var FLOW_ID_BYTES = 36;
|
|
186
|
+
var FLOW_FIELDS_BYTES = FLOW_ID_BYTES + 1;
|
|
187
|
+
var HEADER_MIN_BYTES = 5;
|
|
188
|
+
var HEADER_FLAG_MASK = 1 /* HasRequestSeq */ | 2 /* HasMetadata */ | 4 /* PayloadCompressed */ | 8 /* HasCorrelationId */ | 16 /* HasFlowId */ | 32 /* HasActorSlot */;
|
|
189
|
+
var CONTROL_PAYLOAD_VERSION = 1;
|
|
190
|
+
var ACTOR_SLOT_OFFSET = 1;
|
|
191
|
+
var ACTOR_ID_LENGTH_OFFSET = ACTOR_SLOT_OFFSET + UINT16_BYTES;
|
|
192
|
+
var ACTOR_BOUND_PREFIX_BYTES = ACTOR_ID_LENGTH_OFFSET + 1;
|
|
193
|
+
var ACTOR_UNBOUND_BYTES = ACTOR_SLOT_OFFSET + UINT16_BYTES;
|
|
194
|
+
var CLOSING_DIAGNOSTIC_LENGTH_OFFSET = 2;
|
|
195
|
+
var CLOSING_PREFIX_BYTES = CLOSING_DIAGNOSTIC_LENGTH_OFFSET + UINT16_BYTES;
|
|
196
|
+
var MAX_CLOSING_DIAGNOSTIC_BYTES = 512;
|
|
197
|
+
function encodeStreamWireActorBoundPayload(actorSlot, actorId) {
|
|
198
|
+
const actorIdBytes = utf8Encode(actorId);
|
|
199
|
+
if (actorIdBytes.length < 1 || actorIdBytes.length > UINT8_MAX) {
|
|
200
|
+
throw new Error("Actor id length is invalid for a STREAM binding control packet.");
|
|
201
|
+
}
|
|
202
|
+
const payload = new Uint8Array(ACTOR_BOUND_PREFIX_BYTES + actorIdBytes.length);
|
|
203
|
+
payload[0] = CONTROL_PAYLOAD_VERSION;
|
|
204
|
+
writeUInt16BE(payload, ACTOR_SLOT_OFFSET, actorSlot);
|
|
205
|
+
payload[ACTOR_ID_LENGTH_OFFSET] = actorIdBytes.length;
|
|
206
|
+
payload.set(actorIdBytes, ACTOR_BOUND_PREFIX_BYTES);
|
|
207
|
+
return payload;
|
|
208
|
+
}
|
|
209
|
+
function decodeStreamWireActorBoundPayload(payload) {
|
|
210
|
+
if (payload.length < ACTOR_BOUND_PREFIX_BYTES + 1 || payload[0] !== CONTROL_PAYLOAD_VERSION) {
|
|
211
|
+
throw new Error("Actor bound payload is invalid.");
|
|
212
|
+
}
|
|
213
|
+
const slot = readUInt16BE(payload, ACTOR_SLOT_OFFSET);
|
|
214
|
+
const idLength = payload[ACTOR_ID_LENGTH_OFFSET];
|
|
215
|
+
if (slot === 0 || idLength === 0 || payload.length !== ACTOR_BOUND_PREFIX_BYTES + idLength) {
|
|
216
|
+
throw new Error("Actor bound payload is invalid.");
|
|
217
|
+
}
|
|
218
|
+
try {
|
|
219
|
+
return { slot, actorId: decodeControlText(payload.subarray(ACTOR_BOUND_PREFIX_BYTES)) };
|
|
220
|
+
} catch (cause) {
|
|
221
|
+
throw new Error("Actor id is not valid UTF-8.", { cause });
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
function encodeStreamWireActorUnboundPayload(actorSlot) {
|
|
225
|
+
const payload = new Uint8Array(ACTOR_UNBOUND_BYTES);
|
|
226
|
+
payload[0] = CONTROL_PAYLOAD_VERSION;
|
|
227
|
+
writeUInt16BE(payload, ACTOR_SLOT_OFFSET, actorSlot);
|
|
228
|
+
return payload;
|
|
229
|
+
}
|
|
230
|
+
function decodeStreamWireActorUnboundPayload(payload) {
|
|
231
|
+
if (payload.length !== ACTOR_UNBOUND_BYTES || payload[0] !== CONTROL_PAYLOAD_VERSION) {
|
|
232
|
+
throw new Error("Actor unbound payload is invalid.");
|
|
233
|
+
}
|
|
234
|
+
return readUInt16BE(payload, ACTOR_SLOT_OFFSET);
|
|
235
|
+
}
|
|
236
|
+
function encodeStreamWireSessionClosingPayload(reasonCode, diagnostic = "") {
|
|
237
|
+
const bytes = utf8Encode(diagnostic);
|
|
238
|
+
if (bytes.length > MAX_CLOSING_DIAGNOSTIC_BYTES) {
|
|
239
|
+
throw new Error("Session-closing diagnostic is too large.");
|
|
240
|
+
}
|
|
241
|
+
const payload = new Uint8Array(CLOSING_PREFIX_BYTES + bytes.length);
|
|
242
|
+
payload[0] = CONTROL_PAYLOAD_VERSION;
|
|
243
|
+
payload[1] = reasonCode;
|
|
244
|
+
writeUInt16BE(payload, CLOSING_DIAGNOSTIC_LENGTH_OFFSET, bytes.length);
|
|
245
|
+
payload.set(bytes, CLOSING_PREFIX_BYTES);
|
|
246
|
+
return payload;
|
|
247
|
+
}
|
|
248
|
+
function decodeStreamWireSessionClosing(payload) {
|
|
249
|
+
if (payload.length < CLOSING_PREFIX_BYTES || payload[0] !== CONTROL_PAYLOAD_VERSION) {
|
|
250
|
+
throw new Error("Unsupported session-closing version.");
|
|
251
|
+
}
|
|
252
|
+
const closeReason = ZlinkStreamCloseReasonCode[payload[1]];
|
|
253
|
+
if (closeReason === void 0) throw new Error("Unknown session-closing reason.");
|
|
254
|
+
const length = readUInt16BE(payload, CLOSING_DIAGNOSTIC_LENGTH_OFFSET);
|
|
255
|
+
if (length > MAX_CLOSING_DIAGNOSTIC_BYTES || payload.length !== CLOSING_PREFIX_BYTES + length) {
|
|
256
|
+
throw new Error("Invalid session-closing diagnostic length.");
|
|
257
|
+
}
|
|
258
|
+
const diagnostic = length === 0 ? void 0 : decodeControlText(payload.subarray(CLOSING_PREFIX_BYTES));
|
|
259
|
+
return { closeReason, diagnostic };
|
|
260
|
+
}
|
|
261
|
+
function decodeControlText(value) {
|
|
262
|
+
return new TextDecoder("utf-8", { fatal: true }).decode(value);
|
|
263
|
+
}
|
|
264
|
+
function splitStreamWireFrames(chunk) {
|
|
265
|
+
if (chunk.length === 0) throw new Error("Stream frame prefix is incomplete.");
|
|
266
|
+
const frames = [];
|
|
267
|
+
let offset = 0;
|
|
268
|
+
while (offset < chunk.length) {
|
|
269
|
+
const remaining = chunk.length - offset;
|
|
270
|
+
if (remaining < ZLINK_STREAM_FRAME_PREFIX_BYTES) {
|
|
271
|
+
throw new Error("Stream frame prefix is incomplete.");
|
|
272
|
+
}
|
|
273
|
+
const headerLength = readUInt16BE(chunk, offset);
|
|
274
|
+
const payloadLength = readUInt32BE(chunk, offset + UINT16_BYTES);
|
|
275
|
+
const frameLength = ZLINK_STREAM_FRAME_PREFIX_BYTES + headerLength + payloadLength;
|
|
276
|
+
if (frameLength > remaining) throw new Error("Frame length does not match prefix.");
|
|
277
|
+
frames.push(chunk.subarray(offset, offset + frameLength));
|
|
278
|
+
offset += frameLength;
|
|
279
|
+
}
|
|
280
|
+
return frames;
|
|
281
|
+
}
|
|
282
|
+
var ZLINK_STREAM_RESERVED_PACKET_NAME_PREFIX = "$zlink.";
|
|
283
|
+
var ZlinkStreamControlPacket = Object.freeze({
|
|
284
|
+
HeartbeatPing: `${ZLINK_STREAM_RESERVED_PACKET_NAME_PREFIX}heartbeat.ping`,
|
|
285
|
+
HeartbeatPong: `${ZLINK_STREAM_RESERVED_PACKET_NAME_PREFIX}heartbeat.pong`,
|
|
286
|
+
ActorBound: `${ZLINK_STREAM_RESERVED_PACKET_NAME_PREFIX}actor.bound`,
|
|
287
|
+
ActorUnbound: `${ZLINK_STREAM_RESERVED_PACKET_NAME_PREFIX}actor.unbound`,
|
|
288
|
+
SessionClosing: "session-closing"
|
|
289
|
+
});
|
|
290
|
+
var ZlinkStreamContentType = Object.freeze({
|
|
291
|
+
Raw: "application/octet-stream",
|
|
292
|
+
Json: "application/json",
|
|
293
|
+
MessagePack: "application/x-msgpack",
|
|
294
|
+
Protobuf: "application/x-protobuf"
|
|
295
|
+
});
|
|
296
|
+
var contentTypesByCodec = /* @__PURE__ */ new Map([
|
|
297
|
+
[0 /* Raw */, ZlinkStreamContentType.Raw],
|
|
298
|
+
[1 /* Json */, ZlinkStreamContentType.Json],
|
|
299
|
+
[2 /* MessagePack */, ZlinkStreamContentType.MessagePack],
|
|
300
|
+
[3 /* Protobuf */, ZlinkStreamContentType.Protobuf]
|
|
301
|
+
]);
|
|
302
|
+
var codecsByContentType = new Map(
|
|
303
|
+
Array.from(contentTypesByCodec, ([codec, contentType]) => [contentType, codec])
|
|
304
|
+
);
|
|
305
|
+
function streamCodecContentType(codec) {
|
|
306
|
+
const contentType = contentTypesByCodec.get(codec);
|
|
307
|
+
if (contentType === void 0) throw new TypeError(`Unsupported STREAM codec '${codec}'.`);
|
|
308
|
+
return contentType;
|
|
309
|
+
}
|
|
310
|
+
function streamCodecForContentType(contentType) {
|
|
311
|
+
const codec = codecsByContentType.get(contentType);
|
|
312
|
+
if (codec === void 0) throw new TypeError(`Unsupported STREAM content type '${contentType}'.`);
|
|
313
|
+
return codec;
|
|
314
|
+
}
|
|
125
315
|
var defaultHeaderFlags = {
|
|
126
|
-
hasRequestSeq: 1
|
|
127
|
-
hasMetadata: 2
|
|
128
|
-
hasCorrelationId: 8
|
|
129
|
-
hasFlowId: 16
|
|
130
|
-
hasActorSlot: 32
|
|
316
|
+
hasRequestSeq: 1 /* HasRequestSeq */,
|
|
317
|
+
hasMetadata: 2 /* HasMetadata */,
|
|
318
|
+
hasCorrelationId: 8 /* HasCorrelationId */,
|
|
319
|
+
hasFlowId: 16 /* HasFlowId */,
|
|
320
|
+
hasActorSlot: 32 /* HasActorSlot */
|
|
131
321
|
};
|
|
132
322
|
var ZLINK_STREAM_FORMAT_MARKER = 242;
|
|
133
|
-
var ZLINK_STREAM_RESPONSE_KIND = 3;
|
|
134
|
-
var ZLINK_STREAM_ERROR_KIND = 4;
|
|
135
323
|
function encodeStreamWireFrame(header, payload) {
|
|
136
|
-
if (header.length >
|
|
324
|
+
if (header.length > UINT16_MAX) {
|
|
137
325
|
throw new Error("Stream header is too large.");
|
|
138
326
|
}
|
|
139
|
-
if (payload.length >
|
|
327
|
+
if (payload.length > UINT32_MAX) {
|
|
140
328
|
throw new Error("Stream payload is too large.");
|
|
141
329
|
}
|
|
142
|
-
const frame = new Uint8Array(
|
|
330
|
+
const frame = new Uint8Array(ZLINK_STREAM_FRAME_PREFIX_BYTES + header.length + payload.length);
|
|
143
331
|
writeUInt16BE(frame, 0, header.length);
|
|
144
|
-
writeUInt32BE(frame,
|
|
145
|
-
frame.set(header,
|
|
146
|
-
frame.set(payload,
|
|
332
|
+
writeUInt32BE(frame, UINT16_BYTES, payload.length);
|
|
333
|
+
frame.set(header, ZLINK_STREAM_FRAME_PREFIX_BYTES);
|
|
334
|
+
frame.set(payload, ZLINK_STREAM_FRAME_PREFIX_BYTES + header.length);
|
|
147
335
|
return frame;
|
|
148
336
|
}
|
|
149
337
|
function decodeStreamWireFrame(frame) {
|
|
150
|
-
if (frame.length <
|
|
338
|
+
if (frame.length < ZLINK_STREAM_FRAME_PREFIX_BYTES) {
|
|
151
339
|
throw new Error("Stream frame prefix is incomplete.");
|
|
152
340
|
}
|
|
153
341
|
const headerLength = readUInt16BE(frame, 0);
|
|
154
|
-
const payloadLength = readUInt32BE(frame,
|
|
155
|
-
if (frame.length !==
|
|
342
|
+
const payloadLength = readUInt32BE(frame, UINT16_BYTES);
|
|
343
|
+
if (frame.length !== ZLINK_STREAM_FRAME_PREFIX_BYTES + headerLength + payloadLength) {
|
|
156
344
|
throw new Error("Stream frame length does not match prefix.");
|
|
157
345
|
}
|
|
158
346
|
return {
|
|
159
|
-
header: frame.slice(
|
|
160
|
-
|
|
347
|
+
header: frame.slice(
|
|
348
|
+
ZLINK_STREAM_FRAME_PREFIX_BYTES,
|
|
349
|
+
ZLINK_STREAM_FRAME_PREFIX_BYTES + headerLength
|
|
350
|
+
),
|
|
351
|
+
payload: frame.slice(ZLINK_STREAM_FRAME_PREFIX_BYTES + headerLength)
|
|
161
352
|
};
|
|
162
353
|
}
|
|
163
354
|
function tryDecodeStreamWireFrame(frame) {
|
|
164
|
-
if (frame.length <
|
|
355
|
+
if (frame.length < ZLINK_STREAM_FRAME_PREFIX_BYTES) {
|
|
165
356
|
return void 0;
|
|
166
357
|
}
|
|
167
358
|
const headerLength = readUInt16BE(frame, 0);
|
|
168
|
-
const payloadLength = readUInt32BE(frame,
|
|
169
|
-
if (frame.length !==
|
|
359
|
+
const payloadLength = readUInt32BE(frame, UINT16_BYTES);
|
|
360
|
+
if (frame.length !== ZLINK_STREAM_FRAME_PREFIX_BYTES + headerLength + payloadLength) {
|
|
170
361
|
return void 0;
|
|
171
362
|
}
|
|
172
363
|
return {
|
|
173
|
-
header: frame.slice(
|
|
174
|
-
|
|
364
|
+
header: frame.slice(
|
|
365
|
+
ZLINK_STREAM_FRAME_PREFIX_BYTES,
|
|
366
|
+
ZLINK_STREAM_FRAME_PREFIX_BYTES + headerLength
|
|
367
|
+
),
|
|
368
|
+
payload: frame.slice(ZLINK_STREAM_FRAME_PREFIX_BYTES + headerLength)
|
|
175
369
|
};
|
|
176
370
|
}
|
|
177
371
|
function encodeStreamWireHeader(header, flagOverrides) {
|
|
178
372
|
const flags = flagOverrides ?? defaultHeaderFlags;
|
|
179
373
|
const reply = isReplyKind(header.kind);
|
|
180
374
|
const packetName = reply ? "" : header.name;
|
|
181
|
-
|
|
182
|
-
const nameBytes = utf8Encode(packetName);
|
|
375
|
+
const nameBytes = reply ? new Uint8Array() : validateStreamWirePacketName(packetName);
|
|
183
376
|
const hasRequestSeq = header.requestSeq !== void 0;
|
|
184
377
|
const hasMetadata = header.metadata.size > 0;
|
|
185
378
|
const correlationBytes = header.correlationId !== void 0 && header.correlationId.length > 0 ? utf8Encode(header.correlationId) : void 0;
|
|
186
|
-
if (correlationBytes !== void 0 && correlationBytes.length >
|
|
379
|
+
if (correlationBytes !== void 0 && correlationBytes.length > UINT8_MAX) {
|
|
187
380
|
throw new Error("Stream correlation id is too large.");
|
|
188
381
|
}
|
|
189
382
|
const hasCorrelation = correlationBytes !== void 0;
|
|
@@ -196,7 +389,7 @@ function encodeStreamWireHeader(header, flagOverrides) {
|
|
|
196
389
|
if (header.flowOrigin !== void 0 && ![1, 2, 3, 4].includes(header.flowOrigin)) {
|
|
197
390
|
throw new Error("Stream flow origin is invalid.");
|
|
198
391
|
}
|
|
199
|
-
if (header.actorSlot !== void 0 && (!Number.isInteger(header.actorSlot) || header.actorSlot < 1 || header.actorSlot >
|
|
392
|
+
if (header.actorSlot !== void 0 && (!Number.isInteger(header.actorSlot) || header.actorSlot < 1 || header.actorSlot > UINT16_MAX)) {
|
|
200
393
|
throw new Error("Stream actor slot is invalid.");
|
|
201
394
|
}
|
|
202
395
|
let headerFlags = header.flags;
|
|
@@ -206,7 +399,7 @@ function encodeStreamWireHeader(header, flagOverrides) {
|
|
|
206
399
|
headerFlags = hasFlow ? headerFlags | flags.hasFlowId : headerFlags & ~flags.hasFlowId;
|
|
207
400
|
headerFlags = hasActorSlot ? headerFlags | flags.hasActorSlot : headerFlags & ~flags.hasActorSlot;
|
|
208
401
|
const metadataBytes = hasMetadata ? encodeStreamWireMetadata(header.metadata) : new Uint8Array();
|
|
209
|
-
const size = 4 + (hasRequestSeq ?
|
|
402
|
+
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);
|
|
210
403
|
const buffer = new Uint8Array(size);
|
|
211
404
|
let offset = 0;
|
|
212
405
|
buffer[offset++] = ZLINK_STREAM_FORMAT_MARKER;
|
|
@@ -218,14 +411,14 @@ function encodeStreamWireHeader(header, flagOverrides) {
|
|
|
218
411
|
throw new Error("Request sequence must not be zero.");
|
|
219
412
|
}
|
|
220
413
|
writeBigUInt64BE(buffer, offset, header.requestSeq);
|
|
221
|
-
offset +=
|
|
414
|
+
offset += UINT64_BYTES;
|
|
222
415
|
}
|
|
223
416
|
buffer[offset++] = nameBytes.length;
|
|
224
417
|
buffer.set(nameBytes, offset);
|
|
225
418
|
offset += nameBytes.length;
|
|
226
419
|
if (hasMetadata) {
|
|
227
420
|
writeUInt16BE(buffer, offset, metadataBytes.length);
|
|
228
|
-
offset +=
|
|
421
|
+
offset += UINT16_BYTES;
|
|
229
422
|
buffer.set(metadataBytes, offset);
|
|
230
423
|
offset += metadataBytes.length;
|
|
231
424
|
}
|
|
@@ -236,7 +429,7 @@ function encodeStreamWireHeader(header, flagOverrides) {
|
|
|
236
429
|
}
|
|
237
430
|
if (hasFlow) {
|
|
238
431
|
buffer.set(asciiEncode(header.flowId), offset);
|
|
239
|
-
offset +=
|
|
432
|
+
offset += FLOW_ID_BYTES;
|
|
240
433
|
buffer[offset++] = header.flowOrigin;
|
|
241
434
|
}
|
|
242
435
|
if (hasActorSlot) {
|
|
@@ -247,7 +440,7 @@ function encodeStreamWireHeader(header, flagOverrides) {
|
|
|
247
440
|
function decodeStreamWireHeader(header, flagOverrides, includeFlow = true) {
|
|
248
441
|
const flags = flagOverrides ?? defaultHeaderFlags;
|
|
249
442
|
let offset = 0;
|
|
250
|
-
if (header.length <
|
|
443
|
+
if (header.length < HEADER_MIN_BYTES) {
|
|
251
444
|
throw new Error("Stream header is incomplete.");
|
|
252
445
|
}
|
|
253
446
|
if (header[offset++] !== ZLINK_STREAM_FORMAT_MARKER) {
|
|
@@ -261,29 +454,28 @@ function decodeStreamWireHeader(header, flagOverrides, includeFlow = true) {
|
|
|
261
454
|
const hasCorrelation = (headerFlags & flags.hasCorrelationId) !== 0;
|
|
262
455
|
const hasFlow = (headerFlags & flags.hasFlowId) !== 0;
|
|
263
456
|
const hasActorSlot = (headerFlags & flags.hasActorSlot) !== 0;
|
|
264
|
-
if ((headerFlags & ~
|
|
457
|
+
if ((headerFlags & ~HEADER_FLAG_MASK) !== 0) {
|
|
265
458
|
throw new Error("Unknown mandatory stream header flag.");
|
|
266
459
|
}
|
|
267
460
|
let requestSeq;
|
|
268
461
|
if (hasRequestSeq) {
|
|
269
|
-
if (header.length - offset <
|
|
462
|
+
if (header.length - offset < UINT64_BYTES) {
|
|
270
463
|
throw new Error("Stream request sequence is incomplete.");
|
|
271
464
|
}
|
|
272
465
|
requestSeq = readBigUInt64BE(header, offset);
|
|
273
466
|
if (requestSeq === 0n) {
|
|
274
467
|
throw new Error("Request sequence must not be zero.");
|
|
275
468
|
}
|
|
276
|
-
offset +=
|
|
469
|
+
offset += UINT64_BYTES;
|
|
277
470
|
}
|
|
278
471
|
if (header.length - offset < 1) {
|
|
279
472
|
throw new Error("Stream packet name length is missing.");
|
|
280
473
|
}
|
|
281
474
|
const nameLength = header[offset++];
|
|
282
|
-
if (
|
|
475
|
+
if ((isReplyKind(kind) ? nameLength !== 0 : nameLength === 0) || header.length - offset < nameLength) {
|
|
283
476
|
throw new Error("Stream packet name is invalid.");
|
|
284
477
|
}
|
|
285
|
-
const
|
|
286
|
-
const name = isReplyKind(kind) ? "" : decodedName;
|
|
478
|
+
const name = utf8Decode(header.subarray(offset, offset + nameLength));
|
|
287
479
|
offset += nameLength;
|
|
288
480
|
const decodedMetadata = hasMetadata ? decodeStreamWireHeaderMetadata(header, offset) : { metadata: /* @__PURE__ */ new Map(), offset };
|
|
289
481
|
offset = decodedMetadata.offset;
|
|
@@ -302,14 +494,14 @@ function decodeStreamWireHeader(header, flagOverrides, includeFlow = true) {
|
|
|
302
494
|
let flowId;
|
|
303
495
|
let flowOrigin;
|
|
304
496
|
if (hasFlow) {
|
|
305
|
-
if (header.length - offset <
|
|
497
|
+
if (header.length - offset < FLOW_FIELDS_BYTES) {
|
|
306
498
|
throw new Error("Stream flow fields are incomplete.");
|
|
307
499
|
}
|
|
308
500
|
if (includeFlow) {
|
|
309
|
-
flowId = asciiDecode(header.subarray(offset, offset +
|
|
501
|
+
flowId = asciiDecode(header.subarray(offset, offset + FLOW_ID_BYTES));
|
|
310
502
|
validateFlowId(flowId);
|
|
311
503
|
}
|
|
312
|
-
offset +=
|
|
504
|
+
offset += FLOW_ID_BYTES;
|
|
313
505
|
const decodedFlowOrigin = header[offset++];
|
|
314
506
|
if (includeFlow && ![1, 2, 3, 4].includes(decodedFlowOrigin)) {
|
|
315
507
|
throw new Error("Stream flow origin is invalid.");
|
|
@@ -318,14 +510,14 @@ function decodeStreamWireHeader(header, flagOverrides, includeFlow = true) {
|
|
|
318
510
|
}
|
|
319
511
|
let actorSlot;
|
|
320
512
|
if (hasActorSlot) {
|
|
321
|
-
if (header.length - offset <
|
|
513
|
+
if (header.length - offset < UINT16_BYTES) {
|
|
322
514
|
throw new Error("Stream actor slot is incomplete.");
|
|
323
515
|
}
|
|
324
516
|
actorSlot = readUInt16BE(header, offset);
|
|
325
517
|
if (actorSlot === 0) {
|
|
326
518
|
throw new Error("Stream actor slot must not be zero.");
|
|
327
519
|
}
|
|
328
|
-
offset +=
|
|
520
|
+
offset += UINT16_BYTES;
|
|
329
521
|
}
|
|
330
522
|
if (offset !== header.length) {
|
|
331
523
|
throw new Error("Stream header has trailing bytes.");
|
|
@@ -355,32 +547,36 @@ function asciiDecode(value) {
|
|
|
355
547
|
if (value.some((byte) => byte > 127)) throw new Error("Stream flow id must be ASCII.");
|
|
356
548
|
return String.fromCharCode(...value);
|
|
357
549
|
}
|
|
358
|
-
function
|
|
359
|
-
if (metadata.size >
|
|
550
|
+
function streamWireMetadataSize(metadata) {
|
|
551
|
+
if (metadata.size > UINT8_MAX) {
|
|
360
552
|
throw new Error("Metadata entry count must not exceed 255.");
|
|
361
553
|
}
|
|
362
554
|
let size = 1;
|
|
363
|
-
const
|
|
364
|
-
const
|
|
365
|
-
const
|
|
366
|
-
if (
|
|
555
|
+
for (const [key, value] of metadata) {
|
|
556
|
+
const keySize = utf8Size(key);
|
|
557
|
+
const valueSize = utf8Size(value);
|
|
558
|
+
if (keySize === 0 || keySize > UINT8_MAX) {
|
|
367
559
|
throw new Error("Metadata key length is invalid.");
|
|
368
560
|
}
|
|
369
|
-
if (
|
|
561
|
+
if (valueSize > UINT16_MAX) {
|
|
370
562
|
throw new Error("Metadata value is too large.");
|
|
371
563
|
}
|
|
372
|
-
size += 1 +
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
564
|
+
size += 1 + keySize + UINT16_BYTES + valueSize;
|
|
565
|
+
}
|
|
566
|
+
return size;
|
|
567
|
+
}
|
|
568
|
+
function encodeStreamWireMetadata(metadata) {
|
|
569
|
+
const buffer = new Uint8Array(streamWireMetadataSize(metadata));
|
|
376
570
|
let offset = 0;
|
|
377
571
|
buffer[offset++] = metadata.size;
|
|
378
|
-
for (const
|
|
572
|
+
for (const [key, value] of metadata) {
|
|
573
|
+
const keyBytes = utf8Encode(key);
|
|
574
|
+
const valueBytes = utf8Encode(value);
|
|
379
575
|
buffer[offset++] = keyBytes.length;
|
|
380
576
|
buffer.set(keyBytes, offset);
|
|
381
577
|
offset += keyBytes.length;
|
|
382
578
|
writeUInt16BE(buffer, offset, valueBytes.length);
|
|
383
|
-
offset +=
|
|
579
|
+
offset += UINT16_BYTES;
|
|
384
580
|
buffer.set(valueBytes, offset);
|
|
385
581
|
offset += valueBytes.length;
|
|
386
582
|
}
|
|
@@ -409,11 +605,11 @@ function utf8Decode(value) {
|
|
|
409
605
|
return new TextDecoder().decode(value);
|
|
410
606
|
}
|
|
411
607
|
function decodeStreamWireHeaderMetadata(header, offset) {
|
|
412
|
-
if (header.length - offset <
|
|
608
|
+
if (header.length - offset < UINT16_BYTES) {
|
|
413
609
|
throw new Error("Stream metadata section is incomplete.");
|
|
414
610
|
}
|
|
415
611
|
const metadataLength = readUInt16BE(header, offset);
|
|
416
|
-
offset +=
|
|
612
|
+
offset += UINT16_BYTES;
|
|
417
613
|
if (header.length - offset < metadataLength) {
|
|
418
614
|
throw new Error("Stream metadata payload is incomplete.");
|
|
419
615
|
}
|
|
@@ -439,7 +635,7 @@ function decodeStreamWireMetadataAt(source, offset, end) {
|
|
|
439
635
|
throw new Error("Stream metadata value length is missing.");
|
|
440
636
|
}
|
|
441
637
|
const valueLength = readUInt16BE(source, offset);
|
|
442
|
-
offset +=
|
|
638
|
+
offset += UINT16_BYTES;
|
|
443
639
|
if (end - offset < valueLength) {
|
|
444
640
|
throw new Error("Stream metadata value is incomplete.");
|
|
445
641
|
}
|
|
@@ -456,16 +652,17 @@ function decodeStreamWireMetadataAt(source, offset, end) {
|
|
|
456
652
|
}
|
|
457
653
|
function validateStreamWirePacketName(name) {
|
|
458
654
|
const nameBytes = utf8Encode(name);
|
|
459
|
-
if (
|
|
655
|
+
if (unicodeWhiteSpaceOnly.test(name) || nameBytes.length > ZLINK_STREAM_MAX_PACKET_NAME_BYTES) {
|
|
460
656
|
throw new Error("Stream packet name is invalid.");
|
|
461
657
|
}
|
|
658
|
+
return nameBytes;
|
|
462
659
|
}
|
|
463
660
|
function isReplyKind(kind) {
|
|
464
|
-
return kind ===
|
|
661
|
+
return kind === 3 /* Response */ || kind === 4 /* Error */;
|
|
465
662
|
}
|
|
466
663
|
function writeUInt16BE(buffer, offset, value) {
|
|
467
|
-
buffer[offset] = value >>> 8 &
|
|
468
|
-
buffer[offset + 1] = value &
|
|
664
|
+
buffer[offset] = value >>> 8 & UINT8_MAX;
|
|
665
|
+
buffer[offset + 1] = value & UINT8_MAX;
|
|
469
666
|
}
|
|
470
667
|
function readUInt16BE(buffer, offset) {
|
|
471
668
|
return buffer[offset] << 8 | buffer[offset + 1];
|
|
@@ -474,10 +671,10 @@ function readUInt32BE(buffer, offset) {
|
|
|
474
671
|
return buffer[offset] * 16777216 + (buffer[offset + 1] << 16 | buffer[offset + 2] << 8 | buffer[offset + 3]);
|
|
475
672
|
}
|
|
476
673
|
function writeUInt32BE(buffer, offset, value) {
|
|
477
|
-
buffer[offset] = value >>> 24 &
|
|
478
|
-
buffer[offset + 1] = value >>> 16 &
|
|
479
|
-
buffer[offset + 2] = value >>> 8 &
|
|
480
|
-
buffer[offset + 3] = value &
|
|
674
|
+
buffer[offset] = value >>> 24 & UINT8_MAX;
|
|
675
|
+
buffer[offset + 1] = value >>> 16 & UINT8_MAX;
|
|
676
|
+
buffer[offset + 2] = value >>> 8 & UINT8_MAX;
|
|
677
|
+
buffer[offset + 3] = value & UINT8_MAX;
|
|
481
678
|
}
|
|
482
679
|
function writeBigUInt64BE(buffer, offset, value) {
|
|
483
680
|
for (let index = 7; index >= 0; index -= 1) {
|
|
@@ -492,19 +689,58 @@ function readBigUInt64BE(buffer, offset) {
|
|
|
492
689
|
}
|
|
493
690
|
return value;
|
|
494
691
|
}
|
|
692
|
+
function utf8Size(value) {
|
|
693
|
+
let size = 0;
|
|
694
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
695
|
+
const code = value.charCodeAt(index);
|
|
696
|
+
if (code < UTF8_TWO_BYTE_MIN) size += 1;
|
|
697
|
+
else if (code < UTF8_THREE_BYTE_MIN) size += 2;
|
|
698
|
+
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) {
|
|
699
|
+
size += 4;
|
|
700
|
+
index += 1;
|
|
701
|
+
} else size += 3;
|
|
702
|
+
}
|
|
703
|
+
return size;
|
|
704
|
+
}
|
|
495
705
|
export {
|
|
706
|
+
UINT32_MAX,
|
|
707
|
+
UINT64_BYTES,
|
|
708
|
+
UINT64_MAX,
|
|
496
709
|
ZLINK_STREAM_FORMAT_MARKER,
|
|
710
|
+
ZLINK_STREAM_FRAME_PREFIX_BYTES,
|
|
711
|
+
ZLINK_STREAM_MAX_METADATA_BYTES,
|
|
712
|
+
ZLINK_STREAM_MAX_PACKET_NAME_BYTES,
|
|
713
|
+
ZLINK_STREAM_RESERVED_PACKET_NAME_PREFIX,
|
|
714
|
+
ZlinkStreamCloseReasonCode,
|
|
497
715
|
ZlinkStreamCodec,
|
|
716
|
+
ZlinkStreamContentType,
|
|
717
|
+
ZlinkStreamControlPacket,
|
|
718
|
+
ZlinkStreamHeaderFlags,
|
|
719
|
+
ZlinkStreamMessageKind,
|
|
720
|
+
decodeStreamWireActorBoundPayload,
|
|
721
|
+
decodeStreamWireActorUnboundPayload,
|
|
498
722
|
decodeStreamWireFrame,
|
|
499
723
|
decodeStreamWireHeader,
|
|
500
724
|
decodeStreamWireMetadata,
|
|
725
|
+
decodeStreamWireSessionClosing,
|
|
726
|
+
defaultMaxDecompressedPayloadSize,
|
|
727
|
+
encodeStreamWireActorBoundPayload,
|
|
728
|
+
encodeStreamWireActorUnboundPayload,
|
|
501
729
|
encodeStreamWireFrame,
|
|
502
730
|
encodeStreamWireHeader,
|
|
503
731
|
encodeStreamWireMetadata,
|
|
732
|
+
encodeStreamWireSessionClosingPayload,
|
|
733
|
+
isStreamWireCodec,
|
|
734
|
+
isStreamWireMessageKind,
|
|
504
735
|
lz4PickleUncompressed2 as lz4PickleUncompressed,
|
|
505
736
|
lz4PickledLength2 as lz4PickledLength,
|
|
506
737
|
lz4UnpicklePayload2 as lz4UnpicklePayload,
|
|
738
|
+
splitStreamWireFrames,
|
|
739
|
+
streamCodecContentType,
|
|
740
|
+
streamCodecForContentType,
|
|
741
|
+
streamWireMetadataSize,
|
|
507
742
|
tryDecodeStreamWireFrame,
|
|
508
743
|
utf8Decode,
|
|
509
|
-
utf8Encode
|
|
744
|
+
utf8Encode,
|
|
745
|
+
validateStreamWirePacketName
|
|
510
746
|
};
|