@signalwire/js 4.0.0-beta.8 → 4.0.0-beta.9

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.
@@ -14,17 +14,18 @@ interface JSONRPCSuccessResponse<TResult = unknown> {
14
14
  result: TResult;
15
15
  error?: never;
16
16
  }
17
+ interface TError {
18
+ code: string;
19
+ message: string;
20
+ data?: unknown;
21
+ }
17
22
  interface JSONRPCErrorResponse {
18
23
  jsonrpc: '2.0';
19
24
  id: string;
20
- result?: never;
21
- error: {
22
- code: number;
23
- message: string;
24
- data?: unknown;
25
- };
25
+ result?: TError;
26
+ error?: TError;
26
27
  }
27
28
  type JSONRPCResponse<TResult = unknown> = JSONRPCSuccessResponse<TResult> | JSONRPCErrorResponse;
28
29
  //#endregion
29
30
  export { JSONRPCSuccessResponse as a, JSONRPCResponse as i, JSONRPCErrorResponse as n, JSONRPCRequest as r, EventChannel as t };
30
- //# sourceMappingURL=base-BxFSgMTI.d.cts.map
31
+ //# sourceMappingURL=base-CQPEW1lJ.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base-CQPEW1lJ.d.mts","names":[],"sources":["../src/core/RPCMessages/types/base.ts"],"sourcesContent":[],"mappings":";KAUY,YAAA;AAOA,KAAA,cAAA,GAAc,KAAA;AACd,KAAA,aAAA,GAAa,MAAA;AAER,UAAA,cAAc,CAAA,UAAA,OAAA,CAAA,CAAA;EACpB,OAAA,EAAA,cAAA;EAED,EAAA,EAAA,MAAA;EACC,MAAA,EADD,aACC;EAAO,MAAA,CAAA,EAAP,OAAO;AAGlB;AAOiB,UAPA,sBAOM,CAAA,UAAA,OAAA,CAAA,CAAA;EAKN,OAAA,EAAA,KAAA;EAOL,EAAA,EAAA,MAAA;EACe,MAAA,EAjBjB,OAiBiB;EAAvB,KAAA,CAAA,EAAA,KAAA;;AACoB,UAdP,MAAA,CAcO;;;;;UATP,oBAAA;;;WAGN;UACD;;KAGE,qCACR,uBAAuB,WACvB"}
@@ -14,17 +14,18 @@ interface JSONRPCSuccessResponse<TResult = unknown> {
14
14
  result: TResult;
15
15
  error?: never;
16
16
  }
17
+ interface TError {
18
+ code: string;
19
+ message: string;
20
+ data?: unknown;
21
+ }
17
22
  interface JSONRPCErrorResponse {
18
23
  jsonrpc: '2.0';
19
24
  id: string;
20
- result?: never;
21
- error: {
22
- code: number;
23
- message: string;
24
- data?: unknown;
25
- };
25
+ result?: TError;
26
+ error?: TError;
26
27
  }
27
28
  type JSONRPCResponse<TResult = unknown> = JSONRPCSuccessResponse<TResult> | JSONRPCErrorResponse;
28
29
  //#endregion
29
30
  export { JSONRPCSuccessResponse as a, JSONRPCResponse as i, JSONRPCErrorResponse as n, JSONRPCRequest as r, EventChannel as t };
30
- //# sourceMappingURL=base-DKDZK4Rr.d.mts.map
31
+ //# sourceMappingURL=base-Cif20s3C.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base-Cif20s3C.d.cts","names":[],"sources":["../src/core/RPCMessages/types/base.ts"],"sourcesContent":[],"mappings":";KAUY,YAAA;AAOA,KAAA,cAAA,GAAc,KAAA;AACd,KAAA,aAAA,GAAa,MAAA;AAER,UAAA,cAAc,CAAA,UAAA,OAAA,CAAA,CAAA;EACpB,OAAA,EAAA,cAAA;EAED,EAAA,EAAA,MAAA;EACC,MAAA,EADD,aACC;EAAO,MAAA,CAAA,EAAP,OAAO;AAGlB;AAOiB,UAPA,sBAOM,CAAA,UAAA,OAAA,CAAA,CAAA;EAKN,OAAA,EAAA,KAAA;EAOL,EAAA,EAAA,MAAA;EACe,MAAA,EAjBjB,OAiBiB;EAAvB,KAAA,CAAA,EAAA,KAAA;;AACoB,UAdP,MAAA,CAcO;;;;;UATP,oBAAA;;;WAGN;UACD;;KAGE,qCACR,uBAAuB,WACvB"}
package/dist/browser.mjs CHANGED
@@ -2879,7 +2879,7 @@ var require_observeOn = /* @__PURE__ */ __commonJSMin(((exports) => {
2879
2879
  var executeSchedule_1$7 = require_executeSchedule();
2880
2880
  var lift_1$67 = require_lift();
2881
2881
  var OperatorSubscriber_1$56 = require_OperatorSubscriber();
2882
- function observeOn(scheduler, delay$1) {
2882
+ function observeOn$1(scheduler, delay$1) {
2883
2883
  if (delay$1 === void 0) delay$1 = 0;
2884
2884
  return lift_1$67.operate(function(source, subscriber) {
2885
2885
  source.subscribe(OperatorSubscriber_1$56.createOperatorSubscriber(subscriber, function(value) {
@@ -2897,7 +2897,7 @@ var require_observeOn = /* @__PURE__ */ __commonJSMin(((exports) => {
2897
2897
  }));
2898
2898
  });
2899
2899
  }
2900
- exports.observeOn = observeOn;
2900
+ exports.observeOn = observeOn$1;
2901
2901
  }));
2902
2902
 
2903
2903
  //#endregion
@@ -8956,6 +8956,40 @@ var Destroyable = class {
8956
8956
  }
8957
8957
  return cached;
8958
8958
  }
8959
+ /**
8960
+ * Like `cachedObservable`, but defers emissions to the microtask queue
8961
+ * via `observeOn(asapScheduler)`.
8962
+ *
8963
+ * Use ONLY for public-facing observable getters that external consumers
8964
+ * subscribe to. Prevents a class of bugs where `BehaviorSubject` or
8965
+ * `ReplaySubject` replays synchronously during `subscribe()`, before
8966
+ * the subscription variable is assigned in the caller's scope.
8967
+ *
8968
+ * Do NOT use for observables consumed internally by the SDK — internal
8969
+ * code using `subscribeTo()`, `firstValueFrom()`, or `withLatestFrom()`
8970
+ * depends on synchronous emission delivery.
8971
+ */
8972
+ publicCachedObservable(key, factory) {
8973
+ const publicKey = `public:${key}`;
8974
+ this._observableCache ??= /* @__PURE__ */ new Map();
8975
+ let cached = this._observableCache.get(publicKey);
8976
+ if (!cached) {
8977
+ cached = factory().pipe((0, import_cjs$22.observeOn)(import_cjs$22.asapScheduler));
8978
+ this._observableCache.set(publicKey, cached);
8979
+ }
8980
+ return cached;
8981
+ }
8982
+ /**
8983
+ * Wraps an observable so emissions are deferred to the microtask queue.
8984
+ *
8985
+ * Use ONLY for public-facing getters that expose a subject via
8986
+ * `.asObservable()` without going through `cachedObservable`.
8987
+ *
8988
+ * Do NOT use for observables consumed internally by the SDK.
8989
+ */
8990
+ deferEmission(observable) {
8991
+ return observable.pipe((0, import_cjs$22.observeOn)(import_cjs$22.asapScheduler));
8992
+ }
8959
8993
  subscribeTo(observable, observerOrNext) {
8960
8994
  const subscription = observable.subscribe(observerOrNext);
8961
8995
  this.subscriptions.push(subscription);
@@ -9116,20 +9150,12 @@ var CallCreateError = class extends Error {
9116
9150
  }
9117
9151
  };
9118
9152
  var JSONRPCError = class extends Error {
9119
- constructor(code, message, data, options) {
9153
+ constructor(code, message, data, options, requestId) {
9120
9154
  super(message, options);
9121
9155
  this.code = code;
9122
9156
  this.data = data;
9123
- this.name = "JSONRPCError";
9124
- }
9125
- };
9126
- var RPCError = class extends Error {
9127
- constructor(code, requestId, message, data, options) {
9128
- super(message, options);
9129
- this.code = code;
9130
9157
  this.requestId = requestId;
9131
- this.data = data;
9132
- this.name = "RPCError";
9158
+ this.name = "JSONRPCError";
9133
9159
  }
9134
9160
  };
9135
9161
  var InvalidParams = class extends Error {
@@ -10654,17 +10680,21 @@ var AttachManager = class {
10654
10680
  buildCallOptions(attachment) {
10655
10681
  const { audio: audioDirection, video: videoDirection } = attachment.mediaDirections;
10656
10682
  const { audioInputDevice, videoInputDevice } = attachment;
10683
+ const receiveAudio = audioDirection.includes("recv");
10684
+ const receiveVideo = videoDirection.includes("recv");
10685
+ const sendAudio = audioDirection.includes("send");
10686
+ const sendVideo = videoDirection.includes("send");
10657
10687
  return {
10658
- receiveAudio: audioDirection.includes("recv"),
10659
- receiveVideo: videoDirection.includes("recv"),
10660
- inputAudioDeviceConstraints: {
10661
- audio: audioDirection.includes("send"),
10688
+ receiveAudio,
10689
+ receiveVideo,
10690
+ inputAudioDeviceConstraints: sendAudio ? {
10691
+ audio: true,
10662
10692
  ...this.deviceController.deviceInfoToConstraints(audioInputDevice)
10663
- },
10664
- inputVideoDeviceConstraints: {
10665
- video: videoDirection.includes("send"),
10693
+ } : void 0,
10694
+ inputVideoDeviceConstraints: sendVideo ? {
10695
+ video: true,
10666
10696
  ...this.deviceController.deviceInfoToConstraints(videoInputDevice)
10667
- },
10697
+ } : void 0,
10668
10698
  reattach: true
10669
10699
  };
10670
10700
  }
@@ -12240,6 +12270,9 @@ function isJSONRPCRequest(value) {
12240
12270
  function isJSONRPCResponse(value) {
12241
12271
  return isObject(value) && hasProperty(value, "jsonrpc") && value.jsonrpc === "2.0" && hasProperty(value, "id") && typeof value.id === "string" && (hasProperty(value, "result") || hasProperty(value, "error"));
12242
12272
  }
12273
+ function isJSONRPCErrorResponse(value) {
12274
+ return isObject(value) && hasProperty(value, "jsonrpc") && value.jsonrpc === "2.0" && hasProperty(value, "id") && typeof value.id === "string" && (hasProperty(value, "error") && isObject(value.error) && hasProperty(value.error, "code") && hasProperty(value.error, "message") || hasProperty(value, "result") && isObject(value.result) && hasProperty(value.result, "code") && value.result.code !== "200" && hasProperty(value.result, "message"));
12275
+ }
12243
12276
 
12244
12277
  //#endregion
12245
12278
  //#region src/core/RPCMessages/guards/events.guards.ts
@@ -14082,6 +14115,11 @@ var WebRTCVertoManager = class extends VertoManager {
14082
14115
  ].includes(connectionState)))));
14083
14116
  }
14084
14117
  initSubscriptions() {
14118
+ this.subscribeTo(this.callJoinedEvent$, (event) => {
14119
+ const memberNodeId = event.room_session.members.find((m) => m.call_id === event.call_id)?.node_id;
14120
+ if (memberNodeId) this.setNodeIdIfNull(memberNodeId);
14121
+ if (event.member_id) this.setSelfIdIfNull(event.member_id);
14122
+ });
14085
14123
  this.subscribeTo(this.vertoMedia$, (event) => {
14086
14124
  logger$10.debug("[WebRTCManager] Received Verto media event (early media SDP):", event);
14087
14125
  this._signalingStatus$.next("ringing");
@@ -14113,6 +14151,28 @@ var WebRTCVertoManager = class extends VertoManager {
14113
14151
  this.sendVertoPong(vertoPing);
14114
14152
  });
14115
14153
  }
14154
+ /**
14155
+ * Set node_id/selfId only when the current value is null.
14156
+ *
14157
+ * During reattach, `call.joined` and `verto.answer` events can deliver
14158
+ * these identifiers before the `verto.invite` RPC response (`CALL CREATED`)
14159
+ * arrives. These methods let early events populate them eagerly so that
14160
+ * downstream RPC calls (e.g. `call.layout.list`) don't fail with empty
14161
+ * identifiers. `processInviteResponse()` remains the authoritative source
14162
+ * and always overwrites unconditionally.
14163
+ */
14164
+ setNodeIdIfNull(nodeId) {
14165
+ if (!this._nodeId$.value && nodeId) {
14166
+ logger$10.debug(`[WebRTCManager] Early node_id set: ${nodeId}`);
14167
+ this._nodeId$.next(nodeId);
14168
+ }
14169
+ }
14170
+ setSelfIdIfNull(selfId) {
14171
+ if (!this._selfId$.value && selfId) {
14172
+ logger$10.debug(`[WebRTCManager] Early selfId set: ${selfId}`);
14173
+ this._selfId$.next(selfId);
14174
+ }
14175
+ }
14116
14176
  async sendVertoPong(vertoPing) {
14117
14177
  try {
14118
14178
  const vertoPongMessage = VertoPong({ ...vertoPing });
@@ -14136,6 +14196,9 @@ var WebRTCVertoManager = class extends VertoManager {
14136
14196
  get selfId() {
14137
14197
  return this._selfId$.value;
14138
14198
  }
14199
+ get callJoinedEvent$() {
14200
+ return this.webRtcCallSession.callEvent$.pipe((0, import_cjs$10.filter)(isCallJoinedPayload), (0, import_cjs$10.takeUntil)(this.destroyed$));
14201
+ }
14139
14202
  get vertoMedia$() {
14140
14203
  return this.webRtcCallSession.webrtcMessages$.pipe(filterAs(isVertoMediaInnerParams, "params"), (0, import_cjs$10.takeUntil)(this.destroyed$));
14141
14204
  }
@@ -14667,7 +14730,7 @@ var WebRTCCall = class extends Destroyable {
14667
14730
  }
14668
14731
  /** Observable stream of errors from media, signaling, and peer connection layers. */
14669
14732
  get errors$() {
14670
- return this._errors$.asObservable();
14733
+ return this.deferEmission(this._errors$.asObservable());
14671
14734
  }
14672
14735
  /**
14673
14736
  * @internal Push an error to the call's error stream.
@@ -14687,7 +14750,7 @@ var WebRTCCall = class extends Destroyable {
14687
14750
  }
14688
14751
  /** Observable of the address associated with this call. */
14689
14752
  get address$() {
14690
- return (0, import_cjs$9.from)([this.address]);
14753
+ return this.deferEmission((0, import_cjs$9.from)([this.address])).pipe((0, import_cjs$9.takeUntil)(this._destroyed$));
14691
14754
  }
14692
14755
  /** Display name of the caller. */
14693
14756
  get fromName() {
@@ -14748,7 +14811,7 @@ var WebRTCCall = class extends Destroyable {
14748
14811
  }
14749
14812
  /** Observable of layout layer positions for all participants. */
14750
14813
  get layoutLayers$() {
14751
- return this.callEventsManager.layoutLayers$;
14814
+ return this.deferEmission(this.callEventsManager.layoutLayers$).pipe((0, import_cjs$9.takeUntil)(this._destroyed$));
14752
14815
  }
14753
14816
  /** Current snapshot of layout layers. */
14754
14817
  get layoutLayers() {
@@ -14762,7 +14825,9 @@ var WebRTCCall = class extends Destroyable {
14762
14825
  params
14763
14826
  });
14764
14827
  try {
14765
- return await this.clientSession.execute(request);
14828
+ const response = await this.clientSession.execute(request);
14829
+ if (isJSONRPCErrorResponse(response)) throw new JSONRPCError(parseInt(response.result?.code ?? "0"), `Error response from method ${method}: ${response.result?.code} ${response.result?.message}`, void 0, void 0, request.id);
14830
+ return response;
14766
14831
  } catch (error) {
14767
14832
  logger$9.error(`[Call] Error executing method ${method} with params`, params, error);
14768
14833
  throw error;
@@ -14791,45 +14856,45 @@ var WebRTCCall = class extends Destroyable {
14791
14856
  }
14792
14857
  /** Observable of the current call status (e.g. `'ringing'`, `'connected'`). */
14793
14858
  get status$() {
14794
- return this.cachedObservable("status$", () => (0, import_cjs$9.merge)(this._status$.asObservable(), this.vertoManager.signalingStatus$).pipe((0, import_cjs$9.distinctUntilChanged)(), (0, import_cjs$9.tap)((status) => {
14859
+ return this.publicCachedObservable("status$", () => (0, import_cjs$9.merge)(this._status$.asObservable(), this.vertoManager.signalingStatus$).pipe((0, import_cjs$9.distinctUntilChanged)(), (0, import_cjs$9.tap)((status) => {
14795
14860
  this._lastMergedStatus = status;
14796
14861
  })));
14797
14862
  }
14798
14863
  /** Observable of the participants list, emits on join/leave/update. */
14799
14864
  get participants$() {
14800
- return this.callEventsManager.participants$;
14865
+ return this.deferEmission(this.callEventsManager.participants$).pipe((0, import_cjs$9.takeUntil)(this._destroyed$));
14801
14866
  }
14802
14867
  /** Observable of the local (self) participant. */
14803
14868
  get self$() {
14804
- return this.callEventsManager.self$;
14869
+ return this.deferEmission(this.callEventsManager.self$).pipe((0, import_cjs$9.takeUntil)(this._destroyed$));
14805
14870
  }
14806
14871
  /** Observable indicating whether the call is being recorded. */
14807
14872
  get recording$() {
14808
- return this.callEventsManager.recording$;
14873
+ return this.deferEmission(this.callEventsManager.recording$).pipe((0, import_cjs$9.takeUntil)(this._destroyed$));
14809
14874
  }
14810
14875
  /** Observable indicating whether the call is being streamed. */
14811
14876
  get streaming$() {
14812
- return this.callEventsManager.streaming$;
14877
+ return this.deferEmission(this.callEventsManager.streaming$).pipe((0, import_cjs$9.takeUntil)(this._destroyed$));
14813
14878
  }
14814
14879
  /** Observable indicating whether raise-hand priority is active. */
14815
14880
  get raiseHandPriority$() {
14816
- return this.callEventsManager.raiseHandPriority$;
14881
+ return this.deferEmission(this.callEventsManager.raiseHandPriority$).pipe((0, import_cjs$9.takeUntil)(this._destroyed$));
14817
14882
  }
14818
14883
  /** Observable indicating whether the call room is locked. */
14819
14884
  get locked$() {
14820
- return this.callEventsManager.locked$;
14885
+ return this.deferEmission(this.callEventsManager.locked$).pipe((0, import_cjs$9.takeUntil)(this._destroyed$));
14821
14886
  }
14822
14887
  /** Observable of custom metadata associated with the call. */
14823
14888
  get meta$() {
14824
- return this.callEventsManager.meta$;
14889
+ return this.deferEmission(this.callEventsManager.meta$).pipe((0, import_cjs$9.takeUntil)(this._destroyed$));
14825
14890
  }
14826
14891
  /** Observable of the call's capability flags. */
14827
14892
  get capabilities$() {
14828
- return this.callEventsManager.capabilities$;
14893
+ return this.deferEmission(this.callEventsManager.capabilities$).pipe((0, import_cjs$9.takeUntil)(this._destroyed$));
14829
14894
  }
14830
14895
  /** Observable of the current layout name. */
14831
14896
  get layout$() {
14832
- return this.callEventsManager.layout$;
14897
+ return this.deferEmission(this.callEventsManager.layout$).pipe((0, import_cjs$9.takeUntil)(this._destroyed$));
14833
14898
  }
14834
14899
  /** Current call status. */
14835
14900
  get status() {
@@ -14861,7 +14926,7 @@ var WebRTCCall = class extends Destroyable {
14861
14926
  }
14862
14927
  /** Observable of available layout names. */
14863
14928
  get layouts$() {
14864
- return this.callEventsManager.layouts$;
14929
+ return this.deferEmission(this.callEventsManager.layouts$).pipe((0, import_cjs$9.takeUntil)(this._destroyed$));
14865
14930
  }
14866
14931
  /** Current snapshot of available layout names. */
14867
14932
  get layouts() {
@@ -14869,7 +14934,7 @@ var WebRTCCall = class extends Destroyable {
14869
14934
  }
14870
14935
  /** Observable of the local media stream (camera/microphone). */
14871
14936
  get localStream$() {
14872
- return this.vertoManager.localStream$;
14937
+ return this.deferEmission(this.vertoManager.localStream$).pipe((0, import_cjs$9.takeUntil)(this._destroyed$));
14873
14938
  }
14874
14939
  /** Current local media stream, or `null` if not available. */
14875
14940
  get localStream() {
@@ -14877,7 +14942,7 @@ var WebRTCCall = class extends Destroyable {
14877
14942
  }
14878
14943
  /** Observable of the remote media stream from the far end. */
14879
14944
  get remoteStream$() {
14880
- return this.vertoManager.remoteStream$;
14945
+ return this.deferEmission(this.vertoManager.remoteStream$).pipe((0, import_cjs$9.takeUntil)(this._destroyed$));
14881
14946
  }
14882
14947
  /** Current remote media stream, or `null` if not available. */
14883
14948
  get remoteStream() {
@@ -14885,7 +14950,7 @@ var WebRTCCall = class extends Destroyable {
14885
14950
  }
14886
14951
  /** Observable of custom user variables associated with the call. */
14887
14952
  get userVariables$() {
14888
- return this._userVariables$.asObservable();
14953
+ return this.deferEmission(this._userVariables$.asObservable());
14889
14954
  }
14890
14955
  /** a copy of the current custom user variables of the call. */
14891
14956
  get userVariables() {
@@ -14905,7 +14970,7 @@ var WebRTCCall = class extends Destroyable {
14905
14970
  }
14906
14971
  /** Observable of the current audio/video send/receive directions. */
14907
14972
  get mediaDirections$() {
14908
- return this.vertoManager.mediaDirections$;
14973
+ return this.deferEmission(this.vertoManager.mediaDirections$).pipe((0, import_cjs$9.takeUntil)(this._destroyed$));
14909
14974
  }
14910
14975
  /** Current audio/video send/receive directions. */
14911
14976
  get mediaDirections() {
@@ -14951,31 +15016,31 @@ var WebRTCCall = class extends Destroyable {
14951
15016
  }
14952
15017
  /** Observable of call-updated events. */
14953
15018
  get callUpdated$() {
14954
- return this.cachedObservable("callUpdated$", () => this.callSessionEvents$.pipe(filterAs(isCallUpdatedMetadata, "params"), (0, import_cjs$9.takeUntil)(this.destroyed$)));
15019
+ return this.publicCachedObservable("callUpdated$", () => this.callSessionEvents$.pipe(filterAs(isCallUpdatedMetadata, "params"), (0, import_cjs$9.takeUntil)(this.destroyed$)));
14955
15020
  }
14956
15021
  /** Observable of member-joined events. */
14957
15022
  get memberJoined$() {
14958
- return this.cachedObservable("memberJoined$", () => this.callSessionEvents$.pipe(filterAs(isMemberJoinedMetadata, "params"), (0, import_cjs$9.takeUntil)(this.destroyed$)));
15023
+ return this.publicCachedObservable("memberJoined$", () => this.callSessionEvents$.pipe(filterAs(isMemberJoinedMetadata, "params"), (0, import_cjs$9.takeUntil)(this.destroyed$)));
14959
15024
  }
14960
15025
  /** Observable of member-left events. */
14961
15026
  get memberLeft$() {
14962
- return this.cachedObservable("memberLeft$", () => this.callSessionEvents$.pipe(filterAs(isMemberLeftMetadata, "params"), (0, import_cjs$9.takeUntil)(this.destroyed$)));
15027
+ return this.publicCachedObservable("memberLeft$", () => this.callSessionEvents$.pipe(filterAs(isMemberLeftMetadata, "params"), (0, import_cjs$9.takeUntil)(this.destroyed$)));
14963
15028
  }
14964
15029
  /** Observable of member-updated events (mute, volume, etc.). */
14965
15030
  get memberUpdated$() {
14966
- return this.cachedObservable("memberUpdated$", () => this.callSessionEvents$.pipe(filterAs(isMemberUpdatedMetadata, "params"), (0, import_cjs$9.takeUntil)(this.destroyed$)));
15031
+ return this.publicCachedObservable("memberUpdated$", () => this.callSessionEvents$.pipe(filterAs(isMemberUpdatedMetadata, "params"), (0, import_cjs$9.takeUntil)(this.destroyed$)));
14967
15032
  }
14968
15033
  /** Observable of member-talking events (speech start/stop). */
14969
15034
  get memberTalking$() {
14970
- return this.cachedObservable("memberTalking$", () => this.callSessionEvents$.pipe(filterAs(isMemberTalkingMetadata, "params"), (0, import_cjs$9.takeUntil)(this.destroyed$)));
15035
+ return this.publicCachedObservable("memberTalking$", () => this.callSessionEvents$.pipe(filterAs(isMemberTalkingMetadata, "params"), (0, import_cjs$9.takeUntil)(this.destroyed$)));
14971
15036
  }
14972
15037
  /** Observable of call state-change events. */
14973
15038
  get callStates$() {
14974
- return this.cachedObservable("callStates$", () => this.callSessionEvents$.pipe(filterAs(isCallStateMetadata, "params"), (0, import_cjs$9.takeUntil)(this.destroyed$)));
15039
+ return this.publicCachedObservable("callStates$", () => this.callSessionEvents$.pipe(filterAs(isCallStateMetadata, "params"), (0, import_cjs$9.takeUntil)(this.destroyed$)));
14975
15040
  }
14976
15041
  /** Observable of layout-changed events. */
14977
15042
  get layoutUpdates$() {
14978
- return this.cachedObservable("layoutUpdates$", () => this.callSessionEvents$.pipe(filterAs(isLayoutChangedMetadata, "params"), (0, import_cjs$9.takeUntil)(this.destroyed$)));
15043
+ return this.publicCachedObservable("layoutUpdates$", () => this.callSessionEvents$.pipe(filterAs(isLayoutChangedMetadata, "params"), (0, import_cjs$9.takeUntil)(this.destroyed$)));
14979
15044
  }
14980
15045
  /** Underlying `RTCPeerConnection`, for advanced use cases. */
14981
15046
  get rtcPeerConnection() {
@@ -14983,7 +15048,7 @@ var WebRTCCall = class extends Destroyable {
14983
15048
  }
14984
15049
  /** Observable of raw signaling events as plain objects. */
14985
15050
  get signalingEvent$() {
14986
- return this.cachedObservable("signalingEvent$", () => this.callEvent$.pipe((0, import_cjs$9.map)((event) => JSON.parse(JSON.stringify(event)))));
15051
+ return this.publicCachedObservable("signalingEvent$", () => this.callEvent$.pipe((0, import_cjs$9.map)((event) => JSON.parse(JSON.stringify(event)))));
14987
15052
  }
14988
15053
  /** Observable of WebRTC-specific signaling messages. */
14989
15054
  get webrtcMessages$() {
@@ -15025,7 +15090,7 @@ var WebRTCCall = class extends Destroyable {
15025
15090
  }
15026
15091
  /** Observable that emits `true` when answered, `false` when rejected. */
15027
15092
  get answered$() {
15028
- return this._answered$.asObservable();
15093
+ return this.deferEmission(this._answered$.asObservable());
15029
15094
  }
15030
15095
  /**
15031
15096
  * Sets the call layout and participant positions.
@@ -15482,7 +15547,7 @@ var PendingRPC = class PendingRPC {
15482
15547
  next: (response) => {
15483
15548
  isSettled = true;
15484
15549
  if (response.error) {
15485
- const rpcError = new RPCError(response.error.code, request.id, response.error.message, response.error.data);
15550
+ const rpcError = new JSONRPCError(response.error.code, response.error.message, response.error.data, void 0, request.id);
15486
15551
  logger$7.debug(`[PendingRPC(${this.id}) request:${request.id}] Rejecting promise with RPC error:`, rpcError);
15487
15552
  reject(rpcError);
15488
15553
  } else {
@@ -15773,6 +15838,7 @@ var ClientSessionManager = class extends Destroyable {
15773
15838
  ...params,
15774
15839
  ...persistedParams
15775
15840
  });
15841
+ this.transport.resetSessionEpoch();
15776
15842
  const response = await (0, import_cjs$5.lastValueFrom)((0, import_cjs$5.from)(this.transport.execute(rpcConnectRequest)).pipe(throwOnRPCError(), (0, import_cjs$5.map)((res) => res.result), (0, import_cjs$5.filter)(isRPCConnectResult), (0, import_cjs$5.tap)(() => {
15777
15843
  logger$6.debug("[Session] Response passed filter, processing authentication result");
15778
15844
  }), (0, import_cjs$5.take)(1), (0, import_cjs$5.catchError)((err) => {
@@ -16256,7 +16322,30 @@ function isSignalwirePingRequest(value) {
16256
16322
  //#region src/managers/TransportManager.ts
16257
16323
  var import_cjs$1 = require_cjs();
16258
16324
  const logger$2 = getLogger();
16259
- var TransportManager = class extends Destroyable {
16325
+ var TransportManager = class TransportManager extends Destroyable {
16326
+ /**
16327
+ * Normalise a server event timestamp to epoch seconds.
16328
+ *
16329
+ * The server uses two formats:
16330
+ * - `webrtc.message`: float epoch seconds (e.g. 1774372099.022817)
16331
+ * - all other events: int epoch microseconds (e.g. 1774372099925857)
16332
+ *
16333
+ * Values above 1e12 are treated as microseconds and divided by 1e6.
16334
+ */
16335
+ static toEpochSeconds(ts) {
16336
+ const n = typeof ts === "string" ? Number(ts) : ts;
16337
+ return n > 0xe8d4a51000 ? n / 1e6 : n;
16338
+ }
16339
+ /**
16340
+ * Extract the event timestamp from a signalwire.event message.
16341
+ * Returns `null` for messages that have no timestamp
16342
+ * (e.g. signalwire.authorization.state, RPC responses).
16343
+ */
16344
+ static extractEventTimestamp(message) {
16345
+ if (!isSignalwireRequest(message)) return null;
16346
+ if (message.params.event_type === "signalwire.authorization.state") return null;
16347
+ return TransportManager.toEpochSeconds(message.params.timestamp);
16348
+ }
16260
16349
  constructor(storage, protocolKey, webSocketConstructor, relayHost, onError) {
16261
16350
  super();
16262
16351
  this.storage = storage;
@@ -16289,6 +16378,23 @@ var TransportManager = class extends Destroyable {
16289
16378
  return true;
16290
16379
  });
16291
16380
  };
16381
+ this.discardStaleEvents = () => {
16382
+ return (0, import_cjs$1.filter)((message) => {
16383
+ const ts = TransportManager.extractEventTimestamp(message);
16384
+ if (ts === null) return true;
16385
+ if (this._sessionEpoch === null) {
16386
+ this._sessionEpoch = ts;
16387
+ return true;
16388
+ }
16389
+ if (ts < this._sessionEpoch) {
16390
+ const eventType = isSignalwireRequest(message) ? message.params.event_type : "unknown";
16391
+ logger$2.warn(`[Transport] Discarding stale event: ${eventType} (timestamp=${ts.toFixed(3)}, sessionEpoch=${this._sessionEpoch.toFixed(3)}, delta=${(this._sessionEpoch - ts).toFixed(3)}s)`);
16392
+ return false;
16393
+ }
16394
+ return true;
16395
+ });
16396
+ };
16397
+ this._sessionEpoch = null;
16292
16398
  this._outgoingMessages$ = this.createSubject();
16293
16399
  this._webSocketConnections = new WebSocketController(webSocketConstructor, relayHost, this._outgoingMessages$.asObservable(), {
16294
16400
  connectionTimeout: PreferencesContainer.instance.connectionTimeout,
@@ -16313,7 +16419,14 @@ var TransportManager = class extends Destroyable {
16313
16419
  return import_cjs$1.EMPTY;
16314
16420
  }), (0, import_cjs$1.share)(), (0, import_cjs$1.takeUntil)(this.destroyed$));
16315
16421
  this._jsonRPCResponse$ = this._jsonRPCMessage$.pipe((0, import_cjs$1.filter)(isJSONRPCResponse));
16316
- this._incomingEvent$ = this._jsonRPCMessage$.pipe(this.ackEvent(), this.replySignalwirePing(), (0, import_cjs$1.filter)((message) => !isJSONRPCResponse(message)), (0, import_cjs$1.share)(), (0, import_cjs$1.takeUntil)(this.destroyed$));
16422
+ this._incomingEvent$ = this._jsonRPCMessage$.pipe(this.ackEvent(), this.replySignalwirePing(), (0, import_cjs$1.filter)((message) => !isJSONRPCResponse(message)), this.discardStaleEvents(), (0, import_cjs$1.share)(), (0, import_cjs$1.takeUntil)(this.destroyed$));
16423
+ }
16424
+ /**
16425
+ * Reset the session epoch. Call this before each signalwire.connect
16426
+ * so that the first event after authentication establishes the new baseline.
16427
+ */
16428
+ resetSessionEpoch() {
16429
+ this._sessionEpoch = null;
16317
16430
  }
16318
16431
  async setProtocol(protocol) {
16319
16432
  this.protocol$.next(protocol);
@@ -16637,7 +16750,7 @@ var SignalWire = class extends Destroyable {
16637
16750
  * ```
16638
16751
  */
16639
16752
  get subscriber$() {
16640
- return this._subscriber$.asObservable();
16753
+ return this.deferEmission(this._subscriber$.asObservable());
16641
16754
  }
16642
16755
  /** Current subscriber snapshot, or `undefined` if not yet authenticated. */
16643
16756
  get subscriber() {
@@ -16656,7 +16769,7 @@ var SignalWire = class extends Destroyable {
16656
16769
  * ```
16657
16770
  */
16658
16771
  get directory$() {
16659
- return this._directory$.asObservable();
16772
+ return this.deferEmission(this._directory$.asObservable());
16660
16773
  }
16661
16774
  /**
16662
16775
  * Current directory snapshot, or `undefined` if the client is not yet connected.
@@ -16667,7 +16780,7 @@ var SignalWire = class extends Destroyable {
16667
16780
  }
16668
16781
  /** Observable that emits when the subscriber registration state changes. */
16669
16782
  get isRegistered$() {
16670
- return this._isRegistered$.asObservable();
16783
+ return this.deferEmission(this._isRegistered$.asObservable());
16671
16784
  }
16672
16785
  /** Whether the subscriber is currently registered. */
16673
16786
  get isRegistered() {
@@ -16679,15 +16792,15 @@ var SignalWire = class extends Destroyable {
16679
16792
  }
16680
16793
  /** Observable that emits when the connection state changes. */
16681
16794
  get isConnected$() {
16682
- return this._isConnected$.asObservable();
16795
+ return this.deferEmission(this._isConnected$.asObservable());
16683
16796
  }
16684
16797
  /** Observable that emits `true` when the client is both connected and authenticated. */
16685
16798
  get ready$() {
16686
- return this.cachedObservable("ready$", () => this._isConnected$.pipe((0, import_cjs.switchMap)((connected) => connected ? this._clientSession.authenticated$ : (0, import_cjs.of)(false))));
16799
+ return this.publicCachedObservable("ready$", () => this._isConnected$.pipe((0, import_cjs.switchMap)((connected) => connected ? this._clientSession.authenticated$ : (0, import_cjs.of)(false))));
16687
16800
  }
16688
16801
  /** Observable stream of errors from transport, authentication, and devices. */
16689
16802
  get errors$() {
16690
- return this._errors$.asObservable();
16803
+ return this.deferEmission(this._errors$.asObservable());
16691
16804
  }
16692
16805
  /** Disconnects the WebSocket and tears down the session. */
16693
16806
  async disconnect() {
@@ -16762,7 +16875,7 @@ var SignalWire = class extends Destroyable {
16762
16875
  }
16763
16876
  /** Observable list of available audio input (microphone) devices. */
16764
16877
  get audioInputDevices$() {
16765
- return this._deviceController.audioInputDevices$;
16878
+ return this.deferEmission(this._deviceController.audioInputDevices$);
16766
16879
  }
16767
16880
  /** Current snapshot of available audio input devices. */
16768
16881
  get audioInputDevices() {
@@ -16770,7 +16883,7 @@ var SignalWire = class extends Destroyable {
16770
16883
  }
16771
16884
  /** Observable list of available audio output (speaker) devices. */
16772
16885
  get audioOutputDevices$() {
16773
- return this._deviceController.audioOutputDevices$;
16886
+ return this.deferEmission(this._deviceController.audioOutputDevices$);
16774
16887
  }
16775
16888
  /** Current snapshot of available audio output devices. */
16776
16889
  get audioOutputDevices() {
@@ -16778,7 +16891,7 @@ var SignalWire = class extends Destroyable {
16778
16891
  }
16779
16892
  /** Observable list of available video input (camera) devices. */
16780
16893
  get videoInputDevices$() {
16781
- return this._deviceController.videoInputDevices$;
16894
+ return this.deferEmission(this._deviceController.videoInputDevices$);
16782
16895
  }
16783
16896
  /** Current snapshot of available video input devices. */
16784
16897
  get videoInputDevices() {
@@ -16786,15 +16899,15 @@ var SignalWire = class extends Destroyable {
16786
16899
  }
16787
16900
  /** Observable of the currently selected audio input device. */
16788
16901
  get selectedAudioInputDevice$() {
16789
- return this._deviceController.selectedAudioInputDevice$;
16902
+ return this.deferEmission(this._deviceController.selectedAudioInputDevice$);
16790
16903
  }
16791
16904
  /** Observable of the currently selected audio output device. */
16792
16905
  get selectedAudioOutputDevice$() {
16793
- return this._deviceController.selectedAudioOutputDevice$;
16906
+ return this.deferEmission(this._deviceController.selectedAudioOutputDevice$);
16794
16907
  }
16795
16908
  /** Observable of the currently selected video input device. */
16796
16909
  get selectedVideoInputDevice$() {
16797
- return this._deviceController.selectedVideoInputDevice$;
16910
+ return this.deferEmission(this._deviceController.selectedVideoInputDevice$);
16798
16911
  }
16799
16912
  /** Currently selected audio input device, or `null` if none. */
16800
16913
  get selectedAudioInputDevice() {