Aller au contenu principal

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émentPris en charge
Node.js18 ou plus ("engines": { "node": ">=18" }), qui fournit fetch, AbortController et crypto
Autres environnementsTout environnement avec un fetch standard : navigateurs, Deno, Bun, workers en périphérie ; ou passez votre propre fetch
Formats de moduleESM (import) et CommonJS (require), avec les déclarations de types pour les deux
TypeScriptTypes livrés dans dist/index.d.ts ; le mode strict est pris en charge
Dépendancesajv et ajv-formats (validation hors ligne des contrats)
Systèmes d'exploitationTout système pris en charge par l'environnement (Linux, macOS, Windows)
API du Control Planev1
attention

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​

  1. Téléchargez les paquets depuis Harbor. Les paquets des SDK sont hébergés dans le projet sdk du registre Harbor de Navinspire (artefact sdk/typescript, tag = version du SDK). Le registre Navinspire est registry.navinspire.ai ; connectez-vous avec un compte robot qui peut lire (pull) le projet sdk (fourni par l'équipe plateforme). Si votre organisation réplique le projet sdk dans son propre Harbor, utilisez l'adresse de ce miroir.

    oras login registry.navinspire.ai
    oras pull registry.navinspire.ai/sdk/typescript:1.0.2 -o sdk-typescript

    Résultat attendu : le dossier sdk-typescript contient enterprise-ai-sdk-1.0.2.tgz et enterprise-ai-realtime-1.0.2.tgz.

  2. Ajoutez le paquet à votre projet.

    npm install ./sdk-typescript/enterprise-ai-sdk-1.0.2.tgz
    npm install ./sdk-typescript/enterprise-ai-realtime-1.0.2.tgz

    La deuxième ligne n'est utile que pour les sessions vocales en direct. Résultat attendu : package.json liste @enterprise-ai/sdk et node -e "import('@enterprise-ai/sdk').then(m => console.log(typeof m.EnterpriseAI))" affiche function.

    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​

  1. Copiez l'archive récupérée dans Harbor sur la machine cible. Le package.json contient alors une référence file: 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
  2. 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éthodeOptionEn-tête envoyé
Clé API de tenant eai_<prefix>_<secret> (serveurs uniquement)apiKeyX-API-Key
Jeton d'accès OIDC, fixe ou renouvelé par un fournisseur appelé avant chaque requêtetoken: string | () => string | Promise<string>Authorization: Bearer <token>
Mode développement (serveur lancé avec EAI_AUTH_DEV=1)tenant, devUser, devRolesX-Dev-Tenant, X-Dev-User, X-Dev-Roles
Identité de workload (SPIFFE, mTLS)aucune : le maillage authentifie le workloadposé 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) :

NomTypeDéfautRequisDescription
baseUrlstringaucunouiURL du Control Plane sans /v1. https obligatoire sauf pour localhost, 127.0.0.1 et ::1 ; les identifiants intégrés sont refusés.
apiKeystringaucunnonClé API du tenant, envoyée dans X-API-Key.
tokenstring | (() => string | Promise<string>)aucunnonJeton OIDC ou fournisseur, envoyé dans Authorization: Bearer.
tenantstringaucunnonSlug du tenant de développement, envoyé dans X-Dev-Tenant.
devUserstringaucunnonUtilisateur de développement, envoyé dans X-Dev-User.
devRolesstring[]aucunnonRôles de développement, envoyés dans X-Dev-Roles (joints par des virgules).
projectstringaucunnonSlug du projet, envoyé dans X-Project.
environment"dev" | "test" | "staging" | "prod" | stringaucunnonEnvironnement, envoyé dans X-Environment.
locale"en" | "fr""en"nonLangue des messages d'erreur, envoyée dans Accept-Language.
fetch(input: string, init?: RequestInit) => Promise<Response>fetch globalnonfetch personnalisé (agent proxy, tests, instrumentation).
retriesnumber2nonReprises après la première tentative (Reprises et délais).
retryBaseDelayMsnumber300nonBase du délai exponentiel, en millisecondes.
retryMaxDelayMsnumber20000nonBorne d'un délai, et d'un Retry-After respecté.
timeoutMsnumber60000nonDélai d'une tentative en millisecondes ; 0 le désactive. Les flux ne sont pas limités.
headersRecord<string, string>{}nonEn-têtes supplémentaires envoyés avec chaque requête.
sleep(ms: number) => Promise<void>basé sur setTimeoutnonAttente entre les reprises, injectable dans les tests.

Options par appel (CallOptions, dernier argument de chaque méthode) :

NomTypeDescription
idempotencyKeystringIdempotency-Key d'un POST ; sinon une clé est générée.
traceparentstringContexte de trace W3C de l'appel ; sinon un contexte aléatoire est généré.
headersRecord<string, string>En-têtes supplémentaires pour cet appel.
signalAbortSignalAnnule 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.

ClasseCodesStatut HTTPReprise par le SDK
EaiErrortout autre code (missing_base_url, no_fetch, invalid_response, http_<status>...)autrenon
AuthErrorunauthorized, unauthenticated, forbidden, invalid_credentials401, 403non
PolicyDeniedError (decisionId, reasons)policy_denied403non
QuotaExceededErrorquota_exceeded, budget_exceeded429oui, comme un 429, jusqu'à épuisement des reprises
EffortNotSupportedErroreffort_not_supported422non
ContextOverflowErrorcontext_overflow422non
ApprovalRequiredError (approvalId)approval_required409non
NotFoundErrornot_found404non
ValidationErrorvalidation_error400, 422non
ConflictErrorconflict409non
PayloadTooLargeErrorpayload_too_large413non
RateLimitErrorrate_limited429oui, puis levée
ServerErrorserver_error et tout 5xx500 à 599oui, puis levée
NetworkErrornetwork_error, timeoutaucunoui, puis levée
EgressDeniedError (reason)egress_denied403non
PromptInjectionBlockedErrorprompt_injection_blocked403non
AuthzUnconfirmedErrorlevée quand une réponse d'autorisation n'a pas de décision expliciteaucunnon
ContractValidationErroréchec de la validation hors ligne d'un contrataucunnon
AgentLoopErrorarrêt de la boucle d'agent localeaucunnon
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.x garde chaque nom exporté ; une suppression attend 2.0.
  • Il cible l'API v1 et les contrats v1 ; 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.ts et conformance.test.ts vé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​