summaryrefslogtreecommitdiff
path: root/includes/external/matrix/node_modules/matrix-widget-api/src
diff options
context:
space:
mode:
Diffstat (limited to 'includes/external/matrix/node_modules/matrix-widget-api/src')
-rw-r--r--includes/external/matrix/node_modules/matrix-widget-api/src/ClientWidgetApi.ts798
-rw-r--r--includes/external/matrix/node_modules/matrix-widget-api/src/Symbols.ts19
-rw-r--r--includes/external/matrix/node_modules/matrix-widget-api/src/WidgetApi.ts717
-rw-r--r--includes/external/matrix/node_modules/matrix-widget-api/src/driver/WidgetDriver.ts247
-rw-r--r--includes/external/matrix/node_modules/matrix-widget-api/src/index.ts73
-rw-r--r--includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/ApiVersion.ts50
-rw-r--r--includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/Capabilities.ts71
-rw-r--r--includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/CapabilitiesAction.ts60
-rw-r--r--includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/ContentLoadedAction.ts28
-rw-r--r--includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/GetOpenIDAction.ts49
-rw-r--r--includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/ICustomWidgetData.ts27
-rw-r--r--includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/IJitsiWidgetData.ts38
-rw-r--r--includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/IRoomEvent.ts26
-rw-r--r--includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/IStickerpickerWidgetData.ts21
-rw-r--r--includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/IWidget.ts75
-rw-r--r--includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/IWidgetApiErrorResponse.ts35
-rw-r--r--includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/IWidgetApiRequest.ts37
-rw-r--r--includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/IWidgetApiResponse.ts29
-rw-r--r--includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/ModalButtonKind.ts23
-rw-r--r--includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/ModalWidgetActions.ts89
-rw-r--r--includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/NavigateAction.ts32
-rw-r--r--includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/OpenIDCredentialsAction.ts38
-rw-r--r--includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/ReadEventAction.ts42
-rw-r--r--includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/ReadRelationsAction.ts48
-rw-r--r--includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/ScreenshotAction.ts32
-rw-r--r--includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/SendEventAction.ts57
-rw-r--r--includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/SendToDeviceAction.ts56
-rw-r--r--includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/SetModalButtonEnabledAction.ts34
-rw-r--r--includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/StickerAction.ts48
-rw-r--r--includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/StickyAction.ts36
-rw-r--r--includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/SupportedVersionsAction.ts33
-rw-r--r--includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/TurnServerActions.ts55
-rw-r--r--includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/UserDirectorySearchAction.ts42
-rw-r--r--includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/VisibilityAction.ts32
-rw-r--r--includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/WidgetApiAction.ts72
-rw-r--r--includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/WidgetApiDirection.ts30
-rw-r--r--includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/WidgetConfigAction.ts29
-rw-r--r--includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/WidgetKind.ts21
-rw-r--r--includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/WidgetType.ts23
-rw-r--r--includes/external/matrix/node_modules/matrix-widget-api/src/models/Widget.ts109
-rw-r--r--includes/external/matrix/node_modules/matrix-widget-api/src/models/WidgetEventCapability.ts204
-rw-r--r--includes/external/matrix/node_modules/matrix-widget-api/src/models/WidgetParser.ts147
-rw-r--r--includes/external/matrix/node_modules/matrix-widget-api/src/models/validation/url.ts32
-rw-r--r--includes/external/matrix/node_modules/matrix-widget-api/src/models/validation/utils.ts21
-rw-r--r--includes/external/matrix/node_modules/matrix-widget-api/src/templating/url-template.ts62
-rw-r--r--includes/external/matrix/node_modules/matrix-widget-api/src/transport/ITransport.ts104
-rw-r--r--includes/external/matrix/node_modules/matrix-widget-api/src/transport/PostmessageTransport.ts203
-rw-r--r--includes/external/matrix/node_modules/matrix-widget-api/src/util/SimpleObservable.ts39
48 files changed, 4193 insertions, 0 deletions
diff --git a/includes/external/matrix/node_modules/matrix-widget-api/src/ClientWidgetApi.ts b/includes/external/matrix/node_modules/matrix-widget-api/src/ClientWidgetApi.ts
new file mode 100644
index 0000000..fecbefc
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-widget-api/src/ClientWidgetApi.ts
@@ -0,0 +1,798 @@
+/*
+ * Copyright 2020 - 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.
+ */
+
+import { EventEmitter } from "events";
+import { ITransport } from "./transport/ITransport";
+import { Widget } from "./models/Widget";
+import { PostmessageTransport } from "./transport/PostmessageTransport";
+import { WidgetApiDirection } from "./interfaces/WidgetApiDirection";
+import { IWidgetApiRequest, IWidgetApiRequestEmptyData } from "./interfaces/IWidgetApiRequest";
+import { IContentLoadedActionRequest } from "./interfaces/ContentLoadedAction";
+import { WidgetApiFromWidgetAction, WidgetApiToWidgetAction } from "./interfaces/WidgetApiAction";
+import { IWidgetApiErrorResponseData } from "./interfaces/IWidgetApiErrorResponse";
+import { Capability, MatrixCapabilities } from "./interfaces/Capabilities";
+import { IOpenIDUpdate, ISendEventDetails, WidgetDriver } from "./driver/WidgetDriver";
+import {
+ ICapabilitiesActionResponseData,
+ INotifyCapabilitiesActionRequestData,
+ IRenegotiateCapabilitiesActionRequest,
+} from "./interfaces/CapabilitiesAction";
+import {
+ ISupportedVersionsActionRequest,
+ ISupportedVersionsActionResponseData,
+} from "./interfaces/SupportedVersionsAction";
+import { CurrentApiVersions } from "./interfaces/ApiVersion";
+import { IScreenshotActionResponseData } from "./interfaces/ScreenshotAction";
+import { IVisibilityActionRequestData } from "./interfaces/VisibilityAction";
+import { IWidgetApiAcknowledgeResponseData, IWidgetApiResponseData } from "./interfaces/IWidgetApiResponse";
+import {
+ IModalWidgetButtonClickedRequestData,
+ IModalWidgetOpenRequestData,
+ IModalWidgetOpenRequestDataButton,
+ IModalWidgetReturnData,
+} from "./interfaces/ModalWidgetActions";
+import {
+ ISendEventFromWidgetActionRequest,
+ ISendEventFromWidgetResponseData,
+ ISendEventToWidgetRequestData,
+} from "./interfaces/SendEventAction";
+import {
+ ISendToDeviceFromWidgetActionRequest,
+ ISendToDeviceFromWidgetResponseData,
+ ISendToDeviceToWidgetRequestData,
+} from "./interfaces/SendToDeviceAction";
+import { EventDirection, WidgetEventCapability } from "./models/WidgetEventCapability";
+import { IRoomEvent } from "./interfaces/IRoomEvent";
+import {
+ IGetOpenIDActionRequest,
+ IGetOpenIDActionResponseData,
+ IOpenIDCredentials,
+ OpenIDRequestState,
+} from "./interfaces/GetOpenIDAction";
+import { SimpleObservable } from "./util/SimpleObservable";
+import { IOpenIDCredentialsActionRequestData } from "./interfaces/OpenIDCredentialsAction";
+import { INavigateActionRequest } from "./interfaces/NavigateAction";
+import { IReadEventFromWidgetActionRequest, IReadEventFromWidgetResponseData } from "./interfaces/ReadEventAction";
+import {
+ ITurnServer,
+ IWatchTurnServersRequest,
+ IUnwatchTurnServersRequest,
+ IUpdateTurnServersRequestData,
+} from "./interfaces/TurnServerActions";
+import { Symbols } from "./Symbols";
+import {
+ IReadRelationsFromWidgetActionRequest,
+ IReadRelationsFromWidgetResponseData,
+} from "./interfaces/ReadRelationsAction";
+import {
+ IUserDirectorySearchFromWidgetActionRequest,
+ IUserDirectorySearchFromWidgetResponseData,
+} from "./interfaces/UserDirectorySearchAction";
+
+/**
+ * API handler for the client side of widgets. This raises events
+ * for each action received as `action:${action}` (eg: "action:screenshot").
+ * Default handling can be prevented by using preventDefault() on the
+ * raised event. The default handling varies for each action: ones
+ * which the SDK can handle safely are acknowledged appropriately and
+ * ones which are unhandled (custom or require the client to do something)
+ * are rejected with an error.
+ *
+ * Events which are preventDefault()ed must reply using the transport.
+ * The events raised will have a default of an IWidgetApiRequest
+ * interface.
+ *
+ * When the ClientWidgetApi is ready to start sending requests, it will
+ * raise a "ready" CustomEvent. After the ready event fires, actions can
+ * be sent and the transport will be ready.
+ *
+ * When the widget has indicated it has loaded, this class raises a
+ * "preparing" CustomEvent. The preparing event does not indicate that
+ * the widget is ready to receive communications - that is signified by
+ * the ready event exclusively.
+ *
+ * This class only handles one widget at a time.
+ */
+export class ClientWidgetApi extends EventEmitter {
+ public readonly transport: ITransport;
+
+ // contentLoadedActionSent is used to check that only one ContentLoaded request is send.
+ private contentLoadedActionSent = false;
+ private allowedCapabilities = new Set<Capability>();
+ private allowedEvents: WidgetEventCapability[] = [];
+ private isStopped = false;
+ private turnServers: AsyncGenerator<ITurnServer> | null = null;
+
+ /**
+ * Creates a new client widget API. This will instantiate the transport
+ * and start everything. When the iframe is loaded under the widget's
+ * conditions, a "ready" event will be raised.
+ * @param {Widget} widget The widget to communicate with.
+ * @param {HTMLIFrameElement} iframe The iframe the widget is in.
+ * @param {WidgetDriver} driver The driver for this widget/client.
+ */
+ public constructor(
+ public readonly widget: Widget,
+ private iframe: HTMLIFrameElement,
+ private driver: WidgetDriver,
+ ) {
+ super();
+ if (!iframe?.contentWindow) {
+ throw new Error("No iframe supplied");
+ }
+ if (!widget) {
+ throw new Error("Invalid widget");
+ }
+ if (!driver) {
+ throw new Error("Invalid driver");
+ }
+ this.transport = new PostmessageTransport(
+ WidgetApiDirection.ToWidget,
+ widget.id,
+ iframe.contentWindow,
+ window,
+ );
+ this.transport.targetOrigin = widget.origin;
+ this.transport.on("message", this.handleMessage.bind(this));
+
+ iframe.addEventListener("load", this.onIframeLoad.bind(this));
+
+ this.transport.start();
+ }
+
+ public hasCapability(capability: Capability): boolean {
+ return this.allowedCapabilities.has(capability);
+ }
+
+ public canUseRoomTimeline(roomId: string | Symbols.AnyRoom): boolean {
+ return this.hasCapability(`org.matrix.msc2762.timeline:${Symbols.AnyRoom}`)
+ || this.hasCapability(`org.matrix.msc2762.timeline:${roomId}`);
+ }
+
+ public canSendRoomEvent(eventType: string, msgtype: string | null = null): boolean {
+ return this.allowedEvents.some(e => e.matchesAsRoomEvent(EventDirection.Send, eventType, msgtype));
+ }
+
+ public canSendStateEvent(eventType: string, stateKey: string): boolean {
+ return this.allowedEvents.some(e => e.matchesAsStateEvent(EventDirection.Send, eventType, stateKey));
+ }
+
+ public canSendToDeviceEvent(eventType: string): boolean {
+ return this.allowedEvents.some(e => e.matchesAsToDeviceEvent(EventDirection.Send, eventType));
+ }
+
+ public canReceiveRoomEvent(eventType: string, msgtype: string | null = null): boolean {
+ return this.allowedEvents.some(e => e.matchesAsRoomEvent(EventDirection.Receive, eventType, msgtype));
+ }
+
+ public canReceiveStateEvent(eventType: string, stateKey: string | null): boolean {
+ return this.allowedEvents.some(e => e.matchesAsStateEvent(EventDirection.Receive, eventType, stateKey));
+ }
+
+ public canReceiveToDeviceEvent(eventType: string): boolean {
+ return this.allowedEvents.some(e => e.matchesAsToDeviceEvent(EventDirection.Receive, eventType));
+ }
+
+ public stop() {
+ this.isStopped = true;
+ this.transport.stop();
+ }
+
+ private beginCapabilities() {
+ // widget has loaded - tell all the listeners that
+ this.emit("preparing");
+
+ let requestedCaps: Capability[];
+ this.transport.send<IWidgetApiRequestEmptyData, ICapabilitiesActionResponseData>(
+ WidgetApiToWidgetAction.Capabilities, {},
+ ).then(caps => {
+ requestedCaps = caps.capabilities;
+ return this.driver.validateCapabilities(new Set(caps.capabilities));
+ }).then(allowedCaps => {
+ console.log(`Widget ${this.widget.id} is allowed capabilities:`, Array.from(allowedCaps));
+ this.allowedCapabilities = allowedCaps;
+ this.allowedEvents = WidgetEventCapability.findEventCapabilities(allowedCaps);
+ this.notifyCapabilities(requestedCaps);
+ this.emit("ready");
+ });
+ }
+
+ private notifyCapabilities(requested: Capability[]) {
+ this.transport.send(WidgetApiToWidgetAction.NotifyCapabilities, <INotifyCapabilitiesActionRequestData>{
+ requested: requested,
+ approved: Array.from(this.allowedCapabilities),
+ }).catch(e => {
+ console.warn("non-fatal error notifying widget of approved capabilities:", e);
+ }).then(() => {
+ this.emit("capabilitiesNotified")
+ });
+ }
+
+ private onIframeLoad(ev: Event) {
+ if (this.widget.waitForIframeLoad) {
+ // If the widget is set to waitForIframeLoad the capabilities immediatly get setup after load.
+ // The client does not wait for the ContentLoaded action.
+ this.beginCapabilities();
+ } else {
+ // Reaching this means, that the Iframe got reloaded/loaded and
+ // the clientApi is awaiting the FIRST ContentLoaded action.
+ this.contentLoadedActionSent = false;
+ }
+ }
+
+ private handleContentLoadedAction(action: IContentLoadedActionRequest) {
+ if (this.contentLoadedActionSent) {
+ throw new Error("Improper sequence: ContentLoaded Action can only be send once after the widget loaded "
+ +"and should only be used if waitForIframeLoad is false (default=true)");
+ }
+ if (this.widget.waitForIframeLoad) {
+ this.transport.reply(action, <IWidgetApiErrorResponseData>{
+ error: {
+ message: "Improper sequence: not expecting ContentLoaded event if "
+ +"waitForIframLoad is true (default=true)",
+ },
+ });
+ } else {
+ this.transport.reply(action, <IWidgetApiRequestEmptyData>{});
+ this.beginCapabilities();
+ }
+ this.contentLoadedActionSent = true;
+ }
+
+ private replyVersions(request: ISupportedVersionsActionRequest) {
+ this.transport.reply<ISupportedVersionsActionResponseData>(request, {
+ supported_versions: CurrentApiVersions,
+ });
+ }
+
+ private handleCapabilitiesRenegotiate(request: IRenegotiateCapabilitiesActionRequest) {
+ // acknowledge first
+ this.transport.reply<IWidgetApiAcknowledgeResponseData>(request, {});
+
+ const requested = request.data?.capabilities || [];
+ const newlyRequested = new Set(requested.filter(r => !this.hasCapability(r)));
+ if (newlyRequested.size === 0) {
+ // Nothing to do - notify capabilities
+ return this.notifyCapabilities([]);
+ }
+
+ this.driver.validateCapabilities(newlyRequested).then(allowed => {
+ allowed.forEach(c => this.allowedCapabilities.add(c));
+
+ const allowedEvents = WidgetEventCapability.findEventCapabilities(allowed);
+ allowedEvents.forEach(c => this.allowedEvents.push(c));
+
+ return this.notifyCapabilities(Array.from(newlyRequested));
+ });
+ }
+
+ private handleNavigate(request: INavigateActionRequest) {
+ if (!this.hasCapability(MatrixCapabilities.MSC2931Navigate)) {
+ return this.transport.reply<IWidgetApiErrorResponseData>(request, {
+ error: {message: "Missing capability"},
+ });
+ }
+
+ if (!request.data?.uri || !request.data?.uri.toString().startsWith("https://matrix.to/#")) {
+ return this.transport.reply<IWidgetApiErrorResponseData>(request, {
+ error: {message: "Invalid matrix.to URI"},
+ });
+ }
+
+ const onErr = (e: any) => {
+ console.error("[ClientWidgetApi] Failed to handle navigation: ", e);
+ return this.transport.reply<IWidgetApiErrorResponseData>(request, {
+ error: {message: "Error handling navigation"},
+ });
+ };
+
+ try {
+ this.driver.navigate(request.data.uri.toString()).catch(e => onErr(e)).then(() => {
+ return this.transport.reply<IWidgetApiAcknowledgeResponseData>(request, {});
+ });
+ } catch (e) {
+ return onErr(e);
+ }
+ }
+
+ private handleOIDC(request: IGetOpenIDActionRequest) {
+ let phase = 1; // 1 = initial request, 2 = after user manual confirmation
+
+ const replyState = (state: OpenIDRequestState, credential?: IOpenIDCredentials) => {
+ credential = credential || {};
+ if (phase > 1) {
+ return this.transport.send<IOpenIDCredentialsActionRequestData>(
+ WidgetApiToWidgetAction.OpenIDCredentials,
+ {
+ state: state,
+ original_request_id: request.requestId,
+ ...credential,
+ },
+ );
+ } else {
+ return this.transport.reply<IGetOpenIDActionResponseData>(request, {
+ state: state,
+ ...credential,
+ });
+ }
+ };
+
+ const replyError = (msg: string) => {
+ console.error("[ClientWidgetApi] Failed to handle OIDC: ", msg);
+ if (phase > 1) {
+ // We don't have a way to indicate that a random error happened in this flow, so
+ // just block the attempt.
+ return replyState(OpenIDRequestState.Blocked);
+ } else {
+ return this.transport.reply<IWidgetApiErrorResponseData>(request, {
+ error: {message: msg},
+ });
+ }
+ };
+
+ const observer = new SimpleObservable<IOpenIDUpdate>(update => {
+ if (update.state === OpenIDRequestState.PendingUserConfirmation && phase > 1) {
+ observer.close();
+ return replyError("client provided out-of-phase response to OIDC flow");
+ }
+
+ if (update.state === OpenIDRequestState.PendingUserConfirmation) {
+ replyState(update.state);
+ phase++;
+ return;
+ }
+
+ if (update.state === OpenIDRequestState.Allowed && !update.token) {
+ return replyError("client provided invalid OIDC token for an allowed request");
+ }
+ if (update.state === OpenIDRequestState.Blocked) {
+ update.token = undefined; // just in case the client did something weird
+ }
+
+ observer.close();
+ return replyState(update.state, update.token);
+ });
+
+ this.driver.askOpenID(observer);
+ }
+
+ private handleReadEvents(request: IReadEventFromWidgetActionRequest) {
+ if (!request.data.type) {
+ return this.transport.reply<IWidgetApiErrorResponseData>(request, {
+ error: {message: "Invalid request - missing event type"},
+ });
+ }
+ if (request.data.limit !== undefined && (!request.data.limit || request.data.limit < 0)) {
+ return this.transport.reply<IWidgetApiErrorResponseData>(request, {
+ error: {message: "Invalid request - limit out of range"},
+ });
+ }
+
+ let askRoomIds: string[] | null = null; // null denotes current room only
+ if (request.data.room_ids) {
+ askRoomIds = request.data.room_ids as string[];
+ if (!Array.isArray(askRoomIds)) {
+ askRoomIds = [askRoomIds as any as string];
+ }
+ for (const roomId of askRoomIds) {
+ if (!this.canUseRoomTimeline(roomId)) {
+ return this.transport.reply<IWidgetApiErrorResponseData>(request, {
+ error: {message: `Unable to access room timeline: ${roomId}`},
+ });
+ }
+ }
+ }
+
+ const limit = request.data.limit || 0;
+
+ let events: Promise<IRoomEvent[]> = Promise.resolve([]);
+ if (request.data.state_key !== undefined) {
+ const stateKey = request.data.state_key === true ? undefined : request.data.state_key.toString();
+ if (!this.canReceiveStateEvent(request.data.type, stateKey ?? null)) {
+ return this.transport.reply<IWidgetApiErrorResponseData>(request, {
+ error: {message: "Cannot read state events of this type"},
+ });
+ }
+ events = this.driver.readStateEvents(request.data.type, stateKey, limit, askRoomIds);
+ } else {
+ if (!this.canReceiveRoomEvent(request.data.type, request.data.msgtype)) {
+ return this.transport.reply<IWidgetApiErrorResponseData>(request, {
+ error: {message: "Cannot read room events of this type"},
+ });
+ }
+ events = this.driver.readRoomEvents(request.data.type, request.data.msgtype, limit, askRoomIds);
+ }
+
+ return events.then(evs => this.transport.reply<IReadEventFromWidgetResponseData>(request, {events: evs}));
+ }
+
+ private handleSendEvent(request: ISendEventFromWidgetActionRequest) {
+ if (!request.data.type) {
+ return this.transport.reply<IWidgetApiErrorResponseData>(request, {
+ error: {message: "Invalid request - missing event type"},
+ });
+ }
+
+ if (!!request.data.room_id && !this.canUseRoomTimeline(request.data.room_id)) {
+ return this.transport.reply<IWidgetApiErrorResponseData>(request, {
+ error: {message: `Unable to access room timeline: ${request.data.room_id}`},
+ });
+ }
+
+ const isState = request.data.state_key !== null && request.data.state_key !== undefined;
+ let sendEventPromise: Promise<ISendEventDetails>;
+ if (isState) {
+ if (!this.canSendStateEvent(request.data.type, request.data.state_key!)) {
+ return this.transport.reply<IWidgetApiErrorResponseData>(request, {
+ error: {message: "Cannot send state events of this type"},
+ });
+ }
+
+ sendEventPromise = this.driver.sendEvent(
+ request.data.type,
+ request.data.content || {},
+ request.data.state_key,
+ request.data.room_id,
+ );
+ } else {
+ const content = request.data.content as { msgtype?: string } || {};
+ const msgtype = content['msgtype'];
+ if (!this.canSendRoomEvent(request.data.type, msgtype)) {
+ return this.transport.reply<IWidgetApiErrorResponseData>(request, {
+ error: {message: "Cannot send room events of this type"},
+ });
+ }
+
+ sendEventPromise = this.driver.sendEvent(
+ request.data.type,
+ content,
+ null, // not sending a state event
+ request.data.room_id,
+ );
+ }
+
+ sendEventPromise.then(sentEvent => {
+ return this.transport.reply<ISendEventFromWidgetResponseData>(request, {
+ room_id: sentEvent.roomId,
+ event_id: sentEvent.eventId,
+ });
+ }).catch(e => {
+ console.error("error sending event: ", e);
+ return this.transport.reply<IWidgetApiErrorResponseData>(request, {
+ error: {message: "Error sending event"},
+ });
+ });
+ }
+
+ private async handleSendToDevice(request: ISendToDeviceFromWidgetActionRequest): Promise<void> {
+ if (!request.data.type) {
+ await this.transport.reply<IWidgetApiErrorResponseData>(request, {
+ error: {message: "Invalid request - missing event type"},
+ });
+ } else if (!request.data.messages) {
+ await this.transport.reply<IWidgetApiErrorResponseData>(request, {
+ error: {message: "Invalid request - missing event contents"},
+ });
+ } else if (typeof request.data.encrypted !== "boolean") {
+ await this.transport.reply<IWidgetApiErrorResponseData>(request, {
+ error: {message: "Invalid request - missing encryption flag"},
+ });
+ } else if (!this.canSendToDeviceEvent(request.data.type)) {
+ await this.transport.reply<IWidgetApiErrorResponseData>(request, {
+ error: {message: "Cannot send to-device events of this type"},
+ });
+ } else {
+ try {
+ await this.driver.sendToDevice(request.data.type, request.data.encrypted, request.data.messages);
+ await this.transport.reply<ISendToDeviceFromWidgetResponseData>(request, {});
+ } catch (e) {
+ console.error("error sending to-device event", e);
+ await this.transport.reply<IWidgetApiErrorResponseData>(request, {
+ error: {message: "Error sending event"},
+ });
+ }
+ }
+ }
+
+ private async pollTurnServers(turnServers: AsyncGenerator<ITurnServer>, initialServer: ITurnServer) {
+ try {
+ await this.transport.send<IUpdateTurnServersRequestData>(
+ WidgetApiToWidgetAction.UpdateTurnServers,
+ initialServer as IUpdateTurnServersRequestData, // it's compatible, but missing the index signature
+ );
+
+ // Pick the generator up where we left off
+ for await (const server of turnServers) {
+ await this.transport.send<IUpdateTurnServersRequestData>(
+ WidgetApiToWidgetAction.UpdateTurnServers,
+ server as IUpdateTurnServersRequestData, // it's compatible, but missing the index signature
+ );
+ }
+ } catch (e) {
+ console.error("error polling for TURN servers", e);
+ }
+ }
+
+ private async handleWatchTurnServers(request: IWatchTurnServersRequest): Promise<void> {
+ if (!this.hasCapability(MatrixCapabilities.MSC3846TurnServers)) {
+ await this.transport.reply<IWidgetApiErrorResponseData>(request, {
+ error: {message: "Missing capability"},
+ });
+ } else if (this.turnServers) {
+ // We're already polling, so this is a no-op
+ await this.transport.reply<IWidgetApiAcknowledgeResponseData>(request, {});
+ } else {
+ try {
+ const turnServers = this.driver.getTurnServers();
+
+ // Peek at the first result, so we can at least verify that the
+ // client isn't banned from getting TURN servers entirely
+ const { done, value } = await turnServers.next();
+ if (done) throw new Error("Client refuses to provide any TURN servers");
+ await this.transport.reply<IWidgetApiAcknowledgeResponseData>(request, {});
+
+ // Start the poll loop, sending the widget the initial result
+ this.pollTurnServers(turnServers, value);
+ this.turnServers = turnServers;
+ } catch (e) {
+ console.error("error getting first TURN server results", e);
+ await this.transport.reply<IWidgetApiErrorResponseData>(request, {
+ error: {message: "TURN servers not available"},
+ });
+ }
+ }
+ }
+
+ private async handleUnwatchTurnServers(request: IUnwatchTurnServersRequest): Promise<void> {
+ if (!this.hasCapability(MatrixCapabilities.MSC3846TurnServers)) {
+ await this.transport.reply<IWidgetApiErrorResponseData>(request, {
+ error: {message: "Missing capability"},
+ });
+ } else if (!this.turnServers) {
+ // We weren't polling anyways, so this is a no-op
+ await this.transport.reply<IWidgetApiAcknowledgeResponseData>(request, {});
+ } else {
+ // Stop the generator, allowing it to clean up
+ await this.turnServers.return(undefined);
+ this.turnServers = null;
+ await this.transport.reply<IWidgetApiAcknowledgeResponseData>(request, {});
+ }
+ }
+
+ private async handleReadRelations(request: IReadRelationsFromWidgetActionRequest) {
+ if (!request.data.event_id) {
+ return this.transport.reply<IWidgetApiErrorResponseData>(request, {
+ error: { message: "Invalid request - missing event ID" },
+ });
+ }
+
+ if (request.data.limit !== undefined && request.data.limit < 0) {
+ return this.transport.reply<IWidgetApiErrorResponseData>(request, {
+ error: { message: "Invalid request - limit out of range" },
+ });
+ }
+
+ if (request.data.room_id !== undefined && !this.canUseRoomTimeline(request.data.room_id)) {
+ return this.transport.reply<IWidgetApiErrorResponseData>(request, {
+ error: { message: `Unable to access room timeline: ${request.data.room_id}` },
+ });
+ }
+
+ try {
+ const result = await this.driver.readEventRelations(
+ request.data.event_id, request.data.room_id, request.data.rel_type,
+ request.data.event_type, request.data.from, request.data.to,
+ request.data.limit, request.data.direction,
+ );
+
+ // only return events that the user has the permission to receive
+ const chunk = result.chunk.filter(e => {
+ if (e.state_key !== undefined) {
+ return this.canReceiveStateEvent(e.type, e.state_key);
+ } else {
+ return this.canReceiveRoomEvent(e.type, (e.content as { msgtype?: string })['msgtype']);
+ }
+ });
+
+ return this.transport.reply<IReadRelationsFromWidgetResponseData>(
+ request,
+ {
+ chunk,
+ prev_batch: result.prevBatch,
+ next_batch: result.nextBatch,
+ },
+ );
+ } catch (e) {
+ console.error("error getting the relations", e);
+ await this.transport.reply<IWidgetApiErrorResponseData>(request, {
+ error: { message: "Unexpected error while reading relations" },
+ });
+ }
+ }
+
+ private async handleUserDirectorySearch(request: IUserDirectorySearchFromWidgetActionRequest) {
+ if (!this.hasCapability(MatrixCapabilities.MSC3973UserDirectorySearch)) {
+ return this.transport.reply<IWidgetApiErrorResponseData>(request, {
+ error: { message: "Missing capability" },
+ });
+ }
+
+ if (typeof request.data.search_term !== 'string') {
+ return this.transport.reply<IWidgetApiErrorResponseData>(request, {
+ error: { message: "Invalid request - missing search term" },
+ });
+ }
+
+ if (request.data.limit !== undefined && request.data.limit < 0) {
+ return this.transport.reply<IWidgetApiErrorResponseData>(request, {
+ error: { message: "Invalid request - limit out of range" },
+ });
+ }
+
+ try {
+ const result = await this.driver.searchUserDirectory(
+ request.data.search_term, request.data.limit,
+ );
+
+ return this.transport.reply<IUserDirectorySearchFromWidgetResponseData>(
+ request,
+ {
+ limited: result.limited,
+ results: result.results.map(r => ({
+ user_id: r.userId,
+ display_name: r.displayName,
+ avatar_url: r.avatarUrl,
+ })),
+ },
+ );
+ } catch (e) {
+ console.error("error searching in the user directory", e);
+ await this.transport.reply<IWidgetApiErrorResponseData>(request, {
+ error: { message: "Unexpected error while searching in the user directory" },
+ });
+ }
+ }
+
+ private handleMessage(ev: CustomEvent<IWidgetApiRequest>) {
+ if (this.isStopped) return;
+ const actionEv = new CustomEvent(`action:${ev.detail.action}`, {
+ detail: ev.detail,
+ cancelable: true,
+ });
+ this.emit(`action:${ev.detail.action}`, actionEv);
+ if (!actionEv.defaultPrevented) {
+ switch (ev.detail.action) {
+ case WidgetApiFromWidgetAction.ContentLoaded:
+ return this.handleContentLoadedAction(<IContentLoadedActionRequest>ev.detail);
+ case WidgetApiFromWidgetAction.SupportedApiVersions:
+ return this.replyVersions(<ISupportedVersionsActionRequest>ev.detail);
+ case WidgetApiFromWidgetAction.SendEvent:
+ return this.handleSendEvent(<ISendEventFromWidgetActionRequest>ev.detail);
+ case WidgetApiFromWidgetAction.SendToDevice:
+ return this.handleSendToDevice(<ISendToDeviceFromWidgetActionRequest>ev.detail);
+ case WidgetApiFromWidgetAction.GetOpenIDCredentials:
+ return this.handleOIDC(<IGetOpenIDActionRequest>ev.detail);
+ case WidgetApiFromWidgetAction.MSC2931Navigate:
+ return this.handleNavigate(<INavigateActionRequest>ev.detail);
+ case WidgetApiFromWidgetAction.MSC2974RenegotiateCapabilities:
+ return this.handleCapabilitiesRenegotiate(<IRenegotiateCapabilitiesActionRequest>ev.detail);
+ case WidgetApiFromWidgetAction.MSC2876ReadEvents:
+ return this.handleReadEvents(<IReadEventFromWidgetActionRequest>ev.detail);
+ case WidgetApiFromWidgetAction.WatchTurnServers:
+ return this.handleWatchTurnServers(<IWatchTurnServersRequest>ev.detail);
+ case WidgetApiFromWidgetAction.UnwatchTurnServers:
+ return this.handleUnwatchTurnServers(<IUnwatchTurnServersRequest>ev.detail);
+ case WidgetApiFromWidgetAction.MSC3869ReadRelations:
+ return this.handleReadRelations(<IReadRelationsFromWidgetActionRequest>ev.detail);
+ case WidgetApiFromWidgetAction.MSC3973UserDirectorySearch:
+ return this.handleUserDirectorySearch(<IUserDirectorySearchFromWidgetActionRequest>ev.detail)
+ default:
+ return this.transport.reply(ev.detail, <IWidgetApiErrorResponseData>{
+ error: {
+ message: "Unknown or unsupported action: " + ev.detail.action,
+ },
+ });
+ }
+ }
+ }
+
+ /**
+ * Takes a screenshot of the widget.
+ * @returns Resolves to the widget's screenshot.
+ * @throws Throws if there is a problem.
+ */
+ public takeScreenshot(): Promise<IScreenshotActionResponseData> {
+ return this.transport.send(WidgetApiToWidgetAction.TakeScreenshot, <IWidgetApiRequestEmptyData>{});
+ }
+
+ /**
+ * Alerts the widget to whether or not it is currently visible.
+ * @param {boolean} isVisible Whether the widget is visible or not.
+ * @returns {Promise<IWidgetApiResponseData>} Resolves when the widget acknowledges the update.
+ */
+ public updateVisibility(isVisible: boolean): Promise<IWidgetApiResponseData> {
+ return this.transport.send(WidgetApiToWidgetAction.UpdateVisibility, <IVisibilityActionRequestData>{
+ visible: isVisible,
+ });
+ }
+
+ public sendWidgetConfig(data: IModalWidgetOpenRequestData): Promise<void> {
+ return this.transport.send<IModalWidgetOpenRequestData>(WidgetApiToWidgetAction.WidgetConfig, data).then();
+ }
+
+ public notifyModalWidgetButtonClicked(id: IModalWidgetOpenRequestDataButton["id"]): Promise<void> {
+ return this.transport.send<IModalWidgetButtonClickedRequestData>(
+ WidgetApiToWidgetAction.ButtonClicked, {id},
+ ).then();
+ }
+
+ public notifyModalWidgetClose(data: IModalWidgetReturnData): Promise<void> {
+ return this.transport.send<IModalWidgetReturnData>(
+ WidgetApiToWidgetAction.CloseModalWidget, data,
+ ).then();
+ }
+
+ /**
+ * Feeds an event to the widget. If the widget is not able to accept the event due to
+ * permissions, this will no-op and return calmly. If the widget failed to handle the
+ * event, this will raise an error.
+ * @param {IRoomEvent} rawEvent The event to (try to) send to the widget.
+ * @param {string} currentViewedRoomId The room ID the user is currently interacting with.
+ * Not the room ID of the event.
+ * @returns {Promise<void>} Resolves when complete, rejects if there was an error sending.
+ */
+ public async feedEvent(rawEvent: IRoomEvent, currentViewedRoomId: string): Promise<void> {
+ if (rawEvent.room_id !== currentViewedRoomId && !this.canUseRoomTimeline(rawEvent.room_id)) {
+ return; // no-op
+ }
+
+ if (rawEvent.state_key !== undefined && rawEvent.state_key !== null) {
+ // state event
+ if (!this.canReceiveStateEvent(rawEvent.type, rawEvent.state_key)) {
+ return; // no-op
+ }
+ } else {
+ // message event
+ if (!this.canReceiveRoomEvent(rawEvent.type, (rawEvent.content as { msgtype?: string })?.["msgtype"])) {
+ return; // no-op
+ }
+ }
+
+ // Feed the event into the widget
+ await this.transport.send<ISendEventToWidgetRequestData>(
+ WidgetApiToWidgetAction.SendEvent,
+ rawEvent as ISendEventToWidgetRequestData, // it's compatible, but missing the index signature
+ );
+ }
+
+ /**
+ * Feeds a to-device event to the widget. If the widget is not able to accept the
+ * event due to permissions, this will no-op and return calmly. If the widget failed
+ * to handle the event, this will raise an error.
+ * @param {IRoomEvent} rawEvent The event to (try to) send to the widget.
+ * @param {boolean} encrypted Whether the event contents were encrypted.
+ * @returns {Promise<void>} Resolves when complete, rejects if there was an error sending.
+ */
+ public async feedToDevice(rawEvent: IRoomEvent, encrypted: boolean): Promise<void> {
+ if (this.canReceiveToDeviceEvent(rawEvent.type)) {
+ await this.transport.send<ISendToDeviceToWidgetRequestData>(
+ WidgetApiToWidgetAction.SendToDevice,
+ // it's compatible, but missing the index signature
+ { ...rawEvent, encrypted } as ISendToDeviceToWidgetRequestData,
+ );
+ }
+ }
+}
diff --git a/includes/external/matrix/node_modules/matrix-widget-api/src/Symbols.ts b/includes/external/matrix/node_modules/matrix-widget-api/src/Symbols.ts
new file mode 100644
index 0000000..85ca12e
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-widget-api/src/Symbols.ts
@@ -0,0 +1,19 @@
+/*
+ * 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.
+ */
+
+export enum Symbols {
+ AnyRoom = "*",
+}
diff --git a/includes/external/matrix/node_modules/matrix-widget-api/src/WidgetApi.ts b/includes/external/matrix/node_modules/matrix-widget-api/src/WidgetApi.ts
new file mode 100644
index 0000000..a74187a
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-widget-api/src/WidgetApi.ts
@@ -0,0 +1,717 @@
+/*
+ * Copyright 2020 - 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.
+ */
+
+import { EventEmitter } from "events";
+import { Capability } from "./interfaces/Capabilities";
+import { IWidgetApiRequest, IWidgetApiRequestEmptyData } from "./interfaces/IWidgetApiRequest";
+import { IWidgetApiAcknowledgeResponseData } from "./interfaces/IWidgetApiResponse";
+import { WidgetApiDirection } from "./interfaces/WidgetApiDirection";
+import {
+ ISupportedVersionsActionRequest,
+ ISupportedVersionsActionResponseData,
+} from "./interfaces/SupportedVersionsAction";
+import { ApiVersion, CurrentApiVersions, UnstableApiVersion } from "./interfaces/ApiVersion";
+import {
+ ICapabilitiesActionRequest,
+ ICapabilitiesActionResponseData,
+ INotifyCapabilitiesActionRequest,
+ IRenegotiateCapabilitiesRequestData,
+} from "./interfaces/CapabilitiesAction";
+import { ITransport } from "./transport/ITransport";
+import { PostmessageTransport } from "./transport/PostmessageTransport";
+import { WidgetApiFromWidgetAction, WidgetApiToWidgetAction } from "./interfaces/WidgetApiAction";
+import { IWidgetApiErrorResponseData } from "./interfaces/IWidgetApiErrorResponse";
+import { IStickerActionRequestData } from "./interfaces/StickerAction";
+import { IStickyActionRequestData, IStickyActionResponseData } from "./interfaces/StickyAction";
+import {
+ IGetOpenIDActionRequestData,
+ IGetOpenIDActionResponse,
+ IOpenIDCredentials,
+ OpenIDRequestState,
+} from "./interfaces/GetOpenIDAction";
+import { IOpenIDCredentialsActionRequest } from "./interfaces/OpenIDCredentialsAction";
+import { MatrixWidgetType, WidgetType } from "./interfaces/WidgetType";
+import {
+ BuiltInModalButtonID,
+ IModalWidgetCreateData,
+ IModalWidgetOpenRequestData,
+ IModalWidgetOpenRequestDataButton,
+ IModalWidgetReturnData,
+ ModalButtonID,
+} from "./interfaces/ModalWidgetActions";
+import { ISetModalButtonEnabledActionRequestData } from "./interfaces/SetModalButtonEnabledAction";
+import { ISendEventFromWidgetRequestData, ISendEventFromWidgetResponseData } from "./interfaces/SendEventAction";
+import {
+ ISendToDeviceFromWidgetRequestData,
+ ISendToDeviceFromWidgetResponseData,
+} from "./interfaces/SendToDeviceAction";
+import { EventDirection, WidgetEventCapability } from "./models/WidgetEventCapability";
+import { INavigateActionRequestData } from "./interfaces/NavigateAction";
+import { IReadEventFromWidgetRequestData, IReadEventFromWidgetResponseData } from "./interfaces/ReadEventAction";
+import { IRoomEvent } from "./interfaces/IRoomEvent";
+import { ITurnServer, IUpdateTurnServersRequest } from "./interfaces/TurnServerActions";
+import { Symbols } from "./Symbols";
+import {
+ IReadRelationsFromWidgetRequestData,
+ IReadRelationsFromWidgetResponseData,
+} from "./interfaces/ReadRelationsAction";
+import {
+ IUserDirectorySearchFromWidgetRequestData,
+ IUserDirectorySearchFromWidgetResponseData,
+} from "./interfaces/UserDirectorySearchAction";
+
+/**
+ * API handler for widgets. This raises events for each action
+ * received as `action:${action}` (eg: "action:screenshot").
+ * Default handling can be prevented by using preventDefault()
+ * on the raised event. The default handling varies for each
+ * action: ones which the SDK can handle safely are acknowledged
+ * appropriately and ones which are unhandled (custom or require
+ * the widget to do something) are rejected with an error.
+ *
+ * Events which are preventDefault()ed must reply using the
+ * transport. The events raised will have a detail of an
+ * IWidgetApiRequest interface.
+ *
+ * When the WidgetApi is ready to start sending requests, it will
+ * raise a "ready" CustomEvent. After the ready event fires, actions
+ * can be sent and the transport will be ready.
+ */
+export class WidgetApi extends EventEmitter {
+ public readonly transport: ITransport;
+
+ private capabilitiesFinished = false;
+ private supportsMSC2974Renegotiate = false;
+ private requestedCapabilities: Capability[] = [];
+ private approvedCapabilities?: Capability[];
+ private cachedClientVersions?: ApiVersion[];
+ private turnServerWatchers = 0;
+
+ /**
+ * Creates a new API handler for the given widget.
+ * @param {string} widgetId The widget ID to listen for. If not supplied then
+ * the API will use the widget ID from the first valid request it receives.
+ * @param {string} clientOrigin The origin of the client, or null if not known.
+ */
+ public constructor(widgetId: string | null = null, private clientOrigin: string | null = null) {
+ super();
+ if (!window.parent) {
+ throw new Error("No parent window. This widget doesn't appear to be embedded properly.");
+ }
+ this.transport = new PostmessageTransport(
+ WidgetApiDirection.FromWidget,
+ widgetId,
+ window.parent,
+ window,
+ );
+ this.transport.targetOrigin = clientOrigin;
+ this.transport.on("message", this.handleMessage.bind(this));
+ }
+
+ /**
+ * Determines if the widget was granted a particular capability. Note that on
+ * clients where the capabilities are not fed back to the widget this function
+ * will rely on requested capabilities instead.
+ * @param {Capability} capability The capability to check for approval of.
+ * @returns {boolean} True if the widget has approval for the given capability.
+ */
+ public hasCapability(capability: Capability): boolean {
+ if (Array.isArray(this.approvedCapabilities)) {
+ return this.approvedCapabilities.includes(capability);
+ }
+ return this.requestedCapabilities.includes(capability);
+ }
+
+ /**
+ * Request a capability from the client. It is not guaranteed to be allowed,
+ * but will be asked for.
+ * @param {Capability} capability The capability to request.
+ * @throws Throws if the capabilities negotiation has already started and the
+ * widget is unable to request additional capabilities.
+ */
+ public requestCapability(capability: Capability) {
+ if (this.capabilitiesFinished && !this.supportsMSC2974Renegotiate) {
+ throw new Error("Capabilities have already been negotiated");
+ }
+
+ this.requestedCapabilities.push(capability);
+ }
+
+ /**
+ * Request capabilities from the client. They are not guaranteed to be allowed,
+ * but will be asked for if the negotiation has not already happened.
+ * @param {Capability[]} capabilities The capabilities to request.
+ * @throws Throws if the capabilities negotiation has already started.
+ */
+ public requestCapabilities(capabilities: Capability[]) {
+ capabilities.forEach(cap => this.requestCapability(cap));
+ }
+
+ /**
+ * Requests the capability to interact with rooms other than the user's currently
+ * viewed room. Applies to event receiving and sending.
+ * @param {string | Symbols.AnyRoom} roomId The room ID, or `Symbols.AnyRoom` to
+ * denote all known rooms.
+ */
+ public requestCapabilityForRoomTimeline(roomId: string | Symbols.AnyRoom) {
+ this.requestCapability(`org.matrix.msc2762.timeline:${roomId}`);
+ }
+
+ /**
+ * Requests the capability to send a given state event with optional explicit
+ * state key. It is not guaranteed to be allowed, but will be asked for if the
+ * negotiation has not already happened.
+ * @param {string} eventType The state event type to ask for.
+ * @param {string} stateKey If specified, the specific state key to request.
+ * Otherwise all state keys will be requested.
+ */
+ public requestCapabilityToSendState(eventType: string, stateKey?: string) {
+ this.requestCapability(WidgetEventCapability.forStateEvent(EventDirection.Send, eventType, stateKey).raw);
+ }
+
+ /**
+ * Requests the capability to receive a given state event with optional explicit
+ * state key. It is not guaranteed to be allowed, but will be asked for if the
+ * negotiation has not already happened.
+ * @param {string} eventType The state event type to ask for.
+ * @param {string} stateKey If specified, the specific state key to request.
+ * Otherwise all state keys will be requested.
+ */
+ public requestCapabilityToReceiveState(eventType: string, stateKey?: string) {
+ this.requestCapability(WidgetEventCapability.forStateEvent(EventDirection.Receive, eventType, stateKey).raw);
+ }
+
+ /**
+ * Requests the capability to send a given to-device event. It is not
+ * guaranteed to be allowed, but will be asked for if the negotiation has
+ * not already happened.
+ * @param {string} eventType The room event type to ask for.
+ */
+ public requestCapabilityToSendToDevice(eventType: string) {
+ this.requestCapability(WidgetEventCapability.forToDeviceEvent(EventDirection.Send, eventType).raw);
+ }
+
+ /**
+ * Requests the capability to receive a given to-device event. It is not
+ * guaranteed to be allowed, but will be asked for if the negotiation has
+ * not already happened.
+ * @param {string} eventType The room event type to ask for.
+ */
+ public requestCapabilityToReceiveToDevice(eventType: string) {
+ this.requestCapability(WidgetEventCapability.forToDeviceEvent(EventDirection.Receive, eventType).raw);
+ }
+
+ /**
+ * Requests the capability to send a given room event. It is not guaranteed to be
+ * allowed, but will be asked for if the negotiation has not already happened.
+ * @param {string} eventType The room event type to ask for.
+ */
+ public requestCapabilityToSendEvent(eventType: string) {
+ this.requestCapability(WidgetEventCapability.forRoomEvent(EventDirection.Send, eventType).raw);
+ }
+
+ /**
+ * Requests the capability to receive a given room event. It is not guaranteed to be
+ * allowed, but will be asked for if the negotiation has not already happened.
+ * @param {string} eventType The room event type to ask for.
+ */
+ public requestCapabilityToReceiveEvent(eventType: string) {
+ this.requestCapability(WidgetEventCapability.forRoomEvent(EventDirection.Receive, eventType).raw);
+ }
+
+ /**
+ * Requests the capability to send a given message event with optional explicit
+ * `msgtype`. It is not guaranteed to be allowed, but will be asked for if the
+ * negotiation has not already happened.
+ * @param {string} msgtype If specified, the specific msgtype to request.
+ * Otherwise all message types will be requested.
+ */
+ public requestCapabilityToSendMessage(msgtype?: string) {
+ this.requestCapability(WidgetEventCapability.forRoomMessageEvent(EventDirection.Send, msgtype).raw);
+ }
+
+ /**
+ * Requests the capability to receive a given message event with optional explicit
+ * `msgtype`. It is not guaranteed to be allowed, but will be asked for if the
+ * negotiation has not already happened.
+ * @param {string} msgtype If specified, the specific msgtype to request.
+ * Otherwise all message types will be requested.
+ */
+ public requestCapabilityToReceiveMessage(msgtype?: string) {
+ this.requestCapability(WidgetEventCapability.forRoomMessageEvent(EventDirection.Receive, msgtype).raw);
+ }
+
+ /**
+ * Requests an OpenID Connect token from the client for the currently logged in
+ * user. This token can be validated server-side with the federation API. Note
+ * that the widget is responsible for validating the token and caching any results
+ * it needs.
+ * @returns {Promise<IOpenIDCredentials>} Resolves to a token for verification.
+ * @throws Throws if the user rejected the request or the request failed.
+ */
+ public requestOpenIDConnectToken(): Promise<IOpenIDCredentials> {
+ return new Promise<IOpenIDCredentials>((resolve, reject) => {
+ this.transport.sendComplete<IGetOpenIDActionRequestData, IGetOpenIDActionResponse>(
+ WidgetApiFromWidgetAction.GetOpenIDCredentials, {},
+ ).then(response => {
+ const rdata = response.response;
+ if (rdata.state === OpenIDRequestState.Allowed) {
+ resolve(rdata);
+ } else if (rdata.state === OpenIDRequestState.Blocked) {
+ reject(new Error("User declined to verify their identity"));
+ } else if (rdata.state === OpenIDRequestState.PendingUserConfirmation) {
+ const handlerFn = (ev: CustomEvent<IOpenIDCredentialsActionRequest>) => {
+ ev.preventDefault();
+ const request = ev.detail;
+ if (request.data.original_request_id !== response.requestId) return;
+ if (request.data.state === OpenIDRequestState.Allowed) {
+ resolve(request.data);
+ this.transport.reply(request, <IWidgetApiRequestEmptyData>{}); // ack
+ } else if (request.data.state === OpenIDRequestState.Blocked) {
+ reject(new Error("User declined to verify their identity"));
+ this.transport.reply(request, <IWidgetApiRequestEmptyData>{}); // ack
+ } else {
+ reject(new Error("Invalid state on reply: " + rdata.state));
+ this.transport.reply(request, <IWidgetApiErrorResponseData>{
+ error: {
+ message: "Invalid state",
+ },
+ });
+ }
+ this.off(`action:${WidgetApiToWidgetAction.OpenIDCredentials}`, handlerFn);
+ };
+ this.on(`action:${WidgetApiToWidgetAction.OpenIDCredentials}`, handlerFn);
+ } else {
+ reject(new Error("Invalid state: " + rdata.state));
+ }
+ }).catch(reject);
+ });
+ }
+
+ /**
+ * Asks the client for additional capabilities. Capabilities can be queued for this
+ * request with the requestCapability() functions.
+ * @returns {Promise<void>} Resolves when complete. Note that the promise resolves when
+ * the capabilities request has gone through, not when the capabilities are approved/denied.
+ * Use the WidgetApiToWidgetAction.NotifyCapabilities action to detect changes.
+ */
+ public updateRequestedCapabilities(): Promise<void> {
+ return this.transport.send(WidgetApiFromWidgetAction.MSC2974RenegotiateCapabilities,
+ <IRenegotiateCapabilitiesRequestData>{
+ capabilities: this.requestedCapabilities,
+ }).then();
+ }
+
+ /**
+ * Tell the client that the content has been loaded.
+ * @returns {Promise} Resolves when the client acknowledges the request.
+ */
+ public sendContentLoaded(): Promise<void> {
+ return this.transport.send(WidgetApiFromWidgetAction.ContentLoaded, <IWidgetApiRequestEmptyData>{}).then();
+ }
+
+ /**
+ * Sends a sticker to the client.
+ * @param {IStickerActionRequestData} sticker The sticker to send.
+ * @returns {Promise} Resolves when the client acknowledges the request.
+ */
+ public sendSticker(sticker: IStickerActionRequestData): Promise<void> {
+ return this.transport.send(WidgetApiFromWidgetAction.SendSticker, sticker).then();
+ }
+
+ /**
+ * Asks the client to set the always-on-screen status for this widget.
+ * @param {boolean} value The new state to request.
+ * @returns {Promise<boolean>} Resolve with true if the client was able to fulfill
+ * the request, resolves to false otherwise. Rejects if an error occurred.
+ */
+ public setAlwaysOnScreen(value: boolean): Promise<boolean> {
+ return this.transport.send<IStickyActionRequestData, IStickyActionResponseData>(
+ WidgetApiFromWidgetAction.UpdateAlwaysOnScreen, {value},
+ ).then(res => res.success);
+ }
+
+ /**
+ * Opens a modal widget.
+ * @param {string} url The URL to the modal widget.
+ * @param {string} name The name of the widget.
+ * @param {IModalWidgetOpenRequestDataButton[]} buttons The buttons to have on the widget.
+ * @param {IModalWidgetCreateData} data Data to supply to the modal widget.
+ * @param {WidgetType} type The type of modal widget.
+ * @returns {Promise<void>} Resolves when the modal widget has been opened.
+ */
+ public openModalWidget(
+ url: string,
+ name: string,
+ buttons: IModalWidgetOpenRequestDataButton[] = [],
+ data: IModalWidgetCreateData = {},
+ type: WidgetType = MatrixWidgetType.Custom,
+ ): Promise<void> {
+ return this.transport.send<IModalWidgetOpenRequestData>(
+ WidgetApiFromWidgetAction.OpenModalWidget, { type, url, name, buttons, data },
+ ).then();
+ }
+
+ /**
+ * Closes the modal widget. The widget's session will be terminated shortly after.
+ * @param {IModalWidgetReturnData} data Optional data to close the modal widget with.
+ * @returns {Promise<void>} Resolves when complete.
+ */
+ public closeModalWidget(data: IModalWidgetReturnData = {}): Promise<void> {
+ return this.transport.send<IModalWidgetReturnData>(WidgetApiFromWidgetAction.CloseModalWidget, data).then();
+ }
+
+ public sendRoomEvent(
+ eventType: string,
+ content: unknown,
+ roomId?: string,
+ ): Promise<ISendEventFromWidgetResponseData> {
+ return this.transport.send<ISendEventFromWidgetRequestData, ISendEventFromWidgetResponseData>(
+ WidgetApiFromWidgetAction.SendEvent,
+ {type: eventType, content, room_id: roomId},
+ );
+ }
+
+ public sendStateEvent(
+ eventType: string,
+ stateKey: string,
+ content: unknown,
+ roomId?: string,
+ ): Promise<ISendEventFromWidgetResponseData> {
+ return this.transport.send<ISendEventFromWidgetRequestData, ISendEventFromWidgetResponseData>(
+ WidgetApiFromWidgetAction.SendEvent,
+ {type: eventType, content, state_key: stateKey, room_id: roomId},
+ );
+ }
+
+ /**
+ * Sends a to-device event.
+ * @param {string} eventType The type of events being sent.
+ * @param {boolean} encrypted Whether to encrypt the message contents.
+ * @param {Object} contentMap A map from user IDs to device IDs to message contents.
+ * @returns {Promise<ISendToDeviceFromWidgetResponseData>} Resolves when complete.
+ */
+ public sendToDevice(
+ eventType: string,
+ encrypted: boolean,
+ contentMap: { [userId: string]: { [deviceId: string]: object } },
+ ): Promise<ISendToDeviceFromWidgetResponseData> {
+ return this.transport.send<ISendToDeviceFromWidgetRequestData, ISendToDeviceFromWidgetResponseData>(
+ WidgetApiFromWidgetAction.SendToDevice,
+ {type: eventType, encrypted, messages: contentMap},
+ );
+ }
+
+ public readRoomEvents(
+ eventType: string,
+ limit?: number,
+ msgtype?: string,
+ roomIds?: (string | Symbols.AnyRoom)[],
+ ): Promise<IRoomEvent[]> {
+ const data: IReadEventFromWidgetRequestData = {type: eventType, msgtype: msgtype};
+ if (limit !== undefined) {
+ data.limit = limit;
+ }
+ if (roomIds) {
+ if (roomIds.includes(Symbols.AnyRoom)) {
+ data.room_ids = Symbols.AnyRoom;
+ } else {
+ data.room_ids = roomIds;
+ }
+ }
+ return this.transport.send<IReadEventFromWidgetRequestData, IReadEventFromWidgetResponseData>(
+ WidgetApiFromWidgetAction.MSC2876ReadEvents,
+ data,
+ ).then(r => r.events);
+ }
+
+ /**
+ * Reads all related events given a known eventId.
+ * @param eventId The id of the parent event to be read.
+ * @param roomId The room to look within. When undefined, the user's currently
+ * viewed room.
+ * @param relationType The relationship type of child events to search for.
+ * When undefined, all relations are returned.
+ * @param eventType The event type of child events to search for. When undefined,
+ * all related events are returned.
+ * @param limit The maximum number of events to retrieve per room. If not
+ * supplied, the server will apply a default limit.
+ * @param from The pagination token to start returning results from, as
+ * received from a previous call. If not supplied, results start at the most
+ * recent topological event known to the server.
+ * @param to The pagination token to stop returning results at. If not
+ * supplied, results continue up to limit or until there are no more events.
+ * @param direction The direction to search for according to MSC3715.
+ * @returns Resolves to the room relations.
+ */
+ public async readEventRelations(
+ eventId: string,
+ roomId?: string,
+ relationType?: string,
+ eventType?: string,
+ limit?: number,
+ from?: string,
+ to?: string,
+ direction?: 'f' | 'b',
+ ): Promise<IReadRelationsFromWidgetResponseData> {
+ const versions = await this.getClientVersions();
+ if (!versions.includes(UnstableApiVersion.MSC3869)) {
+ throw new Error("The read_relations action is not supported by the client.")
+ }
+
+ const data: IReadRelationsFromWidgetRequestData = {
+ event_id: eventId,
+ rel_type: relationType,
+ event_type: eventType,
+ room_id: roomId,
+ to,
+ from,
+ limit,
+ direction,
+ };
+
+ return this.transport.send<IReadRelationsFromWidgetRequestData, IReadRelationsFromWidgetResponseData>(
+ WidgetApiFromWidgetAction.MSC3869ReadRelations,
+ data,
+ )
+ }
+
+ public readStateEvents(
+ eventType: string,
+ limit?: number,
+ stateKey?: string,
+ roomIds?: (string | Symbols.AnyRoom)[],
+ ): Promise<IRoomEvent[]> {
+ const data: IReadEventFromWidgetRequestData = {
+ type: eventType,
+ state_key: stateKey === undefined ? true : stateKey,
+ };
+ if (limit !== undefined) {
+ data.limit = limit;
+ }
+ if (roomIds) {
+ if (roomIds.includes(Symbols.AnyRoom)) {
+ data.room_ids = Symbols.AnyRoom;
+ } else {
+ data.room_ids = roomIds;
+ }
+ }
+ return this.transport.send<IReadEventFromWidgetRequestData, IReadEventFromWidgetResponseData>(
+ WidgetApiFromWidgetAction.MSC2876ReadEvents,
+ data,
+ ).then(r => r.events);
+ }
+
+ /**
+ * Sets a button as disabled or enabled on the modal widget. Buttons are enabled by default.
+ * @param {ModalButtonID} buttonId The button ID to enable/disable.
+ * @param {boolean} isEnabled Whether or not the button is enabled.
+ * @returns {Promise<void>} Resolves when complete.
+ * @throws Throws if the button cannot be disabled, or the client refuses to disable the button.
+ */
+ public setModalButtonEnabled(buttonId: ModalButtonID, isEnabled: boolean): Promise<void> {
+ if (buttonId === BuiltInModalButtonID.Close) {
+ throw new Error("The close button cannot be disabled");
+ }
+ return this.transport.send<ISetModalButtonEnabledActionRequestData>(
+ WidgetApiFromWidgetAction.SetModalButtonEnabled, {button: buttonId, enabled: isEnabled},
+ ).then();
+ }
+
+ /**
+ * Attempts to navigate the client to the given URI. This can only be called with Matrix URIs
+ * (currently only matrix.to, but in future a Matrix URI scheme will be defined).
+ * @param {string} uri The URI to navigate to.
+ * @returns {Promise<void>} Resolves when complete.
+ * @throws Throws if the URI is invalid or cannot be processed.
+ * @deprecated This currently relies on an unstable MSC (MSC2931).
+ */
+ public navigateTo(uri: string): Promise<void> {
+ if (!uri || !uri.startsWith("https://matrix.to/#")) {
+ throw new Error("Invalid matrix.to URI");
+ }
+
+ return this.transport.send<INavigateActionRequestData>(
+ WidgetApiFromWidgetAction.MSC2931Navigate, {uri},
+ ).then();
+ }
+
+ /**
+ * Starts watching for TURN servers, yielding an initial set of credentials as soon as possible,
+ * and thereafter yielding new credentials whenever the previous ones expire.
+ * @yields {ITurnServer} The TURN server URIs and credentials currently available to the widget.
+ */
+ public async* getTurnServers(): AsyncGenerator<ITurnServer> {
+ let setTurnServer: (server: ITurnServer) => void;
+
+ const onUpdateTurnServers = async (ev: CustomEvent<IUpdateTurnServersRequest>) => {
+ ev.preventDefault();
+ setTurnServer(ev.detail.data);
+ await this.transport.reply<IWidgetApiAcknowledgeResponseData>(ev.detail, {});
+ };
+
+ // Start listening for updates before we even start watching, to catch
+ // TURN data that is sent immediately
+ this.on(`action:${WidgetApiToWidgetAction.UpdateTurnServers}`, onUpdateTurnServers);
+
+ // Only send the 'watch' action if we aren't already watching
+ if (this.turnServerWatchers === 0) {
+ try {
+ await this.transport.send<IWidgetApiRequestEmptyData>(WidgetApiFromWidgetAction.WatchTurnServers, {});
+ } catch (e) {
+ this.off(`action:${WidgetApiToWidgetAction.UpdateTurnServers}`, onUpdateTurnServers);
+ throw e;
+ }
+ }
+ this.turnServerWatchers++;
+
+ try {
+ // Watch for new data indefinitely (until this generator's return method is called)
+ while (true) {
+ yield await new Promise<ITurnServer>(resolve => setTurnServer = resolve);
+ }
+ } finally {
+ // The loop was broken by the caller - clean up
+ this.off(`action:${WidgetApiToWidgetAction.UpdateTurnServers}`, onUpdateTurnServers);
+
+ // Since sending the 'unwatch' action will end updates for all other
+ // consumers, only send it if we're the only consumer remaining
+ this.turnServerWatchers--;
+ if (this.turnServerWatchers === 0) {
+ await this.transport.send<IWidgetApiRequestEmptyData>(WidgetApiFromWidgetAction.UnwatchTurnServers, {});
+ }
+ }
+ }
+
+ /**
+ * Search for users in the user directory.
+ * @param searchTerm The term to search for.
+ * @param limit The maximum number of results to return. If not supplied, the
+ * @returns Resolves to the search results.
+ */
+ public async searchUserDirectory(
+ searchTerm: string,
+ limit?: number,
+ ): Promise<IUserDirectorySearchFromWidgetResponseData> {
+ const versions = await this.getClientVersions();
+ if (!versions.includes(UnstableApiVersion.MSC3973)) {
+ throw new Error("The user_directory_search action is not supported by the client.")
+ }
+
+ const data: IUserDirectorySearchFromWidgetRequestData = {
+ search_term: searchTerm,
+ limit,
+ };
+
+ return this.transport.send<
+ IUserDirectorySearchFromWidgetRequestData,
+ IUserDirectorySearchFromWidgetResponseData
+ >(WidgetApiFromWidgetAction.MSC3973UserDirectorySearch, data);
+ }
+
+ /**
+ * Starts the communication channel. This should be done early to ensure
+ * that messages are not missed. Communication can only be stopped by the client.
+ */
+ public start() {
+ this.transport.start();
+ this.getClientVersions().then(v => {
+ if (v.includes(UnstableApiVersion.MSC2974)) {
+ this.supportsMSC2974Renegotiate = true;
+ }
+ });
+ }
+
+ private handleMessage(ev: CustomEvent<IWidgetApiRequest>) {
+ const actionEv = new CustomEvent(`action:${ev.detail.action}`, {
+ detail: ev.detail,
+ cancelable: true,
+ });
+ this.emit(`action:${ev.detail.action}`, actionEv);
+ if (!actionEv.defaultPrevented) {
+ switch (ev.detail.action) {
+ case WidgetApiToWidgetAction.SupportedApiVersions:
+ return this.replyVersions(<ISupportedVersionsActionRequest>ev.detail);
+ case WidgetApiToWidgetAction.Capabilities:
+ return this.handleCapabilities(<ICapabilitiesActionRequest>ev.detail);
+ case WidgetApiToWidgetAction.UpdateVisibility:
+ return this.transport.reply(ev.detail, <IWidgetApiRequestEmptyData>{}); // ack to avoid error spam
+ case WidgetApiToWidgetAction.NotifyCapabilities:
+ return this.transport.reply(ev.detail, <IWidgetApiRequestEmptyData>{}); // ack to avoid error spam
+ default:
+ return this.transport.reply(ev.detail, <IWidgetApiErrorResponseData>{
+ error: {
+ message: "Unknown or unsupported action: " + ev.detail.action,
+ },
+ });
+ }
+ }
+ }
+
+ private replyVersions(request: ISupportedVersionsActionRequest) {
+ this.transport.reply<ISupportedVersionsActionResponseData>(request, {
+ supported_versions: CurrentApiVersions,
+ });
+ }
+
+ public getClientVersions(): Promise<ApiVersion[]> {
+ if (Array.isArray(this.cachedClientVersions)) {
+ return Promise.resolve(this.cachedClientVersions);
+ }
+
+ return this.transport.send<IWidgetApiRequestEmptyData, ISupportedVersionsActionResponseData>(
+ WidgetApiFromWidgetAction.SupportedApiVersions, {},
+ ).then(r => {
+ this.cachedClientVersions = r.supported_versions;
+ return r.supported_versions;
+ }).catch(e => {
+ console.warn("non-fatal error getting supported client versions: ", e);
+ return [];
+ });
+ }
+
+ private handleCapabilities(request: ICapabilitiesActionRequest) {
+ if (this.capabilitiesFinished) {
+ return this.transport.reply<IWidgetApiErrorResponseData>(request, {
+ error: {
+ message: "Capability negotiation already completed",
+ },
+ });
+ }
+
+ // See if we can expect a capabilities notification or not
+ return this.getClientVersions().then(v => {
+ if (v.includes(UnstableApiVersion.MSC2871)) {
+ this.once(
+ `action:${WidgetApiToWidgetAction.NotifyCapabilities}`,
+ (ev: CustomEvent<INotifyCapabilitiesActionRequest>) => {
+ this.approvedCapabilities = ev.detail.data.approved;
+ this.emit("ready");
+ },
+ );
+ } else {
+ // if we can't expect notification, we're as done as we can be
+ this.emit("ready");
+ }
+
+ // in either case, reply to that capabilities request
+ this.capabilitiesFinished = true;
+ return this.transport.reply<ICapabilitiesActionResponseData>(request, {
+ capabilities: this.requestedCapabilities,
+ });
+ });
+ }
+}
diff --git a/includes/external/matrix/node_modules/matrix-widget-api/src/driver/WidgetDriver.ts b/includes/external/matrix/node_modules/matrix-widget-api/src/driver/WidgetDriver.ts
new file mode 100644
index 0000000..9fdeee2
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-widget-api/src/driver/WidgetDriver.ts
@@ -0,0 +1,247 @@
+/*
+ * Copyright 2020 - 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.
+ */
+
+import { Capability, IOpenIDCredentials, OpenIDRequestState, SimpleObservable, IRoomEvent, ITurnServer } from "..";
+
+export interface ISendEventDetails {
+ roomId: string;
+ eventId: string;
+}
+
+export interface IOpenIDUpdate {
+ state: OpenIDRequestState;
+ token?: IOpenIDCredentials;
+}
+
+export interface IReadEventRelationsResult {
+ chunk: IRoomEvent[];
+ nextBatch?: string;
+ prevBatch?: string;
+}
+
+export interface ISearchUserDirectoryResult {
+ limited: boolean;
+ results: Array<{
+ userId: string;
+ displayName?: string;
+ avatarUrl?: string;
+ }>;
+}
+
+/**
+ * Represents the functions and behaviour the widget-api is unable to
+ * do, such as prompting the user for information or interacting with
+ * the UI. Clients are expected to implement this class and override
+ * any functions they need/want to support.
+ *
+ * This class assumes the client will have a context of a Widget
+ * instance already.
+ */
+export abstract class WidgetDriver {
+ /**
+ * Verifies the widget's requested capabilities, returning the ones
+ * it is approved to use. Mutating the requested capabilities will
+ * have no effect.
+ *
+ * This SHOULD result in the user being prompted to approve/deny
+ * capabilities.
+ *
+ * By default this rejects all capabilities (returns an empty set).
+ * @param {Set<Capability>} requested The set of requested capabilities.
+ * @returns {Promise<Set<Capability>>} Resolves to the allowed capabilities.
+ */
+ public validateCapabilities(requested: Set<Capability>): Promise<Set<Capability>> {
+ return Promise.resolve(new Set());
+ }
+
+ /**
+ * Sends an event into a room. If `roomId` is falsy, the client should send the event
+ * into the room the user is currently looking at. The widget API will have already
+ * verified that the widget is capable of sending the event to that room.
+ * @param {string} eventType The event type to be sent.
+ * @param {*} content The content for the event.
+ * @param {string|null} stateKey The state key if this is a state event, otherwise null.
+ * May be an empty string.
+ * @param {string|null} roomId The room ID to send the event to. If falsy, the room the
+ * user is currently looking at.
+ * @returns {Promise<ISendEventDetails>} Resolves when the event has been sent with
+ * details of that event.
+ * @throws Rejected when the event could not be sent.
+ */
+ public sendEvent(
+ eventType: string,
+ content: unknown,
+ stateKey: string | null = null,
+ roomId: string | null = null,
+ ): Promise<ISendEventDetails> {
+ return Promise.reject(new Error("Failed to override function"));
+ }
+
+ /**
+ * Sends a to-device event. The widget API will have already verified that the widget
+ * is capable of sending the event.
+ * @param {string} eventType The event type to be sent.
+ * @param {boolean} encrypted Whether to encrypt the message contents.
+ * @param {Object} contentMap A map from user ID and device ID to event content.
+ * @returns {Promise<void>} Resolves when the event has been sent.
+ * @throws Rejected when the event could not be sent.
+ */
+ public sendToDevice(
+ eventType: string,
+ encrypted: boolean,
+ contentMap: { [userId: string]: { [deviceId: string]: object } },
+ ): Promise<void> {
+ return Promise.reject(new Error("Failed to override function"));
+ }
+
+ /**
+ * Reads all events of the given type, and optionally `msgtype` (if applicable/defined),
+ * the user has access to. The widget API will have already verified that the widget is
+ * capable of receiving the events. Less events than the limit are allowed to be returned,
+ * but not more. If `roomIds` is supplied, it may contain `Symbols.AnyRoom` to denote that
+ * `limit` in each of the client's known rooms should be returned. When `null`, only the
+ * room the user is currently looking at should be considered.
+ * @param eventType The event type to be read.
+ * @param msgtype The msgtype of the events to be read, if applicable/defined.
+ * @param limit The maximum number of events to retrieve per room. Will be zero to denote "as many
+ * as possible".
+ * @param roomIds When null, the user's currently viewed room. Otherwise, the list of room IDs
+ * to look within, possibly containing Symbols.AnyRoom to denote all known rooms.
+ * @returns {Promise<IRoomEvent[]>} Resolves to the room events, or an empty array.
+ */
+ public readRoomEvents(
+ eventType: string,
+ msgtype: string | undefined,
+ limit: number,
+ roomIds: string[] | null = null,
+ ): Promise<IRoomEvent[]> {
+ return Promise.resolve([]);
+ }
+
+ /**
+ * Reads all events of the given type, and optionally state key (if applicable/defined),
+ * the user has access to. The widget API will have already verified that the widget is
+ * capable of receiving the events. Less events than the limit are allowed to be returned,
+ * but not more. If `roomIds` is supplied, it may contain `Symbols.AnyRoom` to denote that
+ * `limit` in each of the client's known rooms should be returned. When `null`, only the
+ * room the user is currently looking at should be considered.
+ * @param eventType The event type to be read.
+ * @param stateKey The state key of the events to be read, if applicable/defined.
+ * @param limit The maximum number of events to retrieve. Will be zero to denote "as many
+ * as possible".
+ * @param roomIds When null, the user's currently viewed room. Otherwise, the list of room IDs
+ * to look within, possibly containing Symbols.AnyRoom to denote all known rooms.
+ * @returns {Promise<IRoomEvent[]>} Resolves to the state events, or an empty array.
+ */
+ public readStateEvents(
+ eventType: string,
+ stateKey: string | undefined,
+ limit: number,
+ roomIds: string[] | null = null,
+ ): Promise<IRoomEvent[]> {
+ return Promise.resolve([]);
+ }
+
+ /**
+ * Reads all events that are related to a given event. The widget API will
+ * have already verified that the widget is capable of receiving the event,
+ * or will make sure to reject access to events which are returned from this
+ * function, but are not capable of receiving. If `relationType` or `eventType`
+ * are set, the returned events should already be filtered. Less events than
+ * the limit are allowed to be returned, but not more.
+ * @param eventId The id of the parent event to be read.
+ * @param roomId The room to look within. When undefined, the user's
+ * currently viewed room.
+ * @param relationType The relationship type of child events to search for.
+ * When undefined, all relations are returned.
+ * @param eventType The event type of child events to search for. When undefined,
+ * all related events are returned.
+ * @param from The pagination token to start returning results from, as
+ * received from a previous call. If not supplied, results start at the most
+ * recent topological event known to the server.
+ * @param to The pagination token to stop returning results at. If not
+ * supplied, results continue up to limit or until there are no more events.
+ * @param limit The maximum number of events to retrieve per room. If not
+ * supplied, the server will apply a default limit.
+ * @param direction The direction to search for according to MSC3715
+ * @returns Resolves to the room relations.
+ */
+ public readEventRelations(
+ eventId: string,
+ roomId?: string,
+ relationType?: string,
+ eventType?: string,
+ from?: string,
+ to?: string,
+ limit?: number,
+ direction?: 'f' | 'b',
+ ): Promise<IReadEventRelationsResult> {
+ return Promise.resolve({ chunk: [] });
+ }
+
+ /**
+ * Asks the user for permission to validate their identity through OpenID Connect. The
+ * interface for this function is an observable which accepts the state machine of the
+ * OIDC exchange flow. For example, if the client/user blocks the request then it would
+ * feed back a `{state: Blocked}` into the observable. Similarly, if the user already
+ * approved the widget then a `{state: Allowed}` would be fed into the observable alongside
+ * the token itself. If the client is asking for permission, it should feed in a
+ * `{state: PendingUserConfirmation}` followed by the relevant Allowed or Blocked state.
+ *
+ * The widget API will reject the widget's request with an error if this contract is not
+ * met properly. By default, the widget driver will block all OIDC requests.
+ * @param {SimpleObservable<IOpenIDUpdate>} observer The observable to feed updates into.
+ */
+ public askOpenID(observer: SimpleObservable<IOpenIDUpdate>) {
+ observer.update({state: OpenIDRequestState.Blocked});
+ }
+
+ /**
+ * Navigates the client with a matrix.to URI. In future this function will also be provided
+ * with the Matrix URIs once matrix.to is replaced. The given URI will have already been
+ * lightly checked to ensure it looks like a valid URI, though the implementation is recommended
+ * to do further checks on the URI.
+ * @param {string} uri The URI to navigate to.
+ * @returns {Promise<void>} Resolves when complete.
+ * @throws Throws if there's a problem with the navigation, such as invalid format.
+ */
+ public navigate(uri: string): Promise<void> {
+ throw new Error("Navigation is not implemented");
+ }
+
+ /**
+ * Polls for TURN server data, yielding an initial set of credentials as soon as possible, and
+ * thereafter yielding new credentials whenever the previous ones expire. The widget API will
+ * have already verified that the widget has permission to access TURN servers.
+ * @yields {ITurnServer} The TURN server URIs and credentials currently available to the client.
+ */
+ public getTurnServers(): AsyncGenerator<ITurnServer> {
+ throw new Error("TURN server support is not implemented");
+ }
+
+ /**
+ * Search for users in the user directory.
+ * @param searchTerm The term to search for.
+ * @param limit The maximum number of results to return. If not supplied, the
+ * @returns Resolves to the search results.
+ */
+ public searchUserDirectory(
+ searchTerm: string,
+ limit?: number,
+ ): Promise<ISearchUserDirectoryResult> {
+ return Promise.resolve({ limited: false, results: [] });
+ }
+}
diff --git a/includes/external/matrix/node_modules/matrix-widget-api/src/index.ts b/includes/external/matrix/node_modules/matrix-widget-api/src/index.ts
new file mode 100644
index 0000000..b7247c9
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-widget-api/src/index.ts
@@ -0,0 +1,73 @@
+/*
+Copyright 2020 - 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.
+*/
+
+// Primary structures
+export * from "./WidgetApi";
+export * from "./ClientWidgetApi";
+export * from "./Symbols";
+
+// Transports (not sure why you'd use these directly, but might as well export all the things)
+export * from "./transport/ITransport";
+export * from "./transport/PostmessageTransport";
+
+// Interfaces and simple models
+export * from "./interfaces/ICustomWidgetData";
+export * from "./interfaces/IJitsiWidgetData";
+export * from "./interfaces/IStickerpickerWidgetData";
+export * from "./interfaces/IWidget";
+export * from "./interfaces/WidgetType";
+export * from "./interfaces/IWidgetApiErrorResponse";
+export * from "./interfaces/IWidgetApiRequest";
+export * from "./interfaces/IWidgetApiResponse";
+export * from "./interfaces/WidgetApiAction";
+export * from "./interfaces/WidgetApiDirection";
+export * from "./interfaces/ApiVersion";
+export * from "./interfaces/Capabilities";
+export * from "./interfaces/CapabilitiesAction";
+export * from "./interfaces/ContentLoadedAction";
+export * from "./interfaces/ScreenshotAction";
+export * from "./interfaces/StickerAction";
+export * from "./interfaces/StickyAction";
+export * from "./interfaces/SupportedVersionsAction";
+export * from "./interfaces/VisibilityAction";
+export * from "./interfaces/GetOpenIDAction";
+export * from "./interfaces/OpenIDCredentialsAction";
+export * from "./interfaces/WidgetKind";
+export * from "./interfaces/ModalButtonKind";
+export * from "./interfaces/ModalWidgetActions";
+export * from "./interfaces/SetModalButtonEnabledAction";
+export * from "./interfaces/WidgetConfigAction";
+export * from "./interfaces/SendEventAction";
+export * from "./interfaces/SendToDeviceAction";
+export * from "./interfaces/ReadEventAction";
+export * from "./interfaces/IRoomEvent";
+export * from "./interfaces/NavigateAction";
+export * from "./interfaces/TurnServerActions";
+export * from "./interfaces/ReadRelationsAction";
+
+// Complex models
+export * from "./models/WidgetEventCapability";
+export * from "./models/validation/url";
+export * from "./models/validation/utils";
+export * from "./models/Widget";
+export * from "./models/WidgetParser";
+
+// Utilities
+export * from "./templating/url-template";
+export * from "./util/SimpleObservable";
+
+// Drivers
+export * from "./driver/WidgetDriver";
diff --git a/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/ApiVersion.ts b/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/ApiVersion.ts
new file mode 100644
index 0000000..6586c14
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/ApiVersion.ts
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2020 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.
+ */
+
+export enum MatrixApiVersion {
+ Prerelease1 = "0.0.1",
+ Prerelease2 = "0.0.2",
+ //V010 = "0.1.0", // first release
+}
+
+export enum UnstableApiVersion {
+ MSC2762 = "org.matrix.msc2762",
+ MSC2871 = "org.matrix.msc2871",
+ MSC2931 = "org.matrix.msc2931",
+ MSC2974 = "org.matrix.msc2974",
+ MSC2876 = "org.matrix.msc2876",
+ MSC3819 = "org.matrix.msc3819",
+ MSC3846 = "town.robin.msc3846",
+ MSC3869 = "org.matrix.msc3869",
+ MSC3973 = "org.matrix.msc3973",
+}
+
+export type ApiVersion = MatrixApiVersion | UnstableApiVersion | string;
+
+export const CurrentApiVersions: ApiVersion[] = [
+ MatrixApiVersion.Prerelease1,
+ MatrixApiVersion.Prerelease2,
+ //MatrixApiVersion.V010,
+ UnstableApiVersion.MSC2762,
+ UnstableApiVersion.MSC2871,
+ UnstableApiVersion.MSC2931,
+ UnstableApiVersion.MSC2974,
+ UnstableApiVersion.MSC2876,
+ UnstableApiVersion.MSC3819,
+ UnstableApiVersion.MSC3846,
+ UnstableApiVersion.MSC3869,
+ UnstableApiVersion.MSC3973,
+];
diff --git a/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/Capabilities.ts b/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/Capabilities.ts
new file mode 100644
index 0000000..1572105
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/Capabilities.ts
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2020 - 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.
+ */
+
+import { Symbols } from "../Symbols";
+
+export enum MatrixCapabilities {
+ Screenshots = "m.capability.screenshot",
+ StickerSending = "m.sticker",
+ AlwaysOnScreen = "m.always_on_screen",
+ /**
+ * @deprecated It is not recommended to rely on this existing - it can be removed without notice.
+ * Ask Element to not give the option to move the widget into a separate tab.
+ */
+ RequiresClient = "io.element.requires_client",
+ /**
+ * @deprecated It is not recommended to rely on this existing - it can be removed without notice.
+ */
+ MSC2931Navigate = "org.matrix.msc2931.navigate",
+ MSC3846TurnServers = "town.robin.msc3846.turn_servers",
+ /**
+ * @deprecated It is not recommended to rely on this existing - it can be removed without notice.
+ */
+ MSC3973UserDirectorySearch = "org.matrix.msc3973.user_directory_search",
+}
+
+export type Capability = MatrixCapabilities | string;
+
+export const StickerpickerCapabilities: Capability[] = [MatrixCapabilities.StickerSending];
+export const VideoConferenceCapabilities: Capability[] = [MatrixCapabilities.AlwaysOnScreen];
+
+/**
+ * Determines if a capability is a capability for a timeline.
+ * @param {Capability} capability The capability to test.
+ * @returns {boolean} True if a timeline capability, false otherwise.
+ */
+export function isTimelineCapability(capability: Capability): boolean {
+ // TODO: Change when MSC2762 becomes stable.
+ return capability?.startsWith("org.matrix.msc2762.timeline:");
+}
+
+/**
+ * Determines if a capability is a timeline capability for the given room.
+ * @param {Capability} capability The capability to test.
+ * @param {string | Symbols.AnyRoom} roomId The room ID, or `Symbols.AnyRoom` for that designation.
+ * @returns {boolean} True if a matching capability, false otherwise.
+ */
+export function isTimelineCapabilityFor(capability: Capability, roomId: string | Symbols.AnyRoom): boolean {
+ return capability === `org.matrix.msc2762.timeline:${roomId}`;
+}
+
+/**
+ * Gets the room ID described by a timeline capability.
+ * @param {string} capability The capability to parse.
+ * @returns {string} The room ID.
+ */
+export function getTimelineRoomIDFromCapability(capability: Capability): string {
+ return capability.substring(capability.indexOf(":") + 1);
+}
diff --git a/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/CapabilitiesAction.ts b/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/CapabilitiesAction.ts
new file mode 100644
index 0000000..365bb79
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/CapabilitiesAction.ts
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2020 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.
+ */
+
+import { IWidgetApiRequest, IWidgetApiRequestData, IWidgetApiRequestEmptyData } from "./IWidgetApiRequest";
+import { WidgetApiFromWidgetAction, WidgetApiToWidgetAction } from "./WidgetApiAction";
+import { Capability } from "./Capabilities";
+import { IWidgetApiAcknowledgeResponseData, IWidgetApiResponseData } from "./IWidgetApiResponse";
+
+export interface ICapabilitiesActionRequest extends IWidgetApiRequest {
+ action: WidgetApiToWidgetAction.Capabilities;
+ data: IWidgetApiRequestEmptyData;
+}
+
+export interface ICapabilitiesActionResponseData extends IWidgetApiResponseData {
+ capabilities: Capability[];
+}
+
+export interface ICapabilitiesActionResponse extends ICapabilitiesActionRequest {
+ response: ICapabilitiesActionResponseData;
+}
+
+export interface INotifyCapabilitiesActionRequestData extends IWidgetApiRequestData {
+ requested: Capability[];
+ approved: Capability[];
+}
+
+export interface INotifyCapabilitiesActionRequest extends IWidgetApiRequest {
+ action: WidgetApiToWidgetAction.NotifyCapabilities;
+ data: INotifyCapabilitiesActionRequestData;
+}
+
+export interface INotifyCapabilitiesActionResponse extends INotifyCapabilitiesActionRequest {
+ response: IWidgetApiAcknowledgeResponseData;
+}
+
+export interface IRenegotiateCapabilitiesActionRequest extends IWidgetApiRequest {
+ action: WidgetApiFromWidgetAction.MSC2974RenegotiateCapabilities;
+ data: IRenegotiateCapabilitiesRequestData;
+}
+
+export interface IRenegotiateCapabilitiesRequestData extends IWidgetApiResponseData {
+ capabilities: Capability[];
+}
+
+export interface IRenegotiateCapabilitiesActionResponse extends IRenegotiateCapabilitiesActionRequest {
+ // nothing
+}
diff --git a/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/ContentLoadedAction.ts b/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/ContentLoadedAction.ts
new file mode 100644
index 0000000..ceca93f
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/ContentLoadedAction.ts
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2020 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.
+ */
+
+import { IWidgetApiRequest, IWidgetApiRequestEmptyData } from "./IWidgetApiRequest";
+import { WidgetApiFromWidgetAction } from "./WidgetApiAction";
+import { IWidgetApiAcknowledgeResponseData } from "./IWidgetApiResponse";
+
+export interface IContentLoadedActionRequest extends IWidgetApiRequest {
+ action: WidgetApiFromWidgetAction.ContentLoaded;
+ data: IWidgetApiRequestEmptyData;
+}
+
+export interface IContentLoadedActionResponse extends IContentLoadedActionRequest {
+ response: IWidgetApiAcknowledgeResponseData;
+}
diff --git a/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/GetOpenIDAction.ts b/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/GetOpenIDAction.ts
new file mode 100644
index 0000000..000313c
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/GetOpenIDAction.ts
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2020 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.
+ */
+
+import { IWidgetApiRequest, IWidgetApiRequestData } from "./IWidgetApiRequest";
+import { WidgetApiFromWidgetAction } from "./WidgetApiAction";
+import { IWidgetApiResponseData } from "./IWidgetApiResponse";
+
+export enum OpenIDRequestState {
+ Allowed = "allowed",
+ Blocked = "blocked",
+ PendingUserConfirmation = "request",
+}
+
+export interface IOpenIDCredentials {
+ access_token?: string; // eslint-disable-line camelcase
+ expires_in?: number; // eslint-disable-line camelcase
+ matrix_server_name?: string; // eslint-disable-line camelcase
+ token_type?: "Bearer" | string; // eslint-disable-line camelcase
+}
+
+export interface IGetOpenIDActionRequestData extends IWidgetApiRequestData {
+ // nothing
+}
+
+export interface IGetOpenIDActionRequest extends IWidgetApiRequest {
+ action: WidgetApiFromWidgetAction.GetOpenIDCredentials;
+ data: IGetOpenIDActionRequestData;
+}
+
+export interface IGetOpenIDActionResponseData extends IWidgetApiResponseData, IOpenIDCredentials {
+ state: OpenIDRequestState;
+}
+
+export interface IGetOpenIDActionResponse extends IGetOpenIDActionRequest {
+ response: IGetOpenIDActionResponseData;
+}
diff --git a/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/ICustomWidgetData.ts b/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/ICustomWidgetData.ts
new file mode 100644
index 0000000..56657fb
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/ICustomWidgetData.ts
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2020 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.
+ */
+
+import { IWidgetData } from "./IWidget";
+
+/**
+ * Widget data for m.custom specifically.
+ */
+export interface ICustomWidgetData extends IWidgetData {
+ /**
+ * The URL for the widget if the templated URL is not exactly what will be loaded.
+ */
+ url?: string;
+}
diff --git a/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/IJitsiWidgetData.ts b/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/IJitsiWidgetData.ts
new file mode 100644
index 0000000..65b22a0
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/IJitsiWidgetData.ts
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2020 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.
+ */
+
+import { IWidgetData } from "./IWidget";
+
+/**
+ * Widget data for m.jitsi widgets.
+ */
+export interface IJitsiWidgetData extends IWidgetData {
+ /**
+ * The domain where the Jitsi Meet conference is being held.
+ */
+ domain: string;
+
+ /**
+ * The conference ID (also known as the room name) where the conference is being held.
+ */
+ conferenceId: string;
+
+ /**
+ * Optional. True to indicate that the conference should be without video, false
+ * otherwise (default).
+ */
+ isAudioOnly?: boolean;
+}
diff --git a/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/IRoomEvent.ts b/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/IRoomEvent.ts
new file mode 100644
index 0000000..5e90005
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/IRoomEvent.ts
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2020 - 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.
+ */
+
+export interface IRoomEvent {
+ type: string;
+ sender: string;
+ event_id: string; // eslint-disable-line camelcase
+ room_id: string; // eslint-disable-line camelcase
+ state_key?: string; // eslint-disable-line camelcase
+ origin_server_ts: number; // eslint-disable-line camelcase
+ content: unknown;
+ unsigned: unknown;
+}
diff --git a/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/IStickerpickerWidgetData.ts b/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/IStickerpickerWidgetData.ts
new file mode 100644
index 0000000..1459fa5
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/IStickerpickerWidgetData.ts
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2020 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.
+ */
+
+import { IWidgetData } from "./IWidget";
+
+export interface IStickerpickerWidgetData extends IWidgetData {
+ // no additional properties (for now)
+}
diff --git a/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/IWidget.ts b/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/IWidget.ts
new file mode 100644
index 0000000..a6ee670
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/IWidget.ts
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2020 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.
+ */
+
+import { WidgetType } from "./WidgetType";
+
+/**
+ * Widget data.
+ */
+export interface IWidgetData {
+ /**
+ * Optional title for the widget.
+ */
+ title?: string;
+
+ /**
+ * Custom keys for inclusion in the template URL.
+ */
+ [key: string]: unknown;
+}
+
+/**
+ * Common properties of a widget.
+ * https://matrix.org/docs/spec/widgets/latest#widgetcommonproperties-schema
+ */
+export interface IWidget {
+ /**
+ * The ID of the widget.
+ */
+ id: string;
+
+ /**
+ * The user ID who originally created the widget.
+ */
+ creatorUserId: string;
+
+ /**
+ * Optional name for the widget.
+ */
+ name?: string;
+
+ /**
+ * The type of widget.
+ */
+ type: WidgetType;
+
+ /**
+ * The URL for the widget, with template variables.
+ */
+ url: string;
+
+ /**
+ * Optional flag to indicate whether or not the client should initiate communication
+ * right after the iframe loads (default, true) or when the widget indicates it is
+ * ready (false).
+ */
+ waitForIframeLoad?: boolean;
+
+ /**
+ * Data for the widget.
+ */
+ data?: IWidgetData;
+}
diff --git a/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/IWidgetApiErrorResponse.ts b/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/IWidgetApiErrorResponse.ts
new file mode 100644
index 0000000..f9e123f
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/IWidgetApiErrorResponse.ts
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2020 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.
+ */
+
+import { IWidgetApiResponse, IWidgetApiResponseData } from "./IWidgetApiResponse";
+
+export interface IWidgetApiErrorResponseData extends IWidgetApiResponseData {
+ error: {
+ message: string;
+ };
+}
+
+export interface IWidgetApiErrorResponse extends IWidgetApiResponse {
+ response: IWidgetApiErrorResponseData;
+}
+
+export function isErrorResponse(responseData: IWidgetApiResponseData): boolean {
+ if ("error" in responseData) {
+ const err = <IWidgetApiErrorResponseData>responseData;
+ return !!err.error.message;
+ }
+ return false;
+}
diff --git a/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/IWidgetApiRequest.ts b/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/IWidgetApiRequest.ts
new file mode 100644
index 0000000..ec9e211
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/IWidgetApiRequest.ts
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2020 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.
+ */
+
+import { WidgetApiDirection } from "./WidgetApiDirection";
+import { WidgetApiAction } from "./WidgetApiAction";
+
+export interface IWidgetApiRequestData {
+ [key: string]: unknown;
+}
+
+export interface IWidgetApiRequestEmptyData extends IWidgetApiRequestData {
+ // nothing
+}
+
+export interface IWidgetApiRequest {
+ api: WidgetApiDirection;
+ requestId: string;
+ action: WidgetApiAction;
+ widgetId: string;
+ data: IWidgetApiRequestData;
+ // XXX: This is for Scalar support
+ // TODO: Fix scalar
+ visible?: any;
+}
diff --git a/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/IWidgetApiResponse.ts b/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/IWidgetApiResponse.ts
new file mode 100644
index 0000000..2347b6f
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/IWidgetApiResponse.ts
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2020 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.
+ */
+
+import { IWidgetApiRequest } from "./IWidgetApiRequest";
+
+export interface IWidgetApiResponseData {
+ [key: string]: unknown;
+}
+
+export interface IWidgetApiAcknowledgeResponseData extends IWidgetApiResponseData {
+ // nothing
+}
+
+export interface IWidgetApiResponse extends IWidgetApiRequest {
+ response: IWidgetApiResponseData;
+}
diff --git a/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/ModalButtonKind.ts b/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/ModalButtonKind.ts
new file mode 100644
index 0000000..e82c939
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/ModalButtonKind.ts
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2020 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.
+ */
+
+export enum ModalButtonKind {
+ Primary = "m.primary",
+ Secondary = "m.secondary",
+ Warning = "m.warning",
+ Danger = "m.danger",
+ Link = "m.link",
+}
diff --git a/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/ModalWidgetActions.ts b/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/ModalWidgetActions.ts
new file mode 100644
index 0000000..b8f07d4
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/ModalWidgetActions.ts
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2020 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.
+ */
+
+import { IWidgetApiRequest, IWidgetApiRequestData } from "./IWidgetApiRequest";
+import { WidgetApiFromWidgetAction, WidgetApiToWidgetAction } from "./WidgetApiAction";
+import { IWidgetApiAcknowledgeResponseData, IWidgetApiResponse } from "./IWidgetApiResponse";
+import { IWidget } from "./IWidget";
+import { ModalButtonKind } from "./ModalButtonKind";
+
+export enum BuiltInModalButtonID {
+ Close = "m.close",
+}
+export type ModalButtonID = BuiltInModalButtonID | string;
+
+export interface IModalWidgetCreateData extends IWidgetApiRequestData {
+ [key: string]: unknown;
+}
+
+export interface IModalWidgetReturnData {
+ [key: string]: unknown;
+}
+
+// Types for a normal modal requesting the opening a modal widget
+export interface IModalWidgetOpenRequestDataButton {
+ id: ModalButtonID;
+ label: string;
+ kind: ModalButtonKind | string;
+ disabled?: boolean;
+}
+
+export interface IModalWidgetOpenRequestData extends IModalWidgetCreateData, Omit<IWidget, "id" | "creatorUserId"> {
+ buttons?: IModalWidgetOpenRequestDataButton[];
+}
+
+export interface IModalWidgetOpenRequest extends IWidgetApiRequest {
+ action: WidgetApiFromWidgetAction.OpenModalWidget;
+ data: IModalWidgetOpenRequestData;
+}
+
+export interface IModalWidgetOpenResponse extends IWidgetApiResponse {
+ response: IWidgetApiAcknowledgeResponseData;
+}
+
+// Types for a modal widget receiving notifications that its buttons have been pressed
+export interface IModalWidgetButtonClickedRequestData extends IWidgetApiRequestData {
+ id: IModalWidgetOpenRequestDataButton["id"];
+}
+
+export interface IModalWidgetButtonClickedRequest extends IWidgetApiRequest {
+ action: WidgetApiToWidgetAction.ButtonClicked;
+ data: IModalWidgetButtonClickedRequestData;
+}
+
+export interface IModalWidgetButtonClickedResponse extends IWidgetApiResponse {
+ response: IWidgetApiAcknowledgeResponseData;
+}
+
+// Types for a modal widget requesting close
+export interface IModalWidgetCloseRequest extends IWidgetApiRequest {
+ action: WidgetApiFromWidgetAction.CloseModalWidget;
+ data: IModalWidgetReturnData;
+}
+
+export interface IModalWidgetCloseResponse extends IWidgetApiResponse {
+ response: IWidgetApiAcknowledgeResponseData;
+}
+
+// Types for a normal widget being notified that the modal widget it opened has been closed
+export interface IModalWidgetCloseNotificationRequest extends IWidgetApiRequest {
+ action: WidgetApiToWidgetAction.CloseModalWidget;
+ data: IModalWidgetReturnData;
+}
+
+export interface IModalWidgetCloseNotificationResponse extends IWidgetApiResponse {
+ response: IWidgetApiAcknowledgeResponseData;
+}
diff --git a/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/NavigateAction.ts b/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/NavigateAction.ts
new file mode 100644
index 0000000..04960eb
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/NavigateAction.ts
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2020 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.
+ */
+
+import { IWidgetApiRequest, IWidgetApiRequestData } from "./IWidgetApiRequest";
+import { WidgetApiFromWidgetAction } from "./WidgetApiAction";
+import { IWidgetApiAcknowledgeResponseData } from "./IWidgetApiResponse";
+
+export interface INavigateActionRequest extends IWidgetApiRequest {
+ action: WidgetApiFromWidgetAction.MSC2931Navigate;
+ data: INavigateActionRequestData;
+}
+
+export interface INavigateActionRequestData extends IWidgetApiRequestData {
+ uri: string;
+}
+
+export interface INavigateActionResponse extends INavigateActionRequest {
+ response: IWidgetApiAcknowledgeResponseData;
+}
diff --git a/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/OpenIDCredentialsAction.ts b/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/OpenIDCredentialsAction.ts
new file mode 100644
index 0000000..c4766f1
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/OpenIDCredentialsAction.ts
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2020 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.
+ */
+
+import { IWidgetApiRequest, IWidgetApiRequestData } from "./IWidgetApiRequest";
+import { WidgetApiToWidgetAction } from "./WidgetApiAction";
+import { IWidgetApiResponseData } from "./IWidgetApiResponse";
+import { IOpenIDCredentials, OpenIDRequestState } from "./GetOpenIDAction";
+
+export interface IOpenIDCredentialsActionRequestData extends IWidgetApiRequestData, IOpenIDCredentials {
+ state: OpenIDRequestState;
+ original_request_id: string; // eslint-disable-line camelcase
+}
+
+export interface IOpenIDCredentialsActionRequest extends IWidgetApiRequest {
+ action: WidgetApiToWidgetAction.OpenIDCredentials;
+ data: IOpenIDCredentialsActionRequestData;
+}
+
+export interface IOpenIDCredentialsActionResponseData extends IWidgetApiResponseData {
+ // nothing
+}
+
+export interface IOpenIDCredentialsIDActionResponse extends IOpenIDCredentialsActionRequest {
+ response: IOpenIDCredentialsActionResponseData;
+}
diff --git a/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/ReadEventAction.ts b/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/ReadEventAction.ts
new file mode 100644
index 0000000..8cea7cf
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/ReadEventAction.ts
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+
+import { IWidgetApiRequest, IWidgetApiRequestData } from "./IWidgetApiRequest";
+import { WidgetApiFromWidgetAction } from "./WidgetApiAction";
+import { IWidgetApiResponseData } from "./IWidgetApiResponse";
+import { IRoomEvent } from "./IRoomEvent";
+import { Symbols } from "../Symbols";
+
+export interface IReadEventFromWidgetRequestData extends IWidgetApiRequestData {
+ state_key?: string | boolean; // eslint-disable-line camelcase
+ msgtype?: string;
+ type: string;
+ limit?: number;
+ room_ids?: Symbols.AnyRoom | string[]; // eslint-disable-line camelcase
+}
+
+export interface IReadEventFromWidgetActionRequest extends IWidgetApiRequest {
+ action: WidgetApiFromWidgetAction.MSC2876ReadEvents;
+ data: IReadEventFromWidgetRequestData;
+}
+
+export interface IReadEventFromWidgetResponseData extends IWidgetApiResponseData {
+ events: IRoomEvent[];
+}
+
+export interface IReadEventFromWidgetActionResponse extends IReadEventFromWidgetActionRequest {
+ response: IReadEventFromWidgetResponseData;
+}
diff --git a/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/ReadRelationsAction.ts b/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/ReadRelationsAction.ts
new file mode 100644
index 0000000..76a041a
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/ReadRelationsAction.ts
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2022 Nordeck IT + Consulting GmbH.
+ *
+ * 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.
+ */
+
+import { IRoomEvent } from "./IRoomEvent";
+import { IWidgetApiRequest, IWidgetApiRequestData } from "./IWidgetApiRequest";
+import { IWidgetApiResponseData } from "./IWidgetApiResponse";
+import { WidgetApiFromWidgetAction } from "./WidgetApiAction";
+
+export interface IReadRelationsFromWidgetRequestData extends IWidgetApiRequestData {
+ event_id: string; // eslint-disable-line camelcase
+ rel_type?: string; // eslint-disable-line camelcase
+ event_type?: string; // eslint-disable-line camelcase
+ room_id?: string; // eslint-disable-line camelcase
+
+ limit?: number;
+ from?: string;
+ to?: string;
+ direction?: 'f' | 'b';
+}
+
+export interface IReadRelationsFromWidgetActionRequest extends IWidgetApiRequest {
+ action: WidgetApiFromWidgetAction.MSC3869ReadRelations;
+ data: IReadRelationsFromWidgetRequestData;
+}
+
+export interface IReadRelationsFromWidgetResponseData extends IWidgetApiResponseData {
+ chunk: IRoomEvent[];
+
+ next_batch?: string; // eslint-disable-line camelcase
+ prev_batch?: string; // eslint-disable-line camelcase
+}
+
+export interface IReadRelationsFromWidgetActionResponse extends IReadRelationsFromWidgetActionRequest {
+ response: IReadRelationsFromWidgetResponseData;
+}
diff --git a/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/ScreenshotAction.ts b/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/ScreenshotAction.ts
new file mode 100644
index 0000000..f9ec315
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/ScreenshotAction.ts
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2020 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.
+ */
+
+import { IWidgetApiRequest, IWidgetApiRequestEmptyData } from "./IWidgetApiRequest";
+import { WidgetApiToWidgetAction } from "./WidgetApiAction";
+import { IWidgetApiResponseData } from "./IWidgetApiResponse";
+
+export interface IScreenshotActionRequest extends IWidgetApiRequest {
+ action: WidgetApiToWidgetAction.TakeScreenshot;
+ data: IWidgetApiRequestEmptyData;
+}
+
+export interface IScreenshotActionResponseData extends IWidgetApiResponseData {
+ screenshot: Blob;
+}
+
+export interface IScreenshotActionResponse extends IScreenshotActionRequest {
+ response: IScreenshotActionResponseData;
+}
diff --git a/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/SendEventAction.ts b/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/SendEventAction.ts
new file mode 100644
index 0000000..8fe6da0
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/SendEventAction.ts
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2020 - 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.
+ */
+
+import { IWidgetApiRequest, IWidgetApiRequestData } from "./IWidgetApiRequest";
+import { WidgetApiFromWidgetAction, WidgetApiToWidgetAction } from "./WidgetApiAction";
+import { IWidgetApiResponseData } from "./IWidgetApiResponse";
+import { IRoomEvent } from "./IRoomEvent";
+
+export interface ISendEventFromWidgetRequestData extends IWidgetApiRequestData {
+ state_key?: string; // eslint-disable-line camelcase
+ type: string;
+ content: unknown;
+ room_id?: string; // eslint-disable-line camelcase
+}
+
+export interface ISendEventFromWidgetActionRequest extends IWidgetApiRequest {
+ action: WidgetApiFromWidgetAction.SendEvent;
+ data: ISendEventFromWidgetRequestData;
+}
+
+export interface ISendEventFromWidgetResponseData extends IWidgetApiResponseData {
+ room_id: string; // eslint-disable-line camelcase
+ event_id: string; // eslint-disable-line camelcase
+}
+
+export interface ISendEventFromWidgetActionResponse extends ISendEventFromWidgetActionRequest {
+ response: ISendEventFromWidgetResponseData;
+}
+
+export interface ISendEventToWidgetRequestData extends IWidgetApiRequestData, IRoomEvent {
+}
+
+export interface ISendEventToWidgetActionRequest extends IWidgetApiRequest {
+ action: WidgetApiToWidgetAction.SendEvent;
+ data: ISendEventToWidgetRequestData;
+}
+
+export interface ISendEventToWidgetResponseData extends IWidgetApiResponseData {
+ // nothing
+}
+
+export interface ISendEventToWidgetActionResponse extends ISendEventToWidgetActionRequest {
+ response: ISendEventToWidgetResponseData;
+}
diff --git a/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/SendToDeviceAction.ts b/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/SendToDeviceAction.ts
new file mode 100644
index 0000000..e7507b3
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/SendToDeviceAction.ts
@@ -0,0 +1,56 @@
+/*
+ * 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.
+ */
+
+import { IWidgetApiRequest, IWidgetApiRequestData } from "./IWidgetApiRequest";
+import { WidgetApiFromWidgetAction, WidgetApiToWidgetAction } from "./WidgetApiAction";
+import { IWidgetApiResponseData } from "./IWidgetApiResponse";
+import { IRoomEvent } from "./IRoomEvent";
+
+export interface ISendToDeviceFromWidgetRequestData extends IWidgetApiRequestData {
+ type: string;
+ encrypted: boolean;
+ messages: { [userId: string]: { [deviceId: string]: object } };
+}
+
+export interface ISendToDeviceFromWidgetActionRequest extends IWidgetApiRequest {
+ action: WidgetApiFromWidgetAction.SendToDevice;
+ data: ISendToDeviceFromWidgetRequestData;
+}
+
+export interface ISendToDeviceFromWidgetResponseData extends IWidgetApiResponseData {
+ // nothing
+}
+
+export interface ISendToDeviceFromWidgetActionResponse extends ISendToDeviceFromWidgetActionRequest {
+ response: ISendToDeviceFromWidgetResponseData;
+}
+
+export interface ISendToDeviceToWidgetRequestData extends IWidgetApiRequestData, IRoomEvent {
+ encrypted: boolean;
+}
+
+export interface ISendToDeviceToWidgetActionRequest extends IWidgetApiRequest {
+ action: WidgetApiToWidgetAction.SendToDevice;
+ data: ISendToDeviceToWidgetRequestData;
+}
+
+export interface ISendToDeviceToWidgetResponseData extends IWidgetApiResponseData {
+ // nothing
+}
+
+export interface ISendToDeviceToWidgetActionResponse extends ISendToDeviceToWidgetActionRequest {
+ response: ISendToDeviceToWidgetResponseData;
+}
diff --git a/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/SetModalButtonEnabledAction.ts b/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/SetModalButtonEnabledAction.ts
new file mode 100644
index 0000000..5702e8c
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/SetModalButtonEnabledAction.ts
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2020 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.
+ */
+
+import { IWidgetApiRequest, IWidgetApiRequestData } from "./IWidgetApiRequest";
+import { WidgetApiFromWidgetAction } from "./WidgetApiAction";
+import { IWidgetApiAcknowledgeResponseData } from "./IWidgetApiResponse";
+import { ModalButtonID } from "./ModalWidgetActions";
+
+export interface ISetModalButtonEnabledActionRequestData extends IWidgetApiRequestData {
+ enabled: boolean;
+ button: ModalButtonID;
+}
+
+export interface ISetModalButtonEnabledActionRequest extends IWidgetApiRequest {
+ action: WidgetApiFromWidgetAction.SetModalButtonEnabled;
+ data: ISetModalButtonEnabledActionRequestData;
+}
+
+export interface ISetModalButtonEnabledActionResponse extends ISetModalButtonEnabledActionRequest {
+ response: IWidgetApiAcknowledgeResponseData;
+}
diff --git a/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/StickerAction.ts b/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/StickerAction.ts
new file mode 100644
index 0000000..13cb94a
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/StickerAction.ts
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2020 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.
+ */
+
+import { IWidgetApiRequest, IWidgetApiRequestData } from "./IWidgetApiRequest";
+import { WidgetApiFromWidgetAction } from "./WidgetApiAction";
+import { IWidgetApiAcknowledgeResponseData } from "./IWidgetApiResponse";
+
+export interface IStickerActionRequestData extends IWidgetApiRequestData {
+ name: string;
+ description?: string;
+ content: {
+ url: string;
+ info?: {
+ h?: number;
+ w?: number;
+ mimetype?: string;
+ size?: number;
+ thumbnail_info?: { // eslint-disable-line camelcase
+ h?: number;
+ w?: number;
+ mimetype?: string;
+ size?: number;
+ };
+ };
+ };
+}
+
+export interface IStickerActionRequest extends IWidgetApiRequest {
+ action: WidgetApiFromWidgetAction.SendSticker;
+ data: IStickerActionRequestData;
+}
+
+export interface IStickerActionResponse extends IStickerActionRequest {
+ response: IWidgetApiAcknowledgeResponseData;
+}
diff --git a/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/StickyAction.ts b/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/StickyAction.ts
new file mode 100644
index 0000000..7d49f02
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/StickyAction.ts
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2020 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.
+ */
+
+import { IWidgetApiRequest, IWidgetApiRequestData } from "./IWidgetApiRequest";
+import { WidgetApiFromWidgetAction } from "./WidgetApiAction";
+import { IWidgetApiResponseData } from "./IWidgetApiResponse";
+
+export interface IStickyActionRequestData extends IWidgetApiRequestData {
+ value: boolean;
+}
+
+export interface IStickyActionRequest extends IWidgetApiRequest {
+ action: WidgetApiFromWidgetAction.UpdateAlwaysOnScreen;
+ data: IStickyActionRequestData;
+}
+
+export interface IStickyActionResponseData extends IWidgetApiResponseData {
+ success: boolean;
+}
+
+export interface IStickyActionResponse extends IStickyActionRequest {
+ response: IStickyActionResponseData;
+}
diff --git a/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/SupportedVersionsAction.ts b/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/SupportedVersionsAction.ts
new file mode 100644
index 0000000..8486ebc
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/SupportedVersionsAction.ts
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2020 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.
+ */
+
+import { IWidgetApiRequest, IWidgetApiRequestEmptyData } from "./IWidgetApiRequest";
+import { WidgetApiFromWidgetAction, WidgetApiToWidgetAction } from "./WidgetApiAction";
+import { ApiVersion } from "./ApiVersion";
+import { IWidgetApiResponseData } from "./IWidgetApiResponse";
+
+export interface ISupportedVersionsActionRequest extends IWidgetApiRequest {
+ action: WidgetApiFromWidgetAction.SupportedApiVersions | WidgetApiToWidgetAction.SupportedApiVersions;
+ data: IWidgetApiRequestEmptyData;
+}
+
+export interface ISupportedVersionsActionResponseData extends IWidgetApiResponseData {
+ supported_versions: ApiVersion[]; // eslint-disable-line camelcase
+}
+
+export interface ISupportedVersionsActionResponse extends ISupportedVersionsActionRequest {
+ response: ISupportedVersionsActionResponseData;
+}
diff --git a/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/TurnServerActions.ts b/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/TurnServerActions.ts
new file mode 100644
index 0000000..3a9bd29
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/TurnServerActions.ts
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ */
+
+import { IWidgetApiRequest, IWidgetApiRequestData, IWidgetApiRequestEmptyData } from "./IWidgetApiRequest";
+import { WidgetApiFromWidgetAction, WidgetApiToWidgetAction } from "./WidgetApiAction";
+import { IWidgetApiAcknowledgeResponseData, IWidgetApiResponse } from "./IWidgetApiResponse";
+
+export interface ITurnServer {
+ uris: string[];
+ username: string;
+ password: string;
+}
+
+export interface IWatchTurnServersRequest extends IWidgetApiRequest {
+ action: WidgetApiFromWidgetAction.WatchTurnServers;
+ data: IWidgetApiRequestEmptyData;
+}
+
+export interface IWatchTurnServersResponse extends IWidgetApiResponse {
+ response: IWidgetApiAcknowledgeResponseData;
+}
+
+export interface IUnwatchTurnServersRequest extends IWidgetApiRequest {
+ action: WidgetApiFromWidgetAction.UnwatchTurnServers;
+ data: IWidgetApiRequestEmptyData;
+}
+
+export interface IUnwatchTurnServersResponse extends IWidgetApiResponse {
+ response: IWidgetApiAcknowledgeResponseData;
+}
+
+export interface IUpdateTurnServersRequestData extends IWidgetApiRequestData, ITurnServer {
+}
+
+export interface IUpdateTurnServersRequest extends IWidgetApiRequest {
+ action: WidgetApiToWidgetAction.UpdateTurnServers;
+ data: IUpdateTurnServersRequestData;
+}
+
+export interface IUpdateTurnServersResponse extends IWidgetApiResponse {
+ response: IWidgetApiAcknowledgeResponseData;
+}
diff --git a/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/UserDirectorySearchAction.ts b/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/UserDirectorySearchAction.ts
new file mode 100644
index 0000000..fb900cc
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/UserDirectorySearchAction.ts
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2023 Nordeck IT + Consulting GmbH.
+ *
+ * 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.
+ */
+
+import { IWidgetApiRequest, IWidgetApiRequestData } from "./IWidgetApiRequest";
+import { IWidgetApiResponseData } from "./IWidgetApiResponse";
+import { WidgetApiFromWidgetAction } from "./WidgetApiAction";
+
+export interface IUserDirectorySearchFromWidgetRequestData extends IWidgetApiRequestData {
+ search_term: string; // eslint-disable-line camelcase
+ limit?: number;
+}
+
+export interface IUserDirectorySearchFromWidgetActionRequest extends IWidgetApiRequest {
+ action: WidgetApiFromWidgetAction.MSC3973UserDirectorySearch;
+ data: IUserDirectorySearchFromWidgetRequestData;
+}
+
+export interface IUserDirectorySearchFromWidgetResponseData extends IWidgetApiResponseData {
+ limited: boolean;
+ results: Array<{
+ user_id: string; // eslint-disable-line camelcase
+ display_name?: string; // eslint-disable-line camelcase
+ avatar_url?: string; // eslint-disable-line camelcase
+ }>;
+}
+
+export interface IUserDirectorySearchFromWidgetActionResponse extends IUserDirectorySearchFromWidgetActionRequest {
+ response: IUserDirectorySearchFromWidgetResponseData;
+}
diff --git a/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/VisibilityAction.ts b/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/VisibilityAction.ts
new file mode 100644
index 0000000..55aa53f
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/VisibilityAction.ts
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2020 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.
+ */
+
+import { IWidgetApiRequest, IWidgetApiRequestData } from "./IWidgetApiRequest";
+import { WidgetApiToWidgetAction } from "./WidgetApiAction";
+import { IWidgetApiAcknowledgeResponseData } from "./IWidgetApiResponse";
+
+export interface IVisibilityActionRequestData extends IWidgetApiRequestData {
+ visible: boolean;
+}
+
+export interface IVisibilityActionRequest extends IWidgetApiRequest {
+ action: WidgetApiToWidgetAction.UpdateVisibility;
+ data: IVisibilityActionRequestData;
+}
+
+export interface IVisibilityActionResponse extends IVisibilityActionRequest {
+ response: IWidgetApiAcknowledgeResponseData;
+}
diff --git a/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/WidgetApiAction.ts b/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/WidgetApiAction.ts
new file mode 100644
index 0000000..34c8aa3
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/WidgetApiAction.ts
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2020 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.
+ */
+
+export enum WidgetApiToWidgetAction {
+ SupportedApiVersions = "supported_api_versions",
+ Capabilities = "capabilities",
+ NotifyCapabilities = "notify_capabilities",
+ TakeScreenshot = "screenshot",
+ UpdateVisibility = "visibility",
+ OpenIDCredentials = "openid_credentials",
+ WidgetConfig = "widget_config",
+ CloseModalWidget = "close_modal",
+ ButtonClicked = "button_clicked",
+ SendEvent = "send_event",
+ SendToDevice = "send_to_device",
+ UpdateTurnServers = "update_turn_servers",
+}
+
+export enum WidgetApiFromWidgetAction {
+ SupportedApiVersions = "supported_api_versions",
+ ContentLoaded = "content_loaded",
+ SendSticker = "m.sticker",
+ UpdateAlwaysOnScreen = "set_always_on_screen",
+ GetOpenIDCredentials = "get_openid",
+ CloseModalWidget = "close_modal",
+ OpenModalWidget = "open_modal",
+ SetModalButtonEnabled = "set_button_enabled",
+ SendEvent = "send_event",
+ SendToDevice = "send_to_device",
+ WatchTurnServers = "watch_turn_servers",
+ UnwatchTurnServers = "unwatch_turn_servers",
+
+ /**
+ * @deprecated It is not recommended to rely on this existing - it can be removed without notice.
+ */
+ MSC2876ReadEvents = "org.matrix.msc2876.read_events",
+
+ /**
+ * @deprecated It is not recommended to rely on this existing - it can be removed without notice.
+ */
+ MSC2931Navigate = "org.matrix.msc2931.navigate",
+
+ /**
+ * @deprecated It is not recommended to rely on this existing - it can be removed without notice.
+ */
+ MSC2974RenegotiateCapabilities = "org.matrix.msc2974.request_capabilities",
+
+ /**
+ * @deprecated It is not recommended to rely on this existing - it can be removed without notice.
+ */
+ MSC3869ReadRelations = "org.matrix.msc3869.read_relations",
+
+ /**
+ * @deprecated It is not recommended to rely on this existing - it can be removed without notice.
+ */
+ MSC3973UserDirectorySearch = "org.matrix.msc3973.user_directory_search",
+}
+
+export type WidgetApiAction = WidgetApiToWidgetAction | WidgetApiFromWidgetAction | string;
diff --git a/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/WidgetApiDirection.ts b/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/WidgetApiDirection.ts
new file mode 100644
index 0000000..e11e144
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/WidgetApiDirection.ts
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2020 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.
+ */
+
+export enum WidgetApiDirection {
+ ToWidget = "toWidget",
+ FromWidget = "fromWidget",
+}
+
+export function invertedDirection(dir: WidgetApiDirection): WidgetApiDirection {
+ if (dir === WidgetApiDirection.ToWidget) {
+ return WidgetApiDirection.FromWidget;
+ } else if (dir === WidgetApiDirection.FromWidget) {
+ return WidgetApiDirection.ToWidget;
+ } else {
+ throw new Error("Invalid direction");
+ }
+}
diff --git a/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/WidgetConfigAction.ts b/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/WidgetConfigAction.ts
new file mode 100644
index 0000000..b10314c
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/WidgetConfigAction.ts
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2020 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.
+ */
+
+import { IWidgetApiRequest } from "./IWidgetApiRequest";
+import { WidgetApiToWidgetAction } from "./WidgetApiAction";
+import { IWidgetApiAcknowledgeResponseData, IWidgetApiResponse } from "./IWidgetApiResponse";
+import { IModalWidgetOpenRequestData } from "./ModalWidgetActions";
+
+export interface IWidgetConfigRequest extends IWidgetApiRequest {
+ action: WidgetApiToWidgetAction.WidgetConfig;
+ data: IModalWidgetOpenRequestData;
+}
+
+export interface IWidgetConfigResponse extends IWidgetApiResponse {
+ response: IWidgetApiAcknowledgeResponseData;
+}
diff --git a/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/WidgetKind.ts b/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/WidgetKind.ts
new file mode 100644
index 0000000..374e198
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/WidgetKind.ts
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2020 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.
+ */
+
+export enum WidgetKind {
+ Room = "room",
+ Account = "account",
+ Modal = "modal",
+}
diff --git a/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/WidgetType.ts b/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/WidgetType.ts
new file mode 100644
index 0000000..d6b3e33
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-widget-api/src/interfaces/WidgetType.ts
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2020 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.
+ */
+
+export enum MatrixWidgetType {
+ Custom = "m.custom",
+ JitsiMeet = "m.jitsi",
+ Stickerpicker = "m.stickerpicker",
+}
+
+export type WidgetType = MatrixWidgetType | string;
diff --git a/includes/external/matrix/node_modules/matrix-widget-api/src/models/Widget.ts b/includes/external/matrix/node_modules/matrix-widget-api/src/models/Widget.ts
new file mode 100644
index 0000000..0b66452
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-widget-api/src/models/Widget.ts
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2020 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.
+ */
+
+import { IWidget, IWidgetData, WidgetType } from "..";
+import { assertPresent } from "./validation/utils";
+import { ITemplateParams, runTemplate } from "..";
+
+/**
+ * Represents the barest form of widget.
+ */
+export class Widget {
+ public constructor(private definition: IWidget) {
+ if (!this.definition) throw new Error("Definition is required");
+
+ assertPresent(definition, "id");
+ assertPresent(definition, "creatorUserId");
+ assertPresent(definition, "type");
+ assertPresent(definition, "url");
+ }
+
+ /**
+ * The user ID who created the widget.
+ */
+ public get creatorUserId(): string {
+ return this.definition.creatorUserId;
+ }
+
+ /**
+ * The type of widget.
+ */
+ public get type(): WidgetType {
+ return this.definition.type;
+ }
+
+ /**
+ * The ID of the widget.
+ */
+ public get id(): string {
+ return this.definition.id;
+ }
+
+ /**
+ * The name of the widget, or null if not set.
+ */
+ public get name(): string | null {
+ return this.definition.name || null;
+ }
+
+ /**
+ * The title for the widget, or null if not set.
+ */
+ public get title(): string | null {
+ return this.rawData.title || null;
+ }
+
+ /**
+ * The templated URL for the widget.
+ */
+ public get templateUrl(): string {
+ return this.definition.url;
+ }
+
+ /**
+ * The origin for this widget.
+ */
+ public get origin(): string {
+ return new URL(this.templateUrl).origin;
+ }
+
+ /**
+ * Whether or not the client should wait for the iframe to load. Defaults
+ * to true.
+ */
+ public get waitForIframeLoad(): boolean {
+ if (this.definition.waitForIframeLoad === false) return false;
+ if (this.definition.waitForIframeLoad === true) return true;
+ return true; // default true
+ }
+
+ /**
+ * The raw data for the widget. This will always be defined, though
+ * may be empty.
+ */
+ public get rawData(): IWidgetData {
+ return this.definition.data || {};
+ }
+
+ /**
+ * Gets a complete widget URL for the client to render.
+ * @param {ITemplateParams} params The template parameters.
+ * @returns {string} A templated URL.
+ */
+ public getCompleteUrl(params: ITemplateParams): string {
+ return runTemplate(this.templateUrl, this.definition, params);
+ }
+}
diff --git a/includes/external/matrix/node_modules/matrix-widget-api/src/models/WidgetEventCapability.ts b/includes/external/matrix/node_modules/matrix-widget-api/src/models/WidgetEventCapability.ts
new file mode 100644
index 0000000..16d933e
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-widget-api/src/models/WidgetEventCapability.ts
@@ -0,0 +1,204 @@
+/*
+ * Copyright 2020 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.
+ */
+
+import { Capability } from "..";
+
+export enum EventKind {
+ Event = "event",
+ State = "state_event",
+ ToDevice = "to_device",
+}
+
+export enum EventDirection {
+ Send = "send",
+ Receive = "receive",
+}
+
+export class WidgetEventCapability {
+ private constructor(
+ public readonly direction: EventDirection,
+ public readonly eventType: string,
+ public readonly kind: EventKind,
+ public readonly keyStr: string | null,
+ public readonly raw: string,
+ ) {
+ }
+
+ public matchesAsStateEvent(direction: EventDirection, eventType: string, stateKey: string | null): boolean {
+ if (this.kind !== EventKind.State) return false; // not a state event
+ if (this.direction !== direction) return false; // direction mismatch
+ if (this.eventType !== eventType) return false; // event type mismatch
+ if (this.keyStr === null) return true; // all state keys are allowed
+ if (this.keyStr === stateKey) return true; // this state key is allowed
+
+ // Default not allowed
+ return false;
+ }
+
+ public matchesAsToDeviceEvent(direction: EventDirection, eventType: string): boolean {
+ if (this.kind !== EventKind.ToDevice) return false; // not a to-device event
+ if (this.direction !== direction) return false; // direction mismatch
+ if (this.eventType !== eventType) return false; // event type mismatch
+
+ // Checks passed, the event is allowed
+ return true;
+ }
+
+ public matchesAsRoomEvent(direction: EventDirection, eventType: string, msgtype: string | null = null): boolean {
+ if (this.kind !== EventKind.Event) return false; // not a room event
+ if (this.direction !== direction) return false; // direction mismatch
+ if (this.eventType !== eventType) return false; // event type mismatch
+
+ if (this.eventType === "m.room.message") {
+ if (this.keyStr === null) return true; // all message types are allowed
+ if (this.keyStr === msgtype) return true; // this message type is allowed
+ } else {
+ return true; // already passed the check for if the event is allowed
+ }
+
+ // Default not allowed
+ return false;
+ }
+
+ public static forStateEvent(
+ direction: EventDirection,
+ eventType: string,
+ stateKey?: string,
+ ): WidgetEventCapability {
+ // TODO: Enable support for m.* namespace once the MSC lands.
+ // https://github.com/matrix-org/matrix-widget-api/issues/22
+ eventType = eventType.replace(/#/g, '\\#');
+ stateKey = stateKey !== null && stateKey !== undefined ? `#${stateKey}` : '';
+ const str = `org.matrix.msc2762.${direction}.state_event:${eventType}${stateKey}`;
+
+ // cheat by sending it through the processor
+ return WidgetEventCapability.findEventCapabilities([str])[0];
+ }
+
+ public static forToDeviceEvent(direction: EventDirection, eventType: string): WidgetEventCapability {
+ // TODO: Enable support for m.* namespace once the MSC lands.
+ // https://github.com/matrix-org/matrix-widget-api/issues/56
+ const str = `org.matrix.msc3819.${direction}.to_device:${eventType}`;
+
+ // cheat by sending it through the processor
+ return WidgetEventCapability.findEventCapabilities([str])[0];
+ }
+
+ public static forRoomEvent(direction: EventDirection, eventType: string): WidgetEventCapability {
+ // TODO: Enable support for m.* namespace once the MSC lands.
+ // https://github.com/matrix-org/matrix-widget-api/issues/22
+ const str = `org.matrix.msc2762.${direction}.event:${eventType}`;
+
+ // cheat by sending it through the processor
+ return WidgetEventCapability.findEventCapabilities([str])[0];
+ }
+
+ public static forRoomMessageEvent(direction: EventDirection, msgtype?: string): WidgetEventCapability {
+ // TODO: Enable support for m.* namespace once the MSC lands.
+ // https://github.com/matrix-org/matrix-widget-api/issues/22
+ msgtype = msgtype === null || msgtype === undefined ? '' : msgtype;
+ const str = `org.matrix.msc2762.${direction}.event:m.room.message#${msgtype}`;
+
+ // cheat by sending it through the processor
+ return WidgetEventCapability.findEventCapabilities([str])[0];
+ }
+
+ /**
+ * Parses a capabilities request to find all the event capability requests.
+ * @param {Iterable<Capability>} capabilities The capabilities requested/to parse.
+ * @returns {WidgetEventCapability[]} An array of event capability requests. May be empty, but never null.
+ */
+ public static findEventCapabilities(capabilities: Iterable<Capability>): WidgetEventCapability[] {
+ const parsed: WidgetEventCapability[] = [];
+ for (const cap of capabilities) {
+ let direction: EventDirection | null = null;
+ let eventSegment: string | undefined;
+ let kind: EventKind | null = null;
+
+ // TODO: Enable support for m.* namespace once the MSCs land.
+ // https://github.com/matrix-org/matrix-widget-api/issues/22
+ // https://github.com/matrix-org/matrix-widget-api/issues/56
+
+ if (cap.startsWith("org.matrix.msc2762.send.event:")) {
+ direction = EventDirection.Send;
+ kind = EventKind.Event;
+ eventSegment = cap.substring("org.matrix.msc2762.send.event:".length);
+ } else if (cap.startsWith("org.matrix.msc2762.send.state_event:")) {
+ direction = EventDirection.Send;
+ kind = EventKind.State;
+ eventSegment = cap.substring("org.matrix.msc2762.send.state_event:".length);
+ } else if (cap.startsWith("org.matrix.msc3819.send.to_device:")) {
+ direction = EventDirection.Send;
+ kind = EventKind.ToDevice;
+ eventSegment = cap.substring("org.matrix.msc3819.send.to_device:".length);
+ } else if (cap.startsWith("org.matrix.msc2762.receive.event:")) {
+ direction = EventDirection.Receive;
+ kind = EventKind.Event;
+ eventSegment = cap.substring("org.matrix.msc2762.receive.event:".length);
+ } else if (cap.startsWith("org.matrix.msc2762.receive.state_event:")) {
+ direction = EventDirection.Receive;
+ kind = EventKind.State;
+ eventSegment = cap.substring("org.matrix.msc2762.receive.state_event:".length);
+ } else if (cap.startsWith("org.matrix.msc3819.receive.to_device:")) {
+ direction = EventDirection.Receive;
+ kind = EventKind.ToDevice;
+ eventSegment = cap.substring("org.matrix.msc3819.receive.to_device:".length);
+ }
+
+ if (direction === null || kind === null || eventSegment === undefined) continue;
+
+ // The capability uses `#` as a separator between event type and state key/msgtype,
+ // so we split on that. However, a # is also valid in either one of those so we
+ // join accordingly.
+ // Eg: `m.room.message##m.text` is "m.room.message" event with msgtype "#m.text".
+ const expectingKeyStr = eventSegment.startsWith("m.room.message#") || kind === EventKind.State;
+ let keyStr: string | null = null;
+ if (eventSegment.includes('#') && expectingKeyStr) {
+ // Dev note: regex is difficult to write, so instead the rules are manually written
+ // out. This is probably just as understandable as a boring regex though, so win-win?
+
+ // Test cases:
+ // str eventSegment keyStr
+ // -------------------------------------------------------------
+ // m.room.message# m.room.message <empty string>
+ // m.room.message#test m.room.message test
+ // m.room.message\# m.room.message# test
+ // m.room.message##test m.room.message #test
+ // m.room.message\##test m.room.message# test
+ // m.room.message\\##test m.room.message\# test
+ // m.room.message\\###test m.room.message\# #test
+
+ // First step: explode the string
+ const parts = eventSegment.split('#');
+
+ // To form the eventSegment, we'll keep finding parts of the exploded string until
+ // there's one that doesn't end with the escape character (\). We'll then join those
+ // segments together with the exploding character. We have to remember to consume the
+ // escape character as well.
+ const idx = parts.findIndex(p => !p.endsWith("\\"));
+ eventSegment = parts.slice(0, idx + 1)
+ .map(p => p.endsWith('\\') ? p.substring(0, p.length - 1) : p)
+ .join('#');
+
+ // The keyStr is whatever is left over.
+ keyStr = parts.slice(idx + 1).join('#');
+ }
+
+ parsed.push(new WidgetEventCapability(direction, eventSegment, kind, keyStr, cap));
+ }
+ return parsed;
+ }
+}
diff --git a/includes/external/matrix/node_modules/matrix-widget-api/src/models/WidgetParser.ts b/includes/external/matrix/node_modules/matrix-widget-api/src/models/WidgetParser.ts
new file mode 100644
index 0000000..f93c077
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-widget-api/src/models/WidgetParser.ts
@@ -0,0 +1,147 @@
+/*
+ * Copyright 2020 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.
+ */
+
+import { Widget } from "./Widget";
+import { IWidget } from "..";
+import { isValidUrl } from "./validation/url";
+
+export interface IStateEvent {
+ event_id: string; // eslint-disable-line camelcase
+ room_id: string; // eslint-disable-line camelcase
+ type: string;
+ sender: string;
+ origin_server_ts: number; // eslint-disable-line camelcase
+ unsigned?: unknown;
+ content: unknown;
+ state_key: string; // eslint-disable-line camelcase
+}
+
+export interface IAccountDataWidgets {
+ [widgetId: string]: {
+ type: "m.widget";
+ // the state_key is also the widget's ID
+ state_key: string; // eslint-disable-line camelcase
+ sender: string; // current user's ID
+ content: IWidget;
+ id?: string; // off-spec, but possible
+ };
+}
+
+export class WidgetParser {
+ private constructor() {
+ // private constructor because this is a util class
+ }
+
+ /**
+ * Parses widgets from the "m.widgets" account data event. This will always
+ * return an array, though may be empty if no valid widgets were found.
+ * @param {IAccountDataWidgets} content The content of the "m.widgets" account data.
+ * @returns {Widget[]} The widgets in account data, or an empty array.
+ */
+ public static parseAccountData(content: IAccountDataWidgets): Widget[] {
+ if (!content) return [];
+
+ const result: Widget[] = [];
+ for (const widgetId of Object.keys(content)) {
+ const roughWidget = content[widgetId];
+ if (!roughWidget) continue;
+ if (roughWidget.type !== "m.widget" && roughWidget.type !== "im.vector.modular.widgets") continue;
+ if (!roughWidget.sender) continue;
+
+ const probableWidgetId = roughWidget.state_key || roughWidget.id;
+ if (probableWidgetId !== widgetId) continue;
+
+ const asStateEvent: IStateEvent = {
+ content: roughWidget.content,
+ sender: roughWidget.sender,
+ type: "m.widget",
+ state_key: widgetId,
+ event_id: "$example",
+ room_id: "!example",
+ origin_server_ts: 1,
+ };
+
+ const widget = WidgetParser.parseRoomWidget(asStateEvent);
+ if (widget) result.push(widget);
+ }
+
+ return result;
+ }
+
+ /**
+ * Parses all the widgets possible in the given array. This will always return
+ * an array, though may be empty if no widgets could be parsed.
+ * @param {IStateEvent[]} currentState The room state to parse.
+ * @returns {Widget[]} The widgets in the state, or an empty array.
+ */
+ public static parseWidgetsFromRoomState(currentState: IStateEvent[]): Widget[] {
+ if (!currentState) return [];
+ const result: Widget[] = [];
+ for (const state of currentState) {
+ const widget = WidgetParser.parseRoomWidget(state);
+ if (widget) result.push(widget);
+ }
+ return result;
+ }
+
+ /**
+ * Parses a state event into a widget. If the state event does not represent
+ * a widget (wrong event type, invalid widget, etc) then null is returned.
+ * @param {IStateEvent} stateEvent The state event.
+ * @returns {Widget|null} The widget, or null if invalid
+ */
+ public static parseRoomWidget(stateEvent: IStateEvent): Widget | null {
+ if (!stateEvent) return null;
+
+ // TODO: [Legacy] Remove legacy support
+ if (stateEvent.type !== "m.widget" && stateEvent.type !== "im.vector.modular.widgets") {
+ return null;
+ }
+
+ // Dev note: Throughout this function we have null safety to ensure that
+ // if the caller did not supply something useful that we don't error. This
+ // is done against the requirements of the interface because not everyone
+ // will have an interface to validate against.
+
+ const content = stateEvent.content as IWidget || {};
+
+ // Form our best approximation of a widget with the information we have
+ const estimatedWidget: IWidget = {
+ id: stateEvent.state_key,
+ creatorUserId: content['creatorUserId'] || stateEvent.sender,
+ name: content['name'],
+ type: content['type'],
+ url: content['url'],
+ waitForIframeLoad: content['waitForIframeLoad'],
+ data: content['data'],
+ };
+
+ // Finally, process that widget
+ return WidgetParser.processEstimatedWidget(estimatedWidget);
+ }
+
+ private static processEstimatedWidget(widget: IWidget): Widget | null {
+ // Validate that the widget has the best chance of passing as a widget
+ if (!widget.id || !widget.creatorUserId || !widget.type) {
+ return null;
+ }
+ if (!isValidUrl(widget.url)) {
+ return null;
+ }
+ // TODO: Validate data for known widget types
+ return new Widget(widget);
+ }
+}
diff --git a/includes/external/matrix/node_modules/matrix-widget-api/src/models/validation/url.ts b/includes/external/matrix/node_modules/matrix-widget-api/src/models/validation/url.ts
new file mode 100644
index 0000000..c56a9c6
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-widget-api/src/models/validation/url.ts
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2020 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.
+ */
+
+export function isValidUrl(val: string): boolean {
+ if (!val) return false; // easy: not valid if not present
+
+ try {
+ const parsed = new URL(val);
+ if (parsed.protocol !== "http" && parsed.protocol !== "https") {
+ return false;
+ }
+ return true;
+ } catch (e) {
+ if (e instanceof TypeError) {
+ return false;
+ }
+ throw e;
+ }
+}
diff --git a/includes/external/matrix/node_modules/matrix-widget-api/src/models/validation/utils.ts b/includes/external/matrix/node_modules/matrix-widget-api/src/models/validation/utils.ts
new file mode 100644
index 0000000..b9c8761
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-widget-api/src/models/validation/utils.ts
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2020 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.
+ */
+
+export function assertPresent<O>(obj: O, key: keyof O) {
+ if (!obj[key]) {
+ throw new Error(`${key} is required`);
+ }
+}
diff --git a/includes/external/matrix/node_modules/matrix-widget-api/src/templating/url-template.ts b/includes/external/matrix/node_modules/matrix-widget-api/src/templating/url-template.ts
new file mode 100644
index 0000000..901f131
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-widget-api/src/templating/url-template.ts
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2020, 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.
+ */
+
+import { IWidget } from "..";
+
+export interface ITemplateParams {
+ widgetRoomId?: string;
+ currentUserId: string;
+ userDisplayName?: string;
+ userHttpAvatarUrl?: string;
+ clientId?: string;
+ clientTheme?: string;
+ clientLanguage?: string;
+}
+
+export function runTemplate(url: string, widget: IWidget, params: ITemplateParams): string {
+ // Always apply the supplied params over top of data to ensure the data can't lie about them.
+ const variables = Object.assign({}, widget.data, {
+ 'matrix_room_id': params.widgetRoomId || "",
+ 'matrix_user_id': params.currentUserId,
+ 'matrix_display_name': params.userDisplayName || params.currentUserId,
+ 'matrix_avatar_url': params.userHttpAvatarUrl || "",
+ 'matrix_widget_id': widget.id,
+
+ // TODO: Convert to stable (https://github.com/matrix-org/matrix-doc/pull/2873)
+ 'org.matrix.msc2873.client_id': params.clientId || "",
+ 'org.matrix.msc2873.client_theme': params.clientTheme || "",
+ 'org.matrix.msc2873.client_language': params.clientLanguage || "",
+ });
+ let result = url;
+ for (const key of Object.keys(variables)) {
+ // Regex escape from https://stackoverflow.com/a/6969486/7037379
+ const pattern = `$${key}`.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string
+ const rexp = new RegExp(pattern, 'g');
+
+ // This is technically not what we're supposed to do for a couple of reasons:
+ // 1. We are assuming that there won't later be a $key match after we replace a variable.
+ // 2. We are assuming that the variable is in a place where it can be escaped (eg: path or query string).
+ result = result.replace(rexp, encodeURIComponent(toString(variables[key])));
+ }
+ return result;
+}
+
+export function toString(a: unknown): string {
+ if (a === null || a === undefined) {
+ return `${a}`;
+ }
+ return String(a);
+}
diff --git a/includes/external/matrix/node_modules/matrix-widget-api/src/transport/ITransport.ts b/includes/external/matrix/node_modules/matrix-widget-api/src/transport/ITransport.ts
new file mode 100644
index 0000000..b3b2e9a
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-widget-api/src/transport/ITransport.ts
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2020 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.
+ */
+
+import { EventEmitter } from "events";
+import {
+ IWidgetApiAcknowledgeResponseData,
+ IWidgetApiRequest,
+ IWidgetApiRequestData,
+ IWidgetApiResponse,
+ IWidgetApiResponseData,
+ WidgetApiAction,
+} from "..";
+
+/**
+ * A transport for widget requests/responses. All actions
+ * get raised through a "message" CustomEvent with detail
+ * of the IWidgetApiRequest.
+ */
+export interface ITransport extends EventEmitter {
+ /**
+ * True if the transport is ready to start sending, false otherwise.
+ */
+ readonly ready: boolean;
+
+ /**
+ * The widget ID, if known. If not known, null.
+ */
+ readonly widgetId: string | null;
+
+ /**
+ * If true, the transport will refuse requests from origins other than the
+ * widget's current origin. This is intended to be used only by widgets which
+ * need excess security.
+ */
+ strictOriginCheck: boolean;
+
+ /**
+ * The origin the transport should be replying/sending to. If not known, leave
+ * null.
+ */
+ targetOrigin: string | null;
+
+ /**
+ * The number of seconds an outbound request is allowed to take before it
+ * times out.
+ */
+ timeoutSeconds: number;
+
+ /**
+ * Starts the transport for listening
+ */
+ start(): void;
+
+ /**
+ * Stops the transport. It cannot be re-started.
+ */
+ stop(): void;
+
+ /**
+ * Sends a request to the remote end.
+ * @param {WidgetApiAction} action The action to send.
+ * @param {IWidgetApiRequestData} data The request data.
+ * @returns {Promise<IWidgetApiResponseData>} A promise which resolves
+ * to the remote end's response, or throws with an Error if the request
+ * failed.
+ */
+ send<T extends IWidgetApiRequestData, R extends IWidgetApiResponseData = IWidgetApiAcknowledgeResponseData>(
+ action: WidgetApiAction,
+ data: T
+ ): Promise<R>;
+
+ /**
+ * Sends a request to the remote end. This is similar to the send() function
+ * however this version returns the full response rather than just the response
+ * data.
+ * @param {WidgetApiAction} action The action to send.
+ * @param {IWidgetApiRequestData} data The request data.
+ * @returns {Promise<IWidgetApiResponseData>} A promise which resolves
+ * to the remote end's response, or throws with an Error if the request
+ * failed.
+ */
+ sendComplete<T extends IWidgetApiRequestData, R extends IWidgetApiResponse>(action: WidgetApiAction, data: T)
+ : Promise<R>;
+
+ /**
+ * Replies to a request.
+ * @param {IWidgetApiRequest} request The request to reply to.
+ * @param {IWidgetApiResponseData} responseData The response data to reply with.
+ */
+ reply<T extends IWidgetApiResponseData>(request: IWidgetApiRequest, responseData: T): void;
+}
diff --git a/includes/external/matrix/node_modules/matrix-widget-api/src/transport/PostmessageTransport.ts b/includes/external/matrix/node_modules/matrix-widget-api/src/transport/PostmessageTransport.ts
new file mode 100644
index 0000000..9f86aa5
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-widget-api/src/transport/PostmessageTransport.ts
@@ -0,0 +1,203 @@
+/*
+ * Copyright 2020 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.
+ */
+
+import { EventEmitter } from "events";
+import { ITransport } from "./ITransport";
+import {
+ invertedDirection,
+ isErrorResponse,
+ IWidgetApiErrorResponseData,
+ IWidgetApiRequest,
+ IWidgetApiRequestData,
+ IWidgetApiResponse,
+ IWidgetApiResponseData,
+ WidgetApiAction,
+ WidgetApiDirection,
+ WidgetApiToWidgetAction,
+} from "..";
+
+interface IOutboundRequest {
+ request: IWidgetApiRequest;
+ resolve: (response: IWidgetApiResponse) => void;
+ reject: (err: Error) => void;
+}
+
+/**
+ * Transport for the Widget API over postMessage.
+ */
+export class PostmessageTransport extends EventEmitter implements ITransport {
+ public strictOriginCheck = false;
+ public targetOrigin = "*";
+ public timeoutSeconds = 10;
+
+ private _ready = false;
+ private _widgetId: string | null = null;
+ private outboundRequests = new Map<string, IOutboundRequest | null>();
+ private stopController = new AbortController();
+
+ public get ready(): boolean {
+ return this._ready;
+ }
+
+ public get widgetId(): string | null {
+ return this._widgetId || null;
+ }
+
+ public constructor(
+ private sendDirection: WidgetApiDirection,
+ private initialWidgetId: string | null,
+ private transportWindow: Window,
+ private inboundWindow: Window,
+ ) {
+ super();
+ this._widgetId = initialWidgetId;
+ }
+
+ private get nextRequestId(): string {
+ const idBase = `widgetapi-${Date.now()}`;
+ let index = 0;
+ let id = idBase;
+ while (this.outboundRequests.has(id)) {
+ id = `${idBase}-${index++}`;
+ }
+
+ // reserve the ID
+ this.outboundRequests.set(id, null);
+
+ return id;
+ }
+
+ private sendInternal(message: IWidgetApiRequest | IWidgetApiResponse) {
+ console.log(`[PostmessageTransport] Sending object to ${this.targetOrigin}: `, message);
+ this.transportWindow.postMessage(message, this.targetOrigin);
+ }
+
+ public reply<T extends IWidgetApiResponseData>(request: IWidgetApiRequest, responseData: T) {
+ return this.sendInternal(<IWidgetApiResponse>{
+ ...request,
+ response: responseData,
+ });
+ }
+
+ public send<T extends IWidgetApiRequestData, R extends IWidgetApiResponseData>(
+ action: WidgetApiAction, data: T,
+ ): Promise<R> {
+ return this.sendComplete(action, data).then(r => <R>r.response);
+ }
+
+ public sendComplete<T extends IWidgetApiRequestData, R extends IWidgetApiResponse>(
+ action: WidgetApiAction, data: T,
+ ): Promise<R> {
+ if (!this.ready || !this.widgetId) {
+ return Promise.reject(new Error("Not ready or unknown widget ID"));
+ }
+ const request: IWidgetApiRequest = {
+ api: this.sendDirection,
+ widgetId: this.widgetId,
+ requestId: this.nextRequestId,
+ action: action,
+ data: data,
+ };
+ if (action === WidgetApiToWidgetAction.UpdateVisibility) {
+ request['visible'] = data['visible'];
+ }
+ return new Promise<R>((prResolve, prReject) => {
+ const resolve = (response: IWidgetApiResponse) => {
+ cleanUp();
+ prResolve(<R>response);
+ };
+ const reject = (err: Error) => {
+ cleanUp();
+ prReject(err);
+ };
+
+ const timerId = setTimeout(
+ () => reject(new Error("Request timed out")),
+ (this.timeoutSeconds || 1) * 1000,
+ );
+
+ const onStop = () => reject(new Error("Transport stopped"));
+ this.stopController.signal.addEventListener("abort", onStop);
+
+ const cleanUp = () => {
+ this.outboundRequests.delete(request.requestId);
+ clearTimeout(timerId);
+ this.stopController.signal.removeEventListener("abort", onStop);
+ };
+
+ this.outboundRequests.set(request.requestId, { request, resolve, reject });
+ this.sendInternal(request);
+ });
+ }
+
+ public start() {
+ this.inboundWindow.addEventListener("message", (ev: MessageEvent) => {
+ this.handleMessage(ev);
+ });
+ this._ready = true;
+ }
+
+ public stop() {
+ this._ready = false;
+ this.stopController.abort();
+ }
+
+ private handleMessage(ev: MessageEvent) {
+ if (this.stopController.signal.aborted) return;
+ if (!ev.data) return; // invalid event
+
+ if (this.strictOriginCheck && ev.origin !== window.origin) return; // bad origin
+
+ // treat the message as a response first, then downgrade to a request
+ const response = <IWidgetApiResponse>ev.data;
+ if (!response.action || !response.requestId || !response.widgetId) return; // invalid request/response
+
+ if (!response.response) {
+ // it's a request
+ const request = <IWidgetApiRequest>response;
+ if (request.api !== invertedDirection(this.sendDirection)) return; // wrong direction
+ this.handleRequest(request);
+ } else {
+ // it's a response
+ if (response.api !== this.sendDirection) return; // wrong direction
+ this.handleResponse(response);
+ }
+ }
+
+ private handleRequest(request: IWidgetApiRequest) {
+ if (this.widgetId) {
+ if (this.widgetId !== request.widgetId) return; // wrong widget
+ } else {
+ this._widgetId = request.widgetId;
+ }
+
+ this.emit("message", new CustomEvent("message", {detail: request}));
+ }
+
+ private handleResponse(response: IWidgetApiResponse) {
+ if (response.widgetId !== this.widgetId) return; // wrong widget
+
+ const req = this.outboundRequests.get(response.requestId);
+ if (!req) return; // response to an unknown request
+
+ if (isErrorResponse(response.response)) {
+ const err = <IWidgetApiErrorResponseData>response.response;
+ req.reject(new Error(err.error.message));
+ } else {
+ req.resolve(response);
+ }
+ }
+}
diff --git a/includes/external/matrix/node_modules/matrix-widget-api/src/util/SimpleObservable.ts b/includes/external/matrix/node_modules/matrix-widget-api/src/util/SimpleObservable.ts
new file mode 100644
index 0000000..77b2080
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-widget-api/src/util/SimpleObservable.ts
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2020 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.
+ */
+
+export type ObservableFunction<T> = (val: T) => void;
+
+export class SimpleObservable<T> {
+ private listeners: ObservableFunction<T>[] = [];
+
+ public constructor(initialFn?: ObservableFunction<T>) {
+ if (initialFn) this.listeners.push(initialFn);
+ }
+
+ public onUpdate(fn: ObservableFunction<T>) {
+ this.listeners.push(fn);
+ }
+
+ public update(val: T) {
+ for (const listener of this.listeners) {
+ listener(val);
+ }
+ }
+
+ public close() {
+ this.listeners = []; // reset
+ }
+}