@marianmeres/webrtc 1.1.0 → 1.2.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/API.md CHANGED
@@ -759,6 +759,9 @@ interface WebRtcManagerConfig {
759
759
  /** Initial reconnection delay in ms (doubles each attempt). Default: 1000 */
760
760
  reconnectDelay?: number;
761
761
 
762
+ /** Timeout in ms for full reconnection to reach connected state. Default: 30000 */
763
+ fullReconnectTimeout?: number;
764
+
762
765
  /** Callback to control whether reconnection should proceed */
763
766
  shouldReconnect?: (context: {
764
767
  attempt: number;
@@ -942,19 +945,24 @@ When `autoReconnect: true`:
942
945
  2. **Attempts 3+:** Full reconnection (new peer connection)
943
946
  3. **Backoff:** `reconnectDelay * 2^(attempt-1)` milliseconds
944
947
 
945
- For "full" strategy reconnections, listen for the `reconnecting` event and re-perform signaling:
948
+ #### Full Reconnection and Signaling
949
+
950
+ **Important:** For "full" strategy reconnections, the manager creates a new peer connection but **cannot automatically complete the signaling handshake**. You must listen for the `reconnecting` event and re-perform signaling when `strategy === 'full'`:
946
951
 
947
952
  ```typescript
948
- manager.on('reconnecting', ({ attempt, strategy }) => {
953
+ manager.on('reconnecting', async ({ attempt, strategy }) => {
949
954
  if (strategy === 'full') {
950
955
  // Re-do offer/answer exchange
951
956
  const offer = await manager.createOffer();
952
957
  await manager.setLocalDescription(offer);
953
958
  sendToRemote(offer);
954
959
  }
960
+ // For 'ice-restart', the manager handles it automatically
955
961
  });
956
962
  ```
957
963
 
964
+ If the connection doesn't reach `CONNECTED` state within `fullReconnectTimeout` (default: 30 seconds), it's treated as a failed attempt and the next reconnection attempt begins. When all attempts are exhausted, `EVENT_RECONNECT_FAILED` is emitted.
965
+
958
966
  ### Conditional Reconnection
959
967
 
960
968
  Use the `shouldReconnect` callback to suppress reconnection when the peer disconnected intentionally:
package/README.md CHANGED
@@ -51,6 +51,7 @@ const manager = new WebRtcManager(factory, config);
51
51
  - `autoReconnect`: Enable automatic reconnection (default: false)
52
52
  - `maxReconnectAttempts`: Max reconnection attempts (default: 5)
53
53
  - `reconnectDelay`: Initial reconnection delay in ms (default: 1000)
54
+ - `fullReconnectTimeout`: Timeout in ms for full reconnection to succeed (default: 30000)
54
55
  - `shouldReconnect`: Callback to control whether reconnection should proceed (see below)
55
56
  - `debug`: Enable debug logging (default: false)
56
57
  - `logger`: Custom logger instance implementing `Logger` interface (default: console)
@@ -161,6 +162,39 @@ The callback receives:
161
162
  - `maxAttempts`: Configured maximum attempts
162
163
  - `strategy`: `"ice-restart"` (attempts 1-2) or `"full"` (attempts 3+)
163
164
 
165
+ ### Reconnection Strategies
166
+
167
+ The manager uses two reconnection strategies with exponential backoff:
168
+
169
+ 1. **ICE Restart** (attempts 1-2): Lightweight reconnection that keeps the existing peer connection and restarts ICE negotiation. Works when the network path changed but the remote peer is still available.
170
+
171
+ 2. **Full Reconnection** (attempts 3+): Creates a completely new peer connection. This is necessary when ICE restart fails, but **requires consumer action** to complete the signaling handshake.
172
+
173
+ #### Handling Full Reconnection
174
+
175
+ When a full reconnection is triggered, the manager will:
176
+ 1. Clean up the old peer connection
177
+ 2. Create a new peer connection
178
+ 3. Emit `EVENT_RECONNECTING` with `strategy: 'full'`
179
+
180
+ **Important:** The manager cannot automatically complete the signaling handshake for full reconnections. You must listen for the `reconnecting` event and re-establish signaling when the strategy is `'full'`:
181
+
182
+ ```typescript
183
+ manager.on(WebRtcManager.EVENT_RECONNECTING, async ({ attempt, strategy }) => {
184
+ console.log(`Reconnecting (attempt ${attempt}, strategy: ${strategy})`);
185
+
186
+ if (strategy === 'full') {
187
+ // Re-do the signaling handshake
188
+ const offer = await manager.createOffer();
189
+ await manager.setLocalDescription(offer);
190
+ signalingChannel.send({ type: 'offer', offer });
191
+ }
192
+ // For 'ice-restart', the manager handles it automatically
193
+ });
194
+ ```
195
+
196
+ If the full reconnection doesn't reach `CONNECTED` state within `fullReconnectTimeout` (default: 30 seconds), it's treated as a failed attempt and the next reconnection attempt begins (or `EVENT_RECONNECT_FAILED` is emitted if max attempts reached).
197
+
164
198
  ## Examples
165
199
 
166
200
  ### Basic Usage (Vanilla JavaScript)
package/dist/types.d.ts CHANGED
@@ -26,6 +26,8 @@ export interface WebRtcManagerConfig {
26
26
  maxReconnectAttempts?: number;
27
27
  /** Initial reconnection delay in ms. Doubles with each attempt. Defaults to 1000. */
28
28
  reconnectDelay?: number;
29
+ /** Timeout in ms for full reconnection strategy to reach connected state. Defaults to 30000. */
30
+ fullReconnectTimeout?: number;
29
31
  /**
30
32
  * Callback to determine whether reconnection should be attempted.
31
33
  * Called before each reconnection attempt when autoReconnect is enabled.
@@ -89,6 +89,7 @@ export class WebRtcManager {
89
89
  #dataChannels = new Map();
90
90
  #reconnectAttempts = 0;
91
91
  #reconnectTimer = null;
92
+ #fullReconnectTimeoutTimer = null;
92
93
  #deviceChangeHandler = null;
93
94
  /**
94
95
  * Creates a new WebRtcManager instance.
@@ -705,8 +706,12 @@ export class WebRtcManager {
705
706
  const state = this.#pc.connectionState;
706
707
  this.#debug("Connection state changed:", state);
707
708
  if (state === "connected") {
708
- // Connection successful - reset reconnect attempts
709
+ // Connection successful - reset reconnect attempts and clear any pending timeout
709
710
  this.#reconnectAttempts = 0;
711
+ if (this.#fullReconnectTimeoutTimer !== null) {
712
+ clearTimeout(this.#fullReconnectTimeoutTimer);
713
+ this.#fullReconnectTimeoutTimer = null;
714
+ }
710
715
  this.#dispatch(WebRtcFsmEvent.CONNECTED);
711
716
  }
712
717
  else if (state === "failed") {
@@ -747,6 +752,11 @@ export class WebRtcManager {
747
752
  clearTimeout(this.#reconnectTimer);
748
753
  this.#reconnectTimer = null;
749
754
  }
755
+ // Clear any pending full reconnection timeout
756
+ if (this.#fullReconnectTimeoutTimer !== null) {
757
+ clearTimeout(this.#fullReconnectTimeoutTimer);
758
+ this.#fullReconnectTimeoutTimer = null;
759
+ }
750
760
  // Remove device change listener
751
761
  if (this.#deviceChangeHandler) {
752
762
  navigator.mediaDevices.removeEventListener("devicechange", this.#deviceChangeHandler);
@@ -853,8 +863,21 @@ export class WebRtcManager {
853
863
  // perform the signaling handshake (create offer/answer exchange) to
854
864
  // complete the reconnection.
855
865
  try {
866
+ // Clean up old connection and reset to IDLE so connect() creates a new PC
867
+ this.#cleanup();
868
+ this.#dispatch(WebRtcFsmEvent.RESET);
856
869
  await this.connect();
857
- // If successful, onconnectionstatechange will reset attempts
870
+ // Start timeout for full reconnection - if connection doesn't succeed
871
+ // within the timeout, treat it as a failure
872
+ const timeout = this.#config.fullReconnectTimeout ?? 30000;
873
+ this.#fullReconnectTimeoutTimer = setTimeout(() => {
874
+ this.#fullReconnectTimeoutTimer = null;
875
+ // Only trigger failure if still not connected
876
+ if (this.state !== WebRtcState.CONNECTED) {
877
+ this.#debug("Full reconnection timeout reached, connection not established");
878
+ this.#handleConnectionFailure();
879
+ }
880
+ }, timeout);
858
881
  }
859
882
  catch (e) {
860
883
  this.#logger.error("[WebRtcManager] Reconnection failed:", e);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@marianmeres/webrtc",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "type": "module",
5
5
  "main": "dist/mod.js",
6
6
  "types": "dist/mod.d.ts",