stinky-moq-js 0.1.0

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/README.md ADDED
@@ -0,0 +1,446 @@
1
+ # Stinky MoQ JS
2
+
3
+ A TypeScript library for Media over Quic (MoQ) with session management, automatic reconnection, and simple API for browser applications. Built on top of [@kixelated/moq](https://github.com/kixelated/moq-js) using the moq-lite-draft-04 specification.
4
+
5
+ ## Features
6
+
7
+ - 🔄 **Infinite Reconnection**: Persistent reconnection with configurable delays
8
+ - 🔍 **Broadcast Discovery**: Automatic discovery of available broadcasts via announcements
9
+ - 📡 **Session Management**: Handle MoQ relay connections with namespace support
10
+ - 📤 **Broadcasting**: Send binary data to MoQ tracks with status reporting
11
+ - 📥 **Subscriptions**: Receive binary data from MoQ tracks with automatic retry
12
+ - 🎯 **Type Safe**: Full TypeScript support with comprehensive type definitions
13
+ - 🌐 **WebTransport Only**: Uses modern WebTransport for optimal performance
14
+ - 🔁 **Bidirectional Communication**: Full pub/sub support for two-way data exchange
15
+
16
+ ## Installation
17
+
18
+ ```bash
19
+ npm install stinky-moq-js
20
+ ```
21
+
22
+ ## Quick Start
23
+
24
+ ```typescript
25
+ import { MoQSession, SessionState } from 'stinky-moq-js';
26
+
27
+ // Create a session
28
+ const session = new MoQSession({
29
+ relayUrl: 'wss://relay.quic.video',
30
+ namespace: 'my-app',
31
+ reconnection: {
32
+ delay: 1000 // Reconnect delay in ms
33
+ }
34
+ });
35
+
36
+ // Listen to session events
37
+ session.on('stateChange', (status) => {
38
+ console.log('Session state:', status.state);
39
+ });
40
+
41
+ session.on('error', (error) => {
42
+ console.error('Session error:', error);
43
+ });
44
+
45
+ // Listen for broadcast discoveries
46
+ session.on('broadcastAnnounced', (announcement) => {
47
+ console.log('Found broadcast:', announcement.path);
48
+ });
49
+
50
+ // Connect to the relay
51
+ await session.connect();
52
+ ```
53
+
54
+ ## Working with Broadcasts
55
+
56
+ ```typescript
57
+ // Define what you want to broadcast
58
+ const broadcasts = [
59
+ { trackName: 'my-video-track', priority: 1 },
60
+ { trackName: 'my-audio-track', priority: 2 }
61
+ ];
62
+
63
+ // Apply the configuration
64
+ session.updateBroadcasts(broadcasts);
65
+
66
+ // Listen to broadcast events through the session
67
+ session.on('broadcastStateChange', (trackName, status) => {
68
+ console.log(`Broadcast ${trackName} state:`, status.state);
69
+ console.log('Bytes sent:', status.bytesSent);
70
+ });
71
+
72
+ session.on('broadcastError', (trackName, error) => {
73
+ console.error(`Broadcast error on ${trackName}:`, error.message);
74
+ });
75
+
76
+ // Send binary data through the session
77
+ const data = new Uint8Array([1, 2, 3, 4, 5]);
78
+ await session.send('my-video-track', data);
79
+ ```
80
+
81
+ ## Working with Subscriptions
82
+
83
+ ```typescript
84
+ // Define what you want to subscribe to
85
+ const subscriptions = [
86
+ { trackName: 'remote-video-track', priority: 1 },
87
+ { trackName: 'remote-audio-track', priority: 2, retry: { delay: 2000 } }
88
+ ];
89
+
90
+ // Apply the configuration
91
+ session.updateSubscriptions(subscriptions);
92
+
93
+ // Listen to incoming data through the session
94
+ session.on('data', (trackName, data) => {
95
+ console.log('Received data from:', trackName);
96
+ console.log('Data length:', data.length);
97
+ });
98
+
99
+ // Listen to subscription status through the session
100
+ session.on('subscriptionStateChange', (trackName, status) => {
101
+ console.log(`Subscription ${trackName} state:`, status.state);
102
+ console.log('Bytes received:', status.bytesReceived);
103
+ console.log('Retry attempts:', status.retryAttempts);
104
+ });
105
+
106
+ session.on('subscriptionError', (trackName, error) => {
107
+ console.error(`Subscription error on ${trackName}:`, error.message);
108
+ });
109
+ ```
110
+
111
+ ## Configuration
112
+
113
+ ### Session Configuration
114
+
115
+ ```typescript
116
+ interface MoQSessionConfig {
117
+ relayUrl: string; // URL of the MoQ relay server
118
+ namespace: string; // MoQ namespace (broadcast name)
119
+ reconnection?: {
120
+ delay?: number; // Delay between attempts in ms (default: 1000)
121
+ };
122
+ connectionTimeout?: number; // Connection timeout in ms (default: 10000)
123
+ }
124
+ ```
125
+
126
+ ### Broadcast Configuration
127
+
128
+ ```typescript
129
+ interface BroadcastConfig {
130
+ trackName: string; // Track name for the broadcast
131
+ priority?: number; // Priority for the track (default: 0)
132
+ }
133
+ ```
134
+
135
+ ### Subscription Configuration
136
+
137
+ ```typescript
138
+ interface SubscriptionConfig {
139
+ trackName: string; // Track name to subscribe to
140
+ priority?: number; // Priority for the subscription (default: 0)
141
+ retry?: {
142
+ delay?: number; // Delay between retries in ms (default: 2000)
143
+ };
144
+ }
145
+ ```
146
+
147
+ ## Status Monitoring
148
+
149
+ ### Session Status
150
+
151
+ ```typescript
152
+ const status = session.status;
153
+ console.log({
154
+ state: status.state, // SessionState enum
155
+ reconnectAttempts: status.reconnectAttempts,
156
+ lastError: status.lastError,
157
+ connectedAt: status.connectedAt
158
+ });
159
+ ```
160
+
161
+ ### Broadcast Status
162
+
163
+ ```typescript
164
+ const status = session.getBroadcastStatus('my-track');
165
+ if (status) {
166
+ console.log({
167
+ state: status.state, // BroadcastState enum
168
+ trackName: status.trackName,
169
+ bytesSent: status.bytesSent,
170
+ lastError: status.lastError
171
+ });
172
+ }
173
+ ```
174
+
175
+ ### Subscription Status
176
+
177
+ ```typescript
178
+ const status = session.getSubscriptionStatus('remote-track');
179
+ if (status) {
180
+ console.log({
181
+ state: status.state, // SubscriptionState enum
182
+ trackName: status.trackName,
183
+ bytesReceived: status.bytesReceived,
184
+ retryAttempts: status.retryAttempts,
185
+ lastError: status.lastError
186
+ });
187
+ }
188
+ ```
189
+
190
+ ## States
191
+
192
+ ### Session States
193
+ - `DISCONNECTED`: Not connected to relay
194
+ - `CONNECTING`: Attempting to connect
195
+ - `CONNECTED`: Successfully connected
196
+ - `RECONNECTING`: Attempting to reconnect after disconnect
197
+ - `FAILED`: Connection failed completely
198
+
199
+ ### Broadcast States
200
+ - `IDLE`: Not broadcasting
201
+ - `BROADCASTING`: Actively broadcasting
202
+ - `ERROR`: Error occurred
203
+
204
+ ### Subscription States
205
+ - `PENDING`: Waiting to subscribe
206
+ - `SUBSCRIBED`: Successfully subscribed
207
+ - `RETRYING`: Retrying after failure
208
+ - `FAILED`: Subscription failed completely
209
+
210
+ ## Error Handling
211
+
212
+ ```typescript
213
+ // Session errors
214
+ session.on('error', (error) => {
215
+ console.error('Session error:', error.message);
216
+ });
217
+
218
+ // Broadcast errors (per track)
219
+ session.on('broadcastError', (trackName, error) => {
220
+ console.error(`Broadcast error on ${trackName}:`, error.message);
221
+ });
222
+
223
+ // Subscription errors (per track)
224
+ session.on('subscriptionError', (trackName, error) => {
225
+ console.error(`Subscription error on ${trackName}:`, error.message);
226
+ });
227
+ ```
228
+
229
+ ## Cleanup
230
+
231
+ ```typescript
232
+ // Remove all broadcasts and subscriptions
233
+ session.updateBroadcasts([]); // Empty array removes all
234
+ session.updateSubscriptions([]);
235
+
236
+ // Or disconnect to cleanup everything
237
+ await session.disconnect();
238
+ ```
239
+
240
+ ## Broadcast Discovery
241
+
242
+ The library automatically discovers available broadcasts via MoQ announcements:
243
+
244
+ ```typescript
245
+ // Listen for broadcast announcements
246
+ session.on('broadcastAnnounced', (announcement) => {
247
+ console.log('Found broadcast:', announcement.path);
248
+ console.log('Is active:', announcement.active);
249
+
250
+ // Subscribe to discovered broadcast
251
+ if (announcement.active) {
252
+ session.updateSubscriptions([
253
+ { trackName: announcement.path }
254
+ ]);
255
+ }
256
+ });
257
+ ```
258
+
259
+ ## Dynamic Track Management
260
+
261
+ The library provides a declarative API for managing broadcasts and subscriptions. Simply define the desired state and the library handles all add/remove/update operations automatically:
262
+
263
+ ### Managing Broadcasts Dynamically
264
+
265
+ ```typescript
266
+ // Define the desired state of broadcasts
267
+ const desiredBroadcasts = [
268
+ { trackName: 'video', priority: 1 },
269
+ { trackName: 'audio', priority: 2 },
270
+ { trackName: 'metadata', priority: 0 }
271
+ ];
272
+
273
+ // Apply the desired state - library handles add/remove/update automatically
274
+ session.updateBroadcasts(desiredBroadcasts);
275
+
276
+ // Later, change the desired state
277
+ const newBroadcasts = [
278
+ { trackName: 'video', priority: 1 }, // Kept
279
+ { trackName: 'chat', priority: 0 } // Audio and metadata removed, chat added
280
+ ];
281
+
282
+ session.updateBroadcasts(newBroadcasts);
283
+ ```
284
+
285
+ ### Managing Subscriptions Dynamically
286
+
287
+ ```typescript
288
+ // Define what you want to subscribe to
289
+ const desiredSubscriptions = [
290
+ { trackName: 'remote-video', priority: 1 },
291
+ { trackName: 'remote-audio', priority: 2, retry: { delay: 1000 } },
292
+ { trackName: 'remote-chat', priority: 0 }
293
+ ];
294
+
295
+ // Apply the desired state
296
+ session.updateSubscriptions(desiredSubscriptions);
297
+
298
+ // Update subscriptions based on user preferences
299
+ const userPreferences = {
300
+ videoEnabled: true,
301
+ audioEnabled: false,
302
+ chatEnabled: true
303
+ };
304
+
305
+ const activeSubscriptions = [
306
+ ...(userPreferences.videoEnabled ? [{ trackName: 'remote-video', priority: 1 }] : []),
307
+ ...(userPreferences.audioEnabled ? [{ trackName: 'remote-audio', priority: 2 }] : []),
308
+ ...(userPreferences.chatEnabled ? [{ trackName: 'remote-chat', priority: 0 }] : [])
309
+ ];
310
+
311
+ session.updateSubscriptions(activeSubscriptions);
312
+ ```
313
+
314
+ ### Benefits of Declarative API
315
+
316
+ - **Cleaner State Management**: Just declare what you want, not how to get there
317
+ - **Automatic Cleanup**: Tracks not in the desired state are automatically removed
318
+ - **Idempotent**: Calling `updateBroadcasts`/`updateSubscriptions` multiple times with the same config is safe
319
+ - **Less Error-Prone**: No need to manually track what's been added/removed
320
+ - **Reactive Updates**: Easy to update based on user preferences or external state changes
321
+
322
+ ## Advanced Usage
323
+
324
+ ### Managing Multiple Tracks
325
+
326
+ ```typescript
327
+ // Define multiple tracks at once
328
+ const broadcasts = [
329
+ { trackName: 'video', priority: 1 },
330
+ { trackName: 'audio', priority: 2 },
331
+ { trackName: 'screen', priority: 3 }
332
+ ];
333
+
334
+ const subscriptions = [
335
+ { trackName: 'remote-video', priority: 1 },
336
+ { trackName: 'remote-audio', priority: 2 },
337
+ { trackName: 'remote-screen', priority: 3 }
338
+ ];
339
+
340
+ session.updateBroadcasts(broadcasts);
341
+ session.updateSubscriptions(subscriptions);
342
+
343
+ // Get all active track names
344
+ const allBroadcasts = session.getAllBroadcastTrackNames();
345
+ const allSubscriptions = session.getAllSubscriptionTrackNames();
346
+ console.log('Broadcasting:', allBroadcasts);
347
+ console.log('Subscribed to:', allSubscriptions);
348
+ ```
349
+
350
+ ### Infinite Retry Logic
351
+
352
+ Both reconnection and subscription retries run infinitely with configurable delays:
353
+
354
+ ```typescript
355
+ // Session with custom reconnection delay
356
+ const session = new MoQSession({
357
+ relayUrl: 'wss://relay.quic.video',
358
+ namespace: 'persistent-app',
359
+ reconnection: {
360
+ delay: 5000 // Wait 5 seconds between reconnection attempts
361
+ }
362
+ });
363
+
364
+ // Subscription with custom retry delay
365
+ session.updateSubscriptions([
366
+ {
367
+ trackName: 'important-track',
368
+ retry: {
369
+ delay: 3000 // Wait 3 seconds between retry attempts
370
+ }
371
+ }
372
+ ]);
373
+ ```
374
+
375
+ ### Bidirectional Communication
376
+
377
+ Set up full bidirectional communication between two applications:
378
+
379
+ ```typescript
380
+ // App A: Publisher and Subscriber
381
+ const sessionA = new MoQSession({
382
+ relayUrl: 'wss://relay.quic.video',
383
+ namespace: 'app-a'
384
+ });
385
+
386
+ await sessionA.connect();
387
+
388
+ // Set up tracks
389
+ sessionA.updateBroadcasts([{ trackName: 'data-from-a' }]);
390
+ sessionA.updateSubscriptions([{ trackName: 'data-from-b' }]);
391
+
392
+ // Listen for data from App B
393
+ sessionA.on('data', (trackName, data) => {
394
+ if (trackName === 'data-from-b') {
395
+ console.log('App A received data from App B:', data);
396
+ }
397
+ });
398
+
399
+ // App B: Subscriber and Publisher
400
+ const sessionB = new MoQSession({
401
+ relayUrl: 'wss://relay.quic.video',
402
+ namespace: 'app-b'
403
+ });
404
+
405
+ await sessionB.connect();
406
+
407
+ // Set up tracks
408
+ sessionB.updateSubscriptions([{ trackName: 'data-from-a' }]);
409
+ sessionB.updateBroadcasts([{ trackName: 'data-from-b' }]);
410
+
411
+ // Listen for data from App A
412
+ sessionB.on('data', (trackName, data) => {
413
+ if (trackName === 'data-from-a') {
414
+ console.log('App B received data from App A:', data);
415
+ }
416
+ });
417
+
418
+ // Send data from App A to App B
419
+ await sessionA.send('data-from-a', new TextEncoder().encode('Hello from A'));
420
+
421
+ // Send data from App B to App A
422
+ await sessionB.send('data-from-b', new TextEncoder().encode('Hello from B'));
423
+ ```
424
+ ```
425
+
426
+ ## Dependencies
427
+
428
+ This library is built on top of:
429
+ - [@kixelated/moq](https://github.com/kixelated/moq-js) v0.9.1 - Core MoQ implementation
430
+ - Uses the `moq-lite-draft-04` specification (not the standard IETF MoQ draft)
431
+ - WebTransport only (no WebSocket fallback)
432
+
433
+ ## Browser Support
434
+
435
+ Requires modern browsers with WebTransport support:
436
+ - Chrome 97+
437
+ - Edge 97+
438
+ - Safari 15.4+ (with WebTransport enabled)
439
+
440
+ ## License
441
+
442
+ MIT
443
+
444
+ ## Contributing
445
+
446
+ Contributions are welcome! Please feel free to submit a Pull Request.
@@ -0,0 +1,21 @@
1
+ import { Connection } from '@kixelated/moq';
2
+ import { EventEmitter } from './event-emitter';
3
+ import { BroadcastConfig, BroadcastStatus, BroadcastEvents } from './types';
4
+ export declare class MoQBroadcast extends EventEmitter<BroadcastEvents> {
5
+ private _config;
6
+ private state;
7
+ private bytesSent;
8
+ private lastError?;
9
+ private track?;
10
+ private broadcast?;
11
+ constructor(config: BroadcastConfig);
12
+ get status(): BroadcastStatus;
13
+ get config(): BroadcastConfig;
14
+ start(connection: Connection.Established, namespace: string): Promise<void>;
15
+ private handleTrackRequests;
16
+ send(data: Uint8Array): Promise<void>;
17
+ stop(): Promise<void>;
18
+ private setState;
19
+ private handleError;
20
+ }
21
+ //# sourceMappingURL=broadcast.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"broadcast.d.ts","sourceRoot":"","sources":["../src/broadcast.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoB,UAAU,EAAQ,MAAM,gBAAgB,CAAC;AACpE,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,SAAS,CAAC,CAAY;gBAElB,MAAM,EAAE,eAAe;IAKnC,IAAI,MAAM,IAAI,eAAe,CAO5B;IAED,IAAI,MAAM,IAAI,eAAe,CAE5B;IAEK,KAAK,CAAC,UAAU,EAAE,UAAU,CAAC,WAAW,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;YAoBnE,mBAAmB;IAmB3B,IAAI,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAcrC,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAsB3B,OAAO,CAAC,QAAQ;IAOhB,OAAO,CAAC,WAAW;CAKpB"}
@@ -0,0 +1,8 @@
1
+ export declare class EventEmitter<T extends Record<string, (...args: any[]) => void>> {
2
+ private listeners;
3
+ on<K extends keyof T>(event: K, listener: T[K]): void;
4
+ off<K extends keyof T>(event: K, listener: T[K]): void;
5
+ emit<K extends keyof T>(event: K, ...args: Parameters<T[K]>): void;
6
+ removeAllListeners<K extends keyof T>(event?: K): void;
7
+ }
8
+ //# sourceMappingURL=event-emitter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-emitter.d.ts","sourceRoot":"","sources":["../src/event-emitter.ts"],"names":[],"mappings":"AAEA,qBAAa,YAAY,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,CAAC;IAC1E,OAAO,CAAC,SAAS,CAAuC;IAExD,EAAE,CAAC,CAAC,SAAS,MAAM,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI;IAOrD,GAAG,CAAC,CAAC,SAAS,MAAM,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI;IAOtD,IAAI,CAAC,CAAC,SAAS,MAAM,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,GAAG,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI;IAalE,kBAAkB,CAAC,CAAC,SAAS,MAAM,CAAC,EAAE,KAAK,CAAC,EAAE,CAAC,GAAG,IAAI;CAOvD"}
package/dist/index.cjs ADDED
@@ -0,0 +1,2 @@
1
+ "use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const m=require("@kixelated/moq");class p{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(c=>{try{c(...s)}catch(n){console.error("Error in event listener:",n)}})}removeAllListeners(t){t?this.listeners.delete(t):this.listeners.clear()}}var o=(r=>(r.DISCONNECTED="disconnected",r.CONNECTING="connecting",r.CONNECTED="connected",r.RECONNECTING="reconnecting",r.FAILED="failed",r))(o||{}),d=(r=>(r.IDLE="idle",r.BROADCASTING="broadcasting",r.ERROR="error",r))(d||{}),l=(r=>(r.PENDING="pending",r.SUBSCRIBED="subscribed",r.RETRYING="retrying",r.FAILED="failed",r))(l||{});class b extends p{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}}async start(t,s){try{this.setState(d.BROADCASTING),this.broadcast=new m.Broadcast;const e=m.Path.from(s);t.publish(e,this.broadcast),this.handleTrackRequests()}catch(e){throw this.handleError(e),e}}async handleTrackRequests(){if(this.broadcast)try{for(;;){const t=await this.broadcast.requested();if(!t)break;t.track.name===this._config.trackName&&(this.track=t.track)}}catch(t){console.warn("Error handling track requests:",t),this.handleError(t)}}async send(t){if(this.state!==d.BROADCASTING||!this.track)throw new Error("Broadcast is not active");try{this.track.writeFrame(t),this.bytesSent+=t.length}catch(s){throw this.handleError(s),s}}async stop(){if(this.track){try{this.track.close()}catch(t){console.warn("Error closing track:",t)}this.track=void 0}if(this.broadcast){try{this.broadcast.close()}catch(t){console.warn("Error closing broadcast:",t)}this.broadcast=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)}}class f extends p{constructor(t){super(),this.state=l.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(l.PENDING);const e=m.Path.from(s);this.broadcast=t.consume(e),this.subscription=this.broadcast.subscribe(this._config.trackName,this._config.priority||0),this.setState(l.SUBSCRIBED),this.retryAttempts=0,this.readFrames()}async readFrames(){if(this.subscription)try{for(;;){const t=await this.subscription.nextGroup();if(!t)break;for(;;){const s=await t.readFrame();if(!s)break;this.bytesReceived+=s.length;const e={trackName:this._config.trackName,data:s,timestamp:Date.now()};this.emit("data",e)}}}catch(t){this.handleError(t),this.connection&&this.namespace&&this.scheduleRetry(this.connection,this.namespace)}}scheduleRetry(t,s){var c;const e=((c=this._config.retry)==null?void 0:c.delay)||2e3;this.setState(l.RETRYING),this.retryAttempts++,this.retryTimer=setTimeout(async()=>{try{await this.subscribe(t,s)}catch(n){this.handleError(n),this.scheduleRetry(t,s)}},e)}async stop(){if(this.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(l.PENDING)}setState(t){this.state!==t&&(this.state=t,this.emit("stateChange",this.status))}handleError(t){this.lastError=t,this.emit("error",t)}}class y extends p{constructor(t){var s;super(),this.state=o.DISCONNECTED,this.reconnectAttempts=0,this.broadcasts=new Map,this.subscriptions=new Map,this.announcedBroadcasts=new Set,console.log("AJAOFJODJFADJFJDASOFJADOSFJ"),this.config={...t,reconnection:{delay:Math.max(((s=t.reconnection)==null?void 0:s.delay)||1e3,1e3)},connectionTimeout:t.connectionTimeout||1e4}}get status(){return{state:this.state,reconnectAttempts:this.reconnectAttempts,lastError:this.lastError,connectedAt:this.connectedAt}}async connect(){if(!(this.state===o.CONNECTING||this.state===o.CONNECTED)){this.setState(o.CONNECTING);try{this.connection=await m.Connection.connect(new URL(this.config.relayUrl),{websocket:{enabled:!1}}),this.setState(o.CONNECTED),this.connectedAt=new Date,this.reconnectAttempts=0,this.connection.closed.then(()=>{this.state===o.CONNECTED&&this.handleDisconnection()}),this.startAnnouncementDiscovery(),await this.restartBroadcasts(),await this.restartSubscriptions()}catch(t){throw this.handleError(t),this.scheduleReconnect(),t}}}async disconnect(){if(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(o.DISCONNECTED),this.connectedAt=void 0}getAllBroadcastTrackNames(){return Array.from(this.broadcasts.keys())}getAllSubscriptionTrackNames(){return Array.from(this.subscriptions.keys())}updateBroadcasts(t){const s=t.map(i=>i.trackName),e=new Set(s);if(s.length!==e.size){const i=s.filter((h,a)=>s.indexOf(h)!==a);throw new Error(`Duplicate broadcast track name: ${i[0]}`)}const c=new Set(t.map(i=>i.trackName)),n=new Set(this.broadcasts.keys());for(const i of n)c.has(i)||this._removeBroadcast(i);for(const i of t){const h=this.broadcasts.get(i.trackName);h?h.config.priority!==i.priority&&(this._removeBroadcast(i.trackName),this._createBroadcast(i)):this._createBroadcast(i)}}updateSubscriptions(t){var i,h;const s=t.map(a=>a.trackName),e=new Set(s);if(s.length!==e.size){const a=s.filter((u,E)=>s.indexOf(u)!==E);throw new Error(`Duplicate subscription track name: ${a[0]}`)}const c=new Set(t.map(a=>a.trackName)),n=new Set(this.subscriptions.keys());for(const a of n)c.has(a)||this._removeSubscription(a);for(const a of t){const u=this.subscriptions.get(a.trackName);u?(u.config.priority!==a.priority||((i=u.config.retry)==null?void 0:i.delay)!==((h=a.retry)==null?void 0:h.delay))&&(this._removeSubscription(a.trackName),this._createSubscription(a)):this._createSubscription(a)}}getAnnouncedBroadcasts(){return Array.from(this.announcedBroadcasts)}async send(t,s){const e=this.broadcasts.get(t);if(!e)throw new Error(`No broadcast found for track: ${t}`);await e.send(s)}getBroadcastStatus(t){const s=this.broadcasts.get(t);return s==null?void 0:s.status}getSubscriptionStatus(t){const s=this.subscriptions.get(t);return s==null?void 0:s.status}_createBroadcast(t){const s=new b(t);return this.broadcasts.set(t.trackName,s),s.on("stateChange",e=>{this.emit("broadcastStateChange",t.trackName,e)}),s.on("error",e=>{this.emit("broadcastError",t.trackName,e)}),this.state===o.CONNECTED&&this.connection&&s.start(this.connection,this.config.namespace).catch(e=>{console.error("Failed to start broadcast:",e)}),s}_createSubscription(t){const s=new f(t);return this.subscriptions.set(t.trackName,s),s.on("data",e=>{this.emit("data",e.trackName,e.data)}),s.on("stateChange",e=>{this.emit("subscriptionStateChange",t.trackName,e)}),s.on("error",e=>{this.emit("subscriptionError",t.trackName,e)}),this.state===o.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=m.Path.from(this.config.namespace),s=this.connection.announced(t);this.processAnnouncements(s)}catch(t){console.error("Failed to start announcement discovery:",t)}}async processAnnouncements(t){try{for(;;){const s=await t.next();if(!s)break;s.active?(this.announcedBroadcasts.add(s.path),this.emit("broadcastAnnounced",{path:s.path,active:!0})):(this.announcedBroadcasts.delete(s.path),this.emit("broadcastAnnounced",{path:s.path,active:!1}))}}catch(s){console.error("Error processing announcements:",s)}}async restartBroadcasts(){if(!this.connection)return;const t=Array.from(this.broadcasts.values()).map(s=>s.start(this.connection,this.config.namespace).catch(e=>{console.error("Failed to restart broadcast:",e)}));await Promise.allSettled(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(){const t=Array.from(this.broadcasts.values()).map(s=>s.stop().catch(e=>{console.warn("Error stopping broadcast:",e)}));await Promise.allSettled(t)}async stopAllSubscriptions(){const t=Array.from(this.subscriptions.values()).map(s=>s.stop().catch(e=>{console.warn("Error stopping subscription:",e)}));await Promise.allSettled(t)}handleDisconnection(){this.setState(o.DISCONNECTED),this.scheduleReconnect()}scheduleReconnect(){var s;const t=((s=this.config.reconnection)==null?void 0:s.delay)||1e3;this.setState(o.RECONNECTING),this.reconnectAttempts++,this.reconnectTimer=setTimeout(()=>{this.connect().catch(e=>{console.error("Reconnection failed:",e)})},t)}setState(t){this.state!==t&&(this.state=t,this.emit("stateChange",this.status))}handleError(t){this.lastError=t,this.emit("error",t)}}exports.BroadcastState=d;exports.MoQBroadcast=b;exports.MoQSession=y;exports.MoQSubscription=f;exports.SessionState=o;exports.SubscriptionState=l;exports.default=y;
2
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +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}\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) => 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 // 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 { Broadcast, Track, Connection, Path } 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 broadcast?: Broadcast;\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 async start(connection: Connection.Established, namespace: string): Promise<void> {\n try {\n this.setState(BroadcastState.BROADCASTING);\n \n // Create broadcast for publishing\n this.broadcast = new Broadcast();\n \n // Publish the broadcast to the connection using namespace as broadcast ID\n const broadcastPath = Path.from(namespace);\n connection.publish(broadcastPath, this.broadcast);\n \n // Handle incoming track requests\n this.handleTrackRequests();\n \n } catch (error) {\n this.handleError(error as Error);\n throw error;\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) break; // Broadcast is closed\n \n // Check if this is the track we want to serve\n if (request.track.name === this._config.trackName) {\n this.track = request.track;\n }\n }\n } catch (error) {\n console.warn('Error handling track requests:', error);\n this.handleError(error as Error);\n }\n }\n\n async send(data: Uint8Array): Promise<void> {\n if (this.state !== BroadcastState.BROADCASTING || !this.track) {\n throw new Error('Broadcast is not active');\n }\n\n try {\n this.track.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 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(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}","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 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 \n this.bytesReceived += frame.length;\n const receivedData: DataReceived = {\n trackName: this._config.trackName,\n data: frame,\n timestamp: Date.now()\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 } 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 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}","import { 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 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\n constructor(config: MoQSessionConfig) {\n super();\n console.log('AJAOFJODJFADJFJDASOFJADOSFJ')\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\n get status(): SessionStatus {\n return {\n state: this.state,\n reconnectAttempts: this.reconnectAttempts,\n lastError: this.lastError,\n connectedAt: this.connectedAt\n };\n }\n\n async connect(): Promise<void> {\n if (this.state === SessionState.CONNECTING || this.state === SessionState.CONNECTED) {\n return;\n }\n\n this.setState(SessionState.CONNECTING);\n\n try {\n // Connect using the @kixelated/moq library with WebSocket fallback disabled\n this.connection = await Connection.connect(new URL(this.config.relayUrl), {\n websocket: {\n enabled: false // Disable WebSocket fallback\n }\n });\n\n this.setState(SessionState.CONNECTED);\n this.connectedAt = new Date();\n this.reconnectAttempts = 0;\n\n // Set up connection close handling\n this.connection.closed.then(() => {\n if (this.state === SessionState.CONNECTED) {\n this.handleDisconnection();\n }\n });\n\n // Start discovering announced broadcasts\n this.startAnnouncementDiscovery();\n\n // Restart all broadcasts and subscriptions\n await this.restartBroadcasts();\n await this.restartSubscriptions();\n\n } catch (error) {\n this.handleError(error as Error);\n this.scheduleReconnect();\n throw error;\n }\n }\n\n async disconnect(): Promise<void> {\n 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): 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);\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 // Start broadcast if we're connected\n if (this.state === SessionState.CONNECTED && this.connection) {\n broadcast.start(this.connection, this.config.namespace).catch(error => {\n console.error('Failed to start broadcast:', error);\n });\n }\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);\n });\n\n subscription.on('stateChange', (status) => {\n this.emit('subscriptionStateChange', config.trackName, status);\n });\n\n subscription.on('error', (error) => {\n this.emit('subscriptionError', config.trackName, error);\n });\n\n // Start subscription if we're connected\n if (this.state === SessionState.CONNECTED && this.connection) {\n subscription.start(this.connection, this.config.namespace).catch(error => {\n console.error('Failed to start subscription:', error);\n });\n }\n\n return subscription;\n }\n\n private _removeBroadcast(trackName: string): void {\n const broadcast = this.broadcasts.get(trackName);\n if (broadcast) {\n broadcast.stop().catch(error => {\n console.warn('Error stopping broadcast:', error);\n });\n this.broadcasts.delete(trackName);\n }\n }\n\n private _removeSubscription(trackName: string): void {\n const subscription = this.subscriptions.get(trackName);\n if (subscription) {\n subscription.stop().catch(error => {\n console.warn('Error stopping subscription:', error);\n });\n this.subscriptions.delete(trackName);\n }\n }\n\n private async startAnnouncementDiscovery(): Promise<void> {\n if (!this.connection) return;\n\n try {\n // Listen for announcements with our namespace as prefix\n const namespacePath = Path.from(this.config.namespace);\n const announced = this.connection.announced(namespacePath);\n \n // Process announcements in the background\n this.processAnnouncements(announced);\n \n } catch (error) {\n console.error('Failed to start announcement discovery:', error);\n }\n }\n\n private async processAnnouncements(announced: ReturnType<Connection.Established['announced']>): Promise<void> {\n try {\n for (;;) {\n const announcement = await announced.next();\n if (!announcement) break; // Announcements closed\n \n if (announcement.active) {\n this.announcedBroadcasts.add(announcement.path);\n this.emit('broadcastAnnounced', {\n path: announcement.path,\n active: true\n });\n } else {\n this.announcedBroadcasts.delete(announcement.path);\n this.emit('broadcastAnnounced', {\n path: announcement.path,\n active: false\n });\n }\n }\n } catch (error) {\n console.error('Error processing announcements:', error);\n }\n }\n\n private async restartBroadcasts(): Promise<void> {\n if (!this.connection) return;\n\n const promises = Array.from(this.broadcasts.values()).map(broadcast => \n broadcast.start(this.connection!, this.config.namespace).catch(error => {\n console.error('Failed to restart broadcast:', error);\n })\n );\n\n await Promise.allSettled(promises);\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 const promises = Array.from(this.broadcasts.values()).map(broadcast => \n broadcast.stop().catch(error => {\n console.warn('Error stopping broadcast:', error);\n })\n );\n\n await Promise.allSettled(promises);\n }\n\n private async stopAllSubscriptions(): Promise<void> {\n const promises = Array.from(this.subscriptions.values()).map(subscription => \n subscription.stop().catch(error => {\n console.warn('Error stopping subscription:', error);\n })\n );\n\n await Promise.allSettled(promises);\n }\n\n private handleDisconnection(): void {\n this.setState(SessionState.DISCONNECTED);\n this.scheduleReconnect();\n }\n\n private scheduleReconnect(): void {\n const delay = this.config.reconnection?.delay || 1000;\n\n this.setState(SessionState.RECONNECTING);\n this.reconnectAttempts++;\n\n this.reconnectTimer = setTimeout(() => {\n this.connect().catch(error => {\n console.error('Reconnection failed:', error);\n });\n }, delay);\n }\n\n private setState(newState: SessionState): void {\n if (this.state !== newState) {\n this.state = newState;\n this.emit('stateChange', this.status);\n }\n }\n\n private handleError(error: Error): void {\n this.lastError = error;\n this.emit('error', error);\n }\n}"],"names":["EventEmitter","event","listener","eventListeners","args","error","SessionState","BroadcastState","SubscriptionState","MoQBroadcast","config","connection","namespace","Broadcast","broadcastPath","Path","request","data","newState","MoQSubscription","group","frame","receivedData","delay","_a","MoQSession","Connection","configs","trackNames","uniqueTrackNames","duplicates","name","index","desiredTracks","currentTracks","trackName","existing","_b","broadcast","subscription","status","received","namespacePath","announced","announcement","promises"],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ export { MoQSession } from './session';
2
+ export { MoQBroadcast } from './broadcast';
3
+ export { MoQSubscription } from './subscription';
4
+ export type { MoQSessionConfig, BroadcastConfig, SubscriptionConfig, SessionStatus, BroadcastStatus, SubscriptionStatus, DataReceived, SessionEvents, BroadcastEvents, SubscriptionEvents } from './types';
5
+ export { SessionState, BroadcastState, SubscriptionState } from './types';
6
+ export { MoQSession as default } from './session';
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAGjD,YAAY,EACV,gBAAgB,EAChB,eAAe,EACf,kBAAkB,EAClB,aAAa,EACb,eAAe,EACf,kBAAkB,EAClB,YAAY,EACZ,aAAa,EACb,eAAe,EACf,kBAAkB,EACnB,MAAM,SAAS,CAAC;AAGjB,OAAO,EACL,YAAY,EACZ,cAAc,EACd,iBAAiB,EAClB,MAAM,SAAS,CAAC;AAGjB,OAAO,EAAE,UAAU,IAAI,OAAO,EAAE,MAAM,WAAW,CAAC"}