@volley/recognition-client-sdk 0.1.211 → 0.1.254

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.js CHANGED
@@ -19,6 +19,11 @@ var RecognitionMode;
19
19
  RecognitionMode2["STREAMING"] = "streaming";
20
20
  RecognitionMode2["BATCH"] = "batch";
21
21
  })(RecognitionMode || (RecognitionMode = {}));
22
+ var ASRApiType;
23
+ (function(ASRApiType2) {
24
+ ASRApiType2["STREAMING"] = "streaming";
25
+ ASRApiType2["FILE_BASED"] = "file-based";
26
+ })(ASRApiType || (ASRApiType = {}));
22
27
  var DeepgramModel;
23
28
  (function(DeepgramModel2) {
24
29
  DeepgramModel2["NOVA_2"] = "nova-2";
@@ -82,6 +87,8 @@ var MetadataResultSchemaV1 = z.object({
82
87
  accumulatedAudioTimeMs: z.number().optional(),
83
88
  // Cost Information
84
89
  costInUSD: z.number().default(0).optional(),
90
+ // ASR API Type
91
+ apiType: z.nativeEnum(ASRApiType).optional(),
85
92
  // ASR configuration as JSON string (no type validation)
86
93
  asrConfig: z.string().optional(),
87
94
  // Raw ASR metadata payload as provided by the provider (stringified if needed)
@@ -94,6 +101,7 @@ var ErrorTypeV1;
94
101
  ErrorTypeV12["PROVIDER_ERROR"] = "provider_error";
95
102
  ErrorTypeV12["TIMEOUT_ERROR"] = "timeout_error";
96
103
  ErrorTypeV12["QUOTA_EXCEEDED"] = "quota_exceeded";
104
+ ErrorTypeV12["CONNECTION_ERROR"] = "connection_error";
97
105
  ErrorTypeV12["UNKNOWN_ERROR"] = "unknown_error";
98
106
  })(ErrorTypeV1 || (ErrorTypeV1 = {}));
99
107
  var ErrorResultSchemaV1 = z.object({
@@ -214,7 +222,19 @@ var TranscriptMessageSchema = z.object({
214
222
  * Whether this transcript is finalized (won't change)
215
223
  * @example true
216
224
  */
217
- is_final: z.boolean()
225
+ is_final: z.boolean(),
226
+ /**
227
+ * Accumulated confirmed transcript (all finalized text received so far)
228
+ * Contains only the completed/finalized portions
229
+ * @example "hello world how are you"
230
+ */
231
+ confirmedTranscript: z.string().optional(),
232
+ /**
233
+ * New pending transcript (current interim text since last confirmation)
234
+ * Contains only the unconfirmed interim text
235
+ * @example "I'm doing"
236
+ */
237
+ newPendingTranscript: z.string().optional()
218
238
  });
219
239
  var VADEndSignalSchema = z.object({
220
240
  type: z.literal(ProviderMessageType.VAD_END_SIGNAL),
@@ -302,7 +322,20 @@ var TimerSchema = z.object({
302
322
  * Total duration of all audio chunks sent to this provider session
303
323
  * @example 2500 (2.5 seconds of audio has been sent)
304
324
  */
305
- accumulatedAudioTimeMs: z.number().optional()
325
+ accumulatedAudioTimeMs: z.number().optional(),
326
+ /**
327
+ * Estimated cost in USD for this session
328
+ * Calculated by the job based on audio duration and provider pricing
329
+ * @example 0.0025 (quarter of a cent)
330
+ */
331
+ costInUSD: z.number().optional().default(0),
332
+ /**
333
+ * ASR API type from the job
334
+ * - STREAMING: Real-time streaming APIs (Deepgram, AssemblyAI, Google)
335
+ * - FILE_BASED: File upload/batch APIs (OpenAI Batch, Gemini Batch)
336
+ * @example ASRApiType.STREAMING
337
+ */
338
+ apiType: z.nativeEnum(ASRApiType).optional()
306
339
  });
307
340
  var RawMessageSchema = z.object({
308
341
  type: z.literal(ProviderMessageType.RAW),
@@ -391,6 +424,16 @@ var QuotaExceededExceptionSchema = BaseRecognitionExceptionSchema.extend({
391
424
  /** How long to wait in seconds before retry */
392
425
  retryAfterSeconds: z.number().optional()
393
426
  });
427
+ var ConnectionExceptionSchema = BaseRecognitionExceptionSchema.extend({
428
+ errorType: z.literal(ErrorTypeV1.CONNECTION_ERROR),
429
+ isImmediatelyAvailable: z.literal(true),
430
+ /** Number of connection attempts made */
431
+ attempts: z.number().optional(),
432
+ /** URL that failed to connect */
433
+ url: z.string().optional(),
434
+ /** Underlying error message */
435
+ underlyingError: z.string().optional()
436
+ });
394
437
  var UnknownExceptionSchema = BaseRecognitionExceptionSchema.extend({
395
438
  errorType: z.literal(ErrorTypeV1.UNKNOWN_ERROR),
396
439
  isImmediatelyAvailable: z.literal(false),
@@ -405,8 +448,32 @@ z.discriminatedUnion("errorType", [
405
448
  ProviderExceptionSchema,
406
449
  TimeoutExceptionSchema,
407
450
  QuotaExceededExceptionSchema,
451
+ ConnectionExceptionSchema,
408
452
  UnknownExceptionSchema
409
453
  ]);
454
+ function isExceptionImmediatelyAvailable(exception) {
455
+ return exception.isImmediatelyAvailable;
456
+ }
457
+ __name(isExceptionImmediatelyAvailable, "isExceptionImmediatelyAvailable");
458
+ function getUserFriendlyMessage(exception) {
459
+ if (!exception.isImmediatelyAvailable) {
460
+ return "An error occurred. Please try again or contact support.";
461
+ }
462
+ switch (exception.errorType) {
463
+ case ErrorTypeV1.VALIDATION_ERROR:
464
+ return exception.message || "Invalid input. Please check your request.";
465
+ case ErrorTypeV1.TIMEOUT_ERROR:
466
+ return exception.message || "Request timed out. Please try again.";
467
+ case ErrorTypeV1.QUOTA_EXCEEDED:
468
+ if (exception.retryAfterSeconds) {
469
+ return `Rate limit exceeded. Please try again in ${exception.retryAfterSeconds} seconds.`;
470
+ }
471
+ return exception.message || "Rate limit exceeded. Please try again later.";
472
+ case ErrorTypeV1.CONNECTION_ERROR:
473
+ return exception.message || "Connection failed. Please check your network and try again.";
474
+ }
475
+ }
476
+ __name(getUserFriendlyMessage, "getUserFriendlyMessage");
410
477
  var RecognitionContextTypeV1;
411
478
  (function(RecognitionContextTypeV12) {
412
479
  RecognitionContextTypeV12["GAME_CONTEXT"] = "GameContext";
@@ -948,6 +1015,11 @@ var STAGES = {
948
1015
  STAGING: "staging",
949
1016
  PRODUCTION: "production"
950
1017
  };
1018
+ [
1019
+ STAGES.LOCAL,
1020
+ STAGES.DEV,
1021
+ STAGES.STAGING
1022
+ ];
951
1023
 
952
1024
  // ../../libs/websocket/dist/core/audio-upload-websocket-protocol.js
953
1025
  var WebSocketCloseCode;
@@ -1209,8 +1281,16 @@ __name(getRecognitionConductorHost, "getRecognitionConductorHost");
1209
1281
 
1210
1282
  // src/utils/url-builder.ts
1211
1283
  function buildWebSocketUrl(config) {
1212
- const defaultBase = getRecognitionServiceBase("production");
1213
- const baseUrl = config.url || `${defaultBase.wsBase}/ws/v1/recognize`;
1284
+ let baseUrl;
1285
+ if (config.url) {
1286
+ baseUrl = config.url;
1287
+ } else if (config.stage) {
1288
+ const stageBase = getRecognitionServiceBase(config.stage);
1289
+ baseUrl = `${stageBase.wsBase}/ws/v1/recognize`;
1290
+ } else {
1291
+ const defaultBase = getRecognitionServiceBase("production");
1292
+ baseUrl = `${defaultBase.wsBase}/ws/v1/recognize`;
1293
+ }
1214
1294
  const url = new URL(baseUrl);
1215
1295
  url.searchParams.set("audioUtteranceId", config.audioUtteranceId);
1216
1296
  if (config.callbackUrls && config.callbackUrls.length > 0) {
@@ -1466,6 +1546,75 @@ var MessageHandler = class {
1466
1546
  }
1467
1547
  };
1468
1548
 
1549
+ // src/errors.ts
1550
+ var RecognitionError = class extends Error {
1551
+ static {
1552
+ __name(this, "RecognitionError");
1553
+ }
1554
+ errorType;
1555
+ timestamp;
1556
+ constructor(errorType, message) {
1557
+ super(message);
1558
+ this.name = "RecognitionError";
1559
+ this.errorType = errorType;
1560
+ this.timestamp = Date.now();
1561
+ if (Error.captureStackTrace) {
1562
+ Error.captureStackTrace(this, this.constructor);
1563
+ }
1564
+ }
1565
+ };
1566
+ var ConnectionError = class extends RecognitionError {
1567
+ static {
1568
+ __name(this, "ConnectionError");
1569
+ }
1570
+ attempts;
1571
+ url;
1572
+ underlyingError;
1573
+ constructor(message, attempts, url, underlyingError) {
1574
+ super(ErrorTypeV1.CONNECTION_ERROR, message);
1575
+ this.name = "ConnectionError";
1576
+ this.attempts = attempts;
1577
+ this.url = url;
1578
+ if (underlyingError !== void 0) {
1579
+ this.underlyingError = underlyingError;
1580
+ }
1581
+ }
1582
+ };
1583
+ var TimeoutError = class extends RecognitionError {
1584
+ static {
1585
+ __name(this, "TimeoutError");
1586
+ }
1587
+ timeoutMs;
1588
+ operation;
1589
+ constructor(message, timeoutMs, operation) {
1590
+ super(ErrorTypeV1.TIMEOUT_ERROR, message);
1591
+ this.name = "TimeoutError";
1592
+ this.timeoutMs = timeoutMs;
1593
+ this.operation = operation;
1594
+ }
1595
+ };
1596
+ var ValidationError = class extends RecognitionError {
1597
+ static {
1598
+ __name(this, "ValidationError");
1599
+ }
1600
+ field;
1601
+ expected;
1602
+ received;
1603
+ constructor(message, field, expected, received) {
1604
+ super(ErrorTypeV1.VALIDATION_ERROR, message);
1605
+ this.name = "ValidationError";
1606
+ if (field !== void 0) {
1607
+ this.field = field;
1608
+ }
1609
+ if (expected !== void 0) {
1610
+ this.expected = expected;
1611
+ }
1612
+ if (received !== void 0) {
1613
+ this.received = received;
1614
+ }
1615
+ }
1616
+ };
1617
+
1469
1618
  // src/recognition-client.ts
1470
1619
  function isNormalDisconnection(code) {
1471
1620
  return code === 1e3;
@@ -1507,6 +1656,9 @@ var RealTimeTwoWayWebSocketRecognitionClient = class _RealTimeTwoWayWebSocketRec
1507
1656
  ...config.url && {
1508
1657
  url: config.url
1509
1658
  },
1659
+ ...config.stage && {
1660
+ stage: config.stage
1661
+ },
1510
1662
  ...config.callbackUrls && {
1511
1663
  callbackUrls: config.callbackUrls
1512
1664
  },
@@ -1537,6 +1689,9 @@ var RealTimeTwoWayWebSocketRecognitionClient = class _RealTimeTwoWayWebSocketRec
1537
1689
  highWM: config.highWaterMark ?? 512e3,
1538
1690
  lowWM: config.lowWaterMark ?? 128e3
1539
1691
  });
1692
+ const retryConfig = config.connectionRetry || {};
1693
+ const maxAttempts = Math.max(1, Math.min(5, retryConfig.maxAttempts ?? 4));
1694
+ const delayMs = retryConfig.delayMs ?? 200;
1540
1695
  this.config = {
1541
1696
  url,
1542
1697
  audioUtteranceId,
@@ -1565,6 +1720,10 @@ var RealTimeTwoWayWebSocketRecognitionClient = class _RealTimeTwoWayWebSocketRec
1565
1720
  lowWaterMark: config.lowWaterMark ?? 128e3,
1566
1721
  maxBufferDurationSec: config.maxBufferDurationSec ?? 60,
1567
1722
  chunksPerSecond: config.chunksPerSecond ?? 100,
1723
+ connectionRetry: {
1724
+ maxAttempts,
1725
+ delayMs
1726
+ },
1568
1727
  ...config.logger && {
1569
1728
  logger: config.logger
1570
1729
  }
@@ -1622,9 +1781,8 @@ var RealTimeTwoWayWebSocketRecognitionClient = class _RealTimeTwoWayWebSocketRec
1622
1781
  // ==========================================================================
1623
1782
  async connect() {
1624
1783
  if (this.connectionPromise) {
1625
- this.log("debug", "Returning existing connection promise", {
1626
- state: this.state,
1627
- hasPromise: true
1784
+ this.log("debug", "Returning existing connection promise (already connecting)", {
1785
+ state: this.state
1628
1786
  });
1629
1787
  return this.connectionPromise;
1630
1788
  }
@@ -1634,43 +1792,97 @@ var RealTimeTwoWayWebSocketRecognitionClient = class _RealTimeTwoWayWebSocketRec
1634
1792
  });
1635
1793
  return Promise.resolve();
1636
1794
  }
1637
- this.log("debug", "Creating new connection to WebSocket", {
1638
- url: this.config.url
1639
- });
1640
- this.state = ClientState.CONNECTING;
1641
- const connectionStartTime = Date.now();
1642
- this.connectionPromise = new Promise((resolve, reject) => {
1643
- const timeout = setTimeout(() => {
1644
- this.log("warn", "Connection timeout", {
1645
- timeout: 1e4
1646
- });
1647
- this.state = ClientState.FAILED;
1648
- reject(new Error("Timeout"));
1649
- }, 1e4);
1650
- const originalOnConnected = this.onConnected.bind(this);
1651
- this.onConnected = () => {
1652
- clearTimeout(timeout);
1653
- const connectionTime = Date.now() - connectionStartTime;
1654
- this.log("debug", "Connection established successfully", {
1655
- connectionTimeMs: connectionTime,
1656
- url: this.config.url
1657
- });
1658
- this.state = ClientState.CONNECTED;
1659
- originalOnConnected();
1660
- resolve();
1661
- };
1662
- const originalOnError = this.onError.bind(this);
1663
- this.onError = (error) => {
1664
- clearTimeout(timeout);
1665
- this.log("warn", "Connection error", error);
1666
- this.state = ClientState.FAILED;
1667
- originalOnError(error);
1668
- reject(error);
1669
- };
1670
- super.connect();
1671
- });
1795
+ this.connectionPromise = this.connectWithRetry();
1672
1796
  return this.connectionPromise;
1673
1797
  }
1798
+ /**
1799
+ * Attempt to connect with retry logic
1800
+ * Only retries on initial connection establishment, not mid-stream interruptions
1801
+ */
1802
+ async connectWithRetry() {
1803
+ const { maxAttempts, delayMs } = this.config.connectionRetry;
1804
+ const connectionTimeout = 1e4;
1805
+ let lastError;
1806
+ const originalOnConnected = this.config.onConnected;
1807
+ const originalOnError = this.config.onError;
1808
+ try {
1809
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
1810
+ const attemptLogLevel = attempt === 1 ? "debug" : "info";
1811
+ this.log(attemptLogLevel, `Connection attempt ${attempt}/${maxAttempts}`, {
1812
+ url: this.config.url,
1813
+ delayMs: attempt > 1 ? delayMs : 0
1814
+ });
1815
+ this.state = ClientState.CONNECTING;
1816
+ const connectionStartTime = Date.now();
1817
+ try {
1818
+ await new Promise((resolve, reject) => {
1819
+ let settled = false;
1820
+ const timeout = setTimeout(() => {
1821
+ if (settled) return;
1822
+ settled = true;
1823
+ this.log("warn", "Connection timeout", {
1824
+ timeout: connectionTimeout,
1825
+ attempt
1826
+ });
1827
+ this.state = ClientState.FAILED;
1828
+ reject(new Error(`Connection timeout after ${connectionTimeout}ms`));
1829
+ }, connectionTimeout);
1830
+ this.onConnected = () => {
1831
+ if (settled) return;
1832
+ settled = true;
1833
+ clearTimeout(timeout);
1834
+ const connectionTime = Date.now() - connectionStartTime;
1835
+ this.log("debug", "Connection established successfully", {
1836
+ connectionTimeMs: connectionTime,
1837
+ url: this.config.url,
1838
+ attempt
1839
+ });
1840
+ this.state = ClientState.CONNECTED;
1841
+ originalOnConnected();
1842
+ resolve();
1843
+ };
1844
+ this.onError = (error) => {
1845
+ if (settled) return;
1846
+ settled = true;
1847
+ clearTimeout(timeout);
1848
+ this.log("warn", "Connection error", {
1849
+ error,
1850
+ attempt
1851
+ });
1852
+ this.state = ClientState.FAILED;
1853
+ reject(error);
1854
+ };
1855
+ super.connect();
1856
+ });
1857
+ const successLogLevel = attempt === 1 ? "debug" : "info";
1858
+ this.log(successLogLevel, `Connection successful on attempt ${attempt}`, {
1859
+ totalAttempts: attempt
1860
+ });
1861
+ return;
1862
+ } catch (error) {
1863
+ lastError = error;
1864
+ if (attempt < maxAttempts) {
1865
+ const logLevel = attempt < 3 ? "info" : "warn";
1866
+ this.log(logLevel, `Connection attempt ${attempt} failed, retrying after ${delayMs}ms`, {
1867
+ error: lastError.message,
1868
+ nextAttempt: attempt + 1
1869
+ });
1870
+ this.state = ClientState.INITIAL;
1871
+ await new Promise((resolve) => setTimeout(resolve, delayMs));
1872
+ } else {
1873
+ this.log("warn", `All ${maxAttempts} connection attempts failed`, {
1874
+ error: lastError.message
1875
+ });
1876
+ }
1877
+ }
1878
+ }
1879
+ throw new ConnectionError(`Failed to establish connection after ${maxAttempts} attempts`, maxAttempts, this.config.url, lastError);
1880
+ } finally {
1881
+ this.config.onConnected = originalOnConnected;
1882
+ this.config.onError = originalOnError;
1883
+ this.connectionPromise = void 0;
1884
+ }
1885
+ }
1674
1886
  sendAudio(audioData) {
1675
1887
  if (audioData instanceof Blob) {
1676
1888
  blobToArrayBuffer(audioData).then((arrayBuffer) => {
@@ -1745,6 +1957,9 @@ var RealTimeTwoWayWebSocketRecognitionClient = class _RealTimeTwoWayWebSocketRec
1745
1957
  getAudioUtteranceId() {
1746
1958
  return this.config.audioUtteranceId;
1747
1959
  }
1960
+ getUrl() {
1961
+ return this.config.url;
1962
+ }
1748
1963
  getState() {
1749
1964
  return this.state;
1750
1965
  }
@@ -1897,13 +2112,27 @@ var ConfigBuilder = class {
1897
2112
  }
1898
2113
  config = {};
1899
2114
  /**
1900
- * Set the WebSocket URL
2115
+ * Set the WebSocket URL (advanced usage)
2116
+ * For standard environments, use stage() instead
1901
2117
  */
1902
2118
  url(url) {
1903
2119
  this.config.url = url;
1904
2120
  return this;
1905
2121
  }
1906
2122
  /**
2123
+ * Set the stage for automatic environment selection (recommended)
2124
+ * @param stage - STAGES.LOCAL | STAGES.DEV | STAGES.STAGING | STAGES.PRODUCTION
2125
+ * @example
2126
+ * ```typescript
2127
+ * import { STAGES } from '@recog/shared-types';
2128
+ * builder.stage(STAGES.STAGING)
2129
+ * ```
2130
+ */
2131
+ stage(stage) {
2132
+ this.config.stage = stage;
2133
+ return this;
2134
+ }
2135
+ /**
1907
2136
  * Set ASR request configuration
1908
2137
  */
1909
2138
  asrRequestConfig(config) {
@@ -2307,6 +2536,9 @@ var SimplifiedVGFRecognitionClient = class {
2307
2536
  getAudioUtteranceId() {
2308
2537
  return this.client.getAudioUtteranceId();
2309
2538
  }
2539
+ getUrl() {
2540
+ return this.client.getUrl();
2541
+ }
2310
2542
  getState() {
2311
2543
  return this.client.getState();
2312
2544
  }
@@ -2344,6 +2576,6 @@ function createSimplifiedVGFClient(config) {
2344
2576
  }
2345
2577
  __name(createSimplifiedVGFClient, "createSimplifiedVGFClient");
2346
2578
 
2347
- export { AudioEncoding, ClientState, ConfigBuilder, ControlSignalTypeV1 as ControlSignal, ControlSignalTypeV1, DeepgramModel, GeminiModel, GoogleModel, Language, OpenAIModel, RECOGNITION_CONDUCTOR_BASES, RECOGNITION_SERVICE_BASES, RealTimeTwoWayWebSocketRecognitionClient, RecognitionContextTypeV1, RecognitionProvider, RecognitionResultTypeV1, RecognitionVGFStateSchema, RecordingStatus, SampleRate, SimplifiedVGFRecognitionClient, TranscriptionStatus, createClient, createClientWithBuilder, createInitialRecognitionState, createSimplifiedVGFClient, getRecognitionConductorBase, getRecognitionConductorHost, getRecognitionConductorHttpBase, getRecognitionConductorWsBase, getRecognitionServiceBase, getRecognitionServiceHost, getRecognitionServiceHttpBase, getRecognitionServiceWsBase, isNormalDisconnection, isValidRecordingStatusTransition, normalizeStage };
2579
+ export { AudioEncoding, ClientState, ConfigBuilder, ConnectionError, ControlSignalTypeV1 as ControlSignal, ControlSignalTypeV1, DeepgramModel, ErrorTypeV1, GeminiModel, GoogleModel, Language, OpenAIModel, RECOGNITION_CONDUCTOR_BASES, RECOGNITION_SERVICE_BASES, RealTimeTwoWayWebSocketRecognitionClient, RecognitionContextTypeV1, RecognitionError, RecognitionProvider, RecognitionResultTypeV1, RecognitionVGFStateSchema, RecordingStatus, STAGES, SampleRate, SimplifiedVGFRecognitionClient, TimeoutError, TranscriptionStatus, ValidationError, createClient, createClientWithBuilder, createInitialRecognitionState, createSimplifiedVGFClient, getRecognitionConductorBase, getRecognitionConductorHost, getRecognitionConductorHttpBase, getRecognitionConductorWsBase, getRecognitionServiceBase, getRecognitionServiceHost, getRecognitionServiceHttpBase, getRecognitionServiceWsBase, getUserFriendlyMessage, isExceptionImmediatelyAvailable, isNormalDisconnection, isValidRecordingStatusTransition, normalizeStage };
2348
2580
  //# sourceMappingURL=index.js.map
2349
2581
  //# sourceMappingURL=index.js.map