summaryrefslogtreecommitdiff
path: root/includes/external/matrix/node_modules/matrix-js-sdk/lib/models
diff options
context:
space:
mode:
Diffstat (limited to 'includes/external/matrix/node_modules/matrix-js-sdk/lib/models')
-rw-r--r--includes/external/matrix/node_modules/matrix-js-sdk/lib/models/MSC3089Branch.d.ts86
-rw-r--r--includes/external/matrix/node_modules/matrix-js-sdk/lib/models/MSC3089Branch.d.ts.map1
-rw-r--r--includes/external/matrix/node_modules/matrix-js-sdk/lib/models/MSC3089Branch.js214
-rw-r--r--includes/external/matrix/node_modules/matrix-js-sdk/lib/models/MSC3089Branch.js.map1
-rw-r--r--includes/external/matrix/node_modules/matrix-js-sdk/lib/models/MSC3089TreeSpace.d.ts164
-rw-r--r--includes/external/matrix/node_modules/matrix-js-sdk/lib/models/MSC3089TreeSpace.d.ts.map1
-rw-r--r--includes/external/matrix/node_modules/matrix-js-sdk/lib/models/MSC3089TreeSpace.js503
-rw-r--r--includes/external/matrix/node_modules/matrix-js-sdk/lib/models/MSC3089TreeSpace.js.map1
-rw-r--r--includes/external/matrix/node_modules/matrix-js-sdk/lib/models/ToDeviceMessage.d.ts17
-rw-r--r--includes/external/matrix/node_modules/matrix-js-sdk/lib/models/ToDeviceMessage.d.ts.map1
-rw-r--r--includes/external/matrix/node_modules/matrix-js-sdk/lib/models/ToDeviceMessage.js6
-rw-r--r--includes/external/matrix/node_modules/matrix-js-sdk/lib/models/ToDeviceMessage.js.map1
-rw-r--r--includes/external/matrix/node_modules/matrix-js-sdk/lib/models/beacon.d.ts53
-rw-r--r--includes/external/matrix/node_modules/matrix-js-sdk/lib/models/beacon.d.ts.map1
-rw-r--r--includes/external/matrix/node_modules/matrix-js-sdk/lib/models/beacon.js184
-rw-r--r--includes/external/matrix/node_modules/matrix-js-sdk/lib/models/beacon.js.map1
-rw-r--r--includes/external/matrix/node_modules/matrix-js-sdk/lib/models/event-context.d.ts62
-rw-r--r--includes/external/matrix/node_modules/matrix-js-sdk/lib/models/event-context.d.ts.map1
-rw-r--r--includes/external/matrix/node_modules/matrix-js-sdk/lib/models/event-context.js118
-rw-r--r--includes/external/matrix/node_modules/matrix-js-sdk/lib/models/event-context.js.map1
-rw-r--r--includes/external/matrix/node_modules/matrix-js-sdk/lib/models/event-status.d.ts19
-rw-r--r--includes/external/matrix/node_modules/matrix-js-sdk/lib/models/event-status.d.ts.map1
-rw-r--r--includes/external/matrix/node_modules/matrix-js-sdk/lib/models/event-status.js36
-rw-r--r--includes/external/matrix/node_modules/matrix-js-sdk/lib/models/event-status.js.map1
-rw-r--r--includes/external/matrix/node_modules/matrix-js-sdk/lib/models/event-timeline-set.d.ts296
-rw-r--r--includes/external/matrix/node_modules/matrix-js-sdk/lib/models/event-timeline-set.d.ts.map1
-rw-r--r--includes/external/matrix/node_modules/matrix-js-sdk/lib/models/event-timeline-set.js725
-rw-r--r--includes/external/matrix/node_modules/matrix-js-sdk/lib/models/event-timeline-set.js.map1
-rw-r--r--includes/external/matrix/node_modules/matrix-js-sdk/lib/models/event-timeline.d.ts211
-rw-r--r--includes/external/matrix/node_modules/matrix-js-sdk/lib/models/event-timeline.d.ts.map1
-rw-r--r--includes/external/matrix/node_modules/matrix-js-sdk/lib/models/event-timeline.js433
-rw-r--r--includes/external/matrix/node_modules/matrix-js-sdk/lib/models/event-timeline.js.map1
-rw-r--r--includes/external/matrix/node_modules/matrix-js-sdk/lib/models/event.d.ts759
-rw-r--r--includes/external/matrix/node_modules/matrix-js-sdk/lib/models/event.d.ts.map1
-rw-r--r--includes/external/matrix/node_modules/matrix-js-sdk/lib/models/event.js1433
-rw-r--r--includes/external/matrix/node_modules/matrix-js-sdk/lib/models/event.js.map1
-rw-r--r--includes/external/matrix/node_modules/matrix-js-sdk/lib/models/invites-ignorer.d.ts132
-rw-r--r--includes/external/matrix/node_modules/matrix-js-sdk/lib/models/invites-ignorer.d.ts.map1
-rw-r--r--includes/external/matrix/node_modules/matrix-js-sdk/lib/models/invites-ignorer.js360
-rw-r--r--includes/external/matrix/node_modules/matrix-js-sdk/lib/models/invites-ignorer.js.map1
-rw-r--r--includes/external/matrix/node_modules/matrix-js-sdk/lib/models/poll.d.ts60
-rw-r--r--includes/external/matrix/node_modules/matrix-js-sdk/lib/models/poll.d.ts.map1
-rw-r--r--includes/external/matrix/node_modules/matrix-js-sdk/lib/models/poll.js231
-rw-r--r--includes/external/matrix/node_modules/matrix-js-sdk/lib/models/poll.js.map1
-rw-r--r--includes/external/matrix/node_modules/matrix-js-sdk/lib/models/read-receipt.d.ts76
-rw-r--r--includes/external/matrix/node_modules/matrix-js-sdk/lib/models/read-receipt.d.ts.map1
-rw-r--r--includes/external/matrix/node_modules/matrix-js-sdk/lib/models/read-receipt.js267
-rw-r--r--includes/external/matrix/node_modules/matrix-js-sdk/lib/models/read-receipt.js.map1
-rw-r--r--includes/external/matrix/node_modules/matrix-js-sdk/lib/models/related-relations.d.ts11
-rw-r--r--includes/external/matrix/node_modules/matrix-js-sdk/lib/models/related-relations.d.ts.map1
-rw-r--r--includes/external/matrix/node_modules/matrix-js-sdk/lib/models/related-relations.js41
-rw-r--r--includes/external/matrix/node_modules/matrix-js-sdk/lib/models/related-relations.js.map1
-rw-r--r--includes/external/matrix/node_modules/matrix-js-sdk/lib/models/relations-container.d.ts44
-rw-r--r--includes/external/matrix/node_modules/matrix-js-sdk/lib/models/relations-container.d.ts.map1
-rw-r--r--includes/external/matrix/node_modules/matrix-js-sdk/lib/models/relations-container.js141
-rw-r--r--includes/external/matrix/node_modules/matrix-js-sdk/lib/models/relations-container.js.map1
-rw-r--r--includes/external/matrix/node_modules/matrix-js-sdk/lib/models/relations.d.ts114
-rw-r--r--includes/external/matrix/node_modules/matrix-js-sdk/lib/models/relations.d.ts.map1
-rw-r--r--includes/external/matrix/node_modules/matrix-js-sdk/lib/models/relations.js343
-rw-r--r--includes/external/matrix/node_modules/matrix-js-sdk/lib/models/relations.js.map1
-rw-r--r--includes/external/matrix/node_modules/matrix-js-sdk/lib/models/room-member.d.ts203
-rw-r--r--includes/external/matrix/node_modules/matrix-js-sdk/lib/models/room-member.d.ts.map1
-rw-r--r--includes/external/matrix/node_modules/matrix-js-sdk/lib/models/room-member.js377
-rw-r--r--includes/external/matrix/node_modules/matrix-js-sdk/lib/models/room-member.js.map1
-rw-r--r--includes/external/matrix/node_modules/matrix-js-sdk/lib/models/room-state.d.ts448
-rw-r--r--includes/external/matrix/node_modules/matrix-js-sdk/lib/models/room-state.d.ts.map1
-rw-r--r--includes/external/matrix/node_modules/matrix-js-sdk/lib/models/room-state.js949
-rw-r--r--includes/external/matrix/node_modules/matrix-js-sdk/lib/models/room-state.js.map1
-rw-r--r--includes/external/matrix/node_modules/matrix-js-sdk/lib/models/room-summary.d.ts29
-rw-r--r--includes/external/matrix/node_modules/matrix-js-sdk/lib/models/room-summary.d.ts.map1
-rw-r--r--includes/external/matrix/node_modules/matrix-js-sdk/lib/models/room-summary.js35
-rw-r--r--includes/external/matrix/node_modules/matrix-js-sdk/lib/models/room-summary.js.map1
-rw-r--r--includes/external/matrix/node_modules/matrix-js-sdk/lib/models/room.d.ts1087
-rw-r--r--includes/external/matrix/node_modules/matrix-js-sdk/lib/models/room.d.ts.map1
-rw-r--r--includes/external/matrix/node_modules/matrix-js-sdk/lib/models/room.js2979
-rw-r--r--includes/external/matrix/node_modules/matrix-js-sdk/lib/models/room.js.map1
-rw-r--r--includes/external/matrix/node_modules/matrix-js-sdk/lib/models/search-result.d.ts20
-rw-r--r--includes/external/matrix/node_modules/matrix-js-sdk/lib/models/search-result.d.ts.map1
-rw-r--r--includes/external/matrix/node_modules/matrix-js-sdk/lib/models/search-result.js59
-rw-r--r--includes/external/matrix/node_modules/matrix-js-sdk/lib/models/search-result.js.map1
-rw-r--r--includes/external/matrix/node_modules/matrix-js-sdk/lib/models/thread.d.ts175
-rw-r--r--includes/external/matrix/node_modules/matrix-js-sdk/lib/models/thread.d.ts.map1
-rw-r--r--includes/external/matrix/node_modules/matrix-js-sdk/lib/models/thread.js581
-rw-r--r--includes/external/matrix/node_modules/matrix-js-sdk/lib/models/thread.js.map1
-rw-r--r--includes/external/matrix/node_modules/matrix-js-sdk/lib/models/typed-event-emitter.d.ts39
-rw-r--r--includes/external/matrix/node_modules/matrix-js-sdk/lib/models/typed-event-emitter.d.ts.map1
-rw-r--r--includes/external/matrix/node_modules/matrix-js-sdk/lib/models/typed-event-emitter.js80
-rw-r--r--includes/external/matrix/node_modules/matrix-js-sdk/lib/models/typed-event-emitter.js.map1
-rw-r--r--includes/external/matrix/node_modules/matrix-js-sdk/lib/models/user.d.ts185
-rw-r--r--includes/external/matrix/node_modules/matrix-js-sdk/lib/models/user.d.ts.map1
-rw-r--r--includes/external/matrix/node_modules/matrix-js-sdk/lib/models/user.js220
-rw-r--r--includes/external/matrix/node_modules/matrix-js-sdk/lib/models/user.js.map1
92 files changed, 14651 insertions, 0 deletions
diff --git a/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/MSC3089Branch.d.ts b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/MSC3089Branch.d.ts
new file mode 100644
index 0000000..11722ab
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/MSC3089Branch.d.ts
@@ -0,0 +1,86 @@
+import { MatrixClient } from "../client";
+import { IEncryptedFile } from "../@types/event";
+import { IContent, MatrixEvent } from "./event";
+import { MSC3089TreeSpace } from "./MSC3089TreeSpace";
+import { FileType } from "../http-api";
+import type { ISendEventResponse } from "../@types/requests";
+/**
+ * Represents a [MSC3089](https://github.com/matrix-org/matrix-doc/pull/3089) branch - a reference
+ * to a file (leaf) in the tree. Note that this is UNSTABLE and subject to breaking changes
+ * without notice.
+ */
+export declare class MSC3089Branch {
+ private client;
+ readonly indexEvent: MatrixEvent;
+ readonly directory: MSC3089TreeSpace;
+ constructor(client: MatrixClient, indexEvent: MatrixEvent, directory: MSC3089TreeSpace);
+ /**
+ * The file ID.
+ */
+ get id(): string;
+ /**
+ * Whether this branch is active/valid.
+ */
+ get isActive(): boolean;
+ /**
+ * Version for the file, one-indexed.
+ */
+ get version(): number;
+ private get roomId();
+ /**
+ * Deletes the file from the tree, including all prior edits/versions.
+ * @returns Promise which resolves when complete.
+ */
+ delete(): Promise<void>;
+ /**
+ * Gets the name for this file.
+ * @returns The name, or "Unnamed File" if unknown.
+ */
+ getName(): string;
+ /**
+ * Sets the name for this file.
+ * @param name - The new name for this file.
+ * @returns Promise which resolves when complete.
+ */
+ setName(name: string): Promise<void>;
+ /**
+ * Gets whether or not a file is locked.
+ * @returns True if locked, false otherwise.
+ */
+ isLocked(): boolean;
+ /**
+ * Sets a file as locked or unlocked.
+ * @param locked - True to lock the file, false otherwise.
+ * @returns Promise which resolves when complete.
+ */
+ setLocked(locked: boolean): Promise<void>;
+ /**
+ * Gets information about the file needed to download it.
+ * @returns Information about the file.
+ */
+ getFileInfo(): Promise<{
+ info: IEncryptedFile;
+ httpUrl: string;
+ }>;
+ /**
+ * Gets the event the file points to.
+ * @returns Promise which resolves to the file's event.
+ */
+ getFileEvent(): Promise<MatrixEvent>;
+ /**
+ * Creates a new version of this file with contents in a type that is compatible with MatrixClient.uploadContent().
+ * @param name - The name of the file.
+ * @param encryptedContents - The encrypted contents.
+ * @param info - The encrypted file information.
+ * @param additionalContent - Optional event content fields to include in the message.
+ * @returns Promise which resolves to the file event's sent response.
+ */
+ createNewVersion(name: string, encryptedContents: FileType, info: Partial<IEncryptedFile>, additionalContent?: IContent): Promise<ISendEventResponse>;
+ /**
+ * Gets the file's version history, starting at this file.
+ * @returns Promise which resolves to the file's version history, with the
+ * first element being the current version and the last element being the first version.
+ */
+ getVersionHistory(): Promise<MSC3089Branch[]>;
+}
+//# sourceMappingURL=MSC3089Branch.d.ts.map \ No newline at end of file
diff --git a/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/MSC3089Branch.d.ts.map b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/MSC3089Branch.d.ts.map
new file mode 100644
index 0000000..bebdb11
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/MSC3089Branch.d.ts.map
@@ -0,0 +1 @@
+{"version":3,"file":"MSC3089Branch.d.ts","sourceRoot":"","sources":["../../src/models/MSC3089Branch.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,EAAE,cAAc,EAAyC,MAAM,iBAAiB,CAAC;AACxF,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAChD,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAEtD,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAE7D;;;;GAIG;AACH,qBAAa,aAAa;IAElB,OAAO,CAAC,MAAM;aACE,UAAU,EAAE,WAAW;aACvB,SAAS,EAAE,gBAAgB;gBAFnC,MAAM,EAAE,YAAY,EACZ,UAAU,EAAE,WAAW,EACvB,SAAS,EAAE,gBAAgB;IAK/C;;OAEG;IACH,IAAW,EAAE,IAAI,MAAM,CAMtB;IAED;;OAEG;IACH,IAAW,QAAQ,IAAI,OAAO,CAE7B;IAED;;OAEG;IACH,IAAW,OAAO,IAAI,MAAM,CAE3B;IAED,OAAO,KAAK,MAAM,GAEjB;IAED;;;OAGG;IACU,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;IAQpC;;;OAGG;IACI,OAAO,IAAI,MAAM;IAIxB;;;;OAIG;IACU,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAYjD;;;OAGG;IACI,QAAQ,IAAI,OAAO;IAI1B;;;;OAIG;IACU,SAAS,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAYtD;;;OAGG;IACU,WAAW,IAAI,OAAO,CAAC;QAAE,IAAI,EAAE,cAAc,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IAa9E;;;OAGG;IACU,YAAY,IAAI,OAAO,CAAC,WAAW,CAAC;IAqBjD;;;;;;;OAOG;IACU,gBAAgB,CACzB,IAAI,EAAE,MAAM,EACZ,iBAAiB,EAAE,QAAQ,EAC3B,IAAI,EAAE,OAAO,CAAC,cAAc,CAAC,EAC7B,iBAAiB,CAAC,EAAE,QAAQ,GAC7B,OAAO,CAAC,kBAAkB,CAAC;IAoC9B;;;;OAIG;IACU,iBAAiB,IAAI,OAAO,CAAC,aAAa,EAAE,CAAC;CAgC7D"} \ No newline at end of file
diff --git a/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/MSC3089Branch.js b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/MSC3089Branch.js
new file mode 100644
index 0000000..ff45c17
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/MSC3089Branch.js
@@ -0,0 +1,214 @@
+"use strict";
+
+var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.MSC3089Branch = void 0;
+var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
+var _event = require("../@types/event");
+var _eventTimeline = require("./event-timeline");
+function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
+function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { (0, _defineProperty2.default)(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
+/**
+ * Represents a [MSC3089](https://github.com/matrix-org/matrix-doc/pull/3089) branch - a reference
+ * to a file (leaf) in the tree. Note that this is UNSTABLE and subject to breaking changes
+ * without notice.
+ */
+class MSC3089Branch {
+ constructor(client, indexEvent, directory) {
+ this.client = client;
+ this.indexEvent = indexEvent;
+ this.directory = directory;
+ } // Nothing to do
+
+ /**
+ * The file ID.
+ */
+ get id() {
+ const stateKey = this.indexEvent.getStateKey();
+ if (!stateKey) {
+ throw new Error("State key not found for branch");
+ }
+ return stateKey;
+ }
+
+ /**
+ * Whether this branch is active/valid.
+ */
+ get isActive() {
+ return this.indexEvent.getContent()["active"] === true;
+ }
+
+ /**
+ * Version for the file, one-indexed.
+ */
+ get version() {
+ var _this$indexEvent$getC;
+ return (_this$indexEvent$getC = this.indexEvent.getContent()["version"]) !== null && _this$indexEvent$getC !== void 0 ? _this$indexEvent$getC : 1;
+ }
+ get roomId() {
+ return this.indexEvent.getRoomId();
+ }
+
+ /**
+ * Deletes the file from the tree, including all prior edits/versions.
+ * @returns Promise which resolves when complete.
+ */
+ async delete() {
+ await this.client.sendStateEvent(this.roomId, _event.UNSTABLE_MSC3089_BRANCH.name, {}, this.id);
+ await this.client.redactEvent(this.roomId, this.id);
+ const nextVersion = (await this.getVersionHistory())[1]; // [0] will be us
+ if (nextVersion) await nextVersion.delete(); // implicit recursion
+ }
+
+ /**
+ * Gets the name for this file.
+ * @returns The name, or "Unnamed File" if unknown.
+ */
+ getName() {
+ return this.indexEvent.getContent()["name"] || "Unnamed File";
+ }
+
+ /**
+ * Sets the name for this file.
+ * @param name - The new name for this file.
+ * @returns Promise which resolves when complete.
+ */
+ async setName(name) {
+ await this.client.sendStateEvent(this.roomId, _event.UNSTABLE_MSC3089_BRANCH.name, _objectSpread(_objectSpread({}, this.indexEvent.getContent()), {}, {
+ name: name
+ }), this.id);
+ }
+
+ /**
+ * Gets whether or not a file is locked.
+ * @returns True if locked, false otherwise.
+ */
+ isLocked() {
+ return this.indexEvent.getContent()["locked"] || false;
+ }
+
+ /**
+ * Sets a file as locked or unlocked.
+ * @param locked - True to lock the file, false otherwise.
+ * @returns Promise which resolves when complete.
+ */
+ async setLocked(locked) {
+ await this.client.sendStateEvent(this.roomId, _event.UNSTABLE_MSC3089_BRANCH.name, _objectSpread(_objectSpread({}, this.indexEvent.getContent()), {}, {
+ locked: locked
+ }), this.id);
+ }
+
+ /**
+ * Gets information about the file needed to download it.
+ * @returns Information about the file.
+ */
+ async getFileInfo() {
+ const event = await this.getFileEvent();
+ const file = event.getOriginalContent()["file"];
+ const httpUrl = this.client.mxcUrlToHttp(file["url"]);
+ if (!httpUrl) {
+ throw new Error(`No HTTP URL available for ${file["url"]}`);
+ }
+ return {
+ info: file,
+ httpUrl: httpUrl
+ };
+ }
+
+ /**
+ * Gets the event the file points to.
+ * @returns Promise which resolves to the file's event.
+ */
+ async getFileEvent() {
+ const room = this.client.getRoom(this.roomId);
+ if (!room) throw new Error("Unknown room");
+ let event = room.getUnfilteredTimelineSet().findEventById(this.id);
+
+ // keep scrolling back if needed until we find the event or reach the start of the room:
+ while (!event && room.getLiveTimeline().getState(_eventTimeline.EventTimeline.BACKWARDS).paginationToken) {
+ await this.client.scrollback(room, 100);
+ event = room.getUnfilteredTimelineSet().findEventById(this.id);
+ }
+ if (!event) throw new Error("Failed to find event");
+
+ // Sometimes the event isn't decrypted for us, so do that. We specifically set `emit: true`
+ // to ensure that the relations system in the sdk will function.
+ await this.client.decryptEventIfNeeded(event, {
+ emit: true,
+ isRetry: true
+ });
+ return event;
+ }
+
+ /**
+ * Creates a new version of this file with contents in a type that is compatible with MatrixClient.uploadContent().
+ * @param name - The name of the file.
+ * @param encryptedContents - The encrypted contents.
+ * @param info - The encrypted file information.
+ * @param additionalContent - Optional event content fields to include in the message.
+ * @returns Promise which resolves to the file event's sent response.
+ */
+ async createNewVersion(name, encryptedContents, info, additionalContent) {
+ const fileEventResponse = await this.directory.createFile(name, encryptedContents, info, _objectSpread(_objectSpread({}, additionalContent !== null && additionalContent !== void 0 ? additionalContent : {}), {}, {
+ "m.new_content": true,
+ "m.relates_to": {
+ rel_type: _event.RelationType.Replace,
+ event_id: this.id
+ }
+ }));
+
+ // Update the version of the new event
+ await this.client.sendStateEvent(this.roomId, _event.UNSTABLE_MSC3089_BRANCH.name, {
+ active: true,
+ name: name,
+ version: this.version + 1
+ }, fileEventResponse["event_id"]);
+
+ // Deprecate ourselves
+ await this.client.sendStateEvent(this.roomId, _event.UNSTABLE_MSC3089_BRANCH.name, _objectSpread(_objectSpread({}, this.indexEvent.getContent()), {}, {
+ active: false
+ }), this.id);
+ return fileEventResponse;
+ }
+
+ /**
+ * Gets the file's version history, starting at this file.
+ * @returns Promise which resolves to the file's version history, with the
+ * first element being the current version and the last element being the first version.
+ */
+ async getVersionHistory() {
+ const fileHistory = [];
+ fileHistory.push(this); // start with ourselves
+
+ const room = this.client.getRoom(this.roomId);
+ if (!room) throw new Error("Invalid or unknown room");
+
+ // Clone the timeline to reverse it, getting most-recent-first ordering, hopefully
+ // shortening the awful loop below. Without the clone, we can unintentionally mutate
+ // the timeline.
+ const timelineEvents = [...room.getLiveTimeline().getEvents()].reverse();
+
+ // XXX: This is a very inefficient search, but it's the best we can do with the
+ // relations structure we have in the SDK. As of writing, it is not worth the
+ // investment in improving the structure.
+ let childEvent;
+ let parentEvent = await this.getFileEvent();
+ do {
+ childEvent = timelineEvents.find(e => e.replacingEventId() === parentEvent.getId());
+ if (childEvent) {
+ const branch = this.directory.getFile(childEvent.getId());
+ if (branch) {
+ fileHistory.push(branch);
+ parentEvent = childEvent;
+ } else {
+ break; // prevent infinite loop
+ }
+ }
+ } while (childEvent);
+ return fileHistory;
+ }
+}
+exports.MSC3089Branch = MSC3089Branch;
+//# sourceMappingURL=MSC3089Branch.js.map \ No newline at end of file
diff --git a/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/MSC3089Branch.js.map b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/MSC3089Branch.js.map
new file mode 100644
index 0000000..888871d
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/MSC3089Branch.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"MSC3089Branch.js","names":["_event","require","_eventTimeline","ownKeys","object","enumerableOnly","keys","Object","getOwnPropertySymbols","symbols","filter","sym","getOwnPropertyDescriptor","enumerable","push","apply","_objectSpread","target","i","arguments","length","source","forEach","key","_defineProperty2","default","getOwnPropertyDescriptors","defineProperties","defineProperty","MSC3089Branch","constructor","client","indexEvent","directory","id","stateKey","getStateKey","Error","isActive","getContent","version","_this$indexEvent$getC","roomId","getRoomId","delete","sendStateEvent","UNSTABLE_MSC3089_BRANCH","name","redactEvent","nextVersion","getVersionHistory","getName","setName","isLocked","setLocked","locked","getFileInfo","event","getFileEvent","file","getOriginalContent","httpUrl","mxcUrlToHttp","info","room","getRoom","getUnfilteredTimelineSet","findEventById","getLiveTimeline","getState","EventTimeline","BACKWARDS","paginationToken","scrollback","decryptEventIfNeeded","emit","isRetry","createNewVersion","encryptedContents","additionalContent","fileEventResponse","createFile","rel_type","RelationType","Replace","event_id","active","fileHistory","timelineEvents","getEvents","reverse","childEvent","parentEvent","find","e","replacingEventId","getId","branch","getFile","exports"],"sources":["../../src/models/MSC3089Branch.ts"],"sourcesContent":["/*\nCopyright 2021 The Matrix.org Foundation C.I.C.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n*/\n\nimport { MatrixClient } from \"../client\";\nimport { IEncryptedFile, RelationType, UNSTABLE_MSC3089_BRANCH } from \"../@types/event\";\nimport { IContent, MatrixEvent } from \"./event\";\nimport { MSC3089TreeSpace } from \"./MSC3089TreeSpace\";\nimport { EventTimeline } from \"./event-timeline\";\nimport { FileType } from \"../http-api\";\nimport type { ISendEventResponse } from \"../@types/requests\";\n\n/**\n * Represents a [MSC3089](https://github.com/matrix-org/matrix-doc/pull/3089) branch - a reference\n * to a file (leaf) in the tree. Note that this is UNSTABLE and subject to breaking changes\n * without notice.\n */\nexport class MSC3089Branch {\n public constructor(\n private client: MatrixClient,\n public readonly indexEvent: MatrixEvent,\n public readonly directory: MSC3089TreeSpace,\n ) {\n // Nothing to do\n }\n\n /**\n * The file ID.\n */\n public get id(): string {\n const stateKey = this.indexEvent.getStateKey();\n if (!stateKey) {\n throw new Error(\"State key not found for branch\");\n }\n return stateKey;\n }\n\n /**\n * Whether this branch is active/valid.\n */\n public get isActive(): boolean {\n return this.indexEvent.getContent()[\"active\"] === true;\n }\n\n /**\n * Version for the file, one-indexed.\n */\n public get version(): number {\n return this.indexEvent.getContent()[\"version\"] ?? 1;\n }\n\n private get roomId(): string {\n return this.indexEvent.getRoomId()!;\n }\n\n /**\n * Deletes the file from the tree, including all prior edits/versions.\n * @returns Promise which resolves when complete.\n */\n public async delete(): Promise<void> {\n await this.client.sendStateEvent(this.roomId, UNSTABLE_MSC3089_BRANCH.name, {}, this.id);\n await this.client.redactEvent(this.roomId, this.id);\n\n const nextVersion = (await this.getVersionHistory())[1]; // [0] will be us\n if (nextVersion) await nextVersion.delete(); // implicit recursion\n }\n\n /**\n * Gets the name for this file.\n * @returns The name, or \"Unnamed File\" if unknown.\n */\n public getName(): string {\n return this.indexEvent.getContent()[\"name\"] || \"Unnamed File\";\n }\n\n /**\n * Sets the name for this file.\n * @param name - The new name for this file.\n * @returns Promise which resolves when complete.\n */\n public async setName(name: string): Promise<void> {\n await this.client.sendStateEvent(\n this.roomId,\n UNSTABLE_MSC3089_BRANCH.name,\n {\n ...this.indexEvent.getContent(),\n name: name,\n },\n this.id,\n );\n }\n\n /**\n * Gets whether or not a file is locked.\n * @returns True if locked, false otherwise.\n */\n public isLocked(): boolean {\n return this.indexEvent.getContent()[\"locked\"] || false;\n }\n\n /**\n * Sets a file as locked or unlocked.\n * @param locked - True to lock the file, false otherwise.\n * @returns Promise which resolves when complete.\n */\n public async setLocked(locked: boolean): Promise<void> {\n await this.client.sendStateEvent(\n this.roomId,\n UNSTABLE_MSC3089_BRANCH.name,\n {\n ...this.indexEvent.getContent(),\n locked: locked,\n },\n this.id,\n );\n }\n\n /**\n * Gets information about the file needed to download it.\n * @returns Information about the file.\n */\n public async getFileInfo(): Promise<{ info: IEncryptedFile; httpUrl: string }> {\n const event = await this.getFileEvent();\n\n const file = event.getOriginalContent()[\"file\"];\n const httpUrl = this.client.mxcUrlToHttp(file[\"url\"]);\n\n if (!httpUrl) {\n throw new Error(`No HTTP URL available for ${file[\"url\"]}`);\n }\n\n return { info: file, httpUrl: httpUrl };\n }\n\n /**\n * Gets the event the file points to.\n * @returns Promise which resolves to the file's event.\n */\n public async getFileEvent(): Promise<MatrixEvent> {\n const room = this.client.getRoom(this.roomId);\n if (!room) throw new Error(\"Unknown room\");\n\n let event: MatrixEvent | undefined = room.getUnfilteredTimelineSet().findEventById(this.id);\n\n // keep scrolling back if needed until we find the event or reach the start of the room:\n while (!event && room.getLiveTimeline().getState(EventTimeline.BACKWARDS)!.paginationToken) {\n await this.client.scrollback(room, 100);\n event = room.getUnfilteredTimelineSet().findEventById(this.id);\n }\n\n if (!event) throw new Error(\"Failed to find event\");\n\n // Sometimes the event isn't decrypted for us, so do that. We specifically set `emit: true`\n // to ensure that the relations system in the sdk will function.\n await this.client.decryptEventIfNeeded(event, { emit: true, isRetry: true });\n\n return event;\n }\n\n /**\n * Creates a new version of this file with contents in a type that is compatible with MatrixClient.uploadContent().\n * @param name - The name of the file.\n * @param encryptedContents - The encrypted contents.\n * @param info - The encrypted file information.\n * @param additionalContent - Optional event content fields to include in the message.\n * @returns Promise which resolves to the file event's sent response.\n */\n public async createNewVersion(\n name: string,\n encryptedContents: FileType,\n info: Partial<IEncryptedFile>,\n additionalContent?: IContent,\n ): Promise<ISendEventResponse> {\n const fileEventResponse = await this.directory.createFile(name, encryptedContents, info, {\n ...(additionalContent ?? {}),\n \"m.new_content\": true,\n \"m.relates_to\": {\n rel_type: RelationType.Replace,\n event_id: this.id,\n },\n });\n\n // Update the version of the new event\n await this.client.sendStateEvent(\n this.roomId,\n UNSTABLE_MSC3089_BRANCH.name,\n {\n active: true,\n name: name,\n version: this.version + 1,\n },\n fileEventResponse[\"event_id\"],\n );\n\n // Deprecate ourselves\n await this.client.sendStateEvent(\n this.roomId,\n UNSTABLE_MSC3089_BRANCH.name,\n {\n ...this.indexEvent.getContent(),\n active: false,\n },\n this.id,\n );\n\n return fileEventResponse;\n }\n\n /**\n * Gets the file's version history, starting at this file.\n * @returns Promise which resolves to the file's version history, with the\n * first element being the current version and the last element being the first version.\n */\n public async getVersionHistory(): Promise<MSC3089Branch[]> {\n const fileHistory: MSC3089Branch[] = [];\n fileHistory.push(this); // start with ourselves\n\n const room = this.client.getRoom(this.roomId);\n if (!room) throw new Error(\"Invalid or unknown room\");\n\n // Clone the timeline to reverse it, getting most-recent-first ordering, hopefully\n // shortening the awful loop below. Without the clone, we can unintentionally mutate\n // the timeline.\n const timelineEvents = [...room.getLiveTimeline().getEvents()].reverse();\n\n // XXX: This is a very inefficient search, but it's the best we can do with the\n // relations structure we have in the SDK. As of writing, it is not worth the\n // investment in improving the structure.\n let childEvent: MatrixEvent | undefined;\n let parentEvent = await this.getFileEvent();\n do {\n childEvent = timelineEvents.find((e) => e.replacingEventId() === parentEvent.getId());\n if (childEvent) {\n const branch = this.directory.getFile(childEvent.getId()!);\n if (branch) {\n fileHistory.push(branch);\n parentEvent = childEvent;\n } else {\n break; // prevent infinite loop\n }\n }\n } while (childEvent);\n\n return fileHistory;\n }\n}\n"],"mappings":";;;;;;;;AAiBA,IAAAA,MAAA,GAAAC,OAAA;AAGA,IAAAC,cAAA,GAAAD,OAAA;AAAiD,SAAAE,QAAAC,MAAA,EAAAC,cAAA,QAAAC,IAAA,GAAAC,MAAA,CAAAD,IAAA,CAAAF,MAAA,OAAAG,MAAA,CAAAC,qBAAA,QAAAC,OAAA,GAAAF,MAAA,CAAAC,qBAAA,CAAAJ,MAAA,GAAAC,cAAA,KAAAI,OAAA,GAAAA,OAAA,CAAAC,MAAA,WAAAC,GAAA,WAAAJ,MAAA,CAAAK,wBAAA,CAAAR,MAAA,EAAAO,GAAA,EAAAE,UAAA,OAAAP,IAAA,CAAAQ,IAAA,CAAAC,KAAA,CAAAT,IAAA,EAAAG,OAAA,YAAAH,IAAA;AAAA,SAAAU,cAAAC,MAAA,aAAAC,CAAA,MAAAA,CAAA,GAAAC,SAAA,CAAAC,MAAA,EAAAF,CAAA,UAAAG,MAAA,WAAAF,SAAA,CAAAD,CAAA,IAAAC,SAAA,CAAAD,CAAA,QAAAA,CAAA,OAAAf,OAAA,CAAAI,MAAA,CAAAc,MAAA,OAAAC,OAAA,WAAAC,GAAA,QAAAC,gBAAA,CAAAC,OAAA,EAAAR,MAAA,EAAAM,GAAA,EAAAF,MAAA,CAAAE,GAAA,SAAAhB,MAAA,CAAAmB,yBAAA,GAAAnB,MAAA,CAAAoB,gBAAA,CAAAV,MAAA,EAAAV,MAAA,CAAAmB,yBAAA,CAAAL,MAAA,KAAAlB,OAAA,CAAAI,MAAA,CAAAc,MAAA,GAAAC,OAAA,WAAAC,GAAA,IAAAhB,MAAA,CAAAqB,cAAA,CAAAX,MAAA,EAAAM,GAAA,EAAAhB,MAAA,CAAAK,wBAAA,CAAAS,MAAA,EAAAE,GAAA,iBAAAN,MAAA;AAIjD;AACA;AACA;AACA;AACA;AACO,MAAMY,aAAa,CAAC;EAChBC,WAAWA,CACNC,MAAoB,EACZC,UAAuB,EACvBC,SAA2B,EAC7C;IAAA,KAHUF,MAAoB,GAApBA,MAAoB;IAAA,KACZC,UAAuB,GAAvBA,UAAuB;IAAA,KACvBC,SAA2B,GAA3BA,SAA2B;EAG/C,CAAC,CADG;;EAGJ;AACJ;AACA;EACI,IAAWC,EAAEA,CAAA,EAAW;IACpB,MAAMC,QAAQ,GAAG,IAAI,CAACH,UAAU,CAACI,WAAW,EAAE;IAC9C,IAAI,CAACD,QAAQ,EAAE;MACX,MAAM,IAAIE,KAAK,CAAC,gCAAgC,CAAC;IACrD;IACA,OAAOF,QAAQ;EACnB;;EAEA;AACJ;AACA;EACI,IAAWG,QAAQA,CAAA,EAAY;IAC3B,OAAO,IAAI,CAACN,UAAU,CAACO,UAAU,EAAE,CAAC,QAAQ,CAAC,KAAK,IAAI;EAC1D;;EAEA;AACJ;AACA;EACI,IAAWC,OAAOA,CAAA,EAAW;IAAA,IAAAC,qBAAA;IACzB,QAAAA,qBAAA,GAAO,IAAI,CAACT,UAAU,CAACO,UAAU,EAAE,CAAC,SAAS,CAAC,cAAAE,qBAAA,cAAAA,qBAAA,GAAI,CAAC;EACvD;EAEA,IAAYC,MAAMA,CAAA,EAAW;IACzB,OAAO,IAAI,CAACV,UAAU,CAACW,SAAS,EAAE;EACtC;;EAEA;AACJ;AACA;AACA;EACI,MAAaC,MAAMA,CAAA,EAAkB;IACjC,MAAM,IAAI,CAACb,MAAM,CAACc,cAAc,CAAC,IAAI,CAACH,MAAM,EAAEI,8BAAuB,CAACC,IAAI,EAAE,CAAC,CAAC,EAAE,IAAI,CAACb,EAAE,CAAC;IACxF,MAAM,IAAI,CAACH,MAAM,CAACiB,WAAW,CAAC,IAAI,CAACN,MAAM,EAAE,IAAI,CAACR,EAAE,CAAC;IAEnD,MAAMe,WAAW,GAAG,CAAC,MAAM,IAAI,CAACC,iBAAiB,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC;IACzD,IAAID,WAAW,EAAE,MAAMA,WAAW,CAACL,MAAM,EAAE,CAAC,CAAC;EACjD;;EAEA;AACJ;AACA;AACA;EACWO,OAAOA,CAAA,EAAW;IACrB,OAAO,IAAI,CAACnB,UAAU,CAACO,UAAU,EAAE,CAAC,MAAM,CAAC,IAAI,cAAc;EACjE;;EAEA;AACJ;AACA;AACA;AACA;EACI,MAAaa,OAAOA,CAACL,IAAY,EAAiB;IAC9C,MAAM,IAAI,CAAChB,MAAM,CAACc,cAAc,CAC5B,IAAI,CAACH,MAAM,EACXI,8BAAuB,CAACC,IAAI,EAAA/B,aAAA,CAAAA,aAAA,KAErB,IAAI,CAACgB,UAAU,CAACO,UAAU,EAAE;MAC/BQ,IAAI,EAAEA;IAAI,IAEd,IAAI,CAACb,EAAE,CACV;EACL;;EAEA;AACJ;AACA;AACA;EACWmB,QAAQA,CAAA,EAAY;IACvB,OAAO,IAAI,CAACrB,UAAU,CAACO,UAAU,EAAE,CAAC,QAAQ,CAAC,IAAI,KAAK;EAC1D;;EAEA;AACJ;AACA;AACA;AACA;EACI,MAAae,SAASA,CAACC,MAAe,EAAiB;IACnD,MAAM,IAAI,CAACxB,MAAM,CAACc,cAAc,CAC5B,IAAI,CAACH,MAAM,EACXI,8BAAuB,CAACC,IAAI,EAAA/B,aAAA,CAAAA,aAAA,KAErB,IAAI,CAACgB,UAAU,CAACO,UAAU,EAAE;MAC/BgB,MAAM,EAAEA;IAAM,IAElB,IAAI,CAACrB,EAAE,CACV;EACL;;EAEA;AACJ;AACA;AACA;EACI,MAAasB,WAAWA,CAAA,EAAuD;IAC3E,MAAMC,KAAK,GAAG,MAAM,IAAI,CAACC,YAAY,EAAE;IAEvC,MAAMC,IAAI,GAAGF,KAAK,CAACG,kBAAkB,EAAE,CAAC,MAAM,CAAC;IAC/C,MAAMC,OAAO,GAAG,IAAI,CAAC9B,MAAM,CAAC+B,YAAY,CAACH,IAAI,CAAC,KAAK,CAAC,CAAC;IAErD,IAAI,CAACE,OAAO,EAAE;MACV,MAAM,IAAIxB,KAAK,CAAE,6BAA4BsB,IAAI,CAAC,KAAK,CAAE,EAAC,CAAC;IAC/D;IAEA,OAAO;MAAEI,IAAI,EAAEJ,IAAI;MAAEE,OAAO,EAAEA;IAAQ,CAAC;EAC3C;;EAEA;AACJ;AACA;AACA;EACI,MAAaH,YAAYA,CAAA,EAAyB;IAC9C,MAAMM,IAAI,GAAG,IAAI,CAACjC,MAAM,CAACkC,OAAO,CAAC,IAAI,CAACvB,MAAM,CAAC;IAC7C,IAAI,CAACsB,IAAI,EAAE,MAAM,IAAI3B,KAAK,CAAC,cAAc,CAAC;IAE1C,IAAIoB,KAA8B,GAAGO,IAAI,CAACE,wBAAwB,EAAE,CAACC,aAAa,CAAC,IAAI,CAACjC,EAAE,CAAC;;IAE3F;IACA,OAAO,CAACuB,KAAK,IAAIO,IAAI,CAACI,eAAe,EAAE,CAACC,QAAQ,CAACC,4BAAa,CAACC,SAAS,CAAC,CAAEC,eAAe,EAAE;MACxF,MAAM,IAAI,CAACzC,MAAM,CAAC0C,UAAU,CAACT,IAAI,EAAE,GAAG,CAAC;MACvCP,KAAK,GAAGO,IAAI,CAACE,wBAAwB,EAAE,CAACC,aAAa,CAAC,IAAI,CAACjC,EAAE,CAAC;IAClE;IAEA,IAAI,CAACuB,KAAK,EAAE,MAAM,IAAIpB,KAAK,CAAC,sBAAsB,CAAC;;IAEnD;IACA;IACA,MAAM,IAAI,CAACN,MAAM,CAAC2C,oBAAoB,CAACjB,KAAK,EAAE;MAAEkB,IAAI,EAAE,IAAI;MAAEC,OAAO,EAAE;IAAK,CAAC,CAAC;IAE5E,OAAOnB,KAAK;EAChB;;EAEA;AACJ;AACA;AACA;AACA;AACA;AACA;AACA;EACI,MAAaoB,gBAAgBA,CACzB9B,IAAY,EACZ+B,iBAA2B,EAC3Bf,IAA6B,EAC7BgB,iBAA4B,EACD;IAC3B,MAAMC,iBAAiB,GAAG,MAAM,IAAI,CAAC/C,SAAS,CAACgD,UAAU,CAAClC,IAAI,EAAE+B,iBAAiB,EAAEf,IAAI,EAAA/C,aAAA,CAAAA,aAAA,KAC/E+D,iBAAiB,aAAjBA,iBAAiB,cAAjBA,iBAAiB,GAAI,CAAC,CAAC;MAC3B,eAAe,EAAE,IAAI;MACrB,cAAc,EAAE;QACZG,QAAQ,EAAEC,mBAAY,CAACC,OAAO;QAC9BC,QAAQ,EAAE,IAAI,CAACnD;MACnB;IAAC,GACH;;IAEF;IACA,MAAM,IAAI,CAACH,MAAM,CAACc,cAAc,CAC5B,IAAI,CAACH,MAAM,EACXI,8BAAuB,CAACC,IAAI,EAC5B;MACIuC,MAAM,EAAE,IAAI;MACZvC,IAAI,EAAEA,IAAI;MACVP,OAAO,EAAE,IAAI,CAACA,OAAO,GAAG;IAC5B,CAAC,EACDwC,iBAAiB,CAAC,UAAU,CAAC,CAChC;;IAED;IACA,MAAM,IAAI,CAACjD,MAAM,CAACc,cAAc,CAC5B,IAAI,CAACH,MAAM,EACXI,8BAAuB,CAACC,IAAI,EAAA/B,aAAA,CAAAA,aAAA,KAErB,IAAI,CAACgB,UAAU,CAACO,UAAU,EAAE;MAC/B+C,MAAM,EAAE;IAAK,IAEjB,IAAI,CAACpD,EAAE,CACV;IAED,OAAO8C,iBAAiB;EAC5B;;EAEA;AACJ;AACA;AACA;AACA;EACI,MAAa9B,iBAAiBA,CAAA,EAA6B;IACvD,MAAMqC,WAA4B,GAAG,EAAE;IACvCA,WAAW,CAACzE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;;IAExB,MAAMkD,IAAI,GAAG,IAAI,CAACjC,MAAM,CAACkC,OAAO,CAAC,IAAI,CAACvB,MAAM,CAAC;IAC7C,IAAI,CAACsB,IAAI,EAAE,MAAM,IAAI3B,KAAK,CAAC,yBAAyB,CAAC;;IAErD;IACA;IACA;IACA,MAAMmD,cAAc,GAAG,CAAC,GAAGxB,IAAI,CAACI,eAAe,EAAE,CAACqB,SAAS,EAAE,CAAC,CAACC,OAAO,EAAE;;IAExE;IACA;IACA;IACA,IAAIC,UAAmC;IACvC,IAAIC,WAAW,GAAG,MAAM,IAAI,CAAClC,YAAY,EAAE;IAC3C,GAAG;MACCiC,UAAU,GAAGH,cAAc,CAACK,IAAI,CAAEC,CAAC,IAAKA,CAAC,CAACC,gBAAgB,EAAE,KAAKH,WAAW,CAACI,KAAK,EAAE,CAAC;MACrF,IAAIL,UAAU,EAAE;QACZ,MAAMM,MAAM,GAAG,IAAI,CAAChE,SAAS,CAACiE,OAAO,CAACP,UAAU,CAACK,KAAK,EAAE,CAAE;QAC1D,IAAIC,MAAM,EAAE;UACRV,WAAW,CAACzE,IAAI,CAACmF,MAAM,CAAC;UACxBL,WAAW,GAAGD,UAAU;QAC5B,CAAC,MAAM;UACH,MAAM,CAAC;QACX;MACJ;IACJ,CAAC,QAAQA,UAAU;IAEnB,OAAOJ,WAAW;EACtB;AACJ;AAACY,OAAA,CAAAtE,aAAA,GAAAA,aAAA"} \ No newline at end of file
diff --git a/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/MSC3089TreeSpace.d.ts b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/MSC3089TreeSpace.d.ts
new file mode 100644
index 0000000..fce3d15
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/MSC3089TreeSpace.d.ts
@@ -0,0 +1,164 @@
+import { MatrixClient } from "../client";
+import { IEncryptedFile } from "../@types/event";
+import { Room } from "./room";
+import { IContent } from "./event";
+import { MSC3089Branch } from "./MSC3089Branch";
+import { ISendEventResponse } from "../@types/requests";
+import { FileType } from "../http-api";
+/**
+ * The recommended defaults for a tree space's power levels. Note that this
+ * is UNSTABLE and subject to breaking changes without notice.
+ */
+export declare const DEFAULT_TREE_POWER_LEVELS_TEMPLATE: {
+ invite: number;
+ kick: number;
+ ban: number;
+ redact: number;
+ state_default: number;
+ events_default: number;
+ users_default: number;
+ events: {
+ "m.room.power_levels": number;
+ "m.room.history_visibility": number;
+ "m.room.tombstone": number;
+ "m.room.encryption": number;
+ "m.room.name": number;
+ "m.room.message": number;
+ "m.room.encrypted": number;
+ "m.sticker": number;
+ };
+ users: {};
+};
+/**
+ * Ease-of-use representation for power levels represented as simple roles.
+ * Note that this is UNSTABLE and subject to breaking changes without notice.
+ */
+export declare enum TreePermissions {
+ Viewer = "viewer",
+ Editor = "editor",
+ Owner = "owner"
+}
+/**
+ * Represents a [MSC3089](https://github.com/matrix-org/matrix-doc/pull/3089)
+ * file tree Space. Note that this is UNSTABLE and subject to breaking changes
+ * without notice.
+ */
+export declare class MSC3089TreeSpace {
+ private client;
+ readonly roomId: string;
+ readonly room: Room;
+ constructor(client: MatrixClient, roomId: string);
+ /**
+ * Syntactic sugar for room ID of the Space.
+ */
+ get id(): string;
+ /**
+ * Whether or not this is a top level space.
+ */
+ get isTopLevel(): boolean;
+ /**
+ * Sets the name of the tree space.
+ * @param name - The new name for the space.
+ * @returns Promise which resolves when complete.
+ */
+ setName(name: string): Promise<void>;
+ /**
+ * Invites a user to the tree space. They will be given the default Viewer
+ * permission level unless specified elsewhere.
+ * @param userId - The user ID to invite.
+ * @param andSubspaces - True (default) to invite the user to all
+ * directories/subspaces too, recursively.
+ * @param shareHistoryKeys - True (default) to share encryption keys
+ * with the invited user. This will allow them to decrypt the events (files)
+ * in the tree. Keys will not be shared if the room is lacking appropriate
+ * history visibility (by default, history visibility is "shared" in trees,
+ * which is an appropriate visibility for these purposes).
+ * @returns Promise which resolves when complete.
+ */
+ invite(userId: string, andSubspaces?: boolean, shareHistoryKeys?: boolean): Promise<void>;
+ private retryInvite;
+ /**
+ * Sets the permissions of a user to the given role. Note that if setting a user
+ * to Owner then they will NOT be able to be demoted. If the user does not have
+ * permission to change the power level of the target, an error will be thrown.
+ * @param userId - The user ID to change the role of.
+ * @param role - The role to assign.
+ * @returns Promise which resolves when complete.
+ */
+ setPermissions(userId: string, role: TreePermissions): Promise<void>;
+ /**
+ * Gets the current permissions of a user. Note that any users missing explicit permissions (or not
+ * in the space) will be considered Viewers. Appropriate membership checks need to be performed
+ * elsewhere.
+ * @param userId - The user ID to check permissions of.
+ * @returns The permissions for the user, defaulting to Viewer.
+ */
+ getPermissions(userId: string): TreePermissions;
+ /**
+ * Creates a directory under this tree space, represented as another tree space.
+ * @param name - The name for the directory.
+ * @returns Promise which resolves to the created directory.
+ */
+ createDirectory(name: string): Promise<MSC3089TreeSpace>;
+ /**
+ * Gets a list of all known immediate subdirectories to this tree space.
+ * @returns The tree spaces (directories). May be empty, but not null.
+ */
+ getDirectories(): MSC3089TreeSpace[];
+ /**
+ * Gets a subdirectory of a given ID under this tree space. Note that this will not recurse
+ * into children and instead only look one level deep.
+ * @param roomId - The room ID (directory ID) to find.
+ * @returns The directory, or undefined if not found.
+ */
+ getDirectory(roomId: string): MSC3089TreeSpace | undefined;
+ /**
+ * Deletes the tree, kicking all members and deleting **all subdirectories**.
+ * @returns Promise which resolves when complete.
+ */
+ delete(): Promise<void>;
+ private getOrderedChildren;
+ private getParentRoom;
+ /**
+ * Gets the current order index for this directory. Note that if this is the top level space
+ * then -1 will be returned.
+ * @returns The order index of this space.
+ */
+ getOrder(): number;
+ /**
+ * Sets the order index for this directory within its parent. Note that if this is a top level
+ * space then an error will be thrown. -1 can be used to move the child to the start, and numbers
+ * larger than the number of children can be used to move the child to the end.
+ * @param index - The new order index for this space.
+ * @returns Promise which resolves when complete.
+ * @throws Throws if this is a top level space.
+ */
+ setOrder(index: number): Promise<void>;
+ /**
+ * Creates (uploads) a new file to this tree. The file must have already been encrypted for the room.
+ * The file contents are in a type that is compatible with MatrixClient.uploadContent().
+ * @param name - The name of the file.
+ * @param encryptedContents - The encrypted contents.
+ * @param info - The encrypted file information.
+ * @param additionalContent - Optional event content fields to include in the message.
+ * @returns Promise which resolves to the file event's sent response.
+ */
+ createFile(name: string, encryptedContents: FileType, info: Partial<IEncryptedFile>, additionalContent?: IContent): Promise<ISendEventResponse>;
+ /**
+ * Retrieves a file from the tree.
+ * @param fileEventId - The event ID of the file.
+ * @returns The file, or null if not found.
+ */
+ getFile(fileEventId: string): MSC3089Branch | null;
+ /**
+ * Gets an array of all known files for the tree.
+ * @returns The known files. May be empty, but not null.
+ */
+ listFiles(): MSC3089Branch[];
+ /**
+ * Gets an array of all known files for the tree, including inactive/invalid ones.
+ * @returns The known files. May be empty, but not null.
+ */
+ listAllFiles(): MSC3089Branch[];
+}
+//# sourceMappingURL=MSC3089TreeSpace.d.ts.map \ No newline at end of file
diff --git a/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/MSC3089TreeSpace.d.ts.map b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/MSC3089TreeSpace.d.ts.map
new file mode 100644
index 0000000..cb8e4f6
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/MSC3089TreeSpace.d.ts.map
@@ -0,0 +1 @@
+{"version":3,"file":"MSC3089TreeSpace.d.ts","sourceRoot":"","sources":["../../src/models/MSC3089TreeSpace.ts"],"names":[],"mappings":"AAkBA,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,EAAa,cAAc,EAA2D,MAAM,iBAAiB,CAAC;AACrH,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAE9B,OAAO,EAAE,QAAQ,EAAe,MAAM,SAAS,CAAC;AAShD,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAEhD,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAEvC;;;GAGG;AACH,eAAO,MAAM,kCAAkC;;;;;;;;;;;;;;;;;;;CA2B9C,CAAC;AAEF;;;GAGG;AACH,oBAAY,eAAe;IACvB,MAAM,WAAW;IACjB,MAAM,WAAW;IACjB,KAAK,UAAU;CAClB;AAED;;;;GAIG;AACH,qBAAa,gBAAgB;IAGN,OAAO,CAAC,MAAM;aAAgC,MAAM,EAAE,MAAM;IAF/E,SAAgB,IAAI,EAAE,IAAI,CAAC;gBAEA,MAAM,EAAE,YAAY,EAAkB,MAAM,EAAE,MAAM;IAM/E;;OAEG;IACH,IAAW,EAAE,IAAI,MAAM,CAEtB;IAED;;OAEG;IACH,IAAW,UAAU,IAAI,OAAO,CAM/B;IAED;;;;OAIG;IACU,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIjD;;;;;;;;;;;;OAYG;IACU,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,YAAY,UAAO,EAAE,gBAAgB,UAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAiBhG,OAAO,CAAC,WAAW;IAYnB;;;;;;;OAOG;IACU,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC;IA4BjF;;;;;;OAMG;IACI,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,eAAe;IAetD;;;;OAIG;IACU,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAwBrE;;;OAGG;IACI,cAAc,IAAI,gBAAgB,EAAE;IAiB3C;;;;;OAKG;IACI,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,gBAAgB,GAAG,SAAS;IAIjE;;;OAGG;IACU,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;IAsBpC,OAAO,CAAC,kBAAkB;IA+B1B,OAAO,CAAC,aAAa;IAerB;;;;OAIG;IACI,QAAQ,IAAI,MAAM;IAUzB;;;;;;;OAOG;IACU,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IA8GnD;;;;;;;;OAQG;IACU,UAAU,CACnB,IAAI,EAAE,MAAM,EACZ,iBAAiB,EAAE,QAAQ,EAC3B,IAAI,EAAE,OAAO,CAAC,cAAc,CAAC,EAC7B,iBAAiB,CAAC,EAAE,QAAQ,GAC7B,OAAO,CAAC,kBAAkB,CAAC;IAwC9B;;;;OAIG;IACI,OAAO,CAAC,WAAW,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI;IAKzD;;;OAGG;IACI,SAAS,IAAI,aAAa,EAAE;IAInC;;;OAGG;IACI,YAAY,IAAI,aAAa,EAAE;CAIzC"} \ No newline at end of file
diff --git a/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/MSC3089TreeSpace.js b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/MSC3089TreeSpace.js
new file mode 100644
index 0000000..cb23980
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/MSC3089TreeSpace.js
@@ -0,0 +1,503 @@
+"use strict";
+
+var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.TreePermissions = exports.MSC3089TreeSpace = exports.DEFAULT_TREE_POWER_LEVELS_TEMPLATE = void 0;
+var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
+var _pRetry = _interopRequireDefault(require("p-retry"));
+var _event = require("../@types/event");
+var _logger = require("../logger");
+var _utils = require("../utils");
+var _MSC3089Branch = require("./MSC3089Branch");
+var _megolm = require("../crypto/algorithms/megolm");
+function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
+function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { (0, _defineProperty2.default)(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
+/**
+ * The recommended defaults for a tree space's power levels. Note that this
+ * is UNSTABLE and subject to breaking changes without notice.
+ */
+const DEFAULT_TREE_POWER_LEVELS_TEMPLATE = {
+ // Owner
+ invite: 100,
+ kick: 100,
+ ban: 100,
+ // Editor
+ redact: 50,
+ state_default: 50,
+ events_default: 50,
+ // Viewer
+ users_default: 0,
+ // Mixed
+ events: {
+ [_event.EventType.RoomPowerLevels]: 100,
+ [_event.EventType.RoomHistoryVisibility]: 100,
+ [_event.EventType.RoomTombstone]: 100,
+ [_event.EventType.RoomEncryption]: 100,
+ [_event.EventType.RoomName]: 50,
+ [_event.EventType.RoomMessage]: 50,
+ [_event.EventType.RoomMessageEncrypted]: 50,
+ [_event.EventType.Sticker]: 50
+ },
+ users: {} // defined by calling code
+};
+
+/**
+ * Ease-of-use representation for power levels represented as simple roles.
+ * Note that this is UNSTABLE and subject to breaking changes without notice.
+ */
+exports.DEFAULT_TREE_POWER_LEVELS_TEMPLATE = DEFAULT_TREE_POWER_LEVELS_TEMPLATE;
+let TreePermissions; // "Admin" or PL100
+/**
+ * Represents a [MSC3089](https://github.com/matrix-org/matrix-doc/pull/3089)
+ * file tree Space. Note that this is UNSTABLE and subject to breaking changes
+ * without notice.
+ */
+exports.TreePermissions = TreePermissions;
+(function (TreePermissions) {
+ TreePermissions["Viewer"] = "viewer";
+ TreePermissions["Editor"] = "editor";
+ TreePermissions["Owner"] = "owner";
+})(TreePermissions || (exports.TreePermissions = TreePermissions = {}));
+class MSC3089TreeSpace {
+ constructor(client, roomId) {
+ this.client = client;
+ this.roomId = roomId;
+ (0, _defineProperty2.default)(this, "room", void 0);
+ this.room = this.client.getRoom(this.roomId);
+ if (!this.room) throw new Error("Unknown room");
+ }
+
+ /**
+ * Syntactic sugar for room ID of the Space.
+ */
+ get id() {
+ return this.roomId;
+ }
+
+ /**
+ * Whether or not this is a top level space.
+ */
+ get isTopLevel() {
+ // XXX: This is absolutely not how you find out if the space is top level
+ // but is safe for a managed usecase like we offer in the SDK.
+ const parentEvents = this.room.currentState.getStateEvents(_event.EventType.SpaceParent);
+ if (!(parentEvents !== null && parentEvents !== void 0 && parentEvents.length)) return true;
+ return parentEvents.every(e => {
+ var _e$getContent;
+ return !((_e$getContent = e.getContent()) !== null && _e$getContent !== void 0 && _e$getContent["via"]);
+ });
+ }
+
+ /**
+ * Sets the name of the tree space.
+ * @param name - The new name for the space.
+ * @returns Promise which resolves when complete.
+ */
+ async setName(name) {
+ await this.client.sendStateEvent(this.roomId, _event.EventType.RoomName, {
+ name
+ }, "");
+ }
+
+ /**
+ * Invites a user to the tree space. They will be given the default Viewer
+ * permission level unless specified elsewhere.
+ * @param userId - The user ID to invite.
+ * @param andSubspaces - True (default) to invite the user to all
+ * directories/subspaces too, recursively.
+ * @param shareHistoryKeys - True (default) to share encryption keys
+ * with the invited user. This will allow them to decrypt the events (files)
+ * in the tree. Keys will not be shared if the room is lacking appropriate
+ * history visibility (by default, history visibility is "shared" in trees,
+ * which is an appropriate visibility for these purposes).
+ * @returns Promise which resolves when complete.
+ */
+ async invite(userId, andSubspaces = true, shareHistoryKeys = true) {
+ const promises = [this.retryInvite(userId)];
+ if (andSubspaces) {
+ promises.push(...this.getDirectories().map(d => d.invite(userId, andSubspaces, shareHistoryKeys)));
+ }
+ return Promise.all(promises).then(() => {
+ // Note: key sharing is default on because for file trees it is relatively important that the invite
+ // target can actually decrypt the files. The implied use case is that by inviting a user to the tree
+ // it means the sender would like the receiver to view/download the files contained within, much like
+ // sharing a folder in other circles.
+ if (shareHistoryKeys && (0, _megolm.isRoomSharedHistory)(this.room)) {
+ // noinspection JSIgnoredPromiseFromCall - we aren't concerned as much if this fails.
+ this.client.sendSharedHistoryKeys(this.roomId, [userId]);
+ }
+ });
+ }
+ retryInvite(userId) {
+ return (0, _utils.simpleRetryOperation)(async () => {
+ await this.client.invite(this.roomId, userId).catch(e => {
+ // We don't want to retry permission errors forever...
+ if ((e === null || e === void 0 ? void 0 : e.errcode) === "M_FORBIDDEN") {
+ throw new _pRetry.default.AbortError(e);
+ }
+ throw e;
+ });
+ });
+ }
+
+ /**
+ * Sets the permissions of a user to the given role. Note that if setting a user
+ * to Owner then they will NOT be able to be demoted. If the user does not have
+ * permission to change the power level of the target, an error will be thrown.
+ * @param userId - The user ID to change the role of.
+ * @param role - The role to assign.
+ * @returns Promise which resolves when complete.
+ */
+ async setPermissions(userId, role) {
+ var _pls$events;
+ const currentPls = this.room.currentState.getStateEvents(_event.EventType.RoomPowerLevels, "");
+ if (Array.isArray(currentPls)) throw new Error("Unexpected return type for power levels");
+ const pls = (currentPls === null || currentPls === void 0 ? void 0 : currentPls.getContent()) || {};
+ const viewLevel = pls["users_default"] || 0;
+ const editLevel = pls["events_default"] || 50;
+ const adminLevel = ((_pls$events = pls["events"]) === null || _pls$events === void 0 ? void 0 : _pls$events[_event.EventType.RoomPowerLevels]) || 100;
+ const users = pls["users"] || {};
+ switch (role) {
+ case TreePermissions.Viewer:
+ users[userId] = viewLevel;
+ break;
+ case TreePermissions.Editor:
+ users[userId] = editLevel;
+ break;
+ case TreePermissions.Owner:
+ users[userId] = adminLevel;
+ break;
+ default:
+ throw new Error("Invalid role: " + role);
+ }
+ pls["users"] = users;
+ await this.client.sendStateEvent(this.roomId, _event.EventType.RoomPowerLevels, pls, "");
+ }
+
+ /**
+ * Gets the current permissions of a user. Note that any users missing explicit permissions (or not
+ * in the space) will be considered Viewers. Appropriate membership checks need to be performed
+ * elsewhere.
+ * @param userId - The user ID to check permissions of.
+ * @returns The permissions for the user, defaulting to Viewer.
+ */
+ getPermissions(userId) {
+ var _pls$events2, _pls$users;
+ const currentPls = this.room.currentState.getStateEvents(_event.EventType.RoomPowerLevels, "");
+ if (Array.isArray(currentPls)) throw new Error("Unexpected return type for power levels");
+ const pls = (currentPls === null || currentPls === void 0 ? void 0 : currentPls.getContent()) || {};
+ const viewLevel = pls["users_default"] || 0;
+ const editLevel = pls["events_default"] || 50;
+ const adminLevel = ((_pls$events2 = pls["events"]) === null || _pls$events2 === void 0 ? void 0 : _pls$events2[_event.EventType.RoomPowerLevels]) || 100;
+ const userLevel = ((_pls$users = pls["users"]) === null || _pls$users === void 0 ? void 0 : _pls$users[userId]) || viewLevel;
+ if (userLevel >= adminLevel) return TreePermissions.Owner;
+ if (userLevel >= editLevel) return TreePermissions.Editor;
+ return TreePermissions.Viewer;
+ }
+
+ /**
+ * Creates a directory under this tree space, represented as another tree space.
+ * @param name - The name for the directory.
+ * @returns Promise which resolves to the created directory.
+ */
+ async createDirectory(name) {
+ const directory = await this.client.unstableCreateFileTree(name);
+ await this.client.sendStateEvent(this.roomId, _event.EventType.SpaceChild, {
+ via: [this.client.getDomain()]
+ }, directory.roomId);
+ await this.client.sendStateEvent(directory.roomId, _event.EventType.SpaceParent, {
+ via: [this.client.getDomain()]
+ }, this.roomId);
+ return directory;
+ }
+
+ /**
+ * Gets a list of all known immediate subdirectories to this tree space.
+ * @returns The tree spaces (directories). May be empty, but not null.
+ */
+ getDirectories() {
+ const trees = [];
+ const children = this.room.currentState.getStateEvents(_event.EventType.SpaceChild);
+ for (const child of children) {
+ try {
+ const stateKey = child.getStateKey();
+ if (stateKey) {
+ const tree = this.client.unstableGetFileTreeSpace(stateKey);
+ if (tree) trees.push(tree);
+ }
+ } catch (e) {
+ _logger.logger.warn("Unable to create tree space instance for listing. Are we joined?", e);
+ }
+ }
+ return trees;
+ }
+
+ /**
+ * Gets a subdirectory of a given ID under this tree space. Note that this will not recurse
+ * into children and instead only look one level deep.
+ * @param roomId - The room ID (directory ID) to find.
+ * @returns The directory, or undefined if not found.
+ */
+ getDirectory(roomId) {
+ return this.getDirectories().find(r => r.roomId === roomId);
+ }
+
+ /**
+ * Deletes the tree, kicking all members and deleting **all subdirectories**.
+ * @returns Promise which resolves when complete.
+ */
+ async delete() {
+ const subdirectories = this.getDirectories();
+ for (const dir of subdirectories) {
+ await dir.delete();
+ }
+ const kickMemberships = ["invite", "knock", "join"];
+ const members = this.room.currentState.getStateEvents(_event.EventType.RoomMember);
+ for (const member of members) {
+ const isNotUs = member.getStateKey() !== this.client.getUserId();
+ if (isNotUs && kickMemberships.includes(member.getContent().membership)) {
+ const stateKey = member.getStateKey();
+ if (!stateKey) {
+ throw new Error("State key not found for branch");
+ }
+ await this.client.kick(this.roomId, stateKey, "Room deleted");
+ }
+ }
+ await this.client.leave(this.roomId);
+ }
+ getOrderedChildren(children) {
+ const ordered = children.map(c => ({
+ roomId: c.getStateKey(),
+ order: c.getContent()["order"]
+ })).filter(c => c.roomId);
+ ordered.sort((a, b) => {
+ if (a.order && !b.order) {
+ return -1;
+ } else if (!a.order && b.order) {
+ return 1;
+ } else if (!a.order && !b.order) {
+ var _roomA$currentState$g, _roomA$currentState$g2, _roomB$currentState$g, _roomB$currentState$g2;
+ const roomA = this.client.getRoom(a.roomId);
+ const roomB = this.client.getRoom(b.roomId);
+ if (!roomA || !roomB) {
+ // just don't bother trying to do more partial sorting
+ return (0, _utils.lexicographicCompare)(a.roomId, b.roomId);
+ }
+ const createTsA = (_roomA$currentState$g = (_roomA$currentState$g2 = roomA.currentState.getStateEvents(_event.EventType.RoomCreate, "")) === null || _roomA$currentState$g2 === void 0 ? void 0 : _roomA$currentState$g2.getTs()) !== null && _roomA$currentState$g !== void 0 ? _roomA$currentState$g : 0;
+ const createTsB = (_roomB$currentState$g = (_roomB$currentState$g2 = roomB.currentState.getStateEvents(_event.EventType.RoomCreate, "")) === null || _roomB$currentState$g2 === void 0 ? void 0 : _roomB$currentState$g2.getTs()) !== null && _roomB$currentState$g !== void 0 ? _roomB$currentState$g : 0;
+ if (createTsA === createTsB) {
+ return (0, _utils.lexicographicCompare)(a.roomId, b.roomId);
+ }
+ return createTsA - createTsB;
+ } else {
+ // both not-null orders
+ return (0, _utils.lexicographicCompare)(a.order, b.order);
+ }
+ });
+ return ordered;
+ }
+ getParentRoom() {
+ const parents = this.room.currentState.getStateEvents(_event.EventType.SpaceParent);
+ const parent = parents[0]; // XXX: Wild assumption
+ if (!parent) throw new Error("Expected to have a parent in a non-top level space");
+
+ // XXX: We are assuming the parent is a valid tree space.
+ // We probably don't need to validate the parent room state for this usecase though.
+ const stateKey = parent.getStateKey();
+ if (!stateKey) throw new Error("No state key found for parent");
+ const parentRoom = this.client.getRoom(stateKey);
+ if (!parentRoom) throw new Error("Unable to locate room for parent");
+ return parentRoom;
+ }
+
+ /**
+ * Gets the current order index for this directory. Note that if this is the top level space
+ * then -1 will be returned.
+ * @returns The order index of this space.
+ */
+ getOrder() {
+ if (this.isTopLevel) return -1;
+ const parentRoom = this.getParentRoom();
+ const children = parentRoom.currentState.getStateEvents(_event.EventType.SpaceChild);
+ const ordered = this.getOrderedChildren(children);
+ return ordered.findIndex(c => c.roomId === this.roomId);
+ }
+
+ /**
+ * Sets the order index for this directory within its parent. Note that if this is a top level
+ * space then an error will be thrown. -1 can be used to move the child to the start, and numbers
+ * larger than the number of children can be used to move the child to the end.
+ * @param index - The new order index for this space.
+ * @returns Promise which resolves when complete.
+ * @throws Throws if this is a top level space.
+ */
+ async setOrder(index) {
+ var _currentChild$getCont2;
+ if (this.isTopLevel) throw new Error("Cannot set order of top level spaces currently");
+ const parentRoom = this.getParentRoom();
+ const children = parentRoom.currentState.getStateEvents(_event.EventType.SpaceChild);
+ const ordered = this.getOrderedChildren(children);
+ index = Math.max(Math.min(index, ordered.length - 1), 0);
+ const currentIndex = this.getOrder();
+ const movingUp = currentIndex < index;
+ if (movingUp && index === ordered.length - 1) {
+ index--;
+ } else if (!movingUp && index === 0) {
+ index++;
+ }
+ const prev = ordered[movingUp ? index : index - 1];
+ const next = ordered[movingUp ? index + 1 : index];
+ let newOrder = _utils.DEFAULT_ALPHABET[0];
+ let ensureBeforeIsSane = false;
+ if (!prev) {
+ // Move to front
+ if (next !== null && next !== void 0 && next.order) {
+ newOrder = (0, _utils.prevString)(next.order);
+ }
+ } else if (index === ordered.length - 1) {
+ // Move to back
+ if (next !== null && next !== void 0 && next.order) {
+ newOrder = (0, _utils.nextString)(next.order);
+ }
+ } else {
+ // Move somewhere in the middle
+ const startOrder = prev === null || prev === void 0 ? void 0 : prev.order;
+ const endOrder = next === null || next === void 0 ? void 0 : next.order;
+ if (startOrder && endOrder) {
+ if (startOrder === endOrder) {
+ // Error case: just move +1 to break out of awful math
+ newOrder = (0, _utils.nextString)(startOrder);
+ } else {
+ newOrder = (0, _utils.averageBetweenStrings)(startOrder, endOrder);
+ }
+ } else {
+ if (startOrder) {
+ // We're at the end (endOrder is null, so no explicit order)
+ newOrder = (0, _utils.nextString)(startOrder);
+ } else if (endOrder) {
+ // We're at the start (startOrder is null, so nothing before us)
+ newOrder = (0, _utils.prevString)(endOrder);
+ } else {
+ // Both points are unknown. We're likely in a range where all the children
+ // don't have particular order values, so we may need to update them too.
+ // The other possibility is there's only us as a child, but we should have
+ // shown up in the other states.
+ ensureBeforeIsSane = true;
+ }
+ }
+ }
+ if (ensureBeforeIsSane) {
+ // We were asked by the order algorithm to prepare the moving space for a landing
+ // in the undefined order part of the order array, which means we need to update the
+ // spaces that come before it with a stable order value.
+ let lastOrder;
+ for (let i = 0; i <= index; i++) {
+ const target = ordered[i];
+ if (i === 0) {
+ lastOrder = target.order;
+ }
+ if (!target.order) {
+ var _currentChild$getCont;
+ // XXX: We should be creating gaps to avoid conflicts
+ lastOrder = lastOrder ? (0, _utils.nextString)(lastOrder) : _utils.DEFAULT_ALPHABET[0];
+ const currentChild = parentRoom.currentState.getStateEvents(_event.EventType.SpaceChild, target.roomId);
+ const content = (_currentChild$getCont = currentChild === null || currentChild === void 0 ? void 0 : currentChild.getContent()) !== null && _currentChild$getCont !== void 0 ? _currentChild$getCont : {
+ via: [this.client.getDomain()]
+ };
+ await this.client.sendStateEvent(parentRoom.roomId, _event.EventType.SpaceChild, _objectSpread(_objectSpread({}, content), {}, {
+ order: lastOrder
+ }), target.roomId);
+ } else {
+ lastOrder = target.order;
+ }
+ }
+ if (lastOrder) {
+ newOrder = (0, _utils.nextString)(lastOrder);
+ }
+ }
+
+ // TODO: Deal with order conflicts by reordering
+
+ // Now we can finally update our own order state
+ const currentChild = parentRoom.currentState.getStateEvents(_event.EventType.SpaceChild, this.roomId);
+ const content = (_currentChild$getCont2 = currentChild === null || currentChild === void 0 ? void 0 : currentChild.getContent()) !== null && _currentChild$getCont2 !== void 0 ? _currentChild$getCont2 : {
+ via: [this.client.getDomain()]
+ };
+ await this.client.sendStateEvent(parentRoom.roomId, _event.EventType.SpaceChild, _objectSpread(_objectSpread({}, content), {}, {
+ // TODO: Safely constrain to 50 character limit required by spaces.
+ order: newOrder
+ }), this.roomId);
+ }
+
+ /**
+ * Creates (uploads) a new file to this tree. The file must have already been encrypted for the room.
+ * The file contents are in a type that is compatible with MatrixClient.uploadContent().
+ * @param name - The name of the file.
+ * @param encryptedContents - The encrypted contents.
+ * @param info - The encrypted file information.
+ * @param additionalContent - Optional event content fields to include in the message.
+ * @returns Promise which resolves to the file event's sent response.
+ */
+ async createFile(name, encryptedContents, info, additionalContent) {
+ var _additionalContent;
+ const {
+ content_uri: mxc
+ } = await this.client.uploadContent(encryptedContents, {
+ includeFilename: false
+ });
+ info.url = mxc;
+ const fileContent = {
+ msgtype: _event.MsgType.File,
+ body: name,
+ url: mxc,
+ file: info
+ };
+ additionalContent = (_additionalContent = additionalContent) !== null && _additionalContent !== void 0 ? _additionalContent : {};
+ if (additionalContent["m.new_content"]) {
+ // We do the right thing according to the spec, but due to how relations are
+ // handled we also end up duplicating this information to the regular `content`
+ // as well.
+ additionalContent["m.new_content"] = fileContent;
+ }
+ const res = await this.client.sendMessage(this.roomId, _objectSpread(_objectSpread(_objectSpread({}, additionalContent), fileContent), {}, {
+ [_event.UNSTABLE_MSC3089_LEAF.name]: {}
+ }));
+ await this.client.sendStateEvent(this.roomId, _event.UNSTABLE_MSC3089_BRANCH.name, {
+ active: true,
+ name: name
+ }, res["event_id"]);
+ return res;
+ }
+
+ /**
+ * Retrieves a file from the tree.
+ * @param fileEventId - The event ID of the file.
+ * @returns The file, or null if not found.
+ */
+ getFile(fileEventId) {
+ const branch = this.room.currentState.getStateEvents(_event.UNSTABLE_MSC3089_BRANCH.name, fileEventId);
+ return branch ? new _MSC3089Branch.MSC3089Branch(this.client, branch, this) : null;
+ }
+
+ /**
+ * Gets an array of all known files for the tree.
+ * @returns The known files. May be empty, but not null.
+ */
+ listFiles() {
+ return this.listAllFiles().filter(b => b.isActive);
+ }
+
+ /**
+ * Gets an array of all known files for the tree, including inactive/invalid ones.
+ * @returns The known files. May be empty, but not null.
+ */
+ listAllFiles() {
+ var _this$room$currentSta;
+ const branches = (_this$room$currentSta = this.room.currentState.getStateEvents(_event.UNSTABLE_MSC3089_BRANCH.name)) !== null && _this$room$currentSta !== void 0 ? _this$room$currentSta : [];
+ return branches.map(e => new _MSC3089Branch.MSC3089Branch(this.client, e, this));
+ }
+}
+exports.MSC3089TreeSpace = MSC3089TreeSpace;
+//# sourceMappingURL=MSC3089TreeSpace.js.map \ No newline at end of file
diff --git a/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/MSC3089TreeSpace.js.map b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/MSC3089TreeSpace.js.map
new file mode 100644
index 0000000..a243b4c
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/MSC3089TreeSpace.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"MSC3089TreeSpace.js","names":["_pRetry","_interopRequireDefault","require","_event","_logger","_utils","_MSC3089Branch","_megolm","ownKeys","object","enumerableOnly","keys","Object","getOwnPropertySymbols","symbols","filter","sym","getOwnPropertyDescriptor","enumerable","push","apply","_objectSpread","target","i","arguments","length","source","forEach","key","_defineProperty2","default","getOwnPropertyDescriptors","defineProperties","defineProperty","DEFAULT_TREE_POWER_LEVELS_TEMPLATE","invite","kick","ban","redact","state_default","events_default","users_default","events","EventType","RoomPowerLevels","RoomHistoryVisibility","RoomTombstone","RoomEncryption","RoomName","RoomMessage","RoomMessageEncrypted","Sticker","users","exports","TreePermissions","MSC3089TreeSpace","constructor","client","roomId","room","getRoom","Error","id","isTopLevel","parentEvents","currentState","getStateEvents","SpaceParent","every","e","_e$getContent","getContent","setName","name","sendStateEvent","userId","andSubspaces","shareHistoryKeys","promises","retryInvite","getDirectories","map","d","Promise","all","then","isRoomSharedHistory","sendSharedHistoryKeys","simpleRetryOperation","catch","errcode","promiseRetry","AbortError","setPermissions","role","_pls$events","currentPls","Array","isArray","pls","viewLevel","editLevel","adminLevel","Viewer","Editor","Owner","getPermissions","_pls$events2","_pls$users","userLevel","createDirectory","directory","unstableCreateFileTree","SpaceChild","via","getDomain","trees","children","child","stateKey","getStateKey","tree","unstableGetFileTreeSpace","logger","warn","getDirectory","find","r","delete","subdirectories","dir","kickMemberships","members","RoomMember","member","isNotUs","getUserId","includes","membership","leave","getOrderedChildren","ordered","c","order","sort","a","b","_roomA$currentState$g","_roomA$currentState$g2","_roomB$currentState$g","_roomB$currentState$g2","roomA","roomB","lexicographicCompare","createTsA","RoomCreate","getTs","createTsB","getParentRoom","parents","parent","parentRoom","getOrder","findIndex","setOrder","index","_currentChild$getCont2","Math","max","min","currentIndex","movingUp","prev","next","newOrder","DEFAULT_ALPHABET","ensureBeforeIsSane","prevString","nextString","startOrder","endOrder","averageBetweenStrings","lastOrder","_currentChild$getCont","currentChild","content","createFile","encryptedContents","info","additionalContent","_additionalContent","content_uri","mxc","uploadContent","includeFilename","url","fileContent","msgtype","MsgType","File","body","file","res","sendMessage","UNSTABLE_MSC3089_LEAF","UNSTABLE_MSC3089_BRANCH","active","getFile","fileEventId","branch","MSC3089Branch","listFiles","listAllFiles","isActive","_this$room$currentSta","branches"],"sources":["../../src/models/MSC3089TreeSpace.ts"],"sourcesContent":["/*\nCopyright 2021 The Matrix.org Foundation C.I.C.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n*/\n\nimport promiseRetry from \"p-retry\";\n\nimport { MatrixClient } from \"../client\";\nimport { EventType, IEncryptedFile, MsgType, UNSTABLE_MSC3089_BRANCH, UNSTABLE_MSC3089_LEAF } from \"../@types/event\";\nimport { Room } from \"./room\";\nimport { logger } from \"../logger\";\nimport { IContent, MatrixEvent } from \"./event\";\nimport {\n averageBetweenStrings,\n DEFAULT_ALPHABET,\n lexicographicCompare,\n nextString,\n prevString,\n simpleRetryOperation,\n} from \"../utils\";\nimport { MSC3089Branch } from \"./MSC3089Branch\";\nimport { isRoomSharedHistory } from \"../crypto/algorithms/megolm\";\nimport { ISendEventResponse } from \"../@types/requests\";\nimport { FileType } from \"../http-api\";\n\n/**\n * The recommended defaults for a tree space's power levels. Note that this\n * is UNSTABLE and subject to breaking changes without notice.\n */\nexport const DEFAULT_TREE_POWER_LEVELS_TEMPLATE = {\n // Owner\n invite: 100,\n kick: 100,\n ban: 100,\n\n // Editor\n redact: 50,\n state_default: 50,\n events_default: 50,\n\n // Viewer\n users_default: 0,\n\n // Mixed\n events: {\n [EventType.RoomPowerLevels]: 100,\n [EventType.RoomHistoryVisibility]: 100,\n [EventType.RoomTombstone]: 100,\n [EventType.RoomEncryption]: 100,\n [EventType.RoomName]: 50,\n [EventType.RoomMessage]: 50,\n [EventType.RoomMessageEncrypted]: 50,\n [EventType.Sticker]: 50,\n },\n\n users: {}, // defined by calling code\n};\n\n/**\n * Ease-of-use representation for power levels represented as simple roles.\n * Note that this is UNSTABLE and subject to breaking changes without notice.\n */\nexport enum TreePermissions {\n Viewer = \"viewer\", // Default\n Editor = \"editor\", // \"Moderator\" or ~PL50\n Owner = \"owner\", // \"Admin\" or PL100\n}\n\n/**\n * Represents a [MSC3089](https://github.com/matrix-org/matrix-doc/pull/3089)\n * file tree Space. Note that this is UNSTABLE and subject to breaking changes\n * without notice.\n */\nexport class MSC3089TreeSpace {\n public readonly room: Room;\n\n public constructor(private client: MatrixClient, public readonly roomId: string) {\n this.room = this.client.getRoom(this.roomId)!;\n\n if (!this.room) throw new Error(\"Unknown room\");\n }\n\n /**\n * Syntactic sugar for room ID of the Space.\n */\n public get id(): string {\n return this.roomId;\n }\n\n /**\n * Whether or not this is a top level space.\n */\n public get isTopLevel(): boolean {\n // XXX: This is absolutely not how you find out if the space is top level\n // but is safe for a managed usecase like we offer in the SDK.\n const parentEvents = this.room.currentState.getStateEvents(EventType.SpaceParent);\n if (!parentEvents?.length) return true;\n return parentEvents.every((e) => !e.getContent()?.[\"via\"]);\n }\n\n /**\n * Sets the name of the tree space.\n * @param name - The new name for the space.\n * @returns Promise which resolves when complete.\n */\n public async setName(name: string): Promise<void> {\n await this.client.sendStateEvent(this.roomId, EventType.RoomName, { name }, \"\");\n }\n\n /**\n * Invites a user to the tree space. They will be given the default Viewer\n * permission level unless specified elsewhere.\n * @param userId - The user ID to invite.\n * @param andSubspaces - True (default) to invite the user to all\n * directories/subspaces too, recursively.\n * @param shareHistoryKeys - True (default) to share encryption keys\n * with the invited user. This will allow them to decrypt the events (files)\n * in the tree. Keys will not be shared if the room is lacking appropriate\n * history visibility (by default, history visibility is \"shared\" in trees,\n * which is an appropriate visibility for these purposes).\n * @returns Promise which resolves when complete.\n */\n public async invite(userId: string, andSubspaces = true, shareHistoryKeys = true): Promise<void> {\n const promises: Promise<void>[] = [this.retryInvite(userId)];\n if (andSubspaces) {\n promises.push(...this.getDirectories().map((d) => d.invite(userId, andSubspaces, shareHistoryKeys)));\n }\n return Promise.all(promises).then(() => {\n // Note: key sharing is default on because for file trees it is relatively important that the invite\n // target can actually decrypt the files. The implied use case is that by inviting a user to the tree\n // it means the sender would like the receiver to view/download the files contained within, much like\n // sharing a folder in other circles.\n if (shareHistoryKeys && isRoomSharedHistory(this.room)) {\n // noinspection JSIgnoredPromiseFromCall - we aren't concerned as much if this fails.\n this.client.sendSharedHistoryKeys(this.roomId, [userId]);\n }\n });\n }\n\n private retryInvite(userId: string): Promise<void> {\n return simpleRetryOperation(async () => {\n await this.client.invite(this.roomId, userId).catch((e) => {\n // We don't want to retry permission errors forever...\n if (e?.errcode === \"M_FORBIDDEN\") {\n throw new promiseRetry.AbortError(e);\n }\n throw e;\n });\n });\n }\n\n /**\n * Sets the permissions of a user to the given role. Note that if setting a user\n * to Owner then they will NOT be able to be demoted. If the user does not have\n * permission to change the power level of the target, an error will be thrown.\n * @param userId - The user ID to change the role of.\n * @param role - The role to assign.\n * @returns Promise which resolves when complete.\n */\n public async setPermissions(userId: string, role: TreePermissions): Promise<void> {\n const currentPls = this.room.currentState.getStateEvents(EventType.RoomPowerLevels, \"\");\n if (Array.isArray(currentPls)) throw new Error(\"Unexpected return type for power levels\");\n\n const pls = currentPls?.getContent() || {};\n const viewLevel = pls[\"users_default\"] || 0;\n const editLevel = pls[\"events_default\"] || 50;\n const adminLevel = pls[\"events\"]?.[EventType.RoomPowerLevels] || 100;\n\n const users = pls[\"users\"] || {};\n switch (role) {\n case TreePermissions.Viewer:\n users[userId] = viewLevel;\n break;\n case TreePermissions.Editor:\n users[userId] = editLevel;\n break;\n case TreePermissions.Owner:\n users[userId] = adminLevel;\n break;\n default:\n throw new Error(\"Invalid role: \" + role);\n }\n pls[\"users\"] = users;\n\n await this.client.sendStateEvent(this.roomId, EventType.RoomPowerLevels, pls, \"\");\n }\n\n /**\n * Gets the current permissions of a user. Note that any users missing explicit permissions (or not\n * in the space) will be considered Viewers. Appropriate membership checks need to be performed\n * elsewhere.\n * @param userId - The user ID to check permissions of.\n * @returns The permissions for the user, defaulting to Viewer.\n */\n public getPermissions(userId: string): TreePermissions {\n const currentPls = this.room.currentState.getStateEvents(EventType.RoomPowerLevels, \"\");\n if (Array.isArray(currentPls)) throw new Error(\"Unexpected return type for power levels\");\n\n const pls = currentPls?.getContent() || {};\n const viewLevel = pls[\"users_default\"] || 0;\n const editLevel = pls[\"events_default\"] || 50;\n const adminLevel = pls[\"events\"]?.[EventType.RoomPowerLevels] || 100;\n\n const userLevel = pls[\"users\"]?.[userId] || viewLevel;\n if (userLevel >= adminLevel) return TreePermissions.Owner;\n if (userLevel >= editLevel) return TreePermissions.Editor;\n return TreePermissions.Viewer;\n }\n\n /**\n * Creates a directory under this tree space, represented as another tree space.\n * @param name - The name for the directory.\n * @returns Promise which resolves to the created directory.\n */\n public async createDirectory(name: string): Promise<MSC3089TreeSpace> {\n const directory = await this.client.unstableCreateFileTree(name);\n\n await this.client.sendStateEvent(\n this.roomId,\n EventType.SpaceChild,\n {\n via: [this.client.getDomain()],\n },\n directory.roomId,\n );\n\n await this.client.sendStateEvent(\n directory.roomId,\n EventType.SpaceParent,\n {\n via: [this.client.getDomain()],\n },\n this.roomId,\n );\n\n return directory;\n }\n\n /**\n * Gets a list of all known immediate subdirectories to this tree space.\n * @returns The tree spaces (directories). May be empty, but not null.\n */\n public getDirectories(): MSC3089TreeSpace[] {\n const trees: MSC3089TreeSpace[] = [];\n const children = this.room.currentState.getStateEvents(EventType.SpaceChild);\n for (const child of children) {\n try {\n const stateKey = child.getStateKey();\n if (stateKey) {\n const tree = this.client.unstableGetFileTreeSpace(stateKey);\n if (tree) trees.push(tree);\n }\n } catch (e) {\n logger.warn(\"Unable to create tree space instance for listing. Are we joined?\", e);\n }\n }\n return trees;\n }\n\n /**\n * Gets a subdirectory of a given ID under this tree space. Note that this will not recurse\n * into children and instead only look one level deep.\n * @param roomId - The room ID (directory ID) to find.\n * @returns The directory, or undefined if not found.\n */\n public getDirectory(roomId: string): MSC3089TreeSpace | undefined {\n return this.getDirectories().find((r) => r.roomId === roomId);\n }\n\n /**\n * Deletes the tree, kicking all members and deleting **all subdirectories**.\n * @returns Promise which resolves when complete.\n */\n public async delete(): Promise<void> {\n const subdirectories = this.getDirectories();\n for (const dir of subdirectories) {\n await dir.delete();\n }\n\n const kickMemberships = [\"invite\", \"knock\", \"join\"];\n const members = this.room.currentState.getStateEvents(EventType.RoomMember);\n for (const member of members) {\n const isNotUs = member.getStateKey() !== this.client.getUserId();\n if (isNotUs && kickMemberships.includes(member.getContent().membership!)) {\n const stateKey = member.getStateKey();\n if (!stateKey) {\n throw new Error(\"State key not found for branch\");\n }\n await this.client.kick(this.roomId, stateKey, \"Room deleted\");\n }\n }\n\n await this.client.leave(this.roomId);\n }\n\n private getOrderedChildren(children: MatrixEvent[]): { roomId: string; order: string }[] {\n const ordered: { roomId: string; order: string }[] = children\n .map((c) => ({ roomId: c.getStateKey(), order: c.getContent()[\"order\"] }))\n .filter((c) => c.roomId) as { roomId: string; order: string }[];\n ordered.sort((a, b) => {\n if (a.order && !b.order) {\n return -1;\n } else if (!a.order && b.order) {\n return 1;\n } else if (!a.order && !b.order) {\n const roomA = this.client.getRoom(a.roomId);\n const roomB = this.client.getRoom(b.roomId);\n if (!roomA || !roomB) {\n // just don't bother trying to do more partial sorting\n return lexicographicCompare(a.roomId, b.roomId);\n }\n\n const createTsA = roomA.currentState.getStateEvents(EventType.RoomCreate, \"\")?.getTs() ?? 0;\n const createTsB = roomB.currentState.getStateEvents(EventType.RoomCreate, \"\")?.getTs() ?? 0;\n if (createTsA === createTsB) {\n return lexicographicCompare(a.roomId, b.roomId);\n }\n return createTsA - createTsB;\n } else {\n // both not-null orders\n return lexicographicCompare(a.order, b.order);\n }\n });\n return ordered;\n }\n\n private getParentRoom(): Room {\n const parents = this.room.currentState.getStateEvents(EventType.SpaceParent);\n const parent = parents[0]; // XXX: Wild assumption\n if (!parent) throw new Error(\"Expected to have a parent in a non-top level space\");\n\n // XXX: We are assuming the parent is a valid tree space.\n // We probably don't need to validate the parent room state for this usecase though.\n const stateKey = parent.getStateKey();\n if (!stateKey) throw new Error(\"No state key found for parent\");\n const parentRoom = this.client.getRoom(stateKey);\n if (!parentRoom) throw new Error(\"Unable to locate room for parent\");\n\n return parentRoom;\n }\n\n /**\n * Gets the current order index for this directory. Note that if this is the top level space\n * then -1 will be returned.\n * @returns The order index of this space.\n */\n public getOrder(): number {\n if (this.isTopLevel) return -1;\n\n const parentRoom = this.getParentRoom();\n const children = parentRoom.currentState.getStateEvents(EventType.SpaceChild);\n const ordered = this.getOrderedChildren(children);\n\n return ordered.findIndex((c) => c.roomId === this.roomId);\n }\n\n /**\n * Sets the order index for this directory within its parent. Note that if this is a top level\n * space then an error will be thrown. -1 can be used to move the child to the start, and numbers\n * larger than the number of children can be used to move the child to the end.\n * @param index - The new order index for this space.\n * @returns Promise which resolves when complete.\n * @throws Throws if this is a top level space.\n */\n public async setOrder(index: number): Promise<void> {\n if (this.isTopLevel) throw new Error(\"Cannot set order of top level spaces currently\");\n\n const parentRoom = this.getParentRoom();\n const children = parentRoom.currentState.getStateEvents(EventType.SpaceChild);\n const ordered = this.getOrderedChildren(children);\n index = Math.max(Math.min(index, ordered.length - 1), 0);\n\n const currentIndex = this.getOrder();\n const movingUp = currentIndex < index;\n if (movingUp && index === ordered.length - 1) {\n index--;\n } else if (!movingUp && index === 0) {\n index++;\n }\n\n const prev = ordered[movingUp ? index : index - 1];\n const next = ordered[movingUp ? index + 1 : index];\n\n let newOrder = DEFAULT_ALPHABET[0];\n let ensureBeforeIsSane = false;\n if (!prev) {\n // Move to front\n if (next?.order) {\n newOrder = prevString(next.order);\n }\n } else if (index === ordered.length - 1) {\n // Move to back\n if (next?.order) {\n newOrder = nextString(next.order);\n }\n } else {\n // Move somewhere in the middle\n const startOrder = prev?.order;\n const endOrder = next?.order;\n if (startOrder && endOrder) {\n if (startOrder === endOrder) {\n // Error case: just move +1 to break out of awful math\n newOrder = nextString(startOrder);\n } else {\n newOrder = averageBetweenStrings(startOrder, endOrder);\n }\n } else {\n if (startOrder) {\n // We're at the end (endOrder is null, so no explicit order)\n newOrder = nextString(startOrder);\n } else if (endOrder) {\n // We're at the start (startOrder is null, so nothing before us)\n newOrder = prevString(endOrder);\n } else {\n // Both points are unknown. We're likely in a range where all the children\n // don't have particular order values, so we may need to update them too.\n // The other possibility is there's only us as a child, but we should have\n // shown up in the other states.\n ensureBeforeIsSane = true;\n }\n }\n }\n\n if (ensureBeforeIsSane) {\n // We were asked by the order algorithm to prepare the moving space for a landing\n // in the undefined order part of the order array, which means we need to update the\n // spaces that come before it with a stable order value.\n let lastOrder: string | undefined;\n for (let i = 0; i <= index; i++) {\n const target = ordered[i];\n if (i === 0) {\n lastOrder = target.order;\n }\n if (!target.order) {\n // XXX: We should be creating gaps to avoid conflicts\n lastOrder = lastOrder ? nextString(lastOrder) : DEFAULT_ALPHABET[0];\n const currentChild = parentRoom.currentState.getStateEvents(EventType.SpaceChild, target.roomId);\n const content = currentChild?.getContent() ?? { via: [this.client.getDomain()] };\n await this.client.sendStateEvent(\n parentRoom.roomId,\n EventType.SpaceChild,\n {\n ...content,\n order: lastOrder,\n },\n target.roomId,\n );\n } else {\n lastOrder = target.order;\n }\n }\n if (lastOrder) {\n newOrder = nextString(lastOrder);\n }\n }\n\n // TODO: Deal with order conflicts by reordering\n\n // Now we can finally update our own order state\n const currentChild = parentRoom.currentState.getStateEvents(EventType.SpaceChild, this.roomId);\n const content = currentChild?.getContent() ?? { via: [this.client.getDomain()] };\n await this.client.sendStateEvent(\n parentRoom.roomId,\n EventType.SpaceChild,\n {\n ...content,\n\n // TODO: Safely constrain to 50 character limit required by spaces.\n order: newOrder,\n },\n this.roomId,\n );\n }\n\n /**\n * Creates (uploads) a new file to this tree. The file must have already been encrypted for the room.\n * The file contents are in a type that is compatible with MatrixClient.uploadContent().\n * @param name - The name of the file.\n * @param encryptedContents - The encrypted contents.\n * @param info - The encrypted file information.\n * @param additionalContent - Optional event content fields to include in the message.\n * @returns Promise which resolves to the file event's sent response.\n */\n public async createFile(\n name: string,\n encryptedContents: FileType,\n info: Partial<IEncryptedFile>,\n additionalContent?: IContent,\n ): Promise<ISendEventResponse> {\n const { content_uri: mxc } = await this.client.uploadContent(encryptedContents, {\n includeFilename: false,\n });\n info.url = mxc;\n\n const fileContent = {\n msgtype: MsgType.File,\n body: name,\n url: mxc,\n file: info,\n };\n\n additionalContent = additionalContent ?? {};\n if (additionalContent[\"m.new_content\"]) {\n // We do the right thing according to the spec, but due to how relations are\n // handled we also end up duplicating this information to the regular `content`\n // as well.\n additionalContent[\"m.new_content\"] = fileContent;\n }\n\n const res = await this.client.sendMessage(this.roomId, {\n ...additionalContent,\n ...fileContent,\n [UNSTABLE_MSC3089_LEAF.name]: {},\n });\n\n await this.client.sendStateEvent(\n this.roomId,\n UNSTABLE_MSC3089_BRANCH.name,\n {\n active: true,\n name: name,\n },\n res[\"event_id\"],\n );\n\n return res;\n }\n\n /**\n * Retrieves a file from the tree.\n * @param fileEventId - The event ID of the file.\n * @returns The file, or null if not found.\n */\n public getFile(fileEventId: string): MSC3089Branch | null {\n const branch = this.room.currentState.getStateEvents(UNSTABLE_MSC3089_BRANCH.name, fileEventId);\n return branch ? new MSC3089Branch(this.client, branch, this) : null;\n }\n\n /**\n * Gets an array of all known files for the tree.\n * @returns The known files. May be empty, but not null.\n */\n public listFiles(): MSC3089Branch[] {\n return this.listAllFiles().filter((b) => b.isActive);\n }\n\n /**\n * Gets an array of all known files for the tree, including inactive/invalid ones.\n * @returns The known files. May be empty, but not null.\n */\n public listAllFiles(): MSC3089Branch[] {\n const branches = this.room.currentState.getStateEvents(UNSTABLE_MSC3089_BRANCH.name) ?? [];\n return branches.map((e) => new MSC3089Branch(this.client, e, this));\n }\n}\n"],"mappings":"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"} \ No newline at end of file
diff --git a/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/ToDeviceMessage.d.ts b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/ToDeviceMessage.d.ts
new file mode 100644
index 0000000..c5c8761
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/ToDeviceMessage.d.ts
@@ -0,0 +1,17 @@
+export type ToDevicePayload = Record<string, any>;
+export interface ToDeviceMessage {
+ userId: string;
+ deviceId: string;
+ payload: ToDevicePayload;
+}
+export interface ToDeviceBatch {
+ eventType: string;
+ batch: ToDeviceMessage[];
+}
+export interface ToDeviceBatchWithTxnId extends ToDeviceBatch {
+ txnId: string;
+}
+export interface IndexedToDeviceBatch extends ToDeviceBatchWithTxnId {
+ id: number;
+}
+//# sourceMappingURL=ToDeviceMessage.d.ts.map \ No newline at end of file
diff --git a/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/ToDeviceMessage.d.ts.map b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/ToDeviceMessage.d.ts.map
new file mode 100644
index 0000000..4c6f6ed
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/ToDeviceMessage.d.ts.map
@@ -0,0 +1 @@
+{"version":3,"file":"ToDeviceMessage.d.ts","sourceRoot":"","sources":["../../src/models/ToDeviceMessage.ts"],"names":[],"mappings":"AAgBA,MAAM,MAAM,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;AAElD,MAAM,WAAW,eAAe;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,eAAe,CAAC;CAC5B;AAED,MAAM,WAAW,aAAa;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,eAAe,EAAE,CAAC;CAC5B;AAGD,MAAM,WAAW,sBAAuB,SAAQ,aAAa;IACzD,KAAK,EAAE,MAAM,CAAC;CACjB;AAGD,MAAM,WAAW,oBAAqB,SAAQ,sBAAsB;IAChE,EAAE,EAAE,MAAM,CAAC;CACd"} \ No newline at end of file
diff --git a/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/ToDeviceMessage.js b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/ToDeviceMessage.js
new file mode 100644
index 0000000..d383c67
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/ToDeviceMessage.js
@@ -0,0 +1,6 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+//# sourceMappingURL=ToDeviceMessage.js.map \ No newline at end of file
diff --git a/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/ToDeviceMessage.js.map b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/ToDeviceMessage.js.map
new file mode 100644
index 0000000..986f7f5
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/ToDeviceMessage.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"ToDeviceMessage.js","names":[],"sources":["../../src/models/ToDeviceMessage.ts"],"sourcesContent":["/*\nCopyright 2022 The Matrix.org Foundation C.I.C.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n*/\n\nexport type ToDevicePayload = Record<string, any>;\n\nexport interface ToDeviceMessage {\n userId: string;\n deviceId: string;\n payload: ToDevicePayload;\n}\n\nexport interface ToDeviceBatch {\n eventType: string;\n batch: ToDeviceMessage[];\n}\n\n// Only used internally\nexport interface ToDeviceBatchWithTxnId extends ToDeviceBatch {\n txnId: string;\n}\n\n// Only used internally\nexport interface IndexedToDeviceBatch extends ToDeviceBatchWithTxnId {\n id: number;\n}\n"],"mappings":""} \ No newline at end of file
diff --git a/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/beacon.d.ts b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/beacon.d.ts
new file mode 100644
index 0000000..3a6918c
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/beacon.d.ts
@@ -0,0 +1,53 @@
+import { BeaconInfoState, BeaconLocationState } from "../content-helpers";
+import { MatrixEvent } from "./event";
+import { TypedEventEmitter } from "./typed-event-emitter";
+export declare enum BeaconEvent {
+ New = "Beacon.new",
+ Update = "Beacon.update",
+ LivenessChange = "Beacon.LivenessChange",
+ Destroy = "Beacon.Destroy",
+ LocationUpdate = "Beacon.LocationUpdate"
+}
+export type BeaconEventHandlerMap = {
+ [BeaconEvent.Update]: (event: MatrixEvent, beacon: Beacon) => void;
+ [BeaconEvent.LivenessChange]: (isLive: boolean, beacon: Beacon) => void;
+ [BeaconEvent.Destroy]: (beaconIdentifier: string) => void;
+ [BeaconEvent.LocationUpdate]: (locationState: BeaconLocationState) => void;
+ [BeaconEvent.Destroy]: (beaconIdentifier: string) => void;
+};
+export declare const isTimestampInDuration: (startTimestamp: number, durationMs: number, timestamp: number) => boolean;
+export type BeaconIdentifier = string;
+export declare const getBeaconInfoIdentifier: (event: MatrixEvent) => BeaconIdentifier;
+export declare class Beacon extends TypedEventEmitter<Exclude<BeaconEvent, BeaconEvent.New>, BeaconEventHandlerMap> {
+ private rootEvent;
+ readonly roomId: string;
+ private _beaconInfo;
+ private _isLive?;
+ private livenessWatchTimeout?;
+ private _latestLocationEvent?;
+ constructor(rootEvent: MatrixEvent);
+ get isLive(): boolean;
+ get identifier(): BeaconIdentifier;
+ get beaconInfoId(): string;
+ get beaconInfoOwner(): string;
+ get beaconInfoEventType(): string;
+ get beaconInfo(): BeaconInfoState;
+ get latestLocationState(): BeaconLocationState | undefined;
+ get latestLocationEvent(): MatrixEvent | undefined;
+ update(beaconInfoEvent: MatrixEvent): void;
+ destroy(): void;
+ /**
+ * Monitor liveness of a beacon
+ * Emits BeaconEvent.LivenessChange when beacon expires
+ */
+ monitorLiveness(): void;
+ /**
+ * Process Beacon locations
+ * Emits BeaconEvent.LocationUpdate
+ */
+ addLocations(beaconLocationEvents: MatrixEvent[]): void;
+ private clearLatestLocation;
+ private setBeaconInfo;
+ private checkLiveness;
+}
+//# sourceMappingURL=beacon.d.ts.map \ No newline at end of file
diff --git a/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/beacon.d.ts.map b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/beacon.d.ts.map
new file mode 100644
index 0000000..1d7253b
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/beacon.d.ts.map
@@ -0,0 +1 @@
+{"version":3,"file":"beacon.d.ts","sourceRoot":"","sources":["../../src/models/beacon.ts"],"names":[],"mappings":"AAiBA,OAAO,EAAE,eAAe,EAAE,mBAAmB,EAA8C,MAAM,oBAAoB,CAAC;AACtH,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAEtC,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAE1D,oBAAY,WAAW;IACnB,GAAG,eAAe;IAClB,MAAM,kBAAkB;IACxB,cAAc,0BAA0B;IACxC,OAAO,mBAAmB;IAC1B,cAAc,0BAA0B;CAC3C;AAED,MAAM,MAAM,qBAAqB,GAAG;IAChC,CAAC,WAAW,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACnE,CAAC,WAAW,CAAC,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACxE,CAAC,WAAW,CAAC,OAAO,CAAC,EAAE,CAAC,gBAAgB,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1D,CAAC,WAAW,CAAC,cAAc,CAAC,EAAE,CAAC,aAAa,EAAE,mBAAmB,KAAK,IAAI,CAAC;IAC3E,CAAC,WAAW,CAAC,OAAO,CAAC,EAAE,CAAC,gBAAgB,EAAE,MAAM,KAAK,IAAI,CAAC;CAC7D,CAAC;AAEF,eAAO,MAAM,qBAAqB,mBAAoB,MAAM,cAAc,MAAM,aAAa,MAAM,KAAG,OAC3B,CAAC;AAI5E,MAAM,MAAM,gBAAgB,GAAG,MAAM,CAAC;AACtC,eAAO,MAAM,uBAAuB,UAAW,WAAW,KAAG,gBACZ,CAAC;AAGlD,qBAAa,MAAO,SAAQ,iBAAiB,CAAC,OAAO,CAAC,WAAW,EAAE,WAAW,CAAC,GAAG,CAAC,EAAE,qBAAqB,CAAC;IASpF,OAAO,CAAC,SAAS;IARpC,SAAgB,MAAM,EAAE,MAAM,CAAC;IAG/B,OAAO,CAAC,WAAW,CAAmB;IACtC,OAAO,CAAC,OAAO,CAAC,CAAU;IAC1B,OAAO,CAAC,oBAAoB,CAAC,CAAgC;IAC7D,OAAO,CAAC,oBAAoB,CAAC,CAAc;gBAEhB,SAAS,EAAE,WAAW;IAMjD,IAAW,MAAM,IAAI,OAAO,CAE3B;IAED,IAAW,UAAU,IAAI,gBAAgB,CAExC;IAED,IAAW,YAAY,IAAI,MAAM,CAEhC;IAED,IAAW,eAAe,IAAI,MAAM,CAEnC;IAED,IAAW,mBAAmB,IAAI,MAAM,CAEvC;IAED,IAAW,UAAU,IAAI,eAAe,CAEvC;IAED,IAAW,mBAAmB,IAAI,mBAAmB,GAAG,SAAS,CAEhE;IAED,IAAW,mBAAmB,IAAI,WAAW,GAAG,SAAS,CAExD;IAEM,MAAM,CAAC,eAAe,EAAE,WAAW,GAAG,IAAI;IAe1C,OAAO,IAAI,IAAI;IAStB;;;OAGG;IACI,eAAe,IAAI,IAAI;IAuB9B;;;OAGG;IACI,YAAY,CAAC,oBAAoB,EAAE,WAAW,EAAE,GAAG,IAAI;IA2B9D,OAAO,CAAC,mBAAmB,CAGzB;IAEF,OAAO,CAAC,aAAa;IAKrB,OAAO,CAAC,aAAa;CAqBxB"} \ No newline at end of file
diff --git a/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/beacon.js b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/beacon.js
new file mode 100644
index 0000000..93a226d
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/beacon.js
@@ -0,0 +1,184 @@
+"use strict";
+
+var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.isTimestampInDuration = exports.getBeaconInfoIdentifier = exports.BeaconEvent = exports.Beacon = void 0;
+var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
+var _contentHelpers = require("../content-helpers");
+var _utils = require("../utils");
+var _typedEventEmitter = require("./typed-event-emitter");
+/*
+Copyright 2022 The Matrix.org Foundation C.I.C.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+let BeaconEvent;
+exports.BeaconEvent = BeaconEvent;
+(function (BeaconEvent) {
+ BeaconEvent["New"] = "Beacon.new";
+ BeaconEvent["Update"] = "Beacon.update";
+ BeaconEvent["LivenessChange"] = "Beacon.LivenessChange";
+ BeaconEvent["Destroy"] = "Beacon.Destroy";
+ BeaconEvent["LocationUpdate"] = "Beacon.LocationUpdate";
+})(BeaconEvent || (exports.BeaconEvent = BeaconEvent = {}));
+const isTimestampInDuration = (startTimestamp, durationMs, timestamp) => timestamp >= startTimestamp && startTimestamp + durationMs >= timestamp;
+
+// beacon info events are uniquely identified by
+// `<roomId>_<state_key>`
+exports.isTimestampInDuration = isTimestampInDuration;
+const getBeaconInfoIdentifier = event => `${event.getRoomId()}_${event.getStateKey()}`;
+
+// https://github.com/matrix-org/matrix-spec-proposals/pull/3672
+exports.getBeaconInfoIdentifier = getBeaconInfoIdentifier;
+class Beacon extends _typedEventEmitter.TypedEventEmitter {
+ // beaconInfo is assigned by setBeaconInfo in the constructor
+ // ! to make tsc believe it is definitely assigned
+
+ constructor(rootEvent) {
+ super();
+ this.rootEvent = rootEvent;
+ (0, _defineProperty2.default)(this, "roomId", void 0);
+ (0, _defineProperty2.default)(this, "_beaconInfo", void 0);
+ (0, _defineProperty2.default)(this, "_isLive", void 0);
+ (0, _defineProperty2.default)(this, "livenessWatchTimeout", void 0);
+ (0, _defineProperty2.default)(this, "_latestLocationEvent", void 0);
+ (0, _defineProperty2.default)(this, "clearLatestLocation", () => {
+ this._latestLocationEvent = undefined;
+ this.emit(BeaconEvent.LocationUpdate, this.latestLocationState);
+ });
+ this.roomId = this.rootEvent.getRoomId();
+ this.setBeaconInfo(this.rootEvent);
+ }
+ get isLive() {
+ return !!this._isLive;
+ }
+ get identifier() {
+ return getBeaconInfoIdentifier(this.rootEvent);
+ }
+ get beaconInfoId() {
+ return this.rootEvent.getId();
+ }
+ get beaconInfoOwner() {
+ return this.rootEvent.getStateKey();
+ }
+ get beaconInfoEventType() {
+ return this.rootEvent.getType();
+ }
+ get beaconInfo() {
+ return this._beaconInfo;
+ }
+ get latestLocationState() {
+ return this._latestLocationEvent && (0, _contentHelpers.parseBeaconContent)(this._latestLocationEvent.getContent());
+ }
+ get latestLocationEvent() {
+ return this._latestLocationEvent;
+ }
+ update(beaconInfoEvent) {
+ if (getBeaconInfoIdentifier(beaconInfoEvent) !== this.identifier) {
+ throw new Error("Invalid updating event");
+ }
+ // don't update beacon with an older event
+ if (beaconInfoEvent.getTs() < this.rootEvent.getTs()) {
+ return;
+ }
+ this.rootEvent = beaconInfoEvent;
+ this.setBeaconInfo(this.rootEvent);
+ this.emit(BeaconEvent.Update, beaconInfoEvent, this);
+ this.clearLatestLocation();
+ }
+ destroy() {
+ if (this.livenessWatchTimeout) {
+ clearTimeout(this.livenessWatchTimeout);
+ }
+ this._isLive = false;
+ this.emit(BeaconEvent.Destroy, this.identifier);
+ }
+
+ /**
+ * Monitor liveness of a beacon
+ * Emits BeaconEvent.LivenessChange when beacon expires
+ */
+ monitorLiveness() {
+ if (this.livenessWatchTimeout) {
+ clearTimeout(this.livenessWatchTimeout);
+ }
+ this.checkLiveness();
+ if (!this.beaconInfo) return;
+ if (this.isLive) {
+ const expiryInMs = this.beaconInfo.timestamp + this.beaconInfo.timeout - Date.now();
+ if (expiryInMs > 1) {
+ this.livenessWatchTimeout = setTimeout(() => {
+ this.monitorLiveness();
+ }, expiryInMs);
+ }
+ } else if (this.beaconInfo.timestamp > Date.now()) {
+ // beacon start timestamp is in the future
+ // check liveness again then
+ this.livenessWatchTimeout = setTimeout(() => {
+ this.monitorLiveness();
+ }, this.beaconInfo.timestamp - Date.now());
+ }
+ }
+
+ /**
+ * Process Beacon locations
+ * Emits BeaconEvent.LocationUpdate
+ */
+ addLocations(beaconLocationEvents) {
+ var _validLocationEvents$;
+ // discard locations for beacons that are not live
+ if (!this.isLive) {
+ return;
+ }
+ const validLocationEvents = beaconLocationEvents.filter(event => {
+ const content = event.getContent();
+ const parsed = (0, _contentHelpers.parseBeaconContent)(content);
+ if (!parsed.uri || !parsed.timestamp) return false; // we won't be able to process these
+ const {
+ timestamp
+ } = parsed;
+ return this._beaconInfo.timestamp &&
+ // only include positions that were taken inside the beacon's live period
+ isTimestampInDuration(this._beaconInfo.timestamp, this._beaconInfo.timeout, timestamp) && (
+ // ignore positions older than our current latest location
+ !this.latestLocationState || timestamp > this.latestLocationState.timestamp);
+ });
+ const latestLocationEvent = (_validLocationEvents$ = validLocationEvents.sort(_utils.sortEventsByLatestContentTimestamp)) === null || _validLocationEvents$ === void 0 ? void 0 : _validLocationEvents$[0];
+ if (latestLocationEvent) {
+ this._latestLocationEvent = latestLocationEvent;
+ this.emit(BeaconEvent.LocationUpdate, this.latestLocationState);
+ }
+ }
+ setBeaconInfo(event) {
+ this._beaconInfo = (0, _contentHelpers.parseBeaconInfoContent)(event.getContent());
+ this.checkLiveness();
+ }
+ checkLiveness() {
+ const prevLiveness = this.isLive;
+
+ // element web sets a beacon's start timestamp to the senders local current time
+ // when Alice's system clock deviates slightly from Bob's a beacon Alice intended to be live
+ // may have a start timestamp in the future from Bob's POV
+ // handle this by adding 6min of leniency to the start timestamp when it is in the future
+ if (!this.beaconInfo) return;
+ const startTimestamp = this.beaconInfo.timestamp > Date.now() ? this.beaconInfo.timestamp - 360000 /* 6min */ : this.beaconInfo.timestamp;
+ this._isLive = !!this._beaconInfo.live && !!startTimestamp && isTimestampInDuration(startTimestamp, this._beaconInfo.timeout, Date.now());
+ if (prevLiveness !== this.isLive) {
+ this.emit(BeaconEvent.LivenessChange, this.isLive, this);
+ }
+ }
+}
+exports.Beacon = Beacon;
+//# sourceMappingURL=beacon.js.map \ No newline at end of file
diff --git a/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/beacon.js.map b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/beacon.js.map
new file mode 100644
index 0000000..15062fb
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/beacon.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"beacon.js","names":["_contentHelpers","require","_utils","_typedEventEmitter","BeaconEvent","exports","isTimestampInDuration","startTimestamp","durationMs","timestamp","getBeaconInfoIdentifier","event","getRoomId","getStateKey","Beacon","TypedEventEmitter","constructor","rootEvent","_defineProperty2","default","_latestLocationEvent","undefined","emit","LocationUpdate","latestLocationState","roomId","setBeaconInfo","isLive","_isLive","identifier","beaconInfoId","getId","beaconInfoOwner","beaconInfoEventType","getType","beaconInfo","_beaconInfo","parseBeaconContent","getContent","latestLocationEvent","update","beaconInfoEvent","Error","getTs","Update","clearLatestLocation","destroy","livenessWatchTimeout","clearTimeout","Destroy","monitorLiveness","checkLiveness","expiryInMs","timeout","Date","now","setTimeout","addLocations","beaconLocationEvents","_validLocationEvents$","validLocationEvents","filter","content","parsed","uri","sort","sortEventsByLatestContentTimestamp","parseBeaconInfoContent","prevLiveness","live","LivenessChange"],"sources":["../../src/models/beacon.ts"],"sourcesContent":["/*\nCopyright 2022 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 { MBeaconEventContent } from \"../@types/beacon\";\nimport { BeaconInfoState, BeaconLocationState, parseBeaconContent, parseBeaconInfoContent } from \"../content-helpers\";\nimport { MatrixEvent } from \"./event\";\nimport { sortEventsByLatestContentTimestamp } from \"../utils\";\nimport { TypedEventEmitter } from \"./typed-event-emitter\";\n\nexport enum BeaconEvent {\n New = \"Beacon.new\",\n Update = \"Beacon.update\",\n LivenessChange = \"Beacon.LivenessChange\",\n Destroy = \"Beacon.Destroy\",\n LocationUpdate = \"Beacon.LocationUpdate\",\n}\n\nexport type BeaconEventHandlerMap = {\n [BeaconEvent.Update]: (event: MatrixEvent, beacon: Beacon) => void;\n [BeaconEvent.LivenessChange]: (isLive: boolean, beacon: Beacon) => void;\n [BeaconEvent.Destroy]: (beaconIdentifier: string) => void;\n [BeaconEvent.LocationUpdate]: (locationState: BeaconLocationState) => void;\n [BeaconEvent.Destroy]: (beaconIdentifier: string) => void;\n};\n\nexport const isTimestampInDuration = (startTimestamp: number, durationMs: number, timestamp: number): boolean =>\n timestamp >= startTimestamp && startTimestamp + durationMs >= timestamp;\n\n// beacon info events are uniquely identified by\n// `<roomId>_<state_key>`\nexport type BeaconIdentifier = string;\nexport const getBeaconInfoIdentifier = (event: MatrixEvent): BeaconIdentifier =>\n `${event.getRoomId()}_${event.getStateKey()}`;\n\n// https://github.com/matrix-org/matrix-spec-proposals/pull/3672\nexport class Beacon extends TypedEventEmitter<Exclude<BeaconEvent, BeaconEvent.New>, BeaconEventHandlerMap> {\n public readonly roomId: string;\n // beaconInfo is assigned by setBeaconInfo in the constructor\n // ! to make tsc believe it is definitely assigned\n private _beaconInfo!: BeaconInfoState;\n private _isLive?: boolean;\n private livenessWatchTimeout?: ReturnType<typeof setTimeout>;\n private _latestLocationEvent?: MatrixEvent;\n\n public constructor(private rootEvent: MatrixEvent) {\n super();\n this.roomId = this.rootEvent.getRoomId()!;\n this.setBeaconInfo(this.rootEvent);\n }\n\n public get isLive(): boolean {\n return !!this._isLive;\n }\n\n public get identifier(): BeaconIdentifier {\n return getBeaconInfoIdentifier(this.rootEvent);\n }\n\n public get beaconInfoId(): string {\n return this.rootEvent.getId()!;\n }\n\n public get beaconInfoOwner(): string {\n return this.rootEvent.getStateKey()!;\n }\n\n public get beaconInfoEventType(): string {\n return this.rootEvent.getType();\n }\n\n public get beaconInfo(): BeaconInfoState {\n return this._beaconInfo;\n }\n\n public get latestLocationState(): BeaconLocationState | undefined {\n return this._latestLocationEvent && parseBeaconContent(this._latestLocationEvent.getContent());\n }\n\n public get latestLocationEvent(): MatrixEvent | undefined {\n return this._latestLocationEvent;\n }\n\n public update(beaconInfoEvent: MatrixEvent): void {\n if (getBeaconInfoIdentifier(beaconInfoEvent) !== this.identifier) {\n throw new Error(\"Invalid updating event\");\n }\n // don't update beacon with an older event\n if (beaconInfoEvent.getTs() < this.rootEvent.getTs()) {\n return;\n }\n this.rootEvent = beaconInfoEvent;\n this.setBeaconInfo(this.rootEvent);\n\n this.emit(BeaconEvent.Update, beaconInfoEvent, this);\n this.clearLatestLocation();\n }\n\n public destroy(): void {\n if (this.livenessWatchTimeout) {\n clearTimeout(this.livenessWatchTimeout);\n }\n\n this._isLive = false;\n this.emit(BeaconEvent.Destroy, this.identifier);\n }\n\n /**\n * Monitor liveness of a beacon\n * Emits BeaconEvent.LivenessChange when beacon expires\n */\n public monitorLiveness(): void {\n if (this.livenessWatchTimeout) {\n clearTimeout(this.livenessWatchTimeout);\n }\n\n this.checkLiveness();\n if (!this.beaconInfo) return;\n if (this.isLive) {\n const expiryInMs = this.beaconInfo.timestamp! + this.beaconInfo.timeout - Date.now();\n if (expiryInMs > 1) {\n this.livenessWatchTimeout = setTimeout(() => {\n this.monitorLiveness();\n }, expiryInMs);\n }\n } else if (this.beaconInfo.timestamp! > Date.now()) {\n // beacon start timestamp is in the future\n // check liveness again then\n this.livenessWatchTimeout = setTimeout(() => {\n this.monitorLiveness();\n }, this.beaconInfo.timestamp! - Date.now());\n }\n }\n\n /**\n * Process Beacon locations\n * Emits BeaconEvent.LocationUpdate\n */\n public addLocations(beaconLocationEvents: MatrixEvent[]): void {\n // discard locations for beacons that are not live\n if (!this.isLive) {\n return;\n }\n\n const validLocationEvents = beaconLocationEvents.filter((event) => {\n const content = event.getContent<MBeaconEventContent>();\n const parsed = parseBeaconContent(content);\n if (!parsed.uri || !parsed.timestamp) return false; // we won't be able to process these\n const { timestamp } = parsed;\n return (\n this._beaconInfo.timestamp &&\n // only include positions that were taken inside the beacon's live period\n isTimestampInDuration(this._beaconInfo.timestamp, this._beaconInfo.timeout, timestamp) &&\n // ignore positions older than our current latest location\n (!this.latestLocationState || timestamp > this.latestLocationState.timestamp!)\n );\n });\n const latestLocationEvent = validLocationEvents.sort(sortEventsByLatestContentTimestamp)?.[0];\n\n if (latestLocationEvent) {\n this._latestLocationEvent = latestLocationEvent;\n this.emit(BeaconEvent.LocationUpdate, this.latestLocationState!);\n }\n }\n\n private clearLatestLocation = (): void => {\n this._latestLocationEvent = undefined;\n this.emit(BeaconEvent.LocationUpdate, this.latestLocationState!);\n };\n\n private setBeaconInfo(event: MatrixEvent): void {\n this._beaconInfo = parseBeaconInfoContent(event.getContent());\n this.checkLiveness();\n }\n\n private checkLiveness(): void {\n const prevLiveness = this.isLive;\n\n // element web sets a beacon's start timestamp to the senders local current time\n // when Alice's system clock deviates slightly from Bob's a beacon Alice intended to be live\n // may have a start timestamp in the future from Bob's POV\n // handle this by adding 6min of leniency to the start timestamp when it is in the future\n if (!this.beaconInfo) return;\n const startTimestamp =\n this.beaconInfo.timestamp! > Date.now()\n ? this.beaconInfo.timestamp! - 360000 /* 6min */\n : this.beaconInfo.timestamp;\n this._isLive =\n !!this._beaconInfo.live &&\n !!startTimestamp &&\n isTimestampInDuration(startTimestamp, this._beaconInfo.timeout, Date.now());\n\n if (prevLiveness !== this.isLive) {\n this.emit(BeaconEvent.LivenessChange, this.isLive, this);\n }\n }\n}\n"],"mappings":"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"} \ No newline at end of file
diff --git a/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/event-context.d.ts b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/event-context.d.ts
new file mode 100644
index 0000000..2b5b748
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/event-context.d.ts
@@ -0,0 +1,62 @@
+import { MatrixEvent } from "./event";
+export declare class EventContext {
+ readonly ourEvent: MatrixEvent;
+ private timeline;
+ private ourEventIndex;
+ private paginateTokens;
+ /**
+ * Construct a new EventContext
+ *
+ * An eventcontext is used for circumstances such as search results, when we
+ * have a particular event of interest, and a bunch of events before and after
+ * it.
+ *
+ * It also stores pagination tokens for going backwards and forwards in the
+ * timeline.
+ *
+ * @param ourEvent - the event at the centre of this context
+ */
+ constructor(ourEvent: MatrixEvent);
+ /**
+ * Get the main event of interest
+ *
+ * This is a convenience function for getTimeline()[getOurEventIndex()].
+ *
+ * @returns The event at the centre of this context.
+ */
+ getEvent(): MatrixEvent;
+ /**
+ * Get the list of events in this context
+ *
+ * @returns An array of MatrixEvents
+ */
+ getTimeline(): MatrixEvent[];
+ /**
+ * Get the index in the timeline of our event
+ */
+ getOurEventIndex(): number;
+ /**
+ * Get a pagination token.
+ *
+ * @param backwards - true to get the pagination token for going
+ */
+ getPaginateToken(backwards?: boolean): string | null;
+ /**
+ * Set a pagination token.
+ *
+ * Generally this will be used only by the matrix js sdk.
+ *
+ * @param token - pagination token
+ * @param backwards - true to set the pagination token for going
+ * backwards in time
+ */
+ setPaginateToken(token?: string, backwards?: boolean): void;
+ /**
+ * Add more events to the timeline
+ *
+ * @param events - new events, in timeline order
+ * @param atStart - true to insert new events at the start
+ */
+ addEvents(events: MatrixEvent[], atStart?: boolean): void;
+}
+//# sourceMappingURL=event-context.d.ts.map \ No newline at end of file
diff --git a/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/event-context.d.ts.map b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/event-context.d.ts.map
new file mode 100644
index 0000000..7186ddf
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/event-context.d.ts.map
@@ -0,0 +1 @@
+{"version":3,"file":"event-context.d.ts","sourceRoot":"","sources":["../../src/models/event-context.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAGtC,qBAAa,YAAY;aAoBc,QAAQ,EAAE,WAAW;IAnBxD,OAAO,CAAC,QAAQ,CAAgB;IAChC,OAAO,CAAC,aAAa,CAAK;IAC1B,OAAO,CAAC,cAAc,CAGpB;IAEF;;;;;;;;;;;OAWG;gBACgC,QAAQ,EAAE,WAAW;IAIxD;;;;;;OAMG;IACI,QAAQ,IAAI,WAAW;IAI9B;;;;OAIG;IACI,WAAW,IAAI,WAAW,EAAE;IAInC;;OAEG;IACI,gBAAgB,IAAI,MAAM;IAIjC;;;;OAIG;IACI,gBAAgB,CAAC,SAAS,UAAQ,GAAG,MAAM,GAAG,IAAI;IAIzD;;;;;;;;OAQG;IACI,gBAAgB,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,SAAS,UAAQ,GAAG,IAAI;IAIhE;;;;;OAKG;IACI,SAAS,CAAC,MAAM,EAAE,WAAW,EAAE,EAAE,OAAO,UAAQ,GAAG,IAAI;CAWjE"} \ No newline at end of file
diff --git a/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/event-context.js b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/event-context.js
new file mode 100644
index 0000000..a6f5ca9
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/event-context.js
@@ -0,0 +1,118 @@
+"use strict";
+
+var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.EventContext = void 0;
+var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
+var _eventTimeline = require("./event-timeline");
+/*
+Copyright 2015 - 2021 The Matrix.org Foundation C.I.C.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+class EventContext {
+ /**
+ * Construct a new EventContext
+ *
+ * An eventcontext is used for circumstances such as search results, when we
+ * have a particular event of interest, and a bunch of events before and after
+ * it.
+ *
+ * It also stores pagination tokens for going backwards and forwards in the
+ * timeline.
+ *
+ * @param ourEvent - the event at the centre of this context
+ */
+ constructor(ourEvent) {
+ this.ourEvent = ourEvent;
+ (0, _defineProperty2.default)(this, "timeline", void 0);
+ (0, _defineProperty2.default)(this, "ourEventIndex", 0);
+ (0, _defineProperty2.default)(this, "paginateTokens", {
+ [_eventTimeline.Direction.Backward]: null,
+ [_eventTimeline.Direction.Forward]: null
+ });
+ this.timeline = [ourEvent];
+ }
+
+ /**
+ * Get the main event of interest
+ *
+ * This is a convenience function for getTimeline()[getOurEventIndex()].
+ *
+ * @returns The event at the centre of this context.
+ */
+ getEvent() {
+ return this.timeline[this.ourEventIndex];
+ }
+
+ /**
+ * Get the list of events in this context
+ *
+ * @returns An array of MatrixEvents
+ */
+ getTimeline() {
+ return this.timeline;
+ }
+
+ /**
+ * Get the index in the timeline of our event
+ */
+ getOurEventIndex() {
+ return this.ourEventIndex;
+ }
+
+ /**
+ * Get a pagination token.
+ *
+ * @param backwards - true to get the pagination token for going
+ */
+ getPaginateToken(backwards = false) {
+ return this.paginateTokens[backwards ? _eventTimeline.Direction.Backward : _eventTimeline.Direction.Forward];
+ }
+
+ /**
+ * Set a pagination token.
+ *
+ * Generally this will be used only by the matrix js sdk.
+ *
+ * @param token - pagination token
+ * @param backwards - true to set the pagination token for going
+ * backwards in time
+ */
+ setPaginateToken(token, backwards = false) {
+ this.paginateTokens[backwards ? _eventTimeline.Direction.Backward : _eventTimeline.Direction.Forward] = token !== null && token !== void 0 ? token : null;
+ }
+
+ /**
+ * Add more events to the timeline
+ *
+ * @param events - new events, in timeline order
+ * @param atStart - true to insert new events at the start
+ */
+ addEvents(events, atStart = false) {
+ // TODO: should we share logic with Room.addEventsToTimeline?
+ // Should Room even use EventContext?
+
+ if (atStart) {
+ this.timeline = events.concat(this.timeline);
+ this.ourEventIndex += events.length;
+ } else {
+ this.timeline = this.timeline.concat(events);
+ }
+ }
+}
+exports.EventContext = EventContext;
+//# sourceMappingURL=event-context.js.map \ No newline at end of file
diff --git a/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/event-context.js.map b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/event-context.js.map
new file mode 100644
index 0000000..17df5b8
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/event-context.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"event-context.js","names":["_eventTimeline","require","EventContext","constructor","ourEvent","_defineProperty2","default","Direction","Backward","Forward","timeline","getEvent","ourEventIndex","getTimeline","getOurEventIndex","getPaginateToken","backwards","paginateTokens","setPaginateToken","token","addEvents","events","atStart","concat","length","exports"],"sources":["../../src/models/event-context.ts"],"sourcesContent":["/*\nCopyright 2015 - 2021 The Matrix.org Foundation C.I.C.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n*/\n\nimport { MatrixEvent } from \"./event\";\nimport { Direction } from \"./event-timeline\";\n\nexport class EventContext {\n private timeline: MatrixEvent[];\n private ourEventIndex = 0;\n private paginateTokens: Record<Direction, string | null> = {\n [Direction.Backward]: null,\n [Direction.Forward]: null,\n };\n\n /**\n * Construct a new EventContext\n *\n * An eventcontext is used for circumstances such as search results, when we\n * have a particular event of interest, and a bunch of events before and after\n * it.\n *\n * It also stores pagination tokens for going backwards and forwards in the\n * timeline.\n *\n * @param ourEvent - the event at the centre of this context\n */\n public constructor(public readonly ourEvent: MatrixEvent) {\n this.timeline = [ourEvent];\n }\n\n /**\n * Get the main event of interest\n *\n * This is a convenience function for getTimeline()[getOurEventIndex()].\n *\n * @returns The event at the centre of this context.\n */\n public getEvent(): MatrixEvent {\n return this.timeline[this.ourEventIndex];\n }\n\n /**\n * Get the list of events in this context\n *\n * @returns An array of MatrixEvents\n */\n public getTimeline(): MatrixEvent[] {\n return this.timeline;\n }\n\n /**\n * Get the index in the timeline of our event\n */\n public getOurEventIndex(): number {\n return this.ourEventIndex;\n }\n\n /**\n * Get a pagination token.\n *\n * @param backwards - true to get the pagination token for going\n */\n public getPaginateToken(backwards = false): string | null {\n return this.paginateTokens[backwards ? Direction.Backward : Direction.Forward];\n }\n\n /**\n * Set a pagination token.\n *\n * Generally this will be used only by the matrix js sdk.\n *\n * @param token - pagination token\n * @param backwards - true to set the pagination token for going\n * backwards in time\n */\n public setPaginateToken(token?: string, backwards = false): void {\n this.paginateTokens[backwards ? Direction.Backward : Direction.Forward] = token ?? null;\n }\n\n /**\n * Add more events to the timeline\n *\n * @param events - new events, in timeline order\n * @param atStart - true to insert new events at the start\n */\n public addEvents(events: MatrixEvent[], atStart = false): void {\n // TODO: should we share logic with Room.addEventsToTimeline?\n // Should Room even use EventContext?\n\n if (atStart) {\n this.timeline = events.concat(this.timeline);\n this.ourEventIndex += events.length;\n } else {\n this.timeline = this.timeline.concat(events);\n }\n }\n}\n"],"mappings":";;;;;;;;AAiBA,IAAAA,cAAA,GAAAC,OAAA;AAjBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAKO,MAAMC,YAAY,CAAC;EAQtB;AACJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;EACWC,WAAWA,CAAiBC,QAAqB,EAAE;IAAA,KAAvBA,QAAqB,GAArBA,QAAqB;IAAA,IAAAC,gBAAA,CAAAC,OAAA;IAAA,IAAAD,gBAAA,CAAAC,OAAA,yBAlBhC,CAAC;IAAA,IAAAD,gBAAA,CAAAC,OAAA,0BACkC;MACvD,CAACC,wBAAS,CAACC,QAAQ,GAAG,IAAI;MAC1B,CAACD,wBAAS,CAACE,OAAO,GAAG;IACzB,CAAC;IAeG,IAAI,CAACC,QAAQ,GAAG,CAACN,QAAQ,CAAC;EAC9B;;EAEA;AACJ;AACA;AACA;AACA;AACA;AACA;EACWO,QAAQA,CAAA,EAAgB;IAC3B,OAAO,IAAI,CAACD,QAAQ,CAAC,IAAI,CAACE,aAAa,CAAC;EAC5C;;EAEA;AACJ;AACA;AACA;AACA;EACWC,WAAWA,CAAA,EAAkB;IAChC,OAAO,IAAI,CAACH,QAAQ;EACxB;;EAEA;AACJ;AACA;EACWI,gBAAgBA,CAAA,EAAW;IAC9B,OAAO,IAAI,CAACF,aAAa;EAC7B;;EAEA;AACJ;AACA;AACA;AACA;EACWG,gBAAgBA,CAACC,SAAS,GAAG,KAAK,EAAiB;IACtD,OAAO,IAAI,CAACC,cAAc,CAACD,SAAS,GAAGT,wBAAS,CAACC,QAAQ,GAAGD,wBAAS,CAACE,OAAO,CAAC;EAClF;;EAEA;AACJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;EACWS,gBAAgBA,CAACC,KAAc,EAAEH,SAAS,GAAG,KAAK,EAAQ;IAC7D,IAAI,CAACC,cAAc,CAACD,SAAS,GAAGT,wBAAS,CAACC,QAAQ,GAAGD,wBAAS,CAACE,OAAO,CAAC,GAAGU,KAAK,aAALA,KAAK,cAALA,KAAK,GAAI,IAAI;EAC3F;;EAEA;AACJ;AACA;AACA;AACA;AACA;EACWC,SAASA,CAACC,MAAqB,EAAEC,OAAO,GAAG,KAAK,EAAQ;IAC3D;IACA;;IAEA,IAAIA,OAAO,EAAE;MACT,IAAI,CAACZ,QAAQ,GAAGW,MAAM,CAACE,MAAM,CAAC,IAAI,CAACb,QAAQ,CAAC;MAC5C,IAAI,CAACE,aAAa,IAAIS,MAAM,CAACG,MAAM;IACvC,CAAC,MAAM;MACH,IAAI,CAACd,QAAQ,GAAG,IAAI,CAACA,QAAQ,CAACa,MAAM,CAACF,MAAM,CAAC;IAChD;EACJ;AACJ;AAACI,OAAA,CAAAvB,YAAA,GAAAA,YAAA"} \ No newline at end of file
diff --git a/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/event-status.d.ts b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/event-status.d.ts
new file mode 100644
index 0000000..1f438ab
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/event-status.d.ts
@@ -0,0 +1,19 @@
+/**
+ * Enum for event statuses.
+ * @readonly
+ */
+export declare enum EventStatus {
+ /** The event was not sent and will no longer be retried. */
+ NOT_SENT = "not_sent",
+ /** The message is being encrypted */
+ ENCRYPTING = "encrypting",
+ /** The event is in the process of being sent. */
+ SENDING = "sending",
+ /** The event is in a queue waiting to be sent. */
+ QUEUED = "queued",
+ /** The event has been sent to the server, but we have not yet received the echo. */
+ SENT = "sent",
+ /** The event was cancelled before it was successfully sent. */
+ CANCELLED = "cancelled"
+}
+//# sourceMappingURL=event-status.d.ts.map \ No newline at end of file
diff --git a/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/event-status.d.ts.map b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/event-status.d.ts.map
new file mode 100644
index 0000000..f5bcc04
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/event-status.d.ts.map
@@ -0,0 +1 @@
+{"version":3,"file":"event-status.d.ts","sourceRoot":"","sources":["../../src/models/event-status.ts"],"names":[],"mappings":"AAgBA;;;GAGG;AACH,oBAAY,WAAW;IACnB,4DAA4D;IAC5D,QAAQ,aAAa;IAErB,qCAAqC;IACrC,UAAU,eAAe;IAEzB,iDAAiD;IACjD,OAAO,YAAY;IAEnB,kDAAkD;IAClD,MAAM,WAAW;IAEjB,oFAAoF;IACpF,IAAI,SAAS;IAEb,+DAA+D;IAC/D,SAAS,cAAc;CAC1B"} \ No newline at end of file
diff --git a/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/event-status.js b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/event-status.js
new file mode 100644
index 0000000..4c279af
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/event-status.js
@@ -0,0 +1,36 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.EventStatus = void 0;
+/*
+Copyright 2015 - 2022 The Matrix.org Foundation C.I.C.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+/**
+ * Enum for event statuses.
+ * @readonly
+ */
+let EventStatus;
+exports.EventStatus = EventStatus;
+(function (EventStatus) {
+ EventStatus["NOT_SENT"] = "not_sent";
+ EventStatus["ENCRYPTING"] = "encrypting";
+ EventStatus["SENDING"] = "sending";
+ EventStatus["QUEUED"] = "queued";
+ EventStatus["SENT"] = "sent";
+ EventStatus["CANCELLED"] = "cancelled";
+})(EventStatus || (exports.EventStatus = EventStatus = {}));
+//# sourceMappingURL=event-status.js.map \ No newline at end of file
diff --git a/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/event-status.js.map b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/event-status.js.map
new file mode 100644
index 0000000..3fdca8d
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/event-status.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"event-status.js","names":["EventStatus","exports"],"sources":["../../src/models/event-status.ts"],"sourcesContent":["/*\nCopyright 2015 - 2022 The Matrix.org Foundation C.I.C.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n*/\n\n/**\n * Enum for event statuses.\n * @readonly\n */\nexport enum EventStatus {\n /** The event was not sent and will no longer be retried. */\n NOT_SENT = \"not_sent\",\n\n /** The message is being encrypted */\n ENCRYPTING = \"encrypting\",\n\n /** The event is in the process of being sent. */\n SENDING = \"sending\",\n\n /** The event is in a queue waiting to be sent. */\n QUEUED = \"queued\",\n\n /** The event has been sent to the server, but we have not yet received the echo. */\n SENT = \"sent\",\n\n /** The event was cancelled before it was successfully sent. */\n CANCELLED = \"cancelled\",\n}\n"],"mappings":";;;;;;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAHA,IAIYA,WAAW;AAAAC,OAAA,CAAAD,WAAA,GAAAA,WAAA;AAAA,WAAXA,WAAW;EAAXA,WAAW;EAAXA,WAAW;EAAXA,WAAW;EAAXA,WAAW;EAAXA,WAAW;EAAXA,WAAW;AAAA,GAAXA,WAAW,KAAAC,OAAA,CAAAD,WAAA,GAAXA,WAAW"} \ No newline at end of file
diff --git a/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/event-timeline-set.d.ts b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/event-timeline-set.d.ts
new file mode 100644
index 0000000..88bddd6
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/event-timeline-set.d.ts
@@ -0,0 +1,296 @@
+import { EventTimeline, IAddEventOptions } from "./event-timeline";
+import { MatrixEvent } from "./event";
+import { Room, RoomEvent } from "./room";
+import { Filter } from "../filter";
+import { RoomState } from "./room-state";
+import { TypedEventEmitter } from "./typed-event-emitter";
+import { RelationsContainer } from "./relations-container";
+import { MatrixClient } from "../client";
+import { Thread, ThreadFilterType } from "./thread";
+interface IOpts {
+ timelineSupport?: boolean;
+ filter?: Filter;
+ pendingEvents?: boolean;
+}
+export declare enum DuplicateStrategy {
+ Ignore = "ignore",
+ Replace = "replace"
+}
+export interface IRoomTimelineData {
+ timeline: EventTimeline;
+ liveEvent?: boolean;
+}
+export interface IAddEventToTimelineOptions extends Pick<IAddEventOptions, "toStartOfTimeline" | "roomState" | "timelineWasEmpty"> {
+ /** Whether the sync response came from cache */
+ fromCache?: boolean;
+}
+export interface IAddLiveEventOptions extends Pick<IAddEventToTimelineOptions, "fromCache" | "roomState" | "timelineWasEmpty"> {
+ /** Applies to events in the timeline only. If this is 'replace' then if a
+ * duplicate is encountered, the event passed to this function will replace
+ * the existing event in the timeline. If this is not specified, or is
+ * 'ignore', then the event passed to this function will be ignored
+ * entirely, preserving the existing event in the timeline. Events are
+ * identical based on their event ID <b>only</b>. */
+ duplicateStrategy?: DuplicateStrategy;
+}
+type EmittedEvents = RoomEvent.Timeline | RoomEvent.TimelineReset;
+export type EventTimelineSetHandlerMap = {
+ /**
+ * Fires whenever the timeline in a room is updated.
+ * @param event - The matrix event which caused this event to fire.
+ * @param room - The room, if any, whose timeline was updated.
+ * @param toStartOfTimeline - True if this event was added to the start
+ * @param removed - True if this event has just been removed from the timeline
+ * (beginning; oldest) of the timeline e.g. due to pagination.
+ *
+ * @param data - more data about the event
+ *
+ * @example
+ * ```
+ * matrixClient.on("Room.timeline",
+ * function(event, room, toStartOfTimeline, removed, data) {
+ * if (!toStartOfTimeline && data.liveEvent) {
+ * var messageToAppend = room.timeline.[room.timeline.length - 1];
+ * }
+ * });
+ * ```
+ */
+ [RoomEvent.Timeline]: (event: MatrixEvent, room: Room | undefined, toStartOfTimeline: boolean | undefined, removed: boolean, data: IRoomTimelineData) => void;
+ /**
+ * Fires whenever the live timeline in a room is reset.
+ *
+ * When we get a 'limited' sync (for example, after a network outage), we reset
+ * the live timeline to be empty before adding the recent events to the new
+ * timeline. This event is fired after the timeline is reset, and before the
+ * new events are added.
+ *
+ * @param room - The room whose live timeline was reset, if any
+ * @param timelineSet - timelineSet room whose live timeline was reset
+ * @param resetAllTimelines - True if all timelines were reset.
+ */
+ [RoomEvent.TimelineReset]: (room: Room | undefined, eventTimelineSet: EventTimelineSet, resetAllTimelines: boolean) => void;
+};
+export declare class EventTimelineSet extends TypedEventEmitter<EmittedEvents, EventTimelineSetHandlerMap> {
+ readonly room: Room | undefined;
+ readonly thread?: Thread | undefined;
+ readonly threadListType: ThreadFilterType | null;
+ readonly relations: RelationsContainer;
+ private readonly timelineSupport;
+ private readonly displayPendingEvents;
+ private liveTimeline;
+ private timelines;
+ private _eventIdToTimeline;
+ private filter?;
+ /**
+ * Construct a set of EventTimeline objects, typically on behalf of a given
+ * room. A room may have multiple EventTimelineSets for different levels
+ * of filtering. The global notification list is also an EventTimelineSet, but
+ * lacks a room.
+ *
+ * <p>This is an ordered sequence of timelines, which may or may not
+ * be continuous. Each timeline lists a series of events, as well as tracking
+ * the room state at the start and the end of the timeline (if appropriate).
+ * It also tracks forward and backward pagination tokens, as well as containing
+ * links to the next timeline in the sequence.
+ *
+ * <p>There is one special timeline - the 'live' timeline, which represents the
+ * timeline to which events are being added in real-time as they are received
+ * from the /sync API. Note that you should not retain references to this
+ * timeline - even if it is the current timeline right now, it may not remain
+ * so if the server gives us a timeline gap in /sync.
+ *
+ * <p>In order that we can find events from their ids later, we also maintain a
+ * map from event_id to timeline and index.
+ *
+ * @param room - Room for this timelineSet. May be null for non-room cases, such as the
+ * notification timeline.
+ * @param opts - Options inherited from Room.
+ * @param client - the Matrix client which owns this EventTimelineSet,
+ * can be omitted if room is specified.
+ * @param thread - the thread to which this timeline set relates.
+ * @param isThreadTimeline - Whether this timeline set relates to a thread list timeline
+ * (e.g., All threads or My threads)
+ */
+ constructor(room: Room | undefined, opts?: IOpts, client?: MatrixClient, thread?: Thread | undefined, threadListType?: ThreadFilterType | null);
+ /**
+ * Get all the timelines in this set
+ * @returns the timelines in this set
+ */
+ getTimelines(): EventTimeline[];
+ /**
+ * Get the filter object this timeline set is filtered on, if any
+ * @returns the optional filter for this timelineSet
+ */
+ getFilter(): Filter | undefined;
+ /**
+ * Set the filter object this timeline set is filtered on
+ * (passed to the server when paginating via /messages).
+ * @param filter - the filter for this timelineSet
+ */
+ setFilter(filter?: Filter): void;
+ /**
+ * Get the list of pending sent events for this timelineSet's room, filtered
+ * by the timelineSet's filter if appropriate.
+ *
+ * @returns A list of the sent events
+ * waiting for remote echo.
+ *
+ * @throws If `opts.pendingEventOrdering` was not 'detached'
+ */
+ getPendingEvents(): MatrixEvent[];
+ /**
+ * Get the live timeline for this room.
+ *
+ * @returns live timeline
+ */
+ getLiveTimeline(): EventTimeline;
+ /**
+ * Set the live timeline for this room.
+ *
+ * @returns live timeline
+ */
+ setLiveTimeline(timeline: EventTimeline): void;
+ /**
+ * Return the timeline (if any) this event is in.
+ * @param eventId - the eventId being sought
+ * @returns timeline
+ */
+ eventIdToTimeline(eventId: string): EventTimeline | undefined;
+ /**
+ * Track a new event as if it were in the same timeline as an old event,
+ * replacing it.
+ * @param oldEventId - event ID of the original event
+ * @param newEventId - event ID of the replacement event
+ */
+ replaceEventId(oldEventId: string, newEventId: string): void;
+ /**
+ * Reset the live timeline, and start a new one.
+ *
+ * <p>This is used when /sync returns a 'limited' timeline.
+ *
+ * @param backPaginationToken - token for back-paginating the new timeline
+ * @param forwardPaginationToken - token for forward-paginating the old live timeline,
+ * if absent or null, all timelines are reset.
+ *
+ * @remarks
+ * Fires {@link RoomEvent.TimelineReset}
+ */
+ resetLiveTimeline(backPaginationToken?: string, forwardPaginationToken?: string): void;
+ /**
+ * Get the timeline which contains the given event, if any
+ *
+ * @param eventId - event ID to look for
+ * @returns timeline containing
+ * the given event, or null if unknown
+ */
+ getTimelineForEvent(eventId?: string): EventTimeline | null;
+ /**
+ * Get an event which is stored in our timelines
+ *
+ * @param eventId - event ID to look for
+ * @returns the given event, or undefined if unknown
+ */
+ findEventById(eventId: string): MatrixEvent | undefined;
+ /**
+ * Add a new timeline to this timeline list
+ *
+ * @returns newly-created timeline
+ */
+ addTimeline(): EventTimeline;
+ /**
+ * Add events to a timeline
+ *
+ * <p>Will fire "Room.timeline" for each event added.
+ *
+ * @param events - A list of events to add.
+ *
+ * @param toStartOfTimeline - True to add these events to the start
+ * (oldest) instead of the end (newest) of the timeline. If true, the oldest
+ * event will be the <b>last</b> element of 'events'.
+ *
+ * @param timeline - timeline to
+ * add events to.
+ *
+ * @param paginationToken - token for the next batch of events
+ *
+ * @remarks
+ * Fires {@link RoomEvent.Timeline}
+ *
+ */
+ addEventsToTimeline(events: MatrixEvent[], toStartOfTimeline: boolean, timeline: EventTimeline, paginationToken?: string | null): void;
+ /**
+ * Add an event to the end of this live timeline.
+ *
+ * @param event - Event to be added
+ * @param options - addLiveEvent options
+ */
+ addLiveEvent(event: MatrixEvent, { duplicateStrategy, fromCache, roomState, timelineWasEmpty }: IAddLiveEventOptions): void;
+ /**
+ * @deprecated In favor of the overload with `IAddLiveEventOptions`
+ */
+ addLiveEvent(event: MatrixEvent, duplicateStrategy?: DuplicateStrategy, fromCache?: boolean, roomState?: RoomState): void;
+ /**
+ * Add event to the given timeline, and emit Room.timeline. Assumes
+ * we have already checked we don't know about this event.
+ *
+ * Will fire "Room.timeline" for each event added.
+ *
+ * @param options - addEventToTimeline options
+ *
+ * @remarks
+ * Fires {@link RoomEvent.Timeline}
+ */
+ addEventToTimeline(event: MatrixEvent, timeline: EventTimeline, { toStartOfTimeline, fromCache, roomState, timelineWasEmpty }: IAddEventToTimelineOptions): void;
+ /**
+ * @deprecated In favor of the overload with `IAddEventToTimelineOptions`
+ */
+ addEventToTimeline(event: MatrixEvent, timeline: EventTimeline, toStartOfTimeline: boolean, fromCache?: boolean, roomState?: RoomState): void;
+ /**
+ * Replaces event with ID oldEventId with one with newEventId, if oldEventId is
+ * recognised. Otherwise, add to the live timeline. Used to handle remote echos.
+ *
+ * @param localEvent - the new event to be added to the timeline
+ * @param oldEventId - the ID of the original event
+ * @param newEventId - the ID of the replacement event
+ *
+ * @remarks
+ * Fires {@link RoomEvent.Timeline}
+ */
+ handleRemoteEcho(localEvent: MatrixEvent, oldEventId: string, newEventId: string): void;
+ /**
+ * Removes a single event from this room.
+ *
+ * @param eventId - The id of the event to remove
+ *
+ * @returns the removed event, or null if the event was not found
+ * in this room.
+ */
+ removeEvent(eventId: string): MatrixEvent | null;
+ /**
+ * Determine where two events appear in the timeline relative to one another
+ *
+ * @param eventId1 - The id of the first event
+ * @param eventId2 - The id of the second event
+
+ * @returns a number less than zero if eventId1 precedes eventId2, and
+ * greater than zero if eventId1 succeeds eventId2. zero if they are the
+ * same event; null if we can't tell (either because we don't know about one
+ * of the events, or because they are in separate timelines which don't join
+ * up).
+ */
+ compareEventOrdering(eventId1: string, eventId2: string): number | null;
+ /**
+ * Determine whether a given event can sanely be added to this event timeline set,
+ * for timeline sets relating to a thread, only return true for events in the same
+ * thread timeline, for timeline sets not relating to a thread only return true
+ * for events which should be shown in the main room timeline.
+ * Requires the `room` property to have been set at EventTimelineSet construction time.
+ *
+ * @param event - the event to check whether it belongs to this timeline set.
+ * @throws Error if `room` was not set when constructing this timeline set.
+ * @returns whether the event belongs to this timeline set.
+ */
+ canContain(event: MatrixEvent): boolean;
+}
+export {};
+//# sourceMappingURL=event-timeline-set.d.ts.map \ No newline at end of file
diff --git a/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/event-timeline-set.d.ts.map b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/event-timeline-set.d.ts.map
new file mode 100644
index 0000000..20d2e64
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/event-timeline-set.d.ts.map
@@ -0,0 +1 @@
+{"version":3,"file":"event-timeline-set.d.ts","sourceRoot":"","sources":["../../src/models/event-timeline-set.ts"],"names":[],"mappings":"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"} \ No newline at end of file
diff --git a/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/event-timeline-set.js b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/event-timeline-set.js
new file mode 100644
index 0000000..b0f08b7
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/event-timeline-set.js
@@ -0,0 +1,725 @@
+"use strict";
+
+var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.EventTimelineSet = exports.DuplicateStrategy = void 0;
+var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
+var _eventTimeline = require("./event-timeline");
+var _logger = require("../logger");
+var _room = require("./room");
+var _typedEventEmitter = require("./typed-event-emitter");
+var _relationsContainer = require("./relations-container");
+/*
+Copyright 2016 - 2021 The Matrix.org Foundation C.I.C.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+const DEBUG = true;
+
+/* istanbul ignore next */
+let debuglog;
+if (DEBUG) {
+ // using bind means that we get to keep useful line numbers in the console
+ debuglog = _logger.logger.log.bind(_logger.logger);
+} else {
+ /* istanbul ignore next */
+ debuglog = function () {};
+}
+let DuplicateStrategy;
+exports.DuplicateStrategy = DuplicateStrategy;
+(function (DuplicateStrategy) {
+ DuplicateStrategy["Ignore"] = "ignore";
+ DuplicateStrategy["Replace"] = "replace";
+})(DuplicateStrategy || (exports.DuplicateStrategy = DuplicateStrategy = {}));
+class EventTimelineSet extends _typedEventEmitter.TypedEventEmitter {
+ /**
+ * Construct a set of EventTimeline objects, typically on behalf of a given
+ * room. A room may have multiple EventTimelineSets for different levels
+ * of filtering. The global notification list is also an EventTimelineSet, but
+ * lacks a room.
+ *
+ * <p>This is an ordered sequence of timelines, which may or may not
+ * be continuous. Each timeline lists a series of events, as well as tracking
+ * the room state at the start and the end of the timeline (if appropriate).
+ * It also tracks forward and backward pagination tokens, as well as containing
+ * links to the next timeline in the sequence.
+ *
+ * <p>There is one special timeline - the 'live' timeline, which represents the
+ * timeline to which events are being added in real-time as they are received
+ * from the /sync API. Note that you should not retain references to this
+ * timeline - even if it is the current timeline right now, it may not remain
+ * so if the server gives us a timeline gap in /sync.
+ *
+ * <p>In order that we can find events from their ids later, we also maintain a
+ * map from event_id to timeline and index.
+ *
+ * @param room - Room for this timelineSet. May be null for non-room cases, such as the
+ * notification timeline.
+ * @param opts - Options inherited from Room.
+ * @param client - the Matrix client which owns this EventTimelineSet,
+ * can be omitted if room is specified.
+ * @param thread - the thread to which this timeline set relates.
+ * @param isThreadTimeline - Whether this timeline set relates to a thread list timeline
+ * (e.g., All threads or My threads)
+ */
+ constructor(room, opts = {}, client, thread, threadListType = null) {
+ var _this$room$relations, _this$room, _room$client;
+ super();
+ this.room = room;
+ this.thread = thread;
+ this.threadListType = threadListType;
+ (0, _defineProperty2.default)(this, "relations", void 0);
+ (0, _defineProperty2.default)(this, "timelineSupport", void 0);
+ (0, _defineProperty2.default)(this, "displayPendingEvents", void 0);
+ (0, _defineProperty2.default)(this, "liveTimeline", void 0);
+ (0, _defineProperty2.default)(this, "timelines", void 0);
+ (0, _defineProperty2.default)(this, "_eventIdToTimeline", new Map());
+ (0, _defineProperty2.default)(this, "filter", void 0);
+ this.timelineSupport = Boolean(opts.timelineSupport);
+ this.liveTimeline = new _eventTimeline.EventTimeline(this);
+ this.displayPendingEvents = opts.pendingEvents !== false;
+
+ // just a list - *not* ordered.
+ this.timelines = [this.liveTimeline];
+ this._eventIdToTimeline = new Map();
+ this.filter = opts.filter;
+ this.relations = (_this$room$relations = (_this$room = this.room) === null || _this$room === void 0 ? void 0 : _this$room.relations) !== null && _this$room$relations !== void 0 ? _this$room$relations : new _relationsContainer.RelationsContainer((_room$client = room === null || room === void 0 ? void 0 : room.client) !== null && _room$client !== void 0 ? _room$client : client);
+ }
+
+ /**
+ * Get all the timelines in this set
+ * @returns the timelines in this set
+ */
+ getTimelines() {
+ return this.timelines;
+ }
+
+ /**
+ * Get the filter object this timeline set is filtered on, if any
+ * @returns the optional filter for this timelineSet
+ */
+ getFilter() {
+ return this.filter;
+ }
+
+ /**
+ * Set the filter object this timeline set is filtered on
+ * (passed to the server when paginating via /messages).
+ * @param filter - the filter for this timelineSet
+ */
+ setFilter(filter) {
+ this.filter = filter;
+ }
+
+ /**
+ * Get the list of pending sent events for this timelineSet's room, filtered
+ * by the timelineSet's filter if appropriate.
+ *
+ * @returns A list of the sent events
+ * waiting for remote echo.
+ *
+ * @throws If `opts.pendingEventOrdering` was not 'detached'
+ */
+ getPendingEvents() {
+ if (!this.room || !this.displayPendingEvents) {
+ return [];
+ }
+ return this.room.getPendingEvents();
+ }
+ /**
+ * Get the live timeline for this room.
+ *
+ * @returns live timeline
+ */
+ getLiveTimeline() {
+ return this.liveTimeline;
+ }
+
+ /**
+ * Set the live timeline for this room.
+ *
+ * @returns live timeline
+ */
+ setLiveTimeline(timeline) {
+ this.liveTimeline = timeline;
+ }
+
+ /**
+ * Return the timeline (if any) this event is in.
+ * @param eventId - the eventId being sought
+ * @returns timeline
+ */
+ eventIdToTimeline(eventId) {
+ return this._eventIdToTimeline.get(eventId);
+ }
+
+ /**
+ * Track a new event as if it were in the same timeline as an old event,
+ * replacing it.
+ * @param oldEventId - event ID of the original event
+ * @param newEventId - event ID of the replacement event
+ */
+ replaceEventId(oldEventId, newEventId) {
+ const existingTimeline = this._eventIdToTimeline.get(oldEventId);
+ if (existingTimeline) {
+ this._eventIdToTimeline.delete(oldEventId);
+ this._eventIdToTimeline.set(newEventId, existingTimeline);
+ }
+ }
+
+ /**
+ * Reset the live timeline, and start a new one.
+ *
+ * <p>This is used when /sync returns a 'limited' timeline.
+ *
+ * @param backPaginationToken - token for back-paginating the new timeline
+ * @param forwardPaginationToken - token for forward-paginating the old live timeline,
+ * if absent or null, all timelines are reset.
+ *
+ * @remarks
+ * Fires {@link RoomEvent.TimelineReset}
+ */
+ resetLiveTimeline(backPaginationToken, forwardPaginationToken) {
+ // Each EventTimeline has RoomState objects tracking the state at the start
+ // and end of that timeline. The copies at the end of the live timeline are
+ // special because they will have listeners attached to monitor changes to
+ // the current room state, so we move this RoomState from the end of the
+ // current live timeline to the end of the new one and, if necessary,
+ // replace it with a newly created one. We also make a copy for the start
+ // of the new timeline.
+
+ // if timeline support is disabled, forget about the old timelines
+ const resetAllTimelines = !this.timelineSupport || !forwardPaginationToken;
+ const oldTimeline = this.liveTimeline;
+ const newTimeline = resetAllTimelines ? oldTimeline.forkLive(_eventTimeline.EventTimeline.FORWARDS) : oldTimeline.fork(_eventTimeline.EventTimeline.FORWARDS);
+ if (resetAllTimelines) {
+ this.timelines = [newTimeline];
+ this._eventIdToTimeline = new Map();
+ } else {
+ this.timelines.push(newTimeline);
+ }
+ if (forwardPaginationToken) {
+ // Now set the forward pagination token on the old live timeline
+ // so it can be forward-paginated.
+ oldTimeline.setPaginationToken(forwardPaginationToken, _eventTimeline.EventTimeline.FORWARDS);
+ }
+
+ // make sure we set the pagination token before firing timelineReset,
+ // otherwise clients which start back-paginating will fail, and then get
+ // stuck without realising that they *can* back-paginate.
+ newTimeline.setPaginationToken(backPaginationToken !== null && backPaginationToken !== void 0 ? backPaginationToken : null, _eventTimeline.EventTimeline.BACKWARDS);
+
+ // Now we can swap the live timeline to the new one.
+ this.liveTimeline = newTimeline;
+ this.emit(_room.RoomEvent.TimelineReset, this.room, this, resetAllTimelines);
+ }
+
+ /**
+ * Get the timeline which contains the given event, if any
+ *
+ * @param eventId - event ID to look for
+ * @returns timeline containing
+ * the given event, or null if unknown
+ */
+ getTimelineForEvent(eventId) {
+ if (eventId === null || eventId === undefined) {
+ return null;
+ }
+ const res = this._eventIdToTimeline.get(eventId);
+ return res === undefined ? null : res;
+ }
+
+ /**
+ * Get an event which is stored in our timelines
+ *
+ * @param eventId - event ID to look for
+ * @returns the given event, or undefined if unknown
+ */
+ findEventById(eventId) {
+ const tl = this.getTimelineForEvent(eventId);
+ if (!tl) {
+ return undefined;
+ }
+ return tl.getEvents().find(function (ev) {
+ return ev.getId() == eventId;
+ });
+ }
+
+ /**
+ * Add a new timeline to this timeline list
+ *
+ * @returns newly-created timeline
+ */
+ addTimeline() {
+ if (!this.timelineSupport) {
+ throw new Error("timeline support is disabled. Set the 'timelineSupport'" + " parameter to true when creating MatrixClient to enable" + " it.");
+ }
+ const timeline = new _eventTimeline.EventTimeline(this);
+ this.timelines.push(timeline);
+ return timeline;
+ }
+
+ /**
+ * Add events to a timeline
+ *
+ * <p>Will fire "Room.timeline" for each event added.
+ *
+ * @param events - A list of events to add.
+ *
+ * @param toStartOfTimeline - True to add these events to the start
+ * (oldest) instead of the end (newest) of the timeline. If true, the oldest
+ * event will be the <b>last</b> element of 'events'.
+ *
+ * @param timeline - timeline to
+ * add events to.
+ *
+ * @param paginationToken - token for the next batch of events
+ *
+ * @remarks
+ * Fires {@link RoomEvent.Timeline}
+ *
+ */
+ addEventsToTimeline(events, toStartOfTimeline, timeline, paginationToken) {
+ if (!timeline) {
+ throw new Error("'timeline' not specified for EventTimelineSet.addEventsToTimeline");
+ }
+ if (!toStartOfTimeline && timeline == this.liveTimeline) {
+ throw new Error("EventTimelineSet.addEventsToTimeline cannot be used for adding events to " + "the live timeline - use Room.addLiveEvents instead");
+ }
+ if (this.filter) {
+ events = this.filter.filterRoomTimeline(events);
+ if (!events.length) {
+ return;
+ }
+ }
+ const direction = toStartOfTimeline ? _eventTimeline.EventTimeline.BACKWARDS : _eventTimeline.EventTimeline.FORWARDS;
+ const inverseDirection = toStartOfTimeline ? _eventTimeline.EventTimeline.FORWARDS : _eventTimeline.EventTimeline.BACKWARDS;
+
+ // Adding events to timelines can be quite complicated. The following
+ // illustrates some of the corner-cases.
+ //
+ // Let's say we start by knowing about four timelines. timeline3 and
+ // timeline4 are neighbours:
+ //
+ // timeline1 timeline2 timeline3 timeline4
+ // [M] [P] [S] <------> [T]
+ //
+ // Now we paginate timeline1, and get the following events from the server:
+ // [M, N, P, R, S, T, U].
+ //
+ // 1. First, we ignore event M, since we already know about it.
+ //
+ // 2. Next, we append N to timeline 1.
+ //
+ // 3. Next, we don't add event P, since we already know about it,
+ // but we do link together the timelines. We now have:
+ //
+ // timeline1 timeline2 timeline3 timeline4
+ // [M, N] <---> [P] [S] <------> [T]
+ //
+ // 4. Now we add event R to timeline2:
+ //
+ // timeline1 timeline2 timeline3 timeline4
+ // [M, N] <---> [P, R] [S] <------> [T]
+ //
+ // Note that we have switched the timeline we are working on from
+ // timeline1 to timeline2.
+ //
+ // 5. We ignore event S, but again join the timelines:
+ //
+ // timeline1 timeline2 timeline3 timeline4
+ // [M, N] <---> [P, R] <---> [S] <------> [T]
+ //
+ // 6. We ignore event T, and the timelines are already joined, so there
+ // is nothing to do.
+ //
+ // 7. Finally, we add event U to timeline4:
+ //
+ // timeline1 timeline2 timeline3 timeline4
+ // [M, N] <---> [P, R] <---> [S] <------> [T, U]
+ //
+ // The important thing to note in the above is what happened when we
+ // already knew about a given event:
+ //
+ // - if it was appropriate, we joined up the timelines (steps 3, 5).
+ // - in any case, we started adding further events to the timeline which
+ // contained the event we knew about (steps 3, 5, 6).
+ //
+ //
+ // So much for adding events to the timeline. But what do we want to do
+ // with the pagination token?
+ //
+ // In the case above, we will be given a pagination token which tells us how to
+ // get events beyond 'U' - in this case, it makes sense to store this
+ // against timeline4. But what if timeline4 already had 'U' and beyond? in
+ // that case, our best bet is to throw away the pagination token we were
+ // given and stick with whatever token timeline4 had previously. In short,
+ // we want to only store the pagination token if the last event we receive
+ // is one we didn't previously know about.
+ //
+ // We make an exception for this if it turns out that we already knew about
+ // *all* of the events, and we weren't able to join up any timelines. When
+ // that happens, it means our existing pagination token is faulty, since it
+ // is only telling us what we already know. Rather than repeatedly
+ // paginating with the same token, we might as well use the new pagination
+ // token in the hope that we eventually work our way out of the mess.
+
+ let didUpdate = false;
+ let lastEventWasNew = false;
+ for (const event of events) {
+ const eventId = event.getId();
+ const existingTimeline = this._eventIdToTimeline.get(eventId);
+ if (!existingTimeline) {
+ // we don't know about this event yet. Just add it to the timeline.
+ this.addEventToTimeline(event, timeline, {
+ toStartOfTimeline
+ });
+ lastEventWasNew = true;
+ didUpdate = true;
+ continue;
+ }
+ lastEventWasNew = false;
+ if (existingTimeline == timeline) {
+ debuglog("Event " + eventId + " already in timeline " + timeline);
+ continue;
+ }
+ const neighbour = timeline.getNeighbouringTimeline(direction);
+ if (neighbour) {
+ // this timeline already has a neighbour in the relevant direction;
+ // let's assume the timelines are already correctly linked up, and
+ // skip over to it.
+ //
+ // there's probably some edge-case here where we end up with an
+ // event which is in a timeline a way down the chain, and there is
+ // a break in the chain somewhere. But I can't really imagine how
+ // that would happen, so I'm going to ignore it for now.
+ //
+ if (existingTimeline == neighbour) {
+ debuglog("Event " + eventId + " in neighbouring timeline - " + "switching to " + existingTimeline);
+ } else {
+ debuglog("Event " + eventId + " already in a different " + "timeline " + existingTimeline);
+ }
+ timeline = existingTimeline;
+ continue;
+ }
+
+ // time to join the timelines.
+ _logger.logger.info("Already have timeline for " + eventId + " - joining timeline " + timeline + " to " + existingTimeline);
+
+ // Variables to keep the line length limited below.
+ const existingIsLive = existingTimeline === this.liveTimeline;
+ const timelineIsLive = timeline === this.liveTimeline;
+ const backwardsIsLive = direction === _eventTimeline.EventTimeline.BACKWARDS && existingIsLive;
+ const forwardsIsLive = direction === _eventTimeline.EventTimeline.FORWARDS && timelineIsLive;
+ if (backwardsIsLive || forwardsIsLive) {
+ // The live timeline should never be spliced into a non-live position.
+ // We use independent logging to better discover the problem at a glance.
+ if (backwardsIsLive) {
+ _logger.logger.warn("Refusing to set a preceding existingTimeLine on our " + "timeline as the existingTimeLine is live (" + existingTimeline + ")");
+ }
+ if (forwardsIsLive) {
+ _logger.logger.warn("Refusing to set our preceding timeline on a existingTimeLine " + "as our timeline is live (" + timeline + ")");
+ }
+ continue; // abort splicing - try next event
+ }
+
+ timeline.setNeighbouringTimeline(existingTimeline, direction);
+ existingTimeline.setNeighbouringTimeline(timeline, inverseDirection);
+ timeline = existingTimeline;
+ didUpdate = true;
+ }
+
+ // see above - if the last event was new to us, or if we didn't find any
+ // new information, we update the pagination token for whatever
+ // timeline we ended up on.
+ if (lastEventWasNew || !didUpdate) {
+ if (direction === _eventTimeline.EventTimeline.FORWARDS && timeline === this.liveTimeline) {
+ _logger.logger.warn({
+ lastEventWasNew,
+ didUpdate
+ }); // for debugging
+ _logger.logger.warn(`Refusing to set forwards pagination token of live timeline ` + `${timeline} to ${paginationToken}`);
+ return;
+ }
+ timeline.setPaginationToken(paginationToken !== null && paginationToken !== void 0 ? paginationToken : null, direction);
+ }
+ }
+
+ /**
+ * Add an event to the end of this live timeline.
+ *
+ * @param event - Event to be added
+ * @param options - addLiveEvent options
+ */
+
+ addLiveEvent(event, duplicateStrategyOrOpts, fromCache = false, roomState) {
+ let duplicateStrategy = duplicateStrategyOrOpts || DuplicateStrategy.Ignore;
+ let timelineWasEmpty;
+ if (typeof duplicateStrategyOrOpts === "object") {
+ ({
+ duplicateStrategy = DuplicateStrategy.Ignore,
+ fromCache = false,
+ roomState,
+ timelineWasEmpty
+ } = duplicateStrategyOrOpts);
+ } else if (duplicateStrategyOrOpts !== undefined) {
+ // Deprecation warning
+ // FIXME: Remove after 2023-06-01 (technical debt)
+ _logger.logger.warn("Overload deprecated: " + "`EventTimelineSet.addLiveEvent(event, duplicateStrategy?, fromCache?, roomState?)` " + "is deprecated in favor of the overload with " + "`EventTimelineSet.addLiveEvent(event, IAddLiveEventOptions)`");
+ }
+ if (this.filter) {
+ const events = this.filter.filterRoomTimeline([event]);
+ if (!events.length) {
+ return;
+ }
+ }
+ const timeline = this._eventIdToTimeline.get(event.getId());
+ if (timeline) {
+ if (duplicateStrategy === DuplicateStrategy.Replace) {
+ debuglog("EventTimelineSet.addLiveEvent: replacing duplicate event " + event.getId());
+ const tlEvents = timeline.getEvents();
+ for (let j = 0; j < tlEvents.length; j++) {
+ if (tlEvents[j].getId() === event.getId()) {
+ // still need to set the right metadata on this event
+ if (!roomState) {
+ roomState = timeline.getState(_eventTimeline.EventTimeline.FORWARDS);
+ }
+ _eventTimeline.EventTimeline.setEventMetadata(event, roomState, false);
+ tlEvents[j] = event;
+
+ // XXX: we need to fire an event when this happens.
+ break;
+ }
+ }
+ } else {
+ debuglog("EventTimelineSet.addLiveEvent: ignoring duplicate event " + event.getId());
+ }
+ return;
+ }
+ this.addEventToTimeline(event, this.liveTimeline, {
+ toStartOfTimeline: false,
+ fromCache,
+ roomState,
+ timelineWasEmpty
+ });
+ }
+
+ /**
+ * Add event to the given timeline, and emit Room.timeline. Assumes
+ * we have already checked we don't know about this event.
+ *
+ * Will fire "Room.timeline" for each event added.
+ *
+ * @param options - addEventToTimeline options
+ *
+ * @remarks
+ * Fires {@link RoomEvent.Timeline}
+ */
+
+ addEventToTimeline(event, timeline, toStartOfTimelineOrOpts, fromCache = false, roomState) {
+ let toStartOfTimeline = !!toStartOfTimelineOrOpts;
+ let timelineWasEmpty;
+ if (typeof toStartOfTimelineOrOpts === "object") {
+ ({
+ toStartOfTimeline,
+ fromCache = false,
+ roomState,
+ timelineWasEmpty
+ } = toStartOfTimelineOrOpts);
+ } else if (toStartOfTimelineOrOpts !== undefined) {
+ // Deprecation warning
+ // FIXME: Remove after 2023-06-01 (technical debt)
+ _logger.logger.warn("Overload deprecated: " + "`EventTimelineSet.addEventToTimeline(event, timeline, toStartOfTimeline, fromCache?, roomState?)` " + "is deprecated in favor of the overload with " + "`EventTimelineSet.addEventToTimeline(event, timeline, IAddEventToTimelineOptions)`");
+ }
+ if (timeline.getTimelineSet() !== this) {
+ var _this$thread;
+ throw new Error(`EventTimelineSet.addEventToTimeline: Timeline=${timeline.toString()} does not belong " +
+ "in timelineSet(threadId=${(_this$thread = this.thread) === null || _this$thread === void 0 ? void 0 : _this$thread.id})`);
+ }
+
+ // Make sure events don't get mixed in timelines they shouldn't be in (e.g. a
+ // threaded message should not be in the main timeline).
+ //
+ // We can only run this check for timelines with a `room` because `canContain`
+ // requires it
+ if (this.room && !this.canContain(event)) {
+ var _this$thread2;
+ let eventDebugString = `event=${event.getId()}`;
+ if (event.threadRootId) {
+ eventDebugString += `(belongs to thread=${event.threadRootId})`;
+ }
+ _logger.logger.warn(`EventTimelineSet.addEventToTimeline: Ignoring ${eventDebugString} that does not belong ` + `in timeline=${timeline.toString()} timelineSet(threadId=${(_this$thread2 = this.thread) === null || _this$thread2 === void 0 ? void 0 : _this$thread2.id})`);
+ return;
+ }
+ const eventId = event.getId();
+ timeline.addEvent(event, {
+ toStartOfTimeline,
+ roomState,
+ timelineWasEmpty
+ });
+ this._eventIdToTimeline.set(eventId, timeline);
+ this.relations.aggregateParentEvent(event);
+ this.relations.aggregateChildEvent(event, this);
+ const data = {
+ timeline: timeline,
+ liveEvent: !toStartOfTimeline && timeline == this.liveTimeline && !fromCache
+ };
+ this.emit(_room.RoomEvent.Timeline, event, this.room, Boolean(toStartOfTimeline), false, data);
+ }
+
+ /**
+ * Replaces event with ID oldEventId with one with newEventId, if oldEventId is
+ * recognised. Otherwise, add to the live timeline. Used to handle remote echos.
+ *
+ * @param localEvent - the new event to be added to the timeline
+ * @param oldEventId - the ID of the original event
+ * @param newEventId - the ID of the replacement event
+ *
+ * @remarks
+ * Fires {@link RoomEvent.Timeline}
+ */
+ handleRemoteEcho(localEvent, oldEventId, newEventId) {
+ // XXX: why don't we infer newEventId from localEvent?
+ const existingTimeline = this._eventIdToTimeline.get(oldEventId);
+ if (existingTimeline) {
+ this._eventIdToTimeline.delete(oldEventId);
+ this._eventIdToTimeline.set(newEventId, existingTimeline);
+ } else if (!this.filter || this.filter.filterRoomTimeline([localEvent]).length) {
+ this.addEventToTimeline(localEvent, this.liveTimeline, {
+ toStartOfTimeline: false
+ });
+ }
+ }
+
+ /**
+ * Removes a single event from this room.
+ *
+ * @param eventId - The id of the event to remove
+ *
+ * @returns the removed event, or null if the event was not found
+ * in this room.
+ */
+ removeEvent(eventId) {
+ const timeline = this._eventIdToTimeline.get(eventId);
+ if (!timeline) {
+ return null;
+ }
+ const removed = timeline.removeEvent(eventId);
+ if (removed) {
+ this._eventIdToTimeline.delete(eventId);
+ const data = {
+ timeline: timeline
+ };
+ this.emit(_room.RoomEvent.Timeline, removed, this.room, undefined, true, data);
+ }
+ return removed;
+ }
+
+ /**
+ * Determine where two events appear in the timeline relative to one another
+ *
+ * @param eventId1 - The id of the first event
+ * @param eventId2 - The id of the second event
+ * @returns a number less than zero if eventId1 precedes eventId2, and
+ * greater than zero if eventId1 succeeds eventId2. zero if they are the
+ * same event; null if we can't tell (either because we don't know about one
+ * of the events, or because they are in separate timelines which don't join
+ * up).
+ */
+ compareEventOrdering(eventId1, eventId2) {
+ if (eventId1 == eventId2) {
+ // optimise this case
+ return 0;
+ }
+ const timeline1 = this._eventIdToTimeline.get(eventId1);
+ const timeline2 = this._eventIdToTimeline.get(eventId2);
+ if (timeline1 === undefined) {
+ return null;
+ }
+ if (timeline2 === undefined) {
+ return null;
+ }
+ if (timeline1 === timeline2) {
+ // both events are in the same timeline - figure out their relative indices
+ let idx1 = undefined;
+ let idx2 = undefined;
+ const events = timeline1.getEvents();
+ for (let idx = 0; idx < events.length && (idx1 === undefined || idx2 === undefined); idx++) {
+ const evId = events[idx].getId();
+ if (evId == eventId1) {
+ idx1 = idx;
+ }
+ if (evId == eventId2) {
+ idx2 = idx;
+ }
+ }
+ return idx1 - idx2;
+ }
+
+ // the events are in different timelines. Iterate through the
+ // linkedlist to see which comes first.
+
+ // first work forwards from timeline1
+ let tl = timeline1;
+ while (tl) {
+ if (tl === timeline2) {
+ // timeline1 is before timeline2
+ return -1;
+ }
+ tl = tl.getNeighbouringTimeline(_eventTimeline.EventTimeline.FORWARDS);
+ }
+
+ // now try backwards from timeline1
+ tl = timeline1;
+ while (tl) {
+ if (tl === timeline2) {
+ // timeline2 is before timeline1
+ return 1;
+ }
+ tl = tl.getNeighbouringTimeline(_eventTimeline.EventTimeline.BACKWARDS);
+ }
+
+ // the timelines are not contiguous.
+ return null;
+ }
+
+ /**
+ * Determine whether a given event can sanely be added to this event timeline set,
+ * for timeline sets relating to a thread, only return true for events in the same
+ * thread timeline, for timeline sets not relating to a thread only return true
+ * for events which should be shown in the main room timeline.
+ * Requires the `room` property to have been set at EventTimelineSet construction time.
+ *
+ * @param event - the event to check whether it belongs to this timeline set.
+ * @throws Error if `room` was not set when constructing this timeline set.
+ * @returns whether the event belongs to this timeline set.
+ */
+ canContain(event) {
+ if (!this.room) {
+ throw new Error("Cannot call `EventTimelineSet::canContain without a `room` set. " + "Set the room when creating the EventTimelineSet to call this method.");
+ }
+ const {
+ threadId,
+ shouldLiveInRoom
+ } = this.room.eventShouldLiveIn(event);
+ if (this.thread) {
+ return this.thread.id === threadId;
+ }
+ return shouldLiveInRoom;
+ }
+}
+exports.EventTimelineSet = EventTimelineSet;
+//# sourceMappingURL=event-timeline-set.js.map \ No newline at end of file
diff --git a/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/event-timeline-set.js.map b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/event-timeline-set.js.map
new file mode 100644
index 0000000..fbb25e2
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/event-timeline-set.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"event-timeline-set.js","names":["_eventTimeline","require","_logger","_room","_typedEventEmitter","_relationsContainer","DEBUG","debuglog","logger","log","bind","DuplicateStrategy","exports","EventTimelineSet","TypedEventEmitter","constructor","room","opts","client","thread","threadListType","_this$room$relations","_this$room","_room$client","_defineProperty2","default","Map","timelineSupport","Boolean","liveTimeline","EventTimeline","displayPendingEvents","pendingEvents","timelines","_eventIdToTimeline","filter","relations","RelationsContainer","getTimelines","getFilter","setFilter","getPendingEvents","getLiveTimeline","setLiveTimeline","timeline","eventIdToTimeline","eventId","get","replaceEventId","oldEventId","newEventId","existingTimeline","delete","set","resetLiveTimeline","backPaginationToken","forwardPaginationToken","resetAllTimelines","oldTimeline","newTimeline","forkLive","FORWARDS","fork","push","setPaginationToken","BACKWARDS","emit","RoomEvent","TimelineReset","getTimelineForEvent","undefined","res","findEventById","tl","getEvents","find","ev","getId","addTimeline","Error","addEventsToTimeline","events","toStartOfTimeline","paginationToken","filterRoomTimeline","length","direction","inverseDirection","didUpdate","lastEventWasNew","event","addEventToTimeline","neighbour","getNeighbouringTimeline","info","existingIsLive","timelineIsLive","backwardsIsLive","forwardsIsLive","warn","setNeighbouringTimeline","addLiveEvent","duplicateStrategyOrOpts","fromCache","roomState","duplicateStrategy","Ignore","timelineWasEmpty","Replace","tlEvents","j","getState","setEventMetadata","toStartOfTimelineOrOpts","getTimelineSet","_this$thread","toString","id","canContain","_this$thread2","eventDebugString","threadRootId","addEvent","aggregateParentEvent","aggregateChildEvent","data","liveEvent","Timeline","handleRemoteEcho","localEvent","removeEvent","removed","compareEventOrdering","eventId1","eventId2","timeline1","timeline2","idx1","idx2","idx","evId","threadId","shouldLiveInRoom","eventShouldLiveIn"],"sources":["../../src/models/event-timeline-set.ts"],"sourcesContent":["/*\nCopyright 2016 - 2021 The Matrix.org Foundation C.I.C.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n*/\n\nimport { EventTimeline, IAddEventOptions } from \"./event-timeline\";\nimport { MatrixEvent } from \"./event\";\nimport { logger } from \"../logger\";\nimport { Room, RoomEvent } from \"./room\";\nimport { Filter } from \"../filter\";\nimport { RoomState } from \"./room-state\";\nimport { TypedEventEmitter } from \"./typed-event-emitter\";\nimport { RelationsContainer } from \"./relations-container\";\nimport { MatrixClient } from \"../client\";\nimport { Thread, ThreadFilterType } from \"./thread\";\n\nconst DEBUG = true;\n\n/* istanbul ignore next */\nlet debuglog: (...args: any[]) => void;\nif (DEBUG) {\n // using bind means that we get to keep useful line numbers in the console\n debuglog = logger.log.bind(logger);\n} else {\n /* istanbul ignore next */\n debuglog = function (): void {};\n}\n\ninterface IOpts {\n // Set to true to enable improved timeline support.\n timelineSupport?: boolean;\n // The filter object, if any, for this timelineSet.\n filter?: Filter;\n pendingEvents?: boolean;\n}\n\nexport enum DuplicateStrategy {\n Ignore = \"ignore\",\n Replace = \"replace\",\n}\n\nexport interface IRoomTimelineData {\n // the timeline the event was added to/removed from\n timeline: EventTimeline;\n // true if the event was a real-time event added to the end of the live timeline\n liveEvent?: boolean;\n}\n\nexport interface IAddEventToTimelineOptions\n extends Pick<IAddEventOptions, \"toStartOfTimeline\" | \"roomState\" | \"timelineWasEmpty\"> {\n /** Whether the sync response came from cache */\n fromCache?: boolean;\n}\n\nexport interface IAddLiveEventOptions\n extends Pick<IAddEventToTimelineOptions, \"fromCache\" | \"roomState\" | \"timelineWasEmpty\"> {\n /** Applies to events in the timeline only. If this is 'replace' then if a\n * duplicate is encountered, the event passed to this function will replace\n * the existing event in the timeline. If this is not specified, or is\n * 'ignore', then the event passed to this function will be ignored\n * entirely, preserving the existing event in the timeline. Events are\n * identical based on their event ID <b>only</b>. */\n duplicateStrategy?: DuplicateStrategy;\n}\n\ntype EmittedEvents = RoomEvent.Timeline | RoomEvent.TimelineReset;\n\nexport type EventTimelineSetHandlerMap = {\n /**\n * Fires whenever the timeline in a room is updated.\n * @param event - The matrix event which caused this event to fire.\n * @param room - The room, if any, whose timeline was updated.\n * @param toStartOfTimeline - True if this event was added to the start\n * @param removed - True if this event has just been removed from the timeline\n * (beginning; oldest) of the timeline e.g. due to pagination.\n *\n * @param data - more data about the event\n *\n * @example\n * ```\n * matrixClient.on(\"Room.timeline\",\n * function(event, room, toStartOfTimeline, removed, data) {\n * if (!toStartOfTimeline && data.liveEvent) {\n * var messageToAppend = room.timeline.[room.timeline.length - 1];\n * }\n * });\n * ```\n */\n [RoomEvent.Timeline]: (\n event: MatrixEvent,\n room: Room | undefined,\n toStartOfTimeline: boolean | undefined,\n removed: boolean,\n data: IRoomTimelineData,\n ) => void;\n /**\n * Fires whenever the live timeline in a room is reset.\n *\n * When we get a 'limited' sync (for example, after a network outage), we reset\n * the live timeline to be empty before adding the recent events to the new\n * timeline. This event is fired after the timeline is reset, and before the\n * new events are added.\n *\n * @param room - The room whose live timeline was reset, if any\n * @param timelineSet - timelineSet room whose live timeline was reset\n * @param resetAllTimelines - True if all timelines were reset.\n */\n [RoomEvent.TimelineReset]: (\n room: Room | undefined,\n eventTimelineSet: EventTimelineSet,\n resetAllTimelines: boolean,\n ) => void;\n};\n\nexport class EventTimelineSet extends TypedEventEmitter<EmittedEvents, EventTimelineSetHandlerMap> {\n public readonly relations: RelationsContainer;\n private readonly timelineSupport: boolean;\n private readonly displayPendingEvents: boolean;\n private liveTimeline: EventTimeline;\n private timelines: EventTimeline[];\n private _eventIdToTimeline = new Map<string, EventTimeline>();\n private filter?: Filter;\n\n /**\n * Construct a set of EventTimeline objects, typically on behalf of a given\n * room. A room may have multiple EventTimelineSets for different levels\n * of filtering. The global notification list is also an EventTimelineSet, but\n * lacks a room.\n *\n * <p>This is an ordered sequence of timelines, which may or may not\n * be continuous. Each timeline lists a series of events, as well as tracking\n * the room state at the start and the end of the timeline (if appropriate).\n * It also tracks forward and backward pagination tokens, as well as containing\n * links to the next timeline in the sequence.\n *\n * <p>There is one special timeline - the 'live' timeline, which represents the\n * timeline to which events are being added in real-time as they are received\n * from the /sync API. Note that you should not retain references to this\n * timeline - even if it is the current timeline right now, it may not remain\n * so if the server gives us a timeline gap in /sync.\n *\n * <p>In order that we can find events from their ids later, we also maintain a\n * map from event_id to timeline and index.\n *\n * @param room - Room for this timelineSet. May be null for non-room cases, such as the\n * notification timeline.\n * @param opts - Options inherited from Room.\n * @param client - the Matrix client which owns this EventTimelineSet,\n * can be omitted if room is specified.\n * @param thread - the thread to which this timeline set relates.\n * @param isThreadTimeline - Whether this timeline set relates to a thread list timeline\n * (e.g., All threads or My threads)\n */\n public constructor(\n public readonly room: Room | undefined,\n opts: IOpts = {},\n client?: MatrixClient,\n public readonly thread?: Thread,\n public readonly threadListType: ThreadFilterType | null = null,\n ) {\n super();\n\n this.timelineSupport = Boolean(opts.timelineSupport);\n this.liveTimeline = new EventTimeline(this);\n this.displayPendingEvents = opts.pendingEvents !== false;\n\n // just a list - *not* ordered.\n this.timelines = [this.liveTimeline];\n this._eventIdToTimeline = new Map<string, EventTimeline>();\n\n this.filter = opts.filter;\n\n this.relations = this.room?.relations ?? new RelationsContainer(room?.client ?? client!);\n }\n\n /**\n * Get all the timelines in this set\n * @returns the timelines in this set\n */\n public getTimelines(): EventTimeline[] {\n return this.timelines;\n }\n\n /**\n * Get the filter object this timeline set is filtered on, if any\n * @returns the optional filter for this timelineSet\n */\n public getFilter(): Filter | undefined {\n return this.filter;\n }\n\n /**\n * Set the filter object this timeline set is filtered on\n * (passed to the server when paginating via /messages).\n * @param filter - the filter for this timelineSet\n */\n public setFilter(filter?: Filter): void {\n this.filter = filter;\n }\n\n /**\n * Get the list of pending sent events for this timelineSet's room, filtered\n * by the timelineSet's filter if appropriate.\n *\n * @returns A list of the sent events\n * waiting for remote echo.\n *\n * @throws If `opts.pendingEventOrdering` was not 'detached'\n */\n public getPendingEvents(): MatrixEvent[] {\n if (!this.room || !this.displayPendingEvents) {\n return [];\n }\n\n return this.room.getPendingEvents();\n }\n /**\n * Get the live timeline for this room.\n *\n * @returns live timeline\n */\n public getLiveTimeline(): EventTimeline {\n return this.liveTimeline;\n }\n\n /**\n * Set the live timeline for this room.\n *\n * @returns live timeline\n */\n public setLiveTimeline(timeline: EventTimeline): void {\n this.liveTimeline = timeline;\n }\n\n /**\n * Return the timeline (if any) this event is in.\n * @param eventId - the eventId being sought\n * @returns timeline\n */\n public eventIdToTimeline(eventId: string): EventTimeline | undefined {\n return this._eventIdToTimeline.get(eventId);\n }\n\n /**\n * Track a new event as if it were in the same timeline as an old event,\n * replacing it.\n * @param oldEventId - event ID of the original event\n * @param newEventId - event ID of the replacement event\n */\n public replaceEventId(oldEventId: string, newEventId: string): void {\n const existingTimeline = this._eventIdToTimeline.get(oldEventId);\n if (existingTimeline) {\n this._eventIdToTimeline.delete(oldEventId);\n this._eventIdToTimeline.set(newEventId, existingTimeline);\n }\n }\n\n /**\n * Reset the live timeline, and start a new one.\n *\n * <p>This is used when /sync returns a 'limited' timeline.\n *\n * @param backPaginationToken - token for back-paginating the new timeline\n * @param forwardPaginationToken - token for forward-paginating the old live timeline,\n * if absent or null, all timelines are reset.\n *\n * @remarks\n * Fires {@link RoomEvent.TimelineReset}\n */\n public resetLiveTimeline(backPaginationToken?: string, forwardPaginationToken?: string): void {\n // Each EventTimeline has RoomState objects tracking the state at the start\n // and end of that timeline. The copies at the end of the live timeline are\n // special because they will have listeners attached to monitor changes to\n // the current room state, so we move this RoomState from the end of the\n // current live timeline to the end of the new one and, if necessary,\n // replace it with a newly created one. We also make a copy for the start\n // of the new timeline.\n\n // if timeline support is disabled, forget about the old timelines\n const resetAllTimelines = !this.timelineSupport || !forwardPaginationToken;\n\n const oldTimeline = this.liveTimeline;\n const newTimeline = resetAllTimelines\n ? oldTimeline.forkLive(EventTimeline.FORWARDS)\n : oldTimeline.fork(EventTimeline.FORWARDS);\n\n if (resetAllTimelines) {\n this.timelines = [newTimeline];\n this._eventIdToTimeline = new Map<string, EventTimeline>();\n } else {\n this.timelines.push(newTimeline);\n }\n\n if (forwardPaginationToken) {\n // Now set the forward pagination token on the old live timeline\n // so it can be forward-paginated.\n oldTimeline.setPaginationToken(forwardPaginationToken, EventTimeline.FORWARDS);\n }\n\n // make sure we set the pagination token before firing timelineReset,\n // otherwise clients which start back-paginating will fail, and then get\n // stuck without realising that they *can* back-paginate.\n newTimeline.setPaginationToken(backPaginationToken ?? null, EventTimeline.BACKWARDS);\n\n // Now we can swap the live timeline to the new one.\n this.liveTimeline = newTimeline;\n this.emit(RoomEvent.TimelineReset, this.room, this, resetAllTimelines);\n }\n\n /**\n * Get the timeline which contains the given event, if any\n *\n * @param eventId - event ID to look for\n * @returns timeline containing\n * the given event, or null if unknown\n */\n public getTimelineForEvent(eventId?: string): EventTimeline | null {\n if (eventId === null || eventId === undefined) {\n return null;\n }\n const res = this._eventIdToTimeline.get(eventId);\n return res === undefined ? null : res;\n }\n\n /**\n * Get an event which is stored in our timelines\n *\n * @param eventId - event ID to look for\n * @returns the given event, or undefined if unknown\n */\n public findEventById(eventId: string): MatrixEvent | undefined {\n const tl = this.getTimelineForEvent(eventId);\n if (!tl) {\n return undefined;\n }\n return tl.getEvents().find(function (ev) {\n return ev.getId() == eventId;\n });\n }\n\n /**\n * Add a new timeline to this timeline list\n *\n * @returns newly-created timeline\n */\n public addTimeline(): EventTimeline {\n if (!this.timelineSupport) {\n throw new Error(\n \"timeline support is disabled. Set the 'timelineSupport'\" +\n \" parameter to true when creating MatrixClient to enable\" +\n \" it.\",\n );\n }\n\n const timeline = new EventTimeline(this);\n this.timelines.push(timeline);\n return timeline;\n }\n\n /**\n * Add events to a timeline\n *\n * <p>Will fire \"Room.timeline\" for each event added.\n *\n * @param events - A list of events to add.\n *\n * @param toStartOfTimeline - True to add these events to the start\n * (oldest) instead of the end (newest) of the timeline. If true, the oldest\n * event will be the <b>last</b> element of 'events'.\n *\n * @param timeline - timeline to\n * add events to.\n *\n * @param paginationToken - token for the next batch of events\n *\n * @remarks\n * Fires {@link RoomEvent.Timeline}\n *\n */\n public addEventsToTimeline(\n events: MatrixEvent[],\n toStartOfTimeline: boolean,\n timeline: EventTimeline,\n paginationToken?: string | null,\n ): void {\n if (!timeline) {\n throw new Error(\"'timeline' not specified for EventTimelineSet.addEventsToTimeline\");\n }\n\n if (!toStartOfTimeline && timeline == this.liveTimeline) {\n throw new Error(\n \"EventTimelineSet.addEventsToTimeline cannot be used for adding events to \" +\n \"the live timeline - use Room.addLiveEvents instead\",\n );\n }\n\n if (this.filter) {\n events = this.filter.filterRoomTimeline(events);\n if (!events.length) {\n return;\n }\n }\n\n const direction = toStartOfTimeline ? EventTimeline.BACKWARDS : EventTimeline.FORWARDS;\n const inverseDirection = toStartOfTimeline ? EventTimeline.FORWARDS : EventTimeline.BACKWARDS;\n\n // Adding events to timelines can be quite complicated. The following\n // illustrates some of the corner-cases.\n //\n // Let's say we start by knowing about four timelines. timeline3 and\n // timeline4 are neighbours:\n //\n // timeline1 timeline2 timeline3 timeline4\n // [M] [P] [S] <------> [T]\n //\n // Now we paginate timeline1, and get the following events from the server:\n // [M, N, P, R, S, T, U].\n //\n // 1. First, we ignore event M, since we already know about it.\n //\n // 2. Next, we append N to timeline 1.\n //\n // 3. Next, we don't add event P, since we already know about it,\n // but we do link together the timelines. We now have:\n //\n // timeline1 timeline2 timeline3 timeline4\n // [M, N] <---> [P] [S] <------> [T]\n //\n // 4. Now we add event R to timeline2:\n //\n // timeline1 timeline2 timeline3 timeline4\n // [M, N] <---> [P, R] [S] <------> [T]\n //\n // Note that we have switched the timeline we are working on from\n // timeline1 to timeline2.\n //\n // 5. We ignore event S, but again join the timelines:\n //\n // timeline1 timeline2 timeline3 timeline4\n // [M, N] <---> [P, R] <---> [S] <------> [T]\n //\n // 6. We ignore event T, and the timelines are already joined, so there\n // is nothing to do.\n //\n // 7. Finally, we add event U to timeline4:\n //\n // timeline1 timeline2 timeline3 timeline4\n // [M, N] <---> [P, R] <---> [S] <------> [T, U]\n //\n // The important thing to note in the above is what happened when we\n // already knew about a given event:\n //\n // - if it was appropriate, we joined up the timelines (steps 3, 5).\n // - in any case, we started adding further events to the timeline which\n // contained the event we knew about (steps 3, 5, 6).\n //\n //\n // So much for adding events to the timeline. But what do we want to do\n // with the pagination token?\n //\n // In the case above, we will be given a pagination token which tells us how to\n // get events beyond 'U' - in this case, it makes sense to store this\n // against timeline4. But what if timeline4 already had 'U' and beyond? in\n // that case, our best bet is to throw away the pagination token we were\n // given and stick with whatever token timeline4 had previously. In short,\n // we want to only store the pagination token if the last event we receive\n // is one we didn't previously know about.\n //\n // We make an exception for this if it turns out that we already knew about\n // *all* of the events, and we weren't able to join up any timelines. When\n // that happens, it means our existing pagination token is faulty, since it\n // is only telling us what we already know. Rather than repeatedly\n // paginating with the same token, we might as well use the new pagination\n // token in the hope that we eventually work our way out of the mess.\n\n let didUpdate = false;\n let lastEventWasNew = false;\n for (const event of events) {\n const eventId = event.getId()!;\n\n const existingTimeline = this._eventIdToTimeline.get(eventId);\n\n if (!existingTimeline) {\n // we don't know about this event yet. Just add it to the timeline.\n this.addEventToTimeline(event, timeline, {\n toStartOfTimeline,\n });\n lastEventWasNew = true;\n didUpdate = true;\n continue;\n }\n\n lastEventWasNew = false;\n\n if (existingTimeline == timeline) {\n debuglog(\"Event \" + eventId + \" already in timeline \" + timeline);\n continue;\n }\n\n const neighbour = timeline.getNeighbouringTimeline(direction);\n if (neighbour) {\n // this timeline already has a neighbour in the relevant direction;\n // let's assume the timelines are already correctly linked up, and\n // skip over to it.\n //\n // there's probably some edge-case here where we end up with an\n // event which is in a timeline a way down the chain, and there is\n // a break in the chain somewhere. But I can't really imagine how\n // that would happen, so I'm going to ignore it for now.\n //\n if (existingTimeline == neighbour) {\n debuglog(\"Event \" + eventId + \" in neighbouring timeline - \" + \"switching to \" + existingTimeline);\n } else {\n debuglog(\"Event \" + eventId + \" already in a different \" + \"timeline \" + existingTimeline);\n }\n timeline = existingTimeline;\n continue;\n }\n\n // time to join the timelines.\n logger.info(\n \"Already have timeline for \" + eventId + \" - joining timeline \" + timeline + \" to \" + existingTimeline,\n );\n\n // Variables to keep the line length limited below.\n const existingIsLive = existingTimeline === this.liveTimeline;\n const timelineIsLive = timeline === this.liveTimeline;\n\n const backwardsIsLive = direction === EventTimeline.BACKWARDS && existingIsLive;\n const forwardsIsLive = direction === EventTimeline.FORWARDS && timelineIsLive;\n\n if (backwardsIsLive || forwardsIsLive) {\n // The live timeline should never be spliced into a non-live position.\n // We use independent logging to better discover the problem at a glance.\n if (backwardsIsLive) {\n logger.warn(\n \"Refusing to set a preceding existingTimeLine on our \" +\n \"timeline as the existingTimeLine is live (\" +\n existingTimeline +\n \")\",\n );\n }\n if (forwardsIsLive) {\n logger.warn(\n \"Refusing to set our preceding timeline on a existingTimeLine \" +\n \"as our timeline is live (\" +\n timeline +\n \")\",\n );\n }\n continue; // abort splicing - try next event\n }\n\n timeline.setNeighbouringTimeline(existingTimeline, direction);\n existingTimeline.setNeighbouringTimeline(timeline, inverseDirection);\n\n timeline = existingTimeline;\n didUpdate = true;\n }\n\n // see above - if the last event was new to us, or if we didn't find any\n // new information, we update the pagination token for whatever\n // timeline we ended up on.\n if (lastEventWasNew || !didUpdate) {\n if (direction === EventTimeline.FORWARDS && timeline === this.liveTimeline) {\n logger.warn({ lastEventWasNew, didUpdate }); // for debugging\n logger.warn(\n `Refusing to set forwards pagination token of live timeline ` + `${timeline} to ${paginationToken}`,\n );\n return;\n }\n timeline.setPaginationToken(paginationToken ?? null, direction);\n }\n }\n\n /**\n * Add an event to the end of this live timeline.\n *\n * @param event - Event to be added\n * @param options - addLiveEvent options\n */\n public addLiveEvent(\n event: MatrixEvent,\n { duplicateStrategy, fromCache, roomState, timelineWasEmpty }: IAddLiveEventOptions,\n ): void;\n /**\n * @deprecated In favor of the overload with `IAddLiveEventOptions`\n */\n public addLiveEvent(\n event: MatrixEvent,\n duplicateStrategy?: DuplicateStrategy,\n fromCache?: boolean,\n roomState?: RoomState,\n ): void;\n public addLiveEvent(\n event: MatrixEvent,\n duplicateStrategyOrOpts?: DuplicateStrategy | IAddLiveEventOptions,\n fromCache = false,\n roomState?: RoomState,\n ): void {\n let duplicateStrategy = (duplicateStrategyOrOpts as DuplicateStrategy) || DuplicateStrategy.Ignore;\n let timelineWasEmpty: boolean | undefined;\n if (typeof duplicateStrategyOrOpts === \"object\") {\n ({\n duplicateStrategy = DuplicateStrategy.Ignore,\n fromCache = false,\n roomState,\n timelineWasEmpty,\n } = duplicateStrategyOrOpts);\n } else if (duplicateStrategyOrOpts !== undefined) {\n // Deprecation warning\n // FIXME: Remove after 2023-06-01 (technical debt)\n logger.warn(\n \"Overload deprecated: \" +\n \"`EventTimelineSet.addLiveEvent(event, duplicateStrategy?, fromCache?, roomState?)` \" +\n \"is deprecated in favor of the overload with \" +\n \"`EventTimelineSet.addLiveEvent(event, IAddLiveEventOptions)`\",\n );\n }\n\n if (this.filter) {\n const events = this.filter.filterRoomTimeline([event]);\n if (!events.length) {\n return;\n }\n }\n\n const timeline = this._eventIdToTimeline.get(event.getId()!);\n if (timeline) {\n if (duplicateStrategy === DuplicateStrategy.Replace) {\n debuglog(\"EventTimelineSet.addLiveEvent: replacing duplicate event \" + event.getId());\n const tlEvents = timeline.getEvents();\n for (let j = 0; j < tlEvents.length; j++) {\n if (tlEvents[j].getId() === event.getId()) {\n // still need to set the right metadata on this event\n if (!roomState) {\n roomState = timeline.getState(EventTimeline.FORWARDS);\n }\n EventTimeline.setEventMetadata(event, roomState!, false);\n tlEvents[j] = event;\n\n // XXX: we need to fire an event when this happens.\n break;\n }\n }\n } else {\n debuglog(\"EventTimelineSet.addLiveEvent: ignoring duplicate event \" + event.getId());\n }\n return;\n }\n\n this.addEventToTimeline(event, this.liveTimeline, {\n toStartOfTimeline: false,\n fromCache,\n roomState,\n timelineWasEmpty,\n });\n }\n\n /**\n * Add event to the given timeline, and emit Room.timeline. Assumes\n * we have already checked we don't know about this event.\n *\n * Will fire \"Room.timeline\" for each event added.\n *\n * @param options - addEventToTimeline options\n *\n * @remarks\n * Fires {@link RoomEvent.Timeline}\n */\n public addEventToTimeline(\n event: MatrixEvent,\n timeline: EventTimeline,\n { toStartOfTimeline, fromCache, roomState, timelineWasEmpty }: IAddEventToTimelineOptions,\n ): void;\n /**\n * @deprecated In favor of the overload with `IAddEventToTimelineOptions`\n */\n public addEventToTimeline(\n event: MatrixEvent,\n timeline: EventTimeline,\n toStartOfTimeline: boolean,\n fromCache?: boolean,\n roomState?: RoomState,\n ): void;\n public addEventToTimeline(\n event: MatrixEvent,\n timeline: EventTimeline,\n toStartOfTimelineOrOpts: boolean | IAddEventToTimelineOptions,\n fromCache = false,\n roomState?: RoomState,\n ): void {\n let toStartOfTimeline = !!toStartOfTimelineOrOpts;\n let timelineWasEmpty: boolean | undefined;\n if (typeof toStartOfTimelineOrOpts === \"object\") {\n ({ toStartOfTimeline, fromCache = false, roomState, timelineWasEmpty } = toStartOfTimelineOrOpts);\n } else if (toStartOfTimelineOrOpts !== undefined) {\n // Deprecation warning\n // FIXME: Remove after 2023-06-01 (technical debt)\n logger.warn(\n \"Overload deprecated: \" +\n \"`EventTimelineSet.addEventToTimeline(event, timeline, toStartOfTimeline, fromCache?, roomState?)` \" +\n \"is deprecated in favor of the overload with \" +\n \"`EventTimelineSet.addEventToTimeline(event, timeline, IAddEventToTimelineOptions)`\",\n );\n }\n\n if (timeline.getTimelineSet() !== this) {\n throw new Error(`EventTimelineSet.addEventToTimeline: Timeline=${timeline.toString()} does not belong \" +\n \"in timelineSet(threadId=${this.thread?.id})`);\n }\n\n // Make sure events don't get mixed in timelines they shouldn't be in (e.g. a\n // threaded message should not be in the main timeline).\n //\n // We can only run this check for timelines with a `room` because `canContain`\n // requires it\n if (this.room && !this.canContain(event)) {\n let eventDebugString = `event=${event.getId()}`;\n if (event.threadRootId) {\n eventDebugString += `(belongs to thread=${event.threadRootId})`;\n }\n logger.warn(\n `EventTimelineSet.addEventToTimeline: Ignoring ${eventDebugString} that does not belong ` +\n `in timeline=${timeline.toString()} timelineSet(threadId=${this.thread?.id})`,\n );\n return;\n }\n\n const eventId = event.getId()!;\n timeline.addEvent(event, {\n toStartOfTimeline,\n roomState,\n timelineWasEmpty,\n });\n this._eventIdToTimeline.set(eventId, timeline);\n\n this.relations.aggregateParentEvent(event);\n this.relations.aggregateChildEvent(event, this);\n\n const data: IRoomTimelineData = {\n timeline: timeline,\n liveEvent: !toStartOfTimeline && timeline == this.liveTimeline && !fromCache,\n };\n this.emit(RoomEvent.Timeline, event, this.room, Boolean(toStartOfTimeline), false, data);\n }\n\n /**\n * Replaces event with ID oldEventId with one with newEventId, if oldEventId is\n * recognised. Otherwise, add to the live timeline. Used to handle remote echos.\n *\n * @param localEvent - the new event to be added to the timeline\n * @param oldEventId - the ID of the original event\n * @param newEventId - the ID of the replacement event\n *\n * @remarks\n * Fires {@link RoomEvent.Timeline}\n */\n public handleRemoteEcho(localEvent: MatrixEvent, oldEventId: string, newEventId: string): void {\n // XXX: why don't we infer newEventId from localEvent?\n const existingTimeline = this._eventIdToTimeline.get(oldEventId);\n if (existingTimeline) {\n this._eventIdToTimeline.delete(oldEventId);\n this._eventIdToTimeline.set(newEventId, existingTimeline);\n } else if (!this.filter || this.filter.filterRoomTimeline([localEvent]).length) {\n this.addEventToTimeline(localEvent, this.liveTimeline, {\n toStartOfTimeline: false,\n });\n }\n }\n\n /**\n * Removes a single event from this room.\n *\n * @param eventId - The id of the event to remove\n *\n * @returns the removed event, or null if the event was not found\n * in this room.\n */\n public removeEvent(eventId: string): MatrixEvent | null {\n const timeline = this._eventIdToTimeline.get(eventId);\n if (!timeline) {\n return null;\n }\n\n const removed = timeline.removeEvent(eventId);\n if (removed) {\n this._eventIdToTimeline.delete(eventId);\n const data = {\n timeline: timeline,\n };\n this.emit(RoomEvent.Timeline, removed, this.room, undefined, true, data);\n }\n return removed;\n }\n\n /**\n * Determine where two events appear in the timeline relative to one another\n *\n * @param eventId1 - The id of the first event\n * @param eventId2 - The id of the second event\n\n * @returns a number less than zero if eventId1 precedes eventId2, and\n * greater than zero if eventId1 succeeds eventId2. zero if they are the\n * same event; null if we can't tell (either because we don't know about one\n * of the events, or because they are in separate timelines which don't join\n * up).\n */\n public compareEventOrdering(eventId1: string, eventId2: string): number | null {\n if (eventId1 == eventId2) {\n // optimise this case\n return 0;\n }\n\n const timeline1 = this._eventIdToTimeline.get(eventId1);\n const timeline2 = this._eventIdToTimeline.get(eventId2);\n\n if (timeline1 === undefined) {\n return null;\n }\n if (timeline2 === undefined) {\n return null;\n }\n\n if (timeline1 === timeline2) {\n // both events are in the same timeline - figure out their relative indices\n let idx1: number | undefined = undefined;\n let idx2: number | undefined = undefined;\n const events = timeline1.getEvents();\n for (let idx = 0; idx < events.length && (idx1 === undefined || idx2 === undefined); idx++) {\n const evId = events[idx].getId();\n if (evId == eventId1) {\n idx1 = idx;\n }\n if (evId == eventId2) {\n idx2 = idx;\n }\n }\n return idx1! - idx2!;\n }\n\n // the events are in different timelines. Iterate through the\n // linkedlist to see which comes first.\n\n // first work forwards from timeline1\n let tl: EventTimeline | null = timeline1;\n while (tl) {\n if (tl === timeline2) {\n // timeline1 is before timeline2\n return -1;\n }\n tl = tl.getNeighbouringTimeline(EventTimeline.FORWARDS);\n }\n\n // now try backwards from timeline1\n tl = timeline1;\n while (tl) {\n if (tl === timeline2) {\n // timeline2 is before timeline1\n return 1;\n }\n tl = tl.getNeighbouringTimeline(EventTimeline.BACKWARDS);\n }\n\n // the timelines are not contiguous.\n return null;\n }\n\n /**\n * Determine whether a given event can sanely be added to this event timeline set,\n * for timeline sets relating to a thread, only return true for events in the same\n * thread timeline, for timeline sets not relating to a thread only return true\n * for events which should be shown in the main room timeline.\n * Requires the `room` property to have been set at EventTimelineSet construction time.\n *\n * @param event - the event to check whether it belongs to this timeline set.\n * @throws Error if `room` was not set when constructing this timeline set.\n * @returns whether the event belongs to this timeline set.\n */\n public canContain(event: MatrixEvent): boolean {\n if (!this.room) {\n throw new Error(\n \"Cannot call `EventTimelineSet::canContain without a `room` set. \" +\n \"Set the room when creating the EventTimelineSet to call this method.\",\n );\n }\n\n const { threadId, shouldLiveInRoom } = this.room.eventShouldLiveIn(event);\n\n if (this.thread) {\n return this.thread.id === threadId;\n }\n return shouldLiveInRoom;\n }\n}\n"],"mappings":"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"} \ No newline at end of file
diff --git a/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/event-timeline.d.ts b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/event-timeline.d.ts
new file mode 100644
index 0000000..b6ab2eb
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/event-timeline.d.ts
@@ -0,0 +1,211 @@
+import { IMarkerFoundOptions, RoomState } from "./room-state";
+import { EventTimelineSet } from "./event-timeline-set";
+import { MatrixEvent } from "./event";
+import { Filter } from "../filter";
+export interface IInitialiseStateOptions extends Pick<IMarkerFoundOptions, "timelineWasEmpty"> {
+}
+export interface IAddEventOptions extends Pick<IMarkerFoundOptions, "timelineWasEmpty"> {
+ /** Whether to insert the new event at the start of the timeline where the
+ * oldest events are (timeline is in chronological order, oldest to most
+ * recent) */
+ toStartOfTimeline: boolean;
+ /** The state events to reconcile metadata from */
+ roomState?: RoomState;
+}
+export declare enum Direction {
+ Backward = "b",
+ Forward = "f"
+}
+export declare class EventTimeline {
+ private readonly eventTimelineSet;
+ /**
+ * Symbolic constant for methods which take a 'direction' argument:
+ * refers to the start of the timeline, or backwards in time.
+ */
+ static readonly BACKWARDS = Direction.Backward;
+ /**
+ * Symbolic constant for methods which take a 'direction' argument:
+ * refers to the end of the timeline, or forwards in time.
+ */
+ static readonly FORWARDS = Direction.Forward;
+ /**
+ * Static helper method to set sender and target properties
+ *
+ * @param event - the event whose metadata is to be set
+ * @param stateContext - the room state to be queried
+ * @param toStartOfTimeline - if true the event's forwardLooking flag is set false
+ */
+ static setEventMetadata(event: MatrixEvent, stateContext: RoomState, toStartOfTimeline: boolean): void;
+ private readonly roomId;
+ private readonly name;
+ private events;
+ private baseIndex;
+ private startState?;
+ private endState?;
+ private startToken;
+ private endToken;
+ private prevTimeline;
+ private nextTimeline;
+ paginationRequests: Record<Direction, Promise<boolean> | null>;
+ /**
+ * Construct a new EventTimeline
+ *
+ * <p>An EventTimeline represents a contiguous sequence of events in a room.
+ *
+ * <p>As well as keeping track of the events themselves, it stores the state of
+ * the room at the beginning and end of the timeline, and pagination tokens for
+ * going backwards and forwards in the timeline.
+ *
+ * <p>In order that clients can meaningfully maintain an index into a timeline,
+ * the EventTimeline object tracks a 'baseIndex'. This starts at zero, but is
+ * incremented when events are prepended to the timeline. The index of an event
+ * relative to baseIndex therefore remains constant.
+ *
+ * <p>Once a timeline joins up with its neighbour, they are linked together into a
+ * doubly-linked list.
+ *
+ * @param eventTimelineSet - the set of timelines this is part of
+ */
+ constructor(eventTimelineSet: EventTimelineSet);
+ /**
+ * Initialise the start and end state with the given events
+ *
+ * <p>This can only be called before any events are added.
+ *
+ * @param stateEvents - list of state events to initialise the
+ * state with.
+ * @throws Error if an attempt is made to call this after addEvent is called.
+ */
+ initialiseState(stateEvents: MatrixEvent[], { timelineWasEmpty }?: IInitialiseStateOptions): void;
+ /**
+ * Forks the (live) timeline, taking ownership of the existing directional state of this timeline.
+ * All attached listeners will keep receiving state updates from the new live timeline state.
+ * The end state of this timeline gets replaced with an independent copy of the current RoomState,
+ * and will need a new pagination token if it ever needs to paginate forwards.
+
+ * @param direction - EventTimeline.BACKWARDS to get the state at the
+ * start of the timeline; EventTimeline.FORWARDS to get the state at the end
+ * of the timeline.
+ *
+ * @returns the new timeline
+ */
+ forkLive(direction: Direction): EventTimeline;
+ /**
+ * Creates an independent timeline, inheriting the directional state from this timeline.
+ *
+ * @param direction - EventTimeline.BACKWARDS to get the state at the
+ * start of the timeline; EventTimeline.FORWARDS to get the state at the end
+ * of the timeline.
+ *
+ * @returns the new timeline
+ */
+ fork(direction: Direction): EventTimeline;
+ /**
+ * Get the ID of the room for this timeline
+ * @returns room ID
+ */
+ getRoomId(): string | null;
+ /**
+ * Get the filter for this timeline's timelineSet (if any)
+ * @returns filter
+ */
+ getFilter(): Filter | undefined;
+ /**
+ * Get the timelineSet for this timeline
+ * @returns timelineSet
+ */
+ getTimelineSet(): EventTimelineSet;
+ /**
+ * Get the base index.
+ *
+ * <p>This is an index which is incremented when events are prepended to the
+ * timeline. An individual event therefore stays at the same index in the array
+ * relative to the base index (although note that a given event's index may
+ * well be less than the base index, thus giving that event a negative relative
+ * index).
+ */
+ getBaseIndex(): number;
+ /**
+ * Get the list of events in this context
+ *
+ * @returns An array of MatrixEvents
+ */
+ getEvents(): MatrixEvent[];
+ /**
+ * Get the room state at the start/end of the timeline
+ *
+ * @param direction - EventTimeline.BACKWARDS to get the state at the
+ * start of the timeline; EventTimeline.FORWARDS to get the state at the end
+ * of the timeline.
+ *
+ * @returns state at the start/end of the timeline
+ */
+ getState(direction: Direction): RoomState | undefined;
+ /**
+ * Get a pagination token
+ *
+ * @param direction - EventTimeline.BACKWARDS to get the pagination
+ * token for going backwards in time; EventTimeline.FORWARDS to get the
+ * pagination token for going forwards in time.
+ *
+ * @returns pagination token
+ */
+ getPaginationToken(direction: Direction): string | null;
+ /**
+ * Set a pagination token
+ *
+ * @param token - pagination token
+ *
+ * @param direction - EventTimeline.BACKWARDS to set the pagination
+ * token for going backwards in time; EventTimeline.FORWARDS to set the
+ * pagination token for going forwards in time.
+ */
+ setPaginationToken(token: string | null, direction: Direction): void;
+ /**
+ * Get the next timeline in the series
+ *
+ * @param direction - EventTimeline.BACKWARDS to get the previous
+ * timeline; EventTimeline.FORWARDS to get the next timeline.
+ *
+ * @returns previous or following timeline, if they have been
+ * joined up.
+ */
+ getNeighbouringTimeline(direction: Direction): EventTimeline | null;
+ /**
+ * Set the next timeline in the series
+ *
+ * @param neighbour - previous/following timeline
+ *
+ * @param direction - EventTimeline.BACKWARDS to set the previous
+ * timeline; EventTimeline.FORWARDS to set the next timeline.
+ *
+ * @throws Error if an attempt is made to set the neighbouring timeline when
+ * it is already set.
+ */
+ setNeighbouringTimeline(neighbour: EventTimeline, direction: Direction): void;
+ /**
+ * Add a new event to the timeline, and update the state
+ *
+ * @param event - new event
+ * @param options - addEvent options
+ */
+ addEvent(event: MatrixEvent, { toStartOfTimeline, roomState, timelineWasEmpty }: IAddEventOptions): void;
+ /**
+ * @deprecated In favor of the overload with `IAddEventOptions`
+ */
+ addEvent(event: MatrixEvent, toStartOfTimeline: boolean, roomState?: RoomState): void;
+ /**
+ * Remove an event from the timeline
+ *
+ * @param eventId - ID of event to be removed
+ * @returns removed event, or null if not found
+ */
+ removeEvent(eventId: string): MatrixEvent | null;
+ /**
+ * Return a string to identify this timeline, for debugging
+ *
+ * @returns name for this timeline
+ */
+ toString(): string;
+}
+//# sourceMappingURL=event-timeline.d.ts.map \ No newline at end of file
diff --git a/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/event-timeline.d.ts.map b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/event-timeline.d.ts.map
new file mode 100644
index 0000000..4b39d51
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/event-timeline.d.ts.map
@@ -0,0 +1 @@
+{"version":3,"file":"event-timeline.d.ts","sourceRoot":"","sources":["../../src/models/event-timeline.ts"],"names":[],"mappings":"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"} \ No newline at end of file
diff --git a/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/event-timeline.js b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/event-timeline.js
new file mode 100644
index 0000000..9857888
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/event-timeline.js
@@ -0,0 +1,433 @@
+"use strict";
+
+var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.EventTimeline = exports.Direction = void 0;
+var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
+var _logger = require("../logger");
+var _roomState2 = require("./room-state");
+var _event = require("../@types/event");
+/*
+Copyright 2016 - 2021 The Matrix.org Foundation C.I.C.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+let Direction;
+exports.Direction = Direction;
+(function (Direction) {
+ Direction["Backward"] = "b";
+ Direction["Forward"] = "f";
+})(Direction || (exports.Direction = Direction = {}));
+class EventTimeline {
+ /**
+ * Symbolic constant for methods which take a 'direction' argument:
+ * refers to the start of the timeline, or backwards in time.
+ */
+
+ /**
+ * Symbolic constant for methods which take a 'direction' argument:
+ * refers to the end of the timeline, or forwards in time.
+ */
+
+ /**
+ * Static helper method to set sender and target properties
+ *
+ * @param event - the event whose metadata is to be set
+ * @param stateContext - the room state to be queried
+ * @param toStartOfTimeline - if true the event's forwardLooking flag is set false
+ */
+ static setEventMetadata(event, stateContext, toStartOfTimeline) {
+ var _event$sender, _event$sender$events, _event$target, _event$target$events;
+ // When we try to generate a sentinel member before we have that member
+ // in the members object, we still generate a sentinel but it doesn't
+ // have a membership event, so test to see if events.member is set. We
+ // check this to avoid overriding non-sentinel members by sentinel ones
+ // when adding the event to a filtered timeline
+ if (!((_event$sender = event.sender) !== null && _event$sender !== void 0 && (_event$sender$events = _event$sender.events) !== null && _event$sender$events !== void 0 && _event$sender$events.member)) {
+ event.sender = stateContext.getSentinelMember(event.getSender());
+ }
+ if (!((_event$target = event.target) !== null && _event$target !== void 0 && (_event$target$events = _event$target.events) !== null && _event$target$events !== void 0 && _event$target$events.member) && event.getType() === _event.EventType.RoomMember) {
+ event.target = stateContext.getSentinelMember(event.getStateKey());
+ }
+ if (event.isState()) {
+ // room state has no concept of 'old' or 'current', but we want the
+ // room state to regress back to previous values if toStartOfTimeline
+ // is set, which means inspecting prev_content if it exists. This
+ // is done by toggling the forwardLooking flag.
+ if (toStartOfTimeline) {
+ event.forwardLooking = false;
+ }
+ }
+ }
+ /**
+ * Construct a new EventTimeline
+ *
+ * <p>An EventTimeline represents a contiguous sequence of events in a room.
+ *
+ * <p>As well as keeping track of the events themselves, it stores the state of
+ * the room at the beginning and end of the timeline, and pagination tokens for
+ * going backwards and forwards in the timeline.
+ *
+ * <p>In order that clients can meaningfully maintain an index into a timeline,
+ * the EventTimeline object tracks a 'baseIndex'. This starts at zero, but is
+ * incremented when events are prepended to the timeline. The index of an event
+ * relative to baseIndex therefore remains constant.
+ *
+ * <p>Once a timeline joins up with its neighbour, they are linked together into a
+ * doubly-linked list.
+ *
+ * @param eventTimelineSet - the set of timelines this is part of
+ */
+ constructor(eventTimelineSet) {
+ var _eventTimelineSet$roo, _eventTimelineSet$roo2;
+ this.eventTimelineSet = eventTimelineSet;
+ (0, _defineProperty2.default)(this, "roomId", void 0);
+ (0, _defineProperty2.default)(this, "name", void 0);
+ (0, _defineProperty2.default)(this, "events", []);
+ (0, _defineProperty2.default)(this, "baseIndex", 0);
+ (0, _defineProperty2.default)(this, "startState", void 0);
+ (0, _defineProperty2.default)(this, "endState", void 0);
+ (0, _defineProperty2.default)(this, "startToken", null);
+ (0, _defineProperty2.default)(this, "endToken", null);
+ (0, _defineProperty2.default)(this, "prevTimeline", null);
+ (0, _defineProperty2.default)(this, "nextTimeline", null);
+ (0, _defineProperty2.default)(this, "paginationRequests", {
+ [Direction.Backward]: null,
+ [Direction.Forward]: null
+ });
+ this.roomId = (_eventTimelineSet$roo = (_eventTimelineSet$roo2 = eventTimelineSet.room) === null || _eventTimelineSet$roo2 === void 0 ? void 0 : _eventTimelineSet$roo2.roomId) !== null && _eventTimelineSet$roo !== void 0 ? _eventTimelineSet$roo : null;
+ if (this.roomId) {
+ this.startState = new _roomState2.RoomState(this.roomId);
+ this.endState = new _roomState2.RoomState(this.roomId);
+ }
+
+ // this is used by client.js
+ this.paginationRequests = {
+ b: null,
+ f: null
+ };
+ this.name = this.roomId + ":" + new Date().toISOString();
+ }
+
+ /**
+ * Initialise the start and end state with the given events
+ *
+ * <p>This can only be called before any events are added.
+ *
+ * @param stateEvents - list of state events to initialise the
+ * state with.
+ * @throws Error if an attempt is made to call this after addEvent is called.
+ */
+ initialiseState(stateEvents, {
+ timelineWasEmpty
+ } = {}) {
+ var _this$startState, _this$endState;
+ if (this.events.length > 0) {
+ throw new Error("Cannot initialise state after events are added");
+ }
+ (_this$startState = this.startState) === null || _this$startState === void 0 ? void 0 : _this$startState.setStateEvents(stateEvents, {
+ timelineWasEmpty
+ });
+ (_this$endState = this.endState) === null || _this$endState === void 0 ? void 0 : _this$endState.setStateEvents(stateEvents, {
+ timelineWasEmpty
+ });
+ }
+
+ /**
+ * Forks the (live) timeline, taking ownership of the existing directional state of this timeline.
+ * All attached listeners will keep receiving state updates from the new live timeline state.
+ * The end state of this timeline gets replaced with an independent copy of the current RoomState,
+ * and will need a new pagination token if it ever needs to paginate forwards.
+ * @param direction - EventTimeline.BACKWARDS to get the state at the
+ * start of the timeline; EventTimeline.FORWARDS to get the state at the end
+ * of the timeline.
+ *
+ * @returns the new timeline
+ */
+ forkLive(direction) {
+ const forkState = this.getState(direction);
+ const timeline = new EventTimeline(this.eventTimelineSet);
+ timeline.startState = forkState === null || forkState === void 0 ? void 0 : forkState.clone();
+ // Now clobber the end state of the new live timeline with that from the
+ // previous live timeline. It will be identical except that we'll keep
+ // using the same RoomMember objects for the 'live' set of members with any
+ // listeners still attached
+ timeline.endState = forkState;
+ // Firstly, we just stole the current timeline's end state, so it needs a new one.
+ // Make an immutable copy of the state so back pagination will get the correct sentinels.
+ this.endState = forkState === null || forkState === void 0 ? void 0 : forkState.clone();
+ return timeline;
+ }
+
+ /**
+ * Creates an independent timeline, inheriting the directional state from this timeline.
+ *
+ * @param direction - EventTimeline.BACKWARDS to get the state at the
+ * start of the timeline; EventTimeline.FORWARDS to get the state at the end
+ * of the timeline.
+ *
+ * @returns the new timeline
+ */
+ fork(direction) {
+ const forkState = this.getState(direction);
+ const timeline = new EventTimeline(this.eventTimelineSet);
+ timeline.startState = forkState === null || forkState === void 0 ? void 0 : forkState.clone();
+ timeline.endState = forkState === null || forkState === void 0 ? void 0 : forkState.clone();
+ return timeline;
+ }
+
+ /**
+ * Get the ID of the room for this timeline
+ * @returns room ID
+ */
+ getRoomId() {
+ return this.roomId;
+ }
+
+ /**
+ * Get the filter for this timeline's timelineSet (if any)
+ * @returns filter
+ */
+ getFilter() {
+ return this.eventTimelineSet.getFilter();
+ }
+
+ /**
+ * Get the timelineSet for this timeline
+ * @returns timelineSet
+ */
+ getTimelineSet() {
+ return this.eventTimelineSet;
+ }
+
+ /**
+ * Get the base index.
+ *
+ * <p>This is an index which is incremented when events are prepended to the
+ * timeline. An individual event therefore stays at the same index in the array
+ * relative to the base index (although note that a given event's index may
+ * well be less than the base index, thus giving that event a negative relative
+ * index).
+ */
+ getBaseIndex() {
+ return this.baseIndex;
+ }
+
+ /**
+ * Get the list of events in this context
+ *
+ * @returns An array of MatrixEvents
+ */
+ getEvents() {
+ return this.events;
+ }
+
+ /**
+ * Get the room state at the start/end of the timeline
+ *
+ * @param direction - EventTimeline.BACKWARDS to get the state at the
+ * start of the timeline; EventTimeline.FORWARDS to get the state at the end
+ * of the timeline.
+ *
+ * @returns state at the start/end of the timeline
+ */
+ getState(direction) {
+ if (direction == EventTimeline.BACKWARDS) {
+ return this.startState;
+ } else if (direction == EventTimeline.FORWARDS) {
+ return this.endState;
+ } else {
+ throw new Error("Invalid direction '" + direction + "'");
+ }
+ }
+
+ /**
+ * Get a pagination token
+ *
+ * @param direction - EventTimeline.BACKWARDS to get the pagination
+ * token for going backwards in time; EventTimeline.FORWARDS to get the
+ * pagination token for going forwards in time.
+ *
+ * @returns pagination token
+ */
+ getPaginationToken(direction) {
+ if (this.roomId) {
+ return this.getState(direction).paginationToken;
+ } else if (direction === Direction.Backward) {
+ return this.startToken;
+ } else {
+ return this.endToken;
+ }
+ }
+
+ /**
+ * Set a pagination token
+ *
+ * @param token - pagination token
+ *
+ * @param direction - EventTimeline.BACKWARDS to set the pagination
+ * token for going backwards in time; EventTimeline.FORWARDS to set the
+ * pagination token for going forwards in time.
+ */
+ setPaginationToken(token, direction) {
+ if (this.roomId) {
+ this.getState(direction).paginationToken = token;
+ } else if (direction === Direction.Backward) {
+ this.startToken = token;
+ } else {
+ this.endToken = token;
+ }
+ }
+
+ /**
+ * Get the next timeline in the series
+ *
+ * @param direction - EventTimeline.BACKWARDS to get the previous
+ * timeline; EventTimeline.FORWARDS to get the next timeline.
+ *
+ * @returns previous or following timeline, if they have been
+ * joined up.
+ */
+ getNeighbouringTimeline(direction) {
+ if (direction == EventTimeline.BACKWARDS) {
+ return this.prevTimeline;
+ } else if (direction == EventTimeline.FORWARDS) {
+ return this.nextTimeline;
+ } else {
+ throw new Error("Invalid direction '" + direction + "'");
+ }
+ }
+
+ /**
+ * Set the next timeline in the series
+ *
+ * @param neighbour - previous/following timeline
+ *
+ * @param direction - EventTimeline.BACKWARDS to set the previous
+ * timeline; EventTimeline.FORWARDS to set the next timeline.
+ *
+ * @throws Error if an attempt is made to set the neighbouring timeline when
+ * it is already set.
+ */
+ setNeighbouringTimeline(neighbour, direction) {
+ if (this.getNeighbouringTimeline(direction)) {
+ throw new Error("timeline already has a neighbouring timeline - " + "cannot reset neighbour (direction: " + direction + ")");
+ }
+ if (direction == EventTimeline.BACKWARDS) {
+ this.prevTimeline = neighbour;
+ } else if (direction == EventTimeline.FORWARDS) {
+ this.nextTimeline = neighbour;
+ } else {
+ throw new Error("Invalid direction '" + direction + "'");
+ }
+
+ // make sure we don't try to paginate this timeline
+ this.setPaginationToken(null, direction);
+ }
+
+ /**
+ * Add a new event to the timeline, and update the state
+ *
+ * @param event - new event
+ * @param options - addEvent options
+ */
+
+ addEvent(event, toStartOfTimelineOrOpts, roomState) {
+ let toStartOfTimeline = !!toStartOfTimelineOrOpts;
+ let timelineWasEmpty;
+ if (typeof toStartOfTimelineOrOpts === "object") {
+ ({
+ toStartOfTimeline,
+ roomState,
+ timelineWasEmpty
+ } = toStartOfTimelineOrOpts);
+ } else if (toStartOfTimelineOrOpts !== undefined) {
+ // Deprecation warning
+ // FIXME: Remove after 2023-06-01 (technical debt)
+ _logger.logger.warn("Overload deprecated: " + "`EventTimeline.addEvent(event, toStartOfTimeline, roomState?)` " + "is deprecated in favor of the overload with `EventTimeline.addEvent(event, IAddEventOptions)`");
+ }
+ if (!roomState) {
+ roomState = toStartOfTimeline ? this.startState : this.endState;
+ }
+ const timelineSet = this.getTimelineSet();
+ if (timelineSet.room) {
+ EventTimeline.setEventMetadata(event, roomState, toStartOfTimeline);
+
+ // modify state but only on unfiltered timelineSets
+ if (event.isState() && timelineSet.room.getUnfilteredTimelineSet() === timelineSet) {
+ var _roomState;
+ (_roomState = roomState) === null || _roomState === void 0 ? void 0 : _roomState.setStateEvents([event], {
+ timelineWasEmpty
+ });
+ // it is possible that the act of setting the state event means we
+ // can set more metadata (specifically sender/target props), so try
+ // it again if the prop wasn't previously set. It may also mean that
+ // the sender/target is updated (if the event set was a room member event)
+ // so we want to use the *updated* member (new avatar/name) instead.
+ //
+ // However, we do NOT want to do this on member events if we're going
+ // back in time, else we'll set the .sender value for BEFORE the given
+ // member event, whereas we want to set the .sender value for the ACTUAL
+ // member event itself.
+ if (!event.sender || event.getType() === _event.EventType.RoomMember && !toStartOfTimeline) {
+ EventTimeline.setEventMetadata(event, roomState, toStartOfTimeline);
+ }
+ }
+ }
+ let insertIndex;
+ if (toStartOfTimeline) {
+ insertIndex = 0;
+ } else {
+ insertIndex = this.events.length;
+ }
+ this.events.splice(insertIndex, 0, event); // insert element
+ if (toStartOfTimeline) {
+ this.baseIndex++;
+ }
+ }
+
+ /**
+ * Remove an event from the timeline
+ *
+ * @param eventId - ID of event to be removed
+ * @returns removed event, or null if not found
+ */
+ removeEvent(eventId) {
+ for (let i = this.events.length - 1; i >= 0; i--) {
+ const ev = this.events[i];
+ if (ev.getId() == eventId) {
+ this.events.splice(i, 1);
+ if (i < this.baseIndex) {
+ this.baseIndex--;
+ }
+ return ev;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Return a string to identify this timeline, for debugging
+ *
+ * @returns name for this timeline
+ */
+ toString() {
+ return this.name;
+ }
+}
+exports.EventTimeline = EventTimeline;
+(0, _defineProperty2.default)(EventTimeline, "BACKWARDS", Direction.Backward);
+(0, _defineProperty2.default)(EventTimeline, "FORWARDS", Direction.Forward);
+//# sourceMappingURL=event-timeline.js.map \ No newline at end of file
diff --git a/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/event-timeline.js.map b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/event-timeline.js.map
new file mode 100644
index 0000000..76dd790
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/event-timeline.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"event-timeline.js","names":["_logger","require","_roomState2","_event","Direction","exports","EventTimeline","setEventMetadata","event","stateContext","toStartOfTimeline","_event$sender","_event$sender$events","_event$target","_event$target$events","sender","events","member","getSentinelMember","getSender","target","getType","EventType","RoomMember","getStateKey","isState","forwardLooking","constructor","eventTimelineSet","_eventTimelineSet$roo","_eventTimelineSet$roo2","_defineProperty2","default","Backward","Forward","roomId","room","startState","RoomState","endState","paginationRequests","b","f","name","Date","toISOString","initialiseState","stateEvents","timelineWasEmpty","_this$startState","_this$endState","length","Error","setStateEvents","forkLive","direction","forkState","getState","timeline","clone","fork","getRoomId","getFilter","getTimelineSet","getBaseIndex","baseIndex","getEvents","BACKWARDS","FORWARDS","getPaginationToken","paginationToken","startToken","endToken","setPaginationToken","token","getNeighbouringTimeline","prevTimeline","nextTimeline","setNeighbouringTimeline","neighbour","addEvent","toStartOfTimelineOrOpts","roomState","undefined","logger","warn","timelineSet","getUnfilteredTimelineSet","_roomState","insertIndex","splice","removeEvent","eventId","i","ev","getId","toString"],"sources":["../../src/models/event-timeline.ts"],"sourcesContent":["/*\nCopyright 2016 - 2021 The Matrix.org Foundation C.I.C.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n*/\n\nimport { logger } from \"../logger\";\nimport { IMarkerFoundOptions, RoomState } from \"./room-state\";\nimport { EventTimelineSet } from \"./event-timeline-set\";\nimport { MatrixEvent } from \"./event\";\nimport { Filter } from \"../filter\";\nimport { EventType } from \"../@types/event\";\n\nexport interface IInitialiseStateOptions extends Pick<IMarkerFoundOptions, \"timelineWasEmpty\"> {\n // This is a separate interface without any extra stuff currently added on\n // top of `IMarkerFoundOptions` just because it feels like they have\n // different concerns. One shouldn't necessarily look to add to\n // `IMarkerFoundOptions` just because they want to add an extra option to\n // `initialiseState`.\n}\n\nexport interface IAddEventOptions extends Pick<IMarkerFoundOptions, \"timelineWasEmpty\"> {\n /** Whether to insert the new event at the start of the timeline where the\n * oldest events are (timeline is in chronological order, oldest to most\n * recent) */\n toStartOfTimeline: boolean;\n /** The state events to reconcile metadata from */\n roomState?: RoomState;\n}\n\nexport enum Direction {\n Backward = \"b\",\n Forward = \"f\",\n}\n\nexport class EventTimeline {\n /**\n * Symbolic constant for methods which take a 'direction' argument:\n * refers to the start of the timeline, or backwards in time.\n */\n public static readonly BACKWARDS = Direction.Backward;\n\n /**\n * Symbolic constant for methods which take a 'direction' argument:\n * refers to the end of the timeline, or forwards in time.\n */\n public static readonly FORWARDS = Direction.Forward;\n\n /**\n * Static helper method to set sender and target properties\n *\n * @param event - the event whose metadata is to be set\n * @param stateContext - the room state to be queried\n * @param toStartOfTimeline - if true the event's forwardLooking flag is set false\n */\n public static setEventMetadata(event: MatrixEvent, stateContext: RoomState, toStartOfTimeline: boolean): void {\n // When we try to generate a sentinel member before we have that member\n // in the members object, we still generate a sentinel but it doesn't\n // have a membership event, so test to see if events.member is set. We\n // check this to avoid overriding non-sentinel members by sentinel ones\n // when adding the event to a filtered timeline\n if (!event.sender?.events?.member) {\n event.sender = stateContext.getSentinelMember(event.getSender()!);\n }\n if (!event.target?.events?.member && event.getType() === EventType.RoomMember) {\n event.target = stateContext.getSentinelMember(event.getStateKey()!);\n }\n\n if (event.isState()) {\n // room state has no concept of 'old' or 'current', but we want the\n // room state to regress back to previous values if toStartOfTimeline\n // is set, which means inspecting prev_content if it exists. This\n // is done by toggling the forwardLooking flag.\n if (toStartOfTimeline) {\n event.forwardLooking = false;\n }\n }\n }\n\n private readonly roomId: string | null;\n private readonly name: string;\n private events: MatrixEvent[] = [];\n private baseIndex = 0;\n\n private startState?: RoomState;\n private endState?: RoomState;\n // If we have a roomId then we delegate pagination token storage to the room state objects `startState` and\n // `endState`, but for things like the notification timeline which mix multiple rooms we store the tokens ourselves.\n private startToken: string | null = null;\n private endToken: string | null = null;\n\n private prevTimeline: EventTimeline | null = null;\n private nextTimeline: EventTimeline | null = null;\n public paginationRequests: Record<Direction, Promise<boolean> | null> = {\n [Direction.Backward]: null,\n [Direction.Forward]: null,\n };\n\n /**\n * Construct a new EventTimeline\n *\n * <p>An EventTimeline represents a contiguous sequence of events in a room.\n *\n * <p>As well as keeping track of the events themselves, it stores the state of\n * the room at the beginning and end of the timeline, and pagination tokens for\n * going backwards and forwards in the timeline.\n *\n * <p>In order that clients can meaningfully maintain an index into a timeline,\n * the EventTimeline object tracks a 'baseIndex'. This starts at zero, but is\n * incremented when events are prepended to the timeline. The index of an event\n * relative to baseIndex therefore remains constant.\n *\n * <p>Once a timeline joins up with its neighbour, they are linked together into a\n * doubly-linked list.\n *\n * @param eventTimelineSet - the set of timelines this is part of\n */\n public constructor(private readonly eventTimelineSet: EventTimelineSet) {\n this.roomId = eventTimelineSet.room?.roomId ?? null;\n if (this.roomId) {\n this.startState = new RoomState(this.roomId);\n this.endState = new RoomState(this.roomId);\n }\n\n // this is used by client.js\n this.paginationRequests = { b: null, f: null };\n\n this.name = this.roomId + \":\" + new Date().toISOString();\n }\n\n /**\n * Initialise the start and end state with the given events\n *\n * <p>This can only be called before any events are added.\n *\n * @param stateEvents - list of state events to initialise the\n * state with.\n * @throws Error if an attempt is made to call this after addEvent is called.\n */\n public initialiseState(stateEvents: MatrixEvent[], { timelineWasEmpty }: IInitialiseStateOptions = {}): void {\n if (this.events.length > 0) {\n throw new Error(\"Cannot initialise state after events are added\");\n }\n\n this.startState?.setStateEvents(stateEvents, { timelineWasEmpty });\n this.endState?.setStateEvents(stateEvents, { timelineWasEmpty });\n }\n\n /**\n * Forks the (live) timeline, taking ownership of the existing directional state of this timeline.\n * All attached listeners will keep receiving state updates from the new live timeline state.\n * The end state of this timeline gets replaced with an independent copy of the current RoomState,\n * and will need a new pagination token if it ever needs to paginate forwards.\n\n * @param direction - EventTimeline.BACKWARDS to get the state at the\n * start of the timeline; EventTimeline.FORWARDS to get the state at the end\n * of the timeline.\n *\n * @returns the new timeline\n */\n public forkLive(direction: Direction): EventTimeline {\n const forkState = this.getState(direction);\n const timeline = new EventTimeline(this.eventTimelineSet);\n timeline.startState = forkState?.clone();\n // Now clobber the end state of the new live timeline with that from the\n // previous live timeline. It will be identical except that we'll keep\n // using the same RoomMember objects for the 'live' set of members with any\n // listeners still attached\n timeline.endState = forkState;\n // Firstly, we just stole the current timeline's end state, so it needs a new one.\n // Make an immutable copy of the state so back pagination will get the correct sentinels.\n this.endState = forkState?.clone();\n return timeline;\n }\n\n /**\n * Creates an independent timeline, inheriting the directional state from this timeline.\n *\n * @param direction - EventTimeline.BACKWARDS to get the state at the\n * start of the timeline; EventTimeline.FORWARDS to get the state at the end\n * of the timeline.\n *\n * @returns the new timeline\n */\n public fork(direction: Direction): EventTimeline {\n const forkState = this.getState(direction);\n const timeline = new EventTimeline(this.eventTimelineSet);\n timeline.startState = forkState?.clone();\n timeline.endState = forkState?.clone();\n return timeline;\n }\n\n /**\n * Get the ID of the room for this timeline\n * @returns room ID\n */\n public getRoomId(): string | null {\n return this.roomId;\n }\n\n /**\n * Get the filter for this timeline's timelineSet (if any)\n * @returns filter\n */\n public getFilter(): Filter | undefined {\n return this.eventTimelineSet.getFilter();\n }\n\n /**\n * Get the timelineSet for this timeline\n * @returns timelineSet\n */\n public getTimelineSet(): EventTimelineSet {\n return this.eventTimelineSet;\n }\n\n /**\n * Get the base index.\n *\n * <p>This is an index which is incremented when events are prepended to the\n * timeline. An individual event therefore stays at the same index in the array\n * relative to the base index (although note that a given event's index may\n * well be less than the base index, thus giving that event a negative relative\n * index).\n */\n public getBaseIndex(): number {\n return this.baseIndex;\n }\n\n /**\n * Get the list of events in this context\n *\n * @returns An array of MatrixEvents\n */\n public getEvents(): MatrixEvent[] {\n return this.events;\n }\n\n /**\n * Get the room state at the start/end of the timeline\n *\n * @param direction - EventTimeline.BACKWARDS to get the state at the\n * start of the timeline; EventTimeline.FORWARDS to get the state at the end\n * of the timeline.\n *\n * @returns state at the start/end of the timeline\n */\n public getState(direction: Direction): RoomState | undefined {\n if (direction == EventTimeline.BACKWARDS) {\n return this.startState;\n } else if (direction == EventTimeline.FORWARDS) {\n return this.endState;\n } else {\n throw new Error(\"Invalid direction '\" + direction + \"'\");\n }\n }\n\n /**\n * Get a pagination token\n *\n * @param direction - EventTimeline.BACKWARDS to get the pagination\n * token for going backwards in time; EventTimeline.FORWARDS to get the\n * pagination token for going forwards in time.\n *\n * @returns pagination token\n */\n public getPaginationToken(direction: Direction): string | null {\n if (this.roomId) {\n return this.getState(direction)!.paginationToken;\n } else if (direction === Direction.Backward) {\n return this.startToken;\n } else {\n return this.endToken;\n }\n }\n\n /**\n * Set a pagination token\n *\n * @param token - pagination token\n *\n * @param direction - EventTimeline.BACKWARDS to set the pagination\n * token for going backwards in time; EventTimeline.FORWARDS to set the\n * pagination token for going forwards in time.\n */\n public setPaginationToken(token: string | null, direction: Direction): void {\n if (this.roomId) {\n this.getState(direction)!.paginationToken = token;\n } else if (direction === Direction.Backward) {\n this.startToken = token;\n } else {\n this.endToken = token;\n }\n }\n\n /**\n * Get the next timeline in the series\n *\n * @param direction - EventTimeline.BACKWARDS to get the previous\n * timeline; EventTimeline.FORWARDS to get the next timeline.\n *\n * @returns previous or following timeline, if they have been\n * joined up.\n */\n public getNeighbouringTimeline(direction: Direction): EventTimeline | null {\n if (direction == EventTimeline.BACKWARDS) {\n return this.prevTimeline;\n } else if (direction == EventTimeline.FORWARDS) {\n return this.nextTimeline;\n } else {\n throw new Error(\"Invalid direction '\" + direction + \"'\");\n }\n }\n\n /**\n * Set the next timeline in the series\n *\n * @param neighbour - previous/following timeline\n *\n * @param direction - EventTimeline.BACKWARDS to set the previous\n * timeline; EventTimeline.FORWARDS to set the next timeline.\n *\n * @throws Error if an attempt is made to set the neighbouring timeline when\n * it is already set.\n */\n public setNeighbouringTimeline(neighbour: EventTimeline, direction: Direction): void {\n if (this.getNeighbouringTimeline(direction)) {\n throw new Error(\n \"timeline already has a neighbouring timeline - \" +\n \"cannot reset neighbour (direction: \" +\n direction +\n \")\",\n );\n }\n\n if (direction == EventTimeline.BACKWARDS) {\n this.prevTimeline = neighbour;\n } else if (direction == EventTimeline.FORWARDS) {\n this.nextTimeline = neighbour;\n } else {\n throw new Error(\"Invalid direction '\" + direction + \"'\");\n }\n\n // make sure we don't try to paginate this timeline\n this.setPaginationToken(null, direction);\n }\n\n /**\n * Add a new event to the timeline, and update the state\n *\n * @param event - new event\n * @param options - addEvent options\n */\n public addEvent(event: MatrixEvent, { toStartOfTimeline, roomState, timelineWasEmpty }: IAddEventOptions): void;\n /**\n * @deprecated In favor of the overload with `IAddEventOptions`\n */\n public addEvent(event: MatrixEvent, toStartOfTimeline: boolean, roomState?: RoomState): void;\n public addEvent(\n event: MatrixEvent,\n toStartOfTimelineOrOpts: boolean | IAddEventOptions,\n roomState?: RoomState,\n ): void {\n let toStartOfTimeline = !!toStartOfTimelineOrOpts;\n let timelineWasEmpty: boolean | undefined;\n if (typeof toStartOfTimelineOrOpts === \"object\") {\n ({ toStartOfTimeline, roomState, timelineWasEmpty } = toStartOfTimelineOrOpts);\n } else if (toStartOfTimelineOrOpts !== undefined) {\n // Deprecation warning\n // FIXME: Remove after 2023-06-01 (technical debt)\n logger.warn(\n \"Overload deprecated: \" +\n \"`EventTimeline.addEvent(event, toStartOfTimeline, roomState?)` \" +\n \"is deprecated in favor of the overload with `EventTimeline.addEvent(event, IAddEventOptions)`\",\n );\n }\n\n if (!roomState) {\n roomState = toStartOfTimeline ? this.startState : this.endState;\n }\n\n const timelineSet = this.getTimelineSet();\n\n if (timelineSet.room) {\n EventTimeline.setEventMetadata(event, roomState!, toStartOfTimeline);\n\n // modify state but only on unfiltered timelineSets\n if (event.isState() && timelineSet.room.getUnfilteredTimelineSet() === timelineSet) {\n roomState?.setStateEvents([event], { timelineWasEmpty });\n // it is possible that the act of setting the state event means we\n // can set more metadata (specifically sender/target props), so try\n // it again if the prop wasn't previously set. It may also mean that\n // the sender/target is updated (if the event set was a room member event)\n // so we want to use the *updated* member (new avatar/name) instead.\n //\n // However, we do NOT want to do this on member events if we're going\n // back in time, else we'll set the .sender value for BEFORE the given\n // member event, whereas we want to set the .sender value for the ACTUAL\n // member event itself.\n if (!event.sender || (event.getType() === EventType.RoomMember && !toStartOfTimeline)) {\n EventTimeline.setEventMetadata(event, roomState!, toStartOfTimeline);\n }\n }\n }\n\n let insertIndex: number;\n\n if (toStartOfTimeline) {\n insertIndex = 0;\n } else {\n insertIndex = this.events.length;\n }\n\n this.events.splice(insertIndex, 0, event); // insert element\n if (toStartOfTimeline) {\n this.baseIndex++;\n }\n }\n\n /**\n * Remove an event from the timeline\n *\n * @param eventId - ID of event to be removed\n * @returns removed event, or null if not found\n */\n public removeEvent(eventId: string): MatrixEvent | null {\n for (let i = this.events.length - 1; i >= 0; i--) {\n const ev = this.events[i];\n if (ev.getId() == eventId) {\n this.events.splice(i, 1);\n if (i < this.baseIndex) {\n this.baseIndex--;\n }\n return ev;\n }\n }\n return null;\n }\n\n /**\n * Return a string to identify this timeline, for debugging\n *\n * @returns name for this timeline\n */\n public toString(): string {\n return this.name;\n }\n}\n"],"mappings":"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"} \ No newline at end of file
diff --git a/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/event.d.ts b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/event.d.ts
new file mode 100644
index 0000000..d874d29
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/event.d.ts
@@ -0,0 +1,759 @@
+/**
+ * This is an internal module. See {@link MatrixEvent} and {@link RoomEvent} for
+ * the public classes.
+ */
+import { ExtensibleEvent, Optional } from "matrix-events-sdk";
+import { VerificationRequest } from "../crypto/verification/request/VerificationRequest";
+import { EventType, MsgType, RelationType } from "../@types/event";
+import { Crypto } from "../crypto";
+import { RoomMember } from "./room-member";
+import { Thread, ThreadEvent, EventHandlerMap as ThreadEventHandlerMap } from "./thread";
+import { IActionsObject } from "../pushprocessor";
+import { MatrixError } from "../http-api";
+import { TypedEventEmitter } from "./typed-event-emitter";
+import { EventStatus } from "./event-status";
+import { CryptoBackend } from "../common-crypto/CryptoBackend";
+export { EventStatus } from "./event-status";
+export interface IContent {
+ [key: string]: any;
+ "msgtype"?: MsgType | string;
+ "membership"?: string;
+ "avatar_url"?: string;
+ "displayname"?: string;
+ "m.relates_to"?: IEventRelation;
+ "org.matrix.msc3952.mentions"?: IMentions;
+}
+type StrippedState = Required<Pick<IEvent, "content" | "state_key" | "type" | "sender">>;
+export interface IUnsigned {
+ "age"?: number;
+ "prev_sender"?: string;
+ "prev_content"?: IContent;
+ "redacted_because"?: IEvent;
+ "transaction_id"?: string;
+ "invite_room_state"?: StrippedState[];
+ "m.relations"?: Record<RelationType | string, any>;
+}
+export interface IThreadBundledRelationship {
+ latest_event: IEvent;
+ count: number;
+ current_user_participated?: boolean;
+}
+export interface IEvent {
+ event_id: string;
+ type: string;
+ content: IContent;
+ sender: string;
+ room_id?: string;
+ origin_server_ts: number;
+ txn_id?: string;
+ state_key?: string;
+ membership?: string;
+ unsigned: IUnsigned;
+ redacts?: string;
+ /**
+ * @deprecated in favour of `sender`
+ */
+ user_id?: string;
+ /**
+ * @deprecated in favour of `unsigned.prev_content`
+ */
+ prev_content?: IContent;
+ /**
+ * @deprecated in favour of `origin_server_ts`
+ */
+ age?: number;
+}
+export interface IAggregatedRelation {
+ origin_server_ts: number;
+ event_id?: string;
+ sender?: string;
+ type?: string;
+ count?: number;
+ key?: string;
+}
+export interface IEventRelation {
+ "rel_type"?: RelationType | string;
+ "event_id"?: string;
+ "is_falling_back"?: boolean;
+ "m.in_reply_to"?: {
+ event_id?: string;
+ };
+ "key"?: string;
+}
+export interface IMentions {
+ user_ids?: string[];
+ room?: boolean;
+}
+/**
+ * When an event is a visibility change event, as per MSC3531,
+ * the visibility change implied by the event.
+ */
+export interface IVisibilityChange {
+ /**
+ * If `true`, the target event should be made visible.
+ * Otherwise, it should be hidden.
+ */
+ visible: boolean;
+ /**
+ * The event id affected.
+ */
+ eventId: string;
+ /**
+ * Optionally, a human-readable reason explaining why
+ * the event was hidden. Ignored if the event was made
+ * visible.
+ */
+ reason: string | null;
+}
+export interface IClearEvent {
+ room_id?: string;
+ type: string;
+ content: Omit<IContent, "membership" | "avatar_url" | "displayname" | "m.relates_to">;
+ unsigned?: IUnsigned;
+}
+interface IKeyRequestRecipient {
+ userId: string;
+ deviceId: "*" | string;
+}
+export interface IDecryptOptions {
+ emit?: boolean;
+ isRetry?: boolean;
+ forceRedecryptIfUntrusted?: boolean;
+}
+/**
+ * Message hiding, as specified by https://github.com/matrix-org/matrix-doc/pull/3531.
+ */
+export type MessageVisibility = IMessageVisibilityHidden | IMessageVisibilityVisible;
+/**
+ * Variant of `MessageVisibility` for the case in which the message should be displayed.
+ */
+export interface IMessageVisibilityVisible {
+ readonly visible: true;
+}
+/**
+ * Variant of `MessageVisibility` for the case in which the message should be hidden.
+ */
+export interface IMessageVisibilityHidden {
+ readonly visible: false;
+ /**
+ * Optionally, a human-readable reason to show to the user indicating why the
+ * message has been hidden (e.g. "Message Pending Moderation").
+ */
+ readonly reason: string | null;
+}
+export declare enum MatrixEventEvent {
+ Decrypted = "Event.decrypted",
+ BeforeRedaction = "Event.beforeRedaction",
+ VisibilityChange = "Event.visibilityChange",
+ LocalEventIdReplaced = "Event.localEventIdReplaced",
+ Status = "Event.status",
+ Replaced = "Event.replaced",
+ RelationsCreated = "Event.relationsCreated"
+}
+export type MatrixEventEmittedEvents = MatrixEventEvent | ThreadEvent.Update;
+export type MatrixEventHandlerMap = {
+ /**
+ * Fires when an event is decrypted
+ *
+ * @param event - The matrix event which has been decrypted
+ * @param err - The error that occurred during decryption, or `undefined` if no error occurred.
+ */
+ [MatrixEventEvent.Decrypted]: (event: MatrixEvent, err?: Error) => void;
+ [MatrixEventEvent.BeforeRedaction]: (event: MatrixEvent, redactionEvent: MatrixEvent) => void;
+ [MatrixEventEvent.VisibilityChange]: (event: MatrixEvent, visible: boolean) => void;
+ [MatrixEventEvent.LocalEventIdReplaced]: (event: MatrixEvent) => void;
+ [MatrixEventEvent.Status]: (event: MatrixEvent, status: EventStatus | null) => void;
+ [MatrixEventEvent.Replaced]: (event: MatrixEvent) => void;
+ [MatrixEventEvent.RelationsCreated]: (relationType: string, eventType: string) => void;
+} & Pick<ThreadEventHandlerMap, ThreadEvent.Update>;
+export declare class MatrixEvent extends TypedEventEmitter<MatrixEventEmittedEvents, MatrixEventHandlerMap> {
+ event: Partial<IEvent>;
+ private pushActions;
+ private _replacingEvent;
+ private _localRedactionEvent;
+ private _isCancelled;
+ private clearEvent?;
+ private visibility;
+ private _hasCachedExtEv;
+ private _cachedExtEv;
+ private senderCurve25519Key;
+ private claimedEd25519Key;
+ private forwardingCurve25519KeyChain;
+ private untrusted;
+ private decryptionPromise;
+ private retryDecryption;
+ private txnId?;
+ /**
+ * A reference to the thread this event belongs to
+ */
+ private thread?;
+ private threadId?;
+ private encryptedDisabledForUnverifiedDevices;
+ localTimestamp: number;
+ /**
+ * The room member who sent this event, or null e.g.
+ * this is a presence event. This is only guaranteed to be set for events that
+ * appear in a timeline, ie. do not guarantee that it will be set on state
+ * events.
+ * @privateRemarks
+ * Should be read-only
+ */
+ sender: RoomMember | null;
+ /**
+ * The room member who is the target of this event, e.g.
+ * the invitee, the person being banned, etc.
+ * @privateRemarks
+ * Should be read-only
+ */
+ target: RoomMember | null;
+ /**
+ * The sending status of the event.
+ * @privateRemarks
+ * Should be read-only
+ */
+ status: EventStatus | null;
+ /**
+ * most recent error associated with sending the event, if any
+ * @privateRemarks
+ * Should be read-only
+ */
+ error: MatrixError | null;
+ /**
+ * True if this event is 'forward looking', meaning
+ * that getDirectionalContent() will return event.content and not event.prev_content.
+ * Only state events may be backwards looking
+ * Default: true. <strong>This property is experimental and may change.</strong>
+ * @privateRemarks
+ * Should be read-only
+ */
+ forwardLooking: boolean;
+ verificationRequest?: VerificationRequest;
+ private readonly reEmitter;
+ /**
+ * Construct a Matrix Event object
+ *
+ * @param event - The raw (possibly encrypted) event. <b>Do not access
+ * this property</b> directly unless you absolutely have to. Prefer the getter
+ * methods defined on this class. Using the getter methods shields your app
+ * from changes to event JSON between Matrix versions.
+ */
+ constructor(event?: Partial<IEvent>);
+ /**
+ * Unstable getter to try and get an extensible event. Note that this might
+ * return a falsy value if the event could not be parsed as an extensible
+ * event.
+ *
+ * @deprecated Use stable functions where possible.
+ */
+ get unstableExtensibleEvent(): Optional<ExtensibleEvent>;
+ private invalidateExtensibleEvent;
+ /**
+ * Gets the event as though it would appear unencrypted. If the event is already not
+ * encrypted, it is simply returned as-is.
+ * @returns The event in wire format.
+ */
+ getEffectiveEvent(): IEvent;
+ /**
+ * Get the event_id for this event.
+ * @returns The event ID, e.g. <code>$143350589368169JsLZx:localhost
+ * </code>
+ */
+ getId(): string | undefined;
+ /**
+ * Get the user_id for this event.
+ * @returns The user ID, e.g. `@alice:matrix.org`
+ */
+ getSender(): string | undefined;
+ /**
+ * Get the (decrypted, if necessary) type of event.
+ *
+ * @returns The event type, e.g. `m.room.message`
+ */
+ getType(): EventType | string;
+ /**
+ * Get the (possibly encrypted) type of the event that will be sent to the
+ * homeserver.
+ *
+ * @returns The event type.
+ */
+ getWireType(): EventType | string;
+ /**
+ * Get the room_id for this event. This will return `undefined`
+ * for `m.presence` events.
+ * @returns The room ID, e.g. <code>!cURbafjkfsMDVwdRDQ:matrix.org
+ * </code>
+ */
+ getRoomId(): string | undefined;
+ /**
+ * Get the timestamp of this event.
+ * @returns The event timestamp, e.g. `1433502692297`
+ */
+ getTs(): number;
+ /**
+ * Get the timestamp of this event, as a Date object.
+ * @returns The event date, e.g. `new Date(1433502692297)`
+ */
+ getDate(): Date | null;
+ /**
+ * Get a string containing details of this event
+ *
+ * This is intended for logging, to help trace errors. Example output:
+ *
+ * @example
+ * ```
+ * id=$HjnOHV646n0SjLDAqFrgIjim7RCpB7cdMXFrekWYAn type=m.room.encrypted
+ * sender=@user:example.com room=!room:example.com ts=2022-10-25T17:30:28.404Z
+ * ```
+ */
+ getDetails(): string;
+ /**
+ * Get the (decrypted, if necessary) event content JSON, even if the event
+ * was replaced by another event.
+ *
+ * @returns The event content JSON, or an empty object.
+ */
+ getOriginalContent<T = IContent>(): T;
+ /**
+ * Get the (decrypted, if necessary) event content JSON,
+ * or the content from the replacing event, if any.
+ * See `makeReplaced`.
+ *
+ * @returns The event content JSON, or an empty object.
+ */
+ getContent<T extends IContent = IContent>(): T;
+ /**
+ * Get the (possibly encrypted) event content JSON that will be sent to the
+ * homeserver.
+ *
+ * @returns The event content JSON, or an empty object.
+ */
+ getWireContent(): IContent;
+ /**
+ * Get the event ID of the thread head
+ */
+ get threadRootId(): string | undefined;
+ /**
+ * A helper to check if an event is a thread's head or not
+ */
+ get isThreadRoot(): boolean;
+ get replyEventId(): string | undefined;
+ get relationEventId(): string | undefined;
+ /**
+ * Get the previous event content JSON. This will only return something for
+ * state events which exist in the timeline.
+ * @returns The previous event content JSON, or an empty object.
+ */
+ getPrevContent(): IContent;
+ /**
+ * Get either 'content' or 'prev_content' depending on if this event is
+ * 'forward-looking' or not. This can be modified via event.forwardLooking.
+ * In practice, this means we get the chronologically earlier content value
+ * for this event (this method should surely be called getEarlierContent)
+ * <strong>This method is experimental and may change.</strong>
+ * @returns event.content if this event is forward-looking, else
+ * event.prev_content.
+ */
+ getDirectionalContent(): IContent;
+ /**
+ * Get the age of this event. This represents the age of the event when the
+ * event arrived at the device, and not the age of the event when this
+ * function was called.
+ * Can only be returned once the server has echo'ed back
+ * @returns The age of this event in milliseconds.
+ */
+ getAge(): number | undefined;
+ /**
+ * Get the age of the event when this function was called.
+ * This is the 'age' field adjusted according to how long this client has
+ * had the event.
+ * @returns The age of this event in milliseconds.
+ */
+ getLocalAge(): number;
+ /**
+ * Get the event state_key if it has one. This will return <code>undefined
+ * </code> for message events.
+ * @returns The event's `state_key`.
+ */
+ getStateKey(): string | undefined;
+ /**
+ * Check if this event is a state event.
+ * @returns True if this is a state event.
+ */
+ isState(): boolean;
+ /**
+ * Replace the content of this event with encrypted versions.
+ * (This is used when sending an event; it should not be used by applications).
+ *
+ * @internal
+ *
+ * @param cryptoType - type of the encrypted event - typically
+ * <tt>"m.room.encrypted"</tt>
+ *
+ * @param cryptoContent - raw 'content' for the encrypted event.
+ *
+ * @param senderCurve25519Key - curve25519 key to record for the
+ * sender of this event.
+ * See {@link MatrixEvent#getSenderKey}.
+ *
+ * @param claimedEd25519Key - claimed ed25519 key to record for the
+ * sender if this event.
+ * See {@link MatrixEvent#getClaimedEd25519Key}
+ */
+ makeEncrypted(cryptoType: string, cryptoContent: object, senderCurve25519Key: string, claimedEd25519Key: string): void;
+ /**
+ * Check if this event is currently being decrypted.
+ *
+ * @returns True if this event is currently being decrypted, else false.
+ */
+ isBeingDecrypted(): boolean;
+ getDecryptionPromise(): Promise<void> | null;
+ /**
+ * Check if this event is an encrypted event which we failed to decrypt
+ *
+ * (This implies that we might retry decryption at some point in the future)
+ *
+ * @returns True if this event is an encrypted event which we
+ * couldn't decrypt.
+ */
+ isDecryptionFailure(): boolean;
+ get isEncryptedDisabledForUnverifiedDevices(): boolean;
+ shouldAttemptDecryption(): boolean;
+ /**
+ * Start the process of trying to decrypt this event.
+ *
+ * (This is used within the SDK: it isn't intended for use by applications)
+ *
+ * @internal
+ *
+ * @param crypto - crypto module
+ *
+ * @returns promise which resolves (to undefined) when the decryption
+ * attempt is completed.
+ */
+ attemptDecryption(crypto: CryptoBackend, options?: IDecryptOptions): Promise<void>;
+ /**
+ * Cancel any room key request for this event and resend another.
+ *
+ * @param crypto - crypto module
+ * @param userId - the user who received this event
+ *
+ * @returns a promise that resolves when the request is queued
+ */
+ cancelAndResendKeyRequest(crypto: Crypto, userId: string): Promise<void>;
+ /**
+ * Calculate the recipients for keyshare requests.
+ *
+ * @param userId - the user who received this event.
+ *
+ * @returns array of recipients
+ */
+ getKeyRequestRecipients(userId: string): IKeyRequestRecipient[];
+ private decryptionLoop;
+ private badEncryptedMessage;
+ /**
+ * Update the cleartext data on this event.
+ *
+ * (This is used after decrypting an event; it should not be used by applications).
+ *
+ * @internal
+ *
+ * @param decryptionResult - the decryption result, including the plaintext and some key info
+ *
+ * @remarks
+ * Fires {@link MatrixEventEvent.Decrypted}
+ */
+ private setClearData;
+ /**
+ * Gets the cleartext content for this event. If the event is not encrypted,
+ * or encryption has not been completed, this will return null.
+ *
+ * @returns The cleartext (decrypted) content for the event
+ */
+ getClearContent(): IContent | null;
+ /**
+ * Check if the event is encrypted.
+ * @returns True if this event is encrypted.
+ */
+ isEncrypted(): boolean;
+ /**
+ * The curve25519 key for the device that we think sent this event
+ *
+ * For an Olm-encrypted event, this is inferred directly from the DH
+ * exchange at the start of the session: the curve25519 key is involved in
+ * the DH exchange, so only a device which holds the private part of that
+ * key can establish such a session.
+ *
+ * For a megolm-encrypted event, it is inferred from the Olm message which
+ * established the megolm session
+ */
+ getSenderKey(): string | null;
+ /**
+ * The additional keys the sender of this encrypted event claims to possess.
+ *
+ * Just a wrapper for #getClaimedEd25519Key (q.v.)
+ */
+ getKeysClaimed(): Partial<Record<"ed25519", string>>;
+ /**
+ * Get the ed25519 the sender of this event claims to own.
+ *
+ * For Olm messages, this claim is encoded directly in the plaintext of the
+ * event itself. For megolm messages, it is implied by the m.room_key event
+ * which established the megolm session.
+ *
+ * Until we download the device list of the sender, it's just a claim: the
+ * device list gives a proof that the owner of the curve25519 key used for
+ * this event (and returned by #getSenderKey) also owns the ed25519 key by
+ * signing the public curve25519 key with the ed25519 key.
+ *
+ * In general, applications should not use this method directly, but should
+ * instead use MatrixClient.getEventSenderDeviceInfo.
+ */
+ getClaimedEd25519Key(): string | null;
+ /**
+ * Get the curve25519 keys of the devices which were involved in telling us
+ * about the claimedEd25519Key and sender curve25519 key.
+ *
+ * Normally this will be empty, but in the case of a forwarded megolm
+ * session, the sender keys are sent to us by another device (the forwarding
+ * device), which we need to trust to do this. In that case, the result will
+ * be a list consisting of one entry.
+ *
+ * If the device that sent us the key (A) got it from another device which
+ * it wasn't prepared to vouch for (B), the result will be [A, B]. And so on.
+ *
+ * @returns base64-encoded curve25519 keys, from oldest to newest.
+ */
+ getForwardingCurve25519KeyChain(): string[];
+ /**
+ * Whether the decryption key was obtained from an untrusted source. If so,
+ * we cannot verify the authenticity of the message.
+ */
+ isKeySourceUntrusted(): boolean | undefined;
+ getUnsigned(): IUnsigned;
+ setUnsigned(unsigned: IUnsigned): void;
+ unmarkLocallyRedacted(): boolean;
+ markLocallyRedacted(redactionEvent: MatrixEvent): void;
+ /**
+ * Change the visibility of an event, as per https://github.com/matrix-org/matrix-doc/pull/3531 .
+ *
+ * @param visibilityChange - event holding a hide/unhide payload, or nothing
+ * if the event is being reset to its original visibility (presumably
+ * by a visibility event being redacted).
+ *
+ * @remarks
+ * Fires {@link MatrixEventEvent.VisibilityChange} if `visibilityEvent`
+ * caused a change in the actual visibility of this event, either by making it
+ * visible (if it was hidden), by making it hidden (if it was visible) or by
+ * changing the reason (if it was hidden).
+ */
+ applyVisibilityEvent(visibilityChange?: IVisibilityChange): void;
+ /**
+ * Return instructions to display or hide the message.
+ *
+ * @returns Instructions determining whether the message
+ * should be displayed.
+ */
+ messageVisibility(): MessageVisibility;
+ /**
+ * Update the content of an event in the same way it would be by the server
+ * if it were redacted before it was sent to us
+ *
+ * @param redactionEvent - event causing the redaction
+ */
+ makeRedacted(redactionEvent: MatrixEvent): void;
+ /**
+ * Check if this event has been redacted
+ *
+ * @returns True if this event has been redacted
+ */
+ isRedacted(): boolean;
+ /**
+ * Check if this event is a redaction of another event
+ *
+ * @returns True if this event is a redaction
+ */
+ isRedaction(): boolean;
+ /**
+ * Return the visibility change caused by this event,
+ * as per https://github.com/matrix-org/matrix-doc/pull/3531.
+ *
+ * @returns If the event is a well-formed visibility change event,
+ * an instance of `IVisibilityChange`, otherwise `null`.
+ */
+ asVisibilityChange(): IVisibilityChange | null;
+ /**
+ * Check if this event alters the visibility of another event,
+ * as per https://github.com/matrix-org/matrix-doc/pull/3531.
+ *
+ * @returns True if this event alters the visibility
+ * of another event.
+ */
+ isVisibilityEvent(): boolean;
+ /**
+ * Get the (decrypted, if necessary) redaction event JSON
+ * if event was redacted
+ *
+ * @returns The redaction event JSON, or an empty object
+ */
+ getRedactionEvent(): IEvent | {} | null;
+ /**
+ * Get the push actions, if known, for this event
+ *
+ * @returns push actions
+ */
+ getPushActions(): IActionsObject | null;
+ /**
+ * Set the push actions for this event.
+ *
+ * @param pushActions - push actions
+ */
+ setPushActions(pushActions: IActionsObject | null): void;
+ /**
+ * Replace the `event` property and recalculate any properties based on it.
+ * @param event - the object to assign to the `event` property
+ */
+ handleRemoteEcho(event: object): void;
+ /**
+ * Whether the event is in any phase of sending, send failure, waiting for
+ * remote echo, etc.
+ */
+ isSending(): boolean;
+ /**
+ * Update the event's sending status and emit an event as well.
+ *
+ * @param status - The new status
+ */
+ setStatus(status: EventStatus | null): void;
+ replaceLocalEventId(eventId: string): void;
+ /**
+ * Get whether the event is a relation event, and of a given type if
+ * `relType` is passed in. State events cannot be relation events
+ *
+ * @param relType - if given, checks that the relation is of the
+ * given type
+ */
+ isRelation(relType?: string): boolean;
+ /**
+ * Get relation info for the event, if any.
+ */
+ getRelation(): IEventRelation | null;
+ /**
+ * Set an event that replaces the content of this event, through an m.replace relation.
+ *
+ * @param newEvent - the event with the replacing content, if any.
+ *
+ * @remarks
+ * Fires {@link MatrixEventEvent.Replaced}
+ */
+ makeReplaced(newEvent?: MatrixEvent): void;
+ /**
+ * Returns the status of any associated edit or redaction
+ * (not for reactions/annotations as their local echo doesn't affect the original event),
+ * or else the status of the event.
+ */
+ getAssociatedStatus(): EventStatus | null;
+ getServerAggregatedRelation<T>(relType: RelationType | string): T | undefined;
+ /**
+ * Returns the event ID of the event replacing the content of this event, if any.
+ */
+ replacingEventId(): string | undefined;
+ /**
+ * Returns the event replacing the content of this event, if any.
+ * Replacements are aggregated on the server, so this would only
+ * return an event in case it came down the sync, or for local echo of edits.
+ */
+ replacingEvent(): MatrixEvent | null;
+ /**
+ * Returns the origin_server_ts of the event replacing the content of this event, if any.
+ */
+ replacingEventDate(): Date | undefined;
+ /**
+ * Returns the event that wants to redact this event, but hasn't been sent yet.
+ * @returns the event
+ */
+ localRedactionEvent(): MatrixEvent | null;
+ /**
+ * For relations and redactions, returns the event_id this event is referring to.
+ */
+ getAssociatedId(): string | undefined;
+ /**
+ * Checks if this event is associated with another event. See `getAssociatedId`.
+ * @deprecated use hasAssociation instead.
+ */
+ hasAssocation(): boolean;
+ /**
+ * Checks if this event is associated with another event. See `getAssociatedId`.
+ */
+ hasAssociation(): boolean;
+ /**
+ * Update the related id with a new one.
+ *
+ * Used to replace a local id with remote one before sending
+ * an event with a related id.
+ *
+ * @param eventId - the new event id
+ */
+ updateAssociatedId(eventId: string): void;
+ /**
+ * Flags an event as cancelled due to future conditions. For example, a verification
+ * request event in the same sync transaction may be flagged as cancelled to warn
+ * listeners that a cancellation event is coming down the same pipe shortly.
+ * @param cancelled - Whether the event is to be cancelled or not.
+ */
+ flagCancelled(cancelled?: boolean): void;
+ /**
+ * Gets whether or not the event is flagged as cancelled. See flagCancelled() for
+ * more information.
+ * @returns True if the event is cancelled, false otherwise.
+ */
+ isCancelled(): boolean;
+ /**
+ * Get a copy/snapshot of this event. The returned copy will be loosely linked
+ * back to this instance, though will have "frozen" event information. Other
+ * properties of this MatrixEvent instance will be copied verbatim, which can
+ * mean they are in reference to this instance despite being on the copy too.
+ * The reference the snapshot uses does not change, however members aside from
+ * the underlying event will not be deeply cloned, thus may be mutated internally.
+ * For example, the sender profile will be copied over at snapshot time, and
+ * the sender profile internally may mutate without notice to the consumer.
+ *
+ * This is meant to be used to snapshot the event details themselves, not the
+ * features (such as sender) surrounding the event.
+ * @returns A snapshot of this event.
+ */
+ toSnapshot(): MatrixEvent;
+ /**
+ * Determines if this event is equivalent to the given event. This only checks
+ * the event object itself, not the other properties of the event. Intended for
+ * use with toSnapshot() to identify events changing.
+ * @param otherEvent - The other event to check against.
+ * @returns True if the events are the same, false otherwise.
+ */
+ isEquivalentTo(otherEvent: MatrixEvent): boolean;
+ /**
+ * Summarise the event as JSON. This is currently used by React SDK's view
+ * event source feature and Seshat's event indexing, so take care when
+ * adjusting the output here.
+ *
+ * If encrypted, include both the decrypted and encrypted view of the event.
+ *
+ * This is named `toJSON` for use with `JSON.stringify` which checks objects
+ * for functions named `toJSON` and will call them to customise the output
+ * if they are defined.
+ */
+ toJSON(): object;
+ setVerificationRequest(request: VerificationRequest): void;
+ setTxnId(txnId: string): void;
+ getTxnId(): string | undefined;
+ /**
+ * Set the instance of a thread associated with the current event
+ * @param thread - the thread
+ */
+ setThread(thread?: Thread): void;
+ /**
+ * Get the instance of the thread associated with the current event
+ */
+ getThread(): Thread | undefined;
+ setThreadId(threadId?: string): void;
+}
+//# sourceMappingURL=event.d.ts.map \ No newline at end of file
diff --git a/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/event.d.ts.map b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/event.d.ts.map
new file mode 100644
index 0000000..c333e86
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/event.d.ts.map
@@ -0,0 +1 @@
+{"version":3,"file":"event.d.ts","sourceRoot":"","sources":["../../src/models/event.ts"],"names":[],"mappings":"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"} \ No newline at end of file
diff --git a/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/event.js b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/event.js
new file mode 100644
index 0000000..76539a6
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/event.js
@@ -0,0 +1,1433 @@
+"use strict";
+
+var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+Object.defineProperty(exports, "EventStatus", {
+ enumerable: true,
+ get: function () {
+ return _eventStatus.EventStatus;
+ }
+});
+exports.MatrixEventEvent = exports.MatrixEvent = void 0;
+var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
+var _matrixEventsSdk = require("matrix-events-sdk");
+var _logger = require("../logger");
+var _event = require("../@types/event");
+var _utils = require("../utils");
+var _thread = require("./thread");
+var _ReEmitter = require("../ReEmitter");
+var _typedEventEmitter = require("./typed-event-emitter");
+var _algorithms = require("../crypto/algorithms");
+var _OlmDevice = require("../crypto/OlmDevice");
+var _eventStatus = require("./event-status");
+/*
+Copyright 2015 - 2023 The Matrix.org Foundation C.I.C.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+/**
+ * This is an internal module. See {@link MatrixEvent} and {@link RoomEvent} for
+ * the public classes.
+ */
+
+// A singleton implementing `IMessageVisibilityVisible`.
+const MESSAGE_VISIBLE = Object.freeze({
+ visible: true
+});
+let MatrixEventEvent;
+exports.MatrixEventEvent = MatrixEventEvent;
+(function (MatrixEventEvent) {
+ MatrixEventEvent["Decrypted"] = "Event.decrypted";
+ MatrixEventEvent["BeforeRedaction"] = "Event.beforeRedaction";
+ MatrixEventEvent["VisibilityChange"] = "Event.visibilityChange";
+ MatrixEventEvent["LocalEventIdReplaced"] = "Event.localEventIdReplaced";
+ MatrixEventEvent["Status"] = "Event.status";
+ MatrixEventEvent["Replaced"] = "Event.replaced";
+ MatrixEventEvent["RelationsCreated"] = "Event.relationsCreated";
+})(MatrixEventEvent || (exports.MatrixEventEvent = MatrixEventEvent = {}));
+class MatrixEvent extends _typedEventEmitter.TypedEventEmitter {
+ /* Message hiding, as specified by https://github.com/matrix-org/matrix-doc/pull/3531.
+ Note: We're returning this object, so any value stored here MUST be frozen.
+ */
+
+ // Not all events will be extensible-event compatible, so cache a flag in
+ // addition to a falsy cached event value. We check the flag later on in
+ // a public getter to decide if the cache is valid.
+
+ /* curve25519 key which we believe belongs to the sender of the event. See
+ * getSenderKey()
+ */
+
+ /* ed25519 key which the sender of this event (for olm) or the creator of
+ * the megolm session (for megolm) claims to own. See getClaimedEd25519Key()
+ */
+
+ /* curve25519 keys of devices involved in telling us about the
+ * senderCurve25519Key and claimedEd25519Key.
+ * See getForwardingCurve25519KeyChain().
+ */
+
+ /* where the decryption key is untrusted
+ */
+
+ /* if we have a process decrypting this event, a Promise which resolves
+ * when it is finished. Normally null.
+ */
+
+ /* flag to indicate if we should retry decrypting this event after the
+ * first attempt (eg, we have received new data which means that a second
+ * attempt may succeed)
+ */
+
+ /* The txnId with which this event was sent if it was during this session,
+ * allows for a unique ID which does not change when the event comes back down sync.
+ */
+
+ /**
+ * A reference to the thread this event belongs to
+ */
+
+ /*
+ * True if this event is an encrypted event which we failed to decrypt, the receiver's device is unverified and
+ * the sender has disabled encrypting to unverified devices.
+ */
+
+ /* Set an approximate timestamp for the event relative the local clock.
+ * This will inherently be approximate because it doesn't take into account
+ * the time between the server putting the 'age' field on the event as it sent
+ * it to us and the time we're now constructing this event, but that's better
+ * than assuming the local clock is in sync with the origin HS's clock.
+ */
+
+ /**
+ * The room member who sent this event, or null e.g.
+ * this is a presence event. This is only guaranteed to be set for events that
+ * appear in a timeline, ie. do not guarantee that it will be set on state
+ * events.
+ * @privateRemarks
+ * Should be read-only
+ */
+
+ /**
+ * The room member who is the target of this event, e.g.
+ * the invitee, the person being banned, etc.
+ * @privateRemarks
+ * Should be read-only
+ */
+
+ /**
+ * The sending status of the event.
+ * @privateRemarks
+ * Should be read-only
+ */
+
+ /**
+ * most recent error associated with sending the event, if any
+ * @privateRemarks
+ * Should be read-only
+ */
+
+ /**
+ * True if this event is 'forward looking', meaning
+ * that getDirectionalContent() will return event.content and not event.prev_content.
+ * Only state events may be backwards looking
+ * Default: true. <strong>This property is experimental and may change.</strong>
+ * @privateRemarks
+ * Should be read-only
+ */
+
+ /* If the event is a `m.key.verification.request` (or to_device `m.key.verification.start`) event,
+ * `Crypto` will set this the `VerificationRequest` for the event
+ * so it can be easily accessed from the timeline.
+ */
+
+ /**
+ * Construct a Matrix Event object
+ *
+ * @param event - The raw (possibly encrypted) event. <b>Do not access
+ * this property</b> directly unless you absolutely have to. Prefer the getter
+ * methods defined on this class. Using the getter methods shields your app
+ * from changes to event JSON between Matrix versions.
+ */
+ constructor(event = {}) {
+ var _this$getAge;
+ super();
+
+ // intern the values of matrix events to force share strings and reduce the
+ // amount of needless string duplication. This can save moderate amounts of
+ // memory (~10% on a 350MB heap).
+ // 'membership' at the event level (rather than the content level) is a legacy
+ // field that Element never otherwise looks at, but it will still take up a lot
+ // of space if we don't intern it.
+ this.event = event;
+ (0, _defineProperty2.default)(this, "pushActions", null);
+ (0, _defineProperty2.default)(this, "_replacingEvent", null);
+ (0, _defineProperty2.default)(this, "_localRedactionEvent", null);
+ (0, _defineProperty2.default)(this, "_isCancelled", false);
+ (0, _defineProperty2.default)(this, "clearEvent", void 0);
+ (0, _defineProperty2.default)(this, "visibility", MESSAGE_VISIBLE);
+ (0, _defineProperty2.default)(this, "_hasCachedExtEv", false);
+ (0, _defineProperty2.default)(this, "_cachedExtEv", undefined);
+ (0, _defineProperty2.default)(this, "senderCurve25519Key", null);
+ (0, _defineProperty2.default)(this, "claimedEd25519Key", null);
+ (0, _defineProperty2.default)(this, "forwardingCurve25519KeyChain", []);
+ (0, _defineProperty2.default)(this, "untrusted", null);
+ (0, _defineProperty2.default)(this, "decryptionPromise", null);
+ (0, _defineProperty2.default)(this, "retryDecryption", false);
+ (0, _defineProperty2.default)(this, "txnId", void 0);
+ (0, _defineProperty2.default)(this, "thread", void 0);
+ (0, _defineProperty2.default)(this, "threadId", void 0);
+ (0, _defineProperty2.default)(this, "encryptedDisabledForUnverifiedDevices", false);
+ (0, _defineProperty2.default)(this, "localTimestamp", void 0);
+ (0, _defineProperty2.default)(this, "sender", null);
+ (0, _defineProperty2.default)(this, "target", null);
+ (0, _defineProperty2.default)(this, "status", null);
+ (0, _defineProperty2.default)(this, "error", null);
+ (0, _defineProperty2.default)(this, "forwardLooking", true);
+ (0, _defineProperty2.default)(this, "verificationRequest", void 0);
+ (0, _defineProperty2.default)(this, "reEmitter", void 0);
+ ["state_key", "type", "sender", "room_id", "membership"].forEach(prop => {
+ if (typeof event[prop] !== "string") return;
+ event[prop] = (0, _utils.internaliseString)(event[prop]);
+ });
+ ["membership", "avatar_url", "displayname"].forEach(prop => {
+ var _event$content;
+ if (typeof ((_event$content = event.content) === null || _event$content === void 0 ? void 0 : _event$content[prop]) !== "string") return;
+ event.content[prop] = (0, _utils.internaliseString)(event.content[prop]);
+ });
+ ["rel_type"].forEach(prop => {
+ var _event$content2, _event$content2$mRel;
+ if (typeof ((_event$content2 = event.content) === null || _event$content2 === void 0 ? void 0 : (_event$content2$mRel = _event$content2["m.relates_to"]) === null || _event$content2$mRel === void 0 ? void 0 : _event$content2$mRel[prop]) !== "string") return;
+ event.content["m.relates_to"][prop] = (0, _utils.internaliseString)(event.content["m.relates_to"][prop]);
+ });
+ this.txnId = event.txn_id;
+ this.localTimestamp = Date.now() - ((_this$getAge = this.getAge()) !== null && _this$getAge !== void 0 ? _this$getAge : 0);
+ this.reEmitter = new _ReEmitter.TypedReEmitter(this);
+ }
+
+ /**
+ * Unstable getter to try and get an extensible event. Note that this might
+ * return a falsy value if the event could not be parsed as an extensible
+ * event.
+ *
+ * @deprecated Use stable functions where possible.
+ */
+ get unstableExtensibleEvent() {
+ if (!this._hasCachedExtEv) {
+ this._cachedExtEv = _matrixEventsSdk.ExtensibleEvents.parse(this.getEffectiveEvent());
+ }
+ return this._cachedExtEv;
+ }
+ invalidateExtensibleEvent() {
+ // just reset the flag - that'll trick the getter into parsing a new event
+ this._hasCachedExtEv = false;
+ }
+
+ /**
+ * Gets the event as though it would appear unencrypted. If the event is already not
+ * encrypted, it is simply returned as-is.
+ * @returns The event in wire format.
+ */
+ getEffectiveEvent() {
+ const content = Object.assign({}, this.getContent()); // clone for mutation
+
+ if (this.getWireType() === _event.EventType.RoomMessageEncrypted) {
+ // Encrypted events sometimes aren't symmetrical on the `content` so we'll copy
+ // that over too, but only for missing properties. We don't copy over mismatches
+ // between the plain and decrypted copies of `content` because we assume that the
+ // app is relying on the decrypted version, so we want to expose that as a source
+ // of truth here too.
+ for (const [key, value] of Object.entries(this.getWireContent())) {
+ // Skip fields from the encrypted event schema though - we don't want to leak
+ // these.
+ if (["algorithm", "ciphertext", "device_id", "sender_key", "session_id"].includes(key)) {
+ continue;
+ }
+ if (content[key] === undefined) content[key] = value;
+ }
+ }
+
+ // clearEvent doesn't have all the fields, so we'll copy what we can from this.event.
+ // We also copy over our "fixed" content key.
+ return Object.assign({}, this.event, this.clearEvent, {
+ content
+ });
+ }
+
+ /**
+ * Get the event_id for this event.
+ * @returns The event ID, e.g. <code>$143350589368169JsLZx:localhost
+ * </code>
+ */
+ getId() {
+ return this.event.event_id;
+ }
+
+ /**
+ * Get the user_id for this event.
+ * @returns The user ID, e.g. `@alice:matrix.org`
+ */
+ getSender() {
+ return this.event.sender || this.event.user_id; // v2 / v1
+ }
+
+ /**
+ * Get the (decrypted, if necessary) type of event.
+ *
+ * @returns The event type, e.g. `m.room.message`
+ */
+ getType() {
+ if (this.clearEvent) {
+ return this.clearEvent.type;
+ }
+ return this.event.type;
+ }
+
+ /**
+ * Get the (possibly encrypted) type of the event that will be sent to the
+ * homeserver.
+ *
+ * @returns The event type.
+ */
+ getWireType() {
+ return this.event.type;
+ }
+
+ /**
+ * Get the room_id for this event. This will return `undefined`
+ * for `m.presence` events.
+ * @returns The room ID, e.g. <code>!cURbafjkfsMDVwdRDQ:matrix.org
+ * </code>
+ */
+ getRoomId() {
+ return this.event.room_id;
+ }
+
+ /**
+ * Get the timestamp of this event.
+ * @returns The event timestamp, e.g. `1433502692297`
+ */
+ getTs() {
+ return this.event.origin_server_ts;
+ }
+
+ /**
+ * Get the timestamp of this event, as a Date object.
+ * @returns The event date, e.g. `new Date(1433502692297)`
+ */
+ getDate() {
+ return this.event.origin_server_ts ? new Date(this.event.origin_server_ts) : null;
+ }
+
+ /**
+ * Get a string containing details of this event
+ *
+ * This is intended for logging, to help trace errors. Example output:
+ *
+ * @example
+ * ```
+ * id=$HjnOHV646n0SjLDAqFrgIjim7RCpB7cdMXFrekWYAn type=m.room.encrypted
+ * sender=@user:example.com room=!room:example.com ts=2022-10-25T17:30:28.404Z
+ * ```
+ */
+ getDetails() {
+ let details = `id=${this.getId()} type=${this.getWireType()} sender=${this.getSender()}`;
+ const room = this.getRoomId();
+ if (room) {
+ details += ` room=${room}`;
+ }
+ const date = this.getDate();
+ if (date) {
+ details += ` ts=${date.toISOString()}`;
+ }
+ return details;
+ }
+
+ /**
+ * Get the (decrypted, if necessary) event content JSON, even if the event
+ * was replaced by another event.
+ *
+ * @returns The event content JSON, or an empty object.
+ */
+ getOriginalContent() {
+ if (this._localRedactionEvent) {
+ return {};
+ }
+ if (this.clearEvent) {
+ return this.clearEvent.content || {};
+ }
+ return this.event.content || {};
+ }
+
+ /**
+ * Get the (decrypted, if necessary) event content JSON,
+ * or the content from the replacing event, if any.
+ * See `makeReplaced`.
+ *
+ * @returns The event content JSON, or an empty object.
+ */
+ getContent() {
+ if (this._localRedactionEvent) {
+ return {};
+ } else if (this._replacingEvent) {
+ return this._replacingEvent.getContent()["m.new_content"] || {};
+ } else {
+ return this.getOriginalContent();
+ }
+ }
+
+ /**
+ * Get the (possibly encrypted) event content JSON that will be sent to the
+ * homeserver.
+ *
+ * @returns The event content JSON, or an empty object.
+ */
+ getWireContent() {
+ return this.event.content || {};
+ }
+
+ /**
+ * Get the event ID of the thread head
+ */
+ get threadRootId() {
+ var _this$getWireContent;
+ const relatesTo = (_this$getWireContent = this.getWireContent()) === null || _this$getWireContent === void 0 ? void 0 : _this$getWireContent["m.relates_to"];
+ if ((relatesTo === null || relatesTo === void 0 ? void 0 : relatesTo.rel_type) === _thread.THREAD_RELATION_TYPE.name) {
+ return relatesTo.event_id;
+ } else {
+ var _this$getThread;
+ return ((_this$getThread = this.getThread()) === null || _this$getThread === void 0 ? void 0 : _this$getThread.id) || this.threadId;
+ }
+ }
+
+ /**
+ * A helper to check if an event is a thread's head or not
+ */
+ get isThreadRoot() {
+ var _this$getThread2;
+ const threadDetails = this.getServerAggregatedRelation(_thread.THREAD_RELATION_TYPE.name);
+
+ // Bundled relationships only returned when the sync response is limited
+ // hence us having to check both bundled relation and inspect the thread
+ // model
+ return !!threadDetails || ((_this$getThread2 = this.getThread()) === null || _this$getThread2 === void 0 ? void 0 : _this$getThread2.id) === this.getId();
+ }
+ get replyEventId() {
+ var _this$getWireContent$, _this$getWireContent$2;
+ return (_this$getWireContent$ = this.getWireContent()["m.relates_to"]) === null || _this$getWireContent$ === void 0 ? void 0 : (_this$getWireContent$2 = _this$getWireContent$["m.in_reply_to"]) === null || _this$getWireContent$2 === void 0 ? void 0 : _this$getWireContent$2.event_id;
+ }
+ get relationEventId() {
+ var _this$getWireContent2, _this$getWireContent3;
+ return (_this$getWireContent2 = this.getWireContent()) === null || _this$getWireContent2 === void 0 ? void 0 : (_this$getWireContent3 = _this$getWireContent2["m.relates_to"]) === null || _this$getWireContent3 === void 0 ? void 0 : _this$getWireContent3.event_id;
+ }
+
+ /**
+ * Get the previous event content JSON. This will only return something for
+ * state events which exist in the timeline.
+ * @returns The previous event content JSON, or an empty object.
+ */
+ getPrevContent() {
+ // v2 then v1 then default
+ return this.getUnsigned().prev_content || this.event.prev_content || {};
+ }
+
+ /**
+ * Get either 'content' or 'prev_content' depending on if this event is
+ * 'forward-looking' or not. This can be modified via event.forwardLooking.
+ * In practice, this means we get the chronologically earlier content value
+ * for this event (this method should surely be called getEarlierContent)
+ * <strong>This method is experimental and may change.</strong>
+ * @returns event.content if this event is forward-looking, else
+ * event.prev_content.
+ */
+ getDirectionalContent() {
+ return this.forwardLooking ? this.getContent() : this.getPrevContent();
+ }
+
+ /**
+ * Get the age of this event. This represents the age of the event when the
+ * event arrived at the device, and not the age of the event when this
+ * function was called.
+ * Can only be returned once the server has echo'ed back
+ * @returns The age of this event in milliseconds.
+ */
+ getAge() {
+ return this.getUnsigned().age || this.event.age; // v2 / v1
+ }
+
+ /**
+ * Get the age of the event when this function was called.
+ * This is the 'age' field adjusted according to how long this client has
+ * had the event.
+ * @returns The age of this event in milliseconds.
+ */
+ getLocalAge() {
+ return Date.now() - this.localTimestamp;
+ }
+
+ /**
+ * Get the event state_key if it has one. This will return <code>undefined
+ * </code> for message events.
+ * @returns The event's `state_key`.
+ */
+ getStateKey() {
+ return this.event.state_key;
+ }
+
+ /**
+ * Check if this event is a state event.
+ * @returns True if this is a state event.
+ */
+ isState() {
+ return this.event.state_key !== undefined;
+ }
+
+ /**
+ * Replace the content of this event with encrypted versions.
+ * (This is used when sending an event; it should not be used by applications).
+ *
+ * @internal
+ *
+ * @param cryptoType - type of the encrypted event - typically
+ * <tt>"m.room.encrypted"</tt>
+ *
+ * @param cryptoContent - raw 'content' for the encrypted event.
+ *
+ * @param senderCurve25519Key - curve25519 key to record for the
+ * sender of this event.
+ * See {@link MatrixEvent#getSenderKey}.
+ *
+ * @param claimedEd25519Key - claimed ed25519 key to record for the
+ * sender if this event.
+ * See {@link MatrixEvent#getClaimedEd25519Key}
+ */
+ makeEncrypted(cryptoType, cryptoContent, senderCurve25519Key, claimedEd25519Key) {
+ // keep the plain-text data for 'view source'
+ this.clearEvent = {
+ type: this.event.type,
+ content: this.event.content
+ };
+ this.event.type = cryptoType;
+ this.event.content = cryptoContent;
+ this.senderCurve25519Key = senderCurve25519Key;
+ this.claimedEd25519Key = claimedEd25519Key;
+ }
+
+ /**
+ * Check if this event is currently being decrypted.
+ *
+ * @returns True if this event is currently being decrypted, else false.
+ */
+ isBeingDecrypted() {
+ return this.decryptionPromise != null;
+ }
+ getDecryptionPromise() {
+ return this.decryptionPromise;
+ }
+
+ /**
+ * Check if this event is an encrypted event which we failed to decrypt
+ *
+ * (This implies that we might retry decryption at some point in the future)
+ *
+ * @returns True if this event is an encrypted event which we
+ * couldn't decrypt.
+ */
+ isDecryptionFailure() {
+ var _this$clearEvent, _this$clearEvent$cont;
+ return ((_this$clearEvent = this.clearEvent) === null || _this$clearEvent === void 0 ? void 0 : (_this$clearEvent$cont = _this$clearEvent.content) === null || _this$clearEvent$cont === void 0 ? void 0 : _this$clearEvent$cont.msgtype) === "m.bad.encrypted";
+ }
+
+ /*
+ * True if this event is an encrypted event which we failed to decrypt, the receiver's device is unverified and
+ * the sender has disabled encrypting to unverified devices.
+ */
+ get isEncryptedDisabledForUnverifiedDevices() {
+ return this.isDecryptionFailure() && this.encryptedDisabledForUnverifiedDevices;
+ }
+ shouldAttemptDecryption() {
+ if (this.isRedacted()) return false;
+ if (this.isBeingDecrypted()) return false;
+ if (this.clearEvent) return false;
+ if (!this.isEncrypted()) return false;
+ return true;
+ }
+
+ /**
+ * Start the process of trying to decrypt this event.
+ *
+ * (This is used within the SDK: it isn't intended for use by applications)
+ *
+ * @internal
+ *
+ * @param crypto - crypto module
+ *
+ * @returns promise which resolves (to undefined) when the decryption
+ * attempt is completed.
+ */
+ async attemptDecryption(crypto, options = {}) {
+ // start with a couple of sanity checks.
+ if (!this.isEncrypted()) {
+ throw new Error("Attempt to decrypt event which isn't encrypted");
+ }
+ const alreadyDecrypted = this.clearEvent && !this.isDecryptionFailure();
+ const forceRedecrypt = options.forceRedecryptIfUntrusted && this.isKeySourceUntrusted();
+ if (alreadyDecrypted && !forceRedecrypt) {
+ // we may want to just ignore this? let's start with rejecting it.
+ throw new Error("Attempt to decrypt event which has already been decrypted");
+ }
+
+ // if we already have a decryption attempt in progress, then it may
+ // fail because it was using outdated info. We now have reason to
+ // succeed where it failed before, but we don't want to have multiple
+ // attempts going at the same time, so just set a flag that says we have
+ // new info.
+ //
+ if (this.decryptionPromise) {
+ _logger.logger.log(`Event ${this.getId()} already being decrypted; queueing a retry`);
+ this.retryDecryption = true;
+ return this.decryptionPromise;
+ }
+ this.decryptionPromise = this.decryptionLoop(crypto, options);
+ return this.decryptionPromise;
+ }
+
+ /**
+ * Cancel any room key request for this event and resend another.
+ *
+ * @param crypto - crypto module
+ * @param userId - the user who received this event
+ *
+ * @returns a promise that resolves when the request is queued
+ */
+ cancelAndResendKeyRequest(crypto, userId) {
+ const wireContent = this.getWireContent();
+ return crypto.requestRoomKey({
+ algorithm: wireContent.algorithm,
+ room_id: this.getRoomId(),
+ session_id: wireContent.session_id,
+ sender_key: wireContent.sender_key
+ }, this.getKeyRequestRecipients(userId), true);
+ }
+
+ /**
+ * Calculate the recipients for keyshare requests.
+ *
+ * @param userId - the user who received this event.
+ *
+ * @returns array of recipients
+ */
+ getKeyRequestRecipients(userId) {
+ // send the request to all of our own devices
+ const recipients = [{
+ userId,
+ deviceId: "*"
+ }];
+ return recipients;
+ }
+ async decryptionLoop(crypto, options = {}) {
+ // make sure that this method never runs completely synchronously.
+ // (doing so would mean that we would clear decryptionPromise *before*
+ // it is set in attemptDecryption - and hence end up with a stuck
+ // `decryptionPromise`).
+ await Promise.resolve();
+
+ // eslint-disable-next-line no-constant-condition
+ while (true) {
+ this.retryDecryption = false;
+ let res;
+ let err = undefined;
+ try {
+ if (!crypto) {
+ res = this.badEncryptedMessage("Encryption not enabled");
+ } else {
+ res = await crypto.decryptEvent(this);
+ if (options.isRetry === true) {
+ _logger.logger.info(`Decrypted event on retry (${this.getDetails()})`);
+ }
+ }
+ } catch (e) {
+ const detailedError = e instanceof _algorithms.DecryptionError ? e.detailedString : String(e);
+ err = e;
+
+ // see if we have a retry queued.
+ //
+ // NB: make sure to keep this check in the same tick of the
+ // event loop as `decryptionPromise = null` below - otherwise we
+ // risk a race:
+ //
+ // * A: we check retryDecryption here and see that it is
+ // false
+ // * B: we get a second call to attemptDecryption, which sees
+ // that decryptionPromise is set so sets
+ // retryDecryption
+ // * A: we continue below, clear decryptionPromise, and
+ // never do the retry.
+ //
+ if (this.retryDecryption) {
+ // decryption error, but we have a retry queued.
+ _logger.logger.log(`Error decrypting event (${this.getDetails()}), but retrying: ${detailedError}`);
+ continue;
+ }
+
+ // decryption error, no retries queued. Warn about the error and
+ // set it to m.bad.encrypted.
+ //
+ // the detailedString already includes the name and message of the error, and the stack isn't much use,
+ // so we don't bother to log `e` separately.
+ _logger.logger.warn(`Error decrypting event (${this.getDetails()}): ${detailedError}`);
+ res = this.badEncryptedMessage(String(e));
+ }
+
+ // at this point, we've either successfully decrypted the event, or have given up
+ // (and set res to a 'badEncryptedMessage'). Either way, we can now set the
+ // cleartext of the event and raise Event.decrypted.
+ //
+ // make sure we clear 'decryptionPromise' before sending the 'Event.decrypted' event,
+ // otherwise the app will be confused to see `isBeingDecrypted` still set when
+ // there isn't an `Event.decrypted` on the way.
+ //
+ // see also notes on retryDecryption above.
+ //
+ this.decryptionPromise = null;
+ this.retryDecryption = false;
+ this.setClearData(res);
+
+ // Before we emit the event, clear the push actions so that they can be recalculated
+ // by relevant code. We do this because the clear event has now changed, making it
+ // so that existing rules can be re-run over the applicable properties. Stuff like
+ // highlighting when the user's name is mentioned rely on this happening. We also want
+ // to set the push actions before emitting so that any notification listeners don't
+ // pick up the wrong contents.
+ this.setPushActions(null);
+ if (options.emit !== false) {
+ this.emit(MatrixEventEvent.Decrypted, this, err);
+ }
+ return;
+ }
+ }
+ badEncryptedMessage(reason) {
+ return {
+ clearEvent: {
+ type: _event.EventType.RoomMessage,
+ content: {
+ msgtype: "m.bad.encrypted",
+ body: "** Unable to decrypt: " + reason + " **"
+ }
+ },
+ encryptedDisabledForUnverifiedDevices: reason === `DecryptionError: ${_OlmDevice.WITHHELD_MESSAGES["m.unverified"]}`
+ };
+ }
+
+ /**
+ * Update the cleartext data on this event.
+ *
+ * (This is used after decrypting an event; it should not be used by applications).
+ *
+ * @internal
+ *
+ * @param decryptionResult - the decryption result, including the plaintext and some key info
+ *
+ * @remarks
+ * Fires {@link MatrixEventEvent.Decrypted}
+ */
+ setClearData(decryptionResult) {
+ var _decryptionResult$sen, _decryptionResult$cla;
+ this.clearEvent = decryptionResult.clearEvent;
+ this.senderCurve25519Key = (_decryptionResult$sen = decryptionResult.senderCurve25519Key) !== null && _decryptionResult$sen !== void 0 ? _decryptionResult$sen : null;
+ this.claimedEd25519Key = (_decryptionResult$cla = decryptionResult.claimedEd25519Key) !== null && _decryptionResult$cla !== void 0 ? _decryptionResult$cla : null;
+ this.forwardingCurve25519KeyChain = decryptionResult.forwardingCurve25519KeyChain || [];
+ this.untrusted = decryptionResult.untrusted || false;
+ this.encryptedDisabledForUnverifiedDevices = decryptionResult.encryptedDisabledForUnverifiedDevices || false;
+ this.invalidateExtensibleEvent();
+ }
+
+ /**
+ * Gets the cleartext content for this event. If the event is not encrypted,
+ * or encryption has not been completed, this will return null.
+ *
+ * @returns The cleartext (decrypted) content for the event
+ */
+ getClearContent() {
+ return this.clearEvent ? this.clearEvent.content : null;
+ }
+
+ /**
+ * Check if the event is encrypted.
+ * @returns True if this event is encrypted.
+ */
+ isEncrypted() {
+ return !this.isState() && this.event.type === _event.EventType.RoomMessageEncrypted;
+ }
+
+ /**
+ * The curve25519 key for the device that we think sent this event
+ *
+ * For an Olm-encrypted event, this is inferred directly from the DH
+ * exchange at the start of the session: the curve25519 key is involved in
+ * the DH exchange, so only a device which holds the private part of that
+ * key can establish such a session.
+ *
+ * For a megolm-encrypted event, it is inferred from the Olm message which
+ * established the megolm session
+ */
+ getSenderKey() {
+ return this.senderCurve25519Key;
+ }
+
+ /**
+ * The additional keys the sender of this encrypted event claims to possess.
+ *
+ * Just a wrapper for #getClaimedEd25519Key (q.v.)
+ */
+ getKeysClaimed() {
+ if (!this.claimedEd25519Key) return {};
+ return {
+ ed25519: this.claimedEd25519Key
+ };
+ }
+
+ /**
+ * Get the ed25519 the sender of this event claims to own.
+ *
+ * For Olm messages, this claim is encoded directly in the plaintext of the
+ * event itself. For megolm messages, it is implied by the m.room_key event
+ * which established the megolm session.
+ *
+ * Until we download the device list of the sender, it's just a claim: the
+ * device list gives a proof that the owner of the curve25519 key used for
+ * this event (and returned by #getSenderKey) also owns the ed25519 key by
+ * signing the public curve25519 key with the ed25519 key.
+ *
+ * In general, applications should not use this method directly, but should
+ * instead use MatrixClient.getEventSenderDeviceInfo.
+ */
+ getClaimedEd25519Key() {
+ return this.claimedEd25519Key;
+ }
+
+ /**
+ * Get the curve25519 keys of the devices which were involved in telling us
+ * about the claimedEd25519Key and sender curve25519 key.
+ *
+ * Normally this will be empty, but in the case of a forwarded megolm
+ * session, the sender keys are sent to us by another device (the forwarding
+ * device), which we need to trust to do this. In that case, the result will
+ * be a list consisting of one entry.
+ *
+ * If the device that sent us the key (A) got it from another device which
+ * it wasn't prepared to vouch for (B), the result will be [A, B]. And so on.
+ *
+ * @returns base64-encoded curve25519 keys, from oldest to newest.
+ */
+ getForwardingCurve25519KeyChain() {
+ return this.forwardingCurve25519KeyChain;
+ }
+
+ /**
+ * Whether the decryption key was obtained from an untrusted source. If so,
+ * we cannot verify the authenticity of the message.
+ */
+ isKeySourceUntrusted() {
+ return !!this.untrusted;
+ }
+ getUnsigned() {
+ return this.event.unsigned || {};
+ }
+ setUnsigned(unsigned) {
+ this.event.unsigned = unsigned;
+ }
+ unmarkLocallyRedacted() {
+ const value = this._localRedactionEvent;
+ this._localRedactionEvent = null;
+ if (this.event.unsigned) {
+ this.event.unsigned.redacted_because = undefined;
+ }
+ return !!value;
+ }
+ markLocallyRedacted(redactionEvent) {
+ if (this._localRedactionEvent) return;
+ this.emit(MatrixEventEvent.BeforeRedaction, this, redactionEvent);
+ this._localRedactionEvent = redactionEvent;
+ if (!this.event.unsigned) {
+ this.event.unsigned = {};
+ }
+ this.event.unsigned.redacted_because = redactionEvent.event;
+ }
+
+ /**
+ * Change the visibility of an event, as per https://github.com/matrix-org/matrix-doc/pull/3531 .
+ *
+ * @param visibilityChange - event holding a hide/unhide payload, or nothing
+ * if the event is being reset to its original visibility (presumably
+ * by a visibility event being redacted).
+ *
+ * @remarks
+ * Fires {@link MatrixEventEvent.VisibilityChange} if `visibilityEvent`
+ * caused a change in the actual visibility of this event, either by making it
+ * visible (if it was hidden), by making it hidden (if it was visible) or by
+ * changing the reason (if it was hidden).
+ */
+ applyVisibilityEvent(visibilityChange) {
+ var _visibilityChange$vis, _visibilityChange$rea;
+ const visible = (_visibilityChange$vis = visibilityChange === null || visibilityChange === void 0 ? void 0 : visibilityChange.visible) !== null && _visibilityChange$vis !== void 0 ? _visibilityChange$vis : true;
+ const reason = (_visibilityChange$rea = visibilityChange === null || visibilityChange === void 0 ? void 0 : visibilityChange.reason) !== null && _visibilityChange$rea !== void 0 ? _visibilityChange$rea : null;
+ let change = false;
+ if (this.visibility.visible !== visible) {
+ change = true;
+ } else if (!this.visibility.visible && this.visibility["reason"] !== reason) {
+ change = true;
+ }
+ if (change) {
+ if (visible) {
+ this.visibility = MESSAGE_VISIBLE;
+ } else {
+ this.visibility = Object.freeze({
+ visible: false,
+ reason
+ });
+ }
+ this.emit(MatrixEventEvent.VisibilityChange, this, visible);
+ }
+ }
+
+ /**
+ * Return instructions to display or hide the message.
+ *
+ * @returns Instructions determining whether the message
+ * should be displayed.
+ */
+ messageVisibility() {
+ // Note: We may return `this.visibility` without fear, as
+ // this is a shallow frozen object.
+ return this.visibility;
+ }
+
+ /**
+ * Update the content of an event in the same way it would be by the server
+ * if it were redacted before it was sent to us
+ *
+ * @param redactionEvent - event causing the redaction
+ */
+ makeRedacted(redactionEvent) {
+ // quick sanity-check
+ if (!redactionEvent.event) {
+ throw new Error("invalid redactionEvent in makeRedacted");
+ }
+ this._localRedactionEvent = null;
+ this.emit(MatrixEventEvent.BeforeRedaction, this, redactionEvent);
+ this._replacingEvent = null;
+ // we attempt to replicate what we would see from the server if
+ // the event had been redacted before we saw it.
+ //
+ // The server removes (most of) the content of the event, and adds a
+ // "redacted_because" key to the unsigned section containing the
+ // redacted event.
+ if (!this.event.unsigned) {
+ this.event.unsigned = {};
+ }
+ this.event.unsigned.redacted_because = redactionEvent.event;
+ for (const key in this.event) {
+ if (this.event.hasOwnProperty(key) && !REDACT_KEEP_KEYS.has(key)) {
+ delete this.event[key];
+ }
+ }
+
+ // If the event is encrypted prune the decrypted bits
+ if (this.isEncrypted()) {
+ this.clearEvent = undefined;
+ }
+ const keeps = this.getType() in REDACT_KEEP_CONTENT_MAP ? REDACT_KEEP_CONTENT_MAP[this.getType()] : {};
+ const content = this.getContent();
+ for (const key in content) {
+ if (content.hasOwnProperty(key) && !keeps[key]) {
+ delete content[key];
+ }
+ }
+ this.invalidateExtensibleEvent();
+ }
+
+ /**
+ * Check if this event has been redacted
+ *
+ * @returns True if this event has been redacted
+ */
+ isRedacted() {
+ return Boolean(this.getUnsigned().redacted_because);
+ }
+
+ /**
+ * Check if this event is a redaction of another event
+ *
+ * @returns True if this event is a redaction
+ */
+ isRedaction() {
+ return this.getType() === _event.EventType.RoomRedaction;
+ }
+
+ /**
+ * Return the visibility change caused by this event,
+ * as per https://github.com/matrix-org/matrix-doc/pull/3531.
+ *
+ * @returns If the event is a well-formed visibility change event,
+ * an instance of `IVisibilityChange`, otherwise `null`.
+ */
+ asVisibilityChange() {
+ if (!_event.EVENT_VISIBILITY_CHANGE_TYPE.matches(this.getType())) {
+ // Not a visibility change event.
+ return null;
+ }
+ const relation = this.getRelation();
+ if (!relation || relation.rel_type != "m.reference") {
+ // Ill-formed, ignore this event.
+ return null;
+ }
+ const eventId = relation.event_id;
+ if (!eventId) {
+ // Ill-formed, ignore this event.
+ return null;
+ }
+ const content = this.getWireContent();
+ const visible = !!content.visible;
+ const reason = content.reason;
+ if (reason && typeof reason != "string") {
+ // Ill-formed, ignore this event.
+ return null;
+ }
+ // Well-formed visibility change event.
+ return {
+ visible,
+ reason,
+ eventId
+ };
+ }
+
+ /**
+ * Check if this event alters the visibility of another event,
+ * as per https://github.com/matrix-org/matrix-doc/pull/3531.
+ *
+ * @returns True if this event alters the visibility
+ * of another event.
+ */
+ isVisibilityEvent() {
+ return _event.EVENT_VISIBILITY_CHANGE_TYPE.matches(this.getType());
+ }
+
+ /**
+ * Get the (decrypted, if necessary) redaction event JSON
+ * if event was redacted
+ *
+ * @returns The redaction event JSON, or an empty object
+ */
+ getRedactionEvent() {
+ var _this$clearEvent2, _this$event$unsigned;
+ if (!this.isRedacted()) return null;
+ if ((_this$clearEvent2 = this.clearEvent) !== null && _this$clearEvent2 !== void 0 && _this$clearEvent2.unsigned) {
+ var _this$clearEvent$unsi, _this$clearEvent3;
+ return (_this$clearEvent$unsi = (_this$clearEvent3 = this.clearEvent) === null || _this$clearEvent3 === void 0 ? void 0 : _this$clearEvent3.unsigned.redacted_because) !== null && _this$clearEvent$unsi !== void 0 ? _this$clearEvent$unsi : null;
+ } else if ((_this$event$unsigned = this.event.unsigned) !== null && _this$event$unsigned !== void 0 && _this$event$unsigned.redacted_because) {
+ return this.event.unsigned.redacted_because;
+ } else {
+ return {};
+ }
+ }
+
+ /**
+ * Get the push actions, if known, for this event
+ *
+ * @returns push actions
+ */
+ getPushActions() {
+ return this.pushActions;
+ }
+
+ /**
+ * Set the push actions for this event.
+ *
+ * @param pushActions - push actions
+ */
+ setPushActions(pushActions) {
+ this.pushActions = pushActions;
+ }
+
+ /**
+ * Replace the `event` property and recalculate any properties based on it.
+ * @param event - the object to assign to the `event` property
+ */
+ handleRemoteEcho(event) {
+ const oldUnsigned = this.getUnsigned();
+ const oldId = this.getId();
+ this.event = event;
+ // if this event was redacted before it was sent, it's locally marked as redacted.
+ // At this point, we've received the remote echo for the event, but not yet for
+ // the redaction that we are sending ourselves. Preserve the locally redacted
+ // state by copying over redacted_because so we don't get a flash of
+ // redacted, not-redacted, redacted as remote echos come in
+ if (oldUnsigned.redacted_because) {
+ if (!this.event.unsigned) {
+ this.event.unsigned = {};
+ }
+ this.event.unsigned.redacted_because = oldUnsigned.redacted_because;
+ }
+ // successfully sent.
+ this.setStatus(null);
+ if (this.getId() !== oldId) {
+ // emit the event if it changed
+ this.emit(MatrixEventEvent.LocalEventIdReplaced, this);
+ }
+ this.localTimestamp = Date.now() - this.getAge();
+ }
+
+ /**
+ * Whether the event is in any phase of sending, send failure, waiting for
+ * remote echo, etc.
+ */
+ isSending() {
+ return !!this.status;
+ }
+
+ /**
+ * Update the event's sending status and emit an event as well.
+ *
+ * @param status - The new status
+ */
+ setStatus(status) {
+ this.status = status;
+ this.emit(MatrixEventEvent.Status, this, status);
+ }
+ replaceLocalEventId(eventId) {
+ this.event.event_id = eventId;
+ this.emit(MatrixEventEvent.LocalEventIdReplaced, this);
+ }
+
+ /**
+ * Get whether the event is a relation event, and of a given type if
+ * `relType` is passed in. State events cannot be relation events
+ *
+ * @param relType - if given, checks that the relation is of the
+ * given type
+ */
+ isRelation(relType) {
+ var _this$getWireContent4;
+ // Relation info is lifted out of the encrypted content when sent to
+ // encrypted rooms, so we have to check `getWireContent` for this.
+ const relation = (_this$getWireContent4 = this.getWireContent()) === null || _this$getWireContent4 === void 0 ? void 0 : _this$getWireContent4["m.relates_to"];
+ if (this.isState() && (relation === null || relation === void 0 ? void 0 : relation.rel_type) === _event.RelationType.Replace) {
+ // State events cannot be m.replace relations
+ return false;
+ }
+ return !!(relation !== null && relation !== void 0 && relation.rel_type && relation.event_id && (relType ? relation.rel_type === relType : true));
+ }
+
+ /**
+ * Get relation info for the event, if any.
+ */
+ getRelation() {
+ var _this$getWireContent$3;
+ if (!this.isRelation()) {
+ return null;
+ }
+ return (_this$getWireContent$3 = this.getWireContent()["m.relates_to"]) !== null && _this$getWireContent$3 !== void 0 ? _this$getWireContent$3 : null;
+ }
+
+ /**
+ * Set an event that replaces the content of this event, through an m.replace relation.
+ *
+ * @param newEvent - the event with the replacing content, if any.
+ *
+ * @remarks
+ * Fires {@link MatrixEventEvent.Replaced}
+ */
+ makeReplaced(newEvent) {
+ // don't allow redacted events to be replaced.
+ // if newEvent is null we allow to go through though,
+ // as with local redaction, the replacing event might get
+ // cancelled, which should be reflected on the target event.
+ if (this.isRedacted() && newEvent) {
+ return;
+ }
+ // don't allow state events to be replaced using this mechanism as per MSC2676
+ if (this.isState()) {
+ return;
+ }
+ if (this._replacingEvent !== newEvent) {
+ this._replacingEvent = newEvent !== null && newEvent !== void 0 ? newEvent : null;
+ this.emit(MatrixEventEvent.Replaced, this);
+ this.invalidateExtensibleEvent();
+ }
+ }
+
+ /**
+ * Returns the status of any associated edit or redaction
+ * (not for reactions/annotations as their local echo doesn't affect the original event),
+ * or else the status of the event.
+ */
+ getAssociatedStatus() {
+ if (this._replacingEvent) {
+ return this._replacingEvent.status;
+ } else if (this._localRedactionEvent) {
+ return this._localRedactionEvent.status;
+ }
+ return this.status;
+ }
+ getServerAggregatedRelation(relType) {
+ var _this$getUnsigned$mR;
+ return (_this$getUnsigned$mR = this.getUnsigned()["m.relations"]) === null || _this$getUnsigned$mR === void 0 ? void 0 : _this$getUnsigned$mR[relType];
+ }
+
+ /**
+ * Returns the event ID of the event replacing the content of this event, if any.
+ */
+ replacingEventId() {
+ const replaceRelation = this.getServerAggregatedRelation(_event.RelationType.Replace);
+ if (replaceRelation) {
+ return replaceRelation.event_id;
+ } else if (this._replacingEvent) {
+ return this._replacingEvent.getId();
+ }
+ }
+
+ /**
+ * Returns the event replacing the content of this event, if any.
+ * Replacements are aggregated on the server, so this would only
+ * return an event in case it came down the sync, or for local echo of edits.
+ */
+ replacingEvent() {
+ return this._replacingEvent;
+ }
+
+ /**
+ * Returns the origin_server_ts of the event replacing the content of this event, if any.
+ */
+ replacingEventDate() {
+ const replaceRelation = this.getServerAggregatedRelation(_event.RelationType.Replace);
+ if (replaceRelation) {
+ const ts = replaceRelation.origin_server_ts;
+ if (Number.isFinite(ts)) {
+ return new Date(ts);
+ }
+ } else if (this._replacingEvent) {
+ var _this$_replacingEvent;
+ return (_this$_replacingEvent = this._replacingEvent.getDate()) !== null && _this$_replacingEvent !== void 0 ? _this$_replacingEvent : undefined;
+ }
+ }
+
+ /**
+ * Returns the event that wants to redact this event, but hasn't been sent yet.
+ * @returns the event
+ */
+ localRedactionEvent() {
+ return this._localRedactionEvent;
+ }
+
+ /**
+ * For relations and redactions, returns the event_id this event is referring to.
+ */
+ getAssociatedId() {
+ const relation = this.getRelation();
+ if (this.replyEventId) {
+ return this.replyEventId;
+ } else if (relation) {
+ return relation.event_id;
+ } else if (this.isRedaction()) {
+ return this.event.redacts;
+ }
+ }
+
+ /**
+ * Checks if this event is associated with another event. See `getAssociatedId`.
+ * @deprecated use hasAssociation instead.
+ */
+ hasAssocation() {
+ return !!this.getAssociatedId();
+ }
+
+ /**
+ * Checks if this event is associated with another event. See `getAssociatedId`.
+ */
+ hasAssociation() {
+ return !!this.getAssociatedId();
+ }
+
+ /**
+ * Update the related id with a new one.
+ *
+ * Used to replace a local id with remote one before sending
+ * an event with a related id.
+ *
+ * @param eventId - the new event id
+ */
+ updateAssociatedId(eventId) {
+ const relation = this.getRelation();
+ if (relation) {
+ relation.event_id = eventId;
+ } else if (this.isRedaction()) {
+ this.event.redacts = eventId;
+ }
+ }
+
+ /**
+ * Flags an event as cancelled due to future conditions. For example, a verification
+ * request event in the same sync transaction may be flagged as cancelled to warn
+ * listeners that a cancellation event is coming down the same pipe shortly.
+ * @param cancelled - Whether the event is to be cancelled or not.
+ */
+ flagCancelled(cancelled = true) {
+ this._isCancelled = cancelled;
+ }
+
+ /**
+ * Gets whether or not the event is flagged as cancelled. See flagCancelled() for
+ * more information.
+ * @returns True if the event is cancelled, false otherwise.
+ */
+ isCancelled() {
+ return this._isCancelled;
+ }
+
+ /**
+ * Get a copy/snapshot of this event. The returned copy will be loosely linked
+ * back to this instance, though will have "frozen" event information. Other
+ * properties of this MatrixEvent instance will be copied verbatim, which can
+ * mean they are in reference to this instance despite being on the copy too.
+ * The reference the snapshot uses does not change, however members aside from
+ * the underlying event will not be deeply cloned, thus may be mutated internally.
+ * For example, the sender profile will be copied over at snapshot time, and
+ * the sender profile internally may mutate without notice to the consumer.
+ *
+ * This is meant to be used to snapshot the event details themselves, not the
+ * features (such as sender) surrounding the event.
+ * @returns A snapshot of this event.
+ */
+ toSnapshot() {
+ const ev = new MatrixEvent(JSON.parse(JSON.stringify(this.event)));
+ for (const [p, v] of Object.entries(this)) {
+ if (p !== "event") {
+ // exclude the thing we just cloned
+ // @ts-ignore - XXX: this is just nasty
+ ev[p] = v;
+ }
+ }
+ return ev;
+ }
+
+ /**
+ * Determines if this event is equivalent to the given event. This only checks
+ * the event object itself, not the other properties of the event. Intended for
+ * use with toSnapshot() to identify events changing.
+ * @param otherEvent - The other event to check against.
+ * @returns True if the events are the same, false otherwise.
+ */
+ isEquivalentTo(otherEvent) {
+ if (!otherEvent) return false;
+ if (otherEvent === this) return true;
+ const myProps = (0, _utils.deepSortedObjectEntries)(this.event);
+ const theirProps = (0, _utils.deepSortedObjectEntries)(otherEvent.event);
+ return JSON.stringify(myProps) === JSON.stringify(theirProps);
+ }
+
+ /**
+ * Summarise the event as JSON. This is currently used by React SDK's view
+ * event source feature and Seshat's event indexing, so take care when
+ * adjusting the output here.
+ *
+ * If encrypted, include both the decrypted and encrypted view of the event.
+ *
+ * This is named `toJSON` for use with `JSON.stringify` which checks objects
+ * for functions named `toJSON` and will call them to customise the output
+ * if they are defined.
+ */
+ toJSON() {
+ const event = this.getEffectiveEvent();
+ if (!this.isEncrypted()) {
+ return event;
+ }
+ return {
+ decrypted: event,
+ encrypted: this.event
+ };
+ }
+ setVerificationRequest(request) {
+ this.verificationRequest = request;
+ }
+ setTxnId(txnId) {
+ this.txnId = txnId;
+ }
+ getTxnId() {
+ return this.txnId;
+ }
+
+ /**
+ * Set the instance of a thread associated with the current event
+ * @param thread - the thread
+ */
+ setThread(thread) {
+ if (this.thread) {
+ this.reEmitter.stopReEmitting(this.thread, [_thread.ThreadEvent.Update]);
+ }
+ this.thread = thread;
+ this.setThreadId(thread === null || thread === void 0 ? void 0 : thread.id);
+ if (thread) {
+ this.reEmitter.reEmit(thread, [_thread.ThreadEvent.Update]);
+ }
+ }
+
+ /**
+ * Get the instance of the thread associated with the current event
+ */
+ getThread() {
+ return this.thread;
+ }
+ setThreadId(threadId) {
+ this.threadId = threadId;
+ }
+}
+
+/* REDACT_KEEP_KEYS gives the keys we keep when an event is redacted
+ *
+ * This is specified here:
+ * http://matrix.org/speculator/spec/HEAD/client_server/latest.html#redactions
+ *
+ * Also:
+ * - We keep 'unsigned' since that is created by the local server
+ * - We keep user_id for backwards-compat with v1
+ */
+exports.MatrixEvent = MatrixEvent;
+const REDACT_KEEP_KEYS = new Set(["event_id", "type", "room_id", "user_id", "sender", "state_key", "prev_state", "content", "unsigned", "origin_server_ts"]);
+
+// a map from state event type to the .content keys we keep when an event is redacted
+const REDACT_KEEP_CONTENT_MAP = {
+ [_event.EventType.RoomMember]: {
+ membership: 1
+ },
+ [_event.EventType.RoomCreate]: {
+ creator: 1
+ },
+ [_event.EventType.RoomJoinRules]: {
+ join_rule: 1
+ },
+ [_event.EventType.RoomPowerLevels]: {
+ ban: 1,
+ events: 1,
+ events_default: 1,
+ kick: 1,
+ redact: 1,
+ state_default: 1,
+ users: 1,
+ users_default: 1
+ }
+};
+//# sourceMappingURL=event.js.map \ No newline at end of file
diff --git a/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/event.js.map b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/event.js.map
new file mode 100644
index 0000000..cf33248
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/event.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"event.js","names":["_matrixEventsSdk","require","_logger","_event","_utils","_thread","_ReEmitter","_typedEventEmitter","_algorithms","_OlmDevice","_eventStatus","MESSAGE_VISIBLE","Object","freeze","visible","MatrixEventEvent","exports","MatrixEvent","TypedEventEmitter","constructor","event","_this$getAge","_defineProperty2","default","undefined","forEach","prop","internaliseString","_event$content","content","_event$content2","_event$content2$mRel","txnId","txn_id","localTimestamp","Date","now","getAge","reEmitter","TypedReEmitter","unstableExtensibleEvent","_hasCachedExtEv","_cachedExtEv","ExtensibleEvents","parse","getEffectiveEvent","invalidateExtensibleEvent","assign","getContent","getWireType","EventType","RoomMessageEncrypted","key","value","entries","getWireContent","includes","clearEvent","getId","event_id","getSender","sender","user_id","getType","type","getRoomId","room_id","getTs","origin_server_ts","getDate","getDetails","details","room","date","toISOString","getOriginalContent","_localRedactionEvent","_replacingEvent","threadRootId","_this$getWireContent","relatesTo","rel_type","THREAD_RELATION_TYPE","name","_this$getThread","getThread","id","threadId","isThreadRoot","_this$getThread2","threadDetails","getServerAggregatedRelation","replyEventId","_this$getWireContent$","_this$getWireContent$2","relationEventId","_this$getWireContent2","_this$getWireContent3","getPrevContent","getUnsigned","prev_content","getDirectionalContent","forwardLooking","age","getLocalAge","getStateKey","state_key","isState","makeEncrypted","cryptoType","cryptoContent","senderCurve25519Key","claimedEd25519Key","isBeingDecrypted","decryptionPromise","getDecryptionPromise","isDecryptionFailure","_this$clearEvent","_this$clearEvent$cont","msgtype","isEncryptedDisabledForUnverifiedDevices","encryptedDisabledForUnverifiedDevices","shouldAttemptDecryption","isRedacted","isEncrypted","attemptDecryption","crypto","options","Error","alreadyDecrypted","forceRedecrypt","forceRedecryptIfUntrusted","isKeySourceUntrusted","logger","log","retryDecryption","decryptionLoop","cancelAndResendKeyRequest","userId","wireContent","requestRoomKey","algorithm","session_id","sender_key","getKeyRequestRecipients","recipients","deviceId","Promise","resolve","res","err","badEncryptedMessage","decryptEvent","isRetry","info","e","detailedError","DecryptionError","detailedString","String","warn","setClearData","setPushActions","emit","Decrypted","reason","RoomMessage","body","WITHHELD_MESSAGES","decryptionResult","_decryptionResult$sen","_decryptionResult$cla","forwardingCurve25519KeyChain","untrusted","getClearContent","getSenderKey","getKeysClaimed","ed25519","getClaimedEd25519Key","getForwardingCurve25519KeyChain","unsigned","setUnsigned","unmarkLocallyRedacted","redacted_because","markLocallyRedacted","redactionEvent","BeforeRedaction","applyVisibilityEvent","visibilityChange","_visibilityChange$vis","_visibilityChange$rea","change","visibility","VisibilityChange","messageVisibility","makeRedacted","hasOwnProperty","REDACT_KEEP_KEYS","has","keeps","REDACT_KEEP_CONTENT_MAP","Boolean","isRedaction","RoomRedaction","asVisibilityChange","EVENT_VISIBILITY_CHANGE_TYPE","matches","relation","getRelation","eventId","isVisibilityEvent","getRedactionEvent","_this$clearEvent2","_this$event$unsigned","_this$clearEvent$unsi","_this$clearEvent3","getPushActions","pushActions","handleRemoteEcho","oldUnsigned","oldId","setStatus","LocalEventIdReplaced","isSending","status","Status","replaceLocalEventId","isRelation","relType","_this$getWireContent4","RelationType","Replace","_this$getWireContent$3","makeReplaced","newEvent","Replaced","getAssociatedStatus","_this$getUnsigned$mR","replacingEventId","replaceRelation","replacingEvent","replacingEventDate","ts","Number","isFinite","_this$_replacingEvent","localRedactionEvent","getAssociatedId","redacts","hasAssocation","hasAssociation","updateAssociatedId","flagCancelled","cancelled","_isCancelled","isCancelled","toSnapshot","ev","JSON","stringify","p","v","isEquivalentTo","otherEvent","myProps","deepSortedObjectEntries","theirProps","toJSON","decrypted","encrypted","setVerificationRequest","request","verificationRequest","setTxnId","getTxnId","setThread","thread","stopReEmitting","ThreadEvent","Update","setThreadId","reEmit","Set","RoomMember","membership","RoomCreate","creator","RoomJoinRules","join_rule","RoomPowerLevels","ban","events","events_default","kick","redact","state_default","users","users_default"],"sources":["../../src/models/event.ts"],"sourcesContent":["/*\nCopyright 2015 - 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\n/**\n * This is an internal module. See {@link MatrixEvent} and {@link RoomEvent} for\n * the public classes.\n */\n\nimport { ExtensibleEvent, ExtensibleEvents, Optional } from \"matrix-events-sdk\";\n\nimport type { IEventDecryptionResult } from \"../@types/crypto\";\nimport { logger } from \"../logger\";\nimport { VerificationRequest } from \"../crypto/verification/request/VerificationRequest\";\nimport { EVENT_VISIBILITY_CHANGE_TYPE, EventType, MsgType, RelationType } from \"../@types/event\";\nimport { Crypto } from \"../crypto\";\nimport { deepSortedObjectEntries, internaliseString } from \"../utils\";\nimport { RoomMember } from \"./room-member\";\nimport { Thread, ThreadEvent, EventHandlerMap as ThreadEventHandlerMap, THREAD_RELATION_TYPE } from \"./thread\";\nimport { IActionsObject } from \"../pushprocessor\";\nimport { TypedReEmitter } from \"../ReEmitter\";\nimport { MatrixError } from \"../http-api\";\nimport { TypedEventEmitter } from \"./typed-event-emitter\";\nimport { EventStatus } from \"./event-status\";\nimport { DecryptionError } from \"../crypto/algorithms\";\nimport { CryptoBackend } from \"../common-crypto/CryptoBackend\";\nimport { WITHHELD_MESSAGES } from \"../crypto/OlmDevice\";\n\nexport { EventStatus } from \"./event-status\";\n\n/* eslint-disable camelcase */\nexport interface IContent {\n [key: string]: any;\n \"msgtype\"?: MsgType | string;\n \"membership\"?: string;\n \"avatar_url\"?: string;\n \"displayname\"?: string;\n \"m.relates_to\"?: IEventRelation;\n\n \"org.matrix.msc3952.mentions\"?: IMentions;\n}\n\ntype StrippedState = Required<Pick<IEvent, \"content\" | \"state_key\" | \"type\" | \"sender\">>;\n\nexport interface IUnsigned {\n \"age\"?: number;\n \"prev_sender\"?: string;\n \"prev_content\"?: IContent;\n \"redacted_because\"?: IEvent;\n \"transaction_id\"?: string;\n \"invite_room_state\"?: StrippedState[];\n \"m.relations\"?: Record<RelationType | string, any>; // No common pattern for aggregated relations\n}\n\nexport interface IThreadBundledRelationship {\n latest_event: IEvent;\n count: number;\n current_user_participated?: boolean;\n}\n\nexport interface IEvent {\n event_id: string;\n type: string;\n content: IContent;\n sender: string;\n room_id?: string;\n origin_server_ts: number;\n txn_id?: string;\n state_key?: string;\n membership?: string;\n unsigned: IUnsigned;\n redacts?: string;\n\n /**\n * @deprecated in favour of `sender`\n */\n user_id?: string;\n /**\n * @deprecated in favour of `unsigned.prev_content`\n */\n prev_content?: IContent;\n /**\n * @deprecated in favour of `origin_server_ts`\n */\n age?: number;\n}\n\nexport interface IAggregatedRelation {\n origin_server_ts: number;\n event_id?: string;\n sender?: string;\n type?: string;\n count?: number;\n key?: string;\n}\n\nexport interface IEventRelation {\n \"rel_type\"?: RelationType | string;\n \"event_id\"?: string;\n \"is_falling_back\"?: boolean;\n \"m.in_reply_to\"?: {\n event_id?: string;\n };\n \"key\"?: string;\n}\n\nexport interface IMentions {\n user_ids?: string[];\n room?: boolean;\n}\n\n/**\n * When an event is a visibility change event, as per MSC3531,\n * the visibility change implied by the event.\n */\nexport interface IVisibilityChange {\n /**\n * If `true`, the target event should be made visible.\n * Otherwise, it should be hidden.\n */\n visible: boolean;\n\n /**\n * The event id affected.\n */\n eventId: string;\n\n /**\n * Optionally, a human-readable reason explaining why\n * the event was hidden. Ignored if the event was made\n * visible.\n */\n reason: string | null;\n}\n\nexport interface IClearEvent {\n room_id?: string;\n type: string;\n content: Omit<IContent, \"membership\" | \"avatar_url\" | \"displayname\" | \"m.relates_to\">;\n unsigned?: IUnsigned;\n}\n/* eslint-enable camelcase */\n\ninterface IKeyRequestRecipient {\n userId: string;\n deviceId: \"*\" | string;\n}\n\nexport interface IDecryptOptions {\n // Emits \"event.decrypted\" if set to true\n emit?: boolean;\n // True if this is a retry (enables more logging)\n isRetry?: boolean;\n // whether the message should be re-decrypted if it was previously successfully decrypted with an untrusted key\n forceRedecryptIfUntrusted?: boolean;\n}\n\n/**\n * Message hiding, as specified by https://github.com/matrix-org/matrix-doc/pull/3531.\n */\nexport type MessageVisibility = IMessageVisibilityHidden | IMessageVisibilityVisible;\n/**\n * Variant of `MessageVisibility` for the case in which the message should be displayed.\n */\nexport interface IMessageVisibilityVisible {\n readonly visible: true;\n}\n/**\n * Variant of `MessageVisibility` for the case in which the message should be hidden.\n */\nexport interface IMessageVisibilityHidden {\n readonly visible: false;\n /**\n * Optionally, a human-readable reason to show to the user indicating why the\n * message has been hidden (e.g. \"Message Pending Moderation\").\n */\n readonly reason: string | null;\n}\n// A singleton implementing `IMessageVisibilityVisible`.\nconst MESSAGE_VISIBLE: IMessageVisibilityVisible = Object.freeze({ visible: true });\n\nexport enum MatrixEventEvent {\n Decrypted = \"Event.decrypted\",\n BeforeRedaction = \"Event.beforeRedaction\",\n VisibilityChange = \"Event.visibilityChange\",\n LocalEventIdReplaced = \"Event.localEventIdReplaced\",\n Status = \"Event.status\",\n Replaced = \"Event.replaced\",\n RelationsCreated = \"Event.relationsCreated\",\n}\n\nexport type MatrixEventEmittedEvents = MatrixEventEvent | ThreadEvent.Update;\n\nexport type MatrixEventHandlerMap = {\n /**\n * Fires when an event is decrypted\n *\n * @param event - The matrix event which has been decrypted\n * @param err - The error that occurred during decryption, or `undefined` if no error occurred.\n */\n [MatrixEventEvent.Decrypted]: (event: MatrixEvent, err?: Error) => void;\n [MatrixEventEvent.BeforeRedaction]: (event: MatrixEvent, redactionEvent: MatrixEvent) => void;\n [MatrixEventEvent.VisibilityChange]: (event: MatrixEvent, visible: boolean) => void;\n [MatrixEventEvent.LocalEventIdReplaced]: (event: MatrixEvent) => void;\n [MatrixEventEvent.Status]: (event: MatrixEvent, status: EventStatus | null) => void;\n [MatrixEventEvent.Replaced]: (event: MatrixEvent) => void;\n [MatrixEventEvent.RelationsCreated]: (relationType: string, eventType: string) => void;\n} & Pick<ThreadEventHandlerMap, ThreadEvent.Update>;\n\nexport class MatrixEvent extends TypedEventEmitter<MatrixEventEmittedEvents, MatrixEventHandlerMap> {\n private pushActions: IActionsObject | null = null;\n private _replacingEvent: MatrixEvent | null = null;\n private _localRedactionEvent: MatrixEvent | null = null;\n private _isCancelled = false;\n private clearEvent?: IClearEvent;\n\n /* Message hiding, as specified by https://github.com/matrix-org/matrix-doc/pull/3531.\n\n Note: We're returning this object, so any value stored here MUST be frozen.\n */\n private visibility: MessageVisibility = MESSAGE_VISIBLE;\n\n // Not all events will be extensible-event compatible, so cache a flag in\n // addition to a falsy cached event value. We check the flag later on in\n // a public getter to decide if the cache is valid.\n private _hasCachedExtEv = false;\n private _cachedExtEv: Optional<ExtensibleEvent> = undefined;\n\n /* curve25519 key which we believe belongs to the sender of the event. See\n * getSenderKey()\n */\n private senderCurve25519Key: string | null = null;\n\n /* ed25519 key which the sender of this event (for olm) or the creator of\n * the megolm session (for megolm) claims to own. See getClaimedEd25519Key()\n */\n private claimedEd25519Key: string | null = null;\n\n /* curve25519 keys of devices involved in telling us about the\n * senderCurve25519Key and claimedEd25519Key.\n * See getForwardingCurve25519KeyChain().\n */\n private forwardingCurve25519KeyChain: string[] = [];\n\n /* where the decryption key is untrusted\n */\n private untrusted: boolean | null = null;\n\n /* if we have a process decrypting this event, a Promise which resolves\n * when it is finished. Normally null.\n */\n private decryptionPromise: Promise<void> | null = null;\n\n /* flag to indicate if we should retry decrypting this event after the\n * first attempt (eg, we have received new data which means that a second\n * attempt may succeed)\n */\n private retryDecryption = false;\n\n /* The txnId with which this event was sent if it was during this session,\n * allows for a unique ID which does not change when the event comes back down sync.\n */\n private txnId?: string;\n\n /**\n * A reference to the thread this event belongs to\n */\n private thread?: Thread;\n private threadId?: string;\n\n /*\n * True if this event is an encrypted event which we failed to decrypt, the receiver's device is unverified and\n * the sender has disabled encrypting to unverified devices.\n */\n private encryptedDisabledForUnverifiedDevices = false;\n\n /* Set an approximate timestamp for the event relative the local clock.\n * This will inherently be approximate because it doesn't take into account\n * the time between the server putting the 'age' field on the event as it sent\n * it to us and the time we're now constructing this event, but that's better\n * than assuming the local clock is in sync with the origin HS's clock.\n */\n public localTimestamp: number;\n\n /**\n * The room member who sent this event, or null e.g.\n * this is a presence event. This is only guaranteed to be set for events that\n * appear in a timeline, ie. do not guarantee that it will be set on state\n * events.\n * @privateRemarks\n * Should be read-only\n */\n public sender: RoomMember | null = null;\n /**\n * The room member who is the target of this event, e.g.\n * the invitee, the person being banned, etc.\n * @privateRemarks\n * Should be read-only\n */\n public target: RoomMember | null = null;\n /**\n * The sending status of the event.\n * @privateRemarks\n * Should be read-only\n */\n public status: EventStatus | null = null;\n /**\n * most recent error associated with sending the event, if any\n * @privateRemarks\n * Should be read-only\n */\n public error: MatrixError | null = null;\n /**\n * True if this event is 'forward looking', meaning\n * that getDirectionalContent() will return event.content and not event.prev_content.\n * Only state events may be backwards looking\n * Default: true. <strong>This property is experimental and may change.</strong>\n * @privateRemarks\n * Should be read-only\n */\n public forwardLooking = true;\n\n /* If the event is a `m.key.verification.request` (or to_device `m.key.verification.start`) event,\n * `Crypto` will set this the `VerificationRequest` for the event\n * so it can be easily accessed from the timeline.\n */\n public verificationRequest?: VerificationRequest;\n\n private readonly reEmitter: TypedReEmitter<MatrixEventEmittedEvents, MatrixEventHandlerMap>;\n\n /**\n * Construct a Matrix Event object\n *\n * @param event - The raw (possibly encrypted) event. <b>Do not access\n * this property</b> directly unless you absolutely have to. Prefer the getter\n * methods defined on this class. Using the getter methods shields your app\n * from changes to event JSON between Matrix versions.\n */\n public constructor(public event: Partial<IEvent> = {}) {\n super();\n\n // intern the values of matrix events to force share strings and reduce the\n // amount of needless string duplication. This can save moderate amounts of\n // memory (~10% on a 350MB heap).\n // 'membership' at the event level (rather than the content level) is a legacy\n // field that Element never otherwise looks at, but it will still take up a lot\n // of space if we don't intern it.\n ([\"state_key\", \"type\", \"sender\", \"room_id\", \"membership\"] as const).forEach((prop) => {\n if (typeof event[prop] !== \"string\") return;\n event[prop] = internaliseString(event[prop]!);\n });\n\n ([\"membership\", \"avatar_url\", \"displayname\"] as const).forEach((prop) => {\n if (typeof event.content?.[prop] !== \"string\") return;\n event.content[prop] = internaliseString(event.content[prop]!);\n });\n\n ([\"rel_type\"] as const).forEach((prop) => {\n if (typeof event.content?.[\"m.relates_to\"]?.[prop] !== \"string\") return;\n event.content[\"m.relates_to\"][prop] = internaliseString(event.content[\"m.relates_to\"][prop]!);\n });\n\n this.txnId = event.txn_id;\n this.localTimestamp = Date.now() - (this.getAge() ?? 0);\n this.reEmitter = new TypedReEmitter(this);\n }\n\n /**\n * Unstable getter to try and get an extensible event. Note that this might\n * return a falsy value if the event could not be parsed as an extensible\n * event.\n *\n * @deprecated Use stable functions where possible.\n */\n public get unstableExtensibleEvent(): Optional<ExtensibleEvent> {\n if (!this._hasCachedExtEv) {\n this._cachedExtEv = ExtensibleEvents.parse(this.getEffectiveEvent());\n }\n return this._cachedExtEv;\n }\n\n private invalidateExtensibleEvent(): void {\n // just reset the flag - that'll trick the getter into parsing a new event\n this._hasCachedExtEv = false;\n }\n\n /**\n * Gets the event as though it would appear unencrypted. If the event is already not\n * encrypted, it is simply returned as-is.\n * @returns The event in wire format.\n */\n public getEffectiveEvent(): IEvent {\n const content = Object.assign({}, this.getContent()); // clone for mutation\n\n if (this.getWireType() === EventType.RoomMessageEncrypted) {\n // Encrypted events sometimes aren't symmetrical on the `content` so we'll copy\n // that over too, but only for missing properties. We don't copy over mismatches\n // between the plain and decrypted copies of `content` because we assume that the\n // app is relying on the decrypted version, so we want to expose that as a source\n // of truth here too.\n for (const [key, value] of Object.entries(this.getWireContent())) {\n // Skip fields from the encrypted event schema though - we don't want to leak\n // these.\n if ([\"algorithm\", \"ciphertext\", \"device_id\", \"sender_key\", \"session_id\"].includes(key)) {\n continue;\n }\n\n if (content[key] === undefined) content[key] = value;\n }\n }\n\n // clearEvent doesn't have all the fields, so we'll copy what we can from this.event.\n // We also copy over our \"fixed\" content key.\n return Object.assign({}, this.event, this.clearEvent, { content }) as IEvent;\n }\n\n /**\n * Get the event_id for this event.\n * @returns The event ID, e.g. <code>$143350589368169JsLZx:localhost\n * </code>\n */\n public getId(): string | undefined {\n return this.event.event_id;\n }\n\n /**\n * Get the user_id for this event.\n * @returns The user ID, e.g. `@alice:matrix.org`\n */\n public getSender(): string | undefined {\n return this.event.sender || this.event.user_id; // v2 / v1\n }\n\n /**\n * Get the (decrypted, if necessary) type of event.\n *\n * @returns The event type, e.g. `m.room.message`\n */\n public getType(): EventType | string {\n if (this.clearEvent) {\n return this.clearEvent.type;\n }\n return this.event.type!;\n }\n\n /**\n * Get the (possibly encrypted) type of the event that will be sent to the\n * homeserver.\n *\n * @returns The event type.\n */\n public getWireType(): EventType | string {\n return this.event.type!;\n }\n\n /**\n * Get the room_id for this event. This will return `undefined`\n * for `m.presence` events.\n * @returns The room ID, e.g. <code>!cURbafjkfsMDVwdRDQ:matrix.org\n * </code>\n */\n public getRoomId(): string | undefined {\n return this.event.room_id;\n }\n\n /**\n * Get the timestamp of this event.\n * @returns The event timestamp, e.g. `1433502692297`\n */\n public getTs(): number {\n return this.event.origin_server_ts!;\n }\n\n /**\n * Get the timestamp of this event, as a Date object.\n * @returns The event date, e.g. `new Date(1433502692297)`\n */\n public getDate(): Date | null {\n return this.event.origin_server_ts ? new Date(this.event.origin_server_ts) : null;\n }\n\n /**\n * Get a string containing details of this event\n *\n * This is intended for logging, to help trace errors. Example output:\n *\n * @example\n * ```\n * id=$HjnOHV646n0SjLDAqFrgIjim7RCpB7cdMXFrekWYAn type=m.room.encrypted\n * sender=@user:example.com room=!room:example.com ts=2022-10-25T17:30:28.404Z\n * ```\n */\n public getDetails(): string {\n let details = `id=${this.getId()} type=${this.getWireType()} sender=${this.getSender()}`;\n const room = this.getRoomId();\n if (room) {\n details += ` room=${room}`;\n }\n const date = this.getDate();\n if (date) {\n details += ` ts=${date.toISOString()}`;\n }\n return details;\n }\n\n /**\n * Get the (decrypted, if necessary) event content JSON, even if the event\n * was replaced by another event.\n *\n * @returns The event content JSON, or an empty object.\n */\n public getOriginalContent<T = IContent>(): T {\n if (this._localRedactionEvent) {\n return {} as T;\n }\n if (this.clearEvent) {\n return (this.clearEvent.content || {}) as T;\n }\n return (this.event.content || {}) as T;\n }\n\n /**\n * Get the (decrypted, if necessary) event content JSON,\n * or the content from the replacing event, if any.\n * See `makeReplaced`.\n *\n * @returns The event content JSON, or an empty object.\n */\n public getContent<T extends IContent = IContent>(): T {\n if (this._localRedactionEvent) {\n return {} as T;\n } else if (this._replacingEvent) {\n return this._replacingEvent.getContent()[\"m.new_content\"] || {};\n } else {\n return this.getOriginalContent();\n }\n }\n\n /**\n * Get the (possibly encrypted) event content JSON that will be sent to the\n * homeserver.\n *\n * @returns The event content JSON, or an empty object.\n */\n public getWireContent(): IContent {\n return this.event.content || {};\n }\n\n /**\n * Get the event ID of the thread head\n */\n public get threadRootId(): string | undefined {\n const relatesTo = this.getWireContent()?.[\"m.relates_to\"];\n if (relatesTo?.rel_type === THREAD_RELATION_TYPE.name) {\n return relatesTo.event_id;\n } else {\n return this.getThread()?.id || this.threadId;\n }\n }\n\n /**\n * A helper to check if an event is a thread's head or not\n */\n public get isThreadRoot(): boolean {\n const threadDetails = this.getServerAggregatedRelation<IThreadBundledRelationship>(THREAD_RELATION_TYPE.name);\n\n // Bundled relationships only returned when the sync response is limited\n // hence us having to check both bundled relation and inspect the thread\n // model\n return !!threadDetails || this.getThread()?.id === this.getId();\n }\n\n public get replyEventId(): string | undefined {\n return this.getWireContent()[\"m.relates_to\"]?.[\"m.in_reply_to\"]?.event_id;\n }\n\n public get relationEventId(): string | undefined {\n return this.getWireContent()?.[\"m.relates_to\"]?.event_id;\n }\n\n /**\n * Get the previous event content JSON. This will only return something for\n * state events which exist in the timeline.\n * @returns The previous event content JSON, or an empty object.\n */\n public getPrevContent(): IContent {\n // v2 then v1 then default\n return this.getUnsigned().prev_content || this.event.prev_content || {};\n }\n\n /**\n * Get either 'content' or 'prev_content' depending on if this event is\n * 'forward-looking' or not. This can be modified via event.forwardLooking.\n * In practice, this means we get the chronologically earlier content value\n * for this event (this method should surely be called getEarlierContent)\n * <strong>This method is experimental and may change.</strong>\n * @returns event.content if this event is forward-looking, else\n * event.prev_content.\n */\n public getDirectionalContent(): IContent {\n return this.forwardLooking ? this.getContent() : this.getPrevContent();\n }\n\n /**\n * Get the age of this event. This represents the age of the event when the\n * event arrived at the device, and not the age of the event when this\n * function was called.\n * Can only be returned once the server has echo'ed back\n * @returns The age of this event in milliseconds.\n */\n public getAge(): number | undefined {\n return this.getUnsigned().age || this.event.age; // v2 / v1\n }\n\n /**\n * Get the age of the event when this function was called.\n * This is the 'age' field adjusted according to how long this client has\n * had the event.\n * @returns The age of this event in milliseconds.\n */\n public getLocalAge(): number {\n return Date.now() - this.localTimestamp;\n }\n\n /**\n * Get the event state_key if it has one. This will return <code>undefined\n * </code> for message events.\n * @returns The event's `state_key`.\n */\n public getStateKey(): string | undefined {\n return this.event.state_key;\n }\n\n /**\n * Check if this event is a state event.\n * @returns True if this is a state event.\n */\n public isState(): boolean {\n return this.event.state_key !== undefined;\n }\n\n /**\n * Replace the content of this event with encrypted versions.\n * (This is used when sending an event; it should not be used by applications).\n *\n * @internal\n *\n * @param cryptoType - type of the encrypted event - typically\n * <tt>\"m.room.encrypted\"</tt>\n *\n * @param cryptoContent - raw 'content' for the encrypted event.\n *\n * @param senderCurve25519Key - curve25519 key to record for the\n * sender of this event.\n * See {@link MatrixEvent#getSenderKey}.\n *\n * @param claimedEd25519Key - claimed ed25519 key to record for the\n * sender if this event.\n * See {@link MatrixEvent#getClaimedEd25519Key}\n */\n public makeEncrypted(\n cryptoType: string,\n cryptoContent: object,\n senderCurve25519Key: string,\n claimedEd25519Key: string,\n ): void {\n // keep the plain-text data for 'view source'\n this.clearEvent = {\n type: this.event.type!,\n content: this.event.content!,\n };\n this.event.type = cryptoType;\n this.event.content = cryptoContent;\n this.senderCurve25519Key = senderCurve25519Key;\n this.claimedEd25519Key = claimedEd25519Key;\n }\n\n /**\n * Check if this event is currently being decrypted.\n *\n * @returns True if this event is currently being decrypted, else false.\n */\n public isBeingDecrypted(): boolean {\n return this.decryptionPromise != null;\n }\n\n public getDecryptionPromise(): Promise<void> | null {\n return this.decryptionPromise;\n }\n\n /**\n * Check if this event is an encrypted event which we failed to decrypt\n *\n * (This implies that we might retry decryption at some point in the future)\n *\n * @returns True if this event is an encrypted event which we\n * couldn't decrypt.\n */\n public isDecryptionFailure(): boolean {\n return this.clearEvent?.content?.msgtype === \"m.bad.encrypted\";\n }\n\n /*\n * True if this event is an encrypted event which we failed to decrypt, the receiver's device is unverified and\n * the sender has disabled encrypting to unverified devices.\n */\n public get isEncryptedDisabledForUnverifiedDevices(): boolean {\n return this.isDecryptionFailure() && this.encryptedDisabledForUnverifiedDevices;\n }\n\n public shouldAttemptDecryption(): boolean {\n if (this.isRedacted()) return false;\n if (this.isBeingDecrypted()) return false;\n if (this.clearEvent) return false;\n if (!this.isEncrypted()) return false;\n\n return true;\n }\n\n /**\n * Start the process of trying to decrypt this event.\n *\n * (This is used within the SDK: it isn't intended for use by applications)\n *\n * @internal\n *\n * @param crypto - crypto module\n *\n * @returns promise which resolves (to undefined) when the decryption\n * attempt is completed.\n */\n public async attemptDecryption(crypto: CryptoBackend, options: IDecryptOptions = {}): Promise<void> {\n // start with a couple of sanity checks.\n if (!this.isEncrypted()) {\n throw new Error(\"Attempt to decrypt event which isn't encrypted\");\n }\n\n const alreadyDecrypted = this.clearEvent && !this.isDecryptionFailure();\n const forceRedecrypt = options.forceRedecryptIfUntrusted && this.isKeySourceUntrusted();\n if (alreadyDecrypted && !forceRedecrypt) {\n // we may want to just ignore this? let's start with rejecting it.\n throw new Error(\"Attempt to decrypt event which has already been decrypted\");\n }\n\n // if we already have a decryption attempt in progress, then it may\n // fail because it was using outdated info. We now have reason to\n // succeed where it failed before, but we don't want to have multiple\n // attempts going at the same time, so just set a flag that says we have\n // new info.\n //\n if (this.decryptionPromise) {\n logger.log(`Event ${this.getId()} already being decrypted; queueing a retry`);\n this.retryDecryption = true;\n return this.decryptionPromise;\n }\n\n this.decryptionPromise = this.decryptionLoop(crypto, options);\n return this.decryptionPromise;\n }\n\n /**\n * Cancel any room key request for this event and resend another.\n *\n * @param crypto - crypto module\n * @param userId - the user who received this event\n *\n * @returns a promise that resolves when the request is queued\n */\n public cancelAndResendKeyRequest(crypto: Crypto, userId: string): Promise<void> {\n const wireContent = this.getWireContent();\n return crypto.requestRoomKey(\n {\n algorithm: wireContent.algorithm,\n room_id: this.getRoomId()!,\n session_id: wireContent.session_id,\n sender_key: wireContent.sender_key,\n },\n this.getKeyRequestRecipients(userId),\n true,\n );\n }\n\n /**\n * Calculate the recipients for keyshare requests.\n *\n * @param userId - the user who received this event.\n *\n * @returns array of recipients\n */\n public getKeyRequestRecipients(userId: string): IKeyRequestRecipient[] {\n // send the request to all of our own devices\n const recipients = [\n {\n userId,\n deviceId: \"*\",\n },\n ];\n\n return recipients;\n }\n\n private async decryptionLoop(crypto: CryptoBackend, options: IDecryptOptions = {}): Promise<void> {\n // make sure that this method never runs completely synchronously.\n // (doing so would mean that we would clear decryptionPromise *before*\n // it is set in attemptDecryption - and hence end up with a stuck\n // `decryptionPromise`).\n await Promise.resolve();\n\n // eslint-disable-next-line no-constant-condition\n while (true) {\n this.retryDecryption = false;\n\n let res: IEventDecryptionResult;\n let err: Error | undefined = undefined;\n try {\n if (!crypto) {\n res = this.badEncryptedMessage(\"Encryption not enabled\");\n } else {\n res = await crypto.decryptEvent(this);\n if (options.isRetry === true) {\n logger.info(`Decrypted event on retry (${this.getDetails()})`);\n }\n }\n } catch (e) {\n const detailedError = e instanceof DecryptionError ? (<DecryptionError>e).detailedString : String(e);\n\n err = e as Error;\n\n // see if we have a retry queued.\n //\n // NB: make sure to keep this check in the same tick of the\n // event loop as `decryptionPromise = null` below - otherwise we\n // risk a race:\n //\n // * A: we check retryDecryption here and see that it is\n // false\n // * B: we get a second call to attemptDecryption, which sees\n // that decryptionPromise is set so sets\n // retryDecryption\n // * A: we continue below, clear decryptionPromise, and\n // never do the retry.\n //\n if (this.retryDecryption) {\n // decryption error, but we have a retry queued.\n logger.log(`Error decrypting event (${this.getDetails()}), but retrying: ${detailedError}`);\n continue;\n }\n\n // decryption error, no retries queued. Warn about the error and\n // set it to m.bad.encrypted.\n //\n // the detailedString already includes the name and message of the error, and the stack isn't much use,\n // so we don't bother to log `e` separately.\n logger.warn(`Error decrypting event (${this.getDetails()}): ${detailedError}`);\n\n res = this.badEncryptedMessage(String(e));\n }\n\n // at this point, we've either successfully decrypted the event, or have given up\n // (and set res to a 'badEncryptedMessage'). Either way, we can now set the\n // cleartext of the event and raise Event.decrypted.\n //\n // make sure we clear 'decryptionPromise' before sending the 'Event.decrypted' event,\n // otherwise the app will be confused to see `isBeingDecrypted` still set when\n // there isn't an `Event.decrypted` on the way.\n //\n // see also notes on retryDecryption above.\n //\n this.decryptionPromise = null;\n this.retryDecryption = false;\n this.setClearData(res);\n\n // Before we emit the event, clear the push actions so that they can be recalculated\n // by relevant code. We do this because the clear event has now changed, making it\n // so that existing rules can be re-run over the applicable properties. Stuff like\n // highlighting when the user's name is mentioned rely on this happening. We also want\n // to set the push actions before emitting so that any notification listeners don't\n // pick up the wrong contents.\n this.setPushActions(null);\n\n if (options.emit !== false) {\n this.emit(MatrixEventEvent.Decrypted, this, err);\n }\n\n return;\n }\n }\n\n private badEncryptedMessage(reason: string): IEventDecryptionResult {\n return {\n clearEvent: {\n type: EventType.RoomMessage,\n content: {\n msgtype: \"m.bad.encrypted\",\n body: \"** Unable to decrypt: \" + reason + \" **\",\n },\n },\n encryptedDisabledForUnverifiedDevices: reason === `DecryptionError: ${WITHHELD_MESSAGES[\"m.unverified\"]}`,\n };\n }\n\n /**\n * Update the cleartext data on this event.\n *\n * (This is used after decrypting an event; it should not be used by applications).\n *\n * @internal\n *\n * @param decryptionResult - the decryption result, including the plaintext and some key info\n *\n * @remarks\n * Fires {@link MatrixEventEvent.Decrypted}\n */\n private setClearData(decryptionResult: IEventDecryptionResult): void {\n this.clearEvent = decryptionResult.clearEvent;\n this.senderCurve25519Key = decryptionResult.senderCurve25519Key ?? null;\n this.claimedEd25519Key = decryptionResult.claimedEd25519Key ?? null;\n this.forwardingCurve25519KeyChain = decryptionResult.forwardingCurve25519KeyChain || [];\n this.untrusted = decryptionResult.untrusted || false;\n this.encryptedDisabledForUnverifiedDevices = decryptionResult.encryptedDisabledForUnverifiedDevices || false;\n this.invalidateExtensibleEvent();\n }\n\n /**\n * Gets the cleartext content for this event. If the event is not encrypted,\n * or encryption has not been completed, this will return null.\n *\n * @returns The cleartext (decrypted) content for the event\n */\n public getClearContent(): IContent | null {\n return this.clearEvent ? this.clearEvent.content : null;\n }\n\n /**\n * Check if the event is encrypted.\n * @returns True if this event is encrypted.\n */\n public isEncrypted(): boolean {\n return !this.isState() && this.event.type === EventType.RoomMessageEncrypted;\n }\n\n /**\n * The curve25519 key for the device that we think sent this event\n *\n * For an Olm-encrypted event, this is inferred directly from the DH\n * exchange at the start of the session: the curve25519 key is involved in\n * the DH exchange, so only a device which holds the private part of that\n * key can establish such a session.\n *\n * For a megolm-encrypted event, it is inferred from the Olm message which\n * established the megolm session\n */\n public getSenderKey(): string | null {\n return this.senderCurve25519Key;\n }\n\n /**\n * The additional keys the sender of this encrypted event claims to possess.\n *\n * Just a wrapper for #getClaimedEd25519Key (q.v.)\n */\n public getKeysClaimed(): Partial<Record<\"ed25519\", string>> {\n if (!this.claimedEd25519Key) return {};\n\n return {\n ed25519: this.claimedEd25519Key,\n };\n }\n\n /**\n * Get the ed25519 the sender of this event claims to own.\n *\n * For Olm messages, this claim is encoded directly in the plaintext of the\n * event itself. For megolm messages, it is implied by the m.room_key event\n * which established the megolm session.\n *\n * Until we download the device list of the sender, it's just a claim: the\n * device list gives a proof that the owner of the curve25519 key used for\n * this event (and returned by #getSenderKey) also owns the ed25519 key by\n * signing the public curve25519 key with the ed25519 key.\n *\n * In general, applications should not use this method directly, but should\n * instead use MatrixClient.getEventSenderDeviceInfo.\n */\n public getClaimedEd25519Key(): string | null {\n return this.claimedEd25519Key;\n }\n\n /**\n * Get the curve25519 keys of the devices which were involved in telling us\n * about the claimedEd25519Key and sender curve25519 key.\n *\n * Normally this will be empty, but in the case of a forwarded megolm\n * session, the sender keys are sent to us by another device (the forwarding\n * device), which we need to trust to do this. In that case, the result will\n * be a list consisting of one entry.\n *\n * If the device that sent us the key (A) got it from another device which\n * it wasn't prepared to vouch for (B), the result will be [A, B]. And so on.\n *\n * @returns base64-encoded curve25519 keys, from oldest to newest.\n */\n public getForwardingCurve25519KeyChain(): string[] {\n return this.forwardingCurve25519KeyChain;\n }\n\n /**\n * Whether the decryption key was obtained from an untrusted source. If so,\n * we cannot verify the authenticity of the message.\n */\n public isKeySourceUntrusted(): boolean | undefined {\n return !!this.untrusted;\n }\n\n public getUnsigned(): IUnsigned {\n return this.event.unsigned || {};\n }\n\n public setUnsigned(unsigned: IUnsigned): void {\n this.event.unsigned = unsigned;\n }\n\n public unmarkLocallyRedacted(): boolean {\n const value = this._localRedactionEvent;\n this._localRedactionEvent = null;\n if (this.event.unsigned) {\n this.event.unsigned.redacted_because = undefined;\n }\n return !!value;\n }\n\n public markLocallyRedacted(redactionEvent: MatrixEvent): void {\n if (this._localRedactionEvent) return;\n this.emit(MatrixEventEvent.BeforeRedaction, this, redactionEvent);\n this._localRedactionEvent = redactionEvent;\n if (!this.event.unsigned) {\n this.event.unsigned = {};\n }\n this.event.unsigned.redacted_because = redactionEvent.event as IEvent;\n }\n\n /**\n * Change the visibility of an event, as per https://github.com/matrix-org/matrix-doc/pull/3531 .\n *\n * @param visibilityChange - event holding a hide/unhide payload, or nothing\n * if the event is being reset to its original visibility (presumably\n * by a visibility event being redacted).\n *\n * @remarks\n * Fires {@link MatrixEventEvent.VisibilityChange} if `visibilityEvent`\n * caused a change in the actual visibility of this event, either by making it\n * visible (if it was hidden), by making it hidden (if it was visible) or by\n * changing the reason (if it was hidden).\n */\n public applyVisibilityEvent(visibilityChange?: IVisibilityChange): void {\n const visible = visibilityChange?.visible ?? true;\n const reason = visibilityChange?.reason ?? null;\n let change = false;\n if (this.visibility.visible !== visible) {\n change = true;\n } else if (!this.visibility.visible && this.visibility[\"reason\"] !== reason) {\n change = true;\n }\n if (change) {\n if (visible) {\n this.visibility = MESSAGE_VISIBLE;\n } else {\n this.visibility = Object.freeze({\n visible: false,\n reason,\n });\n }\n this.emit(MatrixEventEvent.VisibilityChange, this, visible);\n }\n }\n\n /**\n * Return instructions to display or hide the message.\n *\n * @returns Instructions determining whether the message\n * should be displayed.\n */\n public messageVisibility(): MessageVisibility {\n // Note: We may return `this.visibility` without fear, as\n // this is a shallow frozen object.\n return this.visibility;\n }\n\n /**\n * Update the content of an event in the same way it would be by the server\n * if it were redacted before it was sent to us\n *\n * @param redactionEvent - event causing the redaction\n */\n public makeRedacted(redactionEvent: MatrixEvent): void {\n // quick sanity-check\n if (!redactionEvent.event) {\n throw new Error(\"invalid redactionEvent in makeRedacted\");\n }\n\n this._localRedactionEvent = null;\n\n this.emit(MatrixEventEvent.BeforeRedaction, this, redactionEvent);\n\n this._replacingEvent = null;\n // we attempt to replicate what we would see from the server if\n // the event had been redacted before we saw it.\n //\n // The server removes (most of) the content of the event, and adds a\n // \"redacted_because\" key to the unsigned section containing the\n // redacted event.\n if (!this.event.unsigned) {\n this.event.unsigned = {};\n }\n this.event.unsigned.redacted_because = redactionEvent.event as IEvent;\n\n for (const key in this.event) {\n if (this.event.hasOwnProperty(key) && !REDACT_KEEP_KEYS.has(key)) {\n delete this.event[key as keyof IEvent];\n }\n }\n\n // If the event is encrypted prune the decrypted bits\n if (this.isEncrypted()) {\n this.clearEvent = undefined;\n }\n\n const keeps =\n this.getType() in REDACT_KEEP_CONTENT_MAP\n ? REDACT_KEEP_CONTENT_MAP[this.getType() as keyof typeof REDACT_KEEP_CONTENT_MAP]\n : {};\n const content = this.getContent();\n for (const key in content) {\n if (content.hasOwnProperty(key) && !keeps[key]) {\n delete content[key];\n }\n }\n\n this.invalidateExtensibleEvent();\n }\n\n /**\n * Check if this event has been redacted\n *\n * @returns True if this event has been redacted\n */\n public isRedacted(): boolean {\n return Boolean(this.getUnsigned().redacted_because);\n }\n\n /**\n * Check if this event is a redaction of another event\n *\n * @returns True if this event is a redaction\n */\n public isRedaction(): boolean {\n return this.getType() === EventType.RoomRedaction;\n }\n\n /**\n * Return the visibility change caused by this event,\n * as per https://github.com/matrix-org/matrix-doc/pull/3531.\n *\n * @returns If the event is a well-formed visibility change event,\n * an instance of `IVisibilityChange`, otherwise `null`.\n */\n public asVisibilityChange(): IVisibilityChange | null {\n if (!EVENT_VISIBILITY_CHANGE_TYPE.matches(this.getType())) {\n // Not a visibility change event.\n return null;\n }\n const relation = this.getRelation();\n if (!relation || relation.rel_type != \"m.reference\") {\n // Ill-formed, ignore this event.\n return null;\n }\n const eventId = relation.event_id;\n if (!eventId) {\n // Ill-formed, ignore this event.\n return null;\n }\n const content = this.getWireContent();\n const visible = !!content.visible;\n const reason = content.reason;\n if (reason && typeof reason != \"string\") {\n // Ill-formed, ignore this event.\n return null;\n }\n // Well-formed visibility change event.\n return {\n visible,\n reason,\n eventId,\n };\n }\n\n /**\n * Check if this event alters the visibility of another event,\n * as per https://github.com/matrix-org/matrix-doc/pull/3531.\n *\n * @returns True if this event alters the visibility\n * of another event.\n */\n public isVisibilityEvent(): boolean {\n return EVENT_VISIBILITY_CHANGE_TYPE.matches(this.getType());\n }\n\n /**\n * Get the (decrypted, if necessary) redaction event JSON\n * if event was redacted\n *\n * @returns The redaction event JSON, or an empty object\n */\n public getRedactionEvent(): IEvent | {} | null {\n if (!this.isRedacted()) return null;\n\n if (this.clearEvent?.unsigned) {\n return this.clearEvent?.unsigned.redacted_because ?? null;\n } else if (this.event.unsigned?.redacted_because) {\n return this.event.unsigned.redacted_because;\n } else {\n return {};\n }\n }\n\n /**\n * Get the push actions, if known, for this event\n *\n * @returns push actions\n */\n public getPushActions(): IActionsObject | null {\n return this.pushActions;\n }\n\n /**\n * Set the push actions for this event.\n *\n * @param pushActions - push actions\n */\n public setPushActions(pushActions: IActionsObject | null): void {\n this.pushActions = pushActions;\n }\n\n /**\n * Replace the `event` property and recalculate any properties based on it.\n * @param event - the object to assign to the `event` property\n */\n public handleRemoteEcho(event: object): void {\n const oldUnsigned = this.getUnsigned();\n const oldId = this.getId();\n this.event = event;\n // if this event was redacted before it was sent, it's locally marked as redacted.\n // At this point, we've received the remote echo for the event, but not yet for\n // the redaction that we are sending ourselves. Preserve the locally redacted\n // state by copying over redacted_because so we don't get a flash of\n // redacted, not-redacted, redacted as remote echos come in\n if (oldUnsigned.redacted_because) {\n if (!this.event.unsigned) {\n this.event.unsigned = {};\n }\n this.event.unsigned.redacted_because = oldUnsigned.redacted_because;\n }\n // successfully sent.\n this.setStatus(null);\n if (this.getId() !== oldId) {\n // emit the event if it changed\n this.emit(MatrixEventEvent.LocalEventIdReplaced, this);\n }\n\n this.localTimestamp = Date.now() - this.getAge()!;\n }\n\n /**\n * Whether the event is in any phase of sending, send failure, waiting for\n * remote echo, etc.\n */\n public isSending(): boolean {\n return !!this.status;\n }\n\n /**\n * Update the event's sending status and emit an event as well.\n *\n * @param status - The new status\n */\n public setStatus(status: EventStatus | null): void {\n this.status = status;\n this.emit(MatrixEventEvent.Status, this, status);\n }\n\n public replaceLocalEventId(eventId: string): void {\n this.event.event_id = eventId;\n this.emit(MatrixEventEvent.LocalEventIdReplaced, this);\n }\n\n /**\n * Get whether the event is a relation event, and of a given type if\n * `relType` is passed in. State events cannot be relation events\n *\n * @param relType - if given, checks that the relation is of the\n * given type\n */\n public isRelation(relType?: string): boolean {\n // Relation info is lifted out of the encrypted content when sent to\n // encrypted rooms, so we have to check `getWireContent` for this.\n const relation = this.getWireContent()?.[\"m.relates_to\"];\n if (this.isState() && relation?.rel_type === RelationType.Replace) {\n // State events cannot be m.replace relations\n return false;\n }\n return !!(relation?.rel_type && relation.event_id && (relType ? relation.rel_type === relType : true));\n }\n\n /**\n * Get relation info for the event, if any.\n */\n public getRelation(): IEventRelation | null {\n if (!this.isRelation()) {\n return null;\n }\n return this.getWireContent()[\"m.relates_to\"] ?? null;\n }\n\n /**\n * Set an event that replaces the content of this event, through an m.replace relation.\n *\n * @param newEvent - the event with the replacing content, if any.\n *\n * @remarks\n * Fires {@link MatrixEventEvent.Replaced}\n */\n public makeReplaced(newEvent?: MatrixEvent): void {\n // don't allow redacted events to be replaced.\n // if newEvent is null we allow to go through though,\n // as with local redaction, the replacing event might get\n // cancelled, which should be reflected on the target event.\n if (this.isRedacted() && newEvent) {\n return;\n }\n // don't allow state events to be replaced using this mechanism as per MSC2676\n if (this.isState()) {\n return;\n }\n if (this._replacingEvent !== newEvent) {\n this._replacingEvent = newEvent ?? null;\n this.emit(MatrixEventEvent.Replaced, this);\n this.invalidateExtensibleEvent();\n }\n }\n\n /**\n * Returns the status of any associated edit or redaction\n * (not for reactions/annotations as their local echo doesn't affect the original event),\n * or else the status of the event.\n */\n public getAssociatedStatus(): EventStatus | null {\n if (this._replacingEvent) {\n return this._replacingEvent.status;\n } else if (this._localRedactionEvent) {\n return this._localRedactionEvent.status;\n }\n return this.status;\n }\n\n public getServerAggregatedRelation<T>(relType: RelationType | string): T | undefined {\n return this.getUnsigned()[\"m.relations\"]?.[relType];\n }\n\n /**\n * Returns the event ID of the event replacing the content of this event, if any.\n */\n public replacingEventId(): string | undefined {\n const replaceRelation = this.getServerAggregatedRelation<IAggregatedRelation>(RelationType.Replace);\n if (replaceRelation) {\n return replaceRelation.event_id;\n } else if (this._replacingEvent) {\n return this._replacingEvent.getId();\n }\n }\n\n /**\n * Returns the event replacing the content of this event, if any.\n * Replacements are aggregated on the server, so this would only\n * return an event in case it came down the sync, or for local echo of edits.\n */\n public replacingEvent(): MatrixEvent | null {\n return this._replacingEvent;\n }\n\n /**\n * Returns the origin_server_ts of the event replacing the content of this event, if any.\n */\n public replacingEventDate(): Date | undefined {\n const replaceRelation = this.getServerAggregatedRelation<IAggregatedRelation>(RelationType.Replace);\n if (replaceRelation) {\n const ts = replaceRelation.origin_server_ts;\n if (Number.isFinite(ts)) {\n return new Date(ts);\n }\n } else if (this._replacingEvent) {\n return this._replacingEvent.getDate() ?? undefined;\n }\n }\n\n /**\n * Returns the event that wants to redact this event, but hasn't been sent yet.\n * @returns the event\n */\n public localRedactionEvent(): MatrixEvent | null {\n return this._localRedactionEvent;\n }\n\n /**\n * For relations and redactions, returns the event_id this event is referring to.\n */\n public getAssociatedId(): string | undefined {\n const relation = this.getRelation();\n if (this.replyEventId) {\n return this.replyEventId;\n } else if (relation) {\n return relation.event_id;\n } else if (this.isRedaction()) {\n return this.event.redacts;\n }\n }\n\n /**\n * Checks if this event is associated with another event. See `getAssociatedId`.\n * @deprecated use hasAssociation instead.\n */\n public hasAssocation(): boolean {\n return !!this.getAssociatedId();\n }\n\n /**\n * Checks if this event is associated with another event. See `getAssociatedId`.\n */\n public hasAssociation(): boolean {\n return !!this.getAssociatedId();\n }\n\n /**\n * Update the related id with a new one.\n *\n * Used to replace a local id with remote one before sending\n * an event with a related id.\n *\n * @param eventId - the new event id\n */\n public updateAssociatedId(eventId: string): void {\n const relation = this.getRelation();\n if (relation) {\n relation.event_id = eventId;\n } else if (this.isRedaction()) {\n this.event.redacts = eventId;\n }\n }\n\n /**\n * Flags an event as cancelled due to future conditions. For example, a verification\n * request event in the same sync transaction may be flagged as cancelled to warn\n * listeners that a cancellation event is coming down the same pipe shortly.\n * @param cancelled - Whether the event is to be cancelled or not.\n */\n public flagCancelled(cancelled = true): void {\n this._isCancelled = cancelled;\n }\n\n /**\n * Gets whether or not the event is flagged as cancelled. See flagCancelled() for\n * more information.\n * @returns True if the event is cancelled, false otherwise.\n */\n public isCancelled(): boolean {\n return this._isCancelled;\n }\n\n /**\n * Get a copy/snapshot of this event. The returned copy will be loosely linked\n * back to this instance, though will have \"frozen\" event information. Other\n * properties of this MatrixEvent instance will be copied verbatim, which can\n * mean they are in reference to this instance despite being on the copy too.\n * The reference the snapshot uses does not change, however members aside from\n * the underlying event will not be deeply cloned, thus may be mutated internally.\n * For example, the sender profile will be copied over at snapshot time, and\n * the sender profile internally may mutate without notice to the consumer.\n *\n * This is meant to be used to snapshot the event details themselves, not the\n * features (such as sender) surrounding the event.\n * @returns A snapshot of this event.\n */\n public toSnapshot(): MatrixEvent {\n const ev = new MatrixEvent(JSON.parse(JSON.stringify(this.event)));\n for (const [p, v] of Object.entries(this)) {\n if (p !== \"event\") {\n // exclude the thing we just cloned\n // @ts-ignore - XXX: this is just nasty\n ev[p as keyof MatrixEvent] = v;\n }\n }\n return ev;\n }\n\n /**\n * Determines if this event is equivalent to the given event. This only checks\n * the event object itself, not the other properties of the event. Intended for\n * use with toSnapshot() to identify events changing.\n * @param otherEvent - The other event to check against.\n * @returns True if the events are the same, false otherwise.\n */\n public isEquivalentTo(otherEvent: MatrixEvent): boolean {\n if (!otherEvent) return false;\n if (otherEvent === this) return true;\n const myProps = deepSortedObjectEntries(this.event);\n const theirProps = deepSortedObjectEntries(otherEvent.event);\n return JSON.stringify(myProps) === JSON.stringify(theirProps);\n }\n\n /**\n * Summarise the event as JSON. This is currently used by React SDK's view\n * event source feature and Seshat's event indexing, so take care when\n * adjusting the output here.\n *\n * If encrypted, include both the decrypted and encrypted view of the event.\n *\n * This is named `toJSON` for use with `JSON.stringify` which checks objects\n * for functions named `toJSON` and will call them to customise the output\n * if they are defined.\n */\n public toJSON(): object {\n const event = this.getEffectiveEvent();\n\n if (!this.isEncrypted()) {\n return event;\n }\n\n return {\n decrypted: event,\n encrypted: this.event,\n };\n }\n\n public setVerificationRequest(request: VerificationRequest): void {\n this.verificationRequest = request;\n }\n\n public setTxnId(txnId: string): void {\n this.txnId = txnId;\n }\n\n public getTxnId(): string | undefined {\n return this.txnId;\n }\n\n /**\n * Set the instance of a thread associated with the current event\n * @param thread - the thread\n */\n public setThread(thread?: Thread): void {\n if (this.thread) {\n this.reEmitter.stopReEmitting(this.thread, [ThreadEvent.Update]);\n }\n this.thread = thread;\n this.setThreadId(thread?.id);\n if (thread) {\n this.reEmitter.reEmit(thread, [ThreadEvent.Update]);\n }\n }\n\n /**\n * Get the instance of the thread associated with the current event\n */\n public getThread(): Thread | undefined {\n return this.thread;\n }\n\n public setThreadId(threadId?: string): void {\n this.threadId = threadId;\n }\n}\n\n/* REDACT_KEEP_KEYS gives the keys we keep when an event is redacted\n *\n * This is specified here:\n * http://matrix.org/speculator/spec/HEAD/client_server/latest.html#redactions\n *\n * Also:\n * - We keep 'unsigned' since that is created by the local server\n * - We keep user_id for backwards-compat with v1\n */\nconst REDACT_KEEP_KEYS = new Set([\n \"event_id\",\n \"type\",\n \"room_id\",\n \"user_id\",\n \"sender\",\n \"state_key\",\n \"prev_state\",\n \"content\",\n \"unsigned\",\n \"origin_server_ts\",\n]);\n\n// a map from state event type to the .content keys we keep when an event is redacted\nconst REDACT_KEEP_CONTENT_MAP: Record<string, Record<string, 1>> = {\n [EventType.RoomMember]: { membership: 1 },\n [EventType.RoomCreate]: { creator: 1 },\n [EventType.RoomJoinRules]: { join_rule: 1 },\n [EventType.RoomPowerLevels]: {\n ban: 1,\n events: 1,\n events_default: 1,\n kick: 1,\n redact: 1,\n state_default: 1,\n users: 1,\n users_default: 1,\n },\n} as const;\n"],"mappings":"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"} \ No newline at end of file
diff --git a/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/invites-ignorer.d.ts b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/invites-ignorer.d.ts
new file mode 100644
index 0000000..afb901c
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/invites-ignorer.d.ts
@@ -0,0 +1,132 @@
+import { UnstableValue } from "matrix-events-sdk";
+import { MatrixClient } from "../client";
+import { MatrixEvent } from "./event";
+import { Room } from "./room";
+export declare const POLICIES_ACCOUNT_EVENT_TYPE: UnstableValue<"m.policies", "org.matrix.msc3847.policies">;
+export declare const IGNORE_INVITES_ACCOUNT_EVENT_KEY: UnstableValue<"m.ignore.invites", "org.matrix.msc3847.ignore.invites">;
+/**
+ * The various scopes for policies.
+ */
+export declare enum PolicyScope {
+ /**
+ * The policy deals with an individual user, e.g. reject invites
+ * from this user.
+ */
+ User = "m.policy.user",
+ /**
+ * The policy deals with a room, e.g. reject invites towards
+ * a specific room.
+ */
+ Room = "m.policy.room",
+ /**
+ * The policy deals with a server, e.g. reject invites from
+ * this server.
+ */
+ Server = "m.policy.server"
+}
+/**
+ * A container for ignored invites.
+ *
+ * # Performance
+ *
+ * This implementation is extremely naive. It expects that we are dealing
+ * with a very short list of sources (e.g. only one). If real-world
+ * applications turn out to require longer lists, we may need to rework
+ * our data structures.
+ */
+export declare class IgnoredInvites {
+ private readonly client;
+ constructor(client: MatrixClient);
+ /**
+ * Add a new rule.
+ *
+ * @param scope - The scope for this rule.
+ * @param entity - The entity covered by this rule. Globs are supported.
+ * @param reason - A human-readable reason for introducing this new rule.
+ * @returns The event id for the new rule.
+ */
+ addRule(scope: PolicyScope, entity: string, reason: string): Promise<string>;
+ /**
+ * Remove a rule.
+ */
+ removeRule(event: MatrixEvent): Promise<void>;
+ /**
+ * Add a new room to the list of sources. If the user isn't a member of the
+ * room, attempt to join it.
+ *
+ * @param roomId - A valid room id. If this room is already in the list
+ * of sources, it will not be duplicated.
+ * @returns `true` if the source was added, `false` if it was already present.
+ * @throws If `roomId` isn't the id of a room that the current user is already
+ * member of or can join.
+ *
+ * # Safety
+ *
+ * This method will rewrite the `Policies` object in the user's account data.
+ * This rewrite is inherently racy and could overwrite or be overwritten by
+ * other concurrent rewrites of the same object.
+ */
+ addSource(roomId: string): Promise<boolean>;
+ /**
+ * Find out whether an invite should be ignored.
+ *
+ * @param sender - The user id for the user who issued the invite.
+ * @param roomId - The room to which the user is invited.
+ * @returns A rule matching the entity, if any was found, `null` otherwise.
+ */
+ getRuleForInvite({ sender, roomId, }: {
+ sender: string;
+ roomId: string;
+ }): Promise<Readonly<MatrixEvent | null>>;
+ /**
+ * Get the target room, i.e. the room in which any new rule should be written.
+ *
+ * If there is no target room setup, a target room is created.
+ *
+ * Note: This method is public for testing reasons. Most clients should not need
+ * to call it directly.
+ *
+ * # Safety
+ *
+ * This method will rewrite the `Policies` object in the user's account data.
+ * This rewrite is inherently racy and could overwrite or be overwritten by
+ * other concurrent rewrites of the same object.
+ */
+ getOrCreateTargetRoom(): Promise<Room>;
+ /**
+ * Get the list of source rooms, i.e. the rooms from which rules need to be read.
+ *
+ * If no source rooms are setup, the target room is used as sole source room.
+ *
+ * Note: This method is public for testing reasons. Most clients should not need
+ * to call it directly.
+ *
+ * # Safety
+ *
+ * This method will rewrite the `Policies` object in the user's account data.
+ * This rewrite is inherently racy and could overwrite or be overwritten by
+ * other concurrent rewrites of the same object.
+ */
+ getOrCreateSourceRooms(): Promise<Room[]>;
+ /**
+ * Fetch the `IGNORE_INVITES_POLICIES` object from account data.
+ *
+ * If both an unstable prefix version and a stable prefix version are available,
+ * it will return the stable prefix version preferentially.
+ *
+ * The result is *not* validated but is guaranteed to be a non-null object.
+ *
+ * @returns A non-null object.
+ */
+ private getIgnoreInvitesPolicies;
+ /**
+ * Modify in place the `IGNORE_INVITES_POLICIES` object from account data.
+ */
+ private withIgnoreInvitesPolicies;
+ /**
+ * As `getIgnoreInvitesPolicies` but also return the `POLICIES_ACCOUNT_EVENT_TYPE`
+ * object.
+ */
+ private getPoliciesAndIgnoreInvitesPolicies;
+}
+//# sourceMappingURL=invites-ignorer.d.ts.map \ No newline at end of file
diff --git a/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/invites-ignorer.d.ts.map b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/invites-ignorer.d.ts.map
new file mode 100644
index 0000000..846564d
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/invites-ignorer.d.ts.map
@@ -0,0 +1 @@
+{"version":3,"file":"invites-ignorer.d.ts","sourceRoot":"","sources":["../../src/models/invites-ignorer.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAElD,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,EAAY,WAAW,EAAE,MAAM,SAAS,CAAC;AAIhD,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAK9B,eAAO,MAAM,2BAA2B,4DAAiE,CAAC;AAK1G,eAAO,MAAM,gCAAgC,wEAG5C,CAAC;AAOF;;GAEG;AACH,oBAAY,WAAW;IACnB;;;OAGG;IACH,IAAI,kBAAkB;IAEtB;;;OAGG;IACH,IAAI,kBAAkB;IAEtB;;;OAGG;IACH,MAAM,oBAAoB;CAC7B;AAED;;;;;;;;;GASG;AACH,qBAAa,cAAc;IACJ,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAN,MAAM,EAAE,YAAY;IAExD;;;;;;;OAOG;IACU,OAAO,CAAC,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAUzF;;OAEG;IACU,UAAU,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAI1D;;;;;;;;;;;;;;;OAeG;IACU,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAmBxD;;;;;;OAMG;IACU,gBAAgB,CAAC,EAC1B,MAAM,EACN,MAAM,GACT,EAAE;QACC,MAAM,EAAE,MAAM,CAAC;QACf,MAAM,EAAE,MAAM,CAAC;KAClB,GAAG,OAAO,CAAC,QAAQ,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IAqDzC;;;;;;;;;;;;;OAaG;IACU,qBAAqB,IAAI,OAAO,CAAC,IAAI,CAAC;IAgCnD;;;;;;;;;;;;;OAaG;IACU,sBAAsB,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;IAqCtD;;;;;;;;;OASG;IACH,OAAO,CAAC,wBAAwB;IAIhC;;OAEG;YACW,yBAAyB;IASvC;;;OAGG;IACH,OAAO,CAAC,mCAAmC;CAmC9C"} \ No newline at end of file
diff --git a/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/invites-ignorer.js b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/invites-ignorer.js
new file mode 100644
index 0000000..dfa3093
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/invites-ignorer.js
@@ -0,0 +1,360 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.PolicyScope = exports.POLICIES_ACCOUNT_EVENT_TYPE = exports.IgnoredInvites = exports.IGNORE_INVITES_ACCOUNT_EVENT_KEY = void 0;
+var _matrixEventsSdk = require("matrix-events-sdk");
+var _eventTimeline = require("./event-timeline");
+var _partials = require("../@types/partials");
+var _utils = require("../utils");
+/*
+Copyright 2022 The Matrix.org Foundation C.I.C.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+/// The event type storing the user's individual policies.
+///
+/// Exported for testing purposes.
+const POLICIES_ACCOUNT_EVENT_TYPE = new _matrixEventsSdk.UnstableValue("m.policies", "org.matrix.msc3847.policies");
+
+/// The key within the user's individual policies storing the user's ignored invites.
+///
+/// Exported for testing purposes.
+exports.POLICIES_ACCOUNT_EVENT_TYPE = POLICIES_ACCOUNT_EVENT_TYPE;
+const IGNORE_INVITES_ACCOUNT_EVENT_KEY = new _matrixEventsSdk.UnstableValue("m.ignore.invites", "org.matrix.msc3847.ignore.invites");
+
+/// The types of recommendations understood.
+exports.IGNORE_INVITES_ACCOUNT_EVENT_KEY = IGNORE_INVITES_ACCOUNT_EVENT_KEY;
+var PolicyRecommendation;
+/**
+ * The various scopes for policies.
+ */
+(function (PolicyRecommendation) {
+ PolicyRecommendation["Ban"] = "m.ban";
+})(PolicyRecommendation || (PolicyRecommendation = {}));
+let PolicyScope;
+/**
+ * A container for ignored invites.
+ *
+ * # Performance
+ *
+ * This implementation is extremely naive. It expects that we are dealing
+ * with a very short list of sources (e.g. only one). If real-world
+ * applications turn out to require longer lists, we may need to rework
+ * our data structures.
+ */
+exports.PolicyScope = PolicyScope;
+(function (PolicyScope) {
+ PolicyScope["User"] = "m.policy.user";
+ PolicyScope["Room"] = "m.policy.room";
+ PolicyScope["Server"] = "m.policy.server";
+})(PolicyScope || (exports.PolicyScope = PolicyScope = {}));
+class IgnoredInvites {
+ constructor(client) {
+ this.client = client;
+ }
+
+ /**
+ * Add a new rule.
+ *
+ * @param scope - The scope for this rule.
+ * @param entity - The entity covered by this rule. Globs are supported.
+ * @param reason - A human-readable reason for introducing this new rule.
+ * @returns The event id for the new rule.
+ */
+ async addRule(scope, entity, reason) {
+ const target = await this.getOrCreateTargetRoom();
+ const response = await this.client.sendStateEvent(target.roomId, scope, {
+ entity,
+ reason,
+ recommendation: PolicyRecommendation.Ban
+ });
+ return response.event_id;
+ }
+
+ /**
+ * Remove a rule.
+ */
+ async removeRule(event) {
+ await this.client.redactEvent(event.getRoomId(), event.getId());
+ }
+
+ /**
+ * Add a new room to the list of sources. If the user isn't a member of the
+ * room, attempt to join it.
+ *
+ * @param roomId - A valid room id. If this room is already in the list
+ * of sources, it will not be duplicated.
+ * @returns `true` if the source was added, `false` if it was already present.
+ * @throws If `roomId` isn't the id of a room that the current user is already
+ * member of or can join.
+ *
+ * # Safety
+ *
+ * This method will rewrite the `Policies` object in the user's account data.
+ * This rewrite is inherently racy and could overwrite or be overwritten by
+ * other concurrent rewrites of the same object.
+ */
+ async addSource(roomId) {
+ // We attempt to join the room *before* calling
+ // `await this.getOrCreateSourceRooms()` to decrease the duration
+ // of the racy section.
+ await this.client.joinRoom(roomId);
+ // Race starts.
+ const sources = (await this.getOrCreateSourceRooms()).map(room => room.roomId);
+ if (sources.includes(roomId)) {
+ return false;
+ }
+ sources.push(roomId);
+ await this.withIgnoreInvitesPolicies(ignoreInvitesPolicies => {
+ ignoreInvitesPolicies.sources = sources;
+ });
+
+ // Race ends.
+ return true;
+ }
+
+ /**
+ * Find out whether an invite should be ignored.
+ *
+ * @param sender - The user id for the user who issued the invite.
+ * @param roomId - The room to which the user is invited.
+ * @returns A rule matching the entity, if any was found, `null` otherwise.
+ */
+ async getRuleForInvite({
+ sender,
+ roomId
+ }) {
+ // In this implementation, we perform a very naive lookup:
+ // - search in each policy room;
+ // - turn each (potentially glob) rule entity into a regexp.
+ //
+ // Real-world testing will tell us whether this is performant enough.
+ // In the (unfortunately likely) case it isn't, there are several manners
+ // in which we could optimize this:
+ // - match several entities per go;
+ // - pre-compile each rule entity into a regexp;
+ // - pre-compile entire rooms into a single regexp.
+ const policyRooms = await this.getOrCreateSourceRooms();
+ const senderServer = sender.split(":")[1];
+ const roomServer = roomId.split(":")[1];
+ for (const room of policyRooms) {
+ const state = room.getUnfilteredTimelineSet().getLiveTimeline().getState(_eventTimeline.EventTimeline.FORWARDS);
+ for (const {
+ scope,
+ entities
+ } of [{
+ scope: PolicyScope.Room,
+ entities: [roomId]
+ }, {
+ scope: PolicyScope.User,
+ entities: [sender]
+ }, {
+ scope: PolicyScope.Server,
+ entities: [senderServer, roomServer]
+ }]) {
+ const events = state.getStateEvents(scope);
+ for (const event of events) {
+ const content = event.getContent();
+ if ((content === null || content === void 0 ? void 0 : content.recommendation) != PolicyRecommendation.Ban) {
+ // Ignoring invites only looks at `m.ban` recommendations.
+ continue;
+ }
+ const glob = content === null || content === void 0 ? void 0 : content.entity;
+ if (!glob) {
+ // Invalid event.
+ continue;
+ }
+ let regexp;
+ try {
+ regexp = new RegExp((0, _utils.globToRegexp)(glob, false));
+ } catch (ex) {
+ // Assume invalid event.
+ continue;
+ }
+ for (const entity of entities) {
+ if (entity && regexp.test(entity)) {
+ return event;
+ }
+ }
+ // No match.
+ }
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Get the target room, i.e. the room in which any new rule should be written.
+ *
+ * If there is no target room setup, a target room is created.
+ *
+ * Note: This method is public for testing reasons. Most clients should not need
+ * to call it directly.
+ *
+ * # Safety
+ *
+ * This method will rewrite the `Policies` object in the user's account data.
+ * This rewrite is inherently racy and could overwrite or be overwritten by
+ * other concurrent rewrites of the same object.
+ */
+ async getOrCreateTargetRoom() {
+ const ignoreInvitesPolicies = this.getIgnoreInvitesPolicies();
+ let target = ignoreInvitesPolicies.target;
+ // Validate `target`. If it is invalid, trash out the current `target`
+ // and create a new room.
+ if (typeof target !== "string") {
+ target = null;
+ }
+ if (target) {
+ // Check that the room exists and is valid.
+ const room = this.client.getRoom(target);
+ if (room) {
+ return room;
+ } else {
+ target = null;
+ }
+ }
+ // We need to create our own policy room for ignoring invites.
+ target = (await this.client.createRoom({
+ name: "Individual Policy Room",
+ preset: _partials.Preset.PrivateChat
+ })).room_id;
+ await this.withIgnoreInvitesPolicies(ignoreInvitesPolicies => {
+ ignoreInvitesPolicies.target = target;
+ });
+
+ // Since we have just called `createRoom`, `getRoom` should not be `null`.
+ return this.client.getRoom(target);
+ }
+
+ /**
+ * Get the list of source rooms, i.e. the rooms from which rules need to be read.
+ *
+ * If no source rooms are setup, the target room is used as sole source room.
+ *
+ * Note: This method is public for testing reasons. Most clients should not need
+ * to call it directly.
+ *
+ * # Safety
+ *
+ * This method will rewrite the `Policies` object in the user's account data.
+ * This rewrite is inherently racy and could overwrite or be overwritten by
+ * other concurrent rewrites of the same object.
+ */
+ async getOrCreateSourceRooms() {
+ const ignoreInvitesPolicies = this.getIgnoreInvitesPolicies();
+ let sources = ignoreInvitesPolicies.sources;
+
+ // Validate `sources`. If it is invalid, trash out the current `sources`
+ // and create a new list of sources from `target`.
+ let hasChanges = false;
+ if (!Array.isArray(sources)) {
+ // `sources` could not be an array.
+ hasChanges = true;
+ sources = [];
+ }
+ let sourceRooms = sources
+ // `sources` could contain non-string / invalid room ids
+ .filter(roomId => typeof roomId === "string").map(roomId => this.client.getRoom(roomId)).filter(room => !!room);
+ if (sourceRooms.length != sources.length) {
+ hasChanges = true;
+ }
+ if (sourceRooms.length == 0) {
+ // `sources` could be empty (possibly because we've removed
+ // invalid content)
+ const target = await this.getOrCreateTargetRoom();
+ hasChanges = true;
+ sourceRooms = [target];
+ }
+ if (hasChanges) {
+ // Reload `policies`/`ignoreInvitesPolicies` in case it has been changed
+ // during or by our call to `this.getTargetRoom()`.
+ await this.withIgnoreInvitesPolicies(ignoreInvitesPolicies => {
+ ignoreInvitesPolicies.sources = sources;
+ });
+ }
+ return sourceRooms;
+ }
+
+ /**
+ * Fetch the `IGNORE_INVITES_POLICIES` object from account data.
+ *
+ * If both an unstable prefix version and a stable prefix version are available,
+ * it will return the stable prefix version preferentially.
+ *
+ * The result is *not* validated but is guaranteed to be a non-null object.
+ *
+ * @returns A non-null object.
+ */
+ getIgnoreInvitesPolicies() {
+ return this.getPoliciesAndIgnoreInvitesPolicies().ignoreInvitesPolicies;
+ }
+
+ /**
+ * Modify in place the `IGNORE_INVITES_POLICIES` object from account data.
+ */
+ async withIgnoreInvitesPolicies(cb) {
+ const {
+ policies,
+ ignoreInvitesPolicies
+ } = this.getPoliciesAndIgnoreInvitesPolicies();
+ cb(ignoreInvitesPolicies);
+ policies[IGNORE_INVITES_ACCOUNT_EVENT_KEY.name] = ignoreInvitesPolicies;
+ await this.client.setAccountData(POLICIES_ACCOUNT_EVENT_TYPE.name, policies);
+ }
+
+ /**
+ * As `getIgnoreInvitesPolicies` but also return the `POLICIES_ACCOUNT_EVENT_TYPE`
+ * object.
+ */
+ getPoliciesAndIgnoreInvitesPolicies() {
+ let policies = {};
+ for (const key of [POLICIES_ACCOUNT_EVENT_TYPE.name, POLICIES_ACCOUNT_EVENT_TYPE.altName]) {
+ var _this$client$getAccou;
+ if (!key) {
+ continue;
+ }
+ const value = (_this$client$getAccou = this.client.getAccountData(key)) === null || _this$client$getAccou === void 0 ? void 0 : _this$client$getAccou.getContent();
+ if (value) {
+ policies = value;
+ break;
+ }
+ }
+ let ignoreInvitesPolicies = {};
+ let hasIgnoreInvitesPolicies = false;
+ for (const key of [IGNORE_INVITES_ACCOUNT_EVENT_KEY.name, IGNORE_INVITES_ACCOUNT_EVENT_KEY.altName]) {
+ if (!key) {
+ continue;
+ }
+ const value = policies[key];
+ if (value && typeof value == "object") {
+ ignoreInvitesPolicies = value;
+ hasIgnoreInvitesPolicies = true;
+ break;
+ }
+ }
+ if (!hasIgnoreInvitesPolicies) {
+ policies[IGNORE_INVITES_ACCOUNT_EVENT_KEY.name] = ignoreInvitesPolicies;
+ }
+ return {
+ policies,
+ ignoreInvitesPolicies
+ };
+ }
+}
+exports.IgnoredInvites = IgnoredInvites;
+//# sourceMappingURL=invites-ignorer.js.map \ No newline at end of file
diff --git a/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/invites-ignorer.js.map b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/invites-ignorer.js.map
new file mode 100644
index 0000000..4e6c8a3
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/invites-ignorer.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"invites-ignorer.js","names":["_matrixEventsSdk","require","_eventTimeline","_partials","_utils","POLICIES_ACCOUNT_EVENT_TYPE","UnstableValue","exports","IGNORE_INVITES_ACCOUNT_EVENT_KEY","PolicyRecommendation","PolicyScope","IgnoredInvites","constructor","client","addRule","scope","entity","reason","target","getOrCreateTargetRoom","response","sendStateEvent","roomId","recommendation","Ban","event_id","removeRule","event","redactEvent","getRoomId","getId","addSource","joinRoom","sources","getOrCreateSourceRooms","map","room","includes","push","withIgnoreInvitesPolicies","ignoreInvitesPolicies","getRuleForInvite","sender","policyRooms","senderServer","split","roomServer","state","getUnfilteredTimelineSet","getLiveTimeline","getState","EventTimeline","FORWARDS","entities","Room","User","Server","events","getStateEvents","content","getContent","glob","regexp","RegExp","globToRegexp","ex","test","getIgnoreInvitesPolicies","getRoom","createRoom","name","preset","Preset","PrivateChat","room_id","hasChanges","Array","isArray","sourceRooms","filter","length","getPoliciesAndIgnoreInvitesPolicies","cb","policies","setAccountData","key","altName","_this$client$getAccou","value","getAccountData","hasIgnoreInvitesPolicies"],"sources":["../../src/models/invites-ignorer.ts"],"sourcesContent":["/*\nCopyright 2022 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 { UnstableValue } from \"matrix-events-sdk\";\n\nimport { MatrixClient } from \"../client\";\nimport { IContent, MatrixEvent } from \"./event\";\nimport { EventTimeline } from \"./event-timeline\";\nimport { Preset } from \"../@types/partials\";\nimport { globToRegexp } from \"../utils\";\nimport { Room } from \"./room\";\n\n/// The event type storing the user's individual policies.\n///\n/// Exported for testing purposes.\nexport const POLICIES_ACCOUNT_EVENT_TYPE = new UnstableValue(\"m.policies\", \"org.matrix.msc3847.policies\");\n\n/// The key within the user's individual policies storing the user's ignored invites.\n///\n/// Exported for testing purposes.\nexport const IGNORE_INVITES_ACCOUNT_EVENT_KEY = new UnstableValue(\n \"m.ignore.invites\",\n \"org.matrix.msc3847.ignore.invites\",\n);\n\n/// The types of recommendations understood.\nenum PolicyRecommendation {\n Ban = \"m.ban\",\n}\n\n/**\n * The various scopes for policies.\n */\nexport enum PolicyScope {\n /**\n * The policy deals with an individual user, e.g. reject invites\n * from this user.\n */\n User = \"m.policy.user\",\n\n /**\n * The policy deals with a room, e.g. reject invites towards\n * a specific room.\n */\n Room = \"m.policy.room\",\n\n /**\n * The policy deals with a server, e.g. reject invites from\n * this server.\n */\n Server = \"m.policy.server\",\n}\n\n/**\n * A container for ignored invites.\n *\n * # Performance\n *\n * This implementation is extremely naive. It expects that we are dealing\n * with a very short list of sources (e.g. only one). If real-world\n * applications turn out to require longer lists, we may need to rework\n * our data structures.\n */\nexport class IgnoredInvites {\n public constructor(private readonly client: MatrixClient) {}\n\n /**\n * Add a new rule.\n *\n * @param scope - The scope for this rule.\n * @param entity - The entity covered by this rule. Globs are supported.\n * @param reason - A human-readable reason for introducing this new rule.\n * @returns The event id for the new rule.\n */\n public async addRule(scope: PolicyScope, entity: string, reason: string): Promise<string> {\n const target = await this.getOrCreateTargetRoom();\n const response = await this.client.sendStateEvent(target.roomId, scope, {\n entity,\n reason,\n recommendation: PolicyRecommendation.Ban,\n });\n return response.event_id;\n }\n\n /**\n * Remove a rule.\n */\n public async removeRule(event: MatrixEvent): Promise<void> {\n await this.client.redactEvent(event.getRoomId()!, event.getId()!);\n }\n\n /**\n * Add a new room to the list of sources. If the user isn't a member of the\n * room, attempt to join it.\n *\n * @param roomId - A valid room id. If this room is already in the list\n * of sources, it will not be duplicated.\n * @returns `true` if the source was added, `false` if it was already present.\n * @throws If `roomId` isn't the id of a room that the current user is already\n * member of or can join.\n *\n * # Safety\n *\n * This method will rewrite the `Policies` object in the user's account data.\n * This rewrite is inherently racy and could overwrite or be overwritten by\n * other concurrent rewrites of the same object.\n */\n public async addSource(roomId: string): Promise<boolean> {\n // We attempt to join the room *before* calling\n // `await this.getOrCreateSourceRooms()` to decrease the duration\n // of the racy section.\n await this.client.joinRoom(roomId);\n // Race starts.\n const sources = (await this.getOrCreateSourceRooms()).map((room) => room.roomId);\n if (sources.includes(roomId)) {\n return false;\n }\n sources.push(roomId);\n await this.withIgnoreInvitesPolicies((ignoreInvitesPolicies) => {\n ignoreInvitesPolicies.sources = sources;\n });\n\n // Race ends.\n return true;\n }\n\n /**\n * Find out whether an invite should be ignored.\n *\n * @param sender - The user id for the user who issued the invite.\n * @param roomId - The room to which the user is invited.\n * @returns A rule matching the entity, if any was found, `null` otherwise.\n */\n public async getRuleForInvite({\n sender,\n roomId,\n }: {\n sender: string;\n roomId: string;\n }): Promise<Readonly<MatrixEvent | null>> {\n // In this implementation, we perform a very naive lookup:\n // - search in each policy room;\n // - turn each (potentially glob) rule entity into a regexp.\n //\n // Real-world testing will tell us whether this is performant enough.\n // In the (unfortunately likely) case it isn't, there are several manners\n // in which we could optimize this:\n // - match several entities per go;\n // - pre-compile each rule entity into a regexp;\n // - pre-compile entire rooms into a single regexp.\n const policyRooms = await this.getOrCreateSourceRooms();\n const senderServer = sender.split(\":\")[1];\n const roomServer = roomId.split(\":\")[1];\n for (const room of policyRooms) {\n const state = room.getUnfilteredTimelineSet().getLiveTimeline().getState(EventTimeline.FORWARDS)!;\n\n for (const { scope, entities } of [\n { scope: PolicyScope.Room, entities: [roomId] },\n { scope: PolicyScope.User, entities: [sender] },\n { scope: PolicyScope.Server, entities: [senderServer, roomServer] },\n ]) {\n const events = state.getStateEvents(scope);\n for (const event of events) {\n const content = event.getContent();\n if (content?.recommendation != PolicyRecommendation.Ban) {\n // Ignoring invites only looks at `m.ban` recommendations.\n continue;\n }\n const glob = content?.entity;\n if (!glob) {\n // Invalid event.\n continue;\n }\n let regexp: RegExp;\n try {\n regexp = new RegExp(globToRegexp(glob, false));\n } catch (ex) {\n // Assume invalid event.\n continue;\n }\n for (const entity of entities) {\n if (entity && regexp.test(entity)) {\n return event;\n }\n }\n // No match.\n }\n }\n }\n return null;\n }\n\n /**\n * Get the target room, i.e. the room in which any new rule should be written.\n *\n * If there is no target room setup, a target room is created.\n *\n * Note: This method is public for testing reasons. Most clients should not need\n * to call it directly.\n *\n * # Safety\n *\n * This method will rewrite the `Policies` object in the user's account data.\n * This rewrite is inherently racy and could overwrite or be overwritten by\n * other concurrent rewrites of the same object.\n */\n public async getOrCreateTargetRoom(): Promise<Room> {\n const ignoreInvitesPolicies = this.getIgnoreInvitesPolicies();\n let target = ignoreInvitesPolicies.target;\n // Validate `target`. If it is invalid, trash out the current `target`\n // and create a new room.\n if (typeof target !== \"string\") {\n target = null;\n }\n if (target) {\n // Check that the room exists and is valid.\n const room = this.client.getRoom(target);\n if (room) {\n return room;\n } else {\n target = null;\n }\n }\n // We need to create our own policy room for ignoring invites.\n target = (\n await this.client.createRoom({\n name: \"Individual Policy Room\",\n preset: Preset.PrivateChat,\n })\n ).room_id;\n await this.withIgnoreInvitesPolicies((ignoreInvitesPolicies) => {\n ignoreInvitesPolicies.target = target;\n });\n\n // Since we have just called `createRoom`, `getRoom` should not be `null`.\n return this.client.getRoom(target)!;\n }\n\n /**\n * Get the list of source rooms, i.e. the rooms from which rules need to be read.\n *\n * If no source rooms are setup, the target room is used as sole source room.\n *\n * Note: This method is public for testing reasons. Most clients should not need\n * to call it directly.\n *\n * # Safety\n *\n * This method will rewrite the `Policies` object in the user's account data.\n * This rewrite is inherently racy and could overwrite or be overwritten by\n * other concurrent rewrites of the same object.\n */\n public async getOrCreateSourceRooms(): Promise<Room[]> {\n const ignoreInvitesPolicies = this.getIgnoreInvitesPolicies();\n let sources: string[] = ignoreInvitesPolicies.sources;\n\n // Validate `sources`. If it is invalid, trash out the current `sources`\n // and create a new list of sources from `target`.\n let hasChanges = false;\n if (!Array.isArray(sources)) {\n // `sources` could not be an array.\n hasChanges = true;\n sources = [];\n }\n let sourceRooms = sources\n // `sources` could contain non-string / invalid room ids\n .filter((roomId) => typeof roomId === \"string\")\n .map((roomId) => this.client.getRoom(roomId))\n .filter((room) => !!room) as Room[];\n if (sourceRooms.length != sources.length) {\n hasChanges = true;\n }\n if (sourceRooms.length == 0) {\n // `sources` could be empty (possibly because we've removed\n // invalid content)\n const target = await this.getOrCreateTargetRoom();\n hasChanges = true;\n sourceRooms = [target];\n }\n if (hasChanges) {\n // Reload `policies`/`ignoreInvitesPolicies` in case it has been changed\n // during or by our call to `this.getTargetRoom()`.\n await this.withIgnoreInvitesPolicies((ignoreInvitesPolicies) => {\n ignoreInvitesPolicies.sources = sources;\n });\n }\n return sourceRooms;\n }\n\n /**\n * Fetch the `IGNORE_INVITES_POLICIES` object from account data.\n *\n * If both an unstable prefix version and a stable prefix version are available,\n * it will return the stable prefix version preferentially.\n *\n * The result is *not* validated but is guaranteed to be a non-null object.\n *\n * @returns A non-null object.\n */\n private getIgnoreInvitesPolicies(): { [key: string]: any } {\n return this.getPoliciesAndIgnoreInvitesPolicies().ignoreInvitesPolicies;\n }\n\n /**\n * Modify in place the `IGNORE_INVITES_POLICIES` object from account data.\n */\n private async withIgnoreInvitesPolicies(\n cb: (ignoreInvitesPolicies: { [key: string]: any }) => void,\n ): Promise<void> {\n const { policies, ignoreInvitesPolicies } = this.getPoliciesAndIgnoreInvitesPolicies();\n cb(ignoreInvitesPolicies);\n policies[IGNORE_INVITES_ACCOUNT_EVENT_KEY.name] = ignoreInvitesPolicies;\n await this.client.setAccountData(POLICIES_ACCOUNT_EVENT_TYPE.name, policies);\n }\n\n /**\n * As `getIgnoreInvitesPolicies` but also return the `POLICIES_ACCOUNT_EVENT_TYPE`\n * object.\n */\n private getPoliciesAndIgnoreInvitesPolicies(): {\n policies: { [key: string]: any };\n ignoreInvitesPolicies: { [key: string]: any };\n } {\n let policies: IContent = {};\n for (const key of [POLICIES_ACCOUNT_EVENT_TYPE.name, POLICIES_ACCOUNT_EVENT_TYPE.altName]) {\n if (!key) {\n continue;\n }\n const value = this.client.getAccountData(key)?.getContent();\n if (value) {\n policies = value;\n break;\n }\n }\n\n let ignoreInvitesPolicies = {};\n let hasIgnoreInvitesPolicies = false;\n for (const key of [IGNORE_INVITES_ACCOUNT_EVENT_KEY.name, IGNORE_INVITES_ACCOUNT_EVENT_KEY.altName]) {\n if (!key) {\n continue;\n }\n const value = policies[key];\n if (value && typeof value == \"object\") {\n ignoreInvitesPolicies = value;\n hasIgnoreInvitesPolicies = true;\n break;\n }\n }\n if (!hasIgnoreInvitesPolicies) {\n policies[IGNORE_INVITES_ACCOUNT_EVENT_KEY.name] = ignoreInvitesPolicies;\n }\n\n return { policies, ignoreInvitesPolicies };\n }\n}\n"],"mappings":"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"} \ No newline at end of file
diff --git a/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/poll.d.ts b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/poll.d.ts
new file mode 100644
index 0000000..50e1729
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/poll.d.ts
@@ -0,0 +1,60 @@
+import { MatrixClient } from "../client";
+import { PollStartEvent } from "../extensible_events_v1/PollStartEvent";
+import { MatrixEvent } from "./event";
+import { Relations } from "./relations";
+import { Room } from "./room";
+import { TypedEventEmitter } from "./typed-event-emitter";
+export declare enum PollEvent {
+ New = "Poll.new",
+ End = "Poll.end",
+ Update = "Poll.update",
+ Responses = "Poll.Responses",
+ Destroy = "Poll.Destroy",
+ UndecryptableRelations = "Poll.UndecryptableRelations"
+}
+export type PollEventHandlerMap = {
+ [PollEvent.Update]: (event: MatrixEvent, poll: Poll) => void;
+ [PollEvent.Destroy]: (pollIdentifier: string) => void;
+ [PollEvent.End]: () => void;
+ [PollEvent.Responses]: (responses: Relations) => void;
+ [PollEvent.UndecryptableRelations]: (count: number) => void;
+};
+export declare class Poll extends TypedEventEmitter<Exclude<PollEvent, PollEvent.New>, PollEventHandlerMap> {
+ readonly rootEvent: MatrixEvent;
+ private matrixClient;
+ private room;
+ readonly roomId: string;
+ readonly pollEvent: PollStartEvent;
+ private _isFetchingResponses;
+ private relationsNextBatch;
+ private responses;
+ private endEvent;
+ /**
+ * Keep track of undecryptable relations
+ * As incomplete result sets affect poll results
+ */
+ private undecryptableRelationEventIds;
+ constructor(rootEvent: MatrixEvent, matrixClient: MatrixClient, room: Room);
+ get pollId(): string;
+ get endEventId(): string | undefined;
+ get isEnded(): boolean;
+ get isFetchingResponses(): boolean;
+ get undecryptableRelationsCount(): number;
+ getResponses(): Promise<Relations>;
+ /**
+ *
+ * @param event - event with a relation to the rootEvent
+ * @returns void
+ */
+ onNewRelation(event: MatrixEvent): void;
+ private fetchResponses;
+ /**
+ * Only responses made before the poll ended are valid
+ * Refilter after an end event is recieved
+ * To ensure responses are valid
+ */
+ private refilterResponsesOnEnd;
+ private countUndecryptableEvents;
+ private validateEndEvent;
+}
+//# sourceMappingURL=poll.d.ts.map \ No newline at end of file
diff --git a/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/poll.d.ts.map b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/poll.d.ts.map
new file mode 100644
index 0000000..568e552
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/poll.d.ts.map
@@ -0,0 +1 @@
+{"version":3,"file":"poll.d.ts","sourceRoot":"","sources":["../../src/models/poll.ts"],"names":[],"mappings":"AAiBA,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,EAAE,cAAc,EAAE,MAAM,wCAAwC,CAAC;AACxE,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AACtC,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAC9B,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAE1D,oBAAY,SAAS;IACjB,GAAG,aAAa;IAChB,GAAG,aAAa;IAChB,MAAM,gBAAgB;IACtB,SAAS,mBAAmB;IAC5B,OAAO,iBAAiB;IACxB,sBAAsB,gCAAgC;CACzD;AAED,MAAM,MAAM,mBAAmB,GAAG;IAC9B,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;IAC7D,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC,cAAc,EAAE,MAAM,KAAK,IAAI,CAAC;IACtD,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,MAAM,IAAI,CAAC;IAC5B,CAAC,SAAS,CAAC,SAAS,CAAC,EAAE,CAAC,SAAS,EAAE,SAAS,KAAK,IAAI,CAAC;IACtD,CAAC,SAAS,CAAC,sBAAsB,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CAC/D,CAAC;AAuBF,qBAAa,IAAK,SAAQ,iBAAiB,CAAC,OAAO,CAAC,SAAS,EAAE,SAAS,CAAC,GAAG,CAAC,EAAE,mBAAmB,CAAC;aAa5D,SAAS,EAAE,WAAW;IAAE,OAAO,CAAC,YAAY;IAAgB,OAAO,CAAC,IAAI;IAZ3G,SAAgB,MAAM,EAAE,MAAM,CAAC;IAC/B,SAAgB,SAAS,EAAE,cAAc,CAAC;IAC1C,OAAO,CAAC,oBAAoB,CAAS;IACrC,OAAO,CAAC,kBAAkB,CAAqB;IAC/C,OAAO,CAAC,SAAS,CAA0B;IAC3C,OAAO,CAAC,QAAQ,CAA0B;IAC1C;;;OAGG;IACH,OAAO,CAAC,6BAA6B,CAAqB;gBAEvB,SAAS,EAAE,WAAW,EAAU,YAAY,EAAE,YAAY,EAAU,IAAI,EAAE,IAAI;IASjH,IAAW,MAAM,IAAI,MAAM,CAE1B;IAED,IAAW,UAAU,IAAI,MAAM,GAAG,SAAS,CAE1C;IAED,IAAW,OAAO,IAAI,OAAO,CAE5B;IAED,IAAW,mBAAmB,IAAI,OAAO,CAExC;IAED,IAAW,2BAA2B,IAAI,MAAM,CAE/C;IAEY,YAAY,IAAI,OAAO,CAAC,SAAS,CAAC;IAgB/C;;;;OAIG;IACI,aAAa,CAAC,KAAK,EAAE,WAAW,GAAG,IAAI;YA0BhC,cAAc;IA0D5B;;;;OAIG;IACH,OAAO,CAAC,sBAAsB;IAe9B,OAAO,CAAC,wBAAwB,CAW9B;IAEF,OAAO,CAAC,gBAAgB;CAyB3B"} \ No newline at end of file
diff --git a/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/poll.js b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/poll.js
new file mode 100644
index 0000000..755119e
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/poll.js
@@ -0,0 +1,231 @@
+"use strict";
+
+var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.PollEvent = exports.Poll = void 0;
+var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
+var _polls = require("../@types/polls");
+var _relations = require("./relations");
+var _typedEventEmitter = require("./typed-event-emitter");
+/*
+Copyright 2023 The Matrix.org Foundation C.I.C.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+let PollEvent;
+exports.PollEvent = PollEvent;
+(function (PollEvent) {
+ PollEvent["New"] = "Poll.new";
+ PollEvent["End"] = "Poll.end";
+ PollEvent["Update"] = "Poll.update";
+ PollEvent["Responses"] = "Poll.Responses";
+ PollEvent["Destroy"] = "Poll.Destroy";
+ PollEvent["UndecryptableRelations"] = "Poll.UndecryptableRelations";
+})(PollEvent || (exports.PollEvent = PollEvent = {}));
+const filterResponseRelations = (relationEvents, pollEndTimestamp) => {
+ const responseEvents = relationEvents.filter(event => {
+ if (event.isDecryptionFailure()) {
+ return;
+ }
+ return _polls.M_POLL_RESPONSE.matches(event.getType()) &&
+ // From MSC3381:
+ // "Votes sent on or before the end event's timestamp are valid votes"
+ event.getTs() <= pollEndTimestamp;
+ });
+ return {
+ responseEvents
+ };
+};
+class Poll extends _typedEventEmitter.TypedEventEmitter {
+ /**
+ * Keep track of undecryptable relations
+ * As incomplete result sets affect poll results
+ */
+
+ constructor(rootEvent, matrixClient, room) {
+ super();
+ this.rootEvent = rootEvent;
+ this.matrixClient = matrixClient;
+ this.room = room;
+ (0, _defineProperty2.default)(this, "roomId", void 0);
+ (0, _defineProperty2.default)(this, "pollEvent", void 0);
+ (0, _defineProperty2.default)(this, "_isFetchingResponses", false);
+ (0, _defineProperty2.default)(this, "relationsNextBatch", void 0);
+ (0, _defineProperty2.default)(this, "responses", null);
+ (0, _defineProperty2.default)(this, "endEvent", void 0);
+ (0, _defineProperty2.default)(this, "undecryptableRelationEventIds", new Set());
+ (0, _defineProperty2.default)(this, "countUndecryptableEvents", events => {
+ const undecryptableEventIds = events.filter(event => event.isDecryptionFailure()).map(event => event.getId());
+ const previousCount = this.undecryptableRelationsCount;
+ this.undecryptableRelationEventIds = new Set([...this.undecryptableRelationEventIds, ...undecryptableEventIds]);
+ if (this.undecryptableRelationsCount !== previousCount) {
+ this.emit(PollEvent.UndecryptableRelations, this.undecryptableRelationsCount);
+ }
+ });
+ if (!this.rootEvent.getRoomId() || !this.rootEvent.getId()) {
+ throw new Error("Invalid poll start event.");
+ }
+ this.roomId = this.rootEvent.getRoomId();
+ this.pollEvent = this.rootEvent.unstableExtensibleEvent;
+ }
+ get pollId() {
+ return this.rootEvent.getId();
+ }
+ get endEventId() {
+ var _this$endEvent;
+ return (_this$endEvent = this.endEvent) === null || _this$endEvent === void 0 ? void 0 : _this$endEvent.getId();
+ }
+ get isEnded() {
+ return !!this.endEvent;
+ }
+ get isFetchingResponses() {
+ return this._isFetchingResponses;
+ }
+ get undecryptableRelationsCount() {
+ return this.undecryptableRelationEventIds.size;
+ }
+ async getResponses() {
+ // if we have already fetched some responses
+ // just return them
+ if (this.responses) {
+ return this.responses;
+ }
+
+ // if there is no fetching in progress
+ // start fetching
+ if (!this.isFetchingResponses) {
+ await this.fetchResponses();
+ }
+ // return whatever responses we got from the first page
+ return this.responses;
+ }
+
+ /**
+ *
+ * @param event - event with a relation to the rootEvent
+ * @returns void
+ */
+ onNewRelation(event) {
+ var _this$endEvent2;
+ if (_polls.M_POLL_END.matches(event.getType()) && this.validateEndEvent(event)) {
+ this.endEvent = event;
+ this.refilterResponsesOnEnd();
+ this.emit(PollEvent.End);
+ }
+
+ // wait for poll responses to be initialised
+ if (!this.responses) {
+ return;
+ }
+ const pollEndTimestamp = ((_this$endEvent2 = this.endEvent) === null || _this$endEvent2 === void 0 ? void 0 : _this$endEvent2.getTs()) || Number.MAX_SAFE_INTEGER;
+ const {
+ responseEvents
+ } = filterResponseRelations([event], pollEndTimestamp);
+ this.countUndecryptableEvents([event]);
+ if (responseEvents.length) {
+ responseEvents.forEach(event => {
+ this.responses.addEvent(event);
+ });
+ this.emit(PollEvent.Responses, this.responses);
+ }
+ }
+ async fetchResponses() {
+ var _this$endEvent3, _allRelations$nextBat;
+ this._isFetchingResponses = true;
+
+ // we want:
+ // - stable and unstable M_POLL_RESPONSE
+ // - stable and unstable M_POLL_END
+ // so make one api call and filter by event type client side
+ const allRelations = await this.matrixClient.relations(this.roomId, this.rootEvent.getId(), "m.reference", undefined, {
+ from: this.relationsNextBatch || undefined
+ });
+ await Promise.all(allRelations.events.map(event => this.matrixClient.decryptEventIfNeeded(event)));
+ const responses = this.responses || new _relations.Relations("m.reference", _polls.M_POLL_RESPONSE.name, this.matrixClient, [_polls.M_POLL_RESPONSE.altName]);
+ const pollEndEvent = allRelations.events.find(event => _polls.M_POLL_END.matches(event.getType()));
+ if (this.validateEndEvent(pollEndEvent)) {
+ this.endEvent = pollEndEvent;
+ this.refilterResponsesOnEnd();
+ this.emit(PollEvent.End);
+ }
+ const pollCloseTimestamp = ((_this$endEvent3 = this.endEvent) === null || _this$endEvent3 === void 0 ? void 0 : _this$endEvent3.getTs()) || Number.MAX_SAFE_INTEGER;
+ const {
+ responseEvents
+ } = filterResponseRelations(allRelations.events, pollCloseTimestamp);
+ responseEvents.forEach(event => {
+ responses.addEvent(event);
+ });
+ this.relationsNextBatch = (_allRelations$nextBat = allRelations.nextBatch) !== null && _allRelations$nextBat !== void 0 ? _allRelations$nextBat : undefined;
+ this.responses = responses;
+ this.countUndecryptableEvents(allRelations.events);
+
+ // while there are more pages of relations
+ // fetch them
+ if (this.relationsNextBatch) {
+ // don't await
+ // we want to return the first page as soon as possible
+ this.fetchResponses();
+ } else {
+ // no more pages
+ this._isFetchingResponses = false;
+ }
+
+ // emit after updating _isFetchingResponses state
+ this.emit(PollEvent.Responses, this.responses);
+ }
+
+ /**
+ * Only responses made before the poll ended are valid
+ * Refilter after an end event is recieved
+ * To ensure responses are valid
+ */
+ refilterResponsesOnEnd() {
+ var _this$endEvent4;
+ if (!this.responses) {
+ return;
+ }
+ const pollEndTimestamp = ((_this$endEvent4 = this.endEvent) === null || _this$endEvent4 === void 0 ? void 0 : _this$endEvent4.getTs()) || Number.MAX_SAFE_INTEGER;
+ this.responses.getRelations().forEach(event => {
+ if (event.getTs() > pollEndTimestamp) {
+ var _this$responses;
+ (_this$responses = this.responses) === null || _this$responses === void 0 ? void 0 : _this$responses.removeEvent(event);
+ }
+ });
+ this.emit(PollEvent.Responses, this.responses);
+ }
+ validateEndEvent(endEvent) {
+ if (!endEvent) {
+ return false;
+ }
+ /**
+ * Repeated end events are ignored -
+ * only the first (valid) closure event by origin_server_ts is counted.
+ */
+ if (this.endEvent && this.endEvent.getTs() < endEvent.getTs()) {
+ return false;
+ }
+
+ /**
+ * MSC3381
+ * If a m.poll.end event is received from someone other than the poll creator or user with permission to redact
+ * others' messages in the room, the event must be ignored by clients due to being invalid.
+ */
+ const roomCurrentState = this.room.currentState;
+ const endEventSender = endEvent.getSender();
+ return !!endEventSender && (endEventSender === this.rootEvent.getSender() || roomCurrentState.maySendRedactionForEvent(this.rootEvent, endEventSender));
+ }
+}
+exports.Poll = Poll;
+//# sourceMappingURL=poll.js.map \ No newline at end of file
diff --git a/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/poll.js.map b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/poll.js.map
new file mode 100644
index 0000000..36b4b37
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/poll.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"poll.js","names":["_polls","require","_relations","_typedEventEmitter","PollEvent","exports","filterResponseRelations","relationEvents","pollEndTimestamp","responseEvents","filter","event","isDecryptionFailure","M_POLL_RESPONSE","matches","getType","getTs","Poll","TypedEventEmitter","constructor","rootEvent","matrixClient","room","_defineProperty2","default","Set","events","undecryptableEventIds","map","getId","previousCount","undecryptableRelationsCount","undecryptableRelationEventIds","emit","UndecryptableRelations","getRoomId","Error","roomId","pollEvent","unstableExtensibleEvent","pollId","endEventId","_this$endEvent","endEvent","isEnded","isFetchingResponses","_isFetchingResponses","size","getResponses","responses","fetchResponses","onNewRelation","_this$endEvent2","M_POLL_END","validateEndEvent","refilterResponsesOnEnd","End","Number","MAX_SAFE_INTEGER","countUndecryptableEvents","length","forEach","addEvent","Responses","_this$endEvent3","_allRelations$nextBat","allRelations","relations","undefined","from","relationsNextBatch","Promise","all","decryptEventIfNeeded","Relations","name","altName","pollEndEvent","find","pollCloseTimestamp","nextBatch","_this$endEvent4","getRelations","_this$responses","removeEvent","roomCurrentState","currentState","endEventSender","getSender","maySendRedactionForEvent"],"sources":["../../src/models/poll.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 { M_POLL_END, M_POLL_RESPONSE } from \"../@types/polls\";\nimport { MatrixClient } from \"../client\";\nimport { PollStartEvent } from \"../extensible_events_v1/PollStartEvent\";\nimport { MatrixEvent } from \"./event\";\nimport { Relations } from \"./relations\";\nimport { Room } from \"./room\";\nimport { TypedEventEmitter } from \"./typed-event-emitter\";\n\nexport enum PollEvent {\n New = \"Poll.new\",\n End = \"Poll.end\",\n Update = \"Poll.update\",\n Responses = \"Poll.Responses\",\n Destroy = \"Poll.Destroy\",\n UndecryptableRelations = \"Poll.UndecryptableRelations\",\n}\n\nexport type PollEventHandlerMap = {\n [PollEvent.Update]: (event: MatrixEvent, poll: Poll) => void;\n [PollEvent.Destroy]: (pollIdentifier: string) => void;\n [PollEvent.End]: () => void;\n [PollEvent.Responses]: (responses: Relations) => void;\n [PollEvent.UndecryptableRelations]: (count: number) => void;\n};\n\nconst filterResponseRelations = (\n relationEvents: MatrixEvent[],\n pollEndTimestamp: number,\n): {\n responseEvents: MatrixEvent[];\n} => {\n const responseEvents = relationEvents.filter((event) => {\n if (event.isDecryptionFailure()) {\n return;\n }\n return (\n M_POLL_RESPONSE.matches(event.getType()) &&\n // From MSC3381:\n // \"Votes sent on or before the end event's timestamp are valid votes\"\n event.getTs() <= pollEndTimestamp\n );\n });\n\n return { responseEvents };\n};\n\nexport class Poll extends TypedEventEmitter<Exclude<PollEvent, PollEvent.New>, PollEventHandlerMap> {\n public readonly roomId: string;\n public readonly pollEvent: PollStartEvent;\n private _isFetchingResponses = false;\n private relationsNextBatch: string | undefined;\n private responses: null | Relations = null;\n private endEvent: MatrixEvent | undefined;\n /**\n * Keep track of undecryptable relations\n * As incomplete result sets affect poll results\n */\n private undecryptableRelationEventIds = new Set<string>();\n\n public constructor(public readonly rootEvent: MatrixEvent, private matrixClient: MatrixClient, private room: Room) {\n super();\n if (!this.rootEvent.getRoomId() || !this.rootEvent.getId()) {\n throw new Error(\"Invalid poll start event.\");\n }\n this.roomId = this.rootEvent.getRoomId()!;\n this.pollEvent = this.rootEvent.unstableExtensibleEvent as unknown as PollStartEvent;\n }\n\n public get pollId(): string {\n return this.rootEvent.getId()!;\n }\n\n public get endEventId(): string | undefined {\n return this.endEvent?.getId();\n }\n\n public get isEnded(): boolean {\n return !!this.endEvent;\n }\n\n public get isFetchingResponses(): boolean {\n return this._isFetchingResponses;\n }\n\n public get undecryptableRelationsCount(): number {\n return this.undecryptableRelationEventIds.size;\n }\n\n public async getResponses(): Promise<Relations> {\n // if we have already fetched some responses\n // just return them\n if (this.responses) {\n return this.responses;\n }\n\n // if there is no fetching in progress\n // start fetching\n if (!this.isFetchingResponses) {\n await this.fetchResponses();\n }\n // return whatever responses we got from the first page\n return this.responses!;\n }\n\n /**\n *\n * @param event - event with a relation to the rootEvent\n * @returns void\n */\n public onNewRelation(event: MatrixEvent): void {\n if (M_POLL_END.matches(event.getType()) && this.validateEndEvent(event)) {\n this.endEvent = event;\n this.refilterResponsesOnEnd();\n this.emit(PollEvent.End);\n }\n\n // wait for poll responses to be initialised\n if (!this.responses) {\n return;\n }\n\n const pollEndTimestamp = this.endEvent?.getTs() || Number.MAX_SAFE_INTEGER;\n const { responseEvents } = filterResponseRelations([event], pollEndTimestamp);\n\n this.countUndecryptableEvents([event]);\n\n if (responseEvents.length) {\n responseEvents.forEach((event) => {\n this.responses!.addEvent(event);\n });\n\n this.emit(PollEvent.Responses, this.responses);\n }\n }\n\n private async fetchResponses(): Promise<void> {\n this._isFetchingResponses = true;\n\n // we want:\n // - stable and unstable M_POLL_RESPONSE\n // - stable and unstable M_POLL_END\n // so make one api call and filter by event type client side\n const allRelations = await this.matrixClient.relations(\n this.roomId,\n this.rootEvent.getId()!,\n \"m.reference\",\n undefined,\n {\n from: this.relationsNextBatch || undefined,\n },\n );\n\n await Promise.all(allRelations.events.map((event) => this.matrixClient.decryptEventIfNeeded(event)));\n\n const responses =\n this.responses ||\n new Relations(\"m.reference\", M_POLL_RESPONSE.name, this.matrixClient, [M_POLL_RESPONSE.altName!]);\n\n const pollEndEvent = allRelations.events.find((event) => M_POLL_END.matches(event.getType()));\n\n if (this.validateEndEvent(pollEndEvent)) {\n this.endEvent = pollEndEvent;\n this.refilterResponsesOnEnd();\n this.emit(PollEvent.End);\n }\n\n const pollCloseTimestamp = this.endEvent?.getTs() || Number.MAX_SAFE_INTEGER;\n\n const { responseEvents } = filterResponseRelations(allRelations.events, pollCloseTimestamp);\n\n responseEvents.forEach((event) => {\n responses.addEvent(event);\n });\n\n this.relationsNextBatch = allRelations.nextBatch ?? undefined;\n this.responses = responses;\n this.countUndecryptableEvents(allRelations.events);\n\n // while there are more pages of relations\n // fetch them\n if (this.relationsNextBatch) {\n // don't await\n // we want to return the first page as soon as possible\n this.fetchResponses();\n } else {\n // no more pages\n this._isFetchingResponses = false;\n }\n\n // emit after updating _isFetchingResponses state\n this.emit(PollEvent.Responses, this.responses);\n }\n\n /**\n * Only responses made before the poll ended are valid\n * Refilter after an end event is recieved\n * To ensure responses are valid\n */\n private refilterResponsesOnEnd(): void {\n if (!this.responses) {\n return;\n }\n\n const pollEndTimestamp = this.endEvent?.getTs() || Number.MAX_SAFE_INTEGER;\n this.responses.getRelations().forEach((event) => {\n if (event.getTs() > pollEndTimestamp) {\n this.responses?.removeEvent(event);\n }\n });\n\n this.emit(PollEvent.Responses, this.responses);\n }\n\n private countUndecryptableEvents = (events: MatrixEvent[]): void => {\n const undecryptableEventIds = events\n .filter((event) => event.isDecryptionFailure())\n .map((event) => event.getId()!);\n\n const previousCount = this.undecryptableRelationsCount;\n this.undecryptableRelationEventIds = new Set([...this.undecryptableRelationEventIds, ...undecryptableEventIds]);\n\n if (this.undecryptableRelationsCount !== previousCount) {\n this.emit(PollEvent.UndecryptableRelations, this.undecryptableRelationsCount);\n }\n };\n\n private validateEndEvent(endEvent?: MatrixEvent): boolean {\n if (!endEvent) {\n return false;\n }\n /**\n * Repeated end events are ignored -\n * only the first (valid) closure event by origin_server_ts is counted.\n */\n if (this.endEvent && this.endEvent.getTs() < endEvent.getTs()) {\n return false;\n }\n\n /**\n * MSC3381\n * If a m.poll.end event is received from someone other than the poll creator or user with permission to redact\n * others' messages in the room, the event must be ignored by clients due to being invalid.\n */\n const roomCurrentState = this.room.currentState;\n const endEventSender = endEvent.getSender();\n return (\n !!endEventSender &&\n (endEventSender === this.rootEvent.getSender() ||\n roomCurrentState.maySendRedactionForEvent(this.rootEvent, endEventSender))\n );\n }\n}\n"],"mappings":"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"} \ No newline at end of file
diff --git a/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/read-receipt.d.ts b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/read-receipt.d.ts
new file mode 100644
index 0000000..1c228c2
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/read-receipt.d.ts
@@ -0,0 +1,76 @@
+import { CachedReceipt, Receipt, ReceiptType, WrappedReceipt } from "../@types/read_receipts";
+import { ListenerMap, TypedEventEmitter } from "./typed-event-emitter";
+import { MatrixEvent } from "./event";
+import { EventTimelineSet } from "./event-timeline-set";
+import { NotificationCountType } from "./room";
+export declare function synthesizeReceipt(userId: string, event: MatrixEvent, receiptType: ReceiptType): MatrixEvent;
+export declare abstract class ReadReceipt<Events extends string, Arguments extends ListenerMap<Events>, SuperclassArguments extends ListenerMap<any> = Arguments> extends TypedEventEmitter<Events, Arguments, SuperclassArguments> {
+ private receipts;
+ private receiptCacheByEventId;
+ abstract getUnfilteredTimelineSet(): EventTimelineSet;
+ abstract timeline: MatrixEvent[];
+ /**
+ * Gets the latest receipt for a given user in the room
+ * @param userId - The id of the user for which we want the receipt
+ * @param ignoreSynthesized - Whether to ignore synthesized receipts or not
+ * @param receiptType - Optional. The type of the receipt we want to get
+ * @returns the latest receipts of the chosen type for the chosen user
+ */
+ getReadReceiptForUserId(userId: string, ignoreSynthesized?: boolean, receiptType?: ReceiptType): WrappedReceipt | null;
+ /**
+ * Get the ID of the event that a given user has read up to, or null if we
+ * have received no read receipts from them.
+ * @param userId - The user ID to get read receipt event ID for
+ * @param ignoreSynthesized - If true, return only receipts that have been
+ * sent by the server, not implicit ones generated
+ * by the JS SDK.
+ * @returns ID of the latest event that the given user has read, or null.
+ */
+ getEventReadUpTo(userId: string, ignoreSynthesized?: boolean): string | null;
+ addReceiptToStructure(eventId: string, receiptType: ReceiptType, userId: string, receipt: Receipt, synthetic: boolean): void;
+ /**
+ * Get a list of receipts for the given event.
+ * @param event - the event to get receipts for
+ * @returns A list of receipts with a userId, type and data keys or
+ * an empty list.
+ */
+ getReceiptsForEvent(event: MatrixEvent): CachedReceipt[];
+ abstract addReceipt(event: MatrixEvent, synthetic: boolean): void;
+ abstract setUnread(type: NotificationCountType, count: number): void;
+ /**
+ * This issue should also be addressed on synapse's side and is tracked as part
+ * of https://github.com/matrix-org/synapse/issues/14837
+ *
+ * Retrieves the read receipt for the logged in user and checks if it matches
+ * the last event in the room and whether that event originated from the logged
+ * in user.
+ * Under those conditions we can consider the context as read. This is useful
+ * because we never send read receipts against our own events
+ * @param userId - the logged in user
+ */
+ fixupNotifications(userId: string): void;
+ /**
+ * Add a temporary local-echo receipt to the room to reflect in the
+ * client the fact that we've sent one.
+ * @param userId - The user ID if the receipt sender
+ * @param e - The event that is to be acknowledged
+ * @param receiptType - The type of receipt
+ */
+ addLocalEchoReceipt(userId: string, e: MatrixEvent, receiptType: ReceiptType): void;
+ /**
+ * Get a list of user IDs who have <b>read up to</b> the given event.
+ * @param event - the event to get read receipts for.
+ * @returns A list of user IDs.
+ */
+ getUsersReadUpTo(event: MatrixEvent): string[];
+ /**
+ * Determines if the given user has read a particular event ID with the known
+ * history of the room. This is not a definitive check as it relies only on
+ * what is available to the room at the time of execution.
+ * @param userId - The user ID to check the read state of.
+ * @param eventId - The event ID to check if the user read.
+ * @returns True if the user has read the event, false otherwise.
+ */
+ hasUserReadEvent(userId: string, eventId: string): boolean;
+}
+//# sourceMappingURL=read-receipt.d.ts.map \ No newline at end of file
diff --git a/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/read-receipt.d.ts.map b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/read-receipt.d.ts.map
new file mode 100644
index 0000000..2b5306c
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/read-receipt.d.ts.map
@@ -0,0 +1 @@
+{"version":3,"file":"read-receipt.d.ts","sourceRoot":"","sources":["../../src/models/read-receipt.ts"],"names":[],"mappings":"AAaA,OAAO,EACH,aAAa,EAEb,OAAO,EAEP,WAAW,EACX,cAAc,EACjB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAEvE,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAEtC,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAExD,OAAO,EAAE,qBAAqB,EAAE,MAAM,QAAQ,CAAC;AAE/C,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,WAAW,GAAG,WAAW,CAe3G;AAKD,8BAAsB,WAAW,CAC7B,MAAM,SAAS,MAAM,EACrB,SAAS,SAAS,WAAW,CAAC,MAAM,CAAC,EACrC,mBAAmB,SAAS,WAAW,CAAC,GAAG,CAAC,GAAG,SAAS,CAC1D,SAAQ,iBAAiB,CAAC,MAAM,EAAE,SAAS,EAAE,mBAAmB,CAAC;IAM/D,OAAO,CAAC,QAAQ,CAEd;IACF,OAAO,CAAC,qBAAqB,CAA2B;aAExC,wBAAwB,IAAI,gBAAgB;IAC5D,SAAgB,QAAQ,EAAE,WAAW,EAAE,CAAC;IAExC;;;;;;OAMG;IACI,uBAAuB,CAC1B,MAAM,EAAE,MAAM,EACd,iBAAiB,UAAQ,EACzB,WAAW,cAAmB,GAC/B,cAAc,GAAG,IAAI;IASxB;;;;;;;;OAQG;IACI,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,iBAAiB,UAAQ,GAAG,MAAM,GAAG,IAAI;IA4B1E,qBAAqB,CACxB,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,WAAW,EACxB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,OAAO,EAChB,SAAS,EAAE,OAAO,GACnB,IAAI;IAqFP;;;;;OAKG;IACI,mBAAmB,CAAC,KAAK,EAAE,WAAW,GAAG,aAAa,EAAE;aAI/C,UAAU,CAAC,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,OAAO,GAAG,IAAI;aAExD,SAAS,CAAC,IAAI,EAAE,qBAAqB,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAE3E;;;;;;;;;;OAUG;IACI,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAU/C;;;;;;OAMG;IACI,mBAAmB,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,EAAE,WAAW,EAAE,WAAW,EAAE,WAAW,GAAG,IAAI;IAI1F;;;;OAIG;IACI,gBAAgB,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,EAAE;IAUrD;;;;;;;OAOG;IACI,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO;CA2BpE"} \ No newline at end of file
diff --git a/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/read-receipt.js b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/read-receipt.js
new file mode 100644
index 0000000..c5948ef
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/read-receipt.js
@@ -0,0 +1,267 @@
+"use strict";
+
+var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.ReadReceipt = void 0;
+exports.synthesizeReceipt = synthesizeReceipt;
+var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
+var _read_receipts = require("../@types/read_receipts");
+var _typedEventEmitter = require("./typed-event-emitter");
+var utils = _interopRequireWildcard(require("../utils"));
+var _event = require("./event");
+var _event2 = require("../@types/event");
+var _room = require("./room");
+function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
+function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
+/*
+Copyright 2022 The Matrix.org Foundation C.I.C.
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+function synthesizeReceipt(userId, event, receiptType) {
+ var _event$threadRootId;
+ return new _event.MatrixEvent({
+ content: {
+ [event.getId()]: {
+ [receiptType]: {
+ [userId]: {
+ ts: event.getTs(),
+ thread_id: (_event$threadRootId = event.threadRootId) !== null && _event$threadRootId !== void 0 ? _event$threadRootId : _read_receipts.MAIN_ROOM_TIMELINE
+ }
+ }
+ }
+ },
+ type: _event2.EventType.Receipt,
+ room_id: event.getRoomId()
+ });
+}
+const ReceiptPairRealIndex = 0;
+const ReceiptPairSyntheticIndex = 1;
+class ReadReceipt extends _typedEventEmitter.TypedEventEmitter {
+ constructor(...args) {
+ super(...args);
+ (0, _defineProperty2.default)(this, "receipts", new utils.MapWithDefault(() => new Map()));
+ (0, _defineProperty2.default)(this, "receiptCacheByEventId", new Map());
+ (0, _defineProperty2.default)(this, "timeline", void 0);
+ }
+ /**
+ * Gets the latest receipt for a given user in the room
+ * @param userId - The id of the user for which we want the receipt
+ * @param ignoreSynthesized - Whether to ignore synthesized receipts or not
+ * @param receiptType - Optional. The type of the receipt we want to get
+ * @returns the latest receipts of the chosen type for the chosen user
+ */
+ getReadReceiptForUserId(userId, ignoreSynthesized = false, receiptType = _read_receipts.ReceiptType.Read) {
+ var _this$receipts$get$ge, _this$receipts$get;
+ const [realReceipt, syntheticReceipt] = (_this$receipts$get$ge = (_this$receipts$get = this.receipts.get(receiptType)) === null || _this$receipts$get === void 0 ? void 0 : _this$receipts$get.get(userId)) !== null && _this$receipts$get$ge !== void 0 ? _this$receipts$get$ge : [null, null];
+ if (ignoreSynthesized) {
+ return realReceipt;
+ }
+ return syntheticReceipt !== null && syntheticReceipt !== void 0 ? syntheticReceipt : realReceipt;
+ }
+
+ /**
+ * Get the ID of the event that a given user has read up to, or null if we
+ * have received no read receipts from them.
+ * @param userId - The user ID to get read receipt event ID for
+ * @param ignoreSynthesized - If true, return only receipts that have been
+ * sent by the server, not implicit ones generated
+ * by the JS SDK.
+ * @returns ID of the latest event that the given user has read, or null.
+ */
+ getEventReadUpTo(userId, ignoreSynthesized = false) {
+ var _publicReadReceipt$da, _privateReadReceipt$d, _ref, _privateReadReceipt$e, _ref2;
+ // XXX: This is very very ugly and I hope I won't have to ever add a new
+ // receipt type here again. IMHO this should be done by the server in
+ // some more intelligent manner or the client should just use timestamps
+
+ const timelineSet = this.getUnfilteredTimelineSet();
+ const publicReadReceipt = this.getReadReceiptForUserId(userId, ignoreSynthesized, _read_receipts.ReceiptType.Read);
+ const privateReadReceipt = this.getReadReceiptForUserId(userId, ignoreSynthesized, _read_receipts.ReceiptType.ReadPrivate);
+
+ // If we have both, compare them
+ let comparison;
+ if (publicReadReceipt !== null && publicReadReceipt !== void 0 && publicReadReceipt.eventId && privateReadReceipt !== null && privateReadReceipt !== void 0 && privateReadReceipt.eventId) {
+ comparison = timelineSet.compareEventOrdering(publicReadReceipt === null || publicReadReceipt === void 0 ? void 0 : publicReadReceipt.eventId, privateReadReceipt === null || privateReadReceipt === void 0 ? void 0 : privateReadReceipt.eventId);
+ }
+
+ // If we didn't get a comparison try to compare the ts of the receipts
+ if (!comparison && publicReadReceipt !== null && publicReadReceipt !== void 0 && (_publicReadReceipt$da = publicReadReceipt.data) !== null && _publicReadReceipt$da !== void 0 && _publicReadReceipt$da.ts && privateReadReceipt !== null && privateReadReceipt !== void 0 && (_privateReadReceipt$d = privateReadReceipt.data) !== null && _privateReadReceipt$d !== void 0 && _privateReadReceipt$d.ts) {
+ var _publicReadReceipt$da2, _privateReadReceipt$d2;
+ comparison = (publicReadReceipt === null || publicReadReceipt === void 0 ? void 0 : (_publicReadReceipt$da2 = publicReadReceipt.data) === null || _publicReadReceipt$da2 === void 0 ? void 0 : _publicReadReceipt$da2.ts) - (privateReadReceipt === null || privateReadReceipt === void 0 ? void 0 : (_privateReadReceipt$d2 = privateReadReceipt.data) === null || _privateReadReceipt$d2 === void 0 ? void 0 : _privateReadReceipt$d2.ts);
+ }
+
+ // The public receipt is more likely to drift out of date so the private
+ // one has precedence
+ if (!comparison) return (_ref = (_privateReadReceipt$e = privateReadReceipt === null || privateReadReceipt === void 0 ? void 0 : privateReadReceipt.eventId) !== null && _privateReadReceipt$e !== void 0 ? _privateReadReceipt$e : publicReadReceipt === null || publicReadReceipt === void 0 ? void 0 : publicReadReceipt.eventId) !== null && _ref !== void 0 ? _ref : null;
+
+ // If public read receipt is older, return the private one
+ return (_ref2 = comparison < 0 ? privateReadReceipt === null || privateReadReceipt === void 0 ? void 0 : privateReadReceipt.eventId : publicReadReceipt === null || publicReadReceipt === void 0 ? void 0 : publicReadReceipt.eventId) !== null && _ref2 !== void 0 ? _ref2 : null;
+ }
+ addReceiptToStructure(eventId, receiptType, userId, receipt, synthetic) {
+ var _pair$ReceiptPairSynt2, _pair$ReceiptPairSynt3;
+ const receiptTypesMap = this.receipts.getOrCreate(receiptType);
+ let pair = receiptTypesMap.get(userId);
+ if (!pair) {
+ pair = [null, null];
+ receiptTypesMap.set(userId, pair);
+ }
+ let existingReceipt = pair[ReceiptPairRealIndex];
+ if (synthetic) {
+ var _pair$ReceiptPairSynt;
+ existingReceipt = (_pair$ReceiptPairSynt = pair[ReceiptPairSyntheticIndex]) !== null && _pair$ReceiptPairSynt !== void 0 ? _pair$ReceiptPairSynt : pair[ReceiptPairRealIndex];
+ }
+ if (existingReceipt) {
+ // we only want to add this receipt if we think it is later than the one we already have.
+ // This is managed server-side, but because we synthesize RRs locally we have to do it here too.
+ const ordering = this.getUnfilteredTimelineSet().compareEventOrdering(existingReceipt.eventId, eventId);
+ if (ordering !== null && ordering >= 0) {
+ return;
+ }
+ }
+ const wrappedReceipt = {
+ eventId,
+ data: receipt
+ };
+ const realReceipt = synthetic ? pair[ReceiptPairRealIndex] : wrappedReceipt;
+ const syntheticReceipt = synthetic ? wrappedReceipt : pair[ReceiptPairSyntheticIndex];
+ let ordering = null;
+ if (realReceipt && syntheticReceipt) {
+ ordering = this.getUnfilteredTimelineSet().compareEventOrdering(realReceipt.eventId, syntheticReceipt.eventId);
+ }
+ const preferSynthetic = ordering === null || ordering < 0;
+
+ // we don't bother caching just real receipts by event ID as there's nothing that would read it.
+ // Take the current cached receipt before we overwrite the pair elements.
+ const cachedReceipt = (_pair$ReceiptPairSynt2 = pair[ReceiptPairSyntheticIndex]) !== null && _pair$ReceiptPairSynt2 !== void 0 ? _pair$ReceiptPairSynt2 : pair[ReceiptPairRealIndex];
+ if (synthetic && preferSynthetic) {
+ pair[ReceiptPairSyntheticIndex] = wrappedReceipt;
+ } else if (!synthetic) {
+ pair[ReceiptPairRealIndex] = wrappedReceipt;
+ if (!preferSynthetic) {
+ pair[ReceiptPairSyntheticIndex] = null;
+ }
+ }
+ const newCachedReceipt = (_pair$ReceiptPairSynt3 = pair[ReceiptPairSyntheticIndex]) !== null && _pair$ReceiptPairSynt3 !== void 0 ? _pair$ReceiptPairSynt3 : pair[ReceiptPairRealIndex];
+ if (cachedReceipt === newCachedReceipt) return;
+
+ // clean up any previous cache entry
+ if (cachedReceipt && this.receiptCacheByEventId.get(cachedReceipt.eventId)) {
+ const previousEventId = cachedReceipt.eventId;
+ // Remove the receipt we're about to clobber out of existence from the cache
+ this.receiptCacheByEventId.set(previousEventId, this.receiptCacheByEventId.get(previousEventId).filter(r => {
+ return r.type !== receiptType || r.userId !== userId;
+ }));
+ if (this.receiptCacheByEventId.get(previousEventId).length < 1) {
+ this.receiptCacheByEventId.delete(previousEventId); // clean up the cache keys
+ }
+ }
+
+ // cache the new one
+ if (!this.receiptCacheByEventId.get(eventId)) {
+ this.receiptCacheByEventId.set(eventId, []);
+ }
+ this.receiptCacheByEventId.get(eventId).push({
+ userId: userId,
+ type: receiptType,
+ data: receipt
+ });
+ }
+
+ /**
+ * Get a list of receipts for the given event.
+ * @param event - the event to get receipts for
+ * @returns A list of receipts with a userId, type and data keys or
+ * an empty list.
+ */
+ getReceiptsForEvent(event) {
+ return this.receiptCacheByEventId.get(event.getId()) || [];
+ }
+ /**
+ * This issue should also be addressed on synapse's side and is tracked as part
+ * of https://github.com/matrix-org/synapse/issues/14837
+ *
+ * Retrieves the read receipt for the logged in user and checks if it matches
+ * the last event in the room and whether that event originated from the logged
+ * in user.
+ * Under those conditions we can consider the context as read. This is useful
+ * because we never send read receipts against our own events
+ * @param userId - the logged in user
+ */
+ fixupNotifications(userId) {
+ const receipt = this.getReadReceiptForUserId(userId, false);
+ const lastEvent = this.timeline[this.timeline.length - 1];
+ if (lastEvent && (receipt === null || receipt === void 0 ? void 0 : receipt.eventId) === lastEvent.getId() && userId === lastEvent.getSender()) {
+ this.setUnread(_room.NotificationCountType.Total, 0);
+ this.setUnread(_room.NotificationCountType.Highlight, 0);
+ }
+ }
+
+ /**
+ * Add a temporary local-echo receipt to the room to reflect in the
+ * client the fact that we've sent one.
+ * @param userId - The user ID if the receipt sender
+ * @param e - The event that is to be acknowledged
+ * @param receiptType - The type of receipt
+ */
+ addLocalEchoReceipt(userId, e, receiptType) {
+ this.addReceipt(synthesizeReceipt(userId, e, receiptType), true);
+ }
+
+ /**
+ * Get a list of user IDs who have <b>read up to</b> the given event.
+ * @param event - the event to get read receipts for.
+ * @returns A list of user IDs.
+ */
+ getUsersReadUpTo(event) {
+ return this.getReceiptsForEvent(event).filter(function (receipt) {
+ return utils.isSupportedReceiptType(receipt.type);
+ }).map(function (receipt) {
+ return receipt.userId;
+ });
+ }
+
+ /**
+ * Determines if the given user has read a particular event ID with the known
+ * history of the room. This is not a definitive check as it relies only on
+ * what is available to the room at the time of execution.
+ * @param userId - The user ID to check the read state of.
+ * @param eventId - The event ID to check if the user read.
+ * @returns True if the user has read the event, false otherwise.
+ */
+ hasUserReadEvent(userId, eventId) {
+ var _this$timeline;
+ const readUpToId = this.getEventReadUpTo(userId, false);
+ if (readUpToId === eventId) return true;
+ if ((_this$timeline = this.timeline) !== null && _this$timeline !== void 0 && _this$timeline.length && this.timeline[this.timeline.length - 1].getSender() && this.timeline[this.timeline.length - 1].getSender() === userId) {
+ // It doesn't matter where the event is in the timeline, the user has read
+ // it because they've sent the latest event.
+ return true;
+ }
+ for (let i = ((_this$timeline2 = this.timeline) === null || _this$timeline2 === void 0 ? void 0 : _this$timeline2.length) - 1; i >= 0; --i) {
+ var _this$timeline2;
+ const ev = this.timeline[i];
+
+ // If we encounter the target event first, the user hasn't read it
+ // however if we encounter the readUpToId first then the user has read
+ // it. These rules apply because we're iterating bottom-up.
+ if (ev.getId() === eventId) return false;
+ if (ev.getId() === readUpToId) return true;
+ }
+
+ // We don't know if the user has read it, so assume not.
+ return false;
+ }
+}
+exports.ReadReceipt = ReadReceipt;
+//# sourceMappingURL=read-receipt.js.map \ No newline at end of file
diff --git a/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/read-receipt.js.map b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/read-receipt.js.map
new file mode 100644
index 0000000..435e602
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/read-receipt.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"read-receipt.js","names":["_read_receipts","require","_typedEventEmitter","utils","_interopRequireWildcard","_event","_event2","_room","_getRequireWildcardCache","nodeInterop","WeakMap","cacheBabelInterop","cacheNodeInterop","obj","__esModule","default","cache","has","get","newObj","hasPropertyDescriptor","Object","defineProperty","getOwnPropertyDescriptor","key","prototype","hasOwnProperty","call","desc","set","synthesizeReceipt","userId","event","receiptType","_event$threadRootId","MatrixEvent","content","getId","ts","getTs","thread_id","threadRootId","MAIN_ROOM_TIMELINE","type","EventType","Receipt","room_id","getRoomId","ReceiptPairRealIndex","ReceiptPairSyntheticIndex","ReadReceipt","TypedEventEmitter","constructor","args","_defineProperty2","MapWithDefault","Map","getReadReceiptForUserId","ignoreSynthesized","ReceiptType","Read","_this$receipts$get$ge","_this$receipts$get","realReceipt","syntheticReceipt","receipts","getEventReadUpTo","_publicReadReceipt$da","_privateReadReceipt$d","_ref","_privateReadReceipt$e","_ref2","timelineSet","getUnfilteredTimelineSet","publicReadReceipt","privateReadReceipt","ReadPrivate","comparison","eventId","compareEventOrdering","data","_publicReadReceipt$da2","_privateReadReceipt$d2","addReceiptToStructure","receipt","synthetic","_pair$ReceiptPairSynt2","_pair$ReceiptPairSynt3","receiptTypesMap","getOrCreate","pair","existingReceipt","_pair$ReceiptPairSynt","ordering","wrappedReceipt","preferSynthetic","cachedReceipt","newCachedReceipt","receiptCacheByEventId","previousEventId","filter","r","length","delete","push","getReceiptsForEvent","fixupNotifications","lastEvent","timeline","getSender","setUnread","NotificationCountType","Total","Highlight","addLocalEchoReceipt","e","addReceipt","getUsersReadUpTo","isSupportedReceiptType","map","hasUserReadEvent","_this$timeline","readUpToId","i","_this$timeline2","ev","exports"],"sources":["../../src/models/read-receipt.ts"],"sourcesContent":["/*\nCopyright 2022 The Matrix.org Foundation C.I.C.\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 http://www.apache.org/licenses/LICENSE-2.0\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 CachedReceipt,\n MAIN_ROOM_TIMELINE,\n Receipt,\n ReceiptCache,\n ReceiptType,\n WrappedReceipt,\n} from \"../@types/read_receipts\";\nimport { ListenerMap, TypedEventEmitter } from \"./typed-event-emitter\";\nimport * as utils from \"../utils\";\nimport { MatrixEvent } from \"./event\";\nimport { EventType } from \"../@types/event\";\nimport { EventTimelineSet } from \"./event-timeline-set\";\nimport { MapWithDefault } from \"../utils\";\nimport { NotificationCountType } from \"./room\";\n\nexport function synthesizeReceipt(userId: string, event: MatrixEvent, receiptType: ReceiptType): MatrixEvent {\n return new MatrixEvent({\n content: {\n [event.getId()!]: {\n [receiptType]: {\n [userId]: {\n ts: event.getTs(),\n thread_id: event.threadRootId ?? MAIN_ROOM_TIMELINE,\n },\n },\n },\n },\n type: EventType.Receipt,\n room_id: event.getRoomId(),\n });\n}\n\nconst ReceiptPairRealIndex = 0;\nconst ReceiptPairSyntheticIndex = 1;\n\nexport abstract class ReadReceipt<\n Events extends string,\n Arguments extends ListenerMap<Events>,\n SuperclassArguments extends ListenerMap<any> = Arguments,\n> extends TypedEventEmitter<Events, Arguments, SuperclassArguments> {\n // receipts should clobber based on receipt_type and user_id pairs hence\n // the form of this structure. This is sub-optimal for the exposed APIs\n // which pass in an event ID and get back some receipts, so we also store\n // a pre-cached list for this purpose.\n // Map: receipt type → user Id → receipt\n private receipts = new MapWithDefault<string, Map<string, [WrappedReceipt | null, WrappedReceipt | null]>>(\n () => new Map(),\n );\n private receiptCacheByEventId: ReceiptCache = new Map();\n\n public abstract getUnfilteredTimelineSet(): EventTimelineSet;\n public abstract timeline: MatrixEvent[];\n\n /**\n * Gets the latest receipt for a given user in the room\n * @param userId - The id of the user for which we want the receipt\n * @param ignoreSynthesized - Whether to ignore synthesized receipts or not\n * @param receiptType - Optional. The type of the receipt we want to get\n * @returns the latest receipts of the chosen type for the chosen user\n */\n public getReadReceiptForUserId(\n userId: string,\n ignoreSynthesized = false,\n receiptType = ReceiptType.Read,\n ): WrappedReceipt | null {\n const [realReceipt, syntheticReceipt] = this.receipts.get(receiptType)?.get(userId) ?? [null, null];\n if (ignoreSynthesized) {\n return realReceipt;\n }\n\n return syntheticReceipt ?? realReceipt;\n }\n\n /**\n * Get the ID of the event that a given user has read up to, or null if we\n * have received no read receipts 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 = false): string | null {\n // XXX: This is very very ugly and I hope I won't have to ever add a new\n // receipt type here again. IMHO this should be done by the server in\n // some more intelligent manner or the client should just use timestamps\n\n const timelineSet = this.getUnfilteredTimelineSet();\n const publicReadReceipt = this.getReadReceiptForUserId(userId, ignoreSynthesized, ReceiptType.Read);\n const privateReadReceipt = this.getReadReceiptForUserId(userId, ignoreSynthesized, ReceiptType.ReadPrivate);\n\n // If we have both, compare them\n let comparison: number | null | undefined;\n if (publicReadReceipt?.eventId && privateReadReceipt?.eventId) {\n comparison = timelineSet.compareEventOrdering(publicReadReceipt?.eventId, privateReadReceipt?.eventId);\n }\n\n // If we didn't get a comparison try to compare the ts of the receipts\n if (!comparison && publicReadReceipt?.data?.ts && privateReadReceipt?.data?.ts) {\n comparison = publicReadReceipt?.data?.ts - privateReadReceipt?.data?.ts;\n }\n\n // The public receipt is more likely to drift out of date so the private\n // one has precedence\n if (!comparison) return privateReadReceipt?.eventId ?? publicReadReceipt?.eventId ?? null;\n\n // If public read receipt is older, return the private one\n return (comparison < 0 ? privateReadReceipt?.eventId : publicReadReceipt?.eventId) ?? null;\n }\n\n public addReceiptToStructure(\n eventId: string,\n receiptType: ReceiptType,\n userId: string,\n receipt: Receipt,\n synthetic: boolean,\n ): void {\n const receiptTypesMap = this.receipts.getOrCreate(receiptType);\n let pair = receiptTypesMap.get(userId);\n\n if (!pair) {\n pair = [null, null];\n receiptTypesMap.set(userId, pair);\n }\n\n let existingReceipt = pair[ReceiptPairRealIndex];\n if (synthetic) {\n existingReceipt = pair[ReceiptPairSyntheticIndex] ?? pair[ReceiptPairRealIndex];\n }\n\n if (existingReceipt) {\n // we only want to add this receipt if we think it is later than the one we already have.\n // This is managed server-side, but because we synthesize RRs locally we have to do it here too.\n const ordering = this.getUnfilteredTimelineSet().compareEventOrdering(existingReceipt.eventId, eventId);\n if (ordering !== null && ordering >= 0) {\n return;\n }\n }\n\n const wrappedReceipt: WrappedReceipt = {\n eventId,\n data: receipt,\n };\n\n const realReceipt = synthetic ? pair[ReceiptPairRealIndex] : wrappedReceipt;\n const syntheticReceipt = synthetic ? wrappedReceipt : pair[ReceiptPairSyntheticIndex];\n\n let ordering: number | null = null;\n if (realReceipt && syntheticReceipt) {\n ordering = this.getUnfilteredTimelineSet().compareEventOrdering(\n realReceipt.eventId,\n syntheticReceipt.eventId,\n );\n }\n\n const preferSynthetic = ordering === null || ordering < 0;\n\n // we don't bother caching just real receipts by event ID as there's nothing that would read it.\n // Take the current cached receipt before we overwrite the pair elements.\n const cachedReceipt = pair[ReceiptPairSyntheticIndex] ?? pair[ReceiptPairRealIndex];\n\n if (synthetic && preferSynthetic) {\n pair[ReceiptPairSyntheticIndex] = wrappedReceipt;\n } else if (!synthetic) {\n pair[ReceiptPairRealIndex] = wrappedReceipt;\n\n if (!preferSynthetic) {\n pair[ReceiptPairSyntheticIndex] = null;\n }\n }\n\n const newCachedReceipt = pair[ReceiptPairSyntheticIndex] ?? pair[ReceiptPairRealIndex];\n if (cachedReceipt === newCachedReceipt) return;\n\n // clean up any previous cache entry\n if (cachedReceipt && this.receiptCacheByEventId.get(cachedReceipt.eventId)) {\n const previousEventId = cachedReceipt.eventId;\n // Remove the receipt we're about to clobber out of existence from the cache\n this.receiptCacheByEventId.set(\n previousEventId,\n this.receiptCacheByEventId.get(previousEventId)!.filter((r) => {\n return r.type !== receiptType || r.userId !== userId;\n }),\n );\n\n if (this.receiptCacheByEventId.get(previousEventId)!.length < 1) {\n this.receiptCacheByEventId.delete(previousEventId); // clean up the cache keys\n }\n }\n\n // cache the new one\n if (!this.receiptCacheByEventId.get(eventId)) {\n this.receiptCacheByEventId.set(eventId, []);\n }\n this.receiptCacheByEventId.get(eventId)!.push({\n userId: userId,\n type: receiptType as ReceiptType,\n data: receipt,\n });\n }\n\n /**\n * Get a list of receipts for the given event.\n * @param event - the event to get receipts for\n * @returns A list of receipts with a userId, type and data keys or\n * an empty list.\n */\n public getReceiptsForEvent(event: MatrixEvent): CachedReceipt[] {\n return this.receiptCacheByEventId.get(event.getId()!) || [];\n }\n\n public abstract addReceipt(event: MatrixEvent, synthetic: boolean): void;\n\n public abstract setUnread(type: NotificationCountType, count: number): void;\n\n /**\n * This issue should also be addressed on synapse's side and is tracked as part\n * of https://github.com/matrix-org/synapse/issues/14837\n *\n * Retrieves the read receipt for the logged in user and checks if it matches\n * the last event in the room and whether that event originated from the logged\n * in user.\n * Under those conditions we can consider the context as read. This is useful\n * because we never send read receipts against our own events\n * @param userId - the logged in user\n */\n public fixupNotifications(userId: string): void {\n const receipt = this.getReadReceiptForUserId(userId, false);\n\n const lastEvent = this.timeline[this.timeline.length - 1];\n if (lastEvent && receipt?.eventId === lastEvent.getId() && userId === lastEvent.getSender()) {\n this.setUnread(NotificationCountType.Total, 0);\n this.setUnread(NotificationCountType.Highlight, 0);\n }\n }\n\n /**\n * Add a temporary local-echo receipt to the room to reflect in the\n * client the fact that we've sent one.\n * @param userId - The user ID if the receipt sender\n * @param e - The event that is to be acknowledged\n * @param receiptType - The type of receipt\n */\n public addLocalEchoReceipt(userId: string, e: MatrixEvent, receiptType: ReceiptType): void {\n this.addReceipt(synthesizeReceipt(userId, e, receiptType), true);\n }\n\n /**\n * Get a list of user IDs who have <b>read up to</b> the given event.\n * @param event - the event to get read receipts for.\n * @returns A list of user IDs.\n */\n public getUsersReadUpTo(event: MatrixEvent): string[] {\n return this.getReceiptsForEvent(event)\n .filter(function (receipt) {\n return utils.isSupportedReceiptType(receipt.type);\n })\n .map(function (receipt) {\n return receipt.userId;\n });\n }\n\n /**\n * Determines if the given user has read a particular event ID with the known\n * history of the room. This is not a definitive check as it relies only on\n * what is available to the room 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 const readUpToId = this.getEventReadUpTo(userId, false);\n if (readUpToId === eventId) return true;\n\n if (\n this.timeline?.length &&\n this.timeline[this.timeline.length - 1].getSender() &&\n this.timeline[this.timeline.length - 1].getSender() === userId\n ) {\n // It doesn't matter where the event is in the timeline, the user has read\n // it because they've sent the latest event.\n return true;\n }\n\n for (let i = this.timeline?.length - 1; i >= 0; --i) {\n const ev = this.timeline[i];\n\n // If we encounter the target event first, the user hasn't read it\n // however if we encounter the readUpToId first then the user has read\n // it. These rules apply because we're iterating bottom-up.\n if (ev.getId() === eventId) return false;\n if (ev.getId() === readUpToId) return true;\n }\n\n // We don't know if the user has read it, so assume not.\n return false;\n }\n}\n"],"mappings":";;;;;;;;;AAaA,IAAAA,cAAA,GAAAC,OAAA;AAQA,IAAAC,kBAAA,GAAAD,OAAA;AACA,IAAAE,KAAA,GAAAC,uBAAA,CAAAH,OAAA;AACA,IAAAI,MAAA,GAAAJ,OAAA;AACA,IAAAK,OAAA,GAAAL,OAAA;AAGA,IAAAM,KAAA,GAAAN,OAAA;AAA+C,SAAAO,yBAAAC,WAAA,eAAAC,OAAA,kCAAAC,iBAAA,OAAAD,OAAA,QAAAE,gBAAA,OAAAF,OAAA,YAAAF,wBAAA,YAAAA,CAAAC,WAAA,WAAAA,WAAA,GAAAG,gBAAA,GAAAD,iBAAA,KAAAF,WAAA;AAAA,SAAAL,wBAAAS,GAAA,EAAAJ,WAAA,SAAAA,WAAA,IAAAI,GAAA,IAAAA,GAAA,CAAAC,UAAA,WAAAD,GAAA,QAAAA,GAAA,oBAAAA,GAAA,wBAAAA,GAAA,4BAAAE,OAAA,EAAAF,GAAA,UAAAG,KAAA,GAAAR,wBAAA,CAAAC,WAAA,OAAAO,KAAA,IAAAA,KAAA,CAAAC,GAAA,CAAAJ,GAAA,YAAAG,KAAA,CAAAE,GAAA,CAAAL,GAAA,SAAAM,MAAA,WAAAC,qBAAA,GAAAC,MAAA,CAAAC,cAAA,IAAAD,MAAA,CAAAE,wBAAA,WAAAC,GAAA,IAAAX,GAAA,QAAAW,GAAA,kBAAAH,MAAA,CAAAI,SAAA,CAAAC,cAAA,CAAAC,IAAA,CAAAd,GAAA,EAAAW,GAAA,SAAAI,IAAA,GAAAR,qBAAA,GAAAC,MAAA,CAAAE,wBAAA,CAAAV,GAAA,EAAAW,GAAA,cAAAI,IAAA,KAAAA,IAAA,CAAAV,GAAA,IAAAU,IAAA,CAAAC,GAAA,KAAAR,MAAA,CAAAC,cAAA,CAAAH,MAAA,EAAAK,GAAA,EAAAI,IAAA,YAAAT,MAAA,CAAAK,GAAA,IAAAX,GAAA,CAAAW,GAAA,SAAAL,MAAA,CAAAJ,OAAA,GAAAF,GAAA,MAAAG,KAAA,IAAAA,KAAA,CAAAa,GAAA,CAAAhB,GAAA,EAAAM,MAAA,YAAAA,MAAA;AA3B/C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAkBO,SAASW,iBAAiBA,CAACC,MAAc,EAAEC,KAAkB,EAAEC,WAAwB,EAAe;EAAA,IAAAC,mBAAA;EACzG,OAAO,IAAIC,kBAAW,CAAC;IACnBC,OAAO,EAAE;MACL,CAACJ,KAAK,CAACK,KAAK,EAAE,GAAI;QACd,CAACJ,WAAW,GAAG;UACX,CAACF,MAAM,GAAG;YACNO,EAAE,EAAEN,KAAK,CAACO,KAAK,EAAE;YACjBC,SAAS,GAAAN,mBAAA,GAAEF,KAAK,CAACS,YAAY,cAAAP,mBAAA,cAAAA,mBAAA,GAAIQ;UACrC;QACJ;MACJ;IACJ,CAAC;IACDC,IAAI,EAAEC,iBAAS,CAACC,OAAO;IACvBC,OAAO,EAAEd,KAAK,CAACe,SAAS;EAC5B,CAAC,CAAC;AACN;AAEA,MAAMC,oBAAoB,GAAG,CAAC;AAC9B,MAAMC,yBAAyB,GAAG,CAAC;AAE5B,MAAeC,WAAW,SAIvBC,oCAAiB,CAAyC;EAAAC,YAAA,GAAAC,IAAA;IAAA,SAAAA,IAAA;IAAA,IAAAC,gBAAA,CAAAvC,OAAA,oBAM7C,IAAIwC,oBAAc,CACjC,MAAM,IAAIC,GAAG,EAAE,CAClB;IAAA,IAAAF,gBAAA,CAAAvC,OAAA,iCAC6C,IAAIyC,GAAG,EAAE;IAAA,IAAAF,gBAAA,CAAAvC,OAAA;EAAA;EAKvD;AACJ;AACA;AACA;AACA;AACA;AACA;EACW0C,uBAAuBA,CAC1B1B,MAAc,EACd2B,iBAAiB,GAAG,KAAK,EACzBzB,WAAW,GAAG0B,0BAAW,CAACC,IAAI,EACT;IAAA,IAAAC,qBAAA,EAAAC,kBAAA;IACrB,MAAM,CAACC,WAAW,EAAEC,gBAAgB,CAAC,IAAAH,qBAAA,IAAAC,kBAAA,GAAG,IAAI,CAACG,QAAQ,CAAC/C,GAAG,CAACe,WAAW,CAAC,cAAA6B,kBAAA,uBAA9BA,kBAAA,CAAgC5C,GAAG,CAACa,MAAM,CAAC,cAAA8B,qBAAA,cAAAA,qBAAA,GAAI,CAAC,IAAI,EAAE,IAAI,CAAC;IACnG,IAAIH,iBAAiB,EAAE;MACnB,OAAOK,WAAW;IACtB;IAEA,OAAOC,gBAAgB,aAAhBA,gBAAgB,cAAhBA,gBAAgB,GAAID,WAAW;EAC1C;;EAEA;AACJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;EACWG,gBAAgBA,CAACnC,MAAc,EAAE2B,iBAAiB,GAAG,KAAK,EAAiB;IAAA,IAAAS,qBAAA,EAAAC,qBAAA,EAAAC,IAAA,EAAAC,qBAAA,EAAAC,KAAA;IAC9E;IACA;IACA;;IAEA,MAAMC,WAAW,GAAG,IAAI,CAACC,wBAAwB,EAAE;IACnD,MAAMC,iBAAiB,GAAG,IAAI,CAACjB,uBAAuB,CAAC1B,MAAM,EAAE2B,iBAAiB,EAAEC,0BAAW,CAACC,IAAI,CAAC;IACnG,MAAMe,kBAAkB,GAAG,IAAI,CAAClB,uBAAuB,CAAC1B,MAAM,EAAE2B,iBAAiB,EAAEC,0BAAW,CAACiB,WAAW,CAAC;;IAE3G;IACA,IAAIC,UAAqC;IACzC,IAAIH,iBAAiB,aAAjBA,iBAAiB,eAAjBA,iBAAiB,CAAEI,OAAO,IAAIH,kBAAkB,aAAlBA,kBAAkB,eAAlBA,kBAAkB,CAAEG,OAAO,EAAE;MAC3DD,UAAU,GAAGL,WAAW,CAACO,oBAAoB,CAACL,iBAAiB,aAAjBA,iBAAiB,uBAAjBA,iBAAiB,CAAEI,OAAO,EAAEH,kBAAkB,aAAlBA,kBAAkB,uBAAlBA,kBAAkB,CAAEG,OAAO,CAAC;IAC1G;;IAEA;IACA,IAAI,CAACD,UAAU,IAAIH,iBAAiB,aAAjBA,iBAAiB,gBAAAP,qBAAA,GAAjBO,iBAAiB,CAAEM,IAAI,cAAAb,qBAAA,eAAvBA,qBAAA,CAAyB7B,EAAE,IAAIqC,kBAAkB,aAAlBA,kBAAkB,gBAAAP,qBAAA,GAAlBO,kBAAkB,CAAEK,IAAI,cAAAZ,qBAAA,eAAxBA,qBAAA,CAA0B9B,EAAE,EAAE;MAAA,IAAA2C,sBAAA,EAAAC,sBAAA;MAC5EL,UAAU,GAAG,CAAAH,iBAAiB,aAAjBA,iBAAiB,wBAAAO,sBAAA,GAAjBP,iBAAiB,CAAEM,IAAI,cAAAC,sBAAA,uBAAvBA,sBAAA,CAAyB3C,EAAE,KAAGqC,kBAAkB,aAAlBA,kBAAkB,wBAAAO,sBAAA,GAAlBP,kBAAkB,CAAEK,IAAI,cAAAE,sBAAA,uBAAxBA,sBAAA,CAA0B5C,EAAE;IAC3E;;IAEA;IACA;IACA,IAAI,CAACuC,UAAU,EAAE,QAAAR,IAAA,IAAAC,qBAAA,GAAOK,kBAAkB,aAAlBA,kBAAkB,uBAAlBA,kBAAkB,CAAEG,OAAO,cAAAR,qBAAA,cAAAA,qBAAA,GAAII,iBAAiB,aAAjBA,iBAAiB,uBAAjBA,iBAAiB,CAAEI,OAAO,cAAAT,IAAA,cAAAA,IAAA,GAAI,IAAI;;IAEzF;IACA,QAAAE,KAAA,GAAQM,UAAU,GAAG,CAAC,GAAGF,kBAAkB,aAAlBA,kBAAkB,uBAAlBA,kBAAkB,CAAEG,OAAO,GAAGJ,iBAAiB,aAAjBA,iBAAiB,uBAAjBA,iBAAiB,CAAEI,OAAO,cAAAP,KAAA,cAAAA,KAAA,GAAK,IAAI;EAC9F;EAEOY,qBAAqBA,CACxBL,OAAe,EACf7C,WAAwB,EACxBF,MAAc,EACdqD,OAAgB,EAChBC,SAAkB,EACd;IAAA,IAAAC,sBAAA,EAAAC,sBAAA;IACJ,MAAMC,eAAe,GAAG,IAAI,CAACvB,QAAQ,CAACwB,WAAW,CAACxD,WAAW,CAAC;IAC9D,IAAIyD,IAAI,GAAGF,eAAe,CAACtE,GAAG,CAACa,MAAM,CAAC;IAEtC,IAAI,CAAC2D,IAAI,EAAE;MACPA,IAAI,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC;MACnBF,eAAe,CAAC3D,GAAG,CAACE,MAAM,EAAE2D,IAAI,CAAC;IACrC;IAEA,IAAIC,eAAe,GAAGD,IAAI,CAAC1C,oBAAoB,CAAC;IAChD,IAAIqC,SAAS,EAAE;MAAA,IAAAO,qBAAA;MACXD,eAAe,IAAAC,qBAAA,GAAGF,IAAI,CAACzC,yBAAyB,CAAC,cAAA2C,qBAAA,cAAAA,qBAAA,GAAIF,IAAI,CAAC1C,oBAAoB,CAAC;IACnF;IAEA,IAAI2C,eAAe,EAAE;MACjB;MACA;MACA,MAAME,QAAQ,GAAG,IAAI,CAACpB,wBAAwB,EAAE,CAACM,oBAAoB,CAACY,eAAe,CAACb,OAAO,EAAEA,OAAO,CAAC;MACvG,IAAIe,QAAQ,KAAK,IAAI,IAAIA,QAAQ,IAAI,CAAC,EAAE;QACpC;MACJ;IACJ;IAEA,MAAMC,cAA8B,GAAG;MACnChB,OAAO;MACPE,IAAI,EAAEI;IACV,CAAC;IAED,MAAMrB,WAAW,GAAGsB,SAAS,GAAGK,IAAI,CAAC1C,oBAAoB,CAAC,GAAG8C,cAAc;IAC3E,MAAM9B,gBAAgB,GAAGqB,SAAS,GAAGS,cAAc,GAAGJ,IAAI,CAACzC,yBAAyB,CAAC;IAErF,IAAI4C,QAAuB,GAAG,IAAI;IAClC,IAAI9B,WAAW,IAAIC,gBAAgB,EAAE;MACjC6B,QAAQ,GAAG,IAAI,CAACpB,wBAAwB,EAAE,CAACM,oBAAoB,CAC3DhB,WAAW,CAACe,OAAO,EACnBd,gBAAgB,CAACc,OAAO,CAC3B;IACL;IAEA,MAAMiB,eAAe,GAAGF,QAAQ,KAAK,IAAI,IAAIA,QAAQ,GAAG,CAAC;;IAEzD;IACA;IACA,MAAMG,aAAa,IAAAV,sBAAA,GAAGI,IAAI,CAACzC,yBAAyB,CAAC,cAAAqC,sBAAA,cAAAA,sBAAA,GAAII,IAAI,CAAC1C,oBAAoB,CAAC;IAEnF,IAAIqC,SAAS,IAAIU,eAAe,EAAE;MAC9BL,IAAI,CAACzC,yBAAyB,CAAC,GAAG6C,cAAc;IACpD,CAAC,MAAM,IAAI,CAACT,SAAS,EAAE;MACnBK,IAAI,CAAC1C,oBAAoB,CAAC,GAAG8C,cAAc;MAE3C,IAAI,CAACC,eAAe,EAAE;QAClBL,IAAI,CAACzC,yBAAyB,CAAC,GAAG,IAAI;MAC1C;IACJ;IAEA,MAAMgD,gBAAgB,IAAAV,sBAAA,GAAGG,IAAI,CAACzC,yBAAyB,CAAC,cAAAsC,sBAAA,cAAAA,sBAAA,GAAIG,IAAI,CAAC1C,oBAAoB,CAAC;IACtF,IAAIgD,aAAa,KAAKC,gBAAgB,EAAE;;IAExC;IACA,IAAID,aAAa,IAAI,IAAI,CAACE,qBAAqB,CAAChF,GAAG,CAAC8E,aAAa,CAAClB,OAAO,CAAC,EAAE;MACxE,MAAMqB,eAAe,GAAGH,aAAa,CAAClB,OAAO;MAC7C;MACA,IAAI,CAACoB,qBAAqB,CAACrE,GAAG,CAC1BsE,eAAe,EACf,IAAI,CAACD,qBAAqB,CAAChF,GAAG,CAACiF,eAAe,CAAC,CAAEC,MAAM,CAAEC,CAAC,IAAK;QAC3D,OAAOA,CAAC,CAAC1D,IAAI,KAAKV,WAAW,IAAIoE,CAAC,CAACtE,MAAM,KAAKA,MAAM;MACxD,CAAC,CAAC,CACL;MAED,IAAI,IAAI,CAACmE,qBAAqB,CAAChF,GAAG,CAACiF,eAAe,CAAC,CAAEG,MAAM,GAAG,CAAC,EAAE;QAC7D,IAAI,CAACJ,qBAAqB,CAACK,MAAM,CAACJ,eAAe,CAAC,CAAC,CAAC;MACxD;IACJ;;IAEA;IACA,IAAI,CAAC,IAAI,CAACD,qBAAqB,CAAChF,GAAG,CAAC4D,OAAO,CAAC,EAAE;MAC1C,IAAI,CAACoB,qBAAqB,CAACrE,GAAG,CAACiD,OAAO,EAAE,EAAE,CAAC;IAC/C;IACA,IAAI,CAACoB,qBAAqB,CAAChF,GAAG,CAAC4D,OAAO,CAAC,CAAE0B,IAAI,CAAC;MAC1CzE,MAAM,EAAEA,MAAM;MACdY,IAAI,EAAEV,WAA0B;MAChC+C,IAAI,EAAEI;IACV,CAAC,CAAC;EACN;;EAEA;AACJ;AACA;AACA;AACA;AACA;EACWqB,mBAAmBA,CAACzE,KAAkB,EAAmB;IAC5D,OAAO,IAAI,CAACkE,qBAAqB,CAAChF,GAAG,CAACc,KAAK,CAACK,KAAK,EAAE,CAAE,IAAI,EAAE;EAC/D;EAMA;AACJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;EACWqE,kBAAkBA,CAAC3E,MAAc,EAAQ;IAC5C,MAAMqD,OAAO,GAAG,IAAI,CAAC3B,uBAAuB,CAAC1B,MAAM,EAAE,KAAK,CAAC;IAE3D,MAAM4E,SAAS,GAAG,IAAI,CAACC,QAAQ,CAAC,IAAI,CAACA,QAAQ,CAACN,MAAM,GAAG,CAAC,CAAC;IACzD,IAAIK,SAAS,IAAI,CAAAvB,OAAO,aAAPA,OAAO,uBAAPA,OAAO,CAAEN,OAAO,MAAK6B,SAAS,CAACtE,KAAK,EAAE,IAAIN,MAAM,KAAK4E,SAAS,CAACE,SAAS,EAAE,EAAE;MACzF,IAAI,CAACC,SAAS,CAACC,2BAAqB,CAACC,KAAK,EAAE,CAAC,CAAC;MAC9C,IAAI,CAACF,SAAS,CAACC,2BAAqB,CAACE,SAAS,EAAE,CAAC,CAAC;IACtD;EACJ;;EAEA;AACJ;AACA;AACA;AACA;AACA;AACA;EACWC,mBAAmBA,CAACnF,MAAc,EAAEoF,CAAc,EAAElF,WAAwB,EAAQ;IACvF,IAAI,CAACmF,UAAU,CAACtF,iBAAiB,CAACC,MAAM,EAAEoF,CAAC,EAAElF,WAAW,CAAC,EAAE,IAAI,CAAC;EACpE;;EAEA;AACJ;AACA;AACA;AACA;EACWoF,gBAAgBA,CAACrF,KAAkB,EAAY;IAClD,OAAO,IAAI,CAACyE,mBAAmB,CAACzE,KAAK,CAAC,CACjCoE,MAAM,CAAC,UAAUhB,OAAO,EAAE;MACvB,OAAOjF,KAAK,CAACmH,sBAAsB,CAAClC,OAAO,CAACzC,IAAI,CAAC;IACrD,CAAC,CAAC,CACD4E,GAAG,CAAC,UAAUnC,OAAO,EAAE;MACpB,OAAOA,OAAO,CAACrD,MAAM;IACzB,CAAC,CAAC;EACV;;EAEA;AACJ;AACA;AACA;AACA;AACA;AACA;AACA;EACWyF,gBAAgBA,CAACzF,MAAc,EAAE+C,OAAe,EAAW;IAAA,IAAA2C,cAAA;IAC9D,MAAMC,UAAU,GAAG,IAAI,CAACxD,gBAAgB,CAACnC,MAAM,EAAE,KAAK,CAAC;IACvD,IAAI2F,UAAU,KAAK5C,OAAO,EAAE,OAAO,IAAI;IAEvC,IACI,CAAA2C,cAAA,OAAI,CAACb,QAAQ,cAAAa,cAAA,eAAbA,cAAA,CAAenB,MAAM,IACrB,IAAI,CAACM,QAAQ,CAAC,IAAI,CAACA,QAAQ,CAACN,MAAM,GAAG,CAAC,CAAC,CAACO,SAAS,EAAE,IACnD,IAAI,CAACD,QAAQ,CAAC,IAAI,CAACA,QAAQ,CAACN,MAAM,GAAG,CAAC,CAAC,CAACO,SAAS,EAAE,KAAK9E,MAAM,EAChE;MACE;MACA;MACA,OAAO,IAAI;IACf;IAEA,KAAK,IAAI4F,CAAC,GAAG,EAAAC,eAAA,OAAI,CAAChB,QAAQ,cAAAgB,eAAA,uBAAbA,eAAA,CAAetB,MAAM,IAAG,CAAC,EAAEqB,CAAC,IAAI,CAAC,EAAE,EAAEA,CAAC,EAAE;MAAA,IAAAC,eAAA;MACjD,MAAMC,EAAE,GAAG,IAAI,CAACjB,QAAQ,CAACe,CAAC,CAAC;;MAE3B;MACA;MACA;MACA,IAAIE,EAAE,CAACxF,KAAK,EAAE,KAAKyC,OAAO,EAAE,OAAO,KAAK;MACxC,IAAI+C,EAAE,CAACxF,KAAK,EAAE,KAAKqF,UAAU,EAAE,OAAO,IAAI;IAC9C;;IAEA;IACA,OAAO,KAAK;EAChB;AACJ;AAACI,OAAA,CAAA5E,WAAA,GAAAA,WAAA"} \ No newline at end of file
diff --git a/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/related-relations.d.ts b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/related-relations.d.ts
new file mode 100644
index 0000000..1b1cbcc
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/related-relations.d.ts
@@ -0,0 +1,11 @@
+import { Relations, RelationsEvent, EventHandlerMap } from "./relations";
+import { MatrixEvent } from "./event";
+import { Listener } from "./typed-event-emitter";
+export declare class RelatedRelations {
+ private relations;
+ constructor(relations: Relations[]);
+ getRelations(): MatrixEvent[];
+ on<T extends RelationsEvent>(ev: T, fn: Listener<RelationsEvent, EventHandlerMap, T>): void;
+ off<T extends RelationsEvent>(ev: T, fn: Listener<RelationsEvent, EventHandlerMap, T>): void;
+}
+//# sourceMappingURL=related-relations.d.ts.map \ No newline at end of file
diff --git a/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/related-relations.d.ts.map b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/related-relations.d.ts.map
new file mode 100644
index 0000000..969534e
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/related-relations.d.ts.map
@@ -0,0 +1 @@
+{"version":3,"file":"related-relations.d.ts","sourceRoot":"","sources":["../../src/models/related-relations.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACzE,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AACtC,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAEjD,qBAAa,gBAAgB;IACzB,OAAO,CAAC,SAAS,CAAc;gBAEZ,SAAS,EAAE,SAAS,EAAE;IAIlC,YAAY,IAAI,WAAW,EAAE;IAI7B,EAAE,CAAC,CAAC,SAAS,cAAc,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,QAAQ,CAAC,cAAc,EAAE,eAAe,EAAE,CAAC,CAAC,GAAG,IAAI;IAI3F,GAAG,CAAC,CAAC,SAAS,cAAc,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,QAAQ,CAAC,cAAc,EAAE,eAAe,EAAE,CAAC,CAAC,GAAG,IAAI;CAGtG"} \ No newline at end of file
diff --git a/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/related-relations.js b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/related-relations.js
new file mode 100644
index 0000000..ac0be44
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/related-relations.js
@@ -0,0 +1,41 @@
+"use strict";
+
+var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.RelatedRelations = void 0;
+var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
+/*
+Copyright 2022 The Matrix.org Foundation C.I.C.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+class RelatedRelations {
+ constructor(relations) {
+ (0, _defineProperty2.default)(this, "relations", void 0);
+ this.relations = relations.filter(r => !!r);
+ }
+ getRelations() {
+ return this.relations.reduce((c, p) => [...c, ...p.getRelations()], []);
+ }
+ on(ev, fn) {
+ this.relations.forEach(r => r.on(ev, fn));
+ }
+ off(ev, fn) {
+ this.relations.forEach(r => r.off(ev, fn));
+ }
+}
+exports.RelatedRelations = RelatedRelations;
+//# sourceMappingURL=related-relations.js.map \ No newline at end of file
diff --git a/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/related-relations.js.map b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/related-relations.js.map
new file mode 100644
index 0000000..5fb7a0c
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/related-relations.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"related-relations.js","names":["RelatedRelations","constructor","relations","_defineProperty2","default","filter","r","getRelations","reduce","c","p","on","ev","fn","forEach","off","exports"],"sources":["../../src/models/related-relations.ts"],"sourcesContent":["/*\nCopyright 2022 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 { Relations, RelationsEvent, EventHandlerMap } from \"./relations\";\nimport { MatrixEvent } from \"./event\";\nimport { Listener } from \"./typed-event-emitter\";\n\nexport class RelatedRelations {\n private relations: Relations[];\n\n public constructor(relations: Relations[]) {\n this.relations = relations.filter((r) => !!r);\n }\n\n public getRelations(): MatrixEvent[] {\n return this.relations.reduce<MatrixEvent[]>((c, p) => [...c, ...p.getRelations()], []);\n }\n\n public on<T extends RelationsEvent>(ev: T, fn: Listener<RelationsEvent, EventHandlerMap, T>): void {\n this.relations.forEach((r) => r.on(ev, fn));\n }\n\n public off<T extends RelationsEvent>(ev: T, fn: Listener<RelationsEvent, EventHandlerMap, T>): void {\n this.relations.forEach((r) => r.off(ev, fn));\n }\n}\n"],"mappings":";;;;;;;;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAMO,MAAMA,gBAAgB,CAAC;EAGnBC,WAAWA,CAACC,SAAsB,EAAE;IAAA,IAAAC,gBAAA,CAAAC,OAAA;IACvC,IAAI,CAACF,SAAS,GAAGA,SAAS,CAACG,MAAM,CAAEC,CAAC,IAAK,CAAC,CAACA,CAAC,CAAC;EACjD;EAEOC,YAAYA,CAAA,EAAkB;IACjC,OAAO,IAAI,CAACL,SAAS,CAACM,MAAM,CAAgB,CAACC,CAAC,EAAEC,CAAC,KAAK,CAAC,GAAGD,CAAC,EAAE,GAAGC,CAAC,CAACH,YAAY,EAAE,CAAC,EAAE,EAAE,CAAC;EAC1F;EAEOI,EAAEA,CAA2BC,EAAK,EAAEC,EAAgD,EAAQ;IAC/F,IAAI,CAACX,SAAS,CAACY,OAAO,CAAER,CAAC,IAAKA,CAAC,CAACK,EAAE,CAACC,EAAE,EAAEC,EAAE,CAAC,CAAC;EAC/C;EAEOE,GAAGA,CAA2BH,EAAK,EAAEC,EAAgD,EAAQ;IAChG,IAAI,CAACX,SAAS,CAACY,OAAO,CAAER,CAAC,IAAKA,CAAC,CAACS,GAAG,CAACH,EAAE,EAAEC,EAAE,CAAC,CAAC;EAChD;AACJ;AAACG,OAAA,CAAAhB,gBAAA,GAAAA,gBAAA"} \ No newline at end of file
diff --git a/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/relations-container.d.ts b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/relations-container.d.ts
new file mode 100644
index 0000000..2b2c7ad
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/relations-container.d.ts
@@ -0,0 +1,44 @@
+import { Relations } from "./relations";
+import { EventType, RelationType } from "../@types/event";
+import { MatrixEvent } from "./event";
+import { EventTimelineSet } from "./event-timeline-set";
+import { MatrixClient } from "../client";
+import { Room } from "./room";
+export declare class RelationsContainer {
+ private readonly client;
+ private readonly room?;
+ private relations;
+ constructor(client: MatrixClient, room?: Room | undefined);
+ /**
+ * Get a collection of child events to a given event in this timeline set.
+ *
+ * @param eventId - The ID of the event that you'd like to access child events for.
+ * For example, with annotations, this would be the ID of the event being annotated.
+ * @param relationType - The type of relationship involved, such as "m.annotation", "m.reference", "m.replace", etc.
+ * @param eventType - The relation event's type, such as "m.reaction", etc.
+ * @throws If `eventId</code>, <code>relationType</code> or <code>eventType`
+ * are not valid.
+ *
+ * @returns
+ * A container for relation events or undefined if there are no relation events for
+ * the relationType.
+ */
+ getChildEventsForEvent(eventId: string, relationType: RelationType | string, eventType: EventType | string): Relations | undefined;
+ getAllChildEventsForEvent(parentEventId: string): MatrixEvent[];
+ /**
+ * Set an event as the target event if any Relations exist for it already.
+ * Child events can point to other child events as their parent, so this method may be
+ * called for events which are also logically child events.
+ *
+ * @param event - The event to check as relation target.
+ */
+ aggregateParentEvent(event: MatrixEvent): void;
+ /**
+ * Add relation events to the relevant relation collection.
+ *
+ * @param event - The new child event to be aggregated.
+ * @param timelineSet - The event timeline set within which to search for the related event if any.
+ */
+ aggregateChildEvent(event: MatrixEvent, timelineSet?: EventTimelineSet): void;
+}
+//# sourceMappingURL=relations-container.d.ts.map \ No newline at end of file
diff --git a/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/relations-container.d.ts.map b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/relations-container.d.ts.map
new file mode 100644
index 0000000..ebb8110
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/relations-container.d.ts.map
@@ -0,0 +1 @@
+{"version":3,"file":"relations-container.d.ts","sourceRoot":"","sources":["../../src/models/relations-container.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC1D,OAAO,EAAe,WAAW,EAAoB,MAAM,SAAS,CAAC;AACrE,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAE9B,qBAAa,kBAAkB;IAKR,OAAO,CAAC,QAAQ,CAAC,MAAM;IAAgB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC;IAFhF,OAAO,CAAC,SAAS,CAAqF;gBAElE,MAAM,EAAE,YAAY,EAAmB,IAAI,CAAC,kBAAM;IAEtF;;;;;;;;;;;;;OAaG;IACI,sBAAsB,CACzB,OAAO,EAAE,MAAM,EACf,YAAY,EAAE,YAAY,GAAG,MAAM,EACnC,SAAS,EAAE,SAAS,GAAG,MAAM,GAC9B,SAAS,GAAG,SAAS;IAIjB,yBAAyB,CAAC,aAAa,EAAE,MAAM,GAAG,WAAW,EAAE;IAYtE;;;;;;OAMG;IACI,oBAAoB,CAAC,KAAK,EAAE,WAAW,GAAG,IAAI;IAWrD;;;;;OAKG;IACI,mBAAmB,CAAC,KAAK,EAAE,WAAW,EAAE,WAAW,CAAC,EAAE,gBAAgB,GAAG,IAAI;CAyDvF"} \ No newline at end of file
diff --git a/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/relations-container.js b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/relations-container.js
new file mode 100644
index 0000000..ef516e3
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/relations-container.js
@@ -0,0 +1,141 @@
+"use strict";
+
+var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.RelationsContainer = void 0;
+var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
+var _relations = require("./relations");
+var _event = require("./event");
+/*
+Copyright 2022 The Matrix.org Foundation C.I.C.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+class RelationsContainer {
+ // A tree of objects to access a set of related children for an event, as in:
+ // this.relations.get(parentEventId).get(relationType).get(relationEventType)
+
+ constructor(client, room) {
+ this.client = client;
+ this.room = room;
+ (0, _defineProperty2.default)(this, "relations", new Map());
+ }
+
+ /**
+ * Get a collection of child events to a given event in this timeline set.
+ *
+ * @param eventId - The ID of the event that you'd like to access child events for.
+ * For example, with annotations, this would be the ID of the event being annotated.
+ * @param relationType - The type of relationship involved, such as "m.annotation", "m.reference", "m.replace", etc.
+ * @param eventType - The relation event's type, such as "m.reaction", etc.
+ * @throws If `eventId</code>, <code>relationType</code> or <code>eventType`
+ * are not valid.
+ *
+ * @returns
+ * A container for relation events or undefined if there are no relation events for
+ * the relationType.
+ */
+ getChildEventsForEvent(eventId, relationType, eventType) {
+ var _this$relations$get, _this$relations$get$g;
+ return (_this$relations$get = this.relations.get(eventId)) === null || _this$relations$get === void 0 ? void 0 : (_this$relations$get$g = _this$relations$get.get(relationType)) === null || _this$relations$get$g === void 0 ? void 0 : _this$relations$get$g.get(eventType);
+ }
+ getAllChildEventsForEvent(parentEventId) {
+ var _this$relations$get2;
+ const relationsForEvent = (_this$relations$get2 = this.relations.get(parentEventId)) !== null && _this$relations$get2 !== void 0 ? _this$relations$get2 : new Map();
+ const events = [];
+ for (const relationsRecord of relationsForEvent.values()) {
+ for (const relations of relationsRecord.values()) {
+ events.push(...relations.getRelations());
+ }
+ }
+ return events;
+ }
+
+ /**
+ * Set an event as the target event if any Relations exist for it already.
+ * Child events can point to other child events as their parent, so this method may be
+ * called for events which are also logically child events.
+ *
+ * @param event - The event to check as relation target.
+ */
+ aggregateParentEvent(event) {
+ const relationsForEvent = this.relations.get(event.getId());
+ if (!relationsForEvent) return;
+ for (const relationsWithRelType of relationsForEvent.values()) {
+ for (const relationsWithEventType of relationsWithRelType.values()) {
+ relationsWithEventType.setTargetEvent(event);
+ }
+ }
+ }
+
+ /**
+ * Add relation events to the relevant relation collection.
+ *
+ * @param event - The new child event to be aggregated.
+ * @param timelineSet - The event timeline set within which to search for the related event if any.
+ */
+ aggregateChildEvent(event, timelineSet) {
+ if (event.isRedacted() || event.status === _event.EventStatus.CANCELLED) {
+ return;
+ }
+ const relation = event.getRelation();
+ if (!relation) return;
+ const onEventDecrypted = () => {
+ if (event.isDecryptionFailure()) {
+ // This could for example happen if the encryption keys are not yet available.
+ // The event may still be decrypted later. Register the listener again.
+ event.once(_event.MatrixEventEvent.Decrypted, onEventDecrypted);
+ return;
+ }
+ this.aggregateChildEvent(event, timelineSet);
+ };
+
+ // If the event is currently encrypted, wait until it has been decrypted.
+ if (event.isBeingDecrypted() || event.shouldAttemptDecryption()) {
+ event.once(_event.MatrixEventEvent.Decrypted, onEventDecrypted);
+ return;
+ }
+ const {
+ event_id: relatesToEventId,
+ rel_type: relationType
+ } = relation;
+ const eventType = event.getType();
+ let relationsForEvent = this.relations.get(relatesToEventId);
+ if (!relationsForEvent) {
+ relationsForEvent = new Map();
+ this.relations.set(relatesToEventId, relationsForEvent);
+ }
+ let relationsWithRelType = relationsForEvent.get(relationType);
+ if (!relationsWithRelType) {
+ relationsWithRelType = new Map();
+ relationsForEvent.set(relationType, relationsWithRelType);
+ }
+ let relationsWithEventType = relationsWithRelType.get(eventType);
+ if (!relationsWithEventType) {
+ var _this$room, _ref, _timelineSet$findEven;
+ relationsWithEventType = new _relations.Relations(relationType, eventType, this.client);
+ relationsWithRelType.set(eventType, relationsWithEventType);
+ const room = (_this$room = this.room) !== null && _this$room !== void 0 ? _this$room : timelineSet === null || timelineSet === void 0 ? void 0 : timelineSet.room;
+ const relatesToEvent = (_ref = (_timelineSet$findEven = timelineSet === null || timelineSet === void 0 ? void 0 : timelineSet.findEventById(relatesToEventId)) !== null && _timelineSet$findEven !== void 0 ? _timelineSet$findEven : room === null || room === void 0 ? void 0 : room.findEventById(relatesToEventId)) !== null && _ref !== void 0 ? _ref : room === null || room === void 0 ? void 0 : room.getPendingEvent(relatesToEventId);
+ if (relatesToEvent) {
+ relationsWithEventType.setTargetEvent(relatesToEvent);
+ }
+ }
+ relationsWithEventType.addEvent(event);
+ }
+}
+exports.RelationsContainer = RelationsContainer;
+//# sourceMappingURL=relations-container.js.map \ No newline at end of file
diff --git a/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/relations-container.js.map b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/relations-container.js.map
new file mode 100644
index 0000000..b01767c
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/relations-container.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"relations-container.js","names":["_relations","require","_event","RelationsContainer","constructor","client","room","_defineProperty2","default","Map","getChildEventsForEvent","eventId","relationType","eventType","_this$relations$get","_this$relations$get$g","relations","get","getAllChildEventsForEvent","parentEventId","_this$relations$get2","relationsForEvent","events","relationsRecord","values","push","getRelations","aggregateParentEvent","event","getId","relationsWithRelType","relationsWithEventType","setTargetEvent","aggregateChildEvent","timelineSet","isRedacted","status","EventStatus","CANCELLED","relation","getRelation","onEventDecrypted","isDecryptionFailure","once","MatrixEventEvent","Decrypted","isBeingDecrypted","shouldAttemptDecryption","event_id","relatesToEventId","rel_type","getType","set","_this$room","_ref","_timelineSet$findEven","Relations","relatesToEvent","findEventById","getPendingEvent","addEvent","exports"],"sources":["../../src/models/relations-container.ts"],"sourcesContent":["/*\nCopyright 2022 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 { Relations } from \"./relations\";\nimport { EventType, RelationType } from \"../@types/event\";\nimport { EventStatus, MatrixEvent, MatrixEventEvent } from \"./event\";\nimport { EventTimelineSet } from \"./event-timeline-set\";\nimport { MatrixClient } from \"../client\";\nimport { Room } from \"./room\";\n\nexport class RelationsContainer {\n // A tree of objects to access a set of related children for an event, as in:\n // this.relations.get(parentEventId).get(relationType).get(relationEventType)\n private relations = new Map<string, Map<RelationType | string, Map<EventType | string, Relations>>>();\n\n public constructor(private readonly client: MatrixClient, private readonly room?: Room) {}\n\n /**\n * Get a collection of child events to a given event in this timeline set.\n *\n * @param eventId - The ID of the event that you'd like to access child events for.\n * For example, with annotations, this would be the ID of the event being annotated.\n * @param relationType - The type of relationship involved, such as \"m.annotation\", \"m.reference\", \"m.replace\", etc.\n * @param eventType - The relation event's type, such as \"m.reaction\", etc.\n * @throws If `eventId</code>, <code>relationType</code> or <code>eventType`\n * are not valid.\n *\n * @returns\n * A container for relation events or undefined if there are no relation events for\n * the relationType.\n */\n public getChildEventsForEvent(\n eventId: string,\n relationType: RelationType | string,\n eventType: EventType | string,\n ): Relations | undefined {\n return this.relations.get(eventId)?.get(relationType)?.get(eventType);\n }\n\n public getAllChildEventsForEvent(parentEventId: string): MatrixEvent[] {\n const relationsForEvent =\n this.relations.get(parentEventId) ?? new Map<RelationType | string, Map<EventType | string, Relations>>();\n const events: MatrixEvent[] = [];\n for (const relationsRecord of relationsForEvent.values()) {\n for (const relations of relationsRecord.values()) {\n events.push(...relations.getRelations());\n }\n }\n return events;\n }\n\n /**\n * Set an event as the target event if any Relations exist for it already.\n * Child events can point to other child events as their parent, so this method may be\n * called for events which are also logically child events.\n *\n * @param event - The event to check as relation target.\n */\n public aggregateParentEvent(event: MatrixEvent): void {\n const relationsForEvent = this.relations.get(event.getId()!);\n if (!relationsForEvent) return;\n\n for (const relationsWithRelType of relationsForEvent.values()) {\n for (const relationsWithEventType of relationsWithRelType.values()) {\n relationsWithEventType.setTargetEvent(event);\n }\n }\n }\n\n /**\n * Add relation events to the relevant relation collection.\n *\n * @param event - The new child event to be aggregated.\n * @param timelineSet - The event timeline set within which to search for the related event if any.\n */\n public aggregateChildEvent(event: MatrixEvent, timelineSet?: EventTimelineSet): void {\n if (event.isRedacted() || event.status === EventStatus.CANCELLED) {\n return;\n }\n\n const relation = event.getRelation();\n if (!relation) return;\n\n const onEventDecrypted = (): void => {\n if (event.isDecryptionFailure()) {\n // This could for example happen if the encryption keys are not yet available.\n // The event may still be decrypted later. Register the listener again.\n event.once(MatrixEventEvent.Decrypted, onEventDecrypted);\n return;\n }\n\n this.aggregateChildEvent(event, timelineSet);\n };\n\n // If the event is currently encrypted, wait until it has been decrypted.\n if (event.isBeingDecrypted() || event.shouldAttemptDecryption()) {\n event.once(MatrixEventEvent.Decrypted, onEventDecrypted);\n return;\n }\n\n const { event_id: relatesToEventId, rel_type: relationType } = relation;\n const eventType = event.getType();\n\n let relationsForEvent = this.relations.get(relatesToEventId!);\n if (!relationsForEvent) {\n relationsForEvent = new Map<RelationType | string, Map<EventType | string, Relations>>();\n this.relations.set(relatesToEventId!, relationsForEvent);\n }\n\n let relationsWithRelType = relationsForEvent.get(relationType!);\n if (!relationsWithRelType) {\n relationsWithRelType = new Map<EventType | string, Relations>();\n relationsForEvent.set(relationType!, relationsWithRelType);\n }\n\n let relationsWithEventType = relationsWithRelType.get(eventType);\n if (!relationsWithEventType) {\n relationsWithEventType = new Relations(relationType!, eventType, this.client);\n relationsWithRelType.set(eventType, relationsWithEventType);\n\n const room = this.room ?? timelineSet?.room;\n const relatesToEvent =\n timelineSet?.findEventById(relatesToEventId!) ??\n room?.findEventById(relatesToEventId!) ??\n room?.getPendingEvent(relatesToEventId!);\n if (relatesToEvent) {\n relationsWithEventType.setTargetEvent(relatesToEvent);\n }\n }\n\n relationsWithEventType.addEvent(event);\n }\n}\n"],"mappings":"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"} \ No newline at end of file
diff --git a/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/relations.d.ts b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/relations.d.ts
new file mode 100644
index 0000000..e99d3b4
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/relations.d.ts
@@ -0,0 +1,114 @@
+import { MatrixEvent } from "./event";
+import { RelationType } from "../@types/event";
+import { TypedEventEmitter } from "./typed-event-emitter";
+import { MatrixClient } from "../client";
+import { Room } from "./room";
+export declare enum RelationsEvent {
+ Add = "Relations.add",
+ Remove = "Relations.remove",
+ Redaction = "Relations.redaction"
+}
+export type EventHandlerMap = {
+ [RelationsEvent.Add]: (event: MatrixEvent) => void;
+ [RelationsEvent.Remove]: (event: MatrixEvent) => void;
+ [RelationsEvent.Redaction]: (event: MatrixEvent) => void;
+};
+/**
+ * A container for relation events that supports easy access to common ways of
+ * aggregating such events. Each instance holds events that of a single relation
+ * type and event type. All of the events also relate to the same original event.
+ *
+ * The typical way to get one of these containers is via
+ * EventTimelineSet#getRelationsForEvent.
+ */
+export declare class Relations extends TypedEventEmitter<RelationsEvent, EventHandlerMap> {
+ readonly relationType: RelationType | string;
+ readonly eventType: string;
+ readonly altEventTypes?: string[] | undefined;
+ private relationEventIds;
+ private relations;
+ private annotationsByKey;
+ private annotationsBySender;
+ private sortedAnnotationsByKey;
+ private targetEvent;
+ private creationEmitted;
+ private readonly client;
+ /**
+ * @param relationType - The type of relation involved, such as "m.annotation", "m.reference", "m.replace", etc.
+ * @param eventType - The relation event's type, such as "m.reaction", etc.
+ * @param client - The client which created this instance. For backwards compatibility also accepts a Room.
+ * @param altEventTypes - alt event types for relation events, for example to support unstable prefixed event types
+ */
+ constructor(relationType: RelationType | string, eventType: string, client: MatrixClient | Room, altEventTypes?: string[] | undefined);
+ /**
+ * Add relation events to this collection.
+ *
+ * @param event - The new relation event to be added.
+ */
+ addEvent(event: MatrixEvent): Promise<void>;
+ /**
+ * Remove relation event from this collection.
+ *
+ * @param event - The relation event to remove.
+ */
+ removeEvent(event: MatrixEvent): Promise<void>;
+ /**
+ * Listens for event status changes to remove cancelled events.
+ *
+ * @param event - The event whose status has changed
+ * @param status - The new status
+ */
+ private onEventStatus;
+ /**
+ * Get all relation events in this collection.
+ *
+ * These are currently in the order of insertion to this collection, which
+ * won't match timeline order in the case of scrollback.
+ * TODO: Tweak `addEvent` to insert correctly for scrollback.
+ *
+ * Relation events in insertion order.
+ */
+ getRelations(): MatrixEvent[];
+ private addAnnotationToAggregation;
+ private removeAnnotationFromAggregation;
+ /**
+ * For relations that have been redacted, we want to remove them from
+ * aggregation data sets and emit an update event.
+ *
+ * To do so, we listen for `Event.beforeRedaction`, which happens:
+ * - after the server accepted the redaction and remote echoed back to us
+ * - before the original event has been marked redacted in the client
+ *
+ * @param redactedEvent - The original relation event that is about to be redacted.
+ */
+ private onBeforeRedaction;
+ /**
+ * Get all events in this collection grouped by key and sorted by descending
+ * event count in each group.
+ *
+ * This is currently only supported for the annotation relation type.
+ *
+ * An array of [key, events] pairs sorted by descending event count.
+ * The events are stored in a Set (which preserves insertion order).
+ */
+ getSortedAnnotationsByKey(): [string, Set<MatrixEvent>][] | null;
+ /**
+ * Get all events in this collection grouped by sender.
+ *
+ * This is currently only supported for the annotation relation type.
+ *
+ * An object with each relation sender as a key and the matching Set of
+ * events for that sender as a value.
+ */
+ getAnnotationsBySender(): Record<string, Set<MatrixEvent>> | null;
+ /**
+ * Returns the most recent (and allowed) m.replace relation, if any.
+ *
+ * This is currently only supported for the m.replace relation type,
+ * once the target event is known, see `addEvent`.
+ */
+ getLastReplacement(): Promise<MatrixEvent | null>;
+ setTargetEvent(event: MatrixEvent): Promise<void>;
+ private maybeEmitCreated;
+}
+//# sourceMappingURL=relations.d.ts.map \ No newline at end of file
diff --git a/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/relations.d.ts.map b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/relations.d.ts.map
new file mode 100644
index 0000000..356f7c0
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/relations.d.ts.map
@@ -0,0 +1 @@
+{"version":3,"file":"relations.d.ts","sourceRoot":"","sources":["../../src/models/relations.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAoC,WAAW,EAAoB,MAAM,SAAS,CAAC;AAE1F,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAE9B,oBAAY,cAAc;IACtB,GAAG,kBAAkB;IACrB,MAAM,qBAAqB;IAC3B,SAAS,wBAAwB;CACpC;AAED,MAAM,MAAM,eAAe,GAAG;IAC1B,CAAC,cAAc,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,CAAC;IACnD,CAAC,cAAc,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,CAAC;IACtD,CAAC,cAAc,CAAC,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,CAAC;CAC5D,CAAC;AAKF;;;;;;;GAOG;AACH,qBAAa,SAAU,SAAQ,iBAAiB,CAAC,cAAc,EAAE,eAAe,CAAC;aAiBzD,YAAY,EAAE,YAAY,GAAG,MAAM;aACnC,SAAS,EAAE,MAAM;aAEjB,aAAa,CAAC;IAnBlC,OAAO,CAAC,gBAAgB,CAAqB;IAC7C,OAAO,CAAC,SAAS,CAA0B;IAC3C,OAAO,CAAC,gBAAgB,CAAwC;IAChE,OAAO,CAAC,mBAAmB,CAAwC;IACnE,OAAO,CAAC,sBAAsB,CAAoC;IAClE,OAAO,CAAC,WAAW,CAA4B;IAC/C,OAAO,CAAC,eAAe,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAe;IAEtC;;;;;OAKG;gBAEiB,YAAY,EAAE,YAAY,GAAG,MAAM,EACnC,SAAS,EAAE,MAAM,EACjC,MAAM,EAAE,YAAY,GAAG,IAAI,EACX,aAAa,CAAC,sBAAU;IAM5C;;;;OAIG;IACU,QAAQ,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IA0CxD;;;;OAIG;IACU,WAAW,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAiB3D;;;;;OAKG;IACH,OAAO,CAAC,aAAa,CAYnB;IAEF;;;;;;;;OAQG;IACI,YAAY,IAAI,WAAW,EAAE;IAIpC,OAAO,CAAC,0BAA0B;IA2BlC,OAAO,CAAC,+BAA+B;IAuBvC;;;;;;;;;OASG;IACH,OAAO,CAAC,iBAAiB,CAkBvB;IAEF;;;;;;;;OAQG;IACI,yBAAyB,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC,WAAW,CAAC,CAAC,EAAE,GAAG,IAAI;IASvE;;;;;;;OAOG;IACI,sBAAsB,IAAI,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,WAAW,CAAC,CAAC,GAAG,IAAI;IASxE;;;;;OAKG;IACU,kBAAkB,IAAI,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IA0CjD,cAAc,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAkB9D,OAAO,CAAC,gBAAgB;CAY3B"} \ No newline at end of file
diff --git a/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/relations.js b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/relations.js
new file mode 100644
index 0000000..238d6c1
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/relations.js
@@ -0,0 +1,343 @@
+"use strict";
+
+var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.RelationsEvent = exports.Relations = void 0;
+var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
+var _event = require("./event");
+var _logger = require("../logger");
+var _event2 = require("../@types/event");
+var _typedEventEmitter = require("./typed-event-emitter");
+var _room = require("./room");
+/*
+Copyright 2019, 2021, 2023 The Matrix.org Foundation C.I.C.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+let RelationsEvent;
+exports.RelationsEvent = RelationsEvent;
+(function (RelationsEvent) {
+ RelationsEvent["Add"] = "Relations.add";
+ RelationsEvent["Remove"] = "Relations.remove";
+ RelationsEvent["Redaction"] = "Relations.redaction";
+})(RelationsEvent || (exports.RelationsEvent = RelationsEvent = {}));
+const matchesEventType = (eventType, targetEventType, altTargetEventTypes = []) => [targetEventType, ...altTargetEventTypes].includes(eventType);
+
+/**
+ * A container for relation events that supports easy access to common ways of
+ * aggregating such events. Each instance holds events that of a single relation
+ * type and event type. All of the events also relate to the same original event.
+ *
+ * The typical way to get one of these containers is via
+ * EventTimelineSet#getRelationsForEvent.
+ */
+class Relations extends _typedEventEmitter.TypedEventEmitter {
+ /**
+ * @param relationType - The type of relation involved, such as "m.annotation", "m.reference", "m.replace", etc.
+ * @param eventType - The relation event's type, such as "m.reaction", etc.
+ * @param client - The client which created this instance. For backwards compatibility also accepts a Room.
+ * @param altEventTypes - alt event types for relation events, for example to support unstable prefixed event types
+ */
+ constructor(relationType, eventType, client, altEventTypes) {
+ super();
+ this.relationType = relationType;
+ this.eventType = eventType;
+ this.altEventTypes = altEventTypes;
+ (0, _defineProperty2.default)(this, "relationEventIds", new Set());
+ (0, _defineProperty2.default)(this, "relations", new Set());
+ (0, _defineProperty2.default)(this, "annotationsByKey", {});
+ (0, _defineProperty2.default)(this, "annotationsBySender", {});
+ (0, _defineProperty2.default)(this, "sortedAnnotationsByKey", []);
+ (0, _defineProperty2.default)(this, "targetEvent", null);
+ (0, _defineProperty2.default)(this, "creationEmitted", false);
+ (0, _defineProperty2.default)(this, "client", void 0);
+ (0, _defineProperty2.default)(this, "onEventStatus", (event, status) => {
+ if (!event.isSending()) {
+ // Sending is done, so we don't need to listen anymore
+ event.removeListener(_event.MatrixEventEvent.Status, this.onEventStatus);
+ return;
+ }
+ if (status !== _event.EventStatus.CANCELLED) {
+ return;
+ }
+ // Event was cancelled, remove from the collection
+ event.removeListener(_event.MatrixEventEvent.Status, this.onEventStatus);
+ this.removeEvent(event);
+ });
+ (0, _defineProperty2.default)(this, "onBeforeRedaction", async redactedEvent => {
+ if (!this.relations.has(redactedEvent)) {
+ return;
+ }
+ this.relations.delete(redactedEvent);
+ if (this.relationType === _event2.RelationType.Annotation) {
+ // Remove the redacted annotation from aggregation by key
+ this.removeAnnotationFromAggregation(redactedEvent);
+ } else if (this.relationType === _event2.RelationType.Replace && this.targetEvent && !this.targetEvent.isState()) {
+ const lastReplacement = await this.getLastReplacement();
+ this.targetEvent.makeReplaced(lastReplacement);
+ }
+ redactedEvent.removeListener(_event.MatrixEventEvent.BeforeRedaction, this.onBeforeRedaction);
+ this.emit(RelationsEvent.Redaction, redactedEvent);
+ });
+ this.client = client instanceof _room.Room ? client.client : client;
+ }
+
+ /**
+ * Add relation events to this collection.
+ *
+ * @param event - The new relation event to be added.
+ */
+ async addEvent(event) {
+ if (this.relationEventIds.has(event.getId())) {
+ return;
+ }
+ const relation = event.getRelation();
+ if (!relation) {
+ _logger.logger.error("Event must have relation info");
+ return;
+ }
+ const relationType = relation.rel_type;
+ const eventType = event.getType();
+ if (this.relationType !== relationType || !matchesEventType(eventType, this.eventType, this.altEventTypes)) {
+ _logger.logger.error("Event relation info doesn't match this container");
+ return;
+ }
+
+ // If the event is in the process of being sent, listen for cancellation
+ // so we can remove the event from the collection.
+ if (event.isSending()) {
+ event.on(_event.MatrixEventEvent.Status, this.onEventStatus);
+ }
+ this.relations.add(event);
+ this.relationEventIds.add(event.getId());
+ if (this.relationType === _event2.RelationType.Annotation) {
+ this.addAnnotationToAggregation(event);
+ } else if (this.relationType === _event2.RelationType.Replace && this.targetEvent && !this.targetEvent.isState()) {
+ const lastReplacement = await this.getLastReplacement();
+ this.targetEvent.makeReplaced(lastReplacement);
+ }
+ event.on(_event.MatrixEventEvent.BeforeRedaction, this.onBeforeRedaction);
+ this.emit(RelationsEvent.Add, event);
+ this.maybeEmitCreated();
+ }
+
+ /**
+ * Remove relation event from this collection.
+ *
+ * @param event - The relation event to remove.
+ */
+ async removeEvent(event) {
+ if (!this.relations.has(event)) {
+ return;
+ }
+ this.relations.delete(event);
+ if (this.relationType === _event2.RelationType.Annotation) {
+ this.removeAnnotationFromAggregation(event);
+ } else if (this.relationType === _event2.RelationType.Replace && this.targetEvent && !this.targetEvent.isState()) {
+ const lastReplacement = await this.getLastReplacement();
+ this.targetEvent.makeReplaced(lastReplacement);
+ }
+ this.emit(RelationsEvent.Remove, event);
+ }
+
+ /**
+ * Listens for event status changes to remove cancelled events.
+ *
+ * @param event - The event whose status has changed
+ * @param status - The new status
+ */
+
+ /**
+ * Get all relation events in this collection.
+ *
+ * These are currently in the order of insertion to this collection, which
+ * won't match timeline order in the case of scrollback.
+ * TODO: Tweak `addEvent` to insert correctly for scrollback.
+ *
+ * Relation events in insertion order.
+ */
+ getRelations() {
+ return [...this.relations];
+ }
+ addAnnotationToAggregation(event) {
+ var _event$getRelation;
+ const {
+ key
+ } = (_event$getRelation = event.getRelation()) !== null && _event$getRelation !== void 0 ? _event$getRelation : {};
+ if (!key) return;
+ let eventsForKey = this.annotationsByKey[key];
+ if (!eventsForKey) {
+ eventsForKey = this.annotationsByKey[key] = new Set();
+ this.sortedAnnotationsByKey.push([key, eventsForKey]);
+ }
+ // Add the new event to the set for this key
+ eventsForKey.add(event);
+ // Re-sort the [key, events] pairs in descending order of event count
+ this.sortedAnnotationsByKey.sort((a, b) => {
+ const aEvents = a[1];
+ const bEvents = b[1];
+ return bEvents.size - aEvents.size;
+ });
+ const sender = event.getSender();
+ let eventsFromSender = this.annotationsBySender[sender];
+ if (!eventsFromSender) {
+ eventsFromSender = this.annotationsBySender[sender] = new Set();
+ }
+ // Add the new event to the set for this sender
+ eventsFromSender.add(event);
+ }
+ removeAnnotationFromAggregation(event) {
+ var _event$getRelation2;
+ const {
+ key
+ } = (_event$getRelation2 = event.getRelation()) !== null && _event$getRelation2 !== void 0 ? _event$getRelation2 : {};
+ if (!key) return;
+ const eventsForKey = this.annotationsByKey[key];
+ if (eventsForKey) {
+ eventsForKey.delete(event);
+
+ // Re-sort the [key, events] pairs in descending order of event count
+ this.sortedAnnotationsByKey.sort((a, b) => {
+ const aEvents = a[1];
+ const bEvents = b[1];
+ return bEvents.size - aEvents.size;
+ });
+ }
+ const sender = event.getSender();
+ const eventsFromSender = this.annotationsBySender[sender];
+ if (eventsFromSender) {
+ eventsFromSender.delete(event);
+ }
+ }
+
+ /**
+ * For relations that have been redacted, we want to remove them from
+ * aggregation data sets and emit an update event.
+ *
+ * To do so, we listen for `Event.beforeRedaction`, which happens:
+ * - after the server accepted the redaction and remote echoed back to us
+ * - before the original event has been marked redacted in the client
+ *
+ * @param redactedEvent - The original relation event that is about to be redacted.
+ */
+
+ /**
+ * Get all events in this collection grouped by key and sorted by descending
+ * event count in each group.
+ *
+ * This is currently only supported for the annotation relation type.
+ *
+ * An array of [key, events] pairs sorted by descending event count.
+ * The events are stored in a Set (which preserves insertion order).
+ */
+ getSortedAnnotationsByKey() {
+ if (this.relationType !== _event2.RelationType.Annotation) {
+ // Other relation types are not grouped currently.
+ return null;
+ }
+ return this.sortedAnnotationsByKey;
+ }
+
+ /**
+ * Get all events in this collection grouped by sender.
+ *
+ * This is currently only supported for the annotation relation type.
+ *
+ * An object with each relation sender as a key and the matching Set of
+ * events for that sender as a value.
+ */
+ getAnnotationsBySender() {
+ if (this.relationType !== _event2.RelationType.Annotation) {
+ // Other relation types are not grouped currently.
+ return null;
+ }
+ return this.annotationsBySender;
+ }
+
+ /**
+ * Returns the most recent (and allowed) m.replace relation, if any.
+ *
+ * This is currently only supported for the m.replace relation type,
+ * once the target event is known, see `addEvent`.
+ */
+ async getLastReplacement() {
+ if (this.relationType !== _event2.RelationType.Replace) {
+ // Aggregating on last only makes sense for this relation type
+ return null;
+ }
+ if (!this.targetEvent) {
+ // Don't know which replacements to accept yet.
+ // This method shouldn't be called before the original
+ // event is known anyway.
+ return null;
+ }
+
+ // the all-knowning server tells us that the event at some point had
+ // this timestamp for its replacement, so any following replacement should definitely not be less
+ const replaceRelation = this.targetEvent.getServerAggregatedRelation(_event2.RelationType.Replace);
+ const minTs = replaceRelation === null || replaceRelation === void 0 ? void 0 : replaceRelation.origin_server_ts;
+ const lastReplacement = this.getRelations().reduce((last, event) => {
+ if (event.getSender() !== this.targetEvent.getSender()) {
+ return last;
+ }
+ if (minTs && minTs > event.getTs()) {
+ return last;
+ }
+ if (last && last.getTs() > event.getTs()) {
+ return last;
+ }
+ return event;
+ }, null);
+ if (lastReplacement !== null && lastReplacement !== void 0 && lastReplacement.shouldAttemptDecryption() && this.client.isCryptoEnabled()) {
+ await lastReplacement.attemptDecryption(this.client.crypto);
+ } else if (lastReplacement !== null && lastReplacement !== void 0 && lastReplacement.isBeingDecrypted()) {
+ await lastReplacement.getDecryptionPromise();
+ }
+ return lastReplacement;
+ }
+
+ /*
+ * @param targetEvent - the event the relations are related to.
+ */
+ async setTargetEvent(event) {
+ if (this.targetEvent) {
+ return;
+ }
+ this.targetEvent = event;
+ if (this.relationType === _event2.RelationType.Replace && !this.targetEvent.isState()) {
+ const replacement = await this.getLastReplacement();
+ // this is the initial update, so only call it if we already have something
+ // to not emit Event.replaced needlessly
+ if (replacement) {
+ this.targetEvent.makeReplaced(replacement);
+ }
+ }
+ this.maybeEmitCreated();
+ }
+ maybeEmitCreated() {
+ if (this.creationEmitted) {
+ return;
+ }
+ // Only emit we're "created" once we have a target event instance _and_
+ // at least one related event.
+ if (!this.targetEvent || !this.relations.size) {
+ return;
+ }
+ this.creationEmitted = true;
+ this.targetEvent.emit(_event.MatrixEventEvent.RelationsCreated, this.relationType, this.eventType);
+ }
+}
+exports.Relations = Relations;
+//# sourceMappingURL=relations.js.map \ No newline at end of file
diff --git a/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/relations.js.map b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/relations.js.map
new file mode 100644
index 0000000..eb8ec46
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/relations.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"relations.js","names":["_event","require","_logger","_event2","_typedEventEmitter","_room","RelationsEvent","exports","matchesEventType","eventType","targetEventType","altTargetEventTypes","includes","Relations","TypedEventEmitter","constructor","relationType","client","altEventTypes","_defineProperty2","default","Set","event","status","isSending","removeListener","MatrixEventEvent","Status","onEventStatus","EventStatus","CANCELLED","removeEvent","redactedEvent","relations","has","delete","RelationType","Annotation","removeAnnotationFromAggregation","Replace","targetEvent","isState","lastReplacement","getLastReplacement","makeReplaced","BeforeRedaction","onBeforeRedaction","emit","Redaction","Room","addEvent","relationEventIds","getId","relation","getRelation","logger","error","rel_type","getType","on","add","addAnnotationToAggregation","Add","maybeEmitCreated","Remove","getRelations","_event$getRelation","key","eventsForKey","annotationsByKey","sortedAnnotationsByKey","push","sort","a","b","aEvents","bEvents","size","sender","getSender","eventsFromSender","annotationsBySender","_event$getRelation2","getSortedAnnotationsByKey","getAnnotationsBySender","replaceRelation","getServerAggregatedRelation","minTs","origin_server_ts","reduce","last","getTs","shouldAttemptDecryption","isCryptoEnabled","attemptDecryption","crypto","isBeingDecrypted","getDecryptionPromise","setTargetEvent","replacement","creationEmitted","RelationsCreated"],"sources":["../../src/models/relations.ts"],"sourcesContent":["/*\nCopyright 2019, 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 { EventStatus, IAggregatedRelation, MatrixEvent, MatrixEventEvent } from \"./event\";\nimport { logger } from \"../logger\";\nimport { RelationType } from \"../@types/event\";\nimport { TypedEventEmitter } from \"./typed-event-emitter\";\nimport { MatrixClient } from \"../client\";\nimport { Room } from \"./room\";\n\nexport enum RelationsEvent {\n Add = \"Relations.add\",\n Remove = \"Relations.remove\",\n Redaction = \"Relations.redaction\",\n}\n\nexport type EventHandlerMap = {\n [RelationsEvent.Add]: (event: MatrixEvent) => void;\n [RelationsEvent.Remove]: (event: MatrixEvent) => void;\n [RelationsEvent.Redaction]: (event: MatrixEvent) => void;\n};\n\nconst matchesEventType = (eventType: string, targetEventType: string, altTargetEventTypes: string[] = []): boolean =>\n [targetEventType, ...altTargetEventTypes].includes(eventType);\n\n/**\n * A container for relation events that supports easy access to common ways of\n * aggregating such events. Each instance holds events that of a single relation\n * type and event type. All of the events also relate to the same original event.\n *\n * The typical way to get one of these containers is via\n * EventTimelineSet#getRelationsForEvent.\n */\nexport class Relations extends TypedEventEmitter<RelationsEvent, EventHandlerMap> {\n private relationEventIds = new Set<string>();\n private relations = new Set<MatrixEvent>();\n private annotationsByKey: Record<string, Set<MatrixEvent>> = {};\n private annotationsBySender: Record<string, Set<MatrixEvent>> = {};\n private sortedAnnotationsByKey: [string, Set<MatrixEvent>][] = [];\n private targetEvent: MatrixEvent | null = null;\n private creationEmitted = false;\n private readonly client: MatrixClient;\n\n /**\n * @param relationType - The type of relation involved, such as \"m.annotation\", \"m.reference\", \"m.replace\", etc.\n * @param eventType - The relation event's type, such as \"m.reaction\", etc.\n * @param client - The client which created this instance. For backwards compatibility also accepts a Room.\n * @param altEventTypes - alt event types for relation events, for example to support unstable prefixed event types\n */\n public constructor(\n public readonly relationType: RelationType | string,\n public readonly eventType: string,\n client: MatrixClient | Room,\n public readonly altEventTypes?: string[],\n ) {\n super();\n this.client = client instanceof Room ? client.client : client;\n }\n\n /**\n * Add relation events to this collection.\n *\n * @param event - The new relation event to be added.\n */\n public async addEvent(event: MatrixEvent): Promise<void> {\n if (this.relationEventIds.has(event.getId()!)) {\n return;\n }\n\n const relation = event.getRelation();\n if (!relation) {\n logger.error(\"Event must have relation info\");\n return;\n }\n\n const relationType = relation.rel_type;\n const eventType = event.getType();\n\n if (this.relationType !== relationType || !matchesEventType(eventType, this.eventType, this.altEventTypes)) {\n logger.error(\"Event relation info doesn't match this container\");\n return;\n }\n\n // If the event is in the process of being sent, listen for cancellation\n // so we can remove the event from the collection.\n if (event.isSending()) {\n event.on(MatrixEventEvent.Status, this.onEventStatus);\n }\n\n this.relations.add(event);\n this.relationEventIds.add(event.getId()!);\n\n if (this.relationType === RelationType.Annotation) {\n this.addAnnotationToAggregation(event);\n } else if (this.relationType === RelationType.Replace && this.targetEvent && !this.targetEvent.isState()) {\n const lastReplacement = await this.getLastReplacement();\n this.targetEvent.makeReplaced(lastReplacement!);\n }\n\n event.on(MatrixEventEvent.BeforeRedaction, this.onBeforeRedaction);\n\n this.emit(RelationsEvent.Add, event);\n\n this.maybeEmitCreated();\n }\n\n /**\n * Remove relation event from this collection.\n *\n * @param event - The relation event to remove.\n */\n public async removeEvent(event: MatrixEvent): Promise<void> {\n if (!this.relations.has(event)) {\n return;\n }\n\n this.relations.delete(event);\n\n if (this.relationType === RelationType.Annotation) {\n this.removeAnnotationFromAggregation(event);\n } else if (this.relationType === RelationType.Replace && this.targetEvent && !this.targetEvent.isState()) {\n const lastReplacement = await this.getLastReplacement();\n this.targetEvent.makeReplaced(lastReplacement!);\n }\n\n this.emit(RelationsEvent.Remove, event);\n }\n\n /**\n * Listens for event status changes to remove cancelled events.\n *\n * @param event - The event whose status has changed\n * @param status - The new status\n */\n private onEventStatus = (event: MatrixEvent, status: EventStatus | null): void => {\n if (!event.isSending()) {\n // Sending is done, so we don't need to listen anymore\n event.removeListener(MatrixEventEvent.Status, this.onEventStatus);\n return;\n }\n if (status !== EventStatus.CANCELLED) {\n return;\n }\n // Event was cancelled, remove from the collection\n event.removeListener(MatrixEventEvent.Status, this.onEventStatus);\n this.removeEvent(event);\n };\n\n /**\n * Get all relation events in this collection.\n *\n * These are currently in the order of insertion to this collection, which\n * won't match timeline order in the case of scrollback.\n * TODO: Tweak `addEvent` to insert correctly for scrollback.\n *\n * Relation events in insertion order.\n */\n public getRelations(): MatrixEvent[] {\n return [...this.relations];\n }\n\n private addAnnotationToAggregation(event: MatrixEvent): void {\n const { key } = event.getRelation() ?? {};\n if (!key) return;\n\n let eventsForKey = this.annotationsByKey[key];\n if (!eventsForKey) {\n eventsForKey = this.annotationsByKey[key] = new Set();\n this.sortedAnnotationsByKey.push([key, eventsForKey]);\n }\n // Add the new event to the set for this key\n eventsForKey.add(event);\n // Re-sort the [key, events] pairs in descending order of event count\n this.sortedAnnotationsByKey.sort((a, b) => {\n const aEvents = a[1];\n const bEvents = b[1];\n return bEvents.size - aEvents.size;\n });\n\n const sender = event.getSender()!;\n let eventsFromSender = this.annotationsBySender[sender];\n if (!eventsFromSender) {\n eventsFromSender = this.annotationsBySender[sender] = new Set();\n }\n // Add the new event to the set for this sender\n eventsFromSender.add(event);\n }\n\n private removeAnnotationFromAggregation(event: MatrixEvent): void {\n const { key } = event.getRelation() ?? {};\n if (!key) return;\n\n const eventsForKey = this.annotationsByKey[key];\n if (eventsForKey) {\n eventsForKey.delete(event);\n\n // Re-sort the [key, events] pairs in descending order of event count\n this.sortedAnnotationsByKey.sort((a, b) => {\n const aEvents = a[1];\n const bEvents = b[1];\n return bEvents.size - aEvents.size;\n });\n }\n\n const sender = event.getSender()!;\n const eventsFromSender = this.annotationsBySender[sender];\n if (eventsFromSender) {\n eventsFromSender.delete(event);\n }\n }\n\n /**\n * For relations that have been redacted, we want to remove them from\n * aggregation data sets and emit an update event.\n *\n * To do so, we listen for `Event.beforeRedaction`, which happens:\n * - after the server accepted the redaction and remote echoed back to us\n * - before the original event has been marked redacted in the client\n *\n * @param redactedEvent - The original relation event that is about to be redacted.\n */\n private onBeforeRedaction = async (redactedEvent: MatrixEvent): Promise<void> => {\n if (!this.relations.has(redactedEvent)) {\n return;\n }\n\n this.relations.delete(redactedEvent);\n\n if (this.relationType === RelationType.Annotation) {\n // Remove the redacted annotation from aggregation by key\n this.removeAnnotationFromAggregation(redactedEvent);\n } else if (this.relationType === RelationType.Replace && this.targetEvent && !this.targetEvent.isState()) {\n const lastReplacement = await this.getLastReplacement();\n this.targetEvent.makeReplaced(lastReplacement!);\n }\n\n redactedEvent.removeListener(MatrixEventEvent.BeforeRedaction, this.onBeforeRedaction);\n\n this.emit(RelationsEvent.Redaction, redactedEvent);\n };\n\n /**\n * Get all events in this collection grouped by key and sorted by descending\n * event count in each group.\n *\n * This is currently only supported for the annotation relation type.\n *\n * An array of [key, events] pairs sorted by descending event count.\n * The events are stored in a Set (which preserves insertion order).\n */\n public getSortedAnnotationsByKey(): [string, Set<MatrixEvent>][] | null {\n if (this.relationType !== RelationType.Annotation) {\n // Other relation types are not grouped currently.\n return null;\n }\n\n return this.sortedAnnotationsByKey;\n }\n\n /**\n * Get all events in this collection grouped by sender.\n *\n * This is currently only supported for the annotation relation type.\n *\n * An object with each relation sender as a key and the matching Set of\n * events for that sender as a value.\n */\n public getAnnotationsBySender(): Record<string, Set<MatrixEvent>> | null {\n if (this.relationType !== RelationType.Annotation) {\n // Other relation types are not grouped currently.\n return null;\n }\n\n return this.annotationsBySender;\n }\n\n /**\n * Returns the most recent (and allowed) m.replace relation, if any.\n *\n * This is currently only supported for the m.replace relation type,\n * once the target event is known, see `addEvent`.\n */\n public async getLastReplacement(): Promise<MatrixEvent | null> {\n if (this.relationType !== RelationType.Replace) {\n // Aggregating on last only makes sense for this relation type\n return null;\n }\n if (!this.targetEvent) {\n // Don't know which replacements to accept yet.\n // This method shouldn't be called before the original\n // event is known anyway.\n return null;\n }\n\n // the all-knowning server tells us that the event at some point had\n // this timestamp for its replacement, so any following replacement should definitely not be less\n const replaceRelation = this.targetEvent.getServerAggregatedRelation<IAggregatedRelation>(RelationType.Replace);\n const minTs = replaceRelation?.origin_server_ts;\n\n const lastReplacement = this.getRelations().reduce<MatrixEvent | null>((last, event) => {\n if (event.getSender() !== this.targetEvent!.getSender()) {\n return last;\n }\n if (minTs && minTs > event.getTs()) {\n return last;\n }\n if (last && last.getTs() > event.getTs()) {\n return last;\n }\n return event;\n }, null);\n\n if (lastReplacement?.shouldAttemptDecryption() && this.client.isCryptoEnabled()) {\n await lastReplacement.attemptDecryption(this.client.crypto!);\n } else if (lastReplacement?.isBeingDecrypted()) {\n await lastReplacement.getDecryptionPromise();\n }\n\n return lastReplacement;\n }\n\n /*\n * @param targetEvent - the event the relations are related to.\n */\n public async setTargetEvent(event: MatrixEvent): Promise<void> {\n if (this.targetEvent) {\n return;\n }\n this.targetEvent = event;\n\n if (this.relationType === RelationType.Replace && !this.targetEvent.isState()) {\n const replacement = await this.getLastReplacement();\n // this is the initial update, so only call it if we already have something\n // to not emit Event.replaced needlessly\n if (replacement) {\n this.targetEvent.makeReplaced(replacement);\n }\n }\n\n this.maybeEmitCreated();\n }\n\n private maybeEmitCreated(): void {\n if (this.creationEmitted) {\n return;\n }\n // Only emit we're \"created\" once we have a target event instance _and_\n // at least one related event.\n if (!this.targetEvent || !this.relations.size) {\n return;\n }\n this.creationEmitted = true;\n this.targetEvent.emit(MatrixEventEvent.RelationsCreated, this.relationType, this.eventType);\n }\n}\n"],"mappings":"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"} \ No newline at end of file
diff --git a/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/room-member.d.ts b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/room-member.d.ts
new file mode 100644
index 0000000..cfbd4c7
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/room-member.d.ts
@@ -0,0 +1,203 @@
+import { User } from "./user";
+import { MatrixEvent } from "./event";
+import { RoomState } from "./room-state";
+import { TypedEventEmitter } from "./typed-event-emitter";
+export declare enum RoomMemberEvent {
+ Membership = "RoomMember.membership",
+ Name = "RoomMember.name",
+ PowerLevel = "RoomMember.powerLevel",
+ Typing = "RoomMember.typing"
+}
+export type RoomMemberEventHandlerMap = {
+ /**
+ * Fires whenever any room member's membership state changes.
+ * @param event - The matrix event which caused this event to fire.
+ * @param member - The member whose RoomMember.membership changed.
+ * @param oldMembership - The previous membership state. Null if it's a new member.
+ * @example
+ * ```
+ * matrixClient.on("RoomMember.membership", function(event, member, oldMembership){
+ * var newState = member.membership;
+ * });
+ * ```
+ */
+ [RoomMemberEvent.Membership]: (event: MatrixEvent, member: RoomMember, oldMembership?: string) => void;
+ /**
+ * Fires whenever any room member's name changes.
+ * @param event - The matrix event which caused this event to fire.
+ * @param member - The member whose RoomMember.name changed.
+ * @param oldName - The previous name. Null if the member didn't have a name previously.
+ * @example
+ * ```
+ * matrixClient.on("RoomMember.name", function(event, member){
+ * var newName = member.name;
+ * });
+ * ```
+ */
+ [RoomMemberEvent.Name]: (event: MatrixEvent, member: RoomMember, oldName: string | null) => void;
+ /**
+ * Fires whenever any room member's power level changes.
+ * @param event - The matrix event which caused this event to fire.
+ * @param member - The member whose RoomMember.powerLevel changed.
+ * @example
+ * ```
+ * matrixClient.on("RoomMember.powerLevel", function(event, member){
+ * var newPowerLevel = member.powerLevel;
+ * var newNormPowerLevel = member.powerLevelNorm;
+ * });
+ * ```
+ */
+ [RoomMemberEvent.PowerLevel]: (event: MatrixEvent, member: RoomMember) => void;
+ /**
+ * Fires whenever any room member's typing state changes.
+ * @param event - The matrix event which caused this event to fire.
+ * @param member - The member whose RoomMember.typing changed.
+ * @example
+ * ```
+ * matrixClient.on("RoomMember.typing", function(event, member){
+ * var isTyping = member.typing;
+ * });
+ * ```
+ */
+ [RoomMemberEvent.Typing]: (event: MatrixEvent, member: RoomMember) => void;
+};
+export declare class RoomMember extends TypedEventEmitter<RoomMemberEvent, RoomMemberEventHandlerMap> {
+ readonly roomId: string;
+ readonly userId: string;
+ private _isOutOfBand;
+ private modified;
+ requestedProfileInfo: boolean;
+ /**
+ * True if the room member is currently typing.
+ */
+ typing: boolean;
+ /**
+ * The human-readable name for this room member. This will be
+ * disambiguated with a suffix of " (\@user_id:matrix.org)" if another member shares the
+ * same displayname.
+ */
+ name: string;
+ /**
+ * The ambiguous displayname of this room member.
+ */
+ rawDisplayName: string;
+ /**
+ * The power level for this room member.
+ */
+ powerLevel: number;
+ /**
+ * The normalised power level (0-100) for this room member.
+ */
+ powerLevelNorm: number;
+ /**
+ * The User object for this room member, if one exists.
+ */
+ user?: User;
+ /**
+ * The membership state for this room member e.g. 'join'.
+ */
+ membership?: string;
+ /**
+ * True if the member's name is disambiguated.
+ */
+ disambiguate: boolean;
+ /**
+ * The events describing this RoomMember.
+ */
+ events: {
+ /**
+ * The m.room.member event for this RoomMember.
+ */
+ member?: MatrixEvent;
+ };
+ /**
+ * Construct a new room member.
+ *
+ * @param roomId - The room ID of the member.
+ * @param userId - The user ID of the member.
+ */
+ constructor(roomId: string, userId: string);
+ /**
+ * Mark the member as coming from a channel that is not sync
+ */
+ markOutOfBand(): void;
+ /**
+ * @returns does the member come from a channel that is not sync?
+ * This is used to store the member seperately
+ * from the sync state so it available across browser sessions.
+ */
+ isOutOfBand(): boolean;
+ /**
+ * Update this room member's membership event. May fire "RoomMember.name" if
+ * this event updates this member's name.
+ * @param event - The `m.room.member` event
+ * @param roomState - Optional. The room state to take into account
+ * when calculating (e.g. for disambiguating users with the same name).
+ *
+ * @remarks
+ * Fires {@link RoomMemberEvent.Name}
+ * Fires {@link RoomMemberEvent.Membership}
+ */
+ setMembershipEvent(event: MatrixEvent, roomState?: RoomState): void;
+ /**
+ * Update this room member's power level event. May fire
+ * "RoomMember.powerLevel" if this event updates this member's power levels.
+ * @param powerLevelEvent - The `m.room.power_levels` event
+ *
+ * @remarks
+ * Fires {@link RoomMemberEvent.PowerLevel}
+ */
+ setPowerLevelEvent(powerLevelEvent: MatrixEvent): void;
+ /**
+ * Update this room member's typing event. May fire "RoomMember.typing" if
+ * this event changes this member's typing state.
+ * @param event - The typing event
+ *
+ * @remarks
+ * Fires {@link RoomMemberEvent.Typing}
+ */
+ setTypingEvent(event: MatrixEvent): void;
+ /**
+ * Update the last modified time to the current time.
+ */
+ private updateModifiedTime;
+ /**
+ * Get the timestamp when this RoomMember was last updated. This timestamp is
+ * updated when properties on this RoomMember are updated.
+ * It is updated <i>before</i> firing events.
+ * @returns The timestamp
+ */
+ getLastModifiedTime(): number;
+ isKicked(): boolean;
+ /**
+ * If this member was invited with the is_direct flag set, return
+ * the user that invited this member
+ * @returns user id of the inviter
+ */
+ getDMInviter(): string | undefined;
+ /**
+ * Get the avatar URL for a room member.
+ * @param baseUrl - The base homeserver URL See
+ * {@link MatrixClient#getHomeserverUrl}.
+ * @param width - The desired width of the thumbnail.
+ * @param height - The desired height of the thumbnail.
+ * @param resizeMethod - The thumbnail resize method to use, either
+ * "crop" or "scale".
+ * @param allowDefault - (optional) Passing false causes this method to
+ * return null if the user has no avatar image. Otherwise, a default image URL
+ * will be returned. Default: true. (Deprecated)
+ * @param allowDirectLinks - (optional) If true, the avatar URL will be
+ * returned even if it is a direct hyperlink rather than a matrix content URL.
+ * If false, any non-matrix content URLs will be ignored. Setting this option to
+ * true will expose URLs that, if fetched, will leak information about the user
+ * to anyone who they share a room with.
+ * @returns the avatar URL or null.
+ */
+ getAvatarUrl(baseUrl: string, width: number, height: number, resizeMethod: string, allowDefault: boolean | undefined, allowDirectLinks: boolean): string | null;
+ /**
+ * get the mxc avatar url, either from a state event, or from a lazily loaded member
+ * @returns the mxc avatar url
+ */
+ getMxcAvatarUrl(): string | undefined;
+}
+//# sourceMappingURL=room-member.d.ts.map \ No newline at end of file
diff --git a/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/room-member.d.ts.map b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/room-member.d.ts.map
new file mode 100644
index 0000000..e5267d0
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/room-member.d.ts.map
@@ -0,0 +1 @@
+{"version":3,"file":"room-member.d.ts","sourceRoot":"","sources":["../../src/models/room-member.ts"],"names":[],"mappings":"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"} \ No newline at end of file
diff --git a/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/room-member.js b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/room-member.js
new file mode 100644
index 0000000..6e8eb3f
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/room-member.js
@@ -0,0 +1,377 @@
+"use strict";
+
+var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.RoomMemberEvent = exports.RoomMember = void 0;
+var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
+var _contentRepo = require("../content-repo");
+var utils = _interopRequireWildcard(require("../utils"));
+var _logger = require("../logger");
+var _typedEventEmitter = require("./typed-event-emitter");
+var _event = require("../@types/event");
+function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
+function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
+/*
+Copyright 2015 - 2021 The Matrix.org Foundation C.I.C.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+let RoomMemberEvent;
+exports.RoomMemberEvent = RoomMemberEvent;
+(function (RoomMemberEvent) {
+ RoomMemberEvent["Membership"] = "RoomMember.membership";
+ RoomMemberEvent["Name"] = "RoomMember.name";
+ RoomMemberEvent["PowerLevel"] = "RoomMember.powerLevel";
+ RoomMemberEvent["Typing"] = "RoomMember.typing";
+})(RoomMemberEvent || (exports.RoomMemberEvent = RoomMemberEvent = {}));
+class RoomMember extends _typedEventEmitter.TypedEventEmitter {
+ // used by sync.ts
+
+ // XXX these should be read-only
+ /**
+ * True if the room member is currently typing.
+ */
+
+ /**
+ * The human-readable name for this room member. This will be
+ * disambiguated with a suffix of " (\@user_id:matrix.org)" if another member shares the
+ * same displayname.
+ */
+
+ /**
+ * The ambiguous displayname of this room member.
+ */
+
+ /**
+ * The power level for this room member.
+ */
+
+ /**
+ * The normalised power level (0-100) for this room member.
+ */
+
+ /**
+ * The User object for this room member, if one exists.
+ */
+
+ /**
+ * The membership state for this room member e.g. 'join'.
+ */
+
+ /**
+ * True if the member's name is disambiguated.
+ */
+
+ /**
+ * The events describing this RoomMember.
+ */
+
+ /**
+ * Construct a new room member.
+ *
+ * @param roomId - The room ID of the member.
+ * @param userId - The user ID of the member.
+ */
+ constructor(roomId, userId) {
+ super();
+ this.roomId = roomId;
+ this.userId = userId;
+ (0, _defineProperty2.default)(this, "_isOutOfBand", false);
+ (0, _defineProperty2.default)(this, "modified", -1);
+ (0, _defineProperty2.default)(this, "requestedProfileInfo", false);
+ (0, _defineProperty2.default)(this, "typing", false);
+ (0, _defineProperty2.default)(this, "name", void 0);
+ (0, _defineProperty2.default)(this, "rawDisplayName", void 0);
+ (0, _defineProperty2.default)(this, "powerLevel", 0);
+ (0, _defineProperty2.default)(this, "powerLevelNorm", 0);
+ (0, _defineProperty2.default)(this, "user", void 0);
+ (0, _defineProperty2.default)(this, "membership", void 0);
+ (0, _defineProperty2.default)(this, "disambiguate", false);
+ (0, _defineProperty2.default)(this, "events", {});
+ this.name = userId;
+ this.rawDisplayName = userId;
+ this.updateModifiedTime();
+ }
+
+ /**
+ * Mark the member as coming from a channel that is not sync
+ */
+ markOutOfBand() {
+ this._isOutOfBand = true;
+ }
+
+ /**
+ * @returns does the member come from a channel that is not sync?
+ * This is used to store the member seperately
+ * from the sync state so it available across browser sessions.
+ */
+ isOutOfBand() {
+ return this._isOutOfBand;
+ }
+
+ /**
+ * Update this room member's membership event. May fire "RoomMember.name" if
+ * this event updates this member's name.
+ * @param event - The `m.room.member` event
+ * @param roomState - Optional. The room state to take into account
+ * when calculating (e.g. for disambiguating users with the same name).
+ *
+ * @remarks
+ * Fires {@link RoomMemberEvent.Name}
+ * Fires {@link RoomMemberEvent.Membership}
+ */
+ setMembershipEvent(event, roomState) {
+ var _event$getDirectional, _event$getDirectional2;
+ const displayName = (_event$getDirectional = event.getDirectionalContent().displayname) !== null && _event$getDirectional !== void 0 ? _event$getDirectional : "";
+ if (event.getType() !== _event.EventType.RoomMember) {
+ return;
+ }
+ this._isOutOfBand = false;
+ this.events.member = event;
+ const oldMembership = this.membership;
+ this.membership = event.getDirectionalContent().membership;
+ if (this.membership === undefined) {
+ // logging to diagnose https://github.com/vector-im/element-web/issues/20962
+ // (logs event content, although only of membership events)
+ _logger.logger.trace(`membership event with membership undefined (forwardLooking: ${event.forwardLooking})!`, event.getContent(), `prevcontent is `, event.getPrevContent());
+ }
+ this.disambiguate = shouldDisambiguate(this.userId, displayName, roomState);
+ const oldName = this.name;
+ this.name = calculateDisplayName(this.userId, displayName, this.disambiguate);
+
+ // not quite raw: we strip direction override chars so it can safely be inserted into
+ // blocks of text without breaking the text direction
+ this.rawDisplayName = utils.removeDirectionOverrideChars((_event$getDirectional2 = event.getDirectionalContent().displayname) !== null && _event$getDirectional2 !== void 0 ? _event$getDirectional2 : "");
+ if (!this.rawDisplayName || !utils.removeHiddenChars(this.rawDisplayName)) {
+ this.rawDisplayName = this.userId;
+ }
+ if (oldMembership !== this.membership) {
+ this.updateModifiedTime();
+ this.emit(RoomMemberEvent.Membership, event, this, oldMembership);
+ }
+ if (oldName !== this.name) {
+ this.updateModifiedTime();
+ this.emit(RoomMemberEvent.Name, event, this, oldName);
+ }
+ }
+
+ /**
+ * Update this room member's power level event. May fire
+ * "RoomMember.powerLevel" if this event updates this member's power levels.
+ * @param powerLevelEvent - The `m.room.power_levels` event
+ *
+ * @remarks
+ * Fires {@link RoomMemberEvent.PowerLevel}
+ */
+ setPowerLevelEvent(powerLevelEvent) {
+ if (powerLevelEvent.getType() !== _event.EventType.RoomPowerLevels || powerLevelEvent.getStateKey() !== "") {
+ return;
+ }
+ const evContent = powerLevelEvent.getDirectionalContent();
+ let maxLevel = evContent.users_default || 0;
+ const users = evContent.users || {};
+ Object.values(users).forEach(lvl => {
+ maxLevel = Math.max(maxLevel, lvl);
+ });
+ const oldPowerLevel = this.powerLevel;
+ const oldPowerLevelNorm = this.powerLevelNorm;
+ if (users[this.userId] !== undefined && Number.isInteger(users[this.userId])) {
+ this.powerLevel = users[this.userId];
+ } else if (evContent.users_default !== undefined) {
+ this.powerLevel = evContent.users_default;
+ } else {
+ this.powerLevel = 0;
+ }
+ this.powerLevelNorm = 0;
+ if (maxLevel > 0) {
+ this.powerLevelNorm = this.powerLevel * 100 / maxLevel;
+ }
+
+ // emit for changes in powerLevelNorm as well (since the app will need to
+ // redraw everyone's level if the max has changed)
+ if (oldPowerLevel !== this.powerLevel || oldPowerLevelNorm !== this.powerLevelNorm) {
+ this.updateModifiedTime();
+ this.emit(RoomMemberEvent.PowerLevel, powerLevelEvent, this);
+ }
+ }
+
+ /**
+ * Update this room member's typing event. May fire "RoomMember.typing" if
+ * this event changes this member's typing state.
+ * @param event - The typing event
+ *
+ * @remarks
+ * Fires {@link RoomMemberEvent.Typing}
+ */
+ setTypingEvent(event) {
+ if (event.getType() !== "m.typing") {
+ return;
+ }
+ const oldTyping = this.typing;
+ this.typing = false;
+ const typingList = event.getContent().user_ids;
+ if (!Array.isArray(typingList)) {
+ // malformed event :/ bail early. TODO: whine?
+ return;
+ }
+ if (typingList.indexOf(this.userId) !== -1) {
+ this.typing = true;
+ }
+ if (oldTyping !== this.typing) {
+ this.updateModifiedTime();
+ this.emit(RoomMemberEvent.Typing, event, this);
+ }
+ }
+
+ /**
+ * Update the last modified time to the current time.
+ */
+ updateModifiedTime() {
+ this.modified = Date.now();
+ }
+
+ /**
+ * Get the timestamp when this RoomMember was last updated. This timestamp is
+ * updated when properties on this RoomMember are updated.
+ * It is updated <i>before</i> firing events.
+ * @returns The timestamp
+ */
+ getLastModifiedTime() {
+ return this.modified;
+ }
+ isKicked() {
+ return this.membership === "leave" && this.events.member !== undefined && this.events.member.getSender() !== this.events.member.getStateKey();
+ }
+
+ /**
+ * If this member was invited with the is_direct flag set, return
+ * the user that invited this member
+ * @returns user id of the inviter
+ */
+ getDMInviter() {
+ // when not available because that room state hasn't been loaded in,
+ // we don't really know, but more likely to not be a direct chat
+ if (this.events.member) {
+ // TODO: persist the is_direct flag on the member as more member events
+ // come in caused by displayName changes.
+
+ // the is_direct flag is set on the invite member event.
+ // This is copied on the prev_content section of the join member event
+ // when the invite is accepted.
+
+ const memberEvent = this.events.member;
+ let memberContent = memberEvent.getContent();
+ let inviteSender = memberEvent.getSender();
+ if (memberContent.membership === "join") {
+ memberContent = memberEvent.getPrevContent();
+ inviteSender = memberEvent.getUnsigned().prev_sender;
+ }
+ if (memberContent.membership === "invite" && memberContent.is_direct) {
+ return inviteSender;
+ }
+ }
+ }
+
+ /**
+ * Get the avatar URL for a room member.
+ * @param baseUrl - The base homeserver URL See
+ * {@link MatrixClient#getHomeserverUrl}.
+ * @param width - The desired width of the thumbnail.
+ * @param height - The desired height of the thumbnail.
+ * @param resizeMethod - The thumbnail resize method to use, either
+ * "crop" or "scale".
+ * @param allowDefault - (optional) Passing false causes this method to
+ * return null if the user has no avatar image. Otherwise, a default image URL
+ * will be returned. Default: true. (Deprecated)
+ * @param allowDirectLinks - (optional) If true, the avatar URL will be
+ * returned even if it is a direct hyperlink rather than a matrix content URL.
+ * If false, any non-matrix content URLs will be ignored. Setting this option to
+ * true will expose URLs that, if fetched, will leak information about the user
+ * to anyone who they share a room with.
+ * @returns the avatar URL or null.
+ */
+ getAvatarUrl(baseUrl, width, height, resizeMethod, allowDefault = true, allowDirectLinks) {
+ const rawUrl = this.getMxcAvatarUrl();
+ if (!rawUrl && !allowDefault) {
+ return null;
+ }
+ const httpUrl = (0, _contentRepo.getHttpUriForMxc)(baseUrl, rawUrl, width, height, resizeMethod, allowDirectLinks);
+ if (httpUrl) {
+ return httpUrl;
+ }
+ return null;
+ }
+
+ /**
+ * get the mxc avatar url, either from a state event, or from a lazily loaded member
+ * @returns the mxc avatar url
+ */
+ getMxcAvatarUrl() {
+ if (this.events.member) {
+ return this.events.member.getDirectionalContent().avatar_url;
+ } else if (this.user) {
+ return this.user.avatarUrl;
+ }
+ }
+}
+exports.RoomMember = RoomMember;
+const MXID_PATTERN = /@.+:.+/;
+const LTR_RTL_PATTERN = /[\u200E\u200F\u202A-\u202F]/;
+function shouldDisambiguate(selfUserId, displayName, roomState) {
+ if (!displayName || displayName === selfUserId) return false;
+
+ // First check if the displayname is something we consider truthy
+ // after stripping it of zero width characters and padding spaces
+ if (!utils.removeHiddenChars(displayName)) return false;
+ if (!roomState) return false;
+
+ // Next check if the name contains something that look like a mxid
+ // If it does, it may be someone trying to impersonate someone else
+ // Show full mxid in this case
+ if (MXID_PATTERN.test(displayName)) return true;
+
+ // Also show mxid if the display name contains any LTR/RTL characters as these
+ // make it very difficult for us to find similar *looking* display names
+ // E.g "Mark" could be cloned by writing "kraM" but in RTL.
+ if (LTR_RTL_PATTERN.test(displayName)) return true;
+
+ // Also show mxid if there are other people with the same or similar
+ // displayname, after hidden character removal.
+ const userIds = roomState.getUserIdsWithDisplayName(displayName);
+ if (userIds.some(u => u !== selfUserId)) return true;
+ return false;
+}
+function calculateDisplayName(selfUserId, displayName, disambiguate) {
+ if (!displayName || displayName === selfUserId) return selfUserId;
+ if (disambiguate) return utils.removeDirectionOverrideChars(displayName) + " (" + selfUserId + ")";
+
+ // First check if the displayname is something we consider truthy
+ // after stripping it of zero width characters and padding spaces
+ if (!utils.removeHiddenChars(displayName)) return selfUserId;
+
+ // We always strip the direction override characters (LRO and RLO).
+ // These override the text direction for all subsequent characters
+ // in the paragraph so if display names contained these, they'd
+ // need to be wrapped in something to prevent this from leaking out
+ // (which we can do in HTML but not text) or we'd need to add
+ // control characters to the string to reset any overrides (eg.
+ // adding PDF characters at the end). As far as we can see,
+ // there should be no reason these would be necessary - rtl display
+ // names should flip into the correct direction automatically based on
+ // the characters, and you can still embed rtl in ltr or vice versa
+ // with the embed chars or marker chars.
+ return utils.removeDirectionOverrideChars(displayName);
+}
+//# sourceMappingURL=room-member.js.map \ No newline at end of file
diff --git a/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/room-member.js.map b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/room-member.js.map
new file mode 100644
index 0000000..003ae8a
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/room-member.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"room-member.js","names":["_contentRepo","require","utils","_interopRequireWildcard","_logger","_typedEventEmitter","_event","_getRequireWildcardCache","nodeInterop","WeakMap","cacheBabelInterop","cacheNodeInterop","obj","__esModule","default","cache","has","get","newObj","hasPropertyDescriptor","Object","defineProperty","getOwnPropertyDescriptor","key","prototype","hasOwnProperty","call","desc","set","RoomMemberEvent","exports","RoomMember","TypedEventEmitter","constructor","roomId","userId","_defineProperty2","name","rawDisplayName","updateModifiedTime","markOutOfBand","_isOutOfBand","isOutOfBand","setMembershipEvent","event","roomState","_event$getDirectional","_event$getDirectional2","displayName","getDirectionalContent","displayname","getType","EventType","events","member","oldMembership","membership","undefined","logger","trace","forwardLooking","getContent","getPrevContent","disambiguate","shouldDisambiguate","oldName","calculateDisplayName","removeDirectionOverrideChars","removeHiddenChars","emit","Membership","Name","setPowerLevelEvent","powerLevelEvent","RoomPowerLevels","getStateKey","evContent","maxLevel","users_default","users","values","forEach","lvl","Math","max","oldPowerLevel","powerLevel","oldPowerLevelNorm","powerLevelNorm","Number","isInteger","PowerLevel","setTypingEvent","oldTyping","typing","typingList","user_ids","Array","isArray","indexOf","Typing","modified","Date","now","getLastModifiedTime","isKicked","getSender","getDMInviter","memberEvent","memberContent","inviteSender","getUnsigned","prev_sender","is_direct","getAvatarUrl","baseUrl","width","height","resizeMethod","allowDefault","allowDirectLinks","rawUrl","getMxcAvatarUrl","httpUrl","getHttpUriForMxc","avatar_url","user","avatarUrl","MXID_PATTERN","LTR_RTL_PATTERN","selfUserId","test","userIds","getUserIdsWithDisplayName","some","u"],"sources":["../../src/models/room-member.ts"],"sourcesContent":["/*\nCopyright 2015 - 2021 The Matrix.org Foundation C.I.C.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n*/\n\nimport { getHttpUriForMxc } from \"../content-repo\";\nimport * as utils from \"../utils\";\nimport { User } from \"./user\";\nimport { MatrixEvent } from \"./event\";\nimport { RoomState } from \"./room-state\";\nimport { logger } from \"../logger\";\nimport { TypedEventEmitter } from \"./typed-event-emitter\";\nimport { EventType } from \"../@types/event\";\n\nexport enum RoomMemberEvent {\n Membership = \"RoomMember.membership\",\n Name = \"RoomMember.name\",\n PowerLevel = \"RoomMember.powerLevel\",\n Typing = \"RoomMember.typing\",\n}\n\nexport type RoomMemberEventHandlerMap = {\n /**\n * Fires whenever any room member's membership state changes.\n * @param event - The matrix event which caused this event to fire.\n * @param member - The member whose RoomMember.membership changed.\n * @param oldMembership - The previous membership state. Null if it's a new member.\n * @example\n * ```\n * matrixClient.on(\"RoomMember.membership\", function(event, member, oldMembership){\n * var newState = member.membership;\n * });\n * ```\n */\n [RoomMemberEvent.Membership]: (event: MatrixEvent, member: RoomMember, oldMembership?: string) => void;\n /**\n * Fires whenever any room member's name changes.\n * @param event - The matrix event which caused this event to fire.\n * @param member - The member whose RoomMember.name changed.\n * @param oldName - The previous name. Null if the member didn't have a name previously.\n * @example\n * ```\n * matrixClient.on(\"RoomMember.name\", function(event, member){\n * var newName = member.name;\n * });\n * ```\n */\n [RoomMemberEvent.Name]: (event: MatrixEvent, member: RoomMember, oldName: string | null) => void;\n /**\n * Fires whenever any room member's power level changes.\n * @param event - The matrix event which caused this event to fire.\n * @param member - The member whose RoomMember.powerLevel changed.\n * @example\n * ```\n * matrixClient.on(\"RoomMember.powerLevel\", function(event, member){\n * var newPowerLevel = member.powerLevel;\n * var newNormPowerLevel = member.powerLevelNorm;\n * });\n * ```\n */\n [RoomMemberEvent.PowerLevel]: (event: MatrixEvent, member: RoomMember) => void;\n /**\n * Fires whenever any room member's typing state changes.\n * @param event - The matrix event which caused this event to fire.\n * @param member - The member whose RoomMember.typing changed.\n * @example\n * ```\n * matrixClient.on(\"RoomMember.typing\", function(event, member){\n * var isTyping = member.typing;\n * });\n * ```\n */\n [RoomMemberEvent.Typing]: (event: MatrixEvent, member: RoomMember) => void;\n};\n\nexport class RoomMember extends TypedEventEmitter<RoomMemberEvent, RoomMemberEventHandlerMap> {\n private _isOutOfBand = false;\n private modified = -1;\n public requestedProfileInfo = false; // used by sync.ts\n\n // XXX these should be read-only\n /**\n * True if the room member is currently typing.\n */\n public typing = false;\n /**\n * The human-readable name for this room member. This will be\n * disambiguated with a suffix of \" (\\@user_id:matrix.org)\" if another member shares the\n * same displayname.\n */\n public name: string;\n /**\n * The ambiguous displayname of this room member.\n */\n public rawDisplayName: string;\n /**\n * The power level for this room member.\n */\n public powerLevel = 0;\n /**\n * The normalised power level (0-100) for this room member.\n */\n public powerLevelNorm = 0;\n /**\n * The User object for this room member, if one exists.\n */\n public user?: User;\n /**\n * The membership state for this room member e.g. 'join'.\n */\n public membership?: string;\n /**\n * True if the member's name is disambiguated.\n */\n public disambiguate = false;\n /**\n * The events describing this RoomMember.\n */\n public events: {\n /**\n * The m.room.member event for this RoomMember.\n */\n member?: MatrixEvent;\n } = {};\n\n /**\n * Construct a new room member.\n *\n * @param roomId - The room ID of the member.\n * @param userId - The user ID of the member.\n */\n public constructor(public readonly roomId: string, public readonly userId: string) {\n super();\n\n this.name = userId;\n this.rawDisplayName = userId;\n this.updateModifiedTime();\n }\n\n /**\n * Mark the member as coming from a channel that is not sync\n */\n public markOutOfBand(): void {\n this._isOutOfBand = true;\n }\n\n /**\n * @returns does the member come from a channel that is not sync?\n * This is used to store the member seperately\n * from the sync state so it available across browser sessions.\n */\n public isOutOfBand(): boolean {\n return this._isOutOfBand;\n }\n\n /**\n * Update this room member's membership event. May fire \"RoomMember.name\" if\n * this event updates this member's name.\n * @param event - The `m.room.member` event\n * @param roomState - Optional. The room state to take into account\n * when calculating (e.g. for disambiguating users with the same name).\n *\n * @remarks\n * Fires {@link RoomMemberEvent.Name}\n * Fires {@link RoomMemberEvent.Membership}\n */\n public setMembershipEvent(event: MatrixEvent, roomState?: RoomState): void {\n const displayName = event.getDirectionalContent().displayname ?? \"\";\n\n if (event.getType() !== EventType.RoomMember) {\n return;\n }\n\n this._isOutOfBand = false;\n\n this.events.member = event;\n\n const oldMembership = this.membership;\n this.membership = event.getDirectionalContent().membership;\n if (this.membership === undefined) {\n // logging to diagnose https://github.com/vector-im/element-web/issues/20962\n // (logs event content, although only of membership events)\n logger.trace(\n `membership event with membership undefined (forwardLooking: ${event.forwardLooking})!`,\n event.getContent(),\n `prevcontent is `,\n event.getPrevContent(),\n );\n }\n\n this.disambiguate = shouldDisambiguate(this.userId, displayName, roomState);\n\n const oldName = this.name;\n this.name = calculateDisplayName(this.userId, displayName, this.disambiguate);\n\n // not quite raw: we strip direction override chars so it can safely be inserted into\n // blocks of text without breaking the text direction\n this.rawDisplayName = utils.removeDirectionOverrideChars(event.getDirectionalContent().displayname ?? \"\");\n if (!this.rawDisplayName || !utils.removeHiddenChars(this.rawDisplayName)) {\n this.rawDisplayName = this.userId;\n }\n\n if (oldMembership !== this.membership) {\n this.updateModifiedTime();\n this.emit(RoomMemberEvent.Membership, event, this, oldMembership);\n }\n if (oldName !== this.name) {\n this.updateModifiedTime();\n this.emit(RoomMemberEvent.Name, event, this, oldName);\n }\n }\n\n /**\n * Update this room member's power level event. May fire\n * \"RoomMember.powerLevel\" if this event updates this member's power levels.\n * @param powerLevelEvent - The `m.room.power_levels` event\n *\n * @remarks\n * Fires {@link RoomMemberEvent.PowerLevel}\n */\n public setPowerLevelEvent(powerLevelEvent: MatrixEvent): void {\n if (powerLevelEvent.getType() !== EventType.RoomPowerLevels || powerLevelEvent.getStateKey() !== \"\") {\n return;\n }\n\n const evContent = powerLevelEvent.getDirectionalContent();\n\n let maxLevel = evContent.users_default || 0;\n const users: { [userId: string]: number } = evContent.users || {};\n Object.values(users).forEach((lvl: number) => {\n maxLevel = Math.max(maxLevel, lvl);\n });\n const oldPowerLevel = this.powerLevel;\n const oldPowerLevelNorm = this.powerLevelNorm;\n\n if (users[this.userId] !== undefined && Number.isInteger(users[this.userId])) {\n this.powerLevel = users[this.userId];\n } else if (evContent.users_default !== undefined) {\n this.powerLevel = evContent.users_default;\n } else {\n this.powerLevel = 0;\n }\n this.powerLevelNorm = 0;\n if (maxLevel > 0) {\n this.powerLevelNorm = (this.powerLevel * 100) / maxLevel;\n }\n\n // emit for changes in powerLevelNorm as well (since the app will need to\n // redraw everyone's level if the max has changed)\n if (oldPowerLevel !== this.powerLevel || oldPowerLevelNorm !== this.powerLevelNorm) {\n this.updateModifiedTime();\n this.emit(RoomMemberEvent.PowerLevel, powerLevelEvent, this);\n }\n }\n\n /**\n * Update this room member's typing event. May fire \"RoomMember.typing\" if\n * this event changes this member's typing state.\n * @param event - The typing event\n *\n * @remarks\n * Fires {@link RoomMemberEvent.Typing}\n */\n public setTypingEvent(event: MatrixEvent): void {\n if (event.getType() !== \"m.typing\") {\n return;\n }\n const oldTyping = this.typing;\n this.typing = false;\n const typingList = event.getContent().user_ids;\n if (!Array.isArray(typingList)) {\n // malformed event :/ bail early. TODO: whine?\n return;\n }\n if (typingList.indexOf(this.userId) !== -1) {\n this.typing = true;\n }\n if (oldTyping !== this.typing) {\n this.updateModifiedTime();\n this.emit(RoomMemberEvent.Typing, event, this);\n }\n }\n\n /**\n * Update the last modified time to the current time.\n */\n private updateModifiedTime(): void {\n this.modified = Date.now();\n }\n\n /**\n * Get the timestamp when this RoomMember was last updated. This timestamp is\n * updated when properties on this RoomMember are updated.\n * It is updated <i>before</i> firing events.\n * @returns The timestamp\n */\n public getLastModifiedTime(): number {\n return this.modified;\n }\n\n public isKicked(): boolean {\n return (\n this.membership === \"leave\" &&\n this.events.member !== undefined &&\n this.events.member.getSender() !== this.events.member.getStateKey()\n );\n }\n\n /**\n * If this member was invited with the is_direct flag set, return\n * the user that invited this member\n * @returns user id of the inviter\n */\n public getDMInviter(): string | undefined {\n // when not available because that room state hasn't been loaded in,\n // we don't really know, but more likely to not be a direct chat\n if (this.events.member) {\n // TODO: persist the is_direct flag on the member as more member events\n // come in caused by displayName changes.\n\n // the is_direct flag is set on the invite member event.\n // This is copied on the prev_content section of the join member event\n // when the invite is accepted.\n\n const memberEvent = this.events.member;\n let memberContent = memberEvent.getContent();\n let inviteSender: string | undefined = memberEvent.getSender();\n\n if (memberContent.membership === \"join\") {\n memberContent = memberEvent.getPrevContent();\n inviteSender = memberEvent.getUnsigned().prev_sender;\n }\n\n if (memberContent.membership === \"invite\" && memberContent.is_direct) {\n return inviteSender;\n }\n }\n }\n\n /**\n * Get the avatar URL for a room member.\n * @param baseUrl - The base homeserver URL See\n * {@link MatrixClient#getHomeserverUrl}.\n * @param width - The desired width of the thumbnail.\n * @param height - The desired height of the thumbnail.\n * @param resizeMethod - The thumbnail resize method to use, either\n * \"crop\" or \"scale\".\n * @param allowDefault - (optional) Passing false causes this method to\n * return null if the user has no avatar image. Otherwise, a default image URL\n * will be returned. Default: true. (Deprecated)\n * @param allowDirectLinks - (optional) If true, the avatar URL will be\n * returned even if it is a direct hyperlink rather than a matrix content URL.\n * If false, any non-matrix content URLs will be ignored. Setting this option to\n * true will expose URLs that, if fetched, will leak information about the user\n * to anyone who they share a room with.\n * @returns the avatar URL or null.\n */\n public getAvatarUrl(\n baseUrl: string,\n width: number,\n height: number,\n resizeMethod: string,\n allowDefault = true,\n allowDirectLinks: boolean,\n ): string | null {\n const rawUrl = this.getMxcAvatarUrl();\n\n if (!rawUrl && !allowDefault) {\n return null;\n }\n const httpUrl = getHttpUriForMxc(baseUrl, rawUrl, width, height, resizeMethod, allowDirectLinks);\n if (httpUrl) {\n return httpUrl;\n }\n return null;\n }\n\n /**\n * get the mxc avatar url, either from a state event, or from a lazily loaded member\n * @returns the mxc avatar url\n */\n public getMxcAvatarUrl(): string | undefined {\n if (this.events.member) {\n return this.events.member.getDirectionalContent().avatar_url;\n } else if (this.user) {\n return this.user.avatarUrl;\n }\n }\n}\n\nconst MXID_PATTERN = /@.+:.+/;\nconst LTR_RTL_PATTERN = /[\\u200E\\u200F\\u202A-\\u202F]/;\n\nfunction shouldDisambiguate(selfUserId: string, displayName?: string, roomState?: RoomState): boolean {\n if (!displayName || displayName === selfUserId) return false;\n\n // First check if the displayname is something we consider truthy\n // after stripping it of zero width characters and padding spaces\n if (!utils.removeHiddenChars(displayName)) return false;\n\n if (!roomState) return false;\n\n // Next check if the name contains something that look like a mxid\n // If it does, it may be someone trying to impersonate someone else\n // Show full mxid in this case\n if (MXID_PATTERN.test(displayName)) return true;\n\n // Also show mxid if the display name contains any LTR/RTL characters as these\n // make it very difficult for us to find similar *looking* display names\n // E.g \"Mark\" could be cloned by writing \"kraM\" but in RTL.\n if (LTR_RTL_PATTERN.test(displayName)) return true;\n\n // Also show mxid if there are other people with the same or similar\n // displayname, after hidden character removal.\n const userIds = roomState.getUserIdsWithDisplayName(displayName);\n if (userIds.some((u) => u !== selfUserId)) return true;\n\n return false;\n}\n\nfunction calculateDisplayName(selfUserId: string, displayName: string | undefined, disambiguate: boolean): string {\n if (!displayName || displayName === selfUserId) return selfUserId;\n\n if (disambiguate) return utils.removeDirectionOverrideChars(displayName) + \" (\" + selfUserId + \")\";\n\n // First check if the displayname is something we consider truthy\n // after stripping it of zero width characters and padding spaces\n if (!utils.removeHiddenChars(displayName)) return selfUserId;\n\n // We always strip the direction override characters (LRO and RLO).\n // These override the text direction for all subsequent characters\n // in the paragraph so if display names contained these, they'd\n // need to be wrapped in something to prevent this from leaking out\n // (which we can do in HTML but not text) or we'd need to add\n // control characters to the string to reset any overrides (eg.\n // adding PDF characters at the end). As far as we can see,\n // there should be no reason these would be necessary - rtl display\n // names should flip into the correct direction automatically based on\n // the characters, and you can still embed rtl in ltr or vice versa\n // with the embed chars or marker chars.\n return utils.removeDirectionOverrideChars(displayName);\n}\n"],"mappings":"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"} \ No newline at end of file
diff --git a/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/room-state.d.ts b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/room-state.d.ts
new file mode 100644
index 0000000..316a8dd
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/room-state.d.ts
@@ -0,0 +1,448 @@
+import { RoomMember } from "./room-member";
+import { EventType } from "../@types/event";
+import { MatrixEvent } from "./event";
+import { MatrixClient } from "../client";
+import { GuestAccess, HistoryVisibility, JoinRule } from "../@types/partials";
+import { TypedEventEmitter } from "./typed-event-emitter";
+import { Beacon, BeaconEvent, BeaconEventHandlerMap, BeaconIdentifier } from "./beacon";
+import { TypedReEmitter } from "../ReEmitter";
+export interface IMarkerFoundOptions {
+ /** Whether the timeline was empty before the marker event arrived in the
+ * room. This could be happen in a variety of cases:
+ * 1. From the initial sync
+ * 2. It's the first state we're seeing after joining the room
+ * 3. Or whether it's coming from `syncFromCache`
+ *
+ * A marker event refers to `UNSTABLE_MSC2716_MARKER` and indicates that
+ * history was imported somewhere back in time. It specifically points to an
+ * MSC2716 insertion event where the history was imported at. Marker events
+ * are sent as state events so they are easily discoverable by clients and
+ * homeservers and don't get lost in timeline gaps.
+ */
+ timelineWasEmpty?: boolean;
+}
+declare enum OobStatus {
+ NotStarted = 0,
+ InProgress = 1,
+ Finished = 2
+}
+export interface IPowerLevelsContent {
+ users?: Record<string, number>;
+ events?: Record<string, number>;
+ users_default?: number;
+ events_default?: number;
+ state_default?: number;
+ ban?: number;
+ kick?: number;
+ redact?: number;
+}
+export declare enum RoomStateEvent {
+ Events = "RoomState.events",
+ Members = "RoomState.members",
+ NewMember = "RoomState.newMember",
+ Update = "RoomState.update",
+ BeaconLiveness = "RoomState.BeaconLiveness",
+ Marker = "RoomState.Marker"
+}
+export type RoomStateEventHandlerMap = {
+ /**
+ * Fires whenever the event dictionary in room state is updated.
+ * @param event - The matrix event which caused this event to fire.
+ * @param state - The room state whose RoomState.events dictionary
+ * was updated.
+ * @param prevEvent - The event being replaced by the new state, if
+ * known. Note that this can differ from `getPrevContent()` on the new state event
+ * as this is the store's view of the last state, not the previous state provided
+ * by the server.
+ * @example
+ * ```
+ * matrixClient.on("RoomState.events", function(event, state, prevEvent){
+ * var newStateEvent = event;
+ * });
+ * ```
+ */
+ [RoomStateEvent.Events]: (event: MatrixEvent, state: RoomState, lastStateEvent: MatrixEvent | null) => void;
+ /**
+ * Fires whenever a member in the members dictionary is updated in any way.
+ * @param event - The matrix event which caused this event to fire.
+ * @param state - The room state whose RoomState.members dictionary
+ * was updated.
+ * @param member - The room member that was updated.
+ * @example
+ * ```
+ * matrixClient.on("RoomState.members", function(event, state, member){
+ * var newMembershipState = member.membership;
+ * });
+ * ```
+ */
+ [RoomStateEvent.Members]: (event: MatrixEvent, state: RoomState, member: RoomMember) => void;
+ /**
+ * Fires whenever a member is added to the members dictionary. The RoomMember
+ * will not be fully populated yet (e.g. no membership state) but will already
+ * be available in the members dictionary.
+ * @param event - The matrix event which caused this event to fire.
+ * @param state - The room state whose RoomState.members dictionary
+ * was updated with a new entry.
+ * @param member - The room member that was added.
+ * @example
+ * ```
+ * matrixClient.on("RoomState.newMember", function(event, state, member){
+ * // add event listeners on 'member'
+ * });
+ * ```
+ */
+ [RoomStateEvent.NewMember]: (event: MatrixEvent, state: RoomState, member: RoomMember) => void;
+ [RoomStateEvent.Update]: (state: RoomState) => void;
+ [RoomStateEvent.BeaconLiveness]: (state: RoomState, hasLiveBeacons: boolean) => void;
+ [RoomStateEvent.Marker]: (event: MatrixEvent, setStateOptions?: IMarkerFoundOptions) => void;
+ [BeaconEvent.New]: (event: MatrixEvent, beacon: Beacon) => void;
+};
+type EmittedEvents = RoomStateEvent | BeaconEvent;
+type EventHandlerMap = RoomStateEventHandlerMap & BeaconEventHandlerMap;
+export declare class RoomState extends TypedEventEmitter<EmittedEvents, EventHandlerMap> {
+ readonly roomId: string;
+ private oobMemberFlags;
+ readonly reEmitter: TypedReEmitter<EmittedEvents, EventHandlerMap>;
+ private sentinels;
+ private displayNameToUserIds;
+ private userIdsToDisplayNames;
+ private tokenToInvite;
+ private joinedMemberCount;
+ private summaryJoinedMemberCount;
+ private invitedMemberCount;
+ private summaryInvitedMemberCount;
+ private modified;
+ members: Record<string, RoomMember>;
+ events: Map<string, Map<string, MatrixEvent>>;
+ paginationToken: string | null;
+ readonly beacons: Map<string, Beacon>;
+ private _liveBeaconIds;
+ /**
+ * Construct room state.
+ *
+ * Room State represents the state of the room at a given point.
+ * It can be mutated by adding state events to it.
+ * There are two types of room member associated with a state event:
+ * normal member objects (accessed via getMember/getMembers) which mutate
+ * with the state to represent the current state of that room/user, e.g.
+ * the object returned by `getMember('@bob:example.com')` will mutate to
+ * get a different display name if Bob later changes his display name
+ * in the room.
+ * There are also 'sentinel' members (accessed via getSentinelMember).
+ * These also represent the state of room members at the point in time
+ * represented by the RoomState object, but unlike objects from getMember,
+ * sentinel objects will always represent the room state as at the time
+ * getSentinelMember was called, so if Bob subsequently changes his display
+ * name, a room member object previously acquired with getSentinelMember
+ * will still have his old display name. Calling getSentinelMember again
+ * after the display name change will return a new RoomMember object
+ * with Bob's new display name.
+ *
+ * @param roomId - Optional. The ID of the room which has this state.
+ * If none is specified it just tracks paginationTokens, useful for notifTimelineSet
+ * @param oobMemberFlags - Optional. The state of loading out of bound members.
+ * As the timeline might get reset while they are loading, this state needs to be inherited
+ * and shared when the room state is cloned for the new timeline.
+ * This should only be passed from clone.
+ */
+ constructor(roomId: string, oobMemberFlags?: {
+ status: OobStatus;
+ });
+ /**
+ * Returns the number of joined members in this room
+ * This method caches the result.
+ * @returns The number of members in this room whose membership is 'join'
+ */
+ getJoinedMemberCount(): number;
+ /**
+ * Set the joined member count explicitly (like from summary part of the sync response)
+ * @param count - the amount of joined members
+ */
+ setJoinedMemberCount(count: number): void;
+ /**
+ * Returns the number of invited members in this room
+ * @returns The number of members in this room whose membership is 'invite'
+ */
+ getInvitedMemberCount(): number;
+ /**
+ * Set the amount of invited members in this room
+ * @param count - the amount of invited members
+ */
+ setInvitedMemberCount(count: number): void;
+ /**
+ * Get all RoomMembers in this room.
+ * @returns A list of RoomMembers.
+ */
+ getMembers(): RoomMember[];
+ /**
+ * Get all RoomMembers in this room, excluding the user IDs provided.
+ * @param excludedIds - The user IDs to exclude.
+ * @returns A list of RoomMembers.
+ */
+ getMembersExcept(excludedIds: string[]): RoomMember[];
+ /**
+ * Get a room member by their user ID.
+ * @param userId - The room member's user ID.
+ * @returns The member or null if they do not exist.
+ */
+ getMember(userId: string): RoomMember | null;
+ /**
+ * Get a room member whose properties will not change with this room state. You
+ * typically want this if you want to attach a RoomMember to a MatrixEvent which
+ * may no longer be represented correctly by Room.currentState or Room.oldState.
+ * The term 'sentinel' refers to the fact that this RoomMember is an unchanging
+ * guardian for state at this particular point in time.
+ * @param userId - The room member's user ID.
+ * @returns The member or null if they do not exist.
+ */
+ getSentinelMember(userId: string): RoomMember | null;
+ /**
+ * Get state events from the state of the room.
+ * @param eventType - The event type of the state event.
+ * @param stateKey - Optional. The state_key of the state event. If
+ * this is `undefined` then all matching state events will be
+ * returned.
+ * @returns A list of events if state_key was
+ * `undefined`, else a single event (or null if no match found).
+ */
+ getStateEvents(eventType: EventType | string): MatrixEvent[];
+ getStateEvents(eventType: EventType | string, stateKey: string): MatrixEvent | null;
+ get hasLiveBeacons(): boolean;
+ get liveBeaconIds(): BeaconIdentifier[];
+ /**
+ * Creates a copy of this room state so that mutations to either won't affect the other.
+ * @returns the copy of the room state
+ */
+ clone(): RoomState;
+ /**
+ * Add previously unknown state events.
+ * When lazy loading members while back-paginating,
+ * the relevant room state for the timeline chunk at the end
+ * of the chunk can be set with this method.
+ * @param events - state events to prepend
+ */
+ setUnknownStateEvents(events: MatrixEvent[]): void;
+ /**
+ * Add an array of one or more state MatrixEvents, overwriting any existing
+ * state with the same `{type, stateKey}` tuple. Will fire "RoomState.events"
+ * for every event added. May fire "RoomState.members" if there are
+ * `m.room.member` events. May fire "RoomStateEvent.Marker" if there are
+ * `UNSTABLE_MSC2716_MARKER` events.
+ * @param stateEvents - a list of state events for this room.
+ *
+ * @remarks
+ * Fires {@link RoomStateEvent.Members}
+ * Fires {@link RoomStateEvent.NewMember}
+ * Fires {@link RoomStateEvent.Events}
+ * Fires {@link RoomStateEvent.Marker}
+ */
+ setStateEvents(stateEvents: MatrixEvent[], markerFoundOptions?: IMarkerFoundOptions): void;
+ processBeaconEvents(events: MatrixEvent[], matrixClient: MatrixClient): Promise<void>;
+ /**
+ * Looks up a member by the given userId, and if it doesn't exist,
+ * create it and emit the `RoomState.newMember` event.
+ * This method makes sure the member is added to the members dictionary
+ * before emitting, as this is done from setStateEvents and setOutOfBandMember.
+ * @param userId - the id of the user to look up
+ * @param event - the membership event for the (new) member. Used to emit.
+ * @returns the member, existing or newly created.
+ *
+ * @remarks
+ * Fires {@link RoomStateEvent.NewMember}
+ */
+ private getOrCreateMember;
+ private setStateEvent;
+ /**
+ * @experimental
+ */
+ private setBeacon;
+ /**
+ * @experimental
+ * Check liveness of room beacons
+ * emit RoomStateEvent.BeaconLiveness event
+ */
+ private onBeaconLivenessChange;
+ private getStateEventMatching;
+ private updateMember;
+ /**
+ * Get the out-of-band members loading state, whether loading is needed or not.
+ * Note that loading might be in progress and hence isn't needed.
+ * @returns whether or not the members of this room need to be loaded
+ */
+ needsOutOfBandMembers(): boolean;
+ /**
+ * Check if loading of out-of-band-members has completed
+ *
+ * @returns true if the full membership list of this room has been loaded. False if it is not started or is in
+ * progress.
+ */
+ outOfBandMembersReady(): boolean;
+ /**
+ * Mark this room state as waiting for out-of-band members,
+ * ensuring it doesn't ask for them to be requested again
+ * through needsOutOfBandMembers
+ */
+ markOutOfBandMembersStarted(): void;
+ /**
+ * Mark this room state as having failed to fetch out-of-band members
+ */
+ markOutOfBandMembersFailed(): void;
+ /**
+ * Clears the loaded out-of-band members
+ */
+ clearOutOfBandMembers(): void;
+ /**
+ * Sets the loaded out-of-band members.
+ * @param stateEvents - array of membership state events
+ */
+ setOutOfBandMembers(stateEvents: MatrixEvent[]): void;
+ /**
+ * Sets a single out of band member, used by both setOutOfBandMembers and clone
+ * @param stateEvent - membership state event
+ */
+ private setOutOfBandMember;
+ /**
+ * Set the current typing event for this room.
+ * @param event - The typing event
+ */
+ setTypingEvent(event: MatrixEvent): void;
+ /**
+ * Get the m.room.member event which has the given third party invite token.
+ *
+ * @param token - The token
+ * @returns The m.room.member event or null
+ */
+ getInviteForThreePidToken(token: string): MatrixEvent | null;
+ /**
+ * Update the last modified time to the current time.
+ */
+ private updateModifiedTime;
+ /**
+ * Get the timestamp when this room state was last updated. This timestamp is
+ * updated when this object has received new state events.
+ * @returns The timestamp
+ */
+ getLastModifiedTime(): number;
+ /**
+ * Get user IDs with the specified or similar display names.
+ * @param displayName - The display name to get user IDs from.
+ * @returns An array of user IDs or an empty array.
+ */
+ getUserIdsWithDisplayName(displayName: string): string[];
+ /**
+ * Returns true if userId is in room, event is not redacted and either sender of
+ * mxEvent or has power level sufficient to redact events other than their own.
+ * @param mxEvent - The event to test permission for
+ * @param userId - The user ID of the user to test permission for
+ * @returns true if the given used ID can redact given event
+ */
+ maySendRedactionForEvent(mxEvent: MatrixEvent, userId: string): boolean;
+ /**
+ * Returns true if the given power level is sufficient for action
+ * @param action - The type of power level to check
+ * @param powerLevel - The power level of the member
+ * @returns true if the given power level is sufficient
+ */
+ hasSufficientPowerLevelFor(action: "ban" | "kick" | "redact", powerLevel: number): boolean;
+ /**
+ * Short-form for maySendEvent('m.room.message', userId)
+ * @param userId - The user ID of the user to test permission for
+ * @returns true if the given user ID should be permitted to send
+ * message events into the given room.
+ */
+ maySendMessage(userId: string): boolean;
+ /**
+ * Returns true if the given user ID has permission to send a normal
+ * event of type `eventType` into this room.
+ * @param eventType - The type of event to test
+ * @param userId - The user ID of the user to test permission for
+ * @returns true if the given user ID should be permitted to send
+ * the given type of event into this room,
+ * according to the room's state.
+ */
+ maySendEvent(eventType: EventType | string, userId: string): boolean;
+ /**
+ * Returns true if the given MatrixClient has permission to send a state
+ * event of type `stateEventType` into this room.
+ * @param stateEventType - The type of state events to test
+ * @param cli - The client to test permission for
+ * @returns true if the given client should be permitted to send
+ * the given type of state event into this room,
+ * according to the room's state.
+ */
+ mayClientSendStateEvent(stateEventType: EventType | string, cli: MatrixClient): boolean;
+ /**
+ * Returns true if the given user ID has permission to send a state
+ * event of type `stateEventType` into this room.
+ * @param stateEventType - The type of state events to test
+ * @param userId - The user ID of the user to test permission for
+ * @returns true if the given user ID should be permitted to send
+ * the given type of state event into this room,
+ * according to the room's state.
+ */
+ maySendStateEvent(stateEventType: EventType | string, userId: string): boolean;
+ /**
+ * Returns true if the given user ID has permission to send a normal or state
+ * event of type `eventType` into this room.
+ * @param eventType - The type of event to test
+ * @param userId - The user ID of the user to test permission for
+ * @param state - If true, tests if the user may send a state
+ event of this type. Otherwise tests whether
+ they may send a regular event.
+ * @returns true if the given user ID should be permitted to send
+ * the given type of event into this room,
+ * according to the room's state.
+ */
+ private maySendEventOfType;
+ /**
+ * Returns true if the given user ID has permission to trigger notification
+ * of type `notifLevelKey`
+ * @param notifLevelKey - The level of notification to test (eg. 'room')
+ * @param userId - The user ID of the user to test permission for
+ * @returns true if the given user ID has permission to trigger a
+ * notification of this type.
+ */
+ mayTriggerNotifOfType(notifLevelKey: string, userId: string): boolean;
+ /**
+ * Returns the join rule based on the m.room.join_rule state event, defaulting to `invite`.
+ * @returns the join_rule applied to this room
+ */
+ getJoinRule(): JoinRule;
+ /**
+ * Returns the history visibility based on the m.room.history_visibility state event, defaulting to `shared`.
+ * @returns the history_visibility applied to this room
+ */
+ getHistoryVisibility(): HistoryVisibility;
+ /**
+ * Returns the guest access based on the m.room.guest_access state event, defaulting to `shared`.
+ * @returns the guest_access applied to this room
+ */
+ getGuestAccess(): GuestAccess;
+ /**
+ * Find the predecessor room based on this room state.
+ *
+ * @param msc3946ProcessDynamicPredecessor - if true, look for an
+ * m.room.predecessor state event and use it if found (MSC3946).
+ * @returns null if this room has no predecessor. Otherwise, returns
+ * the roomId, last eventId and viaServers of the predecessor room.
+ *
+ * If msc3946ProcessDynamicPredecessor is true, use m.predecessor events
+ * as well as m.room.create events to find predecessors.
+ *
+ * Note: if an m.predecessor event is used, eventId may be undefined
+ * since last_known_event_id is optional.
+ *
+ * Note: viaServers may be undefined, and will definitely be undefined if
+ * this predecessor comes from a RoomCreate event (rather than a
+ * RoomPredecessor, which has the optional via_servers property).
+ */
+ findPredecessor(msc3946ProcessDynamicPredecessor?: boolean): {
+ roomId: string;
+ eventId?: string;
+ viaServers?: string[];
+ } | null;
+ private updateThirdPartyTokenCache;
+ private updateDisplayNameCache;
+}
+export {};
+//# sourceMappingURL=room-state.d.ts.map \ No newline at end of file
diff --git a/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/room-state.d.ts.map b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/room-state.d.ts.map
new file mode 100644
index 0000000..090c925
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/room-state.d.ts.map
@@ -0,0 +1 @@
+{"version":3,"file":"room-state.d.ts","sourceRoot":"","sources":["../../src/models/room-state.ts"],"names":[],"mappings":"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"} \ No newline at end of file
diff --git a/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/room-state.js b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/room-state.js
new file mode 100644
index 0000000..a99ea32
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/room-state.js
@@ -0,0 +1,949 @@
+"use strict";
+
+var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.RoomStateEvent = exports.RoomState = void 0;
+var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
+var _roomMember = require("./room-member");
+var _logger = require("../logger");
+var utils = _interopRequireWildcard(require("../utils"));
+var _event = require("../@types/event");
+var _event2 = require("./event");
+var _partials = require("../@types/partials");
+var _typedEventEmitter = require("./typed-event-emitter");
+var _beacon = require("./beacon");
+var _ReEmitter = require("../ReEmitter");
+var _beacon2 = require("../@types/beacon");
+function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
+function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
+/*
+Copyright 2015 - 2021 The Matrix.org Foundation C.I.C.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+// possible statuses for out-of-band member loading
+var OobStatus;
+(function (OobStatus) {
+ OobStatus[OobStatus["NotStarted"] = 0] = "NotStarted";
+ OobStatus[OobStatus["InProgress"] = 1] = "InProgress";
+ OobStatus[OobStatus["Finished"] = 2] = "Finished";
+})(OobStatus || (OobStatus = {}));
+let RoomStateEvent;
+exports.RoomStateEvent = RoomStateEvent;
+(function (RoomStateEvent) {
+ RoomStateEvent["Events"] = "RoomState.events";
+ RoomStateEvent["Members"] = "RoomState.members";
+ RoomStateEvent["NewMember"] = "RoomState.newMember";
+ RoomStateEvent["Update"] = "RoomState.update";
+ RoomStateEvent["BeaconLiveness"] = "RoomState.BeaconLiveness";
+ RoomStateEvent["Marker"] = "RoomState.Marker";
+})(RoomStateEvent || (exports.RoomStateEvent = RoomStateEvent = {}));
+class RoomState extends _typedEventEmitter.TypedEventEmitter {
+ // userId: RoomMember
+ // stores fuzzy matches to a list of userIDs (applies utils.removeHiddenChars to keys)
+
+ // 3pid invite state_key to m.room.member invite
+ // cache of the number of joined members
+ // joined members count from summary api
+ // once set, we know the server supports the summary api
+ // and we should only trust that
+ // we could also only trust that before OOB members
+ // are loaded but doesn't seem worth the hassle atm
+
+ // same for invited member count
+
+ // XXX: Should be read-only
+ // The room member dictionary, keyed on the user's ID.
+ // userId: RoomMember
+ // The state events dictionary, keyed on the event type and then the state_key value.
+ // Map<eventType, Map<stateKey, MatrixEvent>>
+ // The pagination token for this state.
+
+ /**
+ * Construct room state.
+ *
+ * Room State represents the state of the room at a given point.
+ * It can be mutated by adding state events to it.
+ * There are two types of room member associated with a state event:
+ * normal member objects (accessed via getMember/getMembers) which mutate
+ * with the state to represent the current state of that room/user, e.g.
+ * the object returned by `getMember('@bob:example.com')` will mutate to
+ * get a different display name if Bob later changes his display name
+ * in the room.
+ * There are also 'sentinel' members (accessed via getSentinelMember).
+ * These also represent the state of room members at the point in time
+ * represented by the RoomState object, but unlike objects from getMember,
+ * sentinel objects will always represent the room state as at the time
+ * getSentinelMember was called, so if Bob subsequently changes his display
+ * name, a room member object previously acquired with getSentinelMember
+ * will still have his old display name. Calling getSentinelMember again
+ * after the display name change will return a new RoomMember object
+ * with Bob's new display name.
+ *
+ * @param roomId - Optional. The ID of the room which has this state.
+ * If none is specified it just tracks paginationTokens, useful for notifTimelineSet
+ * @param oobMemberFlags - Optional. The state of loading out of bound members.
+ * As the timeline might get reset while they are loading, this state needs to be inherited
+ * and shared when the room state is cloned for the new timeline.
+ * This should only be passed from clone.
+ */
+ constructor(roomId, oobMemberFlags = {
+ status: OobStatus.NotStarted
+ }) {
+ super();
+ this.roomId = roomId;
+ this.oobMemberFlags = oobMemberFlags;
+ (0, _defineProperty2.default)(this, "reEmitter", new _ReEmitter.TypedReEmitter(this));
+ (0, _defineProperty2.default)(this, "sentinels", {});
+ (0, _defineProperty2.default)(this, "displayNameToUserIds", new Map());
+ (0, _defineProperty2.default)(this, "userIdsToDisplayNames", {});
+ (0, _defineProperty2.default)(this, "tokenToInvite", {});
+ (0, _defineProperty2.default)(this, "joinedMemberCount", null);
+ (0, _defineProperty2.default)(this, "summaryJoinedMemberCount", null);
+ (0, _defineProperty2.default)(this, "invitedMemberCount", null);
+ (0, _defineProperty2.default)(this, "summaryInvitedMemberCount", null);
+ (0, _defineProperty2.default)(this, "modified", -1);
+ (0, _defineProperty2.default)(this, "members", {});
+ (0, _defineProperty2.default)(this, "events", new Map());
+ (0, _defineProperty2.default)(this, "paginationToken", null);
+ (0, _defineProperty2.default)(this, "beacons", new Map());
+ (0, _defineProperty2.default)(this, "_liveBeaconIds", []);
+ this.updateModifiedTime();
+ }
+
+ /**
+ * Returns the number of joined members in this room
+ * This method caches the result.
+ * @returns The number of members in this room whose membership is 'join'
+ */
+ getJoinedMemberCount() {
+ if (this.summaryJoinedMemberCount !== null) {
+ return this.summaryJoinedMemberCount;
+ }
+ if (this.joinedMemberCount === null) {
+ this.joinedMemberCount = this.getMembers().reduce((count, m) => {
+ return m.membership === "join" ? count + 1 : count;
+ }, 0);
+ }
+ return this.joinedMemberCount;
+ }
+
+ /**
+ * Set the joined member count explicitly (like from summary part of the sync response)
+ * @param count - the amount of joined members
+ */
+ setJoinedMemberCount(count) {
+ this.summaryJoinedMemberCount = count;
+ }
+
+ /**
+ * Returns the number of invited members in this room
+ * @returns The number of members in this room whose membership is 'invite'
+ */
+ getInvitedMemberCount() {
+ if (this.summaryInvitedMemberCount !== null) {
+ return this.summaryInvitedMemberCount;
+ }
+ if (this.invitedMemberCount === null) {
+ this.invitedMemberCount = this.getMembers().reduce((count, m) => {
+ return m.membership === "invite" ? count + 1 : count;
+ }, 0);
+ }
+ return this.invitedMemberCount;
+ }
+
+ /**
+ * Set the amount of invited members in this room
+ * @param count - the amount of invited members
+ */
+ setInvitedMemberCount(count) {
+ this.summaryInvitedMemberCount = count;
+ }
+
+ /**
+ * Get all RoomMembers in this room.
+ * @returns A list of RoomMembers.
+ */
+ getMembers() {
+ return Object.values(this.members);
+ }
+
+ /**
+ * Get all RoomMembers in this room, excluding the user IDs provided.
+ * @param excludedIds - The user IDs to exclude.
+ * @returns A list of RoomMembers.
+ */
+ getMembersExcept(excludedIds) {
+ return this.getMembers().filter(m => !excludedIds.includes(m.userId));
+ }
+
+ /**
+ * Get a room member by their user ID.
+ * @param userId - The room member's user ID.
+ * @returns The member or null if they do not exist.
+ */
+ getMember(userId) {
+ return this.members[userId] || null;
+ }
+
+ /**
+ * Get a room member whose properties will not change with this room state. You
+ * typically want this if you want to attach a RoomMember to a MatrixEvent which
+ * may no longer be represented correctly by Room.currentState or Room.oldState.
+ * The term 'sentinel' refers to the fact that this RoomMember is an unchanging
+ * guardian for state at this particular point in time.
+ * @param userId - The room member's user ID.
+ * @returns The member or null if they do not exist.
+ */
+ getSentinelMember(userId) {
+ if (!userId) return null;
+ let sentinel = this.sentinels[userId];
+ if (sentinel === undefined) {
+ sentinel = new _roomMember.RoomMember(this.roomId, userId);
+ const member = this.members[userId];
+ if (member !== null && member !== void 0 && member.events.member) {
+ sentinel.setMembershipEvent(member.events.member, this);
+ }
+ this.sentinels[userId] = sentinel;
+ }
+ return sentinel;
+ }
+
+ /**
+ * Get state events from the state of the room.
+ * @param eventType - The event type of the state event.
+ * @param stateKey - Optional. The state_key of the state event. If
+ * this is `undefined` then all matching state events will be
+ * returned.
+ * @returns A list of events if state_key was
+ * `undefined`, else a single event (or null if no match found).
+ */
+
+ getStateEvents(eventType, stateKey) {
+ if (!this.events.has(eventType)) {
+ // no match
+ return stateKey === undefined ? [] : null;
+ }
+ if (stateKey === undefined) {
+ // return all values
+ return Array.from(this.events.get(eventType).values());
+ }
+ const event = this.events.get(eventType).get(stateKey);
+ return event ? event : null;
+ }
+ get hasLiveBeacons() {
+ var _this$liveBeaconIds;
+ return !!((_this$liveBeaconIds = this.liveBeaconIds) !== null && _this$liveBeaconIds !== void 0 && _this$liveBeaconIds.length);
+ }
+ get liveBeaconIds() {
+ return this._liveBeaconIds;
+ }
+
+ /**
+ * Creates a copy of this room state so that mutations to either won't affect the other.
+ * @returns the copy of the room state
+ */
+ clone() {
+ const copy = new RoomState(this.roomId, this.oobMemberFlags);
+
+ // Ugly hack: because setStateEvents will mark
+ // members as susperseding future out of bound members
+ // if loading is in progress (through oobMemberFlags)
+ // since these are not new members, we're merely copying them
+ // set the status to not started
+ // after copying, we set back the status
+ const status = this.oobMemberFlags.status;
+ this.oobMemberFlags.status = OobStatus.NotStarted;
+ Array.from(this.events.values()).forEach(eventsByStateKey => {
+ copy.setStateEvents(Array.from(eventsByStateKey.values()));
+ });
+
+ // Ugly hack: see above
+ this.oobMemberFlags.status = status;
+ if (this.summaryInvitedMemberCount !== null) {
+ copy.setInvitedMemberCount(this.getInvitedMemberCount());
+ }
+ if (this.summaryJoinedMemberCount !== null) {
+ copy.setJoinedMemberCount(this.getJoinedMemberCount());
+ }
+
+ // copy out of band flags if needed
+ if (this.oobMemberFlags.status == OobStatus.Finished) {
+ // copy markOutOfBand flags
+ this.getMembers().forEach(member => {
+ if (member.isOutOfBand()) {
+ var _copy$getMember;
+ (_copy$getMember = copy.getMember(member.userId)) === null || _copy$getMember === void 0 ? void 0 : _copy$getMember.markOutOfBand();
+ }
+ });
+ }
+ return copy;
+ }
+
+ /**
+ * Add previously unknown state events.
+ * When lazy loading members while back-paginating,
+ * the relevant room state for the timeline chunk at the end
+ * of the chunk can be set with this method.
+ * @param events - state events to prepend
+ */
+ setUnknownStateEvents(events) {
+ const unknownStateEvents = events.filter(event => {
+ return !this.events.has(event.getType()) || !this.events.get(event.getType()).has(event.getStateKey());
+ });
+ this.setStateEvents(unknownStateEvents);
+ }
+
+ /**
+ * Add an array of one or more state MatrixEvents, overwriting any existing
+ * state with the same `{type, stateKey}` tuple. Will fire "RoomState.events"
+ * for every event added. May fire "RoomState.members" if there are
+ * `m.room.member` events. May fire "RoomStateEvent.Marker" if there are
+ * `UNSTABLE_MSC2716_MARKER` events.
+ * @param stateEvents - a list of state events for this room.
+ *
+ * @remarks
+ * Fires {@link RoomStateEvent.Members}
+ * Fires {@link RoomStateEvent.NewMember}
+ * Fires {@link RoomStateEvent.Events}
+ * Fires {@link RoomStateEvent.Marker}
+ */
+ setStateEvents(stateEvents, markerFoundOptions) {
+ this.updateModifiedTime();
+
+ // update the core event dict
+ stateEvents.forEach(event => {
+ if (event.getRoomId() !== this.roomId || !event.isState()) return;
+ if (_beacon2.M_BEACON_INFO.matches(event.getType())) {
+ this.setBeacon(event);
+ }
+ const lastStateEvent = this.getStateEventMatching(event);
+ this.setStateEvent(event);
+ if (event.getType() === _event.EventType.RoomMember) {
+ var _event$getContent$dis;
+ this.updateDisplayNameCache(event.getStateKey(), (_event$getContent$dis = event.getContent().displayname) !== null && _event$getContent$dis !== void 0 ? _event$getContent$dis : "");
+ this.updateThirdPartyTokenCache(event);
+ }
+ this.emit(RoomStateEvent.Events, event, this, lastStateEvent);
+ });
+ this.onBeaconLivenessChange();
+ // update higher level data structures. This needs to be done AFTER the
+ // core event dict as these structures may depend on other state events in
+ // the given array (e.g. disambiguating display names in one go to do both
+ // clashing names rather than progressively which only catches 1 of them).
+ stateEvents.forEach(event => {
+ if (event.getRoomId() !== this.roomId || !event.isState()) return;
+ if (event.getType() === _event.EventType.RoomMember) {
+ const userId = event.getStateKey();
+
+ // leave events apparently elide the displayname or avatar_url,
+ // so let's fake one up so that we don't leak user ids
+ // into the timeline
+ if (event.getContent().membership === "leave" || event.getContent().membership === "ban") {
+ event.getContent().avatar_url = event.getContent().avatar_url || event.getPrevContent().avatar_url;
+ event.getContent().displayname = event.getContent().displayname || event.getPrevContent().displayname;
+ }
+ const member = this.getOrCreateMember(userId, event);
+ member.setMembershipEvent(event, this);
+ this.updateMember(member);
+ this.emit(RoomStateEvent.Members, event, this, member);
+ } else if (event.getType() === _event.EventType.RoomPowerLevels) {
+ // events with unknown state keys should be ignored
+ // and should not aggregate onto members power levels
+ if (event.getStateKey() !== "") {
+ return;
+ }
+ const members = Object.values(this.members);
+ members.forEach(member => {
+ // We only propagate `RoomState.members` event if the
+ // power levels has been changed
+ // large room suffer from large re-rendering especially when not needed
+ const oldLastModified = member.getLastModifiedTime();
+ member.setPowerLevelEvent(event);
+ if (oldLastModified !== member.getLastModifiedTime()) {
+ this.emit(RoomStateEvent.Members, event, this, member);
+ }
+ });
+
+ // assume all our sentinels are now out-of-date
+ this.sentinels = {};
+ } else if (_event.UNSTABLE_MSC2716_MARKER.matches(event.getType())) {
+ this.emit(RoomStateEvent.Marker, event, markerFoundOptions);
+ }
+ });
+ this.emit(RoomStateEvent.Update, this);
+ }
+ async processBeaconEvents(events, matrixClient) {
+ if (!events.length ||
+ // discard locations if we have no beacons
+ !this.beacons.size) {
+ return;
+ }
+ const beaconByEventIdDict = [...this.beacons.values()].reduce((dict, beacon) => {
+ dict[beacon.beaconInfoId] = beacon;
+ return dict;
+ }, {});
+ const processBeaconRelation = (beaconInfoEventId, event) => {
+ if (!_beacon2.M_BEACON.matches(event.getType())) {
+ return;
+ }
+ const beacon = beaconByEventIdDict[beaconInfoEventId];
+ if (beacon) {
+ beacon.addLocations([event]);
+ }
+ };
+ for (const event of events) {
+ var _event$getRelation;
+ const relatedToEventId = (_event$getRelation = event.getRelation()) === null || _event$getRelation === void 0 ? void 0 : _event$getRelation.event_id;
+ // not related to a beacon we know about; discard
+ if (!relatedToEventId || !beaconByEventIdDict[relatedToEventId]) return;
+ if (!_beacon2.M_BEACON.matches(event.getType()) && !event.isEncrypted()) return;
+ try {
+ await matrixClient.decryptEventIfNeeded(event);
+ processBeaconRelation(relatedToEventId, event);
+ } catch {
+ if (event.isDecryptionFailure()) {
+ // add an event listener for once the event is decrypted.
+ event.once(_event2.MatrixEventEvent.Decrypted, async () => {
+ processBeaconRelation(relatedToEventId, event);
+ });
+ }
+ }
+ }
+ }
+
+ /**
+ * Looks up a member by the given userId, and if it doesn't exist,
+ * create it and emit the `RoomState.newMember` event.
+ * This method makes sure the member is added to the members dictionary
+ * before emitting, as this is done from setStateEvents and setOutOfBandMember.
+ * @param userId - the id of the user to look up
+ * @param event - the membership event for the (new) member. Used to emit.
+ * @returns the member, existing or newly created.
+ *
+ * @remarks
+ * Fires {@link RoomStateEvent.NewMember}
+ */
+ getOrCreateMember(userId, event) {
+ let member = this.members[userId];
+ if (!member) {
+ member = new _roomMember.RoomMember(this.roomId, userId);
+ // add member to members before emitting any events,
+ // as event handlers often lookup the member
+ this.members[userId] = member;
+ this.emit(RoomStateEvent.NewMember, event, this, member);
+ }
+ return member;
+ }
+ setStateEvent(event) {
+ if (!this.events.has(event.getType())) {
+ this.events.set(event.getType(), new Map());
+ }
+ this.events.get(event.getType()).set(event.getStateKey(), event);
+ }
+
+ /**
+ * @experimental
+ */
+ setBeacon(event) {
+ const beaconIdentifier = (0, _beacon.getBeaconInfoIdentifier)(event);
+ if (this.beacons.has(beaconIdentifier)) {
+ const beacon = this.beacons.get(beaconIdentifier);
+ if (event.isRedacted()) {
+ var _event$getRedactionEv;
+ if (beacon.beaconInfoId === ((_event$getRedactionEv = event.getRedactionEvent()) === null || _event$getRedactionEv === void 0 ? void 0 : _event$getRedactionEv.redacts)) {
+ beacon.destroy();
+ this.beacons.delete(beaconIdentifier);
+ }
+ return;
+ }
+ return beacon.update(event);
+ }
+ if (event.isRedacted()) {
+ return;
+ }
+ const beacon = new _beacon.Beacon(event);
+ this.reEmitter.reEmit(beacon, [_beacon.BeaconEvent.New, _beacon.BeaconEvent.Update, _beacon.BeaconEvent.Destroy, _beacon.BeaconEvent.LivenessChange]);
+ this.emit(_beacon.BeaconEvent.New, event, beacon);
+ beacon.on(_beacon.BeaconEvent.LivenessChange, this.onBeaconLivenessChange.bind(this));
+ beacon.on(_beacon.BeaconEvent.Destroy, this.onBeaconLivenessChange.bind(this));
+ this.beacons.set(beacon.identifier, beacon);
+ }
+
+ /**
+ * @experimental
+ * Check liveness of room beacons
+ * emit RoomStateEvent.BeaconLiveness event
+ */
+ onBeaconLivenessChange() {
+ this._liveBeaconIds = Array.from(this.beacons.values()).filter(beacon => beacon.isLive).map(beacon => beacon.identifier);
+ this.emit(RoomStateEvent.BeaconLiveness, this, this.hasLiveBeacons);
+ }
+ getStateEventMatching(event) {
+ var _this$events$get$get, _this$events$get;
+ return (_this$events$get$get = (_this$events$get = this.events.get(event.getType())) === null || _this$events$get === void 0 ? void 0 : _this$events$get.get(event.getStateKey())) !== null && _this$events$get$get !== void 0 ? _this$events$get$get : null;
+ }
+ updateMember(member) {
+ // this member may have a power level already, so set it.
+ const pwrLvlEvent = this.getStateEvents(_event.EventType.RoomPowerLevels, "");
+ if (pwrLvlEvent) {
+ member.setPowerLevelEvent(pwrLvlEvent);
+ }
+
+ // blow away the sentinel which is now outdated
+ delete this.sentinels[member.userId];
+ this.members[member.userId] = member;
+ this.joinedMemberCount = null;
+ this.invitedMemberCount = null;
+ }
+
+ /**
+ * Get the out-of-band members loading state, whether loading is needed or not.
+ * Note that loading might be in progress and hence isn't needed.
+ * @returns whether or not the members of this room need to be loaded
+ */
+ needsOutOfBandMembers() {
+ return this.oobMemberFlags.status === OobStatus.NotStarted;
+ }
+
+ /**
+ * Check if loading of out-of-band-members has completed
+ *
+ * @returns true if the full membership list of this room has been loaded. False if it is not started or is in
+ * progress.
+ */
+ outOfBandMembersReady() {
+ return this.oobMemberFlags.status === OobStatus.Finished;
+ }
+
+ /**
+ * Mark this room state as waiting for out-of-band members,
+ * ensuring it doesn't ask for them to be requested again
+ * through needsOutOfBandMembers
+ */
+ markOutOfBandMembersStarted() {
+ if (this.oobMemberFlags.status !== OobStatus.NotStarted) {
+ return;
+ }
+ this.oobMemberFlags.status = OobStatus.InProgress;
+ }
+
+ /**
+ * Mark this room state as having failed to fetch out-of-band members
+ */
+ markOutOfBandMembersFailed() {
+ if (this.oobMemberFlags.status !== OobStatus.InProgress) {
+ return;
+ }
+ this.oobMemberFlags.status = OobStatus.NotStarted;
+ }
+
+ /**
+ * Clears the loaded out-of-band members
+ */
+ clearOutOfBandMembers() {
+ let count = 0;
+ Object.keys(this.members).forEach(userId => {
+ const member = this.members[userId];
+ if (member.isOutOfBand()) {
+ ++count;
+ delete this.members[userId];
+ }
+ });
+ _logger.logger.log(`LL: RoomState removed ${count} members...`);
+ this.oobMemberFlags.status = OobStatus.NotStarted;
+ }
+
+ /**
+ * Sets the loaded out-of-band members.
+ * @param stateEvents - array of membership state events
+ */
+ setOutOfBandMembers(stateEvents) {
+ _logger.logger.log(`LL: RoomState about to set ${stateEvents.length} OOB members ...`);
+ if (this.oobMemberFlags.status !== OobStatus.InProgress) {
+ return;
+ }
+ _logger.logger.log(`LL: RoomState put in finished state ...`);
+ this.oobMemberFlags.status = OobStatus.Finished;
+ stateEvents.forEach(e => this.setOutOfBandMember(e));
+ this.emit(RoomStateEvent.Update, this);
+ }
+
+ /**
+ * Sets a single out of band member, used by both setOutOfBandMembers and clone
+ * @param stateEvent - membership state event
+ */
+ setOutOfBandMember(stateEvent) {
+ if (stateEvent.getType() !== _event.EventType.RoomMember) {
+ return;
+ }
+ const userId = stateEvent.getStateKey();
+ const existingMember = this.getMember(userId);
+ // never replace members received as part of the sync
+ if (existingMember && !existingMember.isOutOfBand()) {
+ return;
+ }
+ const member = this.getOrCreateMember(userId, stateEvent);
+ member.setMembershipEvent(stateEvent, this);
+ // needed to know which members need to be stored seperately
+ // as they are not part of the sync accumulator
+ // this is cleared by setMembershipEvent so when it's updated through /sync
+ member.markOutOfBand();
+ this.updateDisplayNameCache(member.userId, member.name);
+ this.setStateEvent(stateEvent);
+ this.updateMember(member);
+ this.emit(RoomStateEvent.Members, stateEvent, this, member);
+ }
+
+ /**
+ * Set the current typing event for this room.
+ * @param event - The typing event
+ */
+ setTypingEvent(event) {
+ Object.values(this.members).forEach(function (member) {
+ member.setTypingEvent(event);
+ });
+ }
+
+ /**
+ * Get the m.room.member event which has the given third party invite token.
+ *
+ * @param token - The token
+ * @returns The m.room.member event or null
+ */
+ getInviteForThreePidToken(token) {
+ return this.tokenToInvite[token] || null;
+ }
+
+ /**
+ * Update the last modified time to the current time.
+ */
+ updateModifiedTime() {
+ this.modified = Date.now();
+ }
+
+ /**
+ * Get the timestamp when this room state was last updated. This timestamp is
+ * updated when this object has received new state events.
+ * @returns The timestamp
+ */
+ getLastModifiedTime() {
+ return this.modified;
+ }
+
+ /**
+ * Get user IDs with the specified or similar display names.
+ * @param displayName - The display name to get user IDs from.
+ * @returns An array of user IDs or an empty array.
+ */
+ getUserIdsWithDisplayName(displayName) {
+ var _this$displayNameToUs;
+ return (_this$displayNameToUs = this.displayNameToUserIds.get(utils.removeHiddenChars(displayName))) !== null && _this$displayNameToUs !== void 0 ? _this$displayNameToUs : [];
+ }
+
+ /**
+ * Returns true if userId is in room, event is not redacted and either sender of
+ * mxEvent or has power level sufficient to redact events other than their own.
+ * @param mxEvent - The event to test permission for
+ * @param userId - The user ID of the user to test permission for
+ * @returns true if the given used ID can redact given event
+ */
+ maySendRedactionForEvent(mxEvent, userId) {
+ const member = this.getMember(userId);
+ if (!member || member.membership === "leave") return false;
+ if (mxEvent.status || mxEvent.isRedacted()) return false;
+
+ // The user may have been the sender, but they can't redact their own message
+ // if redactions are blocked.
+ const canRedact = this.maySendEvent(_event.EventType.RoomRedaction, userId);
+ if (mxEvent.getSender() === userId) return canRedact;
+ return this.hasSufficientPowerLevelFor("redact", member.powerLevel);
+ }
+
+ /**
+ * Returns true if the given power level is sufficient for action
+ * @param action - The type of power level to check
+ * @param powerLevel - The power level of the member
+ * @returns true if the given power level is sufficient
+ */
+ hasSufficientPowerLevelFor(action, powerLevel) {
+ const powerLevelsEvent = this.getStateEvents(_event.EventType.RoomPowerLevels, "");
+ let powerLevels = {};
+ if (powerLevelsEvent) {
+ powerLevels = powerLevelsEvent.getContent();
+ }
+ let requiredLevel = 50;
+ if (utils.isNumber(powerLevels[action])) {
+ requiredLevel = powerLevels[action];
+ }
+ return powerLevel >= requiredLevel;
+ }
+
+ /**
+ * Short-form for maySendEvent('m.room.message', userId)
+ * @param userId - The user ID of the user to test permission for
+ * @returns true if the given user ID should be permitted to send
+ * message events into the given room.
+ */
+ maySendMessage(userId) {
+ return this.maySendEventOfType(_event.EventType.RoomMessage, userId, false);
+ }
+
+ /**
+ * Returns true if the given user ID has permission to send a normal
+ * event of type `eventType` into this room.
+ * @param eventType - The type of event to test
+ * @param userId - The user ID of the user to test permission for
+ * @returns true if the given user ID should be permitted to send
+ * the given type of event into this room,
+ * according to the room's state.
+ */
+ maySendEvent(eventType, userId) {
+ return this.maySendEventOfType(eventType, userId, false);
+ }
+
+ /**
+ * Returns true if the given MatrixClient has permission to send a state
+ * event of type `stateEventType` into this room.
+ * @param stateEventType - The type of state events to test
+ * @param cli - The client to test permission for
+ * @returns true if the given client should be permitted to send
+ * the given type of state event into this room,
+ * according to the room's state.
+ */
+ mayClientSendStateEvent(stateEventType, cli) {
+ if (cli.isGuest() || !cli.credentials.userId) {
+ return false;
+ }
+ return this.maySendStateEvent(stateEventType, cli.credentials.userId);
+ }
+
+ /**
+ * Returns true if the given user ID has permission to send a state
+ * event of type `stateEventType` into this room.
+ * @param stateEventType - The type of state events to test
+ * @param userId - The user ID of the user to test permission for
+ * @returns true if the given user ID should be permitted to send
+ * the given type of state event into this room,
+ * according to the room's state.
+ */
+ maySendStateEvent(stateEventType, userId) {
+ return this.maySendEventOfType(stateEventType, userId, true);
+ }
+
+ /**
+ * Returns true if the given user ID has permission to send a normal or state
+ * event of type `eventType` into this room.
+ * @param eventType - The type of event to test
+ * @param userId - The user ID of the user to test permission for
+ * @param state - If true, tests if the user may send a state
+ event of this type. Otherwise tests whether
+ they may send a regular event.
+ * @returns true if the given user ID should be permitted to send
+ * the given type of event into this room,
+ * according to the room's state.
+ */
+ maySendEventOfType(eventType, userId, state) {
+ const powerLevelsEvent = this.getStateEvents(_event.EventType.RoomPowerLevels, "");
+ let powerLevels;
+ let eventsLevels = {};
+ let stateDefault = 0;
+ let eventsDefault = 0;
+ let powerLevel = 0;
+ if (powerLevelsEvent) {
+ powerLevels = powerLevelsEvent.getContent();
+ eventsLevels = powerLevels.events || {};
+ if (Number.isSafeInteger(powerLevels.state_default)) {
+ stateDefault = powerLevels.state_default;
+ } else {
+ stateDefault = 50;
+ }
+ const userPowerLevel = powerLevels.users && powerLevels.users[userId];
+ if (Number.isSafeInteger(userPowerLevel)) {
+ powerLevel = userPowerLevel;
+ } else if (Number.isSafeInteger(powerLevels.users_default)) {
+ powerLevel = powerLevels.users_default;
+ }
+ if (Number.isSafeInteger(powerLevels.events_default)) {
+ eventsDefault = powerLevels.events_default;
+ }
+ }
+ let requiredLevel = state ? stateDefault : eventsDefault;
+ if (Number.isSafeInteger(eventsLevels[eventType])) {
+ requiredLevel = eventsLevels[eventType];
+ }
+ return powerLevel >= requiredLevel;
+ }
+
+ /**
+ * Returns true if the given user ID has permission to trigger notification
+ * of type `notifLevelKey`
+ * @param notifLevelKey - The level of notification to test (eg. 'room')
+ * @param userId - The user ID of the user to test permission for
+ * @returns true if the given user ID has permission to trigger a
+ * notification of this type.
+ */
+ mayTriggerNotifOfType(notifLevelKey, userId) {
+ const member = this.getMember(userId);
+ if (!member) {
+ return false;
+ }
+ const powerLevelsEvent = this.getStateEvents(_event.EventType.RoomPowerLevels, "");
+ let notifLevel = 50;
+ if (powerLevelsEvent && powerLevelsEvent.getContent() && powerLevelsEvent.getContent().notifications && utils.isNumber(powerLevelsEvent.getContent().notifications[notifLevelKey])) {
+ notifLevel = powerLevelsEvent.getContent().notifications[notifLevelKey];
+ }
+ return member.powerLevel >= notifLevel;
+ }
+
+ /**
+ * Returns the join rule based on the m.room.join_rule state event, defaulting to `invite`.
+ * @returns the join_rule applied to this room
+ */
+ getJoinRule() {
+ var _joinRuleEvent$getCon;
+ const joinRuleEvent = this.getStateEvents(_event.EventType.RoomJoinRules, "");
+ const joinRuleContent = (_joinRuleEvent$getCon = joinRuleEvent === null || joinRuleEvent === void 0 ? void 0 : joinRuleEvent.getContent()) !== null && _joinRuleEvent$getCon !== void 0 ? _joinRuleEvent$getCon : {};
+ return joinRuleContent["join_rule"] || _partials.JoinRule.Invite;
+ }
+
+ /**
+ * Returns the history visibility based on the m.room.history_visibility state event, defaulting to `shared`.
+ * @returns the history_visibility applied to this room
+ */
+ getHistoryVisibility() {
+ var _historyVisibilityEve;
+ const historyVisibilityEvent = this.getStateEvents(_event.EventType.RoomHistoryVisibility, "");
+ const historyVisibilityContent = (_historyVisibilityEve = historyVisibilityEvent === null || historyVisibilityEvent === void 0 ? void 0 : historyVisibilityEvent.getContent()) !== null && _historyVisibilityEve !== void 0 ? _historyVisibilityEve : {};
+ return historyVisibilityContent["history_visibility"] || _partials.HistoryVisibility.Shared;
+ }
+
+ /**
+ * Returns the guest access based on the m.room.guest_access state event, defaulting to `shared`.
+ * @returns the guest_access applied to this room
+ */
+ getGuestAccess() {
+ var _guestAccessEvent$get;
+ const guestAccessEvent = this.getStateEvents(_event.EventType.RoomGuestAccess, "");
+ const guestAccessContent = (_guestAccessEvent$get = guestAccessEvent === null || guestAccessEvent === void 0 ? void 0 : guestAccessEvent.getContent()) !== null && _guestAccessEvent$get !== void 0 ? _guestAccessEvent$get : {};
+ return guestAccessContent["guest_access"] || _partials.GuestAccess.Forbidden;
+ }
+
+ /**
+ * Find the predecessor room based on this room state.
+ *
+ * @param msc3946ProcessDynamicPredecessor - if true, look for an
+ * m.room.predecessor state event and use it if found (MSC3946).
+ * @returns null if this room has no predecessor. Otherwise, returns
+ * the roomId, last eventId and viaServers of the predecessor room.
+ *
+ * If msc3946ProcessDynamicPredecessor is true, use m.predecessor events
+ * as well as m.room.create events to find predecessors.
+ *
+ * Note: if an m.predecessor event is used, eventId may be undefined
+ * since last_known_event_id is optional.
+ *
+ * Note: viaServers may be undefined, and will definitely be undefined if
+ * this predecessor comes from a RoomCreate event (rather than a
+ * RoomPredecessor, which has the optional via_servers property).
+ */
+ findPredecessor(msc3946ProcessDynamicPredecessor = false) {
+ // Note: the tests for this function are against Room.findPredecessor,
+ // which just calls through to here.
+
+ if (msc3946ProcessDynamicPredecessor) {
+ const predecessorEvent = this.getStateEvents(_event.EventType.RoomPredecessor, "");
+ if (predecessorEvent) {
+ const content = predecessorEvent.getContent();
+ const roomId = content.predecessor_room_id;
+ let eventId = content.last_known_event_id;
+ if (typeof eventId !== "string") {
+ eventId = undefined;
+ }
+ let viaServers = content.via_servers;
+ if (!Array.isArray(viaServers)) {
+ viaServers = undefined;
+ }
+ if (typeof roomId === "string") {
+ return {
+ roomId,
+ eventId,
+ viaServers
+ };
+ }
+ }
+ }
+ const createEvent = this.getStateEvents(_event.EventType.RoomCreate, "");
+ if (createEvent) {
+ const predecessor = createEvent.getContent()["predecessor"];
+ if (predecessor) {
+ const roomId = predecessor["room_id"];
+ if (typeof roomId === "string") {
+ let eventId = predecessor["event_id"];
+ if (typeof eventId !== "string" || eventId === "") {
+ eventId = undefined;
+ }
+ return {
+ roomId,
+ eventId
+ };
+ }
+ }
+ }
+ return null;
+ }
+ updateThirdPartyTokenCache(memberEvent) {
+ if (!memberEvent.getContent().third_party_invite) {
+ return;
+ }
+ const token = (memberEvent.getContent().third_party_invite.signed || {}).token;
+ if (!token) {
+ return;
+ }
+ const threePidInvite = this.getStateEvents(_event.EventType.RoomThirdPartyInvite, token);
+ if (!threePidInvite) {
+ return;
+ }
+ this.tokenToInvite[token] = memberEvent;
+ }
+ updateDisplayNameCache(userId, displayName) {
+ const oldName = this.userIdsToDisplayNames[userId];
+ delete this.userIdsToDisplayNames[userId];
+ if (oldName) {
+ // Remove the old name from the cache.
+ // We clobber the user_id > name lookup but the name -> [user_id] lookup
+ // means we need to remove that user ID from that array rather than nuking
+ // the lot.
+ const strippedOldName = utils.removeHiddenChars(oldName);
+ const existingUserIds = this.displayNameToUserIds.get(strippedOldName);
+ if (existingUserIds) {
+ // remove this user ID from this array
+ const filteredUserIDs = existingUserIds.filter(id => id !== userId);
+ this.displayNameToUserIds.set(strippedOldName, filteredUserIDs);
+ }
+ }
+ this.userIdsToDisplayNames[userId] = displayName;
+ const strippedDisplayname = displayName && utils.removeHiddenChars(displayName);
+ // an empty stripped displayname (undefined/'') will be set to MXID in room-member.js
+ if (strippedDisplayname) {
+ var _this$displayNameToUs2;
+ const arr = (_this$displayNameToUs2 = this.displayNameToUserIds.get(strippedDisplayname)) !== null && _this$displayNameToUs2 !== void 0 ? _this$displayNameToUs2 : [];
+ arr.push(userId);
+ this.displayNameToUserIds.set(strippedDisplayname, arr);
+ }
+ }
+}
+exports.RoomState = RoomState;
+//# sourceMappingURL=room-state.js.map \ No newline at end of file
diff --git a/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/room-state.js.map b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/room-state.js.map
new file mode 100644
index 0000000..60c587e
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/room-state.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"room-state.js","names":["_roomMember","require","_logger","utils","_interopRequireWildcard","_event","_event2","_partials","_typedEventEmitter","_beacon","_ReEmitter","_beacon2","_getRequireWildcardCache","nodeInterop","WeakMap","cacheBabelInterop","cacheNodeInterop","obj","__esModule","default","cache","has","get","newObj","hasPropertyDescriptor","Object","defineProperty","getOwnPropertyDescriptor","key","prototype","hasOwnProperty","call","desc","set","OobStatus","RoomStateEvent","exports","RoomState","TypedEventEmitter","constructor","roomId","oobMemberFlags","status","NotStarted","_defineProperty2","TypedReEmitter","Map","updateModifiedTime","getJoinedMemberCount","summaryJoinedMemberCount","joinedMemberCount","getMembers","reduce","count","m","membership","setJoinedMemberCount","getInvitedMemberCount","summaryInvitedMemberCount","invitedMemberCount","setInvitedMemberCount","values","members","getMembersExcept","excludedIds","filter","includes","userId","getMember","getSentinelMember","sentinel","sentinels","undefined","RoomMember","member","events","setMembershipEvent","getStateEvents","eventType","stateKey","Array","from","event","hasLiveBeacons","_this$liveBeaconIds","liveBeaconIds","length","_liveBeaconIds","clone","copy","forEach","eventsByStateKey","setStateEvents","Finished","isOutOfBand","_copy$getMember","markOutOfBand","setUnknownStateEvents","unknownStateEvents","getType","getStateKey","stateEvents","markerFoundOptions","getRoomId","isState","M_BEACON_INFO","matches","setBeacon","lastStateEvent","getStateEventMatching","setStateEvent","EventType","_event$getContent$dis","updateDisplayNameCache","getContent","displayname","updateThirdPartyTokenCache","emit","Events","onBeaconLivenessChange","avatar_url","getPrevContent","getOrCreateMember","updateMember","Members","RoomPowerLevels","oldLastModified","getLastModifiedTime","setPowerLevelEvent","UNSTABLE_MSC2716_MARKER","Marker","Update","processBeaconEvents","matrixClient","beacons","size","beaconByEventIdDict","dict","beacon","beaconInfoId","processBeaconRelation","beaconInfoEventId","M_BEACON","addLocations","_event$getRelation","relatedToEventId","getRelation","event_id","isEncrypted","decryptEventIfNeeded","isDecryptionFailure","once","MatrixEventEvent","Decrypted","NewMember","beaconIdentifier","getBeaconInfoIdentifier","isRedacted","_event$getRedactionEv","getRedactionEvent","redacts","destroy","delete","update","Beacon","reEmitter","reEmit","BeaconEvent","New","Destroy","LivenessChange","on","bind","identifier","isLive","map","BeaconLiveness","_this$events$get$get","_this$events$get","pwrLvlEvent","needsOutOfBandMembers","outOfBandMembersReady","markOutOfBandMembersStarted","InProgress","markOutOfBandMembersFailed","clearOutOfBandMembers","keys","logger","log","setOutOfBandMembers","e","setOutOfBandMember","stateEvent","existingMember","name","setTypingEvent","getInviteForThreePidToken","token","tokenToInvite","modified","Date","now","getUserIdsWithDisplayName","displayName","_this$displayNameToUs","displayNameToUserIds","removeHiddenChars","maySendRedactionForEvent","mxEvent","canRedact","maySendEvent","RoomRedaction","getSender","hasSufficientPowerLevelFor","powerLevel","action","powerLevelsEvent","powerLevels","requiredLevel","isNumber","maySendMessage","maySendEventOfType","RoomMessage","mayClientSendStateEvent","stateEventType","cli","isGuest","credentials","maySendStateEvent","state","eventsLevels","stateDefault","eventsDefault","Number","isSafeInteger","state_default","userPowerLevel","users","users_default","events_default","mayTriggerNotifOfType","notifLevelKey","notifLevel","notifications","getJoinRule","_joinRuleEvent$getCon","joinRuleEvent","RoomJoinRules","joinRuleContent","JoinRule","Invite","getHistoryVisibility","_historyVisibilityEve","historyVisibilityEvent","RoomHistoryVisibility","historyVisibilityContent","HistoryVisibility","Shared","getGuestAccess","_guestAccessEvent$get","guestAccessEvent","RoomGuestAccess","guestAccessContent","GuestAccess","Forbidden","findPredecessor","msc3946ProcessDynamicPredecessor","predecessorEvent","RoomPredecessor","content","predecessor_room_id","eventId","last_known_event_id","viaServers","via_servers","isArray","createEvent","RoomCreate","predecessor","memberEvent","third_party_invite","signed","threePidInvite","RoomThirdPartyInvite","oldName","userIdsToDisplayNames","strippedOldName","existingUserIds","filteredUserIDs","id","strippedDisplayname","_this$displayNameToUs2","arr","push"],"sources":["../../src/models/room-state.ts"],"sourcesContent":["/*\nCopyright 2015 - 2021 The Matrix.org Foundation C.I.C.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n*/\n\nimport { RoomMember } from \"./room-member\";\nimport { logger } from \"../logger\";\nimport * as utils from \"../utils\";\nimport { EventType, UNSTABLE_MSC2716_MARKER } from \"../@types/event\";\nimport { IEvent, MatrixEvent, MatrixEventEvent } from \"./event\";\nimport { MatrixClient } from \"../client\";\nimport { GuestAccess, HistoryVisibility, IJoinRuleEventContent, JoinRule } from \"../@types/partials\";\nimport { TypedEventEmitter } from \"./typed-event-emitter\";\nimport { Beacon, BeaconEvent, BeaconEventHandlerMap, getBeaconInfoIdentifier, BeaconIdentifier } from \"./beacon\";\nimport { TypedReEmitter } from \"../ReEmitter\";\nimport { M_BEACON, M_BEACON_INFO } from \"../@types/beacon\";\n\nexport interface IMarkerFoundOptions {\n /** Whether the timeline was empty before the marker event arrived in the\n * room. This could be happen in a variety of cases:\n * 1. From the initial sync\n * 2. It's the first state we're seeing after joining the room\n * 3. Or whether it's coming from `syncFromCache`\n *\n * A marker event refers to `UNSTABLE_MSC2716_MARKER` and indicates that\n * history was imported somewhere back in time. It specifically points to an\n * MSC2716 insertion event where the history was imported at. Marker events\n * are sent as state events so they are easily discoverable by clients and\n * homeservers and don't get lost in timeline gaps.\n */\n timelineWasEmpty?: boolean;\n}\n\n// possible statuses for out-of-band member loading\nenum OobStatus {\n NotStarted,\n InProgress,\n Finished,\n}\n\nexport interface IPowerLevelsContent {\n users?: Record<string, number>;\n events?: Record<string, number>;\n // eslint-disable-next-line camelcase\n users_default?: number;\n // eslint-disable-next-line camelcase\n events_default?: number;\n // eslint-disable-next-line camelcase\n state_default?: number;\n ban?: number;\n kick?: number;\n redact?: number;\n}\n\nexport enum RoomStateEvent {\n Events = \"RoomState.events\",\n Members = \"RoomState.members\",\n NewMember = \"RoomState.newMember\",\n Update = \"RoomState.update\", // signals batches of updates without specificity\n BeaconLiveness = \"RoomState.BeaconLiveness\",\n Marker = \"RoomState.Marker\",\n}\n\nexport type RoomStateEventHandlerMap = {\n /**\n * Fires whenever the event dictionary in room state is updated.\n * @param event - The matrix event which caused this event to fire.\n * @param state - The room state whose RoomState.events dictionary\n * was updated.\n * @param prevEvent - The event being replaced by the new state, if\n * known. Note that this can differ from `getPrevContent()` on the new state event\n * as this is the store's view of the last state, not the previous state provided\n * by the server.\n * @example\n * ```\n * matrixClient.on(\"RoomState.events\", function(event, state, prevEvent){\n * var newStateEvent = event;\n * });\n * ```\n */\n [RoomStateEvent.Events]: (event: MatrixEvent, state: RoomState, lastStateEvent: MatrixEvent | null) => void;\n /**\n * Fires whenever a member in the members dictionary is updated in any way.\n * @param event - The matrix event which caused this event to fire.\n * @param state - The room state whose RoomState.members dictionary\n * was updated.\n * @param member - The room member that was updated.\n * @example\n * ```\n * matrixClient.on(\"RoomState.members\", function(event, state, member){\n * var newMembershipState = member.membership;\n * });\n * ```\n */\n [RoomStateEvent.Members]: (event: MatrixEvent, state: RoomState, member: RoomMember) => void;\n /**\n * Fires whenever a member is added to the members dictionary. The RoomMember\n * will not be fully populated yet (e.g. no membership state) but will already\n * be available in the members dictionary.\n * @param event - The matrix event which caused this event to fire.\n * @param state - The room state whose RoomState.members dictionary\n * was updated with a new entry.\n * @param member - The room member that was added.\n * @example\n * ```\n * matrixClient.on(\"RoomState.newMember\", function(event, state, member){\n * // add event listeners on 'member'\n * });\n * ```\n */\n [RoomStateEvent.NewMember]: (event: MatrixEvent, state: RoomState, member: RoomMember) => void;\n [RoomStateEvent.Update]: (state: RoomState) => void;\n [RoomStateEvent.BeaconLiveness]: (state: RoomState, hasLiveBeacons: boolean) => void;\n [RoomStateEvent.Marker]: (event: MatrixEvent, setStateOptions?: IMarkerFoundOptions) => void;\n [BeaconEvent.New]: (event: MatrixEvent, beacon: Beacon) => void;\n};\n\ntype EmittedEvents = RoomStateEvent | BeaconEvent;\ntype EventHandlerMap = RoomStateEventHandlerMap & BeaconEventHandlerMap;\n\nexport class RoomState extends TypedEventEmitter<EmittedEvents, EventHandlerMap> {\n public readonly reEmitter = new TypedReEmitter<EmittedEvents, EventHandlerMap>(this);\n private sentinels: Record<string, RoomMember> = {}; // userId: RoomMember\n // stores fuzzy matches to a list of userIDs (applies utils.removeHiddenChars to keys)\n private displayNameToUserIds = new Map<string, string[]>();\n private userIdsToDisplayNames: Record<string, string> = {};\n private tokenToInvite: Record<string, MatrixEvent> = {}; // 3pid invite state_key to m.room.member invite\n private joinedMemberCount: number | null = null; // cache of the number of joined members\n // joined members count from summary api\n // once set, we know the server supports the summary api\n // and we should only trust that\n // we could also only trust that before OOB members\n // are loaded but doesn't seem worth the hassle atm\n private summaryJoinedMemberCount: number | null = null;\n // same for invited member count\n private invitedMemberCount: number | null = null;\n private summaryInvitedMemberCount: number | null = null;\n private modified = -1;\n\n // XXX: Should be read-only\n // The room member dictionary, keyed on the user's ID.\n public members: Record<string, RoomMember> = {}; // userId: RoomMember\n // The state events dictionary, keyed on the event type and then the state_key value.\n public events = new Map<string, Map<string, MatrixEvent>>(); // Map<eventType, Map<stateKey, MatrixEvent>>\n // The pagination token for this state.\n public paginationToken: string | null = null;\n\n public readonly beacons = new Map<BeaconIdentifier, Beacon>();\n private _liveBeaconIds: BeaconIdentifier[] = [];\n\n /**\n * Construct room state.\n *\n * Room State represents the state of the room at a given point.\n * It can be mutated by adding state events to it.\n * There are two types of room member associated with a state event:\n * normal member objects (accessed via getMember/getMembers) which mutate\n * with the state to represent the current state of that room/user, e.g.\n * the object returned by `getMember('@bob:example.com')` will mutate to\n * get a different display name if Bob later changes his display name\n * in the room.\n * There are also 'sentinel' members (accessed via getSentinelMember).\n * These also represent the state of room members at the point in time\n * represented by the RoomState object, but unlike objects from getMember,\n * sentinel objects will always represent the room state as at the time\n * getSentinelMember was called, so if Bob subsequently changes his display\n * name, a room member object previously acquired with getSentinelMember\n * will still have his old display name. Calling getSentinelMember again\n * after the display name change will return a new RoomMember object\n * with Bob's new display name.\n *\n * @param roomId - Optional. The ID of the room which has this state.\n * If none is specified it just tracks paginationTokens, useful for notifTimelineSet\n * @param oobMemberFlags - Optional. The state of loading out of bound members.\n * As the timeline might get reset while they are loading, this state needs to be inherited\n * and shared when the room state is cloned for the new timeline.\n * This should only be passed from clone.\n */\n public constructor(public readonly roomId: string, private oobMemberFlags = { status: OobStatus.NotStarted }) {\n super();\n this.updateModifiedTime();\n }\n\n /**\n * Returns the number of joined members in this room\n * This method caches the result.\n * @returns The number of members in this room whose membership is 'join'\n */\n public getJoinedMemberCount(): number {\n if (this.summaryJoinedMemberCount !== null) {\n return this.summaryJoinedMemberCount;\n }\n if (this.joinedMemberCount === null) {\n this.joinedMemberCount = this.getMembers().reduce((count, m) => {\n return m.membership === \"join\" ? count + 1 : count;\n }, 0);\n }\n return this.joinedMemberCount;\n }\n\n /**\n * Set the joined member count explicitly (like from summary part of the sync response)\n * @param count - the amount of joined members\n */\n public setJoinedMemberCount(count: number): void {\n this.summaryJoinedMemberCount = count;\n }\n\n /**\n * Returns the number of invited members in this room\n * @returns The number of members in this room whose membership is 'invite'\n */\n public getInvitedMemberCount(): number {\n if (this.summaryInvitedMemberCount !== null) {\n return this.summaryInvitedMemberCount;\n }\n if (this.invitedMemberCount === null) {\n this.invitedMemberCount = this.getMembers().reduce((count, m) => {\n return m.membership === \"invite\" ? count + 1 : count;\n }, 0);\n }\n return this.invitedMemberCount;\n }\n\n /**\n * Set the amount of invited members in this room\n * @param count - the amount of invited members\n */\n public setInvitedMemberCount(count: number): void {\n this.summaryInvitedMemberCount = count;\n }\n\n /**\n * Get all RoomMembers in this room.\n * @returns A list of RoomMembers.\n */\n public getMembers(): RoomMember[] {\n return Object.values(this.members);\n }\n\n /**\n * Get all RoomMembers in this room, excluding the user IDs provided.\n * @param excludedIds - The user IDs to exclude.\n * @returns A list of RoomMembers.\n */\n public getMembersExcept(excludedIds: string[]): RoomMember[] {\n return this.getMembers().filter((m) => !excludedIds.includes(m.userId));\n }\n\n /**\n * Get a room member by their user ID.\n * @param userId - The room member's user ID.\n * @returns The member or null if they do not exist.\n */\n public getMember(userId: string): RoomMember | null {\n return this.members[userId] || null;\n }\n\n /**\n * Get a room member whose properties will not change with this room state. You\n * typically want this if you want to attach a RoomMember to a MatrixEvent which\n * may no longer be represented correctly by Room.currentState or Room.oldState.\n * The term 'sentinel' refers to the fact that this RoomMember is an unchanging\n * guardian for state at this particular point in time.\n * @param userId - The room member's user ID.\n * @returns The member or null if they do not exist.\n */\n public getSentinelMember(userId: string): RoomMember | null {\n if (!userId) return null;\n let sentinel = this.sentinels[userId];\n\n if (sentinel === undefined) {\n sentinel = new RoomMember(this.roomId, userId);\n const member = this.members[userId];\n if (member?.events.member) {\n sentinel.setMembershipEvent(member.events.member, this);\n }\n this.sentinels[userId] = sentinel;\n }\n return sentinel;\n }\n\n /**\n * Get state events from the state of the room.\n * @param eventType - The event type of the state event.\n * @param stateKey - Optional. The state_key of the state event. If\n * this is `undefined` then all matching state events will be\n * returned.\n * @returns A list of events if state_key was\n * `undefined`, else a single event (or null if no match found).\n */\n public getStateEvents(eventType: EventType | string): MatrixEvent[];\n public getStateEvents(eventType: EventType | string, stateKey: string): MatrixEvent | null;\n public getStateEvents(eventType: EventType | string, stateKey?: string): MatrixEvent[] | MatrixEvent | null {\n if (!this.events.has(eventType)) {\n // no match\n return stateKey === undefined ? [] : null;\n }\n if (stateKey === undefined) {\n // return all values\n return Array.from(this.events.get(eventType)!.values());\n }\n const event = this.events.get(eventType)!.get(stateKey);\n return event ? event : null;\n }\n\n public get hasLiveBeacons(): boolean {\n return !!this.liveBeaconIds?.length;\n }\n\n public get liveBeaconIds(): BeaconIdentifier[] {\n return this._liveBeaconIds;\n }\n\n /**\n * Creates a copy of this room state so that mutations to either won't affect the other.\n * @returns the copy of the room state\n */\n public clone(): RoomState {\n const copy = new RoomState(this.roomId, this.oobMemberFlags);\n\n // Ugly hack: because setStateEvents will mark\n // members as susperseding future out of bound members\n // if loading is in progress (through oobMemberFlags)\n // since these are not new members, we're merely copying them\n // set the status to not started\n // after copying, we set back the status\n const status = this.oobMemberFlags.status;\n this.oobMemberFlags.status = OobStatus.NotStarted;\n\n Array.from(this.events.values()).forEach((eventsByStateKey) => {\n copy.setStateEvents(Array.from(eventsByStateKey.values()));\n });\n\n // Ugly hack: see above\n this.oobMemberFlags.status = status;\n\n if (this.summaryInvitedMemberCount !== null) {\n copy.setInvitedMemberCount(this.getInvitedMemberCount());\n }\n if (this.summaryJoinedMemberCount !== null) {\n copy.setJoinedMemberCount(this.getJoinedMemberCount());\n }\n\n // copy out of band flags if needed\n if (this.oobMemberFlags.status == OobStatus.Finished) {\n // copy markOutOfBand flags\n this.getMembers().forEach((member) => {\n if (member.isOutOfBand()) {\n copy.getMember(member.userId)?.markOutOfBand();\n }\n });\n }\n\n return copy;\n }\n\n /**\n * Add previously unknown state events.\n * When lazy loading members while back-paginating,\n * the relevant room state for the timeline chunk at the end\n * of the chunk can be set with this method.\n * @param events - state events to prepend\n */\n public setUnknownStateEvents(events: MatrixEvent[]): void {\n const unknownStateEvents = events.filter((event) => {\n return !this.events.has(event.getType()) || !this.events.get(event.getType())!.has(event.getStateKey()!);\n });\n\n this.setStateEvents(unknownStateEvents);\n }\n\n /**\n * Add an array of one or more state MatrixEvents, overwriting any existing\n * state with the same `{type, stateKey}` tuple. Will fire \"RoomState.events\"\n * for every event added. May fire \"RoomState.members\" if there are\n * `m.room.member` events. May fire \"RoomStateEvent.Marker\" if there are\n * `UNSTABLE_MSC2716_MARKER` events.\n * @param stateEvents - a list of state events for this room.\n *\n * @remarks\n * Fires {@link RoomStateEvent.Members}\n * Fires {@link RoomStateEvent.NewMember}\n * Fires {@link RoomStateEvent.Events}\n * Fires {@link RoomStateEvent.Marker}\n */\n public setStateEvents(stateEvents: MatrixEvent[], markerFoundOptions?: IMarkerFoundOptions): void {\n this.updateModifiedTime();\n\n // update the core event dict\n stateEvents.forEach((event) => {\n if (event.getRoomId() !== this.roomId || !event.isState()) return;\n\n if (M_BEACON_INFO.matches(event.getType())) {\n this.setBeacon(event);\n }\n\n const lastStateEvent = this.getStateEventMatching(event);\n this.setStateEvent(event);\n if (event.getType() === EventType.RoomMember) {\n this.updateDisplayNameCache(event.getStateKey()!, event.getContent().displayname ?? \"\");\n this.updateThirdPartyTokenCache(event);\n }\n this.emit(RoomStateEvent.Events, event, this, lastStateEvent);\n });\n\n this.onBeaconLivenessChange();\n // update higher level data structures. This needs to be done AFTER the\n // core event dict as these structures may depend on other state events in\n // the given array (e.g. disambiguating display names in one go to do both\n // clashing names rather than progressively which only catches 1 of them).\n stateEvents.forEach((event) => {\n if (event.getRoomId() !== this.roomId || !event.isState()) return;\n\n if (event.getType() === EventType.RoomMember) {\n const userId = event.getStateKey()!;\n\n // leave events apparently elide the displayname or avatar_url,\n // so let's fake one up so that we don't leak user ids\n // into the timeline\n if (event.getContent().membership === \"leave\" || event.getContent().membership === \"ban\") {\n event.getContent().avatar_url = event.getContent().avatar_url || event.getPrevContent().avatar_url;\n event.getContent().displayname =\n event.getContent().displayname || event.getPrevContent().displayname;\n }\n\n const member = this.getOrCreateMember(userId, event);\n member.setMembershipEvent(event, this);\n this.updateMember(member);\n this.emit(RoomStateEvent.Members, event, this, member);\n } else if (event.getType() === EventType.RoomPowerLevels) {\n // events with unknown state keys should be ignored\n // and should not aggregate onto members power levels\n if (event.getStateKey() !== \"\") {\n return;\n }\n const members = Object.values(this.members);\n members.forEach((member) => {\n // We only propagate `RoomState.members` event if the\n // power levels has been changed\n // large room suffer from large re-rendering especially when not needed\n const oldLastModified = member.getLastModifiedTime();\n member.setPowerLevelEvent(event);\n if (oldLastModified !== member.getLastModifiedTime()) {\n this.emit(RoomStateEvent.Members, event, this, member);\n }\n });\n\n // assume all our sentinels are now out-of-date\n this.sentinels = {};\n } else if (UNSTABLE_MSC2716_MARKER.matches(event.getType())) {\n this.emit(RoomStateEvent.Marker, event, markerFoundOptions);\n }\n });\n\n this.emit(RoomStateEvent.Update, this);\n }\n\n public async processBeaconEvents(events: MatrixEvent[], matrixClient: MatrixClient): Promise<void> {\n if (\n !events.length ||\n // discard locations if we have no beacons\n !this.beacons.size\n ) {\n return;\n }\n\n const beaconByEventIdDict = [...this.beacons.values()].reduce<Record<string, Beacon>>((dict, beacon) => {\n dict[beacon.beaconInfoId] = beacon;\n return dict;\n }, {});\n\n const processBeaconRelation = (beaconInfoEventId: string, event: MatrixEvent): void => {\n if (!M_BEACON.matches(event.getType())) {\n return;\n }\n\n const beacon = beaconByEventIdDict[beaconInfoEventId];\n\n if (beacon) {\n beacon.addLocations([event]);\n }\n };\n\n for (const event of events) {\n const relatedToEventId = event.getRelation()?.event_id;\n // not related to a beacon we know about; discard\n if (!relatedToEventId || !beaconByEventIdDict[relatedToEventId]) return;\n if (!M_BEACON.matches(event.getType()) && !event.isEncrypted()) return;\n\n try {\n await matrixClient.decryptEventIfNeeded(event);\n processBeaconRelation(relatedToEventId, event);\n } catch {\n if (event.isDecryptionFailure()) {\n // add an event listener for once the event is decrypted.\n event.once(MatrixEventEvent.Decrypted, async () => {\n processBeaconRelation(relatedToEventId, event);\n });\n }\n }\n }\n }\n\n /**\n * Looks up a member by the given userId, and if it doesn't exist,\n * create it and emit the `RoomState.newMember` event.\n * This method makes sure the member is added to the members dictionary\n * before emitting, as this is done from setStateEvents and setOutOfBandMember.\n * @param userId - the id of the user to look up\n * @param event - the membership event for the (new) member. Used to emit.\n * @returns the member, existing or newly created.\n *\n * @remarks\n * Fires {@link RoomStateEvent.NewMember}\n */\n private getOrCreateMember(userId: string, event: MatrixEvent): RoomMember {\n let member = this.members[userId];\n if (!member) {\n member = new RoomMember(this.roomId, userId);\n // add member to members before emitting any events,\n // as event handlers often lookup the member\n this.members[userId] = member;\n this.emit(RoomStateEvent.NewMember, event, this, member);\n }\n return member;\n }\n\n private setStateEvent(event: MatrixEvent): void {\n if (!this.events.has(event.getType())) {\n this.events.set(event.getType(), new Map());\n }\n this.events.get(event.getType())!.set(event.getStateKey()!, event);\n }\n\n /**\n * @experimental\n */\n private setBeacon(event: MatrixEvent): void {\n const beaconIdentifier = getBeaconInfoIdentifier(event);\n\n if (this.beacons.has(beaconIdentifier)) {\n const beacon = this.beacons.get(beaconIdentifier)!;\n\n if (event.isRedacted()) {\n if (beacon.beaconInfoId === (<IEvent>event.getRedactionEvent())?.redacts) {\n beacon.destroy();\n this.beacons.delete(beaconIdentifier);\n }\n return;\n }\n\n return beacon.update(event);\n }\n\n if (event.isRedacted()) {\n return;\n }\n\n const beacon = new Beacon(event);\n\n this.reEmitter.reEmit<BeaconEvent, BeaconEvent>(beacon, [\n BeaconEvent.New,\n BeaconEvent.Update,\n BeaconEvent.Destroy,\n BeaconEvent.LivenessChange,\n ]);\n\n this.emit(BeaconEvent.New, event, beacon);\n beacon.on(BeaconEvent.LivenessChange, this.onBeaconLivenessChange.bind(this));\n beacon.on(BeaconEvent.Destroy, this.onBeaconLivenessChange.bind(this));\n\n this.beacons.set(beacon.identifier, beacon);\n }\n\n /**\n * @experimental\n * Check liveness of room beacons\n * emit RoomStateEvent.BeaconLiveness event\n */\n private onBeaconLivenessChange(): void {\n this._liveBeaconIds = Array.from(this.beacons.values())\n .filter((beacon) => beacon.isLive)\n .map((beacon) => beacon.identifier);\n\n this.emit(RoomStateEvent.BeaconLiveness, this, this.hasLiveBeacons);\n }\n\n private getStateEventMatching(event: MatrixEvent): MatrixEvent | null {\n return this.events.get(event.getType())?.get(event.getStateKey()!) ?? null;\n }\n\n private updateMember(member: RoomMember): void {\n // this member may have a power level already, so set it.\n const pwrLvlEvent = this.getStateEvents(EventType.RoomPowerLevels, \"\");\n if (pwrLvlEvent) {\n member.setPowerLevelEvent(pwrLvlEvent);\n }\n\n // blow away the sentinel which is now outdated\n delete this.sentinels[member.userId];\n\n this.members[member.userId] = member;\n this.joinedMemberCount = null;\n this.invitedMemberCount = null;\n }\n\n /**\n * Get the out-of-band members loading state, whether loading is needed or not.\n * Note that loading might be in progress and hence isn't needed.\n * @returns whether or not the members of this room need to be loaded\n */\n public needsOutOfBandMembers(): boolean {\n return this.oobMemberFlags.status === OobStatus.NotStarted;\n }\n\n /**\n * Check if loading of out-of-band-members has completed\n *\n * @returns true if the full membership list of this room has been loaded. False if it is not started or is in\n * progress.\n */\n public outOfBandMembersReady(): boolean {\n return this.oobMemberFlags.status === OobStatus.Finished;\n }\n\n /**\n * Mark this room state as waiting for out-of-band members,\n * ensuring it doesn't ask for them to be requested again\n * through needsOutOfBandMembers\n */\n public markOutOfBandMembersStarted(): void {\n if (this.oobMemberFlags.status !== OobStatus.NotStarted) {\n return;\n }\n this.oobMemberFlags.status = OobStatus.InProgress;\n }\n\n /**\n * Mark this room state as having failed to fetch out-of-band members\n */\n public markOutOfBandMembersFailed(): void {\n if (this.oobMemberFlags.status !== OobStatus.InProgress) {\n return;\n }\n this.oobMemberFlags.status = OobStatus.NotStarted;\n }\n\n /**\n * Clears the loaded out-of-band members\n */\n public clearOutOfBandMembers(): void {\n let count = 0;\n Object.keys(this.members).forEach((userId) => {\n const member = this.members[userId];\n if (member.isOutOfBand()) {\n ++count;\n delete this.members[userId];\n }\n });\n logger.log(`LL: RoomState removed ${count} members...`);\n this.oobMemberFlags.status = OobStatus.NotStarted;\n }\n\n /**\n * Sets the loaded out-of-band members.\n * @param stateEvents - array of membership state events\n */\n public setOutOfBandMembers(stateEvents: MatrixEvent[]): void {\n logger.log(`LL: RoomState about to set ${stateEvents.length} OOB members ...`);\n if (this.oobMemberFlags.status !== OobStatus.InProgress) {\n return;\n }\n logger.log(`LL: RoomState put in finished state ...`);\n this.oobMemberFlags.status = OobStatus.Finished;\n stateEvents.forEach((e) => this.setOutOfBandMember(e));\n this.emit(RoomStateEvent.Update, this);\n }\n\n /**\n * Sets a single out of band member, used by both setOutOfBandMembers and clone\n * @param stateEvent - membership state event\n */\n private setOutOfBandMember(stateEvent: MatrixEvent): void {\n if (stateEvent.getType() !== EventType.RoomMember) {\n return;\n }\n const userId = stateEvent.getStateKey()!;\n const existingMember = this.getMember(userId);\n // never replace members received as part of the sync\n if (existingMember && !existingMember.isOutOfBand()) {\n return;\n }\n\n const member = this.getOrCreateMember(userId, stateEvent);\n member.setMembershipEvent(stateEvent, this);\n // needed to know which members need to be stored seperately\n // as they are not part of the sync accumulator\n // this is cleared by setMembershipEvent so when it's updated through /sync\n member.markOutOfBand();\n\n this.updateDisplayNameCache(member.userId, member.name);\n\n this.setStateEvent(stateEvent);\n this.updateMember(member);\n this.emit(RoomStateEvent.Members, stateEvent, this, member);\n }\n\n /**\n * Set the current typing event for this room.\n * @param event - The typing event\n */\n public setTypingEvent(event: MatrixEvent): void {\n Object.values(this.members).forEach(function (member) {\n member.setTypingEvent(event);\n });\n }\n\n /**\n * Get the m.room.member event which has the given third party invite token.\n *\n * @param token - The token\n * @returns The m.room.member event or null\n */\n public getInviteForThreePidToken(token: string): MatrixEvent | null {\n return this.tokenToInvite[token] || null;\n }\n\n /**\n * Update the last modified time to the current time.\n */\n private updateModifiedTime(): void {\n this.modified = Date.now();\n }\n\n /**\n * Get the timestamp when this room state was last updated. This timestamp is\n * updated when this object has received new state events.\n * @returns The timestamp\n */\n public getLastModifiedTime(): number {\n return this.modified;\n }\n\n /**\n * Get user IDs with the specified or similar display names.\n * @param displayName - The display name to get user IDs from.\n * @returns An array of user IDs or an empty array.\n */\n public getUserIdsWithDisplayName(displayName: string): string[] {\n return this.displayNameToUserIds.get(utils.removeHiddenChars(displayName)) ?? [];\n }\n\n /**\n * Returns true if userId is in room, event is not redacted and either sender of\n * mxEvent or has power level sufficient to redact events other than their own.\n * @param mxEvent - The event to test permission for\n * @param userId - The user ID of the user to test permission for\n * @returns true if the given used ID can redact given event\n */\n public maySendRedactionForEvent(mxEvent: MatrixEvent, userId: string): boolean {\n const member = this.getMember(userId);\n if (!member || member.membership === \"leave\") return false;\n\n if (mxEvent.status || mxEvent.isRedacted()) return false;\n\n // The user may have been the sender, but they can't redact their own message\n // if redactions are blocked.\n const canRedact = this.maySendEvent(EventType.RoomRedaction, userId);\n if (mxEvent.getSender() === userId) return canRedact;\n\n return this.hasSufficientPowerLevelFor(\"redact\", member.powerLevel);\n }\n\n /**\n * Returns true if the given power level is sufficient for action\n * @param action - The type of power level to check\n * @param powerLevel - The power level of the member\n * @returns true if the given power level is sufficient\n */\n public hasSufficientPowerLevelFor(action: \"ban\" | \"kick\" | \"redact\", powerLevel: number): boolean {\n const powerLevelsEvent = this.getStateEvents(EventType.RoomPowerLevels, \"\");\n\n let powerLevels: IPowerLevelsContent = {};\n if (powerLevelsEvent) {\n powerLevels = powerLevelsEvent.getContent();\n }\n\n let requiredLevel = 50;\n if (utils.isNumber(powerLevels[action])) {\n requiredLevel = powerLevels[action]!;\n }\n\n return powerLevel >= requiredLevel;\n }\n\n /**\n * Short-form for maySendEvent('m.room.message', userId)\n * @param userId - The user ID of the user to test permission for\n * @returns true if the given user ID should be permitted to send\n * message events into the given room.\n */\n public maySendMessage(userId: string): boolean {\n return this.maySendEventOfType(EventType.RoomMessage, userId, false);\n }\n\n /**\n * Returns true if the given user ID has permission to send a normal\n * event of type `eventType` into this room.\n * @param eventType - The type of event to test\n * @param userId - The user ID of the user to test permission for\n * @returns true if the given user ID should be permitted to send\n * the given type of event into this room,\n * according to the room's state.\n */\n public maySendEvent(eventType: EventType | string, userId: string): boolean {\n return this.maySendEventOfType(eventType, userId, false);\n }\n\n /**\n * Returns true if the given MatrixClient has permission to send a state\n * event of type `stateEventType` into this room.\n * @param stateEventType - The type of state events to test\n * @param cli - The client to test permission for\n * @returns true if the given client should be permitted to send\n * the given type of state event into this room,\n * according to the room's state.\n */\n public mayClientSendStateEvent(stateEventType: EventType | string, cli: MatrixClient): boolean {\n if (cli.isGuest() || !cli.credentials.userId) {\n return false;\n }\n return this.maySendStateEvent(stateEventType, cli.credentials.userId);\n }\n\n /**\n * Returns true if the given user ID has permission to send a state\n * event of type `stateEventType` into this room.\n * @param stateEventType - The type of state events to test\n * @param userId - The user ID of the user to test permission for\n * @returns true if the given user ID should be permitted to send\n * the given type of state event into this room,\n * according to the room's state.\n */\n public maySendStateEvent(stateEventType: EventType | string, userId: string): boolean {\n return this.maySendEventOfType(stateEventType, userId, true);\n }\n\n /**\n * Returns true if the given user ID has permission to send a normal or state\n * event of type `eventType` into this room.\n * @param eventType - The type of event to test\n * @param userId - The user ID of the user to test permission for\n * @param state - If true, tests if the user may send a state\n event of this type. Otherwise tests whether\n they may send a regular event.\n * @returns true if the given user ID should be permitted to send\n * the given type of event into this room,\n * according to the room's state.\n */\n private maySendEventOfType(eventType: EventType | string, userId: string, state: boolean): boolean {\n const powerLevelsEvent = this.getStateEvents(EventType.RoomPowerLevels, \"\");\n\n let powerLevels: IPowerLevelsContent;\n let eventsLevels: Record<EventType | string, number> = {};\n\n let stateDefault = 0;\n let eventsDefault = 0;\n let powerLevel = 0;\n if (powerLevelsEvent) {\n powerLevels = powerLevelsEvent.getContent();\n eventsLevels = powerLevels.events || {};\n\n if (Number.isSafeInteger(powerLevels.state_default)) {\n stateDefault = powerLevels.state_default!;\n } else {\n stateDefault = 50;\n }\n\n const userPowerLevel = powerLevels.users && powerLevels.users[userId];\n if (Number.isSafeInteger(userPowerLevel)) {\n powerLevel = userPowerLevel!;\n } else if (Number.isSafeInteger(powerLevels.users_default)) {\n powerLevel = powerLevels.users_default!;\n }\n\n if (Number.isSafeInteger(powerLevels.events_default)) {\n eventsDefault = powerLevels.events_default!;\n }\n }\n\n let requiredLevel = state ? stateDefault : eventsDefault;\n if (Number.isSafeInteger(eventsLevels[eventType])) {\n requiredLevel = eventsLevels[eventType];\n }\n return powerLevel >= requiredLevel;\n }\n\n /**\n * Returns true if the given user ID has permission to trigger notification\n * of type `notifLevelKey`\n * @param notifLevelKey - The level of notification to test (eg. 'room')\n * @param userId - The user ID of the user to test permission for\n * @returns true if the given user ID has permission to trigger a\n * notification of this type.\n */\n public mayTriggerNotifOfType(notifLevelKey: string, userId: string): boolean {\n const member = this.getMember(userId);\n if (!member) {\n return false;\n }\n\n const powerLevelsEvent = this.getStateEvents(EventType.RoomPowerLevels, \"\");\n\n let notifLevel = 50;\n if (\n powerLevelsEvent &&\n powerLevelsEvent.getContent() &&\n powerLevelsEvent.getContent().notifications &&\n utils.isNumber(powerLevelsEvent.getContent().notifications[notifLevelKey])\n ) {\n notifLevel = powerLevelsEvent.getContent().notifications[notifLevelKey];\n }\n\n return member.powerLevel >= notifLevel;\n }\n\n /**\n * Returns the join rule based on the m.room.join_rule state event, defaulting to `invite`.\n * @returns the join_rule applied to this room\n */\n public getJoinRule(): JoinRule {\n const joinRuleEvent = this.getStateEvents(EventType.RoomJoinRules, \"\");\n const joinRuleContent: Partial<IJoinRuleEventContent> = joinRuleEvent?.getContent() ?? {};\n return joinRuleContent[\"join_rule\"] || JoinRule.Invite;\n }\n\n /**\n * Returns the history visibility based on the m.room.history_visibility state event, defaulting to `shared`.\n * @returns the history_visibility applied to this room\n */\n public getHistoryVisibility(): HistoryVisibility {\n const historyVisibilityEvent = this.getStateEvents(EventType.RoomHistoryVisibility, \"\");\n const historyVisibilityContent = historyVisibilityEvent?.getContent() ?? {};\n return historyVisibilityContent[\"history_visibility\"] || HistoryVisibility.Shared;\n }\n\n /**\n * Returns the guest access based on the m.room.guest_access state event, defaulting to `shared`.\n * @returns the guest_access applied to this room\n */\n public getGuestAccess(): GuestAccess {\n const guestAccessEvent = this.getStateEvents(EventType.RoomGuestAccess, \"\");\n const guestAccessContent = guestAccessEvent?.getContent() ?? {};\n return guestAccessContent[\"guest_access\"] || GuestAccess.Forbidden;\n }\n\n /**\n * Find the predecessor room based on this room state.\n *\n * @param msc3946ProcessDynamicPredecessor - if true, look for an\n * m.room.predecessor state event and use it if found (MSC3946).\n * @returns null if this room has no predecessor. Otherwise, returns\n * the roomId, last eventId and viaServers of the predecessor room.\n *\n * If msc3946ProcessDynamicPredecessor is true, use m.predecessor events\n * as well as m.room.create events to find predecessors.\n *\n * Note: if an m.predecessor event is used, eventId may be undefined\n * since last_known_event_id is optional.\n *\n * Note: viaServers may be undefined, and will definitely be undefined if\n * this predecessor comes from a RoomCreate event (rather than a\n * RoomPredecessor, which has the optional via_servers property).\n */\n public findPredecessor(\n msc3946ProcessDynamicPredecessor = false,\n ): { roomId: string; eventId?: string; viaServers?: string[] } | null {\n // Note: the tests for this function are against Room.findPredecessor,\n // which just calls through to here.\n\n if (msc3946ProcessDynamicPredecessor) {\n const predecessorEvent = this.getStateEvents(EventType.RoomPredecessor, \"\");\n if (predecessorEvent) {\n const content = predecessorEvent.getContent<{\n predecessor_room_id: string;\n last_known_event_id?: string;\n via_servers?: string[];\n }>();\n const roomId = content.predecessor_room_id;\n let eventId = content.last_known_event_id;\n if (typeof eventId !== \"string\") {\n eventId = undefined;\n }\n let viaServers = content.via_servers;\n if (!Array.isArray(viaServers)) {\n viaServers = undefined;\n }\n if (typeof roomId === \"string\") {\n return { roomId, eventId, viaServers };\n }\n }\n }\n\n const createEvent = this.getStateEvents(EventType.RoomCreate, \"\");\n if (createEvent) {\n const predecessor = createEvent.getContent<{\n predecessor?: Partial<{\n room_id: string;\n event_id: string;\n }>;\n }>()[\"predecessor\"];\n if (predecessor) {\n const roomId = predecessor[\"room_id\"];\n if (typeof roomId === \"string\") {\n let eventId = predecessor[\"event_id\"];\n if (typeof eventId !== \"string\" || eventId === \"\") {\n eventId = undefined;\n }\n return { roomId, eventId };\n }\n }\n }\n return null;\n }\n\n private updateThirdPartyTokenCache(memberEvent: MatrixEvent): void {\n if (!memberEvent.getContent().third_party_invite) {\n return;\n }\n const token = (memberEvent.getContent().third_party_invite.signed || {}).token;\n if (!token) {\n return;\n }\n const threePidInvite = this.getStateEvents(EventType.RoomThirdPartyInvite, token);\n if (!threePidInvite) {\n return;\n }\n this.tokenToInvite[token] = memberEvent;\n }\n\n private updateDisplayNameCache(userId: string, displayName: string): void {\n const oldName = this.userIdsToDisplayNames[userId];\n delete this.userIdsToDisplayNames[userId];\n if (oldName) {\n // Remove the old name from the cache.\n // We clobber the user_id > name lookup but the name -> [user_id] lookup\n // means we need to remove that user ID from that array rather than nuking\n // the lot.\n const strippedOldName = utils.removeHiddenChars(oldName);\n\n const existingUserIds = this.displayNameToUserIds.get(strippedOldName);\n if (existingUserIds) {\n // remove this user ID from this array\n const filteredUserIDs = existingUserIds.filter((id) => id !== userId);\n this.displayNameToUserIds.set(strippedOldName, filteredUserIDs);\n }\n }\n\n this.userIdsToDisplayNames[userId] = displayName;\n\n const strippedDisplayname = displayName && utils.removeHiddenChars(displayName);\n // an empty stripped displayname (undefined/'') will be set to MXID in room-member.js\n if (strippedDisplayname) {\n const arr = this.displayNameToUserIds.get(strippedDisplayname) ?? [];\n arr.push(userId);\n this.displayNameToUserIds.set(strippedDisplayname, arr);\n }\n }\n}\n"],"mappings":"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"} \ No newline at end of file
diff --git a/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/room-summary.d.ts b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/room-summary.d.ts
new file mode 100644
index 0000000..32f2df4
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/room-summary.d.ts
@@ -0,0 +1,29 @@
+export interface IRoomSummary {
+ "m.heroes": string[];
+ "m.joined_member_count"?: number;
+ "m.invited_member_count"?: number;
+}
+interface IInfo {
+ /** The title of the room (e.g. `m.room.name`) */
+ title: string;
+ /** The description of the room (e.g. `m.room.topic`) */
+ desc?: string;
+ /** The number of joined users. */
+ numMembers?: number;
+ /** The list of aliases for this room. */
+ aliases?: string[];
+ /** The timestamp for this room. */
+ timestamp?: number;
+}
+/**
+ * Construct a new Room Summary. A summary can be used for display on a recent
+ * list, without having to load the entire room list into memory.
+ * @param roomId - Required. The ID of this room.
+ * @param info - Optional. The summary info. Additional keys are supported.
+ */
+export declare class RoomSummary {
+ readonly roomId: string;
+ constructor(roomId: string, info?: IInfo);
+}
+export {};
+//# sourceMappingURL=room-summary.d.ts.map \ No newline at end of file
diff --git a/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/room-summary.d.ts.map b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/room-summary.d.ts.map
new file mode 100644
index 0000000..8febcab
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/room-summary.d.ts.map
@@ -0,0 +1 @@
+{"version":3,"file":"room-summary.d.ts","sourceRoot":"","sources":["../../src/models/room-summary.ts"],"names":[],"mappings":"AAgBA,MAAM,WAAW,YAAY;IACzB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,wBAAwB,CAAC,EAAE,MAAM,CAAC;CACrC;AAED,UAAU,KAAK;IACX,iDAAiD;IACjD,KAAK,EAAE,MAAM,CAAC;IACd,wDAAwD;IACxD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,kCAAkC;IAClC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,yCAAyC;IACzC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,mCAAmC;IACnC,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;;GAKG;AACH,qBAAa,WAAW;aACe,MAAM,EAAE,MAAM;gBAAd,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,KAAK;CAClE"} \ No newline at end of file
diff --git a/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/room-summary.js b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/room-summary.js
new file mode 100644
index 0000000..b0f89ab
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/room-summary.js
@@ -0,0 +1,35 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.RoomSummary = void 0;
+/*
+Copyright 2015 - 2021 The Matrix.org Foundation C.I.C.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+/**
+ * Construct a new Room Summary. A summary can be used for display on a recent
+ * list, without having to load the entire room list into memory.
+ * @param roomId - Required. The ID of this room.
+ * @param info - Optional. The summary info. Additional keys are supported.
+ */
+class RoomSummary {
+ constructor(roomId, info) {
+ this.roomId = roomId;
+ }
+}
+exports.RoomSummary = RoomSummary;
+//# sourceMappingURL=room-summary.js.map \ No newline at end of file
diff --git a/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/room-summary.js.map b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/room-summary.js.map
new file mode 100644
index 0000000..a334eb1
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/room-summary.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"room-summary.js","names":["RoomSummary","constructor","roomId","info","exports"],"sources":["../../src/models/room-summary.ts"],"sourcesContent":["/*\nCopyright 2015 - 2021 The Matrix.org Foundation C.I.C.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n*/\n\nexport interface IRoomSummary {\n \"m.heroes\": string[];\n \"m.joined_member_count\"?: number;\n \"m.invited_member_count\"?: number;\n}\n\ninterface IInfo {\n /** The title of the room (e.g. `m.room.name`) */\n title: string;\n /** The description of the room (e.g. `m.room.topic`) */\n desc?: string;\n /** The number of joined users. */\n numMembers?: number;\n /** The list of aliases for this room. */\n aliases?: string[];\n /** The timestamp for this room. */\n timestamp?: number;\n}\n\n/**\n * Construct a new Room Summary. A summary can be used for display on a recent\n * list, without having to load the entire room list into memory.\n * @param roomId - Required. The ID of this room.\n * @param info - Optional. The summary info. Additional keys are supported.\n */\nexport class RoomSummary {\n public constructor(public readonly roomId: string, info?: IInfo) {}\n}\n"],"mappings":";;;;;;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAqBA;AACA;AACA;AACA;AACA;AACA;AACO,MAAMA,WAAW,CAAC;EACdC,WAAWA,CAAiBC,MAAc,EAAEC,IAAY,EAAE;IAAA,KAA9BD,MAAc,GAAdA,MAAc;EAAiB;AACtE;AAACE,OAAA,CAAAJ,WAAA,GAAAA,WAAA"} \ No newline at end of file
diff --git a/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/room.d.ts b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/room.d.ts
new file mode 100644
index 0000000..438ce42
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/room.d.ts
@@ -0,0 +1,1087 @@
+import { EventTimelineSet, DuplicateStrategy, IAddLiveEventOptions, EventTimelineSetHandlerMap } from "./event-timeline-set";
+import { EventTimeline } from "./event-timeline";
+import { MatrixEvent, MatrixEventEvent, MatrixEventHandlerMap } from "./event";
+import { EventStatus } from "./event-status";
+import { RoomMember } from "./room-member";
+import { IRoomSummary, RoomSummary } from "./room-summary";
+import { TypedReEmitter } from "../ReEmitter";
+import { EventType, RoomType } from "../@types/event";
+import { MatrixClient, PendingEventOrdering } from "../client";
+import { GuestAccess, HistoryVisibility, JoinRule, ResizeMethod } from "../@types/partials";
+import { Filter } from "../filter";
+import { RoomState, RoomStateEvent, RoomStateEventHandlerMap } from "./room-state";
+import { BeaconEvent, BeaconEventHandlerMap } from "./beacon";
+import { Thread, ThreadEvent, EventHandlerMap as ThreadHandlerMap } from "./thread";
+import { CachedReceiptStructure, Receipt } from "../@types/read_receipts";
+import { RelationsContainer } from "./relations-container";
+import { ReadReceipt } from "./read-receipt";
+import { Poll, PollEvent } from "./poll";
+export declare const KNOWN_SAFE_ROOM_VERSION = "9";
+interface IOpts {
+ /**
+ * Controls where pending messages appear in a room's timeline.
+ * If "<b>chronological</b>", messages will appear in the timeline when the call to `sendEvent` was made.
+ * If "<b>detached</b>", pending messages will appear in a separate list,
+ * accessible via {@link Room#getPendingEvents}.
+ * Default: "chronological".
+ */
+ pendingEventOrdering?: PendingEventOrdering;
+ /**
+ * Set to true to enable improved timeline support.
+ */
+ timelineSupport?: boolean;
+ lazyLoadMembers?: boolean;
+}
+export interface IRecommendedVersion {
+ version: string;
+ needsUpgrade: boolean;
+ urgent: boolean;
+}
+export type NotificationCount = Partial<Record<NotificationCountType, number>>;
+export declare enum NotificationCountType {
+ Highlight = "highlight",
+ Total = "total"
+}
+export interface ICreateFilterOpts {
+ prepopulateTimeline?: boolean;
+ useSyncEvents?: boolean;
+ pendingEvents?: boolean;
+}
+export declare enum RoomEvent {
+ MyMembership = "Room.myMembership",
+ Tags = "Room.tags",
+ AccountData = "Room.accountData",
+ Receipt = "Room.receipt",
+ Name = "Room.name",
+ Redaction = "Room.redaction",
+ RedactionCancelled = "Room.redactionCancelled",
+ LocalEchoUpdated = "Room.localEchoUpdated",
+ Timeline = "Room.timeline",
+ TimelineReset = "Room.timelineReset",
+ TimelineRefresh = "Room.TimelineRefresh",
+ OldStateUpdated = "Room.OldStateUpdated",
+ CurrentStateUpdated = "Room.CurrentStateUpdated",
+ HistoryImportedWithinTimeline = "Room.historyImportedWithinTimeline",
+ UnreadNotifications = "Room.UnreadNotifications"
+}
+export type RoomEmittedEvents = RoomEvent | RoomStateEvent.Events | RoomStateEvent.Members | RoomStateEvent.NewMember | RoomStateEvent.Update | RoomStateEvent.Marker | ThreadEvent.New | ThreadEvent.Update | ThreadEvent.NewReply | ThreadEvent.Delete | MatrixEventEvent.BeforeRedaction | BeaconEvent.New | BeaconEvent.Update | BeaconEvent.Destroy | BeaconEvent.LivenessChange | PollEvent.New;
+export type RoomEventHandlerMap = {
+ /**
+ * Fires when the logged in user's membership in the room is updated.
+ *
+ * @param room - The room in which the membership has been updated
+ * @param membership - The new membership value
+ * @param prevMembership - The previous membership value
+ */
+ [RoomEvent.MyMembership]: (room: Room, membership: string, prevMembership?: string) => void;
+ /**
+ * Fires whenever a room's tags are updated.
+ * @param event - The tags event
+ * @param room - The room whose Room.tags was updated.
+ * @example
+ * ```
+ * matrixClient.on("Room.tags", function(event, room){
+ * var newTags = event.getContent().tags;
+ * if (newTags["favourite"]) showStar(room);
+ * });
+ * ```
+ */
+ [RoomEvent.Tags]: (event: MatrixEvent, room: Room) => void;
+ /**
+ * Fires whenever a room's account_data is updated.
+ * @param event - The account_data event
+ * @param room - The room whose account_data was updated.
+ * @param prevEvent - The event being replaced by
+ * the new account data, if known.
+ * @example
+ * ```
+ * matrixClient.on("Room.accountData", function(event, room, oldEvent){
+ * if (event.getType() === "m.room.colorscheme") {
+ * applyColorScheme(event.getContents());
+ * }
+ * });
+ * ```
+ */
+ [RoomEvent.AccountData]: (event: MatrixEvent, room: Room, lastEvent?: MatrixEvent) => void;
+ /**
+ * Fires whenever a receipt is received for a room
+ * @param event - The receipt event
+ * @param room - The room whose receipts was updated.
+ * @example
+ * ```
+ * matrixClient.on("Room.receipt", function(event, room){
+ * var receiptContent = event.getContent();
+ * });
+ * ```
+ */
+ [RoomEvent.Receipt]: (event: MatrixEvent, room: Room) => void;
+ /**
+ * Fires whenever the name of a room is updated.
+ * @param room - The room whose Room.name was updated.
+ * @example
+ * ```
+ * matrixClient.on("Room.name", function(room){
+ * var newName = room.name;
+ * });
+ * ```
+ */
+ [RoomEvent.Name]: (room: Room) => void;
+ /**
+ * Fires when an event we had previously received is redacted.
+ *
+ * (Note this is *not* fired when the redaction happens before we receive the
+ * event).
+ *
+ * @param event - The matrix redaction event
+ * @param room - The room containing the redacted event
+ */
+ [RoomEvent.Redaction]: (event: MatrixEvent, room: Room) => void;
+ /**
+ * Fires when an event that was previously redacted isn't anymore.
+ * This happens when the redaction couldn't be sent and
+ * was subsequently cancelled by the user. Redactions have a local echo
+ * which is undone in this scenario.
+ *
+ * @param event - The matrix redaction event that was cancelled.
+ * @param room - The room containing the unredacted event
+ */
+ [RoomEvent.RedactionCancelled]: (event: MatrixEvent, room: Room) => void;
+ /**
+ * Fires when the status of a transmitted event is updated.
+ *
+ * <p>When an event is first transmitted, a temporary copy of the event is
+ * inserted into the timeline, with a temporary event id, and a status of
+ * 'SENDING'.
+ *
+ * <p>Once the echo comes back from the server, the content of the event
+ * (MatrixEvent.event) is replaced by the complete event from the homeserver,
+ * thus updating its event id, as well as server-generated fields such as the
+ * timestamp. Its status is set to null.
+ *
+ * <p>Once the /send request completes, if the remote echo has not already
+ * arrived, the event is updated with a new event id and the status is set to
+ * 'SENT'. The server-generated fields are of course not updated yet.
+ *
+ * <p>If the /send fails, In this case, the event's status is set to
+ * 'NOT_SENT'. If it is later resent, the process starts again, setting the
+ * status to 'SENDING'. Alternatively, the message may be cancelled, which
+ * removes the event from the room, and sets the status to 'CANCELLED'.
+ *
+ * <p>This event is raised to reflect each of the transitions above.
+ *
+ * @param event - The matrix event which has been updated
+ *
+ * @param room - The room containing the redacted event
+ *
+ * @param oldEventId - The previous event id (the temporary event id,
+ * except when updating a successfully-sent event when its echo arrives)
+ *
+ * @param oldStatus - The previous event status.
+ */
+ [RoomEvent.LocalEchoUpdated]: (event: MatrixEvent, room: Room, oldEventId?: string, oldStatus?: EventStatus | null) => void;
+ [RoomEvent.OldStateUpdated]: (room: Room, previousRoomState: RoomState, roomState: RoomState) => void;
+ [RoomEvent.CurrentStateUpdated]: (room: Room, previousRoomState: RoomState, roomState: RoomState) => void;
+ [RoomEvent.HistoryImportedWithinTimeline]: (markerEvent: MatrixEvent, room: Room) => void;
+ [RoomEvent.UnreadNotifications]: (unreadNotifications?: NotificationCount, threadId?: string) => void;
+ [RoomEvent.TimelineRefresh]: (room: Room, eventTimelineSet: EventTimelineSet) => void;
+ [ThreadEvent.New]: (thread: Thread, toStartOfTimeline: boolean) => void;
+ /**
+ * Fires when a new poll instance is added to the room state
+ * @param poll - the new poll
+ */
+ [PollEvent.New]: (poll: Poll) => void;
+} & Pick<ThreadHandlerMap, ThreadEvent.Update | ThreadEvent.NewReply | ThreadEvent.Delete> & EventTimelineSetHandlerMap & Pick<MatrixEventHandlerMap, MatrixEventEvent.BeforeRedaction> & Pick<RoomStateEventHandlerMap, RoomStateEvent.Events | RoomStateEvent.Members | RoomStateEvent.NewMember | RoomStateEvent.Update | RoomStateEvent.Marker | BeaconEvent.New> & Pick<BeaconEventHandlerMap, BeaconEvent.Update | BeaconEvent.Destroy | BeaconEvent.LivenessChange>;
+export declare class Room extends ReadReceipt<RoomEmittedEvents, RoomEventHandlerMap> {
+ readonly roomId: string;
+ readonly client: MatrixClient;
+ readonly myUserId: string;
+ private readonly opts;
+ readonly reEmitter: TypedReEmitter<RoomEmittedEvents, RoomEventHandlerMap>;
+ private txnToEvent;
+ private notificationCounts;
+ private readonly threadNotifications;
+ readonly cachedThreadReadReceipts: Map<string, CachedReceiptStructure[]>;
+ private oldestThreadedReceiptTs;
+ /**
+ * A record of the latest unthread receipts per user
+ * This is useful in determining whether a user has read a thread or not
+ */
+ private unthreadedReceipts;
+ private readonly timelineSets;
+ readonly polls: Map<string, Poll>;
+ readonly threadsTimelineSets: EventTimelineSet[];
+ private readonly filteredTimelineSets;
+ private timelineNeedsRefresh;
+ private readonly pendingEventList?;
+ private blacklistUnverifiedDevices?;
+ private selfMembership?;
+ private summaryHeroes;
+ private getTypeWarning;
+ private getVersionWarning;
+ private membersPromise?;
+ /**
+ * The human-readable display name for this room.
+ */
+ name: string;
+ /**
+ * The un-homoglyphed name for this room.
+ */
+ normalizedName: string;
+ /**
+ * Dict of room tags; the keys are the tag name and the values
+ * are any metadata associated with the tag - e.g. `{ "fav" : { order: 1 } }`
+ */
+ tags: Record<string, Record<string, any>>;
+ /**
+ * accountData Dict of per-room account_data events; the keys are the
+ * event type and the values are the events.
+ */
+ accountData: Map<string, MatrixEvent>;
+ /**
+ * The room summary.
+ */
+ summary: RoomSummary | null;
+ /**
+ * The live event timeline for this room, with the oldest event at index 0.
+ * Present for backwards compatibility - prefer getLiveTimeline().getEvents()
+ */
+ timeline: MatrixEvent[];
+ /**
+ * oldState The state of the room at the time of the oldest
+ * event in the live timeline. Present for backwards compatibility -
+ * prefer getLiveTimeline().getState(EventTimeline.BACKWARDS).
+ */
+ oldState: RoomState;
+ /**
+ * currentState The state of the room at the time of the
+ * newest event in the timeline. Present for backwards compatibility -
+ * prefer getLiveTimeline().getState(EventTimeline.FORWARDS).
+ */
+ currentState: RoomState;
+ readonly relations: RelationsContainer;
+ /**
+ * A collection of events known by the client
+ * This is not a comprehensive list of the threads that exist in this room
+ */
+ private threads;
+ lastThread?: Thread;
+ /**
+ * A mapping of eventId to all visibility changes to apply
+ * to the event, by chronological order, as per
+ * https://github.com/matrix-org/matrix-doc/pull/3531
+ *
+ * # Invariants
+ *
+ * - within each list, all events are classed by
+ * chronological order;
+ * - all events are events such that
+ * `asVisibilityEvent()` returns a non-null `IVisibilityChange`;
+ * - within each list with key `eventId`, all events
+ * are in relation to `eventId`.
+ *
+ * @experimental
+ */
+ private visibilityEvents;
+ /**
+ * Construct a new Room.
+ *
+ * <p>For a room, we store an ordered sequence of timelines, which may or may not
+ * be continuous. Each timeline lists a series of events, as well as tracking
+ * the room state at the start and the end of the timeline. It also tracks
+ * forward and backward pagination tokens, as well as containing links to the
+ * next timeline in the sequence.
+ *
+ * <p>There is one special timeline - the 'live' timeline, which represents the
+ * timeline to which events are being added in real-time as they are received
+ * from the /sync API. Note that you should not retain references to this
+ * timeline - even if it is the current timeline right now, it may not remain
+ * so if the server gives us a timeline gap in /sync.
+ *
+ * <p>In order that we can find events from their ids later, we also maintain a
+ * map from event_id to timeline and index.
+ *
+ * @param roomId - Required. The ID of this room.
+ * @param client - Required. The client, used to lazy load members.
+ * @param myUserId - Required. The ID of the syncing user.
+ * @param opts - Configuration options
+ */
+ constructor(roomId: string, client: MatrixClient, myUserId: string, opts?: IOpts);
+ private threadTimelineSetsPromise;
+ createThreadsTimelineSets(): Promise<[EventTimelineSet, EventTimelineSet] | null>;
+ /**
+ * Bulk decrypt critical events in a room
+ *
+ * Critical events represents the minimal set of events to decrypt
+ * for a typical UI to function properly
+ *
+ * - Last event of every room (to generate likely message preview)
+ * - All events up to the read receipt (to calculate an accurate notification count)
+ *
+ * @returns Signals when all events have been decrypted
+ */
+ decryptCriticalEvents(): Promise<void>;
+ /**
+ * Bulk decrypt events in a room
+ *
+ * @returns Signals when all events have been decrypted
+ */
+ decryptAllEvents(): Promise<void>;
+ /**
+ * Gets the creator of the room
+ * @returns The creator of the room, or null if it could not be determined
+ */
+ getCreator(): string | null;
+ /**
+ * Gets the version of the room
+ * @returns The version of the room, or null if it could not be determined
+ */
+ getVersion(): string;
+ /**
+ * Determines whether this room needs to be upgraded to a new version
+ * @returns What version the room should be upgraded to, or null if
+ * the room does not require upgrading at this time.
+ * @deprecated Use #getRecommendedVersion() instead
+ */
+ shouldUpgradeToVersion(): string | null;
+ /**
+ * Determines the recommended room version for the room. This returns an
+ * object with 3 properties: `version` as the new version the
+ * room should be upgraded to (may be the same as the current version);
+ * `needsUpgrade` to indicate if the room actually can be
+ * upgraded (ie: does the current version not match?); and `urgent`
+ * to indicate if the new version patches a vulnerability in a previous
+ * version.
+ * @returns
+ * Resolves to the version the room should be upgraded to.
+ */
+ getRecommendedVersion(): Promise<IRecommendedVersion>;
+ private checkVersionAgainstCapability;
+ /**
+ * Determines whether the given user is permitted to perform a room upgrade
+ * @param userId - The ID of the user to test against
+ * @returns True if the given user is permitted to upgrade the room
+ */
+ userMayUpgradeRoom(userId: string): boolean;
+ /**
+ * Get the list of pending sent events for this room
+ *
+ * @returns A list of the sent events
+ * waiting for remote echo.
+ *
+ * @throws If `opts.pendingEventOrdering` was not 'detached'
+ */
+ getPendingEvents(): MatrixEvent[];
+ /**
+ * Removes a pending event for this room
+ *
+ * @returns True if an element was removed.
+ */
+ removePendingEvent(eventId: string): boolean;
+ /**
+ * Check whether the pending event list contains a given event by ID.
+ * If pending event ordering is not "detached" then this returns false.
+ *
+ * @param eventId - The event ID to check for.
+ */
+ hasPendingEvent(eventId: string): boolean;
+ /**
+ * Get a specific event from the pending event list, if configured, null otherwise.
+ *
+ * @param eventId - The event ID to check for.
+ */
+ getPendingEvent(eventId: string): MatrixEvent | null;
+ /**
+ * Get the live unfiltered timeline for this room.
+ *
+ * @returns live timeline
+ */
+ getLiveTimeline(): EventTimeline;
+ /**
+ * Get the timestamp of the last message in the room
+ *
+ * @returns the timestamp of the last message in the room
+ */
+ getLastActiveTimestamp(): number;
+ /**
+ * @returns the membership type (join | leave | invite) for the logged in user
+ */
+ getMyMembership(): string;
+ /**
+ * If this room is a DM we're invited to,
+ * try to find out who invited us
+ * @returns user id of the inviter
+ */
+ getDMInviter(): string | undefined;
+ /**
+ * Assuming this room is a DM room, tries to guess with which user.
+ * @returns user id of the other member (could be syncing user)
+ */
+ guessDMUserId(): string;
+ getAvatarFallbackMember(): RoomMember | undefined;
+ /**
+ * Sets the membership this room was received as during sync
+ * @param membership - join | leave | invite
+ */
+ updateMyMembership(membership: string): void;
+ private loadMembersFromServer;
+ private loadMembers;
+ /**
+ * Check if loading of out-of-band-members has completed
+ *
+ * @returns true if the full membership list of this room has been loaded (including if lazy-loading is disabled).
+ * False if the load is not started or is in progress.
+ */
+ membersLoaded(): boolean;
+ /**
+ * Preloads the member list in case lazy loading
+ * of memberships is in use. Can be called multiple times,
+ * it will only preload once.
+ * @returns when preloading is done and
+ * accessing the members on the room will take
+ * all members in the room into account
+ */
+ loadMembersIfNeeded(): Promise<boolean>;
+ /**
+ * Removes the lazily loaded members from storage if needed
+ */
+ clearLoadedMembersIfNeeded(): Promise<void>;
+ /**
+ * called when sync receives this room in the leave section
+ * to do cleanup after leaving a room. Possibly called multiple times.
+ */
+ private cleanupAfterLeaving;
+ /**
+ * Empty out the current live timeline and re-request it. This is used when
+ * historical messages are imported into the room via MSC2716 `/batch_send`
+ * because the client may already have that section of the timeline loaded.
+ * We need to force the client to throw away their current timeline so that
+ * when they back paginate over the area again with the historical messages
+ * in between, it grabs the newly imported messages. We can listen for
+ * `UNSTABLE_MSC2716_MARKER`, in order to tell when historical messages are ready
+ * to be discovered in the room and the timeline needs a refresh. The SDK
+ * emits a `RoomEvent.HistoryImportedWithinTimeline` event when we detect a
+ * valid marker and can check the needs refresh status via
+ * `room.getTimelineNeedsRefresh()`.
+ */
+ refreshLiveTimeline(): Promise<void>;
+ /**
+ * Reset the live timeline of all timelineSets, and start new ones.
+ *
+ * <p>This is used when /sync returns a 'limited' timeline.
+ *
+ * @param backPaginationToken - token for back-paginating the new timeline
+ * @param forwardPaginationToken - token for forward-paginating the old live timeline,
+ * if absent or null, all timelines are reset, removing old ones (including the previous live
+ * timeline which would otherwise be unable to paginate forwards without this token).
+ * Removing just the old live timeline whilst preserving previous ones is not supported.
+ */
+ resetLiveTimeline(backPaginationToken?: string | null, forwardPaginationToken?: string | null): void;
+ /**
+ * Fix up this.timeline, this.oldState and this.currentState
+ *
+ * @internal
+ */
+ private fixUpLegacyTimelineFields;
+ /**
+ * Returns whether there are any devices in the room that are unverified
+ *
+ * Note: Callers should first check if crypto is enabled on this device. If it is
+ * disabled, then we aren't tracking room devices at all, so we can't answer this, and an
+ * error will be thrown.
+ *
+ * @returns the result
+ */
+ hasUnverifiedDevices(): Promise<boolean>;
+ /**
+ * Return the timeline sets for this room.
+ * @returns array of timeline sets for this room
+ */
+ getTimelineSets(): EventTimelineSet[];
+ /**
+ * Helper to return the main unfiltered timeline set for this room
+ * @returns room's unfiltered timeline set
+ */
+ getUnfilteredTimelineSet(): EventTimelineSet;
+ /**
+ * Get the timeline which contains the given event from the unfiltered set, if any
+ *
+ * @param eventId - event ID to look for
+ * @returns timeline containing
+ * the given event, or null if unknown
+ */
+ getTimelineForEvent(eventId: string): EventTimeline | null;
+ /**
+ * Add a new timeline to this room's unfiltered timeline set
+ *
+ * @returns newly-created timeline
+ */
+ addTimeline(): EventTimeline;
+ /**
+ * Whether the timeline needs to be refreshed in order to pull in new
+ * historical messages that were imported.
+ * @param value - The value to set
+ */
+ setTimelineNeedsRefresh(value: boolean): void;
+ /**
+ * Whether the timeline needs to be refreshed in order to pull in new
+ * historical messages that were imported.
+ * @returns .
+ */
+ getTimelineNeedsRefresh(): boolean;
+ /**
+ * Get an event which is stored in our unfiltered timeline set, or in a thread
+ *
+ * @param eventId - event ID to look for
+ * @returns the given event, or undefined if unknown
+ */
+ findEventById(eventId: string): MatrixEvent | undefined;
+ /**
+ * Get one of the notification counts for this room
+ * @param type - The type of notification count to get. default: 'total'
+ * @returns The notification count, or undefined if there is no count
+ * for this type.
+ */
+ getUnreadNotificationCount(type?: NotificationCountType): number;
+ /**
+ * Get the notification for the event context (room or thread timeline)
+ */
+ getUnreadCountForEventContext(type: NotificationCountType | undefined, event: MatrixEvent): number;
+ /**
+ * Get one of the notification counts for this room
+ * @param type - The type of notification count to get. default: 'total'
+ * @returns The notification count, or undefined if there is no count
+ * for this type.
+ */
+ getRoomUnreadNotificationCount(type?: NotificationCountType): number;
+ /**
+ * Get one of the notification counts for a thread
+ * @param threadId - the root event ID
+ * @param type - The type of notification count to get. default: 'total'
+ * @returns The notification count, or undefined if there is no count
+ * for this type.
+ */
+ getThreadUnreadNotificationCount(threadId: string, type?: NotificationCountType): number;
+ /**
+ * Checks if the current room has unread thread notifications
+ * @returns
+ */
+ hasThreadUnreadNotification(): boolean;
+ /**
+ * Swet one of the notification count for a thread
+ * @param threadId - the root event ID
+ * @param type - The type of notification count to get. default: 'total'
+ * @returns
+ */
+ setThreadUnreadNotificationCount(threadId: string, type: NotificationCountType, count: number): void;
+ /**
+ * @returns the notification count type for all the threads in the room
+ */
+ get threadsAggregateNotificationType(): NotificationCountType | null;
+ /**
+ * Resets the thread notifications for this room
+ */
+ resetThreadUnreadNotificationCount(notificationsToKeep?: string[]): void;
+ /**
+ * Set one of the notification counts for this room
+ * @param type - The type of notification count to set.
+ * @param count - The new count
+ */
+ setUnreadNotificationCount(type: NotificationCountType, count: number): void;
+ setUnread(type: NotificationCountType, count: number): void;
+ setSummary(summary: IRoomSummary): void;
+ /**
+ * Whether to send encrypted messages to devices within this room.
+ * @param value - true to blacklist unverified devices, null
+ * to use the global value for this room.
+ */
+ setBlacklistUnverifiedDevices(value: boolean): void;
+ /**
+ * Whether to send encrypted messages to devices within this room.
+ * @returns true if blacklisting unverified devices, null
+ * if the global value should be used for this room.
+ */
+ getBlacklistUnverifiedDevices(): boolean | null;
+ /**
+ * Get the avatar URL for a room if one was set.
+ * @param baseUrl - The homeserver base URL. See
+ * {@link MatrixClient#getHomeserverUrl}.
+ * @param width - The desired width of the thumbnail.
+ * @param height - The desired height of the thumbnail.
+ * @param resizeMethod - The thumbnail resize method to use, either
+ * "crop" or "scale".
+ * @param allowDefault - True to allow an identicon for this room if an
+ * avatar URL wasn't explicitly set. Default: true. (Deprecated)
+ * @returns the avatar URL or null.
+ */
+ getAvatarUrl(baseUrl: string, width: number, height: number, resizeMethod: ResizeMethod, allowDefault?: boolean): string | null;
+ /**
+ * Get the mxc avatar url for the room, if one was set.
+ * @returns the mxc avatar url or falsy
+ */
+ getMxcAvatarUrl(): string | null;
+ /**
+ * Get this room's canonical alias
+ * The alias returned by this function may not necessarily
+ * still point to this room.
+ * @returns The room's canonical alias, or null if there is none
+ */
+ getCanonicalAlias(): string | null;
+ /**
+ * Get this room's alternative aliases
+ * @returns The room's alternative aliases, or an empty array
+ */
+ getAltAliases(): string[];
+ /**
+ * Add events to a timeline
+ *
+ * <p>Will fire "Room.timeline" for each event added.
+ *
+ * @param events - A list of events to add.
+ *
+ * @param toStartOfTimeline - True to add these events to the start
+ * (oldest) instead of the end (newest) of the timeline. If true, the oldest
+ * event will be the <b>last</b> element of 'events'.
+ *
+ * @param timeline - timeline to
+ * add events to.
+ *
+ * @param paginationToken - token for the next batch of events
+ *
+ * @remarks
+ * Fires {@link RoomEvent.Timeline}
+ */
+ addEventsToTimeline(events: MatrixEvent[], toStartOfTimeline: boolean, timeline: EventTimeline, paginationToken?: string): void;
+ /**
+ * Get the instance of the thread associated with the current event
+ * @param eventId - the ID of the current event
+ * @returns a thread instance if known
+ */
+ getThread(eventId: string): Thread | null;
+ /**
+ * Get all the known threads in the room
+ */
+ getThreads(): Thread[];
+ /**
+ * Get a member from the current room state.
+ * @param userId - The user ID of the member.
+ * @returns The member or `null`.
+ */
+ getMember(userId: string): RoomMember | null;
+ /**
+ * Get all currently loaded members from the current
+ * room state.
+ * @returns Room members
+ */
+ getMembers(): RoomMember[];
+ /**
+ * Get a list of members whose membership state is "join".
+ * @returns A list of currently joined members.
+ */
+ getJoinedMembers(): RoomMember[];
+ /**
+ * Returns the number of joined members in this room
+ * This method caches the result.
+ * This is a wrapper around the method of the same name in roomState, returning
+ * its result for the room's current state.
+ * @returns The number of members in this room whose membership is 'join'
+ */
+ getJoinedMemberCount(): number;
+ /**
+ * Returns the number of invited members in this room
+ * @returns The number of members in this room whose membership is 'invite'
+ */
+ getInvitedMemberCount(): number;
+ /**
+ * Returns the number of invited + joined members in this room
+ * @returns The number of members in this room whose membership is 'invite' or 'join'
+ */
+ getInvitedAndJoinedMemberCount(): number;
+ /**
+ * Get a list of members with given membership state.
+ * @param membership - The membership state.
+ * @returns A list of members with the given membership state.
+ */
+ getMembersWithMembership(membership: string): RoomMember[];
+ /**
+ * Get a list of members we should be encrypting for in this room
+ * @returns A list of members who
+ * we should encrypt messages for in this room.
+ */
+ getEncryptionTargetMembers(): Promise<RoomMember[]>;
+ /**
+ * Determine whether we should encrypt messages for invited users in this room
+ * @returns if we should encrypt messages for invited users
+ */
+ shouldEncryptForInvitedMembers(): boolean;
+ /**
+ * Get the default room name (i.e. what a given user would see if the
+ * room had no m.room.name)
+ * @param userId - The userId from whose perspective we want
+ * to calculate the default name
+ * @returns The default room name
+ */
+ getDefaultRoomName(userId: string): string;
+ /**
+ * Check if the given user_id has the given membership state.
+ * @param userId - The user ID to check.
+ * @param membership - The membership e.g. `'join'`
+ * @returns True if this user_id has the given membership state.
+ */
+ hasMembershipState(userId: string, membership: string): boolean;
+ /**
+ * Add a timelineSet for this room with the given filter
+ * @param filter - The filter to be applied to this timelineSet
+ * @param opts - Configuration options
+ * @returns The timelineSet
+ */
+ getOrCreateFilteredTimelineSet(filter: Filter, { prepopulateTimeline, useSyncEvents, pendingEvents }?: ICreateFilterOpts): EventTimelineSet;
+ private getThreadListFilter;
+ private createThreadTimelineSet;
+ private threadsReady;
+ /**
+ * Takes the given thread root events and creates threads for them.
+ */
+ processThreadRoots(events: MatrixEvent[], toStartOfTimeline: boolean): void;
+ /**
+ * Fetch the bare minimum of room threads required for the thread list to work reliably.
+ * With server support that means fetching one page.
+ * Without server support that means fetching as much at once as the server allows us to.
+ */
+ fetchRoomThreads(): Promise<void>;
+ processPollEvents(events: MatrixEvent[]): Promise<void>;
+ /**
+ * Fetch a single page of threadlist messages for the specific thread filter
+ * @internal
+ */
+ private fetchRoomThreadList;
+ private onThreadNewReply;
+ private onThreadDelete;
+ /**
+ * Forget the timelineSet for this room with the given filter
+ *
+ * @param filter - the filter whose timelineSet is to be forgotten
+ */
+ removeFilteredTimelineSet(filter: Filter): void;
+ eventShouldLiveIn(event: MatrixEvent, events?: MatrixEvent[], roots?: Set<string>): {
+ shouldLiveInRoom: boolean;
+ shouldLiveInThread: boolean;
+ threadId?: string;
+ };
+ findThreadForEvent(event?: MatrixEvent): Thread | null;
+ private addThreadedEvents;
+ /**
+ * Adds events to a thread's timeline. Will fire "Thread.update"
+ */
+ processThreadedEvents(events: MatrixEvent[], toStartOfTimeline: boolean): void;
+ private updateThreadRootEvents;
+ private updateThreadRootEvent;
+ createThread(threadId: string, rootEvent: MatrixEvent | undefined, events: MatrixEvent[] | undefined, toStartOfTimeline: boolean): Thread;
+ private applyRedaction;
+ private processLiveEvent;
+ /**
+ * Add an event to the end of this room's live timelines. Will fire
+ * "Room.timeline".
+ *
+ * @param event - Event to be added
+ * @param addLiveEventOptions - addLiveEvent options
+ * @internal
+ *
+ * @remarks
+ * Fires {@link RoomEvent.Timeline}
+ */
+ private addLiveEvent;
+ /**
+ * Add a pending outgoing event to this room.
+ *
+ * <p>The event is added to either the pendingEventList, or the live timeline,
+ * depending on the setting of opts.pendingEventOrdering.
+ *
+ * <p>This is an internal method, intended for use by MatrixClient.
+ *
+ * @param event - The event to add.
+ *
+ * @param txnId - Transaction id for this outgoing event
+ *
+ * @throws if the event doesn't have status SENDING, or we aren't given a
+ * unique transaction id.
+ *
+ * @remarks
+ * Fires {@link RoomEvent.LocalEchoUpdated}
+ */
+ addPendingEvent(event: MatrixEvent, txnId: string): void;
+ /**
+ * Persists all pending events to local storage
+ *
+ * If the current room is encrypted only encrypted events will be persisted
+ * all messages that are not yet encrypted will be discarded
+ *
+ * This is because the flow of EVENT_STATUS transition is
+ * `queued => sending => encrypting => sending => sent`
+ *
+ * Steps 3 and 4 are skipped for unencrypted room.
+ * It is better to discard an unencrypted message rather than persisting
+ * it locally for everyone to read
+ */
+ private savePendingEvents;
+ /**
+ * Used to aggregate the local echo for a relation, and also
+ * for re-applying a relation after it's redaction has been cancelled,
+ * as the local echo for the redaction of the relation would have
+ * un-aggregated the relation. Note that this is different from regular messages,
+ * which are just kept detached for their local echo.
+ *
+ * Also note that live events are aggregated in the live EventTimelineSet.
+ * @param event - the relation event that needs to be aggregated.
+ */
+ private aggregateNonLiveRelation;
+ getEventForTxnId(txnId: string): MatrixEvent | undefined;
+ /**
+ * Deal with the echo of a message we sent.
+ *
+ * <p>We move the event to the live timeline if it isn't there already, and
+ * update it.
+ *
+ * @param remoteEvent - The event received from
+ * /sync
+ * @param localEvent - The local echo, which
+ * should be either in the pendingEventList or the timeline.
+ *
+ * @internal
+ *
+ * @remarks
+ * Fires {@link RoomEvent.LocalEchoUpdated}
+ */
+ handleRemoteEcho(remoteEvent: MatrixEvent, localEvent: MatrixEvent): void;
+ /**
+ * Update the status / event id on a pending event, to reflect its transmission
+ * progress.
+ *
+ * <p>This is an internal method.
+ *
+ * @param event - local echo event
+ * @param newStatus - status to assign
+ * @param newEventId - new event id to assign. Ignored unless newStatus == EventStatus.SENT.
+ *
+ * @remarks
+ * Fires {@link RoomEvent.LocalEchoUpdated}
+ */
+ updatePendingEvent(event: MatrixEvent, newStatus: EventStatus, newEventId?: string): void;
+ private revertRedactionLocalEcho;
+ /**
+ * Add some events to this room. This can include state events, message
+ * events and typing notifications. These events are treated as "live" so
+ * they will go to the end of the timeline.
+ *
+ * @param events - A list of events to add.
+ * @param addLiveEventOptions - addLiveEvent options
+ * @throws If `duplicateStrategy` is not falsey, 'replace' or 'ignore'.
+ */
+ addLiveEvents(events: MatrixEvent[], addLiveEventOptions?: IAddLiveEventOptions): void;
+ /**
+ * @deprecated In favor of the overload with `IAddLiveEventOptions`
+ */
+ addLiveEvents(events: MatrixEvent[], duplicateStrategy?: DuplicateStrategy, fromCache?: boolean): void;
+ partitionThreadedEvents(events: MatrixEvent[]): [timelineEvents: MatrixEvent[], threadedEvents: MatrixEvent[]];
+ /**
+ * Given some events, find the IDs of all the thread roots that are referred to by them.
+ */
+ private findThreadRoots;
+ /**
+ * Add a receipt event to the room.
+ * @param event - The m.receipt event.
+ * @param synthetic - True if this event is implicit.
+ */
+ addReceipt(event: MatrixEvent, synthetic?: boolean): void;
+ /**
+ * Adds/handles ephemeral events such as typing notifications and read receipts.
+ * @param events - A list of events to process
+ */
+ addEphemeralEvents(events: MatrixEvent[]): void;
+ /**
+ * Removes events from this room.
+ * @param eventIds - A list of eventIds to remove.
+ */
+ removeEvents(eventIds: string[]): void;
+ /**
+ * Removes a single event from this room.
+ *
+ * @param eventId - The id of the event to remove
+ *
+ * @returns true if the event was removed from any of the room's timeline sets
+ */
+ removeEvent(eventId: string): boolean;
+ /**
+ * Recalculate various aspects of the room, including the room name and
+ * room summary. Call this any time the room's current state is modified.
+ * May fire "Room.name" if the room name is updated.
+ *
+ * @remarks
+ * Fires {@link RoomEvent.Name}
+ */
+ recalculate(): void;
+ /**
+ * Update the room-tag event for the room. The previous one is overwritten.
+ * @param event - the m.tag event
+ */
+ addTags(event: MatrixEvent): void;
+ /**
+ * Update the account_data events for this room, overwriting events of the same type.
+ * @param events - an array of account_data events to add
+ */
+ addAccountData(events: MatrixEvent[]): void;
+ /**
+ * Access account_data event of given event type for this room
+ * @param type - the type of account_data event to be accessed
+ * @returns the account_data event in question
+ */
+ getAccountData(type: EventType | string): MatrixEvent | undefined;
+ /**
+ * Returns whether the syncing user has permission to send a message in the room
+ * @returns true if the user should be permitted to send
+ * message events into the room.
+ */
+ maySendMessage(): boolean;
+ /**
+ * Returns whether the given user has permissions to issue an invite for this room.
+ * @param userId - the ID of the Matrix user to check permissions for
+ * @returns true if the user should be permitted to issue invites for this room.
+ */
+ canInvite(userId: string): boolean;
+ /**
+ * Returns the join rule based on the m.room.join_rule state event, defaulting to `invite`.
+ * @returns the join_rule applied to this room
+ */
+ getJoinRule(): JoinRule;
+ /**
+ * Returns the history visibility based on the m.room.history_visibility state event, defaulting to `shared`.
+ * @returns the history_visibility applied to this room
+ */
+ getHistoryVisibility(): HistoryVisibility;
+ /**
+ * Returns the history visibility based on the m.room.history_visibility state event, defaulting to `shared`.
+ * @returns the history_visibility applied to this room
+ */
+ getGuestAccess(): GuestAccess;
+ /**
+ * Returns the type of the room from the `m.room.create` event content or undefined if none is set
+ * @returns the type of the room.
+ */
+ getType(): RoomType | string | undefined;
+ /**
+ * Returns whether the room is a space-room as defined by MSC1772.
+ * @returns true if the room's type is RoomType.Space
+ */
+ isSpaceRoom(): boolean;
+ /**
+ * Returns whether the room is a call-room as defined by MSC3417.
+ * @returns true if the room's type is RoomType.UnstableCall
+ */
+ isCallRoom(): boolean;
+ /**
+ * Returns whether the room is a video room.
+ * @returns true if the room's type is RoomType.ElementVideo
+ */
+ isElementVideoRoom(): boolean;
+ /**
+ * Find the predecessor of this room.
+ *
+ * @param msc3946ProcessDynamicPredecessor - if true, look for an
+ * m.room.predecessor state event and use it if found (MSC3946).
+ * @returns null if this room has no predecessor. Otherwise, returns
+ * the roomId, last eventId and viaServers of the predecessor room.
+ *
+ * If msc3946ProcessDynamicPredecessor is true, use m.predecessor events
+ * as well as m.room.create events to find predecessors.
+ *
+ * Note: if an m.predecessor event is used, eventId may be undefined
+ * since last_known_event_id is optional.
+ *
+ * Note: viaServers may be undefined, and will definitely be undefined if
+ * this predecessor comes from a RoomCreate event (rather than a
+ * RoomPredecessor, which has the optional via_servers property).
+ */
+ findPredecessor(msc3946ProcessDynamicPredecessor?: boolean): {
+ roomId: string;
+ eventId?: string;
+ viaServers?: string[];
+ } | null;
+ private roomNameGenerator;
+ /**
+ * This is an internal method. Calculates the name of the room from the current
+ * room state.
+ * @param userId - The client's user ID. Used to filter room members
+ * correctly.
+ * @param ignoreRoomNameEvent - Return the implicit room name that we'd see if there
+ * was no m.room.name event.
+ * @returns The calculated room name.
+ */
+ private calculateRoomName;
+ /**
+ * When we receive a new visibility change event:
+ *
+ * - store this visibility change alongside the timeline, in case we
+ * later need to apply it to an event that we haven't received yet;
+ * - if we have already received the event whose visibility has changed,
+ * patch it to reflect the visibility change and inform listeners.
+ */
+ private applyNewVisibilityEvent;
+ private redactVisibilityChangeEvent;
+ /**
+ * When we receive an event whose visibility has been altered by
+ * a (more recent) visibility change event, patch the event in
+ * place so that clients now not to display it.
+ *
+ * @param event - Any matrix event. If this event has at least one a
+ * pending visibility change event, apply the latest visibility
+ * change event.
+ */
+ private applyPendingVisibilityEvents;
+ /**
+ * Find when a client has gained thread capabilities by inspecting the oldest
+ * threaded receipt
+ * @returns the timestamp of the oldest threaded receipt
+ */
+ getOldestThreadedReceiptTs(): number;
+ /**
+ * Returns the most recent unthreaded receipt for a given user
+ * @param userId - the MxID of the User
+ * @returns an unthreaded Receipt. Can be undefined if receipts have been disabled
+ * or a user chooses to use private read receipts (or we have simply not received
+ * a receipt from this user yet).
+ */
+ getLastUnthreadedReceiptFor(userId: string): Receipt | undefined;
+ /**
+ * This issue should also be addressed on synapse's side and is tracked as part
+ * of https://github.com/matrix-org/synapse/issues/14837
+ *
+ *
+ * We consider a room fully read if the current user has sent
+ * the last event in the live timeline of that context and if the read receipt
+ * we have on record matches.
+ * This also detects all unread threads and applies the same logic to those
+ * contexts
+ */
+ fixupNotifications(userId: string): void;
+}
+export declare enum RoomNameType {
+ EmptyRoom = 0,
+ Generated = 1,
+ Actual = 2
+}
+export interface EmptyRoomNameState {
+ type: RoomNameType.EmptyRoom;
+ oldName?: string;
+}
+export interface GeneratedRoomNameState {
+ type: RoomNameType.Generated;
+ subtype?: "Inviting";
+ names: string[];
+ count: number;
+}
+export interface ActualRoomNameState {
+ type: RoomNameType.Actual;
+ name: string;
+}
+export type RoomNameState = EmptyRoomNameState | GeneratedRoomNameState | ActualRoomNameState;
+export {};
+//# sourceMappingURL=room.d.ts.map \ No newline at end of file
diff --git a/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/room.d.ts.map b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/room.d.ts.map
new file mode 100644
index 0000000..ce49a21
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/room.d.ts.map
@@ -0,0 +1 @@
+{"version":3,"file":"room.d.ts","sourceRoot":"","sources":["../../src/models/room.ts"],"names":[],"mappings":"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"} \ No newline at end of file
diff --git a/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/room.js b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/room.js
new file mode 100644
index 0000000..46dd7de
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/room.js
@@ -0,0 +1,2979 @@
+"use strict";
+
+var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.RoomNameType = exports.RoomEvent = exports.Room = exports.NotificationCountType = exports.KNOWN_SAFE_ROOM_VERSION = void 0;
+var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
+var _matrixEventsSdk = require("matrix-events-sdk");
+var _eventTimelineSet = require("./event-timeline-set");
+var _eventTimeline = require("./event-timeline");
+var _contentRepo = require("../content-repo");
+var utils = _interopRequireWildcard(require("../utils"));
+var _event = require("./event");
+var _eventStatus = require("./event-status");
+var _roomMember = require("./room-member");
+var _roomSummary = require("./room-summary");
+var _logger = require("../logger");
+var _ReEmitter = require("../ReEmitter");
+var _event2 = require("../@types/event");
+var _client = require("../client");
+var _filter = require("../filter");
+var _roomState = require("./room-state");
+var _beacon = require("./beacon");
+var _thread = require("./thread");
+var _read_receipts = require("../@types/read_receipts");
+var _relationsContainer = require("./relations-container");
+var _readReceipt = require("./read-receipt");
+var _poll = require("./poll");
+function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
+function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
+function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
+function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { (0, _defineProperty2.default)(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
+// These constants are used as sane defaults when the homeserver doesn't support
+// the m.room_versions capability. In practice, KNOWN_SAFE_ROOM_VERSION should be
+// the same as the common default room version whereas SAFE_ROOM_VERSIONS are the
+// room versions which are considered okay for people to run without being asked
+// to upgrade (ie: "stable"). Eventually, we should remove these when all homeservers
+// return an m.room_versions capability.
+const KNOWN_SAFE_ROOM_VERSION = "9";
+exports.KNOWN_SAFE_ROOM_VERSION = KNOWN_SAFE_ROOM_VERSION;
+const SAFE_ROOM_VERSIONS = ["1", "2", "3", "4", "5", "6", "7", "8", "9"];
+// When inserting a visibility event affecting event `eventId`, we
+// need to scan through existing visibility events for `eventId`.
+// In theory, this could take an unlimited amount of time if:
+//
+// - the visibility event was sent by a moderator; and
+// - `eventId` already has many visibility changes (usually, it should
+// be 2 or less); and
+// - for some reason, the visibility changes are received out of order
+// (usually, this shouldn't happen at all).
+//
+// For this reason, we limit the number of events to scan through,
+// expecting that a broken visibility change for a single event in
+// an extremely uncommon case (possibly a DoS) is a small
+// price to pay to keep matrix-js-sdk responsive.
+const MAX_NUMBER_OF_VISIBILITY_EVENTS_TO_SCAN_THROUGH = 30;
+let NotificationCountType;
+exports.NotificationCountType = NotificationCountType;
+(function (NotificationCountType) {
+ NotificationCountType["Highlight"] = "highlight";
+ NotificationCountType["Total"] = "total";
+})(NotificationCountType || (exports.NotificationCountType = NotificationCountType = {}));
+let RoomEvent;
+exports.RoomEvent = RoomEvent;
+(function (RoomEvent) {
+ RoomEvent["MyMembership"] = "Room.myMembership";
+ RoomEvent["Tags"] = "Room.tags";
+ RoomEvent["AccountData"] = "Room.accountData";
+ RoomEvent["Receipt"] = "Room.receipt";
+ RoomEvent["Name"] = "Room.name";
+ RoomEvent["Redaction"] = "Room.redaction";
+ RoomEvent["RedactionCancelled"] = "Room.redactionCancelled";
+ RoomEvent["LocalEchoUpdated"] = "Room.localEchoUpdated";
+ RoomEvent["Timeline"] = "Room.timeline";
+ RoomEvent["TimelineReset"] = "Room.timelineReset";
+ RoomEvent["TimelineRefresh"] = "Room.TimelineRefresh";
+ RoomEvent["OldStateUpdated"] = "Room.OldStateUpdated";
+ RoomEvent["CurrentStateUpdated"] = "Room.CurrentStateUpdated";
+ RoomEvent["HistoryImportedWithinTimeline"] = "Room.historyImportedWithinTimeline";
+ RoomEvent["UnreadNotifications"] = "Room.UnreadNotifications";
+})(RoomEvent || (exports.RoomEvent = RoomEvent = {}));
+class Room extends _readReceipt.ReadReceipt {
+ // Pending in-flight requests { string: MatrixEvent }
+
+ // Useful to know at what point the current user has started using threads in this room
+
+ /**
+ * A record of the latest unthread receipts per user
+ * This is useful in determining whether a user has read a thread or not
+ */
+
+ // any filtered timeline sets we're maintaining for this room
+ // filter_id: timelineSet
+
+ // read by megolm via getter; boolean value - null indicates "use global value"
+
+ // flags to stop logspam about missing m.room.create events
+
+ // XXX: These should be read-only
+ /**
+ * The human-readable display name for this room.
+ */
+
+ /**
+ * The un-homoglyphed name for this room.
+ */
+
+ /**
+ * Dict of room tags; the keys are the tag name and the values
+ * are any metadata associated with the tag - e.g. `{ "fav" : { order: 1 } }`
+ */
+ // $tagName: { $metadata: $value }
+ /**
+ * accountData Dict of per-room account_data events; the keys are the
+ * event type and the values are the events.
+ */
+ // $eventType: $event
+ /**
+ * The room summary.
+ */
+
+ // legacy fields
+ /**
+ * The live event timeline for this room, with the oldest event at index 0.
+ * Present for backwards compatibility - prefer getLiveTimeline().getEvents()
+ */
+
+ /**
+ * oldState The state of the room at the time of the oldest
+ * event in the live timeline. Present for backwards compatibility -
+ * prefer getLiveTimeline().getState(EventTimeline.BACKWARDS).
+ */
+
+ /**
+ * currentState The state of the room at the time of the
+ * newest event in the timeline. Present for backwards compatibility -
+ * prefer getLiveTimeline().getState(EventTimeline.FORWARDS).
+ */
+
+ /**
+ * A collection of events known by the client
+ * This is not a comprehensive list of the threads that exist in this room
+ */
+
+ /**
+ * A mapping of eventId to all visibility changes to apply
+ * to the event, by chronological order, as per
+ * https://github.com/matrix-org/matrix-doc/pull/3531
+ *
+ * # Invariants
+ *
+ * - within each list, all events are classed by
+ * chronological order;
+ * - all events are events such that
+ * `asVisibilityEvent()` returns a non-null `IVisibilityChange`;
+ * - within each list with key `eventId`, all events
+ * are in relation to `eventId`.
+ *
+ * @experimental
+ */
+
+ /**
+ * Construct a new Room.
+ *
+ * <p>For a room, we store an ordered sequence of timelines, which may or may not
+ * be continuous. Each timeline lists a series of events, as well as tracking
+ * the room state at the start and the end of the timeline. It also tracks
+ * forward and backward pagination tokens, as well as containing links to the
+ * next timeline in the sequence.
+ *
+ * <p>There is one special timeline - the 'live' timeline, which represents the
+ * timeline to which events are being added in real-time as they are received
+ * from the /sync API. Note that you should not retain references to this
+ * timeline - even if it is the current timeline right now, it may not remain
+ * so if the server gives us a timeline gap in /sync.
+ *
+ * <p>In order that we can find events from their ids later, we also maintain a
+ * map from event_id to timeline and index.
+ *
+ * @param roomId - Required. The ID of this room.
+ * @param client - Required. The client, used to lazy load members.
+ * @param myUserId - Required. The ID of the syncing user.
+ * @param opts - Configuration options
+ */
+ constructor(roomId, client, myUserId, opts = {}) {
+ super();
+ // In some cases, we add listeners for every displayed Matrix event, so it's
+ // common to have quite a few more than the default limit.
+ this.roomId = roomId;
+ this.client = client;
+ this.myUserId = myUserId;
+ this.opts = opts;
+ (0, _defineProperty2.default)(this, "reEmitter", void 0);
+ (0, _defineProperty2.default)(this, "txnToEvent", new Map());
+ (0, _defineProperty2.default)(this, "notificationCounts", {});
+ (0, _defineProperty2.default)(this, "threadNotifications", new Map());
+ (0, _defineProperty2.default)(this, "cachedThreadReadReceipts", new Map());
+ (0, _defineProperty2.default)(this, "oldestThreadedReceiptTs", Infinity);
+ (0, _defineProperty2.default)(this, "unthreadedReceipts", new Map());
+ (0, _defineProperty2.default)(this, "timelineSets", void 0);
+ (0, _defineProperty2.default)(this, "polls", new Map());
+ (0, _defineProperty2.default)(this, "threadsTimelineSets", []);
+ (0, _defineProperty2.default)(this, "filteredTimelineSets", {});
+ (0, _defineProperty2.default)(this, "timelineNeedsRefresh", false);
+ (0, _defineProperty2.default)(this, "pendingEventList", void 0);
+ (0, _defineProperty2.default)(this, "blacklistUnverifiedDevices", void 0);
+ (0, _defineProperty2.default)(this, "selfMembership", void 0);
+ (0, _defineProperty2.default)(this, "summaryHeroes", null);
+ (0, _defineProperty2.default)(this, "getTypeWarning", false);
+ (0, _defineProperty2.default)(this, "getVersionWarning", false);
+ (0, _defineProperty2.default)(this, "membersPromise", void 0);
+ (0, _defineProperty2.default)(this, "name", void 0);
+ (0, _defineProperty2.default)(this, "normalizedName", void 0);
+ (0, _defineProperty2.default)(this, "tags", {});
+ (0, _defineProperty2.default)(this, "accountData", new Map());
+ (0, _defineProperty2.default)(this, "summary", null);
+ (0, _defineProperty2.default)(this, "timeline", void 0);
+ (0, _defineProperty2.default)(this, "oldState", void 0);
+ (0, _defineProperty2.default)(this, "currentState", void 0);
+ (0, _defineProperty2.default)(this, "relations", new _relationsContainer.RelationsContainer(this.client, this));
+ (0, _defineProperty2.default)(this, "threads", new Map());
+ (0, _defineProperty2.default)(this, "lastThread", void 0);
+ (0, _defineProperty2.default)(this, "visibilityEvents", new Map());
+ (0, _defineProperty2.default)(this, "threadTimelineSetsPromise", null);
+ (0, _defineProperty2.default)(this, "threadsReady", false);
+ (0, _defineProperty2.default)(this, "updateThreadRootEvents", (thread, toStartOfTimeline, recreateEvent) => {
+ if (thread.length) {
+ var _this$threadsTimeline;
+ this.updateThreadRootEvent((_this$threadsTimeline = this.threadsTimelineSets) === null || _this$threadsTimeline === void 0 ? void 0 : _this$threadsTimeline[0], thread, toStartOfTimeline, recreateEvent);
+ if (thread.hasCurrentUserParticipated) {
+ var _this$threadsTimeline2;
+ this.updateThreadRootEvent((_this$threadsTimeline2 = this.threadsTimelineSets) === null || _this$threadsTimeline2 === void 0 ? void 0 : _this$threadsTimeline2[1], thread, toStartOfTimeline, recreateEvent);
+ }
+ }
+ });
+ (0, _defineProperty2.default)(this, "updateThreadRootEvent", (timelineSet, thread, toStartOfTimeline, recreateEvent) => {
+ if (timelineSet && thread.rootEvent) {
+ if (recreateEvent) {
+ timelineSet.removeEvent(thread.id);
+ }
+ if (_thread.Thread.hasServerSideSupport) {
+ timelineSet.addLiveEvent(thread.rootEvent, {
+ duplicateStrategy: _eventTimelineSet.DuplicateStrategy.Replace,
+ fromCache: false,
+ roomState: this.currentState
+ });
+ } else {
+ timelineSet.addEventToTimeline(thread.rootEvent, timelineSet.getLiveTimeline(), {
+ toStartOfTimeline
+ });
+ }
+ }
+ });
+ (0, _defineProperty2.default)(this, "applyRedaction", event => {
+ if (event.isRedaction()) {
+ const redactId = event.event.redacts;
+
+ // if we know about this event, redact its contents now.
+ const redactedEvent = redactId ? this.findEventById(redactId) : undefined;
+ if (redactedEvent) {
+ redactedEvent.makeRedacted(event);
+
+ // If this is in the current state, replace it with the redacted version
+ if (redactedEvent.isState()) {
+ const currentStateEvent = this.currentState.getStateEvents(redactedEvent.getType(), redactedEvent.getStateKey());
+ if ((currentStateEvent === null || currentStateEvent === void 0 ? void 0 : currentStateEvent.getId()) === redactedEvent.getId()) {
+ this.currentState.setStateEvents([redactedEvent]);
+ }
+ }
+ this.emit(RoomEvent.Redaction, event, this);
+
+ // TODO: we stash user displaynames (among other things) in
+ // RoomMember objects which are then attached to other events
+ // (in the sender and target fields). We should get those
+ // RoomMember objects to update themselves when the events that
+ // they are based on are changed.
+
+ // Remove any visibility change on this event.
+ this.visibilityEvents.delete(redactId);
+
+ // If this event is a visibility change event, remove it from the
+ // list of visibility changes and update any event affected by it.
+ if (redactedEvent.isVisibilityEvent()) {
+ this.redactVisibilityChangeEvent(event);
+ }
+ }
+
+ // FIXME: apply redactions to notification list
+
+ // NB: We continue to add the redaction event to the timeline so
+ // clients can say "so and so redacted an event" if they wish to. Also
+ // this may be needed to trigger an update.
+ }
+ });
+ this.setMaxListeners(100);
+ this.reEmitter = new _ReEmitter.TypedReEmitter(this);
+ opts.pendingEventOrdering = opts.pendingEventOrdering || _client.PendingEventOrdering.Chronological;
+ this.name = roomId;
+ this.normalizedName = roomId;
+
+ // all our per-room timeline sets. the first one is the unfiltered ones;
+ // the subsequent ones are the filtered ones in no particular order.
+ this.timelineSets = [new _eventTimelineSet.EventTimelineSet(this, opts)];
+ this.reEmitter.reEmit(this.getUnfilteredTimelineSet(), [RoomEvent.Timeline, RoomEvent.TimelineReset]);
+ this.fixUpLegacyTimelineFields();
+ if (this.opts.pendingEventOrdering === _client.PendingEventOrdering.Detached) {
+ this.pendingEventList = [];
+ this.client.store.getPendingEvents(this.roomId).then(events => {
+ const mapper = this.client.getEventMapper({
+ toDevice: false,
+ decrypt: false
+ });
+ events.forEach(async serializedEvent => {
+ const event = mapper(serializedEvent);
+ await client.decryptEventIfNeeded(event);
+ event.setStatus(_eventStatus.EventStatus.NOT_SENT);
+ this.addPendingEvent(event, event.getTxnId());
+ });
+ });
+ }
+
+ // awaited by getEncryptionTargetMembers while room members are loading
+ if (!this.opts.lazyLoadMembers) {
+ this.membersPromise = Promise.resolve(false);
+ } else {
+ this.membersPromise = undefined;
+ }
+ }
+ async createThreadsTimelineSets() {
+ var _this$client;
+ if (this.threadTimelineSetsPromise) {
+ return this.threadTimelineSetsPromise;
+ }
+ if ((_this$client = this.client) !== null && _this$client !== void 0 && _this$client.supportsThreads()) {
+ try {
+ this.threadTimelineSetsPromise = Promise.all([this.createThreadTimelineSet(), this.createThreadTimelineSet(_thread.ThreadFilterType.My)]);
+ const timelineSets = await this.threadTimelineSetsPromise;
+ this.threadsTimelineSets.push(...timelineSets);
+ return timelineSets;
+ } catch (e) {
+ this.threadTimelineSetsPromise = null;
+ return null;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Bulk decrypt critical events in a room
+ *
+ * Critical events represents the minimal set of events to decrypt
+ * for a typical UI to function properly
+ *
+ * - Last event of every room (to generate likely message preview)
+ * - All events up to the read receipt (to calculate an accurate notification count)
+ *
+ * @returns Signals when all events have been decrypted
+ */
+ async decryptCriticalEvents() {
+ if (!this.client.isCryptoEnabled()) return;
+ const readReceiptEventId = this.getEventReadUpTo(this.client.getUserId(), true);
+ const events = this.getLiveTimeline().getEvents();
+ const readReceiptTimelineIndex = events.findIndex(matrixEvent => {
+ return matrixEvent.event.event_id === readReceiptEventId;
+ });
+ const decryptionPromises = events.slice(readReceiptTimelineIndex).reverse().map(event => this.client.decryptEventIfNeeded(event, {
+ isRetry: true
+ }));
+ await Promise.allSettled(decryptionPromises);
+ }
+
+ /**
+ * Bulk decrypt events in a room
+ *
+ * @returns Signals when all events have been decrypted
+ */
+ async decryptAllEvents() {
+ if (!this.client.isCryptoEnabled()) return;
+ const decryptionPromises = this.getUnfilteredTimelineSet().getLiveTimeline().getEvents().slice(0) // copy before reversing
+ .reverse().map(event => this.client.decryptEventIfNeeded(event, {
+ isRetry: true
+ }));
+ await Promise.allSettled(decryptionPromises);
+ }
+
+ /**
+ * Gets the creator of the room
+ * @returns The creator of the room, or null if it could not be determined
+ */
+ getCreator() {
+ var _createEvent$getConte;
+ const createEvent = this.currentState.getStateEvents(_event2.EventType.RoomCreate, "");
+ return (_createEvent$getConte = createEvent === null || createEvent === void 0 ? void 0 : createEvent.getContent()["creator"]) !== null && _createEvent$getConte !== void 0 ? _createEvent$getConte : null;
+ }
+
+ /**
+ * Gets the version of the room
+ * @returns The version of the room, or null if it could not be determined
+ */
+ getVersion() {
+ var _createEvent$getConte2;
+ const createEvent = this.currentState.getStateEvents(_event2.EventType.RoomCreate, "");
+ if (!createEvent) {
+ if (!this.getVersionWarning) {
+ _logger.logger.warn("[getVersion] Room " + this.roomId + " does not have an m.room.create event");
+ this.getVersionWarning = true;
+ }
+ return "1";
+ }
+ return (_createEvent$getConte2 = createEvent.getContent()["room_version"]) !== null && _createEvent$getConte2 !== void 0 ? _createEvent$getConte2 : "1";
+ }
+
+ /**
+ * Determines whether this room needs to be upgraded to a new version
+ * @returns What version the room should be upgraded to, or null if
+ * the room does not require upgrading at this time.
+ * @deprecated Use #getRecommendedVersion() instead
+ */
+ shouldUpgradeToVersion() {
+ // TODO: Remove this function.
+ // This makes assumptions about which versions are safe, and can easily
+ // be wrong. Instead, people are encouraged to use getRecommendedVersion
+ // which determines a safer value. This function doesn't use that function
+ // because this is not async-capable, and to avoid breaking the contract
+ // we're deprecating this.
+
+ if (!SAFE_ROOM_VERSIONS.includes(this.getVersion())) {
+ return KNOWN_SAFE_ROOM_VERSION;
+ }
+ return null;
+ }
+
+ /**
+ * Determines the recommended room version for the room. This returns an
+ * object with 3 properties: `version` as the new version the
+ * room should be upgraded to (may be the same as the current version);
+ * `needsUpgrade` to indicate if the room actually can be
+ * upgraded (ie: does the current version not match?); and `urgent`
+ * to indicate if the new version patches a vulnerability in a previous
+ * version.
+ * @returns
+ * Resolves to the version the room should be upgraded to.
+ */
+ async getRecommendedVersion() {
+ const capabilities = await this.client.getCapabilities();
+ let versionCap = capabilities["m.room_versions"];
+ if (!versionCap) {
+ versionCap = {
+ default: KNOWN_SAFE_ROOM_VERSION,
+ available: {}
+ };
+ for (const safeVer of SAFE_ROOM_VERSIONS) {
+ versionCap.available[safeVer] = _client.RoomVersionStability.Stable;
+ }
+ }
+ let result = this.checkVersionAgainstCapability(versionCap);
+ if (result.urgent && result.needsUpgrade) {
+ // Something doesn't feel right: we shouldn't need to update
+ // because the version we're on should be in the protocol's
+ // namespace. This usually means that the server was updated
+ // before the client was, making us think the newest possible
+ // room version is not stable. As a solution, we'll refresh
+ // the capability we're using to determine this.
+ _logger.logger.warn("Refreshing room version capability because the server looks " + "to be supporting a newer room version we don't know about.");
+ const caps = await this.client.getCapabilities(true);
+ versionCap = caps["m.room_versions"];
+ if (!versionCap) {
+ _logger.logger.warn("No room version capability - assuming upgrade required.");
+ return result;
+ } else {
+ result = this.checkVersionAgainstCapability(versionCap);
+ }
+ }
+ return result;
+ }
+ checkVersionAgainstCapability(versionCap) {
+ const currentVersion = this.getVersion();
+ _logger.logger.log(`[${this.roomId}] Current version: ${currentVersion}`);
+ _logger.logger.log(`[${this.roomId}] Version capability: `, versionCap);
+ const result = {
+ version: currentVersion,
+ needsUpgrade: false,
+ urgent: false
+ };
+
+ // If the room is on the default version then nothing needs to change
+ if (currentVersion === versionCap.default) return result;
+ const stableVersions = Object.keys(versionCap.available).filter(v => versionCap.available[v] === "stable");
+
+ // Check if the room is on an unstable version. We determine urgency based
+ // off the version being in the Matrix spec namespace or not (if the version
+ // is in the current namespace and unstable, the room is probably vulnerable).
+ if (!stableVersions.includes(currentVersion)) {
+ result.version = versionCap.default;
+ result.needsUpgrade = true;
+ result.urgent = !!this.getVersion().match(/^[0-9]+[0-9.]*$/g);
+ if (result.urgent) {
+ _logger.logger.warn(`URGENT upgrade required on ${this.roomId}`);
+ } else {
+ _logger.logger.warn(`Non-urgent upgrade required on ${this.roomId}`);
+ }
+ return result;
+ }
+
+ // The room is on a stable, but non-default, version by this point.
+ // No upgrade needed.
+ return result;
+ }
+
+ /**
+ * Determines whether the given user is permitted to perform a room upgrade
+ * @param userId - The ID of the user to test against
+ * @returns True if the given user is permitted to upgrade the room
+ */
+ userMayUpgradeRoom(userId) {
+ return this.currentState.maySendStateEvent(_event2.EventType.RoomTombstone, userId);
+ }
+
+ /**
+ * Get the list of pending sent events for this room
+ *
+ * @returns A list of the sent events
+ * waiting for remote echo.
+ *
+ * @throws If `opts.pendingEventOrdering` was not 'detached'
+ */
+ getPendingEvents() {
+ if (!this.pendingEventList) {
+ throw new Error("Cannot call getPendingEvents with pendingEventOrdering == " + this.opts.pendingEventOrdering);
+ }
+ return this.pendingEventList;
+ }
+
+ /**
+ * Removes a pending event for this room
+ *
+ * @returns True if an element was removed.
+ */
+ removePendingEvent(eventId) {
+ if (!this.pendingEventList) {
+ throw new Error("Cannot call removePendingEvent with pendingEventOrdering == " + this.opts.pendingEventOrdering);
+ }
+ const removed = utils.removeElement(this.pendingEventList, function (ev) {
+ return ev.getId() == eventId;
+ }, false);
+ this.savePendingEvents();
+ return removed;
+ }
+
+ /**
+ * Check whether the pending event list contains a given event by ID.
+ * If pending event ordering is not "detached" then this returns false.
+ *
+ * @param eventId - The event ID to check for.
+ */
+ hasPendingEvent(eventId) {
+ var _this$pendingEventLis, _this$pendingEventLis2;
+ return (_this$pendingEventLis = (_this$pendingEventLis2 = this.pendingEventList) === null || _this$pendingEventLis2 === void 0 ? void 0 : _this$pendingEventLis2.some(event => event.getId() === eventId)) !== null && _this$pendingEventLis !== void 0 ? _this$pendingEventLis : false;
+ }
+
+ /**
+ * Get a specific event from the pending event list, if configured, null otherwise.
+ *
+ * @param eventId - The event ID to check for.
+ */
+ getPendingEvent(eventId) {
+ var _this$pendingEventLis3, _this$pendingEventLis4;
+ return (_this$pendingEventLis3 = (_this$pendingEventLis4 = this.pendingEventList) === null || _this$pendingEventLis4 === void 0 ? void 0 : _this$pendingEventLis4.find(event => event.getId() === eventId)) !== null && _this$pendingEventLis3 !== void 0 ? _this$pendingEventLis3 : null;
+ }
+
+ /**
+ * Get the live unfiltered timeline for this room.
+ *
+ * @returns live timeline
+ */
+ getLiveTimeline() {
+ return this.getUnfilteredTimelineSet().getLiveTimeline();
+ }
+
+ /**
+ * Get the timestamp of the last message in the room
+ *
+ * @returns the timestamp of the last message in the room
+ */
+ getLastActiveTimestamp() {
+ const timeline = this.getLiveTimeline();
+ const events = timeline.getEvents();
+ if (events.length) {
+ const lastEvent = events[events.length - 1];
+ return lastEvent.getTs();
+ } else {
+ return Number.MIN_SAFE_INTEGER;
+ }
+ }
+
+ /**
+ * @returns the membership type (join | leave | invite) for the logged in user
+ */
+ getMyMembership() {
+ var _this$selfMembership;
+ return (_this$selfMembership = this.selfMembership) !== null && _this$selfMembership !== void 0 ? _this$selfMembership : "leave";
+ }
+
+ /**
+ * If this room is a DM we're invited to,
+ * try to find out who invited us
+ * @returns user id of the inviter
+ */
+ getDMInviter() {
+ const me = this.getMember(this.myUserId);
+ if (me) {
+ return me.getDMInviter();
+ }
+ if (this.selfMembership === "invite") {
+ // fall back to summary information
+ const memberCount = this.getInvitedAndJoinedMemberCount();
+ if (memberCount === 2) {
+ var _this$summaryHeroes;
+ return (_this$summaryHeroes = this.summaryHeroes) === null || _this$summaryHeroes === void 0 ? void 0 : _this$summaryHeroes[0];
+ }
+ }
+ }
+
+ /**
+ * Assuming this room is a DM room, tries to guess with which user.
+ * @returns user id of the other member (could be syncing user)
+ */
+ guessDMUserId() {
+ const me = this.getMember(this.myUserId);
+ if (me) {
+ const inviterId = me.getDMInviter();
+ if (inviterId) {
+ return inviterId;
+ }
+ }
+ // Remember, we're assuming this room is a DM, so returning the first member we find should be fine
+ if (Array.isArray(this.summaryHeroes) && this.summaryHeroes.length) {
+ return this.summaryHeroes[0];
+ }
+ const members = this.currentState.getMembers();
+ const anyMember = members.find(m => m.userId !== this.myUserId);
+ if (anyMember) {
+ return anyMember.userId;
+ }
+ // it really seems like I'm the only user in the room
+ // so I probably created a room with just me in it
+ // and marked it as a DM. Ok then
+ return this.myUserId;
+ }
+ getAvatarFallbackMember() {
+ const memberCount = this.getInvitedAndJoinedMemberCount();
+ if (memberCount > 2) {
+ return;
+ }
+ const hasHeroes = Array.isArray(this.summaryHeroes) && this.summaryHeroes.length;
+ if (hasHeroes) {
+ const availableMember = this.summaryHeroes.map(userId => {
+ return this.getMember(userId);
+ }).find(member => !!member);
+ if (availableMember) {
+ return availableMember;
+ }
+ }
+ const members = this.currentState.getMembers();
+ // could be different than memberCount
+ // as this includes left members
+ if (members.length <= 2) {
+ const availableMember = members.find(m => {
+ return m.userId !== this.myUserId;
+ });
+ if (availableMember) {
+ return availableMember;
+ }
+ }
+ // if all else fails, try falling back to a user,
+ // and create a one-off member for it
+ if (hasHeroes) {
+ const availableUser = this.summaryHeroes.map(userId => {
+ return this.client.getUser(userId);
+ }).find(user => !!user);
+ if (availableUser) {
+ const member = new _roomMember.RoomMember(this.roomId, availableUser.userId);
+ member.user = availableUser;
+ return member;
+ }
+ }
+ }
+
+ /**
+ * Sets the membership this room was received as during sync
+ * @param membership - join | leave | invite
+ */
+ updateMyMembership(membership) {
+ const prevMembership = this.selfMembership;
+ this.selfMembership = membership;
+ if (prevMembership !== membership) {
+ if (membership === "leave") {
+ this.cleanupAfterLeaving();
+ }
+ this.emit(RoomEvent.MyMembership, this, membership, prevMembership);
+ }
+ }
+ async loadMembersFromServer() {
+ const lastSyncToken = this.client.store.getSyncToken();
+ const response = await this.client.members(this.roomId, undefined, "leave", lastSyncToken !== null && lastSyncToken !== void 0 ? lastSyncToken : undefined);
+ return response.chunk;
+ }
+ async loadMembers() {
+ // were the members loaded from the server?
+ let fromServer = false;
+ let rawMembersEvents = await this.client.store.getOutOfBandMembers(this.roomId);
+ // If the room is encrypted, we always fetch members from the server at
+ // least once, in case the latest state wasn't persisted properly. Note
+ // that this function is only called once (unless loading the members
+ // fails), since loadMembersIfNeeded always returns this.membersPromise
+ // if set, which will be the result of the first (successful) call.
+ if (rawMembersEvents === null || this.client.isCryptoEnabled() && this.client.isRoomEncrypted(this.roomId)) {
+ fromServer = true;
+ rawMembersEvents = await this.loadMembersFromServer();
+ _logger.logger.log(`LL: got ${rawMembersEvents.length} ` + `members from server for room ${this.roomId}`);
+ }
+ const memberEvents = rawMembersEvents.filter(utils.noUnsafeEventProps).map(this.client.getEventMapper());
+ return {
+ memberEvents,
+ fromServer
+ };
+ }
+
+ /**
+ * Check if loading of out-of-band-members has completed
+ *
+ * @returns true if the full membership list of this room has been loaded (including if lazy-loading is disabled).
+ * False if the load is not started or is in progress.
+ */
+ membersLoaded() {
+ if (!this.opts.lazyLoadMembers) {
+ return true;
+ }
+ return this.currentState.outOfBandMembersReady();
+ }
+
+ /**
+ * Preloads the member list in case lazy loading
+ * of memberships is in use. Can be called multiple times,
+ * it will only preload once.
+ * @returns when preloading is done and
+ * accessing the members on the room will take
+ * all members in the room into account
+ */
+ loadMembersIfNeeded() {
+ if (this.membersPromise) {
+ return this.membersPromise;
+ }
+
+ // mark the state so that incoming messages while
+ // the request is in flight get marked as superseding
+ // the OOB members
+ this.currentState.markOutOfBandMembersStarted();
+ const inMemoryUpdate = this.loadMembers().then(result => {
+ this.currentState.setOutOfBandMembers(result.memberEvents);
+ return result.fromServer;
+ }).catch(err => {
+ // allow retries on fail
+ this.membersPromise = undefined;
+ this.currentState.markOutOfBandMembersFailed();
+ throw err;
+ });
+ // update members in storage, but don't wait for it
+ inMemoryUpdate.then(fromServer => {
+ if (fromServer) {
+ const oobMembers = this.currentState.getMembers().filter(m => m.isOutOfBand()).map(m => {
+ var _m$events$member;
+ return (_m$events$member = m.events.member) === null || _m$events$member === void 0 ? void 0 : _m$events$member.event;
+ });
+ _logger.logger.log(`LL: telling store to write ${oobMembers.length}` + ` members for room ${this.roomId}`);
+ const store = this.client.store;
+ return store.setOutOfBandMembers(this.roomId, oobMembers)
+ // swallow any IDB error as we don't want to fail
+ // because of this
+ .catch(err => {
+ _logger.logger.log("LL: storing OOB room members failed, oh well", err);
+ });
+ }
+ }).catch(err => {
+ // as this is not awaited anywhere,
+ // at least show the error in the console
+ _logger.logger.error(err);
+ });
+ this.membersPromise = inMemoryUpdate;
+ return this.membersPromise;
+ }
+
+ /**
+ * Removes the lazily loaded members from storage if needed
+ */
+ async clearLoadedMembersIfNeeded() {
+ if (this.opts.lazyLoadMembers && this.membersPromise) {
+ await this.loadMembersIfNeeded();
+ await this.client.store.clearOutOfBandMembers(this.roomId);
+ this.currentState.clearOutOfBandMembers();
+ this.membersPromise = undefined;
+ }
+ }
+
+ /**
+ * called when sync receives this room in the leave section
+ * to do cleanup after leaving a room. Possibly called multiple times.
+ */
+ cleanupAfterLeaving() {
+ this.clearLoadedMembersIfNeeded().catch(err => {
+ _logger.logger.error(`error after clearing loaded members from ` + `room ${this.roomId} after leaving`);
+ _logger.logger.log(err);
+ });
+ }
+
+ /**
+ * Empty out the current live timeline and re-request it. This is used when
+ * historical messages are imported into the room via MSC2716 `/batch_send`
+ * because the client may already have that section of the timeline loaded.
+ * We need to force the client to throw away their current timeline so that
+ * when they back paginate over the area again with the historical messages
+ * in between, it grabs the newly imported messages. We can listen for
+ * `UNSTABLE_MSC2716_MARKER`, in order to tell when historical messages are ready
+ * to be discovered in the room and the timeline needs a refresh. The SDK
+ * emits a `RoomEvent.HistoryImportedWithinTimeline` event when we detect a
+ * valid marker and can check the needs refresh status via
+ * `room.getTimelineNeedsRefresh()`.
+ */
+ async refreshLiveTimeline() {
+ const liveTimelineBefore = this.getLiveTimeline();
+ const forwardPaginationToken = liveTimelineBefore.getPaginationToken(_eventTimeline.EventTimeline.FORWARDS);
+ const backwardPaginationToken = liveTimelineBefore.getPaginationToken(_eventTimeline.EventTimeline.BACKWARDS);
+ const eventsBefore = liveTimelineBefore.getEvents();
+ const mostRecentEventInTimeline = eventsBefore[eventsBefore.length - 1];
+ _logger.logger.log(`[refreshLiveTimeline for ${this.roomId}] at ` + `mostRecentEventInTimeline=${mostRecentEventInTimeline && mostRecentEventInTimeline.getId()} ` + `liveTimelineBefore=${liveTimelineBefore.toString()} ` + `forwardPaginationToken=${forwardPaginationToken} ` + `backwardPaginationToken=${backwardPaginationToken}`);
+
+ // Get the main TimelineSet
+ const timelineSet = this.getUnfilteredTimelineSet();
+ let newTimeline;
+ // If there isn't any event in the timeline, let's go fetch the latest
+ // event and construct a timeline from it.
+ //
+ // This should only really happen if the user ran into an error
+ // with refreshing the timeline before which left them in a blank
+ // timeline from `resetLiveTimeline`.
+ if (!mostRecentEventInTimeline) {
+ newTimeline = await this.client.getLatestTimeline(timelineSet);
+ } else {
+ // Empty out all of `this.timelineSets`. But we also need to keep the
+ // same `timelineSet` references around so the React code updates
+ // properly and doesn't ignore the room events we emit because it checks
+ // that the `timelineSet` references are the same. We need the
+ // `timelineSet` empty so that the `client.getEventTimeline(...)` call
+ // later, will call `/context` and create a new timeline instead of
+ // returning the same one.
+ this.resetLiveTimeline(null, null);
+
+ // Make the UI timeline show the new blank live timeline we just
+ // reset so that if the network fails below it's showing the
+ // accurate state of what we're working with instead of the
+ // disconnected one in the TimelineWindow which is just hanging
+ // around by reference.
+ this.emit(RoomEvent.TimelineRefresh, this, timelineSet);
+
+ // Use `client.getEventTimeline(...)` to construct a new timeline from a
+ // `/context` response state and events for the most recent event before
+ // we reset everything. The `timelineSet` we pass in needs to be empty
+ // in order for this function to call `/context` and generate a new
+ // timeline.
+ newTimeline = await this.client.getEventTimeline(timelineSet, mostRecentEventInTimeline.getId());
+ }
+
+ // If a racing `/sync` beat us to creating a new timeline, use that
+ // instead because it's the latest in the room and any new messages in
+ // the scrollback will include the history.
+ const liveTimeline = timelineSet.getLiveTimeline();
+ if (!liveTimeline || liveTimeline.getPaginationToken(_eventTimeline.Direction.Forward) === null && liveTimeline.getPaginationToken(_eventTimeline.Direction.Backward) === null && liveTimeline.getEvents().length === 0) {
+ _logger.logger.log(`[refreshLiveTimeline for ${this.roomId}] using our new live timeline`);
+ // Set the pagination token back to the live sync token (`null`) instead
+ // of using the `/context` historical token (ex. `t12-13_0_0_0_0_0_0_0_0`)
+ // so that it matches the next response from `/sync` and we can properly
+ // continue the timeline.
+ newTimeline.setPaginationToken(forwardPaginationToken, _eventTimeline.EventTimeline.FORWARDS);
+
+ // Set our new fresh timeline as the live timeline to continue syncing
+ // forwards and back paginating from.
+ timelineSet.setLiveTimeline(newTimeline);
+ // Fixup `this.oldstate` so that `scrollback` has the pagination tokens
+ // available
+ this.fixUpLegacyTimelineFields();
+ } else {
+ _logger.logger.log(`[refreshLiveTimeline for ${this.roomId}] \`/sync\` or some other request beat us to creating a new ` + `live timeline after we reset it. We'll use that instead since any events in the scrollback from ` + `this timeline will include the history.`);
+ }
+
+ // The timeline has now been refreshed ✅
+ this.setTimelineNeedsRefresh(false);
+
+ // Emit an event which clients can react to and re-load the timeline
+ // from the SDK
+ this.emit(RoomEvent.TimelineRefresh, this, timelineSet);
+ }
+
+ /**
+ * Reset the live timeline of all timelineSets, and start new ones.
+ *
+ * <p>This is used when /sync returns a 'limited' timeline.
+ *
+ * @param backPaginationToken - token for back-paginating the new timeline
+ * @param forwardPaginationToken - token for forward-paginating the old live timeline,
+ * if absent or null, all timelines are reset, removing old ones (including the previous live
+ * timeline which would otherwise be unable to paginate forwards without this token).
+ * Removing just the old live timeline whilst preserving previous ones is not supported.
+ */
+ resetLiveTimeline(backPaginationToken, forwardPaginationToken) {
+ for (const timelineSet of this.timelineSets) {
+ timelineSet.resetLiveTimeline(backPaginationToken !== null && backPaginationToken !== void 0 ? backPaginationToken : undefined, forwardPaginationToken !== null && forwardPaginationToken !== void 0 ? forwardPaginationToken : undefined);
+ }
+ for (const thread of this.threads.values()) {
+ thread.resetLiveTimeline(backPaginationToken, forwardPaginationToken);
+ }
+ this.fixUpLegacyTimelineFields();
+ }
+
+ /**
+ * Fix up this.timeline, this.oldState and this.currentState
+ *
+ * @internal
+ */
+ fixUpLegacyTimelineFields() {
+ const previousOldState = this.oldState;
+ const previousCurrentState = this.currentState;
+
+ // maintain this.timeline as a reference to the live timeline,
+ // and this.oldState and this.currentState as references to the
+ // state at the start and end of that timeline. These are more
+ // for backwards-compatibility than anything else.
+ this.timeline = this.getLiveTimeline().getEvents();
+ this.oldState = this.getLiveTimeline().getState(_eventTimeline.EventTimeline.BACKWARDS);
+ this.currentState = this.getLiveTimeline().getState(_eventTimeline.EventTimeline.FORWARDS);
+
+ // Let people know to register new listeners for the new state
+ // references. The reference won't necessarily change every time so only
+ // emit when we see a change.
+ if (previousOldState !== this.oldState) {
+ this.emit(RoomEvent.OldStateUpdated, this, previousOldState, this.oldState);
+ }
+ if (previousCurrentState !== this.currentState) {
+ this.emit(RoomEvent.CurrentStateUpdated, this, previousCurrentState, this.currentState);
+
+ // Re-emit various events on the current room state
+ // TODO: If currentState really only exists for backwards
+ // compatibility, shouldn't we be doing this some other way?
+ this.reEmitter.stopReEmitting(previousCurrentState, [_roomState.RoomStateEvent.Events, _roomState.RoomStateEvent.Members, _roomState.RoomStateEvent.NewMember, _roomState.RoomStateEvent.Update, _roomState.RoomStateEvent.Marker, _beacon.BeaconEvent.New, _beacon.BeaconEvent.Update, _beacon.BeaconEvent.Destroy, _beacon.BeaconEvent.LivenessChange]);
+ this.reEmitter.reEmit(this.currentState, [_roomState.RoomStateEvent.Events, _roomState.RoomStateEvent.Members, _roomState.RoomStateEvent.NewMember, _roomState.RoomStateEvent.Update, _roomState.RoomStateEvent.Marker, _beacon.BeaconEvent.New, _beacon.BeaconEvent.Update, _beacon.BeaconEvent.Destroy, _beacon.BeaconEvent.LivenessChange]);
+ }
+ }
+
+ /**
+ * Returns whether there are any devices in the room that are unverified
+ *
+ * Note: Callers should first check if crypto is enabled on this device. If it is
+ * disabled, then we aren't tracking room devices at all, so we can't answer this, and an
+ * error will be thrown.
+ *
+ * @returns the result
+ */
+ async hasUnverifiedDevices() {
+ if (!this.client.isRoomEncrypted(this.roomId)) {
+ return false;
+ }
+ const e2eMembers = await this.getEncryptionTargetMembers();
+ for (const member of e2eMembers) {
+ const devices = this.client.getStoredDevicesForUser(member.userId);
+ if (devices.some(device => device.isUnverified())) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Return the timeline sets for this room.
+ * @returns array of timeline sets for this room
+ */
+ getTimelineSets() {
+ return this.timelineSets;
+ }
+
+ /**
+ * Helper to return the main unfiltered timeline set for this room
+ * @returns room's unfiltered timeline set
+ */
+ getUnfilteredTimelineSet() {
+ return this.timelineSets[0];
+ }
+
+ /**
+ * Get the timeline which contains the given event from the unfiltered set, if any
+ *
+ * @param eventId - event ID to look for
+ * @returns timeline containing
+ * the given event, or null if unknown
+ */
+ getTimelineForEvent(eventId) {
+ const event = this.findEventById(eventId);
+ const thread = this.findThreadForEvent(event);
+ if (thread) {
+ return thread.timelineSet.getTimelineForEvent(eventId);
+ } else {
+ return this.getUnfilteredTimelineSet().getTimelineForEvent(eventId);
+ }
+ }
+
+ /**
+ * Add a new timeline to this room's unfiltered timeline set
+ *
+ * @returns newly-created timeline
+ */
+ addTimeline() {
+ return this.getUnfilteredTimelineSet().addTimeline();
+ }
+
+ /**
+ * Whether the timeline needs to be refreshed in order to pull in new
+ * historical messages that were imported.
+ * @param value - The value to set
+ */
+ setTimelineNeedsRefresh(value) {
+ this.timelineNeedsRefresh = value;
+ }
+
+ /**
+ * Whether the timeline needs to be refreshed in order to pull in new
+ * historical messages that were imported.
+ * @returns .
+ */
+ getTimelineNeedsRefresh() {
+ return this.timelineNeedsRefresh;
+ }
+
+ /**
+ * Get an event which is stored in our unfiltered timeline set, or in a thread
+ *
+ * @param eventId - event ID to look for
+ * @returns the given event, or undefined if unknown
+ */
+ findEventById(eventId) {
+ let event = this.getUnfilteredTimelineSet().findEventById(eventId);
+ if (!event) {
+ const threads = this.getThreads();
+ for (let i = 0; i < threads.length; i++) {
+ const thread = threads[i];
+ event = thread.findEventById(eventId);
+ if (event) {
+ return event;
+ }
+ }
+ }
+ return event;
+ }
+
+ /**
+ * Get one of the notification counts for this room
+ * @param type - The type of notification count to get. default: 'total'
+ * @returns The notification count, or undefined if there is no count
+ * for this type.
+ */
+ getUnreadNotificationCount(type = NotificationCountType.Total) {
+ let count = this.getRoomUnreadNotificationCount(type);
+ for (const threadNotification of this.threadNotifications.values()) {
+ var _threadNotification$t;
+ count += (_threadNotification$t = threadNotification[type]) !== null && _threadNotification$t !== void 0 ? _threadNotification$t : 0;
+ }
+ return count;
+ }
+
+ /**
+ * Get the notification for the event context (room or thread timeline)
+ */
+ getUnreadCountForEventContext(type = NotificationCountType.Total, event) {
+ var _ref;
+ const isThreadEvent = !!event.threadRootId && !event.isThreadRoot;
+ return (_ref = isThreadEvent ? this.getThreadUnreadNotificationCount(event.threadRootId, type) : this.getRoomUnreadNotificationCount(type)) !== null && _ref !== void 0 ? _ref : 0;
+ }
+
+ /**
+ * Get one of the notification counts for this room
+ * @param type - The type of notification count to get. default: 'total'
+ * @returns The notification count, or undefined if there is no count
+ * for this type.
+ */
+ getRoomUnreadNotificationCount(type = NotificationCountType.Total) {
+ var _this$notificationCou;
+ return (_this$notificationCou = this.notificationCounts[type]) !== null && _this$notificationCou !== void 0 ? _this$notificationCou : 0;
+ }
+
+ /**
+ * Get one of the notification counts for a thread
+ * @param threadId - the root event ID
+ * @param type - The type of notification count to get. default: 'total'
+ * @returns The notification count, or undefined if there is no count
+ * for this type.
+ */
+ getThreadUnreadNotificationCount(threadId, type = NotificationCountType.Total) {
+ var _this$threadNotificat, _this$threadNotificat2;
+ return (_this$threadNotificat = (_this$threadNotificat2 = this.threadNotifications.get(threadId)) === null || _this$threadNotificat2 === void 0 ? void 0 : _this$threadNotificat2[type]) !== null && _this$threadNotificat !== void 0 ? _this$threadNotificat : 0;
+ }
+
+ /**
+ * Checks if the current room has unread thread notifications
+ * @returns
+ */
+ hasThreadUnreadNotification() {
+ for (const notification of this.threadNotifications.values()) {
+ var _notification$highlig, _notification$total;
+ if (((_notification$highlig = notification.highlight) !== null && _notification$highlig !== void 0 ? _notification$highlig : 0) > 0 || ((_notification$total = notification.total) !== null && _notification$total !== void 0 ? _notification$total : 0) > 0) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Swet one of the notification count for a thread
+ * @param threadId - the root event ID
+ * @param type - The type of notification count to get. default: 'total'
+ * @returns
+ */
+ setThreadUnreadNotificationCount(threadId, type, count) {
+ var _this$threadNotificat3, _this$threadNotificat4;
+ const notification = _objectSpread({
+ highlight: (_this$threadNotificat3 = this.threadNotifications.get(threadId)) === null || _this$threadNotificat3 === void 0 ? void 0 : _this$threadNotificat3.highlight,
+ total: (_this$threadNotificat4 = this.threadNotifications.get(threadId)) === null || _this$threadNotificat4 === void 0 ? void 0 : _this$threadNotificat4.total
+ }, {
+ [type]: count
+ });
+ this.threadNotifications.set(threadId, notification);
+ this.emit(RoomEvent.UnreadNotifications, notification, threadId);
+ }
+
+ /**
+ * @returns the notification count type for all the threads in the room
+ */
+ get threadsAggregateNotificationType() {
+ let type = null;
+ for (const threadNotification of this.threadNotifications.values()) {
+ var _threadNotification$h, _threadNotification$t2;
+ if (((_threadNotification$h = threadNotification.highlight) !== null && _threadNotification$h !== void 0 ? _threadNotification$h : 0) > 0) {
+ return NotificationCountType.Highlight;
+ } else if (((_threadNotification$t2 = threadNotification.total) !== null && _threadNotification$t2 !== void 0 ? _threadNotification$t2 : 0) > 0 && !type) {
+ type = NotificationCountType.Total;
+ }
+ }
+ return type;
+ }
+
+ /**
+ * Resets the thread notifications for this room
+ */
+ resetThreadUnreadNotificationCount(notificationsToKeep) {
+ if (notificationsToKeep) {
+ for (const [threadId] of this.threadNotifications) {
+ if (!notificationsToKeep.includes(threadId)) {
+ this.threadNotifications.delete(threadId);
+ }
+ }
+ } else {
+ this.threadNotifications.clear();
+ }
+ this.emit(RoomEvent.UnreadNotifications);
+ }
+
+ /**
+ * Set one of the notification counts for this room
+ * @param type - The type of notification count to set.
+ * @param count - The new count
+ */
+ setUnreadNotificationCount(type, count) {
+ this.notificationCounts[type] = count;
+ this.emit(RoomEvent.UnreadNotifications, this.notificationCounts);
+ }
+ setUnread(type, count) {
+ return this.setUnreadNotificationCount(type, count);
+ }
+ setSummary(summary) {
+ const heroes = summary["m.heroes"];
+ const joinedCount = summary["m.joined_member_count"];
+ const invitedCount = summary["m.invited_member_count"];
+ if (Number.isInteger(joinedCount)) {
+ this.currentState.setJoinedMemberCount(joinedCount);
+ }
+ if (Number.isInteger(invitedCount)) {
+ this.currentState.setInvitedMemberCount(invitedCount);
+ }
+ if (Array.isArray(heroes)) {
+ // be cautious about trusting server values,
+ // and make sure heroes doesn't contain our own id
+ // just to be sure
+ this.summaryHeroes = heroes.filter(userId => {
+ return userId !== this.myUserId;
+ });
+ }
+ }
+
+ /**
+ * Whether to send encrypted messages to devices within this room.
+ * @param value - true to blacklist unverified devices, null
+ * to use the global value for this room.
+ */
+ setBlacklistUnverifiedDevices(value) {
+ this.blacklistUnverifiedDevices = value;
+ }
+
+ /**
+ * Whether to send encrypted messages to devices within this room.
+ * @returns true if blacklisting unverified devices, null
+ * if the global value should be used for this room.
+ */
+ getBlacklistUnverifiedDevices() {
+ if (this.blacklistUnverifiedDevices === undefined) return null;
+ return this.blacklistUnverifiedDevices;
+ }
+
+ /**
+ * Get the avatar URL for a room if one was set.
+ * @param baseUrl - The homeserver base URL. See
+ * {@link MatrixClient#getHomeserverUrl}.
+ * @param width - The desired width of the thumbnail.
+ * @param height - The desired height of the thumbnail.
+ * @param resizeMethod - The thumbnail resize method to use, either
+ * "crop" or "scale".
+ * @param allowDefault - True to allow an identicon for this room if an
+ * avatar URL wasn't explicitly set. Default: true. (Deprecated)
+ * @returns the avatar URL or null.
+ */
+ getAvatarUrl(baseUrl, width, height, resizeMethod, allowDefault = true) {
+ const roomAvatarEvent = this.currentState.getStateEvents(_event2.EventType.RoomAvatar, "");
+ if (!roomAvatarEvent && !allowDefault) {
+ return null;
+ }
+ const mainUrl = roomAvatarEvent ? roomAvatarEvent.getContent().url : null;
+ if (mainUrl) {
+ return (0, _contentRepo.getHttpUriForMxc)(baseUrl, mainUrl, width, height, resizeMethod);
+ }
+ return null;
+ }
+
+ /**
+ * Get the mxc avatar url for the room, if one was set.
+ * @returns the mxc avatar url or falsy
+ */
+ getMxcAvatarUrl() {
+ var _this$currentState$ge, _this$currentState$ge2;
+ return ((_this$currentState$ge = this.currentState.getStateEvents(_event2.EventType.RoomAvatar, "")) === null || _this$currentState$ge === void 0 ? void 0 : (_this$currentState$ge2 = _this$currentState$ge.getContent()) === null || _this$currentState$ge2 === void 0 ? void 0 : _this$currentState$ge2.url) || null;
+ }
+
+ /**
+ * Get this room's canonical alias
+ * The alias returned by this function may not necessarily
+ * still point to this room.
+ * @returns The room's canonical alias, or null if there is none
+ */
+ getCanonicalAlias() {
+ const canonicalAlias = this.currentState.getStateEvents(_event2.EventType.RoomCanonicalAlias, "");
+ if (canonicalAlias) {
+ return canonicalAlias.getContent().alias || null;
+ }
+ return null;
+ }
+
+ /**
+ * Get this room's alternative aliases
+ * @returns The room's alternative aliases, or an empty array
+ */
+ getAltAliases() {
+ const canonicalAlias = this.currentState.getStateEvents(_event2.EventType.RoomCanonicalAlias, "");
+ if (canonicalAlias) {
+ return canonicalAlias.getContent().alt_aliases || [];
+ }
+ return [];
+ }
+
+ /**
+ * Add events to a timeline
+ *
+ * <p>Will fire "Room.timeline" for each event added.
+ *
+ * @param events - A list of events to add.
+ *
+ * @param toStartOfTimeline - True to add these events to the start
+ * (oldest) instead of the end (newest) of the timeline. If true, the oldest
+ * event will be the <b>last</b> element of 'events'.
+ *
+ * @param timeline - timeline to
+ * add events to.
+ *
+ * @param paginationToken - token for the next batch of events
+ *
+ * @remarks
+ * Fires {@link RoomEvent.Timeline}
+ */
+ addEventsToTimeline(events, toStartOfTimeline, timeline, paginationToken) {
+ timeline.getTimelineSet().addEventsToTimeline(events, toStartOfTimeline, timeline, paginationToken);
+ }
+
+ /**
+ * Get the instance of the thread associated with the current event
+ * @param eventId - the ID of the current event
+ * @returns a thread instance if known
+ */
+ getThread(eventId) {
+ var _this$threads$get;
+ return (_this$threads$get = this.threads.get(eventId)) !== null && _this$threads$get !== void 0 ? _this$threads$get : null;
+ }
+
+ /**
+ * Get all the known threads in the room
+ */
+ getThreads() {
+ return Array.from(this.threads.values());
+ }
+
+ /**
+ * Get a member from the current room state.
+ * @param userId - The user ID of the member.
+ * @returns The member or `null`.
+ */
+ getMember(userId) {
+ return this.currentState.getMember(userId);
+ }
+
+ /**
+ * Get all currently loaded members from the current
+ * room state.
+ * @returns Room members
+ */
+ getMembers() {
+ return this.currentState.getMembers();
+ }
+
+ /**
+ * Get a list of members whose membership state is "join".
+ * @returns A list of currently joined members.
+ */
+ getJoinedMembers() {
+ return this.getMembersWithMembership("join");
+ }
+
+ /**
+ * Returns the number of joined members in this room
+ * This method caches the result.
+ * This is a wrapper around the method of the same name in roomState, returning
+ * its result for the room's current state.
+ * @returns The number of members in this room whose membership is 'join'
+ */
+ getJoinedMemberCount() {
+ return this.currentState.getJoinedMemberCount();
+ }
+
+ /**
+ * Returns the number of invited members in this room
+ * @returns The number of members in this room whose membership is 'invite'
+ */
+ getInvitedMemberCount() {
+ return this.currentState.getInvitedMemberCount();
+ }
+
+ /**
+ * Returns the number of invited + joined members in this room
+ * @returns The number of members in this room whose membership is 'invite' or 'join'
+ */
+ getInvitedAndJoinedMemberCount() {
+ return this.getInvitedMemberCount() + this.getJoinedMemberCount();
+ }
+
+ /**
+ * Get a list of members with given membership state.
+ * @param membership - The membership state.
+ * @returns A list of members with the given membership state.
+ */
+ getMembersWithMembership(membership) {
+ return this.currentState.getMembers().filter(function (m) {
+ return m.membership === membership;
+ });
+ }
+
+ /**
+ * Get a list of members we should be encrypting for in this room
+ * @returns A list of members who
+ * we should encrypt messages for in this room.
+ */
+ async getEncryptionTargetMembers() {
+ await this.loadMembersIfNeeded();
+ let members = this.getMembersWithMembership("join");
+ if (this.shouldEncryptForInvitedMembers()) {
+ members = members.concat(this.getMembersWithMembership("invite"));
+ }
+ return members;
+ }
+
+ /**
+ * Determine whether we should encrypt messages for invited users in this room
+ * @returns if we should encrypt messages for invited users
+ */
+ shouldEncryptForInvitedMembers() {
+ var _ev$getContent;
+ const ev = this.currentState.getStateEvents(_event2.EventType.RoomHistoryVisibility, "");
+ return (ev === null || ev === void 0 ? void 0 : (_ev$getContent = ev.getContent()) === null || _ev$getContent === void 0 ? void 0 : _ev$getContent.history_visibility) !== "joined";
+ }
+
+ /**
+ * Get the default room name (i.e. what a given user would see if the
+ * room had no m.room.name)
+ * @param userId - The userId from whose perspective we want
+ * to calculate the default name
+ * @returns The default room name
+ */
+ getDefaultRoomName(userId) {
+ return this.calculateRoomName(userId, true);
+ }
+
+ /**
+ * Check if the given user_id has the given membership state.
+ * @param userId - The user ID to check.
+ * @param membership - The membership e.g. `'join'`
+ * @returns True if this user_id has the given membership state.
+ */
+ hasMembershipState(userId, membership) {
+ const member = this.getMember(userId);
+ if (!member) {
+ return false;
+ }
+ return member.membership === membership;
+ }
+
+ /**
+ * Add a timelineSet for this room with the given filter
+ * @param filter - The filter to be applied to this timelineSet
+ * @param opts - Configuration options
+ * @returns The timelineSet
+ */
+ getOrCreateFilteredTimelineSet(filter, {
+ prepopulateTimeline = true,
+ useSyncEvents = true,
+ pendingEvents = true
+ } = {}) {
+ if (this.filteredTimelineSets[filter.filterId]) {
+ return this.filteredTimelineSets[filter.filterId];
+ }
+ const opts = Object.assign({
+ filter,
+ pendingEvents
+ }, this.opts);
+ const timelineSet = new _eventTimelineSet.EventTimelineSet(this, opts);
+ this.reEmitter.reEmit(timelineSet, [RoomEvent.Timeline, RoomEvent.TimelineReset]);
+ if (useSyncEvents) {
+ this.filteredTimelineSets[filter.filterId] = timelineSet;
+ this.timelineSets.push(timelineSet);
+ }
+ const unfilteredLiveTimeline = this.getLiveTimeline();
+ // Not all filter are possible to replicate client-side only
+ // When that's the case we do not want to prepopulate from the live timeline
+ // as we would get incorrect results compared to what the server would send back
+ if (prepopulateTimeline) {
+ // populate up the new timelineSet with filtered events from our live
+ // unfiltered timeline.
+ //
+ // XXX: This is risky as our timeline
+ // may have grown huge and so take a long time to filter.
+ // see https://github.com/vector-im/vector-web/issues/2109
+
+ unfilteredLiveTimeline.getEvents().forEach(function (event) {
+ timelineSet.addLiveEvent(event);
+ });
+
+ // find the earliest unfiltered timeline
+ let timeline = unfilteredLiveTimeline;
+ while (timeline.getNeighbouringTimeline(_eventTimeline.EventTimeline.BACKWARDS)) {
+ timeline = timeline.getNeighbouringTimeline(_eventTimeline.EventTimeline.BACKWARDS);
+ }
+ timelineSet.getLiveTimeline().setPaginationToken(timeline.getPaginationToken(_eventTimeline.EventTimeline.BACKWARDS), _eventTimeline.EventTimeline.BACKWARDS);
+ } else if (useSyncEvents) {
+ const livePaginationToken = unfilteredLiveTimeline.getPaginationToken(_eventTimeline.Direction.Forward);
+ timelineSet.getLiveTimeline().setPaginationToken(livePaginationToken, _eventTimeline.Direction.Backward);
+ }
+
+ // alternatively, we could try to do something like this to try and re-paginate
+ // in the filtered events from nothing, but Mark says it's an abuse of the API
+ // to do so:
+ //
+ // timelineSet.resetLiveTimeline(
+ // unfilteredLiveTimeline.getPaginationToken(EventTimeline.FORWARDS)
+ // );
+
+ return timelineSet;
+ }
+ async getThreadListFilter(filterType = _thread.ThreadFilterType.All) {
+ const myUserId = this.client.getUserId();
+ const filter = new _filter.Filter(myUserId);
+ const definition = {
+ room: {
+ timeline: {
+ [_thread.FILTER_RELATED_BY_REL_TYPES.name]: [_thread.THREAD_RELATION_TYPE.name]
+ }
+ }
+ };
+ if (filterType === _thread.ThreadFilterType.My) {
+ definition.room.timeline[_thread.FILTER_RELATED_BY_SENDERS.name] = [myUserId];
+ }
+ filter.setDefinition(definition);
+ const filterId = await this.client.getOrCreateFilter(`THREAD_PANEL_${this.roomId}_${filterType}`, filter);
+ filter.filterId = filterId;
+ return filter;
+ }
+ async createThreadTimelineSet(filterType) {
+ let timelineSet;
+ if (_thread.Thread.hasServerSideListSupport) {
+ timelineSet = new _eventTimelineSet.EventTimelineSet(this, _objectSpread(_objectSpread({}, this.opts), {}, {
+ pendingEvents: false
+ }), undefined, undefined, filterType !== null && filterType !== void 0 ? filterType : _thread.ThreadFilterType.All);
+ this.reEmitter.reEmit(timelineSet, [RoomEvent.Timeline, RoomEvent.TimelineReset]);
+ } else if (_thread.Thread.hasServerSideSupport) {
+ const filter = await this.getThreadListFilter(filterType);
+ timelineSet = this.getOrCreateFilteredTimelineSet(filter, {
+ prepopulateTimeline: false,
+ useSyncEvents: false,
+ pendingEvents: false
+ });
+ } else {
+ timelineSet = new _eventTimelineSet.EventTimelineSet(this, {
+ pendingEvents: false
+ });
+ Array.from(this.threads).forEach(([, thread]) => {
+ if (thread.length === 0) return;
+ const currentUserParticipated = thread.timeline.some(event => {
+ return event.getSender() === this.client.getUserId();
+ });
+ if (filterType !== _thread.ThreadFilterType.My || currentUserParticipated) {
+ timelineSet.getLiveTimeline().addEvent(thread.rootEvent, {
+ toStartOfTimeline: false
+ });
+ }
+ });
+ }
+ return timelineSet;
+ }
+ /**
+ * Takes the given thread root events and creates threads for them.
+ */
+ processThreadRoots(events, toStartOfTimeline) {
+ for (const rootEvent of events) {
+ _eventTimeline.EventTimeline.setEventMetadata(rootEvent, this.currentState, toStartOfTimeline);
+ if (!this.getThread(rootEvent.getId())) {
+ this.createThread(rootEvent.getId(), rootEvent, [], toStartOfTimeline);
+ }
+ }
+ }
+
+ /**
+ * Fetch the bare minimum of room threads required for the thread list to work reliably.
+ * With server support that means fetching one page.
+ * Without server support that means fetching as much at once as the server allows us to.
+ */
+ async fetchRoomThreads() {
+ if (this.threadsReady || !this.client.supportsThreads()) {
+ return;
+ }
+ if (_thread.Thread.hasServerSideListSupport) {
+ await Promise.all([this.fetchRoomThreadList(_thread.ThreadFilterType.All), this.fetchRoomThreadList(_thread.ThreadFilterType.My)]);
+ } else {
+ const allThreadsFilter = await this.getThreadListFilter();
+ const {
+ chunk: events
+ } = await this.client.createMessagesRequest(this.roomId, "", Number.MAX_SAFE_INTEGER, _eventTimeline.Direction.Backward, allThreadsFilter);
+ if (!events.length) return;
+
+ // Sorted by last_reply origin_server_ts
+ const threadRoots = events.map(this.client.getEventMapper()).sort((eventA, eventB) => {
+ /**
+ * `origin_server_ts` in a decentralised world is far from ideal
+ * but for lack of any better, we will have to use this
+ * Long term the sorting should be handled by homeservers and this
+ * is only meant as a short term patch
+ */
+ const threadAMetadata = eventA.getServerAggregatedRelation(_thread.THREAD_RELATION_TYPE.name);
+ const threadBMetadata = eventB.getServerAggregatedRelation(_thread.THREAD_RELATION_TYPE.name);
+ return threadAMetadata.latest_event.origin_server_ts - threadBMetadata.latest_event.origin_server_ts;
+ });
+ let latestMyThreadsRootEvent;
+ const roomState = this.getLiveTimeline().getState(_eventTimeline.EventTimeline.FORWARDS);
+ for (const rootEvent of threadRoots) {
+ var _this$threadsTimeline3;
+ const opts = {
+ duplicateStrategy: _eventTimelineSet.DuplicateStrategy.Ignore,
+ fromCache: false,
+ roomState
+ };
+ (_this$threadsTimeline3 = this.threadsTimelineSets[0]) === null || _this$threadsTimeline3 === void 0 ? void 0 : _this$threadsTimeline3.addLiveEvent(rootEvent, opts);
+ const threadRelationship = rootEvent.getServerAggregatedRelation(_thread.THREAD_RELATION_TYPE.name);
+ if (threadRelationship !== null && threadRelationship !== void 0 && threadRelationship.current_user_participated) {
+ var _this$threadsTimeline4;
+ (_this$threadsTimeline4 = this.threadsTimelineSets[1]) === null || _this$threadsTimeline4 === void 0 ? void 0 : _this$threadsTimeline4.addLiveEvent(rootEvent, opts);
+ latestMyThreadsRootEvent = rootEvent;
+ }
+ }
+ this.processThreadRoots(threadRoots, true);
+ this.client.decryptEventIfNeeded(threadRoots[threadRoots.length - 1]);
+ if (latestMyThreadsRootEvent) {
+ this.client.decryptEventIfNeeded(latestMyThreadsRootEvent);
+ }
+ }
+ this.on(_thread.ThreadEvent.NewReply, this.onThreadNewReply);
+ this.on(_thread.ThreadEvent.Delete, this.onThreadDelete);
+ this.threadsReady = true;
+ }
+ async processPollEvents(events) {
+ const processPollStartEvent = event => {
+ if (!_matrixEventsSdk.M_POLL_START.matches(event.getType())) return;
+ try {
+ const poll = new _poll.Poll(event, this.client, this);
+ this.polls.set(event.getId(), poll);
+ this.emit(_poll.PollEvent.New, poll);
+ } catch {}
+ // poll creation can fail for malformed poll start events
+ };
+
+ const processPollRelationEvent = event => {
+ const relationEventId = event.relationEventId;
+ if (relationEventId && this.polls.has(relationEventId)) {
+ const poll = this.polls.get(relationEventId);
+ poll === null || poll === void 0 ? void 0 : poll.onNewRelation(event);
+ }
+ };
+ const processPollEvent = event => {
+ processPollStartEvent(event);
+ processPollRelationEvent(event);
+ };
+ for (const event of events) {
+ try {
+ await this.client.decryptEventIfNeeded(event);
+ processPollEvent(event);
+ } catch {}
+ }
+ }
+
+ /**
+ * Fetch a single page of threadlist messages for the specific thread filter
+ * @internal
+ */
+ async fetchRoomThreadList(filter) {
+ const timelineSet = filter === _thread.ThreadFilterType.My ? this.threadsTimelineSets[1] : this.threadsTimelineSets[0];
+ const {
+ chunk: events,
+ end
+ } = await this.client.createThreadListMessagesRequest(this.roomId, null, undefined, _eventTimeline.Direction.Backward, timelineSet.threadListType, timelineSet.getFilter());
+ timelineSet.getLiveTimeline().setPaginationToken(end !== null && end !== void 0 ? end : null, _eventTimeline.Direction.Backward);
+ if (!events.length) return;
+ const matrixEvents = events.map(this.client.getEventMapper());
+ this.processThreadRoots(matrixEvents, true);
+ const roomState = this.getLiveTimeline().getState(_eventTimeline.EventTimeline.FORWARDS);
+ for (const rootEvent of matrixEvents) {
+ timelineSet.addLiveEvent(rootEvent, {
+ duplicateStrategy: _eventTimelineSet.DuplicateStrategy.Replace,
+ fromCache: false,
+ roomState
+ });
+ }
+ }
+ onThreadNewReply(thread) {
+ this.updateThreadRootEvents(thread, false, true);
+ }
+ onThreadDelete(thread) {
+ var _timeline$getEvents;
+ this.threads.delete(thread.id);
+ const timeline = this.getTimelineForEvent(thread.id);
+ const roomEvent = timeline === null || timeline === void 0 ? void 0 : (_timeline$getEvents = timeline.getEvents()) === null || _timeline$getEvents === void 0 ? void 0 : _timeline$getEvents.find(it => it.getId() === thread.id);
+ if (roomEvent) {
+ thread.clearEventMetadata(roomEvent);
+ } else {
+ _logger.logger.debug("onThreadDelete: Could not find root event in room timeline");
+ }
+ for (const timelineSet of this.threadsTimelineSets) {
+ timelineSet.removeEvent(thread.id);
+ }
+ }
+
+ /**
+ * Forget the timelineSet for this room with the given filter
+ *
+ * @param filter - the filter whose timelineSet is to be forgotten
+ */
+ removeFilteredTimelineSet(filter) {
+ const timelineSet = this.filteredTimelineSets[filter.filterId];
+ delete this.filteredTimelineSets[filter.filterId];
+ const i = this.timelineSets.indexOf(timelineSet);
+ if (i > -1) {
+ this.timelineSets.splice(i, 1);
+ }
+ }
+ eventShouldLiveIn(event, events, roots) {
+ var _this$client2;
+ if (!((_this$client2 = this.client) !== null && _this$client2 !== void 0 && _this$client2.supportsThreads())) {
+ return {
+ shouldLiveInRoom: true,
+ shouldLiveInThread: false
+ };
+ }
+
+ // A thread root is always shown in both timelines
+ if (event.isThreadRoot || roots !== null && roots !== void 0 && roots.has(event.getId())) {
+ return {
+ shouldLiveInRoom: true,
+ shouldLiveInThread: true,
+ threadId: event.getId()
+ };
+ }
+
+ // A thread relation is always only shown in a thread
+ if (event.isRelation(_thread.THREAD_RELATION_TYPE.name)) {
+ return {
+ shouldLiveInRoom: false,
+ shouldLiveInThread: true,
+ threadId: event.threadRootId
+ };
+ }
+ const parentEventId = event.getAssociatedId();
+ let parentEvent;
+ if (parentEventId) {
+ var _this$findEventById;
+ parentEvent = (_this$findEventById = this.findEventById(parentEventId)) !== null && _this$findEventById !== void 0 ? _this$findEventById : events === null || events === void 0 ? void 0 : events.find(e => e.getId() === parentEventId);
+ }
+
+ // Treat relations and redactions as extensions of their parents so evaluate parentEvent instead
+ if (parentEvent && (event.isRelation() || event.isRedaction())) {
+ return this.eventShouldLiveIn(parentEvent, events, roots);
+ }
+
+ // Edge case where we know the event is a relation but don't have the parentEvent
+ if (roots !== null && roots !== void 0 && roots.has(event.relationEventId)) {
+ return {
+ shouldLiveInRoom: true,
+ shouldLiveInThread: true,
+ threadId: event.relationEventId
+ };
+ }
+
+ // We've exhausted all scenarios, can safely assume that this event should live in the room timeline only
+ return {
+ shouldLiveInRoom: true,
+ shouldLiveInThread: false
+ };
+ }
+ findThreadForEvent(event) {
+ if (!event) return null;
+ const {
+ threadId
+ } = this.eventShouldLiveIn(event);
+ return threadId ? this.getThread(threadId) : null;
+ }
+ addThreadedEvents(threadId, events, toStartOfTimeline = false) {
+ let thread = this.getThread(threadId);
+ if (!thread) {
+ var _this$findEventById2;
+ const rootEvent = (_this$findEventById2 = this.findEventById(threadId)) !== null && _this$findEventById2 !== void 0 ? _this$findEventById2 : events.find(e => e.getId() === threadId);
+ thread = this.createThread(threadId, rootEvent, events, toStartOfTimeline);
+ }
+ thread.addEvents(events, toStartOfTimeline);
+ }
+
+ /**
+ * Adds events to a thread's timeline. Will fire "Thread.update"
+ */
+ processThreadedEvents(events, toStartOfTimeline) {
+ events.forEach(this.applyRedaction);
+ const eventsByThread = {};
+ for (const event of events) {
+ var _eventsByThread;
+ const {
+ threadId,
+ shouldLiveInThread
+ } = this.eventShouldLiveIn(event);
+ if (shouldLiveInThread && !eventsByThread[threadId]) {
+ eventsByThread[threadId] = [];
+ }
+ (_eventsByThread = eventsByThread[threadId]) === null || _eventsByThread === void 0 ? void 0 : _eventsByThread.push(event);
+ }
+ Object.entries(eventsByThread).map(([threadId, threadEvents]) => this.addThreadedEvents(threadId, threadEvents, toStartOfTimeline));
+ }
+ createThread(threadId, rootEvent, events = [], toStartOfTimeline) {
+ var _this$cachedThreadRea, _this$lastThread, _this$lastThread$root;
+ if (this.threads.has(threadId)) {
+ return this.threads.get(threadId);
+ }
+ if (rootEvent) {
+ const relatedEvents = this.relations.getAllChildEventsForEvent(rootEvent.getId());
+ if (relatedEvents !== null && relatedEvents !== void 0 && relatedEvents.length) {
+ // Include all relations of the root event, given it'll be visible in both timelines,
+ // except `m.replace` as that will already be applied atop the event using `MatrixEvent::makeReplaced`
+ events = events.concat(relatedEvents.filter(e => !e.isRelation(_event2.RelationType.Replace)));
+ }
+ }
+ const thread = new _thread.Thread(threadId, rootEvent, {
+ room: this,
+ client: this.client,
+ pendingEventOrdering: this.opts.pendingEventOrdering,
+ receipts: (_this$cachedThreadRea = this.cachedThreadReadReceipts.get(threadId)) !== null && _this$cachedThreadRea !== void 0 ? _this$cachedThreadRea : []
+ });
+
+ // All read receipts should now come down from sync, we do not need to keep
+ // a reference to the cached receipts anymore.
+ this.cachedThreadReadReceipts.delete(threadId);
+
+ // If we managed to create a thread and figure out its `id` then we can use it
+ // This has to happen before thread.addEvents, because that adds events to the eventtimeline, and the
+ // eventtimeline sometimes looks up thread information via the room.
+ this.threads.set(thread.id, thread);
+
+ // This is necessary to be able to jump to events in threads:
+ // If we jump to an event in a thread where neither the event, nor the root,
+ // nor any thread event are loaded yet, we'll load the event as well as the thread root, create the thread,
+ // and pass the event through this.
+ thread.addEvents(events, false);
+ this.reEmitter.reEmit(thread, [_thread.ThreadEvent.Delete, _thread.ThreadEvent.Update, _thread.ThreadEvent.NewReply, RoomEvent.Timeline, RoomEvent.TimelineReset]);
+ const isNewer = ((_this$lastThread = this.lastThread) === null || _this$lastThread === void 0 ? void 0 : _this$lastThread.rootEvent) && (rootEvent === null || rootEvent === void 0 ? void 0 : rootEvent.localTimestamp) && ((_this$lastThread$root = this.lastThread.rootEvent) === null || _this$lastThread$root === void 0 ? void 0 : _this$lastThread$root.localTimestamp) < (rootEvent === null || rootEvent === void 0 ? void 0 : rootEvent.localTimestamp);
+ if (!this.lastThread || isNewer) {
+ this.lastThread = thread;
+ }
+ if (this.threadsReady) {
+ this.updateThreadRootEvents(thread, toStartOfTimeline, false);
+ }
+ this.emit(_thread.ThreadEvent.New, thread, toStartOfTimeline);
+ return thread;
+ }
+ processLiveEvent(event) {
+ this.applyRedaction(event);
+
+ // Implement MSC3531: hiding messages.
+ if (event.isVisibilityEvent()) {
+ // This event changes the visibility of another event, record
+ // the visibility change, inform clients if necessary.
+ this.applyNewVisibilityEvent(event);
+ }
+ // If any pending visibility change is waiting for this (older) event,
+ this.applyPendingVisibilityEvents(event);
+
+ // Sliding Sync modifications:
+ // The proxy cannot guarantee every sent event will have a transaction_id field, so we need
+ // to check the event ID against the list of pending events if there is no transaction ID
+ // field. Only do this for events sent by us though as it's potentially expensive to loop
+ // the pending events map.
+ const txnId = event.getUnsigned().transaction_id;
+ if (!txnId && event.getSender() === this.myUserId) {
+ // check the txn map for a matching event ID
+ for (const [tid, localEvent] of this.txnToEvent) {
+ if (localEvent.getId() === event.getId()) {
+ _logger.logger.debug("processLiveEvent: found sent event without txn ID: ", tid, event.getId());
+ // update the unsigned field so we can re-use the same codepaths
+ const unsigned = event.getUnsigned();
+ unsigned.transaction_id = tid;
+ event.setUnsigned(unsigned);
+ break;
+ }
+ }
+ }
+ }
+
+ /**
+ * Add an event to the end of this room's live timelines. Will fire
+ * "Room.timeline".
+ *
+ * @param event - Event to be added
+ * @param addLiveEventOptions - addLiveEvent options
+ * @internal
+ *
+ * @remarks
+ * Fires {@link RoomEvent.Timeline}
+ */
+ addLiveEvent(event, addLiveEventOptions) {
+ const {
+ duplicateStrategy,
+ timelineWasEmpty,
+ fromCache
+ } = addLiveEventOptions;
+
+ // add to our timeline sets
+ for (const timelineSet of this.timelineSets) {
+ timelineSet.addLiveEvent(event, {
+ duplicateStrategy,
+ fromCache,
+ timelineWasEmpty
+ });
+ }
+
+ // synthesize and inject implicit read receipts
+ // Done after adding the event because otherwise the app would get a read receipt
+ // pointing to an event that wasn't yet in the timeline
+ // Don't synthesize RR for m.room.redaction as this causes the RR to go missing.
+ if (event.sender && event.getType() !== _event2.EventType.RoomRedaction) {
+ this.addReceipt((0, _readReceipt.synthesizeReceipt)(event.sender.userId, event, _read_receipts.ReceiptType.Read), true);
+
+ // Any live events from a user could be taken as implicit
+ // presence information: evidence that they are currently active.
+ // ...except in a world where we use 'user.currentlyActive' to reduce
+ // presence spam, this isn't very useful - we'll get a transition when
+ // they are no longer currently active anyway. So don't bother to
+ // reset the lastActiveAgo and lastPresenceTs from the RoomState's user.
+ }
+ }
+
+ /**
+ * Add a pending outgoing event to this room.
+ *
+ * <p>The event is added to either the pendingEventList, or the live timeline,
+ * depending on the setting of opts.pendingEventOrdering.
+ *
+ * <p>This is an internal method, intended for use by MatrixClient.
+ *
+ * @param event - The event to add.
+ *
+ * @param txnId - Transaction id for this outgoing event
+ *
+ * @throws if the event doesn't have status SENDING, or we aren't given a
+ * unique transaction id.
+ *
+ * @remarks
+ * Fires {@link RoomEvent.LocalEchoUpdated}
+ */
+ addPendingEvent(event, txnId) {
+ if (event.status !== _eventStatus.EventStatus.SENDING && event.status !== _eventStatus.EventStatus.NOT_SENT) {
+ throw new Error("addPendingEvent called on an event with status " + event.status);
+ }
+ if (this.txnToEvent.get(txnId)) {
+ throw new Error("addPendingEvent called on an event with known txnId " + txnId);
+ }
+
+ // call setEventMetadata to set up event.sender etc
+ // as event is shared over all timelineSets, we set up its metadata based
+ // on the unfiltered timelineSet.
+ _eventTimeline.EventTimeline.setEventMetadata(event, this.getLiveTimeline().getState(_eventTimeline.EventTimeline.FORWARDS), false);
+ this.txnToEvent.set(txnId, event);
+ if (this.pendingEventList) {
+ if (this.pendingEventList.some(e => e.status === _eventStatus.EventStatus.NOT_SENT)) {
+ _logger.logger.warn("Setting event as NOT_SENT due to messages in the same state");
+ event.setStatus(_eventStatus.EventStatus.NOT_SENT);
+ }
+ this.pendingEventList.push(event);
+ this.savePendingEvents();
+ if (event.isRelation()) {
+ // For pending events, add them to the relations collection immediately.
+ // (The alternate case below already covers this as part of adding to
+ // the timeline set.)
+ this.aggregateNonLiveRelation(event);
+ }
+ if (event.isRedaction()) {
+ const redactId = event.event.redacts;
+ let redactedEvent = this.pendingEventList.find(e => e.getId() === redactId);
+ if (!redactedEvent && redactId) {
+ redactedEvent = this.findEventById(redactId);
+ }
+ if (redactedEvent) {
+ redactedEvent.markLocallyRedacted(event);
+ this.emit(RoomEvent.Redaction, event, this);
+ }
+ }
+ } else {
+ for (const timelineSet of this.timelineSets) {
+ if (timelineSet.getFilter()) {
+ if (timelineSet.getFilter().filterRoomTimeline([event]).length) {
+ timelineSet.addEventToTimeline(event, timelineSet.getLiveTimeline(), {
+ toStartOfTimeline: false
+ });
+ }
+ } else {
+ timelineSet.addEventToTimeline(event, timelineSet.getLiveTimeline(), {
+ toStartOfTimeline: false
+ });
+ }
+ }
+ }
+ this.emit(RoomEvent.LocalEchoUpdated, event, this);
+ }
+
+ /**
+ * Persists all pending events to local storage
+ *
+ * If the current room is encrypted only encrypted events will be persisted
+ * all messages that are not yet encrypted will be discarded
+ *
+ * This is because the flow of EVENT_STATUS transition is
+ * `queued => sending => encrypting => sending => sent`
+ *
+ * Steps 3 and 4 are skipped for unencrypted room.
+ * It is better to discard an unencrypted message rather than persisting
+ * it locally for everyone to read
+ */
+ savePendingEvents() {
+ if (this.pendingEventList) {
+ const pendingEvents = this.pendingEventList.map(event => {
+ return _objectSpread(_objectSpread({}, event.event), {}, {
+ txn_id: event.getTxnId()
+ });
+ }).filter(event => {
+ // Filter out the unencrypted messages if the room is encrypted
+ const isEventEncrypted = event.type === _event2.EventType.RoomMessageEncrypted;
+ const isRoomEncrypted = this.client.isRoomEncrypted(this.roomId);
+ return isEventEncrypted || !isRoomEncrypted;
+ });
+ this.client.store.setPendingEvents(this.roomId, pendingEvents);
+ }
+ }
+
+ /**
+ * Used to aggregate the local echo for a relation, and also
+ * for re-applying a relation after it's redaction has been cancelled,
+ * as the local echo for the redaction of the relation would have
+ * un-aggregated the relation. Note that this is different from regular messages,
+ * which are just kept detached for their local echo.
+ *
+ * Also note that live events are aggregated in the live EventTimelineSet.
+ * @param event - the relation event that needs to be aggregated.
+ */
+ aggregateNonLiveRelation(event) {
+ this.relations.aggregateChildEvent(event);
+ }
+ getEventForTxnId(txnId) {
+ return this.txnToEvent.get(txnId);
+ }
+
+ /**
+ * Deal with the echo of a message we sent.
+ *
+ * <p>We move the event to the live timeline if it isn't there already, and
+ * update it.
+ *
+ * @param remoteEvent - The event received from
+ * /sync
+ * @param localEvent - The local echo, which
+ * should be either in the pendingEventList or the timeline.
+ *
+ * @internal
+ *
+ * @remarks
+ * Fires {@link RoomEvent.LocalEchoUpdated}
+ */
+ handleRemoteEcho(remoteEvent, localEvent) {
+ const oldEventId = localEvent.getId();
+ const newEventId = remoteEvent.getId();
+ const oldStatus = localEvent.status;
+ _logger.logger.debug(`Got remote echo for event ${oldEventId} -> ${newEventId} old status ${oldStatus}`);
+
+ // no longer pending
+ this.txnToEvent.delete(remoteEvent.getUnsigned().transaction_id);
+
+ // if it's in the pending list, remove it
+ if (this.pendingEventList) {
+ this.removePendingEvent(oldEventId);
+ }
+
+ // replace the event source (this will preserve the plaintext payload if
+ // any, which is good, because we don't want to try decoding it again).
+ localEvent.handleRemoteEcho(remoteEvent.event);
+ const {
+ shouldLiveInRoom,
+ threadId
+ } = this.eventShouldLiveIn(remoteEvent);
+ const thread = threadId ? this.getThread(threadId) : null;
+ thread === null || thread === void 0 ? void 0 : thread.setEventMetadata(localEvent);
+ thread === null || thread === void 0 ? void 0 : thread.timelineSet.handleRemoteEcho(localEvent, oldEventId, newEventId);
+ if (shouldLiveInRoom) {
+ for (const timelineSet of this.timelineSets) {
+ // if it's already in the timeline, update the timeline map. If it's not, add it.
+ timelineSet.handleRemoteEcho(localEvent, oldEventId, newEventId);
+ }
+ }
+ this.emit(RoomEvent.LocalEchoUpdated, localEvent, this, oldEventId, oldStatus);
+ }
+
+ /**
+ * Update the status / event id on a pending event, to reflect its transmission
+ * progress.
+ *
+ * <p>This is an internal method.
+ *
+ * @param event - local echo event
+ * @param newStatus - status to assign
+ * @param newEventId - new event id to assign. Ignored unless newStatus == EventStatus.SENT.
+ *
+ * @remarks
+ * Fires {@link RoomEvent.LocalEchoUpdated}
+ */
+ updatePendingEvent(event, newStatus, newEventId) {
+ _logger.logger.log(`setting pendingEvent status to ${newStatus} in ${event.getRoomId()} ` + `event ID ${event.getId()} -> ${newEventId}`);
+
+ // if the message was sent, we expect an event id
+ if (newStatus == _eventStatus.EventStatus.SENT && !newEventId) {
+ throw new Error("updatePendingEvent called with status=SENT, but no new event id");
+ }
+
+ // SENT races against /sync, so we have to special-case it.
+ if (newStatus == _eventStatus.EventStatus.SENT) {
+ const timeline = this.getTimelineForEvent(newEventId);
+ if (timeline) {
+ // we've already received the event via the event stream.
+ // nothing more to do here, assuming the transaction ID was correctly matched.
+ // Let's check that.
+ const remoteEvent = this.findEventById(newEventId);
+ const remoteTxnId = remoteEvent === null || remoteEvent === void 0 ? void 0 : remoteEvent.getUnsigned().transaction_id;
+ if (!remoteTxnId && remoteEvent) {
+ // This code path is mostly relevant for the Sliding Sync proxy.
+ // The remote event did not contain a transaction ID, so we did not handle
+ // the remote echo yet. Handle it now.
+ const unsigned = remoteEvent.getUnsigned();
+ unsigned.transaction_id = event.getTxnId();
+ remoteEvent.setUnsigned(unsigned);
+ // the remote event is _already_ in the timeline, so we need to remove it so
+ // we can convert the local event into the final event.
+ this.removeEvent(remoteEvent.getId());
+ this.handleRemoteEcho(remoteEvent, event);
+ }
+ return;
+ }
+ }
+ const oldStatus = event.status;
+ const oldEventId = event.getId();
+ if (!oldStatus) {
+ throw new Error("updatePendingEventStatus called on an event which is not a local echo.");
+ }
+ const allowed = ALLOWED_TRANSITIONS[oldStatus];
+ if (!(allowed !== null && allowed !== void 0 && allowed.includes(newStatus))) {
+ throw new Error(`Invalid EventStatus transition ${oldStatus}->${newStatus}`);
+ }
+ event.setStatus(newStatus);
+ if (newStatus == _eventStatus.EventStatus.SENT) {
+ // update the event id
+ event.replaceLocalEventId(newEventId);
+ const {
+ shouldLiveInRoom,
+ threadId
+ } = this.eventShouldLiveIn(event);
+ const thread = threadId ? this.getThread(threadId) : undefined;
+ thread === null || thread === void 0 ? void 0 : thread.setEventMetadata(event);
+ thread === null || thread === void 0 ? void 0 : thread.timelineSet.replaceEventId(oldEventId, newEventId);
+ if (shouldLiveInRoom) {
+ // if the event was already in the timeline (which will be the case if
+ // opts.pendingEventOrdering==chronological), we need to update the
+ // timeline map.
+ for (const timelineSet of this.timelineSets) {
+ timelineSet.replaceEventId(oldEventId, newEventId);
+ }
+ }
+ } else if (newStatus == _eventStatus.EventStatus.CANCELLED) {
+ // remove it from the pending event list, or the timeline.
+ if (this.pendingEventList) {
+ const removedEvent = this.getPendingEvent(oldEventId);
+ this.removePendingEvent(oldEventId);
+ if (removedEvent !== null && removedEvent !== void 0 && removedEvent.isRedaction()) {
+ this.revertRedactionLocalEcho(removedEvent);
+ }
+ }
+ this.removeEvent(oldEventId);
+ }
+ this.savePendingEvents();
+ this.emit(RoomEvent.LocalEchoUpdated, event, this, oldEventId, oldStatus);
+ }
+ revertRedactionLocalEcho(redactionEvent) {
+ const redactId = redactionEvent.event.redacts;
+ if (!redactId) {
+ return;
+ }
+ const redactedEvent = this.getUnfilteredTimelineSet().findEventById(redactId);
+ if (redactedEvent) {
+ redactedEvent.unmarkLocallyRedacted();
+ // re-render after undoing redaction
+ this.emit(RoomEvent.RedactionCancelled, redactionEvent, this);
+ // reapply relation now redaction failed
+ if (redactedEvent.isRelation()) {
+ this.aggregateNonLiveRelation(redactedEvent);
+ }
+ }
+ }
+
+ /**
+ * Add some events to this room. This can include state events, message
+ * events and typing notifications. These events are treated as "live" so
+ * they will go to the end of the timeline.
+ *
+ * @param events - A list of events to add.
+ * @param addLiveEventOptions - addLiveEvent options
+ * @throws If `duplicateStrategy` is not falsey, 'replace' or 'ignore'.
+ */
+
+ addLiveEvents(events, duplicateStrategyOrOpts, fromCache = false) {
+ let duplicateStrategy = duplicateStrategyOrOpts;
+ let timelineWasEmpty = false;
+ if (typeof duplicateStrategyOrOpts === "object") {
+ ({
+ duplicateStrategy,
+ fromCache = false,
+ /* roomState, (not used here) */
+ timelineWasEmpty
+ } = duplicateStrategyOrOpts);
+ } else if (duplicateStrategyOrOpts !== undefined) {
+ // Deprecation warning
+ // FIXME: Remove after 2023-06-01 (technical debt)
+ _logger.logger.warn("Overload deprecated: " + "`Room.addLiveEvents(events, duplicateStrategy?, fromCache?)` " + "is deprecated in favor of the overload with `Room.addLiveEvents(events, IAddLiveEventOptions)`");
+ }
+ if (duplicateStrategy && ["replace", "ignore"].indexOf(duplicateStrategy) === -1) {
+ throw new Error("duplicateStrategy MUST be either 'replace' or 'ignore'");
+ }
+
+ // sanity check that the live timeline is still live
+ for (let i = 0; i < this.timelineSets.length; i++) {
+ const liveTimeline = this.timelineSets[i].getLiveTimeline();
+ if (liveTimeline.getPaginationToken(_eventTimeline.EventTimeline.FORWARDS)) {
+ throw new Error("live timeline " + i + " is no longer live - it has a pagination token " + "(" + liveTimeline.getPaginationToken(_eventTimeline.EventTimeline.FORWARDS) + ")");
+ }
+ if (liveTimeline.getNeighbouringTimeline(_eventTimeline.EventTimeline.FORWARDS)) {
+ throw new Error(`live timeline ${i} is no longer live - it has a neighbouring timeline`);
+ }
+ }
+ const threadRoots = this.findThreadRoots(events);
+ const eventsByThread = {};
+ const options = {
+ duplicateStrategy,
+ fromCache,
+ timelineWasEmpty
+ };
+ for (const event of events) {
+ var _eventsByThread2;
+ // TODO: We should have a filter to say "only add state event types X Y Z to the timeline".
+ this.processLiveEvent(event);
+ if (event.getUnsigned().transaction_id) {
+ const existingEvent = this.txnToEvent.get(event.getUnsigned().transaction_id);
+ if (existingEvent) {
+ // remote echo of an event we sent earlier
+ this.handleRemoteEcho(event, existingEvent);
+ continue; // we can skip adding the event to the timeline sets, it is already there
+ }
+ }
+
+ const {
+ shouldLiveInRoom,
+ shouldLiveInThread,
+ threadId
+ } = this.eventShouldLiveIn(event, events, threadRoots);
+ if (shouldLiveInThread && !eventsByThread[threadId !== null && threadId !== void 0 ? threadId : ""]) {
+ eventsByThread[threadId !== null && threadId !== void 0 ? threadId : ""] = [];
+ }
+ (_eventsByThread2 = eventsByThread[threadId !== null && threadId !== void 0 ? threadId : ""]) === null || _eventsByThread2 === void 0 ? void 0 : _eventsByThread2.push(event);
+ if (shouldLiveInRoom) {
+ this.addLiveEvent(event, options);
+ }
+ }
+ Object.entries(eventsByThread).forEach(([threadId, threadEvents]) => {
+ this.addThreadedEvents(threadId, threadEvents, false);
+ });
+ }
+ partitionThreadedEvents(events) {
+ // Indices to the events array, for readability
+ const ROOM = 0;
+ const THREAD = 1;
+ if (this.client.supportsThreads()) {
+ const threadRoots = this.findThreadRoots(events);
+ return events.reduce((memo, event) => {
+ const {
+ shouldLiveInRoom,
+ shouldLiveInThread,
+ threadId
+ } = this.eventShouldLiveIn(event, events, threadRoots);
+ if (shouldLiveInRoom) {
+ memo[ROOM].push(event);
+ }
+ if (shouldLiveInThread) {
+ event.setThreadId(threadId !== null && threadId !== void 0 ? threadId : "");
+ memo[THREAD].push(event);
+ }
+ return memo;
+ }, [[], []]);
+ } else {
+ // When `experimentalThreadSupport` is disabled treat all events as timelineEvents
+ return [events, []];
+ }
+ }
+
+ /**
+ * Given some events, find the IDs of all the thread roots that are referred to by them.
+ */
+ findThreadRoots(events) {
+ const threadRoots = new Set();
+ for (const event of events) {
+ if (event.isRelation(_thread.THREAD_RELATION_TYPE.name)) {
+ var _event$relationEventI;
+ threadRoots.add((_event$relationEventI = event.relationEventId) !== null && _event$relationEventI !== void 0 ? _event$relationEventI : "");
+ }
+ }
+ return threadRoots;
+ }
+
+ /**
+ * Add a receipt event to the room.
+ * @param event - The m.receipt event.
+ * @param synthetic - True if this event is implicit.
+ */
+ addReceipt(event, synthetic = false) {
+ const content = event.getContent();
+ Object.keys(content).forEach(eventId => {
+ Object.keys(content[eventId]).forEach(receiptType => {
+ Object.keys(content[eventId][receiptType]).forEach(userId => {
+ var _receipt$thread_id, _this$unthreadedRecei, _this$unthreadedRecei2;
+ const receipt = content[eventId][receiptType][userId];
+ const receiptForMainTimeline = !receipt.thread_id || receipt.thread_id === _read_receipts.MAIN_ROOM_TIMELINE;
+ const receiptDestination = receiptForMainTimeline ? this : this.threads.get((_receipt$thread_id = receipt.thread_id) !== null && _receipt$thread_id !== void 0 ? _receipt$thread_id : "");
+ if (receiptDestination) {
+ receiptDestination.addReceiptToStructure(eventId, receiptType, userId, receipt, synthetic);
+
+ // If the read receipt sent for the logged in user matches
+ // the last event of the live timeline, then we know for a fact
+ // that the user has read that message.
+ // We can mark the room as read and not wait for the local echo
+ // from synapse
+ // This needs to be done after the initial sync as we do not want this
+ // logic to run whilst the room is being initialised
+ if (this.client.isInitialSyncComplete() && userId === this.client.getUserId()) {
+ const lastEvent = receiptDestination.timeline[receiptDestination.timeline.length - 1];
+ if (lastEvent && eventId === lastEvent.getId() && userId === lastEvent.getSender()) {
+ receiptDestination.setUnread(NotificationCountType.Total, 0);
+ receiptDestination.setUnread(NotificationCountType.Highlight, 0);
+ }
+ }
+ } else {
+ var _this$cachedThreadRea2;
+ // The thread does not exist locally, keep the read receipt
+ // in a cache locally, and re-apply the `addReceipt` logic
+ // when the thread is created
+ this.cachedThreadReadReceipts.set(receipt.thread_id, [...((_this$cachedThreadRea2 = this.cachedThreadReadReceipts.get(receipt.thread_id)) !== null && _this$cachedThreadRea2 !== void 0 ? _this$cachedThreadRea2 : []), {
+ eventId,
+ receiptType,
+ userId,
+ receipt,
+ synthetic
+ }]);
+ }
+ const me = this.client.getUserId();
+ // Track the time of the current user's oldest threaded receipt in the room.
+ if (userId === me && !receiptForMainTimeline && receipt.ts < this.oldestThreadedReceiptTs) {
+ this.oldestThreadedReceiptTs = receipt.ts;
+ }
+
+ // Track each user's unthreaded read receipt.
+ if (!receipt.thread_id && receipt.ts > ((_this$unthreadedRecei = (_this$unthreadedRecei2 = this.unthreadedReceipts.get(userId)) === null || _this$unthreadedRecei2 === void 0 ? void 0 : _this$unthreadedRecei2.ts) !== null && _this$unthreadedRecei !== void 0 ? _this$unthreadedRecei : 0)) {
+ this.unthreadedReceipts.set(userId, receipt);
+ }
+ });
+ });
+ });
+
+ // send events after we've regenerated the structure & cache, otherwise things that
+ // listened for the event would read stale data.
+ this.emit(RoomEvent.Receipt, event, this);
+ }
+
+ /**
+ * Adds/handles ephemeral events such as typing notifications and read receipts.
+ * @param events - A list of events to process
+ */
+ addEphemeralEvents(events) {
+ for (const event of events) {
+ if (event.getType() === _event2.EventType.Typing) {
+ this.currentState.setTypingEvent(event);
+ } else if (event.getType() === _event2.EventType.Receipt) {
+ this.addReceipt(event);
+ } // else ignore - life is too short for us to care about these events
+ }
+ }
+
+ /**
+ * Removes events from this room.
+ * @param eventIds - A list of eventIds to remove.
+ */
+ removeEvents(eventIds) {
+ for (const eventId of eventIds) {
+ this.removeEvent(eventId);
+ }
+ }
+
+ /**
+ * Removes a single event from this room.
+ *
+ * @param eventId - The id of the event to remove
+ *
+ * @returns true if the event was removed from any of the room's timeline sets
+ */
+ removeEvent(eventId) {
+ let removedAny = false;
+ for (const timelineSet of this.timelineSets) {
+ const removed = timelineSet.removeEvent(eventId);
+ if (removed) {
+ if (removed.isRedaction()) {
+ this.revertRedactionLocalEcho(removed);
+ }
+ removedAny = true;
+ }
+ }
+ return removedAny;
+ }
+
+ /**
+ * Recalculate various aspects of the room, including the room name and
+ * room summary. Call this any time the room's current state is modified.
+ * May fire "Room.name" if the room name is updated.
+ *
+ * @remarks
+ * Fires {@link RoomEvent.Name}
+ */
+ recalculate() {
+ // set fake stripped state events if this is an invite room so logic remains
+ // consistent elsewhere.
+ const membershipEvent = this.currentState.getStateEvents(_event2.EventType.RoomMember, this.myUserId);
+ if (membershipEvent) {
+ const membership = membershipEvent.getContent().membership;
+ this.updateMyMembership(membership);
+ if (membership === "invite") {
+ const strippedStateEvents = membershipEvent.getUnsigned().invite_room_state || [];
+ strippedStateEvents.forEach(strippedEvent => {
+ const existingEvent = this.currentState.getStateEvents(strippedEvent.type, strippedEvent.state_key);
+ if (!existingEvent) {
+ // set the fake stripped event instead
+ this.currentState.setStateEvents([new _event.MatrixEvent({
+ type: strippedEvent.type,
+ state_key: strippedEvent.state_key,
+ content: strippedEvent.content,
+ event_id: "$fake" + Date.now(),
+ room_id: this.roomId,
+ user_id: this.myUserId // technically a lie
+ })]);
+ }
+ });
+ }
+ }
+
+ const oldName = this.name;
+ this.name = this.calculateRoomName(this.myUserId);
+ this.normalizedName = (0, utils.normalize)(this.name);
+ this.summary = new _roomSummary.RoomSummary(this.roomId, {
+ title: this.name
+ });
+ if (oldName !== this.name) {
+ this.emit(RoomEvent.Name, this);
+ }
+ }
+
+ /**
+ * Update the room-tag event for the room. The previous one is overwritten.
+ * @param event - the m.tag event
+ */
+ addTags(event) {
+ // event content looks like:
+ // content: {
+ // tags: {
+ // $tagName: { $metadata: $value },
+ // $tagName: { $metadata: $value },
+ // }
+ // }
+
+ // XXX: do we need to deep copy here?
+ this.tags = event.getContent().tags || {};
+
+ // XXX: we could do a deep-comparison to see if the tags have really
+ // changed - but do we want to bother?
+ this.emit(RoomEvent.Tags, event, this);
+ }
+
+ /**
+ * Update the account_data events for this room, overwriting events of the same type.
+ * @param events - an array of account_data events to add
+ */
+ addAccountData(events) {
+ for (const event of events) {
+ if (event.getType() === "m.tag") {
+ this.addTags(event);
+ }
+ const eventType = event.getType();
+ const lastEvent = this.accountData.get(eventType);
+ this.accountData.set(eventType, event);
+ this.emit(RoomEvent.AccountData, event, this, lastEvent);
+ }
+ }
+
+ /**
+ * Access account_data event of given event type for this room
+ * @param type - the type of account_data event to be accessed
+ * @returns the account_data event in question
+ */
+ getAccountData(type) {
+ return this.accountData.get(type);
+ }
+
+ /**
+ * Returns whether the syncing user has permission to send a message in the room
+ * @returns true if the user should be permitted to send
+ * message events into the room.
+ */
+ maySendMessage() {
+ return this.getMyMembership() === "join" && (this.client.isRoomEncrypted(this.roomId) ? this.currentState.maySendEvent(_event2.EventType.RoomMessageEncrypted, this.myUserId) : this.currentState.maySendEvent(_event2.EventType.RoomMessage, this.myUserId));
+ }
+
+ /**
+ * Returns whether the given user has permissions to issue an invite for this room.
+ * @param userId - the ID of the Matrix user to check permissions for
+ * @returns true if the user should be permitted to issue invites for this room.
+ */
+ canInvite(userId) {
+ let canInvite = this.getMyMembership() === "join";
+ const powerLevelsEvent = this.currentState.getStateEvents(_event2.EventType.RoomPowerLevels, "");
+ const powerLevels = powerLevelsEvent && powerLevelsEvent.getContent();
+ const me = this.getMember(userId);
+ if (powerLevels && me && powerLevels.invite > me.powerLevel) {
+ canInvite = false;
+ }
+ return canInvite;
+ }
+
+ /**
+ * Returns the join rule based on the m.room.join_rule state event, defaulting to `invite`.
+ * @returns the join_rule applied to this room
+ */
+ getJoinRule() {
+ return this.currentState.getJoinRule();
+ }
+
+ /**
+ * Returns the history visibility based on the m.room.history_visibility state event, defaulting to `shared`.
+ * @returns the history_visibility applied to this room
+ */
+ getHistoryVisibility() {
+ return this.currentState.getHistoryVisibility();
+ }
+
+ /**
+ * Returns the history visibility based on the m.room.history_visibility state event, defaulting to `shared`.
+ * @returns the history_visibility applied to this room
+ */
+ getGuestAccess() {
+ return this.currentState.getGuestAccess();
+ }
+
+ /**
+ * Returns the type of the room from the `m.room.create` event content or undefined if none is set
+ * @returns the type of the room.
+ */
+ getType() {
+ const createEvent = this.currentState.getStateEvents(_event2.EventType.RoomCreate, "");
+ if (!createEvent) {
+ if (!this.getTypeWarning) {
+ _logger.logger.warn("[getType] Room " + this.roomId + " does not have an m.room.create event");
+ this.getTypeWarning = true;
+ }
+ return undefined;
+ }
+ return createEvent.getContent()[_event2.RoomCreateTypeField];
+ }
+
+ /**
+ * Returns whether the room is a space-room as defined by MSC1772.
+ * @returns true if the room's type is RoomType.Space
+ */
+ isSpaceRoom() {
+ return this.getType() === _event2.RoomType.Space;
+ }
+
+ /**
+ * Returns whether the room is a call-room as defined by MSC3417.
+ * @returns true if the room's type is RoomType.UnstableCall
+ */
+ isCallRoom() {
+ return this.getType() === _event2.RoomType.UnstableCall;
+ }
+
+ /**
+ * Returns whether the room is a video room.
+ * @returns true if the room's type is RoomType.ElementVideo
+ */
+ isElementVideoRoom() {
+ return this.getType() === _event2.RoomType.ElementVideo;
+ }
+
+ /**
+ * Find the predecessor of this room.
+ *
+ * @param msc3946ProcessDynamicPredecessor - if true, look for an
+ * m.room.predecessor state event and use it if found (MSC3946).
+ * @returns null if this room has no predecessor. Otherwise, returns
+ * the roomId, last eventId and viaServers of the predecessor room.
+ *
+ * If msc3946ProcessDynamicPredecessor is true, use m.predecessor events
+ * as well as m.room.create events to find predecessors.
+ *
+ * Note: if an m.predecessor event is used, eventId may be undefined
+ * since last_known_event_id is optional.
+ *
+ * Note: viaServers may be undefined, and will definitely be undefined if
+ * this predecessor comes from a RoomCreate event (rather than a
+ * RoomPredecessor, which has the optional via_servers property).
+ */
+ findPredecessor(msc3946ProcessDynamicPredecessor = false) {
+ const currentState = this.getLiveTimeline().getState(_eventTimeline.EventTimeline.FORWARDS);
+ if (!currentState) {
+ return null;
+ }
+ return currentState.findPredecessor(msc3946ProcessDynamicPredecessor);
+ }
+ roomNameGenerator(state) {
+ if (this.client.roomNameGenerator) {
+ const name = this.client.roomNameGenerator(this.roomId, state);
+ if (name !== null) {
+ return name;
+ }
+ }
+ switch (state.type) {
+ case RoomNameType.Actual:
+ return state.name;
+ case RoomNameType.Generated:
+ switch (state.subtype) {
+ case "Inviting":
+ return `Inviting ${memberNamesToRoomName(state.names, state.count)}`;
+ default:
+ return memberNamesToRoomName(state.names, state.count);
+ }
+ case RoomNameType.EmptyRoom:
+ if (state.oldName) {
+ return `Empty room (was ${state.oldName})`;
+ } else {
+ return "Empty room";
+ }
+ }
+ }
+
+ /**
+ * This is an internal method. Calculates the name of the room from the current
+ * room state.
+ * @param userId - The client's user ID. Used to filter room members
+ * correctly.
+ * @param ignoreRoomNameEvent - Return the implicit room name that we'd see if there
+ * was no m.room.name event.
+ * @returns The calculated room name.
+ */
+ calculateRoomName(userId, ignoreRoomNameEvent = false) {
+ if (!ignoreRoomNameEvent) {
+ // check for an alias, if any. for now, assume first alias is the
+ // official one.
+ const mRoomName = this.currentState.getStateEvents(_event2.EventType.RoomName, "");
+ if (mRoomName !== null && mRoomName !== void 0 && mRoomName.getContent().name) {
+ return this.roomNameGenerator({
+ type: RoomNameType.Actual,
+ name: mRoomName.getContent().name
+ });
+ }
+ }
+ const alias = this.getCanonicalAlias();
+ if (alias) {
+ return this.roomNameGenerator({
+ type: RoomNameType.Actual,
+ name: alias
+ });
+ }
+ const joinedMemberCount = this.currentState.getJoinedMemberCount();
+ const invitedMemberCount = this.currentState.getInvitedMemberCount();
+ // -1 because these numbers include the syncing user
+ let inviteJoinCount = joinedMemberCount + invitedMemberCount - 1;
+
+ // get service members (e.g. helper bots) for exclusion
+ let excludedUserIds = [];
+ const mFunctionalMembers = this.currentState.getStateEvents(_event2.UNSTABLE_ELEMENT_FUNCTIONAL_USERS.name, "");
+ if (Array.isArray(mFunctionalMembers === null || mFunctionalMembers === void 0 ? void 0 : mFunctionalMembers.getContent().service_members)) {
+ excludedUserIds = mFunctionalMembers.getContent().service_members;
+ }
+
+ // get members that are NOT ourselves and are actually in the room.
+ let otherNames = [];
+ if (this.summaryHeroes) {
+ // if we have a summary, the member state events should be in the room state
+ this.summaryHeroes.forEach(userId => {
+ // filter service members
+ if (excludedUserIds.includes(userId)) {
+ inviteJoinCount--;
+ return;
+ }
+ const member = this.getMember(userId);
+ otherNames.push(member ? member.name : userId);
+ });
+ } else {
+ let otherMembers = this.currentState.getMembers().filter(m => {
+ return m.userId !== userId && (m.membership === "invite" || m.membership === "join");
+ });
+ otherMembers = otherMembers.filter(({
+ userId
+ }) => {
+ // filter service members
+ if (excludedUserIds.includes(userId)) {
+ inviteJoinCount--;
+ return false;
+ }
+ return true;
+ });
+ // make sure members have stable order
+ otherMembers.sort((a, b) => utils.compare(a.userId, b.userId));
+ // only 5 first members, immitate summaryHeroes
+ otherMembers = otherMembers.slice(0, 5);
+ otherNames = otherMembers.map(m => m.name);
+ }
+ if (inviteJoinCount) {
+ return this.roomNameGenerator({
+ type: RoomNameType.Generated,
+ names: otherNames,
+ count: inviteJoinCount
+ });
+ }
+ const myMembership = this.getMyMembership();
+ // if I have created a room and invited people through
+ // 3rd party invites
+ if (myMembership == "join") {
+ const thirdPartyInvites = this.currentState.getStateEvents(_event2.EventType.RoomThirdPartyInvite);
+ if (thirdPartyInvites !== null && thirdPartyInvites !== void 0 && thirdPartyInvites.length) {
+ const thirdPartyNames = thirdPartyInvites.map(i => {
+ return i.getContent().display_name;
+ });
+ return this.roomNameGenerator({
+ type: RoomNameType.Generated,
+ subtype: "Inviting",
+ names: thirdPartyNames,
+ count: thirdPartyNames.length + 1
+ });
+ }
+ }
+
+ // let's try to figure out who was here before
+ let leftNames = otherNames;
+ // if we didn't have heroes, try finding them in the room state
+ if (!leftNames.length) {
+ leftNames = this.currentState.getMembers().filter(m => {
+ return m.userId !== userId && m.membership !== "invite" && m.membership !== "join";
+ }).map(m => m.name);
+ }
+ let oldName;
+ if (leftNames.length) {
+ oldName = this.roomNameGenerator({
+ type: RoomNameType.Generated,
+ names: leftNames,
+ count: leftNames.length + 1
+ });
+ }
+ return this.roomNameGenerator({
+ type: RoomNameType.EmptyRoom,
+ oldName
+ });
+ }
+
+ /**
+ * When we receive a new visibility change event:
+ *
+ * - store this visibility change alongside the timeline, in case we
+ * later need to apply it to an event that we haven't received yet;
+ * - if we have already received the event whose visibility has changed,
+ * patch it to reflect the visibility change and inform listeners.
+ */
+ applyNewVisibilityEvent(event) {
+ const visibilityChange = event.asVisibilityChange();
+ if (!visibilityChange) {
+ // The event is ill-formed.
+ return;
+ }
+
+ // Ignore visibility change events that are not emitted by moderators.
+ const userId = event.getSender();
+ if (!userId) {
+ return;
+ }
+ const isPowerSufficient = _event2.EVENT_VISIBILITY_CHANGE_TYPE.name && this.currentState.maySendStateEvent(_event2.EVENT_VISIBILITY_CHANGE_TYPE.name, userId) || _event2.EVENT_VISIBILITY_CHANGE_TYPE.altName && this.currentState.maySendStateEvent(_event2.EVENT_VISIBILITY_CHANGE_TYPE.altName, userId);
+ if (!isPowerSufficient) {
+ // Powerlevel is insufficient.
+ return;
+ }
+
+ // Record this change in visibility.
+ // If the event is not in our timeline and we only receive it later,
+ // we may need to apply the visibility change at a later date.
+
+ const visibilityEventsOnOriginalEvent = this.visibilityEvents.get(visibilityChange.eventId);
+ if (visibilityEventsOnOriginalEvent) {
+ // It would be tempting to simply erase the latest visibility change
+ // but we need to record all of the changes in case the latest change
+ // is ever redacted.
+ //
+ // In practice, linear scans through `visibilityEvents` should be fast.
+ // However, to protect against a potential DoS attack, we limit the
+ // number of iterations in this loop.
+ let index = visibilityEventsOnOriginalEvent.length - 1;
+ const min = Math.max(0, visibilityEventsOnOriginalEvent.length - MAX_NUMBER_OF_VISIBILITY_EVENTS_TO_SCAN_THROUGH);
+ for (; index >= min; --index) {
+ const target = visibilityEventsOnOriginalEvent[index];
+ if (target.getTs() < event.getTs()) {
+ break;
+ }
+ }
+ if (index === -1) {
+ visibilityEventsOnOriginalEvent.unshift(event);
+ } else {
+ visibilityEventsOnOriginalEvent.splice(index + 1, 0, event);
+ }
+ } else {
+ this.visibilityEvents.set(visibilityChange.eventId, [event]);
+ }
+
+ // Finally, let's check if the event is already in our timeline.
+ // If so, we need to patch it and inform listeners.
+
+ const originalEvent = this.findEventById(visibilityChange.eventId);
+ if (!originalEvent) {
+ return;
+ }
+ originalEvent.applyVisibilityEvent(visibilityChange);
+ }
+ redactVisibilityChangeEvent(event) {
+ // Sanity checks.
+ if (!event.isVisibilityEvent) {
+ throw new Error("expected a visibility change event");
+ }
+ const relation = event.getRelation();
+ const originalEventId = relation === null || relation === void 0 ? void 0 : relation.event_id;
+ const visibilityEventsOnOriginalEvent = this.visibilityEvents.get(originalEventId);
+ if (!visibilityEventsOnOriginalEvent) {
+ // No visibility changes on the original event.
+ // In particular, this change event was not recorded,
+ // most likely because it was ill-formed.
+ return;
+ }
+ const index = visibilityEventsOnOriginalEvent.findIndex(change => change.getId() === event.getId());
+ if (index === -1) {
+ // This change event was not recorded, most likely because
+ // it was ill-formed.
+ return;
+ }
+ // Remove visibility change.
+ visibilityEventsOnOriginalEvent.splice(index, 1);
+
+ // If we removed the latest visibility change event, propagate changes.
+ if (index === visibilityEventsOnOriginalEvent.length) {
+ const originalEvent = this.findEventById(originalEventId);
+ if (!originalEvent) {
+ return;
+ }
+ if (index === 0) {
+ // We have just removed the only visibility change event.
+ this.visibilityEvents.delete(originalEventId);
+ originalEvent.applyVisibilityEvent();
+ } else {
+ const newEvent = visibilityEventsOnOriginalEvent[visibilityEventsOnOriginalEvent.length - 1];
+ const newVisibility = newEvent.asVisibilityChange();
+ if (!newVisibility) {
+ // Event is ill-formed.
+ // This breaks our invariant.
+ throw new Error("at this stage, visibility changes should be well-formed");
+ }
+ originalEvent.applyVisibilityEvent(newVisibility);
+ }
+ }
+ }
+
+ /**
+ * When we receive an event whose visibility has been altered by
+ * a (more recent) visibility change event, patch the event in
+ * place so that clients now not to display it.
+ *
+ * @param event - Any matrix event. If this event has at least one a
+ * pending visibility change event, apply the latest visibility
+ * change event.
+ */
+ applyPendingVisibilityEvents(event) {
+ const visibilityEvents = this.visibilityEvents.get(event.getId());
+ if (!visibilityEvents || visibilityEvents.length == 0) {
+ // No pending visibility change in store.
+ return;
+ }
+ const visibilityEvent = visibilityEvents[visibilityEvents.length - 1];
+ const visibilityChange = visibilityEvent.asVisibilityChange();
+ if (!visibilityChange) {
+ return;
+ }
+ if (visibilityChange.visible) {
+ // Events are visible by default, no need to apply a visibility change.
+ // Note that we need to keep the visibility changes in `visibilityEvents`,
+ // in case we later fetch an older visibility change event that is superseded
+ // by `visibilityChange`.
+ }
+ if (visibilityEvent.getTs() < event.getTs()) {
+ // Something is wrong, the visibility change cannot happen before the
+ // event. Presumably an ill-formed event.
+ return;
+ }
+ event.applyVisibilityEvent(visibilityChange);
+ }
+
+ /**
+ * Find when a client has gained thread capabilities by inspecting the oldest
+ * threaded receipt
+ * @returns the timestamp of the oldest threaded receipt
+ */
+ getOldestThreadedReceiptTs() {
+ return this.oldestThreadedReceiptTs;
+ }
+
+ /**
+ * Returns the most recent unthreaded receipt for a given user
+ * @param userId - the MxID of the User
+ * @returns an unthreaded Receipt. Can be undefined if receipts have been disabled
+ * or a user chooses to use private read receipts (or we have simply not received
+ * a receipt from this user yet).
+ */
+ getLastUnthreadedReceiptFor(userId) {
+ return this.unthreadedReceipts.get(userId);
+ }
+
+ /**
+ * This issue should also be addressed on synapse's side and is tracked as part
+ * of https://github.com/matrix-org/synapse/issues/14837
+ *
+ *
+ * We consider a room fully read if the current user has sent
+ * the last event in the live timeline of that context and if the read receipt
+ * we have on record matches.
+ * This also detects all unread threads and applies the same logic to those
+ * contexts
+ */
+ fixupNotifications(userId) {
+ super.fixupNotifications(userId);
+ const unreadThreads = this.getThreads().filter(thread => this.getThreadUnreadNotificationCount(thread.id, NotificationCountType.Total) > 0);
+ for (const thread of unreadThreads) {
+ thread.fixupNotifications(userId);
+ }
+ }
+}
+
+// a map from current event status to a list of allowed next statuses
+exports.Room = Room;
+const ALLOWED_TRANSITIONS = {
+ [_eventStatus.EventStatus.ENCRYPTING]: [_eventStatus.EventStatus.SENDING, _eventStatus.EventStatus.NOT_SENT, _eventStatus.EventStatus.CANCELLED],
+ [_eventStatus.EventStatus.SENDING]: [_eventStatus.EventStatus.ENCRYPTING, _eventStatus.EventStatus.QUEUED, _eventStatus.EventStatus.NOT_SENT, _eventStatus.EventStatus.SENT],
+ [_eventStatus.EventStatus.QUEUED]: [_eventStatus.EventStatus.SENDING, _eventStatus.EventStatus.NOT_SENT, _eventStatus.EventStatus.CANCELLED],
+ [_eventStatus.EventStatus.SENT]: [],
+ [_eventStatus.EventStatus.NOT_SENT]: [_eventStatus.EventStatus.SENDING, _eventStatus.EventStatus.QUEUED, _eventStatus.EventStatus.CANCELLED],
+ [_eventStatus.EventStatus.CANCELLED]: []
+};
+let RoomNameType;
+exports.RoomNameType = RoomNameType;
+(function (RoomNameType) {
+ RoomNameType[RoomNameType["EmptyRoom"] = 0] = "EmptyRoom";
+ RoomNameType[RoomNameType["Generated"] = 1] = "Generated";
+ RoomNameType[RoomNameType["Actual"] = 2] = "Actual";
+})(RoomNameType || (exports.RoomNameType = RoomNameType = {}));
+// Can be overriden by IMatrixClientCreateOpts::memberNamesToRoomNameFn
+function memberNamesToRoomName(names, count) {
+ const countWithoutMe = count - 1;
+ if (!names.length) {
+ return "Empty room";
+ } else if (names.length === 1 && countWithoutMe <= 1) {
+ return names[0];
+ } else if (names.length === 2 && countWithoutMe <= 2) {
+ return `${names[0]} and ${names[1]}`;
+ } else {
+ const plural = countWithoutMe > 1;
+ if (plural) {
+ return `${names[0]} and ${countWithoutMe} others`;
+ } else {
+ return `${names[0]} and 1 other`;
+ }
+ }
+}
+//# sourceMappingURL=room.js.map \ No newline at end of file
diff --git a/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/room.js.map b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/room.js.map
new file mode 100644
index 0000000..91bda73
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/room.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"room.js","names":["_matrixEventsSdk","require","_eventTimelineSet","_eventTimeline","_contentRepo","utils","_interopRequireWildcard","_event","_eventStatus","_roomMember","_roomSummary","_logger","_ReEmitter","_event2","_client","_filter","_roomState","_beacon","_thread","_read_receipts","_relationsContainer","_readReceipt","_poll","_getRequireWildcardCache","nodeInterop","WeakMap","cacheBabelInterop","cacheNodeInterop","obj","__esModule","default","cache","has","get","newObj","hasPropertyDescriptor","Object","defineProperty","getOwnPropertyDescriptor","key","prototype","hasOwnProperty","call","desc","set","ownKeys","object","enumerableOnly","keys","getOwnPropertySymbols","symbols","filter","sym","enumerable","push","apply","_objectSpread","target","i","arguments","length","source","forEach","_defineProperty2","getOwnPropertyDescriptors","defineProperties","KNOWN_SAFE_ROOM_VERSION","exports","SAFE_ROOM_VERSIONS","MAX_NUMBER_OF_VISIBILITY_EVENTS_TO_SCAN_THROUGH","NotificationCountType","RoomEvent","Room","ReadReceipt","constructor","roomId","client","myUserId","opts","Map","Infinity","RelationsContainer","thread","toStartOfTimeline","recreateEvent","_this$threadsTimeline","updateThreadRootEvent","threadsTimelineSets","hasCurrentUserParticipated","_this$threadsTimeline2","timelineSet","rootEvent","removeEvent","id","Thread","hasServerSideSupport","addLiveEvent","duplicateStrategy","DuplicateStrategy","Replace","fromCache","roomState","currentState","addEventToTimeline","getLiveTimeline","event","isRedaction","redactId","redacts","redactedEvent","findEventById","undefined","makeRedacted","isState","currentStateEvent","getStateEvents","getType","getStateKey","getId","setStateEvents","emit","Redaction","visibilityEvents","delete","isVisibilityEvent","redactVisibilityChangeEvent","setMaxListeners","reEmitter","TypedReEmitter","pendingEventOrdering","PendingEventOrdering","Chronological","name","normalizedName","timelineSets","EventTimelineSet","reEmit","getUnfilteredTimelineSet","Timeline","TimelineReset","fixUpLegacyTimelineFields","Detached","pendingEventList","store","getPendingEvents","then","events","mapper","getEventMapper","toDevice","decrypt","serializedEvent","decryptEventIfNeeded","setStatus","EventStatus","NOT_SENT","addPendingEvent","getTxnId","lazyLoadMembers","membersPromise","Promise","resolve","createThreadsTimelineSets","_this$client","threadTimelineSetsPromise","supportsThreads","all","createThreadTimelineSet","ThreadFilterType","My","e","decryptCriticalEvents","isCryptoEnabled","readReceiptEventId","getEventReadUpTo","getUserId","getEvents","readReceiptTimelineIndex","findIndex","matrixEvent","event_id","decryptionPromises","slice","reverse","map","isRetry","allSettled","decryptAllEvents","getCreator","_createEvent$getConte","createEvent","EventType","RoomCreate","getContent","getVersion","_createEvent$getConte2","getVersionWarning","logger","warn","shouldUpgradeToVersion","includes","getRecommendedVersion","capabilities","getCapabilities","versionCap","available","safeVer","RoomVersionStability","Stable","result","checkVersionAgainstCapability","urgent","needsUpgrade","caps","currentVersion","log","version","stableVersions","v","match","userMayUpgradeRoom","userId","maySendStateEvent","RoomTombstone","Error","removePendingEvent","eventId","removed","removeElement","ev","savePendingEvents","hasPendingEvent","_this$pendingEventLis","_this$pendingEventLis2","some","getPendingEvent","_this$pendingEventLis3","_this$pendingEventLis4","find","getLastActiveTimestamp","timeline","lastEvent","getTs","Number","MIN_SAFE_INTEGER","getMyMembership","_this$selfMembership","selfMembership","getDMInviter","me","getMember","memberCount","getInvitedAndJoinedMemberCount","_this$summaryHeroes","summaryHeroes","guessDMUserId","inviterId","Array","isArray","members","getMembers","anyMember","m","getAvatarFallbackMember","hasHeroes","availableMember","member","availableUser","getUser","user","RoomMember","updateMyMembership","membership","prevMembership","cleanupAfterLeaving","MyMembership","loadMembersFromServer","lastSyncToken","getSyncToken","response","chunk","loadMembers","fromServer","rawMembersEvents","getOutOfBandMembers","isRoomEncrypted","memberEvents","noUnsafeEventProps","membersLoaded","outOfBandMembersReady","loadMembersIfNeeded","markOutOfBandMembersStarted","inMemoryUpdate","setOutOfBandMembers","catch","err","markOutOfBandMembersFailed","oobMembers","isOutOfBand","_m$events$member","error","clearLoadedMembersIfNeeded","clearOutOfBandMembers","refreshLiveTimeline","liveTimelineBefore","forwardPaginationToken","getPaginationToken","EventTimeline","FORWARDS","backwardPaginationToken","BACKWARDS","eventsBefore","mostRecentEventInTimeline","toString","newTimeline","getLatestTimeline","resetLiveTimeline","TimelineRefresh","getEventTimeline","liveTimeline","Direction","Forward","Backward","setPaginationToken","setLiveTimeline","setTimelineNeedsRefresh","backPaginationToken","threads","values","previousOldState","oldState","previousCurrentState","getState","OldStateUpdated","CurrentStateUpdated","stopReEmitting","RoomStateEvent","Events","Members","NewMember","Update","Marker","BeaconEvent","New","Destroy","LivenessChange","hasUnverifiedDevices","e2eMembers","getEncryptionTargetMembers","devices","getStoredDevicesForUser","device","isUnverified","getTimelineSets","getTimelineForEvent","findThreadForEvent","addTimeline","value","timelineNeedsRefresh","getTimelineNeedsRefresh","getThreads","getUnreadNotificationCount","type","Total","count","getRoomUnreadNotificationCount","threadNotification","threadNotifications","_threadNotification$t","getUnreadCountForEventContext","_ref","isThreadEvent","threadRootId","isThreadRoot","getThreadUnreadNotificationCount","_this$notificationCou","notificationCounts","threadId","_this$threadNotificat","_this$threadNotificat2","hasThreadUnreadNotification","notification","_notification$highlig","_notification$total","highlight","total","setThreadUnreadNotificationCount","_this$threadNotificat3","_this$threadNotificat4","UnreadNotifications","threadsAggregateNotificationType","_threadNotification$h","_threadNotification$t2","Highlight","resetThreadUnreadNotificationCount","notificationsToKeep","clear","setUnreadNotificationCount","setUnread","setSummary","summary","heroes","joinedCount","invitedCount","isInteger","setJoinedMemberCount","setInvitedMemberCount","setBlacklistUnverifiedDevices","blacklistUnverifiedDevices","getBlacklistUnverifiedDevices","getAvatarUrl","baseUrl","width","height","resizeMethod","allowDefault","roomAvatarEvent","RoomAvatar","mainUrl","url","getHttpUriForMxc","getMxcAvatarUrl","_this$currentState$ge","_this$currentState$ge2","getCanonicalAlias","canonicalAlias","RoomCanonicalAlias","alias","getAltAliases","alt_aliases","addEventsToTimeline","paginationToken","getTimelineSet","getThread","_this$threads$get","from","getJoinedMembers","getMembersWithMembership","getJoinedMemberCount","getInvitedMemberCount","shouldEncryptForInvitedMembers","concat","_ev$getContent","RoomHistoryVisibility","history_visibility","getDefaultRoomName","calculateRoomName","hasMembershipState","getOrCreateFilteredTimelineSet","prepopulateTimeline","useSyncEvents","pendingEvents","filteredTimelineSets","filterId","assign","unfilteredLiveTimeline","getNeighbouringTimeline","livePaginationToken","getThreadListFilter","filterType","All","Filter","definition","room","FILTER_RELATED_BY_REL_TYPES","THREAD_RELATION_TYPE","FILTER_RELATED_BY_SENDERS","setDefinition","getOrCreateFilter","hasServerSideListSupport","currentUserParticipated","getSender","addEvent","processThreadRoots","setEventMetadata","createThread","fetchRoomThreads","threadsReady","fetchRoomThreadList","allThreadsFilter","createMessagesRequest","MAX_SAFE_INTEGER","threadRoots","sort","eventA","eventB","threadAMetadata","getServerAggregatedRelation","threadBMetadata","latest_event","origin_server_ts","latestMyThreadsRootEvent","_this$threadsTimeline3","Ignore","threadRelationship","current_user_participated","_this$threadsTimeline4","on","ThreadEvent","NewReply","onThreadNewReply","Delete","onThreadDelete","processPollEvents","processPollStartEvent","M_POLL_START","matches","poll","Poll","polls","PollEvent","processPollRelationEvent","relationEventId","onNewRelation","processPollEvent","end","createThreadListMessagesRequest","threadListType","getFilter","matrixEvents","updateThreadRootEvents","_timeline$getEvents","roomEvent","it","clearEventMetadata","debug","removeFilteredTimelineSet","indexOf","splice","eventShouldLiveIn","roots","_this$client2","shouldLiveInRoom","shouldLiveInThread","isRelation","parentEventId","getAssociatedId","parentEvent","_this$findEventById","addThreadedEvents","_this$findEventById2","addEvents","processThreadedEvents","applyRedaction","eventsByThread","_eventsByThread","entries","threadEvents","_this$cachedThreadRea","_this$lastThread","_this$lastThread$root","relatedEvents","relations","getAllChildEventsForEvent","RelationType","receipts","cachedThreadReadReceipts","isNewer","lastThread","localTimestamp","processLiveEvent","applyNewVisibilityEvent","applyPendingVisibilityEvents","txnId","getUnsigned","transaction_id","tid","localEvent","txnToEvent","unsigned","setUnsigned","addLiveEventOptions","timelineWasEmpty","sender","RoomRedaction","addReceipt","synthesizeReceipt","ReceiptType","Read","status","SENDING","aggregateNonLiveRelation","markLocallyRedacted","filterRoomTimeline","LocalEchoUpdated","txn_id","isEventEncrypted","RoomMessageEncrypted","setPendingEvents","aggregateChildEvent","getEventForTxnId","handleRemoteEcho","remoteEvent","oldEventId","newEventId","oldStatus","updatePendingEvent","newStatus","getRoomId","SENT","remoteTxnId","allowed","ALLOWED_TRANSITIONS","replaceLocalEventId","replaceEventId","CANCELLED","removedEvent","revertRedactionLocalEcho","redactionEvent","unmarkLocallyRedacted","RedactionCancelled","addLiveEvents","duplicateStrategyOrOpts","findThreadRoots","options","_eventsByThread2","existingEvent","partitionThreadedEvents","ROOM","THREAD","reduce","memo","setThreadId","Set","_event$relationEventI","add","synthetic","content","receiptType","_receipt$thread_id","_this$unthreadedRecei","_this$unthreadedRecei2","receipt","receiptForMainTimeline","thread_id","MAIN_ROOM_TIMELINE","receiptDestination","addReceiptToStructure","isInitialSyncComplete","_this$cachedThreadRea2","ts","oldestThreadedReceiptTs","unthreadedReceipts","Receipt","addEphemeralEvents","Typing","setTypingEvent","removeEvents","eventIds","removedAny","recalculate","membershipEvent","strippedStateEvents","invite_room_state","strippedEvent","state_key","MatrixEvent","Date","now","room_id","user_id","oldName","normalize","RoomSummary","title","Name","addTags","tags","Tags","addAccountData","eventType","accountData","AccountData","getAccountData","maySendMessage","maySendEvent","RoomMessage","canInvite","powerLevelsEvent","RoomPowerLevels","powerLevels","invite","powerLevel","getJoinRule","getHistoryVisibility","getGuestAccess","getTypeWarning","RoomCreateTypeField","isSpaceRoom","RoomType","Space","isCallRoom","UnstableCall","isElementVideoRoom","ElementVideo","findPredecessor","msc3946ProcessDynamicPredecessor","roomNameGenerator","state","RoomNameType","Actual","Generated","subtype","memberNamesToRoomName","names","EmptyRoom","ignoreRoomNameEvent","mRoomName","RoomName","joinedMemberCount","invitedMemberCount","inviteJoinCount","excludedUserIds","mFunctionalMembers","UNSTABLE_ELEMENT_FUNCTIONAL_USERS","service_members","otherNames","otherMembers","a","b","compare","myMembership","thirdPartyInvites","RoomThirdPartyInvite","thirdPartyNames","display_name","leftNames","visibilityChange","asVisibilityChange","isPowerSufficient","EVENT_VISIBILITY_CHANGE_TYPE","altName","visibilityEventsOnOriginalEvent","index","min","Math","max","unshift","originalEvent","applyVisibilityEvent","relation","getRelation","originalEventId","change","newEvent","newVisibility","visibilityEvent","visible","getOldestThreadedReceiptTs","getLastUnthreadedReceiptFor","fixupNotifications","unreadThreads","ENCRYPTING","QUEUED","countWithoutMe","plural"],"sources":["../../src/models/room.ts"],"sourcesContent":["/*\nCopyright 2015 - 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 { M_POLL_START, Optional } from \"matrix-events-sdk\";\n\nimport {\n EventTimelineSet,\n DuplicateStrategy,\n IAddLiveEventOptions,\n EventTimelineSetHandlerMap,\n} from \"./event-timeline-set\";\nimport { Direction, EventTimeline } from \"./event-timeline\";\nimport { getHttpUriForMxc } from \"../content-repo\";\nimport * as utils from \"../utils\";\nimport { normalize, noUnsafeEventProps } from \"../utils\";\nimport { IEvent, IThreadBundledRelationship, MatrixEvent, MatrixEventEvent, MatrixEventHandlerMap } from \"./event\";\nimport { EventStatus } from \"./event-status\";\nimport { RoomMember } from \"./room-member\";\nimport { IRoomSummary, RoomSummary } from \"./room-summary\";\nimport { logger } from \"../logger\";\nimport { TypedReEmitter } from \"../ReEmitter\";\nimport {\n EventType,\n RoomCreateTypeField,\n RoomType,\n UNSTABLE_ELEMENT_FUNCTIONAL_USERS,\n EVENT_VISIBILITY_CHANGE_TYPE,\n RelationType,\n} from \"../@types/event\";\nimport { IRoomVersionsCapability, MatrixClient, PendingEventOrdering, RoomVersionStability } from \"../client\";\nimport { GuestAccess, HistoryVisibility, JoinRule, ResizeMethod } from \"../@types/partials\";\nimport { Filter, IFilterDefinition } from \"../filter\";\nimport { RoomState, RoomStateEvent, RoomStateEventHandlerMap } from \"./room-state\";\nimport { BeaconEvent, BeaconEventHandlerMap } from \"./beacon\";\nimport {\n Thread,\n ThreadEvent,\n EventHandlerMap as ThreadHandlerMap,\n FILTER_RELATED_BY_REL_TYPES,\n THREAD_RELATION_TYPE,\n FILTER_RELATED_BY_SENDERS,\n ThreadFilterType,\n} from \"./thread\";\nimport {\n CachedReceiptStructure,\n MAIN_ROOM_TIMELINE,\n Receipt,\n ReceiptContent,\n ReceiptType,\n} from \"../@types/read_receipts\";\nimport { IStateEventWithRoomId } from \"../@types/search\";\nimport { RelationsContainer } from \"./relations-container\";\nimport { ReadReceipt, synthesizeReceipt } from \"./read-receipt\";\nimport { Poll, PollEvent } from \"./poll\";\n\n// These constants are used as sane defaults when the homeserver doesn't support\n// the m.room_versions capability. In practice, KNOWN_SAFE_ROOM_VERSION should be\n// the same as the common default room version whereas SAFE_ROOM_VERSIONS are the\n// room versions which are considered okay for people to run without being asked\n// to upgrade (ie: \"stable\"). Eventually, we should remove these when all homeservers\n// return an m.room_versions capability.\nexport const KNOWN_SAFE_ROOM_VERSION = \"9\";\nconst SAFE_ROOM_VERSIONS = [\"1\", \"2\", \"3\", \"4\", \"5\", \"6\", \"7\", \"8\", \"9\"];\n\ninterface IOpts {\n /**\n * Controls where pending messages appear in a room's timeline.\n * If \"<b>chronological</b>\", messages will appear in the timeline when the call to `sendEvent` was made.\n * If \"<b>detached</b>\", pending messages will appear in a separate list,\n * accessible via {@link Room#getPendingEvents}.\n * Default: \"chronological\".\n */\n pendingEventOrdering?: PendingEventOrdering;\n /**\n * Set to true to enable improved timeline support.\n */\n timelineSupport?: boolean;\n lazyLoadMembers?: boolean;\n}\n\nexport interface IRecommendedVersion {\n version: string;\n needsUpgrade: boolean;\n urgent: boolean;\n}\n\n// When inserting a visibility event affecting event `eventId`, we\n// need to scan through existing visibility events for `eventId`.\n// In theory, this could take an unlimited amount of time if:\n//\n// - the visibility event was sent by a moderator; and\n// - `eventId` already has many visibility changes (usually, it should\n// be 2 or less); and\n// - for some reason, the visibility changes are received out of order\n// (usually, this shouldn't happen at all).\n//\n// For this reason, we limit the number of events to scan through,\n// expecting that a broken visibility change for a single event in\n// an extremely uncommon case (possibly a DoS) is a small\n// price to pay to keep matrix-js-sdk responsive.\nconst MAX_NUMBER_OF_VISIBILITY_EVENTS_TO_SCAN_THROUGH = 30;\n\nexport type NotificationCount = Partial<Record<NotificationCountType, number>>;\n\nexport enum NotificationCountType {\n Highlight = \"highlight\",\n Total = \"total\",\n}\n\nexport interface ICreateFilterOpts {\n // Populate the filtered timeline with already loaded events in the room\n // timeline. Useful to disable for some filters that can't be achieved by the\n // client in an efficient manner\n prepopulateTimeline?: boolean;\n useSyncEvents?: boolean;\n pendingEvents?: boolean;\n}\n\nexport enum RoomEvent {\n MyMembership = \"Room.myMembership\",\n Tags = \"Room.tags\",\n AccountData = \"Room.accountData\",\n Receipt = \"Room.receipt\",\n Name = \"Room.name\",\n Redaction = \"Room.redaction\",\n RedactionCancelled = \"Room.redactionCancelled\",\n LocalEchoUpdated = \"Room.localEchoUpdated\",\n Timeline = \"Room.timeline\",\n TimelineReset = \"Room.timelineReset\",\n TimelineRefresh = \"Room.TimelineRefresh\",\n OldStateUpdated = \"Room.OldStateUpdated\",\n CurrentStateUpdated = \"Room.CurrentStateUpdated\",\n HistoryImportedWithinTimeline = \"Room.historyImportedWithinTimeline\",\n UnreadNotifications = \"Room.UnreadNotifications\",\n}\n\nexport type RoomEmittedEvents =\n | RoomEvent\n | RoomStateEvent.Events\n | RoomStateEvent.Members\n | RoomStateEvent.NewMember\n | RoomStateEvent.Update\n | RoomStateEvent.Marker\n | ThreadEvent.New\n | ThreadEvent.Update\n | ThreadEvent.NewReply\n | ThreadEvent.Delete\n | MatrixEventEvent.BeforeRedaction\n | BeaconEvent.New\n | BeaconEvent.Update\n | BeaconEvent.Destroy\n | BeaconEvent.LivenessChange\n | PollEvent.New;\n\nexport type RoomEventHandlerMap = {\n /**\n * Fires when the logged in user's membership in the room is updated.\n *\n * @param room - The room in which the membership has been updated\n * @param membership - The new membership value\n * @param prevMembership - The previous membership value\n */\n [RoomEvent.MyMembership]: (room: Room, membership: string, prevMembership?: string) => void;\n /**\n * Fires whenever a room's tags are updated.\n * @param event - The tags event\n * @param room - The room whose Room.tags was updated.\n * @example\n * ```\n * matrixClient.on(\"Room.tags\", function(event, room){\n * var newTags = event.getContent().tags;\n * if (newTags[\"favourite\"]) showStar(room);\n * });\n * ```\n */\n [RoomEvent.Tags]: (event: MatrixEvent, room: Room) => void;\n /**\n * Fires whenever a room's account_data is updated.\n * @param event - The account_data event\n * @param room - The room whose account_data was updated.\n * @param prevEvent - The event being replaced by\n * the new account data, if known.\n * @example\n * ```\n * matrixClient.on(\"Room.accountData\", function(event, room, oldEvent){\n * if (event.getType() === \"m.room.colorscheme\") {\n * applyColorScheme(event.getContents());\n * }\n * });\n * ```\n */\n [RoomEvent.AccountData]: (event: MatrixEvent, room: Room, lastEvent?: MatrixEvent) => void;\n /**\n * Fires whenever a receipt is received for a room\n * @param event - The receipt event\n * @param room - The room whose receipts was updated.\n * @example\n * ```\n * matrixClient.on(\"Room.receipt\", function(event, room){\n * var receiptContent = event.getContent();\n * });\n * ```\n */\n [RoomEvent.Receipt]: (event: MatrixEvent, room: Room) => void;\n /**\n * Fires whenever the name of a room is updated.\n * @param room - The room whose Room.name was updated.\n * @example\n * ```\n * matrixClient.on(\"Room.name\", function(room){\n * var newName = room.name;\n * });\n * ```\n */\n [RoomEvent.Name]: (room: Room) => void;\n /**\n * Fires when an event we had previously received is redacted.\n *\n * (Note this is *not* fired when the redaction happens before we receive the\n * event).\n *\n * @param event - The matrix redaction event\n * @param room - The room containing the redacted event\n */\n [RoomEvent.Redaction]: (event: MatrixEvent, room: Room) => void;\n /**\n * Fires when an event that was previously redacted isn't anymore.\n * This happens when the redaction couldn't be sent and\n * was subsequently cancelled by the user. Redactions have a local echo\n * which is undone in this scenario.\n *\n * @param event - The matrix redaction event that was cancelled.\n * @param room - The room containing the unredacted event\n */\n [RoomEvent.RedactionCancelled]: (event: MatrixEvent, room: Room) => void;\n /**\n * Fires when the status of a transmitted event is updated.\n *\n * <p>When an event is first transmitted, a temporary copy of the event is\n * inserted into the timeline, with a temporary event id, and a status of\n * 'SENDING'.\n *\n * <p>Once the echo comes back from the server, the content of the event\n * (MatrixEvent.event) is replaced by the complete event from the homeserver,\n * thus updating its event id, as well as server-generated fields such as the\n * timestamp. Its status is set to null.\n *\n * <p>Once the /send request completes, if the remote echo has not already\n * arrived, the event is updated with a new event id and the status is set to\n * 'SENT'. The server-generated fields are of course not updated yet.\n *\n * <p>If the /send fails, In this case, the event's status is set to\n * 'NOT_SENT'. If it is later resent, the process starts again, setting the\n * status to 'SENDING'. Alternatively, the message may be cancelled, which\n * removes the event from the room, and sets the status to 'CANCELLED'.\n *\n * <p>This event is raised to reflect each of the transitions above.\n *\n * @param event - The matrix event which has been updated\n *\n * @param room - The room containing the redacted event\n *\n * @param oldEventId - The previous event id (the temporary event id,\n * except when updating a successfully-sent event when its echo arrives)\n *\n * @param oldStatus - The previous event status.\n */\n [RoomEvent.LocalEchoUpdated]: (\n event: MatrixEvent,\n room: Room,\n oldEventId?: string,\n oldStatus?: EventStatus | null,\n ) => void;\n [RoomEvent.OldStateUpdated]: (room: Room, previousRoomState: RoomState, roomState: RoomState) => void;\n [RoomEvent.CurrentStateUpdated]: (room: Room, previousRoomState: RoomState, roomState: RoomState) => void;\n [RoomEvent.HistoryImportedWithinTimeline]: (markerEvent: MatrixEvent, room: Room) => void;\n [RoomEvent.UnreadNotifications]: (unreadNotifications?: NotificationCount, threadId?: string) => void;\n [RoomEvent.TimelineRefresh]: (room: Room, eventTimelineSet: EventTimelineSet) => void;\n [ThreadEvent.New]: (thread: Thread, toStartOfTimeline: boolean) => void;\n /**\n * Fires when a new poll instance is added to the room state\n * @param poll - the new poll\n */\n [PollEvent.New]: (poll: Poll) => void;\n} & Pick<ThreadHandlerMap, ThreadEvent.Update | ThreadEvent.NewReply | ThreadEvent.Delete> &\n EventTimelineSetHandlerMap &\n Pick<MatrixEventHandlerMap, MatrixEventEvent.BeforeRedaction> &\n Pick<\n RoomStateEventHandlerMap,\n | RoomStateEvent.Events\n | RoomStateEvent.Members\n | RoomStateEvent.NewMember\n | RoomStateEvent.Update\n | RoomStateEvent.Marker\n | BeaconEvent.New\n > &\n Pick<BeaconEventHandlerMap, BeaconEvent.Update | BeaconEvent.Destroy | BeaconEvent.LivenessChange>;\n\nexport class Room extends ReadReceipt<RoomEmittedEvents, RoomEventHandlerMap> {\n public readonly reEmitter: TypedReEmitter<RoomEmittedEvents, RoomEventHandlerMap>;\n private txnToEvent: Map<string, MatrixEvent> = new Map(); // Pending in-flight requests { string: MatrixEvent }\n private notificationCounts: NotificationCount = {};\n private readonly threadNotifications = new Map<string, NotificationCount>();\n public readonly cachedThreadReadReceipts = new Map<string, CachedReceiptStructure[]>();\n // Useful to know at what point the current user has started using threads in this room\n private oldestThreadedReceiptTs = Infinity;\n /**\n * A record of the latest unthread receipts per user\n * This is useful in determining whether a user has read a thread or not\n */\n private unthreadedReceipts = new Map<string, Receipt>();\n private readonly timelineSets: EventTimelineSet[];\n public readonly polls: Map<string, Poll> = new Map<string, Poll>();\n public readonly threadsTimelineSets: EventTimelineSet[] = [];\n // any filtered timeline sets we're maintaining for this room\n private readonly filteredTimelineSets: Record<string, EventTimelineSet> = {}; // filter_id: timelineSet\n private timelineNeedsRefresh = false;\n private readonly pendingEventList?: MatrixEvent[];\n // read by megolm via getter; boolean value - null indicates \"use global value\"\n private blacklistUnverifiedDevices?: boolean;\n private selfMembership?: string;\n private summaryHeroes: string[] | null = null;\n // flags to stop logspam about missing m.room.create events\n private getTypeWarning = false;\n private getVersionWarning = false;\n private membersPromise?: Promise<boolean>;\n\n // XXX: These should be read-only\n /**\n * The human-readable display name for this room.\n */\n public name: string;\n /**\n * The un-homoglyphed name for this room.\n */\n public normalizedName: string;\n /**\n * Dict of room tags; the keys are the tag name and the values\n * are any metadata associated with the tag - e.g. `{ \"fav\" : { order: 1 } }`\n */\n public tags: Record<string, Record<string, any>> = {}; // $tagName: { $metadata: $value }\n /**\n * accountData Dict of per-room account_data events; the keys are the\n * event type and the values are the events.\n */\n public accountData: Map<string, MatrixEvent> = new Map(); // $eventType: $event\n /**\n * The room summary.\n */\n public summary: RoomSummary | null = null;\n // legacy fields\n /**\n * The live event timeline for this room, with the oldest event at index 0.\n * Present for backwards compatibility - prefer getLiveTimeline().getEvents()\n */\n public timeline!: MatrixEvent[];\n /**\n * oldState The state of the room at the time of the oldest\n * event in the live timeline. Present for backwards compatibility -\n * prefer getLiveTimeline().getState(EventTimeline.BACKWARDS).\n */\n public oldState!: RoomState;\n /**\n * currentState The state of the room at the time of the\n * newest event in the timeline. Present for backwards compatibility -\n * prefer getLiveTimeline().getState(EventTimeline.FORWARDS).\n */\n public currentState!: RoomState;\n public readonly relations = new RelationsContainer(this.client, this);\n\n /**\n * A collection of events known by the client\n * This is not a comprehensive list of the threads that exist in this room\n */\n private threads = new Map<string, Thread>();\n public lastThread?: Thread;\n\n /**\n * A mapping of eventId to all visibility changes to apply\n * to the event, by chronological order, as per\n * https://github.com/matrix-org/matrix-doc/pull/3531\n *\n * # Invariants\n *\n * - within each list, all events are classed by\n * chronological order;\n * - all events are events such that\n * `asVisibilityEvent()` returns a non-null `IVisibilityChange`;\n * - within each list with key `eventId`, all events\n * are in relation to `eventId`.\n *\n * @experimental\n */\n private visibilityEvents = new Map<string, MatrixEvent[]>();\n\n /**\n * Construct a new Room.\n *\n * <p>For a room, we store an ordered sequence of timelines, which may or may not\n * be continuous. Each timeline lists a series of events, as well as tracking\n * the room state at the start and the end of the timeline. It also tracks\n * forward and backward pagination tokens, as well as containing links to the\n * next timeline in the sequence.\n *\n * <p>There is one special timeline - the 'live' timeline, which represents the\n * timeline to which events are being added in real-time as they are received\n * from the /sync API. Note that you should not retain references to this\n * timeline - even if it is the current timeline right now, it may not remain\n * so if the server gives us a timeline gap in /sync.\n *\n * <p>In order that we can find events from their ids later, we also maintain a\n * map from event_id to timeline and index.\n *\n * @param roomId - Required. The ID of this room.\n * @param client - Required. The client, used to lazy load members.\n * @param myUserId - Required. The ID of the syncing user.\n * @param opts - Configuration options\n */\n public constructor(\n public readonly roomId: string,\n public readonly client: MatrixClient,\n public readonly myUserId: string,\n private readonly opts: IOpts = {},\n ) {\n super();\n // In some cases, we add listeners for every displayed Matrix event, so it's\n // common to have quite a few more than the default limit.\n this.setMaxListeners(100);\n this.reEmitter = new TypedReEmitter(this);\n\n opts.pendingEventOrdering = opts.pendingEventOrdering || PendingEventOrdering.Chronological;\n\n this.name = roomId;\n this.normalizedName = roomId;\n\n // all our per-room timeline sets. the first one is the unfiltered ones;\n // the subsequent ones are the filtered ones in no particular order.\n this.timelineSets = [new EventTimelineSet(this, opts)];\n this.reEmitter.reEmit(this.getUnfilteredTimelineSet(), [RoomEvent.Timeline, RoomEvent.TimelineReset]);\n\n this.fixUpLegacyTimelineFields();\n\n if (this.opts.pendingEventOrdering === PendingEventOrdering.Detached) {\n this.pendingEventList = [];\n this.client.store.getPendingEvents(this.roomId).then((events) => {\n const mapper = this.client.getEventMapper({\n toDevice: false,\n decrypt: false,\n });\n events.forEach(async (serializedEvent: Partial<IEvent>) => {\n const event = mapper(serializedEvent);\n await client.decryptEventIfNeeded(event);\n event.setStatus(EventStatus.NOT_SENT);\n this.addPendingEvent(event, event.getTxnId()!);\n });\n });\n }\n\n // awaited by getEncryptionTargetMembers while room members are loading\n if (!this.opts.lazyLoadMembers) {\n this.membersPromise = Promise.resolve(false);\n } else {\n this.membersPromise = undefined;\n }\n }\n\n private threadTimelineSetsPromise: Promise<[EventTimelineSet, EventTimelineSet]> | null = null;\n public async createThreadsTimelineSets(): Promise<[EventTimelineSet, EventTimelineSet] | null> {\n if (this.threadTimelineSetsPromise) {\n return this.threadTimelineSetsPromise;\n }\n\n if (this.client?.supportsThreads()) {\n try {\n this.threadTimelineSetsPromise = Promise.all([\n this.createThreadTimelineSet(),\n this.createThreadTimelineSet(ThreadFilterType.My),\n ]);\n const timelineSets = await this.threadTimelineSetsPromise;\n this.threadsTimelineSets.push(...timelineSets);\n return timelineSets;\n } catch (e) {\n this.threadTimelineSetsPromise = null;\n return null;\n }\n }\n return null;\n }\n\n /**\n * Bulk decrypt critical events in a room\n *\n * Critical events represents the minimal set of events to decrypt\n * for a typical UI to function properly\n *\n * - Last event of every room (to generate likely message preview)\n * - All events up to the read receipt (to calculate an accurate notification count)\n *\n * @returns Signals when all events have been decrypted\n */\n public async decryptCriticalEvents(): Promise<void> {\n if (!this.client.isCryptoEnabled()) return;\n\n const readReceiptEventId = this.getEventReadUpTo(this.client.getUserId()!, true);\n const events = this.getLiveTimeline().getEvents();\n const readReceiptTimelineIndex = events.findIndex((matrixEvent) => {\n return matrixEvent.event.event_id === readReceiptEventId;\n });\n\n const decryptionPromises = events\n .slice(readReceiptTimelineIndex)\n .reverse()\n .map((event) => this.client.decryptEventIfNeeded(event, { isRetry: true }));\n\n await Promise.allSettled(decryptionPromises);\n }\n\n /**\n * Bulk decrypt events in a room\n *\n * @returns Signals when all events have been decrypted\n */\n public async decryptAllEvents(): Promise<void> {\n if (!this.client.isCryptoEnabled()) return;\n\n const decryptionPromises = this.getUnfilteredTimelineSet()\n .getLiveTimeline()\n .getEvents()\n .slice(0) // copy before reversing\n .reverse()\n .map((event) => this.client.decryptEventIfNeeded(event, { isRetry: true }));\n\n await Promise.allSettled(decryptionPromises);\n }\n\n /**\n * Gets the creator of the room\n * @returns The creator of the room, or null if it could not be determined\n */\n public getCreator(): string | null {\n const createEvent = this.currentState.getStateEvents(EventType.RoomCreate, \"\");\n return createEvent?.getContent()[\"creator\"] ?? null;\n }\n\n /**\n * Gets the version of the room\n * @returns The version of the room, or null if it could not be determined\n */\n public getVersion(): string {\n const createEvent = this.currentState.getStateEvents(EventType.RoomCreate, \"\");\n if (!createEvent) {\n if (!this.getVersionWarning) {\n logger.warn(\"[getVersion] Room \" + this.roomId + \" does not have an m.room.create event\");\n this.getVersionWarning = true;\n }\n return \"1\";\n }\n return createEvent.getContent()[\"room_version\"] ?? \"1\";\n }\n\n /**\n * Determines whether this room needs to be upgraded to a new version\n * @returns What version the room should be upgraded to, or null if\n * the room does not require upgrading at this time.\n * @deprecated Use #getRecommendedVersion() instead\n */\n public shouldUpgradeToVersion(): string | null {\n // TODO: Remove this function.\n // This makes assumptions about which versions are safe, and can easily\n // be wrong. Instead, people are encouraged to use getRecommendedVersion\n // which determines a safer value. This function doesn't use that function\n // because this is not async-capable, and to avoid breaking the contract\n // we're deprecating this.\n\n if (!SAFE_ROOM_VERSIONS.includes(this.getVersion())) {\n return KNOWN_SAFE_ROOM_VERSION;\n }\n\n return null;\n }\n\n /**\n * Determines the recommended room version for the room. This returns an\n * object with 3 properties: `version` as the new version the\n * room should be upgraded to (may be the same as the current version);\n * `needsUpgrade` to indicate if the room actually can be\n * upgraded (ie: does the current version not match?); and `urgent`\n * to indicate if the new version patches a vulnerability in a previous\n * version.\n * @returns\n * Resolves to the version the room should be upgraded to.\n */\n public async getRecommendedVersion(): Promise<IRecommendedVersion> {\n const capabilities = await this.client.getCapabilities();\n let versionCap = capabilities[\"m.room_versions\"];\n if (!versionCap) {\n versionCap = {\n default: KNOWN_SAFE_ROOM_VERSION,\n available: {},\n };\n for (const safeVer of SAFE_ROOM_VERSIONS) {\n versionCap.available[safeVer] = RoomVersionStability.Stable;\n }\n }\n\n let result = this.checkVersionAgainstCapability(versionCap);\n if (result.urgent && result.needsUpgrade) {\n // Something doesn't feel right: we shouldn't need to update\n // because the version we're on should be in the protocol's\n // namespace. This usually means that the server was updated\n // before the client was, making us think the newest possible\n // room version is not stable. As a solution, we'll refresh\n // the capability we're using to determine this.\n logger.warn(\n \"Refreshing room version capability because the server looks \" +\n \"to be supporting a newer room version we don't know about.\",\n );\n\n const caps = await this.client.getCapabilities(true);\n versionCap = caps[\"m.room_versions\"];\n if (!versionCap) {\n logger.warn(\"No room version capability - assuming upgrade required.\");\n return result;\n } else {\n result = this.checkVersionAgainstCapability(versionCap);\n }\n }\n\n return result;\n }\n\n private checkVersionAgainstCapability(versionCap: IRoomVersionsCapability): IRecommendedVersion {\n const currentVersion = this.getVersion();\n logger.log(`[${this.roomId}] Current version: ${currentVersion}`);\n logger.log(`[${this.roomId}] Version capability: `, versionCap);\n\n const result: IRecommendedVersion = {\n version: currentVersion,\n needsUpgrade: false,\n urgent: false,\n };\n\n // If the room is on the default version then nothing needs to change\n if (currentVersion === versionCap.default) return result;\n\n const stableVersions = Object.keys(versionCap.available).filter((v) => versionCap.available[v] === \"stable\");\n\n // Check if the room is on an unstable version. We determine urgency based\n // off the version being in the Matrix spec namespace or not (if the version\n // is in the current namespace and unstable, the room is probably vulnerable).\n if (!stableVersions.includes(currentVersion)) {\n result.version = versionCap.default;\n result.needsUpgrade = true;\n result.urgent = !!this.getVersion().match(/^[0-9]+[0-9.]*$/g);\n if (result.urgent) {\n logger.warn(`URGENT upgrade required on ${this.roomId}`);\n } else {\n logger.warn(`Non-urgent upgrade required on ${this.roomId}`);\n }\n return result;\n }\n\n // The room is on a stable, but non-default, version by this point.\n // No upgrade needed.\n return result;\n }\n\n /**\n * Determines whether the given user is permitted to perform a room upgrade\n * @param userId - The ID of the user to test against\n * @returns True if the given user is permitted to upgrade the room\n */\n public userMayUpgradeRoom(userId: string): boolean {\n return this.currentState.maySendStateEvent(EventType.RoomTombstone, userId);\n }\n\n /**\n * Get the list of pending sent events for this room\n *\n * @returns A list of the sent events\n * waiting for remote echo.\n *\n * @throws If `opts.pendingEventOrdering` was not 'detached'\n */\n public getPendingEvents(): MatrixEvent[] {\n if (!this.pendingEventList) {\n throw new Error(\n \"Cannot call getPendingEvents with pendingEventOrdering == \" + this.opts.pendingEventOrdering,\n );\n }\n\n return this.pendingEventList;\n }\n\n /**\n * Removes a pending event for this room\n *\n * @returns True if an element was removed.\n */\n public removePendingEvent(eventId: string): boolean {\n if (!this.pendingEventList) {\n throw new Error(\n \"Cannot call removePendingEvent with pendingEventOrdering == \" + this.opts.pendingEventOrdering,\n );\n }\n\n const removed = utils.removeElement(\n this.pendingEventList,\n function (ev) {\n return ev.getId() == eventId;\n },\n false,\n );\n\n this.savePendingEvents();\n\n return removed;\n }\n\n /**\n * Check whether the pending event list contains a given event by ID.\n * If pending event ordering is not \"detached\" then this returns false.\n *\n * @param eventId - The event ID to check for.\n */\n public hasPendingEvent(eventId: string): boolean {\n return this.pendingEventList?.some((event) => event.getId() === eventId) ?? false;\n }\n\n /**\n * Get a specific event from the pending event list, if configured, null otherwise.\n *\n * @param eventId - The event ID to check for.\n */\n public getPendingEvent(eventId: string): MatrixEvent | null {\n return this.pendingEventList?.find((event) => event.getId() === eventId) ?? null;\n }\n\n /**\n * Get the live unfiltered timeline for this room.\n *\n * @returns live timeline\n */\n public getLiveTimeline(): EventTimeline {\n return this.getUnfilteredTimelineSet().getLiveTimeline();\n }\n\n /**\n * Get the timestamp of the last message in the room\n *\n * @returns the timestamp of the last message in the room\n */\n public getLastActiveTimestamp(): number {\n const timeline = this.getLiveTimeline();\n const events = timeline.getEvents();\n if (events.length) {\n const lastEvent = events[events.length - 1];\n return lastEvent.getTs();\n } else {\n return Number.MIN_SAFE_INTEGER;\n }\n }\n\n /**\n * @returns the membership type (join | leave | invite) for the logged in user\n */\n public getMyMembership(): string {\n return this.selfMembership ?? \"leave\";\n }\n\n /**\n * If this room is a DM we're invited to,\n * try to find out who invited us\n * @returns user id of the inviter\n */\n public getDMInviter(): string | undefined {\n const me = this.getMember(this.myUserId);\n if (me) {\n return me.getDMInviter();\n }\n\n if (this.selfMembership === \"invite\") {\n // fall back to summary information\n const memberCount = this.getInvitedAndJoinedMemberCount();\n if (memberCount === 2) {\n return this.summaryHeroes?.[0];\n }\n }\n }\n\n /**\n * Assuming this room is a DM room, tries to guess with which user.\n * @returns user id of the other member (could be syncing user)\n */\n public guessDMUserId(): string {\n const me = this.getMember(this.myUserId);\n if (me) {\n const inviterId = me.getDMInviter();\n if (inviterId) {\n return inviterId;\n }\n }\n // Remember, we're assuming this room is a DM, so returning the first member we find should be fine\n if (Array.isArray(this.summaryHeroes) && this.summaryHeroes.length) {\n return this.summaryHeroes[0];\n }\n const members = this.currentState.getMembers();\n const anyMember = members.find((m) => m.userId !== this.myUserId);\n if (anyMember) {\n return anyMember.userId;\n }\n // it really seems like I'm the only user in the room\n // so I probably created a room with just me in it\n // and marked it as a DM. Ok then\n return this.myUserId;\n }\n\n public getAvatarFallbackMember(): RoomMember | undefined {\n const memberCount = this.getInvitedAndJoinedMemberCount();\n if (memberCount > 2) {\n return;\n }\n const hasHeroes = Array.isArray(this.summaryHeroes) && this.summaryHeroes.length;\n if (hasHeroes) {\n const availableMember = this.summaryHeroes!.map((userId) => {\n return this.getMember(userId);\n }).find((member) => !!member);\n if (availableMember) {\n return availableMember;\n }\n }\n const members = this.currentState.getMembers();\n // could be different than memberCount\n // as this includes left members\n if (members.length <= 2) {\n const availableMember = members.find((m) => {\n return m.userId !== this.myUserId;\n });\n if (availableMember) {\n return availableMember;\n }\n }\n // if all else fails, try falling back to a user,\n // and create a one-off member for it\n if (hasHeroes) {\n const availableUser = this.summaryHeroes!.map((userId) => {\n return this.client.getUser(userId);\n }).find((user) => !!user);\n if (availableUser) {\n const member = new RoomMember(this.roomId, availableUser.userId);\n member.user = availableUser;\n return member;\n }\n }\n }\n\n /**\n * Sets the membership this room was received as during sync\n * @param membership - join | leave | invite\n */\n public updateMyMembership(membership: string): void {\n const prevMembership = this.selfMembership;\n this.selfMembership = membership;\n if (prevMembership !== membership) {\n if (membership === \"leave\") {\n this.cleanupAfterLeaving();\n }\n this.emit(RoomEvent.MyMembership, this, membership, prevMembership);\n }\n }\n\n private async loadMembersFromServer(): Promise<IStateEventWithRoomId[]> {\n const lastSyncToken = this.client.store.getSyncToken();\n const response = await this.client.members(this.roomId, undefined, \"leave\", lastSyncToken ?? undefined);\n return response.chunk;\n }\n\n private async loadMembers(): Promise<{ memberEvents: MatrixEvent[]; fromServer: boolean }> {\n // were the members loaded from the server?\n let fromServer = false;\n let rawMembersEvents = await this.client.store.getOutOfBandMembers(this.roomId);\n // If the room is encrypted, we always fetch members from the server at\n // least once, in case the latest state wasn't persisted properly. Note\n // that this function is only called once (unless loading the members\n // fails), since loadMembersIfNeeded always returns this.membersPromise\n // if set, which will be the result of the first (successful) call.\n if (rawMembersEvents === null || (this.client.isCryptoEnabled() && this.client.isRoomEncrypted(this.roomId))) {\n fromServer = true;\n rawMembersEvents = await this.loadMembersFromServer();\n logger.log(`LL: got ${rawMembersEvents.length} ` + `members from server for room ${this.roomId}`);\n }\n const memberEvents = rawMembersEvents.filter(noUnsafeEventProps).map(this.client.getEventMapper());\n return { memberEvents, fromServer };\n }\n\n /**\n * Check if loading of out-of-band-members has completed\n *\n * @returns true if the full membership list of this room has been loaded (including if lazy-loading is disabled).\n * False if the load is not started or is in progress.\n */\n public membersLoaded(): boolean {\n if (!this.opts.lazyLoadMembers) {\n return true;\n }\n\n return this.currentState.outOfBandMembersReady();\n }\n\n /**\n * Preloads the member list in case lazy loading\n * of memberships is in use. Can be called multiple times,\n * it will only preload once.\n * @returns when preloading is done and\n * accessing the members on the room will take\n * all members in the room into account\n */\n public loadMembersIfNeeded(): Promise<boolean> {\n if (this.membersPromise) {\n return this.membersPromise;\n }\n\n // mark the state so that incoming messages while\n // the request is in flight get marked as superseding\n // the OOB members\n this.currentState.markOutOfBandMembersStarted();\n\n const inMemoryUpdate = this.loadMembers()\n .then((result) => {\n this.currentState.setOutOfBandMembers(result.memberEvents);\n return result.fromServer;\n })\n .catch((err) => {\n // allow retries on fail\n this.membersPromise = undefined;\n this.currentState.markOutOfBandMembersFailed();\n throw err;\n });\n // update members in storage, but don't wait for it\n inMemoryUpdate\n .then((fromServer) => {\n if (fromServer) {\n const oobMembers = this.currentState\n .getMembers()\n .filter((m) => m.isOutOfBand())\n .map((m) => m.events.member?.event as IStateEventWithRoomId);\n logger.log(`LL: telling store to write ${oobMembers.length}` + ` members for room ${this.roomId}`);\n const store = this.client.store;\n return (\n store\n .setOutOfBandMembers(this.roomId, oobMembers)\n // swallow any IDB error as we don't want to fail\n // because of this\n .catch((err) => {\n logger.log(\"LL: storing OOB room members failed, oh well\", err);\n })\n );\n }\n })\n .catch((err) => {\n // as this is not awaited anywhere,\n // at least show the error in the console\n logger.error(err);\n });\n\n this.membersPromise = inMemoryUpdate;\n\n return this.membersPromise;\n }\n\n /**\n * Removes the lazily loaded members from storage if needed\n */\n public async clearLoadedMembersIfNeeded(): Promise<void> {\n if (this.opts.lazyLoadMembers && this.membersPromise) {\n await this.loadMembersIfNeeded();\n await this.client.store.clearOutOfBandMembers(this.roomId);\n this.currentState.clearOutOfBandMembers();\n this.membersPromise = undefined;\n }\n }\n\n /**\n * called when sync receives this room in the leave section\n * to do cleanup after leaving a room. Possibly called multiple times.\n */\n private cleanupAfterLeaving(): void {\n this.clearLoadedMembersIfNeeded().catch((err) => {\n logger.error(`error after clearing loaded members from ` + `room ${this.roomId} after leaving`);\n logger.log(err);\n });\n }\n\n /**\n * Empty out the current live timeline and re-request it. This is used when\n * historical messages are imported into the room via MSC2716 `/batch_send`\n * because the client may already have that section of the timeline loaded.\n * We need to force the client to throw away their current timeline so that\n * when they back paginate over the area again with the historical messages\n * in between, it grabs the newly imported messages. We can listen for\n * `UNSTABLE_MSC2716_MARKER`, in order to tell when historical messages are ready\n * to be discovered in the room and the timeline needs a refresh. The SDK\n * emits a `RoomEvent.HistoryImportedWithinTimeline` event when we detect a\n * valid marker and can check the needs refresh status via\n * `room.getTimelineNeedsRefresh()`.\n */\n public async refreshLiveTimeline(): Promise<void> {\n const liveTimelineBefore = this.getLiveTimeline();\n const forwardPaginationToken = liveTimelineBefore.getPaginationToken(EventTimeline.FORWARDS);\n const backwardPaginationToken = liveTimelineBefore.getPaginationToken(EventTimeline.BACKWARDS);\n const eventsBefore = liveTimelineBefore.getEvents();\n const mostRecentEventInTimeline = eventsBefore[eventsBefore.length - 1];\n logger.log(\n `[refreshLiveTimeline for ${this.roomId}] at ` +\n `mostRecentEventInTimeline=${mostRecentEventInTimeline && mostRecentEventInTimeline.getId()} ` +\n `liveTimelineBefore=${liveTimelineBefore.toString()} ` +\n `forwardPaginationToken=${forwardPaginationToken} ` +\n `backwardPaginationToken=${backwardPaginationToken}`,\n );\n\n // Get the main TimelineSet\n const timelineSet = this.getUnfilteredTimelineSet();\n\n let newTimeline: Optional<EventTimeline>;\n // If there isn't any event in the timeline, let's go fetch the latest\n // event and construct a timeline from it.\n //\n // This should only really happen if the user ran into an error\n // with refreshing the timeline before which left them in a blank\n // timeline from `resetLiveTimeline`.\n if (!mostRecentEventInTimeline) {\n newTimeline = await this.client.getLatestTimeline(timelineSet);\n } else {\n // Empty out all of `this.timelineSets`. But we also need to keep the\n // same `timelineSet` references around so the React code updates\n // properly and doesn't ignore the room events we emit because it checks\n // that the `timelineSet` references are the same. We need the\n // `timelineSet` empty so that the `client.getEventTimeline(...)` call\n // later, will call `/context` and create a new timeline instead of\n // returning the same one.\n this.resetLiveTimeline(null, null);\n\n // Make the UI timeline show the new blank live timeline we just\n // reset so that if the network fails below it's showing the\n // accurate state of what we're working with instead of the\n // disconnected one in the TimelineWindow which is just hanging\n // around by reference.\n this.emit(RoomEvent.TimelineRefresh, this, timelineSet);\n\n // Use `client.getEventTimeline(...)` to construct a new timeline from a\n // `/context` response state and events for the most recent event before\n // we reset everything. The `timelineSet` we pass in needs to be empty\n // in order for this function to call `/context` and generate a new\n // timeline.\n newTimeline = await this.client.getEventTimeline(timelineSet, mostRecentEventInTimeline.getId()!);\n }\n\n // If a racing `/sync` beat us to creating a new timeline, use that\n // instead because it's the latest in the room and any new messages in\n // the scrollback will include the history.\n const liveTimeline = timelineSet.getLiveTimeline();\n if (\n !liveTimeline ||\n (liveTimeline.getPaginationToken(Direction.Forward) === null &&\n liveTimeline.getPaginationToken(Direction.Backward) === null &&\n liveTimeline.getEvents().length === 0)\n ) {\n logger.log(`[refreshLiveTimeline for ${this.roomId}] using our new live timeline`);\n // Set the pagination token back to the live sync token (`null`) instead\n // of using the `/context` historical token (ex. `t12-13_0_0_0_0_0_0_0_0`)\n // so that it matches the next response from `/sync` and we can properly\n // continue the timeline.\n newTimeline!.setPaginationToken(forwardPaginationToken, EventTimeline.FORWARDS);\n\n // Set our new fresh timeline as the live timeline to continue syncing\n // forwards and back paginating from.\n timelineSet.setLiveTimeline(newTimeline!);\n // Fixup `this.oldstate` so that `scrollback` has the pagination tokens\n // available\n this.fixUpLegacyTimelineFields();\n } else {\n logger.log(\n `[refreshLiveTimeline for ${this.roomId}] \\`/sync\\` or some other request beat us to creating a new ` +\n `live timeline after we reset it. We'll use that instead since any events in the scrollback from ` +\n `this timeline will include the history.`,\n );\n }\n\n // The timeline has now been refreshed ✅\n this.setTimelineNeedsRefresh(false);\n\n // Emit an event which clients can react to and re-load the timeline\n // from the SDK\n this.emit(RoomEvent.TimelineRefresh, this, timelineSet);\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.\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 resetLiveTimeline(backPaginationToken?: string | null, forwardPaginationToken?: string | null): void {\n for (const timelineSet of this.timelineSets) {\n timelineSet.resetLiveTimeline(backPaginationToken ?? undefined, forwardPaginationToken ?? undefined);\n }\n for (const thread of this.threads.values()) {\n thread.resetLiveTimeline(backPaginationToken, forwardPaginationToken);\n }\n\n this.fixUpLegacyTimelineFields();\n }\n\n /**\n * Fix up this.timeline, this.oldState and this.currentState\n *\n * @internal\n */\n private fixUpLegacyTimelineFields(): void {\n const previousOldState = this.oldState;\n const previousCurrentState = this.currentState;\n\n // maintain this.timeline as a reference to the live timeline,\n // and this.oldState and this.currentState as references to the\n // state at the start and end of that timeline. These are more\n // for backwards-compatibility than anything else.\n this.timeline = this.getLiveTimeline().getEvents();\n this.oldState = this.getLiveTimeline().getState(EventTimeline.BACKWARDS)!;\n this.currentState = this.getLiveTimeline().getState(EventTimeline.FORWARDS)!;\n\n // Let people know to register new listeners for the new state\n // references. The reference won't necessarily change every time so only\n // emit when we see a change.\n if (previousOldState !== this.oldState) {\n this.emit(RoomEvent.OldStateUpdated, this, previousOldState, this.oldState);\n }\n\n if (previousCurrentState !== this.currentState) {\n this.emit(RoomEvent.CurrentStateUpdated, this, previousCurrentState, this.currentState);\n\n // Re-emit various events on the current room state\n // TODO: If currentState really only exists for backwards\n // compatibility, shouldn't we be doing this some other way?\n this.reEmitter.stopReEmitting(previousCurrentState, [\n RoomStateEvent.Events,\n RoomStateEvent.Members,\n RoomStateEvent.NewMember,\n RoomStateEvent.Update,\n RoomStateEvent.Marker,\n BeaconEvent.New,\n BeaconEvent.Update,\n BeaconEvent.Destroy,\n BeaconEvent.LivenessChange,\n ]);\n this.reEmitter.reEmit(this.currentState, [\n RoomStateEvent.Events,\n RoomStateEvent.Members,\n RoomStateEvent.NewMember,\n RoomStateEvent.Update,\n RoomStateEvent.Marker,\n BeaconEvent.New,\n BeaconEvent.Update,\n BeaconEvent.Destroy,\n BeaconEvent.LivenessChange,\n ]);\n }\n }\n\n /**\n * Returns whether there are any devices in the room that are unverified\n *\n * Note: Callers should first check if crypto is enabled on this device. If it is\n * disabled, then we aren't tracking room devices at all, so we can't answer this, and an\n * error will be thrown.\n *\n * @returns the result\n */\n public async hasUnverifiedDevices(): Promise<boolean> {\n if (!this.client.isRoomEncrypted(this.roomId)) {\n return false;\n }\n const e2eMembers = await this.getEncryptionTargetMembers();\n for (const member of e2eMembers) {\n const devices = this.client.getStoredDevicesForUser(member.userId);\n if (devices.some((device) => device.isUnverified())) {\n return true;\n }\n }\n return false;\n }\n\n /**\n * Return the timeline sets for this room.\n * @returns array of timeline sets for this room\n */\n public getTimelineSets(): EventTimelineSet[] {\n return this.timelineSets;\n }\n\n /**\n * Helper to return the main unfiltered timeline set for this room\n * @returns room's unfiltered timeline set\n */\n public getUnfilteredTimelineSet(): EventTimelineSet {\n return this.timelineSets[0];\n }\n\n /**\n * Get the timeline which contains the given event from the unfiltered set, if any\n *\n * @param eventId - event ID to look for\n * @returns timeline containing\n * the given event, or null if unknown\n */\n public getTimelineForEvent(eventId: string): EventTimeline | null {\n const event = this.findEventById(eventId);\n const thread = this.findThreadForEvent(event);\n if (thread) {\n return thread.timelineSet.getTimelineForEvent(eventId);\n } else {\n return this.getUnfilteredTimelineSet().getTimelineForEvent(eventId);\n }\n }\n\n /**\n * Add a new timeline to this room's unfiltered timeline set\n *\n * @returns newly-created timeline\n */\n public addTimeline(): EventTimeline {\n return this.getUnfilteredTimelineSet().addTimeline();\n }\n\n /**\n * Whether the timeline needs to be refreshed in order to pull in new\n * historical messages that were imported.\n * @param value - The value to set\n */\n public setTimelineNeedsRefresh(value: boolean): void {\n this.timelineNeedsRefresh = value;\n }\n\n /**\n * Whether the timeline needs to be refreshed in order to pull in new\n * historical messages that were imported.\n * @returns .\n */\n public getTimelineNeedsRefresh(): boolean {\n return this.timelineNeedsRefresh;\n }\n\n /**\n * Get an event which is stored in our unfiltered timeline set, or in a thread\n *\n * @param eventId - event ID to look for\n * @returns the given event, or undefined if unknown\n */\n public findEventById(eventId: string): MatrixEvent | undefined {\n let event = this.getUnfilteredTimelineSet().findEventById(eventId);\n\n if (!event) {\n const threads = this.getThreads();\n for (let i = 0; i < threads.length; i++) {\n const thread = threads[i];\n event = thread.findEventById(eventId);\n if (event) {\n return event;\n }\n }\n }\n\n return event;\n }\n\n /**\n * Get one of the notification counts for this room\n * @param type - The type of notification count to get. default: 'total'\n * @returns The notification count, or undefined if there is no count\n * for this type.\n */\n public getUnreadNotificationCount(type = NotificationCountType.Total): number {\n let count = this.getRoomUnreadNotificationCount(type);\n for (const threadNotification of this.threadNotifications.values()) {\n count += threadNotification[type] ?? 0;\n }\n return count;\n }\n\n /**\n * Get the notification for the event context (room or thread timeline)\n */\n public getUnreadCountForEventContext(type = NotificationCountType.Total, event: MatrixEvent): number {\n const isThreadEvent = !!event.threadRootId && !event.isThreadRoot;\n\n return (\n (isThreadEvent\n ? this.getThreadUnreadNotificationCount(event.threadRootId, type)\n : this.getRoomUnreadNotificationCount(type)) ?? 0\n );\n }\n\n /**\n * Get one of the notification counts for this room\n * @param type - The type of notification count to get. default: 'total'\n * @returns The notification count, or undefined if there is no count\n * for this type.\n */\n public getRoomUnreadNotificationCount(type = NotificationCountType.Total): number {\n return this.notificationCounts[type] ?? 0;\n }\n\n /**\n * Get one of the notification counts for a thread\n * @param threadId - the root event ID\n * @param type - The type of notification count to get. default: 'total'\n * @returns The notification count, or undefined if there is no count\n * for this type.\n */\n public getThreadUnreadNotificationCount(threadId: string, type = NotificationCountType.Total): number {\n return this.threadNotifications.get(threadId)?.[type] ?? 0;\n }\n\n /**\n * Checks if the current room has unread thread notifications\n * @returns\n */\n public hasThreadUnreadNotification(): boolean {\n for (const notification of this.threadNotifications.values()) {\n if ((notification.highlight ?? 0) > 0 || (notification.total ?? 0) > 0) {\n return true;\n }\n }\n return false;\n }\n\n /**\n * Swet one of the notification count for a thread\n * @param threadId - the root event ID\n * @param type - The type of notification count to get. default: 'total'\n * @returns\n */\n public setThreadUnreadNotificationCount(threadId: string, type: NotificationCountType, count: number): void {\n const notification: NotificationCount = {\n highlight: this.threadNotifications.get(threadId)?.highlight,\n total: this.threadNotifications.get(threadId)?.total,\n ...{\n [type]: count,\n },\n };\n\n this.threadNotifications.set(threadId, notification);\n\n this.emit(RoomEvent.UnreadNotifications, notification, threadId);\n }\n\n /**\n * @returns the notification count type for all the threads in the room\n */\n public get threadsAggregateNotificationType(): NotificationCountType | null {\n let type: NotificationCountType | null = null;\n for (const threadNotification of this.threadNotifications.values()) {\n if ((threadNotification.highlight ?? 0) > 0) {\n return NotificationCountType.Highlight;\n } else if ((threadNotification.total ?? 0) > 0 && !type) {\n type = NotificationCountType.Total;\n }\n }\n return type;\n }\n\n /**\n * Resets the thread notifications for this room\n */\n public resetThreadUnreadNotificationCount(notificationsToKeep?: string[]): void {\n if (notificationsToKeep) {\n for (const [threadId] of this.threadNotifications) {\n if (!notificationsToKeep.includes(threadId)) {\n this.threadNotifications.delete(threadId);\n }\n }\n } else {\n this.threadNotifications.clear();\n }\n this.emit(RoomEvent.UnreadNotifications);\n }\n\n /**\n * Set one of the notification counts for this room\n * @param type - The type of notification count to set.\n * @param count - The new count\n */\n public setUnreadNotificationCount(type: NotificationCountType, count: number): void {\n this.notificationCounts[type] = count;\n this.emit(RoomEvent.UnreadNotifications, this.notificationCounts);\n }\n\n public setUnread(type: NotificationCountType, count: number): void {\n return this.setUnreadNotificationCount(type, count);\n }\n\n public setSummary(summary: IRoomSummary): void {\n const heroes = summary[\"m.heroes\"];\n const joinedCount = summary[\"m.joined_member_count\"];\n const invitedCount = summary[\"m.invited_member_count\"];\n if (Number.isInteger(joinedCount)) {\n this.currentState.setJoinedMemberCount(joinedCount!);\n }\n if (Number.isInteger(invitedCount)) {\n this.currentState.setInvitedMemberCount(invitedCount!);\n }\n if (Array.isArray(heroes)) {\n // be cautious about trusting server values,\n // and make sure heroes doesn't contain our own id\n // just to be sure\n this.summaryHeroes = heroes.filter((userId) => {\n return userId !== this.myUserId;\n });\n }\n }\n\n /**\n * Whether to send encrypted messages to devices within this room.\n * @param value - true to blacklist unverified devices, null\n * to use the global value for this room.\n */\n public setBlacklistUnverifiedDevices(value: boolean): void {\n this.blacklistUnverifiedDevices = value;\n }\n\n /**\n * Whether to send encrypted messages to devices within this room.\n * @returns true if blacklisting unverified devices, null\n * if the global value should be used for this room.\n */\n public getBlacklistUnverifiedDevices(): boolean | null {\n if (this.blacklistUnverifiedDevices === undefined) return null;\n return this.blacklistUnverifiedDevices;\n }\n\n /**\n * Get the avatar URL for a room if one was set.\n * @param baseUrl - The homeserver base URL. See\n * {@link MatrixClient#getHomeserverUrl}.\n * @param width - The desired width of the thumbnail.\n * @param height - The desired height of the thumbnail.\n * @param resizeMethod - The thumbnail resize method to use, either\n * \"crop\" or \"scale\".\n * @param allowDefault - True to allow an identicon for this room if an\n * avatar URL wasn't explicitly set. Default: true. (Deprecated)\n * @returns the avatar URL or null.\n */\n public getAvatarUrl(\n baseUrl: string,\n width: number,\n height: number,\n resizeMethod: ResizeMethod,\n allowDefault = true,\n ): string | null {\n const roomAvatarEvent = this.currentState.getStateEvents(EventType.RoomAvatar, \"\");\n if (!roomAvatarEvent && !allowDefault) {\n return null;\n }\n\n const mainUrl = roomAvatarEvent ? roomAvatarEvent.getContent().url : null;\n if (mainUrl) {\n return getHttpUriForMxc(baseUrl, mainUrl, width, height, resizeMethod);\n }\n\n return null;\n }\n\n /**\n * Get the mxc avatar url for the room, if one was set.\n * @returns the mxc avatar url or falsy\n */\n public getMxcAvatarUrl(): string | null {\n return this.currentState.getStateEvents(EventType.RoomAvatar, \"\")?.getContent()?.url || null;\n }\n\n /**\n * Get this room's canonical alias\n * The alias returned by this function may not necessarily\n * still point to this room.\n * @returns The room's canonical alias, or null if there is none\n */\n public getCanonicalAlias(): string | null {\n const canonicalAlias = this.currentState.getStateEvents(EventType.RoomCanonicalAlias, \"\");\n if (canonicalAlias) {\n return canonicalAlias.getContent().alias || null;\n }\n return null;\n }\n\n /**\n * Get this room's alternative aliases\n * @returns The room's alternative aliases, or an empty array\n */\n public getAltAliases(): string[] {\n const canonicalAlias = this.currentState.getStateEvents(EventType.RoomCanonicalAlias, \"\");\n if (canonicalAlias) {\n return canonicalAlias.getContent().alt_aliases || [];\n }\n return [];\n }\n\n /**\n * Add events to a timeline\n *\n * <p>Will fire \"Room.timeline\" for each event added.\n *\n * @param events - A list of events to add.\n *\n * @param toStartOfTimeline - True to add these events to the start\n * (oldest) instead of the end (newest) of the timeline. If true, the oldest\n * event will be the <b>last</b> element of 'events'.\n *\n * @param timeline - timeline to\n * add events to.\n *\n * @param paginationToken - token for the next batch of events\n *\n * @remarks\n * Fires {@link RoomEvent.Timeline}\n */\n public addEventsToTimeline(\n events: MatrixEvent[],\n toStartOfTimeline: boolean,\n timeline: EventTimeline,\n paginationToken?: string,\n ): void {\n timeline.getTimelineSet().addEventsToTimeline(events, toStartOfTimeline, timeline, paginationToken);\n }\n\n /**\n * Get the instance of the thread associated with the current event\n * @param eventId - the ID of the current event\n * @returns a thread instance if known\n */\n public getThread(eventId: string): Thread | null {\n return this.threads.get(eventId) ?? null;\n }\n\n /**\n * Get all the known threads in the room\n */\n public getThreads(): Thread[] {\n return Array.from(this.threads.values());\n }\n\n /**\n * Get a member from the current room state.\n * @param userId - The user ID of the member.\n * @returns The member or `null`.\n */\n public getMember(userId: string): RoomMember | null {\n return this.currentState.getMember(userId);\n }\n\n /**\n * Get all currently loaded members from the current\n * room state.\n * @returns Room members\n */\n public getMembers(): RoomMember[] {\n return this.currentState.getMembers();\n }\n\n /**\n * Get a list of members whose membership state is \"join\".\n * @returns A list of currently joined members.\n */\n public getJoinedMembers(): RoomMember[] {\n return this.getMembersWithMembership(\"join\");\n }\n\n /**\n * Returns the number of joined members in this room\n * This method caches the result.\n * This is a wrapper around the method of the same name in roomState, returning\n * its result for the room's current state.\n * @returns The number of members in this room whose membership is 'join'\n */\n public getJoinedMemberCount(): number {\n return this.currentState.getJoinedMemberCount();\n }\n\n /**\n * Returns the number of invited members in this room\n * @returns The number of members in this room whose membership is 'invite'\n */\n public getInvitedMemberCount(): number {\n return this.currentState.getInvitedMemberCount();\n }\n\n /**\n * Returns the number of invited + joined members in this room\n * @returns The number of members in this room whose membership is 'invite' or 'join'\n */\n public getInvitedAndJoinedMemberCount(): number {\n return this.getInvitedMemberCount() + this.getJoinedMemberCount();\n }\n\n /**\n * Get a list of members with given membership state.\n * @param membership - The membership state.\n * @returns A list of members with the given membership state.\n */\n public getMembersWithMembership(membership: string): RoomMember[] {\n return this.currentState.getMembers().filter(function (m) {\n return m.membership === membership;\n });\n }\n\n /**\n * Get a list of members we should be encrypting for in this room\n * @returns A list of members who\n * we should encrypt messages for in this room.\n */\n public async getEncryptionTargetMembers(): Promise<RoomMember[]> {\n await this.loadMembersIfNeeded();\n let members = this.getMembersWithMembership(\"join\");\n if (this.shouldEncryptForInvitedMembers()) {\n members = members.concat(this.getMembersWithMembership(\"invite\"));\n }\n return members;\n }\n\n /**\n * Determine whether we should encrypt messages for invited users in this room\n * @returns if we should encrypt messages for invited users\n */\n public shouldEncryptForInvitedMembers(): boolean {\n const ev = this.currentState.getStateEvents(EventType.RoomHistoryVisibility, \"\");\n return ev?.getContent()?.history_visibility !== \"joined\";\n }\n\n /**\n * Get the default room name (i.e. what a given user would see if the\n * room had no m.room.name)\n * @param userId - The userId from whose perspective we want\n * to calculate the default name\n * @returns The default room name\n */\n public getDefaultRoomName(userId: string): string {\n return this.calculateRoomName(userId, true);\n }\n\n /**\n * Check if the given user_id has the given membership state.\n * @param userId - The user ID to check.\n * @param membership - The membership e.g. `'join'`\n * @returns True if this user_id has the given membership state.\n */\n public hasMembershipState(userId: string, membership: string): boolean {\n const member = this.getMember(userId);\n if (!member) {\n return false;\n }\n return member.membership === membership;\n }\n\n /**\n * Add a timelineSet for this room with the given filter\n * @param filter - The filter to be applied to this timelineSet\n * @param opts - Configuration options\n * @returns The timelineSet\n */\n public getOrCreateFilteredTimelineSet(\n filter: Filter,\n { prepopulateTimeline = true, useSyncEvents = true, pendingEvents = true }: ICreateFilterOpts = {},\n ): EventTimelineSet {\n if (this.filteredTimelineSets[filter.filterId!]) {\n return this.filteredTimelineSets[filter.filterId!];\n }\n const opts = Object.assign({ filter, pendingEvents }, this.opts);\n const timelineSet = new EventTimelineSet(this, opts);\n this.reEmitter.reEmit(timelineSet, [RoomEvent.Timeline, RoomEvent.TimelineReset]);\n if (useSyncEvents) {\n this.filteredTimelineSets[filter.filterId!] = timelineSet;\n this.timelineSets.push(timelineSet);\n }\n\n const unfilteredLiveTimeline = this.getLiveTimeline();\n // Not all filter are possible to replicate client-side only\n // When that's the case we do not want to prepopulate from the live timeline\n // as we would get incorrect results compared to what the server would send back\n if (prepopulateTimeline) {\n // populate up the new timelineSet with filtered events from our live\n // unfiltered timeline.\n //\n // XXX: This is risky as our timeline\n // may have grown huge and so take a long time to filter.\n // see https://github.com/vector-im/vector-web/issues/2109\n\n unfilteredLiveTimeline.getEvents().forEach(function (event) {\n timelineSet.addLiveEvent(event);\n });\n\n // find the earliest unfiltered timeline\n let timeline = unfilteredLiveTimeline;\n while (timeline.getNeighbouringTimeline(EventTimeline.BACKWARDS)) {\n timeline = timeline.getNeighbouringTimeline(EventTimeline.BACKWARDS)!;\n }\n\n timelineSet\n .getLiveTimeline()\n .setPaginationToken(timeline.getPaginationToken(EventTimeline.BACKWARDS), EventTimeline.BACKWARDS);\n } else if (useSyncEvents) {\n const livePaginationToken = unfilteredLiveTimeline.getPaginationToken(Direction.Forward);\n timelineSet.getLiveTimeline().setPaginationToken(livePaginationToken, Direction.Backward);\n }\n\n // alternatively, we could try to do something like this to try and re-paginate\n // in the filtered events from nothing, but Mark says it's an abuse of the API\n // to do so:\n //\n // timelineSet.resetLiveTimeline(\n // unfilteredLiveTimeline.getPaginationToken(EventTimeline.FORWARDS)\n // );\n\n return timelineSet;\n }\n\n private async getThreadListFilter(filterType = ThreadFilterType.All): Promise<Filter> {\n const myUserId = this.client.getUserId()!;\n const filter = new Filter(myUserId);\n\n const definition: IFilterDefinition = {\n room: {\n timeline: {\n [FILTER_RELATED_BY_REL_TYPES.name]: [THREAD_RELATION_TYPE.name],\n },\n },\n };\n\n if (filterType === ThreadFilterType.My) {\n definition!.room!.timeline![FILTER_RELATED_BY_SENDERS.name] = [myUserId];\n }\n\n filter.setDefinition(definition);\n const filterId = await this.client.getOrCreateFilter(`THREAD_PANEL_${this.roomId}_${filterType}`, filter);\n\n filter.filterId = filterId;\n\n return filter;\n }\n\n private async createThreadTimelineSet(filterType?: ThreadFilterType): Promise<EventTimelineSet> {\n let timelineSet: EventTimelineSet;\n if (Thread.hasServerSideListSupport) {\n timelineSet = new EventTimelineSet(\n this,\n {\n ...this.opts,\n pendingEvents: false,\n },\n undefined,\n undefined,\n filterType ?? ThreadFilterType.All,\n );\n this.reEmitter.reEmit(timelineSet, [RoomEvent.Timeline, RoomEvent.TimelineReset]);\n } else if (Thread.hasServerSideSupport) {\n const filter = await this.getThreadListFilter(filterType);\n\n timelineSet = this.getOrCreateFilteredTimelineSet(filter, {\n prepopulateTimeline: false,\n useSyncEvents: false,\n pendingEvents: false,\n });\n } else {\n timelineSet = new EventTimelineSet(this, {\n pendingEvents: false,\n });\n\n Array.from(this.threads).forEach(([, thread]) => {\n if (thread.length === 0) return;\n const currentUserParticipated = thread.timeline.some((event) => {\n return event.getSender() === this.client.getUserId();\n });\n if (filterType !== ThreadFilterType.My || currentUserParticipated) {\n timelineSet.getLiveTimeline().addEvent(thread.rootEvent!, {\n toStartOfTimeline: false,\n });\n }\n });\n }\n\n return timelineSet;\n }\n\n private threadsReady = false;\n\n /**\n * Takes the given thread root events and creates threads for them.\n */\n public processThreadRoots(events: MatrixEvent[], toStartOfTimeline: boolean): void {\n for (const rootEvent of events) {\n EventTimeline.setEventMetadata(rootEvent, this.currentState, toStartOfTimeline);\n if (!this.getThread(rootEvent.getId()!)) {\n this.createThread(rootEvent.getId()!, rootEvent, [], toStartOfTimeline);\n }\n }\n }\n\n /**\n * Fetch the bare minimum of room threads required for the thread list to work reliably.\n * With server support that means fetching one page.\n * Without server support that means fetching as much at once as the server allows us to.\n */\n public async fetchRoomThreads(): Promise<void> {\n if (this.threadsReady || !this.client.supportsThreads()) {\n return;\n }\n\n if (Thread.hasServerSideListSupport) {\n await Promise.all([\n this.fetchRoomThreadList(ThreadFilterType.All),\n this.fetchRoomThreadList(ThreadFilterType.My),\n ]);\n } else {\n const allThreadsFilter = await this.getThreadListFilter();\n\n const { chunk: events } = await this.client.createMessagesRequest(\n this.roomId,\n \"\",\n Number.MAX_SAFE_INTEGER,\n Direction.Backward,\n allThreadsFilter,\n );\n\n if (!events.length) return;\n\n // Sorted by last_reply origin_server_ts\n const threadRoots = events.map(this.client.getEventMapper()).sort((eventA, eventB) => {\n /**\n * `origin_server_ts` in a decentralised world is far from ideal\n * but for lack of any better, we will have to use this\n * Long term the sorting should be handled by homeservers and this\n * is only meant as a short term patch\n */\n const threadAMetadata = eventA.getServerAggregatedRelation<IThreadBundledRelationship>(\n THREAD_RELATION_TYPE.name,\n )!;\n const threadBMetadata = eventB.getServerAggregatedRelation<IThreadBundledRelationship>(\n THREAD_RELATION_TYPE.name,\n )!;\n return threadAMetadata.latest_event.origin_server_ts - threadBMetadata.latest_event.origin_server_ts;\n });\n\n let latestMyThreadsRootEvent: MatrixEvent | undefined;\n const roomState = this.getLiveTimeline().getState(EventTimeline.FORWARDS);\n for (const rootEvent of threadRoots) {\n const opts = {\n duplicateStrategy: DuplicateStrategy.Ignore,\n fromCache: false,\n roomState,\n };\n this.threadsTimelineSets[0]?.addLiveEvent(rootEvent, opts);\n\n const threadRelationship = rootEvent.getServerAggregatedRelation<IThreadBundledRelationship>(\n THREAD_RELATION_TYPE.name,\n );\n if (threadRelationship?.current_user_participated) {\n this.threadsTimelineSets[1]?.addLiveEvent(rootEvent, opts);\n latestMyThreadsRootEvent = rootEvent;\n }\n }\n\n this.processThreadRoots(threadRoots, true);\n\n this.client.decryptEventIfNeeded(threadRoots[threadRoots.length - 1]);\n if (latestMyThreadsRootEvent) {\n this.client.decryptEventIfNeeded(latestMyThreadsRootEvent);\n }\n }\n\n this.on(ThreadEvent.NewReply, this.onThreadNewReply);\n this.on(ThreadEvent.Delete, this.onThreadDelete);\n this.threadsReady = true;\n }\n\n public async processPollEvents(events: MatrixEvent[]): Promise<void> {\n const processPollStartEvent = (event: MatrixEvent): void => {\n if (!M_POLL_START.matches(event.getType())) return;\n try {\n const poll = new Poll(event, this.client, this);\n this.polls.set(event.getId()!, poll);\n this.emit(PollEvent.New, poll);\n } catch {}\n // poll creation can fail for malformed poll start events\n };\n\n const processPollRelationEvent = (event: MatrixEvent): void => {\n const relationEventId = event.relationEventId;\n if (relationEventId && this.polls.has(relationEventId)) {\n const poll = this.polls.get(relationEventId);\n poll?.onNewRelation(event);\n }\n };\n\n const processPollEvent = (event: MatrixEvent): void => {\n processPollStartEvent(event);\n processPollRelationEvent(event);\n };\n\n for (const event of events) {\n try {\n await this.client.decryptEventIfNeeded(event);\n processPollEvent(event);\n } catch {}\n }\n }\n\n /**\n * Fetch a single page of threadlist messages for the specific thread filter\n * @internal\n */\n private async fetchRoomThreadList(filter?: ThreadFilterType): Promise<void> {\n const timelineSet = filter === ThreadFilterType.My ? this.threadsTimelineSets[1] : this.threadsTimelineSets[0];\n\n const { chunk: events, end } = await this.client.createThreadListMessagesRequest(\n this.roomId,\n null,\n undefined,\n Direction.Backward,\n timelineSet.threadListType,\n timelineSet.getFilter(),\n );\n\n timelineSet.getLiveTimeline().setPaginationToken(end ?? null, Direction.Backward);\n\n if (!events.length) return;\n\n const matrixEvents = events.map(this.client.getEventMapper());\n this.processThreadRoots(matrixEvents, true);\n const roomState = this.getLiveTimeline().getState(EventTimeline.FORWARDS);\n for (const rootEvent of matrixEvents) {\n timelineSet.addLiveEvent(rootEvent, {\n duplicateStrategy: DuplicateStrategy.Replace,\n fromCache: false,\n roomState,\n });\n }\n }\n\n private onThreadNewReply(thread: Thread): void {\n this.updateThreadRootEvents(thread, false, true);\n }\n\n private onThreadDelete(thread: Thread): void {\n this.threads.delete(thread.id);\n\n const timeline = this.getTimelineForEvent(thread.id);\n const roomEvent = timeline?.getEvents()?.find((it) => it.getId() === thread.id);\n if (roomEvent) {\n thread.clearEventMetadata(roomEvent);\n } else {\n logger.debug(\"onThreadDelete: Could not find root event in room timeline\");\n }\n for (const timelineSet of this.threadsTimelineSets) {\n timelineSet.removeEvent(thread.id);\n }\n }\n\n /**\n * Forget the timelineSet for this room with the given filter\n *\n * @param filter - the filter whose timelineSet is to be forgotten\n */\n public removeFilteredTimelineSet(filter: Filter): void {\n const timelineSet = this.filteredTimelineSets[filter.filterId!];\n delete this.filteredTimelineSets[filter.filterId!];\n const i = this.timelineSets.indexOf(timelineSet);\n if (i > -1) {\n this.timelineSets.splice(i, 1);\n }\n }\n\n public eventShouldLiveIn(\n event: MatrixEvent,\n events?: MatrixEvent[],\n roots?: Set<string>,\n ): {\n shouldLiveInRoom: boolean;\n shouldLiveInThread: boolean;\n threadId?: string;\n } {\n if (!this.client?.supportsThreads()) {\n return {\n shouldLiveInRoom: true,\n shouldLiveInThread: false,\n };\n }\n\n // A thread root is always shown in both timelines\n if (event.isThreadRoot || roots?.has(event.getId()!)) {\n return {\n shouldLiveInRoom: true,\n shouldLiveInThread: true,\n threadId: event.getId(),\n };\n }\n\n // A thread relation is always only shown in a thread\n if (event.isRelation(THREAD_RELATION_TYPE.name)) {\n return {\n shouldLiveInRoom: false,\n shouldLiveInThread: true,\n threadId: event.threadRootId,\n };\n }\n\n const parentEventId = event.getAssociatedId();\n let parentEvent: MatrixEvent | undefined;\n if (parentEventId) {\n parentEvent = this.findEventById(parentEventId) ?? events?.find((e) => e.getId() === parentEventId);\n }\n\n // Treat relations and redactions as extensions of their parents so evaluate parentEvent instead\n if (parentEvent && (event.isRelation() || event.isRedaction())) {\n return this.eventShouldLiveIn(parentEvent, events, roots);\n }\n\n // Edge case where we know the event is a relation but don't have the parentEvent\n if (roots?.has(event.relationEventId!)) {\n return {\n shouldLiveInRoom: true,\n shouldLiveInThread: true,\n threadId: event.relationEventId,\n };\n }\n\n // We've exhausted all scenarios, can safely assume that this event should live in the room timeline only\n return {\n shouldLiveInRoom: true,\n shouldLiveInThread: false,\n };\n }\n\n public findThreadForEvent(event?: MatrixEvent): Thread | null {\n if (!event) return null;\n\n const { threadId } = this.eventShouldLiveIn(event);\n return threadId ? this.getThread(threadId) : null;\n }\n\n private addThreadedEvents(threadId: string, events: MatrixEvent[], toStartOfTimeline = false): void {\n let thread = this.getThread(threadId);\n\n if (!thread) {\n const rootEvent = this.findEventById(threadId) ?? events.find((e) => e.getId() === threadId);\n thread = this.createThread(threadId, rootEvent, events, toStartOfTimeline);\n }\n\n thread.addEvents(events, toStartOfTimeline);\n }\n\n /**\n * Adds events to a thread's timeline. Will fire \"Thread.update\"\n */\n public processThreadedEvents(events: MatrixEvent[], toStartOfTimeline: boolean): void {\n events.forEach(this.applyRedaction);\n\n const eventsByThread: { [threadId: string]: MatrixEvent[] } = {};\n for (const event of events) {\n const { threadId, shouldLiveInThread } = this.eventShouldLiveIn(event);\n if (shouldLiveInThread && !eventsByThread[threadId!]) {\n eventsByThread[threadId!] = [];\n }\n eventsByThread[threadId!]?.push(event);\n }\n\n Object.entries(eventsByThread).map(([threadId, threadEvents]) =>\n this.addThreadedEvents(threadId, threadEvents, toStartOfTimeline),\n );\n }\n\n private updateThreadRootEvents = (thread: Thread, toStartOfTimeline: boolean, recreateEvent: boolean): void => {\n if (thread.length) {\n this.updateThreadRootEvent(this.threadsTimelineSets?.[0], thread, toStartOfTimeline, recreateEvent);\n if (thread.hasCurrentUserParticipated) {\n this.updateThreadRootEvent(this.threadsTimelineSets?.[1], thread, toStartOfTimeline, recreateEvent);\n }\n }\n };\n\n private updateThreadRootEvent = (\n timelineSet: Optional<EventTimelineSet>,\n thread: Thread,\n toStartOfTimeline: boolean,\n recreateEvent: boolean,\n ): void => {\n if (timelineSet && thread.rootEvent) {\n if (recreateEvent) {\n timelineSet.removeEvent(thread.id);\n }\n if (Thread.hasServerSideSupport) {\n timelineSet.addLiveEvent(thread.rootEvent, {\n duplicateStrategy: DuplicateStrategy.Replace,\n fromCache: false,\n roomState: this.currentState,\n });\n } else {\n timelineSet.addEventToTimeline(thread.rootEvent, timelineSet.getLiveTimeline(), { toStartOfTimeline });\n }\n }\n };\n\n public createThread(\n threadId: string,\n rootEvent: MatrixEvent | undefined,\n events: MatrixEvent[] = [],\n toStartOfTimeline: boolean,\n ): Thread {\n if (this.threads.has(threadId)) {\n return this.threads.get(threadId)!;\n }\n\n if (rootEvent) {\n const relatedEvents = this.relations.getAllChildEventsForEvent(rootEvent.getId()!);\n if (relatedEvents?.length) {\n // Include all relations of the root event, given it'll be visible in both timelines,\n // except `m.replace` as that will already be applied atop the event using `MatrixEvent::makeReplaced`\n events = events.concat(relatedEvents.filter((e) => !e.isRelation(RelationType.Replace)));\n }\n }\n\n const thread = new Thread(threadId, rootEvent, {\n room: this,\n client: this.client,\n pendingEventOrdering: this.opts.pendingEventOrdering,\n receipts: this.cachedThreadReadReceipts.get(threadId) ?? [],\n });\n\n // All read receipts should now come down from sync, we do not need to keep\n // a reference to the cached receipts anymore.\n this.cachedThreadReadReceipts.delete(threadId);\n\n // If we managed to create a thread and figure out its `id` then we can use it\n // This has to happen before thread.addEvents, because that adds events to the eventtimeline, and the\n // eventtimeline sometimes looks up thread information via the room.\n this.threads.set(thread.id, thread);\n\n // This is necessary to be able to jump to events in threads:\n // If we jump to an event in a thread where neither the event, nor the root,\n // nor any thread event are loaded yet, we'll load the event as well as the thread root, create the thread,\n // and pass the event through this.\n thread.addEvents(events, false);\n\n this.reEmitter.reEmit(thread, [\n ThreadEvent.Delete,\n ThreadEvent.Update,\n ThreadEvent.NewReply,\n RoomEvent.Timeline,\n RoomEvent.TimelineReset,\n ]);\n const isNewer =\n this.lastThread?.rootEvent &&\n rootEvent?.localTimestamp &&\n this.lastThread.rootEvent?.localTimestamp < rootEvent?.localTimestamp;\n\n if (!this.lastThread || isNewer) {\n this.lastThread = thread;\n }\n\n if (this.threadsReady) {\n this.updateThreadRootEvents(thread, toStartOfTimeline, false);\n }\n this.emit(ThreadEvent.New, thread, toStartOfTimeline);\n\n return thread;\n }\n\n private applyRedaction = (event: MatrixEvent): void => {\n if (event.isRedaction()) {\n const redactId = event.event.redacts;\n\n // if we know about this event, redact its contents now.\n const redactedEvent = redactId ? this.findEventById(redactId) : undefined;\n if (redactedEvent) {\n redactedEvent.makeRedacted(event);\n\n // If this is in the current state, replace it with the redacted version\n if (redactedEvent.isState()) {\n const currentStateEvent = this.currentState.getStateEvents(\n redactedEvent.getType(),\n redactedEvent.getStateKey()!,\n );\n if (currentStateEvent?.getId() === redactedEvent.getId()) {\n this.currentState.setStateEvents([redactedEvent]);\n }\n }\n\n this.emit(RoomEvent.Redaction, event, this);\n\n // TODO: we stash user displaynames (among other things) in\n // RoomMember objects which are then attached to other events\n // (in the sender and target fields). We should get those\n // RoomMember objects to update themselves when the events that\n // they are based on are changed.\n\n // Remove any visibility change on this event.\n this.visibilityEvents.delete(redactId!);\n\n // If this event is a visibility change event, remove it from the\n // list of visibility changes and update any event affected by it.\n if (redactedEvent.isVisibilityEvent()) {\n this.redactVisibilityChangeEvent(event);\n }\n }\n\n // FIXME: apply redactions to notification list\n\n // NB: We continue to add the redaction event to the timeline so\n // clients can say \"so and so redacted an event\" if they wish to. Also\n // this may be needed to trigger an update.\n }\n };\n\n private processLiveEvent(event: MatrixEvent): void {\n this.applyRedaction(event);\n\n // Implement MSC3531: hiding messages.\n if (event.isVisibilityEvent()) {\n // This event changes the visibility of another event, record\n // the visibility change, inform clients if necessary.\n this.applyNewVisibilityEvent(event);\n }\n // If any pending visibility change is waiting for this (older) event,\n this.applyPendingVisibilityEvents(event);\n\n // Sliding Sync modifications:\n // The proxy cannot guarantee every sent event will have a transaction_id field, so we need\n // to check the event ID against the list of pending events if there is no transaction ID\n // field. Only do this for events sent by us though as it's potentially expensive to loop\n // the pending events map.\n const txnId = event.getUnsigned().transaction_id;\n if (!txnId && event.getSender() === this.myUserId) {\n // check the txn map for a matching event ID\n for (const [tid, localEvent] of this.txnToEvent) {\n if (localEvent.getId() === event.getId()) {\n logger.debug(\"processLiveEvent: found sent event without txn ID: \", tid, event.getId());\n // update the unsigned field so we can re-use the same codepaths\n const unsigned = event.getUnsigned();\n unsigned.transaction_id = tid;\n event.setUnsigned(unsigned);\n break;\n }\n }\n }\n }\n\n /**\n * Add an event to the end of this room's live timelines. Will fire\n * \"Room.timeline\".\n *\n * @param event - Event to be added\n * @param addLiveEventOptions - addLiveEvent options\n * @internal\n *\n * @remarks\n * Fires {@link RoomEvent.Timeline}\n */\n private addLiveEvent(event: MatrixEvent, addLiveEventOptions: IAddLiveEventOptions): void {\n const { duplicateStrategy, timelineWasEmpty, fromCache } = addLiveEventOptions;\n\n // add to our timeline sets\n for (const timelineSet of this.timelineSets) {\n timelineSet.addLiveEvent(event, {\n duplicateStrategy,\n fromCache,\n timelineWasEmpty,\n });\n }\n\n // synthesize and inject implicit read receipts\n // Done after adding the event because otherwise the app would get a read receipt\n // pointing to an event that wasn't yet in the timeline\n // Don't synthesize RR for m.room.redaction as this causes the RR to go missing.\n if (event.sender && event.getType() !== EventType.RoomRedaction) {\n this.addReceipt(synthesizeReceipt(event.sender.userId, event, ReceiptType.Read), true);\n\n // Any live events from a user could be taken as implicit\n // presence information: evidence that they are currently active.\n // ...except in a world where we use 'user.currentlyActive' to reduce\n // presence spam, this isn't very useful - we'll get a transition when\n // they are no longer currently active anyway. So don't bother to\n // reset the lastActiveAgo and lastPresenceTs from the RoomState's user.\n }\n }\n\n /**\n * Add a pending outgoing event to this room.\n *\n * <p>The event is added to either the pendingEventList, or the live timeline,\n * depending on the setting of opts.pendingEventOrdering.\n *\n * <p>This is an internal method, intended for use by MatrixClient.\n *\n * @param event - The event to add.\n *\n * @param txnId - Transaction id for this outgoing event\n *\n * @throws if the event doesn't have status SENDING, or we aren't given a\n * unique transaction id.\n *\n * @remarks\n * Fires {@link RoomEvent.LocalEchoUpdated}\n */\n public addPendingEvent(event: MatrixEvent, txnId: string): void {\n if (event.status !== EventStatus.SENDING && event.status !== EventStatus.NOT_SENT) {\n throw new Error(\"addPendingEvent called on an event with status \" + event.status);\n }\n\n if (this.txnToEvent.get(txnId)) {\n throw new Error(\"addPendingEvent called on an event with known txnId \" + txnId);\n }\n\n // call setEventMetadata to set up event.sender etc\n // as event is shared over all timelineSets, we set up its metadata based\n // on the unfiltered timelineSet.\n EventTimeline.setEventMetadata(event, this.getLiveTimeline().getState(EventTimeline.FORWARDS)!, false);\n\n this.txnToEvent.set(txnId, event);\n if (this.pendingEventList) {\n if (this.pendingEventList.some((e) => e.status === EventStatus.NOT_SENT)) {\n logger.warn(\"Setting event as NOT_SENT due to messages in the same state\");\n event.setStatus(EventStatus.NOT_SENT);\n }\n this.pendingEventList.push(event);\n this.savePendingEvents();\n if (event.isRelation()) {\n // For pending events, add them to the relations collection immediately.\n // (The alternate case below already covers this as part of adding to\n // the timeline set.)\n this.aggregateNonLiveRelation(event);\n }\n\n if (event.isRedaction()) {\n const redactId = event.event.redacts;\n let redactedEvent = this.pendingEventList.find((e) => e.getId() === redactId);\n if (!redactedEvent && redactId) {\n redactedEvent = this.findEventById(redactId);\n }\n if (redactedEvent) {\n redactedEvent.markLocallyRedacted(event);\n this.emit(RoomEvent.Redaction, event, this);\n }\n }\n } else {\n for (const timelineSet of this.timelineSets) {\n if (timelineSet.getFilter()) {\n if (timelineSet.getFilter()!.filterRoomTimeline([event]).length) {\n timelineSet.addEventToTimeline(event, timelineSet.getLiveTimeline(), {\n toStartOfTimeline: false,\n });\n }\n } else {\n timelineSet.addEventToTimeline(event, timelineSet.getLiveTimeline(), {\n toStartOfTimeline: false,\n });\n }\n }\n }\n\n this.emit(RoomEvent.LocalEchoUpdated, event, this);\n }\n\n /**\n * Persists all pending events to local storage\n *\n * If the current room is encrypted only encrypted events will be persisted\n * all messages that are not yet encrypted will be discarded\n *\n * This is because the flow of EVENT_STATUS transition is\n * `queued => sending => encrypting => sending => sent`\n *\n * Steps 3 and 4 are skipped for unencrypted room.\n * It is better to discard an unencrypted message rather than persisting\n * it locally for everyone to read\n */\n private savePendingEvents(): void {\n if (this.pendingEventList) {\n const pendingEvents = this.pendingEventList\n .map((event) => {\n return {\n ...event.event,\n txn_id: event.getTxnId(),\n };\n })\n .filter((event) => {\n // Filter out the unencrypted messages if the room is encrypted\n const isEventEncrypted = event.type === EventType.RoomMessageEncrypted;\n const isRoomEncrypted = this.client.isRoomEncrypted(this.roomId);\n return isEventEncrypted || !isRoomEncrypted;\n });\n\n this.client.store.setPendingEvents(this.roomId, pendingEvents);\n }\n }\n\n /**\n * Used to aggregate the local echo for a relation, and also\n * for re-applying a relation after it's redaction has been cancelled,\n * as the local echo for the redaction of the relation would have\n * un-aggregated the relation. Note that this is different from regular messages,\n * which are just kept detached for their local echo.\n *\n * Also note that live events are aggregated in the live EventTimelineSet.\n * @param event - the relation event that needs to be aggregated.\n */\n private aggregateNonLiveRelation(event: MatrixEvent): void {\n this.relations.aggregateChildEvent(event);\n }\n\n public getEventForTxnId(txnId: string): MatrixEvent | undefined {\n return this.txnToEvent.get(txnId);\n }\n\n /**\n * Deal with the echo of a message we sent.\n *\n * <p>We move the event to the live timeline if it isn't there already, and\n * update it.\n *\n * @param remoteEvent - The event received from\n * /sync\n * @param localEvent - The local echo, which\n * should be either in the pendingEventList or the timeline.\n *\n * @internal\n *\n * @remarks\n * Fires {@link RoomEvent.LocalEchoUpdated}\n */\n public handleRemoteEcho(remoteEvent: MatrixEvent, localEvent: MatrixEvent): void {\n const oldEventId = localEvent.getId()!;\n const newEventId = remoteEvent.getId()!;\n const oldStatus = localEvent.status;\n\n logger.debug(`Got remote echo for event ${oldEventId} -> ${newEventId} old status ${oldStatus}`);\n\n // no longer pending\n this.txnToEvent.delete(remoteEvent.getUnsigned().transaction_id!);\n\n // if it's in the pending list, remove it\n if (this.pendingEventList) {\n this.removePendingEvent(oldEventId);\n }\n\n // replace the event source (this will preserve the plaintext payload if\n // any, which is good, because we don't want to try decoding it again).\n localEvent.handleRemoteEcho(remoteEvent.event);\n\n const { shouldLiveInRoom, threadId } = this.eventShouldLiveIn(remoteEvent);\n const thread = threadId ? this.getThread(threadId) : null;\n thread?.setEventMetadata(localEvent);\n thread?.timelineSet.handleRemoteEcho(localEvent, oldEventId, newEventId);\n\n if (shouldLiveInRoom) {\n for (const timelineSet of this.timelineSets) {\n // if it's already in the timeline, update the timeline map. If it's not, add it.\n timelineSet.handleRemoteEcho(localEvent, oldEventId, newEventId);\n }\n }\n\n this.emit(RoomEvent.LocalEchoUpdated, localEvent, this, oldEventId, oldStatus);\n }\n\n /**\n * Update the status / event id on a pending event, to reflect its transmission\n * progress.\n *\n * <p>This is an internal method.\n *\n * @param event - local echo event\n * @param newStatus - status to assign\n * @param newEventId - new event id to assign. Ignored unless newStatus == EventStatus.SENT.\n *\n * @remarks\n * Fires {@link RoomEvent.LocalEchoUpdated}\n */\n public updatePendingEvent(event: MatrixEvent, newStatus: EventStatus, newEventId?: string): void {\n logger.log(\n `setting pendingEvent status to ${newStatus} in ${event.getRoomId()} ` +\n `event ID ${event.getId()} -> ${newEventId}`,\n );\n\n // if the message was sent, we expect an event id\n if (newStatus == EventStatus.SENT && !newEventId) {\n throw new Error(\"updatePendingEvent called with status=SENT, but no new event id\");\n }\n\n // SENT races against /sync, so we have to special-case it.\n if (newStatus == EventStatus.SENT) {\n const timeline = this.getTimelineForEvent(newEventId!);\n if (timeline) {\n // we've already received the event via the event stream.\n // nothing more to do here, assuming the transaction ID was correctly matched.\n // Let's check that.\n const remoteEvent = this.findEventById(newEventId!);\n const remoteTxnId = remoteEvent?.getUnsigned().transaction_id;\n if (!remoteTxnId && remoteEvent) {\n // This code path is mostly relevant for the Sliding Sync proxy.\n // The remote event did not contain a transaction ID, so we did not handle\n // the remote echo yet. Handle it now.\n const unsigned = remoteEvent.getUnsigned();\n unsigned.transaction_id = event.getTxnId();\n remoteEvent.setUnsigned(unsigned);\n // the remote event is _already_ in the timeline, so we need to remove it so\n // we can convert the local event into the final event.\n this.removeEvent(remoteEvent.getId()!);\n this.handleRemoteEcho(remoteEvent, event);\n }\n return;\n }\n }\n\n const oldStatus = event.status;\n const oldEventId = event.getId()!;\n\n if (!oldStatus) {\n throw new Error(\"updatePendingEventStatus called on an event which is not a local echo.\");\n }\n\n const allowed = ALLOWED_TRANSITIONS[oldStatus];\n if (!allowed?.includes(newStatus)) {\n throw new Error(`Invalid EventStatus transition ${oldStatus}->${newStatus}`);\n }\n\n event.setStatus(newStatus);\n\n if (newStatus == EventStatus.SENT) {\n // update the event id\n event.replaceLocalEventId(newEventId!);\n\n const { shouldLiveInRoom, threadId } = this.eventShouldLiveIn(event);\n const thread = threadId ? this.getThread(threadId) : undefined;\n thread?.setEventMetadata(event);\n thread?.timelineSet.replaceEventId(oldEventId, newEventId!);\n\n if (shouldLiveInRoom) {\n // if the event was already in the timeline (which will be the case if\n // opts.pendingEventOrdering==chronological), we need to update the\n // timeline map.\n for (const timelineSet of this.timelineSets) {\n timelineSet.replaceEventId(oldEventId, newEventId!);\n }\n }\n } else if (newStatus == EventStatus.CANCELLED) {\n // remove it from the pending event list, or the timeline.\n if (this.pendingEventList) {\n const removedEvent = this.getPendingEvent(oldEventId);\n this.removePendingEvent(oldEventId);\n if (removedEvent?.isRedaction()) {\n this.revertRedactionLocalEcho(removedEvent);\n }\n }\n this.removeEvent(oldEventId);\n }\n this.savePendingEvents();\n\n this.emit(RoomEvent.LocalEchoUpdated, event, this, oldEventId, oldStatus);\n }\n\n private revertRedactionLocalEcho(redactionEvent: MatrixEvent): void {\n const redactId = redactionEvent.event.redacts;\n if (!redactId) {\n return;\n }\n const redactedEvent = this.getUnfilteredTimelineSet().findEventById(redactId);\n if (redactedEvent) {\n redactedEvent.unmarkLocallyRedacted();\n // re-render after undoing redaction\n this.emit(RoomEvent.RedactionCancelled, redactionEvent, this);\n // reapply relation now redaction failed\n if (redactedEvent.isRelation()) {\n this.aggregateNonLiveRelation(redactedEvent);\n }\n }\n }\n\n /**\n * Add some events to this room. This can include state events, message\n * events and typing notifications. These events are treated as \"live\" so\n * they will go to the end of the timeline.\n *\n * @param events - A list of events to add.\n * @param addLiveEventOptions - addLiveEvent options\n * @throws If `duplicateStrategy` is not falsey, 'replace' or 'ignore'.\n */\n public addLiveEvents(events: MatrixEvent[], addLiveEventOptions?: IAddLiveEventOptions): void;\n /**\n * @deprecated In favor of the overload with `IAddLiveEventOptions`\n */\n public addLiveEvents(events: MatrixEvent[], duplicateStrategy?: DuplicateStrategy, fromCache?: boolean): void;\n public addLiveEvents(\n events: MatrixEvent[],\n duplicateStrategyOrOpts?: DuplicateStrategy | IAddLiveEventOptions,\n fromCache = false,\n ): void {\n let duplicateStrategy: DuplicateStrategy | undefined = duplicateStrategyOrOpts as DuplicateStrategy;\n let timelineWasEmpty: boolean | undefined = false;\n if (typeof duplicateStrategyOrOpts === \"object\") {\n ({\n duplicateStrategy,\n fromCache = false,\n /* roomState, (not used here) */\n timelineWasEmpty,\n } = duplicateStrategyOrOpts);\n } else if (duplicateStrategyOrOpts !== undefined) {\n // Deprecation warning\n // FIXME: Remove after 2023-06-01 (technical debt)\n logger.warn(\n \"Overload deprecated: \" +\n \"`Room.addLiveEvents(events, duplicateStrategy?, fromCache?)` \" +\n \"is deprecated in favor of the overload with `Room.addLiveEvents(events, IAddLiveEventOptions)`\",\n );\n }\n\n if (duplicateStrategy && [\"replace\", \"ignore\"].indexOf(duplicateStrategy) === -1) {\n throw new Error(\"duplicateStrategy MUST be either 'replace' or 'ignore'\");\n }\n\n // sanity check that the live timeline is still live\n for (let i = 0; i < this.timelineSets.length; i++) {\n const liveTimeline = this.timelineSets[i].getLiveTimeline();\n if (liveTimeline.getPaginationToken(EventTimeline.FORWARDS)) {\n throw new Error(\n \"live timeline \" +\n i +\n \" is no longer live - it has a pagination token \" +\n \"(\" +\n liveTimeline.getPaginationToken(EventTimeline.FORWARDS) +\n \")\",\n );\n }\n if (liveTimeline.getNeighbouringTimeline(EventTimeline.FORWARDS)) {\n throw new Error(`live timeline ${i} is no longer live - it has a neighbouring timeline`);\n }\n }\n\n const threadRoots = this.findThreadRoots(events);\n const eventsByThread: { [threadId: string]: MatrixEvent[] } = {};\n\n const options: IAddLiveEventOptions = {\n duplicateStrategy,\n fromCache,\n timelineWasEmpty,\n };\n\n for (const event of events) {\n // TODO: We should have a filter to say \"only add state event types X Y Z to the timeline\".\n this.processLiveEvent(event);\n\n if (event.getUnsigned().transaction_id) {\n const existingEvent = this.txnToEvent.get(event.getUnsigned().transaction_id!);\n if (existingEvent) {\n // remote echo of an event we sent earlier\n this.handleRemoteEcho(event, existingEvent);\n continue; // we can skip adding the event to the timeline sets, it is already there\n }\n }\n\n const { shouldLiveInRoom, shouldLiveInThread, threadId } = this.eventShouldLiveIn(\n event,\n events,\n threadRoots,\n );\n\n if (shouldLiveInThread && !eventsByThread[threadId ?? \"\"]) {\n eventsByThread[threadId ?? \"\"] = [];\n }\n eventsByThread[threadId ?? \"\"]?.push(event);\n\n if (shouldLiveInRoom) {\n this.addLiveEvent(event, options);\n }\n }\n\n Object.entries(eventsByThread).forEach(([threadId, threadEvents]) => {\n this.addThreadedEvents(threadId, threadEvents, false);\n });\n }\n\n public partitionThreadedEvents(\n events: MatrixEvent[],\n ): [timelineEvents: MatrixEvent[], threadedEvents: MatrixEvent[]] {\n // Indices to the events array, for readability\n const ROOM = 0;\n const THREAD = 1;\n if (this.client.supportsThreads()) {\n const threadRoots = this.findThreadRoots(events);\n return events.reduce(\n (memo, event: MatrixEvent) => {\n const { shouldLiveInRoom, shouldLiveInThread, threadId } = this.eventShouldLiveIn(\n event,\n events,\n threadRoots,\n );\n\n if (shouldLiveInRoom) {\n memo[ROOM].push(event);\n }\n\n if (shouldLiveInThread) {\n event.setThreadId(threadId ?? \"\");\n memo[THREAD].push(event);\n }\n\n return memo;\n },\n [[] as MatrixEvent[], [] as MatrixEvent[]],\n );\n } else {\n // When `experimentalThreadSupport` is disabled treat all events as timelineEvents\n return [events as MatrixEvent[], [] as MatrixEvent[]];\n }\n }\n\n /**\n * Given some events, find the IDs of all the thread roots that are referred to by them.\n */\n private findThreadRoots(events: MatrixEvent[]): Set<string> {\n const threadRoots = new Set<string>();\n for (const event of events) {\n if (event.isRelation(THREAD_RELATION_TYPE.name)) {\n threadRoots.add(event.relationEventId ?? \"\");\n }\n }\n return threadRoots;\n }\n\n /**\n * Add a receipt event to the room.\n * @param event - The m.receipt event.\n * @param synthetic - True if this event is implicit.\n */\n public addReceipt(event: MatrixEvent, synthetic = false): void {\n const content = event.getContent<ReceiptContent>();\n Object.keys(content).forEach((eventId: string) => {\n Object.keys(content[eventId]).forEach((receiptType: ReceiptType | string) => {\n Object.keys(content[eventId][receiptType]).forEach((userId: string) => {\n const receipt = content[eventId][receiptType][userId] as Receipt;\n const receiptForMainTimeline = !receipt.thread_id || receipt.thread_id === MAIN_ROOM_TIMELINE;\n const receiptDestination: Thread | this | undefined = receiptForMainTimeline\n ? this\n : this.threads.get(receipt.thread_id ?? \"\");\n\n if (receiptDestination) {\n receiptDestination.addReceiptToStructure(\n eventId,\n receiptType as ReceiptType,\n userId,\n receipt,\n synthetic,\n );\n\n // If the read receipt sent for the logged in user matches\n // the last event of the live timeline, then we know for a fact\n // that the user has read that message.\n // We can mark the room as read and not wait for the local echo\n // from synapse\n // This needs to be done after the initial sync as we do not want this\n // logic to run whilst the room is being initialised\n if (this.client.isInitialSyncComplete() && userId === this.client.getUserId()) {\n const lastEvent = receiptDestination.timeline[receiptDestination.timeline.length - 1];\n if (lastEvent && eventId === lastEvent.getId() && userId === lastEvent.getSender()) {\n receiptDestination.setUnread(NotificationCountType.Total, 0);\n receiptDestination.setUnread(NotificationCountType.Highlight, 0);\n }\n }\n } else {\n // The thread does not exist locally, keep the read receipt\n // in a cache locally, and re-apply the `addReceipt` logic\n // when the thread is created\n this.cachedThreadReadReceipts.set(receipt.thread_id!, [\n ...(this.cachedThreadReadReceipts.get(receipt.thread_id!) ?? []),\n { eventId, receiptType, userId, receipt, synthetic },\n ]);\n }\n\n const me = this.client.getUserId();\n // Track the time of the current user's oldest threaded receipt in the room.\n if (userId === me && !receiptForMainTimeline && receipt.ts < this.oldestThreadedReceiptTs) {\n this.oldestThreadedReceiptTs = receipt.ts;\n }\n\n // Track each user's unthreaded read receipt.\n if (!receipt.thread_id && receipt.ts > (this.unthreadedReceipts.get(userId)?.ts ?? 0)) {\n this.unthreadedReceipts.set(userId, receipt);\n }\n });\n });\n });\n\n // send events after we've regenerated the structure & cache, otherwise things that\n // listened for the event would read stale data.\n this.emit(RoomEvent.Receipt, event, this);\n }\n\n /**\n * Adds/handles ephemeral events such as typing notifications and read receipts.\n * @param events - A list of events to process\n */\n public addEphemeralEvents(events: MatrixEvent[]): void {\n for (const event of events) {\n if (event.getType() === EventType.Typing) {\n this.currentState.setTypingEvent(event);\n } else if (event.getType() === EventType.Receipt) {\n this.addReceipt(event);\n } // else ignore - life is too short for us to care about these events\n }\n }\n\n /**\n * Removes events from this room.\n * @param eventIds - A list of eventIds to remove.\n */\n public removeEvents(eventIds: string[]): void {\n for (const eventId of eventIds) {\n this.removeEvent(eventId);\n }\n }\n\n /**\n * Removes a single event from this room.\n *\n * @param eventId - The id of the event to remove\n *\n * @returns true if the event was removed from any of the room's timeline sets\n */\n public removeEvent(eventId: string): boolean {\n let removedAny = false;\n for (const timelineSet of this.timelineSets) {\n const removed = timelineSet.removeEvent(eventId);\n if (removed) {\n if (removed.isRedaction()) {\n this.revertRedactionLocalEcho(removed);\n }\n removedAny = true;\n }\n }\n return removedAny;\n }\n\n /**\n * Recalculate various aspects of the room, including the room name and\n * room summary. Call this any time the room's current state is modified.\n * May fire \"Room.name\" if the room name is updated.\n *\n * @remarks\n * Fires {@link RoomEvent.Name}\n */\n public recalculate(): void {\n // set fake stripped state events if this is an invite room so logic remains\n // consistent elsewhere.\n const membershipEvent = this.currentState.getStateEvents(EventType.RoomMember, this.myUserId);\n if (membershipEvent) {\n const membership = membershipEvent.getContent().membership;\n this.updateMyMembership(membership!);\n\n if (membership === \"invite\") {\n const strippedStateEvents = membershipEvent.getUnsigned().invite_room_state || [];\n strippedStateEvents.forEach((strippedEvent) => {\n const existingEvent = this.currentState.getStateEvents(strippedEvent.type, strippedEvent.state_key);\n if (!existingEvent) {\n // set the fake stripped event instead\n this.currentState.setStateEvents([\n new MatrixEvent({\n type: strippedEvent.type,\n state_key: strippedEvent.state_key,\n content: strippedEvent.content,\n event_id: \"$fake\" + Date.now(),\n room_id: this.roomId,\n user_id: this.myUserId, // technically a lie\n }),\n ]);\n }\n });\n }\n }\n\n const oldName = this.name;\n this.name = this.calculateRoomName(this.myUserId);\n this.normalizedName = normalize(this.name);\n this.summary = new RoomSummary(this.roomId, {\n title: this.name,\n });\n\n if (oldName !== this.name) {\n this.emit(RoomEvent.Name, this);\n }\n }\n\n /**\n * Update the room-tag event for the room. The previous one is overwritten.\n * @param event - the m.tag event\n */\n public addTags(event: MatrixEvent): void {\n // event content looks like:\n // content: {\n // tags: {\n // $tagName: { $metadata: $value },\n // $tagName: { $metadata: $value },\n // }\n // }\n\n // XXX: do we need to deep copy here?\n this.tags = event.getContent().tags || {};\n\n // XXX: we could do a deep-comparison to see if the tags have really\n // changed - but do we want to bother?\n this.emit(RoomEvent.Tags, event, this);\n }\n\n /**\n * Update the account_data events for this room, overwriting events of the same type.\n * @param events - an array of account_data events to add\n */\n public addAccountData(events: MatrixEvent[]): void {\n for (const event of events) {\n if (event.getType() === \"m.tag\") {\n this.addTags(event);\n }\n const eventType = event.getType();\n const lastEvent = this.accountData.get(eventType);\n this.accountData.set(eventType, event);\n this.emit(RoomEvent.AccountData, event, this, lastEvent);\n }\n }\n\n /**\n * Access account_data event of given event type for this room\n * @param type - the type of account_data event to be accessed\n * @returns the account_data event in question\n */\n public getAccountData(type: EventType | string): MatrixEvent | undefined {\n return this.accountData.get(type);\n }\n\n /**\n * Returns whether the syncing user has permission to send a message in the room\n * @returns true if the user should be permitted to send\n * message events into the room.\n */\n public maySendMessage(): boolean {\n return (\n this.getMyMembership() === \"join\" &&\n (this.client.isRoomEncrypted(this.roomId)\n ? this.currentState.maySendEvent(EventType.RoomMessageEncrypted, this.myUserId)\n : this.currentState.maySendEvent(EventType.RoomMessage, this.myUserId))\n );\n }\n\n /**\n * Returns whether the given user has permissions to issue an invite for this room.\n * @param userId - the ID of the Matrix user to check permissions for\n * @returns true if the user should be permitted to issue invites for this room.\n */\n public canInvite(userId: string): boolean {\n let canInvite = this.getMyMembership() === \"join\";\n const powerLevelsEvent = this.currentState.getStateEvents(EventType.RoomPowerLevels, \"\");\n const powerLevels = powerLevelsEvent && powerLevelsEvent.getContent();\n const me = this.getMember(userId);\n if (powerLevels && me && powerLevels.invite > me.powerLevel) {\n canInvite = false;\n }\n return canInvite;\n }\n\n /**\n * Returns the join rule based on the m.room.join_rule state event, defaulting to `invite`.\n * @returns the join_rule applied to this room\n */\n public getJoinRule(): JoinRule {\n return this.currentState.getJoinRule();\n }\n\n /**\n * Returns the history visibility based on the m.room.history_visibility state event, defaulting to `shared`.\n * @returns the history_visibility applied to this room\n */\n public getHistoryVisibility(): HistoryVisibility {\n return this.currentState.getHistoryVisibility();\n }\n\n /**\n * Returns the history visibility based on the m.room.history_visibility state event, defaulting to `shared`.\n * @returns the history_visibility applied to this room\n */\n public getGuestAccess(): GuestAccess {\n return this.currentState.getGuestAccess();\n }\n\n /**\n * Returns the type of the room from the `m.room.create` event content or undefined if none is set\n * @returns the type of the room.\n */\n public getType(): RoomType | string | undefined {\n const createEvent = this.currentState.getStateEvents(EventType.RoomCreate, \"\");\n if (!createEvent) {\n if (!this.getTypeWarning) {\n logger.warn(\"[getType] Room \" + this.roomId + \" does not have an m.room.create event\");\n this.getTypeWarning = true;\n }\n return undefined;\n }\n return createEvent.getContent()[RoomCreateTypeField];\n }\n\n /**\n * Returns whether the room is a space-room as defined by MSC1772.\n * @returns true if the room's type is RoomType.Space\n */\n public isSpaceRoom(): boolean {\n return this.getType() === RoomType.Space;\n }\n\n /**\n * Returns whether the room is a call-room as defined by MSC3417.\n * @returns true if the room's type is RoomType.UnstableCall\n */\n public isCallRoom(): boolean {\n return this.getType() === RoomType.UnstableCall;\n }\n\n /**\n * Returns whether the room is a video room.\n * @returns true if the room's type is RoomType.ElementVideo\n */\n public isElementVideoRoom(): boolean {\n return this.getType() === RoomType.ElementVideo;\n }\n\n /**\n * Find the predecessor of this room.\n *\n * @param msc3946ProcessDynamicPredecessor - if true, look for an\n * m.room.predecessor state event and use it if found (MSC3946).\n * @returns null if this room has no predecessor. Otherwise, returns\n * the roomId, last eventId and viaServers of the predecessor room.\n *\n * If msc3946ProcessDynamicPredecessor is true, use m.predecessor events\n * as well as m.room.create events to find predecessors.\n *\n * Note: if an m.predecessor event is used, eventId may be undefined\n * since last_known_event_id is optional.\n *\n * Note: viaServers may be undefined, and will definitely be undefined if\n * this predecessor comes from a RoomCreate event (rather than a\n * RoomPredecessor, which has the optional via_servers property).\n */\n public findPredecessor(\n msc3946ProcessDynamicPredecessor = false,\n ): { roomId: string; eventId?: string; viaServers?: string[] } | null {\n const currentState = this.getLiveTimeline().getState(EventTimeline.FORWARDS);\n if (!currentState) {\n return null;\n }\n return currentState.findPredecessor(msc3946ProcessDynamicPredecessor);\n }\n\n private roomNameGenerator(state: RoomNameState): string {\n if (this.client.roomNameGenerator) {\n const name = this.client.roomNameGenerator(this.roomId, state);\n if (name !== null) {\n return name;\n }\n }\n\n switch (state.type) {\n case RoomNameType.Actual:\n return state.name;\n case RoomNameType.Generated:\n switch (state.subtype) {\n case \"Inviting\":\n return `Inviting ${memberNamesToRoomName(state.names, state.count)}`;\n default:\n return memberNamesToRoomName(state.names, state.count);\n }\n case RoomNameType.EmptyRoom:\n if (state.oldName) {\n return `Empty room (was ${state.oldName})`;\n } else {\n return \"Empty room\";\n }\n }\n }\n\n /**\n * This is an internal method. Calculates the name of the room from the current\n * room state.\n * @param userId - The client's user ID. Used to filter room members\n * correctly.\n * @param ignoreRoomNameEvent - Return the implicit room name that we'd see if there\n * was no m.room.name event.\n * @returns The calculated room name.\n */\n private calculateRoomName(userId: string, ignoreRoomNameEvent = false): string {\n if (!ignoreRoomNameEvent) {\n // check for an alias, if any. for now, assume first alias is the\n // official one.\n const mRoomName = this.currentState.getStateEvents(EventType.RoomName, \"\");\n if (mRoomName?.getContent().name) {\n return this.roomNameGenerator({\n type: RoomNameType.Actual,\n name: mRoomName.getContent().name,\n });\n }\n }\n\n const alias = this.getCanonicalAlias();\n if (alias) {\n return this.roomNameGenerator({\n type: RoomNameType.Actual,\n name: alias,\n });\n }\n\n const joinedMemberCount = this.currentState.getJoinedMemberCount();\n const invitedMemberCount = this.currentState.getInvitedMemberCount();\n // -1 because these numbers include the syncing user\n let inviteJoinCount = joinedMemberCount + invitedMemberCount - 1;\n\n // get service members (e.g. helper bots) for exclusion\n let excludedUserIds: string[] = [];\n const mFunctionalMembers = this.currentState.getStateEvents(UNSTABLE_ELEMENT_FUNCTIONAL_USERS.name, \"\");\n if (Array.isArray(mFunctionalMembers?.getContent().service_members)) {\n excludedUserIds = mFunctionalMembers!.getContent().service_members;\n }\n\n // get members that are NOT ourselves and are actually in the room.\n let otherNames: string[] = [];\n if (this.summaryHeroes) {\n // if we have a summary, the member state events should be in the room state\n this.summaryHeroes.forEach((userId) => {\n // filter service members\n if (excludedUserIds.includes(userId)) {\n inviteJoinCount--;\n return;\n }\n const member = this.getMember(userId);\n otherNames.push(member ? member.name : userId);\n });\n } else {\n let otherMembers = this.currentState.getMembers().filter((m) => {\n return m.userId !== userId && (m.membership === \"invite\" || m.membership === \"join\");\n });\n otherMembers = otherMembers.filter(({ userId }) => {\n // filter service members\n if (excludedUserIds.includes(userId)) {\n inviteJoinCount--;\n return false;\n }\n return true;\n });\n // make sure members have stable order\n otherMembers.sort((a, b) => utils.compare(a.userId, b.userId));\n // only 5 first members, immitate summaryHeroes\n otherMembers = otherMembers.slice(0, 5);\n otherNames = otherMembers.map((m) => m.name);\n }\n\n if (inviteJoinCount) {\n return this.roomNameGenerator({\n type: RoomNameType.Generated,\n names: otherNames,\n count: inviteJoinCount,\n });\n }\n\n const myMembership = this.getMyMembership();\n // if I have created a room and invited people through\n // 3rd party invites\n if (myMembership == \"join\") {\n const thirdPartyInvites = this.currentState.getStateEvents(EventType.RoomThirdPartyInvite);\n\n if (thirdPartyInvites?.length) {\n const thirdPartyNames = thirdPartyInvites.map((i) => {\n return i.getContent().display_name;\n });\n\n return this.roomNameGenerator({\n type: RoomNameType.Generated,\n subtype: \"Inviting\",\n names: thirdPartyNames,\n count: thirdPartyNames.length + 1,\n });\n }\n }\n\n // let's try to figure out who was here before\n let leftNames = otherNames;\n // if we didn't have heroes, try finding them in the room state\n if (!leftNames.length) {\n leftNames = this.currentState\n .getMembers()\n .filter((m) => {\n return m.userId !== userId && m.membership !== \"invite\" && m.membership !== \"join\";\n })\n .map((m) => m.name);\n }\n\n let oldName: string | undefined;\n if (leftNames.length) {\n oldName = this.roomNameGenerator({\n type: RoomNameType.Generated,\n names: leftNames,\n count: leftNames.length + 1,\n });\n }\n\n return this.roomNameGenerator({\n type: RoomNameType.EmptyRoom,\n oldName,\n });\n }\n\n /**\n * When we receive a new visibility change event:\n *\n * - store this visibility change alongside the timeline, in case we\n * later need to apply it to an event that we haven't received yet;\n * - if we have already received the event whose visibility has changed,\n * patch it to reflect the visibility change and inform listeners.\n */\n private applyNewVisibilityEvent(event: MatrixEvent): void {\n const visibilityChange = event.asVisibilityChange();\n if (!visibilityChange) {\n // The event is ill-formed.\n return;\n }\n\n // Ignore visibility change events that are not emitted by moderators.\n const userId = event.getSender();\n if (!userId) {\n return;\n }\n const isPowerSufficient =\n (EVENT_VISIBILITY_CHANGE_TYPE.name &&\n this.currentState.maySendStateEvent(EVENT_VISIBILITY_CHANGE_TYPE.name, userId)) ||\n (EVENT_VISIBILITY_CHANGE_TYPE.altName &&\n this.currentState.maySendStateEvent(EVENT_VISIBILITY_CHANGE_TYPE.altName, userId));\n if (!isPowerSufficient) {\n // Powerlevel is insufficient.\n return;\n }\n\n // Record this change in visibility.\n // If the event is not in our timeline and we only receive it later,\n // we may need to apply the visibility change at a later date.\n\n const visibilityEventsOnOriginalEvent = this.visibilityEvents.get(visibilityChange.eventId);\n if (visibilityEventsOnOriginalEvent) {\n // It would be tempting to simply erase the latest visibility change\n // but we need to record all of the changes in case the latest change\n // is ever redacted.\n //\n // In practice, linear scans through `visibilityEvents` should be fast.\n // However, to protect against a potential DoS attack, we limit the\n // number of iterations in this loop.\n let index = visibilityEventsOnOriginalEvent.length - 1;\n const min = Math.max(\n 0,\n visibilityEventsOnOriginalEvent.length - MAX_NUMBER_OF_VISIBILITY_EVENTS_TO_SCAN_THROUGH,\n );\n for (; index >= min; --index) {\n const target = visibilityEventsOnOriginalEvent[index];\n if (target.getTs() < event.getTs()) {\n break;\n }\n }\n if (index === -1) {\n visibilityEventsOnOriginalEvent.unshift(event);\n } else {\n visibilityEventsOnOriginalEvent.splice(index + 1, 0, event);\n }\n } else {\n this.visibilityEvents.set(visibilityChange.eventId, [event]);\n }\n\n // Finally, let's check if the event is already in our timeline.\n // If so, we need to patch it and inform listeners.\n\n const originalEvent = this.findEventById(visibilityChange.eventId);\n if (!originalEvent) {\n return;\n }\n originalEvent.applyVisibilityEvent(visibilityChange);\n }\n\n private redactVisibilityChangeEvent(event: MatrixEvent): void {\n // Sanity checks.\n if (!event.isVisibilityEvent) {\n throw new Error(\"expected a visibility change event\");\n }\n const relation = event.getRelation();\n const originalEventId = relation?.event_id;\n const visibilityEventsOnOriginalEvent = this.visibilityEvents.get(originalEventId!);\n if (!visibilityEventsOnOriginalEvent) {\n // No visibility changes on the original event.\n // In particular, this change event was not recorded,\n // most likely because it was ill-formed.\n return;\n }\n const index = visibilityEventsOnOriginalEvent.findIndex((change) => change.getId() === event.getId());\n if (index === -1) {\n // This change event was not recorded, most likely because\n // it was ill-formed.\n return;\n }\n // Remove visibility change.\n visibilityEventsOnOriginalEvent.splice(index, 1);\n\n // If we removed the latest visibility change event, propagate changes.\n if (index === visibilityEventsOnOriginalEvent.length) {\n const originalEvent = this.findEventById(originalEventId!);\n if (!originalEvent) {\n return;\n }\n if (index === 0) {\n // We have just removed the only visibility change event.\n this.visibilityEvents.delete(originalEventId!);\n originalEvent.applyVisibilityEvent();\n } else {\n const newEvent = visibilityEventsOnOriginalEvent[visibilityEventsOnOriginalEvent.length - 1];\n const newVisibility = newEvent.asVisibilityChange();\n if (!newVisibility) {\n // Event is ill-formed.\n // This breaks our invariant.\n throw new Error(\"at this stage, visibility changes should be well-formed\");\n }\n originalEvent.applyVisibilityEvent(newVisibility);\n }\n }\n }\n\n /**\n * When we receive an event whose visibility has been altered by\n * a (more recent) visibility change event, patch the event in\n * place so that clients now not to display it.\n *\n * @param event - Any matrix event. If this event has at least one a\n * pending visibility change event, apply the latest visibility\n * change event.\n */\n private applyPendingVisibilityEvents(event: MatrixEvent): void {\n const visibilityEvents = this.visibilityEvents.get(event.getId()!);\n if (!visibilityEvents || visibilityEvents.length == 0) {\n // No pending visibility change in store.\n return;\n }\n const visibilityEvent = visibilityEvents[visibilityEvents.length - 1];\n const visibilityChange = visibilityEvent.asVisibilityChange();\n if (!visibilityChange) {\n return;\n }\n if (visibilityChange.visible) {\n // Events are visible by default, no need to apply a visibility change.\n // Note that we need to keep the visibility changes in `visibilityEvents`,\n // in case we later fetch an older visibility change event that is superseded\n // by `visibilityChange`.\n }\n if (visibilityEvent.getTs() < event.getTs()) {\n // Something is wrong, the visibility change cannot happen before the\n // event. Presumably an ill-formed event.\n return;\n }\n event.applyVisibilityEvent(visibilityChange);\n }\n\n /**\n * Find when a client has gained thread capabilities by inspecting the oldest\n * threaded receipt\n * @returns the timestamp of the oldest threaded receipt\n */\n public getOldestThreadedReceiptTs(): number {\n return this.oldestThreadedReceiptTs;\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.unthreadedReceipts.get(userId);\n }\n\n /**\n * This issue should also be addressed on synapse's side and is tracked as part\n * of https://github.com/matrix-org/synapse/issues/14837\n *\n *\n * We consider a room fully read if the current user has sent\n * the last event in the live timeline of that context and if the read receipt\n * we have on record matches.\n * This also detects all unread threads and applies the same logic to those\n * contexts\n */\n public fixupNotifications(userId: string): void {\n super.fixupNotifications(userId);\n\n const unreadThreads = this.getThreads().filter(\n (thread) => this.getThreadUnreadNotificationCount(thread.id, NotificationCountType.Total) > 0,\n );\n\n for (const thread of unreadThreads) {\n thread.fixupNotifications(userId);\n }\n }\n}\n\n// a map from current event status to a list of allowed next statuses\nconst ALLOWED_TRANSITIONS: Record<EventStatus, EventStatus[]> = {\n [EventStatus.ENCRYPTING]: [EventStatus.SENDING, EventStatus.NOT_SENT, EventStatus.CANCELLED],\n [EventStatus.SENDING]: [EventStatus.ENCRYPTING, EventStatus.QUEUED, EventStatus.NOT_SENT, EventStatus.SENT],\n [EventStatus.QUEUED]: [EventStatus.SENDING, EventStatus.NOT_SENT, EventStatus.CANCELLED],\n [EventStatus.SENT]: [],\n [EventStatus.NOT_SENT]: [EventStatus.SENDING, EventStatus.QUEUED, EventStatus.CANCELLED],\n [EventStatus.CANCELLED]: [],\n};\n\nexport enum RoomNameType {\n EmptyRoom,\n Generated,\n Actual,\n}\n\nexport interface EmptyRoomNameState {\n type: RoomNameType.EmptyRoom;\n oldName?: string;\n}\n\nexport interface GeneratedRoomNameState {\n type: RoomNameType.Generated;\n subtype?: \"Inviting\";\n names: string[];\n count: number;\n}\n\nexport interface ActualRoomNameState {\n type: RoomNameType.Actual;\n name: string;\n}\n\nexport type RoomNameState = EmptyRoomNameState | GeneratedRoomNameState | ActualRoomNameState;\n\n// Can be overriden by IMatrixClientCreateOpts::memberNamesToRoomNameFn\nfunction memberNamesToRoomName(names: string[], count: number): string {\n const countWithoutMe = count - 1;\n if (!names.length) {\n return \"Empty room\";\n } else if (names.length === 1 && countWithoutMe <= 1) {\n return names[0];\n } else if (names.length === 2 && countWithoutMe <= 2) {\n return `${names[0]} and ${names[1]}`;\n } else {\n const plural = countWithoutMe > 1;\n if (plural) {\n return `${names[0]} and ${countWithoutMe} others`;\n } else {\n return `${names[0]} and 1 other`;\n }\n }\n}\n"],"mappings":";;;;;;;;AAgBA,IAAAA,gBAAA,GAAAC,OAAA;AAEA,IAAAC,iBAAA,GAAAD,OAAA;AAMA,IAAAE,cAAA,GAAAF,OAAA;AACA,IAAAG,YAAA,GAAAH,OAAA;AACA,IAAAI,KAAA,GAAAC,uBAAA,CAAAL,OAAA;AAEA,IAAAM,MAAA,GAAAN,OAAA;AACA,IAAAO,YAAA,GAAAP,OAAA;AACA,IAAAQ,WAAA,GAAAR,OAAA;AACA,IAAAS,YAAA,GAAAT,OAAA;AACA,IAAAU,OAAA,GAAAV,OAAA;AACA,IAAAW,UAAA,GAAAX,OAAA;AACA,IAAAY,OAAA,GAAAZ,OAAA;AAQA,IAAAa,OAAA,GAAAb,OAAA;AAEA,IAAAc,OAAA,GAAAd,OAAA;AACA,IAAAe,UAAA,GAAAf,OAAA;AACA,IAAAgB,OAAA,GAAAhB,OAAA;AACA,IAAAiB,OAAA,GAAAjB,OAAA;AASA,IAAAkB,cAAA,GAAAlB,OAAA;AAQA,IAAAmB,mBAAA,GAAAnB,OAAA;AACA,IAAAoB,YAAA,GAAApB,OAAA;AACA,IAAAqB,KAAA,GAAArB,OAAA;AAAyC,SAAAsB,yBAAAC,WAAA,eAAAC,OAAA,kCAAAC,iBAAA,OAAAD,OAAA,QAAAE,gBAAA,OAAAF,OAAA,YAAAF,wBAAA,YAAAA,CAAAC,WAAA,WAAAA,WAAA,GAAAG,gBAAA,GAAAD,iBAAA,KAAAF,WAAA;AAAA,SAAAlB,wBAAAsB,GAAA,EAAAJ,WAAA,SAAAA,WAAA,IAAAI,GAAA,IAAAA,GAAA,CAAAC,UAAA,WAAAD,GAAA,QAAAA,GAAA,oBAAAA,GAAA,wBAAAA,GAAA,4BAAAE,OAAA,EAAAF,GAAA,UAAAG,KAAA,GAAAR,wBAAA,CAAAC,WAAA,OAAAO,KAAA,IAAAA,KAAA,CAAAC,GAAA,CAAAJ,GAAA,YAAAG,KAAA,CAAAE,GAAA,CAAAL,GAAA,SAAAM,MAAA,WAAAC,qBAAA,GAAAC,MAAA,CAAAC,cAAA,IAAAD,MAAA,CAAAE,wBAAA,WAAAC,GAAA,IAAAX,GAAA,QAAAW,GAAA,kBAAAH,MAAA,CAAAI,SAAA,CAAAC,cAAA,CAAAC,IAAA,CAAAd,GAAA,EAAAW,GAAA,SAAAI,IAAA,GAAAR,qBAAA,GAAAC,MAAA,CAAAE,wBAAA,CAAAV,GAAA,EAAAW,GAAA,cAAAI,IAAA,KAAAA,IAAA,CAAAV,GAAA,IAAAU,IAAA,CAAAC,GAAA,KAAAR,MAAA,CAAAC,cAAA,CAAAH,MAAA,EAAAK,GAAA,EAAAI,IAAA,YAAAT,MAAA,CAAAK,GAAA,IAAAX,GAAA,CAAAW,GAAA,SAAAL,MAAA,CAAAJ,OAAA,GAAAF,GAAA,MAAAG,KAAA,IAAAA,KAAA,CAAAa,GAAA,CAAAhB,GAAA,EAAAM,MAAA,YAAAA,MAAA;AAAA,SAAAW,QAAAC,MAAA,EAAAC,cAAA,QAAAC,IAAA,GAAAZ,MAAA,CAAAY,IAAA,CAAAF,MAAA,OAAAV,MAAA,CAAAa,qBAAA,QAAAC,OAAA,GAAAd,MAAA,CAAAa,qBAAA,CAAAH,MAAA,GAAAC,cAAA,KAAAG,OAAA,GAAAA,OAAA,CAAAC,MAAA,WAAAC,GAAA,WAAAhB,MAAA,CAAAE,wBAAA,CAAAQ,MAAA,EAAAM,GAAA,EAAAC,UAAA,OAAAL,IAAA,CAAAM,IAAA,CAAAC,KAAA,CAAAP,IAAA,EAAAE,OAAA,YAAAF,IAAA;AAAA,SAAAQ,cAAAC,MAAA,aAAAC,CAAA,MAAAA,CAAA,GAAAC,SAAA,CAAAC,MAAA,EAAAF,CAAA,UAAAG,MAAA,WAAAF,SAAA,CAAAD,CAAA,IAAAC,SAAA,CAAAD,CAAA,QAAAA,CAAA,OAAAb,OAAA,CAAAT,MAAA,CAAAyB,MAAA,OAAAC,OAAA,WAAAvB,GAAA,QAAAwB,gBAAA,CAAAjC,OAAA,EAAA2B,MAAA,EAAAlB,GAAA,EAAAsB,MAAA,CAAAtB,GAAA,SAAAH,MAAA,CAAA4B,yBAAA,GAAA5B,MAAA,CAAA6B,gBAAA,CAAAR,MAAA,EAAArB,MAAA,CAAA4B,yBAAA,CAAAH,MAAA,KAAAhB,OAAA,CAAAT,MAAA,CAAAyB,MAAA,GAAAC,OAAA,WAAAvB,GAAA,IAAAH,MAAA,CAAAC,cAAA,CAAAoB,MAAA,EAAAlB,GAAA,EAAAH,MAAA,CAAAE,wBAAA,CAAAuB,MAAA,EAAAtB,GAAA,iBAAAkB,MAAA;AAEzC;AACA;AACA;AACA;AACA;AACA;AACO,MAAMS,uBAAuB,GAAG,GAAG;AAACC,OAAA,CAAAD,uBAAA,GAAAA,uBAAA;AAC3C,MAAME,kBAAkB,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC;AAwBxE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAMC,+CAA+C,GAAG,EAAE;AAAC,IAI/CC,qBAAqB;AAAAH,OAAA,CAAAG,qBAAA,GAAAA,qBAAA;AAAA,WAArBA,qBAAqB;EAArBA,qBAAqB;EAArBA,qBAAqB;AAAA,GAArBA,qBAAqB,KAAAH,OAAA,CAAAG,qBAAA,GAArBA,qBAAqB;AAAA,IAcrBC,SAAS;AAAAJ,OAAA,CAAAI,SAAA,GAAAA,SAAA;AAAA,WAATA,SAAS;EAATA,SAAS;EAATA,SAAS;EAATA,SAAS;EAATA,SAAS;EAATA,SAAS;EAATA,SAAS;EAATA,SAAS;EAATA,SAAS;EAATA,SAAS;EAATA,SAAS;EAATA,SAAS;EAATA,SAAS;EAATA,SAAS;EAATA,SAAS;EAATA,SAAS;AAAA,GAATA,SAAS,KAAAJ,OAAA,CAAAI,SAAA,GAATA,SAAS;AAoLd,MAAMC,IAAI,SAASC,wBAAW,CAAyC;EAEhB;;EAI1D;;EAEA;AACJ;AACA;AACA;;EAKI;EAC8E;;EAG9E;;EAIA;;EAKA;EACA;AACJ;AACA;;EAEI;AACJ;AACA;;EAEI;AACJ;AACA;AACA;EAC2D;EACvD;AACJ;AACA;AACA;EAC8D;EAC1D;AACJ;AACA;;EAEI;EACA;AACJ;AACA;AACA;;EAEI;AACJ;AACA;AACA;AACA;;EAEI;AACJ;AACA;AACA;AACA;;EAII;AACJ;AACA;AACA;;EAII;AACJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;EAGI;AACJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;EACWC,WAAWA,CACEC,MAAc,EACdC,MAAoB,EACpBC,QAAgB,EACfC,IAAW,GAAG,CAAC,CAAC,EACnC;IACE,KAAK,EAAE;IACP;IACA;IAAA,KAPgBH,MAAc,GAAdA,MAAc;IAAA,KACdC,MAAoB,GAApBA,MAAoB;IAAA,KACpBC,QAAgB,GAAhBA,QAAgB;IAAA,KACfC,IAAW,GAAXA,IAAW;IAAA,IAAAf,gBAAA,CAAAjC,OAAA;IAAA,IAAAiC,gBAAA,CAAAjC,OAAA,sBA1He,IAAIiD,GAAG,EAAE;IAAA,IAAAhB,gBAAA,CAAAjC,OAAA,8BACR,CAAC,CAAC;IAAA,IAAAiC,gBAAA,CAAAjC,OAAA,+BACX,IAAIiD,GAAG,EAA6B;IAAA,IAAAhB,gBAAA,CAAAjC,OAAA,oCAChC,IAAIiD,GAAG,EAAoC;IAAA,IAAAhB,gBAAA,CAAAjC,OAAA,mCAEpDkD,QAAQ;IAAA,IAAAjB,gBAAA,CAAAjC,OAAA,8BAKb,IAAIiD,GAAG,EAAmB;IAAA,IAAAhB,gBAAA,CAAAjC,OAAA;IAAA,IAAAiC,gBAAA,CAAAjC,OAAA,iBAEZ,IAAIiD,GAAG,EAAgB;IAAA,IAAAhB,gBAAA,CAAAjC,OAAA,+BACR,EAAE;IAAA,IAAAiC,gBAAA,CAAAjC,OAAA,gCAEc,CAAC,CAAC;IAAA,IAAAiC,gBAAA,CAAAjC,OAAA,gCAC7C,KAAK;IAAA,IAAAiC,gBAAA,CAAAjC,OAAA;IAAA,IAAAiC,gBAAA,CAAAjC,OAAA;IAAA,IAAAiC,gBAAA,CAAAjC,OAAA;IAAA,IAAAiC,gBAAA,CAAAjC,OAAA,yBAKK,IAAI;IAAA,IAAAiC,gBAAA,CAAAjC,OAAA,0BAEpB,KAAK;IAAA,IAAAiC,gBAAA,CAAAjC,OAAA,6BACF,KAAK;IAAA,IAAAiC,gBAAA,CAAAjC,OAAA;IAAA,IAAAiC,gBAAA,CAAAjC,OAAA;IAAA,IAAAiC,gBAAA,CAAAjC,OAAA;IAAA,IAAAiC,gBAAA,CAAAjC,OAAA,gBAgBkB,CAAC,CAAC;IAAA,IAAAiC,gBAAA,CAAAjC,OAAA,uBAKN,IAAIiD,GAAG,EAAE;IAAA,IAAAhB,gBAAA,CAAAjC,OAAA,mBAInB,IAAI;IAAA,IAAAiC,gBAAA,CAAAjC,OAAA;IAAA,IAAAiC,gBAAA,CAAAjC,OAAA;IAAA,IAAAiC,gBAAA,CAAAjC,OAAA;IAAA,IAAAiC,gBAAA,CAAAjC,OAAA,qBAmBb,IAAImD,sCAAkB,CAAC,IAAI,CAACL,MAAM,EAAE,IAAI,CAAC;IAAA,IAAAb,gBAAA,CAAAjC,OAAA,mBAMnD,IAAIiD,GAAG,EAAkB;IAAA,IAAAhB,gBAAA,CAAAjC,OAAA;IAAA,IAAAiC,gBAAA,CAAAjC,OAAA,4BAmBhB,IAAIiD,GAAG,EAAyB;IAAA,IAAAhB,gBAAA,CAAAjC,OAAA,qCAyE+B,IAAI;IAAA,IAAAiC,gBAAA,CAAAjC,OAAA,wBAizCvE,KAAK;IAAA,IAAAiC,gBAAA,CAAAjC,OAAA,kCA+RK,CAACoD,MAAc,EAAEC,iBAA0B,EAAEC,aAAsB,KAAW;MAC3G,IAAIF,MAAM,CAACtB,MAAM,EAAE;QAAA,IAAAyB,qBAAA;QACf,IAAI,CAACC,qBAAqB,EAAAD,qBAAA,GAAC,IAAI,CAACE,mBAAmB,cAAAF,qBAAA,uBAAxBA,qBAAA,CAA2B,CAAC,CAAC,EAAEH,MAAM,EAAEC,iBAAiB,EAAEC,aAAa,CAAC;QACnG,IAAIF,MAAM,CAACM,0BAA0B,EAAE;UAAA,IAAAC,sBAAA;UACnC,IAAI,CAACH,qBAAqB,EAAAG,sBAAA,GAAC,IAAI,CAACF,mBAAmB,cAAAE,sBAAA,uBAAxBA,sBAAA,CAA2B,CAAC,CAAC,EAAEP,MAAM,EAAEC,iBAAiB,EAAEC,aAAa,CAAC;QACvG;MACJ;IACJ,CAAC;IAAA,IAAArB,gBAAA,CAAAjC,OAAA,iCAE+B,CAC5B4D,WAAuC,EACvCR,MAAc,EACdC,iBAA0B,EAC1BC,aAAsB,KACf;MACP,IAAIM,WAAW,IAAIR,MAAM,CAACS,SAAS,EAAE;QACjC,IAAIP,aAAa,EAAE;UACfM,WAAW,CAACE,WAAW,CAACV,MAAM,CAACW,EAAE,CAAC;QACtC;QACA,IAAIC,cAAM,CAACC,oBAAoB,EAAE;UAC7BL,WAAW,CAACM,YAAY,CAACd,MAAM,CAACS,SAAS,EAAE;YACvCM,iBAAiB,EAAEC,mCAAiB,CAACC,OAAO;YAC5CC,SAAS,EAAE,KAAK;YAChBC,SAAS,EAAE,IAAI,CAACC;UACpB,CAAC,CAAC;QACN,CAAC,MAAM;UACHZ,WAAW,CAACa,kBAAkB,CAACrB,MAAM,CAACS,SAAS,EAAED,WAAW,CAACc,eAAe,EAAE,EAAE;YAAErB;UAAkB,CAAC,CAAC;QAC1G;MACJ;IACJ,CAAC;IAAA,IAAApB,gBAAA,CAAAjC,OAAA,0BAmEyB2E,KAAkB,IAAW;MACnD,IAAIA,KAAK,CAACC,WAAW,EAAE,EAAE;QACrB,MAAMC,QAAQ,GAAGF,KAAK,CAACA,KAAK,CAACG,OAAO;;QAEpC;QACA,MAAMC,aAAa,GAAGF,QAAQ,GAAG,IAAI,CAACG,aAAa,CAACH,QAAQ,CAAC,GAAGI,SAAS;QACzE,IAAIF,aAAa,EAAE;UACfA,aAAa,CAACG,YAAY,CAACP,KAAK,CAAC;;UAEjC;UACA,IAAII,aAAa,CAACI,OAAO,EAAE,EAAE;YACzB,MAAMC,iBAAiB,GAAG,IAAI,CAACZ,YAAY,CAACa,cAAc,CACtDN,aAAa,CAACO,OAAO,EAAE,EACvBP,aAAa,CAACQ,WAAW,EAAE,CAC9B;YACD,IAAI,CAAAH,iBAAiB,aAAjBA,iBAAiB,uBAAjBA,iBAAiB,CAAEI,KAAK,EAAE,MAAKT,aAAa,CAACS,KAAK,EAAE,EAAE;cACtD,IAAI,CAAChB,YAAY,CAACiB,cAAc,CAAC,CAACV,aAAa,CAAC,CAAC;YACrD;UACJ;UAEA,IAAI,CAACW,IAAI,CAACjD,SAAS,CAACkD,SAAS,EAAEhB,KAAK,EAAE,IAAI,CAAC;;UAE3C;UACA;UACA;UACA;UACA;;UAEA;UACA,IAAI,CAACiB,gBAAgB,CAACC,MAAM,CAAChB,QAAQ,CAAE;;UAEvC;UACA;UACA,IAAIE,aAAa,CAACe,iBAAiB,EAAE,EAAE;YACnC,IAAI,CAACC,2BAA2B,CAACpB,KAAK,CAAC;UAC3C;QACJ;;QAEA;;QAEA;QACA;QACA;MACJ;IACJ,CAAC;IAnwDG,IAAI,CAACqB,eAAe,CAAC,GAAG,CAAC;IACzB,IAAI,CAACC,SAAS,GAAG,IAAIC,yBAAc,CAAC,IAAI,CAAC;IAEzClD,IAAI,CAACmD,oBAAoB,GAAGnD,IAAI,CAACmD,oBAAoB,IAAIC,4BAAoB,CAACC,aAAa;IAE3F,IAAI,CAACC,IAAI,GAAGzD,MAAM;IAClB,IAAI,CAAC0D,cAAc,GAAG1D,MAAM;;IAE5B;IACA;IACA,IAAI,CAAC2D,YAAY,GAAG,CAAC,IAAIC,kCAAgB,CAAC,IAAI,EAAEzD,IAAI,CAAC,CAAC;IACtD,IAAI,CAACiD,SAAS,CAACS,MAAM,CAAC,IAAI,CAACC,wBAAwB,EAAE,EAAE,CAAClE,SAAS,CAACmE,QAAQ,EAAEnE,SAAS,CAACoE,aAAa,CAAC,CAAC;IAErG,IAAI,CAACC,yBAAyB,EAAE;IAEhC,IAAI,IAAI,CAAC9D,IAAI,CAACmD,oBAAoB,KAAKC,4BAAoB,CAACW,QAAQ,EAAE;MAClE,IAAI,CAACC,gBAAgB,GAAG,EAAE;MAC1B,IAAI,CAAClE,MAAM,CAACmE,KAAK,CAACC,gBAAgB,CAAC,IAAI,CAACrE,MAAM,CAAC,CAACsE,IAAI,CAAEC,MAAM,IAAK;QAC7D,MAAMC,MAAM,GAAG,IAAI,CAACvE,MAAM,CAACwE,cAAc,CAAC;UACtCC,QAAQ,EAAE,KAAK;UACfC,OAAO,EAAE;QACb,CAAC,CAAC;QACFJ,MAAM,CAACpF,OAAO,CAAC,MAAOyF,eAAgC,IAAK;UACvD,MAAM9C,KAAK,GAAG0C,MAAM,CAACI,eAAe,CAAC;UACrC,MAAM3E,MAAM,CAAC4E,oBAAoB,CAAC/C,KAAK,CAAC;UACxCA,KAAK,CAACgD,SAAS,CAACC,wBAAW,CAACC,QAAQ,CAAC;UACrC,IAAI,CAACC,eAAe,CAACnD,KAAK,EAAEA,KAAK,CAACoD,QAAQ,EAAE,CAAE;QAClD,CAAC,CAAC;MACN,CAAC,CAAC;IACN;;IAEA;IACA,IAAI,CAAC,IAAI,CAAC/E,IAAI,CAACgF,eAAe,EAAE;MAC5B,IAAI,CAACC,cAAc,GAAGC,OAAO,CAACC,OAAO,CAAC,KAAK,CAAC;IAChD,CAAC,MAAM;MACH,IAAI,CAACF,cAAc,GAAGhD,SAAS;IACnC;EACJ;EAGA,MAAamD,yBAAyBA,CAAA,EAAyD;IAAA,IAAAC,YAAA;IAC3F,IAAI,IAAI,CAACC,yBAAyB,EAAE;MAChC,OAAO,IAAI,CAACA,yBAAyB;IACzC;IAEA,KAAAD,YAAA,GAAI,IAAI,CAACvF,MAAM,cAAAuF,YAAA,eAAXA,YAAA,CAAaE,eAAe,EAAE,EAAE;MAChC,IAAI;QACA,IAAI,CAACD,yBAAyB,GAAGJ,OAAO,CAACM,GAAG,CAAC,CACzC,IAAI,CAACC,uBAAuB,EAAE,EAC9B,IAAI,CAACA,uBAAuB,CAACC,wBAAgB,CAACC,EAAE,CAAC,CACpD,CAAC;QACF,MAAMnC,YAAY,GAAG,MAAM,IAAI,CAAC8B,yBAAyB;QACzD,IAAI,CAAC7E,mBAAmB,CAACjC,IAAI,CAAC,GAAGgF,YAAY,CAAC;QAC9C,OAAOA,YAAY;MACvB,CAAC,CAAC,OAAOoC,CAAC,EAAE;QACR,IAAI,CAACN,yBAAyB,GAAG,IAAI;QACrC,OAAO,IAAI;MACf;IACJ;IACA,OAAO,IAAI;EACf;;EAEA;AACJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;EACI,MAAaO,qBAAqBA,CAAA,EAAkB;IAChD,IAAI,CAAC,IAAI,CAAC/F,MAAM,CAACgG,eAAe,EAAE,EAAE;IAEpC,MAAMC,kBAAkB,GAAG,IAAI,CAACC,gBAAgB,CAAC,IAAI,CAAClG,MAAM,CAACmG,SAAS,EAAE,EAAG,IAAI,CAAC;IAChF,MAAM7B,MAAM,GAAG,IAAI,CAAC1C,eAAe,EAAE,CAACwE,SAAS,EAAE;IACjD,MAAMC,wBAAwB,GAAG/B,MAAM,CAACgC,SAAS,CAAEC,WAAW,IAAK;MAC/D,OAAOA,WAAW,CAAC1E,KAAK,CAAC2E,QAAQ,KAAKP,kBAAkB;IAC5D,CAAC,CAAC;IAEF,MAAMQ,kBAAkB,GAAGnC,MAAM,CAC5BoC,KAAK,CAACL,wBAAwB,CAAC,CAC/BM,OAAO,EAAE,CACTC,GAAG,CAAE/E,KAAK,IAAK,IAAI,CAAC7B,MAAM,CAAC4E,oBAAoB,CAAC/C,KAAK,EAAE;MAAEgF,OAAO,EAAE;IAAK,CAAC,CAAC,CAAC;IAE/E,MAAMzB,OAAO,CAAC0B,UAAU,CAACL,kBAAkB,CAAC;EAChD;;EAEA;AACJ;AACA;AACA;AACA;EACI,MAAaM,gBAAgBA,CAAA,EAAkB;IAC3C,IAAI,CAAC,IAAI,CAAC/G,MAAM,CAACgG,eAAe,EAAE,EAAE;IAEpC,MAAMS,kBAAkB,GAAG,IAAI,CAAC5C,wBAAwB,EAAE,CACrDjC,eAAe,EAAE,CACjBwE,SAAS,EAAE,CACXM,KAAK,CAAC,CAAC,CAAC,CAAC;IAAA,CACTC,OAAO,EAAE,CACTC,GAAG,CAAE/E,KAAK,IAAK,IAAI,CAAC7B,MAAM,CAAC4E,oBAAoB,CAAC/C,KAAK,EAAE;MAAEgF,OAAO,EAAE;IAAK,CAAC,CAAC,CAAC;IAE/E,MAAMzB,OAAO,CAAC0B,UAAU,CAACL,kBAAkB,CAAC;EAChD;;EAEA;AACJ;AACA;AACA;EACWO,UAAUA,CAAA,EAAkB;IAAA,IAAAC,qBAAA;IAC/B,MAAMC,WAAW,GAAG,IAAI,CAACxF,YAAY,CAACa,cAAc,CAAC4E,iBAAS,CAACC,UAAU,EAAE,EAAE,CAAC;IAC9E,QAAAH,qBAAA,GAAOC,WAAW,aAAXA,WAAW,uBAAXA,WAAW,CAAEG,UAAU,EAAE,CAAC,SAAS,CAAC,cAAAJ,qBAAA,cAAAA,qBAAA,GAAI,IAAI;EACvD;;EAEA;AACJ;AACA;AACA;EACWK,UAAUA,CAAA,EAAW;IAAA,IAAAC,sBAAA;IACxB,MAAML,WAAW,GAAG,IAAI,CAACxF,YAAY,CAACa,cAAc,CAAC4E,iBAAS,CAACC,UAAU,EAAE,EAAE,CAAC;IAC9E,IAAI,CAACF,WAAW,EAAE;MACd,IAAI,CAAC,IAAI,CAACM,iBAAiB,EAAE;QACzBC,cAAM,CAACC,IAAI,CAAC,oBAAoB,GAAG,IAAI,CAAC3H,MAAM,GAAG,uCAAuC,CAAC;QACzF,IAAI,CAACyH,iBAAiB,GAAG,IAAI;MACjC;MACA,OAAO,GAAG;IACd;IACA,QAAAD,sBAAA,GAAOL,WAAW,CAACG,UAAU,EAAE,CAAC,cAAc,CAAC,cAAAE,sBAAA,cAAAA,sBAAA,GAAI,GAAG;EAC1D;;EAEA;AACJ;AACA;AACA;AACA;AACA;EACWI,sBAAsBA,CAAA,EAAkB;IAC3C;IACA;IACA;IACA;IACA;IACA;;IAEA,IAAI,CAACnI,kBAAkB,CAACoI,QAAQ,CAAC,IAAI,CAACN,UAAU,EAAE,CAAC,EAAE;MACjD,OAAOhI,uBAAuB;IAClC;IAEA,OAAO,IAAI;EACf;;EAEA;AACJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;EACI,MAAauI,qBAAqBA,CAAA,EAAiC;IAC/D,MAAMC,YAAY,GAAG,MAAM,IAAI,CAAC9H,MAAM,CAAC+H,eAAe,EAAE;IACxD,IAAIC,UAAU,GAAGF,YAAY,CAAC,iBAAiB,CAAC;IAChD,IAAI,CAACE,UAAU,EAAE;MACbA,UAAU,GAAG;QACT9K,OAAO,EAAEoC,uBAAuB;QAChC2I,SAAS,EAAE,CAAC;MAChB,CAAC;MACD,KAAK,MAAMC,OAAO,IAAI1I,kBAAkB,EAAE;QACtCwI,UAAU,CAACC,SAAS,CAACC,OAAO,CAAC,GAAGC,4BAAoB,CAACC,MAAM;MAC/D;IACJ;IAEA,IAAIC,MAAM,GAAG,IAAI,CAACC,6BAA6B,CAACN,UAAU,CAAC;IAC3D,IAAIK,MAAM,CAACE,MAAM,IAAIF,MAAM,CAACG,YAAY,EAAE;MACtC;MACA;MACA;MACA;MACA;MACA;MACAf,cAAM,CAACC,IAAI,CACP,8DAA8D,GAC1D,4DAA4D,CACnE;MAED,MAAMe,IAAI,GAAG,MAAM,IAAI,CAACzI,MAAM,CAAC+H,eAAe,CAAC,IAAI,CAAC;MACpDC,UAAU,GAAGS,IAAI,CAAC,iBAAiB,CAAC;MACpC,IAAI,CAACT,UAAU,EAAE;QACbP,cAAM,CAACC,IAAI,CAAC,yDAAyD,CAAC;QACtE,OAAOW,MAAM;MACjB,CAAC,MAAM;QACHA,MAAM,GAAG,IAAI,CAACC,6BAA6B,CAACN,UAAU,CAAC;MAC3D;IACJ;IAEA,OAAOK,MAAM;EACjB;EAEQC,6BAA6BA,CAACN,UAAmC,EAAuB;IAC5F,MAAMU,cAAc,GAAG,IAAI,CAACpB,UAAU,EAAE;IACxCG,cAAM,CAACkB,GAAG,CAAE,IAAG,IAAI,CAAC5I,MAAO,sBAAqB2I,cAAe,EAAC,CAAC;IACjEjB,cAAM,CAACkB,GAAG,CAAE,IAAG,IAAI,CAAC5I,MAAO,wBAAuB,EAAEiI,UAAU,CAAC;IAE/D,MAAMK,MAA2B,GAAG;MAChCO,OAAO,EAAEF,cAAc;MACvBF,YAAY,EAAE,KAAK;MACnBD,MAAM,EAAE;IACZ,CAAC;;IAED;IACA,IAAIG,cAAc,KAAKV,UAAU,CAAC9K,OAAO,EAAE,OAAOmL,MAAM;IAExD,MAAMQ,cAAc,GAAGrL,MAAM,CAACY,IAAI,CAAC4J,UAAU,CAACC,SAAS,CAAC,CAAC1J,MAAM,CAAEuK,CAAC,IAAKd,UAAU,CAACC,SAAS,CAACa,CAAC,CAAC,KAAK,QAAQ,CAAC;;IAE5G;IACA;IACA;IACA,IAAI,CAACD,cAAc,CAACjB,QAAQ,CAACc,cAAc,CAAC,EAAE;MAC1CL,MAAM,CAACO,OAAO,GAAGZ,UAAU,CAAC9K,OAAO;MACnCmL,MAAM,CAACG,YAAY,GAAG,IAAI;MAC1BH,MAAM,CAACE,MAAM,GAAG,CAAC,CAAC,IAAI,CAACjB,UAAU,EAAE,CAACyB,KAAK,CAAC,kBAAkB,CAAC;MAC7D,IAAIV,MAAM,CAACE,MAAM,EAAE;QACfd,cAAM,CAACC,IAAI,CAAE,8BAA6B,IAAI,CAAC3H,MAAO,EAAC,CAAC;MAC5D,CAAC,MAAM;QACH0H,cAAM,CAACC,IAAI,CAAE,kCAAiC,IAAI,CAAC3H,MAAO,EAAC,CAAC;MAChE;MACA,OAAOsI,MAAM;IACjB;;IAEA;IACA;IACA,OAAOA,MAAM;EACjB;;EAEA;AACJ;AACA;AACA;AACA;EACWW,kBAAkBA,CAACC,MAAc,EAAW;IAC/C,OAAO,IAAI,CAACvH,YAAY,CAACwH,iBAAiB,CAAC/B,iBAAS,CAACgC,aAAa,EAAEF,MAAM,CAAC;EAC/E;;EAEA;AACJ;AACA;AACA;AACA;AACA;AACA;AACA;EACW7E,gBAAgBA,CAAA,EAAkB;IACrC,IAAI,CAAC,IAAI,CAACF,gBAAgB,EAAE;MACxB,MAAM,IAAIkF,KAAK,CACX,4DAA4D,GAAG,IAAI,CAAClJ,IAAI,CAACmD,oBAAoB,CAChG;IACL;IAEA,OAAO,IAAI,CAACa,gBAAgB;EAChC;;EAEA;AACJ;AACA;AACA;AACA;EACWmF,kBAAkBA,CAACC,OAAe,EAAW;IAChD,IAAI,CAAC,IAAI,CAACpF,gBAAgB,EAAE;MACxB,MAAM,IAAIkF,KAAK,CACX,8DAA8D,GAAG,IAAI,CAAClJ,IAAI,CAACmD,oBAAoB,CAClG;IACL;IAEA,MAAMkG,OAAO,GAAG9N,KAAK,CAAC+N,aAAa,CAC/B,IAAI,CAACtF,gBAAgB,EACrB,UAAUuF,EAAE,EAAE;MACV,OAAOA,EAAE,CAAC/G,KAAK,EAAE,IAAI4G,OAAO;IAChC,CAAC,EACD,KAAK,CACR;IAED,IAAI,CAACI,iBAAiB,EAAE;IAExB,OAAOH,OAAO;EAClB;;EAEA;AACJ;AACA;AACA;AACA;AACA;EACWI,eAAeA,CAACL,OAAe,EAAW;IAAA,IAAAM,qBAAA,EAAAC,sBAAA;IAC7C,QAAAD,qBAAA,IAAAC,sBAAA,GAAO,IAAI,CAAC3F,gBAAgB,cAAA2F,sBAAA,uBAArBA,sBAAA,CAAuBC,IAAI,CAAEjI,KAAK,IAAKA,KAAK,CAACa,KAAK,EAAE,KAAK4G,OAAO,CAAC,cAAAM,qBAAA,cAAAA,qBAAA,GAAI,KAAK;EACrF;;EAEA;AACJ;AACA;AACA;AACA;EACWG,eAAeA,CAACT,OAAe,EAAsB;IAAA,IAAAU,sBAAA,EAAAC,sBAAA;IACxD,QAAAD,sBAAA,IAAAC,sBAAA,GAAO,IAAI,CAAC/F,gBAAgB,cAAA+F,sBAAA,uBAArBA,sBAAA,CAAuBC,IAAI,CAAErI,KAAK,IAAKA,KAAK,CAACa,KAAK,EAAE,KAAK4G,OAAO,CAAC,cAAAU,sBAAA,cAAAA,sBAAA,GAAI,IAAI;EACpF;;EAEA;AACJ;AACA;AACA;AACA;EACWpI,eAAeA,CAAA,EAAkB;IACpC,OAAO,IAAI,CAACiC,wBAAwB,EAAE,CAACjC,eAAe,EAAE;EAC5D;;EAEA;AACJ;AACA;AACA;AACA;EACWuI,sBAAsBA,CAAA,EAAW;IACpC,MAAMC,QAAQ,GAAG,IAAI,CAACxI,eAAe,EAAE;IACvC,MAAM0C,MAAM,GAAG8F,QAAQ,CAAChE,SAAS,EAAE;IACnC,IAAI9B,MAAM,CAACtF,MAAM,EAAE;MACf,MAAMqL,SAAS,GAAG/F,MAAM,CAACA,MAAM,CAACtF,MAAM,GAAG,CAAC,CAAC;MAC3C,OAAOqL,SAAS,CAACC,KAAK,EAAE;IAC5B,CAAC,MAAM;MACH,OAAOC,MAAM,CAACC,gBAAgB;IAClC;EACJ;;EAEA;AACJ;AACA;EACWC,eAAeA,CAAA,EAAW;IAAA,IAAAC,oBAAA;IAC7B,QAAAA,oBAAA,GAAO,IAAI,CAACC,cAAc,cAAAD,oBAAA,cAAAA,oBAAA,GAAI,OAAO;EACzC;;EAEA;AACJ;AACA;AACA;AACA;EACWE,YAAYA,CAAA,EAAuB;IACtC,MAAMC,EAAE,GAAG,IAAI,CAACC,SAAS,CAAC,IAAI,CAAC7K,QAAQ,CAAC;IACxC,IAAI4K,EAAE,EAAE;MACJ,OAAOA,EAAE,CAACD,YAAY,EAAE;IAC5B;IAEA,IAAI,IAAI,CAACD,cAAc,KAAK,QAAQ,EAAE;MAClC;MACA,MAAMI,WAAW,GAAG,IAAI,CAACC,8BAA8B,EAAE;MACzD,IAAID,WAAW,KAAK,CAAC,EAAE;QAAA,IAAAE,mBAAA;QACnB,QAAAA,mBAAA,GAAO,IAAI,CAACC,aAAa,cAAAD,mBAAA,uBAAlBA,mBAAA,CAAqB,CAAC,CAAC;MAClC;IACJ;EACJ;;EAEA;AACJ;AACA;AACA;EACWE,aAAaA,CAAA,EAAW;IAC3B,MAAMN,EAAE,GAAG,IAAI,CAACC,SAAS,CAAC,IAAI,CAAC7K,QAAQ,CAAC;IACxC,IAAI4K,EAAE,EAAE;MACJ,MAAMO,SAAS,GAAGP,EAAE,CAACD,YAAY,EAAE;MACnC,IAAIQ,SAAS,EAAE;QACX,OAAOA,SAAS;MACpB;IACJ;IACA;IACA,IAAIC,KAAK,CAACC,OAAO,CAAC,IAAI,CAACJ,aAAa,CAAC,IAAI,IAAI,CAACA,aAAa,CAAClM,MAAM,EAAE;MAChE,OAAO,IAAI,CAACkM,aAAa,CAAC,CAAC,CAAC;IAChC;IACA,MAAMK,OAAO,GAAG,IAAI,CAAC7J,YAAY,CAAC8J,UAAU,EAAE;IAC9C,MAAMC,SAAS,GAAGF,OAAO,CAACrB,IAAI,CAAEwB,CAAC,IAAKA,CAAC,CAACzC,MAAM,KAAK,IAAI,CAAChJ,QAAQ,CAAC;IACjE,IAAIwL,SAAS,EAAE;MACX,OAAOA,SAAS,CAACxC,MAAM;IAC3B;IACA;IACA;IACA;IACA,OAAO,IAAI,CAAChJ,QAAQ;EACxB;EAEO0L,uBAAuBA,CAAA,EAA2B;IACrD,MAAMZ,WAAW,GAAG,IAAI,CAACC,8BAA8B,EAAE;IACzD,IAAID,WAAW,GAAG,CAAC,EAAE;MACjB;IACJ;IACA,MAAMa,SAAS,GAAGP,KAAK,CAACC,OAAO,CAAC,IAAI,CAACJ,aAAa,CAAC,IAAI,IAAI,CAACA,aAAa,CAAClM,MAAM;IAChF,IAAI4M,SAAS,EAAE;MACX,MAAMC,eAAe,GAAG,IAAI,CAACX,aAAa,CAAEtE,GAAG,CAAEqC,MAAM,IAAK;QACxD,OAAO,IAAI,CAAC6B,SAAS,CAAC7B,MAAM,CAAC;MACjC,CAAC,CAAC,CAACiB,IAAI,CAAE4B,MAAM,IAAK,CAAC,CAACA,MAAM,CAAC;MAC7B,IAAID,eAAe,EAAE;QACjB,OAAOA,eAAe;MAC1B;IACJ;IACA,MAAMN,OAAO,GAAG,IAAI,CAAC7J,YAAY,CAAC8J,UAAU,EAAE;IAC9C;IACA;IACA,IAAID,OAAO,CAACvM,MAAM,IAAI,CAAC,EAAE;MACrB,MAAM6M,eAAe,GAAGN,OAAO,CAACrB,IAAI,CAAEwB,CAAC,IAAK;QACxC,OAAOA,CAAC,CAACzC,MAAM,KAAK,IAAI,CAAChJ,QAAQ;MACrC,CAAC,CAAC;MACF,IAAI4L,eAAe,EAAE;QACjB,OAAOA,eAAe;MAC1B;IACJ;IACA;IACA;IACA,IAAID,SAAS,EAAE;MACX,MAAMG,aAAa,GAAG,IAAI,CAACb,aAAa,CAAEtE,GAAG,CAAEqC,MAAM,IAAK;QACtD,OAAO,IAAI,CAACjJ,MAAM,CAACgM,OAAO,CAAC/C,MAAM,CAAC;MACtC,CAAC,CAAC,CAACiB,IAAI,CAAE+B,IAAI,IAAK,CAAC,CAACA,IAAI,CAAC;MACzB,IAAIF,aAAa,EAAE;QACf,MAAMD,MAAM,GAAG,IAAII,sBAAU,CAAC,IAAI,CAACnM,MAAM,EAAEgM,aAAa,CAAC9C,MAAM,CAAC;QAChE6C,MAAM,CAACG,IAAI,GAAGF,aAAa;QAC3B,OAAOD,MAAM;MACjB;IACJ;EACJ;;EAEA;AACJ;AACA;AACA;EACWK,kBAAkBA,CAACC,UAAkB,EAAQ;IAChD,MAAMC,cAAc,GAAG,IAAI,CAAC1B,cAAc;IAC1C,IAAI,CAACA,cAAc,GAAGyB,UAAU;IAChC,IAAIC,cAAc,KAAKD,UAAU,EAAE;MAC/B,IAAIA,UAAU,KAAK,OAAO,EAAE;QACxB,IAAI,CAACE,mBAAmB,EAAE;MAC9B;MACA,IAAI,CAAC1J,IAAI,CAACjD,SAAS,CAAC4M,YAAY,EAAE,IAAI,EAAEH,UAAU,EAAEC,cAAc,CAAC;IACvE;EACJ;EAEA,MAAcG,qBAAqBA,CAAA,EAAqC;IACpE,MAAMC,aAAa,GAAG,IAAI,CAACzM,MAAM,CAACmE,KAAK,CAACuI,YAAY,EAAE;IACtD,MAAMC,QAAQ,GAAG,MAAM,IAAI,CAAC3M,MAAM,CAACuL,OAAO,CAAC,IAAI,CAACxL,MAAM,EAAEoC,SAAS,EAAE,OAAO,EAAEsK,aAAa,aAAbA,aAAa,cAAbA,aAAa,GAAItK,SAAS,CAAC;IACvG,OAAOwK,QAAQ,CAACC,KAAK;EACzB;EAEA,MAAcC,WAAWA,CAAA,EAAkE;IACvF;IACA,IAAIC,UAAU,GAAG,KAAK;IACtB,IAAIC,gBAAgB,GAAG,MAAM,IAAI,CAAC/M,MAAM,CAACmE,KAAK,CAAC6I,mBAAmB,CAAC,IAAI,CAACjN,MAAM,CAAC;IAC/E;IACA;IACA;IACA;IACA;IACA,IAAIgN,gBAAgB,KAAK,IAAI,IAAK,IAAI,CAAC/M,MAAM,CAACgG,eAAe,EAAE,IAAI,IAAI,CAAChG,MAAM,CAACiN,eAAe,CAAC,IAAI,CAAClN,MAAM,CAAE,EAAE;MAC1G+M,UAAU,GAAG,IAAI;MACjBC,gBAAgB,GAAG,MAAM,IAAI,CAACP,qBAAqB,EAAE;MACrD/E,cAAM,CAACkB,GAAG,CAAE,WAAUoE,gBAAgB,CAAC/N,MAAO,GAAE,GAAI,gCAA+B,IAAI,CAACe,MAAO,EAAC,CAAC;IACrG;IACA,MAAMmN,YAAY,GAAGH,gBAAgB,CAACxO,MAAM,CAAC4O,wBAAkB,CAAC,CAACvG,GAAG,CAAC,IAAI,CAAC5G,MAAM,CAACwE,cAAc,EAAE,CAAC;IAClG,OAAO;MAAE0I,YAAY;MAAEJ;IAAW,CAAC;EACvC;;EAEA;AACJ;AACA;AACA;AACA;AACA;EACWM,aAAaA,CAAA,EAAY;IAC5B,IAAI,CAAC,IAAI,CAAClN,IAAI,CAACgF,eAAe,EAAE;MAC5B,OAAO,IAAI;IACf;IAEA,OAAO,IAAI,CAACxD,YAAY,CAAC2L,qBAAqB,EAAE;EACpD;;EAEA;AACJ;AACA;AACA;AACA;AACA;AACA;AACA;EACWC,mBAAmBA,CAAA,EAAqB;IAC3C,IAAI,IAAI,CAACnI,cAAc,EAAE;MACrB,OAAO,IAAI,CAACA,cAAc;IAC9B;;IAEA;IACA;IACA;IACA,IAAI,CAACzD,YAAY,CAAC6L,2BAA2B,EAAE;IAE/C,MAAMC,cAAc,GAAG,IAAI,CAACX,WAAW,EAAE,CACpCxI,IAAI,CAAEgE,MAAM,IAAK;MACd,IAAI,CAAC3G,YAAY,CAAC+L,mBAAmB,CAACpF,MAAM,CAAC6E,YAAY,CAAC;MAC1D,OAAO7E,MAAM,CAACyE,UAAU;IAC5B,CAAC,CAAC,CACDY,KAAK,CAAEC,GAAG,IAAK;MACZ;MACA,IAAI,CAACxI,cAAc,GAAGhD,SAAS;MAC/B,IAAI,CAACT,YAAY,CAACkM,0BAA0B,EAAE;MAC9C,MAAMD,GAAG;IACb,CAAC,CAAC;IACN;IACAH,cAAc,CACTnJ,IAAI,CAAEyI,UAAU,IAAK;MAClB,IAAIA,UAAU,EAAE;QACZ,MAAMe,UAAU,GAAG,IAAI,CAACnM,YAAY,CAC/B8J,UAAU,EAAE,CACZjN,MAAM,CAAEmN,CAAC,IAAKA,CAAC,CAACoC,WAAW,EAAE,CAAC,CAC9BlH,GAAG,CAAE8E,CAAC;UAAA,IAAAqC,gBAAA;UAAA,QAAAA,gBAAA,GAAKrC,CAAC,CAACpH,MAAM,CAACwH,MAAM,cAAAiC,gBAAA,uBAAfA,gBAAA,CAAiBlM,KAAK;QAAA,CAAyB,CAAC;QAChE4F,cAAM,CAACkB,GAAG,CAAE,8BAA6BkF,UAAU,CAAC7O,MAAO,EAAC,GAAI,qBAAoB,IAAI,CAACe,MAAO,EAAC,CAAC;QAClG,MAAMoE,KAAK,GAAG,IAAI,CAACnE,MAAM,CAACmE,KAAK;QAC/B,OACIA,KAAK,CACAsJ,mBAAmB,CAAC,IAAI,CAAC1N,MAAM,EAAE8N,UAAU;QAC5C;QACA;QAAA,CACCH,KAAK,CAAEC,GAAG,IAAK;UACZlG,cAAM,CAACkB,GAAG,CAAC,8CAA8C,EAAEgF,GAAG,CAAC;QACnE,CAAC,CAAC;MAEd;IACJ,CAAC,CAAC,CACDD,KAAK,CAAEC,GAAG,IAAK;MACZ;MACA;MACAlG,cAAM,CAACuG,KAAK,CAACL,GAAG,CAAC;IACrB,CAAC,CAAC;IAEN,IAAI,CAACxI,cAAc,GAAGqI,cAAc;IAEpC,OAAO,IAAI,CAACrI,cAAc;EAC9B;;EAEA;AACJ;AACA;EACI,MAAa8I,0BAA0BA,CAAA,EAAkB;IACrD,IAAI,IAAI,CAAC/N,IAAI,CAACgF,eAAe,IAAI,IAAI,CAACC,cAAc,EAAE;MAClD,MAAM,IAAI,CAACmI,mBAAmB,EAAE;MAChC,MAAM,IAAI,CAACtN,MAAM,CAACmE,KAAK,CAAC+J,qBAAqB,CAAC,IAAI,CAACnO,MAAM,CAAC;MAC1D,IAAI,CAAC2B,YAAY,CAACwM,qBAAqB,EAAE;MACzC,IAAI,CAAC/I,cAAc,GAAGhD,SAAS;IACnC;EACJ;;EAEA;AACJ;AACA;AACA;EACYmK,mBAAmBA,CAAA,EAAS;IAChC,IAAI,CAAC2B,0BAA0B,EAAE,CAACP,KAAK,CAAEC,GAAG,IAAK;MAC7ClG,cAAM,CAACuG,KAAK,CAAE,2CAA0C,GAAI,QAAO,IAAI,CAACjO,MAAO,gBAAe,CAAC;MAC/F0H,cAAM,CAACkB,GAAG,CAACgF,GAAG,CAAC;IACnB,CAAC,CAAC;EACN;;EAEA;AACJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;EACI,MAAaQ,mBAAmBA,CAAA,EAAkB;IAC9C,MAAMC,kBAAkB,GAAG,IAAI,CAACxM,eAAe,EAAE;IACjD,MAAMyM,sBAAsB,GAAGD,kBAAkB,CAACE,kBAAkB,CAACC,4BAAa,CAACC,QAAQ,CAAC;IAC5F,MAAMC,uBAAuB,GAAGL,kBAAkB,CAACE,kBAAkB,CAACC,4BAAa,CAACG,SAAS,CAAC;IAC9F,MAAMC,YAAY,GAAGP,kBAAkB,CAAChI,SAAS,EAAE;IACnD,MAAMwI,yBAAyB,GAAGD,YAAY,CAACA,YAAY,CAAC3P,MAAM,GAAG,CAAC,CAAC;IACvEyI,cAAM,CAACkB,GAAG,CACL,4BAA2B,IAAI,CAAC5I,MAAO,OAAM,GACzC,6BAA4B6O,yBAAyB,IAAIA,yBAAyB,CAAClM,KAAK,EAAG,GAAE,GAC7F,sBAAqB0L,kBAAkB,CAACS,QAAQ,EAAG,GAAE,GACrD,0BAAyBR,sBAAuB,GAAE,GAClD,2BAA0BI,uBAAwB,EAAC,CAC3D;;IAED;IACA,MAAM3N,WAAW,GAAG,IAAI,CAAC+C,wBAAwB,EAAE;IAEnD,IAAIiL,WAAoC;IACxC;IACA;IACA;IACA;IACA;IACA;IACA,IAAI,CAACF,yBAAyB,EAAE;MAC5BE,WAAW,GAAG,MAAM,IAAI,CAAC9O,MAAM,CAAC+O,iBAAiB,CAACjO,WAAW,CAAC;IAClE,CAAC,MAAM;MACH;MACA;MACA;MACA;MACA;MACA;MACA;MACA,IAAI,CAACkO,iBAAiB,CAAC,IAAI,EAAE,IAAI,CAAC;;MAElC;MACA;MACA;MACA;MACA;MACA,IAAI,CAACpM,IAAI,CAACjD,SAAS,CAACsP,eAAe,EAAE,IAAI,EAAEnO,WAAW,CAAC;;MAEvD;MACA;MACA;MACA;MACA;MACAgO,WAAW,GAAG,MAAM,IAAI,CAAC9O,MAAM,CAACkP,gBAAgB,CAACpO,WAAW,EAAE8N,yBAAyB,CAAClM,KAAK,EAAE,CAAE;IACrG;;IAEA;IACA;IACA;IACA,MAAMyM,YAAY,GAAGrO,WAAW,CAACc,eAAe,EAAE;IAClD,IACI,CAACuN,YAAY,IACZA,YAAY,CAACb,kBAAkB,CAACc,wBAAS,CAACC,OAAO,CAAC,KAAK,IAAI,IACxDF,YAAY,CAACb,kBAAkB,CAACc,wBAAS,CAACE,QAAQ,CAAC,KAAK,IAAI,IAC5DH,YAAY,CAAC/I,SAAS,EAAE,CAACpH,MAAM,KAAK,CAAE,EAC5C;MACEyI,cAAM,CAACkB,GAAG,CAAE,4BAA2B,IAAI,CAAC5I,MAAO,+BAA8B,CAAC;MAClF;MACA;MACA;MACA;MACA+O,WAAW,CAAES,kBAAkB,CAAClB,sBAAsB,EAAEE,4BAAa,CAACC,QAAQ,CAAC;;MAE/E;MACA;MACA1N,WAAW,CAAC0O,eAAe,CAACV,WAAW,CAAE;MACzC;MACA;MACA,IAAI,CAAC9K,yBAAyB,EAAE;IACpC,CAAC,MAAM;MACHyD,cAAM,CAACkB,GAAG,CACL,4BAA2B,IAAI,CAAC5I,MAAO,8DAA6D,GAChG,kGAAiG,GACjG,yCAAwC,CAChD;IACL;;IAEA;IACA,IAAI,CAAC0P,uBAAuB,CAAC,KAAK,CAAC;;IAEnC;IACA;IACA,IAAI,CAAC7M,IAAI,CAACjD,SAAS,CAACsP,eAAe,EAAE,IAAI,EAAEnO,WAAW,CAAC;EAC3D;;EAEA;AACJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;EACWkO,iBAAiBA,CAACU,mBAAmC,EAAErB,sBAAsC,EAAQ;IACxG,KAAK,MAAMvN,WAAW,IAAI,IAAI,CAAC4C,YAAY,EAAE;MACzC5C,WAAW,CAACkO,iBAAiB,CAACU,mBAAmB,aAAnBA,mBAAmB,cAAnBA,mBAAmB,GAAIvN,SAAS,EAAEkM,sBAAsB,aAAtBA,sBAAsB,cAAtBA,sBAAsB,GAAIlM,SAAS,CAAC;IACxG;IACA,KAAK,MAAM7B,MAAM,IAAI,IAAI,CAACqP,OAAO,CAACC,MAAM,EAAE,EAAE;MACxCtP,MAAM,CAAC0O,iBAAiB,CAACU,mBAAmB,EAAErB,sBAAsB,CAAC;IACzE;IAEA,IAAI,CAACrK,yBAAyB,EAAE;EACpC;;EAEA;AACJ;AACA;AACA;AACA;EACYA,yBAAyBA,CAAA,EAAS;IACtC,MAAM6L,gBAAgB,GAAG,IAAI,CAACC,QAAQ;IACtC,MAAMC,oBAAoB,GAAG,IAAI,CAACrO,YAAY;;IAE9C;IACA;IACA;IACA;IACA,IAAI,CAAC0I,QAAQ,GAAG,IAAI,CAACxI,eAAe,EAAE,CAACwE,SAAS,EAAE;IAClD,IAAI,CAAC0J,QAAQ,GAAG,IAAI,CAAClO,eAAe,EAAE,CAACoO,QAAQ,CAACzB,4BAAa,CAACG,SAAS,CAAE;IACzE,IAAI,CAAChN,YAAY,GAAG,IAAI,CAACE,eAAe,EAAE,CAACoO,QAAQ,CAACzB,4BAAa,CAACC,QAAQ,CAAE;;IAE5E;IACA;IACA;IACA,IAAIqB,gBAAgB,KAAK,IAAI,CAACC,QAAQ,EAAE;MACpC,IAAI,CAAClN,IAAI,CAACjD,SAAS,CAACsQ,eAAe,EAAE,IAAI,EAAEJ,gBAAgB,EAAE,IAAI,CAACC,QAAQ,CAAC;IAC/E;IAEA,IAAIC,oBAAoB,KAAK,IAAI,CAACrO,YAAY,EAAE;MAC5C,IAAI,CAACkB,IAAI,CAACjD,SAAS,CAACuQ,mBAAmB,EAAE,IAAI,EAAEH,oBAAoB,EAAE,IAAI,CAACrO,YAAY,CAAC;;MAEvF;MACA;MACA;MACA,IAAI,CAACyB,SAAS,CAACgN,cAAc,CAACJ,oBAAoB,EAAE,CAChDK,yBAAc,CAACC,MAAM,EACrBD,yBAAc,CAACE,OAAO,EACtBF,yBAAc,CAACG,SAAS,EACxBH,yBAAc,CAACI,MAAM,EACrBJ,yBAAc,CAACK,MAAM,EACrBC,mBAAW,CAACC,GAAG,EACfD,mBAAW,CAACF,MAAM,EAClBE,mBAAW,CAACE,OAAO,EACnBF,mBAAW,CAACG,cAAc,CAC7B,CAAC;MACF,IAAI,CAAC1N,SAAS,CAACS,MAAM,CAAC,IAAI,CAAClC,YAAY,EAAE,CACrC0O,yBAAc,CAACC,MAAM,EACrBD,yBAAc,CAACE,OAAO,EACtBF,yBAAc,CAACG,SAAS,EACxBH,yBAAc,CAACI,MAAM,EACrBJ,yBAAc,CAACK,MAAM,EACrBC,mBAAW,CAACC,GAAG,EACfD,mBAAW,CAACF,MAAM,EAClBE,mBAAW,CAACE,OAAO,EACnBF,mBAAW,CAACG,cAAc,CAC7B,CAAC;IACN;EACJ;;EAEA;AACJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;EACI,MAAaC,oBAAoBA,CAAA,EAAqB;IAClD,IAAI,CAAC,IAAI,CAAC9Q,MAAM,CAACiN,eAAe,CAAC,IAAI,CAAClN,MAAM,CAAC,EAAE;MAC3C,OAAO,KAAK;IAChB;IACA,MAAMgR,UAAU,GAAG,MAAM,IAAI,CAACC,0BAA0B,EAAE;IAC1D,KAAK,MAAMlF,MAAM,IAAIiF,UAAU,EAAE;MAC7B,MAAME,OAAO,GAAG,IAAI,CAACjR,MAAM,CAACkR,uBAAuB,CAACpF,MAAM,CAAC7C,MAAM,CAAC;MAClE,IAAIgI,OAAO,CAACnH,IAAI,CAAEqH,MAAM,IAAKA,MAAM,CAACC,YAAY,EAAE,CAAC,EAAE;QACjD,OAAO,IAAI;MACf;IACJ;IACA,OAAO,KAAK;EAChB;;EAEA;AACJ;AACA;AACA;EACWC,eAAeA,CAAA,EAAuB;IACzC,OAAO,IAAI,CAAC3N,YAAY;EAC5B;;EAEA;AACJ;AACA;AACA;EACWG,wBAAwBA,CAAA,EAAqB;IAChD,OAAO,IAAI,CAACH,YAAY,CAAC,CAAC,CAAC;EAC/B;;EAEA;AACJ;AACA;AACA;AACA;AACA;AACA;EACW4N,mBAAmBA,CAAChI,OAAe,EAAwB;IAC9D,MAAMzH,KAAK,GAAG,IAAI,CAACK,aAAa,CAACoH,OAAO,CAAC;IACzC,MAAMhJ,MAAM,GAAG,IAAI,CAACiR,kBAAkB,CAAC1P,KAAK,CAAC;IAC7C,IAAIvB,MAAM,EAAE;MACR,OAAOA,MAAM,CAACQ,WAAW,CAACwQ,mBAAmB,CAAChI,OAAO,CAAC;IAC1D,CAAC,MAAM;MACH,OAAO,IAAI,CAACzF,wBAAwB,EAAE,CAACyN,mBAAmB,CAAChI,OAAO,CAAC;IACvE;EACJ;;EAEA;AACJ;AACA;AACA;AACA;EACWkI,WAAWA,CAAA,EAAkB;IAChC,OAAO,IAAI,CAAC3N,wBAAwB,EAAE,CAAC2N,WAAW,EAAE;EACxD;;EAEA;AACJ;AACA;AACA;AACA;EACW/B,uBAAuBA,CAACgC,KAAc,EAAQ;IACjD,IAAI,CAACC,oBAAoB,GAAGD,KAAK;EACrC;;EAEA;AACJ;AACA;AACA;AACA;EACWE,uBAAuBA,CAAA,EAAY;IACtC,OAAO,IAAI,CAACD,oBAAoB;EACpC;;EAEA;AACJ;AACA;AACA;AACA;AACA;EACWxP,aAAaA,CAACoH,OAAe,EAA2B;IAC3D,IAAIzH,KAAK,GAAG,IAAI,CAACgC,wBAAwB,EAAE,CAAC3B,aAAa,CAACoH,OAAO,CAAC;IAElE,IAAI,CAACzH,KAAK,EAAE;MACR,MAAM8N,OAAO,GAAG,IAAI,CAACiC,UAAU,EAAE;MACjC,KAAK,IAAI9S,CAAC,GAAG,CAAC,EAAEA,CAAC,GAAG6Q,OAAO,CAAC3Q,MAAM,EAAEF,CAAC,EAAE,EAAE;QACrC,MAAMwB,MAAM,GAAGqP,OAAO,CAAC7Q,CAAC,CAAC;QACzB+C,KAAK,GAAGvB,MAAM,CAAC4B,aAAa,CAACoH,OAAO,CAAC;QACrC,IAAIzH,KAAK,EAAE;UACP,OAAOA,KAAK;QAChB;MACJ;IACJ;IAEA,OAAOA,KAAK;EAChB;;EAEA;AACJ;AACA;AACA;AACA;AACA;EACWgQ,0BAA0BA,CAACC,IAAI,GAAGpS,qBAAqB,CAACqS,KAAK,EAAU;IAC1E,IAAIC,KAAK,GAAG,IAAI,CAACC,8BAA8B,CAACH,IAAI,CAAC;IACrD,KAAK,MAAMI,kBAAkB,IAAI,IAAI,CAACC,mBAAmB,CAACvC,MAAM,EAAE,EAAE;MAAA,IAAAwC,qBAAA;MAChEJ,KAAK,KAAAI,qBAAA,GAAIF,kBAAkB,CAACJ,IAAI,CAAC,cAAAM,qBAAA,cAAAA,qBAAA,GAAI,CAAC;IAC1C;IACA,OAAOJ,KAAK;EAChB;;EAEA;AACJ;AACA;EACWK,6BAA6BA,CAACP,IAAI,GAAGpS,qBAAqB,CAACqS,KAAK,EAAElQ,KAAkB,EAAU;IAAA,IAAAyQ,IAAA;IACjG,MAAMC,aAAa,GAAG,CAAC,CAAC1Q,KAAK,CAAC2Q,YAAY,IAAI,CAAC3Q,KAAK,CAAC4Q,YAAY;IAEjE,QAAAH,IAAA,GACKC,aAAa,GACR,IAAI,CAACG,gCAAgC,CAAC7Q,KAAK,CAAC2Q,YAAY,EAAEV,IAAI,CAAC,GAC/D,IAAI,CAACG,8BAA8B,CAACH,IAAI,CAAC,cAAAQ,IAAA,cAAAA,IAAA,GAAK,CAAC;EAE7D;;EAEA;AACJ;AACA;AACA;AACA;AACA;EACWL,8BAA8BA,CAACH,IAAI,GAAGpS,qBAAqB,CAACqS,KAAK,EAAU;IAAA,IAAAY,qBAAA;IAC9E,QAAAA,qBAAA,GAAO,IAAI,CAACC,kBAAkB,CAACd,IAAI,CAAC,cAAAa,qBAAA,cAAAA,qBAAA,GAAI,CAAC;EAC7C;;EAEA;AACJ;AACA;AACA;AACA;AACA;AACA;EACWD,gCAAgCA,CAACG,QAAgB,EAAEf,IAAI,GAAGpS,qBAAqB,CAACqS,KAAK,EAAU;IAAA,IAAAe,qBAAA,EAAAC,sBAAA;IAClG,QAAAD,qBAAA,IAAAC,sBAAA,GAAO,IAAI,CAACZ,mBAAmB,CAAC9U,GAAG,CAACwV,QAAQ,CAAC,cAAAE,sBAAA,uBAAtCA,sBAAA,CAAyCjB,IAAI,CAAC,cAAAgB,qBAAA,cAAAA,qBAAA,GAAI,CAAC;EAC9D;;EAEA;AACJ;AACA;AACA;EACWE,2BAA2BA,CAAA,EAAY;IAC1C,KAAK,MAAMC,YAAY,IAAI,IAAI,CAACd,mBAAmB,CAACvC,MAAM,EAAE,EAAE;MAAA,IAAAsD,qBAAA,EAAAC,mBAAA;MAC1D,IAAI,EAAAD,qBAAA,GAACD,YAAY,CAACG,SAAS,cAAAF,qBAAA,cAAAA,qBAAA,GAAI,CAAC,IAAI,CAAC,IAAI,EAAAC,mBAAA,GAACF,YAAY,CAACI,KAAK,cAAAF,mBAAA,cAAAA,mBAAA,GAAI,CAAC,IAAI,CAAC,EAAE;QACpE,OAAO,IAAI;MACf;IACJ;IACA,OAAO,KAAK;EAChB;;EAEA;AACJ;AACA;AACA;AACA;AACA;EACWG,gCAAgCA,CAACT,QAAgB,EAAEf,IAA2B,EAAEE,KAAa,EAAQ;IAAA,IAAAuB,sBAAA,EAAAC,sBAAA;IACxG,MAAMP,YAA+B,GAAArU,aAAA;MACjCwU,SAAS,GAAAG,sBAAA,GAAE,IAAI,CAACpB,mBAAmB,CAAC9U,GAAG,CAACwV,QAAQ,CAAC,cAAAU,sBAAA,uBAAtCA,sBAAA,CAAwCH,SAAS;MAC5DC,KAAK,GAAAG,sBAAA,GAAE,IAAI,CAACrB,mBAAmB,CAAC9U,GAAG,CAACwV,QAAQ,CAAC,cAAAW,sBAAA,uBAAtCA,sBAAA,CAAwCH;IAAK,GACjD;MACC,CAACvB,IAAI,GAAGE;IACZ,CAAC,CACJ;IAED,IAAI,CAACG,mBAAmB,CAACnU,GAAG,CAAC6U,QAAQ,EAAEI,YAAY,CAAC;IAEpD,IAAI,CAACrQ,IAAI,CAACjD,SAAS,CAAC8T,mBAAmB,EAAER,YAAY,EAAEJ,QAAQ,CAAC;EACpE;;EAEA;AACJ;AACA;EACI,IAAWa,gCAAgCA,CAAA,EAAiC;IACxE,IAAI5B,IAAkC,GAAG,IAAI;IAC7C,KAAK,MAAMI,kBAAkB,IAAI,IAAI,CAACC,mBAAmB,CAACvC,MAAM,EAAE,EAAE;MAAA,IAAA+D,qBAAA,EAAAC,sBAAA;MAChE,IAAI,EAAAD,qBAAA,GAACzB,kBAAkB,CAACkB,SAAS,cAAAO,qBAAA,cAAAA,qBAAA,GAAI,CAAC,IAAI,CAAC,EAAE;QACzC,OAAOjU,qBAAqB,CAACmU,SAAS;MAC1C,CAAC,MAAM,IAAI,EAAAD,sBAAA,GAAC1B,kBAAkB,CAACmB,KAAK,cAAAO,sBAAA,cAAAA,sBAAA,GAAI,CAAC,IAAI,CAAC,IAAI,CAAC9B,IAAI,EAAE;QACrDA,IAAI,GAAGpS,qBAAqB,CAACqS,KAAK;MACtC;IACJ;IACA,OAAOD,IAAI;EACf;;EAEA;AACJ;AACA;EACWgC,kCAAkCA,CAACC,mBAA8B,EAAQ;IAC5E,IAAIA,mBAAmB,EAAE;MACrB,KAAK,MAAM,CAAClB,QAAQ,CAAC,IAAI,IAAI,CAACV,mBAAmB,EAAE;QAC/C,IAAI,CAAC4B,mBAAmB,CAACnM,QAAQ,CAACiL,QAAQ,CAAC,EAAE;UACzC,IAAI,CAACV,mBAAmB,CAACpP,MAAM,CAAC8P,QAAQ,CAAC;QAC7C;MACJ;IACJ,CAAC,MAAM;MACH,IAAI,CAACV,mBAAmB,CAAC6B,KAAK,EAAE;IACpC;IACA,IAAI,CAACpR,IAAI,CAACjD,SAAS,CAAC8T,mBAAmB,CAAC;EAC5C;;EAEA;AACJ;AACA;AACA;AACA;EACWQ,0BAA0BA,CAACnC,IAA2B,EAAEE,KAAa,EAAQ;IAChF,IAAI,CAACY,kBAAkB,CAACd,IAAI,CAAC,GAAGE,KAAK;IACrC,IAAI,CAACpP,IAAI,CAACjD,SAAS,CAAC8T,mBAAmB,EAAE,IAAI,CAACb,kBAAkB,CAAC;EACrE;EAEOsB,SAASA,CAACpC,IAA2B,EAAEE,KAAa,EAAQ;IAC/D,OAAO,IAAI,CAACiC,0BAA0B,CAACnC,IAAI,EAAEE,KAAK,CAAC;EACvD;EAEOmC,UAAUA,CAACC,OAAqB,EAAQ;IAC3C,MAAMC,MAAM,GAAGD,OAAO,CAAC,UAAU,CAAC;IAClC,MAAME,WAAW,GAAGF,OAAO,CAAC,uBAAuB,CAAC;IACpD,MAAMG,YAAY,GAAGH,OAAO,CAAC,wBAAwB,CAAC;IACtD,IAAI7J,MAAM,CAACiK,SAAS,CAACF,WAAW,CAAC,EAAE;MAC/B,IAAI,CAAC5S,YAAY,CAAC+S,oBAAoB,CAACH,WAAW,CAAE;IACxD;IACA,IAAI/J,MAAM,CAACiK,SAAS,CAACD,YAAY,CAAC,EAAE;MAChC,IAAI,CAAC7S,YAAY,CAACgT,qBAAqB,CAACH,YAAY,CAAE;IAC1D;IACA,IAAIlJ,KAAK,CAACC,OAAO,CAAC+I,MAAM,CAAC,EAAE;MACvB;MACA;MACA;MACA,IAAI,CAACnJ,aAAa,GAAGmJ,MAAM,CAAC9V,MAAM,CAAE0K,MAAM,IAAK;QAC3C,OAAOA,MAAM,KAAK,IAAI,CAAChJ,QAAQ;MACnC,CAAC,CAAC;IACN;EACJ;;EAEA;AACJ;AACA;AACA;AACA;EACW0U,6BAA6BA,CAAClD,KAAc,EAAQ;IACvD,IAAI,CAACmD,0BAA0B,GAAGnD,KAAK;EAC3C;;EAEA;AACJ;AACA;AACA;AACA;EACWoD,6BAA6BA,CAAA,EAAmB;IACnD,IAAI,IAAI,CAACD,0BAA0B,KAAKzS,SAAS,EAAE,OAAO,IAAI;IAC9D,OAAO,IAAI,CAACyS,0BAA0B;EAC1C;;EAEA;AACJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;EACWE,YAAYA,CACfC,OAAe,EACfC,KAAa,EACbC,MAAc,EACdC,YAA0B,EAC1BC,YAAY,GAAG,IAAI,EACN;IACb,MAAMC,eAAe,GAAG,IAAI,CAAC1T,YAAY,CAACa,cAAc,CAAC4E,iBAAS,CAACkO,UAAU,EAAE,EAAE,CAAC;IAClF,IAAI,CAACD,eAAe,IAAI,CAACD,YAAY,EAAE;MACnC,OAAO,IAAI;IACf;IAEA,MAAMG,OAAO,GAAGF,eAAe,GAAGA,eAAe,CAAC/N,UAAU,EAAE,CAACkO,GAAG,GAAG,IAAI;IACzE,IAAID,OAAO,EAAE;MACT,OAAO,IAAAE,6BAAgB,EAACT,OAAO,EAAEO,OAAO,EAAEN,KAAK,EAAEC,MAAM,EAAEC,YAAY,CAAC;IAC1E;IAEA,OAAO,IAAI;EACf;;EAEA;AACJ;AACA;AACA;EACWO,eAAeA,CAAA,EAAkB;IAAA,IAAAC,qBAAA,EAAAC,sBAAA;IACpC,OAAO,EAAAD,qBAAA,OAAI,CAAChU,YAAY,CAACa,cAAc,CAAC4E,iBAAS,CAACkO,UAAU,EAAE,EAAE,CAAC,cAAAK,qBAAA,wBAAAC,sBAAA,GAA1DD,qBAAA,CAA4DrO,UAAU,EAAE,cAAAsO,sBAAA,uBAAxEA,sBAAA,CAA0EJ,GAAG,KAAI,IAAI;EAChG;;EAEA;AACJ;AACA;AACA;AACA;AACA;EACWK,iBAAiBA,CAAA,EAAkB;IACtC,MAAMC,cAAc,GAAG,IAAI,CAACnU,YAAY,CAACa,cAAc,CAAC4E,iBAAS,CAAC2O,kBAAkB,EAAE,EAAE,CAAC;IACzF,IAAID,cAAc,EAAE;MAChB,OAAOA,cAAc,CAACxO,UAAU,EAAE,CAAC0O,KAAK,IAAI,IAAI;IACpD;IACA,OAAO,IAAI;EACf;;EAEA;AACJ;AACA;AACA;EACWC,aAAaA,CAAA,EAAa;IAC7B,MAAMH,cAAc,GAAG,IAAI,CAACnU,YAAY,CAACa,cAAc,CAAC4E,iBAAS,CAAC2O,kBAAkB,EAAE,EAAE,CAAC;IACzF,IAAID,cAAc,EAAE;MAChB,OAAOA,cAAc,CAACxO,UAAU,EAAE,CAAC4O,WAAW,IAAI,EAAE;IACxD;IACA,OAAO,EAAE;EACb;;EAEA;AACJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;EACWC,mBAAmBA,CACtB5R,MAAqB,EACrB/D,iBAA0B,EAC1B6J,QAAuB,EACvB+L,eAAwB,EACpB;IACJ/L,QAAQ,CAACgM,cAAc,EAAE,CAACF,mBAAmB,CAAC5R,MAAM,EAAE/D,iBAAiB,EAAE6J,QAAQ,EAAE+L,eAAe,CAAC;EACvG;;EAEA;AACJ;AACA;AACA;AACA;EACWE,SAASA,CAAC/M,OAAe,EAAiB;IAAA,IAAAgN,iBAAA;IAC7C,QAAAA,iBAAA,GAAO,IAAI,CAAC3G,OAAO,CAACtS,GAAG,CAACiM,OAAO,CAAC,cAAAgN,iBAAA,cAAAA,iBAAA,GAAI,IAAI;EAC5C;;EAEA;AACJ;AACA;EACW1E,UAAUA,CAAA,EAAa;IAC1B,OAAOvG,KAAK,CAACkL,IAAI,CAAC,IAAI,CAAC5G,OAAO,CAACC,MAAM,EAAE,CAAC;EAC5C;;EAEA;AACJ;AACA;AACA;AACA;EACW9E,SAASA,CAAC7B,MAAc,EAAqB;IAChD,OAAO,IAAI,CAACvH,YAAY,CAACoJ,SAAS,CAAC7B,MAAM,CAAC;EAC9C;;EAEA;AACJ;AACA;AACA;AACA;EACWuC,UAAUA,CAAA,EAAiB;IAC9B,OAAO,IAAI,CAAC9J,YAAY,CAAC8J,UAAU,EAAE;EACzC;;EAEA;AACJ;AACA;AACA;EACWgL,gBAAgBA,CAAA,EAAiB;IACpC,OAAO,IAAI,CAACC,wBAAwB,CAAC,MAAM,CAAC;EAChD;;EAEA;AACJ;AACA;AACA;AACA;AACA;AACA;EACWC,oBAAoBA,CAAA,EAAW;IAClC,OAAO,IAAI,CAAChV,YAAY,CAACgV,oBAAoB,EAAE;EACnD;;EAEA;AACJ;AACA;AACA;EACWC,qBAAqBA,CAAA,EAAW;IACnC,OAAO,IAAI,CAACjV,YAAY,CAACiV,qBAAqB,EAAE;EACpD;;EAEA;AACJ;AACA;AACA;EACW3L,8BAA8BA,CAAA,EAAW;IAC5C,OAAO,IAAI,CAAC2L,qBAAqB,EAAE,GAAG,IAAI,CAACD,oBAAoB,EAAE;EACrE;;EAEA;AACJ;AACA;AACA;AACA;EACWD,wBAAwBA,CAACrK,UAAkB,EAAgB;IAC9D,OAAO,IAAI,CAAC1K,YAAY,CAAC8J,UAAU,EAAE,CAACjN,MAAM,CAAC,UAAUmN,CAAC,EAAE;MACtD,OAAOA,CAAC,CAACU,UAAU,KAAKA,UAAU;IACtC,CAAC,CAAC;EACN;;EAEA;AACJ;AACA;AACA;AACA;EACI,MAAa4E,0BAA0BA,CAAA,EAA0B;IAC7D,MAAM,IAAI,CAAC1D,mBAAmB,EAAE;IAChC,IAAI/B,OAAO,GAAG,IAAI,CAACkL,wBAAwB,CAAC,MAAM,CAAC;IACnD,IAAI,IAAI,CAACG,8BAA8B,EAAE,EAAE;MACvCrL,OAAO,GAAGA,OAAO,CAACsL,MAAM,CAAC,IAAI,CAACJ,wBAAwB,CAAC,QAAQ,CAAC,CAAC;IACrE;IACA,OAAOlL,OAAO;EAClB;;EAEA;AACJ;AACA;AACA;EACWqL,8BAA8BA,CAAA,EAAY;IAAA,IAAAE,cAAA;IAC7C,MAAMrN,EAAE,GAAG,IAAI,CAAC/H,YAAY,CAACa,cAAc,CAAC4E,iBAAS,CAAC4P,qBAAqB,EAAE,EAAE,CAAC;IAChF,OAAO,CAAAtN,EAAE,aAAFA,EAAE,wBAAAqN,cAAA,GAAFrN,EAAE,CAAEpC,UAAU,EAAE,cAAAyP,cAAA,uBAAhBA,cAAA,CAAkBE,kBAAkB,MAAK,QAAQ;EAC5D;;EAEA;AACJ;AACA;AACA;AACA;AACA;AACA;EACWC,kBAAkBA,CAAChO,MAAc,EAAU;IAC9C,OAAO,IAAI,CAACiO,iBAAiB,CAACjO,MAAM,EAAE,IAAI,CAAC;EAC/C;;EAEA;AACJ;AACA;AACA;AACA;AACA;EACWkO,kBAAkBA,CAAClO,MAAc,EAAEmD,UAAkB,EAAW;IACnE,MAAMN,MAAM,GAAG,IAAI,CAAChB,SAAS,CAAC7B,MAAM,CAAC;IACrC,IAAI,CAAC6C,MAAM,EAAE;MACT,OAAO,KAAK;IAChB;IACA,OAAOA,MAAM,CAACM,UAAU,KAAKA,UAAU;EAC3C;;EAEA;AACJ;AACA;AACA;AACA;AACA;EACWgL,8BAA8BA,CACjC7Y,MAAc,EACd;IAAE8Y,mBAAmB,GAAG,IAAI;IAAEC,aAAa,GAAG,IAAI;IAAEC,aAAa,GAAG;EAAwB,CAAC,GAAG,CAAC,CAAC,EAClF;IAChB,IAAI,IAAI,CAACC,oBAAoB,CAACjZ,MAAM,CAACkZ,QAAQ,CAAE,EAAE;MAC7C,OAAO,IAAI,CAACD,oBAAoB,CAACjZ,MAAM,CAACkZ,QAAQ,CAAE;IACtD;IACA,MAAMvX,IAAI,GAAG1C,MAAM,CAACka,MAAM,CAAC;MAAEnZ,MAAM;MAAEgZ;IAAc,CAAC,EAAE,IAAI,CAACrX,IAAI,CAAC;IAChE,MAAMY,WAAW,GAAG,IAAI6C,kCAAgB,CAAC,IAAI,EAAEzD,IAAI,CAAC;IACpD,IAAI,CAACiD,SAAS,CAACS,MAAM,CAAC9C,WAAW,EAAE,CAACnB,SAAS,CAACmE,QAAQ,EAAEnE,SAAS,CAACoE,aAAa,CAAC,CAAC;IACjF,IAAIuT,aAAa,EAAE;MACf,IAAI,CAACE,oBAAoB,CAACjZ,MAAM,CAACkZ,QAAQ,CAAE,GAAG3W,WAAW;MACzD,IAAI,CAAC4C,YAAY,CAAChF,IAAI,CAACoC,WAAW,CAAC;IACvC;IAEA,MAAM6W,sBAAsB,GAAG,IAAI,CAAC/V,eAAe,EAAE;IACrD;IACA;IACA;IACA,IAAIyV,mBAAmB,EAAE;MACrB;MACA;MACA;MACA;MACA;MACA;;MAEAM,sBAAsB,CAACvR,SAAS,EAAE,CAAClH,OAAO,CAAC,UAAU2C,KAAK,EAAE;QACxDf,WAAW,CAACM,YAAY,CAACS,KAAK,CAAC;MACnC,CAAC,CAAC;;MAEF;MACA,IAAIuI,QAAQ,GAAGuN,sBAAsB;MACrC,OAAOvN,QAAQ,CAACwN,uBAAuB,CAACrJ,4BAAa,CAACG,SAAS,CAAC,EAAE;QAC9DtE,QAAQ,GAAGA,QAAQ,CAACwN,uBAAuB,CAACrJ,4BAAa,CAACG,SAAS,CAAE;MACzE;MAEA5N,WAAW,CACNc,eAAe,EAAE,CACjB2N,kBAAkB,CAACnF,QAAQ,CAACkE,kBAAkB,CAACC,4BAAa,CAACG,SAAS,CAAC,EAAEH,4BAAa,CAACG,SAAS,CAAC;IAC1G,CAAC,MAAM,IAAI4I,aAAa,EAAE;MACtB,MAAMO,mBAAmB,GAAGF,sBAAsB,CAACrJ,kBAAkB,CAACc,wBAAS,CAACC,OAAO,CAAC;MACxFvO,WAAW,CAACc,eAAe,EAAE,CAAC2N,kBAAkB,CAACsI,mBAAmB,EAAEzI,wBAAS,CAACE,QAAQ,CAAC;IAC7F;;IAEA;IACA;IACA;IACA;IACA;IACA;IACA;;IAEA,OAAOxO,WAAW;EACtB;EAEA,MAAcgX,mBAAmBA,CAACC,UAAU,GAAGnS,wBAAgB,CAACoS,GAAG,EAAmB;IAClF,MAAM/X,QAAQ,GAAG,IAAI,CAACD,MAAM,CAACmG,SAAS,EAAG;IACzC,MAAM5H,MAAM,GAAG,IAAI0Z,cAAM,CAAChY,QAAQ,CAAC;IAEnC,MAAMiY,UAA6B,GAAG;MAClCC,IAAI,EAAE;QACF/N,QAAQ,EAAE;UACN,CAACgO,mCAA2B,CAAC5U,IAAI,GAAG,CAAC6U,4BAAoB,CAAC7U,IAAI;QAClE;MACJ;IACJ,CAAC;IAED,IAAIuU,UAAU,KAAKnS,wBAAgB,CAACC,EAAE,EAAE;MACpCqS,UAAU,CAAEC,IAAI,CAAE/N,QAAQ,CAAEkO,iCAAyB,CAAC9U,IAAI,CAAC,GAAG,CAACvD,QAAQ,CAAC;IAC5E;IAEA1B,MAAM,CAACga,aAAa,CAACL,UAAU,CAAC;IAChC,MAAMT,QAAQ,GAAG,MAAM,IAAI,CAACzX,MAAM,CAACwY,iBAAiB,CAAE,gBAAe,IAAI,CAACzY,MAAO,IAAGgY,UAAW,EAAC,EAAExZ,MAAM,CAAC;IAEzGA,MAAM,CAACkZ,QAAQ,GAAGA,QAAQ;IAE1B,OAAOlZ,MAAM;EACjB;EAEA,MAAcoH,uBAAuBA,CAACoS,UAA6B,EAA6B;IAC5F,IAAIjX,WAA6B;IACjC,IAAII,cAAM,CAACuX,wBAAwB,EAAE;MACjC3X,WAAW,GAAG,IAAI6C,kCAAgB,CAC9B,IAAI,EAAA/E,aAAA,CAAAA,aAAA,KAEG,IAAI,CAACsB,IAAI;QACZqX,aAAa,EAAE;MAAK,IAExBpV,SAAS,EACTA,SAAS,EACT4V,UAAU,aAAVA,UAAU,cAAVA,UAAU,GAAInS,wBAAgB,CAACoS,GAAG,CACrC;MACD,IAAI,CAAC7U,SAAS,CAACS,MAAM,CAAC9C,WAAW,EAAE,CAACnB,SAAS,CAACmE,QAAQ,EAAEnE,SAAS,CAACoE,aAAa,CAAC,CAAC;IACrF,CAAC,MAAM,IAAI7C,cAAM,CAACC,oBAAoB,EAAE;MACpC,MAAM5C,MAAM,GAAG,MAAM,IAAI,CAACuZ,mBAAmB,CAACC,UAAU,CAAC;MAEzDjX,WAAW,GAAG,IAAI,CAACsW,8BAA8B,CAAC7Y,MAAM,EAAE;QACtD8Y,mBAAmB,EAAE,KAAK;QAC1BC,aAAa,EAAE,KAAK;QACpBC,aAAa,EAAE;MACnB,CAAC,CAAC;IACN,CAAC,MAAM;MACHzW,WAAW,GAAG,IAAI6C,kCAAgB,CAAC,IAAI,EAAE;QACrC4T,aAAa,EAAE;MACnB,CAAC,CAAC;MAEFlM,KAAK,CAACkL,IAAI,CAAC,IAAI,CAAC5G,OAAO,CAAC,CAACzQ,OAAO,CAAC,CAAC,GAAGoB,MAAM,CAAC,KAAK;QAC7C,IAAIA,MAAM,CAACtB,MAAM,KAAK,CAAC,EAAE;QACzB,MAAM0Z,uBAAuB,GAAGpY,MAAM,CAAC8J,QAAQ,CAACN,IAAI,CAAEjI,KAAK,IAAK;UAC5D,OAAOA,KAAK,CAAC8W,SAAS,EAAE,KAAK,IAAI,CAAC3Y,MAAM,CAACmG,SAAS,EAAE;QACxD,CAAC,CAAC;QACF,IAAI4R,UAAU,KAAKnS,wBAAgB,CAACC,EAAE,IAAI6S,uBAAuB,EAAE;UAC/D5X,WAAW,CAACc,eAAe,EAAE,CAACgX,QAAQ,CAACtY,MAAM,CAACS,SAAS,EAAG;YACtDR,iBAAiB,EAAE;UACvB,CAAC,CAAC;QACN;MACJ,CAAC,CAAC;IACN;IAEA,OAAOO,WAAW;EACtB;EAIA;AACJ;AACA;EACW+X,kBAAkBA,CAACvU,MAAqB,EAAE/D,iBAA0B,EAAQ;IAC/E,KAAK,MAAMQ,SAAS,IAAIuD,MAAM,EAAE;MAC5BiK,4BAAa,CAACuK,gBAAgB,CAAC/X,SAAS,EAAE,IAAI,CAACW,YAAY,EAAEnB,iBAAiB,CAAC;MAC/E,IAAI,CAAC,IAAI,CAAC8V,SAAS,CAACtV,SAAS,CAAC2B,KAAK,EAAE,CAAE,EAAE;QACrC,IAAI,CAACqW,YAAY,CAAChY,SAAS,CAAC2B,KAAK,EAAE,EAAG3B,SAAS,EAAE,EAAE,EAAER,iBAAiB,CAAC;MAC3E;IACJ;EACJ;;EAEA;AACJ;AACA;AACA;AACA;EACI,MAAayY,gBAAgBA,CAAA,EAAkB;IAC3C,IAAI,IAAI,CAACC,YAAY,IAAI,CAAC,IAAI,CAACjZ,MAAM,CAACyF,eAAe,EAAE,EAAE;MACrD;IACJ;IAEA,IAAIvE,cAAM,CAACuX,wBAAwB,EAAE;MACjC,MAAMrT,OAAO,CAACM,GAAG,CAAC,CACd,IAAI,CAACwT,mBAAmB,CAACtT,wBAAgB,CAACoS,GAAG,CAAC,EAC9C,IAAI,CAACkB,mBAAmB,CAACtT,wBAAgB,CAACC,EAAE,CAAC,CAChD,CAAC;IACN,CAAC,MAAM;MACH,MAAMsT,gBAAgB,GAAG,MAAM,IAAI,CAACrB,mBAAmB,EAAE;MAEzD,MAAM;QAAElL,KAAK,EAAEtI;MAAO,CAAC,GAAG,MAAM,IAAI,CAACtE,MAAM,CAACoZ,qBAAqB,CAC7D,IAAI,CAACrZ,MAAM,EACX,EAAE,EACFwK,MAAM,CAAC8O,gBAAgB,EACvBjK,wBAAS,CAACE,QAAQ,EAClB6J,gBAAgB,CACnB;MAED,IAAI,CAAC7U,MAAM,CAACtF,MAAM,EAAE;;MAEpB;MACA,MAAMsa,WAAW,GAAGhV,MAAM,CAACsC,GAAG,CAAC,IAAI,CAAC5G,MAAM,CAACwE,cAAc,EAAE,CAAC,CAAC+U,IAAI,CAAC,CAACC,MAAM,EAAEC,MAAM,KAAK;QAClF;AAChB;AACA;AACA;AACA;AACA;QACgB,MAAMC,eAAe,GAAGF,MAAM,CAACG,2BAA2B,CACtDtB,4BAAoB,CAAC7U,IAAI,CAC3B;QACF,MAAMoW,eAAe,GAAGH,MAAM,CAACE,2BAA2B,CACtDtB,4BAAoB,CAAC7U,IAAI,CAC3B;QACF,OAAOkW,eAAe,CAACG,YAAY,CAACC,gBAAgB,GAAGF,eAAe,CAACC,YAAY,CAACC,gBAAgB;MACxG,CAAC,CAAC;MAEF,IAAIC,wBAAiD;MACrD,MAAMtY,SAAS,GAAG,IAAI,CAACG,eAAe,EAAE,CAACoO,QAAQ,CAACzB,4BAAa,CAACC,QAAQ,CAAC;MACzE,KAAK,MAAMzN,SAAS,IAAIuY,WAAW,EAAE;QAAA,IAAAU,sBAAA;QACjC,MAAM9Z,IAAI,GAAG;UACTmB,iBAAiB,EAAEC,mCAAiB,CAAC2Y,MAAM;UAC3CzY,SAAS,EAAE,KAAK;UAChBC;QACJ,CAAC;QACD,CAAAuY,sBAAA,OAAI,CAACrZ,mBAAmB,CAAC,CAAC,CAAC,cAAAqZ,sBAAA,uBAA3BA,sBAAA,CAA6B5Y,YAAY,CAACL,SAAS,EAAEb,IAAI,CAAC;QAE1D,MAAMga,kBAAkB,GAAGnZ,SAAS,CAAC4Y,2BAA2B,CAC5DtB,4BAAoB,CAAC7U,IAAI,CAC5B;QACD,IAAI0W,kBAAkB,aAAlBA,kBAAkB,eAAlBA,kBAAkB,CAAEC,yBAAyB,EAAE;UAAA,IAAAC,sBAAA;UAC/C,CAAAA,sBAAA,OAAI,CAACzZ,mBAAmB,CAAC,CAAC,CAAC,cAAAyZ,sBAAA,uBAA3BA,sBAAA,CAA6BhZ,YAAY,CAACL,SAAS,EAAEb,IAAI,CAAC;UAC1D6Z,wBAAwB,GAAGhZ,SAAS;QACxC;MACJ;MAEA,IAAI,CAAC8X,kBAAkB,CAACS,WAAW,EAAE,IAAI,CAAC;MAE1C,IAAI,CAACtZ,MAAM,CAAC4E,oBAAoB,CAAC0U,WAAW,CAACA,WAAW,CAACta,MAAM,GAAG,CAAC,CAAC,CAAC;MACrE,IAAI+a,wBAAwB,EAAE;QAC1B,IAAI,CAAC/Z,MAAM,CAAC4E,oBAAoB,CAACmV,wBAAwB,CAAC;MAC9D;IACJ;IAEA,IAAI,CAACM,EAAE,CAACC,mBAAW,CAACC,QAAQ,EAAE,IAAI,CAACC,gBAAgB,CAAC;IACpD,IAAI,CAACH,EAAE,CAACC,mBAAW,CAACG,MAAM,EAAE,IAAI,CAACC,cAAc,CAAC;IAChD,IAAI,CAACzB,YAAY,GAAG,IAAI;EAC5B;EAEA,MAAa0B,iBAAiBA,CAACrW,MAAqB,EAAiB;IACjE,MAAMsW,qBAAqB,GAAI/Y,KAAkB,IAAW;MACxD,IAAI,CAACgZ,6BAAY,CAACC,OAAO,CAACjZ,KAAK,CAACW,OAAO,EAAE,CAAC,EAAE;MAC5C,IAAI;QACA,MAAMuY,IAAI,GAAG,IAAIC,UAAI,CAACnZ,KAAK,EAAE,IAAI,CAAC7B,MAAM,EAAE,IAAI,CAAC;QAC/C,IAAI,CAACib,KAAK,CAACjd,GAAG,CAAC6D,KAAK,CAACa,KAAK,EAAE,EAAGqY,IAAI,CAAC;QACpC,IAAI,CAACnY,IAAI,CAACsY,eAAS,CAACvK,GAAG,EAAEoK,IAAI,CAAC;MAClC,CAAC,CAAC,MAAM,CAAC;MACT;IACJ,CAAC;;IAED,MAAMI,wBAAwB,GAAItZ,KAAkB,IAAW;MAC3D,MAAMuZ,eAAe,GAAGvZ,KAAK,CAACuZ,eAAe;MAC7C,IAAIA,eAAe,IAAI,IAAI,CAACH,KAAK,CAAC7d,GAAG,CAACge,eAAe,CAAC,EAAE;QACpD,MAAML,IAAI,GAAG,IAAI,CAACE,KAAK,CAAC5d,GAAG,CAAC+d,eAAe,CAAC;QAC5CL,IAAI,aAAJA,IAAI,uBAAJA,IAAI,CAAEM,aAAa,CAACxZ,KAAK,CAAC;MAC9B;IACJ,CAAC;IAED,MAAMyZ,gBAAgB,GAAIzZ,KAAkB,IAAW;MACnD+Y,qBAAqB,CAAC/Y,KAAK,CAAC;MAC5BsZ,wBAAwB,CAACtZ,KAAK,CAAC;IACnC,CAAC;IAED,KAAK,MAAMA,KAAK,IAAIyC,MAAM,EAAE;MACxB,IAAI;QACA,MAAM,IAAI,CAACtE,MAAM,CAAC4E,oBAAoB,CAAC/C,KAAK,CAAC;QAC7CyZ,gBAAgB,CAACzZ,KAAK,CAAC;MAC3B,CAAC,CAAC,MAAM,CAAC;IACb;EACJ;;EAEA;AACJ;AACA;AACA;EACI,MAAcqX,mBAAmBA,CAAC3a,MAAyB,EAAiB;IACxE,MAAMuC,WAAW,GAAGvC,MAAM,KAAKqH,wBAAgB,CAACC,EAAE,GAAG,IAAI,CAAClF,mBAAmB,CAAC,CAAC,CAAC,GAAG,IAAI,CAACA,mBAAmB,CAAC,CAAC,CAAC;IAE9G,MAAM;MAAEiM,KAAK,EAAEtI,MAAM;MAAEiX;IAAI,CAAC,GAAG,MAAM,IAAI,CAACvb,MAAM,CAACwb,+BAA+B,CAC5E,IAAI,CAACzb,MAAM,EACX,IAAI,EACJoC,SAAS,EACTiN,wBAAS,CAACE,QAAQ,EAClBxO,WAAW,CAAC2a,cAAc,EAC1B3a,WAAW,CAAC4a,SAAS,EAAE,CAC1B;IAED5a,WAAW,CAACc,eAAe,EAAE,CAAC2N,kBAAkB,CAACgM,GAAG,aAAHA,GAAG,cAAHA,GAAG,GAAI,IAAI,EAAEnM,wBAAS,CAACE,QAAQ,CAAC;IAEjF,IAAI,CAAChL,MAAM,CAACtF,MAAM,EAAE;IAEpB,MAAM2c,YAAY,GAAGrX,MAAM,CAACsC,GAAG,CAAC,IAAI,CAAC5G,MAAM,CAACwE,cAAc,EAAE,CAAC;IAC7D,IAAI,CAACqU,kBAAkB,CAAC8C,YAAY,EAAE,IAAI,CAAC;IAC3C,MAAMla,SAAS,GAAG,IAAI,CAACG,eAAe,EAAE,CAACoO,QAAQ,CAACzB,4BAAa,CAACC,QAAQ,CAAC;IACzE,KAAK,MAAMzN,SAAS,IAAI4a,YAAY,EAAE;MAClC7a,WAAW,CAACM,YAAY,CAACL,SAAS,EAAE;QAChCM,iBAAiB,EAAEC,mCAAiB,CAACC,OAAO;QAC5CC,SAAS,EAAE,KAAK;QAChBC;MACJ,CAAC,CAAC;IACN;EACJ;EAEQ+Y,gBAAgBA,CAACla,MAAc,EAAQ;IAC3C,IAAI,CAACsb,sBAAsB,CAACtb,MAAM,EAAE,KAAK,EAAE,IAAI,CAAC;EACpD;EAEQoa,cAAcA,CAACpa,MAAc,EAAQ;IAAA,IAAAub,mBAAA;IACzC,IAAI,CAAClM,OAAO,CAAC5M,MAAM,CAACzC,MAAM,CAACW,EAAE,CAAC;IAE9B,MAAMmJ,QAAQ,GAAG,IAAI,CAACkH,mBAAmB,CAAChR,MAAM,CAACW,EAAE,CAAC;IACpD,MAAM6a,SAAS,GAAG1R,QAAQ,aAARA,QAAQ,wBAAAyR,mBAAA,GAARzR,QAAQ,CAAEhE,SAAS,EAAE,cAAAyV,mBAAA,uBAArBA,mBAAA,CAAuB3R,IAAI,CAAE6R,EAAE,IAAKA,EAAE,CAACrZ,KAAK,EAAE,KAAKpC,MAAM,CAACW,EAAE,CAAC;IAC/E,IAAI6a,SAAS,EAAE;MACXxb,MAAM,CAAC0b,kBAAkB,CAACF,SAAS,CAAC;IACxC,CAAC,MAAM;MACHrU,cAAM,CAACwU,KAAK,CAAC,4DAA4D,CAAC;IAC9E;IACA,KAAK,MAAMnb,WAAW,IAAI,IAAI,CAACH,mBAAmB,EAAE;MAChDG,WAAW,CAACE,WAAW,CAACV,MAAM,CAACW,EAAE,CAAC;IACtC;EACJ;;EAEA;AACJ;AACA;AACA;AACA;EACWib,yBAAyBA,CAAC3d,MAAc,EAAQ;IACnD,MAAMuC,WAAW,GAAG,IAAI,CAAC0W,oBAAoB,CAACjZ,MAAM,CAACkZ,QAAQ,CAAE;IAC/D,OAAO,IAAI,CAACD,oBAAoB,CAACjZ,MAAM,CAACkZ,QAAQ,CAAE;IAClD,MAAM3Y,CAAC,GAAG,IAAI,CAAC4E,YAAY,CAACyY,OAAO,CAACrb,WAAW,CAAC;IAChD,IAAIhC,CAAC,GAAG,CAAC,CAAC,EAAE;MACR,IAAI,CAAC4E,YAAY,CAAC0Y,MAAM,CAACtd,CAAC,EAAE,CAAC,CAAC;IAClC;EACJ;EAEOud,iBAAiBA,CACpBxa,KAAkB,EAClByC,MAAsB,EACtBgY,KAAmB,EAKrB;IAAA,IAAAC,aAAA;IACE,IAAI,GAAAA,aAAA,GAAC,IAAI,CAACvc,MAAM,cAAAuc,aAAA,eAAXA,aAAA,CAAa9W,eAAe,EAAE,GAAE;MACjC,OAAO;QACH+W,gBAAgB,EAAE,IAAI;QACtBC,kBAAkB,EAAE;MACxB,CAAC;IACL;;IAEA;IACA,IAAI5a,KAAK,CAAC4Q,YAAY,IAAI6J,KAAK,aAALA,KAAK,eAALA,KAAK,CAAElf,GAAG,CAACyE,KAAK,CAACa,KAAK,EAAE,CAAE,EAAE;MAClD,OAAO;QACH8Z,gBAAgB,EAAE,IAAI;QACtBC,kBAAkB,EAAE,IAAI;QACxB5J,QAAQ,EAAEhR,KAAK,CAACa,KAAK;MACzB,CAAC;IACL;;IAEA;IACA,IAAIb,KAAK,CAAC6a,UAAU,CAACrE,4BAAoB,CAAC7U,IAAI,CAAC,EAAE;MAC7C,OAAO;QACHgZ,gBAAgB,EAAE,KAAK;QACvBC,kBAAkB,EAAE,IAAI;QACxB5J,QAAQ,EAAEhR,KAAK,CAAC2Q;MACpB,CAAC;IACL;IAEA,MAAMmK,aAAa,GAAG9a,KAAK,CAAC+a,eAAe,EAAE;IAC7C,IAAIC,WAAoC;IACxC,IAAIF,aAAa,EAAE;MAAA,IAAAG,mBAAA;MACfD,WAAW,IAAAC,mBAAA,GAAG,IAAI,CAAC5a,aAAa,CAACya,aAAa,CAAC,cAAAG,mBAAA,cAAAA,mBAAA,GAAIxY,MAAM,aAANA,MAAM,uBAANA,MAAM,CAAE4F,IAAI,CAAEpE,CAAC,IAAKA,CAAC,CAACpD,KAAK,EAAE,KAAKia,aAAa,CAAC;IACvG;;IAEA;IACA,IAAIE,WAAW,KAAKhb,KAAK,CAAC6a,UAAU,EAAE,IAAI7a,KAAK,CAACC,WAAW,EAAE,CAAC,EAAE;MAC5D,OAAO,IAAI,CAACua,iBAAiB,CAACQ,WAAW,EAAEvY,MAAM,EAAEgY,KAAK,CAAC;IAC7D;;IAEA;IACA,IAAIA,KAAK,aAALA,KAAK,eAALA,KAAK,CAAElf,GAAG,CAACyE,KAAK,CAACuZ,eAAe,CAAE,EAAE;MACpC,OAAO;QACHoB,gBAAgB,EAAE,IAAI;QACtBC,kBAAkB,EAAE,IAAI;QACxB5J,QAAQ,EAAEhR,KAAK,CAACuZ;MACpB,CAAC;IACL;;IAEA;IACA,OAAO;MACHoB,gBAAgB,EAAE,IAAI;MACtBC,kBAAkB,EAAE;IACxB,CAAC;EACL;EAEOlL,kBAAkBA,CAAC1P,KAAmB,EAAiB;IAC1D,IAAI,CAACA,KAAK,EAAE,OAAO,IAAI;IAEvB,MAAM;MAAEgR;IAAS,CAAC,GAAG,IAAI,CAACwJ,iBAAiB,CAACxa,KAAK,CAAC;IAClD,OAAOgR,QAAQ,GAAG,IAAI,CAACwD,SAAS,CAACxD,QAAQ,CAAC,GAAG,IAAI;EACrD;EAEQkK,iBAAiBA,CAAClK,QAAgB,EAAEvO,MAAqB,EAAE/D,iBAAiB,GAAG,KAAK,EAAQ;IAChG,IAAID,MAAM,GAAG,IAAI,CAAC+V,SAAS,CAACxD,QAAQ,CAAC;IAErC,IAAI,CAACvS,MAAM,EAAE;MAAA,IAAA0c,oBAAA;MACT,MAAMjc,SAAS,IAAAic,oBAAA,GAAG,IAAI,CAAC9a,aAAa,CAAC2Q,QAAQ,CAAC,cAAAmK,oBAAA,cAAAA,oBAAA,GAAI1Y,MAAM,CAAC4F,IAAI,CAAEpE,CAAC,IAAKA,CAAC,CAACpD,KAAK,EAAE,KAAKmQ,QAAQ,CAAC;MAC5FvS,MAAM,GAAG,IAAI,CAACyY,YAAY,CAAClG,QAAQ,EAAE9R,SAAS,EAAEuD,MAAM,EAAE/D,iBAAiB,CAAC;IAC9E;IAEAD,MAAM,CAAC2c,SAAS,CAAC3Y,MAAM,EAAE/D,iBAAiB,CAAC;EAC/C;;EAEA;AACJ;AACA;EACW2c,qBAAqBA,CAAC5Y,MAAqB,EAAE/D,iBAA0B,EAAQ;IAClF+D,MAAM,CAACpF,OAAO,CAAC,IAAI,CAACie,cAAc,CAAC;IAEnC,MAAMC,cAAqD,GAAG,CAAC,CAAC;IAChE,KAAK,MAAMvb,KAAK,IAAIyC,MAAM,EAAE;MAAA,IAAA+Y,eAAA;MACxB,MAAM;QAAExK,QAAQ;QAAE4J;MAAmB,CAAC,GAAG,IAAI,CAACJ,iBAAiB,CAACxa,KAAK,CAAC;MACtE,IAAI4a,kBAAkB,IAAI,CAACW,cAAc,CAACvK,QAAQ,CAAE,EAAE;QAClDuK,cAAc,CAACvK,QAAQ,CAAE,GAAG,EAAE;MAClC;MACA,CAAAwK,eAAA,GAAAD,cAAc,CAACvK,QAAQ,CAAE,cAAAwK,eAAA,uBAAzBA,eAAA,CAA2B3e,IAAI,CAACmD,KAAK,CAAC;IAC1C;IAEArE,MAAM,CAAC8f,OAAO,CAACF,cAAc,CAAC,CAACxW,GAAG,CAAC,CAAC,CAACiM,QAAQ,EAAE0K,YAAY,CAAC,KACxD,IAAI,CAACR,iBAAiB,CAAClK,QAAQ,EAAE0K,YAAY,EAAEhd,iBAAiB,CAAC,CACpE;EACL;EAiCOwY,YAAYA,CACflG,QAAgB,EAChB9R,SAAkC,EAClCuD,MAAqB,GAAG,EAAE,EAC1B/D,iBAA0B,EACpB;IAAA,IAAAid,qBAAA,EAAAC,gBAAA,EAAAC,qBAAA;IACN,IAAI,IAAI,CAAC/N,OAAO,CAACvS,GAAG,CAACyV,QAAQ,CAAC,EAAE;MAC5B,OAAO,IAAI,CAAClD,OAAO,CAACtS,GAAG,CAACwV,QAAQ,CAAC;IACrC;IAEA,IAAI9R,SAAS,EAAE;MACX,MAAM4c,aAAa,GAAG,IAAI,CAACC,SAAS,CAACC,yBAAyB,CAAC9c,SAAS,CAAC2B,KAAK,EAAE,CAAE;MAClF,IAAIib,aAAa,aAAbA,aAAa,eAAbA,aAAa,CAAE3e,MAAM,EAAE;QACvB;QACA;QACAsF,MAAM,GAAGA,MAAM,CAACuS,MAAM,CAAC8G,aAAa,CAACpf,MAAM,CAAEuH,CAAC,IAAK,CAACA,CAAC,CAAC4W,UAAU,CAACoB,oBAAY,CAACvc,OAAO,CAAC,CAAC,CAAC;MAC5F;IACJ;IAEA,MAAMjB,MAAM,GAAG,IAAIY,cAAM,CAAC2R,QAAQ,EAAE9R,SAAS,EAAE;MAC3CoX,IAAI,EAAE,IAAI;MACVnY,MAAM,EAAE,IAAI,CAACA,MAAM;MACnBqD,oBAAoB,EAAE,IAAI,CAACnD,IAAI,CAACmD,oBAAoB;MACpD0a,QAAQ,GAAAP,qBAAA,GAAE,IAAI,CAACQ,wBAAwB,CAAC3gB,GAAG,CAACwV,QAAQ,CAAC,cAAA2K,qBAAA,cAAAA,qBAAA,GAAI;IAC7D,CAAC,CAAC;;IAEF;IACA;IACA,IAAI,CAACQ,wBAAwB,CAACjb,MAAM,CAAC8P,QAAQ,CAAC;;IAE9C;IACA;IACA;IACA,IAAI,CAAClD,OAAO,CAAC3R,GAAG,CAACsC,MAAM,CAACW,EAAE,EAAEX,MAAM,CAAC;;IAEnC;IACA;IACA;IACA;IACAA,MAAM,CAAC2c,SAAS,CAAC3Y,MAAM,EAAE,KAAK,CAAC;IAE/B,IAAI,CAACnB,SAAS,CAACS,MAAM,CAACtD,MAAM,EAAE,CAC1Bga,mBAAW,CAACG,MAAM,EAClBH,mBAAW,CAAC9J,MAAM,EAClB8J,mBAAW,CAACC,QAAQ,EACpB5a,SAAS,CAACmE,QAAQ,EAClBnE,SAAS,CAACoE,aAAa,CAC1B,CAAC;IACF,MAAMka,OAAO,GACT,EAAAR,gBAAA,OAAI,CAACS,UAAU,cAAAT,gBAAA,uBAAfA,gBAAA,CAAiB1c,SAAS,MAC1BA,SAAS,aAATA,SAAS,uBAATA,SAAS,CAAEod,cAAc,KACzB,EAAAT,qBAAA,OAAI,CAACQ,UAAU,CAACnd,SAAS,cAAA2c,qBAAA,uBAAzBA,qBAAA,CAA2BS,cAAc,KAAGpd,SAAS,aAATA,SAAS,uBAATA,SAAS,CAAEod,cAAc;IAEzE,IAAI,CAAC,IAAI,CAACD,UAAU,IAAID,OAAO,EAAE;MAC7B,IAAI,CAACC,UAAU,GAAG5d,MAAM;IAC5B;IAEA,IAAI,IAAI,CAAC2Y,YAAY,EAAE;MACnB,IAAI,CAAC2C,sBAAsB,CAACtb,MAAM,EAAEC,iBAAiB,EAAE,KAAK,CAAC;IACjE;IACA,IAAI,CAACqC,IAAI,CAAC0X,mBAAW,CAAC3J,GAAG,EAAErQ,MAAM,EAAEC,iBAAiB,CAAC;IAErD,OAAOD,MAAM;EACjB;EAgDQ8d,gBAAgBA,CAACvc,KAAkB,EAAQ;IAC/C,IAAI,CAACsb,cAAc,CAACtb,KAAK,CAAC;;IAE1B;IACA,IAAIA,KAAK,CAACmB,iBAAiB,EAAE,EAAE;MAC3B;MACA;MACA,IAAI,CAACqb,uBAAuB,CAACxc,KAAK,CAAC;IACvC;IACA;IACA,IAAI,CAACyc,4BAA4B,CAACzc,KAAK,CAAC;;IAExC;IACA;IACA;IACA;IACA;IACA,MAAM0c,KAAK,GAAG1c,KAAK,CAAC2c,WAAW,EAAE,CAACC,cAAc;IAChD,IAAI,CAACF,KAAK,IAAI1c,KAAK,CAAC8W,SAAS,EAAE,KAAK,IAAI,CAAC1Y,QAAQ,EAAE;MAC/C;MACA,KAAK,MAAM,CAACye,GAAG,EAAEC,UAAU,CAAC,IAAI,IAAI,CAACC,UAAU,EAAE;QAC7C,IAAID,UAAU,CAACjc,KAAK,EAAE,KAAKb,KAAK,CAACa,KAAK,EAAE,EAAE;UACtC+E,cAAM,CAACwU,KAAK,CAAC,qDAAqD,EAAEyC,GAAG,EAAE7c,KAAK,CAACa,KAAK,EAAE,CAAC;UACvF;UACA,MAAMmc,QAAQ,GAAGhd,KAAK,CAAC2c,WAAW,EAAE;UACpCK,QAAQ,CAACJ,cAAc,GAAGC,GAAG;UAC7B7c,KAAK,CAACid,WAAW,CAACD,QAAQ,CAAC;UAC3B;QACJ;MACJ;IACJ;EACJ;;EAEA;AACJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;EACYzd,YAAYA,CAACS,KAAkB,EAAEkd,mBAAyC,EAAQ;IACtF,MAAM;MAAE1d,iBAAiB;MAAE2d,gBAAgB;MAAExd;IAAU,CAAC,GAAGud,mBAAmB;;IAE9E;IACA,KAAK,MAAMje,WAAW,IAAI,IAAI,CAAC4C,YAAY,EAAE;MACzC5C,WAAW,CAACM,YAAY,CAACS,KAAK,EAAE;QAC5BR,iBAAiB;QACjBG,SAAS;QACTwd;MACJ,CAAC,CAAC;IACN;;IAEA;IACA;IACA;IACA;IACA,IAAInd,KAAK,CAACod,MAAM,IAAIpd,KAAK,CAACW,OAAO,EAAE,KAAK2E,iBAAS,CAAC+X,aAAa,EAAE;MAC7D,IAAI,CAACC,UAAU,CAAC,IAAAC,8BAAiB,EAACvd,KAAK,CAACod,MAAM,CAAChW,MAAM,EAAEpH,KAAK,EAAEwd,0BAAW,CAACC,IAAI,CAAC,EAAE,IAAI,CAAC;;MAEtF;MACA;MACA;MACA;MACA;MACA;IACJ;EACJ;;EAEA;AACJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;EACWta,eAAeA,CAACnD,KAAkB,EAAE0c,KAAa,EAAQ;IAC5D,IAAI1c,KAAK,CAAC0d,MAAM,KAAKza,wBAAW,CAAC0a,OAAO,IAAI3d,KAAK,CAAC0d,MAAM,KAAKza,wBAAW,CAACC,QAAQ,EAAE;MAC/E,MAAM,IAAIqE,KAAK,CAAC,iDAAiD,GAAGvH,KAAK,CAAC0d,MAAM,CAAC;IACrF;IAEA,IAAI,IAAI,CAACX,UAAU,CAACvhB,GAAG,CAACkhB,KAAK,CAAC,EAAE;MAC5B,MAAM,IAAInV,KAAK,CAAC,sDAAsD,GAAGmV,KAAK,CAAC;IACnF;;IAEA;IACA;IACA;IACAhQ,4BAAa,CAACuK,gBAAgB,CAACjX,KAAK,EAAE,IAAI,CAACD,eAAe,EAAE,CAACoO,QAAQ,CAACzB,4BAAa,CAACC,QAAQ,CAAC,EAAG,KAAK,CAAC;IAEtG,IAAI,CAACoQ,UAAU,CAAC5gB,GAAG,CAACugB,KAAK,EAAE1c,KAAK,CAAC;IACjC,IAAI,IAAI,CAACqC,gBAAgB,EAAE;MACvB,IAAI,IAAI,CAACA,gBAAgB,CAAC4F,IAAI,CAAEhE,CAAC,IAAKA,CAAC,CAACyZ,MAAM,KAAKza,wBAAW,CAACC,QAAQ,CAAC,EAAE;QACtE0C,cAAM,CAACC,IAAI,CAAC,6DAA6D,CAAC;QAC1E7F,KAAK,CAACgD,SAAS,CAACC,wBAAW,CAACC,QAAQ,CAAC;MACzC;MACA,IAAI,CAACb,gBAAgB,CAACxF,IAAI,CAACmD,KAAK,CAAC;MACjC,IAAI,CAAC6H,iBAAiB,EAAE;MACxB,IAAI7H,KAAK,CAAC6a,UAAU,EAAE,EAAE;QACpB;QACA;QACA;QACA,IAAI,CAAC+C,wBAAwB,CAAC5d,KAAK,CAAC;MACxC;MAEA,IAAIA,KAAK,CAACC,WAAW,EAAE,EAAE;QACrB,MAAMC,QAAQ,GAAGF,KAAK,CAACA,KAAK,CAACG,OAAO;QACpC,IAAIC,aAAa,GAAG,IAAI,CAACiC,gBAAgB,CAACgG,IAAI,CAAEpE,CAAC,IAAKA,CAAC,CAACpD,KAAK,EAAE,KAAKX,QAAQ,CAAC;QAC7E,IAAI,CAACE,aAAa,IAAIF,QAAQ,EAAE;UAC5BE,aAAa,GAAG,IAAI,CAACC,aAAa,CAACH,QAAQ,CAAC;QAChD;QACA,IAAIE,aAAa,EAAE;UACfA,aAAa,CAACyd,mBAAmB,CAAC7d,KAAK,CAAC;UACxC,IAAI,CAACe,IAAI,CAACjD,SAAS,CAACkD,SAAS,EAAEhB,KAAK,EAAE,IAAI,CAAC;QAC/C;MACJ;IACJ,CAAC,MAAM;MACH,KAAK,MAAMf,WAAW,IAAI,IAAI,CAAC4C,YAAY,EAAE;QACzC,IAAI5C,WAAW,CAAC4a,SAAS,EAAE,EAAE;UACzB,IAAI5a,WAAW,CAAC4a,SAAS,EAAE,CAAEiE,kBAAkB,CAAC,CAAC9d,KAAK,CAAC,CAAC,CAAC7C,MAAM,EAAE;YAC7D8B,WAAW,CAACa,kBAAkB,CAACE,KAAK,EAAEf,WAAW,CAACc,eAAe,EAAE,EAAE;cACjErB,iBAAiB,EAAE;YACvB,CAAC,CAAC;UACN;QACJ,CAAC,MAAM;UACHO,WAAW,CAACa,kBAAkB,CAACE,KAAK,EAAEf,WAAW,CAACc,eAAe,EAAE,EAAE;YACjErB,iBAAiB,EAAE;UACvB,CAAC,CAAC;QACN;MACJ;IACJ;IAEA,IAAI,CAACqC,IAAI,CAACjD,SAAS,CAACigB,gBAAgB,EAAE/d,KAAK,EAAE,IAAI,CAAC;EACtD;;EAEA;AACJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;EACY6H,iBAAiBA,CAAA,EAAS;IAC9B,IAAI,IAAI,CAACxF,gBAAgB,EAAE;MACvB,MAAMqT,aAAa,GAAG,IAAI,CAACrT,gBAAgB,CACtC0C,GAAG,CAAE/E,KAAK,IAAK;QACZ,OAAAjD,aAAA,CAAAA,aAAA,KACOiD,KAAK,CAACA,KAAK;UACdge,MAAM,EAAEhe,KAAK,CAACoD,QAAQ;QAAE;MAEhC,CAAC,CAAC,CACD1G,MAAM,CAAEsD,KAAK,IAAK;QACf;QACA,MAAMie,gBAAgB,GAAGje,KAAK,CAACiQ,IAAI,KAAK3K,iBAAS,CAAC4Y,oBAAoB;QACtE,MAAM9S,eAAe,GAAG,IAAI,CAACjN,MAAM,CAACiN,eAAe,CAAC,IAAI,CAAClN,MAAM,CAAC;QAChE,OAAO+f,gBAAgB,IAAI,CAAC7S,eAAe;MAC/C,CAAC,CAAC;MAEN,IAAI,CAACjN,MAAM,CAACmE,KAAK,CAAC6b,gBAAgB,CAAC,IAAI,CAACjgB,MAAM,EAAEwX,aAAa,CAAC;IAClE;EACJ;;EAEA;AACJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;EACYkI,wBAAwBA,CAAC5d,KAAkB,EAAQ;IACvD,IAAI,CAAC+b,SAAS,CAACqC,mBAAmB,CAACpe,KAAK,CAAC;EAC7C;EAEOqe,gBAAgBA,CAAC3B,KAAa,EAA2B;IAC5D,OAAO,IAAI,CAACK,UAAU,CAACvhB,GAAG,CAACkhB,KAAK,CAAC;EACrC;;EAEA;AACJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;EACW4B,gBAAgBA,CAACC,WAAwB,EAAEzB,UAAuB,EAAQ;IAC7E,MAAM0B,UAAU,GAAG1B,UAAU,CAACjc,KAAK,EAAG;IACtC,MAAM4d,UAAU,GAAGF,WAAW,CAAC1d,KAAK,EAAG;IACvC,MAAM6d,SAAS,GAAG5B,UAAU,CAACY,MAAM;IAEnC9X,cAAM,CAACwU,KAAK,CAAE,6BAA4BoE,UAAW,OAAMC,UAAW,eAAcC,SAAU,EAAC,CAAC;;IAEhG;IACA,IAAI,CAAC3B,UAAU,CAAC7b,MAAM,CAACqd,WAAW,CAAC5B,WAAW,EAAE,CAACC,cAAc,CAAE;;IAEjE;IACA,IAAI,IAAI,CAACva,gBAAgB,EAAE;MACvB,IAAI,CAACmF,kBAAkB,CAACgX,UAAU,CAAC;IACvC;;IAEA;IACA;IACA1B,UAAU,CAACwB,gBAAgB,CAACC,WAAW,CAACve,KAAK,CAAC;IAE9C,MAAM;MAAE2a,gBAAgB;MAAE3J;IAAS,CAAC,GAAG,IAAI,CAACwJ,iBAAiB,CAAC+D,WAAW,CAAC;IAC1E,MAAM9f,MAAM,GAAGuS,QAAQ,GAAG,IAAI,CAACwD,SAAS,CAACxD,QAAQ,CAAC,GAAG,IAAI;IACzDvS,MAAM,aAANA,MAAM,uBAANA,MAAM,CAAEwY,gBAAgB,CAAC6F,UAAU,CAAC;IACpCre,MAAM,aAANA,MAAM,uBAANA,MAAM,CAAEQ,WAAW,CAACqf,gBAAgB,CAACxB,UAAU,EAAE0B,UAAU,EAAEC,UAAU,CAAC;IAExE,IAAI9D,gBAAgB,EAAE;MAClB,KAAK,MAAM1b,WAAW,IAAI,IAAI,CAAC4C,YAAY,EAAE;QACzC;QACA5C,WAAW,CAACqf,gBAAgB,CAACxB,UAAU,EAAE0B,UAAU,EAAEC,UAAU,CAAC;MACpE;IACJ;IAEA,IAAI,CAAC1d,IAAI,CAACjD,SAAS,CAACigB,gBAAgB,EAAEjB,UAAU,EAAE,IAAI,EAAE0B,UAAU,EAAEE,SAAS,CAAC;EAClF;;EAEA;AACJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;EACWC,kBAAkBA,CAAC3e,KAAkB,EAAE4e,SAAsB,EAAEH,UAAmB,EAAQ;IAC7F7Y,cAAM,CAACkB,GAAG,CACL,kCAAiC8X,SAAU,OAAM5e,KAAK,CAAC6e,SAAS,EAAG,GAAE,GACjE,YAAW7e,KAAK,CAACa,KAAK,EAAG,OAAM4d,UAAW,EAAC,CACnD;;IAED;IACA,IAAIG,SAAS,IAAI3b,wBAAW,CAAC6b,IAAI,IAAI,CAACL,UAAU,EAAE;MAC9C,MAAM,IAAIlX,KAAK,CAAC,iEAAiE,CAAC;IACtF;;IAEA;IACA,IAAIqX,SAAS,IAAI3b,wBAAW,CAAC6b,IAAI,EAAE;MAC/B,MAAMvW,QAAQ,GAAG,IAAI,CAACkH,mBAAmB,CAACgP,UAAU,CAAE;MACtD,IAAIlW,QAAQ,EAAE;QACV;QACA;QACA;QACA,MAAMgW,WAAW,GAAG,IAAI,CAACle,aAAa,CAACoe,UAAU,CAAE;QACnD,MAAMM,WAAW,GAAGR,WAAW,aAAXA,WAAW,uBAAXA,WAAW,CAAE5B,WAAW,EAAE,CAACC,cAAc;QAC7D,IAAI,CAACmC,WAAW,IAAIR,WAAW,EAAE;UAC7B;UACA;UACA;UACA,MAAMvB,QAAQ,GAAGuB,WAAW,CAAC5B,WAAW,EAAE;UAC1CK,QAAQ,CAACJ,cAAc,GAAG5c,KAAK,CAACoD,QAAQ,EAAE;UAC1Cmb,WAAW,CAACtB,WAAW,CAACD,QAAQ,CAAC;UACjC;UACA;UACA,IAAI,CAAC7d,WAAW,CAACof,WAAW,CAAC1d,KAAK,EAAE,CAAE;UACtC,IAAI,CAACyd,gBAAgB,CAACC,WAAW,EAAEve,KAAK,CAAC;QAC7C;QACA;MACJ;IACJ;IAEA,MAAM0e,SAAS,GAAG1e,KAAK,CAAC0d,MAAM;IAC9B,MAAMc,UAAU,GAAGxe,KAAK,CAACa,KAAK,EAAG;IAEjC,IAAI,CAAC6d,SAAS,EAAE;MACZ,MAAM,IAAInX,KAAK,CAAC,wEAAwE,CAAC;IAC7F;IAEA,MAAMyX,OAAO,GAAGC,mBAAmB,CAACP,SAAS,CAAC;IAC9C,IAAI,EAACM,OAAO,aAAPA,OAAO,eAAPA,OAAO,CAAEjZ,QAAQ,CAAC6Y,SAAS,CAAC,GAAE;MAC/B,MAAM,IAAIrX,KAAK,CAAE,kCAAiCmX,SAAU,KAAIE,SAAU,EAAC,CAAC;IAChF;IAEA5e,KAAK,CAACgD,SAAS,CAAC4b,SAAS,CAAC;IAE1B,IAAIA,SAAS,IAAI3b,wBAAW,CAAC6b,IAAI,EAAE;MAC/B;MACA9e,KAAK,CAACkf,mBAAmB,CAACT,UAAU,CAAE;MAEtC,MAAM;QAAE9D,gBAAgB;QAAE3J;MAAS,CAAC,GAAG,IAAI,CAACwJ,iBAAiB,CAACxa,KAAK,CAAC;MACpE,MAAMvB,MAAM,GAAGuS,QAAQ,GAAG,IAAI,CAACwD,SAAS,CAACxD,QAAQ,CAAC,GAAG1Q,SAAS;MAC9D7B,MAAM,aAANA,MAAM,uBAANA,MAAM,CAAEwY,gBAAgB,CAACjX,KAAK,CAAC;MAC/BvB,MAAM,aAANA,MAAM,uBAANA,MAAM,CAAEQ,WAAW,CAACkgB,cAAc,CAACX,UAAU,EAAEC,UAAU,CAAE;MAE3D,IAAI9D,gBAAgB,EAAE;QAClB;QACA;QACA;QACA,KAAK,MAAM1b,WAAW,IAAI,IAAI,CAAC4C,YAAY,EAAE;UACzC5C,WAAW,CAACkgB,cAAc,CAACX,UAAU,EAAEC,UAAU,CAAE;QACvD;MACJ;IACJ,CAAC,MAAM,IAAIG,SAAS,IAAI3b,wBAAW,CAACmc,SAAS,EAAE;MAC3C;MACA,IAAI,IAAI,CAAC/c,gBAAgB,EAAE;QACvB,MAAMgd,YAAY,GAAG,IAAI,CAACnX,eAAe,CAACsW,UAAU,CAAC;QACrD,IAAI,CAAChX,kBAAkB,CAACgX,UAAU,CAAC;QACnC,IAAIa,YAAY,aAAZA,YAAY,eAAZA,YAAY,CAAEpf,WAAW,EAAE,EAAE;UAC7B,IAAI,CAACqf,wBAAwB,CAACD,YAAY,CAAC;QAC/C;MACJ;MACA,IAAI,CAAClgB,WAAW,CAACqf,UAAU,CAAC;IAChC;IACA,IAAI,CAAC3W,iBAAiB,EAAE;IAExB,IAAI,CAAC9G,IAAI,CAACjD,SAAS,CAACigB,gBAAgB,EAAE/d,KAAK,EAAE,IAAI,EAAEwe,UAAU,EAAEE,SAAS,CAAC;EAC7E;EAEQY,wBAAwBA,CAACC,cAA2B,EAAQ;IAChE,MAAMrf,QAAQ,GAAGqf,cAAc,CAACvf,KAAK,CAACG,OAAO;IAC7C,IAAI,CAACD,QAAQ,EAAE;MACX;IACJ;IACA,MAAME,aAAa,GAAG,IAAI,CAAC4B,wBAAwB,EAAE,CAAC3B,aAAa,CAACH,QAAQ,CAAC;IAC7E,IAAIE,aAAa,EAAE;MACfA,aAAa,CAACof,qBAAqB,EAAE;MACrC;MACA,IAAI,CAACze,IAAI,CAACjD,SAAS,CAAC2hB,kBAAkB,EAAEF,cAAc,EAAE,IAAI,CAAC;MAC7D;MACA,IAAInf,aAAa,CAACya,UAAU,EAAE,EAAE;QAC5B,IAAI,CAAC+C,wBAAwB,CAACxd,aAAa,CAAC;MAChD;IACJ;EACJ;;EAEA;AACJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;EAMWsf,aAAaA,CAChBjd,MAAqB,EACrBkd,uBAAkE,EAClEhgB,SAAS,GAAG,KAAK,EACb;IACJ,IAAIH,iBAAgD,GAAGmgB,uBAA4C;IACnG,IAAIxC,gBAAqC,GAAG,KAAK;IACjD,IAAI,OAAOwC,uBAAuB,KAAK,QAAQ,EAAE;MAC7C,CAAC;QACGngB,iBAAiB;QACjBG,SAAS,GAAG,KAAK;QACjB;QACAwd;MACJ,CAAC,GAAGwC,uBAAuB;IAC/B,CAAC,MAAM,IAAIA,uBAAuB,KAAKrf,SAAS,EAAE;MAC9C;MACA;MACAsF,cAAM,CAACC,IAAI,CACP,uBAAuB,GACnB,+DAA+D,GAC/D,gGAAgG,CACvG;IACL;IAEA,IAAIrG,iBAAiB,IAAI,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC8a,OAAO,CAAC9a,iBAAiB,CAAC,KAAK,CAAC,CAAC,EAAE;MAC9E,MAAM,IAAI+H,KAAK,CAAC,wDAAwD,CAAC;IAC7E;;IAEA;IACA,KAAK,IAAItK,CAAC,GAAG,CAAC,EAAEA,CAAC,GAAG,IAAI,CAAC4E,YAAY,CAAC1E,MAAM,EAAEF,CAAC,EAAE,EAAE;MAC/C,MAAMqQ,YAAY,GAAG,IAAI,CAACzL,YAAY,CAAC5E,CAAC,CAAC,CAAC8C,eAAe,EAAE;MAC3D,IAAIuN,YAAY,CAACb,kBAAkB,CAACC,4BAAa,CAACC,QAAQ,CAAC,EAAE;QACzD,MAAM,IAAIpF,KAAK,CACX,gBAAgB,GACZtK,CAAC,GACD,iDAAiD,GACjD,GAAG,GACHqQ,YAAY,CAACb,kBAAkB,CAACC,4BAAa,CAACC,QAAQ,CAAC,GACvD,GAAG,CACV;MACL;MACA,IAAIW,YAAY,CAACyI,uBAAuB,CAACrJ,4BAAa,CAACC,QAAQ,CAAC,EAAE;QAC9D,MAAM,IAAIpF,KAAK,CAAE,iBAAgBtK,CAAE,qDAAoD,CAAC;MAC5F;IACJ;IAEA,MAAMwa,WAAW,GAAG,IAAI,CAACmI,eAAe,CAACnd,MAAM,CAAC;IAChD,MAAM8Y,cAAqD,GAAG,CAAC,CAAC;IAEhE,MAAMsE,OAA6B,GAAG;MAClCrgB,iBAAiB;MACjBG,SAAS;MACTwd;IACJ,CAAC;IAED,KAAK,MAAMnd,KAAK,IAAIyC,MAAM,EAAE;MAAA,IAAAqd,gBAAA;MACxB;MACA,IAAI,CAACvD,gBAAgB,CAACvc,KAAK,CAAC;MAE5B,IAAIA,KAAK,CAAC2c,WAAW,EAAE,CAACC,cAAc,EAAE;QACpC,MAAMmD,aAAa,GAAG,IAAI,CAAChD,UAAU,CAACvhB,GAAG,CAACwE,KAAK,CAAC2c,WAAW,EAAE,CAACC,cAAc,CAAE;QAC9E,IAAImD,aAAa,EAAE;UACf;UACA,IAAI,CAACzB,gBAAgB,CAACte,KAAK,EAAE+f,aAAa,CAAC;UAC3C,SAAS,CAAC;QACd;MACJ;;MAEA,MAAM;QAAEpF,gBAAgB;QAAEC,kBAAkB;QAAE5J;MAAS,CAAC,GAAG,IAAI,CAACwJ,iBAAiB,CAC7Exa,KAAK,EACLyC,MAAM,EACNgV,WAAW,CACd;MAED,IAAImD,kBAAkB,IAAI,CAACW,cAAc,CAACvK,QAAQ,aAARA,QAAQ,cAARA,QAAQ,GAAI,EAAE,CAAC,EAAE;QACvDuK,cAAc,CAACvK,QAAQ,aAARA,QAAQ,cAARA,QAAQ,GAAI,EAAE,CAAC,GAAG,EAAE;MACvC;MACA,CAAA8O,gBAAA,GAAAvE,cAAc,CAACvK,QAAQ,aAARA,QAAQ,cAARA,QAAQ,GAAI,EAAE,CAAC,cAAA8O,gBAAA,uBAA9BA,gBAAA,CAAgCjjB,IAAI,CAACmD,KAAK,CAAC;MAE3C,IAAI2a,gBAAgB,EAAE;QAClB,IAAI,CAACpb,YAAY,CAACS,KAAK,EAAE6f,OAAO,CAAC;MACrC;IACJ;IAEAlkB,MAAM,CAAC8f,OAAO,CAACF,cAAc,CAAC,CAACle,OAAO,CAAC,CAAC,CAAC2T,QAAQ,EAAE0K,YAAY,CAAC,KAAK;MACjE,IAAI,CAACR,iBAAiB,CAAClK,QAAQ,EAAE0K,YAAY,EAAE,KAAK,CAAC;IACzD,CAAC,CAAC;EACN;EAEOsE,uBAAuBA,CAC1Bvd,MAAqB,EACyC;IAC9D;IACA,MAAMwd,IAAI,GAAG,CAAC;IACd,MAAMC,MAAM,GAAG,CAAC;IAChB,IAAI,IAAI,CAAC/hB,MAAM,CAACyF,eAAe,EAAE,EAAE;MAC/B,MAAM6T,WAAW,GAAG,IAAI,CAACmI,eAAe,CAACnd,MAAM,CAAC;MAChD,OAAOA,MAAM,CAAC0d,MAAM,CAChB,CAACC,IAAI,EAAEpgB,KAAkB,KAAK;QAC1B,MAAM;UAAE2a,gBAAgB;UAAEC,kBAAkB;UAAE5J;QAAS,CAAC,GAAG,IAAI,CAACwJ,iBAAiB,CAC7Exa,KAAK,EACLyC,MAAM,EACNgV,WAAW,CACd;QAED,IAAIkD,gBAAgB,EAAE;UAClByF,IAAI,CAACH,IAAI,CAAC,CAACpjB,IAAI,CAACmD,KAAK,CAAC;QAC1B;QAEA,IAAI4a,kBAAkB,EAAE;UACpB5a,KAAK,CAACqgB,WAAW,CAACrP,QAAQ,aAARA,QAAQ,cAARA,QAAQ,GAAI,EAAE,CAAC;UACjCoP,IAAI,CAACF,MAAM,CAAC,CAACrjB,IAAI,CAACmD,KAAK,CAAC;QAC5B;QAEA,OAAOogB,IAAI;MACf,CAAC,EACD,CAAC,EAAE,EAAmB,EAAE,CAAkB,CAC7C;IACL,CAAC,MAAM;MACH;MACA,OAAO,CAAC3d,MAAM,EAAmB,EAAE,CAAkB;IACzD;EACJ;;EAEA;AACJ;AACA;EACYmd,eAAeA,CAACnd,MAAqB,EAAe;IACxD,MAAMgV,WAAW,GAAG,IAAI6I,GAAG,EAAU;IACrC,KAAK,MAAMtgB,KAAK,IAAIyC,MAAM,EAAE;MACxB,IAAIzC,KAAK,CAAC6a,UAAU,CAACrE,4BAAoB,CAAC7U,IAAI,CAAC,EAAE;QAAA,IAAA4e,qBAAA;QAC7C9I,WAAW,CAAC+I,GAAG,EAAAD,qBAAA,GAACvgB,KAAK,CAACuZ,eAAe,cAAAgH,qBAAA,cAAAA,qBAAA,GAAI,EAAE,CAAC;MAChD;IACJ;IACA,OAAO9I,WAAW;EACtB;;EAEA;AACJ;AACA;AACA;AACA;EACW6F,UAAUA,CAACtd,KAAkB,EAAEygB,SAAS,GAAG,KAAK,EAAQ;IAC3D,MAAMC,OAAO,GAAG1gB,KAAK,CAACwF,UAAU,EAAkB;IAClD7J,MAAM,CAACY,IAAI,CAACmkB,OAAO,CAAC,CAACrjB,OAAO,CAAEoK,OAAe,IAAK;MAC9C9L,MAAM,CAACY,IAAI,CAACmkB,OAAO,CAACjZ,OAAO,CAAC,CAAC,CAACpK,OAAO,CAAEsjB,WAAiC,IAAK;QACzEhlB,MAAM,CAACY,IAAI,CAACmkB,OAAO,CAACjZ,OAAO,CAAC,CAACkZ,WAAW,CAAC,CAAC,CAACtjB,OAAO,CAAE+J,MAAc,IAAK;UAAA,IAAAwZ,kBAAA,EAAAC,qBAAA,EAAAC,sBAAA;UACnE,MAAMC,OAAO,GAAGL,OAAO,CAACjZ,OAAO,CAAC,CAACkZ,WAAW,CAAC,CAACvZ,MAAM,CAAY;UAChE,MAAM4Z,sBAAsB,GAAG,CAACD,OAAO,CAACE,SAAS,IAAIF,OAAO,CAACE,SAAS,KAAKC,iCAAkB;UAC7F,MAAMC,kBAA6C,GAAGH,sBAAsB,GACtE,IAAI,GACJ,IAAI,CAAClT,OAAO,CAACtS,GAAG,EAAAolB,kBAAA,GAACG,OAAO,CAACE,SAAS,cAAAL,kBAAA,cAAAA,kBAAA,GAAI,EAAE,CAAC;UAE/C,IAAIO,kBAAkB,EAAE;YACpBA,kBAAkB,CAACC,qBAAqB,CACpC3Z,OAAO,EACPkZ,WAAW,EACXvZ,MAAM,EACN2Z,OAAO,EACPN,SAAS,CACZ;;YAED;YACA;YACA;YACA;YACA;YACA;YACA;YACA,IAAI,IAAI,CAACtiB,MAAM,CAACkjB,qBAAqB,EAAE,IAAIja,MAAM,KAAK,IAAI,CAACjJ,MAAM,CAACmG,SAAS,EAAE,EAAE;cAC3E,MAAMkE,SAAS,GAAG2Y,kBAAkB,CAAC5Y,QAAQ,CAAC4Y,kBAAkB,CAAC5Y,QAAQ,CAACpL,MAAM,GAAG,CAAC,CAAC;cACrF,IAAIqL,SAAS,IAAIf,OAAO,KAAKe,SAAS,CAAC3H,KAAK,EAAE,IAAIuG,MAAM,KAAKoB,SAAS,CAACsO,SAAS,EAAE,EAAE;gBAChFqK,kBAAkB,CAAC9O,SAAS,CAACxU,qBAAqB,CAACqS,KAAK,EAAE,CAAC,CAAC;gBAC5DiR,kBAAkB,CAAC9O,SAAS,CAACxU,qBAAqB,CAACmU,SAAS,EAAE,CAAC,CAAC;cACpE;YACJ;UACJ,CAAC,MAAM;YAAA,IAAAsP,sBAAA;YACH;YACA;YACA;YACA,IAAI,CAACnF,wBAAwB,CAAChgB,GAAG,CAAC4kB,OAAO,CAACE,SAAS,EAAG,CAClD,KAAAK,sBAAA,GAAI,IAAI,CAACnF,wBAAwB,CAAC3gB,GAAG,CAACulB,OAAO,CAACE,SAAS,CAAE,cAAAK,sBAAA,cAAAA,sBAAA,GAAI,EAAE,CAAC,EAChE;cAAE7Z,OAAO;cAAEkZ,WAAW;cAAEvZ,MAAM;cAAE2Z,OAAO;cAAEN;YAAU,CAAC,CACvD,CAAC;UACN;UAEA,MAAMzX,EAAE,GAAG,IAAI,CAAC7K,MAAM,CAACmG,SAAS,EAAE;UAClC;UACA,IAAI8C,MAAM,KAAK4B,EAAE,IAAI,CAACgY,sBAAsB,IAAID,OAAO,CAACQ,EAAE,GAAG,IAAI,CAACC,uBAAuB,EAAE;YACvF,IAAI,CAACA,uBAAuB,GAAGT,OAAO,CAACQ,EAAE;UAC7C;;UAEA;UACA,IAAI,CAACR,OAAO,CAACE,SAAS,IAAIF,OAAO,CAACQ,EAAE,KAAAV,qBAAA,IAAAC,sBAAA,GAAI,IAAI,CAACW,kBAAkB,CAACjmB,GAAG,CAAC4L,MAAM,CAAC,cAAA0Z,sBAAA,uBAAnCA,sBAAA,CAAqCS,EAAE,cAAAV,qBAAA,cAAAA,qBAAA,GAAI,CAAC,CAAC,EAAE;YACnF,IAAI,CAACY,kBAAkB,CAACtlB,GAAG,CAACiL,MAAM,EAAE2Z,OAAO,CAAC;UAChD;QACJ,CAAC,CAAC;MACN,CAAC,CAAC;IACN,CAAC,CAAC;;IAEF;IACA;IACA,IAAI,CAAChgB,IAAI,CAACjD,SAAS,CAAC4jB,OAAO,EAAE1hB,KAAK,EAAE,IAAI,CAAC;EAC7C;;EAEA;AACJ;AACA;AACA;EACW2hB,kBAAkBA,CAAClf,MAAqB,EAAQ;IACnD,KAAK,MAAMzC,KAAK,IAAIyC,MAAM,EAAE;MACxB,IAAIzC,KAAK,CAACW,OAAO,EAAE,KAAK2E,iBAAS,CAACsc,MAAM,EAAE;QACtC,IAAI,CAAC/hB,YAAY,CAACgiB,cAAc,CAAC7hB,KAAK,CAAC;MAC3C,CAAC,MAAM,IAAIA,KAAK,CAACW,OAAO,EAAE,KAAK2E,iBAAS,CAACoc,OAAO,EAAE;QAC9C,IAAI,CAACpE,UAAU,CAACtd,KAAK,CAAC;MAC1B,CAAC,CAAC;IACN;EACJ;;EAEA;AACJ;AACA;AACA;EACW8hB,YAAYA,CAACC,QAAkB,EAAQ;IAC1C,KAAK,MAAMta,OAAO,IAAIsa,QAAQ,EAAE;MAC5B,IAAI,CAAC5iB,WAAW,CAACsI,OAAO,CAAC;IAC7B;EACJ;;EAEA;AACJ;AACA;AACA;AACA;AACA;AACA;EACWtI,WAAWA,CAACsI,OAAe,EAAW;IACzC,IAAIua,UAAU,GAAG,KAAK;IACtB,KAAK,MAAM/iB,WAAW,IAAI,IAAI,CAAC4C,YAAY,EAAE;MACzC,MAAM6F,OAAO,GAAGzI,WAAW,CAACE,WAAW,CAACsI,OAAO,CAAC;MAChD,IAAIC,OAAO,EAAE;QACT,IAAIA,OAAO,CAACzH,WAAW,EAAE,EAAE;UACvB,IAAI,CAACqf,wBAAwB,CAAC5X,OAAO,CAAC;QAC1C;QACAsa,UAAU,GAAG,IAAI;MACrB;IACJ;IACA,OAAOA,UAAU;EACrB;;EAEA;AACJ;AACA;AACA;AACA;AACA;AACA;AACA;EACWC,WAAWA,CAAA,EAAS;IACvB;IACA;IACA,MAAMC,eAAe,GAAG,IAAI,CAACriB,YAAY,CAACa,cAAc,CAAC4E,iBAAS,CAAC+E,UAAU,EAAE,IAAI,CAACjM,QAAQ,CAAC;IAC7F,IAAI8jB,eAAe,EAAE;MACjB,MAAM3X,UAAU,GAAG2X,eAAe,CAAC1c,UAAU,EAAE,CAAC+E,UAAU;MAC1D,IAAI,CAACD,kBAAkB,CAACC,UAAU,CAAE;MAEpC,IAAIA,UAAU,KAAK,QAAQ,EAAE;QACzB,MAAM4X,mBAAmB,GAAGD,eAAe,CAACvF,WAAW,EAAE,CAACyF,iBAAiB,IAAI,EAAE;QACjFD,mBAAmB,CAAC9kB,OAAO,CAAEglB,aAAa,IAAK;UAC3C,MAAMtC,aAAa,GAAG,IAAI,CAAClgB,YAAY,CAACa,cAAc,CAAC2hB,aAAa,CAACpS,IAAI,EAAEoS,aAAa,CAACC,SAAS,CAAC;UACnG,IAAI,CAACvC,aAAa,EAAE;YAChB;YACA,IAAI,CAAClgB,YAAY,CAACiB,cAAc,CAAC,CAC7B,IAAIyhB,kBAAW,CAAC;cACZtS,IAAI,EAAEoS,aAAa,CAACpS,IAAI;cACxBqS,SAAS,EAAED,aAAa,CAACC,SAAS;cAClC5B,OAAO,EAAE2B,aAAa,CAAC3B,OAAO;cAC9B/b,QAAQ,EAAE,OAAO,GAAG6d,IAAI,CAACC,GAAG,EAAE;cAC9BC,OAAO,EAAE,IAAI,CAACxkB,MAAM;cACpBykB,OAAO,EAAE,IAAI,CAACvkB,QAAQ,CAAE;YAC5B,CAAC,CAAC,CACL,CAAC;UACN;QACJ,CAAC,CAAC;MACN;IACJ;;IAEA,MAAMwkB,OAAO,GAAG,IAAI,CAACjhB,IAAI;IACzB,IAAI,CAACA,IAAI,GAAG,IAAI,CAAC0T,iBAAiB,CAAC,IAAI,CAACjX,QAAQ,CAAC;IACjD,IAAI,CAACwD,cAAc,GAAG,IAAAihB,eAAS,EAAC,IAAI,CAAClhB,IAAI,CAAC;IAC1C,IAAI,CAAC4Q,OAAO,GAAG,IAAIuQ,wBAAW,CAAC,IAAI,CAAC5kB,MAAM,EAAE;MACxC6kB,KAAK,EAAE,IAAI,CAACphB;IAChB,CAAC,CAAC;IAEF,IAAIihB,OAAO,KAAK,IAAI,CAACjhB,IAAI,EAAE;MACvB,IAAI,CAACZ,IAAI,CAACjD,SAAS,CAACklB,IAAI,EAAE,IAAI,CAAC;IACnC;EACJ;;EAEA;AACJ;AACA;AACA;EACWC,OAAOA,CAACjjB,KAAkB,EAAQ;IACrC;IACA;IACA;IACA;IACA;IACA;IACA;;IAEA;IACA,IAAI,CAACkjB,IAAI,GAAGljB,KAAK,CAACwF,UAAU,EAAE,CAAC0d,IAAI,IAAI,CAAC,CAAC;;IAEzC;IACA;IACA,IAAI,CAACniB,IAAI,CAACjD,SAAS,CAACqlB,IAAI,EAAEnjB,KAAK,EAAE,IAAI,CAAC;EAC1C;;EAEA;AACJ;AACA;AACA;EACWojB,cAAcA,CAAC3gB,MAAqB,EAAQ;IAC/C,KAAK,MAAMzC,KAAK,IAAIyC,MAAM,EAAE;MACxB,IAAIzC,KAAK,CAACW,OAAO,EAAE,KAAK,OAAO,EAAE;QAC7B,IAAI,CAACsiB,OAAO,CAACjjB,KAAK,CAAC;MACvB;MACA,MAAMqjB,SAAS,GAAGrjB,KAAK,CAACW,OAAO,EAAE;MACjC,MAAM6H,SAAS,GAAG,IAAI,CAAC8a,WAAW,CAAC9nB,GAAG,CAAC6nB,SAAS,CAAC;MACjD,IAAI,CAACC,WAAW,CAACnnB,GAAG,CAACknB,SAAS,EAAErjB,KAAK,CAAC;MACtC,IAAI,CAACe,IAAI,CAACjD,SAAS,CAACylB,WAAW,EAAEvjB,KAAK,EAAE,IAAI,EAAEwI,SAAS,CAAC;IAC5D;EACJ;;EAEA;AACJ;AACA;AACA;AACA;EACWgb,cAAcA,CAACvT,IAAwB,EAA2B;IACrE,OAAO,IAAI,CAACqT,WAAW,CAAC9nB,GAAG,CAACyU,IAAI,CAAC;EACrC;;EAEA;AACJ;AACA;AACA;AACA;EACWwT,cAAcA,CAAA,EAAY;IAC7B,OACI,IAAI,CAAC7a,eAAe,EAAE,KAAK,MAAM,KAChC,IAAI,CAACzK,MAAM,CAACiN,eAAe,CAAC,IAAI,CAAClN,MAAM,CAAC,GACnC,IAAI,CAAC2B,YAAY,CAAC6jB,YAAY,CAACpe,iBAAS,CAAC4Y,oBAAoB,EAAE,IAAI,CAAC9f,QAAQ,CAAC,GAC7E,IAAI,CAACyB,YAAY,CAAC6jB,YAAY,CAACpe,iBAAS,CAACqe,WAAW,EAAE,IAAI,CAACvlB,QAAQ,CAAC,CAAC;EAEnF;;EAEA;AACJ;AACA;AACA;AACA;EACWwlB,SAASA,CAACxc,MAAc,EAAW;IACtC,IAAIwc,SAAS,GAAG,IAAI,CAAChb,eAAe,EAAE,KAAK,MAAM;IACjD,MAAMib,gBAAgB,GAAG,IAAI,CAAChkB,YAAY,CAACa,cAAc,CAAC4E,iBAAS,CAACwe,eAAe,EAAE,EAAE,CAAC;IACxF,MAAMC,WAAW,GAAGF,gBAAgB,IAAIA,gBAAgB,CAACre,UAAU,EAAE;IACrE,MAAMwD,EAAE,GAAG,IAAI,CAACC,SAAS,CAAC7B,MAAM,CAAC;IACjC,IAAI2c,WAAW,IAAI/a,EAAE,IAAI+a,WAAW,CAACC,MAAM,GAAGhb,EAAE,CAACib,UAAU,EAAE;MACzDL,SAAS,GAAG,KAAK;IACrB;IACA,OAAOA,SAAS;EACpB;;EAEA;AACJ;AACA;AACA;EACWM,WAAWA,CAAA,EAAa;IAC3B,OAAO,IAAI,CAACrkB,YAAY,CAACqkB,WAAW,EAAE;EAC1C;;EAEA;AACJ;AACA;AACA;EACWC,oBAAoBA,CAAA,EAAsB;IAC7C,OAAO,IAAI,CAACtkB,YAAY,CAACskB,oBAAoB,EAAE;EACnD;;EAEA;AACJ;AACA;AACA;EACWC,cAAcA,CAAA,EAAgB;IACjC,OAAO,IAAI,CAACvkB,YAAY,CAACukB,cAAc,EAAE;EAC7C;;EAEA;AACJ;AACA;AACA;EACWzjB,OAAOA,CAAA,EAAkC;IAC5C,MAAM0E,WAAW,GAAG,IAAI,CAACxF,YAAY,CAACa,cAAc,CAAC4E,iBAAS,CAACC,UAAU,EAAE,EAAE,CAAC;IAC9E,IAAI,CAACF,WAAW,EAAE;MACd,IAAI,CAAC,IAAI,CAACgf,cAAc,EAAE;QACtBze,cAAM,CAACC,IAAI,CAAC,iBAAiB,GAAG,IAAI,CAAC3H,MAAM,GAAG,uCAAuC,CAAC;QACtF,IAAI,CAACmmB,cAAc,GAAG,IAAI;MAC9B;MACA,OAAO/jB,SAAS;IACpB;IACA,OAAO+E,WAAW,CAACG,UAAU,EAAE,CAAC8e,2BAAmB,CAAC;EACxD;;EAEA;AACJ;AACA;AACA;EACWC,WAAWA,CAAA,EAAY;IAC1B,OAAO,IAAI,CAAC5jB,OAAO,EAAE,KAAK6jB,gBAAQ,CAACC,KAAK;EAC5C;;EAEA;AACJ;AACA;AACA;EACWC,UAAUA,CAAA,EAAY;IACzB,OAAO,IAAI,CAAC/jB,OAAO,EAAE,KAAK6jB,gBAAQ,CAACG,YAAY;EACnD;;EAEA;AACJ;AACA;AACA;EACWC,kBAAkBA,CAAA,EAAY;IACjC,OAAO,IAAI,CAACjkB,OAAO,EAAE,KAAK6jB,gBAAQ,CAACK,YAAY;EACnD;;EAEA;AACJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;EACWC,eAAeA,CAClBC,gCAAgC,GAAG,KAAK,EAC0B;IAClE,MAAMllB,YAAY,GAAG,IAAI,CAACE,eAAe,EAAE,CAACoO,QAAQ,CAACzB,4BAAa,CAACC,QAAQ,CAAC;IAC5E,IAAI,CAAC9M,YAAY,EAAE;MACf,OAAO,IAAI;IACf;IACA,OAAOA,YAAY,CAACilB,eAAe,CAACC,gCAAgC,CAAC;EACzE;EAEQC,iBAAiBA,CAACC,KAAoB,EAAU;IACpD,IAAI,IAAI,CAAC9mB,MAAM,CAAC6mB,iBAAiB,EAAE;MAC/B,MAAMrjB,IAAI,GAAG,IAAI,CAACxD,MAAM,CAAC6mB,iBAAiB,CAAC,IAAI,CAAC9mB,MAAM,EAAE+mB,KAAK,CAAC;MAC9D,IAAItjB,IAAI,KAAK,IAAI,EAAE;QACf,OAAOA,IAAI;MACf;IACJ;IAEA,QAAQsjB,KAAK,CAAChV,IAAI;MACd,KAAKiV,YAAY,CAACC,MAAM;QACpB,OAAOF,KAAK,CAACtjB,IAAI;MACrB,KAAKujB,YAAY,CAACE,SAAS;QACvB,QAAQH,KAAK,CAACI,OAAO;UACjB,KAAK,UAAU;YACX,OAAQ,YAAWC,qBAAqB,CAACL,KAAK,CAACM,KAAK,EAAEN,KAAK,CAAC9U,KAAK,CAAE,EAAC;UACxE;YACI,OAAOmV,qBAAqB,CAACL,KAAK,CAACM,KAAK,EAAEN,KAAK,CAAC9U,KAAK,CAAC;QAAC;MAEnE,KAAK+U,YAAY,CAACM,SAAS;QACvB,IAAIP,KAAK,CAACrC,OAAO,EAAE;UACf,OAAQ,mBAAkBqC,KAAK,CAACrC,OAAQ,GAAE;QAC9C,CAAC,MAAM;UACH,OAAO,YAAY;QACvB;IAAC;EAEb;;EAEA;AACJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;EACYvN,iBAAiBA,CAACjO,MAAc,EAAEqe,mBAAmB,GAAG,KAAK,EAAU;IAC3E,IAAI,CAACA,mBAAmB,EAAE;MACtB;MACA;MACA,MAAMC,SAAS,GAAG,IAAI,CAAC7lB,YAAY,CAACa,cAAc,CAAC4E,iBAAS,CAACqgB,QAAQ,EAAE,EAAE,CAAC;MAC1E,IAAID,SAAS,aAATA,SAAS,eAATA,SAAS,CAAElgB,UAAU,EAAE,CAAC7D,IAAI,EAAE;QAC9B,OAAO,IAAI,CAACqjB,iBAAiB,CAAC;UAC1B/U,IAAI,EAAEiV,YAAY,CAACC,MAAM;UACzBxjB,IAAI,EAAE+jB,SAAS,CAAClgB,UAAU,EAAE,CAAC7D;QACjC,CAAC,CAAC;MACN;IACJ;IAEA,MAAMuS,KAAK,GAAG,IAAI,CAACH,iBAAiB,EAAE;IACtC,IAAIG,KAAK,EAAE;MACP,OAAO,IAAI,CAAC8Q,iBAAiB,CAAC;QAC1B/U,IAAI,EAAEiV,YAAY,CAACC,MAAM;QACzBxjB,IAAI,EAAEuS;MACV,CAAC,CAAC;IACN;IAEA,MAAM0R,iBAAiB,GAAG,IAAI,CAAC/lB,YAAY,CAACgV,oBAAoB,EAAE;IAClE,MAAMgR,kBAAkB,GAAG,IAAI,CAAChmB,YAAY,CAACiV,qBAAqB,EAAE;IACpE;IACA,IAAIgR,eAAe,GAAGF,iBAAiB,GAAGC,kBAAkB,GAAG,CAAC;;IAEhE;IACA,IAAIE,eAAyB,GAAG,EAAE;IAClC,MAAMC,kBAAkB,GAAG,IAAI,CAACnmB,YAAY,CAACa,cAAc,CAACulB,yCAAiC,CAACtkB,IAAI,EAAE,EAAE,CAAC;IACvG,IAAI6H,KAAK,CAACC,OAAO,CAACuc,kBAAkB,aAAlBA,kBAAkB,uBAAlBA,kBAAkB,CAAExgB,UAAU,EAAE,CAAC0gB,eAAe,CAAC,EAAE;MACjEH,eAAe,GAAGC,kBAAkB,CAAExgB,UAAU,EAAE,CAAC0gB,eAAe;IACtE;;IAEA;IACA,IAAIC,UAAoB,GAAG,EAAE;IAC7B,IAAI,IAAI,CAAC9c,aAAa,EAAE;MACpB;MACA,IAAI,CAACA,aAAa,CAAChM,OAAO,CAAE+J,MAAM,IAAK;QACnC;QACA,IAAI2e,eAAe,CAAChgB,QAAQ,CAACqB,MAAM,CAAC,EAAE;UAClC0e,eAAe,EAAE;UACjB;QACJ;QACA,MAAM7b,MAAM,GAAG,IAAI,CAAChB,SAAS,CAAC7B,MAAM,CAAC;QACrC+e,UAAU,CAACtpB,IAAI,CAACoN,MAAM,GAAGA,MAAM,CAACtI,IAAI,GAAGyF,MAAM,CAAC;MAClD,CAAC,CAAC;IACN,CAAC,MAAM;MACH,IAAIgf,YAAY,GAAG,IAAI,CAACvmB,YAAY,CAAC8J,UAAU,EAAE,CAACjN,MAAM,CAAEmN,CAAC,IAAK;QAC5D,OAAOA,CAAC,CAACzC,MAAM,KAAKA,MAAM,KAAKyC,CAAC,CAACU,UAAU,KAAK,QAAQ,IAAIV,CAAC,CAACU,UAAU,KAAK,MAAM,CAAC;MACxF,CAAC,CAAC;MACF6b,YAAY,GAAGA,YAAY,CAAC1pB,MAAM,CAAC,CAAC;QAAE0K;MAAO,CAAC,KAAK;QAC/C;QACA,IAAI2e,eAAe,CAAChgB,QAAQ,CAACqB,MAAM,CAAC,EAAE;UAClC0e,eAAe,EAAE;UACjB,OAAO,KAAK;QAChB;QACA,OAAO,IAAI;MACf,CAAC,CAAC;MACF;MACAM,YAAY,CAAC1O,IAAI,CAAC,CAAC2O,CAAC,EAAEC,CAAC,KAAK1sB,KAAK,CAAC2sB,OAAO,CAACF,CAAC,CAACjf,MAAM,EAAEkf,CAAC,CAAClf,MAAM,CAAC,CAAC;MAC9D;MACAgf,YAAY,GAAGA,YAAY,CAACvhB,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;MACvCshB,UAAU,GAAGC,YAAY,CAACrhB,GAAG,CAAE8E,CAAC,IAAKA,CAAC,CAAClI,IAAI,CAAC;IAChD;IAEA,IAAImkB,eAAe,EAAE;MACjB,OAAO,IAAI,CAACd,iBAAiB,CAAC;QAC1B/U,IAAI,EAAEiV,YAAY,CAACE,SAAS;QAC5BG,KAAK,EAAEY,UAAU;QACjBhW,KAAK,EAAE2V;MACX,CAAC,CAAC;IACN;IAEA,MAAMU,YAAY,GAAG,IAAI,CAAC5d,eAAe,EAAE;IAC3C;IACA;IACA,IAAI4d,YAAY,IAAI,MAAM,EAAE;MACxB,MAAMC,iBAAiB,GAAG,IAAI,CAAC5mB,YAAY,CAACa,cAAc,CAAC4E,iBAAS,CAACohB,oBAAoB,CAAC;MAE1F,IAAID,iBAAiB,aAAjBA,iBAAiB,eAAjBA,iBAAiB,CAAEtpB,MAAM,EAAE;QAC3B,MAAMwpB,eAAe,GAAGF,iBAAiB,CAAC1hB,GAAG,CAAE9H,CAAC,IAAK;UACjD,OAAOA,CAAC,CAACuI,UAAU,EAAE,CAACohB,YAAY;QACtC,CAAC,CAAC;QAEF,OAAO,IAAI,CAAC5B,iBAAiB,CAAC;UAC1B/U,IAAI,EAAEiV,YAAY,CAACE,SAAS;UAC5BC,OAAO,EAAE,UAAU;UACnBE,KAAK,EAAEoB,eAAe;UACtBxW,KAAK,EAAEwW,eAAe,CAACxpB,MAAM,GAAG;QACpC,CAAC,CAAC;MACN;IACJ;;IAEA;IACA,IAAI0pB,SAAS,GAAGV,UAAU;IAC1B;IACA,IAAI,CAACU,SAAS,CAAC1pB,MAAM,EAAE;MACnB0pB,SAAS,GAAG,IAAI,CAAChnB,YAAY,CACxB8J,UAAU,EAAE,CACZjN,MAAM,CAAEmN,CAAC,IAAK;QACX,OAAOA,CAAC,CAACzC,MAAM,KAAKA,MAAM,IAAIyC,CAAC,CAACU,UAAU,KAAK,QAAQ,IAAIV,CAAC,CAACU,UAAU,KAAK,MAAM;MACtF,CAAC,CAAC,CACDxF,GAAG,CAAE8E,CAAC,IAAKA,CAAC,CAAClI,IAAI,CAAC;IAC3B;IAEA,IAAIihB,OAA2B;IAC/B,IAAIiE,SAAS,CAAC1pB,MAAM,EAAE;MAClBylB,OAAO,GAAG,IAAI,CAACoC,iBAAiB,CAAC;QAC7B/U,IAAI,EAAEiV,YAAY,CAACE,SAAS;QAC5BG,KAAK,EAAEsB,SAAS;QAChB1W,KAAK,EAAE0W,SAAS,CAAC1pB,MAAM,GAAG;MAC9B,CAAC,CAAC;IACN;IAEA,OAAO,IAAI,CAAC6nB,iBAAiB,CAAC;MAC1B/U,IAAI,EAAEiV,YAAY,CAACM,SAAS;MAC5B5C;IACJ,CAAC,CAAC;EACN;;EAEA;AACJ;AACA;AACA;AACA;AACA;AACA;AACA;EACYpG,uBAAuBA,CAACxc,KAAkB,EAAQ;IACtD,MAAM8mB,gBAAgB,GAAG9mB,KAAK,CAAC+mB,kBAAkB,EAAE;IACnD,IAAI,CAACD,gBAAgB,EAAE;MACnB;MACA;IACJ;;IAEA;IACA,MAAM1f,MAAM,GAAGpH,KAAK,CAAC8W,SAAS,EAAE;IAChC,IAAI,CAAC1P,MAAM,EAAE;MACT;IACJ;IACA,MAAM4f,iBAAiB,GAClBC,oCAA4B,CAACtlB,IAAI,IAC9B,IAAI,CAAC9B,YAAY,CAACwH,iBAAiB,CAAC4f,oCAA4B,CAACtlB,IAAI,EAAEyF,MAAM,CAAC,IACjF6f,oCAA4B,CAACC,OAAO,IACjC,IAAI,CAACrnB,YAAY,CAACwH,iBAAiB,CAAC4f,oCAA4B,CAACC,OAAO,EAAE9f,MAAM,CAAE;IAC1F,IAAI,CAAC4f,iBAAiB,EAAE;MACpB;MACA;IACJ;;IAEA;IACA;IACA;;IAEA,MAAMG,+BAA+B,GAAG,IAAI,CAAClmB,gBAAgB,CAACzF,GAAG,CAACsrB,gBAAgB,CAACrf,OAAO,CAAC;IAC3F,IAAI0f,+BAA+B,EAAE;MACjC;MACA;MACA;MACA;MACA;MACA;MACA;MACA,IAAIC,KAAK,GAAGD,+BAA+B,CAAChqB,MAAM,GAAG,CAAC;MACtD,MAAMkqB,GAAG,GAAGC,IAAI,CAACC,GAAG,CAChB,CAAC,EACDJ,+BAA+B,CAAChqB,MAAM,GAAGS,+CAA+C,CAC3F;MACD,OAAOwpB,KAAK,IAAIC,GAAG,EAAE,EAAED,KAAK,EAAE;QAC1B,MAAMpqB,MAAM,GAAGmqB,+BAA+B,CAACC,KAAK,CAAC;QACrD,IAAIpqB,MAAM,CAACyL,KAAK,EAAE,GAAGzI,KAAK,CAACyI,KAAK,EAAE,EAAE;UAChC;QACJ;MACJ;MACA,IAAI2e,KAAK,KAAK,CAAC,CAAC,EAAE;QACdD,+BAA+B,CAACK,OAAO,CAACxnB,KAAK,CAAC;MAClD,CAAC,MAAM;QACHmnB,+BAA+B,CAAC5M,MAAM,CAAC6M,KAAK,GAAG,CAAC,EAAE,CAAC,EAAEpnB,KAAK,CAAC;MAC/D;IACJ,CAAC,MAAM;MACH,IAAI,CAACiB,gBAAgB,CAAC9E,GAAG,CAAC2qB,gBAAgB,CAACrf,OAAO,EAAE,CAACzH,KAAK,CAAC,CAAC;IAChE;;IAEA;IACA;;IAEA,MAAMynB,aAAa,GAAG,IAAI,CAACpnB,aAAa,CAACymB,gBAAgB,CAACrf,OAAO,CAAC;IAClE,IAAI,CAACggB,aAAa,EAAE;MAChB;IACJ;IACAA,aAAa,CAACC,oBAAoB,CAACZ,gBAAgB,CAAC;EACxD;EAEQ1lB,2BAA2BA,CAACpB,KAAkB,EAAQ;IAC1D;IACA,IAAI,CAACA,KAAK,CAACmB,iBAAiB,EAAE;MAC1B,MAAM,IAAIoG,KAAK,CAAC,oCAAoC,CAAC;IACzD;IACA,MAAMogB,QAAQ,GAAG3nB,KAAK,CAAC4nB,WAAW,EAAE;IACpC,MAAMC,eAAe,GAAGF,QAAQ,aAARA,QAAQ,uBAARA,QAAQ,CAAEhjB,QAAQ;IAC1C,MAAMwiB,+BAA+B,GAAG,IAAI,CAAClmB,gBAAgB,CAACzF,GAAG,CAACqsB,eAAe,CAAE;IACnF,IAAI,CAACV,+BAA+B,EAAE;MAClC;MACA;MACA;MACA;IACJ;IACA,MAAMC,KAAK,GAAGD,+BAA+B,CAAC1iB,SAAS,CAAEqjB,MAAM,IAAKA,MAAM,CAACjnB,KAAK,EAAE,KAAKb,KAAK,CAACa,KAAK,EAAE,CAAC;IACrG,IAAIumB,KAAK,KAAK,CAAC,CAAC,EAAE;MACd;MACA;MACA;IACJ;IACA;IACAD,+BAA+B,CAAC5M,MAAM,CAAC6M,KAAK,EAAE,CAAC,CAAC;;IAEhD;IACA,IAAIA,KAAK,KAAKD,+BAA+B,CAAChqB,MAAM,EAAE;MAClD,MAAMsqB,aAAa,GAAG,IAAI,CAACpnB,aAAa,CAACwnB,eAAe,CAAE;MAC1D,IAAI,CAACJ,aAAa,EAAE;QAChB;MACJ;MACA,IAAIL,KAAK,KAAK,CAAC,EAAE;QACb;QACA,IAAI,CAACnmB,gBAAgB,CAACC,MAAM,CAAC2mB,eAAe,CAAE;QAC9CJ,aAAa,CAACC,oBAAoB,EAAE;MACxC,CAAC,MAAM;QACH,MAAMK,QAAQ,GAAGZ,+BAA+B,CAACA,+BAA+B,CAAChqB,MAAM,GAAG,CAAC,CAAC;QAC5F,MAAM6qB,aAAa,GAAGD,QAAQ,CAAChB,kBAAkB,EAAE;QACnD,IAAI,CAACiB,aAAa,EAAE;UAChB;UACA;UACA,MAAM,IAAIzgB,KAAK,CAAC,yDAAyD,CAAC;QAC9E;QACAkgB,aAAa,CAACC,oBAAoB,CAACM,aAAa,CAAC;MACrD;IACJ;EACJ;;EAEA;AACJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;EACYvL,4BAA4BA,CAACzc,KAAkB,EAAQ;IAC3D,MAAMiB,gBAAgB,GAAG,IAAI,CAACA,gBAAgB,CAACzF,GAAG,CAACwE,KAAK,CAACa,KAAK,EAAE,CAAE;IAClE,IAAI,CAACI,gBAAgB,IAAIA,gBAAgB,CAAC9D,MAAM,IAAI,CAAC,EAAE;MACnD;MACA;IACJ;IACA,MAAM8qB,eAAe,GAAGhnB,gBAAgB,CAACA,gBAAgB,CAAC9D,MAAM,GAAG,CAAC,CAAC;IACrE,MAAM2pB,gBAAgB,GAAGmB,eAAe,CAAClB,kBAAkB,EAAE;IAC7D,IAAI,CAACD,gBAAgB,EAAE;MACnB;IACJ;IACA,IAAIA,gBAAgB,CAACoB,OAAO,EAAE;MAC1B;MACA;MACA;MACA;IAAA;IAEJ,IAAID,eAAe,CAACxf,KAAK,EAAE,GAAGzI,KAAK,CAACyI,KAAK,EAAE,EAAE;MACzC;MACA;MACA;IACJ;IACAzI,KAAK,CAAC0nB,oBAAoB,CAACZ,gBAAgB,CAAC;EAChD;;EAEA;AACJ;AACA;AACA;AACA;EACWqB,0BAA0BA,CAAA,EAAW;IACxC,OAAO,IAAI,CAAC3G,uBAAuB;EACvC;;EAEA;AACJ;AACA;AACA;AACA;AACA;AACA;EACW4G,2BAA2BA,CAAChhB,MAAc,EAAuB;IACpE,OAAO,IAAI,CAACqa,kBAAkB,CAACjmB,GAAG,CAAC4L,MAAM,CAAC;EAC9C;;EAEA;AACJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;EACWihB,kBAAkBA,CAACjhB,MAAc,EAAQ;IAC5C,KAAK,CAACihB,kBAAkB,CAACjhB,MAAM,CAAC;IAEhC,MAAMkhB,aAAa,GAAG,IAAI,CAACvY,UAAU,EAAE,CAACrT,MAAM,CACzC+B,MAAM,IAAK,IAAI,CAACoS,gCAAgC,CAACpS,MAAM,CAACW,EAAE,EAAEvB,qBAAqB,CAACqS,KAAK,CAAC,GAAG,CAAC,CAChG;IAED,KAAK,MAAMzR,MAAM,IAAI6pB,aAAa,EAAE;MAChC7pB,MAAM,CAAC4pB,kBAAkB,CAACjhB,MAAM,CAAC;IACrC;EACJ;AACJ;;AAEA;AAAA1J,OAAA,CAAAK,IAAA,GAAAA,IAAA;AACA,MAAMkhB,mBAAuD,GAAG;EAC5D,CAAChc,wBAAW,CAACslB,UAAU,GAAG,CAACtlB,wBAAW,CAAC0a,OAAO,EAAE1a,wBAAW,CAACC,QAAQ,EAAED,wBAAW,CAACmc,SAAS,CAAC;EAC5F,CAACnc,wBAAW,CAAC0a,OAAO,GAAG,CAAC1a,wBAAW,CAACslB,UAAU,EAAEtlB,wBAAW,CAACulB,MAAM,EAAEvlB,wBAAW,CAACC,QAAQ,EAAED,wBAAW,CAAC6b,IAAI,CAAC;EAC3G,CAAC7b,wBAAW,CAACulB,MAAM,GAAG,CAACvlB,wBAAW,CAAC0a,OAAO,EAAE1a,wBAAW,CAACC,QAAQ,EAAED,wBAAW,CAACmc,SAAS,CAAC;EACxF,CAACnc,wBAAW,CAAC6b,IAAI,GAAG,EAAE;EACtB,CAAC7b,wBAAW,CAACC,QAAQ,GAAG,CAACD,wBAAW,CAAC0a,OAAO,EAAE1a,wBAAW,CAACulB,MAAM,EAAEvlB,wBAAW,CAACmc,SAAS,CAAC;EACxF,CAACnc,wBAAW,CAACmc,SAAS,GAAG;AAC7B,CAAC;AAAC,IAEU8F,YAAY;AAAAxnB,OAAA,CAAAwnB,YAAA,GAAAA,YAAA;AAAA,WAAZA,YAAY;EAAZA,YAAY,CAAZA,YAAY;EAAZA,YAAY,CAAZA,YAAY;EAAZA,YAAY,CAAZA,YAAY;AAAA,GAAZA,YAAY,KAAAxnB,OAAA,CAAAwnB,YAAA,GAAZA,YAAY;AAyBxB;AACA,SAASI,qBAAqBA,CAACC,KAAe,EAAEpV,KAAa,EAAU;EACnE,MAAMsY,cAAc,GAAGtY,KAAK,GAAG,CAAC;EAChC,IAAI,CAACoV,KAAK,CAACpoB,MAAM,EAAE;IACf,OAAO,YAAY;EACvB,CAAC,MAAM,IAAIooB,KAAK,CAACpoB,MAAM,KAAK,CAAC,IAAIsrB,cAAc,IAAI,CAAC,EAAE;IAClD,OAAOlD,KAAK,CAAC,CAAC,CAAC;EACnB,CAAC,MAAM,IAAIA,KAAK,CAACpoB,MAAM,KAAK,CAAC,IAAIsrB,cAAc,IAAI,CAAC,EAAE;IAClD,OAAQ,GAAElD,KAAK,CAAC,CAAC,CAAE,QAAOA,KAAK,CAAC,CAAC,CAAE,EAAC;EACxC,CAAC,MAAM;IACH,MAAMmD,MAAM,GAAGD,cAAc,GAAG,CAAC;IACjC,IAAIC,MAAM,EAAE;MACR,OAAQ,GAAEnD,KAAK,CAAC,CAAC,CAAE,QAAOkD,cAAe,SAAQ;IACrD,CAAC,MAAM;MACH,OAAQ,GAAElD,KAAK,CAAC,CAAC,CAAE,cAAa;IACpC;EACJ;AACJ"} \ No newline at end of file
diff --git a/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/search-result.d.ts b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/search-result.d.ts
new file mode 100644
index 0000000..d39ea0e
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/search-result.d.ts
@@ -0,0 +1,20 @@
+import { EventContext } from "./event-context";
+import { EventMapper } from "../event-mapper";
+import { ISearchResult } from "../@types/search";
+export declare class SearchResult {
+ readonly rank: number;
+ readonly context: EventContext;
+ /**
+ * Create a SearchResponse from the response to /search
+ */
+ static fromJson(jsonObj: ISearchResult, eventMapper: EventMapper): SearchResult;
+ /**
+ * Construct a new SearchResult
+ *
+ * @param rank - where this SearchResult ranks in the results
+ * @param context - the matching event and its
+ * context
+ */
+ constructor(rank: number, context: EventContext);
+}
+//# sourceMappingURL=search-result.d.ts.map \ No newline at end of file
diff --git a/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/search-result.d.ts.map b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/search-result.d.ts.map
new file mode 100644
index 0000000..3350dff
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/search-result.d.ts.map
@@ -0,0 +1 @@
+{"version":3,"file":"search-result.d.ts","sourceRoot":"","sources":["../../src/models/search-result.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EAAkB,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEjE,qBAAa,YAAY;aAgCc,IAAI,EAAE,MAAM;aAAkB,OAAO,EAAE,YAAY;IA/BtF;;OAEG;WAEW,QAAQ,CAAC,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,WAAW,GAAG,YAAY;IAoBtF;;;;;;OAMG;gBACgC,IAAI,EAAE,MAAM,EAAkB,OAAO,EAAE,YAAY;CACzF"} \ No newline at end of file
diff --git a/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/search-result.js b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/search-result.js
new file mode 100644
index 0000000..2149486
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/search-result.js
@@ -0,0 +1,59 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.SearchResult = void 0;
+var _eventContext = require("./event-context");
+/*
+Copyright 2015 - 2021 The Matrix.org Foundation C.I.C.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+class SearchResult {
+ /**
+ * Create a SearchResponse from the response to /search
+ */
+
+ static fromJson(jsonObj, eventMapper) {
+ const jsonContext = jsonObj.context || {};
+ let eventsBefore = (jsonContext.events_before || []).map(eventMapper);
+ let eventsAfter = (jsonContext.events_after || []).map(eventMapper);
+ const context = new _eventContext.EventContext(eventMapper(jsonObj.result));
+
+ // Filter out any contextual events which do not correspond to the same timeline (thread or room)
+ const threadRootId = context.ourEvent.threadRootId;
+ eventsBefore = eventsBefore.filter(e => e.threadRootId === threadRootId);
+ eventsAfter = eventsAfter.filter(e => e.threadRootId === threadRootId);
+ context.setPaginateToken(jsonContext.start, true);
+ context.addEvents(eventsBefore, true);
+ context.addEvents(eventsAfter, false);
+ context.setPaginateToken(jsonContext.end, false);
+ return new SearchResult(jsonObj.rank, context);
+ }
+
+ /**
+ * Construct a new SearchResult
+ *
+ * @param rank - where this SearchResult ranks in the results
+ * @param context - the matching event and its
+ * context
+ */
+ constructor(rank, context) {
+ this.rank = rank;
+ this.context = context;
+ }
+}
+exports.SearchResult = SearchResult;
+//# sourceMappingURL=search-result.js.map \ No newline at end of file
diff --git a/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/search-result.js.map b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/search-result.js.map
new file mode 100644
index 0000000..bc18102
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/search-result.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"search-result.js","names":["_eventContext","require","SearchResult","fromJson","jsonObj","eventMapper","jsonContext","context","eventsBefore","events_before","map","eventsAfter","events_after","EventContext","result","threadRootId","ourEvent","filter","e","setPaginateToken","start","addEvents","end","rank","constructor","exports"],"sources":["../../src/models/search-result.ts"],"sourcesContent":["/*\nCopyright 2015 - 2021 The Matrix.org Foundation C.I.C.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n*/\n\nimport { EventContext } from \"./event-context\";\nimport { EventMapper } from \"../event-mapper\";\nimport { IResultContext, ISearchResult } from \"../@types/search\";\n\nexport class SearchResult {\n /**\n * Create a SearchResponse from the response to /search\n */\n\n public static fromJson(jsonObj: ISearchResult, eventMapper: EventMapper): SearchResult {\n const jsonContext = jsonObj.context || ({} as IResultContext);\n let eventsBefore = (jsonContext.events_before || []).map(eventMapper);\n let eventsAfter = (jsonContext.events_after || []).map(eventMapper);\n\n const context = new EventContext(eventMapper(jsonObj.result));\n\n // Filter out any contextual events which do not correspond to the same timeline (thread or room)\n const threadRootId = context.ourEvent.threadRootId;\n eventsBefore = eventsBefore.filter((e) => e.threadRootId === threadRootId);\n eventsAfter = eventsAfter.filter((e) => e.threadRootId === threadRootId);\n\n context.setPaginateToken(jsonContext.start, true);\n context.addEvents(eventsBefore, true);\n context.addEvents(eventsAfter, false);\n context.setPaginateToken(jsonContext.end, false);\n\n return new SearchResult(jsonObj.rank, context);\n }\n\n /**\n * Construct a new SearchResult\n *\n * @param rank - where this SearchResult ranks in the results\n * @param context - the matching event and its\n * context\n */\n public constructor(public readonly rank: number, public readonly context: EventContext) {}\n}\n"],"mappings":";;;;;;AAgBA,IAAAA,aAAA,GAAAC,OAAA;AAhBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAMO,MAAMC,YAAY,CAAC;EACtB;AACJ;AACA;;EAEI,OAAcC,QAAQA,CAACC,OAAsB,EAAEC,WAAwB,EAAgB;IACnF,MAAMC,WAAW,GAAGF,OAAO,CAACG,OAAO,IAAK,CAAC,CAAoB;IAC7D,IAAIC,YAAY,GAAG,CAACF,WAAW,CAACG,aAAa,IAAI,EAAE,EAAEC,GAAG,CAACL,WAAW,CAAC;IACrE,IAAIM,WAAW,GAAG,CAACL,WAAW,CAACM,YAAY,IAAI,EAAE,EAAEF,GAAG,CAACL,WAAW,CAAC;IAEnE,MAAME,OAAO,GAAG,IAAIM,0BAAY,CAACR,WAAW,CAACD,OAAO,CAACU,MAAM,CAAC,CAAC;;IAE7D;IACA,MAAMC,YAAY,GAAGR,OAAO,CAACS,QAAQ,CAACD,YAAY;IAClDP,YAAY,GAAGA,YAAY,CAACS,MAAM,CAAEC,CAAC,IAAKA,CAAC,CAACH,YAAY,KAAKA,YAAY,CAAC;IAC1EJ,WAAW,GAAGA,WAAW,CAACM,MAAM,CAAEC,CAAC,IAAKA,CAAC,CAACH,YAAY,KAAKA,YAAY,CAAC;IAExER,OAAO,CAACY,gBAAgB,CAACb,WAAW,CAACc,KAAK,EAAE,IAAI,CAAC;IACjDb,OAAO,CAACc,SAAS,CAACb,YAAY,EAAE,IAAI,CAAC;IACrCD,OAAO,CAACc,SAAS,CAACV,WAAW,EAAE,KAAK,CAAC;IACrCJ,OAAO,CAACY,gBAAgB,CAACb,WAAW,CAACgB,GAAG,EAAE,KAAK,CAAC;IAEhD,OAAO,IAAIpB,YAAY,CAACE,OAAO,CAACmB,IAAI,EAAEhB,OAAO,CAAC;EAClD;;EAEA;AACJ;AACA;AACA;AACA;AACA;AACA;EACWiB,WAAWA,CAAiBD,IAAY,EAAkBhB,OAAqB,EAAE;IAAA,KAArDgB,IAAY,GAAZA,IAAY;IAAA,KAAkBhB,OAAqB,GAArBA,OAAqB;EAAG;AAC7F;AAACkB,OAAA,CAAAvB,YAAA,GAAAA,YAAA"} \ No newline at end of file
diff --git a/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/thread.d.ts b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/thread.d.ts
new file mode 100644
index 0000000..df26baf
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/thread.d.ts
@@ -0,0 +1,175 @@
+import { Optional } from "matrix-events-sdk";
+import { MatrixClient, PendingEventOrdering } from "../client";
+import { MatrixEvent } from "./event";
+import { EventTimeline } from "./event-timeline";
+import { EventTimelineSet, EventTimelineSetHandlerMap } from "./event-timeline-set";
+import { NotificationCountType, Room, RoomEvent } from "./room";
+import { RoomState } from "./room-state";
+import { ServerControlledNamespacedValue } from "../NamespacedValue";
+import { ReadReceipt } from "./read-receipt";
+import { CachedReceiptStructure } from "../@types/read_receipts";
+export declare enum ThreadEvent {
+ New = "Thread.new",
+ Update = "Thread.update",
+ NewReply = "Thread.newReply",
+ ViewThread = "Thread.viewThread",
+ Delete = "Thread.delete"
+}
+type EmittedEvents = Exclude<ThreadEvent, ThreadEvent.New> | RoomEvent.Timeline | RoomEvent.TimelineReset;
+export type EventHandlerMap = {
+ [ThreadEvent.Update]: (thread: Thread) => void;
+ [ThreadEvent.NewReply]: (thread: Thread, event: MatrixEvent) => void;
+ [ThreadEvent.ViewThread]: () => void;
+ [ThreadEvent.Delete]: (thread: Thread) => void;
+} & EventTimelineSetHandlerMap;
+interface IThreadOpts {
+ room: Room;
+ client: MatrixClient;
+ pendingEventOrdering?: PendingEventOrdering;
+ receipts?: CachedReceiptStructure[];
+}
+export declare enum FeatureSupport {
+ None = 0,
+ Experimental = 1,
+ Stable = 2
+}
+export declare function determineFeatureSupport(stable: boolean, unstable: boolean): FeatureSupport;
+export declare class Thread extends ReadReceipt<EmittedEvents, EventHandlerMap> {
+ readonly id: string;
+ rootEvent: MatrixEvent | undefined;
+ static hasServerSideSupport: FeatureSupport;
+ static hasServerSideListSupport: FeatureSupport;
+ static hasServerSideFwdPaginationSupport: FeatureSupport;
+ /**
+ * A reference to all the events ID at the bottom of the threads
+ */
+ readonly timelineSet: EventTimelineSet;
+ timeline: MatrixEvent[];
+ private _currentUserParticipated;
+ private reEmitter;
+ private lastEvent;
+ private replyCount;
+ private lastPendingEvent;
+ private pendingReplyCount;
+ readonly room: Room;
+ readonly client: MatrixClient;
+ private readonly pendingEventOrdering;
+ initialEventsFetched: boolean;
+ /**
+ * An array of events to add to the timeline once the thread has been initialised
+ * with server suppport.
+ */
+ replayEvents: MatrixEvent[] | null;
+ constructor(id: string, rootEvent: MatrixEvent | undefined, opts: IThreadOpts);
+ private fetchRootEvent;
+ static setServerSideSupport(status: FeatureSupport): void;
+ static setServerSideListSupport(status: FeatureSupport): void;
+ static setServerSideFwdPaginationSupport(status: FeatureSupport): void;
+ private onBeforeRedaction;
+ private onRedaction;
+ private onTimelineEvent;
+ private onLocalEcho;
+ private onEcho;
+ get roomState(): RoomState;
+ private addEventToTimeline;
+ addEvents(events: MatrixEvent[], toStartOfTimeline: boolean): void;
+ /**
+ * Add an event to the thread and updates
+ * the tail/root references if needed
+ * Will fire "Thread.update"
+ * @param event - The event to add
+ * @param toStartOfTimeline - whether the event is being added
+ * to the start (and not the end) of the timeline.
+ * @param emit - whether to emit the Update event if the thread was updated or not.
+ */
+ addEvent(event: MatrixEvent, toStartOfTimeline: boolean, emit?: boolean): Promise<void>;
+ processEvent(event: Optional<MatrixEvent>): Promise<void>;
+ /**
+ * Processes the receipts that were caught during initial sync
+ * When clients become aware of a thread, they try to retrieve those read receipts
+ * and apply them to the current thread
+ * @param receipts - A collection of the receipts cached from initial sync
+ */
+ private processReceipts;
+ private getRootEventBundledRelationship;
+ private processRootEvent;
+ private updatePendingReplyCount;
+ /**
+ * Reset the live timeline of all timelineSets, and start new ones.
+ *
+ * <p>This is used when /sync returns a 'limited' timeline. 'Limited' means that there's a gap between the messages
+ * /sync returned, and the last known message in our timeline. In such a case, our live timeline isn't live anymore
+ * and has to be replaced by a new one. To make sure we can continue paginating our timelines correctly, we have to
+ * set new pagination tokens on the old and the new timeline.
+ *
+ * @param backPaginationToken - token for back-paginating the new timeline
+ * @param forwardPaginationToken - token for forward-paginating the old live timeline,
+ * if absent or null, all timelines are reset, removing old ones (including the previous live
+ * timeline which would otherwise be unable to paginate forwards without this token).
+ * Removing just the old live timeline whilst preserving previous ones is not supported.
+ */
+ resetLiveTimeline(backPaginationToken?: string | null, forwardPaginationToken?: string | null): Promise<void>;
+ private updateThreadMetadata;
+ private fetchEditsWhereNeeded;
+ setEventMetadata(event: Optional<MatrixEvent>): void;
+ clearEventMetadata(event: Optional<MatrixEvent>): void;
+ /**
+ * Finds an event by ID in the current thread
+ */
+ findEventById(eventId: string): MatrixEvent | undefined;
+ /**
+ * Return last reply to the thread, if known.
+ */
+ lastReply(matches?: (ev: MatrixEvent) => boolean): MatrixEvent | null;
+ get roomId(): string;
+ /**
+ * The number of messages in the thread
+ * Only count rel_type=m.thread as we want to
+ * exclude annotations from that number
+ */
+ get length(): number;
+ /**
+ * A getter for the last event of the thread.
+ * This might be a synthesized event, if so, it will not emit any events to listeners.
+ */
+ get replyToEvent(): Optional<MatrixEvent>;
+ get events(): MatrixEvent[];
+ has(eventId: string): boolean;
+ get hasCurrentUserParticipated(): boolean;
+ get liveTimeline(): EventTimeline;
+ getUnfilteredTimelineSet(): EventTimelineSet;
+ addReceipt(event: MatrixEvent, synthetic: boolean): void;
+ /**
+ * Get the ID of the event that a given user has read up to within this thread,
+ * or null if we have received no read receipt (at all) from them.
+ * @param userId - The user ID to get read receipt event ID for
+ * @param ignoreSynthesized - If true, return only receipts that have been
+ * sent by the server, not implicit ones generated
+ * by the JS SDK.
+ * @returns ID of the latest event that the given user has read, or null.
+ */
+ getEventReadUpTo(userId: string, ignoreSynthesized?: boolean): string | null;
+ /**
+ * Determine if the given user has read a particular event.
+ *
+ * It is invalid to call this method with an event that is not part of this thread.
+ *
+ * This is not a definitive check as it only checks the events that have been
+ * loaded client-side at the time of execution.
+ * @param userId - The user ID to check the read state of.
+ * @param eventId - The event ID to check if the user read.
+ * @returns True if the user has read the event, false otherwise.
+ */
+ hasUserReadEvent(userId: string, eventId: string): boolean;
+ setUnread(type: NotificationCountType, count: number): void;
+}
+export declare const FILTER_RELATED_BY_SENDERS: ServerControlledNamespacedValue<"related_by_senders", "io.element.relation_senders">;
+export declare const FILTER_RELATED_BY_REL_TYPES: ServerControlledNamespacedValue<"related_by_rel_types", "io.element.relation_types">;
+export declare const THREAD_RELATION_TYPE: ServerControlledNamespacedValue<"m.thread", "io.element.thread">;
+export declare enum ThreadFilterType {
+ "My" = 0,
+ "All" = 1
+}
+export declare function threadFilterTypeToFilter(type: ThreadFilterType | null): "all" | "participated";
+export {};
+//# sourceMappingURL=thread.d.ts.map \ No newline at end of file
diff --git a/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/thread.d.ts.map b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/thread.d.ts.map
new file mode 100644
index 0000000..5cb2c6a
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/thread.d.ts.map
@@ -0,0 +1 @@
+{"version":3,"file":"thread.d.ts","sourceRoot":"","sources":["../../src/models/thread.ts"],"names":[],"mappings":"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"} \ No newline at end of file
diff --git a/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/thread.js b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/thread.js
new file mode 100644
index 0000000..bc47b2e
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/thread.js
@@ -0,0 +1,581 @@
+"use strict";
+
+var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.ThreadFilterType = exports.ThreadEvent = exports.Thread = exports.THREAD_RELATION_TYPE = exports.FeatureSupport = exports.FILTER_RELATED_BY_SENDERS = exports.FILTER_RELATED_BY_REL_TYPES = void 0;
+exports.determineFeatureSupport = determineFeatureSupport;
+exports.threadFilterTypeToFilter = threadFilterTypeToFilter;
+var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
+var _client = require("../client");
+var _ReEmitter = require("../ReEmitter");
+var _event = require("../@types/event");
+var _event2 = require("./event");
+var _eventTimeline = require("./event-timeline");
+var _eventTimelineSet = require("./event-timeline-set");
+var _room = require("./room");
+var _NamespacedValue = require("../NamespacedValue");
+var _logger = require("../logger");
+var _readReceipt = require("./read-receipt");
+var _read_receipts = require("../@types/read_receipts");
+function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
+function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { (0, _defineProperty2.default)(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
+let ThreadEvent;
+exports.ThreadEvent = ThreadEvent;
+(function (ThreadEvent) {
+ ThreadEvent["New"] = "Thread.new";
+ ThreadEvent["Update"] = "Thread.update";
+ ThreadEvent["NewReply"] = "Thread.newReply";
+ ThreadEvent["ViewThread"] = "Thread.viewThread";
+ ThreadEvent["Delete"] = "Thread.delete";
+})(ThreadEvent || (exports.ThreadEvent = ThreadEvent = {}));
+let FeatureSupport;
+exports.FeatureSupport = FeatureSupport;
+(function (FeatureSupport) {
+ FeatureSupport[FeatureSupport["None"] = 0] = "None";
+ FeatureSupport[FeatureSupport["Experimental"] = 1] = "Experimental";
+ FeatureSupport[FeatureSupport["Stable"] = 2] = "Stable";
+})(FeatureSupport || (exports.FeatureSupport = FeatureSupport = {}));
+function determineFeatureSupport(stable, unstable) {
+ if (stable) {
+ return FeatureSupport.Stable;
+ } else if (unstable) {
+ return FeatureSupport.Experimental;
+ } else {
+ return FeatureSupport.None;
+ }
+}
+class Thread extends _readReceipt.ReadReceipt {
+ /**
+ * A reference to all the events ID at the bottom of the threads
+ */
+
+ /**
+ * An array of events to add to the timeline once the thread has been initialised
+ * with server suppport.
+ */
+
+ constructor(id, rootEvent, opts) {
+ var _opts$pendingEventOrd;
+ super();
+ this.id = id;
+ this.rootEvent = rootEvent;
+ (0, _defineProperty2.default)(this, "timelineSet", void 0);
+ (0, _defineProperty2.default)(this, "timeline", []);
+ (0, _defineProperty2.default)(this, "_currentUserParticipated", false);
+ (0, _defineProperty2.default)(this, "reEmitter", void 0);
+ (0, _defineProperty2.default)(this, "lastEvent", void 0);
+ (0, _defineProperty2.default)(this, "replyCount", 0);
+ (0, _defineProperty2.default)(this, "lastPendingEvent", void 0);
+ (0, _defineProperty2.default)(this, "pendingReplyCount", 0);
+ (0, _defineProperty2.default)(this, "room", void 0);
+ (0, _defineProperty2.default)(this, "client", void 0);
+ (0, _defineProperty2.default)(this, "pendingEventOrdering", void 0);
+ (0, _defineProperty2.default)(this, "initialEventsFetched", !Thread.hasServerSideSupport);
+ (0, _defineProperty2.default)(this, "replayEvents", []);
+ (0, _defineProperty2.default)(this, "onBeforeRedaction", (event, redaction) => {
+ if (event !== null && event !== void 0 && event.isRelation(THREAD_RELATION_TYPE.name) && this.room.eventShouldLiveIn(event).threadId === this.id && event.getId() !== this.id &&
+ // the root event isn't counted in the length so ignore this redaction
+ !redaction.status // only respect it when it succeeds
+ ) {
+ this.replyCount--;
+ this.updatePendingReplyCount();
+ this.emit(ThreadEvent.Update, this);
+ }
+ });
+ (0, _defineProperty2.default)(this, "onRedaction", async event => {
+ if (event.threadRootId !== this.id) return; // ignore redactions for other timelines
+ if (this.replyCount <= 0) {
+ for (const threadEvent of this.timeline) {
+ this.clearEventMetadata(threadEvent);
+ }
+ this.lastEvent = this.rootEvent;
+ this._currentUserParticipated = false;
+ this.emit(ThreadEvent.Delete, this);
+ } else {
+ await this.updateThreadMetadata();
+ }
+ });
+ (0, _defineProperty2.default)(this, "onTimelineEvent", (event, room, toStartOfTimeline) => {
+ // Add a synthesized receipt when paginating forward in the timeline
+ if (!toStartOfTimeline) {
+ room.addLocalEchoReceipt(event.getSender(), event, _read_receipts.ReceiptType.Read);
+ }
+ this.onEcho(event, toStartOfTimeline !== null && toStartOfTimeline !== void 0 ? toStartOfTimeline : false);
+ });
+ (0, _defineProperty2.default)(this, "onLocalEcho", event => {
+ this.onEcho(event, false);
+ });
+ (0, _defineProperty2.default)(this, "onEcho", async (event, toStartOfTimeline) => {
+ if (event.threadRootId !== this.id) return; // ignore echoes for other timelines
+ if (this.lastEvent === event) return; // ignore duplicate events
+ await this.updateThreadMetadata();
+ if (!event.isRelation(THREAD_RELATION_TYPE.name)) return; // don't send a new reply event for reactions or edits
+ if (toStartOfTimeline) return; // ignore messages added to the start of the timeline
+ this.emit(ThreadEvent.NewReply, this, event);
+ });
+ if (!(opts !== null && opts !== void 0 && opts.room)) {
+ // Logging/debugging for https://github.com/vector-im/element-web/issues/22141
+ // Hope is that we end up with a more obvious stack trace.
+ throw new Error("element-web#22141: A thread requires a room in order to function");
+ }
+ this.room = opts.room;
+ this.client = opts.client;
+ this.pendingEventOrdering = (_opts$pendingEventOrd = opts.pendingEventOrdering) !== null && _opts$pendingEventOrd !== void 0 ? _opts$pendingEventOrd : _client.PendingEventOrdering.Chronological;
+ this.timelineSet = new _eventTimelineSet.EventTimelineSet(this.room, {
+ timelineSupport: true,
+ pendingEvents: true
+ }, this.client, this);
+ this.reEmitter = new _ReEmitter.TypedReEmitter(this);
+ this.reEmitter.reEmit(this.timelineSet, [_room.RoomEvent.Timeline, _room.RoomEvent.TimelineReset]);
+ this.room.on(_event2.MatrixEventEvent.BeforeRedaction, this.onBeforeRedaction);
+ this.room.on(_room.RoomEvent.Redaction, this.onRedaction);
+ this.room.on(_room.RoomEvent.LocalEchoUpdated, this.onLocalEcho);
+ this.timelineSet.on(_room.RoomEvent.Timeline, this.onTimelineEvent);
+ this.processReceipts(opts.receipts);
+
+ // even if this thread is thought to be originating from this client, we initialise it as we may be in a
+ // gappy sync and a thread around this event may already exist.
+ this.updateThreadMetadata();
+ this.setEventMetadata(this.rootEvent);
+ }
+ async fetchRootEvent() {
+ this.rootEvent = this.room.findEventById(this.id);
+ // If the rootEvent does not exist in the local stores, then fetch it from the server.
+ try {
+ const eventData = await this.client.fetchRoomEvent(this.roomId, this.id);
+ const mapper = this.client.getEventMapper();
+ this.rootEvent = mapper(eventData); // will merge with existing event object if such is known
+ } catch (e) {
+ _logger.logger.error("Failed to fetch thread root to construct thread with", e);
+ }
+ await this.processEvent(this.rootEvent);
+ }
+ static setServerSideSupport(status) {
+ Thread.hasServerSideSupport = status;
+ if (status !== FeatureSupport.Stable) {
+ FILTER_RELATED_BY_SENDERS.setPreferUnstable(true);
+ FILTER_RELATED_BY_REL_TYPES.setPreferUnstable(true);
+ THREAD_RELATION_TYPE.setPreferUnstable(true);
+ }
+ }
+ static setServerSideListSupport(status) {
+ Thread.hasServerSideListSupport = status;
+ }
+ static setServerSideFwdPaginationSupport(status) {
+ Thread.hasServerSideFwdPaginationSupport = status;
+ }
+ get roomState() {
+ return this.room.getLiveTimeline().getState(_eventTimeline.EventTimeline.FORWARDS);
+ }
+ addEventToTimeline(event, toStartOfTimeline) {
+ if (!this.findEventById(event.getId())) {
+ this.timelineSet.addEventToTimeline(event, this.liveTimeline, {
+ toStartOfTimeline,
+ fromCache: false,
+ roomState: this.roomState
+ });
+ this.timeline = this.events;
+ }
+ }
+ addEvents(events, toStartOfTimeline) {
+ events.forEach(ev => this.addEvent(ev, toStartOfTimeline, false));
+ this.updateThreadMetadata();
+ }
+
+ /**
+ * Add an event to the thread and updates
+ * the tail/root references if needed
+ * Will fire "Thread.update"
+ * @param event - The event to add
+ * @param toStartOfTimeline - whether the event is being added
+ * to the start (and not the end) of the timeline.
+ * @param emit - whether to emit the Update event if the thread was updated or not.
+ */
+ async addEvent(event, toStartOfTimeline, emit = true) {
+ this.setEventMetadata(event);
+ const lastReply = this.lastReply();
+ const isNewestReply = !lastReply || event.localTimestamp >= lastReply.localTimestamp;
+
+ // Add all incoming events to the thread's timeline set when there's no server support
+ if (!Thread.hasServerSideSupport) {
+ // all the relevant membership info to hydrate events with a sender
+ // is held in the main room timeline
+ // We want to fetch the room state from there and pass it down to this thread
+ // timeline set to let it reconcile an event with its relevant RoomMember
+ this.addEventToTimeline(event, toStartOfTimeline);
+ this.client.decryptEventIfNeeded(event, {});
+ } else if (!toStartOfTimeline && this.initialEventsFetched && isNewestReply) {
+ this.addEventToTimeline(event, false);
+ this.fetchEditsWhereNeeded(event);
+ } else if (event.isRelation(_event.RelationType.Annotation) || event.isRelation(_event.RelationType.Replace)) {
+ var _this$timelineSet$rel, _this$timelineSet$rel2;
+ if (!this.initialEventsFetched) {
+ var _this$replayEvents;
+ /**
+ * A thread can be fully discovered via a single sync response
+ * And when that's the case we still ask the server to do an initialisation
+ * as it's the safest to ensure we have everything.
+ * However when we are in that scenario we might loose annotation or edits
+ *
+ * This fix keeps a reference to those events and replay them once the thread
+ * has been initialised properly.
+ */
+ (_this$replayEvents = this.replayEvents) === null || _this$replayEvents === void 0 ? void 0 : _this$replayEvents.push(event);
+ } else {
+ this.addEventToTimeline(event, toStartOfTimeline);
+ }
+ // Apply annotations and replace relations to the relations of the timeline only
+ (_this$timelineSet$rel = this.timelineSet.relations) === null || _this$timelineSet$rel === void 0 ? void 0 : _this$timelineSet$rel.aggregateParentEvent(event);
+ (_this$timelineSet$rel2 = this.timelineSet.relations) === null || _this$timelineSet$rel2 === void 0 ? void 0 : _this$timelineSet$rel2.aggregateChildEvent(event, this.timelineSet);
+ return;
+ }
+
+ // If no thread support exists we want to count all thread relation
+ // added as a reply. We can't rely on the bundled relationships count
+ if ((!Thread.hasServerSideSupport || !this.rootEvent) && event.isRelation(THREAD_RELATION_TYPE.name)) {
+ this.replyCount++;
+ }
+ if (emit) {
+ this.emit(ThreadEvent.NewReply, this, event);
+ this.updateThreadMetadata();
+ }
+ }
+ async processEvent(event) {
+ if (event) {
+ this.setEventMetadata(event);
+ await this.fetchEditsWhereNeeded(event);
+ }
+ this.timeline = this.events;
+ }
+
+ /**
+ * Processes the receipts that were caught during initial sync
+ * When clients become aware of a thread, they try to retrieve those read receipts
+ * and apply them to the current thread
+ * @param receipts - A collection of the receipts cached from initial sync
+ */
+ processReceipts(receipts = []) {
+ for (const {
+ eventId,
+ receiptType,
+ userId,
+ receipt,
+ synthetic
+ } of receipts) {
+ this.addReceiptToStructure(eventId, receiptType, userId, receipt, synthetic);
+ }
+ }
+ getRootEventBundledRelationship(rootEvent = this.rootEvent) {
+ return rootEvent === null || rootEvent === void 0 ? void 0 : rootEvent.getServerAggregatedRelation(THREAD_RELATION_TYPE.name);
+ }
+ async processRootEvent() {
+ const bundledRelationship = this.getRootEventBundledRelationship();
+ if (Thread.hasServerSideSupport && bundledRelationship) {
+ this.replyCount = bundledRelationship.count;
+ this._currentUserParticipated = !!bundledRelationship.current_user_participated;
+ const mapper = this.client.getEventMapper();
+ // re-insert roomId
+ this.lastEvent = mapper(_objectSpread(_objectSpread({}, bundledRelationship.latest_event), {}, {
+ room_id: this.roomId
+ }));
+ this.updatePendingReplyCount();
+ await this.processEvent(this.lastEvent);
+ }
+ }
+ updatePendingReplyCount() {
+ const unfilteredPendingEvents = this.pendingEventOrdering === _client.PendingEventOrdering.Detached ? this.room.getPendingEvents() : this.events;
+ const pendingEvents = unfilteredPendingEvents.filter(ev => {
+ var _this$lastEvent;
+ return ev.threadRootId === this.id && ev.isRelation(THREAD_RELATION_TYPE.name) && ev.status !== null && ev.getId() !== ((_this$lastEvent = this.lastEvent) === null || _this$lastEvent === void 0 ? void 0 : _this$lastEvent.getId());
+ });
+ this.lastPendingEvent = pendingEvents.length ? pendingEvents[pendingEvents.length - 1] : undefined;
+ this.pendingReplyCount = pendingEvents.length;
+ }
+
+ /**
+ * Reset the live timeline of all timelineSets, and start new ones.
+ *
+ * <p>This is used when /sync returns a 'limited' timeline. 'Limited' means that there's a gap between the messages
+ * /sync returned, and the last known message in our timeline. In such a case, our live timeline isn't live anymore
+ * and has to be replaced by a new one. To make sure we can continue paginating our timelines correctly, we have to
+ * set new pagination tokens on the old and the new timeline.
+ *
+ * @param backPaginationToken - token for back-paginating the new timeline
+ * @param forwardPaginationToken - token for forward-paginating the old live timeline,
+ * if absent or null, all timelines are reset, removing old ones (including the previous live
+ * timeline which would otherwise be unable to paginate forwards without this token).
+ * Removing just the old live timeline whilst preserving previous ones is not supported.
+ */
+ async resetLiveTimeline(backPaginationToken, forwardPaginationToken) {
+ const oldLive = this.liveTimeline;
+ this.timelineSet.resetLiveTimeline(backPaginationToken !== null && backPaginationToken !== void 0 ? backPaginationToken : undefined, forwardPaginationToken !== null && forwardPaginationToken !== void 0 ? forwardPaginationToken : undefined);
+ const newLive = this.liveTimeline;
+
+ // FIXME: Remove the following as soon as https://github.com/matrix-org/synapse/issues/14830 is resolved.
+ //
+ // The pagination API for thread timelines currently can't handle the type of pagination tokens returned by sync
+ //
+ // To make this work anyway, we'll have to transform them into one of the types that the API can handle.
+ // One option is passing the tokens to /messages, which can handle sync tokens, and returns the right format.
+ // /messages does not return new tokens on requests with a limit of 0.
+ // This means our timelines might overlap a slight bit, but that's not an issue, as we deduplicate messages
+ // anyway.
+
+ let newBackward;
+ let oldForward;
+ if (backPaginationToken) {
+ const res = await this.client.createMessagesRequest(this.roomId, backPaginationToken, 1, _eventTimeline.Direction.Forward);
+ newBackward = res.end;
+ }
+ if (forwardPaginationToken) {
+ const res = await this.client.createMessagesRequest(this.roomId, forwardPaginationToken, 1, _eventTimeline.Direction.Backward);
+ oldForward = res.start;
+ }
+ // Only replace the token if we don't have paginated away from this position already. This situation doesn't
+ // occur today, but if the above issue is resolved, we'd have to go down this path.
+ if (forwardPaginationToken && oldLive.getPaginationToken(_eventTimeline.Direction.Forward) === forwardPaginationToken) {
+ var _oldForward;
+ oldLive.setPaginationToken((_oldForward = oldForward) !== null && _oldForward !== void 0 ? _oldForward : null, _eventTimeline.Direction.Forward);
+ }
+ if (backPaginationToken && newLive.getPaginationToken(_eventTimeline.Direction.Backward) === backPaginationToken) {
+ var _newBackward;
+ newLive.setPaginationToken((_newBackward = newBackward) !== null && _newBackward !== void 0 ? _newBackward : null, _eventTimeline.Direction.Backward);
+ }
+ }
+ async updateThreadMetadata() {
+ this.updatePendingReplyCount();
+ if (Thread.hasServerSideSupport) {
+ // Ensure we show *something* as soon as possible, we'll update it as soon as we get better data, but we
+ // don't want the thread preview to be empty if we can avoid it
+ if (!this.initialEventsFetched) {
+ await this.processRootEvent();
+ }
+ await this.fetchRootEvent();
+ }
+ await this.processRootEvent();
+ if (!this.initialEventsFetched) {
+ this.initialEventsFetched = true;
+ // fetch initial event to allow proper pagination
+ try {
+ // if the thread has regular events, this will just load the last reply.
+ // if the thread is newly created, this will load the root event.
+ if (this.replyCount === 0 && this.rootEvent) {
+ this.timelineSet.addEventsToTimeline([this.rootEvent], true, this.liveTimeline, null);
+ this.liveTimeline.setPaginationToken(null, _eventTimeline.Direction.Backward);
+ } else {
+ await this.client.paginateEventTimeline(this.liveTimeline, {
+ backwards: true,
+ limit: Math.max(1, this.length)
+ });
+ }
+ for (const event of this.replayEvents) {
+ this.addEvent(event, false);
+ }
+ this.replayEvents = null;
+ // just to make sure that, if we've created a timeline window for this thread before the thread itself
+ // existed (e.g. when creating a new thread), we'll make sure the panel is force refreshed correctly.
+ this.emit(_room.RoomEvent.TimelineReset, this.room, this.timelineSet, true);
+ } catch (e) {
+ _logger.logger.error("Failed to load start of newly created thread: ", e);
+ this.initialEventsFetched = false;
+ }
+ }
+ this.emit(ThreadEvent.Update, this);
+ }
+
+ // XXX: Workaround for https://github.com/matrix-org/matrix-spec-proposals/pull/2676/files#r827240084
+ async fetchEditsWhereNeeded(...events) {
+ return Promise.all(events.filter(e => e.isEncrypted()).map(event => {
+ if (event.isRelation()) return; // skip - relations don't get edits
+ return this.client.relations(this.roomId, event.getId(), _event.RelationType.Replace, event.getType(), {
+ limit: 1
+ }).then(relations => {
+ if (relations.events.length) {
+ event.makeReplaced(relations.events[0]);
+ }
+ }).catch(e => {
+ _logger.logger.error("Failed to load edits for encrypted thread event", e);
+ });
+ }));
+ }
+ setEventMetadata(event) {
+ if (event) {
+ _eventTimeline.EventTimeline.setEventMetadata(event, this.roomState, false);
+ event.setThread(this);
+ }
+ }
+ clearEventMetadata(event) {
+ if (event) {
+ var _event$event, _event$event$unsigned, _event$event$unsigned2;
+ event.setThread(undefined);
+ (_event$event = event.event) === null || _event$event === void 0 ? true : (_event$event$unsigned = _event$event.unsigned) === null || _event$event$unsigned === void 0 ? true : (_event$event$unsigned2 = _event$event$unsigned["m.relations"]) === null || _event$event$unsigned2 === void 0 ? true : delete _event$event$unsigned2[THREAD_RELATION_TYPE.name];
+ }
+ }
+
+ /**
+ * Finds an event by ID in the current thread
+ */
+ findEventById(eventId) {
+ return this.timelineSet.findEventById(eventId);
+ }
+
+ /**
+ * Return last reply to the thread, if known.
+ */
+ lastReply(matches = () => true) {
+ for (let i = this.timeline.length - 1; i >= 0; i--) {
+ const event = this.timeline[i];
+ if (matches(event)) {
+ return event;
+ }
+ }
+ return null;
+ }
+ get roomId() {
+ return this.room.roomId;
+ }
+
+ /**
+ * The number of messages in the thread
+ * Only count rel_type=m.thread as we want to
+ * exclude annotations from that number
+ */
+ get length() {
+ return this.replyCount + this.pendingReplyCount;
+ }
+
+ /**
+ * A getter for the last event of the thread.
+ * This might be a synthesized event, if so, it will not emit any events to listeners.
+ */
+ get replyToEvent() {
+ var _ref, _this$lastPendingEven;
+ return (_ref = (_this$lastPendingEven = this.lastPendingEvent) !== null && _this$lastPendingEven !== void 0 ? _this$lastPendingEven : this.lastEvent) !== null && _ref !== void 0 ? _ref : this.lastReply();
+ }
+ get events() {
+ return this.liveTimeline.getEvents();
+ }
+ has(eventId) {
+ return this.timelineSet.findEventById(eventId) instanceof _event2.MatrixEvent;
+ }
+ get hasCurrentUserParticipated() {
+ return this._currentUserParticipated;
+ }
+ get liveTimeline() {
+ return this.timelineSet.getLiveTimeline();
+ }
+ getUnfilteredTimelineSet() {
+ return this.timelineSet;
+ }
+ addReceipt(event, synthetic) {
+ throw new Error("Unsupported function on the thread model");
+ }
+
+ /**
+ * Get the ID of the event that a given user has read up to within this thread,
+ * or null if we have received no read receipt (at all) from them.
+ * @param userId - The user ID to get read receipt event ID for
+ * @param ignoreSynthesized - If true, return only receipts that have been
+ * sent by the server, not implicit ones generated
+ * by the JS SDK.
+ * @returns ID of the latest event that the given user has read, or null.
+ */
+ getEventReadUpTo(userId, ignoreSynthesized) {
+ const isCurrentUser = userId === this.client.getUserId();
+ const lastReply = this.timeline[this.timeline.length - 1];
+ if (isCurrentUser && lastReply) {
+ // If the last activity in a thread is prior to the first threaded read receipt
+ // sent in the room (suggesting that it was sent before the user started
+ // using a client that supported threaded read receipts), we want to
+ // consider this thread as read.
+ const beforeFirstThreadedReceipt = lastReply.getTs() < this.room.getOldestThreadedReceiptTs();
+ const lastReplyId = lastReply.getId();
+ // Some unsent events do not have an ID, we do not want to consider them read
+ if (beforeFirstThreadedReceipt && lastReplyId) {
+ return lastReplyId;
+ }
+ }
+ const readUpToId = super.getEventReadUpTo(userId, ignoreSynthesized);
+
+ // Check whether the unthreaded read receipt for that user is more recent
+ // than the read receipt inside that thread.
+ if (lastReply) {
+ const unthreadedReceipt = this.room.getLastUnthreadedReceiptFor(userId);
+ if (!unthreadedReceipt) {
+ return readUpToId;
+ }
+ for (let i = ((_this$timeline = this.timeline) === null || _this$timeline === void 0 ? void 0 : _this$timeline.length) - 1; i >= 0; --i) {
+ var _this$timeline, _ev$getId;
+ const ev = this.timeline[i];
+ // If we encounter the `readUpToId` we do not need to look further
+ // there is no "more recent" unthreaded read receipt
+ if (ev.getId() === readUpToId) return readUpToId;
+
+ // Inspecting events from most recent to oldest, we're checking
+ // whether an unthreaded read receipt is more recent that the current event.
+ // We usually prefer relying on the order of the DAG but in this scenario
+ // it is not possible and we have to rely on timestamp
+ if (ev.getTs() < unthreadedReceipt.ts) return (_ev$getId = ev.getId()) !== null && _ev$getId !== void 0 ? _ev$getId : readUpToId;
+ }
+ }
+ return readUpToId;
+ }
+
+ /**
+ * Determine if the given user has read a particular event.
+ *
+ * It is invalid to call this method with an event that is not part of this thread.
+ *
+ * This is not a definitive check as it only checks the events that have been
+ * loaded client-side at the time of execution.
+ * @param userId - The user ID to check the read state of.
+ * @param eventId - The event ID to check if the user read.
+ * @returns True if the user has read the event, false otherwise.
+ */
+ hasUserReadEvent(userId, eventId) {
+ if (userId === this.client.getUserId()) {
+ var _this$lastReply$getTs, _this$lastReply, _this$room$getLastUnt, _this$room$getLastUnt2, _this$lastReply$getTs2, _this$lastReply2;
+ // Consider an event read if it's part of a thread that is before the
+ // first threaded receipt sent in that room. It is likely that it is
+ // part of a thread that was created before MSC3771 was implemented.
+ // Or before the last unthreaded receipt for the logged in user
+ const beforeFirstThreadedReceipt = ((_this$lastReply$getTs = (_this$lastReply = this.lastReply()) === null || _this$lastReply === void 0 ? void 0 : _this$lastReply.getTs()) !== null && _this$lastReply$getTs !== void 0 ? _this$lastReply$getTs : 0) < this.room.getOldestThreadedReceiptTs();
+ const unthreadedReceiptTs = (_this$room$getLastUnt = (_this$room$getLastUnt2 = this.room.getLastUnthreadedReceiptFor(userId)) === null || _this$room$getLastUnt2 === void 0 ? void 0 : _this$room$getLastUnt2.ts) !== null && _this$room$getLastUnt !== void 0 ? _this$room$getLastUnt : 0;
+ const beforeLastUnthreadedReceipt = ((_this$lastReply$getTs2 = this === null || this === void 0 ? void 0 : (_this$lastReply2 = this.lastReply()) === null || _this$lastReply2 === void 0 ? void 0 : _this$lastReply2.getTs()) !== null && _this$lastReply$getTs2 !== void 0 ? _this$lastReply$getTs2 : 0) < unthreadedReceiptTs;
+ if (beforeFirstThreadedReceipt || beforeLastUnthreadedReceipt) {
+ return true;
+ }
+ }
+ return super.hasUserReadEvent(userId, eventId);
+ }
+ setUnread(type, count) {
+ return this.room.setThreadUnreadNotificationCount(this.id, type, count);
+ }
+}
+exports.Thread = Thread;
+(0, _defineProperty2.default)(Thread, "hasServerSideSupport", FeatureSupport.None);
+(0, _defineProperty2.default)(Thread, "hasServerSideListSupport", FeatureSupport.None);
+(0, _defineProperty2.default)(Thread, "hasServerSideFwdPaginationSupport", FeatureSupport.None);
+const FILTER_RELATED_BY_SENDERS = new _NamespacedValue.ServerControlledNamespacedValue("related_by_senders", "io.element.relation_senders");
+exports.FILTER_RELATED_BY_SENDERS = FILTER_RELATED_BY_SENDERS;
+const FILTER_RELATED_BY_REL_TYPES = new _NamespacedValue.ServerControlledNamespacedValue("related_by_rel_types", "io.element.relation_types");
+exports.FILTER_RELATED_BY_REL_TYPES = FILTER_RELATED_BY_REL_TYPES;
+const THREAD_RELATION_TYPE = new _NamespacedValue.ServerControlledNamespacedValue("m.thread", "io.element.thread");
+exports.THREAD_RELATION_TYPE = THREAD_RELATION_TYPE;
+let ThreadFilterType;
+exports.ThreadFilterType = ThreadFilterType;
+(function (ThreadFilterType) {
+ ThreadFilterType[ThreadFilterType["My"] = 0] = "My";
+ ThreadFilterType[ThreadFilterType["All"] = 1] = "All";
+})(ThreadFilterType || (exports.ThreadFilterType = ThreadFilterType = {}));
+function threadFilterTypeToFilter(type) {
+ switch (type) {
+ case ThreadFilterType.My:
+ return "participated";
+ default:
+ return "all";
+ }
+}
+//# sourceMappingURL=thread.js.map \ No newline at end of file
diff --git a/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/thread.js.map b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/thread.js.map
new file mode 100644
index 0000000..75f50b5
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/thread.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"thread.js","names":["_client","require","_ReEmitter","_event","_event2","_eventTimeline","_eventTimelineSet","_room","_NamespacedValue","_logger","_readReceipt","_read_receipts","ownKeys","object","enumerableOnly","keys","Object","getOwnPropertySymbols","symbols","filter","sym","getOwnPropertyDescriptor","enumerable","push","apply","_objectSpread","target","i","arguments","length","source","forEach","key","_defineProperty2","default","getOwnPropertyDescriptors","defineProperties","defineProperty","ThreadEvent","exports","FeatureSupport","determineFeatureSupport","stable","unstable","Stable","Experimental","None","Thread","ReadReceipt","constructor","id","rootEvent","opts","_opts$pendingEventOrd","hasServerSideSupport","event","redaction","isRelation","THREAD_RELATION_TYPE","name","room","eventShouldLiveIn","threadId","getId","status","replyCount","updatePendingReplyCount","emit","Update","threadRootId","threadEvent","timeline","clearEventMetadata","lastEvent","_currentUserParticipated","Delete","updateThreadMetadata","toStartOfTimeline","addLocalEchoReceipt","getSender","ReceiptType","Read","onEcho","NewReply","Error","client","pendingEventOrdering","PendingEventOrdering","Chronological","timelineSet","EventTimelineSet","timelineSupport","pendingEvents","reEmitter","TypedReEmitter","reEmit","RoomEvent","Timeline","TimelineReset","on","MatrixEventEvent","BeforeRedaction","onBeforeRedaction","Redaction","onRedaction","LocalEchoUpdated","onLocalEcho","onTimelineEvent","processReceipts","receipts","setEventMetadata","fetchRootEvent","findEventById","eventData","fetchRoomEvent","roomId","mapper","getEventMapper","e","logger","error","processEvent","setServerSideSupport","FILTER_RELATED_BY_SENDERS","setPreferUnstable","FILTER_RELATED_BY_REL_TYPES","setServerSideListSupport","hasServerSideListSupport","setServerSideFwdPaginationSupport","hasServerSideFwdPaginationSupport","roomState","getLiveTimeline","getState","EventTimeline","FORWARDS","addEventToTimeline","liveTimeline","fromCache","events","addEvents","ev","addEvent","lastReply","isNewestReply","localTimestamp","decryptEventIfNeeded","initialEventsFetched","fetchEditsWhereNeeded","RelationType","Annotation","Replace","_this$timelineSet$rel","_this$timelineSet$rel2","_this$replayEvents","replayEvents","relations","aggregateParentEvent","aggregateChildEvent","eventId","receiptType","userId","receipt","synthetic","addReceiptToStructure","getRootEventBundledRelationship","getServerAggregatedRelation","processRootEvent","bundledRelationship","count","current_user_participated","latest_event","room_id","unfilteredPendingEvents","Detached","getPendingEvents","_this$lastEvent","lastPendingEvent","undefined","pendingReplyCount","resetLiveTimeline","backPaginationToken","forwardPaginationToken","oldLive","newLive","newBackward","oldForward","res","createMessagesRequest","Direction","Forward","end","Backward","start","getPaginationToken","_oldForward","setPaginationToken","_newBackward","addEventsToTimeline","paginateEventTimeline","backwards","limit","Math","max","Promise","all","isEncrypted","map","getType","then","makeReplaced","catch","setThread","_event$event","_event$event$unsigned","_event$event$unsigned2","unsigned","matches","replyToEvent","_ref","_this$lastPendingEven","getEvents","has","MatrixEvent","hasCurrentUserParticipated","getUnfilteredTimelineSet","addReceipt","getEventReadUpTo","ignoreSynthesized","isCurrentUser","getUserId","beforeFirstThreadedReceipt","getTs","getOldestThreadedReceiptTs","lastReplyId","readUpToId","unthreadedReceipt","getLastUnthreadedReceiptFor","_this$timeline","_ev$getId","ts","hasUserReadEvent","_this$lastReply$getTs","_this$lastReply","_this$room$getLastUnt","_this$room$getLastUnt2","_this$lastReply$getTs2","_this$lastReply2","unthreadedReceiptTs","beforeLastUnthreadedReceipt","setUnread","type","setThreadUnreadNotificationCount","ServerControlledNamespacedValue","ThreadFilterType","threadFilterTypeToFilter","My"],"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 { Optional } from \"matrix-events-sdk\";\n\nimport { MatrixClient, PendingEventOrdering } from \"../client\";\nimport { TypedReEmitter } from \"../ReEmitter\";\nimport { RelationType } from \"../@types/event\";\nimport { IThreadBundledRelationship, MatrixEvent, MatrixEventEvent } from \"./event\";\nimport { Direction, EventTimeline } from \"./event-timeline\";\nimport { EventTimelineSet, EventTimelineSetHandlerMap } from \"./event-timeline-set\";\nimport { NotificationCountType, Room, RoomEvent } from \"./room\";\nimport { RoomState } from \"./room-state\";\nimport { ServerControlledNamespacedValue } from \"../NamespacedValue\";\nimport { logger } from \"../logger\";\nimport { ReadReceipt } from \"./read-receipt\";\nimport { CachedReceiptStructure, ReceiptType } from \"../@types/read_receipts\";\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\ntype EmittedEvents = Exclude<ThreadEvent, ThreadEvent.New> | RoomEvent.Timeline | RoomEvent.TimelineReset;\n\nexport type EventHandlerMap = {\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<EmittedEvents, EventHandlerMap> {\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 public timeline: MatrixEvent[] = [];\n\n private _currentUserParticipated = false;\n\n private reEmitter: TypedReEmitter<EmittedEvents, EventHandlerMap>;\n\n private lastEvent: MatrixEvent | undefined;\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\n public initialEventsFetched = !Thread.hasServerSideSupport;\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(public readonly id: string, public rootEvent: MatrixEvent | undefined, opts: IThreadOpts) {\n super();\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.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 async fetchRootEvent(): Promise<void> {\n this.rootEvent = this.room.findEventById(this.id);\n // If the rootEvent does not exist in the local stores, then fetch it from the server.\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 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): Promise<void> => {\n if (event.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 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 room!.addLocalEchoReceipt(event.getSender()!, event, ReceiptType.Read);\n }\n this.onEcho(event, toStartOfTimeline ?? false);\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 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 });\n this.timeline = this.events;\n }\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 async addEvent(event: MatrixEvent, toStartOfTimeline: boolean, emit = true): Promise<void> {\n this.setEventMetadata(event);\n\n const lastReply = this.lastReply();\n const isNewestReply = !lastReply || event.localTimestamp >= lastReply!.localTimestamp;\n\n // Add all incoming events to the thread's timeline set when there's no server support\n if (!Thread.hasServerSideSupport) {\n // all the relevant membership info to hydrate events with a sender\n // is held in the main room timeline\n // We want to fetch the room state from there and pass it down to this thread\n // timeline set to let it reconcile an event with its relevant RoomMember\n this.addEventToTimeline(event, toStartOfTimeline);\n\n this.client.decryptEventIfNeeded(event, {});\n } else if (!toStartOfTimeline && this.initialEventsFetched && isNewestReply) {\n this.addEventToTimeline(event, false);\n this.fetchEditsWhereNeeded(event);\n } else if (event.isRelation(RelationType.Annotation) || event.isRelation(RelationType.Replace)) {\n if (!this.initialEventsFetched) {\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 } else {\n this.addEventToTimeline(event, toStartOfTimeline);\n }\n // Apply annotations and replace relations to the relations of the timeline only\n this.timelineSet.relations?.aggregateParentEvent(event);\n this.timelineSet.relations?.aggregateChildEvent(event, this.timelineSet);\n return;\n }\n\n // If no thread support exists we want to count all thread relation\n // added as a reply. We can't rely on the bundled relationships count\n if ((!Thread.hasServerSideSupport || !this.rootEvent) && event.isRelation(THREAD_RELATION_TYPE.name)) {\n this.replyCount++;\n }\n\n if (emit) {\n this.emit(ThreadEvent.NewReply, this, event);\n this.updateThreadMetadata();\n }\n }\n\n public async processEvent(event: Optional<MatrixEvent>): Promise<void> {\n if (event) {\n this.setEventMetadata(event);\n await this.fetchEditsWhereNeeded(event);\n }\n this.timeline = this.events;\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 updateThreadMetadata(): Promise<void> {\n this.updatePendingReplyCount();\n\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) {\n await this.processRootEvent();\n }\n await this.fetchRootEvent();\n }\n await this.processRootEvent();\n\n if (!this.initialEventsFetched) {\n this.initialEventsFetched = true;\n // fetch initial event to allow proper pagination\n try {\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, this.liveTimeline, null);\n this.liveTimeline.setPaginationToken(null, Direction.Backward);\n } else {\n await this.client.paginateEventTimeline(this.liveTimeline, {\n backwards: true,\n limit: Math.max(1, this.length),\n });\n }\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 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 return Promise.all(\n events\n .filter((e) => e.isEncrypted())\n .map((event: MatrixEvent) => {\n if (event.isRelation()) return; // skip - relations don't get edits\n return this.client\n .relations(this.roomId, event.getId()!, RelationType.Replace, event.getType(), {\n limit: 1,\n })\n .then((relations) => {\n if (relations.events.length) {\n event.makeReplaced(relations.events[0]);\n }\n })\n .catch((e) => {\n logger.error(\"Failed to load edits for encrypted thread event\", e);\n });\n }),\n );\n }\n\n public setEventMetadata(event: Optional<MatrixEvent>): void {\n if (event) {\n EventTimeline.setEventMetadata(event, this.roomState, false);\n event.setThread(this);\n }\n }\n\n public clearEventMetadata(event: Optional<MatrixEvent>): 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(matches: (ev: MatrixEvent) => boolean = (): boolean => true): 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(): Optional<MatrixEvent> {\n return this.lastPendingEvent ?? this.lastEvent ?? this.lastReply();\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 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 super.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\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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"} \ No newline at end of file
diff --git a/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/typed-event-emitter.d.ts b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/typed-event-emitter.d.ts
new file mode 100644
index 0000000..f6fd85c
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/typed-event-emitter.d.ts
@@ -0,0 +1,39 @@
+/// <reference types="node" />
+import { EventEmitter } from "events";
+export declare enum EventEmitterEvents {
+ NewListener = "newListener",
+ RemoveListener = "removeListener",
+ Error = "error"
+}
+type AnyListener = (...args: any) => any;
+export type ListenerMap<E extends string> = {
+ [eventName in E]: AnyListener;
+};
+type EventEmitterEventListener = (eventName: string, listener: AnyListener) => void;
+type EventEmitterErrorListener = (error: Error) => void;
+export type Listener<E extends string, A extends ListenerMap<E>, T extends E | EventEmitterEvents> = T extends E ? A[T] : T extends EventEmitterEvents ? EventEmitterErrorListener : EventEmitterEventListener;
+/**
+ * Typed Event Emitter class which can act as a Base Model for all our model
+ * and communication events.
+ * This makes it much easier for us to distinguish between events, as we now need
+ * to properly type this, so that our events are not stringly-based and prone
+ * to silly typos.
+ */
+export declare class TypedEventEmitter<Events extends string, Arguments extends ListenerMap<Events>, SuperclassArguments extends ListenerMap<any> = Arguments> extends EventEmitter {
+ addListener<T extends Events | EventEmitterEvents>(event: T, listener: Listener<Events, Arguments, T>): this;
+ emit<T extends Events>(event: T, ...args: Parameters<SuperclassArguments[T]>): boolean;
+ emit<T extends Events>(event: T, ...args: Parameters<Arguments[T]>): boolean;
+ eventNames(): (Events | EventEmitterEvents)[];
+ listenerCount(event: Events | EventEmitterEvents): number;
+ listeners(event: Events | EventEmitterEvents): ReturnType<EventEmitter["listeners"]>;
+ off<T extends Events | EventEmitterEvents>(event: T, listener: Listener<Events, Arguments, T>): this;
+ on<T extends Events | EventEmitterEvents>(event: T, listener: Listener<Events, Arguments, T>): this;
+ once<T extends Events | EventEmitterEvents>(event: T, listener: Listener<Events, Arguments, T>): this;
+ prependListener<T extends Events | EventEmitterEvents>(event: T, listener: Listener<Events, Arguments, T>): this;
+ prependOnceListener<T extends Events | EventEmitterEvents>(event: T, listener: Listener<Events, Arguments, T>): this;
+ removeAllListeners(event?: Events | EventEmitterEvents): this;
+ removeListener<T extends Events | EventEmitterEvents>(event: T, listener: Listener<Events, Arguments, T>): this;
+ rawListeners(event: Events | EventEmitterEvents): ReturnType<EventEmitter["rawListeners"]>;
+}
+export {};
+//# sourceMappingURL=typed-event-emitter.d.ts.map \ No newline at end of file
diff --git a/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/typed-event-emitter.d.ts.map b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/typed-event-emitter.d.ts.map
new file mode 100644
index 0000000..5ac98df
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/typed-event-emitter.d.ts.map
@@ -0,0 +1 @@
+{"version":3,"file":"typed-event-emitter.d.ts","sourceRoot":"","sources":["../../src/models/typed-event-emitter.ts"],"names":[],"mappings":"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"} \ No newline at end of file
diff --git a/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/typed-event-emitter.js b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/typed-event-emitter.js
new file mode 100644
index 0000000..57fa136
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/typed-event-emitter.js
@@ -0,0 +1,80 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.TypedEventEmitter = exports.EventEmitterEvents = void 0;
+var _events = require("events");
+/*
+Copyright 2021 The Matrix.org Foundation C.I.C.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+// eslint-disable-next-line no-restricted-imports
+let EventEmitterEvents;
+exports.EventEmitterEvents = EventEmitterEvents;
+(function (EventEmitterEvents) {
+ EventEmitterEvents["NewListener"] = "newListener";
+ EventEmitterEvents["RemoveListener"] = "removeListener";
+ EventEmitterEvents["Error"] = "error";
+})(EventEmitterEvents || (exports.EventEmitterEvents = EventEmitterEvents = {}));
+/**
+ * Typed Event Emitter class which can act as a Base Model for all our model
+ * and communication events.
+ * This makes it much easier for us to distinguish between events, as we now need
+ * to properly type this, so that our events are not stringly-based and prone
+ * to silly typos.
+ */
+class TypedEventEmitter extends _events.EventEmitter {
+ addListener(event, listener) {
+ return super.addListener(event, listener);
+ }
+ emit(event, ...args) {
+ return super.emit(event, ...args);
+ }
+ eventNames() {
+ return super.eventNames();
+ }
+ listenerCount(event) {
+ return super.listenerCount(event);
+ }
+ listeners(event) {
+ return super.listeners(event);
+ }
+ off(event, listener) {
+ return super.off(event, listener);
+ }
+ on(event, listener) {
+ return super.on(event, listener);
+ }
+ once(event, listener) {
+ return super.once(event, listener);
+ }
+ prependListener(event, listener) {
+ return super.prependListener(event, listener);
+ }
+ prependOnceListener(event, listener) {
+ return super.prependOnceListener(event, listener);
+ }
+ removeAllListeners(event) {
+ return super.removeAllListeners(event);
+ }
+ removeListener(event, listener) {
+ return super.removeListener(event, listener);
+ }
+ rawListeners(event) {
+ return super.rawListeners(event);
+ }
+}
+exports.TypedEventEmitter = TypedEventEmitter;
+//# sourceMappingURL=typed-event-emitter.js.map \ No newline at end of file
diff --git a/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/typed-event-emitter.js.map b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/typed-event-emitter.js.map
new file mode 100644
index 0000000..bf1770d
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/typed-event-emitter.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"typed-event-emitter.js","names":["_events","require","EventEmitterEvents","exports","TypedEventEmitter","EventEmitter","addListener","event","listener","emit","args","eventNames","listenerCount","listeners","off","on","once","prependListener","prependOnceListener","removeAllListeners","removeListener","rawListeners"],"sources":["../../src/models/typed-event-emitter.ts"],"sourcesContent":["/*\nCopyright 2021 The Matrix.org Foundation C.I.C.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n*/\n\n// eslint-disable-next-line no-restricted-imports\nimport { EventEmitter } from \"events\";\n\nexport enum EventEmitterEvents {\n NewListener = \"newListener\",\n RemoveListener = \"removeListener\",\n Error = \"error\",\n}\n\ntype AnyListener = (...args: any) => any;\nexport type ListenerMap<E extends string> = { [eventName in E]: AnyListener };\ntype EventEmitterEventListener = (eventName: string, listener: AnyListener) => void;\ntype EventEmitterErrorListener = (error: Error) => void;\n\nexport type Listener<E extends string, A extends ListenerMap<E>, T extends E | EventEmitterEvents> = T extends E\n ? A[T]\n : T extends EventEmitterEvents\n ? EventEmitterErrorListener\n : EventEmitterEventListener;\n\n/**\n * Typed Event Emitter class which can act as a Base Model for all our model\n * and communication events.\n * This makes it much easier for us to distinguish between events, as we now need\n * to properly type this, so that our events are not stringly-based and prone\n * to silly typos.\n */\nexport class TypedEventEmitter<\n Events extends string,\n Arguments extends ListenerMap<Events>,\n SuperclassArguments extends ListenerMap<any> = Arguments,\n> extends EventEmitter {\n public addListener<T extends Events | EventEmitterEvents>(\n event: T,\n listener: Listener<Events, Arguments, T>,\n ): this {\n return super.addListener(event, listener);\n }\n\n public emit<T extends Events>(event: T, ...args: Parameters<SuperclassArguments[T]>): boolean;\n public emit<T extends Events>(event: T, ...args: Parameters<Arguments[T]>): boolean;\n public emit<T extends Events>(event: T, ...args: any[]): boolean {\n return super.emit(event, ...args);\n }\n\n public eventNames(): (Events | EventEmitterEvents)[] {\n return super.eventNames() as Array<Events | EventEmitterEvents>;\n }\n\n public listenerCount(event: Events | EventEmitterEvents): number {\n return super.listenerCount(event);\n }\n\n public listeners(event: Events | EventEmitterEvents): ReturnType<EventEmitter[\"listeners\"]> {\n return super.listeners(event);\n }\n\n public off<T extends Events | EventEmitterEvents>(event: T, listener: Listener<Events, Arguments, T>): this {\n return super.off(event, listener);\n }\n\n public on<T extends Events | EventEmitterEvents>(event: T, listener: Listener<Events, Arguments, T>): this {\n return super.on(event, listener);\n }\n\n public once<T extends Events | EventEmitterEvents>(event: T, listener: Listener<Events, Arguments, T>): this {\n return super.once(event, listener);\n }\n\n public prependListener<T extends Events | EventEmitterEvents>(\n event: T,\n listener: Listener<Events, Arguments, T>,\n ): this {\n return super.prependListener(event, listener);\n }\n\n public prependOnceListener<T extends Events | EventEmitterEvents>(\n event: T,\n listener: Listener<Events, Arguments, T>,\n ): this {\n return super.prependOnceListener(event, listener);\n }\n\n public removeAllListeners(event?: Events | EventEmitterEvents): this {\n return super.removeAllListeners(event);\n }\n\n public removeListener<T extends Events | EventEmitterEvents>(\n event: T,\n listener: Listener<Events, Arguments, T>,\n ): this {\n return super.removeListener(event, listener);\n }\n\n public rawListeners(event: Events | EventEmitterEvents): ReturnType<EventEmitter[\"rawListeners\"]> {\n return super.rawListeners(event);\n }\n}\n"],"mappings":";;;;;;AAiBA,IAAAA,OAAA,GAAAC,OAAA;AAjBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA,IAGYC,kBAAkB;AAAAC,OAAA,CAAAD,kBAAA,GAAAA,kBAAA;AAAA,WAAlBA,kBAAkB;EAAlBA,kBAAkB;EAAlBA,kBAAkB;EAAlBA,kBAAkB;AAAA,GAAlBA,kBAAkB,KAAAC,OAAA,CAAAD,kBAAA,GAAlBA,kBAAkB;AAiB9B;AACA;AACA;AACA;AACA;AACA;AACA;AACO,MAAME,iBAAiB,SAIpBC,oBAAY,CAAC;EACZC,WAAWA,CACdC,KAAQ,EACRC,QAAwC,EACpC;IACJ,OAAO,KAAK,CAACF,WAAW,CAACC,KAAK,EAAEC,QAAQ,CAAC;EAC7C;EAIOC,IAAIA,CAAmBF,KAAQ,EAAE,GAAGG,IAAW,EAAW;IAC7D,OAAO,KAAK,CAACD,IAAI,CAACF,KAAK,EAAE,GAAGG,IAAI,CAAC;EACrC;EAEOC,UAAUA,CAAA,EAAoC;IACjD,OAAO,KAAK,CAACA,UAAU,EAAE;EAC7B;EAEOC,aAAaA,CAACL,KAAkC,EAAU;IAC7D,OAAO,KAAK,CAACK,aAAa,CAACL,KAAK,CAAC;EACrC;EAEOM,SAASA,CAACN,KAAkC,EAAyC;IACxF,OAAO,KAAK,CAACM,SAAS,CAACN,KAAK,CAAC;EACjC;EAEOO,GAAGA,CAAwCP,KAAQ,EAAEC,QAAwC,EAAQ;IACxG,OAAO,KAAK,CAACM,GAAG,CAACP,KAAK,EAAEC,QAAQ,CAAC;EACrC;EAEOO,EAAEA,CAAwCR,KAAQ,EAAEC,QAAwC,EAAQ;IACvG,OAAO,KAAK,CAACO,EAAE,CAACR,KAAK,EAAEC,QAAQ,CAAC;EACpC;EAEOQ,IAAIA,CAAwCT,KAAQ,EAAEC,QAAwC,EAAQ;IACzG,OAAO,KAAK,CAACQ,IAAI,CAACT,KAAK,EAAEC,QAAQ,CAAC;EACtC;EAEOS,eAAeA,CAClBV,KAAQ,EACRC,QAAwC,EACpC;IACJ,OAAO,KAAK,CAACS,eAAe,CAACV,KAAK,EAAEC,QAAQ,CAAC;EACjD;EAEOU,mBAAmBA,CACtBX,KAAQ,EACRC,QAAwC,EACpC;IACJ,OAAO,KAAK,CAACU,mBAAmB,CAACX,KAAK,EAAEC,QAAQ,CAAC;EACrD;EAEOW,kBAAkBA,CAACZ,KAAmC,EAAQ;IACjE,OAAO,KAAK,CAACY,kBAAkB,CAACZ,KAAK,CAAC;EAC1C;EAEOa,cAAcA,CACjBb,KAAQ,EACRC,QAAwC,EACpC;IACJ,OAAO,KAAK,CAACY,cAAc,CAACb,KAAK,EAAEC,QAAQ,CAAC;EAChD;EAEOa,YAAYA,CAACd,KAAkC,EAA4C;IAC9F,OAAO,KAAK,CAACc,YAAY,CAACd,KAAK,CAAC;EACpC;AACJ;AAACJ,OAAA,CAAAC,iBAAA,GAAAA,iBAAA"} \ No newline at end of file
diff --git a/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/user.d.ts b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/user.d.ts
new file mode 100644
index 0000000..7dbfc5b
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/user.d.ts
@@ -0,0 +1,185 @@
+import { MatrixEvent } from "./event";
+import { TypedEventEmitter } from "./typed-event-emitter";
+export declare enum UserEvent {
+ DisplayName = "User.displayName",
+ AvatarUrl = "User.avatarUrl",
+ Presence = "User.presence",
+ CurrentlyActive = "User.currentlyActive",
+ LastPresenceTs = "User.lastPresenceTs"
+}
+export type UserEventHandlerMap = {
+ /**
+ * Fires whenever any user's display name changes.
+ * @param event - The matrix event which caused this event to fire.
+ * @param user - The user whose User.displayName changed.
+ * @example
+ * ```
+ * matrixClient.on("User.displayName", function(event, user){
+ * var newName = user.displayName;
+ * });
+ * ```
+ */
+ [UserEvent.DisplayName]: (event: MatrixEvent | undefined, user: User) => void;
+ /**
+ * Fires whenever any user's avatar URL changes.
+ * @param event - The matrix event which caused this event to fire.
+ * @param user - The user whose User.avatarUrl changed.
+ * @example
+ * ```
+ * matrixClient.on("User.avatarUrl", function(event, user){
+ * var newUrl = user.avatarUrl;
+ * });
+ * ```
+ */
+ [UserEvent.AvatarUrl]: (event: MatrixEvent | undefined, user: User) => void;
+ /**
+ * Fires whenever any user's presence changes.
+ * @param event - The matrix event which caused this event to fire.
+ * @param user - The user whose User.presence changed.
+ * @example
+ * ```
+ * matrixClient.on("User.presence", function(event, user){
+ * var newPresence = user.presence;
+ * });
+ * ```
+ */
+ [UserEvent.Presence]: (event: MatrixEvent | undefined, user: User) => void;
+ /**
+ * Fires whenever any user's currentlyActive changes.
+ * @param event - The matrix event which caused this event to fire.
+ * @param user - The user whose User.currentlyActive changed.
+ * @example
+ * ```
+ * matrixClient.on("User.currentlyActive", function(event, user){
+ * var newCurrentlyActive = user.currentlyActive;
+ * });
+ * ```
+ */
+ [UserEvent.CurrentlyActive]: (event: MatrixEvent | undefined, user: User) => void;
+ /**
+ * Fires whenever any user's lastPresenceTs changes,
+ * ie. whenever any presence event is received for a user.
+ * @param event - The matrix event which caused this event to fire.
+ * @param user - The user whose User.lastPresenceTs changed.
+ * @example
+ * ```
+ * matrixClient.on("User.lastPresenceTs", function(event, user){
+ * var newlastPresenceTs = user.lastPresenceTs;
+ * });
+ * ```
+ */
+ [UserEvent.LastPresenceTs]: (event: MatrixEvent | undefined, user: User) => void;
+};
+export declare class User extends TypedEventEmitter<UserEvent, UserEventHandlerMap> {
+ readonly userId: string;
+ private modified;
+ /**
+ * The 'displayname' of the user if known.
+ * @privateRemarks
+ * Should be read-only
+ */
+ displayName?: string;
+ rawDisplayName?: string;
+ /**
+ * The 'avatar_url' of the user if known.
+ * @privateRemarks
+ * Should be read-only
+ */
+ avatarUrl?: string;
+ /**
+ * The presence status message if known.
+ * @privateRemarks
+ * Should be read-only
+ */
+ presenceStatusMsg?: string;
+ /**
+ * The presence enum if known.
+ * @privateRemarks
+ * Should be read-only
+ */
+ presence: string;
+ /**
+ * Timestamp (ms since the epoch) for when we last received presence data for this user.
+ * We can subtract lastActiveAgo from this to approximate an absolute value for when a user was last active.
+ * @privateRemarks
+ * Should be read-only
+ */
+ lastActiveAgo: number;
+ /**
+ * The time elapsed in ms since the user interacted proactively with the server,
+ * or we saw a message from the user
+ * @privateRemarks
+ * Should be read-only
+ */
+ lastPresenceTs: number;
+ /**
+ * Whether we should consider lastActiveAgo to be an approximation
+ * and that the user should be seen as active 'now'
+ * @privateRemarks
+ * Should be read-only
+ */
+ currentlyActive: boolean;
+ /**
+ * The events describing this user.
+ * @privateRemarks
+ * Should be read-only
+ */
+ events: {
+ /** The m.presence event for this user. */
+ presence?: MatrixEvent;
+ profile?: MatrixEvent;
+ };
+ /**
+ * Construct a new User. A User must have an ID and can optionally have extra information associated with it.
+ * @param userId - Required. The ID of this user.
+ */
+ constructor(userId: string);
+ /**
+ * Update this User with the given presence event. May fire "User.presence",
+ * "User.avatarUrl" and/or "User.displayName" if this event updates this user's
+ * properties.
+ * @param event - The `m.presence` event.
+ *
+ * @remarks
+ * Fires {@link UserEvent.Presence}
+ * Fires {@link UserEvent.DisplayName}
+ * Fires {@link UserEvent.AvatarUrl}
+ */
+ setPresenceEvent(event: MatrixEvent): void;
+ /**
+ * Manually set this user's display name. No event is emitted in response to this
+ * as there is no underlying MatrixEvent to emit with.
+ * @param name - The new display name.
+ */
+ setDisplayName(name: string): void;
+ /**
+ * Manually set this user's non-disambiguated display name. No event is emitted
+ * in response to this as there is no underlying MatrixEvent to emit with.
+ * @param name - The new display name.
+ */
+ setRawDisplayName(name?: string): void;
+ /**
+ * Manually set this user's avatar URL. No event is emitted in response to this
+ * as there is no underlying MatrixEvent to emit with.
+ * @param url - The new avatar URL.
+ */
+ setAvatarUrl(url?: string): void;
+ /**
+ * Update the last modified time to the current time.
+ */
+ private updateModifiedTime;
+ /**
+ * Get the timestamp when this User was last updated. This timestamp is
+ * updated when this User receives a new Presence event which has updated a
+ * property on this object. It is updated <i>before</i> firing events.
+ * @returns The timestamp
+ */
+ getLastModifiedTime(): number;
+ /**
+ * Get the absolute timestamp when this User was last known active on the server.
+ * It is *NOT* accurate if this.currentlyActive is true.
+ * @returns The timestamp
+ */
+ getLastActiveTs(): number;
+}
+//# sourceMappingURL=user.d.ts.map \ No newline at end of file
diff --git a/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/user.d.ts.map b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/user.d.ts.map
new file mode 100644
index 0000000..a21f2c0
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/user.d.ts.map
@@ -0,0 +1 @@
+{"version":3,"file":"user.d.ts","sourceRoot":"","sources":["../../src/models/user.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AACtC,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAE1D,oBAAY,SAAS;IACjB,WAAW,qBAAqB;IAChC,SAAS,mBAAmB;IAC5B,QAAQ,kBAAkB;IAC1B,eAAe,yBAAyB;IACxC,cAAc,wBAAwB;CACzC;AAED,MAAM,MAAM,mBAAmB,GAAG;IAC9B;;;;;;;;;;OAUG;IACH,CAAC,SAAS,CAAC,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,WAAW,GAAG,SAAS,EAAE,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;IAC9E;;;;;;;;;;OAUG;IACH,CAAC,SAAS,CAAC,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,WAAW,GAAG,SAAS,EAAE,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;IAC5E;;;;;;;;;;OAUG;IACH,CAAC,SAAS,CAAC,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,WAAW,GAAG,SAAS,EAAE,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;IAC3E;;;;;;;;;;OAUG;IACH,CAAC,SAAS,CAAC,eAAe,CAAC,EAAE,CAAC,KAAK,EAAE,WAAW,GAAG,SAAS,EAAE,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;IAClF;;;;;;;;;;;OAWG;IACH,CAAC,SAAS,CAAC,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,WAAW,GAAG,SAAS,EAAE,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;CACpF,CAAC;AAEF,qBAAa,IAAK,SAAQ,iBAAiB,CAAC,SAAS,EAAE,mBAAmB,CAAC;aAgEpC,MAAM,EAAE,MAAM;IA/DjD,OAAO,CAAC,QAAQ,CAAM;IAEtB;;;;OAIG;IACI,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,CAAC;IAC/B;;;;OAIG;IACI,SAAS,CAAC,EAAE,MAAM,CAAC;IAC1B;;;;OAIG;IACI,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAClC;;;;OAIG;IACI,QAAQ,SAAa;IAC5B;;;;;OAKG;IACI,aAAa,SAAK;IACzB;;;;;OAKG;IACI,cAAc,SAAK;IAC1B;;;;;OAKG;IACI,eAAe,UAAS;IAC/B;;;;OAIG;IACI,MAAM,EAAE;QACX,0CAA0C;QAC1C,QAAQ,CAAC,EAAE,WAAW,CAAC;QACvB,OAAO,CAAC,EAAE,WAAW,CAAC;KACzB,CAAM;IAEP;;;OAGG;gBACgC,MAAM,EAAE,MAAM;IAOjD;;;;;;;;;;OAUG;IACI,gBAAgB,CAAC,KAAK,EAAE,WAAW,GAAG,IAAI;IA+CjD;;;;OAIG;IACI,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAQzC;;;;OAIG;IACI,iBAAiB,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI;IAI7C;;;;OAIG;IACI,YAAY,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI;IAQvC;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAI1B;;;;;OAKG;IACI,mBAAmB,IAAI,MAAM;IAIpC;;;;OAIG;IACI,eAAe,IAAI,MAAM;CAGnC"} \ No newline at end of file
diff --git a/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/user.js b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/user.js
new file mode 100644
index 0000000..ba78068
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/user.js
@@ -0,0 +1,220 @@
+"use strict";
+
+var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.UserEvent = exports.User = void 0;
+var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
+var _typedEventEmitter = require("./typed-event-emitter");
+/*
+Copyright 2015 - 2021 The Matrix.org Foundation C.I.C.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+let UserEvent;
+exports.UserEvent = UserEvent;
+(function (UserEvent) {
+ UserEvent["DisplayName"] = "User.displayName";
+ UserEvent["AvatarUrl"] = "User.avatarUrl";
+ UserEvent["Presence"] = "User.presence";
+ UserEvent["CurrentlyActive"] = "User.currentlyActive";
+ UserEvent["LastPresenceTs"] = "User.lastPresenceTs";
+})(UserEvent || (exports.UserEvent = UserEvent = {}));
+class User extends _typedEventEmitter.TypedEventEmitter {
+ /**
+ * The 'displayname' of the user if known.
+ * @privateRemarks
+ * Should be read-only
+ */
+
+ /**
+ * The 'avatar_url' of the user if known.
+ * @privateRemarks
+ * Should be read-only
+ */
+
+ /**
+ * The presence status message if known.
+ * @privateRemarks
+ * Should be read-only
+ */
+
+ /**
+ * The presence enum if known.
+ * @privateRemarks
+ * Should be read-only
+ */
+
+ /**
+ * Timestamp (ms since the epoch) for when we last received presence data for this user.
+ * We can subtract lastActiveAgo from this to approximate an absolute value for when a user was last active.
+ * @privateRemarks
+ * Should be read-only
+ */
+
+ /**
+ * The time elapsed in ms since the user interacted proactively with the server,
+ * or we saw a message from the user
+ * @privateRemarks
+ * Should be read-only
+ */
+
+ /**
+ * Whether we should consider lastActiveAgo to be an approximation
+ * and that the user should be seen as active 'now'
+ * @privateRemarks
+ * Should be read-only
+ */
+
+ /**
+ * The events describing this user.
+ * @privateRemarks
+ * Should be read-only
+ */
+
+ /**
+ * Construct a new User. A User must have an ID and can optionally have extra information associated with it.
+ * @param userId - Required. The ID of this user.
+ */
+ constructor(userId) {
+ super();
+ this.userId = userId;
+ (0, _defineProperty2.default)(this, "modified", -1);
+ (0, _defineProperty2.default)(this, "displayName", void 0);
+ (0, _defineProperty2.default)(this, "rawDisplayName", void 0);
+ (0, _defineProperty2.default)(this, "avatarUrl", void 0);
+ (0, _defineProperty2.default)(this, "presenceStatusMsg", void 0);
+ (0, _defineProperty2.default)(this, "presence", "offline");
+ (0, _defineProperty2.default)(this, "lastActiveAgo", 0);
+ (0, _defineProperty2.default)(this, "lastPresenceTs", 0);
+ (0, _defineProperty2.default)(this, "currentlyActive", false);
+ (0, _defineProperty2.default)(this, "events", {});
+ this.displayName = userId;
+ this.rawDisplayName = userId;
+ this.updateModifiedTime();
+ }
+
+ /**
+ * Update this User with the given presence event. May fire "User.presence",
+ * "User.avatarUrl" and/or "User.displayName" if this event updates this user's
+ * properties.
+ * @param event - The `m.presence` event.
+ *
+ * @remarks
+ * Fires {@link UserEvent.Presence}
+ * Fires {@link UserEvent.DisplayName}
+ * Fires {@link UserEvent.AvatarUrl}
+ */
+ setPresenceEvent(event) {
+ if (event.getType() !== "m.presence") {
+ return;
+ }
+ const firstFire = this.events.presence === null;
+ this.events.presence = event;
+ const eventsToFire = [];
+ if (event.getContent().presence !== this.presence || firstFire) {
+ eventsToFire.push(UserEvent.Presence);
+ }
+ if (event.getContent().avatar_url && event.getContent().avatar_url !== this.avatarUrl) {
+ eventsToFire.push(UserEvent.AvatarUrl);
+ }
+ if (event.getContent().displayname && event.getContent().displayname !== this.displayName) {
+ eventsToFire.push(UserEvent.DisplayName);
+ }
+ if (event.getContent().currently_active !== undefined && event.getContent().currently_active !== this.currentlyActive) {
+ eventsToFire.push(UserEvent.CurrentlyActive);
+ }
+ this.presence = event.getContent().presence;
+ eventsToFire.push(UserEvent.LastPresenceTs);
+ if (event.getContent().status_msg) {
+ this.presenceStatusMsg = event.getContent().status_msg;
+ }
+ if (event.getContent().displayname) {
+ this.displayName = event.getContent().displayname;
+ }
+ if (event.getContent().avatar_url) {
+ this.avatarUrl = event.getContent().avatar_url;
+ }
+ this.lastActiveAgo = event.getContent().last_active_ago;
+ this.lastPresenceTs = Date.now();
+ this.currentlyActive = event.getContent().currently_active;
+ this.updateModifiedTime();
+ for (const eventToFire of eventsToFire) {
+ this.emit(eventToFire, event, this);
+ }
+ }
+
+ /**
+ * Manually set this user's display name. No event is emitted in response to this
+ * as there is no underlying MatrixEvent to emit with.
+ * @param name - The new display name.
+ */
+ setDisplayName(name) {
+ const oldName = this.displayName;
+ this.displayName = name;
+ if (name !== oldName) {
+ this.updateModifiedTime();
+ }
+ }
+
+ /**
+ * Manually set this user's non-disambiguated display name. No event is emitted
+ * in response to this as there is no underlying MatrixEvent to emit with.
+ * @param name - The new display name.
+ */
+ setRawDisplayName(name) {
+ this.rawDisplayName = name;
+ }
+
+ /**
+ * Manually set this user's avatar URL. No event is emitted in response to this
+ * as there is no underlying MatrixEvent to emit with.
+ * @param url - The new avatar URL.
+ */
+ setAvatarUrl(url) {
+ const oldUrl = this.avatarUrl;
+ this.avatarUrl = url;
+ if (url !== oldUrl) {
+ this.updateModifiedTime();
+ }
+ }
+
+ /**
+ * Update the last modified time to the current time.
+ */
+ updateModifiedTime() {
+ this.modified = Date.now();
+ }
+
+ /**
+ * Get the timestamp when this User was last updated. This timestamp is
+ * updated when this User receives a new Presence event which has updated a
+ * property on this object. It is updated <i>before</i> firing events.
+ * @returns The timestamp
+ */
+ getLastModifiedTime() {
+ return this.modified;
+ }
+
+ /**
+ * Get the absolute timestamp when this User was last known active on the server.
+ * It is *NOT* accurate if this.currentlyActive is true.
+ * @returns The timestamp
+ */
+ getLastActiveTs() {
+ return this.lastPresenceTs - this.lastActiveAgo;
+ }
+}
+exports.User = User;
+//# sourceMappingURL=user.js.map \ No newline at end of file
diff --git a/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/user.js.map b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/user.js.map
new file mode 100644
index 0000000..fbc10e5
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-js-sdk/lib/models/user.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"user.js","names":["_typedEventEmitter","require","UserEvent","exports","User","TypedEventEmitter","constructor","userId","_defineProperty2","default","displayName","rawDisplayName","updateModifiedTime","setPresenceEvent","event","getType","firstFire","events","presence","eventsToFire","getContent","push","Presence","avatar_url","avatarUrl","AvatarUrl","displayname","DisplayName","currently_active","undefined","currentlyActive","CurrentlyActive","LastPresenceTs","status_msg","presenceStatusMsg","lastActiveAgo","last_active_ago","lastPresenceTs","Date","now","eventToFire","emit","setDisplayName","name","oldName","setRawDisplayName","setAvatarUrl","url","oldUrl","modified","getLastModifiedTime","getLastActiveTs"],"sources":["../../src/models/user.ts"],"sourcesContent":["/*\nCopyright 2015 - 2021 The Matrix.org Foundation C.I.C.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n*/\n\nimport { MatrixEvent } from \"./event\";\nimport { TypedEventEmitter } from \"./typed-event-emitter\";\n\nexport enum UserEvent {\n DisplayName = \"User.displayName\",\n AvatarUrl = \"User.avatarUrl\",\n Presence = \"User.presence\",\n CurrentlyActive = \"User.currentlyActive\",\n LastPresenceTs = \"User.lastPresenceTs\",\n}\n\nexport type UserEventHandlerMap = {\n /**\n * Fires whenever any user's display name changes.\n * @param event - The matrix event which caused this event to fire.\n * @param user - The user whose User.displayName changed.\n * @example\n * ```\n * matrixClient.on(\"User.displayName\", function(event, user){\n * var newName = user.displayName;\n * });\n * ```\n */\n [UserEvent.DisplayName]: (event: MatrixEvent | undefined, user: User) => void;\n /**\n * Fires whenever any user's avatar URL changes.\n * @param event - The matrix event which caused this event to fire.\n * @param user - The user whose User.avatarUrl changed.\n * @example\n * ```\n * matrixClient.on(\"User.avatarUrl\", function(event, user){\n * var newUrl = user.avatarUrl;\n * });\n * ```\n */\n [UserEvent.AvatarUrl]: (event: MatrixEvent | undefined, user: User) => void;\n /**\n * Fires whenever any user's presence changes.\n * @param event - The matrix event which caused this event to fire.\n * @param user - The user whose User.presence changed.\n * @example\n * ```\n * matrixClient.on(\"User.presence\", function(event, user){\n * var newPresence = user.presence;\n * });\n * ```\n */\n [UserEvent.Presence]: (event: MatrixEvent | undefined, user: User) => void;\n /**\n * Fires whenever any user's currentlyActive changes.\n * @param event - The matrix event which caused this event to fire.\n * @param user - The user whose User.currentlyActive changed.\n * @example\n * ```\n * matrixClient.on(\"User.currentlyActive\", function(event, user){\n * var newCurrentlyActive = user.currentlyActive;\n * });\n * ```\n */\n [UserEvent.CurrentlyActive]: (event: MatrixEvent | undefined, user: User) => void;\n /**\n * Fires whenever any user's lastPresenceTs changes,\n * ie. whenever any presence event is received for a user.\n * @param event - The matrix event which caused this event to fire.\n * @param user - The user whose User.lastPresenceTs changed.\n * @example\n * ```\n * matrixClient.on(\"User.lastPresenceTs\", function(event, user){\n * var newlastPresenceTs = user.lastPresenceTs;\n * });\n * ```\n */\n [UserEvent.LastPresenceTs]: (event: MatrixEvent | undefined, user: User) => void;\n};\n\nexport class User extends TypedEventEmitter<UserEvent, UserEventHandlerMap> {\n private modified = -1;\n\n /**\n * The 'displayname' of the user if known.\n * @privateRemarks\n * Should be read-only\n */\n public displayName?: string;\n public rawDisplayName?: string;\n /**\n * The 'avatar_url' of the user if known.\n * @privateRemarks\n * Should be read-only\n */\n public avatarUrl?: string;\n /**\n * The presence status message if known.\n * @privateRemarks\n * Should be read-only\n */\n public presenceStatusMsg?: string;\n /**\n * The presence enum if known.\n * @privateRemarks\n * Should be read-only\n */\n public presence = \"offline\";\n /**\n * Timestamp (ms since the epoch) for when we last received presence data for this user.\n * We can subtract lastActiveAgo from this to approximate an absolute value for when a user was last active.\n * @privateRemarks\n * Should be read-only\n */\n public lastActiveAgo = 0;\n /**\n * The time elapsed in ms since the user interacted proactively with the server,\n * or we saw a message from the user\n * @privateRemarks\n * Should be read-only\n */\n public lastPresenceTs = 0;\n /**\n * Whether we should consider lastActiveAgo to be an approximation\n * and that the user should be seen as active 'now'\n * @privateRemarks\n * Should be read-only\n */\n public currentlyActive = false;\n /**\n * The events describing this user.\n * @privateRemarks\n * Should be read-only\n */\n public events: {\n /** The m.presence event for this user. */\n presence?: MatrixEvent;\n profile?: MatrixEvent;\n } = {};\n\n /**\n * Construct a new User. A User must have an ID and can optionally have extra information associated with it.\n * @param userId - Required. The ID of this user.\n */\n public constructor(public readonly userId: string) {\n super();\n this.displayName = userId;\n this.rawDisplayName = userId;\n this.updateModifiedTime();\n }\n\n /**\n * Update this User with the given presence event. May fire \"User.presence\",\n * \"User.avatarUrl\" and/or \"User.displayName\" if this event updates this user's\n * properties.\n * @param event - The `m.presence` event.\n *\n * @remarks\n * Fires {@link UserEvent.Presence}\n * Fires {@link UserEvent.DisplayName}\n * Fires {@link UserEvent.AvatarUrl}\n */\n public setPresenceEvent(event: MatrixEvent): void {\n if (event.getType() !== \"m.presence\") {\n return;\n }\n const firstFire = this.events.presence === null;\n this.events.presence = event;\n\n const eventsToFire: UserEvent[] = [];\n if (event.getContent().presence !== this.presence || firstFire) {\n eventsToFire.push(UserEvent.Presence);\n }\n if (event.getContent().avatar_url && event.getContent().avatar_url !== this.avatarUrl) {\n eventsToFire.push(UserEvent.AvatarUrl);\n }\n if (event.getContent().displayname && event.getContent().displayname !== this.displayName) {\n eventsToFire.push(UserEvent.DisplayName);\n }\n if (\n event.getContent().currently_active !== undefined &&\n event.getContent().currently_active !== this.currentlyActive\n ) {\n eventsToFire.push(UserEvent.CurrentlyActive);\n }\n\n this.presence = event.getContent().presence;\n eventsToFire.push(UserEvent.LastPresenceTs);\n\n if (event.getContent().status_msg) {\n this.presenceStatusMsg = event.getContent().status_msg;\n }\n if (event.getContent().displayname) {\n this.displayName = event.getContent().displayname;\n }\n if (event.getContent().avatar_url) {\n this.avatarUrl = event.getContent().avatar_url;\n }\n this.lastActiveAgo = event.getContent().last_active_ago;\n this.lastPresenceTs = Date.now();\n this.currentlyActive = event.getContent().currently_active;\n\n this.updateModifiedTime();\n\n for (const eventToFire of eventsToFire) {\n this.emit(eventToFire, event, this);\n }\n }\n\n /**\n * Manually set this user's display name. No event is emitted in response to this\n * as there is no underlying MatrixEvent to emit with.\n * @param name - The new display name.\n */\n public setDisplayName(name: string): void {\n const oldName = this.displayName;\n this.displayName = name;\n if (name !== oldName) {\n this.updateModifiedTime();\n }\n }\n\n /**\n * Manually set this user's non-disambiguated display name. No event is emitted\n * in response to this as there is no underlying MatrixEvent to emit with.\n * @param name - The new display name.\n */\n public setRawDisplayName(name?: string): void {\n this.rawDisplayName = name;\n }\n\n /**\n * Manually set this user's avatar URL. No event is emitted in response to this\n * as there is no underlying MatrixEvent to emit with.\n * @param url - The new avatar URL.\n */\n public setAvatarUrl(url?: string): void {\n const oldUrl = this.avatarUrl;\n this.avatarUrl = url;\n if (url !== oldUrl) {\n this.updateModifiedTime();\n }\n }\n\n /**\n * Update the last modified time to the current time.\n */\n private updateModifiedTime(): void {\n this.modified = Date.now();\n }\n\n /**\n * Get the timestamp when this User was last updated. This timestamp is\n * updated when this User receives a new Presence event which has updated a\n * property on this object. It is updated <i>before</i> firing events.\n * @returns The timestamp\n */\n public getLastModifiedTime(): number {\n return this.modified;\n }\n\n /**\n * Get the absolute timestamp when this User was last known active on the server.\n * It is *NOT* accurate if this.currentlyActive is true.\n * @returns The timestamp\n */\n public getLastActiveTs(): number {\n return this.lastPresenceTs - this.lastActiveAgo;\n }\n}\n"],"mappings":"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"} \ No newline at end of file