@moqtap/codec 0.10.0 → 0.12.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 +175 -0
- package/README.md +3 -2
- package/dist/auth-redaction-B9JJOlIY.d.cts +100 -0
- package/dist/auth-redaction-B9JJOlIY.d.ts +100 -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-OBATJBNL.cjs +868 -0
- 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-T2TCLZZV.js +2304 -0
- package/dist/chunk-WB65UG7G.cjs +2304 -0
- package/dist/{chunk-CF5DDD3Q.js → chunk-WCRLAKDW.js} +239 -245
- package/dist/{chunk-KYVTM5VI.js → chunk-WL2YUEXH.js} +19 -3
- package/dist/chunk-XPCBPACE.js +868 -0
- package/dist/{chunk-KGDVC4O6.js → chunk-YCNIVZS7.js} +439 -469
- package/dist/{chunk-KLPWJU6W.js → chunk-YRZQVNZO.js} +50 -0
- package/dist/{codec-DOmAmFkI.d.ts → codec-B-oUU-cp.d.ts} +21 -2
- package/dist/{codec-DNmiG2e0.d.cts → codec-B3RpCI9k.d.cts} +21 -2
- package/dist/codec-B5pcOS3m.d.cts +38 -0
- package/dist/{codec-BNy5syCU.d.ts → codec-BLjxwK2f.d.ts} +21 -2
- package/dist/{codec-alVA27Uc.d.ts → codec-BV3CL_3m.d.ts} +21 -2
- package/dist/{codec-Czejcmxr.d.cts → codec-BYCDWgED.d.ts} +22 -3
- package/dist/{codec-DaXjRrOV.d.ts → codec-Bwqq7ZQT.d.ts} +22 -3
- package/dist/{codec-CFWu5KVT.d.cts → codec-BzWxOFby.d.cts} +22 -3
- package/dist/codec-C-nJhNNl.d.ts +38 -0
- package/dist/{codec-EvybrBuY.d.cts → codec-C11VEPbQ.d.cts} +21 -2
- package/dist/codec-C9U0Vzy9.d.cts +68 -0
- package/dist/{codec-Cm3D261p.d.ts → codec-CCx22jnd.d.ts} +21 -2
- package/dist/{codec-CwZ6OCPP.d.ts → codec-CP3zkfTv.d.ts} +22 -3
- package/dist/{codec-BxQTybUX.d.cts → codec-CRmOLDpt.d.ts} +22 -3
- package/dist/{codec-DzkdW4kO.d.cts → codec-CUu56DDU.d.cts} +21 -2
- package/dist/codec-Cb8mUre3.d.ts +68 -0
- package/dist/{codec-f7vxeVIS.d.cts → codec-CemqAQdR.d.cts} +22 -3
- package/dist/{codec-gl4_QEva.d.ts → codec-CxMvsVMS.d.ts} +21 -2
- package/dist/{codec-Bd60SGKH.d.cts → codec-DIgMVTi4.d.cts} +21 -2
- package/dist/{codec--CVeqGQv.d.ts → codec-DYzozF68.d.ts} +21 -2
- package/dist/{codec-CWnf8mn_.d.cts → codec-D_O9zxax.d.ts} +22 -3
- package/dist/{codec-08ZOr5wI.d.ts → codec-Ddc-QxV6.d.cts} +22 -3
- package/dist/{codec-CBdOIfMY.d.ts → codec-DoojMl2z.d.cts} +22 -3
- package/dist/{codec-BrTi4K7r.d.cts → codec-DqdjiOQF.d.ts} +22 -3
- package/dist/{codec-CXCjya_G.d.cts → codec-Dstemwrq.d.cts} +21 -2
- package/dist/{codec-Dl_QIXMz.d.ts → codec-Dt6nuejp.d.ts} +21 -2
- package/dist/{codec-Bux_Q40X.d.ts → codec-DuYhd8fP.d.cts} +22 -3
- package/dist/{codec-Cfo_z5ET.d.cts → codec-DwNOFgPU.d.cts} +21 -2
- package/dist/{codec-guzqtfMk.d.cts → codec-l01BpNhF.d.cts} +21 -2
- package/dist/{codec-C3mdsGx3.d.ts → codec-psN2vB6I.d.cts} +22 -3
- package/dist/draft07-session.d.cts +3 -3
- package/dist/draft07-session.d.ts +3 -3
- package/dist/draft07.cjs +48 -4
- package/dist/draft07.d.cts +44 -4
- package/dist/draft07.d.ts +44 -4
- package/dist/draft07.js +49 -5
- package/dist/draft08-session.d.cts +3 -3
- package/dist/draft08-session.d.ts +3 -3
- package/dist/draft08.cjs +76 -3
- package/dist/draft08.d.cts +73 -5
- package/dist/draft08.d.ts +73 -5
- package/dist/draft08.js +77 -4
- package/dist/draft09-session.d.cts +3 -3
- package/dist/draft09-session.d.ts +3 -3
- package/dist/draft09.cjs +76 -3
- package/dist/draft09.d.cts +73 -5
- package/dist/draft09.d.ts +73 -5
- package/dist/draft09.js +77 -4
- package/dist/draft10-session.d.cts +3 -3
- package/dist/draft10-session.d.ts +3 -3
- package/dist/draft10.cjs +76 -3
- package/dist/draft10.d.cts +73 -5
- package/dist/draft10.d.ts +73 -5
- package/dist/draft10.js +77 -4
- package/dist/draft11-session.d.cts +3 -3
- package/dist/draft11-session.d.ts +3 -3
- package/dist/draft11.cjs +104 -3
- package/dist/draft11.d.cts +101 -5
- package/dist/draft11.d.ts +101 -5
- package/dist/draft11.js +105 -4
- package/dist/draft12-session.d.cts +3 -3
- package/dist/draft12-session.d.ts +3 -3
- package/dist/draft12.cjs +113 -3
- package/dist/draft12.d.cts +110 -5
- package/dist/draft12.d.ts +110 -5
- package/dist/draft12.js +114 -4
- package/dist/draft13-session.d.cts +3 -3
- package/dist/draft13-session.d.ts +3 -3
- package/dist/draft13.cjs +105 -3
- package/dist/draft13.d.cts +102 -5
- package/dist/draft13.d.ts +102 -5
- package/dist/draft13.js +106 -4
- package/dist/draft14-session.d.cts +3 -3
- package/dist/draft14-session.d.ts +3 -3
- package/dist/draft14.cjs +107 -3
- package/dist/draft14.d.cts +104 -31
- package/dist/draft14.d.ts +104 -31
- package/dist/draft14.js +108 -4
- package/dist/draft15-session.d.cts +4 -4
- package/dist/draft15-session.d.ts +4 -4
- package/dist/draft15.cjs +69 -3
- package/dist/draft15.d.cts +68 -25
- package/dist/draft15.d.ts +68 -25
- package/dist/draft15.js +70 -4
- package/dist/draft16-session.cjs +2 -2
- package/dist/draft16-session.d.cts +4 -4
- package/dist/draft16-session.d.ts +4 -4
- package/dist/draft16-session.js +1 -1
- package/dist/draft16.cjs +76 -8
- package/dist/draft16.d.cts +70 -16
- package/dist/draft16.d.ts +70 -16
- package/dist/draft16.js +73 -5
- package/dist/draft17-session.d.cts +4 -4
- package/dist/draft17-session.d.ts +4 -4
- package/dist/draft17.cjs +77 -3
- package/dist/draft17.d.cts +75 -6
- package/dist/draft17.d.ts +75 -6
- package/dist/draft17.js +78 -4
- package/dist/draft18-session.d.cts +4 -4
- package/dist/draft18-session.d.ts +4 -4
- package/dist/draft18.cjs +8 -3
- package/dist/draft18.d.cts +6 -5
- package/dist/draft18.d.ts +6 -5
- package/dist/draft18.js +9 -4
- package/dist/draft19-session.d.cts +4 -4
- package/dist/draft19-session.d.ts +4 -4
- package/dist/draft19.cjs +11 -4
- package/dist/draft19.d.cts +6 -5
- package/dist/draft19.d.ts +6 -5
- package/dist/draft19.js +12 -5
- package/dist/draft20-session.d.cts +4 -4
- package/dist/draft20-session.d.ts +4 -4
- package/dist/draft20.cjs +8 -3
- package/dist/draft20.d.cts +6 -5
- package/dist/draft20.d.ts +6 -5
- package/dist/draft20.js +9 -4
- package/dist/draft21-session.cjs +8 -0
- package/dist/draft21-session.d.cts +195 -0
- package/dist/draft21-session.d.ts +195 -0
- package/dist/draft21-session.js +8 -0
- package/dist/draft21.cjs +222 -0
- package/dist/draft21.d.cts +176 -0
- package/dist/draft21.d.ts +176 -0
- package/dist/draft21.js +222 -0
- package/dist/index.cjs +37 -31
- package/dist/index.d.cts +29 -23
- package/dist/index.d.ts +29 -23
- package/dist/index.js +22 -16
- package/dist/{session-types-Dn7b3RZM.d.ts → session-types-Cxx7W8zZ.d.ts} +1 -1
- package/dist/{session-types-B9idsih-.d.cts → session-types-DZkI_qFG.d.cts} +1 -1
- package/dist/session.cjs +7 -3
- package/dist/session.d.cts +11 -9
- package/dist/session.d.ts +11 -9
- package/dist/session.js +6 -2
- package/dist/{types-DG5_iKuv.d.cts → types-2NisMA8_.d.cts} +1 -1
- package/dist/{types-DG5_iKuv.d.ts → types-2NisMA8_.d.ts} +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-DDwidj2d.d.cts +371 -0
- package/dist/types-DDwidj2d.d.ts +371 -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 +15 -3
- package/src/core/auth-redaction.ts +190 -0
- package/src/core/types.ts +1 -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/src/drafts/draft21/codec.ts +1816 -0
- package/src/drafts/draft21/data-streams.ts +1338 -0
- package/src/drafts/draft21/error-codes.ts +135 -0
- package/src/drafts/draft21/index.ts +168 -0
- package/src/drafts/draft21/messages.ts +68 -0
- package/src/drafts/draft21/rules.ts +107 -0
- package/src/drafts/draft21/session-fsm.ts +1063 -0
- package/src/drafts/draft21/session.ts +21 -0
- package/src/drafts/draft21/types.ts +473 -0
- package/src/index.ts +9 -1
- package/src/session.ts +4 -0
- package/dist/codec-BJ7BHuiZ.d.ts +0 -18
- package/dist/codec-C6Mx4bwz.d.cts +0 -18
|
@@ -248,107 +248,165 @@ export function encodeFetchStream(stream: FetchStream): Uint8Array {
|
|
|
248
248
|
return w.finish()
|
|
249
249
|
}
|
|
250
250
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
251
|
+
/**
|
|
252
|
+
* The SUBGROUP_HEADER fields, read once for both decoders.
|
|
253
|
+
*
|
|
254
|
+
* `decodeSubgroupStream` and `createSubgroupStreamDecoder` used to parse this
|
|
255
|
+
* header separately and they drifted: the incremental one dropped the header
|
|
256
|
+
* flags, reported no Type Flags, and left the Subgroup ID at zero under the
|
|
257
|
+
* mode that derives it from the first Object. One reader means there is
|
|
258
|
+
* nothing left to keep in sync.
|
|
259
|
+
*/
|
|
260
|
+
interface SubgroupHeaderFields {
|
|
261
|
+
readonly streamType: number
|
|
262
|
+
readonly propertiesPresent: boolean
|
|
263
|
+
readonly subgroupIsFirstObjId: boolean
|
|
264
|
+
readonly endOfGroup: boolean
|
|
265
|
+
readonly firstObjectFlag: boolean
|
|
266
|
+
readonly trackAlias: bigint
|
|
267
|
+
readonly groupId: bigint
|
|
268
|
+
/** Zero under `subgroupIsFirstObjId` until the first Object has been read. */
|
|
269
|
+
readonly subgroupId: bigint
|
|
270
|
+
readonly publisherPriority: number
|
|
271
|
+
}
|
|
255
272
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
}
|
|
273
|
+
function readSubgroupHeader(r: BufferReader): SubgroupHeaderFields {
|
|
274
|
+
const streamType = r.readUint8()
|
|
275
|
+
if (!isValidSubgroupType(streamType)) {
|
|
276
|
+
throw new DecodeError(
|
|
277
|
+
'CONSTRAINT_VIOLATION',
|
|
278
|
+
`Invalid subgroup stream type 0x${streamType.toString(16)}`,
|
|
279
|
+
0,
|
|
280
|
+
)
|
|
281
|
+
}
|
|
266
282
|
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
283
|
+
const propertiesPresent = (streamType & 0x01) !== 0
|
|
284
|
+
const subgroupMode = (streamType & 0x06) >> 1
|
|
285
|
+
const hasSubgroupField = subgroupMode === 0x02
|
|
286
|
+
const subgroupIsFirstObjId = subgroupMode === 0x01
|
|
287
|
+
const endOfGroup = (streamType & 0x08) !== 0
|
|
288
|
+
const hasPriority = (streamType & 0x20) === 0
|
|
289
|
+
const firstObjectFlag = (streamType & 0x40) !== 0
|
|
274
290
|
|
|
275
|
-
|
|
276
|
-
|
|
291
|
+
const trackAlias = r.readVarInt()
|
|
292
|
+
const groupId = r.readVarInt()
|
|
277
293
|
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
294
|
+
let subgroupId = 0n
|
|
295
|
+
if (hasSubgroupField) {
|
|
296
|
+
subgroupId = r.readVarInt()
|
|
297
|
+
}
|
|
282
298
|
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
299
|
+
let publisherPriority = 128
|
|
300
|
+
if (hasPriority) {
|
|
301
|
+
publisherPriority = r.readUint8()
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
return {
|
|
305
|
+
streamType,
|
|
306
|
+
propertiesPresent,
|
|
307
|
+
subgroupIsFirstObjId,
|
|
308
|
+
endOfGroup,
|
|
309
|
+
firstObjectFlag,
|
|
310
|
+
trackAlias,
|
|
311
|
+
groupId,
|
|
312
|
+
subgroupId,
|
|
313
|
+
publisherPriority,
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
/**
|
|
318
|
+
* One Object off a subgroup stream, for both decoders.
|
|
319
|
+
*
|
|
320
|
+
* `base` is the absolute offset within the stream that `r.offset === 0`
|
|
321
|
+
* corresponds to. The one-shot decoder reads from a reader spanning the whole
|
|
322
|
+
* stream and passes 0; the incremental decoder reads from a window over its
|
|
323
|
+
* own buffer and passes that window's position. That is what makes
|
|
324
|
+
* `byteOffset` mean the same thing on both paths, instead of being hardcoded
|
|
325
|
+
* to zero on one of them.
|
|
326
|
+
*
|
|
327
|
+
* Throws `UNEXPECTED_END` when the Object is not yet complete, which the
|
|
328
|
+
* incremental decoder reads as "wait for more bytes" rather than as an error.
|
|
329
|
+
*/
|
|
330
|
+
function readSubgroupObject(
|
|
331
|
+
r: BufferReader,
|
|
332
|
+
propertiesPresent: boolean,
|
|
333
|
+
isFirst: boolean,
|
|
334
|
+
prevObjectId: bigint,
|
|
335
|
+
base: number,
|
|
336
|
+
): ObjectPayload {
|
|
337
|
+
const byteOffset = base + r.offset
|
|
338
|
+
const delta = r.readVarInt()
|
|
339
|
+
const objectId = isFirst ? delta : prevObjectId + 1n + delta
|
|
340
|
+
|
|
341
|
+
const extensionData = new Uint8Array(0)
|
|
342
|
+
let objectProperties: Record<string, bigint> | undefined
|
|
343
|
+
if (propertiesPresent) {
|
|
344
|
+
const propsLen = Number(r.readVarInt())
|
|
345
|
+
if (propsLen > 0) {
|
|
346
|
+
objectProperties = decodeObjectProperties(r, propsLen)
|
|
286
347
|
}
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
const payloadLength = Number(r.readVarInt())
|
|
351
|
+
let payload: Uint8Array
|
|
352
|
+
let status: bigint | undefined
|
|
353
|
+
let payloadByteOffset: number
|
|
354
|
+
if (payloadLength === 0) {
|
|
355
|
+
// The Object Status field is sent only when the Payload Length is zero.
|
|
356
|
+
// Skipping it leaves the varint to be read as the next Object's Object ID
|
|
357
|
+
// Delta, which desynchronises the rest of the stream silently.
|
|
358
|
+
status = r.readVarInt()
|
|
359
|
+
payloadByteOffset = base + r.offset
|
|
360
|
+
payload = new Uint8Array(0)
|
|
361
|
+
} else {
|
|
362
|
+
payloadByteOffset = base + r.offset
|
|
363
|
+
payload = r.readBytesView(payloadLength)
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
const obj: ObjectPayload = {
|
|
367
|
+
type: 'object',
|
|
368
|
+
byteOffset,
|
|
369
|
+
payloadByteOffset,
|
|
370
|
+
objectId,
|
|
371
|
+
payloadLength,
|
|
372
|
+
payload,
|
|
373
|
+
extensionData,
|
|
374
|
+
}
|
|
375
|
+
if (status !== undefined) (obj as unknown as Record<string, unknown>).status = status
|
|
376
|
+
if (objectProperties !== undefined)
|
|
377
|
+
(obj as unknown as Record<string, unknown>).objectProperties = objectProperties
|
|
378
|
+
return obj
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
export function decodeSubgroupStream(bytes: Uint8Array): DecodeResult<SubgroupStream> {
|
|
382
|
+
try {
|
|
383
|
+
const r = new BufferReader(bytes)
|
|
384
|
+
const h = readSubgroupHeader(r)
|
|
287
385
|
|
|
288
386
|
const objects: ObjectPayload[] = []
|
|
289
387
|
let prevObjectId = -1n
|
|
290
388
|
let isFirst = true
|
|
389
|
+
let subgroupId = h.subgroupId
|
|
291
390
|
|
|
292
391
|
while (r.remaining > 0) {
|
|
293
|
-
const
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
if (isFirst) {
|
|
297
|
-
objectId = delta
|
|
298
|
-
if (subgroupIsFirstObjId) {
|
|
299
|
-
subgroupId = objectId
|
|
300
|
-
}
|
|
301
|
-
isFirst = false
|
|
302
|
-
} else {
|
|
303
|
-
objectId = prevObjectId + 1n + delta
|
|
304
|
-
}
|
|
305
|
-
const extensionData = new Uint8Array(0)
|
|
306
|
-
let objectProperties: Record<string, bigint> | undefined
|
|
307
|
-
if (propertiesPresent) {
|
|
308
|
-
const propsLen = Number(r.readVarInt())
|
|
309
|
-
if (propsLen > 0) {
|
|
310
|
-
objectProperties = decodeObjectProperties(r, propsLen)
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
const payloadLength = Number(r.readVarInt())
|
|
314
|
-
let payload: Uint8Array
|
|
315
|
-
let status: bigint | undefined
|
|
316
|
-
let payloadByteOffset: number
|
|
317
|
-
if (payloadLength === 0) {
|
|
318
|
-
status = r.readVarInt()
|
|
319
|
-
payloadByteOffset = r.offset
|
|
320
|
-
payload = new Uint8Array(0)
|
|
321
|
-
} else {
|
|
322
|
-
payloadByteOffset = r.offset
|
|
323
|
-
payload = r.readBytesView(payloadLength)
|
|
324
|
-
}
|
|
325
|
-
const obj: ObjectPayload = {
|
|
326
|
-
type: 'object',
|
|
327
|
-
byteOffset,
|
|
328
|
-
payloadByteOffset,
|
|
329
|
-
objectId,
|
|
330
|
-
payloadLength,
|
|
331
|
-
payload,
|
|
332
|
-
extensionData,
|
|
333
|
-
}
|
|
334
|
-
if (status !== undefined) (obj as unknown as Record<string, unknown>).status = status
|
|
335
|
-
if (objectProperties !== undefined)
|
|
336
|
-
(obj as unknown as Record<string, unknown>).objectProperties = objectProperties
|
|
392
|
+
const obj = readSubgroupObject(r, h.propertiesPresent, isFirst, prevObjectId, 0)
|
|
393
|
+
if (isFirst && h.subgroupIsFirstObjId) subgroupId = obj.objectId
|
|
394
|
+
isFirst = false
|
|
337
395
|
objects.push(obj)
|
|
338
|
-
prevObjectId = objectId
|
|
396
|
+
prevObjectId = obj.objectId
|
|
339
397
|
}
|
|
340
398
|
|
|
341
399
|
const result: SubgroupStream = {
|
|
342
400
|
type: 'subgroup',
|
|
343
|
-
headerType: streamType,
|
|
344
|
-
trackAlias,
|
|
345
|
-
groupId,
|
|
401
|
+
headerType: h.streamType,
|
|
402
|
+
trackAlias: h.trackAlias,
|
|
403
|
+
groupId: h.groupId,
|
|
346
404
|
subgroupId,
|
|
347
|
-
publisherPriority,
|
|
405
|
+
publisherPriority: h.publisherPriority,
|
|
348
406
|
objects,
|
|
407
|
+
...(h.endOfGroup ? { endOfGroup: true } : {}),
|
|
408
|
+
...(h.firstObjectFlag ? { firstObject: true } : {}),
|
|
349
409
|
}
|
|
350
|
-
if (endOfGroup) (result as unknown as Record<string, unknown>).endOfGroup = true
|
|
351
|
-
if (firstObject) (result as unknown as Record<string, unknown>).firstObject = true
|
|
352
410
|
|
|
353
411
|
return {
|
|
354
412
|
ok: true,
|
|
@@ -426,213 +484,176 @@ export function decodeDatagram(bytes: Uint8Array): DecodeResult<DatagramObject>
|
|
|
426
484
|
}
|
|
427
485
|
}
|
|
428
486
|
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
'CONSTRAINT_VIOLATION',
|
|
438
|
-
`Expected fetch stream type 0x05, got 0x${streamType.toString(16)}`,
|
|
439
|
-
0,
|
|
440
|
-
),
|
|
441
|
-
}
|
|
442
|
-
}
|
|
443
|
-
const requestId = r.readVarInt()
|
|
444
|
-
const objects: FetchObjectPayload[] = []
|
|
487
|
+
/** The delta state a fetch stream carries from one Object to the next. */
|
|
488
|
+
interface FetchObjectState {
|
|
489
|
+
prevGroupId: bigint
|
|
490
|
+
prevSubgroupId: bigint
|
|
491
|
+
prevObjectId: bigint
|
|
492
|
+
prevPriority: number
|
|
493
|
+
first: boolean
|
|
494
|
+
}
|
|
445
495
|
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
let prevPriority = 128
|
|
450
|
-
let first = true
|
|
496
|
+
function newFetchObjectState(): FetchObjectState {
|
|
497
|
+
return { prevGroupId: 0n, prevSubgroupId: 0n, prevObjectId: 0n, prevPriority: 128, first: true }
|
|
498
|
+
}
|
|
451
499
|
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
const groupIdPresent = (flags & 0x08) !== 0
|
|
536
|
-
const priorityPresent = (flags & 0x10) !== 0
|
|
537
|
-
const propsPresent = (flags & 0x20) !== 0
|
|
538
|
-
|
|
539
|
-
if (groupIdPresent) {
|
|
540
|
-
const groupDelta = r.readVarInt()
|
|
541
|
-
groupId = first ? groupDelta : prevGroupId + groupDelta + 1n
|
|
542
|
-
} else if (first) {
|
|
543
|
-
return {
|
|
544
|
-
ok: false,
|
|
545
|
-
error: new DecodeError(
|
|
546
|
-
'CONSTRAINT_VIOLATION',
|
|
547
|
-
'First fetch object must include groupId',
|
|
548
|
-
r.offset,
|
|
549
|
-
),
|
|
550
|
-
}
|
|
551
|
-
}
|
|
500
|
+
/**
|
|
501
|
+
* One Object off a fetch stream, for both decoders.
|
|
502
|
+
*
|
|
503
|
+
* Lifted out of `decodeFetchStream` unchanged so the incremental decoder
|
|
504
|
+
* cannot report a different shape for the same bytes. It used to return a
|
|
505
|
+
* bare ObjectPayload -- no Serialization Flags, no Group or Subgroup ID, no
|
|
506
|
+
* Priority, no deltas -- with every `byteOffset` zero, and in DATAGRAM mode
|
|
507
|
+
* it resolved the Object ID against state it never carried.
|
|
508
|
+
*
|
|
509
|
+
* `base` is the absolute offset that `r.offset === 0` corresponds to: 0 for
|
|
510
|
+
* the one-shot decoder, the buffer window's position for the incremental one.
|
|
511
|
+
*/
|
|
512
|
+
function readFetchObject(r: BufferReader, base: number, st: FetchObjectState): FetchObjectPayload {
|
|
513
|
+
const byteOffset = base + r.offset
|
|
514
|
+
const flags = Number(r.readVarInt())
|
|
515
|
+
|
|
516
|
+
let groupId = st.prevGroupId
|
|
517
|
+
let subgroupId = st.prevSubgroupId
|
|
518
|
+
let objectId = st.prevObjectId + 1n
|
|
519
|
+
let payloadLength: number
|
|
520
|
+
let payload: Uint8Array
|
|
521
|
+
let payloadByteOffset: number
|
|
522
|
+
const extensionData = new Uint8Array(0)
|
|
523
|
+
|
|
524
|
+
if (flags >= 0x80) {
|
|
525
|
+
// End of Range: 0x8C = End of Non-Existent Range, 0x10C = End of Unknown Range
|
|
526
|
+
if (flags !== 0x8c && flags !== 0x10c) {
|
|
527
|
+
throw new DecodeError(
|
|
528
|
+
'CONSTRAINT_VIOLATION',
|
|
529
|
+
`Unknown serialization flags value: 0x${flags.toString(16)}`,
|
|
530
|
+
r.offset,
|
|
531
|
+
)
|
|
532
|
+
}
|
|
533
|
+
groupId = r.readVarInt()
|
|
534
|
+
objectId = r.readVarInt()
|
|
535
|
+
payloadLength = Number(r.readVarInt())
|
|
536
|
+
payloadByteOffset = base + r.offset
|
|
537
|
+
payload = payloadLength > 0 ? r.readBytesView(payloadLength) : new Uint8Array(0)
|
|
538
|
+
} else if (flags & 0x40) {
|
|
539
|
+
// DATAGRAM mode: no subgroup_id field
|
|
540
|
+
const objectIdPresent = (flags & 0x04) !== 0
|
|
541
|
+
const groupIdPresent = (flags & 0x08) !== 0
|
|
542
|
+
const priorityPresent = (flags & 0x10) !== 0
|
|
543
|
+
const propsPresent = (flags & 0x20) !== 0
|
|
544
|
+
|
|
545
|
+
if (groupIdPresent) {
|
|
546
|
+
// First object's delta IS the absolute group id;
|
|
547
|
+
// subsequent objects: groupId = st.prevGroupId + delta + 1 (ascending)
|
|
548
|
+
const groupDelta = r.readVarInt()
|
|
549
|
+
groupId = st.first ? groupDelta : st.prevGroupId + groupDelta + 1n
|
|
550
|
+
}
|
|
551
|
+
if (objectIdPresent) {
|
|
552
|
+
objectId = r.readVarInt()
|
|
553
|
+
}
|
|
554
|
+
if (priorityPresent) {
|
|
555
|
+
st.prevPriority = r.readUint8()
|
|
556
|
+
}
|
|
557
|
+
let objectProperties: Record<string, bigint> | undefined
|
|
558
|
+
if (propsPresent) {
|
|
559
|
+
const propsLen = Number(r.readVarInt())
|
|
560
|
+
if (propsLen > 0) {
|
|
561
|
+
objectProperties = decodeObjectProperties(r, propsLen)
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
payloadLength = Number(r.readVarInt())
|
|
565
|
+
payloadByteOffset = base + r.offset
|
|
566
|
+
payload = payloadLength > 0 ? r.readBytesView(payloadLength) : new Uint8Array(0)
|
|
567
|
+
|
|
568
|
+
const obj: FetchObjectPayload = {
|
|
569
|
+
type: 'object',
|
|
570
|
+
byteOffset,
|
|
571
|
+
payloadByteOffset,
|
|
572
|
+
serializationFlags: flags,
|
|
573
|
+
groupId,
|
|
574
|
+
subgroupId: 0n,
|
|
575
|
+
objectId,
|
|
576
|
+
publisherPriority: st.prevPriority,
|
|
577
|
+
payloadLength,
|
|
578
|
+
payload,
|
|
579
|
+
extensionData,
|
|
580
|
+
}
|
|
581
|
+
if (objectProperties)
|
|
582
|
+
(obj as unknown as Record<string, unknown>).objectProperties = objectProperties
|
|
552
583
|
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
r.offset,
|
|
575
|
-
),
|
|
576
|
-
}
|
|
577
|
-
}
|
|
578
|
-
subgroupId = prevSubgroupId + 1n
|
|
579
|
-
} else if (subgroupEncoding === 0x03) {
|
|
580
|
-
subgroupId = r.readVarInt()
|
|
581
|
-
}
|
|
584
|
+
st.prevGroupId = groupId
|
|
585
|
+
st.prevObjectId = objectId
|
|
586
|
+
st.first = false
|
|
587
|
+
return obj
|
|
588
|
+
} else {
|
|
589
|
+
const subgroupEncoding = flags & 0x03
|
|
590
|
+
const objectIdPresent = (flags & 0x04) !== 0
|
|
591
|
+
const groupIdPresent = (flags & 0x08) !== 0
|
|
592
|
+
const priorityPresent = (flags & 0x10) !== 0
|
|
593
|
+
const propsPresent = (flags & 0x20) !== 0
|
|
594
|
+
|
|
595
|
+
if (groupIdPresent) {
|
|
596
|
+
const groupDelta = r.readVarInt()
|
|
597
|
+
groupId = st.first ? groupDelta : st.prevGroupId + groupDelta + 1n
|
|
598
|
+
} else if (st.first) {
|
|
599
|
+
throw new DecodeError(
|
|
600
|
+
'CONSTRAINT_VIOLATION',
|
|
601
|
+
'First fetch object must include groupId',
|
|
602
|
+
r.offset,
|
|
603
|
+
)
|
|
604
|
+
}
|
|
582
605
|
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
606
|
+
if (subgroupEncoding === 0x00) {
|
|
607
|
+
subgroupId = 0n
|
|
608
|
+
} else if (subgroupEncoding === 0x01) {
|
|
609
|
+
if (st.first) {
|
|
610
|
+
throw new DecodeError(
|
|
611
|
+
'CONSTRAINT_VIOLATION',
|
|
612
|
+
'First fetch object cannot reference prior subgroupId',
|
|
613
|
+
r.offset,
|
|
614
|
+
)
|
|
615
|
+
}
|
|
616
|
+
subgroupId = st.prevSubgroupId
|
|
617
|
+
} else if (subgroupEncoding === 0x02) {
|
|
618
|
+
if (st.first) {
|
|
619
|
+
throw new DecodeError(
|
|
620
|
+
'CONSTRAINT_VIOLATION',
|
|
621
|
+
'First fetch object cannot reference prior subgroupId',
|
|
622
|
+
r.offset,
|
|
623
|
+
)
|
|
624
|
+
}
|
|
625
|
+
subgroupId = st.prevSubgroupId + 1n
|
|
626
|
+
} else if (subgroupEncoding === 0x03) {
|
|
627
|
+
subgroupId = r.readVarInt()
|
|
628
|
+
}
|
|
595
629
|
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
630
|
+
if (objectIdPresent) {
|
|
631
|
+
objectId = r.readVarInt()
|
|
632
|
+
} else if (st.first) {
|
|
633
|
+
throw new DecodeError(
|
|
634
|
+
'CONSTRAINT_VIOLATION',
|
|
635
|
+
'First fetch object must include objectId',
|
|
636
|
+
r.offset,
|
|
637
|
+
)
|
|
638
|
+
}
|
|
599
639
|
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
if (propsLen > 0) {
|
|
604
|
-
objectProperties = decodeObjectProperties(r, propsLen)
|
|
605
|
-
}
|
|
606
|
-
}
|
|
640
|
+
if (priorityPresent) {
|
|
641
|
+
st.prevPriority = r.readUint8()
|
|
642
|
+
}
|
|
607
643
|
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
const obj: FetchObjectPayload = {
|
|
614
|
-
type: 'object',
|
|
615
|
-
byteOffset,
|
|
616
|
-
payloadByteOffset,
|
|
617
|
-
serializationFlags: flags,
|
|
618
|
-
groupId,
|
|
619
|
-
subgroupId,
|
|
620
|
-
objectId,
|
|
621
|
-
publisherPriority: prevPriority,
|
|
622
|
-
payloadLength,
|
|
623
|
-
payload,
|
|
624
|
-
extensionData,
|
|
625
|
-
}
|
|
626
|
-
;(obj as unknown as Record<string, unknown>).objectProperties = objectProperties
|
|
627
|
-
objects.push(obj)
|
|
628
|
-
prevGroupId = groupId
|
|
629
|
-
prevSubgroupId = subgroupId
|
|
630
|
-
prevObjectId = objectId
|
|
631
|
-
first = false
|
|
632
|
-
continue
|
|
633
|
-
}
|
|
644
|
+
let objectProperties: Record<string, bigint> | undefined
|
|
645
|
+
if (propsPresent) {
|
|
646
|
+
const propsLen = Number(r.readVarInt())
|
|
647
|
+
if (propsLen > 0) {
|
|
648
|
+
objectProperties = decodeObjectProperties(r, propsLen)
|
|
634
649
|
}
|
|
650
|
+
}
|
|
635
651
|
|
|
652
|
+
payloadLength = Number(r.readVarInt())
|
|
653
|
+
payloadByteOffset = base + r.offset
|
|
654
|
+
payload = payloadLength > 0 ? r.readBytesView(payloadLength) : new Uint8Array(0)
|
|
655
|
+
|
|
656
|
+
if (objectProperties) {
|
|
636
657
|
const obj: FetchObjectPayload = {
|
|
637
658
|
type: 'object',
|
|
638
659
|
byteOffset,
|
|
@@ -641,17 +662,63 @@ export function decodeFetchStream(bytes: Uint8Array): DecodeResult<FetchStream>
|
|
|
641
662
|
groupId,
|
|
642
663
|
subgroupId,
|
|
643
664
|
objectId,
|
|
644
|
-
publisherPriority: prevPriority,
|
|
665
|
+
publisherPriority: st.prevPriority,
|
|
645
666
|
payloadLength,
|
|
646
667
|
payload,
|
|
647
668
|
extensionData,
|
|
648
669
|
}
|
|
649
|
-
|
|
670
|
+
;(obj as unknown as Record<string, unknown>).objectProperties = objectProperties
|
|
671
|
+
st.prevGroupId = groupId
|
|
672
|
+
st.prevSubgroupId = subgroupId
|
|
673
|
+
st.prevObjectId = objectId
|
|
674
|
+
st.first = false
|
|
675
|
+
return obj
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
const obj: FetchObjectPayload = {
|
|
680
|
+
type: 'object',
|
|
681
|
+
byteOffset,
|
|
682
|
+
payloadByteOffset,
|
|
683
|
+
serializationFlags: flags,
|
|
684
|
+
groupId,
|
|
685
|
+
subgroupId,
|
|
686
|
+
objectId,
|
|
687
|
+
publisherPriority: st.prevPriority,
|
|
688
|
+
payloadLength,
|
|
689
|
+
payload,
|
|
690
|
+
extensionData,
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
st.prevGroupId = groupId
|
|
694
|
+
st.prevSubgroupId = subgroupId
|
|
695
|
+
st.prevObjectId = objectId
|
|
696
|
+
st.first = false
|
|
697
|
+
|
|
698
|
+
return obj
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
export function decodeFetchStream(bytes: Uint8Array): DecodeResult<FetchStream> {
|
|
702
|
+
try {
|
|
703
|
+
const r = new BufferReader(bytes)
|
|
704
|
+
const streamType = r.readVarInt()
|
|
705
|
+
if (streamType !== FETCH_STREAM_TYPE) {
|
|
706
|
+
return {
|
|
707
|
+
ok: false,
|
|
708
|
+
error: new DecodeError(
|
|
709
|
+
'CONSTRAINT_VIOLATION',
|
|
710
|
+
`Expected fetch stream type 0x05, got 0x${streamType.toString(16)}`,
|
|
711
|
+
0,
|
|
712
|
+
),
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
const requestId = r.readVarInt()
|
|
716
|
+
const objects: FetchObjectPayload[] = []
|
|
650
717
|
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
718
|
+
const st = newFetchObjectState()
|
|
719
|
+
|
|
720
|
+
while (r.remaining > 0) {
|
|
721
|
+
objects.push(readFetchObject(r, 0, st))
|
|
655
722
|
}
|
|
656
723
|
|
|
657
724
|
return {
|
|
@@ -685,71 +752,108 @@ export function decodeDataStream(
|
|
|
685
752
|
|
|
686
753
|
// ─── Data Stream Decoders ──────────────────────────────────────────────────────
|
|
687
754
|
|
|
755
|
+
/**
|
|
756
|
+
* A data stream's bytes, accumulated across chunks.
|
|
757
|
+
*
|
|
758
|
+
* The decoders below used to allocate an array of `unread + chunk.length` and
|
|
759
|
+
* copy both halves into it on *every* chunk. Capacity now grows geometrically,
|
|
760
|
+
* so most chunks are a single `set` into spare room.
|
|
761
|
+
*
|
|
762
|
+
* **It never compacts in place.** Object payloads are handed out as views into
|
|
763
|
+
* this buffer (`readBytesView`), so moving bytes within it would corrupt an
|
|
764
|
+
* object that has already been emitted. The consumed prefix is dropped only
|
|
765
|
+
* when a fresh array is being allocated anyway, which leaves the old array
|
|
766
|
+
* alive for exactly as long as the views into it are.
|
|
767
|
+
*/
|
|
768
|
+
class StreamBuffer {
|
|
769
|
+
private buf = new Uint8Array(0)
|
|
770
|
+
/** Bytes written into `buf`. */
|
|
771
|
+
private len = 0
|
|
772
|
+
/** Consumed prefix of `buf`; `base + offset` is the position in the stream. */
|
|
773
|
+
offset = 0
|
|
774
|
+
/** Absolute position of `buf[0]` within the stream. */
|
|
775
|
+
base = 0
|
|
776
|
+
|
|
777
|
+
get unread(): number {
|
|
778
|
+
return this.len - this.offset
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
append(chunk: Uint8Array): void {
|
|
782
|
+
if (this.len + chunk.length > this.buf.length) {
|
|
783
|
+
const live = this.len - this.offset
|
|
784
|
+
const needed = live + chunk.length
|
|
785
|
+
// Grow until reclaiming the consumed prefix leaves the buffer at least
|
|
786
|
+
// half free. Sizing to `needed` -- which is what this did first -- leaves
|
|
787
|
+
// no room at all, so the next chunk reallocates too and the buffer
|
|
788
|
+
// reallocates on every single chunk, which is the cost it exists to
|
|
789
|
+
// avoid. Capacity never shrinks, so it settles at roughly twice the
|
|
790
|
+
// largest `live + chunk` this stream has seen.
|
|
791
|
+
let cap = Math.max(4096, this.buf.length)
|
|
792
|
+
while (cap < needed * 2) cap *= 2
|
|
793
|
+
// A fresh array every time, including when the capacity is unchanged:
|
|
794
|
+
// the old one is still pinned by the payload views handed out of it, so
|
|
795
|
+
// it can be neither compacted nor reused.
|
|
796
|
+
const next = new Uint8Array(cap)
|
|
797
|
+
next.set(this.buf.subarray(this.offset, this.len), 0)
|
|
798
|
+
this.buf = next
|
|
799
|
+
this.base += this.offset
|
|
800
|
+
this.len = live
|
|
801
|
+
this.offset = 0
|
|
802
|
+
}
|
|
803
|
+
this.buf.set(chunk, this.len)
|
|
804
|
+
this.len += chunk.length
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
/**
|
|
808
|
+
* The written bytes, for a reader positioned at `offset`. Bounded by `len`
|
|
809
|
+
* rather than by capacity, so `BufferReader.remaining` counts real bytes and
|
|
810
|
+
* not the spare room after them.
|
|
811
|
+
*/
|
|
812
|
+
written(): Uint8Array {
|
|
813
|
+
return this.buf.subarray(0, this.len)
|
|
814
|
+
}
|
|
815
|
+
}
|
|
816
|
+
|
|
688
817
|
export function createSubgroupStreamDecoder(): TransformStream<
|
|
689
818
|
Uint8Array,
|
|
690
819
|
SubgroupStreamHeader | ObjectPayload
|
|
691
820
|
> {
|
|
692
|
-
|
|
693
|
-
let
|
|
821
|
+
const b = new StreamBuffer()
|
|
822
|
+
let header: SubgroupHeaderFields | null = null
|
|
694
823
|
let headerEmitted = false
|
|
695
824
|
let prevObjectId = -1n
|
|
696
|
-
let
|
|
697
|
-
|
|
825
|
+
let isFirst = true
|
|
826
|
+
|
|
827
|
+
function emitHeader(
|
|
828
|
+
controller: TransformStreamDefaultController<SubgroupStreamHeader | ObjectPayload>,
|
|
829
|
+
h: SubgroupHeaderFields,
|
|
830
|
+
subgroupId: bigint,
|
|
831
|
+
): void {
|
|
832
|
+
controller.enqueue({
|
|
833
|
+
type: 'subgroup_header',
|
|
834
|
+
headerType: h.streamType,
|
|
835
|
+
trackAlias: h.trackAlias,
|
|
836
|
+
groupId: h.groupId,
|
|
837
|
+
subgroupId,
|
|
838
|
+
publisherPriority: h.publisherPriority,
|
|
839
|
+
...(h.endOfGroup ? { endOfGroup: true } : {}),
|
|
840
|
+
...(h.firstObjectFlag ? { firstObject: true } : {}),
|
|
841
|
+
})
|
|
842
|
+
headerEmitted = true
|
|
843
|
+
}
|
|
698
844
|
|
|
699
845
|
return new TransformStream<Uint8Array, SubgroupStreamHeader | ObjectPayload>({
|
|
700
846
|
transform(chunk, controller) {
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
const newBuffer = new Uint8Array(buffer.length + chunk.length)
|
|
706
|
-
newBuffer.set(buffer, 0)
|
|
707
|
-
newBuffer.set(chunk, buffer.length)
|
|
708
|
-
buffer = newBuffer
|
|
847
|
+
b.append(chunk)
|
|
848
|
+
// One view and one reader per chunk. Both used to be allocated per
|
|
849
|
+
// object, and an object is the thing there are a great many of.
|
|
850
|
+
const view = b.written()
|
|
709
851
|
|
|
710
|
-
if (
|
|
852
|
+
if (header === null) {
|
|
711
853
|
try {
|
|
712
|
-
const
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
if (!isValidSubgroupType(streamType)) {
|
|
716
|
-
controller.error(
|
|
717
|
-
new DecodeError(
|
|
718
|
-
'CONSTRAINT_VIOLATION',
|
|
719
|
-
`Invalid subgroup stream type 0x${streamType.toString(16)}`,
|
|
720
|
-
0,
|
|
721
|
-
),
|
|
722
|
-
)
|
|
723
|
-
return
|
|
724
|
-
}
|
|
725
|
-
|
|
726
|
-
_propertiesPresent = (streamType & 0x01) !== 0
|
|
727
|
-
const subgroupMode = (streamType & 0x06) >> 1
|
|
728
|
-
const hasSubgroupField = subgroupMode === 0x02
|
|
729
|
-
const hasPriority = (streamType & 0x20) === 0
|
|
730
|
-
|
|
731
|
-
const trackAlias = r.readVarInt()
|
|
732
|
-
const groupId = r.readVarInt()
|
|
733
|
-
|
|
734
|
-
let subgroupId = 0n
|
|
735
|
-
if (hasSubgroupField) {
|
|
736
|
-
subgroupId = r.readVarInt()
|
|
737
|
-
}
|
|
738
|
-
|
|
739
|
-
let publisherPriority = 128
|
|
740
|
-
if (hasPriority) {
|
|
741
|
-
publisherPriority = r.readUint8()
|
|
742
|
-
}
|
|
743
|
-
|
|
744
|
-
controller.enqueue({
|
|
745
|
-
type: 'subgroup_header',
|
|
746
|
-
trackAlias,
|
|
747
|
-
groupId,
|
|
748
|
-
subgroupId,
|
|
749
|
-
publisherPriority,
|
|
750
|
-
})
|
|
751
|
-
headerEmitted = true
|
|
752
|
-
offset += r.offset
|
|
854
|
+
const hr = new BufferReader(view, b.offset)
|
|
855
|
+
header = readSubgroupHeader(hr)
|
|
856
|
+
b.offset = hr.offset
|
|
753
857
|
} catch (e) {
|
|
754
858
|
if (e instanceof DecodeError && e.code === 'UNEXPECTED_END') {
|
|
755
859
|
return
|
|
@@ -757,50 +861,46 @@ export function createSubgroupStreamDecoder(): TransformStream<
|
|
|
757
861
|
controller.error(e)
|
|
758
862
|
return
|
|
759
863
|
}
|
|
864
|
+
// Where the Subgroup ID is the first Object's ID, that Object has not
|
|
865
|
+
// been read yet. Holding the header back until it has is the only way
|
|
866
|
+
// to emit the value the one-shot decoder reports; every other mode
|
|
867
|
+
// knows its Subgroup ID already.
|
|
868
|
+
if (!header.subgroupIsFirstObjId) emitHeader(controller, header, header.subgroupId)
|
|
760
869
|
}
|
|
761
870
|
|
|
762
|
-
|
|
871
|
+
const h = header
|
|
872
|
+
if (h === null) return
|
|
873
|
+
|
|
874
|
+
const r = new BufferReader(view, b.offset)
|
|
875
|
+
while (r.remaining > 0) {
|
|
876
|
+
// Where this Object starts, so a partial one is re-read from the top
|
|
877
|
+
// once the rest of it arrives.
|
|
878
|
+
const start = r.offset
|
|
879
|
+
let obj: ObjectPayload
|
|
763
880
|
try {
|
|
764
|
-
|
|
765
|
-
const delta = r.readVarInt()
|
|
766
|
-
let objectId: bigint
|
|
767
|
-
if (firstObject) {
|
|
768
|
-
objectId = delta
|
|
769
|
-
firstObject = false
|
|
770
|
-
} else {
|
|
771
|
-
objectId = prevObjectId + 1n + delta
|
|
772
|
-
}
|
|
773
|
-
let extensionData = new Uint8Array(0)
|
|
774
|
-
if (_propertiesPresent) {
|
|
775
|
-
const extLen = Number(r.readVarInt())
|
|
776
|
-
extensionData = extLen > 0 ? r.readBytesView(extLen) : new Uint8Array(0)
|
|
777
|
-
}
|
|
778
|
-
const payloadLength = Number(r.readVarInt())
|
|
779
|
-
const payloadByteOffset = r.offset
|
|
780
|
-
const payload = payloadLength > 0 ? r.readBytesView(payloadLength) : new Uint8Array(0)
|
|
781
|
-
controller.enqueue({
|
|
782
|
-
type: 'object',
|
|
783
|
-
objectId,
|
|
784
|
-
payloadLength,
|
|
785
|
-
payload,
|
|
786
|
-
extensionData,
|
|
787
|
-
byteOffset: 0,
|
|
788
|
-
payloadByteOffset,
|
|
789
|
-
})
|
|
790
|
-
offset += r.offset
|
|
791
|
-
prevObjectId = objectId
|
|
881
|
+
obj = readSubgroupObject(r, h.propertiesPresent, isFirst, prevObjectId, b.base)
|
|
792
882
|
} catch (e) {
|
|
793
883
|
if (e instanceof DecodeError && e.code === 'UNEXPECTED_END') {
|
|
794
|
-
|
|
884
|
+
b.offset = start
|
|
885
|
+
return
|
|
795
886
|
}
|
|
796
887
|
controller.error(e)
|
|
797
888
|
return
|
|
798
889
|
}
|
|
890
|
+
if (!headerEmitted) emitHeader(controller, h, obj.objectId)
|
|
891
|
+
isFirst = false
|
|
892
|
+
b.offset = r.offset
|
|
893
|
+
prevObjectId = obj.objectId
|
|
894
|
+
controller.enqueue(obj)
|
|
799
895
|
}
|
|
800
896
|
},
|
|
801
897
|
|
|
802
898
|
flush(controller) {
|
|
803
|
-
|
|
899
|
+
// A stream carrying a header and no Objects still has a header to report,
|
|
900
|
+
// and its Subgroup ID is then zero -- the same value the one-shot decoder
|
|
901
|
+
// returns when it finds no first Object to derive one from.
|
|
902
|
+
if (header !== null && !headerEmitted) emitHeader(controller, header, 0n)
|
|
903
|
+
if (b.unread > 0) {
|
|
804
904
|
controller.error(new DecodeError('UNEXPECTED_END', 'Stream ended with incomplete data', 0))
|
|
805
905
|
}
|
|
806
906
|
},
|
|
@@ -811,24 +911,23 @@ export function createFetchStreamDecoder(): TransformStream<
|
|
|
811
911
|
Uint8Array,
|
|
812
912
|
FetchStreamHeader | ObjectPayload
|
|
813
913
|
> {
|
|
814
|
-
|
|
815
|
-
let offset = 0
|
|
914
|
+
const b = new StreamBuffer()
|
|
816
915
|
let headerEmitted = false
|
|
916
|
+
/**
|
|
917
|
+
* The delta state the Objects carry between them. This decoder used to keep
|
|
918
|
+
* none, which is why DATAGRAM-mode Object IDs came out wrong: they resolve
|
|
919
|
+
* against the previous Object's ID.
|
|
920
|
+
*/
|
|
921
|
+
const st = newFetchObjectState()
|
|
817
922
|
|
|
818
923
|
return new TransformStream<Uint8Array, FetchStreamHeader | ObjectPayload>({
|
|
819
924
|
transform(chunk, controller) {
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
offset = 0
|
|
823
|
-
}
|
|
824
|
-
const newBuffer = new Uint8Array(buffer.length + chunk.length)
|
|
825
|
-
newBuffer.set(buffer, 0)
|
|
826
|
-
newBuffer.set(chunk, buffer.length)
|
|
827
|
-
buffer = newBuffer
|
|
925
|
+
b.append(chunk)
|
|
926
|
+
const view = b.written()
|
|
828
927
|
|
|
829
928
|
if (!headerEmitted) {
|
|
830
929
|
try {
|
|
831
|
-
const r = new BufferReader(
|
|
930
|
+
const r = new BufferReader(view, b.offset)
|
|
832
931
|
const streamType = r.readVarInt()
|
|
833
932
|
if (streamType !== FETCH_STREAM_TYPE) {
|
|
834
933
|
controller.error(
|
|
@@ -843,7 +942,7 @@ export function createFetchStreamDecoder(): TransformStream<
|
|
|
843
942
|
const requestId = r.readVarInt()
|
|
844
943
|
controller.enqueue({ type: 'fetch_header', requestId })
|
|
845
944
|
headerEmitted = true
|
|
846
|
-
offset
|
|
945
|
+
b.offset = r.offset
|
|
847
946
|
} catch (e) {
|
|
848
947
|
if (e instanceof DecodeError && e.code === 'UNEXPECTED_END') {
|
|
849
948
|
return
|
|
@@ -853,51 +952,27 @@ export function createFetchStreamDecoder(): TransformStream<
|
|
|
853
952
|
}
|
|
854
953
|
}
|
|
855
954
|
|
|
856
|
-
|
|
955
|
+
const r = new BufferReader(view, b.offset)
|
|
956
|
+
while (r.remaining > 0) {
|
|
957
|
+
const start = r.offset
|
|
958
|
+
let obj: FetchObjectPayload
|
|
857
959
|
try {
|
|
858
|
-
|
|
859
|
-
const flags = Number(r.readVarInt())
|
|
860
|
-
const objectIdPresent = (flags & 0x04) !== 0
|
|
861
|
-
const groupIdPresent = (flags & 0x08) !== 0
|
|
862
|
-
const priorityPresent = (flags & 0x10) !== 0
|
|
863
|
-
const extensionsPresent = (flags & 0x20) !== 0
|
|
864
|
-
const subgroupEncoding = flags & 0x03
|
|
865
|
-
|
|
866
|
-
if (groupIdPresent) r.readVarInt()
|
|
867
|
-
if (subgroupEncoding === 0x03) r.readVarInt()
|
|
868
|
-
let objectId = 0n
|
|
869
|
-
if (objectIdPresent) objectId = r.readVarInt()
|
|
870
|
-
if (priorityPresent) r.readUint8()
|
|
871
|
-
let extensionData = new Uint8Array(0)
|
|
872
|
-
if (extensionsPresent) {
|
|
873
|
-
const extLen = Number(r.readVarInt())
|
|
874
|
-
extensionData = extLen > 0 ? r.readBytesView(extLen) : new Uint8Array(0)
|
|
875
|
-
}
|
|
876
|
-
const payloadLength = Number(r.readVarInt())
|
|
877
|
-
const payloadByteOffset = r.offset
|
|
878
|
-
const payload = payloadLength > 0 ? r.readBytesView(payloadLength) : new Uint8Array(0)
|
|
879
|
-
controller.enqueue({
|
|
880
|
-
type: 'object',
|
|
881
|
-
objectId,
|
|
882
|
-
payloadLength,
|
|
883
|
-
payload,
|
|
884
|
-
extensionData,
|
|
885
|
-
byteOffset: 0,
|
|
886
|
-
payloadByteOffset,
|
|
887
|
-
})
|
|
888
|
-
offset += r.offset
|
|
960
|
+
obj = readFetchObject(r, b.base, st)
|
|
889
961
|
} catch (e) {
|
|
890
962
|
if (e instanceof DecodeError && e.code === 'UNEXPECTED_END') {
|
|
891
|
-
|
|
963
|
+
b.offset = start
|
|
964
|
+
return
|
|
892
965
|
}
|
|
893
966
|
controller.error(e)
|
|
894
967
|
return
|
|
895
968
|
}
|
|
969
|
+
b.offset = r.offset
|
|
970
|
+
controller.enqueue(obj)
|
|
896
971
|
}
|
|
897
972
|
},
|
|
898
973
|
|
|
899
974
|
flush(controller) {
|
|
900
|
-
if (
|
|
975
|
+
if (b.unread > 0) {
|
|
901
976
|
controller.error(new DecodeError('UNEXPECTED_END', 'Stream ended with incomplete data', 0))
|
|
902
977
|
}
|
|
903
978
|
},
|
|
@@ -905,56 +980,82 @@ export function createFetchStreamDecoder(): TransformStream<
|
|
|
905
980
|
}
|
|
906
981
|
|
|
907
982
|
export function createDataStreamDecoder(): TransformStream<Uint8Array, DataStreamEvent> {
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
983
|
+
/**
|
|
984
|
+
* Delegation that actually delegates.
|
|
985
|
+
*
|
|
986
|
+
* This function used to pick an inner decoder and then never write a byte to
|
|
987
|
+
* it: chunks accumulated in a local buffer and `flush` decoded the whole
|
|
988
|
+
* stream in one shot. Every event therefore arrived at end-of-stream, which
|
|
989
|
+
* on a subscription that stays open means no events at all. The inner
|
|
990
|
+
* decoder's readable is now pumped into this one's controller as the bytes
|
|
991
|
+
* arrive.
|
|
992
|
+
*
|
|
993
|
+
* The first byte still decides which decoder to use, on exactly the range
|
|
994
|
+
* this draft accepted before.
|
|
995
|
+
*/
|
|
996
|
+
let writer: WritableStreamDefaultWriter<Uint8Array> | null = null
|
|
997
|
+
let pump: Promise<void> = Promise.resolve()
|
|
998
|
+
let broken = false
|
|
999
|
+
|
|
1000
|
+
function attach(
|
|
1001
|
+
inner: TransformStream<Uint8Array, DataStreamEvent>,
|
|
1002
|
+
controller: TransformStreamDefaultController<DataStreamEvent>,
|
|
1003
|
+
): void {
|
|
1004
|
+
writer = inner.writable.getWriter()
|
|
1005
|
+
const reader = inner.readable.getReader()
|
|
1006
|
+
pump = (async () => {
|
|
1007
|
+
try {
|
|
1008
|
+
for (;;) {
|
|
1009
|
+
const { done, value } = await reader.read()
|
|
1010
|
+
if (done) break
|
|
1011
|
+
controller.enqueue(value)
|
|
1012
|
+
}
|
|
1013
|
+
} catch (e) {
|
|
1014
|
+
// The inner decoder rejected the stream. It owns the diagnosis, so its
|
|
1015
|
+
// error is the one that surfaces.
|
|
1016
|
+
if (!broken) {
|
|
1017
|
+
broken = true
|
|
1018
|
+
controller.error(e)
|
|
942
1019
|
}
|
|
943
1020
|
}
|
|
944
|
-
}
|
|
1021
|
+
})()
|
|
1022
|
+
}
|
|
945
1023
|
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
1024
|
+
async function feed(bytes: Uint8Array): Promise<void> {
|
|
1025
|
+
if (writer === null || broken || bytes.length === 0) return
|
|
1026
|
+
try {
|
|
1027
|
+
await writer.write(bytes)
|
|
1028
|
+
} catch {
|
|
1029
|
+
// Writing to an errored inner stream throws the same error the pump is
|
|
1030
|
+
// already reporting; swallow it here so it is reported once.
|
|
1031
|
+
broken = true
|
|
1032
|
+
}
|
|
1033
|
+
}
|
|
949
1034
|
|
|
950
|
-
|
|
951
|
-
|
|
1035
|
+
return new TransformStream<Uint8Array, DataStreamEvent>({
|
|
1036
|
+
async transform(chunk, controller) {
|
|
1037
|
+
if (broken) return
|
|
1038
|
+
if (writer !== null) {
|
|
1039
|
+
await feed(chunk)
|
|
1040
|
+
return
|
|
1041
|
+
}
|
|
1042
|
+
// One byte is enough to choose, and until there is one there is nothing
|
|
1043
|
+
// to choose from.
|
|
1044
|
+
if (chunk.length === 0) return
|
|
1045
|
+
const firstByte = chunk[0]!
|
|
952
1046
|
|
|
953
1047
|
if (isValidSubgroupType(firstByte)) {
|
|
954
|
-
|
|
1048
|
+
attach(
|
|
1049
|
+
createSubgroupStreamDecoder() as unknown as TransformStream<Uint8Array, DataStreamEvent>,
|
|
1050
|
+
controller,
|
|
1051
|
+
)
|
|
955
1052
|
} else if (firstByte === 0x05) {
|
|
956
|
-
|
|
1053
|
+
attach(
|
|
1054
|
+
createFetchStreamDecoder() as unknown as TransformStream<Uint8Array, DataStreamEvent>,
|
|
1055
|
+
controller,
|
|
1056
|
+
)
|
|
957
1057
|
} else {
|
|
1058
|
+
broken = true
|
|
958
1059
|
controller.error(
|
|
959
1060
|
new DecodeError(
|
|
960
1061
|
'CONSTRAINT_VIOLATION',
|
|
@@ -965,32 +1066,19 @@ export function createDataStreamDecoder(): TransformStream<Uint8Array, DataStrea
|
|
|
965
1066
|
return
|
|
966
1067
|
}
|
|
967
1068
|
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
1069
|
+
// The type byte is part of the stream the inner decoder reads, so the
|
|
1070
|
+
// whole chunk goes in, first byte included.
|
|
1071
|
+
await feed(chunk)
|
|
1072
|
+
},
|
|
972
1073
|
|
|
973
|
-
|
|
974
|
-
if (
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
subgroupId: stream.subgroupId,
|
|
980
|
-
publisherPriority: stream.publisherPriority,
|
|
981
|
-
})
|
|
982
|
-
for (const obj of stream.objects) {
|
|
983
|
-
controller.enqueue(obj)
|
|
984
|
-
}
|
|
985
|
-
} else if (stream.type === 'fetch') {
|
|
986
|
-
controller.enqueue({
|
|
987
|
-
type: 'fetch_header',
|
|
988
|
-
requestId: stream.requestId,
|
|
989
|
-
})
|
|
990
|
-
for (const obj of stream.objects) {
|
|
991
|
-
controller.enqueue(obj)
|
|
992
|
-
}
|
|
1074
|
+
async flush() {
|
|
1075
|
+
if (writer === null) return
|
|
1076
|
+
try {
|
|
1077
|
+
await writer.close()
|
|
1078
|
+
} catch {
|
|
1079
|
+
// Reported by the pump.
|
|
993
1080
|
}
|
|
1081
|
+
await pump
|
|
994
1082
|
},
|
|
995
1083
|
})
|
|
996
1084
|
}
|