/** * Client Deepgram — Sprint 4b. * * Génère un token éphémère que le frontend utilise pour ouvrir une connexion * WebSocket directe à Deepgram (transcription live). Le token est passé en * query string `?token=...` lors de l'init de la WS — c'est le seul mécanisme * de tokens éphémères WebSocket-compatible côté Deepgram. Les clés API créées * via `/v1/projects/{id}/keys` sont permanentes et ne fonctionnent pas en * query string sur la WS. * * Endpoint : POST https://api.deepgram.com/v1/auth/grant * Doc : https://developers.deepgram.com/docs/create-temporary-api-key * * Pré-requis : la clé `DEEPGRAM_API_KEY` doit avoir le scope « Member » du * projet. Sans ce scope, l'endpoint renvoie 403. */ const DEEPGRAM_API_KEY = process.env.DEEPGRAM_API_KEY ?? ""; const DEEPGRAM_BASE_URL = "https://api.deepgram.com"; const DEEPGRAM_TIMEOUT_MS = 10_000; export interface DeepgramToken { token: string; expires_in: number; } export async function createTemporaryToken( ttlSeconds: number, ): Promise { const response = await fetch(`${DEEPGRAM_BASE_URL}/v1/auth/grant`, { method: "POST", headers: { "Content-Type": "application/json", Authorization: `Token ${DEEPGRAM_API_KEY}`, }, body: JSON.stringify({ ttl_seconds: ttlSeconds }), signal: AbortSignal.timeout(DEEPGRAM_TIMEOUT_MS), }); if (!response.ok) { throw new Error( `Deepgram API error: ${response.status} ${response.statusText}`, ); } const data = (await response.json()) as { access_token?: string }; if (typeof data.access_token !== "string" || data.access_token.length === 0) { throw new Error("Deepgram API: access_token manquant dans la réponse"); } // L'API retourne le TTL effectif dans le payload (champ `expires_in`), // mais on retourne la valeur demandée pour cohérence avec le frontend. return { token: data.access_token, expires_in: ttlSeconds }; }