voice-router-dev 0.1.6 → 0.1.8

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/dist/index.mjs CHANGED
@@ -144,39 +144,7 @@ var VoiceRouter = class {
144
144
  const adapter = this.getAdapter(provider);
145
145
  return adapter.getTranscript(transcriptId);
146
146
  }
147
- /**
148
- * Stream audio for real-time transcription
149
- * Only works with providers that support streaming
150
- *
151
- * @param options - Streaming options including provider selection
152
- * @param callbacks - Event callbacks for transcription results
153
- * @returns Promise that resolves with a StreamingSession
154
- *
155
- * @example
156
- * ```typescript
157
- * import { VoiceRouter } from '@meeting-baas/sdk';
158
- *
159
- * const router = new VoiceRouter();
160
- * router.initialize({
161
- * gladia: { apiKey: process.env.GLADIA_KEY },
162
- * deepgram: { apiKey: process.env.DEEPGRAM_KEY }
163
- * });
164
- *
165
- * const session = await router.transcribeStream({
166
- * provider: 'deepgram',
167
- * encoding: 'linear16',
168
- * sampleRate: 16000,
169
- * language: 'en'
170
- * }, {
171
- * onTranscript: (event) => console.log(event.text),
172
- * onError: (error) => console.error(error)
173
- * });
174
- *
175
- * // Send audio chunks
176
- * await session.sendAudio({ data: audioBuffer });
177
- * await session.close();
178
- * ```
179
- */
147
+ // Implementation
180
148
  async transcribeStream(options, callbacks) {
181
149
  const provider = this.selectProvider(options?.provider);
182
150
  const adapter = this.getAdapter(provider);
@@ -242,24 +210,102 @@ function createVoiceRouter(config, adapters) {
242
210
  return router;
243
211
  }
244
212
 
213
+ // src/constants/defaults.ts
214
+ var DEFAULT_TIMEOUTS = {
215
+ /** Standard HTTP request timeout for API calls (60 seconds) */
216
+ HTTP_REQUEST: 6e4,
217
+ /** Audio processing timeout for long audio files (120 seconds) */
218
+ AUDIO_PROCESSING: 12e4,
219
+ /** WebSocket connection establishment timeout (10 seconds) */
220
+ WS_CONNECTION: 1e4,
221
+ /** WebSocket graceful close timeout (5 seconds) */
222
+ WS_CLOSE: 5e3
223
+ };
224
+ var DEFAULT_POLLING = {
225
+ /** Maximum number of polling attempts before timing out */
226
+ MAX_ATTEMPTS: 60,
227
+ /** Standard interval between polling attempts (2 seconds) */
228
+ INTERVAL_MS: 2e3,
229
+ /** Slower interval for long-running jobs (3 seconds) */
230
+ SLOW_INTERVAL_MS: 3e3
231
+ };
232
+
233
+ // src/utils/errors.ts
234
+ var ERROR_CODES = {
235
+ /** Failed to parse API response or WebSocket message */
236
+ PARSE_ERROR: "PARSE_ERROR",
237
+ /** WebSocket connection error */
238
+ WEBSOCKET_ERROR: "WEBSOCKET_ERROR",
239
+ /** Async transcription job did not complete within timeout */
240
+ POLLING_TIMEOUT: "POLLING_TIMEOUT",
241
+ /** Transcription processing failed on provider side */
242
+ TRANSCRIPTION_ERROR: "TRANSCRIPTION_ERROR",
243
+ /** Connection attempt timed out */
244
+ CONNECTION_TIMEOUT: "CONNECTION_TIMEOUT",
245
+ /** Invalid input provided to API */
246
+ INVALID_INPUT: "INVALID_INPUT",
247
+ /** Requested operation not supported by provider */
248
+ NOT_SUPPORTED: "NOT_SUPPORTED",
249
+ /** No transcription results available */
250
+ NO_RESULTS: "NO_RESULTS",
251
+ /** Unspecified or unknown error */
252
+ UNKNOWN_ERROR: "UNKNOWN_ERROR"
253
+ };
254
+ var ERROR_MESSAGES = {
255
+ PARSE_ERROR: "Failed to parse response data",
256
+ WEBSOCKET_ERROR: "WebSocket connection error",
257
+ POLLING_TIMEOUT: "Transcription did not complete within timeout period",
258
+ TRANSCRIPTION_ERROR: "Transcription processing failed",
259
+ CONNECTION_TIMEOUT: "Connection attempt timed out",
260
+ INVALID_INPUT: "Invalid input provided",
261
+ NOT_SUPPORTED: "Operation not supported by this provider",
262
+ NO_RESULTS: "No transcription results available",
263
+ UNKNOWN_ERROR: "An unknown error occurred"
264
+ };
265
+ function createError(code, customMessage, details) {
266
+ return {
267
+ code,
268
+ message: customMessage || ERROR_MESSAGES[code],
269
+ details
270
+ };
271
+ }
272
+
245
273
  // src/adapters/base-adapter.ts
246
274
  var BaseAdapter = class {
247
275
  initialize(config) {
248
276
  this.config = config;
249
277
  }
250
278
  /**
251
- * Helper method to create error responses
279
+ * Helper method to create error responses with stack traces
280
+ *
281
+ * @param error - Error object or unknown error
282
+ * @param statusCode - Optional HTTP status code
283
+ * @param code - Optional error code (defaults to extracted or UNKNOWN_ERROR)
252
284
  */
253
- createErrorResponse(error, statusCode) {
285
+ createErrorResponse(error, statusCode, code) {
254
286
  const err = error;
287
+ const httpStatus = statusCode || err.statusCode || err.response?.status;
288
+ const httpStatusText = err.response?.statusText;
289
+ const responseData = err.response?.data;
255
290
  return {
256
291
  success: false,
257
292
  provider: this.name,
258
293
  error: {
259
- code: err.code || "UNKNOWN_ERROR",
294
+ code: code || err.code || ERROR_CODES.UNKNOWN_ERROR,
260
295
  message: err.message || "An unknown error occurred",
261
- statusCode: statusCode || err.statusCode,
262
- details: error
296
+ statusCode: httpStatus,
297
+ details: {
298
+ // Include full error object
299
+ error,
300
+ // Include stack trace if available
301
+ stack: err.stack,
302
+ // Include HTTP response details
303
+ httpStatus,
304
+ httpStatusText,
305
+ responseData,
306
+ // Include provider name for debugging
307
+ provider: this.name
308
+ }
263
309
  }
264
310
  };
265
311
  }
@@ -274,6 +320,64 @@ var BaseAdapter = class {
274
320
  throw new Error(`API key is required for ${this.name} provider`);
275
321
  }
276
322
  }
323
+ /**
324
+ * Build axios config for generated API client functions
325
+ *
326
+ * @param authHeaderName - Header name for API key (e.g., "Authorization", "x-gladia-key")
327
+ * @param authHeaderValue - Optional function to format auth header value (defaults to raw API key)
328
+ * @returns Axios config object
329
+ */
330
+ getAxiosConfig(authHeaderName = "Authorization", authHeaderValue) {
331
+ this.validateConfig();
332
+ const authValue = authHeaderValue ? authHeaderValue(this.config.apiKey) : this.config.apiKey;
333
+ return {
334
+ baseURL: this.config.baseUrl || this.baseUrl,
335
+ timeout: this.config.timeout || DEFAULT_TIMEOUTS.HTTP_REQUEST,
336
+ headers: {
337
+ [authHeaderName]: authValue,
338
+ "Content-Type": "application/json",
339
+ ...this.config.headers
340
+ }
341
+ };
342
+ }
343
+ /**
344
+ * Generic polling helper for async transcription jobs
345
+ *
346
+ * Polls getTranscript() until job completes or times out.
347
+ *
348
+ * @param transcriptId - Job/transcript ID to poll
349
+ * @param options - Polling configuration
350
+ * @returns Final transcription result
351
+ */
352
+ async pollForCompletion(transcriptId, options) {
353
+ const { maxAttempts = DEFAULT_POLLING.MAX_ATTEMPTS, intervalMs = DEFAULT_POLLING.INTERVAL_MS } = options || {};
354
+ for (let attempt = 0; attempt < maxAttempts; attempt++) {
355
+ const result = await this.getTranscript(transcriptId);
356
+ if (!result.success) {
357
+ return result;
358
+ }
359
+ const status = result.data?.status;
360
+ if (status === "completed") {
361
+ return result;
362
+ }
363
+ if (status === "error") {
364
+ return this.createErrorResponse(
365
+ new Error("Transcription failed"),
366
+ void 0,
367
+ ERROR_CODES.TRANSCRIPTION_ERROR
368
+ );
369
+ }
370
+ await new Promise((resolve) => setTimeout(resolve, intervalMs));
371
+ }
372
+ return {
373
+ success: false,
374
+ provider: this.name,
375
+ error: {
376
+ code: ERROR_CODES.POLLING_TIMEOUT,
377
+ message: `Transcription did not complete after ${maxAttempts} attempts`
378
+ }
379
+ };
380
+ }
277
381
  };
278
382
 
279
383
  // src/adapters/gladia-adapter.ts
@@ -320,6 +424,143 @@ function mapEncodingToProvider(unifiedEncoding, provider) {
320
424
  return providerEncoding;
321
425
  }
322
426
 
427
+ // src/utils/websocket-helpers.ts
428
+ function waitForWebSocketOpen(ws, timeoutMs = DEFAULT_TIMEOUTS.WS_CONNECTION) {
429
+ return new Promise((resolve, reject) => {
430
+ const timeout = setTimeout(() => {
431
+ reject(new Error("WebSocket connection timeout"));
432
+ }, timeoutMs);
433
+ ws.once("open", () => {
434
+ clearTimeout(timeout);
435
+ resolve();
436
+ });
437
+ ws.once("error", (error) => {
438
+ clearTimeout(timeout);
439
+ reject(error);
440
+ });
441
+ });
442
+ }
443
+ function closeWebSocket(ws, timeoutMs = DEFAULT_TIMEOUTS.WS_CLOSE) {
444
+ return new Promise((resolve) => {
445
+ const timeout = setTimeout(() => {
446
+ ws.terminate();
447
+ resolve();
448
+ }, timeoutMs);
449
+ ws.close();
450
+ ws.once("close", () => {
451
+ clearTimeout(timeout);
452
+ resolve();
453
+ });
454
+ });
455
+ }
456
+ function setupWebSocketHandlers(ws, callbacks, setSessionStatus) {
457
+ ws.on("open", () => {
458
+ setSessionStatus("open");
459
+ callbacks?.onOpen?.();
460
+ });
461
+ ws.on("error", (error) => {
462
+ callbacks?.onError?.(createError(ERROR_CODES.WEBSOCKET_ERROR, error.message, error));
463
+ });
464
+ ws.on("close", (code, reason) => {
465
+ setSessionStatus("closed");
466
+ callbacks?.onClose?.(code, reason.toString());
467
+ });
468
+ }
469
+ function validateSessionForAudio(sessionStatus, wsReadyState, WebSocketOpen) {
470
+ if (sessionStatus !== "open") {
471
+ throw new Error(`Cannot send audio: session is ${sessionStatus}`);
472
+ }
473
+ if (wsReadyState !== WebSocketOpen) {
474
+ throw new Error("WebSocket is not open");
475
+ }
476
+ }
477
+
478
+ // src/utils/validation.ts
479
+ function validateEnumValue(value, enumType, fieldName, provider) {
480
+ const validValues = Object.values(enumType);
481
+ const isValid = validValues.some((v) => v === value);
482
+ if (!isValid) {
483
+ throw new Error(
484
+ `${provider} does not support ${fieldName} '${value}'. Supported values (from OpenAPI spec): ${validValues.join(", ")}`
485
+ );
486
+ }
487
+ return value;
488
+ }
489
+
490
+ // src/utils/transcription-helpers.ts
491
+ function extractSpeakersFromUtterances(utterances, getSpeakerId, formatLabel) {
492
+ if (!utterances || utterances.length === 0) {
493
+ return void 0;
494
+ }
495
+ const speakerSet = /* @__PURE__ */ new Set();
496
+ utterances.forEach((utterance) => {
497
+ const speakerId = getSpeakerId(utterance);
498
+ if (speakerId !== void 0) {
499
+ speakerSet.add(String(speakerId));
500
+ }
501
+ });
502
+ if (speakerSet.size === 0) {
503
+ return void 0;
504
+ }
505
+ return Array.from(speakerSet).map((speakerId) => ({
506
+ id: speakerId,
507
+ label: formatLabel ? formatLabel(speakerId) : `Speaker ${speakerId}`
508
+ }));
509
+ }
510
+ function extractWords(words, mapper) {
511
+ if (!words || words.length === 0) {
512
+ return void 0;
513
+ }
514
+ const normalizedWords = words.map(mapper);
515
+ return normalizedWords.length > 0 ? normalizedWords : void 0;
516
+ }
517
+ var STATUS_MAPPINGS = {
518
+ gladia: {
519
+ queued: "queued",
520
+ processing: "processing",
521
+ done: "completed",
522
+ error: "error"
523
+ },
524
+ assemblyai: {
525
+ queued: "queued",
526
+ processing: "processing",
527
+ completed: "completed",
528
+ error: "error"
529
+ },
530
+ deepgram: {
531
+ queued: "queued",
532
+ processing: "processing",
533
+ completed: "completed",
534
+ error: "error"
535
+ },
536
+ azure: {
537
+ succeeded: "completed",
538
+ running: "processing",
539
+ notstarted: "queued",
540
+ failed: "error"
541
+ },
542
+ speechmatics: {
543
+ running: "processing",
544
+ done: "completed",
545
+ rejected: "error",
546
+ expired: "error"
547
+ }
548
+ };
549
+ function normalizeStatus(providerStatus, provider, defaultStatus = "queued") {
550
+ if (!providerStatus) return defaultStatus;
551
+ const mapping = STATUS_MAPPINGS[provider];
552
+ const statusKey = providerStatus.toString().toLowerCase();
553
+ if (statusKey in mapping) {
554
+ return mapping[statusKey];
555
+ }
556
+ for (const [key, value] of Object.entries(mapping)) {
557
+ if (statusKey.includes(key)) {
558
+ return value;
559
+ }
560
+ }
561
+ return defaultStatus;
562
+ }
563
+
323
564
  // src/generated/gladia/api/gladiaControlAPI.ts
324
565
  import axios from "axios";
325
566
 
@@ -1440,21 +1681,10 @@ var GladiaAdapter = class extends BaseAdapter {
1440
1681
  }
1441
1682
  /**
1442
1683
  * Get axios config for generated API client functions
1443
- * Configures headers and base URL
1684
+ * Configures headers and base URL using Gladia's x-gladia-key header
1444
1685
  */
1445
1686
  getAxiosConfig() {
1446
- if (!this.config) {
1447
- throw new Error("Adapter not initialized. Call initialize() first.");
1448
- }
1449
- return {
1450
- baseURL: this.config.baseUrl || this.baseUrl,
1451
- timeout: this.config.timeout || 6e4,
1452
- headers: {
1453
- "x-gladia-key": this.config.apiKey,
1454
- "Content-Type": "application/json",
1455
- ...this.config.headers
1456
- }
1457
- };
1687
+ return super.getAxiosConfig("x-gladia-key");
1458
1688
  }
1459
1689
  /**
1460
1690
  * Submit audio for transcription
@@ -1621,29 +1851,13 @@ var GladiaAdapter = class extends BaseAdapter {
1621
1851
  * Normalize Gladia response to unified format
1622
1852
  */
1623
1853
  normalizeResponse(response) {
1624
- let status;
1625
- switch (response.status) {
1626
- case "queued":
1627
- status = "queued";
1628
- break;
1629
- case "processing":
1630
- status = "processing";
1631
- break;
1632
- case "done":
1633
- status = "completed";
1634
- break;
1635
- case "error":
1636
- status = "error";
1637
- break;
1638
- default:
1639
- status = "queued";
1640
- }
1854
+ const status = normalizeStatus(response.status, "gladia");
1641
1855
  if (response.status === "error") {
1642
1856
  return {
1643
1857
  success: false,
1644
1858
  provider: this.name,
1645
1859
  error: {
1646
- code: response.error_code?.toString() || "TRANSCRIPTION_ERROR",
1860
+ code: response.error_code?.toString() || ERROR_CODES.TRANSCRIPTION_ERROR,
1647
1861
  message: "Transcription failed",
1648
1862
  statusCode: response.error_code || void 0
1649
1863
  },
@@ -1683,22 +1897,11 @@ var GladiaAdapter = class extends BaseAdapter {
1683
1897
  * Extract speaker information from Gladia response
1684
1898
  */
1685
1899
  extractSpeakers(transcription) {
1686
- if (!transcription?.utterances) {
1687
- return void 0;
1688
- }
1689
- const speakerSet = /* @__PURE__ */ new Set();
1690
- transcription.utterances.forEach((utterance) => {
1691
- if (utterance.speaker !== void 0) {
1692
- speakerSet.add(utterance.speaker);
1693
- }
1694
- });
1695
- if (speakerSet.size === 0) {
1696
- return void 0;
1697
- }
1698
- return Array.from(speakerSet).map((speakerId) => ({
1699
- id: speakerId.toString(),
1700
- label: `Speaker ${speakerId}`
1701
- }));
1900
+ return extractSpeakersFromUtterances(
1901
+ transcription?.utterances,
1902
+ (utterance) => utterance.speaker,
1903
+ (id) => `Speaker ${id}`
1904
+ );
1702
1905
  }
1703
1906
  /**
1704
1907
  * Extract word timestamps from Gladia response
@@ -1709,14 +1912,17 @@ var GladiaAdapter = class extends BaseAdapter {
1709
1912
  }
1710
1913
  const allWords = transcription.utterances.flatMap(
1711
1914
  (utterance) => utterance.words.map((word) => ({
1712
- text: word.word,
1713
- start: word.start,
1714
- end: word.end,
1715
- confidence: word.confidence,
1716
- speaker: utterance.speaker?.toString()
1915
+ word,
1916
+ speaker: utterance.speaker
1717
1917
  }))
1718
1918
  );
1719
- return allWords.length > 0 ? allWords : void 0;
1919
+ return extractWords(allWords, (item) => ({
1920
+ text: item.word.word,
1921
+ start: item.word.start,
1922
+ end: item.word.end,
1923
+ confidence: item.word.confidence,
1924
+ speaker: item.speaker?.toString()
1925
+ }));
1720
1926
  }
1721
1927
  /**
1722
1928
  * Extract utterances from Gladia response
@@ -1742,38 +1948,6 @@ var GladiaAdapter = class extends BaseAdapter {
1742
1948
  /**
1743
1949
  * Poll for transcription completion
1744
1950
  */
1745
- async pollForCompletion(jobId, maxAttempts = 60, intervalMs = 2e3) {
1746
- for (let attempt = 0; attempt < maxAttempts; attempt++) {
1747
- const result = await this.getTranscript(jobId);
1748
- if (!result.success) {
1749
- return result;
1750
- }
1751
- const status = result.data?.status;
1752
- if (status === "completed") {
1753
- return result;
1754
- }
1755
- if (status === "error") {
1756
- return {
1757
- success: false,
1758
- provider: this.name,
1759
- error: {
1760
- code: "TRANSCRIPTION_ERROR",
1761
- message: "Transcription failed"
1762
- },
1763
- raw: result.raw
1764
- };
1765
- }
1766
- await new Promise((resolve) => setTimeout(resolve, intervalMs));
1767
- }
1768
- return {
1769
- success: false,
1770
- provider: this.name,
1771
- error: {
1772
- code: "POLLING_TIMEOUT",
1773
- message: `Transcription did not complete after ${maxAttempts} attempts`
1774
- }
1775
- };
1776
- }
1777
1951
  /**
1778
1952
  * Stream audio for real-time transcription
1779
1953
  *
@@ -1817,14 +1991,12 @@ var GladiaAdapter = class extends BaseAdapter {
1817
1991
  this.validateConfig();
1818
1992
  let validatedSampleRate;
1819
1993
  if (options?.sampleRate) {
1820
- const validRates = Object.values(StreamingSupportedSampleRateEnum);
1821
- const isValidRate = validRates.some((rate) => rate === options.sampleRate);
1822
- if (!isValidRate) {
1823
- throw new Error(
1824
- `Gladia does not support sample rate ${options.sampleRate} Hz. Supported rates (from OpenAPI spec): ${validRates.join(", ")} Hz`
1825
- );
1826
- }
1827
- validatedSampleRate = options.sampleRate;
1994
+ validatedSampleRate = validateEnumValue(
1995
+ options.sampleRate,
1996
+ StreamingSupportedSampleRateEnum,
1997
+ "sample rate",
1998
+ "Gladia"
1999
+ );
1828
2000
  }
1829
2001
  const streamingRequest = {
1830
2002
  encoding: options?.encoding ? mapEncodingToProvider(options.encoding, "gladia") : void 0,
@@ -1846,9 +2018,8 @@ var GladiaAdapter = class extends BaseAdapter {
1846
2018
  const { id, url: wsUrl } = initResponse.data;
1847
2019
  const ws = new WebSocket(wsUrl);
1848
2020
  let sessionStatus = "connecting";
1849
- ws.on("open", () => {
1850
- sessionStatus = "open";
1851
- callbacks?.onOpen?.();
2021
+ setupWebSocketHandlers(ws, callbacks, (status) => {
2022
+ sessionStatus = status;
1852
2023
  });
1853
2024
  ws.on("message", (data) => {
1854
2025
  try {
@@ -1893,48 +2064,20 @@ var GladiaAdapter = class extends BaseAdapter {
1893
2064
  }
1894
2065
  } catch (error) {
1895
2066
  callbacks?.onError?.({
1896
- code: "PARSE_ERROR",
2067
+ code: ERROR_CODES.PARSE_ERROR,
1897
2068
  message: "Failed to parse WebSocket message",
1898
2069
  details: error
1899
2070
  });
1900
2071
  }
1901
2072
  });
1902
- ws.on("error", (error) => {
1903
- callbacks?.onError?.({
1904
- code: "WEBSOCKET_ERROR",
1905
- message: error.message,
1906
- details: error
1907
- });
1908
- });
1909
- ws.on("close", (code, reason) => {
1910
- sessionStatus = "closed";
1911
- callbacks?.onClose?.(code, reason.toString());
1912
- });
1913
- await new Promise((resolve, reject) => {
1914
- const timeout = setTimeout(() => {
1915
- reject(new Error("WebSocket connection timeout"));
1916
- }, 1e4);
1917
- ws.once("open", () => {
1918
- clearTimeout(timeout);
1919
- resolve();
1920
- });
1921
- ws.once("error", (error) => {
1922
- clearTimeout(timeout);
1923
- reject(error);
1924
- });
1925
- });
2073
+ await waitForWebSocketOpen(ws);
1926
2074
  return {
1927
2075
  id,
1928
2076
  provider: this.name,
1929
2077
  createdAt: /* @__PURE__ */ new Date(),
1930
2078
  getStatus: () => sessionStatus,
1931
2079
  sendAudio: async (chunk) => {
1932
- if (sessionStatus !== "open") {
1933
- throw new Error(`Cannot send audio: session is ${sessionStatus}`);
1934
- }
1935
- if (ws.readyState !== WebSocket.OPEN) {
1936
- throw new Error("WebSocket is not open");
1937
- }
2080
+ validateSessionForAudio(sessionStatus, ws.readyState, WebSocket.OPEN);
1938
2081
  ws.send(chunk.data);
1939
2082
  if (chunk.isLast) {
1940
2083
  ws.send(
@@ -1956,18 +2099,8 @@ var GladiaAdapter = class extends BaseAdapter {
1956
2099
  })
1957
2100
  );
1958
2101
  }
1959
- return new Promise((resolve) => {
1960
- const timeout = setTimeout(() => {
1961
- ws.terminate();
1962
- resolve();
1963
- }, 5e3);
1964
- ws.close();
1965
- ws.once("close", () => {
1966
- clearTimeout(timeout);
1967
- sessionStatus = "closed";
1968
- resolve();
1969
- });
1970
- });
2102
+ await closeWebSocket(ws);
2103
+ sessionStatus = "closed";
1971
2104
  }
1972
2105
  };
1973
2106
  }
@@ -2321,26 +2454,16 @@ var AssemblyAIAdapter = class extends BaseAdapter {
2321
2454
  entityDetection: true,
2322
2455
  piiRedaction: true
2323
2456
  };
2324
- this.baseUrl = "https://api.assemblyai.com/v2";
2457
+ this.baseUrl = "https://api.assemblyai.com";
2458
+ // Generated functions already include /v2 path
2325
2459
  this.wsBaseUrl = "wss://api.assemblyai.com/v2/realtime/ws";
2326
2460
  }
2327
2461
  /**
2328
2462
  * Get axios config for generated API client functions
2329
- * Configures headers and base URL
2463
+ * Configures headers and base URL using authorization header
2330
2464
  */
2331
2465
  getAxiosConfig() {
2332
- if (!this.config) {
2333
- throw new Error("Adapter not initialized. Call initialize() first.");
2334
- }
2335
- return {
2336
- baseURL: this.config.baseUrl || this.baseUrl,
2337
- timeout: this.config.timeout || 6e4,
2338
- headers: {
2339
- authorization: this.config.apiKey,
2340
- "Content-Type": "application/json",
2341
- ...this.config.headers
2342
- }
2343
- };
2466
+ return super.getAxiosConfig("authorization");
2344
2467
  }
2345
2468
  /**
2346
2469
  * Submit audio for transcription
@@ -2618,41 +2741,6 @@ var AssemblyAIAdapter = class extends BaseAdapter {
2618
2741
  }))
2619
2742
  }));
2620
2743
  }
2621
- /**
2622
- * Poll for transcription completion
2623
- */
2624
- async pollForCompletion(transcriptId, maxAttempts = 60, intervalMs = 3e3) {
2625
- for (let attempt = 0; attempt < maxAttempts; attempt++) {
2626
- const result = await this.getTranscript(transcriptId);
2627
- if (!result.success) {
2628
- return result;
2629
- }
2630
- const status = result.data?.status;
2631
- if (status === "completed") {
2632
- return result;
2633
- }
2634
- if (status === "error") {
2635
- return {
2636
- success: false,
2637
- provider: this.name,
2638
- error: {
2639
- code: "TRANSCRIPTION_ERROR",
2640
- message: "Transcription failed"
2641
- },
2642
- raw: result.raw
2643
- };
2644
- }
2645
- await new Promise((resolve) => setTimeout(resolve, intervalMs));
2646
- }
2647
- return {
2648
- success: false,
2649
- provider: this.name,
2650
- error: {
2651
- code: "POLLING_TIMEOUT",
2652
- message: `Transcription did not complete after ${maxAttempts} attempts`
2653
- }
2654
- };
2655
- }
2656
2744
  /**
2657
2745
  * Stream audio for real-time transcription
2658
2746
  *
@@ -3294,7 +3382,24 @@ function createDeepgramAdapter(config) {
3294
3382
  }
3295
3383
 
3296
3384
  // src/adapters/azure-stt-adapter.ts
3385
+ import axios5 from "axios";
3386
+
3387
+ // src/generated/azure/api/speechServicesAPIV31.ts
3297
3388
  import axios4 from "axios";
3389
+ var transcriptionsCreate = (transcription, options) => {
3390
+ return axios4.post("/transcriptions", transcription, options);
3391
+ };
3392
+ var transcriptionsGet = (id, options) => {
3393
+ return axios4.get(`/transcriptions/${id}`, options);
3394
+ };
3395
+ var transcriptionsListFiles = (id, params, options) => {
3396
+ return axios4.get(`/transcriptions/${id}/files`, {
3397
+ ...options,
3398
+ params: { ...params, ...options?.params }
3399
+ });
3400
+ };
3401
+
3402
+ // src/adapters/azure-stt-adapter.ts
3298
3403
  var AzureSTTAdapter = class extends BaseAdapter {
3299
3404
  constructor() {
3300
3405
  super(...arguments);
@@ -3311,20 +3416,20 @@ var AzureSTTAdapter = class extends BaseAdapter {
3311
3416
  entityDetection: false,
3312
3417
  piiRedaction: false
3313
3418
  };
3419
+ this.baseUrl = "https://eastus.api.cognitive.microsoft.com/speechtotext/v3.1";
3314
3420
  }
3421
+ // Default, overridden in initialize()
3315
3422
  initialize(config) {
3316
3423
  super.initialize(config);
3317
3424
  this.region = config.region || "eastus";
3318
3425
  this.baseUrl = config.baseUrl || `https://${this.region}.api.cognitive.microsoft.com/speechtotext/v3.1`;
3319
- this.client = axios4.create({
3320
- baseURL: this.baseUrl,
3321
- timeout: config.timeout || 6e4,
3322
- headers: {
3323
- "Ocp-Apim-Subscription-Key": config.apiKey,
3324
- "Content-Type": "application/json",
3325
- ...config.headers
3326
- }
3327
- });
3426
+ }
3427
+ /**
3428
+ * Get axios config for generated API client functions
3429
+ * Configures headers and base URL using Azure subscription key
3430
+ */
3431
+ getAxiosConfig() {
3432
+ return super.getAxiosConfig("Ocp-Apim-Subscription-Key");
3328
3433
  }
3329
3434
  /**
3330
3435
  * Submit audio for transcription
@@ -3356,9 +3461,9 @@ var AzureSTTAdapter = class extends BaseAdapter {
3356
3461
  contentUrls: [audio.url],
3357
3462
  properties: this.buildTranscriptionProperties(options)
3358
3463
  };
3359
- const response = await this.client.post(
3360
- "/transcriptions",
3361
- transcriptionRequest
3464
+ const response = await transcriptionsCreate(
3465
+ transcriptionRequest,
3466
+ this.getAxiosConfig()
3362
3467
  );
3363
3468
  const transcription = response.data;
3364
3469
  return {
@@ -3389,9 +3494,7 @@ var AzureSTTAdapter = class extends BaseAdapter {
3389
3494
  async getTranscript(transcriptId) {
3390
3495
  this.validateConfig();
3391
3496
  try {
3392
- const statusResponse = await this.client.get(
3393
- `/transcriptions/${transcriptId}`
3394
- );
3497
+ const statusResponse = await transcriptionsGet(transcriptId, this.getAxiosConfig());
3395
3498
  const transcription = statusResponse.data;
3396
3499
  const status = this.normalizeStatus(transcription.status);
3397
3500
  if (status !== "completed") {
@@ -3419,7 +3522,11 @@ var AzureSTTAdapter = class extends BaseAdapter {
3419
3522
  raw: transcription
3420
3523
  };
3421
3524
  }
3422
- const filesResponse = await this.client.get(transcription.links.files);
3525
+ const filesResponse = await transcriptionsListFiles(
3526
+ transcriptId,
3527
+ void 0,
3528
+ this.getAxiosConfig()
3529
+ );
3423
3530
  const files = filesResponse.data?.values || [];
3424
3531
  const resultFile = files.find((file) => file.kind === "Transcription");
3425
3532
  if (!resultFile?.links?.contentUrl) {
@@ -3433,7 +3540,7 @@ var AzureSTTAdapter = class extends BaseAdapter {
3433
3540
  raw: transcription
3434
3541
  };
3435
3542
  }
3436
- const contentResponse = await axios4.get(resultFile.links.contentUrl);
3543
+ const contentResponse = await axios5.get(resultFile.links.contentUrl);
3437
3544
  const transcriptionData = contentResponse.data;
3438
3545
  return this.normalizeResponse(transcription, transcriptionData);
3439
3546
  } catch (error) {
@@ -3532,7 +3639,57 @@ function createAzureSTTAdapter(config) {
3532
3639
  }
3533
3640
 
3534
3641
  // src/adapters/openai-whisper-adapter.ts
3535
- import axios5 from "axios";
3642
+ import axios7 from "axios";
3643
+
3644
+ // src/generated/openai/api/openAIAPI.ts
3645
+ import axios6 from "axios";
3646
+ var createTranscription = (createTranscriptionRequest, options) => {
3647
+ const formData = new FormData();
3648
+ formData.append("file", createTranscriptionRequest.file);
3649
+ formData.append("model", createTranscriptionRequest.model);
3650
+ if (createTranscriptionRequest.language !== void 0) {
3651
+ formData.append("language", createTranscriptionRequest.language);
3652
+ }
3653
+ if (createTranscriptionRequest.prompt !== void 0) {
3654
+ formData.append("prompt", createTranscriptionRequest.prompt);
3655
+ }
3656
+ if (createTranscriptionRequest.response_format !== void 0) {
3657
+ formData.append("response_format", createTranscriptionRequest.response_format);
3658
+ }
3659
+ if (createTranscriptionRequest.temperature !== void 0) {
3660
+ formData.append("temperature", createTranscriptionRequest.temperature.toString());
3661
+ }
3662
+ if (createTranscriptionRequest.include !== void 0) {
3663
+ createTranscriptionRequest.include.forEach((value) => formData.append("include", value));
3664
+ }
3665
+ if (createTranscriptionRequest.timestamp_granularities !== void 0) {
3666
+ createTranscriptionRequest.timestamp_granularities.forEach(
3667
+ (value) => formData.append("timestamp_granularities", value)
3668
+ );
3669
+ }
3670
+ if (createTranscriptionRequest.stream !== void 0 && createTranscriptionRequest.stream !== null) {
3671
+ formData.append("stream", createTranscriptionRequest.stream.toString());
3672
+ }
3673
+ if (createTranscriptionRequest.chunking_strategy !== void 0 && createTranscriptionRequest.chunking_strategy !== null) {
3674
+ formData.append(
3675
+ "chunking_strategy",
3676
+ typeof createTranscriptionRequest.chunking_strategy === "object" ? JSON.stringify(createTranscriptionRequest.chunking_strategy) : createTranscriptionRequest.chunking_strategy
3677
+ );
3678
+ }
3679
+ if (createTranscriptionRequest.known_speaker_names !== void 0) {
3680
+ createTranscriptionRequest.known_speaker_names.forEach(
3681
+ (value) => formData.append("known_speaker_names", value)
3682
+ );
3683
+ }
3684
+ if (createTranscriptionRequest.known_speaker_references !== void 0) {
3685
+ createTranscriptionRequest.known_speaker_references.forEach(
3686
+ (value) => formData.append("known_speaker_references", value)
3687
+ );
3688
+ }
3689
+ return axios6.post("/audio/transcriptions", formData, options);
3690
+ };
3691
+
3692
+ // src/adapters/openai-whisper-adapter.ts
3536
3693
  var OpenAIWhisperAdapter = class extends BaseAdapter {
3537
3694
  constructor() {
3538
3695
  super(...arguments);
@@ -3554,19 +3711,12 @@ var OpenAIWhisperAdapter = class extends BaseAdapter {
3554
3711
  };
3555
3712
  this.baseUrl = "https://api.openai.com/v1";
3556
3713
  }
3557
- initialize(config) {
3558
- super.initialize(config);
3559
- this.baseUrl = config.baseUrl || this.baseUrl;
3560
- this.client = axios5.create({
3561
- baseURL: this.baseUrl,
3562
- timeout: config.timeout || 12e4,
3563
- // 2 minutes default (audio processing can take time)
3564
- headers: {
3565
- Authorization: `Bearer ${config.apiKey}`,
3566
- "Content-Type": "multipart/form-data",
3567
- ...config.headers
3568
- }
3569
- });
3714
+ /**
3715
+ * Get axios config for generated API client functions
3716
+ * Configures headers and base URL using Bearer token authorization
3717
+ */
3718
+ getAxiosConfig() {
3719
+ return super.getAxiosConfig("Authorization", (apiKey) => `Bearer ${apiKey}`);
3570
3720
  }
3571
3721
  /**
3572
3722
  * Submit audio for transcription
@@ -3588,7 +3738,7 @@ var OpenAIWhisperAdapter = class extends BaseAdapter {
3588
3738
  let audioData;
3589
3739
  let fileName = "audio.mp3";
3590
3740
  if (audio.type === "url") {
3591
- const response2 = await axios5.get(audio.url, {
3741
+ const response2 = await axios7.get(audio.url, {
3592
3742
  responseType: "arraybuffer"
3593
3743
  });
3594
3744
  audioData = Buffer.from(response2.data);
@@ -3613,40 +3763,37 @@ var OpenAIWhisperAdapter = class extends BaseAdapter {
3613
3763
  const model = this.selectModel(options);
3614
3764
  const isDiarization = model === "gpt-4o-transcribe-diarize";
3615
3765
  const needsWords = options?.wordTimestamps === true;
3616
- const requestBody = {
3766
+ const request = {
3617
3767
  file: audioData,
3768
+ // Generated type expects Blob
3618
3769
  model
3619
3770
  };
3620
3771
  if (options?.language) {
3621
- requestBody.language = options.language;
3772
+ request.language = options.language;
3622
3773
  }
3623
3774
  if (options?.metadata?.prompt) {
3624
- requestBody.prompt = options.metadata.prompt;
3775
+ request.prompt = options.metadata.prompt;
3625
3776
  }
3626
3777
  if (options?.metadata?.temperature !== void 0) {
3627
- requestBody.temperature = options.metadata.temperature;
3778
+ request.temperature = options.metadata.temperature;
3628
3779
  }
3629
3780
  if (isDiarization) {
3630
- requestBody.response_format = "diarized_json";
3781
+ request.response_format = "diarized_json";
3631
3782
  if (options?.metadata?.knownSpeakerNames) {
3632
- requestBody["known_speaker_names"] = options.metadata.knownSpeakerNames;
3783
+ request.known_speaker_names = options.metadata.knownSpeakerNames;
3633
3784
  }
3634
3785
  if (options?.metadata?.knownSpeakerReferences) {
3635
- requestBody["known_speaker_references"] = options.metadata.knownSpeakerReferences;
3786
+ request.known_speaker_references = options.metadata.knownSpeakerReferences;
3636
3787
  }
3637
3788
  } else if (needsWords || options?.diarization) {
3638
- requestBody.response_format = "verbose_json";
3789
+ request.response_format = "verbose_json";
3639
3790
  if (needsWords) {
3640
- requestBody.timestamp_granularities = ["word", "segment"];
3791
+ request.timestamp_granularities = ["word", "segment"];
3641
3792
  }
3642
3793
  } else {
3643
- requestBody.response_format = "json";
3794
+ request.response_format = "json";
3644
3795
  }
3645
- const response = await this.client.post("/audio/transcriptions", requestBody, {
3646
- headers: {
3647
- "Content-Type": "multipart/form-data"
3648
- }
3649
- });
3796
+ const response = await createTranscription(request, this.getAxiosConfig());
3650
3797
  return this.normalizeResponse(response.data, model, isDiarization);
3651
3798
  } catch (error) {
3652
3799
  return this.createErrorResponse(error);
@@ -3767,7 +3914,7 @@ function createOpenAIWhisperAdapter(config) {
3767
3914
  }
3768
3915
 
3769
3916
  // src/adapters/speechmatics-adapter.ts
3770
- import axios6 from "axios";
3917
+ import axios8 from "axios";
3771
3918
  var SpeechmaticsAdapter = class extends BaseAdapter {
3772
3919
  constructor() {
3773
3920
  super(...arguments);
@@ -3789,7 +3936,7 @@ var SpeechmaticsAdapter = class extends BaseAdapter {
3789
3936
  initialize(config) {
3790
3937
  super.initialize(config);
3791
3938
  this.baseUrl = config.baseUrl || this.baseUrl;
3792
- this.client = axios6.create({
3939
+ this.client = axios8.create({
3793
3940
  baseURL: this.baseUrl,
3794
3941
  timeout: config.timeout || 12e4,
3795
3942
  headers: {