@norskvideo/moq-net 0.1.7 → 0.2.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 (286) hide show
  1. package/README.md +2 -2
  2. package/announce.d.ts +7 -0
  3. package/announce.d.ts.map +1 -0
  4. package/announce.js +8 -0
  5. package/announce.js.map +1 -0
  6. package/announced.d.ts +49 -91
  7. package/announced.d.ts.map +1 -1
  8. package/announced.js +21 -156
  9. package/announced.js.map +1 -1
  10. package/bandwidth.d.ts +163 -0
  11. package/bandwidth.d.ts.map +1 -0
  12. package/bandwidth.js +304 -0
  13. package/bandwidth.js.map +1 -0
  14. package/bandwidth_api.d.ts +7 -0
  15. package/bandwidth_api.d.ts.map +1 -0
  16. package/bandwidth_api.js +8 -0
  17. package/bandwidth_api.js.map +1 -0
  18. package/broadcast.d.ts +44 -35
  19. package/broadcast.d.ts.map +1 -1
  20. package/broadcast.js +104 -60
  21. package/broadcast.js.map +1 -1
  22. package/connection/accept.d.ts +16 -1
  23. package/connection/accept.d.ts.map +1 -1
  24. package/connection/accept.js +52 -28
  25. package/connection/accept.js.map +1 -1
  26. package/connection/browser.d.ts.map +1 -1
  27. package/connection/browser.js +9 -7
  28. package/connection/browser.js.map +1 -1
  29. package/connection/connect.d.ts +30 -6
  30. package/connection/connect.d.ts.map +1 -1
  31. package/connection/connect.js +110 -54
  32. package/connection/connect.js.map +1 -1
  33. package/connection/established.d.ts +17 -21
  34. package/connection/established.d.ts.map +1 -1
  35. package/connection/established.js.map +1 -1
  36. package/connection/forward.d.ts +2 -0
  37. package/connection/forward.d.ts.map +1 -0
  38. package/connection/forward.js +173 -0
  39. package/connection/forward.js.map +1 -0
  40. package/connection/handshake.d.ts +1 -0
  41. package/connection/handshake.d.ts.map +1 -1
  42. package/connection/handshake.js +5 -2
  43. package/connection/handshake.js.map +1 -1
  44. package/connection/index.d.ts +5 -5
  45. package/connection/index.d.ts.map +1 -1
  46. package/connection/index.js +4 -5
  47. package/connection/index.js.map +1 -1
  48. package/connection/pool.d.ts +186 -0
  49. package/connection/pool.d.ts.map +1 -0
  50. package/connection/pool.js +361 -0
  51. package/connection/pool.js.map +1 -0
  52. package/connection/reload.d.ts +14 -93
  53. package/connection/reload.d.ts.map +1 -1
  54. package/connection/reload.js +217 -81
  55. package/connection/reload.js.map +1 -1
  56. package/connection/stats.d.ts +3 -26
  57. package/connection/stats.d.ts.map +1 -1
  58. package/connection/stats.js.map +1 -1
  59. package/connection/transport.d.ts +0 -7
  60. package/connection/transport.d.ts.map +1 -1
  61. package/consume.d.ts +1 -43
  62. package/consume.d.ts.map +1 -1
  63. package/consume.js +1 -1
  64. package/consume.js.map +1 -1
  65. package/error.d.ts +180 -29
  66. package/error.d.ts.map +1 -1
  67. package/error.js +331 -16
  68. package/error.js.map +1 -1
  69. package/errors.d.ts +7 -0
  70. package/errors.d.ts.map +1 -0
  71. package/errors.js +8 -0
  72. package/errors.js.map +1 -0
  73. package/group.d.ts +9 -43
  74. package/group.d.ts.map +1 -1
  75. package/group.js +284 -69
  76. package/group.js.map +1 -1
  77. package/hop.d.ts +115 -0
  78. package/hop.d.ts.map +1 -0
  79. package/hop.js +119 -0
  80. package/hop.js.map +1 -0
  81. package/ietf/adapter.d.ts +5 -1
  82. package/ietf/adapter.d.ts.map +1 -1
  83. package/ietf/adapter.js +105 -60
  84. package/ietf/adapter.js.map +1 -1
  85. package/ietf/aliases.d.ts +1 -78
  86. package/ietf/aliases.d.ts.map +1 -1
  87. package/ietf/cluster.d.ts +9 -123
  88. package/ietf/cluster.d.ts.map +1 -1
  89. package/ietf/cluster.js +84 -44
  90. package/ietf/cluster.js.map +1 -1
  91. package/ietf/connection.d.ts +6 -72
  92. package/ietf/connection.d.ts.map +1 -1
  93. package/ietf/connection.js +62 -56
  94. package/ietf/connection.js.map +1 -1
  95. package/ietf/error.d.ts +11 -0
  96. package/ietf/error.d.ts.map +1 -0
  97. package/ietf/error.js +193 -0
  98. package/ietf/error.js.map +1 -0
  99. package/ietf/fetch.d.ts +7 -20
  100. package/ietf/fetch.d.ts.map +1 -1
  101. package/ietf/fetch.js +52 -22
  102. package/ietf/fetch.js.map +1 -1
  103. package/ietf/filter.d.ts +2 -0
  104. package/ietf/filter.d.ts.map +1 -1
  105. package/ietf/filter.js +10 -1
  106. package/ietf/filter.js.map +1 -1
  107. package/ietf/goaway.d.ts.map +1 -1
  108. package/ietf/goaway.js +22 -5
  109. package/ietf/goaway.js.map +1 -1
  110. package/ietf/hidden.d.ts +2 -0
  111. package/ietf/hidden.d.ts.map +1 -0
  112. package/ietf/hidden.js +30 -0
  113. package/ietf/hidden.js.map +1 -0
  114. package/ietf/index.d.ts +2 -0
  115. package/ietf/index.d.ts.map +1 -1
  116. package/ietf/index.js +2 -0
  117. package/ietf/index.js.map +1 -1
  118. package/ietf/object.d.ts +15 -8
  119. package/ietf/object.d.ts.map +1 -1
  120. package/ietf/object.js +51 -36
  121. package/ietf/object.js.map +1 -1
  122. package/ietf/parameters.d.ts +14 -2
  123. package/ietf/parameters.d.ts.map +1 -1
  124. package/ietf/parameters.js +97 -29
  125. package/ietf/parameters.js.map +1 -1
  126. package/ietf/properties.d.ts +1 -0
  127. package/ietf/properties.d.ts.map +1 -1
  128. package/ietf/properties.js +14 -0
  129. package/ietf/properties.js.map +1 -1
  130. package/ietf/publish.d.ts +19 -2
  131. package/ietf/publish.d.ts.map +1 -1
  132. package/ietf/publish.js +40 -6
  133. package/ietf/publish.js.map +1 -1
  134. package/ietf/publish_namespace.d.ts +25 -0
  135. package/ietf/publish_namespace.d.ts.map +1 -1
  136. package/ietf/publish_namespace.js +63 -0
  137. package/ietf/publish_namespace.js.map +1 -1
  138. package/ietf/publisher.d.ts +1 -82
  139. package/ietf/publisher.d.ts.map +1 -1
  140. package/ietf/publisher.js +483 -235
  141. package/ietf/publisher.js.map +1 -1
  142. package/ietf/solicit.d.ts +1 -40
  143. package/ietf/solicit.d.ts.map +1 -1
  144. package/ietf/subscribe.d.ts +8 -6
  145. package/ietf/subscribe.d.ts.map +1 -1
  146. package/ietf/subscribe.js +33 -27
  147. package/ietf/subscribe.js.map +1 -1
  148. package/ietf/subscribe_namespace.d.ts +8 -2
  149. package/ietf/subscribe_namespace.d.ts.map +1 -1
  150. package/ietf/subscribe_namespace.js +18 -8
  151. package/ietf/subscribe_namespace.js.map +1 -1
  152. package/ietf/subscriber.d.ts +1 -65
  153. package/ietf/subscriber.d.ts.map +1 -1
  154. package/ietf/subscriber.js +337 -123
  155. package/ietf/subscriber.js.map +1 -1
  156. package/ietf/token.d.ts +2 -0
  157. package/ietf/token.d.ts.map +1 -0
  158. package/ietf/token.js +99 -0
  159. package/ietf/token.js.map +1 -0
  160. package/ietf/track.d.ts +4 -0
  161. package/ietf/track.d.ts.map +1 -1
  162. package/ietf/track.js +6 -20
  163. package/ietf/track.js.map +1 -1
  164. package/ietf/version.d.ts +12 -1
  165. package/ietf/version.d.ts.map +1 -1
  166. package/ietf/version.js +13 -0
  167. package/ietf/version.js.map +1 -1
  168. package/index.d.ts +12 -7
  169. package/index.d.ts.map +1 -1
  170. package/index.js +10 -5
  171. package/index.js.map +1 -1
  172. package/internal.d.ts +115 -1
  173. package/internal.d.ts.map +1 -1
  174. package/internal.js +108 -0
  175. package/internal.js.map +1 -1
  176. package/lite/announce.d.ts +60 -10
  177. package/lite/announce.d.ts.map +1 -1
  178. package/lite/announce.js +176 -31
  179. package/lite/announce.js.map +1 -1
  180. package/lite/connection.d.ts +9 -59
  181. package/lite/connection.d.ts.map +1 -1
  182. package/lite/connection.js +34 -35
  183. package/lite/connection.js.map +1 -1
  184. package/lite/datagram.d.ts +3 -2
  185. package/lite/datagram.d.ts.map +1 -1
  186. package/lite/datagram.js +7 -8
  187. package/lite/datagram.js.map +1 -1
  188. package/lite/fetch.d.ts +15 -1
  189. package/lite/fetch.d.ts.map +1 -1
  190. package/lite/fetch.js +39 -7
  191. package/lite/fetch.js.map +1 -1
  192. package/lite/goaway.d.ts.map +1 -1
  193. package/lite/goaway.js +7 -1
  194. package/lite/goaway.js.map +1 -1
  195. package/lite/group.d.ts +30 -12
  196. package/lite/group.d.ts.map +1 -1
  197. package/lite/group.js +68 -26
  198. package/lite/group.js.map +1 -1
  199. package/lite/message.d.ts +2 -2
  200. package/lite/message.d.ts.map +1 -1
  201. package/lite/message.js +14 -5
  202. package/lite/message.js.map +1 -1
  203. package/lite/priority.d.ts +1 -61
  204. package/lite/priority.d.ts.map +1 -1
  205. package/lite/priority.js +4 -5
  206. package/lite/priority.js.map +1 -1
  207. package/lite/publisher.d.ts +1 -69
  208. package/lite/publisher.d.ts.map +1 -1
  209. package/lite/publisher.js +630 -262
  210. package/lite/publisher.js.map +1 -1
  211. package/lite/setup.d.ts +8 -8
  212. package/lite/setup.d.ts.map +1 -1
  213. package/lite/setup.js +33 -30
  214. package/lite/setup.js.map +1 -1
  215. package/lite/subscribe.d.ts +71 -17
  216. package/lite/subscribe.d.ts.map +1 -1
  217. package/lite/subscribe.js +205 -53
  218. package/lite/subscribe.js.map +1 -1
  219. package/lite/subscriber.d.ts +15 -56
  220. package/lite/subscriber.d.ts.map +1 -1
  221. package/lite/subscriber.js +451 -247
  222. package/lite/subscriber.js.map +1 -1
  223. package/lite/track.d.ts +4 -10
  224. package/lite/track.d.ts.map +1 -1
  225. package/lite/track.js +34 -29
  226. package/lite/track.js.map +1 -1
  227. package/lite/version.d.ts +42 -6
  228. package/lite/version.d.ts.map +1 -1
  229. package/lite/version.js +126 -10
  230. package/lite/version.js.map +1 -1
  231. package/origin.d.ts +256 -29
  232. package/origin.d.ts.map +1 -1
  233. package/origin.js +1427 -37
  234. package/origin.js.map +1 -1
  235. package/package.json +8 -3
  236. package/path.d.ts +25 -7
  237. package/path.d.ts.map +1 -1
  238. package/path.js +5 -3
  239. package/path.js.map +1 -1
  240. package/stream.d.ts +73 -14
  241. package/stream.d.ts.map +1 -1
  242. package/stream.js +372 -141
  243. package/stream.js.map +1 -1
  244. package/tail.d.ts +18 -0
  245. package/tail.d.ts.map +1 -0
  246. package/tail.js +167 -0
  247. package/tail.js.map +1 -0
  248. package/time.d.ts +15 -2
  249. package/time.d.ts.map +1 -1
  250. package/time.js +28 -9
  251. package/time.js.map +1 -1
  252. package/track.d.ts +211 -83
  253. package/track.d.ts.map +1 -1
  254. package/track.js +816 -205
  255. package/track.js.map +1 -1
  256. package/util/abort.d.ts +2 -0
  257. package/util/abort.d.ts.map +1 -0
  258. package/util/abort.js +20 -0
  259. package/util/abort.js.map +1 -0
  260. package/util/log.d.ts +5 -0
  261. package/util/log.d.ts.map +1 -0
  262. package/util/log.js +17 -0
  263. package/util/log.js.map +1 -0
  264. package/util/u64.d.ts +39 -0
  265. package/util/u64.d.ts.map +1 -0
  266. package/util/u64.js +83 -0
  267. package/util/u64.js.map +1 -0
  268. package/util/varint.d.ts +29 -0
  269. package/util/varint.d.ts.map +1 -0
  270. package/util/varint.js +198 -0
  271. package/util/varint.js.map +1 -0
  272. package/varint.d.ts +10 -6
  273. package/varint.d.ts.map +1 -1
  274. package/varint.js +40 -237
  275. package/varint.js.map +1 -1
  276. package/wire.d.ts +80 -0
  277. package/wire.d.ts.map +1 -0
  278. package/wire.js +32 -0
  279. package/wire.js.map +1 -0
  280. package/zod.d.ts +1 -1
  281. package/zod.d.ts.map +1 -1
  282. package/zod.js.map +1 -1
  283. package/mock.d.ts +0 -66
  284. package/mock.d.ts.map +0 -1
  285. package/mock.js +0 -243
  286. package/mock.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"connect.js","sourceRoot":"","sources":["../../src/connection/connect.ts"],"names":[],"mappings":"AAAA,OAAO,OAAwC,MAAM,WAAW,CAAC;AACjE,OAAO,KAAK,IAAI,MAAM,kBAAkB,CAAC;AACzC,OAAO,KAAK,IAAI,MAAM,kBAAkB,CAAC;AACzC,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AACtC,OAAO,KAAK,GAAG,MAAM,gBAAgB,CAAC;AACtC,OAAO,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAC;AAEvD,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAE/C,gFAAgF;AAChF,MAAM,0BAA0B,GAAG,GAAG,CAAC;AA4EvC,gGAAgG;AAChG,8FAA8F;AAC9F,kEAAkE;AAClE,MAAM,kBAAkB,GAAG,CAAC,mBAAmB,CAAC,CAAC;AAEjD,6EAA6E;AAC7E,SAAS,gBAAgB,CAAC,GAAQ;IACjC,OAAO,CAAC,kBAAkB,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;AACxE,CAAC;AAED,qFAAqF;AACrF,MAAM,YAAY,GAAG,IAAI,GAAG,EAAU,CAAC;AAEvC,gDAAgD;AAChD,MAAM,aAAa,GAAG,IAAI,eAAe,EAAE,CAAC,MAAM,CAAC;AAEnD;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,GAAQ,EAAE,KAAoB;IAC3D,MAAM,MAAM,GAAG,KAAK,EAAE,MAAM,IAAI,aAAa,CAAC;IAC9C,MAAM,CAAC,cAAc,EAAE,CAAC;IAExB,oEAAoE;IACpE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,aAAa,EAAQ,CAAC;IAClE,MAAM,OAAO,GAAG,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC;IAChC,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IAE1D,MAAM,OAAO,GAAG,YAAY,CAAC,GAAG,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC;IAChD,IAAI,CAAC;QACJ,gFAAgF;QAChF,MAAM,UAAU,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;QAC9E,IAAI,UAAU,IAAI,CAAC,MAAM,CAAC,OAAO;YAAE,OAAO,UAAU,CAAC;QAErD,mDAAmD;QACnD,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QACrD,MAAM,MAAM,CAAC,MAAM,CAAC;IACrB,CAAC;YAAS,CAAC;QACV,MAAM,CAAC,mBAAmB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAC9C,CAAC;AACF,CAAC;AAED,KAAK,UAAU,YAAY,CAAC,GAAQ,EAAE,KAA+B,EAAE,KAAoB;IAC1F,MAAM,SAAS,GAAG,KAAK,EAAE,SAAS,IAAI,gBAAgB,CAAC,GAAG,CAAC,CAAC;IAE5D,IAAI,KAAK,EAAE,SAAS,EAAE,CAAC;QACtB,MAAM,SAAS,GAAG,KAAK,CAAC,SAAS,CAAC;QAClC,KAAK,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC,CAAC;QACzC,OAAO,gBAAgB,CAAC,GAAG,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC;IACpD,CAAC;IAED,2DAA2D;IAC3D,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC,aAAa,EAAQ,CAAC;IACxE,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC;IAE5C,MAAM,YAAY,GAAG,uBAAuB,EAAE,CAAC,CAAC,CAAC,mBAAmB,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAEnH,mGAAmG;IACnG,sEAAsE;IACtE,MAAM,SAAS,GACd,CAAC,YAAY,IAAI,YAAY,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE,SAAS,EAAE,KAAK,IAAI,0BAA0B,CAAC,CAAC;IACjH,MAAM,SAAS,GACd,KAAK,EAAE,SAAS,EAAE,OAAO,KAAK,KAAK;QAClC,CAAC,CAAC,gBAAgB,CAAC,KAAK,EAAE,SAAS,EAAE,GAAG,IAAI,GAAG,EAAE,SAAS,EAAE,MAAM,CAAC;QACnE,CAAC,CAAC,SAAS,CAAC;IAEd,IAAI,CAAC,SAAS,IAAI,CAAC,YAAY,EAAE,CAAC;QACjC,MAAM,IAAI,KAAK,CAAC,8EAA8E,CAAC,CAAC;IACjG,CAAC;IAED,yFAAyF;IACzF,wFAAwF;IACxF,gFAAgF;IAChF,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,CAChC,YAAY,KAAK,SAAS;QACzB,CAAC,CAAC,SAAS,KAAK,SAAS;YACxB,CAAC,CAAC,CAAC,SAAS,EAAE,YAAY,CAAC;YAC3B,CAAC,CAAC,CAAC,YAAY,CAAC;QACjB,CAAC,CAAC,CAAC,SAAS,CAAC,CACd,CAAC;IACF,IAAI,EAAE,CAAC;IAEP,IAAI,CAAC,OAAO;QAAE,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC;IAExD,oEAAoE;IACpE,KAAK,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC;IAEvC,qFAAqF;IACrF,IAAI,OAAO,YAAY,OAAO,EAAE,CAAC;QAChC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,EAAE,yBAAyB,CAAC,CAAC;QACxD,YAAY,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAC;IAClC,CAAC;SAAM,CAAC;QACP,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,EAAE,EAAE,4BAA4B,CAAC,CAAC;IAC7D,CAAC;IAED,gFAAgF;IAChF,OAAO,MAAM,gBAAgB,CAAC,GAAG,EAAE,OAAuB,EAAE,SAAS,CAAC,CAAC;AACxE,CAAC;AAED,KAAK,UAAU,gBAAgB,CAAC,GAAQ,EAAE,OAAqB,EAAE,SAAkB;IAClF,oFAAoF;IACpF,sEAAsE;IACtE,MAAM,QAAQ,GAAwB,OAAiC,CAAC,QAAQ,IAAI,SAAS,CAAC;IAC9F,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,EAAE,EAAE,kBAAkB,EAAE,QAAQ,IAAI,QAAQ,CAAC,CAAC;IAExE,4EAA4E;IAC5E,IAAI,YAA0B,CAAC;IAC/B,MAAM,aAAa,GAClB,QAAQ,KAAK,IAAI,CAAC,IAAI,CAAC,QAAQ;QAC9B,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ;QACvB,CAAC,CAAC,QAAQ,KAAK,IAAI,CAAC,IAAI,CAAC,QAAQ;YAChC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ;YACvB,CAAC,CAAC,QAAQ,KAAK,IAAI,CAAC,IAAI,CAAC,QAAQ;gBAChC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ;gBACvB,CAAC,CAAC,QAAQ,KAAK,IAAI,CAAC,IAAI,CAAC,QAAQ;oBAChC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ;oBACvB,CAAC,CAAC,SAAS,CAAC;IACjB,IAAI,aAAa,KAAK,SAAS,EAAE,CAAC;QACjC,OAAO,MAAM,aAAa,CAAC,GAAG,EAAE,OAAO,EAAE,aAAa,EAAE,SAAS,CAAC,CAAC;IACpE,CAAC;SAAM,IAAI,QAAQ,KAAK,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;QAC5C,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC;IACtC,CAAC;SAAM,IAAI,QAAQ,KAAK,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;QAC5C,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC;IACtC,CAAC;SAAM,IAAI,QAAQ,KAAK,IAAI,CAAC,WAAW,EAAE,CAAC;QAC1C,OAAO,IAAI,IAAI,CAAC,UAAU,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,SAAS,EAAE,CAAC,CAAC;IAC/F,CAAC;SAAM,IAAI,QAAQ,KAAK,IAAI,CAAC,OAAO,EAAE,CAAC;QACtC,OAAO,IAAI,IAAI,CAAC,UAAU,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,SAAS,EAAE,CAAC,CAAC;IAC/F,CAAC;SAAM,IAAI,QAAQ,KAAK,IAAI,CAAC,OAAO,EAAE,CAAC;QACtC,OAAO,IAAI,IAAI,CAAC,UAAU,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,SAAS,EAAE,CAAC,CAAC;IAC/F,CAAC;SAAM,IAAI,QAAQ,KAAK,IAAI,CAAC,OAAO,EAAE,CAAC;QACtC,OAAO,IAAI,IAAI,CAAC,UAAU,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,SAAS,EAAE,CAAC,CAAC;IAC/F,CAAC;SAAM,IAAI,QAAQ,KAAK,IAAI,CAAC,IAAI,IAAI,QAAQ,KAAK,EAAE,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;QAChF,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC;IACtC,CAAC;SAAM,CAAC;QACP,MAAM,IAAI,KAAK,CAAC,sCAAsC,QAAQ,EAAE,CAAC,CAAC;IACnE,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC1C,MAAM,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;IAEpD,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC;IAElC,MAAM,MAAM,GAAG,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;IACvC,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,WAAW,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;IACxD,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,cAAc,EAAE,OAAO,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC;IAChF,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC;IAE9B,MAAM,MAAM,GAAG,IAAI,IAAI,CAAC,WAAW,CAAC;QACnC,QAAQ,EACP,YAAY,KAAK,IAAI,CAAC,OAAO,CAAC,QAAQ;YACrC,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC;YACzB,CAAC,CAAC,YAAY,KAAK,IAAI,CAAC,OAAO,CAAC,QAAQ;gBACvC,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC;gBACzB,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC;QAC1E,UAAU,EAAE,MAAM;KAClB,CAAC,CAAC;IACH,MAAM,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IAEjD,MAAM,YAAY,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC;IAC/C,IAAI,YAAY,KAAK,IAAI,CAAC,QAAQ,CAAC,YAAY,EAAE,CAAC;QACjD,MAAM,IAAI,KAAK,CAAC,oCAAoC,YAAY,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;IAChF,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IAE1E,IAAI,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,OAAuB,CAAC,EAAE,CAAC;QAC1E,OAAO,IAAI,IAAI,CAAC,UAAU,CAAC;YAC1B,GAAG;YACH,IAAI,EAAE,OAAO;YACb,OAAO,EAAE,MAAM,CAAC,OAAuB;YACvC,OAAO,EAAE,MAAM;YACf,SAAS;SACT,CAAC,CAAC;IACJ,CAAC;SAAM,IAAI,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,OAAuB,CAAC,EAAE,CAAC;QACjF,MAAM,YAAY,GAAG,MAAM,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,CAAC,WAAW,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC;QACtF,OAAO,IAAI,IAAI,CAAC,UAAU,CAAC;YAC1B,SAAS;YACT,MAAM,EAAE,IAAI;YACZ,GAAG;YACH,IAAI,EAAE,OAAO;YACb,OAAO,EAAE,MAAM;YACf,YAAY;YACZ,OAAO,EAAE,MAAM,CAAC,OAA2B;YAC3C,OAAO,EAAE,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC,UAAU,CAAC;SACjD,CAAC,CAAC;IACJ,CAAC;SAAM,CAAC;QACP,MAAM,IAAI,KAAK,CAAC,+BAA+B,MAAM,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;IAC7E,CAAC;AACF,CAAC;AAED;;;GAGG;AACH,KAAK,UAAU,aAAa,CAC3B,GAAQ,EACR,OAAqB,EACrB,OAAyB,EACzB,SAAkB;IAElB,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,MAAM,aAAa,CAAC,OAAO,EAAE,OAAO,EAAE,aAAa,CAAC,CAAC;IAE3F,OAAO,IAAI,IAAI,CAAC,UAAU,CAAC;QAC1B,SAAS;QACT,MAAM,EAAE,IAAI;QACZ,GAAG;QACH,IAAI,EAAE,OAAO;QACb,OAAO;QACP,OAAO;QACP,OAAO;QACP,qFAAqF;QACrF,YAAY,EAAE,EAAE;QAChB,OAAO;KACP,CAAC,CAAC;AACJ,CAAC;AAKD,0DAA0D;AAC1D,SAAS,QAAQ,CAAC,GAAW;IAC5B,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,gEAAgE,CAAC,CAAC;IAC1F,IAAI,CAAC,KAAK,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CAAC,wEAAwE,CAAC,CAAC;IAC3F,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC;IAClD,MAAM,GAAG,GAAG,IAAI,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAC1C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACxC,GAAG,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;IAC/B,CAAC;IACD,OAAO,GAAG,CAAC;AACZ,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,IAA2B;IAChE,MAAM,GAAG,GAAG,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAC7D,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;IAC1D,OAAO,IAAI,UAAU,CAAC,MAAM,CAAC,CAAC;AAC/B,CAAC;AAED,mFAAmF;AACnF,KAAK,UAAU,wBAAwB,CAAC,OAA2B;IAClE,MAAM,MAAM,GAAuB,EAAE,CAAC;IAEtC,KAAK,MAAM,IAAI,IAAI,OAAO,EAAE,uBAAuB,IAAI,EAAE,EAAE,CAAC;QAC3D,MAAM,KAAK,GAAG,OAAO,IAAI,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC;QACpF,MAAM,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,IAAI,SAAS,EAAE,KAAK,EAAE,CAAC,CAAC;IAChE,CAAC;IAED,IAAI,OAAO,EAAE,iBAAiB,KAAK,SAAS,EAAE,CAAC;QAC9C,MAAM,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC,OAAO,CAAC,iBAAiB,CAAC,EAAE,CAAC,CAAC;IAChG,CAAC;IAED,OAAO,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC;AAC/C,CAAC;AAED,KAAK,UAAU,mBAAmB,CACjC,GAAQ,EACR,MAAqB,EACrB,OAA2B;IAE3B,IAAI,QAAQ,GAAG,GAAG,CAAC;IAEnB,iFAAiF;IACjF,MAAM,EAAE,iBAAiB,EAAE,KAAK,EAAE,uBAAuB,EAAE,OAAO,EAAE,GAAG,YAAY,EAAE,GAAG,OAAO,IAAI,EAAE,CAAC;IAEtG,MAAM,YAAY,GAAwB;QACzC,YAAY,EAAE,KAAK;QACnB,iBAAiB,EAAE,aAAa;QAChC,SAAS,EAAE;YACV,6EAA6E;YAC7E,qFAAqF;YACrF,IAAI,CAAC,OAAO;YACZ,IAAI,CAAC,OAAO;YACZ,IAAI,CAAC,OAAO;YACZ,IAAI,CAAC,IAAI;YACT,IAAI,CAAC,IAAI,CAAC,QAAQ;YAClB,IAAI,CAAC,IAAI,CAAC,QAAQ;YAClB,IAAI,CAAC,IAAI,CAAC,QAAQ;YAClB,IAAI,CAAC,IAAI,CAAC,QAAQ;YAClB,IAAI,CAAC,IAAI,CAAC,QAAQ;YAClB,IAAI,CAAC,IAAI,CAAC,QAAQ;SAClB;QACD,GAAG,YAAY;KACf,CAAC;IAEF,8EAA8E;IAC9E,wEAAwE;IACxE,MAAM,MAAM,GAAG,CAAC,MAAM,wBAAwB,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC;IAE/D,6EAA6E;IAC7E,mFAAmF;IACnF,IAAI,GAAG,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;QAC9B,MAAM,cAAc,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;QACpC,cAAc,CAAC,QAAQ,GAAG,qBAAqB,CAAC;QAChD,cAAc,CAAC,MAAM,GAAG,EAAE,CAAC;QAC3B,8EAA8E;QAC9E,+EAA+E;QAC/E,8EAA8E;QAC9E,OAAO,CAAC,KAAK,CACZ,cAAc,CAAC,QAAQ,EAAE,EACzB,sEAAsE,CACtE,CAAC;QAEF,yCAAyC;QACzC,sDAAsD;QACtD,MAAM,WAAW,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;QACxE,IAAI,CAAC,WAAW;YAAE,OAAO,SAAS,CAAC;QAEnC,MAAM,eAAe,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,WAAW,CAAC,IAAI,EAAE,EAAE,MAAM,CAAC,CAAC,CAAC;QACzE,IAAI,eAAe,KAAK,SAAS;YAAE,OAAO,SAAS,CAAC;QAEpD,MAAM,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,SAAS,EAAE,KAAK,EAAE,GAAG,CAAC,OAAO,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC;QAE3E,QAAQ,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;QACxB,QAAQ,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC9B,CAAC;IAED,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvB,YAAY,CAAC,uBAAuB,GAAG,MAAM,CAAC;IAC/C,CAAC;IAED,MAAM,IAAI,GAAG,IAAI,YAAY,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;IAEtD,4FAA4F;IAC5F,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;IAE5B,8EAA8E;IAC9E,4CAA4C;IAC5C,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;IACzE,IAAI,CAAC,MAAM,EAAE,CAAC;QACb,IAAI,CAAC,KAAK,EAAE,CAAC;QACb,OAAO,SAAS,CAAC;IAClB,CAAC;IAED,OAAO,IAAI,CAAC;AACb,CAAC;AAED,uDAAuD;AACvD,KAAK,UAAU,gBAAgB,CAAC,GAAQ,EAAE,KAAa,EAAE,MAAqB;IAC7E,MAAM,KAAK,GAAG,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC;IAEzE,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACpE,IAAI,CAAC,MAAM;QAAE,OAAO,SAAS,CAAC;IAE9B,wEAAwE;IACxE,0EAA0E;IAC1E,sEAAsE;IACtE,uEAAuE;IACvE,6DAA6D;IAC7D,MAAM,QAAQ,GAAG;QAChB,+FAA+F;QAC/F,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,IAAI;QACpB,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,IAAI;QACpB,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,IAAI;QACpB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI;QACjB,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,SAAS;QAC/B,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,SAAS;QAC/B,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,IAAI;QAC1B,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,IAAI;QAC1B,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,IAAI;KAC4C,CAAC;IAExE,yEAAyE;IACzE,0EAA0E;IAC1E,kEAAkE;IAClE,mBAAmB;IACnB,MAAM,IAAI,GAAG,IAAI,OAAO,CAAC,GAAG,EAAE;QAC7B,SAAS,EAAE,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC;QAChC,QAAQ;KACR,CAAC,CAAC;IAEH,2EAA2E;IAC3E,kFAAkF;IAClF,4EAA4E;IAC5E,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;IACzE,IAAI,CAAC,MAAM,EAAE,CAAC;QACb,IAAI,CAAC,KAAK,EAAE,CAAC;QACb,OAAO,SAAS,CAAC;IAClB,CAAC;IAED,OAAO,IAAI,CAAC;AACb,CAAC","sourcesContent":["import Session, { type Version as QmuxVersion } from \"@moq/qmux\";\nimport * as Ietf from \"../ietf/index.ts\";\nimport * as Lite from \"../lite/index.ts\";\nimport { Stream } from \"../stream.ts\";\nimport * as Hex from \"../util/hex.ts\";\nimport { isWebTransportSupported } from \"./browser.ts\";\nimport type { Established } from \"./established.ts\";\nimport { exchangeSetup } from \"./handshake.ts\";\n\n// Default head start for WebTransport before attempting the WebSocket fallback.\nconst DEFAULT_WEBSOCKET_DELAY_MS = 500;\n\n/** Tuning for the WebSocket fallback used when WebTransport is unavailable or loses the connect race. */\nexport interface WebSocketOptions {\n\t/** Enable the WebSocket fallback. Defaults to `true`. */\n\tenabled?: boolean;\n\n\t/** Use a different URL than WebTransport. By default, `https` maps to `wss` and `http` to `ws`. */\n\turl?: URL;\n\n\t/**\n\t * The delay in milliseconds before attempting the WebSocket fallback (default: 500).\n\t * If WebSocket won the previous race for a given URL, this is 0.\n\t */\n\tdelay?: DOMHighResTimeStamp;\n}\n\n/**\n * A server certificate hash used to pin a self-signed server, one entry of\n * `serverCertificateHashes`. Unlike the DOM type, `value` also accepts a hex string (the\n * format moq servers report via their certificate fingerprints), decoded automatically.\n */\nexport interface CertificateHash {\n\t/** The hash algorithm. Defaults to `sha-256` (the only supported value). */\n\talgorithm?: \"sha-256\";\n\t/** The certificate hash: raw bytes or a hex string. */\n\tvalue: BufferSource | string;\n}\n\n/** WebTransport options extended with friendlier certificate pinning (hex hashes or a raw certificate). */\nexport interface WebTransportProps extends Omit<WebTransportOptions, \"serverCertificateHashes\"> {\n\t/**\n\t * Pin the server to one or more certificate hashes. Each `value` may be raw\n\t * bytes or a hex string; the algorithm defaults to `sha-256`.\n\t */\n\tserverCertificateHashes?: CertificateHash[];\n\n\t/**\n\t * Pin the server by supplying its certificate directly; the SHA-256 hash is\n\t * computed for you. Accepts a PEM string or raw DER bytes. Use this when you\n\t * have the certificate but not its precomputed fingerprint.\n\t */\n\tserverCertificate?: string | BufferSource;\n}\n\n/** Options for {@link connect}. */\nexport interface ConnectProps {\n\t/** WebTransport options. */\n\twebtransport?: WebTransportProps;\n\n\t/** WebSocket (fallback) options. */\n\twebsocket?: WebSocketOptions;\n\n\t/**\n\t * Use a pre-existing WebTransport session instead of connecting; skips the\n\t * WebTransport/WebSocket race. The publisher acquires the session's datagram\n\t * writer lock (`datagrams.writable.getWriter()`) for the session's lifetime,\n\t * so the caller must not hold it. Aborting via {@link ConnectProps.signal}\n\t * closes this session, so don't share one you intend to reuse afterwards.\n\t */\n\ttransport?: WebTransport;\n\n\t/**\n\t * Whether the relay supports broadcast discovery; see {@link Established.discovery}.\n\t * Defaults to true, except for relays known to lack it.\n\t */\n\tdiscovery?: boolean;\n\n\t/**\n\t * Aborts the connection attempt with the signal's reason. An already-aborted\n\t * signal rejects before anything opens, and aborting after the connection is\n\t * established has no effect. Use `AbortSignal.timeout(ms)` for a deadline.\n\t */\n\tsignal?: AbortSignal;\n}\n\n// Relays that don't implement broadcast discovery (SUBSCRIBE_NAMESPACE), so `announced()` would\n// never yield and a consumer waiting on an announcement would hang forever. Override with the\n// `discovery` option. Drop a host once its relay ships discovery.\nconst NO_DISCOVERY_HOSTS = [\"mediaoverquic.com\"];\n\n/** Whether the relay at `url` is expected to support broadcast discovery. */\nfunction defaultDiscovery(url: URL): boolean {\n\treturn !NO_DISCOVERY_HOSTS.some((host) => url.hostname.endsWith(host));\n}\n\n// Save if WebSocket won the last race, so we won't give QUIC a head start next time.\nconst websocketWon = new Set<string>();\n\n/** The default connect signal: never aborts. */\nconst NEVER_ABORTED = new AbortController().signal;\n\n/**\n * Establishes a connection to a MOQ server.\n *\n * @param url - The URL of the server to connect to\n * @param props - Connection options\n * @returns A promise that resolves to a Connection instance\n */\nexport async function connect(url: URL, props?: ConnectProps): Promise<Established> {\n\tconst signal = props?.signal ?? NEVER_ABORTED;\n\tsignal.throwIfAborted();\n\n\t// Resolves on abort so every in-flight transport tears itself down.\n\tconst { promise: abort, resolve } = Promise.withResolvers<void>();\n\tconst onAbort = () => resolve();\n\tsignal.addEventListener(\"abort\", onAbort, { once: true });\n\n\tconst pending = connectInner(url, props, abort);\n\ttry {\n\t\t// A `pending` rejection propagates unless the abort beat it to the finish line.\n\t\tconst connection = await Promise.race([pending, abort.then(() => undefined)]);\n\t\tif (connection && !signal.aborted) return connection;\n\n\t\t// Close a connection that settles after the abort.\n\t\tpending.then((conn) => conn.close()).catch(() => {});\n\t\tthrow signal.reason;\n\t} finally {\n\t\tsignal.removeEventListener(\"abort\", onAbort);\n\t}\n}\n\nasync function connectInner(url: URL, props: ConnectProps | undefined, abort: Promise<void>): Promise<Established> {\n\tconst discovery = props?.discovery ?? defaultDiscovery(url);\n\n\tif (props?.transport) {\n\t\tconst transport = props.transport;\n\t\tvoid abort.then(() => transport.close());\n\t\treturn connectTransport(url, transport, discovery);\n\t}\n\n\t// Stop transports after one connects or the caller aborts.\n\tconst { promise: raced, resolve: done } = Promise.withResolvers<void>();\n\tconst cancel = Promise.race([raced, abort]);\n\n\tconst webtransport = isWebTransportSupported() ? connectWebTransport(url, cancel, props?.webtransport) : undefined;\n\n\t// Give QUIC a head start to connect before trying WebSocket, unless WebSocket has won in the past.\n\t// NOTE that QUIC should be faster because it involves 1/2 fewer RTTs.\n\tconst headstart =\n\t\t!webtransport || websocketWon.has(url.toString()) ? 0 : (props?.websocket?.delay ?? DEFAULT_WEBSOCKET_DELAY_MS);\n\tconst websocket =\n\t\tprops?.websocket?.enabled !== false\n\t\t\t? connectWebSocket(props?.websocket?.url ?? url, headstart, cancel)\n\t\t\t: undefined;\n\n\tif (!websocket && !webtransport) {\n\t\tthrow new Error(\"no transport available; WebTransport not supported and WebSocket is disabled\");\n\t}\n\n\t// Race the available transports, using `.any` to ignore if one participant has an error.\n\t// `webtransport`/`websocket` are `Promise | undefined`, so test existence explicitly: a\n\t// promise is always truthy, so bare truthiness here would be a misused-promise.\n\tconst session = await Promise.any(\n\t\twebtransport !== undefined\n\t\t\t? websocket !== undefined\n\t\t\t\t? [websocket, webtransport]\n\t\t\t\t: [webtransport]\n\t\t\t: [websocket],\n\t);\n\tdone();\n\n\tif (!session) throw new Error(\"no transport available\");\n\n\t// Abort the setup handshake without leaking the selected transport.\n\tvoid abort.then(() => session.close());\n\n\t// Save if WebSocket won the last race, so we won't give QUIC a head start next time.\n\tif (session instanceof Session) {\n\t\tconsole.warn(url.toString(), \"connected via WebSocket\");\n\t\twebsocketWon.add(url.toString());\n\t} else {\n\t\tconsole.debug(url.toString(), \"connected via WebTransport\");\n\t}\n\n\t// The remaining setup is identical whether the transport was raced or supplied.\n\treturn await connectTransport(url, session as WebTransport, discovery);\n}\n\nasync function connectTransport(url: URL, session: WebTransport, discovery: boolean): Promise<Established> {\n\t// qmux Session exposes the negotiated protocol directly (as \"\" when there is none);\n\t// native WebTransport doesn't have a standard .protocol property yet.\n\tconst protocol: string | undefined = (session as { protocol?: string }).protocol || undefined;\n\tconsole.debug(url.toString(), \"negotiated ALPN:\", protocol ?? \"(none)\");\n\n\t// Choose setup encoding based on negotiated WebTransport protocol (if any).\n\tlet setupVersion: Ietf.Version;\n\tconst modernVersion =\n\t\tprotocol === Ietf.ALPN.DRAFT_20\n\t\t\t? Ietf.Version.DRAFT_20\n\t\t\t: protocol === Ietf.ALPN.DRAFT_19\n\t\t\t\t? Ietf.Version.DRAFT_19\n\t\t\t\t: protocol === Ietf.ALPN.DRAFT_18\n\t\t\t\t\t? Ietf.Version.DRAFT_18\n\t\t\t\t\t: protocol === Ietf.ALPN.DRAFT_17\n\t\t\t\t\t\t? Ietf.Version.DRAFT_17\n\t\t\t\t\t\t: undefined;\n\tif (modernVersion !== undefined) {\n\t\treturn await handshakeAlpn(url, session, modernVersion, discovery);\n\t} else if (protocol === Ietf.ALPN.DRAFT_16) {\n\t\tsetupVersion = Ietf.Version.DRAFT_16;\n\t} else if (protocol === Ietf.ALPN.DRAFT_15) {\n\t\tsetupVersion = Ietf.Version.DRAFT_15;\n\t} else if (protocol === Lite.ALPN_06_WIP) {\n\t\treturn new Lite.Connection({ url, quic: session, version: Lite.Version.DRAFT_06, discovery });\n\t} else if (protocol === Lite.ALPN_05) {\n\t\treturn new Lite.Connection({ url, quic: session, version: Lite.Version.DRAFT_05, discovery });\n\t} else if (protocol === Lite.ALPN_04) {\n\t\treturn new Lite.Connection({ url, quic: session, version: Lite.Version.DRAFT_04, discovery });\n\t} else if (protocol === Lite.ALPN_03) {\n\t\treturn new Lite.Connection({ url, quic: session, version: Lite.Version.DRAFT_03, discovery });\n\t} else if (protocol === Lite.ALPN || protocol === \"\" || protocol === undefined) {\n\t\tsetupVersion = Ietf.Version.DRAFT_14;\n\t} else {\n\t\tthrow new Error(`unsupported WebTransport protocol: ${protocol}`);\n\t}\n\n\tconst stream = await Stream.open(session);\n\tawait stream.writer.u53(Lite.StreamId.ClientCompat);\n\n\tconst encoder = new TextEncoder();\n\n\tconst params = new Ietf.SetupOptions();\n\tparams.setVarint(Ietf.SetupOption.MaxRequestId, 42069n);\n\tparams.setBytes(Ietf.SetupOption.Implementation, encoder.encode(\"moq-lite-js\"));\n\tIetf.solicitIntoSetup(params);\n\n\tconst client = new Ietf.ClientSetup({\n\t\tversions:\n\t\t\tsetupVersion === Ietf.Version.DRAFT_16\n\t\t\t\t? [Ietf.Version.DRAFT_16]\n\t\t\t\t: setupVersion === Ietf.Version.DRAFT_15\n\t\t\t\t\t? [Ietf.Version.DRAFT_15]\n\t\t\t\t\t: [Lite.Version.DRAFT_02, Lite.Version.DRAFT_01, Ietf.Version.DRAFT_14],\n\t\tparameters: params,\n\t});\n\tawait client.encode(stream.writer, setupVersion);\n\n\tconst serverCompat = await stream.reader.u53();\n\tif (serverCompat !== Lite.StreamId.ServerCompat) {\n\t\tthrow new Error(`unsupported server message type: ${serverCompat.toString()}`);\n\t}\n\n\tconst server = await Ietf.ServerSetup.decode(stream.reader, setupVersion);\n\n\tif (Object.values(Lite.Version).includes(server.version as Lite.Version)) {\n\t\treturn new Lite.Connection({\n\t\t\turl,\n\t\t\tquic: session,\n\t\t\tversion: server.version as Lite.Version,\n\t\t\tsession: stream,\n\t\t\tdiscovery,\n\t\t});\n\t} else if (Object.values(Ietf.Version).includes(server.version as Ietf.Version)) {\n\t\tconst maxRequestId = server.parameters.getVarint(Ietf.SetupOption.MaxRequestId) ?? 0n;\n\t\treturn new Ietf.Connection({\n\t\t\tdiscovery,\n\t\t\tclient: true,\n\t\t\turl,\n\t\t\tquic: session,\n\t\t\tcontrol: stream,\n\t\t\tmaxRequestId,\n\t\t\tversion: server.version as Ietf.IetfVersion,\n\t\t\tsolicit: Ietf.solicitFromSetup(server.parameters),\n\t\t});\n\t} else {\n\t\tthrow new Error(`unsupported server version: ${server.version.toString()}`);\n\t}\n}\n\n/**\n * Draft-17+ client handshake. ALPN already pinned the version; SETUP is\n * exchanged over a pair of uni streams using stream type 0x2F00.\n */\nasync function handshakeAlpn(\n\turl: URL,\n\tsession: WebTransport,\n\tversion: Ietf.IetfVersion,\n\tdiscovery: boolean,\n): Promise<Established> {\n\tconst { control, solicit, cluster } = await exchangeSetup(session, version, \"moq-lite-js\");\n\n\treturn new Ietf.Connection({\n\t\tdiscovery,\n\t\tclient: true,\n\t\turl,\n\t\tquic: session,\n\t\tcontrol,\n\t\tsolicit,\n\t\tcluster,\n\t\t// v17+ uses NativeSession which manages its own request IDs; maxRequestId is unused.\n\t\tmaxRequestId: 0n,\n\t\tversion,\n\t});\n}\n\n// One entry of the DOM `serverCertificateHashes`, derived without naming the lib type.\ntype WebTransportHash = NonNullable<WebTransportOptions[\"serverCertificateHashes\"]>[number];\n\n// Strip PEM armor and base64-decode to the raw DER bytes.\nfunction pemToDer(pem: string): Uint8Array<ArrayBuffer> {\n\tconst match = pem.match(/-----BEGIN CERTIFICATE-----([\\s\\S]+?)-----END CERTIFICATE-----/);\n\tif (!match) {\n\t\tthrow new Error(\"invalid PEM certificate: missing -----BEGIN/END CERTIFICATE----- armor\");\n\t}\n\n\tconst binary = atob(match[1].replace(/\\s+/g, \"\"));\n\tconst der = new Uint8Array(binary.length);\n\tfor (let i = 0; i < binary.length; i++) {\n\t\tder[i] = binary.charCodeAt(i);\n\t}\n\treturn der;\n}\n\n/**\n * Compute the SHA-256 hash of a certificate, the value `serverCertificateHashes`\n * pins. Accepts a PEM string or raw DER bytes. Matches the hex fingerprints a moq\n * server reports, so `Hex.fromBytes(await certificateHash(pem))` round-trips.\n */\nexport async function certificateHash(cert: string | BufferSource): Promise<Uint8Array<ArrayBuffer>> {\n\tconst der = typeof cert === \"string\" ? pemToDer(cert) : cert;\n\tconst digest = await crypto.subtle.digest(\"SHA-256\", der);\n\treturn new Uint8Array(digest);\n}\n\n// Normalize our friendlier pinning options into the DOM `serverCertificateHashes`.\nasync function resolveCertificateHashes(options?: WebTransportProps): Promise<WebTransportHash[] | undefined> {\n\tconst hashes: WebTransportHash[] = [];\n\n\tfor (const hash of options?.serverCertificateHashes ?? []) {\n\t\tconst value = typeof hash.value === \"string\" ? Hex.toBytes(hash.value) : hash.value;\n\t\thashes.push({ algorithm: hash.algorithm ?? \"sha-256\", value });\n\t}\n\n\tif (options?.serverCertificate !== undefined) {\n\t\thashes.push({ algorithm: \"sha-256\", value: await certificateHash(options.serverCertificate) });\n\t}\n\n\treturn hashes.length > 0 ? hashes : undefined;\n}\n\nasync function connectWebTransport(\n\turl: URL,\n\tcancel: Promise<void>,\n\toptions?: WebTransportProps,\n): Promise<WebTransport | undefined> {\n\tlet finalUrl = url;\n\n\t// Our custom pinning fields are normalized separately; the rest are DOM options.\n\tconst { serverCertificate: _cert, serverCertificateHashes: _hashes, ...webtransport } = options ?? {};\n\n\tconst finalOptions: WebTransportOptions = {\n\t\tallowPooling: false,\n\t\tcongestionControl: \"low-latency\",\n\t\tprotocols: [\n\t\t\t// Lite.ALPN_06_WIP is intentionally omitted: lite-06 is work-in-progress and\n\t\t\t// not advertised by default (connect.ts still accepts it if a server negotiates it).\n\t\t\tLite.ALPN_05,\n\t\t\tLite.ALPN_04,\n\t\t\tLite.ALPN_03,\n\t\t\tLite.ALPN,\n\t\t\tIetf.ALPN.DRAFT_20,\n\t\t\tIetf.ALPN.DRAFT_19,\n\t\t\tIetf.ALPN.DRAFT_18,\n\t\t\tIetf.ALPN.DRAFT_17,\n\t\t\tIetf.ALPN.DRAFT_16,\n\t\t\tIetf.ALPN.DRAFT_15,\n\t\t],\n\t\t...webtransport,\n\t};\n\n\t// Accumulate caller-provided pins first, then append anything we fetch below,\n\t// so a fetched fingerprint never clobbers hashes passed in via options.\n\tconst hashes = (await resolveCertificateHashes(options)) ?? [];\n\n\t// Only perform certificate fetch and URL rewrite when polyfill is not needed\n\t// This is needed because WebTransport is a butt to work with in local development.\n\tif (url.protocol === \"http:\") {\n\t\tconst fingerprintUrl = new URL(url);\n\t\tfingerprintUrl.pathname = \"/certificate.sha256\";\n\t\tfingerprintUrl.search = \"\";\n\t\t// Dev-only path: http:// can't be a real WebTransport origin, so we fetch the\n\t\t// self-signed cert's hash over plain HTTP and pin it. Production uses https://\n\t\t// and never reaches here. Keep this at debug so it doesn't read as a problem.\n\t\tconsole.debug(\n\t\t\tfingerprintUrl.toString(),\n\t\t\t\"performing an insecure fingerprint fetch; use https:// in production\",\n\t\t);\n\n\t\t// Fetch the fingerprint from the server.\n\t\t// TODO cancel the request if the effect is cancelled.\n\t\tconst fingerprint = await Promise.race([fetch(fingerprintUrl), cancel]);\n\t\tif (!fingerprint) return undefined;\n\n\t\tconst fingerprintText = await Promise.race([fingerprint.text(), cancel]);\n\t\tif (fingerprintText === undefined) return undefined;\n\n\t\thashes.push({ algorithm: \"sha-256\", value: Hex.toBytes(fingerprintText) });\n\n\t\tfinalUrl = new URL(url);\n\t\tfinalUrl.protocol = \"https:\";\n\t}\n\n\tif (hashes.length > 0) {\n\t\tfinalOptions.serverCertificateHashes = hashes;\n\t}\n\n\tconst quic = new WebTransport(finalUrl, finalOptions);\n\n\t// Both .ready and .closed reject on failure; catch .closed to avoid an unhandled rejection.\n\tquic.closed.catch(() => {});\n\n\t// Wait for the WebTransport to connect, or for the cancel promise to resolve.\n\t// Close the connection if we lost the race.\n\tconst loaded = await Promise.race([quic.ready.then(() => true), cancel]);\n\tif (!loaded) {\n\t\tquic.close();\n\t\treturn undefined;\n\t}\n\n\treturn quic;\n}\n\n// TODO accept arguments to control the port/path used.\nasync function connectWebSocket(url: URL, delay: number, cancel: Promise<void>): Promise<Session | undefined> {\n\tconst timer = new Promise<void>((resolve) => setTimeout(resolve, delay));\n\n\tconst active = await Promise.race([cancel, timer.then(() => true)]);\n\tif (!active) return undefined;\n\n\t// Only moq-transport-18 is pinned to qmux-01 today. Every other ALPN we\n\t// support is currently negotiated as `qmux-00.{alpn}` on the wire, but we\n\t// don't want to lock that in: set the value to `null` so the polyfill\n\t// advertises every QMux draft it knows about and the server picks one.\n\t// Insertion order is the negotiation preference on the wire.\n\tconst versions = {\n\t\t// Lite.ALPN_06_WIP omitted on purpose: lite-06 is work-in-progress, not advertised by default.\n\t\t[Lite.ALPN_05]: null,\n\t\t[Lite.ALPN_04]: null,\n\t\t[Lite.ALPN_03]: null,\n\t\t[Lite.ALPN]: null,\n\t\t[Ietf.ALPN.DRAFT_20]: \"qmux-01\",\n\t\t[Ietf.ALPN.DRAFT_18]: \"qmux-01\",\n\t\t[Ietf.ALPN.DRAFT_17]: null,\n\t\t[Ietf.ALPN.DRAFT_16]: null,\n\t\t[Ietf.ALPN.DRAFT_15]: null,\n\t} as const satisfies Record<string, QmuxVersion | QmuxVersion[] | null>;\n\n\t// The default (`requireProtocol: false`) also advertises bare `qmux-01`,\n\t// `qmux-00`, and `webtransport` so we still interop with relays that only\n\t// know a wire-format version (today's moq-relay only accepts bare\n\t// `webtransport`).\n\tconst quic = new Session(url, {\n\t\tprotocols: Object.keys(versions),\n\t\tversions,\n\t});\n\n\t// Wait for the WebSocket to connect, or for the cancel promise to resolve.\n\t// `ready` rejects on a refused/failed connection, so a throw here is the caller's\n\t// cue to retry; a lost cancel race instead resolves and we close the loser.\n\tconst loaded = await Promise.race([quic.ready.then(() => true), cancel]);\n\tif (!loaded) {\n\t\tquic.close();\n\t\treturn undefined;\n\t}\n\n\treturn quic;\n}\n"]}
1
+ {"version":3,"file":"connect.js","sourceRoot":"","sources":["../../src/connection/connect.ts"],"names":[],"mappings":"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","sourcesContent":["import Session, { type Version as QmuxVersion } from \"@moq/qmux\";\nimport { error, fromClose } from \"../error.ts\";\nimport * as Ietf from \"../ietf/index.ts\";\nimport * as Lite from \"../lite/index.ts\";\nimport type { Consumer as OriginConsumer, Producer as OriginProducer } from \"../origin.ts\";\nimport { Stream } from \"../stream.ts\";\nimport * as Time from \"../time.ts\";\nimport * as Hex from \"../util/hex.ts\";\nimport { dev, redact } from \"../util/log.ts\";\nimport { isWebTransportSupported } from \"./browser.ts\";\nimport type { Established } from \"./established.ts\";\nimport { forwardAnnounced } from \"./forward.ts\";\nimport { exchangeSetup } from \"./handshake.ts\";\n\n// Default head start for WebTransport before attempting the WebSocket fallback.\nconst DEFAULT_WEBSOCKET_DELAY_MS = Time.Milli(500);\n\n// RESET_STREAM and CONNECTION_CLOSE are separate transport notifications. Give the latter\n// time to surface its authoritative code without letting a reset-only peer stall SETUP forever.\nconst SETUP_CLOSE_GRACE_MS = 100;\n\n/** Tuning for the WebSocket fallback used when WebTransport is unavailable or loses the connect race. */\nexport interface WebSocketProps {\n\t/** Enable the WebSocket fallback. Defaults to `true`. */\n\tenabled?: boolean;\n\n\t/** Use a different URL than WebTransport. By default, `https` maps to `wss` and `http` to `ws`. */\n\turl?: URL;\n\n\t/**\n\t * The delay in milliseconds before attempting the WebSocket fallback (default: 500).\n\t * If WebSocket won the previous race for a given URL, this is 0.\n\t */\n\tdelay?: Time.Milli;\n}\n\n/**\n * A server certificate hash used to pin a self-signed server, one entry of\n * `serverCertificateHashes`. Unlike the DOM type, `value` also accepts a hex string (the\n * format moq servers report via their certificate fingerprints), decoded automatically.\n */\nexport interface CertificateHash {\n\t/** The hash algorithm. Defaults to `sha-256` (the only supported value). */\n\talgorithm?: \"sha-256\";\n\t/** The certificate hash: raw bytes or a hex string. */\n\tvalue: BufferSource | string;\n}\n\n/** WebTransport options extended with friendlier certificate pinning (hex hashes or a raw certificate). */\nexport interface WebTransportProps extends Omit<WebTransportOptions, \"serverCertificateHashes\"> {\n\t/**\n\t * Pin the server to one or more certificate hashes. Each `value` may be raw\n\t * bytes or a hex string; the algorithm defaults to `sha-256`.\n\t */\n\tserverCertificateHashes?: CertificateHash[];\n\n\t/**\n\t * Pin the server by supplying its certificate directly; the SHA-256 hash is\n\t * computed for you. Accepts a PEM string or raw DER bytes. Use this when you\n\t * have the certificate but not its precomputed fingerprint.\n\t */\n\tserverCertificate?: string | BufferSource;\n}\n\n/** Options for {@link connect}. */\nexport interface ConnectProps {\n\t/** The relay URL. */\n\turl: URL;\n\n\t/** WebTransport options. */\n\twebtransport?: WebTransportProps;\n\n\t/** WebSocket (fallback) options. */\n\twebsocket?: WebSocketProps;\n\n\t/**\n\t * Use a pre-existing WebTransport session instead of connecting; skips the\n\t * WebTransport/WebSocket race. The publisher acquires the session's datagram\n\t * writer lock (`datagrams.writable.getWriter()`) for the session's lifetime,\n\t * so the caller must not hold it. Aborting via {@link ConnectProps.signal}\n\t * closes this session, so don't share one you intend to reuse afterwards.\n\t */\n\ttransport?: WebTransport;\n\n\t/**\n\t * Whether the relay supports broadcast discovery; see {@link Established.discovery}.\n\t * Defaults to true.\n\t */\n\tdiscovery?: boolean;\n\n\t/**\n\t * The origin whose broadcasts the session announces and serves to the peer. Omit to\n\t * publish nothing.\n\t *\n\t * The origin is borrowed, not owned: closing the session leaves its broadcasts alone,\n\t * and the same origin can back several sessions (or successive reconnects), each\n\t * announcing the table for as long as it lasts.\n\t */\n\tpublish?: OriginConsumer;\n\n\t/**\n\t * The origin the session feeds with the peer's announced broadcasts. Omit to discover\n\t * nothing.\n\t *\n\t * Everything the peer announces appears in the origin's table for the session's\n\t * lifetime, consumable by path; the entries retract when the session dies. Pass the\n\t * producer behind {@link ConnectProps.publish} to route both directions through one\n\t * origin: a locally published path is then served back to local consumers directly, and\n\t * the session still never announces the peer's own broadcasts back to it.\n\t */\n\tconsume?: OriginProducer;\n\n\t/**\n\t * Aborts the connection attempt with the signal's reason. An already-aborted\n\t * signal rejects before anything opens, and aborting after the connection is\n\t * established has no effect. Use `AbortSignal.timeout(ms)` for a deadline.\n\t */\n\tsignal?: AbortSignal;\n}\n\n/** The per-session wiring shared by every negotiated protocol path. */\ntype SessionProps = {\n\tdiscovery: boolean;\n\tpublish?: OriginConsumer;\n};\n\n// Save if WebSocket won the last race, so we won't give QUIC a head start next time.\nconst websocketWon = new Set<string>();\n\n/** The default connect signal: never aborts. */\nconst NEVER_ABORTED = new AbortController().signal;\n\n/**\n * Establishes a connection to a MOQ server.\n *\n * @param url - The URL of the server to connect to\n * @param props - Connection options\n * @returns A promise that resolves to an established session\n */\nexport async function connect({ url, ...props }: ConnectProps): Promise<Established> {\n\tconst signal = props.signal ?? NEVER_ABORTED;\n\tsignal.throwIfAborted();\n\n\t// Resolves on abort so every in-flight transport tears itself down.\n\tconst { promise: abort, resolve } = Promise.withResolvers<void>();\n\tconst onAbort = () => resolve();\n\tsignal.addEventListener(\"abort\", onAbort, { once: true });\n\n\tconst pending = connectInner(url, props, abort);\n\ttry {\n\t\t// A `pending` rejection propagates unless the abort beat it to the finish line.\n\t\tconst connection = await Promise.race([pending, abort.then(() => undefined)]);\n\t\tif (connection && !signal.aborted) {\n\t\t\tif (props.consume) forwardAnnounced(connection, props.consume);\n\t\t\treturn connection;\n\t\t}\n\n\t\t// Close a connection that settles after the abort.\n\t\tpending.then((conn) => conn.close()).catch(() => {});\n\t\tthrow signal.reason;\n\t} finally {\n\t\tsignal.removeEventListener(\"abort\", onAbort);\n\t}\n}\n\nasync function connectInner(url: URL, props: Omit<ConnectProps, \"url\">, abort: Promise<void>): Promise<Established> {\n\tconst wiring: SessionProps = {\n\t\tdiscovery: props.discovery ?? true,\n\t\tpublish: props.publish,\n\t};\n\n\tif (props.transport) {\n\t\tconst transport = props.transport;\n\t\tvoid abort.then(() => transport.close());\n\t\treturn connectTransport(url, transport, wiring);\n\t}\n\n\t// Stop transports after one connects or the caller aborts.\n\tconst { promise: raced, resolve: done } = Promise.withResolvers<void>();\n\tconst cancel = Promise.race([raced, abort]);\n\n\tconst webtransport = isWebTransportSupported() ? connectWebTransport(url, cancel, props.webtransport) : undefined;\n\n\t// Give QUIC a head start to connect before trying WebSocket, unless WebSocket has won in the past.\n\t// NOTE that QUIC should be faster because it involves 1/2 fewer RTTs.\n\tconst headstart =\n\t\t!webtransport || websocketWon.has(url.toString()) ? 0 : (props.websocket?.delay ?? DEFAULT_WEBSOCKET_DELAY_MS);\n\tconst websocket =\n\t\tprops.websocket?.enabled !== false\n\t\t\t? connectWebSocket(props.websocket?.url ?? url, headstart, cancel)\n\t\t\t: undefined;\n\n\tif (!websocket && !webtransport) {\n\t\tthrow new Error(\"no transport available; WebTransport not supported and WebSocket is disabled\");\n\t}\n\n\t// Race the available transports, using `.any` to ignore if one participant has an error.\n\t// `webtransport`/`websocket` are `Promise | undefined`, so test existence explicitly: a\n\t// promise is always truthy, so bare truthiness here would be a misused-promise.\n\tconst session = await Promise.any(\n\t\twebtransport !== undefined\n\t\t\t? websocket !== undefined\n\t\t\t\t? [websocket, webtransport]\n\t\t\t\t: [webtransport]\n\t\t\t: [websocket],\n\t);\n\tdone();\n\n\tif (!session) throw new Error(\"no transport available\");\n\n\t// Abort the setup handshake without leaking the selected transport.\n\tvoid abort.then(() => session.close());\n\n\t// Save if WebSocket won the last race, so we won't give QUIC a head start next time.\n\tif (session instanceof Session) {\n\t\t// Still a warning, not a debug line: losing the race means we fell back off QUIC.\n\t\tif (dev()) console.warn(redact(url), \"connected via WebSocket\");\n\t\twebsocketWon.add(url.toString());\n\t} else if (dev()) {\n\t\tconsole.debug(redact(url), \"connected via WebTransport\");\n\t}\n\n\t// The remaining setup is identical whether the transport was raced or supplied.\n\treturn await connectTransport(url, session as WebTransport, wiring);\n}\n\nasync function connectTransport(url: URL, session: WebTransport, wiring: SessionProps): Promise<Established> {\n\tconst closed = session.closed.then(fromClose, error);\n\tconst terminal = closed.then((cause) => {\n\t\tthrow cause ?? new Error(\"session closed during SETUP\");\n\t});\n\n\ttry {\n\t\treturn await Promise.race([terminal, negotiate(url, session, wiring)]);\n\t} catch (cause) {\n\t\t// A session shutdown can reject its SETUP stream before `closed` publishes the\n\t\t// peer's close code. Wait briefly without closing locally, since a local clean close\n\t\t// could overwrite that code. A reset-only peer is cleaned up after the grace period.\n\t\tconst pending = Symbol(\"session close pending\");\n\t\tconst final = await Promise.race([\n\t\t\tclosed,\n\t\t\tnew Promise<typeof pending>((resolve) => setTimeout(() => resolve(pending), SETUP_CLOSE_GRACE_MS)),\n\t\t]);\n\t\tif (final !== pending) {\n\t\t\tif (final) throw final;\n\t\t\tthrow cause;\n\t\t}\n\n\t\tsession.close();\n\t\tthrow cause;\n\t}\n}\n\n// Negotiate the MoQ protocol over an established transport. The caller races this against\n// the session closing so a close code is not lost behind a failed or stalled SETUP stream.\nasync function negotiate(url: URL, session: WebTransport, wiring: SessionProps): Promise<Established> {\n\t// The DOM lib has no `protocol` property yet. It is \"\" when none was negotiated, and\n\t// undefined in a browser that predates subprotocols (Firefox before 155).\n\tconst protocol: string | undefined = (session as { protocol?: string }).protocol || undefined;\n\tif (dev()) console.debug(redact(url), \"negotiated ALPN:\", protocol ?? \"(none)\");\n\n\t// Choose setup encoding based on negotiated WebTransport protocol (if any).\n\tlet setupVersion: Ietf.Version;\n\tconst modernVersion =\n\t\tprotocol === Ietf.ALPN.DRAFT_22\n\t\t\t? Ietf.Version.DRAFT_22\n\t\t\t: protocol === Ietf.ALPN.DRAFT_21\n\t\t\t\t? Ietf.Version.DRAFT_21\n\t\t\t\t: protocol === Ietf.ALPN.DRAFT_20\n\t\t\t\t\t? Ietf.Version.DRAFT_20\n\t\t\t\t\t: protocol === Ietf.ALPN.DRAFT_19\n\t\t\t\t\t\t? Ietf.Version.DRAFT_19\n\t\t\t\t\t\t: protocol === Ietf.ALPN.DRAFT_18\n\t\t\t\t\t\t\t? Ietf.Version.DRAFT_18\n\t\t\t\t\t\t\t: protocol === Ietf.ALPN.DRAFT_17\n\t\t\t\t\t\t\t\t? Ietf.Version.DRAFT_17\n\t\t\t\t\t\t\t\t: undefined;\n\tif (modernVersion !== undefined) {\n\t\treturn await handshakeAlpn(url, session, modernVersion, wiring);\n\t} else if (protocol === Ietf.ALPN.DRAFT_16) {\n\t\tsetupVersion = Ietf.Version.DRAFT_16;\n\t} else if (protocol === Ietf.ALPN.DRAFT_15) {\n\t\tsetupVersion = Ietf.Version.DRAFT_15;\n\t} else if (protocol === Lite.ALPN_07_WIP) {\n\t\treturn new Lite.Connection({ url, quic: session, version: Lite.Version.DRAFT_07, ...wiring });\n\t} else if (protocol === Lite.ALPN_06) {\n\t\treturn new Lite.Connection({ url, quic: session, version: Lite.Version.DRAFT_06, ...wiring });\n\t} else if (protocol === Lite.ALPN_05) {\n\t\treturn new Lite.Connection({ url, quic: session, version: Lite.Version.DRAFT_05, ...wiring });\n\t} else if (protocol === Lite.ALPN_04) {\n\t\treturn new Lite.Connection({ url, quic: session, version: Lite.Version.DRAFT_04, ...wiring });\n\t} else if (protocol === Lite.ALPN_03) {\n\t\treturn new Lite.Connection({ url, quic: session, version: Lite.Version.DRAFT_03, ...wiring });\n\t} else if (protocol === Lite.ALPN || protocol === \"\" || protocol === undefined) {\n\t\tsetupVersion = Ietf.Version.DRAFT_14;\n\t} else {\n\t\tthrow new Error(`unsupported WebTransport protocol: ${protocol}`);\n\t}\n\n\tconst stream = await Stream.open(session, { version: setupVersion });\n\tawait stream.writer.u53(Lite.StreamId.ClientCompat);\n\n\tconst encoder = new TextEncoder();\n\n\tconst params = new Ietf.SetupOptions();\n\tparams.setVarint(Ietf.SetupOption.MaxRequestId, 42069n);\n\tparams.setBytes(Ietf.SetupOption.Implementation, encoder.encode(\"moq-lite-js\"));\n\tIetf.solicitIntoSetup(params);\n\tIetf.hiddenIntoSetup(params);\n\n\tconst client = new Ietf.ClientSetup({\n\t\tversions:\n\t\t\tsetupVersion === Ietf.Version.DRAFT_16\n\t\t\t\t? [Ietf.Version.DRAFT_16]\n\t\t\t\t: setupVersion === Ietf.Version.DRAFT_15\n\t\t\t\t\t? [Ietf.Version.DRAFT_15]\n\t\t\t\t\t: [Lite.Version.DRAFT_02, Lite.Version.DRAFT_01, Ietf.Version.DRAFT_14],\n\t\tparameters: params,\n\t});\n\tawait client.encode(stream.writer, setupVersion);\n\n\tconst serverCompat = await stream.reader.u53();\n\tif (serverCompat !== Lite.StreamId.ServerCompat) {\n\t\tthrow new Error(`unsupported server message type: ${serverCompat.toString()}`);\n\t}\n\n\tconst server = await Ietf.ServerSetup.decode(stream.reader, setupVersion);\n\n\tif (Object.values(Lite.Version).includes(server.version as Lite.Version)) {\n\t\treturn new Lite.Connection({\n\t\t\turl,\n\t\t\tquic: session,\n\t\t\tversion: server.version as Lite.Version,\n\t\t\tsession: stream,\n\t\t\t...wiring,\n\t\t});\n\t} else if (Object.values(Ietf.Version).includes(server.version as Ietf.Version)) {\n\t\tconst maxRequestId = server.parameters.getVarint(Ietf.SetupOption.MaxRequestId) ?? 0n;\n\t\treturn new Ietf.Connection({\n\t\t\t...wiring,\n\t\t\tclient: true,\n\t\t\turl,\n\t\t\tquic: session,\n\t\t\tcontrol: stream,\n\t\t\tmaxRequestId,\n\t\t\tversion: server.version as Ietf.IetfVersion,\n\t\t\tsolicit: Ietf.solicitFromSetup(server.parameters),\n\t\t\thidden: Ietf.hiddenFromSetup(server.parameters),\n\t\t});\n\t} else {\n\t\tthrow new Error(`unsupported server version: ${server.version.toString()}`);\n\t}\n}\n\n/**\n * Draft-17+ client handshake. ALPN already pinned the version; SETUP is\n * exchanged over a pair of uni streams using stream type 0x2F00.\n */\nasync function handshakeAlpn(\n\turl: URL,\n\tsession: WebTransport,\n\tversion: Ietf.IetfVersion,\n\twiring: SessionProps,\n): Promise<Established> {\n\tconst { control, solicit, hidden, cluster } = await exchangeSetup(session, version, \"moq-lite-js\");\n\n\treturn new Ietf.Connection({\n\t\t...wiring,\n\t\tclient: true,\n\t\turl,\n\t\tquic: session,\n\t\tcontrol,\n\t\tsolicit,\n\t\thidden,\n\t\tcluster,\n\t\t// v17+ uses NativeSession which manages its own request IDs; maxRequestId is unused.\n\t\tmaxRequestId: 0n,\n\t\tversion,\n\t});\n}\n\n// One entry of the DOM `serverCertificateHashes`, derived without naming the lib type.\ntype WebTransportHash = NonNullable<WebTransportOptions[\"serverCertificateHashes\"]>[number];\n\n// Strip PEM armor and base64-decode to the raw DER bytes.\nfunction pemToDer(pem: string): Uint8Array<ArrayBuffer> {\n\tconst match = pem.match(/-----BEGIN CERTIFICATE-----([\\s\\S]+?)-----END CERTIFICATE-----/);\n\tif (!match) {\n\t\tthrow new Error(\"invalid PEM certificate: missing -----BEGIN/END CERTIFICATE----- armor\");\n\t}\n\n\tconst binary = atob(match[1].replace(/\\s+/g, \"\"));\n\tconst der = new Uint8Array(binary.length);\n\tfor (let i = 0; i < binary.length; i++) {\n\t\tder[i] = binary.charCodeAt(i);\n\t}\n\treturn der;\n}\n\n/**\n * Compute the SHA-256 hash of a certificate, the value `serverCertificateHashes`\n * pins. Accepts a PEM string or raw DER bytes. Matches the hex fingerprints a moq\n * server reports, so `Hex.fromBytes(await certificateHash(pem))` round-trips.\n */\nexport async function certificateHash(cert: string | BufferSource): Promise<Uint8Array<ArrayBuffer>> {\n\tconst der = typeof cert === \"string\" ? pemToDer(cert) : cert;\n\tconst digest = await crypto.subtle.digest(\"SHA-256\", der);\n\treturn new Uint8Array(digest);\n}\n\n// Normalize our friendlier pinning options into the DOM `serverCertificateHashes`.\nasync function resolveCertificateHashes(options?: WebTransportProps): Promise<WebTransportHash[] | undefined> {\n\tconst hashes: WebTransportHash[] = [];\n\n\tfor (const hash of options?.serverCertificateHashes ?? []) {\n\t\tconst value = typeof hash.value === \"string\" ? Hex.toBytes(hash.value) : hash.value;\n\t\thashes.push({ algorithm: hash.algorithm ?? \"sha-256\", value });\n\t}\n\n\tif (options?.serverCertificate !== undefined) {\n\t\thashes.push({ algorithm: \"sha-256\", value: await certificateHash(options.serverCertificate) });\n\t}\n\n\treturn hashes.length > 0 ? hashes : undefined;\n}\n\nasync function connectWebTransport(\n\turl: URL,\n\tcancel: Promise<void>,\n\toptions?: WebTransportProps,\n): Promise<WebTransport | undefined> {\n\tlet finalUrl = url;\n\n\t// Our custom pinning fields are normalized separately; the rest are DOM options.\n\tconst { serverCertificate: _cert, serverCertificateHashes: _hashes, ...webtransport } = options ?? {};\n\n\tconst finalOptions: WebTransportOptions = {\n\t\tallowPooling: false,\n\t\tcongestionControl: \"low-latency\",\n\t\tprotocols: [\n\t\t\t// Lite.ALPN_07_WIP is intentionally omitted: lite-07 is work-in-progress and\n\t\t\t// not advertised by default (negotiate still accepts it if a server selects it).\n\t\t\tLite.ALPN_06,\n\t\t\tLite.ALPN_05,\n\t\t\tLite.ALPN_04,\n\t\t\tLite.ALPN_03,\n\t\t\tLite.ALPN,\n\t\t\tIetf.ALPN.DRAFT_22,\n\t\t\tIetf.ALPN.DRAFT_21,\n\t\t\tIetf.ALPN.DRAFT_20,\n\t\t\tIetf.ALPN.DRAFT_19,\n\t\t\tIetf.ALPN.DRAFT_18,\n\t\t\tIetf.ALPN.DRAFT_17,\n\t\t\tIetf.ALPN.DRAFT_16,\n\t\t\tIetf.ALPN.DRAFT_15,\n\t\t],\n\t\t...webtransport,\n\t};\n\n\t// Accumulate caller-provided pins first, then append anything we fetch below,\n\t// so a fetched fingerprint never clobbers hashes passed in via options.\n\tconst hashes = (await resolveCertificateHashes(options)) ?? [];\n\n\t// Only perform certificate fetch and URL rewrite when polyfill is not needed\n\t// This is needed because WebTransport is a butt to work with in local development.\n\tif (url.protocol === \"http:\") {\n\t\tconst fingerprintUrl = new URL(url);\n\t\tfingerprintUrl.pathname = \"/certificate.sha256\";\n\t\t// The certificate endpoint is unauthenticated, so don't hand it the token.\n\t\tfingerprintUrl.search = \"\";\n\n\t\t// Dev-only path: http:// can't be a real WebTransport origin, so we fetch the\n\t\t// self-signed cert's hash over plain HTTP and pin it. Production uses https://\n\t\t// and never reaches here. Keep this at debug so it doesn't read as a problem.\n\t\tif (dev()) {\n\t\t\tconsole.debug(\n\t\t\t\tredact(fingerprintUrl),\n\t\t\t\t\"performing an insecure fingerprint fetch; use https:// in production\",\n\t\t\t);\n\t\t}\n\n\t\t// Fetch the fingerprint from the server.\n\t\t// TODO cancel the request if the effect is cancelled.\n\t\tconst fingerprint = await Promise.race([fetch(fingerprintUrl), cancel]);\n\t\tif (!fingerprint) return undefined;\n\n\t\tconst fingerprintText = await Promise.race([fingerprint.text(), cancel]);\n\t\tif (fingerprintText === undefined) return undefined;\n\n\t\thashes.push({ algorithm: \"sha-256\", value: Hex.toBytes(fingerprintText) });\n\n\t\tfinalUrl = new URL(url);\n\t\tfinalUrl.protocol = \"https:\";\n\t}\n\n\tif (hashes.length > 0) {\n\t\tfinalOptions.serverCertificateHashes = hashes;\n\t}\n\n\tconst quic = new WebTransport(finalUrl, finalOptions);\n\n\t// Both .ready and .closed reject on failure; catch .closed to avoid an unhandled rejection.\n\tquic.closed.catch(() => {});\n\n\t// Wait for the WebTransport to connect, or for the cancel promise to resolve.\n\t// Close the connection if we lost the race.\n\tconst loaded = await Promise.race([quic.ready.then(() => true), cancel]);\n\tif (!loaded) {\n\t\tquic.close();\n\t\treturn undefined;\n\t}\n\n\treturn quic;\n}\n\n// TODO accept arguments to control the port/path used.\nasync function connectWebSocket(url: URL, delay: number, cancel: Promise<void>): Promise<Session | undefined> {\n\tconst timer = new Promise<void>((resolve) => setTimeout(resolve, delay));\n\n\tconst active = await Promise.race([cancel, timer.then(() => true)]);\n\tif (!active) return undefined;\n\n\t// moq-transport-18 and newer are pinned to qmux-01. Every other ALPN we\n\t// support is currently negotiated as `qmux-00.{alpn}` on the wire, but we\n\t// don't want to lock that in: set the value to `null` so the polyfill\n\t// advertises every QMux draft it knows about and the server picks one.\n\t// Insertion order is the negotiation preference on the wire.\n\tconst versions = {\n\t\t// Lite.ALPN_07_WIP omitted on purpose: lite-07 is work-in-progress, not advertised by default.\n\t\t[Lite.ALPN_06]: null,\n\t\t[Lite.ALPN_05]: null,\n\t\t[Lite.ALPN_04]: null,\n\t\t[Lite.ALPN_03]: null,\n\t\t[Lite.ALPN]: null,\n\t\t[Ietf.ALPN.DRAFT_22]: \"qmux-01\",\n\t\t[Ietf.ALPN.DRAFT_21]: \"qmux-01\",\n\t\t[Ietf.ALPN.DRAFT_20]: \"qmux-01\",\n\t\t[Ietf.ALPN.DRAFT_19]: \"qmux-01\",\n\t\t[Ietf.ALPN.DRAFT_18]: \"qmux-01\",\n\t\t[Ietf.ALPN.DRAFT_17]: null,\n\t\t[Ietf.ALPN.DRAFT_16]: null,\n\t\t[Ietf.ALPN.DRAFT_15]: null,\n\t} as const satisfies Record<string, QmuxVersion | QmuxVersion[] | null>;\n\n\t// The default (`requireProtocol: false`) also advertises bare `qmux-01`,\n\t// `qmux-00`, and `webtransport` so we still interop with relays that only\n\t// know a wire-format version (today's moq-relay only accepts bare\n\t// `webtransport`).\n\tconst quic = new Session(url, {\n\t\tprotocols: Object.keys(versions),\n\t\tversions,\n\t});\n\n\t// Wait for the WebSocket to connect, or for the cancel promise to resolve.\n\t// `ready` rejects on a refused/failed connection, so a throw here is the caller's\n\t// cue to retry; a lost cancel race instead resolves and we close the loser.\n\tconst loaded = await Promise.race([quic.ready.then(() => true), cancel]);\n\tif (!loaded) {\n\t\tquic.close();\n\t\treturn undefined;\n\t}\n\n\treturn quic;\n}\n"]}
@@ -1,10 +1,14 @@
1
1
  import type { Getter } from "@norskvideo/moq-signals";
2
2
  import type * as announce from "../announced";
3
- import type * as broadcast from "../broadcast";
4
3
  import type * as Path from "../path";
5
4
  import type { Probe, Stats } from "./stats";
6
5
  import type { Transport } from "./transport";
7
- /** An established MoQ session, implemented by both the moq-lite and moq-ietf protocols. */
6
+ /**
7
+ * An established MoQ session, implemented by both the moq-lite and moq-ietf protocols.
8
+ *
9
+ * Publishing goes through an origin, not the session: pass an `Origin.Consumer` as the
10
+ * `publish` connect option and the session announces and serves that origin's broadcasts.
11
+ */
8
12
  export interface Established {
9
13
  /** URL of the connected server. */
10
14
  readonly url: URL;
@@ -23,25 +27,13 @@ export interface Established {
23
27
  * rather than wait for an announcement. Set via `discovery` on the connect options.
24
28
  */
25
29
  readonly discovery: boolean;
26
- /** Subscribe to broadcast announcements under an optional path prefix, returning paths relative to that prefix. */
27
- announced(prefix?: Path.Valid): announce.Consumer;
28
- /** Publish a broadcast at the given path. */
29
- publish(path: Path.Valid, broadcast: broadcast.Producer): void;
30
30
  /**
31
- * Consume the broadcast at the given path, immediately.
32
- *
33
- * The subscription is reset if nobody publishes the path, so use
34
- * {@link announcedBroadcast} instead when the broadcast may not be online yet.
35
- */
36
- consume(path: Path.Valid): broadcast.Consumer;
37
- /**
38
- * A reactive handle to the broadcast at the given path, live only while it is announced.
39
- *
40
- * The announcement-gated counterpart to {@link consume}: it waits for the broadcast to come
41
- * online instead of resetting, and drops back to `undefined` when it goes away. See
42
- * {@link announce.Broadcast}. Close the handle when done.
31
+ * Subscribe to broadcast announcements matching `scope`, any pattern (`foo/**`
32
+ * for a subtree, `room/* /chat` for each room's chat, default `**`). Paths are
33
+ * relative to the session; captures report what the scope's wildcards stood for.
34
+ * Hidden routes are left out unless `options.hidden` opts in.
43
35
  */
44
- announcedBroadcast(path: Path.Valid): announce.Broadcast;
36
+ announced(scope?: Path.Pattern, options?: announce.Options): announce.Consumer;
45
37
  /**
46
38
  * Snapshot the transport's counters, querying it fresh on each call.
47
39
  *
@@ -51,7 +43,11 @@ export interface Established {
51
43
  stats(): Promise<Stats>;
52
44
  /** Close the session. */
53
45
  close(): void;
54
- /** Resolves when the session closes. */
55
- closed: Promise<void>;
46
+ /**
47
+ * Resolves when the session closes: `null` for a clean close, an `Error.Session` when the
48
+ * peer closed with a code (e.g. `SessionCode.Unauthorized` for an auth rejection), or the
49
+ * transport's own failure. Never rejects.
50
+ */
51
+ closed: Promise<Error | null>;
56
52
  }
57
53
  //# sourceMappingURL=established.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"established.d.ts","sourceRoot":"","sources":["../../src/connection/established.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,KAAK,KAAK,QAAQ,MAAM,iBAAiB,CAAC;AACjD,OAAO,KAAK,KAAK,SAAS,MAAM,iBAAiB,CAAC;AAClD,OAAO,KAAK,KAAK,IAAI,MAAM,YAAY,CAAC;AACxC,OAAO,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAEhD,2FAA2F;AAC3F,MAAM,WAAW,WAAW;IAC3B,mCAAmC;IACnC,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAC;IAElB,wCAAwC;IACxC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IAEzB,iDAAiD;IACjD,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC;IAE9B;;;OAGG;IACH,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC;IAE9B;;;;OAIG;IACH,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAE5B,mHAAmH;IACnH,SAAS,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC,KAAK,GAAG,QAAQ,CAAC,QAAQ,CAAC;IAElD,6CAA6C;IAC7C,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,EAAE,SAAS,EAAE,SAAS,CAAC,QAAQ,GAAG,IAAI,CAAC;IAE/D;;;;;OAKG;IACH,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,GAAG,SAAS,CAAC,QAAQ,CAAC;IAE9C;;;;;;OAMG;IACH,kBAAkB,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,GAAG,QAAQ,CAAC,SAAS,CAAC;IAEzD;;;;;OAKG;IACH,KAAK,IAAI,OAAO,CAAC,KAAK,CAAC,CAAC;IAExB,yBAAyB;IACzB,KAAK,IAAI,IAAI,CAAC;IAEd,wCAAwC;IACxC,MAAM,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;CACtB"}
1
+ {"version":3,"file":"established.d.ts","sourceRoot":"","sources":["../../src/connection/established.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,KAAK,KAAK,QAAQ,MAAM,iBAAiB,CAAC;AACjD,OAAO,KAAK,KAAK,IAAI,MAAM,YAAY,CAAC;AACxC,OAAO,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAEhD;;;;;GAKG;AACH,MAAM,WAAW,WAAW;IAC3B,mCAAmC;IACnC,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAC;IAElB,wCAAwC;IACxC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IAEzB,iDAAiD;IACjD,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC;IAE9B;;;OAGG;IACH,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC;IAE9B;;;;OAIG;IACH,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAE5B;;;;;OAKG;IACH,SAAS,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,EAAE,QAAQ,CAAC,OAAO,GAAG,QAAQ,CAAC,QAAQ,CAAC;IAE/E;;;;;OAKG;IACH,KAAK,IAAI,OAAO,CAAC,KAAK,CAAC,CAAC;IAExB,yBAAyB;IACzB,KAAK,IAAI,IAAI,CAAC;IAEd;;;;OAIG;IACH,MAAM,EAAE,OAAO,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC;CAC9B"}
@@ -1 +1 @@
1
- {"version":3,"file":"established.js","sourceRoot":"","sources":["../../src/connection/established.ts"],"names":[],"mappings":"","sourcesContent":["import type { Getter } from \"@moq/signals\";\nimport type * as announce from \"../announced.ts\";\nimport type * as broadcast from \"../broadcast.ts\";\nimport type * as Path from \"../path.ts\";\nimport type { Probe, Stats } from \"./stats.ts\";\nimport type { Transport } from \"./transport.ts\";\n\n/** An established MoQ session, implemented by both the moq-lite and moq-ietf protocols. */\nexport interface Established {\n\t/** URL of the connected server. */\n\treadonly url: URL;\n\n\t/** Negotiated wire protocol version. */\n\treadonly version: string;\n\n\t/** The wire transport this session runs over. */\n\treadonly transport: Transport;\n\n\t/**\n\t * Estimates measured by the peer, updated as PROBE messages arrive. Stays empty on\n\t * versions without PROBE. See {@link Stats} for what the local transport counts.\n\t */\n\treadonly probe: Getter<Probe>;\n\n\t/**\n\t * Whether the relay supports broadcast discovery: announcing which broadcasts exist under a\n\t * prefix. When false, {@link announced} never yields, so a consumer must subscribe blind\n\t * rather than wait for an announcement. Set via `discovery` on the connect options.\n\t */\n\treadonly discovery: boolean;\n\n\t/** Subscribe to broadcast announcements under an optional path prefix, returning paths relative to that prefix. */\n\tannounced(prefix?: Path.Valid): announce.Consumer;\n\n\t/** Publish a broadcast at the given path. */\n\tpublish(path: Path.Valid, broadcast: broadcast.Producer): void;\n\n\t/**\n\t * Consume the broadcast at the given path, immediately.\n\t *\n\t * The subscription is reset if nobody publishes the path, so use\n\t * {@link announcedBroadcast} instead when the broadcast may not be online yet.\n\t */\n\tconsume(path: Path.Valid): broadcast.Consumer;\n\n\t/**\n\t * A reactive handle to the broadcast at the given path, live only while it is announced.\n\t *\n\t * The announcement-gated counterpart to {@link consume}: it waits for the broadcast to come\n\t * online instead of resetting, and drops back to `undefined` when it goes away. See\n\t * {@link announce.Broadcast}. Close the handle when done.\n\t */\n\tannouncedBroadcast(path: Path.Valid): announce.Broadcast;\n\n\t/**\n\t * Snapshot the transport's counters, querying it fresh on each call.\n\t *\n\t * Resolves to an empty snapshot on a transport without `getStats()`. Sample it on\n\t * whatever schedule you need rather than expecting the library to poll for you.\n\t */\n\tstats(): Promise<Stats>;\n\n\t/** Close the session. */\n\tclose(): void;\n\n\t/** Resolves when the session closes. */\n\tclosed: Promise<void>;\n}\n"]}
1
+ {"version":3,"file":"established.js","sourceRoot":"","sources":["../../src/connection/established.ts"],"names":[],"mappings":"","sourcesContent":["import type { Getter } from \"@moq/signals\";\nimport type * as announce from \"../announced.ts\";\nimport type * as Path from \"../path.ts\";\nimport type { Probe, Stats } from \"./stats.ts\";\nimport type { Transport } from \"./transport.ts\";\n\n/**\n * An established MoQ session, implemented by both the moq-lite and moq-ietf protocols.\n *\n * Publishing goes through an origin, not the session: pass an `Origin.Consumer` as the\n * `publish` connect option and the session announces and serves that origin's broadcasts.\n */\nexport interface Established {\n\t/** URL of the connected server. */\n\treadonly url: URL;\n\n\t/** Negotiated wire protocol version. */\n\treadonly version: string;\n\n\t/** The wire transport this session runs over. */\n\treadonly transport: Transport;\n\n\t/**\n\t * Estimates measured by the peer, updated as PROBE messages arrive. Stays empty on\n\t * versions without PROBE. See {@link Stats} for what the local transport counts.\n\t */\n\treadonly probe: Getter<Probe>;\n\n\t/**\n\t * Whether the relay supports broadcast discovery: announcing which broadcasts exist under a\n\t * prefix. When false, {@link announced} never yields, so a consumer must subscribe blind\n\t * rather than wait for an announcement. Set via `discovery` on the connect options.\n\t */\n\treadonly discovery: boolean;\n\n\t/**\n\t * Subscribe to broadcast announcements matching `scope`, any pattern (`foo/**`\n\t * for a subtree, `room/* /chat` for each room's chat, default `**`). Paths are\n\t * relative to the session; captures report what the scope's wildcards stood for.\n\t * Hidden routes are left out unless `options.hidden` opts in.\n\t */\n\tannounced(scope?: Path.Pattern, options?: announce.Options): announce.Consumer;\n\n\t/**\n\t * Snapshot the transport's counters, querying it fresh on each call.\n\t *\n\t * Resolves to an empty snapshot on a transport without `getStats()`. Sample it on\n\t * whatever schedule you need rather than expecting the library to poll for you.\n\t */\n\tstats(): Promise<Stats>;\n\n\t/** Close the session. */\n\tclose(): void;\n\n\t/**\n\t * Resolves when the session closes: `null` for a clean close, an `Error.Session` when the\n\t * peer closed with a code (e.g. `SessionCode.Unauthorized` for an auth rejection), or the\n\t * transport's own failure. Never rejects.\n\t */\n\tclosed: Promise<Error | null>;\n}\n"]}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=forward.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"forward.d.ts","sourceRoot":"","sources":["../../src/connection/forward.ts"],"names":[],"mappings":""}
@@ -0,0 +1,173 @@
1
+ /* @ts-self-types="./forward.d.ts" */
2
+ /**
3
+ * Feeds a session's announced routes into an origin; the `consume` connect option.
4
+ *
5
+ * @module
6
+ */
7
+ import { race } from "@norskvideo/moq-signals";
8
+ import { isActive } from "../announced.js";
9
+ import * as Path from "../path.js";
10
+ import { wireOf } from "../wire.js";
11
+ /**
12
+ * Wire a session into `origin` for the session's lifetime: forward the peer's announced
13
+ * routes into the table, and answer the origin's open requests with blind
14
+ * subscriptions.
15
+ *
16
+ * Each active announcement inserts a route covering the announced prefix, served
17
+ * lazily through this connection, so nothing touches the wire until somebody requests
18
+ * a path under it. A retraction removes the entry, and so does the session dying (the
19
+ * announce stream ends with it), which is what scopes remote routes to the session
20
+ * that announced them. A reconnect wires a fresh session to the same origin and
21
+ * re-populates it.
22
+ *
23
+ * Without discovery there are no announcements to forward, so the table stays empty and
24
+ * requests are the only way through; see the origin's `request`.
25
+ *
26
+ * @internal
27
+ */
28
+ export function forwardAnnounced(conn, origin) {
29
+ const originWire = wireOf(origin);
30
+ // Reassigned if discovery dies under a live session, so the origin stops counting this
31
+ // one as a discovering session. Called through a closure so the session's death always
32
+ // detaches whichever attachment is current.
33
+ let detach = originWire.attach(conn.discovery);
34
+ let dead = false;
35
+ let discovering = conn.discovery;
36
+ void conn.closed.then(() => {
37
+ dead = true;
38
+ detach();
39
+ });
40
+ void serveRequests(conn, origin);
41
+ if (!conn.discovery) {
42
+ console.warn("relay does not support broadcast discovery; broadcasts resolve on request only.");
43
+ return;
44
+ }
45
+ for (const prefix of originWire.interests()) {
46
+ // Hidden routes are mirrored too; each local reader opts in on its own.
47
+ const announced = conn.announced(Path.Pattern.subtree(prefix), { hidden: true });
48
+ const inserted = new Map();
49
+ // End the stream the moment the session closes rather than waiting for the wire to
50
+ // error it, so the retractions below land promptly.
51
+ void conn.closed.then(() => announced.close());
52
+ void (async () => {
53
+ let failure;
54
+ try {
55
+ for (;;) {
56
+ const event = await announced.next();
57
+ if (!event)
58
+ break;
59
+ if (!originWire.accepts(event.prefix))
60
+ continue;
61
+ if (isActive(event.kind)) {
62
+ const existing = inserted.get(event.prefix);
63
+ if (existing) {
64
+ existing.update(event.route);
65
+ }
66
+ else {
67
+ const handle = originWire.receive(event.prefix, event.route);
68
+ inserted.set(event.prefix, handle);
69
+ void drive(handle, conn);
70
+ }
71
+ }
72
+ else {
73
+ const handle = inserted.get(event.prefix);
74
+ inserted.delete(event.prefix);
75
+ handle?.close();
76
+ }
77
+ }
78
+ }
79
+ catch (err) {
80
+ // The session died mid-stream, or the relay refused or reset the stream. The
81
+ // cleanup below retracts everything this stream fed either way.
82
+ failure = err;
83
+ }
84
+ finally {
85
+ for (const handle of inserted.values())
86
+ handle.close();
87
+ inserted.clear();
88
+ announced.close();
89
+ // Discovery ended while the session lives, and nothing reopens the stream on this
90
+ // connection. Downgrade the attachment rather than leaving the origin claiming a
91
+ // discovery that no longer works: announcement-gated consumers would wait forever
92
+ // on a table this session can no longer fill. Now they fall back to standing
93
+ // requests, which this session still answers.
94
+ if (!dead && discovering) {
95
+ discovering = false;
96
+ console.warn("broadcast discovery failed; broadcasts resolve on request only.", failure);
97
+ detach();
98
+ detach = originWire.attach(false);
99
+ }
100
+ }
101
+ })();
102
+ }
103
+ }
104
+ /**
105
+ * Answer the origin's open requests with blind subscriptions for the session's lifetime.
106
+ *
107
+ * Every session answers, discovery or not: subscribing to an unannounced path is always
108
+ * legal, and a missing broadcast surfaces as a reset on the first track. The first session
109
+ * to answer wins; when this session dies its answers are withdrawn so a later session
110
+ * answers again, which is what makes a request span reconnects.
111
+ *
112
+ * A path the table already routes is left alone. A request resolves to the table's route over
113
+ * any blind answer, so answering one would only park a handle nothing reads.
114
+ */
115
+ async function drive(handle, conn) {
116
+ const session = wireOf(conn);
117
+ try {
118
+ for await (const request of handle.requested()) {
119
+ request.accept(session.consume(request.path));
120
+ }
121
+ }
122
+ catch {
123
+ handle.close();
124
+ }
125
+ }
126
+ async function serveRequests(conn, origin) {
127
+ const table = wireOf(origin);
128
+ const session = wireOf(conn);
129
+ // The withdraws for the answers this session provided, so a dead session only takes
130
+ // back its own. Keyed by path but remembering the slot, because a path outlives its
131
+ // slot: the last handle closing tears the slot down and a new request installs a fresh
132
+ // one, and those two writes coalesce into a single wakeup. Matching on the path alone
133
+ // would read the new slot as already answered and leave it unanswered forever.
134
+ const answered = new Map();
135
+ let dead = false;
136
+ const closed = conn.closed.then(() => {
137
+ dead = true;
138
+ });
139
+ for (;;) {
140
+ const map = table.requests.peek();
141
+ if (!map || dead)
142
+ break;
143
+ for (const [path, slot] of map) {
144
+ if (slot.blind === 0)
145
+ continue;
146
+ if (answered.get(path)?.slot === slot || slot.answer !== undefined)
147
+ continue;
148
+ if (table.routes(path))
149
+ continue;
150
+ const withdraw = table.answer(path, session.consume(path));
151
+ if (withdraw)
152
+ answered.set(path, { slot, withdraw });
153
+ }
154
+ // A withdrawn request already released the answer; just forget our claim on the path.
155
+ // A replaced slot counts as withdrawn: the answer we hold belongs to the slot that
156
+ // went away, not to whatever now occupies the path.
157
+ for (const [path, entry] of [...answered]) {
158
+ if (map.get(path) === entry.slot && entry.slot.blind > 0)
159
+ continue;
160
+ answered.delete(path);
161
+ entry.withdraw();
162
+ }
163
+ // Woken by the table too, not just the requests: a path that stops being routed needs
164
+ // the blind answer this loop skipped while it was.
165
+ await race([table.changed(), closed]);
166
+ }
167
+ // Session gone: withdraw our answers, waking a standby session to provide fresh ones.
168
+ for (const { withdraw } of answered.values()) {
169
+ withdraw();
170
+ }
171
+ answered.clear();
172
+ }
173
+ //# sourceMappingURL=forward.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"forward.js","sourceRoot":"","sources":["../../src/connection/forward.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Feeds a session's announced routes into an origin; the `consume` connect option.\n *\n * @module\n */\nimport { type Dispose, race } from \"@moq/signals\";\nimport { isActive } from \"../announced.ts\";\nimport type { Dynamic, Producer as OriginProducer, RequestSlot } from \"../origin.ts\";\nimport * as Path from \"../path.ts\";\nimport { wireOf } from \"../wire.ts\";\nimport type { Established } from \"./established.ts\";\n\n/**\n * Wire a session into `origin` for the session's lifetime: forward the peer's announced\n * routes into the table, and answer the origin's open requests with blind\n * subscriptions.\n *\n * Each active announcement inserts a route covering the announced prefix, served\n * lazily through this connection, so nothing touches the wire until somebody requests\n * a path under it. A retraction removes the entry, and so does the session dying (the\n * announce stream ends with it), which is what scopes remote routes to the session\n * that announced them. A reconnect wires a fresh session to the same origin and\n * re-populates it.\n *\n * Without discovery there are no announcements to forward, so the table stays empty and\n * requests are the only way through; see the origin's `request`.\n *\n * @internal\n */\nexport function forwardAnnounced(conn: Established, origin: OriginProducer): void {\n\tconst originWire = wireOf(origin);\n\t// Reassigned if discovery dies under a live session, so the origin stops counting this\n\t// one as a discovering session. Called through a closure so the session's death always\n\t// detaches whichever attachment is current.\n\tlet detach = originWire.attach(conn.discovery);\n\n\tlet dead = false;\n\tlet discovering = conn.discovery;\n\tvoid conn.closed.then(() => {\n\t\tdead = true;\n\t\tdetach();\n\t});\n\n\tvoid serveRequests(conn, origin);\n\n\tif (!conn.discovery) {\n\t\tconsole.warn(\"relay does not support broadcast discovery; broadcasts resolve on request only.\");\n\t\treturn;\n\t}\n\n\tfor (const prefix of originWire.interests()) {\n\t\t// Hidden routes are mirrored too; each local reader opts in on its own.\n\t\tconst announced = conn.announced(Path.Pattern.subtree(prefix), { hidden: true });\n\t\tconst inserted = new Map<Path.Valid, Dynamic>();\n\n\t\t// End the stream the moment the session closes rather than waiting for the wire to\n\t\t// error it, so the retractions below land promptly.\n\t\tvoid conn.closed.then(() => announced.close());\n\n\t\tvoid (async () => {\n\t\t\tlet failure: unknown;\n\t\t\ttry {\n\t\t\t\tfor (;;) {\n\t\t\t\t\tconst event = await announced.next();\n\t\t\t\t\tif (!event) break;\n\t\t\t\t\tif (!originWire.accepts(event.prefix)) continue;\n\n\t\t\t\t\tif (isActive(event.kind)) {\n\t\t\t\t\t\tconst existing = inserted.get(event.prefix);\n\t\t\t\t\t\tif (existing) {\n\t\t\t\t\t\t\texisting.update(event.route);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tconst handle = originWire.receive(event.prefix, event.route);\n\t\t\t\t\t\t\tinserted.set(event.prefix, handle);\n\t\t\t\t\t\t\tvoid drive(handle, conn);\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tconst handle = inserted.get(event.prefix);\n\t\t\t\t\t\tinserted.delete(event.prefix);\n\t\t\t\t\t\thandle?.close();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\t// The session died mid-stream, or the relay refused or reset the stream. The\n\t\t\t\t// cleanup below retracts everything this stream fed either way.\n\t\t\t\tfailure = err;\n\t\t\t} finally {\n\t\t\t\tfor (const handle of inserted.values()) handle.close();\n\t\t\t\tinserted.clear();\n\t\t\t\tannounced.close();\n\n\t\t\t\t// Discovery ended while the session lives, and nothing reopens the stream on this\n\t\t\t\t// connection. Downgrade the attachment rather than leaving the origin claiming a\n\t\t\t\t// discovery that no longer works: announcement-gated consumers would wait forever\n\t\t\t\t// on a table this session can no longer fill. Now they fall back to standing\n\t\t\t\t// requests, which this session still answers.\n\t\t\t\tif (!dead && discovering) {\n\t\t\t\t\tdiscovering = false;\n\t\t\t\t\tconsole.warn(\"broadcast discovery failed; broadcasts resolve on request only.\", failure);\n\t\t\t\t\tdetach();\n\t\t\t\t\tdetach = originWire.attach(false);\n\t\t\t\t}\n\t\t\t}\n\t\t})();\n\t}\n}\n\n/**\n * Answer the origin's open requests with blind subscriptions for the session's lifetime.\n *\n * Every session answers, discovery or not: subscribing to an unannounced path is always\n * legal, and a missing broadcast surfaces as a reset on the first track. The first session\n * to answer wins; when this session dies its answers are withdrawn so a later session\n * answers again, which is what makes a request span reconnects.\n *\n * A path the table already routes is left alone. A request resolves to the table's route over\n * any blind answer, so answering one would only park a handle nothing reads.\n */\nasync function drive(handle: Dynamic, conn: Established): Promise<void> {\n\tconst session = wireOf(conn);\n\ttry {\n\t\tfor await (const request of handle.requested()) {\n\t\t\trequest.accept(session.consume(request.path));\n\t\t}\n\t} catch {\n\t\thandle.close();\n\t}\n}\n\nasync function serveRequests(conn: Established, origin: OriginProducer): Promise<void> {\n\tconst table = wireOf(origin);\n\tconst session = wireOf(conn);\n\t// The withdraws for the answers this session provided, so a dead session only takes\n\t// back its own. Keyed by path but remembering the slot, because a path outlives its\n\t// slot: the last handle closing tears the slot down and a new request installs a fresh\n\t// one, and those two writes coalesce into a single wakeup. Matching on the path alone\n\t// would read the new slot as already answered and leave it unanswered forever.\n\tconst answered = new Map<Path.Valid, { slot: RequestSlot; withdraw: Dispose }>();\n\n\tlet dead = false;\n\tconst closed = conn.closed.then(() => {\n\t\tdead = true;\n\t});\n\n\tfor (;;) {\n\t\tconst map = table.requests.peek();\n\t\tif (!map || dead) break;\n\n\t\tfor (const [path, slot] of map) {\n\t\t\tif (slot.blind === 0) continue;\n\t\t\tif (answered.get(path)?.slot === slot || slot.answer !== undefined) continue;\n\t\t\tif (table.routes(path)) continue;\n\t\t\tconst withdraw = table.answer(path, session.consume(path));\n\t\t\tif (withdraw) answered.set(path, { slot, withdraw });\n\t\t}\n\n\t\t// A withdrawn request already released the answer; just forget our claim on the path.\n\t\t// A replaced slot counts as withdrawn: the answer we hold belongs to the slot that\n\t\t// went away, not to whatever now occupies the path.\n\t\tfor (const [path, entry] of [...answered]) {\n\t\t\tif (map.get(path) === entry.slot && entry.slot.blind > 0) continue;\n\t\t\tanswered.delete(path);\n\t\t\tentry.withdraw();\n\t\t}\n\n\t\t// Woken by the table too, not just the requests: a path that stops being routed needs\n\t\t// the blind answer this loop skipped while it was.\n\t\tawait race([table.changed(), closed]);\n\t}\n\n\t// Session gone: withdraw our answers, waking a standby session to provide fresh ones.\n\tfor (const { withdraw } of answered.values()) {\n\t\twithdraw();\n\t}\n\tanswered.clear();\n}\n"]}
@@ -16,6 +16,7 @@ import { Stream } from "../stream";
16
16
  export declare function exchangeSetup(transport: WebTransport, version: Ietf.IetfVersion, implementation: string): Promise<{
17
17
  control: Stream;
18
18
  solicit: boolean | undefined;
19
+ hidden: boolean;
19
20
  cluster: Ietf.Cluster.Hops;
20
21
  }>;
21
22
  //# sourceMappingURL=handshake.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"handshake.d.ts","sourceRoot":"","sources":["../../src/connection/handshake.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,kBAAkB,CAAC;AAEzC,OAAO,EAAU,MAAM,EAAU,MAAM,cAAc,CAAC;AAEtD;;;;;;;;;;;;GAYG;AACH,wBAAsB,aAAa,CAClC,SAAS,EAAE,YAAY,EACvB,OAAO,EAAE,IAAI,CAAC,WAAW,EACzB,cAAc,EAAE,MAAM,GACpB,OAAO,CAAC;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,GAAG,SAAS,CAAC;IAAC,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,IAAI,CAAA;CAAE,CAAC,CAuBxF"}
1
+ {"version":3,"file":"handshake.d.ts","sourceRoot":"","sources":["../../src/connection/handshake.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,IAAI,MAAM,kBAAkB,CAAC;AACzC,OAAO,EAAU,MAAM,EAAU,MAAM,cAAc,CAAC;AAEtD;;;;;;;;;;;;GAYG;AACH,wBAAsB,aAAa,CAClC,SAAS,EAAE,YAAY,EACvB,OAAO,EAAE,IAAI,CAAC,WAAW,EACzB,cAAc,EAAE,MAAM,GACpB,OAAO,CAAC;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,GAAG,SAAS,CAAC;IAAC,MAAM,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,IAAI,CAAA;CAAE,CAAC,CAyBzG"}
@@ -1,6 +1,6 @@
1
1
  /* @ts-self-types="./handshake.d.ts" */
2
+ import { randomHop } from "../hop.js";
2
3
  import * as Ietf from "../ietf/index.js";
3
- import { randomOrigin } from "../origin.js";
4
4
  import { Reader, Stream, Writer } from "../stream.js";
5
5
  /**
6
6
  * Draft-17+ SETUP exchange. Each side opens a uni stream, writes its Setup
@@ -20,9 +20,10 @@ export async function exchangeSetup(transport, version, implementation) {
20
20
  const params = new Ietf.SetupOptions();
21
21
  params.setBytes(Ietf.SetupOption.Implementation, encoder.encode(implementation));
22
22
  Ietf.solicitIntoSetup(params);
23
+ Ietf.hiddenIntoSetup(params);
23
24
  // One id per session, like the moq-lite connection: nothing in this process forwards
24
25
  // between sessions, so there is nothing for a shared id to detect.
25
- const self = randomOrigin();
26
+ const self = randomHop();
26
27
  Ietf.Cluster.intoSetup(params, self, version);
27
28
  const setupMsg = new Ietf.Setup({ parameters: params });
28
29
  const [writer, received] = await Promise.all([
@@ -32,6 +33,7 @@ export async function exchangeSetup(transport, version, implementation) {
32
33
  return {
33
34
  control: new Stream({ writer, reader: received.reader }),
34
35
  solicit: received.solicit,
36
+ hidden: received.hidden,
35
37
  cluster: { self, peer: received.cluster },
36
38
  };
37
39
  }
@@ -58,6 +60,7 @@ async function receiveSetup(transport, version) {
58
60
  return {
59
61
  reader,
60
62
  solicit: Ietf.solicitFromSetup(setup.parameters),
63
+ hidden: Ietf.hiddenFromSetup(setup.parameters),
61
64
  cluster: Ietf.Cluster.fromSetup(setup.parameters, version),
62
65
  };
63
66
  }
@@ -1 +1 @@
1
- {"version":3,"file":"handshake.js","sourceRoot":"","sources":["../../src/connection/handshake.ts"],"names":[],"mappings":"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","sourcesContent":["import * as Ietf from \"../ietf/index.ts\";\nimport { type Origin, randomOrigin } from \"../origin.ts\";\nimport { Reader, Stream, Writer } from \"../stream.ts\";\n\n/**\n * Draft-17+ SETUP exchange. Each side opens a uni stream, writes its Setup\n * message, and reads the peer's Setup off an incoming uni stream. The two\n * halves run in parallel and the protocol is symmetric, so both `connect`\n * (client) and `accept` (server) use this same function.\n *\n * Returns the control stream plus what the peer's SETUP declared: whether it requires\n * solicitation, which decides whether we announce namespaces unprompted (see the MoQ Solicit\n * extension), and its Hop ID (see the MoQ Cluster extension). We declare both ourselves on\n * every session: we send SUBSCRIBE_NAMESPACE for each prefix we want, so an unsolicited\n * advertisement can tell us nothing we won't have asked for, and a peer that knows our Hop\n * ID can withhold the advertisements that already flowed through us.\n */\nexport async function exchangeSetup(\n\ttransport: WebTransport,\n\tversion: Ietf.IetfVersion,\n\timplementation: string,\n): Promise<{ control: Stream; solicit: boolean | undefined; cluster: Ietf.Cluster.Hops }> {\n\tconst encoder = new TextEncoder();\n\tconst params = new Ietf.SetupOptions();\n\tparams.setBytes(Ietf.SetupOption.Implementation, encoder.encode(implementation));\n\tIetf.solicitIntoSetup(params);\n\n\t// One id per session, like the moq-lite connection: nothing in this process forwards\n\t// between sessions, so there is nothing for a shared id to detect.\n\tconst self = randomOrigin();\n\tIetf.Cluster.intoSetup(params, self, version);\n\n\tconst setupMsg = new Ietf.Setup({ parameters: params });\n\n\tconst [writer, received] = await Promise.all([\n\t\tsendSetup(transport, version, setupMsg),\n\t\treceiveSetup(transport, version),\n\t]);\n\n\treturn {\n\t\tcontrol: new Stream({ writer, reader: received.reader }),\n\t\tsolicit: received.solicit,\n\t\tcluster: { self, peer: received.cluster },\n\t};\n}\n\nasync function sendSetup(transport: WebTransport, version: Ietf.IetfVersion, setupMsg: Ietf.Setup): Promise<Writer> {\n\t// Via Writer.open for its deadline: a peer can advertise a stream limit of zero and\n\t// never raise it, which would otherwise hang the handshake rather than failing it.\n\tconst writer = await Writer.open(transport, { version });\n\tawait writer.u53(Ietf.Setup.id); // 0x2F00 stream type\n\tawait setupMsg.encode(writer, version);\n\treturn writer;\n}\n\nasync function receiveSetup(\n\ttransport: WebTransport,\n\tversion: Ietf.IetfVersion,\n): Promise<{ reader: Reader; solicit: boolean | undefined; cluster: Origin | undefined }> {\n\tconst uniReader = transport.incomingUnidirectionalStreams.getReader() as ReadableStreamDefaultReader<\n\t\tReadableStream<Uint8Array>\n\t>;\n\tconst next = await uniReader.read();\n\tuniReader.releaseLock();\n\tif (next.done) throw new Error(\"no incoming uni stream for SETUP\");\n\n\tconst reader = new Reader(next.value, undefined, version);\n\n\tconst streamType = await reader.u53();\n\tif (streamType !== Ietf.Setup.id) {\n\t\tthrow new Error(`unexpected stream type on setup uni: 0x${streamType.toString(16)}`);\n\t}\n\tconst setup = await Ietf.Setup.decode(reader, version);\n\n\treturn {\n\t\treader,\n\t\tsolicit: Ietf.solicitFromSetup(setup.parameters),\n\t\tcluster: Ietf.Cluster.fromSetup(setup.parameters, version),\n\t};\n}\n"]}
1
+ {"version":3,"file":"handshake.js","sourceRoot":"","sources":["../../src/connection/handshake.ts"],"names":[],"mappings":"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","sourcesContent":["import { type Hop, randomHop } from \"../hop.ts\";\nimport * as Ietf from \"../ietf/index.ts\";\nimport { Reader, Stream, Writer } from \"../stream.ts\";\n\n/**\n * Draft-17+ SETUP exchange. Each side opens a uni stream, writes its Setup\n * message, and reads the peer's Setup off an incoming uni stream. The two\n * halves run in parallel and the protocol is symmetric, so both `connect`\n * (client) and `accept` (server) use this same function.\n *\n * Returns the control stream plus what the peer's SETUP declared: whether it requires\n * solicitation, which decides whether we announce namespaces unprompted (see the MoQ Solicit\n * extension), and its Hop ID (see the MoQ Cluster extension). We declare both ourselves on\n * every session: we send SUBSCRIBE_NAMESPACE for each prefix we want, so an unsolicited\n * advertisement can tell us nothing we won't have asked for, and a peer that knows our Hop\n * ID can withhold the advertisements that already flowed through us.\n */\nexport async function exchangeSetup(\n\ttransport: WebTransport,\n\tversion: Ietf.IetfVersion,\n\timplementation: string,\n): Promise<{ control: Stream; solicit: boolean | undefined; hidden: boolean; cluster: Ietf.Cluster.Hops }> {\n\tconst encoder = new TextEncoder();\n\tconst params = new Ietf.SetupOptions();\n\tparams.setBytes(Ietf.SetupOption.Implementation, encoder.encode(implementation));\n\tIetf.solicitIntoSetup(params);\n\tIetf.hiddenIntoSetup(params);\n\n\t// One id per session, like the moq-lite connection: nothing in this process forwards\n\t// between sessions, so there is nothing for a shared id to detect.\n\tconst self = randomHop();\n\tIetf.Cluster.intoSetup(params, self, version);\n\n\tconst setupMsg = new Ietf.Setup({ parameters: params });\n\n\tconst [writer, received] = await Promise.all([\n\t\tsendSetup(transport, version, setupMsg),\n\t\treceiveSetup(transport, version),\n\t]);\n\n\treturn {\n\t\tcontrol: new Stream({ writer, reader: received.reader }),\n\t\tsolicit: received.solicit,\n\t\thidden: received.hidden,\n\t\tcluster: { self, peer: received.cluster },\n\t};\n}\n\nasync function sendSetup(transport: WebTransport, version: Ietf.IetfVersion, setupMsg: Ietf.Setup): Promise<Writer> {\n\t// Via Writer.open for its deadline: a peer can advertise a stream limit of zero and\n\t// never raise it, which would otherwise hang the handshake rather than failing it.\n\tconst writer = await Writer.open(transport, { version });\n\tawait writer.u53(Ietf.Setup.id); // 0x2F00 stream type\n\tawait setupMsg.encode(writer, version);\n\treturn writer;\n}\n\nasync function receiveSetup(\n\ttransport: WebTransport,\n\tversion: Ietf.IetfVersion,\n): Promise<{ reader: Reader; solicit: boolean | undefined; hidden: boolean; cluster: Hop | undefined }> {\n\tconst uniReader = transport.incomingUnidirectionalStreams.getReader() as ReadableStreamDefaultReader<\n\t\tReadableStream<Uint8Array>\n\t>;\n\tconst next = await uniReader.read();\n\tuniReader.releaseLock();\n\tif (next.done) throw new Error(\"no incoming uni stream for SETUP\");\n\n\tconst reader = new Reader(next.value, undefined, version);\n\n\tconst streamType = await reader.u53();\n\tif (streamType !== Ietf.Setup.id) {\n\t\tthrow new Error(`unexpected stream type on setup uni: 0x${streamType.toString(16)}`);\n\t}\n\tconst setup = await Ietf.Setup.decode(reader, version);\n\n\treturn {\n\t\treader,\n\t\tsolicit: Ietf.solicitFromSetup(setup.parameters),\n\t\thidden: Ietf.hiddenFromSetup(setup.parameters),\n\t\tcluster: Ietf.Cluster.fromSetup(setup.parameters, version),\n\t};\n}\n"]}
@@ -1,13 +1,13 @@
1
1
  /**
2
- * Connection helpers: connect to or accept a MoQ session and reconnect on failure.
2
+ * A reconnecting, shareable handle on a MoQ session, plus one-shot connect/accept.
3
3
  *
4
4
  * @module
5
5
  */
6
- export * from "./accept";
6
+ export { type AcceptProps, accept } from "./accept";
7
7
  export { isWebTransportSupported } from "./browser";
8
- export * from "./connect";
9
- export * from "./established";
10
- export * from "./reload";
8
+ export { type CertificateHash, type ConnectProps, certificateHash, connect, type WebSocketProps, type WebTransportProps, } from "./connect";
9
+ export type { Established } from "./established";
10
+ export { Connection, type ConnectionProps } from "./pool";
11
11
  export type { Probe, Stats } from "./stats";
12
12
  export type { Transport } from "./transport";
13
13
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/connection/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,cAAc,aAAa,CAAC;AAC5B,OAAO,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAC;AACvD,cAAc,cAAc,CAAC;AAC7B,cAAc,kBAAkB,CAAC;AACjC,cAAc,aAAa,CAAC;AAC5B,YAAY,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAC/C,YAAY,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/connection/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACvD,OAAO,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAC;AACvD,OAAO,EACN,KAAK,eAAe,EACpB,KAAK,YAAY,EACjB,eAAe,EACf,OAAO,EACP,KAAK,cAAc,EACnB,KAAK,iBAAiB,GACtB,MAAM,cAAc,CAAC;AACtB,YAAY,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,UAAU,EAAE,KAAK,eAAe,EAAE,MAAM,WAAW,CAAC;AAC7D,YAAY,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAC/C,YAAY,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC"}
@@ -1,12 +1,11 @@
1
1
  /* @ts-self-types="./index.d.ts" */
2
2
  /**
3
- * Connection helpers: connect to or accept a MoQ session and reconnect on failure.
3
+ * A reconnecting, shareable handle on a MoQ session, plus one-shot connect/accept.
4
4
  *
5
5
  * @module
6
6
  */
7
- export * from "./accept.js";
7
+ export { accept } from "./accept.js";
8
8
  export { isWebTransportSupported } from "./browser.js";
9
- export * from "./connect.js";
10
- export * from "./established.js";
11
- export * from "./reload.js";
9
+ export { certificateHash, connect, } from "./connect.js";
10
+ export { Connection } from "./pool.js";
12
11
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/connection/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,cAAc,aAAa,CAAC;AAC5B,OAAO,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAC;AACvD,cAAc,cAAc,CAAC;AAC7B,cAAc,kBAAkB,CAAC;AACjC,cAAc,aAAa,CAAC","sourcesContent":["/**\n * Connection helpers: connect to or accept a MoQ session and reconnect on failure.\n *\n * @module\n */\nexport * from \"./accept.ts\";\nexport { isWebTransportSupported } from \"./browser.ts\";\nexport * from \"./connect.ts\";\nexport * from \"./established.ts\";\nexport * from \"./reload.ts\";\nexport type { Probe, Stats } from \"./stats.ts\";\nexport type { Transport } from \"./transport.ts\";\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/connection/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAoB,MAAM,EAAE,MAAM,aAAa,CAAC;AACvD,OAAO,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAC;AACvD,OAAO,EAGN,eAAe,EACf,OAAO,GAGP,MAAM,cAAc,CAAC;AAEtB,OAAO,EAAE,UAAU,EAAwB,MAAM,WAAW,CAAC","sourcesContent":["/**\n * A reconnecting, shareable handle on a MoQ session, plus one-shot connect/accept.\n *\n * @module\n */\nexport { type AcceptProps, accept } from \"./accept.ts\";\nexport { isWebTransportSupported } from \"./browser.ts\";\nexport {\n\ttype CertificateHash,\n\ttype ConnectProps,\n\tcertificateHash,\n\tconnect,\n\ttype WebSocketProps,\n\ttype WebTransportProps,\n} from \"./connect.ts\";\nexport type { Established } from \"./established.ts\";\nexport { Connection, type ConnectionProps } from \"./pool.ts\";\nexport type { Probe, Stats } from \"./stats.ts\";\nexport type { Transport } from \"./transport.ts\";\n"]}