@dimer47/gladia-sdk 1.0.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.
package/README.fr.md ADDED
@@ -0,0 +1,342 @@
1
+ # 🎙️ Gladia SDK — TypeScript Client
2
+
3
+ ![Version](https://img.shields.io/npm/v/@dimer47/gladia-sdk?color=red&style=flat-square) ![Bundle Size](https://img.shields.io/bundlephobia/minzip/@dimer47/gladia-sdk?color=green&label=bundle%20size&style=flat-square) ![Downloads](https://img.shields.io/npm/dt/@dimer47/gladia-sdk?style=flat-square) ![TypeScript](https://img.shields.io/badge/TypeScript-5.7%2B-3178C6?style=flat-square&logo=typescript&logoColor=white) ![Node](https://img.shields.io/badge/Node.js-18%2B-339933?style=flat-square&logo=node.js&logoColor=white) ![License](https://img.shields.io/npm/l/@dimer47/gladia-sdk?style=flat-square) ![Zero Dependencies](https://img.shields.io/badge/dependencies-0-brightgreen?style=flat-square) ![Build](https://img.shields.io/badge/build-ESM%20%2B%20CJS-blue?style=flat-square)
4
+
5
+ **SDK TypeScript fait main pour l'[API Gladia](https://docs.gladia.io)** — transcription audio/vidéo pré-enregistrée et en temps réel, avec support complet du WebSocket live streaming.
6
+
7
+ > 🌐 **[English version](README.md)**
8
+
9
+ > 💡 Fonctionne partout : **Node.js**, **Bun**, **Deno**, et **navigateurs** — zéro dépendance runtime.
10
+
11
+ ## 🎉 Features
12
+
13
+ - 🎤 **Transcription pré-enregistrée** — envoi par fichier ou URL, polling automatique avec backoff exponentiel
14
+ - 🔴 **Live streaming** — WebSocket typé avec événements temps réel (partiels, finaux, speech events)
15
+ - 📤 **Upload** — multipart (fichier) ou JSON (URL distante)
16
+ - 🌍 **Traduction, résumé, diarisation, analyse de sentiments** — et 10+ addons activables
17
+ - 🔒 **PII redaction** — masquage des données personnelles (GDPR, HIPAA...)
18
+ - 🏷️ **100% typé** — interfaces TypeScript pour les 54 schemas de l'API
19
+ - ⚡ **Dual ESM + CJS** — compatible avec tous les bundlers et runtimes
20
+ - 🪶 **0 dépendance** — uniquement `fetch` et `WebSocket` natifs
21
+ - 🧪 **91 tests unitaires** — couverture complète sans clé API requise
22
+
23
+ ## 📍 Install
24
+
25
+ ```bash
26
+ npm install @dimer47/gladia-sdk
27
+ ```
28
+
29
+ ```bash
30
+ yarn add @dimer47/gladia-sdk
31
+ ```
32
+
33
+ ```bash
34
+ pnpm add @dimer47/gladia-sdk
35
+ ```
36
+
37
+ ## 🚀 Quick Start
38
+
39
+ ```typescript
40
+ import { GladiaClient } from '@dimer47/gladia-sdk';
41
+
42
+ const gladia = new GladiaClient({ apiKey: 'gla_xxx' });
43
+ ```
44
+
45
+ ## 🕹️ Usage
46
+
47
+ ### 📤 Upload
48
+
49
+ ```typescript
50
+ // Depuis un fichier (Blob, File, Buffer)
51
+ const uploaded = await gladia.upload.fromFile(myBlob, 'recording.wav');
52
+ console.log(uploaded.audio_url);
53
+
54
+ // Depuis une URL distante
55
+ const uploaded = await gladia.upload.fromUrl('https://example.com/audio.mp3');
56
+ ```
57
+
58
+ ### 🎧 Transcription pré-enregistrée
59
+
60
+ #### ✅ Mode simple (POST + polling automatique)
61
+
62
+ ```typescript
63
+ const result = await gladia.preRecorded.transcribe({
64
+ audio_url: 'https://example.com/audio.mp3',
65
+ diarization: true,
66
+ translation: true,
67
+ translation_config: { target_languages: ['en'] },
68
+ onPoll: (res) => console.log(`⏳ ${res.status}...`),
69
+ });
70
+
71
+ console.log(result.result?.transcription?.full_transcript);
72
+ ```
73
+
74
+ #### 🔧 Contrôle granulaire
75
+
76
+ ```typescript
77
+ // Créer un job
78
+ const job = await gladia.preRecorded.create({
79
+ audio_url: 'https://example.com/audio.mp3',
80
+ summarization: true,
81
+ sentiment_analysis: true,
82
+ });
83
+ console.log(`🆔 Job: ${job.id}`);
84
+
85
+ // Vérifier le statut
86
+ const status = await gladia.preRecorded.get(job.id);
87
+ console.log(`📊 Status: ${status.status}`);
88
+
89
+ // Lister les transcriptions
90
+ const list = await gladia.preRecorded.list({ limit: 10 });
91
+
92
+ // Télécharger le fichier audio original
93
+ const audioBlob = await gladia.preRecorded.getFile(job.id);
94
+
95
+ // Supprimer
96
+ await gladia.preRecorded.delete(job.id);
97
+ ```
98
+
99
+ ### 🔴 Live Streaming
100
+
101
+ ```typescript
102
+ const session = await gladia.live.stream({
103
+ encoding: 'wav/pcm',
104
+ sample_rate: 16000,
105
+ language_config: { languages: ['fr'] },
106
+ realtime_processing: {
107
+ translation: true,
108
+ translation_config: { target_languages: ['en'] },
109
+ },
110
+ });
111
+
112
+ // 📝 Écouter les transcriptions finales
113
+ session.on('transcript:final', (msg) => {
114
+ console.log(`🗣️ ${msg.transcription.text}`);
115
+ });
116
+
117
+ // 📝 Écouter les transcriptions partielles
118
+ session.on('transcript:partial', (msg) => {
119
+ process.stdout.write(`... ${msg.transcription.text}\r`);
120
+ });
121
+
122
+ // 🎤 Envoyer des chunks audio
123
+ session.sendAudio(audioChunk); // ArrayBuffer | Uint8Array | Blob
124
+
125
+ // ⏹️ Arrêter et attendre la fin du traitement
126
+ await session.stop();
127
+ ```
128
+
129
+ #### 🔧 Contrôle granulaire du live
130
+
131
+ ```typescript
132
+ // Initialiser sans ouvrir le WebSocket
133
+ const liveSession = await gladia.live.init(
134
+ { encoding: 'wav/pcm', sample_rate: 16000 },
135
+ { region: 'eu-west' },
136
+ );
137
+ console.log(`🔗 WebSocket URL: ${liveSession.url}`);
138
+
139
+ // Lister, récupérer, supprimer
140
+ const sessions = await gladia.live.list({ limit: 5 });
141
+ const session = await gladia.live.get('session-id');
142
+ const audioBlob = await gladia.live.getFile('session-id');
143
+ await gladia.live.delete('session-id');
144
+ ```
145
+
146
+ ## 📦 Addons disponibles
147
+
148
+ | Addon | Champ | Config |
149
+ |-------|-------|--------|
150
+ | 🗣️ Diarisation | `diarization` | `diarization_config` |
151
+ | 🌍 Traduction | `translation` | `translation_config` |
152
+ | 📝 Résumé | `summarization` | `summarization_config` |
153
+ | 💬 Analyse de sentiments | `sentiment_analysis` | — |
154
+ | 🏷️ Entités nommées (NER) | `named_entity_recognition` | — |
155
+ | 📑 Chapitrage | `chapterization` | — |
156
+ | 🔒 PII Redaction | `pii_redaction` | `pii_redaction_config` |
157
+ | 📺 Sous-titres | `subtitles` | `subtitles_config` |
158
+ | 🤖 Audio to LLM | `audio_to_llm` | `audio_to_llm_config` |
159
+ | ✏️ Custom Spelling | `custom_spelling` | `custom_spelling_config` |
160
+ | 📊 Extraction structurée | `structured_data_extraction` | `structured_data_extraction_config` |
161
+ | 🔤 Custom Vocabulary | `custom_vocabulary` | `custom_vocabulary_config` |
162
+ | 🧑 Name Consistency | `name_consistency` | — |
163
+ | 🖥️ Display Mode | `display_mode` | — |
164
+ | 🚫 Modération | `moderation` | — |
165
+
166
+ ## 🧮 API Reference
167
+
168
+ ### `GladiaClient`
169
+
170
+ ```typescript
171
+ new GladiaClient(config: GladiaClientConfig)
172
+ ```
173
+
174
+ | Paramètre | Type | Description |
175
+ |-----------|------|-------------|
176
+ | `apiKey` | `string` | 🔑 Clé API Gladia (obligatoire) |
177
+ | `baseUrl` | `string?` | URL de base (défaut: `https://api.gladia.io`) |
178
+ | `WebSocket` | `unknown?` | Constructeur WebSocket custom (pour Node < 21, passer `ws`) |
179
+
180
+ ---
181
+
182
+ ### `gladia.upload`
183
+
184
+ | Méthode | Description |
185
+ |---------|-------------|
186
+ | `fromFile(blob, filename?, signal?)` | 📤 Upload un fichier (multipart) |
187
+ | `fromUrl(url, signal?)` | 🔗 Upload depuis une URL distante |
188
+
189
+ ---
190
+
191
+ ### `gladia.preRecorded`
192
+
193
+ | Méthode | Description |
194
+ |---------|-------------|
195
+ | `transcribe(options)` | ✅ POST + polling auto jusqu'à complétion |
196
+ | `create(request, signal?)` | 📝 Créer un job de transcription |
197
+ | `get(id, signal?)` | 🔍 Récupérer un job par ID |
198
+ | `list(params?, signal?)` | 📋 Lister les jobs (paginé) |
199
+ | `delete(id, signal?)` | 🗑️ Supprimer un job |
200
+ | `getFile(id, signal?)` | 💾 Télécharger le fichier audio original |
201
+
202
+ ---
203
+
204
+ ### `gladia.live`
205
+
206
+ | Méthode | Description |
207
+ |---------|-------------|
208
+ | `stream(options?)` | 🔴 Init + ouverture WebSocket → `LiveSession` |
209
+ | `init(request?, options?)` | 🔧 Init session (retourne l'URL WebSocket) |
210
+ | `get(id, signal?)` | 🔍 Récupérer une session par ID |
211
+ | `list(params?, signal?)` | 📋 Lister les sessions (paginé) |
212
+ | `delete(id, signal?)` | 🗑️ Supprimer une session |
213
+ | `getFile(id, signal?)` | 💾 Télécharger l'enregistrement audio |
214
+
215
+ ---
216
+
217
+ ### `LiveSession`
218
+
219
+ | Méthode / Propriété | Description |
220
+ |---------------------|-------------|
221
+ | `on(event, listener)` | 👂 Écouter un événement typé |
222
+ | `off(event, listener)` | 🔇 Retirer un listener |
223
+ | `sendAudio(data)` | 🎤 Envoyer un chunk audio |
224
+ | `stop()` | ⏹️ Signaler la fin et attendre le traitement |
225
+ | `closed` | `boolean` — état du WebSocket |
226
+
227
+ #### 📡 Événements disponibles
228
+
229
+ | Événement | Type | Description |
230
+ |-----------|------|-------------|
231
+ | `transcript:final` | `LiveTranscriptMessage` | Transcription finale d'un énoncé |
232
+ | `transcript:partial` | `LiveTranscriptMessage` | Transcription partielle en cours |
233
+ | `speech-begin` | `LiveSpeechBeginMessage` | Début de parole détecté |
234
+ | `speech-end` | `LiveSpeechEndMessage` | Fin de parole détectée |
235
+ | `ready` | `LiveReadyMessage` | Session prête à recevoir l'audio |
236
+ | `done` | `LiveDoneMessage` | Traitement terminé |
237
+ | `error` | `LiveErrorMessage` | Erreur WebSocket |
238
+ | `message` | `LiveBaseMessage` | Tout message brut (catch-all) |
239
+
240
+ ## ⚠️ Gestion des erreurs
241
+
242
+ Le SDK fournit une hiérarchie d'erreurs typées :
243
+
244
+ ```
245
+ GladiaError
246
+ ├── GladiaApiError (toute erreur HTTP)
247
+ │ ├── BadRequestError (400)
248
+ │ ├── UnauthorizedError (401)
249
+ │ ├── ForbiddenError (403)
250
+ │ ├── NotFoundError (404)
251
+ │ └── UnprocessableEntityError (422)
252
+ ├── GladiaTimeoutError (polling timeout / abort)
253
+ └── GladiaWebSocketError (erreur WebSocket)
254
+ ```
255
+
256
+ ```typescript
257
+ import { UnauthorizedError, GladiaTimeoutError } from '@dimer47/gladia-sdk';
258
+
259
+ try {
260
+ const result = await gladia.preRecorded.transcribe({
261
+ audio_url: '...',
262
+ pollTimeout: 60_000,
263
+ });
264
+ } catch (err) {
265
+ if (err instanceof UnauthorizedError) {
266
+ console.error('🔑 Clé API invalide');
267
+ } else if (err instanceof GladiaTimeoutError) {
268
+ console.error('⏱️ Timeout dépassé');
269
+ }
270
+ }
271
+ ```
272
+
273
+ ## 🌐 Compatibilité Node < 21 (WebSocket)
274
+
275
+ Node.js < 21 n'a pas de `WebSocket` global. Utilisez le package [`ws`](https://www.npmjs.com/package/ws) :
276
+
277
+ ```bash
278
+ npm install ws
279
+ ```
280
+
281
+ ```typescript
282
+ import WebSocket from 'ws';
283
+ import { GladiaClient } from '@dimer47/gladia-sdk';
284
+
285
+ const gladia = new GladiaClient({
286
+ apiKey: 'gla_xxx',
287
+ WebSocket,
288
+ });
289
+ ```
290
+
291
+ ## 🧪 Tests
292
+
293
+ ```bash
294
+ npm test # Exécuter les 91 tests
295
+ npm run test:watch # Mode watch
296
+ ```
297
+
298
+ Les tests utilisent des mocks (`fetch`, `WebSocket`) — **aucune clé API nécessaire**.
299
+
300
+ ## 🏗️ Build
301
+
302
+ ```bash
303
+ npm run build # ESM + CJS + .d.ts via tsup
304
+ npm run typecheck # Vérification TypeScript
305
+ ```
306
+
307
+ ## 📁 Structure du projet
308
+
309
+ ```
310
+ gladia-sdk/
311
+ ├── src/
312
+ │ ├── index.ts # Re-exports publics
313
+ │ ├── client.ts # GladiaClient (façade)
314
+ │ ├── http.ts # HttpClient (fetch wrapper)
315
+ │ ├── errors.ts # Hiérarchie d'erreurs typées
316
+ │ ├── types/ # 54 interfaces TypeScript
317
+ │ │ ├── config.ts # LanguageConfig, DiarizationConfig, PiiRedactionConfig...
318
+ │ │ ├── common.ts # JobStatus, PaginationParams, GladiaClientConfig
319
+ │ │ ├── upload.ts # UploadResponse, AudioMetadata
320
+ │ │ ├── pre-recorded.ts # PreRecordedRequest (31 champs), responses
321
+ │ │ ├── live.ts # LiveRequest, LiveResponse, LiveRequestParams
322
+ │ │ ├── transcription.ts # Utterance, Word, TranscriptionDTO
323
+ │ │ └── addons.ts # AddonTranslationDTO, SentimentAnalysisEntry...
324
+ │ ├── resources/
325
+ │ │ ├── upload.ts # .fromFile(), .fromUrl()
326
+ │ │ ├── pre-recorded.ts # .create(), .get(), .list(), .delete(), .getFile(), .transcribe()
327
+ │ │ └── live.ts # .init(), .get(), .list(), .delete(), .getFile(), .stream()
328
+ │ ├── live/
329
+ │ │ ├── session.ts # LiveSession (WebSocket typé)
330
+ │ │ └── events.ts # LiveEventMap (11 types d'événements)
331
+ │ └── utils/
332
+ │ └── polling.ts # poll() avec backoff exponentiel
333
+ ├── tests/ # 91 tests unitaires (vitest)
334
+ ├── dist/ # Build output (ESM + CJS + .d.ts)
335
+ ├── package.json
336
+ ├── tsconfig.json
337
+ └── tsup.config.ts
338
+ ```
339
+
340
+ ## 🧾 License
341
+
342
+ [MIT](LICENSE)
package/README.md ADDED
@@ -0,0 +1,342 @@
1
+ # 🎙️ Gladia SDK — TypeScript Client
2
+
3
+ ![Version](https://img.shields.io/npm/v/@dimer47/gladia-sdk?color=red&style=flat-square) ![Bundle Size](https://img.shields.io/bundlephobia/minzip/@dimer47/gladia-sdk?color=green&label=bundle%20size&style=flat-square) ![Downloads](https://img.shields.io/npm/dt/@dimer47/gladia-sdk?style=flat-square) ![TypeScript](https://img.shields.io/badge/TypeScript-5.7%2B-3178C6?style=flat-square&logo=typescript&logoColor=white) ![Node](https://img.shields.io/badge/Node.js-18%2B-339933?style=flat-square&logo=node.js&logoColor=white) ![License](https://img.shields.io/npm/l/@dimer47/gladia-sdk?style=flat-square) ![Zero Dependencies](https://img.shields.io/badge/dependencies-0-brightgreen?style=flat-square) ![Build](https://img.shields.io/badge/build-ESM%20%2B%20CJS-blue?style=flat-square)
4
+
5
+ **Handcrafted TypeScript SDK for the [Gladia API](https://docs.gladia.io)** — supporting both **pre-recorded** transcription (REST + automatic polling) and **real-time live streaming** via WebSocket, with full typed event system.
6
+
7
+ > 🌐 **[Version française](README.fr.md)**
8
+
9
+ > 💡 Works everywhere: **Node.js**, **Bun**, **Deno**, and **browsers** — zero runtime dependencies.
10
+
11
+ ## 🎉 Features
12
+
13
+ - 🎤 **Pre-recorded transcription** — upload by file or URL, automatic polling with exponential backoff
14
+ - 🔴 **Live streaming** — typed WebSocket with real-time events (partial, final, speech events)
15
+ - 📤 **Upload** — multipart (file) or JSON (remote URL)
16
+ - 🌍 **Translation, summarization, diarization, sentiment analysis** — and 10+ toggleable addons
17
+ - 🔒 **PII redaction** — personal data masking (GDPR, HIPAA...)
18
+ - 🏷️ **100% typed** — TypeScript interfaces for all 54 API schemas
19
+ - ⚡ **Dual ESM + CJS** — compatible with all bundlers and runtimes
20
+ - 🪶 **0 dependencies** — only native `fetch` and `WebSocket`
21
+ - 🧪 **91 unit tests** — full coverage without any API key required
22
+
23
+ ## 📍 Install
24
+
25
+ ```bash
26
+ npm install @dimer47/gladia-sdk
27
+ ```
28
+
29
+ ```bash
30
+ yarn add @dimer47/gladia-sdk
31
+ ```
32
+
33
+ ```bash
34
+ pnpm add @dimer47/gladia-sdk
35
+ ```
36
+
37
+ ## 🚀 Quick Start
38
+
39
+ ```typescript
40
+ import { GladiaClient } from '@dimer47/gladia-sdk';
41
+
42
+ const gladia = new GladiaClient({ apiKey: 'gla_xxx' });
43
+ ```
44
+
45
+ ## 🕹️ Usage
46
+
47
+ ### 📤 Upload
48
+
49
+ ```typescript
50
+ // From a file (Blob, File, Buffer)
51
+ const uploaded = await gladia.upload.fromFile(myBlob, 'recording.wav');
52
+ console.log(uploaded.audio_url);
53
+
54
+ // From a remote URL
55
+ const uploaded = await gladia.upload.fromUrl('https://example.com/audio.mp3');
56
+ ```
57
+
58
+ ### 🎧 Pre-recorded Transcription
59
+
60
+ #### ✅ Simple mode (POST + automatic polling)
61
+
62
+ ```typescript
63
+ const result = await gladia.preRecorded.transcribe({
64
+ audio_url: 'https://example.com/audio.mp3',
65
+ diarization: true,
66
+ translation: true,
67
+ translation_config: { target_languages: ['en'] },
68
+ onPoll: (res) => console.log(`⏳ ${res.status}...`),
69
+ });
70
+
71
+ console.log(result.result?.transcription?.full_transcript);
72
+ ```
73
+
74
+ #### 🔧 Granular control
75
+
76
+ ```typescript
77
+ // Create a job
78
+ const job = await gladia.preRecorded.create({
79
+ audio_url: 'https://example.com/audio.mp3',
80
+ summarization: true,
81
+ sentiment_analysis: true,
82
+ });
83
+ console.log(`🆔 Job: ${job.id}`);
84
+
85
+ // Check status
86
+ const status = await gladia.preRecorded.get(job.id);
87
+ console.log(`📊 Status: ${status.status}`);
88
+
89
+ // List transcriptions
90
+ const list = await gladia.preRecorded.list({ limit: 10 });
91
+
92
+ // Download the original audio file
93
+ const audioBlob = await gladia.preRecorded.getFile(job.id);
94
+
95
+ // Delete
96
+ await gladia.preRecorded.delete(job.id);
97
+ ```
98
+
99
+ ### 🔴 Live Streaming
100
+
101
+ ```typescript
102
+ const session = await gladia.live.stream({
103
+ encoding: 'wav/pcm',
104
+ sample_rate: 16000,
105
+ language_config: { languages: ['fr'] },
106
+ realtime_processing: {
107
+ translation: true,
108
+ translation_config: { target_languages: ['en'] },
109
+ },
110
+ });
111
+
112
+ // 📝 Listen to final transcriptions
113
+ session.on('transcript:final', (msg) => {
114
+ console.log(`🗣️ ${msg.transcription.text}`);
115
+ });
116
+
117
+ // 📝 Listen to partial transcriptions
118
+ session.on('transcript:partial', (msg) => {
119
+ process.stdout.write(`... ${msg.transcription.text}\r`);
120
+ });
121
+
122
+ // 🎤 Send audio chunks
123
+ session.sendAudio(audioChunk); // ArrayBuffer | Uint8Array | Blob
124
+
125
+ // ⏹️ Stop and wait for processing to finish
126
+ await session.stop();
127
+ ```
128
+
129
+ #### 🔧 Granular live control
130
+
131
+ ```typescript
132
+ // Initialize without opening the WebSocket
133
+ const liveSession = await gladia.live.init(
134
+ { encoding: 'wav/pcm', sample_rate: 16000 },
135
+ { region: 'eu-west' },
136
+ );
137
+ console.log(`🔗 WebSocket URL: ${liveSession.url}`);
138
+
139
+ // List, retrieve, delete
140
+ const sessions = await gladia.live.list({ limit: 5 });
141
+ const session = await gladia.live.get('session-id');
142
+ const audioBlob = await gladia.live.getFile('session-id');
143
+ await gladia.live.delete('session-id');
144
+ ```
145
+
146
+ ## 📦 Available Addons
147
+
148
+ | Addon | Field | Config |
149
+ |-------|-------|--------|
150
+ | 🗣️ Diarization | `diarization` | `diarization_config` |
151
+ | 🌍 Translation | `translation` | `translation_config` |
152
+ | 📝 Summarization | `summarization` | `summarization_config` |
153
+ | 💬 Sentiment Analysis | `sentiment_analysis` | — |
154
+ | 🏷️ Named Entity Recognition (NER) | `named_entity_recognition` | — |
155
+ | 📑 Chapterization | `chapterization` | — |
156
+ | 🔒 PII Redaction | `pii_redaction` | `pii_redaction_config` |
157
+ | 📺 Subtitles | `subtitles` | `subtitles_config` |
158
+ | 🤖 Audio to LLM | `audio_to_llm` | `audio_to_llm_config` |
159
+ | ✏️ Custom Spelling | `custom_spelling` | `custom_spelling_config` |
160
+ | 📊 Structured Data Extraction | `structured_data_extraction` | `structured_data_extraction_config` |
161
+ | 🔤 Custom Vocabulary | `custom_vocabulary` | `custom_vocabulary_config` |
162
+ | 🧑 Name Consistency | `name_consistency` | — |
163
+ | 🖥️ Display Mode | `display_mode` | — |
164
+ | 🚫 Moderation | `moderation` | — |
165
+
166
+ ## 🧮 API Reference
167
+
168
+ ### `GladiaClient`
169
+
170
+ ```typescript
171
+ new GladiaClient(config: GladiaClientConfig)
172
+ ```
173
+
174
+ | Parameter | Type | Description |
175
+ |-----------|------|-------------|
176
+ | `apiKey` | `string` | 🔑 Gladia API key (required) |
177
+ | `baseUrl` | `string?` | Base URL (default: `https://api.gladia.io`) |
178
+ | `WebSocket` | `unknown?` | Custom WebSocket constructor (for Node < 21, pass `ws`) |
179
+
180
+ ---
181
+
182
+ ### `gladia.upload`
183
+
184
+ | Method | Description |
185
+ |--------|-------------|
186
+ | `fromFile(blob, filename?, signal?)` | 📤 Upload a file (multipart) |
187
+ | `fromUrl(url, signal?)` | 🔗 Upload from a remote URL |
188
+
189
+ ---
190
+
191
+ ### `gladia.preRecorded`
192
+
193
+ | Method | Description |
194
+ |--------|-------------|
195
+ | `transcribe(options)` | ✅ POST + automatic polling until completion |
196
+ | `create(request, signal?)` | 📝 Create a transcription job |
197
+ | `get(id, signal?)` | 🔍 Retrieve a job by ID |
198
+ | `list(params?, signal?)` | 📋 List jobs (paginated) |
199
+ | `delete(id, signal?)` | 🗑️ Delete a job |
200
+ | `getFile(id, signal?)` | 💾 Download the original audio file |
201
+
202
+ ---
203
+
204
+ ### `gladia.live`
205
+
206
+ | Method | Description |
207
+ |--------|-------------|
208
+ | `stream(options?)` | 🔴 Init + open WebSocket → `LiveSession` |
209
+ | `init(request?, options?)` | 🔧 Init session (returns the WebSocket URL) |
210
+ | `get(id, signal?)` | 🔍 Retrieve a session by ID |
211
+ | `list(params?, signal?)` | 📋 List sessions (paginated) |
212
+ | `delete(id, signal?)` | 🗑️ Delete a session |
213
+ | `getFile(id, signal?)` | 💾 Download the audio recording |
214
+
215
+ ---
216
+
217
+ ### `LiveSession`
218
+
219
+ | Method / Property | Description |
220
+ |-------------------|-------------|
221
+ | `on(event, listener)` | 👂 Listen to a typed event |
222
+ | `off(event, listener)` | 🔇 Remove a listener |
223
+ | `sendAudio(data)` | 🎤 Send an audio chunk |
224
+ | `stop()` | ⏹️ Signal end and wait for processing |
225
+ | `closed` | `boolean` — WebSocket state |
226
+
227
+ #### 📡 Available Events
228
+
229
+ | Event | Type | Description |
230
+ |-------|------|-------------|
231
+ | `transcript:final` | `LiveTranscriptMessage` | Final transcription of an utterance |
232
+ | `transcript:partial` | `LiveTranscriptMessage` | Partial transcription in progress |
233
+ | `speech-begin` | `LiveSpeechBeginMessage` | Speech start detected |
234
+ | `speech-end` | `LiveSpeechEndMessage` | Speech end detected |
235
+ | `ready` | `LiveReadyMessage` | Session ready to receive audio |
236
+ | `done` | `LiveDoneMessage` | Processing complete |
237
+ | `error` | `LiveErrorMessage` | WebSocket error |
238
+ | `message` | `LiveBaseMessage` | Any raw message (catch-all) |
239
+
240
+ ## ⚠️ Error Handling
241
+
242
+ The SDK provides a typed error hierarchy:
243
+
244
+ ```
245
+ GladiaError
246
+ ├── GladiaApiError (any HTTP error)
247
+ │ ├── BadRequestError (400)
248
+ │ ├── UnauthorizedError (401)
249
+ │ ├── ForbiddenError (403)
250
+ │ ├── NotFoundError (404)
251
+ │ └── UnprocessableEntityError (422)
252
+ ├── GladiaTimeoutError (polling timeout / abort)
253
+ └── GladiaWebSocketError (WebSocket error)
254
+ ```
255
+
256
+ ```typescript
257
+ import { UnauthorizedError, GladiaTimeoutError } from '@dimer47/gladia-sdk';
258
+
259
+ try {
260
+ const result = await gladia.preRecorded.transcribe({
261
+ audio_url: '...',
262
+ pollTimeout: 60_000,
263
+ });
264
+ } catch (err) {
265
+ if (err instanceof UnauthorizedError) {
266
+ console.error('🔑 Invalid API key');
267
+ } else if (err instanceof GladiaTimeoutError) {
268
+ console.error('⏱️ Timeout exceeded');
269
+ }
270
+ }
271
+ ```
272
+
273
+ ## 🌐 Node < 21 Compatibility (WebSocket)
274
+
275
+ Node.js < 21 does not have a global `WebSocket`. Use the [`ws`](https://www.npmjs.com/package/ws) package:
276
+
277
+ ```bash
278
+ npm install ws
279
+ ```
280
+
281
+ ```typescript
282
+ import WebSocket from 'ws';
283
+ import { GladiaClient } from '@dimer47/gladia-sdk';
284
+
285
+ const gladia = new GladiaClient({
286
+ apiKey: 'gla_xxx',
287
+ WebSocket,
288
+ });
289
+ ```
290
+
291
+ ## 🧪 Tests
292
+
293
+ ```bash
294
+ npm test # Run all 91 tests
295
+ npm run test:watch # Watch mode
296
+ ```
297
+
298
+ Tests use mocks (`fetch`, `WebSocket`) — **no API key required**.
299
+
300
+ ## 🏗️ Build
301
+
302
+ ```bash
303
+ npm run build # ESM + CJS + .d.ts via tsup
304
+ npm run typecheck # TypeScript type checking
305
+ ```
306
+
307
+ ## 📁 Project Structure
308
+
309
+ ```
310
+ gladia-sdk/
311
+ ├── src/
312
+ │ ├── index.ts # Public re-exports
313
+ │ ├── client.ts # GladiaClient (facade)
314
+ │ ├── http.ts # HttpClient (fetch wrapper)
315
+ │ ├── errors.ts # Typed error hierarchy
316
+ │ ├── types/ # 54 TypeScript interfaces
317
+ │ │ ├── config.ts # LanguageConfig, DiarizationConfig, PiiRedactionConfig...
318
+ │ │ ├── common.ts # JobStatus, PaginationParams, GladiaClientConfig
319
+ │ │ ├── upload.ts # UploadResponse, AudioMetadata
320
+ │ │ ├── pre-recorded.ts # PreRecordedRequest (31 fields), responses
321
+ │ │ ├── live.ts # LiveRequest, LiveResponse, LiveRequestParams
322
+ │ │ ├── transcription.ts # Utterance, Word, TranscriptionDTO
323
+ │ │ └── addons.ts # AddonTranslationDTO, SentimentAnalysisEntry...
324
+ │ ├── resources/
325
+ │ │ ├── upload.ts # .fromFile(), .fromUrl()
326
+ │ │ ├── pre-recorded.ts # .create(), .get(), .list(), .delete(), .getFile(), .transcribe()
327
+ │ │ └── live.ts # .init(), .get(), .list(), .delete(), .getFile(), .stream()
328
+ │ ├── live/
329
+ │ │ ├── session.ts # LiveSession (typed WebSocket)
330
+ │ │ └── events.ts # LiveEventMap (11 event types)
331
+ │ └── utils/
332
+ │ └── polling.ts # poll() with exponential backoff
333
+ ├── tests/ # 91 unit tests (vitest)
334
+ ├── dist/ # Build output (ESM + CJS + .d.ts)
335
+ ├── package.json
336
+ ├── tsconfig.json
337
+ └── tsup.config.ts
338
+ ```
339
+
340
+ ## 🧾 License
341
+
342
+ [MIT](LICENSE)