import type { CostumExtensionModule, CostumExtensionField, KnownCostumSlug, Collection } from "./types.js"; import type { BaseEntity } from "../api/BaseEntity.js"; /** * Invalide le cache costum live — d'UN slug (ex. après avoir modifié ce costum en base), ou de TOUT * (`invalidateCostumCache()`). Le prochain accès refetchera `getcostumjson` (C2e). Sans effet sur le bundle. */ export declare function invalidateCostumCache(slug?: string): void; /** * Énumère TOUS les formulaires costum d'un slug (UN descripteur PAR SOUS-TYPE = clé `typeObj`) via * getcostumjson — pour l'assistant config (génération multi-form + routage `editModalMatch`). Distinct de * `CostumScope.describeForm(collection)` qui n'en renvoie qu'UN par collection. Seuls les sous-types dont la * collection de base est gérée par les fabriques (poi/organizations/projects/events) sont retournés. */ export declare function describeCostumForms(user: BaseEntity, slug: string): Promise; /** * Pré-charge EN BATCH les costums (par slug) manquants/périmés du cache live, AVANT un revive synchrone * (finalizer de `searchCostum`, `get()`, `entitySlug`). Dédup + TTL : un slug déjà frais est ignoré. * Chaque fetch qui échoue est avalé (offline → le revive retombera sur le bundle). Concurrence bornée. */ export declare function prefetchCostums(user: BaseEntity, sourceKeys: (string | null | undefined)[]): Promise; /** * Contexte costum résolu, attaché à une instance d'entité via `config.costumCtx`. * Porté tel quel par `BaseEntity._costumCtx` et consommé par les 3 couches de filtrage. */ export interface CostumRuntimeContext { /** slug du costum (= clé envoyée en `costumSlug`, source du `source.key` côté backend). */ slug: string; /** id de l'élément porteur du costum (collection `costumType`). */ costumId: string; /** collection de l'élément porteur (organizations/projects/events…) → `costumType`. */ costumType: string; /** collection de l'entité CRÉÉE sous ce scope (poi/organizations/…) — clé d'index du module. */ collection: Collection; /** schéma AJV permissif {type:object, additionalProperties:true, properties:{…}} des champs costum. */ schema: { type: "object"; additionalProperties: true; properties: Record; }; /** champs costum (path/setType/arrayForm) — dispatch updateField à l'édition. */ fields: CostumExtensionField[]; /** valeurs par défaut costum (presetValue) — appliquées en data, surchargeables par l'appelant. */ presets: Record; /** champs masqués (onload hide) — non éditables. */ hidden: string[]; } /** Type logique d'un champ costum, pour la génération de formulaire côté consommateur. */ export type CostumFieldType = "string" | "number" | "boolean" | "date" | "array" | "object"; /** Champ costum décrit pour un formulaire (dérivé du schéma lazy enrichi : type/enum/multiple). */ export interface CostumFieldDescriptor { name: string; path: string; type: CostumFieldType; multiple: boolean; /** Options de choix (select/multiselect). Absent si champ libre. */ enum?: (string | number)[]; /** Champ masqué (onload hide) — à exclure du formulaire. */ hidden: boolean; } /** * Description NEUTRE d'un formulaire costum pour une collection — projection runtime des métadonnées * (champs + type/enum/multiple, presets, hidden, add, createLabel). Le consommateur (ex. site-json) * en dérive son propre format de form. AUCUN libellé humain n'existe dans la source (label = nom). */ export interface CostumFormDescriptor { slug: string; collection: Collection; costumId: string; costumType: string; add: boolean; createLabel: string | null; presets: Record; /** Noms de champs MASQUÉS (legacy `dynForm hide`) — base ET costum (ex. type/tags/role pour tiers-lieu). * Le consommateur les exclut du formulaire (les champs costum portent aussi `hidden` par champ). */ hidden: string[]; fields: CostumFieldDescriptor[]; /** Clé `typeObj` (sous-type) d'où vient ce form — présent quand issu de `describeCostumForms` (énumération). */ typeKey?: string; /** Valeur de `type` estampillée au save qui distingue le sous-type (= presetValue.type, sinon typeKey). */ discriminator?: string; } /** * Scope costum : fabrique des entités liées à un costum. Réutilise le `user` (parent, deps, auth) * et n'altère jamais l'état partagé — chaque entité reçoit son propre `_costumCtx`. */ export declare class CostumScope { readonly slug: KnownCostumSlug | (string & {}); private readonly user; private readonly module; private readonly costumId; private readonly costumType; constructor(user: BaseEntity, slug: KnownCostumSlug | (string & {}), module: CostumExtensionModule, costumId: string, costumType: string); /** * Construit le `CostumRuntimeContext` pour une collection (null si non couverte). `type` (optionnel) = le * sous-type voulu (= `presetValue.type` de la variante) : sélectionne l'overlay de CE sous-type, sinon la * racine=union. Indispensable au CREATE d'un sous-type précis (bon `type`/presets/champs — cf. P0 write-safety). */ contextFor(collection: Collection, type?: string | null): CostumRuntimeContext | null; /** Crée une entité de `collection` sous ce costum (presets appliqués, surchargeables par `data`). */ private create; poi(data?: Record): Promise; organization(data?: Record): Promise; project(data?: Record): Promise; event(data?: Record): Promise; /** * Poste une news sous CE costum, sur le mur de `target` : `source.key` = costum du scope (le SITE, * comme poi/org — cf. `News::prepData`), `parent` = `target`. News n'est PAS une collection « élément » * (pas d'`element/save` ni de champs costum) : on la crée via `target.entity("news", …, {costumCtx})`. * Le `costumCtx` EXPLICITE court-circuite l'héritage parent d'`entity()` → la source vient du SITE, * jamais du mur. `News._add` lit ce `_costumCtx` et estampille `source` (pendant des uploads costum). */ news(target: BaseEntity, data?: Record): Promise; /** * Décrit le FORMULAIRE costum d'une collection (null si non couverte) — projection NEUTRE des * métadonnées runtime (champs typés + enum/multiple, presets, hidden, add, createLabel). Le module * étant déjà chargé (scope obtenu via `me.costum(slug)`), c'est SYNCHRONE. Le consommateur (site-json) * en dérive son format de form. NB : pas de libellé humain dans la source → label = nom du champ. */ describeForm(collection: Collection): CostumFormDescriptor | null; } /** * Dérive un `CostumRuntimeContext` SYNCHRONE depuis le `source.key` d'un élément CHARGÉ + sa collection. * Permet aux entités revifiées (`fromServerData` des résultats `searchCostum`, `me.poi({id})`) de retrouver * leurs champs costum (writable + dispatch) sans `me.costum(slug)`. * * **LIVE-FIRST** (RFC fil C / cadrage C2) : le cache live FRAIS prime (un costum modifié en base est reflété * sans republier), sinon la map bundlée `COSTUM_RUNTIME` (warm-start / offline), sinon ctx nu / null. Le * cache est peuplé par `prefetchCostums` (async, AVANT le revive) ou `me.costum`/`loadCostumScope`. */ export declare function resolveCostumCtxFromSource(sourceKey: string | undefined | null, collection: Collection, type?: string | null): CostumRuntimeContext | null; /** * Ouvre un scope costum depuis une entité DÉJÀ CHARGÉE (org/projet/event porteur d'un costum) : `costumSlug` * = slug de l'entité (= `source.key` posé par le backend), `costumId/costumType` = l'entité porteuse. C'est * la voie AMBIANTE (« costum du déploiement ») de `me.costum(entity)`. * * Le scope porte les DÉFINITIONS du costum (champs + presets de sous-type, ex. `type:"article"`), PAS * seulement l'identité : sinon un CREATE de sous-type sous l'ambiant perd le `type` forcé → rejet enum ADD_*. * Résolution (dégradée, jamais throw) : 1) cache live frais (zéro fetch — le costum est déjà chargé au rendu * du site) ; 2) digest live `getcostumjson` (comble presets/champs + peuple le cache) ; 3) fieldless * (identité seule — site nu sans costum, ou offline = comportement historique). Le backend re-gate `found` * sur l'existence d'un costum → un site sans costum n'estampille rien. */ export declare function costumScopeFromEntity(user: BaseEntity, entity: BaseEntity): Promise; /** * Résout un `CostumScope` par SLUG pour un user connecté. * - slug à champs (meta + loader) → charge le module généré (code-split via dynamic import). * - slug CONNU sans loader (fieldless) → scope d'identité nu (`collections:{}`). * - slug HORS registry → résolution LIVE via `slug/getinfo` (contextId/contextType) → scope nu (tier 3b). */ export declare function resolveCostumScope(user: BaseEntity, slug: KnownCostumSlug | (string & {})): Promise; /** * Charge EN LIVE le scope costum d'un slug hors registre (getcostumjson) et pose le `CostumRuntimeContext` * de la collection donnée sur l'entité — pour ÉDITER un élément d'un costum non bundlé avec ses champs * (comble l'édition vide L4). Idempotent : ne refetch pas si le cache live couvre déjà (slug, collection). * No-op si le costum ne résout pas / ne couvre pas la collection (l'entité reste en scope d'identité). */ export declare function loadCostumContext(user: BaseEntity, slug: string, collection: Collection): Promise;