@moqtap/codec 0.10.0 → 0.11.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/CHANGELOG.md +147 -0
- package/dist/auth-redaction-DsdLq4Qs.d.cts +102 -0
- package/dist/auth-redaction-DsdLq4Qs.d.ts +102 -0
- package/dist/{chunk-RYKQXBG6.cjs → chunk-27K5BUAG.cjs} +481 -517
- package/dist/{chunk-WCPENYNE.js → chunk-3RNQMGKA.js} +359 -390
- package/dist/{chunk-TSUZ6GJV.js → chunk-5AWIXOLB.js} +438 -469
- package/dist/{chunk-4XLYCT5Q.cjs → chunk-5IMHJIAZ.cjs} +52 -2
- package/dist/{chunk-KTNERCTZ.cjs → chunk-5JGZCKJO.cjs} +488 -518
- package/dist/{chunk-WCTMPDUX.cjs → chunk-73K4OSAN.cjs} +401 -432
- package/dist/{chunk-N2V7Z37J.js → chunk-7VQKRGRD.js} +19 -3
- package/dist/{chunk-BIBMDTU5.cjs → chunk-A3UCQOIB.cjs} +486 -517
- package/dist/{chunk-K2B3OVFK.js → chunk-A7PDMVXM.js} +24 -3
- package/dist/{chunk-VZHL2U2N.cjs → chunk-A7VQO6YC.cjs} +54 -38
- package/dist/{chunk-AQ445VV7.cjs → chunk-ACQHZLRZ.cjs} +66 -46
- package/dist/{chunk-L5DRACXS.js → chunk-BBICOMW6.js} +25 -3
- package/dist/{chunk-T4VWPKDG.cjs → chunk-BNIUVOCJ.cjs} +529 -599
- package/dist/{chunk-UKKDOOUO.cjs → chunk-CNC6ANS4.cjs} +58 -37
- package/dist/{chunk-OZRK73NQ.js → chunk-FDLQSWHK.js} +433 -469
- package/dist/{chunk-IJAF6PAY.js → chunk-FFNOE4UR.js} +19 -3
- package/dist/{chunk-CZNW3R5E.cjs → chunk-GMENT63T.cjs} +54 -38
- package/dist/{chunk-XCRCAUGI.cjs → chunk-HM7BLRVP.cjs} +291 -297
- package/dist/{chunk-XHAP2YST.js → chunk-HZONHFNO.js} +19 -3
- package/dist/{chunk-SDJTSMOW.cjs → chunk-ILYABWDK.cjs} +60 -38
- package/dist/{chunk-IDV2JYJ6.cjs → chunk-KRSFTZVO.cjs} +56 -40
- package/dist/{chunk-RIIA4ALQ.cjs → chunk-KSPH6KMH.cjs} +54 -38
- package/dist/{chunk-OUNN4IQB.cjs → chunk-KTY4LAUV.cjs} +482 -497
- package/dist/{chunk-RZTLQAKF.js → chunk-OJNLJT5D.js} +0 -1
- package/dist/{chunk-FT3HDNIB.js → chunk-PJK2ZS3I.js} +467 -537
- package/dist/{chunk-G53WYUXL.js → chunk-PSMZKHOC.js} +441 -456
- package/dist/{chunk-7RE6KSIY.cjs → chunk-Q5JQGHWY.cjs} +0 -1
- package/dist/{chunk-BX2N7TZM.js → chunk-SQTUQY5E.js} +31 -11
- package/dist/{chunk-CF5DDD3Q.js → chunk-WCRLAKDW.js} +239 -245
- package/dist/{chunk-KYVTM5VI.js → chunk-WL2YUEXH.js} +19 -3
- package/dist/{chunk-KGDVC4O6.js → chunk-YCNIVZS7.js} +439 -469
- package/dist/{chunk-KLPWJU6W.js → chunk-YRZQVNZO.js} +50 -0
- package/dist/{codec-CFWu5KVT.d.cts → codec-76xzrLTL.d.cts} +21 -2
- package/dist/{codec-gl4_QEva.d.ts → codec-8p40WdLg.d.ts} +20 -1
- package/dist/{codec-Dl_QIXMz.d.ts → codec-BN2Bu0KI.d.ts} +20 -1
- package/dist/{codec-Bux_Q40X.d.ts → codec-Bb6GKTrv.d.ts} +21 -2
- package/dist/{codec-EvybrBuY.d.cts → codec-BgpfHoAd.d.cts} +20 -1
- package/dist/{codec-alVA27Uc.d.ts → codec-BkheTXO7.d.ts} +20 -1
- package/dist/{codec-Czejcmxr.d.cts → codec-BwVDkokh.d.cts} +21 -2
- package/dist/{codec-BrTi4K7r.d.cts → codec-C5s1eBJX.d.cts} +21 -2
- package/dist/codec-CM5yd6n3.d.ts +38 -0
- package/dist/{codec-CWnf8mn_.d.cts → codec-Cb8HC3XV.d.cts} +21 -2
- package/dist/codec-Clu_skx8.d.cts +38 -0
- package/dist/{codec-DzkdW4kO.d.cts → codec-CpOpemR8.d.cts} +20 -1
- package/dist/{codec-CXCjya_G.d.cts → codec-Cshdl9Tt.d.cts} +20 -1
- package/dist/{codec-f7vxeVIS.d.cts → codec-DELe00w_.d.cts} +21 -2
- package/dist/{codec-DNmiG2e0.d.cts → codec-DHzKAUCa.d.cts} +20 -1
- package/dist/{codec--CVeqGQv.d.ts → codec-DdVBtvx7.d.ts} +20 -1
- package/dist/{codec-CBdOIfMY.d.ts → codec-DlxGuYMv.d.ts} +21 -2
- package/dist/{codec-BNy5syCU.d.ts → codec-DxtgPxJS.d.ts} +20 -1
- package/dist/{codec-guzqtfMk.d.cts → codec-GAY4lybi.d.cts} +20 -1
- package/dist/{codec-Cfo_z5ET.d.cts → codec-I8u2pfS4.d.cts} +20 -1
- package/dist/{codec-BxQTybUX.d.cts → codec-XLrnreeu.d.cts} +21 -2
- package/dist/{codec-DOmAmFkI.d.ts → codec-c0YEwwWn.d.ts} +20 -1
- package/dist/{codec-DaXjRrOV.d.ts → codec-ejDu-va6.d.ts} +21 -2
- package/dist/{codec-C3mdsGx3.d.ts → codec-kaBUzdpV.d.ts} +21 -2
- package/dist/{codec-CwZ6OCPP.d.ts → codec-mVYqkIUF.d.ts} +21 -2
- package/dist/{codec-08ZOr5wI.d.ts → codec-qSbO5nOa.d.ts} +21 -2
- package/dist/{codec-Cm3D261p.d.ts → codec-yYKGOipj.d.ts} +20 -1
- package/dist/{codec-Bd60SGKH.d.cts → codec-zfzg9uiy.d.cts} +20 -1
- package/dist/draft07.cjs +48 -4
- package/dist/draft07.d.cts +42 -2
- package/dist/draft07.d.ts +42 -2
- package/dist/draft07.js +49 -5
- package/dist/draft08.cjs +76 -3
- package/dist/draft08.d.cts +70 -2
- package/dist/draft08.d.ts +70 -2
- package/dist/draft08.js +77 -4
- package/dist/draft09.cjs +76 -3
- package/dist/draft09.d.cts +70 -2
- package/dist/draft09.d.ts +70 -2
- package/dist/draft09.js +77 -4
- package/dist/draft10.cjs +76 -3
- package/dist/draft10.d.cts +70 -2
- package/dist/draft10.d.ts +70 -2
- package/dist/draft10.js +77 -4
- package/dist/draft11.cjs +104 -3
- package/dist/draft11.d.cts +98 -2
- package/dist/draft11.d.ts +98 -2
- package/dist/draft11.js +105 -4
- package/dist/draft12.cjs +113 -3
- package/dist/draft12.d.cts +107 -2
- package/dist/draft12.d.ts +107 -2
- package/dist/draft12.js +114 -4
- package/dist/draft13.cjs +105 -3
- package/dist/draft13.d.cts +99 -2
- package/dist/draft13.d.ts +99 -2
- package/dist/draft13.js +106 -4
- package/dist/draft14.cjs +107 -3
- package/dist/draft14.d.cts +101 -28
- package/dist/draft14.d.ts +101 -28
- package/dist/draft14.js +108 -4
- package/dist/draft15-session.d.cts +1 -1
- package/dist/draft15-session.d.ts +1 -1
- package/dist/draft15.cjs +69 -3
- package/dist/draft15.d.cts +65 -22
- package/dist/draft15.d.ts +65 -22
- package/dist/draft15.js +70 -4
- package/dist/draft16-session.cjs +2 -2
- package/dist/draft16-session.d.cts +1 -1
- package/dist/draft16-session.d.ts +1 -1
- package/dist/draft16-session.js +1 -1
- package/dist/draft16.cjs +76 -8
- package/dist/draft16.d.cts +67 -13
- package/dist/draft16.d.ts +67 -13
- package/dist/draft16.js +73 -5
- package/dist/draft17-session.d.cts +1 -1
- package/dist/draft17-session.d.ts +1 -1
- package/dist/draft17.cjs +77 -3
- package/dist/draft17.d.cts +73 -4
- package/dist/draft17.d.ts +73 -4
- package/dist/draft17.js +78 -4
- package/dist/draft18-session.d.cts +1 -1
- package/dist/draft18-session.d.ts +1 -1
- package/dist/draft18.cjs +8 -3
- package/dist/draft18.d.cts +4 -3
- package/dist/draft18.d.ts +4 -3
- package/dist/draft18.js +9 -4
- package/dist/draft19-session.d.cts +1 -1
- package/dist/draft19-session.d.ts +1 -1
- package/dist/draft19.cjs +11 -4
- package/dist/draft19.d.cts +4 -3
- package/dist/draft19.d.ts +4 -3
- package/dist/draft19.js +12 -5
- package/dist/draft20-session.d.cts +1 -1
- package/dist/draft20-session.d.ts +1 -1
- package/dist/draft20.cjs +8 -3
- package/dist/draft20.d.cts +4 -3
- package/dist/draft20.d.ts +4 -3
- package/dist/draft20.js +9 -4
- package/dist/index.cjs +30 -30
- package/dist/index.d.cts +21 -20
- package/dist/index.d.ts +21 -20
- package/dist/index.js +15 -15
- package/dist/session.cjs +2 -2
- package/dist/session.d.cts +6 -6
- package/dist/session.d.ts +6 -6
- package/dist/session.js +1 -1
- package/dist/{types-C1rxh-id.d.cts → types-Btp416jt.d.cts} +8 -0
- package/dist/{types-C1rxh-id.d.ts → types-Btp416jt.d.ts} +8 -0
- package/dist/{types-CZTzbIzQ.d.cts → types-BxTL1NXw.d.cts} +7 -0
- package/dist/{types-CZTzbIzQ.d.ts → types-BxTL1NXw.d.ts} +7 -0
- package/dist/{types-pShrs3fN.d.cts → types-CuibHYcf.d.cts} +7 -0
- package/dist/{types-pShrs3fN.d.ts → types-CuibHYcf.d.ts} +7 -0
- package/dist/{types-CY-QWxd-.d.cts → types-CwN7AEoL.d.cts} +13 -1
- package/dist/{types-CY-QWxd-.d.ts → types-CwN7AEoL.d.ts} +13 -1
- package/dist/{types-D4bmW8rY.d.cts → types-DAnalt5K.d.cts} +7 -0
- package/dist/{types-D4bmW8rY.d.ts → types-DAnalt5K.d.ts} +7 -0
- package/dist/{types-Bg86GGVZ.d.cts → types-DxXNP32l.d.cts} +8 -0
- package/dist/{types-Bg86GGVZ.d.ts → types-DxXNP32l.d.ts} +8 -0
- package/package.json +3 -3
- package/src/core/auth-redaction.ts +192 -0
- package/src/drafts/draft07/codec.ts +40 -0
- package/src/drafts/draft07/error-codes.ts +44 -0
- package/src/drafts/draft07/index.ts +15 -0
- package/src/drafts/draft08/codec.ts +40 -0
- package/src/drafts/draft08/error-codes.ts +76 -0
- package/src/drafts/draft08/index.ts +21 -0
- package/src/drafts/draft09/codec.ts +40 -0
- package/src/drafts/draft09/error-codes.ts +76 -0
- package/src/drafts/draft09/index.ts +21 -0
- package/src/drafts/draft10/codec.ts +40 -0
- package/src/drafts/draft10/error-codes.ts +76 -0
- package/src/drafts/draft10/index.ts +21 -0
- package/src/drafts/draft11/codec.ts +60 -0
- package/src/drafts/draft11/error-codes.ts +106 -0
- package/src/drafts/draft11/index.ts +23 -0
- package/src/drafts/draft12/codec.ts +61 -0
- package/src/drafts/draft12/error-codes.ts +116 -0
- package/src/drafts/draft12/index.ts +25 -0
- package/src/drafts/draft13/codec.ts +69 -11
- package/src/drafts/draft13/error-codes.ts +107 -0
- package/src/drafts/draft13/index.ts +23 -0
- package/src/drafts/draft13/types.ts +1 -1
- package/src/drafts/draft14/codec.ts +65 -4
- package/src/drafts/draft14/data-streams.ts +331 -259
- package/src/drafts/draft14/error-codes.ts +109 -0
- package/src/drafts/draft14/index.ts +23 -0
- package/src/drafts/draft15/codec.ts +65 -8
- package/src/drafts/draft15/data-streams.ts +489 -444
- package/src/drafts/draft15/error-codes.ts +66 -0
- package/src/drafts/draft15/index.ts +15 -0
- package/src/drafts/draft15/types.ts +7 -0
- package/src/drafts/draft16/codec.ts +146 -52
- package/src/drafts/draft16/data-streams.ts +513 -442
- package/src/drafts/draft16/error-codes.ts +68 -0
- package/src/drafts/draft16/index.ts +15 -0
- package/src/drafts/draft16/messages.ts +4 -4
- package/src/drafts/draft16/session-fsm.ts +0 -1
- package/src/drafts/draft16/types.ts +22 -8
- package/src/drafts/draft17/codec.ts +73 -12
- package/src/drafts/draft17/data-streams.ts +567 -488
- package/src/drafts/draft17/index.ts +15 -0
- package/src/drafts/draft17/types.ts +7 -0
- package/src/drafts/draft18/codec.ts +66 -9
- package/src/drafts/draft18/data-streams.ts +570 -482
- package/src/drafts/draft18/index.ts +3 -0
- package/src/drafts/draft18/types.ts +16 -8
- package/src/drafts/draft19/codec.ts +70 -10
- package/src/drafts/draft19/data-streams.ts +570 -482
- package/src/drafts/draft19/error-codes.ts +3 -1
- package/src/drafts/draft19/index.ts +3 -0
- package/src/drafts/draft19/messages.ts +3 -1
- package/src/drafts/draft19/types.ts +22 -11
- package/src/drafts/draft20/codec.ts +90 -23
- package/src/drafts/draft20/data-streams.ts +610 -563
- package/src/drafts/draft20/index.ts +3 -0
- package/src/drafts/draft20/types.ts +14 -2
- package/dist/codec-BJ7BHuiZ.d.ts +0 -18
- package/dist/codec-C6Mx4bwz.d.cts +0 -18
|
@@ -139,98 +139,151 @@ export function encodeFetchStream(stream: FetchStream): Uint8Array {
|
|
|
139
139
|
* Decode a subgroup data stream from raw bytes.
|
|
140
140
|
* Accepts types 0x10-0x15 and 0x18-0x1D. Delta-decodes Object IDs.
|
|
141
141
|
*/
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
142
|
+
/**
|
|
143
|
+
* The SUBGROUP_HEADER fields, read once for both decoders.
|
|
144
|
+
*
|
|
145
|
+
* `decodeSubgroupStream` and `createSubgroupStreamDecoder` used to parse this
|
|
146
|
+
* header separately and they drifted: the incremental one dropped the header
|
|
147
|
+
* flags, reported no Type Flags, and left the Subgroup ID at zero under the
|
|
148
|
+
* mode that derives it from the first Object. One reader means there is
|
|
149
|
+
* nothing left to keep in sync.
|
|
150
|
+
*/
|
|
151
|
+
interface SubgroupHeaderFields {
|
|
152
|
+
readonly streamType: number
|
|
153
|
+
readonly extensionsPresent: boolean
|
|
154
|
+
readonly subgroupIsFirstObjId: boolean
|
|
155
|
+
readonly trackAlias: bigint
|
|
156
|
+
readonly groupId: bigint
|
|
157
|
+
/** Zero under `subgroupIsFirstObjId` until the first Object has been read. */
|
|
158
|
+
readonly subgroupId: bigint
|
|
159
|
+
readonly publisherPriority: number
|
|
160
|
+
}
|
|
146
161
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
}
|
|
162
|
+
function readSubgroupHeader(r: BufferReader): SubgroupHeaderFields {
|
|
163
|
+
const streamType = Number(r.readVarInt())
|
|
164
|
+
if (!isValidSubgroupType(streamType)) {
|
|
165
|
+
throw new DecodeError(
|
|
166
|
+
'CONSTRAINT_VIOLATION',
|
|
167
|
+
`Expected subgroup stream type 0x10-0x1D, got 0x${streamType.toString(16)}`,
|
|
168
|
+
0,
|
|
169
|
+
)
|
|
170
|
+
}
|
|
157
171
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
const subgroupIsFirstObjId = (streamType & 0x02) !== 0 && !hasSubgroupField
|
|
172
|
+
const extensionsPresent = (streamType & 0x01) !== 0
|
|
173
|
+
const hasSubgroupField = (streamType & 0x04) !== 0
|
|
174
|
+
const subgroupIsFirstObjId = (streamType & 0x02) !== 0 && !hasSubgroupField
|
|
162
175
|
|
|
163
|
-
|
|
164
|
-
|
|
176
|
+
const trackAlias = r.readVarInt()
|
|
177
|
+
const groupId = r.readVarInt()
|
|
165
178
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
179
|
+
let subgroupId = 0n
|
|
180
|
+
if (hasSubgroupField) {
|
|
181
|
+
subgroupId = r.readVarInt()
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
const publisherPriority = r.readUint8()
|
|
185
|
+
|
|
186
|
+
return {
|
|
187
|
+
streamType,
|
|
188
|
+
extensionsPresent,
|
|
189
|
+
subgroupIsFirstObjId,
|
|
190
|
+
trackAlias,
|
|
191
|
+
groupId,
|
|
192
|
+
subgroupId,
|
|
193
|
+
publisherPriority,
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* One Object off a subgroup stream, for both decoders.
|
|
199
|
+
*
|
|
200
|
+
* `base` is the absolute offset within the stream that `r.offset === 0`
|
|
201
|
+
* corresponds to. The one-shot decoder reads from a reader spanning the whole
|
|
202
|
+
* stream and passes 0; the incremental decoder reads from a window over its
|
|
203
|
+
* own buffer and passes that window's position. That is what makes
|
|
204
|
+
* `byteOffset` mean the same thing on both paths, instead of being hardcoded
|
|
205
|
+
* to zero on one of them.
|
|
206
|
+
*
|
|
207
|
+
* Throws `UNEXPECTED_END` when the Object is not yet complete, which the
|
|
208
|
+
* incremental decoder reads as "wait for more bytes" rather than as an error.
|
|
209
|
+
*/
|
|
210
|
+
function readSubgroupObject(
|
|
211
|
+
r: BufferReader,
|
|
212
|
+
extensionsPresent: boolean,
|
|
213
|
+
isFirst: boolean,
|
|
214
|
+
prevObjectId: bigint,
|
|
215
|
+
base: number,
|
|
216
|
+
): ObjectPayload {
|
|
217
|
+
const byteOffset = base + r.offset
|
|
218
|
+
const delta = r.readVarInt()
|
|
219
|
+
const objectId = isFirst ? delta : prevObjectId + 1n + delta
|
|
220
|
+
|
|
221
|
+
let extensionData = new Uint8Array(0)
|
|
222
|
+
if (extensionsPresent) {
|
|
223
|
+
const extLen = Number(r.readVarInt())
|
|
224
|
+
extensionData = extLen > 0 ? r.readBytesView(extLen) : new Uint8Array(0)
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
const payloadLength = Number(r.readVarInt())
|
|
228
|
+
let payload: Uint8Array
|
|
229
|
+
let status: bigint | undefined
|
|
230
|
+
let payloadByteOffset: number
|
|
231
|
+
if (payloadLength === 0) {
|
|
232
|
+
// The Object Status field is sent only when the Payload Length is zero.
|
|
233
|
+
// Skipping it leaves the varint to be read as the next Object's Object ID
|
|
234
|
+
// Delta, which desynchronises the rest of the stream silently.
|
|
235
|
+
status = r.readVarInt()
|
|
236
|
+
payloadByteOffset = base + r.offset
|
|
237
|
+
payload = new Uint8Array(0)
|
|
238
|
+
} else {
|
|
239
|
+
payloadByteOffset = base + r.offset
|
|
240
|
+
payload = r.readBytesView(payloadLength)
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
const obj: ObjectPayload = {
|
|
244
|
+
type: 'object',
|
|
245
|
+
byteOffset,
|
|
246
|
+
payloadByteOffset,
|
|
247
|
+
objectId,
|
|
248
|
+
payloadLength,
|
|
249
|
+
payload,
|
|
250
|
+
extensionData,
|
|
251
|
+
}
|
|
252
|
+
if (status !== undefined) (obj as unknown as Record<string, unknown>).status = status
|
|
253
|
+
return obj
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
export function decodeSubgroupStream(bytes: Uint8Array): DecodeResult<SubgroupStream> {
|
|
257
|
+
try {
|
|
258
|
+
const r = new BufferReader(bytes)
|
|
259
|
+
const h = readSubgroupHeader(r)
|
|
171
260
|
|
|
172
261
|
const objects: ObjectPayload[] = []
|
|
173
262
|
let prevObjectId = -1n
|
|
174
|
-
let
|
|
263
|
+
let isFirst = true
|
|
264
|
+
let subgroupId = h.subgroupId
|
|
175
265
|
|
|
176
266
|
while (r.remaining > 0) {
|
|
177
|
-
const
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
if (firstObject) {
|
|
181
|
-
objectId = delta
|
|
182
|
-
if (subgroupIsFirstObjId) {
|
|
183
|
-
subgroupId = objectId
|
|
184
|
-
}
|
|
185
|
-
firstObject = false
|
|
186
|
-
} else {
|
|
187
|
-
objectId = prevObjectId + 1n + delta
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
// Read extension headers if type indicates they're present
|
|
191
|
-
let extensionData = new Uint8Array(0)
|
|
192
|
-
if (extensionsPresent) {
|
|
193
|
-
const extLen = Number(r.readVarInt())
|
|
194
|
-
extensionData = extLen > 0 ? r.readBytesView(extLen) : new Uint8Array(0)
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
const payloadLength = Number(r.readVarInt())
|
|
198
|
-
let payload: Uint8Array
|
|
199
|
-
let status: bigint | undefined
|
|
200
|
-
let payloadByteOffset: number
|
|
201
|
-
if (payloadLength === 0) {
|
|
202
|
-
status = r.readVarInt()
|
|
203
|
-
payloadByteOffset = r.offset
|
|
204
|
-
payload = new Uint8Array(0)
|
|
205
|
-
} else {
|
|
206
|
-
payloadByteOffset = r.offset
|
|
207
|
-
payload = r.readBytesView(payloadLength)
|
|
208
|
-
}
|
|
209
|
-
const obj: ObjectPayload = {
|
|
210
|
-
type: 'object',
|
|
211
|
-
byteOffset,
|
|
212
|
-
payloadByteOffset,
|
|
213
|
-
objectId,
|
|
214
|
-
payloadLength,
|
|
215
|
-
payload,
|
|
216
|
-
extensionData,
|
|
217
|
-
}
|
|
218
|
-
if (status !== undefined) (obj as unknown as Record<string, unknown>).status = status
|
|
267
|
+
const obj = readSubgroupObject(r, h.extensionsPresent, isFirst, prevObjectId, 0)
|
|
268
|
+
if (isFirst && h.subgroupIsFirstObjId) subgroupId = obj.objectId
|
|
269
|
+
isFirst = false
|
|
219
270
|
objects.push(obj)
|
|
220
|
-
prevObjectId = objectId
|
|
271
|
+
prevObjectId = obj.objectId
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
const result: SubgroupStream = {
|
|
275
|
+
type: 'subgroup',
|
|
276
|
+
headerType: h.streamType,
|
|
277
|
+
trackAlias: h.trackAlias,
|
|
278
|
+
groupId: h.groupId,
|
|
279
|
+
subgroupId,
|
|
280
|
+
publisherPriority: h.publisherPriority,
|
|
281
|
+
objects,
|
|
221
282
|
}
|
|
222
283
|
|
|
223
284
|
return {
|
|
224
285
|
ok: true,
|
|
225
|
-
value:
|
|
226
|
-
type: 'subgroup',
|
|
227
|
-
headerType: streamType,
|
|
228
|
-
trackAlias,
|
|
229
|
-
groupId,
|
|
230
|
-
subgroupId,
|
|
231
|
-
publisherPriority,
|
|
232
|
-
objects,
|
|
233
|
-
},
|
|
286
|
+
value: result,
|
|
234
287
|
bytesRead: r.offset,
|
|
235
288
|
}
|
|
236
289
|
} catch (e) {
|
|
@@ -239,10 +292,6 @@ export function decodeSubgroupStream(bytes: Uint8Array): DecodeResult<SubgroupSt
|
|
|
239
292
|
}
|
|
240
293
|
}
|
|
241
294
|
|
|
242
|
-
/**
|
|
243
|
-
* Decode a datagram object from raw bytes.
|
|
244
|
-
* Accepts types 0x00-0x07 and 0x20-0x21.
|
|
245
|
-
*/
|
|
246
295
|
export function decodeDatagram(bytes: Uint8Array): DecodeResult<DatagramObject> {
|
|
247
296
|
try {
|
|
248
297
|
const r = new BufferReader(bytes)
|
|
@@ -318,6 +367,66 @@ export function decodeDatagram(bytes: Uint8Array): DecodeResult<DatagramObject>
|
|
|
318
367
|
* Decode a fetch data stream from raw bytes.
|
|
319
368
|
* Draft-14 fetch: type 0x05, per-object has all fields (no serialization flags).
|
|
320
369
|
*/
|
|
370
|
+
/**
|
|
371
|
+
* Nothing is carried between fetch Objects in this draft: Group ID,
|
|
372
|
+
* Subgroup ID, Object ID and Priority are all absolute on the wire, so the
|
|
373
|
+
* reader is a pure function of the bytes in front of it.
|
|
374
|
+
*/
|
|
375
|
+
type FetchObjectState = Record<string, never>
|
|
376
|
+
|
|
377
|
+
function newFetchObjectState(): FetchObjectState {
|
|
378
|
+
return {}
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
/**
|
|
382
|
+
* One Object off a fetch stream, for both decoders.
|
|
383
|
+
*
|
|
384
|
+
* Lifted out of `decodeFetchStream` unchanged so the incremental decoder
|
|
385
|
+
* cannot report a different shape for the same bytes. It used to return a
|
|
386
|
+
* bare ObjectPayload -- no Serialization Flags, no Group or Subgroup ID, no
|
|
387
|
+
* Priority, no deltas -- with every `byteOffset` zero, and in DATAGRAM mode
|
|
388
|
+
* it resolved the Object ID against state it never carried.
|
|
389
|
+
*
|
|
390
|
+
* `base` is the absolute offset that `r.offset === 0` corresponds to: 0 for
|
|
391
|
+
* the one-shot decoder, the buffer window's position for the incremental one.
|
|
392
|
+
*/
|
|
393
|
+
function readFetchObject(r: BufferReader, base: number, _st: FetchObjectState): FetchObjectPayload {
|
|
394
|
+
const byteOffset = base + r.offset
|
|
395
|
+
const groupId = r.readVarInt()
|
|
396
|
+
const subgroupId = r.readVarInt()
|
|
397
|
+
const objectId = r.readVarInt()
|
|
398
|
+
const publisherPriority = r.readUint8()
|
|
399
|
+
const extLen = Number(r.readVarInt())
|
|
400
|
+
const extensionData = extLen > 0 ? r.readBytesView(extLen) : new Uint8Array(0)
|
|
401
|
+
const payloadLength = Number(r.readVarInt())
|
|
402
|
+
let payload: Uint8Array
|
|
403
|
+
let status: bigint | undefined
|
|
404
|
+
let payloadByteOffset: number
|
|
405
|
+
if (payloadLength === 0) {
|
|
406
|
+
status = r.readVarInt()
|
|
407
|
+
payloadByteOffset = base + r.offset
|
|
408
|
+
payload = new Uint8Array(0)
|
|
409
|
+
} else {
|
|
410
|
+
payloadByteOffset = base + r.offset
|
|
411
|
+
payload = r.readBytesView(payloadLength)
|
|
412
|
+
}
|
|
413
|
+
const obj: FetchObjectPayload = {
|
|
414
|
+
type: 'object',
|
|
415
|
+
byteOffset,
|
|
416
|
+
payloadByteOffset,
|
|
417
|
+
groupId,
|
|
418
|
+
subgroupId,
|
|
419
|
+
objectId,
|
|
420
|
+
publisherPriority,
|
|
421
|
+
payloadLength,
|
|
422
|
+
payload,
|
|
423
|
+
extensionData,
|
|
424
|
+
}
|
|
425
|
+
if (status !== undefined) (obj as unknown as Record<string, unknown>).status = status
|
|
426
|
+
|
|
427
|
+
return obj
|
|
428
|
+
}
|
|
429
|
+
|
|
321
430
|
export function decodeFetchStream(bytes: Uint8Array): DecodeResult<FetchStream> {
|
|
322
431
|
try {
|
|
323
432
|
const r = new BufferReader(bytes)
|
|
@@ -334,40 +443,10 @@ export function decodeFetchStream(bytes: Uint8Array): DecodeResult<FetchStream>
|
|
|
334
443
|
}
|
|
335
444
|
const requestId = r.readVarInt()
|
|
336
445
|
const objects: FetchObjectPayload[] = []
|
|
446
|
+
const st = newFetchObjectState()
|
|
447
|
+
|
|
337
448
|
while (r.remaining > 0) {
|
|
338
|
-
|
|
339
|
-
const groupId = r.readVarInt()
|
|
340
|
-
const subgroupId = r.readVarInt()
|
|
341
|
-
const objectId = r.readVarInt()
|
|
342
|
-
const publisherPriority = r.readUint8()
|
|
343
|
-
const extLen = Number(r.readVarInt())
|
|
344
|
-
const extensionData = extLen > 0 ? r.readBytesView(extLen) : new Uint8Array(0)
|
|
345
|
-
const payloadLength = Number(r.readVarInt())
|
|
346
|
-
let payload: Uint8Array
|
|
347
|
-
let status: bigint | undefined
|
|
348
|
-
let payloadByteOffset: number
|
|
349
|
-
if (payloadLength === 0) {
|
|
350
|
-
status = r.readVarInt()
|
|
351
|
-
payloadByteOffset = r.offset
|
|
352
|
-
payload = new Uint8Array(0)
|
|
353
|
-
} else {
|
|
354
|
-
payloadByteOffset = r.offset
|
|
355
|
-
payload = r.readBytesView(payloadLength)
|
|
356
|
-
}
|
|
357
|
-
const obj: FetchObjectPayload = {
|
|
358
|
-
type: 'object',
|
|
359
|
-
byteOffset,
|
|
360
|
-
payloadByteOffset,
|
|
361
|
-
groupId,
|
|
362
|
-
subgroupId,
|
|
363
|
-
objectId,
|
|
364
|
-
publisherPriority,
|
|
365
|
-
payloadLength,
|
|
366
|
-
payload,
|
|
367
|
-
extensionData,
|
|
368
|
-
}
|
|
369
|
-
if (status !== undefined) (obj as unknown as Record<string, unknown>).status = status
|
|
370
|
-
objects.push(obj)
|
|
449
|
+
objects.push(readFetchObject(r, 0, st))
|
|
371
450
|
}
|
|
372
451
|
return {
|
|
373
452
|
ok: true,
|
|
@@ -408,62 +487,106 @@ export function decodeDataStream(
|
|
|
408
487
|
* First emits a SubgroupStreamHeader, then emits ObjectPayload events.
|
|
409
488
|
* Accepts types 0x10-0x1D. Delta-decodes Object IDs.
|
|
410
489
|
*/
|
|
490
|
+
/**
|
|
491
|
+
* A data stream's bytes, accumulated across chunks.
|
|
492
|
+
*
|
|
493
|
+
* The decoders below used to allocate an array of `unread + chunk.length` and
|
|
494
|
+
* copy both halves into it on *every* chunk. Capacity now grows geometrically,
|
|
495
|
+
* so most chunks are a single `set` into spare room.
|
|
496
|
+
*
|
|
497
|
+
* **It never compacts in place.** Object payloads are handed out as views into
|
|
498
|
+
* this buffer (`readBytesView`), so moving bytes within it would corrupt an
|
|
499
|
+
* object that has already been emitted. The consumed prefix is dropped only
|
|
500
|
+
* when a fresh array is being allocated anyway, which leaves the old array
|
|
501
|
+
* alive for exactly as long as the views into it are.
|
|
502
|
+
*/
|
|
503
|
+
class StreamBuffer {
|
|
504
|
+
private buf = new Uint8Array(0)
|
|
505
|
+
/** Bytes written into `buf`. */
|
|
506
|
+
private len = 0
|
|
507
|
+
/** Consumed prefix of `buf`; `base + offset` is the position in the stream. */
|
|
508
|
+
offset = 0
|
|
509
|
+
/** Absolute position of `buf[0]` within the stream. */
|
|
510
|
+
base = 0
|
|
511
|
+
|
|
512
|
+
get unread(): number {
|
|
513
|
+
return this.len - this.offset
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
append(chunk: Uint8Array): void {
|
|
517
|
+
if (this.len + chunk.length > this.buf.length) {
|
|
518
|
+
const live = this.len - this.offset
|
|
519
|
+
const needed = live + chunk.length
|
|
520
|
+
// Grow until reclaiming the consumed prefix leaves the buffer at least
|
|
521
|
+
// half free. Sizing to `needed` -- which is what this did first -- leaves
|
|
522
|
+
// no room at all, so the next chunk reallocates too and the buffer
|
|
523
|
+
// reallocates on every single chunk, which is the cost it exists to
|
|
524
|
+
// avoid. Capacity never shrinks, so it settles at roughly twice the
|
|
525
|
+
// largest `live + chunk` this stream has seen.
|
|
526
|
+
let cap = Math.max(4096, this.buf.length)
|
|
527
|
+
while (cap < needed * 2) cap *= 2
|
|
528
|
+
// A fresh array every time, including when the capacity is unchanged:
|
|
529
|
+
// the old one is still pinned by the payload views handed out of it, so
|
|
530
|
+
// it can be neither compacted nor reused.
|
|
531
|
+
const next = new Uint8Array(cap)
|
|
532
|
+
next.set(this.buf.subarray(this.offset, this.len), 0)
|
|
533
|
+
this.buf = next
|
|
534
|
+
this.base += this.offset
|
|
535
|
+
this.len = live
|
|
536
|
+
this.offset = 0
|
|
537
|
+
}
|
|
538
|
+
this.buf.set(chunk, this.len)
|
|
539
|
+
this.len += chunk.length
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
/**
|
|
543
|
+
* The written bytes, for a reader positioned at `offset`. Bounded by `len`
|
|
544
|
+
* rather than by capacity, so `BufferReader.remaining` counts real bytes and
|
|
545
|
+
* not the spare room after them.
|
|
546
|
+
*/
|
|
547
|
+
written(): Uint8Array {
|
|
548
|
+
return this.buf.subarray(0, this.len)
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
|
|
411
552
|
export function createSubgroupStreamDecoder(): TransformStream<
|
|
412
553
|
Uint8Array,
|
|
413
554
|
SubgroupStreamHeader | ObjectPayload
|
|
414
555
|
> {
|
|
415
|
-
|
|
416
|
-
let
|
|
556
|
+
const b = new StreamBuffer()
|
|
557
|
+
let header: SubgroupHeaderFields | null = null
|
|
417
558
|
let headerEmitted = false
|
|
418
|
-
let extensionsPresent = false
|
|
419
559
|
let prevObjectId = -1n
|
|
420
|
-
let
|
|
560
|
+
let isFirst = true
|
|
561
|
+
|
|
562
|
+
function emitHeader(
|
|
563
|
+
controller: TransformStreamDefaultController<SubgroupStreamHeader | ObjectPayload>,
|
|
564
|
+
h: SubgroupHeaderFields,
|
|
565
|
+
subgroupId: bigint,
|
|
566
|
+
): void {
|
|
567
|
+
controller.enqueue({
|
|
568
|
+
type: 'subgroup_header',
|
|
569
|
+
headerType: h.streamType,
|
|
570
|
+
trackAlias: h.trackAlias,
|
|
571
|
+
groupId: h.groupId,
|
|
572
|
+
subgroupId,
|
|
573
|
+
publisherPriority: h.publisherPriority,
|
|
574
|
+
})
|
|
575
|
+
headerEmitted = true
|
|
576
|
+
}
|
|
421
577
|
|
|
422
578
|
return new TransformStream<Uint8Array, SubgroupStreamHeader | ObjectPayload>({
|
|
423
579
|
transform(chunk, controller) {
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
const newBuffer = new Uint8Array(buffer.length + chunk.length)
|
|
429
|
-
newBuffer.set(buffer, 0)
|
|
430
|
-
newBuffer.set(chunk, buffer.length)
|
|
431
|
-
buffer = newBuffer
|
|
580
|
+
b.append(chunk)
|
|
581
|
+
// One view and one reader per chunk. Both used to be allocated per
|
|
582
|
+
// object, and an object is the thing there are a great many of.
|
|
583
|
+
const view = b.written()
|
|
432
584
|
|
|
433
|
-
if (
|
|
585
|
+
if (header === null) {
|
|
434
586
|
try {
|
|
435
|
-
const
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
controller.error(
|
|
439
|
-
new DecodeError(
|
|
440
|
-
'CONSTRAINT_VIOLATION',
|
|
441
|
-
`Expected subgroup stream type 0x10-0x1D, got 0x${streamType.toString(16)}`,
|
|
442
|
-
0,
|
|
443
|
-
),
|
|
444
|
-
)
|
|
445
|
-
return
|
|
446
|
-
}
|
|
447
|
-
extensionsPresent = (streamType & 0x01) !== 0
|
|
448
|
-
const hasSubgroupField = (streamType & 0x04) !== 0
|
|
449
|
-
const trackAlias = r.readVarInt()
|
|
450
|
-
const groupId = r.readVarInt()
|
|
451
|
-
let subgroupId = 0n
|
|
452
|
-
if (hasSubgroupField) {
|
|
453
|
-
subgroupId = r.readVarInt()
|
|
454
|
-
}
|
|
455
|
-
const publisherPriority = r.readUint8()
|
|
456
|
-
|
|
457
|
-
controller.enqueue({
|
|
458
|
-
type: 'subgroup_header',
|
|
459
|
-
headerType: streamType,
|
|
460
|
-
trackAlias,
|
|
461
|
-
groupId,
|
|
462
|
-
subgroupId,
|
|
463
|
-
publisherPriority,
|
|
464
|
-
})
|
|
465
|
-
headerEmitted = true
|
|
466
|
-
offset += r.offset
|
|
587
|
+
const hr = new BufferReader(view, b.offset)
|
|
588
|
+
header = readSubgroupHeader(hr)
|
|
589
|
+
b.offset = hr.offset
|
|
467
590
|
} catch (e) {
|
|
468
591
|
if (e instanceof DecodeError && e.code === 'UNEXPECTED_END') {
|
|
469
592
|
return
|
|
@@ -471,92 +594,73 @@ export function createSubgroupStreamDecoder(): TransformStream<
|
|
|
471
594
|
controller.error(e)
|
|
472
595
|
return
|
|
473
596
|
}
|
|
597
|
+
// Where the Subgroup ID is the first Object's ID, that Object has not
|
|
598
|
+
// been read yet. Holding the header back until it has is the only way
|
|
599
|
+
// to emit the value the one-shot decoder reports; every other mode
|
|
600
|
+
// knows its Subgroup ID already.
|
|
601
|
+
if (!header.subgroupIsFirstObjId) emitHeader(controller, header, header.subgroupId)
|
|
474
602
|
}
|
|
475
603
|
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
const r = new BufferReader(buffer.subarray(offset))
|
|
479
|
-
const byteOffset = r.offset
|
|
480
|
-
const delta = r.readVarInt()
|
|
481
|
-
const objectId = firstObject ? delta : prevObjectId + 1n + delta
|
|
482
|
-
firstObject = false
|
|
604
|
+
const h = header
|
|
605
|
+
if (h === null) return
|
|
483
606
|
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
let status: bigint | undefined
|
|
493
|
-
let payloadByteOffset: number
|
|
494
|
-
if (payloadLength === 0) {
|
|
495
|
-
status = r.readVarInt()
|
|
496
|
-
payloadByteOffset = r.offset
|
|
497
|
-
payload = new Uint8Array(0)
|
|
498
|
-
} else {
|
|
499
|
-
payloadByteOffset = r.offset
|
|
500
|
-
payload = r.readBytesView(payloadLength)
|
|
501
|
-
}
|
|
502
|
-
const obj: ObjectPayload = {
|
|
503
|
-
type: 'object',
|
|
504
|
-
byteOffset,
|
|
505
|
-
payloadByteOffset,
|
|
506
|
-
objectId,
|
|
507
|
-
payloadLength,
|
|
508
|
-
payload,
|
|
509
|
-
extensionData,
|
|
510
|
-
}
|
|
511
|
-
if (status !== undefined) (obj as unknown as Record<string, unknown>).status = status
|
|
512
|
-
controller.enqueue(obj)
|
|
513
|
-
prevObjectId = objectId
|
|
514
|
-
offset += r.offset
|
|
607
|
+
const r = new BufferReader(view, b.offset)
|
|
608
|
+
while (r.remaining > 0) {
|
|
609
|
+
// Where this Object starts, so a partial one is re-read from the top
|
|
610
|
+
// once the rest of it arrives.
|
|
611
|
+
const start = r.offset
|
|
612
|
+
let obj: ObjectPayload
|
|
613
|
+
try {
|
|
614
|
+
obj = readSubgroupObject(r, h.extensionsPresent, isFirst, prevObjectId, b.base)
|
|
515
615
|
} catch (e) {
|
|
516
616
|
if (e instanceof DecodeError && e.code === 'UNEXPECTED_END') {
|
|
517
|
-
|
|
617
|
+
b.offset = start
|
|
618
|
+
return
|
|
518
619
|
}
|
|
519
620
|
controller.error(e)
|
|
520
621
|
return
|
|
521
622
|
}
|
|
623
|
+
if (!headerEmitted) emitHeader(controller, h, obj.objectId)
|
|
624
|
+
isFirst = false
|
|
625
|
+
b.offset = r.offset
|
|
626
|
+
prevObjectId = obj.objectId
|
|
627
|
+
controller.enqueue(obj)
|
|
522
628
|
}
|
|
523
629
|
},
|
|
524
630
|
|
|
525
631
|
flush(controller) {
|
|
526
|
-
|
|
632
|
+
// A stream carrying a header and no Objects still has a header to report,
|
|
633
|
+
// and its Subgroup ID is then zero -- the same value the one-shot decoder
|
|
634
|
+
// returns when it finds no first Object to derive one from.
|
|
635
|
+
if (header !== null && !headerEmitted) emitHeader(controller, header, 0n)
|
|
636
|
+
if (b.unread > 0) {
|
|
527
637
|
controller.error(new DecodeError('UNEXPECTED_END', 'Stream ended with incomplete data', 0))
|
|
528
638
|
}
|
|
529
639
|
},
|
|
530
640
|
})
|
|
531
641
|
}
|
|
532
642
|
|
|
533
|
-
/**
|
|
534
|
-
* Create a TransformStream that decodes a fetch data stream.
|
|
535
|
-
* First emits a FetchStreamHeader, then emits FetchObjectPayload events.
|
|
536
|
-
* Draft-14 fetch: type 0x05, per-object has all fields.
|
|
537
|
-
*/
|
|
538
643
|
export function createFetchStreamDecoder(): TransformStream<
|
|
539
644
|
Uint8Array,
|
|
540
645
|
FetchStreamHeader | ObjectPayload
|
|
541
646
|
> {
|
|
542
|
-
|
|
543
|
-
let offset = 0
|
|
647
|
+
const b = new StreamBuffer()
|
|
544
648
|
let headerEmitted = false
|
|
649
|
+
/**
|
|
650
|
+
* The delta state the Objects carry between them. This decoder used to keep
|
|
651
|
+
* none, which is why DATAGRAM-mode Object IDs came out wrong: they resolve
|
|
652
|
+
* against the previous Object's ID.
|
|
653
|
+
*/
|
|
654
|
+
const st = newFetchObjectState()
|
|
545
655
|
|
|
546
656
|
return new TransformStream<Uint8Array, FetchStreamHeader | ObjectPayload>({
|
|
547
657
|
transform(chunk, controller) {
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
offset = 0
|
|
551
|
-
}
|
|
552
|
-
const newBuffer = new Uint8Array(buffer.length + chunk.length)
|
|
553
|
-
newBuffer.set(buffer, 0)
|
|
554
|
-
newBuffer.set(chunk, buffer.length)
|
|
555
|
-
buffer = newBuffer
|
|
658
|
+
b.append(chunk)
|
|
659
|
+
const view = b.written()
|
|
556
660
|
|
|
557
661
|
if (!headerEmitted) {
|
|
558
662
|
try {
|
|
559
|
-
const r = new BufferReader(
|
|
663
|
+
const r = new BufferReader(view, b.offset)
|
|
560
664
|
const streamType = r.readVarInt()
|
|
561
665
|
if (streamType !== FETCH_STREAM_TYPE) {
|
|
562
666
|
controller.error(
|
|
@@ -572,7 +676,7 @@ export function createFetchStreamDecoder(): TransformStream<
|
|
|
572
676
|
|
|
573
677
|
controller.enqueue({ type: 'fetch_header', requestId })
|
|
574
678
|
headerEmitted = true
|
|
575
|
-
offset
|
|
679
|
+
b.offset = r.offset
|
|
576
680
|
} catch (e) {
|
|
577
681
|
if (e instanceof DecodeError && e.code === 'UNEXPECTED_END') {
|
|
578
682
|
return
|
|
@@ -582,65 +686,33 @@ export function createFetchStreamDecoder(): TransformStream<
|
|
|
582
686
|
}
|
|
583
687
|
}
|
|
584
688
|
|
|
585
|
-
|
|
689
|
+
const r = new BufferReader(view, b.offset)
|
|
690
|
+
while (r.remaining > 0) {
|
|
691
|
+
const start = r.offset
|
|
692
|
+
let obj: FetchObjectPayload
|
|
586
693
|
try {
|
|
587
|
-
|
|
588
|
-
const byteOffset = r.offset
|
|
589
|
-
const groupId = r.readVarInt()
|
|
590
|
-
const subgroupId = r.readVarInt()
|
|
591
|
-
const objectId = r.readVarInt()
|
|
592
|
-
const publisherPriority = r.readUint8()
|
|
593
|
-
const extLen = Number(r.readVarInt())
|
|
594
|
-
const extensionData = extLen > 0 ? r.readBytesView(extLen) : new Uint8Array(0)
|
|
595
|
-
const payloadLength = Number(r.readVarInt())
|
|
596
|
-
let payload: Uint8Array
|
|
597
|
-
let status: bigint | undefined
|
|
598
|
-
let payloadByteOffset: number
|
|
599
|
-
if (payloadLength === 0) {
|
|
600
|
-
status = r.readVarInt()
|
|
601
|
-
payloadByteOffset = r.offset
|
|
602
|
-
payload = new Uint8Array(0)
|
|
603
|
-
} else {
|
|
604
|
-
payloadByteOffset = r.offset
|
|
605
|
-
payload = r.readBytesView(payloadLength)
|
|
606
|
-
}
|
|
607
|
-
const obj: FetchObjectPayload = {
|
|
608
|
-
type: 'object',
|
|
609
|
-
byteOffset,
|
|
610
|
-
payloadByteOffset,
|
|
611
|
-
groupId,
|
|
612
|
-
subgroupId,
|
|
613
|
-
objectId,
|
|
614
|
-
publisherPriority,
|
|
615
|
-
payloadLength,
|
|
616
|
-
payload,
|
|
617
|
-
extensionData,
|
|
618
|
-
}
|
|
619
|
-
if (status !== undefined) (obj as unknown as Record<string, unknown>).status = status
|
|
620
|
-
controller.enqueue(obj)
|
|
621
|
-
offset += r.offset
|
|
694
|
+
obj = readFetchObject(r, b.base, st)
|
|
622
695
|
} catch (e) {
|
|
623
696
|
if (e instanceof DecodeError && e.code === 'UNEXPECTED_END') {
|
|
624
|
-
|
|
697
|
+
b.offset = start
|
|
698
|
+
return
|
|
625
699
|
}
|
|
626
700
|
controller.error(e)
|
|
627
701
|
return
|
|
628
702
|
}
|
|
703
|
+
b.offset = r.offset
|
|
704
|
+
controller.enqueue(obj)
|
|
629
705
|
}
|
|
630
706
|
},
|
|
631
707
|
|
|
632
708
|
flush(controller) {
|
|
633
|
-
if (
|
|
709
|
+
if (b.unread > 0) {
|
|
634
710
|
controller.error(new DecodeError('UNEXPECTED_END', 'Stream ended with incomplete data', 0))
|
|
635
711
|
}
|
|
636
712
|
},
|
|
637
713
|
})
|
|
638
714
|
}
|
|
639
715
|
|
|
640
|
-
/**
|
|
641
|
-
* Create a unified auto-detecting data stream decoder.
|
|
642
|
-
* Reads the stream type varint: 0x10-0x1D = subgroup, 0x05 = fetch.
|
|
643
|
-
*/
|
|
644
716
|
export function createDataStreamDecoder(): TransformStream<Uint8Array, DataStreamEvent> {
|
|
645
717
|
let buffer = new Uint8Array(0)
|
|
646
718
|
let offset = 0
|