matrix-js-sdk 43.0.0-rc.0 → 44.0.0-rc.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 (88) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/lib/matrixrtc/CallMembership.d.ts +30 -25
  3. package/lib/matrixrtc/CallMembership.d.ts.map +1 -1
  4. package/lib/matrixrtc/CallMembership.js +91 -100
  5. package/lib/matrixrtc/CallMembership.js.map +1 -1
  6. package/lib/matrixrtc/EncryptionManager.d.ts +6 -4
  7. package/lib/matrixrtc/EncryptionManager.d.ts.map +1 -1
  8. package/lib/matrixrtc/EncryptionManager.js.map +1 -1
  9. package/lib/matrixrtc/IMembershipManager.d.ts +2 -15
  10. package/lib/matrixrtc/IMembershipManager.d.ts.map +1 -1
  11. package/lib/matrixrtc/IMembershipManager.js.map +1 -1
  12. package/lib/matrixrtc/LivekitTransport.d.ts +36 -7
  13. package/lib/matrixrtc/LivekitTransport.d.ts.map +1 -1
  14. package/lib/matrixrtc/LivekitTransport.js +29 -2
  15. package/lib/matrixrtc/LivekitTransport.js.map +1 -1
  16. package/lib/matrixrtc/MatrixRTCSession.d.ts +12 -51
  17. package/lib/matrixrtc/MatrixRTCSession.d.ts.map +1 -1
  18. package/lib/matrixrtc/MatrixRTCSession.js +10 -66
  19. package/lib/matrixrtc/MatrixRTCSession.js.map +1 -1
  20. package/lib/matrixrtc/MembershipManager.d.ts +5 -10
  21. package/lib/matrixrtc/MembershipManager.d.ts.map +1 -1
  22. package/lib/matrixrtc/MembershipManager.js +25 -44
  23. package/lib/matrixrtc/MembershipManager.js.map +1 -1
  24. package/lib/matrixrtc/RTCEncryptionManager.d.ts +8 -8
  25. package/lib/matrixrtc/RTCEncryptionManager.d.ts.map +1 -1
  26. package/lib/matrixrtc/RTCEncryptionManager.js +30 -22
  27. package/lib/matrixrtc/RTCEncryptionManager.js.map +1 -1
  28. package/lib/matrixrtc/ToDeviceKeyTransport.js +7 -8
  29. package/lib/matrixrtc/ToDeviceKeyTransport.js.map +1 -1
  30. package/lib/matrixrtc/membershipData/rtc.d.ts +8 -13
  31. package/lib/matrixrtc/membershipData/rtc.d.ts.map +1 -1
  32. package/lib/matrixrtc/membershipData/rtc.js +2 -11
  33. package/lib/matrixrtc/membershipData/rtc.js.map +1 -1
  34. package/lib/matrixrtc/membershipData/session.d.ts +6 -2
  35. package/lib/matrixrtc/membershipData/session.d.ts.map +1 -1
  36. package/lib/matrixrtc/membershipData/session.js +3 -0
  37. package/lib/matrixrtc/membershipData/session.js.map +1 -1
  38. package/lib/matrixrtc/types.d.ts +5 -0
  39. package/lib/matrixrtc/types.d.ts.map +1 -1
  40. package/lib/matrixrtc/types.js +5 -0
  41. package/lib/matrixrtc/types.js.map +1 -1
  42. package/lib/models/event-timeline-set.d.ts +9 -2
  43. package/lib/models/event-timeline-set.d.ts.map +1 -1
  44. package/lib/models/event-timeline-set.js +8 -5
  45. package/lib/models/event-timeline-set.js.map +1 -1
  46. package/lib/models/room-sticky-events.d.ts +17 -2
  47. package/lib/models/room-sticky-events.d.ts.map +1 -1
  48. package/lib/models/room-sticky-events.js +88 -47
  49. package/lib/models/room-sticky-events.js.map +1 -1
  50. package/lib/models/room.d.ts +1 -1
  51. package/lib/models/room.d.ts.map +1 -1
  52. package/lib/models/room.js +8 -2
  53. package/lib/models/room.js.map +1 -1
  54. package/lib/models/thread.d.ts.map +1 -1
  55. package/lib/models/thread.js +23 -2
  56. package/lib/models/thread.js.map +1 -1
  57. package/lib/rendezvous/MSC4108SignInWithQR.d.ts +3 -3
  58. package/lib/rendezvous/MSC4108SignInWithQR.d.ts.map +1 -1
  59. package/lib/rendezvous/MSC4108SignInWithQR.js.map +1 -1
  60. package/lib/rendezvous/SignInWithQRFlow.d.ts +95 -0
  61. package/lib/rendezvous/SignInWithQRFlow.d.ts.map +1 -0
  62. package/lib/rendezvous/SignInWithQRFlow.js +3 -0
  63. package/lib/rendezvous/SignInWithQRFlow.js.map +1 -0
  64. package/lib/rendezvous/index.d.ts +1 -0
  65. package/lib/rendezvous/index.d.ts.map +1 -1
  66. package/lib/rendezvous/index.js.map +1 -1
  67. package/lib/rust-crypto/index.js +5 -1
  68. package/lib/rust-crypto/index.js.map +1 -1
  69. package/package.json +3 -3
  70. package/src/matrixrtc/CallMembership.ts +85 -95
  71. package/src/matrixrtc/EncryptionManager.ts +6 -4
  72. package/src/matrixrtc/IMembershipManager.ts +2 -15
  73. package/src/matrixrtc/LivekitTransport.ts +58 -9
  74. package/src/matrixrtc/MatrixRTCSession.ts +21 -80
  75. package/src/matrixrtc/MembershipManager.ts +23 -40
  76. package/src/matrixrtc/RTCEncryptionManager.ts +51 -39
  77. package/src/matrixrtc/ToDeviceKeyTransport.ts +7 -7
  78. package/src/matrixrtc/membershipData/rtc.ts +9 -23
  79. package/src/matrixrtc/membershipData/session.ts +14 -2
  80. package/src/matrixrtc/types.ts +6 -0
  81. package/src/models/event-timeline-set.ts +19 -4
  82. package/src/models/room-sticky-events.ts +92 -58
  83. package/src/models/room.ts +8 -2
  84. package/src/models/thread.ts +25 -3
  85. package/src/rendezvous/MSC4108SignInWithQR.ts +3 -3
  86. package/src/rendezvous/SignInWithQRFlow.ts +117 -0
  87. package/src/rendezvous/index.ts +1 -0
  88. package/src/rust-crypto/index.ts +5 -1
package/CHANGELOG.md CHANGED
@@ -1,3 +1,26 @@
1
+ Changes in [43.0.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v43.0.0) (2026-09-29)
2
+ ==================================================================================================
3
+ ## 🚨 BREAKING CHANGES
4
+
5
+ * Bring OAuth token refresh into the js-sdk ([#5520](https://github.com/matrix-org/matrix-js-sdk/pull/5520)). Contributed by @dbkr.
6
+
7
+ ## ✨ Features
8
+
9
+ * Update RTC notification and decline events as per MSC4075 ([#5544](https://github.com/matrix-org/matrix-js-sdk/pull/5544)). Contributed by @Johennes.
10
+ * Add support of the stable room summary endpoint ([#5552](https://github.com/matrix-org/matrix-js-sdk/pull/5552)). Contributed by @florianduros.
11
+ * Let applications publish their own data in MatrixRTC memberships ([#5550](https://github.com/matrix-org/matrix-js-sdk/pull/5550)). Contributed by @ara4n.
12
+ * Bring OAuth token refresh into the js-sdk ([#5520](https://github.com/matrix-org/matrix-js-sdk/pull/5520)). Contributed by @dbkr.
13
+
14
+ ## 🐛 Bug Fixes
15
+
16
+ * MatrixRTC: restart the delayed leave event before extending a membership's expiry ([#5522](https://github.com/matrix-org/matrix-js-sdk/pull/5522)). Contributed by @ara4n.
17
+ * MatrixRTC: don't let a superseded membership recalculation overwrite a newer one ([#5523](https://github.com/matrix-org/matrix-js-sdk/pull/5523)). Contributed by @ara4n.
18
+ * Preserve read receipts of different types during sync accumulation ([#5541](https://github.com/matrix-org/matrix-js-sdk/pull/5541)). Contributed by @rubinsh.
19
+ * Fix sync.ts to emit state events when msc4222 state\_after is enabled ([#5542](https://github.com/matrix-org/matrix-js-sdk/pull/5542)). Contributed by @maheichyk.
20
+ * Set hasCurrentUserParticipated when the current user sends a thread reply ([#5516](https://github.com/matrix-org/matrix-js-sdk/pull/5516)). Contributed by @nathanael-h.
21
+ * Fix type definitions on `import|exportSecretsBundle` ([#5526](https://github.com/matrix-org/matrix-js-sdk/pull/5526)). Contributed by @richvdh.
22
+
23
+
1
24
  Changes in [42.4.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v42.4.0) (2026-09-15)
2
25
  ==================================================================================================
3
26
  ## ✨ Features
@@ -1,4 +1,4 @@
1
- import { type RTCCallIntent, type Transport, type SlotDescription } from "./types.ts";
1
+ import { type RTCCallCapability, type RTCCallIntent, type Transport, type SlotDescription } from "./types.ts";
2
2
  import { type MatrixEvent } from "../models/event.ts";
3
3
  import { type RtcMembershipData, type SessionMembershipData } from "./membershipData/index.ts";
4
4
  /**
@@ -32,6 +32,15 @@ export declare class CallMembership {
32
32
  /** The Matrix event that this membership is based on */
33
33
  private readonly matrixEvent;
34
34
  private readonly membershipData;
35
+ /**
36
+ * Possible identities which this member may have on the backends of
37
+ * their published transports.
38
+ */
39
+ readonly backendIdentities: string[];
40
+ /**
41
+ * @deprecated Check the backend for the existence of any of
42
+ * {@link backendIdentities} instead.
43
+ */
35
44
  readonly rtcBackendIdentity: string;
36
45
  /**
37
46
  * Parse the membershipdata from a call membership event.
@@ -55,13 +64,20 @@ export declare class CallMembership {
55
64
  * Use `parseFromEvent`.
56
65
  * Constructor should only be used by tests.
57
66
  * @private
58
- * @param matrixEvent
59
- * @param membershipData
60
- * @param rtcBackendIdentity
61
67
  */
62
68
  constructor(
63
69
  /** The Matrix event that this membership is based on */
64
- matrixEvent: LimitedEvent, membershipData: MembershipData, rtcBackendIdentity: string);
70
+ matrixEvent: LimitedEvent, membershipData: MembershipData,
71
+ /**
72
+ * Possible identities which this member may have on the backends of
73
+ * their published transports.
74
+ */
75
+ backendIdentities: string[],
76
+ /**
77
+ * @deprecated Check the backend for the existence of any of
78
+ * {@link backendIdentities} instead.
79
+ */
80
+ rtcBackendIdentity: string);
65
81
  /** @deprecated use userId instead */
66
82
  get sender(): string;
67
83
  get userId(): string;
@@ -73,15 +89,11 @@ export declare class CallMembership {
73
89
  get slotId(): string;
74
90
  get deviceId(): string;
75
91
  get callIntent(): RTCCallIntent | undefined;
92
+ get callCapabilities(): RTCCallCapability[] | undefined;
76
93
  /**
77
94
  * Parsed `slot_id` (format `{application}#{id}`) into its components (application and id).
78
95
  */
79
96
  get slotDescription(): SlotDescription;
80
- /**
81
- * The application `type`.
82
- * @deprecated Use @see applicationData
83
- */
84
- get application(): string;
85
97
  /**
86
98
  * Information about the application being used for the RTC session.
87
99
  * May contain extra keys specific to the application.
@@ -95,8 +107,8 @@ export declare class CallMembership {
95
107
  /**
96
108
  * This computes the membership ID for the membership.
97
109
  * For the sticky event based rtcSessionData this is trivial it is `member.id`.
98
- * This is not supposed to be used to identity on an rtc backend. This is just a nouance for
99
- * a generated (sha256) anonymised identity. Only send `rtcBackendIdentity` to any rtc backend service.
110
+ * This is not supposed to be used to identity on an rtc backend. This is just a nuance for
111
+ * a generated (sha256) anonymised identity. Only send {@link backendIdentities} to any rtc backend service.
100
112
  *
101
113
  * For the legacy sessionMemberEvents it is a bit more complex. Here we sometimes do not have this data
102
114
  * in the event content and we expected the SFU and the client to use `${this.matrixEventData.sender}:${data.device_id}`.
@@ -107,10 +119,6 @@ export declare class CallMembership {
107
119
  * It is also possible for a session event to set a custom membershipID. in that case this will be used.
108
120
  */
109
121
  get memberId(): string;
110
- /**
111
- * @deprecated renamed to `memberId`
112
- */
113
- get membershipID(): string;
114
122
  createdTs(): number;
115
123
  /**
116
124
  * Gets the absolute expiry timestamp of the membership.
@@ -133,17 +141,14 @@ export declare class CallMembership {
133
141
  * Directly relates to the `transports.published` field.
134
142
  *
135
143
  * ## Legacy session membership
136
- * In case of a legacy session membership (m.call.member) this will return the selected transport where
137
- * media is published. How this selection happens depends on the `focus_active` field of the session membership.
138
- * If the `focus_selection` is `oldest_membership` this will return the transport of the oldest membership
139
- * in the room (based on the `created_ts` field of the session membership).
140
- * If the `focus_selection` is `multi_sfu` it will return the first transport of the `foci_preferred` list.
141
- * (`multi_sfu` is equivalent to how `m.rtc.member` `transports.published` work).
142
- * @param oldestMembership For backwards compatibility with session membership (legacy). Unused in case of RTC membership.
143
- * Always required to make the consumer not care if it deals with RTC or session memberships.
144
+ * In case of a legacy session membership (m.call.member) this will return the first transport of the
145
+ * `foci_preferred` list. (`multi_sfu` is equivalent to how `m.rtc.member` `transports.published` work).
146
+ *
147
+ * @param _oldestMembership Deprecated and unused.
148
+ *
144
149
  * @returns The transport this membership uses to publish media or undefined if no transport is available.
145
150
  */
146
- getTransport(oldestMembership: CallMembership): Transport | undefined;
151
+ getTransport(_oldestMembership?: CallMembership): Transport | undefined;
147
152
  /**
148
153
  * The value of the `transports.published` field for RTC memberships (m.rtc.member).
149
154
  * Or the value of the `foci_preferred` field for legacy session memberships (m.call.member).
@@ -1 +1 @@
1
- {"version":3,"file":"CallMembership.d.ts","sourceRoot":"","sources":["../../src/matrixrtc/CallMembership.ts"],"names":[],"mappings":"AAiBA,OAAO,EAAE,KAAK,aAAa,EAAE,KAAK,SAAS,EAAE,KAAK,eAAe,EAAE,MAAM,YAAY,CAAC;AACtF,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAGtD,OAAO,EAGH,KAAK,iBAAiB,EAEtB,KAAK,qBAAqB,EAE7B,MAAM,2BAA2B,CAAC;AAGnC;;;;GAIG;AACH,eAAO,MAAM,uBAAuB,QAAqB,CAAC;AAgB1D;;GAEG;AACH,aAAK,cAAc;IACf;;OAEG;IACH,GAAG,QAAQ;IACX;;OAEG;IACH,OAAO,YAAY;CACtB;AAED,KAAK,cAAc,GACb;IAAE,IAAI,EAAE,cAAc,CAAC,GAAG,CAAC;IAAC,IAAI,EAAE,iBAAiB,CAAA;CAAE,GACrD;IAAE,IAAI,EAAE,cAAc,CAAC,OAAO,CAAC;IAAC,IAAI,EAAE,qBAAqB,CAAA;CAAE,CAAC;AAEpE,KAAK,YAAY,GAAG,IAAI,CAAC,WAAW,EAAE,OAAO,GAAG,WAAW,GAAG,OAAO,GAAG,SAAS,GAAG,YAAY,CAAC,CAAC;AAElG,qBAAa,cAAc;IAkEnB,wDAAwD;IACxD,OAAO,CAAC,QAAQ,CAAC,WAAW;IAC5B,OAAO,CAAC,QAAQ,CAAC,cAAc;aACf,kBAAkB,EAAE,MAAM;IApE9C;;;;;OAKG;IACH,OAAc,6BAA6B,CAAC,WAAW,EAAE,YAAY,GAAG,cAAc,CAoBrF;IAED;;;OAGG;IACH,OAAoB,cAAc,CAAC,WAAW,EAAE,YAAY,GAAG,OAAO,CAAC,cAAc,CAAC,CAWrF;IAED,OAAc,KAAK,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,CAAC,CAAC,EAAE,cAAc,GAAG,OAAO,CAEnE;IAED,OAAO,CAAC,MAAM,CAAS;IAEvB;;2EAEuE;IACvE,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAsC;IAEtE;;;;;;;OAOG;IACH;IACI,wDAAwD;IACvC,WAAW,EAAE,YAAY,EACzB,cAAc,EAAE,cAAc,EAC/B,kBAAkB,EAAE,MAAM,EAU7C;IAED,qCAAqC;IACrC,IAAW,MAAM,IAAI,MAAM,CAE1B;IAED,IAAW,MAAM,IAAI,MAAM,CAS1B;IAED,IAAW,OAAO,IAAI,MAAM,CAE3B;IAED;;;OAGG;IACH,IAAW,MAAM,IAAI,MAAM,CAgD1B;IAED,IAAW,QAAQ,IAAI,MAAM,CAS5B;IAED,IAAW,UAAU,IAAI,aAAa,GAAG,SAAS,CAOjD;IAED;;OAEG;IACH,IAAW,eAAe,IAAI,eAAe,CAO5C;IAED;;;OAGG;IACH,IAAW,WAAW,IAAI,MAAM,CAE/B;IAED;;;OAGG;IACH,IAAW,eAAe,IAAI;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,CAerE;IAED,mHAAmH;IACnH,IAAW,KAAK,IAAI,qBAAqB,CAAC,OAAO,CAAC,GAAG,SAAS,CAS7D;IAED;;;;;;;;;;;;;OAaG;IACH,IAAW,QAAQ,IAAI,MAAM,CAkB5B;IAED;;OAEG;IACH,IAAW,YAAY,IAAI,MAAM,CAEhC;IAEM,SAAS,IAAI,MAAM,CAUzB;IAED;;;OAGG;IACI,iBAAiB,IAAI,MAAM,GAAG,SAAS,CAU7C;IAED;;;OAGG;IACI,gBAAgB,IAAI,MAAM,GAAG,SAAS,CAY5C;IAED;;OAEG;IACI,SAAS,IAAI,OAAO,CAS1B;IAED;;;;;;;;;;;;;;;;OAgBG;IACI,YAAY,CAAC,gBAAgB,EAAE,cAAc,GAAG,SAAS,GAAG,SAAS,CAqB3E;IAED;;;OAGG;IACH,IAAW,UAAU,IAAI,SAAS,EAAE,CASnC;CACJ"}
1
+ {"version":3,"file":"CallMembership.d.ts","sourceRoot":"","sources":["../../src/matrixrtc/CallMembership.ts"],"names":[],"mappings":"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"}
@@ -23,6 +23,7 @@ import { logger } from "../logger.js";
23
23
  import { computeSlotId, slotIdToDescription } from "./utils.js";
24
24
  import { checkRtcMembershipData, computeRtcIdentityRaw, checkSessionsMembershipData, MatrixRTCMembershipParseError } from "./membershipData/index.js";
25
25
  import { EventType } from "../@types/event.js";
26
+ import { isUnstableLivekitTransport } from "./LivekitTransport.js";
26
27
 
27
28
  /**
28
29
  * The default duration in milliseconds that a membership is considered valid for.
@@ -48,6 +49,47 @@ var MembershipKind = /*#__PURE__*/function (MembershipKind) {
48
49
  MembershipKind["Session"] = "session";
49
50
  return MembershipKind;
50
51
  }(MembershipKind || {});
52
+ function getDeviceId({
53
+ kind,
54
+ data
55
+ }) {
56
+ switch (kind) {
57
+ case MembershipKind.RTC:
58
+ return data.member.device_id;
59
+ case MembershipKind.Session:
60
+ return data.device_id;
61
+ }
62
+ }
63
+ function getMemberId({
64
+ kind,
65
+ data
66
+ }, sender) {
67
+ // the createdTs behaves equivalent to the membershipID.
68
+ // we only need the field for the legacy member events where we needed to update them
69
+ // synapse ignores sending state events if they have the same content.
70
+ switch (kind) {
71
+ case MembershipKind.RTC:
72
+ return data.member.id;
73
+ case MembershipKind.Session:
74
+ return (
75
+ // best case we have a client already publishing the right custom membershipId
76
+ data.membershipID ??
77
+ // alternatively we use the hardcoded jwt id default value (used until version 0.16.0)
78
+ `${sender}:${data.device_id}`
79
+ );
80
+ }
81
+ }
82
+ function getTransports({
83
+ kind,
84
+ data
85
+ }) {
86
+ switch (kind) {
87
+ case MembershipKind.RTC:
88
+ return data.transports.published;
89
+ case MembershipKind.Session:
90
+ return data.foci_preferred;
91
+ }
92
+ }
51
93
  // TODO: Rename to RtcMembership once we removed the legacy SessionMembership is removed, to avoid confusion.
52
94
  export class CallMembership {
53
95
  /**
@@ -89,9 +131,21 @@ export class CallMembership {
89
131
  * @param matrixEvent The Matrix event to read.
90
132
  */
91
133
  static async parseFromEvent(matrixEvent) {
134
+ const sender = matrixEvent.getSender();
135
+ if (sender === undefined) throw new Error("matrixEvent is missing sender field");
92
136
  const membershipData = this.membershipDataFromMatrixEvent(matrixEvent);
93
- const rtcBackendIdentity = membershipData.kind === MembershipKind.RTC ? await computeRtcIdentityRaw(membershipData.data.member.user_id, membershipData.data.member.device_id, membershipData.data.member.id) : `${matrixEvent.getSender()}:${membershipData.data.device_id}`;
94
- return new CallMembership(matrixEvent, membershipData, rtcBackendIdentity);
137
+ const livekitTransports = getTransports(membershipData).filter(isUnstableLivekitTransport);
138
+ const legacyIdentity = `${sender}:${getDeviceId(membershipData)}`;
139
+ const backendIdentities = [];
140
+ if (livekitTransports.some(t => "url" in t)) {
141
+ backendIdentities.push(await computeRtcIdentityRaw(sender, getMemberId(membershipData, sender)));
142
+ }
143
+ if (livekitTransports.some(t => "livekit_service_url" in t)) {
144
+ backendIdentities.push(legacyIdentity);
145
+ }
146
+
147
+ // rtcBackendIdentity is deprecated, so it's fine to always set it to the legacy identity.
148
+ return new CallMembership(matrixEvent, membershipData, backendIdentities, legacyIdentity);
95
149
  }
96
150
  static equal(a, b) {
97
151
  return deepCompare(a?.membershipData, b?.membershipData);
@@ -100,12 +154,19 @@ export class CallMembership {
100
154
  * Use `parseFromEvent`.
101
155
  * Constructor should only be used by tests.
102
156
  * @private
103
- * @param matrixEvent
104
- * @param membershipData
105
- * @param rtcBackendIdentity
106
157
  */
107
158
  constructor(/** The Matrix event that this membership is based on */
108
- matrixEvent, membershipData, rtcBackendIdentity) {
159
+ matrixEvent, membershipData,
160
+ /**
161
+ * Possible identities which this member may have on the backends of
162
+ * their published transports.
163
+ */
164
+ backendIdentities,
165
+ /**
166
+ * @deprecated Check the backend for the existence of any of
167
+ * {@link backendIdentities} instead.
168
+ */
169
+ rtcBackendIdentity) {
109
170
  _defineProperty(this, "logger", void 0);
110
171
  /** The parsed data from the Matrix event.
111
172
  * To access checked eventId and sender from the matrixEvent.
@@ -113,11 +174,12 @@ export class CallMembership {
113
174
  _defineProperty(this, "matrixEventData", void 0);
114
175
  this.matrixEvent = matrixEvent;
115
176
  this.membershipData = membershipData;
177
+ this.backendIdentities = backendIdentities;
116
178
  this.rtcBackendIdentity = rtcBackendIdentity;
117
179
  const eventId = matrixEvent.getId();
118
180
  const sender = matrixEvent.getSender();
119
- if (eventId === undefined) throw new Error("parentEvent is missing eventId field");
120
- if (sender === undefined) throw new Error("parentEvent is missing sender field");
181
+ if (eventId === undefined) throw new Error("matrixEvent is missing eventId field");
182
+ if (sender === undefined) throw new Error("matrixEvent is missing sender field");
121
183
  this.logger = logger.getChild(`[CallMembership ${sender}:${this.deviceId}]`);
122
184
  this.matrixEventData = {
123
185
  eventId,
@@ -130,17 +192,7 @@ export class CallMembership {
130
192
  return this.userId;
131
193
  }
132
194
  get userId() {
133
- const {
134
- kind,
135
- data
136
- } = this.membershipData;
137
- switch (kind) {
138
- case MembershipKind.RTC:
139
- return data.member.user_id;
140
- case MembershipKind.Session:
141
- default:
142
- return this.matrixEventData.sender;
143
- }
195
+ return this.matrixEventData.sender;
144
196
  }
145
197
  get eventId() {
146
198
  return this.matrixEventData.eventId;
@@ -206,17 +258,7 @@ export class CallMembership {
206
258
  }
207
259
  }
208
260
  get deviceId() {
209
- const {
210
- kind,
211
- data
212
- } = this.membershipData;
213
- switch (kind) {
214
- case MembershipKind.RTC:
215
- return data.member.device_id;
216
- case MembershipKind.Session:
217
- default:
218
- return data.device_id;
219
- }
261
+ return getDeviceId(this.membershipData);
220
262
  }
221
263
  get callIntent() {
222
264
  const intent = this.applicationData["m.call.intent"];
@@ -226,6 +268,13 @@ export class CallMembership {
226
268
  this.logger.warn("RTC membership has invalid m.call.intent");
227
269
  return undefined;
228
270
  }
271
+ get callCapabilities() {
272
+ const capabilities = this.applicationData["capabilities"];
273
+ if (capabilities === undefined) return undefined;
274
+ if (Array.isArray(capabilities) && capabilities.every(c => typeof c === "string")) return capabilities;
275
+ this.logger.warn("RTC membership has invalid capabilities");
276
+ return undefined;
277
+ }
229
278
 
230
279
  /**
231
280
  * Parsed `slot_id` (format `{application}#{id}`) into its components (application and id).
@@ -245,14 +294,6 @@ export class CallMembership {
245
294
  return slotIdToDescription(this.slotId);
246
295
  }
247
296
 
248
- /**
249
- * The application `type`.
250
- * @deprecated Use @see applicationData
251
- */
252
- get application() {
253
- return this.applicationData.type;
254
- }
255
-
256
297
  /**
257
298
  * Information about the application being used for the RTC session.
258
299
  * May contain extra keys specific to the application.
@@ -302,8 +343,8 @@ export class CallMembership {
302
343
  /**
303
344
  * This computes the membership ID for the membership.
304
345
  * For the sticky event based rtcSessionData this is trivial it is `member.id`.
305
- * This is not supposed to be used to identity on an rtc backend. This is just a nouance for
306
- * a generated (sha256) anonymised identity. Only send `rtcBackendIdentity` to any rtc backend service.
346
+ * This is not supposed to be used to identity on an rtc backend. This is just a nuance for
347
+ * a generated (sha256) anonymised identity. Only send {@link backendIdentities} to any rtc backend service.
307
348
  *
308
349
  * For the legacy sessionMemberEvents it is a bit more complex. Here we sometimes do not have this data
309
350
  * in the event content and we expected the SFU and the client to use `${this.matrixEventData.sender}:${data.device_id}`.
@@ -314,33 +355,7 @@ export class CallMembership {
314
355
  * It is also possible for a session event to set a custom membershipID. in that case this will be used.
315
356
  */
316
357
  get memberId() {
317
- // the createdTs behaves equivalent to the membershipID.
318
- // we only need the field for the legacy member events where we needed to update them
319
- // synapse ignores sending state events if they have the same content.
320
- const {
321
- kind,
322
- data
323
- } = this.membershipData;
324
- switch (kind) {
325
- case "rtc":
326
- return data.member.id;
327
- case "session":
328
- return (
329
- // best case we have a client already publishing the right custom membershipId
330
- data.membershipID ??
331
- // alternativly we use the hard coded jwt id defuatl value (used until version 0.16.0)
332
- `${this.matrixEventData.sender}:${data.device_id}`
333
- );
334
- default:
335
- throw Error("Not possible to get memberID without knowing the membership event kind");
336
- }
337
- }
338
-
339
- /**
340
- * @deprecated renamed to `memberId`
341
- */
342
- get membershipID() {
343
- return this.memberId;
358
+ return getMemberId(this.membershipData, this.matrixEventData.sender);
344
359
  }
345
360
  createdTs() {
346
361
  const {
@@ -349,7 +364,7 @@ export class CallMembership {
349
364
  } = this.membershipData;
350
365
  switch (kind) {
351
366
  case MembershipKind.RTC:
352
- // TODO we need to read the referenced (relation) event if available to get the real created_ts
367
+ // TODO Do we need this to represent the TS of the original join?
353
368
  return this.matrixEvent.getTs();
354
369
  case MembershipKind.Session:
355
370
  default:
@@ -419,17 +434,14 @@ export class CallMembership {
419
434
  * Directly relates to the `transports.published` field.
420
435
  *
421
436
  * ## Legacy session membership
422
- * In case of a legacy session membership (m.call.member) this will return the selected transport where
423
- * media is published. How this selection happens depends on the `focus_active` field of the session membership.
424
- * If the `focus_selection` is `oldest_membership` this will return the transport of the oldest membership
425
- * in the room (based on the `created_ts` field of the session membership).
426
- * If the `focus_selection` is `multi_sfu` it will return the first transport of the `foci_preferred` list.
427
- * (`multi_sfu` is equivalent to how `m.rtc.member` `transports.published` work).
428
- * @param oldestMembership For backwards compatibility with session membership (legacy). Unused in case of RTC membership.
429
- * Always required to make the consumer not care if it deals with RTC or session memberships.
437
+ * In case of a legacy session membership (m.call.member) this will return the first transport of the
438
+ * `foci_preferred` list. (`multi_sfu` is equivalent to how `m.rtc.member` `transports.published` work).
439
+ *
440
+ * @param _oldestMembership Deprecated and unused.
441
+ *
430
442
  * @returns The transport this membership uses to publish media or undefined if no transport is available.
431
443
  */
432
- getTransport(oldestMembership) {
444
+ getTransport(_oldestMembership) {
433
445
  const {
434
446
  kind,
435
447
  data
@@ -438,18 +450,7 @@ export class CallMembership {
438
450
  case MembershipKind.RTC:
439
451
  return data.transports.published[0];
440
452
  case MembershipKind.Session:
441
- switch (data.focus_active.focus_selection) {
442
- case "oldest_membership":
443
- if (CallMembership.equal(this, oldestMembership)) return data.foci_preferred[0];
444
- if (oldestMembership !== undefined) return oldestMembership.getTransport(oldestMembership);
445
- break;
446
- case "multi_sfu":
447
- return data.foci_preferred[0];
448
- default:
449
- // `focus_selection` not understood.
450
- return undefined;
451
- }
452
- break;
453
+ return data.foci_preferred[0];
453
454
  default:
454
455
  return undefined;
455
456
  }
@@ -460,17 +461,7 @@ export class CallMembership {
460
461
  * Or the value of the `foci_preferred` field for legacy session memberships (m.call.member).
461
462
  */
462
463
  get transports() {
463
- const {
464
- kind,
465
- data
466
- } = this.membershipData;
467
- switch (kind) {
468
- case MembershipKind.RTC:
469
- return data.transports.published;
470
- case MembershipKind.Session:
471
- default:
472
- return data.foci_preferred;
473
- }
464
+ return getTransports(this.membershipData);
474
465
  }
475
466
  }
476
467
  //# sourceMappingURL=CallMembership.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"CallMembership.js","names":[],"sources":["../../src/matrixrtc/CallMembership.ts"],"sourcesContent":["/*\nCopyright 2023-2026 The Matrix.org Foundation C.I.C.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n*/\n\nimport { deepCompare } from \"../utils.ts\";\nimport { type RTCCallIntent, type Transport, type SlotDescription } from \"./types.ts\";\nimport { type MatrixEvent } from \"../models/event.ts\";\nimport { type Logger, logger } from \"../logger.ts\";\nimport { computeSlotId, slotIdToDescription } from \"./utils.ts\";\nimport {\n checkRtcMembershipData,\n computeRtcIdentityRaw,\n type RtcMembershipData,\n checkSessionsMembershipData,\n type SessionMembershipData,\n MatrixRTCMembershipParseError,\n} from \"./membershipData/index.ts\";\nimport { EventType } from \"../@types/event.ts\";\n\n/**\n * The default duration in milliseconds that a membership is considered valid for.\n * Ordinarily the client responsible for the session will update the membership before it expires.\n * We use this duration as the fallback case where stale sessions are present for some reason.\n */\nexport const DEFAULT_EXPIRE_DURATION = 1000 * 60 * 60 * 4;\n\n/** The fields of a legacy session membership that belong to the session, not the application */\nconst sessionFields: (keyof SessionMembershipData)[] = [\n \"application\",\n \"call_id\",\n \"device_id\",\n \"focus_active\",\n \"foci_preferred\",\n \"created_ts\",\n \"scope\",\n \"expires\",\n \"m.call.intent\",\n \"membershipID\",\n];\n\n/**\n * Describes the source event type that provided the membership data.\n */\nenum MembershipKind {\n /**\n * The modern MSC4143 format event.\n */\n RTC = \"rtc\",\n /**\n * The legacy call event type.\n */\n Session = \"session\",\n}\n\ntype MembershipData =\n | { kind: MembershipKind.RTC; data: RtcMembershipData }\n | { kind: MembershipKind.Session; data: SessionMembershipData };\n\ntype LimitedEvent = Pick<MatrixEvent, \"getId\" | \"getSender\" | \"getTs\" | \"getType\" | \"getContent\">;\n// TODO: Rename to RtcMembership once we removed the legacy SessionMembership is removed, to avoid confusion.\nexport class CallMembership {\n /**\n * Parse the membershipdata from a call membership event.\n * @param matrixEvent The Matrix event to read.\n * @returns MembershipData in either MembershipKind.RTC or MembershipKind.Session format.\n * @throws If the content is neither format.\n */\n public static membershipDataFromMatrixEvent(matrixEvent: LimitedEvent): MembershipData {\n const sender = matrixEvent.getSender();\n const evType = matrixEvent.getType();\n const data = matrixEvent.getContent();\n if (sender === undefined) throw new Error(\"matrixEvent is missing sender field\");\n try {\n // Event types are strictly checked here.\n if (evType === EventType.RTCMembership && checkRtcMembershipData(data, sender)) {\n return { kind: MembershipKind.RTC, data };\n } else if (evType === EventType.GroupCallMemberPrefix && checkSessionsMembershipData(data)) {\n return { kind: MembershipKind.Session, data };\n } else {\n throw Error(`'${evType} is not a known call membership type`);\n }\n } catch (ex) {\n if (ex instanceof MatrixRTCMembershipParseError) {\n logger.debug(\"CallMembership.MatrixRTCMembershipParseError provided invalid data\", data);\n }\n throw ex;\n }\n }\n\n /**\n * Parse the contents of a MatrixEvent and create a CallMembership instance.\n * @param matrixEvent The Matrix event to read.\n */\n public static async parseFromEvent(matrixEvent: LimitedEvent): Promise<CallMembership> {\n const membershipData: MembershipData = this.membershipDataFromMatrixEvent(matrixEvent);\n const rtcBackendIdentity =\n membershipData.kind === MembershipKind.RTC\n ? await computeRtcIdentityRaw(\n membershipData.data.member.user_id,\n membershipData.data.member.device_id,\n membershipData.data.member.id,\n )\n : `${matrixEvent.getSender()}:${membershipData.data.device_id}`;\n return new CallMembership(matrixEvent, membershipData, rtcBackendIdentity);\n }\n\n public static equal(a?: CallMembership, b?: CallMembership): boolean {\n return deepCompare(a?.membershipData, b?.membershipData);\n }\n\n private logger: Logger;\n\n /** The parsed data from the Matrix event.\n * To access checked eventId and sender from the matrixEvent.\n * Class construction will fail if these values cannot get obtained. */\n private readonly matrixEventData: { eventId: string; sender: string };\n\n /**\n * Use `parseFromEvent`.\n * Constructor should only be used by tests.\n * @private\n * @param matrixEvent\n * @param membershipData\n * @param rtcBackendIdentity\n */\n public constructor(\n /** The Matrix event that this membership is based on */\n private readonly matrixEvent: LimitedEvent,\n private readonly membershipData: MembershipData,\n public readonly rtcBackendIdentity: string,\n ) {\n const eventId = matrixEvent.getId();\n const sender = matrixEvent.getSender();\n\n if (eventId === undefined) throw new Error(\"parentEvent is missing eventId field\");\n if (sender === undefined) throw new Error(\"parentEvent is missing sender field\");\n\n this.logger = logger.getChild(`[CallMembership ${sender}:${this.deviceId}]`);\n this.matrixEventData = { eventId, sender };\n }\n\n /** @deprecated use userId instead */\n public get sender(): string {\n return this.userId;\n }\n\n public get userId(): string {\n const { kind, data } = this.membershipData;\n switch (kind) {\n case MembershipKind.RTC:\n return data.member.user_id;\n case MembershipKind.Session:\n default:\n return this.matrixEventData.sender;\n }\n }\n\n public get eventId(): string {\n return this.matrixEventData.eventId;\n }\n\n /**\n * The ID of the MatrixRTC slot that this membership belongs to (format `{application}#{id}`).\n * This is computed in case SessionMembershipData is used.\n */\n public get slotId(): string {\n const { kind, data } = this.membershipData;\n if (data.application === \"m.call\") {\n switch (kind) {\n case MembershipKind.RTC:\n return data.slot_id;\n case MembershipKind.Session:\n default: {\n const [application, id] = [data.application, data.call_id];\n\n // INFO_SLOT_ID_LEGACY_CASE (search for all occurances of this INFO to get the full picture)\n // The spec got changed to use `\"ROOM\"` instead of `\"\"` empyt string for the implicit default call.\n // State events still are sent with `\"\"` however. To find other events that should end up in the same call,\n // we use the slotId.\n // Since the CallMembership is the public representation of a rtc.member event, we just pretend it is a\n // \"ROOM\" slotId/call_id.\n // This makes all the remote members work with just this simple trick.\n //\n // We of course now need to be careful when sending legacy events (state events)\n // They get a slotDescription containing \"ROOM\" since this is what we use starting at the time this comment\n // is commited.\n //\n // See the Other INFO_SLOT_ID_LEGACY_CASE comments to see where we revert back to \"\" just before sending the event.\n let compatibilityAdaptedId: string;\n if (id === \"\") {\n compatibilityAdaptedId = \"ROOM\";\n this.logger?.info(\"use slotId compat hack emptyString -> ROOM\");\n } else {\n compatibilityAdaptedId = id;\n }\n return computeSlotId({\n application,\n id: compatibilityAdaptedId,\n });\n }\n }\n }\n\n this.logger?.info(\"NOT using slotId compat hack emptyString -> ROOM\");\n // This is what the function should look like for any other application that did not\n // go through a `\"\"`=> `\"ROOM\"` rename\n switch (kind) {\n case MembershipKind.RTC:\n return data.slot_id;\n case MembershipKind.Session:\n default:\n return computeSlotId({ application: data.application, id: data.call_id });\n }\n }\n\n public get deviceId(): string {\n const { kind, data } = this.membershipData;\n switch (kind) {\n case MembershipKind.RTC:\n return data.member.device_id;\n case MembershipKind.Session:\n default:\n return data.device_id;\n }\n }\n\n public get callIntent(): RTCCallIntent | undefined {\n const intent = this.applicationData[\"m.call.intent\"];\n if (typeof intent === \"string\") {\n return intent;\n }\n this.logger.warn(\"RTC membership has invalid m.call.intent\");\n return undefined;\n }\n\n /**\n * Parsed `slot_id` (format `{application}#{id}`) into its components (application and id).\n */\n public get slotDescription(): SlotDescription {\n const { kind, data } = this.membershipData;\n if (kind === MembershipKind.RTC) {\n const id = data.slot_id.slice(`${data.application.type}#`.length);\n return { application: data.application.type, id };\n }\n return slotIdToDescription(this.slotId);\n }\n\n /**\n * The application `type`.\n * @deprecated Use @see applicationData\n */\n public get application(): string {\n return this.applicationData.type;\n }\n\n /**\n * Information about the application being used for the RTC session.\n * May contain extra keys specific to the application.\n */\n public get applicationData(): { type: string; [key: string]: unknown } {\n const { kind, data } = this.membershipData;\n switch (kind) {\n case MembershipKind.RTC:\n return data.application;\n case MembershipKind.Session:\n default: {\n // SessionData has no application object: the application's own\n // data sits at the top level beside the session fields, so\n // everything but those is the application's\n const { application, ...rest } = data;\n for (const key of sessionFields) delete rest[key as keyof typeof rest];\n return { ...rest, \"type\": application, \"m.call.intent\": data[\"m.call.intent\"] };\n }\n }\n }\n\n /** @deprecated scope is not used and will be removed in future versions. replaced by application specific types.*/\n public get scope(): SessionMembershipData[\"scope\"] | undefined {\n const { kind, data } = this.membershipData;\n switch (kind) {\n case MembershipKind.RTC:\n return undefined;\n case MembershipKind.Session:\n default:\n return data.scope;\n }\n }\n\n /**\n * This computes the membership ID for the membership.\n * For the sticky event based rtcSessionData this is trivial it is `member.id`.\n * This is not supposed to be used to identity on an rtc backend. This is just a nouance for\n * a generated (sha256) anonymised identity. Only send `rtcBackendIdentity` to any rtc backend service.\n *\n * For the legacy sessionMemberEvents it is a bit more complex. Here we sometimes do not have this data\n * in the event content and we expected the SFU and the client to use `${this.matrixEventData.sender}:${data.device_id}`.\n *\n * So if there is no membershipID we use the hard coded jwt id default (`${this.matrixEventData.sender}:${data.device_id}`)\n * value (used until version 0.16.0)\n *\n * It is also possible for a session event to set a custom membershipID. in that case this will be used.\n */\n public get memberId(): string {\n // the createdTs behaves equivalent to the membershipID.\n // we only need the field for the legacy member events where we needed to update them\n // synapse ignores sending state events if they have the same content.\n const { kind, data } = this.membershipData;\n switch (kind) {\n case \"rtc\":\n return data.member.id;\n case \"session\":\n return (\n // best case we have a client already publishing the right custom membershipId\n data.membershipID ??\n // alternativly we use the hard coded jwt id defuatl value (used until version 0.16.0)\n `${this.matrixEventData.sender}:${data.device_id}`\n );\n default:\n throw Error(\"Not possible to get memberID without knowing the membership event kind\");\n }\n }\n\n /**\n * @deprecated renamed to `memberId`\n */\n public get membershipID(): string {\n return this.memberId;\n }\n\n public createdTs(): number {\n const { kind, data } = this.membershipData;\n switch (kind) {\n case MembershipKind.RTC:\n // TODO we need to read the referenced (relation) event if available to get the real created_ts\n return this.matrixEvent.getTs();\n case MembershipKind.Session:\n default:\n return data.created_ts ?? this.matrixEvent.getTs();\n }\n }\n\n /**\n * Gets the absolute expiry timestamp of the membership.\n * @returns The absolute expiry time of the membership as a unix timestamp in milliseconds or undefined if not applicable\n */\n public getAbsoluteExpiry(): number | undefined {\n const { kind, data } = this.membershipData;\n switch (kind) {\n case MembershipKind.RTC:\n return undefined;\n case MembershipKind.Session:\n default:\n // TODO: calculate this from the MatrixRTCSession join configuration directly\n return this.createdTs() + (data.expires ?? DEFAULT_EXPIRE_DURATION);\n }\n }\n\n /**\n * @returns The number of milliseconds until the membership expires or undefined if applicable\n * @deprecated Not used by RTC events.\n */\n public getMsUntilExpiry(): number | undefined {\n const { kind } = this.membershipData;\n if (kind === MembershipKind.Session) {\n const absExpiry = this.getAbsoluteExpiry();\n if (absExpiry) {\n // Assume that local clock is sufficiently in sync with other clocks in the distributed system.\n // We used to try and adjust for the local clock being skewed, but there are cases where this is not accurate.\n // The current implementation allows for the local clock to be -infinity to +MatrixRTCSession.MEMBERSHIP_EXPIRY_TIME/2\n return absExpiry - Date.now();\n }\n }\n return undefined;\n }\n\n /**\n * @returns true if the membership has expired, otherwise false\n */\n public isExpired(): boolean {\n const { kind } = this.membershipData;\n switch (kind) {\n case MembershipKind.RTC:\n return false;\n case MembershipKind.Session:\n default:\n return this.getMsUntilExpiry()! <= 0;\n }\n }\n\n /**\n * ## RTC Membership\n * Gets the primary transport to use for this RTC membership (m.rtc.member).\n * This will return the primary transport that is used by this call membership to publish their media.\n * Directly relates to the `transports.published` field.\n *\n * ## Legacy session membership\n * In case of a legacy session membership (m.call.member) this will return the selected transport where\n * media is published. How this selection happens depends on the `focus_active` field of the session membership.\n * If the `focus_selection` is `oldest_membership` this will return the transport of the oldest membership\n * in the room (based on the `created_ts` field of the session membership).\n * If the `focus_selection` is `multi_sfu` it will return the first transport of the `foci_preferred` list.\n * (`multi_sfu` is equivalent to how `m.rtc.member` `transports.published` work).\n * @param oldestMembership For backwards compatibility with session membership (legacy). Unused in case of RTC membership.\n * Always required to make the consumer not care if it deals with RTC or session memberships.\n * @returns The transport this membership uses to publish media or undefined if no transport is available.\n */\n public getTransport(oldestMembership: CallMembership): Transport | undefined {\n const { kind, data } = this.membershipData;\n switch (kind) {\n case MembershipKind.RTC:\n return data.transports.published[0];\n case MembershipKind.Session:\n switch (data.focus_active.focus_selection) {\n case \"oldest_membership\":\n if (CallMembership.equal(this, oldestMembership)) return data.foci_preferred[0];\n if (oldestMembership !== undefined) return oldestMembership.getTransport(oldestMembership);\n break;\n case \"multi_sfu\":\n return data.foci_preferred[0];\n default:\n // `focus_selection` not understood.\n return undefined;\n }\n break;\n default:\n return undefined;\n }\n }\n\n /**\n * The value of the `transports.published` field for RTC memberships (m.rtc.member).\n * Or the value of the `foci_preferred` field for legacy session memberships (m.call.member).\n */\n public get transports(): Transport[] {\n const { kind, data } = this.membershipData;\n switch (kind) {\n case MembershipKind.RTC:\n return data.transports.published;\n case MembershipKind.Session:\n default:\n return data.foci_preferred;\n }\n }\n}\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"CallMembership.js","names":[],"sources":["../../src/matrixrtc/CallMembership.ts"],"sourcesContent":["/*\nCopyright 2023-2026 The Matrix.org Foundation C.I.C.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n*/\n\nimport { deepCompare } from \"../utils.ts\";\nimport { type RTCCallCapability, type RTCCallIntent, type Transport, type SlotDescription } from \"./types.ts\";\nimport { type MatrixEvent } from \"../models/event.ts\";\nimport { type Logger, logger } from \"../logger.ts\";\nimport { computeSlotId, slotIdToDescription } from \"./utils.ts\";\nimport {\n checkRtcMembershipData,\n computeRtcIdentityRaw,\n type RtcMembershipData,\n checkSessionsMembershipData,\n type SessionMembershipData,\n MatrixRTCMembershipParseError,\n} from \"./membershipData/index.ts\";\nimport { EventType } from \"../@types/event.ts\";\nimport { isUnstableLivekitTransport } from \"./LivekitTransport.ts\";\n\n/**\n * The default duration in milliseconds that a membership is considered valid for.\n * Ordinarily the client responsible for the session will update the membership before it expires.\n * We use this duration as the fallback case where stale sessions are present for some reason.\n */\nexport const DEFAULT_EXPIRE_DURATION = 1000 * 60 * 60 * 4;\n\n/** The fields of a legacy session membership that belong to the session, not the application */\nconst sessionFields: (keyof SessionMembershipData)[] = [\n \"application\",\n \"call_id\",\n \"device_id\",\n \"focus_active\",\n \"foci_preferred\",\n \"created_ts\",\n \"scope\",\n \"expires\",\n \"m.call.intent\",\n \"membershipID\",\n];\n\n/**\n * Describes the source event type that provided the membership data.\n */\nenum MembershipKind {\n /**\n * The modern MSC4143 format event.\n */\n RTC = \"rtc\",\n /**\n * The legacy call event type.\n */\n Session = \"session\",\n}\n\ntype MembershipData =\n | { kind: MembershipKind.RTC; data: RtcMembershipData }\n | { kind: MembershipKind.Session; data: SessionMembershipData };\n\nfunction getDeviceId({ kind, data }: MembershipData): string {\n switch (kind) {\n case MembershipKind.RTC:\n return data.member.device_id;\n case MembershipKind.Session:\n return data.device_id;\n }\n}\n\nfunction getMemberId({ kind, data }: MembershipData, sender: string): string {\n // the createdTs behaves equivalent to the membershipID.\n // we only need the field for the legacy member events where we needed to update them\n // synapse ignores sending state events if they have the same content.\n switch (kind) {\n case MembershipKind.RTC:\n return data.member.id;\n case MembershipKind.Session:\n return (\n // best case we have a client already publishing the right custom membershipId\n data.membershipID ??\n // alternatively we use the hardcoded jwt id default value (used until version 0.16.0)\n `${sender}:${data.device_id}`\n );\n }\n}\n\nfunction getTransports({ kind, data }: MembershipData): Transport[] {\n switch (kind) {\n case MembershipKind.RTC:\n return data.transports.published;\n case MembershipKind.Session:\n return data.foci_preferred;\n }\n}\n\ntype LimitedEvent = Pick<MatrixEvent, \"getId\" | \"getSender\" | \"getTs\" | \"getType\" | \"getContent\">;\n// TODO: Rename to RtcMembership once we removed the legacy SessionMembership is removed, to avoid confusion.\nexport class CallMembership {\n /**\n * Parse the membershipdata from a call membership event.\n * @param matrixEvent The Matrix event to read.\n * @returns MembershipData in either MembershipKind.RTC or MembershipKind.Session format.\n * @throws If the content is neither format.\n */\n public static membershipDataFromMatrixEvent(matrixEvent: LimitedEvent): MembershipData {\n const sender = matrixEvent.getSender();\n const evType = matrixEvent.getType();\n const data = matrixEvent.getContent();\n if (sender === undefined) throw new Error(\"matrixEvent is missing sender field\");\n try {\n // Event types are strictly checked here.\n if (evType === EventType.RTCMembership && checkRtcMembershipData(data, sender)) {\n return { kind: MembershipKind.RTC, data };\n } else if (evType === EventType.GroupCallMemberPrefix && checkSessionsMembershipData(data)) {\n return { kind: MembershipKind.Session, data };\n } else {\n throw Error(`'${evType} is not a known call membership type`);\n }\n } catch (ex) {\n if (ex instanceof MatrixRTCMembershipParseError) {\n logger.debug(\"CallMembership.MatrixRTCMembershipParseError provided invalid data\", data);\n }\n throw ex;\n }\n }\n\n /**\n * Parse the contents of a MatrixEvent and create a CallMembership instance.\n * @param matrixEvent The Matrix event to read.\n */\n public static async parseFromEvent(matrixEvent: LimitedEvent): Promise<CallMembership> {\n const sender = matrixEvent.getSender();\n if (sender === undefined) throw new Error(\"matrixEvent is missing sender field\");\n const membershipData: MembershipData = this.membershipDataFromMatrixEvent(matrixEvent);\n const livekitTransports = getTransports(membershipData).filter(isUnstableLivekitTransport);\n const legacyIdentity = `${sender}:${getDeviceId(membershipData)}`;\n\n const backendIdentities: string[] = [];\n if (livekitTransports.some((t) => \"url\" in t)) {\n backendIdentities.push(await computeRtcIdentityRaw(sender, getMemberId(membershipData, sender)));\n }\n if (livekitTransports.some((t) => \"livekit_service_url\" in t)) {\n backendIdentities.push(legacyIdentity);\n }\n\n // rtcBackendIdentity is deprecated, so it's fine to always set it to the legacy identity.\n return new CallMembership(matrixEvent, membershipData, backendIdentities, legacyIdentity);\n }\n\n public static equal(a?: CallMembership, b?: CallMembership): boolean {\n return deepCompare(a?.membershipData, b?.membershipData);\n }\n\n private logger: Logger;\n\n /** The parsed data from the Matrix event.\n * To access checked eventId and sender from the matrixEvent.\n * Class construction will fail if these values cannot get obtained. */\n private readonly matrixEventData: { eventId: string; sender: string };\n\n /**\n * Use `parseFromEvent`.\n * Constructor should only be used by tests.\n * @private\n */\n public constructor(\n /** The Matrix event that this membership is based on */\n private readonly matrixEvent: LimitedEvent,\n private readonly membershipData: MembershipData,\n /**\n * Possible identities which this member may have on the backends of\n * their published transports.\n */\n public readonly backendIdentities: string[],\n /**\n * @deprecated Check the backend for the existence of any of\n * {@link backendIdentities} instead.\n */\n public readonly rtcBackendIdentity: string,\n ) {\n const eventId = matrixEvent.getId();\n const sender = matrixEvent.getSender();\n\n if (eventId === undefined) throw new Error(\"matrixEvent is missing eventId field\");\n if (sender === undefined) throw new Error(\"matrixEvent is missing sender field\");\n\n this.logger = logger.getChild(`[CallMembership ${sender}:${this.deviceId}]`);\n this.matrixEventData = { eventId, sender };\n }\n\n /** @deprecated use userId instead */\n public get sender(): string {\n return this.userId;\n }\n\n public get userId(): string {\n return this.matrixEventData.sender;\n }\n\n public get eventId(): string {\n return this.matrixEventData.eventId;\n }\n\n /**\n * The ID of the MatrixRTC slot that this membership belongs to (format `{application}#{id}`).\n * This is computed in case SessionMembershipData is used.\n */\n public get slotId(): string {\n const { kind, data } = this.membershipData;\n if (data.application === \"m.call\") {\n switch (kind) {\n case MembershipKind.RTC:\n return data.slot_id;\n case MembershipKind.Session:\n default: {\n const [application, id] = [data.application, data.call_id];\n\n // INFO_SLOT_ID_LEGACY_CASE (search for all occurances of this INFO to get the full picture)\n // The spec got changed to use `\"ROOM\"` instead of `\"\"` empyt string for the implicit default call.\n // State events still are sent with `\"\"` however. To find other events that should end up in the same call,\n // we use the slotId.\n // Since the CallMembership is the public representation of a rtc.member event, we just pretend it is a\n // \"ROOM\" slotId/call_id.\n // This makes all the remote members work with just this simple trick.\n //\n // We of course now need to be careful when sending legacy events (state events)\n // They get a slotDescription containing \"ROOM\" since this is what we use starting at the time this comment\n // is commited.\n //\n // See the Other INFO_SLOT_ID_LEGACY_CASE comments to see where we revert back to \"\" just before sending the event.\n let compatibilityAdaptedId: string;\n if (id === \"\") {\n compatibilityAdaptedId = \"ROOM\";\n this.logger?.info(\"use slotId compat hack emptyString -> ROOM\");\n } else {\n compatibilityAdaptedId = id;\n }\n return computeSlotId({\n application,\n id: compatibilityAdaptedId,\n });\n }\n }\n }\n\n this.logger?.info(\"NOT using slotId compat hack emptyString -> ROOM\");\n // This is what the function should look like for any other application that did not\n // go through a `\"\"`=> `\"ROOM\"` rename\n switch (kind) {\n case MembershipKind.RTC:\n return data.slot_id;\n case MembershipKind.Session:\n default:\n return computeSlotId({ application: data.application, id: data.call_id });\n }\n }\n\n public get deviceId(): string {\n return getDeviceId(this.membershipData);\n }\n\n public get callIntent(): RTCCallIntent | undefined {\n const intent = this.applicationData[\"m.call.intent\"];\n if (typeof intent === \"string\") {\n return intent;\n }\n this.logger.warn(\"RTC membership has invalid m.call.intent\");\n return undefined;\n }\n\n public get callCapabilities(): RTCCallCapability[] | undefined {\n const capabilities = this.applicationData[\"capabilities\"];\n if (capabilities === undefined) return undefined;\n if (Array.isArray(capabilities) && capabilities.every((c) => typeof c === \"string\")) return capabilities;\n this.logger.warn(\"RTC membership has invalid capabilities\");\n return undefined;\n }\n\n /**\n * Parsed `slot_id` (format `{application}#{id}`) into its components (application and id).\n */\n public get slotDescription(): SlotDescription {\n const { kind, data } = this.membershipData;\n if (kind === MembershipKind.RTC) {\n const id = data.slot_id.slice(`${data.application.type}#`.length);\n return { application: data.application.type, id };\n }\n return slotIdToDescription(this.slotId);\n }\n\n /**\n * Information about the application being used for the RTC session.\n * May contain extra keys specific to the application.\n */\n public get applicationData(): { type: string; [key: string]: unknown } {\n const { kind, data } = this.membershipData;\n switch (kind) {\n case MembershipKind.RTC:\n return data.application;\n case MembershipKind.Session:\n default: {\n // SessionData has no application object: the application's own\n // data sits at the top level beside the session fields, so\n // everything but those is the application's\n const { application, ...rest } = data;\n for (const key of sessionFields) delete rest[key as keyof typeof rest];\n return { ...rest, \"type\": application, \"m.call.intent\": data[\"m.call.intent\"] };\n }\n }\n }\n\n /** @deprecated scope is not used and will be removed in future versions. replaced by application specific types.*/\n public get scope(): SessionMembershipData[\"scope\"] | undefined {\n const { kind, data } = this.membershipData;\n switch (kind) {\n case MembershipKind.RTC:\n return undefined;\n case MembershipKind.Session:\n default:\n return data.scope;\n }\n }\n\n /**\n * This computes the membership ID for the membership.\n * For the sticky event based rtcSessionData this is trivial it is `member.id`.\n * This is not supposed to be used to identity on an rtc backend. This is just a nuance for\n * a generated (sha256) anonymised identity. Only send {@link backendIdentities} to any rtc backend service.\n *\n * For the legacy sessionMemberEvents it is a bit more complex. Here we sometimes do not have this data\n * in the event content and we expected the SFU and the client to use `${this.matrixEventData.sender}:${data.device_id}`.\n *\n * So if there is no membershipID we use the hard coded jwt id default (`${this.matrixEventData.sender}:${data.device_id}`)\n * value (used until version 0.16.0)\n *\n * It is also possible for a session event to set a custom membershipID. in that case this will be used.\n */\n public get memberId(): string {\n return getMemberId(this.membershipData, this.matrixEventData.sender);\n }\n\n public createdTs(): number {\n const { kind, data } = this.membershipData;\n switch (kind) {\n case MembershipKind.RTC:\n // TODO Do we need this to represent the TS of the original join?\n return this.matrixEvent.getTs();\n case MembershipKind.Session:\n default:\n return data.created_ts ?? this.matrixEvent.getTs();\n }\n }\n\n /**\n * Gets the absolute expiry timestamp of the membership.\n * @returns The absolute expiry time of the membership as a unix timestamp in milliseconds or undefined if not applicable\n */\n public getAbsoluteExpiry(): number | undefined {\n const { kind, data } = this.membershipData;\n switch (kind) {\n case MembershipKind.RTC:\n return undefined;\n case MembershipKind.Session:\n default:\n // TODO: calculate this from the MatrixRTCSession join configuration directly\n return this.createdTs() + (data.expires ?? DEFAULT_EXPIRE_DURATION);\n }\n }\n\n /**\n * @returns The number of milliseconds until the membership expires or undefined if applicable\n * @deprecated Not used by RTC events.\n */\n public getMsUntilExpiry(): number | undefined {\n const { kind } = this.membershipData;\n if (kind === MembershipKind.Session) {\n const absExpiry = this.getAbsoluteExpiry();\n if (absExpiry) {\n // Assume that local clock is sufficiently in sync with other clocks in the distributed system.\n // We used to try and adjust for the local clock being skewed, but there are cases where this is not accurate.\n // The current implementation allows for the local clock to be -infinity to +MatrixRTCSession.MEMBERSHIP_EXPIRY_TIME/2\n return absExpiry - Date.now();\n }\n }\n return undefined;\n }\n\n /**\n * @returns true if the membership has expired, otherwise false\n */\n public isExpired(): boolean {\n const { kind } = this.membershipData;\n switch (kind) {\n case MembershipKind.RTC:\n return false;\n case MembershipKind.Session:\n default:\n return this.getMsUntilExpiry()! <= 0;\n }\n }\n\n /**\n * ## RTC Membership\n * Gets the primary transport to use for this RTC membership (m.rtc.member).\n * This will return the primary transport that is used by this call membership to publish their media.\n * Directly relates to the `transports.published` field.\n *\n * ## Legacy session membership\n * In case of a legacy session membership (m.call.member) this will return the first transport of the\n * `foci_preferred` list. (`multi_sfu` is equivalent to how `m.rtc.member` `transports.published` work).\n *\n * @param _oldestMembership Deprecated and unused.\n *\n * @returns The transport this membership uses to publish media or undefined if no transport is available.\n */\n public getTransport(_oldestMembership?: CallMembership): Transport | undefined {\n const { kind, data } = this.membershipData;\n switch (kind) {\n case MembershipKind.RTC:\n return data.transports.published[0];\n case MembershipKind.Session:\n return data.foci_preferred[0];\n default:\n return undefined;\n }\n }\n\n /**\n * The value of the `transports.published` field for RTC memberships (m.rtc.member).\n * Or the value of the `foci_preferred` field for legacy session memberships (m.call.member).\n */\n public get transports(): Transport[] {\n return getTransports(this.membershipData);\n }\n}\n"],"mappings":"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","ignoreList":[]}
@@ -1,6 +1,6 @@
1
1
  import { type EncryptionConfig } from "./MatrixRTCSession.ts";
2
2
  import { type CallMembership } from "./CallMembership.ts";
3
- import { type EncryptionKeyMapKey } from "./types.ts";
3
+ import { type Transport, type EncryptionKeyMapKey } from "./types.ts";
4
4
  /**
5
5
  * The string used for the keys in the the encryption key map.
6
6
  * `@bob:examle.org:DEVICEID(UUIDRANDOM_MEMBERID_RANDOMUUID)`
@@ -20,9 +20,11 @@ export interface IEncryptionManager {
20
20
  * Joins the encryption manager with the provided configuration.
21
21
  *
22
22
  * @param joinConfig - The configuration for joining encryption, or undefined
23
- * if no specific configuration is provided.
23
+ * @param publishedTransports - The transports on which we are publishing.
24
+ * (Needed to determine which participant identity formats to use, for
25
+ * compatibility.)
24
26
  */
25
- join(joinConfig: EncryptionConfig | undefined): void;
27
+ join(joinConfig: EncryptionConfig | undefined, publishedTransports: Transport[]): void;
26
28
  /**
27
29
  * Leaves the encryption manager, cleaning up any associated resources.
28
30
  */
@@ -42,7 +44,7 @@ export interface IEncryptionManager {
42
44
  key: Uint8Array<ArrayBuffer>;
43
45
  keyIndex: number;
44
46
  membership: CallMembershipIdentityParts;
45
- rtcBackendIdentity: string;
47
+ backendIdentity: string;
46
48
  }>>;
47
49
  }
48
50
  export type CallMembershipIdentityParts = Pick<CallMembership, "userId" | "deviceId" | "memberId">;
@@ -1 +1 @@
1
- {"version":3,"file":"EncryptionManager.d.ts","sourceRoot":"","sources":["../../src/matrixrtc/EncryptionManager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,EAAE,KAAK,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAEtD;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,UAAU,EAAE,2BAA2B,GAAG,mBAAmB,CAEnG;AAED;;;GAGG;AACH,MAAM,WAAW,kBAAkB;IAC/B;;;OAGG;IACH,QAAQ,CAAC,uBAAuB,EAAE,OAAO,CAAC;IAE1C;;;;;OAKG;IACH,IAAI,CAAC,UAAU,EAAE,gBAAgB,GAAG,SAAS,GAAG,IAAI,CAAC;IAErD;;OAEG;IACH,KAAK,IAAI,IAAI,CAAC;IAEd;;;;OAIG;IACH,mBAAmB,CAAC,cAAc,EAAE,cAAc,EAAE,GAAG,IAAI,CAAC;IAE5D;;;;OAIG;IACH,iBAAiB,IAAI,WAAW,CAC5B,mBAAmB,EACnB,aAAa,CAAC;QACV,GAAG,EAAE,UAAU,CAAC,WAAW,CAAC,CAAC;QAC7B,QAAQ,EAAE,MAAM,CAAC;QACjB,UAAU,EAAE,2BAA2B,CAAC;QACxC,kBAAkB,EAAE,MAAM,CAAC;KAC9B,CAAC,CACL,CAAC;CACL;AAED,MAAM,MAAM,2BAA2B,GAAG,IAAI,CAAC,cAAc,EAAE,QAAQ,GAAG,UAAU,GAAG,UAAU,CAAC,CAAC"}
1
+ {"version":3,"file":"EncryptionManager.d.ts","sourceRoot":"","sources":["../../src/matrixrtc/EncryptionManager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,EAAE,KAAK,SAAS,EAAE,KAAK,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAEtE;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,UAAU,EAAE,2BAA2B,GAAG,mBAAmB,CAEnG;AAED;;;GAGG;AACH,MAAM,WAAW,kBAAkB;IAC/B;;;OAGG;IACH,QAAQ,CAAC,uBAAuB,EAAE,OAAO,CAAC;IAE1C;;;;;;;OAOG;IACH,IAAI,CAAC,UAAU,EAAE,gBAAgB,GAAG,SAAS,EAAE,mBAAmB,EAAE,SAAS,EAAE,GAAG,IAAI,CAAC;IAEvF;;OAEG;IACH,KAAK,IAAI,IAAI,CAAC;IAEd;;;;OAIG;IACH,mBAAmB,CAAC,cAAc,EAAE,cAAc,EAAE,GAAG,IAAI,CAAC;IAE5D;;;;OAIG;IACH,iBAAiB,IAAI,WAAW,CAC5B,mBAAmB,EACnB,aAAa,CAAC;QACV,GAAG,EAAE,UAAU,CAAC,WAAW,CAAC,CAAC;QAC7B,QAAQ,EAAE,MAAM,CAAC;QACjB,UAAU,EAAE,2BAA2B,CAAC;QACxC,eAAe,EAAE,MAAM,CAAC;KAC3B,CAAC,CACL,CAAC;CACL;AAED,MAAM,MAAM,2BAA2B,GAAG,IAAI,CAAC,cAAc,EAAE,QAAQ,GAAG,UAAU,GAAG,UAAU,CAAC,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"EncryptionManager.js","names":[],"sources":["../../src/matrixrtc/EncryptionManager.ts"],"sourcesContent":["import { type EncryptionConfig } from \"./MatrixRTCSession.ts\";\nimport { type CallMembership } from \"./CallMembership.ts\";\nimport { type EncryptionKeyMapKey } from \"./types.ts\";\n\n/**\n * The string used for the keys in the the encryption key map.\n * `@bob:examle.org:DEVICEID(UUIDRANDOM_MEMBERID_RANDOMUUID)`\n */\nexport function getEncryptionKeyMapKey(membership: CallMembershipIdentityParts): EncryptionKeyMapKey {\n return `${membership.userId}:${membership.deviceId}(${membership.memberId})`;\n}\n\n/**\n * This interface is for testing and for making it possible to interchange the encryption manager.\n * @internal\n */\nexport interface IEncryptionManager {\n /**\n * Whether the key rotation is currently halted.\n * @see EncryptionConfig.keyRotationParticipantLimit\n */\n readonly isKeyRotationSuppressed: boolean;\n\n /**\n * Joins the encryption manager with the provided configuration.\n *\n * @param joinConfig - The configuration for joining encryption, or undefined\n * if no specific configuration is provided.\n */\n join(joinConfig: EncryptionConfig | undefined): void;\n\n /**\n * Leaves the encryption manager, cleaning up any associated resources.\n */\n leave(): void;\n\n /**\n * Called from the MatrixRTCSession when the memberships in this session updated.\n *\n * @param oldMemberships - The previous state of call memberships before the update.\n */\n onMembershipsUpdate(oldMemberships: CallMembership[]): void;\n\n /**\n * Retrieves the encryption keys currently managed by the encryption manager.\n *\n * @returns A map of participant IDs to their encryption keys.\n */\n getEncryptionKeys(): ReadonlyMap<\n EncryptionKeyMapKey,\n ReadonlyArray<{\n key: Uint8Array<ArrayBuffer>;\n keyIndex: number;\n membership: CallMembershipIdentityParts;\n rtcBackendIdentity: string;\n }>\n >;\n}\n\nexport type CallMembershipIdentityParts = Pick<CallMembership, \"userId\" | \"deviceId\" | \"memberId\">;\n"],"mappings":"AAIA;AACA;AACA;AACA;AACA,OAAO,SAAS,sBAAsB,CAAC,UAAuC,EAAuB;EACjG,OAAO,GAAG,UAAU,CAAC,MAAM,IAAI,UAAU,CAAC,QAAQ,IAAI,UAAU,CAAC,QAAQ,GAAG;AAChF;;AAEA;AACA;AACA;AACA","ignoreList":[]}
1
+ {"version":3,"file":"EncryptionManager.js","names":[],"sources":["../../src/matrixrtc/EncryptionManager.ts"],"sourcesContent":["import { type EncryptionConfig } from \"./MatrixRTCSession.ts\";\nimport { type CallMembership } from \"./CallMembership.ts\";\nimport { type Transport, type EncryptionKeyMapKey } from \"./types.ts\";\n\n/**\n * The string used for the keys in the the encryption key map.\n * `@bob:examle.org:DEVICEID(UUIDRANDOM_MEMBERID_RANDOMUUID)`\n */\nexport function getEncryptionKeyMapKey(membership: CallMembershipIdentityParts): EncryptionKeyMapKey {\n return `${membership.userId}:${membership.deviceId}(${membership.memberId})`;\n}\n\n/**\n * This interface is for testing and for making it possible to interchange the encryption manager.\n * @internal\n */\nexport interface IEncryptionManager {\n /**\n * Whether the key rotation is currently halted.\n * @see EncryptionConfig.keyRotationParticipantLimit\n */\n readonly isKeyRotationSuppressed: boolean;\n\n /**\n * Joins the encryption manager with the provided configuration.\n *\n * @param joinConfig - The configuration for joining encryption, or undefined\n * @param publishedTransports - The transports on which we are publishing.\n * (Needed to determine which participant identity formats to use, for\n * compatibility.)\n */\n join(joinConfig: EncryptionConfig | undefined, publishedTransports: Transport[]): void;\n\n /**\n * Leaves the encryption manager, cleaning up any associated resources.\n */\n leave(): void;\n\n /**\n * Called from the MatrixRTCSession when the memberships in this session updated.\n *\n * @param oldMemberships - The previous state of call memberships before the update.\n */\n onMembershipsUpdate(oldMemberships: CallMembership[]): void;\n\n /**\n * Retrieves the encryption keys currently managed by the encryption manager.\n *\n * @returns A map of participant IDs to their encryption keys.\n */\n getEncryptionKeys(): ReadonlyMap<\n EncryptionKeyMapKey,\n ReadonlyArray<{\n key: Uint8Array<ArrayBuffer>;\n keyIndex: number;\n membership: CallMembershipIdentityParts;\n backendIdentity: string;\n }>\n >;\n}\n\nexport type CallMembershipIdentityParts = Pick<CallMembership, \"userId\" | \"deviceId\" | \"memberId\">;\n"],"mappings":"AAIA;AACA;AACA;AACA;AACA,OAAO,SAAS,sBAAsB,CAAC,UAAuC,EAAuB;EACjG,OAAO,GAAG,UAAU,CAAC,MAAM,IAAI,UAAU,CAAC,QAAQ,IAAI,UAAU,CAAC,QAAQ,GAAG;AAChF;;AAEA;AACA;AACA;AACA","ignoreList":[]}