@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/index.js
CHANGED
|
@@ -1,11 +1,23 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ZLINK_STREAM_FORMAT_MARKER = exports.ZlinkStreamCodec = void 0;
|
|
3
|
+
exports.ZLINK_STREAM_FORMAT_MARKER = exports.ZlinkStreamContentType = exports.ZlinkStreamControlPacket = exports.ZLINK_STREAM_RESERVED_PACKET_NAME_PREFIX = exports.ZLINK_STREAM_MAX_METADATA_BYTES = exports.ZLINK_STREAM_MAX_PACKET_NAME_BYTES = exports.ZLINK_STREAM_FRAME_PREFIX_BYTES = exports.UINT32_MAX = exports.UINT64_MAX = exports.UINT64_BYTES = exports.ZlinkStreamCloseReasonCode = exports.ZlinkStreamHeaderFlags = exports.ZlinkStreamMessageKind = exports.ZlinkStreamCodec = exports.defaultMaxDecompressedPayloadSize = void 0;
|
|
4
|
+
exports.isStreamWireMessageKind = isStreamWireMessageKind;
|
|
5
|
+
exports.isStreamWireCodec = isStreamWireCodec;
|
|
6
|
+
exports.encodeStreamWireActorBoundPayload = encodeStreamWireActorBoundPayload;
|
|
7
|
+
exports.decodeStreamWireActorBoundPayload = decodeStreamWireActorBoundPayload;
|
|
8
|
+
exports.encodeStreamWireActorUnboundPayload = encodeStreamWireActorUnboundPayload;
|
|
9
|
+
exports.decodeStreamWireActorUnboundPayload = decodeStreamWireActorUnboundPayload;
|
|
10
|
+
exports.encodeStreamWireSessionClosingPayload = encodeStreamWireSessionClosingPayload;
|
|
11
|
+
exports.decodeStreamWireSessionClosing = decodeStreamWireSessionClosing;
|
|
12
|
+
exports.splitStreamWireFrames = splitStreamWireFrames;
|
|
13
|
+
exports.streamCodecContentType = streamCodecContentType;
|
|
14
|
+
exports.streamCodecForContentType = streamCodecForContentType;
|
|
4
15
|
exports.encodeStreamWireFrame = encodeStreamWireFrame;
|
|
5
16
|
exports.decodeStreamWireFrame = decodeStreamWireFrame;
|
|
6
17
|
exports.tryDecodeStreamWireFrame = tryDecodeStreamWireFrame;
|
|
7
18
|
exports.encodeStreamWireHeader = encodeStreamWireHeader;
|
|
8
19
|
exports.decodeStreamWireHeader = decodeStreamWireHeader;
|
|
20
|
+
exports.streamWireMetadataSize = streamWireMetadataSize;
|
|
9
21
|
exports.encodeStreamWireMetadata = encodeStreamWireMetadata;
|
|
10
22
|
exports.decodeStreamWireMetadata = decodeStreamWireMetadata;
|
|
11
23
|
exports.lz4PickleUncompressed = lz4PickleUncompressed;
|
|
@@ -13,7 +25,10 @@ exports.lz4PickledLength = lz4PickledLength;
|
|
|
13
25
|
exports.lz4UnpicklePayload = lz4UnpicklePayload;
|
|
14
26
|
exports.utf8Encode = utf8Encode;
|
|
15
27
|
exports.utf8Decode = utf8Decode;
|
|
28
|
+
exports.validateStreamWirePacketName = validateStreamWirePacketName;
|
|
16
29
|
const lz4_pickle_1 = require("./lz4-pickle");
|
|
30
|
+
var lz4_pickle_2 = require("./lz4-pickle");
|
|
31
|
+
Object.defineProperty(exports, "defaultMaxDecompressedPayloadSize", { enumerable: true, get: function () { return lz4_pickle_2.defaultMaxDecompressedPayloadSize; } });
|
|
17
32
|
/** Numeric payload codec values shared by browser and server wire paths. */
|
|
18
33
|
var ZlinkStreamCodec;
|
|
19
34
|
(function (ZlinkStreamCodec) {
|
|
@@ -22,76 +37,264 @@ var ZlinkStreamCodec;
|
|
|
22
37
|
ZlinkStreamCodec[ZlinkStreamCodec["MessagePack"] = 2] = "MessagePack";
|
|
23
38
|
ZlinkStreamCodec[ZlinkStreamCodec["Protobuf"] = 3] = "Protobuf";
|
|
24
39
|
})(ZlinkStreamCodec || (exports.ZlinkStreamCodec = ZlinkStreamCodec = {}));
|
|
40
|
+
var ZlinkStreamMessageKind;
|
|
41
|
+
(function (ZlinkStreamMessageKind) {
|
|
42
|
+
ZlinkStreamMessageKind[ZlinkStreamMessageKind["Send"] = 1] = "Send";
|
|
43
|
+
ZlinkStreamMessageKind[ZlinkStreamMessageKind["Request"] = 2] = "Request";
|
|
44
|
+
ZlinkStreamMessageKind[ZlinkStreamMessageKind["Response"] = 3] = "Response";
|
|
45
|
+
ZlinkStreamMessageKind[ZlinkStreamMessageKind["Error"] = 4] = "Error";
|
|
46
|
+
ZlinkStreamMessageKind[ZlinkStreamMessageKind["Control"] = 5] = "Control";
|
|
47
|
+
})(ZlinkStreamMessageKind || (exports.ZlinkStreamMessageKind = ZlinkStreamMessageKind = {}));
|
|
48
|
+
var ZlinkStreamHeaderFlags;
|
|
49
|
+
(function (ZlinkStreamHeaderFlags) {
|
|
50
|
+
ZlinkStreamHeaderFlags[ZlinkStreamHeaderFlags["None"] = 0] = "None";
|
|
51
|
+
ZlinkStreamHeaderFlags[ZlinkStreamHeaderFlags["HasRequestSeq"] = 1] = "HasRequestSeq";
|
|
52
|
+
ZlinkStreamHeaderFlags[ZlinkStreamHeaderFlags["HasMetadata"] = 2] = "HasMetadata";
|
|
53
|
+
ZlinkStreamHeaderFlags[ZlinkStreamHeaderFlags["PayloadCompressed"] = 4] = "PayloadCompressed";
|
|
54
|
+
ZlinkStreamHeaderFlags[ZlinkStreamHeaderFlags["HasCorrelationId"] = 8] = "HasCorrelationId";
|
|
55
|
+
ZlinkStreamHeaderFlags[ZlinkStreamHeaderFlags["HasFlowId"] = 16] = "HasFlowId";
|
|
56
|
+
ZlinkStreamHeaderFlags[ZlinkStreamHeaderFlags["HasActorSlot"] = 32] = "HasActorSlot";
|
|
57
|
+
})(ZlinkStreamHeaderFlags || (exports.ZlinkStreamHeaderFlags = ZlinkStreamHeaderFlags = {}));
|
|
58
|
+
var ZlinkStreamCloseReasonCode;
|
|
59
|
+
(function (ZlinkStreamCloseReasonCode) {
|
|
60
|
+
ZlinkStreamCloseReasonCode[ZlinkStreamCloseReasonCode["ClientClose"] = 1] = "ClientClose";
|
|
61
|
+
ZlinkStreamCloseReasonCode[ZlinkStreamCloseReasonCode["IdleTimeout"] = 2] = "IdleTimeout";
|
|
62
|
+
ZlinkStreamCloseReasonCode[ZlinkStreamCloseReasonCode["HeartbeatTimeout"] = 3] = "HeartbeatTimeout";
|
|
63
|
+
ZlinkStreamCloseReasonCode[ZlinkStreamCloseReasonCode["ServerDrain"] = 4] = "ServerDrain";
|
|
64
|
+
ZlinkStreamCloseReasonCode[ZlinkStreamCloseReasonCode["ProtocolError"] = 5] = "ProtocolError";
|
|
65
|
+
ZlinkStreamCloseReasonCode[ZlinkStreamCloseReasonCode["TransportError"] = 6] = "TransportError";
|
|
66
|
+
})(ZlinkStreamCloseReasonCode || (exports.ZlinkStreamCloseReasonCode = ZlinkStreamCloseReasonCode = {}));
|
|
67
|
+
const unicodeWhiteSpaceOnly = /^\p{White_Space}*$/u;
|
|
68
|
+
const validMessageKinds = new Set(Object.values(ZlinkStreamMessageKind).filter((value) => typeof value === 'number'));
|
|
69
|
+
const validCodecs = new Set(Object.values(ZlinkStreamCodec).filter((value) => typeof value === 'number'));
|
|
70
|
+
function isStreamWireMessageKind(value) {
|
|
71
|
+
return validMessageKinds.has(value);
|
|
72
|
+
}
|
|
73
|
+
function isStreamWireCodec(value) {
|
|
74
|
+
return validCodecs.has(value);
|
|
75
|
+
}
|
|
76
|
+
const UTF8_TWO_BYTE_MIN = 0x80;
|
|
77
|
+
const UTF8_THREE_BYTE_MIN = 0x800;
|
|
78
|
+
const UTF16_HIGH_SURROGATE_MIN = 0xd800;
|
|
79
|
+
const UTF16_HIGH_SURROGATE_MAX = 0xdbff;
|
|
80
|
+
const UTF16_LOW_SURROGATE_MIN = 0xdc00;
|
|
81
|
+
const UTF16_LOW_SURROGATE_MAX = 0xdfff;
|
|
82
|
+
const UINT8_MAX = 0xff;
|
|
83
|
+
const UINT16_MAX = 0xffff;
|
|
84
|
+
const UINT16_BYTES = 2;
|
|
85
|
+
const UINT32_BYTES = 4;
|
|
86
|
+
exports.UINT64_BYTES = 8;
|
|
87
|
+
exports.UINT64_MAX = 0xffffffffffffffffn;
|
|
88
|
+
exports.UINT32_MAX = 0xffff_ffff;
|
|
89
|
+
exports.ZLINK_STREAM_FRAME_PREFIX_BYTES = UINT16_BYTES + UINT32_BYTES;
|
|
90
|
+
exports.ZLINK_STREAM_MAX_PACKET_NAME_BYTES = UINT8_MAX;
|
|
91
|
+
exports.ZLINK_STREAM_MAX_METADATA_BYTES = 1024;
|
|
92
|
+
const FLOW_ID_BYTES = 36;
|
|
93
|
+
const FLOW_FIELDS_BYTES = FLOW_ID_BYTES + 1;
|
|
94
|
+
const HEADER_MIN_BYTES = 5;
|
|
95
|
+
const HEADER_FLAG_MASK = ZlinkStreamHeaderFlags.HasRequestSeq |
|
|
96
|
+
ZlinkStreamHeaderFlags.HasMetadata |
|
|
97
|
+
ZlinkStreamHeaderFlags.PayloadCompressed |
|
|
98
|
+
ZlinkStreamHeaderFlags.HasCorrelationId |
|
|
99
|
+
ZlinkStreamHeaderFlags.HasFlowId |
|
|
100
|
+
ZlinkStreamHeaderFlags.HasActorSlot;
|
|
101
|
+
const CONTROL_PAYLOAD_VERSION = 1;
|
|
102
|
+
const ACTOR_SLOT_OFFSET = 1;
|
|
103
|
+
const ACTOR_ID_LENGTH_OFFSET = ACTOR_SLOT_OFFSET + UINT16_BYTES;
|
|
104
|
+
const ACTOR_BOUND_PREFIX_BYTES = ACTOR_ID_LENGTH_OFFSET + 1;
|
|
105
|
+
const ACTOR_UNBOUND_BYTES = ACTOR_SLOT_OFFSET + UINT16_BYTES;
|
|
106
|
+
const CLOSING_DIAGNOSTIC_LENGTH_OFFSET = 2;
|
|
107
|
+
const CLOSING_PREFIX_BYTES = CLOSING_DIAGNOSTIC_LENGTH_OFFSET + UINT16_BYTES;
|
|
108
|
+
const MAX_CLOSING_DIAGNOSTIC_BYTES = 512;
|
|
109
|
+
function encodeStreamWireActorBoundPayload(actorSlot, actorId) {
|
|
110
|
+
const actorIdBytes = utf8Encode(actorId);
|
|
111
|
+
if (actorIdBytes.length < 1 || actorIdBytes.length > UINT8_MAX) {
|
|
112
|
+
throw new Error('Actor id length is invalid for a STREAM binding control packet.');
|
|
113
|
+
}
|
|
114
|
+
const payload = new Uint8Array(ACTOR_BOUND_PREFIX_BYTES + actorIdBytes.length);
|
|
115
|
+
payload[0] = CONTROL_PAYLOAD_VERSION;
|
|
116
|
+
writeUInt16BE(payload, ACTOR_SLOT_OFFSET, actorSlot);
|
|
117
|
+
payload[ACTOR_ID_LENGTH_OFFSET] = actorIdBytes.length;
|
|
118
|
+
payload.set(actorIdBytes, ACTOR_BOUND_PREFIX_BYTES);
|
|
119
|
+
return payload;
|
|
120
|
+
}
|
|
121
|
+
function decodeStreamWireActorBoundPayload(payload) {
|
|
122
|
+
if (payload.length < ACTOR_BOUND_PREFIX_BYTES + 1 || payload[0] !== CONTROL_PAYLOAD_VERSION) {
|
|
123
|
+
throw new Error('Actor bound payload is invalid.');
|
|
124
|
+
}
|
|
125
|
+
const slot = readUInt16BE(payload, ACTOR_SLOT_OFFSET);
|
|
126
|
+
const idLength = payload[ACTOR_ID_LENGTH_OFFSET];
|
|
127
|
+
if (slot === 0 || idLength === 0 || payload.length !== ACTOR_BOUND_PREFIX_BYTES + idLength) {
|
|
128
|
+
throw new Error('Actor bound payload is invalid.');
|
|
129
|
+
}
|
|
130
|
+
try {
|
|
131
|
+
return { slot, actorId: decodeControlText(payload.subarray(ACTOR_BOUND_PREFIX_BYTES)) };
|
|
132
|
+
}
|
|
133
|
+
catch (cause) {
|
|
134
|
+
throw new Error('Actor id is not valid UTF-8.', { cause });
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
function encodeStreamWireActorUnboundPayload(actorSlot) {
|
|
138
|
+
const payload = new Uint8Array(ACTOR_UNBOUND_BYTES);
|
|
139
|
+
payload[0] = CONTROL_PAYLOAD_VERSION;
|
|
140
|
+
writeUInt16BE(payload, ACTOR_SLOT_OFFSET, actorSlot);
|
|
141
|
+
return payload;
|
|
142
|
+
}
|
|
143
|
+
function decodeStreamWireActorUnboundPayload(payload) {
|
|
144
|
+
if (payload.length !== ACTOR_UNBOUND_BYTES || payload[0] !== CONTROL_PAYLOAD_VERSION) {
|
|
145
|
+
throw new Error('Actor unbound payload is invalid.');
|
|
146
|
+
}
|
|
147
|
+
return readUInt16BE(payload, ACTOR_SLOT_OFFSET);
|
|
148
|
+
}
|
|
149
|
+
function encodeStreamWireSessionClosingPayload(reasonCode, diagnostic = '') {
|
|
150
|
+
const bytes = utf8Encode(diagnostic);
|
|
151
|
+
if (bytes.length > MAX_CLOSING_DIAGNOSTIC_BYTES) {
|
|
152
|
+
throw new Error('Session-closing diagnostic is too large.');
|
|
153
|
+
}
|
|
154
|
+
const payload = new Uint8Array(CLOSING_PREFIX_BYTES + bytes.length);
|
|
155
|
+
payload[0] = CONTROL_PAYLOAD_VERSION;
|
|
156
|
+
payload[1] = reasonCode;
|
|
157
|
+
writeUInt16BE(payload, CLOSING_DIAGNOSTIC_LENGTH_OFFSET, bytes.length);
|
|
158
|
+
payload.set(bytes, CLOSING_PREFIX_BYTES);
|
|
159
|
+
return payload;
|
|
160
|
+
}
|
|
161
|
+
function decodeStreamWireSessionClosing(payload) {
|
|
162
|
+
if (payload.length < CLOSING_PREFIX_BYTES || payload[0] !== CONTROL_PAYLOAD_VERSION) {
|
|
163
|
+
throw new Error('Unsupported session-closing version.');
|
|
164
|
+
}
|
|
165
|
+
const closeReason = ZlinkStreamCloseReasonCode[payload[1]];
|
|
166
|
+
if (closeReason === undefined)
|
|
167
|
+
throw new Error('Unknown session-closing reason.');
|
|
168
|
+
const length = readUInt16BE(payload, CLOSING_DIAGNOSTIC_LENGTH_OFFSET);
|
|
169
|
+
if (length > MAX_CLOSING_DIAGNOSTIC_BYTES || payload.length !== CLOSING_PREFIX_BYTES + length) {
|
|
170
|
+
throw new Error('Invalid session-closing diagnostic length.');
|
|
171
|
+
}
|
|
172
|
+
const diagnostic = length === 0 ? undefined : decodeControlText(payload.subarray(CLOSING_PREFIX_BYTES));
|
|
173
|
+
return { closeReason, diagnostic };
|
|
174
|
+
}
|
|
175
|
+
function decodeControlText(value) {
|
|
176
|
+
return new TextDecoder('utf-8', { fatal: true }).decode(value);
|
|
177
|
+
}
|
|
178
|
+
function splitStreamWireFrames(chunk) {
|
|
179
|
+
if (chunk.length === 0)
|
|
180
|
+
throw new Error('Stream frame prefix is incomplete.');
|
|
181
|
+
const frames = [];
|
|
182
|
+
let offset = 0;
|
|
183
|
+
while (offset < chunk.length) {
|
|
184
|
+
const remaining = chunk.length - offset;
|
|
185
|
+
if (remaining < exports.ZLINK_STREAM_FRAME_PREFIX_BYTES) {
|
|
186
|
+
throw new Error('Stream frame prefix is incomplete.');
|
|
187
|
+
}
|
|
188
|
+
const headerLength = readUInt16BE(chunk, offset);
|
|
189
|
+
const payloadLength = readUInt32BE(chunk, offset + UINT16_BYTES);
|
|
190
|
+
const frameLength = exports.ZLINK_STREAM_FRAME_PREFIX_BYTES + headerLength + payloadLength;
|
|
191
|
+
if (frameLength > remaining)
|
|
192
|
+
throw new Error('Frame length does not match prefix.');
|
|
193
|
+
frames.push(chunk.subarray(offset, offset + frameLength));
|
|
194
|
+
offset += frameLength;
|
|
195
|
+
}
|
|
196
|
+
return frames;
|
|
197
|
+
}
|
|
198
|
+
/** @internal Reserved packet name prefix owned by the stream protocol. */
|
|
199
|
+
exports.ZLINK_STREAM_RESERVED_PACKET_NAME_PREFIX = '$zlink.';
|
|
200
|
+
exports.ZlinkStreamControlPacket = Object.freeze({
|
|
201
|
+
HeartbeatPing: `${exports.ZLINK_STREAM_RESERVED_PACKET_NAME_PREFIX}heartbeat.ping`,
|
|
202
|
+
HeartbeatPong: `${exports.ZLINK_STREAM_RESERVED_PACKET_NAME_PREFIX}heartbeat.pong`,
|
|
203
|
+
ActorBound: `${exports.ZLINK_STREAM_RESERVED_PACKET_NAME_PREFIX}actor.bound`,
|
|
204
|
+
ActorUnbound: `${exports.ZLINK_STREAM_RESERVED_PACKET_NAME_PREFIX}actor.unbound`,
|
|
205
|
+
SessionClosing: 'session-closing'
|
|
206
|
+
});
|
|
207
|
+
exports.ZlinkStreamContentType = Object.freeze({
|
|
208
|
+
Raw: 'application/octet-stream',
|
|
209
|
+
Json: 'application/json',
|
|
210
|
+
MessagePack: 'application/x-msgpack',
|
|
211
|
+
Protobuf: 'application/x-protobuf'
|
|
212
|
+
});
|
|
213
|
+
const contentTypesByCodec = new Map([
|
|
214
|
+
[ZlinkStreamCodec.Raw, exports.ZlinkStreamContentType.Raw],
|
|
215
|
+
[ZlinkStreamCodec.Json, exports.ZlinkStreamContentType.Json],
|
|
216
|
+
[ZlinkStreamCodec.MessagePack, exports.ZlinkStreamContentType.MessagePack],
|
|
217
|
+
[ZlinkStreamCodec.Protobuf, exports.ZlinkStreamContentType.Protobuf]
|
|
218
|
+
]);
|
|
219
|
+
const codecsByContentType = new Map(Array.from(contentTypesByCodec, ([codec, contentType]) => [contentType, codec]));
|
|
220
|
+
function streamCodecContentType(codec) {
|
|
221
|
+
const contentType = contentTypesByCodec.get(codec);
|
|
222
|
+
if (contentType === undefined)
|
|
223
|
+
throw new TypeError(`Unsupported STREAM codec '${codec}'.`);
|
|
224
|
+
return contentType;
|
|
225
|
+
}
|
|
226
|
+
function streamCodecForContentType(contentType) {
|
|
227
|
+
const codec = codecsByContentType.get(contentType);
|
|
228
|
+
if (codec === undefined)
|
|
229
|
+
throw new TypeError(`Unsupported STREAM content type '${contentType}'.`);
|
|
230
|
+
return codec;
|
|
231
|
+
}
|
|
25
232
|
// The functions below resolve this inside their bodies rather than in a parameter
|
|
26
233
|
// default. The browser IIFE build of this package is committed into the Unity
|
|
27
234
|
// WebGL adapter as an emscripten pre-js, and emscripten's dead-code pass does not
|
|
28
235
|
// walk parameter default initializers: a binding whose only references are
|
|
29
236
|
// defaults is deleted, and the player fails at runtime with "not defined".
|
|
30
237
|
const defaultHeaderFlags = {
|
|
31
|
-
hasRequestSeq:
|
|
32
|
-
hasMetadata:
|
|
33
|
-
hasCorrelationId:
|
|
34
|
-
hasFlowId:
|
|
35
|
-
hasActorSlot:
|
|
238
|
+
hasRequestSeq: ZlinkStreamHeaderFlags.HasRequestSeq,
|
|
239
|
+
hasMetadata: ZlinkStreamHeaderFlags.HasMetadata,
|
|
240
|
+
hasCorrelationId: ZlinkStreamHeaderFlags.HasCorrelationId,
|
|
241
|
+
hasFlowId: ZlinkStreamHeaderFlags.HasFlowId,
|
|
242
|
+
hasActorSlot: ZlinkStreamHeaderFlags.HasActorSlot
|
|
36
243
|
};
|
|
37
244
|
exports.ZLINK_STREAM_FORMAT_MARKER = 0xf2;
|
|
38
|
-
const ZLINK_STREAM_RESPONSE_KIND = 3;
|
|
39
|
-
const ZLINK_STREAM_ERROR_KIND = 4;
|
|
40
245
|
function encodeStreamWireFrame(header, payload) {
|
|
41
|
-
if (header.length >
|
|
246
|
+
if (header.length > UINT16_MAX) {
|
|
42
247
|
throw new Error('Stream header is too large.');
|
|
43
248
|
}
|
|
44
|
-
if (payload.length >
|
|
249
|
+
if (payload.length > exports.UINT32_MAX) {
|
|
45
250
|
throw new Error('Stream payload is too large.');
|
|
46
251
|
}
|
|
47
|
-
const frame = new Uint8Array(
|
|
252
|
+
const frame = new Uint8Array(exports.ZLINK_STREAM_FRAME_PREFIX_BYTES + header.length + payload.length);
|
|
48
253
|
writeUInt16BE(frame, 0, header.length);
|
|
49
|
-
writeUInt32BE(frame,
|
|
50
|
-
frame.set(header,
|
|
51
|
-
frame.set(payload,
|
|
254
|
+
writeUInt32BE(frame, UINT16_BYTES, payload.length);
|
|
255
|
+
frame.set(header, exports.ZLINK_STREAM_FRAME_PREFIX_BYTES);
|
|
256
|
+
frame.set(payload, exports.ZLINK_STREAM_FRAME_PREFIX_BYTES + header.length);
|
|
52
257
|
return frame;
|
|
53
258
|
}
|
|
54
259
|
function decodeStreamWireFrame(frame) {
|
|
55
|
-
if (frame.length <
|
|
260
|
+
if (frame.length < exports.ZLINK_STREAM_FRAME_PREFIX_BYTES) {
|
|
56
261
|
throw new Error('Stream frame prefix is incomplete.');
|
|
57
262
|
}
|
|
58
263
|
const headerLength = readUInt16BE(frame, 0);
|
|
59
|
-
const payloadLength = readUInt32BE(frame,
|
|
60
|
-
if (frame.length !==
|
|
264
|
+
const payloadLength = readUInt32BE(frame, UINT16_BYTES);
|
|
265
|
+
if (frame.length !== exports.ZLINK_STREAM_FRAME_PREFIX_BYTES + headerLength + payloadLength) {
|
|
61
266
|
throw new Error('Stream frame length does not match prefix.');
|
|
62
267
|
}
|
|
63
268
|
return {
|
|
64
|
-
header: frame.slice(
|
|
65
|
-
payload: frame.slice(
|
|
269
|
+
header: frame.slice(exports.ZLINK_STREAM_FRAME_PREFIX_BYTES, exports.ZLINK_STREAM_FRAME_PREFIX_BYTES + headerLength),
|
|
270
|
+
payload: frame.slice(exports.ZLINK_STREAM_FRAME_PREFIX_BYTES + headerLength)
|
|
66
271
|
};
|
|
67
272
|
}
|
|
68
273
|
function tryDecodeStreamWireFrame(frame) {
|
|
69
|
-
if (frame.length <
|
|
274
|
+
if (frame.length < exports.ZLINK_STREAM_FRAME_PREFIX_BYTES) {
|
|
70
275
|
return undefined;
|
|
71
276
|
}
|
|
72
277
|
const headerLength = readUInt16BE(frame, 0);
|
|
73
|
-
const payloadLength = readUInt32BE(frame,
|
|
74
|
-
if (frame.length !==
|
|
278
|
+
const payloadLength = readUInt32BE(frame, UINT16_BYTES);
|
|
279
|
+
if (frame.length !== exports.ZLINK_STREAM_FRAME_PREFIX_BYTES + headerLength + payloadLength) {
|
|
75
280
|
return undefined;
|
|
76
281
|
}
|
|
77
282
|
return {
|
|
78
|
-
header: frame.slice(
|
|
79
|
-
payload: frame.slice(
|
|
283
|
+
header: frame.slice(exports.ZLINK_STREAM_FRAME_PREFIX_BYTES, exports.ZLINK_STREAM_FRAME_PREFIX_BYTES + headerLength),
|
|
284
|
+
payload: frame.slice(exports.ZLINK_STREAM_FRAME_PREFIX_BYTES + headerLength)
|
|
80
285
|
};
|
|
81
286
|
}
|
|
82
287
|
function encodeStreamWireHeader(header, flagOverrides) {
|
|
83
288
|
const flags = flagOverrides ?? defaultHeaderFlags;
|
|
84
289
|
const reply = isReplyKind(header.kind);
|
|
85
290
|
const packetName = reply ? '' : header.name;
|
|
86
|
-
|
|
87
|
-
validateStreamWirePacketName(packetName);
|
|
88
|
-
const nameBytes = utf8Encode(packetName);
|
|
291
|
+
const nameBytes = reply ? new Uint8Array() : validateStreamWirePacketName(packetName);
|
|
89
292
|
const hasRequestSeq = header.requestSeq !== undefined;
|
|
90
293
|
const hasMetadata = header.metadata.size > 0;
|
|
91
294
|
const correlationBytes = header.correlationId !== undefined && header.correlationId.length > 0
|
|
92
295
|
? utf8Encode(header.correlationId)
|
|
93
296
|
: undefined;
|
|
94
|
-
if (correlationBytes !== undefined && correlationBytes.length >
|
|
297
|
+
if (correlationBytes !== undefined && correlationBytes.length > UINT8_MAX) {
|
|
95
298
|
throw new Error('Stream correlation id is too large.');
|
|
96
299
|
}
|
|
97
300
|
const hasCorrelation = correlationBytes !== undefined;
|
|
@@ -106,7 +309,7 @@ function encodeStreamWireHeader(header, flagOverrides) {
|
|
|
106
309
|
throw new Error('Stream flow origin is invalid.');
|
|
107
310
|
}
|
|
108
311
|
if (header.actorSlot !== undefined &&
|
|
109
|
-
(!Number.isInteger(header.actorSlot) || header.actorSlot < 1 || header.actorSlot >
|
|
312
|
+
(!Number.isInteger(header.actorSlot) || header.actorSlot < 1 || header.actorSlot > UINT16_MAX)) {
|
|
110
313
|
throw new Error('Stream actor slot is invalid.');
|
|
111
314
|
}
|
|
112
315
|
let headerFlags = header.flags;
|
|
@@ -121,13 +324,13 @@ function encodeStreamWireHeader(header, flagOverrides) {
|
|
|
121
324
|
headerFlags = hasActorSlot ? headerFlags | flags.hasActorSlot : headerFlags & ~flags.hasActorSlot;
|
|
122
325
|
const metadataBytes = hasMetadata ? encodeStreamWireMetadata(header.metadata) : new Uint8Array();
|
|
123
326
|
const size = 4 +
|
|
124
|
-
(hasRequestSeq ?
|
|
327
|
+
(hasRequestSeq ? exports.UINT64_BYTES : 0) +
|
|
125
328
|
1 +
|
|
126
329
|
nameBytes.length +
|
|
127
|
-
(hasMetadata ?
|
|
330
|
+
(hasMetadata ? UINT16_BYTES + metadataBytes.length : 0) +
|
|
128
331
|
(hasCorrelation ? 1 + correlationBytes.length : 0) +
|
|
129
|
-
(hasFlow ?
|
|
130
|
-
(hasActorSlot ?
|
|
332
|
+
(hasFlow ? FLOW_FIELDS_BYTES : 0) +
|
|
333
|
+
(hasActorSlot ? UINT16_BYTES : 0);
|
|
131
334
|
const buffer = new Uint8Array(size);
|
|
132
335
|
let offset = 0;
|
|
133
336
|
buffer[offset++] = exports.ZLINK_STREAM_FORMAT_MARKER;
|
|
@@ -139,14 +342,14 @@ function encodeStreamWireHeader(header, flagOverrides) {
|
|
|
139
342
|
throw new Error('Request sequence must not be zero.');
|
|
140
343
|
}
|
|
141
344
|
writeBigUInt64BE(buffer, offset, header.requestSeq);
|
|
142
|
-
offset +=
|
|
345
|
+
offset += exports.UINT64_BYTES;
|
|
143
346
|
}
|
|
144
347
|
buffer[offset++] = nameBytes.length;
|
|
145
348
|
buffer.set(nameBytes, offset);
|
|
146
349
|
offset += nameBytes.length;
|
|
147
350
|
if (hasMetadata) {
|
|
148
351
|
writeUInt16BE(buffer, offset, metadataBytes.length);
|
|
149
|
-
offset +=
|
|
352
|
+
offset += UINT16_BYTES;
|
|
150
353
|
buffer.set(metadataBytes, offset);
|
|
151
354
|
offset += metadataBytes.length;
|
|
152
355
|
}
|
|
@@ -157,7 +360,7 @@ function encodeStreamWireHeader(header, flagOverrides) {
|
|
|
157
360
|
}
|
|
158
361
|
if (hasFlow) {
|
|
159
362
|
buffer.set(asciiEncode(header.flowId), offset);
|
|
160
|
-
offset +=
|
|
363
|
+
offset += FLOW_ID_BYTES;
|
|
161
364
|
buffer[offset++] = header.flowOrigin;
|
|
162
365
|
}
|
|
163
366
|
if (hasActorSlot) {
|
|
@@ -168,7 +371,7 @@ function encodeStreamWireHeader(header, flagOverrides) {
|
|
|
168
371
|
function decodeStreamWireHeader(header, flagOverrides, includeFlow = true) {
|
|
169
372
|
const flags = flagOverrides ?? defaultHeaderFlags;
|
|
170
373
|
let offset = 0;
|
|
171
|
-
if (header.length <
|
|
374
|
+
if (header.length < HEADER_MIN_BYTES) {
|
|
172
375
|
throw new Error('Stream header is incomplete.');
|
|
173
376
|
}
|
|
174
377
|
if (header[offset++] !== exports.ZLINK_STREAM_FORMAT_MARKER) {
|
|
@@ -182,29 +385,29 @@ function decodeStreamWireHeader(header, flagOverrides, includeFlow = true) {
|
|
|
182
385
|
const hasCorrelation = (headerFlags & flags.hasCorrelationId) !== 0;
|
|
183
386
|
const hasFlow = (headerFlags & flags.hasFlowId) !== 0;
|
|
184
387
|
const hasActorSlot = (headerFlags & flags.hasActorSlot) !== 0;
|
|
185
|
-
if ((headerFlags & ~
|
|
388
|
+
if ((headerFlags & ~HEADER_FLAG_MASK) !== 0) {
|
|
186
389
|
throw new Error('Unknown mandatory stream header flag.');
|
|
187
390
|
}
|
|
188
391
|
let requestSeq;
|
|
189
392
|
if (hasRequestSeq) {
|
|
190
|
-
if (header.length - offset <
|
|
393
|
+
if (header.length - offset < exports.UINT64_BYTES) {
|
|
191
394
|
throw new Error('Stream request sequence is incomplete.');
|
|
192
395
|
}
|
|
193
396
|
requestSeq = readBigUInt64BE(header, offset);
|
|
194
397
|
if (requestSeq === 0n) {
|
|
195
398
|
throw new Error('Request sequence must not be zero.');
|
|
196
399
|
}
|
|
197
|
-
offset +=
|
|
400
|
+
offset += exports.UINT64_BYTES;
|
|
198
401
|
}
|
|
199
402
|
if (header.length - offset < 1) {
|
|
200
403
|
throw new Error('Stream packet name length is missing.');
|
|
201
404
|
}
|
|
202
405
|
const nameLength = header[offset++];
|
|
203
|
-
if ((
|
|
406
|
+
if ((isReplyKind(kind) ? nameLength !== 0 : nameLength === 0) ||
|
|
407
|
+
header.length - offset < nameLength) {
|
|
204
408
|
throw new Error('Stream packet name is invalid.');
|
|
205
409
|
}
|
|
206
|
-
const
|
|
207
|
-
const name = isReplyKind(kind) ? '' : decodedName;
|
|
410
|
+
const name = utf8Decode(header.subarray(offset, offset + nameLength));
|
|
208
411
|
offset += nameLength;
|
|
209
412
|
const decodedMetadata = hasMetadata
|
|
210
413
|
? decodeStreamWireHeaderMetadata(header, offset)
|
|
@@ -225,14 +428,14 @@ function decodeStreamWireHeader(header, flagOverrides, includeFlow = true) {
|
|
|
225
428
|
let flowId;
|
|
226
429
|
let flowOrigin;
|
|
227
430
|
if (hasFlow) {
|
|
228
|
-
if (header.length - offset <
|
|
431
|
+
if (header.length - offset < FLOW_FIELDS_BYTES) {
|
|
229
432
|
throw new Error('Stream flow fields are incomplete.');
|
|
230
433
|
}
|
|
231
434
|
if (includeFlow) {
|
|
232
|
-
flowId = asciiDecode(header.subarray(offset, offset +
|
|
435
|
+
flowId = asciiDecode(header.subarray(offset, offset + FLOW_ID_BYTES));
|
|
233
436
|
validateFlowId(flowId);
|
|
234
437
|
}
|
|
235
|
-
offset +=
|
|
438
|
+
offset += FLOW_ID_BYTES;
|
|
236
439
|
const decodedFlowOrigin = header[offset++];
|
|
237
440
|
if (includeFlow && ![1, 2, 3, 4].includes(decodedFlowOrigin)) {
|
|
238
441
|
throw new Error('Stream flow origin is invalid.');
|
|
@@ -241,14 +444,14 @@ function decodeStreamWireHeader(header, flagOverrides, includeFlow = true) {
|
|
|
241
444
|
}
|
|
242
445
|
let actorSlot;
|
|
243
446
|
if (hasActorSlot) {
|
|
244
|
-
if (header.length - offset <
|
|
447
|
+
if (header.length - offset < UINT16_BYTES) {
|
|
245
448
|
throw new Error('Stream actor slot is incomplete.');
|
|
246
449
|
}
|
|
247
450
|
actorSlot = readUInt16BE(header, offset);
|
|
248
451
|
if (actorSlot === 0) {
|
|
249
452
|
throw new Error('Stream actor slot must not be zero.');
|
|
250
453
|
}
|
|
251
|
-
offset +=
|
|
454
|
+
offset += UINT16_BYTES;
|
|
252
455
|
}
|
|
253
456
|
if (offset !== header.length) {
|
|
254
457
|
throw new Error('Stream header has trailing bytes.');
|
|
@@ -279,32 +482,37 @@ function asciiDecode(value) {
|
|
|
279
482
|
throw new Error('Stream flow id must be ASCII.');
|
|
280
483
|
return String.fromCharCode(...value);
|
|
281
484
|
}
|
|
282
|
-
|
|
283
|
-
|
|
485
|
+
/** Standalone metadata includes its count byte even when the map is empty. */
|
|
486
|
+
function streamWireMetadataSize(metadata) {
|
|
487
|
+
if (metadata.size > UINT8_MAX) {
|
|
284
488
|
throw new Error('Metadata entry count must not exceed 255.');
|
|
285
489
|
}
|
|
286
490
|
let size = 1;
|
|
287
|
-
const
|
|
288
|
-
const
|
|
289
|
-
const
|
|
290
|
-
if (
|
|
491
|
+
for (const [key, value] of metadata) {
|
|
492
|
+
const keySize = utf8Size(key);
|
|
493
|
+
const valueSize = utf8Size(value);
|
|
494
|
+
if (keySize === 0 || keySize > UINT8_MAX) {
|
|
291
495
|
throw new Error('Metadata key length is invalid.');
|
|
292
496
|
}
|
|
293
|
-
if (
|
|
497
|
+
if (valueSize > UINT16_MAX) {
|
|
294
498
|
throw new Error('Metadata value is too large.');
|
|
295
499
|
}
|
|
296
|
-
size += 1 +
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
500
|
+
size += 1 + keySize + UINT16_BYTES + valueSize;
|
|
501
|
+
}
|
|
502
|
+
return size;
|
|
503
|
+
}
|
|
504
|
+
function encodeStreamWireMetadata(metadata) {
|
|
505
|
+
const buffer = new Uint8Array(streamWireMetadataSize(metadata));
|
|
300
506
|
let offset = 0;
|
|
301
507
|
buffer[offset++] = metadata.size;
|
|
302
|
-
for (const
|
|
508
|
+
for (const [key, value] of metadata) {
|
|
509
|
+
const keyBytes = utf8Encode(key);
|
|
510
|
+
const valueBytes = utf8Encode(value);
|
|
303
511
|
buffer[offset++] = keyBytes.length;
|
|
304
512
|
buffer.set(keyBytes, offset);
|
|
305
513
|
offset += keyBytes.length;
|
|
306
514
|
writeUInt16BE(buffer, offset, valueBytes.length);
|
|
307
|
-
offset +=
|
|
515
|
+
offset += UINT16_BYTES;
|
|
308
516
|
buffer.set(valueBytes, offset);
|
|
309
517
|
offset += valueBytes.length;
|
|
310
518
|
}
|
|
@@ -333,11 +541,11 @@ function utf8Decode(value) {
|
|
|
333
541
|
return new TextDecoder().decode(value);
|
|
334
542
|
}
|
|
335
543
|
function decodeStreamWireHeaderMetadata(header, offset) {
|
|
336
|
-
if (header.length - offset <
|
|
544
|
+
if (header.length - offset < UINT16_BYTES) {
|
|
337
545
|
throw new Error('Stream metadata section is incomplete.');
|
|
338
546
|
}
|
|
339
547
|
const metadataLength = readUInt16BE(header, offset);
|
|
340
|
-
offset +=
|
|
548
|
+
offset += UINT16_BYTES;
|
|
341
549
|
if (header.length - offset < metadataLength) {
|
|
342
550
|
throw new Error('Stream metadata payload is incomplete.');
|
|
343
551
|
}
|
|
@@ -363,7 +571,7 @@ function decodeStreamWireMetadataAt(source, offset, end) {
|
|
|
363
571
|
throw new Error('Stream metadata value length is missing.');
|
|
364
572
|
}
|
|
365
573
|
const valueLength = readUInt16BE(source, offset);
|
|
366
|
-
offset +=
|
|
574
|
+
offset += UINT16_BYTES;
|
|
367
575
|
if (end - offset < valueLength) {
|
|
368
576
|
throw new Error('Stream metadata value is incomplete.');
|
|
369
577
|
}
|
|
@@ -378,18 +586,20 @@ function decodeStreamWireMetadataAt(source, offset, end) {
|
|
|
378
586
|
}
|
|
379
587
|
return { metadata, offset };
|
|
380
588
|
}
|
|
589
|
+
/** @internal Shared packet name structure validation for the connector. */
|
|
381
590
|
function validateStreamWirePacketName(name) {
|
|
382
591
|
const nameBytes = utf8Encode(name);
|
|
383
|
-
if (
|
|
592
|
+
if (unicodeWhiteSpaceOnly.test(name) || nameBytes.length > exports.ZLINK_STREAM_MAX_PACKET_NAME_BYTES) {
|
|
384
593
|
throw new Error('Stream packet name is invalid.');
|
|
385
594
|
}
|
|
595
|
+
return nameBytes;
|
|
386
596
|
}
|
|
387
597
|
function isReplyKind(kind) {
|
|
388
|
-
return kind ===
|
|
598
|
+
return kind === ZlinkStreamMessageKind.Response || kind === ZlinkStreamMessageKind.Error;
|
|
389
599
|
}
|
|
390
600
|
function writeUInt16BE(buffer, offset, value) {
|
|
391
|
-
buffer[offset] = (value >>> 8) &
|
|
392
|
-
buffer[offset + 1] = value &
|
|
601
|
+
buffer[offset] = (value >>> 8) & UINT8_MAX;
|
|
602
|
+
buffer[offset + 1] = value & UINT8_MAX;
|
|
393
603
|
}
|
|
394
604
|
function readUInt16BE(buffer, offset) {
|
|
395
605
|
return (buffer[offset] << 8) | buffer[offset + 1];
|
|
@@ -399,10 +609,10 @@ function readUInt32BE(buffer, offset) {
|
|
|
399
609
|
((buffer[offset + 1] << 16) | (buffer[offset + 2] << 8) | buffer[offset + 3]));
|
|
400
610
|
}
|
|
401
611
|
function writeUInt32BE(buffer, offset, value) {
|
|
402
|
-
buffer[offset] = (value >>> 24) &
|
|
403
|
-
buffer[offset + 1] = (value >>> 16) &
|
|
404
|
-
buffer[offset + 2] = (value >>> 8) &
|
|
405
|
-
buffer[offset + 3] = value &
|
|
612
|
+
buffer[offset] = (value >>> 24) & UINT8_MAX;
|
|
613
|
+
buffer[offset + 1] = (value >>> 16) & UINT8_MAX;
|
|
614
|
+
buffer[offset + 2] = (value >>> 8) & UINT8_MAX;
|
|
615
|
+
buffer[offset + 3] = value & UINT8_MAX;
|
|
406
616
|
}
|
|
407
617
|
function writeBigUInt64BE(buffer, offset, value) {
|
|
408
618
|
for (let index = 7; index >= 0; index -= 1) {
|
|
@@ -417,3 +627,25 @@ function readBigUInt64BE(buffer, offset) {
|
|
|
417
627
|
}
|
|
418
628
|
return value;
|
|
419
629
|
}
|
|
630
|
+
/** TextEncoder replaces lone surrogates with the three-byte replacement character. */
|
|
631
|
+
function utf8Size(value) {
|
|
632
|
+
let size = 0;
|
|
633
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
634
|
+
const code = value.charCodeAt(index);
|
|
635
|
+
if (code < UTF8_TWO_BYTE_MIN)
|
|
636
|
+
size += 1;
|
|
637
|
+
else if (code < UTF8_THREE_BYTE_MIN)
|
|
638
|
+
size += 2;
|
|
639
|
+
else if (code >= UTF16_HIGH_SURROGATE_MIN &&
|
|
640
|
+
code <= UTF16_HIGH_SURROGATE_MAX &&
|
|
641
|
+
index + 1 < value.length &&
|
|
642
|
+
value.charCodeAt(index + 1) >= UTF16_LOW_SURROGATE_MIN &&
|
|
643
|
+
value.charCodeAt(index + 1) <= UTF16_LOW_SURROGATE_MAX) {
|
|
644
|
+
size += 4;
|
|
645
|
+
index += 1;
|
|
646
|
+
}
|
|
647
|
+
else
|
|
648
|
+
size += 3;
|
|
649
|
+
}
|
|
650
|
+
return size;
|
|
651
|
+
}
|
package/dist/lz4-pickle.js
CHANGED
|
@@ -4,6 +4,10 @@ exports.defaultMaxDecompressedPayloadSize = void 0;
|
|
|
4
4
|
exports.lz4PickleUncompressed = lz4PickleUncompressed;
|
|
5
5
|
exports.lz4PickledLength = lz4PickledLength;
|
|
6
6
|
exports.lz4UnpicklePayload = lz4UnpicklePayload;
|
|
7
|
+
const LZ4_MIN_MATCH_LENGTH = 4;
|
|
8
|
+
const LZ4_MATCH_OFFSET_BYTES = 2;
|
|
9
|
+
const LZ4_EXTENDED_LENGTH_NIBBLE = 15;
|
|
10
|
+
const LZ4_EXTENDED_LENGTH_BYTE = 255;
|
|
7
11
|
// Resolved inside the function body rather than in a parameter default: see the
|
|
8
12
|
// note on defaultHeaderFlags in index.ts. Emscripten's dead-code pass deletes a
|
|
9
13
|
// binding whose only references are parameter defaults.
|
|
@@ -86,15 +90,15 @@ function decodeLz4Block(source, resultLength) {
|
|
|
86
90
|
if (sourceOffset >= source.length) {
|
|
87
91
|
break;
|
|
88
92
|
}
|
|
89
|
-
if (source.length - sourceOffset <
|
|
93
|
+
if (source.length - sourceOffset < LZ4_MATCH_OFFSET_BYTES) {
|
|
90
94
|
throw new Error('LZ4 match offset is incomplete.');
|
|
91
95
|
}
|
|
92
96
|
const matchOffset = source[sourceOffset] | (source[sourceOffset + 1] << 8);
|
|
93
|
-
sourceOffset +=
|
|
97
|
+
sourceOffset += LZ4_MATCH_OFFSET_BYTES;
|
|
94
98
|
if (matchOffset === 0 || matchOffset > targetOffset) {
|
|
95
99
|
throw new Error('LZ4 match offset is invalid.');
|
|
96
100
|
}
|
|
97
|
-
const matchLength = readLz4Length(source, token & 0x0f, () => sourceOffset++) +
|
|
101
|
+
const matchLength = readLz4Length(source, token & 0x0f, () => sourceOffset++) + LZ4_MIN_MATCH_LENGTH;
|
|
98
102
|
if (target.length - targetOffset < matchLength) {
|
|
99
103
|
throw new Error('LZ4 match run exceeds output size.');
|
|
100
104
|
}
|
|
@@ -110,7 +114,7 @@ function decodeLz4Block(source, resultLength) {
|
|
|
110
114
|
}
|
|
111
115
|
function readLz4Length(source, nibble, nextOffset) {
|
|
112
116
|
let length = nibble;
|
|
113
|
-
if (length !==
|
|
117
|
+
if (length !== LZ4_EXTENDED_LENGTH_NIBBLE) {
|
|
114
118
|
return length;
|
|
115
119
|
}
|
|
116
120
|
for (;;) {
|
|
@@ -120,7 +124,7 @@ function readLz4Length(source, nibble, nextOffset) {
|
|
|
120
124
|
}
|
|
121
125
|
const value = source[offset];
|
|
122
126
|
length += value;
|
|
123
|
-
if (value !==
|
|
127
|
+
if (value !== LZ4_EXTENDED_LENGTH_BYTE) {
|
|
124
128
|
return length;
|
|
125
129
|
}
|
|
126
130
|
}
|