@marianmeres/webrtc 0.0.2 → 1.0.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 CHANGED
@@ -1,6 +1,7 @@
1
1
  # @marianmeres/webrtc
2
2
 
3
- > **Full Disclosure:** This code was written by Claude (Anthropic's AI). The human (that is @marianmeres) just asked nicely, occasionally said "thanks", and went through about 47 iterations of "could you improve this", "what about that", and "make it more Svelte-friendly". To be fair, the prompt engineering was top-notch. So if you find bugs, we'll split the blame 50/50. If it works perfectly, Claude gets 95% of the credit and @marianmeres gets the remaining 5% for excellent taste in asking the right questions. 🤖
3
+ [![NPM Version](https://img.shields.io/npm/v/@marianmeres/webrtc)](https://www.npmjs.com/package/@marianmeres/webrtc)
4
+ [![JSR Version](https://jsr.io/badges/@marianmeres/webrtc)](https://jsr.io/@marianmeres/webrtc)
4
5
 
5
6
  A lightweight, framework-agnostic WebRTC manager with state machine-based lifecycle management and event-driven architecture.
6
7
 
@@ -366,6 +367,10 @@ await connection.createOffer();
366
367
  connection.sendMessage('Hello!');
367
368
  ```
368
369
 
370
+ ## API Reference
371
+
372
+ For complete API documentation, see [API.md](API.md).
373
+
369
374
  ## State Machine
370
375
 
371
376
  The manager uses a finite state machine with the following states:
@@ -1,18 +1,61 @@
1
1
  import { type WebRtcFactory, type WebRtcManagerConfig, WebRtcState, type WebRtcEvents } from "./types.js";
2
+ /**
3
+ * WebRTC connection manager with FSM-based lifecycle and event-driven architecture.
4
+ *
5
+ * Provides a high-level API for managing WebRTC peer connections, audio streams,
6
+ * and data channels. The manager uses a finite state machine to handle connection
7
+ * lifecycle and emits events for all state changes and important occurrences.
8
+ *
9
+ * @example
10
+ * ```typescript
11
+ * const factory = {
12
+ * createPeerConnection: (config) => new RTCPeerConnection(config),
13
+ * getUserMedia: (constraints) => navigator.mediaDevices.getUserMedia(constraints),
14
+ * enumerateDevices: () => navigator.mediaDevices.enumerateDevices(),
15
+ * };
16
+ *
17
+ * const manager = new WebRtcManager(factory, {
18
+ * peerConfig: { iceServers: [{ urls: 'stun:stun.l.google.com:19302' }] },
19
+ * enableMicrophone: true,
20
+ * });
21
+ *
22
+ * await manager.initialize();
23
+ * await manager.connect();
24
+ * const offer = await manager.createOffer();
25
+ * await manager.setLocalDescription(offer);
26
+ * ```
27
+ */
2
28
  export declare class WebRtcManager {
3
29
  #private;
30
+ /** Event emitted when connection state changes. Payload: {@link WebRtcState} */
4
31
  static readonly EVENT_STATE_CHANGE = "state_change";
32
+ /** Event emitted when local media stream changes. Payload: `MediaStream | null` */
5
33
  static readonly EVENT_LOCAL_STREAM = "local_stream";
34
+ /** Event emitted when remote media stream is received. Payload: `MediaStream | null` */
6
35
  static readonly EVENT_REMOTE_STREAM = "remote_stream";
36
+ /** Event emitted when a data channel opens. Payload: `RTCDataChannel` */
7
37
  static readonly EVENT_DATA_CHANNEL_OPEN = "data_channel_open";
38
+ /** Event emitted when a data channel receives a message. Payload: `{ channel: RTCDataChannel; data: any }` */
8
39
  static readonly EVENT_DATA_CHANNEL_MESSAGE = "data_channel_message";
40
+ /** Event emitted when a data channel closes. Payload: `RTCDataChannel` */
9
41
  static readonly EVENT_DATA_CHANNEL_CLOSE = "data_channel_close";
42
+ /** Event emitted when an ICE candidate is generated. Payload: `RTCIceCandidate | null` */
10
43
  static readonly EVENT_ICE_CANDIDATE = "ice_candidate";
44
+ /** Event emitted when reconnection is attempted. Payload: `{ attempt: number; strategy: "ice-restart" | "full" }` */
11
45
  static readonly EVENT_RECONNECTING = "reconnecting";
46
+ /** Event emitted when all reconnection attempts fail. Payload: `{ attempts: number }` */
12
47
  static readonly EVENT_RECONNECT_FAILED = "reconnect_failed";
48
+ /** Event emitted when audio devices change. Payload: `MediaDeviceInfo[]` */
13
49
  static readonly EVENT_DEVICE_CHANGED = "device_changed";
50
+ /** Event emitted when microphone access fails. Payload: `{ error?: any; reason?: string }` */
14
51
  static readonly EVENT_MICROPHONE_FAILED = "microphone_failed";
52
+ /** Event emitted when an error occurs. Payload: `Error` */
15
53
  static readonly EVENT_ERROR = "error";
54
+ /**
55
+ * Creates a new WebRtcManager instance.
56
+ * @param factory - Factory object providing WebRTC primitives (peer connection, media, devices).
57
+ * @param config - Optional configuration for the manager.
58
+ */
16
59
  constructor(factory: WebRtcFactory, config?: WebRtcManagerConfig);
17
60
  /** Returns the current state of the WebRTC connection. */
18
61
  get state(): WebRtcState;
@@ -28,6 +71,8 @@ export declare class WebRtcManager {
28
71
  toMermaid(): string;
29
72
  /**
30
73
  * Subscribe to a specific WebRTC event.
74
+ * @param event - The event name to subscribe to (e.g., "state_change", "ice_candidate").
75
+ * @param handler - Callback function that receives the event data.
31
76
  * @returns Unsubscribe function to remove the event listener.
32
77
  */
33
78
  on(event: keyof WebRtcEvents, handler: (data: any) => void): () => void;
@@ -1,19 +1,56 @@
1
1
  import { FSM } from "@marianmeres/fsm";
2
2
  import { PubSub } from "@marianmeres/pubsub";
3
3
  import { WebRtcState, WebRtcFsmEvent, } from "./types.js";
4
+ /**
5
+ * WebRTC connection manager with FSM-based lifecycle and event-driven architecture.
6
+ *
7
+ * Provides a high-level API for managing WebRTC peer connections, audio streams,
8
+ * and data channels. The manager uses a finite state machine to handle connection
9
+ * lifecycle and emits events for all state changes and important occurrences.
10
+ *
11
+ * @example
12
+ * ```typescript
13
+ * const factory = {
14
+ * createPeerConnection: (config) => new RTCPeerConnection(config),
15
+ * getUserMedia: (constraints) => navigator.mediaDevices.getUserMedia(constraints),
16
+ * enumerateDevices: () => navigator.mediaDevices.enumerateDevices(),
17
+ * };
18
+ *
19
+ * const manager = new WebRtcManager(factory, {
20
+ * peerConfig: { iceServers: [{ urls: 'stun:stun.l.google.com:19302' }] },
21
+ * enableMicrophone: true,
22
+ * });
23
+ *
24
+ * await manager.initialize();
25
+ * await manager.connect();
26
+ * const offer = await manager.createOffer();
27
+ * await manager.setLocalDescription(offer);
28
+ * ```
29
+ */
4
30
  export class WebRtcManager {
5
- // Event name constants
31
+ /** Event emitted when connection state changes. Payload: {@link WebRtcState} */
6
32
  static EVENT_STATE_CHANGE = "state_change";
33
+ /** Event emitted when local media stream changes. Payload: `MediaStream | null` */
7
34
  static EVENT_LOCAL_STREAM = "local_stream";
35
+ /** Event emitted when remote media stream is received. Payload: `MediaStream | null` */
8
36
  static EVENT_REMOTE_STREAM = "remote_stream";
37
+ /** Event emitted when a data channel opens. Payload: `RTCDataChannel` */
9
38
  static EVENT_DATA_CHANNEL_OPEN = "data_channel_open";
39
+ /** Event emitted when a data channel receives a message. Payload: `{ channel: RTCDataChannel; data: any }` */
10
40
  static EVENT_DATA_CHANNEL_MESSAGE = "data_channel_message";
41
+ /** Event emitted when a data channel closes. Payload: `RTCDataChannel` */
11
42
  static EVENT_DATA_CHANNEL_CLOSE = "data_channel_close";
43
+ /** Event emitted when an ICE candidate is generated. Payload: `RTCIceCandidate | null` */
12
44
  static EVENT_ICE_CANDIDATE = "ice_candidate";
45
+ /** Event emitted when reconnection is attempted. Payload: `{ attempt: number; strategy: "ice-restart" | "full" }` */
13
46
  static EVENT_RECONNECTING = "reconnecting";
47
+ /** Event emitted when all reconnection attempts fail. Payload: `{ attempts: number }` */
14
48
  static EVENT_RECONNECT_FAILED = "reconnect_failed";
49
+ /** Event emitted when audio devices change. Payload: `MediaDeviceInfo[]` */
15
50
  static EVENT_DEVICE_CHANGED = "device_changed";
51
+ /** Event emitted when microphone access fails. Payload: `{ error?: any; reason?: string }` */
16
52
  static EVENT_MICROPHONE_FAILED = "microphone_failed";
53
+ /** Event emitted when an error occurs. Payload: `Error` */
17
54
  static EVENT_ERROR = "error";
18
55
  #fsm;
19
56
  #pubsub;
@@ -26,6 +63,11 @@ export class WebRtcManager {
26
63
  #reconnectAttempts = 0;
27
64
  #reconnectTimer = null;
28
65
  #deviceChangeHandler = null;
66
+ /**
67
+ * Creates a new WebRtcManager instance.
68
+ * @param factory - Factory object providing WebRTC primitives (peer connection, media, devices).
69
+ * @param config - Optional configuration for the manager.
70
+ */
29
71
  constructor(factory, config = {}) {
30
72
  this.#factory = factory;
31
73
  this.#config = config;
@@ -103,6 +145,8 @@ export class WebRtcManager {
103
145
  }
104
146
  /**
105
147
  * Subscribe to a specific WebRTC event.
148
+ * @param event - The event name to subscribe to (e.g., "state_change", "ice_candidate").
149
+ * @param handler - Callback function that receives the event data.
106
150
  * @returns Unsubscribe function to remove the event listener.
107
151
  */
108
152
  on(event, handler) {
package/llm.txt ADDED
@@ -0,0 +1,364 @@
1
+ # @marianmeres/webrtc - LLM Knowledge Base
2
+
3
+ ## Package Identity
4
+
5
+ name: @marianmeres/webrtc
6
+ version: 0.0.2
7
+ license: MIT
8
+ author: Marian Meres
9
+ repository: https://github.com/marianmeres/webrtc
10
+ runtime: Deno (source), Node.js/Browser (distribution)
11
+ type: WebRTC connection management library
12
+
13
+ ## Purpose
14
+
15
+ A lightweight, framework-agnostic WebRTC manager providing:
16
+ - Finite State Machine (FSM) based lifecycle management
17
+ - Event-driven architecture with PubSub pattern
18
+ - Svelte store compatibility
19
+ - Audio device management (microphone switching)
20
+ - Data channel support
21
+ - Auto-reconnection with exponential backoff
22
+ - Full TypeScript type safety
23
+
24
+ ## Architecture Overview
25
+
26
+ ```
27
+ WebRtcManager
28
+ ├── FSM (@marianmeres/fsm) - State transitions
29
+ ├── PubSub (@marianmeres/pubsub) - Event subscriptions
30
+ ├── RTCPeerConnection - WebRTC connection (via factory)
31
+ ├── MediaStream (local/remote) - Audio streams
32
+ └── DataChannels Map - RTCDataChannel instances
33
+ ```
34
+
35
+ ## Dependencies
36
+
37
+ Production:
38
+ - @marianmeres/fsm: ^2.3.0 (state machine)
39
+ - @marianmeres/pubsub: ^2.3.0 (event system)
40
+
41
+ Development (Deno):
42
+ - @std/assert: testing
43
+ - @std/fs: file operations
44
+ - @std/path: path utilities
45
+
46
+ ## File Structure
47
+
48
+ ```
49
+ src/
50
+ ├── mod.ts # Entry point, re-exports all public APIs
51
+ ├── types.ts # Type definitions (interfaces, enums)
52
+ └── webrtc-manager.ts # Main WebRtcManager class (839 lines)
53
+
54
+ tests/
55
+ ├── mocks.ts # Mock WebRtcFactory for testing
56
+ ├── webrtc-manager.test.ts # Deno unit tests
57
+ └── browser/
58
+ ├── p2p-tests.ts # Browser integration tests
59
+ └── README.md # Browser test documentation
60
+
61
+ example/
62
+ ├── peer.ts # Two-peer example with localStorage signaling
63
+ ├── p2p.ts # Single-page P2P example
64
+ ├── audio-peer.ts # Audio testing implementation
65
+ └── main.ts # Signaling server example
66
+
67
+ scripts/
68
+ ├── build-npm.ts # npm distribution build
69
+ ├── build-example.ts # Example bundling
70
+ ├── build-browser-tests.ts
71
+ ├── serve-browser-tests.ts
72
+ └── signaling-server.ts
73
+ ```
74
+
75
+ ## State Machine
76
+
77
+ ### States (WebRtcState enum)
78
+
79
+ | State | Description | Valid Transitions |
80
+ |-------|-------------|-------------------|
81
+ | IDLE | Initial state, no resources | → INITIALIZING |
82
+ | INITIALIZING | Creating peer connection | → CONNECTING, ERROR |
83
+ | CONNECTING | Performing SDP exchange | → CONNECTED, DISCONNECTED, ERROR |
84
+ | CONNECTED | Connection established | → DISCONNECTED, ERROR |
85
+ | RECONNECTING | Auto-reconnection in progress | → CONNECTING, DISCONNECTED, IDLE |
86
+ | DISCONNECTED | Closed but recoverable | → CONNECTING, RECONNECTING, IDLE |
87
+ | ERROR | Error occurred, must reset | → IDLE |
88
+
89
+ ### Events (WebRtcFsmEvent enum)
90
+
91
+ | Event | Description |
92
+ |-------|-------------|
93
+ | INIT ("initialize") | Start initialization |
94
+ | CONNECT ("connect") | Begin connection |
95
+ | CONNECTED ("connected") | Connection succeeded |
96
+ | RECONNECTING ("reconnecting") | Start reconnection |
97
+ | DISCONNECT ("disconnect") | Close connection |
98
+ | ERROR ("error") | Error occurred |
99
+ | RESET ("reset") | Return to IDLE |
100
+
101
+ ### State Transition Diagram
102
+
103
+ ```
104
+ IDLE --INIT--> INITIALIZING --CONNECT--> CONNECTING --CONNECTED--> CONNECTED
105
+ | | |
106
+ v v v
107
+ ERROR <-----------------ERROR<----------------------ERROR
108
+ |
109
+ v
110
+ IDLE (via RESET)
111
+
112
+ CONNECTED --DISCONNECT--> DISCONNECTED --RESET--> IDLE
113
+ |
114
+ v
115
+ RECONNECTING --CONNECT--> CONNECTING
116
+ ```
117
+
118
+ ## Public API
119
+
120
+ ### Constructor
121
+
122
+ ```typescript
123
+ new WebRtcManager(factory: WebRtcFactory, config?: WebRtcManagerConfig)
124
+ ```
125
+
126
+ ### WebRtcFactory Interface
127
+
128
+ ```typescript
129
+ interface WebRtcFactory {
130
+ createPeerConnection(config?: RTCConfiguration): RTCPeerConnection;
131
+ getUserMedia(constraints: MediaStreamConstraints): Promise<MediaStream>;
132
+ enumerateDevices(): Promise<MediaDeviceInfo[]>;
133
+ }
134
+ ```
135
+
136
+ Browser implementation:
137
+ ```typescript
138
+ const factory = {
139
+ createPeerConnection: (config) => new RTCPeerConnection(config),
140
+ getUserMedia: (constraints) => navigator.mediaDevices.getUserMedia(constraints),
141
+ enumerateDevices: () => navigator.mediaDevices.enumerateDevices(),
142
+ };
143
+ ```
144
+
145
+ ### WebRtcManagerConfig Interface
146
+
147
+ ```typescript
148
+ interface WebRtcManagerConfig {
149
+ peerConfig?: RTCConfiguration; // ICE servers, certificates
150
+ enableMicrophone?: boolean; // Enable mic on init (default: false)
151
+ dataChannelLabel?: string; // Auto-create data channel
152
+ autoReconnect?: boolean; // Enable auto-reconnect (default: false)
153
+ maxReconnectAttempts?: number; // Max attempts (default: 5)
154
+ reconnectDelay?: number; // Initial delay ms (default: 1000)
155
+ debug?: boolean; // Enable logging (default: false)
156
+ }
157
+ ```
158
+
159
+ ### Properties (Getters)
160
+
161
+ | Property | Type | Description |
162
+ |----------|------|-------------|
163
+ | state | WebRtcState | Current FSM state |
164
+ | localStream | MediaStream \| null | Local audio stream |
165
+ | remoteStream | MediaStream \| null | Remote audio stream |
166
+ | dataChannels | ReadonlyMap<string, RTCDataChannel> | Active data channels |
167
+ | peerConnection | RTCPeerConnection \| null | Underlying connection |
168
+
169
+ ### Lifecycle Methods
170
+
171
+ | Method | Signature | Description |
172
+ |--------|-----------|-------------|
173
+ | initialize | `(): Promise<void>` | Create peer connection, setup tracks |
174
+ | connect | `(): Promise<void>` | Transition to CONNECTING (auto-initializes) |
175
+ | disconnect | `(): void` | Close connection, cleanup resources |
176
+ | reset | `(): void` | Reset to IDLE from any state |
177
+
178
+ ### Audio Methods
179
+
180
+ | Method | Signature | Returns | Description |
181
+ |--------|-----------|---------|-------------|
182
+ | enableMicrophone | `(enable: boolean): Promise<boolean>` | success | Enable/disable microphone |
183
+ | switchMicrophone | `(deviceId: string): Promise<boolean>` | success | Switch audio input device |
184
+ | getAudioInputDevices | `(): Promise<MediaDeviceInfo[]>` | devices | List audio inputs |
185
+
186
+ ### Data Channel Methods
187
+
188
+ | Method | Signature | Returns | Description |
189
+ |--------|-----------|---------|-------------|
190
+ | createDataChannel | `(label: string, options?: RTCDataChannelInit): RTCDataChannel \| null` | channel | Create/get data channel |
191
+ | getDataChannel | `(label: string): RTCDataChannel \| undefined` | channel | Get existing channel |
192
+ | sendData | `(label: string, data: string \| Blob \| ArrayBuffer \| ArrayBufferView): boolean` | success | Send through channel |
193
+
194
+ ### Signaling Methods
195
+
196
+ | Method | Signature | Returns | Description |
197
+ |--------|-----------|---------|-------------|
198
+ | createOffer | `(options?: RTCOfferOptions): Promise<RTCSessionDescriptionInit \| null>` | offer | Create SDP offer |
199
+ | createAnswer | `(options?: RTCAnswerOptions): Promise<RTCSessionDescriptionInit \| null>` | answer | Create SDP answer |
200
+ | setLocalDescription | `(description: RTCSessionDescriptionInit): Promise<boolean>` | success | Set local SDP |
201
+ | setRemoteDescription | `(description: RTCSessionDescriptionInit): Promise<boolean>` | success | Set remote SDP |
202
+ | addIceCandidate | `(candidate: RTCIceCandidateInit \| null): Promise<boolean>` | success | Add ICE candidate |
203
+ | iceRestart | `(): Promise<boolean>` | success | Perform ICE restart |
204
+ | getLocalDescription | `(): RTCSessionDescription \| null` | description | Get local SDP |
205
+ | getRemoteDescription | `(): RTCSessionDescription \| null` | description | Get remote SDP |
206
+ | getStats | `(): Promise<RTCStatsReport \| null>` | stats | Get connection statistics |
207
+
208
+ ### Event Subscription Methods
209
+
210
+ | Method | Signature | Returns | Description |
211
+ |--------|-----------|---------|-------------|
212
+ | on | `<K extends keyof WebRtcEvents>(event: K, handler: (data: WebRtcEvents[K]) => void): () => void` | unsubscribe | Subscribe to specific event |
213
+ | subscribe | `(handler: (state: OverallState) => void): () => void` | unsubscribe | Subscribe to overall state (Svelte compatible) |
214
+
215
+ ### Utility Methods
216
+
217
+ | Method | Signature | Returns | Description |
218
+ |--------|-----------|---------|-------------|
219
+ | toMermaid | `(): string` | mermaid | Get FSM as Mermaid diagram |
220
+
221
+ ## Events
222
+
223
+ ### Event Constants (Static)
224
+
225
+ | Constant | Value | Payload Type |
226
+ |----------|-------|--------------|
227
+ | EVENT_STATE_CHANGE | "state_change" | WebRtcState |
228
+ | EVENT_LOCAL_STREAM | "local_stream" | MediaStream \| null |
229
+ | EVENT_REMOTE_STREAM | "remote_stream" | MediaStream \| null |
230
+ | EVENT_DATA_CHANNEL_OPEN | "data_channel_open" | RTCDataChannel |
231
+ | EVENT_DATA_CHANNEL_MESSAGE | "data_channel_message" | { channel: RTCDataChannel; data: any } |
232
+ | EVENT_DATA_CHANNEL_CLOSE | "data_channel_close" | RTCDataChannel |
233
+ | EVENT_ICE_CANDIDATE | "ice_candidate" | RTCIceCandidate \| null |
234
+ | EVENT_RECONNECTING | "reconnecting" | { attempt: number; strategy: "ice-restart" \| "full" } |
235
+ | EVENT_RECONNECT_FAILED | "reconnect_failed" | { attempts: number } |
236
+ | EVENT_DEVICE_CHANGED | "device_changed" | MediaDeviceInfo[] |
237
+ | EVENT_MICROPHONE_FAILED | "microphone_failed" | { error?: any; reason?: string } |
238
+ | EVENT_ERROR | "error" | Error |
239
+
240
+ ### WebRtcEvents Interface
241
+
242
+ ```typescript
243
+ interface WebRtcEvents {
244
+ state_change: WebRtcState;
245
+ local_stream: MediaStream | null;
246
+ remote_stream: MediaStream | null;
247
+ data_channel_open: RTCDataChannel;
248
+ data_channel_message: { channel: RTCDataChannel; data: any };
249
+ data_channel_close: RTCDataChannel;
250
+ ice_candidate: RTCIceCandidate | null;
251
+ reconnecting: { attempt: number; strategy: "ice-restart" | "full" };
252
+ reconnect_failed: { attempts: number };
253
+ device_changed: MediaDeviceInfo[];
254
+ microphone_failed: { error?: any; reason?: string };
255
+ error: Error;
256
+ }
257
+ ```
258
+
259
+ ## Signaling Flow (User Responsibility)
260
+
261
+ The library does NOT handle signaling transport. Users must:
262
+
263
+ 1. Create signaling channel (WebSocket, HTTP, localStorage, etc.)
264
+ 2. Listen for `ice_candidate` events and send to remote peer
265
+ 3. Send offers/answers through signaling channel
266
+ 4. Receive remote offers/answers and call setRemoteDescription
267
+ 5. Receive remote ICE candidates and call addIceCandidate
268
+
269
+ ### Offer/Answer Flow
270
+
271
+ ```
272
+ Initiator: Responder:
273
+ 1. initialize()
274
+ 2. connect()
275
+ 3. createOffer()
276
+ 4. setLocalDescription(offer)
277
+ 5. [send offer via signaling] ───→ 6. initialize()
278
+ 7. setRemoteDescription(offer)
279
+ 8. createAnswer()
280
+ 9. setLocalDescription(answer)
281
+ 10. setRemoteDescription(answer) ←── [send answer via signaling]
282
+ 11. [exchange ICE candidates] ←───→ [exchange ICE candidates]
283
+ 12. CONNECTED 12. CONNECTED
284
+ ```
285
+
286
+ ## Reconnection Strategy
287
+
288
+ When autoReconnect is enabled:
289
+
290
+ 1. Attempts 1-2: ICE restart (preserves connection, quick recovery)
291
+ 2. Attempts 3+: Full reconnection (new peer connection)
292
+ 3. Exponential backoff: delay * 2^(attempt-1)
293
+ 4. Max attempts configurable (default: 5)
294
+
295
+ For "full" strategy reconnections, consumers MUST:
296
+ - Listen for `reconnecting` event with strategy="full"
297
+ - Re-perform signaling handshake (create new offer/answer)
298
+
299
+ ## Error Handling Patterns
300
+
301
+ 1. Methods return boolean for success/failure
302
+ 2. Critical errors transition to ERROR state
303
+ 3. ERROR state requires reset() to recover
304
+ 4. EVENT_ERROR emitted for all errors
305
+ 5. Specific events: EVENT_MICROPHONE_FAILED, EVENT_RECONNECT_FAILED
306
+
307
+ ## Testing
308
+
309
+ ### Unit Tests (Deno)
310
+ ```bash
311
+ deno task test
312
+ ```
313
+
314
+ ### Browser Integration Tests
315
+ ```bash
316
+ deno task test:browser
317
+ ```
318
+
319
+ ## Build Commands
320
+
321
+ ```bash
322
+ deno task npm:build # Build npm distribution
323
+ deno task npm:publish # Build and publish to npm
324
+ deno task build:example # Build examples
325
+ deno task serve:example # Run signaling server
326
+ ```
327
+
328
+ ## Important Implementation Details
329
+
330
+ 1. subscribe() is Svelte store compatible (immediate callback + updates)
331
+ 2. Data channels auto-cleanup on close
332
+ 3. Device change listener auto-setup on initialize
333
+ 4. "User-Initiated Abort" errors from intentional close() are ignored
334
+ 5. recvonly transceiver added when microphone disabled (ensures audio SDP)
335
+ 6. Private fields use # (true private, not accessible externally)
336
+
337
+ ## Common Usage Patterns
338
+
339
+ ### Minimal P2P Setup
340
+ ```typescript
341
+ const manager = new WebRtcManager(factory, { enableMicrophone: true });
342
+ await manager.initialize();
343
+ await manager.connect();
344
+ const offer = await manager.createOffer();
345
+ await manager.setLocalDescription(offer);
346
+ // Send offer, receive answer, exchange ICE candidates...
347
+ ```
348
+
349
+ ### With Data Channel
350
+ ```typescript
351
+ const manager = new WebRtcManager(factory, { dataChannelLabel: "chat" });
352
+ manager.on("data_channel_message", ({ data }) => console.log(data));
353
+ // After connection...
354
+ manager.sendData("chat", "Hello!");
355
+ ```
356
+
357
+ ### Svelte Integration
358
+ ```svelte
359
+ <script>
360
+ const manager = new WebRtcManager(factory, config);
361
+ // $manager reactive access to state
362
+ </script>
363
+ {$manager.state}
364
+ ```
package/package.json CHANGED
@@ -1,20 +1,20 @@
1
1
  {
2
2
  "name": "@marianmeres/webrtc",
3
- "version": "0.0.2",
3
+ "version": "1.0.0",
4
4
  "type": "module",
5
5
  "main": "dist/mod.js",
6
6
  "types": "dist/mod.d.ts",
7
7
  "author": "Marian Meres",
8
8
  "license": "MIT",
9
+ "dependencies": {
10
+ "@marianmeres/fsm": "^2.5.4",
11
+ "@marianmeres/pubsub": "^2.4.2"
12
+ },
9
13
  "repository": {
10
14
  "type": "git",
11
15
  "url": "git+https://github.com/marianmeres/webrtc.git"
12
16
  },
13
17
  "bugs": {
14
18
  "url": "https://github.com/marianmeres/webrtc/issues"
15
- },
16
- "dependencies": {
17
- "@marianmeres/fsm": "^2.3.0",
18
- "@marianmeres/pubsub": "^2.3.0"
19
19
  }
20
- }
20
+ }