@mentra/engine 3.2.0-dev.217 → 3.2.0-dev.222

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 (87) hide show
  1. package/build/generated/releaseMetadata.js +5 -5
  2. package/build/generated/releaseMetadata.js.map +1 -1
  3. package/build/index.d.ts +3 -1
  4. package/build/index.d.ts.map +1 -1
  5. package/build/index.js +2 -1
  6. package/build/index.js.map +1 -1
  7. package/build/react/MentraLiveOtaFlow.d.ts.map +1 -1
  8. package/build/react/MentraLiveOtaFlow.js +19 -3
  9. package/build/react/MentraLiveOtaFlow.js.map +1 -1
  10. package/build/react/useMentraLiveOta.d.ts +12 -0
  11. package/build/react/useMentraLiveOta.d.ts.map +1 -1
  12. package/build/react/useMentraLiveOta.js +31 -5
  13. package/build/react/useMentraLiveOta.js.map +1 -1
  14. package/build/services/AcsMeetingService.d.ts +360 -10
  15. package/build/services/AcsMeetingService.d.ts.map +1 -1
  16. package/build/services/AcsMeetingService.js +836 -19
  17. package/build/services/AcsMeetingService.js.map +1 -1
  18. package/build/services/AudioPlaybackService.d.ts +6 -0
  19. package/build/services/AudioPlaybackService.d.ts.map +1 -1
  20. package/build/services/AudioPlaybackService.js +4 -3
  21. package/build/services/AudioPlaybackService.js.map +1 -1
  22. package/build/services/GlassesMicProbe.d.ts +78 -0
  23. package/build/services/GlassesMicProbe.d.ts.map +1 -0
  24. package/build/services/GlassesMicProbe.js +258 -0
  25. package/build/services/GlassesMicProbe.js.map +1 -0
  26. package/build/services/LocalMiniappRuntime.d.ts +83 -0
  27. package/build/services/LocalMiniappRuntime.d.ts.map +1 -1
  28. package/build/services/LocalMiniappRuntime.js +714 -39
  29. package/build/services/LocalMiniappRuntime.js.map +1 -1
  30. package/build/services/MentraJSLogPipeline.d.ts +39 -0
  31. package/build/services/MentraJSLogPipeline.d.ts.map +1 -1
  32. package/build/services/MentraJSLogPipeline.js +59 -3
  33. package/build/services/MentraJSLogPipeline.js.map +1 -1
  34. package/build/services/MentraJSRouter.d.ts +1 -1
  35. package/build/services/MentraJSRouter.d.ts.map +1 -1
  36. package/build/services/MentraJSRouter.js +2 -2
  37. package/build/services/MentraJSRouter.js.map +1 -1
  38. package/build/services/MicStateCoordinator.d.ts +22 -0
  39. package/build/services/MicStateCoordinator.d.ts.map +1 -1
  40. package/build/services/MicStateCoordinator.js +34 -3
  41. package/build/services/MicStateCoordinator.js.map +1 -1
  42. package/build/services/OtaErrorMapping.d.ts +25 -2
  43. package/build/services/OtaErrorMapping.d.ts.map +1 -1
  44. package/build/services/OtaErrorMapping.js +68 -23
  45. package/build/services/OtaErrorMapping.js.map +1 -1
  46. package/build/services/OtaInstallCoordinator.d.ts.map +1 -1
  47. package/build/services/OtaInstallCoordinator.js +6 -1
  48. package/build/services/OtaInstallCoordinator.js.map +1 -1
  49. package/build/services/PhoneStreamCoordinator.d.ts +8 -0
  50. package/build/services/PhoneStreamCoordinator.d.ts.map +1 -1
  51. package/build/services/PhoneStreamCoordinator.js +2 -0
  52. package/build/services/PhoneStreamCoordinator.js.map +1 -1
  53. package/build/services/SoftapCallTransport.d.ts +365 -0
  54. package/build/services/SoftapCallTransport.d.ts.map +1 -0
  55. package/build/services/SoftapCallTransport.js +722 -0
  56. package/build/services/SoftapCallTransport.js.map +1 -0
  57. package/build/services/SoftapCleanupBarrier.d.ts +45 -0
  58. package/build/services/SoftapCleanupBarrier.d.ts.map +1 -0
  59. package/build/services/SoftapCleanupBarrier.js +51 -0
  60. package/build/services/SoftapCleanupBarrier.js.map +1 -0
  61. package/build/utils/pcm16.d.ts +35 -0
  62. package/build/utils/pcm16.d.ts.map +1 -0
  63. package/build/utils/pcm16.js +85 -0
  64. package/build/utils/pcm16.js.map +1 -0
  65. package/build/utils/softapTrace.d.ts +39 -0
  66. package/build/utils/softapTrace.d.ts.map +1 -0
  67. package/build/utils/softapTrace.js +124 -0
  68. package/build/utils/softapTrace.js.map +1 -0
  69. package/package.json +7 -7
  70. package/src/generated/releaseMetadata.ts +5 -5
  71. package/src/index.ts +8 -0
  72. package/src/react/MentraLiveOtaFlow.tsx +22 -3
  73. package/src/react/useMentraLiveOta.ts +44 -6
  74. package/src/services/AcsMeetingService.ts +956 -22
  75. package/src/services/AudioPlaybackService.ts +12 -3
  76. package/src/services/GlassesMicProbe.ts +300 -0
  77. package/src/services/LocalMiniappRuntime.ts +775 -42
  78. package/src/services/MentraJSLogPipeline.ts +70 -3
  79. package/src/services/MentraJSRouter.ts +2 -2
  80. package/src/services/MicStateCoordinator.ts +35 -3
  81. package/src/services/OtaErrorMapping.ts +77 -25
  82. package/src/services/OtaInstallCoordinator.ts +6 -1
  83. package/src/services/PhoneStreamCoordinator.ts +10 -0
  84. package/src/services/SoftapCallTransport.ts +928 -0
  85. package/src/services/SoftapCleanupBarrier.ts +72 -0
  86. package/src/utils/pcm16.ts +93 -0
  87. package/src/utils/softapTrace.ts +133 -0
@@ -1 +1 @@
1
- {"version":3,"file":"MicStateCoordinator.js","sourceRoot":"","sources":["../../src/services/MicStateCoordinator.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * MicStateCoordinator\n *\n * Owns local-miniapp-driven microphone requirements.\n *\n * Local miniapps subscribe to audio_chunk / transcription streams.\n * This coordinator pushes the aggregate local requirement set to BluetoothSdk\n * so the mic runs whenever at least one local consumer needs it.\n */\n\nimport BluetoothSdk from \"@mentra/bluetooth-sdk/internal\"\n\nimport {createDebouncedPatchFlusher} from \"../utils/debouncedPatch\"\n\nconst LOG_TAG = \"MIC_COORDINATOR\"\n\ntype MicGate = \"vad\" | \"loudnessGate\"\n\ninterface GateOverride {\n enabled: boolean\n order: number\n}\n\ninterface ConfiguredMicGates {\n vadEnabled?: boolean | null\n loudnessGateEnabled?: boolean | null\n}\n\n/** Mic-requirement flips are debounced (300ms) and merged into one BLE write\n * (wire v2 keeps BLE JSON small and infrequent). */\nconst flushMicRequirementsPatch = createDebouncedPatchFlusher<Record<string, unknown>>((patch) => {\n try {\n // Resolve runtime overrides at flush time. A miniapp can acquire/release a\n // gate override during the debounce window, and a captured stale value\n // must not win after that lifecycle transition.\n const runtimePatch = micStateCoordinator.applyEffectiveGatePolicy(patch)\n void Promise.resolve(BluetoothSdk.updateBluetoothSettings(runtimePatch)).catch((err) => {\n console.error(`${LOG_TAG}: failed to apply mic requirements:`, err)\n })\n } catch (err) {\n console.error(`${LOG_TAG}: failed to apply mic requirements:`, err)\n }\n}, 300)\n\nclass MicStateCoordinator {\n private static instance: MicStateCoordinator | null = null\n\n // Local miniapp requirements (set when miniapps subscribe to audio streams)\n private localWantsPcm = false\n private localWantsLc3 = false\n private configuredVad: boolean | undefined\n private configuredLoudnessGate: boolean | undefined\n private readonly miniappVadOverrides = new Map<string, GateOverride>()\n private readonly miniappLoudnessGateOverrides = new Map<string, GateOverride>()\n private overrideSequence = 0\n\n private constructor() {}\n\n public static getInstance(): MicStateCoordinator {\n if (!MicStateCoordinator.instance) {\n MicStateCoordinator.instance = new MicStateCoordinator()\n }\n return MicStateCoordinator.instance\n }\n\n /**\n * Update local miniapp requirements. Called by LocalMiniappRuntime when\n * the aggregated set of local subscriptions changes.\n */\n public setLocalRequirements(req: {pcm: boolean; lc3: boolean} & ConfiguredMicGates): void {\n this.localWantsPcm = req.pcm\n this.localWantsLc3 = req.lc3\n this.rememberConfiguredGates(req)\n console.log(`${LOG_TAG}: local requirements updated — pcm=${req.pcm} lc3=${req.lc3}`)\n this.applyUnion()\n }\n\n /**\n * Apply a miniapp-owned gate override without changing the OS preference.\n * Overrides are lifecycle-scoped and last-live-owner-wins independently for\n * VAD and Barrier.\n */\n public async setMiniappGateOverride(\n packageName: string,\n gate: MicGate,\n enabled: boolean,\n configured: ConfiguredMicGates = {},\n ): Promise<void> {\n this.rememberConfiguredGates(configured)\n const overrides = this.overridesFor(gate)\n const previous = overrides.get(packageName)\n const next = {enabled, order: ++this.overrideSequence}\n overrides.set(packageName, next)\n\n try {\n await BluetoothSdk.updateBluetoothSettings(this.effectiveGatePatch())\n } catch (error) {\n // Do not roll back a newer request from the same package that landed\n // while this native write was in flight.\n if (overrides.get(packageName) === next) {\n if (previous) overrides.set(packageName, previous)\n else overrides.delete(packageName)\n }\n throw error\n }\n }\n\n /**\n * Remove every gate override owned by a miniapp. This is synchronous so\n * unregister can drop ownership before recomputing aggregate mic state.\n */\n public clearMiniappGateOverrides(packageName: string): boolean {\n const removedVad = this.miniappVadOverrides.delete(packageName)\n const removedLoudness = this.miniappLoudnessGateOverrides.delete(packageName)\n return removedVad || removedLoudness\n }\n\n /** Re-apply the current runtime policy after an owner is released. */\n public async syncEffectiveGatePolicy(configured: ConfiguredMicGates = {}): Promise<void> {\n this.rememberConfiguredGates(configured)\n const patch = this.effectiveGatePatch()\n if (Object.keys(patch).length === 0) return\n await BluetoothSdk.updateBluetoothSettings(patch)\n }\n\n /**\n * Preserve the runtime microphone contract when the persisted device\n * settings are replayed (for example after a glasses reconnect). Active\n * miniapp gate overrides replace the OS values, and raw PCM keeps VAD off\n * until the last raw-audio consumer unsubscribes.\n */\n public applyRuntimeOverrides(settings: Record<string, unknown>): Record<string, unknown> {\n this.rememberConfiguredGates({\n vadEnabled:\n typeof settings.voice_activity_detection_enabled === \"boolean\"\n ? settings.voice_activity_detection_enabled\n : undefined,\n loudnessGateEnabled:\n typeof settings.loudness_gate_enabled === \"boolean\" ? settings.loudness_gate_enabled : undefined,\n })\n\n return this.applyActiveRuntimeOverrides(settings)\n }\n\n /**\n * Apply the complete current gate policy without treating the input as an OS\n * preference update. Used by debounced mic-requirement writes, whose queued\n * gate values may be stale after an override is acquired or released.\n */\n public applyEffectiveGatePolicy(settings: Record<string, unknown>): Record<string, unknown> {\n return {\n ...settings,\n ...this.effectiveGatePatch(),\n }\n }\n\n private applyActiveRuntimeOverrides(settings: Record<string, unknown>): Record<string, unknown> {\n const runtimeSettings = {...settings}\n const vadOverride = this.latestOverride(this.miniappVadOverrides)\n const loudnessOverride = this.latestOverride(this.miniappLoudnessGateOverrides)\n\n if (this.localWantsPcm) {\n runtimeSettings.voice_activity_detection_enabled = false\n } else if (vadOverride) {\n runtimeSettings.voice_activity_detection_enabled = vadOverride.enabled\n }\n if (loudnessOverride) {\n runtimeSettings.loudness_gate_enabled = loudnessOverride.enabled\n }\n\n return runtimeSettings\n }\n\n /**\n * Push local requirements to BluetoothSdk. `should_send_pcm` is strictly for\n * on-device PCM consumers; cloud audio uses LC3 through AudioCloudUplink.\n */\n private applyUnion(): void {\n const shouldSendPcm = this.localWantsPcm\n const shouldSendLc3 = this.localWantsLc3\n\n // console.log(\n // `${LOG_TAG}: applying requirements — pcm=${shouldSendPcm} lc3=${shouldSendLc3}`,\n // )\n\n // The mic control plane is a direct btsdk call now (was a host setMicRequirements\n // hook) so a bare OEM streams audio without wiring it.\n const patch: Record<string, unknown> = {\n should_send_pcm: shouldSendPcm,\n should_send_lc3: shouldSendLc3,\n should_send_transcript: false,\n ...this.effectiveGatePatch(),\n }\n\n flushMicRequirementsPatch(patch)\n }\n\n private rememberConfiguredGates(configured: ConfiguredMicGates): void {\n // null means the connected device intentionally omits that setting.\n // undefined means the caller is not updating the remembered preference.\n if (configured.vadEnabled !== undefined) {\n this.configuredVad = configured.vadEnabled ?? undefined\n }\n if (configured.loudnessGateEnabled !== undefined) {\n this.configuredLoudnessGate = configured.loudnessGateEnabled ?? undefined\n }\n }\n\n private overridesFor(gate: MicGate): Map<string, GateOverride> {\n return gate === \"vad\" ? this.miniappVadOverrides : this.miniappLoudnessGateOverrides\n }\n\n private latestOverride(overrides: Map<string, GateOverride>): GateOverride | undefined {\n let latest: GateOverride | undefined\n for (const entry of overrides.values()) {\n if (!latest || entry.order > latest.order) latest = entry\n }\n return latest\n }\n\n private effectiveGatePatch(): Record<string, unknown> {\n const patch: Record<string, unknown> = {}\n const vadOverride = this.latestOverride(this.miniappVadOverrides)\n const loudnessOverride = this.latestOverride(this.miniappLoudnessGateOverrides)\n\n // Hardware VAD suppresses silence. Raw-audio consumers need a continuous\n // timeline, so their requirement wins over both OS and miniapp VAD values.\n if (this.localWantsPcm) patch.voice_activity_detection_enabled = false\n else if (vadOverride) patch.voice_activity_detection_enabled = vadOverride.enabled\n else if (this.configuredVad !== undefined) patch.voice_activity_detection_enabled = this.configuredVad\n\n if (loudnessOverride) patch.loudness_gate_enabled = loudnessOverride.enabled\n else if (this.configuredLoudnessGate !== undefined) {\n patch.loudness_gate_enabled = this.configuredLoudnessGate\n }\n\n return patch\n }\n\n /**\n * Reset all requirements to off. Called during cleanup.\n */\n public reset(): void {\n this.localWantsPcm = false\n this.localWantsLc3 = false\n this.applyUnion()\n }\n\n public cleanup(): void {\n console.log(`${LOG_TAG}: cleanup()`)\n this.miniappVadOverrides.clear()\n this.miniappLoudnessGateOverrides.clear()\n this.reset()\n MicStateCoordinator.instance = null\n }\n}\n\nconst micStateCoordinator = MicStateCoordinator.getInstance()\nexport default micStateCoordinator\n"]}
1
+ {"version":3,"file":"MicStateCoordinator.js","sourceRoot":"","sources":["../../src/services/MicStateCoordinator.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * MicStateCoordinator\n *\n * Owns local-miniapp-driven microphone requirements.\n *\n * Local miniapps subscribe to audio_chunk / transcription streams.\n * This coordinator pushes the aggregate local requirement set to BluetoothSdk\n * so the mic runs whenever at least one local consumer needs it.\n */\n\nimport BluetoothSdk from \"@mentra/bluetooth-sdk/internal\"\n\nimport {createDebouncedPatchFlusher} from \"../utils/debouncedPatch\"\n\nconst LOG_TAG = \"MIC_COORDINATOR\"\n\ntype MicGate = \"vad\" | \"loudnessGate\"\n\ninterface GateOverride {\n enabled: boolean\n order: number\n}\n\ninterface ConfiguredMicGates {\n vadEnabled?: boolean | null\n loudnessGateEnabled?: boolean | null\n}\n\n/** Mic-requirement flips are debounced (300ms) and merged into one BLE write\n * (wire v2 keeps BLE JSON small and infrequent). */\nconst flushMicRequirementsPatch = createDebouncedPatchFlusher<Record<string, unknown>>((patch) => {\n try {\n // Resolve runtime overrides at flush time. A miniapp can acquire/release a\n // gate override during the debounce window, and a captured stale value\n // must not win after that lifecycle transition.\n const runtimePatch = micStateCoordinator.applyEffectiveGatePolicy(patch)\n void Promise.resolve(BluetoothSdk.updateBluetoothSettings(runtimePatch)).catch((err) => {\n console.error(`${LOG_TAG}: failed to apply mic requirements:`, err)\n })\n } catch (err) {\n console.error(`${LOG_TAG}: failed to apply mic requirements:`, err)\n }\n}, 300)\n\nclass MicStateCoordinator {\n private static instance: MicStateCoordinator | null = null\n\n // Local miniapp requirements (set when miniapps subscribe to audio streams)\n private localWantsPcm = false\n private localWantsLc3 = false\n /**\n * A live ACS call taking the wearer's voice off the glasses over BLE LC3.\n *\n * Tracked separately from the miniapp requirement because the two have independent lifetimes:\n * the call miniapp does not subscribe to `audio_chunk`, and a captions miniapp that stops mid-call\n * must not take the call's microphone with it.\n */\n private callWantsPcm = false\n private configuredVad: boolean | undefined\n private configuredLoudnessGate: boolean | undefined\n private readonly miniappVadOverrides = new Map<string, GateOverride>()\n private readonly miniappLoudnessGateOverrides = new Map<string, GateOverride>()\n private overrideSequence = 0\n\n private constructor() {}\n\n public static getInstance(): MicStateCoordinator {\n if (!MicStateCoordinator.instance) {\n MicStateCoordinator.instance = new MicStateCoordinator()\n }\n return MicStateCoordinator.instance\n }\n\n /**\n * Update local miniapp requirements. Called by LocalMiniappRuntime when\n * the aggregated set of local subscriptions changes.\n */\n public setLocalRequirements(req: {pcm: boolean; lc3: boolean} & ConfiguredMicGates): void {\n this.localWantsPcm = req.pcm\n this.localWantsLc3 = req.lc3\n this.rememberConfiguredGates(req)\n console.log(`${LOG_TAG}: local requirements updated — pcm=${req.pcm} lc3=${req.lc3}`)\n this.applyUnion()\n }\n\n /**\n * Claim or release raw PCM on behalf of an active call.\n *\n * Called by AcsMeetingService around a call whose uplink is the glasses microphone over BLE LC3.\n * Releasing is a claim release, not a mic shutdown: if a captions miniapp still wants PCM the\n * microphone stays on, which is the whole reason this is a separate flag rather than a setter on\n * the local requirement.\n */\n public setCallRequirement(pcm: boolean): void {\n if (this.callWantsPcm === pcm) return\n this.callWantsPcm = pcm\n console.log(`${LOG_TAG}: call requirement updated — pcm=${pcm}`)\n this.applyUnion()\n }\n\n /**\n * Whether anything on this device needs a continuous raw-PCM timeline. Also the condition that\n * forces hardware VAD off: a gate that drops silence turns a call into clipped half-words.\n */\n private get wantsRawPcm(): boolean {\n return this.localWantsPcm || this.callWantsPcm\n }\n\n /**\n * Apply a miniapp-owned gate override without changing the OS preference.\n * Overrides are lifecycle-scoped and last-live-owner-wins independently for\n * VAD and Barrier.\n */\n public async setMiniappGateOverride(\n packageName: string,\n gate: MicGate,\n enabled: boolean,\n configured: ConfiguredMicGates = {},\n ): Promise<void> {\n this.rememberConfiguredGates(configured)\n const overrides = this.overridesFor(gate)\n const previous = overrides.get(packageName)\n const next = {enabled, order: ++this.overrideSequence}\n overrides.set(packageName, next)\n\n try {\n await BluetoothSdk.updateBluetoothSettings(this.effectiveGatePatch())\n } catch (error) {\n // Do not roll back a newer request from the same package that landed\n // while this native write was in flight.\n if (overrides.get(packageName) === next) {\n if (previous) overrides.set(packageName, previous)\n else overrides.delete(packageName)\n }\n throw error\n }\n }\n\n /**\n * Remove every gate override owned by a miniapp. This is synchronous so\n * unregister can drop ownership before recomputing aggregate mic state.\n */\n public clearMiniappGateOverrides(packageName: string): boolean {\n const removedVad = this.miniappVadOverrides.delete(packageName)\n const removedLoudness = this.miniappLoudnessGateOverrides.delete(packageName)\n return removedVad || removedLoudness\n }\n\n /** Re-apply the current runtime policy after an owner is released. */\n public async syncEffectiveGatePolicy(configured: ConfiguredMicGates = {}): Promise<void> {\n this.rememberConfiguredGates(configured)\n const patch = this.effectiveGatePatch()\n if (Object.keys(patch).length === 0) return\n await BluetoothSdk.updateBluetoothSettings(patch)\n }\n\n /**\n * Preserve the runtime microphone contract when the persisted device\n * settings are replayed (for example after a glasses reconnect). Active\n * miniapp gate overrides replace the OS values, and raw PCM keeps VAD off\n * until the last raw-audio consumer unsubscribes.\n */\n public applyRuntimeOverrides(settings: Record<string, unknown>): Record<string, unknown> {\n this.rememberConfiguredGates({\n vadEnabled:\n typeof settings.voice_activity_detection_enabled === \"boolean\"\n ? settings.voice_activity_detection_enabled\n : undefined,\n loudnessGateEnabled:\n typeof settings.loudness_gate_enabled === \"boolean\" ? settings.loudness_gate_enabled : undefined,\n })\n\n return this.applyActiveRuntimeOverrides(settings)\n }\n\n /**\n * Apply the complete current gate policy without treating the input as an OS\n * preference update. Used by debounced mic-requirement writes, whose queued\n * gate values may be stale after an override is acquired or released.\n */\n public applyEffectiveGatePolicy(settings: Record<string, unknown>): Record<string, unknown> {\n return {\n ...settings,\n ...this.effectiveGatePatch(),\n }\n }\n\n private applyActiveRuntimeOverrides(settings: Record<string, unknown>): Record<string, unknown> {\n const runtimeSettings = {...settings}\n const vadOverride = this.latestOverride(this.miniappVadOverrides)\n const loudnessOverride = this.latestOverride(this.miniappLoudnessGateOverrides)\n\n if (this.wantsRawPcm) {\n runtimeSettings.voice_activity_detection_enabled = false\n } else if (vadOverride) {\n runtimeSettings.voice_activity_detection_enabled = vadOverride.enabled\n }\n if (loudnessOverride) {\n runtimeSettings.loudness_gate_enabled = loudnessOverride.enabled\n }\n\n return runtimeSettings\n }\n\n /**\n * Push local requirements to BluetoothSdk. `should_send_pcm` is strictly for\n * on-device PCM consumers; cloud audio uses LC3 through AudioCloudUplink.\n */\n private applyUnion(): void {\n const shouldSendPcm = this.wantsRawPcm\n const shouldSendLc3 = this.localWantsLc3\n\n // console.log(\n // `${LOG_TAG}: applying requirements — pcm=${shouldSendPcm} lc3=${shouldSendLc3}`,\n // )\n\n // The mic control plane is a direct btsdk call now (was a host setMicRequirements\n // hook) so a bare OEM streams audio without wiring it.\n const patch: Record<string, unknown> = {\n should_send_pcm: shouldSendPcm,\n should_send_lc3: shouldSendLc3,\n should_send_transcript: false,\n ...this.effectiveGatePatch(),\n }\n\n flushMicRequirementsPatch(patch)\n }\n\n private rememberConfiguredGates(configured: ConfiguredMicGates): void {\n // null means the connected device intentionally omits that setting.\n // undefined means the caller is not updating the remembered preference.\n if (configured.vadEnabled !== undefined) {\n this.configuredVad = configured.vadEnabled ?? undefined\n }\n if (configured.loudnessGateEnabled !== undefined) {\n this.configuredLoudnessGate = configured.loudnessGateEnabled ?? undefined\n }\n }\n\n private overridesFor(gate: MicGate): Map<string, GateOverride> {\n return gate === \"vad\" ? this.miniappVadOverrides : this.miniappLoudnessGateOverrides\n }\n\n private latestOverride(overrides: Map<string, GateOverride>): GateOverride | undefined {\n let latest: GateOverride | undefined\n for (const entry of overrides.values()) {\n if (!latest || entry.order > latest.order) latest = entry\n }\n return latest\n }\n\n private effectiveGatePatch(): Record<string, unknown> {\n const patch: Record<string, unknown> = {}\n const vadOverride = this.latestOverride(this.miniappVadOverrides)\n const loudnessOverride = this.latestOverride(this.miniappLoudnessGateOverrides)\n\n // Hardware VAD suppresses silence. Raw-audio consumers need a continuous\n // timeline, so their requirement wins over both OS and miniapp VAD values.\n if (this.wantsRawPcm) patch.voice_activity_detection_enabled = false\n else if (vadOverride) patch.voice_activity_detection_enabled = vadOverride.enabled\n else if (this.configuredVad !== undefined) patch.voice_activity_detection_enabled = this.configuredVad\n\n if (loudnessOverride) patch.loudness_gate_enabled = loudnessOverride.enabled\n else if (this.configuredLoudnessGate !== undefined) {\n patch.loudness_gate_enabled = this.configuredLoudnessGate\n }\n\n return patch\n }\n\n /**\n * Reset all requirements to off. Called during cleanup.\n */\n public reset(): void {\n this.localWantsPcm = false\n this.localWantsLc3 = false\n this.callWantsPcm = false\n this.applyUnion()\n }\n\n public cleanup(): void {\n console.log(`${LOG_TAG}: cleanup()`)\n this.miniappVadOverrides.clear()\n this.miniappLoudnessGateOverrides.clear()\n this.reset()\n MicStateCoordinator.instance = null\n }\n}\n\nconst micStateCoordinator = MicStateCoordinator.getInstance()\nexport default micStateCoordinator\n"]}
@@ -1,5 +1,27 @@
1
1
  import type { OtaProgress, OtaStatus } from "../facades/ota";
2
- export declare const BES_INSTALL_RESTART_MESSAGE = "Restart your glasses to safely exit firmware update mode before trying again";
2
+ /**
3
+ * Copy keys for OTA failures the glasses report by code (`ota_status.error`), plus the
4
+ * phone-side BES restart instruction. Hosts translate these keys; the engine's own
5
+ * English copy for each key lives in `OTA_ERROR_ENGLISH_COPY`.
6
+ *
7
+ * The glasses-side producers are `sendProgressToPhone(..., "FAILED", errorCode)` in the
8
+ * ASG client's OtaHelper (download classification, install failures, and the downgrade
9
+ * handoff to the recovery worker). Keep this table in sync with those codes; anything
10
+ * else falls back to `OTA_ERROR_UNKNOWN_GLASSES_COPY_KEY` and the raw code is shown in a
11
+ * secondary line so support can still identify it.
12
+ */
13
+ export declare const OTA_GLASSES_ERROR_COPY_KEYS: Readonly<Record<string, string>>;
14
+ export declare const OTA_ERROR_UNKNOWN_GLASSES_COPY_KEY = "ota:errorGlassesUnknown";
15
+ export declare const OTA_ERROR_GENERIC_COPY_KEY = "ota:errorGeneric";
16
+ export declare const OTA_ERROR_BES_RESTART_REQUIRED_COPY_KEY = "ota:errorBesRestartRequired";
17
+ /** English copy for every OTA error key above. Mirrored in the Mentra App's `ota` i18n namespace. */
18
+ export declare const OTA_ERROR_ENGLISH_COPY: Readonly<Record<string, string>>;
19
+ export declare const BES_INSTALL_RESTART_MESSAGE: string;
20
+ /**
21
+ * Copy key for a glasses-reported failure code. Unknown codes get the generic
22
+ * glasses-error copy; a missing code gets the plain generic copy.
23
+ */
24
+ export declare function otaErrorCopyKey(error?: string | null): string;
3
25
  /**
4
26
  * Offer Change WiFi whenever the OTA flow failed while the glasses were in the
5
27
  * download step (any download failure — network, SSL, size cap, verify, etc.).
@@ -8,7 +30,8 @@ export declare const BES_INSTALL_RESTART_MESSAGE = "Restart your glasses to safe
8
30
  * an active download phase (stall / global timeout mid-download).
9
31
  */
10
32
  export declare function shouldShowChangeWifiForOtaDownloadFailure(otaStatus: OtaStatus | null | undefined, otaProgress: OtaProgress | null | undefined, localErrorMessage: string): boolean;
11
- export declare function getOtaErrorMessage(error?: string): string;
33
+ /** English message for a glasses-reported failure code. Never echoes the raw code. */
34
+ export declare function getOtaErrorMessage(error?: string | null): string;
12
35
  /**
13
36
  * Once a BES install has started, any failure conservatively requires a glasses restart. This
14
37
  * avoids adding a BES-specific error code to the wire protocol and, more importantly, never offers
@@ -1 +1 @@
1
- {"version":3,"file":"OtaErrorMapping.d.ts","sourceRoot":"","sources":["../../src/services/OtaErrorMapping.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,WAAW,EAAE,SAAS,EAAC,MAAM,gBAAgB,CAAA;AAE1D,eAAO,MAAM,2BAA2B,iFACwC,CAAA;AAehF;;;;;;GAMG;AACH,wBAAgB,yCAAyC,CACvD,SAAS,EAAE,SAAS,GAAG,IAAI,GAAG,SAAS,EACvC,WAAW,EAAE,WAAW,GAAG,IAAI,GAAG,SAAS,EAC3C,iBAAiB,EAAE,MAAM,GACxB,OAAO,CAcT;AAED,wBAAgB,kBAAkB,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAuBzD;AAED;;;;GAIG;AACH,wBAAgB,uCAAuC,CACrD,SAAS,EAAE,SAAS,GAAG,IAAI,GAAG,SAAS,EACvC,YAAY,EAAE,WAAW,GAAG,IAAI,GAAG,SAAS,EAC5C,iBAAiB,EAAE,MAAM,GACxB,OAAO,CAKT"}
1
+ {"version":3,"file":"OtaErrorMapping.d.ts","sourceRoot":"","sources":["../../src/services/OtaErrorMapping.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,WAAW,EAAE,SAAS,EAAC,MAAM,gBAAgB,CAAA;AAE1D;;;;;;;;;;GAUG;AACH,eAAO,MAAM,2BAA2B,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAcxE,CAAA;AAED,eAAO,MAAM,kCAAkC,4BAA4B,CAAA;AAC3E,eAAO,MAAM,0BAA0B,qBAAqB,CAAA;AAC5D,eAAO,MAAM,uCAAuC,gCAAgC,CAAA;AAEpF,qGAAqG;AACrG,eAAO,MAAM,sBAAsB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAsBnE,CAAA;AAED,eAAO,MAAM,2BAA2B,QAAkE,CAAA;AAE1G;;;GAGG;AACH,wBAAgB,eAAe,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAO7D;AAmBD;;;;;;GAMG;AACH,wBAAgB,yCAAyC,CACvD,SAAS,EAAE,SAAS,GAAG,IAAI,GAAG,SAAS,EACvC,WAAW,EAAE,WAAW,GAAG,IAAI,GAAG,SAAS,EAC3C,iBAAiB,EAAE,MAAM,GACxB,OAAO,CAcT;AAED,sFAAsF;AACtF,wBAAgB,kBAAkB,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAEhE;AAED;;;;GAIG;AACH,wBAAgB,uCAAuC,CACrD,SAAS,EAAE,SAAS,GAAG,IAAI,GAAG,SAAS,EACvC,YAAY,EAAE,WAAW,GAAG,IAAI,GAAG,SAAS,EAC5C,iBAAiB,EAAE,MAAM,GACxB,OAAO,CAKT"}
@@ -1,4 +1,69 @@
1
- export const BES_INSTALL_RESTART_MESSAGE = "Restart your glasses to safely exit firmware update mode before trying again";
1
+ /**
2
+ * Copy keys for OTA failures the glasses report by code (`ota_status.error`), plus the
3
+ * phone-side BES restart instruction. Hosts translate these keys; the engine's own
4
+ * English copy for each key lives in `OTA_ERROR_ENGLISH_COPY`.
5
+ *
6
+ * The glasses-side producers are `sendProgressToPhone(..., "FAILED", errorCode)` in the
7
+ * ASG client's OtaHelper (download classification, install failures, and the downgrade
8
+ * handoff to the recovery worker). Keep this table in sync with those codes; anything
9
+ * else falls back to `OTA_ERROR_UNKNOWN_GLASSES_COPY_KEY` and the raw code is shown in a
10
+ * secondary line so support can still identify it.
11
+ */
12
+ export const OTA_GLASSES_ERROR_COPY_KEYS = {
13
+ no_internet: "ota:errorNoInternet",
14
+ clock_skew: "ota:errorClockSkew",
15
+ ssl_error: "ota:errorSslError",
16
+ download_failed: "ota:errorDownloadFailed",
17
+ insufficient_storage: "ota:errorInsufficientStorage",
18
+ firmware_too_large: "ota:errorFirmwareTooLarge",
19
+ firmware_verify_failed: "ota:errorFirmwareVerifyFailed",
20
+ apk_verify_failed: "ota:errorApkVerifyFailed",
21
+ install_failed: "ota:errorInstallFailed",
22
+ apk_restart_guard_not_persisted: "ota:errorApkRestartGuardNotPersisted",
23
+ downgrade_handoff_refused: "ota:errorDowngradeHandoffRefused",
24
+ downgrade_handoff_failed: "ota:errorDowngradeHandoffFailed",
25
+ downgrade_transaction_stalled: "ota:errorDowngradeTransactionStalled",
26
+ };
27
+ export const OTA_ERROR_UNKNOWN_GLASSES_COPY_KEY = "ota:errorGlassesUnknown";
28
+ export const OTA_ERROR_GENERIC_COPY_KEY = "ota:errorGeneric";
29
+ export const OTA_ERROR_BES_RESTART_REQUIRED_COPY_KEY = "ota:errorBesRestartRequired";
30
+ /** English copy for every OTA error key above. Mirrored in the Mentra App's `ota` i18n namespace. */
31
+ export const OTA_ERROR_ENGLISH_COPY = {
32
+ "ota:errorNoInternet": "Glasses WiFi has no internet connection",
33
+ "ota:errorClockSkew": "Glasses clock is wrong — syncing time from your phone, then retrying update check",
34
+ "ota:errorSslError": "Secure connection failed — try a different WiFi network",
35
+ "ota:errorDownloadFailed": "Download failed — check glasses WiFi connection",
36
+ "ota:errorInsufficientStorage": "Not enough storage on your glasses — free up space before trying again",
37
+ "ota:errorFirmwareTooLarge": "Firmware file is unexpectedly large — please contact support",
38
+ "ota:errorFirmwareVerifyFailed": "Firmware verification failed — please try again or contact support",
39
+ "ota:errorApkVerifyFailed": "Update verification failed — please try again or contact support",
40
+ "ota:errorInstallFailed": "Install failed — please try again",
41
+ "ota:errorApkRestartGuardNotPersisted": "Your glasses could not save the update before restarting. Restart your glasses and try again.",
42
+ "ota:errorDowngradeHandoffRefused": "Your glasses could not start the version change. Restart your glasses and try again.",
43
+ "ota:errorDowngradeHandoffFailed": "The recovery service on your glasses did not respond. Restart your glasses and try again.",
44
+ "ota:errorDowngradeTransactionStalled": "The version change on your glasses did not finish. Restart your glasses and try again.",
45
+ "ota:errorGlassesUnknown": "Your glasses reported an unexpected error. Restart your glasses and try again.",
46
+ "ota:errorGeneric": "Update failed",
47
+ "ota:errorBesRestartRequired": "Restart your glasses to safely exit firmware update mode before trying again",
48
+ "ota:errorCode": "Error code: {{code}}",
49
+ };
50
+ export const BES_INSTALL_RESTART_MESSAGE = OTA_ERROR_ENGLISH_COPY[OTA_ERROR_BES_RESTART_REQUIRED_COPY_KEY];
51
+ /**
52
+ * Copy key for a glasses-reported failure code. Unknown codes get the generic
53
+ * glasses-error copy; a missing code gets the plain generic copy.
54
+ */
55
+ export function otaErrorCopyKey(error) {
56
+ if (!error)
57
+ return OTA_ERROR_GENERIC_COPY_KEY;
58
+ // Own-property lookup: a code that happens to name an inherited Object member
59
+ // ("constructor", "toString", ...) is unknown, not a mapped key.
60
+ return hasOwn(OTA_GLASSES_ERROR_COPY_KEYS, error)
61
+ ? OTA_GLASSES_ERROR_COPY_KEYS[error]
62
+ : OTA_ERROR_UNKNOWN_GLASSES_COPY_KEY;
63
+ }
64
+ function hasOwn(table, key) {
65
+ return Object.prototype.hasOwnProperty.call(table, key);
66
+ }
2
67
  function isDownloadPhaseSnapshot(otaStatus, otaProgress) {
3
68
  if (otaStatus?.phase === "download") {
4
69
  return true;
@@ -30,29 +95,9 @@ export function shouldShowChangeWifiForOtaDownloadFailure(otaStatus, otaProgress
30
95
  }
31
96
  return false;
32
97
  }
98
+ /** English message for a glasses-reported failure code. Never echoes the raw code. */
33
99
  export function getOtaErrorMessage(error) {
34
- switch (error) {
35
- case "no_internet":
36
- return "Glasses WiFi has no internet connection";
37
- case "clock_skew":
38
- return "Glasses clock is wrong — syncing time from your phone, then retrying update check";
39
- case "ssl_error":
40
- return "Secure connection failed — try a different WiFi network";
41
- case "download_failed":
42
- return "Download failed — check glasses WiFi connection";
43
- case "insufficient_storage":
44
- return "Not enough storage on your glasses — free up space before trying again";
45
- case "firmware_too_large":
46
- return "Firmware file is unexpectedly large — please contact support";
47
- case "firmware_verify_failed":
48
- return "Firmware verification failed — please try again or contact support";
49
- case "apk_verify_failed":
50
- return "Update verification failed — please try again or contact support";
51
- case "install_failed":
52
- return "Install failed — please try again";
53
- default:
54
- return error || "Update failed";
55
- }
100
+ return OTA_ERROR_ENGLISH_COPY[otaErrorCopyKey(error)];
56
101
  }
57
102
  /**
58
103
  * Once a BES install has started, any failure conservatively requires a glasses restart. This
@@ -1 +1 @@
1
- {"version":3,"file":"OtaErrorMapping.js","sourceRoot":"","sources":["../../src/services/OtaErrorMapping.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,2BAA2B,GACtC,8EAA8E,CAAA;AAEhF,SAAS,uBAAuB,CAC9B,SAAuC,EACvC,WAA2C;IAE3C,IAAI,SAAS,EAAE,KAAK,KAAK,UAAU,EAAE,CAAC;QACpC,OAAO,IAAI,CAAA;IACb,CAAC;IACD,IAAI,WAAW,EAAE,KAAK,KAAK,UAAU,EAAE,CAAC;QACtC,OAAO,IAAI,CAAA;IACb,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,yCAAyC,CACvD,SAAuC,EACvC,WAA2C,EAC3C,iBAAyB;IAEzB,IAAI,SAAS,EAAE,KAAK,KAAK,sBAAsB,IAAI,WAAW,EAAE,YAAY,KAAK,sBAAsB,EAAE,CAAC;QACxG,OAAO,KAAK,CAAA;IACd,CAAC;IACD,IAAI,SAAS,EAAE,MAAM,KAAK,QAAQ,IAAI,SAAS,CAAC,KAAK,KAAK,UAAU,EAAE,CAAC;QACrE,OAAO,IAAI,CAAA;IACb,CAAC;IACD,IAAI,WAAW,EAAE,MAAM,KAAK,QAAQ,IAAI,WAAW,CAAC,KAAK,KAAK,UAAU,EAAE,CAAC;QACzE,OAAO,IAAI,CAAA;IACb,CAAC;IACD,IAAI,iBAAiB,IAAI,uBAAuB,CAAC,SAAS,EAAE,WAAW,CAAC,EAAE,CAAC;QACzE,OAAO,IAAI,CAAA;IACb,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,KAAc;IAC/C,QAAQ,KAAK,EAAE,CAAC;QACd,KAAK,aAAa;YAChB,OAAO,yCAAyC,CAAA;QAClD,KAAK,YAAY;YACf,OAAO,mFAAmF,CAAA;QAC5F,KAAK,WAAW;YACd,OAAO,yDAAyD,CAAA;QAClE,KAAK,iBAAiB;YACpB,OAAO,iDAAiD,CAAA;QAC1D,KAAK,sBAAsB;YACzB,OAAO,wEAAwE,CAAA;QACjF,KAAK,oBAAoB;YACvB,OAAO,8DAA8D,CAAA;QACvE,KAAK,wBAAwB;YAC3B,OAAO,oEAAoE,CAAA;QAC7E,KAAK,mBAAmB;YACtB,OAAO,kEAAkE,CAAA;QAC3E,KAAK,gBAAgB;YACnB,OAAO,mCAAmC,CAAA;QAC5C;YACE,OAAO,KAAK,IAAI,eAAe,CAAA;IACnC,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,uCAAuC,CACrD,SAAuC,EACvC,YAA4C,EAC5C,iBAAyB;IAEzB,IAAI,SAAS,EAAE,QAAQ,KAAK,KAAK,IAAI,SAAS,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;QACnE,OAAO,KAAK,CAAA;IACd,CAAC;IACD,OAAO,SAAS,CAAC,MAAM,KAAK,QAAQ,IAAI,OAAO,CAAC,iBAAiB,CAAC,CAAA;AACpE,CAAC","sourcesContent":["import type {OtaProgress, OtaStatus} from \"../facades/ota\"\n\nexport const BES_INSTALL_RESTART_MESSAGE =\n \"Restart your glasses to safely exit firmware update mode before trying again\"\n\nfunction isDownloadPhaseSnapshot(\n otaStatus: OtaStatus | null | undefined,\n otaProgress: OtaProgress | null | undefined,\n): boolean {\n if (otaStatus?.phase === \"download\") {\n return true\n }\n if (otaProgress?.stage === \"download\") {\n return true\n }\n return false\n}\n\n/**\n * Offer Change WiFi whenever the OTA flow failed while the glasses were in the\n * download step (any download failure — network, SSL, size cap, verify, etc.).\n *\n * Also covers phone-side watchdog failures that fire while the store still shows\n * an active download phase (stall / global timeout mid-download).\n */\nexport function shouldShowChangeWifiForOtaDownloadFailure(\n otaStatus: OtaStatus | null | undefined,\n otaProgress: OtaProgress | null | undefined,\n localErrorMessage: string,\n): boolean {\n if (otaStatus?.error === \"insufficient_storage\" || otaProgress?.errorMessage === \"insufficient_storage\") {\n return false\n }\n if (otaStatus?.status === \"failed\" && otaStatus.phase === \"download\") {\n return true\n }\n if (otaProgress?.status === \"FAILED\" && otaProgress.stage === \"download\") {\n return true\n }\n if (localErrorMessage && isDownloadPhaseSnapshot(otaStatus, otaProgress)) {\n return true\n }\n return false\n}\n\nexport function getOtaErrorMessage(error?: string): string {\n switch (error) {\n case \"no_internet\":\n return \"Glasses WiFi has no internet connection\"\n case \"clock_skew\":\n return \"Glasses clock is wrong — syncing time from your phone, then retrying update check\"\n case \"ssl_error\":\n return \"Secure connection failed — try a different WiFi network\"\n case \"download_failed\":\n return \"Download failed — check glasses WiFi connection\"\n case \"insufficient_storage\":\n return \"Not enough storage on your glasses free up space before trying again\"\n case \"firmware_too_large\":\n return \"Firmware file is unexpectedly large — please contact support\"\n case \"firmware_verify_failed\":\n return \"Firmware verification failed — please try again or contact support\"\n case \"apk_verify_failed\":\n return \"Update verification failed — please try again or contact support\"\n case \"install_failed\":\n return \"Install failed — please try again\"\n default:\n return error || \"Update failed\"\n }\n}\n\n/**\n * Once a BES install has started, any failure conservatively requires a glasses restart. This\n * avoids adding a BES-specific error code to the wire protocol and, more importantly, never offers\n * an unsafe retry when a generic failure or silence may mean BES entered its raw OTA parser.\n */\nexport function shouldRequireGlassesRebootForBesFailure(\n otaStatus: OtaStatus | null | undefined,\n _otaProgress: OtaProgress | null | undefined,\n localErrorMessage: string,\n): boolean {\n if (otaStatus?.stepType !== \"bes\" || otaStatus.phase !== \"install\") {\n return false\n }\n return otaStatus.status === \"failed\" || Boolean(localErrorMessage)\n}\n"]}
1
+ {"version":3,"file":"OtaErrorMapping.js","sourceRoot":"","sources":["../../src/services/OtaErrorMapping.ts"],"names":[],"mappings":"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","sourcesContent":["import type {OtaProgress, OtaStatus} from \"../facades/ota\"\n\n/**\n * Copy keys for OTA failures the glasses report by code (`ota_status.error`), plus the\n * phone-side BES restart instruction. Hosts translate these keys; the engine's own\n * English copy for each key lives in `OTA_ERROR_ENGLISH_COPY`.\n *\n * The glasses-side producers are `sendProgressToPhone(..., \"FAILED\", errorCode)` in the\n * ASG client's OtaHelper (download classification, install failures, and the downgrade\n * handoff to the recovery worker). Keep this table in sync with those codes; anything\n * else falls back to `OTA_ERROR_UNKNOWN_GLASSES_COPY_KEY` and the raw code is shown in a\n * secondary line so support can still identify it.\n */\nexport const OTA_GLASSES_ERROR_COPY_KEYS: Readonly<Record<string, string>> = {\n no_internet: \"ota:errorNoInternet\",\n clock_skew: \"ota:errorClockSkew\",\n ssl_error: \"ota:errorSslError\",\n download_failed: \"ota:errorDownloadFailed\",\n insufficient_storage: \"ota:errorInsufficientStorage\",\n firmware_too_large: \"ota:errorFirmwareTooLarge\",\n firmware_verify_failed: \"ota:errorFirmwareVerifyFailed\",\n apk_verify_failed: \"ota:errorApkVerifyFailed\",\n install_failed: \"ota:errorInstallFailed\",\n apk_restart_guard_not_persisted: \"ota:errorApkRestartGuardNotPersisted\",\n downgrade_handoff_refused: \"ota:errorDowngradeHandoffRefused\",\n downgrade_handoff_failed: \"ota:errorDowngradeHandoffFailed\",\n downgrade_transaction_stalled: \"ota:errorDowngradeTransactionStalled\",\n}\n\nexport const OTA_ERROR_UNKNOWN_GLASSES_COPY_KEY = \"ota:errorGlassesUnknown\"\nexport const OTA_ERROR_GENERIC_COPY_KEY = \"ota:errorGeneric\"\nexport const OTA_ERROR_BES_RESTART_REQUIRED_COPY_KEY = \"ota:errorBesRestartRequired\"\n\n/** English copy for every OTA error key above. Mirrored in the Mentra App's `ota` i18n namespace. */\nexport const OTA_ERROR_ENGLISH_COPY: Readonly<Record<string, string>> = {\n \"ota:errorNoInternet\": \"Glasses WiFi has no internet connection\",\n \"ota:errorClockSkew\": \"Glasses clock is wrong — syncing time from your phone, then retrying update check\",\n \"ota:errorSslError\": \"Secure connection failed — try a different WiFi network\",\n \"ota:errorDownloadFailed\": \"Download failed — check glasses WiFi connection\",\n \"ota:errorInsufficientStorage\": \"Not enough storage on your glasses — free up space before trying again\",\n \"ota:errorFirmwareTooLarge\": \"Firmware file is unexpectedly large — please contact support\",\n \"ota:errorFirmwareVerifyFailed\": \"Firmware verification failed — please try again or contact support\",\n \"ota:errorApkVerifyFailed\": \"Update verification failed — please try again or contact support\",\n \"ota:errorInstallFailed\": \"Install failed — please try again\",\n \"ota:errorApkRestartGuardNotPersisted\":\n \"Your glasses could not save the update before restarting. Restart your glasses and try again.\",\n \"ota:errorDowngradeHandoffRefused\":\n \"Your glasses could not start the version change. Restart your glasses and try again.\",\n \"ota:errorDowngradeHandoffFailed\":\n \"The recovery service on your glasses did not respond. Restart your glasses and try again.\",\n \"ota:errorDowngradeTransactionStalled\":\n \"The version change on your glasses did not finish. Restart your glasses and try again.\",\n \"ota:errorGlassesUnknown\": \"Your glasses reported an unexpected error. Restart your glasses and try again.\",\n \"ota:errorGeneric\": \"Update failed\",\n \"ota:errorBesRestartRequired\": \"Restart your glasses to safely exit firmware update mode before trying again\",\n \"ota:errorCode\": \"Error code: {{code}}\",\n}\n\nexport const BES_INSTALL_RESTART_MESSAGE = OTA_ERROR_ENGLISH_COPY[OTA_ERROR_BES_RESTART_REQUIRED_COPY_KEY]\n\n/**\n * Copy key for a glasses-reported failure code. Unknown codes get the generic\n * glasses-error copy; a missing code gets the plain generic copy.\n */\nexport function otaErrorCopyKey(error?: string | null): string {\n if (!error) return OTA_ERROR_GENERIC_COPY_KEY\n // Own-property lookup: a code that happens to name an inherited Object member\n // (\"constructor\", \"toString\", ...) is unknown, not a mapped key.\n return hasOwn(OTA_GLASSES_ERROR_COPY_KEYS, error)\n ? OTA_GLASSES_ERROR_COPY_KEYS[error]\n : OTA_ERROR_UNKNOWN_GLASSES_COPY_KEY\n}\n\nfunction hasOwn(table: Readonly<Record<string, string>>, key: string): boolean {\n return Object.prototype.hasOwnProperty.call(table, key)\n}\n\nfunction isDownloadPhaseSnapshot(\n otaStatus: OtaStatus | null | undefined,\n otaProgress: OtaProgress | null | undefined,\n): boolean {\n if (otaStatus?.phase === \"download\") {\n return true\n }\n if (otaProgress?.stage === \"download\") {\n return true\n }\n return false\n}\n\n/**\n * Offer Change WiFi whenever the OTA flow failed while the glasses were in the\n * download step (any download failure — network, SSL, size cap, verify, etc.).\n *\n * Also covers phone-side watchdog failures that fire while the store still shows\n * an active download phase (stall / global timeout mid-download).\n */\nexport function shouldShowChangeWifiForOtaDownloadFailure(\n otaStatus: OtaStatus | null | undefined,\n otaProgress: OtaProgress | null | undefined,\n localErrorMessage: string,\n): boolean {\n if (otaStatus?.error === \"insufficient_storage\" || otaProgress?.errorMessage === \"insufficient_storage\") {\n return false\n }\n if (otaStatus?.status === \"failed\" && otaStatus.phase === \"download\") {\n return true\n }\n if (otaProgress?.status === \"FAILED\" && otaProgress.stage === \"download\") {\n return true\n }\n if (localErrorMessage && isDownloadPhaseSnapshot(otaStatus, otaProgress)) {\n return true\n }\n return false\n}\n\n/** English message for a glasses-reported failure code. Never echoes the raw code. */\nexport function getOtaErrorMessage(error?: string | null): string {\n return OTA_ERROR_ENGLISH_COPY[otaErrorCopyKey(error)]\n}\n\n/**\n * Once a BES install has started, any failure conservatively requires a glasses restart. This\n * avoids adding a BES-specific error code to the wire protocol and, more importantly, never offers\n * an unsafe retry when a generic failure or silence may mean BES entered its raw OTA parser.\n */\nexport function shouldRequireGlassesRebootForBesFailure(\n otaStatus: OtaStatus | null | undefined,\n _otaProgress: OtaProgress | null | undefined,\n localErrorMessage: string,\n): boolean {\n if (otaStatus?.stepType !== \"bes\" || otaStatus.phase !== \"install\") {\n return false\n }\n return otaStatus.status === \"failed\" || Boolean(localErrorMessage)\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"OtaInstallCoordinator.d.ts","sourceRoot":"","sources":["../../src/services/OtaInstallCoordinator.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"OtaInstallCoordinator.d.ts","sourceRoot":"","sources":["../../src/services/OtaInstallCoordinator.ts"],"names":[],"mappings":"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"}
@@ -719,7 +719,12 @@ class OtaInstallCoordinator {
719
719
  // suppress ota_start and hang the fresh downgrade until the global timeout).
720
720
  this.otaStartOwnership?.outcome === "acknowledged" &&
721
721
  otaStatus?.stepType === "apk" &&
722
- otaStatus.phase === "install") {
722
+ otaStatus.phase === "install" &&
723
+ // Only a live install arms the latch. A terminal failed status keeps stepType/phase
724
+ // apk/install and stays in the store, so without this gate every later pass (any
725
+ // unrelated store change) would re-arm the latch and the non-ownership block below
726
+ // would release it again, flooding the log with paired enter/release lines.
727
+ otaStatus.status === "in_progress") {
723
728
  console.log("[OTA_PROGRESS] version-change: apk install started — entering detour wait");
724
729
  this.versionChangeInstallStarted = true;
725
730
  this.emitInternalChange();