Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions packages/element-web-module-api/element-web-module-api.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ export interface Api extends LegacyModuleApiExtension, LegacyCustomisationsApiEx
readonly navigation: NavigationApi;
readonly rootNode: HTMLElement;
readonly stores: StoresApi;
// @alpha
readonly widgetLifecycle: WidgetLifecycleApi;
}

// @alpha
Expand All @@ -64,6 +66,9 @@ export interface BuiltinsApi {
renderRoomView(roomId: string, props?: RoomViewProps): React.ReactNode;
}

// @alpha
export type CapabilitiesApprover = (widget: WidgetDescriptor, requestedCapabilities: Set<string>) => MaybePromise<Set<string> | undefined>;

// @alpha @deprecated (undocumented)
export interface ChatExportCustomisations<ExportFormat, ExportType> {
getForceChatExportParameters(): {
Expand Down Expand Up @@ -180,6 +185,9 @@ export interface I18nApi {
translate(key: keyof Translations, variables?: Variables): string;
}

// @alpha
export type IdentityApprover = (widget: WidgetDescriptor) => MaybePromise<boolean | undefined>;

// @alpha @deprecated (undocumented)
export type LegacyCustomisations<T extends object> = (customisations: T) => void;

Expand Down Expand Up @@ -234,6 +242,9 @@ export interface MatrixEvent {
unsigned: Record<string, unknown>;
}

// @public
export type MaybePromise<T> = T | PromiseLike<T>;

// @alpha @deprecated (undocumented)
export interface Media {
// (undocumented)
Expand Down Expand Up @@ -325,6 +336,9 @@ export type OriginalMessageComponentProps = {
showUrlPreview?: boolean;
};

// @alpha
export type PreloadApprover = (widget: WidgetDescriptor) => MaybePromise<boolean | undefined>;

// @public
export interface Profile {
displayName?: string;
Expand Down Expand Up @@ -422,6 +436,23 @@ export class Watchable<T> {
watch(listener: (value: T) => void): void;
}

// @alpha
export type WidgetDescriptor = {
id: string;
templateUrl: string;
creatorUserId: string;
type: string;
origin: string;
roomId?: string;
};

// @alpha
export interface WidgetLifecycleApi {
registerCapabilitiesApprover(approver: CapabilitiesApprover): void;
registerIdentityApprover(approver: IdentityApprover): void;
registerPreloadApprover(approver: PreloadApprover): void;
}

// @alpha @deprecated (undocumented)
export interface WidgetPermissionsCustomisations<Widget, Capability> {
preapproveCapabilities?(widget: Widget, requestedCapabilities: Set<Capability>): Promise<Set<Capability>>;
Expand Down
7 changes: 7 additions & 0 deletions packages/element-web-module-api/src/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { type ExtrasApi } from "./extras.ts";
import { type BuiltinsApi } from "./builtins.ts";
import { type StoresApi } from "./stores.ts";
import { type ClientApi } from "./client.ts";
import { type WidgetLifecycleApi } from "./widget-lifecycle.ts";

/**
* Module interface for modules to implement.
Expand Down Expand Up @@ -136,6 +137,12 @@ export interface Api
*/
readonly client: ClientApi;

/**
* API for modules to auto-approve widget preloading, identity token requests, and capability requests.
* @alpha Subject to change.
*/
readonly widgetLifecycle: WidgetLifecycleApi;

/**
* Create a ReactDOM root for rendering React components.
* Exposed to allow modules to avoid needing to bundle their own ReactDOM.
Expand Down
76 changes: 76 additions & 0 deletions packages/element-web-module-api/src/api/widget-lifecycle.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*
Copyright 2026 Element Creations Ltd.

SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
Please see LICENSE files in the repository root for full details.
*/

import type { MaybePromise } from "../utils";

/**
* A description of a widget passed to approver callbacks.
* Contains the information needed to make approval decisions.
* @alpha Subject to change.
*/
export type WidgetDescriptor = {
/** The unique identifier of the widget. */
id: string;
/** The template URL of the widget, which may contain `$matrix_*` placeholder variables. */
templateUrl: string;
/** The Matrix user ID of the user who created the widget. */
creatorUserId: string;
/** The widget type, e.g. `m.custom`, `m.jitsi`, `m.stickerpicker`. */
type: string;
/** The origin of the widget URL. */
origin: string;
/** The room ID the widget belongs to, if it is a room widget. */
roomId?: string;
};

/**
* Callback that decides whether a widget should be auto-approved for preloading
* (i.e. loaded without the user clicking "Continue").
* Return `true` to auto-approve, or any other value to defer to the default consent flow.
* @alpha Subject to change.
*/
export type PreloadApprover = (widget: WidgetDescriptor) => MaybePromise<boolean | undefined>;
/**
* Callback that decides whether a widget should be auto-approved to receive
* the user's OpenID identity token.
* Return `true` to auto-approve, or any other value to defer to the default consent flow.
* @alpha Subject to change.
*/
export type IdentityApprover = (widget: WidgetDescriptor) => MaybePromise<boolean | undefined>;
/**
* Callback that decides which of a widget's requested capabilities should be auto-approved.
* Return a `Set` of approved capability strings, or `undefined` to defer to the default consent flow.
* @alpha Subject to change.
*/
export type CapabilitiesApprover = (
widget: WidgetDescriptor,
requestedCapabilities: Set<string>,
) => MaybePromise<Set<string> | undefined>;

/**
* API for modules to auto-approve widget preloading, identity token requests, and capability requests.
* @alpha Subject to change.
*/
export interface WidgetLifecycleApi {
/**
* Register a handler that can auto-approve widget preloading.
* Returning true auto-approves; any other value results in no auto-approval.
*/
registerPreloadApprover(approver: PreloadApprover): void;

/**
* Register a handler that can auto-approve identity token requests.
* Returning true auto-approves; any other value results in no auto-approval.
*/
registerIdentityApprover(approver: IdentityApprover): void;

/**
* Register a handler that can auto-approve widget capabilities.
* Return a set containing the capabilities to approve.
*/
registerCapabilitiesApprover(approver: CapabilitiesApprover): void;
}
2 changes: 2 additions & 0 deletions packages/element-web-module-api/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,6 @@ export type * from "./api/navigation";
export type * from "./api/builtins";
export type * from "./api/stores";
export type * from "./api/client";
export type * from "./api/widget-lifecycle";
export * from "./api/watchable";
export type * from "./utils";
13 changes: 13 additions & 0 deletions packages/element-web-module-api/src/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/*
Copyright 2026 Element Creations Ltd.

SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
Please see LICENSE files in the repository root for full details.
*/

/**
* A value that may be a direct value or a Promise resolving to that value.
* Useful for callback APIs that can operate synchronously or asynchronously.
* @public
*/
export type MaybePromise<T> = T | PromiseLike<T>;