matrix-js-sdk 42.3.0 → 42.4.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 (96) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/lib/@types/json.d.ts.map +1 -1
  3. package/lib/@types/json.js.map +1 -1
  4. package/lib/client.d.ts +74 -5
  5. package/lib/client.d.ts.map +1 -1
  6. package/lib/client.js +83 -7
  7. package/lib/client.js.map +1 -1
  8. package/lib/common-crypto/CryptoBackend.d.ts +42 -23
  9. package/lib/common-crypto/CryptoBackend.d.ts.map +1 -1
  10. package/lib/common-crypto/CryptoBackend.js +7 -0
  11. package/lib/common-crypto/CryptoBackend.js.map +1 -1
  12. package/lib/embedded.d.ts +35 -1
  13. package/lib/embedded.d.ts.map +1 -1
  14. package/lib/embedded.js +49 -1
  15. package/lib/embedded.js.map +1 -1
  16. package/lib/http-api/fetch.d.ts +0 -1
  17. package/lib/http-api/fetch.d.ts.map +1 -1
  18. package/lib/http-api/fetch.js +3 -22
  19. package/lib/http-api/fetch.js.map +1 -1
  20. package/lib/http-api/logging.d.ts +10 -0
  21. package/lib/http-api/logging.d.ts.map +1 -0
  22. package/lib/http-api/logging.js +46 -0
  23. package/lib/http-api/logging.js.map +1 -0
  24. package/lib/matrixrtc/EncryptionManager.d.ts +5 -0
  25. package/lib/matrixrtc/EncryptionManager.d.ts.map +1 -1
  26. package/lib/matrixrtc/EncryptionManager.js.map +1 -1
  27. package/lib/matrixrtc/LivekitTransport.d.ts +82 -0
  28. package/lib/matrixrtc/LivekitTransport.d.ts.map +1 -1
  29. package/lib/matrixrtc/LivekitTransport.js +25 -0
  30. package/lib/matrixrtc/LivekitTransport.js.map +1 -1
  31. package/lib/matrixrtc/MatrixRTCSession.d.ts +41 -2
  32. package/lib/matrixrtc/MatrixRTCSession.d.ts.map +1 -1
  33. package/lib/matrixrtc/MatrixRTCSession.js +59 -1
  34. package/lib/matrixrtc/MatrixRTCSession.js.map +1 -1
  35. package/lib/matrixrtc/MembershipManager.js +7 -4
  36. package/lib/matrixrtc/MembershipManager.js.map +1 -1
  37. package/lib/matrixrtc/RTCEncryptionManager.d.ts +17 -0
  38. package/lib/matrixrtc/RTCEncryptionManager.d.ts.map +1 -1
  39. package/lib/matrixrtc/RTCEncryptionManager.js +68 -29
  40. package/lib/matrixrtc/RTCEncryptionManager.js.map +1 -1
  41. package/lib/models/room-receipts.d.ts +9 -3
  42. package/lib/models/room-receipts.d.ts.map +1 -1
  43. package/lib/models/room-receipts.js +51 -11
  44. package/lib/models/room-receipts.js.map +1 -1
  45. package/lib/oauth/authorize.d.ts +7 -2
  46. package/lib/oauth/authorize.d.ts.map +1 -1
  47. package/lib/oauth/authorize.js +10 -4
  48. package/lib/oauth/authorize.js.map +1 -1
  49. package/lib/oauth/fetch.d.ts +17 -0
  50. package/lib/oauth/fetch.d.ts.map +1 -0
  51. package/lib/oauth/fetch.js +47 -0
  52. package/lib/oauth/fetch.js.map +1 -0
  53. package/lib/oauth/index.d.ts +15 -2
  54. package/lib/oauth/index.d.ts.map +1 -1
  55. package/lib/oauth/index.js +33 -12
  56. package/lib/oauth/index.js.map +1 -1
  57. package/lib/rust-crypto/index.d.ts +17 -0
  58. package/lib/rust-crypto/index.d.ts.map +1 -1
  59. package/lib/rust-crypto/index.js +4 -2
  60. package/lib/rust-crypto/index.js.map +1 -1
  61. package/lib/rust-crypto/rust-crypto.d.ts +6 -26
  62. package/lib/rust-crypto/rust-crypto.d.ts.map +1 -1
  63. package/lib/rust-crypto/rust-crypto.js +19 -54
  64. package/lib/rust-crypto/rust-crypto.js.map +1 -1
  65. package/lib/sliding-sync-sdk.d.ts.map +1 -1
  66. package/lib/sliding-sync-sdk.js +65 -27
  67. package/lib/sliding-sync-sdk.js.map +1 -1
  68. package/lib/sliding-sync.d.ts +17 -0
  69. package/lib/sliding-sync.d.ts.map +1 -1
  70. package/lib/sliding-sync.js +21 -9
  71. package/lib/sliding-sync.js.map +1 -1
  72. package/lib/sync.d.ts +9 -1
  73. package/lib/sync.d.ts.map +1 -1
  74. package/lib/sync.js +54 -29
  75. package/lib/sync.js.map +1 -1
  76. package/package.json +5 -5
  77. package/src/@types/json.ts +11 -2
  78. package/src/client.ts +126 -11
  79. package/src/common-crypto/CryptoBackend.ts +45 -23
  80. package/src/embedded.ts +67 -4
  81. package/src/http-api/fetch.ts +2 -23
  82. package/src/http-api/logging.ts +46 -0
  83. package/src/matrixrtc/EncryptionManager.ts +6 -0
  84. package/src/matrixrtc/LivekitTransport.ts +86 -0
  85. package/src/matrixrtc/MatrixRTCSession.ts +81 -1
  86. package/src/matrixrtc/MembershipManager.ts +7 -7
  87. package/src/matrixrtc/RTCEncryptionManager.ts +80 -31
  88. package/src/models/room-receipts.ts +54 -10
  89. package/src/oauth/authorize.ts +10 -2
  90. package/src/oauth/fetch.ts +54 -0
  91. package/src/oauth/index.ts +29 -10
  92. package/src/rust-crypto/index.ts +23 -0
  93. package/src/rust-crypto/rust-crypto.ts +25 -67
  94. package/src/sliding-sync-sdk.ts +73 -33
  95. package/src/sliding-sync.ts +31 -14
  96. package/src/sync.ts +58 -35
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "matrix-js-sdk",
3
- "version": "42.3.0",
3
+ "version": "42.4.0",
4
4
  "description": "Matrix Client-Server SDK for Javascript",
5
5
  "engines": {
6
6
  "node": ">=22.0.0"
@@ -38,13 +38,13 @@
38
38
  ],
39
39
  "dependencies": {
40
40
  "@babel/runtime": "^8.0.0",
41
- "@matrix-org/matrix-sdk-crypto-wasm": "^18.4.0",
41
+ "@matrix-org/matrix-sdk-crypto-wasm": "^18.7.0",
42
42
  "another-json": "^0.2.0",
43
43
  "bs58": "^6.0.0",
44
- "content-type": "^2.0.0",
44
+ "content-type": "^3.0.0",
45
45
  "loglevel": "^1.9.2",
46
46
  "matrix-events-sdk": "0.0.1",
47
- "matrix-widget-api": "^1.18.0",
47
+ "matrix-widget-api": "^1.19.0",
48
48
  "p-retry": "8",
49
49
  "sdp-transform": "^3.0.0",
50
50
  "unhomoglyph": "^1.0.6"
@@ -79,7 +79,7 @@
79
79
  "knip": "^6.0.0",
80
80
  "lint-staged": "^17.0.0",
81
81
  "matrix-mock-request": "^2.5.0",
82
- "oxfmt": "^0.63.0",
82
+ "oxfmt": "^0.65.0",
83
83
  "oxlint": "^1.70.0",
84
84
  "oxlint-tsgolint": "^7.0.0",
85
85
  "typedoc": "^0.28.1",
@@ -1,8 +1,17 @@
1
1
  /*
2
2
  Copyright 2024 New Vector Ltd.
3
3
 
4
- SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
5
- Please see LICENSE files in the repository root for full details.
4
+ Licensed under the Apache License, Version 2.0 (the "License");
5
+ you may not use this file except in compliance with the License.
6
+ You may obtain a copy of the License at
7
+
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+ Unless required by applicable law or agreed to in writing, software
11
+ distributed under the License is distributed on an "AS IS" BASIS,
12
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ See the License for the specific language governing permissions and
14
+ limitations under the License.
6
15
  */
7
16
 
8
17
  // Types for JSON and JSON objects, copied from element-web (left in both places as I don't think we
package/src/client.ts CHANGED
@@ -245,7 +245,12 @@ import { sha256 } from "./digest.ts";
245
245
  import { type ValidatedAuthMetadata, OAuth2Error, isValidAuthMetadata } from "./oauth/index.ts";
246
246
  import { type EmptyObject } from "./@types/common.ts";
247
247
  import { UnsupportedDelayedEventsEndpointError, UnsupportedStickyEventsEndpointError } from "./errors.ts";
248
- import { type Transport } from "./matrixrtc/index.ts";
248
+ import {
249
+ type LivekitDelegateDelayedLeaveRequest,
250
+ type LivekitGetTokenRequest,
251
+ type LivekitGetTokenResponse,
252
+ type Transport,
253
+ } from "./matrixrtc/index.ts";
249
254
  import { RetentionPolicyService } from "./retentionPolicy.ts";
250
255
  import { createRtcTransportsCachedValue } from "./rtcTransportsCachedValue.ts";
251
256
  import { createWellKnownCachedValue } from "./wellKnownCachedValue.ts";
@@ -525,6 +530,10 @@ export interface IStartClientOpts {
525
530
  /**
526
531
  * The number of seconds between polls to /.well-known/matrix/client, undefined to disable.
527
532
  * This should be in the order of hours. Default: undefined.
533
+ *
534
+ * When disabled, the client never requests the well-known on its own: nothing is fetched on
535
+ * startup and {@link MatrixClient.getClientWellKnown} stays undefined. Callers that still need
536
+ * it can fetch it on demand via {@link MatrixClient.waitForClientWellKnown}.
528
537
  */
529
538
  clientWellKnownPollPeriod?: number;
530
539
 
@@ -1518,11 +1527,11 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
1518
1527
 
1519
1528
  this.syncApi.sync().catch((e) => this.logger.info("Sync startup aborted with an error:", e));
1520
1529
 
1521
- this.cachedWellKnown.start(
1522
- this.clientOpts.clientWellKnownPollPeriod !== undefined
1523
- ? 1000 * this.clientOpts.clientWellKnownPollPeriod
1524
- : undefined,
1525
- );
1530
+ // Only poll the client well-known when a poll period was configured: leaving
1531
+ // `clientWellKnownPollPeriod` undefined disables the lookups entirely.
1532
+ if (this.clientOpts.clientWellKnownPollPeriod !== undefined) {
1533
+ this.cachedWellKnown.start(1000 * this.clientOpts.clientWellKnownPollPeriod);
1534
+ }
1526
1535
 
1527
1536
  this.toDeviceMessageQueue.start();
1528
1537
  this.serverCapabilitiesService.start();
@@ -1980,7 +1989,14 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
1980
1989
  * @param args.caCertsPem - Optional PEM-formatted string that provides CA certificates. These will be used to check
1981
1990
  * X.509 signatures on user identities. Any user identity that has a valid signature according to the supplied
1982
1991
  * CAs will be considered verified, without any manual verification taking place.
1983
- *
1992
+ * NOTE: this is an unspecified extension to Matrix. Applications should exercise caution when using it.
1993
+ * @param args.x509Signer - Optional async function for signing some data with an X.509 certificate. Used to sign
1994
+ * the user's identity so compatible clients will recognise this user as verified without manual verification
1995
+ * taking place. If you supply this you must also supply `x509Validity`.
1996
+ * NOTE: this is an unspecified extension to Matrix. Applications should exercise caution when using it.
1997
+ * @param args.x509Validity - Optional function returning the validity period of the X.509 certificate used for
1998
+ * signing, as the number of milliseconds since the Unix epoch. If you supply this you must also supply
1999
+ * `x509Signer`.
1984
2000
  * NOTE: this is an unspecified extension to Matrix. Applications should exercise caution when using it.
1985
2001
  *
1986
2002
  * @returns a Promise which will resolve when the crypto layer has been
@@ -1993,6 +2009,12 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
1993
2009
  storageKey?: Uint8Array;
1994
2010
  storagePassword?: string;
1995
2011
  caCertsPem?: string;
2012
+ x509Signer?: (item: Uint8Array) => Promise<{
2013
+ signature_bytes: Uint8Array;
2014
+ certificate_chain: string;
2015
+ signature_scheme: "RsaPssSha512";
2016
+ }>;
2017
+ x509Validity?: () => number;
1996
2018
  } = {},
1997
2019
  ): Promise<void> {
1998
2020
  if (this.cryptoBackend) {
@@ -2040,6 +2062,8 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
2040
2062
  enableEncryptedStateEvents: this.enableEncryptedStateEvents,
2041
2063
 
2042
2064
  caCertsPem: args.caCertsPem,
2065
+ x509Signer: args.x509Signer,
2066
+ x509Validity: args.x509Validity,
2043
2067
  });
2044
2068
 
2045
2069
  rustCrypto.setSupportedVerificationMethods(this.verificationMethods);
@@ -3607,6 +3631,45 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
3607
3631
  });
3608
3632
  }
3609
3633
 
3634
+ /**
3635
+ * Get information about a specified delayed event owned by the requesting user.
3636
+ *
3637
+ * Note: This endpoint is unstable, and can throw an `Error`.
3638
+ * Check progress on [MSC4140](https://github.com/matrix-org/matrix-spec-proposals/pull/4140) for more details.
3639
+ */
3640
+ public async _unstable_getDelayedEvent(delayId: string): Promise<{
3641
+ delay_id: string;
3642
+ room_id: string;
3643
+ type: string;
3644
+ state_key?: string;
3645
+ delay_ms: number;
3646
+ delayed_since_ts: number;
3647
+ content: IContent;
3648
+ finalised?: {
3649
+ error?: MatrixError["data"];
3650
+ event_id?: string;
3651
+ finalised_ts: number;
3652
+ };
3653
+ }> {
3654
+ // TODO: define a type/interface for the return shape once MSC4140 has become stable
3655
+ if (!(await this.doesServerSupportUnstableFeature(UNSTABLE_MSC4140_DELAYED_EVENTS))) {
3656
+ throw new UnsupportedDelayedEventsEndpointError(
3657
+ "Server does not support the delayed events API",
3658
+ "getDelayedEvents",
3659
+ );
3660
+ }
3661
+
3662
+ return await this.http.authedRequest(
3663
+ Method.Get,
3664
+ utils.encodeUri("/delayed_events/$delayId", { $delayId: delayId }),
3665
+ undefined,
3666
+ undefined,
3667
+ {
3668
+ prefix: `${ClientPrefix.Unstable}/${UNSTABLE_MSC4140_DELAYED_EVENTS}`,
3669
+ },
3670
+ );
3671
+ }
3672
+
3610
3673
  /**
3611
3674
  * Get information about delayed events owned by the requesting user.
3612
3675
  *
@@ -6181,6 +6244,58 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
6181
6244
  ).rtc_transports;
6182
6245
  }
6183
6246
 
6247
+ /**
6248
+ * Requests a token to authenticate against a LiveKit SFU with (MSC4195).
6249
+ *
6250
+ * The homeserver checks that we are joined to `room_id` before obtaining a token from the SFU. If
6251
+ * `server_name` names a remote homeserver, our homeserver forwards the request to it over federation,
6252
+ * which is how a token for another homeserver's SFU is obtained.
6253
+ *
6254
+ * Requires homeserver support for MSC4195.
6255
+ *
6256
+ * @param body - The details of the `m.rtc.member` event to obtain a token for, and the SFU to obtain it from.
6257
+ * @returns The JWT to authenticate with when connecting to the SFU.
6258
+ * @throws A M_NOT_FOUND error if not supported by the homeserver, a M_FORBIDDEN error if we (or, when
6259
+ * federating, our homeserver) are not joined to the room, or a M_INVALID_PARAM error if `url` is not one
6260
+ * of the answering server's SFUs.
6261
+ */
6262
+ public async _unstable_getLivekitToken(body: LivekitGetTokenRequest): Promise<LivekitGetTokenResponse> {
6263
+ // There is no /versions flag to check for support, so we just have to attempt a request.
6264
+ return await this.http.authedRequest<LivekitGetTokenResponse>(
6265
+ Method.Post,
6266
+ "/rtc/livekit/get_token",
6267
+ undefined,
6268
+ body,
6269
+ { prefix: `${ClientPrefix.Unstable}/io.element.msc4195` },
6270
+ );
6271
+ }
6272
+
6273
+ /**
6274
+ * Hands over the management of a delayed MatrixRTC leave event to the homeserver (MSC4195).
6275
+ *
6276
+ * The homeserver restarts the delayed event for as long as it observes our connection to the SFU, and
6277
+ * sends it once we disconnect, so the client does not have to restart it itself. This is more reliable
6278
+ * than client-side restarts under poor network conditions.
6279
+ *
6280
+ * large timeouts are recommended for delayed delegation (in the range of hours)
6281
+ * Requires homeserver support for MSC4195.
6282
+ *
6283
+ * @param body - The details of the `m.rtc.member` event and the delayed leave event to delegate, and the SFU
6284
+ * we are connected to.
6285
+ * @throws A M_NOT_FOUND error if not supported by the homeserver, a M_BAD_JSON error if the delayed
6286
+ * event's timeout is below one hour, or a M_INVALID_PARAM error if `url` is not one of the homeserver's SFUs.
6287
+ */
6288
+ public async _unstable_delegateDelayedLeave(body: LivekitDelegateDelayedLeaveRequest): Promise<EmptyObject> {
6289
+ // There is no /versions flag to check for support, so we just have to attempt a request.
6290
+ return await this.http.authedRequest<EmptyObject>(
6291
+ Method.Post,
6292
+ "/rtc/livekit/delegate_delayed_leave",
6293
+ undefined,
6294
+ body,
6295
+ { prefix: `${ClientPrefix.Unstable}/io.element.msc4195` },
6296
+ );
6297
+ }
6298
+
6184
6299
  /**
6185
6300
  * Get the API versions supported by the server, along with any
6186
6301
  * unstable APIs it supports
@@ -6907,7 +7022,7 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
6907
7022
  /**
6908
7023
  * @param includeMembership - the membership type to include in the response
6909
7024
  * @param excludeMembership - the membership type to exclude from the response
6910
- * @param atEventId - the id of the event for which moment in the timeline the members should be returned for
7025
+ * @param atSyncToken - the point in time, as a sync pagination token, for when the members should be returned for
6911
7026
  * @returns Promise which resolves: dictionary of userid to profile information
6912
7027
  * @returns Rejects: with an error response.
6913
7028
  */
@@ -6915,7 +7030,7 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
6915
7030
  roomId: string,
6916
7031
  includeMembership?: string,
6917
7032
  excludeMembership?: string,
6918
- atEventId?: string,
7033
+ atSyncToken?: string,
6919
7034
  ): Promise<{ [userId: string]: IStateEventWithRoomId[] }> {
6920
7035
  const queryParams: Record<string, string> = {};
6921
7036
  if (includeMembership) {
@@ -6924,8 +7039,8 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
6924
7039
  if (excludeMembership) {
6925
7040
  queryParams.not_membership = excludeMembership;
6926
7041
  }
6927
- if (atEventId) {
6928
- queryParams.at = atEventId;
7042
+ if (atSyncToken) {
7043
+ queryParams.at = atSyncToken;
6929
7044
  }
6930
7045
 
6931
7046
  const queryString = utils.encodeParams(queryParams);
@@ -118,42 +118,64 @@ export interface CryptoBackend extends SyncCryptoCallbacks, CryptoApi {
118
118
  markRoomAsPendingKeyBundle(roomId: string, inviterId: string): Promise<void>;
119
119
  }
120
120
 
121
- /** The methods which crypto implementations should expose to the Sync api
121
+ /**
122
+ * The parts of a sync response which are relevant to encryption, as passed to
123
+ * {@link SyncCryptoCallbacks.processSyncChanges}.
122
124
  *
123
125
  * @internal
124
126
  */
125
- export interface SyncCryptoCallbacks {
127
+ export interface SyncCryptoChanges {
128
+ /** The to-device events from the sync response (`to_device.events`), or an empty list if there were none. */
129
+ toDeviceEvents: IToDeviceEvent[];
130
+
131
+ /** The `device_lists` field from the sync response, if any. */
132
+ deviceLists?: IDeviceLists;
133
+
126
134
  /**
127
- * Called by the /sync loop whenever there are incoming to-device messages.
128
- *
129
- * The implementation may preprocess the received messages (eg, decrypt them) and return an
130
- * updated list of messages for dispatch to the rest of the system.
131
- *
132
- * Note that, unlike {@link ClientEvent.ToDeviceEvent} events, this is called on the raw to-device
133
- * messages, rather than the results of any decryption attempts.
134
- *
135
- * @param events - the received to-device messages
136
- * @returns A list of preprocessed to-device messages. This will not map 1:1 to the input list, as some messages may be invalid or
137
- * failed to decrypt, and so will be omitted from the output list.
135
+ * The `device_one_time_keys_count` field from the sync response, if any.
138
136
  *
137
+ * The meaning of an algorithm missing from the map (or of an absent field) depends on {@link useMsc4186}: in
138
+ * sync v2 it means that there are no one-time keys of that algorithm on the server; in sliding sync it means that
139
+ * the count is unchanged since the previous response.
139
140
  */
140
- preprocessToDeviceMessages(events: IToDeviceEvent[]): Promise<ReceivedToDeviceMessage[]>;
141
+ oneTimeKeysCounts?: Record<string, number>;
141
142
 
142
143
  /**
143
- * Called by the /sync loop when one time key counts and unused fallback key details are received.
144
- *
145
- * @param oneTimeKeysCounts - the received one time key counts
146
- * @param unusedFallbackKeys - the received unused fallback keys
144
+ * The `device_unused_fallback_key_types` field from the sync response, or `undefined` if the response did not
145
+ * include it (which means that the server does not support fallback keys).
146
+ */
147
+ unusedFallbackKeys?: string[];
148
+
149
+ /**
150
+ * Whether to interpret the response with MSC4186 (simplified sliding sync) semantics rather than sync v2. This
151
+ * selects the meaning of missing one-time key counts: see {@link oneTimeKeysCounts}. Defaults to `false`.
147
152
  */
148
- processKeyCounts(oneTimeKeysCounts?: Record<string, number>, unusedFallbackKeys?: string[]): Promise<void>;
153
+ useMsc4186?: boolean;
154
+ }
149
155
 
156
+ /** The methods which crypto implementations should expose to the Sync api
157
+ *
158
+ * @internal
159
+ */
160
+ export interface SyncCryptoCallbacks {
150
161
  /**
151
- * Handle the notification from /sync that device lists have
152
- * been changed.
162
+ * Called by the sync loop once per sync response, with the parts of the response which are relevant to
163
+ * encryption: to-device messages, device list changes, one-time key counts and unused fallback key types.
164
+ *
165
+ * All of this data must be passed together, in a single call per sync response, because the OlmMachine
166
+ * interprets it as the complete E2EE state from a sync response. In particular, per the sync v2 specification,
167
+ * an absent `device_one_time_keys_count` means that there are no one-time keys on the server, so calling this
168
+ * without the counts from the response would trigger a spurious one-time key upload. (Sliding sync responses
169
+ * omit the count when it is unchanged; {@link SyncCryptoChanges.useMsc4186} selects that interpretation.)
170
+ *
171
+ * This must be called before the room events in the sync response are processed, so that any room keys received
172
+ * in to-device messages are available when decrypting room events.
153
173
  *
154
- * @param deviceLists - device_lists field from /sync
174
+ * @param changes - the E2EE-relevant parts of the sync response
175
+ * @returns A list of processed to-device messages. This will not map 1:1 to the input list, as some messages may
176
+ * be invalid or fail to decrypt, and so will be omitted from the output list.
155
177
  */
156
- processDeviceLists(deviceLists: IDeviceLists): Promise<void>;
178
+ processSyncChanges(changes: SyncCryptoChanges): Promise<ReceivedToDeviceMessage[]>;
157
179
 
158
180
  /**
159
181
  * Called by the /sync loop whenever an m.room.encryption event is received.
package/src/embedded.ts CHANGED
@@ -32,7 +32,12 @@ import {
32
32
  UnstableApiVersion,
33
33
  } from "matrix-widget-api";
34
34
 
35
- import { type Transport } from "./matrixrtc/index.ts";
35
+ import {
36
+ type LivekitDelegateDelayedLeaveRequest,
37
+ type LivekitGetTokenRequest,
38
+ type LivekitGetTokenResponse,
39
+ type Transport,
40
+ } from "./matrixrtc/index.ts";
36
41
  import { MatrixEvent, type IEvent, EventStatus } from "./models/event.ts";
37
42
  import {
38
43
  type ISendEventResponse,
@@ -145,6 +150,21 @@ export interface ICapabilities {
145
150
  * @defaultValue false
146
151
  */
147
152
  rtcTransports?: boolean;
153
+
154
+ /**
155
+ * Whether this client needs to be able to obtain LiveKit SFU tokens through the host.
156
+ * @experimental Part of MSC4195 & MSC4533
157
+ * @defaultValue false
158
+ */
159
+ rtcLivekitGetToken?: boolean;
160
+
161
+ /**
162
+ * Whether this client needs to be able to hand delayed MatrixRTC leave events over to the
163
+ * homeserver through the host.
164
+ * @experimental Part of MSC4195 & MSC4533
165
+ * @defaultValue false
166
+ */
167
+ rtcLivekitDelegateDelayedLeave?: boolean;
148
168
  }
149
169
 
150
170
  export enum RoomWidgetClientEvent {
@@ -296,6 +316,12 @@ export class RoomWidgetClient extends MatrixClient {
296
316
  if (capabilities.rtcTransports) {
297
317
  this.widgetApi.requestCapability(MatrixCapabilities.MSC4515RtcTransports);
298
318
  }
319
+ if (capabilities.rtcLivekitGetToken) {
320
+ this.widgetApi.requestCapability(MatrixCapabilities.MSC4533RtcLivekitGetToken);
321
+ }
322
+ if (capabilities.rtcLivekitDelegateDelayedLeave) {
323
+ this.widgetApi.requestCapability(MatrixCapabilities.MSC4533RtcLivekitDelegateDelayedLeave);
324
+ }
299
325
  }
300
326
 
301
327
  public async supportUpdateState(): Promise<boolean> {
@@ -357,9 +383,11 @@ export class RoomWidgetClient extends MatrixClient {
357
383
  );
358
384
  }
359
385
 
360
- this.cachedWellKnown.start(
361
- opts.clientWellKnownPollPeriod !== undefined ? 1000 * opts.clientWellKnownPollPeriod : undefined,
362
- );
386
+ // Only poll the client well-known when a poll period was configured: leaving
387
+ // `clientWellKnownPollPeriod` undefined disables the lookups entirely.
388
+ if (opts.clientWellKnownPollPeriod !== undefined) {
389
+ this.cachedWellKnown.start(1000 * opts.clientWellKnownPollPeriod);
390
+ }
363
391
  this.setSyncState(SyncState.Syncing);
364
392
  logger.info("Finished initial sync");
365
393
 
@@ -645,6 +673,41 @@ export class RoomWidgetClient extends MatrixClient {
645
673
  return rtcTransports;
646
674
  }
647
675
 
676
+ /**
677
+ * Requests a token to authenticate against a LiveKit SFU with.
678
+ *
679
+ * Overrides the homeserver-side {@link MatrixClient._unstable_getLivekitToken} (MSC4195): a widget
680
+ * cannot make authenticated homeserver calls itself, so we ask the host to make the call on our
681
+ * behalf over the widget API instead (MSC4533). Requires the `rtcLivekitGetToken` capability and a
682
+ * host that advertises the `org.matrix.msc4533` API version (otherwise the request throws).
683
+ *
684
+ * `server_name` defaults to our own homeserver, matching what the endpoint would do server-side.
685
+ */
686
+ public override async _unstable_getLivekitToken(body: LivekitGetTokenRequest): Promise<LivekitGetTokenResponse> {
687
+ const serverName = body.server_name ?? this.getDomain();
688
+ if (serverName === null) throw new Error("Cannot determine the server name to request a token from");
689
+ const { jwt } = await this.widgetApi
690
+ .getRtcLivekitToken({ ...body, server_name: serverName })
691
+ .catch(timeoutToConnectionError);
692
+ return { jwt };
693
+ }
694
+
695
+ /**
696
+ * Hands over the management of a delayed MatrixRTC leave event to the homeserver.
697
+ *
698
+ * Overrides the homeserver-side {@link MatrixClient._unstable_delegateDelayedLeave} (MSC4195): a
699
+ * widget cannot make authenticated homeserver calls itself, so we ask the host to make the call on
700
+ * our behalf over the widget API instead (MSC4533). Requires the `rtcLivekitDelegateDelayedLeave`
701
+ * capability and a host that advertises the `org.matrix.msc4533` API version (otherwise the request
702
+ * throws).
703
+ */
704
+ public override async _unstable_delegateDelayedLeave(
705
+ body: LivekitDelegateDelayedLeaveRequest,
706
+ ): Promise<EmptyObject> {
707
+ await this.widgetApi.delegateRtcLivekitDelayedLeave(body).catch(timeoutToConnectionError);
708
+ return {};
709
+ }
710
+
648
711
  public async queueToDevice({ eventType, batch }: ToDeviceBatch): Promise<void> {
649
712
  // map: user Id → device Id → payload
650
713
  const contentMap: MapWithDefault<string, Map<string, ToDevicePayload>> = new MapWithDefault(() => new Map());
@@ -31,6 +31,7 @@ import {
31
31
  type Body,
32
32
  } from "./interface.ts";
33
33
  import { anySignal, parseErrorResponse, timeoutSignal } from "./utils.ts";
34
+ import { sanitizeUrlForLogs } from "./logging.ts";
34
35
  import { type QueryDict } from "../utils.ts";
35
36
  import { TokenRefresher, TokenRefreshOutcome } from "./refresh.ts";
36
37
 
@@ -241,7 +242,7 @@ export class FetchHttpApi<O extends IHttpOpts> {
241
242
  throw new Error("Invalid call to `FetchHttpApi` sets both `opts.json` and `opts.rawResponseBody`");
242
243
  }
243
244
 
244
- const urlForLogs = this.sanitizeUrlForLogs(url);
245
+ const urlForLogs = sanitizeUrlForLogs(url);
245
246
 
246
247
  this.opts.logger?.debug(`FetchHttpApi: --> ${method} ${urlForLogs}`);
247
248
 
@@ -330,28 +331,6 @@ export class FetchHttpApi<O extends IHttpOpts> {
330
331
  }
331
332
  }
332
333
 
333
- private sanitizeUrlForLogs(url: URL | string): string {
334
- try {
335
- let asUrl: URL;
336
- if (typeof url === "string") {
337
- asUrl = new URL(url);
338
- } else {
339
- asUrl = url;
340
- }
341
- // Remove the values of any URL params that could contain potential secrets
342
- const sanitizedQs = new URLSearchParams();
343
- for (const key of asUrl.searchParams.keys()) {
344
- sanitizedQs.append(key, "xxx");
345
- }
346
- const sanitizedQsString = sanitizedQs.toString();
347
- const sanitizedQsUrlPiece = sanitizedQsString ? `?${sanitizedQsString}` : "";
348
-
349
- return asUrl.origin + asUrl.pathname + sanitizedQsUrlPiece;
350
- } catch {
351
- // defensive coding for malformed url
352
- return "??";
353
- }
354
- }
355
334
  /**
356
335
  * Form and return a homeserver request URL based on the given path params and prefix.
357
336
  * @param path - The HTTP path <b>after</b> the supplied prefix e.g. "/createRoom".
@@ -0,0 +1,46 @@
1
+ /*
2
+ Copyright 2026 The Matrix.org Foundation C.I.C.
3
+
4
+ Licensed under the Apache License, Version 2.0 (the "License");
5
+ you may not use this file except in compliance with the License.
6
+ You may obtain a copy of the License at
7
+
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+ Unless required by applicable law or agreed to in writing, software
11
+ distributed under the License is distributed on an "AS IS" BASIS,
12
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ See the License for the specific language governing permissions and
14
+ limitations under the License.
15
+ */
16
+
17
+ /**
18
+ * Produce a version of the given URL which is safe to write to logs, by redacting the values of any query parameters,
19
+ * as they may contain secrets.
20
+ *
21
+ * @internal
22
+ * @param url - the URL to sanitize.
23
+ * @returns the sanitized URL, or `"??"` if the URL could not be parsed.
24
+ */
25
+ export function sanitizeUrlForLogs(url: URL | string): string {
26
+ try {
27
+ let asUrl: URL;
28
+ if (typeof url === "string") {
29
+ asUrl = new URL(url);
30
+ } else {
31
+ asUrl = url;
32
+ }
33
+ // Remove the values of any URL params that could contain potential secrets
34
+ const sanitizedQs = new URLSearchParams();
35
+ for (const key of asUrl.searchParams.keys()) {
36
+ sanitizedQs.append(key, "xxx");
37
+ }
38
+ const sanitizedQsString = sanitizedQs.toString();
39
+ const sanitizedQsUrlPiece = sanitizedQsString ? `?${sanitizedQsString}` : "";
40
+
41
+ return asUrl.origin + asUrl.pathname + sanitizedQsUrlPiece;
42
+ } catch {
43
+ // defensive coding for malformed url
44
+ return "??";
45
+ }
46
+ }
@@ -15,6 +15,12 @@ export function getEncryptionKeyMapKey(membership: CallMembershipIdentityParts):
15
15
  * @internal
16
16
  */
17
17
  export interface IEncryptionManager {
18
+ /**
19
+ * Whether the key rotation is currently halted.
20
+ * @see EncryptionConfig.keyRotationParticipantLimit
21
+ */
22
+ readonly isKeyRotationSuppressed: boolean;
23
+
18
24
  /**
19
25
  * Joins the encryption manager with the provided configuration.
20
26
  *
@@ -44,3 +44,89 @@ export interface LivekitFocusSelection extends Transport {
44
44
  */
45
45
  export const isLivekitFocusSelection = (object: any): object is LivekitFocusSelection =>
46
46
  object.type === "livekit" && "focus_selection" in object;
47
+
48
+ /**
49
+ * Identifies the MatrixRTC membership that a LiveKit request is made for (MSC4195).
50
+ *
51
+ * Note that this is *not* the `member` field of an `m.rtc.member` event verbatim: the homeserver knows
52
+ * the user ID from the access token, and the device ID is only ever claimed, never verified.
53
+ */
54
+ export interface LivekitRtcMember {
55
+ /**
56
+ * The ID of the member within the MatrixRTC session, i.e. the `member.id` of the `m.rtc.member` event.
57
+ */
58
+ id: string;
59
+ /**
60
+ * The device ID the member claims to be using, i.e. the `member.device_id` of the `m.rtc.member` event.
61
+ */
62
+ claimed_device_id?: string;
63
+ }
64
+
65
+ /**
66
+ * The body of a request to the LiveKit `get_token` endpoint (MSC4195).
67
+ *
68
+ * Declared as a type alias rather than an interface so that it can be passed to the widget API
69
+ * (MSC4533), which expects request data to be assignable to an index signature.
70
+ */
71
+ export type LivekitGetTokenRequest = {
72
+ /**
73
+ * The WebSocket URL of the LiveKit SFU to obtain a token for.
74
+ */
75
+ url: string;
76
+ /**
77
+ * The room ID of the Matrix room the `m.rtc.member` event is in.
78
+ */
79
+ room_id: string;
80
+ /**
81
+ * The slot ID from the `m.rtc.member` event.
82
+ */
83
+ slot_id: string;
84
+ /**
85
+ * The MatrixRTC membership to obtain a token for.
86
+ */
87
+ member: LivekitRtcMember;
88
+ /**
89
+ * The server name of the `m.rtc.member` event's sender. If omitted, the homeserver uses its own
90
+ * server name. This is what makes it possible to obtain a token for an SFU of a remote homeserver.
91
+ */
92
+ server_name?: string;
93
+ };
94
+
95
+ /**
96
+ * The response of the LiveKit `get_token` endpoint (MSC4195).
97
+ */
98
+ export interface LivekitGetTokenResponse {
99
+ /**
100
+ * The JWT to authenticate with when connecting to the SFU.
101
+ */
102
+ jwt: string;
103
+ }
104
+
105
+ /**
106
+ * The body of a request to the LiveKit `delegate_delayed_leave` endpoint (MSC4195).
107
+ *
108
+ * Declared as a type alias rather than an interface so that it can be passed to the widget API
109
+ * (MSC4533), which expects request data to be assignable to an index signature.
110
+ */
111
+ export type LivekitDelegateDelayedLeaveRequest = {
112
+ /**
113
+ * The WebSocket URL of the LiveKit SFU that we are connected to.
114
+ */
115
+ url: string;
116
+ /**
117
+ * The room ID of the Matrix room the `m.rtc.member` event is in.
118
+ */
119
+ room_id: string;
120
+ /**
121
+ * The slot ID from the `m.rtc.member` event.
122
+ */
123
+ slot_id: string;
124
+ /**
125
+ * The MatrixRTC membership the delayed leave event belongs to.
126
+ */
127
+ member: LivekitRtcMember;
128
+ /**
129
+ * The delay ID of the delayed leave event to hand over to the homeserver.
130
+ */
131
+ delay_id: string;
132
+ };