@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
@@ -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
@@ -18,7 +18,7 @@ export interface AuthorizationToken {
18
18
  // Setup options (KVP encoding, no count prefix)
19
19
  export interface Draft19SetupOptions {
20
20
  path?: string // 0x01 odd
21
- authorization_token?: AuthorizationToken // 0x03 odd
21
+ authorization_token?: readonly AuthorizationToken[] // 0x03 odd
22
22
  max_auth_token_cache_size?: bigint // 0x04 even
23
23
  authority?: string // 0x05 odd
24
24
  max_filter_ranges?: bigint // 0x06 even (NEW in draft-19)
@@ -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,22 +57,25 @@ 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)
61
- authorization_token?: AuthorizationToken // 0x03 length-prefixed nested
60
+ object_delivery_timeout?: bigint // 0x02 varint; drafts 11-17 name this parameter DELIVERY TIMEOUT
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
- subgroup_filter?: RangeFilter // 0x25 length-prefixed (NEW in draft-19)
72
- objectid_filter?: RangeFilter // 0x26 length-prefixed (NEW in draft-19)
73
- priority_filter?: RangeFilter // 0x27 length-prefixed (NEW in draft-19)
74
- object_property_filter?: RangeFilter // 0x28 length-prefixed (NEW in draft-19)
75
- track_property_filter?: RangeFilter // 0x29 length-prefixed (NEW in draft-19)
71
+ // Section 5.1.3 permits each of the five more than once in a message: a
72
+ // filter parameter carries one SetID, so two alternatives over the same
73
+ // field need two parameters. A single filter is a one-element list.
74
+ subgroup_filter?: readonly RangeFilter[] // 0x25 length-prefixed (NEW in draft-19)
75
+ objectid_filter?: readonly RangeFilter[] // 0x26 length-prefixed (NEW in draft-19)
76
+ priority_filter?: readonly RangeFilter[] // 0x27 length-prefixed (NEW in draft-19)
77
+ object_property_filter?: readonly RangeFilter[] // 0x28 length-prefixed (NEW in draft-19)
78
+ track_property_filter?: readonly RangeFilter[] // 0x29 length-prefixed (NEW in draft-19)
76
79
  new_group_request?: bigint // 0x32 varint
77
80
  track_namespace_prefix?: string[] // 0x34 Track Namespace encoding (NEW in draft-18)
78
81
  unknown?: UnknownParam[]
@@ -80,7 +83,7 @@ export interface Draft19Params {
80
83
 
81
84
  // Track properties (KVP encoding, no count prefix, read until end of payload)
82
85
  export interface Draft19TrackProperties {
83
- 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
84
87
  max_cache_duration?: bigint // 0x04 even varint
85
88
  subgroup_delivery_timeout?: bigint // 0x06 even varint (NEW in draft-18)
86
89
  immutable_properties?: Uint8Array // 0x0b odd length-prefixed
@@ -122,7 +125,8 @@ export interface Draft19Setup extends Draft19BaseMessage {
122
125
  readonly options: Draft19SetupOptions
123
126
  }
124
127
 
125
- // 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)
126
130
  export interface Draft19Subscribe extends Draft19BaseMessage {
127
131
  readonly type: 'subscribe'
128
132
  readonly request_id: bigint
@@ -180,7 +184,7 @@ export interface Draft19NamespaceDone extends Draft19BaseMessage {
180
184
  readonly namespace_suffix: string[]
181
185
  }
182
186
 
183
- // 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
184
188
  export interface Draft19SubscribeNamespace extends Draft19BaseMessage {
185
189
  readonly type: 'subscribe_namespace'
186
190
  readonly request_id: bigint
@@ -188,7 +192,7 @@ export interface Draft19SubscribeNamespace extends Draft19BaseMessage {
188
192
  readonly parameters: Draft19Params
189
193
  }
190
194
 
191
- // SUBSCRIBE_TRACKS — NEW in draft-18, type 0x51
195
+ // SUBSCRIBE_TRACKS — type 0x51; no draft before 18 carries this message
192
196
  export interface Draft19SubscribeTracks extends Draft19BaseMessage {
193
197
  readonly type: 'subscribe_tracks'
194
198
  readonly request_id: bigint
@@ -235,7 +239,8 @@ export interface Draft19FetchOk extends Draft19BaseMessage {
235
239
  readonly track_properties: Draft19TrackProperties
236
240
  }
237
241
 
238
- // 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).
239
244
  export interface Draft19TrackStatus extends Draft19BaseMessage {
240
245
  readonly type: 'track_status'
241
246
  readonly request_id: bigint
@@ -244,7 +249,7 @@ export interface Draft19TrackStatus extends Draft19BaseMessage {
244
249
  readonly parameters: Draft19Params
245
250
  }
246
251
 
247
- // 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
248
253
  export interface Draft19RequestOk extends Draft19BaseMessage {
249
254
  readonly type: 'request_ok'
250
255
  readonly parameters: Draft19Params
@@ -271,7 +276,8 @@ export interface Draft19GoAway extends Draft19BaseMessage {
271
276
  readonly type: 'goaway'
272
277
  readonly new_session_uri: string
273
278
  readonly timeout: bigint
274
- // 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
275
281
  }
276
282
 
277
283
  // Union of all draft-18 control messages
@@ -353,10 +359,18 @@ export type Draft19DataStream = SubgroupStream | DatagramObject | FetchStream
353
359
  // Streaming data stream decoder types
354
360
  export interface SubgroupStreamHeader {
355
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
356
368
  readonly trackAlias: bigint
357
369
  readonly groupId: bigint
358
370
  readonly subgroupId: bigint
359
371
  readonly publisherPriority: number
372
+ readonly endOfGroup?: boolean
373
+ readonly firstObject?: boolean
360
374
  }
361
375
 
362
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'
@@ -98,12 +104,12 @@ function encodeSetupOptions(opts: Draft20SetupOptions, writer: BufferWriter): vo
98
104
  },
99
105
  })
100
106
  }
101
- if (opts.authorization_token !== undefined) {
107
+ for (const token of opts.authorization_token ?? []) {
102
108
  entries.push({
103
109
  type: SETUP_OPT_AUTHORIZATION_TOKEN,
104
110
  encode: (w) => {
105
111
  const tmpW = new BufferWriter(64)
106
- encodeAuthorizationToken(opts.authorization_token!, tmpW)
112
+ encodeAuthorizationToken(token, tmpW)
107
113
  const raw = tmpW.finish()
108
114
  w.writeVarInt(BigInt(raw.byteLength))
109
115
  w.writeBytes(raw)
@@ -216,7 +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 = decodeAuthorizationToken(new BufferReader(bytes))
225
+ const token = decodeAuthorizationToken(new BufferReader(bytes))
226
+ noteAuthTokenValue(reader.offset - length, length, token)
227
+ result.authorization_token = [...(result.authorization_token ?? []), token]
220
228
  } else if (optType === SETUP_OPT_AUTHORITY) {
221
229
  result.authority = textDecoder.decode(bytes)
222
230
  } else if (optType === SETUP_OPT_MOQT_IMPLEMENTATION) {
@@ -254,6 +262,32 @@ function encodeAuthorizationToken(token: AuthorizationToken, w: BufferWriter): v
254
262
  }
255
263
  }
256
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
+
257
291
  function decodeAuthorizationToken(r: BufferReader): AuthorizationToken {
258
292
  const alias_type = r.readVarInt()
259
293
  const aliasType = Number(alias_type)
@@ -392,7 +426,7 @@ function decodeRangeFilter(reader: BufferReader, hasProperty: boolean): RangeFil
392
426
  return property_type !== undefined ? { set_id, property_type, ranges } : { set_id, ranges }
393
427
  }
394
428
 
395
- // ─── LOCATION_FILTER (0x21) — restructured in draft-20 (Section 5.1.2) ──────
429
+ // ─── LOCATION_FILTER (0x21) — draft-20 Section 5.1.2 ───────────────────────
396
430
 
397
431
  /**
398
432
  * Encode a LOCATION_FILTER value.
@@ -514,9 +548,11 @@ function decodeLocationFilter(reader: BufferReader): LocationFilter {
514
548
  * Read out of draft-20's per-parameter sections, not carried over from
515
549
  * draft-19. The biggest delta is that `request_ok` — which is also PUBLISH_OK,
516
550
  * REQUEST_UPDATE_OK, TRACK_STATUS_OK, SUBSCRIBE_NAMESPACE_OK,
517
- * SUBSCRIBE_TRACKS_OK and PUBLISH_NAMESPACE_OK — lost every subscription
518
- * parameter it used to carry. Only EXPIRES (0x08) and LARGEST_OBJECT (0x09)
519
- * 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
520
556
  * REQUEST_UPDATE (changes) instead.
521
557
  *
522
558
  * `fill_parameters` in a set means the type is one of the eight Table 6 permits
@@ -546,24 +582,24 @@ const PARAMETER_SCOPE = new Map<bigint, Set<string>>([
546
582
  [PARAM_SUBGROUP_DELIVERY_TIMEOUT, new Set(['subscribe', 'publish', 'request_update'])],
547
583
  // 0x08 EXPIRES (10.2.16) — the one parameter that still names PUBLISH_OK.
548
584
  [PARAM_EXPIRES, new Set(['subscribe_ok', 'publish', 'request_ok'])],
549
- // 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.
550
586
  [
551
587
  PARAM_LARGEST_OBJECT,
552
588
  new Set(['subscribe_ok', 'publish', 'request_ok', 'publish_state_notify']),
553
589
  ],
554
590
  // 0x0A FILL_TIMEOUT (10.2.5) — FETCH, or nested inside FILL_PARAMETERS.
555
591
  [PARAM_FILL_TIMEOUT, new Set(['fetch', FILL_SCOPE])],
556
- // 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.
557
593
  [
558
594
  PARAM_FORWARD,
559
595
  new Set(['subscribe', 'request_update', 'publish', 'subscribe_tracks', 'publish_state_notify']),
560
596
  ],
561
- // 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.
562
598
  [
563
599
  PARAM_SUBSCRIBER_PRIORITY,
564
600
  new Set(['subscribe', 'publish', 'fetch', 'request_update', FILL_SCOPE]),
565
601
  ],
566
- // 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.
567
603
  [
568
604
  PARAM_LOCATION_FILTER,
569
605
  new Set([
@@ -575,12 +611,12 @@ const PARAMETER_SCOPE = new Map<bigint, Set<string>>([
575
611
  FILL_SCOPE,
576
612
  ]),
577
613
  ],
578
- // 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.
579
615
  [PARAM_GROUP_ORDER, new Set(['subscribe', 'publish', 'subscribe_tracks', 'fetch', FILL_SCOPE])],
580
616
  // 0x23 FILL_PARAMETERS (10.2.15) — NEW. Subscriptions only, and never nested
581
617
  // in itself: a FETCH already is a fetch, so it has nothing to fill.
582
618
  [PARAM_FILL_PARAMETERS, new Set(['subscribe', 'request_update'])],
583
- // 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).
584
620
  [
585
621
  PARAM_SUBGROUP_FILTER,
586
622
  new Set(['fetch', 'subscribe', 'subscribe_tracks', 'request_update', FILL_SCOPE]),
@@ -597,11 +633,11 @@ const PARAMETER_SCOPE = new Map<bigint, Set<string>>([
597
633
  PARAM_OBJECT_PROPERTY_FILTER,
598
634
  new Set(['fetch', 'subscribe', 'subscribe_tracks', 'request_update', FILL_SCOPE]),
599
635
  ],
600
- // 0x29 TRACK_PROPERTY_FILTER (10.2.14) — lost PUBLISH_OK; NOT permitted
601
- // inside FILL_PARAMETERS. A relay forwarding a downstream FILL_PARAMETERS
602
- // 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.
603
639
  [PARAM_TRACK_PROPERTY_FILTER, new Set(['subscribe_tracks', 'request_update'])],
604
- // 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.
605
641
  [PARAM_NEW_GROUP_REQUEST, new Set(['subscribe', 'request_update'])],
606
642
  // 0x34 TRACK_NAMESPACE_PREFIX (10.2.20) — REQUEST_UPDATE for a namespace subscription.
607
643
  [PARAM_TRACK_NAMESPACE_PREFIX, new Set(['request_update'])],
@@ -619,12 +655,12 @@ function encodeParams(params: Draft20Params, writer: BufferWriter): void {
619
655
  encode: (w) => w.writeVarInt(params.object_delivery_timeout!),
620
656
  })
621
657
  }
622
- if (params.authorization_token !== undefined) {
658
+ for (const token of params.authorization_token ?? []) {
623
659
  entries.push({
624
660
  type: PARAM_AUTHORIZATION_TOKEN,
625
661
  encode: (w) => {
626
662
  const tmpW = new BufferWriter(64)
627
- encodeAuthorizationToken(params.authorization_token!, tmpW)
663
+ encodeAuthorizationToken(token, tmpW)
628
664
  const raw = tmpW.finish()
629
665
  w.writeVarInt(BigInt(raw.byteLength))
630
666
  w.writeBytes(raw)
@@ -718,34 +754,34 @@ function encodeParams(params: Draft20Params, writer: BufferWriter): void {
718
754
  },
719
755
  })
720
756
  }
721
- if (params.subgroup_filter !== undefined) {
757
+ for (const filter of params.subgroup_filter ?? []) {
722
758
  entries.push({
723
759
  type: PARAM_SUBGROUP_FILTER,
724
- encode: (w) => encodeRangeFilter(params.subgroup_filter!, false, w),
760
+ encode: (w) => encodeRangeFilter(filter, false, w),
725
761
  })
726
762
  }
727
- if (params.objectid_filter !== undefined) {
763
+ for (const filter of params.objectid_filter ?? []) {
728
764
  entries.push({
729
765
  type: PARAM_OBJECTID_FILTER,
730
- encode: (w) => encodeRangeFilter(params.objectid_filter!, false, w),
766
+ encode: (w) => encodeRangeFilter(filter, false, w),
731
767
  })
732
768
  }
733
- if (params.priority_filter !== undefined) {
769
+ for (const filter of params.priority_filter ?? []) {
734
770
  entries.push({
735
771
  type: PARAM_PRIORITY_FILTER,
736
- encode: (w) => encodeRangeFilter(params.priority_filter!, false, w),
772
+ encode: (w) => encodeRangeFilter(filter, false, w),
737
773
  })
738
774
  }
739
- if (params.object_property_filter !== undefined) {
775
+ for (const filter of params.object_property_filter ?? []) {
740
776
  entries.push({
741
777
  type: PARAM_OBJECT_PROPERTY_FILTER,
742
- encode: (w) => encodeRangeFilter(params.object_property_filter!, true, w),
778
+ encode: (w) => encodeRangeFilter(filter, true, w),
743
779
  })
744
780
  }
745
- if (params.track_property_filter !== undefined) {
781
+ for (const filter of params.track_property_filter ?? []) {
746
782
  entries.push({
747
783
  type: PARAM_TRACK_PROPERTY_FILTER,
748
- encode: (w) => encodeRangeFilter(params.track_property_filter!, true, w),
784
+ encode: (w) => encodeRangeFilter(filter, true, w),
749
785
  })
750
786
  }
751
787
  if (params.new_group_request !== undefined) {
@@ -823,7 +859,9 @@ function decodeParams(reader: BufferReader, messageType: string): Draft20Params
823
859
  } else if (paramType === PARAM_AUTHORIZATION_TOKEN) {
824
860
  const length = Number(reader.readVarInt())
825
861
  const bytes = reader.readBytes(length)
826
- result.authorization_token = decodeAuthorizationToken(new BufferReader(bytes))
862
+ const token = decodeAuthorizationToken(new BufferReader(bytes))
863
+ noteAuthTokenValue(reader.offset - length, length, token)
864
+ result.authorization_token = [...(result.authorization_token ?? []), token]
827
865
  } else if (paramType === PARAM_RENDEZVOUS_TIMEOUT) {
828
866
  result.rendezvous_timeout = reader.readVarInt()
829
867
  } else if (paramType === PARAM_SUBGROUP_DELIVERY_TIMEOUT) {
@@ -851,15 +889,21 @@ function decodeParams(reader: BufferReader, messageType: string): Draft20Params
851
889
  } else if (paramType === PARAM_FILL_PARAMETERS) {
852
890
  result.fill_parameters = decodeFillParameters(reader)
853
891
  } else if (paramType === PARAM_SUBGROUP_FILTER) {
854
- result.subgroup_filter = decodeRangeFilter(reader, false)
892
+ result.subgroup_filter = [...(result.subgroup_filter ?? []), decodeRangeFilter(reader, false)]
855
893
  } else if (paramType === PARAM_OBJECTID_FILTER) {
856
- result.objectid_filter = decodeRangeFilter(reader, false)
894
+ result.objectid_filter = [...(result.objectid_filter ?? []), decodeRangeFilter(reader, false)]
857
895
  } else if (paramType === PARAM_PRIORITY_FILTER) {
858
- result.priority_filter = decodeRangeFilter(reader, false)
896
+ result.priority_filter = [...(result.priority_filter ?? []), decodeRangeFilter(reader, false)]
859
897
  } else if (paramType === PARAM_OBJECT_PROPERTY_FILTER) {
860
- result.object_property_filter = decodeRangeFilter(reader, true)
898
+ result.object_property_filter = [
899
+ ...(result.object_property_filter ?? []),
900
+ decodeRangeFilter(reader, true),
901
+ ]
861
902
  } else if (paramType === PARAM_TRACK_PROPERTY_FILTER) {
862
- result.track_property_filter = decodeRangeFilter(reader, true)
903
+ result.track_property_filter = [
904
+ ...(result.track_property_filter ?? []),
905
+ decodeRangeFilter(reader, true),
906
+ ]
863
907
  } else if (paramType === PARAM_NEW_GROUP_REQUEST) {
864
908
  result.new_group_request = reader.readVarInt()
865
909
  } else if (paramType === PARAM_TRACK_NAMESPACE_PREFIX) {
@@ -914,7 +958,7 @@ function decodeFillParameters(reader: BufferReader): Draft20FillParameters {
914
958
  const length = Number(reader.readVarInt())
915
959
  const valueBytes = reader.readBytes(length)
916
960
  const nested = new BufferReader(valueBytes)
917
- const params = decodeParams(nested, FILL_SCOPE)
961
+ const params = withoutAuthValueSpans(() => decodeParams(nested, FILL_SCOPE))
918
962
  if (nested.remaining > 0) {
919
963
  // The parameter count and the byte length disagree. The draft does not say
920
964
  // what to do; leaving the slack unread would let a sender smuggle bytes no
@@ -1735,3 +1779,38 @@ export function createDraft20Codec(): Draft20Codec {
1735
1779
  createDataStreamDecoder,
1736
1780
  }
1737
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
+ }