stinky-moq-js 0.1.12 → 0.1.13
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/broadcast.d.ts.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +31 -31
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/dist/broadcast.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"broadcast.d.ts","sourceRoot":"","sources":["../src/broadcast.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EACL,eAAe,EAEf,eAAe,EACf,eAAe,EAChB,MAAM,SAAS,CAAC;AAEjB,qBAAa,YAAa,SAAQ,YAAY,CAAC,eAAe,CAAC;IAC7D,OAAO,CAAC,OAAO,CAAkB;IACjC,OAAO,CAAC,KAAK,CAAuC;IACpD,OAAO,CAAC,SAAS,CAAK;IACtB,OAAO,CAAC,SAAS,CAAC,CAAQ;IAC1B,OAAO,CAAC,KAAK,CAAC,CAAQ;IACtB,OAAO,CAAC,KAAK,CAAC,CAAQ;gBAEV,MAAM,EAAE,eAAe;IAKnC,IAAI,MAAM,IAAI,eAAe,CAO5B;IAED,IAAI,MAAM,IAAI,eAAe,CAE5B;IAED,WAAW,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI;
|
|
1
|
+
{"version":3,"file":"broadcast.d.ts","sourceRoot":"","sources":["../src/broadcast.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EACL,eAAe,EAEf,eAAe,EACf,eAAe,EAChB,MAAM,SAAS,CAAC;AAEjB,qBAAa,YAAa,SAAQ,YAAY,CAAC,eAAe,CAAC;IAC7D,OAAO,CAAC,OAAO,CAAkB;IACjC,OAAO,CAAC,KAAK,CAAuC;IACpD,OAAO,CAAC,SAAS,CAAK;IACtB,OAAO,CAAC,SAAS,CAAC,CAAQ;IAC1B,OAAO,CAAC,KAAK,CAAC,CAAQ;IACtB,OAAO,CAAC,KAAK,CAAC,CAAQ;gBAEV,MAAM,EAAE,eAAe;IAKnC,IAAI,MAAM,IAAI,eAAe,CAO5B;IAED,IAAI,MAAM,IAAI,eAAe,CAE5B;IAED,WAAW,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI;IAUzB,IAAI,CAAC,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAqBxD,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAa3B,OAAO,CAAC,QAAQ;IAOhB,OAAO,CAAC,WAAW;IAMZ,OAAO,IAAI,IAAI;CAIvB"}
|
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(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;
|
|
1
|
+
"use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const l=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),this.group=new l.Group(Math.floor(Math.random()*1e5)),t.writeGroup(this.group))}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(),console.log("Created new group with sequence number:",this.group.sequence)),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=l.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 l.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((p,y)=>s.indexOf(p)!==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 p=this.subscriptions.get(o.trackName);p?(p.config.priority!==o.priority||((i=p.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=l.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 l.Broadcast,this.connection&&(this.connection.publish(l.Path.from(this.config.namespace),this.broadcast),this.handleTrackRequests().catch(t=>{console.error("Error handling track requests:",t)})))}async handleTrackRequests(){if(this.broadcast)try{for(;;){const t=await this.broadcast.requested();if(!t)return;const s=this.broadcasts.get(t.track.name);s&&(s.updateTrack(t.track),this.emit("trackRequested",t.track.name))}}catch(t){console.warn("Error handling track requests:",t),this.handleError(t)}}async restartSubscriptions(){if(!this.connection)return;const t=Array.from(this.subscriptions.values()).map(s=>s.start(this.connection,this.config.namespace).catch(e=>{console.error("Failed to restart subscription:",e)}));await Promise.allSettled(t)}async stopAllBroadcasts(){var s;(s=this.broadcast)==null||s.close(),this.broadcast=void 0;const t=Array.from(this.broadcasts.values()).map(e=>e.stop().catch(a=>{console.warn("Error stopping broadcast:",a)}));await Promise.allSettled(t)}async stopAllSubscriptions(){const t=Array.from(this.subscriptions.values()).map(s=>s.stop().catch(e=>{console.warn("Error stopping subscription:",e)}));await Promise.allSettled(t)}handleDisconnection(){this.disposed||(this.setState(n.DISCONNECTED),this.scheduleReconnect())}scheduleReconnect(){var s;if(this.disposed||!this.config.reconnection||!this.doReconnect)return;const t=((s=this.config.reconnection)==null?void 0:s.delay)||1e3;this.setState(n.RECONNECTING),this.reconnectAttempts++,this.reconnectTimer=setTimeout(()=>{this.disposed||!this.doReconnect||this.state===n.RECONNECTING&&this.connect().catch(e=>{console.error("Reconnection failed:",e)})},t)}setState(t){this.disposed||this.state!==t&&(this.state=t,this.emit("stateChange",this.status))}handleError(t){this.disposed||(this.lastError=t,this.emit("error",t))}dispose(){this.disposed=!0,this.doReconnect=!1,this.reconnectTimer&&(clearTimeout(this.reconnectTimer),this.reconnectTimer=void 0),this.disconnect().catch(t=>{console.warn("Error during session disconnect:",t)}),this.removeAllListeners(),this.subscriptions.forEach(t=>t.dispose()),this.broadcasts.forEach(t=>t.dispose()),this.subscriptions.clear(),this.broadcasts.clear()}}exports.BroadcastState=d;exports.MoQBroadcast=f;exports.MoQSession=E;exports.MoQSubscription=b;exports.SessionState=n;exports.SubscriptionState=u;exports.default=E;
|
|
2
2
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","sources":["../src/event-emitter.ts","../src/types.ts","../src/broadcast.ts","../src/subscription.ts","../src/session.ts"],"sourcesContent":["// Simple event emitter for type-safe events\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport class EventEmitter<T extends Record<string, (...args: any[]) => void>> {\n private listeners = new Map<keyof T, Set<T[keyof T]>>();\n\n on<K extends keyof T>(event: K, listener: T[K]): void {\n if (!this.listeners.has(event)) {\n this.listeners.set(event, new Set());\n }\n this.listeners.get(event)!.add(listener);\n }\n\n off<K extends keyof T>(event: K, listener: T[K]): void {\n const eventListeners = this.listeners.get(event);\n if (eventListeners) {\n eventListeners.delete(listener);\n }\n }\n\n emit<K extends keyof T>(event: K, ...args: Parameters<T[K]>): void {\n const eventListeners = this.listeners.get(event);\n if (eventListeners) {\n eventListeners.forEach(listener => {\n try {\n listener(...args);\n } catch (error) {\n console.error('Error in event listener:', error);\n }\n });\n }\n }\n\n removeAllListeners<K extends keyof T>(event?: K): void {\n if (event) {\n this.listeners.delete(event);\n } else {\n this.listeners.clear();\n }\n }\n}","// Types for the library\nexport interface MoQSessionConfig {\n /** URL of the MoQ relay server */\n relayUrl: string;\n /** MoQ namespace (broadcast name) */\n namespace: string;\n /** Reconnection configuration */\n reconnection?: {\n /** Delay between reconnection attempts in ms (minimum: 1000) */\n delay?: number;\n };\n /** Connection timeout in ms (default: 10000) */\n connectionTimeout?: number;\n}\n\nexport interface BroadcastConfig {\n /** Track name for the broadcast */\n trackName: string;\n /** Priority for the track (default: 0) */\n priority?: number;\n}\n\nexport interface SubscriptionConfig {\n /** Track name to subscribe to */\n trackName: string;\n /** Priority for the subscription (default: 0) */\n priority?: number;\n /** Retry configuration for failed subscriptions */\n retry?: {\n /** Delay between retry attempts in ms (default: 2000) */\n delay?: number;\n };\n}\n\nexport enum SessionState {\n DISCONNECTED = 'disconnected',\n CONNECTING = 'connecting',\n CONNECTED = 'connected',\n RECONNECTING = 'reconnecting',\n FAILED = 'failed'\n}\n\nexport enum BroadcastState {\n IDLE = 'idle',\n BROADCASTING = 'broadcasting',\n ERROR = 'error'\n}\n\nexport enum SubscriptionState {\n PENDING = 'pending',\n SUBSCRIBED = 'subscribed',\n RETRYING = 'retrying',\n FAILED = 'failed'\n}\n\nexport interface SessionStatus {\n state: SessionState;\n reconnectAttempts: number;\n lastError?: Error;\n connectedAt?: Date;\n}\n\nexport interface BroadcastStatus {\n state: BroadcastState;\n trackName: string;\n bytesSent: number;\n lastError?: Error;\n}\n\nexport interface SubscriptionStatus {\n state: SubscriptionState;\n trackName: string;\n bytesReceived: number;\n retryAttempts: number;\n lastError?: Error;\n}\n\nexport interface DataReceived {\n trackName: string;\n data: Uint8Array;\n timestamp: number;\n frameIndex: number;\n}\n\n// Event types\nexport interface BroadcastAnnouncement {\n path: string;\n active: boolean;\n}\n\nexport interface SessionEvents {\n stateChange: (status: SessionStatus) => void;\n error: (error: Error) => void;\n broadcastAnnounced: (announcement: BroadcastAnnouncement) => void;\n data: (trackName: string, data: Uint8Array, frameIndex: number) => void;\n broadcastStateChange: (trackName: string, status: BroadcastStatus) => void;\n subscriptionStateChange: (trackName: string, status: SubscriptionStatus) => void;\n broadcastError: (trackName: string, error: Error) => void;\n subscriptionError: (trackName: string, error: Error) => void;\n trackRequested: (trackName: string) => void;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n [key: string]: (...args: any[]) => void;\n}\n\nexport interface BroadcastEvents {\n stateChange: (status: BroadcastStatus) => void;\n error: (error: Error) => void;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n [key: string]: (...args: any[]) => void;\n}\n\nexport interface SubscriptionEvents {\n stateChange: (status: SubscriptionStatus) => void;\n data: (data: DataReceived) => void;\n error: (error: Error) => void;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n [key: string]: (...args: any[]) => void;\n}","import { Group, Track } from '@kixelated/moq';\nimport { EventEmitter } from './event-emitter';\nimport {\n BroadcastConfig,\n BroadcastState,\n BroadcastStatus,\n BroadcastEvents\n} from './types';\n\nexport class MoQBroadcast extends EventEmitter<BroadcastEvents> {\n private _config: BroadcastConfig;\n private state: BroadcastState = BroadcastState.IDLE;\n private bytesSent = 0;\n private lastError?: Error;\n private track?: Track;\n private group?: Group;\n\n constructor(config: BroadcastConfig) {\n super();\n this._config = config;\n }\n\n get status(): BroadcastStatus {\n return {\n state: this.state,\n trackName: this._config.trackName,\n bytesSent: this.bytesSent,\n lastError: this.lastError\n };\n }\n\n get config(): BroadcastConfig {\n return { ...this._config };\n }\n\n updateTrack(track: Track): void {\n this.track = track;\n if (track) {\n this.setState(BroadcastState.BROADCASTING);\n }\n }\n\n async send(data: Uint8Array, newGroup: boolean): Promise<void> {\n if (this.state !== BroadcastState.BROADCASTING || !this.track) {\n throw new Error('Broadcast is not active');\n }\n\n try {\n if (newGroup || !this.group) {\n if (this.group) {\n this.group.close();\n }\n this.group = this.track.appendGroup();\n }\n await this.group.writeFrame(data);\n this.bytesSent += data.length;\n } catch (error) {\n this.handleError(error as Error);\n throw error;\n }\n }\n\n async stop(): Promise<void> {\n if (this.track) {\n try {\n this.track.close();\n } catch (error) {\n console.warn('Error closing track:', error);\n }\n this.track = undefined;\n }\n \n this.setState(BroadcastState.IDLE);\n }\n\n private setState(newState: BroadcastState): void {\n if (this.state !== newState) {\n this.state = newState;\n this.emit('stateChange', this.status);\n }\n }\n\n private handleError(error: Error): void {\n this.lastError = error;\n this.setState(BroadcastState.ERROR);\n this.emit('error', error);\n }\n\n public dispose(): void {\n this.stop().catch(console.error);\n this.removeAllListeners();\n }\n}","import { Broadcast, Track, Connection, Path } from '@kixelated/moq';\nimport { EventEmitter } from './event-emitter';\nimport {\n SubscriptionConfig,\n SubscriptionState,\n SubscriptionStatus,\n SubscriptionEvents,\n DataReceived\n} from './types';\n\nexport class MoQSubscription extends EventEmitter<SubscriptionEvents> {\n private _config: SubscriptionConfig;\n private state: SubscriptionState = SubscriptionState.PENDING;\n private bytesReceived = 0;\n private retryAttempts = 0;\n private lastError?: Error;\n private subscription?: Track;\n private broadcast?: Broadcast;\n private retryTimer?: ReturnType<typeof setTimeout>;\n private connection?: Connection.Established;\n private namespace?: string;\n\n constructor(config: SubscriptionConfig) {\n super();\n this._config = config;\n }\n\n get status(): SubscriptionStatus {\n return {\n state: this.state,\n trackName: this._config.trackName,\n bytesReceived: this.bytesReceived,\n retryAttempts: this.retryAttempts,\n lastError: this.lastError\n };\n }\n\n get config(): SubscriptionConfig {\n return { ...this._config };\n }\n\n async start(connection: Connection.Established, namespace: string): Promise<void> {\n this.connection = connection;\n this.namespace = namespace;\n try {\n await this.subscribe(connection, namespace);\n } catch (error) {\n this.handleError(error as Error);\n this.scheduleRetry(connection, namespace);\n }\n }\n\n private async subscribe(connection: Connection.Established, namespace: string): Promise<void> {\n this.setState(SubscriptionState.PENDING);\n\n const broadcastPath = Path.from(namespace);\n this.broadcast = connection.consume(broadcastPath);\n\n // Subscribe to the specific track within the broadcast\n this.subscription = this.broadcast.subscribe(this._config.trackName, this._config.priority || 0);\n this.setState(SubscriptionState.SUBSCRIBED);\n this.retryAttempts = 0;\n\n // Set up data reception\n this.readFrames();\n }\n\n private async readFrames(): Promise<void> {\n if (!this.subscription) return;\n\n try {\n // eslint-disable-next-line no-constant-condition\n while (true) {\n let framesInGroup = 0;\n const group = await this.subscription.nextGroup();\n if (!group) break; // Track is closed\n\n // Read all frames from the group\n // eslint-disable-next-line no-constant-condition\n while (true) {\n const frame = await group.readFrame();\n if (!frame) break; // Group is finished\n framesInGroup++;\n\n this.bytesReceived += frame.length;\n const receivedData: DataReceived = {\n trackName: this._config.trackName,\n data: frame,\n timestamp: Date.now(),\n frameIndex: framesInGroup,\n };\n this.emit('data', receivedData);\n }\n }\n } catch (error) {\n this.handleError(error as Error);\n // Trigger retry when stream gets reset/closed\n if (this.connection && this.namespace) {\n this.scheduleRetry(this.connection, this.namespace);\n }\n }\n }\n \n private scheduleRetry(connection: Connection.Established, namespace: string): void {\n const delay = this._config.retry?.delay || 2000;\n\n this.setState(SubscriptionState.RETRYING);\n this.retryAttempts++;\n\n this.retryTimer = setTimeout(async () => {\n try {\n await this.subscribe(connection, namespace);\n } catch (error) {\n this.handleError(error as Error);\n this.scheduleRetry(connection, namespace);\n }\n }, delay);\n }\n\n async stop(): Promise<void> {\n this.connection = undefined;\n this.namespace = undefined;\n \n if (this.retryTimer) {\n clearTimeout(this.retryTimer);\n this.retryTimer = undefined;\n }\n\n if (this.subscription) {\n try {\n this.subscription.close();\n } catch (error) {\n console.warn('Error closing subscription:', error);\n }\n this.subscription = undefined;\n }\n\n if (this.broadcast) {\n try {\n this.broadcast.close();\n } catch (error) {\n console.warn('Error closing broadcast:', error);\n }\n this.broadcast = undefined;\n }\n\n this.setState(SubscriptionState.PENDING);\n }\n\n private setState(newState: SubscriptionState): void {\n if (this.state !== newState) {\n this.state = newState;\n this.emit('stateChange', this.status);\n }\n }\n\n private handleError(error: Error): void {\n this.lastError = error;\n this.emit('error', error);\n }\n\n dispose(): void {\n this.stop().catch((error) => {\n console.warn('Error during dispose:', error);\n });\n this.removeAllListeners();\n }\n}","import { Broadcast, Connection, Path } from '@kixelated/moq';\nimport { EventEmitter } from './event-emitter';\nimport { MoQBroadcast } from './broadcast';\nimport { MoQSubscription } from './subscription';\nimport {\n MoQSessionConfig,\n SessionState,\n SessionStatus,\n SessionEvents,\n BroadcastConfig,\n SubscriptionConfig\n} from './types';\n\nexport class MoQSession extends EventEmitter<SessionEvents> {\n private config: MoQSessionConfig;\n private url: URL;\n private state: SessionState = SessionState.DISCONNECTED;\n private connection?: Connection.Established;\n private reconnectAttempts = 0;\n private lastError?: Error;\n private connectedAt?: Date;\n private reconnectTimer?: ReturnType<typeof setTimeout>;\n private broadcasts = new Map<string, MoQBroadcast>();\n private subscriptions = new Map<string, MoQSubscription>();\n private announcedBroadcasts = new Set<string>();\n private doReconnect = true;\n private broadcast?: Broadcast;\n 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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"}
|
|
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 // randomize sequence number for new track 0-100000\n this.group = new Group(Math.floor(Math.random() * 100000));\n track.writeGroup(this.group);\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 console.log('Created new group with sequence number:', this.group.sequence);\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","Group","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,4 +1,4 @@
|
|
|
1
|
-
import { Path as p, Connection as
|
|
1
|
+
import { Group as b, Path as p, Connection as E, Broadcast as y } from "@kixelated/moq";
|
|
2
2
|
class m {
|
|
3
3
|
constructor() {
|
|
4
4
|
this.listeners = /* @__PURE__ */ new Map();
|
|
@@ -12,9 +12,9 @@ class m {
|
|
|
12
12
|
}
|
|
13
13
|
emit(t, ...s) {
|
|
14
14
|
const e = this.listeners.get(t);
|
|
15
|
-
e && e.forEach((
|
|
15
|
+
e && e.forEach((a) => {
|
|
16
16
|
try {
|
|
17
|
-
|
|
17
|
+
a(...s);
|
|
18
18
|
} catch (c) {
|
|
19
19
|
console.error("Error in event listener:", c);
|
|
20
20
|
}
|
|
@@ -25,7 +25,7 @@ class m {
|
|
|
25
25
|
}
|
|
26
26
|
}
|
|
27
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
|
|
28
|
+
class g extends m {
|
|
29
29
|
constructor(t) {
|
|
30
30
|
super(), this.state = d.IDLE, this.bytesSent = 0, this._config = t;
|
|
31
31
|
}
|
|
@@ -41,13 +41,13 @@ class y extends m {
|
|
|
41
41
|
return { ...this._config };
|
|
42
42
|
}
|
|
43
43
|
updateTrack(t) {
|
|
44
|
-
this.track = t, t && this.setState(d.BROADCASTING);
|
|
44
|
+
this.track = t, t && (this.setState(d.BROADCASTING), this.group = new b(Math.floor(Math.random() * 1e5)), t.writeGroup(this.group));
|
|
45
45
|
}
|
|
46
46
|
async send(t, s) {
|
|
47
47
|
if (this.state !== d.BROADCASTING || !this.track)
|
|
48
48
|
throw new Error("Broadcast is not active");
|
|
49
49
|
try {
|
|
50
|
-
(s || !this.group) && (this.group && this.group.close(), this.group = this.track.appendGroup()), await this.group.writeFrame(t), this.bytesSent += t.length;
|
|
50
|
+
(s || !this.group) && (this.group && this.group.close(), this.group = this.track.appendGroup(), console.log("Created new group with sequence number:", this.group.sequence)), await this.group.writeFrame(t), this.bytesSent += t.length;
|
|
51
51
|
} catch (e) {
|
|
52
52
|
throw this.handleError(e), e;
|
|
53
53
|
}
|
|
@@ -113,13 +113,13 @@ class N extends m {
|
|
|
113
113
|
const e = await s.readFrame();
|
|
114
114
|
if (!e) break;
|
|
115
115
|
t++, this.bytesReceived += e.length;
|
|
116
|
-
const
|
|
116
|
+
const a = {
|
|
117
117
|
trackName: this._config.trackName,
|
|
118
118
|
data: e,
|
|
119
119
|
timestamp: Date.now(),
|
|
120
120
|
frameIndex: t
|
|
121
121
|
};
|
|
122
|
-
this.emit("data",
|
|
122
|
+
this.emit("data", a);
|
|
123
123
|
}
|
|
124
124
|
}
|
|
125
125
|
} catch (t) {
|
|
@@ -127,8 +127,8 @@ class N extends m {
|
|
|
127
127
|
}
|
|
128
128
|
}
|
|
129
129
|
scheduleRetry(t, s) {
|
|
130
|
-
var
|
|
131
|
-
const e = ((
|
|
130
|
+
var a;
|
|
131
|
+
const e = ((a = this._config.retry) == null ? void 0 : a.delay) || 2e3;
|
|
132
132
|
this.setState(u.RETRYING), this.retryAttempts++, this.retryTimer = setTimeout(async () => {
|
|
133
133
|
try {
|
|
134
134
|
await this.subscribe(t, s);
|
|
@@ -194,7 +194,7 @@ class k extends m {
|
|
|
194
194
|
if (!(this.state === n.CONNECTING || this.state === n.CONNECTED)) {
|
|
195
195
|
this.setState(n.CONNECTING);
|
|
196
196
|
try {
|
|
197
|
-
this.doReconnect = !0, this.connection = await
|
|
197
|
+
this.doReconnect = !0, this.connection = await E.connect(this.url, {
|
|
198
198
|
websocket: {
|
|
199
199
|
enabled: !1
|
|
200
200
|
}
|
|
@@ -238,12 +238,12 @@ class k extends m {
|
|
|
238
238
|
updateBroadcasts(t) {
|
|
239
239
|
const s = t.map((i) => i.trackName), e = new Set(s);
|
|
240
240
|
if (s.length !== e.size) {
|
|
241
|
-
const i = s.filter((h,
|
|
241
|
+
const i = s.filter((h, o) => s.indexOf(h) !== o);
|
|
242
242
|
throw new Error(`Duplicate broadcast track name: ${i[0]}`);
|
|
243
243
|
}
|
|
244
|
-
const
|
|
244
|
+
const a = new Set(t.map((i) => i.trackName)), c = new Set(this.broadcasts.keys());
|
|
245
245
|
for (const i of c)
|
|
246
|
-
|
|
246
|
+
a.has(i) || this._removeBroadcast(i);
|
|
247
247
|
for (const i of t) {
|
|
248
248
|
const h = this.broadcasts.get(i.trackName);
|
|
249
249
|
h ? h.config.priority !== i.priority && (this._removeBroadcast(i.trackName), this._createBroadcast(i)) : this._createBroadcast(i);
|
|
@@ -256,17 +256,17 @@ class k extends m {
|
|
|
256
256
|
*/
|
|
257
257
|
updateSubscriptions(t) {
|
|
258
258
|
var i, h;
|
|
259
|
-
const s = t.map((
|
|
259
|
+
const s = t.map((o) => o.trackName), e = new Set(s);
|
|
260
260
|
if (s.length !== e.size) {
|
|
261
|
-
const
|
|
262
|
-
throw new Error(`Duplicate subscription track name: ${
|
|
261
|
+
const o = s.filter((l, f) => s.indexOf(l) !== f);
|
|
262
|
+
throw new Error(`Duplicate subscription track name: ${o[0]}`);
|
|
263
263
|
}
|
|
264
|
-
const
|
|
265
|
-
for (const
|
|
266
|
-
|
|
267
|
-
for (const
|
|
268
|
-
const l = this.subscriptions.get(
|
|
269
|
-
l ? (l.config.priority !==
|
|
264
|
+
const a = new Set(t.map((o) => o.trackName)), c = new Set(this.subscriptions.keys());
|
|
265
|
+
for (const o of c)
|
|
266
|
+
a.has(o) || this._removeSubscription(o);
|
|
267
|
+
for (const o of t) {
|
|
268
|
+
const l = this.subscriptions.get(o.trackName);
|
|
269
|
+
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);
|
|
270
270
|
}
|
|
271
271
|
}
|
|
272
272
|
getAnnouncedBroadcasts() {
|
|
@@ -278,10 +278,10 @@ class k extends m {
|
|
|
278
278
|
* @param data Binary data to send
|
|
279
279
|
*/
|
|
280
280
|
async send(t, s, e) {
|
|
281
|
-
const
|
|
282
|
-
if (!
|
|
281
|
+
const a = this.broadcasts.get(t);
|
|
282
|
+
if (!a)
|
|
283
283
|
throw new Error(`No broadcast found for track: ${t}`);
|
|
284
|
-
await
|
|
284
|
+
await a.send(s, e);
|
|
285
285
|
}
|
|
286
286
|
/**
|
|
287
287
|
* Get the status of a specific broadcast track
|
|
@@ -300,7 +300,7 @@ class k extends m {
|
|
|
300
300
|
return s == null ? void 0 : s.status;
|
|
301
301
|
}
|
|
302
302
|
_createBroadcast(t) {
|
|
303
|
-
const s = new
|
|
303
|
+
const s = new g(t);
|
|
304
304
|
return this.broadcasts.set(t.trackName, s), s.on("stateChange", (e) => {
|
|
305
305
|
this.emit("broadcastStateChange", t.trackName, e);
|
|
306
306
|
}), s.on("error", (e) => {
|
|
@@ -361,7 +361,7 @@ class k extends m {
|
|
|
361
361
|
await this.stopAllBroadcasts(), this.initBroadcasting();
|
|
362
362
|
}
|
|
363
363
|
initBroadcasting() {
|
|
364
|
-
this.broadcast || this.broadcasts.size !== 0 && (this.broadcast = new
|
|
364
|
+
this.broadcast || this.broadcasts.size !== 0 && (this.broadcast = new y(), this.connection && (this.connection.publish(p.from(this.config.namespace), this.broadcast), this.handleTrackRequests().catch((t) => {
|
|
365
365
|
console.error("Error handling track requests:", t);
|
|
366
366
|
})));
|
|
367
367
|
}
|
|
@@ -391,8 +391,8 @@ class k extends m {
|
|
|
391
391
|
var s;
|
|
392
392
|
(s = this.broadcast) == null || s.close(), this.broadcast = void 0;
|
|
393
393
|
const t = Array.from(this.broadcasts.values()).map(
|
|
394
|
-
(e) => e.stop().catch((
|
|
395
|
-
console.warn("Error stopping broadcast:",
|
|
394
|
+
(e) => e.stop().catch((a) => {
|
|
395
|
+
console.warn("Error stopping broadcast:", a);
|
|
396
396
|
})
|
|
397
397
|
);
|
|
398
398
|
await Promise.allSettled(t);
|
|
@@ -432,7 +432,7 @@ class k extends m {
|
|
|
432
432
|
}
|
|
433
433
|
export {
|
|
434
434
|
d as BroadcastState,
|
|
435
|
-
|
|
435
|
+
g as MoQBroadcast,
|
|
436
436
|
k as MoQSession,
|
|
437
437
|
N as MoQSubscription,
|
|
438
438
|
n as SessionState,
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","sources":["../src/event-emitter.ts","../src/types.ts","../src/broadcast.ts","../src/subscription.ts","../src/session.ts"],"sourcesContent":["// Simple event emitter for type-safe events\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport class EventEmitter<T extends Record<string, (...args: any[]) => void>> {\n private listeners = new Map<keyof T, Set<T[keyof T]>>();\n\n on<K extends keyof T>(event: K, listener: T[K]): void {\n if (!this.listeners.has(event)) {\n this.listeners.set(event, new Set());\n }\n this.listeners.get(event)!.add(listener);\n }\n\n off<K extends keyof T>(event: K, listener: T[K]): void {\n const eventListeners = this.listeners.get(event);\n if (eventListeners) {\n eventListeners.delete(listener);\n }\n }\n\n emit<K extends keyof T>(event: K, ...args: Parameters<T[K]>): void {\n const eventListeners = this.listeners.get(event);\n if (eventListeners) {\n eventListeners.forEach(listener => {\n try {\n listener(...args);\n } catch (error) {\n console.error('Error in event listener:', error);\n }\n });\n }\n }\n\n removeAllListeners<K extends keyof T>(event?: K): void {\n if (event) {\n this.listeners.delete(event);\n } else {\n this.listeners.clear();\n }\n }\n}","// Types for the library\nexport interface MoQSessionConfig {\n /** URL of the MoQ relay server */\n relayUrl: string;\n /** MoQ namespace (broadcast name) */\n namespace: string;\n /** Reconnection configuration */\n reconnection?: {\n /** Delay between reconnection attempts in ms (minimum: 1000) */\n delay?: number;\n };\n /** Connection timeout in ms (default: 10000) */\n connectionTimeout?: number;\n}\n\nexport interface BroadcastConfig {\n /** Track name for the broadcast */\n trackName: string;\n /** Priority for the track (default: 0) */\n priority?: number;\n}\n\nexport interface SubscriptionConfig {\n /** Track name to subscribe to */\n trackName: string;\n /** Priority for the subscription (default: 0) */\n priority?: number;\n /** Retry configuration for failed subscriptions */\n retry?: {\n /** Delay between retry attempts in ms (default: 2000) */\n delay?: number;\n };\n}\n\nexport enum SessionState {\n DISCONNECTED = 'disconnected',\n CONNECTING = 'connecting',\n CONNECTED = 'connected',\n RECONNECTING = 'reconnecting',\n FAILED = 'failed'\n}\n\nexport enum BroadcastState {\n IDLE = 'idle',\n BROADCASTING = 'broadcasting',\n ERROR = 'error'\n}\n\nexport enum SubscriptionState {\n PENDING = 'pending',\n SUBSCRIBED = 'subscribed',\n RETRYING = 'retrying',\n FAILED = 'failed'\n}\n\nexport interface SessionStatus {\n state: SessionState;\n reconnectAttempts: number;\n lastError?: Error;\n connectedAt?: Date;\n}\n\nexport interface BroadcastStatus {\n state: BroadcastState;\n trackName: string;\n bytesSent: number;\n lastError?: Error;\n}\n\nexport interface SubscriptionStatus {\n state: SubscriptionState;\n trackName: string;\n bytesReceived: number;\n retryAttempts: number;\n lastError?: Error;\n}\n\nexport interface DataReceived {\n trackName: string;\n data: Uint8Array;\n timestamp: number;\n frameIndex: number;\n}\n\n// Event types\nexport interface BroadcastAnnouncement {\n path: string;\n active: boolean;\n}\n\nexport interface SessionEvents {\n stateChange: (status: SessionStatus) => void;\n error: (error: Error) => void;\n broadcastAnnounced: (announcement: BroadcastAnnouncement) => void;\n data: (trackName: string, data: Uint8Array, frameIndex: number) => void;\n broadcastStateChange: (trackName: string, status: BroadcastStatus) => void;\n subscriptionStateChange: (trackName: string, status: SubscriptionStatus) => void;\n broadcastError: (trackName: string, error: Error) => void;\n subscriptionError: (trackName: string, error: Error) => void;\n trackRequested: (trackName: string) => void;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n [key: string]: (...args: any[]) => void;\n}\n\nexport interface BroadcastEvents {\n stateChange: (status: BroadcastStatus) => void;\n error: (error: Error) => void;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n [key: string]: (...args: any[]) => void;\n}\n\nexport interface SubscriptionEvents {\n stateChange: (status: SubscriptionStatus) => void;\n data: (data: DataReceived) => void;\n error: (error: Error) => void;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n [key: string]: (...args: any[]) => void;\n}","import { Group, Track } from '@kixelated/moq';\nimport { EventEmitter } from './event-emitter';\nimport {\n BroadcastConfig,\n BroadcastState,\n BroadcastStatus,\n BroadcastEvents\n} from './types';\n\nexport class MoQBroadcast extends EventEmitter<BroadcastEvents> {\n private _config: BroadcastConfig;\n private state: BroadcastState = BroadcastState.IDLE;\n private bytesSent = 0;\n private lastError?: Error;\n private track?: Track;\n private group?: Group;\n\n constructor(config: BroadcastConfig) {\n super();\n this._config = config;\n }\n\n get status(): BroadcastStatus {\n return {\n state: this.state,\n trackName: this._config.trackName,\n bytesSent: this.bytesSent,\n lastError: this.lastError\n };\n }\n\n get config(): BroadcastConfig {\n return { ...this._config };\n }\n\n updateTrack(track: Track): void {\n this.track = track;\n if (track) {\n this.setState(BroadcastState.BROADCASTING);\n }\n }\n\n async send(data: Uint8Array, newGroup: boolean): Promise<void> {\n if (this.state !== BroadcastState.BROADCASTING || !this.track) {\n throw new Error('Broadcast is not active');\n }\n\n try {\n if (newGroup || !this.group) {\n if (this.group) {\n this.group.close();\n }\n this.group = this.track.appendGroup();\n }\n await this.group.writeFrame(data);\n this.bytesSent += data.length;\n } catch (error) {\n this.handleError(error as Error);\n throw error;\n }\n }\n\n async stop(): Promise<void> {\n if (this.track) {\n try {\n this.track.close();\n } catch (error) {\n console.warn('Error closing track:', error);\n }\n this.track = undefined;\n }\n \n this.setState(BroadcastState.IDLE);\n }\n\n private setState(newState: BroadcastState): void {\n if (this.state !== newState) {\n this.state = newState;\n this.emit('stateChange', this.status);\n }\n }\n\n private handleError(error: Error): void {\n this.lastError = error;\n this.setState(BroadcastState.ERROR);\n this.emit('error', error);\n }\n\n public dispose(): void {\n this.stop().catch(console.error);\n this.removeAllListeners();\n }\n}","import { Broadcast, Track, Connection, Path } from '@kixelated/moq';\nimport { EventEmitter } from './event-emitter';\nimport {\n SubscriptionConfig,\n SubscriptionState,\n SubscriptionStatus,\n SubscriptionEvents,\n DataReceived\n} from './types';\n\nexport class MoQSubscription extends EventEmitter<SubscriptionEvents> {\n private _config: SubscriptionConfig;\n private state: SubscriptionState = SubscriptionState.PENDING;\n private bytesReceived = 0;\n private retryAttempts = 0;\n private lastError?: Error;\n private subscription?: Track;\n private broadcast?: Broadcast;\n private retryTimer?: ReturnType<typeof setTimeout>;\n private connection?: Connection.Established;\n private namespace?: string;\n\n constructor(config: SubscriptionConfig) {\n super();\n this._config = config;\n }\n\n get status(): SubscriptionStatus {\n return {\n state: this.state,\n trackName: this._config.trackName,\n bytesReceived: this.bytesReceived,\n retryAttempts: this.retryAttempts,\n lastError: this.lastError\n };\n }\n\n get config(): SubscriptionConfig {\n return { ...this._config };\n }\n\n async start(connection: Connection.Established, namespace: string): Promise<void> {\n this.connection = connection;\n this.namespace = namespace;\n try {\n await this.subscribe(connection, namespace);\n } catch (error) {\n this.handleError(error as Error);\n this.scheduleRetry(connection, namespace);\n }\n }\n\n private async subscribe(connection: Connection.Established, namespace: string): Promise<void> {\n this.setState(SubscriptionState.PENDING);\n\n const broadcastPath = Path.from(namespace);\n this.broadcast = connection.consume(broadcastPath);\n\n // Subscribe to the specific track within the broadcast\n this.subscription = this.broadcast.subscribe(this._config.trackName, this._config.priority || 0);\n this.setState(SubscriptionState.SUBSCRIBED);\n this.retryAttempts = 0;\n\n // Set up data reception\n this.readFrames();\n }\n\n private async readFrames(): Promise<void> {\n if (!this.subscription) return;\n\n try {\n // eslint-disable-next-line no-constant-condition\n while (true) {\n let framesInGroup = 0;\n const group = await this.subscription.nextGroup();\n if (!group) break; // Track is closed\n\n // Read all frames from the group\n // eslint-disable-next-line no-constant-condition\n while (true) {\n const frame = await group.readFrame();\n if (!frame) break; // Group is finished\n framesInGroup++;\n\n this.bytesReceived += frame.length;\n const receivedData: DataReceived = {\n trackName: this._config.trackName,\n data: frame,\n timestamp: Date.now(),\n frameIndex: framesInGroup,\n };\n this.emit('data', receivedData);\n }\n }\n } catch (error) {\n this.handleError(error as Error);\n // Trigger retry when stream gets reset/closed\n if (this.connection && this.namespace) {\n this.scheduleRetry(this.connection, this.namespace);\n }\n }\n }\n \n private scheduleRetry(connection: Connection.Established, namespace: string): void {\n const delay = this._config.retry?.delay || 2000;\n\n this.setState(SubscriptionState.RETRYING);\n this.retryAttempts++;\n\n this.retryTimer = setTimeout(async () => {\n try {\n await this.subscribe(connection, namespace);\n } catch (error) {\n this.handleError(error as Error);\n this.scheduleRetry(connection, namespace);\n }\n }, delay);\n }\n\n async stop(): Promise<void> {\n this.connection = undefined;\n this.namespace = undefined;\n \n if (this.retryTimer) {\n clearTimeout(this.retryTimer);\n this.retryTimer = undefined;\n }\n\n if (this.subscription) {\n try {\n this.subscription.close();\n } catch (error) {\n console.warn('Error closing subscription:', error);\n }\n this.subscription = undefined;\n }\n\n if (this.broadcast) {\n try {\n this.broadcast.close();\n } catch (error) {\n console.warn('Error closing broadcast:', error);\n }\n this.broadcast = undefined;\n }\n\n this.setState(SubscriptionState.PENDING);\n }\n\n private setState(newState: SubscriptionState): void {\n if (this.state !== newState) {\n this.state = newState;\n this.emit('stateChange', this.status);\n }\n }\n\n private handleError(error: Error): void {\n this.lastError = error;\n this.emit('error', error);\n }\n\n dispose(): void {\n this.stop().catch((error) => {\n console.warn('Error during dispose:', error);\n });\n this.removeAllListeners();\n }\n}","import { Broadcast, Connection, Path } from '@kixelated/moq';\nimport { EventEmitter } from './event-emitter';\nimport { MoQBroadcast } from './broadcast';\nimport { MoQSubscription } from './subscription';\nimport {\n MoQSessionConfig,\n SessionState,\n SessionStatus,\n SessionEvents,\n BroadcastConfig,\n SubscriptionConfig\n} from './types';\n\nexport class MoQSession extends EventEmitter<SessionEvents> {\n private config: MoQSessionConfig;\n private url: URL;\n private state: SessionState = SessionState.DISCONNECTED;\n private connection?: Connection.Established;\n private reconnectAttempts = 0;\n private lastError?: Error;\n private connectedAt?: Date;\n private reconnectTimer?: ReturnType<typeof setTimeout>;\n private broadcasts = new Map<string, MoQBroadcast>();\n private subscriptions = new Map<string, MoQSubscription>();\n private announcedBroadcasts = new Set<string>();\n private doReconnect = true;\n private broadcast?: Broadcast;\n 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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"}
|
|
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 // randomize sequence number for new track 0-100000\n this.group = new Group(Math.floor(Math.random() * 100000));\n track.writeGroup(this.group);\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 console.log('Created new group with sequence number:', this.group.sequence);\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","Group","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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "stinky-moq-js",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.13",
|
|
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",
|
|
@@ -63,7 +63,7 @@
|
|
|
63
63
|
"vitest": "^2.1.1"
|
|
64
64
|
},
|
|
65
65
|
"dependencies": {
|
|
66
|
-
"@kixelated/moq": "0.9.
|
|
66
|
+
"@kixelated/moq": "0.9.2"
|
|
67
67
|
},
|
|
68
68
|
"browserslist": [
|
|
69
69
|
"defaults",
|