Docs/API Reference/Plugins

Registry

PluginRegistry is the single source of truth for registered plugins, their persisted enable/install status, extension/widget/hook resolution, and lifecycle orchestration. It is…

3 min read

PluginRegistry is the single source of truth for registered plugins, their persisted enable/install status, extension/widget/hook resolution, and lifecycle orchestration. It is registered in the IoC container by PluginsServiceProvider and reached at runtime through the bound plugins context (or the module-level facade helpers).

PluginRegistry#

@Injectable() class constructed with @Inject(PLUGIN_REPOSITORY), @Inject(MIGRATION_RUNNER), @Inject(LOGGER) and @Inject(EVENT_BUS).

MethodBehavior
register(plugin)Registers a plugin (and its nested plugins) by manifest.id; re-registers in development for HMR.
init()Idempotent bootstrap: publishes system:plugins:init:start, seeds statuses, loads the DB status, topologically sorts plugins, runs migrations and onMigrate/onEnable/init for enabled-but-not-installed plugins, then publishes system:plugins:init:end.
getPlugins()All registered plugins.
getEnabledPlugins()Plugins whose runtime status is enabled.
getPlugin(id)A plugin by id.
getPluginsStatus()Manifests merged with persisted/in-memory status (enabled, installed, lastStep).
getPluginStatus(id)Status for one plugin, or null.
getHooks(point)Enabled plugins' hooks for a point, sorted by priority (default 100).
getExtensions(target, point, includeDisabled?, context?)Extensions for a slot, filtered by context.roles/context.permissions and sorted by priority.
getWidgets(area, context?)Widgets for an area, filtered by context.roles/context.permissions and sorted by priority.
togglePlugin(id, enabled, context?)Enables/disables a plugin, cascading dependency activation and dependent deactivation, running migrations and onEnable/onDisable, and publishing system:plugin:toggle.
hasHooks(point) / hasExtension(target, point?)Boolean checks over enabled plugins.
getConfig<T>(id)Parses the stored JSON config, or null.
updateConfig(id, config)Stores the JSON config.

Notes from the implementation:

  • Plugin ids are normalized: an npm dependency like @veap/media-plugin resolves to the registered id media-plugin (resolveDependencyId).
  • getHooks/getExtensions/getWidgets are async even though the work is in-memory.
  • Role filtering is OR across roles; permission filtering requires all listed permissions.
  • togglePlugin rolls back in-memory status when a state-transition write fails, and processes dependency activation/deactivation recursively (guarding against cycles).

Contracts#

The /registry entry point (and the root barrel) export the persistence and migration ports:

  • PluginStatusRecord (alias PluginRecord): id, enabled, installed, system, config?, lastStep?.
  • PluginRuntimeStatus: enabled, installed, lastStep?.
  • UpsertPluginStatusRecord: enabled?, installed?, lastStep?.
  • IPluginRepository: findAll(), findById(id), seed(values), upsertStatus(id, update, defaults), updateConfig(id, configJson).
  • IMigrationRunner: run(scope, migrations), rollback(scope, migrations).
  • Tokens: PLUGIN_REPOSITORY, MIGRATION_RUNNER.
  • ActiveRecordPluginRepository and KnexMigrationRunner are the default implementations used by the provider.

Module-level facade#

registry/facade.ts exposes composition-bound helpers that read the bound plugins context instead of resolving the container themselves:

HelperBehavior
registerPlugins(plugins)Registers each plugin on the context registry.
ensurePluginsInitialized()Calls registry.init().
applyPluginFilters(point, data, context?)Runs the hooks for point in priority order, threading data through each handler.
togglePluginState(id, enabled, context?)Delegates to registry.togglePlugin.
hasPluginHooks(point)Boolean check.
hasPluginExtension(target, point?)Boolean check.
getPluginConfig(id) / updatePluginConfig(id, config)Config read/write.
getPluginsStatus() / getPluginStatus(id)Status reads.

facade.ts also re-exports several aliases used by the older module API (for example applyFilters, getModule, toggleModuleState) via server.ts; prefer the *Plugin* names.

Context binding#

The registry is reached through pluginsContext(), a globalThis-bound object ({ registry, navigation, router? }) that PluginsServiceProvider.boot() binds via bindPluginsContext. Calling pluginsContext() before boot throws AppError.Internal. isPluginsContextBound() reports whether it is available (used by PluginExtensionPoint to fall back gracefully).

Events#

  • system:plugins:init:start / system:plugins:init:end — published around registry initialization (init:end carries { timestamp, pluginCount }).
  • system:plugin:toggle — published after a toggle with { pluginId, isEnabled }; the provider subscribes to clear the router cache.
veap
Preparing0%