@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'
@@ -146,15 +147,15 @@ function decodeSetupParams(r: BufferReader): Draft11SetupParams {
146
147
 
147
148
  function encodeParams(params: Draft11Params, w: BufferWriter): void {
148
149
  let count = params.unknown ? params.unknown.length : 0
149
- if (params.authorization_token !== undefined) count++
150
+ count += params.authorization_token?.length ?? 0
150
151
  if (params.delivery_timeout !== undefined) count++
151
152
  if (params.max_cache_duration !== undefined) count++
152
153
  w.writeVarInt(count)
153
154
 
154
- if (params.authorization_token !== undefined) {
155
+ for (const token of params.authorization_token ?? []) {
155
156
  // AUTHORIZATION_TOKEN = 0x01 (odd → length-prefixed)
156
157
  w.writeVarInt(PARAM_AUTHORIZATION_TOKEN)
157
- const at = params.authorization_token
158
+ const at = token
158
159
  const tmpW = new BufferWriter(64)
159
160
  tmpW.writeVarInt(at.alias_type)
160
161
  tmpW.writeVarInt(at.token_type)
@@ -227,11 +228,15 @@ function decodeParams(r: BufferReader): Draft11Params {
227
228
  const token_type = r.readVarInt()
228
229
  const tokenBytesLen = length - (r.offset - startOff)
229
230
  const tokenBytes = r.readBytes(tokenBytesLen)
230
- result.authorization_token = {
231
- alias_type,
232
- token_type,
233
- token_value: tokenBytes,
234
- }
231
+ noteAuthTokenValue(startOff, length, tokenBytes)
232
+ result.authorization_token = [
233
+ ...(result.authorization_token ?? []),
234
+ {
235
+ alias_type,
236
+ token_type,
237
+ token_value: tokenBytes,
238
+ },
239
+ ]
235
240
  } else {
236
241
  const bytes = r.readBytes(length)
237
242
  unknown.push({
@@ -1051,3 +1056,61 @@ export function createDraft11Codec(): Draft11Codec {
1051
1056
  createStreamDecoder,
1052
1057
  }
1053
1058
  }
1059
+
1060
+ /**
1061
+ * Record where a Token Value sits, so it can be overwritten before the frame
1062
+ * reaches anything that keeps it.
1063
+ *
1064
+ * The span falls out of the decode with no second walk. The Token Value is the
1065
+ * last field of the Token structure, so its start is the parameter value's end
1066
+ * minus the value's own length. The fields before it are left alone
1067
+ * deliberately: Alias Type, Token Alias and Token Type are structure rather
1068
+ * than secret, and they are what distinguishes a session that failed to
1069
+ * authenticate from one that never tried.
1070
+ *
1071
+ * A token carrying no value at all -- DELETE and USE_ALIAS -- records nothing,
1072
+ * and its frame passes through untouched.
1073
+ */
1074
+ function noteAuthTokenValue(
1075
+ valueStart: number,
1076
+ valueLength: number,
1077
+ value: Uint8Array | undefined,
1078
+ ): void {
1079
+ if (value === undefined || value.byteLength === 0) return
1080
+ recordAuthValueSpan(valueStart + valueLength - value.byteLength, value.byteLength)
1081
+ }
1082
+
1083
+ /**
1084
+ * Overwrite every Authorization Token value in a draft-11 control frame.
1085
+ *
1086
+ * One decode, whose *output is discarded*: the point is not to read the
1087
+ * message, it is to learn where the credentials were so the caller never has to
1088
+ * hold a frame that contains one. A caller that also wants the message should
1089
+ * decode the **redacted** frame with {@link decodeMessage}, which then cannot
1090
+ * produce a value because there is no longer one in the bytes.
1091
+ *
1092
+ * A frame that fails to decode is still redacted as far as the decode got. That
1093
+ * is the useful direction to fail in: a value that was read is a value that was
1094
+ * exposed, whatever went wrong after it.
1095
+ *
1096
+ * See {@link AuthRedaction.incomplete} for the one result a caller must not
1097
+ * treat as clean, and {@link AuthRedaction.decoded} for the residual it cannot
1098
+ * close.
1099
+ */
1100
+ export function redactAuthTokens(bytes: Uint8Array): AuthRedaction {
1101
+ let payloadStart: number
1102
+ try {
1103
+ const probe = new BufferReader(bytes)
1104
+ probe.readVarInt()
1105
+ probe.readUint8()
1106
+ probe.readUint8()
1107
+ payloadStart = probe.offset
1108
+ } catch {
1109
+ // Too short to carry a message header, and so too short for the parameters
1110
+ // that carry a credential. Reported as not decoded rather than as clean: a
1111
+ // framer only ever emits complete frames, so a caller that gets here is
1112
+ // holding something this function did not check.
1113
+ return { bytes, redacted: 0, incomplete: false, decoded: false }
1114
+ }
1115
+ return redactWith(bytes, payloadStart, () => decodeMessage(bytes).ok)
1116
+ }
@@ -0,0 +1,106 @@
1
+ // Draft-11 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
+ } as const
21
+ export type SessionErrorCodeValue = (typeof SessionErrorCode)[keyof typeof SessionErrorCode]
22
+
23
+ export const SubscribeErrorCode = {
24
+ InternalError: 0x0n,
25
+ Unauthorized: 0x1n,
26
+ Timeout: 0x2n,
27
+ NotSupported: 0x3n,
28
+ TrackDoesNotExist: 0x4n,
29
+ InvalidRange: 0x5n,
30
+ RetryTrackAlias: 0x6n,
31
+ MalformedAuthToken: 0x10n,
32
+ UnknownAuthTokenAlias: 0x11n,
33
+ ExpiredAuthToken: 0x12n,
34
+ } as const
35
+ export type SubscribeErrorCodeValue = (typeof SubscribeErrorCode)[keyof typeof SubscribeErrorCode]
36
+
37
+ export const SubscribeDoneStatusCode = {
38
+ InternalError: 0x0n,
39
+ Unauthorized: 0x1n,
40
+ TrackEnded: 0x2n,
41
+ SubscriptionEnded: 0x3n,
42
+ GoingAway: 0x4n,
43
+ Expired: 0x5n,
44
+ TooFarBehind: 0x6n,
45
+ } as const
46
+ export type SubscribeDoneStatusCodeValue =
47
+ (typeof SubscribeDoneStatusCode)[keyof typeof SubscribeDoneStatusCode]
48
+
49
+ export const FetchErrorCode = {
50
+ InternalError: 0x0n,
51
+ Unauthorized: 0x1n,
52
+ Timeout: 0x2n,
53
+ NotSupported: 0x3n,
54
+ TrackDoesNotExist: 0x4n,
55
+ InvalidRange: 0x5n,
56
+ NoObjects: 0x6n,
57
+ InvalidJoiningSubscribeId: 0x7n,
58
+ MalformedAuthToken: 0x10n,
59
+ UnknownAuthTokenAlias: 0x11n,
60
+ ExpiredAuthToken: 0x12n,
61
+ } as const
62
+ export type FetchErrorCodeValue = (typeof FetchErrorCode)[keyof typeof FetchErrorCode]
63
+
64
+ export const AnnounceErrorCode = {
65
+ InternalError: 0x0n,
66
+ Unauthorized: 0x1n,
67
+ Timeout: 0x2n,
68
+ NotSupported: 0x3n,
69
+ Uninterested: 0x4n,
70
+ MalformedAuthToken: 0x10n,
71
+ UnknownAuthTokenAlias: 0x11n,
72
+ ExpiredAuthToken: 0x12n,
73
+ } as const
74
+ export type AnnounceErrorCodeValue = (typeof AnnounceErrorCode)[keyof typeof AnnounceErrorCode]
75
+
76
+ export const SubscribeAnnouncesErrorCode = {
77
+ InternalError: 0x0n,
78
+ Unauthorized: 0x1n,
79
+ Timeout: 0x2n,
80
+ NotSupported: 0x3n,
81
+ NamespacePrefixUnknown: 0x4n,
82
+ NamespacePrefixOverlap: 0x5n,
83
+ MalformedAuthToken: 0x10n,
84
+ UnknownAuthTokenAlias: 0x11n,
85
+ ExpiredAuthToken: 0x12n,
86
+ } as const
87
+ export type SubscribeAnnouncesErrorCodeValue =
88
+ (typeof SubscribeAnnouncesErrorCode)[keyof typeof SubscribeAnnouncesErrorCode]
89
+
90
+ export const TrackStatusCode = {
91
+ InProgress: 0x00n,
92
+ TrackDoesNotExist: 0x01n,
93
+ NotYetBegun: 0x02n,
94
+ Finished: 0x03n,
95
+ RelayStatusUnavailable: 0x04n,
96
+ } as const
97
+ export type TrackStatusCodeValue = (typeof TrackStatusCode)[keyof typeof TrackStatusCode]
98
+
99
+ export const StreamResetErrorCode = {
100
+ InternalError: 0x0n,
101
+ Cancelled: 0x1n,
102
+ DeliveryTimeout: 0x2n,
103
+ SessionClosed: 0x3n,
104
+ } as const
105
+ export type StreamResetErrorCodeValue =
106
+ (typeof StreamResetErrorCode)[keyof typeof StreamResetErrorCode]
@@ -1,5 +1,7 @@
1
1
  export const DRAFT_VERSION = 0xff00000bn
2
2
 
3
+ export type { AuthRedaction } from '../../core/auth-redaction.js'
4
+ export { REDACTION_FILL } from '../../core/auth-redaction.js'
3
5
  export type { Draft11Codec } from './codec.js'
4
6
  export {
5
7
  createDraft11Codec,
@@ -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
+ SessionErrorCodeValue,
24
+ StreamResetErrorCodeValue,
25
+ SubscribeAnnouncesErrorCodeValue,
26
+ SubscribeDoneStatusCodeValue,
27
+ SubscribeErrorCodeValue,
28
+ TrackStatusCodeValue,
29
+ } from './error-codes.js'
30
+ export {
31
+ AnnounceErrorCode,
32
+ FetchErrorCode,
33
+ SessionErrorCode,
34
+ StreamResetErrorCode,
35
+ SubscribeAnnouncesErrorCode,
36
+ SubscribeDoneStatusCode,
37
+ SubscribeErrorCode,
38
+ TrackStatusCode,
39
+ } from './error-codes.js'
17
40
  export {
18
41
  MESSAGE_ID_MAP,
19
42
  MESSAGE_TYPE_MAP,
@@ -24,7 +24,7 @@ export interface Draft11SetupParams {
24
24
 
25
25
  // Version-specific parameters — even/odd convention
26
26
  export interface Draft11Params {
27
- authorization_token?: AuthorizationToken // 0x01 odd
27
+ authorization_token?: readonly AuthorizationToken[] // 0x01 odd
28
28
  delivery_timeout?: bigint // 0x02 even
29
29
  max_cache_duration?: bigint // 0x04 even
30
30
  unknown?: UnknownParam[]
@@ -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'
@@ -73,7 +74,7 @@ function encodeSetupParams(params: Draft12SetupParams, w: BufferWriter): void {
73
74
  let count = 0
74
75
  if (params.path !== undefined) count++
75
76
  if (params.max_request_id !== undefined) count++
76
- if (params.authorization_token !== undefined) count++
77
+ count += params.authorization_token?.length ?? 0
77
78
  if (params.unknown) count += params.unknown.length
78
79
 
79
80
  w.writeVarInt(count)
@@ -88,9 +89,9 @@ function encodeSetupParams(params: Draft12SetupParams, w: BufferWriter): void {
88
89
  w.writeVarInt(SETUP_PARAM_MAX_REQUEST_ID)
89
90
  w.writeVarInt(params.max_request_id)
90
91
  }
91
- if (params.authorization_token !== undefined) {
92
+ for (const token of params.authorization_token ?? []) {
92
93
  w.writeVarInt(PARAM_AUTHORIZATION_TOKEN)
93
- const at = params.authorization_token
94
+ const at = token
94
95
  const tmpW = new BufferWriter(64)
95
96
  tmpW.writeVarInt(at.alias_type)
96
97
  tmpW.writeVarInt(at.token_type)
@@ -148,11 +149,15 @@ function decodeSetupParams(r: BufferReader): Draft12SetupParams {
148
149
  const token_type = r.readVarInt()
149
150
  const tokenBytesLen = length - (r.offset - startOff)
150
151
  const tokenBytes = r.readBytes(tokenBytesLen)
151
- result.authorization_token = {
152
- alias_type,
153
- token_type,
154
- token_value: tokenBytes,
155
- }
152
+ noteAuthTokenValue(startOff, length, tokenBytes)
153
+ result.authorization_token = [
154
+ ...(result.authorization_token ?? []),
155
+ {
156
+ alias_type,
157
+ token_type,
158
+ token_value: tokenBytes,
159
+ },
160
+ ]
156
161
  } else {
157
162
  const bytes = r.readBytes(length)
158
163
  unknown.push({
@@ -174,7 +179,7 @@ function decodeSetupParams(r: BufferReader): Draft12SetupParams {
174
179
  function encodeParams(params: Draft12Params, w: BufferWriter): void {
175
180
  let count = params.unknown ? params.unknown.length : 0
176
181
  if (params.delivery_timeout !== undefined) count++
177
- if (params.authorization_token !== undefined) count++
182
+ count += params.authorization_token?.length ?? 0
178
183
  if (params.max_cache_duration !== undefined) count++
179
184
  w.writeVarInt(count)
180
185
 
@@ -183,10 +188,10 @@ function encodeParams(params: Draft12Params, w: BufferWriter): void {
183
188
  w.writeVarInt(PARAM_DELIVERY_TIMEOUT)
184
189
  w.writeVarInt(params.delivery_timeout)
185
190
  }
186
- if (params.authorization_token !== undefined) {
191
+ for (const token of params.authorization_token ?? []) {
187
192
  // AUTHORIZATION_TOKEN = 0x03 (odd → length-prefixed)
188
193
  w.writeVarInt(PARAM_AUTHORIZATION_TOKEN)
189
- const at = params.authorization_token
194
+ const at = token
190
195
  const tmpW = new BufferWriter(64)
191
196
  tmpW.writeVarInt(at.alias_type)
192
197
  tmpW.writeVarInt(at.token_type)
@@ -254,11 +259,15 @@ function decodeParams(r: BufferReader): Draft12Params {
254
259
  const token_type = r.readVarInt()
255
260
  const tokenBytesLen = length - (r.offset - startOff)
256
261
  const tokenBytes = r.readBytes(tokenBytesLen)
257
- result.authorization_token = {
258
- alias_type,
259
- token_type,
260
- token_value: tokenBytes,
261
- }
262
+ noteAuthTokenValue(startOff, length, tokenBytes)
263
+ result.authorization_token = [
264
+ ...(result.authorization_token ?? []),
265
+ {
266
+ alias_type,
267
+ token_type,
268
+ token_value: tokenBytes,
269
+ },
270
+ ]
262
271
  } else {
263
272
  const bytes = r.readBytes(length)
264
273
  unknown.push({
@@ -1199,3 +1208,61 @@ export function createDraft12Codec(): Draft12Codec {
1199
1208
  createStreamDecoder,
1200
1209
  }
1201
1210
  }
1211
+
1212
+ /**
1213
+ * Record where a Token Value sits, so it can be overwritten before the frame
1214
+ * reaches anything that keeps it.
1215
+ *
1216
+ * The span falls out of the decode with no second walk. The Token Value is the
1217
+ * last field of the Token structure, so its start is the parameter value's end
1218
+ * minus the value's own length. The fields before it are left alone
1219
+ * deliberately: Alias Type, Token Alias and Token Type are structure rather
1220
+ * than secret, and they are what distinguishes a session that failed to
1221
+ * authenticate from one that never tried.
1222
+ *
1223
+ * A token carrying no value at all -- DELETE and USE_ALIAS -- records nothing,
1224
+ * and its frame passes through untouched.
1225
+ */
1226
+ function noteAuthTokenValue(
1227
+ valueStart: number,
1228
+ valueLength: number,
1229
+ value: Uint8Array | undefined,
1230
+ ): void {
1231
+ if (value === undefined || value.byteLength === 0) return
1232
+ recordAuthValueSpan(valueStart + valueLength - value.byteLength, value.byteLength)
1233
+ }
1234
+
1235
+ /**
1236
+ * Overwrite every Authorization Token value in a draft-12 control frame.
1237
+ *
1238
+ * One decode, whose *output is discarded*: the point is not to read the
1239
+ * message, it is to learn where the credentials were so the caller never has to
1240
+ * hold a frame that contains one. A caller that also wants the message should
1241
+ * decode the **redacted** frame with {@link decodeMessage}, which then cannot
1242
+ * produce a value because there is no longer one in the bytes.
1243
+ *
1244
+ * A frame that fails to decode is still redacted as far as the decode got. That
1245
+ * is the useful direction to fail in: a value that was read is a value that was
1246
+ * exposed, whatever went wrong after it.
1247
+ *
1248
+ * See {@link AuthRedaction.incomplete} for the one result a caller must not
1249
+ * treat as clean, and {@link AuthRedaction.decoded} for the residual it cannot
1250
+ * close.
1251
+ */
1252
+ export function redactAuthTokens(bytes: Uint8Array): AuthRedaction {
1253
+ let payloadStart: number
1254
+ try {
1255
+ const probe = new BufferReader(bytes)
1256
+ probe.readVarInt()
1257
+ probe.readUint8()
1258
+ probe.readUint8()
1259
+ payloadStart = probe.offset
1260
+ } catch {
1261
+ // Too short to carry a message header, and so too short for the parameters
1262
+ // that carry a credential. Reported as not decoded rather than as clean: a
1263
+ // framer only ever emits complete frames, so a caller that gets here is
1264
+ // holding something this function did not check.
1265
+ return { bytes, redacted: 0, incomplete: false, decoded: false }
1266
+ }
1267
+ return redactWith(bytes, payloadStart, () => decodeMessage(bytes).ok)
1268
+ }
@@ -0,0 +1,116 @@
1
+ // Draft-12 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 SubscribeAnnouncesErrorCode = {
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 SubscribeAnnouncesErrorCodeValue =
98
+ (typeof SubscribeAnnouncesErrorCode)[keyof typeof SubscribeAnnouncesErrorCode]
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]
108
+
109
+ export const TrackStatusCode = {
110
+ InProgress: 0x00n,
111
+ TrackDoesNotExist: 0x01n,
112
+ NotYetBegun: 0x02n,
113
+ Finished: 0x03n,
114
+ RelayStatusUnavailable: 0x04n,
115
+ } as const
116
+ export type TrackStatusCodeValue = (typeof TrackStatusCode)[keyof typeof TrackStatusCode]
@@ -1,5 +1,7 @@
1
1
  export const DRAFT_VERSION = 0xff00000cn
2
2
 
3
+ export type { AuthRedaction } from '../../core/auth-redaction.js'
4
+ export { REDACTION_FILL } from '../../core/auth-redaction.js'
3
5
  export type { Draft12Codec } from './codec.js'
4
6
  export {
5
7
  createDraft12Codec,
@@ -13,7 +15,30 @@ 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
+ SubscribeAnnouncesErrorCodeValue,
27
+ SubscribeDoneStatusCodeValue,
28
+ SubscribeErrorCodeValue,
29
+ TrackStatusCodeValue,
30
+ } from './error-codes.js'
31
+ export {
32
+ AnnounceErrorCode,
33
+ FetchErrorCode,
34
+ PublishErrorCode,
35
+ SessionErrorCode,
36
+ StreamResetErrorCode,
37
+ SubscribeAnnouncesErrorCode,
38
+ SubscribeDoneStatusCode,
39
+ SubscribeErrorCode,
40
+ TrackStatusCode,
41
+ } from './error-codes.js'
17
42
  export {
18
43
  MESSAGE_ID_MAP,
19
44
  MESSAGE_TYPE_MAP,
@@ -19,14 +19,14 @@ export interface AuthorizationToken {
19
19
  export interface Draft12SetupParams {
20
20
  path?: string // 0x01 odd
21
21
  max_request_id?: bigint // 0x02 even
22
- authorization_token?: AuthorizationToken // 0x03 odd
22
+ authorization_token?: readonly AuthorizationToken[] // 0x03 odd
23
23
  unknown?: UnknownParam[]
24
24
  }
25
25
 
26
26
  // Version-specific parameters — even/odd convention
27
27
  export interface Draft12Params {
28
28
  delivery_timeout?: bigint // 0x02 even
29
- authorization_token?: AuthorizationToken // 0x03 odd
29
+ authorization_token?: readonly AuthorizationToken[] // 0x03 odd
30
30
  max_cache_duration?: bigint // 0x04 even
31
31
  unknown?: UnknownParam[]
32
32
  }