@signalwire/js 4.0.0-dev-20260420151734 → 4.0.0-dev-20260421201955
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/browser.mjs +208 -123
- package/dist/browser.mjs.map +1 -1
- package/dist/browser.umd.js +208 -123
- package/dist/browser.umd.js.map +1 -1
- package/dist/index.cjs +164 -78
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +35 -7
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +35 -7
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +156 -70
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -143,7 +143,7 @@ const POST_PARAMS = {
|
|
|
143
143
|
"Content-Type": "application/json"
|
|
144
144
|
}
|
|
145
145
|
};
|
|
146
|
-
var HTTPRequestController = class HTTPRequestController {
|
|
146
|
+
var HTTPRequestController = class HTTPRequestController extends Destroyable {
|
|
147
147
|
static {
|
|
148
148
|
this.defaultMaxRetries = 3;
|
|
149
149
|
}
|
|
@@ -164,11 +164,12 @@ var HTTPRequestController = class HTTPRequestController {
|
|
|
164
164
|
]);
|
|
165
165
|
}
|
|
166
166
|
constructor(baseURL, getCredential, options = {}) {
|
|
167
|
+
super();
|
|
167
168
|
this.baseURL = baseURL;
|
|
168
169
|
this.getCredential = getCredential;
|
|
169
|
-
this._responses$ =
|
|
170
|
-
this._errors$ =
|
|
171
|
-
this._status$ =
|
|
170
|
+
this._responses$ = this.createSubject();
|
|
171
|
+
this._errors$ = this.createSubject();
|
|
172
|
+
this._status$ = this.createBehaviorSubject("idle");
|
|
172
173
|
this.maxRetries = options.maxRetries ?? HTTPRequestController.defaultMaxRetries;
|
|
173
174
|
this.retryDelayMin = options.retryDelayMin ?? HTTPRequestController.defaultRetryDelayMinMs;
|
|
174
175
|
this.retryDelayMax = options.retryDelayMax ?? HTTPRequestController.defaultRetryDelayMaxMs;
|
|
@@ -478,6 +479,12 @@ const DEFAULT_ICE_DISCONNECTED_GRACE_PERIOD_MS = 3e3;
|
|
|
478
479
|
const DEFAULT_ICE_RESTART_TIMEOUT_MS$1 = 5e3;
|
|
479
480
|
/** Maximum recovery attempts before emitting 'max_attempts_reached'. */
|
|
480
481
|
const DEFAULT_MAX_RECOVERY_ATTEMPTS = 3;
|
|
482
|
+
/** Upper bound in ms for waiting on iceGatheringState === 'complete' after an ICE restart. */
|
|
483
|
+
const ICE_GATHERING_COMPLETE_TIMEOUT_MS = 1e4;
|
|
484
|
+
/** Upper bound in ms for waiting on RTCPeerConnection.connectionState === 'connected' after a recovery ICE restart. */
|
|
485
|
+
const PEER_CONNECTION_RECOVERY_WAIT_MS = 5e3;
|
|
486
|
+
/** Polling interval in ms while waiting for RTCPeerConnection.connectionState to transition. */
|
|
487
|
+
const PEER_CONNECTION_RECOVERY_POLL_MS = 100;
|
|
481
488
|
/** Whether to persist device selections to storage by default. */
|
|
482
489
|
const DEFAULT_PERSIST_DEVICE_SELECTION = true;
|
|
483
490
|
/** Whether to auto-apply device changes to active calls by default. */
|
|
@@ -2428,7 +2435,7 @@ var PreflightRunner = class extends Destroyable {
|
|
|
2428
2435
|
const candidateTypes = /* @__PURE__ */ new Set();
|
|
2429
2436
|
const startTime = Date.now();
|
|
2430
2437
|
const gatheringComplete = new Promise((resolve) => {
|
|
2431
|
-
const timer$
|
|
2438
|
+
const timer$3 = setTimeout(resolve, ICE_GATHERING_TIMEOUT_MS);
|
|
2432
2439
|
peerConnection.onicecandidate = (event) => {
|
|
2433
2440
|
if (event.candidate) {
|
|
2434
2441
|
const candidateStr = event.candidate.candidate;
|
|
@@ -2436,7 +2443,7 @@ var PreflightRunner = class extends Destroyable {
|
|
|
2436
2443
|
if (candidateStr.includes("typ srflx")) candidateTypes.add("srflx");
|
|
2437
2444
|
if (candidateStr.includes("typ relay")) candidateTypes.add("relay");
|
|
2438
2445
|
} else {
|
|
2439
|
-
clearTimeout(timer$
|
|
2446
|
+
clearTimeout(timer$3);
|
|
2440
2447
|
resolve();
|
|
2441
2448
|
}
|
|
2442
2449
|
};
|
|
@@ -2797,13 +2804,11 @@ var AttachManager = class {
|
|
|
2797
2804
|
this.deviceController = deviceController;
|
|
2798
2805
|
this.reconnectCallsTimeout = reconnectCallsTimeout;
|
|
2799
2806
|
this.attachKey = attachKey;
|
|
2807
|
+
this.writeQueue = Promise.resolve();
|
|
2800
2808
|
}
|
|
2801
2809
|
async detachAll() {
|
|
2802
|
-
|
|
2803
|
-
|
|
2804
|
-
id: callId,
|
|
2805
|
-
nodeId: attached[callId].nodeId,
|
|
2806
|
-
mediaDirections: attached[callId].mediaDirections
|
|
2810
|
+
await this.mutate((attached) => {
|
|
2811
|
+
return {};
|
|
2807
2812
|
});
|
|
2808
2813
|
}
|
|
2809
2814
|
setSession(session) {
|
|
@@ -2824,31 +2829,47 @@ var AttachManager = class {
|
|
|
2824
2829
|
logger$21.warn("[AttachManager] Failed to write attached calls to storage", error);
|
|
2825
2830
|
}
|
|
2826
2831
|
}
|
|
2832
|
+
/**
|
|
2833
|
+
* Serialize a read-modify-write operation against the attached-calls
|
|
2834
|
+
* storage. The mutator receives the current state and returns the new
|
|
2835
|
+
* state. Concurrent calls queue behind the in-flight one so writes never
|
|
2836
|
+
* interleave.
|
|
2837
|
+
*/
|
|
2838
|
+
async mutate(mutator) {
|
|
2839
|
+
const next = this.writeQueue.then(async () => {
|
|
2840
|
+
const updated = await mutator(await this.readAttached());
|
|
2841
|
+
await this.writeAttached(updated);
|
|
2842
|
+
});
|
|
2843
|
+
this.writeQueue = next.catch(() => void 0);
|
|
2844
|
+
return next;
|
|
2845
|
+
}
|
|
2827
2846
|
async attach(call) {
|
|
2828
2847
|
if (!call.to) {
|
|
2829
2848
|
logger$21.warn("[AttachManager] Skip attach for calls with no destination");
|
|
2830
2849
|
return;
|
|
2831
2850
|
}
|
|
2851
|
+
const destination = call.to;
|
|
2832
2852
|
const attachment = {
|
|
2833
2853
|
nodeId: call.nodeId,
|
|
2834
|
-
destination
|
|
2854
|
+
destination,
|
|
2835
2855
|
mediaDirections: call.mediaDirections,
|
|
2836
2856
|
audioInputDevice: call.mediaDirections.audio !== "inactive" ? this.deviceController.selectedAudioInputDevice : null,
|
|
2837
2857
|
videoInputDevice: call.mediaDirections.video !== "inactive" ? this.deviceController.selectedVideoInputDevice : null,
|
|
2838
2858
|
attachedAt: Date.now()
|
|
2839
2859
|
};
|
|
2840
|
-
|
|
2841
|
-
...
|
|
2860
|
+
await this.mutate((attached) => ({
|
|
2861
|
+
...attached,
|
|
2842
2862
|
[call.id]: attachment
|
|
2843
|
-
};
|
|
2844
|
-
await this.writeAttached(updated);
|
|
2863
|
+
}));
|
|
2845
2864
|
}
|
|
2846
2865
|
async detach(call) {
|
|
2847
|
-
|
|
2848
|
-
|
|
2866
|
+
await this.mutate((attached) => {
|
|
2867
|
+
const { [call.id]: _, ...remaining } = attached;
|
|
2868
|
+
return remaining;
|
|
2869
|
+
});
|
|
2849
2870
|
}
|
|
2850
2871
|
async flush() {
|
|
2851
|
-
await this.
|
|
2872
|
+
await this.mutate(() => ({}));
|
|
2852
2873
|
}
|
|
2853
2874
|
/**
|
|
2854
2875
|
* Reattach to previously active calls by sending verto.invite with
|
|
@@ -2920,20 +2941,31 @@ var AttachManager = class {
|
|
|
2920
2941
|
};
|
|
2921
2942
|
}
|
|
2922
2943
|
/**
|
|
2923
|
-
*
|
|
2924
|
-
*
|
|
2944
|
+
* Look up stored attachment data for a call id and return CallOptions
|
|
2945
|
+
* suitable for rehydrating a reattached call. Returns undefined when no
|
|
2946
|
+
* matching entry exists in storage.
|
|
2947
|
+
*
|
|
2948
|
+
* Used by the session-level verto.attach handler when the server pushes
|
|
2949
|
+
* an attach event for a call the client doesn't have an object for yet
|
|
2950
|
+
* (e.g. after a reload).
|
|
2925
2951
|
*/
|
|
2926
|
-
consumePendingAttachment(
|
|
2952
|
+
async consumePendingAttachment(callId) {
|
|
2953
|
+
const attachment = (await this.readAttached())[callId];
|
|
2954
|
+
if (!attachment) return;
|
|
2955
|
+
return this.buildCallOptions(attachment);
|
|
2956
|
+
}
|
|
2927
2957
|
async detachExpired() {
|
|
2928
|
-
const attached = await this.readAttached();
|
|
2929
2958
|
const now = Date.now();
|
|
2930
2959
|
const timeout$4 = this.reconnectCallsTimeout;
|
|
2931
|
-
|
|
2932
|
-
if (expired.length > 0) {
|
|
2960
|
+
await this.mutate((attached) => {
|
|
2933
2961
|
const remaining = { ...attached };
|
|
2934
|
-
|
|
2935
|
-
|
|
2936
|
-
|
|
2962
|
+
let changed = false;
|
|
2963
|
+
for (const [callId, attachment] of Object.entries(attached)) if (now - attachment.attachedAt > timeout$4) {
|
|
2964
|
+
delete remaining[callId];
|
|
2965
|
+
changed = true;
|
|
2966
|
+
}
|
|
2967
|
+
return changed ? remaining : attached;
|
|
2968
|
+
});
|
|
2937
2969
|
}
|
|
2938
2970
|
};
|
|
2939
2971
|
|
|
@@ -4401,12 +4433,12 @@ var ICEGatheringController = class extends Destroyable {
|
|
|
4401
4433
|
...this.peerConnection.getConfiguration(),
|
|
4402
4434
|
iceTransportPolicy: "relay"
|
|
4403
4435
|
});
|
|
4404
|
-
|
|
4436
|
+
this.peerConnection.restartIce();
|
|
4405
4437
|
}
|
|
4406
|
-
removeTimer(timer$
|
|
4407
|
-
if (this[timer$
|
|
4408
|
-
clearTimeout(this[timer$
|
|
4409
|
-
this[timer$
|
|
4438
|
+
removeTimer(timer$3) {
|
|
4439
|
+
if (this[timer$3]) {
|
|
4440
|
+
clearTimeout(this[timer$3]);
|
|
4441
|
+
this[timer$3] = void 0;
|
|
4410
4442
|
}
|
|
4411
4443
|
}
|
|
4412
4444
|
clearAllTimers() {
|
|
@@ -5370,9 +5402,6 @@ var RTCPeerConnectionController = class extends Destroyable {
|
|
|
5370
5402
|
negotiationEnded() {
|
|
5371
5403
|
this._isNegotiating$.next(false);
|
|
5372
5404
|
}
|
|
5373
|
-
restarIce() {
|
|
5374
|
-
this.peerConnection?.restartIce();
|
|
5375
|
-
}
|
|
5376
5405
|
/**
|
|
5377
5406
|
* Trigger an ICE restart through the existing negotiation pipeline.
|
|
5378
5407
|
*
|
|
@@ -5412,7 +5441,10 @@ var RTCPeerConnectionController = class extends Destroyable {
|
|
|
5412
5441
|
if (policyChanged) this.restoreIceTransportPolicy();
|
|
5413
5442
|
throw error;
|
|
5414
5443
|
}
|
|
5415
|
-
if (policyChanged) this.restoreIceTransportPolicy()
|
|
5444
|
+
if (policyChanged) (0, rxjs.firstValueFrom)((0, rxjs.race)(this._iceGatheringState$.pipe((0, rxjs.filter)((state) => state === "complete"), (0, rxjs.take)(1)), (0, rxjs.timer)(ICE_GATHERING_COMPLETE_TIMEOUT_MS).pipe((0, rxjs.map)(() => "timeout")))).then(() => this.restoreIceTransportPolicy()).catch((error) => {
|
|
5445
|
+
logger$15.warn("[RTCPeerConnectionController] Error waiting for ICE gathering to complete:", error);
|
|
5446
|
+
this.restoreIceTransportPolicy();
|
|
5447
|
+
});
|
|
5416
5448
|
}
|
|
5417
5449
|
restoreIceTransportPolicy() {
|
|
5418
5450
|
try {
|
|
@@ -6584,11 +6616,11 @@ var RTCStatsMonitor = class extends Destroyable {
|
|
|
6584
6616
|
let availableOutgoingBitrate;
|
|
6585
6617
|
report.forEach((stat) => {
|
|
6586
6618
|
if (isInboundRtpStat(stat)) if (stat.kind === "audio") {
|
|
6587
|
-
audioPacketsReceived += stat.packetsReceived ??
|
|
6619
|
+
audioPacketsReceived += stat.packetsReceived ?? 0;
|
|
6588
6620
|
audioPacketsLost += stat.packetsLost ?? 0;
|
|
6589
6621
|
audioJitter = Math.max(audioJitter, (stat.jitter ?? 0) * 1e3);
|
|
6590
6622
|
} else {
|
|
6591
|
-
videoPacketsReceived += stat.packetsReceived ??
|
|
6623
|
+
videoPacketsReceived += stat.packetsReceived ?? 0;
|
|
6592
6624
|
videoPacketsLost += stat.packetsLost ?? 0;
|
|
6593
6625
|
}
|
|
6594
6626
|
if (isCandidatePairStat(stat) && stat.state === "succeeded" && stat.nominated) {
|
|
@@ -7636,10 +7668,10 @@ var WebRTCCall = class extends Destroyable {
|
|
|
7636
7668
|
try {
|
|
7637
7669
|
if (this.vertoManager.requestIceRestartAll) await this.vertoManager.requestIceRestartAll(relayOnly);
|
|
7638
7670
|
else await this.vertoManager.requestIceRestart?.(relayOnly);
|
|
7639
|
-
return true;
|
|
7640
7671
|
} catch {
|
|
7641
7672
|
return false;
|
|
7642
7673
|
}
|
|
7674
|
+
return this.waitForPeerConnectionConnected();
|
|
7643
7675
|
},
|
|
7644
7676
|
disableVideo: () => {
|
|
7645
7677
|
try {
|
|
@@ -7731,6 +7763,27 @@ var WebRTCCall = class extends Destroyable {
|
|
|
7731
7763
|
}
|
|
7732
7764
|
}
|
|
7733
7765
|
/**
|
|
7766
|
+
* Wait for the underlying RTCPeerConnection to reach 'connected' after
|
|
7767
|
+
* triggering an ICE restart. Resolves true on success, false on failure
|
|
7768
|
+
* or if the state doesn't transition within the configured timeout.
|
|
7769
|
+
*
|
|
7770
|
+
* Polls connectionState directly because the recovery manager already
|
|
7771
|
+
* wraps this call in its own withTimeout(); a separate listener-based
|
|
7772
|
+
* implementation would race the outer timeout in subtle ways.
|
|
7773
|
+
*/
|
|
7774
|
+
async waitForPeerConnectionConnected() {
|
|
7775
|
+
const pc = this.rtcPeerConnection;
|
|
7776
|
+
if (!pc) return false;
|
|
7777
|
+
const deadline = Date.now() + PEER_CONNECTION_RECOVERY_WAIT_MS;
|
|
7778
|
+
while (true) {
|
|
7779
|
+
const state = pc.connectionState;
|
|
7780
|
+
if (state === "connected") return true;
|
|
7781
|
+
if (state === "failed" || state === "closed") return false;
|
|
7782
|
+
if (Date.now() >= deadline) return false;
|
|
7783
|
+
await new Promise((resolve) => setTimeout(resolve, PEER_CONNECTION_RECOVERY_POLL_MS));
|
|
7784
|
+
}
|
|
7785
|
+
}
|
|
7786
|
+
/**
|
|
7734
7787
|
* @internal Stop and destroy resilience subsystems (on disconnect/destroy).
|
|
7735
7788
|
* Clears references so they can be re-created on reconnect.
|
|
7736
7789
|
*/
|
|
@@ -7867,8 +7920,13 @@ var WebRTCCall = class extends Destroyable {
|
|
|
7867
7920
|
const cached = this._customSubscriptions.get(eventType);
|
|
7868
7921
|
if (cached) return cached;
|
|
7869
7922
|
const filtered$ = this.callSessionEvents$.pipe((0, rxjs.filter)((event) => event.event_type === eventType), (0, rxjs.map)((event) => JSON.parse(JSON.stringify(event))), (0, rxjs.takeUntil)(this._destroyed$));
|
|
7923
|
+
this._sendVertoSubscribe(eventType).then(() => {
|
|
7924
|
+
this._customSubscriptions.set(eventType, filtered$);
|
|
7925
|
+
}, (error) => {
|
|
7926
|
+
this._customSubscriptions.delete(eventType);
|
|
7927
|
+
logger$11.warn(`[Call] verto.subscribe for '${eventType}' failed, not caching:`, error);
|
|
7928
|
+
});
|
|
7870
7929
|
this._customSubscriptions.set(eventType, filtered$);
|
|
7871
|
-
this._sendVertoSubscribe(eventType);
|
|
7872
7930
|
return filtered$;
|
|
7873
7931
|
}
|
|
7874
7932
|
get webrtcMessages$() {
|
|
@@ -7994,26 +8052,21 @@ var WebRTCCall = class extends Destroyable {
|
|
|
7994
8052
|
}
|
|
7995
8053
|
/**
|
|
7996
8054
|
* @internal Send a verto.subscribe message to add an event type to the
|
|
7997
|
-
* server's subscription list for this call.
|
|
7998
|
-
*
|
|
7999
|
-
|
|
8000
|
-
|
|
8001
|
-
|
|
8002
|
-
|
|
8003
|
-
|
|
8004
|
-
|
|
8005
|
-
|
|
8006
|
-
|
|
8007
|
-
|
|
8008
|
-
|
|
8009
|
-
|
|
8010
|
-
|
|
8011
|
-
|
|
8012
|
-
logger$11.warn(`[Call] verto.subscribe for '${eventType}' failed (non-fatal):`, error);
|
|
8013
|
-
});
|
|
8014
|
-
} catch (error) {
|
|
8015
|
-
logger$11.warn(`[Call] Failed to send verto.subscribe for '${eventType}':`, error);
|
|
8016
|
-
}
|
|
8055
|
+
* server's subscription list for this call. Returns the underlying RPC
|
|
8056
|
+
* promise so callers can decide whether to cache the observable on success
|
|
8057
|
+
* or retry on failure.
|
|
8058
|
+
*/
|
|
8059
|
+
async _sendVertoSubscribe(eventType) {
|
|
8060
|
+
const message = VertoSubscribe({
|
|
8061
|
+
sessid: this.id,
|
|
8062
|
+
eventChannel: [eventType]
|
|
8063
|
+
});
|
|
8064
|
+
const params = {
|
|
8065
|
+
callID: this.id,
|
|
8066
|
+
node_id: this.vertoManager.nodeId ?? "",
|
|
8067
|
+
message
|
|
8068
|
+
};
|
|
8069
|
+
await this.clientSession.execute(WebrtcVerto(params));
|
|
8017
8070
|
}
|
|
8018
8071
|
};
|
|
8019
8072
|
|
|
@@ -8030,11 +8083,21 @@ function inferCallErrorKind(error) {
|
|
|
8030
8083
|
if (error instanceof require_operators.WebSocketConnectionError || error instanceof require_operators.TransportConnectionError) return "network";
|
|
8031
8084
|
return "internal";
|
|
8032
8085
|
}
|
|
8086
|
+
/** JSON-RPC error codes that ClientSessionManager treats as recoverable at the
|
|
8087
|
+
* session level. Surfacing one of these against an in-flight call should not
|
|
8088
|
+
* destroy the call, because the session will reauthenticate and any pending
|
|
8089
|
+
* RPC can then be retried. */
|
|
8090
|
+
const RECOVERABLE_RPC_CODES = new Set([
|
|
8091
|
+
RPC_ERROR_REQUESTER_VALIDATION_FAILED,
|
|
8092
|
+
RPC_ERROR_AUTHENTICATION_FAILED,
|
|
8093
|
+
RPC_ERROR_INVALID_PARAMS
|
|
8094
|
+
]);
|
|
8033
8095
|
/** Determines whether an error should be fatal (destroy the call). */
|
|
8034
8096
|
function isFatalError(error) {
|
|
8035
8097
|
if (error instanceof require_operators.VertoPongError) return false;
|
|
8036
8098
|
if (error instanceof require_operators.MediaTrackError) return false;
|
|
8037
8099
|
if (error instanceof require_operators.RPCTimeoutError) return false;
|
|
8100
|
+
if (error instanceof require_operators.JSONRPCError && RECOVERABLE_RPC_CODES.has(error.code)) return false;
|
|
8038
8101
|
return true;
|
|
8039
8102
|
}
|
|
8040
8103
|
/**
|
|
@@ -8469,10 +8532,10 @@ var PendingRPC = class PendingRPC {
|
|
|
8469
8532
|
}
|
|
8470
8533
|
let isSettled = false;
|
|
8471
8534
|
const subscription = (0, rxjs.race)(responses$.pipe((0, rxjs.filter)((result) => result.id === request.id), (0, rxjs.take)(1)), new rxjs.Observable((subscriber) => {
|
|
8472
|
-
const timer$
|
|
8535
|
+
const timer$3 = setTimeout(() => {
|
|
8473
8536
|
subscriber.error(new require_operators.RPCTimeoutError(request.id, timeoutMs));
|
|
8474
8537
|
}, timeoutMs);
|
|
8475
|
-
return () => clearTimeout(timer$
|
|
8538
|
+
return () => clearTimeout(timer$3);
|
|
8476
8539
|
}), signal ? new rxjs.Observable((subscriber) => {
|
|
8477
8540
|
const abortHandler = () => {
|
|
8478
8541
|
subscriber.error(new DOMException("The operation was aborted", "AbortError"));
|
|
@@ -8537,7 +8600,7 @@ var ClientSessionManager = class extends Destroyable {
|
|
|
8537
8600
|
this.attachManager = attachManager;
|
|
8538
8601
|
this.dpopManager = dpopManager;
|
|
8539
8602
|
this.callCreateTimeout = 6e3;
|
|
8540
|
-
this.agent = `signalwire-
|
|
8603
|
+
this.agent = `signalwire-js/4.0.0`;
|
|
8541
8604
|
this.eventAcks = true;
|
|
8542
8605
|
this.authorizationState$ = this.createReplaySubject(1);
|
|
8543
8606
|
this.connectVersion = {
|
|
@@ -8871,7 +8934,6 @@ var ClientSessionManager = class extends Destroyable {
|
|
|
8871
8934
|
displayDirection: invite.display_direction,
|
|
8872
8935
|
userVariables: invite.userVariables
|
|
8873
8936
|
});
|
|
8874
|
-
await (0, rxjs.firstValueFrom)(callSession.status$);
|
|
8875
8937
|
this._calls$.next({
|
|
8876
8938
|
[`${callSession.id}`]: callSession,
|
|
8877
8939
|
...this._calls$.value
|
|
@@ -8892,7 +8954,7 @@ var ClientSessionManager = class extends Destroyable {
|
|
|
8892
8954
|
logger$8.debug(`[Session] Verto attach for existing call ${callID}, deferring to per-call handler`);
|
|
8893
8955
|
return;
|
|
8894
8956
|
}
|
|
8895
|
-
const storedOptions = this.attachManager.consumePendingAttachment(callID);
|
|
8957
|
+
const storedOptions = await this.attachManager.consumePendingAttachment(callID);
|
|
8896
8958
|
logger$8.debug(`[Session] Creating reattached call for callID: ${callID}`);
|
|
8897
8959
|
const callSession = await this.createCall({
|
|
8898
8960
|
nodeId: attach.node_id,
|
|
@@ -8904,7 +8966,6 @@ var ClientSessionManager = class extends Destroyable {
|
|
|
8904
8966
|
reattach: true,
|
|
8905
8967
|
...storedOptions
|
|
8906
8968
|
});
|
|
8907
|
-
await (0, rxjs.firstValueFrom)(callSession.status$);
|
|
8908
8969
|
this._calls$.next({
|
|
8909
8970
|
[`${callSession.id}`]: callSession,
|
|
8910
8971
|
...this._calls$.value
|
|
@@ -9623,10 +9684,9 @@ var WebSocketController = class WebSocketController extends Destroyable {
|
|
|
9623
9684
|
else this._status$.next("disconnected");
|
|
9624
9685
|
}
|
|
9625
9686
|
reconnect() {
|
|
9626
|
-
|
|
9627
|
-
|
|
9628
|
-
|
|
9629
|
-
} else this._status$.next("disconnected");
|
|
9687
|
+
this.shouldReconnect = true;
|
|
9688
|
+
this._status$.next("reconnecting");
|
|
9689
|
+
this.scheduleReconnection();
|
|
9630
9690
|
}
|
|
9631
9691
|
send(data) {
|
|
9632
9692
|
if (this._status$.value === "connected" && this.socket?.readyState === 1) {
|
|
@@ -10185,6 +10245,7 @@ var SignalWire = class extends Destroyable {
|
|
|
10185
10245
|
* `'reconnecting'`, `'disconnecting'`, or `'disconnected'`.
|
|
10186
10246
|
*/
|
|
10187
10247
|
async connect() {
|
|
10248
|
+
await this.teardownTransportAndSession();
|
|
10188
10249
|
try {
|
|
10189
10250
|
const subscriber = this._subscriber$.value;
|
|
10190
10251
|
if (!subscriber) throw new require_operators.UnexpectedError("Subscriber not initialized before connect");
|
|
@@ -10416,10 +10477,30 @@ var SignalWire = class extends Destroyable {
|
|
|
10416
10477
|
this._refreshTimerId = void 0;
|
|
10417
10478
|
}
|
|
10418
10479
|
this._diagnosticsCollector?.record("connection", "disconnected");
|
|
10419
|
-
await this.
|
|
10420
|
-
this._clientSession.destroy();
|
|
10480
|
+
await this.teardownTransportAndSession();
|
|
10421
10481
|
this._isConnected$.next(false);
|
|
10422
10482
|
}
|
|
10483
|
+
/**
|
|
10484
|
+
* Tear down the current transport / session / attach manager. Safe to call
|
|
10485
|
+
* when nothing has been initialized yet (e.g. first connect()).
|
|
10486
|
+
*/
|
|
10487
|
+
async teardownTransportAndSession() {
|
|
10488
|
+
const session = this._clientSession;
|
|
10489
|
+
const transport = this._transport;
|
|
10490
|
+
if (session) {
|
|
10491
|
+
try {
|
|
10492
|
+
await session.disconnect();
|
|
10493
|
+
} catch (error) {
|
|
10494
|
+
logger$1.warn("[SignalWire] Error disconnecting previous session:", error);
|
|
10495
|
+
}
|
|
10496
|
+
session.destroy();
|
|
10497
|
+
}
|
|
10498
|
+
if (transport) transport.destroy();
|
|
10499
|
+
this._clientSession = void 0;
|
|
10500
|
+
this._publicSession = void 0;
|
|
10501
|
+
this._transport = void 0;
|
|
10502
|
+
this._attachManager = void 0;
|
|
10503
|
+
}
|
|
10423
10504
|
async waitAuthentication() {
|
|
10424
10505
|
await (0, rxjs.firstValueFrom)(this.ready$.pipe((0, rxjs.filter)((ready$1) => ready$1 === true)));
|
|
10425
10506
|
}
|
|
@@ -10439,22 +10520,27 @@ var SignalWire = class extends Destroyable {
|
|
|
10439
10520
|
params: {}
|
|
10440
10521
|
}));
|
|
10441
10522
|
this._isRegistered$.next(true);
|
|
10523
|
+
return;
|
|
10442
10524
|
} catch (error) {
|
|
10525
|
+
if (!this._deps.credential.token) {
|
|
10526
|
+
this._errors$.next(error instanceof Error ? error : new Error(String(error), { cause: error }));
|
|
10527
|
+
throw error;
|
|
10528
|
+
}
|
|
10443
10529
|
logger$1.debug("[SignalWire] Failed to register subscriber, trying reauthentication...");
|
|
10444
|
-
|
|
10530
|
+
try {
|
|
10531
|
+
await this._clientSession.reauthenticate(this._deps.credential.token);
|
|
10445
10532
|
logger$1.debug("[SignalWire] Reauthentication successful, retrying register()");
|
|
10446
10533
|
await this._transport.execute(RPCExecute({
|
|
10447
10534
|
method: "subscriber.online",
|
|
10448
10535
|
params: {}
|
|
10449
10536
|
}));
|
|
10450
10537
|
this._isRegistered$.next(true);
|
|
10451
|
-
}
|
|
10538
|
+
} catch (reauthError) {
|
|
10452
10539
|
logger$1.error("[SignalWire] Reauthentication failed during register():", reauthError);
|
|
10453
10540
|
const registerError = new require_operators.InvalidCredentialsError("Failed to register subscriber, and reauthentication attempt also failed. Please check your credentials.", { cause: reauthError instanceof Error ? reauthError : new Error(String(reauthError), { cause: reauthError }) });
|
|
10454
10541
|
this._errors$.next(registerError);
|
|
10455
|
-
|
|
10456
|
-
|
|
10457
|
-
throw error;
|
|
10542
|
+
throw registerError;
|
|
10543
|
+
}
|
|
10458
10544
|
}
|
|
10459
10545
|
}
|
|
10460
10546
|
/**
|