boondmanager-mcp-server 2.15.2 → 2.17.0

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.
Files changed (272) hide show
  1. package/LICENSE +1 -1
  2. package/NOTICE +16 -2
  3. package/README.md +60 -15
  4. package/dist/config/access-policy.d.ts.map +1 -1
  5. package/dist/config/access-policy.js +6 -18
  6. package/dist/config/access-policy.js.map +1 -1
  7. package/dist/config/dictionary-overrides.d.ts.map +1 -1
  8. package/dist/config/dictionary-overrides.js +2 -12
  9. package/dist/config/dictionary-overrides.js.map +1 -1
  10. package/dist/config/env.d.ts +63 -0
  11. package/dist/config/env.d.ts.map +1 -0
  12. package/dist/config/env.js +116 -0
  13. package/dist/config/env.js.map +1 -0
  14. package/dist/config/profiles.d.ts +22 -8
  15. package/dist/config/profiles.d.ts.map +1 -1
  16. package/dist/config/profiles.js +48 -4
  17. package/dist/config/profiles.js.map +1 -1
  18. package/dist/constants.d.ts +13 -2
  19. package/dist/constants.d.ts.map +1 -1
  20. package/dist/constants.js +25 -1
  21. package/dist/constants.js.map +1 -1
  22. package/dist/icons.d.ts.map +1 -1
  23. package/dist/icons.js +6 -1
  24. package/dist/icons.js.map +1 -1
  25. package/dist/index.js +33 -15
  26. package/dist/index.js.map +1 -1
  27. package/dist/instructions.d.ts +1 -1
  28. package/dist/instructions.d.ts.map +1 -1
  29. package/dist/instructions.js +6 -6
  30. package/dist/instructions.js.map +1 -1
  31. package/dist/prompts/index.d.ts +19 -1
  32. package/dist/prompts/index.d.ts.map +1 -1
  33. package/dist/prompts/index.js +495 -25
  34. package/dist/prompts/index.js.map +1 -1
  35. package/dist/prompts/periods.d.ts +45 -0
  36. package/dist/prompts/periods.d.ts.map +1 -0
  37. package/dist/prompts/periods.js +154 -0
  38. package/dist/prompts/periods.js.map +1 -0
  39. package/dist/resources/index.d.ts +14 -0
  40. package/dist/resources/index.d.ts.map +1 -1
  41. package/dist/resources/index.js +285 -0
  42. package/dist/resources/index.js.map +1 -1
  43. package/dist/resources/templates.d.ts +1 -1
  44. package/dist/resources/templates.d.ts.map +1 -1
  45. package/dist/resources/templates.js +2 -0
  46. package/dist/resources/templates.js.map +1 -1
  47. package/dist/schema-dialect.js.map +1 -1
  48. package/dist/schemas/filter-aliases.d.ts +1 -1
  49. package/dist/schemas/filter-aliases.d.ts.map +1 -1
  50. package/dist/schemas/filter-aliases.js +101 -2
  51. package/dist/schemas/filter-aliases.js.map +1 -1
  52. package/dist/schemas/index.d.ts +987 -161
  53. package/dist/schemas/index.d.ts.map +1 -1
  54. package/dist/schemas/index.js +853 -323
  55. package/dist/schemas/index.js.map +1 -1
  56. package/dist/server.d.ts.map +1 -1
  57. package/dist/server.js +10 -3
  58. package/dist/server.js.map +1 -1
  59. package/dist/services/boond-client.d.ts +29 -213
  60. package/dist/services/boond-client.d.ts.map +1 -1
  61. package/dist/services/boond-client.js +29 -1168
  62. package/dist/services/boond-client.js.map +1 -1
  63. package/dist/services/dictionary.d.ts +27 -3
  64. package/dist/services/dictionary.d.ts.map +1 -1
  65. package/dist/services/dictionary.js +60 -23
  66. package/dist/services/dictionary.js.map +1 -1
  67. package/dist/services/document-text.d.ts +32 -0
  68. package/dist/services/document-text.d.ts.map +1 -0
  69. package/dist/services/document-text.js +120 -0
  70. package/dist/services/document-text.js.map +1 -0
  71. package/dist/services/format/detail.d.ts +16 -0
  72. package/dist/services/format/detail.d.ts.map +1 -0
  73. package/dist/services/format/detail.js +36 -0
  74. package/dist/services/format/detail.js.map +1 -0
  75. package/dist/services/format/html.d.ts +19 -0
  76. package/dist/services/format/html.d.ts.map +1 -0
  77. package/dist/services/format/html.js +87 -0
  78. package/dist/services/format/html.js.map +1 -0
  79. package/dist/services/format/list.d.ts +3 -0
  80. package/dist/services/format/list.d.ts.map +1 -0
  81. package/dist/services/format/list.js +44 -0
  82. package/dist/services/format/list.js.map +1 -0
  83. package/dist/services/format/summary.d.ts +16 -0
  84. package/dist/services/format/summary.d.ts.map +1 -0
  85. package/dist/services/format/summary.js +172 -0
  86. package/dist/services/format/summary.js.map +1 -0
  87. package/dist/services/format/tab.d.ts +9 -0
  88. package/dist/services/format/tab.d.ts.map +1 -0
  89. package/dist/services/format/tab.js +32 -0
  90. package/dist/services/format/tab.js.map +1 -0
  91. package/dist/services/http/auth.d.ts +44 -0
  92. package/dist/services/http/auth.d.ts.map +1 -0
  93. package/dist/services/http/auth.js +146 -0
  94. package/dist/services/http/auth.js.map +1 -0
  95. package/dist/services/http/download.d.ts +60 -0
  96. package/dist/services/http/download.d.ts.map +1 -0
  97. package/dist/services/http/download.js +160 -0
  98. package/dist/services/http/download.js.map +1 -0
  99. package/dist/services/http/errors.d.ts +45 -0
  100. package/dist/services/http/errors.d.ts.map +1 -0
  101. package/dist/services/http/errors.js +188 -0
  102. package/dist/services/http/errors.js.map +1 -0
  103. package/dist/services/http/rate-limit.d.ts +40 -0
  104. package/dist/services/http/rate-limit.d.ts.map +1 -0
  105. package/dist/services/http/rate-limit.js +92 -0
  106. package/dist/services/http/rate-limit.js.map +1 -0
  107. package/dist/services/http/retry.d.ts +46 -0
  108. package/dist/services/http/retry.d.ts.map +1 -0
  109. package/dist/services/http/retry.js +101 -0
  110. package/dist/services/http/retry.js.map +1 -0
  111. package/dist/services/http/transport.d.ts +73 -0
  112. package/dist/services/http/transport.d.ts.map +1 -0
  113. package/dist/services/http/transport.js +272 -0
  114. package/dist/services/http/transport.js.map +1 -0
  115. package/dist/services/logger.d.ts +53 -2
  116. package/dist/services/logger.d.ts.map +1 -1
  117. package/dist/services/logger.js +82 -21
  118. package/dist/services/logger.js.map +1 -1
  119. package/dist/services/oauth.d.ts +12 -0
  120. package/dist/services/oauth.d.ts.map +1 -1
  121. package/dist/services/oauth.js +21 -8
  122. package/dist/services/oauth.js.map +1 -1
  123. package/dist/services/rate-limiter.d.ts +9 -2
  124. package/dist/services/rate-limiter.d.ts.map +1 -1
  125. package/dist/services/rate-limiter.js +18 -6
  126. package/dist/services/rate-limiter.js.map +1 -1
  127. package/dist/services/request-context.d.ts +47 -0
  128. package/dist/services/request-context.d.ts.map +1 -0
  129. package/dist/services/request-context.js +112 -0
  130. package/dist/services/request-context.js.map +1 -0
  131. package/dist/services/search.d.ts +26 -0
  132. package/dist/services/search.d.ts.map +1 -0
  133. package/dist/services/search.js +98 -0
  134. package/dist/services/search.js.map +1 -0
  135. package/dist/services/update-checker.d.ts.map +1 -1
  136. package/dist/services/update-checker.js +15 -8
  137. package/dist/services/update-checker.js.map +1 -1
  138. package/dist/tools/absences.d.ts +9 -0
  139. package/dist/tools/absences.d.ts.map +1 -1
  140. package/dist/tools/absences.js +65 -20
  141. package/dist/tools/absences.js.map +1 -1
  142. package/dist/tools/actions.d.ts.map +1 -1
  143. package/dist/tools/actions.js +11 -27
  144. package/dist/tools/actions.js.map +1 -1
  145. package/dist/tools/advantages.d.ts +2 -0
  146. package/dist/tools/advantages.d.ts.map +1 -1
  147. package/dist/tools/advantages.js +66 -13
  148. package/dist/tools/advantages.js.map +1 -1
  149. package/dist/tools/alerts.d.ts +18 -0
  150. package/dist/tools/alerts.d.ts.map +1 -0
  151. package/dist/tools/alerts.js +82 -0
  152. package/dist/tools/alerts.js.map +1 -0
  153. package/dist/tools/application.d.ts +2 -1
  154. package/dist/tools/application.d.ts.map +1 -1
  155. package/dist/tools/application.js +9 -3
  156. package/dist/tools/application.js.map +1 -1
  157. package/dist/tools/contacts.d.ts.map +1 -1
  158. package/dist/tools/contacts.js +3 -7
  159. package/dist/tools/contacts.js.map +1 -1
  160. package/dist/tools/contracts.d.ts +22 -0
  161. package/dist/tools/contracts.d.ts.map +1 -1
  162. package/dist/tools/contracts.js +185 -52
  163. package/dist/tools/contracts.js.map +1 -1
  164. package/dist/tools/crud-factory.d.ts +33 -2
  165. package/dist/tools/crud-factory.d.ts.map +1 -1
  166. package/dist/tools/crud-factory.js +42 -15
  167. package/dist/tools/crud-factory.js.map +1 -1
  168. package/dist/tools/deliveries.d.ts +3 -0
  169. package/dist/tools/deliveries.d.ts.map +1 -1
  170. package/dist/tools/deliveries.js +50 -94
  171. package/dist/tools/deliveries.js.map +1 -1
  172. package/dist/tools/description-builders.d.ts +0 -1
  173. package/dist/tools/description-builders.d.ts.map +1 -1
  174. package/dist/tools/description-builders.js +46 -3
  175. package/dist/tools/description-builders.js.map +1 -1
  176. package/dist/tools/documents.d.ts.map +1 -1
  177. package/dist/tools/documents.js +73 -21
  178. package/dist/tools/documents.js.map +1 -1
  179. package/dist/tools/expenses.d.ts.map +1 -1
  180. package/dist/tools/expenses.js +2 -11
  181. package/dist/tools/expenses.js.map +1 -1
  182. package/dist/tools/find.d.ts +61 -0
  183. package/dist/tools/find.d.ts.map +1 -0
  184. package/dist/tools/find.js +221 -0
  185. package/dist/tools/find.js.map +1 -0
  186. package/dist/tools/flags.d.ts +5 -0
  187. package/dist/tools/flags.d.ts.map +1 -1
  188. package/dist/tools/flags.js +116 -1
  189. package/dist/tools/flags.js.map +1 -1
  190. package/dist/tools/forms.d.ts +5 -0
  191. package/dist/tools/forms.d.ts.map +1 -0
  192. package/dist/tools/forms.js +64 -0
  193. package/dist/tools/forms.js.map +1 -0
  194. package/dist/tools/groupments.d.ts +5 -0
  195. package/dist/tools/groupments.d.ts.map +1 -0
  196. package/dist/tools/groupments.js +68 -0
  197. package/dist/tools/groupments.js.map +1 -0
  198. package/dist/tools/inactivities.d.ts +5 -0
  199. package/dist/tools/inactivities.d.ts.map +1 -0
  200. package/dist/tools/inactivities.js +59 -0
  201. package/dist/tools/inactivities.js.map +1 -0
  202. package/dist/tools/index.d.ts +4 -0
  203. package/dist/tools/index.d.ts.map +1 -1
  204. package/dist/tools/index.js +4 -0
  205. package/dist/tools/index.js.map +1 -1
  206. package/dist/tools/invoices.d.ts.map +1 -1
  207. package/dist/tools/invoices.js +27 -2
  208. package/dist/tools/invoices.js.map +1 -1
  209. package/dist/tools/linked-entity-filters.d.ts +48 -0
  210. package/dist/tools/linked-entity-filters.d.ts.map +1 -0
  211. package/dist/tools/linked-entity-filters.js +64 -0
  212. package/dist/tools/linked-entity-filters.js.map +1 -0
  213. package/dist/tools/notifications.d.ts.map +1 -1
  214. package/dist/tools/notifications.js +0 -5
  215. package/dist/tools/notifications.js.map +1 -1
  216. package/dist/tools/orders.d.ts.map +1 -1
  217. package/dist/tools/orders.js +33 -4
  218. package/dist/tools/orders.js.map +1 -1
  219. package/dist/tools/parameter-disclosure.js.map +1 -1
  220. package/dist/tools/payments.d.ts +3 -0
  221. package/dist/tools/payments.d.ts.map +1 -1
  222. package/dist/tools/payments.js +43 -109
  223. package/dist/tools/payments.js.map +1 -1
  224. package/dist/tools/positionings.d.ts.map +1 -1
  225. package/dist/tools/positionings.js +9 -39
  226. package/dist/tools/positionings.js.map +1 -1
  227. package/dist/tools/projects.d.ts.map +1 -1
  228. package/dist/tools/projects.js +5 -12
  229. package/dist/tools/projects.js.map +1 -1
  230. package/dist/tools/provider-invoices.d.ts +2 -0
  231. package/dist/tools/provider-invoices.d.ts.map +1 -1
  232. package/dist/tools/provider-invoices.js +30 -111
  233. package/dist/tools/provider-invoices.js.map +1 -1
  234. package/dist/tools/purchases.d.ts +2 -0
  235. package/dist/tools/purchases.d.ts.map +1 -1
  236. package/dist/tools/purchases.js +50 -104
  237. package/dist/tools/purchases.js.map +1 -1
  238. package/dist/tools/registration-decorators.d.ts +28 -0
  239. package/dist/tools/registration-decorators.d.ts.map +1 -1
  240. package/dist/tools/registration-decorators.js +107 -0
  241. package/dist/tools/registration-decorators.js.map +1 -1
  242. package/dist/tools/resources.d.ts.map +1 -1
  243. package/dist/tools/resources.js +27 -5
  244. package/dist/tools/resources.js.map +1 -1
  245. package/dist/tools/rights.d.ts +101 -0
  246. package/dist/tools/rights.d.ts.map +1 -0
  247. package/dist/tools/rights.js +75 -0
  248. package/dist/tools/rights.js.map +1 -0
  249. package/dist/tools/tab-tools.js +3 -3
  250. package/dist/tools/tab-tools.js.map +1 -1
  251. package/dist/tools/timesheets.d.ts +29 -0
  252. package/dist/tools/timesheets.d.ts.map +1 -1
  253. package/dist/tools/timesheets.js +196 -126
  254. package/dist/tools/timesheets.js.map +1 -1
  255. package/dist/tools/todolists.d.ts +2 -0
  256. package/dist/tools/todolists.d.ts.map +1 -1
  257. package/dist/tools/todolists.js +64 -1
  258. package/dist/tools/todolists.js.map +1 -1
  259. package/dist/tools/validations.d.ts +9 -0
  260. package/dist/tools/validations.d.ts.map +1 -1
  261. package/dist/tools/validations.js +86 -9
  262. package/dist/tools/validations.js.map +1 -1
  263. package/dist/tools/workflows.js +1 -1
  264. package/dist/tools/workflows.js.map +1 -1
  265. package/dist/transports/http.d.ts +116 -0
  266. package/dist/transports/http.d.ts.map +1 -1
  267. package/dist/transports/http.js +422 -92
  268. package/dist/transports/http.js.map +1 -1
  269. package/dist/types.d.ts +3 -3
  270. package/dist/types.d.ts.map +1 -1
  271. package/manifest.json +7 -7
  272. package/package.json +14 -10
@@ -0,0 +1,3 @@
1
+ import type { JsonApiResource, JsonApiResponse } from "../../types.js";
2
+ export declare function formatListResponse(response: JsonApiResponse, entityType: string, fields?: string[], summaryFn?: (entity: JsonApiResource) => string): string;
3
+ //# sourceMappingURL=list.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list.d.ts","sourceRoot":"","sources":["../../../src/services/format/list.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAGvE,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,eAAe,EACzB,UAAU,EAAE,MAAM,EAClB,MAAM,CAAC,EAAE,MAAM,EAAE,EACjB,SAAS,GAAE,CAAC,MAAM,EAAE,eAAe,KAAK,MAA4B,GACnE,MAAM,CAwCR"}
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Text rendering of a search page: one summary line per row, a `Total:`
3
+ * header when the API reports one, and truncation on line boundaries under
4
+ * `CHARACTER_LIMIT` (a mid-line cut used to hide the row count).
5
+ */
6
+ import { CHARACTER_LIMIT } from "../../constants.js";
7
+ import { formatEntitySummary, formatProjectedSummary } from "./summary.js";
8
+ export function formatListResponse(response, entityType, fields, summaryFn = formatEntitySummary) {
9
+ // `data: null` is what BoondManager answers on some empty windows
10
+ // (`/times-reports` on a month with no report, #243); it used to become
11
+ // `[null]` and crash the per-row summary.
12
+ const data = Array.isArray(response.data) ? response.data : response.data ? [response.data] : [];
13
+ const total = response.meta?.totals?.rows;
14
+ if (data.length === 0) {
15
+ return `Aucun(e) ${entityType} trouvé(e).`;
16
+ }
17
+ const projected = fields !== undefined && fields.length > 0;
18
+ const lines = data.map((item) => (projected ? formatProjectedSummary(item, fields) : summaryFn(item)));
19
+ const header = total !== undefined ? `Total: ${total} ${entityType}(s)\n\n` : "";
20
+ const body = lines.join("\n");
21
+ if (header.length + body.length <= CHARACTER_LIMIT)
22
+ return header + body;
23
+ // Cut on line boundaries and say how many rows were dropped. A mid-line cut
24
+ // produced a half-row indistinguishable from a complete one, and the count
25
+ // is what tells the model to narrow the query (or use `fields`/`pageSize`)
26
+ // instead of trusting an implicitly complete page.
27
+ const notice = (shown) => `\n\n[Résultats tronqués : ${shown}/${lines.length} ligne(s) affichée(s) (limite de ${CHARACTER_LIMIT} caractères). ` +
28
+ `Affinez les filtres, réduisez pageSize, ou utilisez 'fields' pour raccourcir chaque ligne.]`;
29
+ const budget = CHARACTER_LIMIT - header.length - notice(lines.length).length;
30
+ const kept = [];
31
+ let used = 0;
32
+ for (const line of lines) {
33
+ const cost = kept.length === 0 ? line.length : line.length + 1;
34
+ if (used + cost > budget)
35
+ break;
36
+ used += cost;
37
+ kept.push(line);
38
+ }
39
+ // A single row longer than the whole budget still has to show something.
40
+ if (kept.length === 0)
41
+ return header + body.substring(0, Math.max(budget, 0)) + notice(0);
42
+ return header + kept.join("\n") + notice(kept.length);
43
+ }
44
+ //# sourceMappingURL=list.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list.js","sourceRoot":"","sources":["../../../src/services/format/list.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAErD,OAAO,EAAE,mBAAmB,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAC;AAE3E,MAAM,UAAU,kBAAkB,CAChC,QAAyB,EACzB,UAAkB,EAClB,MAAiB,EACjB,YAAiD,mBAAmB;IAEpE,kEAAkE;IAClE,wEAAwE;IACxE,0CAA0C;IAC1C,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACjG,MAAM,KAAK,GAAG,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC;IAE1C,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACtB,OAAO,YAAY,UAAU,aAAa,CAAC;IAC7C,CAAC;IAED,MAAM,SAAS,GAAG,MAAM,KAAK,SAAS,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC;IAC5D,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,sBAAsB,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACvG,MAAM,MAAM,GAAG,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,UAAU,KAAK,IAAI,UAAU,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC;IACjF,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAE9B,IAAI,MAAM,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,eAAe;QAAE,OAAO,MAAM,GAAG,IAAI,CAAC;IAEzE,4EAA4E;IAC5E,2EAA2E;IAC3E,2EAA2E;IAC3E,mDAAmD;IACnD,MAAM,MAAM,GAAG,CAAC,KAAa,EAAE,EAAE,CAC/B,6BAA6B,KAAK,IAAI,KAAK,CAAC,MAAM,oCAAoC,eAAe,gBAAgB;QACrH,6FAA6F,CAAC;IAChG,MAAM,MAAM,GAAG,eAAe,GAAG,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC;IAE7E,MAAM,IAAI,GAAa,EAAE,CAAC;IAC1B,IAAI,IAAI,GAAG,CAAC,CAAC;IACb,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC;QAC/D,IAAI,IAAI,GAAG,IAAI,GAAG,MAAM;YAAE,MAAM;QAChC,IAAI,IAAI,IAAI,CAAC;QACb,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAClB,CAAC;IAED,yEAAyE;IACzE,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;IAE1F,OAAO,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AACxD,CAAC"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Single rendering rule for a raw JSON:API attribute value, shared by the
3
+ * fallback summary and the `fields` projection — some Boond amounts come back
4
+ * as `{ amount, currency }` objects, and the two paths used to disagree
5
+ * (`[object Object]` on one side, JSON on the other).
6
+ */
7
+ export declare function renderAttributeValue(value: unknown): string;
8
+ export declare function formatEntitySummary(entity: unknown): string;
9
+ /**
10
+ * One result line restricted to the caller-selected attribute names.
11
+ * Unknown names are skipped silently (the schemas document this), so a typo
12
+ * degrades to a shorter line rather than an error. Non-primitive values are
13
+ * JSON-serialised — some Boond attributes are nested objects.
14
+ */
15
+ export declare function formatProjectedSummary(entity: unknown, fields: string[]): string;
16
+ //# sourceMappingURL=summary.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"summary.d.ts","sourceRoot":"","sources":["../../../src/services/format/summary.ts"],"names":[],"mappings":"AAgCA;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAE3D;AAyDD,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,CAqD3D;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,CAchF"}
@@ -0,0 +1,172 @@
1
+ /**
2
+ * One-line summaries of a JSON:API row for list output: the standard summary
3
+ * (`formatEntitySummary`, with its business-identifier fallback) and the
4
+ * `fields` projection. The named-row output is pinned byte-for-byte in tests.
5
+ */
6
+ import { textExcerpt } from "./html.js";
7
+ /**
8
+ * Business identifiers used as a last resort when a list row has no
9
+ * human-readable identity (no name, no title, no dictionary `value`).
10
+ *
11
+ * Transactional endpoints (`/invoices`, `/orders`, `/actions`,
12
+ * `/deliveries-groupments`, `/projects`…) key their rows on a reference, a
13
+ * number or a date rather than on a name, so the standard summary rendered
14
+ * them as a bare `[order #1234] | Statut: 1` — a line the model cannot act on
15
+ * without a follow-up `_get` per row.
16
+ *
17
+ * These are deliberately NOT appended unconditionally: `/resources` and
18
+ * `/opportunities` also carry `reference` and amount attributes, and their
19
+ * rows already read well (name, title). Enriching them too would only inflate
20
+ * every line. See `hasIdentity` in formatEntitySummary.
21
+ */
22
+ const AMOUNT_FALLBACK_FIELDS = [
23
+ ["turnoverInvoicedExcludingTax", "CA facturé HT"],
24
+ ["turnoverOrderedExcludingTax", "CA commandé HT"],
25
+ ["turnoverSimulatedExcludingTax", "CA simulé HT"],
26
+ ["averageDailyPriceExcludingTax", "TJM HT"],
27
+ ];
28
+ /** Max amount entries appended to a fallback line, to keep it scannable. */
29
+ const MAX_FALLBACK_AMOUNTS = 2;
30
+ /**
31
+ * Single rendering rule for a raw JSON:API attribute value, shared by the
32
+ * fallback summary and the `fields` projection — some Boond amounts come back
33
+ * as `{ amount, currency }` objects, and the two paths used to disagree
34
+ * (`[object Object]` on one side, JSON on the other).
35
+ */
36
+ export function renderAttributeValue(value) {
37
+ return value === null || typeof value === "object" ? JSON.stringify(value) : String(value);
38
+ }
39
+ /**
40
+ * A row is considered to name itself through `value` only when that value is a
41
+ * non-empty string once rendered. `value: null` / `value: ""` used to both
42
+ * print a bogus token *and* suppress the business-identifier fallback.
43
+ */
44
+ function hasValueIdentity(value) {
45
+ return value !== undefined && value !== null && renderAttributeValue(value) !== "";
46
+ }
47
+ /**
48
+ * Secondary identifiers for rows that have no name/title/value. Order is
49
+ * chosen so the most identifying token comes first (number, then reference,
50
+ * then when it happened, then how much).
51
+ */
52
+ function fallbackIdentityParts(attrs) {
53
+ const parts = [];
54
+ if (attrs.number)
55
+ parts.push(`N°: ${attrs.number}`);
56
+ if (attrs.reference)
57
+ parts.push(`Réf: ${attrs.reference}`);
58
+ if (attrs.date) {
59
+ parts.push(`Date: ${attrs.date}`);
60
+ }
61
+ else if (attrs.startDate && attrs.endDate) {
62
+ parts.push(`Du ${attrs.startDate} au ${attrs.endDate}`);
63
+ }
64
+ else if (attrs.startDate) {
65
+ parts.push(`Début: ${attrs.startDate}`);
66
+ }
67
+ else if (attrs.endDate) {
68
+ parts.push(`Fin: ${attrs.endDate}`);
69
+ }
70
+ let amounts = 0;
71
+ for (const [field, label] of AMOUNT_FALLBACK_FIELDS) {
72
+ if (amounts >= MAX_FALLBACK_AMOUNTS)
73
+ break;
74
+ const value = attrs[field];
75
+ // 0 is meaningful here (an order with no turnover yet), so only
76
+ // undefined/null are skipped.
77
+ if (value === undefined || value === null)
78
+ continue;
79
+ parts.push(`${label}: ${renderAttributeValue(value)}`);
80
+ amounts++;
81
+ }
82
+ // `typeOf` is an integer resolved through boond://dictionary/typeOf/* — on
83
+ // its own it is weak, but on an action it is often the only discriminator.
84
+ if (attrs.typeOf !== undefined && attrs.typeOf !== null)
85
+ parts.push(`Type: ${attrs.typeOf}`);
86
+ // End-user-authored free text: labelled and quoted so the model reads it as
87
+ // a data field of the row and not as server-authored instructions.
88
+ if (typeof attrs.text === "string") {
89
+ const excerpt = textExcerpt(attrs.text);
90
+ if (excerpt !== undefined)
91
+ parts.push(`Note: "${excerpt}"`);
92
+ }
93
+ return parts;
94
+ }
95
+ export function formatEntitySummary(entity) {
96
+ // A few BoondManager endpoints (e.g. `/calendars`, `/application/dictionary`)
97
+ // return reference items as flat objects without a JSON:API `attributes`
98
+ // wrapper. Treating the whole entity as the attribute bag in that case
99
+ // keeps `formatListResponse` from crashing on `attrs.firstName` and yields
100
+ // a still-useful summary.
101
+ const e = (entity ?? {});
102
+ const hasAttrs = e.attributes !== undefined && e.attributes !== null && typeof e.attributes === "object";
103
+ const attrs = hasAttrs ? e.attributes : e;
104
+ const id = e.id !== undefined ? String(e.id) : undefined;
105
+ const type = e.type !== undefined ? String(e.type) : undefined;
106
+ const header = id !== undefined && type !== undefined
107
+ ? `[${type} #${id}]`
108
+ : id !== undefined
109
+ ? `[#${id}]`
110
+ : type !== undefined
111
+ ? `[${type}]`
112
+ : "[item]";
113
+ const parts = [header];
114
+ // Common name fields
115
+ if (attrs.firstName || attrs.lastName) {
116
+ parts.push(`${attrs.firstName || ""} ${attrs.lastName || ""}`.trim());
117
+ }
118
+ if (attrs.name)
119
+ parts.push(String(attrs.name));
120
+ // `value` covers the `/calendars` and dictionary-style payloads. `0` is a
121
+ // legitimate label there, so only null/undefined/"" are skipped.
122
+ if (!attrs.firstName && !attrs.lastName && !attrs.name && hasValueIdentity(attrs.value)) {
123
+ parts.push(renderAttributeValue(attrs.value));
124
+ }
125
+ if (attrs.email1)
126
+ parts.push(`Email: ${attrs.email1}`);
127
+ if (attrs.phone1)
128
+ parts.push(`Tel: ${attrs.phone1}`);
129
+ if (attrs.city)
130
+ parts.push(`Ville: ${attrs.city}`);
131
+ if (attrs.state !== undefined)
132
+ parts.push(`Statut: ${attrs.state}`);
133
+ if (attrs.title)
134
+ parts.push(`Titre: ${attrs.title}`);
135
+ if (attrs.iso !== undefined && String(attrs.iso) !== id)
136
+ parts.push(`ISO: ${attrs.iso}`);
137
+ // Rows that named themselves are already useful — leave them untouched.
138
+ // Only the ones reduced to `[type #id]` (+ maybe a status integer) get the
139
+ // business identifiers appended.
140
+ const hasIdentity = Boolean(attrs.firstName) ||
141
+ Boolean(attrs.lastName) ||
142
+ Boolean(attrs.name) ||
143
+ Boolean(attrs.title) ||
144
+ hasValueIdentity(attrs.value);
145
+ if (!hasIdentity) {
146
+ parts.push(...fallbackIdentityParts(attrs));
147
+ }
148
+ return parts.join(" | ");
149
+ }
150
+ /**
151
+ * One result line restricted to the caller-selected attribute names.
152
+ * Unknown names are skipped silently (the schemas document this), so a typo
153
+ * degrades to a shorter line rather than an error. Non-primitive values are
154
+ * JSON-serialised — some Boond attributes are nested objects.
155
+ */
156
+ export function formatProjectedSummary(entity, fields) {
157
+ const e = (entity ?? {});
158
+ const attrs = (e.attributes ?? e);
159
+ // Reference endpoints return flat rows keyed on something else than `id`
160
+ // (`/calendars` keys countries on `iso`), so a missing id renders as the same
161
+ // `[item]` token the standard summary uses — not as a `[#?]` that reads like
162
+ // a formatting bug.
163
+ const parts = [e.id !== undefined ? `[#${String(e.id)}]` : "[item]"];
164
+ for (const field of fields) {
165
+ const value = attrs[field];
166
+ if (value === undefined)
167
+ continue;
168
+ parts.push(`${field}: ${renderAttributeValue(value)}`);
169
+ }
170
+ return parts.join(" | ");
171
+ }
172
+ //# sourceMappingURL=summary.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"summary.js","sourceRoot":"","sources":["../../../src/services/format/summary.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import type { JsonApiResponse } from "../../types.js";
2
+ /**
3
+ * Formate la réponse d'un endpoint d'onglet (ex: /resources/{id}/positionings).
4
+ * Contrairement à formatDetailResponse, un tableau est restitué en entier :
5
+ * certains onglets renvoient plusieurs entités (positionnements, contacts...)
6
+ * et n'afficher que la première masquait les autres.
7
+ */
8
+ export declare function formatTabResponse(response: JsonApiResponse): string;
9
+ //# sourceMappingURL=tab.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tab.d.ts","sourceRoot":"","sources":["../../../src/services/format/tab.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAGtD;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,eAAe,GAAG,MAAM,CA0BnE"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Rendering of an entity-tab endpoint (`/resources/{id}/positionings`…).
3
+ */
4
+ import { CHARACTER_LIMIT } from "../../constants.js";
5
+ import { formatDetailResponse, projectEntity } from "./detail.js";
6
+ /**
7
+ * Formate la réponse d'un endpoint d'onglet (ex: /resources/{id}/positionings).
8
+ * Contrairement à formatDetailResponse, un tableau est restitué en entier :
9
+ * certains onglets renvoient plusieurs entités (positionnements, contacts...)
10
+ * et n'afficher que la première masquait les autres.
11
+ */
12
+ export function formatTabResponse(response) {
13
+ if (!Array.isArray(response.data)) {
14
+ return formatDetailResponse(response);
15
+ }
16
+ const entities = response.data.map(projectEntity);
17
+ // Some tabs carry aggregates in `meta.totals` beyond the row count —
18
+ // `/orders/{id}/invoices` publishes the ordered / invoiced / remaining
19
+ // turnover there (issue #258). They are the point of reading that tab, so
20
+ // they are rendered ahead of the rows instead of being dropped.
21
+ const totals = response.meta?.totals;
22
+ const aggregates = totals && typeof totals === "object" ? Object.entries(totals).filter(([key]) => key !== "rows") : [];
23
+ const header = aggregates.length > 0
24
+ ? `${entities.length} élément(s) — totaux : ${JSON.stringify(Object.fromEntries(aggregates))}`
25
+ : `${entities.length} élément(s)`;
26
+ let result = `${header}\n\n` + JSON.stringify(entities, null, 2);
27
+ if (result.length > CHARACTER_LIMIT) {
28
+ result = result.substring(0, CHARACTER_LIMIT) + "\n\n[Résultat tronqué...]";
29
+ }
30
+ return result;
31
+ }
32
+ //# sourceMappingURL=tab.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tab.js","sourceRoot":"","sources":["../../../src/services/format/tab.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAErD,OAAO,EAAE,oBAAoB,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAElE;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB,CAAC,QAAyB;IACzD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QAClC,OAAO,oBAAoB,CAAC,QAAQ,CAAC,CAAC;IACxC,CAAC;IAED,MAAM,QAAQ,GAAG,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;IAElD,qEAAqE;IACrE,uEAAuE;IACvE,0EAA0E;IAC1E,gEAAgE;IAChE,MAAM,MAAM,GAAG,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACrC,MAAM,UAAU,GACd,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,GAAG,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACvG,MAAM,MAAM,GACV,UAAU,CAAC,MAAM,GAAG,CAAC;QACnB,CAAC,CAAC,GAAG,QAAQ,CAAC,MAAM,0BAA0B,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC,EAAE;QAC9F,CAAC,CAAC,GAAG,QAAQ,CAAC,MAAM,aAAa,CAAC;IAEtC,IAAI,MAAM,GAAG,GAAG,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IAEjE,IAAI,MAAM,CAAC,MAAM,GAAG,eAAe,EAAE,CAAC;QACpC,MAAM,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC,EAAE,eAAe,CAAC,GAAG,2BAA2B,CAAC;IAC9E,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,44 @@
1
+ import type { BoondAuthProvider, BoondConfig } from "../../types.js";
2
+ /**
3
+ * Auth provider for the HTTP transport: reads the Bearer token from the
4
+ * per-request AsyncLocalStorage populated by the transport layer and
5
+ * forwards it verbatim to BoondManager as `Authorization: Bearer …`.
6
+ *
7
+ * Errors out clearly if called outside a request context — which would
8
+ * indicate that the transport layer forgot to wrap the request in
9
+ * `oauthContext.run(...)`.
10
+ */
11
+ export declare const oauthContextAuth: BoondAuthProvider;
12
+ /**
13
+ * Build the BoondManager HS256 JWT. By default the payload is exactly
14
+ * `{ userToken, clientToken }` (BoondManager's documented scheme). When
15
+ * `expiresInSeconds` is provided, standard `iat`/`exp` claims are added so the
16
+ * generated token is no longer replayable forever if it leaks — this requires
17
+ * regenerating the token per request (see `jwtAuth`). Opt-in because not every
18
+ * BoondManager deployment is known to honour `exp`.
19
+ */
20
+ export declare function buildJwt(userToken: string, clientToken: string, clientKey: string, options?: {
21
+ expiresInSeconds?: number;
22
+ nowSeconds?: number;
23
+ }): string;
24
+ export declare const JWT_HEADER_NAME = "X-Jwt-Client-Boondmanager";
25
+ export declare function initClient(): void;
26
+ /**
27
+ * True when env-based credentials (JWT components, API token, or BasicAuth) are
28
+ * configured. Used by the HTTP transport in static-auth mode
29
+ * (`BOOND_HTTP_STATIC_AUTH=true`) to fail fast with a readable message before
30
+ * `initClient()` throws; the default HTTP mode is an OAuth2 protected resource
31
+ * and never reads these variables.
32
+ */
33
+ export declare function hasEnvCredentials(): boolean;
34
+ /**
35
+ * Install a custom auth provider — used by the HTTP transport bootstrap to
36
+ * wire in an OAuth2 token source (where the access token is refreshed
37
+ * transparently per request rather than baked in at startup).
38
+ */
39
+ export declare function initClientWithAuth(auth: BoondAuthProvider, baseUrl?: string): void;
40
+ /** Test helper — reset the cached config so the next call re-initialises. */
41
+ export declare function resetClientForTests(): void;
42
+ /** The active configuration, initialising from the environment on first use. */
43
+ export declare function getConfig(): BoondConfig;
44
+ //# sourceMappingURL=auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../../src/services/http/auth.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAKrE;;;;;;;;GAQG;AACH,eAAO,MAAM,gBAAgB,EAAE,iBAU9B,CAAC;AAOF;;;;;;;GAOG;AACH,wBAAgB,QAAQ,CACtB,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE;IAAE,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,GAC3D,MAAM,CAWR;AAED,eAAO,MAAM,eAAe,8BAA8B,CAAC;AAgC3D,wBAAgB,UAAU,IAAI,IAAI,CAsCjC;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,IAAI,OAAO,CAM3C;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,iBAAiB,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAKlF;AAED,6EAA6E;AAC7E,wBAAgB,mBAAmB,IAAI,IAAI,CAE1C;AAED,gFAAgF;AAChF,wBAAgB,SAAS,IAAI,WAAW,CAKvC"}
@@ -0,0 +1,146 @@
1
+ /**
2
+ * Client configuration and the three auth providers (JWT built from
3
+ * components, static header, OAuth Bearer read from the request context).
4
+ *
5
+ * Split out of `boond-client.ts` (issue #239): everything here decides *who*
6
+ * the request is sent as; nothing here sends anything.
7
+ */
8
+ import { createHmac } from "crypto";
9
+ import { readString, readUrl } from "../../config/env.js";
10
+ import { DEFAULT_BASE_URL } from "../../constants.js";
11
+ import { oauthContext } from "../oauth.js";
12
+ let config = null;
13
+ /**
14
+ * Auth provider for the HTTP transport: reads the Bearer token from the
15
+ * per-request AsyncLocalStorage populated by the transport layer and
16
+ * forwards it verbatim to BoondManager as `Authorization: Bearer …`.
17
+ *
18
+ * Errors out clearly if called outside a request context — which would
19
+ * indicate that the transport layer forgot to wrap the request in
20
+ * `oauthContext.run(...)`.
21
+ */
22
+ export const oauthContextAuth = () => {
23
+ const ctx = oauthContext.getStore();
24
+ if (!ctx) {
25
+ return Promise.reject(new Error("No OAuth access token in request context. The HTTP transport requires an `Authorization: Bearer <boond_access_token>` header on every request."));
26
+ }
27
+ return Promise.resolve({ name: "Authorization", value: `Bearer ${ctx.accessToken}` });
28
+ };
29
+ function base64url(data) {
30
+ const b64 = Buffer.from(data).toString("base64");
31
+ return b64.replace(/=/g, "").replace(/\+/g, "-").replace(/\//g, "_");
32
+ }
33
+ /**
34
+ * Build the BoondManager HS256 JWT. By default the payload is exactly
35
+ * `{ userToken, clientToken }` (BoondManager's documented scheme). When
36
+ * `expiresInSeconds` is provided, standard `iat`/`exp` claims are added so the
37
+ * generated token is no longer replayable forever if it leaks — this requires
38
+ * regenerating the token per request (see `jwtAuth`). Opt-in because not every
39
+ * BoondManager deployment is known to honour `exp`.
40
+ */
41
+ export function buildJwt(userToken, clientToken, clientKey, options) {
42
+ const header = base64url(JSON.stringify({ alg: "HS256", typ: "JWT" }));
43
+ const claims = { userToken, clientToken };
44
+ if (options?.expiresInSeconds && options.expiresInSeconds > 0) {
45
+ const now = options.nowSeconds ?? Math.floor(Date.now() / 1000);
46
+ claims.iat = now;
47
+ claims.exp = now + options.expiresInSeconds;
48
+ }
49
+ const payload = base64url(JSON.stringify(claims));
50
+ const signature = base64url(createHmac("sha256", clientKey).update(`${header}.${payload}`).digest());
51
+ return `${header}.${payload}.${signature}`;
52
+ }
53
+ export const JWT_HEADER_NAME = "X-Jwt-Client-Boondmanager";
54
+ /**
55
+ * Wrap a static header pair in the dynamic AuthProvider contract.
56
+ * Used by the stdio transport, which sticks to the JWT / BasicAuth paths.
57
+ */
58
+ function staticAuth(name, value) {
59
+ const cached = Promise.resolve({ name, value });
60
+ return () => cached;
61
+ }
62
+ /**
63
+ * JWT auth provider. When `ttlSeconds` is set (via BOOND_JWT_TTL_SECONDS), a
64
+ * fresh token with `iat`/`exp` is minted per request so a leaked token expires;
65
+ * otherwise the token is built once and cached (legacy, never-expiring).
66
+ */
67
+ function jwtAuth(userToken, clientToken, clientKey, ttlSeconds) {
68
+ if (!ttlSeconds || ttlSeconds <= 0) {
69
+ return staticAuth(JWT_HEADER_NAME, buildJwt(userToken, clientToken, clientKey));
70
+ }
71
+ return () => Promise.resolve({
72
+ name: JWT_HEADER_NAME,
73
+ value: buildJwt(userToken, clientToken, clientKey, { expiresInSeconds: ttlSeconds }),
74
+ });
75
+ }
76
+ export function initClient() {
77
+ const baseUrl = readUrl("BOOND_BASE_URL") ?? DEFAULT_BASE_URL;
78
+ // Auth priority (stdio transport):
79
+ // 1. Build JWT from components (userToken + clientToken + clientKey)
80
+ // 2. Pre-built JWT token
81
+ // 3. BasicAuth (user:password)
82
+ //
83
+ // Per BoondManager's JWT spec the token must travel in the
84
+ // `X-Jwt-Client-Boondmanager` header — sending it as `Authorization: Bearer`
85
+ // makes the API reject the request with 422 "Signature verification failed".
86
+ // BasicAuth, on the other hand, uses the standard `Authorization` header.
87
+ //
88
+ // HTTP transport uses OAuth2 exclusively — see `initClientWithAuth`.
89
+ const userToken = readString("BOOND_USER_TOKEN");
90
+ const clientToken = readString("BOOND_CLIENT_TOKEN");
91
+ const clientKey = readString("BOOND_CLIENT_KEY");
92
+ const token = readString("BOOND_API_TOKEN");
93
+ const user = readString("BOOND_USER");
94
+ const password = readString("BOOND_PASSWORD");
95
+ let auth;
96
+ if (userToken && clientToken && clientKey) {
97
+ const ttlRaw = readString("BOOND_JWT_TTL_SECONDS");
98
+ const ttlSeconds = ttlRaw ? Number(ttlRaw) : undefined;
99
+ auth = jwtAuth(userToken, clientToken, clientKey, Number.isFinite(ttlSeconds) ? ttlSeconds : undefined);
100
+ }
101
+ else if (token) {
102
+ auth = staticAuth(JWT_HEADER_NAME, token);
103
+ }
104
+ else if (user && password) {
105
+ auth = staticAuth("Authorization", `Basic ${Buffer.from(`${user}:${password}`).toString("base64")}`);
106
+ }
107
+ else {
108
+ throw new Error("Authentication required. Set BOOND_USER_TOKEN + BOOND_CLIENT_TOKEN + BOOND_CLIENT_KEY, or BOOND_API_TOKEN, or both BOOND_USER and BOOND_PASSWORD.");
109
+ }
110
+ config = { baseUrl, auth };
111
+ }
112
+ /**
113
+ * True when env-based credentials (JWT components, API token, or BasicAuth) are
114
+ * configured. Used by the HTTP transport in static-auth mode
115
+ * (`BOOND_HTTP_STATIC_AUTH=true`) to fail fast with a readable message before
116
+ * `initClient()` throws; the default HTTP mode is an OAuth2 protected resource
117
+ * and never reads these variables.
118
+ */
119
+ export function hasEnvCredentials() {
120
+ return !!((readString("BOOND_USER_TOKEN") && readString("BOOND_CLIENT_TOKEN") && readString("BOOND_CLIENT_KEY")) ||
121
+ readString("BOOND_API_TOKEN") ||
122
+ (readString("BOOND_USER") && readString("BOOND_PASSWORD")));
123
+ }
124
+ /**
125
+ * Install a custom auth provider — used by the HTTP transport bootstrap to
126
+ * wire in an OAuth2 token source (where the access token is refreshed
127
+ * transparently per request rather than baked in at startup).
128
+ */
129
+ export function initClientWithAuth(auth, baseUrl) {
130
+ config = {
131
+ baseUrl: baseUrl ?? readUrl("BOOND_BASE_URL") ?? DEFAULT_BASE_URL,
132
+ auth,
133
+ };
134
+ }
135
+ /** Test helper — reset the cached config so the next call re-initialises. */
136
+ export function resetClientForTests() {
137
+ config = null;
138
+ }
139
+ /** The active configuration, initialising from the environment on first use. */
140
+ export function getConfig() {
141
+ if (!config) {
142
+ initClient();
143
+ }
144
+ return config;
145
+ }
146
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../../src/services/http/auth.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Binary downloads (`/documents/{id}`): streaming read under a byte cap
3
+ * (issue #235), byte-level progress, and the two guards a document download
4
+ * needs that a JSON request does not — the application-shell detection and
5
+ * the `Content-Disposition` filename.
6
+ */
7
+ import type { ProgressReporter } from "../progress.js";
8
+ /**
9
+ * Parse the filename out of a `Content-Disposition` header. Handles the
10
+ * common `filename="…"`/`filename=…` forms and the RFC 5987
11
+ * `filename*=UTF-8''…` form. Returns undefined when absent. Exported for
12
+ * unit testing.
13
+ */
14
+ export declare function parseContentDispositionFilename(header: string | null): string | undefined;
15
+ /**
16
+ * BoondManager writes the plain `filename="…"` form with UTF-8 bytes (often
17
+ * NFD: `e` + combining acute), and `fetch` decodes header bytes as Latin-1 as
18
+ * the spec says — so "Frédéric" arrives as "FreÌdeÌric" (observed live on
19
+ * 2026-09-26, issue #311). Re-decode those bytes as UTF-8 when that yields a
20
+ * clean string, and normalise to NFC so the name compares like a normal one.
21
+ */
22
+ export declare function repairUtf8Filename(name: string): string;
23
+ export interface DownloadedDocument {
24
+ data: Buffer;
25
+ contentType: string;
26
+ filename?: string;
27
+ }
28
+ /**
29
+ * Thrown by `apiDownload` when the payload exceeds `maxBytes` — before the
30
+ * body is read when the response announces its size, otherwise the moment the
31
+ * running total crosses the cap (the stream is cancelled, nothing more is
32
+ * buffered). `bytes` is the announced size in the first case and a lower
33
+ * bound (bytes received so far) in the second; `announced` tells which.
34
+ */
35
+ export declare class DownloadTooLargeError extends Error {
36
+ readonly bytes: number;
37
+ readonly maxBytes: number;
38
+ readonly announced: boolean;
39
+ constructor(path: string, bytes: number, maxBytes: number, announced: boolean);
40
+ }
41
+ /** Options for `apiDownload`. */
42
+ export interface DownloadOptions {
43
+ /** Refuse payloads larger than this many bytes (see `DownloadTooLargeError`). */
44
+ maxBytes?: number;
45
+ }
46
+ /**
47
+ * Download a binary payload (documents, justificatifs…) from the BoondManager
48
+ * API. Same pipeline as `apiRequest` (`send()`: auth, path guard, rate limit,
49
+ * timeout, retry policy for a GET), but the body is streamed raw instead of
50
+ * being parsed as JSON:API.
51
+ *
52
+ * `onProgress` reports bytes received when the client asked for progress and
53
+ * the response carries a `Content-Length`; otherwise nothing is emitted.
54
+ *
55
+ * `options.maxBytes` bounds memory: a `Content-Length` above it is refused
56
+ * before a single body byte is read, and a body without one is cancelled the
57
+ * moment it crosses the cap (`DownloadTooLargeError` either way).
58
+ */
59
+ export declare function apiDownload(path: string, onProgress?: ProgressReporter, options?: DownloadOptions): Promise<DownloadedDocument>;
60
+ //# sourceMappingURL=download.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"download.d.ts","sourceRoot":"","sources":["../../../src/services/http/download.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAGvD;;;;;GAKG;AACH,wBAAgB,+BAA+B,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,GAAG,SAAS,CAazF;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAKvD;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAUD;;;;;;GAMG;AACH,qBAAa,qBAAsB,SAAQ,KAAK;IAC9C,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;gBAChB,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO;CAS9E;AAED,iCAAiC;AACjC,MAAM,WAAW,eAAe;IAC9B,iFAAiF;IACjF,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AA4DD;;;;;;;;;;;;GAYG;AACH,wBAAsB,WAAW,CAC/B,IAAI,EAAE,MAAM,EACZ,UAAU,CAAC,EAAE,gBAAgB,EAC7B,OAAO,GAAE,eAAoB,GAC5B,OAAO,CAAC,kBAAkB,CAAC,CAoC7B"}