matrix-js-sdk 42.1.0 → 42.2.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.
Files changed (154) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/lib/@types/beacon.d.ts +1 -1
  3. package/lib/@types/beacon.js +1 -1
  4. package/lib/@types/beacon.js.map +1 -1
  5. package/lib/@types/extensible_events.d.ts.map +1 -1
  6. package/lib/@types/extensible_events.js.map +1 -1
  7. package/lib/autodiscovery.js.map +1 -1
  8. package/lib/browser-index.js.map +1 -1
  9. package/lib/client.d.ts +12 -5
  10. package/lib/client.d.ts.map +1 -1
  11. package/lib/client.js +23 -26
  12. package/lib/client.js.map +1 -1
  13. package/lib/common-crypto/key-passphrase.js +1 -1
  14. package/lib/common-crypto/key-passphrase.js.map +1 -1
  15. package/lib/crypto/store/indexeddb-crypto-store-backend.js +2 -1
  16. package/lib/crypto/store/indexeddb-crypto-store-backend.js.map +1 -1
  17. package/lib/crypto/store/indexeddb-crypto-store.d.ts.map +1 -1
  18. package/lib/crypto/store/indexeddb-crypto-store.js +1 -1
  19. package/lib/crypto/store/indexeddb-crypto-store.js.map +1 -1
  20. package/lib/crypto/store/memory-crypto-store.js.map +1 -1
  21. package/lib/embedded.d.ts +16 -0
  22. package/lib/embedded.d.ts.map +1 -1
  23. package/lib/embedded.js +19 -6
  24. package/lib/embedded.js.map +1 -1
  25. package/lib/matrixrtc/MatrixRTCSession.js.map +1 -1
  26. package/lib/matrixrtc/MembershipManager.js.map +1 -1
  27. package/lib/matrixrtc/MembershipManagerActionScheduler.js.map +1 -1
  28. package/lib/matrixrtc/RTCEncryptionManager.js.map +1 -1
  29. package/lib/matrixrtc/ToDeviceKeyTransport.js.map +1 -1
  30. package/lib/matrixrtc/membershipData/rtc.js.map +1 -1
  31. package/lib/matrixrtc/utils.d.ts +0 -1
  32. package/lib/matrixrtc/utils.d.ts.map +1 -1
  33. package/lib/matrixrtc/utils.js +0 -1
  34. package/lib/matrixrtc/utils.js.map +1 -1
  35. package/lib/models/event-timeline-set.js +3 -3
  36. package/lib/models/event-timeline-set.js.map +1 -1
  37. package/lib/models/event.d.ts.map +1 -1
  38. package/lib/models/event.js.map +1 -1
  39. package/lib/models/invites-ignorer.js.map +1 -1
  40. package/lib/models/poll.js.map +1 -1
  41. package/lib/models/read-receipt.js.map +1 -1
  42. package/lib/models/relations-container.d.ts +10 -0
  43. package/lib/models/relations-container.d.ts.map +1 -1
  44. package/lib/models/relations-container.js +39 -17
  45. package/lib/models/relations-container.js.map +1 -1
  46. package/lib/models/relations.js +1 -1
  47. package/lib/models/relations.js.map +1 -1
  48. package/lib/models/room.js +3 -3
  49. package/lib/models/room.js.map +1 -1
  50. package/lib/models/thread.d.ts +3 -0
  51. package/lib/models/thread.d.ts.map +1 -1
  52. package/lib/models/thread.js +36 -3
  53. package/lib/models/thread.js.map +1 -1
  54. package/lib/oauth/authorize.js +1 -1
  55. package/lib/oauth/authorize.js.map +1 -1
  56. package/lib/oauth/index.js +4 -2
  57. package/lib/oauth/index.js.map +1 -1
  58. package/lib/pollingCachedValue.d.ts +77 -0
  59. package/lib/pollingCachedValue.d.ts.map +1 -0
  60. package/lib/pollingCachedValue.js +160 -0
  61. package/lib/pollingCachedValue.js.map +1 -0
  62. package/lib/pushprocessor.js.map +1 -1
  63. package/lib/receipt-accumulator.d.ts.map +1 -1
  64. package/lib/receipt-accumulator.js.map +1 -1
  65. package/lib/rendezvous/MSC4108SignInWithQR.d.ts.map +1 -1
  66. package/lib/rendezvous/MSC4108SignInWithQR.js +2 -3
  67. package/lib/rendezvous/MSC4108SignInWithQR.js.map +1 -1
  68. package/lib/rtcTransportsCachedValue.d.ts +9 -0
  69. package/lib/rtcTransportsCachedValue.d.ts.map +1 -0
  70. package/lib/rtcTransportsCachedValue.js +38 -0
  71. package/lib/rtcTransportsCachedValue.js.map +1 -0
  72. package/lib/rust-crypto/PerSessionKeyBackupDownloader.js.map +1 -1
  73. package/lib/rust-crypto/backup.d.ts +2 -3
  74. package/lib/rust-crypto/backup.d.ts.map +1 -1
  75. package/lib/rust-crypto/backup.js.map +1 -1
  76. package/lib/rust-crypto/index.d.ts +10 -4
  77. package/lib/rust-crypto/index.d.ts.map +1 -1
  78. package/lib/rust-crypto/index.js +20 -3
  79. package/lib/rust-crypto/index.js.map +1 -1
  80. package/lib/rust-crypto/libolm_migration.js.map +1 -1
  81. package/lib/rust-crypto/rust-crypto.js.map +1 -1
  82. package/lib/sliding-sync-sdk.js.map +1 -1
  83. package/lib/sliding-sync.js.map +1 -1
  84. package/lib/store/indexeddb-local-backend.js +1 -1
  85. package/lib/store/indexeddb-local-backend.js.map +1 -1
  86. package/lib/store/indexeddb-store-worker.d.ts.map +1 -1
  87. package/lib/store/indexeddb-store-worker.js +1 -0
  88. package/lib/store/indexeddb-store-worker.js.map +1 -1
  89. package/lib/sync.d.ts.map +1 -1
  90. package/lib/sync.js.map +1 -1
  91. package/lib/utils.d.ts +1 -1
  92. package/lib/utils.d.ts.map +1 -1
  93. package/lib/utils.js +1 -0
  94. package/lib/utils.js.map +1 -1
  95. package/lib/webrtc/call.js.map +1 -1
  96. package/lib/webrtc/groupCall.js.map +1 -1
  97. package/lib/webrtc/mediaHandler.js.map +1 -1
  98. package/lib/webrtc/stats/callStatsReportGatherer.js.map +1 -1
  99. package/lib/webrtc/stats/transportStatsBuilder.js.map +1 -1
  100. package/lib/wellKnownCachedValue.d.ts +8 -0
  101. package/lib/wellKnownCachedValue.d.ts.map +1 -0
  102. package/lib/wellKnownCachedValue.js +34 -0
  103. package/lib/wellKnownCachedValue.js.map +1 -0
  104. package/package.json +4 -4
  105. package/src/@types/beacon.ts +1 -1
  106. package/src/@types/extensible_events.ts +3 -4
  107. package/src/autodiscovery.ts +2 -2
  108. package/src/browser-index.ts +1 -1
  109. package/src/client.ts +48 -40
  110. package/src/common-crypto/key-passphrase.ts +1 -1
  111. package/src/crypto/store/indexeddb-crypto-store-backend.ts +2 -1
  112. package/src/crypto/store/indexeddb-crypto-store.ts +1 -3
  113. package/src/crypto/store/memory-crypto-store.ts +1 -1
  114. package/src/embedded.ts +34 -11
  115. package/src/matrixrtc/MatrixRTCSession.ts +3 -3
  116. package/src/matrixrtc/MembershipManager.ts +1 -1
  117. package/src/matrixrtc/MembershipManagerActionScheduler.ts +1 -1
  118. package/src/matrixrtc/RTCEncryptionManager.ts +2 -2
  119. package/src/matrixrtc/ToDeviceKeyTransport.ts +3 -3
  120. package/src/matrixrtc/membershipData/rtc.ts +1 -1
  121. package/src/matrixrtc/utils.ts +0 -2
  122. package/src/models/event-timeline-set.ts +3 -3
  123. package/src/models/event.ts +7 -10
  124. package/src/models/invites-ignorer.ts +1 -1
  125. package/src/models/poll.ts +1 -1
  126. package/src/models/read-receipt.ts +1 -1
  127. package/src/models/relations-container.ts +55 -19
  128. package/src/models/relations.ts +1 -1
  129. package/src/models/room.ts +9 -9
  130. package/src/models/thread.ts +49 -4
  131. package/src/oauth/authorize.ts +1 -1
  132. package/src/oauth/index.ts +2 -2
  133. package/src/pollingCachedValue.ts +184 -0
  134. package/src/pushprocessor.ts +3 -3
  135. package/src/receipt-accumulator.ts +1 -2
  136. package/src/rendezvous/MSC4108SignInWithQR.ts +3 -4
  137. package/src/rtcTransportsCachedValue.ts +40 -0
  138. package/src/rust-crypto/PerSessionKeyBackupDownloader.ts +1 -1
  139. package/src/rust-crypto/backup.ts +1 -5
  140. package/src/rust-crypto/index.ts +23 -25
  141. package/src/rust-crypto/libolm_migration.ts +1 -1
  142. package/src/rust-crypto/rust-crypto.ts +3 -3
  143. package/src/sliding-sync-sdk.ts +1 -1
  144. package/src/sliding-sync.ts +1 -1
  145. package/src/store/indexeddb-local-backend.ts +1 -1
  146. package/src/store/indexeddb-store-worker.ts +1 -0
  147. package/src/sync.ts +4 -3
  148. package/src/utils.ts +3 -2
  149. package/src/webrtc/call.ts +6 -6
  150. package/src/webrtc/groupCall.ts +7 -7
  151. package/src/webrtc/mediaHandler.ts +1 -1
  152. package/src/webrtc/stats/callStatsReportGatherer.ts +2 -2
  153. package/src/webrtc/stats/transportStatsBuilder.ts +1 -1
  154. package/src/wellKnownCachedValue.ts +34 -0
package/src/client.ts CHANGED
@@ -53,7 +53,7 @@ import * as utils from "./utils.ts";
53
53
  import { deepCompare, noUnsafeEventProps, type QueryDict, replaceParam, safeSet, sleep } from "./utils.ts";
54
54
  import { Direction, EventTimeline } from "./models/event-timeline.ts";
55
55
  import { type IActionsObject, PushProcessor } from "./pushprocessor.ts";
56
- import { AutoDiscovery, type AutoDiscoveryAction } from "./autodiscovery.ts";
56
+ import { type AutoDiscoveryAction } from "./autodiscovery.ts";
57
57
  import { encodeUnpaddedBase64Url } from "./base64.ts";
58
58
  import { TypedReEmitter } from "./ReEmitter.ts";
59
59
  import { logger, type Logger } from "./logger.ts";
@@ -247,6 +247,9 @@ import { type EmptyObject } from "./@types/common.ts";
247
247
  import { UnsupportedDelayedEventsEndpointError, UnsupportedStickyEventsEndpointError } from "./errors.ts";
248
248
  import { type Transport } from "./matrixrtc/index.ts";
249
249
  import { RetentionPolicyService } from "./retentionPolicy.ts";
250
+ import { createRtcTransportsCachedValue } from "./rtcTransportsCachedValue.ts";
251
+ import { createWellKnownCachedValue } from "./wellKnownCachedValue.ts";
252
+ import { type PollingCachedValue } from "./pollingCachedValue.ts";
250
253
 
251
254
  export type Store = IStore;
252
255
 
@@ -1095,6 +1098,7 @@ export enum ClientEvent {
1095
1098
  TurnServers = "turnServers",
1096
1099
  TurnServersError = "turnServers.error",
1097
1100
  UserProfileUpdate = "userProfileUpdate",
1101
+ RtcTransportsUpdated = "rtcTransportsUpdated",
1098
1102
  }
1099
1103
 
1100
1104
  type RoomEvents =
@@ -1165,6 +1169,7 @@ export type ClientEventHandlerMap = {
1165
1169
  [ClientEvent.ReceivedVoipEvent]: (event: MatrixEvent) => void;
1166
1170
  [ClientEvent.TurnServers]: (servers: ITurnServer[]) => void;
1167
1171
  [ClientEvent.TurnServersError]: (error: Error, fatal: boolean) => void;
1172
+ [ClientEvent.RtcTransportsUpdated]: (transports: Transport[]) => void;
1168
1173
  /**
1169
1174
  *
1170
1175
  * @param userId - the user ID of the profile which was updated
@@ -1273,7 +1278,6 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
1273
1278
  protected syncLeftRoomsPromise?: Promise<Room[]>;
1274
1279
  protected syncedLeftRooms = false;
1275
1280
  protected clientOpts?: IStoredClientOpts;
1276
- protected clientWellKnownIntervalID?: ReturnType<typeof setInterval>;
1277
1281
  protected canResetTimelineCallback?: ResetTimelineCallback;
1278
1282
 
1279
1283
  public canSupport = new Map<Feature, ServerSupport>();
@@ -1285,8 +1289,6 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
1285
1289
  // TODO: This should expire: https://github.com/matrix-org/matrix-js-sdk/issues/1020
1286
1290
  protected serverVersionsPromise?: Promise<IServerVersions>;
1287
1291
 
1288
- protected clientWellKnown?: IClientWellKnown;
1289
- protected clientWellKnownPromise?: Promise<IClientWellKnown>;
1290
1292
  protected turnServers: ITurnServer[] = [];
1291
1293
  protected turnServersExpiry = 0;
1292
1294
  protected checkTurnServersIntervalID?: ReturnType<typeof setInterval>;
@@ -1316,6 +1318,9 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
1316
1318
  public readonly retentionPolicyService: RetentionPolicyService;
1317
1319
  public readonly _unstable_shouldApplyMessageRetention: boolean;
1318
1320
 
1321
+ public cachedRtcTransports: PollingCachedValue<Transport[]>;
1322
+ protected cachedWellKnown: PollingCachedValue<IClientWellKnown>;
1323
+
1319
1324
  public constructor(opts: IMatrixClientCreateOpts) {
1320
1325
  super();
1321
1326
 
@@ -1338,7 +1343,7 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
1338
1343
  const userId = opts.userId || null;
1339
1344
  this.credentials = { userId };
1340
1345
 
1341
- this.http = new MatrixHttpApi(this as ConstructorParameters<typeof MatrixHttpApi>[0], {
1346
+ this.http = new MatrixHttpApi(this, {
1342
1347
  fetchFn: opts.fetchFn,
1343
1348
  baseUrl: opts.baseUrl,
1344
1349
  idBaseUrl: opts.idBaseUrl,
@@ -1432,6 +1437,9 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
1432
1437
 
1433
1438
  // having lots of event listeners is not unusual. 0 means "unlimited".
1434
1439
  this.setMaxListeners(0);
1440
+
1441
+ this.cachedRtcTransports = createRtcTransportsCachedValue(this, this.logger);
1442
+ this.cachedWellKnown = createWellKnownCachedValue(this, this.logger);
1435
1443
  }
1436
1444
 
1437
1445
  public set store(newStore: Store) {
@@ -1510,18 +1518,19 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
1510
1518
 
1511
1519
  this.syncApi.sync().catch((e) => this.logger.info("Sync startup aborted with an error:", e));
1512
1520
 
1513
- if (this.clientOpts.clientWellKnownPollPeriod !== undefined) {
1514
- this.clientWellKnownIntervalID = setInterval(() => {
1515
- void this.fetchClientWellKnown();
1516
- }, 1000 * this.clientOpts.clientWellKnownPollPeriod);
1517
- void this.fetchClientWellKnown();
1518
- }
1521
+ this.cachedWellKnown.start(
1522
+ this.clientOpts.clientWellKnownPollPeriod !== undefined
1523
+ ? 1000 * this.clientOpts.clientWellKnownPollPeriod
1524
+ : undefined,
1525
+ );
1519
1526
 
1520
1527
  this.toDeviceMessageQueue.start();
1521
1528
  this.serverCapabilitiesService.start();
1522
1529
  if (this._unstable_shouldApplyMessageRetention) {
1523
1530
  this.retentionPolicyService?.start();
1524
1531
  }
1532
+
1533
+ this.cachedRtcTransports.start();
1525
1534
  }
1526
1535
 
1527
1536
  /**
@@ -1568,15 +1577,14 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
1568
1577
  globalThis.clearInterval(this.checkTurnServersIntervalID);
1569
1578
  this.checkTurnServersIntervalID = undefined;
1570
1579
 
1571
- if (this.clientWellKnownIntervalID !== undefined) {
1572
- globalThis.clearInterval(this.clientWellKnownIntervalID);
1573
- }
1574
-
1575
1580
  this.toDeviceMessageQueue.stop();
1576
1581
 
1577
1582
  this.matrixRTC.stop();
1578
1583
 
1579
1584
  this.serverCapabilitiesService.stop();
1585
+
1586
+ this.cachedRtcTransports.stop();
1587
+ this.cachedWellKnown.stop();
1580
1588
  }
1581
1589
 
1582
1590
  /**
@@ -1969,6 +1977,11 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
1969
1977
  * @param args.storagePassword - An alternative to `storageKey`. A password which will be used to derive a key to
1970
1978
  * encrypt the store with. Deriving a key from a password is (deliberately) a slow operation, so prefer
1971
1979
  * to pass a `storageKey` directly where possible.
1980
+ * @param args.caCertsPem - Optional PEM-formatted string that provides CA certificates. These will be used to check
1981
+ * X.509 signatures on user identities. Any user identity that has a valid signature according to the supplied
1982
+ * CAs will be considered verified, without any manual verification taking place.
1983
+ *
1984
+ * NOTE: this is an unspecified extension to Matrix. Applications should exercise caution when using it.
1972
1985
  *
1973
1986
  * @returns a Promise which will resolve when the crypto layer has been
1974
1987
  * successfully initialised.
@@ -1979,6 +1992,7 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
1979
1992
  cryptoDatabasePrefix?: string;
1980
1993
  storageKey?: Uint8Array;
1981
1994
  storagePassword?: string;
1995
+ caCertsPem?: string;
1982
1996
  } = {},
1983
1997
  ): Promise<void> {
1984
1998
  if (this.cryptoBackend) {
@@ -2024,6 +2038,8 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
2024
2038
  },
2025
2039
 
2026
2040
  enableEncryptedStateEvents: this.enableEncryptedStateEvents,
2041
+
2042
+ caCertsPem: args.caCertsPem,
2027
2043
  });
2028
2044
 
2029
2045
  rustCrypto.setSupportedVerificationMethods(this.verificationMethods);
@@ -2129,7 +2145,7 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
2129
2145
  public deleteKeysFromBackup(roomId: string, sessionId: undefined, version?: string): Promise<void>;
2130
2146
  public deleteKeysFromBackup(roomId: string, sessionId: string, version?: string): Promise<void>;
2131
2147
  public async deleteKeysFromBackup(roomId?: string, sessionId?: string, version?: string): Promise<void> {
2132
- const path = this.makeKeyBackupPath(roomId!, sessionId!, version);
2148
+ const path = this.makeKeyBackupPath(roomId, sessionId, version);
2133
2149
  await this.http.authedRequest(Method.Delete, path.path, path.queryData, undefined, { prefix: ClientPrefix.V3 });
2134
2150
  }
2135
2151
 
@@ -3194,14 +3210,14 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
3194
3210
  ): Promise<ISendEventResponse> {
3195
3211
  if (typeof threadId !== "string" && threadId !== null) {
3196
3212
  txnId = content as string;
3197
- content = threadId as RoomMessageEventContent;
3213
+ content = threadId;
3198
3214
  threadId = null;
3199
3215
  }
3200
3216
 
3201
3217
  const eventType = EventType.RoomMessage;
3202
3218
  const sendContent = content as RoomMessageEventContent;
3203
3219
 
3204
- return this.sendEvent(roomId, threadId as string | null, eventType, sendContent, txnId);
3220
+ return this.sendEvent(roomId, threadId, eventType, sendContent, txnId);
3205
3221
  }
3206
3222
 
3207
3223
  /**
@@ -3310,8 +3326,8 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
3310
3326
  ): Promise<ISendEventResponse> {
3311
3327
  if (!threadId?.startsWith(EVENT_ID_PREFIX) && threadId !== null) {
3312
3328
  text = (info as string) || "Image";
3313
- info = url as ImageInfo;
3314
- url = threadId as string;
3329
+ info = url;
3330
+ url = threadId;
3315
3331
  threadId = null;
3316
3332
  }
3317
3333
  const content = {
@@ -3351,8 +3367,8 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
3351
3367
  ): Promise<ISendEventResponse> {
3352
3368
  if (!threadId?.startsWith(EVENT_ID_PREFIX) && threadId !== null) {
3353
3369
  text = (info as string) || "Sticker";
3354
- info = url as ImageInfo;
3355
- url = threadId as string;
3370
+ info = url;
3371
+ url = threadId;
3356
3372
  threadId = null;
3357
3373
  }
3358
3374
  const content = {
@@ -3384,7 +3400,7 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
3384
3400
  htmlBody?: string,
3385
3401
  ): Promise<ISendEventResponse> {
3386
3402
  if (!threadId?.startsWith(EVENT_ID_PREFIX) && threadId !== null) {
3387
- htmlBody = body as string;
3403
+ htmlBody = body;
3388
3404
  body = threadId;
3389
3405
  threadId = null;
3390
3406
  }
@@ -3412,7 +3428,7 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
3412
3428
  htmlBody?: string,
3413
3429
  ): Promise<ISendEventResponse> {
3414
3430
  if (!threadId?.startsWith(EVENT_ID_PREFIX) && threadId !== null) {
3415
- htmlBody = body as string;
3431
+ htmlBody = body;
3416
3432
  body = threadId;
3417
3433
  threadId = null;
3418
3434
  }
@@ -3440,7 +3456,7 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
3440
3456
  htmlBody?: string,
3441
3457
  ): Promise<ISendEventResponse> {
3442
3458
  if (!threadId?.startsWith(EVENT_ID_PREFIX) && threadId !== null) {
3443
- htmlBody = body as string;
3459
+ htmlBody = body;
3444
3460
  body = threadId;
3445
3461
  threadId = null;
3446
3462
  }
@@ -5561,7 +5577,7 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
5561
5577
  if (promise) {
5562
5578
  return new Promise<void>((resolve, reject) => {
5563
5579
  // Update this.pushRules when the operation completes
5564
- promise!
5580
+ promise
5565
5581
  .then(() => {
5566
5582
  this.getPushRules()
5567
5583
  .then((result) => {
@@ -6046,23 +6062,16 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
6046
6062
  return this.http.authedRequest(Method.Post, path, undefined, undefined, { prefix: "" });
6047
6063
  }
6048
6064
 
6049
- protected async fetchClientWellKnown(): Promise<void> {
6050
- // `getRawClientConfig` does not throw or reject on network errors, instead
6051
- // it absorbs errors and returns `{}`.
6052
- this.clientWellKnownPromise = AutoDiscovery.getRawClientConfig(this.getDomain() ?? undefined);
6053
- this.clientWellKnown = await this.clientWellKnownPromise;
6054
- this.emit(ClientEvent.ClientWellKnown, this.clientWellKnown);
6055
- }
6056
-
6057
6065
  public getClientWellKnown(): IClientWellKnown | undefined {
6058
- return this.clientWellKnown;
6066
+ return this.cachedWellKnown.get();
6059
6067
  }
6060
6068
 
6061
- public waitForClientWellKnown(): Promise<IClientWellKnown> {
6069
+ public async waitForClientWellKnown(): Promise<IClientWellKnown> {
6062
6070
  if (!this.clientRunning) {
6063
6071
  throw new Error("Client is not running");
6064
6072
  }
6065
- return this.clientWellKnownPromise!;
6073
+ const wellKnown = await this.cachedWellKnown.wait();
6074
+ return wellKnown!;
6066
6075
  }
6067
6076
 
6068
6077
  /**
@@ -6986,8 +6995,7 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
6986
6995
  room_id: roomId,
6987
6996
  type: eventType,
6988
6997
  state_key: stateKey,
6989
- // Cast safety: StateEvents[K] is a stronger bound than IContent, which has [key: string]: any
6990
- content: content as IContent,
6998
+ content,
6991
6999
  });
6992
7000
 
6993
7001
  await this.encryptStateEventIfNeeded(event, room ?? undefined);
@@ -7030,7 +7038,7 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
7030
7038
 
7031
7039
  // If the crypto impl thinks we shouldn't encrypt, then we shouldn't.
7032
7040
  // Safety: we checked the crypto impl exists above.
7033
- if (!(await this.cryptoBackend!.isStateEncryptionEnabledInRoom(room.roomId))) {
7041
+ if (!(await this.cryptoBackend.isStateEncryptionEnabledInRoom(room.roomId))) {
7034
7042
  return;
7035
7043
  }
7036
7044
 
@@ -30,7 +30,7 @@ interface IAuthData {
30
30
  */
31
31
  export function keyFromAuthData(authData: IAuthData, passphrase: string): Promise<Uint8Array> {
32
32
  if (!authData.private_key_salt || !authData.private_key_iterations) {
33
- throw new Error("Salt and/or iterations not found: " + "this backup cannot be restored with a passphrase");
33
+ throw new Error("Salt and/or iterations not found: this backup cannot be restored with a passphrase");
34
34
  }
35
35
 
36
36
  return deriveRecoveryKeyFromPassphrase(
@@ -590,7 +590,7 @@ const DB_MIGRATIONS: DbMigration[] = [
590
590
  export const VERSION = DB_MIGRATIONS.length;
591
591
 
592
592
  export function upgradeDatabase(db: IDBDatabase, oldVersion: number): void {
593
- logger.log(`Upgrading IndexedDBCryptoStore from version ${oldVersion}` + ` to ${VERSION}`);
593
+ logger.log(`Upgrading IndexedDBCryptoStore from version ${oldVersion} to ${VERSION}`);
594
594
  DB_MIGRATIONS.forEach((migration, index) => {
595
595
  if (oldVersion <= index) migration(db);
596
596
  });
@@ -632,6 +632,7 @@ function promiseifyTxn<T>(txn: IDBTransaction): Promise<T | null> {
632
632
  txn.oncomplete = (): void => {
633
633
  if ((txn as IWrappedIDBTransaction)._mx_abortexception !== undefined) {
634
634
  reject((txn as IWrappedIDBTransaction)._mx_abortexception);
635
+ return;
635
636
  }
636
637
  resolve(null);
637
638
  };
@@ -199,9 +199,7 @@ export class IndexedDBCryptoStore implements CryptoStore {
199
199
  // in this db so we should use it or nothing at all.
200
200
  throw new InvalidCryptoStoreError(InvalidCryptoStoreState.TooNew);
201
201
  }
202
- logger.warn(
203
- `unable to connect to indexeddb ${this.dbName}` + `: falling back to localStorage store: ${e}`,
204
- );
202
+ logger.warn(`unable to connect to indexeddb ${this.dbName}: falling back to localStorage store: ${e}`);
205
203
 
206
204
  try {
207
205
  if (!(globalThis.localStorage instanceof Storage)) {
@@ -132,7 +132,7 @@ export class MemoryCryptoStore implements CryptoStore {
132
132
  func: (key: SecretStorePrivateKeys[K] | null) => void,
133
133
  type: K,
134
134
  ): void {
135
- const result = this.privateKeys[type] as SecretStorePrivateKeys[K] | undefined;
135
+ const result = this.privateKeys[type];
136
136
  func(result || null);
137
137
  }
138
138
 
package/src/embedded.ts CHANGED
@@ -32,7 +32,8 @@ import {
32
32
  UnstableApiVersion,
33
33
  } from "matrix-widget-api";
34
34
 
35
- import { MatrixEvent, type IEvent, type IContent, EventStatus } from "./models/event.ts";
35
+ import { type Transport } from "./matrixrtc/index.ts";
36
+ import { MatrixEvent, type IEvent, EventStatus } from "./models/event.ts";
36
37
  import {
37
38
  type ISendEventResponse,
38
39
  type SendDelayedEventRequestOpts,
@@ -137,6 +138,13 @@ export interface ICapabilities {
137
138
  * @defaultValue false
138
139
  */
139
140
  receiveSticky?: boolean;
141
+
142
+ /**
143
+ * Whether this client needs to be able to discover the RTC transports the host can reach.
144
+ * @experimental Part of MSC4515
145
+ * @defaultValue false
146
+ */
147
+ rtcTransports?: boolean;
140
148
  }
141
149
 
142
150
  export enum RoomWidgetClientEvent {
@@ -285,6 +293,9 @@ export class RoomWidgetClient extends MatrixClient {
285
293
  if (capabilities.turnServers) {
286
294
  this.widgetApi.requestCapability(MatrixCapabilities.MSC3846TurnServers);
287
295
  }
296
+ if (capabilities.rtcTransports) {
297
+ this.widgetApi.requestCapability(MatrixCapabilities.MSC4515RtcTransports);
298
+ }
288
299
  }
289
300
 
290
301
  public async supportUpdateState(): Promise<boolean> {
@@ -346,12 +357,9 @@ export class RoomWidgetClient extends MatrixClient {
346
357
  );
347
358
  }
348
359
 
349
- if (opts.clientWellKnownPollPeriod !== undefined) {
350
- this.clientWellKnownIntervalID = setInterval(() => {
351
- this.fetchClientWellKnown();
352
- }, 1000 * opts.clientWellKnownPollPeriod);
353
- this.fetchClientWellKnown();
354
- }
360
+ this.cachedWellKnown.start(
361
+ opts.clientWellKnownPollPeriod !== undefined ? 1000 * opts.clientWellKnownPollPeriod : undefined,
362
+ );
355
363
  this.setSyncState(SyncState.Syncing);
356
364
  logger.info("Finished initial sync");
357
365
 
@@ -408,7 +416,7 @@ export class RoomWidgetClient extends MatrixClient {
408
416
  // We need the additional as assertion for the EW linter to be happy.
409
417
  // It is not capable of implying the type based on the throw if `stickyDurationMs !== undefined && typeof stickyDurationMs !== "number"`
410
418
  // above
411
- const stickyDurationMsAsNumber: number | undefined = stickyDurationMs as number | undefined;
419
+ const stickyDurationMsAsNumber: number | undefined = stickyDurationMs;
412
420
 
413
421
  // We need to extend the content with the redacts parameter
414
422
  // The js sdk uses event.redacts but the widget api uses event.content.redacts
@@ -622,6 +630,21 @@ export class RoomWidgetClient extends MatrixClient {
622
630
  };
623
631
  }
624
632
 
633
+ /**
634
+ * Returns a set of configured RTC transports supported by the homeserver.
635
+ *
636
+ * Overrides the homeserver-side {@link MatrixClient._unstable_getRTCTransports} (MSC4143):
637
+ * a widget cannot make authenticated homeserver calls itself, so we ask the host over the
638
+ * widget API instead (MSC4515). Requires the `rtcTransports` capability and a host that
639
+ * advertises the `org.matrix.msc4515` API version (otherwise the request throws).
640
+ */
641
+ public override async _unstable_getRTCTransports(): Promise<Transport[]> {
642
+ const { rtc_transports: rtcTransports } = await this.widgetApi
643
+ .getRtcTransports()
644
+ .catch(timeoutToConnectionError);
645
+ return rtcTransports;
646
+ }
647
+
625
648
  public async queueToDevice({ eventType, batch }: ToDeviceBatch): Promise<void> {
626
649
  // map: user Id → device Id → payload
627
650
  const contentMap: MapWithDefault<string, Map<string, ToDevicePayload>> = new MapWithDefault(() => new Map());
@@ -726,7 +749,7 @@ export class RoomWidgetClient extends MatrixClient {
726
749
  // Verify the room ID matches, since it's possible for the client to
727
750
  // send us events from other rooms if this widget is always on screen
728
751
  if (ev.detail.data.room_id === this.roomId) {
729
- const event = new MatrixEvent(ev.detail.data as Partial<IEvent>);
752
+ const event = new MatrixEvent(ev.detail.data);
730
753
 
731
754
  // Only inject once we have update the txId
732
755
  await this.updateTxId(event);
@@ -768,7 +791,7 @@ export class RoomWidgetClient extends MatrixClient {
768
791
  const event = new MatrixEvent({
769
792
  type: ev.detail.data.type,
770
793
  sender: ev.detail.data.sender,
771
- content: ev.detail.data.content as IContent,
794
+ content: ev.detail.data.content,
772
795
  });
773
796
  // Mark the event as encrypted if it was, using fake contents and keys since those are unknown to us
774
797
  if (ev.detail.data.encrypted) event.makeEncrypted(EventType.RoomMessageEncrypted, {}, "", "");
@@ -791,7 +814,7 @@ export class RoomWidgetClient extends MatrixClient {
791
814
  // send us state updates from other rooms if this widget is always
792
815
  // on screen
793
816
  if (rawEvent.room_id === this.roomId) {
794
- const event = new MatrixEvent(rawEvent as Partial<IEvent>);
817
+ const event = new MatrixEvent(rawEvent);
795
818
 
796
819
  if (this.syncApi instanceof SyncApi) {
797
820
  await this.syncApi.injectRoomEvents(this.room!, undefined, [event]);
@@ -516,7 +516,7 @@ export class MatrixRTCSession extends TypedEventEmitter<
516
516
  )
517
517
  : new MembershipManager(joinConfig, this.roomSubset, this.client, this.slotDescription, this.logger);
518
518
 
519
- this.reEmitter.reEmit(this.membershipManager!, [
519
+ this.reEmitter.reEmit(this.membershipManager, [
520
520
  MembershipManagerEvent.ProbablyLeft,
521
521
  MembershipManagerEvent.StatusChanged,
522
522
  MembershipManagerEvent.DelayIdChanged,
@@ -550,12 +550,12 @@ export class MatrixRTCSession extends TypedEventEmitter<
550
550
  this.pendingNotificationToSend = this.joinConfig?.notificationType;
551
551
 
552
552
  // Join!
553
- this.membershipManager!.join(fociPreferred, multiSfuFocus, (e) => {
553
+ this.membershipManager.join(fociPreferred, multiSfuFocus, (e) => {
554
554
  this.logger.error("MembershipManager encountered an unrecoverable error: ", e);
555
555
  this.emit(MatrixRTCSessionEvent.MembershipManagerError, e);
556
556
  this.emit(MatrixRTCSessionEvent.JoinStateChanged, this.isJoined());
557
557
  });
558
- this.encryptionManager!.join(joinConfig);
558
+ this.encryptionManager.join(joinConfig);
559
559
 
560
560
  this.emit(MatrixRTCSessionEvent.JoinStateChanged, true);
561
561
  }
@@ -284,7 +284,7 @@ export class MembershipManager
284
284
  this.logger.warn("Missing own membership: force re-join");
285
285
  this.state.hasMemberStateEvent = false;
286
286
 
287
- if (this.scheduler.actions.some((a) => sendingMembershipActions.includes(a.type as MembershipActionType))) {
287
+ if (this.scheduler.actions.some((a) => sendingMembershipActions.includes(a.type))) {
288
288
  this.logger.error(
289
289
  "tried adding another `SendDelayedEvent` actions even though we already have one in the Queue\nActionQueueOnMemberUpdate:",
290
290
  this.scheduler.actions,
@@ -101,7 +101,7 @@ export class ActionScheduler {
101
101
  );
102
102
  try {
103
103
  // `this.wakeup` can also be called and sets the `wakeupUpdate` object while we are in the handler.
104
- handlerResult = await this.membershipLoopHandler(nextAction.type as MembershipActionType);
104
+ handlerResult = await this.membershipLoopHandler(nextAction.type);
105
105
  } catch (e) {
106
106
  // Preserve the original error as `cause`.
107
107
  throw new Error(`The MembershipManager shut down because of the end condition: ${e}`, {
@@ -342,7 +342,7 @@ export class RTCEncryptionManager implements IEncryptionManager {
342
342
  })
343
343
  .map((membership) => {
344
344
  return {
345
- userId: membership.sender!,
345
+ userId: membership.sender,
346
346
  deviceId: membership.deviceId,
347
347
  membershipTs: membership.createdTs(),
348
348
  };
@@ -446,7 +446,7 @@ export class RTCEncryptionManager implements IEncryptionManager {
446
446
 
447
447
  private nextKeyIndex(): number {
448
448
  if (this.outboundSession) {
449
- return (this.outboundSession!.keyId + 1) % 256;
449
+ return (this.outboundSession.keyId + 1) % 256;
450
450
  }
451
451
  return 0;
452
452
  }
@@ -88,8 +88,8 @@ export class ToDeviceKeyTransport
88
88
  const targets = members
89
89
  .map((member) => {
90
90
  return {
91
- userId: member.userId!,
92
- deviceId: member.deviceId!,
91
+ userId: member.userId,
92
+ deviceId: member.deviceId,
93
93
  };
94
94
  })
95
95
  // filter out me
@@ -137,7 +137,7 @@ export class ToDeviceKeyTransport
137
137
  // TODO userId this is claimed information, deviceId is claimed information
138
138
  {
139
139
  userId: fromUser,
140
- deviceId: content.member.claimed_device_id!,
140
+ deviceId: content.member.claimed_device_id,
141
141
  memberId: content.member.id ?? hardcodedMemberIdAlternative,
142
142
  },
143
143
  content.keys.key,
@@ -105,7 +105,7 @@ export const checkRtcMembershipData = (data: IContent, sender: string): data is
105
105
  } else {
106
106
  // validate that each transport has at least a string 'type'
107
107
  for (const t of data.transports.published) {
108
- if (typeof t !== "object" || t === null || typeof (t as any).type !== "string") {
108
+ if (typeof t !== "object" || t === null || typeof t.type !== "string") {
109
109
  errors.push(prefix + "transports.published entries must be objects with a string type");
110
110
  break;
111
111
  }
@@ -24,8 +24,6 @@ export class OutdatedKeyFilter {
24
24
  // Map of participantId -> keyIndex -> timestamp
25
25
  private tsBuffer: Map<EncryptionKeyMapKey, Map<number, number>> = new Map();
26
26
 
27
- public constructor() {}
28
-
29
27
  /**
30
28
  * Check if there is a recent key with the same keyId (index) and then use the creationTS to decide what to
31
29
  * do with the key. If the key received is older than the one already in the buffer, it is ignored.
@@ -526,9 +526,9 @@ export class EventTimelineSet extends TypedEventEmitter<EmittedEvents, EventTime
526
526
  // that would happen, so I'm going to ignore it for now.
527
527
  //
528
528
  if (existingTimeline == neighbour) {
529
- debuglog("Event " + eventId + " in neighbouring timeline - " + "switching to " + existingTimeline);
529
+ debuglog("Event " + eventId + " in neighbouring timeline - switching to " + existingTimeline);
530
530
  } else {
531
- debuglog("Event " + eventId + " already in a different " + "timeline " + existingTimeline);
531
+ debuglog("Event " + eventId + " already in a different timeline " + existingTimeline);
532
532
  }
533
533
  timeline = existingTimeline;
534
534
  continue;
@@ -582,7 +582,7 @@ export class EventTimelineSet extends TypedEventEmitter<EmittedEvents, EventTime
582
582
  if (direction === EventTimeline.FORWARDS && timeline === this.liveTimeline) {
583
583
  logger.warn({ lastEventWasNew, didUpdate }); // for debugging
584
584
  logger.warn(
585
- `Refusing to set forwards pagination token of live timeline ` + `${timeline} to ${paginationToken}`,
585
+ `Refusing to set forwards pagination token of live timeline ${timeline} to ${paginationToken}`,
586
586
  );
587
587
  return;
588
588
  }
@@ -436,17 +436,17 @@ export class MatrixEvent extends TypedEventEmitter<MatrixEventEmittedEvents, Mat
436
436
  // of space if we don't intern it.
437
437
  (["state_key", "type", "sender", "room_id", "membership"] as const).forEach((prop) => {
438
438
  if (typeof event[prop] !== "string") return;
439
- event[prop] = internaliseString(event[prop]!);
439
+ event[prop] = internaliseString(event[prop]);
440
440
  });
441
441
 
442
442
  (["membership", "avatar_url", "displayname"] as const).forEach((prop) => {
443
443
  if (typeof event.content?.[prop] !== "string") return;
444
- event.content[prop] = internaliseString(event.content[prop]!);
444
+ event.content[prop] = internaliseString(event.content[prop]);
445
445
  });
446
446
 
447
447
  (["rel_type"] as const).forEach((prop) => {
448
448
  if (typeof event.content?.["m.relates_to"]?.[prop] !== "string") return;
449
- event.content["m.relates_to"][prop] = internaliseString(event.content["m.relates_to"][prop]!);
449
+ event.content["m.relates_to"][prop] = internaliseString(event.content["m.relates_to"][prop]);
450
450
  });
451
451
 
452
452
  this.txnId = event.txn_id;
@@ -827,7 +827,7 @@ export class MatrixEvent extends TypedEventEmitter<MatrixEventEmittedEvents, Mat
827
827
 
828
828
  // if this is a state event, pack cleartext type and statekey
829
829
  if (this.isState()) {
830
- this.event.state_key = `${this.clearEvent!.type}:${this.clearEvent!.state_key}`;
830
+ this.event.state_key = `${this.clearEvent.type}:${this.clearEvent.state_key}`;
831
831
  }
832
832
  }
833
833
 
@@ -948,7 +948,7 @@ export class MatrixEvent extends TypedEventEmitter<MatrixEventEmittedEvents, Mat
948
948
  this.setClearData(res);
949
949
  this._decryptionFailureReason = null;
950
950
  } catch (e) {
951
- const detailedError = e instanceof DecryptionError ? (<DecryptionError>e).detailedString : String(e);
951
+ const detailedError = e instanceof DecryptionError ? e.detailedString : String(e);
952
952
 
953
953
  err = e as Error;
954
954
 
@@ -981,7 +981,7 @@ export class MatrixEvent extends TypedEventEmitter<MatrixEventEmittedEvents, Mat
981
981
 
982
982
  this.setClearDataForDecryptionFailure(String(e));
983
983
  this._decryptionFailureReason =
984
- e instanceof DecryptionError ? (<DecryptionError>e).code : DecryptionFailureCode.UNKNOWN_ERROR;
984
+ e instanceof DecryptionError ? e.code : DecryptionFailureCode.UNKNOWN_ERROR;
985
985
  }
986
986
 
987
987
  // Make sure we clear 'decryptionPromise' before sending the 'Event.decrypted' event,
@@ -1254,10 +1254,7 @@ export class MatrixEvent extends TypedEventEmitter<MatrixEventEmittedEvents, Mat
1254
1254
  this.clearEvent = undefined;
1255
1255
  }
1256
1256
 
1257
- const keeps =
1258
- this.getType() in REDACT_KEEP_CONTENT_MAP
1259
- ? REDACT_KEEP_CONTENT_MAP[this.getType() as keyof typeof REDACT_KEEP_CONTENT_MAP]
1260
- : {};
1257
+ const keeps = this.getType() in REDACT_KEEP_CONTENT_MAP ? REDACT_KEEP_CONTENT_MAP[this.getType()] : {};
1261
1258
  const content = this.getContent();
1262
1259
  for (const key in content) {
1263
1260
  if (content.hasOwnProperty(key) && !keeps[key]) {
@@ -252,7 +252,7 @@ export class IgnoredInvites {
252
252
  // `sources` could contain non-string / invalid room ids
253
253
  .filter((roomId) => typeof roomId === "string")
254
254
  .map((roomId) => this.client.getRoom(roomId))
255
- .filter((room) => !!room) as Room[];
255
+ .filter((room) => !!room);
256
256
  if (sourceRooms.length != sources.length) {
257
257
  hasChanges = true;
258
258
  }
@@ -176,7 +176,7 @@ export class Poll extends TypedEventEmitter<Exclude<PollEvent, PollEvent.New>, P
176
176
 
177
177
  const responses =
178
178
  this.responses ||
179
- new Relations("m.reference", M_POLL_RESPONSE.name, this.matrixClient, [M_POLL_RESPONSE.altName!]);
179
+ new Relations("m.reference", M_POLL_RESPONSE.name, this.matrixClient, [M_POLL_RESPONSE.altName]);
180
180
 
181
181
  const pollEndEvent = allRelations.events.find((event) => M_POLL_END.matches(event.getType()));
182
182
 
@@ -325,7 +325,7 @@ export abstract class ReadReceipt<
325
325
  }
326
326
  this.receiptCacheByEventId.get(eventId)!.push({
327
327
  userId: userId,
328
- type: receiptType as ReceiptType,
328
+ type: receiptType,
329
329
  data: receipt,
330
330
  });
331
331
  }