@signalwire/js 4.0.0-rc.3 → 4.0.0-rc.4

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/index.cjs CHANGED
@@ -1,4 +1,4 @@
1
- const require_operators = require('./operators-BJ6QW1VP.cjs');
1
+ const require_operators = require('./operators-IoitK-As.cjs');
2
2
  let jwt_decode = require("jwt-decode");
3
3
  let rxjs = require("rxjs");
4
4
  let uuid = require("uuid");
@@ -2589,6 +2589,12 @@ const RPCReauthenticate = (params) => {
2589
2589
 
2590
2590
  //#endregion
2591
2591
  //#region src/core/RPCMessages/RPCPing.ts
2592
+ const RPCPing = () => {
2593
+ return buildRPCRequest({
2594
+ method: "signalwire.ping",
2595
+ params: { timestamp: Date.now() / 1e3 }
2596
+ });
2597
+ };
2592
2598
  const RPCPingResponse = (id, timestamp) => {
2593
2599
  return makeRPCResponse({
2594
2600
  id,
@@ -6451,6 +6457,7 @@ var WebRTCVertoManager = class extends VertoManager {
6451
6457
  this._signalingStatus$ = this.createReplaySubject(1);
6452
6458
  this._screenShareStatus$ = this.createBehaviorSubject("none");
6453
6459
  this._rtcPeerConnectionsMap = /* @__PURE__ */ new Map();
6460
+ this._lastVertoPings = /* @__PURE__ */ new Map();
6454
6461
  this._legErrors$ = this.createSubject();
6455
6462
  this._nodeId$ = this.createBehaviorSubject(options.nodeId ?? null);
6456
6463
  this.onError = options.onError;
@@ -6566,9 +6573,13 @@ var WebRTCVertoManager = class extends VertoManager {
6566
6573
  this.applyServerMediaParams(rtcPeerConnController, audio, video);
6567
6574
  });
6568
6575
  this.subscribeTo(this.vertoPing$, (vertoPing) => {
6576
+ this._lastVertoPings.set(vertoPing.callID, vertoPing);
6569
6577
  this.attachManager.refresh(this.buildAttachableCall());
6570
6578
  this.sendVertoPong(vertoPing);
6571
6579
  });
6580
+ this.subscribeTo(this.webRtcCallSession.clientSession.authenticated$.pipe((0, rxjs.skip)(1), (0, rxjs.filter)(Boolean)), () => {
6581
+ this._lastVertoPings.forEach((vertoPing) => void this.sendVertoPong(vertoPing));
6582
+ });
6572
6583
  }
6573
6584
  /**
6574
6585
  * An auxiliary-leg failure must never destroy the call; main-leg and
@@ -10103,6 +10114,10 @@ var ClientSessionManager = class extends Destroyable {
10103
10114
  await (0, rxjs.firstValueFrom)(this.authenticated$.pipe((0, rxjs.takeUntil)(this.destroyed$), (0, rxjs.filter)(Boolean), (0, rxjs.take)(1), (0, rxjs.timeout)({ first: 15e3 })));
10104
10115
  }
10105
10116
  async handleAuthenticationError(error) {
10117
+ if (error instanceof require_operators.TransportConnectionError) {
10118
+ logger$9.debug("[Session] Socket closed during authentication, waiting for reconnect");
10119
+ return;
10120
+ }
10106
10121
  logger$9.error("Authentication error:", error);
10107
10122
  const isRecoverableAuthError$1 = error instanceof require_operators.JSONRPCError && (error.code === require_operators.RPC_ERROR_REQUESTER_VALIDATION_FAILED || error.code === require_operators.RPC_ERROR_INVALID_PARAMS || error.code === require_operators.RPC_ERROR_AUTHENTICATION_FAILED);
10108
10123
  const hasStoredState = await (0, rxjs.firstValueFrom)(this.authorizationState$.pipe((0, rxjs.take)(1))) !== void 0;
@@ -10242,7 +10257,9 @@ var ClientSessionManager = class extends Destroyable {
10242
10257
  protocol: persistedParams.protocol
10243
10258
  } : {}
10244
10259
  });
10245
- 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)(() => {
10260
+ if (this.transport.connectionStatus !== "connected") throw new require_operators.TransportConnectionError("WebSocket closed during authentication");
10261
+ const socketClosed$ = this.transport.connectionStatus$.pipe((0, rxjs.skip)(1), (0, rxjs.filter)((status) => status === "reconnecting" || status === "disconnected"), (0, rxjs.take)(1), (0, rxjs.switchMap)(() => (0, rxjs.throwError)(() => new require_operators.TransportConnectionError("WebSocket closed during authentication"))));
10262
+ const response = await (0, rxjs.lastValueFrom)((0, rxjs.race)((0, rxjs.from)(this.transport.execute(rpcConnectRequest)), socketClosed$).pipe(require_operators.throwOnRPCError(), (0, rxjs.map)((res) => res.result), (0, rxjs.filter)(isRPCConnectResult), (0, rxjs.tap)(() => {
10246
10263
  logger$9.debug("[Session] Response passed filter, processing authentication result");
10247
10264
  }), (0, rxjs.take)(1), (0, rxjs.catchError)((err) => {
10248
10265
  logger$9.error("[Session] Authentication RPC failed:", err);
@@ -10257,6 +10274,7 @@ var ClientSessionManager = class extends Destroyable {
10257
10274
  this._authorization$.next(response.authorization);
10258
10275
  if (response.authorization.cnf?.jkt) this._wasClientBound = true;
10259
10276
  this._iceServers$.next(response.ice_servers ?? []);
10277
+ this.transport.setAuthenticated();
10260
10278
  this._authState$.next({ kind: "authenticated" });
10261
10279
  logger$9.debug("[Session] Authentication completed successfully");
10262
10280
  }
@@ -11449,6 +11467,7 @@ var WebSocketController = class WebSocketController extends Destroyable {
11449
11467
  }
11450
11468
  handleClose(_event) {
11451
11469
  this.clearConnectionTimeout();
11470
+ this.messageQueue = [];
11452
11471
  if (this.shouldReconnect) {
11453
11472
  this._status$.next("reconnecting");
11454
11473
  this.scheduleReconnection();
@@ -11518,6 +11537,9 @@ var WebSocketController = class WebSocketController extends Destroyable {
11518
11537
  function isSignalwirePingRequest(value) {
11519
11538
  return isJSONRPCRequest(value) && value.method === "signalwire.ping";
11520
11539
  }
11540
+ function isSignalwireConnectRequest(value) {
11541
+ return isJSONRPCRequest(value) && value.method === "signalwire.connect";
11542
+ }
11521
11543
 
11522
11544
  //#endregion
11523
11545
  //#region src/managers/TransportManager.ts
@@ -11531,6 +11553,10 @@ var TransportManager = class extends Destroyable {
11531
11553
  this.protocol$ = this.createReplaySubject(1);
11532
11554
  this.isConnecting = false;
11533
11555
  this.isConnected = false;
11556
+ this.socketStatus = "disconnected";
11557
+ this.sessionAuthenticated = false;
11558
+ this.heldRequests = [];
11559
+ this.serverPingWatch = 0;
11534
11560
  this.ackEvent = () => {
11535
11561
  return (0, rxjs.tap)((message) => {
11536
11562
  if (isSignalwireRequest(message)) try {
@@ -11546,6 +11572,7 @@ var TransportManager = class extends Destroyable {
11546
11572
  if (isSignalwirePingRequest(message)) {
11547
11573
  try {
11548
11574
  logger$2.debug("[Transport] Received ping, sending pong", { pingId: message.id });
11575
+ if (this.sessionAuthenticated) this.armServerPingWatchdog();
11549
11576
  this.send(RPCPingResponse(message.id));
11550
11577
  } catch (error) {
11551
11578
  logger$2.error("[Transport] Failed to send ping response:", error);
@@ -11583,6 +11610,14 @@ var TransportManager = class extends Destroyable {
11583
11610
  this.subscribeTo(this._webSocketConnections.errors$, (error) => {
11584
11611
  this.onError?.(error);
11585
11612
  });
11613
+ this.subscribeTo(this._webSocketConnections.status$, (status) => {
11614
+ this.socketStatus = status;
11615
+ if (status !== "connected") {
11616
+ this.sessionAuthenticated = false;
11617
+ this.clearServerPingWatchdog();
11618
+ }
11619
+ if (status === "disconnected") this.heldRequests = [];
11620
+ });
11586
11621
  this.initialized$ = (0, rxjs.defer)(() => (0, rxjs.from)(this._init())).pipe((0, rxjs.shareReplay)(1), (0, rxjs.takeUntil)(this.destroyed$));
11587
11622
  this._jsonRPCMessage$ = this._webSocketConnections.incomingMessages$.pipe((0, rxjs.map)((event) => {
11588
11623
  try {
@@ -11611,6 +11646,9 @@ var TransportManager = class extends Destroyable {
11611
11646
  get connectionStatus$() {
11612
11647
  return this._webSocketConnections.status$;
11613
11648
  }
11649
+ get connectionStatus() {
11650
+ return this.socketStatus;
11651
+ }
11614
11652
  async connect() {
11615
11653
  if (this.isConnecting || this.isConnected) {
11616
11654
  logger$2.warn("[Transport] Already connecting or connected");
@@ -11655,16 +11693,45 @@ var TransportManager = class extends Destroyable {
11655
11693
  }
11656
11694
  async execute(request, options) {
11657
11695
  this.send(request);
11658
- return new PendingRPC(request, this._jsonRPCResponse$, options).promise;
11696
+ const pending = new PendingRPC(request, this._jsonRPCResponse$, options).promise;
11697
+ pending.catch(() => {
11698
+ this.heldRequests = this.heldRequests.filter((held) => held.id !== request.id);
11699
+ });
11700
+ return pending;
11659
11701
  }
11660
11702
  send(message) {
11661
11703
  const payload = JSON.stringify(message);
11704
+ if (isJSONRPCResponse(message)) {
11705
+ if (this.socketStatus !== "connected") {
11706
+ logger$2.debug("[Transport] Dropping response while disconnected", { id: message.id });
11707
+ return;
11708
+ }
11709
+ } else if (!this.sessionAuthenticated && !isSignalwireConnectRequest(message)) {
11710
+ this.heldRequests.push({
11711
+ id: message.id,
11712
+ payload
11713
+ });
11714
+ return;
11715
+ }
11662
11716
  this._outgoingMessages$.next(payload);
11663
11717
  }
11718
+ /**
11719
+ * Called by the session when signalwire.connect succeeds on the current
11720
+ * socket. Sends the requests held since the socket opened, in order.
11721
+ */
11722
+ setAuthenticated() {
11723
+ if (this.socketStatus !== "connected") return;
11724
+ this.sessionAuthenticated = true;
11725
+ this.armServerPingWatchdog();
11726
+ const held = this.heldRequests;
11727
+ this.heldRequests = [];
11728
+ held.forEach(({ payload }) => this._outgoingMessages$.next(payload));
11729
+ }
11664
11730
  disconnect() {
11665
11731
  logger$2.debug("[Transport] Disconnecting");
11666
11732
  this.isConnected = false;
11667
11733
  this.isConnecting = false;
11734
+ this.clearServerPingWatchdog();
11668
11735
  this._webSocketConnections.disconnect();
11669
11736
  }
11670
11737
  destroy() {
@@ -11673,6 +11740,28 @@ var TransportManager = class extends Destroyable {
11673
11740
  super.destroy();
11674
11741
  this._webSocketConnections.destroy();
11675
11742
  }
11743
+ armServerPingWatchdog() {
11744
+ this.clearServerPingWatchdog();
11745
+ const watch = this.serverPingWatch;
11746
+ this.serverPingTimer = setTimeout(() => void this.probeServer(watch), require_operators.SERVER_PING_TIMEOUT_MS);
11747
+ }
11748
+ /** Bumps the watch so a probe still in flight no longer acts on its result. */
11749
+ clearServerPingWatchdog() {
11750
+ clearTimeout(this.serverPingTimer);
11751
+ this.serverPingTimer = void 0;
11752
+ this.serverPingWatch += 1;
11753
+ }
11754
+ async probeServer(watch) {
11755
+ logger$2.debug(`[Transport] No signalwire.ping for ${require_operators.SERVER_PING_TIMEOUT_MS}ms, probing the server`);
11756
+ try {
11757
+ await this.execute(RPCPing(), { timeoutMs: require_operators.SERVER_PING_PROBE_TIMEOUT_MS });
11758
+ if (watch === this.serverPingWatch) this.armServerPingWatchdog();
11759
+ } catch (error) {
11760
+ if (watch !== this.serverPingWatch) return;
11761
+ logger$2.warn("[Transport] Server did not answer the ping probe, replacing the socket", error);
11762
+ this.reconnect();
11763
+ }
11764
+ }
11676
11765
  async _loadProtocolFromStorage() {
11677
11766
  try {
11678
11767
  const storedProtocol = await this.storage.getItem(this.protocolKey);
@@ -12377,7 +12466,7 @@ var SignalWire = class extends Destroyable {
12377
12466
  logger$1.warn("[SignalWire] Failed to initialize VisibilityController:", error);
12378
12467
  }
12379
12468
  try {
12380
- this._diagnosticsCollector = new DiagnosticsCollector({ sdkVersion: "4.0.0-rc.3" });
12469
+ this._diagnosticsCollector = new DiagnosticsCollector({ sdkVersion: "4.0.0-rc.4" });
12381
12470
  } catch (error) {
12382
12471
  logger$1.warn("[SignalWire] Failed to initialize DiagnosticsCollector:", error);
12383
12472
  }
@@ -12931,7 +13020,7 @@ var StaticCredentialProvider = class {
12931
13020
  /**
12932
13021
  * Library version from package.json, injected at build time.
12933
13022
  */
12934
- const version = "4.0.0-rc.3";
13023
+ const version = "4.0.0-rc.4";
12935
13024
  /**
12936
13025
  * Flag indicating the library has been loaded and is ready to use.
12937
13026
  * For UMD builds: `window.SignalWire.ready`
@@ -12953,7 +13042,7 @@ const ready = true;
12953
13042
  */
12954
13043
  const emitReadyEvent = () => {
12955
13044
  if (typeof window !== "undefined") {
12956
- const event = new CustomEvent("signalwire:js:ready", { detail: { version: "4.0.0-rc.3" } });
13045
+ const event = new CustomEvent("signalwire:js:ready", { detail: { version: "4.0.0-rc.4" } });
12957
13046
  window.dispatchEvent(event);
12958
13047
  }
12959
13048
  };