@communecter/cocolight-api-client 1.0.135 → 1.0.136

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.
package/types/Api.d.ts CHANGED
@@ -79,6 +79,24 @@ export default class Api {
79
79
  * Retourne l'instance d'EndpointApi.
80
80
  */
81
81
  get endpointApi(): EndpointApi;
82
+ /**
83
+ * Recherche des tags correspondant à un mot-clé.
84
+ *
85
+ * Wrap de `SEARCH_TAGS` (auth=none) — accessible même non connecté.
86
+ * Méthode exposée sur la facade `Api` (pas d'entité hôte naturelle pour
87
+ * un index global de tags).
88
+ *
89
+ * @param q - Mot-clé de recherche (au moins 1 caractère).
90
+ * @returns Tableau de résultats : soit `[{tag}]` si aucun match (echo du
91
+ * terme), soit `[{_id, tag, field_length}, ...]` avec les tags
92
+ * existants triés par `field_length`.
93
+ * @throws {ApiError} 400 si `q` vide.
94
+ *
95
+ * @example
96
+ * const results = await api.searchTags("permac");
97
+ * results.forEach(t => console.log(t.tag, t.field_length));
98
+ */
99
+ searchTags(q: string): Promise<unknown>;
82
100
  /**
83
101
  * Déconnecte l'utilisateur et réinitialise la session.
84
102
  */
@@ -282,7 +282,9 @@ export declare class Action extends BaseEntity<ActionItemNormalized> {
282
282
  */
283
283
  archive(): Promise<unknown>;
284
284
  /**
285
- * Helper privé : envoie un UPDATE_PATH_VALUE pour un path donné.
285
+ * Helper privé : délègue à `BaseEntity.updateField()` pour un path donné.
286
+ * Bénéficie du normalize automatique (R0 Date → isoDate, R1 collapse setType,
287
+ * R2 pull + empty → "", R6 drop setType vide).
286
288
  */
287
289
  private _updatePath;
288
290
  /**
@@ -136,17 +136,6 @@ export declare class Answer extends BaseEntity<AnswerItemNormalized> {
136
136
  * Les autres sont calculés/posés par le backend.
137
137
  */
138
138
  removeFields: string[];
139
- /**
140
- * {@inheritDoc BaseEntity#isAuthor}
141
- *
142
- * Override Answer : le champ d'autorité est `serverData.user` (pas `creator`
143
- * comme la version par défaut de BaseEntity). Le `user` peut être :
144
- * - un `string` (ID MongoDB brut renvoyé par le backend)
145
- * - une instance `User` (après `_transformServerData` qui le link en entité)
146
- *
147
- * Les pré-conditions (connexion, id, serverData) sont vérifiées comme dans
148
- * la version de base — `silent: true` (défaut) renvoie `false` au lieu de throw.
149
- */
150
139
  /**
151
140
  * {@inheritDoc BaseEntity#_isAdminViaHierarchy}
152
141
  *
@@ -161,6 +150,17 @@ export declare class Answer extends BaseEntity<AnswerItemNormalized> {
161
150
  * @protected
162
151
  */
163
152
  protected _isAdminViaHierarchy(): boolean;
153
+ /**
154
+ * {@inheritDoc BaseEntity#isAuthor}
155
+ *
156
+ * Override Answer : le champ d'autorité est `serverData.user` (pas `creator`
157
+ * comme la version par défaut de BaseEntity). Le `user` peut être :
158
+ * - un `string` (ID MongoDB brut renvoyé par le backend)
159
+ * - une instance `User` (après `_transformServerData` qui le link en entité)
160
+ *
161
+ * Les pré-conditions (connexion, id, serverData) sont vérifiées comme dans
162
+ * la version de base — `silent: true` (défaut) renvoie `false` au lieu de throw.
163
+ */
164
164
  isAuthor(options?: {
165
165
  silent?: boolean;
166
166
  }): boolean;
@@ -1,4 +1,4 @@
1
- import type { UpdateSettingsData, UpdateBlockDescriptionData, UpdateBlockInfoData, UpdateBlockSocialData, UpdateBlockLocalityData, GetNewsData, GetGalleryData, GlobalAutocompleteCostumData, CostumEventRequestActorsData, CostumEventRequestSubeventsData, CostumEventRequestDatesData, CostumEventRequestElementEventData, CostumEventRequestCategoriesData, CostumEventRequestEventData, CostumEventRequestLinkTlToEventData, CostumEventRequestLoadContextTagData, GetOrganizationsAdminData, GetOrganizationsNoAdminData, GetProjectsAdminData, GetProjectsNoAdminData, GetPoisAdminData, GetPoisNoAdminData, GetSubscribersData, GetBadgesData, CoformAnswersSearchData, SearchMemberAutocompleteData, GetEventsData, CostumFilterCoformData, GetCountriesData, SearchZonesData, CoformAnswersByFormsData, FundingEnvelopeData, CoremuOperationData } from "./EndpointApi.types.js";
1
+ import type { UpdateSettingsData, UpdateBlockDescriptionData, UpdateBlockInfoData, UpdateBlockSocialData, UpdateBlockLocalityData, GetNewsData, GetGalleryData, GlobalAutocompleteCostumData, CostumEventRequestActorsData, CostumEventRequestSubeventsData, CostumEventRequestDatesData, CostumEventRequestElementEventData, CostumEventRequestCategoriesData, CostumEventRequestEventData, CostumEventRequestLinkTlToEventData, CostumEventRequestLoadContextTagData, GetOrganizationsAdminData, GetOrganizationsNoAdminData, GetProjectsAdminData, GetProjectsNoAdminData, GetPoisAdminData, GetPoisNoAdminData, GetSubscribersData, GetBadgesData, CoformAnswersSearchData, SearchMemberAutocompleteData, GetEventsData, CostumFilterCoformData, GetCountriesData, SearchZonesData, CoformAnswersByFormsData, FundingEnvelopeData, CoremuOperationData, UpdatePathValueData } from "./EndpointApi.types.js";
2
2
  import type { TransformsMap } from "../types/entities.js";
3
3
  import type { CountryItem } from "./serverDataType/Country.js";
4
4
  import type { ZoneItemNormalized } from "./serverDataType/Zone.js";
@@ -72,6 +72,43 @@ type ParentLike = BaseEntity<any> & {
72
72
  * - `navigator-tl` → `/costum/navigator/gettl`
73
73
  */
74
74
  export type SearchCostumVariant = "default" | "navigator-tl";
75
+ /**
76
+ * Types de coercion backend supportés par `UPDATE_PATH_VALUE.setType`.
77
+ *
78
+ * Référence côté backend : `string_set_type` (PHP) accepte ces 5 valeurs +
79
+ * tout autre string (passthrough — pas de coercion). Le `& Record<never, never>`
80
+ * garde l'autocomplete des literals tout en acceptant des strings custom.
81
+ *
82
+ * - `"int"` → `intval()` (PHP)
83
+ * - `"float"` → `floatval()`
84
+ * - `"boolean"` / `"bool"` → `FILTER_VALIDATE_BOOLEAN` (alias)
85
+ * - `"isoDate"` → parse multi-format → `MongoDate`
86
+ * Formats acceptés : ISO 8601 natif, `m-d-Y`, `d-m-Y`, `{sec, usec}` legacy,
87
+ * string `"now"` (date actuelle), slashes auto-convertis en tirets.
88
+ * - `"timestamp"` → parse → Unix seconds (`int`)
89
+ */
90
+ export type SetTypeValue = "int" | "float" | "boolean" | "bool" | "isoDate" | "timestamp" | (string & Record<never, never>);
91
+ /**
92
+ * Magic values reconnues par `UPDATE_PATH_VALUE` côté backend.
93
+ * Utilisable comme `value` ou `path` selon le cas.
94
+ */
95
+ export declare const UPDATE_PATH_MAGIC: {
96
+ /**
97
+ * `value: "updatedTime"` → backend remplace par `time()` Unix seconds courant
98
+ * (utile pour `lastEditedAt`, audit trail, etc. sans avoir à fournir un timestamp côté client).
99
+ */
100
+ readonly CURRENT_TIME: "updatedTime";
101
+ /**
102
+ * `value: "now"` avec `setType: "isoDate"` → résolu côté backend en `MongoDate(now)`.
103
+ */
104
+ readonly NOW: "now";
105
+ /**
106
+ * `path: "allToRoot"` → la `value` (qui doit être un objet) est exposée à la
107
+ * racine de l'entité : chaque clé devient un champ racine. Combiner avec
108
+ * `updatePartial: true` pour un merge avec préservation des autres champs.
109
+ */
110
+ readonly PATH_ALL_TO_ROOT: "allToRoot";
111
+ };
75
112
  type EndpointApiCtor = {
76
113
  new (apiClient: ApiClient): EndpointApi;
77
114
  };
@@ -588,6 +625,91 @@ export declare class BaseEntity<TServerData = any> {
588
625
  * await news.deleteFile(imageDocId);
589
626
  */
590
627
  deleteFile(docId: string): Promise<void>;
628
+ /**
629
+ * Met à jour un champ unique (ou multi-fields via `updatePartial`) sur cette
630
+ * entité via `UPDATE_PATH_VALUE`.
631
+ *
632
+ * **Cas d'usage couverts** :
633
+ * - `$set` simple : `entity.updateField("name", "Nouveau nom")`
634
+ * - `$unset` : `entity.updateField("description", null)`
635
+ * - `$push` array : `entity.updateField("tags", "x", { arrayForm: true })`
636
+ * - `$pull` array : `entity.updateField("tags.3", null, { pull: "tags" })`
637
+ * - `$pullAll` array : `entity.updateField("tags", ["a","b"], { arrayForm: true, pull: "tags" })`
638
+ * - Coercion type : `entity.updateField("credits", 100, { setType: "int" })`
639
+ * - Date auto : `entity.updateField("startDate", new Date())` → setType "isoDate" + ISO string
640
+ * - Multi-field merge : `entity.updateField("address", {...}, { updatePartial: true })`
641
+ * - Auth sub-form : `entity.updateField("...", value, { formParentId: "..." })`
642
+ *
643
+ * **Magic values** :
644
+ * - `value: "updatedTime"` → backend remplace par `time()` Unix seconds
645
+ * - `value: "now"` + `setType: "isoDate"` → résout en date actuelle
646
+ * - `path: "allToRoot"` → value exposée à la racine de l'entité
647
+ *
648
+ * Le payload est normalisé via `_normalizeUpdatePathPayload` avant envoi
649
+ * (cf. les 4 règles documentées sur cette méthode).
650
+ *
651
+ * @param path - Chemin MongoDB dot-notation (ex: `"address.street"`, `"answers.aapStep1.depense.3"`).
652
+ * @param value - Valeur à poser. Accepte `Date` (auto-convertie en ISO + setType isoDate).
653
+ * @param opts - Options : `setType`, `arrayForm`, `pull`, `updatePartial`, `formParentId`, `edit`.
654
+ * @returns Réponse brute de l'API.
655
+ * @throws {ApiError} 404 si l'entité n'a pas d'id.
656
+ * @throws {ApiError} 400 si `value === undefined`, `path` vide, ou conflit `arrayForm` + `pull` sans value array, ou `updatePartial` sans value object.
657
+ *
658
+ * @example
659
+ * // Update simple
660
+ * await org.updateField("name", "Nouvelle organisation");
661
+ *
662
+ * @example
663
+ * // Date instance auto-convertie
664
+ * await action.updateField("startDate", new Date());
665
+ *
666
+ * @example
667
+ * // Multi-field merge (préserve les autres clés de address)
668
+ * await org.updateField("address", {
669
+ * street: "123 rue X",
670
+ * city: "Paris",
671
+ * }, { updatePartial: true });
672
+ *
673
+ * @example
674
+ * // Push dans array
675
+ * await project.updateField("tags", "permaculture", { arrayForm: true });
676
+ *
677
+ * @example
678
+ * // Pull from array (avec normalisation R2 : null → "")
679
+ * await project.updateField("oceco.milestones.3", null, { pull: "oceco.milestones" });
680
+ */
681
+ updateField(path: string, value: unknown, opts?: {
682
+ setType?: SetTypeValue | Array<{
683
+ path: string;
684
+ type: SetTypeValue;
685
+ }>;
686
+ arrayForm?: boolean;
687
+ pull?: string;
688
+ updatePartial?: boolean;
689
+ formParentId?: string;
690
+ edit?: boolean;
691
+ }): Promise<unknown>;
692
+ /**
693
+ * Normalise le payload `updatePathValue` avant envoi au backend.
694
+ *
695
+ * Règles appliquées (4) :
696
+ * - **R0** : `value instanceof Date` → `value.toISOString()` + `setType: "isoDate"`
697
+ * (override d'un setType existant — l'intent `Date` est prioritaire).
698
+ * - **R1** : `setType: [{type:"isoDate"}, ...]` uniforme + `value: string` →
699
+ * collapse en `setType: "isoDate"` (forme scalaire préférée backend).
700
+ * - **R2** : `pull` présent + `value: ""|null|undefined` → force `value: ""`
701
+ * (le backend exige `value: string` quand `pull` est présent — contrainte
702
+ * schema `allOf`).
703
+ * - **R6** : `setType: []` array vide → drop silencieusement (évite wire
704
+ * format inutile, sécurise contre filtres qui ont tout retiré).
705
+ *
706
+ * Pour traiter une string ISO comme date, le caller doit passer `setType`
707
+ * explicitement (`"isoDate"` ou `[{path, type:"isoDate"}]`). Pas d'heuristique
708
+ * sur les strings pour éviter les faux positifs sur champs texte libre.
709
+ *
710
+ * @protected
711
+ */
712
+ protected _normalizeUpdatePathPayload(payload: UpdatePathValueData): UpdatePathValueData;
591
713
  /**
592
714
  * Valide les entrées d'upload de fichiers.
593
715
  *
@@ -1946,14 +2068,25 @@ export declare class BaseEntity<TServerData = any> {
1946
2068
  */
1947
2069
  getCountries(data?: Partial<GetCountriesData>): Promise<CountryItem[]>;
1948
2070
  /**
1949
- * Generer un nouveau identifiant unique pour un answers basé sur un formulaire donnée
2071
+ * Génère côté backend une nouvelle Answer placeholder rattachée au formulaire
2072
+ * donné (insert en BDD avec nouvel ObjectId) et retourne l'instance Answer
2073
+ * connectée (parent = `this`).
1950
2074
  *
1951
- * @param formId - Identifiant du formulaire pour lequel générer un nouvel ID d'answers
1952
- * @returns Un nouvel answers avec le nouveau ID généré
1953
- * @throws {ApiError} Si formId est absent ou invalide
2075
+ * **Note workflow** : l'Answer renvoyée est en état "placeholder" pas de
2076
+ * `user` posé côté backend tant que `save()` n'a pas été appelé. Pour
2077
+ * récupérer plus tard via `coformAnswersById`, faire `save()` avec au moins
2078
+ * `answers` posés.
1954
2079
  *
2080
+ * @param formId - ID du formulaire (24 hex)
2081
+ * @returns Instance `Answer` connectée à `this` (parent = entité courante)
2082
+ * @throws {ApiError} 400 si `formId` est absent ou invalide
2083
+ *
2084
+ * @example
2085
+ * const org = await api.organization({ slug: "monOrga" });
2086
+ * const answer = await org.generateNewAnswerId(formId);
2087
+ * await answer.updateField(`${finder}.${org.id}`, { id: org.id, type: "organizations", name: org.serverData.name });
1955
2088
  */
1956
- generateNewAnswerId(formId: string): Promise<any>;
2089
+ generateNewAnswerId(formId: string): Promise<Answer>;
1957
2090
  /**
1958
2091
  * Associe un compte Discourse à l'utilisateur courant dans le contexte de l'instance.
1959
2092
  * Injecte automatiquement le `costumSlug` via `_withCostumContext`.
@@ -41,6 +41,22 @@ export declare class Comment extends BaseEntity<CommentItemNormalized> {
41
41
  * @throws {ApiError} Si la news n'a pas d'ID (non enregistrée)
42
42
  */
43
43
  addVote(status: string): Promise<unknown>;
44
+ /**
45
+ * Récupère la liste des votes (like, love, etc.) sur ce commentaire.
46
+ *
47
+ * Wrap de `SHOW_VOTE` avec auto-injection du `type` (`"comments"`) et de
48
+ * `this.id` dans `pathParams`. Le retour contient `vote` (votes individuels
49
+ * indexés par userId) et `voteCount` (compteurs par statut).
50
+ *
51
+ * @returns Réponse API : `{ _id, vote, voteCount }` ou variante d'erreur.
52
+ * @throws {ApiError} 404 si le commentaire n'a pas d'id (non enregistré).
53
+ *
54
+ * @example
55
+ * const votes = await comment.getVotes();
56
+ * votes.voteCount?.like; // nombre de likes
57
+ * votes.vote?.[userId]; // vote détaillé d'un user
58
+ */
59
+ getVotes(): Promise<unknown>;
44
60
  /**
45
61
  * Signale un abus sur ce commentaire
46
62
  *
@@ -5150,6 +5150,18 @@ export interface UpdatePathValueData {
5150
5150
  value: string | number | boolean | {
5151
5151
  [k: string]: unknown;
5152
5152
  } | unknown[] | null;
5153
+ /**
5154
+ * Mode multi-field merge : `value` doit être un objet, chaque clé devient un sub-path et est mise à jour individuellement (vs `$set` qui écrase l'objet entier). Les sous-clés à `null`/`""` sont supprimées (`$unset`). Combinable avec `setType: Array` pour coercion par sous-clé.
5155
+ */
5156
+ updatePartial?: boolean;
5157
+ /**
5158
+ * ID du Form parent. Utilisé côté backend pour : (1) authorisation hiérarchique sur sub-forms (admin du Form parent autorisé à modifier les sub-inputs), (2) invalidation du cache de traduction du Form parent après modification.
5159
+ */
5160
+ formParentId?: string;
5161
+ /**
5162
+ * Avec `arrayForm`, désactive le mode `$push` et force `$set` (écrase l'array entier). Cas legacy — préférer omettre `arrayForm` pour écraser un array.
5163
+ */
5164
+ edit?: boolean;
5153
5165
  [k: string]: unknown;
5154
5166
  }
5155
5167
  export interface DeleteDocumentByContextData {
@@ -82,6 +82,22 @@ export declare class News extends BaseEntity<NewsItemNormalized> {
82
82
  * @throws {ApiError} Si la news n'a pas d'ID (non enregistrée)
83
83
  */
84
84
  addVote(status: string): Promise<unknown>;
85
+ /**
86
+ * Récupère la liste des votes (like, love, etc.) sur cette news.
87
+ *
88
+ * Wrap de `SHOW_VOTE` avec auto-injection du `type` (`"news"`) et de
89
+ * `this.id` dans `pathParams`. Le retour contient `vote` (votes individuels
90
+ * indexés par userId) et `voteCount` (compteurs par statut).
91
+ *
92
+ * @returns Réponse API : `{ _id, vote, voteCount }` ou variante d'erreur.
93
+ * @throws {ApiError} 404 si la news n'a pas d'id (non enregistrée).
94
+ *
95
+ * @example
96
+ * const votes = await news.getVotes();
97
+ * votes.voteCount?.like; // nombre de likes
98
+ * votes.vote?.[userId]; // vote détaillé d'un user
99
+ */
100
+ getVotes(): Promise<unknown>;
85
101
  /**
86
102
  * Signale un abus sur cette news
87
103
  *