@moqtap/codec 0.9.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.
Files changed (232) hide show
  1. package/CHANGELOG.md +173 -0
  2. package/dist/auth-redaction-DsdLq4Qs.d.cts +102 -0
  3. package/dist/auth-redaction-DsdLq4Qs.d.ts +102 -0
  4. package/dist/{chunk-PU2KV7VP.cjs → chunk-27K5BUAG.cjs} +485 -515
  5. package/dist/{chunk-BV6MITLO.js → chunk-3RNQMGKA.js} +365 -390
  6. package/dist/{chunk-2XH6PHXR.js → chunk-5AWIXOLB.js} +442 -467
  7. package/dist/{chunk-4XLYCT5Q.cjs → chunk-5IMHJIAZ.cjs} +52 -2
  8. package/dist/{chunk-TVSFDQYE.cjs → chunk-5JGZCKJO.cjs} +513 -531
  9. package/dist/{chunk-IADVBKEJ.cjs → chunk-73K4OSAN.cjs} +407 -432
  10. package/dist/{chunk-N2V7Z37J.js → chunk-7VQKRGRD.js} +19 -3
  11. package/dist/{chunk-UZO5Z2XT.cjs → chunk-A3UCQOIB.cjs} +490 -515
  12. package/dist/{chunk-JKMYAUGY.js → chunk-A7PDMVXM.js} +35 -11
  13. package/dist/{chunk-VZHL2U2N.cjs → chunk-A7VQO6YC.cjs} +54 -38
  14. package/dist/{chunk-KCH4BQXK.cjs → chunk-ACQHZLRZ.cjs} +73 -47
  15. package/dist/{chunk-H6DTAIWM.js → chunk-BBICOMW6.js} +47 -19
  16. package/dist/{chunk-MAXEHYVB.cjs → chunk-BNIUVOCJ.cjs} +554 -612
  17. package/dist/{chunk-QGIHC6BA.cjs → chunk-CNC6ANS4.cjs} +70 -46
  18. package/dist/{chunk-NH4L6NIY.js → chunk-FDLQSWHK.js} +437 -467
  19. package/dist/{chunk-IJAF6PAY.js → chunk-FFNOE4UR.js} +19 -3
  20. package/dist/{chunk-CZNW3R5E.cjs → chunk-GMENT63T.cjs} +54 -38
  21. package/dist/{chunk-7ENEWAMZ.cjs → chunk-HM7BLRVP.cjs} +305 -305
  22. package/dist/{chunk-XHAP2YST.js → chunk-HZONHFNO.js} +19 -3
  23. package/dist/{chunk-EVCPBFSR.cjs → chunk-ILYABWDK.cjs} +83 -55
  24. package/dist/{chunk-IDV2JYJ6.cjs → chunk-KRSFTZVO.cjs} +56 -40
  25. package/dist/{chunk-RIIA4ALQ.cjs → chunk-KSPH6KMH.cjs} +54 -38
  26. package/dist/{chunk-UA5XFP4O.cjs → chunk-KTY4LAUV.cjs} +485 -494
  27. package/dist/{chunk-RZTLQAKF.js → chunk-OJNLJT5D.js} +0 -1
  28. package/dist/{chunk-YJGOD3Y4.js → chunk-PJK2ZS3I.js} +492 -550
  29. package/dist/{chunk-TMXRYOBS.js → chunk-PSMZKHOC.js} +444 -453
  30. package/dist/{chunk-7RE6KSIY.cjs → chunk-Q5JQGHWY.cjs} +0 -1
  31. package/dist/{chunk-23KRITJ6.js → chunk-SQTUQY5E.js} +37 -11
  32. package/dist/{chunk-XQGEOFGE.js → chunk-WCRLAKDW.js} +253 -253
  33. package/dist/{chunk-KYVTM5VI.js → chunk-WL2YUEXH.js} +19 -3
  34. package/dist/{chunk-Q7NSUXXB.js → chunk-YCNIVZS7.js} +464 -482
  35. package/dist/{chunk-KLPWJU6W.js → chunk-YRZQVNZO.js} +50 -0
  36. package/dist/{codec-Bym-K2q2.d.cts → codec-76xzrLTL.d.cts} +21 -2
  37. package/dist/{codec-BKsVu3Fr.d.ts → codec-8p40WdLg.d.ts} +21 -2
  38. package/dist/{codec-Dl_QIXMz.d.ts → codec-BN2Bu0KI.d.ts} +20 -1
  39. package/dist/{codec-D4RvFQmu.d.ts → codec-Bb6GKTrv.d.ts} +21 -2
  40. package/dist/{codec-DAyiF5sq.d.cts → codec-BgpfHoAd.d.cts} +21 -2
  41. package/dist/{codec-CA6nbbEk.d.ts → codec-BkheTXO7.d.ts} +21 -2
  42. package/dist/{codec-DchsPfr3.d.cts → codec-BwVDkokh.d.cts} +21 -2
  43. package/dist/{codec-CgZdadPt.d.cts → codec-C5s1eBJX.d.cts} +21 -2
  44. package/dist/codec-CM5yd6n3.d.ts +38 -0
  45. package/dist/{codec-DJmqoIsp.d.cts → codec-Cb8HC3XV.d.cts} +21 -2
  46. package/dist/codec-Clu_skx8.d.cts +38 -0
  47. package/dist/{codec-DzkdW4kO.d.cts → codec-CpOpemR8.d.cts} +20 -1
  48. package/dist/{codec-CXCjya_G.d.cts → codec-Cshdl9Tt.d.cts} +20 -1
  49. package/dist/{codec-CSBFdPgP.d.cts → codec-DELe00w_.d.cts} +21 -2
  50. package/dist/{codec-C_xxsbKy.d.cts → codec-DHzKAUCa.d.cts} +21 -2
  51. package/dist/{codec--CVeqGQv.d.ts → codec-DdVBtvx7.d.ts} +20 -1
  52. package/dist/{codec-CviAa4lp.d.ts → codec-DlxGuYMv.d.ts} +21 -2
  53. package/dist/{codec-BNy5syCU.d.ts → codec-DxtgPxJS.d.ts} +20 -1
  54. package/dist/{codec-CtvFK4aV.d.cts → codec-GAY4lybi.d.cts} +21 -2
  55. package/dist/{codec-Cfo_z5ET.d.cts → codec-I8u2pfS4.d.cts} +20 -1
  56. package/dist/{codec-vddqy0KY.d.cts → codec-XLrnreeu.d.cts} +21 -2
  57. package/dist/{codec-O-1Js7h4.d.ts → codec-c0YEwwWn.d.ts} +21 -2
  58. package/dist/{codec-Cl73EfRW.d.ts → codec-ejDu-va6.d.ts} +21 -2
  59. package/dist/{codec-C006F75E.d.ts → codec-kaBUzdpV.d.ts} +21 -2
  60. package/dist/{codec-C5evFHL-.d.ts → codec-mVYqkIUF.d.ts} +21 -2
  61. package/dist/{codec-BMwgZIgG.d.ts → codec-qSbO5nOa.d.ts} +21 -2
  62. package/dist/{codec-BQa6Qsav.d.ts → codec-yYKGOipj.d.ts} +21 -2
  63. package/dist/{codec-DzLvG8Wb.d.cts → codec-zfzg9uiy.d.cts} +21 -2
  64. package/dist/draft07.cjs +48 -4
  65. package/dist/draft07.d.cts +42 -2
  66. package/dist/draft07.d.ts +42 -2
  67. package/dist/draft07.js +49 -5
  68. package/dist/draft08.cjs +76 -3
  69. package/dist/draft08.d.cts +70 -2
  70. package/dist/draft08.d.ts +70 -2
  71. package/dist/draft08.js +77 -4
  72. package/dist/draft09.cjs +76 -3
  73. package/dist/draft09.d.cts +70 -2
  74. package/dist/draft09.d.ts +70 -2
  75. package/dist/draft09.js +77 -4
  76. package/dist/draft10.cjs +76 -3
  77. package/dist/draft10.d.cts +70 -2
  78. package/dist/draft10.d.ts +70 -2
  79. package/dist/draft10.js +77 -4
  80. package/dist/draft11-session.d.cts +1 -1
  81. package/dist/draft11-session.d.ts +1 -1
  82. package/dist/draft11.cjs +104 -3
  83. package/dist/draft11.d.cts +100 -4
  84. package/dist/draft11.d.ts +100 -4
  85. package/dist/draft11.js +105 -4
  86. package/dist/draft12-session.d.cts +1 -1
  87. package/dist/draft12-session.d.ts +1 -1
  88. package/dist/draft12.cjs +113 -3
  89. package/dist/draft12.d.cts +109 -4
  90. package/dist/draft12.d.ts +109 -4
  91. package/dist/draft12.js +114 -4
  92. package/dist/draft13-session.d.cts +1 -1
  93. package/dist/draft13-session.d.ts +1 -1
  94. package/dist/draft13.cjs +105 -3
  95. package/dist/draft13.d.cts +101 -4
  96. package/dist/draft13.d.ts +101 -4
  97. package/dist/draft13.js +106 -4
  98. package/dist/draft14-session.d.cts +1 -1
  99. package/dist/draft14-session.d.ts +1 -1
  100. package/dist/draft14.cjs +107 -3
  101. package/dist/draft14.d.cts +103 -30
  102. package/dist/draft14.d.ts +103 -30
  103. package/dist/draft14.js +108 -4
  104. package/dist/draft15-session.d.cts +1 -1
  105. package/dist/draft15-session.d.ts +1 -1
  106. package/dist/draft15.cjs +69 -3
  107. package/dist/draft15.d.cts +65 -22
  108. package/dist/draft15.d.ts +65 -22
  109. package/dist/draft15.js +70 -4
  110. package/dist/draft16-session.cjs +2 -2
  111. package/dist/draft16-session.d.cts +1 -1
  112. package/dist/draft16-session.d.ts +1 -1
  113. package/dist/draft16-session.js +1 -1
  114. package/dist/draft16.cjs +76 -8
  115. package/dist/draft16.d.cts +67 -13
  116. package/dist/draft16.d.ts +67 -13
  117. package/dist/draft16.js +73 -5
  118. package/dist/draft17-session.d.cts +1 -1
  119. package/dist/draft17-session.d.ts +1 -1
  120. package/dist/draft17.cjs +77 -3
  121. package/dist/draft17.d.cts +73 -4
  122. package/dist/draft17.d.ts +73 -4
  123. package/dist/draft17.js +78 -4
  124. package/dist/draft18-session.d.cts +1 -1
  125. package/dist/draft18-session.d.ts +1 -1
  126. package/dist/draft18.cjs +8 -3
  127. package/dist/draft18.d.cts +4 -3
  128. package/dist/draft18.d.ts +4 -3
  129. package/dist/draft18.js +9 -4
  130. package/dist/draft19-session.d.cts +1 -1
  131. package/dist/draft19-session.d.ts +1 -1
  132. package/dist/draft19.cjs +11 -4
  133. package/dist/draft19.d.cts +4 -3
  134. package/dist/draft19.d.ts +4 -3
  135. package/dist/draft19.js +12 -5
  136. package/dist/draft20-session.d.cts +1 -1
  137. package/dist/draft20-session.d.ts +1 -1
  138. package/dist/draft20.cjs +8 -3
  139. package/dist/draft20.d.cts +4 -3
  140. package/dist/draft20.d.ts +4 -3
  141. package/dist/draft20.js +9 -4
  142. package/dist/index.cjs +30 -30
  143. package/dist/index.d.cts +25 -24
  144. package/dist/index.d.ts +25 -24
  145. package/dist/index.js +15 -15
  146. package/dist/session.cjs +2 -2
  147. package/dist/session.d.cts +10 -10
  148. package/dist/session.d.ts +10 -10
  149. package/dist/session.js +1 -1
  150. package/dist/{types-zHgCS6o5.d.cts → types-Btp416jt.d.cts} +15 -7
  151. package/dist/{types-zHgCS6o5.d.ts → types-Btp416jt.d.ts} +15 -7
  152. package/dist/{types-Cm9fjeYC.d.cts → types-BxTL1NXw.d.cts} +9 -2
  153. package/dist/{types-Cm9fjeYC.d.ts → types-BxTL1NXw.d.ts} +9 -2
  154. package/dist/{types-Bio-91Rt.d.cts → types-CI_SX4Xe.d.cts} +2 -2
  155. package/dist/{types-Bio-91Rt.d.ts → types-CI_SX4Xe.d.ts} +2 -2
  156. package/dist/{types-HI_bbXka.d.cts → types-CmqT0jUf.d.cts} +1 -1
  157. package/dist/{types-HI_bbXka.d.ts → types-CmqT0jUf.d.ts} +1 -1
  158. package/dist/{types-CPaYBsMG.d.cts → types-CuibHYcf.d.cts} +9 -2
  159. package/dist/{types-CPaYBsMG.d.ts → types-CuibHYcf.d.ts} +9 -2
  160. package/dist/{types-CWCQwuvy.d.cts → types-CwN7AEoL.d.cts} +24 -12
  161. package/dist/{types-CWCQwuvy.d.ts → types-CwN7AEoL.d.ts} +24 -12
  162. package/dist/{types-Ck45Ex5S.d.cts → types-D0kTgUuL.d.cts} +1 -1
  163. package/dist/{types-Ck45Ex5S.d.ts → types-D0kTgUuL.d.ts} +1 -1
  164. package/dist/{types-D9eiB_9A.d.cts → types-DAnalt5K.d.cts} +9 -2
  165. package/dist/{types-D9eiB_9A.d.ts → types-DAnalt5K.d.ts} +9 -2
  166. package/dist/{types-CXlSn0I9.d.cts → types-DjxexghA.d.cts} +2 -2
  167. package/dist/{types-CXlSn0I9.d.ts → types-DjxexghA.d.ts} +2 -2
  168. package/dist/{types-Cqp10JtB.d.cts → types-DxXNP32l.d.cts} +10 -2
  169. package/dist/{types-Cqp10JtB.d.ts → types-DxXNP32l.d.ts} +10 -2
  170. package/package.json +3 -3
  171. package/src/core/auth-redaction.ts +192 -0
  172. package/src/drafts/draft07/codec.ts +40 -0
  173. package/src/drafts/draft07/error-codes.ts +44 -0
  174. package/src/drafts/draft07/index.ts +15 -0
  175. package/src/drafts/draft08/codec.ts +40 -0
  176. package/src/drafts/draft08/error-codes.ts +76 -0
  177. package/src/drafts/draft08/index.ts +21 -0
  178. package/src/drafts/draft09/codec.ts +40 -0
  179. package/src/drafts/draft09/error-codes.ts +76 -0
  180. package/src/drafts/draft09/index.ts +21 -0
  181. package/src/drafts/draft10/codec.ts +40 -0
  182. package/src/drafts/draft10/error-codes.ts +76 -0
  183. package/src/drafts/draft10/index.ts +21 -0
  184. package/src/drafts/draft11/codec.ts +71 -8
  185. package/src/drafts/draft11/error-codes.ts +106 -0
  186. package/src/drafts/draft11/index.ts +23 -0
  187. package/src/drafts/draft11/types.ts +1 -1
  188. package/src/drafts/draft12/codec.ts +83 -16
  189. package/src/drafts/draft12/error-codes.ts +116 -0
  190. package/src/drafts/draft12/index.ts +25 -0
  191. package/src/drafts/draft12/types.ts +2 -2
  192. package/src/drafts/draft13/codec.ts +75 -11
  193. package/src/drafts/draft13/error-codes.ts +107 -0
  194. package/src/drafts/draft13/index.ts +23 -0
  195. package/src/drafts/draft13/types.ts +3 -3
  196. package/src/drafts/draft14/codec.ts +79 -12
  197. package/src/drafts/draft14/data-streams.ts +331 -259
  198. package/src/drafts/draft14/error-codes.ts +109 -0
  199. package/src/drafts/draft14/index.ts +23 -0
  200. package/src/drafts/draft14/types.ts +1 -1
  201. package/src/drafts/draft15/codec.ts +71 -8
  202. package/src/drafts/draft15/data-streams.ts +489 -444
  203. package/src/drafts/draft15/error-codes.ts +66 -0
  204. package/src/drafts/draft15/index.ts +15 -0
  205. package/src/drafts/draft15/types.ts +9 -2
  206. package/src/drafts/draft16/codec.ts +149 -49
  207. package/src/drafts/draft16/data-streams.ts +513 -442
  208. package/src/drafts/draft16/error-codes.ts +68 -0
  209. package/src/drafts/draft16/index.ts +15 -0
  210. package/src/drafts/draft16/messages.ts +4 -4
  211. package/src/drafts/draft16/session-fsm.ts +0 -1
  212. package/src/drafts/draft16/types.ts +24 -10
  213. package/src/drafts/draft17/codec.ts +77 -10
  214. package/src/drafts/draft17/data-streams.ts +567 -488
  215. package/src/drafts/draft17/index.ts +15 -0
  216. package/src/drafts/draft17/types.ts +9 -2
  217. package/src/drafts/draft18/codec.ts +70 -7
  218. package/src/drafts/draft18/data-streams.ts +570 -482
  219. package/src/drafts/draft18/index.ts +3 -0
  220. package/src/drafts/draft18/types.ts +18 -10
  221. package/src/drafts/draft19/codec.ts +95 -23
  222. package/src/drafts/draft19/data-streams.ts +570 -482
  223. package/src/drafts/draft19/error-codes.ts +3 -1
  224. package/src/drafts/draft19/index.ts +3 -0
  225. package/src/drafts/draft19/messages.ts +3 -1
  226. package/src/drafts/draft19/types.ts +32 -18
  227. package/src/drafts/draft20/codec.ts +115 -36
  228. package/src/drafts/draft20/data-streams.ts +610 -563
  229. package/src/drafts/draft20/index.ts +3 -0
  230. package/src/drafts/draft20/types.ts +31 -13
  231. package/dist/codec-BJ7BHuiZ.d.ts +0 -18
  232. package/dist/codec-C6Mx4bwz.d.cts +0 -18
@@ -12,7 +12,7 @@ interface AuthorizationToken {
12
12
  interface Draft15SetupParams {
13
13
  path?: string;
14
14
  max_request_id?: bigint;
15
- authorization_token?: AuthorizationToken;
15
+ authorization_token?: readonly AuthorizationToken[];
16
16
  max_auth_token_cache_size?: bigint;
17
17
  authority?: string;
18
18
  moqt_implementation?: string;
@@ -30,7 +30,7 @@ interface LargestObject {
30
30
  }
31
31
  interface Draft15Params {
32
32
  delivery_timeout?: bigint;
33
- authorization_token?: AuthorizationToken;
33
+ authorization_token?: readonly AuthorizationToken[];
34
34
  max_cache_duration?: bigint;
35
35
  expires?: bigint;
36
36
  largest_object?: LargestObject;
@@ -234,10 +234,17 @@ interface FetchStream {
234
234
  type Draft15DataStream = SubgroupStream | DatagramObject | FetchStream;
235
235
  interface SubgroupStreamHeader {
236
236
  readonly type: 'subgroup_header';
237
+ /**
238
+ * The stream Type Flags, the same value `SubgroupStream.headerType` carries.
239
+ * Without it the incremental decoder discarded every flag the header
240
+ * encodes and a consumer could not tell the modes apart.
241
+ */
242
+ readonly headerType: number;
237
243
  readonly trackAlias: bigint;
238
244
  readonly groupId: bigint;
239
245
  readonly subgroupId: bigint;
240
246
  readonly publisherPriority: number;
247
+ readonly endOfGroup?: boolean;
241
248
  }
242
249
  interface FetchStreamHeader {
243
250
  readonly type: 'fetch_header';
@@ -12,7 +12,7 @@ interface AuthorizationToken {
12
12
  interface Draft15SetupParams {
13
13
  path?: string;
14
14
  max_request_id?: bigint;
15
- authorization_token?: AuthorizationToken;
15
+ authorization_token?: readonly AuthorizationToken[];
16
16
  max_auth_token_cache_size?: bigint;
17
17
  authority?: string;
18
18
  moqt_implementation?: string;
@@ -30,7 +30,7 @@ interface LargestObject {
30
30
  }
31
31
  interface Draft15Params {
32
32
  delivery_timeout?: bigint;
33
- authorization_token?: AuthorizationToken;
33
+ authorization_token?: readonly AuthorizationToken[];
34
34
  max_cache_duration?: bigint;
35
35
  expires?: bigint;
36
36
  largest_object?: LargestObject;
@@ -234,10 +234,17 @@ interface FetchStream {
234
234
  type Draft15DataStream = SubgroupStream | DatagramObject | FetchStream;
235
235
  interface SubgroupStreamHeader {
236
236
  readonly type: 'subgroup_header';
237
+ /**
238
+ * The stream Type Flags, the same value `SubgroupStream.headerType` carries.
239
+ * Without it the incremental decoder discarded every flag the header
240
+ * encodes and a consumer could not tell the modes apart.
241
+ */
242
+ readonly headerType: number;
237
243
  readonly trackAlias: bigint;
238
244
  readonly groupId: bigint;
239
245
  readonly subgroupId: bigint;
240
246
  readonly publisherPriority: number;
247
+ readonly endOfGroup?: boolean;
241
248
  }
242
249
  interface FetchStreamHeader {
243
250
  readonly type: 'fetch_header';
@@ -11,7 +11,7 @@ interface AuthorizationToken {
11
11
  }
12
12
  interface Draft20SetupOptions {
13
13
  path?: string;
14
- authorization_token?: AuthorizationToken;
14
+ authorization_token?: readonly AuthorizationToken[];
15
15
  max_auth_token_cache_size?: bigint;
16
16
  authority?: string;
17
17
  max_filter_ranges?: bigint;
@@ -20,7 +20,7 @@ interface Draft20SetupOptions {
20
20
  unknown?: UnknownParam[];
21
21
  }
22
22
  /**
23
- * LOCATION_FILTER (0x21) — restructured in draft-20 (Section 5.1.2).
23
+ * LOCATION_FILTER (0x21) — draft-20 Section 5.1.2.
24
24
  *
25
25
  * The draft-19 `Filter Type` discriminator (0x1 Next Group Start / 0x2 Largest
26
26
  * Object / 0x3 AbsoluteStart / 0x4 AbsoluteRange) is gone; the shape is the
@@ -80,14 +80,14 @@ interface Draft20FillParameters {
80
80
  subscriber_priority?: bigint;
81
81
  location_filter?: LocationFilter;
82
82
  group_order?: bigint;
83
- subgroup_filter?: RangeFilter;
84
- objectid_filter?: RangeFilter;
85
- priority_filter?: RangeFilter;
86
- object_property_filter?: RangeFilter;
83
+ subgroup_filter?: readonly RangeFilter[];
84
+ objectid_filter?: readonly RangeFilter[];
85
+ priority_filter?: readonly RangeFilter[];
86
+ object_property_filter?: readonly RangeFilter[];
87
87
  }
88
88
  interface Draft20Params {
89
89
  object_delivery_timeout?: bigint;
90
- authorization_token?: AuthorizationToken;
90
+ authorization_token?: readonly AuthorizationToken[];
91
91
  rendezvous_timeout?: bigint;
92
92
  subgroup_delivery_timeout?: bigint;
93
93
  expires?: bigint;
@@ -98,11 +98,11 @@ interface Draft20Params {
98
98
  location_filter?: LocationFilter;
99
99
  group_order?: bigint;
100
100
  fill_parameters?: Draft20FillParameters;
101
- subgroup_filter?: RangeFilter;
102
- objectid_filter?: RangeFilter;
103
- priority_filter?: RangeFilter;
104
- object_property_filter?: RangeFilter;
105
- track_property_filter?: RangeFilter;
101
+ subgroup_filter?: readonly RangeFilter[];
102
+ objectid_filter?: readonly RangeFilter[];
103
+ priority_filter?: readonly RangeFilter[];
104
+ object_property_filter?: readonly RangeFilter[];
105
+ track_property_filter?: readonly RangeFilter[];
106
106
  new_group_request?: bigint;
107
107
  track_namespace_prefix?: string[];
108
108
  include_properties?: bigint;
@@ -344,10 +344,22 @@ interface FetchStream {
344
344
  type Draft20DataStream = SubgroupStream | DatagramObject | FetchStream;
345
345
  interface SubgroupStreamHeader {
346
346
  readonly type: 'subgroup_header';
347
+ /**
348
+ * SUBGROUP_HEADER `Type Flags`, the same value `SubgroupStream.headerType`
349
+ * carries. It is reported so the incremental decoder does not drop the flags
350
+ * the header encodes, which is what lets a consumer tell the modes apart.
351
+ */
352
+ readonly headerType: number;
347
353
  readonly trackAlias: bigint;
348
354
  readonly groupId: bigint;
355
+ /**
356
+ * Under Subgroup Mode 0b01 this is the first Object's ID, which is why the
357
+ * header is not emitted until that Object has been read.
358
+ */
349
359
  readonly subgroupId: bigint;
350
360
  readonly publisherPriority: number;
361
+ readonly endOfGroup?: boolean;
362
+ readonly firstObject?: boolean;
351
363
  }
352
364
  interface FetchStreamHeader {
353
365
  readonly type: 'fetch_header';
@@ -11,7 +11,7 @@ interface AuthorizationToken {
11
11
  }
12
12
  interface Draft20SetupOptions {
13
13
  path?: string;
14
- authorization_token?: AuthorizationToken;
14
+ authorization_token?: readonly AuthorizationToken[];
15
15
  max_auth_token_cache_size?: bigint;
16
16
  authority?: string;
17
17
  max_filter_ranges?: bigint;
@@ -20,7 +20,7 @@ interface Draft20SetupOptions {
20
20
  unknown?: UnknownParam[];
21
21
  }
22
22
  /**
23
- * LOCATION_FILTER (0x21) — restructured in draft-20 (Section 5.1.2).
23
+ * LOCATION_FILTER (0x21) — draft-20 Section 5.1.2.
24
24
  *
25
25
  * The draft-19 `Filter Type` discriminator (0x1 Next Group Start / 0x2 Largest
26
26
  * Object / 0x3 AbsoluteStart / 0x4 AbsoluteRange) is gone; the shape is the
@@ -80,14 +80,14 @@ interface Draft20FillParameters {
80
80
  subscriber_priority?: bigint;
81
81
  location_filter?: LocationFilter;
82
82
  group_order?: bigint;
83
- subgroup_filter?: RangeFilter;
84
- objectid_filter?: RangeFilter;
85
- priority_filter?: RangeFilter;
86
- object_property_filter?: RangeFilter;
83
+ subgroup_filter?: readonly RangeFilter[];
84
+ objectid_filter?: readonly RangeFilter[];
85
+ priority_filter?: readonly RangeFilter[];
86
+ object_property_filter?: readonly RangeFilter[];
87
87
  }
88
88
  interface Draft20Params {
89
89
  object_delivery_timeout?: bigint;
90
- authorization_token?: AuthorizationToken;
90
+ authorization_token?: readonly AuthorizationToken[];
91
91
  rendezvous_timeout?: bigint;
92
92
  subgroup_delivery_timeout?: bigint;
93
93
  expires?: bigint;
@@ -98,11 +98,11 @@ interface Draft20Params {
98
98
  location_filter?: LocationFilter;
99
99
  group_order?: bigint;
100
100
  fill_parameters?: Draft20FillParameters;
101
- subgroup_filter?: RangeFilter;
102
- objectid_filter?: RangeFilter;
103
- priority_filter?: RangeFilter;
104
- object_property_filter?: RangeFilter;
105
- track_property_filter?: RangeFilter;
101
+ subgroup_filter?: readonly RangeFilter[];
102
+ objectid_filter?: readonly RangeFilter[];
103
+ priority_filter?: readonly RangeFilter[];
104
+ object_property_filter?: readonly RangeFilter[];
105
+ track_property_filter?: readonly RangeFilter[];
106
106
  new_group_request?: bigint;
107
107
  track_namespace_prefix?: string[];
108
108
  include_properties?: bigint;
@@ -344,10 +344,22 @@ interface FetchStream {
344
344
  type Draft20DataStream = SubgroupStream | DatagramObject | FetchStream;
345
345
  interface SubgroupStreamHeader {
346
346
  readonly type: 'subgroup_header';
347
+ /**
348
+ * SUBGROUP_HEADER `Type Flags`, the same value `SubgroupStream.headerType`
349
+ * carries. It is reported so the incremental decoder does not drop the flags
350
+ * the header encodes, which is what lets a consumer tell the modes apart.
351
+ */
352
+ readonly headerType: number;
347
353
  readonly trackAlias: bigint;
348
354
  readonly groupId: bigint;
355
+ /**
356
+ * Under Subgroup Mode 0b01 this is the first Object's ID, which is why the
357
+ * header is not emitted until that Object has been read.
358
+ */
349
359
  readonly subgroupId: bigint;
350
360
  readonly publisherPriority: number;
361
+ readonly endOfGroup?: boolean;
362
+ readonly firstObject?: boolean;
351
363
  }
352
364
  interface FetchStreamHeader {
353
365
  readonly type: 'fetch_header';
@@ -14,7 +14,7 @@ interface Draft11SetupParams {
14
14
  unknown?: UnknownParam[];
15
15
  }
16
16
  interface Draft11Params {
17
- authorization_token?: AuthorizationToken;
17
+ authorization_token?: readonly AuthorizationToken[];
18
18
  delivery_timeout?: bigint;
19
19
  max_cache_duration?: bigint;
20
20
  unknown?: UnknownParam[];
@@ -14,7 +14,7 @@ interface Draft11SetupParams {
14
14
  unknown?: UnknownParam[];
15
15
  }
16
16
  interface Draft11Params {
17
- authorization_token?: AuthorizationToken;
17
+ authorization_token?: readonly AuthorizationToken[];
18
18
  delivery_timeout?: bigint;
19
19
  max_cache_duration?: bigint;
20
20
  unknown?: UnknownParam[];
@@ -11,7 +11,7 @@ interface AuthorizationToken {
11
11
  }
12
12
  interface Draft17SetupOptions {
13
13
  path?: string;
14
- authorization_token?: AuthorizationToken;
14
+ authorization_token?: readonly AuthorizationToken[];
15
15
  max_auth_token_cache_size?: bigint;
16
16
  authority?: string;
17
17
  moqt_implementation?: string;
@@ -29,7 +29,7 @@ interface LargestObject {
29
29
  }
30
30
  interface Draft17Params {
31
31
  delivery_timeout?: bigint;
32
- authorization_token?: AuthorizationToken;
32
+ authorization_token?: readonly AuthorizationToken[];
33
33
  rendezvous_timeout?: bigint;
34
34
  expires?: bigint;
35
35
  largest_object?: LargestObject;
@@ -227,10 +227,17 @@ interface FetchStream {
227
227
  type Draft17DataStream = SubgroupStream | DatagramObject | FetchStream;
228
228
  interface SubgroupStreamHeader {
229
229
  readonly type: 'subgroup_header';
230
+ /**
231
+ * The stream Type Flags, the same value `SubgroupStream.headerType` carries.
232
+ * Without it the incremental decoder discarded every flag the header
233
+ * encodes and a consumer could not tell the modes apart.
234
+ */
235
+ readonly headerType: number;
230
236
  readonly trackAlias: bigint;
231
237
  readonly groupId: bigint;
232
238
  readonly subgroupId: bigint;
233
239
  readonly publisherPriority: number;
240
+ readonly endOfGroup?: boolean;
234
241
  }
235
242
  interface FetchStreamHeader {
236
243
  readonly type: 'fetch_header';
@@ -11,7 +11,7 @@ interface AuthorizationToken {
11
11
  }
12
12
  interface Draft17SetupOptions {
13
13
  path?: string;
14
- authorization_token?: AuthorizationToken;
14
+ authorization_token?: readonly AuthorizationToken[];
15
15
  max_auth_token_cache_size?: bigint;
16
16
  authority?: string;
17
17
  moqt_implementation?: string;
@@ -29,7 +29,7 @@ interface LargestObject {
29
29
  }
30
30
  interface Draft17Params {
31
31
  delivery_timeout?: bigint;
32
- authorization_token?: AuthorizationToken;
32
+ authorization_token?: readonly AuthorizationToken[];
33
33
  rendezvous_timeout?: bigint;
34
34
  expires?: bigint;
35
35
  largest_object?: LargestObject;
@@ -227,10 +227,17 @@ interface FetchStream {
227
227
  type Draft17DataStream = SubgroupStream | DatagramObject | FetchStream;
228
228
  interface SubgroupStreamHeader {
229
229
  readonly type: 'subgroup_header';
230
+ /**
231
+ * The stream Type Flags, the same value `SubgroupStream.headerType` carries.
232
+ * Without it the incremental decoder discarded every flag the header
233
+ * encodes and a consumer could not tell the modes apart.
234
+ */
235
+ readonly headerType: number;
230
236
  readonly trackAlias: bigint;
231
237
  readonly groupId: bigint;
232
238
  readonly subgroupId: bigint;
233
239
  readonly publisherPriority: number;
240
+ readonly endOfGroup?: boolean;
234
241
  }
235
242
  interface FetchStreamHeader {
236
243
  readonly type: 'fetch_header';
@@ -12,13 +12,13 @@ interface AuthorizationToken {
12
12
  interface Draft13SetupParams {
13
13
  path?: string;
14
14
  max_request_id?: bigint;
15
- authorization_token?: AuthorizationToken;
15
+ authorization_token?: readonly AuthorizationToken[];
16
16
  max_auth_token_cache_size?: bigint;
17
17
  unknown?: UnknownParam[];
18
18
  }
19
19
  interface Draft13Params {
20
20
  delivery_timeout?: bigint;
21
- authorization_token?: AuthorizationToken;
21
+ authorization_token?: readonly AuthorizationToken[];
22
22
  max_cache_duration?: bigint;
23
23
  unknown?: UnknownParam[];
24
24
  }
@@ -12,13 +12,13 @@ interface AuthorizationToken {
12
12
  interface Draft13SetupParams {
13
13
  path?: string;
14
14
  max_request_id?: bigint;
15
- authorization_token?: AuthorizationToken;
15
+ authorization_token?: readonly AuthorizationToken[];
16
16
  max_auth_token_cache_size?: bigint;
17
17
  unknown?: UnknownParam[];
18
18
  }
19
19
  interface Draft13Params {
20
20
  delivery_timeout?: bigint;
21
- authorization_token?: AuthorizationToken;
21
+ authorization_token?: readonly AuthorizationToken[];
22
22
  max_cache_duration?: bigint;
23
23
  unknown?: UnknownParam[];
24
24
  }
@@ -11,7 +11,7 @@ interface AuthorizationToken {
11
11
  }
12
12
  interface Draft18SetupOptions {
13
13
  path?: string;
14
- authorization_token?: AuthorizationToken;
14
+ authorization_token?: readonly AuthorizationToken[];
15
15
  max_auth_token_cache_size?: bigint;
16
16
  authority?: string;
17
17
  moqt_implementation?: string;
@@ -29,7 +29,7 @@ interface LargestObject {
29
29
  }
30
30
  interface Draft18Params {
31
31
  object_delivery_timeout?: bigint;
32
- authorization_token?: AuthorizationToken;
32
+ authorization_token?: readonly AuthorizationToken[];
33
33
  rendezvous_timeout?: bigint;
34
34
  subgroup_delivery_timeout?: bigint;
35
35
  expires?: bigint;
@@ -234,10 +234,18 @@ interface FetchStream {
234
234
  type Draft18DataStream = SubgroupStream | DatagramObject | FetchStream;
235
235
  interface SubgroupStreamHeader {
236
236
  readonly type: 'subgroup_header';
237
+ /**
238
+ * The stream Type Flags, the same value `SubgroupStream.headerType` carries.
239
+ * It is reported so the incremental decoder does not drop the flags the
240
+ * header encodes, which is what lets a consumer tell the modes apart.
241
+ */
242
+ readonly headerType: number;
237
243
  readonly trackAlias: bigint;
238
244
  readonly groupId: bigint;
239
245
  readonly subgroupId: bigint;
240
246
  readonly publisherPriority: number;
247
+ readonly endOfGroup?: boolean;
248
+ readonly firstObject?: boolean;
241
249
  }
242
250
  interface FetchStreamHeader {
243
251
  readonly type: 'fetch_header';
@@ -11,7 +11,7 @@ interface AuthorizationToken {
11
11
  }
12
12
  interface Draft18SetupOptions {
13
13
  path?: string;
14
- authorization_token?: AuthorizationToken;
14
+ authorization_token?: readonly AuthorizationToken[];
15
15
  max_auth_token_cache_size?: bigint;
16
16
  authority?: string;
17
17
  moqt_implementation?: string;
@@ -29,7 +29,7 @@ interface LargestObject {
29
29
  }
30
30
  interface Draft18Params {
31
31
  object_delivery_timeout?: bigint;
32
- authorization_token?: AuthorizationToken;
32
+ authorization_token?: readonly AuthorizationToken[];
33
33
  rendezvous_timeout?: bigint;
34
34
  subgroup_delivery_timeout?: bigint;
35
35
  expires?: bigint;
@@ -234,10 +234,18 @@ interface FetchStream {
234
234
  type Draft18DataStream = SubgroupStream | DatagramObject | FetchStream;
235
235
  interface SubgroupStreamHeader {
236
236
  readonly type: 'subgroup_header';
237
+ /**
238
+ * The stream Type Flags, the same value `SubgroupStream.headerType` carries.
239
+ * It is reported so the incremental decoder does not drop the flags the
240
+ * header encodes, which is what lets a consumer tell the modes apart.
241
+ */
242
+ readonly headerType: number;
237
243
  readonly trackAlias: bigint;
238
244
  readonly groupId: bigint;
239
245
  readonly subgroupId: bigint;
240
246
  readonly publisherPriority: number;
247
+ readonly endOfGroup?: boolean;
248
+ readonly firstObject?: boolean;
241
249
  }
242
250
  interface FetchStreamHeader {
243
251
  readonly type: 'fetch_header';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@moqtap/codec",
3
- "version": "0.9.0",
3
+ "version": "0.11.0",
4
4
  "description": "MoQT wire-format codec and session state machine — multi-draft, zero dependencies",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -221,9 +221,9 @@
221
221
  "test": "vitest run"
222
222
  },
223
223
  "devDependencies": {
224
- "@moqtap/test-vectors": "^0.13.0",
224
+ "@moqtap/test-vectors": "^0.16.0",
225
225
  "tsup": "^8.0.0",
226
226
  "typescript": "^5.5.0",
227
- "vitest": "^3.0.0"
227
+ "vitest": "^3.2.7"
228
228
  }
229
229
  }
@@ -0,0 +1,192 @@
1
+ /**
2
+ * Overwriting Authorization Token values at the point of parse.
3
+ *
4
+ * A collector that ships a customer's control plane verbatim is useful — the
5
+ * control plane is the part of a session a player library cannot misreport —
6
+ * right up until it also ships the bearer token sitting in a SETUP option or a
7
+ * SUBSCRIBE parameter. At that point a debugging tool has become a
8
+ * credential-exfiltration path.
9
+ *
10
+ * The fix has to happen **where the parse happens**, not on the way out. Bytes
11
+ * that were merely *masked before upload* still sat in memory in a form a later
12
+ * feature — a dump, an export, a bug — could reach. So this module hangs off
13
+ * the decoders themselves: the one pass that reads a Token Value is the pass
14
+ * that records where it was, and the value is overwritten before the frame is
15
+ * handed to anything that retains it.
16
+ *
17
+ * ── What is overwritten, and what deliberately is not
18
+ *
19
+ * Only the **Token Value** (draft-20 Section 10.2.2, Figure 5). The Alias Type,
20
+ * the Token Alias and the Token Type all stay:
21
+ *
22
+ * - the parameter's *presence* distinguishes a session that failed to
23
+ * authenticate from one that never tried, and losing that distinction blinds
24
+ * the tool at exactly the moment it is most wanted;
25
+ * - the Token Alias is how you see the same credential being reused across
26
+ * messages, which is a real debugging signal and is not itself a secret;
27
+ * - `USE_ALIAS` and `DELETE` carry no value at all, so those frames pass
28
+ * through untouched and it is visible that they did.
29
+ *
30
+ * The overwrite is **length-preserving**. That is not an aesthetic choice: a
31
+ * control frame carries a fixed 16-bit Message Length, and every offset a
32
+ * caller has already computed into the frame stays valid only if the frame does
33
+ * not change size. Preserving the length also preserves the fact that a token
34
+ * of *some* size was sent.
35
+ *
36
+ * ── Why a span sink and not a return value
37
+ *
38
+ * A Token Value is read in `decodeParams` and `decodeSetupOptions`, which sit
39
+ * under a dozen per-message payload decoders per draft. Threading a redaction
40
+ * channel out through all of them would mean changing every one of those
41
+ * signatures, in every draft, to carry something almost none of them use.
42
+ *
43
+ * The sink is module state, which is safe here for one specific reason and it
44
+ * is worth being explicit about it: **decoding is synchronous and single
45
+ * threaded, and no decoder re-enters the redactor.** {@link redactWith} opens
46
+ * the capture, runs one decode to completion, and closes it in a `finally`.
47
+ * There is no `await` between those points, so no second capture can interleave
48
+ * with the first.
49
+ *
50
+ * Spec of record: `wt-logging-1-collector.md` Section 1.6.
51
+ */
52
+
53
+ /**
54
+ * The byte written over a redacted Token Value.
55
+ *
56
+ * Zero, so that a redacted frame is obviously not a token rather than
57
+ * plausibly one. A caller who needs to tell "redacted" from "the peer really
58
+ * sent zeros" has {@link AuthRedaction.redacted}, which counts what was
59
+ * overwritten.
60
+ */
61
+ export const REDACTION_FILL = 0x00
62
+
63
+ /**
64
+ * The result of a redaction pass over one control frame.
65
+ */
66
+ export interface AuthRedaction {
67
+ /**
68
+ * The frame with every Token Value overwritten, exactly as long as the input.
69
+ *
70
+ * When nothing needed redacting this is the **same reference** as the input,
71
+ * so the common case costs no copy. Callers that retain it must copy for the
72
+ * same reason they would have had to copy the input.
73
+ */
74
+ readonly bytes: Uint8Array
75
+ /** How many Token Values were overwritten. */
76
+ readonly redacted: number
77
+ /**
78
+ * A span was recorded that could not be applied to the frame.
79
+ *
80
+ * This means the offset arithmetic and the frame disagree, which is a defect
81
+ * rather than a wire condition. **A caller must not treat {@link bytes} as
82
+ * clean when this is set** — the safe response is to drop the frame's raw
83
+ * bytes rather than ship them, because the one thing that is certain is that
84
+ * a token was seen and its position is not trusted.
85
+ */
86
+ readonly incomplete: boolean
87
+ /**
88
+ * Whether the message parsed all the way through.
89
+ *
90
+ * A frame can be perfectly legitimate and still not decode: an unknown or
91
+ * extension message codepoint is something a peer is allowed to send, and a
92
+ * collector ships those raw on purpose rather than losing the whole control
93
+ * plane over one of them. But a message that cannot be parsed is a message
94
+ * whose parameters cannot be walked, so `redacted === 0` on such a frame
95
+ * means "nothing was found", not "there is nothing there".
96
+ *
97
+ * That residual is narrow and it is real, and the only dishonest thing to do
98
+ * with it is hide it. Count the frames where this is false, so the gap in the
99
+ * guarantee is a number somebody can look at.
100
+ */
101
+ readonly decoded: boolean
102
+ }
103
+
104
+ /**
105
+ * Payload-relative `[start, length]` pairs, flat. `null` when not capturing —
106
+ * which is the state every ordinary decode runs in, so the recording hook costs
107
+ * one null check on a path that is otherwise untouched.
108
+ */
109
+ let spans: number[] | null = null
110
+
111
+ /**
112
+ * Record that a Token Value occupies `length` bytes at `start`, measured from
113
+ * the beginning of the **payload** the current decoder is reading.
114
+ *
115
+ * Called from the draft decoders. A zero-length value records nothing: there is
116
+ * nothing to overwrite, and a zero-length span would only inflate the count.
117
+ */
118
+ export function recordAuthValueSpan(start: number, length: number): void {
119
+ if (spans === null || length <= 0) return
120
+ spans.push(start, length)
121
+ }
122
+
123
+ /**
124
+ * Run `decode` with span capture suspended.
125
+ *
126
+ * For decoders that read a parameter block out of a **nested** buffer — draft-20's
127
+ * `FILL_PARAMETERS` is the case that exists today. Offsets recorded inside a
128
+ * nested reader are relative to that reader, and applying them to the outer
129
+ * payload would overwrite unrelated bytes: not a failed redaction but a
130
+ * corrupted frame, and a silent one. Scope rules already forbid an
131
+ * AUTHORIZATION_TOKEN inside FILL_PARAMETERS, so this guards against a future
132
+ * nesting rather than a present one — which is exactly when it is cheap to add.
133
+ */
134
+ export function withoutAuthValueSpans<T>(decode: () => T): T {
135
+ const saved = spans
136
+ spans = null
137
+ try {
138
+ return decode()
139
+ } finally {
140
+ spans = saved
141
+ }
142
+ }
143
+
144
+ /**
145
+ * Decode `frame` once, capturing Token Value spans, and return the frame with
146
+ * those values overwritten.
147
+ *
148
+ * `payloadStart` is where the message payload begins inside the frame; the
149
+ * spans the decoders record are payload-relative, and this is what makes them
150
+ * frame-relative. `decode` may fail — a malformed message decodes partially and
151
+ * throws or returns an error — and **spans recorded before it failed are still
152
+ * applied**, because a value that was read is a value that was exposed
153
+ * regardless of what happened afterwards.
154
+ *
155
+ * `decode` reports whether it parsed the whole message; a throw counts as no.
156
+ */
157
+ export function redactWith(
158
+ frame: Uint8Array,
159
+ payloadStart: number,
160
+ decode: () => boolean,
161
+ ): AuthRedaction {
162
+ const outer = spans
163
+ spans = []
164
+ let captured: number[]
165
+ let decoded = false
166
+ try {
167
+ decoded = decode()
168
+ } catch {
169
+ // The caller's decoder threw. Whatever it recorded before it did is real.
170
+ } finally {
171
+ captured = spans
172
+ spans = outer
173
+ }
174
+
175
+ if (captured.length === 0) return { bytes: frame, redacted: 0, incomplete: false, decoded }
176
+
177
+ let out: Uint8Array | null = null
178
+ let redacted = 0
179
+ let incomplete = false
180
+ for (let i = 0; i < captured.length; i += 2) {
181
+ const start = payloadStart + (captured[i] as number)
182
+ const length = captured[i + 1] as number
183
+ if (payloadStart < 0 || start < 0 || start + length > frame.length) {
184
+ incomplete = true
185
+ continue
186
+ }
187
+ if (out === null) out = frame.slice()
188
+ out.fill(REDACTION_FILL, start, start + length)
189
+ redacted++
190
+ }
191
+ return { bytes: out ?? frame, redacted, incomplete, decoded }
192
+ }