@signalwire/js 4.0.0-dev-20260326210326 → 4.0.0-dev-20260401154549
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 +1057 -460
- package/dist/browser.mjs.map +1 -1
- package/dist/browser.umd.js +1059 -459
- package/dist/browser.umd.js.map +1 -1
- package/dist/index.cjs +851 -273
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +223 -10
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +223 -10
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +848 -273
- package/dist/index.mjs.map +1 -1
- package/dist/operators/index.cjs +1 -1
- package/dist/operators/index.mjs +1 -1
- package/dist/{operators-mm21prWr.cjs → operators-DuprVgnV.cjs} +40 -1
- package/dist/operators-DuprVgnV.cjs.map +1 -0
- package/dist/{operators-uT_fb8ba.mjs → operators-MaKNoyky.mjs} +23 -2
- package/dist/operators-MaKNoyky.mjs.map +1 -0
- package/package.json +1 -1
- package/dist/operators-mm21prWr.cjs.map +0 -1
- package/dist/operators-uT_fb8ba.mjs.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const require_operators = require('./operators-
|
|
1
|
+
const require_operators = require('./operators-DuprVgnV.cjs');
|
|
2
2
|
let jwt_decode = require("jwt-decode");
|
|
3
3
|
let rxjs = require("rxjs");
|
|
4
4
|
let uuid = require("uuid");
|
|
@@ -134,7 +134,7 @@ const asyncRetry = async ({ asyncCallable, maxRetries: retries = DEFAULT_MAX_RET
|
|
|
134
134
|
|
|
135
135
|
//#endregion
|
|
136
136
|
//#region src/controllers/HTTPRequestController.ts
|
|
137
|
-
const logger$
|
|
137
|
+
const logger$22 = require_operators.getLogger();
|
|
138
138
|
const GET_PARAMS = {
|
|
139
139
|
method: "GET",
|
|
140
140
|
headers: { Accept: "application/json" }
|
|
@@ -159,9 +159,16 @@ var HTTPRequestController = class HTTPRequestController {
|
|
|
159
159
|
static {
|
|
160
160
|
this.defaultRequestTimeoutMs = 3e4;
|
|
161
161
|
}
|
|
162
|
-
|
|
162
|
+
static {
|
|
163
|
+
this.SENSITIVE_BODY_FIELDS = new Set([
|
|
164
|
+
"dpop_token",
|
|
165
|
+
"token",
|
|
166
|
+
"jwt_token"
|
|
167
|
+
]);
|
|
168
|
+
}
|
|
169
|
+
constructor(baseURL, getCredential, options = {}) {
|
|
163
170
|
this.baseURL = baseURL;
|
|
164
|
-
this.
|
|
171
|
+
this.getCredential = getCredential;
|
|
165
172
|
this._responses$ = new rxjs.Subject();
|
|
166
173
|
this._errors$ = new rxjs.Subject();
|
|
167
174
|
this._status$ = new rxjs.BehaviorSubject("idle");
|
|
@@ -190,7 +197,7 @@ var HTTPRequestController = class HTTPRequestController {
|
|
|
190
197
|
this._responses$.next(response);
|
|
191
198
|
return response;
|
|
192
199
|
} catch (error) {
|
|
193
|
-
logger$
|
|
200
|
+
logger$22.error("[HTTPRequestController] Request error:", error);
|
|
194
201
|
this._status$.next("error");
|
|
195
202
|
const err = error instanceof Error ? error : new Error("HTTP request failed", { cause: error });
|
|
196
203
|
this._errors$.next(err);
|
|
@@ -217,14 +224,14 @@ var HTTPRequestController = class HTTPRequestController {
|
|
|
217
224
|
const url = this.buildURL(request.url);
|
|
218
225
|
const headers = this.buildHeaders(request.headers);
|
|
219
226
|
const timeout$3 = request.timeout ?? this.requestTimeout;
|
|
220
|
-
logger$
|
|
227
|
+
logger$22.debug("[HTTPRequestController] Executing request:", {
|
|
221
228
|
method: request.method,
|
|
222
229
|
url,
|
|
223
230
|
headers: Object.keys(headers).reduce((acc, key) => {
|
|
224
231
|
acc[key] = key === "Authorization" ? `${headers[key].substring(0, 20)}...` : headers[key];
|
|
225
232
|
return acc;
|
|
226
233
|
}, {}),
|
|
227
|
-
body: request.body
|
|
234
|
+
body: this.sanitizeBody(request.body)
|
|
228
235
|
});
|
|
229
236
|
const controller = new AbortController();
|
|
230
237
|
const timeoutId = setTimeout(() => controller.abort(), timeout$3);
|
|
@@ -237,7 +244,7 @@ var HTTPRequestController = class HTTPRequestController {
|
|
|
237
244
|
});
|
|
238
245
|
clearTimeout(timeoutId);
|
|
239
246
|
const httpResponse = await this.convertResponse(response);
|
|
240
|
-
logger$
|
|
247
|
+
logger$22.debug("[HTTPRequestController] Response received:", {
|
|
241
248
|
status: response.status,
|
|
242
249
|
statusText: response.statusText,
|
|
243
250
|
headers: [...response.headers.entries()],
|
|
@@ -247,7 +254,7 @@ var HTTPRequestController = class HTTPRequestController {
|
|
|
247
254
|
} catch (error) {
|
|
248
255
|
clearTimeout(timeoutId);
|
|
249
256
|
if (error instanceof Error && error.name === "AbortError") throw new require_operators.RequestTimeoutError(`Request timeout after ${timeout$3}ms`, { cause: error });
|
|
250
|
-
logger$
|
|
257
|
+
logger$22.error("[HTTPRequestController] Request failed:", error);
|
|
251
258
|
throw error;
|
|
252
259
|
}
|
|
253
260
|
}
|
|
@@ -258,12 +265,26 @@ var HTTPRequestController = class HTTPRequestController {
|
|
|
258
265
|
}
|
|
259
266
|
buildHeaders(requestHeaders) {
|
|
260
267
|
const headers = { ...requestHeaders ?? {} };
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
268
|
+
const credential = this.getCredential();
|
|
269
|
+
if (credential.token) {
|
|
270
|
+
headers.Authorization = `Bearer ${credential.token}`;
|
|
271
|
+
logger$22.debug("[HTTPRequestController] Using Bearer token auth, token length:", credential.token.length);
|
|
272
|
+
} else logger$22.warn("[HTTPRequestController] No credentials available for authentication");
|
|
265
273
|
return headers;
|
|
266
274
|
}
|
|
275
|
+
/**
|
|
276
|
+
* Sanitizes a request body for debug logging by masking sensitive fields.
|
|
277
|
+
*/
|
|
278
|
+
sanitizeBody(body) {
|
|
279
|
+
if (!body || typeof body !== "string") return body ? "(non-string body)" : void 0;
|
|
280
|
+
try {
|
|
281
|
+
const sanitized = { ...JSON.parse(body) };
|
|
282
|
+
for (const key of Object.keys(sanitized)) if (HTTPRequestController.SENSITIVE_BODY_FIELDS.has(key) && typeof sanitized[key] === "string") sanitized[key] = `${sanitized[key].substring(0, 20)}...[redacted]`;
|
|
283
|
+
return JSON.stringify(sanitized);
|
|
284
|
+
} catch {
|
|
285
|
+
return body.length > 200 ? `${body.substring(0, 200)}...` : body;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
267
288
|
async convertResponse(response) {
|
|
268
289
|
const headers = {};
|
|
269
290
|
response.headers.forEach((value, key) => {
|
|
@@ -293,6 +314,25 @@ const DEFAULT_RECONNECT_DELAY_MAX_MS = 3e3;
|
|
|
293
314
|
const DEFAULT_DEVICE_DEBOUNCE_TIME_MS = 1500;
|
|
294
315
|
const DEFAULT_DEVICE_POLLING_INTERVAL_MS = 0;
|
|
295
316
|
const PREFERENCES_STORAGE_KEY = "sw:preferences";
|
|
317
|
+
/** Scope value that enables automatic token refresh. */
|
|
318
|
+
const SAT_REFRESH_SCOPE = "sat:refresh";
|
|
319
|
+
/** API endpoints for device token operations. */
|
|
320
|
+
const DEVICE_TOKEN_ENDPOINT = "/api/fabric/subscriber/devices/token";
|
|
321
|
+
const DEVICE_REFRESH_ENDPOINT = "/api/fabric/subscriber/devices/refresh";
|
|
322
|
+
/** Default device token TTL in seconds (15 minutes). */
|
|
323
|
+
const DEVICE_TOKEN_DEFAULT_EXPIRE_IN = 900;
|
|
324
|
+
/** Buffer time in milliseconds before expiry to trigger refresh. */
|
|
325
|
+
const DEVICE_TOKEN_REFRESH_BUFFER_MS = 3e4;
|
|
326
|
+
/** Maximum retry attempts for device token refresh on transient failure. */
|
|
327
|
+
const DEVICE_TOKEN_REFRESH_MAX_RETRIES = 3;
|
|
328
|
+
/** Base delay in milliseconds for exponential backoff on refresh retry. */
|
|
329
|
+
const DEVICE_TOKEN_REFRESH_RETRY_BASE_MS = 1e3;
|
|
330
|
+
/** JSON-RPC error code for requester validation failure (corrupted auth state). */
|
|
331
|
+
const RPC_ERROR_REQUESTER_VALIDATION_FAILED = -32003;
|
|
332
|
+
/** JSON-RPC error code for invalid params (e.g., missing authentication block). */
|
|
333
|
+
const RPC_ERROR_INVALID_PARAMS = -32602;
|
|
334
|
+
/** JSON-RPC error code for authentication failure (invalid token, missing DPoP, etc.). */
|
|
335
|
+
const RPC_ERROR_AUTHENTICATION_FAILED = -32002;
|
|
296
336
|
|
|
297
337
|
//#endregion
|
|
298
338
|
//#region src/utils/time.ts
|
|
@@ -305,7 +345,7 @@ function fromMsToSec(milliseconds) {
|
|
|
305
345
|
|
|
306
346
|
//#endregion
|
|
307
347
|
//#region src/containers/PreferencesContainer.ts
|
|
308
|
-
const logger$
|
|
348
|
+
const logger$21 = require_operators.getLogger();
|
|
309
349
|
var PreferencesContainer = class PreferencesContainer {
|
|
310
350
|
static get instance() {
|
|
311
351
|
this._instance ??= new PreferencesContainer();
|
|
@@ -599,7 +639,7 @@ var ClientPreferences = class {
|
|
|
599
639
|
if (!this._storage) return;
|
|
600
640
|
const data = collectStoredPreferences();
|
|
601
641
|
this._storage.setItem(PREFERENCES_STORAGE_KEY, data, "local").catch((error) => {
|
|
602
|
-
logger$
|
|
642
|
+
logger$21.error(`[ClientPreferences] Failed to save preferences: ${String(error)}`);
|
|
603
643
|
});
|
|
604
644
|
}
|
|
605
645
|
/** Loads preferences from storage and applies them to the container. */
|
|
@@ -608,14 +648,14 @@ var ClientPreferences = class {
|
|
|
608
648
|
this._storage.getItem(PREFERENCES_STORAGE_KEY, "local").then((stored) => {
|
|
609
649
|
if (stored) applyStoredPreferences(stored);
|
|
610
650
|
}).catch((error) => {
|
|
611
|
-
logger$
|
|
651
|
+
logger$21.error(`[ClientPreferences] Failed to load preferences: ${String(error)}`);
|
|
612
652
|
});
|
|
613
653
|
}
|
|
614
654
|
};
|
|
615
655
|
|
|
616
656
|
//#endregion
|
|
617
657
|
//#region src/controllers/NavigatorDeviceController.ts
|
|
618
|
-
const logger$
|
|
658
|
+
const logger$20 = require_operators.getLogger();
|
|
619
659
|
const initialDevicesState = {
|
|
620
660
|
audioinput: [],
|
|
621
661
|
audiooutput: [],
|
|
@@ -636,7 +676,7 @@ var NavigatorDeviceController = class extends Destroyable {
|
|
|
636
676
|
super();
|
|
637
677
|
this.webRTCApiProvider = webRTCApiProvider;
|
|
638
678
|
this.deviceChangeHandler = () => {
|
|
639
|
-
logger$
|
|
679
|
+
logger$20.debug("[DeviceController] Device change detected");
|
|
640
680
|
this.enumerateDevices();
|
|
641
681
|
};
|
|
642
682
|
this._devicesState$ = this.createBehaviorSubject(initialDevicesState);
|
|
@@ -670,13 +710,13 @@ var NavigatorDeviceController = class extends Destroyable {
|
|
|
670
710
|
return this.cachedObservable("videoInputDevices$", () => this._devicesState$.pipe((0, rxjs.map)((state) => state.videoinput), (0, rxjs.distinctUntilChanged)(), (0, rxjs.takeUntil)(this.destroyed$)));
|
|
671
711
|
}
|
|
672
712
|
get selectedAudioInputDevice$() {
|
|
673
|
-
return this.cachedObservable("selectedAudioInputDevice$", () => this._selectedDevicesState$.asObservable().pipe((0, rxjs.map)((state) => state.audioinput), (0, rxjs.distinctUntilChanged)(), (0, rxjs.takeUntil)(this.destroyed$), (0, rxjs.tap)((info) => logger$
|
|
713
|
+
return this.cachedObservable("selectedAudioInputDevice$", () => this._selectedDevicesState$.asObservable().pipe((0, rxjs.map)((state) => state.audioinput), (0, rxjs.distinctUntilChanged)(), (0, rxjs.takeUntil)(this.destroyed$), (0, rxjs.tap)((info) => logger$20.debug("[DeviceController] Selected audio input device changed:", info))));
|
|
674
714
|
}
|
|
675
715
|
get selectedAudioOutputDevice$() {
|
|
676
|
-
return this.cachedObservable("selectedAudioOutputDevice$", () => this._selectedDevicesState$.asObservable().pipe((0, rxjs.map)((state) => state.audiooutput), (0, rxjs.distinctUntilChanged)(), (0, rxjs.takeUntil)(this.destroyed$), (0, rxjs.tap)((info) => logger$
|
|
716
|
+
return this.cachedObservable("selectedAudioOutputDevice$", () => this._selectedDevicesState$.asObservable().pipe((0, rxjs.map)((state) => state.audiooutput), (0, rxjs.distinctUntilChanged)(), (0, rxjs.takeUntil)(this.destroyed$), (0, rxjs.tap)((info) => logger$20.debug("[DeviceController] Selected audio output device changed:", info))));
|
|
677
717
|
}
|
|
678
718
|
get selectedVideoInputDevice$() {
|
|
679
|
-
return this.cachedObservable("selectedVideoInputDevice$", () => this._selectedDevicesState$.asObservable().pipe((0, rxjs.map)((state) => state.videoinput), (0, rxjs.distinctUntilChanged)(), (0, rxjs.takeUntil)(this.destroyed$), (0, rxjs.tap)((info) => logger$
|
|
719
|
+
return this.cachedObservable("selectedVideoInputDevice$", () => this._selectedDevicesState$.asObservable().pipe((0, rxjs.map)((state) => state.videoinput), (0, rxjs.distinctUntilChanged)(), (0, rxjs.takeUntil)(this.destroyed$), (0, rxjs.tap)((info) => logger$20.debug("[DeviceController] Selected video input device changed:", info))));
|
|
680
720
|
}
|
|
681
721
|
get selectedAudioInputDevice() {
|
|
682
722
|
return this._selectedDevicesState$.value.audioinput;
|
|
@@ -703,7 +743,7 @@ var NavigatorDeviceController = class extends Destroyable {
|
|
|
703
743
|
});
|
|
704
744
|
}
|
|
705
745
|
selectVideoInputDevice(device) {
|
|
706
|
-
logger$
|
|
746
|
+
logger$20.debug("[DeviceController] Setting selected video input device:", device);
|
|
707
747
|
this._selectedDevicesState$.next({
|
|
708
748
|
...this._selectedDevicesState$.value,
|
|
709
749
|
videoinput: device
|
|
@@ -733,7 +773,7 @@ var NavigatorDeviceController = class extends Destroyable {
|
|
|
733
773
|
this.disableDeviceMonitoring();
|
|
734
774
|
this.webRTCApiProvider.mediaDevices.addEventListener("devicechange", this.deviceChangeHandler);
|
|
735
775
|
if (PreferencesContainer.instance.devicePollingInterval > 0) this._devicesPoolingSubscription = (0, rxjs.interval)(PreferencesContainer.instance.devicePollingInterval).subscribe(() => {
|
|
736
|
-
logger$
|
|
776
|
+
logger$20.debug("[DeviceController] Polling devices due to interval");
|
|
737
777
|
this.enumerateDevices();
|
|
738
778
|
});
|
|
739
779
|
this.enumerateDevices();
|
|
@@ -756,13 +796,13 @@ var NavigatorDeviceController = class extends Destroyable {
|
|
|
756
796
|
videoinput: []
|
|
757
797
|
});
|
|
758
798
|
this._devicesState$.next(devicesByKind);
|
|
759
|
-
logger$
|
|
799
|
+
logger$20.debug("[DeviceController] Devices enumerated:", {
|
|
760
800
|
audioInputs: devicesByKind.audioinput.length,
|
|
761
801
|
audioOutputs: devicesByKind.audiooutput.length,
|
|
762
802
|
videoInputs: devicesByKind.videoinput.length
|
|
763
803
|
});
|
|
764
804
|
} catch (error) {
|
|
765
|
-
logger$
|
|
805
|
+
logger$20.error("[DeviceController] Failed to enumerate devices:", error);
|
|
766
806
|
this._errors$.next(error);
|
|
767
807
|
}
|
|
768
808
|
}
|
|
@@ -778,7 +818,7 @@ var NavigatorDeviceController = class extends Destroyable {
|
|
|
778
818
|
stream.getTracks().forEach((t) => t.stop());
|
|
779
819
|
return capabilities;
|
|
780
820
|
} catch (error) {
|
|
781
|
-
logger$
|
|
821
|
+
logger$20.error("[DeviceController] Failed to get device capabilities:", error);
|
|
782
822
|
this._errors$.next(error);
|
|
783
823
|
throw error;
|
|
784
824
|
}
|
|
@@ -925,7 +965,7 @@ var DependencyContainer = class {
|
|
|
925
965
|
return this._storageManager;
|
|
926
966
|
}
|
|
927
967
|
get http() {
|
|
928
|
-
this._httpRequestController ??= new HTTPRequestController(this._baseURL, this._credential);
|
|
968
|
+
this._httpRequestController ??= new HTTPRequestController(this._baseURL, () => this._credential);
|
|
929
969
|
return this._httpRequestController;
|
|
930
970
|
}
|
|
931
971
|
get conversationManager() {
|
|
@@ -981,7 +1021,6 @@ var DependencyContainer = class {
|
|
|
981
1021
|
}
|
|
982
1022
|
set credential(credential) {
|
|
983
1023
|
this._credential = credential;
|
|
984
|
-
this._httpRequestController = void 0;
|
|
985
1024
|
}
|
|
986
1025
|
set storageImpl(storageImpl) {
|
|
987
1026
|
this._storageImpl = storageImpl;
|
|
@@ -994,12 +1033,194 @@ var DependencyContainer = class {
|
|
|
994
1033
|
this._host = ch.substring(0, firstDot);
|
|
995
1034
|
this._domain = ch.substring(firstDot + 1);
|
|
996
1035
|
}
|
|
1036
|
+
this._baseURL = this.apiHost;
|
|
1037
|
+
this._httpRequestController = void 0;
|
|
997
1038
|
}
|
|
998
1039
|
get relayHost() {
|
|
999
1040
|
return `wss://${this._host ?? "puc"}.${this._domain ?? "signalwire.com"}`;
|
|
1000
1041
|
}
|
|
1001
1042
|
get apiHost() {
|
|
1002
|
-
return `https
|
|
1043
|
+
return `https://fabric.${this._domain ?? "signalwire.com"}`;
|
|
1044
|
+
}
|
|
1045
|
+
};
|
|
1046
|
+
|
|
1047
|
+
//#endregion
|
|
1048
|
+
//#region src/controllers/CryptoController.ts
|
|
1049
|
+
const logger$19 = require_operators.getLogger();
|
|
1050
|
+
/**
|
|
1051
|
+
* Base64url-encodes an ArrayBuffer (no padding, URL-safe).
|
|
1052
|
+
*/
|
|
1053
|
+
const base64url = (buffer) => {
|
|
1054
|
+
const bytes = new Uint8Array(buffer);
|
|
1055
|
+
let binary = "";
|
|
1056
|
+
for (const byte of bytes) binary += String.fromCharCode(byte);
|
|
1057
|
+
return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
1058
|
+
};
|
|
1059
|
+
/**
|
|
1060
|
+
* Base64url-encodes a UTF-8 string.
|
|
1061
|
+
*/
|
|
1062
|
+
const base64urlEncode = (str) => {
|
|
1063
|
+
return base64url(new TextEncoder().encode(str).buffer);
|
|
1064
|
+
};
|
|
1065
|
+
/**
|
|
1066
|
+
* Computes the JWK Thumbprint per RFC 7638.
|
|
1067
|
+
*
|
|
1068
|
+
* Only supports RSA keys — the canonical JSON uses lexicographic member ordering: { e, kty, n }.
|
|
1069
|
+
* The thumbprint is SHA-256 of the canonical JSON, base64url-encoded.
|
|
1070
|
+
*
|
|
1071
|
+
* @throws {Error} If the JWK is not an RSA key.
|
|
1072
|
+
*/
|
|
1073
|
+
const computeJwkThumbprint = async (jwk) => {
|
|
1074
|
+
if (jwk.kty !== "RSA") throw new Error(`Unsupported key type for JWK Thumbprint: ${jwk.kty}. Only RSA is supported.`);
|
|
1075
|
+
const canonical = JSON.stringify({
|
|
1076
|
+
e: jwk.e,
|
|
1077
|
+
kty: jwk.kty,
|
|
1078
|
+
n: jwk.n
|
|
1079
|
+
});
|
|
1080
|
+
return base64url(await crypto.subtle.digest("SHA-256", new TextEncoder().encode(canonical)));
|
|
1081
|
+
};
|
|
1082
|
+
/**
|
|
1083
|
+
* Controls DPoP (Demonstrating Proof-of-Possession) cryptographic operations.
|
|
1084
|
+
*
|
|
1085
|
+
* Generates an ephemeral RSA-2048 key pair where the private key is
|
|
1086
|
+
* non-extractable, computes the JWK Thumbprint (RFC 7638) as the fingerprint,
|
|
1087
|
+
* and creates signed DPoP proof JWTs for both HTTP API requests and
|
|
1088
|
+
* WebSocket RPC calls.
|
|
1089
|
+
*
|
|
1090
|
+
* @example
|
|
1091
|
+
* ```typescript
|
|
1092
|
+
* const crypto = new CryptoController();
|
|
1093
|
+
* await crypto.init();
|
|
1094
|
+
*
|
|
1095
|
+
* // Get fingerprint for SAT issuance
|
|
1096
|
+
* const fingerprint = crypto.fingerprint;
|
|
1097
|
+
*
|
|
1098
|
+
* // Create proof for HTTP endpoint
|
|
1099
|
+
* const httpProof = await crypto.createHttpProof({
|
|
1100
|
+
* method: 'POST',
|
|
1101
|
+
* uri: '/api/fabric/subscriber/devices/token'
|
|
1102
|
+
* });
|
|
1103
|
+
*
|
|
1104
|
+
* // Create proof for RPC call
|
|
1105
|
+
* const rpcProof = await crypto.createRpcProof({
|
|
1106
|
+
* method: 'signalwire.connect'
|
|
1107
|
+
* });
|
|
1108
|
+
* ```
|
|
1109
|
+
*/
|
|
1110
|
+
var CryptoController = class {
|
|
1111
|
+
constructor() {
|
|
1112
|
+
this._keyPair = null;
|
|
1113
|
+
this._publicJwk = null;
|
|
1114
|
+
this._fingerprint = null;
|
|
1115
|
+
this._initialized = false;
|
|
1116
|
+
}
|
|
1117
|
+
/**
|
|
1118
|
+
* Generates the ephemeral RSA key pair and computes the fingerprint.
|
|
1119
|
+
*
|
|
1120
|
+
* Must be called before any other method. The private key is generated
|
|
1121
|
+
* as non-extractable to prevent accidental exposure.
|
|
1122
|
+
*
|
|
1123
|
+
* @returns The JWK Thumbprint (fingerprint) for the generated key.
|
|
1124
|
+
*/
|
|
1125
|
+
async init() {
|
|
1126
|
+
if (this._initialized) return this.fingerprint;
|
|
1127
|
+
logger$19.debug("[DPoP] Generating ephemeral RSA key pair");
|
|
1128
|
+
this._keyPair = await crypto.subtle.generateKey({
|
|
1129
|
+
name: "RSASSA-PKCS1-v1_5",
|
|
1130
|
+
modulusLength: 2048,
|
|
1131
|
+
publicExponent: new Uint8Array([
|
|
1132
|
+
1,
|
|
1133
|
+
0,
|
|
1134
|
+
1
|
|
1135
|
+
]),
|
|
1136
|
+
hash: "SHA-256"
|
|
1137
|
+
}, false, ["sign", "verify"]);
|
|
1138
|
+
this._publicJwk = await crypto.subtle.exportKey("jwk", this._keyPair.publicKey);
|
|
1139
|
+
this._fingerprint = await computeJwkThumbprint(this._publicJwk);
|
|
1140
|
+
this._initialized = true;
|
|
1141
|
+
logger$19.debug("[DPoP] Key pair generated, fingerprint computed");
|
|
1142
|
+
return this._fingerprint;
|
|
1143
|
+
}
|
|
1144
|
+
/**
|
|
1145
|
+
* The JWK Thumbprint (RFC 7638) of the public key.
|
|
1146
|
+
* Used as the `fingerprint` parameter when requesting scoped SATs.
|
|
1147
|
+
*
|
|
1148
|
+
* @throws {DPoPInitError} If {@link init} has not been called.
|
|
1149
|
+
*/
|
|
1150
|
+
get fingerprint() {
|
|
1151
|
+
if (!this._fingerprint) throw new require_operators.DPoPInitError("CryptoController not initialized. Call init() first.");
|
|
1152
|
+
return this._fingerprint;
|
|
1153
|
+
}
|
|
1154
|
+
/**
|
|
1155
|
+
* Whether the controller has been initialized with a key pair.
|
|
1156
|
+
*/
|
|
1157
|
+
get initialized() {
|
|
1158
|
+
return this._initialized;
|
|
1159
|
+
}
|
|
1160
|
+
/**
|
|
1161
|
+
* Creates a DPoP proof JWT for an HTTP API request.
|
|
1162
|
+
*
|
|
1163
|
+
* Used for Prime API endpoints like `/api/fabric/subscriber/devices/token`
|
|
1164
|
+
* and `/api/fabric/subscriber/devices/refresh`.
|
|
1165
|
+
*
|
|
1166
|
+
* @param params - HTTP method and URI for the proof.
|
|
1167
|
+
* @returns Signed DPoP proof JWT string.
|
|
1168
|
+
*/
|
|
1169
|
+
async createHttpProof(params) {
|
|
1170
|
+
const payload = {
|
|
1171
|
+
jti: crypto.randomUUID(),
|
|
1172
|
+
htm: params.method,
|
|
1173
|
+
htu: params.uri,
|
|
1174
|
+
iat: Math.floor(Date.now() / 1e3)
|
|
1175
|
+
};
|
|
1176
|
+
if (params.accessToken) payload.ath = base64url(await crypto.subtle.digest("SHA-256", new TextEncoder().encode(params.accessToken)));
|
|
1177
|
+
return this.signProof(payload);
|
|
1178
|
+
}
|
|
1179
|
+
/**
|
|
1180
|
+
* Creates a DPoP proof JWT for a WebSocket RPC call.
|
|
1181
|
+
*
|
|
1182
|
+
* Used for switchblade RPC methods like `signalwire.connect` and
|
|
1183
|
+
* `signalwire.reauthenticate`.
|
|
1184
|
+
*
|
|
1185
|
+
* @param params - RPC method name for the proof.
|
|
1186
|
+
* @returns Signed DPoP proof JWT string.
|
|
1187
|
+
*/
|
|
1188
|
+
async createRpcProof(params) {
|
|
1189
|
+
const payload = {
|
|
1190
|
+
jti: crypto.randomUUID(),
|
|
1191
|
+
rpc: "request",
|
|
1192
|
+
mth: params.method,
|
|
1193
|
+
iat: Math.floor(Date.now() / 1e3)
|
|
1194
|
+
};
|
|
1195
|
+
return this.signProof(payload);
|
|
1196
|
+
}
|
|
1197
|
+
/**
|
|
1198
|
+
* Releases the key pair references.
|
|
1199
|
+
* After calling destroy, the controller must be re-initialized to be used again.
|
|
1200
|
+
*/
|
|
1201
|
+
destroy() {
|
|
1202
|
+
this._keyPair = null;
|
|
1203
|
+
this._publicJwk = null;
|
|
1204
|
+
this._fingerprint = null;
|
|
1205
|
+
this._initialized = false;
|
|
1206
|
+
logger$19.debug("[DPoP] Controller destroyed");
|
|
1207
|
+
}
|
|
1208
|
+
get publicJwk() {
|
|
1209
|
+
if (!this._publicJwk) throw new require_operators.DPoPInitError("CryptoController not initialized. Call init() first.");
|
|
1210
|
+
return this._publicJwk;
|
|
1211
|
+
}
|
|
1212
|
+
get privateKey() {
|
|
1213
|
+
if (!this._keyPair) throw new require_operators.DPoPInitError("CryptoController not initialized. Call init() first.");
|
|
1214
|
+
return this._keyPair.privateKey;
|
|
1215
|
+
}
|
|
1216
|
+
async signProof(payload) {
|
|
1217
|
+
const header = {
|
|
1218
|
+
typ: "dpop+jwt",
|
|
1219
|
+
alg: "RS256",
|
|
1220
|
+
jwk: this.publicJwk
|
|
1221
|
+
};
|
|
1222
|
+
const signingInput = `${base64urlEncode(JSON.stringify(header))}.${base64urlEncode(JSON.stringify(payload))}`;
|
|
1223
|
+
return `${signingInput}.${base64url(await crypto.subtle.sign("RSASSA-PKCS1-v1_5", this.privateKey, new TextEncoder().encode(signingInput)))}`;
|
|
1003
1224
|
}
|
|
1004
1225
|
};
|
|
1005
1226
|
|
|
@@ -1056,6 +1277,7 @@ var Subscriber = class extends Fetchable {
|
|
|
1056
1277
|
scopes: data.app_settings.scopes
|
|
1057
1278
|
} : void 0;
|
|
1058
1279
|
this.addresses = data.fabric_addresses;
|
|
1280
|
+
this.satClaims = data.sat_claims;
|
|
1059
1281
|
}
|
|
1060
1282
|
};
|
|
1061
1283
|
|
|
@@ -1095,10 +1317,14 @@ const RPCConnect = (params) => {
|
|
|
1095
1317
|
|
|
1096
1318
|
//#endregion
|
|
1097
1319
|
//#region src/core/RPCMessages/RPCReauthenticate.ts
|
|
1098
|
-
const RPCReauthenticate = (
|
|
1320
|
+
const RPCReauthenticate = (params) => {
|
|
1321
|
+
const { dpop_token, ...authFields } = params;
|
|
1099
1322
|
return buildRPCRequest({
|
|
1100
1323
|
method: "signalwire.reauthenticate",
|
|
1101
|
-
params: {
|
|
1324
|
+
params: {
|
|
1325
|
+
authentication: authFields,
|
|
1326
|
+
...dpop_token ? { dpop_token } : {}
|
|
1327
|
+
}
|
|
1102
1328
|
});
|
|
1103
1329
|
};
|
|
1104
1330
|
|
|
@@ -1194,7 +1420,7 @@ const RPCEventAckResponse = (id) => makeRPCResponse({
|
|
|
1194
1420
|
|
|
1195
1421
|
//#endregion
|
|
1196
1422
|
//#region src/managers/AttachManager.ts
|
|
1197
|
-
const logger$
|
|
1423
|
+
const logger$18 = require_operators.getLogger();
|
|
1198
1424
|
var AttachManager = class {
|
|
1199
1425
|
constructor(storage, deviceController, reconnectCallsTimeout, attachKey) {
|
|
1200
1426
|
this.storage = storage;
|
|
@@ -1216,7 +1442,7 @@ var AttachManager = class {
|
|
|
1216
1442
|
try {
|
|
1217
1443
|
return await this.storage.getItem(this.attachKey) ?? {};
|
|
1218
1444
|
} catch (error) {
|
|
1219
|
-
logger$
|
|
1445
|
+
logger$18.warn("[AttachManager] Failed to retrieve attached calls from storage", error);
|
|
1220
1446
|
return {};
|
|
1221
1447
|
}
|
|
1222
1448
|
}
|
|
@@ -1224,12 +1450,12 @@ var AttachManager = class {
|
|
|
1224
1450
|
try {
|
|
1225
1451
|
await this.storage.setItem(this.attachKey, attached);
|
|
1226
1452
|
} catch (error) {
|
|
1227
|
-
logger$
|
|
1453
|
+
logger$18.warn("[AttachManager] Failed to write attached calls to storage", error);
|
|
1228
1454
|
}
|
|
1229
1455
|
}
|
|
1230
1456
|
async attach(call) {
|
|
1231
1457
|
if (!call.to) {
|
|
1232
|
-
logger$
|
|
1458
|
+
logger$18.warn("[AttachManager] Skip attach for calls with no destination");
|
|
1233
1459
|
return;
|
|
1234
1460
|
}
|
|
1235
1461
|
const attachment = {
|
|
@@ -1549,7 +1775,7 @@ function toggleHandraiseMethod(is) {
|
|
|
1549
1775
|
|
|
1550
1776
|
//#endregion
|
|
1551
1777
|
//#region src/core/entities/Participant.ts
|
|
1552
|
-
const logger$
|
|
1778
|
+
const logger$17 = require_operators.getLogger();
|
|
1553
1779
|
const initialState = {};
|
|
1554
1780
|
/**
|
|
1555
1781
|
* Represents a participant in a call.
|
|
@@ -1892,7 +2118,7 @@ var SelfParticipant = class extends Participant {
|
|
|
1892
2118
|
try {
|
|
1893
2119
|
await this.vertoManager.addScreenMedia();
|
|
1894
2120
|
} catch (error) {
|
|
1895
|
-
logger$
|
|
2121
|
+
logger$17.error("[Participant.startScreenShare] Screen share error:", error);
|
|
1896
2122
|
}
|
|
1897
2123
|
}
|
|
1898
2124
|
/** Observable of the current screen share status. */
|
|
@@ -1912,7 +2138,7 @@ var SelfParticipant = class extends Participant {
|
|
|
1912
2138
|
try {
|
|
1913
2139
|
await this.vertoManager.addInputDevice(options);
|
|
1914
2140
|
} catch (error) {
|
|
1915
|
-
logger$
|
|
2141
|
+
logger$17.error("[Participant.startScreenShare] Screen share error:", error);
|
|
1916
2142
|
}
|
|
1917
2143
|
}
|
|
1918
2144
|
/** Removes an additional media input device by ID. */
|
|
@@ -1973,7 +2199,7 @@ var SelfParticipant = class extends Participant {
|
|
|
1973
2199
|
try {
|
|
1974
2200
|
await super.mute();
|
|
1975
2201
|
} catch (error) {
|
|
1976
|
-
logger$
|
|
2202
|
+
logger$17.warn("[Participant.toggleAudioInput] Server Error while muting audio input, proceeding with local toggle anyway", error);
|
|
1977
2203
|
} finally {
|
|
1978
2204
|
this.vertoManager.muteMainAudioInputDevice();
|
|
1979
2205
|
}
|
|
@@ -1983,7 +2209,7 @@ var SelfParticipant = class extends Participant {
|
|
|
1983
2209
|
try {
|
|
1984
2210
|
await super.unmute();
|
|
1985
2211
|
} catch (error) {
|
|
1986
|
-
logger$
|
|
2212
|
+
logger$17.warn("[Participant.toggleAudioInput] Server Error while unmuting audio input, proceeding with local toggle anyway", error);
|
|
1987
2213
|
} finally {
|
|
1988
2214
|
await this.vertoManager.unmuteMainAudioInputDevice();
|
|
1989
2215
|
}
|
|
@@ -1993,7 +2219,7 @@ var SelfParticipant = class extends Participant {
|
|
|
1993
2219
|
try {
|
|
1994
2220
|
await super.muteVideo();
|
|
1995
2221
|
} catch (error) {
|
|
1996
|
-
logger$
|
|
2222
|
+
logger$17.warn("[Participant.toggleVideoInput] Server Error while muting video input, proceeding with local toggle anyway", error);
|
|
1997
2223
|
} finally {
|
|
1998
2224
|
this.vertoManager.muteMainVideoInputDevice();
|
|
1999
2225
|
}
|
|
@@ -2003,7 +2229,7 @@ var SelfParticipant = class extends Participant {
|
|
|
2003
2229
|
try {
|
|
2004
2230
|
await super.unmuteVideo();
|
|
2005
2231
|
} catch (error) {
|
|
2006
|
-
logger$
|
|
2232
|
+
logger$17.warn("[Participant.toggleVideoInput] Server Error while unmuting video input, proceeding with local toggle anyway", error);
|
|
2007
2233
|
} finally {
|
|
2008
2234
|
await this.vertoManager.unmuteMainVideoInputDevice();
|
|
2009
2235
|
}
|
|
@@ -2034,6 +2260,7 @@ function isJSONRPCErrorResponse(value) {
|
|
|
2034
2260
|
|
|
2035
2261
|
//#endregion
|
|
2036
2262
|
//#region src/core/RPCMessages/guards/events.guards.ts
|
|
2263
|
+
/** @internal @packageDocumentation */
|
|
2037
2264
|
/**
|
|
2038
2265
|
* Factory function to create Request-level type guards.
|
|
2039
2266
|
*/
|
|
@@ -2057,6 +2284,7 @@ const isCallUpdatedRequest = createEventRequestGuard("call.updated");
|
|
|
2057
2284
|
const isCallStateRequest = createEventRequestGuard("call.state");
|
|
2058
2285
|
const isCallPlayRequest = createEventRequestGuard("call.play");
|
|
2059
2286
|
const isCallConnectRequest = createEventRequestGuard("call.connect");
|
|
2287
|
+
const isRoomUpdatedRequest = createEventRequestGuard("room.updated");
|
|
2060
2288
|
const isMemberUpdatedRequest = createEventRequestGuard("member.updated");
|
|
2061
2289
|
const isMemberJoinedRequest = createEventRequestGuard("member.joined");
|
|
2062
2290
|
const isMemberLeftRequest = createEventRequestGuard("member.left");
|
|
@@ -2068,7 +2296,7 @@ function isSignalwireMetadata(value) {
|
|
|
2068
2296
|
return isObject(value) && hasProperty(value, "event_type") && typeof value.event_type === "string" && hasProperty(value, "params");
|
|
2069
2297
|
}
|
|
2070
2298
|
function isSignalwireCallMetadata(value) {
|
|
2071
|
-
return isSignalwireMetadata(value) && (isCallJoinedMetadata(value) || isCallLeftMetadata(value) || isCallUpdatedMetadata(value) || isCallStateMetadata(value) || isCallPlayMetadata(value) || isCallConnectMetadata(value) || isMemberUpdatedMetadata(value) || isMemberJoinedMetadata(value) || isMemberLeftMetadata(value) || isMemberTalkingMetadata(value) || isLayoutChangedMetadata(value) || isWebrtcMessageMetadata(value) || isConversationMessageMetadata(value) || isConversationMessageUpdatedMetadata(value));
|
|
2299
|
+
return isSignalwireMetadata(value) && (isCallJoinedMetadata(value) || isCallLeftMetadata(value) || isCallUpdatedMetadata(value) || isCallStateMetadata(value) || isCallPlayMetadata(value) || isCallConnectMetadata(value) || isRoomUpdatedMetadata(value) || isMemberUpdatedMetadata(value) || isMemberJoinedMetadata(value) || isMemberLeftMetadata(value) || isMemberTalkingMetadata(value) || isLayoutChangedMetadata(value) || isWebrtcMessageMetadata(value) || isConversationMessageMetadata(value) || isConversationMessageUpdatedMetadata(value));
|
|
2072
2300
|
}
|
|
2073
2301
|
const isSignalwireAuthorizationStateMetadata = createEventMetadataGuard("signalwire.authorization.state");
|
|
2074
2302
|
const isWebrtcMessageMetadata = createEventMetadataGuard("webrtc.message");
|
|
@@ -2078,6 +2306,7 @@ const isCallUpdatedMetadata = createEventMetadataGuard("call.updated");
|
|
|
2078
2306
|
const isCallStateMetadata = createEventMetadataGuard("call.state");
|
|
2079
2307
|
const isCallPlayMetadata = createEventMetadataGuard("call.play");
|
|
2080
2308
|
const isCallConnectMetadata = createEventMetadataGuard("call.connect");
|
|
2309
|
+
const isRoomUpdatedMetadata = createEventMetadataGuard("room.updated");
|
|
2081
2310
|
const isMemberUpdatedMetadata = createEventMetadataGuard("member.updated");
|
|
2082
2311
|
const isMemberJoinedMetadata = createEventMetadataGuard("member.joined");
|
|
2083
2312
|
const isMemberLeftMetadata = createEventMetadataGuard("member.left");
|
|
@@ -2094,8 +2323,9 @@ function isLayoutChangedPayload(value) {
|
|
|
2094
2323
|
|
|
2095
2324
|
//#endregion
|
|
2096
2325
|
//#region src/managers/CallEventsManager.ts
|
|
2097
|
-
const logger$
|
|
2326
|
+
const logger$16 = require_operators.getLogger();
|
|
2098
2327
|
const initialSessionState = {};
|
|
2328
|
+
/** @internal */
|
|
2099
2329
|
var CallEventsManager = class extends Destroyable {
|
|
2100
2330
|
constructor(webRtcCallSession, options = {}) {
|
|
2101
2331
|
super();
|
|
@@ -2197,7 +2427,7 @@ var CallEventsManager = class extends Destroyable {
|
|
|
2197
2427
|
}
|
|
2198
2428
|
initSubscriptions() {
|
|
2199
2429
|
this.subscribeTo(this.callJoinedEvent$, (callJoinedEvent) => {
|
|
2200
|
-
logger$
|
|
2430
|
+
logger$16.debug("[CallEventsManager] Handling call.joined event for call/session IDs:", {
|
|
2201
2431
|
callId: callJoinedEvent.call_id,
|
|
2202
2432
|
roomSessionId: callJoinedEvent.room_session_id
|
|
2203
2433
|
});
|
|
@@ -2224,19 +2454,34 @@ var CallEventsManager = class extends Destroyable {
|
|
|
2224
2454
|
if (this._self$.value?.capabilities.setLayout) this.updateLayouts();
|
|
2225
2455
|
});
|
|
2226
2456
|
this.subscribeTo(this.memberUpdates$, (member) => {
|
|
2227
|
-
logger$
|
|
2457
|
+
logger$16.debug("[CallEventsManager] Handling member update event for member ID:", member);
|
|
2228
2458
|
this.upsertParticipant(member);
|
|
2229
2459
|
});
|
|
2230
2460
|
this.subscribeTo(this.webRtcCallSession.memberLeft$, (memberLeftEvent) => {
|
|
2231
|
-
logger$
|
|
2461
|
+
logger$16.debug("[CallEventsManager] Handling member.left event for member ID:", memberLeftEvent.member.member_id);
|
|
2232
2462
|
const participants = { ...this._participants$.value };
|
|
2233
2463
|
if (memberLeftEvent.member.member_id in participants) {
|
|
2234
2464
|
delete participants[memberLeftEvent.member.member_id];
|
|
2235
2465
|
this._participants$.next(participants);
|
|
2236
|
-
} else logger$
|
|
2466
|
+
} else logger$16.warn(`[CallEventsManager] Received member.left event for unknown member ID: ${memberLeftEvent.member.member_id}`);
|
|
2467
|
+
});
|
|
2468
|
+
this.subscribeTo(this.webRtcCallSession.callUpdated$, (callUpdatedEvent) => {
|
|
2469
|
+
logger$16.debug("[CallEventsManager] Handling call.updated event:", callUpdatedEvent);
|
|
2470
|
+
const roomSession = callUpdatedEvent.room_session;
|
|
2471
|
+
this._sessionState$.next({
|
|
2472
|
+
...this._sessionState$.value,
|
|
2473
|
+
recording: roomSession.recording,
|
|
2474
|
+
recordings: roomSession.recordings,
|
|
2475
|
+
streaming: roomSession.streaming,
|
|
2476
|
+
streams: roomSession.streams,
|
|
2477
|
+
playbacks: roomSession.playbacks,
|
|
2478
|
+
prioritize_handraise: roomSession.prioritize_handraise,
|
|
2479
|
+
locked: roomSession.locked,
|
|
2480
|
+
meta: roomSession.meta
|
|
2481
|
+
});
|
|
2237
2482
|
});
|
|
2238
2483
|
this.subscribeTo(this.layoutChangedEvent$, (layoutChangedEvent) => {
|
|
2239
|
-
logger$
|
|
2484
|
+
logger$16.debug("[CallEventsManager] Handling layout.changed event:", layoutChangedEvent);
|
|
2240
2485
|
this._sessionState$.next({
|
|
2241
2486
|
...this._sessionState$.value,
|
|
2242
2487
|
layout_name: layoutChangedEvent.id,
|
|
@@ -2246,7 +2491,7 @@ var CallEventsManager = class extends Destroyable {
|
|
|
2246
2491
|
});
|
|
2247
2492
|
}
|
|
2248
2493
|
updateParticipantPositions(layoutChangedEvent) {
|
|
2249
|
-
if (Object.keys(this._participants$.value).length > 0 && !layoutChangedEvent.layers.some((layer) => !!layer.member_id)) logger$
|
|
2494
|
+
if (Object.keys(this._participants$.value).length > 0 && !layoutChangedEvent.layers.some((layer) => !!layer.member_id)) logger$16.warn("[CallEventsManager] No layers with member_id found in layout.changed event. Nothing to update.");
|
|
2250
2495
|
layoutChangedEvent.layers.filter((layer) => Boolean(layer.member_id)).map((layer) => {
|
|
2251
2496
|
if (!layer.member_id) throw new require_operators.DependencyError("Layer member_id is required");
|
|
2252
2497
|
this._participants$.value[layer.member_id].upnext({ position: layer });
|
|
@@ -2267,7 +2512,7 @@ var CallEventsManager = class extends Destroyable {
|
|
|
2267
2512
|
layouts: response.result.layouts
|
|
2268
2513
|
});
|
|
2269
2514
|
}).catch((error) => {
|
|
2270
|
-
logger$
|
|
2515
|
+
logger$16.error("[CallEventsManager] Error fetching layouts:", error);
|
|
2271
2516
|
});
|
|
2272
2517
|
}
|
|
2273
2518
|
updateParticipants(members) {
|
|
@@ -2283,7 +2528,7 @@ var CallEventsManager = class extends Destroyable {
|
|
|
2283
2528
|
}
|
|
2284
2529
|
const participant = this._participants$.value[member.member_id];
|
|
2285
2530
|
const oldValue = participant.value;
|
|
2286
|
-
logger$
|
|
2531
|
+
logger$16.debug("[CallEventsManager] Updating participant:", member.member_id, {
|
|
2287
2532
|
oldValue,
|
|
2288
2533
|
newValue: member
|
|
2289
2534
|
});
|
|
@@ -2296,17 +2541,17 @@ var CallEventsManager = class extends Destroyable {
|
|
|
2296
2541
|
}
|
|
2297
2542
|
get callJoinedEvent$() {
|
|
2298
2543
|
return this.cachedObservable("callJoinedEvent$", () => this.webRtcCallSession.callEvent$.pipe((0, rxjs.filter)(isCallJoinedPayload), (0, rxjs.tap)((event) => {
|
|
2299
|
-
logger$
|
|
2544
|
+
logger$16.debug("[CallEventsManager] Call joined event:", event);
|
|
2300
2545
|
})));
|
|
2301
2546
|
}
|
|
2302
2547
|
get layoutChangedEvent$() {
|
|
2303
2548
|
return this.cachedObservable("layoutChangedEvent$", () => this.webRtcCallSession.callEvent$.pipe(require_operators.filterAs(isLayoutChangedPayload, "layout"), (0, rxjs.tap)((event) => {
|
|
2304
|
-
logger$
|
|
2549
|
+
logger$16.debug("[CallEventsManager] Layout changed event:", event);
|
|
2305
2550
|
})));
|
|
2306
2551
|
}
|
|
2307
2552
|
get memberUpdates$() {
|
|
2308
2553
|
return this.cachedObservable("memberUpdates$", () => (0, rxjs.merge)(this.webRtcCallSession.memberJoined$, this.webRtcCallSession.memberUpdated$, this.webRtcCallSession.memberTalking$).pipe((0, rxjs.map)((event) => event.member), (0, rxjs.tap)((event) => {
|
|
2309
|
-
logger$
|
|
2554
|
+
logger$16.debug("[CallEventsManager] Member update event:", event);
|
|
2310
2555
|
})));
|
|
2311
2556
|
}
|
|
2312
2557
|
destroy() {
|
|
@@ -2414,7 +2659,7 @@ function isValidLocalDescription(sdp) {
|
|
|
2414
2659
|
|
|
2415
2660
|
//#endregion
|
|
2416
2661
|
//#region src/controllers/ICEGatheringController.ts
|
|
2417
|
-
const logger$
|
|
2662
|
+
const logger$15 = require_operators.getLogger();
|
|
2418
2663
|
var ICEGatheringController = class extends Destroyable {
|
|
2419
2664
|
constructor(peerConnection, peerConnectionControllerNegotiating$, options = {}) {
|
|
2420
2665
|
super();
|
|
@@ -2422,23 +2667,23 @@ var ICEGatheringController = class extends Destroyable {
|
|
|
2422
2667
|
this.peerConnectionControllerNegotiating$ = peerConnectionControllerNegotiating$;
|
|
2423
2668
|
this.onicegatheringstatechangeHandler = () => {
|
|
2424
2669
|
const { iceGatheringState } = this.peerConnection;
|
|
2425
|
-
logger$
|
|
2670
|
+
logger$15.debug(`[ICEGatheringController] ICE gathering state changed to: ${iceGatheringState}`);
|
|
2426
2671
|
if (iceGatheringState === "gathering") this._iceCandidatesState.next({
|
|
2427
2672
|
state: "gathering",
|
|
2428
2673
|
validSDP: false
|
|
2429
2674
|
});
|
|
2430
2675
|
};
|
|
2431
2676
|
this.onicecandidateHandler = (event) => {
|
|
2432
|
-
logger$
|
|
2677
|
+
logger$15.debug("[ICEGatheringController] ICE candidate event received:", event.candidate);
|
|
2433
2678
|
this.removeTimer("iceCandidateTimer");
|
|
2434
2679
|
if (event.candidate) this.iceCandidateTimer = setTimeout(() => {
|
|
2435
2680
|
if (this.peerConnection.iceGatheringState !== "complete") {
|
|
2436
|
-
logger$
|
|
2681
|
+
logger$15.warn("[ICEGatheringController] ICE candidate timeout, using current SDP");
|
|
2437
2682
|
this.handleICECandidateTimeout();
|
|
2438
2683
|
}
|
|
2439
2684
|
}, this.iceCandidateTimeout);
|
|
2440
2685
|
else {
|
|
2441
|
-
logger$
|
|
2686
|
+
logger$15.debug("[ICEGatheringController] ICE gathering completed: null candidate received");
|
|
2442
2687
|
this.removeTimer("iceGatheringTimer");
|
|
2443
2688
|
this.handleICEGatheringComplete();
|
|
2444
2689
|
}
|
|
@@ -2456,7 +2701,7 @@ var ICEGatheringController = class extends Destroyable {
|
|
|
2456
2701
|
this.setupEventListeners();
|
|
2457
2702
|
this.iceGatheringTimer = setTimeout(() => {
|
|
2458
2703
|
if (this.peerConnection.iceGatheringState !== "complete") {
|
|
2459
|
-
logger$
|
|
2704
|
+
logger$15.warn("[ICEGatheringController] ICE gathering timeout, using current SDP");
|
|
2460
2705
|
this.handleICEGatheringTimeout();
|
|
2461
2706
|
}
|
|
2462
2707
|
}, this.iceGatheringTimeout);
|
|
@@ -2483,9 +2728,9 @@ var ICEGatheringController = class extends Destroyable {
|
|
|
2483
2728
|
this.relayOnly = value;
|
|
2484
2729
|
}
|
|
2485
2730
|
handleICEGatheringComplete() {
|
|
2486
|
-
logger$
|
|
2487
|
-
logger$
|
|
2488
|
-
logger$
|
|
2731
|
+
logger$15.debug("[ICEGatheringController] Handling ICE gathering complete");
|
|
2732
|
+
logger$15.debug(`[ICEGatheringController] Checking ICE gathering state: ${this.peerConnection.iceGatheringState}`);
|
|
2733
|
+
logger$15.debug("[ICEGatheringController] ICE gathering complete");
|
|
2489
2734
|
this._iceCandidatesState.next({
|
|
2490
2735
|
state: "complete",
|
|
2491
2736
|
validSDP: this.hasValidLocalDescriptionSDP
|
|
@@ -2501,21 +2746,21 @@ var ICEGatheringController = class extends Destroyable {
|
|
|
2501
2746
|
this.removeTimer("iceGatheringTimer");
|
|
2502
2747
|
const validSDP = this.hasValidLocalDescriptionSDP;
|
|
2503
2748
|
if (validSDP) {
|
|
2504
|
-
logger$
|
|
2749
|
+
logger$15.debug("[ICEGatheringController] Local SDP is valid");
|
|
2505
2750
|
this._iceCandidatesState.next({
|
|
2506
2751
|
state: "timeout",
|
|
2507
2752
|
validSDP
|
|
2508
2753
|
});
|
|
2509
2754
|
this.stopGathering();
|
|
2510
|
-
} else logger$
|
|
2755
|
+
} else logger$15.debug("### ICE gathering timeout\n", this.peerConnection.localDescription?.sdp);
|
|
2511
2756
|
}
|
|
2512
2757
|
handleICECandidateTimeout() {
|
|
2513
2758
|
if (this.iceCandidateTimer) this.removeTimer("iceCandidateTimer");
|
|
2514
|
-
logger$
|
|
2759
|
+
logger$15.warn("[ICEGatheringController] ICE candidate timeout");
|
|
2515
2760
|
const validSDP = this.hasValidLocalDescriptionSDP;
|
|
2516
2761
|
if (!validSDP && !this.relayOnly) this.restartICEGatheringWithRelayOnly();
|
|
2517
2762
|
else {
|
|
2518
|
-
logger$
|
|
2763
|
+
logger$15.debug("[ICEGatheringController] Using current SDP due to ICE candidate timeout");
|
|
2519
2764
|
this._iceCandidatesState.next({
|
|
2520
2765
|
state: "timeout",
|
|
2521
2766
|
validSDP
|
|
@@ -2524,7 +2769,7 @@ var ICEGatheringController = class extends Destroyable {
|
|
|
2524
2769
|
}
|
|
2525
2770
|
}
|
|
2526
2771
|
restartICEGatheringWithRelayOnly() {
|
|
2527
|
-
logger$
|
|
2772
|
+
logger$15.debug("[ICEGatheringController] Restarting ICE gathering with relay-only candidates");
|
|
2528
2773
|
this.relayOnly = true;
|
|
2529
2774
|
this.peerConnection.setConfiguration({
|
|
2530
2775
|
...this.peerConnection.getConfiguration(),
|
|
@@ -2532,14 +2777,14 @@ var ICEGatheringController = class extends Destroyable {
|
|
|
2532
2777
|
});
|
|
2533
2778
|
if (!(this.peerConnection.connectionState === "connected")) this.peerConnection.restartIce();
|
|
2534
2779
|
}
|
|
2535
|
-
removeTimer(timer) {
|
|
2536
|
-
if (this[timer]) {
|
|
2537
|
-
clearTimeout(this[timer]);
|
|
2538
|
-
this[timer] = void 0;
|
|
2780
|
+
removeTimer(timer$1) {
|
|
2781
|
+
if (this[timer$1]) {
|
|
2782
|
+
clearTimeout(this[timer$1]);
|
|
2783
|
+
this[timer$1] = void 0;
|
|
2539
2784
|
}
|
|
2540
2785
|
}
|
|
2541
2786
|
clearAllTimers() {
|
|
2542
|
-
logger$
|
|
2787
|
+
logger$15.debug("[ICEGatheringController] Clearing all timers");
|
|
2543
2788
|
this.removeTimer("iceGatheringTimer");
|
|
2544
2789
|
this.removeTimer("iceCandidateTimer");
|
|
2545
2790
|
}
|
|
@@ -2548,7 +2793,7 @@ var ICEGatheringController = class extends Destroyable {
|
|
|
2548
2793
|
this.peerConnection.removeEventListener("icecandidate", this.onicecandidateHandler);
|
|
2549
2794
|
}
|
|
2550
2795
|
destroy() {
|
|
2551
|
-
logger$
|
|
2796
|
+
logger$15.debug("[ICEGatheringController] Destroying ICEGatheringController");
|
|
2552
2797
|
this.clearAllTimers();
|
|
2553
2798
|
this.removeEventListeners();
|
|
2554
2799
|
super.destroy();
|
|
@@ -2557,7 +2802,7 @@ var ICEGatheringController = class extends Destroyable {
|
|
|
2557
2802
|
|
|
2558
2803
|
//#endregion
|
|
2559
2804
|
//#region src/controllers/LocalStreamController.ts
|
|
2560
|
-
const logger$
|
|
2805
|
+
const logger$14 = require_operators.getLogger();
|
|
2561
2806
|
var LocalStreamController = class extends Destroyable {
|
|
2562
2807
|
constructor(options) {
|
|
2563
2808
|
super();
|
|
@@ -2595,26 +2840,26 @@ var LocalStreamController = class extends Destroyable {
|
|
|
2595
2840
|
* Build the local media stream based on the provided options.
|
|
2596
2841
|
*/
|
|
2597
2842
|
async buildLocalStream() {
|
|
2598
|
-
logger$
|
|
2843
|
+
logger$14.debug("[LocalStreamController] Building local media stream.");
|
|
2599
2844
|
let stream;
|
|
2600
2845
|
if (this.options.inputAudioStream ?? this.options.inputVideoStream) {
|
|
2601
2846
|
const tracks = [...this.options.inputAudioStream?.getTracks() ?? [], ...this.options.inputVideoStream?.getTracks() ?? []];
|
|
2602
2847
|
stream = new MediaStream(tracks);
|
|
2603
2848
|
} else if (this.options.propose === "screenshare") {
|
|
2604
|
-
logger$
|
|
2849
|
+
logger$14.debug("[LocalStreamController] Requesting display media for screen sharing with audio:", Boolean(this.options.inputAudioDeviceConstraints));
|
|
2605
2850
|
stream = await this.options.getDisplayMedia({
|
|
2606
2851
|
video: true,
|
|
2607
2852
|
audio: Boolean(this.options.inputAudioDeviceConstraints)
|
|
2608
2853
|
});
|
|
2609
|
-
logger$
|
|
2854
|
+
logger$14.debug("[LocalStreamController] Screen share media obtained:", stream);
|
|
2610
2855
|
} else {
|
|
2611
2856
|
const constraints = {
|
|
2612
2857
|
audio: this.options.inputAudioDeviceConstraints,
|
|
2613
2858
|
video: this.options.inputVideoDeviceConstraints
|
|
2614
2859
|
};
|
|
2615
|
-
logger$
|
|
2860
|
+
logger$14.debug("[LocalStreamController] Requesting user media with constraints:", constraints);
|
|
2616
2861
|
stream = await this.options.getUserMedia(constraints);
|
|
2617
|
-
logger$
|
|
2862
|
+
logger$14.debug("[LocalStreamController] User media obtained:", stream);
|
|
2618
2863
|
}
|
|
2619
2864
|
this._localStream$.next(stream);
|
|
2620
2865
|
return stream;
|
|
@@ -2631,7 +2876,7 @@ var LocalStreamController = class extends Destroyable {
|
|
|
2631
2876
|
this._localStream$.next(localStream);
|
|
2632
2877
|
if (track.kind === "video") this._localVideoTracks$.next(localStream.getVideoTracks());
|
|
2633
2878
|
else this._localAudioTracks$.next(localStream.getAudioTracks());
|
|
2634
|
-
logger$
|
|
2879
|
+
logger$14.debug(`[LocalStreamController] ${track.kind} track added:`, track.id);
|
|
2635
2880
|
return localStream;
|
|
2636
2881
|
}
|
|
2637
2882
|
/**
|
|
@@ -2643,7 +2888,7 @@ var LocalStreamController = class extends Destroyable {
|
|
|
2643
2888
|
const stream = this._localStream$.value;
|
|
2644
2889
|
const track = stream?.getTracks().find((t) => t.id === trackId);
|
|
2645
2890
|
if (!track) {
|
|
2646
|
-
logger$
|
|
2891
|
+
logger$14.debug(`[LocalStreamController] track not found: ${trackId}`);
|
|
2647
2892
|
return;
|
|
2648
2893
|
}
|
|
2649
2894
|
track.removeEventListener("ended", this.mediaTrackEndedHandler);
|
|
@@ -2652,7 +2897,7 @@ var LocalStreamController = class extends Destroyable {
|
|
|
2652
2897
|
this._localStream$.next(stream);
|
|
2653
2898
|
if (track.kind === "video") this._localVideoTracks$.next(stream?.getVideoTracks() ?? []);
|
|
2654
2899
|
else this._localAudioTracks$.next(stream?.getAudioTracks() ?? []);
|
|
2655
|
-
logger$
|
|
2900
|
+
logger$14.debug(`[LocalStreamController] ${track.kind} track removed:`, trackId);
|
|
2656
2901
|
return track;
|
|
2657
2902
|
}
|
|
2658
2903
|
/**
|
|
@@ -2687,7 +2932,7 @@ var LocalStreamController = class extends Destroyable {
|
|
|
2687
2932
|
*/
|
|
2688
2933
|
stopAllTracks() {
|
|
2689
2934
|
this._localStream$.value?.getTracks().forEach((track) => {
|
|
2690
|
-
logger$
|
|
2935
|
+
logger$14.debug(`[LocalStreamController] Stopping local track: ${track.kind}`);
|
|
2691
2936
|
track.removeEventListener("ended", this.mediaTrackEndedHandler);
|
|
2692
2937
|
track.stop();
|
|
2693
2938
|
});
|
|
@@ -2703,7 +2948,7 @@ var LocalStreamController = class extends Destroyable {
|
|
|
2703
2948
|
|
|
2704
2949
|
//#endregion
|
|
2705
2950
|
//#region src/controllers/TransceiverController.ts
|
|
2706
|
-
const logger$
|
|
2951
|
+
const logger$13 = require_operators.getLogger();
|
|
2707
2952
|
const getDirection = (send, recv) => {
|
|
2708
2953
|
if (send && recv) return "sendrecv";
|
|
2709
2954
|
else if (send && !recv) return "sendonly";
|
|
@@ -2805,7 +3050,7 @@ var TransceiverController = class extends Destroyable {
|
|
|
2805
3050
|
sendEncodings: isAudio ? void 0 : this.sendEncodings,
|
|
2806
3051
|
streams: direction === "recvonly" ? void 0 : [localStream]
|
|
2807
3052
|
};
|
|
2808
|
-
logger$
|
|
3053
|
+
logger$13.debug(`[TransceiverController] Setting up transceiver sender for local ${track.kind} track:`, {
|
|
2809
3054
|
transceiver,
|
|
2810
3055
|
transceiverParams
|
|
2811
3056
|
});
|
|
@@ -2813,11 +3058,11 @@ var TransceiverController = class extends Destroyable {
|
|
|
2813
3058
|
await transceiver.sender.replaceTrack(track);
|
|
2814
3059
|
transceiver.direction = transceiverParams.direction;
|
|
2815
3060
|
if (transceiverParams.streams?.some((stream) => Boolean(stream))) {
|
|
2816
|
-
logger$
|
|
3061
|
+
logger$13.debug(`[TransceiverController] Setting streams for transceiver sender for local ${track.kind} track:`, transceiverParams.streams);
|
|
2817
3062
|
transceiver.sender.setStreams(...transceiverParams.streams);
|
|
2818
3063
|
}
|
|
2819
3064
|
} else {
|
|
2820
|
-
logger$
|
|
3065
|
+
logger$13.debug(`[TransceiverController] Adding new transceiver for local ${track.kind} track:`, track.id);
|
|
2821
3066
|
this.peerConnection.addTransceiver(track, transceiverParams);
|
|
2822
3067
|
}
|
|
2823
3068
|
}
|
|
@@ -2831,13 +3076,13 @@ var TransceiverController = class extends Destroyable {
|
|
|
2831
3076
|
if (options.updateTransceiverDirection) transceiver.direction = "inactive";
|
|
2832
3077
|
}
|
|
2833
3078
|
} catch (error) {
|
|
2834
|
-
logger$
|
|
3079
|
+
logger$13.error("[TransceiverController] stopTrackSender error", kind, error);
|
|
2835
3080
|
this.options.onError?.(new require_operators.MediaTrackError("stopTrackSender", kind, error));
|
|
2836
3081
|
}
|
|
2837
3082
|
}
|
|
2838
3083
|
async restoreTrackSender(kind) {
|
|
2839
3084
|
try {
|
|
2840
|
-
logger$
|
|
3085
|
+
logger$13.debug("[TransceiverController] restoreTrackSender called", kind);
|
|
2841
3086
|
const constraints = {};
|
|
2842
3087
|
const transceivers = this.transceiverByKind(kind);
|
|
2843
3088
|
for (const transceiver of transceivers) {
|
|
@@ -2847,23 +3092,23 @@ var TransceiverController = class extends Destroyable {
|
|
|
2847
3092
|
if (trackKind === "audio" || trackKind === "video") constraints[trackKind] = this.getConstraintsFor(trackKind);
|
|
2848
3093
|
}
|
|
2849
3094
|
}
|
|
2850
|
-
logger$
|
|
3095
|
+
logger$13.debug("[TransceiverController] restoreTrackSender constraints:", constraints);
|
|
2851
3096
|
if (Object.keys(constraints).length === 0) {
|
|
2852
|
-
logger$
|
|
3097
|
+
logger$13.warn("[TransceiverController] restoreTrackSender: no tracks need restoration", kind);
|
|
2853
3098
|
return;
|
|
2854
3099
|
}
|
|
2855
3100
|
const newTracks = (await this.options.getUserMedia(constraints)).getTracks();
|
|
2856
|
-
logger$
|
|
3101
|
+
logger$13.debug("[TransceiverController] restoreTrackSender new tracks:", newTracks);
|
|
2857
3102
|
for (const newTrack of newTracks) {
|
|
2858
3103
|
this.options.localStreamController.addTrack(newTrack);
|
|
2859
3104
|
const trackKind = newTrack.kind;
|
|
2860
3105
|
const transceiverOfKind = this.transceiverByKind(trackKind)[0];
|
|
2861
3106
|
transceiverOfKind.direction = trackKind === "audio" ? this.audioDirection : this.videoDirection;
|
|
2862
|
-
logger$
|
|
3107
|
+
logger$13.debug("[TransceiverController] restoreTrackSender setting direction for", trackKind, transceiverOfKind.direction);
|
|
2863
3108
|
await transceiverOfKind.sender.replaceTrack(newTrack);
|
|
2864
3109
|
}
|
|
2865
3110
|
} catch (error) {
|
|
2866
|
-
logger$
|
|
3111
|
+
logger$13.error("[TransceiverController] restoreTrackSender error", kind, error);
|
|
2867
3112
|
this.options.onError?.(new require_operators.MediaTrackError("restoreTrackSender", kind, error));
|
|
2868
3113
|
}
|
|
2869
3114
|
}
|
|
@@ -2904,10 +3149,10 @@ var TransceiverController = class extends Destroyable {
|
|
|
2904
3149
|
};
|
|
2905
3150
|
try {
|
|
2906
3151
|
await track.applyConstraints(constraintsToApply);
|
|
2907
|
-
logger$
|
|
2908
|
-
logger$
|
|
3152
|
+
logger$13.debug(`[TransceiverController] Updated ${kind} sender constraints:`, constraintsToApply);
|
|
3153
|
+
logger$13.debug(`[TransceiverController] Updated ${kind} sender constraints:`, track.getConstraints());
|
|
2909
3154
|
} catch (error) {
|
|
2910
|
-
logger$
|
|
3155
|
+
logger$13.warn(`[TransceiverController] Failed to apply constraints to ${kind} track ${track.id}:`, error);
|
|
2911
3156
|
this.options.onError?.(new require_operators.MediaTrackError("updateSendersConstraints", kind, error));
|
|
2912
3157
|
}
|
|
2913
3158
|
}
|
|
@@ -2941,7 +3186,7 @@ var TransceiverController = class extends Destroyable {
|
|
|
2941
3186
|
|
|
2942
3187
|
//#endregion
|
|
2943
3188
|
//#region src/controllers/RTCPeerConnectionController.ts
|
|
2944
|
-
const logger$
|
|
3189
|
+
const logger$12 = require_operators.getLogger();
|
|
2945
3190
|
var RTCPeerConnectionController = class extends Destroyable {
|
|
2946
3191
|
constructor(options = {}, remoteSessionDescription, deviceController) {
|
|
2947
3192
|
super();
|
|
@@ -2957,43 +3202,43 @@ var RTCPeerConnectionController = class extends Destroyable {
|
|
|
2957
3202
|
this.oniceconnectionstatechangeHandler = () => {
|
|
2958
3203
|
if (this.peerConnection) {
|
|
2959
3204
|
const { iceConnectionState } = this.peerConnection;
|
|
2960
|
-
logger$
|
|
3205
|
+
logger$12.debug(`[RTCPeerConnectionController] ICE connection state changed to: ${iceConnectionState}`);
|
|
2961
3206
|
this._iceConnectionState$.next(this.peerConnection.iceConnectionState);
|
|
2962
3207
|
}
|
|
2963
3208
|
};
|
|
2964
3209
|
this.onconnectionstatechangeHandler = () => {
|
|
2965
3210
|
if (this.peerConnection) {
|
|
2966
3211
|
const { connectionState } = this.peerConnection;
|
|
2967
|
-
logger$
|
|
3212
|
+
logger$12.debug(`[RTCPeerConnectionController] Connection state changed to: ${connectionState}`);
|
|
2968
3213
|
if (connectionState === "connected") this.removeConnectionTimer();
|
|
2969
3214
|
this._connectionState$.next(this.peerConnection.connectionState);
|
|
2970
3215
|
}
|
|
2971
3216
|
};
|
|
2972
3217
|
this.onsignalingstatechangeHandler = () => {
|
|
2973
|
-
logger$
|
|
3218
|
+
logger$12.debug(`[RTCPeerConnectionController] Signaling state changed to: ${this.peerConnection?.signalingState}`);
|
|
2974
3219
|
};
|
|
2975
3220
|
this.onicegatheringstatechangeHandler = () => {
|
|
2976
3221
|
if (this.peerConnection) this._iceGatheringState$.next(this.peerConnection.iceGatheringState);
|
|
2977
3222
|
};
|
|
2978
3223
|
this.onnegotiationneededHandler = (event) => {
|
|
2979
|
-
logger$
|
|
3224
|
+
logger$12.debug("[RTCPeerConnectionController] Negotiation needed event received.", event);
|
|
2980
3225
|
this.negotiationNeeded$.next();
|
|
2981
3226
|
};
|
|
2982
3227
|
this.updateSelectedInputDevice = async (kind, deviceInfo) => {
|
|
2983
3228
|
try {
|
|
2984
3229
|
const { localStream } = this;
|
|
2985
3230
|
if (!localStream) {
|
|
2986
|
-
logger$
|
|
3231
|
+
logger$12.warn("[RTCPeerConnectionController] No local stream available to update input device.");
|
|
2987
3232
|
return;
|
|
2988
3233
|
}
|
|
2989
|
-
logger$
|
|
3234
|
+
logger$12.debug(`[RTCPeerConnectionController] Updating selected ${kind} input device:`, localStream.getTracks());
|
|
2990
3235
|
const track = localStream.getTracks().find((track$1) => track$1.kind === kind);
|
|
2991
3236
|
if (track) {
|
|
2992
3237
|
this.transceiverController?.stopTrackSender(kind);
|
|
2993
3238
|
this.localStream?.removeTrack(track);
|
|
2994
|
-
logger$
|
|
3239
|
+
logger$12.debug(`[RTCPeerConnectionController] Stopped existing ${kind} track: ${track.id}`, localStream.getTracks());
|
|
2995
3240
|
if (!deviceInfo) {
|
|
2996
|
-
logger$
|
|
3241
|
+
logger$12.debug(`[RTCPeerConnectionController] ${kind} input device selected: none`);
|
|
2997
3242
|
return;
|
|
2998
3243
|
}
|
|
2999
3244
|
const streamTrack = (await this.getUserMedia({ [kind]: {
|
|
@@ -3001,15 +3246,15 @@ var RTCPeerConnectionController = class extends Destroyable {
|
|
|
3001
3246
|
...this.deviceController.deviceInfoToConstraints(deviceInfo)
|
|
3002
3247
|
} })).getTracks().find((t) => t.kind === kind);
|
|
3003
3248
|
if (streamTrack) {
|
|
3004
|
-
logger$
|
|
3249
|
+
logger$12.debug(`[RTCPeerConnectionController] Adding new ${kind} track: ${streamTrack.id}`);
|
|
3005
3250
|
this.localStream?.addTrack(streamTrack);
|
|
3006
3251
|
await this.transceiverController?.replaceSenderTrack(kind, streamTrack);
|
|
3007
|
-
logger$
|
|
3252
|
+
logger$12.debug(`[RTCPeerConnectionController] Added new ${kind} track: ${streamTrack.id}`, this.localStream?.getTracks());
|
|
3008
3253
|
}
|
|
3009
3254
|
}
|
|
3010
|
-
logger$
|
|
3255
|
+
logger$12.debug(`[RTCPeerConnectionController] ${kind} input device selected:`, deviceInfo?.label);
|
|
3011
3256
|
} catch (error) {
|
|
3012
|
-
logger$
|
|
3257
|
+
logger$12.error(`[RTCPeerConnectionController] Failed to select ${kind} input device:`, error);
|
|
3013
3258
|
this._errors$.next(error);
|
|
3014
3259
|
throw error;
|
|
3015
3260
|
}
|
|
@@ -3238,15 +3483,15 @@ var RTCPeerConnectionController = class extends Destroyable {
|
|
|
3238
3483
|
this.setupPeerConnection();
|
|
3239
3484
|
this.subscribeTo(this.negotiationNeeded$.pipe((0, rxjs.auditTime)(0), (0, rxjs.exhaustMap)(async () => this.startNegotiation())), {
|
|
3240
3485
|
next: () => {
|
|
3241
|
-
logger$
|
|
3486
|
+
logger$12.debug("[RTCPeerConnectionController] Start Negotiation completed successfully");
|
|
3242
3487
|
},
|
|
3243
3488
|
error: (error) => {
|
|
3244
|
-
logger$
|
|
3489
|
+
logger$12.error("[RTCPeerConnectionController] Start Negotiation error:", error);
|
|
3245
3490
|
this._errors$.next(error);
|
|
3246
3491
|
}
|
|
3247
3492
|
});
|
|
3248
3493
|
this.subscribeTo((0, rxjs.merge)(this.deviceController.selectedAudioInputDevice$.pipe((0, rxjs.map)((deviceInfo) => ["audio", deviceInfo])), this.deviceController.selectedVideoInputDevice$.pipe((0, rxjs.map)((deviceInfo) => ["video", deviceInfo]))).pipe((0, rxjs.skipWhile)(() => !this.localStreamController.localStream)), async ([kind, deviceInfo]) => {
|
|
3249
|
-
logger$
|
|
3494
|
+
logger$12.debug(`[RTCPeerConnectionController] Selected input device changed for:`, {
|
|
3250
3495
|
kind,
|
|
3251
3496
|
deviceInfo
|
|
3252
3497
|
});
|
|
@@ -3263,7 +3508,7 @@ var RTCPeerConnectionController = class extends Destroyable {
|
|
|
3263
3508
|
this._initialized$.next(true);
|
|
3264
3509
|
}
|
|
3265
3510
|
} catch (error) {
|
|
3266
|
-
logger$
|
|
3511
|
+
logger$12.error("[RTCPeerConnectionController] Initialization error:", error);
|
|
3267
3512
|
this._errors$.next(error);
|
|
3268
3513
|
this.destroy();
|
|
3269
3514
|
}
|
|
@@ -3295,22 +3540,22 @@ var RTCPeerConnectionController = class extends Destroyable {
|
|
|
3295
3540
|
}
|
|
3296
3541
|
async startNegotiation() {
|
|
3297
3542
|
if (this.isNegotiating) {
|
|
3298
|
-
logger$
|
|
3543
|
+
logger$12.debug("[RTCPeerConnectionController] Negotiation already in progress, skipping.");
|
|
3299
3544
|
return;
|
|
3300
3545
|
}
|
|
3301
3546
|
this.setupEventListeners();
|
|
3302
3547
|
if (this.type === "answer") {
|
|
3303
|
-
logger$
|
|
3548
|
+
logger$12.debug("[RTCPeerConnectionController] This is an answer type still, skipping offer creation.");
|
|
3304
3549
|
return;
|
|
3305
3550
|
}
|
|
3306
3551
|
this._isNegotiating$.next(true);
|
|
3307
|
-
logger$
|
|
3552
|
+
logger$12.debug("[RTCPeerConnectionController] Starting negotiation.");
|
|
3308
3553
|
try {
|
|
3309
3554
|
const { offerOptions } = this;
|
|
3310
|
-
logger$
|
|
3555
|
+
logger$12.debug("[RTCPeerConnectionController] Creating offer with options:", offerOptions);
|
|
3311
3556
|
await this.createOffer(offerOptions);
|
|
3312
3557
|
} catch (error) {
|
|
3313
|
-
logger$
|
|
3558
|
+
logger$12.error("[RTCPeerConnectionController] Error during negotiation:", error);
|
|
3314
3559
|
this._errors$.next(error);
|
|
3315
3560
|
}
|
|
3316
3561
|
}
|
|
@@ -3326,14 +3571,14 @@ var RTCPeerConnectionController = class extends Destroyable {
|
|
|
3326
3571
|
let readyToConnect = status !== "failed";
|
|
3327
3572
|
try {
|
|
3328
3573
|
if (status === "received" && sdp) {
|
|
3329
|
-
logger$
|
|
3574
|
+
logger$12.debug("[RTCPeerConnectionController] Received answer SDP:", sdp);
|
|
3330
3575
|
await this._setRemoteDescription({
|
|
3331
3576
|
type: "answer",
|
|
3332
3577
|
sdp
|
|
3333
3578
|
});
|
|
3334
3579
|
}
|
|
3335
3580
|
} catch (error) {
|
|
3336
|
-
logger$
|
|
3581
|
+
logger$12.error("[RTCPeerConnectionController] Error updating answer status:", error);
|
|
3337
3582
|
this._errors$.next(error);
|
|
3338
3583
|
readyToConnect = false;
|
|
3339
3584
|
} finally {
|
|
@@ -3352,7 +3597,7 @@ var RTCPeerConnectionController = class extends Destroyable {
|
|
|
3352
3597
|
await this.handleOfferReceived();
|
|
3353
3598
|
break;
|
|
3354
3599
|
case "failed":
|
|
3355
|
-
logger$
|
|
3600
|
+
logger$12.error("[RTCPeerConnectionController] Offer failed to be processed by remote.");
|
|
3356
3601
|
break;
|
|
3357
3602
|
case "sent":
|
|
3358
3603
|
default:
|
|
@@ -3384,7 +3629,7 @@ var RTCPeerConnectionController = class extends Destroyable {
|
|
|
3384
3629
|
}
|
|
3385
3630
|
await this.setupLocalTracks();
|
|
3386
3631
|
const { answerOptions } = this;
|
|
3387
|
-
logger$
|
|
3632
|
+
logger$12.debug("[RTCPeerConnectionController] Creating inbound answer with options:", answerOptions);
|
|
3388
3633
|
await this.createAnswer(answerOptions);
|
|
3389
3634
|
}
|
|
3390
3635
|
async handleOfferReceived() {
|
|
@@ -3392,7 +3637,7 @@ var RTCPeerConnectionController = class extends Destroyable {
|
|
|
3392
3637
|
this._isNegotiating$.next(true);
|
|
3393
3638
|
await this._setRemoteDescription(this.sdpInit);
|
|
3394
3639
|
const { answerOptions } = this;
|
|
3395
|
-
logger$
|
|
3640
|
+
logger$12.debug("[RTCPeerConnectionController] Creating answer with options:", answerOptions);
|
|
3396
3641
|
await this.createAnswer(answerOptions);
|
|
3397
3642
|
}
|
|
3398
3643
|
readyToConnect() {
|
|
@@ -3400,7 +3645,7 @@ var RTCPeerConnectionController = class extends Destroyable {
|
|
|
3400
3645
|
this.connectionTimer = setTimeout(() => {
|
|
3401
3646
|
this.removeConnectionTimer();
|
|
3402
3647
|
if (this.peerConnection?.connectionState !== "connected") {
|
|
3403
|
-
logger$
|
|
3648
|
+
logger$12.debug("[RTCPeerConnectionController] Connection timeout, restarting ICE gathering with relay only.");
|
|
3404
3649
|
this.iceGatheringController.restartICEGatheringWithRelayOnly();
|
|
3405
3650
|
}
|
|
3406
3651
|
}, this.connectionTimeout);
|
|
@@ -3460,13 +3705,13 @@ var RTCPeerConnectionController = class extends Destroyable {
|
|
|
3460
3705
|
await this.setupRemoteTracks();
|
|
3461
3706
|
}
|
|
3462
3707
|
async setupLocalTracks() {
|
|
3463
|
-
logger$
|
|
3708
|
+
logger$12.debug("[RTCPeerConnectionController] Setting up local tracks/transceivers.");
|
|
3464
3709
|
const localStream = this.localStream ?? await this.localStreamController.buildLocalStream();
|
|
3465
3710
|
if (this.transceiverController?.useAddStream ?? false) {
|
|
3466
|
-
logger$
|
|
3711
|
+
logger$12.warn("[RTCPeerConnectionController] Using deprecated addStream API to add local stream.");
|
|
3467
3712
|
this.peerConnection?.addStream(localStream);
|
|
3468
3713
|
if (!this.isNegotiating) {
|
|
3469
|
-
logger$
|
|
3714
|
+
logger$12.debug("[RTCPeerConnectionController] Forcing negotiationneeded after local tracks setup.");
|
|
3470
3715
|
this.negotiationNeeded$.next();
|
|
3471
3716
|
}
|
|
3472
3717
|
return;
|
|
@@ -3482,7 +3727,7 @@ var RTCPeerConnectionController = class extends Destroyable {
|
|
|
3482
3727
|
const transceivers = (kind === "audio" ? this.transceiverController?.audioTransceivers : this.transceiverController?.videoTransceivers) ?? [];
|
|
3483
3728
|
await this.transceiverController?.setupTransceiverSender(track, localStream, transceivers[index]);
|
|
3484
3729
|
} else {
|
|
3485
|
-
logger$
|
|
3730
|
+
logger$12.debug(`[RTCPeerConnectionController] Using addTrack for local ${kind} track:`, track.id);
|
|
3486
3731
|
this.peerConnection?.addTrack(track, localStream);
|
|
3487
3732
|
}
|
|
3488
3733
|
}
|
|
@@ -3499,7 +3744,7 @@ var RTCPeerConnectionController = class extends Destroyable {
|
|
|
3499
3744
|
async setupRemoteTracks() {
|
|
3500
3745
|
if (!this.peerConnection) throw new require_operators.DependencyError("RTCPeerConnection is not initialized");
|
|
3501
3746
|
this.peerConnection.ontrack = (event) => {
|
|
3502
|
-
logger$
|
|
3747
|
+
logger$12.debug("[RTCPeerConnectionController] Remote track received:", event.track.kind);
|
|
3503
3748
|
if (event.streams[0]) this._remoteStream$.next(event.streams[0]);
|
|
3504
3749
|
else {
|
|
3505
3750
|
const existingTracks = this._remoteStream$.value?.getTracks() ?? [];
|
|
@@ -3525,9 +3770,9 @@ var RTCPeerConnectionController = class extends Destroyable {
|
|
|
3525
3770
|
try {
|
|
3526
3771
|
const localStream = this.localStreamController.addTrack(track);
|
|
3527
3772
|
this.peerConnection.addTrack(track, localStream);
|
|
3528
|
-
logger$
|
|
3773
|
+
logger$12.debug(`[RTCPeerConnectionController] ${track.kind} track added:`, track.id);
|
|
3529
3774
|
} catch (error) {
|
|
3530
|
-
logger$
|
|
3775
|
+
logger$12.error(`[RTCPeerConnectionController] Failed to add ${track.kind} track:`, error);
|
|
3531
3776
|
this._errors$.next(error);
|
|
3532
3777
|
throw error;
|
|
3533
3778
|
}
|
|
@@ -3544,15 +3789,15 @@ var RTCPeerConnectionController = class extends Destroyable {
|
|
|
3544
3789
|
}
|
|
3545
3790
|
const sender = this.peerConnection.getSenders().find((sender$1) => sender$1.track?.id === trackId);
|
|
3546
3791
|
if (!sender) {
|
|
3547
|
-
logger$
|
|
3792
|
+
logger$12.debug(`[RTCPeerConnectionController] track not found: ${trackId}`);
|
|
3548
3793
|
return;
|
|
3549
3794
|
}
|
|
3550
3795
|
try {
|
|
3551
3796
|
this.peerConnection.removeTrack(sender);
|
|
3552
3797
|
this.localStreamController.removeTrack(trackId);
|
|
3553
|
-
logger$
|
|
3798
|
+
logger$12.debug(`[RTCPeerConnectionController] ${sender.track?.kind} track removed:`, trackId);
|
|
3554
3799
|
} catch (error) {
|
|
3555
|
-
logger$
|
|
3800
|
+
logger$12.error(`[RTCPeerConnectionController] Failed to remove ${sender.track?.kind} track:`, error);
|
|
3556
3801
|
this._errors$.next(error);
|
|
3557
3802
|
throw error;
|
|
3558
3803
|
}
|
|
@@ -3575,7 +3820,7 @@ var RTCPeerConnectionController = class extends Destroyable {
|
|
|
3575
3820
|
* Completes all observables to prevent memory leaks.
|
|
3576
3821
|
*/
|
|
3577
3822
|
destroy() {
|
|
3578
|
-
logger$
|
|
3823
|
+
logger$12.debug(`[RTCPeerConnectionController] Destroying RTCPeerConnectionController. ${this.propose}`);
|
|
3579
3824
|
this.removeConnectionTimer();
|
|
3580
3825
|
this._iceGatheringController?.destroy();
|
|
3581
3826
|
this.localStreamController.destroy();
|
|
@@ -3599,7 +3844,7 @@ var RTCPeerConnectionController = class extends Destroyable {
|
|
|
3599
3844
|
}
|
|
3600
3845
|
stopRemoteTracks() {
|
|
3601
3846
|
this._remoteStream$.value?.getTracks().forEach((track) => {
|
|
3602
|
-
logger$
|
|
3847
|
+
logger$12.debug(`[RTCPeerConnectionController] Stopping remote track: ${track.kind}`);
|
|
3603
3848
|
track.stop();
|
|
3604
3849
|
});
|
|
3605
3850
|
}
|
|
@@ -3616,7 +3861,7 @@ var RTCPeerConnectionController = class extends Destroyable {
|
|
|
3616
3861
|
...params,
|
|
3617
3862
|
sdp: finalRemote
|
|
3618
3863
|
};
|
|
3619
|
-
logger$
|
|
3864
|
+
logger$12.debug("[RTCPeerConnectionController] Setting remote description:", answer);
|
|
3620
3865
|
return this.peerConnection.setRemoteDescription(answer);
|
|
3621
3866
|
}
|
|
3622
3867
|
};
|
|
@@ -3654,7 +3899,7 @@ function isVertoPingInnerParams(value) {
|
|
|
3654
3899
|
|
|
3655
3900
|
//#endregion
|
|
3656
3901
|
//#region src/managers/VertoManager.ts
|
|
3657
|
-
const logger$
|
|
3902
|
+
const logger$11 = require_operators.getLogger();
|
|
3658
3903
|
var VertoManager = class extends Destroyable {
|
|
3659
3904
|
constructor(callSession) {
|
|
3660
3905
|
super();
|
|
@@ -3692,7 +3937,7 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
3692
3937
|
try {
|
|
3693
3938
|
await this.executeVerto(vertoModifyMessage);
|
|
3694
3939
|
} catch (error) {
|
|
3695
|
-
logger$
|
|
3940
|
+
logger$11.warn("[WebRTCManager] Call might already be disconnected, error sending Verto hold:", error);
|
|
3696
3941
|
throw error;
|
|
3697
3942
|
}
|
|
3698
3943
|
}
|
|
@@ -3705,7 +3950,7 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
3705
3950
|
try {
|
|
3706
3951
|
await this.executeVerto(vertoModifyMessage);
|
|
3707
3952
|
} catch (error) {
|
|
3708
|
-
logger$
|
|
3953
|
+
logger$11.warn("[WebRTCManager] Call might already be disconnected, error sending Verto unhold:", error);
|
|
3709
3954
|
throw error;
|
|
3710
3955
|
}
|
|
3711
3956
|
}
|
|
@@ -3758,7 +4003,7 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
3758
4003
|
if (event.member_id) this.setSelfIdIfNull(event.member_id);
|
|
3759
4004
|
});
|
|
3760
4005
|
this.subscribeTo(this.vertoMedia$, (event) => {
|
|
3761
|
-
logger$
|
|
4006
|
+
logger$11.debug("[WebRTCManager] Received Verto media event (early media SDP):", event);
|
|
3762
4007
|
this._signalingStatus$.next("ringing");
|
|
3763
4008
|
const { sdp, callID } = event;
|
|
3764
4009
|
this._rtcPeerConnectionsMap.get(callID)?.updateAnswerStatus({
|
|
@@ -3767,7 +4012,7 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
3767
4012
|
});
|
|
3768
4013
|
});
|
|
3769
4014
|
this.subscribeTo(this.vertoAnswer$, (event) => {
|
|
3770
|
-
logger$
|
|
4015
|
+
logger$11.debug("[WebRTCManager] Received Verto answer event:", event);
|
|
3771
4016
|
this._signalingStatus$.next("connecting");
|
|
3772
4017
|
const { sdp, callID } = event;
|
|
3773
4018
|
this._rtcPeerConnectionsMap.get(callID)?.updateAnswerStatus({
|
|
@@ -3776,7 +4021,7 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
3776
4021
|
});
|
|
3777
4022
|
});
|
|
3778
4023
|
this.subscribeTo(this.vertoMediaParams$, (event) => {
|
|
3779
|
-
logger$
|
|
4024
|
+
logger$11.debug("[WebRTCManager] Received Verto mediaParams event:", event);
|
|
3780
4025
|
const { mediaParams, callID } = event;
|
|
3781
4026
|
const rtcPeerConnController = this._rtcPeerConnectionsMap.get(callID);
|
|
3782
4027
|
const { audio, video } = mediaParams;
|
|
@@ -3800,13 +4045,13 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
3800
4045
|
*/
|
|
3801
4046
|
setNodeIdIfNull(nodeId) {
|
|
3802
4047
|
if (!this._nodeId$.value && nodeId) {
|
|
3803
|
-
logger$
|
|
4048
|
+
logger$11.debug(`[WebRTCManager] Early node_id set: ${nodeId}`);
|
|
3804
4049
|
this._nodeId$.next(nodeId);
|
|
3805
4050
|
}
|
|
3806
4051
|
}
|
|
3807
4052
|
setSelfIdIfNull(selfId) {
|
|
3808
4053
|
if (!this._selfId$.value && selfId) {
|
|
3809
|
-
logger$
|
|
4054
|
+
logger$11.debug(`[WebRTCManager] Early selfId set: ${selfId}`);
|
|
3810
4055
|
this._selfId$.next(selfId);
|
|
3811
4056
|
}
|
|
3812
4057
|
}
|
|
@@ -3815,7 +4060,7 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
3815
4060
|
const vertoPongMessage = VertoPong({ ...vertoPing });
|
|
3816
4061
|
await this.executeVerto(vertoPongMessage);
|
|
3817
4062
|
} catch (error) {
|
|
3818
|
-
logger$
|
|
4063
|
+
logger$11.warn("[WebRTCManager] Call might disconnect, error sending Verto pong:", error);
|
|
3819
4064
|
this.onError?.(new require_operators.VertoPongError(error));
|
|
3820
4065
|
}
|
|
3821
4066
|
}
|
|
@@ -3825,7 +4070,7 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
3825
4070
|
if (audio) await this.mainPeerConnection.updateSendersConstraints("audio", audio);
|
|
3826
4071
|
if (video) await this.mainPeerConnection.updateSendersConstraints("video", video);
|
|
3827
4072
|
} catch (error) {
|
|
3828
|
-
logger$
|
|
4073
|
+
logger$11.warn("[WebRTCManager] Error updating media constraints:", error);
|
|
3829
4074
|
this.onError?.(error instanceof Error ? error : new Error(String(error), { cause: error }));
|
|
3830
4075
|
throw error;
|
|
3831
4076
|
}
|
|
@@ -3890,7 +4135,7 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
3890
4135
|
default:
|
|
3891
4136
|
}
|
|
3892
4137
|
} catch (error) {
|
|
3893
|
-
logger$
|
|
4138
|
+
logger$11.error(`[WebRTCManager] Error sending Verto ${vertoMethod}:`, error);
|
|
3894
4139
|
this.onError?.(error instanceof Error ? error : new Error(String(error), { cause: error }));
|
|
3895
4140
|
}
|
|
3896
4141
|
}
|
|
@@ -3904,7 +4149,7 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
3904
4149
|
sdp
|
|
3905
4150
|
});
|
|
3906
4151
|
} catch (error) {
|
|
3907
|
-
logger$
|
|
4152
|
+
logger$11.warn("[WebRTCManager] Error processing modify response:", error);
|
|
3908
4153
|
const modifyError = error instanceof Error ? error : new Error(String(error), { cause: error });
|
|
3909
4154
|
this.onError?.(modifyError);
|
|
3910
4155
|
}
|
|
@@ -3916,7 +4161,7 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
3916
4161
|
this._nodeId$.next(require_operators.getValueFrom(response, "result.node_id") ?? null);
|
|
3917
4162
|
const memberId = require_operators.getValueFrom(response, "result.result.result.memberID") ?? null;
|
|
3918
4163
|
const callId = require_operators.getValueFrom(response, "result.result.result.callID") ?? null;
|
|
3919
|
-
logger$
|
|
4164
|
+
logger$11.debug("[WebRTCManager] Verto invite response:", {
|
|
3920
4165
|
callId,
|
|
3921
4166
|
memberId,
|
|
3922
4167
|
response
|
|
@@ -3925,10 +4170,10 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
3925
4170
|
rtcPeerConnController.setMemberId(memberId);
|
|
3926
4171
|
if (callId) this.webRtcCallSession.addCallId(callId);
|
|
3927
4172
|
this.attachManager.attach(this.webRtcCallSession);
|
|
3928
|
-
logger$
|
|
3929
|
-
logger$
|
|
4173
|
+
logger$11.info("[WebRTCManager] Verto invite successful");
|
|
4174
|
+
logger$11.debug(`[WebRTCManager] nodeid: ${this._nodeId$.value}, selfId: ${this._selfId$.value}`);
|
|
3930
4175
|
} else {
|
|
3931
|
-
logger$
|
|
4176
|
+
logger$11.error("[WebRTCManager] Verto invite failed:", response);
|
|
3932
4177
|
const inviteError = response.error ? new require_operators.JSONRPCError(response.error.code, response.error.message, response.error.data) : /* @__PURE__ */ new Error("Verto invite failed: unexpected response");
|
|
3933
4178
|
this.onError?.(inviteError);
|
|
3934
4179
|
}
|
|
@@ -3970,17 +4215,17 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
3970
4215
|
if (options.initOffer) this.handleInboundAnswer(rtcPeerConnController);
|
|
3971
4216
|
}
|
|
3972
4217
|
async handleInboundAnswer(rtcPeerConnController) {
|
|
3973
|
-
logger$
|
|
4218
|
+
logger$11.debug("[WebRTCManager] Waiting for inbound call to be accepted or rejected");
|
|
3974
4219
|
const vertoByeOrAccepted = await (0, rxjs.firstValueFrom)((0, rxjs.race)(this.vertoBye$, this.webRtcCallSession.answered$).pipe((0, rxjs.takeUntil)(this.destroyed$))).catch(() => null);
|
|
3975
4220
|
if (vertoByeOrAccepted === null) {
|
|
3976
|
-
logger$
|
|
4221
|
+
logger$11.debug("[WebRTCManager] Inbound answer handler aborted (destroyed).");
|
|
3977
4222
|
return;
|
|
3978
4223
|
}
|
|
3979
4224
|
if (isVertoByeMessage(vertoByeOrAccepted)) {
|
|
3980
|
-
logger$
|
|
4225
|
+
logger$11.info("[WebRTCManager] Inbound call ended by remote before answer.");
|
|
3981
4226
|
this.callSession?.destroy();
|
|
3982
4227
|
} else if (!vertoByeOrAccepted) {
|
|
3983
|
-
logger$
|
|
4228
|
+
logger$11.info("[WebRTCManager] Inbound call rejected by user.");
|
|
3984
4229
|
try {
|
|
3985
4230
|
await this.bye("USER_BUSY");
|
|
3986
4231
|
} finally {
|
|
@@ -3988,19 +4233,19 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
3988
4233
|
this.callSession?.destroy();
|
|
3989
4234
|
}
|
|
3990
4235
|
} else {
|
|
3991
|
-
logger$
|
|
4236
|
+
logger$11.debug("[WebRTCManager] Inbound call accepted, creating SDP answer");
|
|
3992
4237
|
const answerOptions = this.webRtcCallSession.answerMediaOptions;
|
|
3993
4238
|
try {
|
|
3994
4239
|
await rtcPeerConnController.acceptInbound(answerOptions);
|
|
3995
4240
|
} catch (error) {
|
|
3996
|
-
logger$
|
|
4241
|
+
logger$11.error("[WebRTCManager] Error creating inbound answer:", error);
|
|
3997
4242
|
this.onError?.(error instanceof Error ? error : new Error(String(error), { cause: error }));
|
|
3998
4243
|
}
|
|
3999
4244
|
}
|
|
4000
4245
|
}
|
|
4001
4246
|
setupVertoAttachHandler() {
|
|
4002
4247
|
this.subscribeTo(this.vertoAttach$, async (vertoAttach) => {
|
|
4003
|
-
logger$
|
|
4248
|
+
logger$11.debug("[WebRTCManager] Received Verto attach event:", vertoAttach);
|
|
4004
4249
|
const { callID } = vertoAttach;
|
|
4005
4250
|
await this.attachManager.attach({
|
|
4006
4251
|
id: callID,
|
|
@@ -4068,13 +4313,13 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
4068
4313
|
};
|
|
4069
4314
|
}
|
|
4070
4315
|
async sendLocalDescriptionOnceAccepted(vertoMessageRequest, rtcPeerConnectionController) {
|
|
4071
|
-
logger$
|
|
4316
|
+
logger$11.debug("[WebRTCManager] Waiting for call to be accepted or ended before sending answer");
|
|
4072
4317
|
const vertoByeOrAccepted = await (0, rxjs.firstValueFrom)((0, rxjs.race)(this.vertoBye$, this.webRtcCallSession.answered$));
|
|
4073
4318
|
if (isVertoByeMessage(vertoByeOrAccepted)) {
|
|
4074
|
-
logger$
|
|
4319
|
+
logger$11.info("[WebRTCManager] Call ended before answer was sent.");
|
|
4075
4320
|
this.callSession?.destroy();
|
|
4076
4321
|
} else if (!vertoByeOrAccepted) {
|
|
4077
|
-
logger$
|
|
4322
|
+
logger$11.info("[WebRTCManager] Call was not accepted, sending verto.bye.");
|
|
4078
4323
|
try {
|
|
4079
4324
|
await this.bye("USER_BUSY");
|
|
4080
4325
|
} finally {
|
|
@@ -4082,14 +4327,14 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
4082
4327
|
this.callSession?.destroy();
|
|
4083
4328
|
}
|
|
4084
4329
|
} else {
|
|
4085
|
-
logger$
|
|
4330
|
+
logger$11.debug("[WebRTCManager] Call accepted, sending answer");
|
|
4086
4331
|
try {
|
|
4087
4332
|
this._signalingStatus$.next("connecting");
|
|
4088
4333
|
await this.sendLocalDescription(vertoMessageRequest, rtcPeerConnectionController);
|
|
4089
4334
|
await rtcPeerConnectionController.updateAnswerStatus({ status: "sent" });
|
|
4090
4335
|
await this.attachManager.attach(this.webRtcCallSession);
|
|
4091
4336
|
} catch (error) {
|
|
4092
|
-
logger$
|
|
4337
|
+
logger$11.error("[WebRTCManager] Error sending Verto answer:", error);
|
|
4093
4338
|
this.onError?.(error instanceof Error ? error : new Error(String(error), { cause: error }));
|
|
4094
4339
|
await rtcPeerConnectionController.updateAnswerStatus({ status: "failed" });
|
|
4095
4340
|
}
|
|
@@ -4180,10 +4425,10 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
4180
4425
|
});
|
|
4181
4426
|
await (0, rxjs.firstValueFrom)(rtcPeerConnController.connectionState$.pipe((0, rxjs.filter)((state) => state === "connected"), (0, rxjs.take)(1), (0, rxjs.timeout)(this._screenShareTimeoutMs)));
|
|
4182
4427
|
this._screenShareStatus$.next("started");
|
|
4183
|
-
logger$
|
|
4428
|
+
logger$11.info("[WebRTCManager] Screen share started successfully.");
|
|
4184
4429
|
return rtcPeerConnController.id;
|
|
4185
4430
|
} catch (error) {
|
|
4186
|
-
logger$
|
|
4431
|
+
logger$11.warn("[WebRTCManager] Error initializing additional peer connection:", error);
|
|
4187
4432
|
this.onError?.(error instanceof Error ? error : new Error(String(error), { cause: error }));
|
|
4188
4433
|
if (rtcPeerConnController) rtcPeerConnController.destroy();
|
|
4189
4434
|
this._screenShareStatus$.next("none");
|
|
@@ -4202,9 +4447,9 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
4202
4447
|
if (removeTrack) return this.mainPeerConnection.stopTrackSender(removeTrack, { updateTransceiverDirection: true });
|
|
4203
4448
|
}
|
|
4204
4449
|
async removeScreenMedia() {
|
|
4205
|
-
if (!["starting", "started"].includes(this._screenShareStatus$.value)) logger$
|
|
4450
|
+
if (!["starting", "started"].includes(this._screenShareStatus$.value)) logger$11.warn("[WebRTCManager] No active screen share to stop.");
|
|
4206
4451
|
if (!this._screenShareId) {
|
|
4207
|
-
logger$
|
|
4452
|
+
logger$11.debug("[WebRTCManager] No screen share peer connection found.");
|
|
4208
4453
|
return;
|
|
4209
4454
|
}
|
|
4210
4455
|
this._screenShareStatus$.next("stopping");
|
|
@@ -4233,7 +4478,7 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
4233
4478
|
dialogParams: this.dialogParams(rtcPeerConnController)
|
|
4234
4479
|
}));
|
|
4235
4480
|
} catch (error) {
|
|
4236
|
-
logger$
|
|
4481
|
+
logger$11.warn("[WebRTCManager] Call might already be disconnected, error sending Verto bye:", error);
|
|
4237
4482
|
throw error;
|
|
4238
4483
|
}
|
|
4239
4484
|
}
|
|
@@ -4251,7 +4496,7 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
4251
4496
|
try {
|
|
4252
4497
|
await this.executeVerto(vertoInfoMessage);
|
|
4253
4498
|
} catch (error) {
|
|
4254
|
-
logger$
|
|
4499
|
+
logger$11.warn("[WebRTCManager] Error sending DTMF digits:", error);
|
|
4255
4500
|
throw error;
|
|
4256
4501
|
}
|
|
4257
4502
|
}
|
|
@@ -4262,10 +4507,10 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
4262
4507
|
action: "transfer"
|
|
4263
4508
|
});
|
|
4264
4509
|
try {
|
|
4265
|
-
logger$
|
|
4510
|
+
logger$11.debug("[WebRTCManager] Transferring call with options:", options);
|
|
4266
4511
|
await this.executeVerto(message);
|
|
4267
4512
|
} catch (error) {
|
|
4268
|
-
logger$
|
|
4513
|
+
logger$11.error("[WebRTCManager] Error transferring call:", error);
|
|
4269
4514
|
throw error;
|
|
4270
4515
|
}
|
|
4271
4516
|
}
|
|
@@ -4307,7 +4552,7 @@ var ParticipantFactory = class {
|
|
|
4307
4552
|
|
|
4308
4553
|
//#endregion
|
|
4309
4554
|
//#region src/core/entities/Call.ts
|
|
4310
|
-
const logger$
|
|
4555
|
+
const logger$10 = require_operators.getLogger();
|
|
4311
4556
|
const fromDestinationParams = (destination) => {
|
|
4312
4557
|
if (!destination) return {};
|
|
4313
4558
|
try {
|
|
@@ -4318,7 +4563,7 @@ const fromDestinationParams = (destination) => {
|
|
|
4318
4563
|
});
|
|
4319
4564
|
return params;
|
|
4320
4565
|
} catch (error) {
|
|
4321
|
-
logger$
|
|
4566
|
+
logger$10.warn(`Failed to parse destination URI: ${destination}`, error);
|
|
4322
4567
|
return {};
|
|
4323
4568
|
}
|
|
4324
4569
|
};
|
|
@@ -4493,7 +4738,7 @@ var WebRTCCall = class extends Destroyable {
|
|
|
4493
4738
|
if (isJSONRPCErrorResponse(response)) throw new require_operators.JSONRPCError(parseInt(response.result?.code ?? "0"), `Error response from method ${method}: ${response.result?.code} ${response.result?.message}`, void 0, void 0, request.id);
|
|
4494
4739
|
return response;
|
|
4495
4740
|
} catch (error) {
|
|
4496
|
-
logger$
|
|
4741
|
+
logger$10.error(`[Call] Error executing method ${method} with params`, params, error);
|
|
4497
4742
|
throw error;
|
|
4498
4743
|
}
|
|
4499
4744
|
}
|
|
@@ -4674,18 +4919,20 @@ var WebRTCCall = class extends Destroyable {
|
|
|
4674
4919
|
}
|
|
4675
4920
|
isCallSessionEvent(event) {
|
|
4676
4921
|
try {
|
|
4677
|
-
logger$
|
|
4922
|
+
logger$10.debug("[Call] Checking if event is for this call session:", event);
|
|
4678
4923
|
const callId = require_operators.getValueFrom(event, "params.params.callID") ?? require_operators.getValueFrom(event, "params.call_id");
|
|
4679
4924
|
const roomSessionId = require_operators.getValueFrom(event, "params.room_session_id");
|
|
4680
|
-
logger$
|
|
4925
|
+
logger$10.debug(`[Call] Extracted session identifiers callID: ${callId} and roomSessionID: ${roomSessionId} from event:`);
|
|
4681
4926
|
return callId === this.id || !!callId && this.callEventsManager.isCallIdValid(callId) || !!roomSessionId && this.callEventsManager.isRoomSessionIdValid(roomSessionId);
|
|
4682
4927
|
} catch (error) {
|
|
4683
|
-
logger$
|
|
4928
|
+
logger$10.error("[Call] Error checking if event is for this call session:", error);
|
|
4684
4929
|
return false;
|
|
4685
4930
|
}
|
|
4686
4931
|
}
|
|
4687
4932
|
get callSessionEvents$() {
|
|
4688
|
-
return this.cachedObservable("callSessionEvents$", () => this.clientSession.signalingEvent$.pipe((0, rxjs.filter)((event) => this.isCallSessionEvent(event)), (0, rxjs.tap)((event) =>
|
|
4933
|
+
return this.cachedObservable("callSessionEvents$", () => this.clientSession.signalingEvent$.pipe((0, rxjs.filter)((event) => this.isCallSessionEvent(event)), (0, rxjs.tap)((event) => {
|
|
4934
|
+
logger$10.debug("[Call] Received call session event:", event);
|
|
4935
|
+
}), (0, rxjs.takeUntil)(this.destroyed$), (0, rxjs.share)()));
|
|
4689
4936
|
}
|
|
4690
4937
|
/** Observable of call-updated events. */
|
|
4691
4938
|
get callUpdated$() {
|
|
@@ -4725,11 +4972,11 @@ var WebRTCCall = class extends Destroyable {
|
|
|
4725
4972
|
}
|
|
4726
4973
|
/** Observable of WebRTC-specific signaling messages. */
|
|
4727
4974
|
get webrtcMessages$() {
|
|
4728
|
-
return this.cachedObservable("webrtcMessages$", () => this.callSessionEvents$.pipe(require_operators.filterAs(isWebrtcMessageMetadata, "params"), (0, rxjs.tap)((event) => logger$
|
|
4975
|
+
return this.cachedObservable("webrtcMessages$", () => this.callSessionEvents$.pipe(require_operators.filterAs(isWebrtcMessageMetadata, "params"), (0, rxjs.tap)((event) => logger$10.debug("[Call] Event is a WebRTC message event:", event)), (0, rxjs.takeUntil)(this.destroyed$), (0, rxjs.share)()));
|
|
4729
4976
|
}
|
|
4730
4977
|
/** Observable of call-level signaling events. */
|
|
4731
4978
|
get callEvent$() {
|
|
4732
|
-
return this.cachedObservable("callEvent$", () => this.callSessionEvents$.pipe(require_operators.filterAs(isSignalwireCallMetadata, "params"), (0, rxjs.tap)((event) => logger$
|
|
4979
|
+
return this.cachedObservable("callEvent$", () => this.callSessionEvents$.pipe(require_operators.filterAs(isSignalwireCallMetadata, "params"), (0, rxjs.tap)((event) => logger$10.debug("[Call] Event is a call event:", event)), (0, rxjs.takeUntil)(this.destroyed$), (0, rxjs.share)()));
|
|
4733
4980
|
}
|
|
4734
4981
|
/** Observable of layout-changed signaling events. */
|
|
4735
4982
|
get layoutEvent$() {
|
|
@@ -4904,7 +5151,7 @@ var CallFactory = class {
|
|
|
4904
5151
|
|
|
4905
5152
|
//#endregion
|
|
4906
5153
|
//#region src/behaviors/Collection.ts
|
|
4907
|
-
const logger$
|
|
5154
|
+
const logger$9 = require_operators.getLogger();
|
|
4908
5155
|
var Fetcher = class {
|
|
4909
5156
|
constructor(endpoint, params, http) {
|
|
4910
5157
|
this.endpoint = endpoint;
|
|
@@ -4928,7 +5175,7 @@ var Fetcher = class {
|
|
|
4928
5175
|
this.hasMore = !!this.nextUrl;
|
|
4929
5176
|
return result.data.filter(this.filter).map(this.mapper);
|
|
4930
5177
|
}
|
|
4931
|
-
logger$
|
|
5178
|
+
logger$9.error("Failed to fetch entity");
|
|
4932
5179
|
return [];
|
|
4933
5180
|
}
|
|
4934
5181
|
async id(v) {
|
|
@@ -4991,7 +5238,7 @@ var EntityCollection = class extends Destroyable {
|
|
|
4991
5238
|
this._hasMore$.next(this.fetchController.hasMore ?? false);
|
|
4992
5239
|
this.loading$.next(false);
|
|
4993
5240
|
} catch (error) {
|
|
4994
|
-
logger$
|
|
5241
|
+
logger$9.error(`Failed to fetch initial collection data`, error);
|
|
4995
5242
|
this._hasMore$.next(this.fetchController.hasMore ?? false);
|
|
4996
5243
|
this.loading$.next(false);
|
|
4997
5244
|
this.onError?.(new require_operators.CollectionFetchError("fetchMore", error));
|
|
@@ -5005,7 +5252,7 @@ var EntityCollection = class extends Destroyable {
|
|
|
5005
5252
|
if (data) this.upsertData(data);
|
|
5006
5253
|
return data;
|
|
5007
5254
|
} catch (error) {
|
|
5008
|
-
logger$
|
|
5255
|
+
logger$9.error(`Failed to fetch data for (${String(key)}:${String(value)}) :`, error);
|
|
5009
5256
|
this.loading$.next(false);
|
|
5010
5257
|
this.onError?.(new require_operators.CollectionFetchError(`tryFetch(${String(key)})`, error));
|
|
5011
5258
|
}
|
|
@@ -5035,9 +5282,9 @@ var EntityCollection = class extends Destroyable {
|
|
|
5035
5282
|
}
|
|
5036
5283
|
};
|
|
5037
5284
|
var EntityCollectionTransformed = class {
|
|
5038
|
-
constructor(originalCollection, filter$
|
|
5285
|
+
constructor(originalCollection, filter$11 = (i) => !!i, mapper = (item) => item) {
|
|
5039
5286
|
this.originalCollection = originalCollection;
|
|
5040
|
-
this.filter = filter$
|
|
5287
|
+
this.filter = filter$11;
|
|
5041
5288
|
this.mapper = mapper;
|
|
5042
5289
|
}
|
|
5043
5290
|
get loading$() {
|
|
@@ -5254,13 +5501,13 @@ var Address = class extends Destroyable {
|
|
|
5254
5501
|
|
|
5255
5502
|
//#endregion
|
|
5256
5503
|
//#region src/core/utils.ts
|
|
5257
|
-
const logger$
|
|
5504
|
+
const logger$8 = require_operators.getLogger();
|
|
5258
5505
|
const isRPCConnectResult = (e) => {
|
|
5259
|
-
logger$
|
|
5506
|
+
logger$8.debug("isRPCConnectResult check:", e);
|
|
5260
5507
|
if (!e || typeof e !== "object") return false;
|
|
5261
5508
|
const result = e;
|
|
5262
5509
|
const is = typeof result.identity === "string" && typeof result.protocol === "string" && typeof result.authorization === "object" && typeof result.authorization.jti === "string" && typeof result.authorization.project_id === "string" && typeof result.authorization.fabric_subscriber === "object";
|
|
5263
|
-
logger$
|
|
5510
|
+
logger$8.debug("isRPCConnectResult check result:", is);
|
|
5264
5511
|
return is;
|
|
5265
5512
|
};
|
|
5266
5513
|
var PendingRPC = class PendingRPC {
|
|
@@ -5269,7 +5516,7 @@ var PendingRPC = class PendingRPC {
|
|
|
5269
5516
|
}
|
|
5270
5517
|
constructor(request, responses$, options) {
|
|
5271
5518
|
this.id = (0, uuid.v4)();
|
|
5272
|
-
logger$
|
|
5519
|
+
logger$8.debug(`[PendingRPC(${this.id}) request:${request.id}: method:${request.method}] Creating PendingRPC`);
|
|
5273
5520
|
this.request = request;
|
|
5274
5521
|
const timeoutMs = options?.timeoutMs ?? PendingRPC.defaultTimeoutMs;
|
|
5275
5522
|
const signal = options?.signal;
|
|
@@ -5280,10 +5527,10 @@ var PendingRPC = class PendingRPC {
|
|
|
5280
5527
|
}
|
|
5281
5528
|
let isSettled = false;
|
|
5282
5529
|
const subscription = (0, rxjs.race)(responses$.pipe((0, rxjs.filter)((result) => result.id === request.id), (0, rxjs.take)(1)), new rxjs.Observable((subscriber) => {
|
|
5283
|
-
const timer = setTimeout(() => {
|
|
5530
|
+
const timer$1 = setTimeout(() => {
|
|
5284
5531
|
subscriber.error(new require_operators.RPCTimeoutError(request.id, timeoutMs));
|
|
5285
5532
|
}, timeoutMs);
|
|
5286
|
-
return () => clearTimeout(timer);
|
|
5533
|
+
return () => clearTimeout(timer$1);
|
|
5287
5534
|
}), signal ? new rxjs.Observable((subscriber) => {
|
|
5288
5535
|
const abortHandler = () => {
|
|
5289
5536
|
subscriber.error(new DOMException("The operation was aborted", "AbortError"));
|
|
@@ -5295,22 +5542,22 @@ var PendingRPC = class PendingRPC {
|
|
|
5295
5542
|
isSettled = true;
|
|
5296
5543
|
if (response.error) {
|
|
5297
5544
|
const rpcError = new require_operators.JSONRPCError(response.error.code, response.error.message, response.error.data, void 0, request.id);
|
|
5298
|
-
logger$
|
|
5545
|
+
logger$8.debug(`[PendingRPC(${this.id}) request:${request.id}] Rejecting promise with RPC error:`, rpcError);
|
|
5299
5546
|
reject(rpcError);
|
|
5300
5547
|
} else {
|
|
5301
|
-
logger$
|
|
5548
|
+
logger$8.debug(`[PendingRPC(${this.id}) request:${request.id}] Resolving promise with response:`, response);
|
|
5302
5549
|
resolve(response);
|
|
5303
5550
|
}
|
|
5304
5551
|
subscription.unsubscribe();
|
|
5305
5552
|
},
|
|
5306
5553
|
error: (error) => {
|
|
5307
|
-
logger$
|
|
5554
|
+
logger$8.debug(`[PendingRPC(${this.id}) request:${request.id}] Rejecting promise with error:`, error);
|
|
5308
5555
|
isSettled = true;
|
|
5309
5556
|
reject(error);
|
|
5310
5557
|
subscription.unsubscribe();
|
|
5311
5558
|
},
|
|
5312
5559
|
complete: () => {
|
|
5313
|
-
logger$
|
|
5560
|
+
logger$8.debug(`[PendingRPC(${this.id}) request:${request.id}] Observable completed`);
|
|
5314
5561
|
if (!isSettled) reject(new require_operators.RPCTimeoutError(request.id, timeoutMs));
|
|
5315
5562
|
subscription.unsubscribe();
|
|
5316
5563
|
}
|
|
@@ -5330,7 +5577,7 @@ var PendingRPC = class PendingRPC {
|
|
|
5330
5577
|
|
|
5331
5578
|
//#endregion
|
|
5332
5579
|
//#region src/managers/ClientSessionManager.ts
|
|
5333
|
-
const logger$
|
|
5580
|
+
const logger$7 = require_operators.getLogger();
|
|
5334
5581
|
const getAddressSearchURI = (options) => {
|
|
5335
5582
|
const to = options.to?.split("?")[0];
|
|
5336
5583
|
const from$6 = options.from?.startsWith("subscriber://") ? options.from.replace("subscriber://", "") : options.from;
|
|
@@ -5339,13 +5586,14 @@ const getAddressSearchURI = (options) => {
|
|
|
5339
5586
|
return name;
|
|
5340
5587
|
};
|
|
5341
5588
|
var ClientSessionManager = class extends Destroyable {
|
|
5342
|
-
constructor(
|
|
5589
|
+
constructor(getCredential, transport, storage, authorizationStateKey, deviceController, attachManager, webRTCApiProvider, dpopManager) {
|
|
5343
5590
|
super();
|
|
5344
|
-
this.
|
|
5591
|
+
this.getCredential = getCredential;
|
|
5345
5592
|
this.transport = transport;
|
|
5346
5593
|
this.storage = storage;
|
|
5347
5594
|
this.authorizationStateKey = authorizationStateKey;
|
|
5348
5595
|
this.attachManager = attachManager;
|
|
5596
|
+
this.dpopManager = dpopManager;
|
|
5349
5597
|
this.callCreateTimeout = 6e3;
|
|
5350
5598
|
this.agent = `signalwire-typescript-sdk/1.0.0`;
|
|
5351
5599
|
this.eventAcks = true;
|
|
@@ -5358,6 +5606,7 @@ var ClientSessionManager = class extends Destroyable {
|
|
|
5358
5606
|
this._authorization$ = this.createBehaviorSubject(void 0);
|
|
5359
5607
|
this._errors$ = this.createReplaySubject(1);
|
|
5360
5608
|
this._authenticated$ = this.createBehaviorSubject(false);
|
|
5609
|
+
this._clientBound = false;
|
|
5361
5610
|
this._subscriberInfo$ = this.createBehaviorSubject(null);
|
|
5362
5611
|
this._calls$ = this.createBehaviorSubject({});
|
|
5363
5612
|
this._iceServers$ = this.createBehaviorSubject([]);
|
|
@@ -5402,6 +5651,15 @@ var ClientSessionManager = class extends Destroyable {
|
|
|
5402
5651
|
return this._authenticated$.value;
|
|
5403
5652
|
}
|
|
5404
5653
|
/**
|
|
5654
|
+
* Whether this session is client-bound (using a Client Bound SAT).
|
|
5655
|
+
* When client-bound, DPoP proof creation failures are treated as
|
|
5656
|
+
* authentication errors rather than silently degraded.
|
|
5657
|
+
* @internal
|
|
5658
|
+
*/
|
|
5659
|
+
get clientBound() {
|
|
5660
|
+
return this._clientBound;
|
|
5661
|
+
}
|
|
5662
|
+
/**
|
|
5405
5663
|
* Set the directory instance
|
|
5406
5664
|
* Called by SignalWire after directory is created
|
|
5407
5665
|
* @internal
|
|
@@ -5413,7 +5671,7 @@ var ClientSessionManager = class extends Destroyable {
|
|
|
5413
5671
|
try {
|
|
5414
5672
|
return await this.transport.execute(request, options);
|
|
5415
5673
|
} catch (error) {
|
|
5416
|
-
logger$
|
|
5674
|
+
logger$7.debug("[Session] Execute Error", error);
|
|
5417
5675
|
this._errors$.next(error instanceof Error ? error : new Error(String(error), { cause: error }));
|
|
5418
5676
|
throw error;
|
|
5419
5677
|
}
|
|
@@ -5427,32 +5685,31 @@ var ClientSessionManager = class extends Destroyable {
|
|
|
5427
5685
|
return true;
|
|
5428
5686
|
}
|
|
5429
5687
|
setupMessageHandlers() {
|
|
5430
|
-
logger$
|
|
5688
|
+
logger$7.debug("[Session] Setting up message handlers");
|
|
5431
5689
|
this.subscribeTo(this.authStateEvent$, async (authStateEvent) => {
|
|
5432
|
-
logger$
|
|
5690
|
+
logger$7.debug("[Session] Authorization state event received:", authStateEvent);
|
|
5433
5691
|
try {
|
|
5434
5692
|
await this.updateAuthorizationStateInStorage(authStateEvent.authorization_state);
|
|
5435
5693
|
} catch (error) {
|
|
5436
|
-
logger$
|
|
5694
|
+
logger$7.error("[Session] Failed to handle authorization state update:", error);
|
|
5437
5695
|
this._errors$.next(new require_operators.AuthStateHandlerError(error));
|
|
5438
5696
|
}
|
|
5439
5697
|
});
|
|
5440
|
-
this.subscribeTo(this.transport.connectionStatus$.pipe((0, rxjs.filter)((status) => status === "connected")
|
|
5441
|
-
|
|
5442
|
-
|
|
5443
|
-
await this.authenticate();
|
|
5444
|
-
} catch (error) {
|
|
5698
|
+
this.subscribeTo(this.transport.connectionStatus$.pipe((0, rxjs.filter)((status) => status === "connected"), (0, rxjs.exhaustMap)(() => {
|
|
5699
|
+
logger$7.debug("[Session] Connection established, initiating authentication");
|
|
5700
|
+
return (0, rxjs.from)(this.authenticate()).pipe((0, rxjs.catchError)((error) => {
|
|
5445
5701
|
this.handleAuthenticationError(error).catch((err) => {
|
|
5446
|
-
logger$
|
|
5702
|
+
logger$7.error("[Session] Error handling authentication failure:", err);
|
|
5447
5703
|
});
|
|
5448
|
-
|
|
5449
|
-
|
|
5704
|
+
return rxjs.EMPTY;
|
|
5705
|
+
}));
|
|
5706
|
+
})), void 0);
|
|
5450
5707
|
this.subscribeTo(this.vertoInvite$, async (invite) => {
|
|
5451
|
-
logger$
|
|
5708
|
+
logger$7.debug("[Session] Verto invite received:", invite);
|
|
5452
5709
|
try {
|
|
5453
5710
|
await this.createInboundCall(invite);
|
|
5454
5711
|
} catch (error) {
|
|
5455
|
-
logger$
|
|
5712
|
+
logger$7.error("[Session] Error handling Verto invite:", error);
|
|
5456
5713
|
this._errors$.next(new require_operators.VertoInviteHandlerError(error));
|
|
5457
5714
|
}
|
|
5458
5715
|
});
|
|
@@ -5462,35 +5719,35 @@ var ClientSessionManager = class extends Destroyable {
|
|
|
5462
5719
|
const storedState = await this.storage.getItem(this.authorizationStateKey);
|
|
5463
5720
|
this.authorizationState$.next(storedState ?? void 0);
|
|
5464
5721
|
} catch (error) {
|
|
5465
|
-
logger$
|
|
5722
|
+
logger$7.error("Failed to retrieve authorization state from storage:", error);
|
|
5466
5723
|
this.authorizationState$.next(void 0);
|
|
5467
5724
|
}
|
|
5468
5725
|
}
|
|
5469
5726
|
async updateAuthorizationStateInStorage(authorizationState) {
|
|
5470
5727
|
if (!authorizationState) {
|
|
5471
|
-
logger$
|
|
5728
|
+
logger$7.debug("[Session] Removing authorization state from storage");
|
|
5472
5729
|
try {
|
|
5473
5730
|
await this.storage.removeItem(this.authorizationStateKey);
|
|
5474
5731
|
} catch (error) {
|
|
5475
|
-
logger$
|
|
5732
|
+
logger$7.error("Failed to remove authorization state from storage:", error);
|
|
5476
5733
|
throw error;
|
|
5477
5734
|
}
|
|
5478
5735
|
return;
|
|
5479
5736
|
}
|
|
5480
5737
|
try {
|
|
5481
|
-
logger$
|
|
5738
|
+
logger$7.debug("[Session] Updating authorization state in storage");
|
|
5482
5739
|
await this.storage.setItem(this.authorizationStateKey, authorizationState);
|
|
5483
5740
|
this.authorizationState$.next(authorizationState);
|
|
5484
5741
|
} catch (error) {
|
|
5485
|
-
logger$
|
|
5742
|
+
logger$7.error("Failed to retrieve authorization state from storage:", error);
|
|
5486
5743
|
throw error;
|
|
5487
5744
|
}
|
|
5488
5745
|
}
|
|
5489
5746
|
get authStateEvent$() {
|
|
5490
5747
|
return this.cachedObservable("authStateEvent$", () => this.signalingEvent$.pipe((0, rxjs.tap)((msg) => {
|
|
5491
|
-
logger$
|
|
5748
|
+
logger$7.debug("[Session] Received incoming message:", msg);
|
|
5492
5749
|
}), require_operators.filterAs(isSignalwireAuthorizationStateMetadata, "params"), (0, rxjs.tap)((event) => {
|
|
5493
|
-
logger$
|
|
5750
|
+
logger$7.debug("[Session] Authorization state event received:", event.authorization_state);
|
|
5494
5751
|
})));
|
|
5495
5752
|
}
|
|
5496
5753
|
get signalingEvent$() {
|
|
@@ -5512,86 +5769,118 @@ var ClientSessionManager = class extends Destroyable {
|
|
|
5512
5769
|
return [];
|
|
5513
5770
|
}
|
|
5514
5771
|
get authentication() {
|
|
5515
|
-
|
|
5516
|
-
|
|
5772
|
+
const credential = this.getCredential();
|
|
5773
|
+
if (!credential.token) throw new require_operators.DependencyError("Credential token is undefined");
|
|
5774
|
+
return { jwt_token: credential.token };
|
|
5517
5775
|
}
|
|
5518
5776
|
async connect() {
|
|
5519
5777
|
await (0, rxjs.firstValueFrom)(this.initialized$);
|
|
5520
5778
|
await this.transport.connect();
|
|
5521
5779
|
}
|
|
5522
5780
|
async handleAuthenticationError(error) {
|
|
5523
|
-
logger$
|
|
5781
|
+
logger$7.error("Authentication error:", error);
|
|
5524
5782
|
this._errors$.next(error);
|
|
5525
|
-
|
|
5526
|
-
|
|
5527
|
-
|
|
5528
|
-
logger$
|
|
5529
|
-
|
|
5530
|
-
|
|
5783
|
+
const isRecoverableAuthError = error instanceof require_operators.JSONRPCError && (error.code === RPC_ERROR_REQUESTER_VALIDATION_FAILED || error.code === RPC_ERROR_INVALID_PARAMS || error.code === RPC_ERROR_AUTHENTICATION_FAILED);
|
|
5784
|
+
const hasStoredState = this._authorization$.value !== void 0;
|
|
5785
|
+
if (isRecoverableAuthError && hasStoredState) {
|
|
5786
|
+
logger$7.debug("[Session] Recoverable auth error — cleaning up stored state and reconnecting fresh");
|
|
5787
|
+
try {
|
|
5788
|
+
await this.cleanupStoredConnectionParams();
|
|
5789
|
+
} catch (cleanupError) {
|
|
5790
|
+
logger$7.error("Failed to cleanup stored connection params:", cleanupError);
|
|
5791
|
+
} finally {
|
|
5792
|
+
this.transport.reconnect();
|
|
5793
|
+
}
|
|
5531
5794
|
}
|
|
5532
5795
|
}
|
|
5533
5796
|
async cleanupStoredConnectionParams() {
|
|
5534
5797
|
await this.transport.setProtocol(void 0);
|
|
5535
5798
|
await this.updateAuthorizationStateInStorage(void 0);
|
|
5799
|
+
this._authorization$.next(void 0);
|
|
5536
5800
|
await this.attachManager.detachAll();
|
|
5537
5801
|
}
|
|
5538
5802
|
async updateAuthState(authorization_state) {
|
|
5539
5803
|
try {
|
|
5540
5804
|
await this.storage.setItem(this.authorizationStateKey, authorization_state);
|
|
5541
5805
|
} catch (error) {
|
|
5542
|
-
logger$
|
|
5806
|
+
logger$7.error("Failed to update authorization state in storage:", error);
|
|
5543
5807
|
this._errors$.next(new require_operators.AuthStateHandlerError(error));
|
|
5544
5808
|
}
|
|
5545
5809
|
}
|
|
5546
|
-
async reauthenticate(token) {
|
|
5547
|
-
logger$
|
|
5810
|
+
async reauthenticate(token, dpopToken, options) {
|
|
5811
|
+
logger$7.debug("[Session] Re-authenticating session");
|
|
5548
5812
|
try {
|
|
5813
|
+
let resolvedDpopToken = dpopToken;
|
|
5814
|
+
if (!resolvedDpopToken && this.dpopManager?.initialized) try {
|
|
5815
|
+
resolvedDpopToken = await this.dpopManager.createRpcProof({ method: "signalwire.reauthenticate" });
|
|
5816
|
+
} catch (error) {
|
|
5817
|
+
if (this._clientBound) throw error;
|
|
5818
|
+
logger$7.warn("[Session] Failed to create DPoP proof for reauthenticate:", error);
|
|
5819
|
+
}
|
|
5549
5820
|
const request = RPCReauthenticate({
|
|
5550
5821
|
project: this._authorization$.value?.project_id ?? "",
|
|
5551
|
-
jwt_token: token
|
|
5822
|
+
jwt_token: token,
|
|
5823
|
+
...resolvedDpopToken ? { dpop_token: resolvedDpopToken } : {}
|
|
5552
5824
|
});
|
|
5553
5825
|
await (0, rxjs.lastValueFrom)((0, rxjs.from)(this.transport.execute(request)).pipe(require_operators.throwOnRPCError(), (0, rxjs.take)(1), (0, rxjs.catchError)((err) => {
|
|
5554
|
-
logger$
|
|
5826
|
+
logger$7.error("[Session] Re-authentication RPC failed:", err);
|
|
5555
5827
|
throw err;
|
|
5556
5828
|
})));
|
|
5557
|
-
|
|
5829
|
+
if (options?.clientBound) this._clientBound = true;
|
|
5830
|
+
logger$7.debug("[Session] Re-authentication successful, updating stored auth state");
|
|
5558
5831
|
} catch (error) {
|
|
5559
|
-
logger$
|
|
5832
|
+
logger$7.error("[Session] Re-authentication failed:", error);
|
|
5560
5833
|
this._errors$.next(new require_operators.AuthStateHandlerError(error));
|
|
5561
5834
|
throw error;
|
|
5562
5835
|
}
|
|
5563
5836
|
}
|
|
5564
5837
|
async authenticate() {
|
|
5565
|
-
logger$
|
|
5566
|
-
const params = {
|
|
5567
|
-
authentication: this.authentication,
|
|
5568
|
-
version: this.connectVersion,
|
|
5569
|
-
agent: this.agent,
|
|
5570
|
-
contexts: this.contexts,
|
|
5571
|
-
eventing: this.eventing,
|
|
5572
|
-
topics: this.topics,
|
|
5573
|
-
event_acks: this.eventAcks
|
|
5574
|
-
};
|
|
5838
|
+
logger$7.debug("[Session] Starting authentication process");
|
|
5575
5839
|
const persistedParams = await (0, rxjs.firstValueFrom)((0, rxjs.combineLatest)({
|
|
5576
5840
|
protocol: this.transport.protocol$,
|
|
5577
5841
|
authorization_state: this.authorizationState$
|
|
5578
5842
|
}).pipe((0, rxjs.take)(1)));
|
|
5579
|
-
logger$
|
|
5843
|
+
logger$7.debug("[Session] Persisted params:\n", {
|
|
5580
5844
|
protocol: persistedParams.protocol,
|
|
5581
5845
|
authStateLength: persistedParams.authorization_state?.length
|
|
5582
5846
|
});
|
|
5847
|
+
this.transport.resetSessionEpoch();
|
|
5848
|
+
const hasReconnectState = persistedParams.authorization_state && persistedParams.protocol;
|
|
5849
|
+
const storedToken = this.getCredential().token;
|
|
5850
|
+
const isReconnect = hasReconnectState && storedToken;
|
|
5851
|
+
let dpopToken;
|
|
5852
|
+
if (isReconnect) logger$7.debug("[Session] Reconnecting with stored jwt_token + authorization_state");
|
|
5853
|
+
else if (this.onBeforeReconnect && this._clientBound) {
|
|
5854
|
+
logger$7.debug("[Session] Refreshing credentials before fresh connect");
|
|
5855
|
+
await this.onBeforeReconnect();
|
|
5856
|
+
}
|
|
5857
|
+
if (this.dpopManager?.initialized) try {
|
|
5858
|
+
dpopToken = await this.dpopManager.createRpcProof({ method: "signalwire.connect" });
|
|
5859
|
+
} catch (error) {
|
|
5860
|
+
if (this._clientBound) throw error;
|
|
5861
|
+
logger$7.warn("[Session] Failed to create DPoP proof for connect, proceeding without:", error);
|
|
5862
|
+
}
|
|
5583
5863
|
const rpcConnectRequest = RPCConnect({
|
|
5584
|
-
|
|
5585
|
-
|
|
5864
|
+
authentication: isReconnect ? { jwt_token: storedToken } : this.authentication,
|
|
5865
|
+
version: this.connectVersion,
|
|
5866
|
+
agent: this.agent,
|
|
5867
|
+
contexts: this.contexts,
|
|
5868
|
+
eventing: this.eventing,
|
|
5869
|
+
topics: this.topics,
|
|
5870
|
+
event_acks: this.eventAcks,
|
|
5871
|
+
...dpopToken ? { dpop_token: dpopToken } : {},
|
|
5872
|
+
...isReconnect ? {
|
|
5873
|
+
authorization_state: persistedParams.authorization_state,
|
|
5874
|
+
protocol: persistedParams.protocol
|
|
5875
|
+
} : {}
|
|
5586
5876
|
});
|
|
5587
|
-
this.transport.resetSessionEpoch();
|
|
5588
5877
|
const response = await (0, rxjs.lastValueFrom)((0, rxjs.from)(this.transport.execute(rpcConnectRequest)).pipe(require_operators.throwOnRPCError(), (0, rxjs.map)((res) => res.result), (0, rxjs.filter)(isRPCConnectResult), (0, rxjs.tap)(() => {
|
|
5589
|
-
logger$
|
|
5878
|
+
logger$7.debug("[Session] Response passed filter, processing authentication result");
|
|
5590
5879
|
}), (0, rxjs.take)(1), (0, rxjs.catchError)((err) => {
|
|
5591
|
-
logger$
|
|
5880
|
+
logger$7.error("[Session] Authentication RPC failed:", err);
|
|
5592
5881
|
throw err;
|
|
5593
5882
|
})));
|
|
5594
|
-
logger$
|
|
5883
|
+
logger$7.debug("[Session] Processing authentication result:", {
|
|
5595
5884
|
hasProtocol: !!response.protocol,
|
|
5596
5885
|
hasAuthorization: !!response.authorization,
|
|
5597
5886
|
hasIceServers: !!response.ice_servers
|
|
@@ -5600,7 +5889,7 @@ var ClientSessionManager = class extends Destroyable {
|
|
|
5600
5889
|
this._authorization$.next(response.authorization);
|
|
5601
5890
|
this._iceServers$.next(response.ice_servers ?? []);
|
|
5602
5891
|
this._authenticated$.next(true);
|
|
5603
|
-
logger$
|
|
5892
|
+
logger$7.debug("[Session] Authentication completed successfully");
|
|
5604
5893
|
}
|
|
5605
5894
|
async disconnect() {
|
|
5606
5895
|
this.transport.disconnect();
|
|
@@ -5640,7 +5929,7 @@ var ClientSessionManager = class extends Destroyable {
|
|
|
5640
5929
|
});
|
|
5641
5930
|
return callSession;
|
|
5642
5931
|
} catch (error) {
|
|
5643
|
-
logger$
|
|
5932
|
+
logger$7.error("[Session] Error creating outbound call:", error);
|
|
5644
5933
|
callSession?.destroy();
|
|
5645
5934
|
const callError = new require_operators.CallCreateError(error instanceof rxjs.TimeoutError ? "Call create timeout" : "Call creation failed", error, "outbound");
|
|
5646
5935
|
this._errors$.next(callError);
|
|
@@ -5657,8 +5946,8 @@ var ClientSessionManager = class extends Destroyable {
|
|
|
5657
5946
|
if (!addressId) throw new require_operators.DependencyError(`Address name: ${addressURI} not found`);
|
|
5658
5947
|
address = this._directory.get(addressId);
|
|
5659
5948
|
if (!address) throw new require_operators.DependencyError(`Address ID: ${addressId} not found`);
|
|
5660
|
-
} catch
|
|
5661
|
-
logger$
|
|
5949
|
+
} catch {
|
|
5950
|
+
logger$7.warn(`[Session] Directory lookup failed for ${addressURI}, proceeding with raw URI`);
|
|
5662
5951
|
}
|
|
5663
5952
|
const callSession = this.callFactory.createCall(address, { ...options });
|
|
5664
5953
|
callSession.status$.pipe((0, rxjs.filter)((status) => status === "destroyed"), (0, rxjs.take)(1)).subscribe(() => {
|
|
@@ -5667,7 +5956,7 @@ var ClientSessionManager = class extends Destroyable {
|
|
|
5667
5956
|
});
|
|
5668
5957
|
return callSession;
|
|
5669
5958
|
} catch (error) {
|
|
5670
|
-
logger$
|
|
5959
|
+
logger$7.error("[Session] Error creating call session:", error);
|
|
5671
5960
|
throw new require_operators.CallCreateError("Call create error", error, options.initOffer ? "inbound" : "outbound");
|
|
5672
5961
|
}
|
|
5673
5962
|
}
|
|
@@ -5715,7 +6004,7 @@ const isString = (obj) => typeof obj === "string";
|
|
|
5715
6004
|
|
|
5716
6005
|
//#endregion
|
|
5717
6006
|
//#region src/managers/ConversationsManager.ts
|
|
5718
|
-
const logger$
|
|
6007
|
+
const logger$6 = require_operators.getLogger();
|
|
5719
6008
|
var ConversationMessagesFetcher = class extends Fetcher {
|
|
5720
6009
|
constructor(groupId, http) {
|
|
5721
6010
|
super(`/api/fabric/conversations/${groupId}/messages`, "page_size=100", http);
|
|
@@ -5755,13 +6044,13 @@ var ConversationsManager = class {
|
|
|
5755
6044
|
}
|
|
5756
6045
|
throw new require_operators.ConversationError("Join Failed - Unexpected response");
|
|
5757
6046
|
} catch (error) {
|
|
5758
|
-
logger$
|
|
6047
|
+
logger$6.error("[ConversationsManager] Failed to join conversation:", error);
|
|
5759
6048
|
throw error;
|
|
5760
6049
|
}
|
|
5761
6050
|
}
|
|
5762
6051
|
async getConversationMessageCollection(addressId) {
|
|
5763
6052
|
const groupId = this.groupIds.get(addressId) ?? await this.join(addressId);
|
|
5764
|
-
return Promise.resolve(new ConversationMessageCollection(groupId, this.clientSession.signalingEvent$.pipe(require_operators.filterAs(isConversationMessageMetadata, "params"), (0, rxjs.tap)((event) => logger$
|
|
6053
|
+
return Promise.resolve(new ConversationMessageCollection(groupId, this.clientSession.signalingEvent$.pipe(require_operators.filterAs(isConversationMessageMetadata, "params"), (0, rxjs.tap)((event) => logger$6.debug("[ConversationsManager ] Conversation Event:", event)), (0, rxjs.map)((params) => ({ ...params }))), this.http, this.onError));
|
|
5765
6054
|
}
|
|
5766
6055
|
async sendText(text, destinationAddressId) {
|
|
5767
6056
|
const groupId = this.groupIds.get(destinationAddressId) ?? await this.join(destinationAddressId);
|
|
@@ -5778,8 +6067,207 @@ var ConversationsManager = class {
|
|
|
5778
6067
|
})).ok) return;
|
|
5779
6068
|
throw new require_operators.ConversationError("Send Text Failed - Unexpected response");
|
|
5780
6069
|
} catch (error) {
|
|
5781
|
-
logger$
|
|
6070
|
+
logger$6.error("[ConversationsManager] Failed to send text message:", error);
|
|
6071
|
+
}
|
|
6072
|
+
}
|
|
6073
|
+
};
|
|
6074
|
+
|
|
6075
|
+
//#endregion
|
|
6076
|
+
//#region src/managers/DeviceTokenManager.ts
|
|
6077
|
+
const logger$5 = require_operators.getLogger();
|
|
6078
|
+
/**
|
|
6079
|
+
* Resolves the token expiry timestamp (epoch seconds) using a 3-tier priority chain:
|
|
6080
|
+
* 1. `data.expires_at` — server-provided absolute timestamp
|
|
6081
|
+
* 2. `data.expires_in` — server-provided relative lifetime
|
|
6082
|
+
* 3. Fallback to `DEVICE_TOKEN_DEFAULT_EXPIRE_IN` with a warning
|
|
6083
|
+
*/
|
|
6084
|
+
function resolveExpiresAt(data) {
|
|
6085
|
+
if (data.expires_at) return data.expires_at;
|
|
6086
|
+
if (data.expires_in) return Math.floor(Date.now() / 1e3) + data.expires_in;
|
|
6087
|
+
logger$5.warn("[DeviceToken] Could not determine token expiry, using default");
|
|
6088
|
+
return Math.floor(Date.now() / 1e3) + DEVICE_TOKEN_DEFAULT_EXPIRE_IN;
|
|
6089
|
+
}
|
|
6090
|
+
/**
|
|
6091
|
+
* Resolves the token TTL in seconds from a fresh response.
|
|
6092
|
+
* Called at token receive time so `expires_at - now` reflects the original lifetime.
|
|
6093
|
+
*
|
|
6094
|
+
* 1. `data.expires_in` — server-provided TTL directly
|
|
6095
|
+
* 2. `data.expires_at - now` — derive TTL from absolute timestamp
|
|
6096
|
+
* 3. Fallback to `DEVICE_TOKEN_DEFAULT_EXPIRE_IN`
|
|
6097
|
+
*/
|
|
6098
|
+
function resolveExpireIn(data) {
|
|
6099
|
+
if (data.expires_in) return data.expires_in;
|
|
6100
|
+
if (data.expires_at) return Math.max(data.expires_at - Math.floor(Date.now() / 1e3), 1);
|
|
6101
|
+
return DEVICE_TOKEN_DEFAULT_EXPIRE_IN;
|
|
6102
|
+
}
|
|
6103
|
+
/**
|
|
6104
|
+
* Manages the Client Bound SAT lifecycle: activation, token exchange,
|
|
6105
|
+
* reauthentication, and automatic refresh scheduling.
|
|
6106
|
+
*
|
|
6107
|
+
* Extends {@link Destroyable} for automatic RxJS subscription and subject cleanup.
|
|
6108
|
+
* Uses a reactive pipeline (`BehaviorSubject` + `switchMap(timer())`) instead of
|
|
6109
|
+
* raw `setTimeout` for refresh scheduling.
|
|
6110
|
+
*/
|
|
6111
|
+
var DeviceTokenManager = class extends Destroyable {
|
|
6112
|
+
constructor(dpopManager, http, errorHandler, getCredential) {
|
|
6113
|
+
super();
|
|
6114
|
+
this.dpopManager = dpopManager;
|
|
6115
|
+
this.http = http;
|
|
6116
|
+
this.errorHandler = errorHandler;
|
|
6117
|
+
this.getCredential = getCredential;
|
|
6118
|
+
this._currentToken$ = this.createBehaviorSubject(null);
|
|
6119
|
+
this._refreshInProgress = false;
|
|
6120
|
+
this._effectiveExpireIn = DEVICE_TOKEN_DEFAULT_EXPIRE_IN;
|
|
6121
|
+
this.subscribeTo(this._currentToken$.pipe((0, rxjs.filter)(Boolean), (0, rxjs.switchMap)((tokenData) => {
|
|
6122
|
+
const expiresAt = resolveExpiresAt(tokenData);
|
|
6123
|
+
const refreshIn = Math.max(expiresAt * 1e3 - Date.now() - DEVICE_TOKEN_REFRESH_BUFFER_MS, 1e3);
|
|
6124
|
+
logger$5.debug(`[DeviceToken] Scheduling Client Bound SAT refresh in ${refreshIn}ms`);
|
|
6125
|
+
return (0, rxjs.timer)(refreshIn);
|
|
6126
|
+
})), () => {
|
|
6127
|
+
this.executeRefresh();
|
|
6128
|
+
});
|
|
6129
|
+
}
|
|
6130
|
+
/**
|
|
6131
|
+
* Activates the Client Bound SAT flow when the subscriber's token has
|
|
6132
|
+
* `sat:refresh` scope.
|
|
6133
|
+
*
|
|
6134
|
+
* Steps:
|
|
6135
|
+
* 1. Check subscriber's `sat_claims` for `sat:refresh` scope
|
|
6136
|
+
* 2. Call `/api/fabric/subscriber/devices/token` with a DPoP proof
|
|
6137
|
+
* 3. Reauthenticate the session with the Client Bound SAT + DPoP proof
|
|
6138
|
+
* 4. Emit token to trigger the reactive refresh pipeline
|
|
6139
|
+
*/
|
|
6140
|
+
async activate(subscriber, session, updateCredential) {
|
|
6141
|
+
const { satClaims } = subscriber;
|
|
6142
|
+
if (!satClaims?.scope?.includes(SAT_REFRESH_SCOPE)) {
|
|
6143
|
+
logger$5.debug("[DeviceToken] No sat:refresh scope, skipping Client Bound SAT activation");
|
|
6144
|
+
return;
|
|
6145
|
+
}
|
|
6146
|
+
this._session = session;
|
|
6147
|
+
this._updateCredential = updateCredential;
|
|
6148
|
+
try {
|
|
6149
|
+
const tokenData = await this.obtainToken();
|
|
6150
|
+
if (!tokenData.expires_at && !tokenData.expires_in && satClaims.expires_at) tokenData.expires_at = satClaims.expires_at;
|
|
6151
|
+
this._effectiveExpireIn = resolveExpireIn(tokenData);
|
|
6152
|
+
const rpcProof = await this.dpopManager.createRpcProof({ method: "signalwire.reauthenticate" });
|
|
6153
|
+
await session.reauthenticate(tokenData.token, rpcProof, { clientBound: true });
|
|
6154
|
+
updateCredential({ token: tokenData.token });
|
|
6155
|
+
logger$5.info("[DeviceToken] Client Bound SAT activated successfully");
|
|
6156
|
+
this._currentToken$.next(tokenData);
|
|
6157
|
+
} catch (error) {
|
|
6158
|
+
logger$5.error("[DeviceToken] Failed to activate Client Bound SAT:", error);
|
|
6159
|
+
this.errorHandler(new require_operators.DPoPInitError(error, "Failed to activate Client Bound SAT"));
|
|
6160
|
+
}
|
|
6161
|
+
}
|
|
6162
|
+
/**
|
|
6163
|
+
* Obtains a Client Bound SAT from `/api/fabric/subscriber/devices/token`.
|
|
6164
|
+
* Returns the full {@link DeviceTokenResponse} including expiry metadata.
|
|
6165
|
+
*/
|
|
6166
|
+
async obtainToken() {
|
|
6167
|
+
const dpopProof = await this.dpopManager.createHttpProof({
|
|
6168
|
+
method: "POST",
|
|
6169
|
+
uri: DEVICE_TOKEN_ENDPOINT
|
|
6170
|
+
});
|
|
6171
|
+
const response = await this.http.request({
|
|
6172
|
+
url: DEVICE_TOKEN_ENDPOINT,
|
|
6173
|
+
...POST_PARAMS,
|
|
6174
|
+
body: JSON.stringify({
|
|
6175
|
+
dpop_token: dpopProof,
|
|
6176
|
+
expire_in: DEVICE_TOKEN_DEFAULT_EXPIRE_IN
|
|
6177
|
+
})
|
|
6178
|
+
});
|
|
6179
|
+
if (!response.ok || !response.body) throw new require_operators.DeviceTokenError(`Failed to obtain device token: ${response.status} ${response.statusText}`);
|
|
6180
|
+
const data = JSON.parse(response.body);
|
|
6181
|
+
if (!data.token) throw new require_operators.DeviceTokenError("Device token response missing token field");
|
|
6182
|
+
return data;
|
|
6183
|
+
}
|
|
6184
|
+
/**
|
|
6185
|
+
* Refreshes the Client Bound SAT via `/api/fabric/subscriber/devices/refresh`.
|
|
6186
|
+
*
|
|
6187
|
+
* Creates a fresh DPoP proof, calls the refresh endpoint, reauthenticates
|
|
6188
|
+
* the WebSocket session, and returns the new token data (scheduling is
|
|
6189
|
+
* handled by the reactive pipeline).
|
|
6190
|
+
*/
|
|
6191
|
+
async refreshToken(session, currentToken, updateCredential) {
|
|
6192
|
+
logger$5.debug("[DeviceToken] Refreshing Client Bound SAT");
|
|
6193
|
+
const dpopProof = await this.dpopManager.createHttpProof({
|
|
6194
|
+
method: "POST",
|
|
6195
|
+
uri: DEVICE_REFRESH_ENDPOINT,
|
|
6196
|
+
accessToken: currentToken
|
|
6197
|
+
});
|
|
6198
|
+
const response = await this.http.request({
|
|
6199
|
+
url: DEVICE_REFRESH_ENDPOINT,
|
|
6200
|
+
...POST_PARAMS,
|
|
6201
|
+
body: JSON.stringify({
|
|
6202
|
+
dpop_token: dpopProof,
|
|
6203
|
+
expire_in: this._effectiveExpireIn
|
|
6204
|
+
})
|
|
6205
|
+
});
|
|
6206
|
+
if (!response.ok || !response.body) throw new require_operators.TokenRefreshError(`Failed to refresh device token: ${response.status} ${response.statusText}`);
|
|
6207
|
+
const data = JSON.parse(response.body);
|
|
6208
|
+
if (!data.token) throw new require_operators.TokenRefreshError("Device token refresh response missing token field");
|
|
6209
|
+
if (!data.expires_at && !data.expires_in) data.expires_in = this._effectiveExpireIn;
|
|
6210
|
+
this._effectiveExpireIn = resolveExpireIn(data);
|
|
6211
|
+
const rpcProof = await this.dpopManager.createRpcProof({ method: "signalwire.reauthenticate" });
|
|
6212
|
+
await session.reauthenticate(data.token, rpcProof);
|
|
6213
|
+
updateCredential({ token: data.token });
|
|
6214
|
+
logger$5.info("[DeviceToken] Client Bound SAT refreshed successfully");
|
|
6215
|
+
return data;
|
|
6216
|
+
}
|
|
6217
|
+
/**
|
|
6218
|
+
* Executes a refresh with retry and exponential backoff.
|
|
6219
|
+
* On success, emits to `_currentToken$` to schedule the next refresh.
|
|
6220
|
+
* On all retries exhausted, emits to `errorHandler`.
|
|
6221
|
+
*/
|
|
6222
|
+
async executeRefresh() {
|
|
6223
|
+
if (this._refreshInProgress) {
|
|
6224
|
+
logger$5.debug("[DeviceToken] Refresh already in progress, skipping");
|
|
6225
|
+
return;
|
|
6226
|
+
}
|
|
6227
|
+
const session = this._session;
|
|
6228
|
+
const updateCredential = this._updateCredential;
|
|
6229
|
+
if (!session || !updateCredential) {
|
|
6230
|
+
logger$5.warn("[DeviceToken] Cannot refresh: session or updateCredential not set");
|
|
6231
|
+
return;
|
|
6232
|
+
}
|
|
6233
|
+
if (!session.authenticated) {
|
|
6234
|
+
logger$5.debug("[DeviceToken] Session not authenticated, deferring refresh");
|
|
6235
|
+
return;
|
|
6236
|
+
}
|
|
6237
|
+
this._refreshInProgress = true;
|
|
6238
|
+
try {
|
|
6239
|
+
const currentToken = this.getCredential().token;
|
|
6240
|
+
if (!currentToken) throw new require_operators.TokenRefreshError("No current token available for refresh");
|
|
6241
|
+
const newTokenData = await this.retryRefresh(session, currentToken, updateCredential);
|
|
6242
|
+
this._currentToken$.next(newTokenData);
|
|
6243
|
+
} catch (error) {
|
|
6244
|
+
logger$5.error("[DeviceToken] Automatic Client Bound SAT refresh failed:", error);
|
|
6245
|
+
this.errorHandler(error instanceof require_operators.TokenRefreshError ? error : new require_operators.TokenRefreshError("Automatic token refresh failed", error));
|
|
6246
|
+
} finally {
|
|
6247
|
+
this._refreshInProgress = false;
|
|
6248
|
+
}
|
|
6249
|
+
}
|
|
6250
|
+
/**
|
|
6251
|
+
* Retries `refreshToken()` up to `DEVICE_TOKEN_REFRESH_MAX_RETRIES` times
|
|
6252
|
+
* with exponential backoff (1s, 2s, 4s).
|
|
6253
|
+
*/
|
|
6254
|
+
async retryRefresh(session, currentToken, updateCredential) {
|
|
6255
|
+
let lastError;
|
|
6256
|
+
for (let attempt = 0; attempt < DEVICE_TOKEN_REFRESH_MAX_RETRIES; attempt++) try {
|
|
6257
|
+
return await this.refreshToken(session, currentToken, updateCredential);
|
|
6258
|
+
} catch (error) {
|
|
6259
|
+
lastError = error;
|
|
6260
|
+
if (attempt < DEVICE_TOKEN_REFRESH_MAX_RETRIES - 1) {
|
|
6261
|
+
const delay = DEVICE_TOKEN_REFRESH_RETRY_BASE_MS * Math.pow(2, attempt);
|
|
6262
|
+
logger$5.warn(`[DeviceToken] Refresh attempt ${attempt + 1} failed, retrying in ${delay}ms`);
|
|
6263
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
6264
|
+
}
|
|
5782
6265
|
}
|
|
6266
|
+
throw lastError instanceof Error ? lastError : new require_operators.TokenRefreshError("All refresh retries exhausted", lastError);
|
|
6267
|
+
}
|
|
6268
|
+
/** Cleans up the manager, cancelling the reactive pipeline and all subscriptions. */
|
|
6269
|
+
destroy() {
|
|
6270
|
+
super.destroy();
|
|
5783
6271
|
}
|
|
5784
6272
|
};
|
|
5785
6273
|
|
|
@@ -5949,6 +6437,10 @@ var WebSocketController = class WebSocketController extends Destroyable {
|
|
|
5949
6437
|
this.outgoingMessages$ = outgoingMessages$;
|
|
5950
6438
|
this.messageQueue = [];
|
|
5951
6439
|
this.shouldReconnect = false;
|
|
6440
|
+
this.boundHandleOpen = () => this.handleOpen();
|
|
6441
|
+
this.boundHandleClose = (event) => this.handleClose(event);
|
|
6442
|
+
this.boundHandleError = () => this.handleError();
|
|
6443
|
+
this.boundHandleMessage = (event) => this.handleMessage(event);
|
|
5952
6444
|
this._status$ = this.createBehaviorSubject("disconnected");
|
|
5953
6445
|
this._incomingMessages$ = this.createSubject();
|
|
5954
6446
|
this._errors$ = this.createReplaySubject(1);
|
|
@@ -6004,6 +6496,7 @@ var WebSocketController = class WebSocketController extends Destroyable {
|
|
|
6004
6496
|
}
|
|
6005
6497
|
createWebSocket() {
|
|
6006
6498
|
try {
|
|
6499
|
+
this.closeExistingSocket();
|
|
6007
6500
|
this.socket = new this.WebSocketConstructor(this.endpoint);
|
|
6008
6501
|
this.setupWebSocketListeners();
|
|
6009
6502
|
this.startConnectionTimeout();
|
|
@@ -6013,12 +6506,33 @@ var WebSocketController = class WebSocketController extends Destroyable {
|
|
|
6013
6506
|
this.handleConnectionError();
|
|
6014
6507
|
}
|
|
6015
6508
|
}
|
|
6509
|
+
/**
|
|
6510
|
+
* Closes the existing socket and removes its event listeners to prevent
|
|
6511
|
+
* phantom 'open'/'close' events from firing on the orphaned socket.
|
|
6512
|
+
*/
|
|
6513
|
+
closeExistingSocket() {
|
|
6514
|
+
if (!this.socket) return;
|
|
6515
|
+
const oldSocket = this.socket;
|
|
6516
|
+
this.socket = void 0;
|
|
6517
|
+
this.removeWebSocketListeners(oldSocket);
|
|
6518
|
+
try {
|
|
6519
|
+
oldSocket.close();
|
|
6520
|
+
} catch {}
|
|
6521
|
+
}
|
|
6016
6522
|
setupWebSocketListeners() {
|
|
6017
6523
|
if (!this.socket) return;
|
|
6018
|
-
this.socket.addEventListener("open",
|
|
6019
|
-
this.socket.addEventListener("close",
|
|
6020
|
-
this.socket.addEventListener("error",
|
|
6021
|
-
this.socket.addEventListener("message",
|
|
6524
|
+
this.socket.addEventListener("open", this.boundHandleOpen);
|
|
6525
|
+
this.socket.addEventListener("close", this.boundHandleClose);
|
|
6526
|
+
this.socket.addEventListener("error", this.boundHandleError);
|
|
6527
|
+
this.socket.addEventListener("message", this.boundHandleMessage);
|
|
6528
|
+
}
|
|
6529
|
+
removeWebSocketListeners(socket) {
|
|
6530
|
+
try {
|
|
6531
|
+
socket.removeEventListener("open", this.boundHandleOpen);
|
|
6532
|
+
socket.removeEventListener("close", this.boundHandleClose);
|
|
6533
|
+
socket.removeEventListener("error", this.boundHandleError);
|
|
6534
|
+
socket.removeEventListener("message", this.boundHandleMessage);
|
|
6535
|
+
} catch {}
|
|
6022
6536
|
}
|
|
6023
6537
|
handleOpen() {
|
|
6024
6538
|
this.clearConnectionTimeout();
|
|
@@ -6363,6 +6877,7 @@ var SignalWire = class extends Destroyable {
|
|
|
6363
6877
|
this._errors$ = this.createReplaySubject(1);
|
|
6364
6878
|
this._options = {};
|
|
6365
6879
|
this._deps = new DependencyContainer();
|
|
6880
|
+
this._credentialProvider = credentialProvider;
|
|
6366
6881
|
this._options = {
|
|
6367
6882
|
...PreferencesContainer.instance.defaultSignalWireOptions,
|
|
6368
6883
|
...options
|
|
@@ -6386,8 +6901,25 @@ var SignalWire = class extends Destroyable {
|
|
|
6386
6901
|
this._errors$.next(error instanceof Error ? error : new Error(String(error), { cause: error }));
|
|
6387
6902
|
});
|
|
6388
6903
|
}
|
|
6904
|
+
/**
|
|
6905
|
+
* Initializes DPoP if not already set up. Returns the fingerprint on success.
|
|
6906
|
+
*/
|
|
6907
|
+
async initDPoP() {
|
|
6908
|
+
if (this._dpopManager?.initialized) return this._dpopManager.fingerprint;
|
|
6909
|
+
try {
|
|
6910
|
+
this._dpopManager = new CryptoController();
|
|
6911
|
+
const fingerprint = await this._dpopManager.init();
|
|
6912
|
+
logger$1.debug("[SignalWire] DPoP initialized, fingerprint available");
|
|
6913
|
+
return fingerprint;
|
|
6914
|
+
} catch (error) {
|
|
6915
|
+
logger$1.warn("[SignalWire] DPoP initialization failed, proceeding without DPoP:", error);
|
|
6916
|
+
this._dpopManager = void 0;
|
|
6917
|
+
return;
|
|
6918
|
+
}
|
|
6919
|
+
}
|
|
6389
6920
|
async validateCredentials(credentialProvider, credentials) {
|
|
6390
|
-
const
|
|
6921
|
+
const fingerprint = await this.initDPoP();
|
|
6922
|
+
const _credentials = credentials ?? await credentialProvider.authenticate(fingerprint ? { fingerprint } : void 0);
|
|
6391
6923
|
if (_credentials.token) try {
|
|
6392
6924
|
const decodeHeader = (0, jwt_decode.jwtDecode)(_credentials.token, { header: true });
|
|
6393
6925
|
this._deps.ch = decodeHeader.ch;
|
|
@@ -6510,12 +7042,53 @@ var SignalWire = class extends Destroyable {
|
|
|
6510
7042
|
};
|
|
6511
7043
|
this._transport = new TransportManager(this._deps.storage, this._deps.protocolKey, this._deps.WebSocket, PreferencesContainer.instance.relayHost ?? this._deps.relayHost, errorHandler);
|
|
6512
7044
|
this._attachManager = new AttachManager(this._deps.storage, this._deps.deviceController, PreferencesContainer.instance.reconnectCallsTimeout, this._deps.attachedCallsKey);
|
|
6513
|
-
this._clientSession = new ClientSessionManager(this._deps.credential, this._transport, this._deps.storage, this._deps.authorizationStateKey, this._deps.deviceController, this._attachManager, this._deps.webRTCApiProvider);
|
|
7045
|
+
this._clientSession = new ClientSessionManager(() => this._deps.credential, this._transport, this._deps.storage, this._deps.authorizationStateKey, this._deps.deviceController, this._attachManager, this._deps.webRTCApiProvider, this._dpopManager);
|
|
6514
7046
|
this._publicSession = new ClientSessionWrapper(this._clientSession);
|
|
7047
|
+
this._clientSession.onBeforeReconnect = async () => {
|
|
7048
|
+
if (!this._credentialProvider) return;
|
|
7049
|
+
try {
|
|
7050
|
+
const fingerprint = this._dpopManager?.initialized ? this._dpopManager.fingerprint : void 0;
|
|
7051
|
+
logger$1.debug("[SignalWire] Credential expired, refreshing before reconnect");
|
|
7052
|
+
const newCredentials = await this._credentialProvider.authenticate(fingerprint ? { fingerprint } : void 0);
|
|
7053
|
+
this._deps.credential = newCredentials;
|
|
7054
|
+
logger$1.debug("[SignalWire] Credential refreshed successfully for reconnect");
|
|
7055
|
+
} catch (error) {
|
|
7056
|
+
logger$1.error("[SignalWire] Failed to refresh credentials for reconnect:", error);
|
|
7057
|
+
}
|
|
7058
|
+
};
|
|
6515
7059
|
this.subscribeTo(this._clientSession.errors$, (error) => {
|
|
6516
7060
|
this._errors$.next(error);
|
|
6517
7061
|
});
|
|
6518
7062
|
await this._clientSession.connect();
|
|
7063
|
+
if (this._dpopManager?.initialized) {
|
|
7064
|
+
if (this._refreshTimerId) {
|
|
7065
|
+
clearTimeout(this._refreshTimerId);
|
|
7066
|
+
this._refreshTimerId = void 0;
|
|
7067
|
+
logger$1.debug("[SignalWire] Developer refresh disabled — Client Bound SAT activation starting");
|
|
7068
|
+
}
|
|
7069
|
+
this._deviceTokenManager = new DeviceTokenManager(this._dpopManager, this._deps.http, (error) => this._errors$.next(error), () => this._deps.credential);
|
|
7070
|
+
await this._deviceTokenManager.activate(this._deps.subscriber, this._clientSession, (cred) => {
|
|
7071
|
+
this._deps.credential = {
|
|
7072
|
+
...this._deps.credential,
|
|
7073
|
+
...cred
|
|
7074
|
+
};
|
|
7075
|
+
});
|
|
7076
|
+
this.subscribeTo(this._clientSession.authenticated$.pipe((0, rxjs.skip)(1), (0, rxjs.filter)(Boolean)), () => {
|
|
7077
|
+
logger$1.debug("[SignalWire] Re-activating Client Bound SAT after reconnect");
|
|
7078
|
+
this._deviceTokenManager?.activate(this._deps.subscriber, this._clientSession, (cred) => {
|
|
7079
|
+
this._deps.credential = {
|
|
7080
|
+
...this._deps.credential,
|
|
7081
|
+
...cred
|
|
7082
|
+
};
|
|
7083
|
+
});
|
|
7084
|
+
logger$1.debug("[SignalWire] Re-registering subscriber after reconnect");
|
|
7085
|
+
this.register().then(() => {
|
|
7086
|
+
logger$1.debug("[SignalWire] Subscriber re-registered successfully after reconnect");
|
|
7087
|
+
}).catch((error) => {
|
|
7088
|
+
logger$1.error("[SignalWire] Re-registration failed after reconnect:", error);
|
|
7089
|
+
});
|
|
7090
|
+
});
|
|
7091
|
+
}
|
|
6519
7092
|
const conversationManager = new ConversationsManager(this._clientSession, this._deps.http, () => this._deps.getSubscriberFromAddressId(), errorHandler);
|
|
6520
7093
|
const directory = new DirectoryManager(this._deps.http, this._clientSession, conversationManager, errorHandler);
|
|
6521
7094
|
this._directory$.next(directory);
|
|
@@ -6793,6 +7366,8 @@ var SignalWire = class extends Destroyable {
|
|
|
6793
7366
|
clearTimeout(this._refreshTimerId);
|
|
6794
7367
|
this._refreshTimerId = void 0;
|
|
6795
7368
|
}
|
|
7369
|
+
this._deviceTokenManager?.destroy();
|
|
7370
|
+
this._dpopManager?.destroy();
|
|
6796
7371
|
super.destroy();
|
|
6797
7372
|
}
|
|
6798
7373
|
};
|
|
@@ -6919,6 +7494,8 @@ exports.Address = Address;
|
|
|
6919
7494
|
exports.CallCreateError = require_operators.CallCreateError;
|
|
6920
7495
|
exports.ClientPreferences = ClientPreferences;
|
|
6921
7496
|
exports.CollectionFetchError = require_operators.CollectionFetchError;
|
|
7497
|
+
exports.DPoPInitError = require_operators.DPoPInitError;
|
|
7498
|
+
exports.DeviceTokenError = require_operators.DeviceTokenError;
|
|
6922
7499
|
exports.InvalidCredentialsError = require_operators.InvalidCredentialsError;
|
|
6923
7500
|
exports.MediaTrackError = require_operators.MediaTrackError;
|
|
6924
7501
|
exports.MessageParseError = require_operators.MessageParseError;
|
|
@@ -6928,6 +7505,7 @@ exports.SelfParticipant = SelfParticipant;
|
|
|
6928
7505
|
exports.SignalWire = SignalWire;
|
|
6929
7506
|
exports.StaticCredentialProvider = StaticCredentialProvider;
|
|
6930
7507
|
exports.Subscriber = Subscriber;
|
|
7508
|
+
exports.TokenRefreshError = require_operators.TokenRefreshError;
|
|
6931
7509
|
exports.UnexpectedError = require_operators.UnexpectedError;
|
|
6932
7510
|
exports.VertoPongError = require_operators.VertoPongError;
|
|
6933
7511
|
exports.WebRTCCall = WebRTCCall;
|