ConstRegisters a plugin as loaded. Called automatically by globals.js and plugin files.
Plugin identifier (e.g. 'editor', 'measure', 'connector')
Optionalmetadata: PluginMetadata = {}
Optional metadata { version, requires, optional }
Registers a lazy resolver (called by bundle-entry.js).
() => Promise
Registers a capability declaration so it can be queried via
GeoLeaf.Introspection.getCapabilitySchema() / getAllCapabilities().
Idempotent — registering the same id twice is a no-op.
The declaration's optional loader is called at most once, on demand,
via CapabilityRegistry.ensureLoaded().
Capability declaration (id, gate, configSchema, loader…).
Registers a layer loader for a plugin-backed declarative layer.
Called by a plugin (e.g. flatgeobuf) so the core profile loader can render
layers declared with "plugin": "<id>" in a profile config — without the
core referencing any plugin by name.
Plugin identifier matching the layer config plugin field.
Async loader (def) => Promise
Returns the layer loader registered for the given plugin id, or undefined.
Returns true if the plugin is registered lazy but not yet loaded. Used by toolbar guards to show buttons before the bundle downloads.
Associates a toolbar action with a lazy plugin and its UI descriptor.
Call before GeoLeaf.boot() (e.g. from init.js) for each lazy plugin.
Each descriptor carries icon, labelKey, action, the visibility keys profileKey
and legacyProfileKey (read only when the first is absent from the configuration), and
— on desktopTabButton — variant: "icon" (default) or "tab".
toolbar action id (e.g. "print")
plugin registry name (e.g. "print")
Optionalui: PluginLazyUI
optional UI descriptor { mobileIcon?, desktopTabButton? }
// The print slot, as the reference application declares it.
const icon = "<svg viewBox='0 0 24 24'></svg>";
GeoLeaf?.plugins?.registerLazyForAction?.("print", "print", {
gateOnModuleEnabled: true,
mobileIcon: {
icon,
labelKey: "print.toolbar.button",
profileKey: "modules.print.showButton",
legacyProfileKey: "ui.showPrint",
action: "print",
},
desktopTabButton: {
icon,
labelKey: "print.toolbar.button",
profileKey: "modules.print.showButton",
legacyProfileKey: "ui.showPrint",
action: "print",
},
});
Returns true if the action is backed by a lazy plugin that is not yet loaded. Used by the toolbar interceptor before dispatching actions.
Loads the plugin backing the given action if it is lazy and not yet loaded. No-op if the plugin is already loaded or the action is not lazy.
Returns the UI descriptors of every plugin registered lazy — its bundle loaded or not.
Consumed by the toolbar renderers, which run again at every boot: a slot declared with PluginRegistry.registerLazyForAction draws its button before the bundle downloads, and draws it AGAIN when the application is unmounted and mounted once the bundle is loaded.
⚠️ It used to leave the loaded plugins out, and that is what took their button away at
the next GeoLeaf.mount(): a bundle that loads after init() keeps its slot out of the
module registry — the toolbar is built by then — so the rebuilt toolbar found the plugin
in neither list. A renderer does not read this list alone: a slot the module registry
declares under the same id belongs to the plugin, which loaded before the boot — see
lazySlotsToDraw() in kernel/ui/ui-slot-builder.ts.
A click on the button of a loaded plugin emits its action at once: PluginRegistry.isLazyAction still answers for the plugins NOT loaded yet.
Checks if a plugin is currently loaded.
Checks if a plugin can be activated (its requires dependencies are loaded).
Lazily loads a plugin by name.
Returns the list of loaded plugin names.
Returns the list of all availabthe modules (loaded + lazy available).
Prints a console report of loaded plugins (non-core). Silent if none.
There is ONE report, and that is deliberate. Two reports existed until
04/07/2026, splitting the registry on a manifest field backed by two
hard-coded name sets that OVERRODE the declared value — and disagreed with
it in both directions, so storage and editor each appeared in BOTH
reports and every boot double-counted them. A single report has no name set
to keep in sync, and therefore no way to drift. Do not partition it again.
name → registered plugin entry.
name → lazy resolver.
Lazy plugin UI descriptors — keyed by action name.
Layer loaders registered by plugins to render declarative plugin: layers.
Registry of mounted plugins, keyed by name.
The plugin counterpart of CapabilityRegistry. Registration is what puts a plugin's namespace on the global, so a plugin absent from here is absent from
GeoLeaf.*— which is the usual explanation for an integrator's call landing onundefined.