@communecter/cocolight-api-client 1.0.195 → 1.0.197

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,121 @@
1
+ /**
2
+ * Types de l'**ampli** — l'espace de propositions d'un costum.
3
+ *
4
+ * Source de vérité : les actions legacy du module costum
5
+ * `controllers/actions/ampli/{CreateAmpliAction,RemoveAmpliAction}.php`, routées par
6
+ * `CostumizeController` sur `/costum/costumize/{createampli,removeampli}`.
7
+ *
8
+ * Un ampli n'est **pas une entité** : c'est une entrée de la carte `costum.ampli`, portée par
9
+ * l'élément hôte du costum (organisation, projet, citoyen ou événement) et indexée par son
10
+ * **slug**. D'où le placement des deux méthodes sur `BaseEntity` plutôt qu'une classe dédiée :
11
+ * elles s'appliquent à l'hôte, exactement comme `saveToolEnrichment`.
12
+ */
13
+ /** Collections pouvant porter un costum, donc un ampli (`parentType` des deux actions). */
14
+ export declare const AMPLI_PARENT_TYPES: readonly ["organizations", "projects", "citoyens", "events"];
15
+ export type AmpliParentType = (typeof AMPLI_PARENT_TYPES)[number];
16
+ /**
17
+ * Chemins des questions du formulaire de dépôt, forme `<idSousFormulaire>.<idQuestion>`
18
+ * (**sans** le préfixe `answers.`). Chaîne vide quand la question n'existe pas — `finder` l'est
19
+ * toujours pour un formulaire généré par le serveur.
20
+ */
21
+ export interface AmpliPaths {
22
+ name: string;
23
+ description: string;
24
+ address: string;
25
+ tags: string;
26
+ image: string;
27
+ finder: string;
28
+ }
29
+ /**
30
+ * Une entrée de `costum.ampli`, telle que relue via `element/about` — quelle que soit son époque.
31
+ *
32
+ * Deux formes coexistent en base :
33
+ * - les entrées écrites par `CreateAmpliAction` AVANT modules/costum@3ef97ef28 n'ont que
34
+ * `{ name, description, tags, pages, home }`, et leur clé vient de `strtolower` + espace → tiret
35
+ * (« Idées d'été » → `idées-d'été`) ;
36
+ * - les entrées écrites depuis portent en plus `slug`, `coform` et `path` ({@link CreatedAmpliEntry}).
37
+ *
38
+ * La CLÉ de la carte `costum.ampli` reste la seule référence fiable d'un ampli existant.
39
+ */
40
+ export interface AmpliEntry {
41
+ name: string;
42
+ /** Markdown, `""` si non fourni. */
43
+ description: string;
44
+ /** `null` sur une entrée ancienne créée avec des tags en tableau (`explode` d'un tableau). */
45
+ tags: string[] | null;
46
+ /** Pages Co de l'ampli (`#<page>`). Toujours vide pour une création depuis site-json. */
47
+ pages: string[];
48
+ /** Ancre de la page d'accueil Co. Toujours vide pour une création depuis site-json. */
49
+ home: string;
50
+ /** Clé de l'entrée dans `costum.ampli` — absente des entrées anciennes. */
51
+ slug?: string;
52
+ /** ObjectId du `Form` de dépôt — absent des entrées anciennes. */
53
+ coform?: string;
54
+ /** Chemins des questions du formulaire de dépôt — absents des entrées anciennes. */
55
+ path?: AmpliPaths;
56
+ }
57
+ /**
58
+ * L'entrée que {@link BaseEntity#createAmpli} vient d'écrire : la forme actuelle, complète.
59
+ */
60
+ export interface CreatedAmpliEntry extends AmpliEntry {
61
+ slug: string;
62
+ tags: string[];
63
+ coform: string;
64
+ path: AmpliPaths;
65
+ }
66
+ /** Champs communs aux deux modes de {@link BaseEntity#createAmpli}. */
67
+ interface CreateAmpliInputCommon {
68
+ /**
69
+ * Nom affiché. Le serveur en dérive la **clé** de l'entrée (`ampliSlug`) : « Idées d'été » donne
70
+ * `idees-d-ete`. Un nom qui ne produit aucun slug exploitable est refusé.
71
+ */
72
+ name: string;
73
+ /** Markdown, stocké tel quel. */
74
+ description?: string;
75
+ /** Vides et doublons sont retirés côté serveur. */
76
+ tags?: string[];
77
+ }
78
+ /**
79
+ * Mode A (défaut) — le **serveur crée le formulaire** : un `Form` et son sous-formulaire à cinq
80
+ * questions (titre, description, adresse, mots-clés, image), dont les chemins reviennent dans
81
+ * {@link CreatedAmpliEntry.path}. C'est le mode du parcours de création depuis site-json.
82
+ */
83
+ export type CreateAmpliInputGeneratedForm = CreateAmpliInputCommon;
84
+ /**
85
+ * Mode B — **rattachement à un formulaire existant** : `coform` désigne le `Form`, `namePath` et
86
+ * `addressPath` sont exigés par le serveur, les autres chemins sont facultatifs.
87
+ */
88
+ export interface CreateAmpliInputExistingForm extends CreateAmpliInputCommon {
89
+ /** ObjectId du `Form` à rattacher. Sa présence bascule l'appel en mode B. */
90
+ coform: string;
91
+ namePath: string;
92
+ addressPath: string;
93
+ descriptionPath?: string;
94
+ tagsPath?: string;
95
+ imagePath?: string;
96
+ finderPath?: string;
97
+ }
98
+ /** Entrée de {@link BaseEntity#createAmpli} — le mode se lit à la présence de `coform`. */
99
+ export type CreateAmpliInput = CreateAmpliInputGeneratedForm | CreateAmpliInputExistingForm;
100
+ /**
101
+ * Retour de {@link BaseEntity#createAmpli}.
102
+ *
103
+ * `data`, `app` et `blockCms` ne servent qu'à l'interface Co (boutons de menu, carte des pages,
104
+ * blocs CMS) et arrivent **vides** pour un appel site-json. Ils restent au contrat pour garder une
105
+ * seule forme de réponse ; un appelant site-json les ignore.
106
+ */
107
+ export interface CreateAmpliResult {
108
+ result: true;
109
+ /** Clé de l'entrée : permet de naviguer vers `/ampli/<slug>` sans attendre un rechargement. */
110
+ slug: string;
111
+ ampli: CreatedAmpliEntry;
112
+ data: unknown[];
113
+ app: unknown[];
114
+ blockCms: unknown[];
115
+ }
116
+ /** Retour de {@link BaseEntity#removeAmpli} — `msg` vaut `"Ampli removed"`. */
117
+ export interface RemoveAmpliResult {
118
+ result: true;
119
+ msg: string;
120
+ }
121
+ export {};
@@ -63,6 +63,28 @@ interface FieldDef {
63
63
  /** Valeur FORCÉE par le costum — cf. collectValuePresets. */
64
64
  value?: unknown;
65
65
  }
66
+ /** Clé de base d'une collection telle que la déclare un `typeObj` — cf. `findCostumBaseNode`. */
67
+ export interface CostumBaseNode {
68
+ /** Clé `typeObj` retenue (ex. `organizations`, `event`). */
69
+ typeKey: string;
70
+ /** Le nœud déclare-t-il des champs (`beforeBuild.properties`) ? Sinon : variante de base VIDE. */
71
+ hasForm: boolean;
72
+ add: boolean;
73
+ createLabel: string | null;
74
+ }
75
+ /**
76
+ * Trouve la CLÉ DE BASE d'une collection dans le `typeObj` d'un costum — le formulaire que le site
77
+ * applique quand on « ajoute une organisation » sans rien préciser, même quand ce nœud ne déclare AUCUN
78
+ * champ (ex. federationDesCae : `organizations: {add:true}` à côté du sous-type `organizationsTls`).
79
+ *
80
+ * Une base est une clé de `BASE_TYPEKEYS[collection]` dont le nœud est un objet SANS `sameAs`, ou avec un
81
+ * `sameAs` RÉFLEXIF (`event: {sameAs:"event"}` — parent62, institutBleu, navigator) : ce `sameAs` ne
82
+ * rattache le nœud à rien d'autre que lui-même. Deux clés sœurs (`organization` ET `organizations`) : on
83
+ * préfère celle qui porte un formulaire, sinon la première dans l'ordre du `typeObj` — en pratique
84
+ * `costum/co/resolved` n'en livre qu'une (le dernier déclaré gagne à la fusion moteur ⊕ overlay).
85
+ * Null si le costum ne déclare pas de clé de base pour cette collection.
86
+ */
87
+ export declare function findCostumBaseNode(data: CostumJsonData, collection: string): CostumBaseNode | null;
66
88
  /**
67
89
  * Digère `getcostumjson` → `CostumRuntimeContext` pour UNE collection (null si le costum ne couvre pas
68
90
  * cette collection). `meta` = identité de l'élément porteur (costumId/costumType, résolue par slug/getinfo).
@@ -86,6 +108,12 @@ export declare function listCostumFormNodes(data: CostumJsonData): Array<{
86
108
  createLabel: string | null;
87
109
  discriminator?: string;
88
110
  }>;
111
+ /**
112
+ * `opts.typeKey` : ne digère que cette clé `typeObj` (énumération par sous-type).
113
+ * `opts.allowFormless` (avec `typeKey`) : digère AUSSI ce nœud s'il ne déclare aucun champ — sert à la
114
+ * variante de BASE vide (cf. `findCostumBaseNode`) : schéma vide, `fields` vide, mais `presetValue` et
115
+ * `hide` PROPRES du nœud conservés. Sans cette option, un nœud sans formulaire est ignoré (inchangé).
116
+ */
89
117
  export declare function digestCostumJson(data: CostumJsonData, collection: Collection, meta: {
90
118
  costumId: string;
91
119
  costumType: string;
@@ -93,5 +121,6 @@ export declare function digestCostumJson(data: CostumJsonData, collection: Colle
93
121
  baseFieldNames?: string[];
94
122
  }, opts?: {
95
123
  typeKey?: string;
124
+ allowFormless?: boolean;
96
125
  }): DigestedCostum | null;
97
126
  export {};
@@ -1,5 +1,9 @@
1
1
  import type { CostumExtensionModule, CostumExtensionField, KnownCostumSlug, Collection } from "./types.js";
2
2
  import type { BaseEntity } from "../api/BaseEntity.js";
3
+ import type { Event } from "../api/Event.js";
4
+ import type { Organization } from "../api/Organization.js";
5
+ import type { Poi } from "../api/Poi.js";
6
+ import type { Project } from "../api/Project.js";
3
7
  /** Active/désactive FORCE-LIVE (cf. `COSTUM_FORCE_LIVE`). */
4
8
  export declare function setCostumForceLive(actif: boolean): void;
5
9
  /** État courant de FORCE-LIVE. */
@@ -83,6 +87,33 @@ export interface CostumFormDescriptor {
83
87
  /** Valeur de `type` estampillée au save qui distingue le sous-type (= presetValue.type, sinon typeKey). */
84
88
  discriminator?: string;
85
89
  }
90
+ /** Collections couvertes par les fabriques du scope (poi/organization/project/event). Identité entityType↔collection. */
91
+ type ScopeCollection = "poi" | "organizations" | "projects" | "events";
92
+ /** Entité rendue par chaque fabrique — même correspondance que `EntityTypeMap` (BaseEntity), qui n'est pas
93
+ * exporté : `create` étant public, son type de retour doit être nommable dans les `.d.ts`. */
94
+ type ScopeEntityMap = {
95
+ poi: Poi;
96
+ organizations: Organization;
97
+ projects: Project;
98
+ events: Event;
99
+ };
100
+ /**
101
+ * Options de création sous un costum (`CostumScope.create` et ses raccourcis). Jamais envoyées au serveur.
102
+ */
103
+ export interface CostumCreateOptions {
104
+ /**
105
+ * Sous-type CIBLÉ : clé `typeObj` du costum (ex. `"organizationsTls"` pour le formulaire « Créer votre
106
+ * CAE »). Ses presets et champs s'appliquent, quel que soit `data.type`. Sans lui, un sous-type ne
107
+ * s'applique que si `data.type` est son discriminant ; sinon c'est la clé de base de la collection.
108
+ * Inconnu du costum → repli silencieux sur cette règle (trace `debug`).
109
+ */
110
+ subType?: string;
111
+ }
112
+ /** Options de `CostumScope.contextFor` : celles de la création, plus le mode de sélection. */
113
+ export interface CostumContextOptions extends CostumCreateOptions {
114
+ /** Sélectionner comme une CRÉATION (défaut = clé de base) plutôt que comme une lecture (défaut historique). */
115
+ create?: boolean;
116
+ }
86
117
  /**
87
118
  * Scope costum : fabrique des entités liées à un costum. Réutilise le `user` (parent, deps, auth)
88
119
  * et n'altère jamais l'état partagé — chaque entité reçoit son propre `_costumCtx`.
@@ -98,14 +129,38 @@ export declare class CostumScope {
98
129
  * Construit le `CostumRuntimeContext` pour une collection (null si non couverte). `type` (optionnel) = le
99
130
  * sous-type voulu (= `presetValue.type` de la variante) : sélectionne l'overlay de CE sous-type, sinon la
100
131
  * racine=union. Indispensable au CREATE d'un sous-type précis (bon `type`/presets/champs — cf. P0 write-safety).
132
+ *
133
+ * `opts` (optionnel) : `subType` cible un sous-type par sa clé `typeObj` (prime sur `type`) ; `create`
134
+ * sélectionne comme une création (défaut = clé de base du costum). Sans `opts` : sélection de LECTURE,
135
+ * inchangée (revive/édition).
136
+ */
137
+ contextFor(collection: Collection, type?: string | null, opts?: CostumContextOptions): CostumRuntimeContext | null;
138
+ /**
139
+ * Crée une entité de `collection` sous ce costum (presets appliqués, surchargeables par `data`).
140
+ *
141
+ * Formulaire costum appliqué (presets + champs) — dans l'ordre :
142
+ * 1. `opts.subType` : le sous-type CIBLÉ par sa clé `typeObj` (ex. `"organizationsTls"`) ;
143
+ * 2. `data.type` : le sous-type dont c'est le discriminant (ex. `poi({ type: "article" })`) ;
144
+ * 3. sinon la CLÉ DE BASE de la collection si le costum en déclare une (ex. `organizations`), MÊME SANS
145
+ * champ : un sous-type n'est jamais appliqué par défaut ; sans clé de base, comportement historique.
146
+ * Un `subType` inconnu retombe sur 2→3 (trace `debug`, aucune exception). `opts` n'est JAMAIS envoyé au
147
+ * serveur. La whitelist d'écriture reste l'union racine ∪ variante (byte-safe).
148
+ *
149
+ * const cae = await tl.organization({ name }, { subType: "organizationsTls" }); // formulaire « CAE »
150
+ * const org = await tl.organization({ name }); // formulaire de base
151
+ */
152
+ create<T extends ScopeCollection>(collection: T, data?: Record<string, unknown>, opts?: CostumCreateOptions): Promise<ScopeEntityMap[T]>;
153
+ /**
154
+ * Trace (`debug`) un `subType` que ce scope ne sait pas cibler pour `collection` : collection non couverte,
155
+ * ou variantes dont aucune ne porte cette clé `typeObj`. Une collection à formulaire UNIQUE n'a pas de
156
+ * variantes à comparer : rien n'est tracé (la racine EST ce formulaire). Le repli lui-même est fait par
157
+ * `pickCostumOverlay` ; ceci ne fait que le rendre visible.
101
158
  */
102
- contextFor(collection: Collection, type?: string | null): CostumRuntimeContext | null;
103
- /** Crée une entité de `collection` sous ce costum (presets appliqués, surchargeables par `data`). */
104
- private create;
105
- poi(data?: Record<string, unknown>): Promise<import("../index.js").Poi>;
106
- organization(data?: Record<string, unknown>): Promise<import("../index.js").Organization>;
107
- project(data?: Record<string, unknown>): Promise<import("../index.js").Project>;
108
- event(data?: Record<string, unknown>): Promise<import("../index.js").Event>;
159
+ private traceUnknownSubType;
160
+ poi(data?: Record<string, unknown>, opts?: CostumCreateOptions): Promise<Poi>;
161
+ organization(data?: Record<string, unknown>, opts?: CostumCreateOptions): Promise<Organization>;
162
+ project(data?: Record<string, unknown>, opts?: CostumCreateOptions): Promise<Project>;
163
+ event(data?: Record<string, unknown>, opts?: CostumCreateOptions): Promise<Event>;
109
164
  /**
110
165
  * Poste une news sous CE costum, sur le mur de `target` : `source.key` = costum du scope (le SITE,
111
166
  * comme poi/org — cf. `News::prepData`), `parent` = `target`. News n'est PAS une collection « élément »
@@ -159,3 +214,4 @@ export declare function resolveCostumScope(user: BaseEntity, slug: KnownCostumSl
159
214
  * No-op si le costum ne résout pas / ne couvre pas la collection (l'entité reste en scope d'identité).
160
215
  */
161
216
  export declare function loadCostumContext(user: BaseEntity, slug: string, collection: Collection): Promise<CostumRuntimeContext | null>;
217
+ export {};
@@ -0,0 +1,22 @@
1
+ /**
2
+ * UN COSTUM PEUT ÉLARGIR UN CHAMP NATIF, JAMAIS LE RESTREINDRE.
3
+ *
4
+ * Un costum legacy redéclare des champs que le contrat connaît déjà (`type`, `tags`, `openingHours`,
5
+ * `telephone`…). Son schéma ne vient pas du stockage mais du WIDGET déclaré (digest live, `inferType`)
6
+ * ou d'un préremplissage (`presetProps`, typé chaîne). Il sert à ÉLARGIR un champ contraint — les
7
+ * types d'événement d'institutBleu sont tous hors de l'énumération native, et la production en vit.
8
+ * Mais posé À LA PLACE du schéma natif, il refusait aussi la forme native. Mesuré le 2026-10-01 sur les
9
+ * 21 costums résolus des sites de site-json : 111 champs natifs redéclarés, dont 8 RESTREINTS — horaires
10
+ * en liste refusés (CAE, navigator, relief : création impossible dès qu'on les saisit), téléphone en
11
+ * objet legacy refusé, mots-clés préremplis refusés en liste — pour 27 élargissements légitimes.
12
+ *
13
+ * Règle : pour un champ défini des deux côtés, la requête accepte le natif OU le costum (`anyOf`).
14
+ * Elle est monotone — tout ce qui passait passe encore — et une valeur que les deux refusent reste
15
+ * refusée. Appliquée aux DEUX points de fusion : la création (`ApiClient.callEndpoint`, enveloppe
16
+ * costum) et la modification (`BaseEntity._saveCostumViaElementSave`), qui faisaient l'inverse l'une
17
+ * de l'autre (le costum primait à la création, le natif à la modification).
18
+ */
19
+ /** Schéma d'un champ défini par le contrat (`natif`) ET par le costum : natif OU costum. */
20
+ export declare function widenSchema(natif: unknown, costum: unknown): unknown;
21
+ /** `widenSchema` clé par clé : chaque propriété du costum élargit celle du natif, les autres restent. */
22
+ export declare function widenProperties(natives: Record<string, unknown>, costum: Record<string, unknown>): Record<string, unknown>;