@happyvertical/smrt-svelte 0.55.6 → 0.55.8

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 (318) hide show
  1. package/AGENTS.md +9 -31
  2. package/README.md +195 -5
  3. package/agents/browser-ai.md +47 -0
  4. package/agents/command-palette.md +85 -0
  5. package/agents/import-export.md +62 -0
  6. package/agents/overview-surfaces.md +255 -0
  7. package/agents/screens.md +57 -0
  8. package/agents/workspace.md +202 -5
  9. package/dist/browser-ai/adapters/stt/dictation-source.d.ts.map +1 -1
  10. package/dist/browser-ai/adapters/stt/dictation-source.js +8 -2
  11. package/dist/browser-ai/adapters/stt/factory.d.ts +6 -3
  12. package/dist/browser-ai/adapters/stt/factory.d.ts.map +1 -1
  13. package/dist/browser-ai/adapters/stt/factory.js +19 -9
  14. package/dist/browser-ai/adapters/stt/index.d.ts +3 -1
  15. package/dist/browser-ai/adapters/stt/index.d.ts.map +1 -1
  16. package/dist/browser-ai/adapters/stt/index.js +3 -1
  17. package/dist/browser-ai/adapters/stt/local-speech-model.d.ts +111 -0
  18. package/dist/browser-ai/adapters/stt/local-speech-model.d.ts.map +1 -0
  19. package/dist/browser-ai/adapters/stt/local-speech-model.js +377 -0
  20. package/dist/browser-ai/adapters/stt/local-speech.d.ts +82 -0
  21. package/dist/browser-ai/adapters/stt/local-speech.d.ts.map +1 -0
  22. package/dist/browser-ai/adapters/stt/local-speech.js +317 -0
  23. package/dist/browser-ai/adapters/stt/local-speech.worker.d.ts +2 -0
  24. package/dist/browser-ai/adapters/stt/local-speech.worker.d.ts.map +1 -0
  25. package/dist/browser-ai/adapters/stt/local-speech.worker.js +32 -0
  26. package/dist/browser-ai/adapters/stt/transformers-env.d.ts +8 -0
  27. package/dist/browser-ai/adapters/stt/transformers-env.d.ts.map +1 -0
  28. package/dist/browser-ai/adapters/stt/transformers-env.js +17 -0
  29. package/dist/browser-ai/adapters/stt/types.d.ts +54 -9
  30. package/dist/browser-ai/adapters/stt/types.d.ts.map +1 -1
  31. package/dist/browser-ai/adapters/tts/browser-synthesis.d.ts +5 -0
  32. package/dist/browser-ai/adapters/tts/browser-synthesis.d.ts.map +1 -1
  33. package/dist/browser-ai/adapters/tts/browser-synthesis.js +83 -55
  34. package/dist/browser-ai/capabilities/speech-probe.d.ts +29 -0
  35. package/dist/browser-ai/capabilities/speech-probe.d.ts.map +1 -0
  36. package/dist/browser-ai/capabilities/speech-probe.js +19 -0
  37. package/dist/browser-ai/core/errors.d.ts +9 -0
  38. package/dist/browser-ai/core/errors.d.ts.map +1 -1
  39. package/dist/browser-ai/core/errors.js +12 -0
  40. package/dist/browser-ai/index.d.ts +1 -0
  41. package/dist/browser-ai/index.d.ts.map +1 -1
  42. package/dist/browser-ai/index.js +1 -0
  43. package/dist/components/app/AppShell.svelte +587 -33
  44. package/dist/components/app/AppShell.svelte.d.ts +75 -4
  45. package/dist/components/app/AppShell.svelte.d.ts.map +1 -1
  46. package/dist/components/app/DockToggles.svelte +0 -1
  47. package/dist/components/app/dock-toggle.d.ts +7 -1
  48. package/dist/components/app/dock-toggle.d.ts.map +1 -1
  49. package/dist/components/app/index.d.ts +2 -1
  50. package/dist/components/app/index.d.ts.map +1 -1
  51. package/dist/components/app/slot-item.d.ts +21 -0
  52. package/dist/components/app/slot-item.d.ts.map +1 -0
  53. package/dist/components/app/slot-item.js +1 -0
  54. package/dist/components/command-palette/CommandPalette.svelte +75 -0
  55. package/dist/components/command-palette/CommandPalette.svelte.d.ts +22 -0
  56. package/dist/components/command-palette/CommandPalette.svelte.d.ts.map +1 -0
  57. package/dist/components/command-palette/CommandPaletteDialog.svelte +406 -0
  58. package/dist/components/command-palette/CommandPaletteDialog.svelte.d.ts +18 -0
  59. package/dist/components/command-palette/CommandPaletteDialog.svelte.d.ts.map +1 -0
  60. package/dist/components/command-palette/CommandPaletteTrigger.svelte +91 -0
  61. package/dist/components/command-palette/CommandPaletteTrigger.svelte.d.ts +17 -0
  62. package/dist/components/command-palette/CommandPaletteTrigger.svelte.d.ts.map +1 -0
  63. package/dist/components/command-palette/context.d.ts +18 -0
  64. package/dist/components/command-palette/context.d.ts.map +1 -0
  65. package/dist/components/command-palette/context.js +38 -0
  66. package/dist/components/command-palette/controller.svelte.d.ts +70 -0
  67. package/dist/components/command-palette/controller.svelte.d.ts.map +1 -0
  68. package/dist/components/command-palette/controller.svelte.js +379 -0
  69. package/dist/components/command-palette/hotkeys.d.ts +30 -0
  70. package/dist/components/command-palette/hotkeys.d.ts.map +1 -0
  71. package/dist/components/command-palette/hotkeys.js +161 -0
  72. package/dist/components/command-palette/index.d.ts +19 -0
  73. package/dist/components/command-palette/index.d.ts.map +1 -0
  74. package/dist/components/command-palette/index.js +17 -0
  75. package/dist/components/command-palette/match.d.ts +38 -0
  76. package/dist/components/command-palette/match.d.ts.map +1 -0
  77. package/dist/components/command-palette/match.js +172 -0
  78. package/dist/components/command-palette/providers.d.ts +159 -0
  79. package/dist/components/command-palette/providers.d.ts.map +1 -0
  80. package/dist/components/command-palette/providers.js +345 -0
  81. package/dist/components/command-palette/rank.d.ts +20 -0
  82. package/dist/components/command-palette/rank.d.ts.map +1 -0
  83. package/dist/components/command-palette/rank.js +74 -0
  84. package/dist/components/command-palette/types.d.ts +119 -0
  85. package/dist/components/command-palette/types.d.ts.map +1 -0
  86. package/dist/components/command-palette/types.js +10 -0
  87. package/dist/components/command-palette/use-provider.svelte.d.ts +14 -0
  88. package/dist/components/command-palette/use-provider.svelte.d.ts.map +1 -0
  89. package/dist/components/command-palette/use-provider.svelte.js +23 -0
  90. package/dist/components/forms/AddressInput.svelte +2 -15
  91. package/dist/components/forms/AddressInput.svelte.d.ts.map +1 -1
  92. package/dist/components/forms/DateRangeInput.svelte +2 -15
  93. package/dist/components/forms/DateRangeInput.svelte.d.ts.map +1 -1
  94. package/dist/components/forms/DateTimeInput.svelte +8 -15
  95. package/dist/components/forms/DateTimeInput.svelte.d.ts.map +1 -1
  96. package/dist/components/forms/MeasurementInput.svelte +2 -15
  97. package/dist/components/forms/MeasurementInput.svelte.d.ts.map +1 -1
  98. package/dist/components/forms/MoneyInput.svelte +8 -25
  99. package/dist/components/forms/MoneyInput.svelte.d.ts.map +1 -1
  100. package/dist/components/forms/NumberInput.svelte +7 -15
  101. package/dist/components/forms/NumberInput.svelte.d.ts.map +1 -1
  102. package/dist/components/forms/PhoneInput.svelte +7 -15
  103. package/dist/components/forms/PhoneInput.svelte.d.ts.map +1 -1
  104. package/dist/components/forms/SelectInput.svelte +34 -40
  105. package/dist/components/forms/SelectInput.svelte.d.ts.map +1 -1
  106. package/dist/components/forms/TextInput.svelte +20 -37
  107. package/dist/components/forms/TextInput.svelte.d.ts.map +1 -1
  108. package/dist/components/forms/TextareaInput.svelte +19 -35
  109. package/dist/components/forms/TextareaInput.svelte.d.ts.map +1 -1
  110. package/dist/components/import-export/ImportExport.svelte +678 -0
  111. package/dist/components/import-export/ImportExport.svelte.d.ts +5 -0
  112. package/dist/components/import-export/ImportExport.svelte.d.ts.map +1 -0
  113. package/dist/components/import-export/collection-adapter.d.ts +35 -0
  114. package/dist/components/import-export/collection-adapter.d.ts.map +1 -0
  115. package/dist/components/import-export/collection-adapter.js +42 -0
  116. package/dist/components/import-export/csv.d.ts +60 -0
  117. package/dist/components/import-export/csv.d.ts.map +1 -0
  118. package/dist/components/import-export/csv.js +192 -0
  119. package/dist/components/import-export/download.d.ts +4 -0
  120. package/dist/components/import-export/download.d.ts.map +1 -0
  121. package/dist/components/import-export/download.js +17 -0
  122. package/dist/components/import-export/export.d.ts +25 -0
  123. package/dist/components/import-export/export.d.ts.map +1 -0
  124. package/dist/components/import-export/export.js +68 -0
  125. package/dist/components/import-export/fields.d.ts +48 -0
  126. package/dist/components/import-export/fields.d.ts.map +1 -0
  127. package/dist/components/import-export/fields.js +103 -0
  128. package/dist/components/import-export/index.d.ts +12 -0
  129. package/dist/components/import-export/index.d.ts.map +1 -0
  130. package/dist/components/import-export/index.js +9 -0
  131. package/dist/components/import-export/mapping.d.ts +12 -0
  132. package/dist/components/import-export/mapping.d.ts.map +1 -0
  133. package/dist/components/import-export/mapping.js +38 -0
  134. package/dist/components/import-export/props.d.ts +34 -0
  135. package/dist/components/import-export/props.d.ts.map +1 -0
  136. package/dist/components/import-export/props.js +1 -0
  137. package/dist/components/import-export/report.d.ts +13 -0
  138. package/dist/components/import-export/report.d.ts.map +1 -0
  139. package/dist/components/import-export/report.js +50 -0
  140. package/dist/components/import-export/runner.d.ts +17 -0
  141. package/dist/components/import-export/runner.d.ts.map +1 -0
  142. package/dist/components/import-export/runner.js +39 -0
  143. package/dist/components/import-export/types.d.ts +100 -0
  144. package/dist/components/import-export/types.d.ts.map +1 -0
  145. package/dist/components/import-export/types.js +6 -0
  146. package/dist/components/import-export/validate.d.ts +39 -0
  147. package/dist/components/import-export/validate.d.ts.map +1 -0
  148. package/dist/components/import-export/validate.js +268 -0
  149. package/dist/components/overview/OverviewGrid.svelte +579 -0
  150. package/dist/components/overview/OverviewGrid.svelte.d.ts +5 -0
  151. package/dist/components/overview/OverviewGrid.svelte.d.ts.map +1 -0
  152. package/dist/components/overview/WidgetOptionsForm.svelte +193 -0
  153. package/dist/components/overview/WidgetOptionsForm.svelte.d.ts +5 -0
  154. package/dist/components/overview/WidgetOptionsForm.svelte.d.ts.map +1 -0
  155. package/dist/components/overview/controller.svelte.d.ts +92 -0
  156. package/dist/components/overview/controller.svelte.d.ts.map +1 -0
  157. package/dist/components/overview/controller.svelte.js +336 -0
  158. package/dist/components/overview/format.d.ts +13 -0
  159. package/dist/components/overview/format.d.ts.map +1 -0
  160. package/dist/components/overview/format.js +45 -0
  161. package/dist/components/overview/grid-types.d.ts +52 -0
  162. package/dist/components/overview/grid-types.d.ts.map +1 -0
  163. package/dist/components/overview/grid-types.js +1 -0
  164. package/dist/components/overview/index.d.ts +24 -0
  165. package/dist/components/overview/index.d.ts.map +1 -0
  166. package/dist/components/overview/index.js +22 -0
  167. package/dist/components/overview/load.d.ts +30 -0
  168. package/dist/components/overview/load.d.ts.map +1 -0
  169. package/dist/components/overview/load.js +92 -0
  170. package/dist/components/overview/markdown.d.ts +53 -0
  171. package/dist/components/overview/markdown.d.ts.map +1 -0
  172. package/dist/components/overview/markdown.js +203 -0
  173. package/dist/components/overview/model.d.ts +100 -0
  174. package/dist/components/overview/model.d.ts.map +1 -0
  175. package/dist/components/overview/model.js +460 -0
  176. package/dist/components/overview/recipe-widgets.d.ts +77 -0
  177. package/dist/components/overview/recipe-widgets.d.ts.map +1 -0
  178. package/dist/components/overview/recipe-widgets.js +151 -0
  179. package/dist/components/overview/registry.d.ts +45 -0
  180. package/dist/components/overview/registry.d.ts.map +1 -0
  181. package/dist/components/overview/registry.js +112 -0
  182. package/dist/components/overview/resize.d.ts +25 -0
  183. package/dist/components/overview/resize.d.ts.map +1 -0
  184. package/dist/components/overview/resize.js +41 -0
  185. package/dist/components/overview/schema.d.ts +34 -0
  186. package/dist/components/overview/schema.d.ts.map +1 -0
  187. package/dist/components/overview/schema.js +180 -0
  188. package/dist/components/overview/server.d.ts +14 -0
  189. package/dist/components/overview/server.d.ts.map +1 -0
  190. package/dist/components/overview/server.js +13 -0
  191. package/dist/components/overview/types.d.ts +235 -0
  192. package/dist/components/overview/types.d.ts.map +1 -0
  193. package/dist/components/overview/types.js +17 -0
  194. package/dist/components/overview/widgets/ChartWidget.svelte +111 -0
  195. package/dist/components/overview/widgets/ChartWidget.svelte.d.ts +6 -0
  196. package/dist/components/overview/widgets/ChartWidget.svelte.d.ts.map +1 -0
  197. package/dist/components/overview/widgets/MetricWidget.svelte +86 -0
  198. package/dist/components/overview/widgets/MetricWidget.svelte.d.ts +6 -0
  199. package/dist/components/overview/widgets/MetricWidget.svelte.d.ts.map +1 -0
  200. package/dist/components/overview/widgets/NoteWidget.svelte +61 -0
  201. package/dist/components/overview/widgets/NoteWidget.svelte.d.ts +5 -0
  202. package/dist/components/overview/widgets/NoteWidget.svelte.d.ts.map +1 -0
  203. package/dist/components/overview/widgets/RecordListWidget.svelte +91 -0
  204. package/dist/components/overview/widgets/RecordListWidget.svelte.d.ts +6 -0
  205. package/dist/components/overview/widgets/RecordListWidget.svelte.d.ts.map +1 -0
  206. package/dist/components/overview/widgets/ShortcutsWidget.svelte +80 -0
  207. package/dist/components/overview/widgets/ShortcutsWidget.svelte.d.ts +6 -0
  208. package/dist/components/overview/widgets/ShortcutsWidget.svelte.d.ts.map +1 -0
  209. package/dist/components/overview/widgets/core.d.ts +44 -0
  210. package/dist/components/overview/widgets/core.d.ts.map +1 -0
  211. package/dist/components/overview/widgets/core.js +222 -0
  212. package/dist/components/overview/widgets/data.d.ts +76 -0
  213. package/dist/components/overview/widgets/data.d.ts.map +1 -0
  214. package/dist/components/overview/widgets/data.js +40 -0
  215. package/dist/components/screens/DetailScreen.svelte +220 -0
  216. package/dist/components/screens/DetailScreen.svelte.d.ts +5 -0
  217. package/dist/components/screens/DetailScreen.svelte.d.ts.map +1 -0
  218. package/dist/components/screens/EditForm.svelte +313 -0
  219. package/dist/components/screens/EditForm.svelte.d.ts +5 -0
  220. package/dist/components/screens/EditForm.svelte.d.ts.map +1 -0
  221. package/dist/components/screens/ListScreen.svelte +191 -0
  222. package/dist/components/screens/ListScreen.svelte.d.ts +5 -0
  223. package/dist/components/screens/ListScreen.svelte.d.ts.map +1 -0
  224. package/dist/components/screens/RecipeScreens.svelte +237 -0
  225. package/dist/components/screens/RecipeScreens.svelte.d.ts +5 -0
  226. package/dist/components/screens/RecipeScreens.svelte.d.ts.map +1 -0
  227. package/dist/components/screens/fields.d.ts +54 -0
  228. package/dist/components/screens/fields.d.ts.map +1 -0
  229. package/dist/components/screens/fields.js +229 -0
  230. package/dist/components/screens/index.d.ts +8 -0
  231. package/dist/components/screens/index.d.ts.map +1 -0
  232. package/dist/components/screens/index.js +6 -0
  233. package/dist/components/screens/types.d.ts +215 -0
  234. package/dist/components/screens/types.d.ts.map +1 -0
  235. package/dist/components/screens/types.js +1 -0
  236. package/dist/components/screens/values.d.ts +62 -0
  237. package/dist/components/screens/values.d.ts.map +1 -0
  238. package/dist/components/screens/values.js +289 -0
  239. package/dist/components/sortable/Sortable.svelte +6 -33
  240. package/dist/components/sortable/Sortable.svelte.d.ts.map +1 -1
  241. package/dist/components/sortable/announce.d.ts +5 -0
  242. package/dist/components/sortable/announce.d.ts.map +1 -0
  243. package/dist/components/sortable/announce.js +33 -0
  244. package/dist/components/sortable/controller.svelte.d.ts +10 -0
  245. package/dist/components/sortable/controller.svelte.d.ts.map +1 -1
  246. package/dist/components/sortable/controller.svelte.js +29 -7
  247. package/dist/components/workspace/admin-shell/AdminShell.svelte +424 -58
  248. package/dist/components/workspace/admin-shell/AdminShell.svelte.d.ts +27 -2
  249. package/dist/components/workspace/admin-shell/AdminShell.svelte.d.ts.map +1 -1
  250. package/dist/components/workspace/admin-shell/ShellBrand.svelte +86 -0
  251. package/dist/components/workspace/admin-shell/ShellBrand.svelte.d.ts +18 -0
  252. package/dist/components/workspace/admin-shell/ShellBrand.svelte.d.ts.map +1 -0
  253. package/dist/components/workspace/admin-shell/ShellIconButton.svelte +77 -0
  254. package/dist/components/workspace/admin-shell/ShellIconButton.svelte.d.ts +26 -0
  255. package/dist/components/workspace/admin-shell/ShellIconButton.svelte.d.ts.map +1 -0
  256. package/dist/components/workspace/admin-shell/ShellLayoutEditor.svelte +88 -16
  257. package/dist/components/workspace/admin-shell/ShellLayoutEditor.svelte.d.ts.map +1 -1
  258. package/dist/components/workspace/admin-shell/ShellNavEditor.svelte +531 -0
  259. package/dist/components/workspace/admin-shell/ShellNavEditor.svelte.d.ts +26 -0
  260. package/dist/components/workspace/admin-shell/ShellNavEditor.svelte.d.ts.map +1 -0
  261. package/dist/components/workspace/admin-shell/ShellSectionIcon.svelte +57 -0
  262. package/dist/components/workspace/admin-shell/ShellSectionIcon.svelte.d.ts +22 -0
  263. package/dist/components/workspace/admin-shell/ShellSectionIcon.svelte.d.ts.map +1 -0
  264. package/dist/components/workspace/admin-shell/ShellSectionMenu.svelte +290 -0
  265. package/dist/components/workspace/admin-shell/ShellSectionMenu.svelte.d.ts +32 -0
  266. package/dist/components/workspace/admin-shell/ShellSectionMenu.svelte.d.ts.map +1 -0
  267. package/dist/components/workspace/admin-shell/TenantNav.svelte +67 -2
  268. package/dist/components/workspace/admin-shell/TenantNav.svelte.d.ts +8 -0
  269. package/dist/components/workspace/admin-shell/TenantNav.svelte.d.ts.map +1 -1
  270. package/dist/components/workspace/admin-shell/layout-controller.svelte.d.ts +67 -0
  271. package/dist/components/workspace/admin-shell/layout-controller.svelte.d.ts.map +1 -1
  272. package/dist/components/workspace/admin-shell/layout-controller.svelte.js +129 -1
  273. package/dist/components/workspace/admin-shell/layout.d.ts +122 -0
  274. package/dist/components/workspace/admin-shell/layout.d.ts.map +1 -1
  275. package/dist/components/workspace/admin-shell/layout.js +410 -10
  276. package/dist/components/workspace/admin-shell/settings.js +4 -4
  277. package/dist/components/workspace/admin-shell/shell-icons.d.ts +45 -0
  278. package/dist/components/workspace/admin-shell/shell-icons.d.ts.map +1 -0
  279. package/dist/components/workspace/admin-shell/shell-icons.js +66 -0
  280. package/dist/components/workspace/admin-shell/slot-labels.d.ts +33 -0
  281. package/dist/components/workspace/admin-shell/slot-labels.d.ts.map +1 -0
  282. package/dist/components/workspace/admin-shell/slot-labels.js +33 -0
  283. package/dist/components/workspace/admin-shell/slots.d.ts +50 -0
  284. package/dist/components/workspace/admin-shell/slots.d.ts.map +1 -0
  285. package/dist/components/workspace/admin-shell/slots.js +77 -0
  286. package/dist/components/workspace/admin-shell/state.svelte.d.ts +35 -0
  287. package/dist/components/workspace/admin-shell/state.svelte.d.ts.map +1 -1
  288. package/dist/components/workspace/admin-shell/state.svelte.js +111 -0
  289. package/dist/components/workspace/admin-shell/types.d.ts +101 -1
  290. package/dist/components/workspace/admin-shell/types.d.ts.map +1 -1
  291. package/dist/components/workspace/index.d.ts +9 -2
  292. package/dist/components/workspace/index.d.ts.map +1 -1
  293. package/dist/components/workspace/index.js +6 -0
  294. package/dist/components/workspace/manifest-nav.d.ts +20 -0
  295. package/dist/components/workspace/manifest-nav.d.ts.map +1 -1
  296. package/dist/components/workspace/manifest-nav.js +42 -13
  297. package/dist/i18n/server.d.ts +6 -0
  298. package/dist/i18n/server.d.ts.map +1 -1
  299. package/dist/i18n/server.js +6 -0
  300. package/dist/i18n/strings.import-export.d.ts +88 -0
  301. package/dist/i18n/strings.import-export.d.ts.map +1 -0
  302. package/dist/i18n/strings.import-export.js +88 -0
  303. package/dist/i18n/strings.overview.d.ts +100 -0
  304. package/dist/i18n/strings.overview.d.ts.map +1 -0
  305. package/dist/i18n/strings.overview.js +107 -0
  306. package/dist/i18n/strings.palette.d.ts +18 -0
  307. package/dist/i18n/strings.palette.d.ts.map +1 -0
  308. package/dist/i18n/strings.palette.js +18 -0
  309. package/dist/i18n/strings.screens.d.ts +31 -0
  310. package/dist/i18n/strings.screens.d.ts.map +1 -0
  311. package/dist/i18n/strings.screens.js +31 -0
  312. package/dist/i18n/strings.workspace.d.ts +49 -0
  313. package/dist/i18n/strings.workspace.d.ts.map +1 -1
  314. package/dist/i18n/strings.workspace.js +49 -0
  315. package/package.json +59 -19
  316. package/dist/browser-ai/adapters/stt/whisper-wasm.d.ts +0 -51
  317. package/dist/browser-ai/adapters/stt/whisper-wasm.d.ts.map +0 -1
  318. package/dist/browser-ai/adapters/stt/whisper-wasm.js +0 -380
@@ -14,8 +14,12 @@ export class BrowserSynthesisTTSAdapter {
14
14
  synthesis = null;
15
15
  options;
16
16
  voices = [];
17
- // biome-ignore lint/correctness/noUnusedPrivateClassMembers: Used in speak/stop/pause
18
17
  currentUtterance = null;
18
+ operationGeneration = 0;
19
+ initializationGeneration = 0;
20
+ initialization = null;
21
+ cancelVoiceLoad = null;
22
+ settleCurrentSpeech = null;
19
23
  // Event listeners
20
24
  startListeners = new Set();
21
25
  endListeners = new Set();
@@ -36,58 +40,60 @@ export class BrowserSynthesisTTSAdapter {
36
40
  async ensureInitialized(_onProgress) {
37
41
  if (this._initState === 'ready')
38
42
  return;
39
- if (this._initState === 'initializing') {
40
- // Wait for existing initialization
41
- return new Promise((resolve, reject) => {
42
- const check = () => {
43
- if (this._initState === 'ready')
44
- resolve();
45
- else if (this._initState === 'error')
46
- reject(new Error('Initialization failed'));
47
- else
48
- setTimeout(check, 50);
49
- };
50
- check();
51
- });
52
- }
43
+ if (this.initialization)
44
+ return this.initialization;
45
+ const generation = this.initializationGeneration;
53
46
  this._initState = 'initializing';
54
- try {
55
- if (typeof window === 'undefined' || !window.speechSynthesis) {
56
- throw new CapabilityNotAvailableError('Web Speech Synthesis API', 'browser-synthesis');
47
+ const initialization = (async () => {
48
+ try {
49
+ if (typeof window === 'undefined' || !window.speechSynthesis) {
50
+ throw new CapabilityNotAvailableError('Web Speech Synthesis API', 'browser-synthesis');
51
+ }
52
+ this.synthesis = window.speechSynthesis;
53
+ await this.loadVoices(this.synthesis);
54
+ if (generation === this.initializationGeneration) {
55
+ this._initState = 'ready';
56
+ }
57
+ }
58
+ catch (error) {
59
+ if (generation === this.initializationGeneration) {
60
+ this._initState = 'error';
61
+ }
62
+ throw error;
57
63
  }
58
- this.synthesis = window.speechSynthesis;
59
- // Load voices - they may load asynchronously
60
- await this.loadVoices();
61
- this._initState = 'ready';
64
+ })();
65
+ this.initialization = initialization;
66
+ try {
67
+ await initialization;
62
68
  }
63
- catch (error) {
64
- this._initState = 'error';
65
- throw error;
69
+ finally {
70
+ if (this.initialization === initialization)
71
+ this.initialization = null;
66
72
  }
67
73
  }
68
- async loadVoices() {
69
- if (!this.synthesis)
74
+ async loadVoices(synthesis) {
75
+ this.voices = synthesis.getVoices();
76
+ if (this.voices.length > 0)
70
77
  return;
71
- // Get voices - may be empty initially in some browsers
72
- this.voices = this.synthesis.getVoices();
73
- if (this.voices.length === 0) {
74
- // Wait for voices to load
75
- await new Promise((resolve) => {
76
- const handleVoicesChanged = () => {
77
- this.voices = this.synthesis?.getVoices() ?? [];
78
- if (this.voices.length > 0) {
79
- this.synthesis?.removeEventListener('voiceschanged', handleVoicesChanged);
80
- resolve();
81
- }
82
- };
83
- this.synthesis?.addEventListener('voiceschanged', handleVoicesChanged);
84
- // Timeout after 2 seconds - some browsers may not fire the event
85
- setTimeout(() => {
86
- this.voices = this.synthesis?.getVoices() ?? [];
87
- resolve();
88
- }, 2000);
89
- });
90
- }
78
+ await new Promise((resolve) => {
79
+ const finish = () => {
80
+ clearTimeout(timeout);
81
+ synthesis.removeEventListener('voiceschanged', handleVoicesChanged);
82
+ this.cancelVoiceLoad = null;
83
+ resolve();
84
+ };
85
+ const handleVoicesChanged = () => {
86
+ this.voices = synthesis.getVoices();
87
+ if (this.voices.length > 0)
88
+ finish();
89
+ };
90
+ const timeout = setTimeout(() => {
91
+ this.voices = synthesis.getVoices();
92
+ finish();
93
+ }, 2000);
94
+ this.cancelVoiceLoad = finish;
95
+ synthesis.addEventListener('voiceschanged', handleVoicesChanged);
96
+ });
91
97
  }
92
98
  getCapabilities() {
93
99
  return {
@@ -133,12 +139,15 @@ export class BrowserSynthesisTTSAdapter {
133
139
  return this.voices.find((v) => v.default) || this.voices[0];
134
140
  }
135
141
  async speak(text, options = {}) {
142
+ // Invalidate previous requests before the asynchronous voices wait.
143
+ this.stop();
144
+ const generation = this.operationGeneration;
136
145
  await this.ensureInitialized();
146
+ if (generation !== this.operationGeneration)
147
+ return;
137
148
  if (!this.synthesis) {
138
149
  throw new Error('Synthesis not initialized');
139
150
  }
140
- // Cancel any current speech
141
- this.stop();
142
151
  return new Promise((resolve, reject) => {
143
152
  const utterance = new SpeechSynthesisUtterance(text);
144
153
  // Set voice
@@ -154,21 +163,34 @@ export class BrowserSynthesisTTSAdapter {
154
163
  utterance.rate = options.rate ?? this.options.defaultRate ?? 1;
155
164
  utterance.pitch = options.pitch ?? this.options.defaultPitch ?? 1;
156
165
  utterance.volume = options.volume ?? this.options.defaultVolume ?? 1;
166
+ const isCurrent = () => generation === this.operationGeneration &&
167
+ this.currentUtterance === utterance;
168
+ const settle = () => {
169
+ this.currentUtterance = null;
170
+ this.settleCurrentSpeech = null;
171
+ resolve();
172
+ };
157
173
  // Set up event handlers
158
174
  utterance.onstart = () => {
175
+ if (!isCurrent())
176
+ return;
159
177
  for (const cb of this.startListeners) {
160
178
  cb();
161
179
  }
162
180
  };
163
181
  utterance.onend = () => {
164
- this.currentUtterance = null;
182
+ if (!isCurrent())
183
+ return;
184
+ settle();
165
185
  for (const cb of this.endListeners) {
166
186
  cb();
167
187
  }
168
- resolve();
169
188
  };
170
189
  utterance.onerror = (event) => {
190
+ if (!isCurrent())
191
+ return;
171
192
  this.currentUtterance = null;
193
+ this.settleCurrentSpeech = null;
172
194
  const error = new Error(`Speech synthesis error: ${event.error}`);
173
195
  for (const cb of this.errorListeners) {
174
196
  cb(error);
@@ -176,19 +198,22 @@ export class BrowserSynthesisTTSAdapter {
176
198
  reject(error);
177
199
  };
178
200
  utterance.onboundary = (event) => {
201
+ if (!isCurrent())
202
+ return;
179
203
  for (const cb of this.boundaryListeners) {
180
204
  cb(event.charIndex, event.charLength || 1);
181
205
  }
182
206
  };
183
207
  this.currentUtterance = utterance;
208
+ this.settleCurrentSpeech = settle;
184
209
  this.synthesis?.speak(utterance);
185
210
  });
186
211
  }
187
212
  stop() {
188
- if (this.synthesis) {
189
- this.synthesis.cancel();
190
- this.currentUtterance = null;
191
- }
213
+ ++this.operationGeneration;
214
+ // Settle before native cancel: it may emit synchronous callbacks or none.
215
+ this.settleCurrentSpeech?.();
216
+ this.synthesis?.cancel();
192
217
  }
193
218
  pause() {
194
219
  if (this.synthesis) {
@@ -224,6 +249,9 @@ export class BrowserSynthesisTTSAdapter {
224
249
  }
225
250
  async dispose() {
226
251
  this.stop();
252
+ ++this.initializationGeneration;
253
+ this.cancelVoiceLoad?.();
254
+ this.initialization = null;
227
255
  this.synthesis = null;
228
256
  this.voices = [];
229
257
  this.startListeners.clear();
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Should a host offer local (downloadable) speech recognition?
3
+ *
4
+ * The browser's own speech recognition (`SpeechRecognition`) is a thin
5
+ * client for a vendor speech service, so "the API exists" does not mean it
6
+ * works. This looks only at what the browser exposes: it makes no network
7
+ * request and never opens the microphone (so there is no permission prompt).
8
+ *
9
+ * - `'works'`: Chrome-family browsers with the API (Chrome, Edge, Safari).
10
+ * - `'missing'`: no `SpeechRecognition` at all (Firefox).
11
+ * - `'unreliable'`: the API is there but has no speech service behind it:
12
+ * Brave (it ends instantly or fails with `network`), or an embedded
13
+ * Chromium (Electron) with no vendor speech key.
14
+ *
15
+ * Anything but `'works'` is a reason to offer the local model. A recogniser
16
+ * that still turns out to end instantly is caught later by smrt-ui's
17
+ * dictation state machine, which reports it as an error.
18
+ */
19
+ export type BrowserSpeechSupport = 'works' | 'missing' | 'unreliable';
20
+ /** The browser objects the probe reads; injectable for tests. */
21
+ export interface BrowserSpeechProbeEnv {
22
+ window?: Record<string, unknown>;
23
+ navigator?: {
24
+ userAgent?: string;
25
+ brave?: unknown;
26
+ };
27
+ }
28
+ export declare function probeBrowserSpeech(env?: BrowserSpeechProbeEnv): Promise<BrowserSpeechSupport>;
29
+ //# sourceMappingURL=speech-probe.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"speech-probe.d.ts","sourceRoot":"","sources":["../../../src/browser-ai/capabilities/speech-probe.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,MAAM,oBAAoB,GAAG,OAAO,GAAG,SAAS,GAAG,YAAY,CAAC;AAEtE,iEAAiE;AACjE,MAAM,WAAW,qBAAqB;IACpC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,SAAS,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;CACrD;AAED,wBAAsB,kBAAkB,CACtC,GAAG,GAAE,qBAA0B,GAC9B,OAAO,CAAC,oBAAoB,CAAC,CAiB/B"}
@@ -0,0 +1,19 @@
1
+ export async function probeBrowserSpeech(env = {}) {
2
+ const win = env.window ??
3
+ (typeof window !== 'undefined'
4
+ ? window
5
+ : undefined);
6
+ const nav = env.navigator ?? (typeof navigator !== 'undefined' ? navigator : undefined);
7
+ if (!win)
8
+ return 'missing';
9
+ if (!('SpeechRecognition' in win) && !('webkitSpeechRecognition' in win)) {
10
+ return 'missing';
11
+ }
12
+ // Brave defines `navigator.brave`; its recogniser has no service behind it.
13
+ if (nav && 'brave' in nav && nav.brave)
14
+ return 'unreliable';
15
+ // Electron ships the API without the vendor speech key.
16
+ if (/\bElectron\//.test(nav?.userAgent ?? ''))
17
+ return 'unreliable';
18
+ return 'works';
19
+ }
@@ -21,6 +21,15 @@ export declare class InitializationError extends BrowserAIError {
21
21
  export declare class CapabilityNotAvailableError extends BrowserAIError {
22
22
  constructor(capability: string, adapter?: string);
23
23
  }
24
+ /**
25
+ * Thrown when something needs an on-device model that is not stored on this
26
+ * device yet and was asked not to download it. `dictationKind` lets smrt-ui's
27
+ * `Dictation` show "The speech model isn't downloaded yet".
28
+ */
29
+ export declare class ModelNotDownloadedError extends BrowserAIError {
30
+ readonly dictationKind = "model-missing";
31
+ constructor(model: string, adapter?: string);
32
+ }
24
33
  /**
25
34
  * Thrown when a model download fails
26
35
  */
@@ -1 +1 @@
1
- {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../../src/browser-ai/core/errors.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;GAEG;AACH,qBAAa,cAAe,SAAQ,KAAK;IAG9B,IAAI,EAAE,MAAM;IACZ,OAAO,CAAC,EAAE,MAAM;gBAFvB,OAAO,EAAE,MAAM,EACR,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE,MAAM,YAAA;CAK1B;AAED;;GAEG;AACH,qBAAa,mBAAoB,SAAQ,cAAc;gBACzC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM;CAQ7C;AAED;;GAEG;AACH,qBAAa,2BAA4B,SAAQ,cAAc;gBACjD,UAAU,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM;CAQjD;AAED;;GAEG;AACH,qBAAa,aAAc,SAAQ,cAAc;IAEtC,GAAG,EAAE,MAAM;gBAAX,GAAG,EAAE,MAAM,EAClB,MAAM,CAAC,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,MAAM;CASnB;AAED;;GAEG;AACH,qBAAa,cAAe,SAAQ,cAAc;IAEvC,KAAK,EAAE,MAAM;gBAAb,KAAK,EAAE,MAAM,EACpB,MAAM,CAAC,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,MAAM;CASnB;AAED;;GAEG;AACH,qBAAa,YAAa,SAAQ,cAAc;gBAClC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM;CAQnE;AAED;;GAEG;AACH,qBAAa,qBAAsB,SAAQ,cAAc;gBAC3C,UAAU,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM;CAIjD;AAED;;GAEG;AACH,qBAAa,iBAAkB,SAAQ,cAAc;gBACvC,aAAa,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM;CAQzE;AAED;;GAEG;AACH,qBAAa,uBAAwB,SAAQ,cAAc;gBAC7C,WAAW,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,EAAE;CAO1D"}
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../../src/browser-ai/core/errors.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;GAEG;AACH,qBAAa,cAAe,SAAQ,KAAK;IAG9B,IAAI,EAAE,MAAM;IACZ,OAAO,CAAC,EAAE,MAAM;gBAFvB,OAAO,EAAE,MAAM,EACR,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE,MAAM,YAAA;CAK1B;AAED;;GAEG;AACH,qBAAa,mBAAoB,SAAQ,cAAc;gBACzC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM;CAQ7C;AAED;;GAEG;AACH,qBAAa,2BAA4B,SAAQ,cAAc;gBACjD,UAAU,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM;CAQjD;AAED;;;;GAIG;AACH,qBAAa,uBAAwB,SAAQ,cAAc;IACzD,QAAQ,CAAC,aAAa,mBAAmB;gBAC7B,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM;CAQ5C;AAED;;GAEG;AACH,qBAAa,aAAc,SAAQ,cAAc;IAEtC,GAAG,EAAE,MAAM;gBAAX,GAAG,EAAE,MAAM,EAClB,MAAM,CAAC,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,MAAM;CASnB;AAED;;GAEG;AACH,qBAAa,cAAe,SAAQ,cAAc;IAEvC,KAAK,EAAE,MAAM;gBAAb,KAAK,EAAE,MAAM,EACpB,MAAM,CAAC,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,MAAM;CASnB;AAED;;GAEG;AACH,qBAAa,YAAa,SAAQ,cAAc;gBAClC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM;CAQnE;AAED;;GAEG;AACH,qBAAa,qBAAsB,SAAQ,cAAc;gBAC3C,UAAU,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM;CAIjD;AAED;;GAEG;AACH,qBAAa,iBAAkB,SAAQ,cAAc;gBACvC,aAAa,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM;CAQzE;AAED;;GAEG;AACH,qBAAa,uBAAwB,SAAQ,cAAc;gBAC7C,WAAW,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,EAAE;CAO1D"}
@@ -32,6 +32,18 @@ export class CapabilityNotAvailableError extends BrowserAIError {
32
32
  this.name = 'CapabilityNotAvailableError';
33
33
  }
34
34
  }
35
+ /**
36
+ * Thrown when something needs an on-device model that is not stored on this
37
+ * device yet and was asked not to download it. `dictationKind` lets smrt-ui's
38
+ * `Dictation` show "The speech model isn't downloaded yet".
39
+ */
40
+ export class ModelNotDownloadedError extends BrowserAIError {
41
+ dictationKind = 'model-missing';
42
+ constructor(model, adapter) {
43
+ super(`The speech model isn't downloaded yet (${model})`, 'MODEL_NOT_DOWNLOADED', adapter);
44
+ this.name = 'ModelNotDownloadedError';
45
+ }
46
+ }
35
47
  /**
36
48
  * Thrown when a model download fails
37
49
  */
@@ -8,5 +8,6 @@ export * from './adapters/llm/index.js';
8
8
  export * from './adapters/stt/index.js';
9
9
  export * from './adapters/tts/index.js';
10
10
  export * from './capabilities/detector.js';
11
+ export * from './capabilities/speech-probe.js';
11
12
  export * from './core/index.js';
12
13
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/browser-ai/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,cAAc,yBAAyB,CAAC;AAExC,cAAc,yBAAyB,CAAC;AAExC,cAAc,yBAAyB,CAAC;AAExC,cAAc,4BAA4B,CAAC;AAE3C,cAAc,iBAAiB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/browser-ai/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,cAAc,yBAAyB,CAAC;AAExC,cAAc,yBAAyB,CAAC;AAExC,cAAc,yBAAyB,CAAC;AAExC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,gCAAgC,CAAC;AAE/C,cAAc,iBAAiB,CAAC"}
@@ -12,5 +12,6 @@ export * from './adapters/stt/index.js';
12
12
  export * from './adapters/tts/index.js';
13
13
  // Capability detection
14
14
  export * from './capabilities/detector.js';
15
+ export * from './capabilities/speech-probe.js';
15
16
  // Core types and errors
16
17
  export * from './core/index.js';