@moqtap/codec 0.2.3 → 0.4.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 (313) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +100 -99
  3. package/dist/{chunk-RZHAPEXO.js → chunk-2A57DRXV.js} +36 -10
  4. package/dist/{chunk-73MWUKSJ.js → chunk-2UTVXWFF.js} +190 -102
  5. package/dist/{chunk-JTVCOMBI.cjs → chunk-3XKO6PCR.cjs} +290 -183
  6. package/dist/{chunk-ACQ4CUJP.cjs → chunk-4BDEU3D4.cjs} +237 -158
  7. package/dist/{chunk-4N4INRE7.cjs → chunk-4HBKHNU2.cjs} +144 -110
  8. package/dist/{chunk-2ZT6CVSE.js → chunk-4IVZZOY3.js} +269 -162
  9. package/dist/{chunk-GLBQDG4L.cjs → chunk-5O764MBD.cjs} +508 -117
  10. package/dist/chunk-7KBAWOBA.js +1212 -0
  11. package/dist/{chunk-JSQM2MG3.js → chunk-7QOPNSDF.js} +44 -12
  12. package/dist/{chunk-SYHW3FLI.cjs → chunk-7RE6KSIY.cjs} +28 -8
  13. package/dist/{chunk-YG5KJESI.js → chunk-AY6IAHUM.js} +28 -8
  14. package/dist/{chunk-EFM5T7OM.js → chunk-BLQDWOSG.js} +36 -10
  15. package/dist/{chunk-UYXTY6ZQ.cjs → chunk-E65QKRSN.cjs} +20 -12
  16. package/dist/{chunk-BISI45MN.cjs → chunk-EAHE3IOG.cjs} +44 -12
  17. package/dist/{chunk-PZBPH2D7.js → chunk-GCBFHZW6.js} +216 -137
  18. package/dist/{chunk-GXEW4COZ.cjs → chunk-H5NSL4MO.cjs} +36 -10
  19. package/dist/chunk-HZHSO7EW.cjs +1212 -0
  20. package/dist/{chunk-KZCYQ7ED.cjs → chunk-IILNSDEQ.cjs} +69 -41
  21. package/dist/{chunk-4XYGE53S.cjs → chunk-J3XCPBW3.cjs} +36 -10
  22. package/dist/{chunk-6AEHWULA.cjs → chunk-JKOEJZ5B.cjs} +28 -8
  23. package/dist/{chunk-RUPCJTC3.cjs → chunk-JL3NEW3O.cjs} +23 -1
  24. package/dist/{chunk-G7GI7LJA.js → chunk-LORZMJJB.js} +36 -10
  25. package/dist/{chunk-DUBCL3WF.cjs → chunk-LV5C6MEC.cjs} +36 -10
  26. package/dist/{chunk-ENURAVHI.cjs → chunk-MYXAD5JC.cjs} +44 -12
  27. package/dist/{chunk-FXZ2MYKJ.js → chunk-MZ7HUCGJ.js} +20 -12
  28. package/dist/{chunk-S74DWJE2.cjs → chunk-OKG2HT25.cjs} +277 -88
  29. package/dist/{chunk-BGWGVINJ.cjs → chunk-PKEOQSSZ.cjs} +144 -110
  30. package/dist/{chunk-2GODRVT5.js → chunk-Q46ZURKX.js} +325 -48
  31. package/dist/{chunk-UR6JKS56.js → chunk-Q7IGWV3P.js} +41 -9
  32. package/dist/{chunk-XSNX2IUJ.js → chunk-RW4UG7CN.js} +121 -87
  33. package/dist/{chunk-DWK5ZQZ4.js → chunk-RZTLQAKF.js} +28 -8
  34. package/dist/{chunk-UNS34PTA.cjs → chunk-S6IPIN66.cjs} +44 -12
  35. package/dist/{chunk-YIG2C3LF.cjs → chunk-SDWRXXOO.cjs} +214 -126
  36. package/dist/{chunk-CEH7ESNC.js → chunk-SHMA4PBY.js} +121 -87
  37. package/dist/{chunk-MC7W6PMI.js → chunk-U3ZVLT5L.js} +483 -135
  38. package/dist/{chunk-VJUUZ4W2.cjs → chunk-UJU63EFY.cjs} +374 -97
  39. package/dist/{chunk-7L43FE6P.js → chunk-VOU7PNHI.js} +23 -1
  40. package/dist/{chunk-E6E3NQYU.js → chunk-WRHGCVYN.js} +44 -12
  41. package/dist/{chunk-FPISPJ5N.cjs → chunk-XNWYLVGU.cjs} +529 -181
  42. package/dist/{chunk-U3IPZYPX.js → chunk-XS77RBY7.js} +228 -39
  43. package/dist/{chunk-JGG7CMSZ.cjs → chunk-XZE5R57R.cjs} +144 -110
  44. package/dist/{chunk-77MNXX3M.js → chunk-Y6KCSM3V.js} +121 -87
  45. package/dist/{chunk-TLYNOOQP.cjs → chunk-YTPZZI2M.cjs} +41 -9
  46. package/dist/{chunk-7DUBLRXC.js → chunk-YWRCSQBA.js} +44 -12
  47. package/dist/{chunk-MRJWLGYH.js → chunk-Z3VKP3PJ.js} +69 -41
  48. package/dist/{chunk-E6P74GDT.js → chunk-Z6U26IRI.js} +464 -73
  49. package/dist/{codec-FvGCxIhr.d.ts → codec-25u4_1HS.d.ts} +4 -4
  50. package/dist/{codec-DRcsBCsb.d.ts → codec-3Ppy_5Gd.d.ts} +4 -4
  51. package/dist/{codec-BdVMRMOI.d.ts → codec-BB0U8MF2.d.cts} +4 -4
  52. package/dist/{codec-B2cH-f5V.d.cts → codec-BHHfBTnV.d.ts} +4 -4
  53. package/dist/{codec-B5K73Bdj.d.ts → codec-BN6jk0Td.d.cts} +4 -4
  54. package/dist/{codec-R8GrCPt2.d.ts → codec-BU0gaSZm.d.ts} +4 -4
  55. package/dist/{codec-Bq-tLtfP.d.ts → codec-C-Yk2RNa.d.ts} +4 -4
  56. package/dist/codec-CFWQY9Lj.d.cts +18 -0
  57. package/dist/{codec-CPlK3Pi5.d.ts → codec-COy4uuPO.d.cts} +4 -4
  58. package/dist/codec-CewFCsEy.d.ts +18 -0
  59. package/dist/{codec-KXHvXZVb.d.cts → codec-Ck7ZwFF1.d.cts} +4 -4
  60. package/dist/{codec-DZhZSIii.d.cts → codec-D2QVSH9D.d.ts} +4 -4
  61. package/dist/{codec-BwFgpeQu.d.ts → codec-DDUBJGn0.d.cts} +4 -4
  62. package/dist/{codec-BFeliJFc.d.ts → codec-DNfml-se.d.ts} +4 -4
  63. package/dist/{codec-C4n1PS09.d.cts → codec-DoOGjjDq.d.cts} +4 -4
  64. package/dist/{codec-Bap882Fh.d.cts → codec-J7ekOSMc.d.ts} +4 -4
  65. package/dist/{codec-SKBeHQk7.d.ts → codec-R9TJCq-E.d.cts} +4 -4
  66. package/dist/{codec-DNUIgLqc.d.cts → codec-ZwV-Njt6.d.ts} +4 -4
  67. package/dist/{codec-HgBgHkFI.d.cts → codec-j819z_hL.d.cts} +4 -4
  68. package/dist/{codec-DY4QH364.d.cts → codec-w8z2j_uo.d.cts} +4 -4
  69. package/dist/{codec-CPvPq0sb.d.cts → codec-wtt6WF1K.d.ts} +4 -4
  70. package/dist/{codec-BUMjz0J4.d.cts → codec-z6_2PSzi.d.cts} +4 -4
  71. package/dist/{draft7-session.cjs → draft07-session.cjs} +2 -2
  72. package/dist/draft07-session.d.cts +8 -0
  73. package/dist/draft07-session.d.ts +8 -0
  74. package/dist/{draft7-session.js → draft07-session.js} +1 -1
  75. package/dist/draft07.cjs +129 -0
  76. package/dist/draft07.d.cts +67 -0
  77. package/dist/draft07.d.ts +67 -0
  78. package/dist/draft07.js +129 -0
  79. package/dist/draft08-session.cjs +6 -0
  80. package/dist/draft08-session.d.cts +8 -0
  81. package/dist/draft08-session.d.ts +8 -0
  82. package/dist/{draft8-session.js → draft08-session.js} +1 -1
  83. package/dist/draft08.cjs +119 -0
  84. package/dist/{draft8.d.cts → draft08.d.cts} +15 -13
  85. package/dist/{draft8.d.ts → draft08.d.ts} +15 -13
  86. package/dist/{draft8.js → draft08.js} +7 -4
  87. package/dist/draft09-session.cjs +6 -0
  88. package/dist/draft09-session.d.cts +8 -0
  89. package/dist/draft09-session.d.ts +8 -0
  90. package/dist/{draft9-session.js → draft09-session.js} +1 -1
  91. package/dist/draft09.cjs +119 -0
  92. package/dist/{draft9.d.cts → draft09.d.cts} +15 -13
  93. package/dist/{draft9.d.ts → draft09.d.ts} +15 -13
  94. package/dist/{draft9.js → draft09.js} +7 -4
  95. package/dist/draft10-session.cjs +2 -2
  96. package/dist/draft10-session.d.cts +6 -6
  97. package/dist/draft10-session.d.ts +6 -6
  98. package/dist/draft10-session.js +1 -1
  99. package/dist/draft10.cjs +8 -5
  100. package/dist/draft10.d.cts +14 -12
  101. package/dist/draft10.d.ts +14 -12
  102. package/dist/draft10.js +16 -13
  103. package/dist/draft11-session.cjs +2 -2
  104. package/dist/draft11-session.d.cts +6 -6
  105. package/dist/draft11-session.d.ts +6 -6
  106. package/dist/draft11-session.js +1 -1
  107. package/dist/draft11.cjs +8 -5
  108. package/dist/draft11.d.cts +14 -12
  109. package/dist/draft11.d.ts +14 -12
  110. package/dist/draft11.js +16 -13
  111. package/dist/draft12-session.cjs +2 -2
  112. package/dist/draft12-session.d.cts +6 -6
  113. package/dist/draft12-session.d.ts +6 -6
  114. package/dist/draft12-session.js +1 -1
  115. package/dist/draft12.cjs +8 -5
  116. package/dist/draft12.d.cts +16 -14
  117. package/dist/draft12.d.ts +16 -14
  118. package/dist/draft12.js +16 -13
  119. package/dist/draft13-session.cjs +2 -2
  120. package/dist/draft13-session.d.cts +6 -6
  121. package/dist/draft13-session.d.ts +6 -6
  122. package/dist/draft13-session.js +1 -1
  123. package/dist/draft13.cjs +8 -5
  124. package/dist/draft13.d.cts +16 -14
  125. package/dist/draft13.d.ts +16 -14
  126. package/dist/draft13.js +16 -13
  127. package/dist/draft14-session.cjs +2 -2
  128. package/dist/draft14-session.d.cts +6 -6
  129. package/dist/draft14-session.d.ts +6 -6
  130. package/dist/draft14-session.js +1 -1
  131. package/dist/draft14.cjs +14 -5
  132. package/dist/draft14.d.cts +14 -12
  133. package/dist/draft14.d.ts +14 -12
  134. package/dist/draft14.js +13 -4
  135. package/dist/draft15-session.cjs +2 -2
  136. package/dist/draft15-session.d.cts +6 -6
  137. package/dist/draft15-session.d.ts +6 -6
  138. package/dist/draft15-session.js +1 -1
  139. package/dist/draft15.cjs +8 -5
  140. package/dist/draft15.d.cts +14 -12
  141. package/dist/draft15.d.ts +14 -12
  142. package/dist/draft15.js +16 -13
  143. package/dist/draft16-session.cjs +2 -2
  144. package/dist/draft16-session.d.cts +6 -6
  145. package/dist/draft16-session.d.ts +6 -6
  146. package/dist/draft16-session.js +1 -1
  147. package/dist/draft16.cjs +8 -5
  148. package/dist/draft16.d.cts +14 -12
  149. package/dist/draft16.d.ts +14 -12
  150. package/dist/draft16.js +16 -13
  151. package/dist/draft17-session.cjs +2 -2
  152. package/dist/draft17-session.d.cts +7 -7
  153. package/dist/draft17-session.d.ts +7 -7
  154. package/dist/draft17-session.js +1 -1
  155. package/dist/draft17.cjs +8 -5
  156. package/dist/draft17.d.cts +11 -9
  157. package/dist/draft17.d.ts +11 -9
  158. package/dist/draft17.js +16 -13
  159. package/dist/index.cjs +52 -74
  160. package/dist/index.d.cts +41 -60
  161. package/dist/index.d.ts +41 -60
  162. package/dist/index.js +40 -62
  163. package/dist/{session-types-CJIFbTPd.d.ts → session-types-C7UONex5.d.cts} +28 -27
  164. package/dist/{session-types-Cbq8IGCP.d.cts → session-types-X-IYEGoG.d.ts} +28 -27
  165. package/dist/session.cjs +46 -13
  166. package/dist/session.d.cts +29 -11
  167. package/dist/session.d.ts +29 -11
  168. package/dist/session.js +46 -13
  169. package/dist/{types-DxSFvL2b.d.cts → types--Q7_DcvP.d.cts} +43 -39
  170. package/dist/{types-DxSFvL2b.d.ts → types--Q7_DcvP.d.ts} +43 -39
  171. package/dist/{types-B0FT5Qs2.d.cts → types-0IWbU9Z_.d.cts} +36 -36
  172. package/dist/{types-B0FT5Qs2.d.ts → types-0IWbU9Z_.d.ts} +36 -36
  173. package/dist/{types-gQsr0AAA.d.cts → types-B3g5G9KP.d.cts} +36 -36
  174. package/dist/{types-gQsr0AAA.d.ts → types-B3g5G9KP.d.ts} +36 -36
  175. package/dist/{types-Pme7sua0.d.cts → types-BFpFNM_m.d.cts} +57 -32
  176. package/dist/{types-Pme7sua0.d.ts → types-BFpFNM_m.d.ts} +57 -32
  177. package/dist/{types-8gUGeMgs.d.cts → types-Br7fm2mf.d.cts} +48 -26
  178. package/dist/{types-8gUGeMgs.d.ts → types-Br7fm2mf.d.ts} +48 -26
  179. package/dist/{types-BeAVNU-F.d.cts → types-C2qKTRR_.d.cts} +50 -45
  180. package/dist/{types-BeAVNU-F.d.ts → types-C2qKTRR_.d.ts} +50 -45
  181. package/dist/{types-DKpsfD3i.d.cts → types-DEaypVsD.d.cts} +115 -55
  182. package/dist/{types-DKpsfD3i.d.ts → types-DEaypVsD.d.ts} +115 -55
  183. package/dist/types-Dl4IaAHR.d.cts +282 -0
  184. package/dist/types-Dl4IaAHR.d.ts +282 -0
  185. package/dist/{types-CDa7F5ct.d.cts → types-DrQpTW1G.d.cts} +58 -50
  186. package/dist/{types-CDa7F5ct.d.ts → types-DrQpTW1G.d.ts} +58 -50
  187. package/dist/types-DuIO7cWK.d.cts +25 -0
  188. package/dist/types-DuIO7cWK.d.ts +25 -0
  189. package/dist/{types-B9A2g05r.d.cts → types-DuxfOYiO.d.cts} +47 -31
  190. package/dist/{types-B9A2g05r.d.ts → types-DuxfOYiO.d.ts} +47 -31
  191. package/dist/{types-D1dI_oTX.d.cts → types-jV1yDDBA.d.cts} +36 -36
  192. package/dist/{types-D1dI_oTX.d.ts → types-jV1yDDBA.d.ts} +36 -36
  193. package/package.json +192 -192
  194. package/src/core/buffer-reader.ts +130 -130
  195. package/src/core/buffer-writer.ts +100 -100
  196. package/src/core/errors.ts +1 -1
  197. package/src/core/hex.ts +21 -21
  198. package/src/core/session-types.ts +61 -59
  199. package/src/core/types.ts +18 -361
  200. package/src/drafts/draft07/codec.ts +1058 -938
  201. package/src/drafts/draft07/data-streams.ts +240 -240
  202. package/src/drafts/draft07/index.ts +124 -89
  203. package/src/drafts/draft07/messages.ts +76 -42
  204. package/src/drafts/draft07/rules.ts +107 -101
  205. package/src/drafts/draft07/session-fsm.ts +315 -287
  206. package/src/drafts/draft07/session.ts +8 -6
  207. package/src/drafts/draft07/types.ts +406 -72
  208. package/src/drafts/draft07/varint.ts +51 -51
  209. package/src/drafts/draft08/codec.ts +985 -953
  210. package/src/drafts/draft08/data-streams.ts +363 -359
  211. package/src/drafts/draft08/index.ts +10 -9
  212. package/src/drafts/draft08/messages.ts +59 -59
  213. package/src/drafts/draft08/rules.ts +73 -73
  214. package/src/drafts/draft08/session-fsm.ts +335 -303
  215. package/src/drafts/draft08/session.ts +6 -7
  216. package/src/drafts/draft08/types.ts +380 -384
  217. package/src/drafts/draft09/codec.ts +977 -945
  218. package/src/drafts/draft09/data-streams.ts +336 -332
  219. package/src/drafts/draft09/index.ts +10 -9
  220. package/src/drafts/draft09/messages.ts +59 -59
  221. package/src/drafts/draft09/rules.ts +73 -73
  222. package/src/drafts/draft09/session-fsm.ts +335 -303
  223. package/src/drafts/draft09/session.ts +6 -7
  224. package/src/drafts/draft09/types.ts +380 -384
  225. package/src/drafts/draft10/codec.ts +977 -945
  226. package/src/drafts/draft10/data-streams.ts +336 -332
  227. package/src/drafts/draft10/index.ts +10 -9
  228. package/src/drafts/draft10/messages.ts +59 -59
  229. package/src/drafts/draft10/rules.ts +73 -73
  230. package/src/drafts/draft10/session-fsm.ts +335 -303
  231. package/src/drafts/draft10/session.ts +6 -7
  232. package/src/drafts/draft10/types.ts +380 -384
  233. package/src/drafts/draft11/codec.ts +1054 -988
  234. package/src/drafts/draft11/data-streams.ts +316 -269
  235. package/src/drafts/draft11/index.ts +10 -9
  236. package/src/drafts/draft11/messages.ts +60 -59
  237. package/src/drafts/draft11/rules.ts +73 -73
  238. package/src/drafts/draft11/session-fsm.ts +359 -333
  239. package/src/drafts/draft11/session.ts +6 -7
  240. package/src/drafts/draft11/types.ts +385 -381
  241. package/src/drafts/draft12/codec.ts +1178 -1122
  242. package/src/drafts/draft12/data-streams.ts +324 -275
  243. package/src/drafts/draft12/index.ts +10 -9
  244. package/src/drafts/draft12/messages.ts +67 -66
  245. package/src/drafts/draft12/rules.ts +79 -79
  246. package/src/drafts/draft12/session-fsm.ts +384 -358
  247. package/src/drafts/draft12/session.ts +6 -7
  248. package/src/drafts/draft12/types.ts +424 -419
  249. package/src/drafts/draft13/codec.ts +1296 -1206
  250. package/src/drafts/draft13/data-streams.ts +326 -275
  251. package/src/drafts/draft13/index.ts +10 -9
  252. package/src/drafts/draft13/messages.ts +73 -68
  253. package/src/drafts/draft13/rules.ts +81 -81
  254. package/src/drafts/draft13/session-fsm.ts +392 -366
  255. package/src/drafts/draft13/session.ts +6 -7
  256. package/src/drafts/draft13/types.ts +447 -438
  257. package/src/drafts/draft14/codec.ts +1347 -1043
  258. package/src/drafts/draft14/data-streams.ts +831 -813
  259. package/src/drafts/draft14/index.ts +17 -9
  260. package/src/drafts/draft14/messages.ts +65 -65
  261. package/src/drafts/draft14/rules.ts +81 -81
  262. package/src/drafts/draft14/session-fsm.ts +415 -405
  263. package/src/drafts/draft14/session.ts +6 -7
  264. package/src/drafts/draft14/types.ts +451 -381
  265. package/src/drafts/draft15/codec.ts +1138 -978
  266. package/src/drafts/draft15/data-streams.ts +842 -794
  267. package/src/drafts/draft15/index.ts +10 -9
  268. package/src/drafts/draft15/messages.ts +54 -53
  269. package/src/drafts/draft15/rules.ts +67 -67
  270. package/src/drafts/draft15/session-fsm.ts +319 -299
  271. package/src/drafts/draft15/session.ts +6 -7
  272. package/src/drafts/draft15/types.ts +357 -339
  273. package/src/drafts/draft16/codec.ts +1242 -966
  274. package/src/drafts/draft16/data-streams.ts +835 -789
  275. package/src/drafts/draft16/index.ts +10 -9
  276. package/src/drafts/draft16/messages.ts +56 -55
  277. package/src/drafts/draft16/rules.ts +69 -69
  278. package/src/drafts/draft16/session-fsm.ts +319 -299
  279. package/src/drafts/draft16/session.ts +6 -7
  280. package/src/drafts/draft16/types.ts +386 -357
  281. package/src/drafts/draft17/codec.ts +1209 -971
  282. package/src/drafts/draft17/data-streams.ts +969 -758
  283. package/src/drafts/draft17/index.ts +9 -7
  284. package/src/drafts/draft17/messages.ts +43 -42
  285. package/src/drafts/draft17/rules.ts +58 -58
  286. package/src/drafts/draft17/session-fsm.ts +248 -216
  287. package/src/drafts/draft17/session.ts +5 -5
  288. package/src/drafts/draft17/types.ts +337 -313
  289. package/src/index.ts +85 -274
  290. package/src/session.ts +63 -25
  291. package/dist/chunk-FZDIEHQL.cjs +0 -1042
  292. package/dist/chunk-HDWJ2GDE.js +0 -24
  293. package/dist/chunk-KNDYS3DK.cjs +0 -24
  294. package/dist/chunk-N2KBF5Q2.js +0 -1042
  295. package/dist/draft7-session.d.cts +0 -7
  296. package/dist/draft7-session.d.ts +0 -7
  297. package/dist/draft7.cjs +0 -72
  298. package/dist/draft7.d.cts +0 -148
  299. package/dist/draft7.d.ts +0 -148
  300. package/dist/draft7.js +0 -72
  301. package/dist/draft8-session.cjs +0 -6
  302. package/dist/draft8-session.d.cts +0 -8
  303. package/dist/draft8-session.d.ts +0 -8
  304. package/dist/draft8.cjs +0 -116
  305. package/dist/draft9-session.cjs +0 -6
  306. package/dist/draft9-session.d.cts +0 -8
  307. package/dist/draft9-session.d.ts +0 -8
  308. package/dist/draft9.cjs +0 -116
  309. package/dist/types-QNXoxC9Y.d.cts +0 -236
  310. package/dist/types-QNXoxC9Y.d.ts +0 -236
  311. package/src/drafts/draft07/announce-fsm.ts +0 -2
  312. package/src/drafts/draft07/parameters.ts +0 -12
  313. package/src/drafts/draft07/subscription-fsm.ts +0 -3
@@ -1,966 +1,1242 @@
1
- import { bytesToHex, hexToBytes } from "../../core/hex.js";
2
- import { BufferReader } from "../../core/buffer-reader.js";
3
- import { BufferWriter } from "../../core/buffer-writer.js";
4
- import type { BaseCodec, DecodeResult } from "../../core/types.js";
5
- import { DecodeError } from "../../core/types.js";
6
- import {
7
- MESSAGE_ID_MAP,
8
- MSG_CLIENT_SETUP,
9
- MSG_FETCH,
10
- MSG_FETCH_CANCEL,
11
- MSG_FETCH_OK,
12
- MSG_GOAWAY,
13
- MSG_MAX_REQUEST_ID,
14
- MSG_NAMESPACE,
15
- MSG_NAMESPACE_DONE,
16
- MSG_PUBLISH,
17
- MSG_PUBLISH_DONE,
18
- MSG_PUBLISH_NAMESPACE,
19
- MSG_PUBLISH_NAMESPACE_CANCEL,
20
- MSG_PUBLISH_NAMESPACE_DONE,
21
- MSG_PUBLISH_OK,
22
- MSG_REQUEST_ERROR,
23
- MSG_REQUEST_OK,
24
- MSG_REQUEST_UPDATE,
25
- MSG_REQUESTS_BLOCKED,
26
- MSG_SERVER_SETUP,
27
- MSG_SUBSCRIBE,
28
- MSG_SUBSCRIBE_NAMESPACE,
29
- MSG_SUBSCRIBE_OK,
30
- MSG_TRACK_STATUS,
31
- MSG_UNSUBSCRIBE,
32
- SETUP_PARAM_AUTHORITY,
33
- SETUP_PARAM_MAX_AUTH_TOKEN_CACHE_SIZE,
34
- SETUP_PARAM_MAX_REQUEST_ID,
35
- SETUP_PARAM_MOQT_IMPLEMENTATION,
36
- SETUP_PARAM_PATH,
37
- } from "./messages.js";
38
- import type {
39
- DatagramObject,
40
- DataStreamEvent,
41
- Draft16DataStream,
42
- Draft16Fetch,
43
- Draft16Message,
44
- Draft16Params,
45
- Draft16SetupParams,
46
- FetchObjectPayload,
47
- FetchStream,
48
- FetchStreamHeader,
49
- JoiningFetch,
50
- ObjectPayload,
51
- StandaloneFetch,
52
- SubgroupStream,
53
- SubgroupStreamHeader,
54
- UnknownParam,
55
- } from "./types.js";
56
-
57
- const textEncoder = /* @__PURE__ */ new TextEncoder();
58
- const textDecoder = /* @__PURE__ */ new TextDecoder();
59
-
60
- // ─── Setup Parameter Encoding/Decoding ──────────────────────────────────────────
61
-
62
- function encodeSetupParams(params: Draft16SetupParams, writer: BufferWriter): void {
63
- let count = 0;
64
- if (params.path !== undefined) count++;
65
- if (params.max_request_id !== undefined) count++;
66
- if (params.max_auth_token_cache_size !== undefined) count++;
67
- if (params.authority !== undefined) count++;
68
- if (params.moqt_implementation !== undefined) count++;
69
- if (params.unknown) count += params.unknown.length;
70
-
71
- writer.writeVarInt(count);
72
-
73
- // PATH (0x01) - odd, length-prefixed bytes
74
- if (params.path !== undefined) {
75
- writer.writeVarInt(SETUP_PARAM_PATH);
76
- const encoded = textEncoder.encode(params.path);
77
- writer.writeVarInt(encoded.byteLength);
78
- writer.writeBytes(encoded);
79
- }
80
-
81
- // MAX_REQUEST_ID (0x02) - even, varint value
82
- if (params.max_request_id !== undefined) {
83
- writer.writeVarInt(SETUP_PARAM_MAX_REQUEST_ID);
84
- writer.writeVarInt(params.max_request_id);
85
- }
86
-
87
- // MAX_AUTH_TOKEN_CACHE_SIZE (0x04) - even, varint value
88
- if (params.max_auth_token_cache_size !== undefined) {
89
- writer.writeVarInt(SETUP_PARAM_MAX_AUTH_TOKEN_CACHE_SIZE);
90
- writer.writeVarInt(params.max_auth_token_cache_size);
91
- }
92
-
93
- // AUTHORITY (0x05) - odd, length-prefixed bytes
94
- if (params.authority !== undefined) {
95
- writer.writeVarInt(SETUP_PARAM_AUTHORITY);
96
- const encoded = textEncoder.encode(params.authority);
97
- writer.writeVarInt(encoded.byteLength);
98
- writer.writeBytes(encoded);
99
- }
100
-
101
- // MOQT_IMPLEMENTATION (0x07) - odd, length-prefixed bytes
102
- if (params.moqt_implementation !== undefined) {
103
- writer.writeVarInt(SETUP_PARAM_MOQT_IMPLEMENTATION);
104
- const encoded = textEncoder.encode(params.moqt_implementation);
105
- writer.writeVarInt(encoded.byteLength);
106
- writer.writeBytes(encoded);
107
- }
108
-
109
- // Unknown params
110
- if (params.unknown) {
111
- for (const u of params.unknown) {
112
- const id = BigInt(u.id);
113
- writer.writeVarInt(id);
114
- if (id % 2n === 0n) {
115
- const raw = hexToBytes(u.raw_hex);
116
- const tmpReader = new BufferReader(raw);
117
- const value = tmpReader.readVarInt();
118
- writer.writeVarInt(value);
119
- } else {
120
- const raw = hexToBytes(u.raw_hex);
121
- writer.writeVarInt(raw.byteLength);
122
- writer.writeBytes(raw);
123
- }
124
- }
125
- }
126
- }
127
-
128
- function decodeSetupParams(reader: BufferReader): Draft16SetupParams {
129
- const count = Number(reader.readVarInt());
130
- const result: Draft16SetupParams = {};
131
- const unknown: UnknownParam[] = [];
132
-
133
- for (let i = 0; i < count; i++) {
134
- const paramType = reader.readVarInt();
135
-
136
- if (paramType % 2n === 0n) {
137
- const value = reader.readVarInt();
138
- if (paramType === SETUP_PARAM_MAX_REQUEST_ID) {
139
- result.max_request_id = value;
140
- } else if (paramType === SETUP_PARAM_MAX_AUTH_TOKEN_CACHE_SIZE) {
141
- result.max_auth_token_cache_size = value;
142
- } else {
143
- const tmpWriter = new BufferWriter(16);
144
- tmpWriter.writeVarInt(value);
145
- const raw = tmpWriter.finish();
146
- unknown.push({
147
- id: `0x${paramType.toString(16)}`,
148
- length: raw.byteLength,
149
- raw_hex: bytesToHex(raw),
150
- });
151
- }
152
- } else {
153
- const length = Number(reader.readVarInt());
154
- const bytes = reader.readBytes(length);
155
- if (paramType === SETUP_PARAM_PATH) {
156
- result.path = textDecoder.decode(bytes);
157
- } else if (paramType === SETUP_PARAM_AUTHORITY) {
158
- result.authority = textDecoder.decode(bytes);
159
- } else if (paramType === SETUP_PARAM_MOQT_IMPLEMENTATION) {
160
- result.moqt_implementation = textDecoder.decode(bytes);
161
- } else {
162
- unknown.push({
163
- id: `0x${paramType.toString(16)}`,
164
- length,
165
- raw_hex: bytesToHex(bytes),
166
- });
167
- }
168
- }
169
- }
170
-
171
- if (unknown.length > 0) {
172
- result.unknown = unknown;
173
- }
174
-
175
- return result;
176
- }
177
-
178
- // ─── Version-Specific Parameter Encoding/Decoding ───────────────────────────────
179
-
180
- const PARAM_EXPIRES = 0x08n;
181
- const PARAM_LARGEST_OBJECT = 0x09n;
182
- const PARAM_SUBSCRIBER_PRIORITY = 0x20n;
183
- const PARAM_SUBSCRIPTION_FILTER = 0x21n;
184
- const PARAM_GROUP_ORDER = 0x22n;
185
-
186
- function encodeParams(params: Draft16Params, writer: BufferWriter): void {
187
- let count = params.unknown ? params.unknown.length : 0;
188
- if (params.expires !== undefined) count++;
189
- if (params.largest_object !== undefined) count++;
190
- if (params.subscriber_priority !== undefined) count++;
191
- if (params.subscription_filter !== undefined) count++;
192
- if (params.group_order !== undefined) count++;
193
- writer.writeVarInt(count);
194
-
195
- if (params.expires !== undefined) {
196
- writer.writeVarInt(PARAM_EXPIRES);
197
- writer.writeVarInt(params.expires);
198
- }
199
- if (params.largest_object !== undefined) {
200
- writer.writeVarInt(PARAM_LARGEST_OBJECT);
201
- const tmpW = new BufferWriter(16);
202
- tmpW.writeVarInt(params.largest_object.group);
203
- tmpW.writeVarInt(params.largest_object.object);
204
- const raw = tmpW.finish();
205
- writer.writeVarInt(raw.byteLength);
206
- writer.writeBytes(raw);
207
- }
208
- if (params.subscriber_priority !== undefined) {
209
- writer.writeVarInt(PARAM_SUBSCRIBER_PRIORITY);
210
- writer.writeVarInt(params.subscriber_priority);
211
- }
212
- if (params.subscription_filter !== undefined) {
213
- writer.writeVarInt(PARAM_SUBSCRIPTION_FILTER);
214
- const tmpW = new BufferWriter(32);
215
- const f = params.subscription_filter;
216
- tmpW.writeVarInt(f.filter_type);
217
- if (f.filter_type === 3n || f.filter_type === 4n) {
218
- tmpW.writeVarInt(f.start_group!);
219
- tmpW.writeVarInt(f.start_object!);
220
- }
221
- if (f.filter_type === 4n) {
222
- tmpW.writeVarInt(f.end_group!);
223
- }
224
- const raw = tmpW.finish();
225
- writer.writeVarInt(raw.byteLength);
226
- writer.writeBytes(raw);
227
- }
228
- if (params.group_order !== undefined) {
229
- writer.writeVarInt(PARAM_GROUP_ORDER);
230
- writer.writeVarInt(params.group_order);
231
- }
232
-
233
- if (params.unknown) {
234
- for (const u of params.unknown) {
235
- const id = BigInt(u.id);
236
- writer.writeVarInt(id);
237
- if (id % 2n === 0n) {
238
- const raw = hexToBytes(u.raw_hex);
239
- const tmpReader = new BufferReader(raw);
240
- const value = tmpReader.readVarInt();
241
- writer.writeVarInt(value);
242
- } else {
243
- const raw = hexToBytes(u.raw_hex);
244
- writer.writeVarInt(raw.byteLength);
245
- writer.writeBytes(raw);
246
- }
247
- }
248
- }
249
- }
250
-
251
- function decodeParams(reader: BufferReader): Draft16Params {
252
- const count = Number(reader.readVarInt());
253
- const result: Draft16Params = {};
254
- const unknown: UnknownParam[] = [];
255
-
256
- for (let i = 0; i < count; i++) {
257
- const paramType = reader.readVarInt();
258
-
259
- if (paramType === PARAM_EXPIRES) {
260
- result.expires = reader.readVarInt();
261
- } else if (paramType === PARAM_SUBSCRIBER_PRIORITY) {
262
- result.subscriber_priority = reader.readVarInt();
263
- } else if (paramType === PARAM_GROUP_ORDER) {
264
- result.group_order = reader.readVarInt();
265
- } else if (paramType === PARAM_LARGEST_OBJECT) {
266
- const length = Number(reader.readVarInt());
267
- const startOff = reader.offset;
268
- const group = reader.readVarInt();
269
- const object = reader.readVarInt();
270
- const consumed = reader.offset - startOff;
271
- if (consumed < length) reader.readBytes(length - consumed);
272
- result.largest_object = { group, object };
273
- } else if (paramType === PARAM_SUBSCRIPTION_FILTER) {
274
- const length = Number(reader.readVarInt());
275
- const startOff = reader.offset;
276
- const filter_type = reader.readVarInt();
277
- const filter: {
278
- filter_type: bigint;
279
- start_group?: bigint;
280
- start_object?: bigint;
281
- end_group?: bigint;
282
- } = { filter_type };
283
- if (filter_type === 3n || filter_type === 4n) {
284
- filter.start_group = reader.readVarInt();
285
- filter.start_object = reader.readVarInt();
286
- }
287
- if (filter_type === 4n) {
288
- filter.end_group = reader.readVarInt();
289
- }
290
- const consumed = reader.offset - startOff;
291
- if (consumed < length) reader.readBytes(length - consumed);
292
- result.subscription_filter = filter;
293
- } else if (paramType % 2n === 0n) {
294
- const value = reader.readVarInt();
295
- const tmpWriter = new BufferWriter(16);
296
- tmpWriter.writeVarInt(value);
297
- const raw = tmpWriter.finish();
298
- unknown.push({
299
- id: `0x${paramType.toString(16)}`,
300
- length: raw.byteLength,
301
- raw_hex: bytesToHex(raw),
302
- });
303
- } else {
304
- const length = Number(reader.readVarInt());
305
- const bytes = reader.readBytes(length);
306
- unknown.push({
307
- id: `0x${paramType.toString(16)}`,
308
- length,
309
- raw_hex: bytesToHex(bytes),
310
- });
311
- }
312
- }
313
-
314
- if (unknown.length > 0) {
315
- result.unknown = unknown;
316
- }
317
-
318
- return result;
319
- }
320
-
321
- // ─── Payload Encoders ──────────────────────────────────────────────────────────
322
-
323
- function encodeClientSetupPayload(
324
- msg: Draft16Message & { type: "client_setup" },
325
- w: BufferWriter,
326
- ): void {
327
- encodeSetupParams(msg.parameters, w);
328
- }
329
-
330
- function encodeServerSetupPayload(
331
- msg: Draft16Message & { type: "server_setup" },
332
- w: BufferWriter,
333
- ): void {
334
- encodeSetupParams(msg.parameters, w);
335
- }
336
-
337
- function encodeSubscribePayload(
338
- msg: Draft16Message & { type: "subscribe" },
339
- w: BufferWriter,
340
- ): void {
341
- w.writeVarInt(msg.request_id);
342
- w.writeTuple(msg.track_namespace);
343
- w.writeString(msg.track_name);
344
- encodeParams(msg.parameters, w);
345
- }
346
-
347
- function encodeSubscribeOkPayload(
348
- msg: Draft16Message & { type: "subscribe_ok" },
349
- w: BufferWriter,
350
- ): void {
351
- w.writeVarInt(msg.request_id);
352
- w.writeVarInt(msg.track_alias);
353
- encodeParams(msg.parameters, w);
354
- }
355
-
356
- function encodeRequestUpdatePayload(
357
- msg: Draft16Message & { type: "request_update" },
358
- w: BufferWriter,
359
- ): void {
360
- w.writeVarInt(msg.request_id);
361
- w.writeVarInt(msg.existing_request_id);
362
- encodeParams(msg.parameters, w);
363
- }
364
-
365
- function encodeUnsubscribePayload(
366
- msg: Draft16Message & { type: "unsubscribe" },
367
- w: BufferWriter,
368
- ): void {
369
- w.writeVarInt(msg.request_id);
370
- }
371
-
372
- function encodePublishPayload(msg: Draft16Message & { type: "publish" }, w: BufferWriter): void {
373
- w.writeVarInt(msg.request_id);
374
- w.writeTuple(msg.track_namespace);
375
- w.writeString(msg.track_name);
376
- w.writeVarInt(msg.track_alias);
377
- encodeParams(msg.parameters, w);
378
- }
379
-
380
- function encodePublishOkPayload(
381
- msg: Draft16Message & { type: "publish_ok" },
382
- w: BufferWriter,
383
- ): void {
384
- w.writeVarInt(msg.request_id);
385
- encodeParams(msg.parameters, w);
386
- }
387
-
388
- function encodePublishDonePayload(
389
- msg: Draft16Message & { type: "publish_done" },
390
- w: BufferWriter,
391
- ): void {
392
- w.writeVarInt(msg.request_id);
393
- w.writeVarInt(msg.status_code);
394
- w.writeVarInt(msg.stream_count);
395
- w.writeString(msg.reason_phrase);
396
- }
397
-
398
- function encodePublishNamespacePayload(
399
- msg: Draft16Message & { type: "publish_namespace" },
400
- w: BufferWriter,
401
- ): void {
402
- w.writeVarInt(msg.request_id);
403
- w.writeTuple(msg.track_namespace);
404
- encodeParams(msg.parameters, w);
405
- }
406
-
407
- // Draft-16: simplified to just request_id
408
- function encodePublishNamespaceDonePayload(
409
- msg: Draft16Message & { type: "publish_namespace_done" },
410
- w: BufferWriter,
411
- ): void {
412
- w.writeVarInt(msg.request_id);
413
- }
414
-
415
- // Draft-16: changed to request_id + error_code + reason_phrase
416
- function encodePublishNamespaceCancelPayload(
417
- msg: Draft16Message & { type: "publish_namespace_cancel" },
418
- w: BufferWriter,
419
- ): void {
420
- w.writeVarInt(msg.request_id);
421
- w.writeVarInt(msg.error_code);
422
- w.writeString(msg.reason_phrase);
423
- }
424
-
425
- // Draft-16: added subscribe_options
426
- function encodeSubscribeNamespacePayload(
427
- msg: Draft16Message & { type: "subscribe_namespace" },
428
- w: BufferWriter,
429
- ): void {
430
- w.writeVarInt(msg.request_id);
431
- w.writeTuple(msg.namespace_prefix);
432
- w.writeVarInt(msg.subscribe_options);
433
- encodeParams(msg.parameters, w);
434
- }
435
-
436
- // New in draft-16
437
- function encodeNamespacePayload(
438
- msg: Draft16Message & { type: "namespace" },
439
- w: BufferWriter,
440
- ): void {
441
- w.writeTuple(msg.namespace_suffix);
442
- }
443
-
444
- // New in draft-16
445
- function encodeNamespaceDonePayload(
446
- msg: Draft16Message & { type: "namespace_done" },
447
- w: BufferWriter,
448
- ): void {
449
- w.writeTuple(msg.namespace_suffix);
450
- }
451
-
452
- function encodeFetchPayload(msg: Draft16Message & { type: "fetch" }, w: BufferWriter): void {
453
- w.writeVarInt(msg.request_id);
454
- w.writeVarInt(msg.fetch_type);
455
- const ft = Number(msg.fetch_type);
456
- if (ft === 1 && msg.standalone) {
457
- w.writeTuple(msg.standalone.track_namespace);
458
- w.writeString(msg.standalone.track_name);
459
- w.writeVarInt(msg.standalone.start_group);
460
- w.writeVarInt(msg.standalone.start_object);
461
- w.writeVarInt(msg.standalone.end_group);
462
- w.writeVarInt(msg.standalone.end_object);
463
- } else if ((ft === 2 || ft === 3) && msg.joining) {
464
- w.writeVarInt(msg.joining.joining_request_id);
465
- w.writeVarInt(msg.joining.joining_start);
466
- }
467
- encodeParams(msg.parameters, w);
468
- }
469
-
470
- function encodeFetchOkPayload(msg: Draft16Message & { type: "fetch_ok" }, w: BufferWriter): void {
471
- w.writeVarInt(msg.request_id);
472
- w.writeUint8(msg.end_of_track);
473
- w.writeVarInt(msg.end_group);
474
- w.writeVarInt(msg.end_object);
475
- encodeParams(msg.parameters, w);
476
- }
477
-
478
- function encodeFetchCancelPayload(
479
- msg: Draft16Message & { type: "fetch_cancel" },
480
- w: BufferWriter,
481
- ): void {
482
- w.writeVarInt(msg.request_id);
483
- }
484
-
485
- function encodeTrackStatusPayload(
486
- msg: Draft16Message & { type: "track_status" },
487
- w: BufferWriter,
488
- ): void {
489
- w.writeVarInt(msg.request_id);
490
- w.writeTuple(msg.track_namespace);
491
- w.writeString(msg.track_name);
492
- encodeParams(msg.parameters, w);
493
- }
494
-
495
- function encodeRequestOkPayload(
496
- msg: Draft16Message & { type: "request_ok" },
497
- w: BufferWriter,
498
- ): void {
499
- w.writeVarInt(msg.request_id);
500
- encodeParams(msg.parameters, w);
501
- }
502
-
503
- // Draft-16: added retry_interval
504
- function encodeRequestErrorPayload(
505
- msg: Draft16Message & { type: "request_error" },
506
- w: BufferWriter,
507
- ): void {
508
- w.writeVarInt(msg.request_id);
509
- w.writeVarInt(msg.error_code);
510
- w.writeVarInt(msg.retry_interval);
511
- w.writeString(msg.reason_phrase);
512
- }
513
-
514
- function encodeGoAwayPayload(msg: Draft16Message & { type: "goaway" }, w: BufferWriter): void {
515
- w.writeString(msg.new_session_uri);
516
- }
517
-
518
- function encodeMaxRequestIdPayload(
519
- msg: Draft16Message & { type: "max_request_id" },
520
- w: BufferWriter,
521
- ): void {
522
- w.writeVarInt(msg.max_request_id);
523
- }
524
-
525
- function encodeRequestsBlockedPayload(
526
- msg: Draft16Message & { type: "requests_blocked" },
527
- w: BufferWriter,
528
- ): void {
529
- w.writeVarInt(msg.maximum_request_id);
530
- }
531
-
532
- // ─── Payload Decoders ──────────────────────────────────────────────────────────
533
-
534
- function decodeClientSetupPayload(r: BufferReader): Draft16Message {
535
- const parameters = decodeSetupParams(r);
536
- return { type: "client_setup", parameters };
537
- }
538
-
539
- function decodeServerSetupPayload(r: BufferReader): Draft16Message {
540
- const parameters = decodeSetupParams(r);
541
- return { type: "server_setup", parameters };
542
- }
543
-
544
- function decodeSubscribePayload(r: BufferReader): Draft16Message {
545
- const request_id = r.readVarInt();
546
- const track_namespace = r.readTuple();
547
- const track_name = r.readString();
548
- const parameters = decodeParams(r);
549
- return { type: "subscribe", request_id, track_namespace, track_name, parameters };
550
- }
551
-
552
- function decodeSubscribeOkPayload(r: BufferReader): Draft16Message {
553
- const request_id = r.readVarInt();
554
- const track_alias = r.readVarInt();
555
- const parameters = decodeParams(r);
556
- return { type: "subscribe_ok", request_id, track_alias, parameters };
557
- }
558
-
559
- function decodeRequestUpdatePayload(r: BufferReader): Draft16Message {
560
- const request_id = r.readVarInt();
561
- const existing_request_id = r.readVarInt();
562
- const parameters = decodeParams(r);
563
- return { type: "request_update", request_id, existing_request_id, parameters };
564
- }
565
-
566
- function decodeUnsubscribePayload(r: BufferReader): Draft16Message {
567
- const request_id = r.readVarInt();
568
- return { type: "unsubscribe", request_id };
569
- }
570
-
571
- function decodePublishPayload(r: BufferReader): Draft16Message {
572
- const request_id = r.readVarInt();
573
- const track_namespace = r.readTuple();
574
- const track_name = r.readString();
575
- const track_alias = r.readVarInt();
576
- const parameters = decodeParams(r);
577
- return { type: "publish", request_id, track_namespace, track_name, track_alias, parameters };
578
- }
579
-
580
- function decodePublishOkPayload(r: BufferReader): Draft16Message {
581
- const request_id = r.readVarInt();
582
- const parameters = decodeParams(r);
583
- return { type: "publish_ok", request_id, parameters };
584
- }
585
-
586
- function decodePublishDonePayload(r: BufferReader): Draft16Message {
587
- const request_id = r.readVarInt();
588
- const status_code = r.readVarInt();
589
- const stream_count = r.readVarInt();
590
- const reason_phrase = r.readString();
591
- return { type: "publish_done", request_id, status_code, stream_count, reason_phrase };
592
- }
593
-
594
- function decodePublishNamespacePayload(r: BufferReader): Draft16Message {
595
- const request_id = r.readVarInt();
596
- const track_namespace = r.readTuple();
597
- const parameters = decodeParams(r);
598
- return { type: "publish_namespace", request_id, track_namespace, parameters };
599
- }
600
-
601
- // Draft-16: simplified to just request_id
602
- function decodePublishNamespaceDonePayload(r: BufferReader): Draft16Message {
603
- const request_id = r.readVarInt();
604
- return { type: "publish_namespace_done", request_id };
605
- }
606
-
607
- // Draft-16: changed to request_id + error_code + reason_phrase
608
- function decodePublishNamespaceCancelPayload(r: BufferReader): Draft16Message {
609
- const request_id = r.readVarInt();
610
- const error_code = r.readVarInt();
611
- const reason_phrase = r.readString();
612
- return { type: "publish_namespace_cancel", request_id, error_code, reason_phrase };
613
- }
614
-
615
- // Draft-16: added subscribe_options
616
- function decodeSubscribeNamespacePayload(r: BufferReader): Draft16Message {
617
- const request_id = r.readVarInt();
618
- const namespace_prefix = r.readTuple();
619
- const subscribe_options = r.readVarInt();
620
- const parameters = decodeParams(r);
621
- return {
622
- type: "subscribe_namespace",
623
- request_id,
624
- namespace_prefix,
625
- subscribe_options,
626
- parameters,
627
- };
628
- }
629
-
630
- // New in draft-16
631
- function decodeNamespacePayload(r: BufferReader): Draft16Message {
632
- const namespace_suffix = r.readTuple();
633
- return { type: "namespace", namespace_suffix };
634
- }
635
-
636
- // New in draft-16
637
- function decodeNamespaceDonePayload(r: BufferReader): Draft16Message {
638
- const namespace_suffix = r.readTuple();
639
- return { type: "namespace_done", namespace_suffix };
640
- }
641
-
642
- function decodeFetchPayload(r: BufferReader): Draft16Message {
643
- const request_id = r.readVarInt();
644
- const fetch_type = r.readVarInt();
645
- const ft = Number(fetch_type);
646
-
647
- if (ft < 1 || ft > 3) {
648
- throw new DecodeError("CONSTRAINT_VIOLATION", `Invalid fetch_type: ${ft}`, r.offset);
649
- }
650
-
651
- let standalone: StandaloneFetch | undefined;
652
- let joining: JoiningFetch | undefined;
653
-
654
- if (ft === 1) {
655
- const track_namespace = r.readTuple();
656
- const track_name = r.readString();
657
- const start_group = r.readVarInt();
658
- const start_object = r.readVarInt();
659
- const end_group = r.readVarInt();
660
- const end_object = r.readVarInt();
661
- standalone = { track_namespace, track_name, start_group, start_object, end_group, end_object };
662
- } else {
663
- const joining_request_id = r.readVarInt();
664
- const joining_start = r.readVarInt();
665
- joining = { joining_request_id, joining_start };
666
- }
667
-
668
- const parameters = decodeParams(r);
669
-
670
- return {
671
- type: "fetch",
672
- request_id,
673
- fetch_type,
674
- standalone,
675
- joining,
676
- parameters,
677
- } as Draft16Fetch;
678
- }
679
-
680
- function decodeFetchOkPayload(r: BufferReader): Draft16Message {
681
- const request_id = r.readVarInt();
682
- const end_of_track = r.readUint8();
683
- const end_group = r.readVarInt();
684
- const end_object = r.readVarInt();
685
- const parameters = decodeParams(r);
686
- return { type: "fetch_ok", request_id, end_of_track, end_group, end_object, parameters };
687
- }
688
-
689
- function decodeFetchCancelPayload(r: BufferReader): Draft16Message {
690
- const request_id = r.readVarInt();
691
- return { type: "fetch_cancel", request_id };
692
- }
693
-
694
- function decodeTrackStatusPayload(r: BufferReader): Draft16Message {
695
- const request_id = r.readVarInt();
696
- const track_namespace = r.readTuple();
697
- const track_name = r.readString();
698
- const parameters = decodeParams(r);
699
- return { type: "track_status", request_id, track_namespace, track_name, parameters };
700
- }
701
-
702
- function decodeRequestOkPayload(r: BufferReader): Draft16Message {
703
- const request_id = r.readVarInt();
704
- const parameters = decodeParams(r);
705
- return { type: "request_ok", request_id, parameters };
706
- }
707
-
708
- // Draft-16: added retry_interval
709
- function decodeRequestErrorPayload(r: BufferReader): Draft16Message {
710
- const request_id = r.readVarInt();
711
- const error_code = r.readVarInt();
712
- const retry_interval = r.readVarInt();
713
- const reason_phrase = r.readString();
714
- return { type: "request_error", request_id, error_code, retry_interval, reason_phrase };
715
- }
716
-
717
- function decodeGoAwayPayload(r: BufferReader): Draft16Message {
718
- const new_session_uri = r.readString();
719
- return { type: "goaway", new_session_uri };
720
- }
721
-
722
- function decodeMaxRequestIdPayload(r: BufferReader): Draft16Message {
723
- const max_request_id = r.readVarInt();
724
- return { type: "max_request_id", max_request_id };
725
- }
726
-
727
- function decodeRequestsBlockedPayload(r: BufferReader): Draft16Message {
728
- const maximum_request_id = r.readVarInt();
729
- return { type: "requests_blocked", maximum_request_id };
730
- }
731
-
732
- // ─── Payload dispatch tables ───────────────────────────────────────────────────
733
-
734
- const payloadDecoders: ReadonlyMap<bigint, (r: BufferReader) => Draft16Message> = new Map([
735
- [MSG_CLIENT_SETUP, decodeClientSetupPayload],
736
- [MSG_SERVER_SETUP, decodeServerSetupPayload],
737
- [MSG_SUBSCRIBE, decodeSubscribePayload],
738
- [MSG_SUBSCRIBE_OK, decodeSubscribeOkPayload],
739
- [MSG_REQUEST_UPDATE, decodeRequestUpdatePayload],
740
- [MSG_UNSUBSCRIBE, decodeUnsubscribePayload],
741
- [MSG_PUBLISH, decodePublishPayload],
742
- [MSG_PUBLISH_OK, decodePublishOkPayload],
743
- [MSG_PUBLISH_DONE, decodePublishDonePayload],
744
- [MSG_PUBLISH_NAMESPACE, decodePublishNamespacePayload],
745
- [MSG_PUBLISH_NAMESPACE_DONE, decodePublishNamespaceDonePayload],
746
- [MSG_PUBLISH_NAMESPACE_CANCEL, decodePublishNamespaceCancelPayload],
747
- [MSG_SUBSCRIBE_NAMESPACE, decodeSubscribeNamespacePayload],
748
- [MSG_NAMESPACE, decodeNamespacePayload],
749
- [MSG_NAMESPACE_DONE, decodeNamespaceDonePayload],
750
- [MSG_FETCH, decodeFetchPayload],
751
- [MSG_FETCH_OK, decodeFetchOkPayload],
752
- [MSG_FETCH_CANCEL, decodeFetchCancelPayload],
753
- [MSG_TRACK_STATUS, decodeTrackStatusPayload],
754
- [MSG_REQUEST_OK, decodeRequestOkPayload],
755
- [MSG_REQUEST_ERROR, decodeRequestErrorPayload],
756
- [MSG_GOAWAY, decodeGoAwayPayload],
757
- [MSG_MAX_REQUEST_ID, decodeMaxRequestIdPayload],
758
- [MSG_REQUESTS_BLOCKED, decodeRequestsBlockedPayload],
759
- ]);
760
-
761
- // ─── Public API ────────────────────────────────────────────────────────────────
762
-
763
- /**
764
- * Encode a draft-16 control message with type(varint) + length(uint16 BE) + payload.
765
- */
766
- export function encodeMessage(message: Draft16Message): Uint8Array {
767
- const typeId = MESSAGE_ID_MAP.get(message.type);
768
- if (typeId === undefined) {
769
- throw new Error(`Unknown message type: ${message.type}`);
770
- }
771
-
772
- const payloadWriter = new BufferWriter();
773
- encodePayload(message, payloadWriter);
774
- const payload = payloadWriter.finishView();
775
-
776
- if (payload.byteLength > 0xffff) {
777
- throw new Error(`Payload too large for 16-bit length: ${payload.byteLength}`);
778
- }
779
-
780
- const writer = new BufferWriter(payload.byteLength + 16);
781
- writer.writeVarInt(typeId);
782
- writer.writeUint8((payload.byteLength >> 8) & 0xff);
783
- writer.writeUint8(payload.byteLength & 0xff);
784
- writer.writeBytes(payload);
785
-
786
- return writer.finish();
787
- }
788
-
789
- function encodePayload(msg: Draft16Message, w: BufferWriter): void {
790
- switch (msg.type) {
791
- case "client_setup":
792
- return encodeClientSetupPayload(msg, w);
793
- case "server_setup":
794
- return encodeServerSetupPayload(msg, w);
795
- case "subscribe":
796
- return encodeSubscribePayload(msg, w);
797
- case "subscribe_ok":
798
- return encodeSubscribeOkPayload(msg, w);
799
- case "request_update":
800
- return encodeRequestUpdatePayload(msg, w);
801
- case "unsubscribe":
802
- return encodeUnsubscribePayload(msg, w);
803
- case "publish":
804
- return encodePublishPayload(msg, w);
805
- case "publish_ok":
806
- return encodePublishOkPayload(msg, w);
807
- case "publish_done":
808
- return encodePublishDonePayload(msg, w);
809
- case "publish_namespace":
810
- return encodePublishNamespacePayload(msg, w);
811
- case "publish_namespace_done":
812
- return encodePublishNamespaceDonePayload(msg, w);
813
- case "publish_namespace_cancel":
814
- return encodePublishNamespaceCancelPayload(msg, w);
815
- case "subscribe_namespace":
816
- return encodeSubscribeNamespacePayload(msg, w);
817
- case "namespace":
818
- return encodeNamespacePayload(msg, w);
819
- case "namespace_done":
820
- return encodeNamespaceDonePayload(msg, w);
821
- case "fetch":
822
- return encodeFetchPayload(msg, w);
823
- case "fetch_ok":
824
- return encodeFetchOkPayload(msg, w);
825
- case "fetch_cancel":
826
- return encodeFetchCancelPayload(msg, w);
827
- case "track_status":
828
- return encodeTrackStatusPayload(msg, w);
829
- case "request_ok":
830
- return encodeRequestOkPayload(msg, w);
831
- case "request_error":
832
- return encodeRequestErrorPayload(msg, w);
833
- case "goaway":
834
- return encodeGoAwayPayload(msg, w);
835
- case "max_request_id":
836
- return encodeMaxRequestIdPayload(msg, w);
837
- case "requests_blocked":
838
- return encodeRequestsBlockedPayload(msg, w);
839
- default: {
840
- const _exhaustive: never = msg;
841
- throw new Error(`Unhandled message type: ${(_exhaustive as Draft16Message).type}`);
842
- }
843
- }
844
- }
845
-
846
- /**
847
- * Decode a draft-16 control message from bytes (type + uint16 length + payload).
848
- */
849
- export function decodeMessage(bytes: Uint8Array): DecodeResult<Draft16Message> {
850
- try {
851
- const reader = new BufferReader(bytes);
852
- const typeId = reader.readVarInt();
853
-
854
- const lenHi = reader.readUint8();
855
- const lenLo = reader.readUint8();
856
- const payloadLength = (lenHi << 8) | lenLo;
857
-
858
- const payloadBytes = reader.readBytes(payloadLength);
859
- const payloadReader = new BufferReader(payloadBytes);
860
-
861
- const decoder = payloadDecoders.get(typeId);
862
- if (!decoder) {
863
- return {
864
- ok: false,
865
- error: new DecodeError(
866
- "UNKNOWN_MESSAGE_TYPE",
867
- `Unknown message type ID: 0x${typeId.toString(16)}`,
868
- 0,
869
- ),
870
- };
871
- }
872
-
873
- const message = decoder(payloadReader);
874
- return { ok: true, value: message, bytesRead: reader.offset };
875
- } catch (e) {
876
- if (e instanceof DecodeError) {
877
- return { ok: false, error: e };
878
- }
879
- throw e;
880
- }
881
- }
882
-
883
- // ─── Data Stream Encoding/Decoding (re-exported from data-streams.ts) ───────
884
-
885
- import { encodeSubgroupStream, decodeSubgroupStream, encodeDatagram, decodeDatagram, encodeFetchStream, decodeFetchStream, decodeDataStream, createSubgroupStreamDecoder, createFetchStreamDecoder, createDataStreamDecoder } from "./data-streams.js";
886
- export { encodeSubgroupStream, decodeSubgroupStream, encodeDatagram, decodeDatagram, encodeFetchStream, decodeFetchStream, decodeDataStream, createSubgroupStreamDecoder, createFetchStreamDecoder, createDataStreamDecoder };
887
-
888
- // ─── Stream Decoders ───────────────────────────────────────────────────────────
889
-
890
- export function createStreamDecoder(): TransformStream<Uint8Array, Draft16Message> {
891
- let buffer = new Uint8Array(0);
892
- let offset = 0;
893
-
894
- return new TransformStream<Uint8Array, Draft16Message>({
895
- transform(chunk, controller) {
896
- if (offset > 0) {
897
- buffer = buffer.subarray(offset);
898
- offset = 0;
899
- }
900
- const newBuffer = new Uint8Array(buffer.length + chunk.length);
901
- newBuffer.set(buffer, 0);
902
- newBuffer.set(chunk, buffer.length);
903
- buffer = newBuffer;
904
-
905
- while (offset < buffer.length) {
906
- const result = decodeMessage(buffer.subarray(offset));
907
- if (!result.ok) {
908
- if (result.error.code === "UNEXPECTED_END") {
909
- break;
910
- }
911
- controller.error(result.error);
912
- return;
913
- }
914
- controller.enqueue(result.value);
915
- offset += result.bytesRead;
916
- }
917
- },
918
-
919
- flush(controller) {
920
- if (offset < buffer.length) {
921
- controller.error(
922
- new DecodeError("UNEXPECTED_END", "Stream ended with incomplete message data", 0),
923
- );
924
- }
925
- },
926
- });
927
- }
928
-
929
- // ─── Codec Factory ─────────────────────────────────────────────────────────────
930
-
931
- export interface Draft16Codec extends BaseCodec<Draft16Message> {
932
- readonly draft: "draft-ietf-moq-transport-16";
933
- encodeSubgroupStream(stream: SubgroupStream): Uint8Array;
934
- encodeDatagram(dg: DatagramObject): Uint8Array;
935
- encodeFetchStream(stream: FetchStream): Uint8Array;
936
- decodeSubgroupStream(bytes: Uint8Array): DecodeResult<SubgroupStream>;
937
- decodeDatagram(bytes: Uint8Array): DecodeResult<DatagramObject>;
938
- decodeFetchStream(bytes: Uint8Array): DecodeResult<FetchStream>;
939
- decodeDataStream(
940
- streamType: "subgroup" | "datagram" | "fetch",
941
- bytes: Uint8Array,
942
- ): DecodeResult<Draft16DataStream>;
943
- createStreamDecoder(): TransformStream<Uint8Array, Draft16Message>;
944
- createSubgroupStreamDecoder(): TransformStream<Uint8Array, SubgroupStreamHeader | ObjectPayload>;
945
- createFetchStreamDecoder(): TransformStream<Uint8Array, FetchStreamHeader | ObjectPayload>;
946
- createDataStreamDecoder(): TransformStream<Uint8Array, DataStreamEvent>;
947
- }
948
-
949
- export function createDraft16Codec(): Draft16Codec {
950
- return {
951
- draft: "draft-ietf-moq-transport-16",
952
- encodeMessage,
953
- decodeMessage,
954
- encodeSubgroupStream,
955
- encodeDatagram,
956
- encodeFetchStream,
957
- decodeSubgroupStream,
958
- decodeDatagram,
959
- decodeFetchStream,
960
- decodeDataStream,
961
- createStreamDecoder,
962
- createSubgroupStreamDecoder,
963
- createFetchStreamDecoder,
964
- createDataStreamDecoder,
965
- };
966
- }
1
+ import { BufferReader } from '../../core/buffer-reader.js'
2
+ import { BufferWriter } from '../../core/buffer-writer.js'
3
+ import { bytesToHex, hexToBytes } from '../../core/hex.js'
4
+ import type { BaseCodec, DecodeResult } from '../../core/types.js'
5
+ import { DecodeError } from '../../core/types.js'
6
+ import {
7
+ MESSAGE_ID_MAP,
8
+ MSG_CLIENT_SETUP,
9
+ MSG_FETCH,
10
+ MSG_FETCH_CANCEL,
11
+ MSG_FETCH_OK,
12
+ MSG_GOAWAY,
13
+ MSG_MAX_REQUEST_ID,
14
+ MSG_NAMESPACE,
15
+ MSG_NAMESPACE_DONE,
16
+ MSG_PUBLISH,
17
+ MSG_PUBLISH_DONE,
18
+ MSG_PUBLISH_NAMESPACE,
19
+ MSG_PUBLISH_NAMESPACE_CANCEL,
20
+ MSG_PUBLISH_NAMESPACE_DONE,
21
+ MSG_PUBLISH_OK,
22
+ MSG_REQUEST_ERROR,
23
+ MSG_REQUEST_OK,
24
+ MSG_REQUEST_UPDATE,
25
+ MSG_REQUESTS_BLOCKED,
26
+ MSG_SERVER_SETUP,
27
+ MSG_SUBSCRIBE,
28
+ MSG_SUBSCRIBE_NAMESPACE,
29
+ MSG_SUBSCRIBE_OK,
30
+ MSG_TRACK_STATUS,
31
+ MSG_UNSUBSCRIBE,
32
+ SETUP_PARAM_AUTHORITY,
33
+ SETUP_PARAM_AUTHORIZATION_TOKEN,
34
+ SETUP_PARAM_MAX_AUTH_TOKEN_CACHE_SIZE,
35
+ SETUP_PARAM_MAX_REQUEST_ID,
36
+ SETUP_PARAM_MOQT_IMPLEMENTATION,
37
+ SETUP_PARAM_PATH,
38
+ } from './messages.js'
39
+ import type {
40
+ AuthorizationToken,
41
+ DatagramObject,
42
+ DataStreamEvent,
43
+ Draft16DataStream,
44
+ Draft16Fetch,
45
+ Draft16Message,
46
+ Draft16Params,
47
+ Draft16SetupParams,
48
+ Draft16TrackExtensions,
49
+ FetchStream,
50
+ FetchStreamHeader,
51
+ JoiningFetch,
52
+ ObjectPayload,
53
+ StandaloneFetch,
54
+ SubgroupStream,
55
+ SubgroupStreamHeader,
56
+ UnknownParam,
57
+ } from './types.js'
58
+
59
+ const textEncoder = /* @__PURE__ */ new TextEncoder()
60
+ const textDecoder = /* @__PURE__ */ new TextDecoder()
61
+
62
+ // ─── Setup Parameter Encoding/Decoding ──────────────────────────────────────────
63
+
64
+ function encodeSetupParams(params: Draft16SetupParams, writer: BufferWriter): void {
65
+ let count = 0
66
+ if (params.path !== undefined) count++
67
+ if (params.max_request_id !== undefined) count++
68
+ if (params.authorization_token !== undefined) count++
69
+ if (params.max_auth_token_cache_size !== undefined) count++
70
+ if (params.authority !== undefined) count++
71
+ if (params.moqt_implementation !== undefined) count++
72
+ if (params.unknown) count += params.unknown.length
73
+
74
+ writer.writeVarInt(count)
75
+
76
+ // PATH (0x01) - odd, length-prefixed bytes
77
+ if (params.path !== undefined) {
78
+ writer.writeVarInt(SETUP_PARAM_PATH)
79
+ const encoded = textEncoder.encode(params.path)
80
+ writer.writeVarInt(encoded.byteLength)
81
+ writer.writeBytes(encoded)
82
+ }
83
+
84
+ // MAX_REQUEST_ID (0x02) - even, varint value
85
+ if (params.max_request_id !== undefined) {
86
+ writer.writeVarInt(SETUP_PARAM_MAX_REQUEST_ID)
87
+ writer.writeVarInt(params.max_request_id)
88
+ }
89
+
90
+ // AUTHORIZATION_TOKEN (0x03) - odd, length-prefixed with nested structure
91
+ if (params.authorization_token !== undefined) {
92
+ writer.writeVarInt(SETUP_PARAM_AUTHORIZATION_TOKEN)
93
+ const tmpW = new BufferWriter(64)
94
+ encodeAuthorizationToken(params.authorization_token, tmpW)
95
+ const raw = tmpW.finish()
96
+ writer.writeVarInt(raw.byteLength)
97
+ writer.writeBytes(raw)
98
+ }
99
+
100
+ // MAX_AUTH_TOKEN_CACHE_SIZE (0x04) - even, varint value
101
+ if (params.max_auth_token_cache_size !== undefined) {
102
+ writer.writeVarInt(SETUP_PARAM_MAX_AUTH_TOKEN_CACHE_SIZE)
103
+ writer.writeVarInt(params.max_auth_token_cache_size)
104
+ }
105
+
106
+ // AUTHORITY (0x05) - odd, length-prefixed bytes
107
+ if (params.authority !== undefined) {
108
+ writer.writeVarInt(SETUP_PARAM_AUTHORITY)
109
+ const encoded = textEncoder.encode(params.authority)
110
+ writer.writeVarInt(encoded.byteLength)
111
+ writer.writeBytes(encoded)
112
+ }
113
+
114
+ // MOQT_IMPLEMENTATION (0x07) - odd, length-prefixed bytes
115
+ if (params.moqt_implementation !== undefined) {
116
+ writer.writeVarInt(SETUP_PARAM_MOQT_IMPLEMENTATION)
117
+ const encoded = textEncoder.encode(params.moqt_implementation)
118
+ writer.writeVarInt(encoded.byteLength)
119
+ writer.writeBytes(encoded)
120
+ }
121
+
122
+ // Unknown params
123
+ if (params.unknown) {
124
+ for (const u of params.unknown) {
125
+ const id = BigInt(u.id)
126
+ writer.writeVarInt(id)
127
+ if (id % 2n === 0n) {
128
+ const raw = hexToBytes(u.raw_hex)
129
+ const tmpReader = new BufferReader(raw)
130
+ const value = tmpReader.readVarInt()
131
+ writer.writeVarInt(value)
132
+ } else {
133
+ const raw = hexToBytes(u.raw_hex)
134
+ writer.writeVarInt(raw.byteLength)
135
+ writer.writeBytes(raw)
136
+ }
137
+ }
138
+ }
139
+ }
140
+
141
+ function decodeSetupParams(reader: BufferReader): Draft16SetupParams {
142
+ const count = Number(reader.readVarInt())
143
+ const result: Draft16SetupParams = {}
144
+ const unknown: UnknownParam[] = []
145
+
146
+ for (let i = 0; i < count; i++) {
147
+ const paramType = reader.readVarInt()
148
+
149
+ if (paramType % 2n === 0n) {
150
+ const value = reader.readVarInt()
151
+ if (paramType === SETUP_PARAM_MAX_REQUEST_ID) {
152
+ result.max_request_id = value
153
+ } else if (paramType === SETUP_PARAM_MAX_AUTH_TOKEN_CACHE_SIZE) {
154
+ result.max_auth_token_cache_size = value
155
+ } else {
156
+ const tmpWriter = new BufferWriter(16)
157
+ tmpWriter.writeVarInt(value)
158
+ const raw = tmpWriter.finish()
159
+ unknown.push({
160
+ id: `0x${paramType.toString(16)}`,
161
+ length: raw.byteLength,
162
+ raw_hex: bytesToHex(raw),
163
+ })
164
+ }
165
+ } else {
166
+ const length = Number(reader.readVarInt())
167
+ const bytes = reader.readBytes(length)
168
+ if (paramType === SETUP_PARAM_PATH) {
169
+ result.path = textDecoder.decode(bytes)
170
+ } else if (paramType === SETUP_PARAM_AUTHORIZATION_TOKEN) {
171
+ result.authorization_token = decodeAuthorizationToken(new BufferReader(bytes))
172
+ } else if (paramType === SETUP_PARAM_AUTHORITY) {
173
+ result.authority = textDecoder.decode(bytes)
174
+ } else if (paramType === SETUP_PARAM_MOQT_IMPLEMENTATION) {
175
+ result.moqt_implementation = textDecoder.decode(bytes)
176
+ } else {
177
+ unknown.push({
178
+ id: `0x${paramType.toString(16)}`,
179
+ length,
180
+ raw_hex: bytesToHex(bytes),
181
+ })
182
+ }
183
+ }
184
+ }
185
+
186
+ if (unknown.length > 0) {
187
+ result.unknown = unknown
188
+ }
189
+
190
+ return result
191
+ }
192
+
193
+ // ─── Authorization Token Encoding/Decoding ────────────────────────────────────
194
+
195
+ function encodeAuthorizationToken(token: AuthorizationToken, w: BufferWriter): void {
196
+ w.writeVarInt(token.alias_type)
197
+ const aliasType = Number(token.alias_type)
198
+ if (aliasType === 0 || aliasType === 1) {
199
+ w.writeVarInt(token.token_alias!)
200
+ }
201
+ if (aliasType === 1 || aliasType === 3) {
202
+ w.writeVarInt(token.token_type!)
203
+ const tokenBytes = hexToBytes(token.token_value_hex!)
204
+ w.writeBytes(tokenBytes)
205
+ }
206
+ }
207
+
208
+ function decodeAuthorizationToken(r: BufferReader): AuthorizationToken {
209
+ const alias_type = r.readVarInt()
210
+ const aliasType = Number(alias_type)
211
+ const result: Record<string, unknown> = { alias_type }
212
+ if (aliasType === 0 || aliasType === 1) {
213
+ result.token_alias = r.readVarInt()
214
+ }
215
+ if (aliasType === 1 || aliasType === 3) {
216
+ result.token_type = r.readVarInt()
217
+ const tokenBytes = r.readBytesView(r.remaining)
218
+ result.token_value_hex = bytesToHex(tokenBytes)
219
+ }
220
+ return result as unknown as AuthorizationToken
221
+ }
222
+
223
+ // ─── Version-Specific Parameter Encoding/Decoding ───────────────────────────────
224
+
225
+ const PARAM_DELIVERY_TIMEOUT = 0x02n
226
+ const PARAM_AUTHORIZATION_TOKEN = 0x03n
227
+ const PARAM_MAX_CACHE_DURATION = 0x04n
228
+ const PARAM_EXPIRES = 0x08n
229
+ const PARAM_LARGEST_OBJECT = 0x09n
230
+ const PARAM_PUBLISHER_PRIORITY = 0x0en
231
+ const PARAM_FORWARD = 0x10n
232
+ const PARAM_SUBSCRIBER_PRIORITY = 0x20n
233
+ const PARAM_SUBSCRIPTION_FILTER = 0x21n
234
+ const PARAM_GROUP_ORDER = 0x22n
235
+ const PARAM_DYNAMIC_GROUPS = 0x30n
236
+ const PARAM_NEW_GROUP_REQUEST = 0x32n
237
+
238
+ // Track extension IDs (same encoding as params, but separate namespace)
239
+ const TRACK_EXT_DELIVERY_TIMEOUT = 0x02n
240
+ const TRACK_EXT_MAX_CACHE_DURATION = 0x04n
241
+ const TRACK_EXT_DEFAULT_PUBLISHER_PRIORITY = 0x0en
242
+
243
+ function encodeTrackExtensions(ext: Draft16TrackExtensions, writer: BufferWriter): void {
244
+ if (ext.delivery_timeout !== undefined) {
245
+ writer.writeVarInt(TRACK_EXT_DELIVERY_TIMEOUT)
246
+ writer.writeVarInt(ext.delivery_timeout)
247
+ }
248
+ if (ext.max_cache_duration !== undefined) {
249
+ writer.writeVarInt(TRACK_EXT_MAX_CACHE_DURATION)
250
+ writer.writeVarInt(ext.max_cache_duration)
251
+ }
252
+ if (ext.default_publisher_priority !== undefined) {
253
+ writer.writeVarInt(TRACK_EXT_DEFAULT_PUBLISHER_PRIORITY)
254
+ writer.writeVarInt(ext.default_publisher_priority)
255
+ }
256
+ if (ext.unknown) {
257
+ for (const u of ext.unknown) {
258
+ const id = BigInt(u.id)
259
+ writer.writeVarInt(id)
260
+ if (id % 2n === 0n) {
261
+ const raw = hexToBytes(u.raw_hex)
262
+ const tmpReader = new BufferReader(raw)
263
+ const value = tmpReader.readVarInt()
264
+ writer.writeVarInt(value)
265
+ } else {
266
+ const raw = hexToBytes(u.raw_hex)
267
+ writer.writeVarInt(raw.byteLength)
268
+ writer.writeBytes(raw)
269
+ }
270
+ }
271
+ }
272
+ }
273
+
274
+ function decodeTrackExtensions(reader: BufferReader): Draft16TrackExtensions {
275
+ const result: Draft16TrackExtensions = {}
276
+ const unknown: UnknownParam[] = []
277
+
278
+ while (reader.remaining > 0) {
279
+ const extType = reader.readVarInt()
280
+ if (extType === TRACK_EXT_DELIVERY_TIMEOUT) {
281
+ result.delivery_timeout = reader.readVarInt()
282
+ } else if (extType === TRACK_EXT_MAX_CACHE_DURATION) {
283
+ result.max_cache_duration = reader.readVarInt()
284
+ } else if (extType === TRACK_EXT_DEFAULT_PUBLISHER_PRIORITY) {
285
+ result.default_publisher_priority = reader.readVarInt()
286
+ } else if (extType % 2n === 0n) {
287
+ const value = reader.readVarInt()
288
+ const tmpWriter = new BufferWriter(16)
289
+ tmpWriter.writeVarInt(value)
290
+ const raw = tmpWriter.finish()
291
+ unknown.push({
292
+ id: `0x${extType.toString(16)}`,
293
+ length: raw.byteLength,
294
+ raw_hex: bytesToHex(raw),
295
+ })
296
+ } else {
297
+ const length = Number(reader.readVarInt())
298
+ const bytes = reader.readBytes(length)
299
+ unknown.push({
300
+ id: `0x${extType.toString(16)}`,
301
+ length,
302
+ raw_hex: bytesToHex(bytes),
303
+ })
304
+ }
305
+ }
306
+
307
+ if (unknown.length > 0) {
308
+ result.unknown = unknown
309
+ }
310
+
311
+ return result
312
+ }
313
+
314
+ function encodeParams(params: Draft16Params, writer: BufferWriter): void {
315
+ let count = params.unknown ? params.unknown.length : 0
316
+ if (params.delivery_timeout !== undefined) count++
317
+ if (params.authorization_token !== undefined) count++
318
+ if (params.max_cache_duration !== undefined) count++
319
+ if (params.expires !== undefined) count++
320
+ if (params.largest_object !== undefined) count++
321
+ if (params.publisher_priority !== undefined) count++
322
+ if (params.forward !== undefined) count++
323
+ if (params.subscriber_priority !== undefined) count++
324
+ if (params.subscription_filter !== undefined) count++
325
+ if (params.group_order !== undefined) count++
326
+ if (params.dynamic_groups !== undefined) count++
327
+ if (params.new_group_request !== undefined) count++
328
+ writer.writeVarInt(count)
329
+
330
+ if (params.delivery_timeout !== undefined) {
331
+ writer.writeVarInt(PARAM_DELIVERY_TIMEOUT)
332
+ writer.writeVarInt(params.delivery_timeout)
333
+ }
334
+ if (params.authorization_token !== undefined) {
335
+ writer.writeVarInt(PARAM_AUTHORIZATION_TOKEN)
336
+ const tmpW = new BufferWriter(64)
337
+ encodeAuthorizationToken(params.authorization_token, tmpW)
338
+ const raw = tmpW.finish()
339
+ writer.writeVarInt(raw.byteLength)
340
+ writer.writeBytes(raw)
341
+ }
342
+ if (params.max_cache_duration !== undefined) {
343
+ writer.writeVarInt(PARAM_MAX_CACHE_DURATION)
344
+ writer.writeVarInt(params.max_cache_duration)
345
+ }
346
+ if (params.expires !== undefined) {
347
+ writer.writeVarInt(PARAM_EXPIRES)
348
+ writer.writeVarInt(params.expires)
349
+ }
350
+ if (params.largest_object !== undefined) {
351
+ writer.writeVarInt(PARAM_LARGEST_OBJECT)
352
+ const tmpW = new BufferWriter(16)
353
+ tmpW.writeVarInt(params.largest_object.group)
354
+ tmpW.writeVarInt(params.largest_object.object)
355
+ const raw = tmpW.finish()
356
+ writer.writeVarInt(raw.byteLength)
357
+ writer.writeBytes(raw)
358
+ }
359
+ if (params.publisher_priority !== undefined) {
360
+ writer.writeVarInt(PARAM_PUBLISHER_PRIORITY)
361
+ writer.writeVarInt(params.publisher_priority)
362
+ }
363
+ if (params.forward !== undefined) {
364
+ writer.writeVarInt(PARAM_FORWARD)
365
+ writer.writeVarInt(params.forward)
366
+ }
367
+ if (params.subscriber_priority !== undefined) {
368
+ writer.writeVarInt(PARAM_SUBSCRIBER_PRIORITY)
369
+ writer.writeVarInt(params.subscriber_priority)
370
+ }
371
+ if (params.subscription_filter !== undefined) {
372
+ writer.writeVarInt(PARAM_SUBSCRIPTION_FILTER)
373
+ const tmpW = new BufferWriter(32)
374
+ const f = params.subscription_filter
375
+ tmpW.writeVarInt(f.filter_type)
376
+ if (f.filter_type === 3n || f.filter_type === 4n) {
377
+ tmpW.writeVarInt(f.start_group!)
378
+ tmpW.writeVarInt(f.start_object!)
379
+ }
380
+ if (f.filter_type === 4n) {
381
+ tmpW.writeVarInt(f.end_group!)
382
+ }
383
+ const raw = tmpW.finish()
384
+ writer.writeVarInt(raw.byteLength)
385
+ writer.writeBytes(raw)
386
+ }
387
+ if (params.group_order !== undefined) {
388
+ writer.writeVarInt(PARAM_GROUP_ORDER)
389
+ writer.writeVarInt(params.group_order)
390
+ }
391
+ if (params.dynamic_groups !== undefined) {
392
+ writer.writeVarInt(PARAM_DYNAMIC_GROUPS)
393
+ writer.writeVarInt(params.dynamic_groups)
394
+ }
395
+ if (params.new_group_request !== undefined) {
396
+ writer.writeVarInt(PARAM_NEW_GROUP_REQUEST)
397
+ writer.writeVarInt(params.new_group_request)
398
+ }
399
+
400
+ if (params.unknown) {
401
+ for (const u of params.unknown) {
402
+ const id = BigInt(u.id)
403
+ writer.writeVarInt(id)
404
+ if (id % 2n === 0n) {
405
+ const raw = hexToBytes(u.raw_hex)
406
+ const tmpReader = new BufferReader(raw)
407
+ const value = tmpReader.readVarInt()
408
+ writer.writeVarInt(value)
409
+ } else {
410
+ const raw = hexToBytes(u.raw_hex)
411
+ writer.writeVarInt(raw.byteLength)
412
+ writer.writeBytes(raw)
413
+ }
414
+ }
415
+ }
416
+ }
417
+
418
+ function decodeParams(reader: BufferReader): Draft16Params {
419
+ const count = Number(reader.readVarInt())
420
+ const result: Draft16Params = {}
421
+ const unknown: UnknownParam[] = []
422
+
423
+ for (let i = 0; i < count; i++) {
424
+ const paramType = reader.readVarInt()
425
+
426
+ if (paramType === PARAM_DELIVERY_TIMEOUT) {
427
+ result.delivery_timeout = reader.readVarInt()
428
+ } else if (paramType === PARAM_AUTHORIZATION_TOKEN) {
429
+ const length = Number(reader.readVarInt())
430
+ const tokenBytes = reader.readBytes(length)
431
+ result.authorization_token = decodeAuthorizationToken(new BufferReader(tokenBytes))
432
+ } else if (paramType === PARAM_MAX_CACHE_DURATION) {
433
+ result.max_cache_duration = reader.readVarInt()
434
+ } else if (paramType === PARAM_EXPIRES) {
435
+ result.expires = reader.readVarInt()
436
+ } else if (paramType === PARAM_PUBLISHER_PRIORITY) {
437
+ result.publisher_priority = reader.readVarInt()
438
+ } else if (paramType === PARAM_FORWARD) {
439
+ result.forward = reader.readVarInt()
440
+ } else if (paramType === PARAM_SUBSCRIBER_PRIORITY) {
441
+ result.subscriber_priority = reader.readVarInt()
442
+ } else if (paramType === PARAM_GROUP_ORDER) {
443
+ result.group_order = reader.readVarInt()
444
+ } else if (paramType === PARAM_DYNAMIC_GROUPS) {
445
+ result.dynamic_groups = reader.readVarInt()
446
+ } else if (paramType === PARAM_NEW_GROUP_REQUEST) {
447
+ result.new_group_request = reader.readVarInt()
448
+ } else if (paramType === PARAM_LARGEST_OBJECT) {
449
+ const length = Number(reader.readVarInt())
450
+ const startOff = reader.offset
451
+ const group = reader.readVarInt()
452
+ const object = reader.readVarInt()
453
+ const consumed = reader.offset - startOff
454
+ if (consumed < length) reader.readBytes(length - consumed)
455
+ result.largest_object = { group, object }
456
+ } else if (paramType === PARAM_SUBSCRIPTION_FILTER) {
457
+ const length = Number(reader.readVarInt())
458
+ const startOff = reader.offset
459
+ const filter_type = reader.readVarInt()
460
+ const filter: {
461
+ filter_type: bigint
462
+ start_group?: bigint
463
+ start_object?: bigint
464
+ end_group?: bigint
465
+ } = { filter_type }
466
+ if (filter_type === 3n || filter_type === 4n) {
467
+ filter.start_group = reader.readVarInt()
468
+ filter.start_object = reader.readVarInt()
469
+ }
470
+ if (filter_type === 4n) {
471
+ filter.end_group = reader.readVarInt()
472
+ }
473
+ const consumed = reader.offset - startOff
474
+ if (consumed < length) reader.readBytes(length - consumed)
475
+ result.subscription_filter = filter
476
+ } else if (paramType % 2n === 0n) {
477
+ const value = reader.readVarInt()
478
+ const tmpWriter = new BufferWriter(16)
479
+ tmpWriter.writeVarInt(value)
480
+ const raw = tmpWriter.finish()
481
+ unknown.push({
482
+ id: `0x${paramType.toString(16)}`,
483
+ length: raw.byteLength,
484
+ raw_hex: bytesToHex(raw),
485
+ })
486
+ } else {
487
+ const length = Number(reader.readVarInt())
488
+ const bytes = reader.readBytes(length)
489
+ unknown.push({
490
+ id: `0x${paramType.toString(16)}`,
491
+ length,
492
+ raw_hex: bytesToHex(bytes),
493
+ })
494
+ }
495
+ }
496
+
497
+ if (unknown.length > 0) {
498
+ result.unknown = unknown
499
+ }
500
+
501
+ return result
502
+ }
503
+
504
+ // ─── Payload Encoders ──────────────────────────────────────────────────────────
505
+
506
+ function encodeClientSetupPayload(
507
+ msg: Draft16Message & { type: 'client_setup' },
508
+ w: BufferWriter,
509
+ ): void {
510
+ encodeSetupParams(msg.parameters, w)
511
+ }
512
+
513
+ function encodeServerSetupPayload(
514
+ msg: Draft16Message & { type: 'server_setup' },
515
+ w: BufferWriter,
516
+ ): void {
517
+ encodeSetupParams(msg.parameters, w)
518
+ }
519
+
520
+ function encodeSubscribePayload(
521
+ msg: Draft16Message & { type: 'subscribe' },
522
+ w: BufferWriter,
523
+ ): void {
524
+ w.writeVarInt(msg.request_id)
525
+ w.writeTuple(msg.track_namespace)
526
+ w.writeString(msg.track_name)
527
+ encodeParams(msg.parameters, w)
528
+ }
529
+
530
+ function encodeSubscribeOkPayload(
531
+ msg: Draft16Message & { type: 'subscribe_ok' },
532
+ w: BufferWriter,
533
+ ): void {
534
+ w.writeVarInt(msg.request_id)
535
+ w.writeVarInt(msg.track_alias)
536
+ encodeParams(msg.parameters, w)
537
+ if (msg.track_extensions) encodeTrackExtensions(msg.track_extensions, w)
538
+ }
539
+
540
+ function encodeRequestUpdatePayload(
541
+ msg: Draft16Message & { type: 'request_update' },
542
+ w: BufferWriter,
543
+ ): void {
544
+ w.writeVarInt(msg.request_id)
545
+ w.writeVarInt(msg.existing_request_id)
546
+ encodeParams(msg.parameters, w)
547
+ }
548
+
549
+ function encodeUnsubscribePayload(
550
+ msg: Draft16Message & { type: 'unsubscribe' },
551
+ w: BufferWriter,
552
+ ): void {
553
+ w.writeVarInt(msg.request_id)
554
+ }
555
+
556
+ function encodePublishPayload(msg: Draft16Message & { type: 'publish' }, w: BufferWriter): void {
557
+ w.writeVarInt(msg.request_id)
558
+ w.writeTuple(msg.track_namespace)
559
+ w.writeString(msg.track_name)
560
+ w.writeVarInt(msg.track_alias)
561
+ encodeParams(msg.parameters, w)
562
+ if (msg.track_extensions) encodeTrackExtensions(msg.track_extensions, w)
563
+ }
564
+
565
+ function encodePublishOkPayload(
566
+ msg: Draft16Message & { type: 'publish_ok' },
567
+ w: BufferWriter,
568
+ ): void {
569
+ w.writeVarInt(msg.request_id)
570
+ encodeParams(msg.parameters, w)
571
+ }
572
+
573
+ function encodePublishDonePayload(
574
+ msg: Draft16Message & { type: 'publish_done' },
575
+ w: BufferWriter,
576
+ ): void {
577
+ w.writeVarInt(msg.request_id)
578
+ w.writeVarInt(msg.status_code)
579
+ w.writeVarInt(msg.stream_count)
580
+ w.writeString(msg.reason_phrase)
581
+ }
582
+
583
+ function encodePublishNamespacePayload(
584
+ msg: Draft16Message & { type: 'publish_namespace' },
585
+ w: BufferWriter,
586
+ ): void {
587
+ w.writeVarInt(msg.request_id)
588
+ w.writeTuple(msg.track_namespace)
589
+ encodeParams(msg.parameters, w)
590
+ }
591
+
592
+ // Draft-16: simplified to just request_id
593
+ function encodePublishNamespaceDonePayload(
594
+ msg: Draft16Message & { type: 'publish_namespace_done' },
595
+ w: BufferWriter,
596
+ ): void {
597
+ w.writeVarInt(msg.request_id)
598
+ }
599
+
600
+ // Draft-16: changed to request_id + error_code + reason_phrase
601
+ function encodePublishNamespaceCancelPayload(
602
+ msg: Draft16Message & { type: 'publish_namespace_cancel' },
603
+ w: BufferWriter,
604
+ ): void {
605
+ w.writeVarInt(msg.request_id)
606
+ w.writeVarInt(msg.error_code)
607
+ w.writeString(msg.reason_phrase)
608
+ }
609
+
610
+ // Draft-16: added subscribe_options
611
+ function encodeSubscribeNamespacePayload(
612
+ msg: Draft16Message & { type: 'subscribe_namespace' },
613
+ w: BufferWriter,
614
+ ): void {
615
+ w.writeVarInt(msg.request_id)
616
+ w.writeTuple(msg.namespace_prefix)
617
+ w.writeVarInt(msg.subscribe_options)
618
+ encodeParams(msg.parameters, w)
619
+ }
620
+
621
+ // New in draft-16
622
+ function encodeNamespacePayload(
623
+ msg: Draft16Message & { type: 'namespace' },
624
+ w: BufferWriter,
625
+ ): void {
626
+ w.writeTuple(msg.namespace_suffix)
627
+ }
628
+
629
+ // New in draft-16
630
+ function encodeNamespaceDonePayload(
631
+ msg: Draft16Message & { type: 'namespace_done' },
632
+ w: BufferWriter,
633
+ ): void {
634
+ w.writeTuple(msg.namespace_suffix)
635
+ }
636
+
637
+ function encodeFetchPayload(msg: Draft16Message & { type: 'fetch' }, w: BufferWriter): void {
638
+ w.writeVarInt(msg.request_id)
639
+ w.writeVarInt(msg.fetch_type)
640
+ const ft = Number(msg.fetch_type)
641
+ if (ft === 1 && msg.standalone) {
642
+ w.writeTuple(msg.standalone.track_namespace)
643
+ w.writeString(msg.standalone.track_name)
644
+ w.writeVarInt(msg.standalone.start_group)
645
+ w.writeVarInt(msg.standalone.start_object)
646
+ w.writeVarInt(msg.standalone.end_group)
647
+ w.writeVarInt(msg.standalone.end_object)
648
+ } else if ((ft === 2 || ft === 3) && msg.joining) {
649
+ w.writeVarInt(msg.joining.joining_request_id)
650
+ w.writeVarInt(msg.joining.joining_start)
651
+ }
652
+ encodeParams(msg.parameters, w)
653
+ }
654
+
655
+ function encodeFetchOkPayload(msg: Draft16Message & { type: 'fetch_ok' }, w: BufferWriter): void {
656
+ w.writeVarInt(msg.request_id)
657
+ w.writeUint8(msg.end_of_track)
658
+ w.writeVarInt(msg.end_group)
659
+ w.writeVarInt(msg.end_object)
660
+ encodeParams(msg.parameters, w)
661
+ if (msg.track_extensions) encodeTrackExtensions(msg.track_extensions, w)
662
+ }
663
+
664
+ function encodeFetchCancelPayload(
665
+ msg: Draft16Message & { type: 'fetch_cancel' },
666
+ w: BufferWriter,
667
+ ): void {
668
+ w.writeVarInt(msg.request_id)
669
+ }
670
+
671
+ function encodeTrackStatusPayload(
672
+ msg: Draft16Message & { type: 'track_status' },
673
+ w: BufferWriter,
674
+ ): void {
675
+ w.writeVarInt(msg.request_id)
676
+ w.writeTuple(msg.track_namespace)
677
+ w.writeString(msg.track_name)
678
+ encodeParams(msg.parameters, w)
679
+ }
680
+
681
+ function encodeRequestOkPayload(
682
+ msg: Draft16Message & { type: 'request_ok' },
683
+ w: BufferWriter,
684
+ ): void {
685
+ w.writeVarInt(msg.request_id)
686
+ encodeParams(msg.parameters, w)
687
+ }
688
+
689
+ // Draft-16: added retry_interval
690
+ function encodeRequestErrorPayload(
691
+ msg: Draft16Message & { type: 'request_error' },
692
+ w: BufferWriter,
693
+ ): void {
694
+ w.writeVarInt(msg.request_id)
695
+ w.writeVarInt(msg.error_code)
696
+ w.writeVarInt(msg.retry_interval)
697
+ w.writeString(msg.reason_phrase)
698
+ }
699
+
700
+ function encodeGoAwayPayload(msg: Draft16Message & { type: 'goaway' }, w: BufferWriter): void {
701
+ w.writeString(msg.new_session_uri)
702
+ }
703
+
704
+ function encodeMaxRequestIdPayload(
705
+ msg: Draft16Message & { type: 'max_request_id' },
706
+ w: BufferWriter,
707
+ ): void {
708
+ w.writeVarInt(msg.max_request_id)
709
+ }
710
+
711
+ function encodeRequestsBlockedPayload(
712
+ msg: Draft16Message & { type: 'requests_blocked' },
713
+ w: BufferWriter,
714
+ ): void {
715
+ w.writeVarInt(msg.maximum_request_id)
716
+ }
717
+
718
+ // ─── Payload Decoders ──────────────────────────────────────────────────────────
719
+
720
+ function decodeClientSetupPayload(r: BufferReader): Draft16Message {
721
+ const parameters = decodeSetupParams(r)
722
+ return { type: 'client_setup', parameters }
723
+ }
724
+
725
+ function decodeServerSetupPayload(r: BufferReader): Draft16Message {
726
+ const parameters = decodeSetupParams(r)
727
+ return { type: 'server_setup', parameters }
728
+ }
729
+
730
+ function decodeSubscribePayload(r: BufferReader): Draft16Message {
731
+ const request_id = r.readVarInt()
732
+ const track_namespace = r.readTuple()
733
+ const track_name = r.readString()
734
+ const parameters = decodeParams(r)
735
+ return {
736
+ type: 'subscribe',
737
+ request_id,
738
+ track_namespace,
739
+ track_name,
740
+ parameters,
741
+ }
742
+ }
743
+
744
+ function decodeSubscribeOkPayload(r: BufferReader): Draft16Message {
745
+ const request_id = r.readVarInt()
746
+ const track_alias = r.readVarInt()
747
+ const parameters = decodeParams(r)
748
+ const result: Record<string, unknown> = {
749
+ type: 'subscribe_ok',
750
+ request_id,
751
+ track_alias,
752
+ parameters,
753
+ }
754
+ if (r.remaining > 0) {
755
+ result.track_extensions = decodeTrackExtensions(r)
756
+ }
757
+ return result as unknown as Draft16Message
758
+ }
759
+
760
+ function decodeRequestUpdatePayload(r: BufferReader): Draft16Message {
761
+ const request_id = r.readVarInt()
762
+ const existing_request_id = r.readVarInt()
763
+ const parameters = decodeParams(r)
764
+ return { type: 'request_update', request_id, existing_request_id, parameters }
765
+ }
766
+
767
+ function decodeUnsubscribePayload(r: BufferReader): Draft16Message {
768
+ const request_id = r.readVarInt()
769
+ return { type: 'unsubscribe', request_id }
770
+ }
771
+
772
+ function decodePublishPayload(r: BufferReader): Draft16Message {
773
+ const request_id = r.readVarInt()
774
+ const track_namespace = r.readTuple()
775
+ const track_name = r.readString()
776
+ const track_alias = r.readVarInt()
777
+ const parameters = decodeParams(r)
778
+ const result: Record<string, unknown> = {
779
+ type: 'publish',
780
+ request_id,
781
+ track_namespace,
782
+ track_name,
783
+ track_alias,
784
+ parameters,
785
+ }
786
+ if (r.remaining > 0) {
787
+ result.track_extensions = decodeTrackExtensions(r)
788
+ }
789
+ return result as unknown as Draft16Message
790
+ }
791
+
792
+ function decodePublishOkPayload(r: BufferReader): Draft16Message {
793
+ const request_id = r.readVarInt()
794
+ const parameters = decodeParams(r)
795
+ return { type: 'publish_ok', request_id, parameters }
796
+ }
797
+
798
+ function decodePublishDonePayload(r: BufferReader): Draft16Message {
799
+ const request_id = r.readVarInt()
800
+ const status_code = r.readVarInt()
801
+ const stream_count = r.readVarInt()
802
+ const reason_phrase = r.readString()
803
+ return {
804
+ type: 'publish_done',
805
+ request_id,
806
+ status_code,
807
+ stream_count,
808
+ reason_phrase,
809
+ }
810
+ }
811
+
812
+ function decodePublishNamespacePayload(r: BufferReader): Draft16Message {
813
+ const request_id = r.readVarInt()
814
+ const track_namespace = r.readTuple()
815
+ const parameters = decodeParams(r)
816
+ return { type: 'publish_namespace', request_id, track_namespace, parameters }
817
+ }
818
+
819
+ // Draft-16: simplified to just request_id
820
+ function decodePublishNamespaceDonePayload(r: BufferReader): Draft16Message {
821
+ const request_id = r.readVarInt()
822
+ return { type: 'publish_namespace_done', request_id }
823
+ }
824
+
825
+ // Draft-16: changed to request_id + error_code + reason_phrase
826
+ function decodePublishNamespaceCancelPayload(r: BufferReader): Draft16Message {
827
+ const request_id = r.readVarInt()
828
+ const error_code = r.readVarInt()
829
+ const reason_phrase = r.readString()
830
+ return {
831
+ type: 'publish_namespace_cancel',
832
+ request_id,
833
+ error_code,
834
+ reason_phrase,
835
+ }
836
+ }
837
+
838
+ // Draft-16: added subscribe_options
839
+ function decodeSubscribeNamespacePayload(r: BufferReader): Draft16Message {
840
+ const request_id = r.readVarInt()
841
+ const namespace_prefix = r.readTuple()
842
+ const subscribe_options = r.readVarInt()
843
+ const parameters = decodeParams(r)
844
+ return {
845
+ type: 'subscribe_namespace',
846
+ request_id,
847
+ namespace_prefix,
848
+ subscribe_options,
849
+ parameters,
850
+ }
851
+ }
852
+
853
+ // New in draft-16
854
+ function decodeNamespacePayload(r: BufferReader): Draft16Message {
855
+ const namespace_suffix = r.readTuple()
856
+ return { type: 'namespace', namespace_suffix }
857
+ }
858
+
859
+ // New in draft-16
860
+ function decodeNamespaceDonePayload(r: BufferReader): Draft16Message {
861
+ const namespace_suffix = r.readTuple()
862
+ return { type: 'namespace_done', namespace_suffix }
863
+ }
864
+
865
+ function decodeFetchPayload(r: BufferReader): Draft16Message {
866
+ const request_id = r.readVarInt()
867
+ const fetch_type = r.readVarInt()
868
+ const ft = Number(fetch_type)
869
+
870
+ if (ft < 1 || ft > 3) {
871
+ throw new DecodeError('CONSTRAINT_VIOLATION', `Invalid fetch_type: ${ft}`, r.offset)
872
+ }
873
+
874
+ let standalone: StandaloneFetch | undefined
875
+ let joining: JoiningFetch | undefined
876
+
877
+ if (ft === 1) {
878
+ const track_namespace = r.readTuple()
879
+ const track_name = r.readString()
880
+ const start_group = r.readVarInt()
881
+ const start_object = r.readVarInt()
882
+ const end_group = r.readVarInt()
883
+ const end_object = r.readVarInt()
884
+ standalone = {
885
+ track_namespace,
886
+ track_name,
887
+ start_group,
888
+ start_object,
889
+ end_group,
890
+ end_object,
891
+ }
892
+ } else {
893
+ const joining_request_id = r.readVarInt()
894
+ const joining_start = r.readVarInt()
895
+ joining = { joining_request_id, joining_start }
896
+ }
897
+
898
+ const parameters = decodeParams(r)
899
+
900
+ return {
901
+ type: 'fetch',
902
+ request_id,
903
+ fetch_type,
904
+ standalone,
905
+ joining,
906
+ parameters,
907
+ } as Draft16Fetch
908
+ }
909
+
910
+ function decodeFetchOkPayload(r: BufferReader): Draft16Message {
911
+ const request_id = r.readVarInt()
912
+ const end_of_track = r.readUint8()
913
+ const end_group = r.readVarInt()
914
+ const end_object = r.readVarInt()
915
+ const parameters = decodeParams(r)
916
+ const result: Record<string, unknown> = {
917
+ type: 'fetch_ok',
918
+ request_id,
919
+ end_of_track,
920
+ end_group,
921
+ end_object,
922
+ parameters,
923
+ }
924
+ if (r.remaining > 0) {
925
+ result.track_extensions = decodeTrackExtensions(r)
926
+ }
927
+ return result as unknown as Draft16Message
928
+ }
929
+
930
+ function decodeFetchCancelPayload(r: BufferReader): Draft16Message {
931
+ const request_id = r.readVarInt()
932
+ return { type: 'fetch_cancel', request_id }
933
+ }
934
+
935
+ function decodeTrackStatusPayload(r: BufferReader): Draft16Message {
936
+ const request_id = r.readVarInt()
937
+ const track_namespace = r.readTuple()
938
+ const track_name = r.readString()
939
+ const parameters = decodeParams(r)
940
+ return {
941
+ type: 'track_status',
942
+ request_id,
943
+ track_namespace,
944
+ track_name,
945
+ parameters,
946
+ }
947
+ }
948
+
949
+ function decodeRequestOkPayload(r: BufferReader): Draft16Message {
950
+ const request_id = r.readVarInt()
951
+ const parameters = decodeParams(r)
952
+ return { type: 'request_ok', request_id, parameters }
953
+ }
954
+
955
+ // Draft-16: added retry_interval
956
+ function decodeRequestErrorPayload(r: BufferReader): Draft16Message {
957
+ const request_id = r.readVarInt()
958
+ const error_code = r.readVarInt()
959
+ const retry_interval = r.readVarInt()
960
+ const reason_phrase = r.readString()
961
+ return {
962
+ type: 'request_error',
963
+ request_id,
964
+ error_code,
965
+ retry_interval,
966
+ reason_phrase,
967
+ }
968
+ }
969
+
970
+ function decodeGoAwayPayload(r: BufferReader): Draft16Message {
971
+ const new_session_uri = r.readString()
972
+ return { type: 'goaway', new_session_uri }
973
+ }
974
+
975
+ function decodeMaxRequestIdPayload(r: BufferReader): Draft16Message {
976
+ const max_request_id = r.readVarInt()
977
+ return { type: 'max_request_id', max_request_id }
978
+ }
979
+
980
+ function decodeRequestsBlockedPayload(r: BufferReader): Draft16Message {
981
+ const maximum_request_id = r.readVarInt()
982
+ return { type: 'requests_blocked', maximum_request_id }
983
+ }
984
+
985
+ // ─── Payload dispatch tables ───────────────────────────────────────────────────
986
+
987
+ const payloadDecoders: ReadonlyMap<bigint, (r: BufferReader) => Draft16Message> = new Map([
988
+ [MSG_CLIENT_SETUP, decodeClientSetupPayload],
989
+ [MSG_SERVER_SETUP, decodeServerSetupPayload],
990
+ [MSG_SUBSCRIBE, decodeSubscribePayload],
991
+ [MSG_SUBSCRIBE_OK, decodeSubscribeOkPayload],
992
+ [MSG_REQUEST_UPDATE, decodeRequestUpdatePayload],
993
+ [MSG_UNSUBSCRIBE, decodeUnsubscribePayload],
994
+ [MSG_PUBLISH, decodePublishPayload],
995
+ [MSG_PUBLISH_OK, decodePublishOkPayload],
996
+ [MSG_PUBLISH_DONE, decodePublishDonePayload],
997
+ [MSG_PUBLISH_NAMESPACE, decodePublishNamespacePayload],
998
+ [MSG_PUBLISH_NAMESPACE_DONE, decodePublishNamespaceDonePayload],
999
+ [MSG_PUBLISH_NAMESPACE_CANCEL, decodePublishNamespaceCancelPayload],
1000
+ [MSG_SUBSCRIBE_NAMESPACE, decodeSubscribeNamespacePayload],
1001
+ [MSG_NAMESPACE, decodeNamespacePayload],
1002
+ [MSG_NAMESPACE_DONE, decodeNamespaceDonePayload],
1003
+ [MSG_FETCH, decodeFetchPayload],
1004
+ [MSG_FETCH_OK, decodeFetchOkPayload],
1005
+ [MSG_FETCH_CANCEL, decodeFetchCancelPayload],
1006
+ [MSG_TRACK_STATUS, decodeTrackStatusPayload],
1007
+ [MSG_REQUEST_OK, decodeRequestOkPayload],
1008
+ [MSG_REQUEST_ERROR, decodeRequestErrorPayload],
1009
+ [MSG_GOAWAY, decodeGoAwayPayload],
1010
+ [MSG_MAX_REQUEST_ID, decodeMaxRequestIdPayload],
1011
+ [MSG_REQUESTS_BLOCKED, decodeRequestsBlockedPayload],
1012
+ ])
1013
+
1014
+ // ─── Public API ────────────────────────────────────────────────────────────────
1015
+
1016
+ /**
1017
+ * Encode a draft-16 control message with type(varint) + length(uint16 BE) + payload.
1018
+ */
1019
+ export function encodeMessage(message: Draft16Message): Uint8Array {
1020
+ const typeId = MESSAGE_ID_MAP.get(message.type)
1021
+ if (typeId === undefined) {
1022
+ throw new Error(`Unknown message type: ${message.type}`)
1023
+ }
1024
+
1025
+ const payloadWriter = new BufferWriter()
1026
+ encodePayload(message, payloadWriter)
1027
+ const payload = payloadWriter.finishView()
1028
+
1029
+ if (payload.byteLength > 0xffff) {
1030
+ throw new Error(`Payload too large for 16-bit length: ${payload.byteLength}`)
1031
+ }
1032
+
1033
+ const writer = new BufferWriter(payload.byteLength + 16)
1034
+ writer.writeVarInt(typeId)
1035
+ writer.writeUint8((payload.byteLength >> 8) & 0xff)
1036
+ writer.writeUint8(payload.byteLength & 0xff)
1037
+ writer.writeBytes(payload)
1038
+
1039
+ return writer.finish()
1040
+ }
1041
+
1042
+ function encodePayload(msg: Draft16Message, w: BufferWriter): void {
1043
+ switch (msg.type) {
1044
+ case 'client_setup':
1045
+ return encodeClientSetupPayload(msg, w)
1046
+ case 'server_setup':
1047
+ return encodeServerSetupPayload(msg, w)
1048
+ case 'subscribe':
1049
+ return encodeSubscribePayload(msg, w)
1050
+ case 'subscribe_ok':
1051
+ return encodeSubscribeOkPayload(msg, w)
1052
+ case 'request_update':
1053
+ return encodeRequestUpdatePayload(msg, w)
1054
+ case 'unsubscribe':
1055
+ return encodeUnsubscribePayload(msg, w)
1056
+ case 'publish':
1057
+ return encodePublishPayload(msg, w)
1058
+ case 'publish_ok':
1059
+ return encodePublishOkPayload(msg, w)
1060
+ case 'publish_done':
1061
+ return encodePublishDonePayload(msg, w)
1062
+ case 'publish_namespace':
1063
+ return encodePublishNamespacePayload(msg, w)
1064
+ case 'publish_namespace_done':
1065
+ return encodePublishNamespaceDonePayload(msg, w)
1066
+ case 'publish_namespace_cancel':
1067
+ return encodePublishNamespaceCancelPayload(msg, w)
1068
+ case 'subscribe_namespace':
1069
+ return encodeSubscribeNamespacePayload(msg, w)
1070
+ case 'namespace':
1071
+ return encodeNamespacePayload(msg, w)
1072
+ case 'namespace_done':
1073
+ return encodeNamespaceDonePayload(msg, w)
1074
+ case 'fetch':
1075
+ return encodeFetchPayload(msg, w)
1076
+ case 'fetch_ok':
1077
+ return encodeFetchOkPayload(msg, w)
1078
+ case 'fetch_cancel':
1079
+ return encodeFetchCancelPayload(msg, w)
1080
+ case 'track_status':
1081
+ return encodeTrackStatusPayload(msg, w)
1082
+ case 'request_ok':
1083
+ return encodeRequestOkPayload(msg, w)
1084
+ case 'request_error':
1085
+ return encodeRequestErrorPayload(msg, w)
1086
+ case 'goaway':
1087
+ return encodeGoAwayPayload(msg, w)
1088
+ case 'max_request_id':
1089
+ return encodeMaxRequestIdPayload(msg, w)
1090
+ case 'requests_blocked':
1091
+ return encodeRequestsBlockedPayload(msg, w)
1092
+ default: {
1093
+ const _exhaustive: never = msg
1094
+ throw new Error(`Unhandled message type: ${(_exhaustive as Draft16Message).type}`)
1095
+ }
1096
+ }
1097
+ }
1098
+
1099
+ /**
1100
+ * Decode a draft-16 control message from bytes (type + uint16 length + payload).
1101
+ */
1102
+ export function decodeMessage(bytes: Uint8Array): DecodeResult<Draft16Message> {
1103
+ try {
1104
+ const reader = new BufferReader(bytes)
1105
+ const typeId = reader.readVarInt()
1106
+
1107
+ const lenHi = reader.readUint8()
1108
+ const lenLo = reader.readUint8()
1109
+ const payloadLength = (lenHi << 8) | lenLo
1110
+
1111
+ const payloadBytes = reader.readBytes(payloadLength)
1112
+ const payloadReader = new BufferReader(payloadBytes)
1113
+
1114
+ const decoder = payloadDecoders.get(typeId)
1115
+ if (!decoder) {
1116
+ return {
1117
+ ok: false,
1118
+ error: new DecodeError(
1119
+ 'UNKNOWN_MESSAGE_TYPE',
1120
+ `Unknown message type ID: 0x${typeId.toString(16)}`,
1121
+ 0,
1122
+ ),
1123
+ }
1124
+ }
1125
+
1126
+ const message = decoder(payloadReader)
1127
+ return { ok: true, value: message, bytesRead: reader.offset }
1128
+ } catch (e) {
1129
+ if (e instanceof DecodeError) {
1130
+ return { ok: false, error: e }
1131
+ }
1132
+ throw e
1133
+ }
1134
+ }
1135
+
1136
+ // ─── Data Stream Encoding/Decoding (re-exported from data-streams.ts) ───────
1137
+
1138
+ import {
1139
+ createDataStreamDecoder,
1140
+ createFetchStreamDecoder,
1141
+ createSubgroupStreamDecoder,
1142
+ decodeDatagram,
1143
+ decodeDataStream,
1144
+ decodeFetchStream,
1145
+ decodeSubgroupStream,
1146
+ encodeDatagram,
1147
+ encodeFetchStream,
1148
+ encodeSubgroupStream,
1149
+ } from './data-streams.js'
1150
+
1151
+ export {
1152
+ createDataStreamDecoder,
1153
+ createFetchStreamDecoder,
1154
+ createSubgroupStreamDecoder,
1155
+ decodeDatagram,
1156
+ decodeDataStream,
1157
+ decodeFetchStream,
1158
+ decodeSubgroupStream,
1159
+ encodeDatagram,
1160
+ encodeFetchStream,
1161
+ encodeSubgroupStream,
1162
+ }
1163
+
1164
+ // ─── Stream Decoders ───────────────────────────────────────────────────────────
1165
+
1166
+ export function createStreamDecoder(): TransformStream<Uint8Array, Draft16Message> {
1167
+ let buffer = new Uint8Array(0)
1168
+ let offset = 0
1169
+
1170
+ return new TransformStream<Uint8Array, Draft16Message>({
1171
+ transform(chunk, controller) {
1172
+ if (offset > 0) {
1173
+ buffer = buffer.subarray(offset)
1174
+ offset = 0
1175
+ }
1176
+ const newBuffer = new Uint8Array(buffer.length + chunk.length)
1177
+ newBuffer.set(buffer, 0)
1178
+ newBuffer.set(chunk, buffer.length)
1179
+ buffer = newBuffer
1180
+
1181
+ while (offset < buffer.length) {
1182
+ const result = decodeMessage(buffer.subarray(offset))
1183
+ if (!result.ok) {
1184
+ if (result.error.code === 'UNEXPECTED_END') {
1185
+ break
1186
+ }
1187
+ controller.error(result.error)
1188
+ return
1189
+ }
1190
+ controller.enqueue(result.value)
1191
+ offset += result.bytesRead
1192
+ }
1193
+ },
1194
+
1195
+ flush(controller) {
1196
+ if (offset < buffer.length) {
1197
+ controller.error(
1198
+ new DecodeError('UNEXPECTED_END', 'Stream ended with incomplete message data', 0),
1199
+ )
1200
+ }
1201
+ },
1202
+ })
1203
+ }
1204
+
1205
+ // ─── Codec Factory ─────────────────────────────────────────────────────────────
1206
+
1207
+ export interface Draft16Codec extends BaseCodec<Draft16Message> {
1208
+ readonly draft: '16'
1209
+ encodeSubgroupStream(stream: SubgroupStream): Uint8Array
1210
+ encodeDatagram(dg: DatagramObject): Uint8Array
1211
+ encodeFetchStream(stream: FetchStream): Uint8Array
1212
+ decodeSubgroupStream(bytes: Uint8Array): DecodeResult<SubgroupStream>
1213
+ decodeDatagram(bytes: Uint8Array): DecodeResult<DatagramObject>
1214
+ decodeFetchStream(bytes: Uint8Array): DecodeResult<FetchStream>
1215
+ decodeDataStream(
1216
+ streamType: 'subgroup' | 'datagram' | 'fetch',
1217
+ bytes: Uint8Array,
1218
+ ): DecodeResult<Draft16DataStream>
1219
+ createStreamDecoder(): TransformStream<Uint8Array, Draft16Message>
1220
+ createSubgroupStreamDecoder(): TransformStream<Uint8Array, SubgroupStreamHeader | ObjectPayload>
1221
+ createFetchStreamDecoder(): TransformStream<Uint8Array, FetchStreamHeader | ObjectPayload>
1222
+ createDataStreamDecoder(): TransformStream<Uint8Array, DataStreamEvent>
1223
+ }
1224
+
1225
+ export function createDraft16Codec(): Draft16Codec {
1226
+ return {
1227
+ draft: '16',
1228
+ encodeMessage,
1229
+ decodeMessage,
1230
+ encodeSubgroupStream,
1231
+ encodeDatagram,
1232
+ encodeFetchStream,
1233
+ decodeSubgroupStream,
1234
+ decodeDatagram,
1235
+ decodeFetchStream,
1236
+ decodeDataStream,
1237
+ createStreamDecoder,
1238
+ createSubgroupStreamDecoder,
1239
+ createFetchStreamDecoder,
1240
+ createDataStreamDecoder,
1241
+ }
1242
+ }