livekit-client 2.22.2 → 2.22.3

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.
Files changed (68) hide show
  1. package/dist/livekit-client.e2ee.worker.js +1 -1
  2. package/dist/livekit-client.e2ee.worker.js.map +1 -1
  3. package/dist/livekit-client.e2ee.worker.mjs +486 -437
  4. package/dist/livekit-client.e2ee.worker.mjs.map +1 -1
  5. package/dist/livekit-client.esm.mjs +398 -100
  6. package/dist/livekit-client.esm.mjs.map +1 -1
  7. package/dist/livekit-client.fm.worker.js +1 -1
  8. package/dist/livekit-client.fm.worker.js.map +1 -1
  9. package/dist/livekit-client.fm.worker.mjs +8 -1
  10. package/dist/livekit-client.fm.worker.mjs.map +1 -1
  11. package/dist/livekit-client.umd.js +1 -1
  12. package/dist/livekit-client.umd.js.map +1 -1
  13. package/dist/src/api/WebSocketStream.d.ts.map +1 -1
  14. package/dist/src/api/utils.d.ts +1 -0
  15. package/dist/src/api/utils.d.ts.map +1 -1
  16. package/dist/src/e2ee/E2eeManager.d.ts +26 -0
  17. package/dist/src/e2ee/E2eeManager.d.ts.map +1 -1
  18. package/dist/src/e2ee/types.d.ts +15 -1
  19. package/dist/src/e2ee/types.d.ts.map +1 -1
  20. package/dist/src/e2ee/worker/DataCryptor.d.ts.map +1 -1
  21. package/dist/src/e2ee/worker/ErrorRateLimiter.d.ts +21 -0
  22. package/dist/src/e2ee/worker/ErrorRateLimiter.d.ts.map +1 -0
  23. package/dist/src/e2ee/worker/FrameCryptor.d.ts +1 -18
  24. package/dist/src/e2ee/worker/FrameCryptor.d.ts.map +1 -1
  25. package/dist/src/logger.d.ts +4 -0
  26. package/dist/src/logger.d.ts.map +1 -1
  27. package/dist/src/room/RTCEngine.d.ts +1 -0
  28. package/dist/src/room/RTCEngine.d.ts.map +1 -1
  29. package/dist/src/room/participant/LocalParticipant.d.ts.map +1 -1
  30. package/dist/src/room/participant/publishUtils.d.ts +16 -0
  31. package/dist/src/room/participant/publishUtils.d.ts.map +1 -1
  32. package/dist/src/room/track/LocalVideoTrack.d.ts +7 -0
  33. package/dist/src/room/track/LocalVideoTrack.d.ts.map +1 -1
  34. package/dist/src/room/track/options.d.ts +1 -1
  35. package/dist/src/room/utils.d.ts +34 -0
  36. package/dist/src/room/utils.d.ts.map +1 -1
  37. package/dist/ts4.2/api/utils.d.ts +1 -0
  38. package/dist/ts4.2/e2ee/E2eeManager.d.ts +26 -0
  39. package/dist/ts4.2/e2ee/types.d.ts +15 -1
  40. package/dist/ts4.2/e2ee/worker/ErrorRateLimiter.d.ts +21 -0
  41. package/dist/ts4.2/e2ee/worker/FrameCryptor.d.ts +1 -18
  42. package/dist/ts4.2/logger.d.ts +4 -0
  43. package/dist/ts4.2/room/RTCEngine.d.ts +1 -0
  44. package/dist/ts4.2/room/participant/publishUtils.d.ts +16 -0
  45. package/dist/ts4.2/room/track/LocalVideoTrack.d.ts +7 -0
  46. package/dist/ts4.2/room/track/options.d.ts +1 -1
  47. package/dist/ts4.2/room/utils.d.ts +34 -0
  48. package/package.json +1 -1
  49. package/src/api/WebSocketStream.ts +3 -8
  50. package/src/api/utils.ts +10 -0
  51. package/src/e2ee/E2eeManager.test.ts +196 -0
  52. package/src/e2ee/E2eeManager.ts +114 -19
  53. package/src/e2ee/types.ts +19 -1
  54. package/src/e2ee/worker/DataCryptor.ts +2 -1
  55. package/src/e2ee/worker/ErrorRateLimiter.test.ts +53 -0
  56. package/src/e2ee/worker/ErrorRateLimiter.ts +52 -0
  57. package/src/e2ee/worker/FrameCryptor.ts +20 -70
  58. package/src/e2ee/worker/e2ee.worker.ts +34 -11
  59. package/src/logger.ts +22 -0
  60. package/src/room/RTCEngine.ts +28 -7
  61. package/src/room/Room.ts +1 -1
  62. package/src/room/participant/LocalParticipant.ts +30 -14
  63. package/src/room/participant/publishUtils.test.ts +133 -0
  64. package/src/room/participant/publishUtils.ts +54 -19
  65. package/src/room/track/LocalVideoTrack.ts +15 -5
  66. package/src/room/track/options.ts +1 -1
  67. package/src/room/utils.test.ts +87 -0
  68. package/src/room/utils.ts +59 -0
@@ -930,7 +930,10 @@ function isScalarZeroValue(type, value) {
930
930
  return value == 0;
931
931
  // Loose comparison matches 0n, 0 and "0"
932
932
  }
933
- }function _arrayLikeToArray(r, a) {
933
+ }function _OverloadYield(e, d) {
934
+ this.v = e, this.k = d;
935
+ }
936
+ function _arrayLikeToArray(r, a) {
934
937
  (null == a || a > r.length) && (a = r.length);
935
938
  for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e];
936
939
  return n;
@@ -1046,7 +1049,61 @@ function _unsupportedIterableToArray(r, a) {
1046
1049
  var t = {}.toString.call(r).slice(8, -1);
1047
1050
  return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0;
1048
1051
  }
1049
- }/* eslint-disable prefer-const,no-case-declarations,@typescript-eslint/restrict-plus-operands */
1052
+ }
1053
+ function _wrapAsyncGenerator(e) {
1054
+ return function () {
1055
+ return new AsyncGenerator(e.apply(this, arguments));
1056
+ };
1057
+ }
1058
+ function AsyncGenerator(e) {
1059
+ var t, n;
1060
+ function resume(t, n) {
1061
+ try {
1062
+ var r = e[t](n),
1063
+ o = r.value,
1064
+ u = o instanceof _OverloadYield;
1065
+ Promise.resolve(u ? o.v : o).then(function (n) {
1066
+ if (u) {
1067
+ var i = "return" === t && o.k ? t : "next";
1068
+ if (!o.k || n.done) return resume(i, n);
1069
+ n = e[i](n).value;
1070
+ }
1071
+ settle(!!r.done, n);
1072
+ }, function (e) {
1073
+ resume("throw", e);
1074
+ });
1075
+ } catch (e) {
1076
+ settle(2, e);
1077
+ }
1078
+ }
1079
+ function settle(e, r) {
1080
+ 2 === e ? t.reject(r) : t.resolve({
1081
+ value: r,
1082
+ done: e
1083
+ }), (t = t.next) ? resume(t.key, t.arg) : n = null;
1084
+ }
1085
+ this._invoke = function (e, r) {
1086
+ return new Promise(function (o, u) {
1087
+ var i = {
1088
+ key: e,
1089
+ arg: r,
1090
+ resolve: o,
1091
+ reject: u,
1092
+ next: null
1093
+ };
1094
+ n ? n = n.next = i : (t = n = i, resume(e, r));
1095
+ });
1096
+ }, "function" != typeof e.return && (this.return = void 0);
1097
+ }
1098
+ AsyncGenerator.prototype["function" == typeof Symbol && Symbol.asyncIterator || "@@asyncIterator"] = function () {
1099
+ return this;
1100
+ }, AsyncGenerator.prototype.next = function (e) {
1101
+ return this._invoke("next", e);
1102
+ }, AsyncGenerator.prototype.throw = function (e) {
1103
+ return this._invoke("throw", e);
1104
+ }, AsyncGenerator.prototype.return = function (e) {
1105
+ return this._invoke("return", e);
1106
+ };/* eslint-disable prefer-const,no-case-declarations,@typescript-eslint/restrict-plus-operands */
1050
1107
  /**
1051
1108
  * Protobuf binary format wire types.
1052
1109
  *
@@ -8625,7 +8682,21 @@ function setLogExtension(extension, logger) {
8625
8682
  logR.setLevel(logR.getLevel());
8626
8683
  });
8627
8684
  }
8628
- const workerLogger = loglevelExports.getLogger(LoggerNames.E2EE);const maxRetryDelay = 7000;
8685
+ const workerLogger = loglevelExports.getLogger(LoggerNames.E2EE);
8686
+ const workerLogLevelListeners = new Set();
8687
+ const originalWorkerSetLevel = workerLogger.setLevel.bind(workerLogger);
8688
+ workerLogger.setLevel = (level, persist) => {
8689
+ originalWorkerSetLevel(level, persist);
8690
+ const numeric = workerLogger.getLevel();
8691
+ workerLogLevelListeners.forEach(cb => cb(numeric));
8692
+ };
8693
+ /** @internal Subscribe to workerLogger level changes (so E2EE workers can be kept in sync). */
8694
+ function onWorkerLogLevelChanged(cb) {
8695
+ workerLogLevelListeners.add(cb);
8696
+ return () => {
8697
+ workerLogLevelListeners.delete(cb);
8698
+ };
8699
+ }const maxRetryDelay = 7000;
8629
8700
  const DEFAULT_RETRY_DELAYS_IN_MS = [0, 300, 2 * 2 * 300, 3 * 3 * 300, 4 * 4 * 300, maxRetryDelay, maxRetryDelay, maxRetryDelay, maxRetryDelay, maxRetryDelay];
8630
8701
  class DefaultReconnectPolicy {
8631
8702
  constructor(retryDelays) {
@@ -12208,7 +12279,7 @@ function getMatch(exp, ua) {
12208
12279
  }
12209
12280
  function getOSVersion(ua) {
12210
12281
  return ua.includes('mac os') ? getMatch(/\(.+?(\d+_\d+(:?_\d+)?)/, ua, 1).replace(/_/g, '.') : undefined;
12211
- }var version$1 = "2.22.2";const version = version$1;
12282
+ }var version$1 = "2.22.3";const version = version$1;
12212
12283
  const protocolVersion = 17;
12213
12284
  /** Initial client protocol. */
12214
12285
  const CLIENT_PROTOCOL_DEFAULT = 0;
@@ -14216,6 +14287,56 @@ function negotiateDependencyDescriptor(transceiver) {
14216
14287
  return false;
14217
14288
  }
14218
14289
  }
14290
+ /**
14291
+ * VP9 and AV1 are published as SVC (a single RTP stream carrying every spatial layer)
14292
+ * by default. They can instead be published as real, rid based simulcast — one
14293
+ * independent stream per rid, each carrying a single spatial layer — when the caller
14294
+ * opts in with `simulcast: true` and a single spatial layer scalability mode (`L1Tx`).
14295
+ *
14296
+ * The SFU has to be told about this: without an explicit
14297
+ * `SimulcastCodec.videoLayerMode` it assumes `MULTIPLE_SPATIAL_LAYERS_PER_STREAM` for
14298
+ * any SVC capable codec.
14299
+ */
14300
+ function isSVCSimulcast(codec, options) {
14301
+ var _a;
14302
+ return isSVCCodec(codec) && !!(options === null || options === void 0 ? void 0 : options.simulcast) && !!((_a = options.scalabilityMode) === null || _a === void 0 ? void 0 : _a.startsWith('L1T'));
14303
+ }
14304
+ /**
14305
+ * Whether the browser reads multiple encodings on an SVC capable codec as *legacy SVC*
14306
+ * rather than as real simulcast.
14307
+ *
14308
+ * Before Chrome M113, supplying more than one encoding for VP9/AV1 selected SVC mode;
14309
+ * only from M113 does libwebrtc treat such encodings as simulcast, and only when each
14310
+ * one carries its own scalabilityMode. Safari (and anything WebKit based, i. e. every
14311
+ * browser on iOS) still uses the old interpretation, as does React Native's libwebrtc.
14312
+ * Announced at https://groups.google.com/g/discuss-webrtc/c/-QQ3pxrl-fw
14313
+ *
14314
+ * Where this is true the rids would not exist on the wire, so VP9/AV1 must be published
14315
+ * as SVC no matter what the caller asked for.
14316
+ */
14317
+ function usesLegacySVCEncodings() {
14318
+ const browser = getBrowser();
14319
+ return isSafariBased() ||
14320
+ // Even tho RN runs M114, it does not produce SVC layers when a single encoding
14321
+ // is provided. So we'll use the legacy SVC specification for now.
14322
+ // TODO: when we upstream libwebrtc, this will need additional verification
14323
+ isReactNative() || (browser === null || browser === void 0 ? void 0 : browser.name) === 'Chrome' && compareVersions(browser.version, '113') < 0;
14324
+ }
14325
+ /**
14326
+ * Last server version that doesn't support vp9/av1 simulcast.
14327
+ */
14328
+ const svcSimulcastMinServerVersion = '1.13.6';
14329
+ /**
14330
+ * Whether the connected server honours `SimulcastCodec.videoLayerMode`, i. e. whether
14331
+ * VP9/AV1 can be published as rid based simulcast. An unknown version is treated as
14332
+ * unsupported so the publish falls back to SVC.
14333
+ */
14334
+ function isSVCSimulcastSupportedByServer(serverVersion) {
14335
+ if (!serverVersion) {
14336
+ return false;
14337
+ }
14338
+ return compareVersions(serverVersion, svcSimulcastMinServerVersion) > 0;
14339
+ }
14219
14340
  function supportsSetSinkId(elm) {
14220
14341
  if (!document || isSafariBased()) {
14221
14342
  return false;
@@ -14824,6 +14945,15 @@ function getAbortReasonAsString(signal) {
14824
14945
  default:
14825
14946
  return 'toString' in reason ? reason.toString() : defaultMessage;
14826
14947
  }
14948
+ }
14949
+ function getErrorDescription(error, errorCategory) {
14950
+ if (error instanceof Error) {
14951
+ if (error.name && error.message) {
14952
+ return "".concat(error.name, ": ").concat(error.message);
14953
+ }
14954
+ return error.name;
14955
+ }
14956
+ return "Encountered unknown ".concat(errorCategory, " error: ").concat(String(error));
14827
14957
  }const ENCRYPTION_ALGORITHM = 'AES-GCM';
14828
14958
  // How many consecutive frames can fail decrypting before a particular key gets marked as invalid
14829
14959
  const DECRYPTION_FAILURE_TOLERANCE = 10;
@@ -15775,10 +15905,18 @@ function isElementInViewport(el, win) {
15775
15905
  * @experimental
15776
15906
  */
15777
15907
  class E2EEManager extends eventsExports.EventEmitter {
15908
+ get logContext() {
15909
+ var _a, _b;
15910
+ return {
15911
+ room: (_a = this.room) === null || _a === void 0 ? void 0 : _a.name,
15912
+ participant: (_b = this.room) === null || _b === void 0 ? void 0 : _b.localParticipant.identity
15913
+ };
15914
+ }
15778
15915
  constructor(options, dcEncryptionEnabled) {
15779
15916
  super();
15780
15917
  this.decryptDataRequests = new Map();
15781
15918
  this.encryptDataRequests = new Map();
15919
+ this.log = getLogger(LoggerNames.E2EE, () => this.logContext);
15782
15920
  this.onWorkerMessage = ev => {
15783
15921
  var _a, _b;
15784
15922
  const _ev$data = ev.data,
@@ -15786,22 +15924,22 @@ class E2EEManager extends eventsExports.EventEmitter {
15786
15924
  data = _ev$data.data;
15787
15925
  switch (kind) {
15788
15926
  case 'error':
15789
- livekitLogger.error(data.error.message);
15790
- // If error has uuid, it's from an async operation (encrypt/decrypt)
15791
- // Reject the corresponding future
15927
+ // If error has uuid, it's from an async operation (encrypt/decrypt).
15928
+ // Reject the corresponding future and let the caller decide how to log/handle;
15929
+ // logging here would duplicate whatever the caller does.
15792
15930
  if (data.uuid) {
15793
15931
  const decryptFuture = this.decryptDataRequests.get(data.uuid);
15794
15932
  if (decryptFuture === null || decryptFuture === void 0 ? void 0 : decryptFuture.reject) {
15795
15933
  decryptFuture.reject(data.error);
15796
- break; // Don't emit general error if it's handled by future
15934
+ break;
15797
15935
  }
15798
15936
  const encryptFuture = this.encryptDataRequests.get(data.uuid);
15799
15937
  if (encryptFuture === null || encryptFuture === void 0 ? void 0 : encryptFuture.reject) {
15800
15938
  encryptFuture.reject(data.error);
15801
- break; // Don't emit general error if it's handled by future
15939
+ break;
15802
15940
  }
15803
15941
  }
15804
- // Emit general error event for unhandled errors
15942
+ this.log.error(data.error.message);
15805
15943
  this.emit(EncryptionEvent.EncryptionError, data.error, data.participantIdentity);
15806
15944
  break;
15807
15945
  case 'initAck':
@@ -15846,10 +15984,13 @@ class E2EEManager extends eventsExports.EventEmitter {
15846
15984
  case 'packetTrailerMetadata':
15847
15985
  this.handleFrameMetadata(data.trackId, data.rtpTimestamp, data.ssrc, data.metadata);
15848
15986
  break;
15987
+ case 'log':
15988
+ workerLogger[data.level](data.msg, data.context);
15989
+ break;
15849
15990
  }
15850
15991
  };
15851
15992
  this.onWorkerError = ev => {
15852
- livekitLogger.error('e2ee worker encountered an error:', {
15993
+ this.log.error('e2ee worker encountered an error:', {
15853
15994
  error: ev.error
15854
15995
  });
15855
15996
  this.emit(EncryptionEvent.EncryptionError, ev.error, undefined);
@@ -15872,7 +16013,7 @@ class E2EEManager extends eventsExports.EventEmitter {
15872
16013
  if (!isE2EESupported()) {
15873
16014
  throw new DeviceUnsupportedError('tried to setup end-to-end encryption on an unsupported browser');
15874
16015
  }
15875
- livekitLogger.info('setting up e2ee');
16016
+ this.log.info('setting up e2ee');
15876
16017
  if (room !== this.room) {
15877
16018
  this.room = room;
15878
16019
  this.setupEventListeners(room, this.keyProvider);
@@ -15885,20 +16026,94 @@ class E2EEManager extends eventsExports.EventEmitter {
15885
16026
  }
15886
16027
  };
15887
16028
  if (this.worker) {
15888
- livekitLogger.info("initializing worker", {
16029
+ this.log.info("initializing worker", {
15889
16030
  worker: this.worker
15890
16031
  });
15891
16032
  this.worker.onmessage = this.onWorkerMessage;
15892
16033
  this.worker.onerror = this.onWorkerError;
15893
16034
  this.worker.postMessage(msg);
16035
+ this.subscribeToLogLevelChanges();
15894
16036
  }
15895
16037
  }
15896
16038
  }
16039
+ /**
16040
+ * Subscribe the current worker to main-thread `workerLogger` level changes,
16041
+ * without strongly retaining `this` or `this.worker` from the module-global
16042
+ * listener Set on the logger. See {@link disposeRegistry}.
16043
+ */
16044
+ subscribeToLogLevelChanges() {
16045
+ var _a;
16046
+ // Guard against duplicate registration on re-setup.
16047
+ (_a = this.unsubscribeLogLevel) === null || _a === void 0 ? void 0 : _a.call(this);
16048
+ let unsub;
16049
+ if (E2EEManager.disposeRegistry) {
16050
+ // Modern engines: hold the worker weakly so the module-global listener Set
16051
+ // on the logger can't retain this manager, and clean up the entry on GC.
16052
+ const workerRef = new WeakRef(this.worker);
16053
+ unsub = onWorkerLogLevelChanged(level => {
16054
+ const worker = workerRef.deref();
16055
+ if (!worker) {
16056
+ unsub === null || unsub === void 0 ? void 0 : unsub();
16057
+ return;
16058
+ }
16059
+ worker.postMessage({
16060
+ kind: 'setLogLevel',
16061
+ data: {
16062
+ level
16063
+ }
16064
+ });
16065
+ });
16066
+ E2EEManager.disposeRegistry.register(this, unsub, this);
16067
+ } else {
16068
+ // Safari <14.1 and similar: no WeakRef. Fall back to a strong reference;
16069
+ // the leak lives until the consumer calls `dispose()`.
16070
+ const worker = this.worker;
16071
+ unsub = onWorkerLogLevelChanged(level => {
16072
+ worker.postMessage({
16073
+ kind: 'setLogLevel',
16074
+ data: {
16075
+ level
16076
+ }
16077
+ });
16078
+ });
16079
+ }
16080
+ this.unsubscribeLogLevel = unsub;
16081
+ }
16082
+ /**
16083
+ * @internal
16084
+ * Release the log-level subscription, reject any pending encrypt/decrypt
16085
+ * futures, and detach the worker message handlers. The worker itself is
16086
+ * caller-owned and is not terminated. Idempotent.
16087
+ */
16088
+ dispose() {
16089
+ var _a, _b, _c;
16090
+ (_a = this.unsubscribeLogLevel) === null || _a === void 0 ? void 0 : _a.call(this);
16091
+ this.unsubscribeLogLevel = undefined;
16092
+ if (E2EEManager.disposeRegistry) {
16093
+ E2EEManager.disposeRegistry.unregister(this);
16094
+ }
16095
+ // Reject pending futures BEFORE detaching worker handlers, so any late
16096
+ // response can't resolve one after we've cut the pipe. Each future's
16097
+ // `onFinally` deletes its own map entry, so both maps drain themselves.
16098
+ // Snapshot before iterating in case a rejection handler mutates the map.
16099
+ const disposalError = new CryptorError('E2EEManager disposed', CryptorErrorReason.InternalError);
16100
+ for (const future of [...this.encryptDataRequests.values()]) {
16101
+ (_b = future.reject) === null || _b === void 0 ? void 0 : _b.call(future, disposalError);
16102
+ }
16103
+ for (const future of [...this.decryptDataRequests.values()]) {
16104
+ (_c = future.reject) === null || _c === void 0 ? void 0 : _c.call(future, disposalError);
16105
+ }
16106
+ if (this.worker) {
16107
+ this.worker.onmessage = null;
16108
+ this.worker.onerror = null;
16109
+ }
16110
+ this.removeAllListeners();
16111
+ }
15897
16112
  /**
15898
16113
  * @internal
15899
16114
  */
15900
16115
  setParticipantCryptorEnabled(enabled, participantIdentity) {
15901
- livekitLogger.debug("set e2ee to ".concat(enabled, " for participant ").concat(participantIdentity));
16116
+ this.log.debug("set e2ee to ".concat(enabled, " for participant ").concat(participantIdentity));
15902
16117
  this.postEnable(enabled, participantIdentity);
15903
16118
  }
15904
16119
  /**
@@ -15906,7 +16121,7 @@ class E2EEManager extends eventsExports.EventEmitter {
15906
16121
  */
15907
16122
  setSifTrailer(trailer) {
15908
16123
  if (!trailer || trailer.length === 0) {
15909
- livekitLogger.warn("ignoring server sent trailer as it's empty");
16124
+ this.log.warn("ignoring server sent trailer as it's empty");
15910
16125
  } else {
15911
16126
  this.postSifTrailer(trailer);
15912
16127
  }
@@ -16113,8 +16328,7 @@ class E2EEManager extends eventsExports.EventEmitter {
16113
16328
  */
16114
16329
  setParticipantCryptorEnabledForPublication(pub, participantIdentity) {
16115
16330
  if (!pub.trackInfo) {
16116
- livekitLogger.warn('skipping e2ee enabled update for publication without trackInfo', {
16117
- participant: participantIdentity,
16331
+ this.log.warn('skipping e2ee enabled update for publication without trackInfo', {
16118
16332
  trackSid: pub.trackSid
16119
16333
  });
16120
16334
  return;
@@ -16134,7 +16348,7 @@ class E2EEManager extends eventsExports.EventEmitter {
16134
16348
  setupE2EESender(track, sender) {
16135
16349
  var _a, _b, _c;
16136
16350
  if (!isLocalTrack(track) || !sender) {
16137
- if (!sender) livekitLogger.warn('early return because sender is not ready');
16351
+ if (!sender) this.log.warn('early return because sender is not ready');
16138
16352
  return;
16139
16353
  }
16140
16354
  this.handleSender(sender, track.mediaStreamID, undefined, isVideoTrack(track) ? (_b = (_a = track.publishOptions) === null || _a === void 0 ? void 0 : _a.frameMetadata) !== null && _b !== void 0 ? _b : (_c = track.publishOptions) === null || _c === void 0 ? void 0 : _c.packetTrailer : undefined);
@@ -16227,7 +16441,7 @@ class E2EEManager extends eventsExports.EventEmitter {
16227
16441
  throw TypeError('local identity needs to be known in order to set up encrypted sender');
16228
16442
  }
16229
16443
  if (isScriptTransformSupportedForWorker()) {
16230
- livekitLogger.info('initialize script transform');
16444
+ this.log.info('initialize script transform');
16231
16445
  const options = {
16232
16446
  kind: 'encode',
16233
16447
  participantIdentity: this.room.localParticipant.identity,
@@ -16239,7 +16453,7 @@ class E2EEManager extends eventsExports.EventEmitter {
16239
16453
  // @ts-ignore
16240
16454
  sender.transform = new RTCRtpScriptTransform(this.worker, options);
16241
16455
  } else {
16242
- livekitLogger.info('initialize encoded streams');
16456
+ this.log.info('initialize encoded streams');
16243
16457
  // @ts-ignore
16244
16458
  const senderStreams = sender.createEncodedStreams();
16245
16459
  const msg = {
@@ -16259,7 +16473,15 @@ class E2EEManager extends eventsExports.EventEmitter {
16259
16473
  // @ts-ignore
16260
16474
  sender[E2EE_FLAG] = true;
16261
16475
  }
16262
- }const MAX_ENTRIES = 300;
16476
+ }
16477
+ /**
16478
+ * Runs a cleanup callback once this manager is garbage collected. Lets the
16479
+ * log-level listener (held in a module-global Set on the main-thread logger)
16480
+ * fall out of scope even when the consumer forgets to call `dispose()`.
16481
+ */
16482
+ E2EEManager.disposeRegistry = typeof FinalizationRegistry !== 'undefined' && typeof WeakRef !== 'undefined' && new FinalizationRegistry(cleanup => {
16483
+ cleanup();
16484
+ });const MAX_ENTRIES = 300;
16263
16485
  /**
16264
16486
  * Caches frame metadata extracted from received video frames,
16265
16487
  * keyed by RTP timestamp so it can be looked up when the frame is displayed.
@@ -18070,9 +18292,9 @@ class WebSocketStream {
18070
18292
  let data = _ref2.data;
18071
18293
  return controller.enqueue(data);
18072
18294
  };
18073
- ws.onerror = e => controller.error(ConnectionError.websocket(e instanceof Error ? "".concat(e.name, ": ").concat(e.message) : "Encountered unknown websocket error: ".concat(String(e))));
18295
+ ws.onerror = e => controller.error(ConnectionError.websocket(getErrorDescription(e, 'websocket')));
18074
18296
  ws.onclose = ev => {
18075
- if (ev.wasClean) {
18297
+ if (ev.wasClean || ev.code === 1000) {
18076
18298
  controller.close();
18077
18299
  } else {
18078
18300
  controller.error(ConnectionError.websocket("WS closed unexpectedly with code ".concat(ev.code)));
@@ -22962,6 +23184,8 @@ function computeVideoEncodings(isScreenShare, width, height, options) {
22962
23184
  const useSimulcast = options === null || options === void 0 ? void 0 : options.simulcast;
22963
23185
  const scalabilityMode = options === null || options === void 0 ? void 0 : options.scalabilityMode;
22964
23186
  const videoCodec = options === null || options === void 0 ? void 0 : options.videoCodec;
23187
+ // VP9/AV1 published as rid based simulcast rather than SVC, see isSVCSimulcast
23188
+ const useSVCSimulcast = isSVCSimulcast(videoCodec, options);
22965
23189
  if (!videoEncoding && !useSimulcast && !scalabilityMode || !width || !height) {
22966
23190
  // when we aren't simulcasting or svc, will need to return a single encoding without
22967
23191
  // capping bandwidth. we always require a encoding for dynacast
@@ -22974,23 +23198,16 @@ function computeVideoEncodings(isScreenShare, width, height, options) {
22974
23198
  }
22975
23199
  const sourceFramerate = videoEncoding.maxFramerate;
22976
23200
  const original = new VideoPreset(width, height, videoEncoding.maxBitrate, videoEncoding.maxFramerate, videoEncoding.priority);
22977
- if (scalabilityMode && isSVCCodec(videoCodec)) {
23201
+ if (scalabilityMode && isSVCCodec(videoCodec) && !useSVCSimulcast) {
22978
23202
  const sm = new ScalabilityMode(scalabilityMode);
22979
23203
  const encodings = [];
22980
23204
  if (sm.spatial > 3) {
22981
23205
  throw new Error("unsupported scalabilityMode: ".concat(scalabilityMode));
22982
23206
  }
22983
- // Before M113 in Chrome, defining multiple encodings with an SVC codec indicated
22984
- // that SVC mode should be used. Safari still works this way.
22985
- // This is a bit confusing but is due to how libwebrtc interpreted the encodings field
22986
- // before M113.
22987
- // Announced here: https://groups.google.com/g/discuss-webrtc/c/-QQ3pxrl-fw?pli=1
23207
+ // Browsers that read multiple encodings on an SVC codec as SVC rather than as
23208
+ // simulcast, see usesLegacySVCEncodings
22988
23209
  const browser = getBrowser();
22989
- if (isSafariBased() ||
22990
- // Even tho RN runs M114, it does not produce SVC layers when a single encoding
22991
- // is provided. So we'll use the legacy SVC specification for now.
22992
- // TODO: when we upstream libwebrtc, this will need additional verification
22993
- isReactNative() || (browser === null || browser === void 0 ? void 0 : browser.name) === 'Chrome' && compareVersions(browser === null || browser === void 0 ? void 0 : browser.version, '113') < 0) {
23210
+ if (usesLegacySVCEncodings()) {
22994
23211
  const bitratesRatio = sm.suffix == 'h' ? 2 : 3;
22995
23212
  // safari 18.4 uses a different svc API that requires scaleResolutionDownBy to be set.
22996
23213
  const requireScale = isSafariSvcApi(browser);
@@ -23026,6 +23243,18 @@ function computeVideoEncodings(isScreenShare, width, height, options) {
23026
23243
  if (!useSimulcast) {
23027
23244
  return [videoEncoding];
23028
23245
  }
23246
+ // Chrome M113+ only treats multiple encodings on an SVC capable codec as real
23247
+ // simulcast when every encoding carries an explicit scalabilityMode next to its
23248
+ // scaleResolutionDownBy. Without it the encodings are interpreted as legacy SVC.
23249
+ const applySVCSimulcastMode = encodings => {
23250
+ if (useSVCSimulcast) {
23251
+ encodings.forEach(encoding => {
23252
+ /* @ts-ignore */
23253
+ encoding.scalabilityMode = scalabilityMode;
23254
+ });
23255
+ }
23256
+ return encodings;
23257
+ };
23029
23258
  let presets;
23030
23259
  if (isScreenShare) {
23031
23260
  presets = (_a = sortPresets(options === null || options === void 0 ? void 0 : options.screenShareSimulcastLayers)) !== null && _a !== void 0 ? _a : defaultSimulcastLayers(isScreenShare, original);
@@ -23051,13 +23280,38 @@ function computeVideoEncodings(isScreenShare, width, height, options) {
23051
23280
  // based on other conditions.
23052
23281
  const size = Math.max(width, height);
23053
23282
  if (size >= 960 && midPreset) {
23054
- return encodingsFromPresets(width, height, [lowPreset, midPreset, original], sourceFramerate);
23283
+ return applySVCSimulcastMode(encodingsFromPresets(width, height, [lowPreset, midPreset, original], sourceFramerate));
23055
23284
  }
23056
23285
  if (size >= 480) {
23057
- return encodingsFromPresets(width, height, [lowPreset, original], sourceFramerate);
23286
+ return applySVCSimulcastMode(encodingsFromPresets(width, height, [lowPreset, original], sourceFramerate));
23058
23287
  }
23059
23288
  }
23060
- return encodingsFromPresets(width, height, [original]);
23289
+ return applySVCSimulcastMode(encodingsFromPresets(width, height, [original]));
23290
+ }
23291
+ /**
23292
+ * Bitrate to hint to the bandwidth estimator through `x-google-start-bitrate`, so that
23293
+ * a publish does not spend its first seconds ramping up from a very low rate.
23294
+ *
23295
+ * It has to be the total the encoder will put on the wire, which means picking the
23296
+ * encoding that carries the inclusive bitrate:
23297
+ * - SVC publishes a single stream with the layers built in. `encodings[0]` holds the
23298
+ * full bitrate — the legacy SVC shape orders its encodings `f`..`q`, so that holds
23299
+ * for both SVC shapes.
23300
+ * - Simulcast publishes independent streams ordered `q`..`f`, so the total is the sum.
23301
+ * This includes VP9/AV1 published as rid based simulcast, where `encodings[0]` is
23302
+ * the *smallest* layer even though the codec is SVC capable.
23303
+ *
23304
+ * @internal
23305
+ */
23306
+ function computeStartTargetBitrate(codec, options, encodings) {
23307
+ var _a, _b;
23308
+ if (isSVCCodec(codec) && !isSVCSimulcast(codec, options)) {
23309
+ return (_b = (_a = encodings[0]) === null || _a === void 0 ? void 0 : _a.maxBitrate) !== null && _b !== void 0 ? _b : 0;
23310
+ }
23311
+ return encodings.reduce((sum, enc) => {
23312
+ var _a;
23313
+ return sum + ((_a = enc.maxBitrate) !== null && _a !== void 0 ? _a : 0);
23314
+ }, 0);
23061
23315
  }
23062
23316
  function computeTrackBackupEncodings(track, videoCodec, opts) {
23063
23317
  var _a, _b, _c, _d;
@@ -23511,6 +23765,15 @@ class LocalVideoTrack extends LocalTrack {
23511
23765
  return items;
23512
23766
  });
23513
23767
  }
23768
+ /**
23769
+ * Whether `codec` is being published as SVC (a single stream carrying all spatial
23770
+ * layers) as opposed to rid based simulcast. VP9/AV1 are SVC unless the publisher
23771
+ * opted into simulcast, in which case each rid is an independent stream and the
23772
+ * layers can be enabled/disabled individually.
23773
+ */
23774
+ isSvcPublish(codec) {
23775
+ return isSVCCodec(codec) && !isSVCSimulcast(codec, this.publishOptions);
23776
+ }
23514
23777
  setPublishingQuality(maxQuality) {
23515
23778
  const qualities = [];
23516
23779
  for (let q = VideoQuality.LOW; q <= VideoQuality.HIGH; q += 1) {
@@ -23520,7 +23783,7 @@ class LocalVideoTrack extends LocalTrack {
23520
23783
  }));
23521
23784
  }
23522
23785
  this.log.debug("setting publishing quality. max quality ".concat(maxQuality), this.logContext);
23523
- this.setPublishingLayers(isSVCCodec(this.codec), qualities);
23786
+ this.setPublishingLayers(this.isSvcPublish(this.codec), qualities);
23524
23787
  }
23525
23788
  restartTrack(options) {
23526
23789
  return __awaiter(this, void 0, void 0, function* () {
@@ -23785,7 +24048,7 @@ class LocalVideoTrack extends LocalTrack {
23785
24048
  }));
23786
24049
  // only enable simulcast codec for preference codec setted
23787
24050
  if (!this.codec && codecs.length > 0) {
23788
- yield this.setPublishingLayers(isSVCCodec(codecs[0].codec), codecs[0].qualities);
24051
+ yield this.setPublishingLayers(this.isSvcPublish(codecs[0].codec), codecs[0].qualities);
23789
24052
  return [];
23790
24053
  }
23791
24054
  this.subscribedCodecs = codecs;
@@ -23796,7 +24059,7 @@ class LocalVideoTrack extends LocalTrack {
23796
24059
  _a = false;
23797
24060
  const codec = _d;
23798
24061
  if (!this.codec || this.codec === codec.codec) {
23799
- yield this.setPublishingLayers(isSVCCodec(codec.codec), codec.qualities);
24062
+ yield this.setPublishingLayers(this.isSvcPublish(codec.codec), codec.qualities);
23800
24063
  } else {
23801
24064
  const simulcastCodecInfo = this.simulcastCodecs.get(codec.codec);
23802
24065
  this.log.debug("try setPublishingCodec for ".concat(codec.codec), Object.assign(Object.assign({}, this.logContext), {
@@ -23811,7 +24074,7 @@ class LocalVideoTrack extends LocalTrack {
23811
24074
  }
23812
24075
  } else if (simulcastCodecInfo.encodings) {
23813
24076
  this.log.debug("try setPublishingLayersForSender ".concat(codec.codec), this.logContext);
23814
- yield setPublishingLayersForSender(simulcastCodecInfo.sender, simulcastCodecInfo.encodings, codec.qualities, this.senderLock, isSVCCodec(codec.codec), this.log, this.logContext);
24077
+ yield setPublishingLayersForSender(simulcastCodecInfo.sender, simulcastCodecInfo.encodings, codec.qualities, this.senderLock, this.isSvcPublish(codec.codec), this.log, this.logContext);
23815
24078
  }
23816
24079
  }
23817
24080
  }
@@ -24071,6 +24334,10 @@ class RTCEngine extends eventsExports.EventEmitter {
24071
24334
  get pendingReconnect() {
24072
24335
  return !!this.reconnectTimeout;
24073
24336
  }
24337
+ get serverVersion() {
24338
+ var _a, _b, _c;
24339
+ return ((_b = (_a = this.latestJoinResponse) === null || _a === void 0 ? void 0 : _a.serverInfo) === null || _b === void 0 ? void 0 : _b.version) || ((_c = this.latestJoinResponse) === null || _c === void 0 ? void 0 : _c.serverVersion) || undefined;
24340
+ }
24074
24341
  get reliableChannel() {
24075
24342
  return this.dataChannels.reliable;
24076
24343
  }
@@ -24123,7 +24390,7 @@ class RTCEngine extends eventsExports.EventEmitter {
24123
24390
  }();
24124
24391
  });
24125
24392
  this.handleDataMessage = message => __awaiter(this, void 0, void 0, function* () {
24126
- var _a, _b, _c, _d, _e;
24393
+ var _a, _b, _c, _d;
24127
24394
  // make sure to respect incoming data message order by processing message events one after the other
24128
24395
  const unlock = yield this.dataProcessLock.lock();
24129
24396
  try {
@@ -24148,20 +24415,29 @@ class RTCEngine extends eventsExports.EventEmitter {
24148
24415
  this.log.error('Received encrypted packet but E2EE not set up');
24149
24416
  return;
24150
24417
  }
24151
- const decryptedData = yield (_c = this.e2eeManager) === null || _c === void 0 ? void 0 : _c.handleEncryptedData(dp.value.value.encryptedValue, dp.value.value.iv, dp.participantIdentity, dp.value.value.keyIndex);
24418
+ let decryptedData;
24419
+ try {
24420
+ decryptedData = yield this.e2eeManager.handleEncryptedData(dp.value.value.encryptedValue, dp.value.value.iv, dp.participantIdentity, dp.value.value.keyIndex);
24421
+ } catch (err) {
24422
+ this.log.debug('failed to decrypt data packet', {
24423
+ error: err,
24424
+ participantIdentity: dp.participantIdentity
24425
+ });
24426
+ return;
24427
+ }
24152
24428
  const decryptedPacket = EncryptedPacketPayload.fromBinary(decryptedData.payload);
24153
24429
  const newDp = new DataPacket({
24154
24430
  value: decryptedPacket.value,
24155
24431
  participantIdentity: dp.participantIdentity,
24156
24432
  participantSid: dp.participantSid
24157
24433
  });
24158
- if (((_d = newDp.value) === null || _d === void 0 ? void 0 : _d.case) === 'user') {
24434
+ if (((_c = newDp.value) === null || _c === void 0 ? void 0 : _c.case) === 'user') {
24159
24435
  // compatibility
24160
24436
  applyUserDataCompat(newDp, newDp.value.value);
24161
24437
  }
24162
24438
  this.emit(EngineEvent.DataPacketReceived, newDp, dp.value.value.encryptionType);
24163
24439
  } else {
24164
- if (((_e = dp.value) === null || _e === void 0 ? void 0 : _e.case) === 'user') {
24440
+ if (((_d = dp.value) === null || _d === void 0 ? void 0 : _d.case) === 'user') {
24165
24441
  // compatibility
24166
24442
  applyUserDataCompat(dp, dp.value.value);
24167
24443
  }
@@ -24662,7 +24938,11 @@ class RTCEngine extends eventsExports.EventEmitter {
24662
24938
  sdp: sd.sdp,
24663
24939
  midToTrackId
24664
24940
  });
24665
- this.midToTrackId = midToTrackId;
24941
+ // in dual PC mode the publisher answer carries no mapping (the server's publisher
24942
+ // transport has no sending tracks) and must not clobber the subscriber offer mapping
24943
+ if (this.pcManager.mode === 'publisher-only') {
24944
+ this.midToTrackId = midToTrackId;
24945
+ }
24666
24946
  yield this.pcManager.setPublisherAnswer(sd, offerId);
24667
24947
  });
24668
24948
  // add candidate on trickle
@@ -31773,7 +32053,7 @@ class Participant extends eventsExports.EventEmitter {
31773
32053
  }
31774
32054
  publish(track, opts, isStereo) {
31775
32055
  return __awaiter(this, void 0, void 0, function* () {
31776
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
32056
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
31777
32057
  if (!this.hasPermissionsToPublish(track)) {
31778
32058
  throw new PublishTrackError('failed to publish track, insufficient permissions', 403);
31779
32059
  }
@@ -31876,7 +32156,12 @@ class Participant extends eventsExports.EventEmitter {
31876
32156
  req.height = dims.height;
31877
32157
  // for svc codecs, disable simulcast and use vp8 for backup codec
31878
32158
  if (isLocalVideoTrack(track)) {
31879
- if (isSVCCodec(videoCodec)) {
32159
+ if (isSVCSimulcast(videoCodec, opts) && (usesLegacySVCEncodings() || !isSVCSimulcastSupportedByServer((_e = this.engine) === null || _e === void 0 ? void 0 : _e.serverVersion))) {
32160
+ opts.simulcast = false;
32161
+ this.log.info('SVC simulcast is not supported, disabling simulcast.', getLogContextFromTrack(track));
32162
+ }
32163
+ const svcSimulcast = isSVCSimulcast(videoCodec, opts);
32164
+ if (isSVCCodec(videoCodec) && !svcSimulcast) {
31880
32165
  if (track.source === Track.Source.ScreenShare) {
31881
32166
  // vp9 svc with screenshare cannot encode multiple spatial layers
31882
32167
  // doing so reduces publish resolution to minimal resolution
@@ -31892,12 +32177,16 @@ class Participant extends eventsExports.EventEmitter {
31892
32177
  }
31893
32178
  }
31894
32179
  // set scalabilityMode to 'L3T3_KEY' by default
31895
- opts.scalabilityMode = (_e = opts.scalabilityMode) !== null && _e !== void 0 ? _e : 'L3T3_KEY';
32180
+ opts.scalabilityMode = (_f = opts.scalabilityMode) !== null && _f !== void 0 ? _f : 'L3T3_KEY';
31896
32181
  }
31897
- req.simulcastCodecs = [new SimulcastCodec({
32182
+ const primaryCodec = new SimulcastCodec({
31898
32183
  codec: videoCodec,
31899
32184
  cid: track.mediaStreamTrack.id
31900
- })];
32185
+ });
32186
+ if (svcSimulcast) {
32187
+ primaryCodec.videoLayerMode = VideoLayer_Mode.ONE_SPATIAL_LAYER_PER_STREAM;
32188
+ }
32189
+ req.simulcastCodecs = [primaryCodec];
31901
32190
  // set up backup
31902
32191
  if (opts.backupCodec === true) {
31903
32192
  opts.backupCodec = {
@@ -31918,19 +32207,19 @@ class Participant extends eventsExports.EventEmitter {
31918
32207
  }
31919
32208
  }
31920
32209
  encodings = computeVideoEncodings(track.source === Track.Source.ScreenShare, req.width, req.height, opts);
31921
- req.layers = videoLayersFromEncodings(req.width, req.height, encodings, isSVCCodec(opts.videoCodec));
32210
+ req.layers = videoLayersFromEncodings(req.width, req.height, encodings, isSVCCodec(opts.videoCodec) && !isSVCSimulcast(opts.videoCodec, opts));
31922
32211
  } else if (track.kind === Track.Kind.Audio) {
31923
32212
  encodings = [{
31924
- maxBitrate: (_f = opts.audioPreset) === null || _f === void 0 ? void 0 : _f.maxBitrate,
31925
- priority: (_h = (_g = opts.audioPreset) === null || _g === void 0 ? void 0 : _g.priority) !== null && _h !== void 0 ? _h : 'high',
31926
- networkPriority: (_k = (_j = opts.audioPreset) === null || _j === void 0 ? void 0 : _j.priority) !== null && _k !== void 0 ? _k : 'high'
32213
+ maxBitrate: (_g = opts.audioPreset) === null || _g === void 0 ? void 0 : _g.maxBitrate,
32214
+ priority: (_j = (_h = opts.audioPreset) === null || _h === void 0 ? void 0 : _h.priority) !== null && _j !== void 0 ? _j : 'high',
32215
+ networkPriority: (_l = (_k = opts.audioPreset) === null || _k === void 0 ? void 0 : _k.priority) !== null && _l !== void 0 ? _l : 'high'
31927
32216
  }];
31928
32217
  }
31929
32218
  if (!this.engine || this.engine.isClosed) {
31930
32219
  throw new UnexpectedConnectionState('cannot publish track when not connected');
31931
32220
  }
31932
32221
  const negotiate = () => __awaiter(this, void 0, void 0, function* () {
31933
- var _a, _b, _c, _d;
32222
+ var _a, _b;
31934
32223
  if (!this.engine.pcManager) {
31935
32224
  throw new UnexpectedConnectionState('pcManager is not ready');
31936
32225
  }
@@ -31967,13 +32256,9 @@ class Participant extends eventsExports.EventEmitter {
31967
32256
  });
31968
32257
  }
31969
32258
  } else if (track.codec && isVideoCodec(track.codec)) {
31970
- // Apply start bitrate for all video codecs to prevent initial blurriness.
31971
- // - SVC codecs: use first encoding's bitrate (single stream with built-in layers)
31972
- // - Simulcast: sum all encoding bitrates (independent streams, BWE needs total)
31973
- const targetBitrate = isSVCCodec(track.codec) ? (_d = (_c = encodings[0]) === null || _c === void 0 ? void 0 : _c.maxBitrate) !== null && _d !== void 0 ? _d : 0 : encodings.reduce((sum, enc) => {
31974
- var _a;
31975
- return sum + ((_a = enc.maxBitrate) !== null && _a !== void 0 ? _a : 0);
31976
- }, 0);
32259
+ // Apply start bitrate for all video codecs to prevent initial blurriness,
32260
+ // see computeStartTargetBitrate
32261
+ const targetBitrate = computeStartTargetBitrate(track.codec, opts, encodings);
31977
32262
  if (targetBitrate > 0) {
31978
32263
  this.engine.pcManager.publisher.setTrackCodecBitrate({
31979
32264
  cid: req.cid,
@@ -34212,8 +34497,8 @@ class Room extends eventsExports.EventEmitter {
34212
34497
  });
34213
34498
  this.registerRpcDataStreamHandler();
34214
34499
  this.rpcClientManager = new RpcClientManager(this.log, this.outgoingDataStreamManager, this.getRemoteParticipantClientProtocol, () => {
34215
- var _a, _b;
34216
- return (_b = (_a = this.engine.latestJoinResponse) === null || _a === void 0 ? void 0 : _a.serverInfo) === null || _b === void 0 ? void 0 : _b.version;
34500
+ var _a;
34501
+ return (_a = this.engine) === null || _a === void 0 ? void 0 : _a.serverVersion;
34217
34502
  });
34218
34503
  this.rpcClientManager.on('sendDataPacket', _ref2 => {
34219
34504
  let packet = _ref2.packet;
@@ -36368,33 +36653,10 @@ class TokenSourceFixed {}
36368
36653
  * and {@link TokenSourceCustom}.
36369
36654
  */
36370
36655
  class TokenSourceConfigurable {}new TextEncoder();
36371
- const decoder = new TextDecoder();function decodeBase64(encoded) {
36372
- if (Uint8Array.fromBase64) {
36373
- return Uint8Array.fromBase64(encoded);
36374
- }
36375
- const binary = atob(encoded);
36376
- const bytes = new Uint8Array(binary.length);
36377
- for (let i = 0; i < binary.length; i++) {
36378
- bytes[i] = binary.charCodeAt(i);
36379
- }
36380
- return bytes;
36381
- }function decode(input) {
36382
- if (Uint8Array.fromBase64) {
36383
- return Uint8Array.fromBase64(typeof input === 'string' ? input : decoder.decode(input), {
36384
- alphabet: 'base64url'
36385
- });
36386
- }
36387
- let encoded = input;
36388
- if (encoded instanceof Uint8Array) {
36389
- encoded = decoder.decode(encoded);
36390
- }
36391
- encoded = encoded.replace(/-/g, '+').replace(/_/g, '/');
36392
- try {
36393
- return decodeBase64(encoded);
36394
- } catch (_unused) {
36395
- throw new TypeError('The input to be decoded is not correctly encoded.');
36396
- }
36397
- }class JOSEError extends Error {
36656
+ const decoder = new TextDecoder();
36657
+ const strictDecoder = new TextDecoder('utf-8', {
36658
+ fatal: true
36659
+ });class JOSEError extends Error {
36398
36660
  constructor(message, options) {
36399
36661
  var _Error$captureStackTr;
36400
36662
  super(message, options);
@@ -36518,7 +36780,7 @@ class JWKSMultipleMatchingKeys extends JOSEError {
36518
36780
  let message = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'multiple matching keys found in the JSON Web Key Set';
36519
36781
  let options = arguments.length > 1 ? arguments[1] : undefined;
36520
36782
  super(message, options);
36521
- _defineProperty(this, Symbol.asyncIterator, void 0);
36783
+ _defineProperty(this, Symbol.asyncIterator, _wrapAsyncGenerator(function* () {}));
36522
36784
  _defineProperty(this, "code", 'ERR_JWKS_MULTIPLE_MATCHING_KEYS');
36523
36785
  }
36524
36786
  }
@@ -36540,19 +36802,55 @@ class JWSSignatureVerificationFailed extends JOSEError {
36540
36802
  _defineProperty(this, "code", 'ERR_JWS_SIGNATURE_VERIFICATION_FAILED');
36541
36803
  }
36542
36804
  }
36543
- _defineProperty(JWSSignatureVerificationFailed, "code", 'ERR_JWS_SIGNATURE_VERIFICATION_FAILED');const isObjectLike = value => typeof value === 'object' && value !== null;
36544
- function isObject(input) {
36545
- if (!isObjectLike(input) || Object.prototype.toString.call(input) !== '[object Object]') {
36805
+ _defineProperty(JWSSignatureVerificationFailed, "code", 'ERR_JWS_SIGNATURE_VERIFICATION_FAILED');function decodeBase64(encoded) {
36806
+ if (Uint8Array.fromBase64) {
36807
+ return Uint8Array.fromBase64(encoded);
36808
+ }
36809
+ const binary = atob(encoded);
36810
+ const bytes = new Uint8Array(binary.length);
36811
+ for (let i = 0; i < binary.length; i++) {
36812
+ bytes[i] = binary.charCodeAt(i);
36813
+ }
36814
+ return bytes;
36815
+ }const invalid = 'The input to be decoded is not correctly encoded.';
36816
+ function decode(input) {
36817
+ if (Uint8Array.fromBase64) {
36818
+ try {
36819
+ return Uint8Array.fromBase64(typeof input === 'string' ? input : decoder.decode(input), {
36820
+ alphabet: 'base64url'
36821
+ });
36822
+ } catch (cause) {
36823
+ throw new TypeError(invalid, {
36824
+ cause
36825
+ });
36826
+ }
36827
+ }
36828
+ let encoded = input;
36829
+ if (encoded instanceof Uint8Array) {
36830
+ encoded = decoder.decode(encoded);
36831
+ }
36832
+ if (encoded.includes('+') || encoded.includes('/')) {
36833
+ throw new TypeError(invalid);
36834
+ }
36835
+ encoded = encoded.replace(/-/g, '+').replace(/_/g, '/');
36836
+ try {
36837
+ return decodeBase64(encoded);
36838
+ } catch (_unused) {
36839
+ throw new TypeError(invalid);
36840
+ }
36841
+ }function isObject(input) {
36842
+ if (typeof input !== 'object' || input === null || Object.prototype.toString.call(input) !== '[object Object]') {
36546
36843
  return false;
36547
36844
  }
36548
- if (Object.getPrototypeOf(input) === null) {
36845
+ const prototype = Object.getPrototypeOf(input);
36846
+ if (prototype === null) {
36549
36847
  return true;
36550
36848
  }
36551
- let proto = input;
36849
+ let proto = prototype;
36552
36850
  while (Object.getPrototypeOf(proto) !== null) {
36553
36851
  proto = Object.getPrototypeOf(proto);
36554
36852
  }
36555
- return Object.getPrototypeOf(input) === proto;
36853
+ return prototype === proto;
36556
36854
  }function decodeJwt(jwt) {
36557
36855
  if (typeof jwt !== 'string') throw new JWTInvalid('JWTs must use Compact JWS serialization, JWT must be a string');
36558
36856
  const _jwt$split = jwt.split('.'),
@@ -36569,7 +36867,7 @@ function isObject(input) {
36569
36867
  }
36570
36868
  let result;
36571
36869
  try {
36572
- result = JSON.parse(decoder.decode(decoded));
36870
+ result = JSON.parse(strictDecoder.decode(decoded));
36573
36871
  } catch (_unused2) {
36574
36872
  throw new JWTInvalid('Failed to parse the decoded payload as JSON');
36575
36873
  }