GeoLeaf Core API - v3.0.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 {
        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;
            [key: string]: unknown;
        };
        Utils?: {
            createElement?: (
                tag: string,
                props: Record<string, unknown>,
                ...children: unknown[],
            ) => HTMLElement;
            events?: GeoLeafUtilsEvents;
            [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: any): ResolvedIcon;
            getIconVariants(): TaxonomyIconVariant[];
            resolveMarkerPaint(
                layerId: string,
                existingPaint: Record<string, unknown>,
            ): Record<string, unknown> | null;
            resolveTitleIcon(
                layerId: string,
                feature: any,
                surface: TaxonomySurface,
            ): string | null;
            resolveBadgeStyle(
                layerId: string,
                feature: any,
                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;
            getHandlers(): SyncHandler[];
        };
        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;
        };
        Introspection?: IIntrospectionAPI;
        Layers?: LayerDataApi;
        Geolocation?: GeolocationPublicApi;
        Branding?: BrandingPublicApi;
        Cluster?: ClusterPublicApi;
        Coordinates?: CoordinatesPublicApi;
        FeatureInfo?: FeatureInfoPublicApi;
        Labels?: LabelsPublicApi;
        NotificationSystem?: typeof NotificationSystem;
        PWA?: {
            init(config: PWAConfig): void;
            isInstallable(): 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: unknown,
                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?: {
                beforeBoot?: (
                    context: { config: Readonly<Record<string, unknown>> },
                ) => void | Promise<void>;
                onPerformanceMetrics?: (
                    metrics: {
                        timeToMapReadyMs: number | null;
                        timeToAppReadyMs: number | null;
                        startupTotalMs: number | null;
                        capturedAt: string;
                    },
                ) => void;
            },
        ) => void;
        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): unknown;
            getAdapter(mapId?: string): unknown;
            destroy(mapId: string): boolean;
            hasMap(mapId: string): boolean;
            listMaps(): string[];
            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;
            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?: Record<string, unknown>;
            pullLayer?(
                layerId: string,
                options?: {
                    bbox?: [number, number, number, number];
                    signal?: AbortSignal;
                },
            ): Promise<
                {
                    layerId: string;
                    fetched: number;
                    written: number;
                    preserved: number;
                    skipped: number;
                    capped: boolean;
                    aborted: boolean;
                    refused: string
                    | null;
                },
            >;
            getSyncReport?(): Promise<readonly LayerSyncReport[]>;
            [key: string]: unknown;
        };
        GeoJSON?: {
            getLayerById?(id: string): unknown;
            getAllLayers(): unknown;
            getLayerData?(id: string): unknown;
            [key: string]: unknown;
        };
        Log?: LogImplInterface;
        Notifications?: {
            show?(
                message: string,
                typeOrOptions?: unknown,
                duration?: number,
            ): unknown;
            [key: string]: unknown;
        };
        Table?: unknown;
        Geocoding?: unknown;
        RealtimeLayer?: unknown;
        FlatGeobuf?: unknown;
        Connector?: unknown;
        COG?: unknown;
        FileImport?: unknown;
        Measure?: unknown;
        Print?: unknown;
        Editor?: unknown;
        Ws?: unknown;
        getPerformanceMetrics?: () => unknown;
        getRuntimeMetrics?: () => unknown;
        resetRuntimeMetrics?: () => void;
    }
    Index

    Properties

    GeoLeaf.UI — la façade UI du kernel.

    ⚠️ Déclarée Record<string, unknown> jusqu'à l'API S4.2, elle était comptée parmi les membres « typés » alors qu'elle ne vérifiait rien : ce type accepte n'importe quel objet et rend unknown sur chaque accès, exactement comme la traîne qu'il était censé remplacer. C'est HOST-06 (check-namespace-typing-coverage.cjs) qui l'a trouvée, en refusant de compter une déclaration vide comme un typage.

    ⚠️ globals.ui.ts:128 pose _gl.UI = {} si absent : tous les membres de GeoLeafUIFacade sont donc optionnels. Et son typage ne peut PAS passer par typeof import(...) — la façade est auto-montée, le détail est sur l'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
      • Whether the capability is active — mirrors the modules.filter.enabled gate.

        Returns boolean

    • getConfig: function
      • The resolved filter configuration for the active profile.

        Returns unknown

    • getActiveFilter: function
      • The filter state currently applied to the map.

        Returns unknown

    • applyFilter: function
      • Applies a filter state (debounced — see applyNow to flush immediately).

        Parameters

        • state: unknown

        Returns void

    • applyNow: function
      • Flushes the pending debounced filter immediately.

        Returns void

    • reset: function
      • Clears every active filter and restores the unfiltered view.

        Returns void

    • hasActiveFilters: function
      • Whether at least one filter is currently narrowing the view.

        Returns boolean

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

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

      • setRadius: function
        • Sets the proximity radius, in kilometres.

          Parameters

          • radiusKm: number

          Returns void

      • 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;
        [key: string]: unknown;
    }

    Type Declaration

    • [key: string]: unknown
    • get: function
      • Parameters

        • key: string
        • Optionaldef: unknown

        Returns unknown

    • getAll: function
    • getActiveProfile?: function
      • Profil actif enrichi. Son tableau layers porte les configurations de couche complètes — à la différence de getAllLayerConfigs(), qui est une projection en liste blanche et ne porte ni offline, ni data, ni write.

        ⚠️ Config.Profile n'est PAS monté ici, bien que le module Config le porte : mesuré en navigateur (tâche 4.1). Passer par getActiveProfile().

        Returns unknown

    Utils?: {
        createElement?: (
            tag: string,
            props: Record<string, unknown>,
            ...children: unknown[],
        ) => HTMLElement;
        events?: GeoLeafUtilsEvents;
        [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;
    }

    Façade de la légende (GeoLeaf.Legend).

    ⚠️ Les 8 membres ci-dessous étaient implémentés et documentés dans capabilities/legend/legend.ts@example compris — mais non déclarés ici, donc absents de la page GeoLeafGlobal que TypeDoc rend et que lit un intégrateur (B-229). La traîne [key: string]: unknown subsiste (gisement B-13).

    Type Declaration

    • [key: string]: unknown
    • init: function
      • Monte la légende sur une carte. Rend false si le montage échoue.

        Parameters

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

        Returns boolean

    • loadLayerLegend: function
      • Charge et rend l'entrée de légende d'une couche, pour un style donné.

        Parameters

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

        Returns void

    • setLayerVisibility: function
      • Affiche ou masque une couche depuis la légende.

        Parameters

        • layerId: string
        • visible: boolean

        Returns void

    • getAllLayers: function
      • Toutes les couches connues de la légende, indexées par identifiant.

        Returns Map<string, unknown>

    • hideLegend: function
      • Masque le panneau sans le démonter — l'état des couches est conservé.

        Returns void

    • removeLegend: function
      • Démonte le panneau et libère ses écouteurs.

        Returns void

    • isLegendVisible: function
      • Si le panneau est actuellement visible.

        Returns boolean

    • toggleAccordion: (id: string) => void

      Plie ou déplie la section d'une couche.

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

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

    Type Declaration

    • [key: string]: unknown
    • isEnabled: function
    • getIcons: function
    • getCategories: function
    • getFieldMappings: function
    • getLayerCategories: function
      • La table valeur → symbole d'une couche donnée (vide si la couche ne déclare aucune taxonomie). B-229 : implémenté et documenté dans capabilities/taxonomy/public-api.ts, mais non déclaré ici jusqu'au 11/08/2026.

        Parameters

        • layerId: string

        Returns Record<string, TaxonomyCategory>

    • resolvePoiIcon: function
    • getIconVariants: function
    • resolveMarkerPaint: function
      • Peinture MapLibre d'une couche de marqueurs, ou null si la taxonomie ne s'applique pas.

        Parameters

        • layerId: string
        • existingPaint: Record<string, unknown>

        Returns Record<string, unknown> | null

    • resolveTitleIcon: function
      • Le symbolId de l'icône à afficher à côté du TITRE d'une entité sur une surface feature-info, en honorant les drapeaux render par surface (priorité sous-catégorie → catégorie → défaut).

        Parameters

        Returns string | null

    • resolveBadgeStyle: function
    • ensureSprite: function
      • Garantit que le sprite SVG du profil actif (ses <symbol>) est présent dans le DOM, pour qu'un <use href="#…"> puisse le référencer. Sans attente et idempotent — le chargeur dédoublonne.

        Returns void

    _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._LayerVisibilityManagercontrat de fait, délibérément NON promu.

    API publique S4.3d a examiné sa promotion en GeoLeaf.Layers.getVisibilityState() et l'a écartée, pour deux raisons mesurées :

    1. Elle n'aurait retiré aucune clé. Le motif annoncé était « promouvoir puis retirer _LayerVisibilityManager du namespace » — impossible : le CORE le relit lui-même par le global à 5 sites, avec 3 méthodes différentes (kernel/geojson/layers/visibility.ts:87,159,207,246 et capabilities/legend/legend.ts:163). La promotion n'achetait qu'un chemin typé pour plugin-table, au prix d'une entrée publique de plus.

    2. La forme est un piège, et le publier le graverait. getVisibilityState() rend 6 champs, dont current — la visibilité PHYSIQUE, que le zoom force à false — et logicalState, l'intention utilisateur. Le backlog B.19 consigne que lire current pour piloter un toggle est le bug DÉJÀ commis. Or les 2 sites de plugin-table lisent exactement current. Publier dans LayerDataApi est irréversible (règle Q1 : on ajoute un sous-chemin, on n'en retire jamais).

    Lecteurs de fait, hors core : packages/plugins/table/src/panel.ts:236 et src/table-layer.ts:93. Ils restent sur cette clé, sciemment.

    Sync?: {
        registerHandler(id: string, handler: SyncHandler): void;
        getHandler(id: string): SyncHandler | undefined;
        getHandlers(): SyncHandler[];
    }

    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/addpoi does GeoLeaf.Sync.registerHandler("poi", POISyncHandler) 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

    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:273 declares shouldUseVectorTiles / loadVectorTileLayer, layer-manager/style.ts:17 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 (R.33, backlog résiduel S5). 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 and records shared state. 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
    Introspection?: IIntrospectionAPI
    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 déclaré dans 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;
        _reset(): void;
    }

    PWA install/update manager — GeoLeaf.PWA. Pas de type public nommé, cf. ci-dessus.

    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.

    • _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 (S7.5 — 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. Pas de type public nommé.

    Type Declaration

    • init: function
      • Initialise the Permalink module with the config extracted from the active profile. Must be called before readAndStore().

        Parameters

        • config: PermalinkConfig

          Permalink section of ui.permalink or an empty object.

        Returns void

        GeoLeaf.Permalink.init({ enabled: true, mode: "hash" });
        
    • readAndStore: function
      • Read the current URL and cache the parsed state. Call this before map creation so the stored state is available for applyStoredState.

        Returns void

    • applyStoredState: function
    • startSync: function
    • stopSync: function
    • getState: function
      • Return the currently cached permalink state (read-only). Returns null if readAndStore was not called or found no permalink in the URL.

        ⚠️ A null therefore means two different things — the page was not opened through a permalink, or Permalink.readAndStore has not run yet. Only the boot order tells them apart.

        Returns PermalinkState | null

        const state = GeoLeaf.Permalink.getState();
        // → { lat: 48.857, lng: 2.347, zoom: 13, layers: [], filter: "café" }
        // → null
    • buildUrl: function
      • Serialise state (or the cached stored state) to a URL fragment / query string.

        Parameters

        • Optionalstate: PermalinkState | null

          Optional explicit state. Falls back to _storedState.

        Returns string

        URL string starting with # or ?, or empty string if no state.

        // Current stored state
        const url = GeoLeaf.Permalink.buildUrl();
        // → "#gl_lat=48.857445&gl_lng=2.347211&gl_zoom=13"
        // Un lien partageable complet — le fragment seul ne suffit pas.
        const permalinkUrl =
        window.location.origin + window.location.pathname + GeoLeaf.Permalink.buildUrl();
    • isEnabled: function
    • getConfig: function

    Scale bar control — GeoLeaf.Scale.

    ProfileSwitcher?: ProfileSwitcherPublicApi

    Data-profile selector — GeoLeaf.ProfileSwitcher (S1 sélecteurs UI).

    LanguageSwitcher?: LanguageSwitcherPublicApi

    UI language selector — GeoLeaf.LanguageSwitcher (S2 sélecteurs UI).

    ThemePalette?: ThemePalettePublicApi

    Accent-colour palette — GeoLeaf.ThemePalette (S3 sélecteurs UI).

    Share sheet — GeoLeaf.Share, sous-dossier de la capacité permalink.

    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;
    }

    Alias historique de GeoLeafGlobal.Baselayers — même référence, même 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 off() is called.

        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

        GeoLeaf.Events.on("geoleaf:poi:click", (e) => {
        console.log("POI cliqué :", e.detail.poiId);
        });
    • 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

        // Le handler doit être NOMMÉ : une fonction anonyme ne peut jamais être retirée.
        const handlePoiClick = (e) => {
        console.log(e.detail.poiId);
        };
        GeoLeaf.Events.on("geoleaf:poi:click", handlePoiClick);

        // Plus tard :
        GeoLeaf.Events.off("geoleaf:poi:click", handlePoiClick);
    • 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

        • event: K

          Event name.

        • handler: GeoLeafEventHandler<K>

          Callback called at most once.

        Returns void

        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;
    }

    Alias minuscule de GeoLeafGlobal.Events — même référence, même type.

    Type Declaration

    • on: function
      • Registers a listener for a GeoLeaf event. The listener is called every time the event fires until off() is called.

        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

        GeoLeaf.Events.on("geoleaf:poi:click", (e) => {
        console.log("POI cliqué :", e.detail.poiId);
        });
    • 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

        // Le handler doit être NOMMÉ : une fonction anonyme ne peut jamais être retirée.
        const handlePoiClick = (e) => {
        console.log(e.detail.poiId);
        };
        GeoLeaf.Events.on("geoleaf:poi:click", handlePoiClick);

        // Plus tard :
        GeoLeaf.Events.off("geoleaf:poi:click", handlePoiClick);
    • 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

        • event: K

          Event name.

        • handler: GeoLeafEventHandler<K>

          Callback called at most once.

        Returns void

        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 — posé par globals.core.ts:63.

    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 — posé par globals.core.ts:62.

    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 in the legend

        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: unknown,
            metadata?: Record<string, unknown>,
        ): Promise<void>;
        invalidate(layerId: string): Promise<void>;
    }

    Theme cache — posé par globals.ui.ts:120, hors de la chaîne des façades.

    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: unknown
        • 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.

    Un seul écrivain depuis socle-init 7.7 : globals/globals.api.ts, sous garde if (!_gl.version) — ce qui rend setupAPIKernel() ré-appelable sans écraser une version déjà posée.

    ⚠️ Cette note disait « Écrite à DEUX endroits : globals.api.ts:200 […] et kernel/api/geoleaf-api.ts:133 sans garde. Le dernier writer gagne » — c'était vrai (divergence D8), et les deux numéros de ligne avaient dérivé (208 et 164 au moment du retrait). Une citation de ligne dans un commentaire vieillit sans bruit ; celle-ci ne renvoie plus qu'au fichier.

    GeoLeaf.API — les constructeurs de l'API, assemblés en littéral par globals.api.ts:75-84.

    ⚠️ Écrit à la main, et c'est mesuré : contracts/api.contract.ts:103 déclare bien IGeoLeafAPIConstructors, mais il ne couvre que les 3 alias, pas les 7 clés réellement posées. Le référencer aurait typé moins de la moitié de l'objet tout en ayant l'air de le typer — le défaut que HOST-06 traque, un cran plus haut.

    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, liée — requête HTTP instrumentée.

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

    FetchHelper.get, liée.

    Optionalpost

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

    FetchHelper.post, liée.

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

    Rapport de démarrage (⚠️ minuscule côté namespace, BootInfo côté module).

    Type Declaration

    boot?: (
        options?: {
            beforeBoot?: (
                context: { config: Readonly<Record<string, unknown>> },
            ) => void | Promise<void>;
            onPerformanceMetrics?: (
                metrics: {
                    timeToMapReadyMs: number | null;
                    timeToAppReadyMs: number | null;
                    startupTotalMs: number | null;
                    capturedAt: string;
                },
            ) => void;
        },
    ) => void

    Démarre l'application GeoLeaf : charge le profil, crée la carte, initialise les modules. C'est l'entrée applicative — apps/geoleaf-app/init.js l'appelle, et l'ordre de chargement de tous les plugins s'y réfère.

    ⚠️ À ne pas confondre avec GeoLeafGlobal.init, qui est l'enveloppe manuelle de Core.init(). Le chemin de boot passe par registry.init() — celui du ModuleRegistry — et n'appelle jamais GeoLeaf.init.

    Les deux options sont le seul canal par lequel un hôte pose un gate d'auth (SSO) ou récupère les métriques de démarrage ; elles sont relues depuis _beforeBootCallback et _perfCallback, qui restent hors de ce contrat (dette D-14).

    mark?: (name: string) => void

    Pose une marque de performance nommée.

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

    Mesure entre deux marques ; rend la durée en millisecondes.

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

    Rapport de performance agrégé du profileur.

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

    Fige la mesure courante comme référence de comparaison.

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

    Notification utilisateur — primitive, indépendante du rendu.

    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): unknown;
        getAdapter(mapId?: string): unknown;
        destroy(mapId: string): boolean;
        hasMap(mapId: string): boolean;
        listMaps(): string[];
        setTheme(theme: string): void;
        getTheme(): string;
        [key: string]: unknown;
    }

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

    Depuis la v3.0.0, Core tient un registre indexé d'adaptateurs (Map<mapId, IMapAdapter>) : N cartes coexistent sur une page, chacune avec son cycle de vie. Le singleton de module des versions ≤ 2.1.x n'existe plus.

    ⚠️ La traîne [key: string]: unknown subsiste (gisement B-13) : les 8 membres ci-dessous sont désormais déclarés et documentés, le reste du namespace ne l'est pas encore. Ne jamais l'élargir vers any.

    Type Declaration

    • [key: string]: unknown
    • init: function
      • Initialise une carte. Exige options.mapId — sans lui, rend null et journalise. Ré-initialiser un mapId existant rend l'instance déjà en place plutôt que d'en créer une seconde.

        Parameters

        • Optionaloptions: Record<string, unknown>

        Returns unknown

    • getMap: function
      • L'instance ciblée par mapId ; sans argument, la première instance active — forme rétro-compatible pour les applications mono-carte.

        Parameters

        • OptionalmapId: string

        Returns unknown

    • getAdapter: function
      • Alias de getMap.

        Parameters

        • OptionalmapId: string

        Returns unknown

    • destroy: function
      • Détruit l'instance (map.remove() puis libère l'emplacement du registre). Rend true si elle existait. À appeler au démontage côté consommateur.

        Parameters

        • mapId: string

        Returns boolean

    • hasMap: function
      • Si une instance est enregistrée sous ce mapId.

        Parameters

        • mapId: string

        Returns boolean

    • listMaps: function
      • Les identifiants de toutes les instances actives.

        Returns string[]

    • setTheme: function
      • Applique un thème au conteneur de la carte.

        ⚠️ Le thème reste global en v3.0.0 et s'applique à la première instance : l'isolation par carte est hors périmètre de cette version.

        Parameters

        • theme: string

        Returns void

    • getTheme: function
    plugins?: {
        register?(name: string, meta?: Record<string, unknown>): void;
        registerLazy?(name: string, resolver: () => Promise<void>): 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 et registerLazy ont été ajoutés le 31/07/2026, et pas par confort de typage. Les trois sont enseignés par docs/API_REFERENCE.md (section « Plugins ») depuis longtemps, existent dans kernel/api/plugin-registry.ts et partent dans le bundle livré — mais n'étaient déclarés nulle part ici, donc ils tombaient dans la traîne [key: string]: unknown.

    Ce que ça coûtait, mesuré : showBootInfo(GeoLeaf) — l'appel que sa propre doc montre — ne compilait pas. BootInfoNamespace exige plugins?.getLoadedPlugins?: () => string[] ; résolu par la traîne, le membre valait unknown, et unknown n'est pas assignable à (() => string[]) | undefined. Le défaut n'était visible d'aucune gate tant que l'exemple de showBootInfo s'écrivait showBootInfo() — c'est-à-dire tant qu'il était faux d'une AUTRE manière, gelée dans la baseline du typecheck. Un diagnostic gelé masque ce qui vit sous lui.

    Rétrécir la traîne est le sens autorisé (B-13) : jamais élargir vers any.

    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:135 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?: Record<string, unknown>;
        pullLayer?(
            layerId: string,
            options?: {
                bbox?: [number, number, number, number];
                signal?: AbortSignal;
            },
        ): Promise<
            {
                layerId: string;
                fetched: number;
                written: number;
                preserved: number;
                skipped: number;
                capped: boolean;
                aborted: boolean;
                refused: string
                | null;
            },
        >;
        getSyncReport?(): Promise<readonly LayerSyncReport[]>;
        [key: string]: unknown;
    }

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

    ⚠️ La traîne [key: string]: unknown rend unknown — donc non appelable — tout membre non nommé ici, et aucune gate ne le signale : HOST-06 ne rejette qu'une déclaration entièrement vide. Un membre qui est une API publique se nomme.

    Type Declaration

    • [key: string]: unknown
    • OptionalDB?: Record<string, unknown>
    • pullLayer?: function
      • Rapatriement borné d'une couche déclarée vers le store features (tâche 4.1). Ne confère jamais l'éditabilité (invariant S6). Ne jette pas : refused porte le motif quand rien n'a été écrit.

        Parameters

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

        Returns Promise<
            {
                layerId: string;
                fetched: number;
                written: number;
                preserved: number;
                skipped: number;
                capped: boolean;
                aborted: boolean;
                refused: string
                | null;
            },
        >

    • getSyncReport?: function
      • Rapport de synchronisation par couche (tâche 4.8).

        Rend declaredNeverPulled observable : une couche déclarée hors-ligne mais jamais rapatriée est autrement indiscernable d'une couche rapatriée, jusqu'à l'instant où le réseau tombe. Ne jette pas — sans moteur câblé, rend [].

        Returns Promise<readonly LayerSyncReport[]>

    GeoJSON?: {
        getLayerById?(id: string): unknown;
        getAllLayers(): unknown;
        getLayerData?(id: string): unknown;
        [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 de Layers ci-dessus : Layers est le seam de données par couche.

    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:61 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 — panneau tabulaire.

    Geocoding?: unknown

    @geoleaf-plugins/geocoding — recherche d'adresses.

    RealtimeLayer?: unknown

    @geoleaf-plugins/realtime-layer — flux temps réel (GTFS-RT…).

    FlatGeobuf?: unknown

    @geoleaf-plugins/flatgeobuf — lecture FlatGeobuf par bbox.

    Connector?: unknown

    @geoleaf-plugins/connector — pont vers le backend Connector.

    COG?: unknown

    @geoleaf-plugins/cog — Cloud Optimized GeoTIFF.

    FileImport?: unknown

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

    Measure?: unknown

    @geoleaf-plugins/measure — outils de mesure.

    ⚠️ Ne pas confondre avec measure en minuscule, plus haut dans cette même interface : celui-là est l'aide de mesure de performance entre deux marques. Les deux ne diffèrent que par la casse. C'est d'ailleurs le compilateur qui l'a signalé — la sonde de B-52 a rendu TS2551 « Did you mean 'measure'? » sur ce nom.

    Print?: unknown

    @geoleaf-plugins/print — export imprimable de la carte.

    Editor?: unknown

    @geoleaf-plugins/editor — édition d'entités.

    Ws?: unknown

    @geoleaf-plugins/websocket — flux WebSocket (monté sous Ws, pas Websocket).

    getPerformanceMetrics?: () => unknown

    Métriques runtime (alias historique de getRuntimeMetrics).

    getRuntimeMetrics?: () => unknown

    Métriques runtime — temps d'init, mémoire, rendu.

    resetRuntimeMetrics?: () => void

    Remet les compteurs de métriques à zéro.