@myscheme/voice-navigation-sdk 0.1.8 → 0.1.9

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.
@@ -26,6 +26,7 @@ export declare class MicrophoneHandler {
26
26
  private lastRecognitionTime;
27
27
  private recognitionHealthCheckInterval;
28
28
  private isRecovering;
29
+ private isStoppingIntentionally;
29
30
  constructor(config: MicrophoneConfig);
30
31
  hasMicrophonePermission(): boolean;
31
32
  hasUnlockedAudioContext(): boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"microphone-handler.d.ts","sourceRoot":"","sources":["../src/microphone-handler.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,GAAG,MAAM,wCAAwC,CAAC;AAC9D,OAAO,KAAK,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAC3E,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAChE,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAEvD,UAAU,gBAAgB;IACxB,kBAAkB,EAAE,kBAAkB,CAAC;IACvC,cAAc,EAAE,cAAc,CAAC;IAC/B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,kBAAkB,CAAqB;IAC/C,OAAO,CAAC,cAAc,CAAiB;IACvC,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,cAAc,CAAS;IAC/B,OAAO,CAAC,KAAK,CAAuB;IACpC,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,UAAU,CAAqC;IACvD,OAAO,CAAC,mBAAmB,CAAgB;IAC3C,OAAO,CAAC,cAAc,CAA8C;IACpE,OAAO,CAAC,WAAW,CAAkB;IACrC,OAAO,CAAC,aAAa,CAAkB;IACvC,OAAO,CAAC,YAAY,CAA6B;IACjD,OAAO,CAAC,oBAAoB,CAAkB;IAC9C,OAAO,CAAC,eAAe,CAA2B;IAClD,OAAO,CAAC,mBAAmB,CAAa;IACxC,OAAO,CAAC,8BAA8B,CAEtB;IAChB,OAAO,CAAC,YAAY,CAAkB;gBAE1B,MAAM,EAAE,gBAAgB;IAUpC,uBAAuB,IAAI,OAAO;IAIlC,uBAAuB,IAAI,OAAO;IAO5B,kBAAkB,IAAI,OAAO,CAAC,eAAe,GAAG,SAAS,CAAC;IAoB1D,qBAAqB,IAAI,OAAO,CAAC,OAAO,CAAC;IAgBzC,kBAAkB,CAAC,aAAa,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAwDzD,2BAA2B,IAAI,OAAO,CAAC,OAAO,CAAC;IA2BrD,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAYnC,wBAAwB,IAAI,IAAI;IAO1B,eAAe,IAAI,OAAO,CAAC,OAAO,CAAC;IAgBnC,eAAe,IAAI,OAAO,CAAC,OAAO,CAAC;IAkBzC,iBAAiB,IAAI,IAAI;IAUzB,iBAAiB,IAAI,MAAM;IAO3B,oBAAoB,CAAC,SAAS,GAAE,mBAAwB,GAAG,IAAI;IAiB/D,sBAAsB,IAAI,IAAI;IAmB9B,OAAO,CAAC,sBAAsB;IA4B9B,OAAO,CAAC,gBAAgB;IAyBxB,OAAO,CAAC,eAAe;YAUT,4BAA4B;IAoCpC,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAiBpE,iBAAiB,IAAI,IAAI;IAqCnB,gBAAgB,IAAI,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC;IAmBjD,cAAc,CAAC,SAAS,GAAE,mBAAwB,GAAG,OAAO,CAAC,OAAO,CAAC;IAoJrE,aAAa,IAAI,OAAO,CAAC,MAAM,CAAC;WAwCzB,qBAAqB,IAAI,OAAO,CAAC,OAAO,CAAC;CAYvD"}
1
+ {"version":3,"file":"microphone-handler.d.ts","sourceRoot":"","sources":["../src/microphone-handler.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,GAAG,MAAM,wCAAwC,CAAC;AAC9D,OAAO,KAAK,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAC3E,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAChE,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAEvD,UAAU,gBAAgB;IACxB,kBAAkB,EAAE,kBAAkB,CAAC;IACvC,cAAc,EAAE,cAAc,CAAC;IAC/B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,kBAAkB,CAAqB;IAC/C,OAAO,CAAC,cAAc,CAAiB;IACvC,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,cAAc,CAAS;IAC/B,OAAO,CAAC,KAAK,CAAuB;IACpC,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,UAAU,CAAqC;IACvD,OAAO,CAAC,mBAAmB,CAAgB;IAC3C,OAAO,CAAC,cAAc,CAA8C;IACpE,OAAO,CAAC,WAAW,CAAkB;IACrC,OAAO,CAAC,aAAa,CAAkB;IACvC,OAAO,CAAC,YAAY,CAA6B;IACjD,OAAO,CAAC,oBAAoB,CAAkB;IAC9C,OAAO,CAAC,eAAe,CAA2B;IAClD,OAAO,CAAC,mBAAmB,CAAa;IACxC,OAAO,CAAC,8BAA8B,CAEtB;IAChB,OAAO,CAAC,YAAY,CAAkB;IACtC,OAAO,CAAC,uBAAuB,CAAkB;gBAErC,MAAM,EAAE,gBAAgB;IAUpC,uBAAuB,IAAI,OAAO;IAIlC,uBAAuB,IAAI,OAAO;IAO5B,kBAAkB,IAAI,OAAO,CAAC,eAAe,GAAG,SAAS,CAAC;IAoB1D,qBAAqB,IAAI,OAAO,CAAC,OAAO,CAAC;IAgBzC,kBAAkB,CAAC,aAAa,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAwDzD,2BAA2B,IAAI,OAAO,CAAC,OAAO,CAAC;IA2BrD,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAYnC,wBAAwB,IAAI,IAAI;IAO1B,eAAe,IAAI,OAAO,CAAC,OAAO,CAAC;IAgBnC,eAAe,IAAI,OAAO,CAAC,OAAO,CAAC;IAkBzC,iBAAiB,IAAI,IAAI;IAUzB,iBAAiB,IAAI,MAAM;IAO3B,oBAAoB,CAAC,SAAS,GAAE,mBAAwB,GAAG,IAAI;IAiB/D,sBAAsB,IAAI,IAAI;IAmB9B,OAAO,CAAC,sBAAsB;IA4B9B,OAAO,CAAC,gBAAgB;IAyBxB,OAAO,CAAC,eAAe;YAUT,4BAA4B;IAoCpC,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAiBpE,iBAAiB,IAAI,IAAI;IAqCnB,gBAAgB,IAAI,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC;IAmBjD,cAAc,CAAC,SAAS,GAAE,mBAAwB,GAAG,OAAO,CAAC,OAAO,CAAC;IA6JrE,aAAa,IAAI,OAAO,CAAC,MAAM,CAAC;WA6CzB,qBAAqB,IAAI,OAAO,CAAC,OAAO,CAAC;CAYvD"}
@@ -14,6 +14,7 @@ export class MicrophoneHandler {
14
14
  this.lastRecognitionTime = 0;
15
15
  this.recognitionHealthCheckInterval = null;
16
16
  this.isRecovering = false;
17
+ this.isStoppingIntentionally = false;
17
18
  this.azureSpeechService = config.azureSpeechService;
18
19
  this.bedrockService = config.bedrockService;
19
20
  this.language = config.language || "en-IN";
@@ -296,6 +297,7 @@ export class MicrophoneHandler {
296
297
  console.warn("[MicrophoneHandler] Recovery in progress, cannot start");
297
298
  return false;
298
299
  }
300
+ this.isStoppingIntentionally = false;
299
301
  this.activeCallbacks = callbacks;
300
302
  if (!this.hasPermission) {
301
303
  const granted = await this.requestMicrophonePermission();
@@ -369,12 +371,16 @@ export class MicrophoneHandler {
369
371
  }
370
372
  };
371
373
  this.recognizer.sessionStopped = (_s, _e) => {
372
- console.log("[MicrophoneHandler] Session stopped unexpectedly by SDK");
374
+ if (this.isStoppingIntentionally) {
375
+ console.log("[MicrophoneHandler] Session stopped (user-initiated)");
376
+ this.isRecording = false;
377
+ this.stopHealthCheck();
378
+ return;
379
+ }
380
+ console.warn("[MicrophoneHandler] Session stopped unexpectedly by SDK - attempting auto-restart");
373
381
  this.isRecording = false;
374
382
  this.stopHealthCheck();
375
- if (this.activeCallbacks.onError) {
376
- this.activeCallbacks.onError(new Error("Speech recognition session stopped unexpectedly"));
377
- }
383
+ void this.recoverFromStalledRecognizer();
378
384
  };
379
385
  this.recognizer.startContinuousRecognitionAsync(() => {
380
386
  console.log("[MicrophoneHandler] Continuous recognition started");
@@ -395,24 +401,29 @@ export class MicrophoneHandler {
395
401
  async stopRecording() {
396
402
  this.clearSilenceTimer();
397
403
  this.stopHealthCheck();
404
+ this.isStoppingIntentionally = true;
398
405
  if (!this.isRecording || !this.recognizer) {
399
406
  console.warn("[MicrophoneHandler] Not currently recording");
407
+ this.isStoppingIntentionally = false;
400
408
  return this.getAggregatedText();
401
409
  }
402
410
  return new Promise((resolve) => {
403
411
  if (!this.recognizer) {
412
+ this.isStoppingIntentionally = false;
404
413
  resolve(this.getAggregatedText());
405
414
  return;
406
415
  }
407
416
  this.recognizer.stopContinuousRecognitionAsync(() => {
408
417
  console.log("[MicrophoneHandler] Recognition stopped successfully");
409
418
  this.isRecording = false;
419
+ this.isStoppingIntentionally = false;
410
420
  const finalText = this.getAggregatedText();
411
421
  this.disposeRecognizer();
412
422
  resolve(finalText);
413
423
  }, (error) => {
414
424
  console.error("[MicrophoneHandler] Error stopping recognition:", error);
415
425
  this.isRecording = false;
426
+ this.isStoppingIntentionally = false;
416
427
  const finalText = this.getAggregatedText();
417
428
  this.disposeRecognizer();
418
429
  resolve(finalText);
@@ -17,6 +17,8 @@ export declare class VoiceNavigationController {
17
17
  private pagesInitialized;
18
18
  private uiInitialized;
19
19
  private isSyncingButtonState;
20
+ private hasNavigatedAway;
21
+ private removeNavigationListener;
20
22
  constructor(config: NavigationConfig);
21
23
  private initializeUIAsync;
22
24
  private shouldAutoStart;
@@ -33,6 +35,7 @@ export declare class VoiceNavigationController {
33
35
  stop(options?: {
34
36
  triggeredByUser?: boolean;
35
37
  }): Promise<void>;
38
+ private trackNavigationAway;
36
39
  private syncCustomButtonState;
37
40
  private handlePartial;
38
41
  private handleSegment;
@@ -1 +1 @@
1
- {"version":3,"file":"navigation-controller.d.ts","sourceRoot":"","sources":["../src/navigation-controller.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,gBAAgB,EAMjB,MAAM,YAAY,CAAC;AA4DpB,qBAAa,yBAAyB;IACpC,OAAO,CAAC,MAAM,CAAmB;IACjC,OAAO,CAAC,iBAAiB,CAAoB;IAC7C,OAAO,CAAC,kBAAkB,CAAqB;IAC/C,OAAO,CAAC,cAAc,CAAiB;IACvC,OAAO,CAAC,oBAAoB,CAAuB;IACnD,OAAO,CAAC,YAAY,CAAe;IACnC,OAAO,CAAC,EAAE,CAAc;IACxB,OAAO,CAAC,cAAc,CAAc;IACpC,OAAO,CAAC,YAAY,CAAkB;IACtC,OAAO,CAAC,qBAAqB,CAAkB;IAC/C,OAAO,CAAC,eAAe,CAA2B;IAClD,OAAO,CAAC,+BAA+B,CAAkB;IACzD,OAAO,CAAC,wBAAwB,CAA6B;IAC7D,OAAO,CAAC,mBAAmB,CAAoC;IAC/D,OAAO,CAAC,gBAAgB,CAAgB;IACxC,OAAO,CAAC,aAAa,CAAgB;IACrC,OAAO,CAAC,oBAAoB,CAAkB;gBAElC,MAAM,EAAE,gBAAgB;YAqJtB,iBAAiB;IAiD/B,OAAO,CAAC,eAAe;IAoBhB,YAAY,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;IAepC,oBAAoB,CAAC,OAAO,GAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAA;KAAO,GAAG,IAAI;YAOtD,eAAe;IAmE7B,OAAO,CAAC,kBAAkB;YASZ,eAAe;IA8BhB,KAAK,CAChB,OAAO,GAAE;QAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;KAAO,GACzC,OAAO,CAAC,IAAI,CAAC;IAsFH,IAAI,CACf,OAAO,GAAE;QAAE,eAAe,CAAC,EAAE,OAAO,CAAA;KAAO,GAC1C,OAAO,CAAC,IAAI,CAAC;IAoDhB,OAAO,CAAC,qBAAqB;IAwB7B,OAAO,CAAC,aAAa;IAUrB,OAAO,CAAC,aAAa;YAWP,aAAa;YAOb,wBAAwB;IA2CtC,OAAO,CAAC,WAAW;YAuBL,iBAAiB;YAwBjB,iBAAiB;IAoRxB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAQnC,gBAAgB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;IAOxC,sBAAsB,IAAI,OAAO;YAO1B,qBAAqB;YAgFrB,yBAAyB;IAmMvC,OAAO,CAAC,oBAAoB;IAqD5B,OAAO,CAAC,yBAAyB;IAoCjC,OAAO,CAAC,UAAU;IAQlB,OAAO,CAAC,YAAY;IAUpB,OAAO,CAAC,YAAY;IASpB,OAAO,CAAC,4BAA4B;IAiB7B,OAAO,IAAI,IAAI;IAgBtB,OAAO,CAAC,kBAAkB;IA8B1B,OAAO,CAAC,kBAAkB;IAwD1B,OAAO,CAAC,aAAa;IAYrB,OAAO,CAAC,uBAAuB;IAqD/B,OAAO,CAAC,sBAAsB;IAW9B,OAAO,CAAC,wBAAwB;CAmBjC"}
1
+ {"version":3,"file":"navigation-controller.d.ts","sourceRoot":"","sources":["../src/navigation-controller.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,gBAAgB,EAMjB,MAAM,YAAY,CAAC;AA4DpB,qBAAa,yBAAyB;IACpC,OAAO,CAAC,MAAM,CAAmB;IACjC,OAAO,CAAC,iBAAiB,CAAoB;IAC7C,OAAO,CAAC,kBAAkB,CAAqB;IAC/C,OAAO,CAAC,cAAc,CAAiB;IACvC,OAAO,CAAC,oBAAoB,CAAuB;IACnD,OAAO,CAAC,YAAY,CAAe;IACnC,OAAO,CAAC,EAAE,CAAc;IACxB,OAAO,CAAC,cAAc,CAAc;IACpC,OAAO,CAAC,YAAY,CAAkB;IACtC,OAAO,CAAC,qBAAqB,CAAkB;IAC/C,OAAO,CAAC,eAAe,CAA2B;IAClD,OAAO,CAAC,+BAA+B,CAAkB;IACzD,OAAO,CAAC,wBAAwB,CAA6B;IAC7D,OAAO,CAAC,mBAAmB,CAAoC;IAC/D,OAAO,CAAC,gBAAgB,CAAgB;IACxC,OAAO,CAAC,aAAa,CAAgB;IACrC,OAAO,CAAC,oBAAoB,CAAkB;IAC9C,OAAO,CAAC,gBAAgB,CAAkB;IAC1C,OAAO,CAAC,wBAAwB,CAA6B;gBAEjD,MAAM,EAAE,gBAAgB;YA0JtB,iBAAiB;IAiD/B,OAAO,CAAC,eAAe;IAoBhB,YAAY,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;IAepC,oBAAoB,CAAC,OAAO,GAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAA;KAAO,GAAG,IAAI;YAOtD,eAAe;IAmE7B,OAAO,CAAC,kBAAkB;YASZ,eAAe;IA8BhB,KAAK,CAChB,OAAO,GAAE;QAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;KAAO,GACzC,OAAO,CAAC,IAAI,CAAC;IAuFH,IAAI,CACf,OAAO,GAAE;QAAE,eAAe,CAAC,EAAE,OAAO,CAAA;KAAO,GAC1C,OAAO,CAAC,IAAI,CAAC;IAqEhB,OAAO,CAAC,mBAAmB;IAoD3B,OAAO,CAAC,qBAAqB;IA4C7B,OAAO,CAAC,aAAa;IAUrB,OAAO,CAAC,aAAa;YAWP,aAAa;YAOb,wBAAwB;IA2CtC,OAAO,CAAC,WAAW;YAuBL,iBAAiB;YAwBjB,iBAAiB;IA6RxB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAQnC,gBAAgB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;IAOxC,sBAAsB,IAAI,OAAO;YAO1B,qBAAqB;YAgFrB,yBAAyB;IAmMvC,OAAO,CAAC,oBAAoB;IAqD5B,OAAO,CAAC,yBAAyB;IAoCjC,OAAO,CAAC,UAAU;IAQlB,OAAO,CAAC,YAAY;IAUpB,OAAO,CAAC,YAAY;IASpB,OAAO,CAAC,4BAA4B;IAiB7B,OAAO,IAAI,IAAI;IAgBtB,OAAO,CAAC,kBAAkB;IA8B1B,OAAO,CAAC,kBAAkB;IAwD1B,OAAO,CAAC,aAAa;IAYrB,OAAO,CAAC,uBAAuB;IAqD/B,OAAO,CAAC,sBAAsB;IAW9B,OAAO,CAAC,wBAAwB;CAmBjC"}
@@ -39,6 +39,8 @@ export class VoiceNavigationController {
39
39
  this.removeAutoStartListeners = null;
40
40
  this.vectorSearchService = null;
41
41
  this.isSyncingButtonState = false;
42
+ this.hasNavigatedAway = false;
43
+ this.removeNavigationListener = null;
42
44
  const openSearchConfig = resolveOpenSearchConfig(config);
43
45
  this.config = {
44
46
  ...config,
@@ -120,6 +122,9 @@ export class VoiceNavigationController {
120
122
  }
121
123
  }
122
124
  this.resumeAfterNavigation = this.consumeResumeState();
125
+ if (this.resumeAfterNavigation) {
126
+ this.hasNavigatedAway = true;
127
+ }
123
128
  this.uiInitialized = this.initializeUIAsync();
124
129
  if (this.resumeAfterNavigation) {
125
130
  void this.start({ reason: "auto" });
@@ -309,6 +314,7 @@ export class VoiceNavigationController {
309
314
  });
310
315
  if (started) {
311
316
  this.clearAutoStartFallback();
317
+ this.trackNavigationAway();
312
318
  setState(this.ui, "listening");
313
319
  emitEvent("state-change", { state: "listening" });
314
320
  }
@@ -344,8 +350,13 @@ export class VoiceNavigationController {
344
350
  emitEvent("state-change", { state: "idle" });
345
351
  updateTranscript(this.ui, "");
346
352
  if (!triggeredByUser && this.ui.isCustomButton) {
347
- console.log("[VoiceNavigation] Programmatically clicking custom button to sync external UI state");
348
- this.syncCustomButtonState();
353
+ if (!this.hasNavigatedAway) {
354
+ console.log("[VoiceNavigation] Programmatically clicking custom button to sync external UI state");
355
+ this.syncCustomButtonState();
356
+ }
357
+ else {
358
+ console.log("[VoiceNavigation] Skipping custom button click - user has navigated away from start page");
359
+ }
349
360
  }
350
361
  }
351
362
  catch (error) {
@@ -354,27 +365,80 @@ export class VoiceNavigationController {
354
365
  setState(this.ui, "error");
355
366
  emitEvent("error", { error });
356
367
  if (!triggeredByUser && this.ui.isCustomButton) {
357
- console.log("[VoiceNavigation] Programmatically clicking custom button after error");
358
- this.syncCustomButtonState();
368
+ if (!this.hasNavigatedAway) {
369
+ console.log("[VoiceNavigation] Programmatically clicking custom button after error");
370
+ this.syncCustomButtonState();
371
+ }
372
+ else {
373
+ console.log("[VoiceNavigation] Skipping custom button click after error - user has navigated away from start page");
374
+ }
359
375
  }
360
376
  }
361
377
  }
378
+ trackNavigationAway() {
379
+ if (typeof window === "undefined") {
380
+ return;
381
+ }
382
+ if (this.removeNavigationListener) {
383
+ this.removeNavigationListener();
384
+ this.removeNavigationListener = null;
385
+ }
386
+ const startUrl = window.location.href;
387
+ const markNavigatedAway = () => {
388
+ if (window.location.href !== startUrl) {
389
+ this.hasNavigatedAway = true;
390
+ console.log("[VoiceNavigation] User navigated away from start page - custom button sync disabled");
391
+ if (this.removeNavigationListener) {
392
+ this.removeNavigationListener();
393
+ this.removeNavigationListener = null;
394
+ }
395
+ }
396
+ };
397
+ window.addEventListener("popstate", markNavigatedAway);
398
+ const originalPushState = history.pushState.bind(history);
399
+ const originalReplaceState = history.replaceState.bind(history);
400
+ history.pushState = (...args) => {
401
+ originalPushState(...args);
402
+ markNavigatedAway();
403
+ };
404
+ history.replaceState = (...args) => {
405
+ originalReplaceState(...args);
406
+ markNavigatedAway();
407
+ };
408
+ this.removeNavigationListener = () => {
409
+ window.removeEventListener("popstate", markNavigatedAway);
410
+ history.pushState = originalPushState;
411
+ history.replaceState = originalReplaceState;
412
+ };
413
+ }
362
414
  syncCustomButtonState() {
363
- if (!this.ui.isCustomButton) {
415
+ if (!this.ui.isCustomButton || !this.ui.button) {
364
416
  return;
365
417
  }
418
+ console.log("[VoiceNavigation] Syncing custom button state");
366
419
  try {
367
420
  this.isSyncingButtonState = true;
421
+ this.ui.button.setAttribute("aria-pressed", "false");
422
+ this.ui.button.setAttribute("data-voice-state", "idle");
423
+ this.ui.button.classList.remove("active", "recording", "listening");
424
+ this.ui.button.classList.add("inactive", "stopped");
425
+ console.log("[VoiceNavigation] Updated button attributes");
426
+ const event = new CustomEvent("voiceNavigation:stopped", {
427
+ bubbles: true,
428
+ detail: { stopped: true },
429
+ });
430
+ this.ui.button.dispatchEvent(event);
431
+ console.log("[VoiceNavigation] Dispatched voiceNavigation:stopped event");
368
432
  this.ui.button.click();
369
- console.log("[VoiceNavigation] Custom button clicked to sync external UI state");
370
- }
371
- catch (error) {
372
- console.error("[VoiceNavigation] Failed to click custom button:", error);
373
- }
374
- finally {
433
+ console.log("[VoiceNavigation] Clicked button once to sync state");
375
434
  setTimeout(() => {
376
435
  this.isSyncingButtonState = false;
377
- }, 100);
436
+ console.log("[VoiceNavigation] Button state sync complete");
437
+ }, 500);
438
+ }
439
+ catch (error) {
440
+ console.error("[VoiceNavigation] Error syncing button state:", error);
441
+ this.isSyncingButtonState = false;
378
442
  }
379
443
  }
380
444
  handlePartial(text) {
@@ -491,6 +555,8 @@ export class VoiceNavigationController {
491
555
  await this.provideActionFeedback(action, actionResult, originalText);
492
556
  console.log("[VoiceNavigation] Search feedback complete, now navigating to:", actionResult.info.navigationUrl);
493
557
  if (actionResult.info.navigationUrl) {
558
+ if (this.ui.isCustomButton)
559
+ this.syncCustomButtonState();
494
560
  window.location.href = actionResult.info.navigationUrl;
495
561
  actionResult.info.navigated = true;
496
562
  actionResult.info.pendingNavigation = false;
@@ -499,6 +565,8 @@ export class VoiceNavigationController {
499
565
  catch (err) {
500
566
  console.error("[VoiceNavigation] Voice feedback error (search):", err);
501
567
  if (actionResult.info.navigationUrl) {
568
+ if (this.ui.isCustomButton)
569
+ this.syncCustomButtonState();
502
570
  window.location.href = actionResult.info.navigationUrl;
503
571
  }
504
572
  }
@@ -538,7 +606,7 @@ export class VoiceNavigationController {
538
606
  }
539
607
  const actionResult = performAgentAction(action, {
540
608
  handler: this,
541
- onStop: () => this.stop(),
609
+ onStop: () => this.stop({ triggeredByUser: false }),
542
610
  transcript: originalText,
543
611
  parameters: {
544
612
  text: actionData.text || query,
@@ -562,24 +630,32 @@ export class VoiceNavigationController {
562
630
  if (actionResult.info?.pendingNavigation) {
563
631
  if (actionResult.info.navigationUrl) {
564
632
  console.log("[VoiceNavigation] Feedback complete, now navigating to:", actionResult.info.navigationUrl);
633
+ if (this.ui.isCustomButton)
634
+ this.syncCustomButtonState();
565
635
  window.location.href = actionResult.info.navigationUrl;
566
636
  actionResult.info.navigated = true;
567
637
  actionResult.info.pendingNavigation = false;
568
638
  }
569
639
  else if (actionResult.info.navigationType === "back") {
570
640
  console.log("[VoiceNavigation] Feedback complete, navigating back");
641
+ if (this.ui.isCustomButton)
642
+ this.syncCustomButtonState();
571
643
  window.history.back();
572
644
  actionResult.info.navigated = true;
573
645
  actionResult.info.pendingNavigation = false;
574
646
  }
575
647
  else if (actionResult.info.navigationType === "forward") {
576
648
  console.log("[VoiceNavigation] Feedback complete, navigating forward");
649
+ if (this.ui.isCustomButton)
650
+ this.syncCustomButtonState();
577
651
  window.history.forward();
578
652
  actionResult.info.navigated = true;
579
653
  actionResult.info.pendingNavigation = false;
580
654
  }
581
655
  else if (actionResult.info.navigationType === "reload") {
582
656
  console.log("[VoiceNavigation] Feedback complete, reloading page");
657
+ if (this.ui.isCustomButton)
658
+ this.syncCustomButtonState();
583
659
  window.location.reload();
584
660
  actionResult.info.reloaded = true;
585
661
  actionResult.info.pendingNavigation = false;
@@ -589,6 +665,8 @@ export class VoiceNavigationController {
589
665
  catch (err) {
590
666
  console.error("[VoiceNavigation] Voice feedback error (critical action):", err);
591
667
  if (actionResult.info?.pendingNavigation) {
668
+ if (this.ui.isCustomButton)
669
+ this.syncCustomButtonState();
592
670
  if (actionResult.info.navigationUrl) {
593
671
  console.log("[VoiceNavigation] Feedback failed, but proceeding with navigation:", actionResult.info.navigationUrl);
594
672
  window.location.href = actionResult.info.navigationUrl;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@myscheme/voice-navigation-sdk",
3
- "version": "0.1.8",
3
+ "version": "0.1.9",
4
4
  "description": "Voice navigation SDK using Azure Speech and AWS Bedrock",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",