@moqtap/codec 0.10.0 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (213) hide show
  1. package/CHANGELOG.md +147 -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-RYKQXBG6.cjs → chunk-27K5BUAG.cjs} +481 -517
  5. package/dist/{chunk-WCPENYNE.js → chunk-3RNQMGKA.js} +359 -390
  6. package/dist/{chunk-TSUZ6GJV.js → chunk-5AWIXOLB.js} +438 -469
  7. package/dist/{chunk-4XLYCT5Q.cjs → chunk-5IMHJIAZ.cjs} +52 -2
  8. package/dist/{chunk-KTNERCTZ.cjs → chunk-5JGZCKJO.cjs} +488 -518
  9. package/dist/{chunk-WCTMPDUX.cjs → chunk-73K4OSAN.cjs} +401 -432
  10. package/dist/{chunk-N2V7Z37J.js → chunk-7VQKRGRD.js} +19 -3
  11. package/dist/{chunk-BIBMDTU5.cjs → chunk-A3UCQOIB.cjs} +486 -517
  12. package/dist/{chunk-K2B3OVFK.js → chunk-A7PDMVXM.js} +24 -3
  13. package/dist/{chunk-VZHL2U2N.cjs → chunk-A7VQO6YC.cjs} +54 -38
  14. package/dist/{chunk-AQ445VV7.cjs → chunk-ACQHZLRZ.cjs} +66 -46
  15. package/dist/{chunk-L5DRACXS.js → chunk-BBICOMW6.js} +25 -3
  16. package/dist/{chunk-T4VWPKDG.cjs → chunk-BNIUVOCJ.cjs} +529 -599
  17. package/dist/{chunk-UKKDOOUO.cjs → chunk-CNC6ANS4.cjs} +58 -37
  18. package/dist/{chunk-OZRK73NQ.js → chunk-FDLQSWHK.js} +433 -469
  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-XCRCAUGI.cjs → chunk-HM7BLRVP.cjs} +291 -297
  22. package/dist/{chunk-XHAP2YST.js → chunk-HZONHFNO.js} +19 -3
  23. package/dist/{chunk-SDJTSMOW.cjs → chunk-ILYABWDK.cjs} +60 -38
  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-OUNN4IQB.cjs → chunk-KTY4LAUV.cjs} +482 -497
  27. package/dist/{chunk-RZTLQAKF.js → chunk-OJNLJT5D.js} +0 -1
  28. package/dist/{chunk-FT3HDNIB.js → chunk-PJK2ZS3I.js} +467 -537
  29. package/dist/{chunk-G53WYUXL.js → chunk-PSMZKHOC.js} +441 -456
  30. package/dist/{chunk-7RE6KSIY.cjs → chunk-Q5JQGHWY.cjs} +0 -1
  31. package/dist/{chunk-BX2N7TZM.js → chunk-SQTUQY5E.js} +31 -11
  32. package/dist/{chunk-CF5DDD3Q.js → chunk-WCRLAKDW.js} +239 -245
  33. package/dist/{chunk-KYVTM5VI.js → chunk-WL2YUEXH.js} +19 -3
  34. package/dist/{chunk-KGDVC4O6.js → chunk-YCNIVZS7.js} +439 -469
  35. package/dist/{chunk-KLPWJU6W.js → chunk-YRZQVNZO.js} +50 -0
  36. package/dist/{codec-CFWu5KVT.d.cts → codec-76xzrLTL.d.cts} +21 -2
  37. package/dist/{codec-gl4_QEva.d.ts → codec-8p40WdLg.d.ts} +20 -1
  38. package/dist/{codec-Dl_QIXMz.d.ts → codec-BN2Bu0KI.d.ts} +20 -1
  39. package/dist/{codec-Bux_Q40X.d.ts → codec-Bb6GKTrv.d.ts} +21 -2
  40. package/dist/{codec-EvybrBuY.d.cts → codec-BgpfHoAd.d.cts} +20 -1
  41. package/dist/{codec-alVA27Uc.d.ts → codec-BkheTXO7.d.ts} +20 -1
  42. package/dist/{codec-Czejcmxr.d.cts → codec-BwVDkokh.d.cts} +21 -2
  43. package/dist/{codec-BrTi4K7r.d.cts → codec-C5s1eBJX.d.cts} +21 -2
  44. package/dist/codec-CM5yd6n3.d.ts +38 -0
  45. package/dist/{codec-CWnf8mn_.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-f7vxeVIS.d.cts → codec-DELe00w_.d.cts} +21 -2
  50. package/dist/{codec-DNmiG2e0.d.cts → codec-DHzKAUCa.d.cts} +20 -1
  51. package/dist/{codec--CVeqGQv.d.ts → codec-DdVBtvx7.d.ts} +20 -1
  52. package/dist/{codec-CBdOIfMY.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-guzqtfMk.d.cts → codec-GAY4lybi.d.cts} +20 -1
  55. package/dist/{codec-Cfo_z5ET.d.cts → codec-I8u2pfS4.d.cts} +20 -1
  56. package/dist/{codec-BxQTybUX.d.cts → codec-XLrnreeu.d.cts} +21 -2
  57. package/dist/{codec-DOmAmFkI.d.ts → codec-c0YEwwWn.d.ts} +20 -1
  58. package/dist/{codec-DaXjRrOV.d.ts → codec-ejDu-va6.d.ts} +21 -2
  59. package/dist/{codec-C3mdsGx3.d.ts → codec-kaBUzdpV.d.ts} +21 -2
  60. package/dist/{codec-CwZ6OCPP.d.ts → codec-mVYqkIUF.d.ts} +21 -2
  61. package/dist/{codec-08ZOr5wI.d.ts → codec-qSbO5nOa.d.ts} +21 -2
  62. package/dist/{codec-Cm3D261p.d.ts → codec-yYKGOipj.d.ts} +20 -1
  63. package/dist/{codec-Bd60SGKH.d.cts → codec-zfzg9uiy.d.cts} +20 -1
  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.cjs +104 -3
  81. package/dist/draft11.d.cts +98 -2
  82. package/dist/draft11.d.ts +98 -2
  83. package/dist/draft11.js +105 -4
  84. package/dist/draft12.cjs +113 -3
  85. package/dist/draft12.d.cts +107 -2
  86. package/dist/draft12.d.ts +107 -2
  87. package/dist/draft12.js +114 -4
  88. package/dist/draft13.cjs +105 -3
  89. package/dist/draft13.d.cts +99 -2
  90. package/dist/draft13.d.ts +99 -2
  91. package/dist/draft13.js +106 -4
  92. package/dist/draft14.cjs +107 -3
  93. package/dist/draft14.d.cts +101 -28
  94. package/dist/draft14.d.ts +101 -28
  95. package/dist/draft14.js +108 -4
  96. package/dist/draft15-session.d.cts +1 -1
  97. package/dist/draft15-session.d.ts +1 -1
  98. package/dist/draft15.cjs +69 -3
  99. package/dist/draft15.d.cts +65 -22
  100. package/dist/draft15.d.ts +65 -22
  101. package/dist/draft15.js +70 -4
  102. package/dist/draft16-session.cjs +2 -2
  103. package/dist/draft16-session.d.cts +1 -1
  104. package/dist/draft16-session.d.ts +1 -1
  105. package/dist/draft16-session.js +1 -1
  106. package/dist/draft16.cjs +76 -8
  107. package/dist/draft16.d.cts +67 -13
  108. package/dist/draft16.d.ts +67 -13
  109. package/dist/draft16.js +73 -5
  110. package/dist/draft17-session.d.cts +1 -1
  111. package/dist/draft17-session.d.ts +1 -1
  112. package/dist/draft17.cjs +77 -3
  113. package/dist/draft17.d.cts +73 -4
  114. package/dist/draft17.d.ts +73 -4
  115. package/dist/draft17.js +78 -4
  116. package/dist/draft18-session.d.cts +1 -1
  117. package/dist/draft18-session.d.ts +1 -1
  118. package/dist/draft18.cjs +8 -3
  119. package/dist/draft18.d.cts +4 -3
  120. package/dist/draft18.d.ts +4 -3
  121. package/dist/draft18.js +9 -4
  122. package/dist/draft19-session.d.cts +1 -1
  123. package/dist/draft19-session.d.ts +1 -1
  124. package/dist/draft19.cjs +11 -4
  125. package/dist/draft19.d.cts +4 -3
  126. package/dist/draft19.d.ts +4 -3
  127. package/dist/draft19.js +12 -5
  128. package/dist/draft20-session.d.cts +1 -1
  129. package/dist/draft20-session.d.ts +1 -1
  130. package/dist/draft20.cjs +8 -3
  131. package/dist/draft20.d.cts +4 -3
  132. package/dist/draft20.d.ts +4 -3
  133. package/dist/draft20.js +9 -4
  134. package/dist/index.cjs +30 -30
  135. package/dist/index.d.cts +21 -20
  136. package/dist/index.d.ts +21 -20
  137. package/dist/index.js +15 -15
  138. package/dist/session.cjs +2 -2
  139. package/dist/session.d.cts +6 -6
  140. package/dist/session.d.ts +6 -6
  141. package/dist/session.js +1 -1
  142. package/dist/{types-C1rxh-id.d.cts → types-Btp416jt.d.cts} +8 -0
  143. package/dist/{types-C1rxh-id.d.ts → types-Btp416jt.d.ts} +8 -0
  144. package/dist/{types-CZTzbIzQ.d.cts → types-BxTL1NXw.d.cts} +7 -0
  145. package/dist/{types-CZTzbIzQ.d.ts → types-BxTL1NXw.d.ts} +7 -0
  146. package/dist/{types-pShrs3fN.d.cts → types-CuibHYcf.d.cts} +7 -0
  147. package/dist/{types-pShrs3fN.d.ts → types-CuibHYcf.d.ts} +7 -0
  148. package/dist/{types-CY-QWxd-.d.cts → types-CwN7AEoL.d.cts} +13 -1
  149. package/dist/{types-CY-QWxd-.d.ts → types-CwN7AEoL.d.ts} +13 -1
  150. package/dist/{types-D4bmW8rY.d.cts → types-DAnalt5K.d.cts} +7 -0
  151. package/dist/{types-D4bmW8rY.d.ts → types-DAnalt5K.d.ts} +7 -0
  152. package/dist/{types-Bg86GGVZ.d.cts → types-DxXNP32l.d.cts} +8 -0
  153. package/dist/{types-Bg86GGVZ.d.ts → types-DxXNP32l.d.ts} +8 -0
  154. package/package.json +3 -3
  155. package/src/core/auth-redaction.ts +192 -0
  156. package/src/drafts/draft07/codec.ts +40 -0
  157. package/src/drafts/draft07/error-codes.ts +44 -0
  158. package/src/drafts/draft07/index.ts +15 -0
  159. package/src/drafts/draft08/codec.ts +40 -0
  160. package/src/drafts/draft08/error-codes.ts +76 -0
  161. package/src/drafts/draft08/index.ts +21 -0
  162. package/src/drafts/draft09/codec.ts +40 -0
  163. package/src/drafts/draft09/error-codes.ts +76 -0
  164. package/src/drafts/draft09/index.ts +21 -0
  165. package/src/drafts/draft10/codec.ts +40 -0
  166. package/src/drafts/draft10/error-codes.ts +76 -0
  167. package/src/drafts/draft10/index.ts +21 -0
  168. package/src/drafts/draft11/codec.ts +60 -0
  169. package/src/drafts/draft11/error-codes.ts +106 -0
  170. package/src/drafts/draft11/index.ts +23 -0
  171. package/src/drafts/draft12/codec.ts +61 -0
  172. package/src/drafts/draft12/error-codes.ts +116 -0
  173. package/src/drafts/draft12/index.ts +25 -0
  174. package/src/drafts/draft13/codec.ts +69 -11
  175. package/src/drafts/draft13/error-codes.ts +107 -0
  176. package/src/drafts/draft13/index.ts +23 -0
  177. package/src/drafts/draft13/types.ts +1 -1
  178. package/src/drafts/draft14/codec.ts +65 -4
  179. package/src/drafts/draft14/data-streams.ts +331 -259
  180. package/src/drafts/draft14/error-codes.ts +109 -0
  181. package/src/drafts/draft14/index.ts +23 -0
  182. package/src/drafts/draft15/codec.ts +65 -8
  183. package/src/drafts/draft15/data-streams.ts +489 -444
  184. package/src/drafts/draft15/error-codes.ts +66 -0
  185. package/src/drafts/draft15/index.ts +15 -0
  186. package/src/drafts/draft15/types.ts +7 -0
  187. package/src/drafts/draft16/codec.ts +146 -52
  188. package/src/drafts/draft16/data-streams.ts +513 -442
  189. package/src/drafts/draft16/error-codes.ts +68 -0
  190. package/src/drafts/draft16/index.ts +15 -0
  191. package/src/drafts/draft16/messages.ts +4 -4
  192. package/src/drafts/draft16/session-fsm.ts +0 -1
  193. package/src/drafts/draft16/types.ts +22 -8
  194. package/src/drafts/draft17/codec.ts +73 -12
  195. package/src/drafts/draft17/data-streams.ts +567 -488
  196. package/src/drafts/draft17/index.ts +15 -0
  197. package/src/drafts/draft17/types.ts +7 -0
  198. package/src/drafts/draft18/codec.ts +66 -9
  199. package/src/drafts/draft18/data-streams.ts +570 -482
  200. package/src/drafts/draft18/index.ts +3 -0
  201. package/src/drafts/draft18/types.ts +16 -8
  202. package/src/drafts/draft19/codec.ts +70 -10
  203. package/src/drafts/draft19/data-streams.ts +570 -482
  204. package/src/drafts/draft19/error-codes.ts +3 -1
  205. package/src/drafts/draft19/index.ts +3 -0
  206. package/src/drafts/draft19/messages.ts +3 -1
  207. package/src/drafts/draft19/types.ts +22 -11
  208. package/src/drafts/draft20/codec.ts +90 -23
  209. package/src/drafts/draft20/data-streams.ts +610 -563
  210. package/src/drafts/draft20/index.ts +3 -0
  211. package/src/drafts/draft20/types.ts +14 -2
  212. package/dist/codec-BJ7BHuiZ.d.ts +0 -18
  213. package/dist/codec-C6Mx4bwz.d.cts +0 -18
@@ -36,7 +36,9 @@ export const RequestErrorCode = {
36
36
  DoesNotExist: 0x10n,
37
37
  InvalidRange: 0x11n,
38
38
  MalformedTrack: 0x12n,
39
- // DuplicateSubscription (0x19) removed in draft-19 multiple concurrent subscriptions per Track are now allowed
39
+ // 0x19 is unassigned in draft-19: Section 5.1 lets an endpoint hold multiple concurrent
40
+ // subscriptions to the same Track, so there is no DuplicateSubscription error. Draft-18
41
+ // binds 0x19 to DUPLICATE_SUBSCRIPTION.
40
42
  Uninterested: 0x20n,
41
43
  PrefixOverlap: 0x30n,
42
44
  NamespaceTooLarge: 0x31n,
@@ -2,6 +2,8 @@
2
2
 
3
3
  export const DRAFT_VERSION = 0xff000013n
4
4
 
5
+ export type { AuthRedaction } from '../../core/auth-redaction.js'
6
+ export { REDACTION_FILL } from '../../core/auth-redaction.js'
5
7
  export type { Draft19Codec } from './codec.js'
6
8
  export {
7
9
  createDataStreamDecoder,
@@ -18,6 +20,7 @@ export {
18
20
  encodeFetchStream,
19
21
  encodeMessage,
20
22
  encodeSubgroupStream,
23
+ redactAuthTokens,
21
24
  } from './codec.js'
22
25
  export type {
23
26
  DataStreamResetCodeValue,
@@ -15,7 +15,9 @@ export const MSG_GOAWAY = 0x10n
15
15
  export const MSG_FETCH = 0x16n
16
16
  export const MSG_FETCH_OK = 0x18n
17
17
  export const MSG_PUBLISH = 0x1dn
18
- // In draft-18 PUBLISH_OK is an alias for REQUEST_OK (0x07). Kept as alias.
18
+ // PUBLISH_OK is not a codepoint of its own: it is a REQUEST_OK (0x07) sent in
19
+ // reply to a PUBLISH (draft-19 Section 10.5). 0x1E is RESERVED (Section 10,
20
+ // Table 5).
19
21
  export const MSG_PUBLISH_OK = MSG_REQUEST_OK
20
22
  export const MSG_SUBSCRIBE_NAMESPACE = 0x50n
21
23
  export const MSG_SUBSCRIBE_TRACKS = 0x51n
@@ -27,7 +27,7 @@ export interface Draft19SetupOptions {
27
27
  unknown?: UnknownParam[]
28
28
  }
29
29
 
30
- // Location filter parameter (renamed from SubscriptionFilter in draft-19)
30
+ // Location Filter parameter, 0x21; drafts 15 through 18 name that parameter SUBSCRIPTION_FILTER
31
31
  export interface LocationFilter {
32
32
  readonly filter_type: bigint
33
33
  readonly start_group?: bigint
@@ -57,16 +57,16 @@ export interface LargestObject {
57
57
 
58
58
  // Version-specific parameters (delta-encoded types, count-prefixed)
59
59
  export interface Draft19Params {
60
- object_delivery_timeout?: bigint // 0x02 varint (renamed from delivery_timeout in draft-17)
60
+ object_delivery_timeout?: bigint // 0x02 varint; drafts 11-17 name this parameter DELIVERY TIMEOUT
61
61
  authorization_token?: readonly AuthorizationToken[] // 0x03 length-prefixed nested
62
62
  rendezvous_timeout?: bigint // 0x04 varint
63
63
  subgroup_delivery_timeout?: bigint // 0x06 varint (NEW in draft-18)
64
64
  expires?: bigint // 0x08 varint
65
65
  largest_object?: LargestObject // 0x09 Location (2 bare varints)
66
66
  fill_timeout?: bigint // 0x0a varint (NEW in draft-18)
67
- forward?: bigint // 0x10 uint8 (was varint in draft-17)
67
+ forward?: bigint // 0x10 uint8; drafts 15 and 16 encode this parameter as a varint
68
68
  subscriber_priority?: bigint // 0x20 uint8
69
- location_filter?: LocationFilter // 0x21 length-prefixed (renamed from subscription_filter in draft-19)
69
+ location_filter?: LocationFilter // 0x21 length-prefixed; SUBSCRIPTION_FILTER on drafts 15-18
70
70
  group_order?: bigint // 0x22 uint8
71
71
  // Section 5.1.3 permits each of the five more than once in a message: a
72
72
  // filter parameter carries one SetID, so two alternatives over the same
@@ -83,7 +83,7 @@ export interface Draft19Params {
83
83
 
84
84
  // Track properties (KVP encoding, no count prefix, read until end of payload)
85
85
  export interface Draft19TrackProperties {
86
- object_delivery_timeout?: bigint // 0x02 even varint (renamed from delivery_timeout)
86
+ object_delivery_timeout?: bigint // 0x02 even varint; drafts 11-17 name this parameter DELIVERY TIMEOUT
87
87
  max_cache_duration?: bigint // 0x04 even varint
88
88
  subgroup_delivery_timeout?: bigint // 0x06 even varint (NEW in draft-18)
89
89
  immutable_properties?: Uint8Array // 0x0b odd length-prefixed
@@ -125,7 +125,8 @@ export interface Draft19Setup extends Draft19BaseMessage {
125
125
  readonly options: Draft19SetupOptions
126
126
  }
127
127
 
128
- // Subscribe — Required Request ID Delta REMOVED in draft-18
128
+ // SUBSCRIBEtype 0x3; draft-17 is the only draft that carries a Required Request ID Delta
129
+ // after the request_id, there and on every other request message (draft-17 Section 9.2)
129
130
  export interface Draft19Subscribe extends Draft19BaseMessage {
130
131
  readonly type: 'subscribe'
131
132
  readonly request_id: bigint
@@ -183,7 +184,7 @@ export interface Draft19NamespaceDone extends Draft19BaseMessage {
183
184
  readonly namespace_suffix: string[]
184
185
  }
185
186
 
186
- // SUBSCRIBE_NAMESPACE — type 0x50, subscribe_options field removed in draft-18
187
+ // SUBSCRIBE_NAMESPACE — type 0x50; only drafts 16 and 17 carry a subscribe_options field here
187
188
  export interface Draft19SubscribeNamespace extends Draft19BaseMessage {
188
189
  readonly type: 'subscribe_namespace'
189
190
  readonly request_id: bigint
@@ -191,7 +192,7 @@ export interface Draft19SubscribeNamespace extends Draft19BaseMessage {
191
192
  readonly parameters: Draft19Params
192
193
  }
193
194
 
194
- // SUBSCRIBE_TRACKS — NEW in draft-18, type 0x51
195
+ // SUBSCRIBE_TRACKS — type 0x51; no draft before 18 carries this message
195
196
  export interface Draft19SubscribeTracks extends Draft19BaseMessage {
196
197
  readonly type: 'subscribe_tracks'
197
198
  readonly request_id: bigint
@@ -238,7 +239,8 @@ export interface Draft19FetchOk extends Draft19BaseMessage {
238
239
  readonly track_properties: Draft19TrackProperties
239
240
  }
240
241
 
241
- // Track Status — same format as subscribe in draft-18 (without required_request_id_delta)
242
+ // Track Status — format identical to SUBSCRIBE (Section 10.7), minus the subscriber
243
+ // parameters related to Track delivery (e.g. SUBSCRIBER_PRIORITY, Section 10.2.7).
242
244
  export interface Draft19TrackStatus extends Draft19BaseMessage {
243
245
  readonly type: 'track_status'
244
246
  readonly request_id: bigint
@@ -247,7 +249,7 @@ export interface Draft19TrackStatus extends Draft19BaseMessage {
247
249
  readonly parameters: Draft19Params
248
250
  }
249
251
 
250
- // REQUEST_OK — gained trailing Track Properties in draft-18
252
+ // REQUEST_OK — carries trailing Track Properties after the parameters (Section 10.5); drafts 15-17 have no such field
251
253
  export interface Draft19RequestOk extends Draft19BaseMessage {
252
254
  readonly type: 'request_ok'
253
255
  readonly parameters: Draft19Params
@@ -274,7 +276,8 @@ export interface Draft19GoAway extends Draft19BaseMessage {
274
276
  readonly type: 'goaway'
275
277
  readonly new_session_uri: string
276
278
  readonly timeout: bigint
277
- // Request ID removed from GOAWAY in draft-19 control and request streams share one format
279
+ // Draft-18 is the only draft that puts a Request ID on GOAWAY, and carries it only when the
280
+ // message goes on the control stream; on every other draft the message has no such field
278
281
  }
279
282
 
280
283
  // Union of all draft-18 control messages
@@ -356,10 +359,18 @@ export type Draft19DataStream = SubgroupStream | DatagramObject | FetchStream
356
359
  // Streaming data stream decoder types
357
360
  export interface SubgroupStreamHeader {
358
361
  readonly type: 'subgroup_header'
362
+ /**
363
+ * The stream Type Flags, the same value `SubgroupStream.headerType` carries.
364
+ * Without it the incremental decoder drops every flag the header encodes
365
+ * and a consumer cannot tell the modes apart.
366
+ */
367
+ readonly headerType: number
359
368
  readonly trackAlias: bigint
360
369
  readonly groupId: bigint
361
370
  readonly subgroupId: bigint
362
371
  readonly publisherPriority: number
372
+ readonly endOfGroup?: boolean
373
+ readonly firstObject?: boolean
363
374
  }
364
375
 
365
376
  export interface FetchStreamHeader {
@@ -1,3 +1,9 @@
1
+ import {
2
+ type AuthRedaction,
3
+ recordAuthValueSpan,
4
+ redactWith,
5
+ withoutAuthValueSpans,
6
+ } from '../../core/auth-redaction.js'
1
7
  import { MoqtBufferReader as BufferReader } from '../../core/buffer-reader.js'
2
8
  import { MoqtBufferWriter as BufferWriter } from '../../core/buffer-writer.js'
3
9
  import { bytesToHex, hexToBytes } from '../../core/hex.js'
@@ -216,10 +222,9 @@ function decodeSetupOptions(reader: BufferReader, payloadEnd: number): Draft20Se
216
222
  if (optType === SETUP_OPT_PATH) {
217
223
  result.path = textDecoder.decode(bytes)
218
224
  } else if (optType === SETUP_OPT_AUTHORIZATION_TOKEN) {
219
- result.authorization_token = [
220
- ...(result.authorization_token ?? []),
221
- decodeAuthorizationToken(new BufferReader(bytes)),
222
- ]
225
+ const token = decodeAuthorizationToken(new BufferReader(bytes))
226
+ noteAuthTokenValue(reader.offset - length, length, token)
227
+ result.authorization_token = [...(result.authorization_token ?? []), token]
223
228
  } else if (optType === SETUP_OPT_AUTHORITY) {
224
229
  result.authority = textDecoder.decode(bytes)
225
230
  } else if (optType === SETUP_OPT_MOQT_IMPLEMENTATION) {
@@ -257,6 +262,32 @@ function encodeAuthorizationToken(token: AuthorizationToken, w: BufferWriter): v
257
262
  }
258
263
  }
259
264
 
265
+ /**
266
+ * Record where a Token Value sits, so it can be overwritten before the frame
267
+ * reaches anything that keeps it (Section 1.6).
268
+ *
269
+ * The span falls out of the decode with no second walk. The Token Value is the
270
+ * tail of the Token structure — draft-20 Section 10.2.2, Figure 5: it is NOT
271
+ * length-prefixed inside the Token and consumes the remainder of the outer
272
+ * length-prefixed parameter value. So its start is the parameter value's end
273
+ * minus the value's own length, and the fields before it (Alias Type, Token
274
+ * Alias, Token Type) are left alone deliberately: they are structure, not
275
+ * secret, and they are what distinguishes a session that failed to
276
+ * authenticate from one that never tried.
277
+ *
278
+ * DELETE (0x0) and USE_ALIAS (0x2) carry no value at all, so they record
279
+ * nothing and their frames pass through untouched.
280
+ */
281
+ function noteAuthTokenValue(
282
+ valueStart: number,
283
+ valueLength: number,
284
+ token: AuthorizationToken,
285
+ ): void {
286
+ const value = token.token_value
287
+ if (value === undefined || value.byteLength === 0) return
288
+ recordAuthValueSpan(valueStart + valueLength - value.byteLength, value.byteLength)
289
+ }
290
+
260
291
  function decodeAuthorizationToken(r: BufferReader): AuthorizationToken {
261
292
  const alias_type = r.readVarInt()
262
293
  const aliasType = Number(alias_type)
@@ -395,7 +426,7 @@ function decodeRangeFilter(reader: BufferReader, hasProperty: boolean): RangeFil
395
426
  return property_type !== undefined ? { set_id, property_type, ranges } : { set_id, ranges }
396
427
  }
397
428
 
398
- // ─── LOCATION_FILTER (0x21) — restructured in draft-20 (Section 5.1.2) ──────
429
+ // ─── LOCATION_FILTER (0x21) — draft-20 Section 5.1.2 ───────────────────────
399
430
 
400
431
  /**
401
432
  * Encode a LOCATION_FILTER value.
@@ -517,9 +548,11 @@ function decodeLocationFilter(reader: BufferReader): LocationFilter {
517
548
  * Read out of draft-20's per-parameter sections, not carried over from
518
549
  * draft-19. The biggest delta is that `request_ok` — which is also PUBLISH_OK,
519
550
  * REQUEST_UPDATE_OK, TRACK_STATUS_OK, SUBSCRIBE_NAMESPACE_OK,
520
- * SUBSCRIBE_TRACKS_OK and PUBLISH_NAMESPACE_OK — lost every subscription
521
- * parameter it used to carry. Only EXPIRES (0x08) and LARGEST_OBJECT (0x09)
522
- * still name it. Subscription parameters travel on PUBLISH (initial values) and
551
+ * SUBSCRIBE_TRACKS_OK and PUBLISH_NAMESPACE_OK — carries almost no subscription
552
+ * parameter. Only EXPIRES (0x08) names it, where draft-19 also lists it on
553
+ * OBJECT_DELIVERY_TIMEOUT (0x02), SUBGROUP_DELIVERY_TIMEOUT (0x06), FORWARD
554
+ * (0x10), SUBSCRIBER_PRIORITY (0x20), LOCATION_FILTER (0x21) and
555
+ * NEW_GROUP_REQUEST (0x32). Subscription parameters travel on PUBLISH (initial values) and
523
556
  * REQUEST_UPDATE (changes) instead.
524
557
  *
525
558
  * `fill_parameters` in a set means the type is one of the eight Table 6 permits
@@ -549,24 +582,24 @@ const PARAMETER_SCOPE = new Map<bigint, Set<string>>([
549
582
  [PARAM_SUBGROUP_DELIVERY_TIMEOUT, new Set(['subscribe', 'publish', 'request_update'])],
550
583
  // 0x08 EXPIRES (10.2.16) — the one parameter that still names PUBLISH_OK.
551
584
  [PARAM_EXPIRES, new Set(['subscribe_ok', 'publish', 'request_ok'])],
552
- // 0x09 LARGEST_OBJECT (10.2.17) — gained PUBLISH_STATE_NOTIFY in draft-20.
585
+ // 0x09 LARGEST_OBJECT (10.2.17) — PUBLISH_STATE_NOTIFY here; draft-19 (10.2.16) omits it.
553
586
  [
554
587
  PARAM_LARGEST_OBJECT,
555
588
  new Set(['subscribe_ok', 'publish', 'request_ok', 'publish_state_notify']),
556
589
  ],
557
590
  // 0x0A FILL_TIMEOUT (10.2.5) — FETCH, or nested inside FILL_PARAMETERS.
558
591
  [PARAM_FILL_TIMEOUT, new Set(['fetch', FILL_SCOPE])],
559
- // 0x10 FORWARD (10.2.18) — lost PUBLISH_OK, gained PUBLISH_STATE_NOTIFY.
592
+ // 0x10 FORWARD (10.2.18) — PUBLISH_STATE_NOTIFY here where draft-19 (10.2.17) lists PUBLISH_OK.
560
593
  [
561
594
  PARAM_FORWARD,
562
595
  new Set(['subscribe', 'request_update', 'publish', 'subscribe_tracks', 'publish_state_notify']),
563
596
  ],
564
- // 0x20 SUBSCRIBER_PRIORITY (10.2.7) — lost PUBLISH_OK, gained PUBLISH.
597
+ // 0x20 SUBSCRIBER_PRIORITY (10.2.7) — PUBLISH here where draft-19 lists PUBLISH_OK.
565
598
  [
566
599
  PARAM_SUBSCRIBER_PRIORITY,
567
600
  new Set(['subscribe', 'publish', 'fetch', 'request_update', FILL_SCOPE]),
568
601
  ],
569
- // 0x21 LOCATION_FILTER (10.2.9) — lost PUBLISH_OK, gained PUBLISH and PUBLISH_STATE_NOTIFY.
602
+ // 0x21 LOCATION_FILTER (10.2.9) — PUBLISH and PUBLISH_STATE_NOTIFY here where draft-19 lists PUBLISH_OK.
570
603
  [
571
604
  PARAM_LOCATION_FILTER,
572
605
  new Set([
@@ -578,12 +611,12 @@ const PARAMETER_SCOPE = new Map<bigint, Set<string>>([
578
611
  FILL_SCOPE,
579
612
  ]),
580
613
  ],
581
- // 0x22 GROUP_ORDER (10.2.8) — gained PUBLISH and FILL_PARAMETERS nesting.
614
+ // 0x22 GROUP_ORDER (10.2.8) — PUBLISH and FILL_PARAMETERS nesting here; draft-19 has neither.
582
615
  [PARAM_GROUP_ORDER, new Set(['subscribe', 'publish', 'subscribe_tracks', 'fetch', FILL_SCOPE])],
583
616
  // 0x23 FILL_PARAMETERS (10.2.15) — NEW. Subscriptions only, and never nested
584
617
  // in itself: a FETCH already is a fetch, so it has nothing to fill.
585
618
  [PARAM_FILL_PARAMETERS, new Set(['subscribe', 'request_update'])],
586
- // 0x25-0x28 range filters (5.1.4) — lost PUBLISH_OK, gained FILL_PARAMETERS nesting.
619
+ // 0x25-0x28 range filters (5.1.4) — permitted inside FILL_PARAMETERS (Table 6).
587
620
  [
588
621
  PARAM_SUBGROUP_FILTER,
589
622
  new Set(['fetch', 'subscribe', 'subscribe_tracks', 'request_update', FILL_SCOPE]),
@@ -600,11 +633,11 @@ const PARAMETER_SCOPE = new Map<bigint, Set<string>>([
600
633
  PARAM_OBJECT_PROPERTY_FILTER,
601
634
  new Set(['fetch', 'subscribe', 'subscribe_tracks', 'request_update', FILL_SCOPE]),
602
635
  ],
603
- // 0x29 TRACK_PROPERTY_FILTER (10.2.14) — lost PUBLISH_OK; NOT permitted
604
- // inside FILL_PARAMETERS. A relay forwarding a downstream FILL_PARAMETERS
605
- // upstream has to strip it rather than trip this rule.
636
+ // 0x29 TRACK_PROPERTY_FILTER (10.2.14) — NOT permitted inside
637
+ // FILL_PARAMETERS: Table 6 omits it. A relay forwarding a downstream
638
+ // FILL_PARAMETERS upstream has to strip it rather than trip this rule.
606
639
  [PARAM_TRACK_PROPERTY_FILTER, new Set(['subscribe_tracks', 'request_update'])],
607
- // 0x32 NEW_GROUP_REQUEST (10.2.19) — lost PUBLISH_OK.
640
+ // 0x32 NEW_GROUP_REQUEST (10.2.19) — draft-19 (10.2.18) also lists PUBLISH_OK.
608
641
  [PARAM_NEW_GROUP_REQUEST, new Set(['subscribe', 'request_update'])],
609
642
  // 0x34 TRACK_NAMESPACE_PREFIX (10.2.20) — REQUEST_UPDATE for a namespace subscription.
610
643
  [PARAM_TRACK_NAMESPACE_PREFIX, new Set(['request_update'])],
@@ -826,10 +859,9 @@ function decodeParams(reader: BufferReader, messageType: string): Draft20Params
826
859
  } else if (paramType === PARAM_AUTHORIZATION_TOKEN) {
827
860
  const length = Number(reader.readVarInt())
828
861
  const bytes = reader.readBytes(length)
829
- result.authorization_token = [
830
- ...(result.authorization_token ?? []),
831
- decodeAuthorizationToken(new BufferReader(bytes)),
832
- ]
862
+ const token = decodeAuthorizationToken(new BufferReader(bytes))
863
+ noteAuthTokenValue(reader.offset - length, length, token)
864
+ result.authorization_token = [...(result.authorization_token ?? []), token]
833
865
  } else if (paramType === PARAM_RENDEZVOUS_TIMEOUT) {
834
866
  result.rendezvous_timeout = reader.readVarInt()
835
867
  } else if (paramType === PARAM_SUBGROUP_DELIVERY_TIMEOUT) {
@@ -926,7 +958,7 @@ function decodeFillParameters(reader: BufferReader): Draft20FillParameters {
926
958
  const length = Number(reader.readVarInt())
927
959
  const valueBytes = reader.readBytes(length)
928
960
  const nested = new BufferReader(valueBytes)
929
- const params = decodeParams(nested, FILL_SCOPE)
961
+ const params = withoutAuthValueSpans(() => decodeParams(nested, FILL_SCOPE))
930
962
  if (nested.remaining > 0) {
931
963
  // The parameter count and the byte length disagree. The draft does not say
932
964
  // what to do; leaving the slack unread would let a sender smuggle bytes no
@@ -1747,3 +1779,38 @@ export function createDraft20Codec(): Draft20Codec {
1747
1779
  createDataStreamDecoder,
1748
1780
  }
1749
1781
  }
1782
+
1783
+ /**
1784
+ * Overwrite every Authorization Token value in a draft-20 control frame.
1785
+ *
1786
+ * One decode, whose *output is discarded*: the point is not to read the
1787
+ * message, it is to learn where the tokens were so the caller never has to hold
1788
+ * a frame that contains one. A caller that also wants the message should decode
1789
+ * the **redacted** frame with {@link decodeMessage}, which then cannot produce a
1790
+ * token value because there is no longer one in the bytes.
1791
+ *
1792
+ * A frame that fails to decode is still redacted as far as the decode got. That
1793
+ * is the useful direction to fail in: a value that was read is a value that was
1794
+ * exposed, whatever went wrong after it.
1795
+ *
1796
+ * See {@link AuthRedaction.incomplete} for the one result a caller must not
1797
+ * treat as clean, and {@link AuthRedaction.decoded} for the residual it cannot
1798
+ * close.
1799
+ */
1800
+ export function redactAuthTokens(bytes: Uint8Array): AuthRedaction {
1801
+ let payloadStart: number
1802
+ try {
1803
+ const probe = new BufferReader(bytes)
1804
+ probe.readVarInt()
1805
+ probe.readUint8()
1806
+ probe.readUint8()
1807
+ payloadStart = probe.offset
1808
+ } catch {
1809
+ // Too short to carry a message header, and so too short for the parameters
1810
+ // that carry a token. Reported as not decoded rather than as clean: the
1811
+ // framer only ever emits complete frames, so a caller that gets here is
1812
+ // holding something this function did not check.
1813
+ return { bytes, redacted: 0, incomplete: false, decoded: false }
1814
+ }
1815
+ return redactWith(bytes, payloadStart, () => decodeMessage(bytes).ok)
1816
+ }