This commit is contained in:
unfunny
2026-09-12 23:57:45 -04:00
parent 986c0af682
commit dfe4cc537f
1775 changed files with 246421 additions and 0 deletions

1433
node_modules/matrix-widget-api/src/ClientWidgetApi.ts generated vendored Normal file

File diff suppressed because it is too large Load Diff

19
node_modules/matrix-widget-api/src/Symbols.ts generated vendored Normal file
View File

@@ -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 = "*",
}

1076
node_modules/matrix-widget-api/src/WidgetApi.ts generated vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,545 @@
/*
* Copyright 2020 - 2024 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,
IRoomAccountData,
ITurnServer,
IWidgetApiErrorResponseDataDetails,
IRtcTransport,
IRtcLivekitGetTokenFromWidgetRequestData,
IRtcLivekitGetTokenFromWidgetResponseData,
IRtcLivekitDelegateDelayedLeaveFromWidgetRequestData,
IRtcLivekitDelegateDelayedLeaveFromWidgetResponseData,
} from "..";
export interface ISendEventDetails {
roomId: string;
eventId: string;
}
export interface ISendDelayedEventDetails {
roomId: string;
delayId: 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;
}>;
}
export interface IGetMediaConfigResult {
[key: string]: unknown;
"m.upload.size"?: number;
}
export interface IRtcTransportsResult {
rtc_transports: IRtcTransport[];
}
/**
* 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"));
}
/**
* @experimental Part of MSC4407
* Sends a sticky 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 {number} stickyDurationMs The length of time a sticky event may remain sticky, in milliseconds.
* @param {string} eventType The event type to be sent.
* @param {*} content The content for the event.
* @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 sendStickyEvent(
stickyDurationMs: number,
eventType: string,
content: unknown,
roomId: string | null = null,
): Promise<ISendEventDetails> {
throw new Error("Method not implemented.");
}
/**
* @experimental Part of MSC4140 & MSC4157
* Sends a delayed event into a room. If `roomId` is falsy, the client should send it
* 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 {number} delay How much later to send the event.
* @param {string} eventType The event type of the event to be sent.
* @param {*} content The content for the event to be sent.
* @param {string|null} stateKey The state key if the event to be sent 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<ISendDelayedEventDetails>} Resolves when the delayed event has been
* prepared with details of how to refer to it for updating/sending/canceling it later.
* @throws Rejected when the delayed event could not be sent.
*/
public sendDelayedEvent(
delay: number,
eventType: string,
content: unknown,
stateKey: string | null = null,
roomId: string | null = null,
): Promise<ISendDelayedEventDetails> {
return Promise.reject(new Error("Failed to override function"));
}
/**
* @experimental Part of MSC4140, MSC4157 and MSC4407
* Sends a delayed sticky 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 {number} stickyDurationMs The length of time a sticky event may remain sticky, in milliseconds.
* @param {number} delay How much later to send the event.
* @param {string} eventType The event type to be sent.
* @param {*} content The content for the event.
* @param {string|null} roomId The room ID to send the event to. If falsy, the room the
* user is currently looking at.
* @returns {Promise<ISendDelayedEventDetails>} Resolves when the event has been sent with
* details of that event.
* @throws Rejected when the event could not be sent.
*/
public sendDelayedStickyEvent(
delay: number,
stickyDurationMs: number,
eventType: string,
content: unknown,
roomId: string | null = null,
): Promise<ISendDelayedEventDetails> {
throw new Error("Method not implemented.");
}
/**
* @experimental Part of MSC4140 & MSC4157
* Cancel the scheduled delivery of the delayed event matching the provided {@link delayId}.
* @throws Rejected when there is no matching delayed event,
* or when the delayed event failed to be cancelled.
*/
public cancelScheduledDelayedEvent(delayId: string): Promise<void> {
return Promise.reject(new Error("Failed to override function"));
}
/**
* @experimental Part of MSC4140 & MSC4157
* Restart the scheduled delivery of the delayed event matching the provided {@link delayId}.
* @throws Rejected when there is no matching delayed event,
* or when the delayed event failed to be restarted.
*/
public restartScheduledDelayedEvent(delayId: string): Promise<void> {
return Promise.reject(new Error("Failed to override function"));
}
/**
* @experimental Part of MSC4140 & MSC4157
* Immediately send the delayed event matching the provided {@link delayId},
* instead of waiting for its scheduled delivery.
* @throws Rejected when there is no matching delayed event,
* or when the delayed event failed to be sent.
*/
public sendScheduledDelayedEvent(delayId: string): Promise<void> {
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 an element of room account data. The widget API will have already verified that the widget is
* capable of receiving the `eventType` of the requested information. If `roomIds` is supplied, it may
* contain `Symbols.AnyRoom` to denote that the piece of room account data 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 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<IRoomAccountData[]>} Resolves to the element of room account data, or an empty array.
*/
public readRoomAccountData(eventType: string, roomIds: string[] | null = null): Promise<IRoomAccountData[]> {
return Promise.resolve([]);
}
/**
* 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. If `since` is specified but
* the event ID isn't present in the number of events fetched by the client due to `limit`,
* the client will return all the events.
* @param eventType The event type to be read.
* @param msgtype The msgtype of the events to be read, if applicable/defined.
* @param stateKey The state key 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.
* @param since When null, retrieves the number of events specified by the "limit" parameter.
* Otherwise, the event ID at which only subsequent events will be returned, as many as specified
* in "limit".
* @returns {Promise<IRoomEvent[]>} Resolves to the room events, or an empty array.
* @deprecated Clients are advised to implement {@link WidgetDriver.readRoomTimeline} instead.
*/
public readRoomEvents(
eventType: string,
msgtype: string | undefined,
limit: number,
roomIds: string[] | null = null,
since?: string,
): 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.
* @deprecated Clients are advised to implement {@link WidgetDriver.readRoomTimeline} instead.
*/
public readStateEvents(
eventType: string,
stateKey: string | undefined,
limit: number,
roomIds: string[] | null = null,
): Promise<IRoomEvent[]> {
return Promise.resolve([]);
}
/**
* Gets all sticky events of the given type the user has access to.
* The widget API will have already verified that the widget is capable of receiving the events.
*
* This is needed because widgets will get only live messages as they appear in the timeline.
* However, sticky events act like a state, and the current state is made by events that may have been
* sent before the widget was loaded.
* Events are sticky for 1h maximum, so the widget has access to the past hour of sticky events maximum.
*
* @experimental Part of MSC4407 - Sticky Events (Widget API)
* @param roomId - The ID of the room.
*/
public readStickyEvents(roomId: string): Promise<IRoomEvent[]> {
throw new Error("readStickyEvents is not implemented");
}
/**
* 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.
* @param roomId The ID of the room to look within.
* @param eventType The event type to be read.
* @param msgtype The msgtype of the events to be read, if applicable/defined.
* @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 since When null, retrieves the number of events specified by the "limit" parameter.
* Otherwise, the event ID at which only subsequent events will be returned, as many as specified
* in "limit".
* @returns {Promise<IRoomEvent[]>} Resolves to the room events, or an empty array.
*/
public readRoomTimeline(
roomId: string,
eventType: string,
msgtype: string | undefined,
stateKey: string | undefined,
limit: number,
since: string | undefined,
): Promise<IRoomEvent[]> {
// For backward compatibility we try the deprecated methods, in case
// they're implemented
if (stateKey === undefined) return this.readRoomEvents(eventType, msgtype, limit, [roomId], since);
else return this.readStateEvents(eventType, stateKey, limit, [roomId]);
}
/**
* Reads the current values of all matching room state entries.
* @param roomId The ID of the room.
* @param eventType The event type of the entries to be read.
* @param stateKey The state key of the entry to be read. If undefined,
* all room state entries with a matching event type should be returned.
* @returns {Promise<IRoomEvent[]>} Resolves to the events representing the
* current values of the room state entries.
*/
public readRoomState(roomId: string, eventType: string, stateKey: string | undefined): Promise<IRoomEvent[]> {
return this.readStateEvents(eventType, stateKey, Number.MAX_SAFE_INTEGER, [roomId]);
}
/**
* 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>): void {
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: [] });
}
/**
* Get the config for the media repository.
* @returns Promise which resolves with an object containing the config.
*/
public getMediaConfig(): Promise<IGetMediaConfigResult> {
throw new Error("Get media config is not implemented");
}
/**
* Discover the RTC transports (e.g. SFUs, TURN servers) the homeserver
* supports, by delegating to the authenticated
* `GET /_matrix/client/v1/rtc/transports` Client-Server endpoint (MSC4143).
* @returns Promise which resolves with the available transports.
*/
public getRtcTransports(): Promise<IRtcTransportsResult> {
throw new Error("Get RTC transports is not implemented");
}
/**
* Upload a file to the media repository on the homeserver.
* @param file - The object to upload. Something that can be sent to
* XMLHttpRequest.send (typically a File).
* @returns Resolves to the location of the uploaded file.
*/
public uploadFile(file: XMLHttpRequestBodyInit): Promise<{ contentUri: string }> {
throw new Error("Upload file is not implemented");
}
/**
* Download a file from the media repository on the homeserver.
* @param contentUri - MXC URI of the file to download.
* @returns Resolves to the contents of the file.
*/
public downloadFile(contentUri: string): Promise<{ file: XMLHttpRequestBodyInit }> {
throw new Error("Download file is not implemented");
}
/**
* Obtains a JWT for a LiveKit SFU by calling the homeserver's
* `/rtc/livekit/get_token` endpoint on the widget's behalf. The widget API
* will have already verified that the widget has permission to do so.
* @param data The request data, to be used as the request body verbatim.
* @returns Resolves to the response body of the endpoint, verbatim.
* @see {@link https://github.com/matrix-org/matrix-spec-proposals/pull/4533|MSC4533}
*/
public getRtcLivekitToken(
data: IRtcLivekitGetTokenFromWidgetRequestData,
): Promise<IRtcLivekitGetTokenFromWidgetResponseData> {
throw new Error("Getting a LiveKit token is not implemented");
}
/**
* Hands a MatrixRTC session's delayed leave event over to the server by
* calling the homeserver's `/rtc/livekit/delegate_delayed_leave` endpoint on
* the widget's behalf. The widget API will have already verified that the
* widget has permission to do so.
* @param data The request data, to be used as the request body verbatim.
* @returns Resolves to the response body of the endpoint, verbatim.
* @see {@link https://github.com/matrix-org/matrix-spec-proposals/pull/4533|MSC4533}
*/
public delegateRtcLivekitDelayedLeave(
data: IRtcLivekitDelegateDelayedLeaveFromWidgetRequestData,
): Promise<IRtcLivekitDelegateDelayedLeaveFromWidgetResponseData> {
throw new Error("Delegating a LiveKit delayed leave is not implemented");
}
/**
* Gets the IDs of all joined or invited rooms currently known to the
* client.
* @returns The room IDs.
*/
public getKnownRooms(): string[] {
throw new Error("Querying known rooms is not implemented");
}
/**
* Expresses an error thrown by this driver in a format compatible with the Widget API.
* @param error The error to handle.
* @returns The error expressed as a {@link IWidgetApiErrorResponseDataDetails},
* or undefined if it cannot be expressed as one.
*/
public processError(error: unknown): IWidgetApiErrorResponseDataDetails | undefined {
return undefined;
}
}

83
node_modules/matrix-widget-api/src/index.ts generated vendored Normal file
View File

@@ -0,0 +1,83 @@
/*
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 type * from "./transport/ITransport";
export * from "./transport/PostmessageTransport";
// Interfaces and simple models
export type * from "./interfaces/ICustomWidgetData";
export type * from "./interfaces/IJitsiWidgetData";
export type * from "./interfaces/IStickerpickerWidgetData";
export type * from "./interfaces/IWidget";
export * from "./interfaces/WidgetType";
export * from "./interfaces/IWidgetApiErrorResponse";
export type * from "./interfaces/IWidgetApiRequest";
export type * from "./interfaces/IWidgetApiResponse";
export * from "./interfaces/WidgetApiAction";
export * from "./interfaces/WidgetApiDirection";
export * from "./interfaces/ApiVersion";
export * from "./interfaces/Capabilities";
export type * from "./interfaces/CapabilitiesAction";
export type * from "./interfaces/ContentLoadedAction";
export type * from "./interfaces/ScreenshotAction";
export type * from "./interfaces/StickerAction";
export type * from "./interfaces/StickyAction";
export type * from "./interfaces/SupportedVersionsAction";
export type * from "./interfaces/VisibilityAction";
export * from "./interfaces/GetOpenIDAction";
export type * from "./interfaces/OpenIDCredentialsAction";
export * from "./interfaces/WidgetKind";
export * from "./interfaces/ModalButtonKind";
export * from "./interfaces/ModalWidgetActions";
export type * from "./interfaces/SetModalButtonEnabledAction";
export type * from "./interfaces/WidgetConfigAction";
export type * from "./interfaces/SendEventAction";
export type * from "./interfaces/SendToDeviceAction";
export type * from "./interfaces/ReadEventAction";
export type * from "./interfaces/IRoomEvent";
export type * from "./interfaces/IRoomAccountData";
export type * from "./interfaces/NavigateAction";
export type * from "./interfaces/TurnServerActions";
export type * from "./interfaces/ReadRelationsAction";
export type * from "./interfaces/GetMediaConfigAction";
export type * from "./interfaces/RtcTransportsAction";
export * from "./interfaces/UpdateDelayedEventAction";
export type * from "./interfaces/UpdateStateAction";
export type * from "./interfaces/UploadFileAction";
export type * from "./interfaces/DownloadFileAction";
export type * from "./interfaces/RtcLivekitActions";
export type * from "./interfaces/ThemeChangeAction";
export type * from "./interfaces/LanguageChangeAction";
// 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";

View File

@@ -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.
*/
export enum MatrixApiVersion {
Prerelease1 = "0.0.1",
Prerelease2 = "0.0.2",
//V010 = "0.1.0", // first release
}
export enum UnstableApiVersion {
MSC2762 = "org.matrix.msc2762",
MSC2762_UPDATE_STATE = "org.matrix.msc2762_update_state",
MSC2871 = "org.matrix.msc2871",
MSC2873 = "org.matrix.msc2873",
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",
MSC4039 = "org.matrix.msc4039",
MSC4515 = "org.matrix.msc4515",
MSC4533 = "org.matrix.msc4533",
}
export type ApiVersion = MatrixApiVersion | UnstableApiVersion | string;
export const CurrentApiVersions: ApiVersion[] = [
MatrixApiVersion.Prerelease1,
MatrixApiVersion.Prerelease2,
//MatrixApiVersion.V010,
UnstableApiVersion.MSC2762,
UnstableApiVersion.MSC2762_UPDATE_STATE,
UnstableApiVersion.MSC2871,
UnstableApiVersion.MSC2873,
UnstableApiVersion.MSC2931,
UnstableApiVersion.MSC2974,
UnstableApiVersion.MSC2876,
UnstableApiVersion.MSC3819,
UnstableApiVersion.MSC3846,
UnstableApiVersion.MSC3869,
UnstableApiVersion.MSC3973,
UnstableApiVersion.MSC4039,
UnstableApiVersion.MSC4515,
UnstableApiVersion.MSC4533,
];

View File

@@ -0,0 +1,110 @@
/*
* 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",
/**
* @experimental It is not recommended to rely on this existing - it can be removed without notice.
*/
MSC2931Navigate = "org.matrix.msc2931.navigate",
/**
* @experimental It is not recommended to rely on this existing - it can be removed without notice.
*/
MSC3846TurnServers = "town.robin.msc3846.turn_servers",
/**
* @experimental It is not recommended to rely on this existing - it can be removed without notice.
*/
MSC3973UserDirectorySearch = "org.matrix.msc3973.user_directory_search",
/**
* @experimental It is not recommended to rely on this existing - it can be removed without notice.
*/
MSC4039UploadFile = "org.matrix.msc4039.upload_file",
/**
* @experimental It is not recommended to rely on this existing - it can be removed without notice.
*/
MSC4039DownloadFile = "org.matrix.msc4039.download_file",
/**
* @experimental It is not recommended to rely on this existing - it can be removed without notice.
*/
MSC4157SendDelayedEvent = "org.matrix.msc4157.send.delayed_event",
/**
* @experimental It is not recommended to rely on this existing - it can be removed without notice.
*/
MSC4157UpdateDelayedEvent = "org.matrix.msc4157.update_delayed_event",
/**
* @experimental It is not recommended to rely on this existing - it can be removed without notice.
*/
MSC4407SendStickyEvent = "org.matrix.msc4407.send.sticky_event",
/**
* @experimental It is not recommended to rely on this existing - it can be removed without notice.
*/
MSC4407ReceiveStickyEvent = "org.matrix.msc4407.receive.sticky_event",
/**
* @experimental It is not recommended to rely on this existing - it can be removed without notice.
*/
MSC4515RtcTransports = "org.matrix.msc4515.rtc_transports",
/**
* @experimental It is not recommended to rely on this existing - it can be removed without notice.
*/
MSC4533RtcLivekitGetToken = "org.matrix.msc4533.rtc_livekit_get_token",
/**
* @experimental It is not recommended to rely on this existing - it can be removed without notice.
*/
MSC4533RtcLivekitDelegateDelayedLeave = "org.matrix.msc4533.rtc_livekit_delegate_delayed_leave",
}
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);
}

View File

@@ -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
}

View File

@@ -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;
}

View File

@@ -0,0 +1,36 @@
/*
* Copyright 2024 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 IDownloadFileActionFromWidgetRequestData extends IWidgetApiRequestData {
content_uri: string; // eslint-disable-line camelcase
}
export interface IDownloadFileActionFromWidgetActionRequest extends IWidgetApiRequest {
action: WidgetApiFromWidgetAction.MSC4039DownloadFileAction;
data: IDownloadFileActionFromWidgetRequestData;
}
export interface IDownloadFileActionFromWidgetResponseData extends IWidgetApiResponseData {
file: XMLHttpRequestBodyInit;
}
export interface IDownloadFileActionFromWidgetActionResponse extends IDownloadFileActionFromWidgetActionRequest {
response: IDownloadFileActionFromWidgetResponseData;
}

View File

@@ -0,0 +1,34 @@
/*
* 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 IGetMediaConfigActionFromWidgetRequestData extends IWidgetApiRequestData {}
export interface IGetMediaConfigActionFromWidgetActionRequest extends IWidgetApiRequest {
action: WidgetApiFromWidgetAction.MSC4039GetMediaConfigAction;
data: IGetMediaConfigActionFromWidgetRequestData;
}
export interface IGetMediaConfigActionFromWidgetResponseData extends IWidgetApiResponseData {
"m.upload.size"?: number;
}
export interface IGetMediaConfigActionFromWidgetActionResponse extends IGetMediaConfigActionFromWidgetActionRequest {
response: IGetMediaConfigActionFromWidgetResponseData;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -0,0 +1,21 @@
/*
* Copyright 2023 Beeper Inc.
*
* 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 IRoomAccountData {
type: string;
room_id: string; // eslint-disable-line camelcase
content: Record<string, unknown>;
}

View File

@@ -0,0 +1,33 @@
/*
* 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: Record<string, unknown>;
unsigned: Record<string, unknown>;
//MSC4354
sticky?: {
duration_ms: number;
};
msc4354_sticky?: {
duration_ms: number;
};
}

View File

@@ -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)
}

View File

@@ -0,0 +1,21 @@
/*
* Copyright 2025 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 IToDeviceMessage {
content: Record<string, unknown>;
sender: string;
type: string;
}

View File

@@ -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;
}

View File

@@ -0,0 +1,56 @@
/*
* Copyright 2020 - 2024 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";
/**
* The format of errors returned by Matrix API requests
* made by a WidgetDriver.
*/
export interface IMatrixApiError {
/** The HTTP status code of the associated request. */
http_status: number; // eslint-disable-line camelcase
/** Any HTTP response headers that are relevant to the error. */
http_headers: { [name: string]: string }; // eslint-disable-line camelcase
/** The URL of the failed request. */
url: string;
/** @see {@link https://spec.matrix.org/latest/client-server-api/#standard-error-response} */
response: {
errcode: string;
error: string;
} & IWidgetApiResponseData; // extensible
}
export interface IWidgetApiErrorResponseDataDetails {
/** Set if the error came from a Matrix API request made by a widget driver */
matrix_api_error?: IMatrixApiError; // eslint-disable-line camelcase
}
export interface IWidgetApiErrorResponseData extends IWidgetApiResponseData {
error: {
/** A user-friendly string describing the error */
message: string;
} & IWidgetApiErrorResponseDataDetails;
}
export interface IWidgetApiErrorResponse extends IWidgetApiResponse {
response: IWidgetApiErrorResponseData;
}
export function isErrorResponse(responseData: IWidgetApiResponseData): responseData is IWidgetApiErrorResponseData {
const error = responseData.error;
return typeof error === "object" && error !== null && "message" in error && typeof error.message === "string";
}

View File

@@ -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 { 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
// eslint-disable-next-line @typescript-eslint/no-explicit-any
visible?: any;
}

View File

@@ -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;
}

View File

@@ -0,0 +1,35 @@
/*
* Copyright 2024 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 ILanguageChangeActionRequestData extends IWidgetApiRequestData {
/**
* The BCP 47 identifier for the client's current language.
*/
lang: string;
}
export interface ILanguageChangeActionRequest extends IWidgetApiRequest {
action: WidgetApiToWidgetAction.LanguageChange;
data: ILanguageChangeActionRequestData;
}
export interface ILanguageChangeActionResponse extends ILanguageChangeActionRequest {
response: IWidgetApiAcknowledgeResponseData;
}

View File

@@ -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",
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -0,0 +1,43 @@
/*
* 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
since?: string;
}
export interface IReadEventFromWidgetActionRequest extends IWidgetApiRequest {
action: WidgetApiFromWidgetAction.MSC2876ReadEvents;
data: IReadEventFromWidgetRequestData;
}
export interface IReadEventFromWidgetResponseData extends IWidgetApiResponseData {
events: IRoomEvent[];
}
export interface IReadEventFromWidgetActionResponse extends IReadEventFromWidgetActionRequest {
response: IReadEventFromWidgetResponseData;
}

View File

@@ -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;
}

View File

@@ -0,0 +1,39 @@
/*
* Copyright 2023 Beeper Inc.
*
* 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 { IRoomAccountData } from "./IRoomAccountData";
import { Symbols } from "../Symbols";
export interface IReadRoomAccountDataFromWidgetRequestData extends IWidgetApiRequestData {
type: string;
room_ids?: Symbols.AnyRoom | string[]; // eslint-disable-line camelcase
}
export interface IReadRoomAccountDataFromWidgetActionRequest extends IWidgetApiRequest {
action: WidgetApiFromWidgetAction.BeeperReadRoomAccountData;
data: IReadRoomAccountDataFromWidgetRequestData;
}
export interface IReadRoomAccountDataFromWidgetResponseData extends IWidgetApiResponseData {
events: IRoomAccountData[];
}
export interface IReadRoomAccountDataFromWidgetActionResponse extends IReadRoomAccountDataFromWidgetActionRequest {
response: IReadRoomAccountDataFromWidgetResponseData;
}

View File

@@ -0,0 +1,80 @@
/*
* Copyright 2026 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 { IWidgetApiResponseData } from "./IWidgetApiResponse";
import { WidgetApiFromWidgetAction } from "./WidgetApiAction";
/**
* The MatrixRTC member a LiveKit request is made for.
* @see {@link https://github.com/matrix-org/matrix-spec-proposals/pull/4195|MSC4195}
*/
export interface IRtcLivekitMember {
/** The identifier of the member within the MatrixRTC session. */
id: string;
/** The device ID the member claims to be using. */
claimed_device_id?: string; // eslint-disable-line camelcase
}
export interface IRtcLivekitGetTokenFromWidgetRequestData extends IWidgetApiRequestData {
/** The name of the homeserver hosting the MatrixRTC session. */
server_name: string; // eslint-disable-line camelcase
/** The URL of the LiveKit SFU to obtain a token for. */
url: string;
/** The room the MatrixRTC session belongs to. */
room_id: string; // eslint-disable-line camelcase
/** The MatrixRTC session (slot) to join. */
slot_id: string; // eslint-disable-line camelcase
member: IRtcLivekitMember;
}
export interface IRtcLivekitGetTokenFromWidgetActionRequest extends IWidgetApiRequest {
action: WidgetApiFromWidgetAction.MSC4533RtcLivekitGetToken;
data: IRtcLivekitGetTokenFromWidgetRequestData;
}
export interface IRtcLivekitGetTokenFromWidgetResponseData extends IWidgetApiResponseData {
/** The JWT to authenticate against the SFU with. */
jwt: string;
}
export interface IRtcLivekitGetTokenFromWidgetActionResponse extends IRtcLivekitGetTokenFromWidgetActionRequest {
response: IRtcLivekitGetTokenFromWidgetResponseData;
}
export interface IRtcLivekitDelegateDelayedLeaveFromWidgetRequestData extends IWidgetApiRequestData {
/** The room the MatrixRTC session belongs to. */
room_id: string; // eslint-disable-line camelcase
/** The MatrixRTC session (slot) the delayed leave event belongs to. */
slot_id: string; // eslint-disable-line camelcase
member: IRtcLivekitMember;
/** The ID of the delayed leave event to hand over to the server. */
delay_id: string; // eslint-disable-line camelcase
}
export interface IRtcLivekitDelegateDelayedLeaveFromWidgetActionRequest extends IWidgetApiRequest {
action: WidgetApiFromWidgetAction.MSC4533RtcLivekitDelegateDelayedLeave;
data: IRtcLivekitDelegateDelayedLeaveFromWidgetRequestData;
}
export interface IRtcLivekitDelegateDelayedLeaveFromWidgetResponseData extends IWidgetApiResponseData {
// nothing
}
export interface IRtcLivekitDelegateDelayedLeaveFromWidgetActionResponse
extends IRtcLivekitDelegateDelayedLeaveFromWidgetActionRequest {
response: IRtcLivekitDelegateDelayedLeaveFromWidgetResponseData;
}

View File

@@ -0,0 +1,44 @@
/*
* Copyright 2026 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 { IWidgetApiResponseData } from "./IWidgetApiResponse";
import { WidgetApiFromWidgetAction } from "./WidgetApiAction";
export interface IRtcTransport {
/**
* The globally unique transport identifier. Follows the Common Namespaced
* Identifier Grammar (without the namespacing requirement).
*/
type: string;
/** Further transport-specific properties, defined by the transport's specification.*/
[key: string]: unknown;
}
export interface IRtcTransportsFromWidgetRequestData extends IWidgetApiRequestData {}
export interface IRtcTransportsFromWidgetActionRequest extends IWidgetApiRequest {
action: WidgetApiFromWidgetAction.MSC4515GetRtcTransports;
data: IRtcTransportsFromWidgetRequestData;
}
export interface IRtcTransportsFromWidgetResponseData extends IWidgetApiResponseData {
rtc_transports: IRtcTransport[];
}
export interface IRtcTransportsFromWidgetActionResponse extends IRtcTransportsFromWidgetActionRequest {
response: IRtcTransportsFromWidgetResponseData;
}

View File

@@ -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;
}

View File

@@ -0,0 +1,67 @@
/*
* Copyright 2020 - 2024 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
// MSC4157
delay?: number; // eslint-disable-line camelcase
/** @deprecated */
parent_delay_id?: string; // eslint-disable-line camelcase
// MSC4407
sticky_duration_ms?: number;
}
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
// MSC4157
delay_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;
}

View File

@@ -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 { IToDeviceMessage } from "./IToDeviceMessage";
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, IToDeviceMessage {
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;
}

View File

@@ -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;
}

View File

@@ -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 { 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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -0,0 +1,32 @@
/*
* Copyright 2024 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 IThemeChangeActionRequestData extends IWidgetApiRequestData {
// The format of a theme is deliberately unstandardized
}
export interface IThemeChangeActionRequest extends IWidgetApiRequest {
action: WidgetApiToWidgetAction.ThemeChange;
data: IThemeChangeActionRequestData;
}
export interface IThemeChangeActionResponse extends IThemeChangeActionRequest {
response: IWidgetApiAcknowledgeResponseData;
}

View File

@@ -0,0 +1,54 @@
/*
* 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;
}

View File

@@ -0,0 +1,43 @@
/*
* Copyright 2020 - 2024 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 UpdateDelayedEventAction {
Cancel = "cancel",
Restart = "restart",
Send = "send",
}
export interface IUpdateDelayedEventFromWidgetRequestData extends IWidgetApiRequestData {
delay_id: string; // eslint-disable-line camelcase
action: UpdateDelayedEventAction;
}
export interface IUpdateDelayedEventFromWidgetActionRequest extends IWidgetApiRequest {
action: WidgetApiFromWidgetAction.MSC4157UpdateDelayedEvent;
data: IUpdateDelayedEventFromWidgetRequestData;
}
export interface IUpdateDelayedEventFromWidgetResponseData extends IWidgetApiResponseData {
// nothing
}
export interface IUpdateDelayedEventFromWidgetActionResponse extends IUpdateDelayedEventFromWidgetActionRequest {
response: IUpdateDelayedEventFromWidgetResponseData;
}

View File

@@ -0,0 +1,37 @@
/*
* Copyright 2024 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 { IRoomEvent } from "./IRoomEvent";
export interface IUpdateStateToWidgetRequestData extends IWidgetApiRequestData {
state: IRoomEvent[];
}
export interface IUpdateStateToWidgetActionRequest extends IWidgetApiRequest {
action: WidgetApiToWidgetAction.UpdateState;
data: IUpdateStateToWidgetRequestData;
}
export interface IUpdateStateToWidgetResponseData extends IWidgetApiResponseData {
// nothing
}
export interface IUpdateStateToWidgetActionResponse extends IUpdateStateToWidgetActionRequest {
response: IUpdateStateToWidgetResponseData;
}

View File

@@ -0,0 +1,36 @@
/*
* 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 IUploadFileActionFromWidgetRequestData extends IWidgetApiRequestData {
file: XMLHttpRequestBodyInit;
}
export interface IUploadFileActionFromWidgetActionRequest extends IWidgetApiRequest {
action: WidgetApiFromWidgetAction.MSC4039UploadFileAction;
data: IUploadFileActionFromWidgetRequestData;
}
export interface IUploadFileActionFromWidgetResponseData extends IWidgetApiResponseData {
content_uri: string; // eslint-disable-line camelcase
}
export interface IUploadFileActionFromWidgetActionResponse extends IUploadFileActionFromWidgetActionRequest {
response: IUploadFileActionFromWidgetResponseData;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -0,0 +1,112 @@
/*
* 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",
ThemeChange = "theme_change",
LanguageChange = "language_change",
TakeScreenshot = "screenshot",
UpdateVisibility = "visibility",
OpenIDCredentials = "openid_credentials",
WidgetConfig = "widget_config",
CloseModalWidget = "close_modal",
ButtonClicked = "button_clicked",
SendEvent = "send_event",
SendToDevice = "send_to_device",
UpdateState = "update_state",
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",
BeeperReadRoomAccountData = "com.beeper.read_room_account_data",
/**
* @experimental It is not recommended to rely on this existing - it can be removed without notice.
*/
MSC2876ReadEvents = "org.matrix.msc2876.read_events",
/**
* @experimental It is not recommended to rely on this existing - it can be removed without notice.
*/
MSC2931Navigate = "org.matrix.msc2931.navigate",
/**
* @experimental It is not recommended to rely on this existing - it can be removed without notice.
*/
MSC2974RenegotiateCapabilities = "org.matrix.msc2974.request_capabilities",
/**
* @experimental It is not recommended to rely on this existing - it can be removed without notice.
*/
MSC3869ReadRelations = "org.matrix.msc3869.read_relations",
/**
* @experimental It is not recommended to rely on this existing - it can be removed without notice.
*/
MSC3973UserDirectorySearch = "org.matrix.msc3973.user_directory_search",
/**
* @experimental It is not recommended to rely on this existing - it can be removed without notice.
*/
MSC4039GetMediaConfigAction = "org.matrix.msc4039.get_media_config",
/**
* @experimental It is not recommended to rely on this existing - it can be removed without notice.
*/
MSC4039UploadFileAction = "org.matrix.msc4039.upload_file",
/**
* @experimental It is not recommended to rely on this existing - it can be removed without notice.
*/
MSC4039DownloadFileAction = "org.matrix.msc4039.download_file",
/**
* @experimental It is not recommended to rely on this existing - it can be removed without notice.
*/
MSC4157UpdateDelayedEvent = "org.matrix.msc4157.update_delayed_event",
/**
* @experimental It is not recommended to rely on this existing - it can be removed without notice.
*/
MSC4515GetRtcTransports = "org.matrix.msc4515.get_rtc_transports",
/**
* @experimental It is not recommended to rely on this existing - it can be removed without notice.
*/
MSC4533RtcLivekitGetToken = "org.matrix.msc4533.rtc_livekit_get_token",
/**
* @experimental It is not recommended to rely on this existing - it can be removed without notice.
*/
MSC4533RtcLivekitDelegateDelayedLeave = "org.matrix.msc4533.rtc_livekit_delegate_delayed_leave",
}
export type WidgetApiAction = WidgetApiToWidgetAction | WidgetApiFromWidgetAction | string;

View File

@@ -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");
}
}

View File

@@ -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;
}

View File

@@ -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",
}

View File

@@ -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;

108
node_modules/matrix-widget-api/src/models/Widget.ts generated vendored Normal file
View File

@@ -0,0 +1,108 @@
/*
* 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 { ITemplateParams, IWidget, IWidgetData, runTemplate, WidgetType } from "..";
import { assertPresent } from "./validation/utils";
/**
* Represents the barest form of widget.
*/
export class Widget {
public constructor(private readonly 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);
}
}

View File

@@ -0,0 +1,224 @@
/*
* 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",
RoomAccount = "room_account",
}
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 matchesAsRoomAccountData(direction: EventDirection, eventType: string): boolean {
if (this.kind !== EventKind.RoomAccount) return false; // not room account data
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 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];
}
public static forRoomAccountData(direction: EventDirection, eventType: string): WidgetEventCapability {
const str = `com.beeper.capabilities.${direction}.room_account_data:${eventType}`;
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);
} else if (cap.startsWith("com.beeper.capabilities.receive.room_account_data:")) {
direction = EventDirection.Receive;
kind = EventKind.RoomAccount;
eventSegment = cap.substring("com.beeper.capabilities.receive.room_account_data:".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;
}
}

View File

@@ -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);
}
}

View File

@@ -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;
}
}

View File

@@ -0,0 +1,22 @@
/*
* 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.
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function assertPresent<O extends Record<any, any>>(obj: O, key: keyof O): void {
if (!obj[key]) {
throw new Error(`${String(key)} is required`);
}
}

View File

@@ -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 { IWidget } from "..";
export interface ITemplateParams {
widgetRoomId?: string;
currentUserId: string;
userDisplayName?: string;
userHttpAvatarUrl?: string;
clientId?: string;
clientTheme?: string;
clientLanguage?: string;
deviceId?: string;
baseUrl?: 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 || "",
// TODO: Convert to stable (https://github.com/matrix-org/matrix-spec-proposals/pull/3819)
"org.matrix.msc3819.matrix_device_id": params.deviceId || "",
// TODO: Convert to stable (https://github.com/matrix-org/matrix-spec-proposals/pull/4039)
"org.matrix.msc4039.matrix_base_url": params.baseUrl || "",
});
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}`;
}
// eslint-disable-next-line @typescript-eslint/no-base-to-string
return String(a);
}

View File

@@ -0,0 +1,109 @@
/*
* Copyright 2020 - 2024 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 action The action to send.
* @param data The request data.
* @returns A promise which resolves to the remote end's response.
* @throws {Error} if the request failed with a generic error.
* @throws {WidgetApiResponseError} if the request failed with error details
* that can be communicated to the Widget API.
*/
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
* @throws {Error} if the request failed with a generic error.
* @throws {WidgetApiResponseError} if the request failed with error details
* that can be communicated to the Widget API.
*/
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;
}

View File

@@ -0,0 +1,200 @@
/*
* Copyright 2020 - 2024 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,
IWidgetApiRequest,
IWidgetApiRequestData,
IWidgetApiResponse,
IWidgetApiResponseData,
WidgetApiResponseError,
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;
private readonly outboundRequests = new Map<string, IOutboundRequest | null>();
private readonly stopController = new AbortController();
public get ready(): boolean {
return this._ready;
}
public get widgetId(): string | null {
return this._widgetId || null;
}
public constructor(
private readonly sendDirection: WidgetApiDirection,
initialWidgetId: string | null,
private readonly transportWindow: Window | typeof globalThis,
private readonly inboundWindow: Window | typeof globalThis,
) {
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): void {
console.log(`[PostmessageTransport] Sending object to ${this.targetOrigin}: `, message);
this.transportWindow.postMessage(message, this.targetOrigin);
}
public reply<T extends IWidgetApiResponseData>(request: IWidgetApiRequest, responseData: T): void {
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): void => {
cleanUp();
prResolve(<R>response);
};
const reject = (err: Error): void => {
cleanUp();
prReject(err);
};
const timerId = setTimeout(() => reject(new Error("Request timed out")), (this.timeoutSeconds || 1) * 1000);
const onStop = (): void => reject(new Error("Transport stopped"));
this.stopController.signal.addEventListener("abort", onStop);
const cleanUp = (): void => {
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(): void {
this.inboundWindow.addEventListener("message", this.handleMessage);
this._ready = true;
}
public stop(): void {
this._ready = false;
this.stopController.abort();
this.inboundWindow.removeEventListener("message", this.handleMessage);
}
private readonly handleMessage = (ev: MessageEvent): void => {
if (this.stopController.signal.aborted) return;
if (!ev.data) return; // invalid event
if (this.strictOriginCheck && ev.origin !== globalThis.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) {
if (response.api !== this.sendDirection) return; // wrong direction
this.handleResponse(response);
} else {
const request = <IWidgetApiRequest>response;
if (request.api !== invertedDirection(this.sendDirection)) return; // wrong direction
this.handleRequest(request);
}
};
private handleRequest(request: IWidgetApiRequest): void {
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): void {
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 { message, ...data } = response.response.error;
req.reject(new WidgetApiResponseError(message, data));
} else {
req.resolve(response);
}
}
}

View File

@@ -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>): void {
this.listeners.push(fn);
}
public update(val: T): void {
for (const listener of this.listeners) {
listener(val);
}
}
public close(): void {
this.listeners = []; // reset
}
}