matrix-js-sdk 42.4.0 → 43.0.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 (138) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/lib/@types/PushRules.d.ts +3 -1
  3. package/lib/@types/PushRules.d.ts.map +1 -1
  4. package/lib/@types/PushRules.js +2 -0
  5. package/lib/@types/PushRules.js.map +1 -1
  6. package/lib/@types/event.d.ts +1 -0
  7. package/lib/@types/event.d.ts.map +1 -1
  8. package/lib/@types/event.js.map +1 -1
  9. package/lib/@types/matrix-sdk-crypto-wasm.d.js.map +1 -1
  10. package/lib/client.d.ts +88 -37
  11. package/lib/client.d.ts.map +1 -1
  12. package/lib/client.js +72 -47
  13. package/lib/client.js.map +1 -1
  14. package/lib/crypto-api/index.d.ts +3 -3
  15. package/lib/crypto-api/index.d.ts.map +1 -1
  16. package/lib/crypto-api/index.js.map +1 -1
  17. package/lib/embedded.d.ts +17 -1
  18. package/lib/embedded.d.ts.map +1 -1
  19. package/lib/embedded.js +46 -1
  20. package/lib/embedded.js.map +1 -1
  21. package/lib/errors.d.ts +1 -1
  22. package/lib/errors.d.ts.map +1 -1
  23. package/lib/errors.js +2 -2
  24. package/lib/errors.js.map +1 -1
  25. package/lib/http-api/fetch.d.ts +7 -1
  26. package/lib/http-api/fetch.d.ts.map +1 -1
  27. package/lib/http-api/fetch.js +14 -5
  28. package/lib/http-api/fetch.js.map +1 -1
  29. package/lib/http-api/interface.d.ts +34 -8
  30. package/lib/http-api/interface.d.ts.map +1 -1
  31. package/lib/http-api/interface.js +10 -3
  32. package/lib/http-api/interface.js.map +1 -1
  33. package/lib/http-api/refresh.d.ts +30 -11
  34. package/lib/http-api/refresh.d.ts.map +1 -1
  35. package/lib/http-api/refresh.js +72 -5
  36. package/lib/http-api/refresh.js.map +1 -1
  37. package/lib/matrix.d.ts +1 -1
  38. package/lib/matrix.d.ts.map +1 -1
  39. package/lib/matrix.js.map +1 -1
  40. package/lib/matrixrtc/CallMembership.d.ts.map +1 -1
  41. package/lib/matrixrtc/CallMembership.js +20 -6
  42. package/lib/matrixrtc/CallMembership.js.map +1 -1
  43. package/lib/matrixrtc/IMembershipManager.d.ts +5 -0
  44. package/lib/matrixrtc/IMembershipManager.d.ts.map +1 -1
  45. package/lib/matrixrtc/IMembershipManager.js.map +1 -1
  46. package/lib/matrixrtc/MatrixRTCSession.d.ts +27 -1
  47. package/lib/matrixrtc/MatrixRTCSession.d.ts.map +1 -1
  48. package/lib/matrixrtc/MatrixRTCSession.js +58 -36
  49. package/lib/matrixrtc/MatrixRTCSession.js.map +1 -1
  50. package/lib/matrixrtc/MatrixRTCSessionManager.js +1 -1
  51. package/lib/matrixrtc/MatrixRTCSessionManager.js.map +1 -1
  52. package/lib/matrixrtc/MembershipManager.d.ts +76 -0
  53. package/lib/matrixrtc/MembershipManager.d.ts.map +1 -1
  54. package/lib/matrixrtc/MembershipManager.js +264 -47
  55. package/lib/matrixrtc/MembershipManager.js.map +1 -1
  56. package/lib/matrixrtc/index.d.ts +1 -1
  57. package/lib/matrixrtc/index.d.ts.map +1 -1
  58. package/lib/matrixrtc/index.js +1 -1
  59. package/lib/matrixrtc/index.js.map +1 -1
  60. package/lib/matrixrtc/membershipData/common.d.ts +8 -0
  61. package/lib/matrixrtc/membershipData/common.d.ts.map +1 -1
  62. package/lib/matrixrtc/membershipData/common.js +10 -0
  63. package/lib/matrixrtc/membershipData/common.js.map +1 -1
  64. package/lib/matrixrtc/membershipData/index.d.ts +1 -1
  65. package/lib/matrixrtc/membershipData/index.d.ts.map +1 -1
  66. package/lib/matrixrtc/membershipData/index.js +1 -1
  67. package/lib/matrixrtc/membershipData/index.js.map +1 -1
  68. package/lib/matrixrtc/types.d.ts +104 -11
  69. package/lib/matrixrtc/types.d.ts.map +1 -1
  70. package/lib/matrixrtc/types.js +263 -19
  71. package/lib/matrixrtc/types.js.map +1 -1
  72. package/lib/matrixrtc/utils.d.ts +22 -1
  73. package/lib/matrixrtc/utils.d.ts.map +1 -1
  74. package/lib/matrixrtc/utils.js +38 -0
  75. package/lib/matrixrtc/utils.js.map +1 -1
  76. package/lib/models/room-sticky-events.d.ts +7 -0
  77. package/lib/models/room-sticky-events.d.ts.map +1 -1
  78. package/lib/models/room-sticky-events.js +27 -0
  79. package/lib/models/room-sticky-events.js.map +1 -1
  80. package/lib/models/thread.d.ts.map +1 -1
  81. package/lib/models/thread.js +8 -0
  82. package/lib/models/thread.js.map +1 -1
  83. package/lib/oauth/authorize.js +1 -1
  84. package/lib/oauth/authorize.js.map +1 -1
  85. package/lib/oauth/index.d.ts +3 -5
  86. package/lib/oauth/index.d.ts.map +1 -1
  87. package/lib/oauth/index.js +7 -7
  88. package/lib/oauth/index.js.map +1 -1
  89. package/lib/oauth/tokenRefresher.d.ts +10 -4
  90. package/lib/oauth/tokenRefresher.d.ts.map +1 -1
  91. package/lib/oauth/tokenRefresher.js +34 -24
  92. package/lib/oauth/tokenRefresher.js.map +1 -1
  93. package/lib/receipt-accumulator.d.ts +10 -11
  94. package/lib/receipt-accumulator.d.ts.map +1 -1
  95. package/lib/receipt-accumulator.js +26 -25
  96. package/lib/receipt-accumulator.js.map +1 -1
  97. package/lib/room-summary-api.d.ts +71 -0
  98. package/lib/room-summary-api.d.ts.map +1 -0
  99. package/lib/room-summary-api.js +82 -0
  100. package/lib/room-summary-api.js.map +1 -0
  101. package/lib/rust-crypto/backup.d.ts +7 -0
  102. package/lib/rust-crypto/backup.d.ts.map +1 -1
  103. package/lib/rust-crypto/backup.js +41 -25
  104. package/lib/rust-crypto/backup.js.map +1 -1
  105. package/lib/sync.d.ts.map +1 -1
  106. package/lib/sync.js +6 -1
  107. package/lib/sync.js.map +1 -1
  108. package/package.json +6 -6
  109. package/src/@types/PushRules.ts +2 -0
  110. package/src/@types/event.ts +1 -1
  111. package/src/@types/matrix-sdk-crypto-wasm.d.ts +15 -12
  112. package/src/client.ts +105 -62
  113. package/src/crypto-api/index.ts +3 -3
  114. package/src/embedded.ts +61 -2
  115. package/src/errors.ts +2 -1
  116. package/src/http-api/fetch.ts +14 -5
  117. package/src/http-api/interface.ts +36 -8
  118. package/src/http-api/refresh.ts +101 -17
  119. package/src/matrix.ts +1 -1
  120. package/src/matrixrtc/CallMembership.ts +22 -4
  121. package/src/matrixrtc/IMembershipManager.ts +6 -0
  122. package/src/matrixrtc/MatrixRTCSession.ts +72 -49
  123. package/src/matrixrtc/MatrixRTCSessionManager.ts +1 -1
  124. package/src/matrixrtc/MembershipManager.ts +284 -61
  125. package/src/matrixrtc/index.ts +7 -1
  126. package/src/matrixrtc/membershipData/common.ts +12 -0
  127. package/src/matrixrtc/membershipData/index.ts +1 -1
  128. package/src/matrixrtc/types.ts +351 -23
  129. package/src/matrixrtc/utils.ts +54 -1
  130. package/src/models/room-sticky-events.ts +26 -1
  131. package/src/models/thread.ts +9 -0
  132. package/src/oauth/authorize.ts +1 -1
  133. package/src/oauth/index.ts +7 -8
  134. package/src/oauth/tokenRefresher.ts +15 -5
  135. package/src/receipt-accumulator.ts +30 -26
  136. package/src/room-summary-api.ts +114 -0
  137. package/src/rust-crypto/backup.ts +46 -33
  138. package/src/sync.ts +9 -1
@@ -1 +1 @@
1
- {"version":3,"file":"MembershipManager.js","names":[],"sources":["../../src/matrixrtc/MembershipManager.ts"],"sourcesContent":["/*\nCopyright 2025-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*/\nimport { AbortError } from \"p-retry\";\n\nimport { EventType, RelationType } from \"../@types/event.ts\";\nimport { type ISendEventResponse, type SendDelayedEventResponse } from \"../@types/requests.ts\";\nimport { type EmptyObject } from \"../@types/common.ts\";\nimport type { MatrixClient } from \"../client.ts\";\nimport { ConnectionError, HTTPError, MatrixError } from \"../http-api/errors.ts\";\nimport { type Logger, logger as rootLogger } from \"../logger.ts\";\nimport { type Room } from \"../models/room.ts\";\nimport { type CallMembership, DEFAULT_EXPIRE_DURATION } from \"./CallMembership.ts\";\nimport { type Transport, isMyMembership, type RTCCallIntent, Status, type SlotDescription } from \"./types.ts\";\nimport { type MembershipConfig, type SessionConfig } from \"./MatrixRTCSession.ts\";\nimport { ActionScheduler, type ActionUpdate } from \"./MembershipManagerActionScheduler.ts\";\nimport { TypedEventEmitter } from \"../models/typed-event-emitter.ts\";\nimport { UnsupportedDelayedEventsEndpointError } from \"../errors.ts\";\nimport {\n MembershipManagerEvent,\n type IMembershipManager,\n type MembershipManagerEventHandlerMap,\n} from \"./IMembershipManager.ts\";\nimport { type RtcMembershipData, type SessionMembershipData } from \"./membershipData/index.ts\";\nimport { computeSlotId } from \"./utils.ts\";\nimport { isLivekitTransportConfig } from \"./LivekitTransport.ts\";\n\n/* MembershipActionTypes:\nOn Join: ───────────────┐ ┌───────────────(1)───────────┐\n ▼ ▼ │\n ┌────────────────┐ │\n │SendDelayedEvent│ ──────(2)───┐ │\n └────────────────┘ │ │\n │(3) │ │\n ▼ │ │\n ┌─────────────┐ │ │\n ┌──────(4)───│SendJoinEvent│────(4)─────┐ │ │\n │ └─────────────┘ │ │ │\n │ ┌─────┐ ┌──────┐ │ │ │\n ▼ ▼ │ │ ▼ ▼ ▼ │\n┌────────────┐ │ │ ┌───────────────────┐ │\n│UpdateExpiry│ (s) (s)|RestartDelayedEvent│ │\n└────────────┘ │ │ └───────────────────┘ │\n │ │ │ │ │ │\n └─────┘ └──────┘ └───────┘\n\nOn Leave: ───────── STOP ALL ABOVE\n ▼\n ┌────────────────────────────────┐\n │ SendScheduledDelayedLeaveEvent │\n └────────────────────────────────┘\n │(5)\n ▼\n ┌──────────────┐\n │SendLeaveEvent│\n └──────────────┘\n(1) [Not found error] results in resending the delayed event\n(2) [hasMemberEvent = true] Sending the delayed event if we\n already have a call member event results jumping to the\n RestartDelayedEvent loop directly\n(3) [hasMemberEvent = false] if there is not call member event\n sending it is the next step\n(4) Both (UpdateExpiry and RestartDelayedEvent) actions are\n scheduled when successfully sending the state event\n(5) Only if delayed event sending failed (fallback)\n(s) Successful restart/resend\n*/\n\n/**\n * Call membership should always remain sticky for this amount\n * of time.\n */\nconst MEMBERSHIP_STICKY_DURATION_MS = 60 * 60 * 1000; // 60 minutes\n\n/**\n * The different types of actions the MembershipManager can take.\n * @internal\n */\nexport enum MembershipActionType {\n SendDelayedEvent = \"SendDelayedEvent\",\n // -> MembershipActionType.SendJoinEvent if successful\n // -> DelayedLeaveActionType.SendDelayedEvent on error, retry sending the first delayed event.\n // -> DelayedLeaveActionType.RestartDelayedEvent on success start updating the delayed event\n\n SendJoinEvent = \"SendJoinEvent\",\n // -> MembershipActionType.SendJoinEvent if we run into a rate limit and need to retry\n // -> MembershipActionType.Update if we successfully send the join event then schedule the expire event update\n // -> DelayedLeaveActionType.RestartDelayedEvent to recheck the delayed event\n\n RestartDelayedEvent = \"RestartDelayedEvent\",\n // -> DelayedLeaveActionType.SendMainDelayedEvent on missing delay id but there is a rtc state event\n // -> DelayedLeaveActionType.SendDelayedEvent on missing delay id and there is no state event\n // -> DelayedLeaveActionType.RestartDelayedEvent on success we schedule the next restart\n\n UpdateExpiry = \"UpdateExpiry\",\n // -> MembershipActionType.Update if the timeout has passed so the next update is required.\n\n SendScheduledDelayedLeaveEvent = \"SendScheduledDelayedLeaveEvent\",\n // -> MembershipActionType.SendLeaveEvent on failure (not found) we need to send the leave manually and cannot use the scheduled delayed event\n // -> DelayedLeaveActionType.SendScheduledDelayedLeaveEvent on error we try again.\n\n SendLeaveEvent = \"SendLeaveEvent\",\n // -> MembershipActionType.SendLeaveEvent\n}\n\n/**\n * @internal\n */\nexport interface MembershipManagerState {\n /** The delayId we got when successfully sending the delayed leave event.\n * Gets set to undefined if the server claims it cannot find the delayed event anymore. */\n delayId?: string;\n /** Stores how often we have update the `expires` field.\n * `expireUpdateIterations` * `membershipEventExpiryTimeout` resolves to the value the expires field should contain next */\n expireUpdateIterations: number;\n /** The time at which we send the first state event. The time the call started from the DAG point of view.\n * This is used to compute the local sleep timestamps when to next update the member event with a new expires value. */\n startTime: number;\n /** The manager is in the state where its actually connected to the session. */\n hasMemberStateEvent: boolean;\n // There can be multiple retries at once so we need to store counters per action\n // e.g. the send update membership and the restart delayed could be rate limited at the same time.\n /** Retry counter for rate limits */\n rateLimitRetries: Map<MembershipActionType, number>;\n /** Retry counter for other errors */\n networkErrorRetries: Map<MembershipActionType, number>;\n /** The time at which we expect the server to send the delayed leave event. */\n expectedServerDelayLeaveTs?: number;\n /** This is used to track if the client expects the scheduled delayed leave event to have\n * been sent because restarting failed during the available time.\n * Once we resend the delayed event or successfully restarted it will get unset. */\n probablyLeft: boolean;\n}\n\nfunction createInsertActionUpdate(type: MembershipActionType, offset?: number): ActionUpdate {\n return {\n insert: [{ ts: Date.now() + (offset ?? 0), type }],\n };\n}\n\nfunction createReplaceActionUpdate(type: MembershipActionType, offset?: number): ActionUpdate {\n return {\n replace: [{ ts: Date.now() + (offset ?? 0), type }],\n };\n}\n\ntype MembershipManagerClient = Pick<\n MatrixClient,\n | \"getUserId\"\n | \"getDeviceId\"\n | \"sendStateEvent\"\n | \"_unstable_sendDelayedStateEvent\"\n | \"_unstable_updateDelayedEvent\"\n | \"_unstable_cancelScheduledDelayedEvent\"\n | \"_unstable_restartScheduledDelayedEvent\"\n | \"_unstable_sendScheduledDelayedEvent\"\n>;\n\n/**\n * This class is responsible for sending all events relating to the own membership of a matrixRTC call.\n * It has the following tasks:\n * - Send the users leave delayed event before sending the membership\n * - Send the users membership if the state machine is started\n * - Check if the delayed event was canceled due to sending the membership\n * - update the delayed event (`restart`)\n * - Update the state event every ~5h = `DEFAULT_EXPIRE_DURATION` (so it does not get treated as expired)\n * - When the state machine is stopped:\n * - Disconnect the member\n * - Stop the timer for the delay refresh\n * - Stop the timer for updating the state event\n */\nexport class MembershipManager\n extends TypedEventEmitter<MembershipManagerEvent, MembershipManagerEventHandlerMap>\n implements IMembershipManager\n{\n private activated = false;\n private readonly logger: Logger;\n protected callIntent: RTCCallIntent | undefined;\n\n public isActivated(): boolean {\n return this.activated;\n }\n // DEPRECATED use isActivated\n public isJoined(): boolean {\n return this.isActivated();\n }\n\n /**\n * Puts the MembershipManager in a state where it tries to be joined.\n * It will send delayed events and membership events\n * @param fociPreferred the list of preferred foci to use in the joined RTC membership event.\n * If multiSfuFocus is set, this is only needed if this client wants to publish to multiple transports simultaneously.\n * @param multiSfuFocus the active focus to use in the joined RTC membership event. Setting this implies the\n * membership manager will operate in a multi-SFU connection mode. If `undefined`, an `oldest_membership`\n * transport selection will be used instead.\n * @param onError This will be called once the membership manager encounters an unrecoverable error.\n * This should bubble up the the frontend to communicate that the call does not work in the current environment.\n * The original underlying error is preserved as `error.cause`, so consumers can `instanceof`-check the typed\n * cause.\n */\n public join(fociPreferred: Transport[], multiSfuFocus?: Transport, onError?: (error: unknown) => void): void {\n if (this.scheduler.running) {\n this.logger.error(\"MembershipManager is already running. Ignoring join request.\");\n return;\n }\n this.fociPreferred = fociPreferred;\n this.rtcTransport = multiSfuFocus;\n this.leavePromiseResolvers = undefined;\n this.activated = true;\n this.oldStatus = this.status;\n this.state = MembershipManager.defaultState;\n\n this.scheduler\n .startWithJoin()\n .catch((e) => {\n this.logger.error(\"MembershipManager stopped because: \", e);\n onError?.(e);\n })\n .finally(() => {\n // Should already be set to false when calling `leave` in non error cases.\n this.activated = false;\n // Here the scheduler is not running anymore so we the `membershipLoopHandler` is not called to emit.\n if (this.oldStatus && this.oldStatus !== this.status) {\n this.emit(MembershipManagerEvent.StatusChanged, this.oldStatus, this.status);\n }\n if (!this.scheduler.running) {\n this.leavePromiseResolvers?.resolve(true);\n this.leavePromiseResolvers = undefined;\n }\n });\n }\n\n /**\n * Leave from the call (Send an rtc session event with content: `{}`)\n * @param timeout the maximum duration this promise will take to resolve\n * @returns true if it managed to leave and false if the timeout condition happened.\n */\n public leave(timeout?: number): Promise<boolean> {\n if (!this.scheduler.running) {\n this.logger.warn(\"Called MembershipManager.leave() even though the MembershipManager is not running\");\n return Promise.resolve(true);\n }\n\n // We use the promise to track if we already scheduled a leave event\n // So we do not check scheduler.actions/scheduler.insertions\n if (!this.leavePromiseResolvers) {\n // reset scheduled actions so we will not do any new actions.\n this.leavePromiseResolvers = Promise.withResolvers<boolean>();\n this.activated = false;\n this.scheduler.initiateLeave();\n if (timeout) setTimeout(() => this.leavePromiseResolvers?.resolve(false), timeout);\n }\n return this.leavePromiseResolvers.promise;\n }\n\n private leavePromiseResolvers?: PromiseWithResolvers<boolean>;\n\n public onRTCSessionMemberUpdate(memberships: CallMembership[]): Promise<void> {\n if (!this.isActivated()) {\n return Promise.resolve();\n }\n\n this._ownMembership = memberships.find((m) => isMyMembership(m, this.userId, this.deviceId));\n\n if (!this._ownMembership) {\n // If one of these actions are scheduled or are getting inserted in the next iteration, we should already\n // take care of our missing membership.\n const sendingMembershipActions = [\n MembershipActionType.SendDelayedEvent,\n MembershipActionType.SendJoinEvent,\n ];\n this.logger.warn(\"Missing own membership: force re-join\");\n this.state.hasMemberStateEvent = false;\n\n if (this.scheduler.actions.some((a) => sendingMembershipActions.includes(a.type))) {\n this.logger.error(\n \"tried adding another `SendDelayedEvent` actions even though we already have one in the Queue\\nActionQueueOnMemberUpdate:\",\n this.scheduler.actions,\n );\n } else {\n // Only react to our own membership missing if we have not already scheduled sending a new membership DirectMembershipManagerAction.Join\n this.scheduler.initiateJoin();\n }\n }\n return Promise.resolve();\n }\n\n public async updateCallIntent(callIntent: RTCCallIntent): Promise<void> {\n if (!this.activated || !this.ownMembership) {\n throw Error(\"You cannot update your intent before joining the call\");\n }\n if (this.ownMembership.callIntent === callIntent) {\n return; // No-op\n }\n this.callIntent = callIntent;\n // Kick off a new membership event as a result.\n await this.sendJoinEvent();\n }\n\n /**\n * @throws if the client does not return user or device id.\n * @param joinConfig\n * @param room\n * @param client\n */\n public constructor(\n private readonly joinConfig: (SessionConfig & MembershipConfig) | undefined,\n protected readonly room: Pick<Room, \"roomId\" | \"getVersion\">,\n protected readonly client: MembershipManagerClient,\n public readonly slotDescription: SlotDescription,\n parentLogger?: Logger,\n ) {\n super();\n this.logger = (parentLogger ?? rootLogger).getChild(`[MembershipManager]`);\n const [userId, deviceId] = [this.client.getUserId(), this.client.getDeviceId()];\n if (userId === null) throw Error(\"Missing userId in client\");\n if (deviceId === null) throw Error(\"Missing deviceId in client\");\n this.deviceId = deviceId;\n this.userId = userId;\n // this needs to become a uuid so that consecutive join/leaves result in a key rotation.\n // we keep it as a string for now for backwards compatibility.\n this.stateKey = this.makeMembershipStateKey(userId, deviceId);\n this.state = MembershipManager.defaultState;\n this.callIntent = joinConfig?.callIntent;\n this.scheduler = new ActionScheduler((type): Promise<ActionUpdate> => {\n if (this.oldStatus) {\n // we put this at the beginning of the actions scheduler loop handle callback since it is a loop this\n // is equivalent to running it at the end of the loop. (just after applying the status/action list changes)\n // This order is required because this method needs to return the action updates.\n this.logger.debug(\n `MembershipManager applied action changes. Status: ${this.oldStatus} -> ${this.status}`,\n );\n if (this.oldStatus !== this.status) {\n this.emit(MembershipManagerEvent.StatusChanged, this.oldStatus, this.status);\n }\n }\n this.oldStatus = this.status;\n this.logger.debug(`MembershipManager before processing action. status=${this.oldStatus}`);\n return this.membershipLoopHandler(type);\n }, this.logger);\n }\n\n private _ownMembership?: CallMembership;\n public get ownMembership(): CallMembership | undefined {\n return this._ownMembership;\n }\n\n // scheduler\n private oldStatus?: Status;\n private scheduler: ActionScheduler;\n\n // MembershipManager mutable state.\n private state: MembershipManagerState;\n private static get defaultState(): MembershipManagerState {\n return {\n hasMemberStateEvent: false,\n delayId: undefined,\n\n startTime: 0,\n rateLimitRetries: new Map(),\n networkErrorRetries: new Map(),\n expireUpdateIterations: 1,\n probablyLeft: false,\n };\n }\n // Membership Event static parameters:\n protected deviceId: string;\n protected userId: string;\n protected stateKey: string;\n protected rtcTransport?: Transport;\n /** @deprecated This will be removed in favor or rtcTransport becoming a list of actively used transports */\n private fociPreferred?: Transport[];\n\n // Config:\n private delayedLeaveEventDelayMsOverride?: number;\n\n private get networkErrorRetryMs(): number {\n return this.joinConfig?.networkErrorRetryMs ?? 3_000;\n }\n private get membershipEventExpiryMs(): number {\n return this.joinConfig?.membershipEventExpiryMs ?? DEFAULT_EXPIRE_DURATION;\n }\n private get membershipEventExpiryHeadroomMs(): number {\n return this.joinConfig?.membershipEventExpiryHeadroomMs ?? 5_000;\n }\n private computeNextExpiryActionTs(iteration: number): number {\n return (\n this.state.startTime +\n Math.min(this.membershipEventExpiryMs, MEMBERSHIP_STICKY_DURATION_MS) * iteration -\n this.membershipEventExpiryHeadroomMs\n );\n }\n protected get delayedLeaveEventDelayMs(): number {\n return this.delayedLeaveEventDelayMsOverride ?? this.joinConfig?.delayedLeaveEventDelayMs ?? 8_000;\n }\n private get delayedLeaveEventRestartMs(): number {\n return this.joinConfig?.delayedLeaveEventRestartMs ?? 5_000;\n }\n private get maximumRateLimitRetryCount(): number {\n return this.joinConfig?.maximumRateLimitRetryCount ?? 10;\n }\n private get maximumNetworkErrorRetryCount(): number {\n return this.joinConfig?.maximumNetworkErrorRetryCount ?? 10;\n }\n private get delayedLeaveEventRestartLocalTimeoutMs(): number {\n return this.joinConfig?.delayedLeaveEventRestartLocalTimeoutMs ?? 2000;\n }\n\n // LOOP HANDLER:\n private async membershipLoopHandler(type: MembershipActionType): Promise<ActionUpdate> {\n switch (type) {\n case MembershipActionType.SendDelayedEvent: {\n // Before we start we check if we come from a state where we have a delay id.\n if (!this.state.delayId) {\n return this.sendOrResendDelayedLeaveEvent(); // Normal case without any previous delayed id.\n } else {\n // This can happen if someone else (or another client) removes our own membership event.\n // It will trigger `onRTCSessionMemberUpdate` queue `MembershipActionType.SendDelayedEvent`.\n // We might still have our delayed event from the previous participation and dependent on the server this might not\n // get removed automatically if the state changes. Hence, it would remove our membership unexpectedly shortly after the rejoin.\n //\n // In this block we will try to cancel this delayed event before setting up a new one.\n\n return this.cancelKnownDelayIdBeforeSendDelayedEvent(this.state.delayId);\n }\n }\n case MembershipActionType.RestartDelayedEvent: {\n if (!this.state.delayId) {\n // Delay id got reset. This action was used to check if the hs canceled the delayed event when the join state got sent.\n return createInsertActionUpdate(MembershipActionType.SendDelayedEvent);\n }\n return this.restartDelayedEvent(this.state.delayId);\n }\n case MembershipActionType.SendScheduledDelayedLeaveEvent: {\n // We are already good\n if (!this.state.hasMemberStateEvent) {\n return { replace: [] };\n }\n if (this.state.delayId) {\n return this.sendScheduledDelayedLeaveEventOrFallbackToSendLeaveEvent(this.state.delayId);\n } else {\n return createInsertActionUpdate(MembershipActionType.SendLeaveEvent);\n }\n }\n case MembershipActionType.SendJoinEvent: {\n return this.sendJoinEvent();\n }\n case MembershipActionType.UpdateExpiry: {\n return this.updateExpiryOnJoinedEvent();\n }\n case MembershipActionType.SendLeaveEvent: {\n // We are good already\n if (!this.state.hasMemberStateEvent) {\n return { replace: [] };\n }\n // This is only a fallback in case we do not have working delayed events support.\n // first we should try to just send the scheduled leave event\n return this.sendFallbackLeaveEvent();\n }\n }\n }\n\n // an abstraction to switch between sending state or a sticky event\n protected clientSendDelayedDisconnectMembership: () => Promise<SendDelayedEventResponse> = () =>\n this.client._unstable_sendDelayedStateEvent(\n this.room.roomId,\n { delay: this.delayedLeaveEventDelayMs },\n EventType.GroupCallMemberPrefix,\n {},\n this.stateKey,\n );\n\n // HANDLERS (used in the membershipLoopHandler)\n private async sendOrResendDelayedLeaveEvent(): Promise<ActionUpdate> {\n // We can reach this at the start of a call (where we do not yet have a membership: state.hasMemberStateEvent=false)\n // or during a call if the state event canceled our delayed event or caused by an unexpected error that removed our delayed event.\n // (Another client could have canceled it, the homeserver might have removed/lost it due to a restart, ...)\n // In the `then` and `catch` block we treat both cases differently. \"if (this.state.hasMemberStateEvent) {} else {}\"\n return await this.clientSendDelayedDisconnectMembership()\n .then((response) => {\n this.state.expectedServerDelayLeaveTs = Date.now() + this.delayedLeaveEventDelayMs;\n this.setAndEmitProbablyLeft(false);\n // On success we reset retries and set delayId.\n this.resetRateLimitCounter(MembershipActionType.SendDelayedEvent);\n this.setAndEmitDelayId(response.delay_id);\n if (this.state.hasMemberStateEvent) {\n // This action was scheduled because the previous delayed event was cancelled\n // due to lack of https://github.com/element-hq/synapse/pull/17810\n return createInsertActionUpdate(\n MembershipActionType.RestartDelayedEvent,\n this.delayedLeaveEventRestartMs,\n );\n } else {\n // This action was scheduled because we are in the process of joining\n return createInsertActionUpdate(MembershipActionType.SendJoinEvent);\n }\n })\n .catch((e) => {\n const repeatActionType = MembershipActionType.SendDelayedEvent;\n if (this.manageMaxDelayExceededSituation(e)) {\n return createInsertActionUpdate(repeatActionType);\n }\n const update = this.actionUpdateFromErrors(e, repeatActionType, \"_unstable_sendDelayedStateEvent\");\n if (update) return update;\n\n if (this.state.hasMemberStateEvent) {\n // This action was scheduled because the previous delayed event was cancelled\n // due to lack of https://github.com/element-hq/synapse/pull/17810\n\n // Don't do any other delayed event work if its not supported.\n if (this.isUnsupportedDelayedEndpoint(e)) return {};\n throw Error(\"Could not send delayed event, even though delayed events are supported. \" + e);\n } else {\n // This action was scheduled because we are in the process of joining\n // log and fall through\n if (this.isUnsupportedDelayedEndpoint(e)) {\n this.logger.info(\"Not using delayed event because the endpoint is not supported\");\n } else {\n this.logger.info(\"Not using delayed event because: \" + e);\n }\n // On any other error we fall back to not using delayed events and send the join state event immediately\n return createInsertActionUpdate(MembershipActionType.SendJoinEvent);\n }\n });\n }\n\n private async cancelKnownDelayIdBeforeSendDelayedEvent(delayId: string): Promise<ActionUpdate> {\n // Remove all running updates and restarts\n return await this.client\n ._unstable_cancelScheduledDelayedEvent(delayId)\n .then(() => {\n this.setAndEmitDelayId(undefined);\n this.resetRateLimitCounter(MembershipActionType.SendDelayedEvent);\n return createReplaceActionUpdate(MembershipActionType.SendDelayedEvent);\n })\n .catch((e) => {\n const repeatActionType = MembershipActionType.SendDelayedEvent;\n const update = this.actionUpdateFromErrors(e, repeatActionType, \"cancelScheduledDelayedEvent\");\n if (update) return update;\n\n if (this.isNotFoundError(e)) {\n // If we get a M_NOT_FOUND we know that the delayed event got already removed.\n // This means we are good and can set it to undefined and run this again.\n this.setAndEmitDelayId(undefined);\n return createReplaceActionUpdate(repeatActionType);\n }\n if (this.isUnsupportedDelayedEndpoint(e)) {\n return createReplaceActionUpdate(MembershipActionType.SendJoinEvent);\n }\n // We do not just ignore and log this error since we would also need to reset the delayId.\n\n // This becomes an unrecoverable error case since something is significantly off if we don't hit any of the above cases\n // when state.delayId !== undefined\n // We do not just ignore and log this error since we would also need to reset the delayId.\n // It is cleaner if we, the frontend, rejoins instead of resetting the delayId here and behaving like in the success case.\n throw Error(\n \"We failed to cancel a delayed event where we already had a delay id with an error we cannot automatically handle\",\n );\n });\n }\n\n private setAndEmitProbablyLeft(probablyLeft: boolean): void {\n if (this.state.probablyLeft === probablyLeft) {\n return;\n }\n this.state.probablyLeft = probablyLeft;\n this.emit(MembershipManagerEvent.ProbablyLeft, this.state.probablyLeft);\n }\n\n private setAndEmitDelayId(delayId: string | undefined): void {\n if (this.state.delayId === delayId) return;\n\n this.state.delayId = delayId;\n this.emit(MembershipManagerEvent.DelayIdChanged, this.state.delayId);\n }\n\n private async restartDelayedEvent(delayId: string): Promise<ActionUpdate> {\n // Compute the duration until we expect the server to send the delayed leave event.\n const durationUntilServerDelayedLeave = this.state.expectedServerDelayLeaveTs\n ? this.state.expectedServerDelayLeaveTs - Date.now()\n : undefined;\n const abortPromise = new Promise((_, reject) => {\n setTimeout(\n () => {\n reject(new AbortError(\"Restart delayed event timed out before the HS responded\"));\n },\n // We abort immediately at the time where we expect the server to send the delayed leave event.\n // At this point we want the catch block to run and set the `probablyLeft` state.\n //\n // While we are already in probablyLeft state, we use the unaltered delayedLeaveEventRestartLocalTimeoutMs.\n durationUntilServerDelayedLeave !== undefined && !this.state.probablyLeft\n ? Math.min(this.delayedLeaveEventRestartLocalTimeoutMs, durationUntilServerDelayedLeave)\n : this.delayedLeaveEventRestartLocalTimeoutMs,\n );\n });\n\n // The obvious choice here would be to use the `IRequestOpts` to set the timeout. Since this call might be forwarded\n // to the widget driver this information would get lost. That is why we mimic the AbortError using the race.\n return await Promise.race([this.client._unstable_restartScheduledDelayedEvent(delayId), abortPromise])\n .then(() => {\n // Whenever we successfully restart the delayed event we update the `state.expectedServerDelayLeaveTs`\n // which stores the predicted timestamp at which the server will send the delayed leave event if there wont be any further\n // successful restart requests.\n this.state.expectedServerDelayLeaveTs = Date.now() + this.delayedLeaveEventDelayMs;\n this.resetRateLimitCounter(MembershipActionType.RestartDelayedEvent);\n this.setAndEmitProbablyLeft(false);\n return createInsertActionUpdate(\n MembershipActionType.RestartDelayedEvent,\n this.delayedLeaveEventRestartMs,\n );\n })\n .catch((e) => {\n if (this.state.expectedServerDelayLeaveTs && this.state.expectedServerDelayLeaveTs <= Date.now()) {\n // Once we reach this point it's likely that the server is sending the delayed leave event so we emit `probablyLeft = true`.\n // It will emit `probablyLeft = false` once we notice about our leave through sync and successfully setup a new state event.\n this.setAndEmitProbablyLeft(true);\n }\n const repeatActionType = MembershipActionType.RestartDelayedEvent;\n if (this.isNotFoundError(e)) {\n this.setAndEmitDelayId(undefined);\n return createInsertActionUpdate(MembershipActionType.SendDelayedEvent);\n }\n // If the HS does not support delayed events we wont reschedule.\n if (this.isUnsupportedDelayedEndpoint(e)) return {};\n\n // TODO this also needs a test: get rate limit while checking id delayed event is scheduled\n const update = this.actionUpdateFromErrors(e, repeatActionType, \"restartScheduledDelayedEvent\");\n if (update) return update;\n\n // In other error cases we have no idea what is happening\n throw Error(\"Could not restart delayed event, even though delayed events are supported. \" + e);\n });\n }\n\n private async sendScheduledDelayedLeaveEventOrFallbackToSendLeaveEvent(delayId: string): Promise<ActionUpdate> {\n return await this.client\n ._unstable_sendScheduledDelayedEvent(delayId)\n .then(() => {\n this.state.hasMemberStateEvent = false;\n this.setAndEmitDelayId(undefined);\n this.resetRateLimitCounter(MembershipActionType.SendScheduledDelayedLeaveEvent);\n\n return { replace: [] };\n })\n .catch((e) => {\n const repeatActionType = MembershipActionType.SendLeaveEvent;\n if (this.isUnsupportedDelayedEndpoint(e)) return {};\n if (this.isNotFoundError(e)) {\n this.setAndEmitDelayId(undefined);\n return createInsertActionUpdate(repeatActionType);\n }\n const update = this.actionUpdateFromErrors(e, repeatActionType, \"sendScheduledDelayedEvent\");\n if (update) return update;\n\n // On any other error we fall back to SendLeaveEvent (this includes hard errors from rate limiting)\n this.logger.warn(\n \"Encountered unexpected error during SendScheduledDelayedLeaveEvent. Falling back to SendLeaveEvent\",\n e,\n );\n return createInsertActionUpdate(repeatActionType);\n });\n }\n\n protected clientSendMembership: (\n myMembership: RtcMembershipData | SessionMembershipData | EmptyObject,\n ) => Promise<ISendEventResponse> = (myMembership) => {\n return this.client.sendStateEvent(\n this.room.roomId,\n EventType.GroupCallMemberPrefix,\n myMembership as EmptyObject | SessionMembershipData,\n this.stateKey,\n );\n };\n\n private async sendJoinEvent(): Promise<ActionUpdate> {\n return await this.clientSendMembership(this.makeMyMembership(this.membershipEventExpiryMs))\n .then(() => {\n this.setAndEmitProbablyLeft(false);\n this.state.startTime = Date.now();\n // The next update should already use twice the membershipEventExpiryTimeout\n this.state.expireUpdateIterations = 1;\n this.state.hasMemberStateEvent = true;\n this.resetRateLimitCounter(MembershipActionType.SendJoinEvent);\n // An UpdateExpiry action might be left over from a previous join event.\n // We can reach sendJoinEvent when the delayed leave event gets send by the HS.\n // The branch where we might have a leftover UpdateExpiry action is:\n // RestartDelayedEvent (cannot find it, server removed it)\n // -> SendDelayedEvent (send new delayed event)\n // -> SendJoinEvent (here with a still scheduled UpdateExpiry action)\n const actionsWithoutUpdateExpiry = this.scheduler.actions.filter(\n (a) =>\n a.type !== MembershipActionType.UpdateExpiry && // A new UpdateExpiry action with an updated will be scheduled,\n a.type !== MembershipActionType.SendJoinEvent, // Manually remove the SendJoinEvent action,\n );\n return {\n replace: [\n ...actionsWithoutUpdateExpiry,\n // To check if the delayed event is still there or got removed by inserting the stateEvent, we need to restart it.\n { ts: Date.now(), type: MembershipActionType.RestartDelayedEvent },\n {\n ts: this.computeNextExpiryActionTs(this.state.expireUpdateIterations),\n type: MembershipActionType.UpdateExpiry,\n },\n ],\n };\n })\n .catch((e) => {\n const update = this.actionUpdateFromErrors(e, MembershipActionType.SendJoinEvent, \"sendStateEvent\");\n if (update) return update;\n throw e;\n });\n }\n\n private async updateExpiryOnJoinedEvent(): Promise<ActionUpdate> {\n const nextExpireUpdateIteration = this.state.expireUpdateIterations + 1;\n return await this.clientSendMembership(\n this.makeMyMembership(this.membershipEventExpiryMs * nextExpireUpdateIteration),\n )\n .then(() => {\n // Success, we reset retries and schedule update.\n this.resetRateLimitCounter(MembershipActionType.UpdateExpiry);\n this.state.expireUpdateIterations = nextExpireUpdateIteration;\n return {\n insert: [\n {\n ts: this.computeNextExpiryActionTs(nextExpireUpdateIteration),\n type: MembershipActionType.UpdateExpiry,\n },\n ],\n };\n })\n .catch((e) => {\n const update = this.actionUpdateFromErrors(e, MembershipActionType.UpdateExpiry, \"sendStateEvent\");\n if (update) return update;\n\n throw e;\n });\n }\n private async sendFallbackLeaveEvent(): Promise<ActionUpdate> {\n return await this.clientSendMembership({})\n .then(() => {\n this.resetRateLimitCounter(MembershipActionType.SendLeaveEvent);\n this.state.hasMemberStateEvent = false;\n return { replace: [] };\n })\n .catch((e) => {\n const update = this.actionUpdateFromErrors(e, MembershipActionType.SendLeaveEvent, \"sendStateEvent\");\n if (update) return update;\n throw e;\n });\n }\n\n // HELPERS\n /**\n * this creates `${localUserId}_${localDeviceId}_${this.slotDescription.application}${this.slotDescription.id}`\n * which is not compatible with membershipID of session type member events. They have to be `${localUserId}:${localDeviceId}`\n */\n private makeMembershipStateKey(localUserId: string, localDeviceId: string): string {\n // INFO_SLOT_ID_LEGACY_CASE (search for all occurances of this INFO to get the full picture)\n // Revert back to \"\" just for the state key (state keys are always legacy. we use sticky events for non legacy events)\n const application = this.slotDescription.application;\n const needsEmptyStringRoomFix = application === \"m.call\" && this.slotDescription.id === \"ROOM\";\n const slotId = needsEmptyStringRoomFix ? \"\" : this.slotDescription.id;\n const stateKey = `${localUserId}_${localDeviceId}_${application}${slotId}`;\n if (/^org\\.matrix\\.msc(3757|3779)\\b/.exec(this.room.getVersion())) {\n return stateKey;\n } else {\n return `_${stateKey}`;\n }\n }\n\n /**\n * Constructs our own membership\n * @returns Only returns `SessionMembershipData`\n */\n protected makeMyMembership(expires: number): SessionMembershipData | RtcMembershipData {\n const ownMembership = this.ownMembership;\n const needsEmptyStringRoomFix =\n this.slotDescription.application === \"m.call\" && this.slotDescription.id === \"ROOM\";\n\n const focusObjects: Pick<SessionMembershipData, \"foci_preferred\" | \"focus_active\"> =\n this.rtcTransport === undefined\n ? {\n focus_active: { type: \"livekit\", focus_selection: \"oldest_membership\" } as const,\n foci_preferred: this.fociPreferred ?? [],\n }\n : {\n focus_active: { type: \"livekit\", focus_selection: \"multi_sfu\" } as const,\n foci_preferred: [this.rtcTransport, ...(this.fociPreferred ?? [])],\n };\n return {\n \"application\": this.slotDescription.application,\n // INFO_SLOT_ID_LEGACY_CASE (search for all occurances of this INFO to get the full picture)\n // Revert back to \"\" just for the sending the event.\n \"call_id\": needsEmptyStringRoomFix ? \"\" : this.slotDescription.id,\n \"scope\": \"m.room\",\n \"device_id\": this.deviceId,\n // DO NOT use this.memberId here since that is the state key (using application...)\n // But for session events we use the colon seperated userId and deviceId. The SFU will automatically\n // assign those values to the media participant for those versions.\n \"membershipID\": `${this.userId}:${this.deviceId}`,\n expires,\n \"m.call.intent\": this.callIntent,\n ...focusObjects,\n ...(ownMembership !== undefined ? { created_ts: ownMembership.createdTs() } : undefined),\n };\n }\n\n // Error checks and handlers\n\n /**\n * Check if its a NOT_FOUND error\n * @param error the error causing this handler check/execution\n * @returns true if its a not found error\n */\n private isNotFoundError(error: unknown): boolean {\n return error instanceof MatrixError && error.errcode === \"M_NOT_FOUND\";\n }\n\n /**\n * Check if this is a DelayExceeded timeout and update the TimeoutOverride for the next try\n * @param error the error causing this handler check/execution\n * @returns true if its a delay exceeded error and we updated the local TimeoutOverride\n */\n private manageMaxDelayExceededSituation(error: unknown): boolean {\n if (\n error instanceof MatrixError &&\n error.errcode === \"M_UNKNOWN\" &&\n error.data[\"org.matrix.msc4140.errcode\"] === \"M_MAX_DELAY_EXCEEDED\"\n ) {\n const maxDelayAllowed = error.data[\"org.matrix.msc4140.max_delay\"];\n if (typeof maxDelayAllowed === \"number\" && this.delayedLeaveEventDelayMs > maxDelayAllowed) {\n this.delayedLeaveEventDelayMsOverride = maxDelayAllowed;\n }\n this.logger.warn(\"Retry sending delayed disconnection event due to server timeout limitations:\", error);\n return true;\n }\n return false;\n }\n\n protected actionUpdateFromErrors(\n error: unknown,\n type: MembershipActionType,\n method: string,\n ): ActionUpdate | undefined {\n const updateLimit = this.actionUpdateFromRateLimitError(error, method, type);\n if (updateLimit) return updateLimit;\n const updateNetwork = this.actionUpdateFromNetworkErrorRetry(error, type);\n if (updateNetwork) return updateNetwork;\n }\n /**\n * Check if we have a rate limit error and schedule the same action again if we dont exceed the rate limit retry count yet.\n * @param error the error causing this handler check/execution\n * @param method the method used for the throw message\n * @param type which MembershipActionType we reschedule because of a rate limit.\n * @throws If it is a rate limit error and the retry count got exceeded\n * @returns Returns true if we handled the error by rescheduling the correct next action.\n * Returns false if it is not a network error.\n */\n private actionUpdateFromRateLimitError(\n error: unknown,\n method: string,\n type: MembershipActionType,\n ): ActionUpdate | undefined {\n // \"Is rate limit\"-boundary\n if (!((error instanceof HTTPError || error instanceof MatrixError) && error.isRateLimitError())) {\n return undefined;\n }\n\n // retry boundary\n const rateLimitRetries = this.state.rateLimitRetries.get(type) ?? 0;\n if (rateLimitRetries < this.maximumRateLimitRetryCount) {\n let resendDelay: number;\n const defaultMs = 5000;\n try {\n resendDelay = error.getRetryAfterMs() ?? defaultMs;\n this.logger.info(`Rate limited by server, retrying in ${resendDelay}ms`);\n } catch (e) {\n this.logger.warn(\n `Error while retrieving a rate-limit retry delay, retrying after default delay of ${defaultMs}`,\n e,\n );\n resendDelay = defaultMs;\n }\n this.state.rateLimitRetries.set(type, rateLimitRetries + 1);\n return createInsertActionUpdate(type, resendDelay);\n }\n\n throw Error(\"Exceeded maximum retries for \" + type + \" attempts (client.\" + method + \")\", { cause: error });\n }\n\n /**\n * FIXME Don't Check the error and retry the same MembershipAction again in the configured time and for the configured retry count.\n * @param error the error causing this handler check/execution\n * @param type the action type that we need to repeat because of the error\n * @throws If it is a network error and the retry count got exceeded\n * @returns\n * Returns true if we handled the error by rescheduling the correct next action.\n * Returns false if it is not a network error.\n */\n private actionUpdateFromNetworkErrorRetry(error: unknown, type: MembershipActionType): ActionUpdate | undefined {\n // \"Is a network error\"-boundary\n const retries = this.state.networkErrorRetries.get(type) ?? 0;\n\n // Strings for error logging\n const retryDurationString = this.networkErrorRetryMs / 1000 + \"s\";\n const retryCounterString = \"(\" + retries + \"/\" + this.maximumNetworkErrorRetryCount + \")\";\n\n // Variables for scheduling the new event\n const retryDuration = this.networkErrorRetryMs;\n\n if (error instanceof Error && error.name === \"AbortError\") {\n // A local timeout means the server accepted the request but is slow to answer. Retry immediately and\n // do not count it towards the fatal retry limit: the server's delayed leave already bounds how long a\n // stalled restart can go unnoticed, and the resulting forced re-join recovers the membership. Giving\n // up here would only replace a temporary media pause with a \"connection lost\" error for the user.\n this.logger.warn(\"Network local timeout error while sending event, immediate retry\", error);\n return createInsertActionUpdate(type, 0);\n } else if (error instanceof Error && error.message.includes(\"updating delayed event\")) {\n // TODO: We do not want error message matching here but instead the error should be a typed HTTPError\n // and be handled below automatically (the same as in the SPA case).\n //\n // The error originates because of https://github.com/matrix-org/matrix-widget-api/blob/5d81d4a26ff69e4bd3ddc79a884c9527999fb2f4/src/ClientWidgetApi.ts#L698-L701\n // uses `e` instance of HttpError (and not MatrixError)\n // The element web widget driver (only checks for MatrixError) is then failing to process (`processError`) it as a typed error: https://github.com/element-hq/element-web/blob/471712cbf06a067e5499bd5d2d7a75f693d9a12d/src/stores/widgets/StopGapWidgetDriver.ts#L711-L715\n // So it will not call: `error.asWidgetApiErrorData()` which is also missing for `HttpError`\n //\n // A proper fix would be to either find a place to convert the `HttpError` into a `MatrixError` and the `processError`\n // method to handle it as expected or to adjust `processError` to also process `HttpError`'s.\n this.logger.warn(\n \"delayed event update timeout error, retrying in \" + retryDurationString + \" \" + retryCounterString,\n error,\n );\n } else if (error instanceof ConnectionError) {\n this.logger.warn(\n \"Network connection error while sending event, retrying in \" +\n retryDurationString +\n \" \" +\n retryCounterString,\n error,\n );\n } else if (\n (error instanceof HTTPError || error instanceof MatrixError) &&\n typeof error.httpStatus === \"number\" &&\n error.httpStatus >= 500 &&\n error.httpStatus < 600\n ) {\n this.logger.warn(\n \"Server error while sending event, retrying in \" + retryDurationString + \" \" + retryCounterString,\n error,\n );\n } else {\n return undefined;\n }\n\n // retry boundary\n if (retries < this.maximumNetworkErrorRetryCount) {\n this.state.networkErrorRetries.set(type, retries + 1);\n return createInsertActionUpdate(type, retryDuration);\n }\n\n // Failure\n throw Error(\n \"Reached maximum (\" + this.maximumNetworkErrorRetryCount + \") retries cause by: \" + (error as Error),\n );\n }\n\n /**\n * Check if its an UnsupportedDelayedEventsEndpointError and which implies that we cannot do any delayed event logic\n * @param error The error to check\n * @returns true it its an UnsupportedDelayedEventsEndpointError\n */\n private isUnsupportedDelayedEndpoint(error: unknown): boolean {\n return error instanceof UnsupportedDelayedEventsEndpointError;\n }\n\n private resetRateLimitCounter(type: MembershipActionType): void {\n this.state.rateLimitRetries.set(type, 0);\n this.state.networkErrorRetries.set(type, 0);\n }\n\n public get status(): Status {\n const actions = this.scheduler.actions;\n if (actions.length === 1) {\n const { type } = actions[0];\n switch (type) {\n case MembershipActionType.SendDelayedEvent:\n case MembershipActionType.SendJoinEvent:\n return Status.Connecting;\n case MembershipActionType.UpdateExpiry: // where no delayed events\n return Status.Connected;\n case MembershipActionType.SendScheduledDelayedLeaveEvent:\n case MembershipActionType.SendLeaveEvent:\n return Status.Disconnecting;\n default:\n // pass through as not expected\n }\n } else if (actions.length === 2) {\n const types = actions.map((a) => a.type);\n // normal state for connected with delayed events\n if (\n (types.includes(MembershipActionType.RestartDelayedEvent) ||\n (types.includes(MembershipActionType.SendDelayedEvent) && this.state.hasMemberStateEvent)) &&\n types.includes(MembershipActionType.UpdateExpiry)\n ) {\n return Status.Connected;\n }\n } else if (actions.length === 3) {\n const types = actions.map((a) => a.type);\n // It is a correct connected state if we already schedule the next Restart but have not yet cleaned up\n // the current restart.\n if (\n types.filter((t) => t === MembershipActionType.RestartDelayedEvent).length === 2 &&\n types.includes(MembershipActionType.UpdateExpiry)\n ) {\n return Status.Connected;\n }\n }\n\n if (!this.scheduler.running) {\n return Status.Disconnected;\n }\n\n this.logger.error(\"MembershipManager has an unknown state. Actions: \", actions);\n return Status.Unknown;\n }\n\n public get probablyLeft(): boolean {\n return this.state.probablyLeft;\n }\n public get delayId(): string | undefined {\n return this.state.delayId;\n }\n}\n\n/**\n * Implementation of the Membership manager that uses sticky events\n * rather than state events.\n */\nexport class StickyEventMembershipManager extends MembershipManager {\n public constructor(\n joinConfig: (SessionConfig & MembershipConfig) | undefined,\n room: Pick<Room, \"getLiveTimeline\" | \"roomId\" | \"getVersion\">,\n private readonly clientWithSticky: MembershipManagerClient &\n Pick<MatrixClient, \"_unstable_sendStickyEvent\" | \"_unstable_sendStickyDelayedEvent\">,\n sessionDescription: SlotDescription,\n // this needs to become a uuid so that consecutive join/leaves result in a key rotation.\n // we keep it as a string for now for backwards compatibility.\n private readonly memberId: string,\n parentLogger?: Logger,\n ) {\n super(joinConfig, room, clientWithSticky, sessionDescription, parentLogger);\n }\n\n protected clientSendDelayedDisconnectMembership: () => Promise<SendDelayedEventResponse> = () =>\n this.clientWithSticky._unstable_sendStickyDelayedEvent(\n this.room.roomId,\n MEMBERSHIP_STICKY_DURATION_MS,\n { delay: this.delayedLeaveEventDelayMs },\n null,\n EventType.RTCMembership,\n { msc4354_sticky_key: this.memberId },\n );\n\n protected clientSendMembership: (\n myMembership: RtcMembershipData | SessionMembershipData | EmptyObject,\n ) => Promise<ISendEventResponse> = (myMembership) => {\n return this.clientWithSticky._unstable_sendStickyEvent(\n this.room.roomId,\n MEMBERSHIP_STICKY_DURATION_MS,\n null,\n EventType.RTCMembership,\n { ...myMembership, msc4354_sticky_key: this.memberId },\n );\n };\n\n private static nameMap = new Map([\n [\"sendStateEvent\", \"_unstable_sendStickyEvent\"],\n [\"sendDelayedStateEvent\", \"_unstable_sendStickyDelayedEvent\"],\n ]);\n protected actionUpdateFromErrors(e: unknown, t: MembershipActionType, m: string): ActionUpdate | undefined {\n return super.actionUpdateFromErrors(e, t, StickyEventMembershipManager.nameMap.get(m) ?? \"unknown\");\n }\n\n /**\n *\n * @returns Only returns `RtcMembershipData`\n */\n protected makeMyMembership(): RtcMembershipData {\n const ownMembership = this.ownMembership;\n\n const livekitTransport = isLivekitTransportConfig(this.rtcTransport) ? this.rtcTransport : undefined;\n const relationObject = ownMembership?.eventId\n ? { \"m.relation\": { rel_type: RelationType.Reference, event_id: ownMembership?.eventId } }\n : {};\n return {\n application: {\n type: this.slotDescription.application,\n ...(this.callIntent ? { \"m.call.intent\": this.callIntent } : {}),\n },\n slot_id: computeSlotId(this.slotDescription),\n transports: {\n // Make sure we do not add the alias to the transport.\n // It is not needed in matrix2.0. The additional session information will be used to find the right alias on the sfu.\n published: livekitTransport\n ? [{ type: livekitTransport.type, livekit_service_url: livekitTransport.livekit_service_url }]\n : [],\n can_subscribe: [\"livekit\"],\n },\n member: { device_id: this.deviceId, user_id: this.userId, id: this.memberId },\n versions: [],\n ...relationObject,\n };\n }\n}\n"],"mappings":";;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS,UAAU,QAAQ,SAAS;AAEpC,SAAS,SAAS,EAAE,YAAY,QAAQ,oBAAoB;AAI5D,SAAS,eAAe,EAAE,SAAS,EAAE,WAAW,QAAQ,uBAAuB;AAC/E,SAAsB,MAAM,IAAI,UAAU,QAAQ,cAAc;AAEhE,SAA8B,uBAAuB,QAAQ,qBAAqB;AAClF,SAAyB,cAAc,EAAsB,MAAM,QAA8B,YAAY;AAE7G,SAAS,eAAe,QAA2B,uCAAuC;AAC1F,SAAS,iBAAiB,QAAQ,kCAAkC;AACpE,SAAS,qCAAqC,QAAQ,cAAc;AACpE,SACI,sBAAsB,QAGnB,yBAAyB;AAEhC,SAAS,aAAa,QAAQ,YAAY;AAC1C,SAAS,wBAAwB,QAAQ,uBAAuB;;AAEhE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,MAAM,6BAA6B,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;;AAEtD;AACA;AACA;AACA;AACA,WAAY,oBAAoB,0BAApB,oBAAoB;EAApB,oBAAoB;EAE5B;EACA;EACA;EAJQ,oBAAoB;EAO5B;EACA;EACA;EATQ,oBAAoB;EAY5B;EACA;EACA;EAdQ,oBAAoB;EAiB5B;EAjBQ,oBAAoB;EAoB5B;EACA;EArBQ,oBAAoB,uCAwB5B;EAAA,OAxBQ,oBAAoB;AAAA;;AA2BhC;AACA;AACA;;AA2BA,SAAS,wBAAwB,CAAC,IAA0B,EAAE,MAAe,EAAgB;EACzF,OAAO;IACH,MAAM,EAAE,CAAC;MAAE,EAAE,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,MAAM,IAAI,CAAC,CAAC;MAAE;IAAK,CAAC;EACrD,CAAC;AACL;AAEA,SAAS,yBAAyB,CAAC,IAA0B,EAAE,MAAe,EAAgB;EAC1F,OAAO;IACH,OAAO,EAAE,CAAC;MAAE,EAAE,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,MAAM,IAAI,CAAC,CAAC;MAAE;IAAK,CAAC;EACtD,CAAC;AACL;AAcA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,MAAM,iBAAiB,SAClB,iBAAiB,CAE7B;EAKW,WAAW,GAAY;IAC1B,OAAO,IAAI,CAAC,SAAS;EACzB;EACA;EACO,QAAQ,GAAY;IACvB,OAAO,IAAI,CAAC,WAAW,CAAC,CAAC;EAC7B;;EAEA;AACJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;EACW,IAAI,CAAC,aAA0B,EAAE,aAAyB,EAAE,OAAkC,EAAQ;IACzG,IAAI,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE;MACxB,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,8DAA8D,CAAC;MACjF;IACJ;IACA,IAAI,CAAC,aAAa,GAAG,aAAa;IAClC,IAAI,CAAC,YAAY,GAAG,aAAa;IACjC,IAAI,CAAC,qBAAqB,GAAG,SAAS;IACtC,IAAI,CAAC,SAAS,GAAG,IAAI;IACrB,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,MAAM;IAC5B,IAAI,CAAC,KAAK,GAAG,iBAAiB,CAAC,YAAY;IAE3C,IAAI,CAAC,SAAS,CACT,aAAa,CAAC,CAAC,CACf,KAAK,CAAE,CAAC,IAAK;MACV,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,qCAAqC,EAAE,CAAC,CAAC;MAC3D,OAAO,GAAG,CAAC,CAAC;IAChB,CAAC,CAAC,CACD,OAAO,CAAC,MAAM;MACX;MACA,IAAI,CAAC,SAAS,GAAG,KAAK;MACtB;MACA,IAAI,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,SAAS,KAAK,IAAI,CAAC,MAAM,EAAE;QAClD,IAAI,CAAC,IAAI,CAAC,sBAAsB,CAAC,aAAa,EAAE,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC;MAChF;MACA,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE;QACzB,IAAI,CAAC,qBAAqB,EAAE,OAAO,CAAC,IAAI,CAAC;QACzC,IAAI,CAAC,qBAAqB,GAAG,SAAS;MAC1C;IACJ,CAAC,CAAC;EACV;;EAEA;AACJ;AACA;AACA;AACA;EACW,KAAK,CAAC,OAAgB,EAAoB;IAC7C,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE;MACzB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,mFAAmF,CAAC;MACrG,OAAO,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC;IAChC;;IAEA;IACA;IACA,IAAI,CAAC,IAAI,CAAC,qBAAqB,EAAE;MAC7B;MACA,IAAI,CAAC,qBAAqB,GAAG,OAAO,CAAC,aAAa,CAAU,CAAC;MAC7D,IAAI,CAAC,SAAS,GAAG,KAAK;MACtB,IAAI,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC;MAC9B,IAAI,OAAO,EAAE,UAAU,CAAC,MAAM,IAAI,CAAC,qBAAqB,EAAE,OAAO,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;IACtF;IACA,OAAO,IAAI,CAAC,qBAAqB,CAAC,OAAO;EAC7C;EAIO,wBAAwB,CAAC,WAA6B,EAAiB;IAC1E,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,EAAE;MACrB,OAAO,OAAO,CAAC,OAAO,CAAC,CAAC;IAC5B;IAEA,IAAI,CAAC,cAAc,GAAG,WAAW,CAAC,IAAI,CAAE,CAAC,IAAK,cAAc,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;IAE5F,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE;MACtB;MACA;MACA,MAAM,wBAAwB,GAAG,CAC7B,oBAAoB,CAAC,gBAAgB,EACrC,oBAAoB,CAAC,aAAa,CACrC;MACD,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,uCAAuC,CAAC;MACzD,IAAI,CAAC,KAAK,CAAC,mBAAmB,GAAG,KAAK;MAEtC,IAAI,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAE,CAAC,IAAK,wBAAwB,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE;QAC/E,IAAI,CAAC,MAAM,CAAC,KAAK,CACb,0HAA0H,EAC1H,IAAI,CAAC,SAAS,CAAC,OACnB,CAAC;MACL,CAAC,MAAM;QACH;QACA,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC;MACjC;IACJ;IACA,OAAO,OAAO,CAAC,OAAO,CAAC,CAAC;EAC5B;EAEA,MAAa,gBAAgB,CAAC,UAAyB,EAAiB;IACpE,IAAI,CAAC,IAAI,CAAC,SAAS,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE;MACxC,MAAM,KAAK,CAAC,uDAAuD,CAAC;IACxE;IACA,IAAI,IAAI,CAAC,aAAa,CAAC,UAAU,KAAK,UAAU,EAAE;MAC9C,OAAO,CAAC;IACZ;IACA,IAAI,CAAC,UAAU,GAAG,UAAU;IAC5B;IACA,MAAM,IAAI,CAAC,aAAa,CAAC,CAAC;EAC9B;;EAEA;AACJ;AACA;AACA;AACA;AACA;EACW,WAAW,CACG,UAA0D,EACxD,IAAyC,EACzC,MAA+B,EAClC,eAAgC,EAChD,YAAqB,EACvB;IACE,KAAK,CAAC,CAAC;IAAC,mCAzIQ,KAAK;IAAA;IAAA;IAAA;IAAA;IA4KzB;IAAA;IAAA;IAIA;IAAA;IAcA;IAAA;IAAA;IAAA;IAAA;IAKA;IAAA;IAGA;IAAA;IAyFA;IAAA,+DAC2F,MACvF,IAAI,CAAC,MAAM,CAAC,+BAA+B,CACvC,IAAI,CAAC,IAAI,CAAC,MAAM,EAChB;MAAE,KAAK,EAAE,IAAI,CAAC;IAAyB,CAAC,EACxC,SAAS,CAAC,qBAAqB,EAC/B,CAAC,CAAC,EACF,IAAI,CAAC,QACT,CAAC;IAAA,8CAmM+B,YAAY,IAAK;MACjD,OAAO,IAAI,CAAC,MAAM,CAAC,cAAc,CAC7B,IAAI,CAAC,IAAI,CAAC,MAAM,EAChB,SAAS,CAAC,qBAAqB,EAC/B,YAAY,EACZ,IAAI,CAAC,QACT,CAAC;IACL,CAAC;IAAA,KA9WoB,UAA0D,GAA1D,UAA0D;IAAA,KACxD,IAAyC,GAAzC,IAAyC;IAAA,KACzC,MAA+B,GAA/B,MAA+B;IAAA,KAClC,eAAgC,GAAhC,eAAgC;IAIhD,IAAI,CAAC,MAAM,GAAG,CAAC,YAAY,IAAI,UAAU,EAAE,QAAQ,CAAC,qBAAqB,CAAC;IAC1E,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC;IAC/E,IAAI,MAAM,KAAK,IAAI,EAAE,MAAM,KAAK,CAAC,0BAA0B,CAAC;IAC5D,IAAI,QAAQ,KAAK,IAAI,EAAE,MAAM,KAAK,CAAC,4BAA4B,CAAC;IAChE,IAAI,CAAC,QAAQ,GAAG,QAAQ;IACxB,IAAI,CAAC,MAAM,GAAG,MAAM;IACpB;IACA;IACA,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,sBAAsB,CAAC,MAAM,EAAE,QAAQ,CAAC;IAC7D,IAAI,CAAC,KAAK,GAAG,iBAAiB,CAAC,YAAY;IAC3C,IAAI,CAAC,UAAU,GAAG,UAAU,EAAE,UAAU;IACxC,IAAI,CAAC,SAAS,GAAG,IAAI,eAAe,CAAE,IAAI,IAA4B;MAClE,IAAI,IAAI,CAAC,SAAS,EAAE;QAChB;QACA;QACA;QACA,IAAI,CAAC,MAAM,CAAC,KAAK,CACb,qDAAqD,IAAI,CAAC,SAAS,OAAO,IAAI,CAAC,MAAM,EACzF,CAAC;QACD,IAAI,IAAI,CAAC,SAAS,KAAK,IAAI,CAAC,MAAM,EAAE;UAChC,IAAI,CAAC,IAAI,CAAC,sBAAsB,CAAC,aAAa,EAAE,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC;QAChF;MACJ;MACA,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,MAAM;MAC5B,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,sDAAsD,IAAI,CAAC,SAAS,EAAE,CAAC;MACzF,OAAO,IAAI,CAAC,qBAAqB,CAAC,IAAI,CAAC;IAC3C,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC;EACnB;EAGA,IAAW,aAAa,GAA+B;IACnD,OAAO,IAAI,CAAC,cAAc;EAC9B;EAQA,WAAmB,YAAY,GAA2B;IACtD,OAAO;MACH,mBAAmB,EAAE,KAAK;MAC1B,OAAO,EAAE,SAAS;MAElB,SAAS,EAAE,CAAC;MACZ,gBAAgB,EAAE,IAAI,GAAG,CAAC,CAAC;MAC3B,mBAAmB,EAAE,IAAI,GAAG,CAAC,CAAC;MAC9B,sBAAsB,EAAE,CAAC;MACzB,YAAY,EAAE;IAClB,CAAC;EACL;EAYA,IAAY,mBAAmB,GAAW;IACtC,OAAO,IAAI,CAAC,UAAU,EAAE,mBAAmB,IAAI,IAAK;EACxD;EACA,IAAY,uBAAuB,GAAW;IAC1C,OAAO,IAAI,CAAC,UAAU,EAAE,uBAAuB,IAAI,uBAAuB;EAC9E;EACA,IAAY,+BAA+B,GAAW;IAClD,OAAO,IAAI,CAAC,UAAU,EAAE,+BAA+B,IAAI,IAAK;EACpE;EACQ,yBAAyB,CAAC,SAAiB,EAAU;IACzD,OACI,IAAI,CAAC,KAAK,CAAC,SAAS,GACpB,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,uBAAuB,EAAE,6BAA6B,CAAC,GAAG,SAAS,GACjF,IAAI,CAAC,+BAA+B;EAE5C;EACA,IAAc,wBAAwB,GAAW;IAC7C,OAAO,IAAI,CAAC,gCAAgC,IAAI,IAAI,CAAC,UAAU,EAAE,wBAAwB,IAAI,IAAK;EACtG;EACA,IAAY,0BAA0B,GAAW;IAC7C,OAAO,IAAI,CAAC,UAAU,EAAE,0BAA0B,IAAI,IAAK;EAC/D;EACA,IAAY,0BAA0B,GAAW;IAC7C,OAAO,IAAI,CAAC,UAAU,EAAE,0BAA0B,IAAI,EAAE;EAC5D;EACA,IAAY,6BAA6B,GAAW;IAChD,OAAO,IAAI,CAAC,UAAU,EAAE,6BAA6B,IAAI,EAAE;EAC/D;EACA,IAAY,sCAAsC,GAAW;IACzD,OAAO,IAAI,CAAC,UAAU,EAAE,sCAAsC,IAAI,IAAI;EAC1E;;EAEA;EACA,MAAc,qBAAqB,CAAC,IAA0B,EAAyB;IACnF,QAAQ,IAAI;MACR,KAAK,oBAAoB,CAAC,gBAAgB;QAAE;UACxC;UACA,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE;YACrB,OAAO,IAAI,CAAC,6BAA6B,CAAC,CAAC,CAAC,CAAC;UACjD,CAAC,MAAM;YACH;YACA;YACA;YACA;YACA;YACA;;YAEA,OAAO,IAAI,CAAC,wCAAwC,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC;UAC5E;QACJ;MACA,KAAK,oBAAoB,CAAC,mBAAmB;QAAE;UAC3C,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE;YACrB;YACA,OAAO,wBAAwB,CAAC,oBAAoB,CAAC,gBAAgB,CAAC;UAC1E;UACA,OAAO,IAAI,CAAC,mBAAmB,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC;QACvD;MACA,KAAK,oBAAoB,CAAC,8BAA8B;QAAE;UACtD;UACA,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,mBAAmB,EAAE;YACjC,OAAO;cAAE,OAAO,EAAE;YAAG,CAAC;UAC1B;UACA,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE;YACpB,OAAO,IAAI,CAAC,wDAAwD,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC;UAC5F,CAAC,MAAM;YACH,OAAO,wBAAwB,CAAC,oBAAoB,CAAC,cAAc,CAAC;UACxE;QACJ;MACA,KAAK,oBAAoB,CAAC,aAAa;QAAE;UACrC,OAAO,IAAI,CAAC,aAAa,CAAC,CAAC;QAC/B;MACA,KAAK,oBAAoB,CAAC,YAAY;QAAE;UACpC,OAAO,IAAI,CAAC,yBAAyB,CAAC,CAAC;QAC3C;MACA,KAAK,oBAAoB,CAAC,cAAc;QAAE;UACtC;UACA,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,mBAAmB,EAAE;YACjC,OAAO;cAAE,OAAO,EAAE;YAAG,CAAC;UAC1B;UACA;UACA;UACA,OAAO,IAAI,CAAC,sBAAsB,CAAC,CAAC;QACxC;IACJ;EACJ;EAYA;EACA,MAAc,6BAA6B,GAA0B;IACjE;IACA;IACA;IACA;IACA,OAAO,MAAM,IAAI,CAAC,qCAAqC,CAAC,CAAC,CACpD,IAAI,CAAE,QAAQ,IAAK;MAChB,IAAI,CAAC,KAAK,CAAC,0BAA0B,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,wBAAwB;MAClF,IAAI,CAAC,sBAAsB,CAAC,KAAK,CAAC;MAClC;MACA,IAAI,CAAC,qBAAqB,CAAC,oBAAoB,CAAC,gBAAgB,CAAC;MACjE,IAAI,CAAC,iBAAiB,CAAC,QAAQ,CAAC,QAAQ,CAAC;MACzC,IAAI,IAAI,CAAC,KAAK,CAAC,mBAAmB,EAAE;QAChC;QACA;QACA,OAAO,wBAAwB,CAC3B,oBAAoB,CAAC,mBAAmB,EACxC,IAAI,CAAC,0BACT,CAAC;MACL,CAAC,MAAM;QACH;QACA,OAAO,wBAAwB,CAAC,oBAAoB,CAAC,aAAa,CAAC;MACvE;IACJ,CAAC,CAAC,CACD,KAAK,CAAE,CAAC,IAAK;MACV,MAAM,gBAAgB,GAAG,oBAAoB,CAAC,gBAAgB;MAC9D,IAAI,IAAI,CAAC,+BAA+B,CAAC,CAAC,CAAC,EAAE;QACzC,OAAO,wBAAwB,CAAC,gBAAgB,CAAC;MACrD;MACA,MAAM,MAAM,GAAG,IAAI,CAAC,sBAAsB,CAAC,CAAC,EAAE,gBAAgB,EAAE,iCAAiC,CAAC;MAClG,IAAI,MAAM,EAAE,OAAO,MAAM;MAEzB,IAAI,IAAI,CAAC,KAAK,CAAC,mBAAmB,EAAE;QAChC;QACA;;QAEA;QACA,IAAI,IAAI,CAAC,4BAA4B,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;QACnD,MAAM,KAAK,CAAC,0EAA0E,GAAG,CAAC,CAAC;MAC/F,CAAC,MAAM;QACH;QACA;QACA,IAAI,IAAI,CAAC,4BAA4B,CAAC,CAAC,CAAC,EAAE;UACtC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,+DAA+D,CAAC;QACrF,CAAC,MAAM;UACH,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,mCAAmC,GAAG,CAAC,CAAC;QAC7D;QACA;QACA,OAAO,wBAAwB,CAAC,oBAAoB,CAAC,aAAa,CAAC;MACvE;IACJ,CAAC,CAAC;EACV;EAEA,MAAc,wCAAwC,CAAC,OAAe,EAAyB;IAC3F;IACA,OAAO,MAAM,IAAI,CAAC,MAAM,CACnB,qCAAqC,CAAC,OAAO,CAAC,CAC9C,IAAI,CAAC,MAAM;MACR,IAAI,CAAC,iBAAiB,CAAC,SAAS,CAAC;MACjC,IAAI,CAAC,qBAAqB,CAAC,oBAAoB,CAAC,gBAAgB,CAAC;MACjE,OAAO,yBAAyB,CAAC,oBAAoB,CAAC,gBAAgB,CAAC;IAC3E,CAAC,CAAC,CACD,KAAK,CAAE,CAAC,IAAK;MACV,MAAM,gBAAgB,GAAG,oBAAoB,CAAC,gBAAgB;MAC9D,MAAM,MAAM,GAAG,IAAI,CAAC,sBAAsB,CAAC,CAAC,EAAE,gBAAgB,EAAE,6BAA6B,CAAC;MAC9F,IAAI,MAAM,EAAE,OAAO,MAAM;MAEzB,IAAI,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,EAAE;QACzB;QACA;QACA,IAAI,CAAC,iBAAiB,CAAC,SAAS,CAAC;QACjC,OAAO,yBAAyB,CAAC,gBAAgB,CAAC;MACtD;MACA,IAAI,IAAI,CAAC,4BAA4B,CAAC,CAAC,CAAC,EAAE;QACtC,OAAO,yBAAyB,CAAC,oBAAoB,CAAC,aAAa,CAAC;MACxE;MACA;;MAEA;MACA;MACA;MACA;MACA,MAAM,KAAK,CACP,kHACJ,CAAC;IACL,CAAC,CAAC;EACV;EAEQ,sBAAsB,CAAC,YAAqB,EAAQ;IACxD,IAAI,IAAI,CAAC,KAAK,CAAC,YAAY,KAAK,YAAY,EAAE;MAC1C;IACJ;IACA,IAAI,CAAC,KAAK,CAAC,YAAY,GAAG,YAAY;IACtC,IAAI,CAAC,IAAI,CAAC,sBAAsB,CAAC,YAAY,EAAE,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC;EAC3E;EAEQ,iBAAiB,CAAC,OAA2B,EAAQ;IACzD,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,KAAK,OAAO,EAAE;IAEpC,IAAI,CAAC,KAAK,CAAC,OAAO,GAAG,OAAO;IAC5B,IAAI,CAAC,IAAI,CAAC,sBAAsB,CAAC,cAAc,EAAE,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC;EACxE;EAEA,MAAc,mBAAmB,CAAC,OAAe,EAAyB;IACtE;IACA,MAAM,+BAA+B,GAAG,IAAI,CAAC,KAAK,CAAC,0BAA0B,GACvE,IAAI,CAAC,KAAK,CAAC,0BAA0B,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,GAClD,SAAS;IACf,MAAM,YAAY,GAAG,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,MAAM,KAAK;MAC5C,UAAU,CACN,MAAM;QACF,MAAM,CAAC,IAAI,UAAU,CAAC,yDAAyD,CAAC,CAAC;MACrF,CAAC;MACD;MACA;MACA;MACA;MACA,+BAA+B,KAAK,SAAS,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,YAAY,GACnE,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,sCAAsC,EAAE,+BAA+B,CAAC,GACtF,IAAI,CAAC,sCACf,CAAC;IACL,CAAC,CAAC;;IAEF;IACA;IACA,OAAO,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,sCAAsC,CAAC,OAAO,CAAC,EAAE,YAAY,CAAC,CAAC,CACjG,IAAI,CAAC,MAAM;MACR;MACA;MACA;MACA,IAAI,CAAC,KAAK,CAAC,0BAA0B,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,wBAAwB;MAClF,IAAI,CAAC,qBAAqB,CAAC,oBAAoB,CAAC,mBAAmB,CAAC;MACpE,IAAI,CAAC,sBAAsB,CAAC,KAAK,CAAC;MAClC,OAAO,wBAAwB,CAC3B,oBAAoB,CAAC,mBAAmB,EACxC,IAAI,CAAC,0BACT,CAAC;IACL,CAAC,CAAC,CACD,KAAK,CAAE,CAAC,IAAK;MACV,IAAI,IAAI,CAAC,KAAK,CAAC,0BAA0B,IAAI,IAAI,CAAC,KAAK,CAAC,0BAA0B,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE;QAC9F;QACA;QACA,IAAI,CAAC,sBAAsB,CAAC,IAAI,CAAC;MACrC;MACA,MAAM,gBAAgB,GAAG,oBAAoB,CAAC,mBAAmB;MACjE,IAAI,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,EAAE;QACzB,IAAI,CAAC,iBAAiB,CAAC,SAAS,CAAC;QACjC,OAAO,wBAAwB,CAAC,oBAAoB,CAAC,gBAAgB,CAAC;MAC1E;MACA;MACA,IAAI,IAAI,CAAC,4BAA4B,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;;MAEnD;MACA,MAAM,MAAM,GAAG,IAAI,CAAC,sBAAsB,CAAC,CAAC,EAAE,gBAAgB,EAAE,8BAA8B,CAAC;MAC/F,IAAI,MAAM,EAAE,OAAO,MAAM;;MAEzB;MACA,MAAM,KAAK,CAAC,6EAA6E,GAAG,CAAC,CAAC;IAClG,CAAC,CAAC;EACV;EAEA,MAAc,wDAAwD,CAAC,OAAe,EAAyB;IAC3G,OAAO,MAAM,IAAI,CAAC,MAAM,CACnB,mCAAmC,CAAC,OAAO,CAAC,CAC5C,IAAI,CAAC,MAAM;MACR,IAAI,CAAC,KAAK,CAAC,mBAAmB,GAAG,KAAK;MACtC,IAAI,CAAC,iBAAiB,CAAC,SAAS,CAAC;MACjC,IAAI,CAAC,qBAAqB,CAAC,oBAAoB,CAAC,8BAA8B,CAAC;MAE/E,OAAO;QAAE,OAAO,EAAE;MAAG,CAAC;IAC1B,CAAC,CAAC,CACD,KAAK,CAAE,CAAC,IAAK;MACV,MAAM,gBAAgB,GAAG,oBAAoB,CAAC,cAAc;MAC5D,IAAI,IAAI,CAAC,4BAA4B,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;MACnD,IAAI,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,EAAE;QACzB,IAAI,CAAC,iBAAiB,CAAC,SAAS,CAAC;QACjC,OAAO,wBAAwB,CAAC,gBAAgB,CAAC;MACrD;MACA,MAAM,MAAM,GAAG,IAAI,CAAC,sBAAsB,CAAC,CAAC,EAAE,gBAAgB,EAAE,2BAA2B,CAAC;MAC5F,IAAI,MAAM,EAAE,OAAO,MAAM;;MAEzB;MACA,IAAI,CAAC,MAAM,CAAC,IAAI,CACZ,oGAAoG,EACpG,CACJ,CAAC;MACD,OAAO,wBAAwB,CAAC,gBAAgB,CAAC;IACrD,CAAC,CAAC;EACV;EAaA,MAAc,aAAa,GAA0B;IACjD,OAAO,MAAM,IAAI,CAAC,oBAAoB,CAAC,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAC,CACtF,IAAI,CAAC,MAAM;MACR,IAAI,CAAC,sBAAsB,CAAC,KAAK,CAAC;MAClC,IAAI,CAAC,KAAK,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC;MACjC;MACA,IAAI,CAAC,KAAK,CAAC,sBAAsB,GAAG,CAAC;MACrC,IAAI,CAAC,KAAK,CAAC,mBAAmB,GAAG,IAAI;MACrC,IAAI,CAAC,qBAAqB,CAAC,oBAAoB,CAAC,aAAa,CAAC;MAC9D;MACA;MACA;MACA;MACA;MACA;MACA,MAAM,0BAA0B,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,MAAM,CAC3D,CAAC,IACE,CAAC,CAAC,IAAI,KAAK,oBAAoB,CAAC,YAAY;MAAI;MAChD,CAAC,CAAC,IAAI,KAAK,oBAAoB,CAAC,aAAa,CAAE;MACvD,CAAC;MACD,OAAO;QACH,OAAO,EAAE,CACL,GAAG,0BAA0B;QAC7B;QACA;UAAE,EAAE,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC;UAAE,IAAI,EAAE,oBAAoB,CAAC;QAAoB,CAAC,EAClE;UACI,EAAE,EAAE,IAAI,CAAC,yBAAyB,CAAC,IAAI,CAAC,KAAK,CAAC,sBAAsB,CAAC;UACrE,IAAI,EAAE,oBAAoB,CAAC;QAC/B,CAAC;MAET,CAAC;IACL,CAAC,CAAC,CACD,KAAK,CAAE,CAAC,IAAK;MACV,MAAM,MAAM,GAAG,IAAI,CAAC,sBAAsB,CAAC,CAAC,EAAE,oBAAoB,CAAC,aAAa,EAAE,gBAAgB,CAAC;MACnG,IAAI,MAAM,EAAE,OAAO,MAAM;MACzB,MAAM,CAAC;IACX,CAAC,CAAC;EACV;EAEA,MAAc,yBAAyB,GAA0B;IAC7D,MAAM,yBAAyB,GAAG,IAAI,CAAC,KAAK,CAAC,sBAAsB,GAAG,CAAC;IACvE,OAAO,MAAM,IAAI,CAAC,oBAAoB,CAClC,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,uBAAuB,GAAG,yBAAyB,CAClF,CAAC,CACI,IAAI,CAAC,MAAM;MACR;MACA,IAAI,CAAC,qBAAqB,CAAC,oBAAoB,CAAC,YAAY,CAAC;MAC7D,IAAI,CAAC,KAAK,CAAC,sBAAsB,GAAG,yBAAyB;MAC7D,OAAO;QACH,MAAM,EAAE,CACJ;UACI,EAAE,EAAE,IAAI,CAAC,yBAAyB,CAAC,yBAAyB,CAAC;UAC7D,IAAI,EAAE,oBAAoB,CAAC;QAC/B,CAAC;MAET,CAAC;IACL,CAAC,CAAC,CACD,KAAK,CAAE,CAAC,IAAK;MACV,MAAM,MAAM,GAAG,IAAI,CAAC,sBAAsB,CAAC,CAAC,EAAE,oBAAoB,CAAC,YAAY,EAAE,gBAAgB,CAAC;MAClG,IAAI,MAAM,EAAE,OAAO,MAAM;MAEzB,MAAM,CAAC;IACX,CAAC,CAAC;EACV;EACA,MAAc,sBAAsB,GAA0B;IAC1D,OAAO,MAAM,IAAI,CAAC,oBAAoB,CAAC,CAAC,CAAC,CAAC,CACrC,IAAI,CAAC,MAAM;MACR,IAAI,CAAC,qBAAqB,CAAC,oBAAoB,CAAC,cAAc,CAAC;MAC/D,IAAI,CAAC,KAAK,CAAC,mBAAmB,GAAG,KAAK;MACtC,OAAO;QAAE,OAAO,EAAE;MAAG,CAAC;IAC1B,CAAC,CAAC,CACD,KAAK,CAAE,CAAC,IAAK;MACV,MAAM,MAAM,GAAG,IAAI,CAAC,sBAAsB,CAAC,CAAC,EAAE,oBAAoB,CAAC,cAAc,EAAE,gBAAgB,CAAC;MACpG,IAAI,MAAM,EAAE,OAAO,MAAM;MACzB,MAAM,CAAC;IACX,CAAC,CAAC;EACV;;EAEA;EACA;AACJ;AACA;AACA;EACY,sBAAsB,CAAC,WAAmB,EAAE,aAAqB,EAAU;IAC/E;IACA;IACA,MAAM,WAAW,GAAG,IAAI,CAAC,eAAe,CAAC,WAAW;IACpD,MAAM,uBAAuB,GAAG,WAAW,KAAK,QAAQ,IAAI,IAAI,CAAC,eAAe,CAAC,EAAE,KAAK,MAAM;IAC9F,MAAM,MAAM,GAAG,uBAAuB,GAAG,EAAE,GAAG,IAAI,CAAC,eAAe,CAAC,EAAE;IACrE,MAAM,QAAQ,GAAG,GAAG,WAAW,IAAI,aAAa,IAAI,WAAW,GAAG,MAAM,EAAE;IAC1E,IAAI,gCAAgC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE;MAC/D,OAAO,QAAQ;IACnB,CAAC,MAAM;MACH,OAAO,IAAI,QAAQ,EAAE;IACzB;EACJ;;EAEA;AACJ;AACA;AACA;EACc,gBAAgB,CAAC,OAAe,EAA6C;IACnF,MAAM,aAAa,GAAG,IAAI,CAAC,aAAa;IACxC,MAAM,uBAAuB,GACzB,IAAI,CAAC,eAAe,CAAC,WAAW,KAAK,QAAQ,IAAI,IAAI,CAAC,eAAe,CAAC,EAAE,KAAK,MAAM;IAEvF,MAAM,YAA4E,GAC9E,IAAI,CAAC,YAAY,KAAK,SAAS,GACzB;MACI,YAAY,EAAE;QAAE,IAAI,EAAE,SAAS;QAAE,eAAe,EAAE;MAAoB,CAAU;MAChF,cAAc,EAAE,IAAI,CAAC,aAAa,IAAI;IAC1C,CAAC,GACD;MACI,YAAY,EAAE;QAAE,IAAI,EAAE,SAAS;QAAE,eAAe,EAAE;MAAY,CAAU;MACxE,cAAc,EAAE,CAAC,IAAI,CAAC,YAAY,EAAE,IAAI,IAAI,CAAC,aAAa,IAAI,EAAE,CAAC;IACrE,CAAC;IACX;MACI,aAAa,EAAE,IAAI,CAAC,eAAe,CAAC,WAAW;MAC/C;MACA;MACA,SAAS,EAAE,uBAAuB,GAAG,EAAE,GAAG,IAAI,CAAC,eAAe,CAAC,EAAE;MACjE,OAAO,EAAE,QAAQ;MACjB,WAAW,EAAE,IAAI,CAAC,QAAQ;MAC1B;MACA;MACA;MACA,cAAc,EAAE,GAAG,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,QAAQ,EAAE;MACjD,OAAO;MACP,eAAe,EAAE,IAAI,CAAC;IAAU,GAC7B,YAAY,GACX,aAAa,KAAK,SAAS,GAAG;MAAE,UAAU,EAAE,aAAa,CAAC,SAAS,CAAC;IAAE,CAAC,GAAG,SAAS;EAE/F;;EAEA;;EAEA;AACJ;AACA;AACA;AACA;EACY,eAAe,CAAC,KAAc,EAAW;IAC7C,OAAO,KAAK,YAAY,WAAW,IAAI,KAAK,CAAC,OAAO,KAAK,aAAa;EAC1E;;EAEA;AACJ;AACA;AACA;AACA;EACY,+BAA+B,CAAC,KAAc,EAAW;IAC7D,IACI,KAAK,YAAY,WAAW,IAC5B,KAAK,CAAC,OAAO,KAAK,WAAW,IAC7B,KAAK,CAAC,IAAI,CAAC,4BAA4B,CAAC,KAAK,sBAAsB,EACrE;MACE,MAAM,eAAe,GAAG,KAAK,CAAC,IAAI,CAAC,8BAA8B,CAAC;MAClE,IAAI,OAAO,eAAe,KAAK,QAAQ,IAAI,IAAI,CAAC,wBAAwB,GAAG,eAAe,EAAE;QACxF,IAAI,CAAC,gCAAgC,GAAG,eAAe;MAC3D;MACA,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,8EAA8E,EAAE,KAAK,CAAC;MACvG,OAAO,IAAI;IACf;IACA,OAAO,KAAK;EAChB;EAEU,sBAAsB,CAC5B,KAAc,EACd,IAA0B,EAC1B,MAAc,EACU;IACxB,MAAM,WAAW,GAAG,IAAI,CAAC,8BAA8B,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC;IAC5E,IAAI,WAAW,EAAE,OAAO,WAAW;IACnC,MAAM,aAAa,GAAG,IAAI,CAAC,iCAAiC,CAAC,KAAK,EAAE,IAAI,CAAC;IACzE,IAAI,aAAa,EAAE,OAAO,aAAa;EAC3C;EACA;AACJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;EACY,8BAA8B,CAClC,KAAc,EACd,MAAc,EACd,IAA0B,EACF;IACxB;IACA,IAAI,EAAE,CAAC,KAAK,YAAY,SAAS,IAAI,KAAK,YAAY,WAAW,KAAK,KAAK,CAAC,gBAAgB,CAAC,CAAC,CAAC,EAAE;MAC7F,OAAO,SAAS;IACpB;;IAEA;IACA,MAAM,gBAAgB,GAAG,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC;IACnE,IAAI,gBAAgB,GAAG,IAAI,CAAC,0BAA0B,EAAE;MACpD,IAAI,WAAmB;MACvB,MAAM,SAAS,GAAG,IAAI;MACtB,IAAI;QACA,WAAW,GAAG,KAAK,CAAC,eAAe,CAAC,CAAC,IAAI,SAAS;QAClD,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,uCAAuC,WAAW,IAAI,CAAC;MAC5E,CAAC,CAAC,OAAO,CAAC,EAAE;QACR,IAAI,CAAC,MAAM,CAAC,IAAI,CACZ,oFAAoF,SAAS,EAAE,EAC/F,CACJ,CAAC;QACD,WAAW,GAAG,SAAS;MAC3B;MACA,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,GAAG,CAAC,IAAI,EAAE,gBAAgB,GAAG,CAAC,CAAC;MAC3D,OAAO,wBAAwB,CAAC,IAAI,EAAE,WAAW,CAAC;IACtD;IAEA,MAAM,KAAK,CAAC,+BAA+B,GAAG,IAAI,GAAG,oBAAoB,GAAG,MAAM,GAAG,GAAG,EAAE;MAAE,KAAK,EAAE;IAAM,CAAC,CAAC;EAC/G;;EAEA;AACJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;EACY,iCAAiC,CAAC,KAAc,EAAE,IAA0B,EAA4B;IAC5G;IACA,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,mBAAmB,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC;;IAE7D;IACA,MAAM,mBAAmB,GAAG,IAAI,CAAC,mBAAmB,GAAG,IAAI,GAAG,GAAG;IACjE,MAAM,kBAAkB,GAAG,GAAG,GAAG,OAAO,GAAG,GAAG,GAAG,IAAI,CAAC,6BAA6B,GAAG,GAAG;;IAEzF;IACA,MAAM,aAAa,GAAG,IAAI,CAAC,mBAAmB;IAE9C,IAAI,KAAK,YAAY,KAAK,IAAI,KAAK,CAAC,IAAI,KAAK,YAAY,EAAE;MACvD;MACA;MACA;MACA;MACA,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,kEAAkE,EAAE,KAAK,CAAC;MAC3F,OAAO,wBAAwB,CAAC,IAAI,EAAE,CAAC,CAAC;IAC5C,CAAC,MAAM,IAAI,KAAK,YAAY,KAAK,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,wBAAwB,CAAC,EAAE;MACnF;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA,IAAI,CAAC,MAAM,CAAC,IAAI,CACZ,kDAAkD,GAAG,mBAAmB,GAAG,GAAG,GAAG,kBAAkB,EACnG,KACJ,CAAC;IACL,CAAC,MAAM,IAAI,KAAK,YAAY,eAAe,EAAE;MACzC,IAAI,CAAC,MAAM,CAAC,IAAI,CACZ,4DAA4D,GACxD,mBAAmB,GACnB,GAAG,GACH,kBAAkB,EACtB,KACJ,CAAC;IACL,CAAC,MAAM,IACH,CAAC,KAAK,YAAY,SAAS,IAAI,KAAK,YAAY,WAAW,KAC3D,OAAO,KAAK,CAAC,UAAU,KAAK,QAAQ,IACpC,KAAK,CAAC,UAAU,IAAI,GAAG,IACvB,KAAK,CAAC,UAAU,GAAG,GAAG,EACxB;MACE,IAAI,CAAC,MAAM,CAAC,IAAI,CACZ,gDAAgD,GAAG,mBAAmB,GAAG,GAAG,GAAG,kBAAkB,EACjG,KACJ,CAAC;IACL,CAAC,MAAM;MACH,OAAO,SAAS;IACpB;;IAEA;IACA,IAAI,OAAO,GAAG,IAAI,CAAC,6BAA6B,EAAE;MAC9C,IAAI,CAAC,KAAK,CAAC,mBAAmB,CAAC,GAAG,CAAC,IAAI,EAAE,OAAO,GAAG,CAAC,CAAC;MACrD,OAAO,wBAAwB,CAAC,IAAI,EAAE,aAAa,CAAC;IACxD;;IAEA;IACA,MAAM,KAAK,CACP,mBAAmB,GAAG,IAAI,CAAC,6BAA6B,GAAG,sBAAsB,GAAI,KACzF,CAAC;EACL;;EAEA;AACJ;AACA;AACA;AACA;EACY,4BAA4B,CAAC,KAAc,EAAW;IAC1D,OAAO,KAAK,YAAY,qCAAqC;EACjE;EAEQ,qBAAqB,CAAC,IAA0B,EAAQ;IAC5D,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC;IACxC,IAAI,CAAC,KAAK,CAAC,mBAAmB,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC;EAC/C;EAEA,IAAW,MAAM,GAAW;IACxB,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO;IACtC,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE;MACtB,MAAM;QAAE;MAAK,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;MAC3B,QAAQ,IAAI;QACR,KAAK,oBAAoB,CAAC,gBAAgB;QAC1C,KAAK,oBAAoB,CAAC,aAAa;UACnC,OAAO,MAAM,CAAC,UAAU;QAC5B,KAAK,oBAAoB,CAAC,YAAY;UAAE;UACpC,OAAO,MAAM,CAAC,SAAS;QAC3B,KAAK,oBAAoB,CAAC,8BAA8B;QACxD,KAAK,oBAAoB,CAAC,cAAc;UACpC,OAAO,MAAM,CAAC,aAAa;QAC/B;QACA;MACJ;IACJ,CAAC,MAAM,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE;MAC7B,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAE,CAAC,IAAK,CAAC,CAAC,IAAI,CAAC;MACxC;MACA,IACI,CAAC,KAAK,CAAC,QAAQ,CAAC,oBAAoB,CAAC,mBAAmB,CAAC,IACpD,KAAK,CAAC,QAAQ,CAAC,oBAAoB,CAAC,gBAAgB,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,mBAAoB,KAC7F,KAAK,CAAC,QAAQ,CAAC,oBAAoB,CAAC,YAAY,CAAC,EACnD;QACE,OAAO,MAAM,CAAC,SAAS;MAC3B;IACJ,CAAC,MAAM,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE;MAC7B,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAE,CAAC,IAAK,CAAC,CAAC,IAAI,CAAC;MACxC;MACA;MACA,IACI,KAAK,CAAC,MAAM,CAAE,CAAC,IAAK,CAAC,KAAK,oBAAoB,CAAC,mBAAmB,CAAC,CAAC,MAAM,KAAK,CAAC,IAChF,KAAK,CAAC,QAAQ,CAAC,oBAAoB,CAAC,YAAY,CAAC,EACnD;QACE,OAAO,MAAM,CAAC,SAAS;MAC3B;IACJ;IAEA,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE;MACzB,OAAO,MAAM,CAAC,YAAY;IAC9B;IAEA,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,mDAAmD,EAAE,OAAO,CAAC;IAC/E,OAAO,MAAM,CAAC,OAAO;EACzB;EAEA,IAAW,YAAY,GAAY;IAC/B,OAAO,IAAI,CAAC,KAAK,CAAC,YAAY;EAClC;EACA,IAAW,OAAO,GAAuB;IACrC,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO;EAC7B;AACJ;;AAEA;AACA;AACA;AACA;AACA,OAAO,MAAM,4BAA4B,SAAS,iBAAiB,CAAC;EACzD,WAAW,CACd,UAA0D,EAC1D,IAA6D,EAC5C,gBACuE,EACxF,kBAAmC;EACnC;EACA;EACiB,QAAgB,EACjC,YAAqB,EACvB;IACE,KAAK,CAAC,UAAU,EAAE,IAAI,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,YAAY,CAAC;IAAC,+DAGW,MACvF,IAAI,CAAC,gBAAgB,CAAC,gCAAgC,CAClD,IAAI,CAAC,IAAI,CAAC,MAAM,EAChB,6BAA6B,EAC7B;MAAE,KAAK,EAAE,IAAI,CAAC;IAAyB,CAAC,EACxC,IAAI,EACJ,SAAS,CAAC,aAAa,EACvB;MAAE,kBAAkB,EAAE,IAAI,CAAC;IAAS,CACxC,CAAC;IAAA,8CAI+B,YAAY,IAAK;MACjD,OAAO,IAAI,CAAC,gBAAgB,CAAC,yBAAyB,CAClD,IAAI,CAAC,IAAI,CAAC,MAAM,EAChB,6BAA6B,EAC7B,IAAI,EACJ,SAAS,CAAC,aAAa,kCAClB,YAAY;QAAE,kBAAkB,EAAE,IAAI,CAAC;MAAQ,EACxD,CAAC;IACL,CAAC;IAAA,KA/BoB,gBACuE,GADvE,gBACuE;IAAA,KAIvE,QAAgB,GAAhB,QAAgB;EAIrC;EA4BU,sBAAsB,CAAC,CAAU,EAAE,CAAuB,EAAE,CAAS,EAA4B;IACvG,OAAO,KAAK,CAAC,sBAAsB,CAAC,CAAC,EAAE,CAAC,EAAE,4BAA4B,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,SAAS,CAAC;EACvG;;EAEA;AACJ;AACA;AACA;EACc,gBAAgB,GAAsB;IAC5C,MAAM,aAAa,GAAG,IAAI,CAAC,aAAa;IAExC,MAAM,gBAAgB,GAAG,wBAAwB,CAAC,IAAI,CAAC,YAAY,CAAC,GAAG,IAAI,CAAC,YAAY,GAAG,SAAS;IACpG,MAAM,cAAc,GAAG,aAAa,EAAE,OAAO,GACvC;MAAE,YAAY,EAAE;QAAE,QAAQ,EAAE,YAAY,CAAC,SAAS;QAAE,QAAQ,EAAE,aAAa,EAAE;MAAQ;IAAE,CAAC,GACxF,CAAC,CAAC;IACR;MACI,WAAW;QACP,IAAI,EAAE,IAAI,CAAC,eAAe,CAAC;MAAW,GAClC,IAAI,CAAC,UAAU,GAAG;QAAE,eAAe,EAAE,IAAI,CAAC;MAAW,CAAC,GAAG,CAAC,CAAC,CAClE;MACD,OAAO,EAAE,aAAa,CAAC,IAAI,CAAC,eAAe,CAAC;MAC5C,UAAU,EAAE;QACR;QACA;QACA,SAAS,EAAE,gBAAgB,GACrB,CAAC;UAAE,IAAI,EAAE,gBAAgB,CAAC,IAAI;UAAE,mBAAmB,EAAE,gBAAgB,CAAC;QAAoB,CAAC,CAAC,GAC5F,EAAE;QACR,aAAa,EAAE,CAAC,SAAS;MAC7B,CAAC;MACD,MAAM,EAAE;QAAE,SAAS,EAAE,IAAI,CAAC,QAAQ;QAAE,OAAO,EAAE,IAAI,CAAC,MAAM;QAAE,EAAE,EAAE,IAAI,CAAC;MAAS,CAAC;MAC7E,QAAQ,EAAE;IAAE,GACT,cAAc;EAEzB;AACJ;AAAC,gBA3EY,4BAA4B,aAqCZ,IAAI,GAAG,CAAC,CAC7B,CAAC,gBAAgB,EAAE,2BAA2B,CAAC,EAC/C,CAAC,uBAAuB,EAAE,kCAAkC,CAAC,CAChE,CAAC","ignoreList":[]}
1
+ {"version":3,"file":"MembershipManager.js","names":[],"sources":["../../src/matrixrtc/MembershipManager.ts"],"sourcesContent":["/*\nCopyright 2025-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*/\nimport { AbortError } from \"p-retry\";\n\nimport { EventType, RelationType } from \"../@types/event.ts\";\nimport { type ISendEventResponse, type SendDelayedEventResponse } from \"../@types/requests.ts\";\nimport { type EmptyObject } from \"../@types/common.ts\";\nimport type { MatrixClient } from \"../client.ts\";\nimport { ConnectionError, HTTPError, MatrixError } from \"../http-api/errors.ts\";\nimport { type Logger, logger as rootLogger } from \"../logger.ts\";\nimport { type Room } from \"../models/room.ts\";\nimport { type CallMembership, DEFAULT_EXPIRE_DURATION } from \"./CallMembership.ts\";\nimport { type Transport, isMyMembership, type RTCCallIntent, Status, type SlotDescription } from \"./types.ts\";\nimport { type MembershipConfig, type SessionConfig } from \"./MatrixRTCSession.ts\";\nimport { type Action, ActionScheduler, type ActionUpdate } from \"./MembershipManagerActionScheduler.ts\";\nimport { TypedEventEmitter } from \"../models/typed-event-emitter.ts\";\nimport { UnsupportedDelayedEventsEndpointError } from \"../errors.ts\";\nimport {\n MembershipManagerEvent,\n type IMembershipManager,\n type MembershipManagerEventHandlerMap,\n} from \"./IMembershipManager.ts\";\nimport { type RtcMembershipData, type SessionMembershipData } from \"./membershipData/index.ts\";\nimport { computeSlotId } from \"./utils.ts\";\nimport { deepCompare } from \"../utils.ts\";\nimport { isLivekitTransportConfig } from \"./LivekitTransport.ts\";\n\n/* MembershipActionTypes:\nOn Join: ───────────────────┐ ┌───────────────(1)───────────┐\n ▼ ▼ │\n ┌────────────────┐ │\n┌───────(6)───────────▶│SendDelayedEvent│ ──────(2)───┐ │\n│ └────────────────┘ │ │\n│ │(3) │ │\n│ ▼ │ │\n│ ┌─────────────┐ │ │\n│ ┌──────(4)───│SendJoinEvent│────(4)─────┐ │ │\n│ │ └─────────────┘ │ │ │\n│ │ ┌─────┐ ┌──────┐ │ │ │\n│ ▼ ▼ │ │ ▼ ▼ ▼ │\n│ ┌────────────┐ │ │ ┌───────────────────┐ │\n└───│UpdateExpiry│ (s) (s)|RestartDelayedEvent│ │\n └────────────┘ │ │ └───────────────────┘ │\n │ │ │ │ │ │\n └─────┘ └──────┘ └───────┘\n\nOn Leave: ───────── STOP ALL ABOVE\n ▼\n ┌────────────────────────────────┐\n │ SendScheduledDelayedLeaveEvent │\n └────────────────────────────────┘\n │(5)\n ▼\n ┌──────────────┐\n │SendLeaveEvent│\n └──────────────┘\n(1) [Not found error] results in resending the delayed event\n(2) [hasMemberEvent = true] Sending the delayed event if we\n already have a call member event results jumping to the\n RestartDelayedEvent loop directly\n(3) [hasMemberEvent = false] if there is not call member event\n sending it is the next step\n(4) Both (UpdateExpiry and RestartDelayedEvent) actions are\n scheduled when successfully sending the state event\n(5) Only if delayed event sending failed (fallback)\n(6) Before extending `expires` we make sure a delayed leave\n event will outlive the update. If it was only cancelled we\n schedule a new one and retry; if it already fired, or the\n membership expires while we retry, we join again from scratch\n(s) Successful restart/resend\n*/\n\n/**\n * Call membership should always remain sticky for this amount\n * of time.\n */\nconst MEMBERSHIP_STICKY_DURATION_MS = 60 * 60 * 1000; // 60 minutes\n\n/**\n * The different types of actions the MembershipManager can take.\n * @internal\n */\nexport enum MembershipActionType {\n SendDelayedEvent = \"SendDelayedEvent\",\n // -> MembershipActionType.SendJoinEvent if successful\n // -> DelayedLeaveActionType.SendDelayedEvent on error, retry sending the first delayed event.\n // -> DelayedLeaveActionType.RestartDelayedEvent on success start updating the delayed event\n\n SendJoinEvent = \"SendJoinEvent\",\n // -> MembershipActionType.SendJoinEvent if we run into a rate limit and need to retry\n // -> MembershipActionType.UpdateExpiry if we successfully send the join event then schedule the expire event update\n // -> DelayedLeaveActionType.RestartDelayedEvent to recheck the delayed event\n\n RestartDelayedEvent = \"RestartDelayedEvent\",\n // -> DelayedLeaveActionType.SendMainDelayedEvent on missing delay id but there is a rtc state event\n // -> DelayedLeaveActionType.SendDelayedEvent on missing delay id and there is no state event\n // -> DelayedLeaveActionType.RestartDelayedEvent on success we schedule the next restart\n\n UpdateExpiry = \"UpdateExpiry\",\n // -> MembershipActionType.UpdateExpiry if the timeout has passed so the next update is required, or if we first\n // have to wait for a delayed leave event that can protect the updated membership.\n // -> MembershipActionType.SendDelayedEvent if our delayed leave event is gone. Either to schedule a new one for\n // the membership we still have, or to join again from scratch because the server already removed us.\n\n SendScheduledDelayedLeaveEvent = \"SendScheduledDelayedLeaveEvent\",\n // -> MembershipActionType.SendLeaveEvent on failure (not found) we need to send the leave manually and cannot use the scheduled delayed event\n // -> DelayedLeaveActionType.SendScheduledDelayedLeaveEvent on error we try again.\n\n SendLeaveEvent = \"SendLeaveEvent\",\n // -> MembershipActionType.SendLeaveEvent\n}\n\n/**\n * @internal\n */\nexport interface MembershipManagerState {\n /** The delayId we got when successfully sending the delayed leave event.\n * Gets set to undefined if the server claims it cannot find the delayed event anymore. */\n delayId?: string;\n /** Stores how often we have update the `expires` field.\n * `expireUpdateIterations` * `membershipEventExpiryTimeout` resolves to the value the expires field should contain next */\n expireUpdateIterations: number;\n /** The time at which we send the first state event. The time the call started from the DAG point of view.\n * This is used to compute the local sleep timestamps when to next update the member event with a new expires value. */\n startTime: number;\n /** The manager is in the state where its actually connected to the session. */\n hasMemberStateEvent: boolean;\n // There can be multiple retries at once so we need to store counters per action\n // e.g. the send update membership and the restart delayed could be rate limited at the same time.\n /** Retry counter for rate limits */\n rateLimitRetries: Map<MembershipActionType, number>;\n /** Retry counter for other errors */\n networkErrorRetries: Map<MembershipActionType, number>;\n /** The time at which we expect the server to send the delayed leave event. */\n expectedServerDelayLeaveTs?: number;\n /** The time at which the membership we last sent stops being valid for other clients.\n * Recorded when sending, see `membershipExpiryTsOf`. */\n membershipExpiryTs: number;\n /** This is used to track if the client expects the scheduled delayed leave event to have\n * been sent because restarting failed during the available time.\n * Once we resend the delayed event or successfully restarted it will get unset. */\n probablyLeft: boolean;\n}\n\n/**\n * The outcome of a delayed leave event restart attempt.\n *\n * - `\"ok\"`: the server restarted it, it will fire `delayedLeaveEventDelayMs` from now.\n * - `\"gone\"`: the server does not know the delay id anymore. It either sent the event or lost/cancelled it.\n * - `\"unsupported\"`: the server does not support the delayed events endpoint.\n * - `{ error }`: any other failure, for the caller to turn into a retry or to rethrow.\n */\ntype RestartDelayedEventOutcome = \"ok\" | \"gone\" | \"unsupported\" | { error: unknown };\n\nfunction createInsertActionUpdate(type: MembershipActionType, offset?: number): ActionUpdate {\n return {\n insert: [{ ts: Date.now() + (offset ?? 0), type }],\n };\n}\n\nfunction createReplaceActionUpdate(type: MembershipActionType, offset?: number): ActionUpdate {\n return {\n replace: [{ ts: Date.now() + (offset ?? 0), type }],\n };\n}\n\ntype MembershipManagerClient = Pick<\n MatrixClient,\n | \"getUserId\"\n | \"getDeviceId\"\n | \"sendStateEvent\"\n | \"_unstable_sendDelayedStateEvent\"\n | \"_unstable_updateDelayedEvent\"\n | \"_unstable_cancelScheduledDelayedEvent\"\n | \"_unstable_restartScheduledDelayedEvent\"\n | \"_unstable_sendScheduledDelayedEvent\"\n>;\n\n/**\n * This class is responsible for sending all events relating to the own membership of a matrixRTC call.\n * It has the following tasks:\n * - Send the users leave delayed event before sending the membership\n * - Send the users membership if the state machine is started\n * - Check if the delayed event was canceled due to sending the membership\n * - update the delayed event (`restart`)\n * - Update the state event every ~5h = `DEFAULT_EXPIRE_DURATION` (so it does not get treated as expired)\n * - When the state machine is stopped:\n * - Disconnect the member\n * - Stop the timer for the delay refresh\n * - Stop the timer for updating the state event\n */\nexport class MembershipManager\n extends TypedEventEmitter<MembershipManagerEvent, MembershipManagerEventHandlerMap>\n implements IMembershipManager\n{\n private activated = false;\n private readonly logger: Logger;\n protected callIntent: RTCCallIntent | undefined;\n protected applicationData: Record<string, unknown> | undefined;\n\n public isActivated(): boolean {\n return this.activated;\n }\n // DEPRECATED use isActivated\n public isJoined(): boolean {\n return this.isActivated();\n }\n\n /**\n * Puts the MembershipManager in a state where it tries to be joined.\n * It will send delayed events and membership events\n * @param fociPreferred the list of preferred foci to use in the joined RTC membership event.\n * If multiSfuFocus is set, this is only needed if this client wants to publish to multiple transports simultaneously.\n * @param multiSfuFocus the active focus to use in the joined RTC membership event. Setting this implies the\n * membership manager will operate in a multi-SFU connection mode. If `undefined`, an `oldest_membership`\n * transport selection will be used instead.\n * @param onError This will be called once the membership manager encounters an unrecoverable error.\n * This should bubble up the the frontend to communicate that the call does not work in the current environment.\n * The original underlying error is preserved as `error.cause`, so consumers can `instanceof`-check the typed\n * cause.\n */\n public join(fociPreferred: Transport[], multiSfuFocus?: Transport, onError?: (error: unknown) => void): void {\n if (this.scheduler.running) {\n this.logger.error(\"MembershipManager is already running. Ignoring join request.\");\n return;\n }\n this.fociPreferred = fociPreferred;\n this.rtcTransport = multiSfuFocus;\n this.leavePromiseResolvers = undefined;\n this.activated = true;\n this.oldStatus = this.status;\n this.state = MembershipManager.defaultState;\n\n this.scheduler\n .startWithJoin()\n .catch((e) => {\n this.logger.error(\"MembershipManager stopped because: \", e);\n onError?.(e);\n })\n .finally(() => {\n // Should already be set to false when calling `leave` in non error cases.\n this.activated = false;\n // Here the scheduler is not running anymore so we the `membershipLoopHandler` is not called to emit.\n if (this.oldStatus && this.oldStatus !== this.status) {\n this.emit(MembershipManagerEvent.StatusChanged, this.oldStatus, this.status);\n }\n if (!this.scheduler.running) {\n this.leavePromiseResolvers?.resolve(true);\n this.leavePromiseResolvers = undefined;\n }\n });\n }\n\n /**\n * Leave from the call (Send an rtc session event with content: `{}`)\n * @param timeout the maximum duration this promise will take to resolve\n * @returns true if it managed to leave and false if the timeout condition happened.\n */\n public leave(timeout?: number): Promise<boolean> {\n if (!this.scheduler.running) {\n this.logger.warn(\"Called MembershipManager.leave() even though the MembershipManager is not running\");\n return Promise.resolve(true);\n }\n\n // We use the promise to track if we already scheduled a leave event\n // So we do not check scheduler.actions/scheduler.insertions\n if (!this.leavePromiseResolvers) {\n // reset scheduled actions so we will not do any new actions.\n this.leavePromiseResolvers = Promise.withResolvers<boolean>();\n this.activated = false;\n this.scheduler.initiateLeave();\n if (timeout) setTimeout(() => this.leavePromiseResolvers?.resolve(false), timeout);\n }\n return this.leavePromiseResolvers.promise;\n }\n\n private leavePromiseResolvers?: PromiseWithResolvers<boolean>;\n\n public onRTCSessionMemberUpdate(memberships: CallMembership[]): Promise<void> {\n if (!this.isActivated()) {\n return Promise.resolve();\n }\n\n this._ownMembership = memberships.find((m) => isMyMembership(m, this.userId, this.deviceId));\n\n if (!this._ownMembership) {\n // If one of these actions are scheduled or are getting inserted in the next iteration, we should already\n // take care of our missing membership.\n const sendingMembershipActions = [\n MembershipActionType.SendDelayedEvent,\n MembershipActionType.SendJoinEvent,\n ];\n this.logger.warn(\"Missing own membership: force re-join\");\n this.state.hasMemberStateEvent = false;\n\n if (this.scheduler.actions.some((a) => sendingMembershipActions.includes(a.type))) {\n this.logger.error(\n \"tried adding another `SendDelayedEvent` actions even though we already have one in the Queue\\nActionQueueOnMemberUpdate:\",\n this.scheduler.actions,\n );\n } else {\n // Only react to our own membership missing if we have not already scheduled sending a new membership DirectMembershipManagerAction.Join\n this.scheduler.initiateJoin();\n }\n }\n return Promise.resolve();\n }\n\n public async updateCallIntent(callIntent: RTCCallIntent): Promise<void> {\n if (!this.activated || !this.ownMembership) {\n throw Error(\"You cannot update your intent before joining the call\");\n }\n if (this.ownMembership.callIntent === callIntent) {\n return; // No-op\n }\n this.callIntent = callIntent;\n // Kick off a new membership event as a result.\n await this.sendJoinEvent();\n }\n\n public async updateApplicationData(applicationData: Record<string, unknown>): Promise<void> {\n if (!this.activated || !this.ownMembership) {\n throw Error(\"You cannot update your application data before joining the call\");\n }\n if (deepCompare(this.applicationData ?? {}, applicationData)) {\n return; // No-op\n }\n this.applicationData = applicationData;\n await this.sendJoinEvent();\n }\n\n /**\n * @throws if the client does not return user or device id.\n * @param joinConfig\n * @param room\n * @param client\n */\n public constructor(\n private readonly joinConfig: (SessionConfig & MembershipConfig) | undefined,\n protected readonly room: Pick<Room, \"roomId\" | \"getVersion\">,\n protected readonly client: MembershipManagerClient,\n public readonly slotDescription: SlotDescription,\n parentLogger?: Logger,\n ) {\n super();\n this.logger = (parentLogger ?? rootLogger).getChild(`[MembershipManager]`);\n const [userId, deviceId] = [this.client.getUserId(), this.client.getDeviceId()];\n if (userId === null) throw Error(\"Missing userId in client\");\n if (deviceId === null) throw Error(\"Missing deviceId in client\");\n this.deviceId = deviceId;\n this.userId = userId;\n // this needs to become a uuid so that consecutive join/leaves result in a key rotation.\n // we keep it as a string for now for backwards compatibility.\n this.stateKey = this.makeMembershipStateKey(userId, deviceId);\n this.state = MembershipManager.defaultState;\n this.callIntent = joinConfig?.callIntent;\n this.applicationData = joinConfig?.applicationData;\n this.scheduler = new ActionScheduler((type): Promise<ActionUpdate> => {\n if (this.oldStatus) {\n // we put this at the beginning of the actions scheduler loop handle callback since it is a loop this\n // is equivalent to running it at the end of the loop. (just after applying the status/action list changes)\n // This order is required because this method needs to return the action updates.\n this.logger.debug(\n `MembershipManager applied action changes. Status: ${this.oldStatus} -> ${this.status}`,\n );\n if (this.oldStatus !== this.status) {\n this.emit(MembershipManagerEvent.StatusChanged, this.oldStatus, this.status);\n }\n }\n this.oldStatus = this.status;\n this.logger.debug(`MembershipManager before processing action. status=${this.oldStatus}`);\n return this.membershipLoopHandler(type);\n }, this.logger);\n }\n\n private _ownMembership?: CallMembership;\n public get ownMembership(): CallMembership | undefined {\n return this._ownMembership;\n }\n\n // scheduler\n private oldStatus?: Status;\n private scheduler: ActionScheduler;\n\n // MembershipManager mutable state.\n private state: MembershipManagerState;\n private static get defaultState(): MembershipManagerState {\n return {\n hasMemberStateEvent: false,\n delayId: undefined,\n\n startTime: 0,\n membershipExpiryTs: 0,\n rateLimitRetries: new Map(),\n networkErrorRetries: new Map(),\n expireUpdateIterations: 1,\n probablyLeft: false,\n };\n }\n // Membership Event static parameters:\n protected deviceId: string;\n protected userId: string;\n protected stateKey: string;\n protected rtcTransport?: Transport;\n /** @deprecated This will be removed in favor or rtcTransport becoming a list of actively used transports */\n private fociPreferred?: Transport[];\n\n // Config:\n private delayedLeaveEventDelayMsOverride?: number;\n\n private get networkErrorRetryMs(): number {\n return this.joinConfig?.networkErrorRetryMs ?? 3_000;\n }\n private get membershipEventExpiryMs(): number {\n return this.joinConfig?.membershipEventExpiryMs ?? DEFAULT_EXPIRE_DURATION;\n }\n private get membershipEventExpiryHeadroomMs(): number {\n return this.joinConfig?.membershipEventExpiryHeadroomMs ?? 5_000;\n }\n private computeNextExpiryActionTs(iteration: number): number {\n return (\n this.state.startTime +\n Math.min(this.membershipEventExpiryMs, MEMBERSHIP_STICKY_DURATION_MS) * iteration -\n this.membershipEventExpiryHeadroomMs\n );\n }\n protected get delayedLeaveEventDelayMs(): number {\n return this.delayedLeaveEventDelayMsOverride ?? this.joinConfig?.delayedLeaveEventDelayMs ?? 8_000;\n }\n private get delayedLeaveEventRestartMs(): number {\n return this.joinConfig?.delayedLeaveEventRestartMs ?? 5_000;\n }\n private get maximumRateLimitRetryCount(): number {\n return this.joinConfig?.maximumRateLimitRetryCount ?? 10;\n }\n private get maximumNetworkErrorRetryCount(): number {\n return this.joinConfig?.maximumNetworkErrorRetryCount ?? 10;\n }\n private get delayedLeaveEventRestartLocalTimeoutMs(): number {\n return this.joinConfig?.delayedLeaveEventRestartLocalTimeoutMs ?? 2000;\n }\n\n // LOOP HANDLER:\n private async membershipLoopHandler(type: MembershipActionType): Promise<ActionUpdate> {\n switch (type) {\n case MembershipActionType.SendDelayedEvent: {\n // Before we start we check if we come from a state where we have a delay id.\n if (!this.state.delayId) {\n return this.sendOrResendDelayedLeaveEvent(); // Normal case without any previous delayed id.\n } else {\n // This can happen if someone else (or another client) removes our own membership event.\n // It will trigger `onRTCSessionMemberUpdate` queue `MembershipActionType.SendDelayedEvent`.\n // We might still have our delayed event from the previous participation and dependent on the server this might not\n // get removed automatically if the state changes. Hence, it would remove our membership unexpectedly shortly after the rejoin.\n //\n // In this block we will try to cancel this delayed event before setting up a new one.\n\n return this.cancelKnownDelayIdBeforeSendDelayedEvent(this.state.delayId);\n }\n }\n case MembershipActionType.RestartDelayedEvent: {\n if (!this.state.delayId) {\n // Delay id got reset. This action was used to check if the hs canceled the delayed event when the join state got sent.\n return createInsertActionUpdate(MembershipActionType.SendDelayedEvent);\n }\n return this.restartDelayedEvent(this.state.delayId);\n }\n case MembershipActionType.SendScheduledDelayedLeaveEvent: {\n // We are already good\n if (!this.state.hasMemberStateEvent) {\n return { replace: [] };\n }\n if (this.state.delayId) {\n return this.sendScheduledDelayedLeaveEventOrFallbackToSendLeaveEvent(this.state.delayId);\n } else {\n return createInsertActionUpdate(MembershipActionType.SendLeaveEvent);\n }\n }\n case MembershipActionType.SendJoinEvent: {\n return this.sendJoinEvent();\n }\n case MembershipActionType.UpdateExpiry: {\n return this.updateExpiryOnJoinedEvent();\n }\n case MembershipActionType.SendLeaveEvent: {\n // We are good already\n if (!this.state.hasMemberStateEvent) {\n return { replace: [] };\n }\n // This is only a fallback in case we do not have working delayed events support.\n // first we should try to just send the scheduled leave event\n return this.sendFallbackLeaveEvent();\n }\n }\n }\n\n // an abstraction to switch between sending state or a sticky event\n protected clientSendDelayedDisconnectMembership: () => Promise<SendDelayedEventResponse> = () =>\n this.client._unstable_sendDelayedStateEvent(\n this.room.roomId,\n { delay: this.delayedLeaveEventDelayMs },\n EventType.GroupCallMemberPrefix,\n {},\n this.stateKey,\n );\n\n // HANDLERS (used in the membershipLoopHandler)\n private async sendOrResendDelayedLeaveEvent(): Promise<ActionUpdate> {\n // We can reach this at the start of a call (where we do not yet have a membership: state.hasMemberStateEvent=false)\n // or during a call if the state event canceled our delayed event or caused by an unexpected error that removed our delayed event.\n // (Another client could have canceled it, the homeserver might have removed/lost it due to a restart, ...)\n // In the `then` and `catch` block we treat both cases differently. \"if (this.state.hasMemberStateEvent) {} else {}\"\n return await this.clientSendDelayedDisconnectMembership()\n .then((response) => {\n this.state.expectedServerDelayLeaveTs = Date.now() + this.delayedLeaveEventDelayMs;\n this.setAndEmitProbablyLeft(false);\n // On success we reset retries and set delayId.\n this.resetRateLimitCounter(MembershipActionType.SendDelayedEvent);\n this.setAndEmitDelayId(response.delay_id);\n if (this.state.hasMemberStateEvent) {\n // This action was scheduled because the previous delayed event was cancelled\n // due to lack of https://github.com/element-hq/synapse/pull/17810\n return createInsertActionUpdate(\n MembershipActionType.RestartDelayedEvent,\n this.delayedLeaveEventRestartMs,\n );\n } else {\n // This action was scheduled because we are in the process of joining\n return createInsertActionUpdate(MembershipActionType.SendJoinEvent);\n }\n })\n .catch((e) => {\n const repeatActionType = MembershipActionType.SendDelayedEvent;\n if (this.manageMaxDelayExceededSituation(e)) {\n return createInsertActionUpdate(repeatActionType);\n }\n const update = this.actionUpdateFromErrors(e, repeatActionType, \"_unstable_sendDelayedStateEvent\");\n if (update) return update;\n\n if (this.state.hasMemberStateEvent) {\n // This action was scheduled because the previous delayed event was cancelled\n // due to lack of https://github.com/element-hq/synapse/pull/17810\n\n // Don't do any other delayed event work if its not supported.\n if (this.isUnsupportedDelayedEndpoint(e)) return {};\n throw Error(\"Could not send delayed event, even though delayed events are supported. \" + e);\n } else {\n // This action was scheduled because we are in the process of joining\n // log and fall through\n if (this.isUnsupportedDelayedEndpoint(e)) {\n this.logger.info(\"Not using delayed event because the endpoint is not supported\");\n } else {\n this.logger.info(\"Not using delayed event because: \" + e);\n }\n // On any other error we fall back to not using delayed events and send the join state event immediately\n return createInsertActionUpdate(MembershipActionType.SendJoinEvent);\n }\n });\n }\n\n private async cancelKnownDelayIdBeforeSendDelayedEvent(delayId: string): Promise<ActionUpdate> {\n // Remove all running updates and restarts\n return await this.client\n ._unstable_cancelScheduledDelayedEvent(delayId)\n .then(() => {\n this.setAndEmitDelayId(undefined);\n this.resetRateLimitCounter(MembershipActionType.SendDelayedEvent);\n return createReplaceActionUpdate(MembershipActionType.SendDelayedEvent);\n })\n .catch((e) => {\n const repeatActionType = MembershipActionType.SendDelayedEvent;\n const update = this.actionUpdateFromErrors(e, repeatActionType, \"cancelScheduledDelayedEvent\");\n if (update) return update;\n\n if (this.isNotFoundError(e)) {\n // If we get a M_NOT_FOUND we know that the delayed event got already removed.\n // This means we are good and can set it to undefined and run this again.\n this.setAndEmitDelayId(undefined);\n return createReplaceActionUpdate(repeatActionType);\n }\n if (this.isUnsupportedDelayedEndpoint(e)) {\n return createReplaceActionUpdate(MembershipActionType.SendJoinEvent);\n }\n // We do not just ignore and log this error since we would also need to reset the delayId.\n\n // This becomes an unrecoverable error case since something is significantly off if we don't hit any of the above cases\n // when state.delayId !== undefined\n // We do not just ignore and log this error since we would also need to reset the delayId.\n // It is cleaner if we, the frontend, rejoins instead of resetting the delayId here and behaving like in the success case.\n throw Error(\n \"We failed to cancel a delayed event where we already had a delay id with an error we cannot automatically handle\",\n );\n });\n }\n\n private setAndEmitProbablyLeft(probablyLeft: boolean): void {\n if (this.state.probablyLeft === probablyLeft) {\n return;\n }\n this.state.probablyLeft = probablyLeft;\n this.emit(MembershipManagerEvent.ProbablyLeft, this.state.probablyLeft);\n }\n\n private setAndEmitDelayId(delayId: string | undefined): void {\n if (this.state.delayId === delayId) return;\n\n this.state.delayId = delayId;\n this.emit(MembershipManagerEvent.DelayIdChanged, this.state.delayId);\n }\n\n /**\n * Attempts to restart the delayed leave event and keeps everything that depends on it in sync.\n *\n * @param delayId the id of the delayed leave event to restart\n * @returns the outcome of the attempt.\n */\n private async tryRestartDelayedEvent(delayId: string): Promise<RestartDelayedEventOutcome> {\n // Compute the duration until we expect the server to send the delayed leave event.\n const durationUntilServerDelayedLeave = this.state.expectedServerDelayLeaveTs\n ? this.state.expectedServerDelayLeaveTs - Date.now()\n : undefined;\n const abortPromise = new Promise((_, reject) => {\n setTimeout(\n () => {\n reject(new AbortError(\"Restart delayed event timed out before the HS responded\"));\n },\n // We abort immediately at the time where we expect the server to send the delayed leave event.\n // At this point we want the catch block to run and set the `probablyLeft` state.\n //\n // While we are already in probablyLeft state, we use the unaltered delayedLeaveEventRestartLocalTimeoutMs.\n durationUntilServerDelayedLeave !== undefined && !this.state.probablyLeft\n ? Math.min(this.delayedLeaveEventRestartLocalTimeoutMs, durationUntilServerDelayedLeave)\n : this.delayedLeaveEventRestartLocalTimeoutMs,\n );\n });\n\n try {\n // The obvious choice here would be to use the `IRequestOpts` to set the timeout. Since this call might be forwarded\n // to the widget driver this information would get lost. That is why we mimic the AbortError using the race.\n await Promise.race([this.client._unstable_restartScheduledDelayedEvent(delayId), abortPromise]);\n } catch (e) {\n if (this.state.expectedServerDelayLeaveTs && this.state.expectedServerDelayLeaveTs <= Date.now()) {\n // Once we reach this point it's likely that the server is sending the delayed leave event so we emit `probablyLeft = true`.\n // It will emit `probablyLeft = false` once we notice about our leave through sync and successfully setup a new state event.\n this.setAndEmitProbablyLeft(true);\n }\n if (this.isNotFoundError(e)) {\n this.setAndEmitDelayId(undefined);\n return \"gone\";\n }\n if (this.isUnsupportedDelayedEndpoint(e)) {\n // There is nothing left that we could restart, cancel or send with this delay id, so we forget it\n // instead of making every later action try (and fail) to use it.\n this.setAndEmitDelayId(undefined);\n return \"unsupported\";\n }\n return { error: e };\n }\n\n // Whenever we successfully restart the delayed event we update the `state.expectedServerDelayLeaveTs`\n // which stores the predicted timestamp at which the server will send the delayed leave event if there wont be any further\n // successful restart requests.\n this.state.expectedServerDelayLeaveTs = Date.now() + this.delayedLeaveEventDelayMs;\n this.resetRateLimitCounter(MembershipActionType.RestartDelayedEvent);\n this.setAndEmitProbablyLeft(false);\n return \"ok\";\n }\n\n private async restartDelayedEvent(delayId: string): Promise<ActionUpdate> {\n const outcome = await this.tryRestartDelayedEvent(delayId);\n if (outcome === \"ok\") {\n return createInsertActionUpdate(MembershipActionType.RestartDelayedEvent, this.delayedLeaveEventRestartMs);\n }\n if (outcome === \"gone\") {\n return createInsertActionUpdate(MembershipActionType.SendDelayedEvent);\n }\n // If the HS does not support delayed events we won't reschedule.\n if (outcome === \"unsupported\") return {};\n\n // TODO this also needs a test: get rate limit while checking if delayed event is scheduled\n const update = this.actionUpdateFromErrors(\n outcome.error,\n MembershipActionType.RestartDelayedEvent,\n \"restartScheduledDelayedEvent\",\n );\n if (update) return update;\n\n // In other error cases we have no idea what is happening\n throw Error(\"Could not restart delayed event, even though delayed events are supported. \" + outcome.error);\n }\n\n private async sendScheduledDelayedLeaveEventOrFallbackToSendLeaveEvent(delayId: string): Promise<ActionUpdate> {\n return await this.client\n ._unstable_sendScheduledDelayedEvent(delayId)\n .then(() => {\n this.state.hasMemberStateEvent = false;\n this.setAndEmitDelayId(undefined);\n this.resetRateLimitCounter(MembershipActionType.SendScheduledDelayedLeaveEvent);\n\n return { replace: [] };\n })\n .catch((e) => {\n const repeatActionType = MembershipActionType.SendLeaveEvent;\n if (this.isUnsupportedDelayedEndpoint(e)) return {};\n if (this.isNotFoundError(e)) {\n this.setAndEmitDelayId(undefined);\n return createInsertActionUpdate(repeatActionType);\n }\n const update = this.actionUpdateFromErrors(e, repeatActionType, \"sendScheduledDelayedEvent\");\n if (update) return update;\n\n // On any other error we fall back to SendLeaveEvent (this includes hard errors from rate limiting)\n this.logger.warn(\n \"Encountered unexpected error during SendScheduledDelayedLeaveEvent. Falling back to SendLeaveEvent\",\n e,\n );\n return createInsertActionUpdate(repeatActionType);\n });\n }\n\n protected clientSendMembership: (\n myMembership: RtcMembershipData | SessionMembershipData | EmptyObject,\n ) => Promise<ISendEventResponse> = (myMembership) => {\n return this.client.sendStateEvent(\n this.room.roomId,\n EventType.GroupCallMemberPrefix,\n myMembership as EmptyObject | SessionMembershipData,\n this.stateKey,\n );\n };\n\n private async sendJoinEvent(): Promise<ActionUpdate> {\n const myMembership = this.makeMyMembership(this.membershipEventExpiryMs);\n return await this.clientSendMembership(myMembership)\n .then(() => {\n this.setAndEmitProbablyLeft(false);\n this.state.startTime = Date.now();\n this.state.membershipExpiryTs = this.membershipExpiryTsOf(myMembership);\n // The next update should already use twice the membershipEventExpiryTimeout\n this.state.expireUpdateIterations = 1;\n this.state.hasMemberStateEvent = true;\n this.resetRateLimitCounter(MembershipActionType.SendJoinEvent);\n // An UpdateExpiry action might be left over from a previous join event.\n // We can reach sendJoinEvent when the delayed leave event gets send by the HS.\n // The branch where we might have a leftover UpdateExpiry action is:\n // RestartDelayedEvent (cannot find it, server removed it)\n // -> SendDelayedEvent (send new delayed event)\n // -> SendJoinEvent (here with a still scheduled UpdateExpiry action)\n const actionsWithoutUpdateExpiry = this.scheduler.actions.filter(\n (a) =>\n a.type !== MembershipActionType.UpdateExpiry && // A new UpdateExpiry action with an updated will be scheduled,\n a.type !== MembershipActionType.SendJoinEvent, // Manually remove the SendJoinEvent action,\n );\n return {\n replace: [\n ...actionsWithoutUpdateExpiry,\n // To check if the delayed event is still there or got removed by inserting the stateEvent, we need to restart it.\n { ts: Date.now(), type: MembershipActionType.RestartDelayedEvent },\n {\n ts: this.computeNextExpiryActionTs(this.state.expireUpdateIterations),\n type: MembershipActionType.UpdateExpiry,\n },\n ],\n };\n })\n .catch((e) => {\n const update = this.actionUpdateFromErrors(e, MembershipActionType.SendJoinEvent, \"sendStateEvent\");\n if (update) return update;\n throw e;\n });\n }\n\n /**\n * The timestamp at which a membership we send stops being valid for other clients.\n *\n * State events are valid until `created_ts + expires`. `makeMyMembership` inherits `created_ts` from our previous\n * membership when we have one, otherwise the event's own timestamp counts.\n * @param sent the membership as we sent it\n */\n protected membershipExpiryTsOf(sent: SessionMembershipData | RtcMembershipData): number {\n const { created_ts: createdTs, expires } = sent as SessionMembershipData;\n return (createdTs ?? Date.now()) + (expires ?? DEFAULT_EXPIRE_DURATION);\n }\n\n /**\n * Gives up on our current membership and starts a fresh join.\n *\n * We forget our own membership so that the next state event does not inherit its `created_ts`. That would keep\n * the identity of the membership we are giving up while `expires` starts over from a single iteration, which can\n * put the absolute expiry in the past.\n * @param reason why we are not keeping the current membership. Only used for logging.\n */\n private rejoinFromScratch(reason: string): ActionUpdate {\n this.logger.warn(`Rejoining the session from scratch: ${reason}`);\n this.state.hasMemberStateEvent = false;\n this._ownMembership = undefined;\n return createReplaceActionUpdate(MembershipActionType.SendDelayedEvent);\n }\n\n /**\n * Schedules another attempt at the expiry update. Once our membership has expired we stop trying to keep it alive\n * and rejoin instead, so that we never end up silently expired.\n * @param delayMs how long to wait before trying again. Clamped so that we always get a last attempt at the moment\n * the membership expires, and never schedule one beyond it.\n * @param reason why we cannot update the expiry right now. Only used for logging.\n * @param resendDelayedEvent whether to schedule a replacement delayed leave event first, with the retry running\n * right after it.\n */\n private deferExpiryUpdate(\n delayMs: number,\n reason: string,\n { resendDelayedEvent = false }: { resendDelayedEvent?: boolean } = {},\n ): ActionUpdate {\n const remainingMs = this.state.membershipExpiryTs - Date.now();\n if (remainingMs <= 0) {\n return this.rejoinFromScratch(`${reason}, and the membership expired while we were trying`);\n }\n const retry: Action = {\n ts: Date.now() + Math.min(delayMs, remainingMs),\n type: MembershipActionType.UpdateExpiry,\n };\n if (!resendDelayedEvent) return { insert: [retry] };\n\n // Actions with the same timestamp run in insertion order, so the retry gets its turn after the replacement.\n //\n // The periodic `RestartDelayedEvent` that is still queued has to go, like `sendJoinEvent` does it: sending\n // the delayed event schedules the one restart loop we want, and a leftover one would either start a second\n // loop, or, while the replacement is still pending, queue a second `SendDelayedEvent` that cancels the\n // replacement and `replace`s the retry out of the queue.\n const otherActions = this.scheduler.actions.filter(\n (a) => a.type !== MembershipActionType.RestartDelayedEvent && a.type !== MembershipActionType.UpdateExpiry,\n );\n return { replace: [...otherActions, { ts: Date.now(), type: MembershipActionType.SendDelayedEvent }, retry] };\n }\n\n /**\n * Makes sure a delayed leave event is scheduled that will outlive the membership update we are about to send.\n *\n * Re-sending our membership is only safe while our delayed leave event is still scheduled: if the server has\n * already sent it (e.g. because the device was asleep and no restarts reached the server), the membership we\n * would send would come back to life without any delayed leave event to clean it up, and stay until `expires`\n * runs out. So we restart the delayed event first. A success guarantees it will outlive the membership update;\n * a 404 tells us it is gone, and we have to work out why.\n * @returns `undefined` if the membership can be sent, otherwise the action to take instead.\n */\n private async ensureDelayedLeaveEventProtectsMembership(): Promise<ActionUpdate | undefined> {\n if (!this.state.delayId) return this.waitForPendingDelayedLeaveEvent();\n\n const outcome = await this.tryRestartDelayedEvent(this.state.delayId);\n // `\"ok\"` and `\"unsupported\"` both let us go ahead: either the delayed leave event was just restarted, or\n // there is none that could have removed our membership in the first place.\n if (outcome === \"ok\" || outcome === \"unsupported\") return undefined;\n if (outcome === \"gone\") return this.recoverFromGoneDelayedLeaveEvent();\n return this.recoverFromFailedDelayedLeaveEventRestart(outcome.error);\n }\n\n /**\n * Without a delay id, a `SendDelayedEvent` action may be queued that has not succeeded yet. Then we wait for it\n * rather than put the membership back on the server with nothing to clean it up. The retry gets the same\n * timestamp, and actions with the same timestamp run in insertion order, so it runs right after that attempt:\n * straight away if the delayed event is there, or to wait for the next attempt if it rescheduled.\n *\n * Without such an action queued we are not using delayed events at all, because the homeserver does not support\n * them. Then there is also no delayed leave event that could have removed our membership, and nothing to protect\n * it from.\n * @returns `undefined` if the membership can be sent, otherwise the deferred expiry update.\n */\n private waitForPendingDelayedLeaveEvent(): ActionUpdate | undefined {\n const pending = this.scheduler.actions.find((a) => a.type === MembershipActionType.SendDelayedEvent);\n if (!pending) return undefined;\n return this.deferExpiryUpdate(Math.max(0, pending.ts - Date.now()), \"no delayed leave event is scheduled\");\n }\n\n /**\n * The server does not know our delayed leave event anymore. Whether it sent it or lost it decides whether we\n * still have a membership to extend.\n */\n private recoverFromGoneDelayedLeaveEvent(): ActionUpdate {\n if (this.state.expectedServerDelayLeaveTs !== undefined && this.state.expectedServerDelayLeaveTs > Date.now()) {\n // It is too early for the server to have sent the delayed leave event, so it must have been cancelled or\n // lost instead (e.g. by a homeserver lacking https://github.com/element-hq/synapse/pull/17810 when our\n // last state event landed). Our membership is still there and only needs a new delayed event, so we\n // schedule one and pick the expiry update back up right after it.\n return this.deferExpiryUpdate(0, \"the delayed leave event was cancelled or lost\", {\n resendDelayedEvent: true,\n });\n }\n // The delayed leave event has been sent, which also means our membership is gone.\n return this.rejoinFromScratch(\"the server already sent our delayed leave event\");\n }\n\n /**\n * Restarting our delayed leave event failed with something other than a 404.\n * @param error what the restart failed with\n * @returns `undefined` if the membership can be sent regardless, otherwise the action to take instead.\n * @throws the error if it is not one we retry on.\n */\n private recoverFromFailedDelayedLeaveEventRestart(error: unknown): ActionUpdate | undefined {\n // The retry budget belongs to the restart, but what we need to repeat is the expiry update.\n const update = this.actionUpdateFromErrors(\n error,\n MembershipActionType.RestartDelayedEvent,\n \"restartScheduledDelayedEvent\",\n );\n if (!update) throw error;\n\n // A transient failure does not mean the delayed leave event is not there. What we need for the update to be\n // safe is that it is still pending when the update lands, and `expectedServerDelayLeaveTs` tells us that:\n // while it is comfortably in the future, the restart was only a refresh we can do without, and the\n // `RestartDelayedEvent` loop will make up for it. Only a stale timestamp leaves us guessing.\n const durationUntilServerDelayedLeave = (this.state.expectedServerDelayLeaveTs ?? 0) - Date.now();\n if (durationUntilServerDelayedLeave > this.delayedLeaveEventRestartLocalTimeoutMs) {\n this.logger.warn(\n \"Could not restart the delayed leave event before extending `expires`, going ahead since it is still pending\",\n error,\n );\n return undefined;\n }\n const retryTs = \"insert\" in update ? update.insert[0].ts : Date.now();\n return this.deferExpiryUpdate(Math.max(0, retryTs - Date.now()), \"restarting the delayed leave event failed\");\n }\n\n private async updateExpiryOnJoinedEvent(): Promise<ActionUpdate> {\n const protection = await this.ensureDelayedLeaveEventProtectsMembership();\n if (protection) return protection;\n\n const nextExpireUpdateIteration = this.state.expireUpdateIterations + 1;\n const myMembership = this.makeMyMembership(this.membershipEventExpiryMs * nextExpireUpdateIteration);\n return await this.clientSendMembership(myMembership)\n .then(() => {\n // Success, we reset retries and schedule update.\n this.resetRateLimitCounter(MembershipActionType.UpdateExpiry);\n this.state.expireUpdateIterations = nextExpireUpdateIteration;\n this.state.membershipExpiryTs = this.membershipExpiryTsOf(myMembership);\n return {\n insert: [\n {\n ts: this.computeNextExpiryActionTs(nextExpireUpdateIteration),\n type: MembershipActionType.UpdateExpiry,\n },\n ],\n };\n })\n .catch((e) => {\n const update = this.actionUpdateFromErrors(e, MembershipActionType.UpdateExpiry, \"sendStateEvent\");\n if (update) return update;\n\n throw e;\n });\n }\n private async sendFallbackLeaveEvent(): Promise<ActionUpdate> {\n return await this.clientSendMembership({})\n .then(() => {\n this.resetRateLimitCounter(MembershipActionType.SendLeaveEvent);\n this.state.hasMemberStateEvent = false;\n return { replace: [] };\n })\n .catch((e) => {\n const update = this.actionUpdateFromErrors(e, MembershipActionType.SendLeaveEvent, \"sendStateEvent\");\n if (update) return update;\n throw e;\n });\n }\n\n // HELPERS\n /**\n * this creates `${localUserId}_${localDeviceId}_${this.slotDescription.application}${this.slotDescription.id}`\n * which is not compatible with membershipID of session type member events. They have to be `${localUserId}:${localDeviceId}`\n */\n private makeMembershipStateKey(localUserId: string, localDeviceId: string): string {\n // INFO_SLOT_ID_LEGACY_CASE (search for all occurances of this INFO to get the full picture)\n // Revert back to \"\" just for the state key (state keys are always legacy. we use sticky events for non legacy events)\n const application = this.slotDescription.application;\n const needsEmptyStringRoomFix = application === \"m.call\" && this.slotDescription.id === \"ROOM\";\n const slotId = needsEmptyStringRoomFix ? \"\" : this.slotDescription.id;\n const stateKey = `${localUserId}_${localDeviceId}_${application}${slotId}`;\n if (/^org\\.matrix\\.msc(3757|3779)\\b/.exec(this.room.getVersion())) {\n return stateKey;\n } else {\n return `_${stateKey}`;\n }\n }\n\n /**\n * Constructs our own membership\n * @returns Only returns `SessionMembershipData`\n */\n protected makeMyMembership(expires: number): SessionMembershipData | RtcMembershipData {\n const ownMembership = this.ownMembership;\n const needsEmptyStringRoomFix =\n this.slotDescription.application === \"m.call\" && this.slotDescription.id === \"ROOM\";\n\n const focusObjects: Pick<SessionMembershipData, \"foci_preferred\" | \"focus_active\"> =\n this.rtcTransport === undefined\n ? {\n focus_active: { type: \"livekit\", focus_selection: \"oldest_membership\" } as const,\n foci_preferred: this.fociPreferred ?? [],\n }\n : {\n focus_active: { type: \"livekit\", focus_selection: \"multi_sfu\" } as const,\n foci_preferred: [this.rtcTransport, ...(this.fociPreferred ?? [])],\n };\n return {\n // Legacy memberships have no application object, so the\n // application's data sits at the top level, under the fields\n // this manager owns\n ...this.applicationData,\n \"application\": this.slotDescription.application,\n // INFO_SLOT_ID_LEGACY_CASE (search for all occurances of this INFO to get the full picture)\n // Revert back to \"\" just for the sending the event.\n \"call_id\": needsEmptyStringRoomFix ? \"\" : this.slotDescription.id,\n \"scope\": \"m.room\",\n \"device_id\": this.deviceId,\n // DO NOT use this.memberId here since that is the state key (using application...)\n // But for session events we use the colon seperated userId and deviceId. The SFU will automatically\n // assign those values to the media participant for those versions.\n \"membershipID\": `${this.userId}:${this.deviceId}`,\n expires,\n \"m.call.intent\": this.callIntent,\n ...focusObjects,\n ...(ownMembership !== undefined ? { created_ts: ownMembership.createdTs() } : undefined),\n };\n }\n\n // Error checks and handlers\n\n /**\n * Check if its a NOT_FOUND error\n * @param error the error causing this handler check/execution\n * @returns true if its a not found error\n */\n private isNotFoundError(error: unknown): boolean {\n return error instanceof MatrixError && error.errcode === \"M_NOT_FOUND\";\n }\n\n /**\n * Check if this is a DelayExceeded timeout and update the TimeoutOverride for the next try\n * @param error the error causing this handler check/execution\n * @returns true if its a delay exceeded error and we updated the local TimeoutOverride\n */\n private manageMaxDelayExceededSituation(error: unknown): boolean {\n if (\n error instanceof MatrixError &&\n error.errcode === \"M_UNKNOWN\" &&\n error.data[\"org.matrix.msc4140.errcode\"] === \"M_MAX_DELAY_EXCEEDED\"\n ) {\n const maxDelayAllowed = error.data[\"org.matrix.msc4140.max_delay\"];\n if (typeof maxDelayAllowed === \"number\" && this.delayedLeaveEventDelayMs > maxDelayAllowed) {\n this.delayedLeaveEventDelayMsOverride = maxDelayAllowed;\n }\n this.logger.warn(\"Retry sending delayed disconnection event due to server timeout limitations:\", error);\n return true;\n }\n return false;\n }\n\n protected actionUpdateFromErrors(\n error: unknown,\n type: MembershipActionType,\n method: string,\n ): ActionUpdate | undefined {\n const updateLimit = this.actionUpdateFromRateLimitError(error, method, type);\n if (updateLimit) return updateLimit;\n const updateNetwork = this.actionUpdateFromNetworkErrorRetry(error, type);\n if (updateNetwork) return updateNetwork;\n }\n /**\n * Check if we have a rate limit error and schedule the same action again if we dont exceed the rate limit retry count yet.\n * @param error the error causing this handler check/execution\n * @param method the method used for the throw message\n * @param type which MembershipActionType we reschedule because of a rate limit.\n * @throws If it is a rate limit error and the retry count got exceeded\n * @returns Returns true if we handled the error by rescheduling the correct next action.\n * Returns false if it is not a network error.\n */\n private actionUpdateFromRateLimitError(\n error: unknown,\n method: string,\n type: MembershipActionType,\n ): ActionUpdate | undefined {\n // \"Is rate limit\"-boundary\n if (!((error instanceof HTTPError || error instanceof MatrixError) && error.isRateLimitError())) {\n return undefined;\n }\n\n // retry boundary\n const rateLimitRetries = this.state.rateLimitRetries.get(type) ?? 0;\n if (rateLimitRetries < this.maximumRateLimitRetryCount) {\n let resendDelay: number;\n const defaultMs = 5000;\n try {\n resendDelay = error.getRetryAfterMs() ?? defaultMs;\n this.logger.info(`Rate limited by server, retrying in ${resendDelay}ms`);\n } catch (e) {\n this.logger.warn(\n `Error while retrieving a rate-limit retry delay, retrying after default delay of ${defaultMs}`,\n e,\n );\n resendDelay = defaultMs;\n }\n this.state.rateLimitRetries.set(type, rateLimitRetries + 1);\n return createInsertActionUpdate(type, resendDelay);\n }\n\n throw Error(\"Exceeded maximum retries for \" + type + \" attempts (client.\" + method + \")\", { cause: error });\n }\n\n /**\n * FIXME Don't Check the error and retry the same MembershipAction again in the configured time and for the configured retry count.\n * @param error the error causing this handler check/execution\n * @param type the action type that we need to repeat because of the error\n * @throws If it is a network error and the retry count got exceeded\n * @returns\n * Returns true if we handled the error by rescheduling the correct next action.\n * Returns false if it is not a network error.\n */\n private actionUpdateFromNetworkErrorRetry(error: unknown, type: MembershipActionType): ActionUpdate | undefined {\n // \"Is a network error\"-boundary\n const retries = this.state.networkErrorRetries.get(type) ?? 0;\n\n // Strings for error logging\n const retryDurationString = this.networkErrorRetryMs / 1000 + \"s\";\n const retryCounterString = \"(\" + retries + \"/\" + this.maximumNetworkErrorRetryCount + \")\";\n\n // Variables for scheduling the new event\n const retryDuration = this.networkErrorRetryMs;\n\n if (error instanceof Error && error.name === \"AbortError\") {\n // A local timeout means the server accepted the request but is slow to answer. Retry immediately and\n // do not count it towards the fatal retry limit: the server's delayed leave already bounds how long a\n // stalled restart can go unnoticed, and the resulting forced re-join recovers the membership. Giving\n // up here would only replace a temporary media pause with a \"connection lost\" error for the user.\n this.logger.warn(\"Network local timeout error while sending event, immediate retry\", error);\n return createInsertActionUpdate(type, 0);\n } else if (error instanceof Error && error.message.includes(\"updating delayed event\")) {\n // TODO: We do not want error message matching here but instead the error should be a typed HTTPError\n // and be handled below automatically (the same as in the SPA case).\n //\n // The error originates because of https://github.com/matrix-org/matrix-widget-api/blob/5d81d4a26ff69e4bd3ddc79a884c9527999fb2f4/src/ClientWidgetApi.ts#L698-L701\n // uses `e` instance of HttpError (and not MatrixError)\n // The element web widget driver (only checks for MatrixError) is then failing to process (`processError`) it as a typed error: https://github.com/element-hq/element-web/blob/471712cbf06a067e5499bd5d2d7a75f693d9a12d/src/stores/widgets/StopGapWidgetDriver.ts#L711-L715\n // So it will not call: `error.asWidgetApiErrorData()` which is also missing for `HttpError`\n //\n // A proper fix would be to either find a place to convert the `HttpError` into a `MatrixError` and the `processError`\n // method to handle it as expected or to adjust `processError` to also process `HttpError`'s.\n this.logger.warn(\n \"delayed event update timeout error, retrying in \" + retryDurationString + \" \" + retryCounterString,\n error,\n );\n } else if (error instanceof ConnectionError) {\n this.logger.warn(\n \"Network connection error while sending event, retrying in \" +\n retryDurationString +\n \" \" +\n retryCounterString,\n error,\n );\n } else if (\n (error instanceof HTTPError || error instanceof MatrixError) &&\n typeof error.httpStatus === \"number\" &&\n error.httpStatus >= 500 &&\n error.httpStatus < 600\n ) {\n this.logger.warn(\n \"Server error while sending event, retrying in \" + retryDurationString + \" \" + retryCounterString,\n error,\n );\n } else {\n return undefined;\n }\n\n // retry boundary\n if (retries < this.maximumNetworkErrorRetryCount) {\n this.state.networkErrorRetries.set(type, retries + 1);\n return createInsertActionUpdate(type, retryDuration);\n }\n\n // Failure\n throw Error(\n \"Reached maximum (\" + this.maximumNetworkErrorRetryCount + \") retries cause by: \" + (error as Error),\n );\n }\n\n /**\n * Check if its an UnsupportedDelayedEventsEndpointError and which implies that we cannot do any delayed event logic\n * @param error The error to check\n * @returns true it its an UnsupportedDelayedEventsEndpointError\n */\n private isUnsupportedDelayedEndpoint(error: unknown): boolean {\n return error instanceof UnsupportedDelayedEventsEndpointError;\n }\n\n private resetRateLimitCounter(type: MembershipActionType): void {\n this.state.rateLimitRetries.set(type, 0);\n this.state.networkErrorRetries.set(type, 0);\n }\n\n public get status(): Status {\n const actions = this.scheduler.actions;\n if (actions.length === 1) {\n const { type } = actions[0];\n switch (type) {\n case MembershipActionType.SendDelayedEvent:\n case MembershipActionType.SendJoinEvent:\n return Status.Connecting;\n case MembershipActionType.UpdateExpiry: // where no delayed events\n return Status.Connected;\n case MembershipActionType.SendScheduledDelayedLeaveEvent:\n case MembershipActionType.SendLeaveEvent:\n return Status.Disconnecting;\n default:\n // pass through as not expected\n }\n } else if (actions.length === 2) {\n const types = actions.map((a) => a.type);\n // normal state for connected with delayed events\n if (\n (types.includes(MembershipActionType.RestartDelayedEvent) ||\n (types.includes(MembershipActionType.SendDelayedEvent) && this.state.hasMemberStateEvent)) &&\n types.includes(MembershipActionType.UpdateExpiry)\n ) {\n return Status.Connected;\n }\n } else if (actions.length === 3) {\n const types = actions.map((a) => a.type);\n // It is a correct connected state if we already schedule the next Restart but have not yet cleaned up\n // the current restart.\n if (\n types.filter((t) => t === MembershipActionType.RestartDelayedEvent).length === 2 &&\n types.includes(MembershipActionType.UpdateExpiry)\n ) {\n return Status.Connected;\n }\n }\n\n if (!this.scheduler.running) {\n return Status.Disconnected;\n }\n\n this.logger.error(\"MembershipManager has an unknown state. Actions: \", actions);\n return Status.Unknown;\n }\n\n public get probablyLeft(): boolean {\n return this.state.probablyLeft;\n }\n public get delayId(): string | undefined {\n return this.state.delayId;\n }\n}\n\n/**\n * Implementation of the Membership manager that uses sticky events\n * rather than state events.\n */\nexport class StickyEventMembershipManager extends MembershipManager {\n public constructor(\n joinConfig: (SessionConfig & MembershipConfig) | undefined,\n room: Pick<Room, \"getLiveTimeline\" | \"roomId\" | \"getVersion\">,\n private readonly clientWithSticky: MembershipManagerClient &\n Pick<MatrixClient, \"_unstable_sendStickyEvent\" | \"_unstable_sendStickyDelayedEvent\">,\n sessionDescription: SlotDescription,\n // this needs to become a uuid so that consecutive join/leaves result in a key rotation.\n // we keep it as a string for now for backwards compatibility.\n private readonly memberId: string,\n parentLogger?: Logger,\n ) {\n super(joinConfig, room, clientWithSticky, sessionDescription, parentLogger);\n }\n\n protected clientSendDelayedDisconnectMembership: () => Promise<SendDelayedEventResponse> = () =>\n this.clientWithSticky._unstable_sendStickyDelayedEvent(\n this.room.roomId,\n MEMBERSHIP_STICKY_DURATION_MS,\n { delay: this.delayedLeaveEventDelayMs },\n null,\n EventType.RTCMembership,\n { slot_id: computeSlotId(this.slotDescription), msc4354_sticky_key: this.memberId },\n );\n\n protected clientSendMembership: (\n myMembership: RtcMembershipData | SessionMembershipData | EmptyObject,\n ) => Promise<ISendEventResponse> = (myMembership) => {\n return this.clientWithSticky._unstable_sendStickyEvent(\n this.room.roomId,\n MEMBERSHIP_STICKY_DURATION_MS,\n null,\n EventType.RTCMembership,\n { slot_id: computeSlotId(this.slotDescription), ...myMembership, msc4354_sticky_key: this.memberId },\n );\n };\n\n private static nameMap = new Map([\n [\"sendStateEvent\", \"_unstable_sendStickyEvent\"],\n [\"sendDelayedStateEvent\", \"_unstable_sendStickyDelayedEvent\"],\n ]);\n protected actionUpdateFromErrors(e: unknown, t: MembershipActionType, m: string): ActionUpdate | undefined {\n return super.actionUpdateFromErrors(e, t, StickyEventMembershipManager.nameMap.get(m) ?? \"unknown\");\n }\n\n /** A sticky event vanishes `MEMBERSHIP_STICKY_DURATION_MS` after it was sent, whatever its content says. */\n protected membershipExpiryTsOf(): number {\n return Date.now() + MEMBERSHIP_STICKY_DURATION_MS;\n }\n\n /**\n *\n * @returns Only returns `RtcMembershipData`\n */\n protected makeMyMembership(): RtcMembershipData {\n const ownMembership = this.ownMembership;\n\n const livekitTransport = isLivekitTransportConfig(this.rtcTransport) ? this.rtcTransport : undefined;\n const relationObject = ownMembership?.eventId\n ? { \"m.relation\": { rel_type: RelationType.Reference, event_id: ownMembership?.eventId } }\n : {};\n return {\n application: {\n ...this.applicationData,\n type: this.slotDescription.application,\n ...(this.callIntent ? { \"m.call.intent\": this.callIntent } : {}),\n },\n slot_id: computeSlotId(this.slotDescription),\n transports: {\n // Make sure we do not add the alias to the transport.\n // It is not needed in matrix2.0. The additional session information will be used to find the right alias on the sfu.\n published: livekitTransport\n ? [{ type: livekitTransport.type, livekit_service_url: livekitTransport.livekit_service_url }]\n : [],\n can_subscribe: [\"livekit\"],\n },\n member: { device_id: this.deviceId, user_id: this.userId, id: this.memberId },\n versions: [],\n ...relationObject,\n };\n }\n}\n"],"mappings":"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","ignoreList":[]}
@@ -4,6 +4,6 @@ export * from "./MatrixRTCSession.ts";
4
4
  export * from "./MatrixRTCSessionManager.ts";
5
5
  export type * from "./types.ts";
6
6
  export { type SessionMembershipData, type RtcMembershipData } from "./membershipData/index.ts";
7
- export { Status, parseCallNotificationContent, isMyMembership, RTC_SLOT_ENCRYPTION_PER_MEMBER } from "./types.ts";
7
+ export { Status, parseCallNotificationContent, getCallNotificationExpiry, isMyMembership, RTC_SLOT_ENCRYPTION_PER_MEMBER, } from "./types.ts";
8
8
  export { MembershipManagerEvent } from "./IMembershipManager.ts";
9
9
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/matrixrtc/index.ts"],"names":[],"mappings":"AAgBA,cAAc,qBAAqB,CAAC;AACpC,cAAc,uBAAuB,CAAC;AACtC,cAAc,uBAAuB,CAAC;AACtC,cAAc,8BAA8B,CAAC;AAC7C,mBAAmB,YAAY,CAAC;AAChC,OAAO,EAAE,KAAK,qBAAqB,EAAE,KAAK,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC/F,OAAO,EAAE,MAAM,EAAE,4BAA4B,EAAE,cAAc,EAAE,8BAA8B,EAAE,MAAM,YAAY,CAAC;AAClH,OAAO,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/matrixrtc/index.ts"],"names":[],"mappings":"AAgBA,cAAc,qBAAqB,CAAC;AACpC,cAAc,uBAAuB,CAAC;AACtC,cAAc,uBAAuB,CAAC;AACtC,cAAc,8BAA8B,CAAC;AAC7C,mBAAmB,YAAY,CAAC;AAChC,OAAO,EAAE,KAAK,qBAAqB,EAAE,KAAK,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC/F,OAAO,EACH,MAAM,EACN,4BAA4B,EAC5B,yBAAyB,EACzB,cAAc,EACd,8BAA8B,GACjC,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC"}
@@ -18,6 +18,6 @@ export * from "./CallMembership.js";
18
18
  export * from "./LivekitTransport.js";
19
19
  export * from "./MatrixRTCSession.js";
20
20
  export * from "./MatrixRTCSessionManager.js";
21
- export { Status, parseCallNotificationContent, isMyMembership, RTC_SLOT_ENCRYPTION_PER_MEMBER } from "./types.js";
21
+ export { Status, parseCallNotificationContent, getCallNotificationExpiry, isMyMembership, RTC_SLOT_ENCRYPTION_PER_MEMBER } from "./types.js";
22
22
  export { MembershipManagerEvent } from "./IMembershipManager.js";
23
23
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../src/matrixrtc/index.ts"],"sourcesContent":["/*\nCopyright 2024 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\nexport * from \"./CallMembership.ts\";\nexport * from \"./LivekitTransport.ts\";\nexport * from \"./MatrixRTCSession.ts\";\nexport * from \"./MatrixRTCSessionManager.ts\";\nexport type * from \"./types.ts\";\nexport { type SessionMembershipData, type RtcMembershipData } from \"./membershipData/index.ts\";\nexport { Status, parseCallNotificationContent, isMyMembership, RTC_SLOT_ENCRYPTION_PER_MEMBER } from \"./types.ts\";\nexport { MembershipManagerEvent } from \"./IMembershipManager.ts\";\n"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,cAAc,qBAAqB;AACnC,cAAc,uBAAuB;AACrC,cAAc,uBAAuB;AACrC,cAAc,8BAA8B;AAG5C,SAAS,MAAM,EAAE,4BAA4B,EAAE,cAAc,EAAE,8BAA8B,QAAQ,YAAY;AACjH,SAAS,sBAAsB,QAAQ,yBAAyB","ignoreList":[]}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../src/matrixrtc/index.ts"],"sourcesContent":["/*\nCopyright 2024 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\nexport * from \"./CallMembership.ts\";\nexport * from \"./LivekitTransport.ts\";\nexport * from \"./MatrixRTCSession.ts\";\nexport * from \"./MatrixRTCSessionManager.ts\";\nexport type * from \"./types.ts\";\nexport { type SessionMembershipData, type RtcMembershipData } from \"./membershipData/index.ts\";\nexport {\n Status,\n parseCallNotificationContent,\n getCallNotificationExpiry,\n isMyMembership,\n RTC_SLOT_ENCRYPTION_PER_MEMBER,\n} from \"./types.ts\";\nexport { MembershipManagerEvent } from \"./IMembershipManager.ts\";\n"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,cAAc,qBAAqB;AACnC,cAAc,uBAAuB;AACrC,cAAc,uBAAuB;AACrC,cAAc,8BAA8B;AAG5C,SACI,MAAM,EACN,4BAA4B,EAC5B,yBAAyB,EACzB,cAAc,EACd,8BAA8B,QAC3B,YAAY;AACnB,SAAS,sBAAsB,QAAQ,yBAAyB","ignoreList":[]}
@@ -1,3 +1,11 @@
1
+ import type { IContent } from "../../models/event.ts";
2
+ /**
3
+ * Whether the content of an `m.rtc.member` or `m.call.member` event represents a left membership.
4
+ *
5
+ * Leaving a slot is expressed by emptying the event's content, so nothing is left beyond the slot the
6
+ * membership applied to and the MSC4354 sticky key.
7
+ */
8
+ export declare function isLeftMembershipContent(content: IContent): boolean;
1
9
  /**
2
10
  * Thrown when an event is not valid for use with MatrixRTC.
3
11
  */
@@ -1 +1 @@
1
- {"version":3,"file":"common.d.ts","sourceRoot":"","sources":["../../../src/matrixrtc/membershipData/common.ts"],"names":[],"mappings":"AAgBA;;GAEG;AACH,qBAAa,6BAA8B,SAAQ,cAAc;aAEzC,IAAI,EAAE,MAAM;IADhC,YACoB,IAAI,EAAE,MAAM,EAC5B,MAAM,EAAE,MAAM,EAAE,EAGnB;CACJ"}
1
+ {"version":3,"file":"common.d.ts","sourceRoot":"","sources":["../../../src/matrixrtc/membershipData/common.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAEtD;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,QAAQ,GAAG,OAAO,CAElE;AAED;;GAEG;AACH,qBAAa,6BAA8B,SAAQ,cAAc;aAEzC,IAAI,EAAE,MAAM;IADhC,YACoB,IAAI,EAAE,MAAM,EAC5B,MAAM,EAAE,MAAM,EAAE,EAGnB;CACJ"}
@@ -14,6 +14,16 @@ See the License for the specific language governing permissions and
14
14
  limitations under the License.
15
15
  */
16
16
 
17
+ /**
18
+ * Whether the content of an `m.rtc.member` or `m.call.member` event represents a left membership.
19
+ *
20
+ * Leaving a slot is expressed by emptying the event's content, so nothing is left beyond the slot the
21
+ * membership applied to and the MSC4354 sticky key.
22
+ */
23
+ export function isLeftMembershipContent(content) {
24
+ return Object.keys(content).every(key => key === "slot_id" || key === "msc4354_sticky_key");
25
+ }
26
+
17
27
  /**
18
28
  * Thrown when an event is not valid for use with MatrixRTC.
19
29
  */
@@ -1 +1 @@
1
- {"version":3,"file":"common.js","names":[],"sources":["../../../src/matrixrtc/membershipData/common.ts"],"sourcesContent":["/*\nCopyright 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\n/**\n * Thrown when an event is not valid for use with MatrixRTC.\n */\nexport class MatrixRTCMembershipParseError extends AggregateError {\n public constructor(\n public readonly type: string,\n errors: string[],\n ) {\n super(errors, `Does not match ${type}:\\n${errors.join(\"\\n\")}`);\n }\n}\n"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,OAAO,MAAM,6BAA6B,SAAS,cAAc,CAAC;EACvD,WAAW,CACE,IAAY,EAC5B,MAAgB,EAClB;IACE,KAAK,CAAC,MAAM,EAAE,kBAAkB,IAAI,MAAM,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;IAAC,KAH/C,IAAY,GAAZ,IAAY;EAIhC;AACJ","ignoreList":[]}
1
+ {"version":3,"file":"common.js","names":[],"sources":["../../../src/matrixrtc/membershipData/common.ts"],"sourcesContent":["/*\nCopyright 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 type { IContent } from \"../../models/event.ts\";\n\n/**\n * Whether the content of an `m.rtc.member` or `m.call.member` event represents a left membership.\n *\n * Leaving a slot is expressed by emptying the event's content, so nothing is left beyond the slot the\n * membership applied to and the MSC4354 sticky key.\n */\nexport function isLeftMembershipContent(content: IContent): boolean {\n return Object.keys(content).every((key) => key === \"slot_id\" || key === \"msc4354_sticky_key\");\n}\n\n/**\n * Thrown when an event is not valid for use with MatrixRTC.\n */\nexport class MatrixRTCMembershipParseError extends AggregateError {\n public constructor(\n public readonly type: string,\n errors: string[],\n ) {\n super(errors, `Does not match ${type}:\\n${errors.join(\"\\n\")}`);\n }\n}\n"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAIA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAAS,uBAAuB,CAAC,OAAiB,EAAW;EAChE,OAAO,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,KAAK,CAAE,GAAG,IAAK,GAAG,KAAK,SAAS,IAAI,GAAG,KAAK,oBAAoB,CAAC;AACjG;;AAEA;AACA;AACA;AACA,OAAO,MAAM,6BAA6B,SAAS,cAAc,CAAC;EACvD,WAAW,CACE,IAAY,EAC5B,MAAgB,EAClB;IACE,KAAK,CAAC,MAAM,EAAE,kBAAkB,IAAI,MAAM,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;IAAC,KAH/C,IAAY,GAAZ,IAAY;EAIhC;AACJ","ignoreList":[]}
@@ -1,4 +1,4 @@
1
1
  export { type SessionMembershipData, checkSessionsMembershipData } from "./session.ts";
2
2
  export { type RtcMembershipData, computeRtcIdentityRaw, checkRtcMembershipData } from "./rtc.ts";
3
- export { MatrixRTCMembershipParseError } from "./common.ts";
3
+ export { MatrixRTCMembershipParseError, isLeftMembershipContent } from "./common.ts";
4
4
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/matrixrtc/membershipData/index.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAE,KAAK,qBAAqB,EAAE,2BAA2B,EAAE,MAAM,cAAc,CAAC;AACvF,OAAO,EAAE,KAAK,iBAAiB,EAAE,qBAAqB,EAAE,sBAAsB,EAAE,MAAM,UAAU,CAAC;AACjG,OAAO,EAAE,6BAA6B,EAAE,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/matrixrtc/membershipData/index.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAE,KAAK,qBAAqB,EAAE,2BAA2B,EAAE,MAAM,cAAc,CAAC;AACvF,OAAO,EAAE,KAAK,iBAAiB,EAAE,qBAAqB,EAAE,sBAAsB,EAAE,MAAM,UAAU,CAAC;AACjG,OAAO,EAAE,6BAA6B,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC"}
@@ -16,5 +16,5 @@ limitations under the License.
16
16
 
17
17
  export { checkSessionsMembershipData } from "./session.js";
18
18
  export { computeRtcIdentityRaw, checkRtcMembershipData } from "./rtc.js";
19
- export { MatrixRTCMembershipParseError } from "./common.js";
19
+ export { MatrixRTCMembershipParseError, isLeftMembershipContent } from "./common.js";
20
20
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../src/matrixrtc/membershipData/index.ts"],"sourcesContent":["/*\nCopyright 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\nexport { type SessionMembershipData, checkSessionsMembershipData } from \"./session.ts\";\nexport { type RtcMembershipData, computeRtcIdentityRaw, checkRtcMembershipData } from \"./rtc.ts\";\nexport { MatrixRTCMembershipParseError } from \"./common.ts\";\n"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,SAAqC,2BAA2B,QAAQ,cAAc;AACtF,SAAiC,qBAAqB,EAAE,sBAAsB,QAAQ,UAAU;AAChG,SAAS,6BAA6B,QAAQ,aAAa","ignoreList":[]}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../src/matrixrtc/membershipData/index.ts"],"sourcesContent":["/*\nCopyright 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\nexport { type SessionMembershipData, checkSessionsMembershipData } from \"./session.ts\";\nexport { type RtcMembershipData, computeRtcIdentityRaw, checkRtcMembershipData } from \"./rtc.ts\";\nexport { MatrixRTCMembershipParseError, isLeftMembershipContent } from \"./common.ts\";\n"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,SAAqC,2BAA2B,QAAQ,cAAc;AACtF,SAAiC,qBAAqB,EAAE,sBAAsB,QAAQ,UAAU;AAChG,SAAS,6BAA6B,EAAE,uBAAuB,QAAQ,aAAa","ignoreList":[]}