@volley/recognition-client-sdk 0.1.385 → 0.1.417

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
@@ -1,4 +1,4 @@
1
- // ../../node_modules/.pnpm/zod@3.22.5/node_modules/zod/lib/index.mjs
1
+ // ../../node_modules/.pnpm/zod@3.22.4/node_modules/zod/lib/index.mjs
2
2
  var util;
3
3
  (function(util2) {
4
4
  util2.assertEqual = (val) => val;
@@ -3797,6 +3797,7 @@ var RecognitionResultTypeV1;
3797
3797
  RecognitionResultTypeV12["METADATA"] = "Metadata";
3798
3798
  RecognitionResultTypeV12["ERROR"] = "Error";
3799
3799
  RecognitionResultTypeV12["CLIENT_CONTROL_MESSAGE"] = "ClientControlMessage";
3800
+ RecognitionResultTypeV12["AUDIO_METRICS"] = "AudioMetrics";
3800
3801
  })(RecognitionResultTypeV1 || (RecognitionResultTypeV1 = {}));
3801
3802
  var TranscriptionResultSchemaV1 = z.object({
3802
3803
  type: z.literal(RecognitionResultTypeV1.TRANSCRIPTION),
@@ -3821,6 +3822,12 @@ var FunctionCallResultSchemaV1 = z.object({
3821
3822
  functionName: z.string(),
3822
3823
  functionArgJson: z.string()
3823
3824
  });
3825
+ var TranscriptOutcomeType;
3826
+ (function(TranscriptOutcomeType2) {
3827
+ TranscriptOutcomeType2["WITH_CONTENT"] = "with_content";
3828
+ TranscriptOutcomeType2["EMPTY"] = "empty";
3829
+ TranscriptOutcomeType2["NEVER_SENT"] = "never_sent";
3830
+ })(TranscriptOutcomeType || (TranscriptOutcomeType = {}));
3824
3831
  var MetadataResultSchemaV1 = z.object({
3825
3832
  type: z.literal(RecognitionResultTypeV1.METADATA),
3826
3833
  audioUtteranceId: z.string(),
@@ -3840,7 +3847,9 @@ var MetadataResultSchemaV1 = z.object({
3840
3847
  // ASR configuration as JSON string (no type validation)
3841
3848
  asrConfig: z.string().optional(),
3842
3849
  // Raw ASR metadata payload as provided by the provider (stringified if needed)
3843
- rawAsrMetadata: z.string().optional()
3850
+ rawAsrMetadata: z.string().optional(),
3851
+ // Transcript outcome - categorizes the final transcript state
3852
+ transcriptOutcome: z.nativeEnum(TranscriptOutcomeType).optional()
3844
3853
  });
3845
3854
  var ErrorTypeV1;
3846
3855
  (function(ErrorTypeV12) {
@@ -3873,6 +3882,22 @@ var ClientControlMessageSchemaV1 = z.object({
3873
3882
  action: ClientControlActionsV1
3874
3883
  // The control action to perform
3875
3884
  });
3885
+ var AudioMetricsResultSchemaV1 = z.object({
3886
+ type: z.literal(RecognitionResultTypeV1.AUDIO_METRICS),
3887
+ valid: z.boolean(),
3888
+ audioBeginMs: z.number(),
3889
+ audioEndMs: z.number(),
3890
+ maxVolume: z.number(),
3891
+ minVolume: z.number(),
3892
+ avgVolume: z.number(),
3893
+ silenceRatio: z.number(),
3894
+ clippingRatio: z.number(),
3895
+ snrEstimate: z.number().nullable(),
3896
+ lastNonSilenceMs: z.number(),
3897
+ timestamp: z.string(),
3898
+ isFinal: z.boolean().optional()
3899
+ // true if this is the final metrics (STOP_RECORDING signal), false for streaming
3900
+ });
3876
3901
  var RecognitionResultSchemaV1 = z.discriminatedUnion("type", [
3877
3902
  // P0
3878
3903
  TranscriptionResultSchemaV1,
@@ -4541,6 +4566,7 @@ var PlumbingType;
4541
4566
  PlumbingType2["PROVIDER_VAD_SIGNAL"] = "provider_vad_signal";
4542
4567
  PlumbingType2["PROVIDER_TIMER_SIGNAL"] = "provider_timer_signal";
4543
4568
  PlumbingType2["PROVIDER_RAW_MESSAGE"] = "provider_raw_message";
4569
+ PlumbingType2["AUDIO_METRICS"] = "audio_metrics";
4544
4570
  })(PlumbingType || (PlumbingType = {}));
4545
4571
 
4546
4572
  // ../../libs/types/dist/game-id.types.js
@@ -4565,6 +4591,21 @@ var STRING_TO_GAME_ID_MAP = {
4565
4591
  "twenty-questions": GameId.TWENTY_QUESTIONS,
4566
4592
  "emoji": GameId.GUESS_THE_EMOJI
4567
4593
  };
4594
+ var GAME_ID_ALIAS_MAP = {
4595
+ // Song Quiz aliases
4596
+ "songquiz": GameId.SONG_QUIZ,
4597
+ "sq": GameId.SONG_QUIZ,
4598
+ // Wheel of Fortune aliases
4599
+ "wof": GameId.WHEEL_OF_FORTUNE,
4600
+ "wheeloffortune": GameId.WHEEL_OF_FORTUNE,
4601
+ // Twenty Questions aliases
4602
+ "20q": GameId.TWENTY_QUESTIONS,
4603
+ "twentyquestions": GameId.TWENTY_QUESTIONS,
4604
+ "20questions": GameId.TWENTY_QUESTIONS,
4605
+ // Guess the Emoji aliases
4606
+ "guesstheemoji": GameId.GUESS_THE_EMOJI,
4607
+ "gte": GameId.GUESS_THE_EMOJI
4608
+ };
4568
4609
 
4569
4610
  // ../../libs/types/dist/gemini-types.js
4570
4611
  var GeminiModel;
@@ -4770,7 +4811,7 @@ var WebSocketAudioClient = class {
4770
4811
  // ../../libs/websocket/dist/core/audio-upload-websocket-server.js
4771
4812
  import { WebSocketServer, WebSocket as WebSocket2 } from "ws";
4772
4813
 
4773
- // ../../node_modules/.pnpm/uuid@11.1.0/node_modules/uuid/dist/esm-browser/stringify.js
4814
+ // ../../node_modules/.pnpm/uuid@11.0.0/node_modules/uuid/dist/esm-browser/stringify.js
4774
4815
  var byteToHex = [];
4775
4816
  for (let i = 0; i < 256; ++i) {
4776
4817
  byteToHex.push((i + 256).toString(16).slice(1));
@@ -4779,7 +4820,7 @@ function unsafeStringify(arr, offset = 0) {
4779
4820
  return (byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + "-" + byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + "-" + byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + "-" + byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + "-" + byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] + byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]]).toLowerCase();
4780
4821
  }
4781
4822
 
4782
- // ../../node_modules/.pnpm/uuid@11.1.0/node_modules/uuid/dist/esm-browser/rng.js
4823
+ // ../../node_modules/.pnpm/uuid@11.0.0/node_modules/uuid/dist/esm-browser/rng.js
4783
4824
  var getRandomValues;
4784
4825
  var rnds8 = new Uint8Array(16);
4785
4826
  function rng() {
@@ -4792,27 +4833,21 @@ function rng() {
4792
4833
  return getRandomValues(rnds8);
4793
4834
  }
4794
4835
 
4795
- // ../../node_modules/.pnpm/uuid@11.1.0/node_modules/uuid/dist/esm-browser/native.js
4836
+ // ../../node_modules/.pnpm/uuid@11.0.0/node_modules/uuid/dist/esm-browser/native.js
4796
4837
  var randomUUID = typeof crypto !== "undefined" && crypto.randomUUID && crypto.randomUUID.bind(crypto);
4797
4838
  var native_default = { randomUUID };
4798
4839
 
4799
- // ../../node_modules/.pnpm/uuid@11.1.0/node_modules/uuid/dist/esm-browser/v4.js
4840
+ // ../../node_modules/.pnpm/uuid@11.0.0/node_modules/uuid/dist/esm-browser/v4.js
4800
4841
  function v4(options, buf, offset) {
4801
4842
  if (native_default.randomUUID && !buf && !options) {
4802
4843
  return native_default.randomUUID();
4803
4844
  }
4804
4845
  options = options || {};
4805
- const rnds = options.random ?? options.rng?.() ?? rng();
4806
- if (rnds.length < 16) {
4807
- throw new Error("Random bytes length must be >= 16");
4808
- }
4846
+ const rnds = options.random || (options.rng || rng)();
4809
4847
  rnds[6] = rnds[6] & 15 | 64;
4810
4848
  rnds[8] = rnds[8] & 63 | 128;
4811
4849
  if (buf) {
4812
4850
  offset = offset || 0;
4813
- if (offset < 0 || offset + 16 > buf.length) {
4814
- throw new RangeError(`UUID byte range ${offset}:${offset + 15} is out of buffer bounds`);
4815
- }
4816
4851
  for (let i = 0; i < 16; ++i) {
4817
4852
  buf[offset + i] = rnds[i];
4818
4853
  }
@@ -4941,8 +4976,11 @@ function buildWebSocketUrl(config) {
4941
4976
  if (config.platform) {
4942
4977
  url.searchParams.set("platform", config.platform);
4943
4978
  }
4944
- if (config.gameContext) {
4945
- url.searchParams.set("gameId", config.gameContext.gameId);
4979
+ const gameId = config.gameId ?? config.gameContext?.gameId;
4980
+ if (gameId) {
4981
+ url.searchParams.set("gameId", gameId);
4982
+ }
4983
+ if (config.gameContext?.gamePhase) {
4946
4984
  url.searchParams.set("gamePhase", config.gameContext.gamePhase);
4947
4985
  }
4948
4986
  return url.toString();
@@ -4978,7 +5016,7 @@ var AudioRingBuffer = class {
4978
5016
  this.hasWrapped = true;
4979
5017
  this.overflowCount++;
4980
5018
  if (this.logger) {
4981
- this.logger("debug", "Buffer overflow detected", {
5019
+ this.logger("debug", "[RecogSDK] Buffer overflow detected", {
4982
5020
  bufferSize: this.bufferSize,
4983
5021
  totalOverflows: this.overflowCount,
4984
5022
  droppedChunk: this.buffer[this.readIndex]?.timestamp
@@ -5059,7 +5097,7 @@ var AudioRingBuffer = class {
5059
5097
  this.chunksBuffered = 0;
5060
5098
  this.totalBufferedBytes = 0;
5061
5099
  if (this.logger) {
5062
- this.logger("debug", "Audio buffer cleared");
5100
+ this.logger("debug", "[RecogSDK] Audio buffer cleared");
5063
5101
  }
5064
5102
  }
5065
5103
  /**
@@ -5094,7 +5132,7 @@ var MessageHandler = class {
5094
5132
  */
5095
5133
  handleMessage(msg) {
5096
5134
  if (this.callbacks.logger) {
5097
- this.callbacks.logger("debug", "Received WebSocket message", {
5135
+ this.callbacks.logger("debug", "[RecogSDK] Received WebSocket message", {
5098
5136
  msgType: msg.type,
5099
5137
  msgDataType: msg.data && typeof msg.data === "object" && "type" in msg.data ? msg.data.type : "N/A",
5100
5138
  fullMessage: msg
@@ -5102,7 +5140,7 @@ var MessageHandler = class {
5102
5140
  }
5103
5141
  if (msg.data && typeof msg.data !== "object") {
5104
5142
  if (this.callbacks.logger) {
5105
- this.callbacks.logger("error", "Received primitive msg.data from server", {
5143
+ this.callbacks.logger("error", "[RecogSDK] Received primitive msg.data from server", {
5106
5144
  dataType: typeof msg.data,
5107
5145
  data: msg.data,
5108
5146
  fullMessage: msg
@@ -5129,7 +5167,7 @@ var MessageHandler = class {
5129
5167
  break;
5130
5168
  default:
5131
5169
  if (this.callbacks.logger) {
5132
- this.callbacks.logger("debug", "Unknown message type", { type: msgType });
5170
+ this.callbacks.logger("debug", "[RecogSDK] Unknown message type", { type: msgType });
5133
5171
  }
5134
5172
  }
5135
5173
  }
@@ -5142,7 +5180,7 @@ var MessageHandler = class {
5142
5180
  this.firstTranscriptTime = Date.now();
5143
5181
  const timeToFirstTranscript = this.firstTranscriptTime - this.sessionStartTime;
5144
5182
  if (this.callbacks.logger) {
5145
- this.callbacks.logger("debug", "First transcript received", {
5183
+ this.callbacks.logger("debug", "[RecogSDK] First transcript received", {
5146
5184
  timeToFirstTranscriptMs: timeToFirstTranscript
5147
5185
  });
5148
5186
  }
@@ -5237,7 +5275,8 @@ var RealTimeTwoWayWebSocketRecognitionClient = class _RealTimeTwoWayWebSocketRec
5237
5275
  ...config.accountId && { accountId: config.accountId },
5238
5276
  ...config.questionAnswerId && { questionAnswerId: config.questionAnswerId },
5239
5277
  ...config.platform && { platform: config.platform },
5240
- ...config.gameContext && { gameContext: config.gameContext }
5278
+ ...config.gameContext && { gameContext: config.gameContext },
5279
+ ...config.gameId && { gameId: config.gameId }
5241
5280
  });
5242
5281
  super({
5243
5282
  url,
@@ -5315,7 +5354,7 @@ var RealTimeTwoWayWebSocketRecognitionClient = class _RealTimeTwoWayWebSocketRec
5315
5354
  return;
5316
5355
  }
5317
5356
  if (this.config.logger) {
5318
- this.config.logger(level, `[SDK] ${message}`, data);
5357
+ this.config.logger(level, `[RecogSDK] ${message}`, data);
5319
5358
  }
5320
5359
  }
5321
5360
  /**
@@ -5757,6 +5796,14 @@ var ConfigBuilder = class {
5757
5796
  this.config.gameContext = context;
5758
5797
  return this;
5759
5798
  }
5799
+ /**
5800
+ * Set game ID directly (takes precedence over gameContext.gameId)
5801
+ * Use this when you only need to identify the game without full context.
5802
+ */
5803
+ gameId(id) {
5804
+ this.config.gameId = id;
5805
+ return this;
5806
+ }
5760
5807
  /**
5761
5808
  * Set audio utterance ID
5762
5809
  */
@@ -6048,6 +6095,7 @@ function generateUUID() {
6048
6095
  var SimplifiedVGFRecognitionClient = class {
6049
6096
  constructor(config) {
6050
6097
  this.isRecordingAudio = false;
6098
+ this.lastSentTerminalUuid = null;
6051
6099
  const { onStateChange, initialState, ...clientConfig } = config;
6052
6100
  this.stateChangeCallback = onStateChange;
6053
6101
  this.logger = clientConfig.logger;
@@ -6068,6 +6116,7 @@ var SimplifiedVGFRecognitionClient = class {
6068
6116
  finalTranscript: void 0
6069
6117
  };
6070
6118
  clientConfig.audioUtteranceId = newUUID;
6119
+ this.lastSentTerminalUuid = null;
6071
6120
  if (onStateChange) {
6072
6121
  onStateChange(this.state);
6073
6122
  }
@@ -6102,11 +6151,17 @@ var SimplifiedVGFRecognitionClient = class {
6102
6151
  if (this.logger) {
6103
6152
  this.logger(
6104
6153
  "warn",
6105
- `[VGF] Skipping transcript update: UUID mismatch (expected: ${this.expectedUuid}, got: ${result.audioUtteranceId})`
6154
+ `[RecogSDK:VGF] Skipping transcript update: UUID mismatch (expected: ${this.expectedUuid}, got: ${result.audioUtteranceId})`
6106
6155
  );
6107
6156
  }
6108
- if (clientConfig.onTranscript) {
6109
- clientConfig.onTranscript(result);
6157
+ return;
6158
+ }
6159
+ if (this.lastSentTerminalUuid === this.expectedUuid) {
6160
+ if (this.logger) {
6161
+ this.logger(
6162
+ "info",
6163
+ `[RecogSDK:VGF] Duplicate terminal status suppressed (lastSentTerminalUuid: ${this.lastSentTerminalUuid})`
6164
+ );
6110
6165
  }
6111
6166
  return;
6112
6167
  }
@@ -6121,7 +6176,7 @@ var SimplifiedVGFRecognitionClient = class {
6121
6176
  if (this.logger) {
6122
6177
  this.logger(
6123
6178
  "warn",
6124
- `[VGF] Skipping metadata update: UUID mismatch (expected: ${this.expectedUuid}, got: ${metadata.audioUtteranceId})`
6179
+ `[RecogSDK:VGF] Skipping metadata update: UUID mismatch (expected: ${this.expectedUuid}, got: ${metadata.audioUtteranceId})`
6125
6180
  );
6126
6181
  }
6127
6182
  return;
@@ -6140,11 +6195,14 @@ var SimplifiedVGFRecognitionClient = class {
6140
6195
  if (this.logger) {
6141
6196
  this.logger(
6142
6197
  "warn",
6143
- `[VGF] Skipping error update: UUID mismatch (expected: ${this.expectedUuid}, got: ${error.audioUtteranceId})`
6198
+ `[RecogSDK:VGF] Skipping error update: UUID mismatch (expected: ${this.expectedUuid}, got: ${error.audioUtteranceId})`
6144
6199
  );
6145
6200
  }
6146
6201
  return;
6147
6202
  }
6203
+ if (this.lastSentTerminalUuid === this.expectedUuid) {
6204
+ return;
6205
+ }
6148
6206
  this.isRecordingAudio = false;
6149
6207
  this.state = mapErrorToState(this.state, error);
6150
6208
  this.notifyStateChange();
@@ -6186,6 +6244,24 @@ var SimplifiedVGFRecognitionClient = class {
6186
6244
  this.isRecordingAudio = false;
6187
6245
  this.state = updateStateOnStop(this.state);
6188
6246
  this.notifyStateChange();
6247
+ if (this.state.transcriptionStatus === TranscriptionStatus.NOT_STARTED) {
6248
+ if (this.logger) {
6249
+ this.logger(
6250
+ "info",
6251
+ `[RecogSDK:VGF] Early termination detected (transcriptionStatus: NOT_STARTED) - emitting synthetic finalization`
6252
+ );
6253
+ }
6254
+ this.state = {
6255
+ ...this.state,
6256
+ transcriptionStatus: TranscriptionStatus.FINALIZED,
6257
+ finalTranscript: "",
6258
+ finalConfidence: 0,
6259
+ pendingTranscript: "",
6260
+ pendingConfidence: void 0,
6261
+ finalTranscriptionTimestamp: (/* @__PURE__ */ new Date()).toISOString()
6262
+ };
6263
+ this.notifyStateChange();
6264
+ }
6189
6265
  await this.client.stopRecording();
6190
6266
  }
6191
6267
  stopAbnormally() {
@@ -6235,10 +6311,26 @@ var SimplifiedVGFRecognitionClient = class {
6235
6311
  getVGFState() {
6236
6312
  return { ...this.state };
6237
6313
  }
6314
+ isTerminalStatus(status) {
6315
+ return status === TranscriptionStatus.FINALIZED || status === TranscriptionStatus.ABORTED || status === TranscriptionStatus.ERROR;
6316
+ }
6238
6317
  notifyStateChange() {
6239
- if (this.stateChangeCallback) {
6240
- this.stateChangeCallback({ ...this.state });
6318
+ if (this.isTerminalStatus(this.state.transcriptionStatus)) {
6319
+ if (this.lastSentTerminalUuid === this.expectedUuid) {
6320
+ if (this.logger) {
6321
+ this.logger(
6322
+ "info",
6323
+ `[RecogSDK:VGF] Duplicate terminal status suppressed (lastSentTerminalUuid: ${this.lastSentTerminalUuid})`
6324
+ );
6325
+ }
6326
+ return;
6327
+ }
6328
+ this.lastSentTerminalUuid = this.expectedUuid;
6329
+ }
6330
+ if (!this.stateChangeCallback) {
6331
+ return;
6241
6332
  }
6333
+ this.stateChangeCallback({ ...this.state });
6242
6334
  }
6243
6335
  };
6244
6336
  function createSimplifiedVGFClient(config) {