GeoLeaf Core API - v3.0.0
    Preparing search index...
    IndexedDB: {
        init(): Promise<StorageDBInstance>;
        cacheLayer(
            id: string,
            data: unknown,
            profileId: string,
            metadata?: Record<string, unknown>,
        ): Promise<unknown>;
        getLayer(id: string): Promise<unknown>;
        getLayerFeatureCollection(
            layerId: string,
        ): Promise<{ type: "FeatureCollection"; features: unknown[] } | null>;
        applyLocalEdit(input: LocalEditInput): Promise<LocalEditTally | null>;
        putLayerFeatures(
            records: readonly FeatureRecord[],
        ): Promise<PreservingPutTally | null>;
        getSyncCounts(
            layerIds: readonly string[],
        ): Promise<
            | Record<
                string,
                { featureCount: number; pendingCount: number; quarantinedCount: number },
            >
            | null,
        >;
        listPendingEdits(): Promise<
            {
                entryId: string;
                kind: string;
                layerId: string;
                localId: string;
                state: string;
                createdAt: number;
                feature: unknown;
            }[],
        >;
        purgeCachedFeatures(): Promise<{ removed: number; preserved: number }>;
        removeLayer(id: string): Promise<unknown>;
        getLayersByProfile(profileId: string): Promise<unknown>;
        clearProfile(profileId: string): Promise<unknown>;
        getStorageStats(): Promise<StorageStatsReport>;
        setPreference(key: string, value: unknown): Promise<unknown>;
        getPreference(key: string, defaultValue?: unknown): Promise<unknown>;
        storeImageLocally(imageData: unknown): Promise<unknown>;
        getPendingImages(): Promise<unknown>;
        updateImageUploadStatus(id: string, status: string): Promise<unknown>;
        deleteLocalImage(id: string): Promise<unknown>;
        cleanUploadedImages(): Promise<unknown>;
        close(): void;
    } = StorageDB

    Public name of the StorageDB façade: opens the offline database, wires the db/ modules through DBModulesRegistry, and forwards the layer/sync/image/ backup/preference operations to whichever module owns each object store.

    This is the handle offline-engine-entry.ts passes to GeoLeaf.Storage.wireModules().

    Type Declaration

    • init: function
    • cacheLayer: function
      • Parameters

        • id: string
        • data: unknown
        • profileId: string
        • metadata: Record<string, unknown> = {}

        Returns Promise<unknown>

    • getLayer: function
    • getLayerFeatureCollection: function
      • Reads a layer's offline entities back as a GeoJSON FeatureCollection.

        🛑 PREMIER LECTEUR DU STORE features (tâche 4.3). Le store existe depuis 3.4 et n'avait ni producteur ni consommateur : DBFeatures n'était référencé que par db-modules-registry.ts. Son écrivain est arrivé en 4.1 — voir IndexedDB.putLayerFeatures juste en dessous.

        ⚠️ Rend une FeatureCollection et non les enregistrements bruts, parce que l'appelant est le chargeur de couche du kernel : il attend la même forme que celle qu'un fetch lui aurait rendue, et la faire diverger obligerait le seam à distinguer deux formes — la distinction même que cette lecture existe pour supprimer.

        ⚠️ Rend null — et non une collection VIDE — quand rien n'est stocké. Une collection vide est indiscernable d'une couche réellement vide, et l'appelant doit pouvoir retomber sur le réseau plutôt que d'afficher zéro entité en croyant avoir lu.

        Parameters

        • layerId: string

          Identifiant de la couche.

        Returns Promise<{ type: "FeatureCollection"; features: unknown[] } | null>

        La collection, ou null si la couche n'a aucune entité stockée.

    • applyLocalEdit: function
      • Applique une édition locale — l'entité ET sa mise en file, dans UNE transaction (4.4).

        Miroir d'écriture de IndexedDB.getLayerFeatureCollection : la façade délègue, elle n'arbitre pas. La coalescence et l'annulation vivent dans db/local-edit.ts, seul endroit où les deux stores tiennent dans une même transaction.

        ⚠️ Ne vérifie AUCUN droit d'édition. L'invariant S6 — le rapatriement ne confère jamais l'éditabilité — se tient une couche plus haut, là où la déclaration de la couche est lisible. Le mettre ici en ferait une règle de stockage, donc contournable par tout appelant qui parlerait à la base directement.

        Parameters

        Returns Promise<LocalEditTally | null>

        Ce qui a été fait (fusion, annulation, entrée neuve), ou null sans module.

    • putLayerFeatures: function
      • Writes a pulled batch into the features store — the store's FIRST writer (tâche 4.1).

        Miroir de IndexedDB.getLayerFeatureCollection : la façade délègue, elle n'arbitre pas. La règle « ne jamais écraser une saisie non synchronisée » vit dans db/features.ts, seul endroit où lecture et écriture tiennent dans une transaction.

        ⚠️ Chaque enregistrement doit porter un feature défini. getLayerFeatureCollection décide son null sur records.length === 0, avant de filtrer les feature indéfinis : un lot écrit sans géométrie lui ferait rendre une collection vide et non nulle, et le chargeur afficherait zéro entité en croyant avoir lu.

        Parameters

        • records: readonly FeatureRecord[]

          Enregistrements complets, feature compris.

        Returns Promise<PreservingPutTally | null>

        Le décompte réel { written, preserved }, ou null si le module est absent.

    • getSyncCounts: function
      • Counts what the sync report needs, per layer, in one pass (tâche 4.8).

        🛑 UNE méthode plutôt que quatre. La composition du rapport a besoin de trois décomptes par couche ; les exposer un à un (countByLayer, listByState…) élargirait la façade de quatre membres pour un seul consommateur, et déplacerait la connaissance des magasins hors de la couche qui les possède. La façade délègue, elle n'arbitre pas — mais ce qu'elle délègue est le décompte, pas les magasins.

        ⚠️ pendingCount agrège pending + inFlight + failed. C'est « ce qui est encore dû au serveur », et failed en fait partie : la tâche 3.10 l'a explicitement remis dans l'ensemble rejouable, précisément parce qu'une entrée en échec est une saisie de terrain qui n'a pas d'autre copie. quarantined est compté à part — le contrat le décrit comme « gardé, visible, mais non rejouable en l'état », donc ce n'est pas la même dette.

        Parameters

        • layerIds: readonly string[]

          Couches à compter. Une couche sans entité rend des zéros, jamais rien.

        Returns Promise<
            | Record<
                string,
                { featureCount: number; pendingCount: number; quarantinedCount: number },
            >
            | null,
        >

        Les décomptes par identifiant de couche, ou null si les modules sont absents.

        const counts = await GeoLeaf.Storage.DB.getSyncCounts(["sites_rosario"]);
        console.info(counts?.["sites_rosario"]?.featureCount);
    • listPendingEdits: function
      • Lists the edits still owed to the server, each joined to the entity it edits (4.10).

        C'est ce que le panneau « POI locaux » exporte : le TRAVAIL, pas le cache. Une entrée d'outbox ne porte pas la charge utile — elle référence [layerId, localId] —, donc la jointure vers features se fait ici, où les deux magasins sont ouverts.

        ⚠️ Une entrée dont l'entité a disparu du magasin est rendue avec feature: null plutôt qu'écartée. Une saisie qu'on ne sait plus décrire reste une saisie due au serveur ; la taire dans un export dont c'est précisément le rôle de tout sortir serait la perdre.

        Returns Promise<
            {
                entryId: string;
                kind: string;
                layerId: string;
                localId: string;
                state: string;
                createdAt: number;
                feature: unknown;
            }[],
        >

        Une entrée par édition en attente, la plus ancienne d'abord ; [] sans module.

        const pending = await GeoLeaf.Storage.DB.listPendingEdits();
        console.info(`${pending.length} saisie(s) jamais poussée(s)`);
    • purgeCachedFeatures: function
      • Removes the entities that are pure CACHE — synchronised, and re-pullable (4.10).

        🛑 CE QUI FAIT QUE LE NOM DU BOUTON DEVIENT VRAI. Depuis 4.1, le magasin features EST le cache : ses enregistrements synced se re-rapatrient par pullLayer(). L'outbox, elle, porte du travail de terrain qui n'existe nulle part ailleurs. Une purge qui annonce « vider le cache » ne doit donc toucher que le premier — vocabulaire de cache, données re-téléchargeables, et rien d'autre.

        ⚠️ La garde sur l'outbox est là bien que l'invariant de 4.4 la rende théoriquement inutile : applyEdit écrit l'entité en pending en même temps que l'entrée, donc un enregistrement synced ne devrait avoir aucune entrée en attente. « Ne devrait pas » ne garde rien — et l'enjeu ici est une destruction irréversible de saisie.

        Returns Promise<{ removed: number; preserved: number }>

        { removed, preserved }preserved compte les entités épargnées parce qu'une entrée d'outbox les réclame encore. Les deux sont affichables.

        const { removed, preserved } = await GeoLeaf.Storage.DB.purgeCachedFeatures();
        console.info(`${removed} supprimée(s), ${preserved} conservée(s)`);
    • removeLayer: function
    • getLayersByProfile: function
    • clearProfile: function
    • getStorageStats: function
      • Relaie le rapport de stockage de DB.Preferences.

        ⚠️ Ce relais déclarait MOINS que ce que le module rend, et il le déclarait faux. Sa forme était { used, quota, percentage, layersCount, syncQueueCount } : elle nommait un compteur du magasin v3 — retiré à la tâche 4.11 — et omettait featuresCount et outboxCount, que preferences.ts renseigne depuis B-121. Un appelant du chemin dégradé recevait donc un objet dont deux champs manquaient sans que le type le dise.

        Returns Promise<StorageStatsReport>

        Le quota, l'usage, et les décomptes des trois magasins qui portent de la donnée.

    • setPreference: function
    • getPreference: function
    • storeImageLocally: function
    • getPendingImages: function
    • updateImageUploadStatus: function
    • deleteLocalImage: function
    • cleanUploadedImages: function
    • close: function