@deepgram/sdk 4.5.1 → 4.7.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.
Files changed (55) hide show
  1. package/dist/main/lib/errors.d.ts +33 -0
  2. package/dist/main/lib/errors.d.ts.map +1 -1
  3. package/dist/main/lib/errors.js +35 -1
  4. package/dist/main/lib/errors.js.map +1 -1
  5. package/dist/main/lib/version.d.ts +1 -1
  6. package/dist/main/lib/version.js +1 -1
  7. package/dist/main/packages/AbstractClient.d.ts +1 -0
  8. package/dist/main/packages/AbstractClient.d.ts.map +1 -1
  9. package/dist/main/packages/AbstractClient.js +9 -3
  10. package/dist/main/packages/AbstractClient.js.map +1 -1
  11. package/dist/main/packages/AbstractLiveClient.d.ts +163 -0
  12. package/dist/main/packages/AbstractLiveClient.d.ts.map +1 -1
  13. package/dist/main/packages/AbstractLiveClient.js +162 -0
  14. package/dist/main/packages/AbstractLiveClient.js.map +1 -1
  15. package/dist/main/packages/AgentLiveClient.d.ts.map +1 -1
  16. package/dist/main/packages/AgentLiveClient.js +15 -10
  17. package/dist/main/packages/AgentLiveClient.js.map +1 -1
  18. package/dist/main/packages/ListenLiveClient.d.ts.map +1 -1
  19. package/dist/main/packages/ListenLiveClient.js +12 -9
  20. package/dist/main/packages/ListenLiveClient.js.map +1 -1
  21. package/dist/main/packages/SpeakLiveClient.d.ts.map +1 -1
  22. package/dist/main/packages/SpeakLiveClient.js +15 -9
  23. package/dist/main/packages/SpeakLiveClient.js.map +1 -1
  24. package/dist/module/lib/errors.d.ts +33 -0
  25. package/dist/module/lib/errors.d.ts.map +1 -1
  26. package/dist/module/lib/errors.js +33 -0
  27. package/dist/module/lib/errors.js.map +1 -1
  28. package/dist/module/lib/version.d.ts +1 -1
  29. package/dist/module/lib/version.js +1 -1
  30. package/dist/module/packages/AbstractClient.d.ts +1 -0
  31. package/dist/module/packages/AbstractClient.d.ts.map +1 -1
  32. package/dist/module/packages/AbstractClient.js +9 -3
  33. package/dist/module/packages/AbstractClient.js.map +1 -1
  34. package/dist/module/packages/AbstractLiveClient.d.ts +163 -0
  35. package/dist/module/packages/AbstractLiveClient.d.ts.map +1 -1
  36. package/dist/module/packages/AbstractLiveClient.js +162 -0
  37. package/dist/module/packages/AbstractLiveClient.js.map +1 -1
  38. package/dist/module/packages/AgentLiveClient.d.ts.map +1 -1
  39. package/dist/module/packages/AgentLiveClient.js +15 -10
  40. package/dist/module/packages/AgentLiveClient.js.map +1 -1
  41. package/dist/module/packages/ListenLiveClient.d.ts.map +1 -1
  42. package/dist/module/packages/ListenLiveClient.js +12 -9
  43. package/dist/module/packages/ListenLiveClient.js.map +1 -1
  44. package/dist/module/packages/SpeakLiveClient.d.ts.map +1 -1
  45. package/dist/module/packages/SpeakLiveClient.js +15 -9
  46. package/dist/module/packages/SpeakLiveClient.js.map +1 -1
  47. package/dist/umd/deepgram.js +1 -1
  48. package/package.json +1 -1
  49. package/src/lib/errors.ts +52 -0
  50. package/src/lib/version.ts +1 -1
  51. package/src/packages/AbstractClient.ts +10 -3
  52. package/src/packages/AbstractLiveClient.ts +230 -0
  53. package/src/packages/AgentLiveClient.ts +16 -13
  54. package/src/packages/ListenLiveClient.ts +13 -12
  55. package/src/packages/SpeakLiveClient.ts +16 -12
@@ -3,6 +3,7 @@ import { CONNECTION_STATE, SOCKET_STATES } from "../lib/constants";
3
3
  import type { DeepgramClientOptions, LiveSchema } from "../lib/types";
4
4
  import type { WebSocket as WSWebSocket } from "ws";
5
5
  import { isBun } from "../lib/runtime";
6
+ import { DeepgramWebSocketError } from "../lib/errors";
6
7
 
7
8
  /**
8
9
  * Represents a constructor for a WebSocket-like object that can be used in the application.
@@ -285,6 +286,235 @@ export abstract class AbstractLiveClient extends AbstractClient {
285
286
  return this.key === "proxy" && !!this.namespaceOptions.websocket.options.proxy?.url;
286
287
  }
287
288
 
289
+ /**
290
+ * Extracts enhanced error information from a WebSocket error event.
291
+ * This method attempts to capture additional debugging information such as
292
+ * status codes, request IDs, and response headers when available.
293
+ *
294
+ * @example
295
+ * ```typescript
296
+ * // Enhanced error information is now available in error events:
297
+ * connection.on(LiveTranscriptionEvents.Error, (err) => {
298
+ * console.error("WebSocket Error:", err.message);
299
+ *
300
+ * // Access HTTP status code (e.g., 502, 403, etc.)
301
+ * if (err.statusCode) {
302
+ * console.error(`HTTP Status Code: ${err.statusCode}`);
303
+ * }
304
+ *
305
+ * // Access Deepgram request ID for support tickets
306
+ * if (err.requestId) {
307
+ * console.error(`Deepgram Request ID: ${err.requestId}`);
308
+ * }
309
+ *
310
+ * // Access WebSocket URL and connection state
311
+ * if (err.url) {
312
+ * console.error(`WebSocket URL: ${err.url}`);
313
+ * }
314
+ *
315
+ * if (err.readyState !== undefined) {
316
+ * const stateNames = ['CONNECTING', 'OPEN', 'CLOSING', 'CLOSED'];
317
+ * console.error(`Connection State: ${stateNames[err.readyState]}`);
318
+ * }
319
+ *
320
+ * // Access response headers for additional debugging
321
+ * if (err.responseHeaders) {
322
+ * console.error("Response Headers:", err.responseHeaders);
323
+ * }
324
+ *
325
+ * // Access the enhanced error object for detailed debugging
326
+ * if (err.error?.name === 'DeepgramWebSocketError') {
327
+ * console.error("Enhanced Error Details:", err.error.toJSON());
328
+ * }
329
+ * });
330
+ * ```
331
+ *
332
+ * @param event - The error event from the WebSocket
333
+ * @param conn - The WebSocket connection object
334
+ * @returns Enhanced error information object
335
+ */
336
+ protected extractErrorInformation(
337
+ event: ErrorEvent | Event,
338
+ conn?: WebSocketLike
339
+ ): {
340
+ statusCode?: number;
341
+ requestId?: string;
342
+ responseHeaders?: Record<string, string>;
343
+ url?: string;
344
+ readyState?: number;
345
+ } {
346
+ const errorInfo: {
347
+ statusCode?: number;
348
+ requestId?: string;
349
+ responseHeaders?: Record<string, string>;
350
+ url?: string;
351
+ readyState?: number;
352
+ } = {};
353
+
354
+ // Extract basic connection information
355
+ if (conn) {
356
+ errorInfo.readyState = conn.readyState;
357
+ errorInfo.url = typeof conn.url === "string" ? conn.url : conn.url?.toString();
358
+ }
359
+
360
+ // Try to extract additional information from the WebSocket connection
361
+ // This works with the 'ws' package which exposes more detailed error information
362
+ if (conn && typeof conn === "object") {
363
+ const wsConn = conn as any;
364
+
365
+ // Extract status code if available (from 'ws' package)
366
+ if (wsConn._req && wsConn._req.res) {
367
+ errorInfo.statusCode = wsConn._req.res.statusCode;
368
+
369
+ // Extract response headers if available
370
+ if (wsConn._req.res.headers) {
371
+ errorInfo.responseHeaders = { ...wsConn._req.res.headers };
372
+
373
+ // Extract request ID from Deepgram response headers
374
+ const requestId =
375
+ wsConn._req.res.headers["dg-request-id"] || wsConn._req.res.headers["x-dg-request-id"];
376
+ if (requestId) {
377
+ errorInfo.requestId = requestId;
378
+ }
379
+ }
380
+ }
381
+
382
+ // For native WebSocket, try to extract information from the event
383
+ if (event && "target" in event && event.target) {
384
+ const target = event.target as any;
385
+ if (target.url) {
386
+ errorInfo.url = target.url;
387
+ }
388
+ if (target.readyState !== undefined) {
389
+ errorInfo.readyState = target.readyState;
390
+ }
391
+ }
392
+ }
393
+
394
+ return errorInfo;
395
+ }
396
+
397
+ /**
398
+ * Creates an enhanced error object with additional debugging information.
399
+ * This method provides backward compatibility by including both the original
400
+ * error event and enhanced error information.
401
+ *
402
+ * @param event - The original error event
403
+ * @param enhancedInfo - Additional error information extracted from the connection
404
+ * @returns An object containing both original and enhanced error information
405
+ */
406
+ protected createEnhancedError(
407
+ event: ErrorEvent | Event,
408
+ enhancedInfo: {
409
+ statusCode?: number;
410
+ requestId?: string;
411
+ responseHeaders?: Record<string, string>;
412
+ url?: string;
413
+ readyState?: number;
414
+ }
415
+ ) {
416
+ // Create the enhanced error for detailed debugging
417
+ const enhancedError = new DeepgramWebSocketError(
418
+ (event as ErrorEvent).message || "WebSocket connection error",
419
+ {
420
+ originalEvent: event,
421
+ ...enhancedInfo,
422
+ }
423
+ );
424
+
425
+ // Return an object that maintains backward compatibility
426
+ // while providing enhanced information
427
+ return {
428
+ // Original event for backward compatibility
429
+ ...event,
430
+ // Enhanced error information
431
+ error: enhancedError,
432
+ // Additional fields for easier access
433
+ statusCode: enhancedInfo.statusCode,
434
+ requestId: enhancedInfo.requestId,
435
+ responseHeaders: enhancedInfo.responseHeaders,
436
+ url: enhancedInfo.url,
437
+ readyState: enhancedInfo.readyState,
438
+ // Enhanced message with more context
439
+ message: this.buildEnhancedErrorMessage(event, enhancedInfo),
440
+ };
441
+ }
442
+
443
+ /**
444
+ * Builds an enhanced error message with additional context information.
445
+ *
446
+ * @param event - The original error event
447
+ * @param enhancedInfo - Additional error information
448
+ * @returns A more descriptive error message
449
+ */
450
+ protected buildEnhancedErrorMessage(
451
+ event: ErrorEvent | Event,
452
+ enhancedInfo: {
453
+ statusCode?: number;
454
+ requestId?: string;
455
+ responseHeaders?: Record<string, string>;
456
+ url?: string;
457
+ readyState?: number;
458
+ }
459
+ ): string {
460
+ let message = (event as ErrorEvent).message || "WebSocket connection error";
461
+
462
+ const details: string[] = [];
463
+
464
+ if (enhancedInfo.statusCode) {
465
+ details.push(`Status: ${enhancedInfo.statusCode}`);
466
+ }
467
+
468
+ if (enhancedInfo.requestId) {
469
+ details.push(`Request ID: ${enhancedInfo.requestId}`);
470
+ }
471
+
472
+ if (enhancedInfo.readyState !== undefined) {
473
+ const stateNames = ["CONNECTING", "OPEN", "CLOSING", "CLOSED"];
474
+ const stateName =
475
+ stateNames[enhancedInfo.readyState] || `Unknown(${enhancedInfo.readyState})`;
476
+ details.push(`Ready State: ${stateName}`);
477
+ }
478
+
479
+ if (enhancedInfo.url) {
480
+ details.push(`URL: ${enhancedInfo.url}`);
481
+ }
482
+
483
+ if (details.length > 0) {
484
+ message += ` (${details.join(", ")})`;
485
+ }
486
+
487
+ return message;
488
+ }
489
+
490
+ /**
491
+ * Sets up the standard connection event handlers (open, close, error) for WebSocket connections.
492
+ * This method abstracts the common connection event registration pattern used across all live clients.
493
+ *
494
+ * @param events - Object containing the event constants for the specific client type
495
+ * @param events.Open - Event constant for connection open
496
+ * @param events.Close - Event constant for connection close
497
+ * @param events.Error - Event constant for connection error
498
+ * @protected
499
+ */
500
+ protected setupConnectionEvents(events: { Open: string; Close: string; Error: string }): void {
501
+ if (this.conn) {
502
+ this.conn.onopen = () => {
503
+ this.emit(events.Open, this);
504
+ };
505
+
506
+ this.conn.onclose = (event: any) => {
507
+ this.emit(events.Close, event);
508
+ };
509
+
510
+ this.conn.onerror = (event: ErrorEvent) => {
511
+ const enhancedInfo = this.extractErrorInformation(event, this.conn || undefined);
512
+ const enhancedError = this.createEnhancedError(event, enhancedInfo);
513
+ this.emit(events.Error, enhancedError);
514
+ };
515
+ }
516
+ }
517
+
288
518
  /**
289
519
  * Sets up the connection event handlers.
290
520
  *
@@ -22,19 +22,15 @@ export class AgentLiveClient extends AbstractLiveClient {
22
22
  * - When a message is received, it parses the message and emits the appropriate event based on the message type.
23
23
  */
24
24
  public setupConnection(): void {
25
- if (this.conn) {
26
- this.conn.onopen = () => {
27
- this.emit(AgentEvents.Open, this);
28
- };
29
-
30
- this.conn.onclose = (event: any) => {
31
- this.emit(AgentEvents.Close, event);
32
- };
33
-
34
- this.conn.onerror = (event: ErrorEvent) => {
35
- this.emit(AgentEvents.Error, event);
36
- };
25
+ // Set up standard connection events (open, close, error) using abstracted method
26
+ this.setupConnectionEvents({
27
+ Open: AgentEvents.Open,
28
+ Close: AgentEvents.Close,
29
+ Error: AgentEvents.Error,
30
+ });
37
31
 
32
+ // Set up message handling specific to agent conversations
33
+ if (this.conn) {
38
34
  this.conn.onmessage = (event: MessageEvent) => {
39
35
  this.handleMessage(event);
40
36
  };
@@ -53,9 +49,13 @@ export class AgentLiveClient extends AbstractLiveClient {
53
49
  } catch (error) {
54
50
  this.emit(AgentEvents.Error, {
55
51
  event,
56
- data: event.data,
52
+ data:
53
+ event.data?.toString().substring(0, 200) +
54
+ (event.data?.toString().length > 200 ? "..." : ""),
57
55
  message: "Unable to parse `data` as JSON.",
58
56
  error,
57
+ url: this.conn?.url,
58
+ readyState: this.conn?.readyState,
59
59
  });
60
60
  }
61
61
  } else if (event.data instanceof Blob) {
@@ -71,6 +71,9 @@ export class AgentLiveClient extends AbstractLiveClient {
71
71
  this.emit(AgentEvents.Error, {
72
72
  event,
73
73
  message: "Received unknown data type.",
74
+ url: this.conn?.url,
75
+ readyState: this.conn?.readyState,
76
+ dataType: typeof event.data,
74
77
  });
75
78
  }
76
79
  }
@@ -51,19 +51,15 @@ export class ListenLiveClient extends AbstractLiveClient {
51
51
  * - When a message is received, it parses the message and emits the appropriate event based on the message type, such as `LiveTranscriptionEvents.Metadata`, `LiveTranscriptionEvents.Transcript`, `LiveTranscriptionEvents.UtteranceEnd`, and `LiveTranscriptionEvents.SpeechStarted`.
52
52
  */
53
53
  public setupConnection(): void {
54
- if (this.conn) {
55
- this.conn.onopen = () => {
56
- this.emit(LiveTranscriptionEvents.Open, this);
57
- };
58
-
59
- this.conn.onclose = (event: any) => {
60
- this.emit(LiveTranscriptionEvents.Close, event);
61
- };
62
-
63
- this.conn.onerror = (event: ErrorEvent) => {
64
- this.emit(LiveTranscriptionEvents.Error, event);
65
- };
54
+ // Set up standard connection events (open, close, error) using abstracted method
55
+ this.setupConnectionEvents({
56
+ Open: LiveTranscriptionEvents.Open,
57
+ Close: LiveTranscriptionEvents.Close,
58
+ Error: LiveTranscriptionEvents.Error,
59
+ });
66
60
 
61
+ // Set up message handling specific to transcription
62
+ if (this.conn) {
67
63
  this.conn.onmessage = (event: MessageEvent) => {
68
64
  try {
69
65
  const data: any = JSON.parse(event.data.toString());
@@ -84,6 +80,11 @@ export class ListenLiveClient extends AbstractLiveClient {
84
80
  event,
85
81
  message: "Unable to parse `data` as JSON.",
86
82
  error,
83
+ url: this.conn?.url,
84
+ readyState: this.conn?.readyState,
85
+ data:
86
+ event.data?.toString().substring(0, 200) +
87
+ (event.data?.toString().length > 200 ? "..." : ""),
87
88
  });
88
89
  }
89
90
  };
@@ -42,19 +42,15 @@ export class SpeakLiveClient extends AbstractLiveClient {
42
42
  * - When a message is received, it parses the message and emits the appropriate event based on the message type, such as `LiveTTSEvents.Metadata`, `LiveTTSEvents.Flushed`, and `LiveTTSEvents.Warning`.
43
43
  */
44
44
  public setupConnection(): void {
45
- if (this.conn) {
46
- this.conn.onopen = () => {
47
- this.emit(LiveTTSEvents.Open, this);
48
- };
49
-
50
- this.conn.onclose = (event: any) => {
51
- this.emit(LiveTTSEvents.Close, event);
52
- };
53
-
54
- this.conn.onerror = (event: ErrorEvent) => {
55
- this.emit(LiveTTSEvents.Error, event);
56
- };
45
+ // Set up standard connection events (open, close, error) using abstracted method
46
+ this.setupConnectionEvents({
47
+ Open: LiveTTSEvents.Open,
48
+ Close: LiveTTSEvents.Close,
49
+ Error: LiveTTSEvents.Error,
50
+ });
57
51
 
52
+ // Set up message handling specific to text-to-speech
53
+ if (this.conn) {
58
54
  this.conn.onmessage = (event: MessageEvent) => {
59
55
  this.handleMessage(event);
60
56
  };
@@ -146,6 +142,11 @@ export class SpeakLiveClient extends AbstractLiveClient {
146
142
  event,
147
143
  message: "Unable to parse `data` as JSON.",
148
144
  error,
145
+ url: this.conn?.url,
146
+ readyState: this.conn?.readyState,
147
+ data:
148
+ event.data?.toString().substring(0, 200) +
149
+ (event.data?.toString().length > 200 ? "..." : ""),
149
150
  });
150
151
  }
151
152
  } else if (event.data instanceof Blob) {
@@ -161,6 +162,9 @@ export class SpeakLiveClient extends AbstractLiveClient {
161
162
  this.emit(LiveTTSEvents.Error, {
162
163
  event,
163
164
  message: "Received unknown data type.",
165
+ url: this.conn?.url,
166
+ readyState: this.conn?.readyState,
167
+ dataType: typeof event.data,
164
168
  });
165
169
  }
166
170
  }