GeoLeaf Core API - v3.19.0
    Preparing search index...

    Map of the GeoLeaf custom DOM events whose payload is JSON-serialisable.

    The membership criterion is the PAYLOAD, not the carrier — that is what makes this map's boundary a real one and not a stylistic split. dispatchGeoLeafEvent deep-clones every payload through JSON.parse(JSON.stringify(detail)) (kernel/events/event-bus.ts); a detail holding a DOM node, a function or a Map does not survive that round-trip, and belongs in GeoLeafRawEventMap instead. The two maps state one rule from both ends.

    The Events facade subscribes to both maps (kernel/events/facade.ts); only emission through the sanitising bus is restricted to this one.

    ⚠️ Being listed here does NOT mean the event travels through that bus — it means it COULD. This sentence used to read « events carried by the sanitising bus », which was narrower than the rule the two maps actually enforce, and it had no answer for the nine geoleaf:editor:* events: their payloads clone perfectly, but the editor dispatches them as raw CustomEvents and dispatchGeoLeafEvent is exported to no plugin. Reading the criterion as the carrier would have pushed them into the raw map, whose own warning — « adding a key here is a statement that the payload CANNOT be JSON-cloned » — they contradict. Arbitré par Mattieu : the payload decides, and the carrier is a separate question this contract deliberately does not type.

    interface GeoLeafEventMap {
        "geoleaf:app:ready": { version?: string; timestamp?: number };
        "geoleaf:map:ready": undefined;
        "geoleaf:boot:failed": {
            reason:
                | "config"
                | "map"
                | "profile"
                | "engine"
                | "webgl"
                | "module"
                | "timeout"
                | "internal";
            phase: "config"
            | "map"
            | "profile"
            | "before-boot"
            | "registry";
            message: string;
            module?: string;
            provisional: boolean;
            timestamp: number;
        };
        "geoleaf:profile:failed": {
            profileId: string;
            fatal: boolean;
            failures: {
                resource: string;
                url: string;
                required: boolean;
                message: string;
            }[];
        };
        "geoleaf:module:failed": {
            module: string;
            message: string;
            skipped: string[];
            timestamp: number;
        };
        "geoleaf:legend:ready": { position?: string; layerCount?: number };
        "geoleaf:basemap:change": { key: string; previousKey?: string | null };
        "geoleaf:theme:applied": { themeName?: string; layerCount?: number };
        "geoleaf:palette-changed": { palette: string };
        "geoleaf:poi:click": GeoLeafPoiClickDetail;
        "geoleaf:poi:panel:open": GeoLeafPoiPanelOpenDetail;
        "geoleaf:poi:panel:close": GeoLeafPoiPanelCloseDetail;
        "geoleaf:layer:toggle": GeoLeafLayerToggleDetail;
        "geoleaf:layer:added": GeoLeafLayerAddedDetail;
        "geoleaf:layer:updated": GeoLeafLayerUpdatedDetail;
        "geoleaf:feature:click": GeoLeafFeatureClickDetail;
        "geoleaf:feature:hover": GeoLeafFeatureHoverDetail;
        "geoleaf:filter:apply": GeoLeafFilterApplyDetail;
        "geoleaf:filter:reset": GeoLeafFilterResetDetail;
        "geoleaf:map:move": GeoLeafMapMoveDetail;
        "geoleaf:map:zoom": GeoLeafMapZoomDetail;
        "geoleaf:geojson:visibility-changed": GeoLeafLayerToggleDetail;
        "geoleaf:panel:opened": GeoLeafPanelToggleDetail;
        "geoleaf:panel:closed": GeoLeafPanelToggleDetail;
        "geoleaf:filters:applied": GeoLeafFiltersAppliedDetail;
        "geoleaf:sw:updated": Record<string, never>;
        "geoleaf:sw:update-waiting": Record<string, never>;
        "geoleaf:cache:evicted": GeoLeafCacheEvictedDetail;
        "geoleaf:offline:outbox-queued": GeoLeafOutboxQueuedDetail;
        "geoleaf:offline:outbox-drained": GeoLeafOutboxDrainedDetail;
        "geoleaf:offline:quarantine-exited": GeoLeafQuarantineExitedDetail;
        "geoleaf:offline:write-conflict": GeoLeafOfflineWriteConflictDetail;
        "geoleaf:offline:pull-progress": GeoLeafOfflinePullProgressDetail;
        "geoleaf:geolocation:statechange": GeoLeafGeolocationStateChangeDetail;
        "geoleaf:print:render:start": Record<string, never>;
        "geoleaf:print:render:end": Record<string, never>;
        "geoleaf:print:preview:ready": Record<string, never>;
        "geoleaf:plugin:loaded": GeoLeafPluginLoadedDetail;
        "geoleaf:plugin:lazy-loaded": GeoLeafPluginLazyLoadedDetail;
        "geoleaf:plugin:failed": GeoLeafPluginFailedDetail;
        "geoleaf:editor:feature-created": GeoLeafEditorFeatureCreatedDetail;
        "geoleaf:editor:feature-saved": GeoLeafEditorFeatureSavedDetail;
        "geoleaf:editor:feature-deleted": GeoLeafEditorFeatureDeletedDetail;
        "geoleaf:editor:feature-conflict": GeoLeafEditorFeatureConflictDetail;
        "geoleaf:editor:feature-moved": GeoLeafEditorFeatureMovedDetail;
        "geoleaf:editor:vertex-added": GeoLeafEditorVertexChangedDetail;
        "geoleaf:editor:vertex-deleted": GeoLeafEditorVertexChangedDetail;
        "geoleaf:editor:feature-sync-queued": GeoLeafEditorSyncQueuedDetail;
        "geoleaf:editor:feature-sync-flushed": GeoLeafEditorSyncFlushedDetail;
        "geoleaf:table:opened": Record<string, never>;
        "geoleaf:table:closed": Record<string, never>;
        "geoleaf:table:layerChanged": GeoLeafTableLayerChangedDetail;
        "geoleaf:table:sortChanged": GeoLeafTableSortChangedDetail;
        "geoleaf:table:selectionChanged": GeoLeafTableSelectionDetail;
        "geoleaf:table:zoomToSelection": GeoLeafTableSelectionDetail;
        "geoleaf:table:highlightSelection": GeoLeafTableHighlightDetail;
        "geoleaf:table:exportSelection": GeoLeafTableExportSelectionDetail;
        "geoleaf:table:exportLayer": GeoLeafTableExportLayerDetail;
        "geoleaf:table:rowActivated": GeoLeafTableRowActivatedDetail;
        "geoleaf:connector:token-refreshed": GeoLeafConnectorBaseUrlDetail;
        "geoleaf:connector:authenticated": GeoLeafConnectorBaseUrlDetail;
        "geoleaf:connector:signed-out": GeoLeafConnectorBaseUrlDetail;
        "geoleaf:connector:auth-error": GeoLeafConnectorAuthErrorDetail;
        "geoleaf:connector:login-failed": GeoLeafConnectorLoginFailedDetail;
        "geoleaf:connector:credential-button-clicked": GeoLeafConnectorCredentialClickDetail;
        "geoleaf:connector:signup-requested": GeoLeafConnectorLinkRequestDetail;
        "geoleaf:connector:forgot-password-requested": GeoLeafConnectorLinkRequestDetail;
    }
    Index
    geoleaf:app:ready geoleaf:map:ready geoleaf:boot:failed geoleaf:profile:failed geoleaf:module:failed geoleaf:legend:ready geoleaf:basemap:change geoleaf:theme:applied geoleaf:palette-changed geoleaf:poi:click geoleaf:poi:panel:open geoleaf:poi:panel:close geoleaf:layer:toggle geoleaf:layer:added geoleaf:layer:updated geoleaf:feature:click geoleaf:feature:hover geoleaf:filter:apply geoleaf:filter:reset geoleaf:map:move geoleaf:map:zoom geoleaf:geojson:visibility-changed geoleaf:panel:opened geoleaf:panel:closed geoleaf:filters:applied geoleaf:sw:updated geoleaf:sw:update-waiting geoleaf:cache:evicted geoleaf:offline:outbox-queued geoleaf:offline:outbox-drained geoleaf:offline:quarantine-exited geoleaf:offline:write-conflict geoleaf:offline:pull-progress geoleaf:geolocation:statechange geoleaf:print:render:start geoleaf:print:render:end geoleaf:print:preview:ready geoleaf:plugin:loaded geoleaf:plugin:lazy-loaded geoleaf:plugin:failed geoleaf:editor:feature-created geoleaf:editor:feature-saved geoleaf:editor:feature-deleted geoleaf:editor:feature-conflict geoleaf:editor:feature-moved geoleaf:editor:vertex-added geoleaf:editor:vertex-deleted geoleaf:editor:feature-sync-queued geoleaf:editor:feature-sync-flushed geoleaf:table:opened geoleaf:table:closed geoleaf:table:layerChanged geoleaf:table:sortChanged geoleaf:table:selectionChanged geoleaf:table:zoomToSelection geoleaf:table:highlightSelection geoleaf:table:exportSelection geoleaf:table:exportLayer geoleaf:table:rowActivated geoleaf:connector:token-refreshed geoleaf:connector:authenticated geoleaf:connector:signed-out geoleaf:connector:auth-error geoleaf:connector:login-failed geoleaf:connector:credential-button-clicked geoleaf:connector:signup-requested geoleaf:connector:forgot-password-requested
    "geoleaf:app:ready": { version?: string; timestamp?: number }
    "geoleaf:map:ready": undefined
    "geoleaf:boot:failed": {
        reason:
            | "config"
            | "map"
            | "profile"
            | "engine"
            | "webgl"
            | "module"
            | "timeout"
            | "internal";
        phase: "config"
        | "map"
        | "profile"
        | "before-boot"
        | "registry";
        message: string;
        module?: string;
        provisional: boolean;
        timestamp: number;
    }

    The boot could not complete. Emitted by app/boot-failure.ts, the first terminal failure winning. A watchdog expiry is the one PROVISIONAL case: a late reveal may still follow it, and geoleaf:app:ready is then the recovery signal.

    ⚠️ Dispatched CANCELABLE: a host that renders its own failure interface calls preventDefault(), and the default screen is not drawn in #gl-loader. The payload is JSON-safe, which is what places the key in this map. Subscribe BEFORE GeoLeaf.boot().

    reason: "engine" (since 3.13.0): no MapLibre GL JS engine was found when the map was built — neither globalThis.maplibregl nor the maplibregl boot option. A switch over this union that was exhaustive before needs the new case.

    Type Declaration

    • reason:
          | "config"
          | "map"
          | "profile"
          | "engine"
          | "webgl"
          | "module"
          | "timeout"
          | "internal"
    • phase: "config" | "map" | "profile" | "before-boot" | "registry"
    • message: string

      English, meant for logs and support — not a user-facing string.

    • Optionalmodule?: string
    • provisional: boolean

      true only for reason: "timeout": the boot may still complete.

    • timestamp: number
    "geoleaf:profile:failed": {
        profileId: string;
        fatal: boolean;
        failures: {
            resource: string;
            url: string;
            required: boolean;
            message: string;
        }[];
    }

    Resources the active profile DECLARES could not be obtained — an HTTP error, invalid JSON, or a declared section absent from the profile bundle. A file the profile does not declare is never reported. Emitted before geoleaf:profile:loaded; fatal: true means profile.json itself failed, and geoleaf:profile:loaded does not follow.

    ⚠️ Cancelable, like geoleaf:boot:failed: preventDefault() suppresses the default screen that names the failed resources, and the reveal then proceeds untouched.

    "geoleaf:module:failed": {
        module: string;
        message: string;
        skipped: string[];
        timestamp: number;
    }

    A module's init() threw during the boot, and the application goes on without it and without the modules that depend on it (skipped). Emitted by app/boot-failure.ts. A failure the interface cannot survive is not this event: it is geoleaf:boot:failed with reason: "module".

    ⚠️ Cancelable: preventDefault() suppresses the default signal — the screen that holds the reveal and names the module, or the warning once the application is revealed.

    Type Declaration

    • module: string
    • message: string

      English, meant for logs and support — not a user-facing string.

    • skipped: string[]

      The modules that did not run because they depend on it, in initialisation order.

    • timestamp: number
    "geoleaf:legend:ready": { position?: string; layerCount?: number }

    Emitted once when the legend control is first mounted on the map (S10 F2).

    "geoleaf:basemap:change": { key: string; previousKey?: string | null }
    "geoleaf:theme:applied": { themeName?: string; layerCount?: number }
    "geoleaf:palette-changed": { palette: string }

    Emitted when the accent palette changes (capability theme-palette). Distinct from geoleaf:theme:applied (MAP themes) and from geoleaf:ui-theme-changed (light/dark) — the three axes are orthogonal.

    "geoleaf:poi:click": GeoLeafPoiClickDetail
    "geoleaf:poi:panel:open": GeoLeafPoiPanelOpenDetail
    "geoleaf:poi:panel:close": GeoLeafPoiPanelCloseDetail
    "geoleaf:layer:toggle": GeoLeafLayerToggleDetail
    "geoleaf:layer:added": GeoLeafLayerAddedDetail
    "geoleaf:layer:updated": GeoLeafLayerUpdatedDetail

    A layer's store changed — see GeoLeafLayerUpdatedDetail for what does and does not fire it.

    "geoleaf:feature:click": GeoLeafFeatureClickDetail
    "geoleaf:feature:hover": GeoLeafFeatureHoverDetail
    "geoleaf:filter:apply": GeoLeafFilterApplyDetail
    "geoleaf:filter:reset": GeoLeafFilterResetDetail
    "geoleaf:map:move": GeoLeafMapMoveDetail
    "geoleaf:map:zoom": GeoLeafMapZoomDetail
    "geoleaf:geojson:visibility-changed": GeoLeafLayerToggleDetail

    A layer's visibility changed — HISTORICAL form.

    ⚠️ geoleaf:layer:toggle is the CANONICAL event, and it carries the same payload. This one predates it, has internal subscribers (permalink-sync.ts, the table plugin) and a declared downstream consumer — so it is typed for what it is, not promoted. An integrator writing new code takes geoleaf:layer:toggle.

    🛑 The two buses do not carry the same thing, and that is measured, not assumed. visibility-manager.ts fires on the map on EVERY change, but re-dispatches on document only when source !== "zoom" — a deliberate filter, to avoid flooding subscribers during a zoom recalculation. A subscriber via Events.on (thus document) will therefore never see source: "zoom", where map.on does.

    The type still keeps the full union: it is exact on the map, and only too wide on the document. The opposite — narrowing to three values — would become FALSE at the first loosening of the filter, and silently so, an integrator's exhaustive switch ceasing to cover a case it receives.

    "geoleaf:panel:opened": GeoLeafPanelToggleDetail

    The tabbed side panel just opened a tab.

    Emitted on BOTH paths — the tab click and the programmatic call GeoLeaf.UI.openPanel(tabId) — because an event describing only the programmatic path would be half a contract: users open with the mouse.

    "geoleaf:panel:closed": GeoLeafPanelToggleDetail

    The tabbed side panel just closed a tab.

    ⚠️ A tab switch yields closed THEN opened, in that order: the old tab is really closed. Opening while nothing was open yields only opened — there is no empty closed.

    "geoleaf:filters:applied": GeoLeafFiltersAppliedDetail

    A filter pass has just run — because the filter was applied, or because a layer was written under an active filter: see GeoLeafFiltersAppliedDetail for the two reasons, and for the loop a listener must not close.

    "geoleaf:sw:updated": Record<string, never>

    A new service worker ACTIVATED: it now serves the pages of its scope.

    ⚠️ Not "an update is available" — see geoleaf:sw:update-waiting for that. This one also fires at a first install, when the first worker takes the page.

    "geoleaf:sw:update-waiting": Record<string, never>

    A new version of the application is installed and WAITS: its service worker will not take a page that is in use until GeoLeaf.PWA.applyUpdate() is called, or until every tab it serves is closed.

    Emitted once per waiting worker — when its install completes, or when a page boots onto one that was already waiting. Never at a first install. ⚠️ A listener set after the boot may have missed it: read GeoLeaf.PWA.isUpdateWaiting() as well.

    "geoleaf:cache:evicted": GeoLeafCacheEvictedDetail
    "geoleaf:offline:outbox-queued": GeoLeafOutboxQueuedDetail
    "geoleaf:offline:outbox-drained": GeoLeafOutboxDrainedDetail
    "geoleaf:offline:quarantine-exited": GeoLeafQuarantineExitedDetail
    "geoleaf:offline:write-conflict": GeoLeafOfflineWriteConflictDetail
    "geoleaf:offline:pull-progress": GeoLeafOfflinePullProgressDetail
    "geoleaf:geolocation:statechange": GeoLeafGeolocationStateChangeDetail
    "geoleaf:print:render:start": Record<string, never>
    "geoleaf:print:render:end": Record<string, never>
    "geoleaf:print:preview:ready": Record<string, never>
    "geoleaf:plugin:loaded": GeoLeafPluginLoadedDetail
    "geoleaf:plugin:lazy-loaded": GeoLeafPluginLazyLoadedDetail
    "geoleaf:plugin:failed": GeoLeafPluginFailedDetail
    "geoleaf:editor:feature-created": GeoLeafEditorFeatureCreatedDetail
    "geoleaf:editor:feature-saved": GeoLeafEditorFeatureSavedDetail
    "geoleaf:editor:feature-deleted": GeoLeafEditorFeatureDeletedDetail
    "geoleaf:editor:feature-conflict": GeoLeafEditorFeatureConflictDetail
    "geoleaf:editor:feature-moved": GeoLeafEditorFeatureMovedDetail
    "geoleaf:editor:vertex-added": GeoLeafEditorVertexChangedDetail
    "geoleaf:editor:vertex-deleted": GeoLeafEditorVertexChangedDetail
    "geoleaf:editor:feature-sync-queued": GeoLeafEditorSyncQueuedDetail
    "geoleaf:editor:feature-sync-flushed": GeoLeafEditorSyncFlushedDetail
    "geoleaf:table:opened": Record<string, never>
    "geoleaf:table:closed": Record<string, never>
    "geoleaf:table:layerChanged": GeoLeafTableLayerChangedDetail
    "geoleaf:table:sortChanged": GeoLeafTableSortChangedDetail
    "geoleaf:table:selectionChanged": GeoLeafTableSelectionDetail
    "geoleaf:table:zoomToSelection": GeoLeafTableSelectionDetail
    "geoleaf:table:highlightSelection": GeoLeafTableHighlightDetail
    "geoleaf:table:exportSelection": GeoLeafTableExportSelectionDetail
    "geoleaf:table:exportLayer": GeoLeafTableExportLayerDetail
    "geoleaf:table:rowActivated": GeoLeafTableRowActivatedDetail
    "geoleaf:connector:token-refreshed": GeoLeafConnectorBaseUrlDetail
    "geoleaf:connector:authenticated": GeoLeafConnectorBaseUrlDetail
    "geoleaf:connector:signed-out": GeoLeafConnectorBaseUrlDetail

    The session was ended deliberately — Connector.logout().

    ⚠️ Its counterpart :auth-error says the session DIED; this one says it was closed. A host that clears its own view on sign-out must be able to tell the two apart: one calls for a login window, the other precisely does not.

    "geoleaf:connector:auth-error": GeoLeafConnectorAuthErrorDetail
    "geoleaf:connector:login-failed": GeoLeafConnectorLoginFailedDetail

    A sign-in was refused or could not conclude — no session was opened.

    "geoleaf:connector:credential-button-clicked": GeoLeafConnectorCredentialClickDetail
    "geoleaf:connector:signup-requested": GeoLeafConnectorLinkRequestDetail

    ⚠️ Cancelable — preventDefault() prevents the navigation to url.

    "geoleaf:connector:forgot-password-requested": GeoLeafConnectorLinkRequestDetail

    ⚠️ Cancelable — preventDefault() prevents the navigation to url.