@ephia/dova-sdk 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (247) hide show
  1. package/README.md +89 -0
  2. package/dist/EphiaBinding-BvRmlqqC.d.ts +36 -0
  3. package/dist/EphiaFloatingButton-CxiF86VW.d.ts +65 -0
  4. package/dist/EphiaTextarea-B4_CAVUg.d.ts +183 -0
  5. package/dist/NativeBinding-ChG0GeSz.d.ts +53 -0
  6. package/dist/TargetBinding-BKGQwUMc.d.ts +89 -0
  7. package/dist/TiptapBinding-B-agfV2H.d.ts +45 -0
  8. package/dist/Transport-zdeA4Pou.d.ts +63 -0
  9. package/dist/audio-state-kZ3KSvux.d.ts +39 -0
  10. package/dist/chunk-35AJK2IO.js +1 -0
  11. package/dist/chunk-35AJK2IO.js.map +1 -0
  12. package/dist/chunk-3LXZODL4.js +886 -0
  13. package/dist/chunk-3LXZODL4.js.map +1 -0
  14. package/dist/chunk-5IK5TLSK.js +67 -0
  15. package/dist/chunk-5IK5TLSK.js.map +1 -0
  16. package/dist/chunk-7E43RY75.js +9 -0
  17. package/dist/chunk-7E43RY75.js.map +1 -0
  18. package/dist/chunk-A5UEXJ5R.js +183 -0
  19. package/dist/chunk-A5UEXJ5R.js.map +1 -0
  20. package/dist/chunk-AEE554FT.js +51 -0
  21. package/dist/chunk-AEE554FT.js.map +1 -0
  22. package/dist/chunk-DIEWY3IT.js +1332 -0
  23. package/dist/chunk-DIEWY3IT.js.map +1 -0
  24. package/dist/chunk-EGIAN7FH.js +18 -0
  25. package/dist/chunk-EGIAN7FH.js.map +1 -0
  26. package/dist/chunk-EMOEAPVU.js +486 -0
  27. package/dist/chunk-EMOEAPVU.js.map +1 -0
  28. package/dist/chunk-IDC7FHIZ.js +40 -0
  29. package/dist/chunk-IDC7FHIZ.js.map +1 -0
  30. package/dist/chunk-ITJFN3VM.js +601 -0
  31. package/dist/chunk-ITJFN3VM.js.map +1 -0
  32. package/dist/chunk-K24GNU27.js +22 -0
  33. package/dist/chunk-K24GNU27.js.map +1 -0
  34. package/dist/chunk-LXMCRXXF.js +778 -0
  35. package/dist/chunk-LXMCRXXF.js.map +1 -0
  36. package/dist/chunk-MJCEOOLW.js +122 -0
  37. package/dist/chunk-MJCEOOLW.js.map +1 -0
  38. package/dist/chunk-N7U5M3VZ.js +33 -0
  39. package/dist/chunk-N7U5M3VZ.js.map +1 -0
  40. package/dist/chunk-PSYX674B.js +27 -0
  41. package/dist/chunk-PSYX674B.js.map +1 -0
  42. package/dist/chunk-RFQRV7ML.js +33 -0
  43. package/dist/chunk-RFQRV7ML.js.map +1 -0
  44. package/dist/chunk-THNHRV2B.js +18 -0
  45. package/dist/chunk-THNHRV2B.js.map +1 -0
  46. package/dist/chunk-VSLGR64U.js +62 -0
  47. package/dist/chunk-VSLGR64U.js.map +1 -0
  48. package/dist/chunk-W2ZP674X.js +346 -0
  49. package/dist/chunk-W2ZP674X.js.map +1 -0
  50. package/dist/chunk-YWZUMUYE.js +695 -0
  51. package/dist/chunk-YWZUMUYE.js.map +1 -0
  52. package/dist/client-options-Uo6jXO8k.d.ts +64 -0
  53. package/dist/connection-state-Bk33YprE.d.ts +32 -0
  54. package/dist/core/bindings/index.d.ts +24 -0
  55. package/dist/core/bindings/index.js +1025 -0
  56. package/dist/core/bindings/index.js.map +1 -0
  57. package/dist/core/index.d.ts +383 -0
  58. package/dist/core/index.js +1284 -0
  59. package/dist/core/index.js.map +1 -0
  60. package/dist/createEphiaClient-BhdZ183V.d.ts +69 -0
  61. package/dist/devices/speechmike/index.d.ts +148 -0
  62. package/dist/devices/speechmike/index.js +40 -0
  63. package/dist/devices/speechmike/index.js.map +1 -0
  64. package/dist/headless/index.d.ts +10 -0
  65. package/dist/headless/index.js +25 -0
  66. package/dist/headless/index.js.map +1 -0
  67. package/dist/index.d.ts +18 -0
  68. package/dist/index.js +119 -0
  69. package/dist/index.js.map +1 -0
  70. package/dist/react/index.d.ts +38 -0
  71. package/dist/react/index.js +70 -0
  72. package/dist/react/index.js.map +1 -0
  73. package/dist/rich-editor/index.d.ts +46 -0
  74. package/dist/rich-editor/index.js +13 -0
  75. package/dist/rich-editor/index.js.map +1 -0
  76. package/dist/schema-B2ycPlNB.d.ts +87 -0
  77. package/dist/session-APaXR48R.d.ts +12 -0
  78. package/dist/shared/index.d.ts +16 -0
  79. package/dist/shared/index.js +30 -0
  80. package/dist/shared/index.js.map +1 -0
  81. package/dist/style.css +1093 -0
  82. package/dist/testing/index.d.ts +84 -0
  83. package/dist/testing/index.js +36 -0
  84. package/dist/testing/index.js.map +1 -0
  85. package/dist/types-D5SXPSwR.d.ts +32 -0
  86. package/dist/ui/index.d.ts +30 -0
  87. package/dist/ui/index.js +34 -0
  88. package/dist/ui/index.js.map +1 -0
  89. package/dist/useEphiaSpeechMike-CjD7DWnh.d.ts +64 -0
  90. package/package.json +110 -0
  91. package/src/core/audio/audio-worklet-source.ts +30 -0
  92. package/src/core/audio/index.ts +3 -0
  93. package/src/core/audio/voice-level-meter.test.ts +27 -0
  94. package/src/core/audio/voice-level-meter.ts +270 -0
  95. package/src/core/bindings/EphiaBinding.ts +41 -0
  96. package/src/core/bindings/SegmentBindingBridge.test.ts +422 -0
  97. package/src/core/bindings/SegmentBindingBridge.ts +377 -0
  98. package/src/core/bindings/TargetBinding.ts +142 -0
  99. package/src/core/bindings/adapters/NativeAdapter.test.ts +85 -0
  100. package/src/core/bindings/adapters/NativeAdapter.ts +216 -0
  101. package/src/core/bindings/adapters/ProseMirrorAdapter.ts +231 -0
  102. package/src/core/bindings/adapters/index.ts +2 -0
  103. package/src/core/bindings/binding-factory.ts +78 -0
  104. package/src/core/bindings/detect-editor-type.ts +87 -0
  105. package/src/core/bindings/index.ts +13 -0
  106. package/src/core/bindings/insertion-boundary.test.ts +38 -0
  107. package/src/core/bindings/insertion-boundary.ts +26 -0
  108. package/src/core/bindings/native/NativeBinding.test.ts +277 -0
  109. package/src/core/bindings/native/NativeBinding.ts +239 -0
  110. package/src/core/bindings/resolver.ts +18 -0
  111. package/src/core/bindings/targets/codemirror.binding.ts +293 -0
  112. package/src/core/bindings/targets/contenteditable.binding.ts +452 -0
  113. package/src/core/bindings/targets/index.ts +10 -0
  114. package/src/core/bindings/targets/monaco.binding.ts +315 -0
  115. package/src/core/bindings/targets/tiptap.binding.test.ts +417 -0
  116. package/src/core/bindings/targets/tiptap.binding.ts +1192 -0
  117. package/src/core/bindings/tiptap/TiptapBinding.test.ts +63 -0
  118. package/src/core/bindings/tiptap/TiptapBinding.ts +464 -0
  119. package/src/core/bindings/types.ts +41 -0
  120. package/src/core/client/EphiaAudioClient.ts +654 -0
  121. package/src/core/client/audio-capture.ts +263 -0
  122. package/src/core/client/client-options.ts +39 -0
  123. package/src/core/client/client-state.ts +18 -0
  124. package/src/core/client/constants.ts +23 -0
  125. package/src/core/client/session-api.ts +415 -0
  126. package/src/core/connection/connection-state.ts +78 -0
  127. package/src/core/connection/index.ts +6 -0
  128. package/src/core/index.ts +47 -0
  129. package/src/core/operations/textToDocumentOperations.test.ts +69 -0
  130. package/src/core/operations/textToDocumentOperations.ts +92 -0
  131. package/src/core/runtime/DictationRuntime.test.ts +578 -0
  132. package/src/core/runtime/DictationRuntime.ts +434 -0
  133. package/src/core/runtime/TranscriptApplier.test.ts +355 -0
  134. package/src/core/runtime/TranscriptApplier.ts +229 -0
  135. package/src/core/runtime/index.ts +18 -0
  136. package/src/core/session/index.ts +2 -0
  137. package/src/core/session/session-machine.test.ts +16 -0
  138. package/src/core/session/session-machine.ts +59 -0
  139. package/src/core/targets/EditorContextCollector.ts +71 -0
  140. package/src/core/targets/TargetManager.test.ts +194 -0
  141. package/src/core/targets/TargetManager.ts +194 -0
  142. package/src/core/targets/index.ts +10 -0
  143. package/src/core/text-processing/index.ts +11 -0
  144. package/src/core/text-processing/overlap.test.ts +35 -0
  145. package/src/core/text-processing/overlap.ts +101 -0
  146. package/src/core/text-processing/voice-formatting.normalizer.test.ts +132 -0
  147. package/src/core/text-processing/voice-formatting.normalizer.ts +284 -0
  148. package/src/core/transcript/client-transcript.reducer.ts +366 -0
  149. package/src/core/transcript/client-transcript.state.ts +25 -0
  150. package/src/core/transcript/index.ts +19 -0
  151. package/src/core/transcript/transcript.assembler.test.ts +205 -0
  152. package/src/core/transcript/transcript.assembler.ts +152 -0
  153. package/src/core/transcript/transcript.reducer.test.ts +199 -0
  154. package/src/core/transcript/transcript.reducer.ts +771 -0
  155. package/src/core/transcript/transcript.state.ts +123 -0
  156. package/src/core/transport/LiveKitTransport.publish.test.ts +226 -0
  157. package/src/core/transport/LiveKitTransport.ts +459 -0
  158. package/src/core/transport/MockTransport.ts +231 -0
  159. package/src/core/transport/Transport.ts +82 -0
  160. package/src/debug/sdk-debug-collector.ts +79 -0
  161. package/src/devices/index.ts +2 -0
  162. package/src/devices/speechmike/__tests__/EphiaSpeechMikeProvider.test.tsx +99 -0
  163. package/src/devices/speechmike/__tests__/speechmike-audio-resolver.test.ts +96 -0
  164. package/src/devices/speechmike/__tests__/speechmike-button-router.test.ts +66 -0
  165. package/src/devices/speechmike/__tests__/speechmike-device-manager.test.ts +201 -0
  166. package/src/devices/speechmike/__tests__/speechmike-led-controller.test.ts +68 -0
  167. package/src/devices/speechmike/browser.ts +80 -0
  168. package/src/devices/speechmike/constants.ts +74 -0
  169. package/src/devices/speechmike/dictation-support-loader.ts +81 -0
  170. package/src/devices/speechmike/index.ts +11 -0
  171. package/src/devices/speechmike/react/EphiaSpeechMikeContext.ts +34 -0
  172. package/src/devices/speechmike/react/EphiaSpeechMikeProvider.tsx +287 -0
  173. package/src/devices/speechmike/react/useEphiaSpeechMike.ts +26 -0
  174. package/src/devices/speechmike/speechmike-audio-resolver.ts +58 -0
  175. package/src/devices/speechmike/speechmike-button-router.ts +73 -0
  176. package/src/devices/speechmike/speechmike-device-manager.ts +461 -0
  177. package/src/devices/speechmike/speechmike-led-controller.ts +78 -0
  178. package/src/devices/speechmike/types.ts +96 -0
  179. package/src/dictation_support.d.ts +31 -0
  180. package/src/global.d.ts +10 -0
  181. package/src/headless/createEphiaClient.ts +220 -0
  182. package/src/headless/index.ts +18 -0
  183. package/src/index.ts +89 -0
  184. package/src/react/EphiaAuto.tsx +87 -0
  185. package/src/react/components/EphiaDictationButton.tsx +88 -0
  186. package/src/react/components/EphiaStatusBar.tsx +59 -0
  187. package/src/react/components/EphiaTextarea.tsx +295 -0
  188. package/src/react/ephia-react.css +318 -0
  189. package/src/react/hooks/targets/index.ts +3 -0
  190. package/src/react/hooks/targets/useEphiaCodemirror.ts +35 -0
  191. package/src/react/hooks/targets/useEphiaMonaco.ts +35 -0
  192. package/src/react/hooks/targets/useEphiaTiptap.ts +23 -0
  193. package/src/react/hooks/useEphia.lifecycle.test.tsx +389 -0
  194. package/src/react/hooks/useEphia.ts +367 -0
  195. package/src/react/hooks/useEphiaDiscardTarget.ts +53 -0
  196. package/src/react/hooks/useEphiaServerEvent.ts +33 -0
  197. package/src/react/hooks/useEphiaTarget.ts +47 -0
  198. package/src/react/hooks/useEphiaTranscript.ts +22 -0
  199. package/src/react/index.ts +58 -0
  200. package/src/react/provider/EphiaContext.ts +63 -0
  201. package/src/react/provider/EphiaInternalContext.ts +32 -0
  202. package/src/react/provider/EphiaProvider.tsx +373 -0
  203. package/src/react/registry/binding-factory.ts +7 -0
  204. package/src/react/registry/detect-editor-type.ts +2 -0
  205. package/src/react/registry/events.ts +37 -0
  206. package/src/react/registry/registries/CodeMirrorInstanceRegistry.ts +24 -0
  207. package/src/react/registry/registries/MonacoInstanceRegistry.ts +23 -0
  208. package/src/react/registry/registries/TargetRegistry.ts +327 -0
  209. package/src/react/registry/registries/TiptapInstanceRegistry.ts +43 -0
  210. package/src/react/registry/registries/index.ts +5 -0
  211. package/src/react/store/create-ephia-store.ts +36 -0
  212. package/src/react/store/types.ts +41 -0
  213. package/src/react/utils/flash-range.ts +24 -0
  214. package/src/react/utils/index.ts +1 -0
  215. package/src/rich-editor/adapters/tiptap.test.ts +86 -0
  216. package/src/rich-editor/adapters/tiptap.ts +23 -0
  217. package/src/rich-editor/index.ts +3 -0
  218. package/src/rich-editor/types.ts +24 -0
  219. package/src/rich-editor/use-ephia-rich-editor.test.tsx +202 -0
  220. package/src/rich-editor/use-ephia-rich-editor.ts +47 -0
  221. package/src/shared/config/endpoint.test.ts +45 -0
  222. package/src/shared/config/endpoint.ts +39 -0
  223. package/src/shared/config/schema.ts +32 -0
  224. package/src/shared/effective-text.ts +13 -0
  225. package/src/shared/errors/EphiaSdkError.ts +54 -0
  226. package/src/shared/errors/messages.ts +40 -0
  227. package/src/shared/index.ts +27 -0
  228. package/src/shared/state/audio-state.ts +45 -0
  229. package/src/shared/state/index.ts +2 -0
  230. package/src/shared/store/document-store.ts +32 -0
  231. package/src/shared/store/index.ts +2 -0
  232. package/src/shared/types/editors.ts +28 -0
  233. package/src/shared/types/session.ts +12 -0
  234. package/src/style.css +2 -0
  235. package/src/testing/index.tsx +60 -0
  236. package/src/ui/assets/ephia-logo.svg +4 -0
  237. package/src/ui/components/EphiaLogo.tsx +77 -0
  238. package/src/ui/index.ts +24 -0
  239. package/src/ui/primitives/Button.tsx +53 -0
  240. package/src/ui/primitives/Spinner.tsx +21 -0
  241. package/src/ui/primitives/index.ts +5 -0
  242. package/src/ui/recorder/EphiaFloatingButton.tsx +489 -0
  243. package/src/ui/recorder/MinimalProcessingBars.tsx +122 -0
  244. package/src/ui/recorder/StandardIntensityVisualizer.tsx +148 -0
  245. package/src/ui/recorder/appearance.ts +9 -0
  246. package/src/ui/recorder/index.ts +8 -0
  247. package/src/ui/theme.css +775 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/core/client/constants.ts","../src/core/client/session-api.ts","../src/core/client/audio-capture.ts","../src/core/audio/audio-worklet-source.ts","../src/core/audio/voice-level-meter.ts","../src/core/client/EphiaAudioClient.ts"],"sourcesContent":["import { PROTOCOL_VERSION as WIRE_PROTOCOL_VERSION } from \"ephia-protocol\";\n\nexport const SDK_VERSION = \"2.0.0\";\nexport const PROTOCOL_VERSION = WIRE_PROTOCOL_VERSION;\nexport const AUDIO_SESSIONS_PATH = \"/api/v1/audio/sessions\";\n\n/** Durée max de validité d'une session préchargée avant refetch (5 min). */\nexport const TOKEN_MAX_AGE_MS = 5 * 60 * 1000;\n/** TTL token LiveKit côté backend (6h). Refresh à 80%. */\nexport const ACTIVE_TOKEN_TTL_MS = 6 * 60 * 60 * 1000;\n/** Timeout attente session.closed — backend draine en ≤5s, marge incluse. */\nexport const SESSION_END_CLOSED_TIMEOUT_MS = 10_000;\n/** Grace period avant error sur déconnexion transport inattendue. */\nexport const DISCONNECT_GRACE_MS = 6_000;\n\nexport function createCommandId(prefix: string): string {\n const cryptoLike = globalThis.crypto as Crypto | undefined;\n const id =\n typeof cryptoLike?.randomUUID === \"function\"\n ? cryptoLike.randomUUID()\n : `${Date.now()}-${Math.random().toString(36).slice(2)}`;\n return `${prefix}:${id}`;\n}\n","/**\n * SessionApiClient — HTTP vers le backend Ephia (sessions, tokens, preload).\n *\n * Rôle : createSession, refreshToken, stopBackendSession, preload.\n * Possède : session préchargée et timers de refresh preload.\n * Ne fait pas : transport LiveKit, routing events.\n */\n\nimport { z } from \"zod\";\nimport type { EphiaSessionOptions } from \"../../shared/types/session\";\nimport { EphiaSdkError } from \"../../shared/errors/EphiaSdkError\";\nimport { resolveEphiaSdkApiUrl } from \"../../shared/config/endpoint\";\nimport type { EphiaStartOptions } from \"./client-options\";\nimport {\n ACTIVE_TOKEN_TTL_MS,\n AUDIO_SESSIONS_PATH,\n PROTOCOL_VERSION,\n SDK_VERSION,\n TOKEN_MAX_AGE_MS,\n} from \"./constants\";\n\nconst createSessionResponseSchema = z.object({\n session_id: z.string(),\n room_name: z.string(),\n token: z.string(),\n livekit_url: z.string(),\n protocol_version: z.string().optional(),\n capabilities: z\n .object({\n supports_realtime: z.boolean().optional(),\n })\n .optional(),\n});\n\nexport type SessionCredentials = {\n sessionId: string;\n roomName: string;\n token: string;\n livekitUrl: string;\n};\n\ntype PreloadedSession = SessionCredentials & {\n createdAt: number;\n initialTargetId?: string;\n};\n\nexport type SessionApiClientOptions = {\n apiUrl?: string;\n apiKey?: string;\n bearerToken?: string;\n clientType?: string;\n sessionOptions?: EphiaSessionOptions;\n onPrepareConnection?: (livekitUrl: string, token: string) => void;\n onPreloadComplete?: (data: SessionCredentials) => void;\n onPreloadFailed?: () => void;\n isIdle?: () => boolean;\n};\n\nexport class SessionApiClient {\n private readonly opts: SessionApiClientOptions;\n private _preloadedSession: PreloadedSession | null = null;\n private _preloadPromise: Promise<void> | null = null;\n private _preloadToken = 0;\n private _preloadRefreshTimer: ReturnType<typeof setTimeout> | null = null;\n\n constructor(opts: SessionApiClientOptions) {\n this.opts = opts;\n }\n\n get preloadedSession(): PreloadedSession | null {\n return this._preloadedSession;\n }\n\n get preloadToken(): number {\n return this._preloadToken;\n }\n\n incrementPreloadToken(): void {\n this._preloadToken++;\n }\n\n takePreloadedSession(): SessionCredentials | null {\n const s = this._preloadedSession;\n if (!s) return null;\n this._preloadedSession = null;\n return {\n sessionId: s.sessionId,\n roomName: s.roomName,\n token: s.token,\n livekitUrl: s.livekitUrl,\n };\n }\n\n discardPreloadedSession(): PreloadedSession | null {\n const s = this._preloadedSession;\n this._preloadedSession = null;\n return s;\n }\n\n clearPreloadPromise(): void {\n this._preloadPromise = null;\n }\n\n hasPreloadInFlight(): boolean {\n return this._preloadPromise !== null;\n }\n\n async awaitPreloadIfPending(signal?: AbortSignal): Promise<void> {\n const preloadPromise = this._preloadPromise;\n if (!preloadPromise) return;\n if (signal?.aborted) {\n throw new EphiaSdkError(\"client.start_failed\", \"Start aborted\");\n }\n if (!signal) {\n await preloadPromise;\n return;\n }\n\n await new Promise<void>((resolve, reject) => {\n const onAbort = () => {\n signal.removeEventListener(\"abort\", onAbort);\n reject(new EphiaSdkError(\"client.start_failed\", \"Start aborted\"));\n };\n signal.addEventListener(\"abort\", onAbort, { once: true });\n preloadPromise.then(\n () => {\n signal.removeEventListener(\"abort\", onAbort);\n resolve();\n },\n (err) => {\n signal.removeEventListener(\"abort\", onAbort);\n reject(err);\n }\n );\n });\n }\n\n cancelTimers(): void {\n if (this._preloadRefreshTimer !== null) {\n clearTimeout(this._preloadRefreshTimer);\n this._preloadRefreshTimer = null;\n }\n }\n\n async preload(signal?: AbortSignal): Promise<void>;\n async preload(options?: EphiaStartOptions, signal?: AbortSignal): Promise<void>;\n async preload(\n optionsOrSignal?: EphiaStartOptions | AbortSignal,\n maybeSignal?: AbortSignal\n ): Promise<void> {\n const signal =\n optionsOrSignal && \"aborted\" in optionsOrSignal ? optionsOrSignal : maybeSignal;\n const startOptions =\n optionsOrSignal && !(\"aborted\" in optionsOrSignal) ? optionsOrSignal : undefined;\n if (this.opts.isIdle && !this.opts.isIdle()) {\n console.info(\"[EphiaAudioClient] preload: skipped, not idle\");\n return;\n }\n if (this._preloadedSession) {\n console.info(\n \"[EphiaAudioClient] preload: already preloaded\",\n this._preloadedSession.sessionId\n );\n return;\n }\n if (this._preloadPromise) {\n return this._preloadPromise;\n }\n\n const token = ++this._preloadToken;\n const preloadPromise = this.createSession(signal, startOptions)\n .then((data) => {\n if (token !== this._preloadToken) {\n void this.stopBackendSession(data.sessionId);\n return;\n }\n this._preloadedSession = {\n ...data,\n createdAt: Date.now(),\n initialTargetId: startOptions?.initialTargetId,\n };\n this.opts.onPrepareConnection?.(data.livekitUrl, data.token);\n this.opts.onPreloadComplete?.(data);\n console.info(\"[EphiaAudioClient] preload:done\", data.sessionId);\n this.schedulePreloadRefresh();\n })\n .catch((err) => {\n if (err instanceof Error && err.name === \"AbortError\") return;\n console.warn(\"[EphiaAudioClient] preload:failed\", err);\n this.opts.onPreloadFailed?.();\n })\n .finally(() => {\n if (this._preloadPromise === preloadPromise) {\n this._preloadPromise = null;\n }\n });\n\n this._preloadPromise = preloadPromise;\n return this._preloadPromise;\n }\n\n schedulePreloadRefresh(): void {\n if (this._preloadRefreshTimer !== null) {\n clearTimeout(this._preloadRefreshTimer);\n }\n this._preloadRefreshTimer = setTimeout(() => {\n this._preloadRefreshTimer = null;\n if (this.opts.isIdle?.()) {\n console.info(\"[EphiaAudioClient] preload: auto-refreshing expired token\");\n const orphaned = this.discardPreloadedSession();\n if (orphaned) {\n void this.stopBackendSession(orphaned.sessionId);\n }\n this._preloadPromise = null;\n // Preserve initialTargetId from the previous preloaded session.\n const options = orphaned?.initialTargetId\n ? { initialTargetId: orphaned.initialTargetId }\n : undefined;\n void this.preload(options).catch(() => {});\n }\n }, TOKEN_MAX_AGE_MS * 0.8);\n }\n\n /** Refresh token LiveKit — retourne le nouveau token ou null. */\n async refreshToken(sessionId: string): Promise<string | null> {\n const apiUrl = resolveEphiaSdkApiUrl(this.opts.apiUrl);\n const headers = this.authHeaders();\n try {\n const r = await fetch(\n `${apiUrl}${AUDIO_SESSIONS_PATH}/${encodeURIComponent(sessionId)}/token`,\n { headers }\n );\n const data = (await r.json()) as { token?: string };\n if (data.token) {\n console.info(\"[EphiaAudioClient] token refreshed for next reconnect\", sessionId);\n return data.token;\n }\n } catch (err) {\n console.warn(\"[EphiaAudioClient] token refresh failed (non-fatal)\", err);\n }\n return null;\n }\n\n get activeTokenRefreshDelayMs(): number {\n return ACTIVE_TOKEN_TTL_MS * 0.8;\n }\n\n isPreloadedSessionExpired(): boolean {\n if (!this._preloadedSession) return false;\n return Date.now() - this._preloadedSession.createdAt > TOKEN_MAX_AGE_MS;\n }\n\n async createSessionWithRetry(\n signal?: AbortSignal,\n startOptions?: EphiaStartOptions\n ): Promise<SessionCredentials> {\n const maxRetries = 2;\n let lastErr: unknown;\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n if (signal?.aborted) {\n throw new EphiaSdkError(\"client.start_failed\", \"Start aborted\");\n }\n try {\n return await this.createSession(signal, startOptions);\n } catch (err) {\n lastErr = err;\n if (err instanceof EphiaSdkError) throw err;\n if (signal?.aborted) throw err;\n if (attempt < maxRetries) {\n const delay = 250 * Math.pow(2, attempt) + Math.random() * 100;\n console.warn(\n `[EphiaAudioClient] createSession:retry attempt=${attempt + 1} delay=${Math.round(delay)}ms`,\n err\n );\n await new Promise<void>((resolve) => setTimeout(resolve, delay));\n }\n }\n }\n throw lastErr;\n }\n\n async createSession(\n signal?: AbortSignal,\n startOptions?: EphiaStartOptions\n ): Promise<SessionCredentials> {\n const apiUrl = resolveEphiaSdkApiUrl(this.opts.apiUrl);\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n ...this.authHeaders(),\n };\n\n const so = this.opts.sessionOptions;\n const body: Record<string, unknown> = {\n session_mode: \"dictation\",\n client_type: this.opts.clientType ?? \"sdk\",\n language: so?.language ?? \"fr\",\n mode: so?.mode ?? \"smart_s\",\n debug_chunks: so?.debugChunks ?? false,\n sdk_version: SDK_VERSION,\n protocol_version: String(PROTOCOL_VERSION),\n };\n if (startOptions?.initialTargetId) {\n body.initial_target_id = startOptions.initialTargetId;\n }\n\n const response = await fetch(`${apiUrl}${AUDIO_SESSIONS_PATH}`, {\n method: \"POST\",\n headers,\n body: JSON.stringify(body),\n signal,\n });\n\n const rawText = await response.text();\n if (!response.ok) {\n let message = `Failed to create session: ${response.statusText}`;\n try {\n const errBody = JSON.parse(rawText) as {\n detail?:\n | string\n | { message?: string; hint?: string }\n | Array<{\n loc?: Array<string | number>;\n msg?: string;\n type?: string;\n }>;\n };\n const detail = errBody.detail;\n if (typeof detail === \"string\") {\n message = detail;\n } else if (Array.isArray(detail)) {\n message = detail\n .map((item) => {\n const loc = item.loc?.join(\".\") ?? \"body\";\n return `${loc}: ${item.msg ?? item.type ?? \"validation error\"}`;\n })\n .join(\" — \");\n } else if (detail && typeof detail === \"object\") {\n const parts = [detail.message, detail.hint].filter(Boolean);\n if (parts.length > 0) message = parts.join(\" — \");\n }\n } catch {\n if (rawText) message = rawText;\n }\n throw new EphiaSdkError(\"session.create_failed\", message, {\n status: response.status,\n });\n }\n\n const parsed = createSessionResponseSchema.safeParse(JSON.parse(rawText) as unknown);\n if (!parsed.success) {\n throw new EphiaSdkError(\n \"session.create_failed\",\n \"Invalid session response from backend\",\n { issues: parsed.error.issues }\n );\n }\n\n return {\n sessionId: parsed.data.session_id,\n roomName: parsed.data.room_name,\n token: parsed.data.token,\n livekitUrl: parsed.data.livekit_url,\n };\n }\n\n async stopBackendSession(sessionId: string): Promise<void> {\n try {\n const apiUrl = resolveEphiaSdkApiUrl(this.opts.apiUrl);\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n ...this.authHeaders(),\n };\n await fetch(`${apiUrl}${AUDIO_SESSIONS_PATH}/${encodeURIComponent(sessionId)}/stop`, {\n method: \"POST\",\n headers,\n });\n console.info(\"[EphiaAudioClient] stopBackendSession:done\", sessionId);\n } catch (err) {\n console.warn(\"[EphiaAudioClient] stopBackendSession:failed\", sessionId, err);\n }\n }\n\n /** Best-effort stop on tab close (fetch keepalive supports auth headers). */\n stopBackendSessionOnPageHide(sessionId: string): void {\n if (typeof window === \"undefined\" || !sessionId) return;\n try {\n const apiUrl = resolveEphiaSdkApiUrl(this.opts.apiUrl);\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n ...this.authHeaders(),\n };\n void fetch(`${apiUrl}${AUDIO_SESSIONS_PATH}/${encodeURIComponent(sessionId)}/stop`, {\n method: \"POST\",\n headers,\n keepalive: true,\n });\n } catch {\n /* ignore */\n }\n }\n\n private authHeaders(): Record<string, string> {\n const headers: Record<string, string> = {};\n if (this.opts.apiKey) {\n headers[\"X-API-Key\"] = this.opts.apiKey;\n } else if (this.opts.bearerToken) {\n headers[\"Authorization\"] = `Bearer ${this.opts.bearerToken}`;\n }\n if (this.opts.clientType) {\n headers[\"X-Ephia-Client\"] = this.opts.clientType;\n headers[\"X-Ephia-App\"] = this.opts.clientType;\n }\n return headers;\n }\n}\n","/**\n * AudioCaptureManager — micro, MediaStream, niveaux audio, buffers de capture.\n *\n * Rôle : getUserMedia, warmup, VoiceLevelMeter, startup/reconnect capture.\n * Possède : streams actif/warmup, meter, silence tracking.\n * Ne fait pas : publish transport, routing events.\n */\n\nimport { Room } from \"livekit-client\";\nimport { VoiceLevelMeter } from \"../audio/voice-level-meter\";\nimport { EphiaSdkError } from \"../../shared/errors/EphiaSdkError\";\nimport {\n initialAudioState,\n type EphiaAudioState,\n} from \"../../shared/state/audio-state\";\n\nexport type AudioCaptureDeps = {\n onAudioState: (state: EphiaAudioState) => void;\n getLocalAudioPublished: () => boolean;\n};\n\nexport class AudioCaptureManager {\n readonly voiceLevelMeter = new VoiceLevelMeter();\n private _activeStream: MediaStream | null = null;\n private _warmupStream: MediaStream | null = null;\n private _warmupPromise: Promise<void> | null = null;\n private _levelUnsubscribe?: () => void;\n private _silenceStartMs: number | null = null;\n private _lastAudioState: EphiaAudioState = { ...initialAudioState };\n private readonly deps: AudioCaptureDeps;\n\n constructor(deps: AudioCaptureDeps) {\n this.deps = deps;\n }\n\n get lastAudioState(): EphiaAudioState {\n return this._lastAudioState;\n }\n\n get silenceStartMs(): number | null {\n return this._silenceStartMs;\n }\n\n get hasActiveStream(): boolean {\n return !!this._activeStream;\n }\n\n get hasWarmupStream(): boolean {\n return !!this._warmupStream;\n }\n\n setActiveStream(stream: MediaStream | null): void {\n this._activeStream = stream;\n }\n\n emitAudioState(state: EphiaAudioState): void {\n this._lastAudioState = { ...state };\n this.deps.onAudioState(this._lastAudioState);\n }\n\n patchAudioState(patch: Partial<EphiaAudioState>): void {\n this.emitAudioState({ ...this._lastAudioState, ...patch });\n }\n\n stopAudioLevelImmediately(): void {\n this._levelUnsubscribe?.();\n this._levelUnsubscribe = undefined;\n this.voiceLevelMeter.detach();\n this.patchAudioState({\n level: 0,\n rms: 0,\n peak: 0,\n isSilent: true,\n silenceDurationMs: 0,\n localAudioPublished: false,\n muted: false,\n });\n }\n\n async warmupMic(): Promise<void> {\n if (/^((?!chrome|android).)*safari/i.test(navigator.userAgent)) return;\n if (\n this._warmupStream &&\n this._warmupStream.getAudioTracks().some((t) => t.readyState === \"live\")\n ) {\n console.info(\"[EphiaAudioClient] warmupMic: already warmed up\");\n return;\n }\n if (this._warmupPromise) {\n return this._warmupPromise;\n }\n\n this._warmupPromise = this.acquireMicStream()\n .then(async (stream) => {\n this._warmupStream = stream;\n await this.voiceLevelMeter.attach(stream);\n console.info(\"[EphiaAudioClient] warmupMic:done\", {\n trackCount: stream.getAudioTracks().length,\n });\n })\n .catch((err) => {\n console.warn(\"[EphiaAudioClient] warmupMic:failed\", err);\n })\n .finally(() => {\n this._warmupPromise = null;\n });\n\n return this._warmupPromise;\n }\n\n injectWarmupStream(stream: MediaStream): void {\n this.cleanupWarmupStream();\n this._warmupStream = stream;\n this.voiceLevelMeter.attach(stream).catch(() => {});\n }\n\n enableStartupCapture(maxSamples: number): void {\n this.voiceLevelMeter.enableStartupCapture(maxSamples);\n }\n\n drainStartupCapture(): ArrayBuffer | null {\n return this.voiceLevelMeter.drainStartupCapture();\n }\n\n async acquireMicStream(deviceId?: string): Promise<MediaStream> {\n if (\n this._warmupStream &&\n this._warmupStream.getAudioTracks().some((t) => t.readyState === \"live\")\n ) {\n const warmupTracks = this._warmupStream.getAudioTracks();\n const warmupDeviceId = warmupTracks[0]?.getSettings().deviceId;\n // N'utilise le warmup que s'il correspond au deviceId demandé.\n if (!deviceId || warmupDeviceId === deviceId) {\n console.info(\"[EphiaAudioClient] getUserMedia: using warmed-up stream\", {\n warmupDeviceId,\n });\n const stream = this._warmupStream;\n this._warmupStream = null;\n return stream;\n }\n console.info(\"[EphiaAudioClient] getUserMedia: warmup device mismatch, releasing warmup\", {\n warmupDeviceId,\n requestedDeviceId: deviceId,\n });\n this.cleanupWarmupStream();\n }\n if (typeof navigator === \"undefined\" || !navigator.mediaDevices?.getUserMedia) {\n const isSecure = typeof window !== \"undefined\" && window.isSecureContext === false;\n throw new EphiaSdkError(\n \"audio.no_input_device\",\n isSecure\n ? \"getUserMedia not available in non-secure context (requires HTTPS or localhost)\"\n : \"getUserMedia not available in this browser/context\"\n );\n }\n console.info(\"[EphiaAudioClient] getUserMedia:start\", deviceId ? { deviceId } : undefined);\n const audioConstraints: MediaTrackConstraints = {\n echoCancellation: { ideal: false },\n noiseSuppression: { ideal: false },\n autoGainControl: { ideal: false },\n channelCount: { ideal: 1 },\n sampleRate: { ideal: 16000 },\n };\n if (deviceId) {\n audioConstraints.deviceId = { exact: deviceId };\n }\n const stream = await navigator.mediaDevices.getUserMedia({ audio: audioConstraints });\n const tracks = stream.getAudioTracks();\n console.info(\"[EphiaAudioClient] getUserMedia:done\", {\n trackCount: tracks.length,\n tracks: tracks.map((t) => ({\n id: t.id,\n label: t.label,\n readyState: t.readyState,\n })),\n });\n return stream;\n }\n\n async setupAudioLevel(stream: MediaStream): Promise<void> {\n const track = stream.getAudioTracks()[0];\n if (!track) return;\n\n const trackSettings = track.getSettings();\n const deviceId = trackSettings.deviceId ?? \"\";\n const deviceLabel = track.label ?? \"\";\n\n this.emitAudioState({\n permission: \"granted\",\n hasInputDevice: true,\n inputDeviceId: deviceId,\n inputDeviceLabel: deviceLabel,\n level: 0,\n rms: 0,\n peak: 0,\n isSilent: false,\n silenceDurationMs: 0,\n muted: track.muted,\n localAudioPublished: false,\n micReady: true,\n speaking: false,\n });\n\n this._levelUnsubscribe?.();\n if (!this.voiceLevelMeter.isAttached()) {\n try {\n await this.voiceLevelMeter.attach(stream);\n } catch (err) {\n console.warn(\n \"[EphiaAudioClient] _setupAudioLevel: voiceLevelMeter attach failed (non-fatal)\",\n err\n );\n }\n }\n this._levelUnsubscribe = this.voiceLevelMeter.onLevel((snapshot) => {\n const isSilent = snapshot.level < 0.005;\n if (isSilent && this._silenceStartMs === null) {\n this._silenceStartMs = Date.now();\n } else if (!isSilent) {\n this._silenceStartMs = null;\n }\n const silenceDurationMs =\n isSilent && this._silenceStartMs !== null ? Date.now() - this._silenceStartMs : 0;\n this.patchAudioState({\n permission: \"granted\",\n hasInputDevice: true,\n inputDeviceId: deviceId,\n inputDeviceLabel: deviceLabel,\n level: snapshot.level,\n rms: snapshot.rms,\n peak: snapshot.rms,\n isSilent,\n silenceDurationMs,\n muted: track.muted,\n localAudioPublished: this.deps.getLocalAudioPublished(),\n micReady: true,\n });\n });\n }\n\n cleanupActiveStream(): void {\n this._levelUnsubscribe?.();\n this._levelUnsubscribe = undefined;\n this._silenceStartMs = null;\n this.voiceLevelMeter.detach();\n if (this._activeStream) {\n this._activeStream.getTracks().forEach((t) => t.stop());\n this._activeStream = null;\n }\n }\n\n cleanupWarmupStream(): void {\n if (this._warmupStream) {\n this._warmupStream.getTracks().forEach((t) => t.stop());\n this._warmupStream = null;\n }\n this._warmupPromise = null;\n }\n\n async getAvailableMicrophones(): Promise<MediaDeviceInfo[]> {\n return Room.getLocalDevices(\"audioinput\");\n }\n}\n","/**\n * Source AudioWorklet partagée pour la capture audio.\n *\n * Utilisée par VoiceLevelMeter et StartupAudioBuffer.\n * Évite la duplication du blob URL et du processor name.\n */\n\nconst AUDIO_WORKLET_SOURCE = `\nclass AudioCaptureProcessor extends AudioWorkletProcessor {\n process(inputs) {\n const input = inputs[0];\n if (input.length > 0) {\n this.port.postMessage(new Float32Array(input[0]));\n }\n return true;\n }\n}\nregisterProcessor('ephia-audio-capture', AudioCaptureProcessor);\n`;\n\nlet sharedWorkletModuleUrl: string | null = null;\n\nexport function getAudioWorkletModuleUrl(): string {\n if (!sharedWorkletModuleUrl) {\n sharedWorkletModuleUrl = URL.createObjectURL(\n new Blob([AUDIO_WORKLET_SOURCE], { type: \"application/javascript\" })\n );\n }\n return sharedWorkletModuleUrl;\n}\n","/**\n * Niveau vocal minimal pour la barre Standard (RMS brut + enveloppe attack/release).\n */\n\nexport type VoiceLevelSnapshot = {\n level: number;\n rms: number;\n};\n\nimport { getAudioWorkletModuleUrl } from \"./audio-worklet-source\";\n\nconst VOLUME_THROTTLE_MS = 33;\nconst SILENCE_THRESHOLD_RMS = 0.005;\nconst RAW_RMS_SCALE = 7;\nconst TARGET_SAMPLE_RATE = 16_000;\n\nfunction clamp01(value: number): number {\n return Math.max(0, Math.min(1, value));\n}\n\nfunction isAudioContextClosed(audioContext: AudioContext): boolean {\n return (audioContext.state as AudioContextState) === \"closed\";\n}\n\nfunction resampleLinear(\n input: Float32Array,\n sourceSampleRate: number,\n targetSampleRate: number\n): Float32Array {\n if (sourceSampleRate === targetSampleRate || input.length <= 1) {\n return input;\n }\n\n const outputLength = Math.max(\n 1,\n Math.round((input.length * targetSampleRate) / sourceSampleRate)\n );\n const output = new Float32Array(outputLength);\n const scale = sourceSampleRate / targetSampleRate;\n\n for (let i = 0; i < outputLength; i += 1) {\n const sourceIndex = i * scale;\n const leftIndex = Math.floor(sourceIndex);\n const rightIndex = Math.min(leftIndex + 1, input.length - 1);\n const fraction = sourceIndex - leftIndex;\n const left = input[leftIndex] ?? 0;\n const right = input[rightIndex] ?? left;\n output[i] = left + (right - left) * fraction;\n }\n\n return output;\n}\n\nexport class VoiceLevelMeter {\n private audioContext: AudioContext | null = null;\n private processor: AudioWorkletNode | null = null;\n private silentGain: GainNode | null = null;\n private source: MediaStreamAudioSourceNode | null = null;\n private callbacks = new Set<(snapshot: VoiceLevelSnapshot) => void>();\n private pendingRms = 0;\n private lastVolumeUpdateMs = 0;\n private volumeTimer: ReturnType<typeof setTimeout> | null = null;\n private _pipelineReady: Promise<void> | null = null;\n // Startup capture state (shared pipeline avec StartupAudioBuffer)\n private _captureBuffers: Float32Array[] = [];\n private _captureTotalSamples = 0;\n private _captureMaxSamples = 0;\n private _captureEnabled = false;\n private _actualSampleRate = TARGET_SAMPLE_RATE;\n\n attach(stream: MediaStream): Promise<void> {\n this.detach();\n\n const AudioContextClass =\n window.AudioContext ||\n (window as Window & { webkitAudioContext?: typeof AudioContext }).webkitAudioContext;\n if (!AudioContextClass) {\n console.warn(\"[VoiceLevelMeter] AudioContext not supported\");\n return Promise.resolve();\n }\n\n this._pipelineReady = this._startWorkletPipeline(stream, AudioContextClass);\n return this._pipelineReady;\n }\n\n isAttached(): boolean {\n return this.processor !== null;\n }\n\n private async _startWorkletPipeline(\n stream: MediaStream,\n AudioContextClass: typeof AudioContext,\n ): Promise<void> {\n try {\n const audioContext = new AudioContextClass({\n sampleRate: TARGET_SAMPLE_RATE,\n latencyHint: \"interactive\",\n });\n this.audioContext = audioContext;\n this._actualSampleRate = audioContext.sampleRate || TARGET_SAMPLE_RATE;\n\n if (audioContext.state === \"suspended\") {\n await audioContext.resume();\n }\n // Guard: detach() a été appelé entre-temps (ex: dispose pendant navigation)\n if (this.audioContext !== audioContext || isAudioContextClosed(audioContext)) {\n return;\n }\n\n await audioContext.audioWorklet.addModule(getAudioWorkletModuleUrl());\n // Guard: même vérification après le module load async\n if (this.audioContext !== audioContext || isAudioContextClosed(audioContext)) {\n return;\n }\n\n const source = audioContext.createMediaStreamSource(stream);\n const processor = new AudioWorkletNode(audioContext, \"ephia-audio-capture\");\n const silentGain = audioContext.createGain();\n silentGain.gain.value = 0;\n\n processor.connect(silentGain);\n silentGain.connect(audioContext.destination);\n\n processor.port.onmessage = (event: MessageEvent<Float32Array>) => {\n const inputData = event.data;\n if (!inputData?.length) return;\n\n // Startup capture — accumulation FIFO partagée avec le pipeline level\n if (this._captureEnabled) {\n const chunk = new Float32Array(inputData);\n this._captureBuffers.push(chunk);\n this._captureTotalSamples += chunk.length;\n while (this._captureTotalSamples > this._captureMaxSamples && this._captureBuffers.length > 0) {\n const removed = this._captureBuffers.shift()!;\n this._captureTotalSamples -= removed.length;\n }\n }\n\n let sum = 0;\n for (let i = 0; i < inputData.length; i++) {\n const x = inputData[i];\n sum += x * x;\n }\n const rawRms = Math.sqrt(sum / inputData.length);\n this.pendingRms = clamp01(rawRms * RAW_RMS_SCALE);\n\n const now = Date.now();\n if (\n this.volumeTimer === null &&\n now - this.lastVolumeUpdateMs > VOLUME_THROTTLE_MS\n ) {\n this.volumeTimer = setTimeout(() => {\n this.volumeTimer = null;\n this.lastVolumeUpdateMs = Date.now();\n this._emitSnapshot();\n }, VOLUME_THROTTLE_MS);\n }\n };\n\n this.source = source;\n this.processor = processor;\n this.silentGain = silentGain;\n source.connect(processor);\n } catch (err) {\n console.warn(\"[VoiceLevelMeter] worklet pipeline failed\", err);\n this.detach();\n }\n }\n\n private _emitSnapshot(): void {\n const rms = this.pendingRms;\n const snapshot: VoiceLevelSnapshot = {\n level: clamp01(rms),\n rms,\n };\n const isSilent = rms < SILENCE_THRESHOLD_RMS;\n if (isSilent) {\n snapshot.level = 0;\n snapshot.rms = 0;\n }\n this.callbacks.forEach((cb) => cb(snapshot));\n }\n\n detach(): void {\n if (this.volumeTimer !== null) {\n clearTimeout(this.volumeTimer);\n this.volumeTimer = null;\n }\n this.pendingRms = 0;\n this.lastVolumeUpdateMs = 0;\n\n if (this.source) {\n try {\n this.source.disconnect();\n } catch {\n /* ignore */\n }\n this.source = null;\n }\n if (this.processor) {\n try {\n this.processor.port.onmessage = null;\n this.processor.disconnect();\n } catch {\n /* ignore */\n }\n this.processor = null;\n }\n if (this.silentGain) {\n try {\n this.silentGain.disconnect();\n } catch {\n /* ignore */\n }\n this.silentGain = null;\n }\n if (this.audioContext) {\n this.audioContext.close().catch(() => {});\n this.audioContext = null;\n }\n }\n\n onLevel(callback: (snapshot: VoiceLevelSnapshot) => void): () => void {\n this.callbacks.add(callback);\n return () => {\n this.callbacks.delete(callback);\n };\n }\n\n /** Active la capture startup sur le pipeline existant. maxSamples = taille FIFO. */\n enableStartupCapture(maxSamples: number): void {\n this._captureBuffers = [];\n this._captureTotalSamples = 0;\n this._captureMaxSamples = Math.ceil(\n (maxSamples * this._actualSampleRate) / TARGET_SAMPLE_RATE\n );\n this._captureEnabled = true;\n }\n\n /** Stoppe la capture et retourne le PCM16 accumulé (ou null si vide). Le level meter continue. */\n drainStartupCapture(): ArrayBuffer | null {\n this._captureEnabled = false;\n const buffers = this._captureBuffers;\n const totalSamples = this._captureTotalSamples;\n this._captureBuffers = [];\n this._captureTotalSamples = 0;\n\n if (buffers.length === 0) return null;\n\n const float32 = new Float32Array(totalSamples);\n let offset = 0;\n for (const buf of buffers) {\n float32.set(buf, offset);\n offset += buf.length;\n }\n\n const resampled = resampleLinear(\n float32,\n this._actualSampleRate,\n TARGET_SAMPLE_RATE\n );\n\n const pcm16 = new Int16Array(resampled.length);\n for (let i = 0; i < resampled.length; i++) {\n const s = Math.max(-1, Math.min(1, resampled[i] ?? 0));\n pcm16[i] = s < 0 ? s * 0x8000 : s * 0x7fff;\n }\n return pcm16.buffer;\n }\n}\n","/**\n * EphiaAudioClient — façade publique vers le nouvel agent ephia-transcribe-agent.\n *\n * Architecture simplifiée : SessionApiClient + AudioCaptureManager + Transport direct.\n * Pas d'EventGate / CatchupCoordinator / SessionSyncService / ReconnectionManager.\n */\n\nimport type { EphiaClientMessage, EphiaServerEvent } from \"ephia-protocol\";\nimport type { Transport, TransportState } from \"../transport/Transport\";\nimport { LiveKitTransport } from \"../transport/LiveKitTransport\";\nimport type { EphiaClientState } from \"./client-state\";\nimport { initialClientState } from \"./client-state\";\nimport { canTransition, transitionSessionStatus } from \"../session/session-machine\";\nimport type { EphiaSessionStatus } from \"../session/session-machine\";\nimport { EphiaSdkError } from \"../../shared/errors/EphiaSdkError\";\nimport { dbgState } from \"../../debug/sdk-debug-collector\";\nimport { SDK_VERSION, PROTOCOL_VERSION } from \"./constants\";\nimport type { EphiaAudioClientOptions, EphiaStartOptions, EphiaStartResult } from \"./client-options\";\nexport type { EphiaAudioClientOptions, EphiaStartOptions, EphiaStartResult } from \"./client-options\";\nexport { SDK_VERSION, PROTOCOL_VERSION } from \"./constants\";\nimport { SessionApiClient } from \"./session-api\";\nimport { AudioCaptureManager } from \"./audio-capture\";\n\nexport class EphiaAudioClient {\n private options: EphiaAudioClientOptions;\n private transport: Transport;\n private state: EphiaClientState = { ...initialClientState };\n private _unbindTransport?: () => void;\n\n private _stopping = false;\n private _intentionalDisconnect = false;\n private _startAbortController: AbortController | null = null;\n private _lastConnectParams: { livekitUrl: string; token: string; roomName: string; sessionId: string } | null = null;\n private _tokenRefreshTimer: ReturnType<typeof setTimeout> | null = null;\n private _serverSessionClosed = false;\n\n private readonly sessionApi: SessionApiClient;\n private readonly audio: AudioCaptureManager;\n\n constructor(options: EphiaAudioClientOptions = {}) {\n this.options = options;\n this.transport = options.transport ?? new LiveKitTransport();\n\n this.sessionApi = new SessionApiClient({\n apiUrl: options.apiUrl,\n apiKey: options.apiKey,\n bearerToken: options.bearerToken,\n clientType: options.clientType,\n sessionOptions: options.sessionOptions,\n isIdle: () => this.state.status === \"idle\",\n onPrepareConnection: (url, token) => {\n this.transport.prepareConnection?.(url, token).catch(() => {});\n },\n onPreloadComplete: () => {\n this._emitSdkDebug(\"sdk.preload.done\", { ts: Date.now() });\n },\n onPreloadFailed: () => {\n this._emitSdkDebug(\"sdk.preload.failed\", { ts: Date.now() });\n },\n });\n\n this.audio = new AudioCaptureManager({\n onAudioState: (s) => this.options.onAudioState?.(s),\n getLocalAudioPublished: () => this.state.isMicEnabled,\n });\n }\n\n // ── Public API ──────────────────────────────────────────────────────────────\n\n async preload(signal?: AbortSignal): Promise<void>;\n async preload(options?: EphiaStartOptions, signal?: AbortSignal): Promise<void>;\n async preload(\n optionsOrSignal?: EphiaStartOptions | AbortSignal,\n maybeSignal?: AbortSignal\n ): Promise<void> {\n if (this.state.status !== \"idle\") return;\n if (optionsOrSignal && \"aborted\" in optionsOrSignal) {\n return this.sessionApi.preload(optionsOrSignal);\n }\n return this.sessionApi.preload(optionsOrSignal, maybeSignal);\n }\n\n releasePreloadedSession(): void {\n this.sessionApi.cancelTimers();\n const orphaned = this.sessionApi.discardPreloadedSession();\n if (orphaned) {\n this.sessionApi.stopBackendSession(orphaned.sessionId).catch(() => {});\n }\n }\n\n async warmupMic(): Promise<void> {\n return this.audio.warmupMic();\n }\n\n injectWarmupStream(stream: MediaStream): void {\n this.audio.injectWarmupStream(stream);\n }\n\n async start(options?: EphiaStartOptions): Promise<EphiaStartResult> {\n if (this.state.status === \"ended\" || this.state.status === \"error\") {\n this._resetForStart();\n }\n\n // Resume from paused (room still connected, just republish audio)\n if (this.state.status === \"paused\" && this._hasReusableRoom()) {\n await this._resumeAudio(options);\n return { sessionId: this.state.sessionId };\n }\n\n if (!canTransition(this.state.status, \"creating_session\")) {\n throw new EphiaSdkError(\n \"client.invalid_state\",\n `Cannot start while status is ${this.state.status}`\n );\n }\n\n this._setStatus(\"creating_session\");\n this._startAbortController = new AbortController();\n const { signal } = this._startAbortController;\n\n let acquiredStream: MediaStream | undefined;\n let sessionData: Awaited<ReturnType<SessionApiClient[\"createSession\"]>> | undefined;\n\n try {\n // Acquire mic + session in parallel\n const micPromise = this.audio\n .acquireMicStream(this.options.preferredAudioInputDeviceId)\n .then((stream) => {\n if (!signal.aborted) {\n acquiredStream = stream;\n this.audio.setActiveStream(stream);\n } else {\n stream.getTracks().forEach((t) => t.stop());\n }\n });\n\n let sessionPromise: Promise<void>;\n const preloaded = this.sessionApi.takePreloadedSession();\n if (preloaded) {\n sessionData = preloaded;\n this.state = { ...this.state, sessionId: preloaded.sessionId, roomName: preloaded.roomName };\n this.options.onStateChange?.(this.getState());\n sessionPromise = Promise.resolve();\n } else {\n if (this.sessionApi.hasPreloadInFlight()) {\n await this.sessionApi.awaitPreloadIfPending(signal);\n const fromFlight = this.sessionApi.takePreloadedSession();\n if (fromFlight) {\n sessionData = fromFlight;\n this.state = { ...this.state, sessionId: fromFlight.sessionId, roomName: fromFlight.roomName };\n this.options.onStateChange?.(this.getState());\n sessionPromise = Promise.resolve();\n } else {\n sessionPromise = this.sessionApi.createSessionWithRetry(signal, options).then((data) => {\n if (!signal.aborted) {\n sessionData = data;\n this.state = { ...this.state, sessionId: data.sessionId, roomName: data.roomName };\n this.options.onStateChange?.(this.getState());\n }\n });\n }\n } else {\n sessionPromise = this.sessionApi.createSessionWithRetry(signal, options).then((data) => {\n if (!signal.aborted) {\n sessionData = data;\n this.state = { ...this.state, sessionId: data.sessionId, roomName: data.roomName };\n this.options.onStateChange?.(this.getState());\n }\n });\n }\n }\n\n await Promise.all([micPromise, sessionPromise]);\n\n if (signal.aborted) {\n this._handleStartAborted();\n return { sessionId: null };\n }\n if (!acquiredStream || !sessionData) {\n throw new EphiaSdkError(\"client.start_failed\", \"Missing stream or session\");\n }\n\n // Connect transport\n this._setStatus(\"connecting_transport\");\n this._unbindTransport?.();\n this._unbindTransport = this._bindTransportEvents();\n\n const connectParams = {\n livekitUrl: sessionData.livekitUrl,\n token: sessionData.token,\n roomName: sessionData.roomName,\n sessionId: sessionData.sessionId,\n };\n this._lastConnectParams = connectParams;\n this._scheduleTokenRefresh(sessionData.sessionId);\n await this._connectTransportWithRetry(connectParams, signal);\n await this._sendInitialTargetBeforeAudio(options?.initialTargetId, signal);\n\n if (signal.aborted) {\n await this._disconnectTransport().catch(() => {});\n this._handleStartAborted();\n return { sessionId: null };\n }\n\n // Publish audio\n this._setStatus(\"ready\");\n const track = acquiredStream.getAudioTracks()[0];\n if (!track) {\n throw new EphiaSdkError(\"audio.no_input_device\", \"No audio track\");\n }\n if (!track.enabled) track.enabled = true;\n\n try {\n await this.transport.publishAudio(track, { enableNoiseFilter: this.options.noiseFilter });\n } catch (err) {\n if (err instanceof EphiaSdkError) throw err;\n const message = err instanceof Error ? err.message : String(err);\n throw new EphiaSdkError(\"audio.track_publish_failed\", message);\n }\n\n if (signal.aborted) {\n await this.transport.unpublishAudio().catch(() => {});\n await this._disconnectTransport().catch(() => {});\n this._handleStartAborted();\n return { sessionId: null };\n }\n\n this._setStatus(\"recording\");\n this.state = { ...this.state, isMicEnabled: true };\n this.options.onStateChange?.(this.getState());\n await this.audio.setupAudioLevel(acquiredStream);\n\n this._emitSdkDebug(\"sdk.record.started\", { sessionId: sessionData.sessionId, ts: Date.now() });\n\n return { sessionId: sessionData.sessionId };\n } catch (err) {\n if (signal.aborted) {\n await this._disconnectTransport().catch(() => {});\n this._handleStartAborted();\n return { sessionId: null };\n }\n const code = err instanceof EphiaSdkError ? err.code : \"client.start_failed\";\n const message = err instanceof Error ? err.message : String(err);\n this._setErrorState(code, message);\n this.audio.cleanupActiveStream();\n await this._disconnectTransport().catch(() => {});\n throw err;\n } finally {\n if (this._startAbortController?.signal === signal) {\n this._startAbortController = null;\n }\n }\n }\n\n /** Arrête l'enregistrement sans fermer la room (reprise possible via start()). */\n async stop(): Promise<void> {\n if (this._stopping) return;\n this.audio.stopAudioLevelImmediately?.();\n\n if (this._startAbortController) {\n this._stopping = true;\n this._startAbortController.abort();\n this._startAbortController = null;\n this._handleStartAborted();\n this._stopping = false;\n return;\n }\n\n if (\n this.state.status === \"idle\" ||\n this.state.status === \"paused\" ||\n this.state.status === \"ended\" ||\n this.state.status === \"error\" ||\n this.state.status === \"disposed\"\n ) {\n return;\n }\n\n if (\n this.state.status === \"creating_session\" ||\n this.state.status === \"connecting_transport\"\n ) {\n this._stopping = true;\n await this._disconnectTransport().catch(() => {});\n this._handleStartAborted();\n this._stopping = false;\n return;\n }\n\n this._stopping = true;\n try {\n await this.transport.unpublishAudio().catch(() => {});\n this.audio.cleanupActiveStream();\n this.state = { ...this.state, isMicEnabled: false };\n this._setStatus(\"paused\");\n this.options.onStateChange?.(this.getState());\n } finally {\n this._stopping = false;\n }\n }\n\n /** Termine complètement la session : déconnecte la room et stop le backend. */\n async endSession(): Promise<void> {\n if (this._stopping) return;\n this.audio.stopAudioLevelImmediately?.();\n\n if (this._startAbortController) {\n this._stopping = true;\n this._startAbortController.abort();\n this._startAbortController = null;\n this._handleStartAborted();\n this._stopping = false;\n return;\n }\n\n if (\n this.state.status === \"idle\" ||\n this.state.status === \"ended\" ||\n this.state.status === \"disposed\"\n ) {\n return;\n }\n\n this._stopping = true;\n const sessionId = this.state.sessionId;\n try {\n await this.transport.unpublishAudio().catch(() => {});\n this.audio.cleanupActiveStream();\n this._intentionalDisconnect = true;\n await this._disconnectTransport().catch(() => {});\n if (sessionId) {\n this.sessionApi.stopBackendSession(sessionId).catch(() => {});\n }\n this._markSessionEnded();\n } finally {\n this._intentionalDisconnect = false;\n this._stopping = false;\n }\n }\n\n registerPageHideStop(): () => void {\n if (typeof window === \"undefined\") return () => {};\n const handler = () => {\n const sessionId = this.state.sessionId;\n if (sessionId) this.sessionApi.stopBackendSessionOnPageHide(sessionId);\n };\n window.addEventListener(\"pagehide\", handler);\n return () => window.removeEventListener(\"pagehide\", handler);\n }\n\n async dispose(): Promise<void> {\n if (this._startAbortController) {\n this._startAbortController.abort();\n this._startAbortController = null;\n this._handleStartAborted();\n return;\n }\n const status = this.state.status;\n if (status === \"recording\" || status === \"ready\") {\n await this.endSession();\n return;\n }\n this.sessionApi.cancelTimers();\n const orphaned = this.sessionApi.discardPreloadedSession();\n if (orphaned) this.sessionApi.stopBackendSession(orphaned.sessionId).catch(() => {});\n this._intentionalDisconnect = true;\n await this._disconnectTransport().catch(() => {});\n this._intentionalDisconnect = false;\n this._unbindTransport?.();\n this._unbindTransport = undefined;\n this.audio.cleanupActiveStream();\n this.audio.cleanupWarmupStream?.();\n this.state = { ...this.state, status: \"disposed\" };\n this.options.onStateChange?.(this.getState());\n }\n\n getState(): EphiaClientState {\n return { ...this.state };\n }\n\n setPreferredAudioInputDeviceId(deviceId: string | undefined): void {\n this.options = { ...this.options, preferredAudioInputDeviceId: deviceId };\n }\n\n onTransportState(callback: (state: TransportState) => void): () => void {\n return this.transport.onTransportState(callback);\n }\n\n onServerEvent(callback: (event: EphiaServerEvent) => void): () => void {\n return this.transport.onServerEvent(callback);\n }\n\n async sendMessage(message: EphiaClientMessage): Promise<void> {\n await this.transport.sendMessage(message);\n }\n\n async getAvailableMicrophones(): Promise<MediaDeviceInfo[]> {\n return this.audio.getAvailableMicrophones();\n }\n\n async switchMicrophone(deviceId: string): Promise<void> {\n await this.transport.switchActiveDevice?.(\"audioinput\", deviceId);\n }\n\n exportTrace(): Record<string, unknown> {\n return {\n sdkVersion: SDK_VERSION,\n protocolVersion: PROTOCOL_VERSION,\n sessionId: this.state.sessionId,\n state: this.state,\n };\n }\n\n getDebugSnapshot(): Record<string, unknown> {\n return {\n sdkVersion: SDK_VERSION,\n protocolVersion: PROTOCOL_VERSION,\n state: this.state,\n lastAudioState: this.audio.lastAudioState,\n stopping: this._stopping,\n intentionalDisconnect: this._intentionalDisconnect,\n preloadedSession: this.sessionApi.preloadedSession,\n lastConnectParams: this._lastConnectParams\n ? { ...this._lastConnectParams, token: \"[redacted]\" }\n : null,\n hasActiveStream: this.audio.hasActiveStream,\n };\n }\n\n // ── Internals ────────────────────────────────────────────────────────────────\n\n private _bindTransportEvents(): () => void {\n const unsubServerEvent = this.transport.onServerEvent((event) => {\n if (event.type === \"session.error\") {\n this._setErrorState(event.payload.code, event.payload.message);\n this._serverSessionClosed = true;\n }\n if (event.type === \"session.status\") {\n if (event.payload.status === \"closed\") {\n this._serverSessionClosed = true;\n } else if (event.payload.status === \"ready\") {\n this._serverSessionClosed = false;\n }\n }\n });\n\n const unsubState = this.transport.onTransportState((tState) => {\n if (tState.status === \"disconnected\" && !this._intentionalDisconnect && !this._stopping) {\n // LiveKit exhausted its reconnect retries\n this._setErrorState(\"transport.disconnected\", \"Connexion perdue\");\n }\n });\n\n const unsubError = this.transport.onError((err) => {\n this._setErrorState(err.code, err.message);\n });\n\n return () => {\n unsubServerEvent();\n unsubState();\n unsubError();\n };\n }\n\n private async _resumeAudio(options?: EphiaStartOptions): Promise<void> {\n if (this.state.isMicEnabled) return;\n try {\n const stream = await this.audio.acquireMicStream(this.options.preferredAudioInputDeviceId);\n if (!stream) throw new EphiaSdkError(\"audio.no_input_device\", \"No mic stream\");\n this.audio.setActiveStream(stream);\n const track = stream.getAudioTracks()[0];\n if (!track) throw new EphiaSdkError(\"audio.no_input_device\", \"No audio track\");\n await this._sendInitialTargetBeforeAudio(options?.initialTargetId);\n try {\n await this.transport.publishAudio(track, { enableNoiseFilter: this.options.noiseFilter });\n } catch (err) {\n if (err instanceof EphiaSdkError) throw err;\n const message = err instanceof Error ? err.message : String(err);\n throw new EphiaSdkError(\"audio.track_publish_failed\", message);\n }\n await this.transport.sendMessage({\n type: \"session.resume\",\n payload: {\n context: options?.context,\n },\n });\n this._setStatus(\"recording\");\n this.state = { ...this.state, isMicEnabled: true };\n this.options.onStateChange?.(this.getState());\n await this.audio.setupAudioLevel(stream);\n } catch (err) {\n const code = err instanceof EphiaSdkError ? err.code : \"client.start_failed\";\n const message = err instanceof Error ? err.message : String(err);\n this._setErrorState(code, message);\n this.audio.cleanupActiveStream();\n throw err;\n }\n }\n\n private _hasReusableRoom(): boolean {\n const status = this.transport.getState().status;\n return (\n !!this.state.sessionId &&\n (status === \"connected\" || status === \"reconnected\")\n );\n }\n\n private _handleStartAborted(): void {\n this.audio.cleanupActiveStream();\n const orphaned = this.sessionApi.discardPreloadedSession();\n if (orphaned) this.sessionApi.stopBackendSession(orphaned.sessionId).catch(() => {});\n this._forceIdle();\n }\n\n private _forceIdle(): void {\n this.state = { ...this.state, status: \"idle\", isMicEnabled: false };\n this.options.onStateChange?.(this.getState());\n }\n\n private _resetForStart(): void {\n this._unbindTransport?.();\n this._unbindTransport = undefined;\n this.audio.cleanupActiveStream();\n const orphaned = this.sessionApi.discardPreloadedSession();\n if (orphaned) this.sessionApi.stopBackendSession(orphaned.sessionId).catch(() => {});\n this.sessionApi.cancelTimers();\n if (this._tokenRefreshTimer !== null) {\n clearTimeout(this._tokenRefreshTimer);\n this._tokenRefreshTimer = null;\n }\n this._lastConnectParams = null;\n this.state = {\n ...this.state,\n status: \"idle\",\n sessionId: null,\n roomName: null,\n error: null,\n isMicEnabled: false,\n };\n }\n\n private _markSessionEnded(): void {\n this._unbindTransport?.();\n this._unbindTransport = undefined;\n if (this._tokenRefreshTimer !== null) {\n clearTimeout(this._tokenRefreshTimer);\n this._tokenRefreshTimer = null;\n }\n this._lastConnectParams = null;\n if (\n this.state.status !== \"ended\" &&\n this.state.status !== \"error\" &&\n this.state.status !== \"disposed\"\n ) {\n this._setStatus(\"ended\");\n }\n this.state = { ...this.state, isMicEnabled: false };\n this.options.onStateChange?.(this.getState());\n }\n\n private _setStatus(next: EphiaSessionStatus): void {\n const current = this.state.status;\n if (current === next) return;\n const status = transitionSessionStatus(current, next);\n this.state = { ...this.state, status };\n dbgState(\"sdk.client\", this.getDebugSnapshot());\n this.options.onStateChange?.(this.getState());\n }\n\n private _setErrorState(code: string, message: string): void {\n const error = { code, message };\n const current = this.state.status;\n if (canTransition(current, \"error\")) {\n this._setStatus(\"error\");\n } else {\n this.state = { ...this.state, status: \"error\" };\n }\n this.state = { ...this.state, error, isMicEnabled: false };\n this.options.onStateChange?.(this.getState());\n this.options.onError?.(error);\n }\n\n private _scheduleTokenRefresh(sessionId: string): void {\n if (this._tokenRefreshTimer !== null) clearTimeout(this._tokenRefreshTimer);\n this._tokenRefreshTimer = setTimeout(() => {\n this._tokenRefreshTimer = null;\n if (!this._lastConnectParams) return;\n void this.sessionApi.refreshToken(sessionId).then((token) => {\n if (token && this._lastConnectParams) {\n this._lastConnectParams = { ...this._lastConnectParams, token };\n }\n });\n }, this.sessionApi.activeTokenRefreshDelayMs);\n }\n\n private async _connectTransportWithRetry(\n params: { livekitUrl: string; token: string; roomName: string; sessionId: string },\n signal?: AbortSignal\n ): Promise<void> {\n const maxRetries = 2;\n let lastErr: unknown;\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n if (signal?.aborted) throw new EphiaSdkError(\"client.start_failed\", \"Start aborted\");\n try {\n await this.transport.connect(params as any);\n return;\n } catch (err) {\n lastErr = err;\n if (err instanceof EphiaSdkError) throw err;\n if (signal?.aborted) throw err;\n if (attempt < maxRetries) {\n const delay = 300 * Math.pow(2, attempt) + Math.random() * 100;\n await new Promise<void>((resolve) => setTimeout(resolve, delay));\n }\n }\n }\n throw lastErr;\n }\n\n private async _sendInitialTargetBeforeAudio(\n targetId?: string,\n signal?: AbortSignal\n ): Promise<void> {\n if (!targetId) return;\n for (let attempt = 0; attempt < 3; attempt++) {\n if (signal?.aborted) throw new EphiaSdkError(\"client.start_failed\", \"Start aborted\");\n try {\n await this.transport.sendMessage({\n type: \"session.target.changed\",\n payload: { targetId },\n } as unknown as EphiaClientMessage);\n return;\n } catch (err) {\n if (attempt === 2) throw err;\n await new Promise<void>((resolve) => setTimeout(resolve, 50 * (attempt + 1)));\n }\n }\n }\n\n private async _disconnectTransport(): Promise<void> {\n this._unbindTransport?.();\n this._unbindTransport = undefined;\n await this.transport.disconnect();\n }\n\n private _emitSdkDebug(type: string, payload: Record<string, unknown>): void {\n if (typeof window === \"undefined\") return;\n window.dispatchEvent(\n new CustomEvent(\"ephia:sdk-debug\", {\n detail: { type, sessionId: this.state.sessionId ?? null, payload },\n })\n );\n }\n}\n"],"mappings":"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","names":["stream"]}
@@ -0,0 +1,18 @@
1
+ // src/shared/state/audio-state.ts
2
+ var initialAudioState = {
3
+ permission: "unknown",
4
+ hasInputDevice: false,
5
+ level: 0,
6
+ rms: 0,
7
+ peak: 0,
8
+ isSilent: false,
9
+ silenceDurationMs: 0,
10
+ muted: false,
11
+ localAudioPublished: false,
12
+ speaking: false
13
+ };
14
+
15
+ export {
16
+ initialAudioState
17
+ };
18
+ //# sourceMappingURL=chunk-EGIAN7FH.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/shared/state/audio-state.ts"],"sourcesContent":["/**\n * État audio local (micro, niveau, silence, permission).\n */\n\nexport type EphiaAudioPermission = \"unknown\" | \"prompt\" | \"granted\" | \"denied\";\n\nexport type EphiaAudioState = {\n permission: EphiaAudioPermission;\n\n inputDeviceId?: string;\n inputDeviceLabel?: string;\n hasInputDevice: boolean;\n\n level: number; // 0..1\n rms: number;\n peak: number;\n\n isSilent: boolean;\n silenceDurationMs: number;\n\n muted: boolean;\n localAudioPublished: boolean;\n /** true si le VADGate détecte de la parole active */\n speaking: boolean;\n /** True dès que getUserMedia a réussi, même si le transport n'est pas encore connecté. */\n micReady?: boolean;\n\n error?: {\n code: string;\n message: string;\n };\n};\n\nexport const initialAudioState: EphiaAudioState = {\n permission: \"unknown\",\n hasInputDevice: false,\n level: 0,\n rms: 0,\n peak: 0,\n isSilent: false,\n silenceDurationMs: 0,\n muted: false,\n localAudioPublished: false,\n speaking: false,\n};\n"],"mappings":";AAiCO,IAAM,oBAAqC;AAAA,EAChD,YAAY;AAAA,EACZ,gBAAgB;AAAA,EAChB,OAAO;AAAA,EACP,KAAK;AAAA,EACL,MAAM;AAAA,EACN,UAAU;AAAA,EACV,mBAAmB;AAAA,EACnB,OAAO;AAAA,EACP,qBAAqB;AAAA,EACrB,UAAU;AACZ;","names":[]}