matrix-js-sdk 43.0.0 → 44.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 (88) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/lib/matrixrtc/CallMembership.d.ts +30 -25
  3. package/lib/matrixrtc/CallMembership.d.ts.map +1 -1
  4. package/lib/matrixrtc/CallMembership.js +91 -100
  5. package/lib/matrixrtc/CallMembership.js.map +1 -1
  6. package/lib/matrixrtc/EncryptionManager.d.ts +6 -4
  7. package/lib/matrixrtc/EncryptionManager.d.ts.map +1 -1
  8. package/lib/matrixrtc/EncryptionManager.js.map +1 -1
  9. package/lib/matrixrtc/IMembershipManager.d.ts +2 -15
  10. package/lib/matrixrtc/IMembershipManager.d.ts.map +1 -1
  11. package/lib/matrixrtc/IMembershipManager.js.map +1 -1
  12. package/lib/matrixrtc/LivekitTransport.d.ts +36 -7
  13. package/lib/matrixrtc/LivekitTransport.d.ts.map +1 -1
  14. package/lib/matrixrtc/LivekitTransport.js +29 -2
  15. package/lib/matrixrtc/LivekitTransport.js.map +1 -1
  16. package/lib/matrixrtc/MatrixRTCSession.d.ts +12 -51
  17. package/lib/matrixrtc/MatrixRTCSession.d.ts.map +1 -1
  18. package/lib/matrixrtc/MatrixRTCSession.js +10 -66
  19. package/lib/matrixrtc/MatrixRTCSession.js.map +1 -1
  20. package/lib/matrixrtc/MembershipManager.d.ts +5 -10
  21. package/lib/matrixrtc/MembershipManager.d.ts.map +1 -1
  22. package/lib/matrixrtc/MembershipManager.js +25 -44
  23. package/lib/matrixrtc/MembershipManager.js.map +1 -1
  24. package/lib/matrixrtc/RTCEncryptionManager.d.ts +8 -8
  25. package/lib/matrixrtc/RTCEncryptionManager.d.ts.map +1 -1
  26. package/lib/matrixrtc/RTCEncryptionManager.js +30 -22
  27. package/lib/matrixrtc/RTCEncryptionManager.js.map +1 -1
  28. package/lib/matrixrtc/ToDeviceKeyTransport.js +7 -8
  29. package/lib/matrixrtc/ToDeviceKeyTransport.js.map +1 -1
  30. package/lib/matrixrtc/membershipData/rtc.d.ts +8 -13
  31. package/lib/matrixrtc/membershipData/rtc.d.ts.map +1 -1
  32. package/lib/matrixrtc/membershipData/rtc.js +2 -11
  33. package/lib/matrixrtc/membershipData/rtc.js.map +1 -1
  34. package/lib/matrixrtc/membershipData/session.d.ts +6 -2
  35. package/lib/matrixrtc/membershipData/session.d.ts.map +1 -1
  36. package/lib/matrixrtc/membershipData/session.js +3 -0
  37. package/lib/matrixrtc/membershipData/session.js.map +1 -1
  38. package/lib/matrixrtc/types.d.ts +5 -0
  39. package/lib/matrixrtc/types.d.ts.map +1 -1
  40. package/lib/matrixrtc/types.js +5 -0
  41. package/lib/matrixrtc/types.js.map +1 -1
  42. package/lib/models/event-timeline-set.d.ts +9 -2
  43. package/lib/models/event-timeline-set.d.ts.map +1 -1
  44. package/lib/models/event-timeline-set.js +8 -5
  45. package/lib/models/event-timeline-set.js.map +1 -1
  46. package/lib/models/room-sticky-events.d.ts +17 -2
  47. package/lib/models/room-sticky-events.d.ts.map +1 -1
  48. package/lib/models/room-sticky-events.js +88 -47
  49. package/lib/models/room-sticky-events.js.map +1 -1
  50. package/lib/models/room.d.ts +1 -1
  51. package/lib/models/room.d.ts.map +1 -1
  52. package/lib/models/room.js +8 -2
  53. package/lib/models/room.js.map +1 -1
  54. package/lib/models/thread.d.ts.map +1 -1
  55. package/lib/models/thread.js +23 -2
  56. package/lib/models/thread.js.map +1 -1
  57. package/lib/rendezvous/MSC4108SignInWithQR.d.ts +3 -3
  58. package/lib/rendezvous/MSC4108SignInWithQR.d.ts.map +1 -1
  59. package/lib/rendezvous/MSC4108SignInWithQR.js.map +1 -1
  60. package/lib/rendezvous/SignInWithQRFlow.d.ts +95 -0
  61. package/lib/rendezvous/SignInWithQRFlow.d.ts.map +1 -0
  62. package/lib/rendezvous/SignInWithQRFlow.js +3 -0
  63. package/lib/rendezvous/SignInWithQRFlow.js.map +1 -0
  64. package/lib/rendezvous/index.d.ts +1 -0
  65. package/lib/rendezvous/index.d.ts.map +1 -1
  66. package/lib/rendezvous/index.js.map +1 -1
  67. package/lib/rust-crypto/index.js +5 -1
  68. package/lib/rust-crypto/index.js.map +1 -1
  69. package/package.json +3 -3
  70. package/src/matrixrtc/CallMembership.ts +85 -95
  71. package/src/matrixrtc/EncryptionManager.ts +6 -4
  72. package/src/matrixrtc/IMembershipManager.ts +2 -15
  73. package/src/matrixrtc/LivekitTransport.ts +58 -9
  74. package/src/matrixrtc/MatrixRTCSession.ts +21 -80
  75. package/src/matrixrtc/MembershipManager.ts +23 -40
  76. package/src/matrixrtc/RTCEncryptionManager.ts +51 -39
  77. package/src/matrixrtc/ToDeviceKeyTransport.ts +7 -7
  78. package/src/matrixrtc/membershipData/rtc.ts +9 -23
  79. package/src/matrixrtc/membershipData/session.ts +14 -2
  80. package/src/matrixrtc/types.ts +6 -0
  81. package/src/models/event-timeline-set.ts +19 -4
  82. package/src/models/room-sticky-events.ts +92 -58
  83. package/src/models/room.ts +8 -2
  84. package/src/models/thread.ts +25 -3
  85. package/src/rendezvous/MSC4108SignInWithQR.ts +3 -3
  86. package/src/rendezvous/SignInWithQRFlow.ts +117 -0
  87. package/src/rendezvous/index.ts +1 -0
  88. package/src/rust-crypto/index.ts +5 -1
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/matrixrtc/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/matrixrtc/types.ts"],"names":[],"mappings":"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"}
@@ -50,6 +50,11 @@ import { isSlotOpen, slotIdToDescription } from "./utils.js";
50
50
  * May be any string, although `"audio"` and `"video"` are commonly accepted values.
51
51
  */
52
52
 
53
+ /**
54
+ * Represents one kind of media a member's device is capable of handling.
55
+ * May be any string, although `"m.render_audio"` and `"m.render_video"` are commonly accepted values.
56
+ */
57
+
53
58
  /**
54
59
  * The maximum `lifetime` of an RTC notification as per MSC4075. Larger values are capped to this.
55
60
  *
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","names":[],"sources":["../../src/matrixrtc/types.ts"],"sourcesContent":["/*\nCopyright 2023-2026 The Matrix.org Foundation C.I.C.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n*/\nimport type { IContent, IMentions } from \"../matrix.ts\";\nimport type { RelationEvent } from \"../types.ts\";\nimport type { MatrixEvent } from \"../models/event.ts\";\nimport type { Room } from \"../models/room.ts\";\nimport { EventTimeline } from \"../models/event-timeline.ts\";\nimport { EventType, RelationType } from \"../@types/event.ts\";\nimport { CallMembership } from \"./CallMembership.ts\";\nimport { type CallMembershipIdentityParts } from \"./EncryptionManager.ts\";\nimport { isLeftMembershipContent } from \"./membershipData/index.ts\";\nimport { isSlotOpen, slotIdToDescription } from \"./utils.ts\";\n\nexport type EncryptionKeyMapKey = string;\n\nexport interface EncryptionKeyEntry {\n index: number;\n key: string;\n}\n\n/**\n * The mxID, deviceId and membership timestamp of a RTC session participant.\n */\nexport type ParticipantDeviceInfo = {\n userId: string;\n deviceId: string;\n membershipTs: number;\n};\n\n/**\n * A type representing the information needed to decrypt video streams.\n */\nexport type InboundEncryptionSession = {\n key: Uint8Array<ArrayBuffer>;\n membership: CallMembershipIdentityParts;\n keyIndex: number;\n creationTS: number;\n};\n\n/**\n * The information about the key used to encrypt video streams.\n */\nexport type OutboundEncryptionSession = {\n key: Uint8Array<ArrayBuffer>;\n creationTS: number;\n // The devices that this key is shared with.\n sharedWith: Array<ParticipantDeviceInfo>;\n // This is an index acting as the id of the key\n keyId: number;\n};\n\nexport interface EncryptionKeysEventContent {\n keys: EncryptionKeyEntry[];\n device_id: string;\n call_id: string;\n sent_ts?: number;\n}\n\n/**\n * THe content of a to-device event that contains encryption keys.\n */\nexport interface EncryptionKeysToDeviceEventContent {\n keys: { index: number; key: string };\n member: {\n id: string;\n // TODO Remove that it is claimed, need to get the sealed sender from decryption info\n // Or add some validation on it based on the encryption info\n claimed_device_id: string;\n };\n room_id: string;\n session: {\n application: string;\n call_id: string;\n scope: string;\n };\n // Why is this needed?\n sent_ts?: number;\n}\n/**\n * @deprecated Use `RTCNotificationType` instead.\n */\nexport type CallNotifyType = \"ring\" | \"notify\";\n/**\n * @deprecated Use `IRTCNotificationContent` instead.\n */\nexport interface ICallNotifyContent {\n \"application\": string;\n \"m.mentions\": IMentions;\n \"notify_type\": CallNotifyType;\n \"call_id\": string;\n}\n\nexport type RTCNotificationType = \"ring\" | \"notification\";\n\n/**\n * Represents the intention of the call from the perspective of the sending user.\n * May be any string, although `\"audio\"` and `\"video\"` are commonly accepted values.\n */\nexport type RTCCallIntent = \"audio\" | \"video\" | string;\n\n/**\n * The maximum `lifetime` of an RTC notification as per MSC4075. Larger values are capped to this.\n *\n * Exported for use within the js-sdk only. Not re-exported from `matrixrtc/index.ts`.\n * @internal\n */\nexport const RTC_NOTIFICATION_MAX_LIFETIME_MS = 2 * 60 * 1000; // 2 minutes\n\n/**\n * The maximum amount by which a notification's `sender_ts` may lie ahead of its `origin_server_ts`\n * before the `lifetime` is measured from `origin_server_ts` instead, as per MSC4075.\n *\n * Exported for use within the js-sdk only. Not re-exported from `matrixrtc/index.ts`.\n * @internal\n */\nexport const RTC_NOTIFICATION_MAX_SENDER_TS_AHEAD_MS = 20 * 1000; // 20 seconds\n\n/**\n * The context that is needed to evaluate the MSC4075 rules for receiving notifications.\n */\nexport interface RTCNotificationValidationContext {\n /** The room in which the notification was received. */\n room: Pick<\n Room,\n \"getLiveTimeline\" | \"getUnfilteredTimelineSet\" | \"_unstable_getStickyEvents\" | \"_unstable_getKeyedStickyEvent\"\n >;\n /** The user ID of the receiving (local) user. */\n userId: string;\n /** The current time in milliseconds since the epoch. Defaults to `Date.now()`. */\n now?: number;\n}\n\n/**\n * Computes the absolute timestamp at which an RTC notification stops being valid, as per MSC4075.\n *\n * The `lifetime` is measured from `sender_ts` unless `sender_ts` lies more than 20 seconds ahead of\n * `origin_server_ts`, in which case it is measured from `origin_server_ts` instead. Regardless of the basis,\n * the remaining lifetime is capped at 2 minutes.\n *\n * @param content The notification content.\n * @param originServerTs The `origin_server_ts` of the notification event.\n * @param now The current time in milliseconds since the epoch. Defaults to `Date.now()`.\n * @returns The timestamp (in milliseconds since the epoch) at which the notification expires.\n */\nexport function getCallNotificationExpiry(\n content: Pick<IRTCNotificationContent, \"sender_ts\" | \"lifetime\">,\n originServerTs: number,\n now: number = Date.now(),\n): number {\n const basis =\n content.sender_ts - originServerTs > RTC_NOTIFICATION_MAX_SENDER_TS_AHEAD_MS\n ? originServerTs\n : content.sender_ts;\n return Math.min(basis + content.lifetime, now + RTC_NOTIFICATION_MAX_LIFETIME_MS);\n}\n\n/**\n * The subset of a notification event that {@link parseCallNotificationContent} needs.\n */\ntype RTCNotificationEvent = Pick<\n MatrixEvent,\n \"getContent\" | \"getId\" | \"getSender\" | \"getTs\" | \"getType\" | \"unstableStickyInfo\"\n>;\n\n/**\n * Whether the content marks a withdrawn sticky event (MSC4354), i.e. it is empty apart from the sticky key.\n */\nfunction isWithdrawal(content: IContent): boolean {\n return Object.keys(content).every((key) => key === \"msc4354_sticky_key\");\n}\n\nfunction isNonNegativeInteger(value: unknown): value is number {\n return Number.isInteger(value) && (value as number) >= 0;\n}\n\n/**\n * Looks up a legacy `m.call.member` state event by ID in the room's current state.\n *\n * @returns The event, or `undefined` if no current membership state event has that ID.\n */\nfunction findMembershipStateEvent(\n room: RTCNotificationValidationContext[\"room\"],\n eventId: string,\n): MatrixEvent | undefined {\n const roomState = room.getLiveTimeline().getState(EventTimeline.FORWARDS);\n return roomState?.getStateEvents(EventType.GroupCallMemberPrefix).find((event) => event.getId() === eventId);\n}\n\n/**\n * Determines the ID of the slot that a notification invites to.\n *\n * Notifications predating the `slot_id` property instead carry an `m.reference` relation to the sender's\n * membership event.\n *\n * @throws if the slot can't be determined.\n * @returns A promise resolving to the slot ID.\n */\nasync function resolveSlotId(content: IContent, room: RTCNotificationValidationContext[\"room\"]): Promise<string> {\n if (typeof content[\"slot_id\"] === \"string\") {\n // Throws if the ID is malformed, e.g. because it contains more than one \"#\".\n slotIdToDescription(content[\"slot_id\"]);\n return content[\"slot_id\"];\n }\n if (content[\"slot_id\"] !== undefined) throw new Error(\"Invalid slot_id\");\n\n const relation = content[\"m.relates_to\"];\n const membershipEventId = relation?.rel_type === RelationType.Reference ? relation.event_id : undefined;\n if (typeof membershipEventId !== \"string\") {\n throw new Error(\"Missing slot_id and no m.reference relation to derive it from\");\n }\n\n const membershipEvent = findMembershipStateEvent(room, membershipEventId);\n if (!membershipEvent) {\n throw new Error(`Missing slot_id and referenced event ${membershipEventId} is not a current membership`);\n }\n\n try {\n return (await CallMembership.parseFromEvent(membershipEvent)).slotId;\n } catch (cause) {\n throw new Error(`Missing slot_id and referenced event ${membershipEventId} is not a valid membership`, {\n cause,\n });\n }\n}\n\n/**\n * Parses the content of a received `org.matrix.msc4075.rtc.notification` event.\n *\n * This checks that the content matches the schema of MSC4075, caps `lifetime` to 2 minutes and applies\n * the rules for receiving invites from MSC4075.\n * The notification is only considered valid if all of the following hold:\n * - It wasn't sent by the receiving user.\n * - It is the current entry in the room's sticky event map for its sender and slot and isn't a withdrawal.\n * - The slot it refers to exists and is open.\n * - Its lifetime hasn't elapsed (see {@link getCallNotificationExpiry}).\n * - Its `m.mentions` target the receiving user, either directly or via a room mention that the sender is\n * allowed to trigger.\n * - The receiving user has no joined `m.rtc.member` event for the slot in the sticky event map.\n * - Any left `m.rtc.member` event of the receiving user for the slot predates the notification.\n * - The receiving user has no sticky decline event referencing the notification.\n *\n * @param event The notification event.\n * @param context The context needed to evaluate the receiving rules.\n * @throws if the content is malformed or the notification isn't valid.\n * @returns A promise resolving to the parsed content.\n */\nexport async function parseCallNotificationContent(\n event: RTCNotificationEvent,\n context: RTCNotificationValidationContext,\n): Promise<IRTCNotificationContent> {\n if (event.getType() !== EventType.RTCNotification) {\n throw new Error(`Event ${event.getId()} is not an ${EventType.RTCNotification} event`);\n }\n\n const content = event.getContent();\n if (isWithdrawal(content)) {\n throw new Error(\"Notification was withdrawn\");\n }\n\n const slotId = await resolveSlotId(content, context.room);\n // The sticky key is only validated when present. A notification predating it can still be valid, and one\n // carrying the wrong key is filed under that key in the sticky event map, so the lookup below rejects it.\n if (content[\"msc4354_sticky_key\"] !== undefined && content[\"msc4354_sticky_key\"] !== slotId) {\n throw new Error(\"msc4354_sticky_key must be equal to slot_id\");\n }\n if (!isNonNegativeInteger(content[\"sender_ts\"])) {\n throw new Error(\"Missing or invalid sender_ts\");\n }\n if (!isNonNegativeInteger(content[\"lifetime\"])) {\n throw new Error(\"Missing or invalid lifetime\");\n }\n\n const mentions = content[\"m.mentions\"];\n if (typeof mentions !== \"object\" || mentions === null) {\n throw new Error(\"Missing or malformed m.mentions\");\n }\n if (mentions.room !== undefined && typeof mentions.room !== \"boolean\") {\n throw new Error(\"malformed m.mentions.room\");\n }\n if (\n mentions.user_ids !== undefined &&\n (!Array.isArray(mentions.user_ids) || !mentions.user_ids.every((userId) => typeof userId === \"string\"))\n ) {\n throw new Error(\"malformed m.mentions.user_ids\");\n }\n if (mentions.room !== true && !mentions.user_ids?.length) {\n throw new Error(\"m.mentions must target either the room or at least one user\");\n }\n\n const parsed = {\n ...content,\n slot_id: slotId,\n lifetime: Math.min(content[\"lifetime\"], RTC_NOTIFICATION_MAX_LIFETIME_MS),\n } as IRTCNotificationContent;\n\n await checkCallNotificationReceivingRules(parsed, event, context);\n\n return parsed;\n}\n\n/**\n * Applies the MSC4075 rules for receiving invites to an already schema-validated notification.\n * @throws if any of the rules is violated.\n */\nasync function checkCallNotificationReceivingRules(\n content: IRTCNotificationContent,\n event: RTCNotificationEvent,\n { room, userId, now = Date.now() }: RTCNotificationValidationContext,\n): Promise<void> {\n const eventId = event.getId();\n const sender = event.getSender();\n if (eventId === undefined || sender === undefined) {\n throw new Error(\"Notification event is missing its event ID or sender\");\n }\n const originServerTs = event.getTs();\n const slotId = content.slot_id;\n\n if (sender === userId) {\n throw new Error(\"Notification was sent by the receiving user\");\n }\n\n // A notification that wasn't delivered as a sticky event can't be superseded or withdrawn, so there is\n // nothing to check. It isn't in the sticky event map either, which is why this can't be checked blindly.\n if (event.unstableStickyInfo !== undefined) {\n if (room._unstable_getKeyedStickyEvent(sender, event.getType(), slotId)?.getId() !== eventId) {\n throw new Error(\"Notification is not the current sticky event for its sender and slot\");\n }\n }\n\n // `isSlotOpen` returns undefined when no slot event exists at all, which is just as disqualifying.\n if (!isSlotOpen(room, slotIdToDescription(slotId))) {\n throw new Error(`Slot ${slotId} does not exist or is closed`);\n }\n const roomState = room.getLiveTimeline().getState(EventTimeline.FORWARDS);\n\n if (now >= getCallNotificationExpiry(content, originServerTs, now)) {\n throw new Error(\"Notification has expired\");\n }\n\n const mentions = content[\"m.mentions\"];\n const mentionsUser = mentions.user_ids?.includes(userId) ?? false;\n const mentionsRoom = mentions.room === true && (roomState?.mayTriggerNotifOfType(\"room\", sender) ?? false);\n if (!mentionsUser && !mentionsRoom) {\n throw new Error(\"Notification does not mention the receiving user\");\n }\n\n for (const membershipEvent of ownMembershipEvents(room, userId)) {\n const membershipContent = membershipEvent.getContent();\n if (isLeftMembershipContent(membershipContent)) {\n if (membershipContent.slot_id === slotId && membershipEvent.getTs() >= originServerTs) {\n throw new Error(`Receiving user left slot ${slotId} after the notification was sent`);\n }\n } else if (await isJoinedToSlot(membershipEvent, slotId, now)) {\n throw new Error(`Receiving user is already joined to slot ${slotId}`);\n }\n }\n\n if (hasDeclined(room, userId, eventId)) {\n throw new Error(\"Receiving user declined the notification\");\n }\n}\n\n/**\n * Yields the receiving user's own MatrixRTC membership events, from both the sticky event map and the legacy\n * member state events. Sessions that don't use sticky events keep membership in state, so both have to be\n * consulted to tell whether the user is in a session.\n *\n * @yields the user's own `m.rtc.member` and `m.call.member` events.\n */\nfunction* ownMembershipEvents(room: RTCNotificationValidationContext[\"room\"], userId: string): Iterable<MatrixEvent> {\n for (const stickyEvent of room._unstable_getStickyEvents()) {\n if (stickyEvent.getType() === EventType.RTCMembership && stickyEvent.getSender() === userId) {\n yield stickyEvent;\n }\n }\n\n const roomState = room.getLiveTimeline().getState(EventTimeline.FORWARDS);\n for (const stateEvent of roomState?.getStateEvents(EventType.GroupCallMemberPrefix) ?? []) {\n if (stateEvent.getSender() === userId) yield stateEvent;\n }\n}\n\n/**\n * Whether the given membership event places its sender in the given slot, i.e. it is a valid, unexpired\n * membership for that slot.\n */\nasync function isJoinedToSlot(membershipEvent: MatrixEvent, slotId: string, now: number): Promise<boolean> {\n let membership: CallMembership;\n try {\n membership = await CallMembership.parseFromEvent(membershipEvent);\n } catch {\n // Not a membership we understand, so it doesn't place the user anywhere.\n return false;\n }\n if (membership.slotId !== slotId) return false;\n\n // Legacy memberships go stale when the client that sent them disappears without leaving. Honouring an\n // expired one would suppress notifications for hours.\n const expiry = membership.getAbsoluteExpiry();\n return expiry === undefined || expiry > now;\n}\n\n/**\n * Whether the receiving user has declined the given notification.\n *\n * Declines are looked up both through their `m.reference` relation and in the sticky event map. Relations\n * cover declines that couldn't be sent as sticky events, but only see events that reached the timeline. A\n * sticky decline delivered after a gappy or initial sync arrives via the sticky section instead, so it is\n * only in the map.\n */\nfunction hasDeclined(room: RTCNotificationValidationContext[\"room\"], userId: string, eventId: string): boolean {\n const declines = room\n .getUnfilteredTimelineSet()\n .relations.getChildEventsForEvent(eventId, RelationType.Reference, EventType.RTCDecline);\n if (declines?.getRelations().some((decline) => decline.getSender() === userId)) return true;\n\n // Declines are keyed on the event ID of the notification they decline.\n return room._unstable_getKeyedStickyEvent(userId, EventType.RTCDecline, eventId) !== undefined;\n}\n\n/**\n * Interface for `org.matrix.msc4075.rtc.notification` events.\n * Don't cast event content to this directly. Use `parseCallNotificationContent` instead to validate the content first.\n */\nexport interface IRTCNotificationContent extends RelationEvent {\n /**\n * The `state_key` of the `m.rtc.slot` event that the notification refers to.\n *\n * Notifications predating this property omit it. `parseCallNotificationContent` fills it in from the\n * referenced membership event, so the parsed content always carries it.\n */\n \"slot_id\": string;\n /**\n * The users targeted by the notification. Must either mention the room or at least one user.\n */\n \"m.mentions\": IMentions;\n /**\n * @deprecated Not part of MSC4075 anymore. How to present a notification is up to the receiving client.\n */\n \"notification_type\"?: RTCNotificationType;\n /**\n * @deprecated Not part of MSC4075 anymore. The initial intent of the calling user.\n */\n \"m.call.intent\"?: RTCCallIntent;\n /**\n * The timestamp (in milliseconds since the epoch) at which the sending client created the event.\n */\n \"sender_ts\": number;\n /**\n * The time (in milliseconds) that the notification is valid for, measured from `sender_ts`.\n */\n \"lifetime\": number;\n /**\n * The sticky key as per MSC4354. Must be equal to `slot_id`.\n *\n * Optional because notifications predating MSC4354 omit it.\n */\n \"msc4354_sticky_key\"?: string;\n}\n\n/**\n * MSC4310 decline event content for `org.matrix.msc4310.rtc.decline`.\n * Sent as a standard m.reference relation to an `org.matrix.msc4075.rtc.notification` event.\n */\nexport interface IRTCDeclineContent extends RelationEvent {\n /**\n * The sticky key as per MSC4354. Must be equal to the event ID of the notification being declined.\n *\n * Optional because servers without MSC4354 support can't deliver the decline as a sticky event. Such a\n * decline still counts, but only for devices that receive it directly, since it isn't re-delivered after\n * a gappy or initial sync.\n */\n msc4354_sticky_key?: string;\n}\n\nexport enum Status {\n Disconnected = \"Disconnected\",\n Connecting = \"Connecting\",\n Connected = \"Connected\",\n Disconnecting = \"Disconnecting\",\n Unknown = \"Unknown\",\n}\n\n/**\n * A type collecting call encryption statistics for a session.\n */\nexport type Statistics = {\n counters: {\n /**\n * The number of times we have sent a room event containing encryption keys.\n */\n roomEventEncryptionKeysSent: number;\n /**\n * The number of times we have received a room event containing encryption keys.\n */\n roomEventEncryptionKeysReceived: number;\n };\n totals: {\n /**\n * The total age (in milliseconds) of all room events containing encryption keys that we have received.\n * We track the total age so that we can later calculate the average age of all keys received.\n */\n roomEventEncryptionKeysReceivedTotalAge: number;\n };\n};\n\nexport const isMyMembership = (m: CallMembership, userId: string, deviceId: string): boolean =>\n m.sender === userId && m.deviceId === deviceId;\n\n/**\n * A RTC transport is a JSON object that describes how to connect to a RTC member.\n */\nexport interface Transport {\n type: string;\n [key: string]: unknown;\n}\n\n/**\n * Event content for `org.matrix.msc4143.rtc.slot` state events.\n */\nexport interface RtcSlotEventContent<T extends string = string> {\n status: \"open\" | \"closed\";\n application?: RtcSlotApplicationContent<T>;\n encryption?: RtcSlotEncryptionContent;\n}\n\n/**\n * Content of the `application` object within `org.matrix.msc4143.rtc.slot` events.\n */\nexport interface RtcSlotApplicationContent<T extends string = string> {\n type: T;\n // Other application specific keys.\n [key: string]: unknown;\n}\n\nexport const RTC_SLOT_ENCRYPTION_PER_MEMBER = \"org.matrix.msc4143.per_member\";\n\n/**\n * Content of the `encryption` object within `org.matrix.msc4143.rtc.slot` events.\n */\nexport interface RtcSlotEncryptionContent {\n type: typeof RTC_SLOT_ENCRYPTION_PER_MEMBER;\n // Other encryption-mechanism specific keys.\n [key: string]: unknown;\n}\n\n/**\n * The session description is used to identify a session. Used in the state event.\n */\nexport interface SlotDescription {\n /**\n * The application type. e.g. \"m.call\".\n */\n application: string;\n /**\n * The application-specific slot ID. e.g. \"ROOM\".\n */\n id: string;\n}\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"types.js","names":[],"sources":["../../src/matrixrtc/types.ts"],"sourcesContent":["/*\nCopyright 2023-2026 The Matrix.org Foundation C.I.C.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n*/\nimport type { IContent, IMentions } from \"../matrix.ts\";\nimport type { RelationEvent } from \"../types.ts\";\nimport type { MatrixEvent } from \"../models/event.ts\";\nimport type { Room } from \"../models/room.ts\";\nimport { EventTimeline } from \"../models/event-timeline.ts\";\nimport { EventType, RelationType } from \"../@types/event.ts\";\nimport { CallMembership } from \"./CallMembership.ts\";\nimport { type CallMembershipIdentityParts } from \"./EncryptionManager.ts\";\nimport { isLeftMembershipContent } from \"./membershipData/index.ts\";\nimport { isSlotOpen, slotIdToDescription } from \"./utils.ts\";\n\nexport type EncryptionKeyMapKey = string;\n\nexport interface EncryptionKeyEntry {\n index: number;\n key: string;\n}\n\n/**\n * The mxID, deviceId and membership timestamp of a RTC session participant.\n */\nexport type ParticipantDeviceInfo = {\n userId: string;\n deviceId: string;\n membershipTs: number;\n};\n\n/**\n * A type representing the information needed to decrypt video streams.\n */\nexport type InboundEncryptionSession = {\n key: Uint8Array<ArrayBuffer>;\n membership: CallMembershipIdentityParts;\n keyIndex: number;\n creationTS: number;\n};\n\n/**\n * The information about the key used to encrypt video streams.\n */\nexport type OutboundEncryptionSession = {\n key: Uint8Array<ArrayBuffer>;\n creationTS: number;\n // The devices that this key is shared with.\n sharedWith: Array<ParticipantDeviceInfo>;\n // This is an index acting as the id of the key\n keyId: number;\n};\n\nexport interface EncryptionKeysEventContent {\n keys: EncryptionKeyEntry[];\n device_id: string;\n call_id: string;\n sent_ts?: number;\n}\n\n/**\n * THe content of a to-device event that contains encryption keys.\n */\nexport interface EncryptionKeysToDeviceEventContent {\n keys: { index: number; key: string };\n member: {\n id: string;\n // TODO Remove that it is claimed, need to get the sealed sender from decryption info\n // Or add some validation on it based on the encryption info\n claimed_device_id: string;\n };\n room_id: string;\n session: {\n application: string;\n call_id: string;\n scope: string;\n };\n // Why is this needed?\n sent_ts?: number;\n}\n/**\n * @deprecated Use `RTCNotificationType` instead.\n */\nexport type CallNotifyType = \"ring\" | \"notify\";\n/**\n * @deprecated Use `IRTCNotificationContent` instead.\n */\nexport interface ICallNotifyContent {\n \"application\": string;\n \"m.mentions\": IMentions;\n \"notify_type\": CallNotifyType;\n \"call_id\": string;\n}\n\nexport type RTCNotificationType = \"ring\" | \"notification\";\n\n/**\n * Represents the intention of the call from the perspective of the sending user.\n * May be any string, although `\"audio\"` and `\"video\"` are commonly accepted values.\n */\nexport type RTCCallIntent = \"audio\" | \"video\" | string;\n\n/**\n * Represents one kind of media a member's device is capable of handling.\n * May be any string, although `\"m.render_audio\"` and `\"m.render_video\"` are commonly accepted values.\n */\nexport type RTCCallCapability = \"m.render_audio\" | \"m.render_video\" | string;\n\n/**\n * The maximum `lifetime` of an RTC notification as per MSC4075. Larger values are capped to this.\n *\n * Exported for use within the js-sdk only. Not re-exported from `matrixrtc/index.ts`.\n * @internal\n */\nexport const RTC_NOTIFICATION_MAX_LIFETIME_MS = 2 * 60 * 1000; // 2 minutes\n\n/**\n * The maximum amount by which a notification's `sender_ts` may lie ahead of its `origin_server_ts`\n * before the `lifetime` is measured from `origin_server_ts` instead, as per MSC4075.\n *\n * Exported for use within the js-sdk only. Not re-exported from `matrixrtc/index.ts`.\n * @internal\n */\nexport const RTC_NOTIFICATION_MAX_SENDER_TS_AHEAD_MS = 20 * 1000; // 20 seconds\n\n/**\n * The context that is needed to evaluate the MSC4075 rules for receiving notifications.\n */\nexport interface RTCNotificationValidationContext {\n /** The room in which the notification was received. */\n room: Pick<\n Room,\n \"getLiveTimeline\" | \"getUnfilteredTimelineSet\" | \"_unstable_getStickyEvents\" | \"_unstable_getKeyedStickyEvent\"\n >;\n /** The user ID of the receiving (local) user. */\n userId: string;\n /** The current time in milliseconds since the epoch. Defaults to `Date.now()`. */\n now?: number;\n}\n\n/**\n * Computes the absolute timestamp at which an RTC notification stops being valid, as per MSC4075.\n *\n * The `lifetime` is measured from `sender_ts` unless `sender_ts` lies more than 20 seconds ahead of\n * `origin_server_ts`, in which case it is measured from `origin_server_ts` instead. Regardless of the basis,\n * the remaining lifetime is capped at 2 minutes.\n *\n * @param content The notification content.\n * @param originServerTs The `origin_server_ts` of the notification event.\n * @param now The current time in milliseconds since the epoch. Defaults to `Date.now()`.\n * @returns The timestamp (in milliseconds since the epoch) at which the notification expires.\n */\nexport function getCallNotificationExpiry(\n content: Pick<IRTCNotificationContent, \"sender_ts\" | \"lifetime\">,\n originServerTs: number,\n now: number = Date.now(),\n): number {\n const basis =\n content.sender_ts - originServerTs > RTC_NOTIFICATION_MAX_SENDER_TS_AHEAD_MS\n ? originServerTs\n : content.sender_ts;\n return Math.min(basis + content.lifetime, now + RTC_NOTIFICATION_MAX_LIFETIME_MS);\n}\n\n/**\n * The subset of a notification event that {@link parseCallNotificationContent} needs.\n */\ntype RTCNotificationEvent = Pick<\n MatrixEvent,\n \"getContent\" | \"getId\" | \"getSender\" | \"getTs\" | \"getType\" | \"unstableStickyInfo\"\n>;\n\n/**\n * Whether the content marks a withdrawn sticky event (MSC4354), i.e. it is empty apart from the sticky key.\n */\nfunction isWithdrawal(content: IContent): boolean {\n return Object.keys(content).every((key) => key === \"msc4354_sticky_key\");\n}\n\nfunction isNonNegativeInteger(value: unknown): value is number {\n return Number.isInteger(value) && (value as number) >= 0;\n}\n\n/**\n * Looks up a legacy `m.call.member` state event by ID in the room's current state.\n *\n * @returns The event, or `undefined` if no current membership state event has that ID.\n */\nfunction findMembershipStateEvent(\n room: RTCNotificationValidationContext[\"room\"],\n eventId: string,\n): MatrixEvent | undefined {\n const roomState = room.getLiveTimeline().getState(EventTimeline.FORWARDS);\n return roomState?.getStateEvents(EventType.GroupCallMemberPrefix).find((event) => event.getId() === eventId);\n}\n\n/**\n * Determines the ID of the slot that a notification invites to.\n *\n * Notifications predating the `slot_id` property instead carry an `m.reference` relation to the sender's\n * membership event.\n *\n * @throws if the slot can't be determined.\n * @returns A promise resolving to the slot ID.\n */\nasync function resolveSlotId(content: IContent, room: RTCNotificationValidationContext[\"room\"]): Promise<string> {\n if (typeof content[\"slot_id\"] === \"string\") {\n // Throws if the ID is malformed, e.g. because it contains more than one \"#\".\n slotIdToDescription(content[\"slot_id\"]);\n return content[\"slot_id\"];\n }\n if (content[\"slot_id\"] !== undefined) throw new Error(\"Invalid slot_id\");\n\n const relation = content[\"m.relates_to\"];\n const membershipEventId = relation?.rel_type === RelationType.Reference ? relation.event_id : undefined;\n if (typeof membershipEventId !== \"string\") {\n throw new Error(\"Missing slot_id and no m.reference relation to derive it from\");\n }\n\n const membershipEvent = findMembershipStateEvent(room, membershipEventId);\n if (!membershipEvent) {\n throw new Error(`Missing slot_id and referenced event ${membershipEventId} is not a current membership`);\n }\n\n try {\n return (await CallMembership.parseFromEvent(membershipEvent)).slotId;\n } catch (cause) {\n throw new Error(`Missing slot_id and referenced event ${membershipEventId} is not a valid membership`, {\n cause,\n });\n }\n}\n\n/**\n * Parses the content of a received `org.matrix.msc4075.rtc.notification` event.\n *\n * This checks that the content matches the schema of MSC4075, caps `lifetime` to 2 minutes and applies\n * the rules for receiving invites from MSC4075.\n * The notification is only considered valid if all of the following hold:\n * - It wasn't sent by the receiving user.\n * - It is the current entry in the room's sticky event map for its sender and slot and isn't a withdrawal.\n * - The slot it refers to exists and is open.\n * - Its lifetime hasn't elapsed (see {@link getCallNotificationExpiry}).\n * - Its `m.mentions` target the receiving user, either directly or via a room mention that the sender is\n * allowed to trigger.\n * - The receiving user has no joined `m.rtc.member` event for the slot in the sticky event map.\n * - Any left `m.rtc.member` event of the receiving user for the slot predates the notification.\n * - The receiving user has no sticky decline event referencing the notification.\n *\n * @param event The notification event.\n * @param context The context needed to evaluate the receiving rules.\n * @throws if the content is malformed or the notification isn't valid.\n * @returns A promise resolving to the parsed content.\n */\nexport async function parseCallNotificationContent(\n event: RTCNotificationEvent,\n context: RTCNotificationValidationContext,\n): Promise<IRTCNotificationContent> {\n if (event.getType() !== EventType.RTCNotification) {\n throw new Error(`Event ${event.getId()} is not an ${EventType.RTCNotification} event`);\n }\n\n const content = event.getContent();\n if (isWithdrawal(content)) {\n throw new Error(\"Notification was withdrawn\");\n }\n\n const slotId = await resolveSlotId(content, context.room);\n // The sticky key is only validated when present. A notification predating it can still be valid, and one\n // carrying the wrong key is filed under that key in the sticky event map, so the lookup below rejects it.\n if (content[\"msc4354_sticky_key\"] !== undefined && content[\"msc4354_sticky_key\"] !== slotId) {\n throw new Error(\"msc4354_sticky_key must be equal to slot_id\");\n }\n if (!isNonNegativeInteger(content[\"sender_ts\"])) {\n throw new Error(\"Missing or invalid sender_ts\");\n }\n if (!isNonNegativeInteger(content[\"lifetime\"])) {\n throw new Error(\"Missing or invalid lifetime\");\n }\n\n const mentions = content[\"m.mentions\"];\n if (typeof mentions !== \"object\" || mentions === null) {\n throw new Error(\"Missing or malformed m.mentions\");\n }\n if (mentions.room !== undefined && typeof mentions.room !== \"boolean\") {\n throw new Error(\"malformed m.mentions.room\");\n }\n if (\n mentions.user_ids !== undefined &&\n (!Array.isArray(mentions.user_ids) || !mentions.user_ids.every((userId) => typeof userId === \"string\"))\n ) {\n throw new Error(\"malformed m.mentions.user_ids\");\n }\n if (mentions.room !== true && !mentions.user_ids?.length) {\n throw new Error(\"m.mentions must target either the room or at least one user\");\n }\n\n const parsed = {\n ...content,\n slot_id: slotId,\n lifetime: Math.min(content[\"lifetime\"], RTC_NOTIFICATION_MAX_LIFETIME_MS),\n } as IRTCNotificationContent;\n\n await checkCallNotificationReceivingRules(parsed, event, context);\n\n return parsed;\n}\n\n/**\n * Applies the MSC4075 rules for receiving invites to an already schema-validated notification.\n * @throws if any of the rules is violated.\n */\nasync function checkCallNotificationReceivingRules(\n content: IRTCNotificationContent,\n event: RTCNotificationEvent,\n { room, userId, now = Date.now() }: RTCNotificationValidationContext,\n): Promise<void> {\n const eventId = event.getId();\n const sender = event.getSender();\n if (eventId === undefined || sender === undefined) {\n throw new Error(\"Notification event is missing its event ID or sender\");\n }\n const originServerTs = event.getTs();\n const slotId = content.slot_id;\n\n if (sender === userId) {\n throw new Error(\"Notification was sent by the receiving user\");\n }\n\n // A notification that wasn't delivered as a sticky event can't be superseded or withdrawn, so there is\n // nothing to check. It isn't in the sticky event map either, which is why this can't be checked blindly.\n if (event.unstableStickyInfo !== undefined) {\n if (room._unstable_getKeyedStickyEvent(sender, event.getType(), slotId)?.getId() !== eventId) {\n throw new Error(\"Notification is not the current sticky event for its sender and slot\");\n }\n }\n\n // `isSlotOpen` returns undefined when no slot event exists at all, which is just as disqualifying.\n if (!isSlotOpen(room, slotIdToDescription(slotId))) {\n throw new Error(`Slot ${slotId} does not exist or is closed`);\n }\n const roomState = room.getLiveTimeline().getState(EventTimeline.FORWARDS);\n\n if (now >= getCallNotificationExpiry(content, originServerTs, now)) {\n throw new Error(\"Notification has expired\");\n }\n\n const mentions = content[\"m.mentions\"];\n const mentionsUser = mentions.user_ids?.includes(userId) ?? false;\n const mentionsRoom = mentions.room === true && (roomState?.mayTriggerNotifOfType(\"room\", sender) ?? false);\n if (!mentionsUser && !mentionsRoom) {\n throw new Error(\"Notification does not mention the receiving user\");\n }\n\n for (const membershipEvent of ownMembershipEvents(room, userId)) {\n const membershipContent = membershipEvent.getContent();\n if (isLeftMembershipContent(membershipContent)) {\n if (membershipContent.slot_id === slotId && membershipEvent.getTs() >= originServerTs) {\n throw new Error(`Receiving user left slot ${slotId} after the notification was sent`);\n }\n } else if (await isJoinedToSlot(membershipEvent, slotId, now)) {\n throw new Error(`Receiving user is already joined to slot ${slotId}`);\n }\n }\n\n if (hasDeclined(room, userId, eventId)) {\n throw new Error(\"Receiving user declined the notification\");\n }\n}\n\n/**\n * Yields the receiving user's own MatrixRTC membership events, from both the sticky event map and the legacy\n * member state events. Sessions that don't use sticky events keep membership in state, so both have to be\n * consulted to tell whether the user is in a session.\n *\n * @yields the user's own `m.rtc.member` and `m.call.member` events.\n */\nfunction* ownMembershipEvents(room: RTCNotificationValidationContext[\"room\"], userId: string): Iterable<MatrixEvent> {\n for (const stickyEvent of room._unstable_getStickyEvents()) {\n if (stickyEvent.getType() === EventType.RTCMembership && stickyEvent.getSender() === userId) {\n yield stickyEvent;\n }\n }\n\n const roomState = room.getLiveTimeline().getState(EventTimeline.FORWARDS);\n for (const stateEvent of roomState?.getStateEvents(EventType.GroupCallMemberPrefix) ?? []) {\n if (stateEvent.getSender() === userId) yield stateEvent;\n }\n}\n\n/**\n * Whether the given membership event places its sender in the given slot, i.e. it is a valid, unexpired\n * membership for that slot.\n */\nasync function isJoinedToSlot(membershipEvent: MatrixEvent, slotId: string, now: number): Promise<boolean> {\n let membership: CallMembership;\n try {\n membership = await CallMembership.parseFromEvent(membershipEvent);\n } catch {\n // Not a membership we understand, so it doesn't place the user anywhere.\n return false;\n }\n if (membership.slotId !== slotId) return false;\n\n // Legacy memberships go stale when the client that sent them disappears without leaving. Honouring an\n // expired one would suppress notifications for hours.\n const expiry = membership.getAbsoluteExpiry();\n return expiry === undefined || expiry > now;\n}\n\n/**\n * Whether the receiving user has declined the given notification.\n *\n * Declines are looked up both through their `m.reference` relation and in the sticky event map. Relations\n * cover declines that couldn't be sent as sticky events, but only see events that reached the timeline. A\n * sticky decline delivered after a gappy or initial sync arrives via the sticky section instead, so it is\n * only in the map.\n */\nfunction hasDeclined(room: RTCNotificationValidationContext[\"room\"], userId: string, eventId: string): boolean {\n const declines = room\n .getUnfilteredTimelineSet()\n .relations.getChildEventsForEvent(eventId, RelationType.Reference, EventType.RTCDecline);\n if (declines?.getRelations().some((decline) => decline.getSender() === userId)) return true;\n\n // Declines are keyed on the event ID of the notification they decline.\n return room._unstable_getKeyedStickyEvent(userId, EventType.RTCDecline, eventId) !== undefined;\n}\n\n/**\n * Interface for `org.matrix.msc4075.rtc.notification` events.\n * Don't cast event content to this directly. Use `parseCallNotificationContent` instead to validate the content first.\n */\nexport interface IRTCNotificationContent extends RelationEvent {\n /**\n * The `state_key` of the `m.rtc.slot` event that the notification refers to.\n *\n * Notifications predating this property omit it. `parseCallNotificationContent` fills it in from the\n * referenced membership event, so the parsed content always carries it.\n */\n \"slot_id\": string;\n /**\n * The users targeted by the notification. Must either mention the room or at least one user.\n */\n \"m.mentions\": IMentions;\n /**\n * @deprecated Not part of MSC4075 anymore. How to present a notification is up to the receiving client.\n */\n \"notification_type\"?: RTCNotificationType;\n /**\n * @deprecated Not part of MSC4075 anymore. The initial intent of the calling user.\n */\n \"m.call.intent\"?: RTCCallIntent;\n /**\n * The timestamp (in milliseconds since the epoch) at which the sending client created the event.\n */\n \"sender_ts\": number;\n /**\n * The time (in milliseconds) that the notification is valid for, measured from `sender_ts`.\n */\n \"lifetime\": number;\n /**\n * The sticky key as per MSC4354. Must be equal to `slot_id`.\n *\n * Optional because notifications predating MSC4354 omit it.\n */\n \"msc4354_sticky_key\"?: string;\n}\n\n/**\n * MSC4310 decline event content for `org.matrix.msc4310.rtc.decline`.\n * Sent as a standard m.reference relation to an `org.matrix.msc4075.rtc.notification` event.\n */\nexport interface IRTCDeclineContent extends RelationEvent {\n /**\n * The sticky key as per MSC4354. Must be equal to the event ID of the notification being declined.\n *\n * Optional because servers without MSC4354 support can't deliver the decline as a sticky event. Such a\n * decline still counts, but only for devices that receive it directly, since it isn't re-delivered after\n * a gappy or initial sync.\n */\n msc4354_sticky_key?: string;\n}\n\nexport enum Status {\n Disconnected = \"Disconnected\",\n Connecting = \"Connecting\",\n Connected = \"Connected\",\n Disconnecting = \"Disconnecting\",\n Unknown = \"Unknown\",\n}\n\n/**\n * A type collecting call encryption statistics for a session.\n */\nexport type Statistics = {\n counters: {\n /**\n * The number of times we have sent a room event containing encryption keys.\n */\n roomEventEncryptionKeysSent: number;\n /**\n * The number of times we have received a room event containing encryption keys.\n */\n roomEventEncryptionKeysReceived: number;\n };\n totals: {\n /**\n * The total age (in milliseconds) of all room events containing encryption keys that we have received.\n * We track the total age so that we can later calculate the average age of all keys received.\n */\n roomEventEncryptionKeysReceivedTotalAge: number;\n };\n};\n\nexport const isMyMembership = (m: CallMembership, userId: string, deviceId: string): boolean =>\n m.sender === userId && m.deviceId === deviceId;\n\n/**\n * A RTC transport is a JSON object that describes how to connect to a RTC member.\n */\nexport interface Transport {\n type: string;\n [key: string]: unknown;\n}\n\n/**\n * Event content for `org.matrix.msc4143.rtc.slot` state events.\n */\nexport interface RtcSlotEventContent<T extends string = string> {\n status: \"open\" | \"closed\";\n application?: RtcSlotApplicationContent<T>;\n encryption?: RtcSlotEncryptionContent;\n}\n\n/**\n * Content of the `application` object within `org.matrix.msc4143.rtc.slot` events.\n */\nexport interface RtcSlotApplicationContent<T extends string = string> {\n type: T;\n // Other application specific keys.\n [key: string]: unknown;\n}\n\nexport const RTC_SLOT_ENCRYPTION_PER_MEMBER = \"org.matrix.msc4143.per_member\";\n\n/**\n * Content of the `encryption` object within `org.matrix.msc4143.rtc.slot` events.\n */\nexport interface RtcSlotEncryptionContent {\n type: typeof RTC_SLOT_ENCRYPTION_PER_MEMBER;\n // Other encryption-mechanism specific keys.\n [key: string]: unknown;\n}\n\n/**\n * The session description is used to identify a session. Used in the state event.\n */\nexport interface SlotDescription {\n /**\n * The application type. e.g. \"m.call\".\n */\n application: string;\n /**\n * The application-specific slot ID. e.g. \"ROOM\".\n */\n id: string;\n}\n"],"mappings":"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","ignoreList":[]}
@@ -23,6 +23,12 @@ export interface IRoomTimelineData {
23
23
  export interface IAddEventToTimelineOptions extends Pick<IAddEventOptions, "toStartOfTimeline" | "roomState" | "timelineWasEmpty" | "addToState"> {
24
24
  /** Whether the sync response came from cache */
25
25
  fromCache?: boolean;
26
+ /**
27
+ * The other events being added in the same batch. A relation whose parent is in the batch but not yet
28
+ * in a timeline (back-pagination adds newest first) is placed as its parent will be, rather than dropped
29
+ * as a relation to an unknown event.
30
+ */
31
+ batch?: MatrixEvent[];
26
32
  }
27
33
  export interface IAddLiveEventOptions extends Pick<IAddEventToTimelineOptions, "fromCache" | "roomState" | "timelineWasEmpty" | "addToState"> {
28
34
  /** Applies to events in the timeline only. If this is 'replace' then if a
@@ -238,7 +244,7 @@ export declare class EventTimelineSet extends TypedEventEmitter<EmittedEvents, E
238
244
  * @remarks
239
245
  * Fires {@link RoomEvent.Timeline}
240
246
  */
241
- addEventToTimeline(event: MatrixEvent, timeline: EventTimeline, { toStartOfTimeline, fromCache, roomState, timelineWasEmpty, addToState }: IAddEventToTimelineOptions): void;
247
+ addEventToTimeline(event: MatrixEvent, timeline: EventTimeline, { toStartOfTimeline, fromCache, roomState, timelineWasEmpty, addToState, batch, }: IAddEventToTimelineOptions): void;
242
248
  /**
243
249
  * Insert event to the given timeline, and emit Room.timeline. Assumes
244
250
  * we have already checked we don't know about this event.
@@ -299,10 +305,11 @@ export declare class EventTimelineSet extends TypedEventEmitter<EmittedEvents, E
299
305
  * Requires the `room` property to have been set at EventTimelineSet construction time.
300
306
  *
301
307
  * @param event - the event to check whether it belongs to this timeline set.
308
+ * @param batch - other events being added alongside, in which the event's parent may be found
302
309
  * @throws Error if `room` was not set when constructing this timeline set.
303
310
  * @returns whether the event belongs to this timeline set.
304
311
  */
305
- canContain(event: MatrixEvent): boolean;
312
+ canContain(event: MatrixEvent, batch?: MatrixEvent[]): boolean;
306
313
  }
307
314
  export {};
308
315
  //# sourceMappingURL=event-timeline-set.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"event-timeline-set.d.ts","sourceRoot":"","sources":["../../src/models/event-timeline-set.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"event-timeline-set.d.ts","sourceRoot":"","sources":["../../src/models/event-timeline-set.ts"],"names":[],"mappings":"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"}
@@ -377,7 +377,8 @@ export class EventTimelineSet extends TypedEventEmitter {
377
377
  // we don't know about this event yet. Just add it to the timeline.
378
378
  this.addEventToTimeline(event, timeline, {
379
379
  toStartOfTimeline,
380
- addToState
380
+ addToState,
381
+ batch: events
381
382
  });
382
383
  lastEventWasNew = true;
383
384
  didUpdate = true;
@@ -518,7 +519,8 @@ export class EventTimelineSet extends TypedEventEmitter {
518
519
  fromCache = false,
519
520
  roomState,
520
521
  timelineWasEmpty,
521
- addToState
522
+ addToState,
523
+ batch
522
524
  }) {
523
525
  if (timeline.getTimelineSet() !== this) {
524
526
  throw new Error(`EventTimelineSet.addEventToTimeline: Timeline=${timeline.toString()} does not belong " +
@@ -533,7 +535,7 @@ export class EventTimelineSet extends TypedEventEmitter {
533
535
  //
534
536
  // We can only run this check for timelines with a `room` because `canContain`
535
537
  // requires it
536
- if (this.room && !this.canContain(event)) {
538
+ if (this.room && !this.canContain(event, batch)) {
537
539
  let eventDebugString = `event=${eventId}`;
538
540
  if (event.threadRootId) {
539
541
  eventDebugString += `(belongs to thread=${event.threadRootId})`;
@@ -771,10 +773,11 @@ export class EventTimelineSet extends TypedEventEmitter {
771
773
  * Requires the `room` property to have been set at EventTimelineSet construction time.
772
774
  *
773
775
  * @param event - the event to check whether it belongs to this timeline set.
776
+ * @param batch - other events being added alongside, in which the event's parent may be found
774
777
  * @throws Error if `room` was not set when constructing this timeline set.
775
778
  * @returns whether the event belongs to this timeline set.
776
779
  */
777
- canContain(event) {
780
+ canContain(event, batch) {
778
781
  if (!this.room) {
779
782
  throw new Error("Cannot call `EventTimelineSet::canContain without a `room` set. " + "Set the room when creating the EventTimelineSet to call this method.");
780
783
  }
@@ -782,7 +785,7 @@ export class EventTimelineSet extends TypedEventEmitter {
782
785
  threadId,
783
786
  shouldLiveInRoom,
784
787
  shouldLiveInThread
785
- } = this.room.eventShouldLiveIn(event);
788
+ } = this.room.eventShouldLiveIn(event, batch);
786
789
  if (this.thread) {
787
790
  return this.thread.id === threadId;
788
791
  }
@@ -1 +1 @@
1
- {"version":3,"file":"event-timeline-set.js","names":[],"sources":["../../src/models/event-timeline-set.ts"],"sourcesContent":["/*\nCopyright 2016 - 2021 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 { EventTimeline, type IAddEventOptions } from \"./event-timeline.ts\";\nimport { type MatrixEvent } from \"./event.ts\";\nimport { logger } from \"../logger.ts\";\nimport { type Room, RoomEvent } from \"./room.ts\";\nimport { type Filter } from \"../filter.ts\";\nimport { type RoomState } from \"./room-state.ts\";\nimport { TypedEventEmitter } from \"./typed-event-emitter.ts\";\nimport { RelationsContainer } from \"./relations-container.ts\";\nimport { type MatrixClient } from \"../client.ts\";\nimport { type Thread, type ThreadFilterType } from \"./thread.ts\";\n\nconst DEBUG = true;\n\n/* istanbul ignore next */\nlet debuglog: (...args: any[]) => void;\nif (DEBUG) {\n // using bind means that we get to keep useful line numbers in the console\n debuglog = logger.log.bind(logger);\n} else {\n /* istanbul ignore next */\n debuglog = function (): void {};\n}\n\ninterface IOpts {\n // Set to true to enable improved timeline support.\n timelineSupport?: boolean;\n // The filter object, if any, for this timelineSet.\n filter?: Filter;\n pendingEvents?: boolean;\n}\n\nexport enum DuplicateStrategy {\n Ignore = \"ignore\",\n Replace = \"replace\",\n}\n\nexport interface IRoomTimelineData {\n // the timeline the event was added to/removed from\n timeline: EventTimeline;\n // true if the event was a real-time event added to the end of the live timeline\n liveEvent?: boolean;\n}\n\nexport interface IAddEventToTimelineOptions extends Pick<\n IAddEventOptions,\n \"toStartOfTimeline\" | \"roomState\" | \"timelineWasEmpty\" | \"addToState\"\n> {\n /** Whether the sync response came from cache */\n fromCache?: boolean;\n}\n\nexport interface IAddLiveEventOptions extends Pick<\n IAddEventToTimelineOptions,\n \"fromCache\" | \"roomState\" | \"timelineWasEmpty\" | \"addToState\"\n> {\n /** Applies to events in the timeline only. If this is 'replace' then if a\n * duplicate is encountered, the event passed to this function will replace\n * the existing event in the timeline. If this is not specified, or is\n * 'ignore', then the event passed to this function will be ignored\n * entirely, preserving the existing event in the timeline. Events are\n * identical based on their event ID <b>only</b>. */\n duplicateStrategy?: DuplicateStrategy;\n}\n\ntype EmittedEvents = RoomEvent.Timeline | RoomEvent.TimelineReset;\n\nexport type EventTimelineSetHandlerMap = {\n /**\n * Fires whenever the timeline in a room is updated.\n * @param event - The matrix event which caused this event to fire.\n * @param room - The room, if any, whose timeline was updated.\n * @param toStartOfTimeline - True if this event was added to the start\n * @param removed - True if this event has just been removed from the timeline\n * (beginning; oldest) of the timeline e.g. due to pagination.\n *\n * @param data - more data about the event\n *\n * @example\n * ```\n * matrixClient.on(\"Room.timeline\",\n * function(event, room, toStartOfTimeline, removed, data) {\n * if (!toStartOfTimeline && data.liveEvent) {\n * var messageToAppend = room.timeline.[room.timeline.length - 1];\n * }\n * });\n * ```\n */\n [RoomEvent.Timeline]: (\n event: MatrixEvent,\n room: Room | undefined,\n toStartOfTimeline: boolean | undefined,\n removed: boolean,\n data: IRoomTimelineData,\n ) => void;\n /**\n * Fires whenever the live timeline in a room is reset.\n *\n * When we get a 'limited' sync (for example, after a network outage), we reset\n * the live timeline to be empty before adding the recent events to the new\n * timeline. This event is fired after the timeline is reset, and before the\n * new events are added.\n *\n * @param room - The room whose live timeline was reset, if any\n * @param timelineSet - timelineSet room whose live timeline was reset\n * @param resetAllTimelines - True if all timelines were reset.\n */\n [RoomEvent.TimelineReset]: (\n room: Room | undefined,\n timelineSet: EventTimelineSet,\n resetAllTimelines: boolean,\n ) => void;\n};\n\nexport class EventTimelineSet extends TypedEventEmitter<EmittedEvents, EventTimelineSetHandlerMap> {\n public readonly relations: RelationsContainer;\n private readonly timelineSupport: boolean;\n private readonly displayPendingEvents: boolean;\n private liveTimeline: EventTimeline;\n private timelines: EventTimeline[];\n private _eventIdToTimeline = new Map<string, EventTimeline>();\n private filter?: Filter;\n\n /**\n * Construct a set of EventTimeline objects, typically on behalf of a given\n * room. A room may have multiple EventTimelineSets for different levels\n * of filtering. The global notification list is also an EventTimelineSet, but\n * lacks a room.\n *\n * <p>This is an ordered sequence of timelines, which may or may not\n * be continuous. Each timeline lists a series of events, as well as tracking\n * the room state at the start and the end of the timeline (if appropriate).\n * It also tracks forward and backward pagination tokens, as well as containing\n * links to the next timeline in the sequence.\n *\n * <p>There is one special timeline - the 'live' timeline, which represents the\n * timeline to which events are being added in real-time as they are received\n * from the /sync API. Note that you should not retain references to this\n * timeline - even if it is the current timeline right now, it may not remain\n * so if the server gives us a timeline gap in /sync.\n *\n * <p>In order that we can find events from their ids later, we also maintain a\n * map from event_id to timeline and index.\n *\n * @param room - Room for this timelineSet. May be null for non-room cases, such as the\n * notification timeline.\n * @param opts - Options inherited from Room.\n * @param client - the Matrix client which owns this EventTimelineSet,\n * can be omitted if room is specified.\n * @param thread - the thread to which this timeline set relates.\n * @param threadListType - the type of thread list represented, if any\n * (e.g., All threads or My threads)\n */\n public constructor(\n public readonly room: Room | undefined,\n opts: IOpts = {},\n client?: MatrixClient,\n public readonly thread?: Thread,\n public readonly threadListType: ThreadFilterType | null = null,\n ) {\n super();\n\n this.timelineSupport = Boolean(opts.timelineSupport);\n this.liveTimeline = new EventTimeline(this);\n this.displayPendingEvents = opts.pendingEvents !== false;\n\n // just a list - *not* ordered.\n this.timelines = [this.liveTimeline];\n this._eventIdToTimeline = new Map<string, EventTimeline>();\n\n this.filter = opts.filter;\n\n this.relations = this.room?.relations ?? new RelationsContainer(room?.client ?? client!);\n }\n\n /**\n * Get all the timelines in this set\n * @returns the timelines in this set\n */\n public getTimelines(): EventTimeline[] {\n return this.timelines;\n }\n\n /**\n * Get the filter object this timeline set is filtered on, if any\n * @returns the optional filter for this timelineSet\n */\n public getFilter(): Filter | undefined {\n return this.filter;\n }\n\n /**\n * Set the filter object this timeline set is filtered on\n * (passed to the server when paginating via /messages).\n * @param filter - the filter for this timelineSet\n */\n public setFilter(filter?: Filter): void {\n this.filter = filter;\n }\n\n /**\n * Get the list of pending sent events for this timelineSet's room, filtered\n * by the timelineSet's filter if appropriate.\n *\n * @returns A list of the sent events\n * waiting for remote echo.\n *\n * @throws If `opts.pendingEventOrdering` was not 'detached'\n */\n public getPendingEvents(): MatrixEvent[] {\n if (!this.room || !this.displayPendingEvents) {\n return [];\n }\n\n return this.room.getPendingEvents();\n }\n /**\n * Get the live timeline for this room.\n *\n * @returns live timeline\n */\n public getLiveTimeline(): EventTimeline {\n return this.liveTimeline;\n }\n\n /**\n * Set the live timeline for this room.\n *\n * @returns live timeline\n */\n public setLiveTimeline(timeline: EventTimeline): void {\n this.liveTimeline = timeline;\n }\n\n /**\n * Return the timeline (if any) this event is in.\n * @param eventId - the eventId being sought\n * @returns timeline\n */\n public eventIdToTimeline(eventId: string): EventTimeline | undefined {\n return this._eventIdToTimeline.get(eventId);\n }\n\n /**\n * Track a new event as if it were in the same timeline as an old event,\n * replacing it.\n * @param oldEventId - event ID of the original event\n * @param newEventId - event ID of the replacement event\n */\n public replaceEventId(oldEventId: string, newEventId: string): void {\n const existingTimeline = this._eventIdToTimeline.get(oldEventId);\n if (existingTimeline) {\n this._eventIdToTimeline.delete(oldEventId);\n this._eventIdToTimeline.set(newEventId, existingTimeline);\n }\n }\n\n /**\n * Reset the live timeline, and start a new one.\n *\n * <p>This is used when /sync returns a 'limited' timeline.\n *\n * @param backPaginationToken - token for back-paginating the new timeline\n * @param forwardPaginationToken - token for forward-paginating the old live timeline,\n * if absent or null, all timelines are reset.\n *\n * @remarks\n * Fires {@link RoomEvent.TimelineReset}\n */\n public resetLiveTimeline(backPaginationToken?: string, forwardPaginationToken?: string): void {\n // Each EventTimeline has RoomState objects tracking the state at the start\n // and end of that timeline. The copies at the end of the live timeline are\n // special because they will have listeners attached to monitor changes to\n // the current room state, so we move this RoomState from the end of the\n // current live timeline to the end of the new one and, if necessary,\n // replace it with a newly created one. We also make a copy for the start\n // of the new timeline.\n\n // if timeline support is disabled, forget about the old timelines\n const resetAllTimelines = !this.timelineSupport || !forwardPaginationToken;\n\n const oldTimeline = this.liveTimeline;\n const newTimeline = resetAllTimelines\n ? oldTimeline.forkLive(EventTimeline.FORWARDS)\n : oldTimeline.fork(EventTimeline.FORWARDS);\n\n if (resetAllTimelines) {\n this.timelines = [newTimeline];\n this._eventIdToTimeline = new Map<string, EventTimeline>();\n } else {\n this.timelines.push(newTimeline);\n }\n\n if (forwardPaginationToken) {\n // Now set the forward pagination token on the old live timeline\n // so it can be forward-paginated.\n oldTimeline.setPaginationToken(forwardPaginationToken, EventTimeline.FORWARDS);\n }\n\n // make sure we set the pagination token before firing timelineReset,\n // otherwise clients which start back-paginating will fail, and then get\n // stuck without realising that they *can* back-paginate.\n newTimeline.setPaginationToken(backPaginationToken ?? null, EventTimeline.BACKWARDS);\n\n // Now we can swap the live timeline to the new one.\n this.liveTimeline = newTimeline;\n this.emit(RoomEvent.TimelineReset, this.room, this, resetAllTimelines);\n }\n\n /**\n * Get the timeline which contains the given event, if any\n *\n * @param eventId - event ID to look for\n * @returns timeline containing\n * the given event, or null if unknown\n */\n public getTimelineForEvent(eventId?: string): EventTimeline | null {\n if (eventId === null || eventId === undefined) {\n return null;\n }\n const res = this._eventIdToTimeline.get(eventId);\n return res === undefined ? null : res;\n }\n\n /**\n * Get an event which is stored in our timelines\n *\n * @param eventId - event ID to look for\n * @returns the given event, or undefined if unknown\n */\n public findEventById(eventId: string): MatrixEvent | undefined {\n const tl = this.getTimelineForEvent(eventId);\n if (!tl) {\n return undefined;\n }\n return tl.getEvents().find(function (ev) {\n return ev.getId() == eventId;\n });\n }\n\n /**\n * Add a new timeline to this timeline list\n *\n * @returns newly-created timeline\n */\n public addTimeline(): EventTimeline {\n if (!this.timelineSupport) {\n throw new Error(\n \"timeline support is disabled. Set the 'timelineSupport'\" +\n \" parameter to true when creating MatrixClient to enable\" +\n \" it.\",\n );\n }\n\n const timeline = new EventTimeline(this);\n this.timelines.push(timeline);\n return timeline;\n }\n\n /**\n * Add events to a timeline\n *\n * <p>Will fire \"Room.timeline\" for each event added.\n *\n * @param events - A list of events to add.\n *\n * @param toStartOfTimeline - True to add these events to the start\n * (oldest) instead of the end (newest) of the timeline. If true, the oldest\n * event will be the <b>last</b> element of 'events'.\n *\n * @param timeline - timeline to\n * add events to.\n *\n * @param paginationToken - token for the next batch of events\n *\n * @remarks\n * Fires {@link RoomEvent.Timeline}\n *\n */\n public addEventsToTimeline(\n events: MatrixEvent[],\n toStartOfTimeline: boolean,\n addToState: boolean,\n timeline: EventTimeline,\n paginationToken?: string | null,\n ): void {\n if (!timeline) {\n throw new Error(\"'timeline' not specified for EventTimelineSet.addEventsToTimeline\");\n }\n\n if (!toStartOfTimeline && timeline == this.liveTimeline) {\n throw new Error(\n \"EventTimelineSet.addEventsToTimeline cannot be used for adding events to \" +\n \"the live timeline - use Room.addLiveEvents instead\",\n );\n }\n\n if (this.filter) {\n events = this.filter.filterRoomTimeline(events);\n if (!events.length) {\n return;\n }\n }\n\n const direction = toStartOfTimeline ? EventTimeline.BACKWARDS : EventTimeline.FORWARDS;\n const inverseDirection = toStartOfTimeline ? EventTimeline.FORWARDS : EventTimeline.BACKWARDS;\n\n // Adding events to timelines can be quite complicated. The following\n // illustrates some of the corner-cases.\n //\n // Let's say we start by knowing about four timelines. timeline3 and\n // timeline4 are neighbours:\n //\n // timeline1 timeline2 timeline3 timeline4\n // [M] [P] [S] <------> [T]\n //\n // Now we paginate timeline1, and get the following events from the server:\n // [M, N, P, R, S, T, U].\n //\n // 1. First, we ignore event M, since we already know about it.\n //\n // 2. Next, we append N to timeline 1.\n //\n // 3. Next, we don't add event P, since we already know about it,\n // but we do link together the timelines. We now have:\n //\n // timeline1 timeline2 timeline3 timeline4\n // [M, N] <---> [P] [S] <------> [T]\n //\n // 4. Now we add event R to timeline2:\n //\n // timeline1 timeline2 timeline3 timeline4\n // [M, N] <---> [P, R] [S] <------> [T]\n //\n // Note that we have switched the timeline we are working on from\n // timeline1 to timeline2.\n //\n // 5. We ignore event S, but again join the timelines:\n //\n // timeline1 timeline2 timeline3 timeline4\n // [M, N] <---> [P, R] <---> [S] <------> [T]\n //\n // 6. We ignore event T, and the timelines are already joined, so there\n // is nothing to do.\n //\n // 7. Finally, we add event U to timeline4:\n //\n // timeline1 timeline2 timeline3 timeline4\n // [M, N] <---> [P, R] <---> [S] <------> [T, U]\n //\n // The important thing to note in the above is what happened when we\n // already knew about a given event:\n //\n // - if it was appropriate, we joined up the timelines (steps 3, 5).\n // - in any case, we started adding further events to the timeline which\n // contained the event we knew about (steps 3, 5, 6).\n //\n //\n // So much for adding events to the timeline. But what do we want to do\n // with the pagination token?\n //\n // In the case above, we will be given a pagination token which tells us how to\n // get events beyond 'U' - in this case, it makes sense to store this\n // against timeline4. But what if timeline4 already had 'U' and beyond? in\n // that case, our best bet is to throw away the pagination token we were\n // given and stick with whatever token timeline4 had previously. In short,\n // we want to only store the pagination token if the last event we receive\n // is one we didn't previously know about.\n //\n // We make an exception for this if it turns out that we already knew about\n // *all* of the events, and we weren't able to join up any timelines. When\n // that happens, it means our existing pagination token is faulty, since it\n // is only telling us what we already know. Rather than repeatedly\n // paginating with the same token, we might as well use the new pagination\n // token in the hope that we eventually work our way out of the mess.\n\n let didUpdate = false;\n let lastEventWasNew = false;\n for (const event of events) {\n const eventId = event.getId()!;\n\n const existingTimeline = this._eventIdToTimeline.get(eventId);\n\n if (!existingTimeline) {\n // we don't know about this event yet. Just add it to the timeline.\n this.addEventToTimeline(event, timeline, {\n toStartOfTimeline,\n addToState,\n });\n lastEventWasNew = true;\n didUpdate = true;\n continue;\n }\n\n lastEventWasNew = false;\n\n if (existingTimeline == timeline) {\n debuglog(\"Event \" + eventId + \" already in timeline \" + timeline);\n continue;\n }\n\n const neighbour = timeline.getNeighbouringTimeline(direction);\n if (neighbour) {\n // this timeline already has a neighbour in the relevant direction;\n // let's assume the timelines are already correctly linked up, and\n // skip over to it.\n //\n // there's probably some edge-case here where we end up with an\n // event which is in a timeline a way down the chain, and there is\n // a break in the chain somewhere. But I can't really imagine how\n // that would happen, so I'm going to ignore it for now.\n //\n if (existingTimeline == neighbour) {\n debuglog(\"Event \" + eventId + \" in neighbouring timeline - switching to \" + existingTimeline);\n } else {\n debuglog(\"Event \" + eventId + \" already in a different timeline \" + existingTimeline);\n }\n timeline = existingTimeline;\n continue;\n }\n\n // time to join the timelines.\n logger.info(\n \"Already have timeline for \" + eventId + \" - joining timeline \" + timeline + \" to \" + existingTimeline,\n );\n\n // Variables to keep the line length limited below.\n const existingIsLive = existingTimeline === this.liveTimeline;\n const timelineIsLive = timeline === this.liveTimeline;\n\n const backwardsIsLive = direction === EventTimeline.BACKWARDS && existingIsLive;\n const forwardsIsLive = direction === EventTimeline.FORWARDS && timelineIsLive;\n\n if (backwardsIsLive || forwardsIsLive) {\n // The live timeline should never be spliced into a non-live position.\n // We use independent logging to better discover the problem at a glance.\n if (backwardsIsLive) {\n logger.warn(\n \"Refusing to set a preceding existingTimeLine on our \" +\n \"timeline as the existingTimeLine is live (\" +\n existingTimeline +\n \")\",\n );\n }\n if (forwardsIsLive) {\n logger.warn(\n \"Refusing to set our preceding timeline on a existingTimeLine \" +\n \"as our timeline is live (\" +\n timeline +\n \")\",\n );\n }\n continue; // abort splicing - try next event\n }\n\n timeline.setNeighbouringTimeline(existingTimeline, direction);\n existingTimeline.setNeighbouringTimeline(timeline, inverseDirection);\n\n timeline = existingTimeline;\n didUpdate = true;\n }\n\n // see above - if the last event was new to us, or if we didn't find any\n // new information, we update the pagination token for whatever\n // timeline we ended up on.\n if (lastEventWasNew || !didUpdate) {\n if (direction === EventTimeline.FORWARDS && timeline === this.liveTimeline) {\n logger.warn({ lastEventWasNew, didUpdate }); // for debugging\n logger.warn(\n `Refusing to set forwards pagination token of live timeline ${timeline} to ${paginationToken}`,\n );\n return;\n }\n timeline.setPaginationToken(paginationToken ?? null, direction);\n }\n }\n\n /**\n * Add an event to the end of this live timeline.\n *\n * @param event - Event to be added\n * @param options - addLiveEvent options\n */\n public addLiveEvent(\n event: MatrixEvent,\n { duplicateStrategy, fromCache, roomState, timelineWasEmpty, addToState }: IAddLiveEventOptions,\n ): void {\n if (this.filter) {\n const events = this.filter.filterRoomTimeline([event]);\n if (!events.length) {\n return;\n }\n }\n\n const timeline = this._eventIdToTimeline.get(event.getId()!);\n if (timeline) {\n if (duplicateStrategy === DuplicateStrategy.Replace) {\n debuglog(\"EventTimelineSet.addLiveEvent: replacing duplicate event \" + event.getId());\n const tlEvents = timeline.getEvents();\n for (let j = 0; j < tlEvents.length; j++) {\n if (tlEvents[j].getId() === event.getId()) {\n // still need to set the right metadata on this event\n if (!roomState) {\n roomState = timeline.getState(EventTimeline.FORWARDS);\n }\n EventTimeline.setEventMetadata(event, roomState!, false);\n tlEvents[j] = event;\n\n // XXX: we need to fire an event when this happens.\n break;\n }\n }\n } else {\n debuglog(\"EventTimelineSet.addLiveEvent: ignoring duplicate event \" + event.getId());\n }\n return;\n }\n\n this.addEventToTimeline(event, this.liveTimeline, {\n toStartOfTimeline: false,\n fromCache,\n roomState,\n timelineWasEmpty,\n addToState,\n });\n }\n\n /**\n * Add event to the given timeline, and emit Room.timeline. Assumes\n * we have already checked we don't know about this event.\n *\n * Will fire \"Room.timeline\" for each event added.\n *\n * @param event - the event to add\n * @param timeline - the timeline onto which to add it\n * @param options - addEventToTimeline options\n *\n * @remarks\n * Fires {@link RoomEvent.Timeline}\n */\n public addEventToTimeline(\n event: MatrixEvent,\n timeline: EventTimeline,\n { toStartOfTimeline, fromCache = false, roomState, timelineWasEmpty, addToState }: IAddEventToTimelineOptions,\n ): void {\n if (timeline.getTimelineSet() !== this) {\n throw new Error(`EventTimelineSet.addEventToTimeline: Timeline=${timeline.toString()} does not belong \" +\n \"in timelineSet(threadId=${this.thread?.id})`);\n }\n\n const eventId = event.getId()!;\n this.relations.aggregateParentEvent(event);\n this.relations.aggregateChildEvent(event, this);\n\n // Make sure events don't get mixed in timelines they shouldn't be in (e.g. a\n // threaded message should not be in the main timeline).\n //\n // We can only run this check for timelines with a `room` because `canContain`\n // requires it\n if (this.room && !this.canContain(event)) {\n let eventDebugString = `event=${eventId}`;\n if (event.threadRootId) {\n eventDebugString += `(belongs to thread=${event.threadRootId})`;\n }\n logger.warn(\n `EventTimelineSet.addEventToTimeline: Ignoring ${eventDebugString} that does not belong ` +\n `in timeline=${timeline.toString()} timelineSet(threadId=${this.thread?.id})`,\n );\n return;\n }\n\n timeline.addEvent(event, {\n toStartOfTimeline,\n roomState,\n timelineWasEmpty,\n addToState,\n });\n this._eventIdToTimeline.set(eventId, timeline);\n\n const data: IRoomTimelineData = {\n timeline: timeline,\n liveEvent: !toStartOfTimeline && timeline == this.liveTimeline && !fromCache,\n };\n this.emit(RoomEvent.Timeline, event, this.room, Boolean(toStartOfTimeline), false, data);\n }\n\n /**\n * Insert event to the given timeline, and emit Room.timeline. Assumes\n * we have already checked we don't know about this event.\n *\n * TEMPORARY: until we have recursive relations, we need this function\n * to exist to allow us to insert events in timeline order, which is our\n * best guess for Sync Order.\n * This is a copy of addEventToTimeline above, modified to insert the event\n * after the event it relates to, and before any event with a later\n * timestamp. This is our best guess at Sync Order.\n *\n * Will fire \"Room.timeline\" for each event added.\n *\n * @internal\n *\n * @remarks\n * Fires {@link RoomEvent.Timeline}\n */\n public insertEventIntoTimeline(\n event: MatrixEvent,\n timeline: EventTimeline,\n roomState: RoomState,\n addToState: boolean,\n ): void {\n if (timeline.getTimelineSet() !== this) {\n throw new Error(`EventTimelineSet.insertEventIntoTimeline: Timeline=${timeline.toString()} does not belong \" +\n \"in timelineSet(threadId=${this.thread?.id})`);\n }\n\n const eventId = event.getId()!;\n this.relations.aggregateParentEvent(event);\n this.relations.aggregateChildEvent(event, this);\n\n // Make sure events don't get mixed in timelines they shouldn't be in (e.g. a\n // threaded message should not be in the main timeline).\n //\n // We can only run this check for timelines with a `room` because `canContain`\n // requires it\n if (this.room && !this.canContain(event)) {\n let eventDebugString = `event=${eventId}`;\n if (event.threadRootId) {\n eventDebugString += `(belongs to thread=${event.threadRootId})`;\n }\n logger.warn(\n `EventTimelineSet.insertEventIntoTimeline: Ignoring ${eventDebugString} that does not belong ` +\n `in timeline=${timeline.toString()} timelineSet(threadId=${this.thread?.id})`,\n );\n return;\n }\n\n // Find the event that this event is related to - the \"parent\"\n const parentEventId = event.relationEventId;\n if (!parentEventId) {\n // Not related to anything - we just append\n this.addEventToTimeline(event, timeline, {\n toStartOfTimeline: false,\n fromCache: false,\n timelineWasEmpty: false,\n roomState,\n addToState,\n });\n return;\n }\n\n const parentEvent = this.findEventById(parentEventId);\n\n const timelineEvents = timeline.getEvents();\n\n // Start searching from the parent event, or if it's not loaded, start\n // at the beginning and insert purely using timestamp order.\n const parentIndex = parentEvent !== undefined ? timelineEvents.indexOf(parentEvent) : 0;\n let insertIndex = parentIndex;\n for (; insertIndex < timelineEvents.length; insertIndex++) {\n const nextEvent = timelineEvents[insertIndex];\n if (nextEvent.getTs() > event.getTs()) {\n // We found an event later than ours, so insert before that.\n break;\n }\n }\n // If we got to the end of the loop, insertIndex points at the end of\n // the list.\n\n timeline.insertEvent(event, insertIndex, roomState, addToState);\n this._eventIdToTimeline.set(eventId, timeline);\n\n const data: IRoomTimelineData = {\n timeline: timeline,\n // The purpose of this method is inserting events in the middle of the\n // timeline, so the events are, by definition, not live (whether or not\n // we're adding them to the live timeline).\n liveEvent: false,\n };\n this.emit(RoomEvent.Timeline, event, this.room, false, false, data);\n }\n\n /**\n * Replaces event with ID oldEventId with one with newEventId, if oldEventId is\n * recognised. Otherwise, add to the live timeline. Used to handle remote echos.\n *\n * @param localEvent - the new event to be added to the timeline\n * @param oldEventId - the ID of the original event\n * @param newEventId - the ID of the replacement event\n *\n * @remarks\n * Fires {@link RoomEvent.Timeline}\n */\n public handleRemoteEcho(localEvent: MatrixEvent, oldEventId: string, newEventId: string): void {\n // XXX: why don't we infer newEventId from localEvent?\n const existingTimeline = this._eventIdToTimeline.get(oldEventId);\n if (existingTimeline) {\n this._eventIdToTimeline.delete(oldEventId);\n this._eventIdToTimeline.set(newEventId, existingTimeline);\n } else if (!this.filter || this.filter.filterRoomTimeline([localEvent]).length) {\n this.addEventToTimeline(localEvent, this.liveTimeline, {\n toStartOfTimeline: false,\n addToState: false,\n });\n }\n }\n\n /**\n * Removes a single event from this room.\n *\n * @param eventId - The id of the event to remove\n *\n * @returns the removed event, or null if the event was not found\n * in this room.\n */\n public removeEvent(eventId: string): MatrixEvent | null {\n const timeline = this._eventIdToTimeline.get(eventId);\n if (!timeline) {\n return null;\n }\n\n const removed = timeline.removeEvent(eventId);\n if (removed) {\n this._eventIdToTimeline.delete(eventId);\n const data = {\n timeline: timeline,\n };\n this.emit(RoomEvent.Timeline, removed, this.room, undefined, true, data);\n }\n return removed;\n }\n\n /**\n * Determine where two events appear in the timeline relative to one another\n *\n * @param eventId1 - The id of the first event\n * @param eventId2 - The id of the second event\n\n * @returns -1 if eventId1 precedes eventId2, and +1 eventId1 succeeds\n * eventId2. 0 if they are the same event; null if we can't tell (either\n * because we don't know about one of the events, or because they are in\n * separate timelines which don't join up).\n */\n public compareEventOrdering(eventId1: string, eventId2: string): number | null {\n if (eventId1 == eventId2) {\n // optimise this case\n return 0;\n }\n\n const timeline1 = this._eventIdToTimeline.get(eventId1);\n const timeline2 = this._eventIdToTimeline.get(eventId2);\n\n if (timeline1 === undefined) {\n return null;\n }\n if (timeline2 === undefined) {\n return null;\n }\n\n if (timeline1 === timeline2) {\n // both events are in the same timeline - figure out their relative indices\n let idx1: number | undefined = undefined;\n let idx2: number | undefined = undefined;\n const events = timeline1.getEvents();\n for (let idx = 0; idx < events.length && (idx1 === undefined || idx2 === undefined); idx++) {\n const evId = events[idx].getId();\n if (evId == eventId1) {\n idx1 = idx;\n }\n if (evId == eventId2) {\n idx2 = idx;\n }\n }\n const difference = idx1! - idx2!;\n\n // Return the sign of difference.\n if (difference < 0) {\n return -1;\n } else if (difference > 0) {\n return 1;\n } else {\n return 0;\n }\n }\n\n // the events are in different timelines. Iterate through the\n // linkedlist to see which comes first.\n\n // first work forwards from timeline1\n let tl: EventTimeline | null = timeline1;\n while (tl) {\n if (tl === timeline2) {\n // timeline1 is before timeline2\n return -1;\n }\n tl = tl.getNeighbouringTimeline(EventTimeline.FORWARDS);\n }\n\n // now try backwards from timeline1\n tl = timeline1;\n while (tl) {\n if (tl === timeline2) {\n // timeline2 is before timeline1\n return 1;\n }\n tl = tl.getNeighbouringTimeline(EventTimeline.BACKWARDS);\n }\n\n // the timelines are not contiguous.\n return null;\n }\n\n /**\n * Determine whether a given event can sanely be added to this event timeline set,\n * for timeline sets relating to a thread, only return true for events in the same\n * thread timeline, for timeline sets not relating to a thread only return true\n * for events which should be shown in the main room timeline.\n * Requires the `room` property to have been set at EventTimelineSet construction time.\n *\n * @param event - the event to check whether it belongs to this timeline set.\n * @throws Error if `room` was not set when constructing this timeline set.\n * @returns whether the event belongs to this timeline set.\n */\n public canContain(event: MatrixEvent): boolean {\n if (!this.room) {\n throw new Error(\n \"Cannot call `EventTimelineSet::canContain without a `room` set. \" +\n \"Set the room when creating the EventTimelineSet to call this method.\",\n );\n }\n\n const { threadId, shouldLiveInRoom, shouldLiveInThread } = this.room.eventShouldLiveIn(event);\n\n if (this.thread) {\n return this.thread.id === threadId;\n }\n\n if (!shouldLiveInRoom && !shouldLiveInThread) {\n logger.warn(\n `EventTimelineSet:canContain event encountered which cannot be added to any timeline roomId=${\n this.room?.roomId\n } eventId=${event.getId()} threadId=${event.threadRootId}`,\n );\n }\n\n return shouldLiveInRoom;\n }\n}\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"event-timeline-set.js","names":[],"sources":["../../src/models/event-timeline-set.ts"],"sourcesContent":["/*\nCopyright 2016 - 2021 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 { EventTimeline, type IAddEventOptions } from \"./event-timeline.ts\";\nimport { type MatrixEvent } from \"./event.ts\";\nimport { logger } from \"../logger.ts\";\nimport { type Room, RoomEvent } from \"./room.ts\";\nimport { type Filter } from \"../filter.ts\";\nimport { type RoomState } from \"./room-state.ts\";\nimport { TypedEventEmitter } from \"./typed-event-emitter.ts\";\nimport { RelationsContainer } from \"./relations-container.ts\";\nimport { type MatrixClient } from \"../client.ts\";\nimport { type Thread, type ThreadFilterType } from \"./thread.ts\";\n\nconst DEBUG = true;\n\n/* istanbul ignore next */\nlet debuglog: (...args: any[]) => void;\nif (DEBUG) {\n // using bind means that we get to keep useful line numbers in the console\n debuglog = logger.log.bind(logger);\n} else {\n /* istanbul ignore next */\n debuglog = function (): void {};\n}\n\ninterface IOpts {\n // Set to true to enable improved timeline support.\n timelineSupport?: boolean;\n // The filter object, if any, for this timelineSet.\n filter?: Filter;\n pendingEvents?: boolean;\n}\n\nexport enum DuplicateStrategy {\n Ignore = \"ignore\",\n Replace = \"replace\",\n}\n\nexport interface IRoomTimelineData {\n // the timeline the event was added to/removed from\n timeline: EventTimeline;\n // true if the event was a real-time event added to the end of the live timeline\n liveEvent?: boolean;\n}\n\nexport interface IAddEventToTimelineOptions extends Pick<\n IAddEventOptions,\n \"toStartOfTimeline\" | \"roomState\" | \"timelineWasEmpty\" | \"addToState\"\n> {\n /** Whether the sync response came from cache */\n fromCache?: boolean;\n /**\n * The other events being added in the same batch. A relation whose parent is in the batch but not yet\n * in a timeline (back-pagination adds newest first) is placed as its parent will be, rather than dropped\n * as a relation to an unknown event.\n */\n batch?: MatrixEvent[];\n}\n\nexport interface IAddLiveEventOptions extends Pick<\n IAddEventToTimelineOptions,\n \"fromCache\" | \"roomState\" | \"timelineWasEmpty\" | \"addToState\"\n> {\n /** Applies to events in the timeline only. If this is 'replace' then if a\n * duplicate is encountered, the event passed to this function will replace\n * the existing event in the timeline. If this is not specified, or is\n * 'ignore', then the event passed to this function will be ignored\n * entirely, preserving the existing event in the timeline. Events are\n * identical based on their event ID <b>only</b>. */\n duplicateStrategy?: DuplicateStrategy;\n}\n\ntype EmittedEvents = RoomEvent.Timeline | RoomEvent.TimelineReset;\n\nexport type EventTimelineSetHandlerMap = {\n /**\n * Fires whenever the timeline in a room is updated.\n * @param event - The matrix event which caused this event to fire.\n * @param room - The room, if any, whose timeline was updated.\n * @param toStartOfTimeline - True if this event was added to the start\n * @param removed - True if this event has just been removed from the timeline\n * (beginning; oldest) of the timeline e.g. due to pagination.\n *\n * @param data - more data about the event\n *\n * @example\n * ```\n * matrixClient.on(\"Room.timeline\",\n * function(event, room, toStartOfTimeline, removed, data) {\n * if (!toStartOfTimeline && data.liveEvent) {\n * var messageToAppend = room.timeline.[room.timeline.length - 1];\n * }\n * });\n * ```\n */\n [RoomEvent.Timeline]: (\n event: MatrixEvent,\n room: Room | undefined,\n toStartOfTimeline: boolean | undefined,\n removed: boolean,\n data: IRoomTimelineData,\n ) => void;\n /**\n * Fires whenever the live timeline in a room is reset.\n *\n * When we get a 'limited' sync (for example, after a network outage), we reset\n * the live timeline to be empty before adding the recent events to the new\n * timeline. This event is fired after the timeline is reset, and before the\n * new events are added.\n *\n * @param room - The room whose live timeline was reset, if any\n * @param timelineSet - timelineSet room whose live timeline was reset\n * @param resetAllTimelines - True if all timelines were reset.\n */\n [RoomEvent.TimelineReset]: (\n room: Room | undefined,\n timelineSet: EventTimelineSet,\n resetAllTimelines: boolean,\n ) => void;\n};\n\nexport class EventTimelineSet extends TypedEventEmitter<EmittedEvents, EventTimelineSetHandlerMap> {\n public readonly relations: RelationsContainer;\n private readonly timelineSupport: boolean;\n private readonly displayPendingEvents: boolean;\n private liveTimeline: EventTimeline;\n private timelines: EventTimeline[];\n private _eventIdToTimeline = new Map<string, EventTimeline>();\n private filter?: Filter;\n\n /**\n * Construct a set of EventTimeline objects, typically on behalf of a given\n * room. A room may have multiple EventTimelineSets for different levels\n * of filtering. The global notification list is also an EventTimelineSet, but\n * lacks a room.\n *\n * <p>This is an ordered sequence of timelines, which may or may not\n * be continuous. Each timeline lists a series of events, as well as tracking\n * the room state at the start and the end of the timeline (if appropriate).\n * It also tracks forward and backward pagination tokens, as well as containing\n * links to the next timeline in the sequence.\n *\n * <p>There is one special timeline - the 'live' timeline, which represents the\n * timeline to which events are being added in real-time as they are received\n * from the /sync API. Note that you should not retain references to this\n * timeline - even if it is the current timeline right now, it may not remain\n * so if the server gives us a timeline gap in /sync.\n *\n * <p>In order that we can find events from their ids later, we also maintain a\n * map from event_id to timeline and index.\n *\n * @param room - Room for this timelineSet. May be null for non-room cases, such as the\n * notification timeline.\n * @param opts - Options inherited from Room.\n * @param client - the Matrix client which owns this EventTimelineSet,\n * can be omitted if room is specified.\n * @param thread - the thread to which this timeline set relates.\n * @param threadListType - the type of thread list represented, if any\n * (e.g., All threads or My threads)\n */\n public constructor(\n public readonly room: Room | undefined,\n opts: IOpts = {},\n client?: MatrixClient,\n public readonly thread?: Thread,\n public readonly threadListType: ThreadFilterType | null = null,\n ) {\n super();\n\n this.timelineSupport = Boolean(opts.timelineSupport);\n this.liveTimeline = new EventTimeline(this);\n this.displayPendingEvents = opts.pendingEvents !== false;\n\n // just a list - *not* ordered.\n this.timelines = [this.liveTimeline];\n this._eventIdToTimeline = new Map<string, EventTimeline>();\n\n this.filter = opts.filter;\n\n this.relations = this.room?.relations ?? new RelationsContainer(room?.client ?? client!);\n }\n\n /**\n * Get all the timelines in this set\n * @returns the timelines in this set\n */\n public getTimelines(): EventTimeline[] {\n return this.timelines;\n }\n\n /**\n * Get the filter object this timeline set is filtered on, if any\n * @returns the optional filter for this timelineSet\n */\n public getFilter(): Filter | undefined {\n return this.filter;\n }\n\n /**\n * Set the filter object this timeline set is filtered on\n * (passed to the server when paginating via /messages).\n * @param filter - the filter for this timelineSet\n */\n public setFilter(filter?: Filter): void {\n this.filter = filter;\n }\n\n /**\n * Get the list of pending sent events for this timelineSet's room, filtered\n * by the timelineSet's filter if appropriate.\n *\n * @returns A list of the sent events\n * waiting for remote echo.\n *\n * @throws If `opts.pendingEventOrdering` was not 'detached'\n */\n public getPendingEvents(): MatrixEvent[] {\n if (!this.room || !this.displayPendingEvents) {\n return [];\n }\n\n return this.room.getPendingEvents();\n }\n /**\n * Get the live timeline for this room.\n *\n * @returns live timeline\n */\n public getLiveTimeline(): EventTimeline {\n return this.liveTimeline;\n }\n\n /**\n * Set the live timeline for this room.\n *\n * @returns live timeline\n */\n public setLiveTimeline(timeline: EventTimeline): void {\n this.liveTimeline = timeline;\n }\n\n /**\n * Return the timeline (if any) this event is in.\n * @param eventId - the eventId being sought\n * @returns timeline\n */\n public eventIdToTimeline(eventId: string): EventTimeline | undefined {\n return this._eventIdToTimeline.get(eventId);\n }\n\n /**\n * Track a new event as if it were in the same timeline as an old event,\n * replacing it.\n * @param oldEventId - event ID of the original event\n * @param newEventId - event ID of the replacement event\n */\n public replaceEventId(oldEventId: string, newEventId: string): void {\n const existingTimeline = this._eventIdToTimeline.get(oldEventId);\n if (existingTimeline) {\n this._eventIdToTimeline.delete(oldEventId);\n this._eventIdToTimeline.set(newEventId, existingTimeline);\n }\n }\n\n /**\n * Reset the live timeline, and start a new one.\n *\n * <p>This is used when /sync returns a 'limited' timeline.\n *\n * @param backPaginationToken - token for back-paginating the new timeline\n * @param forwardPaginationToken - token for forward-paginating the old live timeline,\n * if absent or null, all timelines are reset.\n *\n * @remarks\n * Fires {@link RoomEvent.TimelineReset}\n */\n public resetLiveTimeline(backPaginationToken?: string, forwardPaginationToken?: string): void {\n // Each EventTimeline has RoomState objects tracking the state at the start\n // and end of that timeline. The copies at the end of the live timeline are\n // special because they will have listeners attached to monitor changes to\n // the current room state, so we move this RoomState from the end of the\n // current live timeline to the end of the new one and, if necessary,\n // replace it with a newly created one. We also make a copy for the start\n // of the new timeline.\n\n // if timeline support is disabled, forget about the old timelines\n const resetAllTimelines = !this.timelineSupport || !forwardPaginationToken;\n\n const oldTimeline = this.liveTimeline;\n const newTimeline = resetAllTimelines\n ? oldTimeline.forkLive(EventTimeline.FORWARDS)\n : oldTimeline.fork(EventTimeline.FORWARDS);\n\n if (resetAllTimelines) {\n this.timelines = [newTimeline];\n this._eventIdToTimeline = new Map<string, EventTimeline>();\n } else {\n this.timelines.push(newTimeline);\n }\n\n if (forwardPaginationToken) {\n // Now set the forward pagination token on the old live timeline\n // so it can be forward-paginated.\n oldTimeline.setPaginationToken(forwardPaginationToken, EventTimeline.FORWARDS);\n }\n\n // make sure we set the pagination token before firing timelineReset,\n // otherwise clients which start back-paginating will fail, and then get\n // stuck without realising that they *can* back-paginate.\n newTimeline.setPaginationToken(backPaginationToken ?? null, EventTimeline.BACKWARDS);\n\n // Now we can swap the live timeline to the new one.\n this.liveTimeline = newTimeline;\n this.emit(RoomEvent.TimelineReset, this.room, this, resetAllTimelines);\n }\n\n /**\n * Get the timeline which contains the given event, if any\n *\n * @param eventId - event ID to look for\n * @returns timeline containing\n * the given event, or null if unknown\n */\n public getTimelineForEvent(eventId?: string): EventTimeline | null {\n if (eventId === null || eventId === undefined) {\n return null;\n }\n const res = this._eventIdToTimeline.get(eventId);\n return res === undefined ? null : res;\n }\n\n /**\n * Get an event which is stored in our timelines\n *\n * @param eventId - event ID to look for\n * @returns the given event, or undefined if unknown\n */\n public findEventById(eventId: string): MatrixEvent | undefined {\n const tl = this.getTimelineForEvent(eventId);\n if (!tl) {\n return undefined;\n }\n return tl.getEvents().find(function (ev) {\n return ev.getId() == eventId;\n });\n }\n\n /**\n * Add a new timeline to this timeline list\n *\n * @returns newly-created timeline\n */\n public addTimeline(): EventTimeline {\n if (!this.timelineSupport) {\n throw new Error(\n \"timeline support is disabled. Set the 'timelineSupport'\" +\n \" parameter to true when creating MatrixClient to enable\" +\n \" it.\",\n );\n }\n\n const timeline = new EventTimeline(this);\n this.timelines.push(timeline);\n return timeline;\n }\n\n /**\n * Add events to a timeline\n *\n * <p>Will fire \"Room.timeline\" for each event added.\n *\n * @param events - A list of events to add.\n *\n * @param toStartOfTimeline - True to add these events to the start\n * (oldest) instead of the end (newest) of the timeline. If true, the oldest\n * event will be the <b>last</b> element of 'events'.\n *\n * @param timeline - timeline to\n * add events to.\n *\n * @param paginationToken - token for the next batch of events\n *\n * @remarks\n * Fires {@link RoomEvent.Timeline}\n *\n */\n public addEventsToTimeline(\n events: MatrixEvent[],\n toStartOfTimeline: boolean,\n addToState: boolean,\n timeline: EventTimeline,\n paginationToken?: string | null,\n ): void {\n if (!timeline) {\n throw new Error(\"'timeline' not specified for EventTimelineSet.addEventsToTimeline\");\n }\n\n if (!toStartOfTimeline && timeline == this.liveTimeline) {\n throw new Error(\n \"EventTimelineSet.addEventsToTimeline cannot be used for adding events to \" +\n \"the live timeline - use Room.addLiveEvents instead\",\n );\n }\n\n if (this.filter) {\n events = this.filter.filterRoomTimeline(events);\n if (!events.length) {\n return;\n }\n }\n\n const direction = toStartOfTimeline ? EventTimeline.BACKWARDS : EventTimeline.FORWARDS;\n const inverseDirection = toStartOfTimeline ? EventTimeline.FORWARDS : EventTimeline.BACKWARDS;\n\n // Adding events to timelines can be quite complicated. The following\n // illustrates some of the corner-cases.\n //\n // Let's say we start by knowing about four timelines. timeline3 and\n // timeline4 are neighbours:\n //\n // timeline1 timeline2 timeline3 timeline4\n // [M] [P] [S] <------> [T]\n //\n // Now we paginate timeline1, and get the following events from the server:\n // [M, N, P, R, S, T, U].\n //\n // 1. First, we ignore event M, since we already know about it.\n //\n // 2. Next, we append N to timeline 1.\n //\n // 3. Next, we don't add event P, since we already know about it,\n // but we do link together the timelines. We now have:\n //\n // timeline1 timeline2 timeline3 timeline4\n // [M, N] <---> [P] [S] <------> [T]\n //\n // 4. Now we add event R to timeline2:\n //\n // timeline1 timeline2 timeline3 timeline4\n // [M, N] <---> [P, R] [S] <------> [T]\n //\n // Note that we have switched the timeline we are working on from\n // timeline1 to timeline2.\n //\n // 5. We ignore event S, but again join the timelines:\n //\n // timeline1 timeline2 timeline3 timeline4\n // [M, N] <---> [P, R] <---> [S] <------> [T]\n //\n // 6. We ignore event T, and the timelines are already joined, so there\n // is nothing to do.\n //\n // 7. Finally, we add event U to timeline4:\n //\n // timeline1 timeline2 timeline3 timeline4\n // [M, N] <---> [P, R] <---> [S] <------> [T, U]\n //\n // The important thing to note in the above is what happened when we\n // already knew about a given event:\n //\n // - if it was appropriate, we joined up the timelines (steps 3, 5).\n // - in any case, we started adding further events to the timeline which\n // contained the event we knew about (steps 3, 5, 6).\n //\n //\n // So much for adding events to the timeline. But what do we want to do\n // with the pagination token?\n //\n // In the case above, we will be given a pagination token which tells us how to\n // get events beyond 'U' - in this case, it makes sense to store this\n // against timeline4. But what if timeline4 already had 'U' and beyond? in\n // that case, our best bet is to throw away the pagination token we were\n // given and stick with whatever token timeline4 had previously. In short,\n // we want to only store the pagination token if the last event we receive\n // is one we didn't previously know about.\n //\n // We make an exception for this if it turns out that we already knew about\n // *all* of the events, and we weren't able to join up any timelines. When\n // that happens, it means our existing pagination token is faulty, since it\n // is only telling us what we already know. Rather than repeatedly\n // paginating with the same token, we might as well use the new pagination\n // token in the hope that we eventually work our way out of the mess.\n\n let didUpdate = false;\n let lastEventWasNew = false;\n for (const event of events) {\n const eventId = event.getId()!;\n\n const existingTimeline = this._eventIdToTimeline.get(eventId);\n\n if (!existingTimeline) {\n // we don't know about this event yet. Just add it to the timeline.\n this.addEventToTimeline(event, timeline, {\n toStartOfTimeline,\n addToState,\n batch: events,\n });\n lastEventWasNew = true;\n didUpdate = true;\n continue;\n }\n\n lastEventWasNew = false;\n\n if (existingTimeline == timeline) {\n debuglog(\"Event \" + eventId + \" already in timeline \" + timeline);\n continue;\n }\n\n const neighbour = timeline.getNeighbouringTimeline(direction);\n if (neighbour) {\n // this timeline already has a neighbour in the relevant direction;\n // let's assume the timelines are already correctly linked up, and\n // skip over to it.\n //\n // there's probably some edge-case here where we end up with an\n // event which is in a timeline a way down the chain, and there is\n // a break in the chain somewhere. But I can't really imagine how\n // that would happen, so I'm going to ignore it for now.\n //\n if (existingTimeline == neighbour) {\n debuglog(\"Event \" + eventId + \" in neighbouring timeline - switching to \" + existingTimeline);\n } else {\n debuglog(\"Event \" + eventId + \" already in a different timeline \" + existingTimeline);\n }\n timeline = existingTimeline;\n continue;\n }\n\n // time to join the timelines.\n logger.info(\n \"Already have timeline for \" + eventId + \" - joining timeline \" + timeline + \" to \" + existingTimeline,\n );\n\n // Variables to keep the line length limited below.\n const existingIsLive = existingTimeline === this.liveTimeline;\n const timelineIsLive = timeline === this.liveTimeline;\n\n const backwardsIsLive = direction === EventTimeline.BACKWARDS && existingIsLive;\n const forwardsIsLive = direction === EventTimeline.FORWARDS && timelineIsLive;\n\n if (backwardsIsLive || forwardsIsLive) {\n // The live timeline should never be spliced into a non-live position.\n // We use independent logging to better discover the problem at a glance.\n if (backwardsIsLive) {\n logger.warn(\n \"Refusing to set a preceding existingTimeLine on our \" +\n \"timeline as the existingTimeLine is live (\" +\n existingTimeline +\n \")\",\n );\n }\n if (forwardsIsLive) {\n logger.warn(\n \"Refusing to set our preceding timeline on a existingTimeLine \" +\n \"as our timeline is live (\" +\n timeline +\n \")\",\n );\n }\n continue; // abort splicing - try next event\n }\n\n timeline.setNeighbouringTimeline(existingTimeline, direction);\n existingTimeline.setNeighbouringTimeline(timeline, inverseDirection);\n\n timeline = existingTimeline;\n didUpdate = true;\n }\n\n // see above - if the last event was new to us, or if we didn't find any\n // new information, we update the pagination token for whatever\n // timeline we ended up on.\n if (lastEventWasNew || !didUpdate) {\n if (direction === EventTimeline.FORWARDS && timeline === this.liveTimeline) {\n logger.warn({ lastEventWasNew, didUpdate }); // for debugging\n logger.warn(\n `Refusing to set forwards pagination token of live timeline ${timeline} to ${paginationToken}`,\n );\n return;\n }\n timeline.setPaginationToken(paginationToken ?? null, direction);\n }\n }\n\n /**\n * Add an event to the end of this live timeline.\n *\n * @param event - Event to be added\n * @param options - addLiveEvent options\n */\n public addLiveEvent(\n event: MatrixEvent,\n { duplicateStrategy, fromCache, roomState, timelineWasEmpty, addToState }: IAddLiveEventOptions,\n ): void {\n if (this.filter) {\n const events = this.filter.filterRoomTimeline([event]);\n if (!events.length) {\n return;\n }\n }\n\n const timeline = this._eventIdToTimeline.get(event.getId()!);\n if (timeline) {\n if (duplicateStrategy === DuplicateStrategy.Replace) {\n debuglog(\"EventTimelineSet.addLiveEvent: replacing duplicate event \" + event.getId());\n const tlEvents = timeline.getEvents();\n for (let j = 0; j < tlEvents.length; j++) {\n if (tlEvents[j].getId() === event.getId()) {\n // still need to set the right metadata on this event\n if (!roomState) {\n roomState = timeline.getState(EventTimeline.FORWARDS);\n }\n EventTimeline.setEventMetadata(event, roomState!, false);\n tlEvents[j] = event;\n\n // XXX: we need to fire an event when this happens.\n break;\n }\n }\n } else {\n debuglog(\"EventTimelineSet.addLiveEvent: ignoring duplicate event \" + event.getId());\n }\n return;\n }\n\n this.addEventToTimeline(event, this.liveTimeline, {\n toStartOfTimeline: false,\n fromCache,\n roomState,\n timelineWasEmpty,\n addToState,\n });\n }\n\n /**\n * Add event to the given timeline, and emit Room.timeline. Assumes\n * we have already checked we don't know about this event.\n *\n * Will fire \"Room.timeline\" for each event added.\n *\n * @param event - the event to add\n * @param timeline - the timeline onto which to add it\n * @param options - addEventToTimeline options\n *\n * @remarks\n * Fires {@link RoomEvent.Timeline}\n */\n public addEventToTimeline(\n event: MatrixEvent,\n timeline: EventTimeline,\n {\n toStartOfTimeline,\n fromCache = false,\n roomState,\n timelineWasEmpty,\n addToState,\n batch,\n }: IAddEventToTimelineOptions,\n ): void {\n if (timeline.getTimelineSet() !== this) {\n throw new Error(`EventTimelineSet.addEventToTimeline: Timeline=${timeline.toString()} does not belong \" +\n \"in timelineSet(threadId=${this.thread?.id})`);\n }\n\n const eventId = event.getId()!;\n this.relations.aggregateParentEvent(event);\n this.relations.aggregateChildEvent(event, this);\n\n // Make sure events don't get mixed in timelines they shouldn't be in (e.g. a\n // threaded message should not be in the main timeline).\n //\n // We can only run this check for timelines with a `room` because `canContain`\n // requires it\n if (this.room && !this.canContain(event, batch)) {\n let eventDebugString = `event=${eventId}`;\n if (event.threadRootId) {\n eventDebugString += `(belongs to thread=${event.threadRootId})`;\n }\n logger.warn(\n `EventTimelineSet.addEventToTimeline: Ignoring ${eventDebugString} that does not belong ` +\n `in timeline=${timeline.toString()} timelineSet(threadId=${this.thread?.id})`,\n );\n return;\n }\n\n timeline.addEvent(event, {\n toStartOfTimeline,\n roomState,\n timelineWasEmpty,\n addToState,\n });\n this._eventIdToTimeline.set(eventId, timeline);\n\n const data: IRoomTimelineData = {\n timeline: timeline,\n liveEvent: !toStartOfTimeline && timeline == this.liveTimeline && !fromCache,\n };\n this.emit(RoomEvent.Timeline, event, this.room, Boolean(toStartOfTimeline), false, data);\n }\n\n /**\n * Insert event to the given timeline, and emit Room.timeline. Assumes\n * we have already checked we don't know about this event.\n *\n * TEMPORARY: until we have recursive relations, we need this function\n * to exist to allow us to insert events in timeline order, which is our\n * best guess for Sync Order.\n * This is a copy of addEventToTimeline above, modified to insert the event\n * after the event it relates to, and before any event with a later\n * timestamp. This is our best guess at Sync Order.\n *\n * Will fire \"Room.timeline\" for each event added.\n *\n * @internal\n *\n * @remarks\n * Fires {@link RoomEvent.Timeline}\n */\n public insertEventIntoTimeline(\n event: MatrixEvent,\n timeline: EventTimeline,\n roomState: RoomState,\n addToState: boolean,\n ): void {\n if (timeline.getTimelineSet() !== this) {\n throw new Error(`EventTimelineSet.insertEventIntoTimeline: Timeline=${timeline.toString()} does not belong \" +\n \"in timelineSet(threadId=${this.thread?.id})`);\n }\n\n const eventId = event.getId()!;\n this.relations.aggregateParentEvent(event);\n this.relations.aggregateChildEvent(event, this);\n\n // Make sure events don't get mixed in timelines they shouldn't be in (e.g. a\n // threaded message should not be in the main timeline).\n //\n // We can only run this check for timelines with a `room` because `canContain`\n // requires it\n if (this.room && !this.canContain(event)) {\n let eventDebugString = `event=${eventId}`;\n if (event.threadRootId) {\n eventDebugString += `(belongs to thread=${event.threadRootId})`;\n }\n logger.warn(\n `EventTimelineSet.insertEventIntoTimeline: Ignoring ${eventDebugString} that does not belong ` +\n `in timeline=${timeline.toString()} timelineSet(threadId=${this.thread?.id})`,\n );\n return;\n }\n\n // Find the event that this event is related to - the \"parent\"\n const parentEventId = event.relationEventId;\n if (!parentEventId) {\n // Not related to anything - we just append\n this.addEventToTimeline(event, timeline, {\n toStartOfTimeline: false,\n fromCache: false,\n timelineWasEmpty: false,\n roomState,\n addToState,\n });\n return;\n }\n\n const parentEvent = this.findEventById(parentEventId);\n\n const timelineEvents = timeline.getEvents();\n\n // Start searching from the parent event, or if it's not loaded, start\n // at the beginning and insert purely using timestamp order.\n const parentIndex = parentEvent !== undefined ? timelineEvents.indexOf(parentEvent) : 0;\n let insertIndex = parentIndex;\n for (; insertIndex < timelineEvents.length; insertIndex++) {\n const nextEvent = timelineEvents[insertIndex];\n if (nextEvent.getTs() > event.getTs()) {\n // We found an event later than ours, so insert before that.\n break;\n }\n }\n // If we got to the end of the loop, insertIndex points at the end of\n // the list.\n\n timeline.insertEvent(event, insertIndex, roomState, addToState);\n this._eventIdToTimeline.set(eventId, timeline);\n\n const data: IRoomTimelineData = {\n timeline: timeline,\n // The purpose of this method is inserting events in the middle of the\n // timeline, so the events are, by definition, not live (whether or not\n // we're adding them to the live timeline).\n liveEvent: false,\n };\n this.emit(RoomEvent.Timeline, event, this.room, false, false, data);\n }\n\n /**\n * Replaces event with ID oldEventId with one with newEventId, if oldEventId is\n * recognised. Otherwise, add to the live timeline. Used to handle remote echos.\n *\n * @param localEvent - the new event to be added to the timeline\n * @param oldEventId - the ID of the original event\n * @param newEventId - the ID of the replacement event\n *\n * @remarks\n * Fires {@link RoomEvent.Timeline}\n */\n public handleRemoteEcho(localEvent: MatrixEvent, oldEventId: string, newEventId: string): void {\n // XXX: why don't we infer newEventId from localEvent?\n const existingTimeline = this._eventIdToTimeline.get(oldEventId);\n if (existingTimeline) {\n this._eventIdToTimeline.delete(oldEventId);\n this._eventIdToTimeline.set(newEventId, existingTimeline);\n } else if (!this.filter || this.filter.filterRoomTimeline([localEvent]).length) {\n this.addEventToTimeline(localEvent, this.liveTimeline, {\n toStartOfTimeline: false,\n addToState: false,\n });\n }\n }\n\n /**\n * Removes a single event from this room.\n *\n * @param eventId - The id of the event to remove\n *\n * @returns the removed event, or null if the event was not found\n * in this room.\n */\n public removeEvent(eventId: string): MatrixEvent | null {\n const timeline = this._eventIdToTimeline.get(eventId);\n if (!timeline) {\n return null;\n }\n\n const removed = timeline.removeEvent(eventId);\n if (removed) {\n this._eventIdToTimeline.delete(eventId);\n const data = {\n timeline: timeline,\n };\n this.emit(RoomEvent.Timeline, removed, this.room, undefined, true, data);\n }\n return removed;\n }\n\n /**\n * Determine where two events appear in the timeline relative to one another\n *\n * @param eventId1 - The id of the first event\n * @param eventId2 - The id of the second event\n\n * @returns -1 if eventId1 precedes eventId2, and +1 eventId1 succeeds\n * eventId2. 0 if they are the same event; null if we can't tell (either\n * because we don't know about one of the events, or because they are in\n * separate timelines which don't join up).\n */\n public compareEventOrdering(eventId1: string, eventId2: string): number | null {\n if (eventId1 == eventId2) {\n // optimise this case\n return 0;\n }\n\n const timeline1 = this._eventIdToTimeline.get(eventId1);\n const timeline2 = this._eventIdToTimeline.get(eventId2);\n\n if (timeline1 === undefined) {\n return null;\n }\n if (timeline2 === undefined) {\n return null;\n }\n\n if (timeline1 === timeline2) {\n // both events are in the same timeline - figure out their relative indices\n let idx1: number | undefined = undefined;\n let idx2: number | undefined = undefined;\n const events = timeline1.getEvents();\n for (let idx = 0; idx < events.length && (idx1 === undefined || idx2 === undefined); idx++) {\n const evId = events[idx].getId();\n if (evId == eventId1) {\n idx1 = idx;\n }\n if (evId == eventId2) {\n idx2 = idx;\n }\n }\n const difference = idx1! - idx2!;\n\n // Return the sign of difference.\n if (difference < 0) {\n return -1;\n } else if (difference > 0) {\n return 1;\n } else {\n return 0;\n }\n }\n\n // the events are in different timelines. Iterate through the\n // linkedlist to see which comes first.\n\n // first work forwards from timeline1\n let tl: EventTimeline | null = timeline1;\n while (tl) {\n if (tl === timeline2) {\n // timeline1 is before timeline2\n return -1;\n }\n tl = tl.getNeighbouringTimeline(EventTimeline.FORWARDS);\n }\n\n // now try backwards from timeline1\n tl = timeline1;\n while (tl) {\n if (tl === timeline2) {\n // timeline2 is before timeline1\n return 1;\n }\n tl = tl.getNeighbouringTimeline(EventTimeline.BACKWARDS);\n }\n\n // the timelines are not contiguous.\n return null;\n }\n\n /**\n * Determine whether a given event can sanely be added to this event timeline set,\n * for timeline sets relating to a thread, only return true for events in the same\n * thread timeline, for timeline sets not relating to a thread only return true\n * for events which should be shown in the main room timeline.\n * Requires the `room` property to have been set at EventTimelineSet construction time.\n *\n * @param event - the event to check whether it belongs to this timeline set.\n * @param batch - other events being added alongside, in which the event's parent may be found\n * @throws Error if `room` was not set when constructing this timeline set.\n * @returns whether the event belongs to this timeline set.\n */\n public canContain(event: MatrixEvent, batch?: MatrixEvent[]): boolean {\n if (!this.room) {\n throw new Error(\n \"Cannot call `EventTimelineSet::canContain without a `room` set. \" +\n \"Set the room when creating the EventTimelineSet to call this method.\",\n );\n }\n\n const { threadId, shouldLiveInRoom, shouldLiveInThread } = this.room.eventShouldLiveIn(event, batch);\n\n if (this.thread) {\n return this.thread.id === threadId;\n }\n\n if (!shouldLiveInRoom && !shouldLiveInThread) {\n logger.warn(\n `EventTimelineSet:canContain event encountered which cannot be added to any timeline roomId=${\n this.room?.roomId\n } eventId=${event.getId()} threadId=${event.threadRootId}`,\n );\n }\n\n return shouldLiveInRoom;\n }\n}\n"],"mappings":"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","ignoreList":[]}
@@ -27,7 +27,7 @@ export declare class RoomStickyEventsStore extends TypedEventEmitter<RoomStickyE
27
27
  * Sticky event map is a nested map of:
28
28
  * eventType -> `content.sticky_key sender` -> StickyMatrixEvent[]
29
29
  *
30
- * The events are ordered in latest to earliest expiry, so that the first event
30
+ * The events are ordered descendingly by expiry, tie breaking on the event ID, so that the first event
31
31
  * in the array will always be the "current" one.
32
32
  */
33
33
  private readonly stickyEventsMap;
@@ -39,11 +39,18 @@ export declare class RoomStickyEventsStore extends TypedEventEmitter<RoomStickyE
39
39
  private stickyEventTimer?;
40
40
  private nextStickyEventExpiryTs;
41
41
  /**
42
- * Sort two sticky events by order of expiry. This assumes the sticky events have the same
42
+ * Sort two sticky events by expiry, tie breaking on the event ID. This assumes the sticky events have the same
43
43
  * `type`, `sticky_key` and `sender`.
44
44
  * @returns A positive value if event A will expire sooner, or a negative value if event B will expire sooner.
45
45
  */
46
46
  private static sortStickyEvent;
47
+ /**
48
+ * Check whether a sticky event has expired.
49
+ * @param event The sticky event to check.
50
+ * @param now The current time in milliseconds since the epoch.
51
+ * @returns True if the event has expired, false otherwise.
52
+ */
53
+ private static isExpired;
47
54
  /**
48
55
  * Generate the correct key for an event to be found in the inner maps of `stickyEventsMap`.
49
56
  * @param stickyKey The sticky key of an event.
@@ -110,6 +117,14 @@ export declare class RoomStickyEventsStore extends TypedEventEmitter<RoomStickyE
110
117
  * @param redactedEvent The MatrixEvent OR event ID of the event being redacted. MAY not be a sticky event.
111
118
  */
112
119
  handleRedaction(redactedEvent: MatrixEvent | string): void;
120
+ /**
121
+ * Remove a redacted event from an entry of the keyed sticky map, emitting
122
+ * `RoomEvent.StickyEvents` if this changes the "current" event of that entry.
123
+ * @param eventType The event `type` of the redacted event.
124
+ * @param mapKey The inner map key of the redacted event, see {@link stickyMapKey}.
125
+ * @param redactEventId The ID of the redacted event.
126
+ */
127
+ private removeKeyedStickyEvent;
113
128
  /**
114
129
  * Clear all events and stop the timer from firing.
115
130
  */