@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
@@ -1,3 +1,4 @@
1
+ import { type AuthRedaction, recordAuthValueSpan, redactWith } from '../../core/auth-redaction.js'
1
2
  import { BufferReader } from '../../core/buffer-reader.js'
2
3
  import { BufferWriter } from '../../core/buffer-writer.js'
3
4
  import { bytesToHex, hexToBytes } from '../../core/hex.js'
@@ -115,7 +116,7 @@ function encodeSetupParams(params: Draft13SetupParams, w: BufferWriter): void {
115
116
  let count = 0
116
117
  if (params.path !== undefined) count++
117
118
  if (params.max_request_id !== undefined) count++
118
- if (params.authorization_token !== undefined) count++
119
+ count += params.authorization_token?.length ?? 0
119
120
  if (params.max_auth_token_cache_size !== undefined) count++
120
121
  if (params.unknown) count += params.unknown.length
121
122
 
@@ -131,9 +132,9 @@ function encodeSetupParams(params: Draft13SetupParams, w: BufferWriter): void {
131
132
  w.writeVarInt(SETUP_PARAM_MAX_REQUEST_ID)
132
133
  w.writeVarInt(params.max_request_id)
133
134
  }
134
- if (params.authorization_token !== undefined) {
135
+ for (const token of params.authorization_token ?? []) {
135
136
  w.writeVarInt(SETUP_PARAM_AUTHORIZATION_TOKEN)
136
- encodeAuthorizationToken(params.authorization_token, w)
137
+ encodeAuthorizationToken(token, w)
137
138
  }
138
139
  if (params.max_auth_token_cache_size !== undefined) {
139
140
  w.writeVarInt(SETUP_PARAM_MAX_AUTH_TOKEN_CACHE_SIZE)
@@ -185,7 +186,10 @@ function decodeSetupParams(r: BufferReader): Draft13SetupParams {
185
186
  const bytes = r.readBytes(length)
186
187
  result.path = textDecoder.decode(bytes)
187
188
  } else if (paramType === SETUP_PARAM_AUTHORIZATION_TOKEN) {
188
- result.authorization_token = decodeAuthorizationToken(r, length)
189
+ const valueStart = r.offset
190
+ const token = decodeAuthorizationToken(r, length)
191
+ noteAuthTokenValue(valueStart, length, token.token_value)
192
+ result.authorization_token = [...(result.authorization_token ?? []), token]
189
193
  } else {
190
194
  const bytes = r.readBytes(length)
191
195
  unknown.push({
@@ -207,7 +211,7 @@ function decodeSetupParams(r: BufferReader): Draft13SetupParams {
207
211
  function encodeParams(params: Draft13Params, w: BufferWriter): void {
208
212
  let count = params.unknown ? params.unknown.length : 0
209
213
  if (params.delivery_timeout !== undefined) count++
210
- if (params.authorization_token !== undefined) count++
214
+ count += params.authorization_token?.length ?? 0
211
215
  if (params.max_cache_duration !== undefined) count++
212
216
  w.writeVarInt(count)
213
217
 
@@ -216,10 +220,10 @@ function encodeParams(params: Draft13Params, w: BufferWriter): void {
216
220
  w.writeVarInt(PARAM_DELIVERY_TIMEOUT)
217
221
  w.writeVarInt(params.delivery_timeout)
218
222
  }
219
- if (params.authorization_token !== undefined) {
223
+ for (const token of params.authorization_token ?? []) {
220
224
  // AUTHORIZATION_TOKEN = 0x03 (odd → length-prefixed)
221
225
  w.writeVarInt(PARAM_AUTHORIZATION_TOKEN)
222
- encodeAuthorizationToken(params.authorization_token, w)
226
+ encodeAuthorizationToken(token, w)
223
227
  }
224
228
  if (params.max_cache_duration !== undefined) {
225
229
  // MAX_CACHE_DURATION = 0x04 (even → bare varint)
@@ -275,7 +279,10 @@ function decodeParams(r: BufferReader): Draft13Params {
275
279
  const length = Number(r.readVarInt())
276
280
 
277
281
  if (paramType === PARAM_AUTHORIZATION_TOKEN) {
278
- result.authorization_token = decodeAuthorizationToken(r, length)
282
+ const valueStart = r.offset
283
+ const token = decodeAuthorizationToken(r, length)
284
+ noteAuthTokenValue(valueStart, length, token.token_value)
285
+ result.authorization_token = [...(result.authorization_token ?? []), token]
279
286
  } else {
280
287
  const bytes = r.readBytes(length)
281
288
  unknown.push({
@@ -425,7 +432,7 @@ function encodeAnnounceCancelPayload(
425
432
  w.writeString(msg.reason_phrase)
426
433
  }
427
434
 
428
- // Draft-13: subscribe_namespace (renamed from subscribe_announces, same wire format)
435
+ // Draft-13 subscribe_namespace (0x11) byte-identical to the payload draft-12 spells subscribe_announces.
429
436
  function encodeSubscribeNamespacePayload(
430
437
  msg: Draft13Message & { type: 'subscribe_namespace' },
431
438
  w: BufferWriter,
@@ -547,7 +554,7 @@ function encodeFetchCancelPayload(
547
554
  w.writeVarInt(msg.request_id)
548
555
  }
549
556
 
550
- // Draft-13: track_status is now SUBSCRIBE-like
557
+ // Draft-13 Section 8.20: the TRACK_STATUS message format is identical to SUBSCRIBE.
551
558
  function encodeTrackStatusPayload(
552
559
  msg: Draft13Message & { type: 'track_status' },
553
560
  w: BufferWriter,
@@ -777,7 +784,6 @@ function decodeAnnounceCancelPayload(r: BufferReader): Draft13Message {
777
784
  return { type: 'announce_cancel', track_namespace, error_code, reason_phrase }
778
785
  }
779
786
 
780
- // Draft-13: subscribe_namespace (renamed from subscribe_announces)
781
787
  function decodeSubscribeNamespacePayload(r: BufferReader): Draft13Message {
782
788
  const request_id = r.readVarInt()
783
789
  const track_namespace_prefix = r.readTuple()
@@ -1293,3 +1299,61 @@ export function createDraft13Codec(): Draft13Codec {
1293
1299
  createStreamDecoder,
1294
1300
  }
1295
1301
  }
1302
+
1303
+ /**
1304
+ * Record where a Token Value sits, so it can be overwritten before the frame
1305
+ * reaches anything that keeps it.
1306
+ *
1307
+ * The span falls out of the decode with no second walk. The Token Value is the
1308
+ * last field of the Token structure, so its start is the parameter value's end
1309
+ * minus the value's own length. The fields before it are left alone
1310
+ * deliberately: Alias Type, Token Alias and Token Type are structure rather
1311
+ * than secret, and they are what distinguishes a session that failed to
1312
+ * authenticate from one that never tried.
1313
+ *
1314
+ * A token carrying no value at all -- DELETE and USE_ALIAS -- records nothing,
1315
+ * and its frame passes through untouched.
1316
+ */
1317
+ function noteAuthTokenValue(
1318
+ valueStart: number,
1319
+ valueLength: number,
1320
+ value: Uint8Array | undefined,
1321
+ ): void {
1322
+ if (value === undefined || value.byteLength === 0) return
1323
+ recordAuthValueSpan(valueStart + valueLength - value.byteLength, value.byteLength)
1324
+ }
1325
+
1326
+ /**
1327
+ * Overwrite every Authorization Token value in a draft-13 control frame.
1328
+ *
1329
+ * One decode, whose *output is discarded*: the point is not to read the
1330
+ * message, it is to learn where the credentials were so the caller never has to
1331
+ * hold a frame that contains one. A caller that also wants the message should
1332
+ * decode the **redacted** frame with {@link decodeMessage}, which then cannot
1333
+ * produce a value because there is no longer one in the bytes.
1334
+ *
1335
+ * A frame that fails to decode is still redacted as far as the decode got. That
1336
+ * is the useful direction to fail in: a value that was read is a value that was
1337
+ * exposed, whatever went wrong after it.
1338
+ *
1339
+ * See {@link AuthRedaction.incomplete} for the one result a caller must not
1340
+ * treat as clean, and {@link AuthRedaction.decoded} for the residual it cannot
1341
+ * close.
1342
+ */
1343
+ export function redactAuthTokens(bytes: Uint8Array): AuthRedaction {
1344
+ let payloadStart: number
1345
+ try {
1346
+ const probe = new BufferReader(bytes)
1347
+ probe.readVarInt()
1348
+ probe.readUint8()
1349
+ probe.readUint8()
1350
+ payloadStart = probe.offset
1351
+ } catch {
1352
+ // Too short to carry a message header, and so too short for the parameters
1353
+ // that carry a credential. Reported as not decoded rather than as clean: a
1354
+ // framer only ever emits complete frames, so a caller that gets here is
1355
+ // holding something this function did not check.
1356
+ return { bytes, redacted: 0, incomplete: false, decoded: false }
1357
+ }
1358
+ return redactWith(bytes, payloadStart, () => decodeMessage(bytes).ok)
1359
+ }
@@ -0,0 +1,107 @@
1
+ // Draft-13 error, status and termination code registries.
2
+
3
+ export const SessionErrorCode = {
4
+ NoError: 0x0n,
5
+ InternalError: 0x1n,
6
+ Unauthorized: 0x2n,
7
+ ProtocolViolation: 0x3n,
8
+ InvalidRequestId: 0x4n,
9
+ DuplicateTrackAlias: 0x5n,
10
+ KeyValueFormattingError: 0x6n,
11
+ TooManyRequests: 0x7n,
12
+ InvalidPath: 0x8n,
13
+ MalformedPath: 0x9n,
14
+ GoawayTimeout: 0x10n,
15
+ ControlMessageTimeout: 0x11n,
16
+ DataStreamTimeout: 0x12n,
17
+ AuthTokenCacheOverflow: 0x13n,
18
+ DuplicateAuthTokenAlias: 0x14n,
19
+ VersionNegotiationFailed: 0x15n,
20
+ MalformedAuthToken: 0x16n,
21
+ UnknownAuthTokenAlias: 0x17n,
22
+ ExpiredAuthToken: 0x18n,
23
+ } as const
24
+ export type SessionErrorCodeValue = (typeof SessionErrorCode)[keyof typeof SessionErrorCode]
25
+
26
+ export const SubscribeErrorCode = {
27
+ InternalError: 0x0n,
28
+ Unauthorized: 0x1n,
29
+ Timeout: 0x2n,
30
+ NotSupported: 0x3n,
31
+ TrackDoesNotExist: 0x4n,
32
+ InvalidRange: 0x5n,
33
+ MalformedAuthToken: 0x10n,
34
+ ExpiredAuthToken: 0x12n,
35
+ } as const
36
+ export type SubscribeErrorCodeValue = (typeof SubscribeErrorCode)[keyof typeof SubscribeErrorCode]
37
+
38
+ export const SubscribeDoneStatusCode = {
39
+ InternalError: 0x0n,
40
+ Unauthorized: 0x1n,
41
+ TrackEnded: 0x2n,
42
+ SubscriptionEnded: 0x3n,
43
+ GoingAway: 0x4n,
44
+ Expired: 0x5n,
45
+ TooFarBehind: 0x6n,
46
+ MalformedTrack: 0x7n,
47
+ } as const
48
+ export type SubscribeDoneStatusCodeValue =
49
+ (typeof SubscribeDoneStatusCode)[keyof typeof SubscribeDoneStatusCode]
50
+
51
+ export const PublishErrorCode = {
52
+ InternalError: 0x0n,
53
+ Unauthorized: 0x1n,
54
+ Timeout: 0x2n,
55
+ NotSupported: 0x3n,
56
+ Uninterested: 0x4n,
57
+ } as const
58
+ export type PublishErrorCodeValue = (typeof PublishErrorCode)[keyof typeof PublishErrorCode]
59
+
60
+ export const FetchErrorCode = {
61
+ InternalError: 0x0n,
62
+ Unauthorized: 0x1n,
63
+ Timeout: 0x2n,
64
+ NotSupported: 0x3n,
65
+ TrackDoesNotExist: 0x4n,
66
+ InvalidRange: 0x5n,
67
+ NoObjects: 0x6n,
68
+ InvalidJoiningRequestId: 0x7n,
69
+ UnknownStatusInRange: 0x8n,
70
+ MalformedTrack: 0x9n,
71
+ MalformedAuthToken: 0x10n,
72
+ ExpiredAuthToken: 0x12n,
73
+ } as const
74
+ export type FetchErrorCodeValue = (typeof FetchErrorCode)[keyof typeof FetchErrorCode]
75
+
76
+ export const AnnounceErrorCode = {
77
+ InternalError: 0x0n,
78
+ Unauthorized: 0x1n,
79
+ Timeout: 0x2n,
80
+ NotSupported: 0x3n,
81
+ Uninterested: 0x4n,
82
+ MalformedAuthToken: 0x10n,
83
+ ExpiredAuthToken: 0x12n,
84
+ } as const
85
+ export type AnnounceErrorCodeValue = (typeof AnnounceErrorCode)[keyof typeof AnnounceErrorCode]
86
+
87
+ export const SubscribeNamespaceErrorCode = {
88
+ InternalError: 0x0n,
89
+ Unauthorized: 0x1n,
90
+ Timeout: 0x2n,
91
+ NotSupported: 0x3n,
92
+ NamespacePrefixUnknown: 0x4n,
93
+ NamespacePrefixOverlap: 0x5n,
94
+ MalformedAuthToken: 0x10n,
95
+ ExpiredAuthToken: 0x12n,
96
+ } as const
97
+ export type SubscribeNamespaceErrorCodeValue =
98
+ (typeof SubscribeNamespaceErrorCode)[keyof typeof SubscribeNamespaceErrorCode]
99
+
100
+ export const StreamResetErrorCode = {
101
+ InternalError: 0x0n,
102
+ Cancelled: 0x1n,
103
+ DeliveryTimeout: 0x2n,
104
+ SessionClosed: 0x3n,
105
+ } as const
106
+ export type StreamResetErrorCodeValue =
107
+ (typeof StreamResetErrorCode)[keyof typeof StreamResetErrorCode]
@@ -1,5 +1,7 @@
1
1
  export const DRAFT_VERSION = 0xff00000dn
2
2
 
3
+ export type { AuthRedaction } from '../../core/auth-redaction.js'
4
+ export { REDACTION_FILL } from '../../core/auth-redaction.js'
3
5
  export type { Draft13Codec } from './codec.js'
4
6
  export {
5
7
  createDraft13Codec,
@@ -13,7 +15,28 @@ export {
13
15
  encodeFetchStream,
14
16
  encodeMessage,
15
17
  encodeSubgroupStream,
18
+ redactAuthTokens,
16
19
  } from './codec.js'
20
+ export type {
21
+ AnnounceErrorCodeValue,
22
+ FetchErrorCodeValue,
23
+ PublishErrorCodeValue,
24
+ SessionErrorCodeValue,
25
+ StreamResetErrorCodeValue,
26
+ SubscribeDoneStatusCodeValue,
27
+ SubscribeErrorCodeValue,
28
+ SubscribeNamespaceErrorCodeValue,
29
+ } from './error-codes.js'
30
+ export {
31
+ AnnounceErrorCode,
32
+ FetchErrorCode,
33
+ PublishErrorCode,
34
+ SessionErrorCode,
35
+ StreamResetErrorCode,
36
+ SubscribeDoneStatusCode,
37
+ SubscribeErrorCode,
38
+ SubscribeNamespaceErrorCode,
39
+ } from './error-codes.js'
17
40
  export {
18
41
  MESSAGE_ID_MAP,
19
42
  MESSAGE_TYPE_MAP,
@@ -21,7 +21,7 @@ export interface AuthorizationToken {
21
21
  export interface Draft13SetupParams {
22
22
  path?: string // 0x01 odd
23
23
  max_request_id?: bigint // 0x02 even
24
- authorization_token?: AuthorizationToken // 0x03 odd
24
+ authorization_token?: readonly AuthorizationToken[] // 0x03 odd
25
25
  max_auth_token_cache_size?: bigint // 0x04 even
26
26
  unknown?: UnknownParam[]
27
27
  }
@@ -29,7 +29,7 @@ export interface Draft13SetupParams {
29
29
  // Version-specific parameters — even/odd convention
30
30
  export interface Draft13Params {
31
31
  delivery_timeout?: bigint // 0x02 even
32
- authorization_token?: AuthorizationToken // 0x03 odd
32
+ authorization_token?: readonly AuthorizationToken[] // 0x03 odd
33
33
  max_cache_duration?: bigint // 0x04 even
34
34
  unknown?: UnknownParam[]
35
35
  }
@@ -181,7 +181,7 @@ export interface Draft13AnnounceCancel extends Draft13BaseMessage {
181
181
  readonly reason_phrase: string
182
182
  }
183
183
 
184
- // Subscribe Namespace (renamed from subscribe_announces in draft-12)
184
+ // Subscribe Namespace type 0x11; drafts 07-12 name the same codepoint SUBSCRIBE_ANNOUNCES
185
185
  export interface Draft13SubscribeNamespace extends Draft13BaseMessage {
186
186
  readonly type: 'subscribe_namespace'
187
187
  readonly request_id: bigint
@@ -1,3 +1,4 @@
1
+ import { type AuthRedaction, recordAuthValueSpan, redactWith } from '../../core/auth-redaction.js'
1
2
  import { BufferReader } from '../../core/buffer-reader.js'
2
3
  import { BufferWriter } from '../../core/buffer-writer.js'
3
4
  import { bytesToHex, hexToBytes } from '../../core/hex.js'
@@ -78,7 +79,7 @@ function encodeSetupParams(params: Draft14Params, writer: BufferWriter): void {
78
79
  if (params.role !== undefined) count++
79
80
  if (params.path !== undefined) count++
80
81
  if (params.max_request_id !== undefined) count++
81
- if (params.authorization_token !== undefined) count++
82
+ count += params.authorization_token?.length ?? 0
82
83
  if (params.authority !== undefined) count++
83
84
  if (params.max_auth_token_cache_size !== undefined) count++
84
85
  if (params.moqt_implementation !== undefined) count++
@@ -100,9 +101,9 @@ function encodeSetupParams(params: Draft14Params, writer: BufferWriter): void {
100
101
  writer.writeVarInt(PARAM_MAX_REQUEST_ID)
101
102
  writer.writeVarInt(params.max_request_id)
102
103
  }
103
- if (params.authorization_token !== undefined) {
104
+ for (const token of params.authorization_token ?? []) {
104
105
  writer.writeVarInt(PARAM_AUTHORIZATION_TOKEN)
105
- const tok = params.authorization_token
106
+ const tok = token
106
107
  const tmpWriter = new BufferWriter(64)
107
108
  tmpWriter.writeVarInt(tok.alias_type)
108
109
  if (tok.token_type !== undefined) {
@@ -183,11 +184,15 @@ function decodeSetupParams(reader: BufferReader): Draft14Params {
183
184
  if (tokenReader.remaining > 0) {
184
185
  tok.token_type = tokenReader.readVarInt()
185
186
  if (tokenReader.remaining > 0) {
186
- const tokenValue = tokenReader.readBytesView(tokenReader.remaining)
187
- tok.token_value = new Uint8Array(tokenValue)
187
+ const value = new Uint8Array(tokenReader.readBytesView(tokenReader.remaining))
188
+ tok.token_value = value
189
+ noteAuthTokenValue(reader.offset - length, length, value)
188
190
  }
189
191
  }
190
- result.authorization_token = tok as unknown as AuthorizationToken
192
+ result.authorization_token = [
193
+ ...(result.authorization_token ?? []),
194
+ tok as unknown as AuthorizationToken,
195
+ ]
191
196
  } else if (paramType === PARAM_AUTHORITY) {
192
197
  result.authority = textDecoder.decode(bytes)
193
198
  } else if (paramType === PARAM_MOQT_IMPLEMENTATION) {
@@ -209,7 +214,7 @@ function decodeSetupParams(reader: BufferReader): Draft14Params {
209
214
  function encodeMessageParams(params: Draft14Params, writer: BufferWriter): void {
210
215
  let count = 0
211
216
  if (params.delivery_timeout !== undefined) count++
212
- if (params.authorization_token !== undefined) count++
217
+ count += params.authorization_token?.length ?? 0
213
218
  if (params.max_cache_duration !== undefined) count++
214
219
  if (params.unknown) count += params.unknown.length
215
220
 
@@ -219,9 +224,9 @@ function encodeMessageParams(params: Draft14Params, writer: BufferWriter): void
219
224
  writer.writeVarInt(PARAM_DELIVERY_TIMEOUT)
220
225
  writer.writeVarInt(params.delivery_timeout)
221
226
  }
222
- if (params.authorization_token !== undefined) {
227
+ for (const token of params.authorization_token ?? []) {
223
228
  writer.writeVarInt(PARAM_AUTHORIZATION_TOKEN)
224
- const tok = params.authorization_token
229
+ const tok = token
225
230
  const tmpWriter = new BufferWriter(64)
226
231
  tmpWriter.writeVarInt(tok.alias_type)
227
232
  if (tok.token_type !== undefined) {
@@ -286,11 +291,15 @@ function decodeMessageParams(reader: BufferReader): Draft14Params {
286
291
  if (tokenReader.remaining > 0) {
287
292
  tok.token_type = tokenReader.readVarInt()
288
293
  if (tokenReader.remaining > 0) {
289
- const tokenValue = tokenReader.readBytesView(tokenReader.remaining)
290
- tok.token_value = new Uint8Array(tokenValue)
294
+ const value = new Uint8Array(tokenReader.readBytesView(tokenReader.remaining))
295
+ tok.token_value = value
296
+ noteAuthTokenValue(reader.offset - length, length, value)
291
297
  }
292
298
  }
293
- result.authorization_token = tok as unknown as AuthorizationToken
299
+ result.authorization_token = [
300
+ ...(result.authorization_token ?? []),
301
+ tok as unknown as AuthorizationToken,
302
+ ]
294
303
  } else {
295
304
  unknown.push({
296
305
  id: `0x${paramType.toString(16)}`,
@@ -1380,3 +1389,61 @@ export function createDraft14Codec(): Draft14Codec {
1380
1389
  createDataStreamDecoder,
1381
1390
  }
1382
1391
  }
1392
+
1393
+ /**
1394
+ * Record where a Token Value sits, so it can be overwritten before the frame
1395
+ * reaches anything that keeps it.
1396
+ *
1397
+ * The span falls out of the decode with no second walk. The Token Value is the
1398
+ * last field of the Token structure, so its start is the parameter value's end
1399
+ * minus the value's own length. The fields before it are left alone
1400
+ * deliberately: Alias Type, Token Alias and Token Type are structure rather
1401
+ * than secret, and they are what distinguishes a session that failed to
1402
+ * authenticate from one that never tried.
1403
+ *
1404
+ * A token carrying no value at all -- DELETE and USE_ALIAS -- records nothing,
1405
+ * and its frame passes through untouched.
1406
+ */
1407
+ function noteAuthTokenValue(
1408
+ valueStart: number,
1409
+ valueLength: number,
1410
+ value: Uint8Array | undefined,
1411
+ ): void {
1412
+ if (value === undefined || value.byteLength === 0) return
1413
+ recordAuthValueSpan(valueStart + valueLength - value.byteLength, value.byteLength)
1414
+ }
1415
+
1416
+ /**
1417
+ * Overwrite every Authorization Token value in a draft-14 control frame.
1418
+ *
1419
+ * One decode, whose *output is discarded*: the point is not to read the
1420
+ * message, it is to learn where the credentials were so the caller never has to
1421
+ * hold a frame that contains one. A caller that also wants the message should
1422
+ * decode the **redacted** frame with {@link decodeMessage}, which then cannot
1423
+ * produce a value because there is no longer one in the bytes.
1424
+ *
1425
+ * A frame that fails to decode is still redacted as far as the decode got. That
1426
+ * is the useful direction to fail in: a value that was read is a value that was
1427
+ * exposed, whatever went wrong after it.
1428
+ *
1429
+ * See {@link AuthRedaction.incomplete} for the one result a caller must not
1430
+ * treat as clean, and {@link AuthRedaction.decoded} for the residual it cannot
1431
+ * close.
1432
+ */
1433
+ export function redactAuthTokens(bytes: Uint8Array): AuthRedaction {
1434
+ let payloadStart: number
1435
+ try {
1436
+ const probe = new BufferReader(bytes)
1437
+ probe.readVarInt()
1438
+ probe.readUint8()
1439
+ probe.readUint8()
1440
+ payloadStart = probe.offset
1441
+ } catch {
1442
+ // Too short to carry a message header, and so too short for the parameters
1443
+ // that carry a credential. Reported as not decoded rather than as clean: a
1444
+ // framer only ever emits complete frames, so a caller that gets here is
1445
+ // holding something this function did not check.
1446
+ return { bytes, redacted: 0, incomplete: false, decoded: false }
1447
+ }
1448
+ return redactWith(bytes, payloadStart, () => decodeMessage(bytes).ok)
1449
+ }