Files
ThreadNet-Web/modules/widget-lifecycle/src/WidgetLifecycleModule.ts
T
Michael TelatynskiandGitHub 7a1a3f518c Make codebase comply to knip --strict (#33893)
* Make codebase comply to `knip --strict`

Deletes a few bits of dead code

* Trim i18n strings

* Fix missing export

* Remove test of dead code
2026-06-18 09:35:47 +00:00

92 lines
3.5 KiB
TypeScript

/*
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 { Api, Module, WidgetDescriptor, WidgetLifecycleApi } from "@element-hq/element-web-module-api";
import { CONFIG_KEY, parseWidgetLifecycleConfig, type WidgetLifecycleModuleConfig } from "./config";
import { constructWidgetPermissions } from "./utils/constructWidgetPermissions";
import { matchPattern } from "./utils/matchPattern";
import { name as ModuleName } from "../package.json";
/**
* Subset of {@link WidgetLifecycleApi} used by the module for registration only.
* @internal
*/
export type WidgetLifecycleApiAdapter = Pick<
WidgetLifecycleApi,
"registerPreloadApprover" | "registerIdentityApprover" | "registerCapabilitiesApprover"
>;
type ModuleApi = Pick<Api, "config" | "widgetLifecycle">;
/**
* Module that auto-approves widget preloading, identity token requests, and capability
* requests based on URL-pattern rules defined in config.json.
*/
export default class WidgetLifecycleModule implements Module {
public static readonly moduleApiVersion = "^1.10.0";
private config: WidgetLifecycleModuleConfig = {};
public constructor(private api: ModuleApi) {}
public async load(): Promise<void> {
const rawConfig = this.api.config.get(CONFIG_KEY);
if (!rawConfig) {
console.debug(`No configuration found for module "${ModuleName}", skipping initialization.`);
return;
}
if (!this.api.widgetLifecycle) {
throw new Error(
"Widget lifecycle API is not available. Update Element Web to a build that provides widget lifecycle module support.",
);
}
try {
this.config = parseWidgetLifecycleConfig(rawConfig);
} catch (error) {
console.error("[WidgetLifecycle] Failed to init module", error);
this.config = {};
}
this.api.widgetLifecycle.registerPreloadApprover((widget) => this.preapprovePreload(widget));
this.api.widgetLifecycle.registerIdentityApprover((widget) => this.preapproveIdentity(widget));
this.api.widgetLifecycle.registerCapabilitiesApprover((widget, requested) =>
this.preapproveCapabilities(widget, requested),
);
}
private preapprovePreload(widget: WidgetDescriptor): boolean {
const configuration = constructWidgetPermissions(this.config, widget.templateUrl);
return configuration.preload_approved === true;
}
private preapproveIdentity(widget: WidgetDescriptor): boolean {
const configuration = constructWidgetPermissions(this.config, widget.templateUrl);
return configuration.identity_approved === true;
}
private preapproveCapabilities(
widget: WidgetDescriptor,
requestedCapabilities: Set<string>,
): Set<string> | undefined {
const configuration = constructWidgetPermissions(this.config, widget.templateUrl);
const capabilitiesApproved = configuration.capabilities_approved;
if (!capabilitiesApproved) return undefined;
const approvedCapabilities = new Set<string>();
for (const requestedCapability of requestedCapabilities) {
if (capabilitiesApproved.some((capability) => matchPattern(requestedCapability, capability))) {
approvedCapabilities.add(requestedCapability);
}
}
return approvedCapabilities.size > 0 ? approvedCapabilities : undefined;
}
}