stinky-moq-js 0.1.10 → 0.1.12
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.
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +48 -45
- package/dist/index.mjs.map +1 -1
- package/dist/session.d.ts +1 -0
- package/dist/session.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const p=require("@kixelated/moq");class m{constructor(){this.listeners=new Map}on(t,s){this.listeners.has(t)||this.listeners.set(t,new Set),this.listeners.get(t).add(s)}off(t,s){const e=this.listeners.get(t);e&&e.delete(s)}emit(t,...s){const e=this.listeners.get(t);e&&e.forEach(o=>{try{o(...s)}catch(n){console.error("Error in event listener:",n)}})}removeAllListeners(t){t?this.listeners.delete(t):this.listeners.clear()}}var c=(r=>(r.DISCONNECTED="disconnected",r.CONNECTING="connecting",r.CONNECTED="connected",r.RECONNECTING="reconnecting",r.FAILED="failed",r))(c||{}),d=(r=>(r.IDLE="idle",r.BROADCASTING="broadcasting",r.ERROR="error",r))(d||{}),u=(r=>(r.PENDING="pending",r.SUBSCRIBED="subscribed",r.RETRYING="retrying",r.FAILED="failed",r))(u||{});class b extends m{constructor(t){super(),this.state=d.IDLE,this.bytesSent=0,this._config=t}get status(){return{state:this.state,trackName:this._config.trackName,bytesSent:this.bytesSent,lastError:this.lastError}}get config(){return{...this._config}}updateTrack(t){this.track=t,t&&this.setState(d.BROADCASTING)}async send(t,s){if(this.state!==d.BROADCASTING||!this.track)throw new Error("Broadcast is not active");try{(s||!this.group)&&(this.group&&this.group.close(),this.group=this.track.appendGroup()),await this.group.writeFrame(t),this.bytesSent+=t.length}catch(e){throw this.handleError(e),e}}async stop(){if(this.track){try{this.track.close()}catch(t){console.warn("Error closing track:",t)}this.track=void 0}this.setState(d.IDLE)}setState(t){this.state!==t&&(this.state=t,this.emit("stateChange",this.status))}handleError(t){this.lastError=t,this.setState(d.ERROR),this.emit("error",t)}dispose(){this.stop().catch(console.error),this.removeAllListeners()}}class f extends m{constructor(t){super(),this.state=u.PENDING,this.bytesReceived=0,this.retryAttempts=0,this._config=t}get status(){return{state:this.state,trackName:this._config.trackName,bytesReceived:this.bytesReceived,retryAttempts:this.retryAttempts,lastError:this.lastError}}get config(){return{...this._config}}async start(t,s){this.connection=t,this.namespace=s;try{await this.subscribe(t,s)}catch(e){this.handleError(e),this.scheduleRetry(t,s)}}async subscribe(t,s){this.setState(u.PENDING);const e=p.Path.from(s);this.broadcast=t.consume(e),this.subscription=this.broadcast.subscribe(this._config.trackName,this._config.priority||0),this.setState(u.SUBSCRIBED),this.retryAttempts=0,this.readFrames()}async readFrames(){if(this.subscription)try{for(;;){let t=0;const s=await this.subscription.nextGroup();if(!s)break;for(;;){const e=await s.readFrame();if(!e)break;t++,this.bytesReceived+=e.length;const o={trackName:this._config.trackName,data:e,timestamp:Date.now(),frameIndex:t};this.emit("data",o)}}}catch(t){this.handleError(t),this.connection&&this.namespace&&this.scheduleRetry(this.connection,this.namespace)}}scheduleRetry(t,s){var o;const e=((o=this._config.retry)==null?void 0:o.delay)||2e3;this.setState(u.RETRYING),this.retryAttempts++,this.retryTimer=setTimeout(async()=>{try{await this.subscribe(t,s)}catch(n){this.handleError(n),this.scheduleRetry(t,s)}},e)}async stop(){if(this.connection=void 0,this.namespace=void 0,this.retryTimer&&(clearTimeout(this.retryTimer),this.retryTimer=void 0),this.subscription){try{this.subscription.close()}catch(t){console.warn("Error closing subscription:",t)}this.subscription=void 0}if(this.broadcast){try{this.broadcast.close()}catch(t){console.warn("Error closing broadcast:",t)}this.broadcast=void 0}this.setState(u.PENDING)}setState(t){this.state!==t&&(this.state=t,this.emit("stateChange",this.status))}handleError(t){this.lastError=t,this.emit("error",t)}dispose(){this.stop().catch(t=>{console.warn("Error during dispose:",t)}),this.removeAllListeners()}}class E extends m{constructor(t){var s;super(),this.state=c.DISCONNECTED,this.reconnectAttempts=0,this.broadcasts=new Map,this.subscriptions=new Map,this.announcedBroadcasts=new Set,this.doReconnect=!0,this.config={...t,reconnection:{delay:Math.max(((s=t.reconnection)==null?void 0:s.delay)||1e3,1e3)},connectionTimeout:t.connectionTimeout||1e4},this.url=new URL(this.config.relayUrl)}get status(){return{state:this.state,reconnectAttempts:this.reconnectAttempts,lastError:this.lastError,connectedAt:this.connectedAt}}async connect(){if(!(this.state===c.CONNECTING||this.state===c.CONNECTED)){this.setState(c.CONNECTING);try{this.doReconnect=!0,this.connection=await p.Connection.connect(this.url,{websocket:{enabled:!1}}),this.setState(c.CONNECTED),this.connectedAt=new Date,this.reconnectAttempts=0,this.connection.closed.then(()=>{this.state===c.CONNECTED&&this.handleDisconnection()}),this.startAnnouncementDiscovery(),await this.restartBroadcasts(),await this.restartSubscriptions()}catch(t){throw this.handleError(t),this.scheduleReconnect(),t}}}async disconnect(){if(this.doReconnect=!1,this.reconnectTimer&&(clearTimeout(this.reconnectTimer),this.reconnectTimer=void 0),await this.stopAllBroadcasts(),await this.stopAllSubscriptions(),this.connection){try{this.connection.close()}catch(t){console.warn("Error closing connection:",t)}this.connection=void 0}this.setState(c.DISCONNECTED),this.connectedAt=void 0}getAllBroadcastTrackNames(){return Array.from(this.broadcasts.keys())}getAllSubscriptionTrackNames(){return Array.from(this.subscriptions.keys())}updateBroadcasts(t){const s=t.map(i=>i.trackName),e=new Set(s);if(s.length!==e.size){const i=s.filter((h,a)=>s.indexOf(h)!==a);throw new Error(`Duplicate broadcast track name: ${i[0]}`)}const o=new Set(t.map(i=>i.trackName)),n=new Set(this.broadcasts.keys());for(const i of n)o.has(i)||this._removeBroadcast(i);for(const i of t){const h=this.broadcasts.get(i.trackName);h?h.config.priority!==i.priority&&(this._removeBroadcast(i.trackName),this._createBroadcast(i)):this._createBroadcast(i)}}updateSubscriptions(t){var i,h;const s=t.map(a=>a.trackName),e=new Set(s);if(s.length!==e.size){const a=s.filter((l,y)=>s.indexOf(l)!==y);throw new Error(`Duplicate subscription track name: ${a[0]}`)}const o=new Set(t.map(a=>a.trackName)),n=new Set(this.subscriptions.keys());for(const a of n)o.has(a)||this._removeSubscription(a);for(const a of t){const l=this.subscriptions.get(a.trackName);l?(l.config.priority!==a.priority||((i=l.config.retry)==null?void 0:i.delay)!==((h=a.retry)==null?void 0:h.delay))&&(this._removeSubscription(a.trackName),this._createSubscription(a)):this._createSubscription(a)}}getAnnouncedBroadcasts(){return Array.from(this.announcedBroadcasts)}async send(t,s,e){const o=this.broadcasts.get(t);if(!o)throw new Error(`No broadcast found for track: ${t}`);await o.send(s,e)}getBroadcastStatus(t){const s=this.broadcasts.get(t);return s==null?void 0:s.status}getSubscriptionStatus(t){const s=this.subscriptions.get(t);return s==null?void 0:s.status}_createBroadcast(t){const s=new b(t);return this.broadcasts.set(t.trackName,s),s.on("stateChange",e=>{this.emit("broadcastStateChange",t.trackName,e)}),s.on("error",e=>{this.emit("broadcastError",t.trackName,e)}),this.initBroadcasting(),s}_createSubscription(t){const s=new f(t);return this.subscriptions.set(t.trackName,s),s.on("data",e=>{this.emit("data",e.trackName,e.data,e.frameIndex)}),s.on("stateChange",e=>{this.emit("subscriptionStateChange",t.trackName,e)}),s.on("error",e=>{this.emit("subscriptionError",t.trackName,e)}),this.state===c.CONNECTED&&this.connection&&s.start(this.connection,this.config.namespace).catch(e=>{console.error("Failed to start subscription:",e)}),s}_removeBroadcast(t){const s=this.broadcasts.get(t);s&&(s.stop().catch(e=>{console.warn("Error stopping broadcast:",e)}),this.broadcasts.delete(t))}_removeSubscription(t){const s=this.subscriptions.get(t);s&&(s.stop().catch(e=>{console.warn("Error stopping subscription:",e)}),this.subscriptions.delete(t))}async startAnnouncementDiscovery(){if(this.connection)try{const t=p.Path.from(this.config.namespace),s=this.connection.announced(t);this.processAnnouncements(s)}catch(t){console.error("Failed to start announcement discovery:",t)}}async processAnnouncements(t){try{for(;;){const s=await t.next();if(!s)break;s.active?(this.announcedBroadcasts.add(s.path),this.emit("broadcastAnnounced",{path:s.path,active:!0})):(this.announcedBroadcasts.delete(s.path),this.emit("broadcastAnnounced",{path:s.path,active:!1}))}}catch(s){console.error("Error processing announcements:",s)}}async restartBroadcasts(){await this.stopAllBroadcasts(),this.initBroadcasting()}initBroadcasting(){this.broadcast||this.broadcasts.size!==0&&(this.broadcast=new p.Broadcast,this.connection&&(this.connection.publish(p.Path.from(this.config.namespace),this.broadcast),this.handleTrackRequests().catch(t=>{console.error("Error handling track requests:",t)})))}async handleTrackRequests(){if(this.broadcast)try{for(;;){const t=await this.broadcast.requested();if(!t)return;const s=this.broadcasts.get(t.track.name);s&&(s.updateTrack(t.track),this.emit("trackRequested",t.track.name))}}catch(t){console.warn("Error handling track requests:",t),this.handleError(t)}}async restartSubscriptions(){if(!this.connection)return;const t=Array.from(this.subscriptions.values()).map(s=>s.start(this.connection,this.config.namespace).catch(e=>{console.error("Failed to restart subscription:",e)}));await Promise.allSettled(t)}async stopAllBroadcasts(){var s;(s=this.broadcast)==null||s.close(),this.broadcast=void 0;const t=Array.from(this.broadcasts.values()).map(e=>e.stop().catch(o=>{console.warn("Error stopping broadcast:",o)}));await Promise.allSettled(t)}async stopAllSubscriptions(){const t=Array.from(this.subscriptions.values()).map(s=>s.stop().catch(e=>{console.warn("Error stopping subscription:",e)}));await Promise.allSettled(t)}handleDisconnection(){this.setState(c.DISCONNECTED),this.scheduleReconnect()}scheduleReconnect(){var s;if(!this.config.reconnection||!this.doReconnect)return;const t=((s=this.config.reconnection)==null?void 0:s.delay)||1e3;this.setState(c.RECONNECTING),this.reconnectAttempts++,this.reconnectTimer=setTimeout(()=>{this.doReconnect&&this.state===c.RECONNECTING&&this.connect().catch(e=>{console.error("Reconnection failed:",e)})},t)}setState(t){this.state!==t&&(this.state=t,this.emit("stateChange",this.status))}handleError(t){this.lastError=t,this.emit("error",t)}dispose(){this.doReconnect=!1,this.reconnectTimer&&(clearTimeout(this.reconnectTimer),this.reconnectTimer=void 0),this.disconnect().catch(t=>{console.warn("Error during session disconnect:",t)}),this.removeAllListeners(),this.subscriptions.forEach(t=>t.dispose()),this.broadcasts.forEach(t=>t.dispose()),this.subscriptions.clear(),this.broadcasts.clear()}}exports.BroadcastState=d;exports.MoQBroadcast=b;exports.MoQSession=E;exports.MoQSubscription=f;exports.SessionState=c;exports.SubscriptionState=u;exports.default=E;
|
|
1
|
+
"use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const p=require("@kixelated/moq");class m{constructor(){this.listeners=new Map}on(t,s){this.listeners.has(t)||this.listeners.set(t,new Set),this.listeners.get(t).add(s)}off(t,s){const e=this.listeners.get(t);e&&e.delete(s)}emit(t,...s){const e=this.listeners.get(t);e&&e.forEach(a=>{try{a(...s)}catch(c){console.error("Error in event listener:",c)}})}removeAllListeners(t){t?this.listeners.delete(t):this.listeners.clear()}}var n=(r=>(r.DISCONNECTED="disconnected",r.CONNECTING="connecting",r.CONNECTED="connected",r.RECONNECTING="reconnecting",r.FAILED="failed",r))(n||{}),d=(r=>(r.IDLE="idle",r.BROADCASTING="broadcasting",r.ERROR="error",r))(d||{}),u=(r=>(r.PENDING="pending",r.SUBSCRIBED="subscribed",r.RETRYING="retrying",r.FAILED="failed",r))(u||{});class f extends m{constructor(t){super(),this.state=d.IDLE,this.bytesSent=0,this._config=t}get status(){return{state:this.state,trackName:this._config.trackName,bytesSent:this.bytesSent,lastError:this.lastError}}get config(){return{...this._config}}updateTrack(t){this.track=t,t&&this.setState(d.BROADCASTING)}async send(t,s){if(this.state!==d.BROADCASTING||!this.track)throw new Error("Broadcast is not active");try{(s||!this.group)&&(this.group&&this.group.close(),this.group=this.track.appendGroup()),await this.group.writeFrame(t),this.bytesSent+=t.length}catch(e){throw this.handleError(e),e}}async stop(){if(this.track){try{this.track.close()}catch(t){console.warn("Error closing track:",t)}this.track=void 0}this.setState(d.IDLE)}setState(t){this.state!==t&&(this.state=t,this.emit("stateChange",this.status))}handleError(t){this.lastError=t,this.setState(d.ERROR),this.emit("error",t)}dispose(){this.stop().catch(console.error),this.removeAllListeners()}}class b extends m{constructor(t){super(),this.state=u.PENDING,this.bytesReceived=0,this.retryAttempts=0,this._config=t}get status(){return{state:this.state,trackName:this._config.trackName,bytesReceived:this.bytesReceived,retryAttempts:this.retryAttempts,lastError:this.lastError}}get config(){return{...this._config}}async start(t,s){this.connection=t,this.namespace=s;try{await this.subscribe(t,s)}catch(e){this.handleError(e),this.scheduleRetry(t,s)}}async subscribe(t,s){this.setState(u.PENDING);const e=p.Path.from(s);this.broadcast=t.consume(e),this.subscription=this.broadcast.subscribe(this._config.trackName,this._config.priority||0),this.setState(u.SUBSCRIBED),this.retryAttempts=0,this.readFrames()}async readFrames(){if(this.subscription)try{for(;;){let t=0;const s=await this.subscription.nextGroup();if(!s)break;for(;;){const e=await s.readFrame();if(!e)break;t++,this.bytesReceived+=e.length;const a={trackName:this._config.trackName,data:e,timestamp:Date.now(),frameIndex:t};this.emit("data",a)}}}catch(t){this.handleError(t),this.connection&&this.namespace&&this.scheduleRetry(this.connection,this.namespace)}}scheduleRetry(t,s){var a;const e=((a=this._config.retry)==null?void 0:a.delay)||2e3;this.setState(u.RETRYING),this.retryAttempts++,this.retryTimer=setTimeout(async()=>{try{await this.subscribe(t,s)}catch(c){this.handleError(c),this.scheduleRetry(t,s)}},e)}async stop(){if(this.connection=void 0,this.namespace=void 0,this.retryTimer&&(clearTimeout(this.retryTimer),this.retryTimer=void 0),this.subscription){try{this.subscription.close()}catch(t){console.warn("Error closing subscription:",t)}this.subscription=void 0}if(this.broadcast){try{this.broadcast.close()}catch(t){console.warn("Error closing broadcast:",t)}this.broadcast=void 0}this.setState(u.PENDING)}setState(t){this.state!==t&&(this.state=t,this.emit("stateChange",this.status))}handleError(t){this.lastError=t,this.emit("error",t)}dispose(){this.stop().catch(t=>{console.warn("Error during dispose:",t)}),this.removeAllListeners()}}class E extends m{constructor(t){var s;super(),this.state=n.DISCONNECTED,this.reconnectAttempts=0,this.broadcasts=new Map,this.subscriptions=new Map,this.announcedBroadcasts=new Set,this.doReconnect=!0,this.disposed=!1,this.config={...t,reconnection:{delay:Math.max(((s=t.reconnection)==null?void 0:s.delay)||1e3,1e3)},connectionTimeout:t.connectionTimeout||1e4},this.url=new URL(this.config.relayUrl)}get status(){return{state:this.state,reconnectAttempts:this.reconnectAttempts,lastError:this.lastError,connectedAt:this.connectedAt}}async connect(){if(this.disposed)throw new Error("Cannot connect a disposed session");if(!(this.state===n.CONNECTING||this.state===n.CONNECTED)){this.setState(n.CONNECTING);try{this.doReconnect=!0,this.connection=await p.Connection.connect(this.url,{websocket:{enabled:!1}}),this.setState(n.CONNECTED),this.connectedAt=new Date,this.reconnectAttempts=0,this.connection.closed.then(()=>{!this.disposed&&this.state===n.CONNECTED&&this.handleDisconnection()}),this.startAnnouncementDiscovery(),await this.restartBroadcasts(),await this.restartSubscriptions()}catch(t){const s=new Error(`Failed to connect to relay: ${t.message}`);throw this.handleError(s),this.scheduleReconnect(),s}}}async disconnect(){if(this.doReconnect=!1,this.reconnectTimer&&(clearTimeout(this.reconnectTimer),this.reconnectTimer=void 0),await this.stopAllBroadcasts(),await this.stopAllSubscriptions(),this.connection){try{this.connection.close()}catch(t){console.warn("Error closing connection:",t)}this.connection=void 0}this.setState(n.DISCONNECTED),this.connectedAt=void 0}getAllBroadcastTrackNames(){return Array.from(this.broadcasts.keys())}getAllSubscriptionTrackNames(){return Array.from(this.subscriptions.keys())}updateBroadcasts(t){const s=t.map(i=>i.trackName),e=new Set(s);if(s.length!==e.size){const i=s.filter((h,o)=>s.indexOf(h)!==o);throw new Error(`Duplicate broadcast track name: ${i[0]}`)}const a=new Set(t.map(i=>i.trackName)),c=new Set(this.broadcasts.keys());for(const i of c)a.has(i)||this._removeBroadcast(i);for(const i of t){const h=this.broadcasts.get(i.trackName);h?h.config.priority!==i.priority&&(this._removeBroadcast(i.trackName),this._createBroadcast(i)):this._createBroadcast(i)}}updateSubscriptions(t){var i,h;const s=t.map(o=>o.trackName),e=new Set(s);if(s.length!==e.size){const o=s.filter((l,y)=>s.indexOf(l)!==y);throw new Error(`Duplicate subscription track name: ${o[0]}`)}const a=new Set(t.map(o=>o.trackName)),c=new Set(this.subscriptions.keys());for(const o of c)a.has(o)||this._removeSubscription(o);for(const o of t){const l=this.subscriptions.get(o.trackName);l?(l.config.priority!==o.priority||((i=l.config.retry)==null?void 0:i.delay)!==((h=o.retry)==null?void 0:h.delay))&&(this._removeSubscription(o.trackName),this._createSubscription(o)):this._createSubscription(o)}}getAnnouncedBroadcasts(){return Array.from(this.announcedBroadcasts)}async send(t,s,e){const a=this.broadcasts.get(t);if(!a)throw new Error(`No broadcast found for track: ${t}`);await a.send(s,e)}getBroadcastStatus(t){const s=this.broadcasts.get(t);return s==null?void 0:s.status}getSubscriptionStatus(t){const s=this.subscriptions.get(t);return s==null?void 0:s.status}_createBroadcast(t){const s=new f(t);return this.broadcasts.set(t.trackName,s),s.on("stateChange",e=>{this.emit("broadcastStateChange",t.trackName,e)}),s.on("error",e=>{this.emit("broadcastError",t.trackName,e)}),this.initBroadcasting(),s}_createSubscription(t){const s=new b(t);return this.subscriptions.set(t.trackName,s),s.on("data",e=>{this.emit("data",e.trackName,e.data,e.frameIndex)}),s.on("stateChange",e=>{this.emit("subscriptionStateChange",t.trackName,e)}),s.on("error",e=>{this.emit("subscriptionError",t.trackName,e)}),this.state===n.CONNECTED&&this.connection&&s.start(this.connection,this.config.namespace).catch(e=>{console.error("Failed to start subscription:",e)}),s}_removeBroadcast(t){const s=this.broadcasts.get(t);s&&(s.stop().catch(e=>{console.warn("Error stopping broadcast:",e)}),this.broadcasts.delete(t))}_removeSubscription(t){const s=this.subscriptions.get(t);s&&(s.stop().catch(e=>{console.warn("Error stopping subscription:",e)}),this.subscriptions.delete(t))}async startAnnouncementDiscovery(){if(this.connection)try{const t=p.Path.from(this.config.namespace),s=this.connection.announced(t);this.processAnnouncements(s)}catch(t){console.error("Failed to start announcement discovery:",t)}}async processAnnouncements(t){try{for(;!this.disposed;){const s=await t.next();if(!s||this.disposed)break;s.active?(this.announcedBroadcasts.add(s.path),this.emit("broadcastAnnounced",{path:s.path,active:!0})):(this.announcedBroadcasts.delete(s.path),this.emit("broadcastAnnounced",{path:s.path,active:!1}))}}catch(s){this.disposed||console.error("Error processing announcements:",s)}}async restartBroadcasts(){await this.stopAllBroadcasts(),this.initBroadcasting()}initBroadcasting(){this.broadcast||this.broadcasts.size!==0&&(this.broadcast=new p.Broadcast,this.connection&&(this.connection.publish(p.Path.from(this.config.namespace),this.broadcast),this.handleTrackRequests().catch(t=>{console.error("Error handling track requests:",t)})))}async handleTrackRequests(){if(this.broadcast)try{for(;;){const t=await this.broadcast.requested();if(!t)return;const s=this.broadcasts.get(t.track.name);s&&(s.updateTrack(t.track),this.emit("trackRequested",t.track.name))}}catch(t){console.warn("Error handling track requests:",t),this.handleError(t)}}async restartSubscriptions(){if(!this.connection)return;const t=Array.from(this.subscriptions.values()).map(s=>s.start(this.connection,this.config.namespace).catch(e=>{console.error("Failed to restart subscription:",e)}));await Promise.allSettled(t)}async stopAllBroadcasts(){var s;(s=this.broadcast)==null||s.close(),this.broadcast=void 0;const t=Array.from(this.broadcasts.values()).map(e=>e.stop().catch(a=>{console.warn("Error stopping broadcast:",a)}));await Promise.allSettled(t)}async stopAllSubscriptions(){const t=Array.from(this.subscriptions.values()).map(s=>s.stop().catch(e=>{console.warn("Error stopping subscription:",e)}));await Promise.allSettled(t)}handleDisconnection(){this.disposed||(this.setState(n.DISCONNECTED),this.scheduleReconnect())}scheduleReconnect(){var s;if(this.disposed||!this.config.reconnection||!this.doReconnect)return;const t=((s=this.config.reconnection)==null?void 0:s.delay)||1e3;this.setState(n.RECONNECTING),this.reconnectAttempts++,this.reconnectTimer=setTimeout(()=>{this.disposed||!this.doReconnect||this.state===n.RECONNECTING&&this.connect().catch(e=>{console.error("Reconnection failed:",e)})},t)}setState(t){this.disposed||this.state!==t&&(this.state=t,this.emit("stateChange",this.status))}handleError(t){this.disposed||(this.lastError=t,this.emit("error",t))}dispose(){this.disposed=!0,this.doReconnect=!1,this.reconnectTimer&&(clearTimeout(this.reconnectTimer),this.reconnectTimer=void 0),this.disconnect().catch(t=>{console.warn("Error during session disconnect:",t)}),this.removeAllListeners(),this.subscriptions.forEach(t=>t.dispose()),this.broadcasts.forEach(t=>t.dispose()),this.subscriptions.clear(),this.broadcasts.clear()}}exports.BroadcastState=d;exports.MoQBroadcast=f;exports.MoQSession=E;exports.MoQSubscription=b;exports.SessionState=n;exports.SubscriptionState=u;exports.default=E;
|
|
2
2
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","sources":["../src/event-emitter.ts","../src/types.ts","../src/broadcast.ts","../src/subscription.ts","../src/session.ts"],"sourcesContent":["// Simple event emitter for type-safe events\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport class EventEmitter<T extends Record<string, (...args: any[]) => void>> {\n private listeners = new Map<keyof T, Set<T[keyof T]>>();\n\n on<K extends keyof T>(event: K, listener: T[K]): void {\n if (!this.listeners.has(event)) {\n this.listeners.set(event, new Set());\n }\n this.listeners.get(event)!.add(listener);\n }\n\n off<K extends keyof T>(event: K, listener: T[K]): void {\n const eventListeners = this.listeners.get(event);\n if (eventListeners) {\n eventListeners.delete(listener);\n }\n }\n\n emit<K extends keyof T>(event: K, ...args: Parameters<T[K]>): void {\n const eventListeners = this.listeners.get(event);\n if (eventListeners) {\n eventListeners.forEach(listener => {\n try {\n listener(...args);\n } catch (error) {\n console.error('Error in event listener:', error);\n }\n });\n }\n }\n\n removeAllListeners<K extends keyof T>(event?: K): void {\n if (event) {\n this.listeners.delete(event);\n } else {\n this.listeners.clear();\n }\n }\n}","// Types for the library\nexport interface MoQSessionConfig {\n /** URL of the MoQ relay server */\n relayUrl: string;\n /** MoQ namespace (broadcast name) */\n namespace: string;\n /** Reconnection configuration */\n reconnection?: {\n /** Delay between reconnection attempts in ms (minimum: 1000) */\n delay?: number;\n };\n /** Connection timeout in ms (default: 10000) */\n connectionTimeout?: number;\n}\n\nexport interface BroadcastConfig {\n /** Track name for the broadcast */\n trackName: string;\n /** Priority for the track (default: 0) */\n priority?: number;\n}\n\nexport interface SubscriptionConfig {\n /** Track name to subscribe to */\n trackName: string;\n /** Priority for the subscription (default: 0) */\n priority?: number;\n /** Retry configuration for failed subscriptions */\n retry?: {\n /** Delay between retry attempts in ms (default: 2000) */\n delay?: number;\n };\n}\n\nexport enum SessionState {\n DISCONNECTED = 'disconnected',\n CONNECTING = 'connecting',\n CONNECTED = 'connected',\n RECONNECTING = 'reconnecting',\n FAILED = 'failed'\n}\n\nexport enum BroadcastState {\n IDLE = 'idle',\n BROADCASTING = 'broadcasting',\n ERROR = 'error'\n}\n\nexport enum SubscriptionState {\n PENDING = 'pending',\n SUBSCRIBED = 'subscribed',\n RETRYING = 'retrying',\n FAILED = 'failed'\n}\n\nexport interface SessionStatus {\n state: SessionState;\n reconnectAttempts: number;\n lastError?: Error;\n connectedAt?: Date;\n}\n\nexport interface BroadcastStatus {\n state: BroadcastState;\n trackName: string;\n bytesSent: number;\n lastError?: Error;\n}\n\nexport interface SubscriptionStatus {\n state: SubscriptionState;\n trackName: string;\n bytesReceived: number;\n retryAttempts: number;\n lastError?: Error;\n}\n\nexport interface DataReceived {\n trackName: string;\n data: Uint8Array;\n timestamp: number;\n frameIndex: number;\n}\n\n// Event types\nexport interface BroadcastAnnouncement {\n path: string;\n active: boolean;\n}\n\nexport interface SessionEvents {\n stateChange: (status: SessionStatus) => void;\n error: (error: Error) => void;\n broadcastAnnounced: (announcement: BroadcastAnnouncement) => void;\n data: (trackName: string, data: Uint8Array, frameIndex: number) => void;\n broadcastStateChange: (trackName: string, status: BroadcastStatus) => void;\n subscriptionStateChange: (trackName: string, status: SubscriptionStatus) => void;\n broadcastError: (trackName: string, error: Error) => void;\n subscriptionError: (trackName: string, error: Error) => void;\n trackRequested: (trackName: string) => void;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n [key: string]: (...args: any[]) => void;\n}\n\nexport interface BroadcastEvents {\n stateChange: (status: BroadcastStatus) => void;\n error: (error: Error) => void;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n [key: string]: (...args: any[]) => void;\n}\n\nexport interface SubscriptionEvents {\n stateChange: (status: SubscriptionStatus) => void;\n data: (data: DataReceived) => void;\n error: (error: Error) => void;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n [key: string]: (...args: any[]) => void;\n}","import { Group, Track } from '@kixelated/moq';\nimport { EventEmitter } from './event-emitter';\nimport {\n BroadcastConfig,\n BroadcastState,\n BroadcastStatus,\n BroadcastEvents\n} from './types';\n\nexport class MoQBroadcast extends EventEmitter<BroadcastEvents> {\n private _config: BroadcastConfig;\n private state: BroadcastState = BroadcastState.IDLE;\n private bytesSent = 0;\n private lastError?: Error;\n private track?: Track;\n private group?: Group;\n\n constructor(config: BroadcastConfig) {\n super();\n this._config = config;\n }\n\n get status(): BroadcastStatus {\n return {\n state: this.state,\n trackName: this._config.trackName,\n bytesSent: this.bytesSent,\n lastError: this.lastError\n };\n }\n\n get config(): BroadcastConfig {\n return { ...this._config };\n }\n\n updateTrack(track: Track): void {\n this.track = track;\n if (track) {\n this.setState(BroadcastState.BROADCASTING);\n }\n }\n\n async send(data: Uint8Array, newGroup: boolean): Promise<void> {\n if (this.state !== BroadcastState.BROADCASTING || !this.track) {\n throw new Error('Broadcast is not active');\n }\n\n try {\n if (newGroup || !this.group) {\n if (this.group) {\n this.group.close();\n }\n this.group = this.track.appendGroup();\n }\n await this.group.writeFrame(data);\n this.bytesSent += data.length;\n } catch (error) {\n this.handleError(error as Error);\n throw error;\n }\n }\n\n async stop(): Promise<void> {\n if (this.track) {\n try {\n this.track.close();\n } catch (error) {\n console.warn('Error closing track:', error);\n }\n this.track = undefined;\n }\n \n this.setState(BroadcastState.IDLE);\n }\n\n private setState(newState: BroadcastState): void {\n if (this.state !== newState) {\n this.state = newState;\n this.emit('stateChange', this.status);\n }\n }\n\n private handleError(error: Error): void {\n this.lastError = error;\n this.setState(BroadcastState.ERROR);\n this.emit('error', error);\n }\n\n public dispose(): void {\n this.stop().catch(console.error);\n this.removeAllListeners();\n }\n}","import { Broadcast, Track, Connection, Path } from '@kixelated/moq';\nimport { EventEmitter } from './event-emitter';\nimport {\n SubscriptionConfig,\n SubscriptionState,\n SubscriptionStatus,\n SubscriptionEvents,\n DataReceived\n} from './types';\n\nexport class MoQSubscription extends EventEmitter<SubscriptionEvents> {\n private _config: SubscriptionConfig;\n private state: SubscriptionState = SubscriptionState.PENDING;\n private bytesReceived = 0;\n private retryAttempts = 0;\n private lastError?: Error;\n private subscription?: Track;\n private broadcast?: Broadcast;\n private retryTimer?: ReturnType<typeof setTimeout>;\n private connection?: Connection.Established;\n private namespace?: string;\n\n constructor(config: SubscriptionConfig) {\n super();\n this._config = config;\n }\n\n get status(): SubscriptionStatus {\n return {\n state: this.state,\n trackName: this._config.trackName,\n bytesReceived: this.bytesReceived,\n retryAttempts: this.retryAttempts,\n lastError: this.lastError\n };\n }\n\n get config(): SubscriptionConfig {\n return { ...this._config };\n }\n\n async start(connection: Connection.Established, namespace: string): Promise<void> {\n this.connection = connection;\n this.namespace = namespace;\n try {\n await this.subscribe(connection, namespace);\n } catch (error) {\n this.handleError(error as Error);\n this.scheduleRetry(connection, namespace);\n }\n }\n\n private async subscribe(connection: Connection.Established, namespace: string): Promise<void> {\n this.setState(SubscriptionState.PENDING);\n\n const broadcastPath = Path.from(namespace);\n this.broadcast = connection.consume(broadcastPath);\n\n // Subscribe to the specific track within the broadcast\n this.subscription = this.broadcast.subscribe(this._config.trackName, this._config.priority || 0);\n this.setState(SubscriptionState.SUBSCRIBED);\n this.retryAttempts = 0;\n\n // Set up data reception\n this.readFrames();\n }\n\n private async readFrames(): Promise<void> {\n if (!this.subscription) return;\n\n try {\n // eslint-disable-next-line no-constant-condition\n while (true) {\n let framesInGroup = 0;\n const group = await this.subscription.nextGroup();\n if (!group) break; // Track is closed\n\n // Read all frames from the group\n // eslint-disable-next-line no-constant-condition\n while (true) {\n const frame = await group.readFrame();\n if (!frame) break; // Group is finished\n framesInGroup++;\n\n this.bytesReceived += frame.length;\n const receivedData: DataReceived = {\n trackName: this._config.trackName,\n data: frame,\n timestamp: Date.now(),\n frameIndex: framesInGroup,\n };\n this.emit('data', receivedData);\n }\n }\n } catch (error) {\n this.handleError(error as Error);\n // Trigger retry when stream gets reset/closed\n if (this.connection && this.namespace) {\n this.scheduleRetry(this.connection, this.namespace);\n }\n }\n }\n \n private scheduleRetry(connection: Connection.Established, namespace: string): void {\n const delay = this._config.retry?.delay || 2000;\n\n this.setState(SubscriptionState.RETRYING);\n this.retryAttempts++;\n\n this.retryTimer = setTimeout(async () => {\n try {\n await this.subscribe(connection, namespace);\n } catch (error) {\n this.handleError(error as Error);\n this.scheduleRetry(connection, namespace);\n }\n }, delay);\n }\n\n async stop(): Promise<void> {\n this.connection = undefined;\n this.namespace = undefined;\n \n if (this.retryTimer) {\n clearTimeout(this.retryTimer);\n this.retryTimer = undefined;\n }\n\n if (this.subscription) {\n try {\n this.subscription.close();\n } catch (error) {\n console.warn('Error closing subscription:', error);\n }\n this.subscription = undefined;\n }\n\n if (this.broadcast) {\n try {\n this.broadcast.close();\n } catch (error) {\n console.warn('Error closing broadcast:', error);\n }\n this.broadcast = undefined;\n }\n\n this.setState(SubscriptionState.PENDING);\n }\n\n private setState(newState: SubscriptionState): void {\n if (this.state !== newState) {\n this.state = newState;\n this.emit('stateChange', this.status);\n }\n }\n\n private handleError(error: Error): void {\n this.lastError = error;\n this.emit('error', error);\n }\n\n dispose(): void {\n this.stop().catch((error) => {\n console.warn('Error during dispose:', error);\n });\n this.removeAllListeners();\n }\n}","import { Broadcast, Connection, Path } from '@kixelated/moq';\nimport { EventEmitter } from './event-emitter';\nimport { MoQBroadcast } from './broadcast';\nimport { MoQSubscription } from './subscription';\nimport {\n MoQSessionConfig,\n SessionState,\n SessionStatus,\n SessionEvents,\n BroadcastConfig,\n SubscriptionConfig\n} from './types';\n\nexport class MoQSession extends EventEmitter<SessionEvents> {\n private config: MoQSessionConfig;\n private url: URL;\n private state: SessionState = SessionState.DISCONNECTED;\n private connection?: Connection.Established;\n private reconnectAttempts = 0;\n private lastError?: Error;\n private connectedAt?: Date;\n private reconnectTimer?: ReturnType<typeof setTimeout>;\n private broadcasts = new Map<string, MoQBroadcast>();\n private subscriptions = new Map<string, MoQSubscription>();\n private announcedBroadcasts = new Set<string>();\n private doReconnect = true;\n private broadcast?: Broadcast;\n\n constructor(config: MoQSessionConfig) {\n super();\n this.config = {\n ...config,\n reconnection: {\n delay: Math.max(config.reconnection?.delay || 1000, 1000), // Enforce minimum 1 second\n },\n connectionTimeout: config.connectionTimeout || 10000\n };\n\n this.url = new URL(this.config.relayUrl);\n }\n\n get status(): SessionStatus {\n return {\n state: this.state,\n reconnectAttempts: this.reconnectAttempts,\n lastError: this.lastError,\n connectedAt: this.connectedAt\n };\n }\n\n async connect(): Promise<void> {\n if (this.state === SessionState.CONNECTING || this.state === SessionState.CONNECTED) {\n return;\n }\n\n this.setState(SessionState.CONNECTING);\n\n try {\n this.doReconnect = true;\n this.connection = await Connection.connect(this.url, {\n websocket: {\n enabled: false\n }\n });\n\n this.setState(SessionState.CONNECTED);\n this.connectedAt = new Date();\n this.reconnectAttempts = 0;\n\n // Set up connection close handling\n this.connection.closed.then(() => {\n if (this.state === SessionState.CONNECTED) {\n this.handleDisconnection();\n }\n });\n\n // Start discovering announced broadcasts\n this.startAnnouncementDiscovery();\n\n // Restart all broadcasts and subscriptions\n await this.restartBroadcasts();\n await this.restartSubscriptions();\n\n } catch (error) {\n this.handleError(error as Error);\n this.scheduleReconnect();\n throw error;\n }\n }\n\n async disconnect(): Promise<void> {\n this.doReconnect = false;\n\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = undefined;\n }\n\n // Stop all broadcasts and subscriptions\n await this.stopAllBroadcasts();\n await this.stopAllSubscriptions();\n\n if (this.connection) {\n try {\n this.connection.close();\n } catch (error) {\n console.warn('Error closing connection:', error);\n }\n this.connection = undefined;\n }\n\n this.setState(SessionState.DISCONNECTED);\n this.connectedAt = undefined;\n }\n\n /**\n * Get all active broadcast track names\n */\n getAllBroadcastTrackNames(): string[] {\n return Array.from(this.broadcasts.keys());\n }\n\n /**\n * Get all active subscription track names\n */\n getAllSubscriptionTrackNames(): string[] {\n return Array.from(this.subscriptions.keys());\n }\n\n /**\n * Declaratively update broadcasts - add, remove, or update broadcasts to match the desired state.\n * \n * @param configs Array of broadcast configurations representing the desired state\n */\n updateBroadcasts(configs: BroadcastConfig[]): void {\n // Check for duplicate track names in the input\n const trackNames = configs.map(config => config.trackName);\n const uniqueTrackNames = new Set(trackNames);\n if (trackNames.length !== uniqueTrackNames.size) {\n const duplicates = trackNames.filter((name, index) => trackNames.indexOf(name) !== index);\n throw new Error(`Duplicate broadcast track name: ${duplicates[0]}`);\n }\n\n const desiredTracks = new Set(configs.map(config => config.trackName));\n const currentTracks = new Set(this.broadcasts.keys());\n\n // Remove broadcasts that are no longer needed\n for (const trackName of currentTracks) {\n if (!desiredTracks.has(trackName)) {\n this._removeBroadcast(trackName);\n }\n }\n\n // Add new broadcasts or update existing ones\n for (const config of configs) {\n const existing = this.broadcasts.get(config.trackName);\n if (!existing) {\n // Create new broadcast\n this._createBroadcast(config);\n } else {\n // Update existing broadcast config if needed\n if (existing.config.priority !== config.priority) {\n // For now, we recreate if priority changed\n // In future, we could support dynamic priority updates\n this._removeBroadcast(config.trackName);\n this._createBroadcast(config);\n }\n }\n }\n }\n\n /**\n * Declaratively update subscriptions - add, remove, or update subscriptions to match the desired state.\n * \n * @param configs Array of subscription configurations representing the desired state\n */\n updateSubscriptions(configs: SubscriptionConfig[]): void {\n // Check for duplicate track names in the input\n const trackNames = configs.map(config => config.trackName);\n const uniqueTrackNames = new Set(trackNames);\n if (trackNames.length !== uniqueTrackNames.size) {\n const duplicates = trackNames.filter((name, index) => trackNames.indexOf(name) !== index);\n throw new Error(`Duplicate subscription track name: ${duplicates[0]}`);\n }\n\n const desiredTracks = new Set(configs.map(config => config.trackName));\n const currentTracks = new Set(this.subscriptions.keys());\n\n // Remove subscriptions that are no longer needed\n for (const trackName of currentTracks) {\n if (!desiredTracks.has(trackName)) {\n this._removeSubscription(trackName);\n }\n }\n\n // Add new subscriptions or update existing ones\n for (const config of configs) {\n const existing = this.subscriptions.get(config.trackName);\n if (!existing) {\n // Create new subscription\n this._createSubscription(config);\n } else {\n // Update existing subscription config if needed\n if (existing.config.priority !== config.priority || \n existing.config.retry?.delay !== config.retry?.delay) {\n // For now, we recreate if config changed\n // In future, we could support dynamic config updates\n this._removeSubscription(config.trackName);\n this._createSubscription(config);\n }\n }\n }\n }\n\n getAnnouncedBroadcasts(): string[] {\n return Array.from(this.announcedBroadcasts);\n }\n\n /**\n * Send data to a broadcast track\n * @param trackName Name of the track to send data to\n * @param data Binary data to send\n */\n async send(trackName: string, data: Uint8Array, newGroup: boolean): Promise<void> {\n const broadcast = this.broadcasts.get(trackName);\n if (!broadcast) {\n throw new Error(`No broadcast found for track: ${trackName}`);\n }\n await broadcast.send(data, newGroup);\n }\n\n /**\n * Get the status of a specific broadcast track\n * @param trackName Name of the track\n */\n getBroadcastStatus(trackName: string) {\n const broadcast = this.broadcasts.get(trackName);\n return broadcast?.status;\n }\n\n /**\n * Get the status of a specific subscription track\n * @param trackName Name of the track\n */\n getSubscriptionStatus(trackName: string) {\n const subscription = this.subscriptions.get(trackName);\n return subscription?.status;\n }\n\n private _createBroadcast(config: BroadcastConfig): MoQBroadcast {\n const broadcast = new MoQBroadcast(config);\n this.broadcasts.set(config.trackName, broadcast);\n\n // Forward broadcast events to session\n broadcast.on('stateChange', (status) => {\n this.emit('broadcastStateChange', config.trackName, status);\n });\n\n broadcast.on('error', (error) => {\n this.emit('broadcastError', config.trackName, error);\n });\n\n this.initBroadcasting();\n\n return broadcast;\n }\n\n private _createSubscription(config: SubscriptionConfig): MoQSubscription {\n const subscription = new MoQSubscription(config);\n this.subscriptions.set(config.trackName, subscription);\n\n // Forward subscription events to session\n subscription.on('data', (received) => {\n this.emit('data', received.trackName, received.data, received.frameIndex);\n });\n\n subscription.on('stateChange', (status) => {\n this.emit('subscriptionStateChange', config.trackName, status);\n });\n\n subscription.on('error', (error) => {\n this.emit('subscriptionError', config.trackName, error);\n });\n\n // Start subscription if we're connected\n if (this.state === SessionState.CONNECTED && this.connection) {\n subscription.start(this.connection, this.config.namespace).catch(error => {\n console.error('Failed to start subscription:', error);\n });\n }\n\n return subscription;\n }\n\n private _removeBroadcast(trackName: string): void {\n const broadcast = this.broadcasts.get(trackName);\n if (broadcast) {\n broadcast.stop().catch(error => {\n console.warn('Error stopping broadcast:', error);\n });\n this.broadcasts.delete(trackName);\n }\n }\n\n private _removeSubscription(trackName: string): void {\n const subscription = this.subscriptions.get(trackName);\n if (subscription) {\n subscription.stop().catch(error => {\n console.warn('Error stopping subscription:', error);\n });\n this.subscriptions.delete(trackName);\n }\n }\n\n private async startAnnouncementDiscovery(): Promise<void> {\n if (!this.connection) return;\n\n try {\n // Listen for announcements with our namespace as prefix\n const namespacePath = Path.from(this.config.namespace);\n const announced = this.connection.announced(namespacePath);\n \n // Process announcements in the background\n this.processAnnouncements(announced);\n \n } catch (error) {\n console.error('Failed to start announcement discovery:', error);\n }\n }\n\n private async processAnnouncements(announced: ReturnType<Connection.Established['announced']>): Promise<void> {\n try {\n for (;;) {\n const announcement = await announced.next();\n if (!announcement) break; // Announcements closed\n \n if (announcement.active) {\n this.announcedBroadcasts.add(announcement.path);\n this.emit('broadcastAnnounced', {\n path: announcement.path,\n active: true\n });\n } else {\n this.announcedBroadcasts.delete(announcement.path);\n this.emit('broadcastAnnounced', {\n path: announcement.path,\n active: false\n });\n }\n }\n } catch (error) {\n console.error('Error processing announcements:', error);\n }\n }\n\n private async restartBroadcasts(): Promise<void> {\n await this.stopAllBroadcasts();\n this.initBroadcasting();\n }\n\n private initBroadcasting(): void {\n if (this.broadcast) return;\n if (this.broadcasts.size === 0) return;\n\n this.broadcast = new Broadcast();\n if (this.connection) {\n this.connection.publish(Path.from(this.config.namespace), this.broadcast);\n this.handleTrackRequests().catch(error => {\n console.error('Error handling track requests:', error);\n });\n }\n }\n\n private async handleTrackRequests(): Promise<void> {\n if (!this.broadcast) return;\n \n try {\n for (;;) {\n const request = await this.broadcast.requested();\n if (!request) return; // No more requests, broadcast closed;\n const broadcast = this.broadcasts.get(request.track.name);\n if (broadcast) {\n broadcast.updateTrack(request.track);\n this.emit('trackRequested', request.track.name);\n }\n }\n\n } catch (error) {\n console.warn('Error handling track requests:', error);\n this.handleError(error as Error);\n }\n}\n\n private async restartSubscriptions(): Promise<void> {\n if (!this.connection) return;\n\n const promises = Array.from(this.subscriptions.values()).map(subscription => \n subscription.start(this.connection!, this.config.namespace).catch(error => {\n console.error('Failed to restart subscription:', error);\n })\n );\n\n await Promise.allSettled(promises);\n }\n\n private async stopAllBroadcasts(): Promise<void> {\n this.broadcast?.close();\n this.broadcast = undefined;\n const promises = Array.from(this.broadcasts.values()).map(broadcast => \n broadcast.stop().catch(error => {\n console.warn('Error stopping broadcast:', error);\n })\n );\n\n await Promise.allSettled(promises);\n }\n\n private async stopAllSubscriptions(): Promise<void> {\n const promises = Array.from(this.subscriptions.values()).map(subscription => \n subscription.stop().catch(error => {\n console.warn('Error stopping subscription:', error);\n })\n );\n\n await Promise.allSettled(promises);\n }\n\n private handleDisconnection(): void {\n this.setState(SessionState.DISCONNECTED);\n this.scheduleReconnect();\n }\n\n private scheduleReconnect(): void {\n if (!this.config.reconnection || !this.doReconnect) return;\n\n const delay = this.config.reconnection?.delay || 1000;\n\n this.setState(SessionState.RECONNECTING);\n this.reconnectAttempts++;\n\n this.reconnectTimer = setTimeout(() => {\n if (!this.doReconnect) return;\n if (this.state !== SessionState.RECONNECTING) return;\n this.connect().catch(error => {\n console.error('Reconnection failed:', error);\n });\n }, delay);\n }\n\n private setState(newState: SessionState): void {\n if (this.state !== newState) {\n this.state = newState;\n this.emit('stateChange', this.status);\n }\n }\n\n private handleError(error: Error): void {\n this.lastError = error;\n this.emit('error', error);\n }\n\n public dispose(): void {\n // Immediately stop reconnection attempts\n this.doReconnect = false;\n \n // Clear any pending reconnect timer immediately\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = undefined;\n }\n \n // Disconnect (but don't await to keep dispose synchronous)\n this.disconnect().catch((error) => {\n console.warn('Error during session disconnect:', error);\n });\n this.removeAllListeners();\n\n this.subscriptions.forEach(sub => sub.dispose());\n this.broadcasts.forEach(bc => bc.dispose());\n this.subscriptions.clear();\n this.broadcasts.clear();\n }\n}"],"names":["EventEmitter","event","listener","eventListeners","args","error","SessionState","BroadcastState","SubscriptionState","MoQBroadcast","config","track","data","newGroup","newState","MoQSubscription","connection","namespace","broadcastPath","Path","framesInGroup","group","frame","receivedData","delay","_a","MoQSession","Connection","configs","trackNames","uniqueTrackNames","duplicates","name","index","desiredTracks","currentTracks","trackName","existing","_b","broadcast","subscription","status","received","namespacePath","announced","announcement","Broadcast","request","promises","sub","bc"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs","sources":["../src/event-emitter.ts","../src/types.ts","../src/broadcast.ts","../src/subscription.ts","../src/session.ts"],"sourcesContent":["// Simple event emitter for type-safe events\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport class EventEmitter<T extends Record<string, (...args: any[]) => void>> {\n private listeners = new Map<keyof T, Set<T[keyof T]>>();\n\n on<K extends keyof T>(event: K, listener: T[K]): void {\n if (!this.listeners.has(event)) {\n this.listeners.set(event, new Set());\n }\n this.listeners.get(event)!.add(listener);\n }\n\n off<K extends keyof T>(event: K, listener: T[K]): void {\n const eventListeners = this.listeners.get(event);\n if (eventListeners) {\n eventListeners.delete(listener);\n }\n }\n\n emit<K extends keyof T>(event: K, ...args: Parameters<T[K]>): void {\n const eventListeners = this.listeners.get(event);\n if (eventListeners) {\n eventListeners.forEach(listener => {\n try {\n listener(...args);\n } catch (error) {\n console.error('Error in event listener:', error);\n }\n });\n }\n }\n\n removeAllListeners<K extends keyof T>(event?: K): void {\n if (event) {\n this.listeners.delete(event);\n } else {\n this.listeners.clear();\n }\n }\n}","// Types for the library\nexport interface MoQSessionConfig {\n /** URL of the MoQ relay server */\n relayUrl: string;\n /** MoQ namespace (broadcast name) */\n namespace: string;\n /** Reconnection configuration */\n reconnection?: {\n /** Delay between reconnection attempts in ms (minimum: 1000) */\n delay?: number;\n };\n /** Connection timeout in ms (default: 10000) */\n connectionTimeout?: number;\n}\n\nexport interface BroadcastConfig {\n /** Track name for the broadcast */\n trackName: string;\n /** Priority for the track (default: 0) */\n priority?: number;\n}\n\nexport interface SubscriptionConfig {\n /** Track name to subscribe to */\n trackName: string;\n /** Priority for the subscription (default: 0) */\n priority?: number;\n /** Retry configuration for failed subscriptions */\n retry?: {\n /** Delay between retry attempts in ms (default: 2000) */\n delay?: number;\n };\n}\n\nexport enum SessionState {\n DISCONNECTED = 'disconnected',\n CONNECTING = 'connecting',\n CONNECTED = 'connected',\n RECONNECTING = 'reconnecting',\n FAILED = 'failed'\n}\n\nexport enum BroadcastState {\n IDLE = 'idle',\n BROADCASTING = 'broadcasting',\n ERROR = 'error'\n}\n\nexport enum SubscriptionState {\n PENDING = 'pending',\n SUBSCRIBED = 'subscribed',\n RETRYING = 'retrying',\n FAILED = 'failed'\n}\n\nexport interface SessionStatus {\n state: SessionState;\n reconnectAttempts: number;\n lastError?: Error;\n connectedAt?: Date;\n}\n\nexport interface BroadcastStatus {\n state: BroadcastState;\n trackName: string;\n bytesSent: number;\n lastError?: Error;\n}\n\nexport interface SubscriptionStatus {\n state: SubscriptionState;\n trackName: string;\n bytesReceived: number;\n retryAttempts: number;\n lastError?: Error;\n}\n\nexport interface DataReceived {\n trackName: string;\n data: Uint8Array;\n timestamp: number;\n frameIndex: number;\n}\n\n// Event types\nexport interface BroadcastAnnouncement {\n path: string;\n active: boolean;\n}\n\nexport interface SessionEvents {\n stateChange: (status: SessionStatus) => void;\n error: (error: Error) => void;\n broadcastAnnounced: (announcement: BroadcastAnnouncement) => void;\n data: (trackName: string, data: Uint8Array, frameIndex: number) => void;\n broadcastStateChange: (trackName: string, status: BroadcastStatus) => void;\n subscriptionStateChange: (trackName: string, status: SubscriptionStatus) => void;\n broadcastError: (trackName: string, error: Error) => void;\n subscriptionError: (trackName: string, error: Error) => void;\n trackRequested: (trackName: string) => void;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n [key: string]: (...args: any[]) => void;\n}\n\nexport interface BroadcastEvents {\n stateChange: (status: BroadcastStatus) => void;\n error: (error: Error) => void;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n [key: string]: (...args: any[]) => void;\n}\n\nexport interface SubscriptionEvents {\n stateChange: (status: SubscriptionStatus) => void;\n data: (data: DataReceived) => void;\n error: (error: Error) => void;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n [key: string]: (...args: any[]) => void;\n}","import { Group, Track } from '@kixelated/moq';\nimport { EventEmitter } from './event-emitter';\nimport {\n BroadcastConfig,\n BroadcastState,\n BroadcastStatus,\n BroadcastEvents\n} from './types';\n\nexport class MoQBroadcast extends EventEmitter<BroadcastEvents> {\n private _config: BroadcastConfig;\n private state: BroadcastState = BroadcastState.IDLE;\n private bytesSent = 0;\n private lastError?: Error;\n private track?: Track;\n private group?: Group;\n\n constructor(config: BroadcastConfig) {\n super();\n this._config = config;\n }\n\n get status(): BroadcastStatus {\n return {\n state: this.state,\n trackName: this._config.trackName,\n bytesSent: this.bytesSent,\n lastError: this.lastError\n };\n }\n\n get config(): BroadcastConfig {\n return { ...this._config };\n }\n\n updateTrack(track: Track): void {\n this.track = track;\n if (track) {\n this.setState(BroadcastState.BROADCASTING);\n }\n }\n\n async send(data: Uint8Array, newGroup: boolean): Promise<void> {\n if (this.state !== BroadcastState.BROADCASTING || !this.track) {\n throw new Error('Broadcast is not active');\n }\n\n try {\n if (newGroup || !this.group) {\n if (this.group) {\n this.group.close();\n }\n this.group = this.track.appendGroup();\n }\n await this.group.writeFrame(data);\n this.bytesSent += data.length;\n } catch (error) {\n this.handleError(error as Error);\n throw error;\n }\n }\n\n async stop(): Promise<void> {\n if (this.track) {\n try {\n this.track.close();\n } catch (error) {\n console.warn('Error closing track:', error);\n }\n this.track = undefined;\n }\n \n this.setState(BroadcastState.IDLE);\n }\n\n private setState(newState: BroadcastState): void {\n if (this.state !== newState) {\n this.state = newState;\n this.emit('stateChange', this.status);\n }\n }\n\n private handleError(error: Error): void {\n this.lastError = error;\n this.setState(BroadcastState.ERROR);\n this.emit('error', error);\n }\n\n public dispose(): void {\n this.stop().catch(console.error);\n this.removeAllListeners();\n }\n}","import { Broadcast, Track, Connection, Path } from '@kixelated/moq';\nimport { EventEmitter } from './event-emitter';\nimport {\n SubscriptionConfig,\n SubscriptionState,\n SubscriptionStatus,\n SubscriptionEvents,\n DataReceived\n} from './types';\n\nexport class MoQSubscription extends EventEmitter<SubscriptionEvents> {\n private _config: SubscriptionConfig;\n private state: SubscriptionState = SubscriptionState.PENDING;\n private bytesReceived = 0;\n private retryAttempts = 0;\n private lastError?: Error;\n private subscription?: Track;\n private broadcast?: Broadcast;\n private retryTimer?: ReturnType<typeof setTimeout>;\n private connection?: Connection.Established;\n private namespace?: string;\n\n constructor(config: SubscriptionConfig) {\n super();\n this._config = config;\n }\n\n get status(): SubscriptionStatus {\n return {\n state: this.state,\n trackName: this._config.trackName,\n bytesReceived: this.bytesReceived,\n retryAttempts: this.retryAttempts,\n lastError: this.lastError\n };\n }\n\n get config(): SubscriptionConfig {\n return { ...this._config };\n }\n\n async start(connection: Connection.Established, namespace: string): Promise<void> {\n this.connection = connection;\n this.namespace = namespace;\n try {\n await this.subscribe(connection, namespace);\n } catch (error) {\n this.handleError(error as Error);\n this.scheduleRetry(connection, namespace);\n }\n }\n\n private async subscribe(connection: Connection.Established, namespace: string): Promise<void> {\n this.setState(SubscriptionState.PENDING);\n\n const broadcastPath = Path.from(namespace);\n this.broadcast = connection.consume(broadcastPath);\n\n // Subscribe to the specific track within the broadcast\n this.subscription = this.broadcast.subscribe(this._config.trackName, this._config.priority || 0);\n this.setState(SubscriptionState.SUBSCRIBED);\n this.retryAttempts = 0;\n\n // Set up data reception\n this.readFrames();\n }\n\n private async readFrames(): Promise<void> {\n if (!this.subscription) return;\n\n try {\n // eslint-disable-next-line no-constant-condition\n while (true) {\n let framesInGroup = 0;\n const group = await this.subscription.nextGroup();\n if (!group) break; // Track is closed\n\n // Read all frames from the group\n // eslint-disable-next-line no-constant-condition\n while (true) {\n const frame = await group.readFrame();\n if (!frame) break; // Group is finished\n framesInGroup++;\n\n this.bytesReceived += frame.length;\n const receivedData: DataReceived = {\n trackName: this._config.trackName,\n data: frame,\n timestamp: Date.now(),\n frameIndex: framesInGroup,\n };\n this.emit('data', receivedData);\n }\n }\n } catch (error) {\n this.handleError(error as Error);\n // Trigger retry when stream gets reset/closed\n if (this.connection && this.namespace) {\n this.scheduleRetry(this.connection, this.namespace);\n }\n }\n }\n \n private scheduleRetry(connection: Connection.Established, namespace: string): void {\n const delay = this._config.retry?.delay || 2000;\n\n this.setState(SubscriptionState.RETRYING);\n this.retryAttempts++;\n\n this.retryTimer = setTimeout(async () => {\n try {\n await this.subscribe(connection, namespace);\n } catch (error) {\n this.handleError(error as Error);\n this.scheduleRetry(connection, namespace);\n }\n }, delay);\n }\n\n async stop(): Promise<void> {\n this.connection = undefined;\n this.namespace = undefined;\n \n if (this.retryTimer) {\n clearTimeout(this.retryTimer);\n this.retryTimer = undefined;\n }\n\n if (this.subscription) {\n try {\n this.subscription.close();\n } catch (error) {\n console.warn('Error closing subscription:', error);\n }\n this.subscription = undefined;\n }\n\n if (this.broadcast) {\n try {\n this.broadcast.close();\n } catch (error) {\n console.warn('Error closing broadcast:', error);\n }\n this.broadcast = undefined;\n }\n\n this.setState(SubscriptionState.PENDING);\n }\n\n private setState(newState: SubscriptionState): void {\n if (this.state !== newState) {\n this.state = newState;\n this.emit('stateChange', this.status);\n }\n }\n\n private handleError(error: Error): void {\n this.lastError = error;\n this.emit('error', error);\n }\n\n dispose(): void {\n this.stop().catch((error) => {\n console.warn('Error during dispose:', error);\n });\n this.removeAllListeners();\n }\n}","import { Broadcast, Connection, Path } from '@kixelated/moq';\nimport { EventEmitter } from './event-emitter';\nimport { MoQBroadcast } from './broadcast';\nimport { MoQSubscription } from './subscription';\nimport {\n MoQSessionConfig,\n SessionState,\n SessionStatus,\n SessionEvents,\n BroadcastConfig,\n SubscriptionConfig\n} from './types';\n\nexport class MoQSession extends EventEmitter<SessionEvents> {\n private config: MoQSessionConfig;\n private url: URL;\n private state: SessionState = SessionState.DISCONNECTED;\n private connection?: Connection.Established;\n private reconnectAttempts = 0;\n private lastError?: Error;\n private connectedAt?: Date;\n private reconnectTimer?: ReturnType<typeof setTimeout>;\n private broadcasts = new Map<string, MoQBroadcast>();\n private subscriptions = new Map<string, MoQSubscription>();\n private announcedBroadcasts = new Set<string>();\n private doReconnect = true;\n private broadcast?: Broadcast;\n private disposed = false;\n\n constructor(config: MoQSessionConfig) {\n super();\n this.config = {\n ...config,\n reconnection: {\n delay: Math.max(config.reconnection?.delay || 1000, 1000), // Enforce minimum 1 second\n },\n connectionTimeout: config.connectionTimeout || 10000\n };\n\n this.url = new URL(this.config.relayUrl);\n }\n\n get status(): SessionStatus {\n return {\n state: this.state,\n reconnectAttempts: this.reconnectAttempts,\n lastError: this.lastError,\n connectedAt: this.connectedAt\n };\n }\n\n async connect(): Promise<void> {\n if (this.disposed) {\n throw new Error('Cannot connect a disposed session');\n }\n \n if (this.state === SessionState.CONNECTING || this.state === SessionState.CONNECTED) {\n return;\n }\n\n this.setState(SessionState.CONNECTING);\n\n try {\n this.doReconnect = true;\n this.connection = await Connection.connect(this.url, {\n websocket: {\n enabled: false\n }\n });\n\n this.setState(SessionState.CONNECTED);\n this.connectedAt = new Date();\n this.reconnectAttempts = 0;\n\n // Set up connection close handling\n this.connection.closed.then(() => {\n // Only handle disconnection if not disposed\n if (!this.disposed && this.state === SessionState.CONNECTED) {\n this.handleDisconnection();\n }\n });\n\n // Start discovering announced broadcasts\n this.startAnnouncementDiscovery();\n\n // Restart all broadcasts and subscriptions\n await this.restartBroadcasts();\n await this.restartSubscriptions();\n\n } catch (error) {\n const err = new Error(`Failed to connect to relay: ${(error as Error).message}`);\n this.handleError(err);\n this.scheduleReconnect();\n throw err;\n }\n }\n\n async disconnect(): Promise<void> {\n this.doReconnect = false;\n\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = undefined;\n }\n\n // Stop all broadcasts and subscriptions\n await this.stopAllBroadcasts();\n await this.stopAllSubscriptions();\n\n if (this.connection) {\n try {\n this.connection.close();\n } catch (error) {\n console.warn('Error closing connection:', error);\n }\n this.connection = undefined;\n }\n\n this.setState(SessionState.DISCONNECTED);\n this.connectedAt = undefined;\n }\n\n /**\n * Get all active broadcast track names\n */\n getAllBroadcastTrackNames(): string[] {\n return Array.from(this.broadcasts.keys());\n }\n\n /**\n * Get all active subscription track names\n */\n getAllSubscriptionTrackNames(): string[] {\n return Array.from(this.subscriptions.keys());\n }\n\n /**\n * Declaratively update broadcasts - add, remove, or update broadcasts to match the desired state.\n * \n * @param configs Array of broadcast configurations representing the desired state\n */\n updateBroadcasts(configs: BroadcastConfig[]): void {\n // Check for duplicate track names in the input\n const trackNames = configs.map(config => config.trackName);\n const uniqueTrackNames = new Set(trackNames);\n if (trackNames.length !== uniqueTrackNames.size) {\n const duplicates = trackNames.filter((name, index) => trackNames.indexOf(name) !== index);\n throw new Error(`Duplicate broadcast track name: ${duplicates[0]}`);\n }\n\n const desiredTracks = new Set(configs.map(config => config.trackName));\n const currentTracks = new Set(this.broadcasts.keys());\n\n // Remove broadcasts that are no longer needed\n for (const trackName of currentTracks) {\n if (!desiredTracks.has(trackName)) {\n this._removeBroadcast(trackName);\n }\n }\n\n // Add new broadcasts or update existing ones\n for (const config of configs) {\n const existing = this.broadcasts.get(config.trackName);\n if (!existing) {\n // Create new broadcast\n this._createBroadcast(config);\n } else {\n // Update existing broadcast config if needed\n if (existing.config.priority !== config.priority) {\n // For now, we recreate if priority changed\n // In future, we could support dynamic priority updates\n this._removeBroadcast(config.trackName);\n this._createBroadcast(config);\n }\n }\n }\n }\n\n /**\n * Declaratively update subscriptions - add, remove, or update subscriptions to match the desired state.\n * \n * @param configs Array of subscription configurations representing the desired state\n */\n updateSubscriptions(configs: SubscriptionConfig[]): void {\n // Check for duplicate track names in the input\n const trackNames = configs.map(config => config.trackName);\n const uniqueTrackNames = new Set(trackNames);\n if (trackNames.length !== uniqueTrackNames.size) {\n const duplicates = trackNames.filter((name, index) => trackNames.indexOf(name) !== index);\n throw new Error(`Duplicate subscription track name: ${duplicates[0]}`);\n }\n\n const desiredTracks = new Set(configs.map(config => config.trackName));\n const currentTracks = new Set(this.subscriptions.keys());\n\n // Remove subscriptions that are no longer needed\n for (const trackName of currentTracks) {\n if (!desiredTracks.has(trackName)) {\n this._removeSubscription(trackName);\n }\n }\n\n // Add new subscriptions or update existing ones\n for (const config of configs) {\n const existing = this.subscriptions.get(config.trackName);\n if (!existing) {\n // Create new subscription\n this._createSubscription(config);\n } else {\n // Update existing subscription config if needed\n if (existing.config.priority !== config.priority || \n existing.config.retry?.delay !== config.retry?.delay) {\n // For now, we recreate if config changed\n // In future, we could support dynamic config updates\n this._removeSubscription(config.trackName);\n this._createSubscription(config);\n }\n }\n }\n }\n\n getAnnouncedBroadcasts(): string[] {\n return Array.from(this.announcedBroadcasts);\n }\n\n /**\n * Send data to a broadcast track\n * @param trackName Name of the track to send data to\n * @param data Binary data to send\n */\n async send(trackName: string, data: Uint8Array, newGroup: boolean): Promise<void> {\n const broadcast = this.broadcasts.get(trackName);\n if (!broadcast) {\n throw new Error(`No broadcast found for track: ${trackName}`);\n }\n await broadcast.send(data, newGroup);\n }\n\n /**\n * Get the status of a specific broadcast track\n * @param trackName Name of the track\n */\n getBroadcastStatus(trackName: string) {\n const broadcast = this.broadcasts.get(trackName);\n return broadcast?.status;\n }\n\n /**\n * Get the status of a specific subscription track\n * @param trackName Name of the track\n */\n getSubscriptionStatus(trackName: string) {\n const subscription = this.subscriptions.get(trackName);\n return subscription?.status;\n }\n\n private _createBroadcast(config: BroadcastConfig): MoQBroadcast {\n const broadcast = new MoQBroadcast(config);\n this.broadcasts.set(config.trackName, broadcast);\n\n // Forward broadcast events to session\n broadcast.on('stateChange', (status) => {\n this.emit('broadcastStateChange', config.trackName, status);\n });\n\n broadcast.on('error', (error) => {\n this.emit('broadcastError', config.trackName, error);\n });\n\n this.initBroadcasting();\n\n return broadcast;\n }\n\n private _createSubscription(config: SubscriptionConfig): MoQSubscription {\n const subscription = new MoQSubscription(config);\n this.subscriptions.set(config.trackName, subscription);\n\n // Forward subscription events to session\n subscription.on('data', (received) => {\n this.emit('data', received.trackName, received.data, received.frameIndex);\n });\n\n subscription.on('stateChange', (status) => {\n this.emit('subscriptionStateChange', config.trackName, status);\n });\n\n subscription.on('error', (error) => {\n this.emit('subscriptionError', config.trackName, error);\n });\n\n // Start subscription if we're connected\n if (this.state === SessionState.CONNECTED && this.connection) {\n subscription.start(this.connection, this.config.namespace).catch(error => {\n console.error('Failed to start subscription:', error);\n });\n }\n\n return subscription;\n }\n\n private _removeBroadcast(trackName: string): void {\n const broadcast = this.broadcasts.get(trackName);\n if (broadcast) {\n broadcast.stop().catch(error => {\n console.warn('Error stopping broadcast:', error);\n });\n this.broadcasts.delete(trackName);\n }\n }\n\n private _removeSubscription(trackName: string): void {\n const subscription = this.subscriptions.get(trackName);\n if (subscription) {\n subscription.stop().catch(error => {\n console.warn('Error stopping subscription:', error);\n });\n this.subscriptions.delete(trackName);\n }\n }\n\n private async startAnnouncementDiscovery(): Promise<void> {\n if (!this.connection) return;\n\n try {\n // Listen for announcements with our namespace as prefix\n const namespacePath = Path.from(this.config.namespace);\n const announced = this.connection.announced(namespacePath);\n \n // Process announcements in the background\n this.processAnnouncements(announced);\n \n } catch (error) {\n console.error('Failed to start announcement discovery:', error);\n }\n }\n\n private async processAnnouncements(announced: ReturnType<Connection.Established['announced']>): Promise<void> {\n try {\n for (;;) {\n // Stop processing if session is disposed\n if (this.disposed) break;\n \n const announcement = await announced.next();\n if (!announcement) break; // Announcements closed\n \n // Don't emit events if disposed\n if (this.disposed) break;\n \n if (announcement.active) {\n this.announcedBroadcasts.add(announcement.path);\n this.emit('broadcastAnnounced', {\n path: announcement.path,\n active: true\n });\n } else {\n this.announcedBroadcasts.delete(announcement.path);\n this.emit('broadcastAnnounced', {\n path: announcement.path,\n active: false\n });\n }\n }\n } catch (error) {\n // Don't log errors if session is disposed\n if (!this.disposed) {\n console.error('Error processing announcements:', error);\n }\n }\n }\n\n private async restartBroadcasts(): Promise<void> {\n await this.stopAllBroadcasts();\n this.initBroadcasting();\n }\n\n private initBroadcasting(): void {\n if (this.broadcast) return;\n if (this.broadcasts.size === 0) return;\n\n this.broadcast = new Broadcast();\n if (this.connection) {\n this.connection.publish(Path.from(this.config.namespace), this.broadcast);\n this.handleTrackRequests().catch(error => {\n console.error('Error handling track requests:', error);\n });\n }\n }\n\n private async handleTrackRequests(): Promise<void> {\n if (!this.broadcast) return;\n \n try {\n for (;;) {\n const request = await this.broadcast.requested();\n if (!request) return; // No more requests, broadcast closed;\n const broadcast = this.broadcasts.get(request.track.name);\n if (broadcast) {\n broadcast.updateTrack(request.track);\n this.emit('trackRequested', request.track.name);\n }\n }\n\n } catch (error) {\n console.warn('Error handling track requests:', error);\n this.handleError(error as Error);\n }\n}\n\n private async restartSubscriptions(): Promise<void> {\n if (!this.connection) return;\n\n const promises = Array.from(this.subscriptions.values()).map(subscription => \n subscription.start(this.connection!, this.config.namespace).catch(error => {\n console.error('Failed to restart subscription:', error);\n })\n );\n\n await Promise.allSettled(promises);\n }\n\n private async stopAllBroadcasts(): Promise<void> {\n this.broadcast?.close();\n this.broadcast = undefined;\n const promises = Array.from(this.broadcasts.values()).map(broadcast => \n broadcast.stop().catch(error => {\n console.warn('Error stopping broadcast:', error);\n })\n );\n\n await Promise.allSettled(promises);\n }\n\n private async stopAllSubscriptions(): Promise<void> {\n const promises = Array.from(this.subscriptions.values()).map(subscription => \n subscription.stop().catch(error => {\n console.warn('Error stopping subscription:', error);\n })\n );\n\n await Promise.allSettled(promises);\n }\n\n private handleDisconnection(): void {\n if (this.disposed) return; // Don't reconnect if disposed\n this.setState(SessionState.DISCONNECTED);\n this.scheduleReconnect();\n }\n\n private scheduleReconnect(): void {\n if (this.disposed || !this.config.reconnection || !this.doReconnect) return;\n\n const delay = this.config.reconnection?.delay || 1000;\n\n this.setState(SessionState.RECONNECTING);\n this.reconnectAttempts++;\n\n this.reconnectTimer = setTimeout(() => {\n if (this.disposed || !this.doReconnect) return;\n if (this.state !== SessionState.RECONNECTING) return;\n this.connect().catch(error => {\n console.error('Reconnection failed:', error);\n });\n }, delay);\n }\n\n private setState(newState: SessionState): void {\n if (this.disposed) return; // Don't change state if disposed\n if (this.state !== newState) {\n this.state = newState;\n this.emit('stateChange', this.status);\n }\n }\n\n private handleError(error: Error): void {\n if (this.disposed) return; // Don't emit errors if disposed\n this.lastError = error;\n this.emit('error', error);\n }\n\n public dispose(): void {\n // Mark as disposed to prevent any further operations\n this.disposed = true;\n \n // Immediately stop reconnection attempts\n this.doReconnect = false;\n \n // Clear any pending reconnect timer immediately\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = undefined;\n }\n \n // Disconnect (but don't await to keep dispose synchronous)\n this.disconnect().catch((error) => {\n console.warn('Error during session disconnect:', error);\n });\n this.removeAllListeners();\n\n this.subscriptions.forEach(sub => sub.dispose());\n this.broadcasts.forEach(bc => bc.dispose());\n this.subscriptions.clear();\n this.broadcasts.clear();\n }\n}"],"names":["EventEmitter","event","listener","eventListeners","args","error","SessionState","BroadcastState","SubscriptionState","MoQBroadcast","config","track","data","newGroup","newState","MoQSubscription","connection","namespace","broadcastPath","Path","framesInGroup","group","frame","receivedData","delay","_a","MoQSession","Connection","err","configs","trackNames","uniqueTrackNames","duplicates","name","index","desiredTracks","currentTracks","trackName","existing","_b","broadcast","subscription","status","received","namespacePath","announced","announcement","Broadcast","request","promises","sub","bc"],"mappings":"8IAEO,MAAMA,CAAiE,CAAvE,aAAA,CACL,KAAQ,cAAgB,GAA8B,CAEtD,GAAsBC,EAAUC,EAAsB,CAC/C,KAAK,UAAU,IAAID,CAAK,GAC3B,KAAK,UAAU,IAAIA,EAAO,IAAI,GAAK,EAErC,KAAK,UAAU,IAAIA,CAAK,EAAG,IAAIC,CAAQ,CACzC,CAEA,IAAuBD,EAAUC,EAAsB,CACrD,MAAMC,EAAiB,KAAK,UAAU,IAAIF,CAAK,EAC3CE,GACFA,EAAe,OAAOD,CAAQ,CAElC,CAEA,KAAwBD,KAAaG,EAA8B,CACjE,MAAMD,EAAiB,KAAK,UAAU,IAAIF,CAAK,EAC3CE,GACFA,EAAe,QAAQD,GAAY,CACjC,GAAI,CACFA,EAAS,GAAGE,CAAI,CAClB,OAASC,EAAO,CACd,QAAQ,MAAM,2BAA4BA,CAAK,CACjD,CACF,CAAC,CAEL,CAEA,mBAAsCJ,EAAiB,CACjDA,EACF,KAAK,UAAU,OAAOA,CAAK,EAE3B,KAAK,UAAU,MAAA,CAEnB,CACF,CCLO,IAAKK,GAAAA,IACVA,EAAA,aAAe,eACfA,EAAA,WAAa,aACbA,EAAA,UAAY,YACZA,EAAA,aAAe,eACfA,EAAA,OAAS,SALCA,IAAAA,GAAA,CAAA,CAAA,EAQAC,GAAAA,IACVA,EAAA,KAAO,OACPA,EAAA,aAAe,eACfA,EAAA,MAAQ,QAHEA,IAAAA,GAAA,CAAA,CAAA,EAMAC,GAAAA,IACVA,EAAA,QAAU,UACVA,EAAA,WAAa,aACbA,EAAA,SAAW,WACXA,EAAA,OAAS,SAJCA,IAAAA,GAAA,CAAA,CAAA,ECvCL,MAAMC,UAAqBT,CAA8B,CAQ9D,YAAYU,EAAyB,CACnC,MAAA,EAPF,KAAQ,MAAwBH,EAAe,KAC/C,KAAQ,UAAY,EAOlB,KAAK,QAAUG,CACjB,CAEA,IAAI,QAA0B,CAC5B,MAAO,CACL,MAAO,KAAK,MACZ,UAAW,KAAK,QAAQ,UACxB,UAAW,KAAK,UAChB,UAAW,KAAK,SAAA,CAEpB,CAEA,IAAI,QAA0B,CAC5B,MAAO,CAAE,GAAG,KAAK,OAAA,CACnB,CAEA,YAAYC,EAAoB,CAC9B,KAAK,MAAQA,EACTA,GACF,KAAK,SAASJ,EAAe,YAAY,CAE7C,CAEA,MAAM,KAAKK,EAAkBC,EAAkC,CAC7D,GAAI,KAAK,QAAUN,EAAe,cAAgB,CAAC,KAAK,MACtD,MAAM,IAAI,MAAM,yBAAyB,EAG3C,GAAI,EACEM,GAAY,CAAC,KAAK,SAChB,KAAK,OACP,KAAK,MAAM,MAAA,EAEb,KAAK,MAAQ,KAAK,MAAM,YAAA,GAE1B,MAAM,KAAK,MAAM,WAAWD,CAAI,EAChC,KAAK,WAAaA,EAAK,MACzB,OAASP,EAAO,CACd,WAAK,YAAYA,CAAc,EACzBA,CACR,CACF,CAEA,MAAM,MAAsB,CAC1B,GAAI,KAAK,MAAO,CACd,GAAI,CACF,KAAK,MAAM,MAAA,CACb,OAASA,EAAO,CACd,QAAQ,KAAK,uBAAwBA,CAAK,CAC5C,CACA,KAAK,MAAQ,MACf,CAEA,KAAK,SAASE,EAAe,IAAI,CACnC,CAEQ,SAASO,EAAgC,CAC3C,KAAK,QAAUA,IACjB,KAAK,MAAQA,EACb,KAAK,KAAK,cAAe,KAAK,MAAM,EAExC,CAEQ,YAAYT,EAAoB,CACtC,KAAK,UAAYA,EACjB,KAAK,SAASE,EAAe,KAAK,EAClC,KAAK,KAAK,QAASF,CAAK,CAC1B,CAEO,SAAgB,CACrB,KAAK,KAAA,EAAO,MAAM,QAAQ,KAAK,EAC/B,KAAK,mBAAA,CACP,CACF,CClFO,MAAMU,UAAwBf,CAAiC,CAYpE,YAAYU,EAA4B,CACtC,MAAA,EAXF,KAAQ,MAA2BF,EAAkB,QACrD,KAAQ,cAAgB,EACxB,KAAQ,cAAgB,EAUtB,KAAK,QAAUE,CACjB,CAEA,IAAI,QAA6B,CAC/B,MAAO,CACL,MAAO,KAAK,MACZ,UAAW,KAAK,QAAQ,UACxB,cAAe,KAAK,cACpB,cAAe,KAAK,cACpB,UAAW,KAAK,SAAA,CAEpB,CAEA,IAAI,QAA6B,CAC/B,MAAO,CAAE,GAAG,KAAK,OAAA,CACnB,CAEA,MAAM,MAAMM,EAAoCC,EAAkC,CAChF,KAAK,WAAaD,EAClB,KAAK,UAAYC,EACjB,GAAI,CACF,MAAM,KAAK,UAAUD,EAAYC,CAAS,CAC5C,OAASZ,EAAO,CACd,KAAK,YAAYA,CAAc,EAC/B,KAAK,cAAcW,EAAYC,CAAS,CAC1C,CACF,CAEA,MAAc,UAAUD,EAAoCC,EAAkC,CAC5F,KAAK,SAAST,EAAkB,OAAO,EAEvC,MAAMU,EAAgBC,EAAAA,KAAK,KAAKF,CAAS,EACzC,KAAK,UAAYD,EAAW,QAAQE,CAAa,EAGjD,KAAK,aAAe,KAAK,UAAU,UAAU,KAAK,QAAQ,UAAW,KAAK,QAAQ,UAAY,CAAC,EAC/F,KAAK,SAASV,EAAkB,UAAU,EAC1C,KAAK,cAAgB,EAGrB,KAAK,WAAA,CACP,CAEA,MAAc,YAA4B,CACxC,GAAK,KAAK,aAEV,GAAI,CAEF,OAAa,CACX,IAAIY,EAAgB,EACpB,MAAMC,EAAQ,MAAM,KAAK,aAAa,UAAA,EACtC,GAAI,CAACA,EAAO,MAIZ,OAAa,CACX,MAAMC,EAAQ,MAAMD,EAAM,UAAA,EAC1B,GAAI,CAACC,EAAO,MACZF,IAEA,KAAK,eAAiBE,EAAM,OAC5B,MAAMC,EAA6B,CACjC,UAAW,KAAK,QAAQ,UACxB,KAAMD,EACN,UAAW,KAAK,IAAA,EAChB,WAAYF,CAAA,EAEd,KAAK,KAAK,OAAQG,CAAY,CAChC,CACF,CACF,OAASlB,EAAO,CACd,KAAK,YAAYA,CAAc,EAE3B,KAAK,YAAc,KAAK,WAC1B,KAAK,cAAc,KAAK,WAAY,KAAK,SAAS,CAEtD,CACF,CAEQ,cAAcW,EAAoCC,EAAyB,OACjF,MAAMO,IAAQC,EAAA,KAAK,QAAQ,QAAb,YAAAA,EAAoB,QAAS,IAE3C,KAAK,SAASjB,EAAkB,QAAQ,EACxC,KAAK,gBAEL,KAAK,WAAa,WAAW,SAAY,CACvC,GAAI,CACF,MAAM,KAAK,UAAUQ,EAAYC,CAAS,CAC5C,OAASZ,EAAO,CACd,KAAK,YAAYA,CAAc,EAC/B,KAAK,cAAcW,EAAYC,CAAS,CAC1C,CACF,EAAGO,CAAK,CACV,CAEA,MAAM,MAAsB,CAS1B,GARA,KAAK,WAAa,OAClB,KAAK,UAAY,OAEb,KAAK,aACP,aAAa,KAAK,UAAU,EAC5B,KAAK,WAAa,QAGhB,KAAK,aAAc,CACrB,GAAI,CACF,KAAK,aAAa,MAAA,CACpB,OAASnB,EAAO,CACd,QAAQ,KAAK,8BAA+BA,CAAK,CACnD,CACA,KAAK,aAAe,MACtB,CAEA,GAAI,KAAK,UAAW,CAClB,GAAI,CACF,KAAK,UAAU,MAAA,CACjB,OAASA,EAAO,CACd,QAAQ,KAAK,2BAA4BA,CAAK,CAChD,CACA,KAAK,UAAY,MACnB,CAEA,KAAK,SAASG,EAAkB,OAAO,CACzC,CAEQ,SAASM,EAAmC,CAC9C,KAAK,QAAUA,IACjB,KAAK,MAAQA,EACb,KAAK,KAAK,cAAe,KAAK,MAAM,EAExC,CAEQ,YAAYT,EAAoB,CACtC,KAAK,UAAYA,EACjB,KAAK,KAAK,QAASA,CAAK,CAC1B,CAEA,SAAgB,CACd,KAAK,KAAA,EAAO,MAAOA,GAAU,CAC3B,QAAQ,KAAK,wBAAyBA,CAAK,CAC7C,CAAC,EACD,KAAK,mBAAA,CACP,CACF,CC1JO,MAAMqB,UAAmB1B,CAA4B,CAgB1D,YAAYU,EAA0B,OACpC,MAAA,EAdF,KAAQ,MAAsBJ,EAAa,aAE3C,KAAQ,kBAAoB,EAI5B,KAAQ,eAAiB,IACzB,KAAQ,kBAAoB,IAC5B,KAAQ,wBAA0B,IAClC,KAAQ,YAAc,GAEtB,KAAQ,SAAW,GAIjB,KAAK,OAAS,CACZ,GAAGI,EACH,aAAc,CACZ,MAAO,KAAK,MAAIe,EAAAf,EAAO,eAAP,YAAAe,EAAqB,QAAS,IAAM,GAAI,CAAA,EAE1D,kBAAmBf,EAAO,mBAAqB,GAAA,EAGjD,KAAK,IAAM,IAAI,IAAI,KAAK,OAAO,QAAQ,CACzC,CAEA,IAAI,QAAwB,CAC1B,MAAO,CACL,MAAO,KAAK,MACZ,kBAAmB,KAAK,kBACxB,UAAW,KAAK,UAChB,YAAa,KAAK,WAAA,CAEtB,CAEA,MAAM,SAAyB,CAC7B,GAAI,KAAK,SACP,MAAM,IAAI,MAAM,mCAAmC,EAGrD,GAAI,OAAK,QAAUJ,EAAa,YAAc,KAAK,QAAUA,EAAa,WAI1E,MAAK,SAASA,EAAa,UAAU,EAErC,GAAI,CACF,KAAK,YAAc,GACnB,KAAK,WAAa,MAAMqB,EAAAA,WAAW,QAAQ,KAAK,IAAK,CACnD,UAAW,CACT,QAAS,EAAA,CACX,CACD,EAED,KAAK,SAASrB,EAAa,SAAS,EACpC,KAAK,gBAAkB,KACvB,KAAK,kBAAoB,EAGzB,KAAK,WAAW,OAAO,KAAK,IAAM,CAE5B,CAAC,KAAK,UAAY,KAAK,QAAUA,EAAa,WAChD,KAAK,oBAAA,CAET,CAAC,EAGD,KAAK,2BAAA,EAGL,MAAM,KAAK,kBAAA,EACX,MAAM,KAAK,qBAAA,CAEb,OAASD,EAAO,CACd,MAAMuB,EAAM,IAAI,MAAM,+BAAgCvB,EAAgB,OAAO,EAAE,EAC/E,WAAK,YAAYuB,CAAG,EACpB,KAAK,kBAAA,EACCA,CACR,EACF,CAEA,MAAM,YAA4B,CAYhC,GAXA,KAAK,YAAc,GAEf,KAAK,iBACP,aAAa,KAAK,cAAc,EAChC,KAAK,eAAiB,QAIxB,MAAM,KAAK,kBAAA,EACX,MAAM,KAAK,qBAAA,EAEP,KAAK,WAAY,CACnB,GAAI,CACF,KAAK,WAAW,MAAA,CAClB,OAASvB,EAAO,CACd,QAAQ,KAAK,4BAA6BA,CAAK,CACjD,CACA,KAAK,WAAa,MACpB,CAEA,KAAK,SAASC,EAAa,YAAY,EACvC,KAAK,YAAc,MACrB,CAKA,2BAAsC,CACpC,OAAO,MAAM,KAAK,KAAK,WAAW,MAAM,CAC1C,CAKA,8BAAyC,CACvC,OAAO,MAAM,KAAK,KAAK,cAAc,MAAM,CAC7C,CAOA,iBAAiBuB,EAAkC,CAEjD,MAAMC,EAAaD,EAAQ,IAAInB,GAAUA,EAAO,SAAS,EACnDqB,EAAmB,IAAI,IAAID,CAAU,EAC3C,GAAIA,EAAW,SAAWC,EAAiB,KAAM,CAC/C,MAAMC,EAAaF,EAAW,OAAO,CAACG,EAAMC,IAAUJ,EAAW,QAAQG,CAAI,IAAMC,CAAK,EACxF,MAAM,IAAI,MAAM,mCAAmCF,EAAW,CAAC,CAAC,EAAE,CACpE,CAEA,MAAMG,EAAgB,IAAI,IAAIN,EAAQ,IAAInB,GAAUA,EAAO,SAAS,CAAC,EAC/D0B,EAAgB,IAAI,IAAI,KAAK,WAAW,MAAM,EAGpD,UAAWC,KAAaD,EACjBD,EAAc,IAAIE,CAAS,GAC9B,KAAK,iBAAiBA,CAAS,EAKnC,UAAW3B,KAAUmB,EAAS,CAC5B,MAAMS,EAAW,KAAK,WAAW,IAAI5B,EAAO,SAAS,EAChD4B,EAKCA,EAAS,OAAO,WAAa5B,EAAO,WAGtC,KAAK,iBAAiBA,EAAO,SAAS,EACtC,KAAK,iBAAiBA,CAAM,GAP9B,KAAK,iBAAiBA,CAAM,CAUhC,CACF,CAOA,oBAAoBmB,EAAqC,SAEvD,MAAMC,EAAaD,EAAQ,IAAInB,GAAUA,EAAO,SAAS,EACnDqB,EAAmB,IAAI,IAAID,CAAU,EAC3C,GAAIA,EAAW,SAAWC,EAAiB,KAAM,CAC/C,MAAMC,EAAaF,EAAW,OAAO,CAACG,EAAMC,IAAUJ,EAAW,QAAQG,CAAI,IAAMC,CAAK,EACxF,MAAM,IAAI,MAAM,sCAAsCF,EAAW,CAAC,CAAC,EAAE,CACvE,CAEA,MAAMG,EAAgB,IAAI,IAAIN,EAAQ,IAAInB,GAAUA,EAAO,SAAS,CAAC,EAC/D0B,EAAgB,IAAI,IAAI,KAAK,cAAc,MAAM,EAGvD,UAAWC,KAAaD,EACjBD,EAAc,IAAIE,CAAS,GAC9B,KAAK,oBAAoBA,CAAS,EAKtC,UAAW3B,KAAUmB,EAAS,CAC5B,MAAMS,EAAW,KAAK,cAAc,IAAI5B,EAAO,SAAS,EACnD4B,GAKCA,EAAS,OAAO,WAAa5B,EAAO,YACpCe,EAAAa,EAAS,OAAO,QAAhB,YAAAb,EAAuB,WAAUc,EAAA7B,EAAO,QAAP,YAAA6B,EAAc,UAGjD,KAAK,oBAAoB7B,EAAO,SAAS,EACzC,KAAK,oBAAoBA,CAAM,GARjC,KAAK,oBAAoBA,CAAM,CAWnC,CACF,CAEA,wBAAmC,CACjC,OAAO,MAAM,KAAK,KAAK,mBAAmB,CAC5C,CAOA,MAAM,KAAK2B,EAAmBzB,EAAkBC,EAAkC,CAChF,MAAM2B,EAAY,KAAK,WAAW,IAAIH,CAAS,EAC/C,GAAI,CAACG,EACH,MAAM,IAAI,MAAM,iCAAiCH,CAAS,EAAE,EAE9D,MAAMG,EAAU,KAAK5B,EAAMC,CAAQ,CACrC,CAMA,mBAAmBwB,EAAmB,CACpC,MAAMG,EAAY,KAAK,WAAW,IAAIH,CAAS,EAC/C,OAAOG,GAAA,YAAAA,EAAW,MACpB,CAMA,sBAAsBH,EAAmB,CACvC,MAAMI,EAAe,KAAK,cAAc,IAAIJ,CAAS,EACrD,OAAOI,GAAA,YAAAA,EAAc,MACvB,CAEQ,iBAAiB/B,EAAuC,CAC9D,MAAM8B,EAAY,IAAI/B,EAAaC,CAAM,EACzC,YAAK,WAAW,IAAIA,EAAO,UAAW8B,CAAS,EAG/CA,EAAU,GAAG,cAAgBE,GAAW,CACtC,KAAK,KAAK,uBAAwBhC,EAAO,UAAWgC,CAAM,CAC5D,CAAC,EAEDF,EAAU,GAAG,QAAUnC,GAAU,CAC/B,KAAK,KAAK,iBAAkBK,EAAO,UAAWL,CAAK,CACrD,CAAC,EAED,KAAK,iBAAA,EAEEmC,CACT,CAEQ,oBAAoB9B,EAA6C,CACvE,MAAM+B,EAAe,IAAI1B,EAAgBL,CAAM,EAC/C,YAAK,cAAc,IAAIA,EAAO,UAAW+B,CAAY,EAGrDA,EAAa,GAAG,OAASE,GAAa,CACpC,KAAK,KAAK,OAAQA,EAAS,UAAWA,EAAS,KAAMA,EAAS,UAAU,CAC1E,CAAC,EAEDF,EAAa,GAAG,cAAgBC,GAAW,CACzC,KAAK,KAAK,0BAA2BhC,EAAO,UAAWgC,CAAM,CAC/D,CAAC,EAEDD,EAAa,GAAG,QAAUpC,GAAU,CAClC,KAAK,KAAK,oBAAqBK,EAAO,UAAWL,CAAK,CACxD,CAAC,EAGG,KAAK,QAAUC,EAAa,WAAa,KAAK,YAChDmC,EAAa,MAAM,KAAK,WAAY,KAAK,OAAO,SAAS,EAAE,MAAMpC,GAAS,CACxE,QAAQ,MAAM,gCAAiCA,CAAK,CACtD,CAAC,EAGIoC,CACT,CAEQ,iBAAiBJ,EAAyB,CAChD,MAAMG,EAAY,KAAK,WAAW,IAAIH,CAAS,EAC3CG,IACFA,EAAU,KAAA,EAAO,MAAMnC,GAAS,CAC9B,QAAQ,KAAK,4BAA6BA,CAAK,CACjD,CAAC,EACD,KAAK,WAAW,OAAOgC,CAAS,EAEpC,CAEQ,oBAAoBA,EAAyB,CACnD,MAAMI,EAAe,KAAK,cAAc,IAAIJ,CAAS,EACjDI,IACFA,EAAa,KAAA,EAAO,MAAMpC,GAAS,CACjC,QAAQ,KAAK,+BAAgCA,CAAK,CACpD,CAAC,EACD,KAAK,cAAc,OAAOgC,CAAS,EAEvC,CAEA,MAAc,4BAA4C,CACxD,GAAK,KAAK,WAEV,GAAI,CAEF,MAAMO,EAAgBzB,EAAAA,KAAK,KAAK,KAAK,OAAO,SAAS,EAC/C0B,EAAY,KAAK,WAAW,UAAUD,CAAa,EAGzD,KAAK,qBAAqBC,CAAS,CAErC,OAASxC,EAAO,CACd,QAAQ,MAAM,0CAA2CA,CAAK,CAChE,CACF,CAEA,MAAc,qBAAqBwC,EAA2E,CAC5G,GAAI,CACF,KAEM,MAAK,UAFF,CAIP,MAAMC,EAAe,MAAMD,EAAU,KAAA,EAIrC,GAHI,CAACC,GAGD,KAAK,SAAU,MAEfA,EAAa,QACf,KAAK,oBAAoB,IAAIA,EAAa,IAAI,EAC9C,KAAK,KAAK,qBAAsB,CAC9B,KAAMA,EAAa,KACnB,OAAQ,EAAA,CACT,IAED,KAAK,oBAAoB,OAAOA,EAAa,IAAI,EACjD,KAAK,KAAK,qBAAsB,CAC9B,KAAMA,EAAa,KACnB,OAAQ,EAAA,CACT,EAEL,CACF,OAASzC,EAAO,CAET,KAAK,UACR,QAAQ,MAAM,kCAAmCA,CAAK,CAE1D,CACF,CAEA,MAAc,mBAAmC,CAC/C,MAAM,KAAK,kBAAA,EACX,KAAK,iBAAA,CACP,CAEQ,kBAAyB,CAC3B,KAAK,WACL,KAAK,WAAW,OAAS,IAE7B,KAAK,UAAY,IAAI0C,YACjB,KAAK,aACP,KAAK,WAAW,QAAQ5B,EAAAA,KAAK,KAAK,KAAK,OAAO,SAAS,EAAG,KAAK,SAAS,EACxE,KAAK,oBAAA,EAAsB,MAAMd,GAAS,CACxC,QAAQ,MAAM,iCAAkCA,CAAK,CACvD,CAAC,GAEL,CAEA,MAAc,qBAAqC,CACnD,GAAK,KAAK,UAEV,GAAI,CACF,OAAS,CACP,MAAM2C,EAAU,MAAM,KAAK,UAAU,UAAA,EACrC,GAAI,CAACA,EAAS,OACd,MAAMR,EAAY,KAAK,WAAW,IAAIQ,EAAQ,MAAM,IAAI,EACpDR,IACFA,EAAU,YAAYQ,EAAQ,KAAK,EACnC,KAAK,KAAK,iBAAkBA,EAAQ,MAAM,IAAI,EAElD,CAEF,OAAS3C,EAAO,CACd,QAAQ,KAAK,iCAAkCA,CAAK,EACpD,KAAK,YAAYA,CAAc,CACjC,CACF,CAEE,MAAc,sBAAsC,CAClD,GAAI,CAAC,KAAK,WAAY,OAEtB,MAAM4C,EAAW,MAAM,KAAK,KAAK,cAAc,OAAA,CAAQ,EAAE,IAAIR,GAC3DA,EAAa,MAAM,KAAK,WAAa,KAAK,OAAO,SAAS,EAAE,MAAMpC,GAAS,CACzE,QAAQ,MAAM,kCAAmCA,CAAK,CACxD,CAAC,CAAA,EAGH,MAAM,QAAQ,WAAW4C,CAAQ,CACnC,CAEA,MAAc,mBAAmC,QAC/CxB,EAAA,KAAK,YAAL,MAAAA,EAAgB,QAChB,KAAK,UAAY,OACjB,MAAMwB,EAAW,MAAM,KAAK,KAAK,WAAW,OAAA,CAAQ,EAAE,IAAIT,GACxDA,EAAU,KAAA,EAAO,MAAMnC,GAAS,CAC9B,QAAQ,KAAK,4BAA6BA,CAAK,CACjD,CAAC,CAAA,EAGH,MAAM,QAAQ,WAAW4C,CAAQ,CACnC,CAEA,MAAc,sBAAsC,CAClD,MAAMA,EAAW,MAAM,KAAK,KAAK,cAAc,OAAA,CAAQ,EAAE,IAAIR,GAC3DA,EAAa,KAAA,EAAO,MAAMpC,GAAS,CACjC,QAAQ,KAAK,+BAAgCA,CAAK,CACpD,CAAC,CAAA,EAGH,MAAM,QAAQ,WAAW4C,CAAQ,CACnC,CAEQ,qBAA4B,CAC9B,KAAK,WACT,KAAK,SAAS3C,EAAa,YAAY,EACvC,KAAK,kBAAA,EACP,CAEQ,mBAA0B,OAChC,GAAI,KAAK,UAAY,CAAC,KAAK,OAAO,cAAgB,CAAC,KAAK,YAAa,OAErE,MAAMkB,IAAQC,EAAA,KAAK,OAAO,eAAZ,YAAAA,EAA0B,QAAS,IAEjD,KAAK,SAASnB,EAAa,YAAY,EACvC,KAAK,oBAEL,KAAK,eAAiB,WAAW,IAAM,CACjC,KAAK,UAAY,CAAC,KAAK,aACvB,KAAK,QAAUA,EAAa,cAChC,KAAK,QAAA,EAAU,MAAMD,GAAS,CAC5B,QAAQ,MAAM,uBAAwBA,CAAK,CAC7C,CAAC,CACH,EAAGmB,CAAK,CACV,CAEQ,SAASV,EAA8B,CACzC,KAAK,UACL,KAAK,QAAUA,IACjB,KAAK,MAAQA,EACb,KAAK,KAAK,cAAe,KAAK,MAAM,EAExC,CAEQ,YAAYT,EAAoB,CAClC,KAAK,WACT,KAAK,UAAYA,EACjB,KAAK,KAAK,QAASA,CAAK,EAC1B,CAEO,SAAgB,CAErB,KAAK,SAAW,GAGhB,KAAK,YAAc,GAGf,KAAK,iBACP,aAAa,KAAK,cAAc,EAChC,KAAK,eAAiB,QAIxB,KAAK,WAAA,EAAa,MAAOA,GAAU,CACjC,QAAQ,KAAK,mCAAoCA,CAAK,CACxD,CAAC,EACD,KAAK,mBAAA,EAEL,KAAK,cAAc,QAAQ6C,GAAOA,EAAI,SAAS,EAC/C,KAAK,WAAW,QAAQC,GAAMA,EAAG,SAAS,EAC1C,KAAK,cAAc,MAAA,EACnB,KAAK,WAAW,MAAA,CAClB,CACF"}
|
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Path as
|
|
2
|
-
class
|
|
1
|
+
import { Path as p, Connection as b, Broadcast as E } from "@kixelated/moq";
|
|
2
|
+
class m {
|
|
3
3
|
constructor() {
|
|
4
4
|
this.listeners = /* @__PURE__ */ new Map();
|
|
5
5
|
}
|
|
@@ -15,8 +15,8 @@ class p {
|
|
|
15
15
|
e && e.forEach((o) => {
|
|
16
16
|
try {
|
|
17
17
|
o(...s);
|
|
18
|
-
} catch (
|
|
19
|
-
console.error("Error in event listener:",
|
|
18
|
+
} catch (c) {
|
|
19
|
+
console.error("Error in event listener:", c);
|
|
20
20
|
}
|
|
21
21
|
});
|
|
22
22
|
}
|
|
@@ -24,8 +24,8 @@ class p {
|
|
|
24
24
|
t ? this.listeners.delete(t) : this.listeners.clear();
|
|
25
25
|
}
|
|
26
26
|
}
|
|
27
|
-
var
|
|
28
|
-
class y extends
|
|
27
|
+
var n = /* @__PURE__ */ ((r) => (r.DISCONNECTED = "disconnected", r.CONNECTING = "connecting", r.CONNECTED = "connected", r.RECONNECTING = "reconnecting", r.FAILED = "failed", r))(n || {}), d = /* @__PURE__ */ ((r) => (r.IDLE = "idle", r.BROADCASTING = "broadcasting", r.ERROR = "error", r))(d || {}), u = /* @__PURE__ */ ((r) => (r.PENDING = "pending", r.SUBSCRIBED = "subscribed", r.RETRYING = "retrying", r.FAILED = "failed", r))(u || {});
|
|
28
|
+
class y extends m {
|
|
29
29
|
constructor(t) {
|
|
30
30
|
super(), this.state = d.IDLE, this.bytesSent = 0, this._config = t;
|
|
31
31
|
}
|
|
@@ -73,9 +73,9 @@ class y extends p {
|
|
|
73
73
|
this.stop().catch(console.error), this.removeAllListeners();
|
|
74
74
|
}
|
|
75
75
|
}
|
|
76
|
-
class N extends
|
|
76
|
+
class N extends m {
|
|
77
77
|
constructor(t) {
|
|
78
|
-
super(), this.state =
|
|
78
|
+
super(), this.state = u.PENDING, this.bytesReceived = 0, this.retryAttempts = 0, this._config = t;
|
|
79
79
|
}
|
|
80
80
|
get status() {
|
|
81
81
|
return {
|
|
@@ -98,9 +98,9 @@ class N extends p {
|
|
|
98
98
|
}
|
|
99
99
|
}
|
|
100
100
|
async subscribe(t, s) {
|
|
101
|
-
this.setState(
|
|
102
|
-
const e =
|
|
103
|
-
this.broadcast = t.consume(e), this.subscription = this.broadcast.subscribe(this._config.trackName, this._config.priority || 0), this.setState(
|
|
101
|
+
this.setState(u.PENDING);
|
|
102
|
+
const e = p.from(s);
|
|
103
|
+
this.broadcast = t.consume(e), this.subscription = this.broadcast.subscribe(this._config.trackName, this._config.priority || 0), this.setState(u.SUBSCRIBED), this.retryAttempts = 0, this.readFrames();
|
|
104
104
|
}
|
|
105
105
|
async readFrames() {
|
|
106
106
|
if (this.subscription)
|
|
@@ -129,11 +129,11 @@ class N extends p {
|
|
|
129
129
|
scheduleRetry(t, s) {
|
|
130
130
|
var o;
|
|
131
131
|
const e = ((o = this._config.retry) == null ? void 0 : o.delay) || 2e3;
|
|
132
|
-
this.setState(
|
|
132
|
+
this.setState(u.RETRYING), this.retryAttempts++, this.retryTimer = setTimeout(async () => {
|
|
133
133
|
try {
|
|
134
134
|
await this.subscribe(t, s);
|
|
135
|
-
} catch (
|
|
136
|
-
this.handleError(
|
|
135
|
+
} catch (c) {
|
|
136
|
+
this.handleError(c), this.scheduleRetry(t, s);
|
|
137
137
|
}
|
|
138
138
|
}, e);
|
|
139
139
|
}
|
|
@@ -154,7 +154,7 @@ class N extends p {
|
|
|
154
154
|
}
|
|
155
155
|
this.broadcast = void 0;
|
|
156
156
|
}
|
|
157
|
-
this.setState(
|
|
157
|
+
this.setState(u.PENDING);
|
|
158
158
|
}
|
|
159
159
|
setState(t) {
|
|
160
160
|
this.state !== t && (this.state = t, this.emit("stateChange", this.status));
|
|
@@ -168,10 +168,10 @@ class N extends p {
|
|
|
168
168
|
}), this.removeAllListeners();
|
|
169
169
|
}
|
|
170
170
|
}
|
|
171
|
-
class k extends
|
|
171
|
+
class k extends m {
|
|
172
172
|
constructor(t) {
|
|
173
173
|
var s;
|
|
174
|
-
super(), this.state =
|
|
174
|
+
super(), this.state = n.DISCONNECTED, this.reconnectAttempts = 0, this.broadcasts = /* @__PURE__ */ new Map(), this.subscriptions = /* @__PURE__ */ new Map(), this.announcedBroadcasts = /* @__PURE__ */ new Set(), this.doReconnect = !0, this.disposed = !1, this.config = {
|
|
175
175
|
...t,
|
|
176
176
|
reconnection: {
|
|
177
177
|
delay: Math.max(((s = t.reconnection) == null ? void 0 : s.delay) || 1e3, 1e3)
|
|
@@ -189,18 +189,21 @@ class k extends p {
|
|
|
189
189
|
};
|
|
190
190
|
}
|
|
191
191
|
async connect() {
|
|
192
|
-
if (
|
|
193
|
-
|
|
192
|
+
if (this.disposed)
|
|
193
|
+
throw new Error("Cannot connect a disposed session");
|
|
194
|
+
if (!(this.state === n.CONNECTING || this.state === n.CONNECTED)) {
|
|
195
|
+
this.setState(n.CONNECTING);
|
|
194
196
|
try {
|
|
195
197
|
this.doReconnect = !0, this.connection = await b.connect(this.url, {
|
|
196
198
|
websocket: {
|
|
197
199
|
enabled: !1
|
|
198
200
|
}
|
|
199
|
-
}), this.setState(
|
|
200
|
-
this.state ===
|
|
201
|
+
}), this.setState(n.CONNECTED), this.connectedAt = /* @__PURE__ */ new Date(), this.reconnectAttempts = 0, this.connection.closed.then(() => {
|
|
202
|
+
!this.disposed && this.state === n.CONNECTED && this.handleDisconnection();
|
|
201
203
|
}), this.startAnnouncementDiscovery(), await this.restartBroadcasts(), await this.restartSubscriptions();
|
|
202
204
|
} catch (t) {
|
|
203
|
-
|
|
205
|
+
const s = new Error(`Failed to connect to relay: ${t.message}`);
|
|
206
|
+
throw this.handleError(s), this.scheduleReconnect(), s;
|
|
204
207
|
}
|
|
205
208
|
}
|
|
206
209
|
}
|
|
@@ -213,7 +216,7 @@ class k extends p {
|
|
|
213
216
|
}
|
|
214
217
|
this.connection = void 0;
|
|
215
218
|
}
|
|
216
|
-
this.setState(
|
|
219
|
+
this.setState(n.DISCONNECTED), this.connectedAt = void 0;
|
|
217
220
|
}
|
|
218
221
|
/**
|
|
219
222
|
* Get all active broadcast track names
|
|
@@ -238,8 +241,8 @@ class k extends p {
|
|
|
238
241
|
const i = s.filter((h, a) => s.indexOf(h) !== a);
|
|
239
242
|
throw new Error(`Duplicate broadcast track name: ${i[0]}`);
|
|
240
243
|
}
|
|
241
|
-
const o = new Set(t.map((i) => i.trackName)),
|
|
242
|
-
for (const i of
|
|
244
|
+
const o = new Set(t.map((i) => i.trackName)), c = new Set(this.broadcasts.keys());
|
|
245
|
+
for (const i of c)
|
|
243
246
|
o.has(i) || this._removeBroadcast(i);
|
|
244
247
|
for (const i of t) {
|
|
245
248
|
const h = this.broadcasts.get(i.trackName);
|
|
@@ -255,15 +258,15 @@ class k extends p {
|
|
|
255
258
|
var i, h;
|
|
256
259
|
const s = t.map((a) => a.trackName), e = new Set(s);
|
|
257
260
|
if (s.length !== e.size) {
|
|
258
|
-
const a = s.filter((
|
|
261
|
+
const a = s.filter((l, f) => s.indexOf(l) !== f);
|
|
259
262
|
throw new Error(`Duplicate subscription track name: ${a[0]}`);
|
|
260
263
|
}
|
|
261
|
-
const o = new Set(t.map((a) => a.trackName)),
|
|
262
|
-
for (const a of
|
|
264
|
+
const o = new Set(t.map((a) => a.trackName)), c = new Set(this.subscriptions.keys());
|
|
265
|
+
for (const a of c)
|
|
263
266
|
o.has(a) || this._removeSubscription(a);
|
|
264
267
|
for (const a of t) {
|
|
265
|
-
const
|
|
266
|
-
|
|
268
|
+
const l = this.subscriptions.get(a.trackName);
|
|
269
|
+
l ? (l.config.priority !== a.priority || ((i = l.config.retry) == null ? void 0 : i.delay) !== ((h = a.retry) == null ? void 0 : h.delay)) && (this._removeSubscription(a.trackName), this._createSubscription(a)) : this._createSubscription(a);
|
|
267
270
|
}
|
|
268
271
|
}
|
|
269
272
|
getAnnouncedBroadcasts() {
|
|
@@ -312,7 +315,7 @@ class k extends p {
|
|
|
312
315
|
this.emit("subscriptionStateChange", t.trackName, e);
|
|
313
316
|
}), s.on("error", (e) => {
|
|
314
317
|
this.emit("subscriptionError", t.trackName, e);
|
|
315
|
-
}), this.state ===
|
|
318
|
+
}), this.state === n.CONNECTED && this.connection && s.start(this.connection, this.config.namespace).catch((e) => {
|
|
316
319
|
console.error("Failed to start subscription:", e);
|
|
317
320
|
}), s;
|
|
318
321
|
}
|
|
@@ -331,7 +334,7 @@ class k extends p {
|
|
|
331
334
|
async startAnnouncementDiscovery() {
|
|
332
335
|
if (this.connection)
|
|
333
336
|
try {
|
|
334
|
-
const t =
|
|
337
|
+
const t = p.from(this.config.namespace), s = this.connection.announced(t);
|
|
335
338
|
this.processAnnouncements(s);
|
|
336
339
|
} catch (t) {
|
|
337
340
|
console.error("Failed to start announcement discovery:", t);
|
|
@@ -339,9 +342,9 @@ class k extends p {
|
|
|
339
342
|
}
|
|
340
343
|
async processAnnouncements(t) {
|
|
341
344
|
try {
|
|
342
|
-
for (; ; ) {
|
|
345
|
+
for (; !this.disposed; ) {
|
|
343
346
|
const s = await t.next();
|
|
344
|
-
if (!s) break;
|
|
347
|
+
if (!s || this.disposed) break;
|
|
345
348
|
s.active ? (this.announcedBroadcasts.add(s.path), this.emit("broadcastAnnounced", {
|
|
346
349
|
path: s.path,
|
|
347
350
|
active: !0
|
|
@@ -351,14 +354,14 @@ class k extends p {
|
|
|
351
354
|
}));
|
|
352
355
|
}
|
|
353
356
|
} catch (s) {
|
|
354
|
-
console.error("Error processing announcements:", s);
|
|
357
|
+
this.disposed || console.error("Error processing announcements:", s);
|
|
355
358
|
}
|
|
356
359
|
}
|
|
357
360
|
async restartBroadcasts() {
|
|
358
361
|
await this.stopAllBroadcasts(), this.initBroadcasting();
|
|
359
362
|
}
|
|
360
363
|
initBroadcasting() {
|
|
361
|
-
this.broadcast || this.broadcasts.size !== 0 && (this.broadcast = new E(), this.connection && (this.connection.publish(
|
|
364
|
+
this.broadcast || this.broadcasts.size !== 0 && (this.broadcast = new E(), this.connection && (this.connection.publish(p.from(this.config.namespace), this.broadcast), this.handleTrackRequests().catch((t) => {
|
|
362
365
|
console.error("Error handling track requests:", t);
|
|
363
366
|
})));
|
|
364
367
|
}
|
|
@@ -403,26 +406,26 @@ class k extends p {
|
|
|
403
406
|
await Promise.allSettled(t);
|
|
404
407
|
}
|
|
405
408
|
handleDisconnection() {
|
|
406
|
-
this.setState(
|
|
409
|
+
this.disposed || (this.setState(n.DISCONNECTED), this.scheduleReconnect());
|
|
407
410
|
}
|
|
408
411
|
scheduleReconnect() {
|
|
409
412
|
var s;
|
|
410
|
-
if (!this.config.reconnection || !this.doReconnect) return;
|
|
413
|
+
if (this.disposed || !this.config.reconnection || !this.doReconnect) return;
|
|
411
414
|
const t = ((s = this.config.reconnection) == null ? void 0 : s.delay) || 1e3;
|
|
412
|
-
this.setState(
|
|
413
|
-
this.doReconnect
|
|
415
|
+
this.setState(n.RECONNECTING), this.reconnectAttempts++, this.reconnectTimer = setTimeout(() => {
|
|
416
|
+
this.disposed || !this.doReconnect || this.state === n.RECONNECTING && this.connect().catch((e) => {
|
|
414
417
|
console.error("Reconnection failed:", e);
|
|
415
418
|
});
|
|
416
419
|
}, t);
|
|
417
420
|
}
|
|
418
421
|
setState(t) {
|
|
419
|
-
this.state !== t && (this.state = t, this.emit("stateChange", this.status));
|
|
422
|
+
this.disposed || this.state !== t && (this.state = t, this.emit("stateChange", this.status));
|
|
420
423
|
}
|
|
421
424
|
handleError(t) {
|
|
422
|
-
this.lastError = t, this.emit("error", t);
|
|
425
|
+
this.disposed || (this.lastError = t, this.emit("error", t));
|
|
423
426
|
}
|
|
424
427
|
dispose() {
|
|
425
|
-
this.doReconnect = !1, this.reconnectTimer && (clearTimeout(this.reconnectTimer), this.reconnectTimer = void 0), this.disconnect().catch((t) => {
|
|
428
|
+
this.disposed = !0, this.doReconnect = !1, this.reconnectTimer && (clearTimeout(this.reconnectTimer), this.reconnectTimer = void 0), this.disconnect().catch((t) => {
|
|
426
429
|
console.warn("Error during session disconnect:", t);
|
|
427
430
|
}), this.removeAllListeners(), this.subscriptions.forEach((t) => t.dispose()), this.broadcasts.forEach((t) => t.dispose()), this.subscriptions.clear(), this.broadcasts.clear();
|
|
428
431
|
}
|
|
@@ -432,8 +435,8 @@ export {
|
|
|
432
435
|
y as MoQBroadcast,
|
|
433
436
|
k as MoQSession,
|
|
434
437
|
N as MoQSubscription,
|
|
435
|
-
|
|
436
|
-
|
|
438
|
+
n as SessionState,
|
|
439
|
+
u as SubscriptionState,
|
|
437
440
|
k as default
|
|
438
441
|
};
|
|
439
442
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","sources":["../src/event-emitter.ts","../src/types.ts","../src/broadcast.ts","../src/subscription.ts","../src/session.ts"],"sourcesContent":["// Simple event emitter for type-safe events\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport class EventEmitter<T extends Record<string, (...args: any[]) => void>> {\n private listeners = new Map<keyof T, Set<T[keyof T]>>();\n\n on<K extends keyof T>(event: K, listener: T[K]): void {\n if (!this.listeners.has(event)) {\n this.listeners.set(event, new Set());\n }\n this.listeners.get(event)!.add(listener);\n }\n\n off<K extends keyof T>(event: K, listener: T[K]): void {\n const eventListeners = this.listeners.get(event);\n if (eventListeners) {\n eventListeners.delete(listener);\n }\n }\n\n emit<K extends keyof T>(event: K, ...args: Parameters<T[K]>): void {\n const eventListeners = this.listeners.get(event);\n if (eventListeners) {\n eventListeners.forEach(listener => {\n try {\n listener(...args);\n } catch (error) {\n console.error('Error in event listener:', error);\n }\n });\n }\n }\n\n removeAllListeners<K extends keyof T>(event?: K): void {\n if (event) {\n this.listeners.delete(event);\n } else {\n this.listeners.clear();\n }\n }\n}","// Types for the library\nexport interface MoQSessionConfig {\n /** URL of the MoQ relay server */\n relayUrl: string;\n /** MoQ namespace (broadcast name) */\n namespace: string;\n /** Reconnection configuration */\n reconnection?: {\n /** Delay between reconnection attempts in ms (minimum: 1000) */\n delay?: number;\n };\n /** Connection timeout in ms (default: 10000) */\n connectionTimeout?: number;\n}\n\nexport interface BroadcastConfig {\n /** Track name for the broadcast */\n trackName: string;\n /** Priority for the track (default: 0) */\n priority?: number;\n}\n\nexport interface SubscriptionConfig {\n /** Track name to subscribe to */\n trackName: string;\n /** Priority for the subscription (default: 0) */\n priority?: number;\n /** Retry configuration for failed subscriptions */\n retry?: {\n /** Delay between retry attempts in ms (default: 2000) */\n delay?: number;\n };\n}\n\nexport enum SessionState {\n DISCONNECTED = 'disconnected',\n CONNECTING = 'connecting',\n CONNECTED = 'connected',\n RECONNECTING = 'reconnecting',\n FAILED = 'failed'\n}\n\nexport enum BroadcastState {\n IDLE = 'idle',\n BROADCASTING = 'broadcasting',\n ERROR = 'error'\n}\n\nexport enum SubscriptionState {\n PENDING = 'pending',\n SUBSCRIBED = 'subscribed',\n RETRYING = 'retrying',\n FAILED = 'failed'\n}\n\nexport interface SessionStatus {\n state: SessionState;\n reconnectAttempts: number;\n lastError?: Error;\n connectedAt?: Date;\n}\n\nexport interface BroadcastStatus {\n state: BroadcastState;\n trackName: string;\n bytesSent: number;\n lastError?: Error;\n}\n\nexport interface SubscriptionStatus {\n state: SubscriptionState;\n trackName: string;\n bytesReceived: number;\n retryAttempts: number;\n lastError?: Error;\n}\n\nexport interface DataReceived {\n trackName: string;\n data: Uint8Array;\n timestamp: number;\n frameIndex: number;\n}\n\n// Event types\nexport interface BroadcastAnnouncement {\n path: string;\n active: boolean;\n}\n\nexport interface SessionEvents {\n stateChange: (status: SessionStatus) => void;\n error: (error: Error) => void;\n broadcastAnnounced: (announcement: BroadcastAnnouncement) => void;\n data: (trackName: string, data: Uint8Array, frameIndex: number) => void;\n broadcastStateChange: (trackName: string, status: BroadcastStatus) => void;\n subscriptionStateChange: (trackName: string, status: SubscriptionStatus) => void;\n broadcastError: (trackName: string, error: Error) => void;\n subscriptionError: (trackName: string, error: Error) => void;\n trackRequested: (trackName: string) => void;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n [key: string]: (...args: any[]) => void;\n}\n\nexport interface BroadcastEvents {\n stateChange: (status: BroadcastStatus) => void;\n error: (error: Error) => void;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n [key: string]: (...args: any[]) => void;\n}\n\nexport interface SubscriptionEvents {\n stateChange: (status: SubscriptionStatus) => void;\n data: (data: DataReceived) => void;\n error: (error: Error) => void;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n [key: string]: (...args: any[]) => void;\n}","import { Group, Track } from '@kixelated/moq';\nimport { EventEmitter } from './event-emitter';\nimport {\n BroadcastConfig,\n BroadcastState,\n BroadcastStatus,\n BroadcastEvents\n} from './types';\n\nexport class MoQBroadcast extends EventEmitter<BroadcastEvents> {\n private _config: BroadcastConfig;\n private state: BroadcastState = BroadcastState.IDLE;\n private bytesSent = 0;\n private lastError?: Error;\n private track?: Track;\n private group?: Group;\n\n constructor(config: BroadcastConfig) {\n super();\n this._config = config;\n }\n\n get status(): BroadcastStatus {\n return {\n state: this.state,\n trackName: this._config.trackName,\n bytesSent: this.bytesSent,\n lastError: this.lastError\n };\n }\n\n get config(): BroadcastConfig {\n return { ...this._config };\n }\n\n updateTrack(track: Track): void {\n this.track = track;\n if (track) {\n this.setState(BroadcastState.BROADCASTING);\n }\n }\n\n async send(data: Uint8Array, newGroup: boolean): Promise<void> {\n if (this.state !== BroadcastState.BROADCASTING || !this.track) {\n throw new Error('Broadcast is not active');\n }\n\n try {\n if (newGroup || !this.group) {\n if (this.group) {\n this.group.close();\n }\n this.group = this.track.appendGroup();\n }\n await this.group.writeFrame(data);\n this.bytesSent += data.length;\n } catch (error) {\n this.handleError(error as Error);\n throw error;\n }\n }\n\n async stop(): Promise<void> {\n if (this.track) {\n try {\n this.track.close();\n } catch (error) {\n console.warn('Error closing track:', error);\n }\n this.track = undefined;\n }\n \n this.setState(BroadcastState.IDLE);\n }\n\n private setState(newState: BroadcastState): void {\n if (this.state !== newState) {\n this.state = newState;\n this.emit('stateChange', this.status);\n }\n }\n\n private handleError(error: Error): void {\n this.lastError = error;\n this.setState(BroadcastState.ERROR);\n this.emit('error', error);\n }\n\n public dispose(): void {\n this.stop().catch(console.error);\n this.removeAllListeners();\n }\n}","import { Broadcast, Track, Connection, Path } from '@kixelated/moq';\nimport { EventEmitter } from './event-emitter';\nimport {\n SubscriptionConfig,\n SubscriptionState,\n SubscriptionStatus,\n SubscriptionEvents,\n DataReceived\n} from './types';\n\nexport class MoQSubscription extends EventEmitter<SubscriptionEvents> {\n private _config: SubscriptionConfig;\n private state: SubscriptionState = SubscriptionState.PENDING;\n private bytesReceived = 0;\n private retryAttempts = 0;\n private lastError?: Error;\n private subscription?: Track;\n private broadcast?: Broadcast;\n private retryTimer?: ReturnType<typeof setTimeout>;\n private connection?: Connection.Established;\n private namespace?: string;\n\n constructor(config: SubscriptionConfig) {\n super();\n this._config = config;\n }\n\n get status(): SubscriptionStatus {\n return {\n state: this.state,\n trackName: this._config.trackName,\n bytesReceived: this.bytesReceived,\n retryAttempts: this.retryAttempts,\n lastError: this.lastError\n };\n }\n\n get config(): SubscriptionConfig {\n return { ...this._config };\n }\n\n async start(connection: Connection.Established, namespace: string): Promise<void> {\n this.connection = connection;\n this.namespace = namespace;\n try {\n await this.subscribe(connection, namespace);\n } catch (error) {\n this.handleError(error as Error);\n this.scheduleRetry(connection, namespace);\n }\n }\n\n private async subscribe(connection: Connection.Established, namespace: string): Promise<void> {\n this.setState(SubscriptionState.PENDING);\n\n const broadcastPath = Path.from(namespace);\n this.broadcast = connection.consume(broadcastPath);\n\n // Subscribe to the specific track within the broadcast\n this.subscription = this.broadcast.subscribe(this._config.trackName, this._config.priority || 0);\n this.setState(SubscriptionState.SUBSCRIBED);\n this.retryAttempts = 0;\n\n // Set up data reception\n this.readFrames();\n }\n\n private async readFrames(): Promise<void> {\n if (!this.subscription) return;\n\n try {\n // eslint-disable-next-line no-constant-condition\n while (true) {\n let framesInGroup = 0;\n const group = await this.subscription.nextGroup();\n if (!group) break; // Track is closed\n\n // Read all frames from the group\n // eslint-disable-next-line no-constant-condition\n while (true) {\n const frame = await group.readFrame();\n if (!frame) break; // Group is finished\n framesInGroup++;\n\n this.bytesReceived += frame.length;\n const receivedData: DataReceived = {\n trackName: this._config.trackName,\n data: frame,\n timestamp: Date.now(),\n frameIndex: framesInGroup,\n };\n this.emit('data', receivedData);\n }\n }\n } catch (error) {\n this.handleError(error as Error);\n // Trigger retry when stream gets reset/closed\n if (this.connection && this.namespace) {\n this.scheduleRetry(this.connection, this.namespace);\n }\n }\n }\n \n private scheduleRetry(connection: Connection.Established, namespace: string): void {\n const delay = this._config.retry?.delay || 2000;\n\n this.setState(SubscriptionState.RETRYING);\n this.retryAttempts++;\n\n this.retryTimer = setTimeout(async () => {\n try {\n await this.subscribe(connection, namespace);\n } catch (error) {\n this.handleError(error as Error);\n this.scheduleRetry(connection, namespace);\n }\n }, delay);\n }\n\n async stop(): Promise<void> {\n this.connection = undefined;\n this.namespace = undefined;\n \n if (this.retryTimer) {\n clearTimeout(this.retryTimer);\n this.retryTimer = undefined;\n }\n\n if (this.subscription) {\n try {\n this.subscription.close();\n } catch (error) {\n console.warn('Error closing subscription:', error);\n }\n this.subscription = undefined;\n }\n\n if (this.broadcast) {\n try {\n this.broadcast.close();\n } catch (error) {\n console.warn('Error closing broadcast:', error);\n }\n this.broadcast = undefined;\n }\n\n this.setState(SubscriptionState.PENDING);\n }\n\n private setState(newState: SubscriptionState): void {\n if (this.state !== newState) {\n this.state = newState;\n this.emit('stateChange', this.status);\n }\n }\n\n private handleError(error: Error): void {\n this.lastError = error;\n this.emit('error', error);\n }\n\n dispose(): void {\n this.stop().catch((error) => {\n console.warn('Error during dispose:', error);\n });\n this.removeAllListeners();\n }\n}","import { Broadcast, Connection, Path } from '@kixelated/moq';\nimport { EventEmitter } from './event-emitter';\nimport { MoQBroadcast } from './broadcast';\nimport { MoQSubscription } from './subscription';\nimport {\n MoQSessionConfig,\n SessionState,\n SessionStatus,\n SessionEvents,\n BroadcastConfig,\n SubscriptionConfig\n} from './types';\n\nexport class MoQSession extends EventEmitter<SessionEvents> {\n private config: MoQSessionConfig;\n private url: URL;\n private state: SessionState = SessionState.DISCONNECTED;\n private connection?: Connection.Established;\n private reconnectAttempts = 0;\n private lastError?: Error;\n private connectedAt?: Date;\n private reconnectTimer?: ReturnType<typeof setTimeout>;\n private broadcasts = new Map<string, MoQBroadcast>();\n private subscriptions = new Map<string, MoQSubscription>();\n private announcedBroadcasts = new Set<string>();\n private doReconnect = true;\n private broadcast?: Broadcast;\n\n constructor(config: MoQSessionConfig) {\n super();\n this.config = {\n ...config,\n reconnection: {\n delay: Math.max(config.reconnection?.delay || 1000, 1000), // Enforce minimum 1 second\n },\n connectionTimeout: config.connectionTimeout || 10000\n };\n\n this.url = new URL(this.config.relayUrl);\n }\n\n get status(): SessionStatus {\n return {\n state: this.state,\n reconnectAttempts: this.reconnectAttempts,\n lastError: this.lastError,\n connectedAt: this.connectedAt\n };\n }\n\n async connect(): Promise<void> {\n if (this.state === SessionState.CONNECTING || this.state === SessionState.CONNECTED) {\n return;\n }\n\n this.setState(SessionState.CONNECTING);\n\n try {\n this.doReconnect = true;\n this.connection = await Connection.connect(this.url, {\n websocket: {\n enabled: false\n }\n });\n\n this.setState(SessionState.CONNECTED);\n this.connectedAt = new Date();\n this.reconnectAttempts = 0;\n\n // Set up connection close handling\n this.connection.closed.then(() => {\n if (this.state === SessionState.CONNECTED) {\n this.handleDisconnection();\n }\n });\n\n // Start discovering announced broadcasts\n this.startAnnouncementDiscovery();\n\n // Restart all broadcasts and subscriptions\n await this.restartBroadcasts();\n await this.restartSubscriptions();\n\n } catch (error) {\n this.handleError(error as Error);\n this.scheduleReconnect();\n throw error;\n }\n }\n\n async disconnect(): Promise<void> {\n this.doReconnect = false;\n\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = undefined;\n }\n\n // Stop all broadcasts and subscriptions\n await this.stopAllBroadcasts();\n await this.stopAllSubscriptions();\n\n if (this.connection) {\n try {\n this.connection.close();\n } catch (error) {\n console.warn('Error closing connection:', error);\n }\n this.connection = undefined;\n }\n\n this.setState(SessionState.DISCONNECTED);\n this.connectedAt = undefined;\n }\n\n /**\n * Get all active broadcast track names\n */\n getAllBroadcastTrackNames(): string[] {\n return Array.from(this.broadcasts.keys());\n }\n\n /**\n * Get all active subscription track names\n */\n getAllSubscriptionTrackNames(): string[] {\n return Array.from(this.subscriptions.keys());\n }\n\n /**\n * Declaratively update broadcasts - add, remove, or update broadcasts to match the desired state.\n * \n * @param configs Array of broadcast configurations representing the desired state\n */\n updateBroadcasts(configs: BroadcastConfig[]): void {\n // Check for duplicate track names in the input\n const trackNames = configs.map(config => config.trackName);\n const uniqueTrackNames = new Set(trackNames);\n if (trackNames.length !== uniqueTrackNames.size) {\n const duplicates = trackNames.filter((name, index) => trackNames.indexOf(name) !== index);\n throw new Error(`Duplicate broadcast track name: ${duplicates[0]}`);\n }\n\n const desiredTracks = new Set(configs.map(config => config.trackName));\n const currentTracks = new Set(this.broadcasts.keys());\n\n // Remove broadcasts that are no longer needed\n for (const trackName of currentTracks) {\n if (!desiredTracks.has(trackName)) {\n this._removeBroadcast(trackName);\n }\n }\n\n // Add new broadcasts or update existing ones\n for (const config of configs) {\n const existing = this.broadcasts.get(config.trackName);\n if (!existing) {\n // Create new broadcast\n this._createBroadcast(config);\n } else {\n // Update existing broadcast config if needed\n if (existing.config.priority !== config.priority) {\n // For now, we recreate if priority changed\n // In future, we could support dynamic priority updates\n this._removeBroadcast(config.trackName);\n this._createBroadcast(config);\n }\n }\n }\n }\n\n /**\n * Declaratively update subscriptions - add, remove, or update subscriptions to match the desired state.\n * \n * @param configs Array of subscription configurations representing the desired state\n */\n updateSubscriptions(configs: SubscriptionConfig[]): void {\n // Check for duplicate track names in the input\n const trackNames = configs.map(config => config.trackName);\n const uniqueTrackNames = new Set(trackNames);\n if (trackNames.length !== uniqueTrackNames.size) {\n const duplicates = trackNames.filter((name, index) => trackNames.indexOf(name) !== index);\n throw new Error(`Duplicate subscription track name: ${duplicates[0]}`);\n }\n\n const desiredTracks = new Set(configs.map(config => config.trackName));\n const currentTracks = new Set(this.subscriptions.keys());\n\n // Remove subscriptions that are no longer needed\n for (const trackName of currentTracks) {\n if (!desiredTracks.has(trackName)) {\n this._removeSubscription(trackName);\n }\n }\n\n // Add new subscriptions or update existing ones\n for (const config of configs) {\n const existing = this.subscriptions.get(config.trackName);\n if (!existing) {\n // Create new subscription\n this._createSubscription(config);\n } else {\n // Update existing subscription config if needed\n if (existing.config.priority !== config.priority || \n existing.config.retry?.delay !== config.retry?.delay) {\n // For now, we recreate if config changed\n // In future, we could support dynamic config updates\n this._removeSubscription(config.trackName);\n this._createSubscription(config);\n }\n }\n }\n }\n\n getAnnouncedBroadcasts(): string[] {\n return Array.from(this.announcedBroadcasts);\n }\n\n /**\n * Send data to a broadcast track\n * @param trackName Name of the track to send data to\n * @param data Binary data to send\n */\n async send(trackName: string, data: Uint8Array, newGroup: boolean): Promise<void> {\n const broadcast = this.broadcasts.get(trackName);\n if (!broadcast) {\n throw new Error(`No broadcast found for track: ${trackName}`);\n }\n await broadcast.send(data, newGroup);\n }\n\n /**\n * Get the status of a specific broadcast track\n * @param trackName Name of the track\n */\n getBroadcastStatus(trackName: string) {\n const broadcast = this.broadcasts.get(trackName);\n return broadcast?.status;\n }\n\n /**\n * Get the status of a specific subscription track\n * @param trackName Name of the track\n */\n getSubscriptionStatus(trackName: string) {\n const subscription = this.subscriptions.get(trackName);\n return subscription?.status;\n }\n\n private _createBroadcast(config: BroadcastConfig): MoQBroadcast {\n const broadcast = new MoQBroadcast(config);\n this.broadcasts.set(config.trackName, broadcast);\n\n // Forward broadcast events to session\n broadcast.on('stateChange', (status) => {\n this.emit('broadcastStateChange', config.trackName, status);\n });\n\n broadcast.on('error', (error) => {\n this.emit('broadcastError', config.trackName, error);\n });\n\n this.initBroadcasting();\n\n return broadcast;\n }\n\n private _createSubscription(config: SubscriptionConfig): MoQSubscription {\n const subscription = new MoQSubscription(config);\n this.subscriptions.set(config.trackName, subscription);\n\n // Forward subscription events to session\n subscription.on('data', (received) => {\n this.emit('data', received.trackName, received.data, received.frameIndex);\n });\n\n subscription.on('stateChange', (status) => {\n this.emit('subscriptionStateChange', config.trackName, status);\n });\n\n subscription.on('error', (error) => {\n this.emit('subscriptionError', config.trackName, error);\n });\n\n // Start subscription if we're connected\n if (this.state === SessionState.CONNECTED && this.connection) {\n subscription.start(this.connection, this.config.namespace).catch(error => {\n console.error('Failed to start subscription:', error);\n });\n }\n\n return subscription;\n }\n\n private _removeBroadcast(trackName: string): void {\n const broadcast = this.broadcasts.get(trackName);\n if (broadcast) {\n broadcast.stop().catch(error => {\n console.warn('Error stopping broadcast:', error);\n });\n this.broadcasts.delete(trackName);\n }\n }\n\n private _removeSubscription(trackName: string): void {\n const subscription = this.subscriptions.get(trackName);\n if (subscription) {\n subscription.stop().catch(error => {\n console.warn('Error stopping subscription:', error);\n });\n this.subscriptions.delete(trackName);\n }\n }\n\n private async startAnnouncementDiscovery(): Promise<void> {\n if (!this.connection) return;\n\n try {\n // Listen for announcements with our namespace as prefix\n const namespacePath = Path.from(this.config.namespace);\n const announced = this.connection.announced(namespacePath);\n \n // Process announcements in the background\n this.processAnnouncements(announced);\n \n } catch (error) {\n console.error('Failed to start announcement discovery:', error);\n }\n }\n\n private async processAnnouncements(announced: ReturnType<Connection.Established['announced']>): Promise<void> {\n try {\n for (;;) {\n const announcement = await announced.next();\n if (!announcement) break; // Announcements closed\n \n if (announcement.active) {\n this.announcedBroadcasts.add(announcement.path);\n this.emit('broadcastAnnounced', {\n path: announcement.path,\n active: true\n });\n } else {\n this.announcedBroadcasts.delete(announcement.path);\n this.emit('broadcastAnnounced', {\n path: announcement.path,\n active: false\n });\n }\n }\n } catch (error) {\n console.error('Error processing announcements:', error);\n }\n }\n\n private async restartBroadcasts(): Promise<void> {\n await this.stopAllBroadcasts();\n this.initBroadcasting();\n }\n\n private initBroadcasting(): void {\n if (this.broadcast) return;\n if (this.broadcasts.size === 0) return;\n\n this.broadcast = new Broadcast();\n if (this.connection) {\n this.connection.publish(Path.from(this.config.namespace), this.broadcast);\n this.handleTrackRequests().catch(error => {\n console.error('Error handling track requests:', error);\n });\n }\n }\n\n private async handleTrackRequests(): Promise<void> {\n if (!this.broadcast) return;\n \n try {\n for (;;) {\n const request = await this.broadcast.requested();\n if (!request) return; // No more requests, broadcast closed;\n const broadcast = this.broadcasts.get(request.track.name);\n if (broadcast) {\n broadcast.updateTrack(request.track);\n this.emit('trackRequested', request.track.name);\n }\n }\n\n } catch (error) {\n console.warn('Error handling track requests:', error);\n this.handleError(error as Error);\n }\n}\n\n private async restartSubscriptions(): Promise<void> {\n if (!this.connection) return;\n\n const promises = Array.from(this.subscriptions.values()).map(subscription => \n subscription.start(this.connection!, this.config.namespace).catch(error => {\n console.error('Failed to restart subscription:', error);\n })\n );\n\n await Promise.allSettled(promises);\n }\n\n private async stopAllBroadcasts(): Promise<void> {\n this.broadcast?.close();\n this.broadcast = undefined;\n const promises = Array.from(this.broadcasts.values()).map(broadcast => \n broadcast.stop().catch(error => {\n console.warn('Error stopping broadcast:', error);\n })\n );\n\n await Promise.allSettled(promises);\n }\n\n private async stopAllSubscriptions(): Promise<void> {\n const promises = Array.from(this.subscriptions.values()).map(subscription => \n subscription.stop().catch(error => {\n console.warn('Error stopping subscription:', error);\n })\n );\n\n await Promise.allSettled(promises);\n }\n\n private handleDisconnection(): void {\n this.setState(SessionState.DISCONNECTED);\n this.scheduleReconnect();\n }\n\n private scheduleReconnect(): void {\n if (!this.config.reconnection || !this.doReconnect) return;\n\n const delay = this.config.reconnection?.delay || 1000;\n\n this.setState(SessionState.RECONNECTING);\n this.reconnectAttempts++;\n\n this.reconnectTimer = setTimeout(() => {\n if (!this.doReconnect) return;\n if (this.state !== SessionState.RECONNECTING) return;\n this.connect().catch(error => {\n console.error('Reconnection failed:', error);\n });\n }, delay);\n }\n\n private setState(newState: SessionState): void {\n if (this.state !== newState) {\n this.state = newState;\n this.emit('stateChange', this.status);\n }\n }\n\n private handleError(error: Error): void {\n this.lastError = error;\n this.emit('error', error);\n }\n\n public dispose(): void {\n // Immediately stop reconnection attempts\n this.doReconnect = false;\n \n // Clear any pending reconnect timer immediately\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = undefined;\n }\n \n // Disconnect (but don't await to keep dispose synchronous)\n this.disconnect().catch((error) => {\n console.warn('Error during session disconnect:', error);\n });\n this.removeAllListeners();\n\n this.subscriptions.forEach(sub => sub.dispose());\n this.broadcasts.forEach(bc => bc.dispose());\n this.subscriptions.clear();\n this.broadcasts.clear();\n }\n}"],"names":["EventEmitter","event","listener","eventListeners","args","error","SessionState","BroadcastState","SubscriptionState","MoQBroadcast","config","track","data","newGroup","newState","MoQSubscription","connection","namespace","broadcastPath","Path","framesInGroup","group","frame","receivedData","delay","_a","MoQSession","Connection","configs","trackNames","uniqueTrackNames","duplicates","name","index","desiredTracks","currentTracks","trackName","existing","_b","broadcast","subscription","status","received","namespacePath","announced","announcement","Broadcast","request","promises","sub","bc"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","sources":["../src/event-emitter.ts","../src/types.ts","../src/broadcast.ts","../src/subscription.ts","../src/session.ts"],"sourcesContent":["// Simple event emitter for type-safe events\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport class EventEmitter<T extends Record<string, (...args: any[]) => void>> {\n private listeners = new Map<keyof T, Set<T[keyof T]>>();\n\n on<K extends keyof T>(event: K, listener: T[K]): void {\n if (!this.listeners.has(event)) {\n this.listeners.set(event, new Set());\n }\n this.listeners.get(event)!.add(listener);\n }\n\n off<K extends keyof T>(event: K, listener: T[K]): void {\n const eventListeners = this.listeners.get(event);\n if (eventListeners) {\n eventListeners.delete(listener);\n }\n }\n\n emit<K extends keyof T>(event: K, ...args: Parameters<T[K]>): void {\n const eventListeners = this.listeners.get(event);\n if (eventListeners) {\n eventListeners.forEach(listener => {\n try {\n listener(...args);\n } catch (error) {\n console.error('Error in event listener:', error);\n }\n });\n }\n }\n\n removeAllListeners<K extends keyof T>(event?: K): void {\n if (event) {\n this.listeners.delete(event);\n } else {\n this.listeners.clear();\n }\n }\n}","// Types for the library\nexport interface MoQSessionConfig {\n /** URL of the MoQ relay server */\n relayUrl: string;\n /** MoQ namespace (broadcast name) */\n namespace: string;\n /** Reconnection configuration */\n reconnection?: {\n /** Delay between reconnection attempts in ms (minimum: 1000) */\n delay?: number;\n };\n /** Connection timeout in ms (default: 10000) */\n connectionTimeout?: number;\n}\n\nexport interface BroadcastConfig {\n /** Track name for the broadcast */\n trackName: string;\n /** Priority for the track (default: 0) */\n priority?: number;\n}\n\nexport interface SubscriptionConfig {\n /** Track name to subscribe to */\n trackName: string;\n /** Priority for the subscription (default: 0) */\n priority?: number;\n /** Retry configuration for failed subscriptions */\n retry?: {\n /** Delay between retry attempts in ms (default: 2000) */\n delay?: number;\n };\n}\n\nexport enum SessionState {\n DISCONNECTED = 'disconnected',\n CONNECTING = 'connecting',\n CONNECTED = 'connected',\n RECONNECTING = 'reconnecting',\n FAILED = 'failed'\n}\n\nexport enum BroadcastState {\n IDLE = 'idle',\n BROADCASTING = 'broadcasting',\n ERROR = 'error'\n}\n\nexport enum SubscriptionState {\n PENDING = 'pending',\n SUBSCRIBED = 'subscribed',\n RETRYING = 'retrying',\n FAILED = 'failed'\n}\n\nexport interface SessionStatus {\n state: SessionState;\n reconnectAttempts: number;\n lastError?: Error;\n connectedAt?: Date;\n}\n\nexport interface BroadcastStatus {\n state: BroadcastState;\n trackName: string;\n bytesSent: number;\n lastError?: Error;\n}\n\nexport interface SubscriptionStatus {\n state: SubscriptionState;\n trackName: string;\n bytesReceived: number;\n retryAttempts: number;\n lastError?: Error;\n}\n\nexport interface DataReceived {\n trackName: string;\n data: Uint8Array;\n timestamp: number;\n frameIndex: number;\n}\n\n// Event types\nexport interface BroadcastAnnouncement {\n path: string;\n active: boolean;\n}\n\nexport interface SessionEvents {\n stateChange: (status: SessionStatus) => void;\n error: (error: Error) => void;\n broadcastAnnounced: (announcement: BroadcastAnnouncement) => void;\n data: (trackName: string, data: Uint8Array, frameIndex: number) => void;\n broadcastStateChange: (trackName: string, status: BroadcastStatus) => void;\n subscriptionStateChange: (trackName: string, status: SubscriptionStatus) => void;\n broadcastError: (trackName: string, error: Error) => void;\n subscriptionError: (trackName: string, error: Error) => void;\n trackRequested: (trackName: string) => void;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n [key: string]: (...args: any[]) => void;\n}\n\nexport interface BroadcastEvents {\n stateChange: (status: BroadcastStatus) => void;\n error: (error: Error) => void;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n [key: string]: (...args: any[]) => void;\n}\n\nexport interface SubscriptionEvents {\n stateChange: (status: SubscriptionStatus) => void;\n data: (data: DataReceived) => void;\n error: (error: Error) => void;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n [key: string]: (...args: any[]) => void;\n}","import { Group, Track } from '@kixelated/moq';\nimport { EventEmitter } from './event-emitter';\nimport {\n BroadcastConfig,\n BroadcastState,\n BroadcastStatus,\n BroadcastEvents\n} from './types';\n\nexport class MoQBroadcast extends EventEmitter<BroadcastEvents> {\n private _config: BroadcastConfig;\n private state: BroadcastState = BroadcastState.IDLE;\n private bytesSent = 0;\n private lastError?: Error;\n private track?: Track;\n private group?: Group;\n\n constructor(config: BroadcastConfig) {\n super();\n this._config = config;\n }\n\n get status(): BroadcastStatus {\n return {\n state: this.state,\n trackName: this._config.trackName,\n bytesSent: this.bytesSent,\n lastError: this.lastError\n };\n }\n\n get config(): BroadcastConfig {\n return { ...this._config };\n }\n\n updateTrack(track: Track): void {\n this.track = track;\n if (track) {\n this.setState(BroadcastState.BROADCASTING);\n }\n }\n\n async send(data: Uint8Array, newGroup: boolean): Promise<void> {\n if (this.state !== BroadcastState.BROADCASTING || !this.track) {\n throw new Error('Broadcast is not active');\n }\n\n try {\n if (newGroup || !this.group) {\n if (this.group) {\n this.group.close();\n }\n this.group = this.track.appendGroup();\n }\n await this.group.writeFrame(data);\n this.bytesSent += data.length;\n } catch (error) {\n this.handleError(error as Error);\n throw error;\n }\n }\n\n async stop(): Promise<void> {\n if (this.track) {\n try {\n this.track.close();\n } catch (error) {\n console.warn('Error closing track:', error);\n }\n this.track = undefined;\n }\n \n this.setState(BroadcastState.IDLE);\n }\n\n private setState(newState: BroadcastState): void {\n if (this.state !== newState) {\n this.state = newState;\n this.emit('stateChange', this.status);\n }\n }\n\n private handleError(error: Error): void {\n this.lastError = error;\n this.setState(BroadcastState.ERROR);\n this.emit('error', error);\n }\n\n public dispose(): void {\n this.stop().catch(console.error);\n this.removeAllListeners();\n }\n}","import { Broadcast, Track, Connection, Path } from '@kixelated/moq';\nimport { EventEmitter } from './event-emitter';\nimport {\n SubscriptionConfig,\n SubscriptionState,\n SubscriptionStatus,\n SubscriptionEvents,\n DataReceived\n} from './types';\n\nexport class MoQSubscription extends EventEmitter<SubscriptionEvents> {\n private _config: SubscriptionConfig;\n private state: SubscriptionState = SubscriptionState.PENDING;\n private bytesReceived = 0;\n private retryAttempts = 0;\n private lastError?: Error;\n private subscription?: Track;\n private broadcast?: Broadcast;\n private retryTimer?: ReturnType<typeof setTimeout>;\n private connection?: Connection.Established;\n private namespace?: string;\n\n constructor(config: SubscriptionConfig) {\n super();\n this._config = config;\n }\n\n get status(): SubscriptionStatus {\n return {\n state: this.state,\n trackName: this._config.trackName,\n bytesReceived: this.bytesReceived,\n retryAttempts: this.retryAttempts,\n lastError: this.lastError\n };\n }\n\n get config(): SubscriptionConfig {\n return { ...this._config };\n }\n\n async start(connection: Connection.Established, namespace: string): Promise<void> {\n this.connection = connection;\n this.namespace = namespace;\n try {\n await this.subscribe(connection, namespace);\n } catch (error) {\n this.handleError(error as Error);\n this.scheduleRetry(connection, namespace);\n }\n }\n\n private async subscribe(connection: Connection.Established, namespace: string): Promise<void> {\n this.setState(SubscriptionState.PENDING);\n\n const broadcastPath = Path.from(namespace);\n this.broadcast = connection.consume(broadcastPath);\n\n // Subscribe to the specific track within the broadcast\n this.subscription = this.broadcast.subscribe(this._config.trackName, this._config.priority || 0);\n this.setState(SubscriptionState.SUBSCRIBED);\n this.retryAttempts = 0;\n\n // Set up data reception\n this.readFrames();\n }\n\n private async readFrames(): Promise<void> {\n if (!this.subscription) return;\n\n try {\n // eslint-disable-next-line no-constant-condition\n while (true) {\n let framesInGroup = 0;\n const group = await this.subscription.nextGroup();\n if (!group) break; // Track is closed\n\n // Read all frames from the group\n // eslint-disable-next-line no-constant-condition\n while (true) {\n const frame = await group.readFrame();\n if (!frame) break; // Group is finished\n framesInGroup++;\n\n this.bytesReceived += frame.length;\n const receivedData: DataReceived = {\n trackName: this._config.trackName,\n data: frame,\n timestamp: Date.now(),\n frameIndex: framesInGroup,\n };\n this.emit('data', receivedData);\n }\n }\n } catch (error) {\n this.handleError(error as Error);\n // Trigger retry when stream gets reset/closed\n if (this.connection && this.namespace) {\n this.scheduleRetry(this.connection, this.namespace);\n }\n }\n }\n \n private scheduleRetry(connection: Connection.Established, namespace: string): void {\n const delay = this._config.retry?.delay || 2000;\n\n this.setState(SubscriptionState.RETRYING);\n this.retryAttempts++;\n\n this.retryTimer = setTimeout(async () => {\n try {\n await this.subscribe(connection, namespace);\n } catch (error) {\n this.handleError(error as Error);\n this.scheduleRetry(connection, namespace);\n }\n }, delay);\n }\n\n async stop(): Promise<void> {\n this.connection = undefined;\n this.namespace = undefined;\n \n if (this.retryTimer) {\n clearTimeout(this.retryTimer);\n this.retryTimer = undefined;\n }\n\n if (this.subscription) {\n try {\n this.subscription.close();\n } catch (error) {\n console.warn('Error closing subscription:', error);\n }\n this.subscription = undefined;\n }\n\n if (this.broadcast) {\n try {\n this.broadcast.close();\n } catch (error) {\n console.warn('Error closing broadcast:', error);\n }\n this.broadcast = undefined;\n }\n\n this.setState(SubscriptionState.PENDING);\n }\n\n private setState(newState: SubscriptionState): void {\n if (this.state !== newState) {\n this.state = newState;\n this.emit('stateChange', this.status);\n }\n }\n\n private handleError(error: Error): void {\n this.lastError = error;\n this.emit('error', error);\n }\n\n dispose(): void {\n this.stop().catch((error) => {\n console.warn('Error during dispose:', error);\n });\n this.removeAllListeners();\n }\n}","import { Broadcast, Connection, Path } from '@kixelated/moq';\nimport { EventEmitter } from './event-emitter';\nimport { MoQBroadcast } from './broadcast';\nimport { MoQSubscription } from './subscription';\nimport {\n MoQSessionConfig,\n SessionState,\n SessionStatus,\n SessionEvents,\n BroadcastConfig,\n SubscriptionConfig\n} from './types';\n\nexport class MoQSession extends EventEmitter<SessionEvents> {\n private config: MoQSessionConfig;\n private url: URL;\n private state: SessionState = SessionState.DISCONNECTED;\n private connection?: Connection.Established;\n private reconnectAttempts = 0;\n private lastError?: Error;\n private connectedAt?: Date;\n private reconnectTimer?: ReturnType<typeof setTimeout>;\n private broadcasts = new Map<string, MoQBroadcast>();\n private subscriptions = new Map<string, MoQSubscription>();\n private announcedBroadcasts = new Set<string>();\n private doReconnect = true;\n private broadcast?: Broadcast;\n private disposed = false;\n\n constructor(config: MoQSessionConfig) {\n super();\n this.config = {\n ...config,\n reconnection: {\n delay: Math.max(config.reconnection?.delay || 1000, 1000), // Enforce minimum 1 second\n },\n connectionTimeout: config.connectionTimeout || 10000\n };\n\n this.url = new URL(this.config.relayUrl);\n }\n\n get status(): SessionStatus {\n return {\n state: this.state,\n reconnectAttempts: this.reconnectAttempts,\n lastError: this.lastError,\n connectedAt: this.connectedAt\n };\n }\n\n async connect(): Promise<void> {\n if (this.disposed) {\n throw new Error('Cannot connect a disposed session');\n }\n \n if (this.state === SessionState.CONNECTING || this.state === SessionState.CONNECTED) {\n return;\n }\n\n this.setState(SessionState.CONNECTING);\n\n try {\n this.doReconnect = true;\n this.connection = await Connection.connect(this.url, {\n websocket: {\n enabled: false\n }\n });\n\n this.setState(SessionState.CONNECTED);\n this.connectedAt = new Date();\n this.reconnectAttempts = 0;\n\n // Set up connection close handling\n this.connection.closed.then(() => {\n // Only handle disconnection if not disposed\n if (!this.disposed && this.state === SessionState.CONNECTED) {\n this.handleDisconnection();\n }\n });\n\n // Start discovering announced broadcasts\n this.startAnnouncementDiscovery();\n\n // Restart all broadcasts and subscriptions\n await this.restartBroadcasts();\n await this.restartSubscriptions();\n\n } catch (error) {\n const err = new Error(`Failed to connect to relay: ${(error as Error).message}`);\n this.handleError(err);\n this.scheduleReconnect();\n throw err;\n }\n }\n\n async disconnect(): Promise<void> {\n this.doReconnect = false;\n\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = undefined;\n }\n\n // Stop all broadcasts and subscriptions\n await this.stopAllBroadcasts();\n await this.stopAllSubscriptions();\n\n if (this.connection) {\n try {\n this.connection.close();\n } catch (error) {\n console.warn('Error closing connection:', error);\n }\n this.connection = undefined;\n }\n\n this.setState(SessionState.DISCONNECTED);\n this.connectedAt = undefined;\n }\n\n /**\n * Get all active broadcast track names\n */\n getAllBroadcastTrackNames(): string[] {\n return Array.from(this.broadcasts.keys());\n }\n\n /**\n * Get all active subscription track names\n */\n getAllSubscriptionTrackNames(): string[] {\n return Array.from(this.subscriptions.keys());\n }\n\n /**\n * Declaratively update broadcasts - add, remove, or update broadcasts to match the desired state.\n * \n * @param configs Array of broadcast configurations representing the desired state\n */\n updateBroadcasts(configs: BroadcastConfig[]): void {\n // Check for duplicate track names in the input\n const trackNames = configs.map(config => config.trackName);\n const uniqueTrackNames = new Set(trackNames);\n if (trackNames.length !== uniqueTrackNames.size) {\n const duplicates = trackNames.filter((name, index) => trackNames.indexOf(name) !== index);\n throw new Error(`Duplicate broadcast track name: ${duplicates[0]}`);\n }\n\n const desiredTracks = new Set(configs.map(config => config.trackName));\n const currentTracks = new Set(this.broadcasts.keys());\n\n // Remove broadcasts that are no longer needed\n for (const trackName of currentTracks) {\n if (!desiredTracks.has(trackName)) {\n this._removeBroadcast(trackName);\n }\n }\n\n // Add new broadcasts or update existing ones\n for (const config of configs) {\n const existing = this.broadcasts.get(config.trackName);\n if (!existing) {\n // Create new broadcast\n this._createBroadcast(config);\n } else {\n // Update existing broadcast config if needed\n if (existing.config.priority !== config.priority) {\n // For now, we recreate if priority changed\n // In future, we could support dynamic priority updates\n this._removeBroadcast(config.trackName);\n this._createBroadcast(config);\n }\n }\n }\n }\n\n /**\n * Declaratively update subscriptions - add, remove, or update subscriptions to match the desired state.\n * \n * @param configs Array of subscription configurations representing the desired state\n */\n updateSubscriptions(configs: SubscriptionConfig[]): void {\n // Check for duplicate track names in the input\n const trackNames = configs.map(config => config.trackName);\n const uniqueTrackNames = new Set(trackNames);\n if (trackNames.length !== uniqueTrackNames.size) {\n const duplicates = trackNames.filter((name, index) => trackNames.indexOf(name) !== index);\n throw new Error(`Duplicate subscription track name: ${duplicates[0]}`);\n }\n\n const desiredTracks = new Set(configs.map(config => config.trackName));\n const currentTracks = new Set(this.subscriptions.keys());\n\n // Remove subscriptions that are no longer needed\n for (const trackName of currentTracks) {\n if (!desiredTracks.has(trackName)) {\n this._removeSubscription(trackName);\n }\n }\n\n // Add new subscriptions or update existing ones\n for (const config of configs) {\n const existing = this.subscriptions.get(config.trackName);\n if (!existing) {\n // Create new subscription\n this._createSubscription(config);\n } else {\n // Update existing subscription config if needed\n if (existing.config.priority !== config.priority || \n existing.config.retry?.delay !== config.retry?.delay) {\n // For now, we recreate if config changed\n // In future, we could support dynamic config updates\n this._removeSubscription(config.trackName);\n this._createSubscription(config);\n }\n }\n }\n }\n\n getAnnouncedBroadcasts(): string[] {\n return Array.from(this.announcedBroadcasts);\n }\n\n /**\n * Send data to a broadcast track\n * @param trackName Name of the track to send data to\n * @param data Binary data to send\n */\n async send(trackName: string, data: Uint8Array, newGroup: boolean): Promise<void> {\n const broadcast = this.broadcasts.get(trackName);\n if (!broadcast) {\n throw new Error(`No broadcast found for track: ${trackName}`);\n }\n await broadcast.send(data, newGroup);\n }\n\n /**\n * Get the status of a specific broadcast track\n * @param trackName Name of the track\n */\n getBroadcastStatus(trackName: string) {\n const broadcast = this.broadcasts.get(trackName);\n return broadcast?.status;\n }\n\n /**\n * Get the status of a specific subscription track\n * @param trackName Name of the track\n */\n getSubscriptionStatus(trackName: string) {\n const subscription = this.subscriptions.get(trackName);\n return subscription?.status;\n }\n\n private _createBroadcast(config: BroadcastConfig): MoQBroadcast {\n const broadcast = new MoQBroadcast(config);\n this.broadcasts.set(config.trackName, broadcast);\n\n // Forward broadcast events to session\n broadcast.on('stateChange', (status) => {\n this.emit('broadcastStateChange', config.trackName, status);\n });\n\n broadcast.on('error', (error) => {\n this.emit('broadcastError', config.trackName, error);\n });\n\n this.initBroadcasting();\n\n return broadcast;\n }\n\n private _createSubscription(config: SubscriptionConfig): MoQSubscription {\n const subscription = new MoQSubscription(config);\n this.subscriptions.set(config.trackName, subscription);\n\n // Forward subscription events to session\n subscription.on('data', (received) => {\n this.emit('data', received.trackName, received.data, received.frameIndex);\n });\n\n subscription.on('stateChange', (status) => {\n this.emit('subscriptionStateChange', config.trackName, status);\n });\n\n subscription.on('error', (error) => {\n this.emit('subscriptionError', config.trackName, error);\n });\n\n // Start subscription if we're connected\n if (this.state === SessionState.CONNECTED && this.connection) {\n subscription.start(this.connection, this.config.namespace).catch(error => {\n console.error('Failed to start subscription:', error);\n });\n }\n\n return subscription;\n }\n\n private _removeBroadcast(trackName: string): void {\n const broadcast = this.broadcasts.get(trackName);\n if (broadcast) {\n broadcast.stop().catch(error => {\n console.warn('Error stopping broadcast:', error);\n });\n this.broadcasts.delete(trackName);\n }\n }\n\n private _removeSubscription(trackName: string): void {\n const subscription = this.subscriptions.get(trackName);\n if (subscription) {\n subscription.stop().catch(error => {\n console.warn('Error stopping subscription:', error);\n });\n this.subscriptions.delete(trackName);\n }\n }\n\n private async startAnnouncementDiscovery(): Promise<void> {\n if (!this.connection) return;\n\n try {\n // Listen for announcements with our namespace as prefix\n const namespacePath = Path.from(this.config.namespace);\n const announced = this.connection.announced(namespacePath);\n \n // Process announcements in the background\n this.processAnnouncements(announced);\n \n } catch (error) {\n console.error('Failed to start announcement discovery:', error);\n }\n }\n\n private async processAnnouncements(announced: ReturnType<Connection.Established['announced']>): Promise<void> {\n try {\n for (;;) {\n // Stop processing if session is disposed\n if (this.disposed) break;\n \n const announcement = await announced.next();\n if (!announcement) break; // Announcements closed\n \n // Don't emit events if disposed\n if (this.disposed) break;\n \n if (announcement.active) {\n this.announcedBroadcasts.add(announcement.path);\n this.emit('broadcastAnnounced', {\n path: announcement.path,\n active: true\n });\n } else {\n this.announcedBroadcasts.delete(announcement.path);\n this.emit('broadcastAnnounced', {\n path: announcement.path,\n active: false\n });\n }\n }\n } catch (error) {\n // Don't log errors if session is disposed\n if (!this.disposed) {\n console.error('Error processing announcements:', error);\n }\n }\n }\n\n private async restartBroadcasts(): Promise<void> {\n await this.stopAllBroadcasts();\n this.initBroadcasting();\n }\n\n private initBroadcasting(): void {\n if (this.broadcast) return;\n if (this.broadcasts.size === 0) return;\n\n this.broadcast = new Broadcast();\n if (this.connection) {\n this.connection.publish(Path.from(this.config.namespace), this.broadcast);\n this.handleTrackRequests().catch(error => {\n console.error('Error handling track requests:', error);\n });\n }\n }\n\n private async handleTrackRequests(): Promise<void> {\n if (!this.broadcast) return;\n \n try {\n for (;;) {\n const request = await this.broadcast.requested();\n if (!request) return; // No more requests, broadcast closed;\n const broadcast = this.broadcasts.get(request.track.name);\n if (broadcast) {\n broadcast.updateTrack(request.track);\n this.emit('trackRequested', request.track.name);\n }\n }\n\n } catch (error) {\n console.warn('Error handling track requests:', error);\n this.handleError(error as Error);\n }\n}\n\n private async restartSubscriptions(): Promise<void> {\n if (!this.connection) return;\n\n const promises = Array.from(this.subscriptions.values()).map(subscription => \n subscription.start(this.connection!, this.config.namespace).catch(error => {\n console.error('Failed to restart subscription:', error);\n })\n );\n\n await Promise.allSettled(promises);\n }\n\n private async stopAllBroadcasts(): Promise<void> {\n this.broadcast?.close();\n this.broadcast = undefined;\n const promises = Array.from(this.broadcasts.values()).map(broadcast => \n broadcast.stop().catch(error => {\n console.warn('Error stopping broadcast:', error);\n })\n );\n\n await Promise.allSettled(promises);\n }\n\n private async stopAllSubscriptions(): Promise<void> {\n const promises = Array.from(this.subscriptions.values()).map(subscription => \n subscription.stop().catch(error => {\n console.warn('Error stopping subscription:', error);\n })\n );\n\n await Promise.allSettled(promises);\n }\n\n private handleDisconnection(): void {\n if (this.disposed) return; // Don't reconnect if disposed\n this.setState(SessionState.DISCONNECTED);\n this.scheduleReconnect();\n }\n\n private scheduleReconnect(): void {\n if (this.disposed || !this.config.reconnection || !this.doReconnect) return;\n\n const delay = this.config.reconnection?.delay || 1000;\n\n this.setState(SessionState.RECONNECTING);\n this.reconnectAttempts++;\n\n this.reconnectTimer = setTimeout(() => {\n if (this.disposed || !this.doReconnect) return;\n if (this.state !== SessionState.RECONNECTING) return;\n this.connect().catch(error => {\n console.error('Reconnection failed:', error);\n });\n }, delay);\n }\n\n private setState(newState: SessionState): void {\n if (this.disposed) return; // Don't change state if disposed\n if (this.state !== newState) {\n this.state = newState;\n this.emit('stateChange', this.status);\n }\n }\n\n private handleError(error: Error): void {\n if (this.disposed) return; // Don't emit errors if disposed\n this.lastError = error;\n this.emit('error', error);\n }\n\n public dispose(): void {\n // Mark as disposed to prevent any further operations\n this.disposed = true;\n \n // Immediately stop reconnection attempts\n this.doReconnect = false;\n \n // Clear any pending reconnect timer immediately\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = undefined;\n }\n \n // Disconnect (but don't await to keep dispose synchronous)\n this.disconnect().catch((error) => {\n console.warn('Error during session disconnect:', error);\n });\n this.removeAllListeners();\n\n this.subscriptions.forEach(sub => sub.dispose());\n this.broadcasts.forEach(bc => bc.dispose());\n this.subscriptions.clear();\n this.broadcasts.clear();\n }\n}"],"names":["EventEmitter","event","listener","eventListeners","args","error","SessionState","BroadcastState","SubscriptionState","MoQBroadcast","config","track","data","newGroup","newState","MoQSubscription","connection","namespace","broadcastPath","Path","framesInGroup","group","frame","receivedData","delay","_a","MoQSession","Connection","err","configs","trackNames","uniqueTrackNames","duplicates","name","index","desiredTracks","currentTracks","trackName","existing","_b","broadcast","subscription","status","received","namespacePath","announced","announcement","Broadcast","request","promises","sub","bc"],"mappings":";AAEO,MAAMA,EAAiE;AAAA,EAAvE,cAAA;AACL,SAAQ,gCAAgB,IAAA;AAAA,EAA8B;AAAA,EAEtD,GAAsBC,GAAUC,GAAsB;AACpD,IAAK,KAAK,UAAU,IAAID,CAAK,KAC3B,KAAK,UAAU,IAAIA,GAAO,oBAAI,KAAK,GAErC,KAAK,UAAU,IAAIA,CAAK,EAAG,IAAIC,CAAQ;AAAA,EACzC;AAAA,EAEA,IAAuBD,GAAUC,GAAsB;AACrD,UAAMC,IAAiB,KAAK,UAAU,IAAIF,CAAK;AAC/C,IAAIE,KACFA,EAAe,OAAOD,CAAQ;AAAA,EAElC;AAAA,EAEA,KAAwBD,MAAaG,GAA8B;AACjE,UAAMD,IAAiB,KAAK,UAAU,IAAIF,CAAK;AAC/C,IAAIE,KACFA,EAAe,QAAQ,CAAAD,MAAY;AACjC,UAAI;AACF,QAAAA,EAAS,GAAGE,CAAI;AAAA,MAClB,SAASC,GAAO;AACd,gBAAQ,MAAM,4BAA4BA,CAAK;AAAA,MACjD;AAAA,IACF,CAAC;AAAA,EAEL;AAAA,EAEA,mBAAsCJ,GAAiB;AACrD,IAAIA,IACF,KAAK,UAAU,OAAOA,CAAK,IAE3B,KAAK,UAAU,MAAA;AAAA,EAEnB;AACF;ACLO,IAAKK,sBAAAA,OACVA,EAAA,eAAe,gBACfA,EAAA,aAAa,cACbA,EAAA,YAAY,aACZA,EAAA,eAAe,gBACfA,EAAA,SAAS,UALCA,IAAAA,KAAA,CAAA,CAAA,GAQAC,sBAAAA,OACVA,EAAA,OAAO,QACPA,EAAA,eAAe,gBACfA,EAAA,QAAQ,SAHEA,IAAAA,KAAA,CAAA,CAAA,GAMAC,sBAAAA,OACVA,EAAA,UAAU,WACVA,EAAA,aAAa,cACbA,EAAA,WAAW,YACXA,EAAA,SAAS,UAJCA,IAAAA,KAAA,CAAA,CAAA;ACvCL,MAAMC,UAAqBT,EAA8B;AAAA,EAQ9D,YAAYU,GAAyB;AACnC,UAAA,GAPF,KAAQ,QAAwBH,EAAe,MAC/C,KAAQ,YAAY,GAOlB,KAAK,UAAUG;AAAA,EACjB;AAAA,EAEA,IAAI,SAA0B;AAC5B,WAAO;AAAA,MACL,OAAO,KAAK;AAAA,MACZ,WAAW,KAAK,QAAQ;AAAA,MACxB,WAAW,KAAK;AAAA,MAChB,WAAW,KAAK;AAAA,IAAA;AAAA,EAEpB;AAAA,EAEA,IAAI,SAA0B;AAC5B,WAAO,EAAE,GAAG,KAAK,QAAA;AAAA,EACnB;AAAA,EAEA,YAAYC,GAAoB;AAC9B,SAAK,QAAQA,GACTA,KACF,KAAK,SAASJ,EAAe,YAAY;AAAA,EAE7C;AAAA,EAEA,MAAM,KAAKK,GAAkBC,GAAkC;AAC7D,QAAI,KAAK,UAAUN,EAAe,gBAAgB,CAAC,KAAK;AACtD,YAAM,IAAI,MAAM,yBAAyB;AAG3C,QAAI;AACF,OAAIM,KAAY,CAAC,KAAK,WAChB,KAAK,SACP,KAAK,MAAM,MAAA,GAEb,KAAK,QAAQ,KAAK,MAAM,YAAA,IAE1B,MAAM,KAAK,MAAM,WAAWD,CAAI,GAChC,KAAK,aAAaA,EAAK;AAAA,IACzB,SAASP,GAAO;AACd,iBAAK,YAAYA,CAAc,GACzBA;AAAA,IACR;AAAA,EACF;AAAA,EAEA,MAAM,OAAsB;AAC1B,QAAI,KAAK,OAAO;AACd,UAAI;AACF,aAAK,MAAM,MAAA;AAAA,MACb,SAASA,GAAO;AACd,gBAAQ,KAAK,wBAAwBA,CAAK;AAAA,MAC5C;AACA,WAAK,QAAQ;AAAA,IACf;AAEA,SAAK,SAASE,EAAe,IAAI;AAAA,EACnC;AAAA,EAEQ,SAASO,GAAgC;AAC/C,IAAI,KAAK,UAAUA,MACjB,KAAK,QAAQA,GACb,KAAK,KAAK,eAAe,KAAK,MAAM;AAAA,EAExC;AAAA,EAEQ,YAAYT,GAAoB;AACtC,SAAK,YAAYA,GACjB,KAAK,SAASE,EAAe,KAAK,GAClC,KAAK,KAAK,SAASF,CAAK;AAAA,EAC1B;AAAA,EAEO,UAAgB;AACrB,SAAK,KAAA,EAAO,MAAM,QAAQ,KAAK,GAC/B,KAAK,mBAAA;AAAA,EACP;AACF;AClFO,MAAMU,UAAwBf,EAAiC;AAAA,EAYpE,YAAYU,GAA4B;AACtC,UAAA,GAXF,KAAQ,QAA2BF,EAAkB,SACrD,KAAQ,gBAAgB,GACxB,KAAQ,gBAAgB,GAUtB,KAAK,UAAUE;AAAA,EACjB;AAAA,EAEA,IAAI,SAA6B;AAC/B,WAAO;AAAA,MACL,OAAO,KAAK;AAAA,MACZ,WAAW,KAAK,QAAQ;AAAA,MACxB,eAAe,KAAK;AAAA,MACpB,eAAe,KAAK;AAAA,MACpB,WAAW,KAAK;AAAA,IAAA;AAAA,EAEpB;AAAA,EAEA,IAAI,SAA6B;AAC/B,WAAO,EAAE,GAAG,KAAK,QAAA;AAAA,EACnB;AAAA,EAEA,MAAM,MAAMM,GAAoCC,GAAkC;AAChF,SAAK,aAAaD,GAClB,KAAK,YAAYC;AACjB,QAAI;AACF,YAAM,KAAK,UAAUD,GAAYC,CAAS;AAAA,IAC5C,SAASZ,GAAO;AACd,WAAK,YAAYA,CAAc,GAC/B,KAAK,cAAcW,GAAYC,CAAS;AAAA,IAC1C;AAAA,EACF;AAAA,EAEA,MAAc,UAAUD,GAAoCC,GAAkC;AAC5F,SAAK,SAAST,EAAkB,OAAO;AAEvC,UAAMU,IAAgBC,EAAK,KAAKF,CAAS;AACzC,SAAK,YAAYD,EAAW,QAAQE,CAAa,GAGjD,KAAK,eAAe,KAAK,UAAU,UAAU,KAAK,QAAQ,WAAW,KAAK,QAAQ,YAAY,CAAC,GAC/F,KAAK,SAASV,EAAkB,UAAU,GAC1C,KAAK,gBAAgB,GAGrB,KAAK,WAAA;AAAA,EACP;AAAA,EAEA,MAAc,aAA4B;AACxC,QAAK,KAAK;AAEV,UAAI;AAEF,mBAAa;AACX,cAAIY,IAAgB;AACpB,gBAAMC,IAAQ,MAAM,KAAK,aAAa,UAAA;AACtC,cAAI,CAACA,EAAO;AAIZ,qBAAa;AACX,kBAAMC,IAAQ,MAAMD,EAAM,UAAA;AAC1B,gBAAI,CAACC,EAAO;AACZ,YAAAF,KAEA,KAAK,iBAAiBE,EAAM;AAC5B,kBAAMC,IAA6B;AAAA,cACjC,WAAW,KAAK,QAAQ;AAAA,cACxB,MAAMD;AAAA,cACN,WAAW,KAAK,IAAA;AAAA,cAChB,YAAYF;AAAA,YAAA;AAEd,iBAAK,KAAK,QAAQG,CAAY;AAAA,UAChC;AAAA,QACF;AAAA,MACF,SAASlB,GAAO;AACd,aAAK,YAAYA,CAAc,GAE3B,KAAK,cAAc,KAAK,aAC1B,KAAK,cAAc,KAAK,YAAY,KAAK,SAAS;AAAA,MAEtD;AAAA,EACF;AAAA,EAEQ,cAAcW,GAAoCC,GAAyB;;AACjF,UAAMO,MAAQC,IAAA,KAAK,QAAQ,UAAb,gBAAAA,EAAoB,UAAS;AAE3C,SAAK,SAASjB,EAAkB,QAAQ,GACxC,KAAK,iBAEL,KAAK,aAAa,WAAW,YAAY;AACvC,UAAI;AACF,cAAM,KAAK,UAAUQ,GAAYC,CAAS;AAAA,MAC5C,SAASZ,GAAO;AACd,aAAK,YAAYA,CAAc,GAC/B,KAAK,cAAcW,GAAYC,CAAS;AAAA,MAC1C;AAAA,IACF,GAAGO,CAAK;AAAA,EACV;AAAA,EAEA,MAAM,OAAsB;AAS1B,QARA,KAAK,aAAa,QAClB,KAAK,YAAY,QAEb,KAAK,eACP,aAAa,KAAK,UAAU,GAC5B,KAAK,aAAa,SAGhB,KAAK,cAAc;AACrB,UAAI;AACF,aAAK,aAAa,MAAA;AAAA,MACpB,SAASnB,GAAO;AACd,gBAAQ,KAAK,+BAA+BA,CAAK;AAAA,MACnD;AACA,WAAK,eAAe;AAAA,IACtB;AAEA,QAAI,KAAK,WAAW;AAClB,UAAI;AACF,aAAK,UAAU,MAAA;AAAA,MACjB,SAASA,GAAO;AACd,gBAAQ,KAAK,4BAA4BA,CAAK;AAAA,MAChD;AACA,WAAK,YAAY;AAAA,IACnB;AAEA,SAAK,SAASG,EAAkB,OAAO;AAAA,EACzC;AAAA,EAEQ,SAASM,GAAmC;AAClD,IAAI,KAAK,UAAUA,MACjB,KAAK,QAAQA,GACb,KAAK,KAAK,eAAe,KAAK,MAAM;AAAA,EAExC;AAAA,EAEQ,YAAYT,GAAoB;AACtC,SAAK,YAAYA,GACjB,KAAK,KAAK,SAASA,CAAK;AAAA,EAC1B;AAAA,EAEA,UAAgB;AACd,SAAK,KAAA,EAAO,MAAM,CAACA,MAAU;AAC3B,cAAQ,KAAK,yBAAyBA,CAAK;AAAA,IAC7C,CAAC,GACD,KAAK,mBAAA;AAAA,EACP;AACF;AC1JO,MAAMqB,UAAmB1B,EAA4B;AAAA,EAgB1D,YAAYU,GAA0B;;AACpC,UAAA,GAdF,KAAQ,QAAsBJ,EAAa,cAE3C,KAAQ,oBAAoB,GAI5B,KAAQ,iCAAiB,IAAA,GACzB,KAAQ,oCAAoB,IAAA,GAC5B,KAAQ,0CAA0B,IAAA,GAClC,KAAQ,cAAc,IAEtB,KAAQ,WAAW,IAIjB,KAAK,SAAS;AAAA,MACZ,GAAGI;AAAA,MACH,cAAc;AAAA,QACZ,OAAO,KAAK,MAAIe,IAAAf,EAAO,iBAAP,gBAAAe,EAAqB,UAAS,KAAM,GAAI;AAAA;AAAA,MAAA;AAAA,MAE1D,mBAAmBf,EAAO,qBAAqB;AAAA,IAAA,GAGjD,KAAK,MAAM,IAAI,IAAI,KAAK,OAAO,QAAQ;AAAA,EACzC;AAAA,EAEA,IAAI,SAAwB;AAC1B,WAAO;AAAA,MACL,OAAO,KAAK;AAAA,MACZ,mBAAmB,KAAK;AAAA,MACxB,WAAW,KAAK;AAAA,MAChB,aAAa,KAAK;AAAA,IAAA;AAAA,EAEtB;AAAA,EAEA,MAAM,UAAyB;AAC7B,QAAI,KAAK;AACP,YAAM,IAAI,MAAM,mCAAmC;AAGrD,QAAI,OAAK,UAAUJ,EAAa,cAAc,KAAK,UAAUA,EAAa,YAI1E;AAAA,WAAK,SAASA,EAAa,UAAU;AAErC,UAAI;AACF,aAAK,cAAc,IACnB,KAAK,aAAa,MAAMqB,EAAW,QAAQ,KAAK,KAAK;AAAA,UACnD,WAAW;AAAA,YACT,SAAS;AAAA,UAAA;AAAA,QACX,CACD,GAED,KAAK,SAASrB,EAAa,SAAS,GACpC,KAAK,kCAAkB,KAAA,GACvB,KAAK,oBAAoB,GAGzB,KAAK,WAAW,OAAO,KAAK,MAAM;AAEhC,UAAI,CAAC,KAAK,YAAY,KAAK,UAAUA,EAAa,aAChD,KAAK,oBAAA;AAAA,QAET,CAAC,GAGD,KAAK,2BAAA,GAGL,MAAM,KAAK,kBAAA,GACX,MAAM,KAAK,qBAAA;AAAA,MAEb,SAASD,GAAO;AACd,cAAMuB,IAAM,IAAI,MAAM,+BAAgCvB,EAAgB,OAAO,EAAE;AAC/E,mBAAK,YAAYuB,CAAG,GACpB,KAAK,kBAAA,GACCA;AAAA,MACR;AAAA;AAAA,EACF;AAAA,EAEA,MAAM,aAA4B;AAYhC,QAXA,KAAK,cAAc,IAEf,KAAK,mBACP,aAAa,KAAK,cAAc,GAChC,KAAK,iBAAiB,SAIxB,MAAM,KAAK,kBAAA,GACX,MAAM,KAAK,qBAAA,GAEP,KAAK,YAAY;AACnB,UAAI;AACF,aAAK,WAAW,MAAA;AAAA,MAClB,SAASvB,GAAO;AACd,gBAAQ,KAAK,6BAA6BA,CAAK;AAAA,MACjD;AACA,WAAK,aAAa;AAAA,IACpB;AAEA,SAAK,SAASC,EAAa,YAAY,GACvC,KAAK,cAAc;AAAA,EACrB;AAAA;AAAA;AAAA;AAAA,EAKA,4BAAsC;AACpC,WAAO,MAAM,KAAK,KAAK,WAAW,MAAM;AAAA,EAC1C;AAAA;AAAA;AAAA;AAAA,EAKA,+BAAyC;AACvC,WAAO,MAAM,KAAK,KAAK,cAAc,MAAM;AAAA,EAC7C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,iBAAiBuB,GAAkC;AAEjD,UAAMC,IAAaD,EAAQ,IAAI,CAAAnB,MAAUA,EAAO,SAAS,GACnDqB,IAAmB,IAAI,IAAID,CAAU;AAC3C,QAAIA,EAAW,WAAWC,EAAiB,MAAM;AAC/C,YAAMC,IAAaF,EAAW,OAAO,CAACG,GAAMC,MAAUJ,EAAW,QAAQG,CAAI,MAAMC,CAAK;AACxF,YAAM,IAAI,MAAM,mCAAmCF,EAAW,CAAC,CAAC,EAAE;AAAA,IACpE;AAEA,UAAMG,IAAgB,IAAI,IAAIN,EAAQ,IAAI,CAAAnB,MAAUA,EAAO,SAAS,CAAC,GAC/D0B,IAAgB,IAAI,IAAI,KAAK,WAAW,MAAM;AAGpD,eAAWC,KAAaD;AACtB,MAAKD,EAAc,IAAIE,CAAS,KAC9B,KAAK,iBAAiBA,CAAS;AAKnC,eAAW3B,KAAUmB,GAAS;AAC5B,YAAMS,IAAW,KAAK,WAAW,IAAI5B,EAAO,SAAS;AACrD,MAAK4B,IAKCA,EAAS,OAAO,aAAa5B,EAAO,aAGtC,KAAK,iBAAiBA,EAAO,SAAS,GACtC,KAAK,iBAAiBA,CAAM,KAP9B,KAAK,iBAAiBA,CAAM;AAAA,IAUhC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,oBAAoBmB,GAAqC;;AAEvD,UAAMC,IAAaD,EAAQ,IAAI,CAAAnB,MAAUA,EAAO,SAAS,GACnDqB,IAAmB,IAAI,IAAID,CAAU;AAC3C,QAAIA,EAAW,WAAWC,EAAiB,MAAM;AAC/C,YAAMC,IAAaF,EAAW,OAAO,CAACG,GAAMC,MAAUJ,EAAW,QAAQG,CAAI,MAAMC,CAAK;AACxF,YAAM,IAAI,MAAM,sCAAsCF,EAAW,CAAC,CAAC,EAAE;AAAA,IACvE;AAEA,UAAMG,IAAgB,IAAI,IAAIN,EAAQ,IAAI,CAAAnB,MAAUA,EAAO,SAAS,CAAC,GAC/D0B,IAAgB,IAAI,IAAI,KAAK,cAAc,MAAM;AAGvD,eAAWC,KAAaD;AACtB,MAAKD,EAAc,IAAIE,CAAS,KAC9B,KAAK,oBAAoBA,CAAS;AAKtC,eAAW3B,KAAUmB,GAAS;AAC5B,YAAMS,IAAW,KAAK,cAAc,IAAI5B,EAAO,SAAS;AACxD,MAAK4B,KAKCA,EAAS,OAAO,aAAa5B,EAAO,cACpCe,IAAAa,EAAS,OAAO,UAAhB,gBAAAb,EAAuB,aAAUc,IAAA7B,EAAO,UAAP,gBAAA6B,EAAc,YAGjD,KAAK,oBAAoB7B,EAAO,SAAS,GACzC,KAAK,oBAAoBA,CAAM,KARjC,KAAK,oBAAoBA,CAAM;AAAA,IAWnC;AAAA,EACF;AAAA,EAEA,yBAAmC;AACjC,WAAO,MAAM,KAAK,KAAK,mBAAmB;AAAA,EAC5C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,KAAK2B,GAAmBzB,GAAkBC,GAAkC;AAChF,UAAM2B,IAAY,KAAK,WAAW,IAAIH,CAAS;AAC/C,QAAI,CAACG;AACH,YAAM,IAAI,MAAM,iCAAiCH,CAAS,EAAE;AAE9D,UAAMG,EAAU,KAAK5B,GAAMC,CAAQ;AAAA,EACrC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,mBAAmBwB,GAAmB;AACpC,UAAMG,IAAY,KAAK,WAAW,IAAIH,CAAS;AAC/C,WAAOG,KAAA,gBAAAA,EAAW;AAAA,EACpB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,sBAAsBH,GAAmB;AACvC,UAAMI,IAAe,KAAK,cAAc,IAAIJ,CAAS;AACrD,WAAOI,KAAA,gBAAAA,EAAc;AAAA,EACvB;AAAA,EAEQ,iBAAiB/B,GAAuC;AAC9D,UAAM8B,IAAY,IAAI/B,EAAaC,CAAM;AACzC,gBAAK,WAAW,IAAIA,EAAO,WAAW8B,CAAS,GAG/CA,EAAU,GAAG,eAAe,CAACE,MAAW;AACtC,WAAK,KAAK,wBAAwBhC,EAAO,WAAWgC,CAAM;AAAA,IAC5D,CAAC,GAEDF,EAAU,GAAG,SAAS,CAACnC,MAAU;AAC/B,WAAK,KAAK,kBAAkBK,EAAO,WAAWL,CAAK;AAAA,IACrD,CAAC,GAED,KAAK,iBAAA,GAEEmC;AAAA,EACT;AAAA,EAEQ,oBAAoB9B,GAA6C;AACvE,UAAM+B,IAAe,IAAI1B,EAAgBL,CAAM;AAC/C,gBAAK,cAAc,IAAIA,EAAO,WAAW+B,CAAY,GAGrDA,EAAa,GAAG,QAAQ,CAACE,MAAa;AACpC,WAAK,KAAK,QAAQA,EAAS,WAAWA,EAAS,MAAMA,EAAS,UAAU;AAAA,IAC1E,CAAC,GAEDF,EAAa,GAAG,eAAe,CAACC,MAAW;AACzC,WAAK,KAAK,2BAA2BhC,EAAO,WAAWgC,CAAM;AAAA,IAC/D,CAAC,GAEDD,EAAa,GAAG,SAAS,CAACpC,MAAU;AAClC,WAAK,KAAK,qBAAqBK,EAAO,WAAWL,CAAK;AAAA,IACxD,CAAC,GAGG,KAAK,UAAUC,EAAa,aAAa,KAAK,cAChDmC,EAAa,MAAM,KAAK,YAAY,KAAK,OAAO,SAAS,EAAE,MAAM,CAAApC,MAAS;AACxE,cAAQ,MAAM,iCAAiCA,CAAK;AAAA,IACtD,CAAC,GAGIoC;AAAA,EACT;AAAA,EAEQ,iBAAiBJ,GAAyB;AAChD,UAAMG,IAAY,KAAK,WAAW,IAAIH,CAAS;AAC/C,IAAIG,MACFA,EAAU,KAAA,EAAO,MAAM,CAAAnC,MAAS;AAC9B,cAAQ,KAAK,6BAA6BA,CAAK;AAAA,IACjD,CAAC,GACD,KAAK,WAAW,OAAOgC,CAAS;AAAA,EAEpC;AAAA,EAEQ,oBAAoBA,GAAyB;AACnD,UAAMI,IAAe,KAAK,cAAc,IAAIJ,CAAS;AACrD,IAAII,MACFA,EAAa,KAAA,EAAO,MAAM,CAAApC,MAAS;AACjC,cAAQ,KAAK,gCAAgCA,CAAK;AAAA,IACpD,CAAC,GACD,KAAK,cAAc,OAAOgC,CAAS;AAAA,EAEvC;AAAA,EAEA,MAAc,6BAA4C;AACxD,QAAK,KAAK;AAEV,UAAI;AAEF,cAAMO,IAAgBzB,EAAK,KAAK,KAAK,OAAO,SAAS,GAC/C0B,IAAY,KAAK,WAAW,UAAUD,CAAa;AAGzD,aAAK,qBAAqBC,CAAS;AAAA,MAErC,SAASxC,GAAO;AACd,gBAAQ,MAAM,2CAA2CA,CAAK;AAAA,MAChE;AAAA,EACF;AAAA,EAEA,MAAc,qBAAqBwC,GAA2E;AAC5G,QAAI;AACF,aAEM,MAAK,YAFF;AAIP,cAAMC,IAAe,MAAMD,EAAU,KAAA;AAIrC,YAHI,CAACC,KAGD,KAAK,SAAU;AAEnB,QAAIA,EAAa,UACf,KAAK,oBAAoB,IAAIA,EAAa,IAAI,GAC9C,KAAK,KAAK,sBAAsB;AAAA,UAC9B,MAAMA,EAAa;AAAA,UACnB,QAAQ;AAAA,QAAA,CACT,MAED,KAAK,oBAAoB,OAAOA,EAAa,IAAI,GACjD,KAAK,KAAK,sBAAsB;AAAA,UAC9B,MAAMA,EAAa;AAAA,UACnB,QAAQ;AAAA,QAAA,CACT;AAAA,MAEL;AAAA,IACF,SAASzC,GAAO;AAEd,MAAK,KAAK,YACR,QAAQ,MAAM,mCAAmCA,CAAK;AAAA,IAE1D;AAAA,EACF;AAAA,EAEA,MAAc,oBAAmC;AAC/C,UAAM,KAAK,kBAAA,GACX,KAAK,iBAAA;AAAA,EACP;AAAA,EAEQ,mBAAyB;AAC/B,IAAI,KAAK,aACL,KAAK,WAAW,SAAS,MAE7B,KAAK,YAAY,IAAI0C,EAAA,GACjB,KAAK,eACP,KAAK,WAAW,QAAQ5B,EAAK,KAAK,KAAK,OAAO,SAAS,GAAG,KAAK,SAAS,GACxE,KAAK,oBAAA,EAAsB,MAAM,CAAAd,MAAS;AACxC,cAAQ,MAAM,kCAAkCA,CAAK;AAAA,IACvD,CAAC;AAAA,EAEL;AAAA,EAEA,MAAc,sBAAqC;AACnD,QAAK,KAAK;AAEV,UAAI;AACF,mBAAS;AACP,gBAAM2C,IAAU,MAAM,KAAK,UAAU,UAAA;AACrC,cAAI,CAACA,EAAS;AACd,gBAAMR,IAAY,KAAK,WAAW,IAAIQ,EAAQ,MAAM,IAAI;AACxD,UAAIR,MACFA,EAAU,YAAYQ,EAAQ,KAAK,GACnC,KAAK,KAAK,kBAAkBA,EAAQ,MAAM,IAAI;AAAA,QAElD;AAAA,MAEF,SAAS3C,GAAO;AACd,gBAAQ,KAAK,kCAAkCA,CAAK,GACpD,KAAK,YAAYA,CAAc;AAAA,MACjC;AAAA,EACF;AAAA,EAEE,MAAc,uBAAsC;AAClD,QAAI,CAAC,KAAK,WAAY;AAEtB,UAAM4C,IAAW,MAAM,KAAK,KAAK,cAAc,OAAA,CAAQ,EAAE;AAAA,MAAI,CAAAR,MAC3DA,EAAa,MAAM,KAAK,YAAa,KAAK,OAAO,SAAS,EAAE,MAAM,CAAApC,MAAS;AACzE,gBAAQ,MAAM,mCAAmCA,CAAK;AAAA,MACxD,CAAC;AAAA,IAAA;AAGH,UAAM,QAAQ,WAAW4C,CAAQ;AAAA,EACnC;AAAA,EAEA,MAAc,oBAAmC;;AAC/C,KAAAxB,IAAA,KAAK,cAAL,QAAAA,EAAgB,SAChB,KAAK,YAAY;AACjB,UAAMwB,IAAW,MAAM,KAAK,KAAK,WAAW,OAAA,CAAQ,EAAE;AAAA,MAAI,CAAAT,MACxDA,EAAU,KAAA,EAAO,MAAM,CAAAnC,MAAS;AAC9B,gBAAQ,KAAK,6BAA6BA,CAAK;AAAA,MACjD,CAAC;AAAA,IAAA;AAGH,UAAM,QAAQ,WAAW4C,CAAQ;AAAA,EACnC;AAAA,EAEA,MAAc,uBAAsC;AAClD,UAAMA,IAAW,MAAM,KAAK,KAAK,cAAc,OAAA,CAAQ,EAAE;AAAA,MAAI,CAAAR,MAC3DA,EAAa,KAAA,EAAO,MAAM,CAAApC,MAAS;AACjC,gBAAQ,KAAK,gCAAgCA,CAAK;AAAA,MACpD,CAAC;AAAA,IAAA;AAGH,UAAM,QAAQ,WAAW4C,CAAQ;AAAA,EACnC;AAAA,EAEQ,sBAA4B;AAClC,IAAI,KAAK,aACT,KAAK,SAAS3C,EAAa,YAAY,GACvC,KAAK,kBAAA;AAAA,EACP;AAAA,EAEQ,oBAA0B;;AAChC,QAAI,KAAK,YAAY,CAAC,KAAK,OAAO,gBAAgB,CAAC,KAAK,YAAa;AAErE,UAAMkB,MAAQC,IAAA,KAAK,OAAO,iBAAZ,gBAAAA,EAA0B,UAAS;AAEjD,SAAK,SAASnB,EAAa,YAAY,GACvC,KAAK,qBAEL,KAAK,iBAAiB,WAAW,MAAM;AACrC,MAAI,KAAK,YAAY,CAAC,KAAK,eACvB,KAAK,UAAUA,EAAa,gBAChC,KAAK,QAAA,EAAU,MAAM,CAAAD,MAAS;AAC5B,gBAAQ,MAAM,wBAAwBA,CAAK;AAAA,MAC7C,CAAC;AAAA,IACH,GAAGmB,CAAK;AAAA,EACV;AAAA,EAEQ,SAASV,GAA8B;AAC7C,IAAI,KAAK,YACL,KAAK,UAAUA,MACjB,KAAK,QAAQA,GACb,KAAK,KAAK,eAAe,KAAK,MAAM;AAAA,EAExC;AAAA,EAEQ,YAAYT,GAAoB;AACtC,IAAI,KAAK,aACT,KAAK,YAAYA,GACjB,KAAK,KAAK,SAASA,CAAK;AAAA,EAC1B;AAAA,EAEO,UAAgB;AAErB,SAAK,WAAW,IAGhB,KAAK,cAAc,IAGf,KAAK,mBACP,aAAa,KAAK,cAAc,GAChC,KAAK,iBAAiB,SAIxB,KAAK,WAAA,EAAa,MAAM,CAACA,MAAU;AACjC,cAAQ,KAAK,oCAAoCA,CAAK;AAAA,IACxD,CAAC,GACD,KAAK,mBAAA,GAEL,KAAK,cAAc,QAAQ,CAAA6C,MAAOA,EAAI,SAAS,GAC/C,KAAK,WAAW,QAAQ,CAAAC,MAAMA,EAAG,SAAS,GAC1C,KAAK,cAAc,MAAA,GACnB,KAAK,WAAW,MAAA;AAAA,EAClB;AACF;"}
|
package/dist/session.d.ts
CHANGED
|
@@ -14,6 +14,7 @@ export declare class MoQSession extends EventEmitter<SessionEvents> {
|
|
|
14
14
|
private announcedBroadcasts;
|
|
15
15
|
private doReconnect;
|
|
16
16
|
private broadcast?;
|
|
17
|
+
private disposed;
|
|
17
18
|
constructor(config: MoQSessionConfig);
|
|
18
19
|
get status(): SessionStatus;
|
|
19
20
|
connect(): Promise<void>;
|
package/dist/session.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAG/C,OAAO,EACL,gBAAgB,EAEhB,aAAa,EACb,aAAa,EACb,eAAe,EACf,kBAAkB,EACnB,MAAM,SAAS,CAAC;AAEjB,qBAAa,UAAW,SAAQ,YAAY,CAAC,aAAa,CAAC;IACzD,OAAO,CAAC,MAAM,CAAmB;IACjC,OAAO,CAAC,GAAG,CAAM;IACjB,OAAO,CAAC,KAAK,CAA2C;IACxD,OAAO,CAAC,UAAU,CAAC,CAAyB;IAC5C,OAAO,CAAC,iBAAiB,CAAK;IAC9B,OAAO,CAAC,SAAS,CAAC,CAAQ;IAC1B,OAAO,CAAC,WAAW,CAAC,CAAO;IAC3B,OAAO,CAAC,cAAc,CAAC,CAAgC;IACvD,OAAO,CAAC,UAAU,CAAmC;IACrD,OAAO,CAAC,aAAa,CAAsC;IAC3D,OAAO,CAAC,mBAAmB,CAAqB;IAChD,OAAO,CAAC,WAAW,CAAQ;IAC3B,OAAO,CAAC,SAAS,CAAC,CAAY;
|
|
1
|
+
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAG/C,OAAO,EACL,gBAAgB,EAEhB,aAAa,EACb,aAAa,EACb,eAAe,EACf,kBAAkB,EACnB,MAAM,SAAS,CAAC;AAEjB,qBAAa,UAAW,SAAQ,YAAY,CAAC,aAAa,CAAC;IACzD,OAAO,CAAC,MAAM,CAAmB;IACjC,OAAO,CAAC,GAAG,CAAM;IACjB,OAAO,CAAC,KAAK,CAA2C;IACxD,OAAO,CAAC,UAAU,CAAC,CAAyB;IAC5C,OAAO,CAAC,iBAAiB,CAAK;IAC9B,OAAO,CAAC,SAAS,CAAC,CAAQ;IAC1B,OAAO,CAAC,WAAW,CAAC,CAAO;IAC3B,OAAO,CAAC,cAAc,CAAC,CAAgC;IACvD,OAAO,CAAC,UAAU,CAAmC;IACrD,OAAO,CAAC,aAAa,CAAsC;IAC3D,OAAO,CAAC,mBAAmB,CAAqB;IAChD,OAAO,CAAC,WAAW,CAAQ;IAC3B,OAAO,CAAC,SAAS,CAAC,CAAY;IAC9B,OAAO,CAAC,QAAQ,CAAS;gBAEb,MAAM,EAAE,gBAAgB;IAapC,IAAI,MAAM,IAAI,aAAa,CAO1B;IAEK,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IA8CxB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAyBjC;;OAEG;IACH,yBAAyB,IAAI,MAAM,EAAE;IAIrC;;OAEG;IACH,4BAA4B,IAAI,MAAM,EAAE;IAIxC;;;;OAIG;IACH,gBAAgB,CAAC,OAAO,EAAE,eAAe,EAAE,GAAG,IAAI;IAqClD;;;;OAIG;IACH,mBAAmB,CAAC,OAAO,EAAE,kBAAkB,EAAE,GAAG,IAAI;IAsCxD,sBAAsB,IAAI,MAAM,EAAE;IAIlC;;;;OAIG;IACG,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAQjF;;;OAGG;IACH,kBAAkB,CAAC,SAAS,EAAE,MAAM;IAKpC;;;OAGG;IACH,qBAAqB,CAAC,SAAS,EAAE,MAAM;IAKvC,OAAO,CAAC,gBAAgB;IAkBxB,OAAO,CAAC,mBAAmB;IA2B3B,OAAO,CAAC,gBAAgB;IAUxB,OAAO,CAAC,mBAAmB;YAUb,0BAA0B;YAgB1B,oBAAoB;YAkCpB,iBAAiB;IAK/B,OAAO,CAAC,gBAAgB;YAaV,mBAAmB;YAoBnB,oBAAoB;YAYpB,iBAAiB;YAYjB,oBAAoB;IAUlC,OAAO,CAAC,mBAAmB;IAM3B,OAAO,CAAC,iBAAiB;IAiBzB,OAAO,CAAC,QAAQ;IAQhB,OAAO,CAAC,WAAW;IAMZ,OAAO,IAAI,IAAI;CAwBvB"}
|