/** * @license * Copyright 2022-2026 Matter.js Authors * SPDX-License-Identifier: Apache-2.0 */ import { Logger } from "#log/Logger.js"; import { BasicSet } from "#util/Set.js"; import { Environment } from "./Environment.js"; const logger = new Logger("ServiceBundle"); /** * A bundle of services that may be added to an {@link Environment} as a unit. * * This serves as an extension mechanism for matter.js. Plugins may register for deployment into environments by adding * a factory to {@link default}. */ export class ServiceBundle extends BasicSet { static #default = new ServiceBundle(); #environments = new Set>(); constructor() { super(); this.added.on(factory => { let toRemove: undefined | Set>; for (const ref of this.#environments) { const env = ref.deref(); if (env) { this.#deployFactory(factory, env); } // Clean up expired ref if (env === undefined) { if (toRemove === undefined) { toRemove = new Set(); } toRemove.add(ref); } } if (toRemove) { for (const expiredRef of toRemove) { this.#environments.delete(expiredRef); } } }); } /** * A default bundle for services that should generally deploy in all environments. */ static get default() { return this.#default; } /** * Install the bundle into an {@link Environment}. * * This installs any services that currently comprise the bundle and will install any services added in the future * as well. */ deploy(env: Environment) { for (const factory of this) { this.#deployFactory(factory, env); } this.#environments.add(new WeakRef(env)); } #deployFactory(factory: ServiceBundle.Factory, env: Environment) { try { factory(env); } catch (e) { let name = "factory"; if (factory.name) { name = `${name} ${factory.name}`; } logger.error(`Error deploying services for ${name}:`, e); } } } export namespace ServiceBundle { /** * A factory function invoked when a bundle is deployed. */ export interface Factory { (env: Environment): void; } }