@communecter/cocolight-api-client 1.0.134 → 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,6 +136,34 @@ 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#_isAdminViaHierarchy}
141
+ *
142
+ * Override Answer : la hiérarchie d'Answer passe par son **parent instance
143
+ * Form** (pas par `serverData.parent` direct comme pour `events`/`projects`/`poi`).
144
+ *
145
+ * Chaîne : `Answer → parent (Form) → form.serverData.parent ({[orgId]: {type, name}}) → check userContext.links`.
146
+ *
147
+ * Si le parent n'est pas un Form (cas `api.answer({id})` direct sans contexte),
148
+ * renvoie `false` — impossible de vérifier la hiérarchie sans le Form.
149
+ *
150
+ * @protected
151
+ */
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
+ isAuthor(options?: {
165
+ silent?: boolean;
166
+ }): boolean;
139
167
  /**
140
168
  * Transforme les champs imbriqués (user, context etc.) en instances d'entités.
141
169
  * @param data - Les données brutes du serveur.
@@ -183,15 +211,53 @@ export declare class Answer extends BaseEntity<AnswerItemNormalized> {
183
211
  * - `serverData` et `draftData` sont vidés (sans casser la réactivité)
184
212
  * - `_isDeleted = true` → toute mutation ultérieure (`save`, `get`, etc.) throw
185
213
  *
214
+ * **Guard** : autorisation côté client si l'utilisateur courant est :
215
+ * - l'**auteur** de l'Answer (`serverData.user === userId`), OU
216
+ * - **admin** d'un parent du Form (org/project) via la hiérarchie
217
+ * (`form.serverData.parent[orgId]` × `userContext.links.memberOf[orgId].isAdmin`).
218
+ *
219
+ * Le check utilise `isAuthorOrAdmin({checkHierarchy: true})` qui s'appuie sur
220
+ * l'override `Answer._isAdminViaHierarchy` (remonte via parent instance Form).
221
+ *
222
+ * **Pré-requis** :
223
+ * - `this.parent` doit être un Form (cas `form.answer({id})`)
224
+ * - `userContext` (User connecté) doit avoir `serverData.links` chargés (cas `api.me()`)
225
+ * Sans ces pré-requis, seul `isAuthor` peut autoriser.
226
+ *
186
227
  * @param reason - Raison libre transmise au backend (audit). Défaut : `"delete coform answer"`.
187
228
  * @throws {ApiError} 400 si l'Answer n'a pas d'id (jamais sauvegardée).
229
+ * @throws {ApiError} 403 si ni auteur ni admin du parent.
188
230
  *
189
231
  * @example
190
232
  * const answer = await form.answer({ id: "..." });
191
- * await answer.delete();
233
+ * await answer.delete(); // OK si auteur OU admin org/project parent du Form
192
234
  * answer._isDeleted; // true
193
235
  */
194
236
  delete(reason?: string): Promise<void>;
237
+ /**
238
+ * {@inheritDoc BaseEntity#deleteFile}
239
+ *
240
+ * Override avec **cleanup local** : après suppression backend, retire le
241
+ * `docId` des structures uploader normalisées dans `serverData.answers` et
242
+ * `_draftData.answers` (format `{updateDate, files: {docId: docPath}}`
243
+ * produit par `processUploads()` et `_transformServerData`).
244
+ *
245
+ * Le caller n'a pas besoin de refetch — `answer.serverData.answers[*][*].files`
246
+ * reflète directement l'état post-suppression.
247
+ *
248
+ * @example
249
+ * const files = await answer.getFiles({ subKey: "sf.input", docType: "image" });
250
+ * await answer.deleteFile(files[0].docId);
251
+ * // answer.serverData.answers[sf][input].files[files[0].docId] === undefined
252
+ */
253
+ deleteFile(docId: string): Promise<void>;
254
+ /**
255
+ * Walk `answers[subFormId][inputId]` et retire `docId` des structures
256
+ * `{updateDate, files: {docId: docPath}}` (format canonique uploader).
257
+ * Mutation in-place pour préserver la réactivité.
258
+ * @private
259
+ */
260
+ private _removeDocIdFromUploaderFields;
195
261
  /**
196
262
  * Récupère la liste des fichiers attachés à un input précis de cette Answer
197
263
  * via `COFORM_GET_ANSWER_FILES`.
@@ -223,6 +289,13 @@ export declare class Answer extends BaseEntity<AnswerItemNormalized> {
223
289
  /**
224
290
  * Upload un fichier rattaché à cette Answer via `COFORM_UPLOAD_ANSWER_FILE`.
225
291
  *
292
+ * **Building block du pipeline** : conçu pour être utilisé via
293
+ * `processUploads()` suivi de `save()`. L'Answer créée par le premier upload
294
+ * est en état "placeholder" côté backend (champ `user` non posé) — `save()`
295
+ * finalise. Appeler `get()` ou `delete()` (via l'entité) sur une Answer
296
+ * upload-only sans save échouera : le backend la considère comme orpheline
297
+ * (`editDeniedReason: "not_owner"`, stub sans `data.id`).
298
+ *
226
299
  * **Cas premier upload (Answer sans id)** : le backend crée l'Answer et
227
300
  * renvoie `answerId`. La méthode pose alors `this._draftData.id = answerId`
228
301
  * — les uploads suivants utiliseront cet id, et un `save()` ultérieur passera
@@ -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
  };
@@ -562,6 +599,117 @@ export declare class BaseEntity<TServerData = any> {
562
599
  qqfilename: string;
563
600
  qqtotalfilesize: number;
564
601
  }>;
602
+ /**
603
+ * Supprime un document (fichier ou image) par son `docId` MongoDB via
604
+ * `DELETE_DOCUMENT_BY_ID`.
605
+ *
606
+ * Méthode générique exposée sur toutes les entités — le endpoint backend
607
+ * opère par docId seul, sans contexte parent requis. Disponible ici pour
608
+ * être découvrable et **override-able** par les entités qui veulent un
609
+ * cleanup local après suppression (ex: `News.deleteFile` pourrait retirer
610
+ * l'id de `mediaImg.images` côté serverData).
611
+ *
612
+ * Ne met PAS à jour `serverData` après suppression — le caller doit
613
+ * invalider son cache local s'il en a un (cas typique : React Query).
614
+ *
615
+ * @param docId - ID MongoDB du document (24 hex)
616
+ * @throws {ApiError} 400 si `docId` invalide.
617
+ *
618
+ * @example
619
+ * // Depuis une Answer (suppression d'un fichier uploader)
620
+ * const files = await answer.getFiles({ subKey: "sf.input", docType: "image" });
621
+ * await answer.deleteFile(files[0].docId);
622
+ *
623
+ * @example
624
+ * // Depuis n'importe quelle entité qui possède un docId
625
+ * await news.deleteFile(imageDocId);
626
+ */
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;
565
713
  /**
566
714
  * Valide les entrées d'upload de fichiers.
567
715
  *
@@ -938,15 +1086,24 @@ export declare class BaseEntity<TServerData = any> {
938
1086
  */
939
1087
  private _extractUserContext;
940
1088
  /**
941
- * Vérifie si l'utilisateur est admin via la hiérarchie parent (logique généraliste)
942
- * @private
1089
+ * Vérifie si l'utilisateur est admin via la hiérarchie parent (logique généraliste).
1090
+ *
1091
+ * Note : passé `protected` pour permettre l'override par les entités dont la
1092
+ * hiérarchie n'est pas un simple champ `serverData.parent` ou `.organizer`
1093
+ * (cf. `Answer._isAdminViaHierarchy` qui remonte via son parent instance Form).
1094
+ *
1095
+ * @protected
943
1096
  */
944
- private _isAdminViaHierarchy;
1097
+ protected _isAdminViaHierarchy(): boolean;
945
1098
  /**
946
- * Vérifie si l'utilisateur est admin d'un parent spécifique
947
- * @private
1099
+ * Vérifie si l'utilisateur est admin d'un parent spécifique.
1100
+ *
1101
+ * Note : passé `protected` pour être utilisable par les overrides de
1102
+ * `_isAdminViaHierarchy()` (cf. `Answer._isAdminViaHierarchy`).
1103
+ *
1104
+ * @protected
948
1105
  */
949
- private _isAdminOfParent;
1106
+ protected _isAdminOfParent(parentId: string, parentType: string): boolean;
950
1107
  /**
951
1108
  * Construit dynamiquement des filtres sur un lien entre entités
952
1109
  *
@@ -1503,11 +1660,15 @@ export declare class BaseEntity<TServerData = any> {
1503
1660
  *
1504
1661
  * @param options - Options de vérification.
1505
1662
  * @param options.silent - Si `true`, retourne `false` au lieu de lever une exception. Par défaut `true`.
1663
+ * @param options.checkHierarchy - Si `true`, propagé à `isAdmin` pour vérifier
1664
+ * également la hiérarchie parent (ex: `Answer.isAdmin({checkHierarchy: true})`
1665
+ * remonte vers org/project du Form parent).
1506
1666
  * @returns - `true` si l'utilisateur est l'auteur ou administrateur, `false` sinon.
1507
1667
  * @throws {ApiError} - Si `silent` est `false` et que les préconditions ne sont pas remplies.
1508
1668
  */
1509
1669
  isAuthorOrAdmin(options?: {
1510
1670
  silent?: boolean;
1671
+ checkHierarchy?: boolean;
1511
1672
  }): boolean;
1512
1673
  /**
1513
1674
  * Vérifie si l'utilisateur est membre de l'entité.
@@ -1907,14 +2068,25 @@ export declare class BaseEntity<TServerData = any> {
1907
2068
  */
1908
2069
  getCountries(data?: Partial<GetCountriesData>): Promise<CountryItem[]>;
1909
2070
  /**
1910
- * 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`).
2074
+ *
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.
1911
2079
  *
1912
- * @param formId - Identifiant du formulaire pour lequel générer un nouvel ID d'answers
1913
- * @returns Un nouvel answers avec le nouveau ID généré
1914
- * @throws {ApiError} Si formId est absent ou invalide
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
1915
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 });
1916
2088
  */
1917
- generateNewAnswerId(formId: string): Promise<any>;
2089
+ generateNewAnswerId(formId: string): Promise<Answer>;
1918
2090
  /**
1919
2091
  * Associe un compte Discourse à l'utilisateur courant dans le contexte de l'instance.
1920
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
  *