import { currentAuthIdentity } from "./oauth.js"; import type { JsonApiResponse } from "../types.js"; /** * Cache du dictionnaire BoondManager. * * L'API BoondManager expose **un seul endpoint** `GET /application/dictionary` * qui retourne l'intégralité des dictionnaires (états, types, pays, devises, * langues, outils, expertises, …) en une seule réponse JSON. La structure * pertinente pour les outils du serveur est `data.setting.*` et * `data.{country,languages}` (cf. RAML `schemas/application/dictionary.json`). * * Sans cache, chaque lecture de ressource ou appel à `boond_application_dictionary` * forcerait un appel HTTP de plusieurs centaines de Ko, alors que le contenu * change rarement (libellés d'états, types métier, …). On cache donc en mémoire * pour la durée du process, avec un TTL configurable. * * Concurrent fetches sont dédupliqués via une promesse partagée pour éviter * de marteler l'API quand plusieurs ressources sont lues en parallèle au * démarrage d'une session MCP. * * **Le cache est partitionné par identité d'authentification et par langue** * (issue #226). Le dictionnaire n'est pas une table de référence globale : il * porte les états, agences, pôles et types *personnalisés* d'un tenant * BoondManager. En transport HTTP OAuth chaque requête arrive avec le token * d'un utilisateur — potentiellement d'un autre tenant — et le transport ne * vérifie que la *présence* du Bearer. Un cache unique par processus servait * donc le dictionnaire du premier appelant à tous les suivants, sans appel * Boond : une fuite inter-tenants. La clé est `sha256(token) + langue` ; en * stdio (credentials env, une seule identité par processus) elle se réduit à * `env + langue`, et le comportement mono-utilisateur est inchangé. */ export type DictionaryLanguage = "fr" | "en" | "es"; interface CacheEntry { payload: JsonApiResponse; fetchedAt: number; language: DictionaryLanguage; } /** * Upper bound on cached (identity, language) pairs. Each entry is a full * dictionary payload (hundreds of KB), so the map is bounded; least recently * used entries are evicted first. 50 is plenty for a gateway serving a * handful of tenants and keeps the worst case around a few tens of MB. */ export declare const MAX_DICTIONARY_CACHE_ENTRIES = 50; /** Identity half of the cache key — see `currentAuthIdentity` in `oauth.ts`. */ export { currentAuthIdentity }; export interface GetDictionaryOptions { language?: DictionaryLanguage; /** Bypass the cache and re-fetch. */ force?: boolean; } /** * Returns the full BoondManager dictionary payload, fetching once per TTL * per (auth identity, language). Concurrent calls for the same key share * the same in-flight request; calls for different keys never do — an `en` * request must not be answered with the `fr` payload still loading. */ export declare function getDictionary(opts?: GetDictionaryOptions): Promise; /** * Resolves a dotted path inside the dictionary `data` object. * * Examples: * "setting.state.resource" → array of resource states * "setting.tool" → array of tools / technos * "country" → array of countries * "languages" → array of UI languages * "setting.state.resource[0]" → not supported (no bracket notation; pass plain dotted path) * * Returns `undefined` if any segment is missing. */ export declare function resolveDictionaryPath(payload: JsonApiResponse, path: string): unknown; /** Number of cached entries. Exposed for tests. */ export declare function dictionaryCacheSizeForTests(): number; /** Reset the cache. Exposed for tests. */ export declare function resetDictionaryCacheForTests(): void; //# sourceMappingURL=dictionary.d.ts.map