boondmanager-mcp-server 2.6.2 → 2.7.1
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/README.md +115 -4
- package/dist/schemas/index.d.ts +30 -4
- package/dist/schemas/index.d.ts.map +1 -1
- package/dist/schemas/index.js +90 -17
- package/dist/schemas/index.js.map +1 -1
- package/dist/services/boond-client.d.ts +8 -0
- package/dist/services/boond-client.d.ts.map +1 -1
- package/dist/services/boond-client.js +15 -14
- package/dist/services/boond-client.js.map +1 -1
- package/dist/services/logger.d.ts +8 -0
- package/dist/services/logger.d.ts.map +1 -1
- package/dist/services/logger.js +26 -1
- package/dist/services/logger.js.map +1 -1
- package/dist/tools/accounts.d.ts.map +1 -1
- package/dist/tools/accounts.js +9 -37
- package/dist/tools/accounts.js.map +1 -1
- package/dist/tools/actions.d.ts.map +1 -1
- package/dist/tools/actions.js +56 -2
- package/dist/tools/actions.js.map +1 -1
- package/dist/tools/agencies.d.ts.map +1 -1
- package/dist/tools/agencies.js +9 -37
- package/dist/tools/agencies.js.map +1 -1
- package/dist/tools/business-units.d.ts.map +1 -1
- package/dist/tools/business-units.js +9 -37
- package/dist/tools/business-units.js.map +1 -1
- package/dist/tools/calendars.d.ts.map +1 -1
- package/dist/tools/calendars.js +9 -37
- package/dist/tools/calendars.js.map +1 -1
- package/dist/tools/candidates.d.ts.map +1 -1
- package/dist/tools/candidates.js +4 -1
- package/dist/tools/candidates.js.map +1 -1
- package/dist/tools/companies.d.ts.map +1 -1
- package/dist/tools/companies.js +4 -1
- package/dist/tools/companies.js.map +1 -1
- package/dist/tools/contacts.d.ts.map +1 -1
- package/dist/tools/contacts.js +4 -1
- package/dist/tools/contacts.js.map +1 -1
- package/dist/tools/crud-factory.d.ts +33 -3
- package/dist/tools/crud-factory.d.ts.map +1 -1
- package/dist/tools/crud-factory.js +39 -18
- package/dist/tools/crud-factory.js.map +1 -1
- package/dist/tools/expenses.d.ts.map +1 -1
- package/dist/tools/expenses.js +25 -100
- package/dist/tools/expenses.js.map +1 -1
- package/dist/tools/flags.d.ts.map +1 -1
- package/dist/tools/flags.js +9 -37
- package/dist/tools/flags.js.map +1 -1
- package/dist/tools/invoices.d.ts.map +1 -1
- package/dist/tools/invoices.js +30 -79
- package/dist/tools/invoices.js.map +1 -1
- package/dist/tools/logs.d.ts.map +1 -1
- package/dist/tools/logs.js +9 -33
- package/dist/tools/logs.js.map +1 -1
- package/dist/tools/opportunities.d.ts.map +1 -1
- package/dist/tools/opportunities.js +28 -20
- package/dist/tools/opportunities.js.map +1 -1
- package/dist/tools/orders.d.ts.map +1 -1
- package/dist/tools/orders.js +26 -94
- package/dist/tools/orders.js.map +1 -1
- package/dist/tools/poles.d.ts.map +1 -1
- package/dist/tools/poles.js +9 -37
- package/dist/tools/poles.js.map +1 -1
- package/dist/tools/products.d.ts.map +1 -1
- package/dist/tools/products.js +4 -1
- package/dist/tools/products.js.map +1 -1
- package/dist/tools/projects.d.ts.map +1 -1
- package/dist/tools/projects.js +4 -1
- package/dist/tools/projects.js.map +1 -1
- package/dist/tools/resources.d.ts.map +1 -1
- package/dist/tools/resources.js +4 -1
- package/dist/tools/resources.js.map +1 -1
- package/dist/tools/roles.d.ts.map +1 -1
- package/dist/tools/roles.js +9 -37
- package/dist/tools/roles.js.map +1 -1
- package/dist/tools/threads.d.ts.map +1 -1
- package/dist/tools/threads.js +9 -37
- package/dist/tools/threads.js.map +1 -1
- package/dist/tools/todolists.d.ts.map +1 -1
- package/dist/tools/todolists.js +9 -37
- package/dist/tools/todolists.js.map +1 -1
- package/dist/tools/webhooks.d.ts.map +1 -1
- package/dist/tools/webhooks.js +9 -37
- package/dist/tools/webhooks.js.map +1 -1
- package/dist/transports/http.d.ts.map +1 -1
- package/dist/transports/http.js +18 -9
- package/dist/transports/http.js.map +1 -1
- package/manifest.json +2 -2
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -11,9 +11,21 @@
|
|
|
11
11
|
[](https://github.com/fauguste/boondmanager-mcp-server/pkgs/container/boondmanager-mcp-server)
|
|
12
12
|
[](https://opensource.org/licenses/Apache-2.0)
|
|
13
13
|
|
|
14
|
+
**Installation 1-clic :**
|
|
15
|
+
|
|
16
|
+
[](https://cursor.com/install-mcp?name=boondmanager&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsImJvb25kbWFuYWdlci1tY3Atc2VydmVyIl19)
|
|
17
|
+
[](https://insiders.vscode.dev/redirect/mcp/install?name=boondmanager&config=%7B%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22boondmanager-mcp-server%22%5D%7D)
|
|
18
|
+
[](https://insiders.vscode.dev/redirect/mcp/install?name=boondmanager&config=%7B%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22boondmanager-mcp-server%22%5D%7D&quality=insiders)
|
|
19
|
+
|
|
20
|
+
<a href="https://glama.ai/mcp/servers/fauguste/boondmanager-mcp-server"><img src="https://glama.ai/mcp/servers/fauguste/boondmanager-mcp-server/badge" alt="Glama" width="180" /></a>
|
|
21
|
+
|
|
22
|
+
> **LM Studio**, **Goose** et **Gemini CLI** s'installent via leur procédure dédiée (deeplink natif ou commande) — voir la section [Installation](#installation). GitHub ne rend pas cliquables les liens à schéma non-HTTP (`lmstudio://`, `goose://`), c'est pourquoi ils n'ont pas de bouton 1-clic ici.
|
|
23
|
+
|
|
14
24
|
Serveur MCP (Model Context Protocol) pour l'API BoondManager, permettant a Claude (Desktop, Cowork, Code) de rechercher, consulter, creer et modifier des enregistrements dans votre instance BoondManager.
|
|
15
25
|
|
|
16
|
-
**
|
|
26
|
+
**176 outils** couvrant **38 domaines** de l'API BoondManager. Voir [TOOLS.md](./TOOLS.md) pour le catalogue auto-généré (outils + prompts + ressources).
|
|
27
|
+
|
|
28
|
+
> **Sorties structurées.** En plus du texte lisible, les outils `search`, `create`, `update` et `delete` renvoient un `structuredContent` conforme à un `outputSchema` MCP : `search` → `{ total?, count, items[] }` (résumés compacts, pas les ressources JSON:API complètes), `create`/`update` → `{ id?, type? }`, `delete` → `{ id, deleted, reason? }`. Les clients MCP qui exploitent les sorties structurées obtiennent une référence d'entité fiable pour chaîner les appels. Les outils `get` restent en texte seul (leur texte est déjà du JSON exploitable).
|
|
17
29
|
|
|
18
30
|
## Domaines couverts
|
|
19
31
|
|
|
@@ -61,7 +73,7 @@ Serveur MCP (Model Context Protocol) pour l'API BoondManager, permettant a Claud
|
|
|
61
73
|
|
|
62
74
|
| Domaine | Outils | Operations |
|
|
63
75
|
|---------|--------|------------|
|
|
64
|
-
| **Actions** |
|
|
76
|
+
| **Actions** | 5 | search, get, create, update, delete |
|
|
65
77
|
| **Validations** | 2 | search, get |
|
|
66
78
|
| **Todolists** | 2 | search, get |
|
|
67
79
|
|
|
@@ -357,6 +369,85 @@ Le serveur est listé sur le [marketplace MCP de LobeHub](https://lobehub.com/mc
|
|
|
357
369
|
|
|
358
370
|
Ou utiliser le transport HTTP (voir section [Transports](#transports)) pour un deploiement partage en mode gateway.
|
|
359
371
|
|
|
372
|
+
### Cursor
|
|
373
|
+
|
|
374
|
+
Cliquez sur le badge **[Add to Cursor](https://cursor.com/install-mcp?name=boondmanager&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsImJvb25kbWFuYWdlci1tY3Atc2VydmVyIl19)** en haut du README (ou ajoutez le serveur manuellement dans **Settings > MCP > Add new MCP server**). Renseignez ensuite l'authentification en ajoutant un bloc `env` au serveur dans `~/.cursor/mcp.json` :
|
|
375
|
+
|
|
376
|
+
```json
|
|
377
|
+
{
|
|
378
|
+
"mcpServers": {
|
|
379
|
+
"boondmanager": {
|
|
380
|
+
"command": "npx",
|
|
381
|
+
"args": ["-y", "boondmanager-mcp-server"],
|
|
382
|
+
"env": {
|
|
383
|
+
"BOOND_API_TOKEN": "votre_token_jwt"
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
### VS Code (GitHub Copilot / agent MCP)
|
|
391
|
+
|
|
392
|
+
Cliquez sur le badge **[Install in VS Code](https://insiders.vscode.dev/redirect/mcp/install?name=boondmanager&config=%7B%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22boondmanager-mcp-server%22%5D%7D)** en haut du README, ou ajoutez le serveur a `.vscode/mcp.json` (par projet) ou a votre `settings.json` utilisateur :
|
|
393
|
+
|
|
394
|
+
```json
|
|
395
|
+
{
|
|
396
|
+
"servers": {
|
|
397
|
+
"boondmanager": {
|
|
398
|
+
"type": "stdio",
|
|
399
|
+
"command": "npx",
|
|
400
|
+
"args": ["-y", "boondmanager-mcp-server"],
|
|
401
|
+
"env": {
|
|
402
|
+
"BOOND_API_TOKEN": "${input:boond_api_token}"
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
### LM Studio
|
|
410
|
+
|
|
411
|
+
Dans LM Studio : **Program > Install > Edit `mcp.json`** et ajoutez :
|
|
412
|
+
|
|
413
|
+
```json
|
|
414
|
+
{
|
|
415
|
+
"mcpServers": {
|
|
416
|
+
"boondmanager": {
|
|
417
|
+
"command": "npx",
|
|
418
|
+
"args": ["-y", "boondmanager-mcp-server"],
|
|
419
|
+
"env": {
|
|
420
|
+
"BOOND_API_TOKEN": "votre_token_jwt"
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
```
|
|
426
|
+
|
|
427
|
+
### Goose
|
|
428
|
+
|
|
429
|
+
Ajoutez une extension de type **STDIO** dans **Settings > Extensions > Add** avec la commande `npx -y boondmanager-mcp-server` et la variable d'environnement `BOOND_API_TOKEN`. En CLI :
|
|
430
|
+
|
|
431
|
+
```bash
|
|
432
|
+
goose session --with-extension "npx -y boondmanager-mcp-server"
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
### Gemini CLI
|
|
436
|
+
|
|
437
|
+
Le depot embarque un manifeste d'extension Gemini CLI (`gemini-extension.json`). Installez l'extension directement depuis GitHub :
|
|
438
|
+
|
|
439
|
+
```bash
|
|
440
|
+
gemini extensions install https://github.com/fauguste/boondmanager-mcp-server
|
|
441
|
+
```
|
|
442
|
+
|
|
443
|
+
Definissez ensuite l'authentification dans votre environnement (Gemini interpole `${VAR}` au demarrage) :
|
|
444
|
+
|
|
445
|
+
```bash
|
|
446
|
+
export BOOND_API_TOKEN="votre_token_jwt"
|
|
447
|
+
# ou le trio JWT auto :
|
|
448
|
+
export BOOND_USER_TOKEN="..." BOOND_CLIENT_TOKEN="..." BOOND_CLIENT_KEY="..."
|
|
449
|
+
```
|
|
450
|
+
|
|
360
451
|
## Configuration
|
|
361
452
|
|
|
362
453
|
### Logs
|
|
@@ -424,6 +515,14 @@ Pour eviter qu'une boucle d'outils emballee n'inonde l'API (et n'enchaine les `4
|
|
|
424
515
|
| `BOOND_HTTP_RATE_LIMIT_RPS` | `10` | Debit soutenu (requetes/seconde). `0` desactive completement. |
|
|
425
516
|
| `BOOND_HTTP_RATE_LIMIT_BURST` | `20` | Capacite du bucket = taille maximale de rafale immediate. |
|
|
426
517
|
|
|
518
|
+
### Cache du dictionnaire
|
|
519
|
+
|
|
520
|
+
L'API BoondManager n'expose qu'un seul endpoint `/application/dictionary` qui renvoie l'intégralité des libellés (états, types, pays…). Le serveur le met en cache en mémoire pour éviter de le re-télécharger à chaque résolution état/type → libellé.
|
|
521
|
+
|
|
522
|
+
| Variable | Defaut | Description |
|
|
523
|
+
|----------|--------|-------------|
|
|
524
|
+
| `BOOND_DICTIONARY_TTL_MS` | `3600000` (1 h) | Durée de vie du cache du dictionnaire, en millisecondes. Une valeur non numérique ou ≤ 0 retombe sur le défaut. |
|
|
525
|
+
|
|
427
526
|
### Restriction d'accès (domaines / lecture seule)
|
|
428
527
|
|
|
429
528
|
Vous pouvez restreindre **ce que l'IA voit et peut faire**, entièrement par
|
|
@@ -593,6 +692,18 @@ docker compose logs -f mcp
|
|
|
593
692
|
|
|
594
693
|
> **Securite** : le serveur HTTP est stateless et ne stocke aucun secret BoondManager. Chaque utilisateur authentifie le serveur via son propre token OAuth2 (issu de sa propre App BoondManager), et toutes les actions sont attribuees a son identite dans l'audit log Boond. Derriere un reverse proxy : terminez TLS (HTTPS), forwardez l'en-tete `Authorization`, et reglez `MCP_HTTP_PUBLIC_URL` sur l'URL publique pour que la discovery soit coherente.
|
|
595
694
|
|
|
695
|
+
### Clients distants non-Claude (ChatGPT, OpenAI / Gemini Agents SDK)
|
|
696
|
+
|
|
697
|
+
MCP est un protocole **agnostique du modele** : le meme endpoint HTTP/OAuth2 est consomme tel quel par tout hote compatible MCP, pas seulement Claude. **Aucun package ni build specifique a un LLM n'est requis** — il suffit de pointer l'hote sur votre URL `MCP_HTTP_PUBLIC_URL`.
|
|
698
|
+
|
|
699
|
+
| Hote | Comment brancher le serveur |
|
|
700
|
+
|------|-----------------------------|
|
|
701
|
+
| **ChatGPT (connecteurs / Developer mode)** | Ajouter un connecteur MCP distant pointant sur l'URL HTTP ; l'OAuth2 est decouvert via la metadata `/.well-known/oauth-protected-resource`. |
|
|
702
|
+
| **OpenAI Agents SDK** | Declarer un `HostedMCPTool` / serveur MCP distant avec l'URL HTTP et le flux OAuth2. |
|
|
703
|
+
| **Google Gemini (Agents SDK / Vertex)** | Enregistrer le serveur MCP distant cote SDK ; en local, l'extension Gemini CLI (voir [Installation](#gemini-cli)) couvre le transport stdio. |
|
|
704
|
+
|
|
705
|
+
Le contrat est identique a celui de Claude Code en HTTP (voir l'exemple `claude mcp add --transport http` ci-dessus) : seule la maniere de declarer le serveur cote client change.
|
|
706
|
+
|
|
596
707
|
## Exemples d'utilisation
|
|
597
708
|
|
|
598
709
|
Une fois configure, vous pouvez demander a Claude :
|
|
@@ -659,7 +770,7 @@ boondmanager-mcp-server/
|
|
|
659
770
|
│ ├── companies.ts # 14 outils (CRUD + 9 onglets)
|
|
660
771
|
│ ├── opportunities.ts # 10 outils (CRUD + 5 onglets)
|
|
661
772
|
│ ├── projects.ts # 12 outils (CRUD + 7 onglets)
|
|
662
|
-
│ ├── actions.ts #
|
|
773
|
+
│ ├── actions.ts # 5 outils
|
|
663
774
|
│ ├── timesheets.ts # 3 outils
|
|
664
775
|
│ ├── invoices.ts # 5 outils
|
|
665
776
|
│ ├── orders.ts # 5 outils
|
|
@@ -702,7 +813,7 @@ boondmanager-mcp-server/
|
|
|
702
813
|
|
|
703
814
|
- Les credentials BoondManager (JWT ou BasicAuth) ne transitent jamais via le protocole MCP -- ils sont configures en variables d'environnement cote serveur uniquement
|
|
704
815
|
- En mode **stdio**, le serveur tourne en local, aucun port reseau n'est expose
|
|
705
|
-
- En mode **streamable HTTP**,
|
|
816
|
+
- En mode **streamable HTTP**, l'authentification est un **OAuth2 protected resource** : chaque requete MCP porte son propre `Authorization: Bearer <token>` (le serveur ne stocke aucun secret). Terminez TLS (HTTPS via reverse proxy), forwardez l'en-tete `Authorization`, reglez `MCP_HTTP_PUBLIC_URL` sur l'URL publique, et activez la protection anti DNS rebinding via `MCP_HTTP_ALLOWED_HOSTS`. Restreignez aussi l'acces reseau a votre gateway. Voir [docs/oauth.md](docs/oauth.md).
|
|
706
817
|
- Compatible avec les exigences ISO 27001
|
|
707
818
|
- L'API BoondManager est hebergee en France et conforme RGPD
|
|
708
819
|
- Authentification BoondManager : JWT (recommande), BasicAuth, ou JWT construit automatiquement a partir des composants
|
package/dist/schemas/index.d.ts
CHANGED
|
@@ -136,9 +136,9 @@ export declare const CandidateSearchSchema: z.ZodObject<{
|
|
|
136
136
|
export declare const ContactSearchSchema: z.ZodObject<{
|
|
137
137
|
keywords: z.ZodOptional<z.ZodString>;
|
|
138
138
|
keywordsType: z.ZodOptional<z.ZodEnum<{
|
|
139
|
-
default: "default";
|
|
140
139
|
firstName: "firstName";
|
|
141
140
|
lastName: "lastName";
|
|
141
|
+
default: "default";
|
|
142
142
|
fullName: "fullName";
|
|
143
143
|
strictFullName: "strictFullName";
|
|
144
144
|
emails: "emails";
|
|
@@ -474,21 +474,39 @@ export declare const CompanyUpdateSchema: z.ZodObject<{
|
|
|
474
474
|
note: z.ZodOptional<z.ZodString>;
|
|
475
475
|
}, z.core.$strict>;
|
|
476
476
|
export declare const OpportunityCreateSchema: z.ZodObject<{
|
|
477
|
-
|
|
477
|
+
typeOf: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
|
|
478
478
|
companyId: z.ZodOptional<z.ZodString>;
|
|
479
479
|
contactId: z.ZodOptional<z.ZodString>;
|
|
480
480
|
state: z.ZodOptional<z.ZodPreprocess<z.ZodCoercedNumber<unknown>>>;
|
|
481
481
|
startDate: z.ZodOptional<z.ZodString>;
|
|
482
482
|
endDate: z.ZodOptional<z.ZodString>;
|
|
483
483
|
note: z.ZodOptional<z.ZodString>;
|
|
484
|
+
criteria: z.ZodOptional<z.ZodString>;
|
|
485
|
+
expertiseArea: z.ZodOptional<z.ZodString>;
|
|
486
|
+
turnoverEstimatedExcludingTax: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
|
|
487
|
+
poleId: z.ZodOptional<z.ZodString>;
|
|
488
|
+
hrManagerId: z.ZodOptional<z.ZodString>;
|
|
489
|
+
mainManagerId: z.ZodOptional<z.ZodString>;
|
|
490
|
+
agencyId: z.ZodOptional<z.ZodString>;
|
|
491
|
+
name: z.ZodString;
|
|
484
492
|
}, z.core.$strict>;
|
|
485
493
|
export declare const OpportunityUpdateSchema: z.ZodObject<{
|
|
486
|
-
|
|
487
|
-
|
|
494
|
+
typeOf: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
|
|
495
|
+
companyId: z.ZodOptional<z.ZodString>;
|
|
496
|
+
contactId: z.ZodOptional<z.ZodString>;
|
|
488
497
|
state: z.ZodOptional<z.ZodPreprocess<z.ZodCoercedNumber<unknown>>>;
|
|
489
498
|
startDate: z.ZodOptional<z.ZodString>;
|
|
490
499
|
endDate: z.ZodOptional<z.ZodString>;
|
|
491
500
|
note: z.ZodOptional<z.ZodString>;
|
|
501
|
+
criteria: z.ZodOptional<z.ZodString>;
|
|
502
|
+
expertiseArea: z.ZodOptional<z.ZodString>;
|
|
503
|
+
turnoverEstimatedExcludingTax: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
|
|
504
|
+
poleId: z.ZodOptional<z.ZodString>;
|
|
505
|
+
hrManagerId: z.ZodOptional<z.ZodString>;
|
|
506
|
+
mainManagerId: z.ZodOptional<z.ZodString>;
|
|
507
|
+
agencyId: z.ZodOptional<z.ZodString>;
|
|
508
|
+
id: z.ZodString;
|
|
509
|
+
name: z.ZodOptional<z.ZodString>;
|
|
492
510
|
}, z.core.$strict>;
|
|
493
511
|
export declare const ActionSearchSchema: z.ZodObject<{
|
|
494
512
|
keywords: z.ZodOptional<z.ZodString>;
|
|
@@ -513,6 +531,14 @@ export declare const ActionCreateSchema: z.ZodObject<{
|
|
|
513
531
|
companyId: z.ZodOptional<z.ZodString>;
|
|
514
532
|
positioningId: z.ZodOptional<z.ZodString>;
|
|
515
533
|
}, z.core.$strict>;
|
|
534
|
+
export declare const ActionUpdateSchema: z.ZodObject<{
|
|
535
|
+
id: z.ZodString;
|
|
536
|
+
typeOf: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
|
|
537
|
+
title: z.ZodOptional<z.ZodString>;
|
|
538
|
+
text: z.ZodOptional<z.ZodString>;
|
|
539
|
+
startDate: z.ZodOptional<z.ZodString>;
|
|
540
|
+
endDate: z.ZodOptional<z.ZodString>;
|
|
541
|
+
}, z.core.$strict>;
|
|
516
542
|
export declare const ResourceTimesheetSchema: z.ZodObject<{
|
|
517
543
|
resourceId: z.ZodString;
|
|
518
544
|
month: z.ZodOptional<z.ZodNumber>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/schemas/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB,eAAO,MAAM,YAAY;;;;kBAkBd,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/schemas/index.ts"],"names":[],"mappings":"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"}
|
package/dist/schemas/index.js
CHANGED
|
@@ -49,6 +49,19 @@ const fieldsField = z
|
|
|
49
49
|
"(ex: ['title', 'updateDate', 'numberOfActiveProjects']). Réduit fortement la taille de la réponse. " +
|
|
50
50
|
"Absent = résumé standard (nom, email, ville, statut...). Les noms inconnus sont ignorés.");
|
|
51
51
|
const strArray = (doc) => z.array(z.string()).optional().describe(doc);
|
|
52
|
+
// Shared `tools` (technologies/skills) filter. Centralised so every entity
|
|
53
|
+
// search exposes the same `#AND#` semantics to the model — previously the
|
|
54
|
+
// description ranged from the full explanation (resources) to a bare
|
|
55
|
+
// "IDs d'outils." (opportunities), so the model only learned about `#AND#`
|
|
56
|
+
// on some endpoints.
|
|
57
|
+
const toolsFilterField = strArray("IDs d'outils/technos (dictionnaire setting.tool). Logique OU par défaut. " +
|
|
58
|
+
"Pour ET, ajouter '#AND#' en 1er élément: tools=['#AND#','12','34'].");
|
|
59
|
+
// Action timestamps: ISO 8601 with timezone, e.g. 2026-06-05T10:00:00+0200.
|
|
60
|
+
// Accepts the colon-less (+0200) and colon (+02:00) offset styles, an optional
|
|
61
|
+
// fractional-seconds part, and a trailing Z. The timezone is optional so the
|
|
62
|
+
// API can apply the account default. Surfaces a malformed value at the schema
|
|
63
|
+
// boundary instead of as an opaque 422.
|
|
64
|
+
const actionDateTimeRegex = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?([+-]\d{2}:?\d{2}|Z)?$/;
|
|
52
65
|
// Shared "perimeter" filters available on every entity search (from RAML trait `searchable`).
|
|
53
66
|
// These are the CORRECT filters for "my team / my agency / my N-1" — NOT the old `mainManagers`.
|
|
54
67
|
const perimeterManagersField = intArray("IDs des managers (ressources). Conserve les entités dont le responsable est l'un de ces managers. " +
|
|
@@ -115,8 +128,7 @@ export const ResourceSearchSchema = z
|
|
|
115
128
|
excludeResourceTypes: intArray("IDs de types de ressource à EXCLURE."),
|
|
116
129
|
activityAreas: strArray("IDs de secteurs d'activité (dictionnaire setting.activityArea)."),
|
|
117
130
|
expertiseAreas: strArray("IDs de domaines d'expertise (dictionnaire setting.expertiseArea)."),
|
|
118
|
-
tools:
|
|
119
|
-
"Pour ET, ajouter '#AND#' en 1er élément: tools=['#AND#','12','34']."),
|
|
131
|
+
tools: toolsFilterField,
|
|
120
132
|
experiences: intArray("IDs de niveaux d'expérience (dictionnaire setting.experience)."),
|
|
121
133
|
trainings: strArray("IDs de formations (dictionnaire setting.training)."),
|
|
122
134
|
mobilityAreas: strArray("IDs de zones de mobilité (dictionnaire setting.mobilityArea)."),
|
|
@@ -201,7 +213,7 @@ export const CandidateSearchSchema = z
|
|
|
201
213
|
availabilityTypes: intArray("IDs de types de disponibilité (dictionnaire setting.availability)."),
|
|
202
214
|
activityAreas: strArray("IDs de secteurs d'activité (dictionnaire setting.activityArea)."),
|
|
203
215
|
expertiseAreas: strArray("IDs de domaines d'expertise."),
|
|
204
|
-
tools:
|
|
216
|
+
tools: toolsFilterField,
|
|
205
217
|
experiences: intArray("IDs de niveaux d'expérience."),
|
|
206
218
|
trainings: strArray("IDs de formations."),
|
|
207
219
|
mobilityAreas: strArray("IDs de zones de mobilité."),
|
|
@@ -268,7 +280,7 @@ export const ContactSearchSchema = z
|
|
|
268
280
|
origins: strArray("IDs d'origines (dictionnaire setting.origin)."),
|
|
269
281
|
activityAreas: strArray("IDs de secteurs d'activité de la société."),
|
|
270
282
|
expertiseAreas: strArray("IDs de domaines d'expertise de la société."),
|
|
271
|
-
tools:
|
|
283
|
+
tools: toolsFilterField,
|
|
272
284
|
influencers: intArray("IDs de contacts influenceurs."),
|
|
273
285
|
flags: intArray("IDs de tags."),
|
|
274
286
|
period: z
|
|
@@ -357,7 +369,7 @@ export const OpportunitySearchSchema = z
|
|
|
357
369
|
positioningStates: strArray("IDs d'états de positionnement, ou 'none' pour les opportunités sans positionnement."),
|
|
358
370
|
expertiseAreas: strArray("IDs de domaines d'expertise."),
|
|
359
371
|
activityAreas: strArray("IDs de secteurs d'activité."),
|
|
360
|
-
tools:
|
|
372
|
+
tools: toolsFilterField,
|
|
361
373
|
places: strArray("IDs de zones (dictionnaire setting.mobilityArea)."),
|
|
362
374
|
durations: intArray("IDs de durées (dictionnaire setting.duration)."),
|
|
363
375
|
origins: strArray("IDs d'origines."),
|
|
@@ -696,25 +708,61 @@ export const CompanyUpdateSchema = z
|
|
|
696
708
|
})
|
|
697
709
|
.strict();
|
|
698
710
|
// ---- Opportunity schemas ----
|
|
711
|
+
// Writable fields shared by create and update. The attribute/relationship
|
|
712
|
+
// names mirror the official RAML (schemas/opportunities/information.json):
|
|
713
|
+
// - `note` → /data/attributes/description (the API has no `note` attribute,
|
|
714
|
+
// so the old direct pass-through was silently dropped — see issue #124)
|
|
715
|
+
// - `typeOf`, `criteria`, `expertiseArea`, `turnoverEstimatedExcludingTax`
|
|
716
|
+
// are plain attributes
|
|
717
|
+
// - `companyId`/`contactId`/`poleId`/`hrManagerId`/`mainManagerId`/`agencyId`
|
|
718
|
+
// become JSON:API relationships (resource types: company, contact, pole,
|
|
719
|
+
// resource, resource, agency)
|
|
720
|
+
const opportunityWritableShape = {
|
|
721
|
+
typeOf: z.coerce
|
|
722
|
+
.number()
|
|
723
|
+
.int()
|
|
724
|
+
.min(1)
|
|
725
|
+
.optional()
|
|
726
|
+
.describe("Type d'opportunité : ID numérique du dictionnaire setting.typeOf.project (ex: 1, 3), via boond_application_dictionary"),
|
|
727
|
+
companyId: z.string().optional().describe("ID de la société cliente (relation company)"),
|
|
728
|
+
contactId: z.string().optional().describe("ID du contact associé (relation contact)"),
|
|
729
|
+
state: stateField("opportunity", "État de l'opportunité"),
|
|
730
|
+
startDate: z.string().optional().describe("Date de début prévue (YYYY-MM-DD ou 'immediate')"),
|
|
731
|
+
endDate: z.string().optional().describe("Date de fin prévue (YYYY-MM-DD)"),
|
|
732
|
+
note: z
|
|
733
|
+
.string()
|
|
734
|
+
.max(65000)
|
|
735
|
+
.optional()
|
|
736
|
+
.describe("Description de l'opportunité (mappée sur /data/attributes/description)"),
|
|
737
|
+
criteria: z
|
|
738
|
+
.string()
|
|
739
|
+
.max(5000)
|
|
740
|
+
.optional()
|
|
741
|
+
.describe("Critères / compétences recherchées (texte libre). Alimente le matching de boond_workflow_candidats_pour_opportunite."),
|
|
742
|
+
expertiseArea: z
|
|
743
|
+
.string()
|
|
744
|
+
.optional()
|
|
745
|
+
.describe("Domaine d'expertise : ID du dictionnaire setting.expertiseArea (via boond_application_dictionary)"),
|
|
746
|
+
turnoverEstimatedExcludingTax: z.coerce.number().optional().describe("Chiffre d'affaires estimé HT (montant)"),
|
|
747
|
+
poleId: z.string().optional().describe("ID du pôle (relation pole)"),
|
|
748
|
+
hrManagerId: z.string().optional().describe("ID de la ressource responsable RH (relation hrManager)"),
|
|
749
|
+
mainManagerId: z
|
|
750
|
+
.string()
|
|
751
|
+
.optional()
|
|
752
|
+
.describe("ID de la ressource responsable principal / commercial (relation mainManager)"),
|
|
753
|
+
agencyId: z.string().optional().describe("ID de l'agence (relation agency)"),
|
|
754
|
+
};
|
|
699
755
|
export const OpportunityCreateSchema = z
|
|
700
756
|
.object({
|
|
701
757
|
name: z.string().min(1).describe("Nom / titre de l'opportunité"),
|
|
702
|
-
|
|
703
|
-
contactId: z.string().optional().describe("ID du contact associé"),
|
|
704
|
-
state: stateField("opportunity", "État de l'opportunité"),
|
|
705
|
-
startDate: z.string().optional().describe("Date de début prévue (YYYY-MM-DD)"),
|
|
706
|
-
endDate: z.string().optional().describe("Date de fin prévue (YYYY-MM-DD)"),
|
|
707
|
-
note: z.string().optional().describe("Notes / description"),
|
|
758
|
+
...opportunityWritableShape,
|
|
708
759
|
})
|
|
709
760
|
.strict();
|
|
710
761
|
export const OpportunityUpdateSchema = z
|
|
711
762
|
.object({
|
|
712
763
|
id: z.string().min(1).describe("ID de l'opportunité à modifier"),
|
|
713
764
|
name: z.string().optional().describe("Nom / titre"),
|
|
714
|
-
|
|
715
|
-
startDate: z.string().optional().describe("Date de début (YYYY-MM-DD)"),
|
|
716
|
-
endDate: z.string().optional().describe("Date de fin (YYYY-MM-DD)"),
|
|
717
|
-
note: z.string().optional().describe("Notes"),
|
|
765
|
+
...opportunityWritableShape,
|
|
718
766
|
})
|
|
719
767
|
.strict();
|
|
720
768
|
// ---- Action schemas ----
|
|
@@ -743,9 +791,10 @@ export const ActionCreateSchema = z
|
|
|
743
791
|
text: z.string().optional().describe("Contenu / notes de l'action"),
|
|
744
792
|
startDate: z
|
|
745
793
|
.string()
|
|
794
|
+
.regex(actionDateTimeRegex)
|
|
746
795
|
.optional()
|
|
747
|
-
.describe("Date de début au format ISO avec timezone (ex: 2026-06-05T10:00:00+0200)"),
|
|
748
|
-
endDate: z.string().optional().describe("Date de fin (même format que startDate)"),
|
|
796
|
+
.describe("Date de début au format ISO 8601 avec timezone (ex: 2026-06-05T10:00:00+0200)"),
|
|
797
|
+
endDate: z.string().regex(actionDateTimeRegex).optional().describe("Date de fin (même format que startDate)"),
|
|
749
798
|
candidateId: z.string().optional().describe("ID du candidat auquel rattacher l'action (dependsOn)"),
|
|
750
799
|
resourceId: z.string().optional().describe("ID de la ressource à laquelle rattacher l'action (dependsOn)"),
|
|
751
800
|
contactId: z.string().optional().describe("ID du contact auquel rattacher l'action (dependsOn)"),
|
|
@@ -758,6 +807,30 @@ export const ActionCreateSchema = z
|
|
|
758
807
|
.describe("ID du positionnement à lier à l'action (relation positioning). Requis par l'API pour les types d'action liés aux positionnements (ex. RQ) — sans lui, erreur 422 « 1002 - Wrong or missing attribute (/data/relationships/positioning) »."),
|
|
759
808
|
})
|
|
760
809
|
.strict();
|
|
810
|
+
// PUT /actions/{id} (PATCH renvoie 405). Mise à jour partielle des seuls
|
|
811
|
+
// attributs : aucune relation n'est envoyée, ce qui préserve le rattachement
|
|
812
|
+
// `dependsOn`/`positioning` et la synchronisation calendrier (event Outlook /
|
|
813
|
+
// Teams). `typeOf` accepte uniquement l'ID numérique du dictionnaire ici (pas
|
|
814
|
+
// de résolution de libellé, faute d'entité `dependsOn` connue sur l'update).
|
|
815
|
+
export const ActionUpdateSchema = z
|
|
816
|
+
.object({
|
|
817
|
+
id: z.string().min(1).describe("ID de l'action à modifier"),
|
|
818
|
+
typeOf: z.coerce
|
|
819
|
+
.number()
|
|
820
|
+
.int()
|
|
821
|
+
.min(0)
|
|
822
|
+
.optional()
|
|
823
|
+
.describe("Nouveau type : ID numérique du dictionnaire setting.action.* (via boond_application_dictionary)"),
|
|
824
|
+
title: z.string().optional().describe("Nouveau titre de l'action"),
|
|
825
|
+
text: z.string().optional().describe("Nouveau contenu / notes (HTML accepté). Remplace l'existant (pas d'ajout)."),
|
|
826
|
+
startDate: z
|
|
827
|
+
.string()
|
|
828
|
+
.regex(actionDateTimeRegex)
|
|
829
|
+
.optional()
|
|
830
|
+
.describe("Date de début au format ISO 8601 avec timezone (ex: 2026-06-05T10:00:00+0200)"),
|
|
831
|
+
endDate: z.string().regex(actionDateTimeRegex).optional().describe("Date de fin (même format que startDate)"),
|
|
832
|
+
})
|
|
833
|
+
.strict();
|
|
761
834
|
// ---- Timesheet schemas ----
|
|
762
835
|
export const ResourceTimesheetSchema = z
|
|
763
836
|
.object({
|