Merge pull request #198 from element-hq/langleyd/widget-lifecycle-module-api

Widget lifecycle module api
This commit is contained in:
David Langley 2026-02-25 12:58:43 +00:00 committed by GitHub
commit 226824890a
5 changed files with 129 additions and 0 deletions

View File

@ -55,6 +55,8 @@ export interface Api extends LegacyModuleApiExtension, LegacyCustomisationsApiEx
readonly navigation: NavigationApi;
readonly rootNode: HTMLElement;
readonly stores: StoresApi;
// @alpha
readonly widgetLifecycle: WidgetLifecycleApi;
}
// @alpha
@ -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(): {
@ -180,6 +185,9 @@ export interface I18nApi {
translate(this: void, 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;
@ -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)
@ -325,6 +336,9 @@ export type OriginalMessageComponentProps = {
showUrlPreview?: boolean;
};
// @alpha
export type PreloadApprover = (widget: WidgetDescriptor) => MaybePromise<boolean | undefined>;
// @public
export interface Profile {
displayName?: string;
@ -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>>;

View File

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

View File

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

View File

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

View File

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