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 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
@@ -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":"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"}
package/dist/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
- import { Path as m, Connection as b, Broadcast as E } from "@kixelated/moq";
2
- class p {
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 (n) {
19
- console.error("Error in event listener:", n);
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 c = /* @__PURE__ */ ((r) => (r.DISCONNECTED = "disconnected", r.CONNECTING = "connecting", r.CONNECTED = "connected", r.RECONNECTING = "reconnecting", r.FAILED = "failed", r))(c || {}), d = /* @__PURE__ */ ((r) => (r.IDLE = "idle", r.BROADCASTING = "broadcasting", r.ERROR = "error", r))(d || {}), l = /* @__PURE__ */ ((r) => (r.PENDING = "pending", r.SUBSCRIBED = "subscribed", r.RETRYING = "retrying", r.FAILED = "failed", r))(l || {});
28
- class y extends p {
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 p {
76
+ class N extends m {
77
77
  constructor(t) {
78
- super(), this.state = l.PENDING, this.bytesReceived = 0, this.retryAttempts = 0, this._config = t;
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(l.PENDING);
102
- const e = m.from(s);
103
- this.broadcast = t.consume(e), this.subscription = this.broadcast.subscribe(this._config.trackName, this._config.priority || 0), this.setState(l.SUBSCRIBED), this.retryAttempts = 0, this.readFrames();
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(l.RETRYING), this.retryAttempts++, this.retryTimer = setTimeout(async () => {
132
+ this.setState(u.RETRYING), this.retryAttempts++, this.retryTimer = setTimeout(async () => {
133
133
  try {
134
134
  await this.subscribe(t, s);
135
- } catch (n) {
136
- this.handleError(n), this.scheduleRetry(t, s);
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(l.PENDING);
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 p {
171
+ class k extends m {
172
172
  constructor(t) {
173
173
  var s;
174
- super(), this.state = c.DISCONNECTED, this.reconnectAttempts = 0, this.broadcasts = /* @__PURE__ */ new Map(), this.subscriptions = /* @__PURE__ */ new Map(), this.announcedBroadcasts = /* @__PURE__ */ new Set(), this.doReconnect = !0, this.config = {
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 (!(this.state === c.CONNECTING || this.state === c.CONNECTED)) {
193
- this.setState(c.CONNECTING);
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(c.CONNECTED), this.connectedAt = /* @__PURE__ */ new Date(), this.reconnectAttempts = 0, this.connection.closed.then(() => {
200
- this.state === c.CONNECTED && this.handleDisconnection();
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
- throw this.handleError(t), this.scheduleReconnect(), t;
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(c.DISCONNECTED), this.connectedAt = void 0;
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)), n = new Set(this.broadcasts.keys());
242
- for (const i of n)
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((u, f) => s.indexOf(u) !== f);
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)), n = new Set(this.subscriptions.keys());
262
- for (const a of n)
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 u = this.subscriptions.get(a.trackName);
266
- u ? (u.config.priority !== a.priority || ((i = u.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);
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 === c.CONNECTED && this.connection && s.start(this.connection, this.config.namespace).catch((e) => {
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 = m.from(this.config.namespace), s = this.connection.announced(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(m.from(this.config.namespace), this.broadcast), this.handleTrackRequests().catch((t) => {
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(c.DISCONNECTED), this.scheduleReconnect();
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(c.RECONNECTING), this.reconnectAttempts++, this.reconnectTimer = setTimeout(() => {
413
- this.doReconnect && this.state === c.RECONNECTING && this.connect().catch((e) => {
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
- c as SessionState,
436
- l as SubscriptionState,
438
+ n as SessionState,
439
+ u as SubscriptionState,
437
440
  k as default
438
441
  };
439
442
  //# sourceMappingURL=index.mjs.map
@@ -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":"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"}
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>;
@@ -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;gBAElB,MAAM,EAAE,gBAAgB;IAapC,IAAI,MAAM,IAAI,aAAa,CAO1B;IAEK,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAwCxB,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;YAyBpB,iBAAiB;IAK/B,OAAO,CAAC,gBAAgB;YAaV,mBAAmB;YAoBnB,oBAAoB;YAYpB,iBAAiB;YAYjB,oBAAoB;IAUlC,OAAO,CAAC,mBAAmB;IAK3B,OAAO,CAAC,iBAAiB;IAiBzB,OAAO,CAAC,QAAQ;IAOhB,OAAO,CAAC,WAAW;IAKZ,OAAO,IAAI,IAAI;CAqBvB"}
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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "stinky-moq-js",
3
- "version": "0.1.10",
3
+ "version": "0.1.12",
4
4
  "description": "A TypeScript library for Media over Quic (MoQ) with session management and simple API",
5
5
  "main": "dist/index.cjs",
6
6
  "types": "dist/index.d.ts",