@norskvideo/moq-net 0.1.1 → 0.1.2

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.
@@ -1 +1 @@
1
- {"version":3,"file":"reload.d.ts","sourceRoot":"","sources":["../../src/connection/reload.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,KAAK,MAAM,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAC3D,OAAO,KAAK,KAAK,IAAI,MAAM,YAAY,CAAC;AAExC,OAAO,EAAE,KAAK,YAAY,EAAW,KAAK,gBAAgB,EAAE,KAAK,iBAAiB,EAAE,MAAM,cAAc,CAAC;AACzG,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAEpD,wEAAwE;AACxE,MAAM,MAAM,WAAW,GAAG;IAGzB,OAAO,EAAE,mBAAmB,CAAC;IAI7B,UAAU,EAAE,MAAM,CAAC;IAInB,GAAG,EAAE,mBAAmB,CAAC;IAKzB,OAAO,CAAC,EAAE,mBAAmB,CAAC;CAC9B,CAAC;AAEF,wGAAwG;AACxG,MAAM,MAAM,WAAW,GAAG,YAAY,GAAG;IAGxC,OAAO,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC;IAGpC,GAAG,CAAC,EAAE,GAAG,GAAG,MAAM,CAAC,GAAG,GAAG,SAAS,CAAC,CAAC;IAGpC,KAAK,CAAC,EAAE,WAAW,CAAC;CACpB,CAAC;AAEF,oDAAoD;AACpD,MAAM,MAAM,YAAY,GAAG,YAAY,GAAG,WAAW,GAAG,cAAc,CAAC;AAEvE,uFAAuF;AACvF,qBAAa,MAAM;;IAClB,iEAAiE;IACjE,GAAG,EAAE,MAAM,CAAC,GAAG,GAAG,SAAS,CAAC,CAAC;IAE7B,sCAAsC;IACtC,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;IAEzB,iCAAiC;IACjC,MAAM,uBAA4C;IAElD,0EAA0E;IAC1E,WAAW,kCAAkD;IAK7D,wFAAwF;IACxF,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAmB;IAE9D,8EAA8E;IAC9E,YAAY,CAAC,EAAE,iBAAiB,CAAC;IAEjC,oFAAoF;IACpF,SAAS,EAAE,gBAAgB,GAAG,SAAS,CAAC;IAExC,+CAA+C;IAC/C,KAAK,EAAE,WAAW,CAAC;IAEnB,0FAA0F;IAC1F,OAAO,SAAgB;IAEvB,4FAA4F;IAC5F,MAAM,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IAYtB,YAAY,KAAK,CAAC,EAAE,WAAW,EAiB9B;IAgGD,0FAA0F;IAC1F,KAAK,SAGJ;CACD"}
1
+ {"version":3,"file":"reload.d.ts","sourceRoot":"","sources":["../../src/connection/reload.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,KAAK,MAAM,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAC3D,OAAO,KAAK,KAAK,IAAI,MAAM,YAAY,CAAC;AAExC,OAAO,EAAE,KAAK,YAAY,EAAW,KAAK,gBAAgB,EAAE,KAAK,iBAAiB,EAAE,MAAM,cAAc,CAAC;AACzG,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAEpD,wEAAwE;AACxE,MAAM,MAAM,WAAW,GAAG;IAGzB,OAAO,EAAE,mBAAmB,CAAC;IAI7B,UAAU,EAAE,MAAM,CAAC;IAInB,GAAG,EAAE,mBAAmB,CAAC;IAKzB,OAAO,CAAC,EAAE,mBAAmB,CAAC;CAC9B,CAAC;AAEF,wGAAwG;AACxG,MAAM,MAAM,WAAW,GAAG,YAAY,GAAG;IAGxC,OAAO,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC;IAGpC,GAAG,CAAC,EAAE,GAAG,GAAG,MAAM,CAAC,GAAG,GAAG,SAAS,CAAC,CAAC;IAGpC,KAAK,CAAC,EAAE,WAAW,CAAC;CACpB,CAAC;AAEF,oDAAoD;AACpD,MAAM,MAAM,YAAY,GAAG,YAAY,GAAG,WAAW,GAAG,cAAc,CAAC;AAEvE,uFAAuF;AACvF,qBAAa,MAAM;;IAClB,iEAAiE;IACjE,GAAG,EAAE,MAAM,CAAC,GAAG,GAAG,SAAS,CAAC,CAAC;IAE7B,sCAAsC;IACtC,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;IAEzB,iCAAiC;IACjC,MAAM,uBAA4C;IAElD,0EAA0E;IAC1E,WAAW,kCAAkD;IAK7D,wFAAwF;IACxF,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAmB;IAE9D,8EAA8E;IAC9E,YAAY,CAAC,EAAE,iBAAiB,CAAC;IAEjC,oFAAoF;IACpF,SAAS,EAAE,gBAAgB,GAAG,SAAS,CAAC;IAExC,+CAA+C;IAC/C,KAAK,EAAE,WAAW,CAAC;IAEnB,0FAA0F;IAC1F,OAAO,SAAgB;IAEvB,4FAA4F;IAC5F,MAAM,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IAgBtB,YAAY,KAAK,CAAC,EAAE,WAAW,EAmB9B;IAiGD,0FAA0F;IAC1F,KAAK,SAGJ;CACD"}
@@ -33,6 +33,9 @@ export class Reload {
33
33
  #retryStart;
34
34
  // Increased by 1 each time to trigger a reload.
35
35
  #tick = new Signal(0);
36
+ // Use the serialized URL as the reactive connection key. URL objects use identity
37
+ // equality, but replacing one with an equivalent instance should not reconnect.
38
+ #url;
36
39
  constructor(props) {
37
40
  this.url = Signal.from(props?.url);
38
41
  this.enabled = Signal.from(props?.enabled ?? false);
@@ -44,6 +47,7 @@ export class Reload {
44
47
  this.#closedResolve = resolve;
45
48
  this.#closedReject = reject;
46
49
  });
50
+ this.#url = this.signals.computed((effect) => effect.get(this.url)?.href);
47
51
  // Create a reactive root so cleanup is easier.
48
52
  this.signals.run(this.#connect.bind(this));
49
53
  this.signals.run(this.#runAnnounced.bind(this));
@@ -54,9 +58,10 @@ export class Reload {
54
58
  const enabled = effect.get(this.enabled);
55
59
  if (!enabled)
56
60
  return;
57
- const url = effect.get(this.url);
58
- if (!url)
61
+ const href = effect.get(this.#url);
62
+ if (!href)
59
63
  return;
64
+ const url = new URL(href);
60
65
  effect.set(this.status, "connecting", "disconnected");
61
66
  effect.spawn(async () => {
62
67
  try {
@@ -1 +1 @@
1
- {"version":3,"file":"reload.js","sourceRoot":"","sources":["../../src/connection/reload.ts"],"names":[],"mappings":"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","sourcesContent":["import { Effect, type Getter, Signal } from \"@moq/signals\";\nimport type * as Path from \"../path.ts\";\nimport { empty as emptyPath } from \"../path.ts\";\nimport { type ConnectProps, connect, type WebSocketOptions, type WebTransportProps } from \"./connect.ts\";\nimport type { Established } from \"./established.ts\";\n\n/** Exponential backoff settings for {@link Reload}'s reconnect loop. */\nexport type ReloadDelay = {\n\t// The delay in milliseconds before reconnecting.\n\t// default: 1000\n\tinitial: DOMHighResTimeStamp;\n\n\t// The multiplier for the delay.\n\t// default: 2\n\tmultiplier: number;\n\n\t// The maximum delay in milliseconds.\n\t// default: 30000\n\tmax: DOMHighResTimeStamp;\n\n\t// Maximum total time in milliseconds to spend retrying before giving up.\n\t// Resets after each successful connection. Set to 0 for unlimited retries.\n\t// default: 300000 (5 minutes)\n\ttimeout?: DOMHighResTimeStamp;\n};\n\n/** Options for {@link Reload}: connect options plus reactive URL/enabled signals and backoff tuning. */\nexport type ReloadProps = ConnectProps & {\n\t// Whether to reload the connection when it disconnects.\n\t// default: true\n\tenabled?: boolean | Signal<boolean>;\n\n\t// The URL of the relay server.\n\turl?: URL | Signal<URL | undefined>;\n\n\t// The delay for the reload.\n\tdelay?: ReloadDelay;\n};\n\n/** Current state of a {@link Reload} connection. */\nexport type ReloadStatus = \"connecting\" | \"connected\" | \"disconnected\";\n\n/** Maintains a MoQ connection, reconnecting with exponential backoff when it drops. */\nexport class Reload {\n\t/** Relay URL to connect to; updating it triggers a reconnect. */\n\turl: Signal<URL | undefined>;\n\n\t/** Whether reconnecting is active. */\n\tenabled: Signal<boolean>;\n\n\t/** Current connection status. */\n\tstatus = new Signal<ReloadStatus>(\"disconnected\");\n\n\t/** The currently established session, or undefined while disconnected. */\n\testablished = new Signal<Established | undefined>(undefined);\n\n\t// All actively announced broadcast paths, updated reactively.\n\t#announced = new Signal<Set<Path.Valid>>(new Set());\n\n\t/** The set of broadcast paths currently announced by the server, updated reactively. */\n\treadonly announced: Getter<Set<Path.Valid>> = this.#announced;\n\n\t/** WebTransport options applied to each connection attempt (not reactive). */\n\twebtransport?: WebTransportProps;\n\n\t/** WebSocket fallback options applied to each connection attempt (not reactive). */\n\twebsocket: WebSocketOptions | undefined;\n\n\t/** Backoff settings for the reconnect loop. */\n\tdelay: ReloadDelay;\n\n\t/** The reactive effect scope driving the connect loop; closed by {@link Reload.close}. */\n\tsignals = new Effect();\n\n\t/** Resolves when the reconnect loop stops via {@link Reload.close} or the retry timeout. */\n\tclosed: Promise<void>;\n\t#closedResolve!: () => void;\n\t#closedReject!: (err: Error) => void;\n\n\t#delay: DOMHighResTimeStamp;\n\n\t// Timestamp when the current retry sequence started (for timeout).\n\t#retryStart: DOMHighResTimeStamp | undefined;\n\n\t// Increased by 1 each time to trigger a reload.\n\t#tick = new Signal(0);\n\n\tconstructor(props?: ReloadProps) {\n\t\tthis.url = Signal.from(props?.url);\n\t\tthis.enabled = Signal.from(props?.enabled ?? false);\n\t\tthis.delay = props?.delay ?? { initial: 1000, multiplier: 2, max: 30000 };\n\t\tthis.webtransport = props?.webtransport;\n\t\tthis.websocket = props?.websocket;\n\n\t\tthis.#delay = this.delay.initial;\n\n\t\tthis.closed = new Promise((resolve, reject) => {\n\t\t\tthis.#closedResolve = resolve;\n\t\t\tthis.#closedReject = reject;\n\t\t});\n\n\t\t// Create a reactive root so cleanup is easier.\n\t\tthis.signals.run(this.#connect.bind(this));\n\t\tthis.signals.run(this.#runAnnounced.bind(this));\n\t}\n\n\t#connect(effect: Effect): void {\n\t\t// Will retry when the tick changes.\n\t\teffect.get(this.#tick);\n\n\t\tconst enabled = effect.get(this.enabled);\n\t\tif (!enabled) return;\n\n\t\tconst url = effect.get(this.url);\n\t\tif (!url) return;\n\n\t\teffect.set(this.status, \"connecting\", \"disconnected\");\n\n\t\teffect.spawn(async () => {\n\t\t\ttry {\n\t\t\t\tconst pending = connect(url, { websocket: this.websocket, webtransport: this.webtransport });\n\n\t\t\t\tconst connection = await Promise.race([effect.cancel, pending]);\n\t\t\t\tif (!connection) {\n\t\t\t\t\tpending.then((conn) => conn.close()).catch(() => {});\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\teffect.set(this.established, connection);\n\t\t\t\teffect.cleanup(() => connection.close());\n\n\t\t\t\teffect.set(this.status, \"connected\", \"disconnected\");\n\n\t\t\t\t// Reset the exponential backoff and timeout on success.\n\t\t\t\tthis.#delay = this.delay.initial;\n\t\t\t\tthis.#retryStart = undefined;\n\n\t\t\t\tawait Promise.race([effect.cancel, connection.closed]);\n\t\t\t} catch (err) {\n\t\t\t\tconsole.warn(\"connection error:\", err);\n\n\t\t\t\t// Track retry start for timeout.\n\t\t\t\tthis.#retryStart ??= performance.now();\n\n\t\t\t\tconst timeout = this.delay.timeout ?? 300000;\n\t\t\t\tif (timeout > 0) {\n\t\t\t\t\tconst elapsed = performance.now() - this.#retryStart;\n\t\t\t\t\tif (elapsed >= timeout) {\n\t\t\t\t\t\tconsole.warn(\"reconnect timed out\");\n\t\t\t\t\t\tthis.#closedReject(err instanceof Error ? err : new Error(String(err)));\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tconst tick = this.#tick.peek() + 1;\n\t\t\t\teffect.timer(() => this.#tick.update((prev) => Math.max(prev, tick)), this.#delay);\n\n\t\t\t\tthis.#delay = Math.min(this.#delay * this.delay.multiplier, this.delay.max);\n\t\t\t}\n\t\t});\n\t}\n\n\t#runAnnounced(effect: Effect): void {\n\t\tthis.#announced.set(new Set());\n\n\t\tconst conn = effect.get(this.established);\n\t\tif (!conn) return;\n\n\t\teffect.cleanup(() => this.#announced.set(new Set()));\n\n\t\t// Cloudflare's relay does not yet support SUBSCRIBE_NAMESPACE, so\n\t\t// skip announce subscriptions entirely for those hosts.\n\t\tif (conn.url.hostname.endsWith(\"mediaoverquic.com\")) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst announced = conn.announced(emptyPath());\n\t\teffect.cleanup(() => announced.close());\n\n\t\teffect.spawn(async () => {\n\t\t\ttry {\n\t\t\t\tfor (;;) {\n\t\t\t\t\tconst entry = await Promise.race([effect.cancel, announced.next()]);\n\t\t\t\t\tif (!entry) break;\n\n\t\t\t\t\tthis.#announced.mutate((active) => {\n\t\t\t\t\t\tif (entry.active) {\n\t\t\t\t\t\t\tactive.add(entry.path);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tactive.delete(entry.path);\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\tthis.#announced.set(new Set());\n\t\t\t\tthrow err;\n\t\t\t}\n\t\t});\n\t}\n\n\t/** Stop reconnecting, close the current connection, and resolve {@link Reload.closed}. */\n\tclose() {\n\t\tthis.signals.close();\n\t\tthis.#closedResolve();\n\t}\n}\n"]}
1
+ {"version":3,"file":"reload.js","sourceRoot":"","sources":["../../src/connection/reload.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAe,MAAM,EAAE,MAAM,cAAc,CAAC;AAE3D,OAAO,EAAE,KAAK,IAAI,SAAS,EAAE,MAAM,YAAY,CAAC;AAChD,OAAO,EAAqB,OAAO,EAAiD,MAAM,cAAc,CAAC;AAuCzG,uFAAuF;AACvF,MAAM,OAAO,MAAM;IAClB,iEAAiE;IACjE,GAAG,CAA0B;IAE7B,sCAAsC;IACtC,OAAO,CAAkB;IAEzB,iCAAiC;IACjC,MAAM,GAAG,IAAI,MAAM,CAAe,cAAc,CAAC,CAAC;IAElD,0EAA0E;IAC1E,WAAW,GAAG,IAAI,MAAM,CAA0B,SAAS,CAAC,CAAC;IAE7D,8DAA8D;IAC9D,UAAU,GAAG,IAAI,MAAM,CAAkB,IAAI,GAAG,EAAE,CAAC,CAAC;IAEpD,wFAAwF;IAC/E,SAAS,GAA4B,IAAI,CAAC,UAAU,CAAC;IAE9D,8EAA8E;IAC9E,YAAY,CAAqB;IAEjC,oFAAoF;IACpF,SAAS,CAA+B;IAExC,+CAA+C;IAC/C,KAAK,CAAc;IAEnB,0FAA0F;IAC1F,OAAO,GAAG,IAAI,MAAM,EAAE,CAAC;IAEvB,4FAA4F;IAC5F,MAAM,CAAgB;IACtB,cAAc,CAAc;IAC5B,aAAa,CAAwB;IAErC,MAAM,CAAsB;IAE5B,mEAAmE;IACnE,WAAW,CAAkC;IAE7C,gDAAgD;IAChD,KAAK,GAAG,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC;IAEtB,kFAAkF;IAClF,gFAAgF;IAChF,IAAI,CAA6B;IAEjC,YAAY,KAAmB;QAC9B,IAAI,CAAC,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;QACnC,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,OAAO,IAAI,KAAK,CAAC,CAAC;QACpD,IAAI,CAAC,KAAK,GAAG,KAAK,EAAE,KAAK,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC;QAC1E,IAAI,CAAC,YAAY,GAAG,KAAK,EAAE,YAAY,CAAC;QACxC,IAAI,CAAC,SAAS,GAAG,KAAK,EAAE,SAAS,CAAC;QAElC,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC;QAEjC,IAAI,CAAC,MAAM,GAAG,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YAC7C,IAAI,CAAC,cAAc,GAAG,OAAO,CAAC;YAC9B,IAAI,CAAC,aAAa,GAAG,MAAM,CAAC;QAC7B,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,CAAC;QAE1E,+CAA+C;QAC/C,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;QAC3C,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IACjD,CAAC;IAED,QAAQ,CAAC,MAAc;QACtB,oCAAoC;QACpC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAEvB,MAAM,OAAO,GAAG,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACzC,IAAI,CAAC,OAAO;YAAE,OAAO;QAErB,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACnC,IAAI,CAAC,IAAI;YAAE,OAAO;QAClB,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,CAAC;QAE1B,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,YAAY,EAAE,cAAc,CAAC,CAAC;QAEtD,MAAM,CAAC,KAAK,CAAC,KAAK,IAAI,EAAE;YACvB,IAAI,CAAC;gBACJ,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,YAAY,EAAE,IAAI,CAAC,YAAY,EAAE,CAAC,CAAC;gBAE7F,MAAM,UAAU,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;gBAChE,IAAI,CAAC,UAAU,EAAE,CAAC;oBACjB,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;oBACrD,OAAO;gBACR,CAAC;gBAED,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,EAAE,UAAU,CAAC,CAAC;gBACzC,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC,CAAC;gBAEzC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,WAAW,EAAE,cAAc,CAAC,CAAC;gBAErD,wDAAwD;gBACxD,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC;gBACjC,IAAI,CAAC,WAAW,GAAG,SAAS,CAAC;gBAE7B,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC;YACxD,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACd,OAAO,CAAC,IAAI,CAAC,mBAAmB,EAAE,GAAG,CAAC,CAAC;gBAEvC,iCAAiC;gBACjC,IAAI,CAAC,WAAW,KAAK,WAAW,CAAC,GAAG,EAAE,CAAC;gBAEvC,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,IAAI,MAAM,CAAC;gBAC7C,IAAI,OAAO,GAAG,CAAC,EAAE,CAAC;oBACjB,MAAM,OAAO,GAAG,WAAW,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,WAAW,CAAC;oBACrD,IAAI,OAAO,IAAI,OAAO,EAAE,CAAC;wBACxB,OAAO,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC;wBACpC,IAAI,CAAC,aAAa,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;wBACxE,OAAO;oBACR,CAAC;gBACF,CAAC;gBAED,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;gBACnC,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;gBAEnF,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YAC7E,CAAC;QACF,CAAC,CAAC,CAAC;IACJ,CAAC;IAED,aAAa,CAAC,MAAc;QAC3B,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,GAAG,EAAE,CAAC,CAAC;QAE/B,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QAC1C,IAAI,CAAC,IAAI;YAAE,OAAO;QAElB,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,GAAG,EAAE,CAAC,CAAC,CAAC;QAErD,kEAAkE;QAClE,wDAAwD;QACxD,IAAI,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,mBAAmB,CAAC,EAAE,CAAC;YACrD,OAAO;QACR,CAAC;QAED,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,SAAS,EAAE,CAAC,CAAC;QAC9C,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC,CAAC;QAExC,MAAM,CAAC,KAAK,CAAC,KAAK,IAAI,EAAE;YACvB,IAAI,CAAC;gBACJ,SAAS,CAAC;oBACT,MAAM,KAAK,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;oBACpE,IAAI,CAAC,KAAK;wBAAE,MAAM;oBAElB,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE;wBACjC,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;4BAClB,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;wBACxB,CAAC;6BAAM,CAAC;4BACP,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;wBAC3B,CAAC;oBACF,CAAC,CAAC,CAAC;gBACJ,CAAC;YACF,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACd,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,GAAG,EAAE,CAAC,CAAC;gBAC/B,MAAM,GAAG,CAAC;YACX,CAAC;QACF,CAAC,CAAC,CAAC;IACJ,CAAC;IAED,0FAA0F;IAC1F,KAAK;QACJ,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;QACrB,IAAI,CAAC,cAAc,EAAE,CAAC;IACvB,CAAC;CACD","sourcesContent":["import { Effect, type Getter, Signal } from \"@moq/signals\";\nimport type * as Path from \"../path.ts\";\nimport { empty as emptyPath } from \"../path.ts\";\nimport { type ConnectProps, connect, type WebSocketOptions, type WebTransportProps } from \"./connect.ts\";\nimport type { Established } from \"./established.ts\";\n\n/** Exponential backoff settings for {@link Reload}'s reconnect loop. */\nexport type ReloadDelay = {\n\t// The delay in milliseconds before reconnecting.\n\t// default: 1000\n\tinitial: DOMHighResTimeStamp;\n\n\t// The multiplier for the delay.\n\t// default: 2\n\tmultiplier: number;\n\n\t// The maximum delay in milliseconds.\n\t// default: 30000\n\tmax: DOMHighResTimeStamp;\n\n\t// Maximum total time in milliseconds to spend retrying before giving up.\n\t// Resets after each successful connection. Set to 0 for unlimited retries.\n\t// default: 300000 (5 minutes)\n\ttimeout?: DOMHighResTimeStamp;\n};\n\n/** Options for {@link Reload}: connect options plus reactive URL/enabled signals and backoff tuning. */\nexport type ReloadProps = ConnectProps & {\n\t// Whether to reload the connection when it disconnects.\n\t// default: true\n\tenabled?: boolean | Signal<boolean>;\n\n\t// The URL of the relay server.\n\turl?: URL | Signal<URL | undefined>;\n\n\t// The delay for the reload.\n\tdelay?: ReloadDelay;\n};\n\n/** Current state of a {@link Reload} connection. */\nexport type ReloadStatus = \"connecting\" | \"connected\" | \"disconnected\";\n\n/** Maintains a MoQ connection, reconnecting with exponential backoff when it drops. */\nexport class Reload {\n\t/** Relay URL to connect to; updating it triggers a reconnect. */\n\turl: Signal<URL | undefined>;\n\n\t/** Whether reconnecting is active. */\n\tenabled: Signal<boolean>;\n\n\t/** Current connection status. */\n\tstatus = new Signal<ReloadStatus>(\"disconnected\");\n\n\t/** The currently established session, or undefined while disconnected. */\n\testablished = new Signal<Established | undefined>(undefined);\n\n\t// All actively announced broadcast paths, updated reactively.\n\t#announced = new Signal<Set<Path.Valid>>(new Set());\n\n\t/** The set of broadcast paths currently announced by the server, updated reactively. */\n\treadonly announced: Getter<Set<Path.Valid>> = this.#announced;\n\n\t/** WebTransport options applied to each connection attempt (not reactive). */\n\twebtransport?: WebTransportProps;\n\n\t/** WebSocket fallback options applied to each connection attempt (not reactive). */\n\twebsocket: WebSocketOptions | undefined;\n\n\t/** Backoff settings for the reconnect loop. */\n\tdelay: ReloadDelay;\n\n\t/** The reactive effect scope driving the connect loop; closed by {@link Reload.close}. */\n\tsignals = new Effect();\n\n\t/** Resolves when the reconnect loop stops via {@link Reload.close} or the retry timeout. */\n\tclosed: Promise<void>;\n\t#closedResolve!: () => void;\n\t#closedReject!: (err: Error) => void;\n\n\t#delay: DOMHighResTimeStamp;\n\n\t// Timestamp when the current retry sequence started (for timeout).\n\t#retryStart: DOMHighResTimeStamp | undefined;\n\n\t// Increased by 1 each time to trigger a reload.\n\t#tick = new Signal(0);\n\n\t// Use the serialized URL as the reactive connection key. URL objects use identity\n\t// equality, but replacing one with an equivalent instance should not reconnect.\n\t#url: Getter<string | undefined>;\n\n\tconstructor(props?: ReloadProps) {\n\t\tthis.url = Signal.from(props?.url);\n\t\tthis.enabled = Signal.from(props?.enabled ?? false);\n\t\tthis.delay = props?.delay ?? { initial: 1000, multiplier: 2, max: 30000 };\n\t\tthis.webtransport = props?.webtransport;\n\t\tthis.websocket = props?.websocket;\n\n\t\tthis.#delay = this.delay.initial;\n\n\t\tthis.closed = new Promise((resolve, reject) => {\n\t\t\tthis.#closedResolve = resolve;\n\t\t\tthis.#closedReject = reject;\n\t\t});\n\n\t\tthis.#url = this.signals.computed((effect) => effect.get(this.url)?.href);\n\n\t\t// Create a reactive root so cleanup is easier.\n\t\tthis.signals.run(this.#connect.bind(this));\n\t\tthis.signals.run(this.#runAnnounced.bind(this));\n\t}\n\n\t#connect(effect: Effect): void {\n\t\t// Will retry when the tick changes.\n\t\teffect.get(this.#tick);\n\n\t\tconst enabled = effect.get(this.enabled);\n\t\tif (!enabled) return;\n\n\t\tconst href = effect.get(this.#url);\n\t\tif (!href) return;\n\t\tconst url = new URL(href);\n\n\t\teffect.set(this.status, \"connecting\", \"disconnected\");\n\n\t\teffect.spawn(async () => {\n\t\t\ttry {\n\t\t\t\tconst pending = connect(url, { websocket: this.websocket, webtransport: this.webtransport });\n\n\t\t\t\tconst connection = await Promise.race([effect.cancel, pending]);\n\t\t\t\tif (!connection) {\n\t\t\t\t\tpending.then((conn) => conn.close()).catch(() => {});\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\teffect.set(this.established, connection);\n\t\t\t\teffect.cleanup(() => connection.close());\n\n\t\t\t\teffect.set(this.status, \"connected\", \"disconnected\");\n\n\t\t\t\t// Reset the exponential backoff and timeout on success.\n\t\t\t\tthis.#delay = this.delay.initial;\n\t\t\t\tthis.#retryStart = undefined;\n\n\t\t\t\tawait Promise.race([effect.cancel, connection.closed]);\n\t\t\t} catch (err) {\n\t\t\t\tconsole.warn(\"connection error:\", err);\n\n\t\t\t\t// Track retry start for timeout.\n\t\t\t\tthis.#retryStart ??= performance.now();\n\n\t\t\t\tconst timeout = this.delay.timeout ?? 300000;\n\t\t\t\tif (timeout > 0) {\n\t\t\t\t\tconst elapsed = performance.now() - this.#retryStart;\n\t\t\t\t\tif (elapsed >= timeout) {\n\t\t\t\t\t\tconsole.warn(\"reconnect timed out\");\n\t\t\t\t\t\tthis.#closedReject(err instanceof Error ? err : new Error(String(err)));\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tconst tick = this.#tick.peek() + 1;\n\t\t\t\teffect.timer(() => this.#tick.update((prev) => Math.max(prev, tick)), this.#delay);\n\n\t\t\t\tthis.#delay = Math.min(this.#delay * this.delay.multiplier, this.delay.max);\n\t\t\t}\n\t\t});\n\t}\n\n\t#runAnnounced(effect: Effect): void {\n\t\tthis.#announced.set(new Set());\n\n\t\tconst conn = effect.get(this.established);\n\t\tif (!conn) return;\n\n\t\teffect.cleanup(() => this.#announced.set(new Set()));\n\n\t\t// Cloudflare's relay does not yet support SUBSCRIBE_NAMESPACE, so\n\t\t// skip announce subscriptions entirely for those hosts.\n\t\tif (conn.url.hostname.endsWith(\"mediaoverquic.com\")) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst announced = conn.announced(emptyPath());\n\t\teffect.cleanup(() => announced.close());\n\n\t\teffect.spawn(async () => {\n\t\t\ttry {\n\t\t\t\tfor (;;) {\n\t\t\t\t\tconst entry = await Promise.race([effect.cancel, announced.next()]);\n\t\t\t\t\tif (!entry) break;\n\n\t\t\t\t\tthis.#announced.mutate((active) => {\n\t\t\t\t\t\tif (entry.active) {\n\t\t\t\t\t\t\tactive.add(entry.path);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tactive.delete(entry.path);\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\tthis.#announced.set(new Set());\n\t\t\t\tthrow err;\n\t\t\t}\n\t\t});\n\t}\n\n\t/** Stop reconnecting, close the current connection, and resolve {@link Reload.closed}. */\n\tclose() {\n\t\tthis.signals.close();\n\t\tthis.#closedResolve();\n\t}\n}\n"]}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=reload.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reload.test.d.ts","sourceRoot":"","sources":["../../src/connection/reload.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,39 @@
1
+ /* @ts-self-types="./reload.test.d.ts" */
2
+ import { expect, test } from "bun:test";
3
+ import { Reload } from "./reload.js";
4
+ async function settle() {
5
+ await new Promise((resolve) => setTimeout(resolve, 0));
6
+ }
7
+ test("equivalent URL instances do not restart a pending connection", async () => {
8
+ const original = globalThis.WebTransport;
9
+ let connects = 0;
10
+ class PendingWebTransport {
11
+ ready = new Promise(() => { });
12
+ closed = new Promise(() => { });
13
+ constructor() {
14
+ connects++;
15
+ }
16
+ close() { }
17
+ }
18
+ globalThis.WebTransport = PendingWebTransport;
19
+ const reload = new Reload({
20
+ enabled: true,
21
+ url: new URL("https://example.com/broadcast"),
22
+ websocket: { enabled: false },
23
+ });
24
+ try {
25
+ await settle();
26
+ expect(connects).toBe(1);
27
+ reload.url.set(new URL("https://example.com/broadcast"));
28
+ await settle();
29
+ expect(connects).toBe(1);
30
+ reload.url.set(new URL("https://example.com/other"));
31
+ await settle();
32
+ expect(connects).toBe(2);
33
+ }
34
+ finally {
35
+ reload.close();
36
+ globalThis.WebTransport = original;
37
+ }
38
+ });
39
+ //# sourceMappingURL=reload.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reload.test.js","sourceRoot":"","sources":["../../src/connection/reload.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,UAAU,CAAC;AACxC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,KAAK,UAAU,MAAM;IACpB,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC;AACxD,CAAC;AAED,IAAI,CAAC,8DAA8D,EAAE,KAAK,IAAI,EAAE;IAC/E,MAAM,QAAQ,GAAG,UAAU,CAAC,YAAY,CAAC;IACzC,IAAI,QAAQ,GAAG,CAAC,CAAC;IAEjB,MAAM,mBAAmB;QACxB,KAAK,GAAG,IAAI,OAAO,CAAO,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QACpC,MAAM,GAAG,IAAI,OAAO,CAAO,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QAErC;YACC,QAAQ,EAAE,CAAC;QACZ,CAAC;QAED,KAAK,KAAI,CAAC;KACV;IAED,UAAU,CAAC,YAAY,GAAG,mBAAqD,CAAC;IAChF,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC;QACzB,OAAO,EAAE,IAAI;QACb,GAAG,EAAE,IAAI,GAAG,CAAC,+BAA+B,CAAC;QAC7C,SAAS,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE;KAC7B,CAAC,CAAC;IAEH,IAAI,CAAC;QACJ,MAAM,MAAM,EAAE,CAAC;QACf,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAEzB,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,+BAA+B,CAAC,CAAC,CAAC;QACzD,MAAM,MAAM,EAAE,CAAC;QACf,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAEzB,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,2BAA2B,CAAC,CAAC,CAAC;QACrD,MAAM,MAAM,EAAE,CAAC;QACf,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC1B,CAAC;YAAS,CAAC;QACV,MAAM,CAAC,KAAK,EAAE,CAAC;QACf,UAAU,CAAC,YAAY,GAAG,QAAQ,CAAC;IACpC,CAAC;AACF,CAAC,CAAC,CAAC","sourcesContent":["import { expect, test } from \"bun:test\";\nimport { Reload } from \"./reload.ts\";\n\nasync function settle() {\n\tawait new Promise((resolve) => setTimeout(resolve, 0));\n}\n\ntest(\"equivalent URL instances do not restart a pending connection\", async () => {\n\tconst original = globalThis.WebTransport;\n\tlet connects = 0;\n\n\tclass PendingWebTransport {\n\t\tready = new Promise<void>(() => {});\n\t\tclosed = new Promise<void>(() => {});\n\n\t\tconstructor() {\n\t\t\tconnects++;\n\t\t}\n\n\t\tclose() {}\n\t}\n\n\tglobalThis.WebTransport = PendingWebTransport as unknown as typeof WebTransport;\n\tconst reload = new Reload({\n\t\tenabled: true,\n\t\turl: new URL(\"https://example.com/broadcast\"),\n\t\twebsocket: { enabled: false },\n\t});\n\n\ttry {\n\t\tawait settle();\n\t\texpect(connects).toBe(1);\n\n\t\treload.url.set(new URL(\"https://example.com/broadcast\"));\n\t\tawait settle();\n\t\texpect(connects).toBe(1);\n\n\t\treload.url.set(new URL(\"https://example.com/other\"));\n\t\tawait settle();\n\t\texpect(connects).toBe(2);\n\t} finally {\n\t\treload.close();\n\t\tglobalThis.WebTransport = original;\n\t}\n});\n"]}
package/ietf/adapter.d.ts CHANGED
@@ -9,7 +9,7 @@ export interface Session {
9
9
  openNativeBi?(): Promise<Stream>;
10
10
  acceptBi(): Promise<Stream | undefined>;
11
11
  nextRequestId(): Promise<bigint | undefined>;
12
- close?(): void;
12
+ close(): void;
13
13
  readonly version: IetfVersion;
14
14
  }
15
15
  /**
@@ -23,6 +23,8 @@ export declare class NativeSession implements Session {
23
23
  openBi(): Promise<Stream>;
24
24
  acceptBi(): Promise<Stream | undefined>;
25
25
  nextRequestId(): Promise<bigint | undefined>;
26
+ /** Closes the underlying WebTransport session. */
27
+ close(): void;
26
28
  }
27
29
  /**
28
30
  * Converts v14-v16 control stream multiplexing into virtual bidi streams.
@@ -1 +1 @@
1
- {"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../../src/ietf/adapter.ts"],"names":[],"mappings":"AACA,OAAO,EAAU,MAAM,EAAe,MAAM,cAAc,CAAC;AAG3D,OAAO,EAAE,KAAK,WAAW,EAAW,MAAM,cAAc,CAAC;AAEzD;;;GAGG;AACH,MAAM,WAAW,OAAO;IACvB,MAAM,IAAI,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACnC,YAAY,CAAC,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;IACjC,QAAQ,IAAI,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IACxC,aAAa,IAAI,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IAC7C,KAAK,CAAC,IAAI,IAAI,CAAC;IACf,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAC;CAC9B;AAED;;;GAGG;AACH,qBAAa,aAAc,YAAW,OAAO;;IAG5C,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAC;IAE9B,YAAY,IAAI,EAAE,YAAY,EAAE,OAAO,EAAE,WAAW,EAGnD;IAEK,MAAM,IAAI,OAAO,CAAC,MAAM,CAAC,CAE9B;IAEK,QAAQ,IAAI,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAE5C;IAEK,aAAa,IAAI,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAIjD;CACD;AAmBD;;;;;;GAMG;AACH,qBAAa,oBAAqB,YAAW,OAAO;;IAQnD,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAC;IAyB9B,YAAY,IAAI,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,EAQhG;IAED;;;OAGG;IACG,QAAQ,IAAI,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAS5C;IAED;;;;;OAKG;IACH,MAAM,IAAI,MAAM,CAsDf;IAED;;OAEG;IACG,YAAY,IAAI,OAAO,CAAC,MAAM,CAAC,CAEpC;IAED;;OAEG;IACG,aAAa,IAAI,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAYjD;IAED;;;OAGG;IACG,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC,CAmDzB;IAwYD,KAAK,SA6BJ;CACD"}
1
+ {"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../../src/ietf/adapter.ts"],"names":[],"mappings":"AACA,OAAO,EAAU,MAAM,EAAe,MAAM,cAAc,CAAC;AAG3D,OAAO,EAAE,KAAK,WAAW,EAAW,MAAM,cAAc,CAAC;AAEzD;;;GAGG;AACH,MAAM,WAAW,OAAO;IACvB,MAAM,IAAI,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACnC,YAAY,CAAC,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;IACjC,QAAQ,IAAI,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IACxC,aAAa,IAAI,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IAC7C,KAAK,IAAI,IAAI,CAAC;IACd,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAC;CAC9B;AAED;;;GAGG;AACH,qBAAa,aAAc,YAAW,OAAO;;IAG5C,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAC;IAE9B,YAAY,IAAI,EAAE,YAAY,EAAE,OAAO,EAAE,WAAW,EAGnD;IAEK,MAAM,IAAI,OAAO,CAAC,MAAM,CAAC,CAE9B;IAEK,QAAQ,IAAI,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAE5C;IAEK,aAAa,IAAI,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAIjD;IAED,kDAAkD;IAClD,KAAK,SAEJ;CACD;AAmBD;;;;;;GAMG;AACH,qBAAa,oBAAqB,YAAW,OAAO;;IAQnD,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAC;IAyB9B,YAAY,IAAI,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,EAQhG;IAED;;;OAGG;IACG,QAAQ,IAAI,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAS5C;IAED;;;;;OAKG;IACH,MAAM,IAAI,MAAM,CAsDf;IAED;;OAEG;IACG,YAAY,IAAI,OAAO,CAAC,MAAM,CAAC,CAEpC;IAED;;OAEG;IACG,aAAa,IAAI,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAYjD;IAED;;;OAGG;IACG,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC,CAmDzB;IAwYD,KAAK,SA6BJ;CACD"}
package/ietf/adapter.js CHANGED
@@ -27,6 +27,10 @@ export class NativeSession {
27
27
  this.#requestId += 2n;
28
28
  return id;
29
29
  }
30
+ /** Closes the underlying WebTransport session. */
31
+ close() {
32
+ this.#quic.close();
33
+ }
30
34
  }
31
35
  // Route classification for control stream messages.
32
36
  const Route = {
@@ -1 +1 @@
1
- {"version":3,"file":"adapter.js","sourceRoot":"","sources":["../../src/ietf/adapter.ts"],"names":[],"mappings":"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","sourcesContent":["import { Mutex } from \"async-mutex\";\nimport { Reader, Stream, type Writer } from \"../stream.ts\";\nimport * as Varint from \"../varint.ts\";\nimport * as Namespace from \"./namespace.ts\";\nimport { type IetfVersion, Version } from \"./version.ts\";\n\n/**\n * Interface for opening outgoing bidi streams and allocating request IDs.\n * Implemented by both ControlStreamAdapter (v14-v16) and NativeSession (v17).\n */\nexport interface Session {\n\topenBi(): Stream | Promise<Stream>;\n\topenNativeBi?(): Promise<Stream>;\n\tacceptBi(): Promise<Stream | undefined>;\n\tnextRequestId(): Promise<bigint | undefined>;\n\tclose?(): void;\n\treadonly version: IetfVersion;\n}\n\n/**\n * v17 native session — thin wrapper around WebTransport.\n * Each request gets its own real bidi stream; no control stream multiplexing.\n */\nexport class NativeSession implements Session {\n\t#quic: WebTransport;\n\t#requestId = 0n;\n\treadonly version: IetfVersion;\n\n\tconstructor(quic: WebTransport, version: IetfVersion) {\n\t\tthis.#quic = quic;\n\t\tthis.version = version;\n\t}\n\n\tasync openBi(): Promise<Stream> {\n\t\treturn Stream.open(this.#quic, this.version);\n\t}\n\n\tasync acceptBi(): Promise<Stream | undefined> {\n\t\treturn Stream.accept(this.#quic, this.version);\n\t}\n\n\tasync nextRequestId(): Promise<bigint | undefined> {\n\t\tconst id = this.#requestId;\n\t\tthis.#requestId += 2n;\n\t\treturn id;\n\t}\n}\n\n// Route classification for control stream messages.\nconst Route = {\n\tNewRequest: 0, // Create virtual bidi stream, push initial message\n\tResponse: 1, // Push message to existing stream (keep open)\n\tErrorResponse: 2, // Push message to existing stream, then close\n\tCloseStream: 3, // Close stream recv (no bytes pushed)\n\tFollowUp: 4, // Push follow-up message to existing stream\n\tMaxRequestId: 5, // Update flow control\n\tIgnore: 6, // Connection-level, no routing\n\tGoAway: 7, // Terminal\n} as const;\ntype Route = (typeof Route)[keyof typeof Route];\n\ninterface StreamEntry {\n\tcontroller: ReadableStreamDefaultController<Uint8Array>;\n}\n\n/**\n * Converts v14-v16 control stream multiplexing into virtual bidi streams.\n *\n * Reads control messages, classifies them, and routes to virtual Stream objects.\n * Each request/response pair gets its own virtual Stream, making all versions\n * look like v17's stream-per-request model.\n */\nexport class ControlStreamAdapter implements Session {\n\t// WebTransport session (for opening real bidi streams in v16)\n\t#quic: WebTransport;\n\n\t// Control stream\n\t#reader: Reader;\n\t#writer: Writer;\n\t#writeMutex = new Mutex();\n\treadonly version: IetfVersion;\n\n\t// Virtual streams keyed by requestId\n\t#streams = new Map<bigint, StreamEntry>();\n\n\t// Namespace → requestId reverse lookup (v14/v15 namespace-keyed messages)\n\t#namespaces = new Map<string, bigint>();\n\n\t// requestId → namespace reverse lookup (for cleanup in #closeStream)\n\t#namespacesByRequestId = new Map<bigint, string>();\n\n\t// SubscribeNamespace requestIds — for routing 0x08/0x0E entries that lack requestId (v14/v15)\n\t#subscribeNamespaces = new Set<bigint>();\n\n\t// Incoming stream queue (for acceptBi)\n\t#incomingQueue: Stream[] = [];\n\t#incomingWaiters: ((stream: Stream | undefined) => void)[] = [];\n\n\t// Request ID flow control\n\t#requestId = 0n;\n\t#maxRequestId: bigint;\n\t#maxRequestIdResolves: (() => void)[] = [];\n\n\t#closed = false;\n\n\tconstructor(quic: WebTransport, controlStream: Stream, version: IetfVersion, maxRequestId: bigint) {\n\t\tthis.#quic = quic;\n\t\tthis.#reader = controlStream.reader;\n\t\tthis.#reader.version = version;\n\t\tthis.#writer = controlStream.writer;\n\t\tthis.#writer.version = version;\n\t\tthis.version = version;\n\t\tthis.#maxRequestId = maxRequestId;\n\t}\n\n\t/**\n\t * Accept the next incoming virtual bidi stream.\n\t * Blocks until a new request arrives on the control stream.\n\t */\n\tasync acceptBi(): Promise<Stream | undefined> {\n\t\tif (this.#closed) return undefined;\n\n\t\tconst queued = this.#incomingQueue.shift();\n\t\tif (queued) return queued;\n\n\t\treturn new Promise<Stream | undefined>((resolve) => {\n\t\t\tthis.#incomingWaiters.push(resolve);\n\t\t});\n\t}\n\n\t/**\n\t * Open an outgoing virtual bidi stream.\n\t * Buffers writes until the first full message is available, parses the\n\t * requestId (and namespace for PublishNamespace), self-registers, then\n\t * flushes. Subsequent writes go directly to the control stream.\n\t */\n\topenBi(): Stream {\n\t\tlet controller!: ReadableStreamDefaultController<Uint8Array>;\n\t\tlet registeredRequestId: bigint | undefined;\n\n\t\tconst readable = new ReadableStream<Uint8Array>({\n\t\t\tstart(c) {\n\t\t\t\tcontroller = c;\n\t\t\t},\n\t\t\tcancel: () => {\n\t\t\t\tif (registeredRequestId !== undefined) {\n\t\t\t\t\tthis.#streams.delete(registeredRequestId);\n\t\t\t\t}\n\t\t\t},\n\t\t});\n\n\t\tlet buffer = new Uint8Array(0);\n\t\tlet registered = false;\n\n\t\tconst sendWritable = new WritableStream<Uint8Array>({\n\t\t\twrite: async (chunk) => {\n\t\t\t\t// Always accumulate bytes and flush only complete messages\n\t\t\t\t// to prevent interleaving of partial messages from concurrent virtual streams.\n\t\t\t\tconst newBuf = new Uint8Array(buffer.length + chunk.length);\n\t\t\t\tnewBuf.set(buffer);\n\t\t\t\tnewBuf.set(chunk, buffer.length);\n\t\t\t\tbuffer = newBuf;\n\n\t\t\t\t// Try to flush complete messages from the buffer\n\t\t\t\tfor (;;) {\n\t\t\t\t\tconst boundary = this.#messageSize(buffer);\n\t\t\t\t\tif (boundary === undefined) break;\n\n\t\t\t\t\tconst toFlush = buffer.subarray(0, boundary);\n\t\t\t\t\tbuffer = buffer.subarray(boundary);\n\n\t\t\t\t\tif (!registered) {\n\t\t\t\t\t\t// First message: extract requestId and register before flushing\n\t\t\t\t\t\tconst parsed = this.#tryParseOutgoing(toFlush);\n\t\t\t\t\t\tif (parsed) {\n\t\t\t\t\t\t\tregisteredRequestId = parsed.requestId;\n\t\t\t\t\t\t\tthis.#streams.set(parsed.requestId, { controller });\n\t\t\t\t\t\t\tregistered = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tawait this.#writeMutex.runExclusive(() => this.#writer.write(toFlush));\n\t\t\t\t}\n\t\t\t},\n\t\t});\n\n\t\tconst stream = new Stream({ readable, writable: sendWritable });\n\t\tstream.reader.version = this.version;\n\t\tstream.writer.version = this.version;\n\t\treturn stream;\n\t}\n\n\t/**\n\t * Open a real WebTransport bidi stream (for v16 SubscribeNamespace).\n\t */\n\tasync openNativeBi(): Promise<Stream> {\n\t\treturn Stream.open(this.#quic, this.version);\n\t}\n\n\t/**\n\t * Allocate the next request ID, blocking if flow control limit reached.\n\t */\n\tasync nextRequestId(): Promise<bigint | undefined> {\n\t\tfor (;;) {\n\t\t\tif (this.#closed) return undefined;\n\t\t\tconst id = this.#requestId;\n\t\t\tif (id < this.#maxRequestId) {\n\t\t\t\tthis.#requestId += 2n;\n\t\t\t\treturn id;\n\t\t\t}\n\t\t\tawait new Promise<void>((resolve) => {\n\t\t\t\tthis.#maxRequestIdResolves.push(resolve);\n\t\t\t});\n\t\t}\n\t}\n\n\t/**\n\t * Main run loop — reads control stream messages and routes to virtual streams.\n\t * Must be called after construction. Runs until the control stream closes.\n\t */\n\tasync run(): Promise<void> {\n\t\ttry {\n\t\t\t// v16: also accept real bidi streams (for SubscribeNamespace)\n\t\t\tif (this.version === Version.DRAFT_16) {\n\t\t\t\tvoid this.#acceptNativeBidis();\n\t\t\t}\n\n\t\t\tfor (;;) {\n\t\t\t\tconst done = await this.#reader.done();\n\t\t\t\tif (done) break;\n\n\t\t\t\tconst typeId = await this.#reader.u53();\n\t\t\t\tconst size = await this.#reader.u16();\n\t\t\t\tconst body = await this.#reader.read(size);\n\n\t\t\t\tconst classified = await this.#classify(typeId, body);\n\n\t\t\t\tif (classified.route === Route.GoAway) {\n\t\t\t\t\tconsole.warn(\"received GOAWAY on control stream\");\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst { route, requestId } = classified;\n\n\t\t\t\tswitch (route) {\n\t\t\t\t\tcase Route.NewRequest:\n\t\t\t\t\t\tthis.#newRequest(typeId, size, body, requestId);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase Route.Response:\n\t\t\t\t\t\tthis.#pushMessage(requestId, typeId, size, body);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase Route.ErrorResponse:\n\t\t\t\t\t\tthis.#pushMessage(requestId, typeId, size, body);\n\t\t\t\t\t\tthis.#closeStream(requestId);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase Route.CloseStream:\n\t\t\t\t\t\tthis.#closeStream(requestId);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase Route.FollowUp:\n\t\t\t\t\t\tthis.#pushMessage(requestId, typeId, size, body);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase Route.MaxRequestId:\n\t\t\t\t\t\tthis.#maxRequestId = requestId;\n\t\t\t\t\t\tfor (const resolve of this.#maxRequestIdResolves) resolve();\n\t\t\t\t\t\tthis.#maxRequestIdResolves = [];\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t} finally {\n\t\t\tthis.close();\n\t\t}\n\t}\n\n\t/** Accept real WebTransport bidi streams and queue them for acceptBi (v16). */\n\tasync #acceptNativeBidis(): Promise<void> {\n\t\ttry {\n\t\t\tfor (;;) {\n\t\t\t\tconst stream = await Stream.accept(this.#quic, this.version);\n\t\t\t\tif (!stream) break;\n\n\t\t\t\tconst waiter = this.#incomingWaiters.shift();\n\t\t\t\tif (waiter) {\n\t\t\t\t\twaiter(stream);\n\t\t\t\t} else {\n\t\t\t\t\tthis.#incomingQueue.push(stream);\n\t\t\t\t}\n\t\t\t}\n\t\t} catch {\n\t\t\t// Session closed\n\t\t}\n\t}\n\n\t#newRequest(typeId: number, size: number, body: Uint8Array, requestId: bigint) {\n\t\tlet controller!: ReadableStreamDefaultController<Uint8Array>;\n\t\tconst readable = new ReadableStream<Uint8Array>({\n\t\t\tstart(c) {\n\t\t\t\tcontroller = c;\n\t\t\t},\n\t\t\tcancel: () => {\n\t\t\t\tthis.#streams.delete(requestId);\n\t\t\t},\n\t\t});\n\n\t\tconst sendWritable = this.#createSendWritable();\n\n\t\tconst stream = new Stream({ readable, writable: sendWritable });\n\t\tstream.reader.version = this.version;\n\t\tstream.writer.version = this.version;\n\n\t\tthis.#streams.set(requestId, { controller });\n\n\t\t// Push initial message bytes so the dispatcher can read typeId + decode\n\t\tcontroller.enqueue(this.#encodeRaw(typeId, size, body));\n\n\t\t// Queue for acceptBi\n\t\tconst waiter = this.#incomingWaiters.shift();\n\t\tif (waiter) {\n\t\t\twaiter(stream);\n\t\t} else {\n\t\t\tthis.#incomingQueue.push(stream);\n\t\t}\n\t}\n\n\t#pushMessage(requestId: bigint, typeId: number, size: number, body: Uint8Array) {\n\t\tconst entry = this.#streams.get(requestId);\n\t\tif (!entry) {\n\t\t\tconsole.warn(`adapter: no stream for requestId=${requestId} typeId=0x${typeId.toString(16)}`);\n\t\t\treturn;\n\t\t}\n\t\ttry {\n\t\t\tentry.controller.enqueue(this.#encodeRaw(typeId, size, body));\n\t\t} catch {\n\t\t\t// Stream already closed\n\t\t}\n\t}\n\n\t#closeStream(requestId: bigint) {\n\t\tconst entry = this.#streams.get(requestId);\n\t\tif (!entry) return;\n\t\tconsole.debug(`adapter: closing stream requestId=${requestId}`);\n\t\tthis.#streams.delete(requestId);\n\t\tthis.#subscribeNamespaces.delete(requestId);\n\t\tconst namespace = this.#namespacesByRequestId.get(requestId);\n\t\tif (namespace !== undefined) {\n\t\t\tthis.#namespaces.delete(namespace);\n\t\t\tthis.#namespacesByRequestId.delete(requestId);\n\t\t}\n\t\ttry {\n\t\t\tentry.controller.close();\n\t\t} catch {\n\t\t\t// Already closed\n\t\t}\n\t}\n\n\t/**\n\t * Returns the total byte size of the first complete message in buffer,\n\t * or undefined if the buffer doesn't contain a complete message yet.\n\t * Message format: [typeId varint][size u16 BE][body of `size` bytes]\n\t */\n\t#messageSize(buffer: Uint8Array): number | undefined {\n\t\tif (buffer.length === 0) return undefined;\n\n\t\tconst typeSize = 1 << ((buffer[0] & 0xc0) >> 6);\n\t\tif (buffer.length < typeSize) return undefined;\n\n\t\tconst [, afterType] = Varint.decode(buffer);\n\t\tif (afterType.length < 2) return undefined;\n\n\t\tconst size = (afterType[0] << 8) | afterType[1];\n\t\tconst totalSize = buffer.length - afterType.length + 2 + size;\n\t\tif (buffer.length < totalSize) return undefined;\n\n\t\treturn totalSize;\n\t}\n\n\t/**\n\t * Try to parse the first outgoing message from accumulated bytes.\n\t * Returns the requestId if enough data is available, undefined otherwise.\n\t */\n\t#tryParseOutgoing(buffer: Uint8Array): { requestId: bigint } | undefined {\n\t\tif (buffer.length === 0) return undefined;\n\n\t\t// Check typeId varint size before decoding\n\t\tconst typeSize = 1 << ((buffer[0] & 0xc0) >> 6);\n\t\tif (buffer.length < typeSize) return undefined;\n\n\t\tconst [typeId, afterType] = Varint.decode(buffer);\n\n\t\t// Need 2 bytes for u16 size\n\t\tif (afterType.length < 2) return undefined;\n\n\t\tconst size = (afterType[0] << 8) | afterType[1];\n\t\tconst bodyStart = afterType.subarray(2);\n\n\t\t// Need full body\n\t\tif (bodyStart.length < size) return undefined;\n\n\t\tconst body = bodyStart.subarray(0, size);\n\n\t\t// Decode requestId from body (QUIC varint)\n\t\tconst [reqId] = Varint.decode(body);\n\t\tconst requestId = BigInt(reqId);\n\n\t\t// PublishNamespace (0x06): also parse namespace for v14/v15 reverse lookup\n\t\tif (typeId === 0x06) {\n\t\t\ttry {\n\t\t\t\tconst [, afterReqId] = Varint.decode(body);\n\t\t\t\tthis.#parseAndRegisterNamespace(afterReqId, requestId);\n\t\t\t} catch {\n\t\t\t\t// Non-critical: only needed for v14/v15 PublishNamespaceDone/Cancel\n\t\t\t}\n\t\t}\n\n\t\t// SubscribeNamespace (0x11): register for follow-up routing\n\t\tif (typeId === 0x11) {\n\t\t\tthis.#subscribeNamespaces.add(requestId);\n\t\t}\n\n\t\treturn { requestId };\n\t}\n\n\t/**\n\t * Parse a namespace from raw bytes and register it for reverse lookup.\n\t */\n\t#parseAndRegisterNamespace(buf: Uint8Array, requestId: bigint) {\n\t\tconst decoder = new TextDecoder();\n\t\tconst [partCount, afterCount] = Varint.decode(buf);\n\t\tlet cursor = afterCount;\n\t\tconst parts: string[] = [];\n\t\tfor (let i = 0; i < partCount; i++) {\n\t\t\tconst [len, afterLen] = Varint.decode(cursor);\n\t\t\tparts.push(decoder.decode(afterLen.subarray(0, len)));\n\t\t\tcursor = afterLen.subarray(len);\n\t\t}\n\t\tconst namespace = parts.join(\"/\");\n\t\tthis.#namespaces.set(namespace, requestId);\n\t\tthis.#namespacesByRequestId.set(requestId, namespace);\n\t}\n\n\t/** Create a WritableStream that buffers and writes complete messages to the control stream under mutex. */\n\t#createSendWritable(): WritableStream<Uint8Array> {\n\t\tlet buffer = new Uint8Array(0);\n\t\treturn new WritableStream<Uint8Array>({\n\t\t\twrite: async (chunk) => {\n\t\t\t\tconst newBuf = new Uint8Array(buffer.length + chunk.length);\n\t\t\t\tnewBuf.set(buffer);\n\t\t\t\tnewBuf.set(chunk, buffer.length);\n\t\t\t\tbuffer = newBuf;\n\n\t\t\t\tfor (;;) {\n\t\t\t\t\tconst boundary = this.#messageSize(buffer);\n\t\t\t\t\tif (boundary === undefined) break;\n\n\t\t\t\t\tconst toFlush = buffer.subarray(0, boundary);\n\t\t\t\t\tbuffer = buffer.subarray(boundary);\n\t\t\t\t\tawait this.#writeMutex.runExclusive(() => this.#writer.write(toFlush));\n\t\t\t\t}\n\t\t\t},\n\t\t});\n\t}\n\n\t/** Encode raw message bytes: [typeId varint][size u16 BE][body] */\n\t#encodeRaw(typeId: number, size: number, body: Uint8Array): Uint8Array {\n\t\t// v14-v16 always use QUIC varint\n\t\tconst typeIdBytes = Varint.encodeTo(new ArrayBuffer(9), typeId);\n\t\tconst result = new Uint8Array(typeIdBytes.byteLength + 2 + body.byteLength);\n\t\tresult.set(typeIdBytes, 0);\n\t\tconst sizeView = new DataView(result.buffer, typeIdBytes.byteLength, 2);\n\t\tsizeView.setUint16(0, size);\n\t\tresult.set(body, typeIdBytes.byteLength + 2);\n\t\treturn result;\n\t}\n\n\t/**\n\t * Classify a control message and extract its requestId for routing.\n\t */\n\tasync #classify(\n\t\ttypeId: number,\n\t\tbody: Uint8Array,\n\t): Promise<{ route: typeof Route.GoAway } | { route: Exclude<Route, typeof Route.GoAway>; requestId: bigint }> {\n\t\tconst readRequestId = async (): Promise<bigint> => {\n\t\t\tconst r = new Reader(undefined, body, this.version);\n\t\t\treturn await r.u62();\n\t\t};\n\n\t\tconst readNamespaceRequestId = async (): Promise<bigint> => {\n\t\t\tconst r = new Reader(undefined, body, this.version);\n\t\t\tconst namespace = await Namespace.decode(r);\n\t\t\tconst requestId = this.#namespaces.get(namespace);\n\t\t\tif (requestId === undefined) throw new Error(`unknown namespace: ${namespace}`);\n\t\t\tthis.#namespaces.delete(namespace);\n\t\t\treturn requestId;\n\t\t};\n\n\t\tswitch (typeId) {\n\t\t\t// === FollowUp: route to existing stream ===\n\t\t\tcase 0x02: {\n\t\t\t\t// SubscribeUpdate / REQUEST_UPDATE\n\t\t\t\tconst requestId = await readRequestId();\n\t\t\t\treturn { route: Route.FollowUp, requestId };\n\t\t\t}\n\n\t\t\t// === NewRequest: create virtual stream ===\n\t\t\tcase 0x03: // Subscribe\n\t\t\tcase 0x16: // Fetch\n\t\t\tcase 0x1d: // Publish\n\t\t\tcase 0x0d: {\n\t\t\t\t// TrackStatusRequest\n\t\t\t\tconst requestId = await readRequestId();\n\t\t\t\treturn { route: Route.NewRequest, requestId };\n\t\t\t}\n\t\t\tcase 0x06: {\n\t\t\t\t// PublishNamespace — also store namespace for v14/v15 reverse lookup\n\t\t\t\tconst r = new Reader(undefined, body, this.version);\n\t\t\t\tconst requestId = await r.u62();\n\t\t\t\tconst namespace = await Namespace.decode(r);\n\t\t\t\tthis.#namespaces.set(namespace, requestId);\n\t\t\t\tthis.#namespacesByRequestId.set(requestId, namespace);\n\t\t\t\treturn { route: Route.NewRequest, requestId };\n\t\t\t}\n\t\t\tcase 0x11: {\n\t\t\t\t// SubscribeNamespace (v14/v15 only on control stream)\n\t\t\t\tif (this.version !== Version.DRAFT_14 && this.version !== Version.DRAFT_15) {\n\t\t\t\t\tthrow new Error(\"unexpected SubscribeNamespace on control stream\");\n\t\t\t\t}\n\t\t\t\tconst requestId = await readRequestId();\n\t\t\t\treturn { route: Route.NewRequest, requestId };\n\t\t\t}\n\n\t\t\t// === Response: push bytes, keep stream open ===\n\t\t\tcase 0x04: {\n\t\t\t\t// SubscribeOk\n\t\t\t\tconst requestId = await readRequestId();\n\t\t\t\treturn { route: Route.Response, requestId };\n\t\t\t}\n\t\t\tcase 0x18: {\n\t\t\t\t// FetchOk\n\t\t\t\tconst requestId = await readRequestId();\n\t\t\t\treturn { route: Route.Response, requestId };\n\t\t\t}\n\t\t\tcase 0x1e: {\n\t\t\t\t// PublishOk\n\t\t\t\tconst requestId = await readRequestId();\n\t\t\t\treturn { route: Route.Response, requestId };\n\t\t\t}\n\t\t\tcase 0x07: {\n\t\t\t\t// v14: PublishNamespaceOk, v15+: RequestOk\n\t\t\t\tconst requestId = await readRequestId();\n\t\t\t\treturn { route: Route.Response, requestId };\n\t\t\t}\n\t\t\tcase 0x12: {\n\t\t\t\t// SubscribeNamespaceOk (v14 only)\n\t\t\t\tif (this.version !== Version.DRAFT_14) throw new Error(\"unexpected SubscribeNamespaceOk\");\n\t\t\t\tconst requestId = await readRequestId();\n\t\t\t\treturn { route: Route.Response, requestId };\n\t\t\t}\n\n\t\t\t// === ErrorResponse: push bytes + close ===\n\t\t\tcase 0x05: {\n\t\t\t\t// SubscribeError (v14) / RequestError (v15+)\n\t\t\t\tconst requestId = await readRequestId();\n\t\t\t\treturn { route: Route.ErrorResponse, requestId };\n\t\t\t}\n\t\t\tcase 0x19: {\n\t\t\t\t// FetchError (v14 only)\n\t\t\t\tif (this.version !== Version.DRAFT_14) throw new Error(\"unexpected FetchError\");\n\t\t\t\tconst requestId = await readRequestId();\n\t\t\t\treturn { route: Route.ErrorResponse, requestId };\n\t\t\t}\n\t\t\tcase 0x1f: {\n\t\t\t\t// PublishError (v14 only)\n\t\t\t\tif (this.version !== Version.DRAFT_14) throw new Error(\"unexpected PublishError\");\n\t\t\t\tconst requestId = await readRequestId();\n\t\t\t\treturn { route: Route.ErrorResponse, requestId };\n\t\t\t}\n\t\t\tcase 0x08: {\n\t\t\t\tif (this.version === Version.DRAFT_14) {\n\t\t\t\t\t// PublishNamespaceError\n\t\t\t\t\tconst requestId = await readRequestId();\n\t\t\t\t\treturn { route: Route.ErrorResponse, requestId };\n\t\t\t\t}\n\t\t\t\t// v15: Namespace entry (no requestId) — route to SubscribeNamespace stream\n\t\t\t\tconst subNs08 = this.#subscribeNamespaces.values().next().value;\n\t\t\t\tif (subNs08 === undefined) throw new Error(\"unexpected message 0x08: no SubscribeNamespace stream\");\n\t\t\t\treturn { route: Route.FollowUp, requestId: subNs08 };\n\t\t\t}\n\t\t\tcase 0x0e: {\n\t\t\t\t// v15: NamespaceDone entry (no requestId) — route to SubscribeNamespace stream\n\t\t\t\tconst subNs0e = this.#subscribeNamespaces.values().next().value;\n\t\t\t\tif (subNs0e === undefined) throw new Error(\"unexpected message 0x0e: no SubscribeNamespace stream\");\n\t\t\t\treturn { route: Route.FollowUp, requestId: subNs0e };\n\t\t\t}\n\t\t\tcase 0x13: {\n\t\t\t\t// SubscribeNamespaceError (v14 only)\n\t\t\t\tif (this.version !== Version.DRAFT_14) throw new Error(\"unexpected SubscribeNamespaceError\");\n\t\t\t\tconst requestId = await readRequestId();\n\t\t\t\treturn { route: Route.ErrorResponse, requestId };\n\t\t\t}\n\n\t\t\t// === CloseStream: close recv (no bytes pushed) ===\n\t\t\tcase 0x0a: {\n\t\t\t\t// Unsubscribe\n\t\t\t\tconst requestId = await readRequestId();\n\t\t\t\treturn { route: Route.CloseStream, requestId };\n\t\t\t}\n\t\t\tcase 0x0b: {\n\t\t\t\t// PublishDone\n\t\t\t\tconst requestId = await readRequestId();\n\t\t\t\treturn { route: Route.CloseStream, requestId };\n\t\t\t}\n\t\t\tcase 0x17: {\n\t\t\t\t// FetchCancel\n\t\t\t\tconst requestId = await readRequestId();\n\t\t\t\treturn { route: Route.CloseStream, requestId };\n\t\t\t}\n\t\t\tcase 0x09: {\n\t\t\t\t// PublishNamespaceDone: v16 uses requestId, v14/v15 uses namespace\n\t\t\t\tif (this.version === Version.DRAFT_16) {\n\t\t\t\t\tconst requestId = await readRequestId();\n\t\t\t\t\treturn { route: Route.CloseStream, requestId };\n\t\t\t\t}\n\t\t\t\tconst requestId = await readNamespaceRequestId();\n\t\t\t\treturn { route: Route.CloseStream, requestId };\n\t\t\t}\n\t\t\tcase 0x0c: {\n\t\t\t\t// PublishNamespaceCancel: v16 uses requestId, v14/v15 uses namespace\n\t\t\t\tif (this.version === Version.DRAFT_16) {\n\t\t\t\t\tconst requestId = await readRequestId();\n\t\t\t\t\treturn { route: Route.CloseStream, requestId };\n\t\t\t\t}\n\t\t\t\tconst requestId = await readNamespaceRequestId();\n\t\t\t\treturn { route: Route.CloseStream, requestId };\n\t\t\t}\n\t\t\tcase 0x14: {\n\t\t\t\t// UnsubscribeNamespace (v14/v15 only)\n\t\t\t\tif (this.version !== Version.DRAFT_14 && this.version !== Version.DRAFT_15) {\n\t\t\t\t\tthrow new Error(\"unexpected UnsubscribeNamespace\");\n\t\t\t\t}\n\t\t\t\tconst requestId = await readRequestId();\n\t\t\t\treturn { route: Route.CloseStream, requestId };\n\t\t\t}\n\n\t\t\t// === Utility ===\n\t\t\tcase 0x15: {\n\t\t\t\t// MaxRequestId\n\t\t\t\tconst requestId = await readRequestId();\n\t\t\t\treturn { route: Route.MaxRequestId, requestId };\n\t\t\t}\n\t\t\tcase 0x1a: {\n\t\t\t\t// RequestsBlocked — connection-level, consume and ignore\n\t\t\t\tawait readRequestId();\n\t\t\t\treturn { route: Route.Ignore, requestId: 0n };\n\t\t\t}\n\n\t\t\t// === Terminal ===\n\t\t\tcase 0x10: // GoAway\n\t\t\t\treturn { route: Route.GoAway };\n\n\t\t\tdefault:\n\t\t\t\tthrow new Error(`unknown control message type: 0x${typeId.toString(16)}`);\n\t\t}\n\t}\n\n\tclose() {\n\t\tif (this.#closed) return;\n\t\tthis.#closed = true;\n\t\tconsole.debug(\"adapter: close() called\");\n\n\t\t// Close all virtual streams\n\t\tfor (const entry of this.#streams.values()) {\n\t\t\ttry {\n\t\t\t\tentry.controller.close();\n\t\t\t} catch {\n\t\t\t\t// Already closed\n\t\t\t}\n\t\t}\n\t\tthis.#streams.clear();\n\n\t\t// Resolve any waiting acceptBi callers\n\t\tfor (const waiter of this.#incomingWaiters) {\n\t\t\twaiter(undefined);\n\t\t}\n\t\tthis.#incomingWaiters = [];\n\n\t\t// Clear namespace mappings\n\t\tthis.#namespaces.clear();\n\t\tthis.#namespacesByRequestId.clear();\n\t\tthis.#subscribeNamespaces.clear();\n\n\t\t// Unblock maxRequestId waiters\n\t\tfor (const resolve of this.#maxRequestIdResolves) resolve();\n\t\tthis.#maxRequestIdResolves = [];\n\t}\n}\n"]}
1
+ {"version":3,"file":"adapter.js","sourceRoot":"","sources":["../../src/ietf/adapter.ts"],"names":[],"mappings":"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","sourcesContent":["import { Mutex } from \"async-mutex\";\nimport { Reader, Stream, type Writer } from \"../stream.ts\";\nimport * as Varint from \"../varint.ts\";\nimport * as Namespace from \"./namespace.ts\";\nimport { type IetfVersion, Version } from \"./version.ts\";\n\n/**\n * Interface for opening outgoing bidi streams and allocating request IDs.\n * Implemented by both ControlStreamAdapter (v14-v16) and NativeSession (v17).\n */\nexport interface Session {\n\topenBi(): Stream | Promise<Stream>;\n\topenNativeBi?(): Promise<Stream>;\n\tacceptBi(): Promise<Stream | undefined>;\n\tnextRequestId(): Promise<bigint | undefined>;\n\tclose(): void;\n\treadonly version: IetfVersion;\n}\n\n/**\n * v17 native session — thin wrapper around WebTransport.\n * Each request gets its own real bidi stream; no control stream multiplexing.\n */\nexport class NativeSession implements Session {\n\t#quic: WebTransport;\n\t#requestId = 0n;\n\treadonly version: IetfVersion;\n\n\tconstructor(quic: WebTransport, version: IetfVersion) {\n\t\tthis.#quic = quic;\n\t\tthis.version = version;\n\t}\n\n\tasync openBi(): Promise<Stream> {\n\t\treturn Stream.open(this.#quic, this.version);\n\t}\n\n\tasync acceptBi(): Promise<Stream | undefined> {\n\t\treturn Stream.accept(this.#quic, this.version);\n\t}\n\n\tasync nextRequestId(): Promise<bigint | undefined> {\n\t\tconst id = this.#requestId;\n\t\tthis.#requestId += 2n;\n\t\treturn id;\n\t}\n\n\t/** Closes the underlying WebTransport session. */\n\tclose() {\n\t\tthis.#quic.close();\n\t}\n}\n\n// Route classification for control stream messages.\nconst Route = {\n\tNewRequest: 0, // Create virtual bidi stream, push initial message\n\tResponse: 1, // Push message to existing stream (keep open)\n\tErrorResponse: 2, // Push message to existing stream, then close\n\tCloseStream: 3, // Close stream recv (no bytes pushed)\n\tFollowUp: 4, // Push follow-up message to existing stream\n\tMaxRequestId: 5, // Update flow control\n\tIgnore: 6, // Connection-level, no routing\n\tGoAway: 7, // Terminal\n} as const;\ntype Route = (typeof Route)[keyof typeof Route];\n\ninterface StreamEntry {\n\tcontroller: ReadableStreamDefaultController<Uint8Array>;\n}\n\n/**\n * Converts v14-v16 control stream multiplexing into virtual bidi streams.\n *\n * Reads control messages, classifies them, and routes to virtual Stream objects.\n * Each request/response pair gets its own virtual Stream, making all versions\n * look like v17's stream-per-request model.\n */\nexport class ControlStreamAdapter implements Session {\n\t// WebTransport session (for opening real bidi streams in v16)\n\t#quic: WebTransport;\n\n\t// Control stream\n\t#reader: Reader;\n\t#writer: Writer;\n\t#writeMutex = new Mutex();\n\treadonly version: IetfVersion;\n\n\t// Virtual streams keyed by requestId\n\t#streams = new Map<bigint, StreamEntry>();\n\n\t// Namespace → requestId reverse lookup (v14/v15 namespace-keyed messages)\n\t#namespaces = new Map<string, bigint>();\n\n\t// requestId → namespace reverse lookup (for cleanup in #closeStream)\n\t#namespacesByRequestId = new Map<bigint, string>();\n\n\t// SubscribeNamespace requestIds — for routing 0x08/0x0E entries that lack requestId (v14/v15)\n\t#subscribeNamespaces = new Set<bigint>();\n\n\t// Incoming stream queue (for acceptBi)\n\t#incomingQueue: Stream[] = [];\n\t#incomingWaiters: ((stream: Stream | undefined) => void)[] = [];\n\n\t// Request ID flow control\n\t#requestId = 0n;\n\t#maxRequestId: bigint;\n\t#maxRequestIdResolves: (() => void)[] = [];\n\n\t#closed = false;\n\n\tconstructor(quic: WebTransport, controlStream: Stream, version: IetfVersion, maxRequestId: bigint) {\n\t\tthis.#quic = quic;\n\t\tthis.#reader = controlStream.reader;\n\t\tthis.#reader.version = version;\n\t\tthis.#writer = controlStream.writer;\n\t\tthis.#writer.version = version;\n\t\tthis.version = version;\n\t\tthis.#maxRequestId = maxRequestId;\n\t}\n\n\t/**\n\t * Accept the next incoming virtual bidi stream.\n\t * Blocks until a new request arrives on the control stream.\n\t */\n\tasync acceptBi(): Promise<Stream | undefined> {\n\t\tif (this.#closed) return undefined;\n\n\t\tconst queued = this.#incomingQueue.shift();\n\t\tif (queued) return queued;\n\n\t\treturn new Promise<Stream | undefined>((resolve) => {\n\t\t\tthis.#incomingWaiters.push(resolve);\n\t\t});\n\t}\n\n\t/**\n\t * Open an outgoing virtual bidi stream.\n\t * Buffers writes until the first full message is available, parses the\n\t * requestId (and namespace for PublishNamespace), self-registers, then\n\t * flushes. Subsequent writes go directly to the control stream.\n\t */\n\topenBi(): Stream {\n\t\tlet controller!: ReadableStreamDefaultController<Uint8Array>;\n\t\tlet registeredRequestId: bigint | undefined;\n\n\t\tconst readable = new ReadableStream<Uint8Array>({\n\t\t\tstart(c) {\n\t\t\t\tcontroller = c;\n\t\t\t},\n\t\t\tcancel: () => {\n\t\t\t\tif (registeredRequestId !== undefined) {\n\t\t\t\t\tthis.#streams.delete(registeredRequestId);\n\t\t\t\t}\n\t\t\t},\n\t\t});\n\n\t\tlet buffer = new Uint8Array(0);\n\t\tlet registered = false;\n\n\t\tconst sendWritable = new WritableStream<Uint8Array>({\n\t\t\twrite: async (chunk) => {\n\t\t\t\t// Always accumulate bytes and flush only complete messages\n\t\t\t\t// to prevent interleaving of partial messages from concurrent virtual streams.\n\t\t\t\tconst newBuf = new Uint8Array(buffer.length + chunk.length);\n\t\t\t\tnewBuf.set(buffer);\n\t\t\t\tnewBuf.set(chunk, buffer.length);\n\t\t\t\tbuffer = newBuf;\n\n\t\t\t\t// Try to flush complete messages from the buffer\n\t\t\t\tfor (;;) {\n\t\t\t\t\tconst boundary = this.#messageSize(buffer);\n\t\t\t\t\tif (boundary === undefined) break;\n\n\t\t\t\t\tconst toFlush = buffer.subarray(0, boundary);\n\t\t\t\t\tbuffer = buffer.subarray(boundary);\n\n\t\t\t\t\tif (!registered) {\n\t\t\t\t\t\t// First message: extract requestId and register before flushing\n\t\t\t\t\t\tconst parsed = this.#tryParseOutgoing(toFlush);\n\t\t\t\t\t\tif (parsed) {\n\t\t\t\t\t\t\tregisteredRequestId = parsed.requestId;\n\t\t\t\t\t\t\tthis.#streams.set(parsed.requestId, { controller });\n\t\t\t\t\t\t\tregistered = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tawait this.#writeMutex.runExclusive(() => this.#writer.write(toFlush));\n\t\t\t\t}\n\t\t\t},\n\t\t});\n\n\t\tconst stream = new Stream({ readable, writable: sendWritable });\n\t\tstream.reader.version = this.version;\n\t\tstream.writer.version = this.version;\n\t\treturn stream;\n\t}\n\n\t/**\n\t * Open a real WebTransport bidi stream (for v16 SubscribeNamespace).\n\t */\n\tasync openNativeBi(): Promise<Stream> {\n\t\treturn Stream.open(this.#quic, this.version);\n\t}\n\n\t/**\n\t * Allocate the next request ID, blocking if flow control limit reached.\n\t */\n\tasync nextRequestId(): Promise<bigint | undefined> {\n\t\tfor (;;) {\n\t\t\tif (this.#closed) return undefined;\n\t\t\tconst id = this.#requestId;\n\t\t\tif (id < this.#maxRequestId) {\n\t\t\t\tthis.#requestId += 2n;\n\t\t\t\treturn id;\n\t\t\t}\n\t\t\tawait new Promise<void>((resolve) => {\n\t\t\t\tthis.#maxRequestIdResolves.push(resolve);\n\t\t\t});\n\t\t}\n\t}\n\n\t/**\n\t * Main run loop — reads control stream messages and routes to virtual streams.\n\t * Must be called after construction. Runs until the control stream closes.\n\t */\n\tasync run(): Promise<void> {\n\t\ttry {\n\t\t\t// v16: also accept real bidi streams (for SubscribeNamespace)\n\t\t\tif (this.version === Version.DRAFT_16) {\n\t\t\t\tvoid this.#acceptNativeBidis();\n\t\t\t}\n\n\t\t\tfor (;;) {\n\t\t\t\tconst done = await this.#reader.done();\n\t\t\t\tif (done) break;\n\n\t\t\t\tconst typeId = await this.#reader.u53();\n\t\t\t\tconst size = await this.#reader.u16();\n\t\t\t\tconst body = await this.#reader.read(size);\n\n\t\t\t\tconst classified = await this.#classify(typeId, body);\n\n\t\t\t\tif (classified.route === Route.GoAway) {\n\t\t\t\t\tconsole.warn(\"received GOAWAY on control stream\");\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst { route, requestId } = classified;\n\n\t\t\t\tswitch (route) {\n\t\t\t\t\tcase Route.NewRequest:\n\t\t\t\t\t\tthis.#newRequest(typeId, size, body, requestId);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase Route.Response:\n\t\t\t\t\t\tthis.#pushMessage(requestId, typeId, size, body);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase Route.ErrorResponse:\n\t\t\t\t\t\tthis.#pushMessage(requestId, typeId, size, body);\n\t\t\t\t\t\tthis.#closeStream(requestId);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase Route.CloseStream:\n\t\t\t\t\t\tthis.#closeStream(requestId);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase Route.FollowUp:\n\t\t\t\t\t\tthis.#pushMessage(requestId, typeId, size, body);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase Route.MaxRequestId:\n\t\t\t\t\t\tthis.#maxRequestId = requestId;\n\t\t\t\t\t\tfor (const resolve of this.#maxRequestIdResolves) resolve();\n\t\t\t\t\t\tthis.#maxRequestIdResolves = [];\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t} finally {\n\t\t\tthis.close();\n\t\t}\n\t}\n\n\t/** Accept real WebTransport bidi streams and queue them for acceptBi (v16). */\n\tasync #acceptNativeBidis(): Promise<void> {\n\t\ttry {\n\t\t\tfor (;;) {\n\t\t\t\tconst stream = await Stream.accept(this.#quic, this.version);\n\t\t\t\tif (!stream) break;\n\n\t\t\t\tconst waiter = this.#incomingWaiters.shift();\n\t\t\t\tif (waiter) {\n\t\t\t\t\twaiter(stream);\n\t\t\t\t} else {\n\t\t\t\t\tthis.#incomingQueue.push(stream);\n\t\t\t\t}\n\t\t\t}\n\t\t} catch {\n\t\t\t// Session closed\n\t\t}\n\t}\n\n\t#newRequest(typeId: number, size: number, body: Uint8Array, requestId: bigint) {\n\t\tlet controller!: ReadableStreamDefaultController<Uint8Array>;\n\t\tconst readable = new ReadableStream<Uint8Array>({\n\t\t\tstart(c) {\n\t\t\t\tcontroller = c;\n\t\t\t},\n\t\t\tcancel: () => {\n\t\t\t\tthis.#streams.delete(requestId);\n\t\t\t},\n\t\t});\n\n\t\tconst sendWritable = this.#createSendWritable();\n\n\t\tconst stream = new Stream({ readable, writable: sendWritable });\n\t\tstream.reader.version = this.version;\n\t\tstream.writer.version = this.version;\n\n\t\tthis.#streams.set(requestId, { controller });\n\n\t\t// Push initial message bytes so the dispatcher can read typeId + decode\n\t\tcontroller.enqueue(this.#encodeRaw(typeId, size, body));\n\n\t\t// Queue for acceptBi\n\t\tconst waiter = this.#incomingWaiters.shift();\n\t\tif (waiter) {\n\t\t\twaiter(stream);\n\t\t} else {\n\t\t\tthis.#incomingQueue.push(stream);\n\t\t}\n\t}\n\n\t#pushMessage(requestId: bigint, typeId: number, size: number, body: Uint8Array) {\n\t\tconst entry = this.#streams.get(requestId);\n\t\tif (!entry) {\n\t\t\tconsole.warn(`adapter: no stream for requestId=${requestId} typeId=0x${typeId.toString(16)}`);\n\t\t\treturn;\n\t\t}\n\t\ttry {\n\t\t\tentry.controller.enqueue(this.#encodeRaw(typeId, size, body));\n\t\t} catch {\n\t\t\t// Stream already closed\n\t\t}\n\t}\n\n\t#closeStream(requestId: bigint) {\n\t\tconst entry = this.#streams.get(requestId);\n\t\tif (!entry) return;\n\t\tconsole.debug(`adapter: closing stream requestId=${requestId}`);\n\t\tthis.#streams.delete(requestId);\n\t\tthis.#subscribeNamespaces.delete(requestId);\n\t\tconst namespace = this.#namespacesByRequestId.get(requestId);\n\t\tif (namespace !== undefined) {\n\t\t\tthis.#namespaces.delete(namespace);\n\t\t\tthis.#namespacesByRequestId.delete(requestId);\n\t\t}\n\t\ttry {\n\t\t\tentry.controller.close();\n\t\t} catch {\n\t\t\t// Already closed\n\t\t}\n\t}\n\n\t/**\n\t * Returns the total byte size of the first complete message in buffer,\n\t * or undefined if the buffer doesn't contain a complete message yet.\n\t * Message format: [typeId varint][size u16 BE][body of `size` bytes]\n\t */\n\t#messageSize(buffer: Uint8Array): number | undefined {\n\t\tif (buffer.length === 0) return undefined;\n\n\t\tconst typeSize = 1 << ((buffer[0] & 0xc0) >> 6);\n\t\tif (buffer.length < typeSize) return undefined;\n\n\t\tconst [, afterType] = Varint.decode(buffer);\n\t\tif (afterType.length < 2) return undefined;\n\n\t\tconst size = (afterType[0] << 8) | afterType[1];\n\t\tconst totalSize = buffer.length - afterType.length + 2 + size;\n\t\tif (buffer.length < totalSize) return undefined;\n\n\t\treturn totalSize;\n\t}\n\n\t/**\n\t * Try to parse the first outgoing message from accumulated bytes.\n\t * Returns the requestId if enough data is available, undefined otherwise.\n\t */\n\t#tryParseOutgoing(buffer: Uint8Array): { requestId: bigint } | undefined {\n\t\tif (buffer.length === 0) return undefined;\n\n\t\t// Check typeId varint size before decoding\n\t\tconst typeSize = 1 << ((buffer[0] & 0xc0) >> 6);\n\t\tif (buffer.length < typeSize) return undefined;\n\n\t\tconst [typeId, afterType] = Varint.decode(buffer);\n\n\t\t// Need 2 bytes for u16 size\n\t\tif (afterType.length < 2) return undefined;\n\n\t\tconst size = (afterType[0] << 8) | afterType[1];\n\t\tconst bodyStart = afterType.subarray(2);\n\n\t\t// Need full body\n\t\tif (bodyStart.length < size) return undefined;\n\n\t\tconst body = bodyStart.subarray(0, size);\n\n\t\t// Decode requestId from body (QUIC varint)\n\t\tconst [reqId] = Varint.decode(body);\n\t\tconst requestId = BigInt(reqId);\n\n\t\t// PublishNamespace (0x06): also parse namespace for v14/v15 reverse lookup\n\t\tif (typeId === 0x06) {\n\t\t\ttry {\n\t\t\t\tconst [, afterReqId] = Varint.decode(body);\n\t\t\t\tthis.#parseAndRegisterNamespace(afterReqId, requestId);\n\t\t\t} catch {\n\t\t\t\t// Non-critical: only needed for v14/v15 PublishNamespaceDone/Cancel\n\t\t\t}\n\t\t}\n\n\t\t// SubscribeNamespace (0x11): register for follow-up routing\n\t\tif (typeId === 0x11) {\n\t\t\tthis.#subscribeNamespaces.add(requestId);\n\t\t}\n\n\t\treturn { requestId };\n\t}\n\n\t/**\n\t * Parse a namespace from raw bytes and register it for reverse lookup.\n\t */\n\t#parseAndRegisterNamespace(buf: Uint8Array, requestId: bigint) {\n\t\tconst decoder = new TextDecoder();\n\t\tconst [partCount, afterCount] = Varint.decode(buf);\n\t\tlet cursor = afterCount;\n\t\tconst parts: string[] = [];\n\t\tfor (let i = 0; i < partCount; i++) {\n\t\t\tconst [len, afterLen] = Varint.decode(cursor);\n\t\t\tparts.push(decoder.decode(afterLen.subarray(0, len)));\n\t\t\tcursor = afterLen.subarray(len);\n\t\t}\n\t\tconst namespace = parts.join(\"/\");\n\t\tthis.#namespaces.set(namespace, requestId);\n\t\tthis.#namespacesByRequestId.set(requestId, namespace);\n\t}\n\n\t/** Create a WritableStream that buffers and writes complete messages to the control stream under mutex. */\n\t#createSendWritable(): WritableStream<Uint8Array> {\n\t\tlet buffer = new Uint8Array(0);\n\t\treturn new WritableStream<Uint8Array>({\n\t\t\twrite: async (chunk) => {\n\t\t\t\tconst newBuf = new Uint8Array(buffer.length + chunk.length);\n\t\t\t\tnewBuf.set(buffer);\n\t\t\t\tnewBuf.set(chunk, buffer.length);\n\t\t\t\tbuffer = newBuf;\n\n\t\t\t\tfor (;;) {\n\t\t\t\t\tconst boundary = this.#messageSize(buffer);\n\t\t\t\t\tif (boundary === undefined) break;\n\n\t\t\t\t\tconst toFlush = buffer.subarray(0, boundary);\n\t\t\t\t\tbuffer = buffer.subarray(boundary);\n\t\t\t\t\tawait this.#writeMutex.runExclusive(() => this.#writer.write(toFlush));\n\t\t\t\t}\n\t\t\t},\n\t\t});\n\t}\n\n\t/** Encode raw message bytes: [typeId varint][size u16 BE][body] */\n\t#encodeRaw(typeId: number, size: number, body: Uint8Array): Uint8Array {\n\t\t// v14-v16 always use QUIC varint\n\t\tconst typeIdBytes = Varint.encodeTo(new ArrayBuffer(9), typeId);\n\t\tconst result = new Uint8Array(typeIdBytes.byteLength + 2 + body.byteLength);\n\t\tresult.set(typeIdBytes, 0);\n\t\tconst sizeView = new DataView(result.buffer, typeIdBytes.byteLength, 2);\n\t\tsizeView.setUint16(0, size);\n\t\tresult.set(body, typeIdBytes.byteLength + 2);\n\t\treturn result;\n\t}\n\n\t/**\n\t * Classify a control message and extract its requestId for routing.\n\t */\n\tasync #classify(\n\t\ttypeId: number,\n\t\tbody: Uint8Array,\n\t): Promise<{ route: typeof Route.GoAway } | { route: Exclude<Route, typeof Route.GoAway>; requestId: bigint }> {\n\t\tconst readRequestId = async (): Promise<bigint> => {\n\t\t\tconst r = new Reader(undefined, body, this.version);\n\t\t\treturn await r.u62();\n\t\t};\n\n\t\tconst readNamespaceRequestId = async (): Promise<bigint> => {\n\t\t\tconst r = new Reader(undefined, body, this.version);\n\t\t\tconst namespace = await Namespace.decode(r);\n\t\t\tconst requestId = this.#namespaces.get(namespace);\n\t\t\tif (requestId === undefined) throw new Error(`unknown namespace: ${namespace}`);\n\t\t\tthis.#namespaces.delete(namespace);\n\t\t\treturn requestId;\n\t\t};\n\n\t\tswitch (typeId) {\n\t\t\t// === FollowUp: route to existing stream ===\n\t\t\tcase 0x02: {\n\t\t\t\t// SubscribeUpdate / REQUEST_UPDATE\n\t\t\t\tconst requestId = await readRequestId();\n\t\t\t\treturn { route: Route.FollowUp, requestId };\n\t\t\t}\n\n\t\t\t// === NewRequest: create virtual stream ===\n\t\t\tcase 0x03: // Subscribe\n\t\t\tcase 0x16: // Fetch\n\t\t\tcase 0x1d: // Publish\n\t\t\tcase 0x0d: {\n\t\t\t\t// TrackStatusRequest\n\t\t\t\tconst requestId = await readRequestId();\n\t\t\t\treturn { route: Route.NewRequest, requestId };\n\t\t\t}\n\t\t\tcase 0x06: {\n\t\t\t\t// PublishNamespace — also store namespace for v14/v15 reverse lookup\n\t\t\t\tconst r = new Reader(undefined, body, this.version);\n\t\t\t\tconst requestId = await r.u62();\n\t\t\t\tconst namespace = await Namespace.decode(r);\n\t\t\t\tthis.#namespaces.set(namespace, requestId);\n\t\t\t\tthis.#namespacesByRequestId.set(requestId, namespace);\n\t\t\t\treturn { route: Route.NewRequest, requestId };\n\t\t\t}\n\t\t\tcase 0x11: {\n\t\t\t\t// SubscribeNamespace (v14/v15 only on control stream)\n\t\t\t\tif (this.version !== Version.DRAFT_14 && this.version !== Version.DRAFT_15) {\n\t\t\t\t\tthrow new Error(\"unexpected SubscribeNamespace on control stream\");\n\t\t\t\t}\n\t\t\t\tconst requestId = await readRequestId();\n\t\t\t\treturn { route: Route.NewRequest, requestId };\n\t\t\t}\n\n\t\t\t// === Response: push bytes, keep stream open ===\n\t\t\tcase 0x04: {\n\t\t\t\t// SubscribeOk\n\t\t\t\tconst requestId = await readRequestId();\n\t\t\t\treturn { route: Route.Response, requestId };\n\t\t\t}\n\t\t\tcase 0x18: {\n\t\t\t\t// FetchOk\n\t\t\t\tconst requestId = await readRequestId();\n\t\t\t\treturn { route: Route.Response, requestId };\n\t\t\t}\n\t\t\tcase 0x1e: {\n\t\t\t\t// PublishOk\n\t\t\t\tconst requestId = await readRequestId();\n\t\t\t\treturn { route: Route.Response, requestId };\n\t\t\t}\n\t\t\tcase 0x07: {\n\t\t\t\t// v14: PublishNamespaceOk, v15+: RequestOk\n\t\t\t\tconst requestId = await readRequestId();\n\t\t\t\treturn { route: Route.Response, requestId };\n\t\t\t}\n\t\t\tcase 0x12: {\n\t\t\t\t// SubscribeNamespaceOk (v14 only)\n\t\t\t\tif (this.version !== Version.DRAFT_14) throw new Error(\"unexpected SubscribeNamespaceOk\");\n\t\t\t\tconst requestId = await readRequestId();\n\t\t\t\treturn { route: Route.Response, requestId };\n\t\t\t}\n\n\t\t\t// === ErrorResponse: push bytes + close ===\n\t\t\tcase 0x05: {\n\t\t\t\t// SubscribeError (v14) / RequestError (v15+)\n\t\t\t\tconst requestId = await readRequestId();\n\t\t\t\treturn { route: Route.ErrorResponse, requestId };\n\t\t\t}\n\t\t\tcase 0x19: {\n\t\t\t\t// FetchError (v14 only)\n\t\t\t\tif (this.version !== Version.DRAFT_14) throw new Error(\"unexpected FetchError\");\n\t\t\t\tconst requestId = await readRequestId();\n\t\t\t\treturn { route: Route.ErrorResponse, requestId };\n\t\t\t}\n\t\t\tcase 0x1f: {\n\t\t\t\t// PublishError (v14 only)\n\t\t\t\tif (this.version !== Version.DRAFT_14) throw new Error(\"unexpected PublishError\");\n\t\t\t\tconst requestId = await readRequestId();\n\t\t\t\treturn { route: Route.ErrorResponse, requestId };\n\t\t\t}\n\t\t\tcase 0x08: {\n\t\t\t\tif (this.version === Version.DRAFT_14) {\n\t\t\t\t\t// PublishNamespaceError\n\t\t\t\t\tconst requestId = await readRequestId();\n\t\t\t\t\treturn { route: Route.ErrorResponse, requestId };\n\t\t\t\t}\n\t\t\t\t// v15: Namespace entry (no requestId) — route to SubscribeNamespace stream\n\t\t\t\tconst subNs08 = this.#subscribeNamespaces.values().next().value;\n\t\t\t\tif (subNs08 === undefined) throw new Error(\"unexpected message 0x08: no SubscribeNamespace stream\");\n\t\t\t\treturn { route: Route.FollowUp, requestId: subNs08 };\n\t\t\t}\n\t\t\tcase 0x0e: {\n\t\t\t\t// v15: NamespaceDone entry (no requestId) — route to SubscribeNamespace stream\n\t\t\t\tconst subNs0e = this.#subscribeNamespaces.values().next().value;\n\t\t\t\tif (subNs0e === undefined) throw new Error(\"unexpected message 0x0e: no SubscribeNamespace stream\");\n\t\t\t\treturn { route: Route.FollowUp, requestId: subNs0e };\n\t\t\t}\n\t\t\tcase 0x13: {\n\t\t\t\t// SubscribeNamespaceError (v14 only)\n\t\t\t\tif (this.version !== Version.DRAFT_14) throw new Error(\"unexpected SubscribeNamespaceError\");\n\t\t\t\tconst requestId = await readRequestId();\n\t\t\t\treturn { route: Route.ErrorResponse, requestId };\n\t\t\t}\n\n\t\t\t// === CloseStream: close recv (no bytes pushed) ===\n\t\t\tcase 0x0a: {\n\t\t\t\t// Unsubscribe\n\t\t\t\tconst requestId = await readRequestId();\n\t\t\t\treturn { route: Route.CloseStream, requestId };\n\t\t\t}\n\t\t\tcase 0x0b: {\n\t\t\t\t// PublishDone\n\t\t\t\tconst requestId = await readRequestId();\n\t\t\t\treturn { route: Route.CloseStream, requestId };\n\t\t\t}\n\t\t\tcase 0x17: {\n\t\t\t\t// FetchCancel\n\t\t\t\tconst requestId = await readRequestId();\n\t\t\t\treturn { route: Route.CloseStream, requestId };\n\t\t\t}\n\t\t\tcase 0x09: {\n\t\t\t\t// PublishNamespaceDone: v16 uses requestId, v14/v15 uses namespace\n\t\t\t\tif (this.version === Version.DRAFT_16) {\n\t\t\t\t\tconst requestId = await readRequestId();\n\t\t\t\t\treturn { route: Route.CloseStream, requestId };\n\t\t\t\t}\n\t\t\t\tconst requestId = await readNamespaceRequestId();\n\t\t\t\treturn { route: Route.CloseStream, requestId };\n\t\t\t}\n\t\t\tcase 0x0c: {\n\t\t\t\t// PublishNamespaceCancel: v16 uses requestId, v14/v15 uses namespace\n\t\t\t\tif (this.version === Version.DRAFT_16) {\n\t\t\t\t\tconst requestId = await readRequestId();\n\t\t\t\t\treturn { route: Route.CloseStream, requestId };\n\t\t\t\t}\n\t\t\t\tconst requestId = await readNamespaceRequestId();\n\t\t\t\treturn { route: Route.CloseStream, requestId };\n\t\t\t}\n\t\t\tcase 0x14: {\n\t\t\t\t// UnsubscribeNamespace (v14/v15 only)\n\t\t\t\tif (this.version !== Version.DRAFT_14 && this.version !== Version.DRAFT_15) {\n\t\t\t\t\tthrow new Error(\"unexpected UnsubscribeNamespace\");\n\t\t\t\t}\n\t\t\t\tconst requestId = await readRequestId();\n\t\t\t\treturn { route: Route.CloseStream, requestId };\n\t\t\t}\n\n\t\t\t// === Utility ===\n\t\t\tcase 0x15: {\n\t\t\t\t// MaxRequestId\n\t\t\t\tconst requestId = await readRequestId();\n\t\t\t\treturn { route: Route.MaxRequestId, requestId };\n\t\t\t}\n\t\t\tcase 0x1a: {\n\t\t\t\t// RequestsBlocked — connection-level, consume and ignore\n\t\t\t\tawait readRequestId();\n\t\t\t\treturn { route: Route.Ignore, requestId: 0n };\n\t\t\t}\n\n\t\t\t// === Terminal ===\n\t\t\tcase 0x10: // GoAway\n\t\t\t\treturn { route: Route.GoAway };\n\n\t\t\tdefault:\n\t\t\t\tthrow new Error(`unknown control message type: 0x${typeId.toString(16)}`);\n\t\t}\n\t}\n\n\tclose() {\n\t\tif (this.#closed) return;\n\t\tthis.#closed = true;\n\t\tconsole.debug(\"adapter: close() called\");\n\n\t\t// Close all virtual streams\n\t\tfor (const entry of this.#streams.values()) {\n\t\t\ttry {\n\t\t\t\tentry.controller.close();\n\t\t\t} catch {\n\t\t\t\t// Already closed\n\t\t\t}\n\t\t}\n\t\tthis.#streams.clear();\n\n\t\t// Resolve any waiting acceptBi callers\n\t\tfor (const waiter of this.#incomingWaiters) {\n\t\t\twaiter(undefined);\n\t\t}\n\t\tthis.#incomingWaiters = [];\n\n\t\t// Clear namespace mappings\n\t\tthis.#namespaces.clear();\n\t\tthis.#namespacesByRequestId.clear();\n\t\tthis.#subscribeNamespaces.clear();\n\n\t\t// Unblock maxRequestId waiters\n\t\tfor (const resolve of this.#maxRequestIdResolves) resolve();\n\t\tthis.#maxRequestIdResolves = [];\n\t}\n}\n"]}
@@ -0,0 +1,11 @@
1
+ /** Resolves publisher-chosen track aliases after control/data stream reordering. @internal */
2
+ export declare class TrackAliases<T> {
3
+ #private;
4
+ /** Waits briefly for an alias to be established by SUBSCRIBE_OK or PUBLISH. */
5
+ get(alias: bigint): Promise<T>;
6
+ /** Establishes an alias and releases any data streams waiting for it. */
7
+ set(alias: bigint, value: T): void;
8
+ /** Removes an alias only if it still belongs to the supplied value. */
9
+ delete(alias: bigint, value: T): void;
10
+ }
11
+ //# sourceMappingURL=aliases.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"aliases.d.ts","sourceRoot":"","sources":["../../src/ietf/aliases.ts"],"names":[],"mappings":"AAIA,8FAA8F;AAC9F,qBAAa,YAAY,CAAC,CAAC;;IAI1B,+EAA+E;IACzE,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAuBnC;IAED,yEAAyE;IACzE,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,QAW1B;IAED,uEAAuE;IACvE,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,QAE7B;CACD"}
@@ -0,0 +1,52 @@
1
+ /* @ts-self-types="./aliases.d.ts" */
2
+ const TRACK_ALIAS_TIMEOUT_MS = 1000;
3
+ /** Resolves publisher-chosen track aliases after control/data stream reordering. @internal */
4
+ export class TrackAliases {
5
+ #active = new Map();
6
+ #pending = new Map();
7
+ /** Waits briefly for an alias to be established by SUBSCRIBE_OK or PUBLISH. */
8
+ async get(alias) {
9
+ if (this.#active.has(alias))
10
+ return this.#active.get(alias);
11
+ const { promise, resolve } = Promise.withResolvers();
12
+ let resolvers = this.#pending.get(alias);
13
+ if (!resolvers) {
14
+ resolvers = new Set();
15
+ this.#pending.set(alias, resolvers);
16
+ }
17
+ resolvers.add(resolve);
18
+ let timer;
19
+ const timeout = new Promise((_, reject) => {
20
+ timer = setTimeout(() => reject(new Error(`unknown track alias: ${alias}`)), TRACK_ALIAS_TIMEOUT_MS);
21
+ });
22
+ try {
23
+ return await Promise.race([promise, timeout]);
24
+ }
25
+ finally {
26
+ clearTimeout(timer);
27
+ resolvers.delete(resolve);
28
+ if (this.#pending.get(alias) === resolvers && resolvers.size === 0)
29
+ this.#pending.delete(alias);
30
+ }
31
+ }
32
+ /** Establishes an alias and releases any data streams waiting for it. */
33
+ set(alias, value) {
34
+ const active = this.#active.get(alias);
35
+ if (this.#active.has(alias)) {
36
+ if (active !== value)
37
+ throw new Error(`duplicate track alias: ${alias}`);
38
+ return;
39
+ }
40
+ this.#active.set(alias, value);
41
+ const resolvers = this.#pending.get(alias);
42
+ this.#pending.delete(alias);
43
+ for (const resolve of resolvers ?? [])
44
+ resolve(value);
45
+ }
46
+ /** Removes an alias only if it still belongs to the supplied value. */
47
+ delete(alias, value) {
48
+ if (this.#active.get(alias) === value)
49
+ this.#active.delete(alias);
50
+ }
51
+ }
52
+ //# sourceMappingURL=aliases.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"aliases.js","sourceRoot":"","sources":["../../src/ietf/aliases.ts"],"names":[],"mappings":"AAAA,MAAM,sBAAsB,GAAG,IAAI,CAAC;AAIpC,8FAA8F;AAC9F,MAAM,OAAO,YAAY;IACxB,OAAO,GAAG,IAAI,GAAG,EAAa,CAAC;IAC/B,QAAQ,GAAG,IAAI,GAAG,EAA4B,CAAC;IAE/C,+EAA+E;IAC/E,KAAK,CAAC,GAAG,CAAC,KAAa;QACtB,IAAI,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC;YAAE,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAM,CAAC;QAEjE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,aAAa,EAAK,CAAC;QACxD,IAAI,SAAS,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACzC,IAAI,CAAC,SAAS,EAAE,CAAC;YAChB,SAAS,GAAG,IAAI,GAAG,EAAE,CAAC;YACtB,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;QACrC,CAAC;QACD,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAEvB,IAAI,KAAgD,CAAC;QACrD,MAAM,OAAO,GAAG,IAAI,OAAO,CAAQ,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE;YAChD,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,wBAAwB,KAAK,EAAE,CAAC,CAAC,EAAE,sBAAsB,CAAC,CAAC;QACtG,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC;YACJ,OAAO,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;QAC/C,CAAC;gBAAS,CAAC;YACV,YAAY,CAAC,KAAK,CAAC,CAAC;YACpB,SAAS,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;YAC1B,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,SAAS,IAAI,SAAS,CAAC,IAAI,KAAK,CAAC;gBAAE,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACjG,CAAC;IACF,CAAC;IAED,yEAAyE;IACzE,GAAG,CAAC,KAAa,EAAE,KAAQ;QAC1B,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACvC,IAAI,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;YAC7B,IAAI,MAAM,KAAK,KAAK;gBAAE,MAAM,IAAI,KAAK,CAAC,0BAA0B,KAAK,EAAE,CAAC,CAAC;YACzE,OAAO;QACR,CAAC;QAED,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;QAC/B,MAAM,SAAS,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAC3C,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAC5B,KAAK,MAAM,OAAO,IAAI,SAAS,IAAI,EAAE;YAAE,OAAO,CAAC,KAAK,CAAC,CAAC;IACvD,CAAC;IAED,uEAAuE;IACvE,MAAM,CAAC,KAAa,EAAE,KAAQ;QAC7B,IAAI,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,KAAK;YAAE,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACnE,CAAC;CACD","sourcesContent":["const TRACK_ALIAS_TIMEOUT_MS = 1000;\n\ntype Resolver<T> = PromiseWithResolvers<T>[\"resolve\"];\n\n/** Resolves publisher-chosen track aliases after control/data stream reordering. @internal */\nexport class TrackAliases<T> {\n\t#active = new Map<bigint, T>();\n\t#pending = new Map<bigint, Set<Resolver<T>>>();\n\n\t/** Waits briefly for an alias to be established by SUBSCRIBE_OK or PUBLISH. */\n\tasync get(alias: bigint): Promise<T> {\n\t\tif (this.#active.has(alias)) return this.#active.get(alias) as T;\n\n\t\tconst { promise, resolve } = Promise.withResolvers<T>();\n\t\tlet resolvers = this.#pending.get(alias);\n\t\tif (!resolvers) {\n\t\t\tresolvers = new Set();\n\t\t\tthis.#pending.set(alias, resolvers);\n\t\t}\n\t\tresolvers.add(resolve);\n\n\t\tlet timer: ReturnType<typeof setTimeout> | undefined;\n\t\tconst timeout = new Promise<never>((_, reject) => {\n\t\t\ttimer = setTimeout(() => reject(new Error(`unknown track alias: ${alias}`)), TRACK_ALIAS_TIMEOUT_MS);\n\t\t});\n\n\t\ttry {\n\t\t\treturn await Promise.race([promise, timeout]);\n\t\t} finally {\n\t\t\tclearTimeout(timer);\n\t\t\tresolvers.delete(resolve);\n\t\t\tif (this.#pending.get(alias) === resolvers && resolvers.size === 0) this.#pending.delete(alias);\n\t\t}\n\t}\n\n\t/** Establishes an alias and releases any data streams waiting for it. */\n\tset(alias: bigint, value: T) {\n\t\tconst active = this.#active.get(alias);\n\t\tif (this.#active.has(alias)) {\n\t\t\tif (active !== value) throw new Error(`duplicate track alias: ${alias}`);\n\t\t\treturn;\n\t\t}\n\n\t\tthis.#active.set(alias, value);\n\t\tconst resolvers = this.#pending.get(alias);\n\t\tthis.#pending.delete(alias);\n\t\tfor (const resolve of resolvers ?? []) resolve(value);\n\t}\n\n\t/** Removes an alias only if it still belongs to the supplied value. */\n\tdelete(alias: bigint, value: T) {\n\t\tif (this.#active.get(alias) === value) this.#active.delete(alias);\n\t}\n}\n"]}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=aliases.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"aliases.test.d.ts","sourceRoot":"","sources":["../../src/ietf/aliases.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,30 @@
1
+ /* @ts-self-types="./aliases.test.d.ts" */
2
+ import { expect, test } from "bun:test";
3
+ import { TrackAliases } from "./aliases.js";
4
+ test("waits for the control message that establishes an alias", async () => {
5
+ const aliases = new TrackAliases();
6
+ const track = {};
7
+ const pending = aliases.get(7n);
8
+ aliases.set(7n, track);
9
+ expect(await pending).toBe(track);
10
+ });
11
+ test("resolves every subgroup waiting for the same alias", async () => {
12
+ const aliases = new TrackAliases();
13
+ const track = {};
14
+ const pending = [aliases.get(7n), aliases.get(7n)];
15
+ aliases.set(7n, track);
16
+ expect(await Promise.all(pending)).toEqual([track, track]);
17
+ });
18
+ test("rejects an alias used by two active tracks", () => {
19
+ const aliases = new TrackAliases();
20
+ aliases.set(7n, {});
21
+ expect(() => aliases.set(7n, {})).toThrow("duplicate track alias");
22
+ });
23
+ test("does not let stale cleanup remove a reused alias", async () => {
24
+ const aliases = new TrackAliases();
25
+ const active = {};
26
+ aliases.set(7n, active);
27
+ aliases.delete(7n, {});
28
+ expect(await aliases.get(7n)).toBe(active);
29
+ });
30
+ //# sourceMappingURL=aliases.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"aliases.test.js","sourceRoot":"","sources":["../../src/ietf/aliases.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,UAAU,CAAC;AACxC,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAE5C,IAAI,CAAC,yDAAyD,EAAE,KAAK,IAAI,EAAE;IAC1E,MAAM,OAAO,GAAG,IAAI,YAAY,EAAU,CAAC;IAC3C,MAAM,KAAK,GAAG,EAAE,CAAC;IACjB,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAEhC,OAAO,CAAC,GAAG,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;IAEvB,MAAM,CAAC,MAAM,OAAO,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AACnC,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,oDAAoD,EAAE,KAAK,IAAI,EAAE;IACrE,MAAM,OAAO,GAAG,IAAI,YAAY,EAAU,CAAC;IAC3C,MAAM,KAAK,GAAG,EAAE,CAAC;IACjB,MAAM,OAAO,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;IAEnD,OAAO,CAAC,GAAG,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;IAEvB,MAAM,CAAC,MAAM,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC;AAC5D,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,4CAA4C,EAAE,GAAG,EAAE;IACvD,MAAM,OAAO,GAAG,IAAI,YAAY,EAAU,CAAC;IAC3C,OAAO,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;IAEpB,MAAM,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,uBAAuB,CAAC,CAAC;AACpE,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,kDAAkD,EAAE,KAAK,IAAI,EAAE;IACnE,MAAM,OAAO,GAAG,IAAI,YAAY,EAAU,CAAC;IAC3C,MAAM,MAAM,GAAG,EAAE,CAAC;IAClB,OAAO,CAAC,GAAG,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;IAExB,OAAO,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;IAEvB,MAAM,CAAC,MAAM,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AAC5C,CAAC,CAAC,CAAC","sourcesContent":["import { expect, test } from \"bun:test\";\nimport { TrackAliases } from \"./aliases.ts\";\n\ntest(\"waits for the control message that establishes an alias\", async () => {\n\tconst aliases = new TrackAliases<object>();\n\tconst track = {};\n\tconst pending = aliases.get(7n);\n\n\taliases.set(7n, track);\n\n\texpect(await pending).toBe(track);\n});\n\ntest(\"resolves every subgroup waiting for the same alias\", async () => {\n\tconst aliases = new TrackAliases<object>();\n\tconst track = {};\n\tconst pending = [aliases.get(7n), aliases.get(7n)];\n\n\taliases.set(7n, track);\n\n\texpect(await Promise.all(pending)).toEqual([track, track]);\n});\n\ntest(\"rejects an alias used by two active tracks\", () => {\n\tconst aliases = new TrackAliases<object>();\n\taliases.set(7n, {});\n\n\texpect(() => aliases.set(7n, {})).toThrow(\"duplicate track alias\");\n});\n\ntest(\"does not let stale cleanup remove a reused alias\", async () => {\n\tconst aliases = new TrackAliases<object>();\n\tconst active = {};\n\taliases.set(7n, active);\n\n\taliases.delete(7n, {});\n\n\texpect(await aliases.get(7n)).toBe(active);\n});\n"]}
@@ -73,7 +73,7 @@ export class Connection {
73
73
  if (this.#closed)
74
74
  return;
75
75
  this.#closed = true;
76
- this.#session.close?.();
76
+ this.#session.close();
77
77
  try {
78
78
  this.#quic.close();
79
79
  }
@@ -1 +1 @@
1
- {"version":3,"file":"connection.js","sourceRoot":"","sources":["../../src/ietf/connection.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Announced } from \"../announced.ts\";\nimport type { Broadcast } from \"../broadcast.ts\";\nimport type { Established } from \"../connection/established.ts\";\nimport * as Path from \"../path.ts\";\nimport { type Reader, Readers, type Stream } from \"../stream.ts\";\nimport { ControlStreamAdapter, NativeSession, type Session } from \"./adapter.ts\";\nimport { GoAway } from \"./goaway.ts\";\nimport { Group } from \"./object.ts\";\nimport { Publish } from \"./publish.ts\";\nimport { PublishNamespace } from \"./publish_namespace.ts\";\nimport { Publisher } from \"./publisher.ts\";\nimport { Subscribe, SubscribeUpdate } from \"./subscribe.ts\";\nimport { SubscribeNamespace, SubscribeNamespaceLegacy } from \"./subscribe_namespace.ts\";\nimport { Subscriber } from \"./subscriber.ts\";\nimport { TrackStatusRequest } from \"./track.ts\";\nimport { type IetfVersion, Version, versionName } from \"./version.ts\";\n\n/**\n * Represents a connection to a MoQ server using moq-transport protocol.\n *\n * @public\n */\nexport class Connection implements Established {\n\t// The URL of the connection.\n\treadonly url: URL;\n\n\t// The negotiated protocol version.\n\treadonly version: string;\n\n\t// The established WebTransport session.\n\t#quic: WebTransport;\n\n\t// Session abstraction: adapter for v14-v16, native for v17.\n\t#session: Session;\n\n\t// Module for contributing tracks.\n\t#publisher: Publisher;\n\n\t// Module for distributing tracks.\n\t#subscriber: Subscriber;\n\n\t// Just to avoid logging when `close()` is called.\n\t#closed = false;\n\n\t/**\n\t * Creates a new Connection instance.\n\t * @param url - The URL of the connection\n\t * @param quic - The WebTransport session\n\t * @param control - The control/setup stream\n\t * @param maxRequestId - The initial max request ID\n\t * @param version - The negotiated protocol version\n\t *\n\t * @internal\n\t */\n\tconstructor({\n\t\turl,\n\t\tquic,\n\t\tcontrol,\n\t\tmaxRequestId,\n\t\tversion,\n\t}: {\n\t\turl: URL;\n\t\tquic: WebTransport;\n\t\tcontrol: Stream;\n\t\tmaxRequestId: bigint;\n\t\tversion: IetfVersion;\n\t}) {\n\t\tthis.url = url;\n\t\tthis.version = versionName(version);\n\t\tthis.#quic = quic;\n\n\t\t// Two-path dispatch: v14-v16 uses adapter, v17+ uses native bidi streams\n\t\tif (version >= Version.DRAFT_17) {\n\t\t\tthis.#session = new NativeSession(quic, version);\n\t\t\t// v17+: control/setup stream only carries GoAway\n\t\t\tvoid this.#runGoAway(control, version);\n\t\t} else {\n\t\t\tconst adapter = new ControlStreamAdapter(quic, control, version, maxRequestId);\n\t\t\tthis.#session = adapter;\n\t\t\t// Start the adapter read loop (routes control messages to virtual streams)\n\t\t\tvoid adapter.run().catch((err: unknown) => {\n\t\t\t\tif (!this.#closed) console.error(\"adapter error\", err);\n\t\t\t\tthis.close();\n\t\t\t});\n\t\t}\n\n\t\tthis.#publisher = new Publisher(this.#quic, this.#session);\n\t\tthis.#subscriber = new Subscriber(this.#session);\n\n\t\tvoid this.#run();\n\t}\n\n\t/**\n\t * Closes the connection.\n\t */\n\tclose() {\n\t\tif (this.#closed) return;\n\n\t\tthis.#closed = true;\n\n\t\tthis.#session.close?.();\n\n\t\ttry {\n\t\t\tthis.#quic.close();\n\t\t} catch {\n\t\t\t// ignore\n\t\t}\n\t}\n\n\tasync #run(): Promise<void> {\n\t\ttry {\n\t\t\tawait Promise.all([this.#runBidis(), this.#runUnis()]);\n\t\t} catch (err) {\n\t\t\tif (!this.#closed) {\n\t\t\t\tconsole.error(\"fatal error running connection\", err);\n\t\t\t}\n\t\t} finally {\n\t\t\tthis.close();\n\t\t}\n\t}\n\n\t/**\n\t * Publishes a broadcast to the connection.\n\t * @param name - The broadcast path to publish\n\t * @param broadcast - The broadcast to publish\n\t */\n\tpublish(path: Path.Valid, broadcast: Broadcast) {\n\t\tthis.#publisher.publish(path, broadcast);\n\t}\n\n\t/**\n\t * Gets an announced reader for the specified prefix.\n\t * @param prefix - The prefix for announcements\n\t * @returns An Announced instance\n\t */\n\tannounced(prefix = Path.empty()): Announced {\n\t\treturn this.#subscriber.announced(prefix);\n\t}\n\n\t/**\n\t * Consumes a broadcast from the connection.\n\t *\n\t * @remarks\n\t * If the broadcast is not found, a \"not found\" error will be thrown when requesting any tracks.\n\t *\n\t * @param broadcast - The path of the broadcast to consume\n\t * @returns A Broadcast instance\n\t */\n\tconsume(broadcast: Path.Valid): Broadcast {\n\t\treturn this.#subscriber.consume(broadcast);\n\t}\n\n\t/**\n\t * Accepts bidi streams (virtual for v14-v16, real for v17) and dispatches.\n\t */\n\tasync #runBidis() {\n\t\tfor (;;) {\n\t\t\tconst stream = await this.#session.acceptBi();\n\t\t\tif (!stream) break;\n\n\t\t\tvoid this.#runBidi(stream).catch((err: unknown) => {\n\t\t\t\tconsole.error(\"error processing bidi stream\", err);\n\t\t\t\tstream.abort(new Error(\"bidi stream error\"));\n\t\t\t});\n\t\t}\n\t}\n\n\t/**\n\t * Unified bidi stream dispatch — reads typeId and routes to handler.\n\t * Matches the lite module's runBidi pattern.\n\t */\n\tasync #runBidi(stream: Stream) {\n\t\tconst typeId = await stream.reader.u53();\n\n\t\tswitch (typeId) {\n\t\t\t// Draft-18 SUBSCRIBE_NAMESPACE (0x50) and the legacy 0x11 message decode\n\t\t\t// to the same request_id + namespace; the legacy options field is ignored.\n\t\t\tcase SubscribeNamespace.id: {\n\t\t\t\tconst msg = await SubscribeNamespace.decode(stream.reader, this.#session.version);\n\t\t\t\tawait this.#publisher.runSubscribeNamespace(msg, stream);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase SubscribeNamespaceLegacy.id: {\n\t\t\t\tconst legacy = await SubscribeNamespaceLegacy.decode(stream.reader, this.#session.version);\n\t\t\t\tconst msg = new SubscribeNamespace({ requestId: legacy.requestId, namespace: legacy.namespace });\n\t\t\t\tawait this.#publisher.runSubscribeNamespace(msg, stream);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase SubscribeUpdate.id: {\n\t\t\t\t// REQUEST_UPDATE (0x02) is a follow-up, not a valid initial message\n\t\t\t\tstream.abort(new Error(\"unexpected REQUEST_UPDATE as initial message\"));\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\t// Publisher handles incoming requests\n\t\t\tcase Subscribe.id: {\n\t\t\t\tconst msg = await Subscribe.decode(stream.reader, this.#session.version);\n\t\t\t\tawait this.#publisher.runSubscribe(msg, stream);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase TrackStatusRequest.id: {\n\t\t\t\tconst msg = await TrackStatusRequest.decode(stream.reader, this.#session.version);\n\t\t\t\tawait this.#publisher.runTrackStatusRequest(msg, stream);\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t// Subscriber handles incoming notifications\n\t\t\tcase PublishNamespace.id: {\n\t\t\t\tconst msg = await PublishNamespace.decode(stream.reader, this.#session.version);\n\t\t\t\tawait this.#subscriber.runPublishNamespace(msg, stream);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase Publish.id: {\n\t\t\t\tconst msg = await Publish.decode(stream.reader, this.#session.version);\n\t\t\t\tawait this.#subscriber.runPublish(msg, stream);\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tdefault:\n\t\t\t\tconsole.warn(`unexpected bidi stream type: 0x${typeId.toString(16)}`);\n\t\t\t\tstream.abort(new Error(\"unexpected stream type\"));\n\t\t}\n\t}\n\n\t/**\n\t * Handles unidirectional streams for media delivery (groups).\n\t */\n\tasync #runUnis() {\n\t\tconst readers = new Readers(this.#quic, this.#session.version);\n\n\t\tfor (;;) {\n\t\t\tconst stream = await readers.next();\n\t\t\tif (!stream) break;\n\n\t\t\tthis.#runUni(stream)\n\t\t\t\t.then(() => {\n\t\t\t\t\tstream.stop(new Error(\"cancel\"));\n\t\t\t\t})\n\t\t\t\t.catch((err: unknown) => {\n\t\t\t\t\tconsole.error(\"error processing object stream\", err);\n\t\t\t\t\tstream.stop(err);\n\t\t\t\t});\n\t\t}\n\t}\n\n\tasync #runUni(stream: Reader) {\n\t\tconst header = await Group.decode(stream, this.#session.version);\n\t\tawait this.#subscriber.handleGroup(header, stream);\n\t}\n\n\t/**\n\t * v17+ only: reads GoAway from the setup/control stream.\n\t */\n\tasync #runGoAway(controlStream: Stream, version: IetfVersion) {\n\t\ttry {\n\t\t\tconst done = await controlStream.reader.done();\n\t\t\tif (done) return;\n\n\t\t\tconst typeId = await controlStream.reader.u53();\n\t\t\tif (typeId === GoAway.id) {\n\t\t\t\tconst msg = await GoAway.decode(controlStream.reader, version);\n\t\t\t\tconsole.warn(`received GOAWAY with redirect URI: ${msg.newSessionUri}`);\n\t\t\t} else {\n\t\t\t\tconsole.warn(`unexpected message on setup stream: 0x${typeId.toString(16)}`);\n\t\t\t}\n\t\t} catch (err) {\n\t\t\tif (!this.#closed) {\n\t\t\t\tconsole.error(\"error reading setup stream\", err);\n\t\t\t}\n\t\t} finally {\n\t\t\tthis.close();\n\t\t}\n\t}\n\n\t/**\n\t * Returns a promise that resolves when the connection is closed.\n\t * @returns A promise that resolves when closed\n\t */\n\tget closed(): Promise<void> {\n\t\treturn this.#quic.closed.then(() => undefined);\n\t}\n}\n"]}
1
+ {"version":3,"file":"connection.js","sourceRoot":"","sources":["../../src/ietf/connection.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Announced } from \"../announced.ts\";\nimport type { Broadcast } from \"../broadcast.ts\";\nimport type { Established } from \"../connection/established.ts\";\nimport * as Path from \"../path.ts\";\nimport { type Reader, Readers, type Stream } from \"../stream.ts\";\nimport { ControlStreamAdapter, NativeSession, type Session } from \"./adapter.ts\";\nimport { GoAway } from \"./goaway.ts\";\nimport { Group } from \"./object.ts\";\nimport { Publish } from \"./publish.ts\";\nimport { PublishNamespace } from \"./publish_namespace.ts\";\nimport { Publisher } from \"./publisher.ts\";\nimport { Subscribe, SubscribeUpdate } from \"./subscribe.ts\";\nimport { SubscribeNamespace, SubscribeNamespaceLegacy } from \"./subscribe_namespace.ts\";\nimport { Subscriber } from \"./subscriber.ts\";\nimport { TrackStatusRequest } from \"./track.ts\";\nimport { type IetfVersion, Version, versionName } from \"./version.ts\";\n\n/**\n * Represents a connection to a MoQ server using moq-transport protocol.\n *\n * @public\n */\nexport class Connection implements Established {\n\t// The URL of the connection.\n\treadonly url: URL;\n\n\t// The negotiated protocol version.\n\treadonly version: string;\n\n\t// The established WebTransport session.\n\t#quic: WebTransport;\n\n\t// Session abstraction: adapter for v14-v16, native for v17.\n\t#session: Session;\n\n\t// Module for contributing tracks.\n\t#publisher: Publisher;\n\n\t// Module for distributing tracks.\n\t#subscriber: Subscriber;\n\n\t// Just to avoid logging when `close()` is called.\n\t#closed = false;\n\n\t/**\n\t * Creates a new Connection instance.\n\t * @param url - The URL of the connection\n\t * @param quic - The WebTransport session\n\t * @param control - The control/setup stream\n\t * @param maxRequestId - The initial max request ID\n\t * @param version - The negotiated protocol version\n\t *\n\t * @internal\n\t */\n\tconstructor({\n\t\turl,\n\t\tquic,\n\t\tcontrol,\n\t\tmaxRequestId,\n\t\tversion,\n\t}: {\n\t\turl: URL;\n\t\tquic: WebTransport;\n\t\tcontrol: Stream;\n\t\tmaxRequestId: bigint;\n\t\tversion: IetfVersion;\n\t}) {\n\t\tthis.url = url;\n\t\tthis.version = versionName(version);\n\t\tthis.#quic = quic;\n\n\t\t// Two-path dispatch: v14-v16 uses adapter, v17+ uses native bidi streams\n\t\tif (version >= Version.DRAFT_17) {\n\t\t\tthis.#session = new NativeSession(quic, version);\n\t\t\t// v17+: control/setup stream only carries GoAway\n\t\t\tvoid this.#runGoAway(control, version);\n\t\t} else {\n\t\t\tconst adapter = new ControlStreamAdapter(quic, control, version, maxRequestId);\n\t\t\tthis.#session = adapter;\n\t\t\t// Start the adapter read loop (routes control messages to virtual streams)\n\t\t\tvoid adapter.run().catch((err: unknown) => {\n\t\t\t\tif (!this.#closed) console.error(\"adapter error\", err);\n\t\t\t\tthis.close();\n\t\t\t});\n\t\t}\n\n\t\tthis.#publisher = new Publisher(this.#quic, this.#session);\n\t\tthis.#subscriber = new Subscriber(this.#session);\n\n\t\tvoid this.#run();\n\t}\n\n\t/**\n\t * Closes the connection.\n\t */\n\tclose() {\n\t\tif (this.#closed) return;\n\n\t\tthis.#closed = true;\n\n\t\tthis.#session.close();\n\n\t\ttry {\n\t\t\tthis.#quic.close();\n\t\t} catch {\n\t\t\t// ignore\n\t\t}\n\t}\n\n\tasync #run(): Promise<void> {\n\t\ttry {\n\t\t\tawait Promise.all([this.#runBidis(), this.#runUnis()]);\n\t\t} catch (err) {\n\t\t\tif (!this.#closed) {\n\t\t\t\tconsole.error(\"fatal error running connection\", err);\n\t\t\t}\n\t\t} finally {\n\t\t\tthis.close();\n\t\t}\n\t}\n\n\t/**\n\t * Publishes a broadcast to the connection.\n\t * @param name - The broadcast path to publish\n\t * @param broadcast - The broadcast to publish\n\t */\n\tpublish(path: Path.Valid, broadcast: Broadcast) {\n\t\tthis.#publisher.publish(path, broadcast);\n\t}\n\n\t/**\n\t * Gets an announced reader for the specified prefix.\n\t * @param prefix - The prefix for announcements\n\t * @returns An Announced instance\n\t */\n\tannounced(prefix = Path.empty()): Announced {\n\t\treturn this.#subscriber.announced(prefix);\n\t}\n\n\t/**\n\t * Consumes a broadcast from the connection.\n\t *\n\t * @remarks\n\t * If the broadcast is not found, a \"not found\" error will be thrown when requesting any tracks.\n\t *\n\t * @param broadcast - The path of the broadcast to consume\n\t * @returns A Broadcast instance\n\t */\n\tconsume(broadcast: Path.Valid): Broadcast {\n\t\treturn this.#subscriber.consume(broadcast);\n\t}\n\n\t/**\n\t * Accepts bidi streams (virtual for v14-v16, real for v17) and dispatches.\n\t */\n\tasync #runBidis() {\n\t\tfor (;;) {\n\t\t\tconst stream = await this.#session.acceptBi();\n\t\t\tif (!stream) break;\n\n\t\t\tvoid this.#runBidi(stream).catch((err: unknown) => {\n\t\t\t\tconsole.error(\"error processing bidi stream\", err);\n\t\t\t\tstream.abort(new Error(\"bidi stream error\"));\n\t\t\t});\n\t\t}\n\t}\n\n\t/**\n\t * Unified bidi stream dispatch — reads typeId and routes to handler.\n\t * Matches the lite module's runBidi pattern.\n\t */\n\tasync #runBidi(stream: Stream) {\n\t\tconst typeId = await stream.reader.u53();\n\n\t\tswitch (typeId) {\n\t\t\t// Draft-18 SUBSCRIBE_NAMESPACE (0x50) and the legacy 0x11 message decode\n\t\t\t// to the same request_id + namespace; the legacy options field is ignored.\n\t\t\tcase SubscribeNamespace.id: {\n\t\t\t\tconst msg = await SubscribeNamespace.decode(stream.reader, this.#session.version);\n\t\t\t\tawait this.#publisher.runSubscribeNamespace(msg, stream);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase SubscribeNamespaceLegacy.id: {\n\t\t\t\tconst legacy = await SubscribeNamespaceLegacy.decode(stream.reader, this.#session.version);\n\t\t\t\tconst msg = new SubscribeNamespace({ requestId: legacy.requestId, namespace: legacy.namespace });\n\t\t\t\tawait this.#publisher.runSubscribeNamespace(msg, stream);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase SubscribeUpdate.id: {\n\t\t\t\t// REQUEST_UPDATE (0x02) is a follow-up, not a valid initial message\n\t\t\t\tstream.abort(new Error(\"unexpected REQUEST_UPDATE as initial message\"));\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\t// Publisher handles incoming requests\n\t\t\tcase Subscribe.id: {\n\t\t\t\tconst msg = await Subscribe.decode(stream.reader, this.#session.version);\n\t\t\t\tawait this.#publisher.runSubscribe(msg, stream);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase TrackStatusRequest.id: {\n\t\t\t\tconst msg = await TrackStatusRequest.decode(stream.reader, this.#session.version);\n\t\t\t\tawait this.#publisher.runTrackStatusRequest(msg, stream);\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t// Subscriber handles incoming notifications\n\t\t\tcase PublishNamespace.id: {\n\t\t\t\tconst msg = await PublishNamespace.decode(stream.reader, this.#session.version);\n\t\t\t\tawait this.#subscriber.runPublishNamespace(msg, stream);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase Publish.id: {\n\t\t\t\tconst msg = await Publish.decode(stream.reader, this.#session.version);\n\t\t\t\tawait this.#subscriber.runPublish(msg, stream);\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tdefault:\n\t\t\t\tconsole.warn(`unexpected bidi stream type: 0x${typeId.toString(16)}`);\n\t\t\t\tstream.abort(new Error(\"unexpected stream type\"));\n\t\t}\n\t}\n\n\t/**\n\t * Handles unidirectional streams for media delivery (groups).\n\t */\n\tasync #runUnis() {\n\t\tconst readers = new Readers(this.#quic, this.#session.version);\n\n\t\tfor (;;) {\n\t\t\tconst stream = await readers.next();\n\t\t\tif (!stream) break;\n\n\t\t\tthis.#runUni(stream)\n\t\t\t\t.then(() => {\n\t\t\t\t\tstream.stop(new Error(\"cancel\"));\n\t\t\t\t})\n\t\t\t\t.catch((err: unknown) => {\n\t\t\t\t\tconsole.error(\"error processing object stream\", err);\n\t\t\t\t\tstream.stop(err);\n\t\t\t\t});\n\t\t}\n\t}\n\n\tasync #runUni(stream: Reader) {\n\t\tconst header = await Group.decode(stream, this.#session.version);\n\t\tawait this.#subscriber.handleGroup(header, stream);\n\t}\n\n\t/**\n\t * v17+ only: reads GoAway from the setup/control stream.\n\t */\n\tasync #runGoAway(controlStream: Stream, version: IetfVersion) {\n\t\ttry {\n\t\t\tconst done = await controlStream.reader.done();\n\t\t\tif (done) return;\n\n\t\t\tconst typeId = await controlStream.reader.u53();\n\t\t\tif (typeId === GoAway.id) {\n\t\t\t\tconst msg = await GoAway.decode(controlStream.reader, version);\n\t\t\t\tconsole.warn(`received GOAWAY with redirect URI: ${msg.newSessionUri}`);\n\t\t\t} else {\n\t\t\t\tconsole.warn(`unexpected message on setup stream: 0x${typeId.toString(16)}`);\n\t\t\t}\n\t\t} catch (err) {\n\t\t\tif (!this.#closed) {\n\t\t\t\tconsole.error(\"error reading setup stream\", err);\n\t\t\t}\n\t\t} finally {\n\t\t\tthis.close();\n\t\t}\n\t}\n\n\t/**\n\t * Returns a promise that resolves when the connection is closed.\n\t * @returns A promise that resolves when closed\n\t */\n\tget closed(): Promise<void> {\n\t\treturn this.#quic.closed.then(() => undefined);\n\t}\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"subscriber.d.ts","sourceRoot":"","sources":["../../src/ietf/subscriber.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAqB,MAAM,iBAAiB,CAAC;AAE/D,OAAO,KAAK,IAAI,MAAM,YAAY,CAAC;AACnC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAGnD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAS,KAAK,KAAK,IAAI,YAAY,EAAE,MAAM,aAAa,CAAC;AAChE,OAAO,EAAE,KAAK,OAAO,EAAgB,MAAM,cAAc,CAAC;AAC1D,OAAO,EAAE,KAAK,gBAAgB,EAA6C,MAAM,wBAAwB,CAAC;AAc1G;;;;;GAKG;AACH,qBAAa,UAAU;;IAYtB;;;;;OAKG;IACH,YAAY,OAAO,EAAE,OAAO,EAE3B;IAED;;OAEG;IACH,SAAS,CAAC,MAAM,aAAe,GAAG,SAAS,CAc1C;IA8GD;;OAEG;IACH,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,GAAG,SAAS,CAYnC;IAuGD;;;;;OAKG;IACG,mBAAmB,CAAC,GAAG,EAAE,gBAAgB,EAAE,MAAM,EAAE,MAAM,iBAwE9D;IAED;;;;;OAKG;IACG,UAAU,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,iBAqB5C;IAED;;;;OAIG;IACG,WAAW,CAAC,KAAK,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,iBAiCpD;CACD"}
1
+ {"version":3,"file":"subscriber.d.ts","sourceRoot":"","sources":["../../src/ietf/subscriber.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAqB,MAAM,iBAAiB,CAAC;AAE/D,OAAO,KAAK,IAAI,MAAM,YAAY,CAAC;AACnC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAGnD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAE5C,OAAO,EAAS,KAAK,KAAK,IAAI,YAAY,EAAE,MAAM,aAAa,CAAC;AAChE,OAAO,EAAE,KAAK,OAAO,EAAgB,MAAM,cAAc,CAAC;AAC1D,OAAO,EAAE,KAAK,gBAAgB,EAA6C,MAAM,wBAAwB,CAAC;AAc1G;;;;;GAKG;AACH,qBAAa,UAAU;;IAYtB;;;;;OAKG;IACH,YAAY,OAAO,EAAE,OAAO,EAE3B;IAED;;OAEG;IACH,SAAS,CAAC,MAAM,aAAe,GAAG,SAAS,CAc1C;IA8GD;;OAEG;IACH,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,GAAG,SAAS,CAYnC;IAkGD;;;;;OAKG;IACG,mBAAmB,CAAC,GAAG,EAAE,gBAAgB,EAAE,MAAM,EAAE,MAAM,iBAwE9D;IAED;;;;;OAKG;IACG,UAAU,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,iBAqB5C;IAED;;;;OAIG;IACG,WAAW,CAAC,KAAK,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,iBA6BpD;CACD"}
@@ -4,6 +4,7 @@ import { Broadcast } from "../broadcast.js";
4
4
  import { Group } from "../group.js";
5
5
  import * as Path from "../path.js";
6
6
  import { error } from "../util/error.js";
7
+ import { TrackAliases } from "./aliases.js";
7
8
  import { Frame } from "./object.js";
8
9
  import { PublishError } from "./publish.js";
9
10
  import { PublishNamespaceError, PublishNamespaceOk } from "./publish_namespace.js";
@@ -19,8 +20,8 @@ import { Version } from "./version.js";
19
20
  */
20
21
  export class Subscriber {
21
22
  #session;
22
- // Our subscribed tracks — keyed by trackAlias for group routing
23
- #subscribes = new Map();
23
+ // Publisher-chosen aliases used by incoming group streams.
24
+ #aliases = new TrackAliases();
24
25
  // Any currently active announcements.
25
26
  #announced = new Set();
26
27
  // Any consumers that want each new announcement.
@@ -190,19 +191,18 @@ export class Subscriber {
190
191
  });
191
192
  await msg.encode(stream.writer, version);
192
193
  console.debug(`subscribe written: id=${requestId} broadcast=${broadcast} track=${request.track.name}`);
193
- // Pre-register with requestId so early group uni streams aren't dropped.
194
- // The publisher typically uses requestId as the trackAlias.
195
- this.#subscribes.set(requestId, request.track);
196
194
  // Read response (SubscribeOk or error)
197
195
  const respTypeId = await stream.reader.u53();
198
196
  if (respTypeId === SubscribeOk.id) {
199
197
  const ok = await SubscribeOk.decode(stream.reader, version);
200
- // Update registration to use the actual trackAlias from SubscribeOk
201
- if (ok.trackAlias !== requestId) {
202
- this.#subscribes.delete(requestId);
203
- this.#subscribes.set(ok.trackAlias, request.track);
198
+ try {
199
+ this.#aliases.set(ok.trackAlias, request.track);
200
+ }
201
+ catch (err) {
202
+ this.#session.close();
203
+ throw err;
204
204
  }
205
- console.debug(`subscribe ok: id=${requestId} broadcast=${broadcast} track=${request.track.name}`);
205
+ console.debug(`subscribe ok: id=${requestId} broadcast=${broadcast} track=${request.track.name} alias=${ok.trackAlias}`);
206
206
  try {
207
207
  // Wait for stream close (= PublishDone) or track close (= local unsubscribe)
208
208
  await Promise.race([stream.reader.closed, request.track.closed]);
@@ -224,12 +224,10 @@ export class Subscriber {
224
224
  console.debug(`subscribe close: id=${requestId} broadcast=${broadcast} track=${request.track.name}`);
225
225
  }
226
226
  finally {
227
- this.#subscribes.delete(ok.trackAlias);
227
+ this.#aliases.delete(ok.trackAlias, request.track);
228
228
  }
229
229
  }
230
230
  else {
231
- // Clean up pre-registered entry on error
232
- this.#subscribes.delete(requestId);
233
231
  // Error response
234
232
  let reasonPhrase = "unknown error";
235
233
  try {
@@ -248,7 +246,6 @@ export class Subscriber {
248
246
  }
249
247
  }
250
248
  catch (err) {
251
- this.#subscribes.delete(requestId);
252
249
  stream.abort(error(err));
253
250
  throw err;
254
251
  }
@@ -376,12 +373,8 @@ export class Subscriber {
376
373
  throw new Error("subgroups are not supported");
377
374
  }
378
375
  try {
379
- // Look up by trackAlias directly
380
- const track = this.#subscribes.get(group.trackAlias);
381
- if (!track) {
382
- // Fallback: try treating trackAlias as requestId (for compat)
383
- throw new Error(`unknown track: trackAlias=${group.trackAlias}`);
384
- }
376
+ // The control message establishing this alias can arrive after the data stream.
377
+ const track = await this.#aliases.get(group.trackAlias);
385
378
  track.writeGroup(producer);
386
379
  for (;;) {
387
380
  const done = await Promise.race([stream.done(), producer.closed, track.closed]);
@@ -1 +1 @@
1
- {"version":3,"file":"subscriber.js","sourceRoot":"","sources":["../../src/ietf/subscriber.ts"],"names":[],"mappings":"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","sourcesContent":["import { Announced } from \"../announced.ts\";\nimport { Broadcast, type TrackRequest } from \"../broadcast.ts\";\nimport { Group } from \"../group.ts\";\nimport * as Path from \"../path.ts\";\nimport type { Reader, Stream } from \"../stream.ts\";\nimport type { Track } from \"../track.ts\";\nimport { error } from \"../util/error.ts\";\nimport type { Session } from \"./adapter.ts\";\nimport { Frame, type Group as GroupMessage } from \"./object.ts\";\nimport { type Publish, PublishError } from \"./publish.ts\";\nimport { type PublishNamespace, PublishNamespaceError, PublishNamespaceOk } from \"./publish_namespace.ts\";\nimport { RequestError, RequestOk } from \"./request.ts\";\nimport { Subscribe, SubscribeError, SubscribeOk, Unsubscribe } from \"./subscribe.ts\";\nimport {\n\tPublishBlocked,\n\tSubscribeNamespace,\n\tSubscribeNamespaceEntry,\n\tSubscribeNamespaceEntryDone,\n\tSubscribeNamespaceLegacy,\n\tSubscribeNamespaceOk,\n\tUnsubscribeNamespace,\n} from \"./subscribe_namespace.ts\";\nimport { Version } from \"./version.ts\";\n\n/**\n * Handles subscribing to broadcasts using moq-transport protocol.\n * Uses the stream-per-request pattern (real bidi streams for v17, virtual for v14-v16).\n *\n * @internal\n */\nexport class Subscriber {\n\t#session: Session;\n\n\t// Our subscribed tracks — keyed by trackAlias for group routing\n\t#subscribes = new Map<bigint, Track>();\n\n\t// Any currently active announcements.\n\t#announced = new Set<Path.Valid>();\n\n\t// Any consumers that want each new announcement.\n\t#announcedConsumers = new Set<Announced>();\n\n\t/**\n\t * Creates a new Subscriber instance.\n\t * @param session - The session abstraction for bidi streams and request IDs\n\t *\n\t * @internal\n\t */\n\tconstructor(session: Session) {\n\t\tthis.#session = session;\n\t}\n\n\t/**\n\t * Gets an announced reader for the specified prefix.\n\t */\n\tannounced(prefix = Path.empty()): Announced {\n\t\tconst announced = new Announced(prefix);\n\t\tfor (const active of this.#announced) {\n\t\t\tif (!Path.hasPrefix(prefix, active)) continue;\n\t\t\tannounced.append({ path: active, active: true });\n\t\t}\n\t\tthis.#announcedConsumers.add(announced);\n\n\t\tvoid this.#runAnnounced(announced, prefix).finally(() => {\n\t\t\tthis.#announcedConsumers.delete(announced);\n\t\t\tannounced.close();\n\t\t});\n\n\t\treturn announced;\n\t}\n\n\tasync #runAnnounced(announced: Announced, prefix: Path.Valid) {\n\t\tconst version = this.#session.version;\n\n\t\t// v14/v15: SubscribeNamespace on control stream (via adapter virtual stream)\n\t\t// v16+: SubscribeNamespace on its own real bidi stream\n\n\t\tconst requestId = await this.#session.nextRequestId();\n\t\tif (requestId === undefined) return;\n\n\t\ttry {\n\t\t\t// v16: use a real bidi stream (not virtual control stream)\n\t\t\tconst stream =\n\t\t\t\tversion === Version.DRAFT_16 && this.#session.openNativeBi\n\t\t\t\t\t? await this.#session.openNativeBi()\n\t\t\t\t\t: await this.#session.openBi();\n\n\t\t\ttry {\n\t\t\t\t// Draft-18+ uses SUBSCRIBE_NAMESPACE (0x50); earlier drafts use the\n\t\t\t\t// legacy 0x11 message with a Subscribe Options field.\n\t\t\t\tif (\n\t\t\t\t\tversion === Version.DRAFT_14 ||\n\t\t\t\t\tversion === Version.DRAFT_15 ||\n\t\t\t\t\tversion === Version.DRAFT_16 ||\n\t\t\t\t\tversion === Version.DRAFT_17\n\t\t\t\t) {\n\t\t\t\t\tawait stream.writer.u53(SubscribeNamespaceLegacy.id);\n\t\t\t\t\tawait new SubscribeNamespaceLegacy({ namespace: prefix, requestId }).encode(stream.writer, version);\n\t\t\t\t} else {\n\t\t\t\t\tawait stream.writer.u53(SubscribeNamespace.id);\n\t\t\t\t\tawait new SubscribeNamespace({ namespace: prefix, requestId }).encode(stream.writer, version);\n\t\t\t\t}\n\t\t\t\tconsole.debug(`subscribe_namespace written: requestId=${requestId}`);\n\n\t\t\t\t// Read response\n\t\t\t\tconst respTypeId = await stream.reader.u53();\n\t\t\t\tif (respTypeId === RequestOk.id) {\n\t\t\t\t\tawait RequestOk.decode(stream.reader, version);\n\t\t\t\t} else if (respTypeId === SubscribeNamespaceOk.id) {\n\t\t\t\t\t// v14: SubscribeNamespaceOk\n\t\t\t\t\tconst size = await stream.reader.u16();\n\t\t\t\t\tawait stream.reader.read(size);\n\t\t\t\t} else {\n\t\t\t\t\tthrow new Error(`SubscribeNamespace rejected: typeId=0x${respTypeId.toString(16)}`);\n\t\t\t\t}\n\n\t\t\t\t// Loop reading Namespace/NamespaceDone entries\n\t\t\t\tconst readLoop = (async () => {\n\t\t\t\t\tfor (;;) {\n\t\t\t\t\t\tconst done = await stream.reader.done();\n\t\t\t\t\t\tif (done) break;\n\n\t\t\t\t\t\tconst msgType = await stream.reader.u53();\n\t\t\t\t\t\tif (msgType === SubscribeNamespaceEntry.id) {\n\t\t\t\t\t\t\tconst entry = await SubscribeNamespaceEntry.decode(stream.reader, version);\n\t\t\t\t\t\t\tconst path = Path.join(prefix, entry.suffix);\n\t\t\t\t\t\t\tconsole.debug(`announced: broadcast=${path} active=true`);\n\n\t\t\t\t\t\t\tthis.#announced.add(path);\n\t\t\t\t\t\t\tfor (const consumer of this.#announcedConsumers) {\n\t\t\t\t\t\t\t\tif (!Path.hasPrefix(consumer.prefix, path)) continue;\n\t\t\t\t\t\t\t\tconsumer.append({ path, active: true });\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else if (msgType === SubscribeNamespaceEntryDone.id) {\n\t\t\t\t\t\t\tconst entry = await SubscribeNamespaceEntryDone.decode(stream.reader, version);\n\t\t\t\t\t\t\tconst path = Path.join(prefix, entry.suffix);\n\t\t\t\t\t\t\tconsole.debug(`announced: broadcast=${path} active=false`);\n\n\t\t\t\t\t\t\tthis.#announced.delete(path);\n\t\t\t\t\t\t\tfor (const consumer of this.#announcedConsumers) {\n\t\t\t\t\t\t\t\tif (!Path.hasPrefix(consumer.prefix, path)) continue;\n\t\t\t\t\t\t\t\tconsumer.append({ path, active: false });\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else if (msgType === PublishBlocked.id && version === Version.DRAFT_17) {\n\t\t\t\t\t\t\tconst blocked = await PublishBlocked.decode(stream.reader, version);\n\t\t\t\t\t\t\tconsole.debug(`publish_blocked: suffix=${blocked.suffix} track=${blocked.trackName}`);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\t\t`unexpected message on subscribe_namespace stream: 0x${msgType.toString(16)}`,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t})();\n\n\t\t\t\t// Wait for either the read loop or the announced to close\n\t\t\t\tawait Promise.race([readLoop, announced.closed]);\n\n\t\t\t\t// For v14/v15: send UnsubscribeNamespace before closing\n\t\t\t\tif (version === Version.DRAFT_14 || version === Version.DRAFT_15) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tawait stream.writer.u53(UnsubscribeNamespace.id);\n\t\t\t\t\t\tconst unsub = new UnsubscribeNamespace({ requestId });\n\t\t\t\t\t\tawait unsub.encode(stream.writer, version);\n\t\t\t\t\t} catch {\n\t\t\t\t\t\t// Stream might already be closed\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tstream.close();\n\t\t\t} catch (err) {\n\t\t\t\tstream.abort(error(err));\n\t\t\t\tthrow err;\n\t\t\t}\n\t\t} catch (err: unknown) {\n\t\t\tconst e = error(err);\n\t\t\tconsole.warn(`subscribe_namespace error: ${e.message}`);\n\t\t}\n\t}\n\n\t/**\n\t * Consumes a broadcast from the connection.\n\t */\n\tconsume(path: Path.Valid): Broadcast {\n\t\tconst broadcast = new Broadcast();\n\n\t\tvoid (async () => {\n\t\t\tfor (;;) {\n\t\t\t\tconst request = await broadcast.requested();\n\t\t\t\tif (!request) break;\n\t\t\t\tvoid this.#runSubscribe(path, request);\n\t\t\t}\n\t\t})();\n\n\t\treturn broadcast;\n\t}\n\n\tasync #runSubscribe(broadcast: Path.Valid, request: TrackRequest) {\n\t\tconst version = this.#session.version;\n\t\tconst requestId = await this.#session.nextRequestId();\n\t\tif (requestId === undefined) {\n\t\t\trequest.track.close(new Error(\"session closed\"));\n\t\t\treturn;\n\t\t}\n\n\t\tconsole.debug(`subscribe start: id=${requestId} broadcast=${broadcast} track=${request.track.name}`);\n\n\t\ttry {\n\t\t\tconst stream = await this.#session.openBi();\n\n\t\t\ttry {\n\t\t\t\t// Write Subscribe\n\t\t\t\tawait stream.writer.u53(Subscribe.id);\n\t\t\t\tconst msg = new Subscribe({\n\t\t\t\t\trequestId,\n\t\t\t\t\ttrackNamespace: broadcast,\n\t\t\t\t\ttrackName: request.track.name,\n\t\t\t\t\tsubscriberPriority: request.priority,\n\t\t\t\t});\n\t\t\t\tawait msg.encode(stream.writer, version);\n\t\t\t\tconsole.debug(`subscribe written: id=${requestId} broadcast=${broadcast} track=${request.track.name}`);\n\n\t\t\t\t// Pre-register with requestId so early group uni streams aren't dropped.\n\t\t\t\t// The publisher typically uses requestId as the trackAlias.\n\t\t\t\tthis.#subscribes.set(requestId, request.track);\n\n\t\t\t\t// Read response (SubscribeOk or error)\n\t\t\t\tconst respTypeId = await stream.reader.u53();\n\t\t\t\tif (respTypeId === SubscribeOk.id) {\n\t\t\t\t\tconst ok = await SubscribeOk.decode(stream.reader, version);\n\t\t\t\t\t// Update registration to use the actual trackAlias from SubscribeOk\n\t\t\t\t\tif (ok.trackAlias !== requestId) {\n\t\t\t\t\t\tthis.#subscribes.delete(requestId);\n\t\t\t\t\t\tthis.#subscribes.set(ok.trackAlias, request.track);\n\t\t\t\t\t}\n\t\t\t\t\tconsole.debug(`subscribe ok: id=${requestId} broadcast=${broadcast} track=${request.track.name}`);\n\n\t\t\t\t\ttry {\n\t\t\t\t\t\t// Wait for stream close (= PublishDone) or track close (= local unsubscribe)\n\t\t\t\t\t\tawait Promise.race([stream.reader.closed, request.track.closed]);\n\n\t\t\t\t\t\t// For v14-v16: send Unsubscribe before closing (removed in v17+)\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\tversion === Version.DRAFT_14 ||\n\t\t\t\t\t\t\tversion === Version.DRAFT_15 ||\n\t\t\t\t\t\t\tversion === Version.DRAFT_16\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\tawait stream.writer.u53(Unsubscribe.id);\n\t\t\t\t\t\t\t\tconst unsub = new Unsubscribe({ requestId });\n\t\t\t\t\t\t\t\tawait unsub.encode(stream.writer, version);\n\t\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t\t// Stream might already be closed\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\trequest.track.close();\n\t\t\t\t\t\tstream.close();\n\t\t\t\t\t\tconsole.debug(\n\t\t\t\t\t\t\t`subscribe close: id=${requestId} broadcast=${broadcast} track=${request.track.name}`,\n\t\t\t\t\t\t);\n\t\t\t\t\t} finally {\n\t\t\t\t\t\tthis.#subscribes.delete(ok.trackAlias);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t// Clean up pre-registered entry on error\n\t\t\t\t\tthis.#subscribes.delete(requestId);\n\n\t\t\t\t\t// Error response\n\t\t\t\t\tlet reasonPhrase = \"unknown error\";\n\t\t\t\t\ttry {\n\t\t\t\t\t\tif (respTypeId === RequestError.id) {\n\t\t\t\t\t\t\t// SubscribeError (v14) or RequestError (v15+)\n\t\t\t\t\t\t\tconst err =\n\t\t\t\t\t\t\t\tversion === Version.DRAFT_14\n\t\t\t\t\t\t\t\t\t? await SubscribeError.decode(stream.reader, version)\n\t\t\t\t\t\t\t\t\t: await RequestError.decode(stream.reader, version);\n\t\t\t\t\t\t\treasonPhrase = `code=${err.errorCode} reason=${err.reasonPhrase}`;\n\t\t\t\t\t\t}\n\t\t\t\t\t} catch {\n\t\t\t\t\t\t// Decoding error response failed, use default message\n\t\t\t\t\t}\n\t\t\t\t\tthrow new Error(`SUBSCRIBE error: ${reasonPhrase}`);\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\tthis.#subscribes.delete(requestId);\n\t\t\t\tstream.abort(error(err));\n\t\t\t\tthrow err;\n\t\t\t}\n\t\t} catch (err) {\n\t\t\tconst e = error(err);\n\t\t\trequest.track.close(e);\n\t\t\tconsole.warn(\n\t\t\t\t`subscribe error: id=${requestId} broadcast=${broadcast} track=${request.track.name} error=${e.message}`,\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Handles an incoming PUBLISH_NAMESPACE on a bidi stream.\n\t * Tracks announced broadcasts and notifies consumers.\n\t *\n\t * @internal\n\t */\n\tasync runPublishNamespace(msg: PublishNamespace, stream: Stream) {\n\t\tconst version = this.#session.version;\n\t\tconst path = msg.trackNamespace;\n\n\t\tif (this.#announced.has(path)) {\n\t\t\tconsole.warn(\"duplicate PublishNamespace\");\n\t\t\tif (version === Version.DRAFT_14) {\n\t\t\t\tawait stream.writer.u53(PublishNamespaceError.id);\n\t\t\t\tconst err = new PublishNamespaceError({\n\t\t\t\t\trequestId: msg.requestId,\n\t\t\t\t\terrorCode: 409,\n\t\t\t\t\treasonPhrase: \"duplicate namespace\",\n\t\t\t\t});\n\t\t\t\tawait err.encode(stream.writer, version);\n\t\t\t} else {\n\t\t\t\tawait stream.writer.u53(RequestError.id);\n\t\t\t\tconst err = new RequestError({\n\t\t\t\t\trequestId: version === Version.DRAFT_15 || version === Version.DRAFT_16 ? msg.requestId : undefined,\n\t\t\t\t\terrorCode: 409,\n\t\t\t\t\treasonPhrase: \"duplicate namespace\",\n\t\t\t\t});\n\t\t\t\tawait err.encode(stream.writer, version);\n\t\t\t}\n\t\t\tstream.close();\n\t\t\treturn;\n\t\t}\n\n\t\tthis.#announced.add(path);\n\n\t\ttry {\n\t\t\t// Send OK first — must complete before notifying consumers,\n\t\t\t// because consumers may trigger Subscribe writes that would\n\t\t\t// interleave with our OK on the control stream.\n\t\t\tif (version === Version.DRAFT_14) {\n\t\t\t\tawait stream.writer.u53(PublishNamespaceOk.id);\n\t\t\t\tconst ok = new PublishNamespaceOk({ requestId: msg.requestId });\n\t\t\t\tawait ok.encode(stream.writer, version);\n\t\t\t} else {\n\t\t\t\tawait stream.writer.u53(RequestOk.id);\n\t\t\t\tconst ok = new RequestOk({\n\t\t\t\t\trequestId: version === Version.DRAFT_15 || version === Version.DRAFT_16 ? msg.requestId : undefined,\n\t\t\t\t});\n\t\t\t\tawait ok.encode(stream.writer, version);\n\t\t\t}\n\n\t\t\tconsole.debug(`announced: broadcast=${path} active=true`);\n\n\t\t\t// Notify consumers after OK is written\n\t\t\tfor (const consumer of this.#announcedConsumers) {\n\t\t\t\tconst suffix = Path.stripPrefix(consumer.prefix, path);\n\t\t\t\tif (suffix === null) continue;\n\t\t\t\tconsumer.append({ path, active: true });\n\t\t\t}\n\n\t\t\t// Wait for stream close (= PublishNamespaceDone)\n\t\t\tconsole.debug(`runPublishNamespace: awaiting stream.reader.closed for ${path}`);\n\t\t\tawait stream.reader.closed;\n\t\t\tconsole.debug(`runPublishNamespace: stream.reader.closed resolved for ${path}`);\n\t\t} finally {\n\t\t\tthis.#announced.delete(path);\n\t\t\tconsole.debug(`announced: broadcast=${path} active=false`);\n\n\t\t\tfor (const consumer of this.#announcedConsumers) {\n\t\t\t\tconst suffix = Path.stripPrefix(consumer.prefix, path);\n\t\t\t\tif (suffix === null) continue;\n\t\t\t\ttry {\n\t\t\t\t\tconsumer.append({ path, active: false });\n\t\t\t\t} catch {\n\t\t\t\t\t// Consumer already closed, will be cleaned up\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Handles an incoming PUBLISH on a bidi stream.\n\t * We don't support reverse publish, so send error.\n\t *\n\t * @internal\n\t */\n\tasync runPublish(msg: Publish, stream: Stream) {\n\t\tconst version = this.#session.version;\n\n\t\tif (version === Version.DRAFT_14) {\n\t\t\tawait stream.writer.u53(PublishError.id);\n\t\t\tconst err = new PublishError({\n\t\t\t\trequestId: msg.requestId,\n\t\t\t\terrorCode: 500,\n\t\t\t\treasonPhrase: \"publish not supported\",\n\t\t\t});\n\t\t\tawait err.encode(stream.writer, version);\n\t\t} else {\n\t\t\tawait stream.writer.u53(RequestError.id);\n\t\t\tconst err = new RequestError({\n\t\t\t\trequestId: version === Version.DRAFT_15 || version === Version.DRAFT_16 ? msg.requestId : undefined,\n\t\t\t\terrorCode: 500,\n\t\t\t\treasonPhrase: \"publish not supported\",\n\t\t\t});\n\t\t\tawait err.encode(stream.writer, version);\n\t\t}\n\t\tstream.close();\n\t}\n\n\t/**\n\t * Handles an ObjectStream message (group + frames on uni stream).\n\t *\n\t * @internal\n\t */\n\tasync handleGroup(group: GroupMessage, stream: Reader) {\n\t\tconst producer = new Group(group.groupId);\n\n\t\tif (group.subGroupId !== 0) {\n\t\t\tthrow new Error(\"subgroups are not supported\");\n\t\t}\n\n\t\ttry {\n\t\t\t// Look up by trackAlias directly\n\t\t\tconst track = this.#subscribes.get(group.trackAlias);\n\t\t\tif (!track) {\n\t\t\t\t// Fallback: try treating trackAlias as requestId (for compat)\n\t\t\t\tthrow new Error(`unknown track: trackAlias=${group.trackAlias}`);\n\t\t\t}\n\n\t\t\ttrack.writeGroup(producer);\n\n\t\t\tfor (;;) {\n\t\t\t\tconst done = await Promise.race([stream.done(), producer.closed, track.closed]);\n\t\t\t\tif (done !== false) break;\n\n\t\t\t\tconst frame = await Frame.decode(stream, group.flags);\n\t\t\t\tif (frame.payload === undefined) break;\n\n\t\t\t\tproducer.writeFrame(frame.payload, frame.extensions);\n\t\t\t}\n\n\t\t\tproducer.close();\n\t\t} catch (err: unknown) {\n\t\t\tconst e = error(err);\n\t\t\tproducer.close(e);\n\t\t\tstream.stop(e);\n\t\t}\n\t}\n}\n"]}
1
+ {"version":3,"file":"subscriber.js","sourceRoot":"","sources":["../../src/ietf/subscriber.ts"],"names":[],"mappings":"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","sourcesContent":["import { Announced } from \"../announced.ts\";\nimport { Broadcast, type TrackRequest } from \"../broadcast.ts\";\nimport { Group } from \"../group.ts\";\nimport * as Path from \"../path.ts\";\nimport type { Reader, Stream } from \"../stream.ts\";\nimport type { Track } from \"../track.ts\";\nimport { error } from \"../util/error.ts\";\nimport type { Session } from \"./adapter.ts\";\nimport { TrackAliases } from \"./aliases.ts\";\nimport { Frame, type Group as GroupMessage } from \"./object.ts\";\nimport { type Publish, PublishError } from \"./publish.ts\";\nimport { type PublishNamespace, PublishNamespaceError, PublishNamespaceOk } from \"./publish_namespace.ts\";\nimport { RequestError, RequestOk } from \"./request.ts\";\nimport { Subscribe, SubscribeError, SubscribeOk, Unsubscribe } from \"./subscribe.ts\";\nimport {\n\tPublishBlocked,\n\tSubscribeNamespace,\n\tSubscribeNamespaceEntry,\n\tSubscribeNamespaceEntryDone,\n\tSubscribeNamespaceLegacy,\n\tSubscribeNamespaceOk,\n\tUnsubscribeNamespace,\n} from \"./subscribe_namespace.ts\";\nimport { Version } from \"./version.ts\";\n\n/**\n * Handles subscribing to broadcasts using moq-transport protocol.\n * Uses the stream-per-request pattern (real bidi streams for v17, virtual for v14-v16).\n *\n * @internal\n */\nexport class Subscriber {\n\t#session: Session;\n\n\t// Publisher-chosen aliases used by incoming group streams.\n\t#aliases = new TrackAliases<Track>();\n\n\t// Any currently active announcements.\n\t#announced = new Set<Path.Valid>();\n\n\t// Any consumers that want each new announcement.\n\t#announcedConsumers = new Set<Announced>();\n\n\t/**\n\t * Creates a new Subscriber instance.\n\t * @param session - The session abstraction for bidi streams and request IDs\n\t *\n\t * @internal\n\t */\n\tconstructor(session: Session) {\n\t\tthis.#session = session;\n\t}\n\n\t/**\n\t * Gets an announced reader for the specified prefix.\n\t */\n\tannounced(prefix = Path.empty()): Announced {\n\t\tconst announced = new Announced(prefix);\n\t\tfor (const active of this.#announced) {\n\t\t\tif (!Path.hasPrefix(prefix, active)) continue;\n\t\t\tannounced.append({ path: active, active: true });\n\t\t}\n\t\tthis.#announcedConsumers.add(announced);\n\n\t\tvoid this.#runAnnounced(announced, prefix).finally(() => {\n\t\t\tthis.#announcedConsumers.delete(announced);\n\t\t\tannounced.close();\n\t\t});\n\n\t\treturn announced;\n\t}\n\n\tasync #runAnnounced(announced: Announced, prefix: Path.Valid) {\n\t\tconst version = this.#session.version;\n\n\t\t// v14/v15: SubscribeNamespace on control stream (via adapter virtual stream)\n\t\t// v16+: SubscribeNamespace on its own real bidi stream\n\n\t\tconst requestId = await this.#session.nextRequestId();\n\t\tif (requestId === undefined) return;\n\n\t\ttry {\n\t\t\t// v16: use a real bidi stream (not virtual control stream)\n\t\t\tconst stream =\n\t\t\t\tversion === Version.DRAFT_16 && this.#session.openNativeBi\n\t\t\t\t\t? await this.#session.openNativeBi()\n\t\t\t\t\t: await this.#session.openBi();\n\n\t\t\ttry {\n\t\t\t\t// Draft-18+ uses SUBSCRIBE_NAMESPACE (0x50); earlier drafts use the\n\t\t\t\t// legacy 0x11 message with a Subscribe Options field.\n\t\t\t\tif (\n\t\t\t\t\tversion === Version.DRAFT_14 ||\n\t\t\t\t\tversion === Version.DRAFT_15 ||\n\t\t\t\t\tversion === Version.DRAFT_16 ||\n\t\t\t\t\tversion === Version.DRAFT_17\n\t\t\t\t) {\n\t\t\t\t\tawait stream.writer.u53(SubscribeNamespaceLegacy.id);\n\t\t\t\t\tawait new SubscribeNamespaceLegacy({ namespace: prefix, requestId }).encode(stream.writer, version);\n\t\t\t\t} else {\n\t\t\t\t\tawait stream.writer.u53(SubscribeNamespace.id);\n\t\t\t\t\tawait new SubscribeNamespace({ namespace: prefix, requestId }).encode(stream.writer, version);\n\t\t\t\t}\n\t\t\t\tconsole.debug(`subscribe_namespace written: requestId=${requestId}`);\n\n\t\t\t\t// Read response\n\t\t\t\tconst respTypeId = await stream.reader.u53();\n\t\t\t\tif (respTypeId === RequestOk.id) {\n\t\t\t\t\tawait RequestOk.decode(stream.reader, version);\n\t\t\t\t} else if (respTypeId === SubscribeNamespaceOk.id) {\n\t\t\t\t\t// v14: SubscribeNamespaceOk\n\t\t\t\t\tconst size = await stream.reader.u16();\n\t\t\t\t\tawait stream.reader.read(size);\n\t\t\t\t} else {\n\t\t\t\t\tthrow new Error(`SubscribeNamespace rejected: typeId=0x${respTypeId.toString(16)}`);\n\t\t\t\t}\n\n\t\t\t\t// Loop reading Namespace/NamespaceDone entries\n\t\t\t\tconst readLoop = (async () => {\n\t\t\t\t\tfor (;;) {\n\t\t\t\t\t\tconst done = await stream.reader.done();\n\t\t\t\t\t\tif (done) break;\n\n\t\t\t\t\t\tconst msgType = await stream.reader.u53();\n\t\t\t\t\t\tif (msgType === SubscribeNamespaceEntry.id) {\n\t\t\t\t\t\t\tconst entry = await SubscribeNamespaceEntry.decode(stream.reader, version);\n\t\t\t\t\t\t\tconst path = Path.join(prefix, entry.suffix);\n\t\t\t\t\t\t\tconsole.debug(`announced: broadcast=${path} active=true`);\n\n\t\t\t\t\t\t\tthis.#announced.add(path);\n\t\t\t\t\t\t\tfor (const consumer of this.#announcedConsumers) {\n\t\t\t\t\t\t\t\tif (!Path.hasPrefix(consumer.prefix, path)) continue;\n\t\t\t\t\t\t\t\tconsumer.append({ path, active: true });\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else if (msgType === SubscribeNamespaceEntryDone.id) {\n\t\t\t\t\t\t\tconst entry = await SubscribeNamespaceEntryDone.decode(stream.reader, version);\n\t\t\t\t\t\t\tconst path = Path.join(prefix, entry.suffix);\n\t\t\t\t\t\t\tconsole.debug(`announced: broadcast=${path} active=false`);\n\n\t\t\t\t\t\t\tthis.#announced.delete(path);\n\t\t\t\t\t\t\tfor (const consumer of this.#announcedConsumers) {\n\t\t\t\t\t\t\t\tif (!Path.hasPrefix(consumer.prefix, path)) continue;\n\t\t\t\t\t\t\t\tconsumer.append({ path, active: false });\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else if (msgType === PublishBlocked.id && version === Version.DRAFT_17) {\n\t\t\t\t\t\t\tconst blocked = await PublishBlocked.decode(stream.reader, version);\n\t\t\t\t\t\t\tconsole.debug(`publish_blocked: suffix=${blocked.suffix} track=${blocked.trackName}`);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\t\t`unexpected message on subscribe_namespace stream: 0x${msgType.toString(16)}`,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t})();\n\n\t\t\t\t// Wait for either the read loop or the announced to close\n\t\t\t\tawait Promise.race([readLoop, announced.closed]);\n\n\t\t\t\t// For v14/v15: send UnsubscribeNamespace before closing\n\t\t\t\tif (version === Version.DRAFT_14 || version === Version.DRAFT_15) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tawait stream.writer.u53(UnsubscribeNamespace.id);\n\t\t\t\t\t\tconst unsub = new UnsubscribeNamespace({ requestId });\n\t\t\t\t\t\tawait unsub.encode(stream.writer, version);\n\t\t\t\t\t} catch {\n\t\t\t\t\t\t// Stream might already be closed\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tstream.close();\n\t\t\t} catch (err) {\n\t\t\t\tstream.abort(error(err));\n\t\t\t\tthrow err;\n\t\t\t}\n\t\t} catch (err: unknown) {\n\t\t\tconst e = error(err);\n\t\t\tconsole.warn(`subscribe_namespace error: ${e.message}`);\n\t\t}\n\t}\n\n\t/**\n\t * Consumes a broadcast from the connection.\n\t */\n\tconsume(path: Path.Valid): Broadcast {\n\t\tconst broadcast = new Broadcast();\n\n\t\tvoid (async () => {\n\t\t\tfor (;;) {\n\t\t\t\tconst request = await broadcast.requested();\n\t\t\t\tif (!request) break;\n\t\t\t\tvoid this.#runSubscribe(path, request);\n\t\t\t}\n\t\t})();\n\n\t\treturn broadcast;\n\t}\n\n\tasync #runSubscribe(broadcast: Path.Valid, request: TrackRequest) {\n\t\tconst version = this.#session.version;\n\t\tconst requestId = await this.#session.nextRequestId();\n\t\tif (requestId === undefined) {\n\t\t\trequest.track.close(new Error(\"session closed\"));\n\t\t\treturn;\n\t\t}\n\n\t\tconsole.debug(`subscribe start: id=${requestId} broadcast=${broadcast} track=${request.track.name}`);\n\n\t\ttry {\n\t\t\tconst stream = await this.#session.openBi();\n\n\t\t\ttry {\n\t\t\t\t// Write Subscribe\n\t\t\t\tawait stream.writer.u53(Subscribe.id);\n\t\t\t\tconst msg = new Subscribe({\n\t\t\t\t\trequestId,\n\t\t\t\t\ttrackNamespace: broadcast,\n\t\t\t\t\ttrackName: request.track.name,\n\t\t\t\t\tsubscriberPriority: request.priority,\n\t\t\t\t});\n\t\t\t\tawait msg.encode(stream.writer, version);\n\t\t\t\tconsole.debug(`subscribe written: id=${requestId} broadcast=${broadcast} track=${request.track.name}`);\n\n\t\t\t\t// Read response (SubscribeOk or error)\n\t\t\t\tconst respTypeId = await stream.reader.u53();\n\t\t\t\tif (respTypeId === SubscribeOk.id) {\n\t\t\t\t\tconst ok = await SubscribeOk.decode(stream.reader, version);\n\t\t\t\t\ttry {\n\t\t\t\t\t\tthis.#aliases.set(ok.trackAlias, request.track);\n\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\tthis.#session.close();\n\t\t\t\t\t\tthrow err;\n\t\t\t\t\t}\n\t\t\t\t\tconsole.debug(\n\t\t\t\t\t\t`subscribe ok: id=${requestId} broadcast=${broadcast} track=${request.track.name} alias=${ok.trackAlias}`,\n\t\t\t\t\t);\n\n\t\t\t\t\ttry {\n\t\t\t\t\t\t// Wait for stream close (= PublishDone) or track close (= local unsubscribe)\n\t\t\t\t\t\tawait Promise.race([stream.reader.closed, request.track.closed]);\n\n\t\t\t\t\t\t// For v14-v16: send Unsubscribe before closing (removed in v17+)\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\tversion === Version.DRAFT_14 ||\n\t\t\t\t\t\t\tversion === Version.DRAFT_15 ||\n\t\t\t\t\t\t\tversion === Version.DRAFT_16\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\tawait stream.writer.u53(Unsubscribe.id);\n\t\t\t\t\t\t\t\tconst unsub = new Unsubscribe({ requestId });\n\t\t\t\t\t\t\t\tawait unsub.encode(stream.writer, version);\n\t\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t\t// Stream might already be closed\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\trequest.track.close();\n\t\t\t\t\t\tstream.close();\n\t\t\t\t\t\tconsole.debug(\n\t\t\t\t\t\t\t`subscribe close: id=${requestId} broadcast=${broadcast} track=${request.track.name}`,\n\t\t\t\t\t\t);\n\t\t\t\t\t} finally {\n\t\t\t\t\t\tthis.#aliases.delete(ok.trackAlias, request.track);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t// Error response\n\t\t\t\t\tlet reasonPhrase = \"unknown error\";\n\t\t\t\t\ttry {\n\t\t\t\t\t\tif (respTypeId === RequestError.id) {\n\t\t\t\t\t\t\t// SubscribeError (v14) or RequestError (v15+)\n\t\t\t\t\t\t\tconst err =\n\t\t\t\t\t\t\t\tversion === Version.DRAFT_14\n\t\t\t\t\t\t\t\t\t? await SubscribeError.decode(stream.reader, version)\n\t\t\t\t\t\t\t\t\t: await RequestError.decode(stream.reader, version);\n\t\t\t\t\t\t\treasonPhrase = `code=${err.errorCode} reason=${err.reasonPhrase}`;\n\t\t\t\t\t\t}\n\t\t\t\t\t} catch {\n\t\t\t\t\t\t// Decoding error response failed, use default message\n\t\t\t\t\t}\n\t\t\t\t\tthrow new Error(`SUBSCRIBE error: ${reasonPhrase}`);\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\tstream.abort(error(err));\n\t\t\t\tthrow err;\n\t\t\t}\n\t\t} catch (err) {\n\t\t\tconst e = error(err);\n\t\t\trequest.track.close(e);\n\t\t\tconsole.warn(\n\t\t\t\t`subscribe error: id=${requestId} broadcast=${broadcast} track=${request.track.name} error=${e.message}`,\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Handles an incoming PUBLISH_NAMESPACE on a bidi stream.\n\t * Tracks announced broadcasts and notifies consumers.\n\t *\n\t * @internal\n\t */\n\tasync runPublishNamespace(msg: PublishNamespace, stream: Stream) {\n\t\tconst version = this.#session.version;\n\t\tconst path = msg.trackNamespace;\n\n\t\tif (this.#announced.has(path)) {\n\t\t\tconsole.warn(\"duplicate PublishNamespace\");\n\t\t\tif (version === Version.DRAFT_14) {\n\t\t\t\tawait stream.writer.u53(PublishNamespaceError.id);\n\t\t\t\tconst err = new PublishNamespaceError({\n\t\t\t\t\trequestId: msg.requestId,\n\t\t\t\t\terrorCode: 409,\n\t\t\t\t\treasonPhrase: \"duplicate namespace\",\n\t\t\t\t});\n\t\t\t\tawait err.encode(stream.writer, version);\n\t\t\t} else {\n\t\t\t\tawait stream.writer.u53(RequestError.id);\n\t\t\t\tconst err = new RequestError({\n\t\t\t\t\trequestId: version === Version.DRAFT_15 || version === Version.DRAFT_16 ? msg.requestId : undefined,\n\t\t\t\t\terrorCode: 409,\n\t\t\t\t\treasonPhrase: \"duplicate namespace\",\n\t\t\t\t});\n\t\t\t\tawait err.encode(stream.writer, version);\n\t\t\t}\n\t\t\tstream.close();\n\t\t\treturn;\n\t\t}\n\n\t\tthis.#announced.add(path);\n\n\t\ttry {\n\t\t\t// Send OK first — must complete before notifying consumers,\n\t\t\t// because consumers may trigger Subscribe writes that would\n\t\t\t// interleave with our OK on the control stream.\n\t\t\tif (version === Version.DRAFT_14) {\n\t\t\t\tawait stream.writer.u53(PublishNamespaceOk.id);\n\t\t\t\tconst ok = new PublishNamespaceOk({ requestId: msg.requestId });\n\t\t\t\tawait ok.encode(stream.writer, version);\n\t\t\t} else {\n\t\t\t\tawait stream.writer.u53(RequestOk.id);\n\t\t\t\tconst ok = new RequestOk({\n\t\t\t\t\trequestId: version === Version.DRAFT_15 || version === Version.DRAFT_16 ? msg.requestId : undefined,\n\t\t\t\t});\n\t\t\t\tawait ok.encode(stream.writer, version);\n\t\t\t}\n\n\t\t\tconsole.debug(`announced: broadcast=${path} active=true`);\n\n\t\t\t// Notify consumers after OK is written\n\t\t\tfor (const consumer of this.#announcedConsumers) {\n\t\t\t\tconst suffix = Path.stripPrefix(consumer.prefix, path);\n\t\t\t\tif (suffix === null) continue;\n\t\t\t\tconsumer.append({ path, active: true });\n\t\t\t}\n\n\t\t\t// Wait for stream close (= PublishNamespaceDone)\n\t\t\tconsole.debug(`runPublishNamespace: awaiting stream.reader.closed for ${path}`);\n\t\t\tawait stream.reader.closed;\n\t\t\tconsole.debug(`runPublishNamespace: stream.reader.closed resolved for ${path}`);\n\t\t} finally {\n\t\t\tthis.#announced.delete(path);\n\t\t\tconsole.debug(`announced: broadcast=${path} active=false`);\n\n\t\t\tfor (const consumer of this.#announcedConsumers) {\n\t\t\t\tconst suffix = Path.stripPrefix(consumer.prefix, path);\n\t\t\t\tif (suffix === null) continue;\n\t\t\t\ttry {\n\t\t\t\t\tconsumer.append({ path, active: false });\n\t\t\t\t} catch {\n\t\t\t\t\t// Consumer already closed, will be cleaned up\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Handles an incoming PUBLISH on a bidi stream.\n\t * We don't support reverse publish, so send error.\n\t *\n\t * @internal\n\t */\n\tasync runPublish(msg: Publish, stream: Stream) {\n\t\tconst version = this.#session.version;\n\n\t\tif (version === Version.DRAFT_14) {\n\t\t\tawait stream.writer.u53(PublishError.id);\n\t\t\tconst err = new PublishError({\n\t\t\t\trequestId: msg.requestId,\n\t\t\t\terrorCode: 500,\n\t\t\t\treasonPhrase: \"publish not supported\",\n\t\t\t});\n\t\t\tawait err.encode(stream.writer, version);\n\t\t} else {\n\t\t\tawait stream.writer.u53(RequestError.id);\n\t\t\tconst err = new RequestError({\n\t\t\t\trequestId: version === Version.DRAFT_15 || version === Version.DRAFT_16 ? msg.requestId : undefined,\n\t\t\t\terrorCode: 500,\n\t\t\t\treasonPhrase: \"publish not supported\",\n\t\t\t});\n\t\t\tawait err.encode(stream.writer, version);\n\t\t}\n\t\tstream.close();\n\t}\n\n\t/**\n\t * Handles an ObjectStream message (group + frames on uni stream).\n\t *\n\t * @internal\n\t */\n\tasync handleGroup(group: GroupMessage, stream: Reader) {\n\t\tconst producer = new Group(group.groupId);\n\n\t\tif (group.subGroupId !== 0) {\n\t\t\tthrow new Error(\"subgroups are not supported\");\n\t\t}\n\n\t\ttry {\n\t\t\t// The control message establishing this alias can arrive after the data stream.\n\t\t\tconst track = await this.#aliases.get(group.trackAlias);\n\n\t\t\ttrack.writeGroup(producer);\n\n\t\t\tfor (;;) {\n\t\t\t\tconst done = await Promise.race([stream.done(), producer.closed, track.closed]);\n\t\t\t\tif (done !== false) break;\n\n\t\t\t\tconst frame = await Frame.decode(stream, group.flags);\n\t\t\t\tif (frame.payload === undefined) break;\n\n\t\t\t\tproducer.writeFrame(frame.payload, frame.extensions);\n\t\t\t}\n\n\t\t\tproducer.close();\n\t\t} catch (err: unknown) {\n\t\t\tconst e = error(err);\n\t\t\tproducer.close(e);\n\t\t\tstream.stop(e);\n\t\t}\n\t}\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"subscriber.d.ts","sourceRoot":"","sources":["../../src/lite/subscriber.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,EAAE,SAAS,EAAqB,MAAM,iBAAiB,CAAC;AAE/D,OAAO,KAAK,IAAI,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,KAAK,MAAM,EAAU,MAAM,cAAc,CAAC;AACnD,OAAO,KAAK,KAAK,IAAI,MAAM,YAAY,CAAC;AAIxC,OAAO,KAAK,EAAE,KAAK,IAAI,YAAY,EAAE,MAAM,YAAY,CAAC;AACxD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAI1C,OAAO,EAAkB,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvD;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAChC;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;CACrB;AAED;;;;GAIG;AACH,qBAAa,UAAU;;IAItB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAI1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAYxB;;;;;;;;;OASG;IACH,YACC,IAAI,EAAE,YAAY,EAClB,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,MAAM,EACd,aAAa,CAAC,EAAE,SAAS,EACzB,GAAG,CAAC,EAAE,MAAM,CAAC,IAAI,CAAC,KAAK,GAAG,SAAS,CAAC,EAOpC;IAED;;;;;OAKG;IACH,SAAS,CAAC,MAAM,aAAe,EAAE,OAAO,GAAE,gBAAqB,GAAG,SAAS,CAI1E;IA6DD;;;;;OAKG;IACH,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,GAAG,SAAS,CAYnC;IAmHD;;;;;;OAMG;IACG,QAAQ,CAAC,KAAK,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,iBAsCjD;IAED;;;;;;;;;;OAUG;IACG,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC,CAyB9B;IAED,KAAK,SAMJ;CACD"}
1
+ {"version":3,"file":"subscriber.d.ts","sourceRoot":"","sources":["../../src/lite/subscriber.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,EAAE,SAAS,EAAqB,MAAM,iBAAiB,CAAC;AAE/D,OAAO,KAAK,IAAI,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,KAAK,MAAM,EAAU,MAAM,cAAc,CAAC;AACnD,OAAO,KAAK,KAAK,IAAI,MAAM,YAAY,CAAC;AAIxC,OAAO,KAAK,EAAE,KAAK,IAAI,YAAY,EAAE,MAAM,YAAY,CAAC;AACxD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAI1C,OAAO,EAAkB,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvD;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAChC;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;CACrB;AAED;;;;GAIG;AACH,qBAAa,UAAU;;IAItB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAI1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAexB;;;;;;;;;OASG;IACH,YACC,IAAI,EAAE,YAAY,EAClB,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,MAAM,EACd,aAAa,CAAC,EAAE,SAAS,EACzB,GAAG,CAAC,EAAE,MAAM,CAAC,IAAI,CAAC,KAAK,GAAG,SAAS,CAAC,EAOpC;IAED;;;;;OAKG;IACH,SAAS,CAAC,MAAM,aAAe,EAAE,OAAO,GAAE,gBAAqB,GAAG,SAAS,CAI1E;IA6DD;;;;;OAKG;IACH,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,GAAG,SAAS,CAYnC;IAmHD;;;;;;OAMG;IACG,QAAQ,CAAC,KAAK,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,iBAsCjD;IAED;;;;;;;;;;OAUG;IACG,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC,CA2B9B;IAED,KAAK,SAQJ;CACD"}
@@ -29,6 +29,8 @@ export class Subscriber {
29
29
  #recvBandwidth;
30
30
  // RTT producer (Lite04+ only).
31
31
  #rtt;
32
+ // Distinguishes failures from streams torn down by Subscriber.close().
33
+ #closed = new AbortController();
32
34
  /**
33
35
  * Creates a new Subscriber instance.
34
36
  * @param quic - The WebTransport session to use
@@ -299,7 +301,9 @@ export class Subscriber {
299
301
  }
300
302
  }
301
303
  catch (err) {
302
- console.warn("probe stream error", err);
304
+ if (!this.#closed.signal.aborted) {
305
+ console.warn("probe stream error", err);
306
+ }
303
307
  }
304
308
  finally {
305
309
  this.#recvBandwidth.set(undefined);
@@ -307,6 +311,7 @@ export class Subscriber {
307
311
  }
308
312
  }
309
313
  close() {
314
+ this.#closed.abort();
310
315
  for (const track of this.#subscribes.values()) {
311
316
  track.close();
312
317
  }
@@ -1 +1 @@
1
- {"version":3,"file":"subscriber.js","sourceRoot":"","sources":["../../src/lite/subscriber.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Signal } from \"@moq/signals\";\nimport { Announced } from \"../announced.ts\";\nimport type { Bandwidth } from \"../bandwidth.ts\";\nimport { Broadcast, type TrackRequest } from \"../broadcast.ts\";\nimport { Group } from \"../group.ts\";\nimport * as Path from \"../path.ts\";\nimport { type Reader, Stream } from \"../stream.ts\";\nimport type * as Time from \"../time.ts\";\nimport type { Track } from \"../track.ts\";\nimport { error } from \"../util/error.ts\";\nimport { Announce, AnnounceInit, AnnounceInterest } from \"./announce.ts\";\nimport type { Group as GroupMessage } from \"./group.ts\";\nimport type { Origin } from \"./origin.ts\";\nimport { Probe } from \"./probe.ts\";\nimport { StreamId } from \"./stream.ts\";\nimport { decodeSubscribeResponse, decodeSubscribeResponseMaybe, Subscribe, SubscribeUpdate } from \"./subscribe.ts\";\nimport { hasTrackStream, Version } from \"./version.ts\";\n\n/**\n * Options accepted by {@link Subscriber.announced}.\n */\nexport interface AnnouncedOptions {\n\t/**\n\t * If true, skip announcements whose hop chain contains this connection's\n\t * own origin id — useful for meshes that reflect announces back. Defaults\n\t * to false for backwards compatibility: existing code (notably hang.live)\n\t * relies on seeing its own publishes as the signal that a namespace\n\t * published successfully.\n\t */\n\tignoreSelf?: boolean;\n}\n\n/**\n * Handles subscribing to broadcasts and managing their lifecycle.\n *\n * @internal\n */\nexport class Subscriber {\n\t#quic: WebTransport;\n\n\t// The version of the connection.\n\treadonly version: Version;\n\n\t// Shared with the Publisher so callers can optionally filter out their\n\t// own announcements on a per-call basis (see {@link AnnouncedOptions}).\n\treadonly origin: Origin;\n\n\t// Our subscribed tracks.\n\t#subscribes = new Map<bigint, Track>();\n\t#subscribeNext = 0n;\n\n\t// Recv bandwidth producer (Lite03+ only).\n\t#recvBandwidth?: Bandwidth;\n\n\t// RTT producer (Lite04+ only).\n\t#rtt?: Signal<Time.Milli | undefined>;\n\n\t/**\n\t * Creates a new Subscriber instance.\n\t * @param quic - The WebTransport session to use\n\t * @param version - The protocol version\n\t * @param origin - Origin id shared with the Publisher\n\t * @param recvBandwidth - Optional bandwidth producer for PROBE\n\t * @param rtt - Optional RTT signal for PROBE\n\t *\n\t * @internal\n\t */\n\tconstructor(\n\t\tquic: WebTransport,\n\t\tversion: Version,\n\t\torigin: Origin,\n\t\trecvBandwidth?: Bandwidth,\n\t\trtt?: Signal<Time.Milli | undefined>,\n\t) {\n\t\tthis.#quic = quic;\n\t\tthis.version = version;\n\t\tthis.origin = origin;\n\t\tthis.#recvBandwidth = recvBandwidth;\n\t\tthis.#rtt = rtt;\n\t}\n\n\t/**\n\t * Subscribe to broadcast announcements under `prefix`.\n\t *\n\t * Pass `{ ignoreSelf: true }` to skip announces that have already traversed\n\t * this connection's {@link origin}.\n\t */\n\tannounced(prefix = Path.empty(), options: AnnouncedOptions = {}): Announced {\n\t\tconst announced = new Announced();\n\t\tvoid this.#runAnnounced(announced, prefix, options);\n\t\treturn announced;\n\t}\n\n\tasync #runAnnounced(announced: Announced, prefix: Path.Valid, options: AnnouncedOptions): Promise<void> {\n\t\tconsole.debug(`announced: prefix=${prefix}`);\n\t\t// Send our own session-level origin id so the peer can skip announces\n\t\t// whose hop chain already passed through us. Matches the Rust subscriber's\n\t\t// `exclude_hop: self.self_origin.id` in `run_announce_prefix`.\n\t\tconst msg = new AnnounceInterest(prefix, this.origin);\n\n\t\ttry {\n\t\t\t// Open a stream and send the announce interest.\n\t\t\tconst stream = await Stream.open(this.#quic);\n\t\t\tawait stream.writer.u53(StreamId.Announce);\n\t\t\tawait msg.encode(stream.writer, this.version);\n\n\t\t\tswitch (this.version) {\n\t\t\t\tcase Version.DRAFT_01:\n\t\t\t\tcase Version.DRAFT_02: {\n\t\t\t\t\t// Receive ANNOUNCE_INIT first\n\t\t\t\t\tconst init = await AnnounceInit.decode(stream.reader, this.version);\n\n\t\t\t\t\t// Process initial announcements\n\t\t\t\t\tfor (const suffix of init.suffixes) {\n\t\t\t\t\t\tconst path = Path.join(prefix, suffix);\n\t\t\t\t\t\tconsole.debug(`announced: broadcast=${path} active=true`);\n\t\t\t\t\t\tannounced.append({ path, active: true });\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tdefault:\n\t\t\t\t\t// Draft03+: no AnnounceInit, initial state comes via Announce messages.\n\t\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t// Receive announce updates (for Draft03, this includes initial state)\n\t\t\tfor (;;) {\n\t\t\t\tconst announce = await Promise.race([\n\t\t\t\t\tAnnounce.decodeMaybe(stream.reader, this.version),\n\t\t\t\t\tannounced.closed,\n\t\t\t\t]);\n\t\t\t\tif (!announce) break;\n\t\t\t\tif (announce instanceof Error) throw announce;\n\n\t\t\t\t// Optionally drop reflected announces so callers asking for\n\t\t\t\t// \"someone else's broadcasts\" don't re-see their own publishes.\n\t\t\t\tif (options.ignoreSelf && announce.hops.includes(this.origin)) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tconst path = Path.join(prefix, announce.suffix);\n\n\t\t\t\tconsole.debug(`announced: broadcast=${path} active=${announce.active}`);\n\t\t\t\tannounced.append({ path, active: announce.active });\n\t\t\t}\n\n\t\t\tannounced.close();\n\t\t} catch (err: unknown) {\n\t\t\tannounced.close(error(err));\n\t\t}\n\t}\n\n\t/**\n\t * Consumes a broadcast from the connection.\n\t *\n\t * @param name - The name of the broadcast to consume\n\t * @returns A Broadcast instance\n\t */\n\tconsume(path: Path.Valid): Broadcast {\n\t\tconst broadcast = new Broadcast();\n\n\t\tvoid (async () => {\n\t\t\tfor (;;) {\n\t\t\t\tconst request = await broadcast.requested();\n\t\t\t\tif (!request) break;\n\t\t\t\tvoid this.#runSubscribe(path, request);\n\t\t\t}\n\t\t})();\n\n\t\treturn broadcast;\n\t}\n\n\tasync #runSubscribe(broadcast: Path.Valid, request: TrackRequest) {\n\t\tconst id = this.#subscribeNext++;\n\n\t\t// Save the writer so we can append groups to it.\n\t\tthis.#subscribes.set(id, request.track);\n\n\t\tconsole.debug(`subscribe start: id=${id} broadcast=${broadcast} track=${request.track.name}`);\n\n\t\tconst msg = new Subscribe({ id, broadcast, track: request.track.name, priority: request.priority });\n\n\t\tconst stream = await Stream.open(this.#quic);\n\t\tawait stream.writer.u53(StreamId.Subscribe);\n\t\tawait msg.encode(stream.writer, this.version);\n\n\t\ttry {\n\t\t\t// The first response MUST be a SUBSCRIBE_OK.\n\t\t\tconst resp = await decodeSubscribeResponse(stream.reader, this.version);\n\t\t\tif (!(\"ok\" in resp)) {\n\t\t\t\tthrow new Error(\"first subscribe response must be SUBSCRIBE_OK\");\n\t\t\t}\n\t\t\tconsole.debug(`subscribe ok: id=${id} broadcast=${broadcast} track=${request.track.name}`);\n\n\t\t\t// Watch for priority changes and send SUBSCRIBE_UPDATE. Lite01/Lite02\n\t\t\t// don't carry SUBSCRIBE_UPDATE on the wire, so skip the watcher there\n\t\t\t// and just wait on the stream/track like before.\n\t\t\t// Draining responses also consumes any SUBSCRIBE_END / SUBSCRIBE_DROP and\n\t\t\t// resolves when the publisher FINs.\n\t\t\tconst waits: Promise<unknown>[] = [this.#drainResponses(stream), request.track.closed];\n\t\t\tswitch (this.version) {\n\t\t\t\tcase Version.DRAFT_01:\n\t\t\t\tcase Version.DRAFT_02:\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\twaits.push(this.#runPriorityUpdates(id, broadcast, request.track, msg, stream));\n\t\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tawait Promise.race(waits);\n\n\t\t\trequest.track.close();\n\t\t\tstream.close();\n\t\t\tconsole.debug(`subscribe close: id=${id} broadcast=${broadcast} track=${request.track.name}`);\n\t\t} catch (err) {\n\t\t\tconst e = error(err);\n\t\t\trequest.track.close(e);\n\t\t\tconsole.warn(\n\t\t\t\t`subscribe error: id=${id} broadcast=${broadcast} track=${request.track.name} error=${e.message}`,\n\t\t\t);\n\t\t\tstream.abort(e);\n\t\t} finally {\n\t\t\tthis.#subscribes.delete(id);\n\t\t}\n\t}\n\n\t/**\n\t * Drain responses on the subscribe stream until the publisher FINs.\n\t *\n\t * The first SUBSCRIBE_OK is consumed by the caller; this reads any further\n\t * SUBSCRIBE_END / SUBSCRIBE_DROP. They aren't acted on yet (groups arrive on\n\t * their own streams regardless), but consuming them keeps the stream aligned.\n\t */\n\tasync #drainResponses(stream: Stream): Promise<void> {\n\t\tfor (;;) {\n\t\t\tconst resp = await decodeSubscribeResponseMaybe(stream.reader, this.version);\n\t\t\tif (!resp) break;\n\t\t}\n\t}\n\n\t/**\n\t * Send SUBSCRIBE_UPDATE messages whenever the track's priority signal changes.\n\t *\n\t * Resolves cleanly when the stream or track closes, so the caller can include\n\t * this in Promise.race without leaving a dangling pending write that would\n\t * become an unhandled rejection if the user calls updatePriority after close.\n\t *\n\t * Peeks the signal at the top of every iteration so that updates which landed\n\t * before SubscribeOk arrived (or between iterations, before .next() registered\n\t * its listener) aren't lost.\n\t */\n\tasync #runPriorityUpdates(\n\t\tid: bigint,\n\t\tbroadcast: Path.Valid,\n\t\ttrack: Track,\n\t\tmsg: Subscribe,\n\t\tstream: Stream,\n\t): Promise<void> {\n\t\tconst stopped: Promise<null> = Promise.race([track.closed, stream.reader.closed]).then(() => null);\n\t\tlet lastSent: number | undefined;\n\n\t\tfor (;;) {\n\t\t\tconst current = track.state.priority.peek();\n\t\t\tif (current === undefined || current === lastSent) {\n\t\t\t\t// Nothing new to send; wait for a change or termination.\n\t\t\t\tconst next = await Promise.race([track.state.priority.next(), stopped]);\n\t\t\t\tif (next === null) return;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// Round-trip the other Subscribe parameters so the publisher doesn't\n\t\t\t// interpret SUBSCRIBE_UPDATE as a reset of ordered/maxLatency/etc.\n\t\t\tconst update = new SubscribeUpdate({\n\t\t\t\tpriority: current,\n\t\t\t\tordered: msg.ordered,\n\t\t\t\tmaxLatency: msg.maxLatency,\n\t\t\t\tstartGroup: msg.startGroup,\n\t\t\t\tendGroup: msg.endGroup,\n\t\t\t});\n\t\t\tawait update.encode(stream.writer, this.version);\n\t\t\tlastSent = current;\n\t\t\tconsole.debug(`subscribe update: id=${id} broadcast=${broadcast} track=${track.name} priority=${current}`);\n\t\t}\n\t}\n\n\t/**\n\t * Handles a group message.\n\t * @param group - The group message\n\t * @param stream - The stream to read frames from\n\t *\n\t * @internal\n\t */\n\tasync runGroup(group: GroupMessage, stream: Reader) {\n\t\tconst subscribe = this.#subscribes.get(group.subscribe);\n\t\tif (!subscribe) {\n\t\t\tif (group.subscribe >= this.#subscribeNext) {\n\t\t\t\tthrow new Error(`unknown subscription: id=${group.subscribe}`);\n\t\t\t}\n\n\t\t\treturn;\n\t\t}\n\n\t\tconst producer = new Group(group.sequence);\n\t\tsubscribe.writeGroup(producer);\n\n\t\ttry {\n\t\t\tfor (;;) {\n\t\t\t\tconst done = await Promise.race([stream.done(), subscribe.closed, producer.closed]);\n\t\t\t\tif (done !== false) break;\n\n\t\t\t\tif (hasTrackStream(this.version)) {\n\t\t\t\t\t// moq-lite-05+ prefixes each frame with a zigzag timestamp delta. Decode it\n\t\t\t\t\t// to stay aligned with the wire, but don't surface it yet.\n\t\t\t\t\tawait stream.u62();\n\t\t\t\t}\n\n\t\t\t\tconst size = await stream.u53();\n\t\t\t\tconst payload = await stream.read(size);\n\t\t\t\tif (!payload) break;\n\n\t\t\t\tproducer.writeFrame(payload);\n\t\t\t}\n\n\t\t\tproducer.close();\n\t\t\tstream.stop(new Error(\"cancel\"));\n\t\t} catch (err: unknown) {\n\t\t\tconst e = error(err);\n\t\t\tproducer.close(e);\n\t\t\tstream.stop(e);\n\t\t}\n\t}\n\n\t/**\n\t * Opens a PROBE bidi stream to receive bandwidth estimates from the publisher.\n\t * Returns immediately if recv bandwidth is not supported.\n\t *\n\t * Probe is best-effort telemetry: a stream-level failure (peer reset, FIN,\n\t * missing peer support, transport hiccup) is caught and logged, never\n\t * propagated to the connection. On exit the bandwidth/RTT signals are\n\t * cleared so consumers see them as stale.\n\t *\n\t * @internal\n\t */\n\tasync runProbe(): Promise<void> {\n\t\tif (!this.#recvBandwidth) return;\n\t\tif (this.version === Version.DRAFT_01 || this.version === Version.DRAFT_02) return;\n\n\t\t// Probe is best-effort: any failure (stream reset by peer, missing peer support,\n\t\t// transport hiccup) MUST NOT tear down the connection. On error, drop the\n\t\t// bandwidth/RTT estimates so consumers know they're stale.\n\t\ttry {\n\t\t\tconst stream = await Stream.open(this.#quic);\n\t\t\tawait stream.writer.u53(StreamId.Probe);\n\n\t\t\tfor (;;) {\n\t\t\t\tconst probe = await Probe.decodeMaybe(stream.reader, this.version);\n\t\t\t\tif (!probe) break;\n\t\t\t\tthis.#recvBandwidth.set(probe.bitrate ?? undefined);\n\t\t\t\tif (this.#rtt && probe.rtt !== undefined) {\n\t\t\t\t\tthis.#rtt.set(probe.rtt as Time.Milli);\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (err: unknown) {\n\t\t\tconsole.warn(\"probe stream error\", err);\n\t\t} finally {\n\t\t\tthis.#recvBandwidth.set(undefined);\n\t\t\tthis.#rtt?.set(undefined);\n\t\t}\n\t}\n\n\tclose() {\n\t\tfor (const track of this.#subscribes.values()) {\n\t\t\ttrack.close();\n\t\t}\n\n\t\tthis.#subscribes.clear();\n\t}\n}\n"]}
1
+ {"version":3,"file":"subscriber.js","sourceRoot":"","sources":["../../src/lite/subscriber.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Signal } from \"@moq/signals\";\nimport { Announced } from \"../announced.ts\";\nimport type { Bandwidth } from \"../bandwidth.ts\";\nimport { Broadcast, type TrackRequest } from \"../broadcast.ts\";\nimport { Group } from \"../group.ts\";\nimport * as Path from \"../path.ts\";\nimport { type Reader, Stream } from \"../stream.ts\";\nimport type * as Time from \"../time.ts\";\nimport type { Track } from \"../track.ts\";\nimport { error } from \"../util/error.ts\";\nimport { Announce, AnnounceInit, AnnounceInterest } from \"./announce.ts\";\nimport type { Group as GroupMessage } from \"./group.ts\";\nimport type { Origin } from \"./origin.ts\";\nimport { Probe } from \"./probe.ts\";\nimport { StreamId } from \"./stream.ts\";\nimport { decodeSubscribeResponse, decodeSubscribeResponseMaybe, Subscribe, SubscribeUpdate } from \"./subscribe.ts\";\nimport { hasTrackStream, Version } from \"./version.ts\";\n\n/**\n * Options accepted by {@link Subscriber.announced}.\n */\nexport interface AnnouncedOptions {\n\t/**\n\t * If true, skip announcements whose hop chain contains this connection's\n\t * own origin id — useful for meshes that reflect announces back. Defaults\n\t * to false for backwards compatibility: existing code (notably hang.live)\n\t * relies on seeing its own publishes as the signal that a namespace\n\t * published successfully.\n\t */\n\tignoreSelf?: boolean;\n}\n\n/**\n * Handles subscribing to broadcasts and managing their lifecycle.\n *\n * @internal\n */\nexport class Subscriber {\n\t#quic: WebTransport;\n\n\t// The version of the connection.\n\treadonly version: Version;\n\n\t// Shared with the Publisher so callers can optionally filter out their\n\t// own announcements on a per-call basis (see {@link AnnouncedOptions}).\n\treadonly origin: Origin;\n\n\t// Our subscribed tracks.\n\t#subscribes = new Map<bigint, Track>();\n\t#subscribeNext = 0n;\n\n\t// Recv bandwidth producer (Lite03+ only).\n\t#recvBandwidth?: Bandwidth;\n\n\t// RTT producer (Lite04+ only).\n\t#rtt?: Signal<Time.Milli | undefined>;\n\n\t// Distinguishes failures from streams torn down by Subscriber.close().\n\t#closed = new AbortController();\n\n\t/**\n\t * Creates a new Subscriber instance.\n\t * @param quic - The WebTransport session to use\n\t * @param version - The protocol version\n\t * @param origin - Origin id shared with the Publisher\n\t * @param recvBandwidth - Optional bandwidth producer for PROBE\n\t * @param rtt - Optional RTT signal for PROBE\n\t *\n\t * @internal\n\t */\n\tconstructor(\n\t\tquic: WebTransport,\n\t\tversion: Version,\n\t\torigin: Origin,\n\t\trecvBandwidth?: Bandwidth,\n\t\trtt?: Signal<Time.Milli | undefined>,\n\t) {\n\t\tthis.#quic = quic;\n\t\tthis.version = version;\n\t\tthis.origin = origin;\n\t\tthis.#recvBandwidth = recvBandwidth;\n\t\tthis.#rtt = rtt;\n\t}\n\n\t/**\n\t * Subscribe to broadcast announcements under `prefix`.\n\t *\n\t * Pass `{ ignoreSelf: true }` to skip announces that have already traversed\n\t * this connection's {@link origin}.\n\t */\n\tannounced(prefix = Path.empty(), options: AnnouncedOptions = {}): Announced {\n\t\tconst announced = new Announced();\n\t\tvoid this.#runAnnounced(announced, prefix, options);\n\t\treturn announced;\n\t}\n\n\tasync #runAnnounced(announced: Announced, prefix: Path.Valid, options: AnnouncedOptions): Promise<void> {\n\t\tconsole.debug(`announced: prefix=${prefix}`);\n\t\t// Send our own session-level origin id so the peer can skip announces\n\t\t// whose hop chain already passed through us. Matches the Rust subscriber's\n\t\t// `exclude_hop: self.self_origin.id` in `run_announce_prefix`.\n\t\tconst msg = new AnnounceInterest(prefix, this.origin);\n\n\t\ttry {\n\t\t\t// Open a stream and send the announce interest.\n\t\t\tconst stream = await Stream.open(this.#quic);\n\t\t\tawait stream.writer.u53(StreamId.Announce);\n\t\t\tawait msg.encode(stream.writer, this.version);\n\n\t\t\tswitch (this.version) {\n\t\t\t\tcase Version.DRAFT_01:\n\t\t\t\tcase Version.DRAFT_02: {\n\t\t\t\t\t// Receive ANNOUNCE_INIT first\n\t\t\t\t\tconst init = await AnnounceInit.decode(stream.reader, this.version);\n\n\t\t\t\t\t// Process initial announcements\n\t\t\t\t\tfor (const suffix of init.suffixes) {\n\t\t\t\t\t\tconst path = Path.join(prefix, suffix);\n\t\t\t\t\t\tconsole.debug(`announced: broadcast=${path} active=true`);\n\t\t\t\t\t\tannounced.append({ path, active: true });\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tdefault:\n\t\t\t\t\t// Draft03+: no AnnounceInit, initial state comes via Announce messages.\n\t\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t// Receive announce updates (for Draft03, this includes initial state)\n\t\t\tfor (;;) {\n\t\t\t\tconst announce = await Promise.race([\n\t\t\t\t\tAnnounce.decodeMaybe(stream.reader, this.version),\n\t\t\t\t\tannounced.closed,\n\t\t\t\t]);\n\t\t\t\tif (!announce) break;\n\t\t\t\tif (announce instanceof Error) throw announce;\n\n\t\t\t\t// Optionally drop reflected announces so callers asking for\n\t\t\t\t// \"someone else's broadcasts\" don't re-see their own publishes.\n\t\t\t\tif (options.ignoreSelf && announce.hops.includes(this.origin)) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tconst path = Path.join(prefix, announce.suffix);\n\n\t\t\t\tconsole.debug(`announced: broadcast=${path} active=${announce.active}`);\n\t\t\t\tannounced.append({ path, active: announce.active });\n\t\t\t}\n\n\t\t\tannounced.close();\n\t\t} catch (err: unknown) {\n\t\t\tannounced.close(error(err));\n\t\t}\n\t}\n\n\t/**\n\t * Consumes a broadcast from the connection.\n\t *\n\t * @param name - The name of the broadcast to consume\n\t * @returns A Broadcast instance\n\t */\n\tconsume(path: Path.Valid): Broadcast {\n\t\tconst broadcast = new Broadcast();\n\n\t\tvoid (async () => {\n\t\t\tfor (;;) {\n\t\t\t\tconst request = await broadcast.requested();\n\t\t\t\tif (!request) break;\n\t\t\t\tvoid this.#runSubscribe(path, request);\n\t\t\t}\n\t\t})();\n\n\t\treturn broadcast;\n\t}\n\n\tasync #runSubscribe(broadcast: Path.Valid, request: TrackRequest) {\n\t\tconst id = this.#subscribeNext++;\n\n\t\t// Save the writer so we can append groups to it.\n\t\tthis.#subscribes.set(id, request.track);\n\n\t\tconsole.debug(`subscribe start: id=${id} broadcast=${broadcast} track=${request.track.name}`);\n\n\t\tconst msg = new Subscribe({ id, broadcast, track: request.track.name, priority: request.priority });\n\n\t\tconst stream = await Stream.open(this.#quic);\n\t\tawait stream.writer.u53(StreamId.Subscribe);\n\t\tawait msg.encode(stream.writer, this.version);\n\n\t\ttry {\n\t\t\t// The first response MUST be a SUBSCRIBE_OK.\n\t\t\tconst resp = await decodeSubscribeResponse(stream.reader, this.version);\n\t\t\tif (!(\"ok\" in resp)) {\n\t\t\t\tthrow new Error(\"first subscribe response must be SUBSCRIBE_OK\");\n\t\t\t}\n\t\t\tconsole.debug(`subscribe ok: id=${id} broadcast=${broadcast} track=${request.track.name}`);\n\n\t\t\t// Watch for priority changes and send SUBSCRIBE_UPDATE. Lite01/Lite02\n\t\t\t// don't carry SUBSCRIBE_UPDATE on the wire, so skip the watcher there\n\t\t\t// and just wait on the stream/track like before.\n\t\t\t// Draining responses also consumes any SUBSCRIBE_END / SUBSCRIBE_DROP and\n\t\t\t// resolves when the publisher FINs.\n\t\t\tconst waits: Promise<unknown>[] = [this.#drainResponses(stream), request.track.closed];\n\t\t\tswitch (this.version) {\n\t\t\t\tcase Version.DRAFT_01:\n\t\t\t\tcase Version.DRAFT_02:\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\twaits.push(this.#runPriorityUpdates(id, broadcast, request.track, msg, stream));\n\t\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tawait Promise.race(waits);\n\n\t\t\trequest.track.close();\n\t\t\tstream.close();\n\t\t\tconsole.debug(`subscribe close: id=${id} broadcast=${broadcast} track=${request.track.name}`);\n\t\t} catch (err) {\n\t\t\tconst e = error(err);\n\t\t\trequest.track.close(e);\n\t\t\tconsole.warn(\n\t\t\t\t`subscribe error: id=${id} broadcast=${broadcast} track=${request.track.name} error=${e.message}`,\n\t\t\t);\n\t\t\tstream.abort(e);\n\t\t} finally {\n\t\t\tthis.#subscribes.delete(id);\n\t\t}\n\t}\n\n\t/**\n\t * Drain responses on the subscribe stream until the publisher FINs.\n\t *\n\t * The first SUBSCRIBE_OK is consumed by the caller; this reads any further\n\t * SUBSCRIBE_END / SUBSCRIBE_DROP. They aren't acted on yet (groups arrive on\n\t * their own streams regardless), but consuming them keeps the stream aligned.\n\t */\n\tasync #drainResponses(stream: Stream): Promise<void> {\n\t\tfor (;;) {\n\t\t\tconst resp = await decodeSubscribeResponseMaybe(stream.reader, this.version);\n\t\t\tif (!resp) break;\n\t\t}\n\t}\n\n\t/**\n\t * Send SUBSCRIBE_UPDATE messages whenever the track's priority signal changes.\n\t *\n\t * Resolves cleanly when the stream or track closes, so the caller can include\n\t * this in Promise.race without leaving a dangling pending write that would\n\t * become an unhandled rejection if the user calls updatePriority after close.\n\t *\n\t * Peeks the signal at the top of every iteration so that updates which landed\n\t * before SubscribeOk arrived (or between iterations, before .next() registered\n\t * its listener) aren't lost.\n\t */\n\tasync #runPriorityUpdates(\n\t\tid: bigint,\n\t\tbroadcast: Path.Valid,\n\t\ttrack: Track,\n\t\tmsg: Subscribe,\n\t\tstream: Stream,\n\t): Promise<void> {\n\t\tconst stopped: Promise<null> = Promise.race([track.closed, stream.reader.closed]).then(() => null);\n\t\tlet lastSent: number | undefined;\n\n\t\tfor (;;) {\n\t\t\tconst current = track.state.priority.peek();\n\t\t\tif (current === undefined || current === lastSent) {\n\t\t\t\t// Nothing new to send; wait for a change or termination.\n\t\t\t\tconst next = await Promise.race([track.state.priority.next(), stopped]);\n\t\t\t\tif (next === null) return;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// Round-trip the other Subscribe parameters so the publisher doesn't\n\t\t\t// interpret SUBSCRIBE_UPDATE as a reset of ordered/maxLatency/etc.\n\t\t\tconst update = new SubscribeUpdate({\n\t\t\t\tpriority: current,\n\t\t\t\tordered: msg.ordered,\n\t\t\t\tmaxLatency: msg.maxLatency,\n\t\t\t\tstartGroup: msg.startGroup,\n\t\t\t\tendGroup: msg.endGroup,\n\t\t\t});\n\t\t\tawait update.encode(stream.writer, this.version);\n\t\t\tlastSent = current;\n\t\t\tconsole.debug(`subscribe update: id=${id} broadcast=${broadcast} track=${track.name} priority=${current}`);\n\t\t}\n\t}\n\n\t/**\n\t * Handles a group message.\n\t * @param group - The group message\n\t * @param stream - The stream to read frames from\n\t *\n\t * @internal\n\t */\n\tasync runGroup(group: GroupMessage, stream: Reader) {\n\t\tconst subscribe = this.#subscribes.get(group.subscribe);\n\t\tif (!subscribe) {\n\t\t\tif (group.subscribe >= this.#subscribeNext) {\n\t\t\t\tthrow new Error(`unknown subscription: id=${group.subscribe}`);\n\t\t\t}\n\n\t\t\treturn;\n\t\t}\n\n\t\tconst producer = new Group(group.sequence);\n\t\tsubscribe.writeGroup(producer);\n\n\t\ttry {\n\t\t\tfor (;;) {\n\t\t\t\tconst done = await Promise.race([stream.done(), subscribe.closed, producer.closed]);\n\t\t\t\tif (done !== false) break;\n\n\t\t\t\tif (hasTrackStream(this.version)) {\n\t\t\t\t\t// moq-lite-05+ prefixes each frame with a zigzag timestamp delta. Decode it\n\t\t\t\t\t// to stay aligned with the wire, but don't surface it yet.\n\t\t\t\t\tawait stream.u62();\n\t\t\t\t}\n\n\t\t\t\tconst size = await stream.u53();\n\t\t\t\tconst payload = await stream.read(size);\n\t\t\t\tif (!payload) break;\n\n\t\t\t\tproducer.writeFrame(payload);\n\t\t\t}\n\n\t\t\tproducer.close();\n\t\t\tstream.stop(new Error(\"cancel\"));\n\t\t} catch (err: unknown) {\n\t\t\tconst e = error(err);\n\t\t\tproducer.close(e);\n\t\t\tstream.stop(e);\n\t\t}\n\t}\n\n\t/**\n\t * Opens a PROBE bidi stream to receive bandwidth estimates from the publisher.\n\t * Returns immediately if recv bandwidth is not supported.\n\t *\n\t * Probe is best-effort telemetry: a stream-level failure (peer reset, FIN,\n\t * missing peer support, transport hiccup) is caught and logged, never\n\t * propagated to the connection. On exit the bandwidth/RTT signals are\n\t * cleared so consumers see them as stale.\n\t *\n\t * @internal\n\t */\n\tasync runProbe(): Promise<void> {\n\t\tif (!this.#recvBandwidth) return;\n\t\tif (this.version === Version.DRAFT_01 || this.version === Version.DRAFT_02) return;\n\n\t\t// Probe is best-effort: any failure (stream reset by peer, missing peer support,\n\t\t// transport hiccup) MUST NOT tear down the connection. On error, drop the\n\t\t// bandwidth/RTT estimates so consumers know they're stale.\n\t\ttry {\n\t\t\tconst stream = await Stream.open(this.#quic);\n\t\t\tawait stream.writer.u53(StreamId.Probe);\n\n\t\t\tfor (;;) {\n\t\t\t\tconst probe = await Probe.decodeMaybe(stream.reader, this.version);\n\t\t\t\tif (!probe) break;\n\t\t\t\tthis.#recvBandwidth.set(probe.bitrate ?? undefined);\n\t\t\t\tif (this.#rtt && probe.rtt !== undefined) {\n\t\t\t\t\tthis.#rtt.set(probe.rtt as Time.Milli);\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (err: unknown) {\n\t\t\tif (!this.#closed.signal.aborted) {\n\t\t\t\tconsole.warn(\"probe stream error\", err);\n\t\t\t}\n\t\t} finally {\n\t\t\tthis.#recvBandwidth.set(undefined);\n\t\t\tthis.#rtt?.set(undefined);\n\t\t}\n\t}\n\n\tclose() {\n\t\tthis.#closed.abort();\n\n\t\tfor (const track of this.#subscribes.values()) {\n\t\t\ttrack.close();\n\t\t}\n\n\t\tthis.#subscribes.clear();\n\t}\n}\n"]}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=subscriber.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"subscriber.test.d.ts","sourceRoot":"","sources":["../../src/lite/subscriber.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,30 @@
1
+ /* @ts-self-types="./subscriber.test.d.ts" */
2
+ import { expect, spyOn, test } from "bun:test";
3
+ import { createBandwidth } from "../bandwidth.js";
4
+ import { OriginSchema } from "./origin.js";
5
+ import { Subscriber } from "./subscriber.js";
6
+ import { Version } from "./version.js";
7
+ test("closing the subscriber suppresses probe stream warnings", async () => {
8
+ let readable;
9
+ const quic = {
10
+ createBidirectionalStream: async () => ({
11
+ readable: new ReadableStream({ start: (controller) => (readable = controller) }),
12
+ writable: new WritableStream(),
13
+ }),
14
+ };
15
+ const subscriber = new Subscriber(quic, Version.DRAFT_03, OriginSchema.parse(1n), createBandwidth());
16
+ const warn = spyOn(console, "warn").mockImplementation(() => { });
17
+ try {
18
+ const probe = subscriber.runProbe();
19
+ await Promise.resolve();
20
+ await Promise.resolve();
21
+ subscriber.close();
22
+ readable.error(new Error("session closed"));
23
+ await probe;
24
+ expect(warn).not.toHaveBeenCalled();
25
+ }
26
+ finally {
27
+ warn.mockRestore();
28
+ }
29
+ });
30
+ //# sourceMappingURL=subscriber.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"subscriber.test.js","sourceRoot":"","sources":["../../src/lite/subscriber.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,UAAU,CAAC;AAC/C,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC,IAAI,CAAC,yDAAyD,EAAE,KAAK,IAAI,EAAE;IAC1E,IAAI,QAAsD,CAAC;IAC3D,MAAM,IAAI,GAAG;QACZ,yBAAyB,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC;YACvC,QAAQ,EAAE,IAAI,cAAc,CAAa,EAAE,KAAK,EAAE,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC,QAAQ,GAAG,UAAU,CAAC,EAAE,CAAC;YAC5F,QAAQ,EAAE,IAAI,cAAc,EAAc;SAC1C,CAAC;KACyB,CAAC;IAC7B,MAAM,UAAU,GAAG,IAAI,UAAU,CAAC,IAAI,EAAE,OAAO,CAAC,QAAQ,EAAE,YAAY,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,eAAe,EAAE,CAAC,CAAC;IACrG,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,kBAAkB,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;IAEjE,IAAI,CAAC;QACJ,MAAM,KAAK,GAAG,UAAU,CAAC,QAAQ,EAAE,CAAC;QAEpC,MAAM,OAAO,CAAC,OAAO,EAAE,CAAC;QACxB,MAAM,OAAO,CAAC,OAAO,EAAE,CAAC;QACxB,UAAU,CAAC,KAAK,EAAE,CAAC;QACnB,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,gBAAgB,CAAC,CAAC,CAAC;QAC5C,MAAM,KAAK,CAAC;QAEZ,MAAM,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAC;IACrC,CAAC;YAAS,CAAC;QACV,IAAI,CAAC,WAAW,EAAE,CAAC;IACpB,CAAC;AACF,CAAC,CAAC,CAAC","sourcesContent":["import { expect, spyOn, test } from \"bun:test\";\nimport { createBandwidth } from \"../bandwidth.ts\";\nimport { OriginSchema } from \"./origin.ts\";\nimport { Subscriber } from \"./subscriber.ts\";\nimport { Version } from \"./version.ts\";\n\ntest(\"closing the subscriber suppresses probe stream warnings\", async () => {\n\tlet readable!: ReadableStreamDefaultController<Uint8Array>;\n\tconst quic = {\n\t\tcreateBidirectionalStream: async () => ({\n\t\t\treadable: new ReadableStream<Uint8Array>({ start: (controller) => (readable = controller) }),\n\t\t\twritable: new WritableStream<Uint8Array>(),\n\t\t}),\n\t} as unknown as WebTransport;\n\tconst subscriber = new Subscriber(quic, Version.DRAFT_03, OriginSchema.parse(1n), createBandwidth());\n\tconst warn = spyOn(console, \"warn\").mockImplementation(() => {});\n\n\ttry {\n\t\tconst probe = subscriber.runProbe();\n\n\t\tawait Promise.resolve();\n\t\tawait Promise.resolve();\n\t\tsubscriber.close();\n\t\treadable.error(new Error(\"session closed\"));\n\t\tawait probe;\n\n\t\texpect(warn).not.toHaveBeenCalled();\n\t} finally {\n\t\twarn.mockRestore();\n\t}\n});\n"]}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@norskvideo/moq-net",
3
3
  "type": "module",
4
- "version": "0.1.1",
4
+ "version": "0.1.2",
5
5
  "description": "The networking layer for Media over QUIC: real-time pub/sub with built-in caching, fan-out, and prioritization.",
6
6
  "license": "(MIT OR Apache-2.0)",
7
7
  "repository": "github:moq-dev/moq",
@@ -19,7 +19,7 @@
19
19
  "dependencies": {
20
20
  "@moq/qmux": "^0.1.3",
21
21
  "async-mutex": "^0.5.0",
22
- "@norskvideo/moq-signals": "^0.1.1"
22
+ "@norskvideo/moq-signals": "^0.1.2"
23
23
  },
24
24
  "peerDependencies": {
25
25
  "zod": "^4.0.0"