SDK TypeScript
Ce guide montre comment installer le SDK TypeScript (@enterprise-ai/sdk), le connecter au Control Plane de la
Navin Platform et appeler chaque groupe de ressources de l'API v1 avec des erreurs typées, des reprises, la
pagination et le streaming. Source : sdks/typescript/packages/sdk/src. Chaque classe, méthode et type figure dans
la référence générée.
English version: typescript.md
Vue d'ensemble
EnterpriseAI est un client à base de promesses sur l'API standard fetch. Il expose un sous-client par groupe de
ressources de l'API v1 en camelCase (client.agents, client.gateway, client.knowledgeBases,
client.finops...). Chaque méthode correspond à une route documentée, envoie les en-têtes d'authentification et de
tenancy, reprend les échecs transitoires et lève une sous-classe typée de EaiError. Le paquet contient aussi
ManagerClient pour le Navin Manager (SDK du Navin Manager), la validation hors ligne des contrats
(Contrats v1) et des aides pour les agents (AgentRunner, ContextBudget). La voix en temps
réel vit dans le paquet séparé @enterprise-ai/realtime (guide temps réel).
Prérequis et compatibilité
| Élément | Pris en charge |
|---|---|
| Node.js | 18 ou plus ("engines": { "node": ">=18" }), qui fournit fetch, AbortController et crypto |
| Autres environnements | Tout environnement avec un fetch standard : navigateurs, Deno, Bun, workers en périphérie ; ou passez votre propre fetch |
| Formats de module | ESM (import) et CommonJS (require), avec les déclarations de types pour les deux |
| TypeScript | Types livrés dans dist/index.d.ts ; le mode strict est pris en charge |
| Dépendances | ajv et ajv-formats (validation hors ligne des contrats) |
| Systèmes d'exploitation | Tout système pris en charge par l'environnement (Linux, macOS, Windows) |
| API du Control Plane | v1 |
Dans un navigateur, authentifiez-vous avec un fournisseur de jeton OIDC, jamais avec une clé API : tout ce qui est livré au navigateur est lisible par son utilisateur.
Installation
-
Téléchargez les paquets depuis Harbor. Les paquets des SDK sont hébergés dans le projet
sdkdu registre Harbor de Navinspire (artefactsdk/typescript, tag = version du SDK). Le registre Navinspire estregistry.navinspire.ai; connectez-vous avec un compte robot qui peut lire (pull) le projetsdk(fourni par l'équipe plateforme). Si votre organisation réplique le projetsdkdans son propre Harbor, utilisez l'adresse de ce miroir.oras login registry.navinspire.aioras pull registry.navinspire.ai/sdk/typescript:1.0.2 -o sdk-typescriptRésultat attendu : le dossier
sdk-typescriptcontiententerprise-ai-sdk-1.0.2.tgzetenterprise-ai-realtime-1.0.2.tgz. -
Ajoutez le paquet à votre projet.
npm install ./sdk-typescript/enterprise-ai-sdk-1.0.2.tgznpm install ./sdk-typescript/enterprise-ai-realtime-1.0.2.tgzLa deuxième ligne n'est utile que pour les sessions vocales en direct. Résultat attendu :
package.jsonliste@enterprise-ai/sdketnode -e "import('@enterprise-ai/sdk').then(m => console.log(typeof m.EnterpriseAI))"affichefunction.En cas d'échec : vérifiez
node --version(18 ou plus) et le registre configuré pour npm (npm config get registry).
Installation hors ligne depuis l'archive
-
Copiez l'archive récupérée dans Harbor sur la machine cible. Le
package.jsoncontient alors une référencefile:vers elle ; gardez l'archive dans un dossier du projet. Les deux dépendances du SDK viennent du registre npm configuré sur la cible, ou de leurs propres archives.npm install ./enterprise-ai-sdk-1.0.2.tgz -
Ou construisez depuis ce dépôt.
cd sdks/typescript && npm ci && npm run build
Démarrage rapide
Cet exemple liste les modèles que l'appelant peut utiliser et envoie une complétion de chat par le gateway, seul chemin vers les modèles.
import { EnterpriseAI } from "@enterprise-ai/sdk";
const client = new EnterpriseAI({ baseUrl: "<control-plane-url>", apiKey: process.env.EAI_API_KEY, locale: "en" });
const models = await client.models.list({ limit: 20 });
for (const model of models.items) console.log(model.id);
const reply = await client.gateway.chat.completions.create({ model: "gpt-4o-mini", messages: [{ role: "user", content: "Bonjour" }] });
console.log(reply.choices[0]?.message?.content);
Ce qui se passe : le constructeur vérifie l'URL de base (https obligatoire sauf sur localhost), chaque appel
envoie la clé dans X-API-Key et un nouveau traceparent W3C, et la complétion part avec une Idempotency-Key.
Résultat attendu : les identifiants des modèles, puis le texte de la réponse. Un appel refusé lève une erreur typée
comme PolicyDeniedError (Erreurs).
Authentification
Le serveur résout toujours le tenant à partir de l'identifiant. Le SDK ne lit aucune variable d'environnement :
passez les valeurs explicitement, par exemple depuis process.env.
| Méthode | Option | En-tête envoyé |
|---|---|---|
Clé API de tenant eai_<prefix>_<secret> (serveurs uniquement) | apiKey | X-API-Key |
| Jeton d'accès OIDC, fixe ou renouvelé par un fournisseur appelé avant chaque requête | token: string | () => string | Promise<string> | Authorization: Bearer <token> |
Mode développement (serveur lancé avec EAI_AUTH_DEV=1) | tenant, devUser, devRoles | X-Dev-Tenant, X-Dev-User, X-Dev-Roles |
| Identité de workload (SPIFFE, mTLS) | aucune : le maillage authentifie le workload | posé par le maillage |
import { EnterpriseAI } from "@enterprise-ai/sdk";
const browserClient = new EnterpriseAI({ baseUrl: "<control-plane-url>", token: async () => "<token>", locale: "fr" });
const keys = await browserClient.apiKeys.list();
client.apiKeys.create(...) crée une clé (le secret n'est affiché qu'une fois) et client.apiKeys.rotate(id) la
fait tourner.
Configuration du client
new EnterpriseAI(options: ClientOptions) :
| Nom | Type | Défaut | Requis | Description |
|---|---|---|---|---|
baseUrl | string | aucun | oui | URL du Control Plane sans /v1. https obligatoire sauf pour localhost, 127.0.0.1 et ::1 ; les identifiants intégrés sont refusés. |
apiKey | string | aucun | non | Clé API du tenant, envoyée dans X-API-Key. |
token | string | (() => string | Promise<string>) | aucun | non | Jeton OIDC ou fournisseur, envoyé dans Authorization: Bearer. |
tenant | string | aucun | non | Slug du tenant de développement, envoyé dans X-Dev-Tenant. |
devUser | string | aucun | non | Utilisateur de développement, envoyé dans X-Dev-User. |
devRoles | string[] | aucun | non | Rôles de développement, envoyés dans X-Dev-Roles (joints par des virgules). |
project | string | aucun | non | Slug du projet, envoyé dans X-Project. |
environment | "dev" | "test" | "staging" | "prod" | string | aucun | non | Environnement, envoyé dans X-Environment. |
locale | "en" | "fr" | "en" | non | Langue des messages d'erreur, envoyée dans Accept-Language. |
fetch | (input: string, init?: RequestInit) => Promise<Response> | fetch global | non | fetch personnalisé (agent proxy, tests, instrumentation). |
retries | number | 2 | non | Reprises après la première tentative (Reprises et délais). |
retryBaseDelayMs | number | 300 | non | Base du délai exponentiel, en millisecondes. |
retryMaxDelayMs | number | 20000 | non | Borne d'un délai, et d'un Retry-After respecté. |
timeoutMs | number | 60000 | non | Délai d'une tentative en millisecondes ; 0 le désactive. Les flux ne sont pas limités. |
headers | Record<string, string> | {} | non | En-têtes supplémentaires envoyés avec chaque requête. |
sleep | (ms: number) => Promise<void> | basé sur setTimeout | non | Attente entre les reprises, injectable dans les tests. |
Options par appel (CallOptions, dernier argument de chaque méthode) :
| Nom | Type | Description |
|---|---|---|
idempotencyKey | string | Idempotency-Key d'un POST ; sinon une clé est générée. |
traceparent | string | Contexte de trace W3C de l'appel ; sinon un contexte aléatoire est généré. |
headers | Record<string, string> | En-têtes supplémentaires pour cet appel. |
signal | AbortSignal | Annule l'appel ; un appel annulé n'est jamais repris. |
import { EnterpriseAI } from "@enterprise-ai/sdk";
const tuned = new EnterpriseAI({
baseUrl: "<control-plane-url>",
token: async () => "<token>",
project: "invoices",
environment: "prod",
retries: 4,
retryBaseDelayMs: 500,
retryMaxDelayMs: 10000,
timeoutMs: 30000,
headers: { "X-Client": "billing" },
});
const controller = new AbortController();
const agent = await tuned.agents.get("agt_ap", { signal: controller.signal, headers: { "X-Correlation-Id": "c-1" } });
JSON.stringify(client.http) et console.log(client.http) masquent la clé API et le jeton. Les redirections ne sont
jamais suivies (redirect: "manual").
Requêtes et réponses
Les paramètres de chemin sont positionnels, le corps est un objet typé d'après les contrats v1, et le résultat est
le corps JSON décodé typé par le SDK (Agent, ChatCompletion, Page<T>...). createWithMeta renvoie aussi les
en-têtes de gouvernance.
const { data: r, meta } = await client.gateway.chat.completions.createWithMeta({ model: "gpt-4o-mini", messages: [{ role: "user", content: "Bonjour" }], eai: { effort: "low", agent_id: "agt_ap" } });
console.log(meta.costMeasured, meta.decisionId);
for await (const chunk of client.gateway.chat.completions.stream({ model: "gpt-4o-mini", messages })) process.stdout.write(chunk.choices[0]?.delta?.content ?? "");
const plan = await client.models.resolve({ model: "o3-mini", effort: "high" });
GatewayMeta contient decisionId (X-EAI-Decision-Id), costEstimated, costMeasured et requestId. La
méthode bas niveau client.http.raw(method, template, options) renvoie { data, status, headers, requestId } pour
n'importe quelle route.
Erreurs
Chaque réponse d'erreur utilise l'enveloppe {"error": {"code", "message", "message_i18n": {"en", "fr"}, "details", "request_id"}}. Le SDK lève la classe du code, sinon celle du statut HTTP. Chaque erreur porte code,
status, message (dans la langue du client), messageI18n, details (clés d'allure secrète masquées),
requestId et retryAfterMs.
| Classe | Codes | Statut HTTP | Reprise par le SDK |
|---|---|---|---|
EaiError | tout autre code (missing_base_url, no_fetch, invalid_response, http_<status>...) | autre | non |
AuthError | unauthorized, unauthenticated, forbidden, invalid_credentials | 401, 403 | non |
PolicyDeniedError (decisionId, reasons) | policy_denied | 403 | non |
QuotaExceededError | quota_exceeded, budget_exceeded | 429 | oui, comme un 429, jusqu'à épuisement des reprises |
EffortNotSupportedError | effort_not_supported | 422 | non |
ContextOverflowError | context_overflow | 422 | non |
ApprovalRequiredError (approvalId) | approval_required | 409 | non |
NotFoundError | not_found | 404 | non |
ValidationError | validation_error | 400, 422 | non |
ConflictError | conflict | 409 | non |
PayloadTooLargeError | payload_too_large | 413 | non |
RateLimitError | rate_limited | 429 | oui, puis levée |
ServerError | server_error et tout 5xx | 500 à 599 | oui, puis levée |
NetworkError | network_error, timeout | aucun | oui, puis levée |
EgressDeniedError (reason) | egress_denied | 403 | non |
PromptInjectionBlockedError | prompt_injection_blocked | 403 | non |
AuthzUnconfirmedError | levée quand une réponse d'autorisation n'a pas de décision explicite | aucun | non |
ContractValidationError | échec de la validation hors ligne d'un contrat | aucun | non |
AgentLoopError | arrêt de la boucle d'agent locale | aucun | non |
import { QuotaExceededError, EaiError } from "@enterprise-ai/sdk";
try { await client.gateway.chat.completions.create(req); }
catch (e) { if (e instanceof QuotaExceededError) console.log(e.code, e.messageI18n.fr, e.requestId); else throw e; }
for await (const run of client.runs.iterate({ agent_id: "agt_ap" })) console.log(run.run_id);
Reprises et délais
Une tentative qui échoue en HTTP 429, en HTTP 5xx, par une erreur réseau ou un dépassement de délai est reprise
jusqu'à retries fois (2 par défaut), quelle que soit la méthode : chaque POST porte une Idempotency-Key, donc le
serveur dédoublonne la reprise. Le délai est exponentiel avec aléa (la moitié de retryBaseDelayMs * 2^tentative
plus une moitié aléatoire, au plus retryMaxDelayMs) ; un en-tête Retry-After (secondes ou date HTTP) le
remplace, borné par retryMaxDelayMs. Les autres statuts sont levés aussitôt. timeoutMs (60 s par défaut) borne
chaque tentative ; une annulation par signal est levée aussitôt.
Pagination
Les routes de liste prennent limit et cursor et répondent Page<T> : { items: T[], next_cursor: string | null }. Une méthode list renvoie une page ; une méthode iterate (agents, runs, tenants, projets, membres,
modèles, approbations, audit) renvoie un générateur asynchrone sur chaque élément ; paginate(fetchPage, params)
fait de même pour n'importe quelle méthode de liste et collect(iterable, max) rassemble les éléments dans un
tableau.
import { collect, paginate } from "@enterprise-ai/sdk";
const first = await client.runs.list({ agent_id: "agt_ap", limit: 50 });
console.log(first.items.length, first.next_cursor);
const agents = await collect(client.agents.iterate({ limit: 100 }), 500);
const sessions = await collect(paginate((q) => client.sessions.list(q), { limit: 50 }));
paginate s'arrête à la dernière page ou quand un curseur se répète.
Idempotence et opérations longues
Chaque POST envoie une Idempotency-Key : la valeur idempotencyKey que vous passez, sinon un UUID généré et
conservé entre les reprises de cet appel. Le Control Plane rejoue la première réponse pour une clé déjà vue.
const run = await client.agents.run("agt_ap", { task: { input: { invoice_media_id: "med_01HZX3K9" } } }, { idempotencyKey: "inv-2291" });
const done = await client.runs.get(run.run_id);
console.log(await client.runs.steps(run.run_id));
Une création longue répond avec les en-têtes Operation-Id et Operation-Location ; client.operations.get(id)
lit l'opération, sa ressource suivie et son état courant. Les runs (client.runs.get), les exécutions en sandbox
(client.sandbox.get) et les tâches multimodales (client.multimodal.getJob) se relisent jusqu'à un état final.
Asynchrone et concurrence
Chaque méthode renvoie une Promise ; les flux sont des générateurs asynchrones. Une instance de EnterpriseAI
sert de nombreux appels concurrents (Promise.all) : elle ne garde aucun état par appel. Annulez un appel avec un
AbortSignal.
const [me, models] = await Promise.all([client.me.get(), client.models.list()]);
Streaming et temps réel
client.gateway.chat.completions.stream(body) renvoie un générateur asynchrone de ChatCompletionChunk sur
Server-Sent Events, terminé par [DONE]. Les méthodes bas niveau client.http.sse(...) et
client.http.sseJSON(...) lisent n'importe quelle route SSE. Les sessions vocales en direct utilisent
client.realtime.createSession et le paquet @enterprise-ai/realtime : voir le
guide temps réel.
Journalisation et débogage
Le SDK n'écrit aucun journal. Pour tracer les appels, passez un fetch qui journalise la méthode, l'URL, le statut
et le X-Request-Id ; ne journalisez jamais les en-têtes de la requête, qui portent les identifiants.
import { EnterpriseAI } from "@enterprise-ai/sdk";
const logged = new EnterpriseAI({
baseUrl: "<control-plane-url>",
apiKey: process.env.EAI_API_KEY,
fetch: async (url, init) => {
const res = await fetch(url, init);
console.debug(init?.method ?? "GET", url, res.status, res.headers.get("x-request-id"));
return res;
},
});
console.log(JSON.stringify(logged.http.toJSON()));
Donnez le requestId d'une erreur à l'équipe plateforme : c'est la clé de l'événement d'audit et de la trace.
Tests
Injectez un faux fetch : aucun serveur n'est nécessaire et le vrai code du SDK s'exécute (en-têtes, erreurs,
pagination). Réglez retries: 0 ou un sleep vide pour garder des tests rapides.
import { EnterpriseAI, NotFoundError } from "@enterprise-ai/sdk";
const fakeFetch = async (url: string): Promise<Response> =>
url.endsWith("/v1/agents/missing")
? new Response(JSON.stringify({ error: { code: "not_found", message: "Resource not found." } }), { status: 404 })
: new Response(JSON.stringify({ items: [{ id: "agt_1" }], next_cursor: null }), { status: 200 });
const testClient = new EnterpriseAI({ baseUrl: "<control-plane-url>", apiKey: "eai_test_key", fetch: fakeFetch, retries: 0 });
const listed = await testClient.agents.list();
try {
await testClient.agents.get("missing");
} catch (err) {
if (!(err instanceof NotFoundError)) throw err;
}
Versions et compatibilité
- Le paquet suit le versionnage sémantique :
1.xgarde chaque nom exporté ; une suppression attend2.0. - Il cible l'API
v1et les contratsv1; les champs inconnus des réponses sont conservés, donc un Control Plane plus récent ne casse pas un SDK plus ancien. - Les tests
doc-coverage.test.tsetconformance.test.tsvérifient que chaque route de l'API v1 est couverte par une méthode. - Fixez la version mineure en production (
"@enterprise-ai/sdk": "~1.0.2").
Guides des ressources
Une sous-section par groupe de ressources, avec un exemple par appel courant. Chaque méthode et type est dans la référence générée.
Système, identité et tenancy
client.meta, client.me, client.catalog, client.operations, client.contracts, client.manifests,
client.tenants, client.projects, client.organizations, client.businessUnits, client.members,
client.apiKeys, client.serviceIdentities, client.authz, client.secrets.
await client.policies.evaluate({ action: "model.invoke", resource: { type: "model", id: "gpt-4o-mini" } });
await client.approvals.decide("apr_3", { decision: "approve", comment: "ok" });
await client.projects.create({ slug: "invoices", name: "Invoices" });
const res = await client.contracts.validate("usage-event", doc);
Licence, contexte, délégation et accès d'urgence
client.license, client.context (contextes d'exécution), client.delegations, client.mandates,
client.breakGlass.
const lic = await client.license.get(); // GET /v1/license
await client.license.activate({ token: signedLicense }); // POST /v1/license/activations
const me = await client.me.whoami(); // GET /v1/identity/whoami
const ctx = await client.context.issue({ run_id: "run_1", ttl_seconds: 300 }); // POST /v1/context/issue
await client.context.verify({ token: String(ctx.token) });
const jwks = await client.context.jwks(); // offline verification keys
const d = await client.delegations.create({ delegate: "agent:support", scopes: ["crm.read"], ttl_seconds: 3600 });
await client.delegations.restrict(String(d.id), { delegate: "agent:sub", scopes: ["crm.read"] });
await client.delegations.authorize({ action: "crm.read", resource: "crm:contact:42" });
const m = await client.mandates.create({ agent: "agt_nightly", purpose: "reporting", service_identity_id: "si_1" });
await client.mandates.decide(String(m.approval_id), { decision: "approve" }); // by another person
const grant = await client.breakGlass.request({ reason: "P1 outage", duration_seconds: 900, incident_ref: "INC-12" });
await client.breakGlass.revoke(String(grant.id), { reason: "resolved" });
Politiques, approbations, risques et incidents
client.policies (évaluation, décisions, révisions, simulation, bundles, moteurs), client.approvals,
client.risk, client.incidents, client.governance, client.security.
await client.policies.revisions("pol_1");
await client.policies.diffRevisions("pol_1", { from_revision: 3, to_revision: 4 });
await client.policies.simulate({ candidate: draftPolicy, policy_id: "pol_1" });
await client.policies.createBundle({ revision: "2026-10-30.1" });
const archive = await client.policies.downloadBundle("current"); // ArrayBuffer (bundle.tar.gz)
const engines = await client.policies.engines(); // expected_revision, in_sync
Modèles, fournisseurs, routes et gateway
client.providers, client.models, client.routes, client.litellm, client.adapters, client.gateway
(complétions de chat, embeddings, rerank, estimation), client.llm, client.llmManagement, client.isolation.
await client.models.createVersion("gpt-4o-mini", { version: "2026-10" });
await client.models.requestVersionApproval("gpt-4o-mini", "2026-10");
await client.models.startRollout("gpt-4o-mini", "2026-10", { percent: 10 });
await client.models.rollout("gpt-4o-mini");
await client.models.rollback("gpt-4o-mini");
await client.isolation.get({ project_id: "prj_1" }); // GET /v1/llm/isolation
Agents et runs
client.agents, client.runs, client.checkpoints, client.heartbeats, client.subagents, client.a2a,
client.sessions, client.schedules, client.triggers, client.events, client.sandbox.
import { signWebhook, tokenUnits } from "@enterprise-ai/sdk";
const headers = await signWebhook(secret, rawBody, { tenant: "acme", deliveryId: "evt-42" });
await client.webhooks.deliver("sap", { event: "invoice" }, { secret, tenant: "acme" });
const units = tokenUnits(1200, 300, { cached: 800, reasoning: 120 });
const hb = await client.heartbeats.send(runId, { progress: 0.5 });
if (hb.action === "stop") { /* checkpoint and exit */ }
Une réponse de heartbeat avec action: "stop" signifie : enregistrer un point de reprise et sortir.
Outils, MCP, skills, plugins, connecteurs et canaux
client.tools, client.mcp, client.mcpRuntime, client.skills, client.plugins, client.connectors,
client.credentials, client.webhooks, client.channels, client.navinLibrary, client.fileSecurity.
await client.tools.invoke("erp.lookup", { arguments: { invoice: "INV-2291" }, run_id: run.run_id });
await client.mcp.callTool("mcp_files", "read", { path: "/a.txt" });
await client.skills.verify("invoice-reader");
await client.channels.inbound("web", { user: "u1", text: "Bonjour" });
Données : RAG, mémoire, DLP et chiffrement
client.privacy, client.dlp, client.tokenization, client.encryption, client.knowledgeBases,
client.memory, client.retention, client.lineage, client.prompts.
const hits = await client.knowledgeBases.query("kb_1", { query: "délai de paiement", top_k: 5 });
await client.dlp.redact({ text: "IBAN FR76...", mode: "mask" });
const tok = await client.tokenization.tokenize({ values: ["FR7630006000011234567890189"] });
Multimodal
client.media (dépôt), client.multimodal (vision, images, vidéo, parole, diarisation, DLP audio, tâches),
client.realtime (sessions, consentements, tours de parole, transcriptions).
const media = await client.media.upload({ file, operation: "vision_understanding" });
await client.multimodal.vision({ model: "vision-default", media_id: media.media_id, prompt: "Total ?" });
await client.multimodal.stt({ media_id: "med_AUD1", language: "fr" });
const job = await client.multimodal.generateVideo({ model: "video-gen-gpu", prompt: "Teaser", seconds: 8 });
await client.multimodal.getJob(job.job_id as string);
Qualité, audit et observabilité
client.evaluations, client.redteam, client.audit, client.telemetry.
const gate = await client.evaluations.checkGate({ target: { type: "agent", ref: "agt_ap", version: "1.4.0" }, suite_ids: ["evs_12"] });
const v = await client.audit.verify();
const corr = await client.audit.correlations({ run_id: "run_42" });
const slo = await client.telemetry.slo({ window_minutes: 60 }); // budget_remaining and burn_rate per service
FinOps et quotas
client.finops et client.quotas. withReservation réserve, exécute votre fonction, puis confirme en cas de
succès ou libère en cas d'erreur.
const est = await client.finops.estimate({ provider: "openai", usage_type: "llm", model_id: "gpt-4o-mini", units: { input_tokens: 12000, output_tokens: 2000 } });
await client.quotas.withReservation(
{ cost: "0.50", tokens: 4000, scope: { agent: "agt_ap" } },
async (r) => client.gateway.chat.completions.createWithMeta({ model: "gpt-4o-mini", messages }),
{ commitBody: (out) => ({ cost: out.meta.costMeasured, tokens: out.data.usage?.total_tokens }) },
);
const sum = await client.finops.summary({ group_by: "model" });
SOC et kill switches
client.soc : détections, ordres de confinement, kill switches, accusés, rétablissements (quatre yeux).
await client.soc.createDetection({ kind: "data_exfiltration", severity: "high", agent: "agt_1" });
const order = await client.soc.createOrder({ reaction: "kill_agent", reason: "exfiltration", target: { agent: "agt_1" } });
await client.soc.approveOrder(String(order.id));
await client.soc.verifyKillSwitch("ks_1"); // effective only once every receipt is verified
await client.soc.requestRecovery({ kill_switch_id: "ks_1", reason: "root cause fixed" });
await client.soc.approveRecovery("rec_1"); // four eyes: another person
await client.soc.webhook("falco", rawBody, { headers: { "X-EAI-Signature": signature } }); // raw bytes
Stockage, place de marché et preuves
client.storageProfiles, client.marketplace, client.evidence, client.applications.
const sp = await client.storageProfiles.create({ name: "archive", provider: "s3_compatible", bucket: "eai-archive", credential_ref: "vault:kv/s3" });
await client.storageProfiles.verify(String(sp.id), { probe_write: true });
const { url } = await client.storageProfiles.presign(String(sp.id), { key: "exports/a.json", scope: "read" });
await client.marketplace.preflight({ package: "hr-onboarding", version: "1.2.0", environment: "staging" });
const inst = await client.marketplace.install({ package: "hr-onboarding", version: "1.2.0", environment: "staging" });
await client.marketplace.apply(String(inst.id));
await client.evidence.createSeal();
await client.evidence.verify();
await client.evidence.createHold({ case_id: "case_7", reason: "litigation" });
await client.evidence.runConfiguration("run_1");
Interfaces de l'architecture
Méthodes nommées sur des routes documentées. Une panne d'OpenFGA ou d'OPA se propage en erreur typée
(ServerError avec le code authz_backend_error), et une réponse sans décision explicite lève
AuthzUnconfirmedError : le SDK ne rapporte jamais une autorisation que le moteur n'a pas confirmée. Un refus se
propage avec son erreur typée (AuthError 403 relation_required, ValidationError 422, ConflictError 409
approval_closed ou storage_object_protected).
import { AuthError, type AuditRecord } from "@enterprise-ai/sdk";
try {
const ctx = await client.serviceIdentities.assume("si-billing", { purpose: "nightly invoice sync", audience: ["erp"], ttl_seconds: 600 });
console.log(ctx.context_id, ctx.effective.scopes); // verified downstream with POST /v1/context/verify
} catch (err) {
if (err instanceof AuthError && err.code === "relation_required") { /* can_assume not granted */ }
else throw err;
}
const event: AuditRecord = { action: "app.invoice.validated", resource: { type: "invoice", id: "inv-42" }, outcome: "success" };
const receipt = await client.audit.record(event); // receipt.event_id, receipt.hash
await client.approvals.cancel("apr-1", { reason: "request withdrawn" });
const page = await client.storageProfiles.listObjects("sp-1", { prefix: "exports/", limit: 100 });
for (const o of page.items) await client.storageProfiles.deleteObject("sp-1", o.key, o.version_id ? { version_id: o.version_id } : {});
Espace Platform Manager (platform_admin)
client.platformManager atteint l'espace Platform Manager de la console : le Control Plane relaie chaque appel au
Navin Manager au nom de l'appelant, dont le RBAC, les approbations et les règles d'arrêt décident. Un refus revient
avec son statut et un code platform_manager_<code>.
const summary = await client.platformManager.summary(); // services total, healthy, warning, failed per cluster
const services = await client.platformManager.services("c1"); // five state fields and administrative state
const op = await client.platformManager.requestOperation("c1", "opa", "rolling_restart", { batch_size: 1 });
const restore = await client.platformManager.planRestore({ artifact_id: "b1", environment: "isolated" }); // two approvers other than the requester (ADR-0162)
const exercises = await client.platformManager.drExercises(); // observed RPO and RTO
const links = await client.platformManager.console(); // Manager console and operator consoles
Client du Navin Manager
ManagerClient de @enterprise-ai/sdk appelle directement l'API du Navin Manager avec un jeton du manager
nmt_<12 hex>_<secret> ; seuls GET, PUT et DELETE sont repris, car le manager ne dédoublonne pas les appels POST. Le
guide complet est SDK du Navin Manager.
import { ManagerClient } from "@enterprise-ai/sdk";
const nm = new ManagerClient({ baseUrl: "<manager-url>", token: async () => "<token>", onBehalfOf: "alice" });
const operation = await nm.services.action("c1", "kafka", { action: "restart" });
Référence
- Référence TypeScript générée : chaque classe, méthode, paramètre et type.
- API v1 du Control Plane, Contrats v1, guide temps réel.
- Autres SDK.