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

    Interface GeoLeafGlobal

    Canonical shape of the global GeoLeaf namespace. All members are optional (assembled at boot) and tolerate extra keys.

    interface GeoLeafGlobal {
        DEBUG?: boolean;
        UI?: GeoLeafUIFacade;
        _UITheme?: {
            initThemeToggle: (...args: unknown[]) => unknown;
            initAutoTheme: (...args: unknown[]) => unknown;
            toggleTheme: (...args: unknown[]) => unknown;
            applyTheme: (...args: unknown[]) => unknown;
            getCurrentTheme: () => string;
            [key: string]: unknown;
        };
        _UINotifications?: {
            show: (...args: unknown[]) => unknown;
            success: (...args: unknown[]) => unknown;
            error: (...args: unknown[]) => unknown;
            warning: (...args: unknown[]) => unknown;
            info: (...args: unknown[]) => unknown;
            clearAll: (...args: unknown[]) => unknown;
            enable: (...args: unknown[]) => unknown;
            disable: (...args: unknown[]) => unknown;
            getStatus: (...args: unknown[]) => unknown;
            [key: string]: unknown;
        };
        _UIEventDelegation?: {
            attachAccordionEvents: (...args: unknown[]) => unknown;
            cleanupAllListeners: () => number;
            [key: string]: unknown;
        };
        Filter?: {
            isEnabled(): boolean;
            getConfig(): unknown;
            getActiveFilter(): unknown;
            applyFilter(state: unknown): void;
            applyNow(): void;
            reset(): void;
            hasActiveFilters(): boolean;
            proximity: {
                setRadius(radiusKm: number): void;
                toggle(
                    map: unknown,
                    radiusKm?: number,
                    options?: { onPointPlaced?: () => void },
                ): boolean;
            };
        };
        Config?: {
            get(key: string, def?: unknown): unknown;
            getAll(): Record<string, unknown>;
            getActiveProfile?(): unknown;
            clearThemesCache(profileId?: string): void;
            [key: string]: unknown;
        };
        Utils?: {
            createElement?: (
                tag: string,
                props: Record<string, unknown>,
                ...children: unknown[],
            ) => HTMLElement;
            events?: GeoLeafUtilsEvents;
            applyCssText?: (el: HTMLElement, css: string) => void;
            validateUrl?: (
                url: string | null | undefined,
                allowedProtocols?: string[],
            ) => string | null;
            getDistance?: (
                lat1: number,
                lng1: number,
                lat2: number,
                lng2: number,
            ) => number;
            Formatters?: {
                formatDateTime: (
                    date: string | number | Date,
                    options?: FormatDateOptions,
                ) => string;
                formatFileSize: (
                    bytes: number | null | undefined,
                    options?: FormatFileSizeOptions,
                ) => string;
                toMB: (bytes: number | null | undefined, precision?: number) => string;
                toGB: (bytes: number | null | undefined, precision?: number) => string;
            };
            DOMSecurity?: {
                setTextContent: (
                    element: HTMLElement | null | undefined,
                    text: string | number | null | undefined,
                ) => void;
                setSafeHTML: (
                    element: HTMLElement,
                    html: string,
                    allowedTags?: string[],
                ) => void;
                clearElement: (element: HTMLElement | null | undefined) => void;
                clearElementFast: (element: HTMLElement | null | undefined) => void;
                createSVGIcon: (
                    width: number,
                    height: number,
                    pathData: string,
                    options?: SVGIconOptions,
                ) => SVGElement;
                getIcon: (
                    name: string,
                    size?: number,
                    options?: SVGIconOptions,
                ) => SVGElement | null;
                SVG_ICONS: Record<string, string>;
            };
            [key: string]: unknown;
        };
        DOMSecurity?: {
            setSafeHTML(element: HTMLElement, html: string): void;
            [key: string]: unknown;
        };
        Security?: { escapeHtml?: (s: unknown) => string; [key: string]: unknown };
        Legend?: {
            init(mapInstance: unknown, options?: Record<string, unknown>): boolean;
            loadLayerLegend(
                layerId: string,
                styleId: string,
                layerConfig: unknown,
            ): void;
            setLayerVisibility(layerId: string, visible: boolean): void;
            getAllLayers(): Map<string, unknown>;
            hideLegend(): void;
            removeLegend(): void;
            isLegendVisible(): boolean;
            toggleAccordion: (id: string) => void;
            [key: string]: unknown;
        };
        Taxonomy?: {
            isEnabled(): boolean;
            getIcons(): TaxonomyIconsConfig | null;
            getCategories(ref: string): Record<string, TaxonomyCategory>;
            getFieldMappings(ref: string): TaxonomyFieldMappings;
            getLayerCategories(layerId: string): Record<string, TaxonomyCategory>;
            resolvePoiIcon(poi: TaxonomyFeatureLike): ResolvedIcon;
            getIconVariants(): TaxonomyIconVariant[];
            resolveMarkerPaint(
                layerId: string,
                existingPaint: Record<string, unknown>,
            ): Record<string, unknown> | null;
            resolveTitleIcon(
                layerId: string,
                feature: TaxonomyFeatureLike,
                surface: TaxonomySurface,
            ): string | null;
            resolveBadgeStyle(
                layerId: string,
                feature: TaxonomyFeatureLike,
                surface: TaxonomySurface,
                field: string,
            ): ResolvedBadgeStyle | null;
            ensureSprite(): void;
            [key: string]: unknown;
        };
        _LegendControl?: {
            create: (opts: unknown) => unknown;
            [key: string]: unknown;
        };
        _LegendGenerator?: {
            generateLegendFromStyle: (
                styleData: unknown,
                geometryType: string,
                taxonomyData: unknown,
            ) => unknown;
            [key: string]: unknown;
        };
        _LayerVisibilityManager?: {
            getVisibilityState: (layerId: string) => { current?: boolean } | null;
            [key: string]: unknown;
        };
        Sync?: {
            registerHandler(id: string, handler: SyncHandler): void;
            getHandler(id: string): SyncHandler | undefined;
            registerBeforeDrain(id: string, step: BeforeDrainStep | null): void;
            registerSessionReader(reader: SessionReader | null): void;
        };
        ThemeSelector?: GeoLeafThemeSelector;
        _VectorTiles?: {
            shouldUseVectorTiles(def: VtLayerDef): boolean;
            _getVTConfig(def: VtLayerDef | null): VtConfig | null;
            _resolveTileUrl(def: VtLayerDef, vtConfig: VtConfig): string | null;
            loadVectorTileLayer(
                layerId: string,
                layerLabel: string,
                def: VtLayerDef,
                _baseOptions: Record<string, unknown>,
            ): Promise<
                {
                    id: string;
                    label: string;
                    featureCount: number;
                    isVectorTile: boolean;
                },
            >;
            updateLayerStyle(
                layerId: string,
                styleData: GeoJSONCurrentStyle | null,
            ): void;
        };
        _Cluster?: {
            getClusteringStrategy: (
                def: ClusterLayerDef,
                geojsonData: ClusterGeoJSONData,
            ) => ClusterStrategyResult;
            applyGeoJSONClusterOptions: (
                adapterOptions: Record<string, unknown>,
                def: ClusterLayerDef,
                layerId: string,
                Log: GeoJSONLoaderLog,
            ) => void;
        };
        Introspection?: IIntrospectionAPI;
        Capabilities?: ICapabilitiesAPI;
        Layers?: LayerDataApi;
        Geolocation?: GeolocationPublicApi;
        Branding?: BrandingPublicApi;
        Cluster?: ClusterPublicApi;
        Coordinates?: CoordinatesPublicApi;
        FeatureInfo?: FeatureInfoPublicApi;
        Labels?: LabelsPublicApi;
        NotificationSystem?: typeof NotificationSystem;
        PWA?: {
            init(config: PWAConfig): void;
            isInstallable(): boolean;
            isUpdateWaiting(): boolean;
            applyUpdate(): boolean;
            _reset(): void;
        };
        Permalink?: {
            init(config: PermalinkConfig): void;
            readAndStore(): void;
            applyStoredState(map: IMapAdapter): void;
            startSync(map: IMapAdapter): void;
            stopSync(): void;
            getState(): PermalinkState | null;
            buildUrl(state?: PermalinkState | null): string;
            isEnabled(): boolean;
            getConfig(): PermalinkConfig;
        };
        Scale?: ScalePublicApi;
        ProfileSwitcher?: ProfileSwitcherPublicApi;
        LanguageSwitcher?: LanguageSwitcherPublicApi;
        ThemePalette?: ThemePalettePublicApi;
        Share?: SharePublicApi;
        ThemeToggle?: ThemeTogglePublicApi;
        Baselayers?: {
            init: (
                options?: BaselayersInitOptions,
            ) => { activeKey: string | null; layers: Record<string, unknown> };
            registerBaseLayer: (key: string, definition: BasemapDefinition) => void;
            registerBaseLayers: (
                definitions: Record<string, BasemapDefinition>,
            ) => void;
            setBaseLayer: (key: string, options?: SetBaseLayerOptions) => void;
            setActive: (key: string, options?: SetBaseLayerOptions) => void;
            refreshBasemap: () => void;
            getBaseLayers: () => { [key: string]: BaseLayerEntry };
            getActiveKey: () => string | null;
            getActiveId: () => string | null;
            getActiveLayer: () => BasemapDefinition | null;
            destroy: () => void;
        };
        BaseLayers?: {
            init: (
                options?: BaselayersInitOptions,
            ) => { activeKey: string | null; layers: Record<string, unknown> };
            registerBaseLayer: (key: string, definition: BasemapDefinition) => void;
            registerBaseLayers: (
                definitions: Record<string, BasemapDefinition>,
            ) => void;
            setBaseLayer: (key: string, options?: SetBaseLayerOptions) => void;
            setActive: (key: string, options?: SetBaseLayerOptions) => void;
            refreshBasemap: () => void;
            getBaseLayers: () => { [key: string]: BaseLayerEntry };
            getActiveKey: () => string | null;
            getActiveId: () => string | null;
            getActiveLayer: () => BasemapDefinition | null;
            destroy: () => void;
        };
        Events?: {
            on<K extends (keyof GeoLeafEventMap) | (keyof GeoLeafRawEventMap)>(
                event: K,
                handler: GeoLeafEventHandler<K>,
            ): () => void;
            off<K extends (keyof GeoLeafEventMap) | (keyof GeoLeafRawEventMap)>(
                event: K,
                handler: GeoLeafEventHandler<K>,
            ): void;
            once<K extends (keyof GeoLeafEventMap) | (keyof GeoLeafRawEventMap)>(
                event: K,
                handler: GeoLeafEventHandler<K>,
            ): () => void;
        };
        events?: {
            on<K extends (keyof GeoLeafEventMap) | (keyof GeoLeafRawEventMap)>(
                event: K,
                handler: GeoLeafEventHandler<K>,
            ): () => void;
            off<K extends (keyof GeoLeafEventMap) | (keyof GeoLeafRawEventMap)>(
                event: K,
                handler: GeoLeafEventHandler<K>,
            ): void;
            once<K extends (keyof GeoLeafEventMap) | (keyof GeoLeafRawEventMap)>(
                event: K,
                handler: GeoLeafEventHandler<K>,
            ): () => void;
        };
        CONSTANTS?: Readonly<
            {
                DEFAULT_ZOOM: 3;
                DEFAULT_CENTER: [number, number];
                MAX_ZOOM_ON_FIT: 15;
                POI_MARKER_SIZE: 12;
                POI_MAX_ZOOM: 18;
                POI_SWIPE_THRESHOLD: 50;
                POI_LIGHTBOX_TRANSITION_MS: 300;
                POI_SIDEPANEL_DEFAULT_WIDTH: 420;
                ROUTE_MAX_ZOOM_ON_FIT: 14;
                ROUTE_WAYPOINT_RADIUS: 5;
                GEOJSON_MAX_ZOOM_ON_FIT: 15;
                GEOJSON_POINT_RADIUS: 6;
                FULLSCREEN_TRANSITION_MS: 10;
            },
        >;
        Errors?: {
            GeoLeafError: typeof GeoLeafError;
            ValidationError: typeof ValidationError;
            SecurityError: typeof SecurityError;
            ConfigError: typeof ConfigError;
            NetworkError: typeof NetworkError;
            InitializationError: typeof InitializationError;
            MapError: typeof MapError;
            DataError: typeof DataError;
            POIError: typeof POIError;
            RouteError: typeof RouteError;
            UIError: typeof UIError;
            normalizeError: (error: unknown, defaultMessage?: string) => GeoLeafError;
            isErrorType: (error: unknown, ErrorClass: typeof GeoLeafError) => boolean;
            getErrorCode: (error: unknown) => string;
            createError: (
                ErrorClass: ErrorClassConstructor,
                message: string,
                context?: ErrorContext,
            ) => GeoLeafError;
            createErrorByType: (
                type: string,
                message: string,
                context?: ErrorContext,
            ) => GeoLeafError;
            sanitizeErrorMessage: (message: unknown, maxLength?: number) => string;
            safeErrorHandler: (
                handler: ((err: unknown) => void) | undefined,
                error: unknown,
            ) => void;
            ErrorCodes: Readonly<
                {
                    VALIDATION: "VALIDATION_ERROR";
                    SECURITY: "SECURITY_ERROR";
                    CONFIG: "CONFIG_ERROR";
                    NETWORK: "NETWORK_ERROR";
                    INITIALIZATION: "INITIALIZATION_ERROR";
                    MAP: "MAP_ERROR";
                    DATA: "DATA_ERROR";
                    POI: "POI_ERROR";
                    ROUTE: "ROUTE_ERROR";
                    UI: "UI_ERROR";
                },
            >;
        };
        Helpers?: {
            getElementById: (id: string | null | undefined) => HTMLElement | null;
            querySelector: (selector: string, parent?: ParentNode) => Element | null;
            querySelectorAll: (selector: string, parent?: ParentNode) => Element[];
            applyCssText: (el: HTMLElement, css: string) => void;
            addClass: (
                element: Element | null | undefined,
                ...classNames: string[],
            ) => void;
            removeClass: (
                element: Element | null | undefined,
                ...classNames: string[],
            ) => void;
            toggleClass: (
                element: Element | null | undefined,
                className: string,
                force?: boolean,
            ) => boolean;
            hasClass: (
                element: Element | null | undefined,
                className: string,
            ) => boolean;
            removeElement: (element: Node | null | undefined) => void;
            requestFrame: (callback: FrameRequestCallback) => number;
            cancelFrame: (id: number) => void;
            createAbortController: (timeout?: number) => AbortController;
            lazyLoadImage: (
                img: HTMLImageElement,
                options?: { threshold?: number },
            ) => void;
            lazyExecute: (callback: () => void, timeout?: number) => void;
            clearObject: (obj: Record<string, unknown> | null | undefined) => void;
            createFragment: (children?: HTMLElement[]) => DocumentFragment;
            addEventListener: (
                element: EventTarget | null | undefined,
                event: string,
                handler: EventListenerOrEventListenerObject,
                options?: boolean | AddEventListenerOptions,
            ) => () => void;
            addEventListeners: (
                element: EventTarget | null | undefined,
                events: Record<string, EventListenerOrEventListenerObject>,
                options?: boolean | AddEventListenerOptions,
            ) => () => void;
            delegateEvent: (
                parent: EventTarget | null | undefined,
                event: string,
                selector: string,
                handler: (this: Element, e: Event) => void,
            ) => () => void;
            deepClone: <T>(obj: T, seen?: WeakMap<object, unknown>) => T;
            isEmpty: (value: unknown) => boolean;
            wait: (ms: number) => Promise<void>;
            retryWithBackoff: <T>(
                fn: () => Promise<T>,
                maxRetries?: number,
                delay?: number,
            ) => Promise<T>;
        };
        LayerManager?: {
            init(options?: Partial<LayerManagerOptions>): LMControlInstance | null;
            _registerGeoJsonLayer(
                layerId: string,
                options?: RegisterLayerOptions,
            ): void;
            refresh(immediate?: boolean): void;
            _reset(): void;
        };
        ThemeCache?: {
            _config: { enabled: boolean; maxAge: number };
            get(layerId: string, profileId?: string | null): Promise<unknown>;
            store(
                layerId: string,
                profileId?: string | null,
                data: string | object | ArrayBuffer,
                metadata?: Record<string, unknown>,
            ): Promise<void>;
            invalidate(layerId: string): Promise<void>;
        };
        Validators?: {
            validateCoordinates: (
                lat: number,
                lng: number,
                options?: ValidatorOptions,
            ) => { valid: boolean; error: string | null };
            validateUrl: (
                url: string,
                options?: ValidateUrlOptions,
            ) => { valid: boolean; error: string | null; url: string | null };
            validateEmail: (
                email: unknown,
                options?: ValidatorOptions,
            ) => { valid: boolean; error: string | null };
            validatePhone: (
                phone: unknown,
                options?: ValidatorOptions,
            ) => { valid: boolean; error: string | null };
            validateZoom: (
                zoom: number,
                options?: ValidateZoomOptions,
            ) => { valid: boolean; error: string | null };
            validateRequiredFields: (
                config: Record<string, unknown> | null | undefined,
                requiredFields: string[],
                options?: ValidatorOptions,
            ) => { valid: boolean; error: string | null; missing: string[] };
            validateGeoJSON: (
                geojson: Record<string, unknown> | null | undefined,
                options?: ValidatorOptions,
            ) => { valid: boolean; error: string | null };
            validateColor: (
                color: unknown,
                options?: ValidatorOptions,
            ) => { valid: boolean; error: string | null };
            validateBatch: (validations: ValidateBatchItem[]) => ValidationResult;
        };
        version?: string;
        API?: GeoLeafApiConstructors;
        init?: (options: Record<string, unknown>) => unknown;
        setTheme?: (theme: string) => boolean;
        loadConfig?: (input: string | Record<string, unknown>) => Promise<unknown>;
        createMap?: (id: string, options?: Record<string, unknown>) => unknown;
        getMap?: (id: string) => unknown;
        getAllMaps?: () => unknown[];
        getModule?: (name: string) => unknown;
        hasModule?: (name: string) => boolean;
        getNamespace?: (name: string) => unknown;
        getHealth?: () => unknown;
        getMetrics?: () => unknown;
        fetch?: (url: string, options?: FetchHelperOptions) => Promise<unknown>;
        get?: (url: string, options?: FetchHelperOptions) => Promise<unknown>;
        post?: (
            url: string,
            data: unknown,
            options?: FetchHelperOptions,
        ) => Promise<unknown>;
        bootInfo?: {
            show: (
                GeoLeaf: BootInfoNamespace | null | undefined,
                options?: BootInfoOptions,
            ) => void;
            detectPlugins: (GeoLeaf: BootInfoNamespace) => string[];
            buildMessage: (GeoLeaf: BootInfoNamespace) => BootMessage;
        };
        boot?: (options?: BootOptions) => void;
        mount?: (el: string | HTMLElement, options?: BootOptions) => GeoLeafMount;
        mark?: (name: string) => void;
        measure?: (name: string, startMark: string, endMark?: string) => number;
        getPerformanceReport?: () => Record<string, unknown>;
        establishBaseline?: () => Record<string, unknown>;
        notify?: (message: string, level?: NotifyLevel) => void;
        Core?: {
            init(options?: Record<string, unknown>): unknown;
            getMap(mapId?: string): IMapAdapter | null;
            getAdapter(mapId?: string): IMapAdapter | null;
            destroy(mapId: string): boolean;
            hasMap(mapId: string): boolean;
            listMaps(): string[];
            isAttached(mapId: string): boolean;
            reattach(mapId: string, parent: HTMLElement): boolean;
            setTheme(theme: string): void;
            getTheme(): string;
            [key: string]: unknown;
        };
        plugins?: {
            register?(name: string, meta?: Record<string, unknown>): void;
            registerLazy?(name: string, resolver: () => Promise<void>): void;
            registerLazyForAction?: (
                action: string,
                pluginName: string,
                ui?: PluginLazyUI,
            ) => void;
            isLoaded?(name: string): boolean;
            canActivate?(name: string): boolean;
            getLoadedPlugins?(): string[];
            registerLayerLoader?(
                pluginId: string,
                loader: (def: Record<string, unknown>) => Promise<string>,
            ): void;
            [key: string]: unknown;
        };
        registry?: IModuleRegistry;
        I18n?: {
            registerDict?(...args: unknown[]): unknown;
            getLabel?(key: string, fallback?: string): string;
            t?(key: string, ...args: unknown[]): string;
            [key: string]: unknown;
        };
        Storage?: {
            DB?: GeoLeafStorageDB;
            db?: GeoLeafStorageDB;
            whenReady?: () => Promise<void>;
            mayEdit?: (
                layerId: string,
                kind: "delete" | "create" | "update",
            ) => boolean;
            canQueueWrites?: (layerId: string) => boolean;
            applyEdit?: (
                input: {
                    layerId: string;
                    kind: "delete" | "create" | "update";
                    localId?: string;
                    feature?: unknown;
                    baseVersion?: { kind: "timestamp" | "etag"; value: string } | null;
                },
            ) => Promise<StorageEditReport>;
            pushOutbox?: () => Promise<StoragePushReport>;
            requeueQuarantined?: (id: string) => Promise<StorageQuarantineOutcome>;
            requeueAll?: (reason?: string) => Promise<StorageBatchRequeueOutcome>;
            discardQuarantined?: (
                id: string,
                confirmedLocalId: string,
            ) => Promise<StorageQuarantineOutcome>;
            requeueableReasons?: () => readonly string[];
            listConflicts?: (
                layerId?: string,
                scope?: { allProfiles?: boolean },
            ) => Promise<StorageConflictRecord[]>;
            clearConflicts?: (
                layerId?: string,
                scope?: { allProfiles?: boolean },
            ) => Promise<boolean>;
            pullLayer?(
                layerId: string,
                options?: {
                    bbox?: [number, number, number, number];
                    signal?: AbortSignal;
                },
            ): Promise<
                {
                    layerId: string;
                    fetched: number;
                    written: number;
                    preserved: number;
                    unchanged: number;
                    removed: number;
                    skipped: number;
                    capped: boolean;
                    aborted: boolean;
                    cursorRefused: boolean;
                    mode: "full"
                    | "delta"
                    | null;
                    refused: string | null;
                },
            >;
            getSyncReport?(): Promise<readonly LayerSyncReport[]>;
            getSyncStatus?(): Promise<SyncStatus>;
            resolveOptions?(
                url: string,
            ): Promise<{ value: string; label: string }[] | null>;
            preflight?(): Promise<PreflightReport | null>;
            prefetchVerdict?: (url: string) => StoragePrefetchVerdict;
            wireModules?: (
                modules: {
                    db?: unknown;
                    cacheManager?: unknown;
                    cache?: unknown;
                    pull?: unknown;
                    report?: unknown;
                    edit?: unknown;
                    ui?: unknown;
                    options?: unknown;
                },
            ) => void;
            init?: (options?: StorageInitOptions) => Promise<boolean>;
            isAvailable?: () => boolean;
            isPluginLoaded?: () => boolean;
            isOffline?: () => boolean;
            getStats?: () => Promise<
                {
                    storage: { used: number; quota: number; percentage: number };
                    layers: { count: number; byProfile: Record<string, number> };
                    features: { count: number };
                    outbox: { count: number };
                    conflicts: { count: number };
                    cache: { profiles: string[] };
                    online: boolean;
                },
            >;
            getOfflineProfiles?: () => Promise<string[]>;
            isProfileAvailableOffline?: (profileId: string) => Promise<boolean>;
            clearAll?: () => Promise<void>;
            close?: () => void;
            CacheManager?: CacheManagerLike;
            cacheManager?: CacheManagerLike;
            OfflineDetector?: OfflineDetectorLike;
            Cache?: unknown;
            cache?: unknown;
        };
        GeoJSON?: {
            getLayerById?(id: string): unknown;
            getAllLayers(): unknown;
            getLayerData?(id: string): unknown;
            setWorkerUrl?(url: string | null): void;
            [key: string]: unknown;
        };
        Log?: LogImplInterface;
        Notifications?: {
            show?(
                message: string,
                typeOrOptions?: unknown,
                duration?: number,
            ): unknown;
            [key: string]: unknown;
        };
        Table?: unknown;
        Geocoding?: unknown;
        RealtimeLayer?: unknown;
        PositionShare?: unknown;
        Routing?: unknown;
        Navigation?: unknown;
        Isochrone?: unknown;
        FlatGeobuf?: unknown;
        Connector?: unknown;
        COG?: unknown;
        FileImport?: unknown;
        Measure?: unknown;
        Print?: unknown;
        Editor?: unknown;
        Ws?: unknown;
        getPerformanceMetrics?: () => unknown;
        getRuntimeMetrics?: () => unknown;
        resetRuntimeMetrics?: () => void;
    }
    Index
    DEBUG?: boolean

    GeoLeaf.DEBUG — debug mode, set by the INTEGRATOR, never by the library.

    getDebugMode() reads it at call time, precisely so that setting window.GeoLeaf.DEBUG = true after boot takes effect without a reload.

    ⚠️ It was missing from this contract until 19/08/2026, and the gap was invisible from the inside: nothing here writes it, so no gate that watches what the library MOUNTS could see it. An integrator following the accessor's own instruction got TS2339: Property 'DEBUG' does not exist on type 'GeoLeafGlobal' — the top-level index signature that used to absorb it is gone, deliberately, so a member only reachable through it became unreachable. A read-only member of the public surface is declared here or it does not exist for the consumer.

    GeoLeaf.UI — the kernel UI facade.

    ⚠️ Long declared Record<string, unknown>, it was counted among the "typed" members while verifying nothing: that type accepts any object and yields unknown on every access, exactly like the tail it was supposed to replace. HOST-06 (check-namespace-typing-coverage.cjs) found it, by refusing to count an empty declaration as typing.

    ⚠️ globals.ui.ts sets _gl.UI = {} when absent: every member of GeoLeafUIFacade is therefore optional. And its typing canNOT go through typeof import(...) — the facade is self-mounted, the detail sits on the interface.

    _UITheme?: {
        initThemeToggle: (...args: unknown[]) => unknown;
        initAutoTheme: (...args: unknown[]) => unknown;
        toggleTheme: (...args: unknown[]) => unknown;
        applyTheme: (...args: unknown[]) => unknown;
        getCurrentTheme: () => string;
        [key: string]: unknown;
    }
    _UINotifications?: {
        show: (...args: unknown[]) => unknown;
        success: (...args: unknown[]) => unknown;
        error: (...args: unknown[]) => unknown;
        warning: (...args: unknown[]) => unknown;
        info: (...args: unknown[]) => unknown;
        clearAll: (...args: unknown[]) => unknown;
        enable: (...args: unknown[]) => unknown;
        disable: (...args: unknown[]) => unknown;
        getStatus: (...args: unknown[]) => unknown;
        [key: string]: unknown;
    }
    _UIEventDelegation?: {
        attachAccordionEvents: (...args: unknown[]) => unknown;
        cleanupAllListeners: () => number;
        [key: string]: unknown;
    }
    Filter?: {
        isEnabled(): boolean;
        getConfig(): unknown;
        getActiveFilter(): unknown;
        applyFilter(state: unknown): void;
        applyNow(): void;
        reset(): void;
        hasActiveFilters(): boolean;
        proximity: {
            setRadius(radiusKm: number): void;
            toggle(
                map: unknown,
                radiusKm?: number,
                options?: { onPointPlaced?: () => void },
            ): boolean;
        };
    }

    Public GeoLeaf.Filter facade — generic attribute filter capability (S5/S13).

    Type Declaration

    • isEnabled: function
    • getConfig: function
    • getActiveFilter: function
      • The panel's current selection, as a serialisable { fields } state. A taxonomy field lists its checked categories and sub-categories in values, and names each checked sub-category's category in subValues.

        Returns unknown

    • applyFilter: function
      • Writes a state back onto the panel's controls and applies it to the map, synchronously.

        Parameters

        • state: unknown

        Returns void

    • applyNow: function
      • Re-reads the panel and applies it to the map now, without waiting for the auto-apply delay.

        Returns void

    • reset: function
    • hasActiveFilters: function
    • proximity: {
          setRadius(radiusKm: number): void;
          toggle(
              map: unknown,
              radiusKm?: number,
              options?: { onPointPlaced?: () => void },
          ): boolean;
      }

      Proximity (radius-around-a-point) sub-filter.

      • setRadius: function
      • toggle: function
        • Toggles proximity mode. Returns the resulting state: true once the map is waiting for the user to place the centre point, false when switched off.

          Parameters

          • map: unknown
          • OptionalradiusKm: number
          • Optionaloptions: { onPointPlaced?: () => void }

          Returns boolean

    Config?: {
        get(key: string, def?: unknown): unknown;
        getAll(): Record<string, unknown>;
        getActiveProfile?(): unknown;
        clearThemesCache(profileId?: string): void;
        [key: string]: unknown;
    }

    Type Declaration

    • [key: string]: unknown
    • get: function
    • getAll: function
    • getActiveProfile?: function
      • Enriched active profile. Its layers array carries the complete layer configurations — unlike getAllLayerConfigs(), which is a whitelist projection and carries neither offline, nor data, nor write.

        ⚠️ Config.Profile is NOT mounted here, although the Config module carries it: measured in a browser. Go through getActiveProfile().

        Returns unknown

    • clearThemesCache: function
      • Drops the cached themes.json of a profile, so the next theme read goes back to its source.

        Clears one profile when profileId is given, all of them otherwise — and in both cases the in-flight loading promises too, so a reload started before the call cannot repopulate the cache behind it.

        ⚠️ This is the cache of the theme configuration, not the IndexedDB cache of layer data — that one is GeoLeaf.ThemeCache, a trap homonym.

        Parameters

        • OptionalprofileId: string

          Profile to clear. Omit to clear every profile.

        Returns void

        GeoLeaf?.Config?.clearThemesCache("reunion-eclairage");
        GeoLeaf?.Config?.clearThemesCache(); // every profile
    Utils?: {
        createElement?: (
            tag: string,
            props: Record<string, unknown>,
            ...children: unknown[],
        ) => HTMLElement;
        events?: GeoLeafUtilsEvents;
        applyCssText?: (el: HTMLElement, css: string) => void;
        validateUrl?: (
            url: string | null | undefined,
            allowedProtocols?: string[],
        ) => string | null;
        getDistance?: (
            lat1: number,
            lng1: number,
            lat2: number,
            lng2: number,
        ) => number;
        Formatters?: {
            formatDateTime: (
                date: string | number | Date,
                options?: FormatDateOptions,
            ) => string;
            formatFileSize: (
                bytes: number | null | undefined,
                options?: FormatFileSizeOptions,
            ) => string;
            toMB: (bytes: number | null | undefined, precision?: number) => string;
            toGB: (bytes: number | null | undefined, precision?: number) => string;
        };
        DOMSecurity?: {
            setTextContent: (
                element: HTMLElement | null | undefined,
                text: string | number | null | undefined,
            ) => void;
            setSafeHTML: (
                element: HTMLElement,
                html: string,
                allowedTags?: string[],
            ) => void;
            clearElement: (element: HTMLElement | null | undefined) => void;
            clearElementFast: (element: HTMLElement | null | undefined) => void;
            createSVGIcon: (
                width: number,
                height: number,
                pathData: string,
                options?: SVGIconOptions,
            ) => SVGElement;
            getIcon: (
                name: string,
                size?: number,
                options?: SVGIconOptions,
            ) => SVGElement | null;
            SVG_ICONS: Record<string, string>;
        };
        [key: string]: unknown;
    }

    Type Declaration

    • [key: string]: unknown
    • OptionalcreateElement?: (
          tag: string,
          props: Record<string, unknown>,
          ...children: unknown[],
      ) => HTMLElement
    • Optionalevents?: GeoLeafUtilsEvents
    • OptionalapplyCssText?: (el: HTMLElement, css: string) => void

      Applies a CSS declaration string property by property, through the CSSOM.

    • OptionalvalidateUrl?: (url: string | null | undefined, allowedProtocols?: string[]) => string | null

      A URL resolved against the allowed protocols, or null when its protocol is refused.

    • OptionalgetDistance?: (lat1: number, lng1: number, lat2: number, lng2: number) => number

      The distance between two points, in kilometres.

    • OptionalFormatters?: {
          formatDateTime: (
              date: string | number | Date,
              options?: FormatDateOptions,
          ) => string;
          formatFileSize: (
              bytes: number | null | undefined,
              options?: FormatFileSizeOptions,
          ) => string;
          toMB: (bytes: number | null | undefined, precision?: number) => string;
          toGB: (bytes: number | null | undefined, precision?: number) => string;
      }

      Date and size formatters.

      • formatDateTime: (date: string | number | Date, options?: FormatDateOptions) => string
      • formatFileSize: (bytes: number | null | undefined, options?: FormatFileSizeOptions) => string
      • toMB: (bytes: number | null | undefined, precision?: number) => string
      • toGB: (bytes: number | null | undefined, precision?: number) => string
    • OptionalDOMSecurity?: {
          setTextContent: (
              element: HTMLElement | null | undefined,
              text: string | number | null | undefined,
          ) => void;
          setSafeHTML: (
              element: HTMLElement,
              html: string,
              allowedTags?: string[],
          ) => void;
          clearElement: (element: HTMLElement | null | undefined) => void;
          clearElementFast: (element: HTMLElement | null | undefined) => void;
          createSVGIcon: (
              width: number,
              height: number,
              pathData: string,
              options?: SVGIconOptions,
          ) => SVGElement;
          getIcon: (
              name: string,
              size?: number,
              options?: SVGIconOptions,
          ) => SVGElement | null;
          SVG_ICONS: Record<string, string>;
      }

      The DOM sanitisation helpers — the same object as GeoLeaf.DOMSecurity.

      • setTextContent: (
            element: HTMLElement | null | undefined,
            text: string | number | null | undefined,
        ) => void
      • setSafeHTML: (element: HTMLElement, html: string, allowedTags?: string[]) => void
      • clearElement: (element: HTMLElement | null | undefined) => void
      • clearElementFast: (element: HTMLElement | null | undefined) => void
      • createSVGIcon: (
            width: number,
            height: number,
            pathData: string,
            options?: SVGIconOptions,
        ) => SVGElement
      • getIcon: (name: string, size?: number, options?: SVGIconOptions) => SVGElement | null
      • SVG_ICONS: Record<string, string>
    DOMSecurity?: {
        setSafeHTML(element: HTMLElement, html: string): void;
        [key: string]: unknown;
    }
    Security?: { escapeHtml?: (s: unknown) => string; [key: string]: unknown }
    Legend?: {
        init(mapInstance: unknown, options?: Record<string, unknown>): boolean;
        loadLayerLegend(
            layerId: string,
            styleId: string,
            layerConfig: unknown,
        ): void;
        setLayerVisibility(layerId: string, visible: boolean): void;
        getAllLayers(): Map<string, unknown>;
        hideLegend(): void;
        removeLegend(): void;
        isLegendVisible(): boolean;
        toggleAccordion: (id: string) => void;
        [key: string]: unknown;
    }

    Legend facade (GeoLeaf.Legend).

    ⚠️ The 8 members below were implemented and documented in capabilities/legend/legend.ts — @example included — but not declared here, hence absent from the GeoLeafGlobal page TypeDoc renders and an integrator reads, until 11/08/2026. The [key: string]: unknown tail remains — it only ever shrinks.

    Type Declaration

    • [key: string]: unknown
    • init: function
      • Mounts the legend on a map. Returns false when mounting fails.

        Parameters

        • mapInstance: unknown
        • Optionaloptions: Record<string, unknown>

        Returns boolean

    • loadLayerLegend: function
      • Loads and renders a layer's legend entry, for a given style.

        Parameters

        • layerId: string
        • styleId: string
        • layerConfig: unknown

        Returns void

    • setLayerVisibility: function
      • Shows or hides a layer from the legend.

        Parameters

        • layerId: string
        • visible: boolean

        Returns void

    • getAllLayers: function
    • hideLegend: function
    • removeLegend: function
    • isLegendVisible: function
    • toggleAccordion: (id: string) => void

      Collapses or expands a layer's section.

    Taxonomy?: {
        isEnabled(): boolean;
        getIcons(): TaxonomyIconsConfig | null;
        getCategories(ref: string): Record<string, TaxonomyCategory>;
        getFieldMappings(ref: string): TaxonomyFieldMappings;
        getLayerCategories(layerId: string): Record<string, TaxonomyCategory>;
        resolvePoiIcon(poi: TaxonomyFeatureLike): ResolvedIcon;
        getIconVariants(): TaxonomyIconVariant[];
        resolveMarkerPaint(
            layerId: string,
            existingPaint: Record<string, unknown>,
        ): Record<string, unknown> | null;
        resolveTitleIcon(
            layerId: string,
            feature: TaxonomyFeatureLike,
            surface: TaxonomySurface,
        ): string | null;
        resolveBadgeStyle(
            layerId: string,
            feature: TaxonomyFeatureLike,
            surface: TaxonomySurface,
            field: string,
        ): ResolvedBadgeStyle | null;
        ensureSprite(): void;
        [key: string]: unknown;
    }

    Taxonomy capability facade (in-core, gated by modules.taxonomy).

    Type Declaration

    _LegendControl?: { create: (opts: unknown) => unknown; [key: string]: unknown }
    _LegendGenerator?: {
        generateLegendFromStyle: (
            styleData: unknown,
            geometryType: string,
            taxonomyData: unknown,
        ) => unknown;
        [key: string]: unknown;
    }
    _LayerVisibilityManager?: {
        getVisibilityState: (layerId: string) => { current?: boolean } | null;
        [key: string]: unknown;
    }

    GeoLeaf._LayerVisibilityManager — internal, and no longer the only route to the visibility state.

    🔻 The refusal written here on 2026-08 is OVERTURNED on 2026-09-04, and one of its two reasons is why the replacement has the shape it has. It read:

    1. "It would have removed no key" — the core re-reads this manager through the global at 5 sites, so promoting it could not retire the key. Still true, and it never was the question. It answers "can we DELETE this?"; what was asked is "does a consumer have a SUPPORTED route?". A published plugin of this repo — plugin-table — had none, and reached into an underscore key of the core to get one. The key stays; the reach is gone.

    2. "The shape is a trap, and publishing would engrave it" — getVisibilityState() returns 6 fields, among them current (PHYSICAL visibility, which zoom forces to false) and logicalState (the user's intent); reading current to drive a toggle is a defect that was ALREADY committed once. This one holds entirely, and it is the reason nothing of this shape was published. It condemns the FORM, not the need. What went public instead is two NAMED booleans — Layers.isVisible() for the physical state, Layers.isEnabled() for the intent — which make the confusion unstateable at the call site rather than merely warned against. The 6-field object is still not public, and the irreversibility rule (subpaths are added, never removed) is what made publishing two accessors rather than one object the only safe move.

    De-facto readers outside the core: none. plugin-table moved to GeoLeaf.Layers.isVisible() on 2026-09-04 (panel.ts, table-layer.ts).

    Sync?: {
        registerHandler(id: string, handler: SyncHandler): void;
        getHandler(id: string): SyncHandler | undefined;
        registerBeforeDrain(id: string, step: BeforeDrainStep | null): void;
        registerSessionReader(reader: SessionReader | null): void;
    }

    GeoLeaf.Sync — the offline sync-handler registry seam (S14 Phase B).

    A public API of fact (B.25): it is how a data plugin pushes its offline sync handler into the core (@geoleaf-plugins/editor does GeoLeaf.Sync.registerHandler("poi", EditorSyncHandler) at its own entry.ts), and the offline engine reads them back at replay time. It was reachable and documented but typed NOWHERE — a third-party plugin integrated against unknown. Mounted twice on purpose: geoleaf.sync.ts self-mounts at import so a plugin can register before boot completes, and offline/install.ts re-assigns the same singleton (Layer B).

    Type Declaration

    • registerHandler: function
    • getHandler: function
    • registerBeforeDrain: function
    • registerSessionReader: function
      • Registers the reader of the write session, which Storage.preflight() reports; null removes it. One slot, the last registration wins. The reader tells the session without renewing it; one that throws, or does not answer within two seconds, leaves session at null. See kernel/shared/session-reader-seam.ts.

        Parameters

        Returns void

    ThemeSelector?: GeoLeafThemeSelector

    Theme switch bar — in-core theme-selector capability (see above).

    _VectorTiles?: {
        shouldUseVectorTiles(def: VtLayerDef): boolean;
        _getVTConfig(def: VtLayerDef | null): VtConfig | null;
        _resolveTileUrl(def: VtLayerDef, vtConfig: VtConfig): string | null;
        loadVectorTileLayer(
            layerId: string,
            layerLabel: string,
            def: VtLayerDef,
            _baseOptions: Record<string, unknown>,
        ): Promise<
            {
                id: string;
                label: string;
                featureCount: number;
                isVectorTile: boolean;
            },
        >;
        updateLayerStyle(
            layerId: string,
            styleData: GeoJSONCurrentStyle | null,
        ): void;
    }

    GeoLeaf._VectorTiles — the MVT policy seam published by the vector-tiles installer. Internal (underscore), but read through the global by two kernel modules that each wrote their own narrow VectorTilesLike — and the two were DISJOINT (loader-types.ts declares shouldUseVectorTiles / loadVectorTileLayer, layer-manager/style.ts declares updateLayerStyle), so neither described the seam. Typed here as the capability's own export, the only shape that covers both (B.25).

    Type Declaration

    • shouldUseVectorTiles: function
      • Determines if a layer definition should use vector tiles. Returns true only when the VT config provides an absolute tile URL. Relative paths (auto-generated from profile structure) are not used because PBF files may not exist — the layer falls back to GeoJSON.

        Parameters

        Returns boolean

    • _getVTConfig: function
    • _resolveTileUrl: function
      • Resolves the full tile URL template from the layer definition.

        ⚠️ The tilesDirectory fallback below is UNREACHABLE from the production flow, and deliberately so. _createVectorTileLayer only calls this after shouldUseVectorTiles() has returned true, and that guard requires an ABSOLUTE tilesUrl — so by the time we get here, the first branch always wins. The derived …/{z}/{x}/{y}.pbf path is therefore dead code in practice.

        It is kept, not purged. Two reasons: it is covered by 13 assertions across __tests__/geojson/vector-tiles.test.js and __tests__/config/s13-layer-data.test.js, several of them asserting the derived path specifically; and it becomes live again the moment the absolute-URL guard is relaxed, which is what "arming" a profile's vector tiles would mean. Removing it would delete tested behaviour to fix a promise that was really a data problem — the six tourism layers that declared enabled:true without a tilesUrl have been disarmed in the profiles instead.

        Parameters

        Returns string | null

    • loadVectorTileLayer: function
      • Creates a vector tile layer by delegating to the adapter, then binds interactions, records shared state and arms the labels the layer declares. The adapter builds one vector source and up to 3 render layers (fill/line/circle) from the resolved spec.

        Parameters

        • layerId: string

          Unique layer ID.

        • layerLabel: string

          Display label.

        • def: VtLayerDef

          Normalised layer definition (must include vectorTiles block).

        • _baseOptions: Record<string, unknown>

          Base options (unused in MapLibre mode).

        Returns Promise<
            {
                id: string;
                label: string;
                featureCount: number;
                isVectorTile: boolean;
            },
        >

        Layer metadata.

    • updateLayerStyle: function
    _Cluster?: {
        getClusteringStrategy: (
            def: ClusterLayerDef,
            geojsonData: ClusterGeoJSONData,
        ) => ClusterStrategyResult;
        applyGeoJSONClusterOptions: (
            adapterOptions: Record<string, unknown>,
            def: ClusterLayerDef,
            layerId: string,
            Log: GeoJSONLoaderLog,
        ) => void;
    }

    GeoLeaf._Cluster — the bag of PURE resolvers the cluster installer publishes for the GeoJSON loader. Same mechanism as _VectorTiles just above, and the same motive: a build that leaves the capability out has no writer, the loader falls back to { shouldCluster: false }, and the core imports nothing statically.

    ⚠️ This is NOT the whole module: the installer writes only two members (install.ts). Typing them via typeof import(...) keeps them tied to the SOURCE — a signature hand-copied here would drift with nothing saying so, which is exactly the defect _VectorTiles documents for its two disjoint local views.

    📌 The reader's local view, ClusterResolversLike (loader/loader-types.ts), widens def/geojsonData to unknown and COPIES the return shape. It agrees with the source as of 20/10/2026 — ClusterStrategyResult is indeed { shouldCluster } — but nothing holds it there: the local-views guard compares NAMES, not SHAPES, and says so.

    Type Declaration

    Introspection?: IIntrospectionAPI
    Capabilities?: ICapabilitiesAPI

    Capability-unavailable bus — declareUnavailable / onUnavailable.

    Layers?: LayerDataApi
    Geolocation?: GeolocationPublicApi

    In-core geolocation capability seam (GPS state + config helpers).

    Branding overlay (logo, attribution) — GeoLeaf.Branding.

    POI clustering controls — GeoLeaf.Cluster.

    Coordinates?: CoordinatesPublicApi

    Coordinate readout control — GeoLeaf.Coordinates.

    FeatureInfo?: FeatureInfoPublicApi

    Feature detail panel — GeoLeaf.FeatureInfo. Type declared in types.ts.

    Map labels toggle + renderer — GeoLeaf.Labels.

    NotificationSystem?: typeof NotificationSystem

    Toast/notification CLASS mounted by the toast-renderer installer.

    PWA?: {
        init(config: PWAConfig): void;
        isInstallable(): boolean;
        isUpdateWaiting(): boolean;
        applyUpdate(): boolean;
        _reset(): void;
    }

    PWA install/update manager — GeoLeaf.PWA. No named public type, see above.

    Type Declaration

    • init: function
      • Initializes the PWA install prompt for the current platform.

        • Opt-in: does nothing unless config.installPrompt.enabled === true.
        • iOS Safari: displays a bottom sheet with manual install instructions.
        • Other browsers: listens for beforeinstallprompt and shows a custom banner.

        Call this method after the GeoLeaf config has been loaded (i.e. from app/boot.ts).

        Parameters

        • config: PWAConfig

          PWA section from the loaded geoleaf.config.json.

        Returns void

    • isInstallable: function
      • true when the app can still be installed on this device — for integrators who want to render their own install button instead of (or alongside) the built-in banner.

        Mirrors the platform split of PWAManager.init:

        • iOS Safari — never fires beforeinstallprompt; answers from the UA + navigator.standalone check (installable = iOS and not already installed).
        • Android / Chrome / Edge — answers true once the browser has handed us a deferred beforeinstallprompt event.

        ⚠️ On Android this reports "a prompt is available", not "the browser could install this app": the deferred event is only captured if PWAManager.init has run, which is gated on modules.pwa.installPrompt.enabled === true. With the prompt disabled, it answers false even on an installable Chrome. iOS is unaffected — its check needs no listener.

        Returns boolean

        true if an install path is available right now.

    • isUpdateWaiting: function
      • true when a newer version of the application is installed and this page has not been reloaded onto it.

        A new service worker no longer takes a page that is in use: it waits, and geoleaf:sw:update-waiting says so. This reads the same fact at any time — a listener set after the boot may have missed the event. It also answers true when the update was applied from another tab: the worker changed under this page, which still runs the previous version's code.

        Always false at a first install, when modules.pwa.enabled is not true, and before the service worker has been registered (it is registered at idle, up to three seconds after the boot).

        Returns boolean

        true if PWAManager.applyUpdate has something to apply.

        document.addEventListener("geoleaf:sw:update-waiting", showMyReloadButton);
        if (GeoLeaf?.PWA?.isUpdateWaiting?.()) showMyReloadButton();
    • applyUpdate: function
      • Applies the waiting update: the new service worker takes over, and the page reloads once it does.

        Call it from a user gesture — unsaved input in the page is lost with the reload. Captures already queued by the offline write cycle are not: they live in IndexedDB. The reload is not instantaneous: the browser lets the new worker take over once the previous one has finished the requests it is serving, and the page reloads then — once.

        ⚠️ Without this call the new version stays installed and unused until every tab of the application is closed. The offline plugin calls it from its « Reload » banner; an application that does not embed that plugin has to offer the gesture itself.

        Returns boolean

        true when an update is being applied — the page will reload; false when nothing was waiting, and nothing happens.

        myReloadButton.addEventListener("click", () => GeoLeaf?.PWA?.applyUpdate?.());
        
    • _reset: function
      • Registry destroy / test seam: tears down both install sub-flows (the Android install-prompt global listeners and the iOS banner timer/banner) so a re-init starts clean (no listener / timer leak).

        Returns void

    Permalink?: {
        init(config: PermalinkConfig): void;
        readAndStore(): void;
        applyStoredState(map: IMapAdapter): void;
        startSync(map: IMapAdapter): void;
        stopSync(): void;
        getState(): PermalinkState | null;
        buildUrl(state?: PermalinkState | null): string;
        isEnabled(): boolean;
        getConfig(): PermalinkConfig;
    }

    URL state serialisation — GeoLeaf.Permalink. No named public type.

    Type Declaration

    Scale bar control — GeoLeaf.Scale.

    ProfileSwitcher?: ProfileSwitcherPublicApi

    Data-profile selector — GeoLeaf.ProfileSwitcher.

    LanguageSwitcher?: LanguageSwitcherPublicApi

    UI language selector — GeoLeaf.LanguageSwitcher.

    ThemePalette?: ThemePalettePublicApi

    Accent-colour palette — GeoLeaf.ThemePalette.

    Share sheet — GeoLeaf.Share, subdirectory of the permalink capability.

    ThemeToggle?: ThemeTogglePublicApi

    Light/dark toggle — GeoLeaf.ThemeToggle.

    Baselayers?: {
        init: (
            options?: BaselayersInitOptions,
        ) => { activeKey: string | null; layers: Record<string, unknown> };
        registerBaseLayer: (key: string, definition: BasemapDefinition) => void;
        registerBaseLayers: (
            definitions: Record<string, BasemapDefinition>,
        ) => void;
        setBaseLayer: (key: string, options?: SetBaseLayerOptions) => void;
        setActive: (key: string, options?: SetBaseLayerOptions) => void;
        refreshBasemap: () => void;
        getBaseLayers: () => { [key: string]: BaseLayerEntry };
        getActiveKey: () => string | null;
        getActiveId: () => string | null;
        getActiveLayer: () => BasemapDefinition | null;
        destroy: () => void;
    }

    Base layer catalogue façade.

    Type Declaration

    BaseLayers?: {
        init: (
            options?: BaselayersInitOptions,
        ) => { activeKey: string | null; layers: Record<string, unknown> };
        registerBaseLayer: (key: string, definition: BasemapDefinition) => void;
        registerBaseLayers: (
            definitions: Record<string, BasemapDefinition>,
        ) => void;
        setBaseLayer: (key: string, options?: SetBaseLayerOptions) => void;
        setActive: (key: string, options?: SetBaseLayerOptions) => void;
        refreshBasemap: () => void;
        getBaseLayers: () => { [key: string]: BaseLayerEntry };
        getActiveKey: () => string | null;
        getActiveId: () => string | null;
        getActiveLayer: () => BasemapDefinition | null;
        destroy: () => void;
    }

    Historical alias of GeoLeafGlobal.Baselayers — same reference, same type.

    Type Declaration

    Events?: {
        on<K extends (keyof GeoLeafEventMap) | (keyof GeoLeafRawEventMap)>(
            event: K,
            handler: GeoLeafEventHandler<K>,
        ): () => void;
        off<K extends (keyof GeoLeafEventMap) | (keyof GeoLeafRawEventMap)>(
            event: K,
            handler: GeoLeafEventHandler<K>,
        ): void;
        once<K extends (keyof GeoLeafEventMap) | (keyof GeoLeafRawEventMap)>(
            event: K,
            handler: GeoLeafEventHandler<K>,
        ): () => void;
    }

    Typed event bus façade (on/off/once/dispatch).

    Type Declaration

    • on: function
      • Registers a listener for a GeoLeaf event. The listener is called every time the event fires until it is removed — by the function this call returns, or by off() with the same handler.

        Type Parameters

        • K extends (keyof GeoLeafEventMap) | (keyof GeoLeafRawEventMap)

        Parameters

        • event: K

          Event name (see module docs for full reference).

        • handler: GeoLeafEventHandler<K>

          Callback receiving the CustomEvent with typed detail.

        Returns () => void

        A function that removes this listener. It is off(event, handler) bound to this subscription: calling it twice is harmless, and since the DOM registers one listener per handler reference, it also removes an identical earlier on(). Without a document (SSR), nothing is registered and the function does nothing.

        import { Events } from "@geoleaf/core";

        // An anonymous handler can only be removed through the returned function.
        const unsubscribe = Events.on("geoleaf:layer:toggle", (e) => {
        console.log(e.detail.layerId, e.detail.visible);
        });

        // On teardown:
        unsubscribe();
    • off: function
      • Removes a previously registered listener. The exact same handler reference must be passed.

        Type Parameters

        • K extends (keyof GeoLeafEventMap) | (keyof GeoLeafRawEventMap)

        Parameters

        • event: K

          Event name.

        • handler: GeoLeafEventHandler<K>

          The handler reference originally passed to on().

        Returns void

        // With off(), the handler must be NAMED — an anonymous one is removed through the
        // function on() returns.
        const handlePoiPanel = (e) => {
        console.log(e.detail.poiId);
        };
        GeoLeaf.Events.on("geoleaf:poi:panel:open", handlePoiPanel);

        // Plus tard :
        GeoLeaf.Events.off("geoleaf:poi:panel:open", handlePoiPanel);
    • once: function
      • Registers a listener that fires once then automatically removes itself. Uses the native {once: true} option — no wrapper function needed.

        Type Parameters

        • K extends (keyof GeoLeafEventMap) | (keyof GeoLeafRawEventMap)

        Parameters

        Returns () => void

        A function that cancels the listener if it has not fired yet — the teardown of a component unmounted before the event arrives. Calling it after the listener fired is harmless. Without a document (SSR), the function does nothing.

        GeoLeaf.Events.once("geoleaf:app:ready", () => {
        console.log("App prête !");
        });
    events?: {
        on<K extends (keyof GeoLeafEventMap) | (keyof GeoLeafRawEventMap)>(
            event: K,
            handler: GeoLeafEventHandler<K>,
        ): () => void;
        off<K extends (keyof GeoLeafEventMap) | (keyof GeoLeafRawEventMap)>(
            event: K,
            handler: GeoLeafEventHandler<K>,
        ): void;
        once<K extends (keyof GeoLeafEventMap) | (keyof GeoLeafRawEventMap)>(
            event: K,
            handler: GeoLeafEventHandler<K>,
        ): () => void;
    }

    Lowercase alias of GeoLeafGlobal.Events — same reference, same type.

    Type Declaration

    • on: function
      • Registers a listener for a GeoLeaf event. The listener is called every time the event fires until it is removed — by the function this call returns, or by off() with the same handler.

        Type Parameters

        • K extends (keyof GeoLeafEventMap) | (keyof GeoLeafRawEventMap)

        Parameters

        • event: K

          Event name (see module docs for full reference).

        • handler: GeoLeafEventHandler<K>

          Callback receiving the CustomEvent with typed detail.

        Returns () => void

        A function that removes this listener. It is off(event, handler) bound to this subscription: calling it twice is harmless, and since the DOM registers one listener per handler reference, it also removes an identical earlier on(). Without a document (SSR), nothing is registered and the function does nothing.

        import { Events } from "@geoleaf/core";

        // An anonymous handler can only be removed through the returned function.
        const unsubscribe = Events.on("geoleaf:layer:toggle", (e) => {
        console.log(e.detail.layerId, e.detail.visible);
        });

        // On teardown:
        unsubscribe();
    • off: function
      • Removes a previously registered listener. The exact same handler reference must be passed.

        Type Parameters

        • K extends (keyof GeoLeafEventMap) | (keyof GeoLeafRawEventMap)

        Parameters

        • event: K

          Event name.

        • handler: GeoLeafEventHandler<K>

          The handler reference originally passed to on().

        Returns void

        // With off(), the handler must be NAMED — an anonymous one is removed through the
        // function on() returns.
        const handlePoiPanel = (e) => {
        console.log(e.detail.poiId);
        };
        GeoLeaf.Events.on("geoleaf:poi:panel:open", handlePoiPanel);

        // Plus tard :
        GeoLeaf.Events.off("geoleaf:poi:panel:open", handlePoiPanel);
    • once: function
      • Registers a listener that fires once then automatically removes itself. Uses the native {once: true} option — no wrapper function needed.

        Type Parameters

        • K extends (keyof GeoLeafEventMap) | (keyof GeoLeafRawEventMap)

        Parameters

        Returns () => void

        A function that cancels the listener if it has not fired yet — the teardown of a component unmounted before the event arrives. Calling it after the listener fired is harmless. Without a document (SSR), the function does nothing.

        GeoLeaf.Events.once("geoleaf:app:ready", () => {
        console.log("App prête !");
        });
    CONSTANTS?: Readonly<
        {
            DEFAULT_ZOOM: 3;
            DEFAULT_CENTER: [number, number];
            MAX_ZOOM_ON_FIT: 15;
            POI_MARKER_SIZE: 12;
            POI_MAX_ZOOM: 18;
            POI_SWIPE_THRESHOLD: 50;
            POI_LIGHTBOX_TRANSITION_MS: 300;
            POI_SIDEPANEL_DEFAULT_WIDTH: 420;
            ROUTE_MAX_ZOOM_ON_FIT: 14;
            ROUTE_WAYPOINT_RADIUS: 5;
            GEOJSON_MAX_ZOOM_ON_FIT: 15;
            GEOJSON_POINT_RADIUS: 6;
            FULLSCREEN_TRANSITION_MS: 10;
        },
    >

    Frozen runtime constants — set by globals.core.ts.

    Errors?: {
        GeoLeafError: typeof GeoLeafError;
        ValidationError: typeof ValidationError;
        SecurityError: typeof SecurityError;
        ConfigError: typeof ConfigError;
        NetworkError: typeof NetworkError;
        InitializationError: typeof InitializationError;
        MapError: typeof MapError;
        DataError: typeof DataError;
        POIError: typeof POIError;
        RouteError: typeof RouteError;
        UIError: typeof UIError;
        normalizeError: (error: unknown, defaultMessage?: string) => GeoLeafError;
        isErrorType: (error: unknown, ErrorClass: typeof GeoLeafError) => boolean;
        getErrorCode: (error: unknown) => string;
        createError: (
            ErrorClass: ErrorClassConstructor,
            message: string,
            context?: ErrorContext,
        ) => GeoLeafError;
        createErrorByType: (
            type: string,
            message: string,
            context?: ErrorContext,
        ) => GeoLeafError;
        sanitizeErrorMessage: (message: unknown, maxLength?: number) => string;
        safeErrorHandler: (
            handler: ((err: unknown) => void) | undefined,
            error: unknown,
        ) => void;
        ErrorCodes: Readonly<
            {
                VALIDATION: "VALIDATION_ERROR";
                SECURITY: "SECURITY_ERROR";
                CONFIG: "CONFIG_ERROR";
                NETWORK: "NETWORK_ERROR";
                INITIALIZATION: "INITIALIZATION_ERROR";
                MAP: "MAP_ERROR";
                DATA: "DATA_ERROR";
                POI: "POI_ERROR";
                ROUTE: "ROUTE_ERROR";
                UI: "UI_ERROR";
            },
        >;
    }

    Error helpers — set by globals.core.ts.

    Type Declaration

    • GeoLeafError: typeof GeoLeafError
    • ValidationError: typeof ValidationError
    • SecurityError: typeof SecurityError
    • ConfigError: typeof ConfigError
    • NetworkError: typeof NetworkError
    • InitializationError: typeof InitializationError
    • MapError: typeof MapError
    • DataError: typeof DataError
    • POIError: typeof POIError
    • RouteError: typeof RouteError
    • UIError: typeof UIError
    • normalizeError: (error: unknown, defaultMessage?: string) => GeoLeafError
    • isErrorType: (error: unknown, ErrorClass: typeof GeoLeafError) => boolean
    • getErrorCode: (error: unknown) => string
    • createError: (
          ErrorClass: ErrorClassConstructor,
          message: string,
          context?: ErrorContext,
      ) => GeoLeafError
    • createErrorByType: (type: string, message: string, context?: ErrorContext) => GeoLeafError
    • sanitizeErrorMessage: (message: unknown, maxLength?: number) => string
    • safeErrorHandler: (handler: ((err: unknown) => void) | undefined, error: unknown) => void
    • ErrorCodes: Readonly<
          {
              VALIDATION: "VALIDATION_ERROR";
              SECURITY: "SECURITY_ERROR";
              CONFIG: "CONFIG_ERROR";
              NETWORK: "NETWORK_ERROR";
              INITIALIZATION: "INITIALIZATION_ERROR";
              MAP: "MAP_ERROR";
              DATA: "DATA_ERROR";
              POI: "POI_ERROR";
              ROUTE: "ROUTE_ERROR";
              UI: "UI_ERROR";
          },
      >

      The machine-readable code carried by each error subclass, frozen.

      Keys are the short family names; values are the strings that land on error.code. Compare against these rather than against literals, so a rename stays a compile-time concern.

      GeoLeaf.Errors.ErrorCodes.VALIDATION; // 'VALIDATION_ERROR'
      GeoLeaf.Errors.ErrorCodes.SECURITY; // 'SECURITY_ERROR'
      GeoLeaf.Errors.ErrorCodes.CONFIG; // 'CONFIG_ERROR'
      GeoLeaf.Errors.ErrorCodes.NETWORK; // 'NETWORK_ERROR'
      GeoLeaf.Errors.ErrorCodes.INITIALIZATION; // 'INITIALIZATION_ERROR'
      GeoLeaf.Errors.ErrorCodes.MAP; // 'MAP_ERROR'
      GeoLeaf.Errors.ErrorCodes.DATA; // 'DATA_ERROR'
      GeoLeaf.Errors.ErrorCodes.POI; // 'POI_ERROR'
      GeoLeaf.Errors.ErrorCodes.ROUTE; // 'ROUTE_ERROR'
      GeoLeaf.Errors.ErrorCodes.UI; // 'UI_ERROR'
    Helpers?: {
        getElementById: (id: string | null | undefined) => HTMLElement | null;
        querySelector: (selector: string, parent?: ParentNode) => Element | null;
        querySelectorAll: (selector: string, parent?: ParentNode) => Element[];
        applyCssText: (el: HTMLElement, css: string) => void;
        addClass: (
            element: Element | null | undefined,
            ...classNames: string[],
        ) => void;
        removeClass: (
            element: Element | null | undefined,
            ...classNames: string[],
        ) => void;
        toggleClass: (
            element: Element | null | undefined,
            className: string,
            force?: boolean,
        ) => boolean;
        hasClass: (
            element: Element | null | undefined,
            className: string,
        ) => boolean;
        removeElement: (element: Node | null | undefined) => void;
        requestFrame: (callback: FrameRequestCallback) => number;
        cancelFrame: (id: number) => void;
        createAbortController: (timeout?: number) => AbortController;
        lazyLoadImage: (
            img: HTMLImageElement,
            options?: { threshold?: number },
        ) => void;
        lazyExecute: (callback: () => void, timeout?: number) => void;
        clearObject: (obj: Record<string, unknown> | null | undefined) => void;
        createFragment: (children?: HTMLElement[]) => DocumentFragment;
        addEventListener: (
            element: EventTarget | null | undefined,
            event: string,
            handler: EventListenerOrEventListenerObject,
            options?: boolean | AddEventListenerOptions,
        ) => () => void;
        addEventListeners: (
            element: EventTarget | null | undefined,
            events: Record<string, EventListenerOrEventListenerObject>,
            options?: boolean | AddEventListenerOptions,
        ) => () => void;
        delegateEvent: (
            parent: EventTarget | null | undefined,
            event: string,
            selector: string,
            handler: (this: Element, e: Event) => void,
        ) => () => void;
        deepClone: <T>(obj: T, seen?: WeakMap<object, unknown>) => T;
        isEmpty: (value: unknown) => boolean;
        wait: (ms: number) => Promise<void>;
        retryWithBackoff: <T>(
            fn: () => Promise<T>,
            maxRetries?: number,
            delay?: number,
        ) => Promise<T>;
    }

    General-purpose helpers façade.

    Type Declaration

    • getElementById: (id: string | null | undefined) => HTMLElement | null
    • querySelector: (selector: string, parent?: ParentNode) => Element | null
    • querySelectorAll: (selector: string, parent?: ParentNode) => Element[]
    • applyCssText: (el: HTMLElement, css: string) => void
    • addClass: (element: Element | null | undefined, ...classNames: string[]) => void
    • removeClass: (element: Element | null | undefined, ...classNames: string[]) => void
    • toggleClass: (
          element: Element | null | undefined,
          className: string,
          force?: boolean,
      ) => boolean
    • hasClass: (element: Element | null | undefined, className: string) => boolean
    • removeElement: (element: Node | null | undefined) => void
    • requestFrame: (callback: FrameRequestCallback) => number
    • cancelFrame: (id: number) => void
    • createAbortController: (timeout?: number) => AbortController
    • lazyLoadImage: (img: HTMLImageElement, options?: { threshold?: number }) => void
    • lazyExecute: (callback: () => void, timeout?: number) => void
    • clearObject: (obj: Record<string, unknown> | null | undefined) => void
    • createFragment: (children?: HTMLElement[]) => DocumentFragment
    • addEventListener: (
          element: EventTarget | null | undefined,
          event: string,
          handler: EventListenerOrEventListenerObject,
          options?: boolean | AddEventListenerOptions,
      ) => () => void
    • addEventListeners: (
          element: EventTarget | null | undefined,
          events: Record<string, EventListenerOrEventListenerObject>,
          options?: boolean | AddEventListenerOptions,
      ) => () => void
    • delegateEvent: (
          parent: EventTarget | null | undefined,
          event: string,
          selector: string,
          handler: (this: Element, e: Event) => void,
      ) => () => void
    • deepClone: <T>(obj: T, seen?: WeakMap<object, unknown>) => T
    • isEmpty: (value: unknown) => boolean
    • wait: (ms: number) => Promise<void>
    • retryWithBackoff: <T>(fn: () => Promise<T>, maxRetries?: number, delay?: number) => Promise<T>
    LayerManager?: {
        init(options?: Partial<LayerManagerOptions>): LMControlInstance | null;
        _registerGeoJsonLayer(
            layerId: string,
            options?: RegisterLayerOptions,
        ): void;
        refresh(immediate?: boolean): void;
        _reset(): void;
    }

    Layer manager façade (visibility, ordering, legend wiring).

    Type Declaration

    • init: function
      • Mounts the layer-manager panel.

        Called without arguments, everything comes from the profile configuration — the recommended path. Anything passed here overrides that, field by field.

        Parameters

        • options: Partial<LayerManagerOptions> = {}

          Position, title, and collapsible/collapsed state.

        Returns LMControlInstance | null

        // Initialisation depuis config (recommandé)
        GeoLeaf.LayerManager.init();

        // Avec options personnalisées
        GeoLeaf.LayerManager.init({
        position: "bottomleft",
        collapsible: true,
        collapsed: false,
        title: "Couches",
        });
    • _registerGeoJsonLayer: function
      • Registers a GeoJSON layer into its LayerManager section.

        Not the legend capability: this fills the COUCHES panel (.gl-layer-manager), not .gl-map-legend. The section named by layerManagerId is created on the fly when unknown, with a generic label and no accordion flag — those placeholder values are meant to be overwritten by _applyLayerManagerConfig, which runs later (at init()), since registration happens first.

        Parameters

        • layerId: string

          The layer id

        • options: RegisterLayerOptions = {}

          Layer options

        Returns void

    • refresh: function
      • Redraws the panel to match the current layer state.

        Debounced by default, so a burst of layer changes costs one redraw. Passing immediate cancels any pending debounce and redraws synchronously — needed when the caller is about to read the rendered DOM.

        A no-op, logged at debug, when the control is not yet mounted (early boot).

        Parameters

        • immediate: boolean = false

          Skip the debounce and redraw now. Defaults to false.

        Returns void

        // Rafraîchissement debouncé (groupé par défaut)
        GeoLeaf.LayerManager.refresh();

        // Rafraîchissement immédiat
        GeoLeaf.LayerManager.refresh(true);
    • _reset: function
      • Resets the module back to its post-import state.

        Run on map teardown so the control, the map handle and the accumulated sections do not survive a destroy → recreate cycle. A pending debounced refresh is cancelled too: its callback closes over the old control and would fire against a detached DOM node.

        Idempotent — safe to call more than once.

        Returns void

    ThemeCache?: {
        _config: { enabled: boolean; maxAge: number };
        get(layerId: string, profileId?: string | null): Promise<unknown>;
        store(
            layerId: string,
            profileId?: string | null,
            data: string | object | ArrayBuffer,
            metadata?: Record<string, unknown>,
        ): Promise<void>;
        invalidate(layerId: string): Promise<void>;
    }

    Theme cache — set by globals.ui.ts, outside the facade chain.

    Type Declaration

    • _config: { enabled: boolean; maxAge: number }
    • get: function
      • Retrieves a layer from the cache si elle est encore valide.

        Parameters

        • layerId: string
        • OptionalprofileId: string | null

        Returns Promise<unknown>

    • store: function
      • Stocke a layer in the cache.

        Parameters

        • layerId: string
        • OptionalprofileId: string | null
        • data: string | object | ArrayBuffer
        • Optionalmetadata: Record<string, unknown> = {}

        Returns Promise<void>

    • invalidate: function
    Validators?: {
        validateCoordinates: (
            lat: number,
            lng: number,
            options?: ValidatorOptions,
        ) => { valid: boolean; error: string | null };
        validateUrl: (
            url: string,
            options?: ValidateUrlOptions,
        ) => { valid: boolean; error: string | null; url: string | null };
        validateEmail: (
            email: unknown,
            options?: ValidatorOptions,
        ) => { valid: boolean; error: string | null };
        validatePhone: (
            phone: unknown,
            options?: ValidatorOptions,
        ) => { valid: boolean; error: string | null };
        validateZoom: (
            zoom: number,
            options?: ValidateZoomOptions,
        ) => { valid: boolean; error: string | null };
        validateRequiredFields: (
            config: Record<string, unknown> | null | undefined,
            requiredFields: string[],
            options?: ValidatorOptions,
        ) => { valid: boolean; error: string | null; missing: string[] };
        validateGeoJSON: (
            geojson: Record<string, unknown> | null | undefined,
            options?: ValidatorOptions,
        ) => { valid: boolean; error: string | null };
        validateColor: (
            color: unknown,
            options?: ValidatorOptions,
        ) => { valid: boolean; error: string | null };
        validateBatch: (validations: ValidateBatchItem[]) => ValidationResult;
    }

    Style/config validators façade.

    Type Declaration

    • validateCoordinates: (
          lat: number,
          lng: number,
          options?: ValidatorOptions,
      ) => { valid: boolean; error: string | null }
    • validateUrl: (
          url: string,
          options?: ValidateUrlOptions,
      ) => { valid: boolean; error: string | null; url: string | null }
    • validateEmail: (
          email: unknown,
          options?: ValidatorOptions,
      ) => { valid: boolean; error: string | null }
    • validatePhone: (
          phone: unknown,
          options?: ValidatorOptions,
      ) => { valid: boolean; error: string | null }
    • validateZoom: (
          zoom: number,
          options?: ValidateZoomOptions,
      ) => { valid: boolean; error: string | null }
    • validateRequiredFields: (
          config: Record<string, unknown> | null | undefined,
          requiredFields: string[],
          options?: ValidatorOptions,
      ) => { valid: boolean; error: string | null; missing: string[] }
    • validateGeoJSON: (
          geojson: Record<string, unknown> | null | undefined,
          options?: ValidatorOptions,
      ) => { valid: boolean; error: string | null }
    • validateColor: (
          color: unknown,
          options?: ValidatorOptions,
      ) => { valid: boolean; error: string | null }
    • validateBatch: (validations: ValidateBatchItem[]) => ValidationResult
    version?: string

    Package version string.

    ✅ A single writer: globals/globals.api.ts, under an if (!_gl.version) guard — which makes setupAPIKernel() re-callable without overwriting an already-set version.

    ⚠️ This note used to say "Written in TWO places: globals.api.ts […] and kernel/api/geoleaf-api.ts unguarded. Last writer wins" — that was true, and both line numbers had drifted (208 and 164 by the time of removal). A line citation in a comment ages silently; this one now points only at the file.

    GeoLeaf.API — the API constructors, assembled as a literal by globals.api.ts.

    ⚠️ Hand-written, and that is measured: contracts/api.contract.ts does declare IGeoLeafAPIConstructors, but it covers only the 3 aliases, not the 7 keys actually set. Referencing it would have typed under half the object while looking like it typed it — the defect HOST-06 hunts, one level up.

    init?: (options: Record<string, unknown>) => unknown

    {@inheritDoc GeoLeafTopLevelApi.init}

    setTheme?: (theme: string) => boolean

    {@inheritDoc GeoLeafTopLevelApi.setTheme}

    loadConfig?: (input: string | Record<string, unknown>) => Promise<unknown>

    {@inheritDoc GeoLeafTopLevelApi.loadConfig}

    createMap?: (id: string, options?: Record<string, unknown>) => unknown

    {@inheritDoc GeoLeafTopLevelApi.createMap}

    getMap?: (id: string) => unknown

    {@inheritDoc GeoLeafTopLevelApi.getMap}

    getAllMaps?: () => unknown[]

    {@inheritDoc GeoLeafTopLevelApi.getAllMaps}

    getModule?: (name: string) => unknown

    {@inheritDoc GeoLeafTopLevelApi.getModule}

    hasModule?: (name: string) => boolean

    {@inheritDoc GeoLeafTopLevelApi.hasModule}

    getNamespace?: (name: string) => unknown

    {@inheritDoc GeoLeafTopLevelApi.getNamespace}

    getHealth?: () => unknown

    {@inheritDoc GeoLeafTopLevelApi.getHealth}

    getMetrics?: () => unknown

    {@inheritDoc GeoLeafTopLevelApi.getMetrics}

    fetch?: (url: string, options?: FetchHelperOptions) => Promise<unknown>

    FetchHelper.fetch, bound — instrumented HTTP request.

    get?: (url: string, options?: FetchHelperOptions) => Promise<unknown>

    FetchHelper.get, bound.

    Optionalpost

    post?: (
        url: string,
        data: unknown,
        options?: FetchHelperOptions,
    ) => Promise<unknown>

    FetchHelper.post, bound.

    bootInfo?: {
        show: (
            GeoLeaf: BootInfoNamespace | null | undefined,
            options?: BootInfoOptions,
        ) => void;
        detectPlugins: (GeoLeaf: BootInfoNamespace) => string[];
        buildMessage: (GeoLeaf: BootInfoNamespace) => BootMessage;
    }

    Boot report (⚠️ lowercase on the namespace side, BootInfo on the module side).

    Type Declaration

    boot?: (options?: BootOptions) => void

    Starts the GeoLeaf application: loads the profile, creates the map, initialises the modules. This is the application entry — apps/geoleaf-app/init.js calls it, and the load order of every plugin refers to it.

    ⚠️ Not to be confused with GeoLeafGlobal.init, the manual wrapper around Core.init(). The boot path goes through registry.init() — the ModuleRegistry's — and never calls GeoLeaf.init.

    The two options are the only channel through which a host sets an auth gate (SSO) or retrieves the startup metrics; they are re-read from _beforeBootCallback and _perfCallback. Those two stay out of this contract: they are service-locator keys, _-prefixed because they are internal to the core and no integrator has to write them — they are the channel, not the rendezvous.

    mount?: (el: string | HTMLElement, options?: BootOptions) => GeoLeafMount

    Mounts the application in a map container and returns the handle that unmounts it — the lifecycle a host that mounts and unmounts views can run again. Boots as GeoLeafGlobal.boot does, with the same options; unmount() takes the whole application down, and the next mount() gives it back whole. One application per page: a mount() while one is alive unmounts it first.

    mark?: (name: string) => void

    Sets a named performance mark.

    measure?: (name: string, startMark: string, endMark?: string) => number

    Measures between two marks; returns the duration in milliseconds.

    getPerformanceReport?: () => Record<string, unknown>

    Aggregated performance report from the profiler.

    establishBaseline?: () => Record<string, unknown>

    Freezes the current measurement as the comparison reference.

    notify?: (message: string, level?: NotifyLevel) => void

    User notification — primitive, renderer-independent.

    Type Declaration

      • (message: string, level?: NotifyLevel): void
      • Emits a user-facing notification.

        • If a renderer is registered: delegates immediately.
        • If no renderer yet: buffers the message and logs a console fallback.

        Parameters

        • message: string

          Text to display.

        • Optionallevel: NotifyLevel

          Severity level (default: "info").

        Returns void

    Core?: {
        init(options?: Record<string, unknown>): unknown;
        getMap(mapId?: string): IMapAdapter | null;
        getAdapter(mapId?: string): IMapAdapter | null;
        destroy(mapId: string): boolean;
        hasMap(mapId: string): boolean;
        listMaps(): string[];
        isAttached(mapId: string): boolean;
        reattach(mapId: string, parent: HTMLElement): boolean;
        setTheme(theme: string): void;
        getTheme(): string;
        [key: string]: unknown;
    }

    Core map façade (GeoLeaf.Core) — low-level map lifecycle.

    Since v3.0.0, Core holds an indexed registry of adapters (Map<mapId, IMapAdapter>): N maps coexist on one page, each with its own lifecycle. The module singleton of versions ≤ 2.1.x no longer exists.

    ⚠️ The [key: string]: unknown tail remains: the 8 members below are now declared and documented, the rest of the namespace is not yet. Never widen it back to any.

    Type Declaration

    • [key: string]: unknown
    • init: function
      • Initialises a map. Requires options.mapId — without it, returns null and logs. Re-initialising an existing mapId returns the instance already in place rather than creating a second one.

        Parameters

        • Optionaloptions: Record<string, unknown>

        Returns unknown

    • getMap: function
      • The instance targeted by mapId; with no argument, the first active instance — the backward-compatible form for single-map applications.

        Parameters

        • OptionalmapId: string

        Returns IMapAdapter | null

    • getAdapter: function
    • destroy: function
      • Destroys the instance (map.remove() then frees the registry slot). Returns true when it existed. Call it at unmount on the consumer side.

        Parameters

        • mapId: string

        Returns boolean

    • hasMap: function
      • Whether an instance is registered under this mapId.

        Parameters

        • mapId: string

        Returns boolean

    • listMaps: function
    • isAttached: function
      • Whether an instance is registered and its container is still in the document. Stronger than hasMap, which only answers for the registration: a host that removes the subtree without calling destroy() leaves a registered map that renders nowhere. Returns false after destroy().

        Parameters

        • mapId: string

        Returns boolean

    • reattach: function
      • Moves a live map into another parent, without destroying or rebuilding it. The ENTIRE container is re-parented — MapLibre remembers its construction element, so moving its children would leave getContainer() pointing at the old node.

        ⚠️ The shell does not follow: the side panel and the mobile pill live in glMain, not in the map container. Remounting them is the host's job, and it is two recipes — UI.destroyDesktopPanel() → initDesktopPanel() → activateDesktopPanel() for the panel, UI.destroyMobileToolbar() → initMobileToolbar() for the pill. 🛑 Run either destroy BEFORE dropping the old shell: both give back nodes they had moved, and only to a parent that still exists.

        Parameters

        • mapId: string
        • parent: HTMLElement

        Returns boolean

    • setTheme: function
      • Applies a theme to the map container.

        ⚠️ The theme stays global in v3.0.0 and applies to the first instance: per-map isolation is out of this version's scope.

        Parameters

        • theme: string

        Returns void

    • getTheme: function
    plugins?: {
        register?(name: string, meta?: Record<string, unknown>): void;
        registerLazy?(name: string, resolver: () => Promise<void>): void;
        registerLazyForAction?: (
            action: string,
            pluginName: string,
            ui?: PluginLazyUI,
        ) => void;
        isLoaded?(name: string): boolean;
        canActivate?(name: string): boolean;
        getLoadedPlugins?(): string[];
        registerLayerLoader?(
            pluginId: string,
            loader: (def: Record<string, unknown>) => Promise<string>,
        ): void;
        [key: string]: unknown;
    }

    Plugin registry / lifecycle façade (GeoLeaf.plugins).

    ⚠️ getLoadedPlugins, canActivate and registerLazy were added on 31/07/2026, and not for typing comfort. All three have long been taught by docs/API_REFERENCE.md ("Plugins" section), exist in kernel/api/plugin-registry.ts and ship in the delivered bundle — but were declared nowhere here, so they fell into the [key: string]: unknown tail.

    What that cost, measured: showBootInfo(GeoLeaf) — the call its own doc shows — did not compile. BootInfoNamespace requires plugins?.getLoadedPlugins?: () => string[]; resolved through the tail the member was unknown, and unknown is not assignable to (() => string[]) | undefined. The defect was visible to no gate as long as the showBootInfo example was written showBootInfo() — that is, as long as it was wrong in ANOTHER way, frozen in the typecheck baseline. A frozen diagnostic masks what lives under it.

    Shrinking the tail is the only allowed direction: never widen back to any.

    Type Declaration

    • [key: string]: unknown
    • register?: function
      • Parameters

        • name: string
        • Optionalmeta: Record<string, unknown>

        Returns void

    • registerLazy?: function
      • Parameters

        • name: string
        • resolver: () => Promise<void>

        Returns void

    • OptionalregisterLazyForAction?: (action: string, pluginName: string, ui?: PluginLazyUI) => void

      Declares the toolbar slot of a plugin loaded on demand — its button exists before its bundle does, and the first press loads the plugin. Call it before the boot.

    • isLoaded?: function
    • canActivate?: function
    • getLoadedPlugins?: function
    • registerLayerLoader?: function
      • Parameters

        • pluginId: string
        • loader: (def: Record<string, unknown>) => Promise<string>

        Returns void

    registry?: IModuleRegistry

    Module registry (GeoLeaf.registry) — lifecycle modules AND UI-only slots.

    Typed as the contract itself rather than as a structural { register?; [key]: unknown }: ModuleRegistry is a CLASS, and TypeScript does not give classes an implicit index signature, so the loose shape rejected the very object boot-install.ts assigns.

    I18n?: {
        registerDict?(...args: unknown[]): unknown;
        getLabel?(key: string, fallback?: string): string;
        t?(key: string, ...args: unknown[]): string;
        [key: string]: unknown;
    }

    Internationalization façade (GeoLeaf.I18n).

    Storage?: {
        DB?: GeoLeafStorageDB;
        db?: GeoLeafStorageDB;
        whenReady?: () => Promise<void>;
        mayEdit?: (
            layerId: string,
            kind: "delete" | "create" | "update",
        ) => boolean;
        canQueueWrites?: (layerId: string) => boolean;
        applyEdit?: (
            input: {
                layerId: string;
                kind: "delete" | "create" | "update";
                localId?: string;
                feature?: unknown;
                baseVersion?: { kind: "timestamp" | "etag"; value: string } | null;
            },
        ) => Promise<StorageEditReport>;
        pushOutbox?: () => Promise<StoragePushReport>;
        requeueQuarantined?: (id: string) => Promise<StorageQuarantineOutcome>;
        requeueAll?: (reason?: string) => Promise<StorageBatchRequeueOutcome>;
        discardQuarantined?: (
            id: string,
            confirmedLocalId: string,
        ) => Promise<StorageQuarantineOutcome>;
        requeueableReasons?: () => readonly string[];
        listConflicts?: (
            layerId?: string,
            scope?: { allProfiles?: boolean },
        ) => Promise<StorageConflictRecord[]>;
        clearConflicts?: (
            layerId?: string,
            scope?: { allProfiles?: boolean },
        ) => Promise<boolean>;
        pullLayer?(
            layerId: string,
            options?: {
                bbox?: [number, number, number, number];
                signal?: AbortSignal;
            },
        ): Promise<
            {
                layerId: string;
                fetched: number;
                written: number;
                preserved: number;
                unchanged: number;
                removed: number;
                skipped: number;
                capped: boolean;
                aborted: boolean;
                cursorRefused: boolean;
                mode: "full"
                | "delta"
                | null;
                refused: string | null;
            },
        >;
        getSyncReport?(): Promise<readonly LayerSyncReport[]>;
        getSyncStatus?(): Promise<SyncStatus>;
        resolveOptions?(
            url: string,
        ): Promise<{ value: string; label: string }[] | null>;
        preflight?(): Promise<PreflightReport | null>;
        prefetchVerdict?: (url: string) => StoragePrefetchVerdict;
        wireModules?: (
            modules: {
                db?: unknown;
                cacheManager?: unknown;
                cache?: unknown;
                pull?: unknown;
                report?: unknown;
                edit?: unknown;
                ui?: unknown;
                options?: unknown;
            },
        ) => void;
        init?: (options?: StorageInitOptions) => Promise<boolean>;
        isAvailable?: () => boolean;
        isPluginLoaded?: () => boolean;
        isOffline?: () => boolean;
        getStats?: () => Promise<
            {
                storage: { used: number; quota: number; percentage: number };
                layers: { count: number; byProfile: Record<string, number> };
                features: { count: number };
                outbox: { count: number };
                conflicts: { count: number };
                cache: { profiles: string[] };
                online: boolean;
            },
        >;
        getOfflineProfiles?: () => Promise<string[]>;
        isProfileAvailableOffline?: (profileId: string) => Promise<boolean>;
        clearAll?: () => Promise<void>;
        close?: () => void;
        CacheManager?: CacheManagerLike;
        cacheManager?: CacheManagerLike;
        OfflineDetector?: OfflineDetectorLike;
        Cache?: unknown;
        cache?: unknown;
    }

    Offline storage façade (GeoLeaf.Storage), mounted in-core by kernel/storage/facade.ts.

    ⚠️ The [key: string]: unknown tail makes any member not named here unknown — hence not callable — and no gate flags it: HOST-06 only rejects a fully empty declaration. A member that is a public API gets named.

    Type Declaration

    • OptionalDB?: GeoLeafStorageDB

      The IndexedDB engine. Its relays are named by GeoLeafStorageDB; what is not named there stays in ITS OWN tail — the namespace's tail is gone, this one is not.

    • Optionaldb?: GeoLeafStorageDB

      Lower-case alias of DB — the same engine.

    • OptionalwhenReady?: () => Promise<void>

      Resolves when the offline engine is ready; never while modules.offline is off.

    • OptionalmayEdit?: (layerId: string, kind: "delete" | "create" | "update") => boolean

      Does the layer grant this operation? Synchronous, read from the active profile; an unknown layer yields false.

    • OptionalcanQueueWrites?: (layerId: string) => boolean

      Will a write to this layer be held on the device? false without the engine.

    • OptionalapplyEdit?: (
          input: {
              layerId: string;
              kind: "delete" | "create" | "update";
              localId?: string;
              feature?: unknown;
              baseVersion?: { kind: "timestamp" | "etag"; value: string } | null;
          },
      ) => Promise<StorageEditReport>

      Records a capture on the device and queues it for the server — possibly merged into, or cancelling, an entry already owed for that entity. Never throws: refused carries the motive.

    • OptionalpushOutbox?: () => Promise<StoragePushReport>

      Runs a drain pass — or joins the one in progress — and returns its tally. Never throws.

    • OptionalrequeueQuarantined?: (id: string) => Promise<StorageQuarantineOutcome>

      Puts one set-aside entry back in the queue, if its motive is requeueable and, where that is checkable, its cause is observed as lifted.

    • OptionalrequeueAll?: (reason?: string) => Promise<StorageBatchRequeueOutcome>

      Same rule, for every set-aside entry — or for those of one motive only.

    • OptionaldiscardQuarantined?: (id: string, confirmedLocalId: string) => Promise<StorageQuarantineOutcome>

      Destroys one set-aside entry, confirmed by the localId the caller listed.

    • OptionalrequeueableReasons?: () => readonly string[]

      The set-aside motives a requeue can lift.

    • OptionallistConflicts?: (
          layerId?: string,
          scope?: { allProfiles?: boolean },
      ) => Promise<StorageConflictRecord[]>

      The server versions a lastWriteWins conflict overwrote, one per entity.

    • OptionalclearConflicts?: (layerId?: string, scope?: { allProfiles?: boolean }) => Promise<boolean>

      Drops the archived conflicts of one layer, or of all.

    • pullLayer?: function
      • Bounded pull of a declared layer into the features store. Never confers editability (a standing invariant). Does not throw: refused carries the motive when nothing was written.

        Parameters

        • layerId: string
        • Optionaloptions: { bbox?: [number, number, number, number]; signal?: AbortSignal }

        Returns Promise<
            {
                layerId: string;
                fetched: number;
                written: number;
                preserved: number;
                unchanged: number;
                removed: number;
                skipped: number;
                capped: boolean;
                aborted: boolean;
                cursorRefused: boolean;
                mode: "full"
                | "delta"
                | null;
                refused: string | null;
            },
        >

    • getSyncReport?: function
      • Per-layer synchronisation report.

        Makes declaredNeverPulled observable: a layer declaring a pull source (offline.source) but never pulled is otherwise indistinguishable from a pulled one, until the instant the network drops. Does not throw — with no engine wired, returns [].

        Returns Promise<readonly LayerSyncReport[]>

    • getSyncStatus?: function
      • The write queue as a whole — network, entries owed, entries set aside, and the last accepted push.

        Distinct from getSyncReport above, which answers per layer. This one answers the question a field user asks before closing the application, and that question has no layer in it. Does not throw — with no engine wired, it answers zeros, which is what "there is no queue here" looks like.

        Returns Promise<SyncStatus>

    • resolveOptions?: function
      • The choices of a dropdown declared by URL — held on the device first, fetched and kept otherwise. null when nothing can answer: the caller fetches itself.

        Parameters

        • url: string

        Returns Promise<{ value: string; label: string }[] | null>

    • preflight?: function
    • OptionalprefetchVerdict?: (url: string) => StoragePrefetchVerdict

      Will the offline preparation download this URL, and if not, why — the origin rule of modules.offline.dataOrigins, asked before the download.

    • OptionalwireModules?: (
          modules: {
              db?: unknown;
              cacheManager?: unknown;
              cache?: unknown;
              pull?: unknown;
              report?: unknown;
              edit?: unknown;
              ui?: unknown;
              options?: unknown;
          },
      ) => void

      Injects the offline engine's modules — called by the engine itself when it loads.

    • Optionalinit?: (options?: StorageInitOptions) => Promise<boolean>

      Initialises the wired sub-modules; resolves false when nothing is wired.

    • OptionalisAvailable?: () => boolean

      Whether the offline engine is wired and its database usable.

    • OptionalisPluginLoaded?: () => boolean

      Whether the offline engine's modules have been injected.

    • OptionalisOffline?: () => boolean

      Whether the network detector currently says offline.

    • OptionalgetStats?: () => Promise<
          {
              storage: { used: number; quota: number; percentage: number };
              layers: { count: number; byProfile: Record<string, number> };
              features: { count: number };
              outbox: { count: number };
              conflicts: { count: number };
              cache: { profiles: string[] };
              online: boolean;
          },
      >

      Quota, usage and the tallies of the data-bearing stores.

    • OptionalgetOfflineProfiles?: () => Promise<string[]>

      The profiles prepared for offline use on this device.

    • OptionalisProfileAvailableOffline?: (profileId: string) => Promise<boolean>

      Whether one profile was prepared for offline use.

    • OptionalclearAll?: () => Promise<void>

      Erases every prepared profile, the cached tiles and the engine's own stores.

    • Optionalclose?: () => void

      Closes the database handle.

    • OptionalCacheManager?: CacheManagerLike

      The cache manager, when the engine is wired — the façade's narrow view of it.

    • OptionalcacheManager?: CacheManagerLike

      Lower-case alias of CacheManager.

    • OptionalOfflineDetector?: OfflineDetectorLike

      The network detector, when the engine is wired — the façade's narrow view of it.

    • OptionalCache?: unknown

      The cache namespace of the engine. Untyped: the façade hands it over as unknown.

    • Optionalcache?: unknown

      Lower-case alias of Cache.

    GeoJSON?: {
        getLayerById?(id: string): unknown;
        getAllLayers(): unknown;
        getLayerData?(id: string): unknown;
        setWorkerUrl?(url: string | null): void;
        [key: string]: unknown;
    }

    GeoJSON subsystem façade (GeoLeaf.GeoJSON) — 87 call sites across the plugins, the single most-used member of the host, and typed nowhere before S3.

    ⚠️ Distinct from Layers above: Layers is the per-layer data seam.

    Type Declaration

    • [key: string]: unknown
    • getLayerById?: function
    • getAllLayers: function
    • getLayerData?: function
    • setWorkerUrl?: function
      • Sets the URL of the GeoJSON Web Worker script — null restores the default. For a bundle run as a module, that is geojson-worker.js in the directory of the last <script src> of the page naming a geoleaf…js file (a plugin's included), or resolved against the page when none does (a bundle imported from an inline module script, with no plugin loaded by <script src>). Applies to the next worker built; call it before GeoLeaf.boot() to cover the first one. Throws a TypeError on any value other than a non-blank string or null.

        Parameters

        • url: string | null

        Returns void

    Logger façade (GeoLeaf.Log).

    Same reason as registry above — LogImplInterface is an interface, so it carries no implicit index signature and a loose { error?; …; [key]: unknown } shape would reject what globals.core.ts actually mounts.

    Notifications?: {
        show?(
            message: string,
            typeOrOptions?: unknown,
            duration?: number,
        ): unknown;
        [key: string]: unknown;
    }

    Toast façade (GeoLeaf.Notifications), mounted by the toast-renderer capability.

    Table?: unknown

    @geoleaf-plugins/table — tabular panel.

    Geocoding?: unknown

    @geoleaf-plugins/geocoding — address search.

    RealtimeLayer?: unknown

    @geoleaf-plugins/realtime-layer — realtime feeds (GTFS-RT…).

    PositionShare?: unknown

    @geoleaf-plugins/position-share — user position broadcasting.

    Routing?: unknown

    @geoleaf-plugins/routing — multi-stop route computation.

    Navigation?: unknown

    @geoleaf-plugins/navigation — realtime guidance.

    ⚠️ Two packages and not one: computation has value alone, guidance has none without it. The dependency is asymmetric, so the boundary sits there — and navigation imports only TYPES from routing.

    Isochrone?: unknown

    @geoleaf-plugins/isochrone — zones reachable from a point, asked of a routing engine.

    FlatGeobuf?: unknown

    @geoleaf-plugins/flatgeobuf — FlatGeobuf reads by bbox.

    Connector?: unknown

    @geoleaf-plugins/connector — bridge to the Connector backend.

    COG?: unknown

    @geoleaf-plugins/cog — Cloud Optimized GeoTIFF.

    FileImport?: unknown

    @geoleaf-plugins/file-import — GPX/KML/KMZ/CSV/TSV/TopoJSON conversion.

    Measure?: unknown

    @geoleaf-plugins/measure — measuring tools.

    ⚠️ Not to be confused with lowercase measure, higher in this same interface: that one is the performance-measuring helper between two marks. The two differ only by case. The compiler is in fact what flagged it — the declaration probe yielded TS2551 "Did you mean 'measure'?" on this name.

    Print?: unknown

    @geoleaf-plugins/print — printable map export.

    Editor?: unknown

    @geoleaf-plugins/editor — feature editing.

    Ws?: unknown

    @geoleaf-plugins/websocket — WebSocket feeds (mounted as Ws, not Websocket).

    getPerformanceMetrics?: () => unknown

    Runtime metrics (historical alias of getRuntimeMetrics).

    getRuntimeMetrics?: () => unknown

    Runtime metrics — init time, memory, rendering.

    resetRuntimeMetrics?: () => void

    Resets the metric counters to zero.