@signalwire/js 4.0.0-rc.0 → 4.0.0-rc.1
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 +138 -22
- package/dist/browser.mjs.map +1 -1
- package/dist/browser.umd.js +138 -22
- package/dist/browser.umd.js.map +1 -1
- package/dist/index.cjs +138 -22
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +106 -16
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +106 -16
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +138 -22
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/browser.umd.js
CHANGED
|
@@ -13373,7 +13373,9 @@ const DEFAULT_MEMBER_CAPABILITIES = {
|
|
|
13373
13373
|
position: false,
|
|
13374
13374
|
meta: false,
|
|
13375
13375
|
remove: false,
|
|
13376
|
-
audioFlags: false
|
|
13376
|
+
audioFlags: false,
|
|
13377
|
+
denoise: false,
|
|
13378
|
+
lowbitrate: false
|
|
13377
13379
|
};
|
|
13378
13380
|
/**
|
|
13379
13381
|
* Default call capabilities with no permissions
|
|
@@ -13446,7 +13448,9 @@ function computeMemberCapabilities(flags, memberType) {
|
|
|
13446
13448
|
position: hasBooleanCapability(flags, memberType, null, "position"),
|
|
13447
13449
|
meta: hasBooleanCapability(flags, memberType, null, "meta"),
|
|
13448
13450
|
remove: hasBooleanCapability(flags, memberType, null, "remove"),
|
|
13449
|
-
audioFlags: hasBooleanCapability(flags, memberType, null, "audioflags")
|
|
13451
|
+
audioFlags: hasBooleanCapability(flags, memberType, null, "audioflags"),
|
|
13452
|
+
denoise: hasBooleanCapability(flags, memberType, null, "denoise"),
|
|
13453
|
+
lowbitrate: hasBooleanCapability(flags, memberType, null, "lowbitrate")
|
|
13450
13454
|
};
|
|
13451
13455
|
}
|
|
13452
13456
|
/**
|
|
@@ -13829,6 +13833,10 @@ var Participant = class extends Destroyable {
|
|
|
13829
13833
|
get nodeId() {
|
|
13830
13834
|
return this._state$.value.node_id;
|
|
13831
13835
|
}
|
|
13836
|
+
/** Call ID for this participant's leg, or `undefined` if not available. */
|
|
13837
|
+
get callId() {
|
|
13838
|
+
return this._state$.value.call_id;
|
|
13839
|
+
}
|
|
13832
13840
|
/** @internal */
|
|
13833
13841
|
get value() {
|
|
13834
13842
|
return this._state$.value;
|
|
@@ -13890,8 +13898,9 @@ var Participant = class extends Destroyable {
|
|
|
13890
13898
|
noise_suppression: !this.noiseSuppression
|
|
13891
13899
|
});
|
|
13892
13900
|
}
|
|
13901
|
+
/** Toggles low-bitrate mode for this participant's media. */
|
|
13893
13902
|
async toggleLowbitrate() {
|
|
13894
|
-
|
|
13903
|
+
await this.executeMethod(this.id, "call.lowbitrate.set", { lowbitrate: !this.lowbitrate });
|
|
13895
13904
|
}
|
|
13896
13905
|
/**
|
|
13897
13906
|
* Adjusts the **conference-only** microphone energy gate / sensitivity level
|
|
@@ -13938,10 +13947,27 @@ var Participant = class extends Destroyable {
|
|
|
13938
13947
|
}
|
|
13939
13948
|
/**
|
|
13940
13949
|
* Sets the participant's position in the video layout.
|
|
13950
|
+
*
|
|
13951
|
+
* Requires the `member.position` capability. The gateway keys positions by the
|
|
13952
|
+
* **target member's own** `call_id`/`node_id` (see issue #19400 and the legacy
|
|
13953
|
+
* `setPositions` implementation), so this sends the participant's own call
|
|
13954
|
+
* context — matching {@link Participant.remove}. A resolved promise does not
|
|
13955
|
+
* guarantee a visible change: the backend silently returns `200` (no-op) for
|
|
13956
|
+
* non-conference targets.
|
|
13957
|
+
*
|
|
13941
13958
|
* @param value - The {@link VideoPosition} to assign (e.g. `'auto'`, `'reserved-0'`).
|
|
13942
13959
|
*/
|
|
13943
13960
|
async setPosition(value) {
|
|
13944
|
-
|
|
13961
|
+
const state = this._state$.value;
|
|
13962
|
+
const target = {
|
|
13963
|
+
member_id: this.id,
|
|
13964
|
+
call_id: state.call_id ?? "",
|
|
13965
|
+
node_id: state.node_id ?? ""
|
|
13966
|
+
};
|
|
13967
|
+
await this.executeMethod(target, "call.member.position.set", { targets: [{
|
|
13968
|
+
target,
|
|
13969
|
+
position: value
|
|
13970
|
+
}] });
|
|
13945
13971
|
}
|
|
13946
13972
|
/** Removes this participant from the call. */
|
|
13947
13973
|
async remove() {
|
|
@@ -16487,7 +16513,11 @@ function isVertoInviteMessage(value) {
|
|
|
16487
16513
|
const msg = value;
|
|
16488
16514
|
return msg.method === "verto.invite" && isObject(msg.params) && hasProperty(msg.params, "sdp") && hasProperty(msg.params, "callID");
|
|
16489
16515
|
}
|
|
16490
|
-
|
|
16516
|
+
/**
|
|
16517
|
+
* Guards inbound `verto.bye` frames (server → client). Outbound bye messages are
|
|
16518
|
+
* built locally and never type-guarded, so only the inbound shape is asserted.
|
|
16519
|
+
*/
|
|
16520
|
+
function isVertoByeInboundMessage(value) {
|
|
16491
16521
|
if (!isVertoMethodMessage(value)) return false;
|
|
16492
16522
|
return value.method === "verto.bye";
|
|
16493
16523
|
}
|
|
@@ -16507,6 +16537,14 @@ function isVertoMediaParamsInnerParams(value) {
|
|
|
16507
16537
|
function isVertoPingInnerParams(value) {
|
|
16508
16538
|
return isObject(value) && hasProperty(value, "jsonrpc") && value.jsonrpc === "2.0" && hasProperty(value, "method") && value.method === "verto.ping";
|
|
16509
16539
|
}
|
|
16540
|
+
/**
|
|
16541
|
+
* Guards the params of an inbound `verto.bye` frame (top-level `callID`). Use
|
|
16542
|
+
* this to recognise the bye payload extracted by `vertoBye$`, e.g. when racing
|
|
16543
|
+
* it against a boolean answer/reject signal.
|
|
16544
|
+
*/
|
|
16545
|
+
function isVertoByeInboundParamsGuard(value) {
|
|
16546
|
+
return isObject(value) && hasProperty(value, "callID") && typeof value.callID === "string";
|
|
16547
|
+
}
|
|
16510
16548
|
|
|
16511
16549
|
//#endregion
|
|
16512
16550
|
//#region src/managers/VertoManager.ts
|
|
@@ -16845,7 +16883,7 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
16845
16883
|
return this.cachedObservable("vertoMediaParams$", () => this.webRtcCallSession.webrtcMessages$.pipe(filterAs(isVertoMediaParamsInnerParams, "params"), (0, import_cjs$15.takeUntil)(this.destroyed$)));
|
|
16846
16884
|
}
|
|
16847
16885
|
get vertoBye$() {
|
|
16848
|
-
return this.cachedObservable("vertoBye$", () => this.webRtcCallSession.webrtcMessages$.pipe(filterAs(
|
|
16886
|
+
return this.cachedObservable("vertoBye$", () => this.webRtcCallSession.webrtcMessages$.pipe(filterAs(isVertoByeInboundMessage, "params"), (0, import_cjs$15.takeUntil)(this.destroyed$)));
|
|
16849
16887
|
}
|
|
16850
16888
|
get vertoAttach$() {
|
|
16851
16889
|
return this.cachedObservable("vertoAttach$", () => this.webRtcCallSession.webrtcMessages$.pipe(filterAs(isVertoAttachMessage, "params"), (0, import_cjs$15.takeUntil)(this.destroyed$)));
|
|
@@ -16998,7 +17036,7 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
16998
17036
|
logger$16.debug("[WebRTCManager] Inbound answer handler aborted (destroyed).");
|
|
16999
17037
|
return;
|
|
17000
17038
|
}
|
|
17001
|
-
if (
|
|
17039
|
+
if (isVertoByeInboundParamsGuard(vertoByeOrAccepted)) {
|
|
17002
17040
|
logger$16.info("[WebRTCManager] Inbound call ended by remote before answer.");
|
|
17003
17041
|
this.callSession?.destroy();
|
|
17004
17042
|
} else if (!vertoByeOrAccepted) {
|
|
@@ -17100,7 +17138,7 @@ var WebRTCVertoManager = class extends VertoManager {
|
|
|
17100
17138
|
logger$16.debug("[WebRTCManager] Destroyed while waiting for call acceptance");
|
|
17101
17139
|
return;
|
|
17102
17140
|
}
|
|
17103
|
-
if (
|
|
17141
|
+
if (isVertoByeInboundParamsGuard(vertoByeOrAccepted)) {
|
|
17104
17142
|
logger$16.info("[WebRTCManager] Call ended before answer was sent.");
|
|
17105
17143
|
this.callSession?.destroy();
|
|
17106
17144
|
} else if (!vertoByeOrAccepted) {
|
|
@@ -18153,6 +18191,12 @@ function mosToQualityLevel(mos) {
|
|
|
18153
18191
|
var import_cjs$11 = require_cjs();
|
|
18154
18192
|
const logger$12 = getLogger();
|
|
18155
18193
|
/**
|
|
18194
|
+
* Verto method for setting member layout positions. Its gateway DTO requires a
|
|
18195
|
+
* `targets` array whose entries are `{ target, position }` (NOT bare targets),
|
|
18196
|
+
* so {@link WebRTCCall.buildMethodParams} special-cases it. See issue #19400.
|
|
18197
|
+
*/
|
|
18198
|
+
const POSITION_SET_METHOD = "call.member.position.set";
|
|
18199
|
+
/**
|
|
18156
18200
|
* Ratio between the critical and warning RTT spike multipliers.
|
|
18157
18201
|
* Warning threshold = baseline * warningMultiplier (default 3x)
|
|
18158
18202
|
* Critical threshold = baseline * warningMultiplier * RTT_CRITICAL_TO_WARNING_RATIO
|
|
@@ -18359,7 +18403,7 @@ var WebRTCCall = class extends Destroyable {
|
|
|
18359
18403
|
* @throws {JSONRPCError} If the RPC call returns an error.
|
|
18360
18404
|
*/
|
|
18361
18405
|
async executeMethod(target, method, args) {
|
|
18362
|
-
const params = this.buildMethodParams(target, args);
|
|
18406
|
+
const params = this.buildMethodParams(target, args, method);
|
|
18363
18407
|
const request = buildRPCRequest({
|
|
18364
18408
|
method,
|
|
18365
18409
|
params
|
|
@@ -18373,12 +18417,16 @@ var WebRTCCall = class extends Destroyable {
|
|
|
18373
18417
|
throw error;
|
|
18374
18418
|
}
|
|
18375
18419
|
}
|
|
18376
|
-
buildMethodParams(target, args) {
|
|
18420
|
+
buildMethodParams(target, args, method) {
|
|
18377
18421
|
const self = {
|
|
18378
18422
|
node_id: this.nodeId ?? "",
|
|
18379
18423
|
call_id: this.id,
|
|
18380
18424
|
member_id: this.vertoManager.selfId ?? ""
|
|
18381
18425
|
};
|
|
18426
|
+
if (method === POSITION_SET_METHOD) return {
|
|
18427
|
+
...args,
|
|
18428
|
+
self
|
|
18429
|
+
};
|
|
18382
18430
|
if (typeof target === "object") return {
|
|
18383
18431
|
...args,
|
|
18384
18432
|
self,
|
|
@@ -18944,10 +18992,21 @@ var WebRTCCall = class extends Destroyable {
|
|
|
18944
18992
|
return this.deferEmission(this._answered$.asObservable());
|
|
18945
18993
|
}
|
|
18946
18994
|
/**
|
|
18947
|
-
* Sets the call layout and participant positions.
|
|
18995
|
+
* Sets the call layout and, optionally, individual participant positions.
|
|
18996
|
+
*
|
|
18997
|
+
* The gateway `call.layout.set` DTO has **no** `positions` member, so when
|
|
18998
|
+
* `positions` is provided this method issues a `call.member.position.set`
|
|
18999
|
+
* request per member (via {@link Participant.setPosition}, which keys each
|
|
19000
|
+
* position by that member's own call context) alongside `call.layout.set`
|
|
19001
|
+
* (issue #19400, Flag #6).
|
|
19002
|
+
*
|
|
19003
|
+
* **These operations are NOT atomic.** The layout is applied first, then each
|
|
19004
|
+
* member position sequentially, so members may briefly flash into their
|
|
19005
|
+
* default slots before being moved to the requested positions.
|
|
18948
19006
|
*
|
|
18949
19007
|
* @param layout - Layout name (must be one of {@link layouts}).
|
|
18950
|
-
* @param positions -
|
|
19008
|
+
* @param positions - Optional map of member IDs to {@link VideoPosition} values.
|
|
19009
|
+
* When omitted or empty, only the layout is changed.
|
|
18951
19010
|
* @throws {InvalidParams} If the layout is not in the available {@link layouts}.
|
|
18952
19011
|
*
|
|
18953
19012
|
* @example
|
|
@@ -18960,10 +19019,17 @@ var WebRTCCall = class extends Destroyable {
|
|
|
18960
19019
|
async setLayout(layout, positions) {
|
|
18961
19020
|
if (!this.layouts.includes(layout)) throw new InvalidParams(`Layout ${layout} is not available in the current call layouts: ${this.layouts.join(", ")}`);
|
|
18962
19021
|
const selfId = await (0, import_cjs$11.firstValueFrom)(this.selfId$.pipe((0, import_cjs$11.filter)((id) => id !== null)));
|
|
18963
|
-
await this.executeMethod(selfId, "call.layout.set", {
|
|
18964
|
-
|
|
18965
|
-
|
|
18966
|
-
|
|
19022
|
+
await this.executeMethod(selfId, "call.layout.set", { layout });
|
|
19023
|
+
const positionEntries = Object.entries(positions ?? {});
|
|
19024
|
+
if (positionEntries.length === 0) return;
|
|
19025
|
+
for (const [memberId, position] of positionEntries) {
|
|
19026
|
+
const participant = this.participants.find((p) => p.id === memberId);
|
|
19027
|
+
if (!participant) {
|
|
19028
|
+
logger$12.warn(`[Call] setLayout: member ${memberId} not found in participants; skipping position ${position}`);
|
|
19029
|
+
continue;
|
|
19030
|
+
}
|
|
19031
|
+
await participant.setPosition(position);
|
|
19032
|
+
}
|
|
18967
19033
|
}
|
|
18968
19034
|
/**
|
|
18969
19035
|
* Transfers the call to another destination.
|
|
@@ -19882,11 +19948,41 @@ var ClientSessionManager = class extends Destroyable {
|
|
|
19882
19948
|
}
|
|
19883
19949
|
} else this._errors$.next(error);
|
|
19884
19950
|
}
|
|
19951
|
+
/**
|
|
19952
|
+
* Clear the resume state (authorization_state + protocol) only.
|
|
19953
|
+
*
|
|
19954
|
+
* This is the stale-auth-state recovery helper used by handleAuthError:
|
|
19955
|
+
* the server rejected a reconnect, so the resume state is discarded and a
|
|
19956
|
+
* fresh connect follows. Attach records are deliberately preserved — the
|
|
19957
|
+
* session lives on through the reconnect and reattachCalls() needs the
|
|
19958
|
+
* stored call references afterwards. Do NOT add detachAll() here.
|
|
19959
|
+
*
|
|
19960
|
+
* For public teardown (disconnect/destroy), use {@link teardownSessionState}
|
|
19961
|
+
* instead, which clears the attach records as well.
|
|
19962
|
+
*/
|
|
19885
19963
|
async cleanupStoredConnectionParams() {
|
|
19886
19964
|
await this.transport.setProtocol(void 0);
|
|
19887
19965
|
await this.updateAuthorizationStateInStorage(void 0);
|
|
19888
19966
|
this._authorization$.next(void 0);
|
|
19889
19967
|
}
|
|
19968
|
+
/**
|
|
19969
|
+
* Public-teardown helper for disconnect()/destroy(). Clears the resume
|
|
19970
|
+
* state (authorization_state + protocol) AND the attach records as one
|
|
19971
|
+
* atomic unit.
|
|
19972
|
+
*
|
|
19973
|
+
* The two stores are coupled: the backend only honors attach records
|
|
19974
|
+
* within the session identified by the resume state, so ending the
|
|
19975
|
+
* session must clear both. Clearing one without the other strands records
|
|
19976
|
+
* no future session can honor (disconnect) or revives a session the
|
|
19977
|
+
* developer explicitly ended (destroy).
|
|
19978
|
+
*
|
|
19979
|
+
* Distinct from {@link cleanupStoredConnectionParams}, which keeps the
|
|
19980
|
+
* attach records for the stale-auth-state recovery path.
|
|
19981
|
+
*/
|
|
19982
|
+
async teardownSessionState() {
|
|
19983
|
+
await this.cleanupStoredConnectionParams();
|
|
19984
|
+
await this.attachManager.detachAll();
|
|
19985
|
+
}
|
|
19890
19986
|
async updateAuthState(authorization_state) {
|
|
19891
19987
|
try {
|
|
19892
19988
|
await this.storage.setItem(this.authorizationStateKey, authorization_state);
|
|
@@ -19981,7 +20077,7 @@ var ClientSessionManager = class extends Destroyable {
|
|
|
19981
20077
|
async disconnect() {
|
|
19982
20078
|
this.transport.disconnect();
|
|
19983
20079
|
this._authState$.next({ kind: "unauthenticated" });
|
|
19984
|
-
await this.
|
|
20080
|
+
await this.teardownSessionState();
|
|
19985
20081
|
}
|
|
19986
20082
|
async createInboundCall(invite) {
|
|
19987
20083
|
const callSession = await this.createCall({
|
|
@@ -21148,6 +21244,10 @@ var TransportManager = class extends Destroyable {
|
|
|
21148
21244
|
if (!isSignalwireRequest(message)) return true;
|
|
21149
21245
|
const eventChannel = message.params.event_channel;
|
|
21150
21246
|
if (!eventChannel) return true;
|
|
21247
|
+
if (message.params.event_type.startsWith("conversation.")) {
|
|
21248
|
+
logger$2.debug(`[Transport] Received conversation event: ${message.params.event_type} (event_channel: ${eventChannel})`);
|
|
21249
|
+
return true;
|
|
21250
|
+
}
|
|
21151
21251
|
const currentProtocol = this._currentProtocol;
|
|
21152
21252
|
if (!currentProtocol) return true;
|
|
21153
21253
|
if (!eventChannel.includes(currentProtocol)) {
|
|
@@ -21748,7 +21848,7 @@ var SignalWire = class extends Destroyable {
|
|
|
21748
21848
|
logger$1.warn("[SignalWire] Failed to initialize VisibilityController:", error);
|
|
21749
21849
|
}
|
|
21750
21850
|
try {
|
|
21751
|
-
this._diagnosticsCollector = new DiagnosticsCollector({ sdkVersion: "4.0.0-rc.
|
|
21851
|
+
this._diagnosticsCollector = new DiagnosticsCollector({ sdkVersion: "4.0.0-rc.1" });
|
|
21752
21852
|
} catch (error) {
|
|
21753
21853
|
logger$1.warn("[SignalWire] Failed to initialize DiagnosticsCollector:", error);
|
|
21754
21854
|
}
|
|
@@ -21756,6 +21856,14 @@ var SignalWire = class extends Destroyable {
|
|
|
21756
21856
|
/**
|
|
21757
21857
|
* Disconnects the WebSocket and tears down the current session.
|
|
21758
21858
|
*
|
|
21859
|
+
* Ends the session identified by the protocol and clears its persisted
|
|
21860
|
+
* resume state (`authorization_state` + protocol) and attach records
|
|
21861
|
+
* together — a later {@link connect} with the same credentials starts a
|
|
21862
|
+
* fresh session and cannot reattach to the ended session's calls.
|
|
21863
|
+
* Credentials and device preferences are preserved. To temporarily stop
|
|
21864
|
+
* receiving inbound calls while keeping the session alive, use
|
|
21865
|
+
* `unregister()` instead.
|
|
21866
|
+
*
|
|
21759
21867
|
* The client can be reconnected by calling {@link connect} again,
|
|
21760
21868
|
* which creates a fresh transport and session.
|
|
21761
21869
|
*/
|
|
@@ -22147,12 +22255,20 @@ var SignalWire = class extends Destroyable {
|
|
|
22147
22255
|
prefs.preferredVideoInput = null;
|
|
22148
22256
|
await this._deviceController.clearDeviceState();
|
|
22149
22257
|
}
|
|
22150
|
-
/**
|
|
22258
|
+
/**
|
|
22259
|
+
* Destroys the client, clearing timers and releasing all resources.
|
|
22260
|
+
*
|
|
22261
|
+
* Intentionally destroying the client ends its session: the resume state
|
|
22262
|
+
* (`authorization_state` + protocol) and the attach records are both
|
|
22263
|
+
* cleared. Credentials and device preferences are preserved — use
|
|
22264
|
+
* {@link resetToDefaults} for a full wipe. To temporarily stop receiving
|
|
22265
|
+
* inbound calls while keeping the session alive, use `unregister()`.
|
|
22266
|
+
*/
|
|
22151
22267
|
destroy() {
|
|
22152
22268
|
this._refreshCoordinator?.destroy();
|
|
22153
22269
|
this._refreshCoordinator = void 0;
|
|
22154
22270
|
this._dpopManager?.destroy();
|
|
22155
|
-
|
|
22271
|
+
this._clientSession.teardownSessionState();
|
|
22156
22272
|
this._transport.destroy();
|
|
22157
22273
|
this._clientSession.destroy();
|
|
22158
22274
|
try {
|
|
@@ -22267,7 +22383,7 @@ var StaticCredentialProvider = class {
|
|
|
22267
22383
|
/**
|
|
22268
22384
|
* Library version from package.json, injected at build time.
|
|
22269
22385
|
*/
|
|
22270
|
-
const version = "4.0.0-rc.
|
|
22386
|
+
const version = "4.0.0-rc.1";
|
|
22271
22387
|
/**
|
|
22272
22388
|
* Flag indicating the library has been loaded and is ready to use.
|
|
22273
22389
|
* For UMD builds: `window.SignalWire.ready`
|
|
@@ -22289,7 +22405,7 @@ const ready = true;
|
|
|
22289
22405
|
*/
|
|
22290
22406
|
const emitReadyEvent = () => {
|
|
22291
22407
|
if (typeof window !== "undefined") {
|
|
22292
|
-
const event = new CustomEvent("signalwire:js:ready", { detail: { version: "4.0.0-rc.
|
|
22408
|
+
const event = new CustomEvent("signalwire:js:ready", { detail: { version: "4.0.0-rc.1" } });
|
|
22293
22409
|
window.dispatchEvent(event);
|
|
22294
22410
|
}
|
|
22295
22411
|
};
|