@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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@communecter/cocolight-api-client",
3
- "version": "1.0.195",
3
+ "version": "1.0.197",
4
4
  "description": "Client Axios simplifié pour l'API cocolight",
5
5
  "repository": {
6
6
  "type": "git",
@@ -22,6 +22,45 @@ export interface AnswerChange {
22
22
  mutationType: "create" | "update" | "";
23
23
  changedFields: string[];
24
24
  }
25
+ /**
26
+ * Résultat d'un {@link Answer#addVote} — le backend BASCULE : re-poster le
27
+ * MÊME statut RETIRE la réaction au lieu d'en poser une seconde.
28
+ *
29
+ * Distinguer les deux cas se lit sur `inc` (`+1` ajout / `-1` retrait) ou, de
30
+ * façon non ambiguë, sur la présence de `removedVoteStatus` — `msg` ne sert à
31
+ * rien pour ça : il vaut `"Reaction succesfully saved"` à l'ajout mais la
32
+ * chaîne VIDE au retrait.
33
+ */
34
+ export interface AnswerVoteResult {
35
+ result: boolean;
36
+ userActionSaved?: boolean;
37
+ /** `+1` réaction posée, `-1` réaction retirée. */
38
+ inc?: number;
39
+ /** `""` au retrait, message traduit à l'ajout. */
40
+ msg?: string;
41
+ /** Présent UNIQUEMENT au retrait : le statut qui vient d'être enlevé. */
42
+ removedVoteStatus?: string;
43
+ user?: Record<string, unknown>;
44
+ element?: Record<string, unknown>;
45
+ [key: string]: unknown;
46
+ }
47
+ /**
48
+ * Résultat d'un {@link Answer#getVotes} — document projeté `{_id, vote, voteCount}`.
49
+ * Chaque entrée de `vote` est enrichie du profil du votant (`name`, `slug`,
50
+ * `profilThumbImageUrl`), ou vaut `null` si l'élément référencé est introuvable.
51
+ */
52
+ export interface AnswerVotesResult {
53
+ vote?: Record<string, {
54
+ status?: string;
55
+ date?: unknown;
56
+ name?: string;
57
+ slug?: string;
58
+ profilThumbImageUrl?: string;
59
+ [key: string]: unknown;
60
+ } | null>;
61
+ voteCount?: Record<string, number>;
62
+ [key: string]: unknown;
63
+ }
25
64
  /** Options de `Answer.generateProject()` — équivalent `costum.contextId`/`costum.contextType` legacy. */
26
65
  export interface GenerateProjectOptions {
27
66
  /** ID de l'entité parente (org/site porteur de l'appel). */
@@ -374,6 +413,56 @@ export declare class Answer extends BaseEntity<AnswerItemNormalized> {
374
413
  * await answer.delete();
375
414
  */
376
415
  delete(reason?: string): Promise<void>;
416
+ /**
417
+ * Ajoute OU retire une réaction sur cette réponse (`co2/action/addaction`,
418
+ * `collection: "answers"`).
419
+ *
420
+ * **Un seul appel pour les deux sens** : le backend bascule. Poster un statut
421
+ * que l'utilisateur n'a pas encore posé l'ajoute (`inc: +1`) ; re-poster le
422
+ * MÊME statut le retire (`inc: -1` + `removedVoteStatus`). Poster un statut
423
+ * DIFFÉRENT remplace le précédent. Il n'existe donc pas d'endpoint de
424
+ * suppression distinct — cf. {@link AnswerVoteResult}.
425
+ *
426
+ * Les compteurs vivent dans `serverData.voteCount` (map `statut → entier`) et
427
+ * le détail par utilisateur dans `serverData.vote` (map `userId → {status, date}`) ;
428
+ * ni l'un ni l'autre n'est renvoyé au serveur au save (`removeFields`).
429
+ * Cette instance n'est PAS resynchronisée : relire via {@link Answer#getVotes}.
430
+ *
431
+ * Droits : le serveur ne vérifie QUE la session (`AddActionAction`). N'importe quel utilisateur
432
+ * connecté peut réagir sur n'importe quelle réponse, y compris d'un formulaire auquel il n'a pas
433
+ * accès — c'est à l'appelant de n'offrir la réaction que là où elle a du sens.
434
+ *
435
+ * @param status - Statut de la réaction (`"like"`, `"love"`, `"sad"`…). Libre côté backend, mais
436
+ * non vide : il devient un nom de champ (`voteCount.<status>`), et un nom vide fait
437
+ * échouer l'écriture Mongo.
438
+ * @returns Réponse API, dont `inc` et `removedVoteStatus` disent le sens de la bascule.
439
+ * @throws {ApiError} 404 si la réponse n'a pas d'id (jamais sauvegardée) ; 400 statut vide.
440
+ *
441
+ * @example
442
+ * const res = await answer.addVote("like");
443
+ * const retiree = res.removedVoteStatus !== undefined; // true = réaction ENLEVÉE
444
+ */
445
+ addVote(status: string): Promise<AnswerVoteResult>;
446
+ /**
447
+ * Récupère les réactions posées sur cette réponse.
448
+ *
449
+ * Wrap de `SHOW_VOTE` avec auto-injection du `type` (`"answers"`) et de
450
+ * `this.id` dans `pathParams`. Le retour contient `vote` (réactions
451
+ * individuelles indexées par userId, enrichies du profil du votant) et
452
+ * `voteCount` (compteurs par statut).
453
+ *
454
+ * Endpoint PUBLIC : les réactions et le profil des votants se lisent sans session.
455
+ *
456
+ * @returns Réponse API : `{ _id, vote, voteCount }` ou variante d'erreur — ou `null` quand l'id ne
457
+ * désigne aucune réponse (le legacy renvoie le `findOne` tel quel).
458
+ * @throws {ApiError} 404 si la réponse n'a pas d'id (jamais sauvegardée).
459
+ *
460
+ * @example
461
+ * const votes = await answer.getVotes();
462
+ * votes?.voteCount?.like; // nombre de "like"
463
+ * votes?.vote?.[userId]?.status === "like"; // l'utilisateur a-t-il réagi ?
464
+ */
465
+ getVotes(): Promise<AnswerVotesResult | null>;
377
466
  /**
378
467
  * {@inheritDoc BaseEntity#deleteFile}
379
468
  *
@@ -1,6 +1,7 @@
1
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, SearchEventsCostumData, CostumFilterCoformData, CostumFilterCoformByPathData, GetCountriesData, SearchZonesData, ZoneGetShapeData, ZoneGetZonirisData, CoformAnswersByFormsData, FundingEnvelopeData, CoremuOperationData, UpdatePathValueData } from "./EndpointApi.types.js";
2
2
  import type { CostumRuntimeContext } from "../costum/runtime.js";
3
3
  import type { TransformsMap } from "../types/entities.js";
4
+ import type { AmpliParentType, CreateAmpliInput, CreateAmpliResult, RemoveAmpliResult } from "./serverDataType/Ampli.js";
4
5
  import type { CountryItem } from "./serverDataType/Country.js";
5
6
  import type { ToolEnrichmentInput, ToolEnrichmentResult, CommunListItem } from "./serverDataType/ToolsCatalog.js";
6
7
  import type { ZoneItemNormalized, ZoneShapeItem, ZonirisShapeItem } from "./serverDataType/Zone.js";
@@ -2692,6 +2693,75 @@ export declare class BaseEntity<TServerData = any> {
2692
2693
  * costum peut être un projet). `formId` en argument positionnel. Retourne le tableau NU.
2693
2694
  */
2694
2695
  getCommunList(formId: string): Promise<CommunListItem[]>;
2696
+ /**
2697
+ * Contexte de l'élément PORTEUR du costum, tel que les deux actions ampli l'exigent.
2698
+ *
2699
+ * Volontairement PAS `_withCostumContext` : ces actions ne lisent ni `contextId` ni `sourceKey`,
2700
+ * elles nomment les mêmes valeurs `parentId`/`parentType`/`parentName`, et leur contrat est en
2701
+ * `additionalProperties:false` — les alias historiques injectés par le helper y seraient rejetés
2702
+ * par l'AJV du client avant même l'envoi.
2703
+ *
2704
+ * Lit `serverData` et non le brouillon : le serveur relit l'élément en base (`PHDB::findOne`),
2705
+ * un slug modifié mais non sauvegardé désignerait un costum qui n'existe pas.
2706
+ */
2707
+ protected _requireAmpliHost(): {
2708
+ id: string;
2709
+ type: AmpliParentType;
2710
+ slug: string;
2711
+ };
2712
+ /**
2713
+ * Crée un **ampli** sur cette entité : une entrée de `costum.ampli`, l'espace de propositions du
2714
+ * costum qu'elle porte.
2715
+ *
2716
+ * BEARER + gate admin serveur (`isInterfaceAdmin`). Porté par `BaseEntity` — comme
2717
+ * {@link saveToolEnrichment} — parce que l'hôte d'un costum peut être une organisation, un
2718
+ * projet, un citoyen ou un événement, et qu'un ampli n'est pas une entité mais une clé de costum.
2719
+ *
2720
+ * DEUX MODES, exclusifs, distingués par la présence de `coform` :
2721
+ * - sans `coform` (défaut) : le serveur crée le `Form` de dépôt et ses cinq questions, et renvoie
2722
+ * les chemins obtenus dans `ampli.path` ;
2723
+ * - avec `coform` : rattachement à un formulaire existant, `namePath` et `addressPath` exigés.
2724
+ *
2725
+ * ⚠ Le serveur dérive la CLÉ de l'entrée du `name` et **écrase** une entrée de même clé, sans
2726
+ * garde. Un appelant qui a déjà la liste des amplis doit tester la collision avec le helper `ampliSlug`.
2727
+ *
2728
+ * Le cache costum est réinitialisé côté serveur après écriture : `element/about` renvoie le nouvel
2729
+ * ampli immédiatement, sans `resetcache`.
2730
+ *
2731
+ * Exige `CreateAmpliAction` de modules/costum@3ef97ef28 ou postérieur (lecture de `source`, clé
2732
+ * `slugifyLikeJS`, réponse `{slug, ampli}`). Face à une version antérieure, l'action écrit tout le
2733
+ * parcours Co et répond sans `slug` : la méthode lève alors au lieu de rendre un résultat incomplet.
2734
+ *
2735
+ * @param input - Nom, description, mots-clés, et le formulaire en mode B.
2736
+ * @returns `{ result, slug, ampli, … }` — `slug` permet d'atteindre `/ampli/<slug>` sans recharger.
2737
+ * @throws {ApiError} 404 entité non enregistrée ; 400 slug manquant, hôte de type impossible,
2738
+ * nom inexploitable, ou mode B incomplet.
2739
+ * @throws {ApiResponseError} Refus métier du serveur (droits, paramètre manquant) — il arrive en
2740
+ * HTTP 200 `{result:false}`, que `checkAndThrowApiResponseError` convertit en exception —, ou
2741
+ * réponse sans `slug` (action legacy antérieure au patch).
2742
+ *
2743
+ * @example
2744
+ * const { slug } = await orga.createAmpli({ name: "Idées d'été", tags: ["proposition"] });
2745
+ * // → navigation vers `/ampli/idees-d-ete`
2746
+ */
2747
+ createAmpli(input: CreateAmpliInput): Promise<CreateAmpliResult>;
2748
+ /**
2749
+ * Supprime un ampli de `costum.ampli`, avec ses pages CMS et son bouton de menu s'il en a.
2750
+ *
2751
+ * ⚠ DEUX EFFETS DE BORD du legacy, non corrigés ici :
2752
+ * - le `Form` de dépôt et ses réponses **survivent** : un ampli créé en mode A puis supprimé
2753
+ * laisse son formulaire derrière lui ;
2754
+ * - l'action réécrit `costum.app` et le `buttonList` du menu à partir du costum **résolu en
2755
+ * cache** (`Costum::init`), pas du sous-document en base. Pour un costum dont la config vient
2756
+ * d'un fichier JSON, la suppression matérialise donc cette config dans le document de l'hôte.
2757
+ *
2758
+ * @param ampliId - La CLÉ de l'entrée, lue dans `costum.ampli` ou renvoyée par `createAmpli` — pas
2759
+ * un ObjectId, et jamais un slug recalculé depuis le nom : les entrées anciennes ont une clé
2760
+ * d'une autre forme (`idées-d'été`), que `ampliSlug` ne reproduit pas.
2761
+ * @throws {ApiError} 404 entité non enregistrée ; 400 slug manquant ou hôte de type impossible.
2762
+ * @throws {ApiResponseError} `Ampli not found`, `ampliId is required`, ou refus de droits.
2763
+ */
2764
+ removeAmpli(ampliId: string): Promise<RemoveAmpliResult>;
2695
2765
  /**
2696
2766
  * @param data
2697
2767
  * Paramètres de recherche (partiels — les valeurs manquantes sont complétées
@@ -1,5 +1,5 @@
1
1
  import type ApiClient from "../ApiClient.js";
2
- import type { DocumentListData, PersonRegisterData, AuthenticateUrlData, RefreshTokenUrlData, PasswordRecoveryData, PasswordResetData, ServerExchangeTokenData, ChangePasswordData, DeleteAccountData, UpdateSettingsData, UpdateBlockDescriptionData, UpdateBlockInfoData, UpdateBlockSocialData, UpdateBlockLocalityData, UpdateBlockSlugData, CheckData, ProfilImageData, ProfilBannerData, GetElementsAboutData, MulticonnectData, RelaunchInvitationData, ContactSendData, GetNewsData, GetNewsByIdData, AddNewsData, AddImageNewsData, AddFileNewsData, DeleteNewsData, UpdateNewsData, ShareNewsData, GetCommentsData, AddCommentsData, DeleteCommentsData, UpdateCommentsData, SearchTagsData, ShowVoteData, GlobalAutocompleteData, CityAutocompleteData, CityAutocompleteByCountryData, SuggestionInputData, GetProjectsNoAdminData, GetProjectsAdminData, GetPoisNoAdminData, GetPoisAdminData, GlobalAutocompleteAdminCostumData, GetOrganizationsNoAdminData, GetOrganizationsAdminData, GetUserEligiblePlacesData, GetMembersNoAdminData, GetMembersAdminData, GetFriendsAdminData, GetSubscriptionsData, GetSubscriptionsAdminData, GetSubscribersData, GetSubscribersAdminData, GetContributorsNoAdminData, GetContributorsAdminData, GetBadgesData, GetBadgesFiltersData, ConnectData, CreateInvitationLinkData, ConnectByRefData, DisconnectData, GetElementsKeyData, GetFavorisData, DeleteFavorisData, AddFavorisData, AddOrganizationData, AddProjectData, AddPoiData, AddEventData, DeleteElementData, AddImageElementData, LinkValidateData, SearchMemberAutocompleteData, GetNotificationsData, GetNotificationsCountData, NotificationUpdateData, MarkNotificationAsReadData, ActivitypubSearchData, ActivitypubLinkData, ActivitypubGetCommunityData, GetBadgeData, AddBadgesData, AssignBadgesData, GetEventsData, SearchEventsCostumData, ShareEventsData, InviteMembersData, FollowData, GetCostumJsonData, GlobalAutocompleteCostumData, NavigatorGettlData, NavigatorGetRessourceTlData, CostumEventRequestActorsData, CostumEventRequestSubeventsData, CostumEventRequestElementEventData, CostumEventRequestCategoriesData, CostumEventRequestDatesData, CostumEventRequestEventData, CostumEventRequestLinkTlToEventData, CostumEventRequestLoadContextTagData, GetGalleryData, GetAttendeesNoAdminData, GetAttendeesAdminData, CoformAnswersSearchData, CoformAnswersByIdData, GetCoformByIdData, CoformUploadAnswerFileData, DeleteCoformAnswerFileData, CoformGetAnswerFilesData, GetCoformCatalogsData, SaveCoformAnswerData, GetCoformAnswerHistoryData, GetCoformMultievalDataData, GetCoformCommontableContributorsData, AddVoteData, AddReportAbuseData, UpdatePathValueData, DeleteDocumentByContextData, DeleteDocumentByIdData, DemoteAdminData, CostumFilterCoformData, CostumFilterCoformByPathData, GetCountriesData, SearchZonesData, CoformAnswersByFormsData, CostumToolsCatalogData, CostumToolUsersData, CostumCommunInfoData, CostumSaveToolEnrichmentData, CostumCommunListData, GenerateAnswerFromFormData, GenerateProjectFromAnswerData, GenerateMilestoneFromDepenseData, FundingEnvelopeData, CoremuOperationData, CoremuAddFinancerData, CoremuPayFinancerData, CoremuValidateFinancerPaymentData, CoremuDeleteFinancerData, CostumProjectActionRequestNewData, CostumProjectActionRequestSetStatusData, CostumProjectActionRequestSetDateData, CostumProjectActionRequestSetContributorsData, CostumProjectActionRequestCancelData, CostumProjectActionRequestArchiveData, LinkDiscourseAccountData, UnlinkDiscourseAccountData, DiscourseProfileData, DiscourseCheckEmailData, DiscourseDismissLinkData, LinkMediawikiAccountData, UnlinkMediawikiAccountData, GetMediawikiContributionsData, AddClassifiedData, PersonActivateData, PersonValidateInvitationData, ValidateInvitationByMailData, ImportPreviewData, ExportElementsData, ImportElementsData, GeocodageData, ValidateGroupData, SetSourceData, TransferSourceCheckData, TransferSourceApplyData, TransferSourceRollbackData, TransferSourceHistoryData, ModerateData, NewsModerateData, CommentModerateData, UploadDocumentData, ZoneGetShapeData, ZoneGetZonirisData, CostumListValuesData, CostumResolvedData, DirectoryProposalData, DirectoryProposalCountData, DirectoryProposalNewCounterData } from "./EndpointApi.types.js";
2
+ import type { DocumentListData, PersonRegisterData, AuthenticateUrlData, RefreshTokenUrlData, PasswordRecoveryData, PasswordResetData, ServerExchangeTokenData, ChangePasswordData, DeleteAccountData, UpdateSettingsData, UpdateBlockDescriptionData, UpdateBlockInfoData, UpdateBlockSocialData, UpdateBlockLocalityData, UpdateBlockSlugData, CheckData, ProfilImageData, ProfilBannerData, GetElementsAboutData, MulticonnectData, RelaunchInvitationData, ContactSendData, GetNewsData, GetNewsByIdData, AddNewsData, AddImageNewsData, AddFileNewsData, DeleteNewsData, UpdateNewsData, ShareNewsData, GetCommentsData, AddCommentsData, DeleteCommentsData, UpdateCommentsData, SearchTagsData, ShowVoteData, GlobalAutocompleteData, CityAutocompleteData, CityAutocompleteByCountryData, SuggestionInputData, GetProjectsNoAdminData, GetProjectsAdminData, GetPoisNoAdminData, GetPoisAdminData, GlobalAutocompleteAdminCostumData, GetOrganizationsNoAdminData, GetOrganizationsAdminData, GetUserEligiblePlacesData, GetMembersNoAdminData, GetMembersAdminData, GetFriendsAdminData, GetSubscriptionsData, GetSubscriptionsAdminData, GetSubscribersData, GetSubscribersAdminData, GetContributorsNoAdminData, GetContributorsAdminData, GetBadgesData, GetBadgesFiltersData, ConnectData, LinkSetRolesData, CreateInvitationLinkData, ConnectByRefData, DisconnectData, GetElementsKeyData, GetFavorisData, DeleteFavorisData, AddFavorisData, AddOrganizationData, AddProjectData, AddPoiData, AddEventData, DeleteElementData, AddImageElementData, LinkValidateData, SearchMemberAutocompleteData, GetNotificationsData, GetNotificationsCountData, NotificationUpdateData, MarkNotificationAsReadData, ActivitypubSearchData, ActivitypubLinkData, ActivitypubGetCommunityData, GetBadgeData, AddBadgesData, AssignBadgesData, GetEventsData, SearchEventsCostumData, ShareEventsData, InviteMembersData, FollowData, GetCostumJsonData, GlobalAutocompleteCostumData, NavigatorGettlData, NavigatorGetRessourceTlData, CostumEventRequestActorsData, CostumEventRequestSubeventsData, CostumEventRequestElementEventData, CostumEventRequestCategoriesData, CostumEventRequestDatesData, CostumEventRequestEventData, CostumEventRequestLinkTlToEventData, CostumEventRequestLoadContextTagData, AgendaGetPdfData, GetGalleryData, GetAttendeesNoAdminData, GetAttendeesAdminData, CoformAnswersSearchData, CoformAnswersByIdData, GetCoformByIdData, CoformUploadAnswerFileData, DeleteCoformAnswerFileData, CoformGetAnswerFilesData, GetCoformCatalogsData, SaveCoformAnswerData, GetCoformAnswerHistoryData, GetCoformMultievalDataData, GetCoformCommontableContributorsData, AddVoteData, AddReportAbuseData, UpdatePathValueData, DeleteDocumentByContextData, DeleteDocumentByIdData, DemoteAdminData, CostumFilterCoformData, CostumFilterCoformByPathData, GetCountriesData, SearchZonesData, CoformAnswersByFormsData, CostumToolsCatalogData, CostumToolUsersData, CostumCommunInfoData, CostumSaveToolEnrichmentData, CostumCommunListData, GenerateAnswerFromFormData, GenerateProjectFromAnswerData, GenerateMilestoneFromDepenseData, FundingEnvelopeData, CoremuOperationData, CoremuAddFinancerData, CoremuPayFinancerData, CoremuValidateFinancerPaymentData, CoremuDeleteFinancerData, CostumProjectActionRequestNewData, CostumProjectActionRequestSetStatusData, CostumProjectActionRequestSetDateData, CostumProjectActionRequestSetContributorsData, CostumProjectActionRequestCancelData, CostumProjectActionRequestArchiveData, LinkDiscourseAccountData, UnlinkDiscourseAccountData, DiscourseProfileData, DiscourseCheckEmailData, DiscourseDismissLinkData, LinkMediawikiAccountData, UnlinkMediawikiAccountData, GetMediawikiContributionsData, AddClassifiedData, PersonActivateData, PersonValidateInvitationData, ValidateInvitationByMailData, ImportPreviewData, ExportElementsData, ImportElementsData, GeocodageData, ValidateGroupData, SetSourceData, TransferSourceCheckData, TransferSourceApplyData, TransferSourceRollbackData, TransferSourceHistoryData, ModerateData, NewsModerateData, CommentModerateData, UploadDocumentData, ZoneGetShapeData, ZoneGetZonirisData, CostumListValuesData, CostumResolvedData, DirectoryProposalData, DirectoryProposalCountData, DirectoryProposalNewCounterData, CostumCreateAmpliData, CostumRemoveAmpliData } from "./EndpointApi.types.js";
3
3
  /**
4
4
  * Classe EndpointApi générée automatiquement depuis endpoints-copie.json
5
5
  */
@@ -395,7 +395,7 @@ export declare class EndpointApi {
395
395
  */
396
396
  searchTags(data: SearchTagsData): Promise<any>;
397
397
  /**
398
- * Afficher les votes d'une actualité/commentaire : Récupère la liste des votes (like, love, etc.) sur une actualité/commentaire.
398
+ * Afficher les votes d'une actualité, d'un commentaire ou d'une réponse de formulaire : Récupère la liste des votes (like, love, etc.) sur une actualité, un commentaire ou une réponse de formulaire (coform).
399
399
  * Constant : SHOW_VOTE
400
400
  * @param data - Données envoyées à l'API
401
401
  * @returns Les données de réponse.
@@ -630,6 +630,16 @@ export declare class EndpointApi {
630
630
  * @throws {Error} - En cas d'erreur inattendue.
631
631
  */
632
632
  connect(data: ConnectData): Promise<any>;
633
+ /**
634
+ * Définir les rôles d'un lien : Remplace INTÉGRALEMENT les rôles d'un lien existant (ou en pose un premier), des deux côtés : `links.<connectType>.<childId>.roles` sur le contexte et `links.<memberOf|projects|events>.<contextId>.roles` sur l'enfant. Malgré le nom du chemin legacy (Link::removeRole, citizenToolKit/models/Link.php:866-917), ce n'est PAS un retrait sélectif : `roles` non vide → `$set` du tableau envoyé ; `roles` vide ou absent → `$unset` (tous les rôles effacés). L'appelant envoie donc la liste COMPLÈTE voulue. Réservé aux admins du contexte au sens d'Authorisation::isElementAdmin — lien admin, admin du parent (ou de l'organisateur d'un événement), super-admin, admin du costum transmis (sinon {result:false, msg:"You are not admin of the Organization : <id>"}, HTTP 200). Le lien doit EXISTER : le backend Node refuse sinon ({result:false, msg:"The actor (<id> / <type>) is not linked to this element"}), le legacy l'écrirait (BUG-L-267).
635
+ * Constant : LINK_SET_ROLES
636
+ * @param data - Données envoyées à l'API
637
+ * @returns Les données de réponse.
638
+ * @throws {ApiResponseError} - En cas d'erreur détectée dans la réponse.
639
+ * @throws {ApiAuthenticationError} - En cas d'erreur d'authentification.
640
+ * @throws {Error} - En cas d'erreur inattendue.
641
+ */
642
+ linkSetRoles(data: LinkSetRolesData): Promise<any>;
633
643
  /**
634
644
  * Générer un lien d'invitation partageable : Génère une URL d'invitation partageable /co2/link/connect/ref/<ref> vers un élément (organizations/projects/events). Tout citoyen connecté qui suit le lien rejoint l'élément IMMÉDIATEMENT (member, ou admin si isAdmin). L'appelant doit être ADMIN de la cible (ou super-admin). ⚠ Durcissements vs legacy : whitelist stricte des champs (pas de mass-assignment du body), ref cryptographique (le legacy dérivait uniqid()). Deux appels (isAdmin=true / false) alimentent costum.invitationLink / costum.invitationLinkAsMember côté UI.
635
645
  * Constant : CREATE_INVITATION_LINK
@@ -1048,6 +1058,15 @@ export declare class EndpointApi {
1048
1058
  * @throws {Error} - En cas d'erreur inattendue.
1049
1059
  */
1050
1060
  costumEventRequestLoadContextTag(data: CostumEventRequestLoadContextTagData): Promise<any>;
1061
+ /**
1062
+ * PDF imprimable de l'agenda d'un costum : Édition imprimable (PDF binaire, application/pdf) de l'agenda d'un costum : sous-événements de l'entité PORTEUSE du costum (id/type de l'entité, pas d'un événement), triés par date d'occurrence. Port de costum/controllers/actions/coevent/pdf/GetPdfAction.php. Tout paramètre GET non réservé (id, type, costum_slug, startDate, vue, rest, tab) filtre les sous-événements sur le champ top-level du même nom, en `$in` insensible à la casse sur une liste séparée par des virgules — d'où `additionalProperties` ouvert : les facettes propres à un site (ex. territoires/publics/thèmes de parent62) n'ont pas à être nommées ici.
1063
+ * Constant : AGENDA_GET_PDF
1064
+ * @param data - Données envoyées à l'API
1065
+ * @returns Les données de réponse.
1066
+ * @throws {ApiResponseError} - En cas d'erreur détectée dans la réponse.
1067
+ * @throws {Error} - En cas d'erreur inattendue.
1068
+ */
1069
+ agendaGetPdf(data: AgendaGetPdfData): Promise<any>;
1051
1070
  /**
1052
1071
  * Récupération de la galerie : Renvoie soit la liste d’albums associés à une entité, soit les images d’un album spécifique.
1053
1072
  * Constant : GET_GALLERY
@@ -1182,7 +1201,7 @@ export declare class EndpointApi {
1182
1201
  */
1183
1202
  getCoformCommontableContributors(data: GetCoformCommontableContributorsData): Promise<any>;
1184
1203
  /**
1185
- * Voter sur un élément (commentaire ou news) : Permet de voter sur un commentaire ou une news en spécifiant un statut de vote
1204
+ * Voter sur un élément (commentaire, news ou réponse de formulaire) : Permet de voter sur un commentaire, une news ou une réponse de formulaire (coform) en spécifiant un statut de vote. Re-poster le MÊME statut retire le vote (bascule) : la réponse porte alors removedVoteStatus et inc:-1.
1186
1205
  * Constant : ADD_VOTE
1187
1206
  * @param data - Données envoyées à l'API
1188
1207
  * @returns Les données de réponse.
@@ -1797,5 +1816,25 @@ export declare class EndpointApi {
1797
1816
  * @throws {Error} - En cas d'erreur inattendue.
1798
1817
  */
1799
1818
  directoryProposalNewCounter(data: DirectoryProposalNewCounterData): Promise<any>;
1819
+ /**
1820
+ * Créer un ampli : Crée une entrée dans costum.ampli de l'élément porteur du costum. Avec source=site-json aucune page CMS, aucun bloc cms ni bouton de menu n'est écrit. Gate isInterfaceAdmin, résolu par costumSlug (refus en HTTP 200 result:false). Le cache costum est réinitialisé après écriture : element/about renvoie le nouvel ampli immédiatement.
1821
+ * Constant : COSTUM_CREATE_AMPLI
1822
+ * @param data - Données envoyées à l'API
1823
+ * @returns Les données de réponse.
1824
+ * @throws {ApiResponseError} - En cas d'erreur détectée dans la réponse.
1825
+ * @throws {ApiAuthenticationError} - En cas d'erreur d'authentification.
1826
+ * @throws {Error} - En cas d'erreur inattendue.
1827
+ */
1828
+ costumCreateAmpli(data: CostumCreateAmpliData): Promise<any>;
1829
+ /**
1830
+ * Supprimer un ampli : Retire une entrée de costum.ampli, ses pages CMS et son bouton de menu s'il en a. Ne supprime NI le Form NI ses réponses. Gate isInterfaceAdmin (refus en HTTP 200 result:false).
1831
+ * Constant : COSTUM_REMOVE_AMPLI
1832
+ * @param data - Données envoyées à l'API
1833
+ * @returns Les données de réponse.
1834
+ * @throws {ApiResponseError} - En cas d'erreur détectée dans la réponse.
1835
+ * @throws {ApiAuthenticationError} - En cas d'erreur d'authentification.
1836
+ * @throws {Error} - En cas d'erreur inattendue.
1837
+ */
1838
+ costumRemoveAmpli(data: CostumRemoveAmpliData): Promise<any>;
1800
1839
  }
1801
1840
  export default EndpointApi;
@@ -1118,9 +1118,9 @@ export interface SearchTagsData {
1118
1118
  export interface ShowVoteData {
1119
1119
  pathParams?: {
1120
1120
  /**
1121
- * Type de l'élément
1121
+ * Type de l'élément (collection Mongo)
1122
1122
  */
1123
- type: "news" | "comments";
1123
+ type: "news" | "comments" | "answers";
1124
1124
  /**
1125
1125
  * ID de l'élément dont on veut récupérer les votes
1126
1126
  */
@@ -2928,6 +2928,49 @@ export interface ConnectData {
2928
2928
  * Type de connexion
2929
2929
  */
2930
2930
  connectType: "admin" | "member" | "contributor" | "attendee" | "friend" | "connect";
2931
+ /**
2932
+ * Rôles à poser sur le lien (`links.<connectType>.<childId>.roles`, des deux côtés). Lu par ConnectAction ($_POST["roles"]) : fusionné AVANT les rôles déjà portés par le lien côté enfant (array_merge), puis écrit par Link::connect. Effectif à la CRÉATION d'un lien, et lors d'une promotion admin (connectType=admin sur un membre non admin : rôles fusionnés puis écrits). Sur un lien déjà établi du même statut, Link::connectParentToChild répond « already member » avant toute écriture — pour modifier les rôles d'un lien établi, utiliser LINK_SET_ROLES.
2933
+ */
2934
+ roles?: string[];
2935
+ /**
2936
+ * Contexte costum de l'action : slug du SITE appelant (l'entité porteuse du costum), jamais le slug du moteur (« costumize »). Injecté automatiquement par le client (ApiClient.setSiteCostum / setCostumScope). Le legacy le lit dans $_POST — CommunecterController::costumCacheParams réchauffe alors le cache costum AVANT l'action, ce qui brande l'e-mail émis (domaine des liens, titre, logo, expéditeur) et stampe source.key sur le job cron.
2937
+ */
2938
+ costumSlug?: string;
2939
+ /**
2940
+ * Contexte costum : _id de l'entité porteuse du costum (contextId). Facultatif, complète costumSlug.
2941
+ */
2942
+ costumId?: string;
2943
+ /**
2944
+ * Contexte costum : collection de l'entité porteuse (organizations | projects | events | citoyens). Facultatif, complète costumSlug.
2945
+ */
2946
+ costumType?: string;
2947
+ [k: string]: unknown;
2948
+ }
2949
+ export interface LinkSetRolesData {
2950
+ /**
2951
+ * ID de l'entité porteuse du lien (organisation, projet, événement)
2952
+ */
2953
+ contextId: string;
2954
+ /**
2955
+ * Type de l'entité porteuse
2956
+ */
2957
+ contextType: "organizations" | "projects" | "events";
2958
+ /**
2959
+ * ID du membre / contributeur / participant
2960
+ */
2961
+ childId: string;
2962
+ /**
2963
+ * Type du membre
2964
+ */
2965
+ childType: "citoyens" | "organizations";
2966
+ /**
2967
+ * Clé du lien côté contexte
2968
+ */
2969
+ connectType: "members" | "contributors" | "attendees";
2970
+ /**
2971
+ * Liste COMPLÈTE des rôles voulus. Vide → efface tous les rôles du lien ($unset). Valeurs écrites telles quelles (pas de trim côté legacy pour un tableau).
2972
+ */
2973
+ roles?: string[];
2931
2974
  /**
2932
2975
  * Contexte costum de l'action : slug du SITE appelant (l'entité porteuse du costum), jamais le slug du moteur (« costumize »). Injecté automatiquement par le client (ApiClient.setSiteCostum / setCostumScope). Le legacy le lit dans $_POST — CommunecterController::costumCacheParams réchauffe alors le cache costum AVANT l'action, ce qui brande l'e-mail émis (domaine des liens, titre, logo, expéditeur) et stampe source.key sur le job cron.
2933
2976
  */
@@ -5621,6 +5664,29 @@ export interface CostumEventRequestLoadContextTagData {
5621
5664
  };
5622
5665
  [k: string]: unknown;
5623
5666
  }
5667
+ export interface AgendaGetPdfData {
5668
+ /**
5669
+ * ID de l'entité porteuse du costum
5670
+ */
5671
+ id: string;
5672
+ /**
5673
+ * Collection de l'entité porteuse
5674
+ */
5675
+ type: "organizations" | "projects" | "events" | "citoyens";
5676
+ /**
5677
+ * Slug du costum (réchauffe le cache costum legacy avant le rendu)
5678
+ */
5679
+ costum_slug: string;
5680
+ /**
5681
+ * Borne basse temporelle (interprétée par strtotime côté legacy, ex. 2026-10-01) : startDate >= cette date.
5682
+ */
5683
+ startDate?: string;
5684
+ /**
5685
+ * Tags séparés par des virgules. ⚠️ Passe par le filtre GET générique : sémantique OU (`$in`, insensible à la casse), pas ET — le filtre ET (`$all`) du legacy n'est lu que dans un corps JSON, absent en GET.
5686
+ */
5687
+ tags?: string;
5688
+ [k: string]: unknown;
5689
+ }
5624
5690
  export interface GetGalleryData {
5625
5691
  /**
5626
5692
  * Clé de contenu pour correspondre à l'album ou aux images
@@ -6137,20 +6203,20 @@ export interface GetCoformCommontableContributorsData {
6137
6203
  }
6138
6204
  export interface AddVoteData {
6139
6205
  /**
6140
- * ID de l'élément (commentaire ou news) sur lequel voter
6206
+ * ID de l'élément (commentaire, news ou réponse de formulaire) sur lequel voter
6141
6207
  */
6142
6208
  id: string;
6143
6209
  /**
6144
- * Type de collection concernée
6210
+ * Type de collection concernée. `answers` = réponse de formulaire coform (Action.php lit la collection sans liste blanche : seule l'action est restreinte).
6145
6211
  */
6146
- collection: "comments" | "news";
6212
+ collection: "comments" | "news" | "answers";
6147
6213
  /**
6148
6214
  * Type d'action à effectuer (vote)
6149
6215
  */
6150
6216
  action: "vote";
6151
6217
  details: {
6152
6218
  /**
6153
- * Statut du vote (ex: 'like', 'dislike', etc.)
6219
+ * Statut du vote (ex: 'like', 'dislike', etc.). Non vide : il devient un nom de champ (voteCount.<status>), un nom vide fait échouer l'écriture Mongo (legacy comme Node).
6154
6220
  */
6155
6221
  status: string;
6156
6222
  };
@@ -8057,3 +8123,89 @@ export interface DirectoryProposalNewCounterData {
8057
8123
  };
8058
8124
  [k: string]: unknown;
8059
8125
  }
8126
+ export interface CostumCreateAmpliData {
8127
+ /**
8128
+ * Origine de l'appel, matérialisée par AJV (useDefaults) : l'appelant n'a pas à la poser. Seules 'co' (interface Communecter) et 'site-json' sont acceptées serveur ; 'co' n'est PAS au contrat car elle génère les pages CMS du parcours Co.
8129
+ */
8130
+ source: "site-json";
8131
+ /**
8132
+ * Nom affiché. Le serveur en dérive la CLÉ de l'entrée (InflectorHelper::slugifyLikeJS : accents retirés, non-alphanumériques en tirets, minuscules). Un nom qui ne produit aucun slug exploitable ('' ou 'n-a') est refusé. ATTENTION : un slug déjà pris ÉCRASE l'entrée existante, aucune garde serveur.
8133
+ */
8134
+ name: string;
8135
+ /**
8136
+ * Markdown, stocké tel quel.
8137
+ */
8138
+ description?: string;
8139
+ /**
8140
+ * Sérialisé tags[]=a&tags[]=b, relu en tableau par PHP. Vides et doublons retirés côté serveur.
8141
+ */
8142
+ tags?: string[];
8143
+ /**
8144
+ * ObjectId de l'élément porteur du costum.
8145
+ */
8146
+ parentId: string;
8147
+ /**
8148
+ * Collection de l'élément porteur du costum.
8149
+ */
8150
+ parentType: "organizations" | "projects" | "citoyens" | "events";
8151
+ /**
8152
+ * Slug de l'élément porteur : préfixe des identifiants du formulaire généré en MODE A, et nom du parent du Form créé.
8153
+ */
8154
+ parentName: string;
8155
+ /**
8156
+ * Slug de l'élément porteur du costum. REQUIS pour le gate : isInterfaceAdmin() est appelé sans id ni type, il n'accepte qu'un super-admin ou un admin du costum RÉSOLU — et beforeAction → costumCacheParams() ne résout le costum que si $_POST[costumSlug] est présent. Sans lui, un admin de costum ordinaire reçoit « You don't have the right to access this feature ».
8157
+ */
8158
+ costumSlug: string;
8159
+ /**
8160
+ * MODE A : le serveur crée le Form et son sous-formulaire (titre, description, adresse, mots-clés, image) et renvoie les chemins obtenus. Exclusif de coform/*Path. Durci serveur par filter_var(FILTER_VALIDATE_BOOLEAN) : la chaîne 'false' du fil form-urlencoded est bien lue comme faux.
8161
+ */
8162
+ new?: boolean;
8163
+ /**
8164
+ * MODE B : ObjectId du Form existant à rattacher. Exige namePath et addressPath non vides.
8165
+ */
8166
+ coform?: string;
8167
+ /**
8168
+ * MODE B, requis : chemin <idSousFormulaire>.<idQuestion> (SANS le préfixe answers.) de la question titre.
8169
+ */
8170
+ namePath?: string;
8171
+ /**
8172
+ * MODE B : chemin de la question description.
8173
+ */
8174
+ descriptionPath?: string;
8175
+ /**
8176
+ * MODE B, requis : chemin de la question adresse.
8177
+ */
8178
+ addressPath?: string;
8179
+ /**
8180
+ * MODE B : chemin de la question mots-clés.
8181
+ */
8182
+ tagsPath?: string;
8183
+ /**
8184
+ * MODE B : chemin de la question image.
8185
+ */
8186
+ imagePath?: string;
8187
+ /**
8188
+ * MODE B : chemin du finder. Toujours '' en MODE A.
8189
+ */
8190
+ finderPath?: string;
8191
+ [k: string]: unknown;
8192
+ }
8193
+ export interface CostumRemoveAmpliData {
8194
+ /**
8195
+ * CLÉ de l'entrée dans costum.ampli, c'est-à-dire le slug renvoyé à la création (PAS un ObjectId).
8196
+ */
8197
+ ampliId: string;
8198
+ /**
8199
+ * ObjectId de l'élément porteur du costum.
8200
+ */
8201
+ parentId: string;
8202
+ /**
8203
+ * Collection de l'élément porteur du costum.
8204
+ */
8205
+ parentType: "organizations" | "projects" | "citoyens" | "events";
8206
+ /**
8207
+ * Slug de l'élément porteur. REQUIS, et pas décoratif : l'action appelle CacheHelper::getCostum($parentType, $parentId) alors que la signature est ($id, $type, $slug) — arguments inversés — et la résolution retombe en pratique sur $_POST[costumSlug]. L'interface Co l'envoie sans le savoir (ajaxPost l'injecte dans tout POST du module costum) ; un client externe doit le fournir explicitement. Inversion non corrigée : antérieure, et elle touche l'appelant Co.
8208
+ */
8209
+ costumSlug: string;
8210
+ [k: string]: unknown;
8211
+ }
@@ -9,7 +9,7 @@ export declare class Event extends BaseEntity<EventItemNormalized> {
9
9
  /** Bloc de création où injecter les champs costum (CostumScope). */
10
10
  static COSTUM_ADD_CONSTANT: string;
11
11
  static SCHEMA_CONSTANTS: string[];
12
- static ADD_BLOCKS: Map<"PROFIL_IMAGE" | "ADD_EVENT", "updateImageProfil" | "addEvent">;
12
+ static ADD_BLOCKS: Map<"ADD_EVENT" | "PROFIL_IMAGE", "addEvent" | "updateImageProfil">;
13
13
  static UPDATE_BLOCKS: Map<"UPDATE_BLOCK_SLUG" | "PROFIL_IMAGE", "updateImageProfil" | "updateSlug">;
14
14
  defaultFields: Record<string, any>;
15
15
  removeFields: string[];
@@ -95,8 +95,8 @@ export declare class Organization extends BaseEntity<OrganizationItemNormalized>
95
95
  readonly updateMethod: "updateVideo";
96
96
  readonly schemaConstant: "VIRTUAL_ORG_BASE_FIELDS";
97
97
  }>;
98
- static ADD_BLOCKS: Map<"UPDATE_BLOCK_SOCIAL" | "PROFIL_IMAGE" | "ADD_ORGANIZATION", "updateImageProfil" | "updateSocial" | "addOrganization">;
99
- static UPDATE_BLOCKS: Map<"UPDATE_BLOCK_DESCRIPTION" | "UPDATE_BLOCK_INFO" | "UPDATE_BLOCK_SOCIAL" | "UPDATE_BLOCK_LOCALITY" | "UPDATE_BLOCK_SLUG" | "PROFIL_IMAGE", "updateImageProfil" | "updateDescription" | "updateSocial" | "updateLocality" | "updateInfo" | "updateSlug">;
98
+ static ADD_BLOCKS: Map<"PROFIL_IMAGE" | "UPDATE_BLOCK_SOCIAL" | "ADD_ORGANIZATION", "updateImageProfil" | "updateSocial" | "addOrganization">;
99
+ static UPDATE_BLOCKS: Map<"UPDATE_BLOCK_SLUG" | "PROFIL_IMAGE" | "UPDATE_BLOCK_DESCRIPTION" | "UPDATE_BLOCK_INFO" | "UPDATE_BLOCK_LOCALITY" | "UPDATE_BLOCK_SOCIAL", "updateImageProfil" | "updateSlug" | "updateDescription" | "updateLocality" | "updateInfo" | "updateSocial">;
100
100
  defaultFields: Record<string, any>;
101
101
  removeFields: string[];
102
102
  transforms: Record<string, (val: any, full: any) => any>;
@@ -8,7 +8,7 @@ export declare class Poi extends BaseEntity<PoiItemNormalized> {
8
8
  static COSTUM_ADD_CONSTANT: string;
9
9
  static SCHEMA_CONSTANTS: string[];
10
10
  static ADD_BLOCKS: Map<"PROFIL_IMAGE" | "ADD_POI", "updateImageProfil" | "addPoi">;
11
- static UPDATE_BLOCKS: Map<"UPDATE_BLOCK_DESCRIPTION" | "UPDATE_BLOCK_INFO" | "UPDATE_BLOCK_LOCALITY" | "UPDATE_BLOCK_SLUG" | "PROFIL_IMAGE", "updateImageProfil" | "updateDescription" | "updateLocality" | "updateInfo" | "updateSlug">;
11
+ static UPDATE_BLOCKS: Map<"UPDATE_BLOCK_SLUG" | "PROFIL_IMAGE" | "UPDATE_BLOCK_DESCRIPTION" | "UPDATE_BLOCK_INFO" | "UPDATE_BLOCK_LOCALITY", "updateImageProfil" | "updateSlug" | "updateDescription" | "updateLocality" | "updateInfo">;
12
12
  defaultFields: Record<string, any>;
13
13
  removeFields: string[];
14
14
  transforms: Record<string, (val: any, full?: any) => any>;
@@ -12,8 +12,8 @@ export declare class Project extends BaseEntity<ProjectItemNormalized> {
12
12
  /** Bloc de création où injecter les champs costum (CostumScope). */
13
13
  static COSTUM_ADD_CONSTANT: string;
14
14
  static SCHEMA_CONSTANTS: string[];
15
- static ADD_BLOCKS: Map<"PROFIL_IMAGE" | "ADD_PROJECT", "addProject" | "updateImageProfil">;
16
- static UPDATE_BLOCKS: Map<"UPDATE_BLOCK_DESCRIPTION" | "UPDATE_BLOCK_INFO" | "UPDATE_BLOCK_SOCIAL" | "UPDATE_BLOCK_LOCALITY" | "UPDATE_BLOCK_SLUG" | "PROFIL_IMAGE", "updateImageProfil" | "updateDescription" | "updateSocial" | "updateLocality" | "updateInfo" | "updateSlug">;
15
+ static ADD_BLOCKS: Map<"PROFIL_IMAGE" | "ADD_PROJECT", "updateImageProfil" | "addProject">;
16
+ static UPDATE_BLOCKS: Map<"UPDATE_BLOCK_SLUG" | "PROFIL_IMAGE" | "UPDATE_BLOCK_DESCRIPTION" | "UPDATE_BLOCK_INFO" | "UPDATE_BLOCK_LOCALITY" | "UPDATE_BLOCK_SOCIAL", "updateImageProfil" | "updateSlug" | "updateDescription" | "updateLocality" | "updateInfo" | "updateSocial">;
17
17
  defaultFields: Record<string, any>;
18
18
  removeFields: string[];
19
19
  transforms: ProjectTransforms;
@@ -14,7 +14,7 @@ export declare class User extends BaseEntity<UserItemNormalized> {
14
14
  static entityType: "citoyens";
15
15
  static entityTag: string;
16
16
  static SCHEMA_CONSTANTS: string[];
17
- static UPDATE_BLOCKS: Map<"UPDATE_BLOCK_DESCRIPTION" | "UPDATE_BLOCK_INFO" | "UPDATE_BLOCK_SOCIAL" | "UPDATE_BLOCK_LOCALITY" | "UPDATE_BLOCK_SLUG" | "PROFIL_IMAGE", "updateImageProfil" | "updateDescription" | "updateSocial" | "updateLocality" | "updateInfo" | "updateSlug">;
17
+ static UPDATE_BLOCKS: Map<"UPDATE_BLOCK_SLUG" | "PROFIL_IMAGE" | "UPDATE_BLOCK_DESCRIPTION" | "UPDATE_BLOCK_INFO" | "UPDATE_BLOCK_LOCALITY" | "UPDATE_BLOCK_SOCIAL", "updateImageProfil" | "updateSlug" | "updateDescription" | "updateLocality" | "updateInfo" | "updateSocial">;
18
18
  defaultFields: Record<string, any>;
19
19
  removeFields: string[];
20
20
  transforms: Record<string, (val: any, full: any) => any>;
@@ -742,6 +742,9 @@ export declare class User extends BaseEntity<UserItemNormalized> {
742
742
  *
743
743
  * @param {Object} [options] - Options de la méthode
744
744
  * @param {boolean} [options.admin=false] - Si true, utilise "admin" comme connectType au lieu du type par défaut (connectTypeConnect)
745
+ * @param {string[]} [options.roles] - Rôles à poser sur le lien CRÉÉ (transmis à `CONNECT`, écrits des deux
746
+ * côtés). Omis ou vide → corps inchangé. Ne sert qu'à la création : pour corriger les rôles d'un lien
747
+ * déjà établi, utiliser {@link User.setRoles}.
745
748
  * @returns {Promise<unknown>} La réponse de l'API après création de la demande
746
749
  * @throws {ApiError} Si l'utilisateur n'est pas connecté, pas admin, ou si le parent n'est pas défini
747
750
  * @throws {ApiError} Si l'utilisateur est déjà en attente de validation
@@ -757,10 +760,14 @@ export declare class User extends BaseEntity<UserItemNormalized> {
757
760
  *
758
761
  * // Avec le type admin explicite
759
762
  * await user.sendRequestToJoinParent({ admin: true });
763
+ *
764
+ * // Avec des rôles posés dès l'invitation
765
+ * await user.sendRequestToJoinParent({ roles: ["Coordonnatrice parentalité Arrageois"] });
760
766
  * ```
761
767
  */
762
- sendRequestToJoinParent({ admin }?: {
763
- admin: boolean;
768
+ sendRequestToJoinParent({ admin, roles }?: {
769
+ admin?: boolean;
770
+ roles?: string[];
764
771
  }): Promise<unknown>;
765
772
  /**
766
773
  * Valide une demande de membre en attente de validation.
@@ -845,6 +852,35 @@ export declare class User extends BaseEntity<UserItemNormalized> {
845
852
  * ```
846
853
  */
847
854
  promoteToAdmin(): Promise<unknown>;
855
+ /**
856
+ * Définit les rôles de cet utilisateur sur son lien avec l'entité parente (`LINK_SET_ROLES`).
857
+ *
858
+ * ⚠️ REMPLACEMENT INTÉGRAL, pas un ajout/retrait : le tableau envoyé devient la liste des rôles du lien,
859
+ * des deux côtés (contexte et citoyen). Pour ajouter un rôle, envoyer les rôles actuels + le nouveau ;
860
+ * pour en retirer un, les rôles actuels privés de celui-ci. **`setRoles([])` efface TOUS les rôles**
861
+ * (`$unset` côté backend).
862
+ *
863
+ * Réservé aux admins de l'entité parente (organisation, projet ou événement). Le lien doit exister.
864
+ * Le backend répond HTTP 200 avec `{result:false}` en cas de refus : l'erreur est levée en `ApiResponseError`.
865
+ * Le contexte costum du PARENT est transmis (droit d'admin du costum, comme les autres actions de lien).
866
+ *
867
+ * @param roles - Liste COMPLÈTE des rôles voulus (vide = tout effacer).
868
+ * @returns La réponse de l'API (`{result, msg, memberOfid, memberid, roles}`).
869
+ * @throws {ApiError} Si le parent n'est pas défini, si l'appelant n'en est pas admin, ou si l'utilisateur
870
+ * n'a aucun lien avec le parent.
871
+ * @throws {ApiResponseError} Si le backend refuse (ex. non admin côté serveur).
872
+ *
873
+ * @example
874
+ * ```typescript
875
+ * const org = await me.organization({ slug: "parent62" });
876
+ * const { results } = await org.getMembers();
877
+ * const membre = results[0];
878
+ * // Source fiable des rôles actuels : le lien côté ORGANISATION (links.members.<id>.roles).
879
+ * const actuels = org.serverData.links?.members?.[membre.id!]?.roles ?? [];
880
+ * await membre.setRoles([...actuels, "Coordonnatrice parentalité Arrageois"]);
881
+ * ```
882
+ */
883
+ setRoles(roles: string[]): Promise<unknown>;
848
884
  /**
849
885
  * Rétrograde un admin au statut de membre ordinaire.
850
886
  *