matrix-js-sdk 42.0.0 → 42.1.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.
- package/CHANGELOG.md +17 -0
- package/lib/@types/PushRules.d.ts.map +1 -1
- package/lib/@types/PushRules.js +0 -5
- package/lib/@types/PushRules.js.map +1 -1
- package/lib/@types/auth.d.ts.map +1 -1
- package/lib/@types/auth.js +0 -5
- package/lib/@types/auth.js.map +1 -1
- package/lib/@types/crypto.d.ts.map +1 -1
- package/lib/@types/crypto.js.map +1 -1
- package/lib/@types/event.d.ts +3 -1
- package/lib/@types/event.d.ts.map +1 -1
- package/lib/@types/event.js +1 -0
- package/lib/@types/event.js.map +1 -1
- package/lib/@types/extensible_events.js.map +1 -1
- package/lib/@types/matrix-sdk-crypto-wasm.d.js.map +1 -1
- package/lib/@types/media.js.map +1 -1
- package/lib/@types/partials.d.ts.map +1 -1
- package/lib/@types/partials.js.map +1 -1
- package/lib/@types/requests.d.ts.map +1 -1
- package/lib/@types/requests.js +0 -5
- package/lib/@types/requests.js.map +1 -1
- package/lib/@types/search.d.ts.map +1 -1
- package/lib/@types/search.js +0 -3
- package/lib/@types/search.js.map +1 -1
- package/lib/@types/spaces.d.ts.map +1 -1
- package/lib/@types/spaces.js.map +1 -1
- package/lib/@types/synapse.d.ts.map +1 -1
- package/lib/@types/synapse.js.map +1 -1
- package/lib/@types/threepids.js.map +1 -1
- package/lib/ToDeviceMessageQueue.d.ts.map +1 -1
- package/lib/ToDeviceMessageQueue.js +0 -2
- package/lib/ToDeviceMessageQueue.js.map +1 -1
- package/lib/browser-index.d.ts.map +1 -1
- package/lib/browser-index.js +3 -1
- package/lib/browser-index.js.map +1 -1
- package/lib/client.d.ts +5 -8
- package/lib/client.d.ts.map +1 -1
- package/lib/client.js +5 -46
- package/lib/client.js.map +1 -1
- package/lib/common-crypto/key-passphrase.d.ts.map +1 -1
- package/lib/common-crypto/key-passphrase.js +0 -3
- package/lib/common-crypto/key-passphrase.js.map +1 -1
- package/lib/crypto/store/base.d.ts.map +1 -1
- package/lib/crypto/store/base.js +0 -9
- package/lib/crypto/store/base.js.map +1 -1
- package/lib/crypto/store/indexeddb-crypto-store-backend.js.map +1 -1
- package/lib/crypto/store/localStorage-crypto-store.d.ts.map +1 -1
- package/lib/crypto/store/localStorage-crypto-store.js +0 -2
- package/lib/crypto/store/localStorage-crypto-store.js.map +1 -1
- package/lib/crypto-api/keybackup.d.ts +13 -6
- package/lib/crypto-api/keybackup.d.ts.map +1 -1
- package/lib/crypto-api/keybackup.js.map +1 -1
- package/lib/embedded.d.ts.map +1 -1
- package/lib/embedded.js +0 -5
- package/lib/embedded.js.map +1 -1
- package/lib/feature.d.ts.map +1 -1
- package/lib/feature.js +0 -3
- package/lib/feature.js.map +1 -1
- package/lib/filter-component.d.ts.map +1 -1
- package/lib/filter-component.js +2 -5
- package/lib/filter-component.js.map +1 -1
- package/lib/filter.d.ts.map +1 -1
- package/lib/filter.js +0 -4
- package/lib/filter.js.map +1 -1
- package/lib/http-api/interface.d.ts.map +1 -1
- package/lib/http-api/interface.js.map +1 -1
- package/lib/http-api/refresh.d.ts.map +1 -1
- package/lib/http-api/refresh.js +0 -3
- package/lib/http-api/refresh.js.map +1 -1
- package/lib/interactive-auth.d.ts.map +1 -1
- package/lib/interactive-auth.js +5 -6
- package/lib/interactive-auth.js.map +1 -1
- package/lib/logger.d.ts.map +1 -1
- package/lib/logger.js +0 -2
- package/lib/logger.js.map +1 -1
- package/lib/matrixrtc/CallMembership.d.ts +3 -3
- package/lib/matrixrtc/CallMembership.js +5 -5
- package/lib/matrixrtc/CallMembership.js.map +1 -1
- package/lib/matrixrtc/MatrixRTCSession.d.ts +18 -1
- package/lib/matrixrtc/MatrixRTCSession.d.ts.map +1 -1
- package/lib/matrixrtc/MatrixRTCSession.js +56 -4
- package/lib/matrixrtc/MatrixRTCSession.js.map +1 -1
- package/lib/matrixrtc/MatrixRTCSessionManager.d.ts +14 -1
- package/lib/matrixrtc/MatrixRTCSessionManager.d.ts.map +1 -1
- package/lib/matrixrtc/MatrixRTCSessionManager.js +20 -1
- package/lib/matrixrtc/MatrixRTCSessionManager.js.map +1 -1
- package/lib/matrixrtc/MembershipManager.d.ts.map +1 -1
- package/lib/matrixrtc/MembershipManager.js +9 -6
- package/lib/matrixrtc/MembershipManager.js.map +1 -1
- package/lib/matrixrtc/index.d.ts +1 -1
- package/lib/matrixrtc/index.d.ts.map +1 -1
- package/lib/matrixrtc/index.js +1 -1
- package/lib/matrixrtc/index.js.map +1 -1
- package/lib/matrixrtc/membershipData/rtc.d.ts +6 -3
- package/lib/matrixrtc/membershipData/rtc.d.ts.map +1 -1
- package/lib/matrixrtc/membershipData/rtc.js +7 -4
- package/lib/matrixrtc/membershipData/rtc.js.map +1 -1
- package/lib/matrixrtc/types.d.ts +19 -6
- package/lib/matrixrtc/types.d.ts.map +1 -1
- package/lib/matrixrtc/types.js +11 -1
- package/lib/matrixrtc/types.js.map +1 -1
- package/lib/models/event.d.ts.map +1 -1
- package/lib/models/event.js +0 -6
- package/lib/models/event.js.map +1 -1
- package/lib/models/room-state.d.ts.map +1 -1
- package/lib/models/room-state.js.map +1 -1
- package/lib/models/room.d.ts.map +1 -1
- package/lib/models/room.js +6 -6
- package/lib/models/room.js.map +1 -1
- package/lib/models/thread.d.ts +2 -2
- package/lib/models/thread.d.ts.map +1 -1
- package/lib/models/thread.js.map +1 -1
- package/lib/realtime-callbacks.js +0 -1
- package/lib/realtime-callbacks.js.map +1 -1
- package/lib/rendezvous/transports/MSC4108RendezvousSession.d.ts.map +1 -1
- package/lib/rendezvous/transports/MSC4108RendezvousSession.js +0 -1
- package/lib/rendezvous/transports/MSC4108RendezvousSession.js.map +1 -1
- package/lib/rust-crypto/OutgoingRequestProcessor.d.ts.map +1 -1
- package/lib/rust-crypto/OutgoingRequestProcessor.js +0 -2
- package/lib/rust-crypto/OutgoingRequestProcessor.js.map +1 -1
- package/lib/rust-crypto/backup.d.ts +21 -1
- package/lib/rust-crypto/backup.d.ts.map +1 -1
- package/lib/rust-crypto/backup.js +62 -21
- package/lib/rust-crypto/backup.js.map +1 -1
- package/lib/rust-crypto/device-converter.d.ts.map +1 -1
- package/lib/rust-crypto/device-converter.js +1 -0
- package/lib/rust-crypto/device-converter.js.map +1 -1
- package/lib/rust-crypto/index.d.ts +7 -0
- package/lib/rust-crypto/index.d.ts.map +1 -1
- package/lib/rust-crypto/index.js +3 -3
- package/lib/rust-crypto/index.js.map +1 -1
- package/lib/rust-crypto/libolm_migration.d.ts.map +1 -1
- package/lib/rust-crypto/libolm_migration.js +0 -2
- package/lib/rust-crypto/libolm_migration.js.map +1 -1
- package/lib/rust-crypto/rust-crypto.d.ts.map +1 -1
- package/lib/rust-crypto/rust-crypto.js +0 -3
- package/lib/rust-crypto/rust-crypto.js.map +1 -1
- package/lib/scheduler.d.ts.map +1 -1
- package/lib/scheduler.js +0 -3
- package/lib/scheduler.js.map +1 -1
- package/lib/sliding-sync-sdk.d.ts.map +1 -1
- package/lib/sliding-sync-sdk.js +6 -0
- package/lib/sliding-sync-sdk.js.map +1 -1
- package/lib/sliding-sync.d.ts.map +1 -1
- package/lib/sliding-sync.js +3 -0
- package/lib/sliding-sync.js.map +1 -1
- package/lib/store/indexeddb.d.ts.map +1 -1
- package/lib/store/indexeddb.js +0 -2
- package/lib/store/indexeddb.js.map +1 -1
- package/lib/store/memory.d.ts.map +1 -1
- package/lib/store/memory.js +7 -9
- package/lib/store/memory.js.map +1 -1
- package/lib/sync-accumulator.d.ts.map +1 -1
- package/lib/sync-accumulator.js +1 -5
- package/lib/sync-accumulator.js.map +1 -1
- package/lib/sync.d.ts.map +1 -1
- package/lib/sync.js +1 -1
- package/lib/sync.js.map +1 -1
- package/lib/timeline-window.d.ts.map +1 -1
- package/lib/timeline-window.js +0 -1
- package/lib/timeline-window.js.map +1 -1
- package/lib/utils/internal/deriveKeys.d.ts.map +1 -1
- package/lib/utils/internal/deriveKeys.js +0 -1
- package/lib/utils/internal/deriveKeys.js.map +1 -1
- package/lib/webrtc/callEventTypes.d.ts.map +1 -1
- package/lib/webrtc/callEventTypes.js +0 -5
- package/lib/webrtc/callEventTypes.js.map +1 -1
- package/package.json +5 -5
- package/src/@types/PushRules.ts +0 -5
- package/src/@types/auth.ts +0 -6
- package/src/@types/crypto.ts +2 -6
- package/src/@types/event.ts +3 -0
- package/src/@types/extensible_events.ts +4 -4
- package/src/@types/matrix-sdk-crypto-wasm.d.ts +0 -1
- package/src/@types/media.ts +1 -1
- package/src/@types/partials.ts +0 -2
- package/src/@types/requests.ts +0 -5
- package/src/@types/search.ts +0 -2
- package/src/@types/spaces.ts +0 -2
- package/src/@types/synapse.ts +0 -2
- package/src/@types/threepids.ts +2 -2
- package/src/ToDeviceMessageQueue.ts +0 -2
- package/src/browser-index.ts +3 -3
- package/src/client.ts +18 -61
- package/src/common-crypto/key-passphrase.ts +0 -1
- package/src/crypto/store/base.ts +1 -8
- package/src/crypto/store/indexeddb-crypto-store-backend.ts +1 -1
- package/src/crypto/store/localStorage-crypto-store.ts +0 -1
- package/src/crypto-api/keybackup.ts +14 -7
- package/src/embedded.ts +0 -5
- package/src/feature.ts +0 -3
- package/src/filter-component.ts +1 -2
- package/src/filter.ts +0 -3
- package/src/http-api/interface.ts +0 -1
- package/src/http-api/refresh.ts +0 -1
- package/src/interactive-auth.ts +4 -4
- package/src/logger.ts +0 -2
- package/src/matrixrtc/CallMembership.ts +5 -5
- package/src/matrixrtc/MatrixRTCSession.ts +70 -3
- package/src/matrixrtc/MatrixRTCSessionManager.ts +21 -2
- package/src/matrixrtc/MembershipManager.ts +8 -5
- package/src/matrixrtc/index.ts +1 -1
- package/src/matrixrtc/membershipData/rtc.ts +18 -7
- package/src/matrixrtc/types.ts +24 -7
- package/src/models/event.ts +0 -3
- package/src/models/room-state.ts +0 -3
- package/src/models/room.ts +6 -6
- package/src/models/thread.ts +2 -2
- package/src/realtime-callbacks.ts +0 -1
- package/src/rendezvous/transports/MSC4108RendezvousSession.ts +0 -1
- package/src/rust-crypto/OutgoingRequestProcessor.ts +0 -1
- package/src/rust-crypto/backup.ts +66 -28
- package/src/rust-crypto/device-converter.ts +1 -0
- package/src/rust-crypto/index.ts +11 -0
- package/src/rust-crypto/libolm_migration.ts +0 -2
- package/src/rust-crypto/rust-crypto.ts +0 -3
- package/src/scheduler.ts +0 -3
- package/src/sliding-sync-sdk.ts +3 -0
- package/src/sliding-sync.ts +2 -0
- package/src/store/indexeddb.ts +0 -2
- package/src/store/memory.ts +7 -9
- package/src/sync-accumulator.ts +1 -3
- package/src/sync.ts +1 -3
- package/src/timeline-window.ts +0 -1
- package/src/utils/internal/deriveKeys.ts +0 -1
- package/src/webrtc/callEventTypes.ts +0 -5
package/lib/models/thread.d.ts
CHANGED
|
@@ -237,8 +237,8 @@ export declare const FILTER_RELATED_BY_SENDERS: ServerControlledNamespacedValue<
|
|
|
237
237
|
export declare const FILTER_RELATED_BY_REL_TYPES: ServerControlledNamespacedValue<"related_by_rel_types", "io.element.relation_types">;
|
|
238
238
|
export declare const THREAD_RELATION_TYPE: ServerControlledNamespacedValue<"m.thread", "io.element.thread">;
|
|
239
239
|
export declare enum ThreadFilterType {
|
|
240
|
-
|
|
241
|
-
|
|
240
|
+
My = 0,
|
|
241
|
+
All = 1
|
|
242
242
|
}
|
|
243
243
|
export declare function threadFilterTypeToFilter(type: ThreadFilterType | null): "all" | "participated";
|
|
244
244
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"thread.d.ts","sourceRoot":"","sources":["../../src/models/thread.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"thread.d.ts","sourceRoot":"","sources":["../../src/models/thread.ts"],"names":[],"mappings":"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"}
|
package/lib/models/thread.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"thread.js","names":[],"sources":["../../src/models/thread.ts"],"sourcesContent":["/*\nCopyright 2021 - 2023 The Matrix.org Foundation C.I.C.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n*/\n\nimport { type MatrixClient, PendingEventOrdering } from \"../client.ts\";\nimport { TypedReEmitter } from \"../ReEmitter.ts\";\nimport { RelationType } from \"../@types/event.ts\";\nimport { type IThreadBundledRelationship, MatrixEvent, MatrixEventEvent } from \"./event.ts\";\nimport { Direction, EventTimeline } from \"./event-timeline.ts\";\nimport { EventTimelineSet, type EventTimelineSetHandlerMap } from \"./event-timeline-set.ts\";\nimport { type NotificationCountType, type Room, RoomEvent } from \"./room.ts\";\nimport { type RoomState } from \"./room-state.ts\";\nimport { ServerControlledNamespacedValue } from \"../NamespacedValue.ts\";\nimport { logger } from \"../logger.ts\";\nimport { ReadReceipt } from \"./read-receipt.ts\";\nimport { type CachedReceiptStructure, type Receipt, ReceiptType } from \"../@types/read_receipts.ts\";\nimport { Feature, ServerSupport } from \"../feature.ts\";\n\nexport enum ThreadEvent {\n New = \"Thread.new\",\n Update = \"Thread.update\",\n NewReply = \"Thread.newReply\",\n ViewThread = \"Thread.viewThread\",\n Delete = \"Thread.delete\",\n}\n\nexport type ThreadEmittedEvents = Exclude<ThreadEvent, ThreadEvent.New> | RoomEvent.Timeline | RoomEvent.TimelineReset;\n\nexport type ThreadEventHandlerMap = {\n [ThreadEvent.Update]: (thread: Thread) => void;\n [ThreadEvent.NewReply]: (thread: Thread, event: MatrixEvent) => void;\n [ThreadEvent.ViewThread]: () => void;\n [ThreadEvent.Delete]: (thread: Thread) => void;\n} & EventTimelineSetHandlerMap;\n\ninterface IThreadOpts {\n room: Room;\n client: MatrixClient;\n pendingEventOrdering?: PendingEventOrdering;\n receipts?: CachedReceiptStructure[];\n}\n\nexport enum FeatureSupport {\n None = 0,\n Experimental = 1,\n Stable = 2,\n}\n\nexport function determineFeatureSupport(stable: boolean, unstable: boolean): FeatureSupport {\n if (stable) {\n return FeatureSupport.Stable;\n } else if (unstable) {\n return FeatureSupport.Experimental;\n } else {\n return FeatureSupport.None;\n }\n}\n\nexport class Thread extends ReadReceipt<ThreadEmittedEvents, ThreadEventHandlerMap> {\n public static hasServerSideSupport = FeatureSupport.None;\n public static hasServerSideListSupport = FeatureSupport.None;\n public static hasServerSideFwdPaginationSupport = FeatureSupport.None;\n\n /**\n * A reference to all the events ID at the bottom of the threads\n */\n public readonly timelineSet: EventTimelineSet;\n\n private _currentUserParticipated = false;\n\n private reEmitter: TypedReEmitter<ThreadEmittedEvents, ThreadEventHandlerMap>;\n\n /**\n * The last event in this thread, if we don't yet have this in the timeline.\n *\n * When we run {@link processRootEvent} (which I think happens during the\n * setting-up of the thread), we set this to the event pointed to by the\n * server in `latest_event` [1] that came through with the thread root.\n *\n * [1]: https://spec.matrix.org/v1.8/client-server-api/#server-side-aggregation-of-mthread-relationships\n *\n * Later, when we have populated the timeline, this is set to undefined, so\n * that methods like {@link replyToEvent} fall through to use lastReply,\n * which looks in the timeline for the latest event that is a \"thread reply\"\n * i.e. directly refers to the thread root with an m.thread relation.\n *\n * So it looks like this is only really relevant when initialEventsFetched\n * is false, because as soon as the initial events have been fetched, we\n * should have a proper chunk of timeline from the pagination fetch.\n *\n * If all replies in this thread are redacted, this is set to the root\n * event. I'm not clear what the meaning of this is, since usually after the\n * initial events have been fetched, lastEvent should be undefined.\n * In fact, the whole usage inside onRedaction looks suspect - it may be\n * that we were thinking lastEvent always refers to the actual last event,\n * but it only does so before initialEventsFetched becomes true.\n *\n * The usage of lastEvent inside {@link onEcho} looks suspicious, since I'd\n * think we probably mean {@link replyToEvent} there - we are trying not to\n * echo a duplicate event, and we probably want that behaviour even after\n * initialEventsFetched has become true.\n *\n * -- andyb\n */\n private lastEvent: MatrixEvent | undefined;\n\n private replyCount = 0;\n private lastPendingEvent: MatrixEvent | undefined;\n private pendingReplyCount = 0;\n\n public readonly room: Room;\n public readonly client: MatrixClient;\n private readonly pendingEventOrdering: PendingEventOrdering;\n private processRootEventPromise?: Promise<void>;\n\n /**\n * Whether or not we need to fetch the initial set of events for the thread. We can\n * only do this if the server has support for it, so if it doesn't we just pretend\n * that we've already fetched them.\n */\n public initialEventsFetched = !Thread.hasServerSideSupport;\n private initalEventFetchProm: Promise<boolean> | undefined;\n\n /**\n * An array of events to add to the timeline once the thread has been initialised\n * with server suppport.\n */\n public replayEvents: MatrixEvent[] | null = [];\n\n public constructor(\n public readonly id: string,\n public rootEvent: MatrixEvent | undefined,\n opts: IThreadOpts,\n ) {\n super();\n\n // each Event in the thread adds a reemitter, so we could hit the listener limit.\n this.setMaxListeners(1000);\n\n if (!opts?.room) {\n // Logging/debugging for https://github.com/vector-im/element-web/issues/22141\n // Hope is that we end up with a more obvious stack trace.\n throw new Error(\"element-web#22141: A thread requires a room in order to function\");\n }\n\n this.room = opts.room;\n this.client = opts.client;\n this.pendingEventOrdering = opts.pendingEventOrdering ?? PendingEventOrdering.Chronological;\n this.timelineSet = new EventTimelineSet(\n this.room,\n {\n timelineSupport: true,\n pendingEvents: true,\n },\n this.client,\n this,\n );\n this.reEmitter = new TypedReEmitter(this);\n\n this.reEmitter.reEmit(this.timelineSet, [RoomEvent.Timeline, RoomEvent.TimelineReset]);\n\n this.room.on(MatrixEventEvent.BeforeRedaction, this.onBeforeRedaction);\n this.room.on(RoomEvent.Redaction, this.onRedaction);\n this.room.on(RoomEvent.LocalEchoUpdated, this.onLocalEcho);\n this.room.on(RoomEvent.TimelineReset, this.onTimelineReset);\n this.timelineSet.on(RoomEvent.Timeline, this.onTimelineEvent);\n\n this.processReceipts(opts.receipts);\n\n // even if this thread is thought to be originating from this client, we initialise it as we may be in a\n // gappy sync and a thread around this event may already exist.\n this.updateThreadMetadata();\n this.setEventMetadata(this.rootEvent);\n }\n\n private onTimelineReset = async (): Promise<void> => {\n // We hit a gappy sync, ask the server for an update\n await this.processRootEventPromise;\n this.processRootEventPromise = undefined;\n };\n\n private async fetchRootEvent(): Promise<void> {\n // Always fetch the root event, even if we already have it, so we can get the latest\n // state (via unsigned).\n try {\n const eventData = await this.client.fetchRoomEvent(this.roomId, this.id);\n const mapper = this.client.getEventMapper();\n this.rootEvent = mapper(eventData); // will merge with existing event object if such is known\n } catch (e) {\n logger.error(\"Failed to fetch thread root to construct thread with\", e);\n }\n await this.processEvent(this.rootEvent);\n }\n\n public static setServerSideSupport(status: FeatureSupport): void {\n Thread.hasServerSideSupport = status;\n // XXX: This global latching behaviour is really unexpected and means that you can't undo when moving to a server without support\n if (status !== FeatureSupport.Stable) {\n FILTER_RELATED_BY_SENDERS.setPreferUnstable(true);\n FILTER_RELATED_BY_REL_TYPES.setPreferUnstable(true);\n THREAD_RELATION_TYPE.setPreferUnstable(true);\n }\n }\n\n public static setServerSideListSupport(status: FeatureSupport): void {\n Thread.hasServerSideListSupport = status;\n }\n\n public static setServerSideFwdPaginationSupport(status: FeatureSupport): void {\n Thread.hasServerSideFwdPaginationSupport = status;\n }\n\n private onBeforeRedaction = (event: MatrixEvent, redaction: MatrixEvent): void => {\n if (\n event?.isRelation(THREAD_RELATION_TYPE.name) &&\n this.room.eventShouldLiveIn(event).threadId === this.id &&\n event.getId() !== this.id && // the root event isn't counted in the length so ignore this redaction\n !redaction.status // only respect it when it succeeds\n ) {\n this.replyCount--;\n this.updatePendingReplyCount();\n this.emit(ThreadEvent.Update, this);\n }\n };\n\n private onRedaction = async (event: MatrixEvent, room: Room, threadRootId?: string): Promise<void> => {\n if (threadRootId !== this.id) return; // ignore redactions for other timelines\n if (this.replyCount <= 0) {\n for (const threadEvent of this.timeline) {\n this.clearEventMetadata(threadEvent);\n }\n this.lastEvent = this.rootEvent;\n this._currentUserParticipated = false;\n this.emit(ThreadEvent.Delete, this);\n } else {\n if (this.lastEvent?.getId() === event.getAssociatedId()) {\n // XXX: If our last event got redacted we query the server for the last event once again\n await this.processRootEventPromise;\n this.processRootEventPromise = undefined;\n }\n await this.updateThreadMetadata();\n }\n };\n\n private onTimelineEvent = (\n event: MatrixEvent,\n room: Room | undefined,\n toStartOfTimeline: boolean | undefined,\n ): void => {\n // Add a synthesized receipt when paginating forward in the timeline\n if (!toStartOfTimeline) {\n const sender = event.getSender();\n if (sender && room && this.shouldSendLocalEchoReceipt(sender, event)) {\n room.addLocalEchoReceipt(sender, event, ReceiptType.Read);\n }\n if (event.getId() !== this.id && event.isRelation(THREAD_RELATION_TYPE.name)) {\n this.replyCount++;\n }\n }\n this.onEcho(event, toStartOfTimeline ?? false);\n };\n\n private shouldSendLocalEchoReceipt(sender: string, event: MatrixEvent): boolean {\n const recursionSupport = this.client.canSupport.get(Feature.RelationsRecursion) ?? ServerSupport.Unsupported;\n\n if (recursionSupport === ServerSupport.Unsupported) {\n // Normally we add a local receipt, but if we don't have\n // recursion support, then events may arrive out of order, so we\n // only create a receipt if it's after our existing receipt.\n const oldReceiptEventId = this.getReadReceiptForUserId(sender)?.eventId;\n if (oldReceiptEventId) {\n const receiptEvent = this.findEventById(oldReceiptEventId);\n if (receiptEvent && receiptEvent.getTs() > event.getTs()) {\n return false;\n }\n }\n }\n\n return true;\n }\n\n private onLocalEcho = (event: MatrixEvent): void => {\n this.onEcho(event, false);\n };\n\n private onEcho = async (event: MatrixEvent, toStartOfTimeline: boolean): Promise<void> => {\n if (event.threadRootId !== this.id) return; // ignore echoes for other timelines\n if (this.lastEvent === event) return; // ignore duplicate events\n await this.updateThreadMetadata();\n if (!event.isRelation(THREAD_RELATION_TYPE.name)) return; // don't send a new reply event for reactions or edits\n if (toStartOfTimeline) return; // ignore messages added to the start of the timeline\n // Clear the lastEvent and instead start tracking locally using lastReply\n this.lastEvent = undefined;\n this.emit(ThreadEvent.NewReply, this, event);\n };\n\n public get roomState(): RoomState {\n return this.room.getLiveTimeline().getState(EventTimeline.FORWARDS)!;\n }\n\n private addEventToTimeline(event: MatrixEvent, toStartOfTimeline: boolean): void {\n if (!this.findEventById(event.getId()!)) {\n this.timelineSet.addEventToTimeline(event, this.liveTimeline, {\n toStartOfTimeline,\n fromCache: false,\n roomState: this.roomState,\n addToState: false,\n });\n }\n }\n\n /**\n * TEMPORARY. Only call this when MSC3981 is not available, and we have some\n * late-arriving events to insert, because we recursively found them as part\n * of populating a thread. When we have MSC3981 we won't need it, because\n * they will all be supplied by the homeserver in one request, and they will\n * already be in the right order in that response.\n * This is a copy of addEventToTimeline above, modified to call\n * insertEventIntoTimeline so this event is inserted into our best guess of\n * the right place based on timestamp. (We should be using Sync Order but we\n * don't have it.)\n *\n * @internal\n */\n public insertEventIntoTimeline(event: MatrixEvent): void {\n const eventId = event.getId();\n if (!eventId) {\n return;\n }\n // If the event is already in this thread, bail out\n if (this.findEventById(eventId)) {\n return;\n }\n this.timelineSet.insertEventIntoTimeline(event, this.liveTimeline, this.roomState, false);\n }\n\n public addEvents(events: MatrixEvent[], toStartOfTimeline: boolean): void {\n events.forEach((ev) => this.addEvent(ev, toStartOfTimeline, false));\n this.updateThreadMetadata();\n }\n\n /**\n * Add an event to the thread and updates\n * the tail/root references if needed\n * Will fire \"Thread.update\"\n * @param event - The event to add\n * @param toStartOfTimeline - whether the event is being added\n * to the start (and not the end) of the timeline.\n * @param emit - whether to emit the Update event if the thread was updated or not.\n */\n public addEvent(event: MatrixEvent, toStartOfTimeline: boolean, emit = true): void {\n // Modify this event to point at our room's state, and mark its thread\n // as this.\n this.setEventMetadata(event);\n\n // Decide whether this event is going to be added at the end of the timeline.\n const lastReply = this.lastReply();\n const isNewestReply = !lastReply || event.localTimestamp >= lastReply!.localTimestamp;\n\n if (!Thread.hasServerSideSupport) {\n // When there's no server-side support, just add it to the end of the timeline.\n this.addEventToTimeline(event, toStartOfTimeline);\n this.client.decryptEventIfNeeded(event);\n } else if (event.isRelation(RelationType.Annotation) || event.isRelation(RelationType.Replace)) {\n this.addRelatedThreadEvent(event, toStartOfTimeline);\n return;\n } else if (!toStartOfTimeline && isNewestReply) {\n // When we've asked for the event to be added to the end,\n // and this event belongs at the end, add it.\n this.addEventToTimeline(event, false);\n this.fetchEditsWhereNeeded(event);\n } else {\n // Otherwise, we should add it, but we suspect it is out of order.\n // This may be because we've just created the thread object and are\n // still fetching events, in which case add it where we think is sensible\n // and it will be removed and replaced with the events from the pagination\n // request once that completes.\n if (toStartOfTimeline) {\n // If we're adding at the start of the timeline, it doesn't\n // matter that it's out of order.\n this.addEventToTimeline(event, toStartOfTimeline);\n } else {\n // We think this event might be out of order, because isNewestReply\n // is false (otherwise we would have gone into the earlier if\n // clause), so try to insert it in the right place based on\n // timestamp.\n this.insertEventIntoTimeline(event);\n }\n }\n\n if (\n event.getId() !== this.id &&\n event.isRelation(THREAD_RELATION_TYPE.name) &&\n !toStartOfTimeline &&\n isNewestReply\n ) {\n // Clear the last event as we have the latest end of the timeline\n this.lastEvent = undefined;\n }\n\n if (emit) {\n this.emit(ThreadEvent.NewReply, this, event);\n this.updateThreadMetadata();\n }\n }\n\n private addRelatedThreadEvent(event: MatrixEvent, toStartOfTimeline: boolean): void {\n // If this event is not a direct member of the thread, but is a\n // reference to something that is, then we have two cases:\n\n if (!this.initialEventsFetched) {\n // Case 1: we haven't yet fetched events from the server. In\n // this case, when we do, the events we get back might only be\n // the first-order ones, so this event (which is second-order -\n // a reference to something directly in the thread) needs to be\n // kept so we can replay it when the first-order ones turn up.\n\n /**\n * A thread can be fully discovered via a single sync response\n * And when that's the case we still ask the server to do an initialisation\n * as it's the safest to ensure we have everything.\n * However when we are in that scenario we might loose annotation or edits\n *\n * This fix keeps a reference to those events and replay them once the thread\n * has been initialised properly.\n */\n this.replayEvents?.push(event);\n\n // For annotations (reactions), aggregate immediately (pre-init) to keep\n // reaction counts/summary visible while the thread is still initialising.\n // Only aggregate as child: parent aggregation is unnecessary here.\n if (event.isRelation(RelationType.Annotation)) {\n this.timelineSet.relations?.aggregateChildEvent(event, this.timelineSet);\n }\n } else {\n // Case 2: this is happening later, and we have a timeline. In\n // this case, these events might be out-of order.\n //\n // Specifically, if the server doesn't support recursion, so we\n // only get these events through sync, they might be coming\n // later than the first-order ones, so we insert them based on\n // timestamp (despite the problems with this documented in\n // #3325).\n //\n // If the server does support recursion, we should have got all\n // the interspersed events from the server when we fetched the\n // initial events, so if they are coming via sync they should be\n // the latest ones, so we can add them as normal.\n //\n // (Note that both insertEventIntoTimeline and addEventToTimeline\n // do nothing if we have seen this event before.)\n\n const recursionSupport =\n this.client.canSupport.get(Feature.RelationsRecursion) ?? ServerSupport.Unsupported;\n\n if (recursionSupport === ServerSupport.Unsupported) {\n this.insertEventIntoTimeline(event);\n } else {\n this.addEventToTimeline(event, toStartOfTimeline);\n }\n // Aggregation is handled by EventTimelineSet when inserting/adding.\n }\n }\n\n public async processEvent(event: MatrixEvent | null | undefined): Promise<void> {\n if (event) {\n this.setEventMetadata(event);\n await this.fetchEditsWhereNeeded(event);\n }\n }\n\n /**\n * Processes the receipts that were caught during initial sync\n * When clients become aware of a thread, they try to retrieve those read receipts\n * and apply them to the current thread\n * @param receipts - A collection of the receipts cached from initial sync\n */\n private processReceipts(receipts: CachedReceiptStructure[] = []): void {\n for (const { eventId, receiptType, userId, receipt, synthetic } of receipts) {\n this.addReceiptToStructure(eventId, receiptType as ReceiptType, userId, receipt, synthetic);\n }\n }\n\n private getRootEventBundledRelationship(rootEvent = this.rootEvent): IThreadBundledRelationship | undefined {\n return rootEvent?.getServerAggregatedRelation<IThreadBundledRelationship>(THREAD_RELATION_TYPE.name);\n }\n\n private async processRootEvent(): Promise<void> {\n const bundledRelationship = this.getRootEventBundledRelationship();\n if (Thread.hasServerSideSupport && bundledRelationship) {\n this.replyCount = bundledRelationship.count;\n this._currentUserParticipated = !!bundledRelationship.current_user_participated;\n\n const mapper = this.client.getEventMapper();\n // re-insert roomId\n this.lastEvent = mapper({\n ...bundledRelationship.latest_event,\n room_id: this.roomId,\n });\n this.updatePendingReplyCount();\n await this.processEvent(this.lastEvent);\n }\n }\n\n private updatePendingReplyCount(): void {\n const unfilteredPendingEvents =\n this.pendingEventOrdering === PendingEventOrdering.Detached ? this.room.getPendingEvents() : this.events;\n const pendingEvents = unfilteredPendingEvents.filter(\n (ev) =>\n ev.threadRootId === this.id &&\n ev.isRelation(THREAD_RELATION_TYPE.name) &&\n ev.status !== null &&\n ev.getId() !== this.lastEvent?.getId(),\n );\n this.lastPendingEvent = pendingEvents.length ? pendingEvents[pendingEvents.length - 1] : undefined;\n this.pendingReplyCount = pendingEvents.length;\n }\n\n /**\n * Reset the live timeline of all timelineSets, and start new ones.\n *\n * <p>This is used when /sync returns a 'limited' timeline. 'Limited' means that there's a gap between the messages\n * /sync returned, and the last known message in our timeline. In such a case, our live timeline isn't live anymore\n * and has to be replaced by a new one. To make sure we can continue paginating our timelines correctly, we have to\n * set new pagination tokens on the old and the new 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, removing old ones (including the previous live\n * timeline which would otherwise be unable to paginate forwards without this token).\n * Removing just the old live timeline whilst preserving previous ones is not supported.\n */\n public async resetLiveTimeline(\n backPaginationToken?: string | null,\n forwardPaginationToken?: string | null,\n ): Promise<void> {\n const oldLive = this.liveTimeline;\n this.timelineSet.resetLiveTimeline(backPaginationToken ?? undefined, forwardPaginationToken ?? undefined);\n const newLive = this.liveTimeline;\n\n // FIXME: Remove the following as soon as https://github.com/matrix-org/synapse/issues/14830 is resolved.\n //\n // The pagination API for thread timelines currently can't handle the type of pagination tokens returned by sync\n //\n // To make this work anyway, we'll have to transform them into one of the types that the API can handle.\n // One option is passing the tokens to /messages, which can handle sync tokens, and returns the right format.\n // /messages does not return new tokens on requests with a limit of 0.\n // This means our timelines might overlap a slight bit, but that's not an issue, as we deduplicate messages\n // anyway.\n\n let newBackward: string | undefined;\n let oldForward: string | undefined;\n if (backPaginationToken) {\n const res = await this.client.createMessagesRequest(this.roomId, backPaginationToken, 1, Direction.Forward);\n newBackward = res.end;\n }\n if (forwardPaginationToken) {\n const res = await this.client.createMessagesRequest(\n this.roomId,\n forwardPaginationToken,\n 1,\n Direction.Backward,\n );\n oldForward = res.start;\n }\n // Only replace the token if we don't have paginated away from this position already. This situation doesn't\n // occur today, but if the above issue is resolved, we'd have to go down this path.\n if (forwardPaginationToken && oldLive.getPaginationToken(Direction.Forward) === forwardPaginationToken) {\n oldLive.setPaginationToken(oldForward ?? null, Direction.Forward);\n }\n if (backPaginationToken && newLive.getPaginationToken(Direction.Backward) === backPaginationToken) {\n newLive.setPaginationToken(newBackward ?? null, Direction.Backward);\n }\n }\n\n private async updateThreadFromRootEvent(): Promise<void> {\n if (Thread.hasServerSideSupport) {\n // Ensure we show *something* as soon as possible, we'll update it as soon as we get better data, but we\n // don't want the thread preview to be empty if we can avoid it\n if (!this.initialEventsFetched && !this.lastEvent) {\n await this.processRootEvent();\n }\n await this.fetchRootEvent();\n }\n await this.processRootEvent();\n }\n\n private async updateThreadMetadata(): Promise<void> {\n this.updatePendingReplyCount();\n\n if (!this.processRootEventPromise) {\n // We only want to do this once otherwise we end up rolling back to the last unsigned summary we have for the thread\n this.processRootEventPromise = this.updateThreadFromRootEvent();\n }\n await this.processRootEventPromise;\n\n if (!this.initialEventsFetched) {\n if (this.initalEventFetchProm) {\n await this.initalEventFetchProm;\n } else {\n // fetch initial events to allow proper pagination\n try {\n // clear out any events that were added before the pagination request\n // completed (eg. from sync). They'll be replaced by those from the pagination.\n // Really, we should do this after the pagination request completes, but\n // paginateEventTimeline does the request and adds the events in one go, so\n // this would need a refactor in order to do. It's therefore possible there's\n // a remaining race where an event comes in while the pagination request is\n // happening.\n this.timelineSet.resetLiveTimeline();\n // if the thread has regular events, this will just load the last reply.\n // if the thread is newly created, this will load the root event.\n if (this.replyCount === 0 && this.rootEvent) {\n this.timelineSet.addEventsToTimeline([this.rootEvent], true, false, this.liveTimeline, null);\n this.liveTimeline.setPaginationToken(null, Direction.Backward);\n } else {\n this.initalEventFetchProm = this.client.paginateEventTimeline(this.liveTimeline, {\n backwards: true,\n });\n await this.initalEventFetchProm;\n }\n // We have now fetched the initial events, so set the flag. We need to do this before\n // we actually add the events, so `this.addEvents` knows that it can now safely add\n // them rather than buffer them in the pending event list. The main thing is that this\n // must remain false while the async fetch happens, so we don't try to add events before\n // the pagination has finished. The important thing is that we're not await-ing anything\n // else between setting this and adding events, so no races.\n this.initialEventsFetched = true;\n for (const event of this.replayEvents!) {\n this.addEvent(event, false);\n }\n this.replayEvents = null;\n // just to make sure that, if we've created a timeline window for this thread before the thread itself\n // existed (e.g. when creating a new thread), we'll make sure the panel is force refreshed correctly.\n this.emit(RoomEvent.TimelineReset, this.room, this.timelineSet, true);\n } catch (e) {\n logger.error(\"Failed to load start of newly created thread: \", e);\n this.initialEventsFetched = false;\n }\n }\n }\n\n this.emit(ThreadEvent.Update, this);\n }\n\n // XXX: Workaround for https://github.com/matrix-org/matrix-spec-proposals/pull/2676/files#r827240084\n private async fetchEditsWhereNeeded(...events: MatrixEvent[]): Promise<unknown> {\n const recursionSupport = this.client.canSupport.get(Feature.RelationsRecursion) ?? ServerSupport.Unsupported;\n if (recursionSupport === ServerSupport.Unsupported) {\n return Promise.all(\n events.filter(isAnEncryptedThreadMessage).map(async (event: MatrixEvent) => {\n try {\n const relations = await this.client.relations(\n this.roomId,\n event.getId()!,\n RelationType.Replace,\n event.getType(),\n {\n limit: 1,\n },\n );\n if (relations.events.length) {\n const editEvent = relations.events[0];\n event.makeReplaced(editEvent);\n this.insertEventIntoTimeline(editEvent);\n }\n } catch (e) {\n logger.error(\"Failed to load edits for encrypted thread event\", e);\n }\n }),\n );\n }\n }\n\n public setEventMetadata(event: MatrixEvent | null | undefined): void {\n if (event) {\n EventTimeline.setEventMetadata(event, this.roomState, false);\n event.setThread(this);\n }\n }\n\n public clearEventMetadata(event: MatrixEvent | null | undefined): void {\n if (event) {\n event.setThread(undefined);\n delete event.event?.unsigned?.[\"m.relations\"]?.[THREAD_RELATION_TYPE.name];\n }\n }\n\n /**\n * Finds an event by ID in the current thread\n */\n public findEventById(eventId: string): MatrixEvent | undefined {\n return this.timelineSet.findEventById(eventId);\n }\n\n /**\n * Return last reply to the thread, if known.\n */\n public lastReply(\n matches: (ev: MatrixEvent) => boolean = (ev): boolean => ev.isRelation(THREAD_RELATION_TYPE.name),\n ): MatrixEvent | null {\n for (let i = this.timeline.length - 1; i >= 0; i--) {\n const event = this.timeline[i];\n if (matches(event)) {\n return event;\n }\n }\n return null;\n }\n\n public get roomId(): string {\n return this.room.roomId;\n }\n\n /**\n * The number of messages in the thread\n * Only count rel_type=m.thread as we want to\n * exclude annotations from that number\n */\n public get length(): number {\n return this.replyCount + this.pendingReplyCount;\n }\n\n /**\n * A getter for the last event of the thread.\n * This might be a synthesized event, if so, it will not emit any events to listeners.\n */\n public get replyToEvent(): MatrixEvent | null {\n return this.lastPendingEvent ?? this.lastEvent ?? this.lastReply();\n }\n\n /**\n * The live event timeline for this thread.\n * @deprecated Present for backwards compatibility.\n * Use this.events instead\n * @returns The live event timeline for this thread.\n */\n public get timeline(): MatrixEvent[] {\n return this.events;\n }\n\n public get events(): MatrixEvent[] {\n return this.liveTimeline.getEvents();\n }\n\n public has(eventId: string): boolean {\n return this.timelineSet.findEventById(eventId) instanceof MatrixEvent;\n }\n\n public get hasCurrentUserParticipated(): boolean {\n return this._currentUserParticipated;\n }\n\n public get liveTimeline(): EventTimeline {\n return this.timelineSet.getLiveTimeline();\n }\n\n public getUnfilteredTimelineSet(): EventTimelineSet {\n return this.timelineSet;\n }\n\n public addReceipt(event: MatrixEvent, synthetic: boolean): void {\n throw new Error(\"Unsupported function on the thread model\");\n }\n\n /**\n * Get the ID of the event that a given user has read up to within this thread,\n * or null if we have received no read receipt (at all) from them.\n * @param userId - The user ID to get read receipt event ID for\n * @param ignoreSynthesized - If true, return only receipts that have been\n * sent by the server, not implicit ones generated\n * by the JS SDK.\n * @returns ID of the latest event that the given user has read, or null.\n */\n public getEventReadUpTo(userId: string, ignoreSynthesized?: boolean): string | null {\n // TODO: we think the implementation here is not right. Here is a sketch\n // of the right answer:\n //\n // for event in timeline.events.reversed():\n // if room.hasUserReadEvent(event):\n // return event\n // return null\n //\n // If this is too slow, we might be able to improve it by trying walking\n // forward from the threaded receipt in this thread. We could alternate\n // between backwards-from-front and forwards-from-threaded-receipt to\n // improve our chances of hitting the right answer sooner.\n //\n // Either way, it's still fundamentally slow because we have to walk\n // events.\n //\n // We also might just want to limit the time we spend on this by giving\n // up after, say, 100 events.\n //\n // --- andyb\n\n const isCurrentUser = userId === this.client.getUserId();\n const lastReply = this.timeline[this.timeline.length - 1];\n if (isCurrentUser && lastReply) {\n // If the last activity in a thread is prior to the first threaded read receipt\n // sent in the room (suggesting that it was sent before the user started\n // using a client that supported threaded read receipts), we want to\n // consider this thread as read.\n const beforeFirstThreadedReceipt = lastReply.getTs() < this.room.getOldestThreadedReceiptTs();\n const lastReplyId = lastReply.getId();\n // Some unsent events do not have an ID, we do not want to consider them read\n if (beforeFirstThreadedReceipt && lastReplyId) {\n return lastReplyId;\n }\n }\n\n const readUpToId = super.getEventReadUpTo(userId, ignoreSynthesized);\n\n // Check whether the unthreaded read receipt for that user is more recent\n // than the read receipt inside that thread.\n if (lastReply) {\n const unthreadedReceipt = this.room.getLastUnthreadedReceiptFor(userId);\n if (!unthreadedReceipt) {\n return readUpToId;\n }\n\n for (let i = this.timeline?.length - 1; i >= 0; --i) {\n const ev = this.timeline[i];\n // If we encounter the `readUpToId` we do not need to look further\n // there is no \"more recent\" unthreaded read receipt\n if (ev.getId() === readUpToId) return readUpToId;\n\n // Inspecting events from most recent to oldest, we're checking\n // whether an unthreaded read receipt is more recent that the current event.\n // We usually prefer relying on the order of the DAG but in this scenario\n // it is not possible and we have to rely on timestamp\n if (ev.getTs() < unthreadedReceipt.ts) return ev.getId() ?? readUpToId;\n }\n }\n\n return readUpToId;\n }\n\n /**\n * Determine if the given user has read a particular event.\n *\n * It is invalid to call this method with an event that is not part of this thread.\n *\n * This is not a definitive check as it only checks the events that have been\n * loaded client-side at the time of execution.\n * @param userId - The user ID to check the read state of.\n * @param eventId - The event ID to check if the user read.\n * @returns True if the user has read the event, false otherwise.\n */\n public hasUserReadEvent(userId: string, eventId: string): boolean {\n if (userId === this.client.getUserId()) {\n // Consider an event read if it's part of a thread that is before the\n // first threaded receipt sent in that room. It is likely that it is\n // part of a thread that was created before MSC3771 was implemented.\n // Or before the last unthreaded receipt for the logged in user\n const beforeFirstThreadedReceipt =\n (this.lastReply()?.getTs() ?? 0) < this.room.getOldestThreadedReceiptTs();\n const unthreadedReceiptTs = this.room.getLastUnthreadedReceiptFor(userId)?.ts ?? 0;\n const beforeLastUnthreadedReceipt = (this?.lastReply()?.getTs() ?? 0) < unthreadedReceiptTs;\n if (beforeFirstThreadedReceipt || beforeLastUnthreadedReceipt) {\n return true;\n }\n }\n\n return this.room.hasUserReadEvent(userId, eventId);\n }\n\n public setUnread(type: NotificationCountType, count: number): void {\n return this.room.setThreadUnreadNotificationCount(this.id, type, count);\n }\n\n /**\n * Returns the most recent unthreaded receipt for a given user\n * @param userId - the MxID of the User\n * @returns an unthreaded Receipt. Can be undefined if receipts have been disabled\n * or a user chooses to use private read receipts (or we have simply not received\n * a receipt from this user yet).\n */\n public getLastUnthreadedReceiptFor(userId: string): Receipt | undefined {\n return this.room.getLastUnthreadedReceiptFor(userId);\n }\n}\n\n/**\n * Decide whether an event deserves to have its potential edits fetched.\n *\n * @returns true if this event is encrypted and is a message that is part of a\n * thread - either inside it, or a root.\n */\nfunction isAnEncryptedThreadMessage(event: MatrixEvent): boolean {\n return event.isEncrypted() && (event.isRelation(THREAD_RELATION_TYPE.name) || event.isThreadRoot);\n}\n\nexport const FILTER_RELATED_BY_SENDERS = new ServerControlledNamespacedValue(\n \"related_by_senders\",\n \"io.element.relation_senders\",\n);\nexport const FILTER_RELATED_BY_REL_TYPES = new ServerControlledNamespacedValue(\n \"related_by_rel_types\",\n \"io.element.relation_types\",\n);\nexport const THREAD_RELATION_TYPE = new ServerControlledNamespacedValue(\"m.thread\", \"io.element.thread\");\n\nexport enum ThreadFilterType {\n \"My\",\n \"All\",\n}\n\nexport function threadFilterTypeToFilter(type: ThreadFilterType | null): \"all\" | \"participated\" {\n switch (type) {\n case ThreadFilterType.My:\n return \"participated\";\n default:\n return \"all\";\n }\n}\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"file":"thread.js","names":[],"sources":["../../src/models/thread.ts"],"sourcesContent":["/*\nCopyright 2021 - 2023 The Matrix.org Foundation C.I.C.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n*/\n\nimport { type MatrixClient, PendingEventOrdering } from \"../client.ts\";\nimport { TypedReEmitter } from \"../ReEmitter.ts\";\nimport { RelationType } from \"../@types/event.ts\";\nimport { type IThreadBundledRelationship, MatrixEvent, MatrixEventEvent } from \"./event.ts\";\nimport { Direction, EventTimeline } from \"./event-timeline.ts\";\nimport { EventTimelineSet, type EventTimelineSetHandlerMap } from \"./event-timeline-set.ts\";\nimport { type NotificationCountType, type Room, RoomEvent } from \"./room.ts\";\nimport { type RoomState } from \"./room-state.ts\";\nimport { ServerControlledNamespacedValue } from \"../NamespacedValue.ts\";\nimport { logger } from \"../logger.ts\";\nimport { ReadReceipt } from \"./read-receipt.ts\";\nimport { type CachedReceiptStructure, type Receipt, ReceiptType } from \"../@types/read_receipts.ts\";\nimport { Feature, ServerSupport } from \"../feature.ts\";\n\nexport enum ThreadEvent {\n New = \"Thread.new\",\n Update = \"Thread.update\",\n NewReply = \"Thread.newReply\",\n ViewThread = \"Thread.viewThread\",\n Delete = \"Thread.delete\",\n}\n\nexport type ThreadEmittedEvents = Exclude<ThreadEvent, ThreadEvent.New> | RoomEvent.Timeline | RoomEvent.TimelineReset;\n\nexport type ThreadEventHandlerMap = {\n [ThreadEvent.Update]: (thread: Thread) => void;\n [ThreadEvent.NewReply]: (thread: Thread, event: MatrixEvent) => void;\n [ThreadEvent.ViewThread]: () => void;\n [ThreadEvent.Delete]: (thread: Thread) => void;\n} & EventTimelineSetHandlerMap;\n\ninterface IThreadOpts {\n room: Room;\n client: MatrixClient;\n pendingEventOrdering?: PendingEventOrdering;\n receipts?: CachedReceiptStructure[];\n}\n\nexport enum FeatureSupport {\n None = 0,\n Experimental = 1,\n Stable = 2,\n}\n\nexport function determineFeatureSupport(stable: boolean, unstable: boolean): FeatureSupport {\n if (stable) {\n return FeatureSupport.Stable;\n } else if (unstable) {\n return FeatureSupport.Experimental;\n } else {\n return FeatureSupport.None;\n }\n}\n\nexport class Thread extends ReadReceipt<ThreadEmittedEvents, ThreadEventHandlerMap> {\n public static hasServerSideSupport = FeatureSupport.None;\n public static hasServerSideListSupport = FeatureSupport.None;\n public static hasServerSideFwdPaginationSupport = FeatureSupport.None;\n\n /**\n * A reference to all the events ID at the bottom of the threads\n */\n public readonly timelineSet: EventTimelineSet;\n\n private _currentUserParticipated = false;\n\n private reEmitter: TypedReEmitter<ThreadEmittedEvents, ThreadEventHandlerMap>;\n\n /**\n * The last event in this thread, if we don't yet have this in the timeline.\n *\n * When we run {@link processRootEvent} (which I think happens during the\n * setting-up of the thread), we set this to the event pointed to by the\n * server in `latest_event` [1] that came through with the thread root.\n *\n * [1]: https://spec.matrix.org/v1.8/client-server-api/#server-side-aggregation-of-mthread-relationships\n *\n * Later, when we have populated the timeline, this is set to undefined, so\n * that methods like {@link replyToEvent} fall through to use lastReply,\n * which looks in the timeline for the latest event that is a \"thread reply\"\n * i.e. directly refers to the thread root with an m.thread relation.\n *\n * So it looks like this is only really relevant when initialEventsFetched\n * is false, because as soon as the initial events have been fetched, we\n * should have a proper chunk of timeline from the pagination fetch.\n *\n * If all replies in this thread are redacted, this is set to the root\n * event. I'm not clear what the meaning of this is, since usually after the\n * initial events have been fetched, lastEvent should be undefined.\n * In fact, the whole usage inside onRedaction looks suspect - it may be\n * that we were thinking lastEvent always refers to the actual last event,\n * but it only does so before initialEventsFetched becomes true.\n *\n * The usage of lastEvent inside {@link onEcho} looks suspicious, since I'd\n * think we probably mean {@link replyToEvent} there - we are trying not to\n * echo a duplicate event, and we probably want that behaviour even after\n * initialEventsFetched has become true.\n *\n * -- andyb\n */\n private lastEvent: MatrixEvent | undefined;\n\n private replyCount = 0;\n private lastPendingEvent: MatrixEvent | undefined;\n private pendingReplyCount = 0;\n\n public readonly room: Room;\n public readonly client: MatrixClient;\n private readonly pendingEventOrdering: PendingEventOrdering;\n private processRootEventPromise?: Promise<void>;\n\n /**\n * Whether or not we need to fetch the initial set of events for the thread. We can\n * only do this if the server has support for it, so if it doesn't we just pretend\n * that we've already fetched them.\n */\n public initialEventsFetched = !Thread.hasServerSideSupport;\n private initalEventFetchProm: Promise<boolean> | undefined;\n\n /**\n * An array of events to add to the timeline once the thread has been initialised\n * with server suppport.\n */\n public replayEvents: MatrixEvent[] | null = [];\n\n public constructor(\n public readonly id: string,\n public rootEvent: MatrixEvent | undefined,\n opts: IThreadOpts,\n ) {\n super();\n\n // each Event in the thread adds a reemitter, so we could hit the listener limit.\n this.setMaxListeners(1000);\n\n if (!opts?.room) {\n // Logging/debugging for https://github.com/vector-im/element-web/issues/22141\n // Hope is that we end up with a more obvious stack trace.\n throw new Error(\"element-web#22141: A thread requires a room in order to function\");\n }\n\n this.room = opts.room;\n this.client = opts.client;\n this.pendingEventOrdering = opts.pendingEventOrdering ?? PendingEventOrdering.Chronological;\n this.timelineSet = new EventTimelineSet(\n this.room,\n {\n timelineSupport: true,\n pendingEvents: true,\n },\n this.client,\n this,\n );\n this.reEmitter = new TypedReEmitter(this);\n\n this.reEmitter.reEmit(this.timelineSet, [RoomEvent.Timeline, RoomEvent.TimelineReset]);\n\n this.room.on(MatrixEventEvent.BeforeRedaction, this.onBeforeRedaction);\n this.room.on(RoomEvent.Redaction, this.onRedaction);\n this.room.on(RoomEvent.LocalEchoUpdated, this.onLocalEcho);\n this.room.on(RoomEvent.TimelineReset, this.onTimelineReset);\n this.timelineSet.on(RoomEvent.Timeline, this.onTimelineEvent);\n\n this.processReceipts(opts.receipts);\n\n // even if this thread is thought to be originating from this client, we initialise it as we may be in a\n // gappy sync and a thread around this event may already exist.\n this.updateThreadMetadata();\n this.setEventMetadata(this.rootEvent);\n }\n\n private onTimelineReset = async (): Promise<void> => {\n // We hit a gappy sync, ask the server for an update\n await this.processRootEventPromise;\n this.processRootEventPromise = undefined;\n };\n\n private async fetchRootEvent(): Promise<void> {\n // Always fetch the root event, even if we already have it, so we can get the latest\n // state (via unsigned).\n try {\n const eventData = await this.client.fetchRoomEvent(this.roomId, this.id);\n const mapper = this.client.getEventMapper();\n this.rootEvent = mapper(eventData); // will merge with existing event object if such is known\n } catch (e) {\n logger.error(\"Failed to fetch thread root to construct thread with\", e);\n }\n await this.processEvent(this.rootEvent);\n }\n\n public static setServerSideSupport(status: FeatureSupport): void {\n Thread.hasServerSideSupport = status;\n // XXX: This global latching behaviour is really unexpected and means that you can't undo when moving to a server without support\n if (status !== FeatureSupport.Stable) {\n FILTER_RELATED_BY_SENDERS.setPreferUnstable(true);\n FILTER_RELATED_BY_REL_TYPES.setPreferUnstable(true);\n THREAD_RELATION_TYPE.setPreferUnstable(true);\n }\n }\n\n public static setServerSideListSupport(status: FeatureSupport): void {\n Thread.hasServerSideListSupport = status;\n }\n\n public static setServerSideFwdPaginationSupport(status: FeatureSupport): void {\n Thread.hasServerSideFwdPaginationSupport = status;\n }\n\n private onBeforeRedaction = (event: MatrixEvent, redaction: MatrixEvent): void => {\n if (\n event?.isRelation(THREAD_RELATION_TYPE.name) &&\n this.room.eventShouldLiveIn(event).threadId === this.id &&\n event.getId() !== this.id && // the root event isn't counted in the length so ignore this redaction\n !redaction.status // only respect it when it succeeds\n ) {\n this.replyCount--;\n this.updatePendingReplyCount();\n this.emit(ThreadEvent.Update, this);\n }\n };\n\n private onRedaction = async (event: MatrixEvent, room: Room, threadRootId?: string): Promise<void> => {\n if (threadRootId !== this.id) return; // ignore redactions for other timelines\n if (this.replyCount <= 0) {\n for (const threadEvent of this.timeline) {\n this.clearEventMetadata(threadEvent);\n }\n this.lastEvent = this.rootEvent;\n this._currentUserParticipated = false;\n this.emit(ThreadEvent.Delete, this);\n } else {\n if (this.lastEvent?.getId() === event.getAssociatedId()) {\n // XXX: If our last event got redacted we query the server for the last event once again\n await this.processRootEventPromise;\n this.processRootEventPromise = undefined;\n }\n await this.updateThreadMetadata();\n }\n };\n\n private onTimelineEvent = (\n event: MatrixEvent,\n room: Room | undefined,\n toStartOfTimeline: boolean | undefined,\n ): void => {\n // Add a synthesized receipt when paginating forward in the timeline\n if (!toStartOfTimeline) {\n const sender = event.getSender();\n if (sender && room && this.shouldSendLocalEchoReceipt(sender, event)) {\n room.addLocalEchoReceipt(sender, event, ReceiptType.Read);\n }\n if (event.getId() !== this.id && event.isRelation(THREAD_RELATION_TYPE.name)) {\n this.replyCount++;\n }\n }\n this.onEcho(event, toStartOfTimeline ?? false);\n };\n\n private shouldSendLocalEchoReceipt(sender: string, event: MatrixEvent): boolean {\n const recursionSupport = this.client.canSupport.get(Feature.RelationsRecursion) ?? ServerSupport.Unsupported;\n\n if (recursionSupport === ServerSupport.Unsupported) {\n // Normally we add a local receipt, but if we don't have\n // recursion support, then events may arrive out of order, so we\n // only create a receipt if it's after our existing receipt.\n const oldReceiptEventId = this.getReadReceiptForUserId(sender)?.eventId;\n if (oldReceiptEventId) {\n const receiptEvent = this.findEventById(oldReceiptEventId);\n if (receiptEvent && receiptEvent.getTs() > event.getTs()) {\n return false;\n }\n }\n }\n\n return true;\n }\n\n private onLocalEcho = (event: MatrixEvent): void => {\n this.onEcho(event, false);\n };\n\n private onEcho = async (event: MatrixEvent, toStartOfTimeline: boolean): Promise<void> => {\n if (event.threadRootId !== this.id) return; // ignore echoes for other timelines\n if (this.lastEvent === event) return; // ignore duplicate events\n await this.updateThreadMetadata();\n if (!event.isRelation(THREAD_RELATION_TYPE.name)) return; // don't send a new reply event for reactions or edits\n if (toStartOfTimeline) return; // ignore messages added to the start of the timeline\n // Clear the lastEvent and instead start tracking locally using lastReply\n this.lastEvent = undefined;\n this.emit(ThreadEvent.NewReply, this, event);\n };\n\n public get roomState(): RoomState {\n return this.room.getLiveTimeline().getState(EventTimeline.FORWARDS)!;\n }\n\n private addEventToTimeline(event: MatrixEvent, toStartOfTimeline: boolean): void {\n if (!this.findEventById(event.getId()!)) {\n this.timelineSet.addEventToTimeline(event, this.liveTimeline, {\n toStartOfTimeline,\n fromCache: false,\n roomState: this.roomState,\n addToState: false,\n });\n }\n }\n\n /**\n * TEMPORARY. Only call this when MSC3981 is not available, and we have some\n * late-arriving events to insert, because we recursively found them as part\n * of populating a thread. When we have MSC3981 we won't need it, because\n * they will all be supplied by the homeserver in one request, and they will\n * already be in the right order in that response.\n * This is a copy of addEventToTimeline above, modified to call\n * insertEventIntoTimeline so this event is inserted into our best guess of\n * the right place based on timestamp. (We should be using Sync Order but we\n * don't have it.)\n *\n * @internal\n */\n public insertEventIntoTimeline(event: MatrixEvent): void {\n const eventId = event.getId();\n if (!eventId) {\n return;\n }\n // If the event is already in this thread, bail out\n if (this.findEventById(eventId)) {\n return;\n }\n this.timelineSet.insertEventIntoTimeline(event, this.liveTimeline, this.roomState, false);\n }\n\n public addEvents(events: MatrixEvent[], toStartOfTimeline: boolean): void {\n events.forEach((ev) => this.addEvent(ev, toStartOfTimeline, false));\n this.updateThreadMetadata();\n }\n\n /**\n * Add an event to the thread and updates\n * the tail/root references if needed\n * Will fire \"Thread.update\"\n * @param event - The event to add\n * @param toStartOfTimeline - whether the event is being added\n * to the start (and not the end) of the timeline.\n * @param emit - whether to emit the Update event if the thread was updated or not.\n */\n public addEvent(event: MatrixEvent, toStartOfTimeline: boolean, emit = true): void {\n // Modify this event to point at our room's state, and mark its thread\n // as this.\n this.setEventMetadata(event);\n\n // Decide whether this event is going to be added at the end of the timeline.\n const lastReply = this.lastReply();\n const isNewestReply = !lastReply || event.localTimestamp >= lastReply!.localTimestamp;\n\n if (!Thread.hasServerSideSupport) {\n // When there's no server-side support, just add it to the end of the timeline.\n this.addEventToTimeline(event, toStartOfTimeline);\n this.client.decryptEventIfNeeded(event);\n } else if (event.isRelation(RelationType.Annotation) || event.isRelation(RelationType.Replace)) {\n this.addRelatedThreadEvent(event, toStartOfTimeline);\n return;\n } else if (!toStartOfTimeline && isNewestReply) {\n // When we've asked for the event to be added to the end,\n // and this event belongs at the end, add it.\n this.addEventToTimeline(event, false);\n this.fetchEditsWhereNeeded(event);\n } else {\n // Otherwise, we should add it, but we suspect it is out of order.\n // This may be because we've just created the thread object and are\n // still fetching events, in which case add it where we think is sensible\n // and it will be removed and replaced with the events from the pagination\n // request once that completes.\n if (toStartOfTimeline) {\n // If we're adding at the start of the timeline, it doesn't\n // matter that it's out of order.\n this.addEventToTimeline(event, toStartOfTimeline);\n } else {\n // We think this event might be out of order, because isNewestReply\n // is false (otherwise we would have gone into the earlier if\n // clause), so try to insert it in the right place based on\n // timestamp.\n this.insertEventIntoTimeline(event);\n }\n }\n\n if (\n event.getId() !== this.id &&\n event.isRelation(THREAD_RELATION_TYPE.name) &&\n !toStartOfTimeline &&\n isNewestReply\n ) {\n // Clear the last event as we have the latest end of the timeline\n this.lastEvent = undefined;\n }\n\n if (emit) {\n this.emit(ThreadEvent.NewReply, this, event);\n this.updateThreadMetadata();\n }\n }\n\n private addRelatedThreadEvent(event: MatrixEvent, toStartOfTimeline: boolean): void {\n // If this event is not a direct member of the thread, but is a\n // reference to something that is, then we have two cases:\n\n if (!this.initialEventsFetched) {\n // Case 1: we haven't yet fetched events from the server. In\n // this case, when we do, the events we get back might only be\n // the first-order ones, so this event (which is second-order -\n // a reference to something directly in the thread) needs to be\n // kept so we can replay it when the first-order ones turn up.\n\n /**\n * A thread can be fully discovered via a single sync response\n * And when that's the case we still ask the server to do an initialisation\n * as it's the safest to ensure we have everything.\n * However when we are in that scenario we might loose annotation or edits\n *\n * This fix keeps a reference to those events and replay them once the thread\n * has been initialised properly.\n */\n this.replayEvents?.push(event);\n\n // For annotations (reactions), aggregate immediately (pre-init) to keep\n // reaction counts/summary visible while the thread is still initialising.\n // Only aggregate as child: parent aggregation is unnecessary here.\n if (event.isRelation(RelationType.Annotation)) {\n this.timelineSet.relations?.aggregateChildEvent(event, this.timelineSet);\n }\n } else {\n // Case 2: this is happening later, and we have a timeline. In\n // this case, these events might be out-of order.\n //\n // Specifically, if the server doesn't support recursion, so we\n // only get these events through sync, they might be coming\n // later than the first-order ones, so we insert them based on\n // timestamp (despite the problems with this documented in\n // #3325).\n //\n // If the server does support recursion, we should have got all\n // the interspersed events from the server when we fetched the\n // initial events, so if they are coming via sync they should be\n // the latest ones, so we can add them as normal.\n //\n // (Note that both insertEventIntoTimeline and addEventToTimeline\n // do nothing if we have seen this event before.)\n\n const recursionSupport =\n this.client.canSupport.get(Feature.RelationsRecursion) ?? ServerSupport.Unsupported;\n\n if (recursionSupport === ServerSupport.Unsupported) {\n this.insertEventIntoTimeline(event);\n } else {\n this.addEventToTimeline(event, toStartOfTimeline);\n }\n // Aggregation is handled by EventTimelineSet when inserting/adding.\n }\n }\n\n public async processEvent(event: MatrixEvent | null | undefined): Promise<void> {\n if (event) {\n this.setEventMetadata(event);\n await this.fetchEditsWhereNeeded(event);\n }\n }\n\n /**\n * Processes the receipts that were caught during initial sync\n * When clients become aware of a thread, they try to retrieve those read receipts\n * and apply them to the current thread\n * @param receipts - A collection of the receipts cached from initial sync\n */\n private processReceipts(receipts: CachedReceiptStructure[] = []): void {\n for (const { eventId, receiptType, userId, receipt, synthetic } of receipts) {\n this.addReceiptToStructure(eventId, receiptType as ReceiptType, userId, receipt, synthetic);\n }\n }\n\n private getRootEventBundledRelationship(rootEvent = this.rootEvent): IThreadBundledRelationship | undefined {\n return rootEvent?.getServerAggregatedRelation<IThreadBundledRelationship>(THREAD_RELATION_TYPE.name);\n }\n\n private async processRootEvent(): Promise<void> {\n const bundledRelationship = this.getRootEventBundledRelationship();\n if (Thread.hasServerSideSupport && bundledRelationship) {\n this.replyCount = bundledRelationship.count;\n this._currentUserParticipated = !!bundledRelationship.current_user_participated;\n\n const mapper = this.client.getEventMapper();\n // re-insert roomId\n this.lastEvent = mapper({\n ...bundledRelationship.latest_event,\n room_id: this.roomId,\n });\n this.updatePendingReplyCount();\n await this.processEvent(this.lastEvent);\n }\n }\n\n private updatePendingReplyCount(): void {\n const unfilteredPendingEvents =\n this.pendingEventOrdering === PendingEventOrdering.Detached ? this.room.getPendingEvents() : this.events;\n const pendingEvents = unfilteredPendingEvents.filter(\n (ev) =>\n ev.threadRootId === this.id &&\n ev.isRelation(THREAD_RELATION_TYPE.name) &&\n ev.status !== null &&\n ev.getId() !== this.lastEvent?.getId(),\n );\n this.lastPendingEvent = pendingEvents.length ? pendingEvents[pendingEvents.length - 1] : undefined;\n this.pendingReplyCount = pendingEvents.length;\n }\n\n /**\n * Reset the live timeline of all timelineSets, and start new ones.\n *\n * <p>This is used when /sync returns a 'limited' timeline. 'Limited' means that there's a gap between the messages\n * /sync returned, and the last known message in our timeline. In such a case, our live timeline isn't live anymore\n * and has to be replaced by a new one. To make sure we can continue paginating our timelines correctly, we have to\n * set new pagination tokens on the old and the new 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, removing old ones (including the previous live\n * timeline which would otherwise be unable to paginate forwards without this token).\n * Removing just the old live timeline whilst preserving previous ones is not supported.\n */\n public async resetLiveTimeline(\n backPaginationToken?: string | null,\n forwardPaginationToken?: string | null,\n ): Promise<void> {\n const oldLive = this.liveTimeline;\n this.timelineSet.resetLiveTimeline(backPaginationToken ?? undefined, forwardPaginationToken ?? undefined);\n const newLive = this.liveTimeline;\n\n // FIXME: Remove the following as soon as https://github.com/matrix-org/synapse/issues/14830 is resolved.\n //\n // The pagination API for thread timelines currently can't handle the type of pagination tokens returned by sync\n //\n // To make this work anyway, we'll have to transform them into one of the types that the API can handle.\n // One option is passing the tokens to /messages, which can handle sync tokens, and returns the right format.\n // /messages does not return new tokens on requests with a limit of 0.\n // This means our timelines might overlap a slight bit, but that's not an issue, as we deduplicate messages\n // anyway.\n\n let newBackward: string | undefined;\n let oldForward: string | undefined;\n if (backPaginationToken) {\n const res = await this.client.createMessagesRequest(this.roomId, backPaginationToken, 1, Direction.Forward);\n newBackward = res.end;\n }\n if (forwardPaginationToken) {\n const res = await this.client.createMessagesRequest(\n this.roomId,\n forwardPaginationToken,\n 1,\n Direction.Backward,\n );\n oldForward = res.start;\n }\n // Only replace the token if we don't have paginated away from this position already. This situation doesn't\n // occur today, but if the above issue is resolved, we'd have to go down this path.\n if (forwardPaginationToken && oldLive.getPaginationToken(Direction.Forward) === forwardPaginationToken) {\n oldLive.setPaginationToken(oldForward ?? null, Direction.Forward);\n }\n if (backPaginationToken && newLive.getPaginationToken(Direction.Backward) === backPaginationToken) {\n newLive.setPaginationToken(newBackward ?? null, Direction.Backward);\n }\n }\n\n private async updateThreadFromRootEvent(): Promise<void> {\n if (Thread.hasServerSideSupport) {\n // Ensure we show *something* as soon as possible, we'll update it as soon as we get better data, but we\n // don't want the thread preview to be empty if we can avoid it\n if (!this.initialEventsFetched && !this.lastEvent) {\n await this.processRootEvent();\n }\n await this.fetchRootEvent();\n }\n await this.processRootEvent();\n }\n\n private async updateThreadMetadata(): Promise<void> {\n this.updatePendingReplyCount();\n\n if (!this.processRootEventPromise) {\n // We only want to do this once otherwise we end up rolling back to the last unsigned summary we have for the thread\n this.processRootEventPromise = this.updateThreadFromRootEvent();\n }\n await this.processRootEventPromise;\n\n if (!this.initialEventsFetched) {\n if (this.initalEventFetchProm) {\n await this.initalEventFetchProm;\n } else {\n // fetch initial events to allow proper pagination\n try {\n // clear out any events that were added before the pagination request\n // completed (eg. from sync). They'll be replaced by those from the pagination.\n // Really, we should do this after the pagination request completes, but\n // paginateEventTimeline does the request and adds the events in one go, so\n // this would need a refactor in order to do. It's therefore possible there's\n // a remaining race where an event comes in while the pagination request is\n // happening.\n this.timelineSet.resetLiveTimeline();\n // if the thread has regular events, this will just load the last reply.\n // if the thread is newly created, this will load the root event.\n if (this.replyCount === 0 && this.rootEvent) {\n this.timelineSet.addEventsToTimeline([this.rootEvent], true, false, this.liveTimeline, null);\n this.liveTimeline.setPaginationToken(null, Direction.Backward);\n } else {\n this.initalEventFetchProm = this.client.paginateEventTimeline(this.liveTimeline, {\n backwards: true,\n });\n await this.initalEventFetchProm;\n }\n // We have now fetched the initial events, so set the flag. We need to do this before\n // we actually add the events, so `this.addEvents` knows that it can now safely add\n // them rather than buffer them in the pending event list. The main thing is that this\n // must remain false while the async fetch happens, so we don't try to add events before\n // the pagination has finished. The important thing is that we're not await-ing anything\n // else between setting this and adding events, so no races.\n this.initialEventsFetched = true;\n for (const event of this.replayEvents!) {\n this.addEvent(event, false);\n }\n this.replayEvents = null;\n // just to make sure that, if we've created a timeline window for this thread before the thread itself\n // existed (e.g. when creating a new thread), we'll make sure the panel is force refreshed correctly.\n this.emit(RoomEvent.TimelineReset, this.room, this.timelineSet, true);\n } catch (e) {\n logger.error(\"Failed to load start of newly created thread: \", e);\n this.initialEventsFetched = false;\n }\n }\n }\n\n this.emit(ThreadEvent.Update, this);\n }\n\n // XXX: Workaround for https://github.com/matrix-org/matrix-spec-proposals/pull/2676/files#r827240084\n private async fetchEditsWhereNeeded(...events: MatrixEvent[]): Promise<unknown> {\n const recursionSupport = this.client.canSupport.get(Feature.RelationsRecursion) ?? ServerSupport.Unsupported;\n if (recursionSupport === ServerSupport.Unsupported) {\n return Promise.all(\n events.filter(isAnEncryptedThreadMessage).map(async (event: MatrixEvent) => {\n try {\n const relations = await this.client.relations(\n this.roomId,\n event.getId()!,\n RelationType.Replace,\n event.getType(),\n {\n limit: 1,\n },\n );\n if (relations.events.length) {\n const editEvent = relations.events[0];\n event.makeReplaced(editEvent);\n this.insertEventIntoTimeline(editEvent);\n }\n } catch (e) {\n logger.error(\"Failed to load edits for encrypted thread event\", e);\n }\n }),\n );\n }\n }\n\n public setEventMetadata(event: MatrixEvent | null | undefined): void {\n if (event) {\n EventTimeline.setEventMetadata(event, this.roomState, false);\n event.setThread(this);\n }\n }\n\n public clearEventMetadata(event: MatrixEvent | null | undefined): void {\n if (event) {\n event.setThread(undefined);\n delete event.event?.unsigned?.[\"m.relations\"]?.[THREAD_RELATION_TYPE.name];\n }\n }\n\n /**\n * Finds an event by ID in the current thread\n */\n public findEventById(eventId: string): MatrixEvent | undefined {\n return this.timelineSet.findEventById(eventId);\n }\n\n /**\n * Return last reply to the thread, if known.\n */\n public lastReply(\n matches: (ev: MatrixEvent) => boolean = (ev): boolean => ev.isRelation(THREAD_RELATION_TYPE.name),\n ): MatrixEvent | null {\n for (let i = this.timeline.length - 1; i >= 0; i--) {\n const event = this.timeline[i];\n if (matches(event)) {\n return event;\n }\n }\n return null;\n }\n\n public get roomId(): string {\n return this.room.roomId;\n }\n\n /**\n * The number of messages in the thread\n * Only count rel_type=m.thread as we want to\n * exclude annotations from that number\n */\n public get length(): number {\n return this.replyCount + this.pendingReplyCount;\n }\n\n /**\n * A getter for the last event of the thread.\n * This might be a synthesized event, if so, it will not emit any events to listeners.\n */\n public get replyToEvent(): MatrixEvent | null {\n return this.lastPendingEvent ?? this.lastEvent ?? this.lastReply();\n }\n\n /**\n * The live event timeline for this thread.\n * @deprecated Present for backwards compatibility.\n * Use this.events instead\n * @returns The live event timeline for this thread.\n */\n public get timeline(): MatrixEvent[] {\n return this.events;\n }\n\n public get events(): MatrixEvent[] {\n return this.liveTimeline.getEvents();\n }\n\n public has(eventId: string): boolean {\n return this.timelineSet.findEventById(eventId) instanceof MatrixEvent;\n }\n\n public get hasCurrentUserParticipated(): boolean {\n return this._currentUserParticipated;\n }\n\n public get liveTimeline(): EventTimeline {\n return this.timelineSet.getLiveTimeline();\n }\n\n public getUnfilteredTimelineSet(): EventTimelineSet {\n return this.timelineSet;\n }\n\n public addReceipt(event: MatrixEvent, synthetic: boolean): void {\n throw new Error(\"Unsupported function on the thread model\");\n }\n\n /**\n * Get the ID of the event that a given user has read up to within this thread,\n * or null if we have received no read receipt (at all) from them.\n * @param userId - The user ID to get read receipt event ID for\n * @param ignoreSynthesized - If true, return only receipts that have been\n * sent by the server, not implicit ones generated\n * by the JS SDK.\n * @returns ID of the latest event that the given user has read, or null.\n */\n public getEventReadUpTo(userId: string, ignoreSynthesized?: boolean): string | null {\n // TODO: we think the implementation here is not right. Here is a sketch\n // of the right answer:\n //\n // for event in timeline.events.reversed():\n // if room.hasUserReadEvent(event):\n // return event\n // return null\n //\n // If this is too slow, we might be able to improve it by trying walking\n // forward from the threaded receipt in this thread. We could alternate\n // between backwards-from-front and forwards-from-threaded-receipt to\n // improve our chances of hitting the right answer sooner.\n //\n // Either way, it's still fundamentally slow because we have to walk\n // events.\n //\n // We also might just want to limit the time we spend on this by giving\n // up after, say, 100 events.\n //\n // --- andyb\n\n const isCurrentUser = userId === this.client.getUserId();\n const lastReply = this.timeline[this.timeline.length - 1];\n if (isCurrentUser && lastReply) {\n // If the last activity in a thread is prior to the first threaded read receipt\n // sent in the room (suggesting that it was sent before the user started\n // using a client that supported threaded read receipts), we want to\n // consider this thread as read.\n const beforeFirstThreadedReceipt = lastReply.getTs() < this.room.getOldestThreadedReceiptTs();\n const lastReplyId = lastReply.getId();\n // Some unsent events do not have an ID, we do not want to consider them read\n if (beforeFirstThreadedReceipt && lastReplyId) {\n return lastReplyId;\n }\n }\n\n const readUpToId = super.getEventReadUpTo(userId, ignoreSynthesized);\n\n // Check whether the unthreaded read receipt for that user is more recent\n // than the read receipt inside that thread.\n if (lastReply) {\n const unthreadedReceipt = this.room.getLastUnthreadedReceiptFor(userId);\n if (!unthreadedReceipt) {\n return readUpToId;\n }\n\n for (let i = this.timeline?.length - 1; i >= 0; --i) {\n const ev = this.timeline[i];\n // If we encounter the `readUpToId` we do not need to look further\n // there is no \"more recent\" unthreaded read receipt\n if (ev.getId() === readUpToId) return readUpToId;\n\n // Inspecting events from most recent to oldest, we're checking\n // whether an unthreaded read receipt is more recent that the current event.\n // We usually prefer relying on the order of the DAG but in this scenario\n // it is not possible and we have to rely on timestamp\n if (ev.getTs() < unthreadedReceipt.ts) return ev.getId() ?? readUpToId;\n }\n }\n\n return readUpToId;\n }\n\n /**\n * Determine if the given user has read a particular event.\n *\n * It is invalid to call this method with an event that is not part of this thread.\n *\n * This is not a definitive check as it only checks the events that have been\n * loaded client-side at the time of execution.\n * @param userId - The user ID to check the read state of.\n * @param eventId - The event ID to check if the user read.\n * @returns True if the user has read the event, false otherwise.\n */\n public hasUserReadEvent(userId: string, eventId: string): boolean {\n if (userId === this.client.getUserId()) {\n // Consider an event read if it's part of a thread that is before the\n // first threaded receipt sent in that room. It is likely that it is\n // part of a thread that was created before MSC3771 was implemented.\n // Or before the last unthreaded receipt for the logged in user\n const beforeFirstThreadedReceipt =\n (this.lastReply()?.getTs() ?? 0) < this.room.getOldestThreadedReceiptTs();\n const unthreadedReceiptTs = this.room.getLastUnthreadedReceiptFor(userId)?.ts ?? 0;\n const beforeLastUnthreadedReceipt = (this?.lastReply()?.getTs() ?? 0) < unthreadedReceiptTs;\n if (beforeFirstThreadedReceipt || beforeLastUnthreadedReceipt) {\n return true;\n }\n }\n\n return this.room.hasUserReadEvent(userId, eventId);\n }\n\n public setUnread(type: NotificationCountType, count: number): void {\n return this.room.setThreadUnreadNotificationCount(this.id, type, count);\n }\n\n /**\n * Returns the most recent unthreaded receipt for a given user\n * @param userId - the MxID of the User\n * @returns an unthreaded Receipt. Can be undefined if receipts have been disabled\n * or a user chooses to use private read receipts (or we have simply not received\n * a receipt from this user yet).\n */\n public getLastUnthreadedReceiptFor(userId: string): Receipt | undefined {\n return this.room.getLastUnthreadedReceiptFor(userId);\n }\n}\n\n/**\n * Decide whether an event deserves to have its potential edits fetched.\n *\n * @returns true if this event is encrypted and is a message that is part of a\n * thread - either inside it, or a root.\n */\nfunction isAnEncryptedThreadMessage(event: MatrixEvent): boolean {\n return event.isEncrypted() && (event.isRelation(THREAD_RELATION_TYPE.name) || event.isThreadRoot);\n}\n\nexport const FILTER_RELATED_BY_SENDERS = new ServerControlledNamespacedValue(\n \"related_by_senders\",\n \"io.element.relation_senders\",\n);\nexport const FILTER_RELATED_BY_REL_TYPES = new ServerControlledNamespacedValue(\n \"related_by_rel_types\",\n \"io.element.relation_types\",\n);\nexport const THREAD_RELATION_TYPE = new ServerControlledNamespacedValue(\"m.thread\", \"io.element.thread\");\n\nexport enum ThreadFilterType {\n My,\n All,\n}\n\nexport function threadFilterTypeToFilter(type: ThreadFilterType | null): \"all\" | \"participated\" {\n switch (type) {\n case ThreadFilterType.My:\n return \"participated\";\n default:\n return \"all\";\n }\n}\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"realtime-callbacks.js","names":[],"sources":["../src/realtime-callbacks.ts"],"sourcesContent":["/*\nCopyright 2016 OpenMarket Ltd\nCopyright 2019 The Matrix.org Foundation C.I.C.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n*/\n\n/* A re-implementation of the javascript callback functions (setTimeout,\n * clearTimeout; setInterval and clearInterval are not yet implemented) which\n * try to improve handling of large clock jumps (as seen when\n * suspending/resuming the system).\n *\n * In particular, if a timeout would have fired while the system was suspended,\n * it will instead fire as soon as possible after resume.\n */\n\nimport { logger } from \"./logger.ts\";\n\n// we schedule a callback at least this often, to check if we've missed out on\n// some wall-clock time due to being suspended.\nconst TIMER_CHECK_PERIOD_MS = 1000;\n\n// counter, for making up ids to return from setTimeout\nlet count = 0;\n\n// the key for our callback with the real globalThis.setTimeout\nlet realCallbackKey: NodeJS.Timeout | number;\n\ntype Callback = {\n runAt: number;\n func: (...params: any[]) => void;\n params: any[];\n key: number;\n};\n\n// a sorted list of the callbacks to be run.\n// each is an object with keys [runAt, func, params, key].\nconst callbackList: Callback[] = [];\n\n// var debuglog = logger.log.bind(logger);\n/* istanbul ignore next */\nconst debuglog = function (...params: any[]): void {};\n\n/**\n * reimplementation of window.setTimeout, which will call the callback if\n * the wallclock time goes past the deadline.\n *\n * @param func - callback to be called after a delay\n * @param delayMs - number of milliseconds to delay by\n *\n * @returns an identifier for this callback, which may be passed into\n * clearTimeout later.\n */\nexport function setTimeout(func: (...params: any[]) => void, delayMs: number, ...params: any[]): number {\n delayMs = delayMs || 0;\n if (delayMs < 0) {\n delayMs = 0;\n }\n\n const runAt = Date.now() + delayMs;\n const key = count++;\n debuglog(\"setTimeout: scheduling cb\", key, \"at\", runAt, \"(delay\", delayMs, \")\");\n const data = {\n runAt: runAt,\n func: func,\n params: params,\n key: key,\n };\n\n // figure out where it goes in the list\n const idx = binarySearch(callbackList, function (el) {\n return el.runAt - runAt;\n });\n\n callbackList.splice(idx, 0, data);\n scheduleRealCallback();\n\n return key;\n}\n\n/**\n * reimplementation of window.clearTimeout, which mirrors setTimeout\n *\n * @param key - result from an earlier setTimeout call\n */\nexport function clearTimeout(key: number): void {\n if (callbackList.length === 0) {\n return;\n }\n\n // remove the element from the list\n let i: number;\n for (i = 0; i < callbackList.length; i++) {\n const cb = callbackList[i];\n if (cb.key == key) {\n callbackList.splice(i, 1);\n break;\n }\n }\n\n // iff it was the first one in the list, reschedule our callback.\n if (i === 0) {\n scheduleRealCallback();\n }\n}\n\n// use the real globalThis.setTimeout to schedule a callback to runCallbacks.\nfunction scheduleRealCallback(): void {\n if (realCallbackKey) {\n globalThis.clearTimeout(realCallbackKey as NodeJS.Timeout);\n }\n\n const first = callbackList[0];\n\n if (!first) {\n debuglog(\"scheduleRealCallback: no more callbacks, not rescheduling\");\n return;\n }\n\n const timestamp = Date.now();\n const delayMs = Math.min(first.runAt - timestamp, TIMER_CHECK_PERIOD_MS);\n\n debuglog(\"scheduleRealCallback: now:\", timestamp, \"delay:\", delayMs);\n realCallbackKey = globalThis.setTimeout(runCallbacks, delayMs);\n}\n\nfunction runCallbacks(): void {\n const timestamp = Date.now();\n debuglog(\"runCallbacks: now:\", timestamp);\n\n // get the list of things to call\n const callbacksToRun: Callback[] = [];\n
|
|
1
|
+
{"version":3,"file":"realtime-callbacks.js","names":[],"sources":["../src/realtime-callbacks.ts"],"sourcesContent":["/*\nCopyright 2016 OpenMarket Ltd\nCopyright 2019 The Matrix.org Foundation C.I.C.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n*/\n\n/* A re-implementation of the javascript callback functions (setTimeout,\n * clearTimeout; setInterval and clearInterval are not yet implemented) which\n * try to improve handling of large clock jumps (as seen when\n * suspending/resuming the system).\n *\n * In particular, if a timeout would have fired while the system was suspended,\n * it will instead fire as soon as possible after resume.\n */\n\nimport { logger } from \"./logger.ts\";\n\n// we schedule a callback at least this often, to check if we've missed out on\n// some wall-clock time due to being suspended.\nconst TIMER_CHECK_PERIOD_MS = 1000;\n\n// counter, for making up ids to return from setTimeout\nlet count = 0;\n\n// the key for our callback with the real globalThis.setTimeout\nlet realCallbackKey: NodeJS.Timeout | number;\n\ntype Callback = {\n runAt: number;\n func: (...params: any[]) => void;\n params: any[];\n key: number;\n};\n\n// a sorted list of the callbacks to be run.\n// each is an object with keys [runAt, func, params, key].\nconst callbackList: Callback[] = [];\n\n// var debuglog = logger.log.bind(logger);\n/* istanbul ignore next */\nconst debuglog = function (...params: any[]): void {};\n\n/**\n * reimplementation of window.setTimeout, which will call the callback if\n * the wallclock time goes past the deadline.\n *\n * @param func - callback to be called after a delay\n * @param delayMs - number of milliseconds to delay by\n *\n * @returns an identifier for this callback, which may be passed into\n * clearTimeout later.\n */\nexport function setTimeout(func: (...params: any[]) => void, delayMs: number, ...params: any[]): number {\n delayMs = delayMs || 0;\n if (delayMs < 0) {\n delayMs = 0;\n }\n\n const runAt = Date.now() + delayMs;\n const key = count++;\n debuglog(\"setTimeout: scheduling cb\", key, \"at\", runAt, \"(delay\", delayMs, \")\");\n const data = {\n runAt: runAt,\n func: func,\n params: params,\n key: key,\n };\n\n // figure out where it goes in the list\n const idx = binarySearch(callbackList, function (el) {\n return el.runAt - runAt;\n });\n\n callbackList.splice(idx, 0, data);\n scheduleRealCallback();\n\n return key;\n}\n\n/**\n * reimplementation of window.clearTimeout, which mirrors setTimeout\n *\n * @param key - result from an earlier setTimeout call\n */\nexport function clearTimeout(key: number): void {\n if (callbackList.length === 0) {\n return;\n }\n\n // remove the element from the list\n let i: number;\n for (i = 0; i < callbackList.length; i++) {\n const cb = callbackList[i];\n if (cb.key == key) {\n callbackList.splice(i, 1);\n break;\n }\n }\n\n // iff it was the first one in the list, reschedule our callback.\n if (i === 0) {\n scheduleRealCallback();\n }\n}\n\n// use the real globalThis.setTimeout to schedule a callback to runCallbacks.\nfunction scheduleRealCallback(): void {\n if (realCallbackKey) {\n globalThis.clearTimeout(realCallbackKey as NodeJS.Timeout);\n }\n\n const first = callbackList[0];\n\n if (!first) {\n debuglog(\"scheduleRealCallback: no more callbacks, not rescheduling\");\n return;\n }\n\n const timestamp = Date.now();\n const delayMs = Math.min(first.runAt - timestamp, TIMER_CHECK_PERIOD_MS);\n\n debuglog(\"scheduleRealCallback: now:\", timestamp, \"delay:\", delayMs);\n realCallbackKey = globalThis.setTimeout(runCallbacks, delayMs);\n}\n\nfunction runCallbacks(): void {\n const timestamp = Date.now();\n debuglog(\"runCallbacks: now:\", timestamp);\n\n // get the list of things to call\n const callbacksToRun: Callback[] = [];\n while (true) {\n const first = callbackList[0];\n if (!first || first.runAt > timestamp) {\n break;\n }\n const cb = callbackList.shift()!;\n debuglog(\"runCallbacks: popping\", cb.key);\n callbacksToRun.push(cb);\n }\n\n // reschedule the real callback before running our functions, to\n // keep the codepaths the same whether or not our functions\n // register their own setTimeouts.\n scheduleRealCallback();\n\n for (const cb of callbacksToRun) {\n try {\n cb.func.apply(globalThis, cb.params);\n } catch (e) {\n logger.error(\"Uncaught exception in callback function\", e);\n }\n }\n}\n\n/* search in a sorted array.\n *\n * returns the index of the last element for which func returns\n * greater than zero, or array.length if no such element exists.\n */\nfunction binarySearch<T>(array: T[], func: (v: T) => number): number {\n // min is inclusive, max exclusive.\n let min = 0;\n let max = array.length;\n\n while (min < max) {\n const mid = (min + max) >> 1;\n const res = func(array[mid]);\n if (res > 0) {\n // the element at 'mid' is too big; set it as the new max.\n max = mid;\n } else {\n // the element at 'mid' is too small. 'min' is inclusive, so +1.\n min = mid + 1;\n }\n }\n // presumably, min==max now.\n return min;\n}\n"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,SAAS,MAAM,QAAQ,aAAa;;AAEpC;AACA;AACA,MAAM,qBAAqB,GAAG,IAAI;;AAElC;AACA,IAAI,KAAK,GAAG,CAAC;;AAEb;AACA,IAAI,eAAwC;AAS5C;AACA;AACA,MAAM,YAAwB,GAAG,EAAE;;AAEnC;AACA;AACA,MAAM,QAAQ,GAAG,UAAU,GAAG,MAAa,EAAQ,CAAC,CAAC;;AAErD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAAS,UAAU,CAAC,IAAgC,EAAE,OAAe,EAAE,GAAG,MAAa,EAAU;EACpG,OAAO,GAAG,OAAO,IAAI,CAAC;EACtB,IAAI,OAAO,GAAG,CAAC,EAAE;IACb,OAAO,GAAG,CAAC;EACf;EAEA,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,OAAO;EAClC,MAAM,GAAG,GAAG,KAAK,EAAE;EACnB,QAAQ,CAAC,2BAA2B,EAAE,GAAG,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,CAAC;EAC/E,MAAM,IAAI,GAAG;IACT,KAAK,EAAE,KAAK;IACZ,IAAI,EAAE,IAAI;IACV,MAAM,EAAE,MAAM;IACd,GAAG,EAAE;EACT,CAAC;;EAED;EACA,MAAM,GAAG,GAAG,YAAY,CAAC,YAAY,EAAE,UAAU,EAAE,EAAE;IACjD,OAAO,EAAE,CAAC,KAAK,GAAG,KAAK;EAC3B,CAAC,CAAC;EAEF,YAAY,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,EAAE,IAAI,CAAC;EACjC,oBAAoB,CAAC,CAAC;EAEtB,OAAO,GAAG;AACd;;AAEA;AACA;AACA;AACA;AACA;AACA,OAAO,SAAS,YAAY,CAAC,GAAW,EAAQ;EAC5C,IAAI,YAAY,CAAC,MAAM,KAAK,CAAC,EAAE;IAC3B;EACJ;;EAEA;EACA,IAAI,CAAS;EACb,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,YAAY,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;IACtC,MAAM,EAAE,GAAG,YAAY,CAAC,CAAC,CAAC;IAC1B,IAAI,EAAE,CAAC,GAAG,IAAI,GAAG,EAAE;MACf,YAAY,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC;MACzB;IACJ;EACJ;;EAEA;EACA,IAAI,CAAC,KAAK,CAAC,EAAE;IACT,oBAAoB,CAAC,CAAC;EAC1B;AACJ;;AAEA;AACA,SAAS,oBAAoB,GAAS;EAClC,IAAI,eAAe,EAAE;IACjB,UAAU,CAAC,YAAY,CAAC,eAAiC,CAAC;EAC9D;EAEA,MAAM,KAAK,GAAG,YAAY,CAAC,CAAC,CAAC;EAE7B,IAAI,CAAC,KAAK,EAAE;IACR,QAAQ,CAAC,2DAA2D,CAAC;IACrE;EACJ;EAEA,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC;EAC5B,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,GAAG,SAAS,EAAE,qBAAqB,CAAC;EAExE,QAAQ,CAAC,4BAA4B,EAAE,SAAS,EAAE,QAAQ,EAAE,OAAO,CAAC;EACpE,eAAe,GAAG,UAAU,CAAC,UAAU,CAAC,YAAY,EAAE,OAAO,CAAC;AAClE;AAEA,SAAS,YAAY,GAAS;EAC1B,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC;EAC5B,QAAQ,CAAC,oBAAoB,EAAE,SAAS,CAAC;;EAEzC;EACA,MAAM,cAA0B,GAAG,EAAE;EACrC,OAAO,IAAI,EAAE;IACT,MAAM,KAAK,GAAG,YAAY,CAAC,CAAC,CAAC;IAC7B,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,KAAK,GAAG,SAAS,EAAE;MACnC;IACJ;IACA,MAAM,EAAE,GAAG,YAAY,CAAC,KAAK,CAAC,CAAE;IAChC,QAAQ,CAAC,uBAAuB,EAAE,EAAE,CAAC,GAAG,CAAC;IACzC,cAAc,CAAC,IAAI,CAAC,EAAE,CAAC;EAC3B;;EAEA;EACA;EACA;EACA,oBAAoB,CAAC,CAAC;EAEtB,KAAK,MAAM,EAAE,IAAI,cAAc,EAAE;IAC7B,IAAI;MACA,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,EAAE,EAAE,CAAC,MAAM,CAAC;IACxC,CAAC,CAAC,OAAO,CAAC,EAAE;MACR,MAAM,CAAC,KAAK,CAAC,yCAAyC,EAAE,CAAC,CAAC;IAC9D;EACJ;AACJ;;AAEA;AACA;AACA;AACA;AACA;AACA,SAAS,YAAY,CAAI,KAAU,EAAE,IAAsB,EAAU;EACjE;EACA,IAAI,GAAG,GAAG,CAAC;EACX,IAAI,GAAG,GAAG,KAAK,CAAC,MAAM;EAEtB,OAAO,GAAG,GAAG,GAAG,EAAE;IACd,MAAM,GAAG,GAAI,GAAG,GAAG,GAAG,IAAK,CAAC;IAC5B,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC5B,IAAI,GAAG,GAAG,CAAC,EAAE;MACT;MACA,GAAG,GAAG,GAAG;IACb,CAAC,MAAM;MACH;MACA,GAAG,GAAG,GAAG,GAAG,CAAC;IACjB;EACJ;EACA;EACA,OAAO,GAAG;AACd","ignoreList":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MSC4108RendezvousSession.d.ts","sourceRoot":"","sources":["../../../src/rendezvous/transports/MSC4108RendezvousSession.ts"],"names":[],"mappings":"AAkBA,OAAO,EAAE,6BAA6B,EAAE,oBAAoB,EAAE,KAAK,yBAAyB,EAAE,MAAM,aAAa,CAAC;AAClH,OAAO,EAAE,KAAK,YAAY,EAAU,MAAM,iBAAiB,CAAC;AAG5D;;;;GAIG;AACH,qBAAa,wBAAwB;IAC1B,GAAG,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAe;IACvC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CAAS;IAC3C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAA0B;IAC5C,SAAS,CAAC,EAAE,yBAAyB,CAAC;IAC7C,OAAO,CAAC,IAAI,CAAC,CAAS;IACtB,OAAO,CAAC,SAAS,CAAC,CAAO;IACzB,OAAO,CAAC,YAAY,CAAC,CAAgC;IACrD,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,MAAM,CAAS;IAEvB,YAAmB,EACf,SAAS,EACT,GAAG,EACH,OAAO,GACV,EAAE;QACC,OAAO,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;QAClC,SAAS,CAAC,EAAE,yBAAyB,CAAC;QACtC,GAAG,EAAE,MAAM,CAAC;KACf,EAAE;IACH,YAAmB,EACf,SAAS,EACT,MAAM,EACN,gBAAgB,EAChB,OAAO,GACV,EAAE;QACC,OAAO,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;QAClC,SAAS,CAAC,EAAE,yBAAyB,CAAC;QACtC,MAAM,CAAC,EAAE,YAAY,CAAC;QACtB,gBAAgB,CAAC,EAAE,MAAM,CAAC;KAC7B,EAAE;IAqBH;;OAEG;IACH,IAAW,KAAK,IAAI,OAAO,CAE1B;IAED;;OAEG;IACH,IAAW,SAAS,IAAI,OAAO,CAE9B;IAED,OAAO,CAAC,KAAK;YAOC,eAAe;IAgB7B;;;OAGG;IACU,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAqD7C;IAED;;;OAGG;IACU,OAAO,IAAI,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,
|
|
1
|
+
{"version":3,"file":"MSC4108RendezvousSession.d.ts","sourceRoot":"","sources":["../../../src/rendezvous/transports/MSC4108RendezvousSession.ts"],"names":[],"mappings":"AAkBA,OAAO,EAAE,6BAA6B,EAAE,oBAAoB,EAAE,KAAK,yBAAyB,EAAE,MAAM,aAAa,CAAC;AAClH,OAAO,EAAE,KAAK,YAAY,EAAU,MAAM,iBAAiB,CAAC;AAG5D;;;;GAIG;AACH,qBAAa,wBAAwB;IAC1B,GAAG,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAe;IACvC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CAAS;IAC3C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAA0B;IAC5C,SAAS,CAAC,EAAE,yBAAyB,CAAC;IAC7C,OAAO,CAAC,IAAI,CAAC,CAAS;IACtB,OAAO,CAAC,SAAS,CAAC,CAAO;IACzB,OAAO,CAAC,YAAY,CAAC,CAAgC;IACrD,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,MAAM,CAAS;IAEvB,YAAmB,EACf,SAAS,EACT,GAAG,EACH,OAAO,GACV,EAAE;QACC,OAAO,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;QAClC,SAAS,CAAC,EAAE,yBAAyB,CAAC;QACtC,GAAG,EAAE,MAAM,CAAC;KACf,EAAE;IACH,YAAmB,EACf,SAAS,EACT,MAAM,EACN,gBAAgB,EAChB,OAAO,GACV,EAAE;QACC,OAAO,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;QAClC,SAAS,CAAC,EAAE,yBAAyB,CAAC;QACtC,MAAM,CAAC,EAAE,YAAY,CAAC;QACtB,gBAAgB,CAAC,EAAE,MAAM,CAAC;KAC7B,EAAE;IAqBH;;OAEG;IACH,IAAW,KAAK,IAAI,OAAO,CAE1B;IAED;;OAEG;IACH,IAAW,SAAS,IAAI,OAAO,CAE9B;IAED,OAAO,CAAC,KAAK;YAOC,eAAe;IAgB7B;;;OAGG;IACU,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAqD7C;IAED;;;OAGG;IACU,OAAO,IAAI,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CA0ClD;IAED;;;;OAIG;IACU,MAAM,CAAC,MAAM,EAAE,oBAAoB,GAAG,6BAA6B,GAAG,OAAO,CAAC,IAAI,CAAC,CAsB/F;IAED;;OAEG;IACU,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAclC;CACJ"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MSC4108RendezvousSession.js","names":[],"sources":["../../../src/rendezvous/transports/MSC4108RendezvousSession.ts"],"sourcesContent":["/*\nCopyright 2024 The Matrix.org Foundation C.I.C.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n*/\n\nimport { logger } from \"../../logger.ts\";\nimport { sleep } from \"../../utils.ts\";\nimport { ClientRendezvousFailureReason, MSC4108FailureReason, type RendezvousFailureListener } from \"../index.ts\";\nimport { type MatrixClient, Method } from \"../../matrix.ts\";\nimport { ClientPrefix } from \"../../http-api/index.ts\";\n\n/**\n * Prototype of the unstable [MSC4108](https://github.com/matrix-org/matrix-spec-proposals/pull/4108)\n * insecure rendezvous session protocol.\n * @experimental Note that this is UNSTABLE and may have breaking changes without notice.\n */\nexport class MSC4108RendezvousSession {\n public url?: string;\n private readonly client?: MatrixClient;\n private readonly fallbackRzServer?: string;\n private readonly fetchFn?: typeof globalThis.fetch;\n public onFailure?: RendezvousFailureListener;\n private etag?: string;\n private expiresAt?: Date;\n private expiresTimer?: ReturnType<typeof setTimeout>;\n private _cancelled = false;\n private _ready = false;\n\n public constructor({\n onFailure,\n url,\n fetchFn,\n }: {\n fetchFn?: typeof globalThis.fetch;\n onFailure?: RendezvousFailureListener;\n url: string;\n });\n public constructor({\n onFailure,\n client,\n fallbackRzServer,\n fetchFn,\n }: {\n fetchFn?: typeof globalThis.fetch;\n onFailure?: RendezvousFailureListener;\n client?: MatrixClient;\n fallbackRzServer?: string;\n });\n public constructor({\n fetchFn,\n onFailure,\n url,\n client,\n fallbackRzServer,\n }: {\n fetchFn?: typeof globalThis.fetch;\n onFailure?: RendezvousFailureListener;\n url?: string;\n client?: MatrixClient;\n fallbackRzServer?: string;\n }) {\n this.fetchFn = fetchFn;\n this.onFailure = onFailure;\n this.client = client;\n this.fallbackRzServer = fallbackRzServer;\n this.url = url;\n }\n\n /**\n * Returns whether the channel is ready to be used.\n */\n public get ready(): boolean {\n return this._ready;\n }\n\n /**\n * Returns whether the channel has been cancelled.\n */\n public get cancelled(): boolean {\n return this._cancelled;\n }\n\n private fetch(resource: URL | string, options?: RequestInit): ReturnType<typeof globalThis.fetch> {\n if (this.fetchFn) {\n return this.fetchFn(resource, options);\n }\n return globalThis.fetch(resource, options);\n }\n\n private async getPostEndpoint(): Promise<string | undefined> {\n if (this.client) {\n try {\n if (await this.client.doesServerSupportUnstableFeature(\"org.matrix.msc4108\")) {\n return this.client.http\n .getUrl(\"/org.matrix.msc4108/rendezvous\", undefined, ClientPrefix.Unstable)\n .toString();\n }\n } catch (err) {\n logger.warn(\"Failed to get unstable features\", err);\n }\n }\n\n return this.fallbackRzServer;\n }\n\n /**\n * Sends data via the rendezvous channel.\n * @param data the payload to send\n */\n public async send(data: string): Promise<void> {\n if (this._cancelled) {\n return;\n }\n const method = this.url ? Method.Put : Method.Post;\n const uri = this.url ?? (await this.getPostEndpoint());\n\n if (!uri) {\n throw new Error(\"Invalid rendezvous URI\");\n }\n\n const headers: Record<string, string> = { \"content-type\": \"text/plain\" };\n\n // if we didn't create the rendezvous channel, we need to fetch the first etag if needed\n if (!this.etag && this.url) {\n await this.receive();\n }\n\n if (this.etag) {\n headers[\"if-match\"] = this.etag;\n }\n\n logger.info(`=> ${method} ${uri} with ${data} if-match: ${this.etag}`);\n\n const res = await this.fetch(uri, { method, headers, body: data, redirect: \"follow\" });\n if (res.status === 404) {\n return this.cancel(ClientRendezvousFailureReason.Unknown);\n }\n this.etag = res.headers.get(\"etag\") ?? undefined;\n\n logger.info(`Received etag: ${this.etag}`);\n\n if (method === Method.Post) {\n const expires = res.headers.get(\"expires\");\n if (expires) {\n if (this.expiresTimer) {\n clearTimeout(this.expiresTimer);\n this.expiresTimer = undefined;\n }\n this.expiresAt = new Date(expires);\n this.expiresTimer = setTimeout(() => {\n this.expiresTimer = undefined;\n void this.cancel(ClientRendezvousFailureReason.Expired);\n }, this.expiresAt.getTime() - Date.now());\n }\n // MSC4108: we expect a JSON response with a rendezvous URL\n const json = await res.json();\n if (typeof json.url !== \"string\") {\n throw new Error(\"No rendezvous URL given\");\n }\n this.url = json.url;\n this._ready = true;\n }\n }\n\n /**\n * Receives data from the rendezvous channel.\n * @returns the returned promise won't resolve until new data is acquired or the channel is closed either by the server or the other party.\n */\n public async receive(): Promise<string | undefined> {\n if (!this.url) {\n throw new Error(\"Rendezvous not set up\");\n }\n // eslint-disable-next-line no-constant-condition\n while (true) {\n if (this._cancelled) {\n return undefined;\n }\n\n const headers: Record<string, string> = {};\n if (this.etag) {\n headers[\"if-none-match\"] = this.etag;\n }\n\n logger.info(`=> GET ${this.url} if-none-match: ${this.etag}`);\n const poll = await this.fetch(this.url, { method: Method.Get, headers });\n\n if (poll.status === 404) {\n await this.cancel(ClientRendezvousFailureReason.Unknown);\n return undefined;\n }\n\n // rely on server expiring the channel rather than checking ourselves\n\n const etag = poll.headers.get(\"etag\") ?? undefined;\n if (poll.headers.get(\"content-type\") !== \"text/plain\") {\n this.etag = etag;\n } else if (poll.status === 200) {\n if (!etag) {\n // Some browsers & extensions block the ETag header for anti-tracking purposes\n // We try and detect this so the client can give the user a somewhat helpful message\n await this.cancel(ClientRendezvousFailureReason.ETagMissing);\n return undefined;\n }\n\n this.etag = etag;\n const text = await poll.text();\n logger.info(`Received: ${text} with etag ${this.etag}`);\n return text;\n }\n await sleep(1000);\n }\n }\n\n /**\n * Cancels the rendezvous channel.\n * If the reason is user_declined or user_cancelled then the channel will also be closed.\n * @param reason the reason to cancel with\n */\n public async cancel(reason: MSC4108FailureReason | ClientRendezvousFailureReason): Promise<void> {\n if (this._cancelled) return;\n if (this.expiresTimer) {\n clearTimeout(this.expiresTimer);\n this.expiresTimer = undefined;\n }\n\n if (\n reason === ClientRendezvousFailureReason.Unknown &&\n this.expiresAt &&\n this.expiresAt.getTime() < Date.now()\n ) {\n reason = ClientRendezvousFailureReason.Expired;\n }\n\n this._cancelled = true;\n this._ready = false;\n this.onFailure?.(reason);\n\n if (reason === ClientRendezvousFailureReason.UserDeclined || reason === MSC4108FailureReason.UserCancelled) {\n await this.close();\n }\n }\n\n /**\n * Closes the rendezvous channel.\n */\n public async close(): Promise<void> {\n if (this.expiresTimer) {\n clearTimeout(this.expiresTimer);\n this.expiresTimer = undefined;\n }\n\n if (!this.url) return;\n try {\n const method = Method.Delete;\n logger.info(`=> ${method} ${this.url}`);\n await this.fetch(this.url, { method });\n } catch (e) {\n logger.warn(e);\n }\n }\n}\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"file":"MSC4108RendezvousSession.js","names":[],"sources":["../../../src/rendezvous/transports/MSC4108RendezvousSession.ts"],"sourcesContent":["/*\nCopyright 2024 The Matrix.org Foundation C.I.C.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n*/\n\nimport { logger } from \"../../logger.ts\";\nimport { sleep } from \"../../utils.ts\";\nimport { ClientRendezvousFailureReason, MSC4108FailureReason, type RendezvousFailureListener } from \"../index.ts\";\nimport { type MatrixClient, Method } from \"../../matrix.ts\";\nimport { ClientPrefix } from \"../../http-api/index.ts\";\n\n/**\n * Prototype of the unstable [MSC4108](https://github.com/matrix-org/matrix-spec-proposals/pull/4108)\n * insecure rendezvous session protocol.\n * @experimental Note that this is UNSTABLE and may have breaking changes without notice.\n */\nexport class MSC4108RendezvousSession {\n public url?: string;\n private readonly client?: MatrixClient;\n private readonly fallbackRzServer?: string;\n private readonly fetchFn?: typeof globalThis.fetch;\n public onFailure?: RendezvousFailureListener;\n private etag?: string;\n private expiresAt?: Date;\n private expiresTimer?: ReturnType<typeof setTimeout>;\n private _cancelled = false;\n private _ready = false;\n\n public constructor({\n onFailure,\n url,\n fetchFn,\n }: {\n fetchFn?: typeof globalThis.fetch;\n onFailure?: RendezvousFailureListener;\n url: string;\n });\n public constructor({\n onFailure,\n client,\n fallbackRzServer,\n fetchFn,\n }: {\n fetchFn?: typeof globalThis.fetch;\n onFailure?: RendezvousFailureListener;\n client?: MatrixClient;\n fallbackRzServer?: string;\n });\n public constructor({\n fetchFn,\n onFailure,\n url,\n client,\n fallbackRzServer,\n }: {\n fetchFn?: typeof globalThis.fetch;\n onFailure?: RendezvousFailureListener;\n url?: string;\n client?: MatrixClient;\n fallbackRzServer?: string;\n }) {\n this.fetchFn = fetchFn;\n this.onFailure = onFailure;\n this.client = client;\n this.fallbackRzServer = fallbackRzServer;\n this.url = url;\n }\n\n /**\n * Returns whether the channel is ready to be used.\n */\n public get ready(): boolean {\n return this._ready;\n }\n\n /**\n * Returns whether the channel has been cancelled.\n */\n public get cancelled(): boolean {\n return this._cancelled;\n }\n\n private fetch(resource: URL | string, options?: RequestInit): ReturnType<typeof globalThis.fetch> {\n if (this.fetchFn) {\n return this.fetchFn(resource, options);\n }\n return globalThis.fetch(resource, options);\n }\n\n private async getPostEndpoint(): Promise<string | undefined> {\n if (this.client) {\n try {\n if (await this.client.doesServerSupportUnstableFeature(\"org.matrix.msc4108\")) {\n return this.client.http\n .getUrl(\"/org.matrix.msc4108/rendezvous\", undefined, ClientPrefix.Unstable)\n .toString();\n }\n } catch (err) {\n logger.warn(\"Failed to get unstable features\", err);\n }\n }\n\n return this.fallbackRzServer;\n }\n\n /**\n * Sends data via the rendezvous channel.\n * @param data the payload to send\n */\n public async send(data: string): Promise<void> {\n if (this._cancelled) {\n return;\n }\n const method = this.url ? Method.Put : Method.Post;\n const uri = this.url ?? (await this.getPostEndpoint());\n\n if (!uri) {\n throw new Error(\"Invalid rendezvous URI\");\n }\n\n const headers: Record<string, string> = { \"content-type\": \"text/plain\" };\n\n // if we didn't create the rendezvous channel, we need to fetch the first etag if needed\n if (!this.etag && this.url) {\n await this.receive();\n }\n\n if (this.etag) {\n headers[\"if-match\"] = this.etag;\n }\n\n logger.info(`=> ${method} ${uri} with ${data} if-match: ${this.etag}`);\n\n const res = await this.fetch(uri, { method, headers, body: data, redirect: \"follow\" });\n if (res.status === 404) {\n return this.cancel(ClientRendezvousFailureReason.Unknown);\n }\n this.etag = res.headers.get(\"etag\") ?? undefined;\n\n logger.info(`Received etag: ${this.etag}`);\n\n if (method === Method.Post) {\n const expires = res.headers.get(\"expires\");\n if (expires) {\n if (this.expiresTimer) {\n clearTimeout(this.expiresTimer);\n this.expiresTimer = undefined;\n }\n this.expiresAt = new Date(expires);\n this.expiresTimer = setTimeout(() => {\n this.expiresTimer = undefined;\n void this.cancel(ClientRendezvousFailureReason.Expired);\n }, this.expiresAt.getTime() - Date.now());\n }\n // MSC4108: we expect a JSON response with a rendezvous URL\n const json = await res.json();\n if (typeof json.url !== \"string\") {\n throw new Error(\"No rendezvous URL given\");\n }\n this.url = json.url;\n this._ready = true;\n }\n }\n\n /**\n * Receives data from the rendezvous channel.\n * @returns the returned promise won't resolve until new data is acquired or the channel is closed either by the server or the other party.\n */\n public async receive(): Promise<string | undefined> {\n if (!this.url) {\n throw new Error(\"Rendezvous not set up\");\n }\n while (true) {\n if (this._cancelled) {\n return undefined;\n }\n\n const headers: Record<string, string> = {};\n if (this.etag) {\n headers[\"if-none-match\"] = this.etag;\n }\n\n logger.info(`=> GET ${this.url} if-none-match: ${this.etag}`);\n const poll = await this.fetch(this.url, { method: Method.Get, headers });\n\n if (poll.status === 404) {\n await this.cancel(ClientRendezvousFailureReason.Unknown);\n return undefined;\n }\n\n // rely on server expiring the channel rather than checking ourselves\n\n const etag = poll.headers.get(\"etag\") ?? undefined;\n if (poll.headers.get(\"content-type\") !== \"text/plain\") {\n this.etag = etag;\n } else if (poll.status === 200) {\n if (!etag) {\n // Some browsers & extensions block the ETag header for anti-tracking purposes\n // We try and detect this so the client can give the user a somewhat helpful message\n await this.cancel(ClientRendezvousFailureReason.ETagMissing);\n return undefined;\n }\n\n this.etag = etag;\n const text = await poll.text();\n logger.info(`Received: ${text} with etag ${this.etag}`);\n return text;\n }\n await sleep(1000);\n }\n }\n\n /**\n * Cancels the rendezvous channel.\n * If the reason is user_declined or user_cancelled then the channel will also be closed.\n * @param reason the reason to cancel with\n */\n public async cancel(reason: MSC4108FailureReason | ClientRendezvousFailureReason): Promise<void> {\n if (this._cancelled) return;\n if (this.expiresTimer) {\n clearTimeout(this.expiresTimer);\n this.expiresTimer = undefined;\n }\n\n if (\n reason === ClientRendezvousFailureReason.Unknown &&\n this.expiresAt &&\n this.expiresAt.getTime() < Date.now()\n ) {\n reason = ClientRendezvousFailureReason.Expired;\n }\n\n this._cancelled = true;\n this._ready = false;\n this.onFailure?.(reason);\n\n if (reason === ClientRendezvousFailureReason.UserDeclined || reason === MSC4108FailureReason.UserCancelled) {\n await this.close();\n }\n }\n\n /**\n * Closes the rendezvous channel.\n */\n public async close(): Promise<void> {\n if (this.expiresTimer) {\n clearTimeout(this.expiresTimer);\n this.expiresTimer = undefined;\n }\n\n if (!this.url) return;\n try {\n const method = Method.Delete;\n logger.info(`=> ${method} ${this.url}`);\n await this.fetch(this.url, { method });\n } catch (e) {\n logger.warn(e);\n }\n }\n}\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OutgoingRequestProcessor.d.ts","sourceRoot":"","sources":["../../src/rust-crypto/OutgoingRequestProcessor.ts"],"names":[],"mappings":"AAgBA,OAAO,EAKH,KAAK,UAAU,EACf,KAAK,eAAe,EACpB,0BAA0B,EAI1B,wBAAwB,EAC3B,MAAM,oCAAoC,CAAC;AAE5C,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,EAAyB,KAAK,SAAS,EAAE,KAAK,aAAa,EAAU,MAAM,sBAAsB,CAAC;AAEzG,OAAO,EAAiB,KAAK,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAI5E;;;;;;;;;;;GAWG;AACH,qBAAa,wBAAwB;IAE7B,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,IAAI;IAHzB,YACqB,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,UAAU,EACtB,IAAI,EAAE,aAAa,CAAC,SAAS,GAAG;QAAE,QAAQ,EAAE,IAAI,CAAA;KAAE,CAAC,EACpE;IAES,mBAAmB,CAAC,CAAC,EAC9B,GAAG,EAAE,eAAe,GAAG,wBAAwB,GAAG,0BAA0B,EAC5E,WAAW,CAAC,EAAE,cAAc,CAAC,CAAC,CAAC,GAChC,OAAO,CAAC,IAAI,CAAC,CAoEf;IAED;;;;;OAKG;YACW,mBAAmB;YAsBnB,kBAAkB;YA2BlB,gBAAgB;
|
|
1
|
+
{"version":3,"file":"OutgoingRequestProcessor.d.ts","sourceRoot":"","sources":["../../src/rust-crypto/OutgoingRequestProcessor.ts"],"names":[],"mappings":"AAgBA,OAAO,EAKH,KAAK,UAAU,EACf,KAAK,eAAe,EACpB,0BAA0B,EAI1B,wBAAwB,EAC3B,MAAM,oCAAoC,CAAC;AAE5C,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,EAAyB,KAAK,SAAS,EAAE,KAAK,aAAa,EAAU,MAAM,sBAAsB,CAAC;AAEzG,OAAO,EAAiB,KAAK,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAI5E;;;;;;;;;;;GAWG;AACH,qBAAa,wBAAwB;IAE7B,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,IAAI;IAHzB,YACqB,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,UAAU,EACtB,IAAI,EAAE,aAAa,CAAC,SAAS,GAAG;QAAE,QAAQ,EAAE,IAAI,CAAA;KAAE,CAAC,EACpE;IAES,mBAAmB,CAAC,CAAC,EAC9B,GAAG,EAAE,eAAe,GAAG,wBAAwB,GAAG,0BAA0B,EAC5E,WAAW,CAAC,EAAE,cAAc,CAAC,CAAC,CAAC,GAChC,OAAO,CAAC,IAAI,CAAC,CAoEf;IAED;;;;;OAKG;YACW,mBAAmB;YAsBnB,kBAAkB;YA2BlB,gBAAgB;YAwBhB,cAAc;CAuB/B"}
|
|
@@ -131,8 +131,6 @@ export class OutgoingRequestProcessor {
|
|
|
131
131
|
}
|
|
132
132
|
async requestWithRetry(method, path, queryParams, body) {
|
|
133
133
|
let currentRetryCount = 0;
|
|
134
|
-
|
|
135
|
-
// eslint-disable-next-line no-constant-condition
|
|
136
134
|
while (true) {
|
|
137
135
|
try {
|
|
138
136
|
return await this.rawJsonRequest(method, path, queryParams, body);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OutgoingRequestProcessor.js","names":[],"sources":["../../src/rust-crypto/OutgoingRequestProcessor.ts"],"sourcesContent":["/*\nCopyright 2023 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 {\n KeysBackupRequest,\n KeysClaimRequest,\n KeysQueryRequest,\n KeysUploadRequest,\n type OlmMachine,\n type OutgoingRequest,\n PutDehydratedDeviceRequest,\n RoomMessageRequest,\n SignatureUploadRequest,\n ToDeviceRequest,\n UploadSigningKeysRequest,\n} from \"@matrix-org/matrix-sdk-crypto-wasm\";\n\nimport { type Logger } from \"../logger.ts\";\nimport { calculateRetryBackoff, type IHttpOpts, type MatrixHttpApi, Method } from \"../http-api/index.ts\";\nimport { logDuration, type QueryDict, sleep } from \"../utils.ts\";\nimport { type AuthDict, type UIAuthCallback } from \"../interactive-auth.ts\";\nimport { ToDeviceMessageId } from \"../@types/event.ts\";\nimport { UnstablePrefix as DehydrationUnstablePrefix } from \"./DehydratedDeviceManager.ts\";\n\n/**\n * OutgoingRequestManager: turns `OutgoingRequest`s from the rust sdk into HTTP requests\n *\n * We have one of these per `RustCrypto` (and hence per `MatrixClient`), not that it does anything terribly complicated.\n * It's responsible for:\n *\n * * holding the reference to the `MatrixHttpApi`\n * * turning `OutgoingRequest`s from the rust backend into HTTP requests, and sending them\n * * sending the results of such requests back to the rust backend.\n *\n * @internal\n */\nexport class OutgoingRequestProcessor {\n public constructor(\n private readonly logger: Logger,\n private readonly olmMachine: OlmMachine,\n private readonly http: MatrixHttpApi<IHttpOpts & { onlyData: true }>,\n ) {}\n\n public async makeOutgoingRequest<T>(\n msg: OutgoingRequest | UploadSigningKeysRequest | PutDehydratedDeviceRequest,\n uiaCallback?: UIAuthCallback<T>,\n ): Promise<void> {\n let resp: string;\n\n /* refer https://docs.rs/matrix-sdk-crypto/0.6.0/matrix_sdk_crypto/requests/enum.OutgoingRequests.html\n * for the complete list of request types\n */\n if (msg instanceof KeysUploadRequest) {\n resp = await this.requestWithRetry(Method.Post, \"/_matrix/client/v3/keys/upload\", {}, msg.body);\n } else if (msg instanceof KeysQueryRequest) {\n resp = await this.requestWithRetry(Method.Post, \"/_matrix/client/v3/keys/query\", {}, msg.body);\n } else if (msg instanceof KeysClaimRequest) {\n resp = await this.requestWithRetry(Method.Post, \"/_matrix/client/v3/keys/claim\", {}, msg.body);\n } else if (msg instanceof SignatureUploadRequest) {\n resp = await this.requestWithRetry(Method.Post, \"/_matrix/client/v3/keys/signatures/upload\", {}, msg.body);\n } else if (msg instanceof KeysBackupRequest) {\n resp = await this.requestWithRetry(\n Method.Put,\n \"/_matrix/client/v3/room_keys/keys\",\n { version: msg.version },\n msg.body,\n );\n } else if (msg instanceof ToDeviceRequest) {\n resp = await this.sendToDeviceRequest(msg);\n } else if (msg instanceof RoomMessageRequest) {\n const path =\n `/_matrix/client/v3/rooms/${encodeURIComponent(msg.room_id)}/send/` +\n `${encodeURIComponent(msg.event_type)}/${encodeURIComponent(msg.txn_id)}`;\n resp = await this.requestWithRetry(Method.Put, path, {}, msg.body);\n } else if (msg instanceof UploadSigningKeysRequest) {\n await this.makeRequestWithUIA(\n Method.Post,\n \"/_matrix/client/v3/keys/device_signing/upload\",\n {},\n msg.body,\n uiaCallback,\n );\n // SigningKeysUploadRequest does not implement OutgoingRequest and does not need to be marked as sent.\n return;\n } else if (msg instanceof PutDehydratedDeviceRequest) {\n const path = DehydrationUnstablePrefix + \"/dehydrated_device\";\n await this.rawJsonRequest(Method.Put, path, {}, msg.body);\n // PutDehydratedDeviceRequest does not implement OutgoingRequest and does not need to be marked as sent.\n return;\n } else {\n this.logger.warn(\"Unsupported outgoing message\", Object.getPrototypeOf(msg));\n resp = \"\";\n }\n\n if (msg.id) {\n try {\n await logDuration(this.logger, `Mark Request as sent ${msg.type}`, async () => {\n await this.olmMachine.markRequestAsSent(msg.id!, msg.type, resp);\n });\n } catch (e) {\n // Ignore errors which are caused by the olmMachine having been freed. The exact error message depends\n // on whether we are using a release or develop build of rust-sdk-crypto-wasm.\n if (\n e instanceof Error &&\n (e.message === \"Attempt to use a moved value\" || e.message === \"null pointer passed to rust\")\n ) {\n this.logger.debug(`Ignoring error '${e.message}': client is likely shutting down`);\n } else {\n throw e;\n }\n }\n } else {\n this.logger.trace(`Outgoing request type:${msg.type} does not have an ID`);\n }\n }\n\n /**\n * Send the HTTP request for a `ToDeviceRequest`\n *\n * @param request - request to send\n * @returns JSON-serialized body of the response, if successful\n */\n private async sendToDeviceRequest(request: ToDeviceRequest): Promise<string> {\n // a bit of extra logging, to help trace to-device messages through the system\n const parsedBody: { messages: Record<string, Record<string, Record<string, any>>> } = JSON.parse(request.body);\n\n const messageList = [];\n for (const [userId, perUserMessages] of Object.entries(parsedBody.messages)) {\n for (const [deviceId, message] of Object.entries(perUserMessages)) {\n messageList.push(`${userId}/${deviceId} (msgid ${message[ToDeviceMessageId]})`);\n }\n }\n\n this.logger.info(\n `Sending batch of to-device messages. type=${request.event_type} txnid=${request.txn_id}`,\n messageList,\n );\n\n const path =\n `/_matrix/client/v3/sendToDevice/${encodeURIComponent(request.event_type)}/` +\n encodeURIComponent(request.txn_id);\n return await this.requestWithRetry(Method.Put, path, {}, request.body);\n }\n\n private async makeRequestWithUIA<T>(\n method: Method,\n path: string,\n queryParams: QueryDict,\n body: string,\n uiaCallback: UIAuthCallback<T> | undefined,\n ): Promise<string> {\n if (!uiaCallback) {\n return await this.requestWithRetry(method, path, queryParams, body);\n }\n\n const parsedBody = JSON.parse(body);\n const makeRequest = async (auth: AuthDict | null): Promise<T> => {\n const newBody: Record<string, any> = {\n ...parsedBody,\n };\n if (auth !== null) {\n newBody.auth = auth;\n }\n const resp = await this.requestWithRetry(method, path, queryParams, JSON.stringify(newBody));\n return JSON.parse(resp) as T;\n };\n\n const resp = await uiaCallback(makeRequest);\n return JSON.stringify(resp);\n }\n\n private async requestWithRetry(\n method: Method,\n path: string,\n queryParams: QueryDict,\n body: string,\n ): Promise<string> {\n let currentRetryCount = 0;\n\n // eslint-disable-next-line no-constant-condition\n while (true) {\n try {\n return await this.rawJsonRequest(method, path, queryParams, body);\n } catch (e) {\n currentRetryCount++;\n const backoff = calculateRetryBackoff(e, currentRetryCount, true);\n if (backoff < 0) {\n // Max number of retries reached, or error is not retryable. rethrow the error\n throw e;\n }\n // wait for the specified time and then retry the request\n await sleep(backoff);\n }\n }\n }\n\n private async rawJsonRequest(method: Method, path: string, queryParams: QueryDict, body: string): Promise<string> {\n const opts = {\n // inhibit the JSON stringification and parsing within HttpApi.\n json: false,\n\n // nevertheless, we are sending, and accept, JSON.\n headers: {\n \"Content-Type\": \"application/json\",\n \"Accept\": \"application/json\",\n },\n\n // we use the full prefix\n prefix: \"\",\n\n // We set a timeout of 60 seconds to guard against requests getting stuck forever and wedging the\n // request loop (cf https://github.com/element-hq/element-web/issues/29534).\n //\n // (XXX: should we do this in the whole of the js-sdk?)\n localTimeoutMs: 60000,\n };\n\n return await this.http.authedRequest<string>(method, path, queryParams, body, opts);\n }\n}\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"file":"OutgoingRequestProcessor.js","names":[],"sources":["../../src/rust-crypto/OutgoingRequestProcessor.ts"],"sourcesContent":["/*\nCopyright 2023 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 {\n KeysBackupRequest,\n KeysClaimRequest,\n KeysQueryRequest,\n KeysUploadRequest,\n type OlmMachine,\n type OutgoingRequest,\n PutDehydratedDeviceRequest,\n RoomMessageRequest,\n SignatureUploadRequest,\n ToDeviceRequest,\n UploadSigningKeysRequest,\n} from \"@matrix-org/matrix-sdk-crypto-wasm\";\n\nimport { type Logger } from \"../logger.ts\";\nimport { calculateRetryBackoff, type IHttpOpts, type MatrixHttpApi, Method } from \"../http-api/index.ts\";\nimport { logDuration, type QueryDict, sleep } from \"../utils.ts\";\nimport { type AuthDict, type UIAuthCallback } from \"../interactive-auth.ts\";\nimport { ToDeviceMessageId } from \"../@types/event.ts\";\nimport { UnstablePrefix as DehydrationUnstablePrefix } from \"./DehydratedDeviceManager.ts\";\n\n/**\n * OutgoingRequestManager: turns `OutgoingRequest`s from the rust sdk into HTTP requests\n *\n * We have one of these per `RustCrypto` (and hence per `MatrixClient`), not that it does anything terribly complicated.\n * It's responsible for:\n *\n * * holding the reference to the `MatrixHttpApi`\n * * turning `OutgoingRequest`s from the rust backend into HTTP requests, and sending them\n * * sending the results of such requests back to the rust backend.\n *\n * @internal\n */\nexport class OutgoingRequestProcessor {\n public constructor(\n private readonly logger: Logger,\n private readonly olmMachine: OlmMachine,\n private readonly http: MatrixHttpApi<IHttpOpts & { onlyData: true }>,\n ) {}\n\n public async makeOutgoingRequest<T>(\n msg: OutgoingRequest | UploadSigningKeysRequest | PutDehydratedDeviceRequest,\n uiaCallback?: UIAuthCallback<T>,\n ): Promise<void> {\n let resp: string;\n\n /* refer https://docs.rs/matrix-sdk-crypto/0.6.0/matrix_sdk_crypto/requests/enum.OutgoingRequests.html\n * for the complete list of request types\n */\n if (msg instanceof KeysUploadRequest) {\n resp = await this.requestWithRetry(Method.Post, \"/_matrix/client/v3/keys/upload\", {}, msg.body);\n } else if (msg instanceof KeysQueryRequest) {\n resp = await this.requestWithRetry(Method.Post, \"/_matrix/client/v3/keys/query\", {}, msg.body);\n } else if (msg instanceof KeysClaimRequest) {\n resp = await this.requestWithRetry(Method.Post, \"/_matrix/client/v3/keys/claim\", {}, msg.body);\n } else if (msg instanceof SignatureUploadRequest) {\n resp = await this.requestWithRetry(Method.Post, \"/_matrix/client/v3/keys/signatures/upload\", {}, msg.body);\n } else if (msg instanceof KeysBackupRequest) {\n resp = await this.requestWithRetry(\n Method.Put,\n \"/_matrix/client/v3/room_keys/keys\",\n { version: msg.version },\n msg.body,\n );\n } else if (msg instanceof ToDeviceRequest) {\n resp = await this.sendToDeviceRequest(msg);\n } else if (msg instanceof RoomMessageRequest) {\n const path =\n `/_matrix/client/v3/rooms/${encodeURIComponent(msg.room_id)}/send/` +\n `${encodeURIComponent(msg.event_type)}/${encodeURIComponent(msg.txn_id)}`;\n resp = await this.requestWithRetry(Method.Put, path, {}, msg.body);\n } else if (msg instanceof UploadSigningKeysRequest) {\n await this.makeRequestWithUIA(\n Method.Post,\n \"/_matrix/client/v3/keys/device_signing/upload\",\n {},\n msg.body,\n uiaCallback,\n );\n // SigningKeysUploadRequest does not implement OutgoingRequest and does not need to be marked as sent.\n return;\n } else if (msg instanceof PutDehydratedDeviceRequest) {\n const path = DehydrationUnstablePrefix + \"/dehydrated_device\";\n await this.rawJsonRequest(Method.Put, path, {}, msg.body);\n // PutDehydratedDeviceRequest does not implement OutgoingRequest and does not need to be marked as sent.\n return;\n } else {\n this.logger.warn(\"Unsupported outgoing message\", Object.getPrototypeOf(msg));\n resp = \"\";\n }\n\n if (msg.id) {\n try {\n await logDuration(this.logger, `Mark Request as sent ${msg.type}`, async () => {\n await this.olmMachine.markRequestAsSent(msg.id!, msg.type, resp);\n });\n } catch (e) {\n // Ignore errors which are caused by the olmMachine having been freed. The exact error message depends\n // on whether we are using a release or develop build of rust-sdk-crypto-wasm.\n if (\n e instanceof Error &&\n (e.message === \"Attempt to use a moved value\" || e.message === \"null pointer passed to rust\")\n ) {\n this.logger.debug(`Ignoring error '${e.message}': client is likely shutting down`);\n } else {\n throw e;\n }\n }\n } else {\n this.logger.trace(`Outgoing request type:${msg.type} does not have an ID`);\n }\n }\n\n /**\n * Send the HTTP request for a `ToDeviceRequest`\n *\n * @param request - request to send\n * @returns JSON-serialized body of the response, if successful\n */\n private async sendToDeviceRequest(request: ToDeviceRequest): Promise<string> {\n // a bit of extra logging, to help trace to-device messages through the system\n const parsedBody: { messages: Record<string, Record<string, Record<string, any>>> } = JSON.parse(request.body);\n\n const messageList = [];\n for (const [userId, perUserMessages] of Object.entries(parsedBody.messages)) {\n for (const [deviceId, message] of Object.entries(perUserMessages)) {\n messageList.push(`${userId}/${deviceId} (msgid ${message[ToDeviceMessageId]})`);\n }\n }\n\n this.logger.info(\n `Sending batch of to-device messages. type=${request.event_type} txnid=${request.txn_id}`,\n messageList,\n );\n\n const path =\n `/_matrix/client/v3/sendToDevice/${encodeURIComponent(request.event_type)}/` +\n encodeURIComponent(request.txn_id);\n return await this.requestWithRetry(Method.Put, path, {}, request.body);\n }\n\n private async makeRequestWithUIA<T>(\n method: Method,\n path: string,\n queryParams: QueryDict,\n body: string,\n uiaCallback: UIAuthCallback<T> | undefined,\n ): Promise<string> {\n if (!uiaCallback) {\n return await this.requestWithRetry(method, path, queryParams, body);\n }\n\n const parsedBody = JSON.parse(body);\n const makeRequest = async (auth: AuthDict | null): Promise<T> => {\n const newBody: Record<string, any> = {\n ...parsedBody,\n };\n if (auth !== null) {\n newBody.auth = auth;\n }\n const resp = await this.requestWithRetry(method, path, queryParams, JSON.stringify(newBody));\n return JSON.parse(resp) as T;\n };\n\n const resp = await uiaCallback(makeRequest);\n return JSON.stringify(resp);\n }\n\n private async requestWithRetry(\n method: Method,\n path: string,\n queryParams: QueryDict,\n body: string,\n ): Promise<string> {\n let currentRetryCount = 0;\n\n while (true) {\n try {\n return await this.rawJsonRequest(method, path, queryParams, body);\n } catch (e) {\n currentRetryCount++;\n const backoff = calculateRetryBackoff(e, currentRetryCount, true);\n if (backoff < 0) {\n // Max number of retries reached, or error is not retryable. rethrow the error\n throw e;\n }\n // wait for the specified time and then retry the request\n await sleep(backoff);\n }\n }\n }\n\n private async rawJsonRequest(method: Method, path: string, queryParams: QueryDict, body: string): Promise<string> {\n const opts = {\n // inhibit the JSON stringification and parsing within HttpApi.\n json: false,\n\n // nevertheless, we are sending, and accept, JSON.\n headers: {\n \"Content-Type\": \"application/json\",\n \"Accept\": \"application/json\",\n },\n\n // we use the full prefix\n prefix: \"\",\n\n // We set a timeout of 60 seconds to guard against requests getting stuck forever and wedging the\n // request loop (cf https://github.com/element-hq/element-web/issues/29534).\n //\n // (XXX: should we do this in the whole of the js-sdk?)\n localTimeoutMs: 60000,\n };\n\n return await this.http.authedRequest<string>(method, path, queryParams, body, opts);\n }\n}\n"],"mappings":"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","ignoreList":[]}
|