@voice-ai-labs/web-sdk 0.8.0 → 0.9.0

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.js CHANGED
@@ -10706,7 +10706,7 @@ function getMatch(exp, ua) {
10706
10706
  }
10707
10707
  function getOSVersion(ua) {
10708
10708
  return ua.includes('mac os') ? getMatch(/\(.+?(\d+_\d+(:?_\d+)?)/, ua, 1).replace(/_/g, '.') : undefined;
10709
- }var version$1 = "2.17.2";const version = version$1;
10709
+ }var version$1 = "2.17.3";const version = version$1;
10710
10710
  const protocolVersion = 16;/** Base error that all LiveKit specific custom errors inherit from. */
10711
10711
  class LivekitError extends Error {
10712
10712
  constructor(code, message, options) {
@@ -10922,7 +10922,7 @@ var RoomEvent;
10922
10922
  RoomEvent["Reconnected"] = "reconnected";
10923
10923
  /**
10924
10924
  * When disconnected from room. This fires when room.disconnect() is called or
10925
- * when an unrecoverable connection issue had occured.
10925
+ * when an unrecoverable connection issue had occurred.
10926
10926
  *
10927
10927
  * DisconnectReason can be used to determine why the participant was disconnected. Notable reasons are
10928
10928
  * - DUPLICATE_IDENTITY: another client with the same identity has joined the room
@@ -12632,6 +12632,10 @@ function getEmptyAudioStreamTrack() {
12632
12632
  }
12633
12633
  return emptyAudioStreamTrack.clone();
12634
12634
  }
12635
+ /** An object that represents a serialized version of a `new Promise((resolve, reject) => {})`
12636
+ * constructor. Wait for a promise resolution with `await future.promise` and explicitly resolve or
12637
+ * reject the inner promise with `future.resolve(...)` or `future.reject(...)`.
12638
+ */
12635
12639
  class Future {
12636
12640
  get isResolved() {
12637
12641
  return this._isResolved;
@@ -12924,6 +12928,7 @@ class BaseKeyProvider extends eventsExports.EventEmitter {
12924
12928
  constructor() {
12925
12929
  let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
12926
12930
  super();
12931
+ this.latestManuallySetKeyIndex = 0;
12927
12932
  /**
12928
12933
  * Callback being invoked after a key has been ratcheted.
12929
12934
  * Can happen when:
@@ -12960,11 +12965,17 @@ class BaseKeyProvider extends eventsExports.EventEmitter {
12960
12965
  throw new Error('participant identity needs to be passed for encryption key if sharedKey option is false');
12961
12966
  }
12962
12967
  this.keyInfoMap.set("".concat(participantIdentity !== null && participantIdentity !== void 0 ? participantIdentity : 'shared', "-").concat(keyIndex !== null && keyIndex !== void 0 ? keyIndex : 0), keyInfo);
12963
- this.emit(KeyProviderEvent.SetKey, keyInfo);
12968
+ if (keyIndex !== undefined) {
12969
+ this.latestManuallySetKeyIndex = keyIndex;
12970
+ }
12971
+ this.emit(KeyProviderEvent.SetKey, keyInfo, keyIndex !== undefined);
12964
12972
  }
12965
12973
  getKeys() {
12966
12974
  return Array.from(this.keyInfoMap.values());
12967
12975
  }
12976
+ getLatestManuallySetKeyIndex() {
12977
+ return this.latestManuallySetKeyIndex;
12978
+ }
12968
12979
  getOptions() {
12969
12980
  return this.options;
12970
12981
  }
@@ -13012,14 +13023,14 @@ class E2EEManager extends eventsExports.EventEmitter {
13012
13023
  case 'initAck':
13013
13024
  if (data.enabled) {
13014
13025
  this.keyProvider.getKeys().forEach(keyInfo => {
13015
- this.postKey(keyInfo);
13026
+ this.postKey(keyInfo, false);
13016
13027
  });
13017
13028
  }
13018
13029
  break;
13019
13030
  case 'enable':
13020
13031
  if (data.enabled) {
13021
13032
  this.keyProvider.getKeys().forEach(keyInfo => {
13022
- this.postKey(keyInfo);
13033
+ this.postKey(keyInfo, false);
13023
13034
  });
13024
13035
  }
13025
13036
  if (this.encryptionEnabled !== data.enabled && data.participantIdentity === ((_a = this.room) === null || _a === void 0 ? void 0 : _a.localParticipant.identity)) {
@@ -13144,8 +13155,10 @@ class E2EEManager extends eventsExports.EventEmitter {
13144
13155
  if (!this.room) {
13145
13156
  throw new TypeError("expected room to be present on signal connect");
13146
13157
  }
13158
+ const latestKeyIndex = keyProvider.getLatestManuallySetKeyIndex();
13147
13159
  keyProvider.getKeys().forEach(keyInfo => {
13148
- this.postKey(keyInfo);
13160
+ var _a;
13161
+ this.postKey(keyInfo, latestKeyIndex === ((_a = keyInfo.keyIndex) !== null && _a !== void 0 ? _a : 0));
13149
13162
  });
13150
13163
  this.setParticipantCryptorEnabled(this.room.localParticipant.isE2EEEnabled, this.room.localParticipant.identity);
13151
13164
  });
@@ -13167,7 +13180,7 @@ class E2EEManager extends eventsExports.EventEmitter {
13167
13180
  };
13168
13181
  this.worker.postMessage(msg);
13169
13182
  });
13170
- keyProvider.on(KeyProviderEvent.SetKey, keyInfo => this.postKey(keyInfo)).on(KeyProviderEvent.RatchetRequest, (participantId, keyIndex) => this.postRatchetRequest(participantId, keyIndex));
13183
+ keyProvider.on(KeyProviderEvent.SetKey, (keyInfo, updateCurrentKeyIndex) => this.postKey(keyInfo, updateCurrentKeyIndex !== null && updateCurrentKeyIndex !== void 0 ? updateCurrentKeyIndex : true)).on(KeyProviderEvent.RatchetRequest, (participantId, keyIndex) => this.postRatchetRequest(participantId, keyIndex));
13171
13184
  }
13172
13185
  encryptData(data) {
13173
13186
  return __awaiter(this, void 0, void 0, function* () {
@@ -13228,7 +13241,7 @@ class E2EEManager extends eventsExports.EventEmitter {
13228
13241
  };
13229
13242
  this.worker.postMessage(msg);
13230
13243
  }
13231
- postKey(_ref) {
13244
+ postKey(_ref, updateCurrentKeyIndex) {
13232
13245
  let {
13233
13246
  key,
13234
13247
  participantIdentity,
@@ -13244,7 +13257,8 @@ class E2EEManager extends eventsExports.EventEmitter {
13244
13257
  participantIdentity: participantIdentity,
13245
13258
  isPublisher: participantIdentity === ((_a = this.room) === null || _a === void 0 ? void 0 : _a.localParticipant.identity),
13246
13259
  key,
13247
- keyIndex
13260
+ keyIndex,
13261
+ updateCurrentKeyIndex
13248
13262
  }
13249
13263
  };
13250
13264
  this.worker.postMessage(msg);
@@ -15360,48 +15374,106 @@ function requireLib() {
15360
15374
  lib.parseImageAttributes = parser.parseImageAttributes;
15361
15375
  lib.parseSimulcastStreamList = parser.parseSimulcastStreamList;
15362
15376
  return lib;
15363
- }var libExports = requireLib();function r(r, e, n) {
15364
- var i, t, o;
15365
- void 0 === e && (e = 50), void 0 === n && (n = {});
15366
- var a = null != (i = n.isImmediate) && i,
15367
- u = null != (t = n.callback) && t,
15368
- c = n.maxWait,
15369
- v = Date.now(),
15370
- l = [];
15371
- function f() {
15372
- if (void 0 !== c) {
15373
- var r = Date.now() - v;
15374
- if (r + e >= c) return c - r;
15375
- }
15376
- return e;
15377
- }
15378
- var d = function () {
15379
- var e = [].slice.call(arguments),
15380
- n = this;
15381
- return new Promise(function (i, t) {
15382
- var c = a && void 0 === o;
15383
- if (void 0 !== o && clearTimeout(o), o = setTimeout(function () {
15384
- if (o = void 0, v = Date.now(), !a) {
15385
- var i = r.apply(n, e);
15386
- u && u(i), l.forEach(function (r) {
15387
- return (0, r.resolve)(i);
15388
- }), l = [];
15389
- }
15390
- }, f()), c) {
15391
- var d = r.apply(n, e);
15392
- return u && u(d), i(d);
15393
- }
15394
- l.push({
15395
- resolve: i,
15396
- reject: t
15377
+ }var libExports = requireLib();/**
15378
+ * Originally from ts-debounce (https://github.com/chodorowicz/ts-debounce)
15379
+ * with the following license:
15380
+ *
15381
+ * MIT License
15382
+ *
15383
+ * Copyright (c) 2017 Jakub Chodorowicz
15384
+ *
15385
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
15386
+ * of this software and associated documentation files (the "Software"), to deal
15387
+ * in the Software without restriction, including without limitation the rights
15388
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15389
+ * copies of the Software, and to permit persons to whom the Software is
15390
+ * furnished to do so, subject to the following conditions:
15391
+ *
15392
+ * The above copyright notice and this permission notice shall be included in all
15393
+ * copies or substantial portions of the Software.
15394
+ *
15395
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15396
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15397
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
15398
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
15399
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
15400
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
15401
+ * SOFTWARE.
15402
+ *
15403
+ * Modified to use CriticalTimers for reliable timer execution.
15404
+ */
15405
+ /* eslint-disable @typescript-eslint/no-this-alias, @typescript-eslint/no-unused-expressions, @typescript-eslint/no-shadow */
15406
+ function debounce(func) {
15407
+ let waitMilliseconds = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 50;
15408
+ let options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
15409
+ var _a, _b;
15410
+ let timeoutId;
15411
+ const isImmediate = (_a = options.isImmediate) !== null && _a !== void 0 ? _a : false;
15412
+ const callback = (_b = options.callback) !== null && _b !== void 0 ? _b : false;
15413
+ const maxWait = options.maxWait;
15414
+ let lastInvokeTime = Date.now();
15415
+ let promises = [];
15416
+ function nextInvokeTimeout() {
15417
+ if (maxWait !== undefined) {
15418
+ const timeSinceLastInvocation = Date.now() - lastInvokeTime;
15419
+ if (timeSinceLastInvocation + waitMilliseconds >= maxWait) {
15420
+ return maxWait - timeSinceLastInvocation;
15421
+ }
15422
+ }
15423
+ return waitMilliseconds;
15424
+ }
15425
+ const debouncedFunction = function () {
15426
+ for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
15427
+ args[_key] = arguments[_key];
15428
+ }
15429
+ const context = this;
15430
+ return new Promise((resolve, reject) => {
15431
+ const invokeFunction = function () {
15432
+ timeoutId = undefined;
15433
+ lastInvokeTime = Date.now();
15434
+ if (!isImmediate) {
15435
+ const result = func.apply(context, args);
15436
+ callback && callback(result);
15437
+ // biome-ignore lint/suspicious/useIterableCallbackReturn: vendored code
15438
+ promises.forEach(_ref => {
15439
+ let {
15440
+ resolve
15441
+ } = _ref;
15442
+ return resolve(result);
15443
+ });
15444
+ promises = [];
15445
+ }
15446
+ };
15447
+ const shouldCallNow = isImmediate && timeoutId === undefined;
15448
+ if (timeoutId !== undefined) {
15449
+ CriticalTimers.clearTimeout(timeoutId);
15450
+ }
15451
+ timeoutId = CriticalTimers.setTimeout(invokeFunction, nextInvokeTimeout());
15452
+ if (shouldCallNow) {
15453
+ const result = func.apply(context, args);
15454
+ callback && callback(result);
15455
+ return resolve(result);
15456
+ }
15457
+ promises.push({
15458
+ resolve,
15459
+ reject
15397
15460
  });
15398
15461
  });
15399
15462
  };
15400
- return d.cancel = function (r) {
15401
- void 0 !== o && clearTimeout(o), l.forEach(function (e) {
15402
- return (0, e.reject)(r);
15403
- }), l = [];
15404
- }, d;
15463
+ debouncedFunction.cancel = function (reason) {
15464
+ if (timeoutId !== undefined) {
15465
+ CriticalTimers.clearTimeout(timeoutId);
15466
+ }
15467
+ // biome-ignore lint/suspicious/useIterableCallbackReturn: vendored code
15468
+ promises.forEach(_ref2 => {
15469
+ let {
15470
+ reject
15471
+ } = _ref2;
15472
+ return reject(reason);
15473
+ });
15474
+ promises = [];
15475
+ };
15476
+ return debouncedFunction;
15405
15477
  }/* The svc codec (av1/vp9) would use a very low bitrate at the begining and
15406
15478
  increase slowly by the bandwidth estimator until it reach the target bitrate. The
15407
15479
  process commonly cost more than 10 seconds cause subscriber will get blur video at
@@ -15437,7 +15509,7 @@ class PCTransport extends eventsExports.EventEmitter {
15437
15509
  this.remoteStereoMids = [];
15438
15510
  this.remoteNackMids = [];
15439
15511
  // debounced negotiate interface
15440
- this.negotiate = r(onError => __awaiter(this, void 0, void 0, function* () {
15512
+ this.negotiate = debounce(onError => __awaiter(this, void 0, void 0, function* () {
15441
15513
  this.emit(PCEvents.NegotiationStarted);
15442
15514
  try {
15443
15515
  yield this.createAndSendOffer();
@@ -16764,7 +16836,7 @@ class LocalTrack extends Track {
16764
16836
  this.pendingDeviceChange = false;
16765
16837
  this._isUpstreamPaused = false;
16766
16838
  this.handleTrackMuteEvent = () => this.debouncedTrackMuteHandler().catch(() => this.log.debug('track mute bounce got cancelled by an unmute event', this.logContext));
16767
- this.debouncedTrackMuteHandler = r(() => __awaiter(this, void 0, void 0, function* () {
16839
+ this.debouncedTrackMuteHandler = debounce(() => __awaiter(this, void 0, void 0, function* () {
16768
16840
  yield this.pauseUpstream();
16769
16841
  }), 5000);
16770
16842
  this.handleTrackUnmuteEvent = () => __awaiter(this, void 0, void 0, function* () {
@@ -16836,7 +16908,7 @@ class LocalTrack extends Track {
16836
16908
  getSourceTrackSettings() {
16837
16909
  return this._mediaStreamTrack.getSettings();
16838
16910
  }
16839
- setMediaStreamTrack(newTrack, force) {
16911
+ setMediaStreamTrack(newTrack, force, isUnmuting) {
16840
16912
  return __awaiter(this, void 0, void 0, function* () {
16841
16913
  var _a;
16842
16914
  if (newTrack === this._mediaStreamTrack && !force) {
@@ -16893,7 +16965,8 @@ class LocalTrack extends Track {
16893
16965
  this._mediaStreamTrack = newTrack;
16894
16966
  if (newTrack) {
16895
16967
  // sync muted state with the enabled state of the newly provided track
16896
- this._mediaStreamTrack.enabled = !this.isMuted;
16968
+ // if restarting as part of an unmute, set enabled to true directly to avoid mute cycling
16969
+ this._mediaStreamTrack.enabled = isUnmuting ? true : !this.isMuted;
16897
16970
  // when a valid track is replace, we'd want to start producing
16898
16971
  yield this.resumeUpstream();
16899
16972
  this.attachedElements.forEach(el => {
@@ -17006,7 +17079,7 @@ class LocalTrack extends Track {
17006
17079
  }
17007
17080
  });
17008
17081
  }
17009
- restart(constraints) {
17082
+ restart(constraints, isUnmuting) {
17010
17083
  return __awaiter(this, void 0, void 0, function* () {
17011
17084
  this.manuallyStopped = false;
17012
17085
  const unlock = yield this.trackChangeLock.lock();
@@ -17055,7 +17128,7 @@ class LocalTrack extends Track {
17055
17128
  }
17056
17129
  newTrack.addEventListener('ended', this.handleEnded);
17057
17130
  this.log.debug('re-acquired MediaStreamTrack', this.logContext);
17058
- yield this.setMediaStreamTrack(newTrack);
17131
+ yield this.setMediaStreamTrack(newTrack, false, isUnmuting);
17059
17132
  this._constraints = constraints;
17060
17133
  this.pendingDeviceChange = false;
17061
17134
  this.emit(TrackEvent.Restarted, this);
@@ -17438,7 +17511,7 @@ class LocalTrack extends Track {
17438
17511
  }
17439
17512
  if (this.source === Track.Source.Microphone && (this.stopOnMute || this._mediaStreamTrack.readyState === 'ended' || this.pendingDeviceChange) && !this.isUserProvided) {
17440
17513
  this.log.debug('reacquiring mic track', this.logContext);
17441
- yield this.restartTrack();
17514
+ yield this.restart(undefined, true);
17442
17515
  }
17443
17516
  yield _super.unmute.call(this);
17444
17517
  return this;
@@ -17461,14 +17534,14 @@ class LocalTrack extends Track {
17461
17534
  yield this.restart(constraints);
17462
17535
  });
17463
17536
  }
17464
- restart(constraints) {
17537
+ restart(constraints, isUnmuting) {
17465
17538
  const _super = Object.create(null, {
17466
17539
  restart: {
17467
17540
  get: () => super.restart
17468
17541
  }
17469
17542
  });
17470
17543
  return __awaiter(this, void 0, void 0, function* () {
17471
- const track = yield _super.restart.call(this, constraints);
17544
+ const track = yield _super.restart.call(this, constraints, isUnmuting);
17472
17545
  this.checkForSilence();
17473
17546
  return track;
17474
17547
  });
@@ -18101,7 +18174,7 @@ class LocalVideoTrack extends LocalTrack {
18101
18174
  }
18102
18175
  if (this.source === Track.Source.Camera && !this.isUserProvided) {
18103
18176
  this.log.debug('reacquiring camera track', this.logContext);
18104
- yield this.restartTrack();
18177
+ yield this.restart(undefined, true);
18105
18178
  }
18106
18179
  yield _super.unmute.call(this);
18107
18180
  return this;
@@ -19993,12 +20066,11 @@ function applyUserDataCompat(newObj, oldObj) {
19993
20066
  throw new DataStreamError("Extra chunk(s) received - expected ".concat(this.totalByteSize, " bytes of data total, received ").concat(this.bytesReceived, " bytes"), DataStreamErrorReason.LengthExceeded);
19994
20067
  }
19995
20068
  }
19996
- constructor(info, stream, totalByteSize, outOfBandFailureRejectingFuture) {
20069
+ constructor(info, stream, totalByteSize) {
19997
20070
  this.reader = stream;
19998
20071
  this.totalByteSize = totalByteSize;
19999
20072
  this._info = info;
20000
20073
  this.bytesReceived = 0;
20001
- this.outOfBandFailureRejectingFuture = outOfBandFailureRejectingFuture;
20002
20074
  }
20003
20075
  }
20004
20076
  class ByteStreamReader extends BaseStreamReader {
@@ -20011,50 +20083,44 @@ class ByteStreamReader extends BaseStreamReader {
20011
20083
  }
20012
20084
  [Symbol.asyncIterator]() {
20013
20085
  const reader = this.reader.getReader();
20014
- let rejectingSignalFuture = new Future();
20015
- let activeSignal = null;
20016
- let onAbort = null;
20017
- if (this.signal) {
20018
- const signal = this.signal;
20019
- onAbort = () => {
20020
- var _a;
20021
- (_a = rejectingSignalFuture.reject) === null || _a === void 0 ? void 0 : _a.call(rejectingSignalFuture, signal.reason);
20022
- };
20023
- signal.addEventListener('abort', onAbort);
20024
- activeSignal = signal;
20025
- }
20086
+ // Suppress unhandled rejection on reader.closed — errors are
20087
+ // already propagated through reader.read() to the consumer.
20088
+ reader.closed.catch(() => {});
20026
20089
  const cleanup = () => {
20027
20090
  reader.releaseLock();
20028
- if (activeSignal && onAbort) {
20029
- activeSignal.removeEventListener('abort', onAbort);
20030
- }
20031
20091
  this.signal = undefined;
20032
20092
  };
20033
20093
  return {
20034
20094
  next: () => __awaiter(this, void 0, void 0, function* () {
20035
- var _a, _b;
20036
20095
  try {
20037
- const {
20038
- done,
20039
- value
20040
- } = yield Promise.race([reader.read(),
20041
- // Rejects if this.signal is aborted
20042
- rejectingSignalFuture.promise,
20043
- // Rejects if something external says it should, like a participant disconnecting, etc
20044
- (_b = (_a = this.outOfBandFailureRejectingFuture) === null || _a === void 0 ? void 0 : _a.promise) !== null && _b !== void 0 ? _b : new Promise(() => {
20045
- /* never resolves */
20046
- })]);
20047
- if (done) {
20096
+ const signal = this.signal;
20097
+ if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
20098
+ throw signal.reason;
20099
+ }
20100
+ const result = yield new Promise((resolve, reject) => {
20101
+ if (signal) {
20102
+ const onAbort = () => reject(signal.reason);
20103
+ signal.addEventListener('abort', onAbort, {
20104
+ once: true
20105
+ });
20106
+ reader.read().then(resolve, reject).finally(() => {
20107
+ signal.removeEventListener('abort', onAbort);
20108
+ });
20109
+ } else {
20110
+ reader.read().then(resolve, reject);
20111
+ }
20112
+ });
20113
+ if (result.done) {
20048
20114
  this.validateBytesReceived(true);
20049
20115
  return {
20050
20116
  done: true,
20051
20117
  value: undefined
20052
20118
  };
20053
20119
  } else {
20054
- this.handleChunkReceived(value);
20120
+ this.handleChunkReceived(result.value);
20055
20121
  return {
20056
20122
  done: false,
20057
- value: value.content
20123
+ value: result.value.content
20058
20124
  };
20059
20125
  }
20060
20126
  } catch (err) {
@@ -20125,8 +20191,8 @@ class TextStreamReader extends BaseStreamReader {
20125
20191
  * A TextStreamReader instance can be used as an AsyncIterator that returns the entire string
20126
20192
  * that has been received up to the current point in time.
20127
20193
  */
20128
- constructor(info, stream, totalChunkCount, outOfBandFailureRejectingFuture) {
20129
- super(info, stream, totalChunkCount, outOfBandFailureRejectingFuture);
20194
+ constructor(info, stream, totalChunkCount) {
20195
+ super(info, stream, totalChunkCount);
20130
20196
  this.receivedChunks = new Map();
20131
20197
  }
20132
20198
  handleChunkReceived(chunk) {
@@ -20150,55 +20216,49 @@ class TextStreamReader extends BaseStreamReader {
20150
20216
  */
20151
20217
  [Symbol.asyncIterator]() {
20152
20218
  const reader = this.reader.getReader();
20219
+ // Suppress unhandled rejection on reader.closed — errors are
20220
+ // already propagated through reader.read() to the consumer.
20221
+ reader.closed.catch(() => {});
20153
20222
  const decoder = new TextDecoder('utf-8', {
20154
20223
  fatal: true
20155
20224
  });
20156
- let rejectingSignalFuture = new Future();
20157
- let activeSignal = null;
20158
- let onAbort = null;
20159
- if (this.signal) {
20160
- const signal = this.signal;
20161
- onAbort = () => {
20162
- var _a;
20163
- (_a = rejectingSignalFuture.reject) === null || _a === void 0 ? void 0 : _a.call(rejectingSignalFuture, signal.reason);
20164
- };
20165
- signal.addEventListener('abort', onAbort);
20166
- activeSignal = signal;
20167
- }
20225
+ const signal = this.signal;
20168
20226
  const cleanup = () => {
20169
20227
  reader.releaseLock();
20170
- if (activeSignal && onAbort) {
20171
- activeSignal.removeEventListener('abort', onAbort);
20172
- }
20173
20228
  this.signal = undefined;
20174
20229
  };
20175
20230
  return {
20176
20231
  next: () => __awaiter(this, void 0, void 0, function* () {
20177
- var _a, _b;
20178
20232
  try {
20179
- const {
20180
- done,
20181
- value
20182
- } = yield Promise.race([reader.read(),
20183
- // Rejects if this.signal is aborted
20184
- rejectingSignalFuture.promise,
20185
- // Rejects if something external says it should, like a participant disconnecting, etc
20186
- (_b = (_a = this.outOfBandFailureRejectingFuture) === null || _a === void 0 ? void 0 : _a.promise) !== null && _b !== void 0 ? _b : new Promise(() => {
20187
- /* never resolves */
20188
- })]);
20189
- if (done) {
20233
+ if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
20234
+ throw signal.reason;
20235
+ }
20236
+ const result = yield new Promise((resolve, reject) => {
20237
+ if (signal) {
20238
+ const onAbort = () => reject(signal.reason);
20239
+ signal.addEventListener('abort', onAbort, {
20240
+ once: true
20241
+ });
20242
+ reader.read().then(resolve, reject).finally(() => {
20243
+ signal.removeEventListener('abort', onAbort);
20244
+ });
20245
+ } else {
20246
+ reader.read().then(resolve, reject);
20247
+ }
20248
+ });
20249
+ if (result.done) {
20190
20250
  this.validateBytesReceived(true);
20191
20251
  return {
20192
20252
  done: true,
20193
20253
  value: undefined
20194
20254
  };
20195
20255
  } else {
20196
- this.handleChunkReceived(value);
20256
+ this.handleChunkReceived(result.value);
20197
20257
  let decodedResult;
20198
20258
  try {
20199
- decodedResult = decoder.decode(value.content);
20259
+ decodedResult = decoder.decode(result.value.content);
20200
20260
  } catch (err) {
20201
- throw new DataStreamError("Cannot decode datastream chunk ".concat(value.chunkIndex, " as text: ").concat(err), DataStreamErrorReason.DecodeFailed);
20261
+ throw new DataStreamError("Cannot decode datastream chunk ".concat(result.value.chunkIndex, " as text: ").concat(err), DataStreamErrorReason.DecodeFailed);
20202
20262
  }
20203
20263
  return {
20204
20264
  done: false,
@@ -20295,18 +20355,17 @@ class TextStreamReader extends BaseStreamReader {
20295
20355
  this.textStreamControllers.clear();
20296
20356
  }
20297
20357
  validateParticipantHasNoActiveDataStreams(participantIdentity) {
20298
- var _a, _b, _c, _d;
20299
20358
  // Terminate any in flight data stream receives from the given participant
20300
20359
  const textStreamsBeingSentByDisconnectingParticipant = Array.from(this.textStreamControllers.entries()).filter(entry => entry[1].sendingParticipantIdentity === participantIdentity);
20301
20360
  const byteStreamsBeingSentByDisconnectingParticipant = Array.from(this.byteStreamControllers.entries()).filter(entry => entry[1].sendingParticipantIdentity === participantIdentity);
20302
20361
  if (textStreamsBeingSentByDisconnectingParticipant.length > 0 || byteStreamsBeingSentByDisconnectingParticipant.length > 0) {
20303
20362
  const abnormalEndError = new DataStreamError("Participant ".concat(participantIdentity, " unexpectedly disconnected in the middle of sending data"), DataStreamErrorReason.AbnormalEnd);
20304
20363
  for (const [id, controller] of byteStreamsBeingSentByDisconnectingParticipant) {
20305
- (_b = (_a = controller.outOfBandFailureRejectingFuture).reject) === null || _b === void 0 ? void 0 : _b.call(_a, abnormalEndError);
20364
+ controller.controller.error(abnormalEndError);
20306
20365
  this.byteStreamControllers.delete(id);
20307
20366
  }
20308
20367
  for (const [id, controller] of textStreamsBeingSentByDisconnectingParticipant) {
20309
- (_d = (_c = controller.outOfBandFailureRejectingFuture).reject) === null || _d === void 0 ? void 0 : _d.call(_c, abnormalEndError);
20368
+ controller.controller.error(abnormalEndError);
20310
20369
  this.textStreamControllers.delete(id);
20311
20370
  }
20312
20371
  }
@@ -20335,10 +20394,6 @@ class TextStreamReader extends BaseStreamReader {
20335
20394
  return;
20336
20395
  }
20337
20396
  let streamController;
20338
- const outOfBandFailureRejectingFuture = new Future();
20339
- outOfBandFailureRejectingFuture.promise.catch(err => {
20340
- this.log.error(err);
20341
- });
20342
20397
  const info = {
20343
20398
  id: streamHeader.streamId,
20344
20399
  name: (_a = streamHeader.contentHeader.value.name) !== null && _a !== void 0 ? _a : 'unknown',
@@ -20359,12 +20414,11 @@ class TextStreamReader extends BaseStreamReader {
20359
20414
  info,
20360
20415
  controller: streamController,
20361
20416
  startTime: Date.now(),
20362
- sendingParticipantIdentity: participantIdentity,
20363
- outOfBandFailureRejectingFuture
20417
+ sendingParticipantIdentity: participantIdentity
20364
20418
  });
20365
20419
  }
20366
20420
  });
20367
- streamHandlerCallback(new ByteStreamReader(info, stream, bigIntToNumber(streamHeader.totalLength), outOfBandFailureRejectingFuture), {
20421
+ streamHandlerCallback(new ByteStreamReader(info, stream, bigIntToNumber(streamHeader.totalLength)), {
20368
20422
  identity: participantIdentity
20369
20423
  });
20370
20424
  } else if (streamHeader.contentHeader.case === 'textHeader') {
@@ -20374,10 +20428,6 @@ class TextStreamReader extends BaseStreamReader {
20374
20428
  return;
20375
20429
  }
20376
20430
  let streamController;
20377
- const outOfBandFailureRejectingFuture = new Future();
20378
- outOfBandFailureRejectingFuture.promise.catch(err => {
20379
- this.log.error(err);
20380
- });
20381
20431
  const info = {
20382
20432
  id: streamHeader.streamId,
20383
20433
  mimeType: streamHeader.mimeType,
@@ -20398,12 +20448,11 @@ class TextStreamReader extends BaseStreamReader {
20398
20448
  info,
20399
20449
  controller: streamController,
20400
20450
  startTime: Date.now(),
20401
- sendingParticipantIdentity: participantIdentity,
20402
- outOfBandFailureRejectingFuture
20451
+ sendingParticipantIdentity: participantIdentity
20403
20452
  });
20404
20453
  }
20405
20454
  });
20406
- streamHandlerCallback(new TextStreamReader(info, stream, bigIntToNumber(streamHeader.totalLength), outOfBandFailureRejectingFuture), {
20455
+ streamHandlerCallback(new TextStreamReader(info, stream, bigIntToNumber(streamHeader.totalLength)), {
20407
20456
  identity: participantIdentity
20408
20457
  });
20409
20458
  }
@@ -21083,7 +21132,7 @@ class RemoteVideoTrack extends RemoteTrack {
21083
21132
  }
21084
21133
  this.prevStats = stats;
21085
21134
  });
21086
- this.debouncedHandleResize = r(() => {
21135
+ this.debouncedHandleResize = debounce(() => {
21087
21136
  this.updateDimensions();
21088
21137
  }, REACTION_DELAY);
21089
21138
  this.adaptiveStreamSettings = adaptiveStreamSettings;
@@ -22070,6 +22119,8 @@ class Participant extends eventsExports.EventEmitter {
22070
22119
  this.handleClosing = () => {
22071
22120
  var _a, _b, _c, _d, _e, _f;
22072
22121
  if (this.reconnectFuture) {
22122
+ // @throws-transformer ignore - introduced due to adding Throws into Future, investigate this
22123
+ // further
22073
22124
  this.reconnectFuture.promise.catch(e => this.log.warn(e.message, this.logContext));
22074
22125
  (_b = (_a = this.reconnectFuture) === null || _a === void 0 ? void 0 : _a.reject) === null || _b === void 0 ? void 0 : _b.call(_a, new Error('Got disconnected during reconnection attempt'));
22075
22126
  this.reconnectFuture = undefined;
@@ -24427,7 +24478,7 @@ class Room extends eventsExports.EventEmitter {
24427
24478
  }
24428
24479
  if (nextUrl && !((_b = this.abortController) === null || _b === void 0 ? void 0 : _b.signal.aborted)) {
24429
24480
  this.log.info("Initial connection failed with ConnectionError: ".concat(error.message, ". Retrying with another region: ").concat(nextUrl), this.logContext);
24430
- this.recreateEngine();
24481
+ this.recreateEngine(true);
24431
24482
  yield connectFn(resolve, reject, nextUrl);
24432
24483
  } else {
24433
24484
  this.handleDisconnect(this.options.stopLocalTrackOnUnpublish, getDisconnectReasonFromConnectionError(error));
@@ -24512,7 +24563,7 @@ class Room extends eventsExports.EventEmitter {
24512
24563
  if (this.state === ConnectionState.Reconnecting || this.isResuming || ((_a = this.engine) === null || _a === void 0 ? void 0 : _a.pendingReconnect)) {
24513
24564
  this.log.info('Reconnection attempt replaced by new connection attempt', this.logContext);
24514
24565
  // make sure we close and recreate the existing engine in order to get rid of any potentially ongoing reconnection attempts
24515
- this.recreateEngine();
24566
+ this.recreateEngine(true);
24516
24567
  } else {
24517
24568
  // create engine if previously disconnected
24518
24569
  this.maybeCreateEngine();
@@ -25625,9 +25676,13 @@ class Room extends eventsExports.EventEmitter {
25625
25676
  setupLocalParticipantEvents() {
25626
25677
  this.localParticipant.on(ParticipantEvent.ParticipantMetadataChanged, this.onLocalParticipantMetadataChanged).on(ParticipantEvent.ParticipantNameChanged, this.onLocalParticipantNameChanged).on(ParticipantEvent.AttributesChanged, this.onLocalAttributesChanged).on(ParticipantEvent.TrackMuted, this.onLocalTrackMuted).on(ParticipantEvent.TrackUnmuted, this.onLocalTrackUnmuted).on(ParticipantEvent.LocalTrackPublished, this.onLocalTrackPublished).on(ParticipantEvent.LocalTrackUnpublished, this.onLocalTrackUnpublished).on(ParticipantEvent.ConnectionQualityChanged, this.onLocalConnectionQualityChanged).on(ParticipantEvent.MediaDevicesError, this.onMediaDevicesError).on(ParticipantEvent.AudioStreamAcquired, this.startAudio).on(ParticipantEvent.ChatMessage, this.onLocalChatMessageSent).on(ParticipantEvent.ParticipantPermissionsChanged, this.onLocalParticipantPermissionsChanged);
25627
25678
  }
25628
- recreateEngine() {
25629
- var _a;
25630
- (_a = this.engine) === null || _a === void 0 ? void 0 : _a.close();
25679
+ recreateEngine(sendLeave) {
25680
+ const oldEngine = this.engine;
25681
+ if (sendLeave && oldEngine && !oldEngine.client.isDisconnected) {
25682
+ oldEngine.client.sendLeave().finally(() => oldEngine.close());
25683
+ } else {
25684
+ oldEngine === null || oldEngine === void 0 ? void 0 : oldEngine.close();
25685
+ }
25631
25686
  /* @ts-ignore */
25632
25687
  this.engine = undefined;
25633
25688
  this.isResuming = false;
@@ -26293,7 +26348,39 @@ var DataTrackDepacketizerDropReason;
26293
26348
  DataTrackDepacketizerDropReason[DataTrackDepacketizerDropReason["UnknownFrame"] = 1] = "UnknownFrame";
26294
26349
  DataTrackDepacketizerDropReason[DataTrackDepacketizerDropReason["BufferFull"] = 2] = "BufferFull";
26295
26350
  DataTrackDepacketizerDropReason[DataTrackDepacketizerDropReason["Incomplete"] = 3] = "Incomplete";
26296
- })(DataTrackDepacketizerDropReason || (DataTrackDepacketizerDropReason = {}));var CheckStatus;
26351
+ })(DataTrackDepacketizerDropReason || (DataTrackDepacketizerDropReason = {}));var DataTrackPublishErrorReason;
26352
+ (function (DataTrackPublishErrorReason) {
26353
+ /**
26354
+ * Local participant does not have permission to publish data tracks.
26355
+ *
26356
+ * Ensure the participant's token contains the `canPublishData` grant.
26357
+ */
26358
+ DataTrackPublishErrorReason[DataTrackPublishErrorReason["NotAllowed"] = 0] = "NotAllowed";
26359
+ /** A track with the same name is already published by the local participant. */
26360
+ DataTrackPublishErrorReason[DataTrackPublishErrorReason["DuplicateName"] = 1] = "DuplicateName";
26361
+ /** Request to publish the track took long to complete. */
26362
+ DataTrackPublishErrorReason[DataTrackPublishErrorReason["Timeout"] = 2] = "Timeout";
26363
+ /** No additional data tracks can be published by the local participant. */
26364
+ DataTrackPublishErrorReason[DataTrackPublishErrorReason["LimitReached"] = 3] = "LimitReached";
26365
+ /** Cannot publish data track when the room is disconnected. */
26366
+ DataTrackPublishErrorReason[DataTrackPublishErrorReason["Disconnected"] = 4] = "Disconnected";
26367
+ // NOTE: this was introduced by web / there isn't a corresponding case in the rust version.
26368
+ DataTrackPublishErrorReason[DataTrackPublishErrorReason["Cancelled"] = 5] = "Cancelled";
26369
+ })(DataTrackPublishErrorReason || (DataTrackPublishErrorReason = {}));
26370
+ var DataTrackPushFrameErrorReason;
26371
+ (function (DataTrackPushFrameErrorReason) {
26372
+ /** Track is no longer published. */
26373
+ DataTrackPushFrameErrorReason[DataTrackPushFrameErrorReason["TrackUnpublished"] = 0] = "TrackUnpublished";
26374
+ /** Frame was dropped. */
26375
+ // NOTE: this should become a web specific error, the rust version of this "dropped" error means
26376
+ // something different and will be renamed to "QueueFull".
26377
+ DataTrackPushFrameErrorReason[DataTrackPushFrameErrorReason["Dropped"] = 1] = "Dropped";
26378
+ })(DataTrackPushFrameErrorReason || (DataTrackPushFrameErrorReason = {}));
26379
+ var DataTrackOutgoingPipelineErrorReason;
26380
+ (function (DataTrackOutgoingPipelineErrorReason) {
26381
+ DataTrackOutgoingPipelineErrorReason[DataTrackOutgoingPipelineErrorReason["Packetizer"] = 0] = "Packetizer";
26382
+ DataTrackOutgoingPipelineErrorReason[DataTrackOutgoingPipelineErrorReason["Encryption"] = 1] = "Encryption";
26383
+ })(DataTrackOutgoingPipelineErrorReason || (DataTrackOutgoingPipelineErrorReason = {}));getLogger(LoggerNames.DataTracks);var CheckStatus;
26297
26384
  (function (CheckStatus) {
26298
26385
  CheckStatus[CheckStatus["IDLE"] = 0] = "IDLE";
26299
26386
  CheckStatus[CheckStatus["RUNNING"] = 1] = "RUNNING";
@@ -27320,6 +27407,39 @@ class BaseClient {
27320
27407
  });
27321
27408
  return this.handleResponse(response);
27322
27409
  }
27410
+ /**
27411
+ * Perform GET request that returns binary data (Blob)
27412
+ */
27413
+ async getForBlob(path, params) {
27414
+ const url = new URL(`${this.apiUrl}${path}`);
27415
+ if (params) {
27416
+ Object.entries(params).forEach(([key, value]) => {
27417
+ if (value !== undefined && value !== null) {
27418
+ if (Array.isArray(value)) {
27419
+ value.forEach(v => url.searchParams.append(key, String(v)));
27420
+ }
27421
+ else {
27422
+ url.searchParams.append(key, String(value));
27423
+ }
27424
+ }
27425
+ });
27426
+ }
27427
+ const response = await fetch(url.toString(), {
27428
+ method: 'GET',
27429
+ headers: this.getHeaders(),
27430
+ });
27431
+ if (!response.ok) {
27432
+ let errorData = null;
27433
+ try {
27434
+ errorData = await response.json();
27435
+ }
27436
+ catch {
27437
+ // Not JSON
27438
+ }
27439
+ throw new VoiceAIError(errorData?.error || errorData?.detail || `Request failed with status ${response.status}`, response.status, errorData?.code);
27440
+ }
27441
+ return response.blob();
27442
+ }
27323
27443
  /**
27324
27444
  * Perform POST request
27325
27445
  */
@@ -28282,6 +28402,45 @@ class TTSClient extends BaseClient {
28282
28402
  async deleteVoice(voiceId) {
28283
28403
  return this.httpDelete(`/tts/voice/${encodeURIComponent(voiceId)}`);
28284
28404
  }
28405
+ // ==========================================================================
28406
+ // PRONUNCIATION DICTIONARY MANAGEMENT
28407
+ // ==========================================================================
28408
+ async listPronunciationDictionaries() {
28409
+ return this.get('/tts/pronunciation-dictionaries');
28410
+ }
28411
+ async getPronunciationDictionary(dictionaryId) {
28412
+ return this.get(`/tts/pronunciation-dictionaries/${encodeURIComponent(dictionaryId)}`);
28413
+ }
28414
+ async createPronunciationDictionaryFromFile(options) {
28415
+ const formData = new FormData();
28416
+ formData.append('file', options.file);
28417
+ formData.append('name', options.name);
28418
+ if (options.language !== undefined) {
28419
+ formData.append('language', options.language);
28420
+ }
28421
+ return this.postFormData('/tts/pronunciation-dictionaries/add-from-file', formData);
28422
+ }
28423
+ async createPronunciationDictionaryFromRules(options) {
28424
+ return this.post('/tts/pronunciation-dictionaries/add-from-rules', options);
28425
+ }
28426
+ async updatePronunciationDictionary(dictionaryId, options) {
28427
+ return this.patch(`/tts/pronunciation-dictionaries/${encodeURIComponent(dictionaryId)}`, options);
28428
+ }
28429
+ async deletePronunciationDictionary(dictionaryId) {
28430
+ return this.httpDelete(`/tts/pronunciation-dictionaries/${encodeURIComponent(dictionaryId)}`);
28431
+ }
28432
+ async downloadPronunciationDictionaryVersion(dictionaryId, version) {
28433
+ return this.getForBlob(`/tts/pronunciation-dictionaries/${encodeURIComponent(dictionaryId)}/${version}/download`);
28434
+ }
28435
+ async setPronunciationDictionaryRules(dictionaryId, rules) {
28436
+ return this.post(`/tts/pronunciation-dictionaries/${encodeURIComponent(dictionaryId)}/set-rules`, { rules });
28437
+ }
28438
+ async addPronunciationDictionaryRules(dictionaryId, rules) {
28439
+ return this.post(`/tts/pronunciation-dictionaries/${encodeURIComponent(dictionaryId)}/add-rules`, { rules });
28440
+ }
28441
+ async removePronunciationDictionaryRules(dictionaryId, ruleIds) {
28442
+ return this.post(`/tts/pronunciation-dictionaries/${encodeURIComponent(dictionaryId)}/remove-rules`, { rule_ids: ruleIds });
28443
+ }
28285
28444
  }
28286
28445
 
28287
28446
  /**
@@ -29183,21 +29342,12 @@ class VoiceAI {
29183
29342
  ? '/connection/test-connection-details'
29184
29343
  : '/connection/connection-details';
29185
29344
  const endpoint = `${url}${endpointPath}`;
29186
- if (options.agentId && options.agentConfig) {
29187
- throw new Error('agentId and agentConfig cannot be used together. Use agentId for a saved agent, or agentConfig for an inline agent configuration.');
29188
- }
29189
- if (options.agentConfig && options.agentOverrides) {
29190
- throw new Error('agentConfig and agentOverrides cannot be used together. Use agentOverrides only with agentId.');
29345
+ if (!options.agentId) {
29346
+ throw new Error('agentId is required.');
29191
29347
  }
29192
29348
  const requestData = {};
29193
29349
  if (options.agentId)
29194
29350
  requestData.agent_id = options.agentId;
29195
- if (options.agentConfig) {
29196
- requestData.agent_config = options.agentConfig;
29197
- }
29198
- if (options.agentOverrides) {
29199
- requestData.agent_overrides = options.agentOverrides;
29200
- }
29201
29351
  if (options.dynamicVariables) {
29202
29352
  requestData.dynamic_variables = options.dynamicVariables;
29203
29353
  }