@norskvideo/moq-net 0.1.2 → 0.1.4

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 (310) hide show
  1. package/README.md +1 -0
  2. package/announced.d.ts +111 -21
  3. package/announced.d.ts.map +1 -1
  4. package/announced.js +213 -40
  5. package/announced.js.map +1 -1
  6. package/broadcast.d.ts +80 -25
  7. package/broadcast.d.ts.map +1 -1
  8. package/broadcast.js +270 -49
  9. package/broadcast.js.map +1 -1
  10. package/connection/accept.d.ts +6 -0
  11. package/connection/accept.d.ts.map +1 -1
  12. package/connection/accept.js +42 -13
  13. package/connection/accept.js.map +1 -1
  14. package/connection/browser.d.ts +5 -0
  15. package/connection/browser.d.ts.map +1 -0
  16. package/connection/browser.js +31 -0
  17. package/connection/browser.js.map +1 -0
  18. package/connection/connect.d.ts +43 -1
  19. package/connection/connect.d.ts.map +1 -1
  20. package/connection/connect.js +118 -123
  21. package/connection/connect.js.map +1 -1
  22. package/connection/established.d.ts +43 -16
  23. package/connection/established.d.ts.map +1 -1
  24. package/connection/established.js.map +1 -1
  25. package/connection/handshake.d.ts +12 -1
  26. package/connection/handshake.d.ts.map +1 -1
  27. package/connection/handshake.js +30 -14
  28. package/connection/handshake.js.map +1 -1
  29. package/connection/index.d.ts +8 -0
  30. package/connection/index.d.ts.map +1 -1
  31. package/connection/index.js +6 -0
  32. package/connection/index.js.map +1 -1
  33. package/connection/reload.d.ts +66 -9
  34. package/connection/reload.d.ts.map +1 -1
  35. package/connection/reload.js +192 -66
  36. package/connection/reload.js.map +1 -1
  37. package/connection/stats.d.ts +92 -0
  38. package/connection/stats.d.ts.map +1 -0
  39. package/connection/stats.js +35 -0
  40. package/connection/stats.js.map +1 -0
  41. package/connection/transport.d.ts +10 -0
  42. package/connection/transport.d.ts.map +1 -0
  43. package/connection/transport.js +12 -0
  44. package/connection/transport.js.map +1 -0
  45. package/consume.d.ts +44 -0
  46. package/consume.d.ts.map +1 -0
  47. package/consume.js +60 -0
  48. package/consume.js.map +1 -0
  49. package/datagram.d.ts +23 -0
  50. package/datagram.d.ts.map +1 -0
  51. package/datagram.js +3 -0
  52. package/datagram.js.map +1 -0
  53. package/error.d.ts +76 -0
  54. package/error.d.ts.map +1 -0
  55. package/error.js +107 -0
  56. package/error.js.map +1 -0
  57. package/group.d.ts +143 -38
  58. package/group.d.ts.map +1 -1
  59. package/group.js +270 -68
  60. package/group.js.map +1 -1
  61. package/ietf/adapter.d.ts +2 -2
  62. package/ietf/adapter.d.ts.map +1 -1
  63. package/ietf/adapter.js +20 -10
  64. package/ietf/adapter.js.map +1 -1
  65. package/ietf/aliases.d.ts +73 -5
  66. package/ietf/aliases.d.ts.map +1 -1
  67. package/ietf/aliases.js +121 -14
  68. package/ietf/aliases.js.map +1 -1
  69. package/ietf/cluster.d.ts +141 -0
  70. package/ietf/cluster.d.ts.map +1 -0
  71. package/ietf/cluster.js +204 -0
  72. package/ietf/cluster.js.map +1 -0
  73. package/ietf/connection.d.ts +39 -6
  74. package/ietf/connection.d.ts.map +1 -1
  75. package/ietf/connection.js +73 -12
  76. package/ietf/connection.js.map +1 -1
  77. package/ietf/fetch.d.ts +17 -0
  78. package/ietf/fetch.d.ts.map +1 -1
  79. package/ietf/fetch.js +21 -0
  80. package/ietf/fetch.js.map +1 -1
  81. package/ietf/filter.d.ts +87 -0
  82. package/ietf/filter.d.ts.map +1 -0
  83. package/ietf/filter.js +292 -0
  84. package/ietf/filter.js.map +1 -0
  85. package/ietf/index.d.ts +2 -0
  86. package/ietf/index.d.ts.map +1 -1
  87. package/ietf/index.js +3 -0
  88. package/ietf/index.js.map +1 -1
  89. package/ietf/namespace.d.ts +6 -0
  90. package/ietf/namespace.d.ts.map +1 -1
  91. package/ietf/namespace.js +27 -2
  92. package/ietf/namespace.js.map +1 -1
  93. package/ietf/object.d.ts +54 -6
  94. package/ietf/object.d.ts.map +1 -1
  95. package/ietf/object.js +178 -25
  96. package/ietf/object.js.map +1 -1
  97. package/ietf/parameters.d.ts +35 -10
  98. package/ietf/parameters.d.ts.map +1 -1
  99. package/ietf/parameters.js +236 -45
  100. package/ietf/parameters.js.map +1 -1
  101. package/ietf/priority.d.ts +5 -0
  102. package/ietf/priority.d.ts.map +1 -0
  103. package/ietf/priority.js +10 -0
  104. package/ietf/priority.js.map +1 -0
  105. package/ietf/properties.d.ts +13 -2
  106. package/ietf/properties.d.ts.map +1 -1
  107. package/ietf/properties.js +65 -8
  108. package/ietf/properties.js.map +1 -1
  109. package/ietf/publish.d.ts.map +1 -1
  110. package/ietf/publish.js +13 -3
  111. package/ietf/publish.js.map +1 -1
  112. package/ietf/publish_namespace.d.ts +16 -2
  113. package/ietf/publish_namespace.d.ts.map +1 -1
  114. package/ietf/publish_namespace.js +25 -6
  115. package/ietf/publish_namespace.js.map +1 -1
  116. package/ietf/publisher.d.ts +40 -7
  117. package/ietf/publisher.d.ts.map +1 -1
  118. package/ietf/publisher.js +751 -134
  119. package/ietf/publisher.js.map +1 -1
  120. package/ietf/request.js +1 -1
  121. package/ietf/request.js.map +1 -1
  122. package/ietf/solicit.d.ts +41 -0
  123. package/ietf/solicit.d.ts.map +1 -0
  124. package/ietf/solicit.js +47 -0
  125. package/ietf/solicit.js.map +1 -0
  126. package/ietf/subscribe.d.ts +41 -2
  127. package/ietf/subscribe.d.ts.map +1 -1
  128. package/ietf/subscribe.js +103 -22
  129. package/ietf/subscribe.js.map +1 -1
  130. package/ietf/subscribe_namespace.d.ts +21 -7
  131. package/ietf/subscribe_namespace.d.ts.map +1 -1
  132. package/ietf/subscribe_namespace.js +31 -14
  133. package/ietf/subscribe_namespace.js.map +1 -1
  134. package/ietf/subscriber.d.ts +20 -7
  135. package/ietf/subscriber.d.ts.map +1 -1
  136. package/ietf/subscriber.js +512 -142
  137. package/ietf/subscriber.js.map +1 -1
  138. package/ietf/version.d.ts +7 -1
  139. package/ietf/version.d.ts.map +1 -1
  140. package/ietf/version.js +7 -0
  141. package/ietf/version.js.map +1 -1
  142. package/index.d.ts +10 -5
  143. package/index.d.ts.map +1 -1
  144. package/index.js +10 -5
  145. package/index.js.map +1 -1
  146. package/internal.d.ts +29 -0
  147. package/internal.d.ts.map +1 -0
  148. package/internal.js +8 -0
  149. package/internal.js.map +1 -0
  150. package/lite/announce.d.ts +62 -15
  151. package/lite/announce.d.ts.map +1 -1
  152. package/lite/announce.js +230 -94
  153. package/lite/announce.js.map +1 -1
  154. package/lite/connection.d.ts +69 -20
  155. package/lite/connection.d.ts.map +1 -1
  156. package/lite/connection.js +128 -81
  157. package/lite/connection.js.map +1 -1
  158. package/lite/datagram.d.ts +23 -0
  159. package/lite/datagram.d.ts.map +1 -0
  160. package/lite/datagram.js +57 -0
  161. package/lite/datagram.js.map +1 -0
  162. package/lite/datagram_stream.d.ts +8 -0
  163. package/lite/datagram_stream.d.ts.map +1 -0
  164. package/lite/datagram_stream.js +44 -0
  165. package/lite/datagram_stream.js.map +1 -0
  166. package/lite/fetch.d.ts.map +1 -1
  167. package/lite/fetch.js +2 -2
  168. package/lite/fetch.js.map +1 -1
  169. package/lite/index.d.ts +3 -0
  170. package/lite/index.d.ts.map +1 -1
  171. package/lite/index.js +3 -0
  172. package/lite/index.js.map +1 -1
  173. package/lite/priority.d.ts +67 -0
  174. package/lite/priority.d.ts.map +1 -0
  175. package/lite/priority.js +114 -0
  176. package/lite/priority.js.map +1 -0
  177. package/lite/probe.d.ts +18 -2
  178. package/lite/probe.d.ts.map +1 -1
  179. package/lite/probe.js +24 -22
  180. package/lite/probe.js.map +1 -1
  181. package/lite/publisher.d.ts +14 -7
  182. package/lite/publisher.d.ts.map +1 -1
  183. package/lite/publisher.js +406 -84
  184. package/lite/publisher.js.map +1 -1
  185. package/lite/setup.d.ts +83 -6
  186. package/lite/setup.d.ts.map +1 -1
  187. package/lite/setup.js +203 -31
  188. package/lite/setup.js.map +1 -1
  189. package/lite/stream.d.ts +12 -3
  190. package/lite/stream.d.ts.map +1 -1
  191. package/lite/stream.js +7 -4
  192. package/lite/stream.js.map +1 -1
  193. package/lite/subscribe.d.ts +37 -23
  194. package/lite/subscribe.d.ts.map +1 -1
  195. package/lite/subscribe.js +70 -55
  196. package/lite/subscribe.js.map +1 -1
  197. package/lite/subscriber.d.ts +29 -23
  198. package/lite/subscriber.d.ts.map +1 -1
  199. package/lite/subscriber.js +689 -112
  200. package/lite/subscriber.js.map +1 -1
  201. package/lite/track.d.ts +25 -13
  202. package/lite/track.d.ts.map +1 -1
  203. package/lite/track.js +60 -35
  204. package/lite/track.js.map +1 -1
  205. package/lite/version.d.ts +39 -4
  206. package/lite/version.d.ts.map +1 -1
  207. package/lite/version.js +139 -17
  208. package/lite/version.js.map +1 -1
  209. package/mock.d.ts +53 -3
  210. package/mock.d.ts.map +1 -1
  211. package/mock.js +110 -21
  212. package/mock.js.map +1 -1
  213. package/{lite/origin.d.ts → origin.d.ts} +25 -1
  214. package/origin.d.ts.map +1 -0
  215. package/{lite/origin.js → origin.js} +25 -1
  216. package/origin.js.map +1 -0
  217. package/package.json +6 -4
  218. package/path.d.ts +67 -0
  219. package/path.d.ts.map +1 -1
  220. package/path.js +128 -0
  221. package/path.js.map +1 -1
  222. package/stream.d.ts +94 -4
  223. package/stream.d.ts.map +1 -1
  224. package/stream.js +128 -17
  225. package/stream.js.map +1 -1
  226. package/time.d.ts +109 -86
  227. package/time.d.ts.map +1 -1
  228. package/time.js +80 -30
  229. package/time.js.map +1 -1
  230. package/track.d.ts +298 -47
  231. package/track.d.ts.map +1 -1
  232. package/track.js +721 -109
  233. package/track.js.map +1 -1
  234. package/util/timeout.d.ts +5 -0
  235. package/util/timeout.d.ts.map +1 -0
  236. package/util/timeout.js +18 -0
  237. package/util/timeout.js.map +1 -0
  238. package/util/utf8.d.ts +3 -0
  239. package/util/utf8.d.ts.map +1 -0
  240. package/util/utf8.js +7 -0
  241. package/util/utf8.js.map +1 -0
  242. package/varint.d.ts +14 -3
  243. package/varint.d.ts.map +1 -1
  244. package/varint.js +23 -12
  245. package/varint.js.map +1 -1
  246. package/zod.d.ts +5 -5
  247. package/zod.d.ts.map +1 -1
  248. package/zod.js.map +1 -1
  249. package/bandwidth.d.ts +0 -11
  250. package/bandwidth.d.ts.map +0 -1
  251. package/bandwidth.js +0 -7
  252. package/bandwidth.js.map +0 -1
  253. package/connection/cert.test.d.ts +0 -2
  254. package/connection/cert.test.d.ts.map +0 -1
  255. package/connection/cert.test.js +0 -26
  256. package/connection/cert.test.js.map +0 -1
  257. package/connection/reload.test.d.ts +0 -2
  258. package/connection/reload.test.d.ts.map +0 -1
  259. package/connection/reload.test.js +0 -39
  260. package/connection/reload.test.js.map +0 -1
  261. package/group.test.d.ts +0 -2
  262. package/group.test.d.ts.map +0 -1
  263. package/group.test.js +0 -66
  264. package/group.test.js.map +0 -1
  265. package/ietf/aliases.test.d.ts +0 -2
  266. package/ietf/aliases.test.d.ts.map +0 -1
  267. package/ietf/aliases.test.js +0 -30
  268. package/ietf/aliases.test.js.map +0 -1
  269. package/ietf/ietf.test.d.ts +0 -2
  270. package/ietf/ietf.test.d.ts.map +0 -1
  271. package/ietf/ietf.test.js +0 -873
  272. package/ietf/ietf.test.js.map +0 -1
  273. package/integration.test.d.ts +0 -2
  274. package/integration.test.d.ts.map +0 -1
  275. package/integration.test.js +0 -90
  276. package/integration.test.js.map +0 -1
  277. package/lite/origin.d.ts.map +0 -1
  278. package/lite/origin.js.map +0 -1
  279. package/lite/subscriber.test.d.ts +0 -2
  280. package/lite/subscriber.test.d.ts.map +0 -1
  281. package/lite/subscriber.test.js +0 -30
  282. package/lite/subscriber.test.js.map +0 -1
  283. package/lite/track.test.d.ts +0 -2
  284. package/lite/track.test.d.ts.map +0 -1
  285. package/lite/track.test.js +0 -53
  286. package/lite/track.test.js.map +0 -1
  287. package/path.test.d.ts +0 -2
  288. package/path.test.d.ts.map +0 -1
  289. package/path.test.js +0 -169
  290. package/path.test.js.map +0 -1
  291. package/stream.test.d.ts +0 -2
  292. package/stream.test.d.ts.map +0 -1
  293. package/stream.test.js +0 -210
  294. package/stream.test.js.map +0 -1
  295. package/track.test.d.ts +0 -2
  296. package/track.test.d.ts.map +0 -1
  297. package/track.test.js +0 -56
  298. package/track.test.js.map +0 -1
  299. package/util/error.d.ts +0 -3
  300. package/util/error.d.ts.map +0 -1
  301. package/util/error.js +0 -9
  302. package/util/error.js.map +0 -1
  303. package/util/index.d.ts +0 -2
  304. package/util/index.d.ts.map +0 -1
  305. package/util/index.js +0 -3
  306. package/util/index.js.map +0 -1
  307. package/varint.test.d.ts +0 -2
  308. package/varint.test.d.ts.map +0 -1
  309. package/varint.test.js +0 -106
  310. package/varint.test.js.map +0 -1
package/lite/version.js CHANGED
@@ -4,10 +4,138 @@ export const Version = {
4
4
  DRAFT_02: 0xff0dad02,
5
5
  DRAFT_03: 0xff0dad03,
6
6
  DRAFT_04: 0xff0dad04,
7
- /// Work-in-progress placeholder for lite-05. Not advertised as a
8
- /// WebTransport subprotocol; callers must opt in explicitly.
9
- DRAFT_05_WIP: 0xff0dad05,
7
+ DRAFT_05: 0xff0dad05,
8
+ /// Work-in-progress lite-06, advertised as the preferred WebTransport subprotocol.
9
+ /// Adds announce ids: each active ANNOUNCE_BROADCAST implicitly assigns the next
10
+ /// ordinal, and ended/restart reference that id instead of repeating the path.
11
+ DRAFT_06: 0xff0dad06,
10
12
  };
13
+ /**
14
+ * Whether the PROBE message carries the RTT field.
15
+ *
16
+ * Added in lite-04. Lite-03 carries the bitrate alone, so a report with only an RTT to
17
+ * give says nothing there and must not be sent.
18
+ */
19
+ export function hasProbeRtt(version) {
20
+ // Explicitly list older versions so future versions default to carrying RTT.
21
+ switch (version) {
22
+ case Version.DRAFT_01:
23
+ case Version.DRAFT_02:
24
+ case Version.DRAFT_03:
25
+ return false;
26
+ default:
27
+ return true;
28
+ }
29
+ }
30
+ /// Whether the session opens a unidirectional Setup Stream carrying a single SETUP message
31
+ /// (capabilities + optional Path). Added in lite-05; older drafts have no Setup Stream.
32
+ export function hasSetupStream(version) {
33
+ // Explicitly list older versions so future versions default to having the stream.
34
+ switch (version) {
35
+ case Version.DRAFT_01:
36
+ case Version.DRAFT_02:
37
+ case Version.DRAFT_03:
38
+ case Version.DRAFT_04:
39
+ return false;
40
+ default:
41
+ return true;
42
+ }
43
+ }
44
+ /// Whether the session may deliver groups over unreliable QUIC datagrams (lite-05 §6.4).
45
+ /// A datagram carries one single-frame group's `subscribe | sequence | timestamp | payload` and is
46
+ /// routed over the existing subscription. Added in lite-05; older versions never send/accept them.
47
+ export function hasDatagrams(version) {
48
+ // Explicitly list older versions so future versions default to having datagrams.
49
+ switch (version) {
50
+ case Version.DRAFT_01:
51
+ case Version.DRAFT_02:
52
+ case Version.DRAFT_03:
53
+ case Version.DRAFT_04:
54
+ return false;
55
+ default:
56
+ return true;
57
+ }
58
+ }
59
+ /** Whether announce streams begin with ANNOUNCE_OK and omit the sender's origin from each hop chain. */
60
+ export function hasAnnounceOk(version) {
61
+ // Explicitly list older versions so future versions keep the lite-05+ announce behavior.
62
+ switch (version) {
63
+ case Version.DRAFT_01:
64
+ case Version.DRAFT_02:
65
+ case Version.DRAFT_03:
66
+ case Version.DRAFT_04:
67
+ return false;
68
+ default:
69
+ return true;
70
+ }
71
+ }
72
+ /** Whether the version can replace an advertisement in place rather than retracting and
73
+ * re-announcing it. Added in lite-05 as a duplicate ANNOUNCE; lite-06 gave it a message of
74
+ * its own (ANNOUNCE_UPDATE) and made the duplicate a violation. */
75
+ export function restartSupported(version) {
76
+ // Explicitly list older versions so future versions default to supported.
77
+ switch (version) {
78
+ case Version.DRAFT_01:
79
+ case Version.DRAFT_02:
80
+ case Version.DRAFT_03:
81
+ case Version.DRAFT_04:
82
+ return false;
83
+ default:
84
+ return true;
85
+ }
86
+ }
87
+ /** Whether announcements carry implicit announce ids: each `active` assigns the next
88
+ * per-stream ordinal, and `ended`/`restart` reference that id instead of repeating the
89
+ * path. Added in lite-06. */
90
+ export function hasAnnounceId(version) {
91
+ // Explicitly list older versions so future versions keep the lite-06+ announce behavior.
92
+ switch (version) {
93
+ case Version.DRAFT_01:
94
+ case Version.DRAFT_02:
95
+ case Version.DRAFT_03:
96
+ case Version.DRAFT_04:
97
+ case Version.DRAFT_05:
98
+ return false;
99
+ default:
100
+ return true;
101
+ }
102
+ }
103
+ /** Whether ANNOUNCE_REQUEST carries the Exclude Hop field: the subscriber's own
104
+ * origin id, which the publisher uses to skip announces whose hop chain already
105
+ * passed through the subscriber. Present in lite-04 and lite-05 only.
106
+ *
107
+ * The receiver's own reflected-announce check drops those announces anyway (and
108
+ * catches loops of any length, not just the two-hop case), so lite-06 drops the
109
+ * field and keeps the check.
110
+ *
111
+ * Unlike the gates above, this lists the versions that *have* the field: it was
112
+ * removed rather than added, so future versions default to not carrying it. */
113
+ export function hasExcludeHop(version) {
114
+ switch (version) {
115
+ case Version.DRAFT_04:
116
+ case Version.DRAFT_05:
117
+ return true;
118
+ default:
119
+ return false;
120
+ }
121
+ }
122
+ /** Whether announcements carry a route cost varint alongside the hop chain: the
123
+ * marginal cost of pulling the broadcast via this route, accumulated per link.
124
+ * Added in lite-06. Older versions carry nothing, so a received route stays at
125
+ * zero and routing falls back to the hop-count tie-break. */
126
+ export function hasRouteCost(version) {
127
+ // Explicitly list older versions so future versions keep the lite-06+ behavior.
128
+ switch (version) {
129
+ case Version.DRAFT_01:
130
+ case Version.DRAFT_02:
131
+ case Version.DRAFT_03:
132
+ case Version.DRAFT_04:
133
+ case Version.DRAFT_05:
134
+ return false;
135
+ default:
136
+ return true;
137
+ }
138
+ }
11
139
  /// The WebTransport subprotocol identifier for moq-lite.
12
140
  /// Version negotiation still happens via SETUP when this is used.
13
141
  export const ALPN = "moql";
@@ -15,27 +143,21 @@ export const ALPN = "moql";
15
143
  export const ALPN_03 = "moq-lite-03";
16
144
  /// The ALPN string for Draft04, which uses ALPN-based version negotiation.
17
145
  export const ALPN_04 = "moq-lite-04";
18
- /// The ALPN string for the work-in-progress Draft05. Intentionally not
19
- /// included in the default WebTransport `protocols` list.
20
- export const ALPN_05_WIP = "moq-lite-05-wip";
146
+ /// The ALPN string for Draft05, which uses ALPN-based version negotiation.
147
+ export const ALPN_05 = "moq-lite-05";
148
+ /// The ALPN string for the work-in-progress Draft06. It is NOT in the default
149
+ /// WebTransport `protocols` list, so lite-06 is never advertised or negotiated by
150
+ /// default; a peer only reaches it when both sides explicitly offer this ALPN.
151
+ export const ALPN_06_WIP = "moq-lite-06-wip";
21
152
  const VERSION_NAMES = {
22
153
  [Version.DRAFT_01]: "moq-lite-01",
23
154
  [Version.DRAFT_02]: "moq-lite-02",
24
155
  [Version.DRAFT_03]: "moq-lite-03",
25
156
  [Version.DRAFT_04]: "moq-lite-04",
26
- [Version.DRAFT_05_WIP]: "moq-lite-05-wip",
157
+ [Version.DRAFT_05]: "moq-lite-05",
158
+ [Version.DRAFT_06]: "moq-lite-06-wip",
27
159
  };
28
160
  export function versionName(v) {
29
161
  return VERSION_NAMES[v] ?? `unknown(0x${v.toString(16)})`;
30
162
  }
31
- /// Whether this version uses a unidirectional Setup stream (moq-lite-05+).
32
- export function hasSetupStream(v) {
33
- return v === Version.DRAFT_05_WIP;
34
- }
35
- /// Whether this version uses the moq-lite-05 framing bundle: the Track stream
36
- /// (TRACK/TRACK_INFO), a SUBSCRIBE_OK trimmed to the resolved start group plus a
37
- /// distinct SUBSCRIBE_END, and a per-frame timestamp delta.
38
- export function hasTrackStream(v) {
39
- return v === Version.DRAFT_05_WIP;
40
- }
41
163
  //# sourceMappingURL=version.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"version.js","sourceRoot":"","sources":["../../src/lite/version.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,OAAO,GAAG;IACtB,QAAQ,EAAE,UAAU;IACpB,QAAQ,EAAE,UAAU;IACpB,QAAQ,EAAE,UAAU;IACpB,QAAQ,EAAE,UAAU;IACpB,iEAAiE;IACjE,6DAA6D;IAC7D,YAAY,EAAE,UAAU;CACf,CAAC;AAIX,yDAAyD;AACzD,kEAAkE;AAClE,MAAM,CAAC,MAAM,IAAI,GAAG,MAAM,CAAC;AAE3B,2EAA2E;AAC3E,MAAM,CAAC,MAAM,OAAO,GAAG,aAAa,CAAC;AAErC,2EAA2E;AAC3E,MAAM,CAAC,MAAM,OAAO,GAAG,aAAa,CAAC;AAErC,uEAAuE;AACvE,0DAA0D;AAC1D,MAAM,CAAC,MAAM,WAAW,GAAG,iBAAiB,CAAC;AAE7C,MAAM,aAAa,GAA2B;IAC7C,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,aAAa;IACjC,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,aAAa;IACjC,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,aAAa;IACjC,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,aAAa;IACjC,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE,iBAAiB;CACzC,CAAC;AAEF,MAAM,UAAU,WAAW,CAAC,CAAU;IACrC,OAAO,aAAa,CAAC,CAAC,CAAC,IAAI,aAAa,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC;AAC3D,CAAC;AAED,2EAA2E;AAC3E,MAAM,UAAU,cAAc,CAAC,CAAU;IACxC,OAAO,CAAC,KAAK,OAAO,CAAC,YAAY,CAAC;AACnC,CAAC;AAED,8EAA8E;AAC9E,iFAAiF;AACjF,4DAA4D;AAC5D,MAAM,UAAU,cAAc,CAAC,CAAU;IACxC,OAAO,CAAC,KAAK,OAAO,CAAC,YAAY,CAAC;AACnC,CAAC","sourcesContent":["export const Version = {\n\tDRAFT_01: 0xff0dad01,\n\tDRAFT_02: 0xff0dad02,\n\tDRAFT_03: 0xff0dad03,\n\tDRAFT_04: 0xff0dad04,\n\t/// Work-in-progress placeholder for lite-05. Not advertised as a\n\t/// WebTransport subprotocol; callers must opt in explicitly.\n\tDRAFT_05_WIP: 0xff0dad05,\n} as const;\n\nexport type Version = (typeof Version)[keyof typeof Version];\n\n/// The WebTransport subprotocol identifier for moq-lite.\n/// Version negotiation still happens via SETUP when this is used.\nexport const ALPN = \"moql\";\n\n/// The ALPN string for Draft03, which uses ALPN-based version negotiation.\nexport const ALPN_03 = \"moq-lite-03\";\n\n/// The ALPN string for Draft04, which uses ALPN-based version negotiation.\nexport const ALPN_04 = \"moq-lite-04\";\n\n/// The ALPN string for the work-in-progress Draft05. Intentionally not\n/// included in the default WebTransport `protocols` list.\nexport const ALPN_05_WIP = \"moq-lite-05-wip\";\n\nconst VERSION_NAMES: Record<number, string> = {\n\t[Version.DRAFT_01]: \"moq-lite-01\",\n\t[Version.DRAFT_02]: \"moq-lite-02\",\n\t[Version.DRAFT_03]: \"moq-lite-03\",\n\t[Version.DRAFT_04]: \"moq-lite-04\",\n\t[Version.DRAFT_05_WIP]: \"moq-lite-05-wip\",\n};\n\nexport function versionName(v: Version): string {\n\treturn VERSION_NAMES[v] ?? `unknown(0x${v.toString(16)})`;\n}\n\n/// Whether this version uses a unidirectional Setup stream (moq-lite-05+).\nexport function hasSetupStream(v: Version): boolean {\n\treturn v === Version.DRAFT_05_WIP;\n}\n\n/// Whether this version uses the moq-lite-05 framing bundle: the Track stream\n/// (TRACK/TRACK_INFO), a SUBSCRIBE_OK trimmed to the resolved start group plus a\n/// distinct SUBSCRIBE_END, and a per-frame timestamp delta.\nexport function hasTrackStream(v: Version): boolean {\n\treturn v === Version.DRAFT_05_WIP;\n}\n"]}
1
+ {"version":3,"file":"version.js","sourceRoot":"","sources":["../../src/lite/version.ts"],"names":[],"mappings":"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","sourcesContent":["export const Version = {\n\tDRAFT_01: 0xff0dad01,\n\tDRAFT_02: 0xff0dad02,\n\tDRAFT_03: 0xff0dad03,\n\tDRAFT_04: 0xff0dad04,\n\tDRAFT_05: 0xff0dad05,\n\t/// Work-in-progress lite-06, advertised as the preferred WebTransport subprotocol.\n\t/// Adds announce ids: each active ANNOUNCE_BROADCAST implicitly assigns the next\n\t/// ordinal, and ended/restart reference that id instead of repeating the path.\n\tDRAFT_06: 0xff0dad06,\n} as const;\n\nexport type Version = (typeof Version)[keyof typeof Version];\n\n/**\n * Whether the PROBE message carries the RTT field.\n *\n * Added in lite-04. Lite-03 carries the bitrate alone, so a report with only an RTT to\n * give says nothing there and must not be sent.\n */\nexport function hasProbeRtt(version: Version): boolean {\n\t// Explicitly list older versions so future versions default to carrying RTT.\n\tswitch (version) {\n\t\tcase Version.DRAFT_01:\n\t\tcase Version.DRAFT_02:\n\t\tcase Version.DRAFT_03:\n\t\t\treturn false;\n\t\tdefault:\n\t\t\treturn true;\n\t}\n}\n\n/// Whether the session opens a unidirectional Setup Stream carrying a single SETUP message\n/// (capabilities + optional Path). Added in lite-05; older drafts have no Setup Stream.\nexport function hasSetupStream(version: Version): boolean {\n\t// Explicitly list older versions so future versions default to having the stream.\n\tswitch (version) {\n\t\tcase Version.DRAFT_01:\n\t\tcase Version.DRAFT_02:\n\t\tcase Version.DRAFT_03:\n\t\tcase Version.DRAFT_04:\n\t\t\treturn false;\n\t\tdefault:\n\t\t\treturn true;\n\t}\n}\n\n/// Whether the session may deliver groups over unreliable QUIC datagrams (lite-05 §6.4).\n/// A datagram carries one single-frame group's `subscribe | sequence | timestamp | payload` and is\n/// routed over the existing subscription. Added in lite-05; older versions never send/accept them.\nexport function hasDatagrams(version: Version): boolean {\n\t// Explicitly list older versions so future versions default to having datagrams.\n\tswitch (version) {\n\t\tcase Version.DRAFT_01:\n\t\tcase Version.DRAFT_02:\n\t\tcase Version.DRAFT_03:\n\t\tcase Version.DRAFT_04:\n\t\t\treturn false;\n\t\tdefault:\n\t\t\treturn true;\n\t}\n}\n\n/** Whether announce streams begin with ANNOUNCE_OK and omit the sender's origin from each hop chain. */\nexport function hasAnnounceOk(version: Version): boolean {\n\t// Explicitly list older versions so future versions keep the lite-05+ announce behavior.\n\tswitch (version) {\n\t\tcase Version.DRAFT_01:\n\t\tcase Version.DRAFT_02:\n\t\tcase Version.DRAFT_03:\n\t\tcase Version.DRAFT_04:\n\t\t\treturn false;\n\t\tdefault:\n\t\t\treturn true;\n\t}\n}\n\n/** Whether the version can replace an advertisement in place rather than retracting and\n * re-announcing it. Added in lite-05 as a duplicate ANNOUNCE; lite-06 gave it a message of\n * its own (ANNOUNCE_UPDATE) and made the duplicate a violation. */\nexport function restartSupported(version: Version): boolean {\n\t// Explicitly list older versions so future versions default to supported.\n\tswitch (version) {\n\t\tcase Version.DRAFT_01:\n\t\tcase Version.DRAFT_02:\n\t\tcase Version.DRAFT_03:\n\t\tcase Version.DRAFT_04:\n\t\t\treturn false;\n\t\tdefault:\n\t\t\treturn true;\n\t}\n}\n\n/** Whether announcements carry implicit announce ids: each `active` assigns the next\n * per-stream ordinal, and `ended`/`restart` reference that id instead of repeating the\n * path. Added in lite-06. */\nexport function hasAnnounceId(version: Version): boolean {\n\t// Explicitly list older versions so future versions keep the lite-06+ announce behavior.\n\tswitch (version) {\n\t\tcase Version.DRAFT_01:\n\t\tcase Version.DRAFT_02:\n\t\tcase Version.DRAFT_03:\n\t\tcase Version.DRAFT_04:\n\t\tcase Version.DRAFT_05:\n\t\t\treturn false;\n\t\tdefault:\n\t\t\treturn true;\n\t}\n}\n\n/** Whether ANNOUNCE_REQUEST carries the Exclude Hop field: the subscriber's own\n * origin id, which the publisher uses to skip announces whose hop chain already\n * passed through the subscriber. Present in lite-04 and lite-05 only.\n *\n * The receiver's own reflected-announce check drops those announces anyway (and\n * catches loops of any length, not just the two-hop case), so lite-06 drops the\n * field and keeps the check.\n *\n * Unlike the gates above, this lists the versions that *have* the field: it was\n * removed rather than added, so future versions default to not carrying it. */\nexport function hasExcludeHop(version: Version): boolean {\n\tswitch (version) {\n\t\tcase Version.DRAFT_04:\n\t\tcase Version.DRAFT_05:\n\t\t\treturn true;\n\t\tdefault:\n\t\t\treturn false;\n\t}\n}\n\n/** Whether announcements carry a route cost varint alongside the hop chain: the\n * marginal cost of pulling the broadcast via this route, accumulated per link.\n * Added in lite-06. Older versions carry nothing, so a received route stays at\n * zero and routing falls back to the hop-count tie-break. */\nexport function hasRouteCost(version: Version): boolean {\n\t// Explicitly list older versions so future versions keep the lite-06+ behavior.\n\tswitch (version) {\n\t\tcase Version.DRAFT_01:\n\t\tcase Version.DRAFT_02:\n\t\tcase Version.DRAFT_03:\n\t\tcase Version.DRAFT_04:\n\t\tcase Version.DRAFT_05:\n\t\t\treturn false;\n\t\tdefault:\n\t\t\treturn true;\n\t}\n}\n\n/// The WebTransport subprotocol identifier for moq-lite.\n/// Version negotiation still happens via SETUP when this is used.\nexport const ALPN = \"moql\";\n\n/// The ALPN string for Draft03, which uses ALPN-based version negotiation.\nexport const ALPN_03 = \"moq-lite-03\";\n\n/// The ALPN string for Draft04, which uses ALPN-based version negotiation.\nexport const ALPN_04 = \"moq-lite-04\";\n\n/// The ALPN string for Draft05, which uses ALPN-based version negotiation.\nexport const ALPN_05 = \"moq-lite-05\";\n\n/// The ALPN string for the work-in-progress Draft06. It is NOT in the default\n/// WebTransport `protocols` list, so lite-06 is never advertised or negotiated by\n/// default; a peer only reaches it when both sides explicitly offer this ALPN.\nexport const ALPN_06_WIP = \"moq-lite-06-wip\";\n\nconst VERSION_NAMES: Record<number, string> = {\n\t[Version.DRAFT_01]: \"moq-lite-01\",\n\t[Version.DRAFT_02]: \"moq-lite-02\",\n\t[Version.DRAFT_03]: \"moq-lite-03\",\n\t[Version.DRAFT_04]: \"moq-lite-04\",\n\t[Version.DRAFT_05]: \"moq-lite-05\",\n\t[Version.DRAFT_06]: \"moq-lite-06-wip\",\n};\n\nexport function versionName(v: Version): string {\n\treturn VERSION_NAMES[v] ?? `unknown(0x${v.toString(16)})`;\n}\n"]}
package/mock.d.ts CHANGED
@@ -3,14 +3,64 @@
3
3
  *
4
4
  * Creates paired client/server transports connected via TransformStreams.
5
5
  */
6
+ import type { TransportStats } from "./connection/stats";
7
+ import type { SendStream } from "./stream";
8
+ /** A fake {@link WebTransport} backed by TransformStreams, paired with a peer. */
9
+ export declare class MockTransport implements WebTransport {
10
+ #private;
11
+ readonly protocol: string;
12
+ readonly ready: Promise<undefined>;
13
+ readonly closed: Promise<WebTransportCloseInfo>;
14
+ readonly incomingBidirectionalStreams: ReadableStream<WebTransportBidirectionalStream>;
15
+ readonly incomingUnidirectionalStreams: ReadableStream<ReadableStream<Uint8Array>>;
16
+ readonly datagrams: WebTransportDatagramDuplexStream;
17
+ readonly congestionControl: WebTransportCongestionControl;
18
+ readonly reliability: string;
19
+ /**
20
+ * Every outgoing stream this transport opened, in call order, split by stream kind. Each
21
+ * carries a live {@link SendStream.sendOrder} (set when it opened, and by any later
22
+ * re-rank), so a test can assert how the wire layer prioritized it. The mock always
23
+ * delivers in creation order, so nothing else observes it.
24
+ */
25
+ readonly sendStreams: {
26
+ uni: SendStream[];
27
+ bidi: SendStream[];
28
+ };
29
+ constructor(protocol: string, datagramsEnabled?: boolean, datagramWritable?: DatagramWritableApi, datagramReadable?: boolean);
30
+ setPeer(peer: MockTransport): void;
31
+ createBidirectionalStream(options?: WebTransportSendStreamOptions): Promise<WebTransportBidirectionalStream>;
32
+ createUnidirectionalStream(options?: WebTransportSendStreamOptions): Promise<WritableStream<Uint8Array>>;
33
+ close(_closeInfo?: WebTransportCloseInfo): void;
34
+ /** The snapshot {@link getStats} resolves with (default empty). */
35
+ stats: TransportStats;
36
+ getStats(): Promise<TransportStats>;
37
+ }
38
+ type DatagramWritableApi = "writable" | "createWritable" | "none";
39
+ /** Options for {@link createMockTransportPair}. */
40
+ export interface MockTransportOptions {
41
+ /**
42
+ * Whether the paired transports carry QUIC datagrams (default true). Set false to
43
+ * simulate a transport that reports `maxDatagramSize` 0 (e.g. a qmux/WebSocket
44
+ * session), so the wire layer must fall back to not sending datagrams.
45
+ */
46
+ datagrams?: boolean;
47
+ /** Which outgoing datagram API shape the mock exposes. */
48
+ datagramWritable?: DatagramWritableApi;
49
+ /** Whether the incoming datagram readable stream is exposed. */
50
+ datagramReadable?: boolean;
51
+ /** The snapshot `getStats()` resolves with on both transports (default empty). */
52
+ stats?: TransportStats;
53
+ }
6
54
  /**
7
55
  * Creates a pair of connected MockTransport instances.
8
56
  *
9
57
  * @param protocol - The WebTransport protocol identifier (e.g. "moqt-17", "moql", "")
58
+ * @param options - Optional behavior toggles for datagram availability
10
59
  * @returns An object containing `client` and `server` transports
11
60
  */
12
- export declare function createMockTransportPair(protocol?: string): {
13
- client: WebTransport;
14
- server: WebTransport;
61
+ export declare function createMockTransportPair(protocol?: string, options?: MockTransportOptions): {
62
+ client: MockTransport;
63
+ server: MockTransport;
15
64
  };
65
+ export {};
16
66
  //# sourceMappingURL=mock.d.ts.map
package/mock.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"mock.d.ts","sourceRoot":"","sources":["../src/mock.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAiKH;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,QAAQ,SAAK,GAAG;IAAE,MAAM,EAAE,YAAY,CAAC;IAAC,MAAM,EAAE,YAAY,CAAA;CAAE,CAMrG"}
1
+ {"version":3,"file":"mock.d.ts","sourceRoot":"","sources":["../src/mock.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAqB9C,kFAAkF;AAClF,qBAAa,aAAc,YAAW,YAAY;;IACjD,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC;IACnC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC,qBAAqB,CAAC,CAAC;IAEhD,QAAQ,CAAC,4BAA4B,EAAE,cAAc,CAAC,+BAA+B,CAAC,CAAC;IACvF,QAAQ,CAAC,6BAA6B,EAAE,cAAc,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC,CAAC;IAEnF,QAAQ,CAAC,SAAS,EAAE,gCAAgC,CAAC;IACrD,QAAQ,CAAC,iBAAiB,EAAE,6BAA6B,CAAC;IAC1D,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAE7B;;;;;OAKG;IACH,QAAQ,CAAC,WAAW,EAAE;QAAE,GAAG,EAAE,UAAU,EAAE,CAAC;QAAC,IAAI,EAAE,UAAU,EAAE,CAAA;KAAE,CAAyB;IAYxF,YACC,QAAQ,EAAE,MAAM,EAChB,gBAAgB,UAAO,EACvB,gBAAgB,GAAE,mBAAgC,EAClD,gBAAgB,UAAO,EAoFvB;IAED,OAAO,CAAC,IAAI,EAAE,aAAa,QAE1B;IAEK,yBAAyB,CAAC,OAAO,CAAC,EAAE,6BAA6B,GAAG,OAAO,CAAC,+BAA+B,CAAC,CA2BjH;IAEK,0BAA0B,CAAC,OAAO,CAAC,EAAE,6BAA6B,GAAG,OAAO,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC,CAiB7G;IAeD,KAAK,CAAC,UAAU,CAAC,EAAE,qBAAqB,GAAG,IAAI,CAwC9C;IAED,mEAAmE;IACnE,KAAK,EAAE,cAAc,CAAM;IAErB,QAAQ,IAAI,OAAO,CAAC,cAAc,CAAC,CAExC;CACD;AAED,KAAK,mBAAmB,GAAG,UAAU,GAAG,gBAAgB,GAAG,MAAM,CAAC;AAElE,mDAAmD;AACnD,MAAM,WAAW,oBAAoB;IACpC;;;;OAIG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB,0DAA0D;IAC1D,gBAAgB,CAAC,EAAE,mBAAmB,CAAC;IAEvC,gEAAgE;IAChE,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAE3B,kFAAkF;IAClF,KAAK,CAAC,EAAE,cAAc,CAAC;CACvB;AAED;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CACtC,QAAQ,SAAK,EACb,OAAO,CAAC,EAAE,oBAAoB,GAC5B;IAAE,MAAM,EAAE,aAAa,CAAC;IAAC,MAAM,EAAE,aAAa,CAAA;CAAE,CAYlD"}
package/mock.js CHANGED
@@ -17,7 +17,8 @@ function newStream() {
17
17
  },
18
18
  }, WRITABLE_STRATEGY, READABLE_STRATEGY);
19
19
  }
20
- class MockTransport {
20
+ /** A fake {@link WebTransport} backed by TransformStreams, paired with a peer. */
21
+ export class MockTransport {
21
22
  protocol;
22
23
  ready;
23
24
  closed;
@@ -26,12 +27,22 @@ class MockTransport {
26
27
  datagrams;
27
28
  congestionControl;
28
29
  reliability;
30
+ /**
31
+ * Every outgoing stream this transport opened, in call order, split by stream kind. Each
32
+ * carries a live {@link SendStream.sendOrder} (set when it opened, and by any later
33
+ * re-rank), so a test can assert how the wire layer prioritized it. The mock always
34
+ * delivers in creation order, so nothing else observes it.
35
+ */
36
+ sendStreams = { uni: [], bidi: [] };
29
37
  #closeResolve;
30
38
  #bidiController;
31
39
  #uniController;
40
+ // Incoming-datagram controller (only set when datagrams are enabled); the peer's
41
+ // writable enqueues into it.
42
+ #datagramController;
32
43
  // Reference to the peer so we can enqueue streams to them
33
44
  #peer;
34
- constructor(protocol) {
45
+ constructor(protocol, datagramsEnabled = true, datagramWritable = "writable", datagramReadable = true) {
35
46
  this.protocol = protocol;
36
47
  this.ready = Promise.resolve(undefined);
37
48
  this.closed = new Promise((resolve) => {
@@ -49,21 +60,68 @@ class MockTransport {
49
60
  });
50
61
  this.congestionControl = "default";
51
62
  this.reliability = "supports-unreliable";
52
- // Stub datagrams
53
- this.datagrams = {
54
- readable: new ReadableStream(),
55
- writable: new WritableStream(),
56
- incomingHighWaterMark: 0,
57
- outgoingHighWaterMark: 0,
58
- incomingMaxAge: null,
59
- outgoingMaxAge: null,
60
- maxDatagramSize: 0,
61
- };
63
+ if (datagramsEnabled) {
64
+ // A real datagram duplex: writes enqueue into the peer's incoming readable,
65
+ // so a peer pair actually exchanges datagrams (unlike a real qmux Session,
66
+ // whose datagram streams are inert stubs).
67
+ const readable = datagramReadable
68
+ ? new ReadableStream({
69
+ start: (controller) => {
70
+ this.#datagramController = controller;
71
+ },
72
+ })
73
+ : undefined;
74
+ const writable = new WritableStream({
75
+ write: (chunk) => {
76
+ const peer = this.#peer;
77
+ if (!peer)
78
+ return;
79
+ const controller = peer.#datagramController;
80
+ if (!controller)
81
+ return;
82
+ try {
83
+ // Copy so the caller's scratch buffer reuse can't corrupt queued data.
84
+ controller.enqueue(new Uint8Array(chunk));
85
+ }
86
+ catch {
87
+ // Peer closed; drop (datagrams are best-effort).
88
+ }
89
+ },
90
+ });
91
+ const datagrams = {
92
+ readable,
93
+ incomingHighWaterMark: 0,
94
+ outgoingHighWaterMark: 0,
95
+ incomingMaxAge: null,
96
+ outgoingMaxAge: null,
97
+ maxDatagramSize: 1200,
98
+ };
99
+ if (datagramWritable === "writable") {
100
+ datagrams.writable = writable;
101
+ }
102
+ else if (datagramWritable === "createWritable") {
103
+ datagrams.createWritable = () => writable;
104
+ }
105
+ this.datagrams = datagrams;
106
+ }
107
+ else {
108
+ // Simulate a transport that doesn't carry datagrams (maxDatagramSize 0): the
109
+ // wire layer must fall back to not sending, with no group fallback.
110
+ this.datagrams = {
111
+ readable: new ReadableStream(),
112
+ writable: new WritableStream(),
113
+ incomingHighWaterMark: 0,
114
+ outgoingHighWaterMark: 0,
115
+ incomingMaxAge: null,
116
+ outgoingMaxAge: null,
117
+ maxDatagramSize: 0,
118
+ };
119
+ }
62
120
  }
63
121
  setPeer(peer) {
64
122
  this.#peer = peer;
65
123
  }
66
- async createBidirectionalStream(_options) {
124
+ async createBidirectionalStream(options) {
67
125
  const peer = this.#peer;
68
126
  if (!peer)
69
127
  throw new Error("no peer");
@@ -73,7 +131,7 @@ class MockTransport {
73
131
  // Local side: writes to c2s, reads from s2c
74
132
  const local = {
75
133
  readable: s2c.readable,
76
- writable: c2s.writable,
134
+ writable: this.#sendStream(c2s.writable, this.sendStreams.bidi, options),
77
135
  };
78
136
  // Peer side: writes to s2c, reads from c2s
79
137
  const remote = {
@@ -88,18 +146,29 @@ class MockTransport {
88
146
  }
89
147
  return local;
90
148
  }
91
- async createUnidirectionalStream(_options) {
149
+ async createUnidirectionalStream(options) {
92
150
  const peer = this.#peer;
93
151
  if (!peer)
94
152
  throw new Error("no peer");
95
153
  const c2s = newStream();
154
+ // Record before handing the peer its end, so a peer that waits for the stream to arrive
155
+ // always finds it here.
156
+ const stream = this.#sendStream(c2s.writable, this.sendStreams.uni, options);
96
157
  try {
97
158
  peer.#uniController.enqueue(c2s.readable);
98
159
  }
99
160
  catch {
100
161
  // Peer closed
101
162
  }
102
- return c2s.writable;
163
+ return stream;
164
+ }
165
+ // Give a writable the send order it opened with and record it, so a test sees both that
166
+ // order and any later re-rank (which assigns the same property, as on a real send stream).
167
+ #sendStream(writable, log, options) {
168
+ const stream = writable;
169
+ stream.sendOrder = options?.sendOrder;
170
+ log.push(stream);
171
+ return stream;
103
172
  }
104
173
  close(_closeInfo) {
105
174
  const info = _closeInfo ?? { closeCode: 0, reason: "" };
@@ -116,6 +185,12 @@ class MockTransport {
116
185
  catch {
117
186
  // Already closed
118
187
  }
188
+ try {
189
+ this.#datagramController?.close();
190
+ }
191
+ catch {
192
+ // Already closed
193
+ }
119
194
  // Also close peer's incoming streams
120
195
  if (this.#peer) {
121
196
  try {
@@ -130,23 +205,37 @@ class MockTransport {
130
205
  catch {
131
206
  // Already closed
132
207
  }
208
+ try {
209
+ this.#peer.#datagramController?.close();
210
+ }
211
+ catch {
212
+ // Already closed
213
+ }
133
214
  this.#peer.#closeResolve(info);
134
215
  }
135
216
  }
136
- // biome-ignore lint/suspicious/noExplicitAny: WebTransportStats type not available in all TS libs
217
+ /** The snapshot {@link getStats} resolves with (default empty). */
218
+ stats = {};
137
219
  async getStats() {
138
- return {};
220
+ return this.stats;
139
221
  }
140
222
  }
141
223
  /**
142
224
  * Creates a pair of connected MockTransport instances.
143
225
  *
144
226
  * @param protocol - The WebTransport protocol identifier (e.g. "moqt-17", "moql", "")
227
+ * @param options - Optional behavior toggles for datagram availability
145
228
  * @returns An object containing `client` and `server` transports
146
229
  */
147
- export function createMockTransportPair(protocol = "") {
148
- const client = new MockTransport(protocol);
149
- const server = new MockTransport(protocol);
230
+ export function createMockTransportPair(protocol = "", options) {
231
+ const datagrams = options?.datagrams ?? true;
232
+ const client = new MockTransport(protocol, datagrams, options?.datagramWritable, options?.datagramReadable);
233
+ const server = new MockTransport(protocol, datagrams, options?.datagramWritable, options?.datagramReadable);
234
+ if (options?.stats) {
235
+ // Copy per side so a test advancing one transport's counters doesn't move the other's.
236
+ client.stats = { ...options.stats };
237
+ server.stats = { ...options.stats };
238
+ }
150
239
  client.setPeer(server);
151
240
  server.setPeer(client);
152
241
  return { client, server };
package/mock.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"mock.js","sourceRoot":"","sources":["../src/mock.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Mock WebTransport implementation for in-process testing.\n *\n * Creates paired client/server transports connected via TransformStreams.\n */\n\n// High watermark to prevent writes from blocking on backpressure.\n// Real WebTransport has kernel buffers; we simulate this with a large queue.\nconst WRITABLE_STRATEGY: QueuingStrategy<Uint8Array> = { highWaterMark: 256 };\nconst READABLE_STRATEGY: QueuingStrategy<Uint8Array> = { highWaterMark: 256 };\n\nfunction newStream(): TransformStream<Uint8Array, Uint8Array> {\n\treturn new TransformStream(\n\t\t{\n\t\t\t// Copy each chunk to simulate real WebTransport's kernel-boundary copy.\n\t\t\t// Without this, Writer's scratch buffer reuse corrupts queued data.\n\t\t\ttransform(chunk, controller) {\n\t\t\t\tcontroller.enqueue(new Uint8Array(chunk));\n\t\t\t},\n\t\t},\n\t\tWRITABLE_STRATEGY,\n\t\tREADABLE_STRATEGY,\n\t);\n}\n\nclass MockTransport implements WebTransport {\n\treadonly protocol: string;\n\treadonly ready: Promise<undefined>;\n\treadonly closed: Promise<WebTransportCloseInfo>;\n\n\treadonly incomingBidirectionalStreams: ReadableStream<WebTransportBidirectionalStream>;\n\treadonly incomingUnidirectionalStreams: ReadableStream<ReadableStream<Uint8Array>>;\n\n\treadonly datagrams: WebTransportDatagramDuplexStream;\n\treadonly congestionControl: WebTransportCongestionControl;\n\treadonly reliability: string;\n\n\t#closeResolve!: (info: WebTransportCloseInfo) => void;\n\t#bidiController!: ReadableStreamDefaultController<WebTransportBidirectionalStream>;\n\t#uniController!: ReadableStreamDefaultController<ReadableStream<Uint8Array>>;\n\n\t// Reference to the peer so we can enqueue streams to them\n\t#peer?: MockTransport;\n\n\tconstructor(protocol: string) {\n\t\tthis.protocol = protocol;\n\t\tthis.ready = Promise.resolve(undefined);\n\t\tthis.closed = new Promise((resolve) => {\n\t\t\tthis.#closeResolve = resolve;\n\t\t});\n\n\t\tthis.incomingBidirectionalStreams = new ReadableStream({\n\t\t\tstart: (controller) => {\n\t\t\t\tthis.#bidiController = controller;\n\t\t\t},\n\t\t});\n\n\t\tthis.incomingUnidirectionalStreams = new ReadableStream({\n\t\t\tstart: (controller) => {\n\t\t\t\tthis.#uniController = controller;\n\t\t\t},\n\t\t});\n\n\t\tthis.congestionControl = \"default\";\n\t\tthis.reliability = \"supports-unreliable\";\n\n\t\t// Stub datagrams\n\t\tthis.datagrams = {\n\t\t\treadable: new ReadableStream(),\n\t\t\twritable: new WritableStream(),\n\t\t\tincomingHighWaterMark: 0,\n\t\t\toutgoingHighWaterMark: 0,\n\t\t\tincomingMaxAge: null,\n\t\t\toutgoingMaxAge: null,\n\t\t\tmaxDatagramSize: 0,\n\t\t};\n\t}\n\n\tsetPeer(peer: MockTransport) {\n\t\tthis.#peer = peer;\n\t}\n\n\tasync createBidirectionalStream(\n\t\t_options?: WebTransportSendStreamOptions,\n\t): Promise<WebTransportBidirectionalStream> {\n\t\tconst peer = this.#peer;\n\t\tif (!peer) throw new Error(\"no peer\");\n\n\t\t// Create two TransformStreams for the two directions\n\t\tconst c2s = newStream();\n\t\tconst s2c = newStream();\n\n\t\t// Local side: writes to c2s, reads from s2c\n\t\tconst local = {\n\t\t\treadable: s2c.readable,\n\t\t\twritable: c2s.writable,\n\t\t} as WebTransportBidirectionalStream;\n\n\t\t// Peer side: writes to s2c, reads from c2s\n\t\tconst remote = {\n\t\t\treadable: c2s.readable,\n\t\t\twritable: s2c.writable,\n\t\t} as WebTransportBidirectionalStream;\n\n\t\ttry {\n\t\t\tpeer.#bidiController.enqueue(remote);\n\t\t} catch {\n\t\t\t// Peer closed\n\t\t}\n\n\t\treturn local;\n\t}\n\n\tasync createUnidirectionalStream(_options?: WebTransportSendStreamOptions): Promise<WritableStream<Uint8Array>> {\n\t\tconst peer = this.#peer;\n\t\tif (!peer) throw new Error(\"no peer\");\n\n\t\tconst c2s = newStream();\n\n\t\ttry {\n\t\t\tpeer.#uniController.enqueue(c2s.readable);\n\t\t} catch {\n\t\t\t// Peer closed\n\t\t}\n\n\t\treturn c2s.writable;\n\t}\n\n\tclose(_closeInfo?: WebTransportCloseInfo): void {\n\t\tconst info = _closeInfo ?? { closeCode: 0, reason: \"\" };\n\t\tthis.#closeResolve(info);\n\n\t\ttry {\n\t\t\tthis.#bidiController.close();\n\t\t} catch {\n\t\t\t// Already closed\n\t\t}\n\t\ttry {\n\t\t\tthis.#uniController.close();\n\t\t} catch {\n\t\t\t// Already closed\n\t\t}\n\n\t\t// Also close peer's incoming streams\n\t\tif (this.#peer) {\n\t\t\ttry {\n\t\t\t\tthis.#peer.#bidiController.close();\n\t\t\t} catch {\n\t\t\t\t// Already closed\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tthis.#peer.#uniController.close();\n\t\t\t} catch {\n\t\t\t\t// Already closed\n\t\t\t}\n\t\t\tthis.#peer.#closeResolve(info);\n\t\t}\n\t}\n\n\t// biome-ignore lint/suspicious/noExplicitAny: WebTransportStats type not available in all TS libs\n\tasync getStats(): Promise<any> {\n\t\treturn {};\n\t}\n}\n\n/**\n * Creates a pair of connected MockTransport instances.\n *\n * @param protocol - The WebTransport protocol identifier (e.g. \"moqt-17\", \"moql\", \"\")\n * @returns An object containing `client` and `server` transports\n */\nexport function createMockTransportPair(protocol = \"\"): { client: WebTransport; server: WebTransport } {\n\tconst client = new MockTransport(protocol);\n\tconst server = new MockTransport(protocol);\n\tclient.setPeer(server);\n\tserver.setPeer(client);\n\treturn { client, server };\n}\n"]}
1
+ {"version":3,"file":"mock.js","sourceRoot":"","sources":["../src/mock.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Mock WebTransport implementation for in-process testing.\n *\n * Creates paired client/server transports connected via TransformStreams.\n */\n\nimport type { TransportStats } from \"./connection/stats.ts\";\nimport type { SendStream } from \"./stream.ts\";\n\n// High watermark to prevent writes from blocking on backpressure.\n// Real WebTransport has kernel buffers; we simulate this with a large queue.\nconst WRITABLE_STRATEGY: QueuingStrategy<Uint8Array> = { highWaterMark: 256 };\nconst READABLE_STRATEGY: QueuingStrategy<Uint8Array> = { highWaterMark: 256 };\n\nfunction newStream(): TransformStream<Uint8Array, Uint8Array> {\n\treturn new TransformStream(\n\t\t{\n\t\t\t// Copy each chunk to simulate real WebTransport's kernel-boundary copy.\n\t\t\t// Without this, Writer's scratch buffer reuse corrupts queued data.\n\t\t\ttransform(chunk, controller) {\n\t\t\t\tcontroller.enqueue(new Uint8Array(chunk));\n\t\t\t},\n\t\t},\n\t\tWRITABLE_STRATEGY,\n\t\tREADABLE_STRATEGY,\n\t);\n}\n\n/** A fake {@link WebTransport} backed by TransformStreams, paired with a peer. */\nexport class MockTransport implements WebTransport {\n\treadonly protocol: string;\n\treadonly ready: Promise<undefined>;\n\treadonly closed: Promise<WebTransportCloseInfo>;\n\n\treadonly incomingBidirectionalStreams: ReadableStream<WebTransportBidirectionalStream>;\n\treadonly incomingUnidirectionalStreams: ReadableStream<ReadableStream<Uint8Array>>;\n\n\treadonly datagrams: WebTransportDatagramDuplexStream;\n\treadonly congestionControl: WebTransportCongestionControl;\n\treadonly reliability: string;\n\n\t/**\n\t * Every outgoing stream this transport opened, in call order, split by stream kind. Each\n\t * carries a live {@link SendStream.sendOrder} (set when it opened, and by any later\n\t * re-rank), so a test can assert how the wire layer prioritized it. The mock always\n\t * delivers in creation order, so nothing else observes it.\n\t */\n\treadonly sendStreams: { uni: SendStream[]; bidi: SendStream[] } = { uni: [], bidi: [] };\n\n\t#closeResolve!: (info: WebTransportCloseInfo) => void;\n\t#bidiController!: ReadableStreamDefaultController<WebTransportBidirectionalStream>;\n\t#uniController!: ReadableStreamDefaultController<ReadableStream<Uint8Array>>;\n\t// Incoming-datagram controller (only set when datagrams are enabled); the peer's\n\t// writable enqueues into it.\n\t#datagramController?: ReadableStreamDefaultController<Uint8Array>;\n\n\t// Reference to the peer so we can enqueue streams to them\n\t#peer?: MockTransport;\n\n\tconstructor(\n\t\tprotocol: string,\n\t\tdatagramsEnabled = true,\n\t\tdatagramWritable: DatagramWritableApi = \"writable\",\n\t\tdatagramReadable = true,\n\t) {\n\t\tthis.protocol = protocol;\n\t\tthis.ready = Promise.resolve(undefined);\n\t\tthis.closed = new Promise((resolve) => {\n\t\t\tthis.#closeResolve = resolve;\n\t\t});\n\n\t\tthis.incomingBidirectionalStreams = new ReadableStream({\n\t\t\tstart: (controller) => {\n\t\t\t\tthis.#bidiController = controller;\n\t\t\t},\n\t\t});\n\n\t\tthis.incomingUnidirectionalStreams = new ReadableStream({\n\t\t\tstart: (controller) => {\n\t\t\t\tthis.#uniController = controller;\n\t\t\t},\n\t\t});\n\n\t\tthis.congestionControl = \"default\";\n\t\tthis.reliability = \"supports-unreliable\";\n\n\t\tif (datagramsEnabled) {\n\t\t\t// A real datagram duplex: writes enqueue into the peer's incoming readable,\n\t\t\t// so a peer pair actually exchanges datagrams (unlike a real qmux Session,\n\t\t\t// whose datagram streams are inert stubs).\n\t\t\tconst readable = datagramReadable\n\t\t\t\t? new ReadableStream<Uint8Array>({\n\t\t\t\t\t\tstart: (controller) => {\n\t\t\t\t\t\t\tthis.#datagramController = controller;\n\t\t\t\t\t\t},\n\t\t\t\t\t})\n\t\t\t\t: undefined;\n\t\t\tconst writable = new WritableStream<Uint8Array>({\n\t\t\t\twrite: (chunk) => {\n\t\t\t\t\tconst peer = this.#peer;\n\t\t\t\t\tif (!peer) return;\n\t\t\t\t\tconst controller = peer.#datagramController;\n\t\t\t\t\tif (!controller) return;\n\t\t\t\t\ttry {\n\t\t\t\t\t\t// Copy so the caller's scratch buffer reuse can't corrupt queued data.\n\t\t\t\t\t\tcontroller.enqueue(new Uint8Array(chunk));\n\t\t\t\t\t} catch {\n\t\t\t\t\t\t// Peer closed; drop (datagrams are best-effort).\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t});\n\t\t\tconst datagrams: {\n\t\t\t\treadable?: ReadableStream<Uint8Array>;\n\t\t\t\twritable?: WritableStream<Uint8Array>;\n\t\t\t\tmaxDatagramSize: number;\n\t\t\t\tincomingHighWaterMark: number;\n\t\t\t\toutgoingHighWaterMark: number;\n\t\t\t\tincomingMaxAge: null;\n\t\t\t\toutgoingMaxAge: null;\n\t\t\t\tcreateWritable?: () => WritableStream<Uint8Array>;\n\t\t\t} = {\n\t\t\t\treadable,\n\t\t\t\tincomingHighWaterMark: 0,\n\t\t\t\toutgoingHighWaterMark: 0,\n\t\t\t\tincomingMaxAge: null,\n\t\t\t\toutgoingMaxAge: null,\n\t\t\t\tmaxDatagramSize: 1200,\n\t\t\t};\n\t\t\tif (datagramWritable === \"writable\") {\n\t\t\t\tdatagrams.writable = writable;\n\t\t\t} else if (datagramWritable === \"createWritable\") {\n\t\t\t\tdatagrams.createWritable = () => writable;\n\t\t\t}\n\t\t\tthis.datagrams = datagrams as WebTransportDatagramDuplexStream;\n\t\t} else {\n\t\t\t// Simulate a transport that doesn't carry datagrams (maxDatagramSize 0): the\n\t\t\t// wire layer must fall back to not sending, with no group fallback.\n\t\t\tthis.datagrams = {\n\t\t\t\treadable: new ReadableStream(),\n\t\t\t\twritable: new WritableStream(),\n\t\t\t\tincomingHighWaterMark: 0,\n\t\t\t\toutgoingHighWaterMark: 0,\n\t\t\t\tincomingMaxAge: null,\n\t\t\t\toutgoingMaxAge: null,\n\t\t\t\tmaxDatagramSize: 0,\n\t\t\t};\n\t\t}\n\t}\n\n\tsetPeer(peer: MockTransport) {\n\t\tthis.#peer = peer;\n\t}\n\n\tasync createBidirectionalStream(options?: WebTransportSendStreamOptions): Promise<WebTransportBidirectionalStream> {\n\t\tconst peer = this.#peer;\n\t\tif (!peer) throw new Error(\"no peer\");\n\n\t\t// Create two TransformStreams for the two directions\n\t\tconst c2s = newStream();\n\t\tconst s2c = newStream();\n\n\t\t// Local side: writes to c2s, reads from s2c\n\t\tconst local = {\n\t\t\treadable: s2c.readable,\n\t\t\twritable: this.#sendStream(c2s.writable, this.sendStreams.bidi, options),\n\t\t} as WebTransportBidirectionalStream;\n\n\t\t// Peer side: writes to s2c, reads from c2s\n\t\tconst remote = {\n\t\t\treadable: c2s.readable,\n\t\t\twritable: s2c.writable,\n\t\t} as WebTransportBidirectionalStream;\n\n\t\ttry {\n\t\t\tpeer.#bidiController.enqueue(remote);\n\t\t} catch {\n\t\t\t// Peer closed\n\t\t}\n\n\t\treturn local;\n\t}\n\n\tasync createUnidirectionalStream(options?: WebTransportSendStreamOptions): Promise<WritableStream<Uint8Array>> {\n\t\tconst peer = this.#peer;\n\t\tif (!peer) throw new Error(\"no peer\");\n\n\t\tconst c2s = newStream();\n\n\t\t// Record before handing the peer its end, so a peer that waits for the stream to arrive\n\t\t// always finds it here.\n\t\tconst stream = this.#sendStream(c2s.writable, this.sendStreams.uni, options);\n\n\t\ttry {\n\t\t\tpeer.#uniController.enqueue(c2s.readable);\n\t\t} catch {\n\t\t\t// Peer closed\n\t\t}\n\n\t\treturn stream;\n\t}\n\n\t// Give a writable the send order it opened with and record it, so a test sees both that\n\t// order and any later re-rank (which assigns the same property, as on a real send stream).\n\t#sendStream(\n\t\twritable: WritableStream<Uint8Array>,\n\t\tlog: SendStream[],\n\t\toptions?: WebTransportSendStreamOptions,\n\t): SendStream {\n\t\tconst stream = writable as SendStream;\n\t\tstream.sendOrder = options?.sendOrder;\n\t\tlog.push(stream);\n\t\treturn stream;\n\t}\n\n\tclose(_closeInfo?: WebTransportCloseInfo): void {\n\t\tconst info = _closeInfo ?? { closeCode: 0, reason: \"\" };\n\t\tthis.#closeResolve(info);\n\n\t\ttry {\n\t\t\tthis.#bidiController.close();\n\t\t} catch {\n\t\t\t// Already closed\n\t\t}\n\t\ttry {\n\t\t\tthis.#uniController.close();\n\t\t} catch {\n\t\t\t// Already closed\n\t\t}\n\n\t\ttry {\n\t\t\tthis.#datagramController?.close();\n\t\t} catch {\n\t\t\t// Already closed\n\t\t}\n\n\t\t// Also close peer's incoming streams\n\t\tif (this.#peer) {\n\t\t\ttry {\n\t\t\t\tthis.#peer.#bidiController.close();\n\t\t\t} catch {\n\t\t\t\t// Already closed\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tthis.#peer.#uniController.close();\n\t\t\t} catch {\n\t\t\t\t// Already closed\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tthis.#peer.#datagramController?.close();\n\t\t\t} catch {\n\t\t\t\t// Already closed\n\t\t\t}\n\t\t\tthis.#peer.#closeResolve(info);\n\t\t}\n\t}\n\n\t/** The snapshot {@link getStats} resolves with (default empty). */\n\tstats: TransportStats = {};\n\n\tasync getStats(): Promise<TransportStats> {\n\t\treturn this.stats;\n\t}\n}\n\ntype DatagramWritableApi = \"writable\" | \"createWritable\" | \"none\";\n\n/** Options for {@link createMockTransportPair}. */\nexport interface MockTransportOptions {\n\t/**\n\t * Whether the paired transports carry QUIC datagrams (default true). Set false to\n\t * simulate a transport that reports `maxDatagramSize` 0 (e.g. a qmux/WebSocket\n\t * session), so the wire layer must fall back to not sending datagrams.\n\t */\n\tdatagrams?: boolean;\n\n\t/** Which outgoing datagram API shape the mock exposes. */\n\tdatagramWritable?: DatagramWritableApi;\n\n\t/** Whether the incoming datagram readable stream is exposed. */\n\tdatagramReadable?: boolean;\n\n\t/** The snapshot `getStats()` resolves with on both transports (default empty). */\n\tstats?: TransportStats;\n}\n\n/**\n * Creates a pair of connected MockTransport instances.\n *\n * @param protocol - The WebTransport protocol identifier (e.g. \"moqt-17\", \"moql\", \"\")\n * @param options - Optional behavior toggles for datagram availability\n * @returns An object containing `client` and `server` transports\n */\nexport function createMockTransportPair(\n\tprotocol = \"\",\n\toptions?: MockTransportOptions,\n): { client: MockTransport; server: MockTransport } {\n\tconst datagrams = options?.datagrams ?? true;\n\tconst client = new MockTransport(protocol, datagrams, options?.datagramWritable, options?.datagramReadable);\n\tconst server = new MockTransport(protocol, datagrams, options?.datagramWritable, options?.datagramReadable);\n\tif (options?.stats) {\n\t\t// Copy per side so a test advancing one transport's counters doesn't move the other's.\n\t\tclient.stats = { ...options.stats };\n\t\tserver.stats = { ...options.stats };\n\t}\n\tclient.setPeer(server);\n\tserver.setPeer(client);\n\treturn { client, server };\n}\n"]}
@@ -1,4 +1,13 @@
1
- import * as z from "zod/mini";
1
+ /**
2
+ * Endpoint identity within a hop chain, shared by both wire protocols.
3
+ *
4
+ * moq-lite carries these natively on every announcement; moq-transport carries them
5
+ * via the MoQ Cluster extension (see `ietf/cluster.ts`). Mirrors `Origin` in
6
+ * `rs/moq-net`.
7
+ *
8
+ * @module
9
+ */
10
+ import * as z from "@zod/mini";
2
11
  /**
3
12
  * A relay origin id, encoded as a 62-bit varint on the wire.
4
13
  *
@@ -9,6 +18,21 @@ import * as z from "zod/mini";
9
18
  */
10
19
  export declare const OriginSchema: z.core.$ZodBranded<z.ZodMiniBigInt<bigint>, "Origin", "out">;
11
20
  export type Origin = z.infer<typeof OriginSchema>;
21
+ /**
22
+ * The reserved id 0, meaning "no identity".
23
+ *
24
+ * It stands in for an endpoint that never declared one, and any number of endpoints can
25
+ * be 0, so it identifies nothing: it is never a loop, never a publisher two chains have
26
+ * in common, and never excluded from an advertisement.
27
+ */
28
+ export declare const UNKNOWN_ORIGIN: Origin;
29
+ /**
30
+ * Maximum length of a hop chain. Must match `MAX_HOPS` in Rust's `model/origin.rs`.
31
+ *
32
+ * Broadcasts with longer chains are rejected, which bounds loop detection and rejects
33
+ * pathological announcements across clusters with unbounded forwarding.
34
+ */
35
+ export declare const MAX_HOPS = 32;
12
36
  /**
13
37
  * Generate a fresh origin with a random non-zero id.
14
38
  *
@@ -0,0 +1 @@
1
+ {"version":3,"file":"origin.d.ts","sourceRoot":"","sources":["../src/origin.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,CAAC,MAAM,WAAW,CAAC;AAE/B;;;;;;;GAOG;AACH,eAAO,MAAM,YAAY,8DAGR,CAAC;AAElB,MAAM,MAAM,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAC;AAElD;;;;;;GAMG;AACH,eAAO,MAAM,cAAc,EAAE,MAA+B,CAAC;AAE7D;;;;;GAKG;AACH,eAAO,MAAM,QAAQ,KAAK,CAAC;AAE3B;;;;;;;;;;;GAWG;AACH,wBAAgB,YAAY,IAAI,MAAM,CAOrC"}
@@ -1,5 +1,14 @@
1
1
  /* @ts-self-types="./origin.d.ts" */
2
- import * as z from "zod/mini";
2
+ /**
3
+ * Endpoint identity within a hop chain, shared by both wire protocols.
4
+ *
5
+ * moq-lite carries these natively on every announcement; moq-transport carries them
6
+ * via the MoQ Cluster extension (see `ietf/cluster.ts`). Mirrors `Origin` in
7
+ * `rs/moq-net`.
8
+ *
9
+ * @module
10
+ */
11
+ import * as z from "@zod/mini";
3
12
  /**
4
13
  * A relay origin id, encoded as a 62-bit varint on the wire.
5
14
  *
@@ -12,6 +21,21 @@ export const OriginSchema = z
12
21
  .bigint()
13
22
  .check(z.refine((value) => value >= 0n && value < 1n << 62n, "Origin must be a non-negative 62-bit integer"))
14
23
  .brand("Origin");
24
+ /**
25
+ * The reserved id 0, meaning "no identity".
26
+ *
27
+ * It stands in for an endpoint that never declared one, and any number of endpoints can
28
+ * be 0, so it identifies nothing: it is never a loop, never a publisher two chains have
29
+ * in common, and never excluded from an advertisement.
30
+ */
31
+ export const UNKNOWN_ORIGIN = OriginSchema.parse(0n);
32
+ /**
33
+ * Maximum length of a hop chain. Must match `MAX_HOPS` in Rust's `model/origin.rs`.
34
+ *
35
+ * Broadcasts with longer chains are rejected, which bounds loop detection and rejects
36
+ * pathological announcements across clusters with unbounded forwarding.
37
+ */
38
+ export const MAX_HOPS = 32;
15
39
  /**
16
40
  * Generate a fresh origin with a random non-zero id.
17
41
  *
package/origin.js.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"origin.js","sourceRoot":"","sources":["../src/origin.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,CAAC,MAAM,WAAW,CAAC;AAE/B;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC;KAC3B,MAAM,EAAE;KACR,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,IAAI,EAAE,IAAI,KAAK,GAAG,EAAE,IAAI,GAAG,EAAE,8CAA8C,CAAC,CAAC;KAC5G,KAAK,CAAC,QAAQ,CAAC,CAAC;AAIlB;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,cAAc,GAAW,YAAY,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;AAE7D;;;;;GAKG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAG,EAAE,CAAC;AAE3B;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,YAAY;IAC3B,MAAM,GAAG,GAAG,IAAI,cAAc,CAAC,CAAC,CAAC,CAAC;IAClC,MAAM,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC;IAC5B,mBAAmB;IACnB,MAAM,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,iBAAoB,CAAC;IAC1C,yDAAyD;IACzD,OAAO,YAAY,CAAC,KAAK,CAAC,GAAG,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;AAClD,CAAC","sourcesContent":["/**\n * Endpoint identity within a hop chain, shared by both wire protocols.\n *\n * moq-lite carries these natively on every announcement; moq-transport carries them\n * via the MoQ Cluster extension (see `ietf/cluster.ts`). Mirrors `Origin` in\n * `rs/moq-net`.\n *\n * @module\n */\nimport * as z from \"@zod/mini\";\n\n/**\n * A relay origin id, encoded as a 62-bit varint on the wire.\n *\n * The {@link OriginSchema} validates any incoming value and brands it so the\n * type system enforces \"only validated origins flow into hop lists.\" Internal\n * code that synthesizes an id (e.g. {@link randomOrigin}) uses\n * `OriginSchema.parse(...)` to produce a branded value from the raw bigint.\n */\nexport const OriginSchema = z\n\t.bigint()\n\t.check(z.refine((value) => value >= 0n && value < 1n << 62n, \"Origin must be a non-negative 62-bit integer\"))\n\t.brand(\"Origin\");\n\nexport type Origin = z.infer<typeof OriginSchema>;\n\n/**\n * The reserved id 0, meaning \"no identity\".\n *\n * It stands in for an endpoint that never declared one, and any number of endpoints can\n * be 0, so it identifies nothing: it is never a loop, never a publisher two chains have\n * in common, and never excluded from an advertisement.\n */\nexport const UNKNOWN_ORIGIN: Origin = OriginSchema.parse(0n);\n\n/**\n * Maximum length of a hop chain. Must match `MAX_HOPS` in Rust's `model/origin.rs`.\n *\n * Broadcasts with longer chains are rejected, which bounds loop detection and rejects\n * pathological announcements across clusters with unbounded forwarding.\n */\nexport const MAX_HOPS = 32;\n\n/**\n * Generate a fresh origin with a random non-zero id.\n *\n * `crypto.getRandomValues` is overkill for best-effort loop detection, but\n * used for slightly better distribution than `Math.random` at negligible cost.\n *\n * TEMPORARY: the wire format allows 62 bits, but older `@moq/lite` JS clients\n * decode `AnnounceInterest.exclude_hop` as a u53 (number) and throw on anything\n * > 2^53-1. To keep those clients alive against fresh peers, we cap the random\n * id at 53 bits. Restore to 62 bits once the u62 fix has propagated to deployed\n * bundles. Mirrors `Origin::random` in rs/moq-net.\n */\nexport function randomOrigin(): Origin {\n\tconst buf = new BigUint64Array(1);\n\tcrypto.getRandomValues(buf);\n\t// Mask to 53 bits.\n\tconst raw = buf[0] & 0x1f_ffff_ffff_ffffn;\n\t// Guard against the (astronomically unlikely) zero draw.\n\treturn OriginSchema.parse(raw === 0n ? 1n : raw);\n}\n"]}