@vertesia/ui 1.5.0-dev.20260807.073259Z → 1.5.0-dev.20260901.005903Z

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 (502) hide show
  1. package/README.md +1 -7
  2. package/lib/core/components/FormItem.d.ts.map +1 -1
  3. package/lib/core/components/FormItem.js +2 -3
  4. package/lib/core/components/FormItem.js.map +1 -1
  5. package/lib/core/components/InfoTip.d.ts +20 -0
  6. package/lib/core/components/InfoTip.d.ts.map +1 -0
  7. package/lib/core/components/InfoTip.js +18 -0
  8. package/lib/core/components/InfoTip.js.map +1 -0
  9. package/lib/core/components/index.d.ts +1 -0
  10. package/lib/core/components/index.d.ts.map +1 -1
  11. package/lib/core/components/index.js +1 -0
  12. package/lib/core/components/index.js.map +1 -1
  13. package/lib/core/components/shadcn/Panel.d.ts.map +1 -1
  14. package/lib/core/components/shadcn/Panel.js +3 -3
  15. package/lib/core/components/shadcn/Panel.js.map +1 -1
  16. package/lib/core/components/shadcn/filters/comboBox/DateCombobox.js +1 -1
  17. package/lib/core/components/shadcn/filters/comboBox/DateCombobox.js.map +1 -1
  18. package/lib/core/components/shadcn/filters/filter/dateFilter.d.ts.map +1 -1
  19. package/lib/core/components/shadcn/filters/filter/dateFilter.js +1 -1
  20. package/lib/core/components/shadcn/filters/filter/dateFilter.js.map +1 -1
  21. package/lib/core/components/shadcn/filters/filters.d.ts.map +1 -1
  22. package/lib/core/components/shadcn/filters/filters.js +1 -1
  23. package/lib/core/components/shadcn/filters/filters.js.map +1 -1
  24. package/lib/core/components/shadcn/index.d.ts +1 -0
  25. package/lib/core/components/shadcn/index.d.ts.map +1 -1
  26. package/lib/core/components/shadcn/index.js +1 -0
  27. package/lib/core/components/shadcn/index.js.map +1 -1
  28. package/lib/core/components/shadcn/modal/dialog.d.ts.map +1 -1
  29. package/lib/core/components/shadcn/modal/dialog.js +1 -3
  30. package/lib/core/components/shadcn/modal/dialog.js.map +1 -1
  31. package/lib/core/components/shadcn/overflowTabs.d.ts +59 -0
  32. package/lib/core/components/shadcn/overflowTabs.d.ts.map +1 -0
  33. package/lib/core/components/shadcn/overflowTabs.js +173 -0
  34. package/lib/core/components/shadcn/overflowTabs.js.map +1 -0
  35. package/lib/core/components/shadcn/selectBox.js +2 -2
  36. package/lib/core/components/shadcn/selectBox.js.map +1 -1
  37. package/lib/core/components/shadcn/theme/ThemeProvider.d.ts +3 -1
  38. package/lib/core/components/shadcn/theme/ThemeProvider.d.ts.map +1 -1
  39. package/lib/core/components/shadcn/theme/ThemeProvider.js +8 -9
  40. package/lib/core/components/shadcn/theme/ThemeProvider.js.map +1 -1
  41. package/lib/core/utils/dayjs.d.ts +12 -0
  42. package/lib/core/utils/dayjs.d.ts.map +1 -0
  43. package/lib/core/utils/dayjs.js +16 -0
  44. package/lib/core/utils/dayjs.js.map +1 -0
  45. package/lib/env/index.d.ts +17 -0
  46. package/lib/env/index.d.ts.map +1 -1
  47. package/lib/env/index.js +18 -1
  48. package/lib/env/index.js.map +1 -1
  49. package/lib/features/agent/PayloadBuilder.d.ts +1 -0
  50. package/lib/features/agent/PayloadBuilder.d.ts.map +1 -1
  51. package/lib/features/agent/PayloadBuilder.js +22 -5
  52. package/lib/features/agent/PayloadBuilder.js.map +1 -1
  53. package/lib/features/agent/chat/AgentRightPanel.d.ts.map +1 -1
  54. package/lib/features/agent/chat/AgentRightPanel.js +3 -135
  55. package/lib/features/agent/chat/AgentRightPanel.js.map +1 -1
  56. package/lib/features/agent/chat/ArtifactsTab.d.ts.map +1 -1
  57. package/lib/features/agent/chat/ArtifactsTab.js +1 -1
  58. package/lib/features/agent/chat/ArtifactsTab.js.map +1 -1
  59. package/lib/features/agent/chat/AskUserWidget.d.ts.map +1 -1
  60. package/lib/features/agent/chat/AskUserWidget.js +19 -4
  61. package/lib/features/agent/chat/AskUserWidget.js.map +1 -1
  62. package/lib/features/agent/chat/ModernAgentConversation.d.ts +6 -0
  63. package/lib/features/agent/chat/ModernAgentConversation.d.ts.map +1 -1
  64. package/lib/features/agent/chat/ModernAgentConversation.js +99 -29
  65. package/lib/features/agent/chat/ModernAgentConversation.js.map +1 -1
  66. package/lib/features/agent/chat/ModernAgentOutput/ActiveWorkstreamsSummary.d.ts.map +1 -1
  67. package/lib/features/agent/chat/ModernAgentOutput/ActiveWorkstreamsSummary.js +10 -9
  68. package/lib/features/agent/chat/ModernAgentOutput/ActiveWorkstreamsSummary.js.map +1 -1
  69. package/lib/features/agent/chat/ModernAgentOutput/AllMessagesMixed.d.ts.map +1 -1
  70. package/lib/features/agent/chat/ModernAgentOutput/AllMessagesMixed.js +5 -8
  71. package/lib/features/agent/chat/ModernAgentOutput/AllMessagesMixed.js.map +1 -1
  72. package/lib/features/agent/chat/ModernAgentOutput/AttachmentPreview.d.ts.map +1 -1
  73. package/lib/features/agent/chat/ModernAgentOutput/AttachmentPreview.js +45 -4
  74. package/lib/features/agent/chat/ModernAgentOutput/AttachmentPreview.js.map +1 -1
  75. package/lib/features/agent/chat/ModernAgentOutput/BatchProgressPanel.js +1 -1
  76. package/lib/features/agent/chat/ModernAgentOutput/BatchProgressPanel.js.map +1 -1
  77. package/lib/features/agent/chat/ModernAgentOutput/Header.d.ts.map +1 -1
  78. package/lib/features/agent/chat/ModernAgentOutput/Header.js +3 -3
  79. package/lib/features/agent/chat/ModernAgentOutput/Header.js.map +1 -1
  80. package/lib/features/agent/chat/ModernAgentOutput/MessageItem.d.ts.map +1 -1
  81. package/lib/features/agent/chat/ModernAgentOutput/MessageItem.js +1 -1
  82. package/lib/features/agent/chat/ModernAgentOutput/MessageItem.js.map +1 -1
  83. package/lib/features/agent/chat/ModernAgentOutput/StreamingMessage.d.ts.map +1 -1
  84. package/lib/features/agent/chat/ModernAgentOutput/StreamingMessage.js +1 -1
  85. package/lib/features/agent/chat/ModernAgentOutput/StreamingMessage.js.map +1 -1
  86. package/lib/features/agent/chat/ModernAgentOutput/ToolCallGroup.js +1 -1
  87. package/lib/features/agent/chat/ModernAgentOutput/ToolCallGroup.js.map +1 -1
  88. package/lib/features/agent/chat/ModernAgentOutput/WorkstreamTabs.d.ts.map +1 -1
  89. package/lib/features/agent/chat/ModernAgentOutput/WorkstreamTabs.js +9 -121
  90. package/lib/features/agent/chat/ModernAgentOutput/WorkstreamTabs.js.map +1 -1
  91. package/lib/features/agent/chat/ModernAgentOutput/utils.d.ts +6 -0
  92. package/lib/features/agent/chat/ModernAgentOutput/utils.d.ts.map +1 -1
  93. package/lib/features/agent/chat/ModernAgentOutput/utils.js +19 -11
  94. package/lib/features/agent/chat/ModernAgentOutput/utils.js.map +1 -1
  95. package/lib/features/agent/chat/VegaLiteChart.d.ts.map +1 -1
  96. package/lib/features/agent/chat/VegaLiteChart.js +11 -3
  97. package/lib/features/agent/chat/VegaLiteChart.js.map +1 -1
  98. package/lib/features/agent/chat/hooks/useAgentStream.d.ts.map +1 -1
  99. package/lib/features/agent/chat/hooks/useAgentStream.js +3 -0
  100. package/lib/features/agent/chat/hooks/useAgentStream.js.map +1 -1
  101. package/lib/features/document-viewer/UniversalDocumentViewer.d.ts.map +1 -1
  102. package/lib/features/document-viewer/UniversalDocumentViewer.js +1 -1
  103. package/lib/features/document-viewer/UniversalDocumentViewer.js.map +1 -1
  104. package/lib/features/facets/AgentRunnerFacetsNav.d.ts +14 -2
  105. package/lib/features/facets/AgentRunnerFacetsNav.d.ts.map +1 -1
  106. package/lib/features/facets/AgentRunnerFacetsNav.js +20 -2
  107. package/lib/features/facets/AgentRunnerFacetsNav.js.map +1 -1
  108. package/lib/features/facets/CollectionsFacetsNav.d.ts +3 -3
  109. package/lib/features/facets/CollectionsFacetsNav.d.ts.map +1 -1
  110. package/lib/features/facets/CollectionsFacetsNav.js +6 -1
  111. package/lib/features/facets/CollectionsFacetsNav.js.map +1 -1
  112. package/lib/features/facets/DocumentsFacetsNav.d.ts +3 -3
  113. package/lib/features/facets/DocumentsFacetsNav.d.ts.map +1 -1
  114. package/lib/features/facets/DocumentsFacetsNav.js +20 -8
  115. package/lib/features/facets/DocumentsFacetsNav.js.map +1 -1
  116. package/lib/features/facets/InteractionsFacetsNav.d.ts +3 -3
  117. package/lib/features/facets/InteractionsFacetsNav.d.ts.map +1 -1
  118. package/lib/features/facets/InteractionsFacetsNav.js +11 -1
  119. package/lib/features/facets/InteractionsFacetsNav.js.map +1 -1
  120. package/lib/features/facets/PromptsFacetsNav.d.ts +3 -3
  121. package/lib/features/facets/PromptsFacetsNav.d.ts.map +1 -1
  122. package/lib/features/facets/PromptsFacetsNav.js +6 -1
  123. package/lib/features/facets/PromptsFacetsNav.js.map +1 -1
  124. package/lib/features/facets/RunsFacetsNav.d.ts +4 -14
  125. package/lib/features/facets/RunsFacetsNav.d.ts.map +1 -1
  126. package/lib/features/facets/RunsFacetsNav.js +26 -15
  127. package/lib/features/facets/RunsFacetsNav.js.map +1 -1
  128. package/lib/features/facets/WorkflowExecutionsFacetsNav.d.ts +4 -3
  129. package/lib/features/facets/WorkflowExecutionsFacetsNav.d.ts.map +1 -1
  130. package/lib/features/facets/WorkflowExecutionsFacetsNav.js +18 -10
  131. package/lib/features/facets/WorkflowExecutionsFacetsNav.js.map +1 -1
  132. package/lib/features/facets/index.d.ts +1 -1
  133. package/lib/features/facets/index.d.ts.map +1 -1
  134. package/lib/features/facets/index.js.map +1 -1
  135. package/lib/features/facets/utils/SearchInterface.d.ts +4 -3
  136. package/lib/features/facets/utils/SearchInterface.d.ts.map +1 -1
  137. package/lib/features/facets/utils/SearchInterface.js +4 -0
  138. package/lib/features/facets/utils/SearchInterface.js.map +1 -1
  139. package/lib/features/layout/GenericPageNavHeader.d.ts +8 -1
  140. package/lib/features/layout/GenericPageNavHeader.d.ts.map +1 -1
  141. package/lib/features/layout/GenericPageNavHeader.js +9 -1
  142. package/lib/features/layout/GenericPageNavHeader.js.map +1 -1
  143. package/lib/features/magic-pdf/DownloadPopover.d.ts +3 -2
  144. package/lib/features/magic-pdf/DownloadPopover.d.ts.map +1 -1
  145. package/lib/features/magic-pdf/DownloadPopover.js.map +1 -1
  146. package/lib/features/magic-pdf/GroundedExtractionView.d.ts.map +1 -1
  147. package/lib/features/magic-pdf/GroundedExtractionView.js +51 -64
  148. package/lib/features/magic-pdf/GroundedExtractionView.js.map +1 -1
  149. package/lib/features/oauth/McpConnectionsButton.d.ts +1 -1
  150. package/lib/features/oauth/McpConnectionsButton.d.ts.map +1 -1
  151. package/lib/features/oauth/McpConnectionsButton.js +2 -2
  152. package/lib/features/oauth/McpConnectionsButton.js.map +1 -1
  153. package/lib/features/oauth/McpConnectionsDialog.d.ts +1 -1
  154. package/lib/features/oauth/McpConnectionsDialog.js +2 -2
  155. package/lib/features/oauth/McpConnectionsDialog.js.map +1 -1
  156. package/lib/features/oauth/useMcpConnections.d.ts +4 -5
  157. package/lib/features/oauth/useMcpConnections.d.ts.map +1 -1
  158. package/lib/features/oauth/useMcpConnections.js +20 -4
  159. package/lib/features/oauth/useMcpConnections.js.map +1 -1
  160. package/lib/features/pdf-viewer/PdfPageRenderer.d.ts.map +1 -1
  161. package/lib/features/pdf-viewer/PdfPageRenderer.js +9 -11
  162. package/lib/features/pdf-viewer/PdfPageRenderer.js.map +1 -1
  163. package/lib/features/pdf-viewer/lazyReactPdf.d.ts +10 -0
  164. package/lib/features/pdf-viewer/lazyReactPdf.d.ts.map +1 -0
  165. package/lib/features/pdf-viewer/lazyReactPdf.js +25 -0
  166. package/lib/features/pdf-viewer/lazyReactPdf.js.map +1 -0
  167. package/lib/features/store/collections/CollectionsTable.d.ts.map +1 -1
  168. package/lib/features/store/collections/CollectionsTable.js +1 -3
  169. package/lib/features/store/collections/CollectionsTable.js.map +1 -1
  170. package/lib/features/store/collections/EditCollectionView.js +1 -1
  171. package/lib/features/store/collections/EditCollectionView.js.map +1 -1
  172. package/lib/features/store/objects/ExportPropertiesModal.d.ts +3 -1
  173. package/lib/features/store/objects/ExportPropertiesModal.d.ts.map +1 -1
  174. package/lib/features/store/objects/ExportPropertiesModal.js +5 -5
  175. package/lib/features/store/objects/ExportPropertiesModal.js.map +1 -1
  176. package/lib/features/store/objects/components/ContentOverview.d.ts.map +1 -1
  177. package/lib/features/store/objects/components/ContentOverview.js +4 -10
  178. package/lib/features/store/objects/components/ContentOverview.js.map +1 -1
  179. package/lib/features/store/objects/components/TextEditorPanel.d.ts.map +1 -1
  180. package/lib/features/store/objects/components/TextEditorPanel.js +8 -3
  181. package/lib/features/store/objects/components/TextEditorPanel.js.map +1 -1
  182. package/lib/features/store/objects/layout/renderers.d.ts.map +1 -1
  183. package/lib/features/store/objects/layout/renderers.js +1 -5
  184. package/lib/features/store/objects/layout/renderers.js.map +1 -1
  185. package/lib/features/store/objects/search/DocumentSearchContext.d.ts +44 -62
  186. package/lib/features/store/objects/search/DocumentSearchContext.d.ts.map +1 -1
  187. package/lib/features/store/objects/search/DocumentSearchContext.js +47 -2
  188. package/lib/features/store/objects/search/DocumentSearchContext.js.map +1 -1
  189. package/lib/features/store/objects/selection/actions/DeleteObjectsAction.d.ts.map +1 -1
  190. package/lib/features/store/objects/selection/actions/DeleteObjectsAction.js +5 -0
  191. package/lib/features/store/objects/selection/actions/DeleteObjectsAction.js.map +1 -1
  192. package/lib/features/store/objects/upload/DocumentUploadModal.d.ts +6 -1
  193. package/lib/features/store/objects/upload/DocumentUploadModal.d.ts.map +1 -1
  194. package/lib/features/store/objects/upload/DocumentUploadModal.js +4 -3
  195. package/lib/features/store/objects/upload/DocumentUploadModal.js.map +1 -1
  196. package/lib/features/store/objects/upload/useSmartFileUploadProcessing.d.ts.map +1 -1
  197. package/lib/features/store/objects/upload/useSmartFileUploadProcessing.js +2 -2
  198. package/lib/features/store/objects/upload/useSmartFileUploadProcessing.js.map +1 -1
  199. package/lib/features/store/types/ContentObjectTypesTable.d.ts.map +1 -1
  200. package/lib/features/store/types/ContentObjectTypesTable.js +1 -3
  201. package/lib/features/store/types/ContentObjectTypesTable.js.map +1 -1
  202. package/lib/features/store/types/IntakePolicyEditor.d.ts.map +1 -1
  203. package/lib/features/store/types/IntakePolicyEditor.js +12 -2
  204. package/lib/features/store/types/IntakePolicyEditor.js.map +1 -1
  205. package/lib/features/store/types/IntakePolicyForm.d.ts.map +1 -1
  206. package/lib/features/store/types/IntakePolicyForm.js +15 -15
  207. package/lib/features/store/types/IntakePolicyForm.js.map +1 -1
  208. package/lib/features/store/types/ObjectSchemaEditor.d.ts.map +1 -1
  209. package/lib/features/store/types/ObjectSchemaEditor.js +6 -2
  210. package/lib/features/store/types/ObjectSchemaEditor.js.map +1 -1
  211. package/lib/features/store/types/TableLayoutEditor.d.ts.map +1 -1
  212. package/lib/features/store/types/TableLayoutEditor.js +2 -0
  213. package/lib/features/store/types/TableLayoutEditor.js.map +1 -1
  214. package/lib/features/store/types/TypeRegistry.d.ts +282 -0
  215. package/lib/features/store/types/TypeRegistry.d.ts.map +1 -1
  216. package/lib/features/store/types/search/ObjectTypeSearchContext.d.ts +281 -0
  217. package/lib/features/store/types/search/ObjectTypeSearchContext.d.ts.map +1 -1
  218. package/lib/features/user/UserInfo.d.ts.map +1 -1
  219. package/lib/features/user/UserInfo.js +2 -4
  220. package/lib/features/user/UserInfo.js.map +1 -1
  221. package/lib/features/views/ViewActions.d.ts +32 -0
  222. package/lib/features/views/ViewActions.d.ts.map +1 -0
  223. package/lib/features/views/ViewActions.js +186 -0
  224. package/lib/features/views/ViewActions.js.map +1 -0
  225. package/lib/features/views/ViewDropTarget.d.ts +15 -0
  226. package/lib/features/views/ViewDropTarget.d.ts.map +1 -0
  227. package/lib/features/views/ViewDropTarget.js +79 -0
  228. package/lib/features/views/ViewDropTarget.js.map +1 -0
  229. package/lib/features/views/ViewExperience.d.ts +3 -2
  230. package/lib/features/views/ViewExperience.d.ts.map +1 -1
  231. package/lib/features/views/ViewExperience.js +103 -12
  232. package/lib/features/views/ViewExperience.js.map +1 -1
  233. package/lib/features/views/ViewNavigation.d.ts +1 -1
  234. package/lib/features/views/ViewNavigation.d.ts.map +1 -1
  235. package/lib/features/views/ViewNavigation.js +14 -5
  236. package/lib/features/views/ViewNavigation.js.map +1 -1
  237. package/lib/features/views/ViewResults.d.ts +1 -1
  238. package/lib/features/views/ViewResults.d.ts.map +1 -1
  239. package/lib/features/views/ViewResults.js +124 -34
  240. package/lib/features/views/ViewResults.js.map +1 -1
  241. package/lib/features/views/index.d.ts +1 -0
  242. package/lib/features/views/index.d.ts.map +1 -1
  243. package/lib/features/views/index.js +1 -0
  244. package/lib/features/views/index.js.map +1 -1
  245. package/lib/features/views/types.d.ts +46 -1
  246. package/lib/features/views/types.d.ts.map +1 -1
  247. package/lib/features/views/viewState.d.ts.map +1 -1
  248. package/lib/features/views/viewState.js +34 -0
  249. package/lib/features/views/viewState.js.map +1 -1
  250. package/lib/i18n/LanguageProvider.d.ts +3 -1
  251. package/lib/i18n/LanguageProvider.d.ts.map +1 -1
  252. package/lib/i18n/LanguageProvider.js +9 -7
  253. package/lib/i18n/LanguageProvider.js.map +1 -1
  254. package/lib/i18n/instance.d.ts +2 -0
  255. package/lib/i18n/instance.d.ts.map +1 -1
  256. package/lib/i18n/instance.js +45 -26
  257. package/lib/i18n/instance.js.map +1 -1
  258. package/lib/i18n/locales/ar.json +296 -15
  259. package/lib/i18n/locales/de.json +294 -13
  260. package/lib/i18n/locales/en.json +65 -4
  261. package/lib/i18n/locales/es.json +295 -14
  262. package/lib/i18n/locales/fr.json +294 -13
  263. package/lib/i18n/locales/it.json +294 -13
  264. package/lib/i18n/locales/ja.json +292 -10
  265. package/lib/i18n/locales/ko.json +292 -10
  266. package/lib/i18n/locales/pt.json +294 -13
  267. package/lib/i18n/locales/ru.json +291 -10
  268. package/lib/i18n/locales/tr.json +291 -10
  269. package/lib/i18n/locales/zh-TW.json +292 -10
  270. package/lib/i18n/locales/zh.json +292 -10
  271. package/lib/router/RouteComponent.d.ts +8 -0
  272. package/lib/router/RouteComponent.d.ts.map +1 -1
  273. package/lib/router/RouteComponent.js +41 -9
  274. package/lib/router/RouteComponent.js.map +1 -1
  275. package/lib/session/UserSessionProvider.d.ts.map +1 -1
  276. package/lib/session/UserSessionProvider.js +20 -29
  277. package/lib/session/UserSessionProvider.js.map +1 -1
  278. package/lib/session/auth/composable.d.ts.map +1 -1
  279. package/lib/session/auth/composable.js +25 -19
  280. package/lib/session/auth/composable.js.map +1 -1
  281. package/lib/session/auth/domainRouting.d.ts +11 -0
  282. package/lib/session/auth/domainRouting.d.ts.map +1 -1
  283. package/lib/session/auth/domainRouting.js +13 -0
  284. package/lib/session/auth/domainRouting.js.map +1 -1
  285. package/lib/session/auth/firebase.js +1 -1
  286. package/lib/session/auth/firebase.js.map +1 -1
  287. package/lib/session/useUXTracking.d.ts.map +1 -1
  288. package/lib/session/useUXTracking.js +6 -1
  289. package/lib/session/useUXTracking.js.map +1 -1
  290. package/lib/shell/VertesiaShell.d.ts.map +1 -1
  291. package/lib/shell/VertesiaShell.js +2 -1
  292. package/lib/shell/VertesiaShell.js.map +1 -1
  293. package/lib/shell/apps/AppInstallationProvider.d.ts +4 -2
  294. package/lib/shell/apps/AppInstallationProvider.d.ts.map +1 -1
  295. package/lib/shell/apps/IframeAppContextSync.d.ts +3 -0
  296. package/lib/shell/apps/IframeAppContextSync.d.ts.map +1 -0
  297. package/lib/shell/apps/IframeAppContextSync.js +95 -0
  298. package/lib/shell/apps/IframeAppContextSync.js.map +1 -0
  299. package/lib/shell/apps/iframe-auth.d.ts +55 -0
  300. package/lib/shell/apps/iframe-auth.d.ts.map +1 -0
  301. package/lib/shell/apps/iframe-auth.js +154 -0
  302. package/lib/shell/apps/iframe-auth.js.map +1 -0
  303. package/lib/shell/apps/index.d.ts +2 -0
  304. package/lib/shell/apps/index.d.ts.map +1 -1
  305. package/lib/shell/apps/index.js +2 -0
  306. package/lib/shell/apps/index.js.map +1 -1
  307. package/lib/vertesia-ui-core.js +199 -4
  308. package/lib/vertesia-ui-core.js.map +1 -1
  309. package/lib/vertesia-ui-env.js +1 -1
  310. package/lib/vertesia-ui-env.js.map +1 -1
  311. package/lib/vertesia-ui-features.js +975 -35
  312. package/lib/vertesia-ui-features.js.map +1 -1
  313. package/lib/vertesia-ui-i18n.BJBGsq-8.chunk.js +5 -0
  314. package/lib/vertesia-ui-i18n.BJBGsq-8.chunk.js.map +1 -0
  315. package/lib/vertesia-ui-i18n.BY5YG5cX.chunk.js +5 -0
  316. package/lib/vertesia-ui-i18n.BY5YG5cX.chunk.js.map +1 -0
  317. package/lib/vertesia-ui-i18n.Bd5_1BXO.chunk.js +5 -0
  318. package/lib/vertesia-ui-i18n.Bd5_1BXO.chunk.js.map +1 -0
  319. package/lib/vertesia-ui-i18n.Bvwej2HH.chunk.js +5 -0
  320. package/lib/vertesia-ui-i18n.Bvwej2HH.chunk.js.map +1 -0
  321. package/lib/vertesia-ui-i18n.CMT3f4gf.chunk.js +5 -0
  322. package/lib/vertesia-ui-i18n.CMT3f4gf.chunk.js.map +1 -0
  323. package/lib/vertesia-ui-i18n.D56DNPJW.chunk.js +5 -0
  324. package/lib/vertesia-ui-i18n.D56DNPJW.chunk.js.map +1 -0
  325. package/lib/vertesia-ui-i18n.DDzKLNx6.chunk.js +5 -0
  326. package/lib/vertesia-ui-i18n.DDzKLNx6.chunk.js.map +1 -0
  327. package/lib/vertesia-ui-i18n.D_Am1LpF.chunk.js +5 -0
  328. package/lib/vertesia-ui-i18n.D_Am1LpF.chunk.js.map +1 -0
  329. package/lib/vertesia-ui-i18n.DrZizgGV.chunk.js +5 -0
  330. package/lib/vertesia-ui-i18n.DrZizgGV.chunk.js.map +1 -0
  331. package/lib/vertesia-ui-i18n.DwHsq86z.chunk.js +5 -0
  332. package/lib/vertesia-ui-i18n.DwHsq86z.chunk.js.map +1 -0
  333. package/lib/vertesia-ui-i18n.PLpo0Bbz.chunk.js +5 -0
  334. package/lib/vertesia-ui-i18n.PLpo0Bbz.chunk.js.map +1 -0
  335. package/lib/vertesia-ui-i18n.js +2 -38
  336. package/lib/vertesia-ui-i18n.js.map +1 -1
  337. package/lib/vertesia-ui-i18n.xVbXALqz.chunk.js +5 -0
  338. package/lib/vertesia-ui-i18n.xVbXALqz.chunk.js.map +1 -0
  339. package/lib/vertesia-ui-layout.js +80 -1
  340. package/lib/vertesia-ui-layout.js.map +1 -1
  341. package/lib/vertesia-ui-rich-text.js +278 -4
  342. package/lib/vertesia-ui-rich-text.js.map +1 -1
  343. package/lib/vertesia-ui-router.js +1 -1
  344. package/lib/vertesia-ui-router.js.map +1 -1
  345. package/lib/vertesia-ui-session.js +1 -1
  346. package/lib/vertesia-ui-session.js.map +1 -1
  347. package/lib/vertesia-ui-shell.js +118 -1
  348. package/lib/vertesia-ui-shell.js.map +1 -1
  349. package/lib/vertesia-ui-widgets.js +336 -20
  350. package/lib/vertesia-ui-widgets.js.map +1 -1
  351. package/lib/widgets/markdown/MarkdownRenderer.d.ts.map +1 -1
  352. package/lib/widgets/markdown/MarkdownRenderer.js +43 -2
  353. package/lib/widgets/markdown/MarkdownRenderer.js.map +1 -1
  354. package/lib/widgets/markdown/MermaidDiagram.d.ts.map +1 -1
  355. package/lib/widgets/markdown/MermaidDiagram.js +35 -22
  356. package/lib/widgets/markdown/MermaidDiagram.js.map +1 -1
  357. package/lib/widgets/monacoEditor/MonacoEditor.d.ts.map +1 -1
  358. package/lib/widgets/monacoEditor/MonacoEditor.js +14 -10
  359. package/lib/widgets/monacoEditor/MonacoEditor.js.map +1 -1
  360. package/lib/widgets/xml-viewer/hooks/useCollapsible.d.ts +1 -1
  361. package/package.json +24 -29
  362. package/src/core/components/FormItem.tsx +2 -5
  363. package/src/core/components/InfoTip.test.tsx +33 -0
  364. package/src/core/components/InfoTip.tsx +32 -0
  365. package/src/core/components/index.ts +1 -0
  366. package/src/core/components/shadcn/Panel.tsx +3 -7
  367. package/src/core/components/shadcn/filters/comboBox/DateCombobox.tsx +1 -1
  368. package/src/core/components/shadcn/filters/filter/dateFilter.tsx +1 -1
  369. package/src/core/components/shadcn/filters/filters.tsx +1 -1
  370. package/src/core/components/shadcn/index.ts +1 -0
  371. package/src/core/components/shadcn/modal/dialog.test.tsx +35 -0
  372. package/src/core/components/shadcn/modal/dialog.tsx +0 -4
  373. package/src/core/components/shadcn/overflowTabs.tsx +320 -0
  374. package/src/core/components/shadcn/selectBox.tsx +2 -2
  375. package/src/core/components/shadcn/theme/ThemeProvider.tsx +10 -9
  376. package/src/core/utils/dayjs.ts +17 -0
  377. package/src/css/base.css +78 -0
  378. package/src/env/index.test.ts +94 -0
  379. package/src/env/index.ts +36 -1
  380. package/src/features/agent/PayloadBuilder.test.ts +68 -0
  381. package/src/features/agent/PayloadBuilder.tsx +28 -4
  382. package/src/features/agent/chat/AgentRightPanel.tsx +2 -252
  383. package/src/features/agent/chat/ArtifactsTab.tsx +1 -0
  384. package/src/features/agent/chat/AskUserWidget.test.tsx +20 -1
  385. package/src/features/agent/chat/AskUserWidget.tsx +22 -6
  386. package/src/features/agent/chat/ModernAgentConversation.test.tsx +160 -0
  387. package/src/features/agent/chat/ModernAgentConversation.tsx +111 -31
  388. package/src/features/agent/chat/ModernAgentOutput/ActiveWorkstreamsSummary.tsx +86 -67
  389. package/src/features/agent/chat/ModernAgentOutput/AllMessagesMixed.test.tsx +90 -7
  390. package/src/features/agent/chat/ModernAgentOutput/AllMessagesMixed.tsx +4 -6
  391. package/src/features/agent/chat/ModernAgentOutput/AttachmentPreview.test.ts +103 -1
  392. package/src/features/agent/chat/ModernAgentOutput/AttachmentPreview.tsx +50 -4
  393. package/src/features/agent/chat/ModernAgentOutput/BatchProgressPanel.tsx +1 -1
  394. package/src/features/agent/chat/ModernAgentOutput/Header.tsx +18 -1
  395. package/src/features/agent/chat/ModernAgentOutput/MessageItem.tsx +1 -1
  396. package/src/features/agent/chat/ModernAgentOutput/StreamingMessage.tsx +1 -1
  397. package/src/features/agent/chat/ModernAgentOutput/ToolCallGroup.tsx +1 -1
  398. package/src/features/agent/chat/ModernAgentOutput/WorkstreamTabs.tsx +37 -167
  399. package/src/features/agent/chat/ModernAgentOutput/utils.test.ts +94 -0
  400. package/src/features/agent/chat/ModernAgentOutput/utils.ts +19 -10
  401. package/src/features/agent/chat/VegaLiteChart.tsx +32 -14
  402. package/src/features/agent/chat/hooks/useAgentStream.test.tsx +18 -0
  403. package/src/features/agent/chat/hooks/useAgentStream.ts +3 -0
  404. package/src/features/document-viewer/UniversalDocumentViewer.tsx +1 -1
  405. package/src/features/facets/AgentRunnerFacetsNav.tsx +44 -4
  406. package/src/features/facets/CollectionsFacetsNav.tsx +15 -4
  407. package/src/features/facets/DocumentsFacetsNav.tsx +25 -8
  408. package/src/features/facets/FacetQueryHandlers.test.ts +84 -0
  409. package/src/features/facets/InteractionsFacetsNav.tsx +20 -4
  410. package/src/features/facets/PromptsFacetsNav.tsx +15 -4
  411. package/src/features/facets/RunsFacetsNav.test.ts +59 -0
  412. package/src/features/facets/RunsFacetsNav.tsx +40 -30
  413. package/src/features/facets/WorkflowExecutionsFacetsNav.test.ts +57 -0
  414. package/src/features/facets/WorkflowExecutionsFacetsNav.tsx +36 -16
  415. package/src/features/facets/index.ts +1 -0
  416. package/src/features/facets/utils/SearchInterface.tsx +12 -3
  417. package/src/features/layout/GenericPageNavHeader.tsx +16 -0
  418. package/src/features/magic-pdf/DownloadPopover.tsx +1 -2
  419. package/src/features/magic-pdf/GroundedExtractionView.test.tsx +7 -1
  420. package/src/features/magic-pdf/GroundedExtractionView.tsx +162 -242
  421. package/src/features/oauth/McpConnectionsButton.test.tsx +18 -1
  422. package/src/features/oauth/McpConnectionsButton.tsx +6 -2
  423. package/src/features/oauth/McpConnectionsDialog.tsx +3 -3
  424. package/src/features/oauth/useMcpConnections.test.ts +1 -0
  425. package/src/features/oauth/useMcpConnections.ts +24 -7
  426. package/src/features/pdf-viewer/PdfPageRenderer.tsx +76 -71
  427. package/src/features/pdf-viewer/lazyReactPdf.ts +33 -0
  428. package/src/features/store/collections/CollectionsTable.tsx +1 -4
  429. package/src/features/store/collections/EditCollectionView.tsx +1 -1
  430. package/src/features/store/objects/ExportPropertiesModal.tsx +25 -16
  431. package/src/features/store/objects/components/ContentOverview.tsx +2 -28
  432. package/src/features/store/objects/components/TextEditorPanel.tsx +13 -3
  433. package/src/features/store/objects/layout/renderers.tsx +1 -6
  434. package/src/features/store/objects/search/DocumentSearchContext.test.ts +45 -0
  435. package/src/features/store/objects/search/DocumentSearchContext.ts +54 -4
  436. package/src/features/store/objects/selection/actions/DeleteObjectsAction.tsx +5 -0
  437. package/src/features/store/objects/upload/DocumentUploadModal.tsx +10 -3
  438. package/src/features/store/objects/upload/useSmartFileUploadProcessing.ts +15 -6
  439. package/src/features/store/types/ContentObjectTypesTable.tsx +1 -4
  440. package/src/features/store/types/IntakePolicyEditor.tsx +14 -5
  441. package/src/features/store/types/IntakePolicyForm.tsx +120 -20
  442. package/src/features/store/types/ObjectSchemaEditor.tsx +6 -2
  443. package/src/features/store/types/TableLayoutEditor.tsx +2 -0
  444. package/src/features/user/UserInfo.test.tsx +10 -0
  445. package/src/features/user/UserInfo.tsx +2 -7
  446. package/src/features/views/ViewActions.test.tsx +80 -0
  447. package/src/features/views/ViewActions.tsx +352 -0
  448. package/src/features/views/ViewDropTarget.test.tsx +150 -0
  449. package/src/features/views/ViewDropTarget.tsx +140 -0
  450. package/src/features/views/ViewExperience.test.tsx +72 -0
  451. package/src/features/views/ViewExperience.tsx +189 -22
  452. package/src/features/views/ViewMedia.test.tsx +180 -0
  453. package/src/features/views/ViewNavigation.test.tsx +42 -0
  454. package/src/features/views/ViewNavigation.tsx +43 -5
  455. package/src/features/views/ViewResults.tsx +243 -26
  456. package/src/features/views/index.ts +1 -0
  457. package/src/features/views/types.ts +50 -0
  458. package/src/features/views/viewState.test.ts +7 -1
  459. package/src/features/views/viewState.ts +32 -0
  460. package/src/i18n/LanguageProvider.tsx +15 -8
  461. package/src/i18n/instance.test.ts +30 -0
  462. package/src/i18n/instance.ts +67 -40
  463. package/src/i18n/locales/ar.json +1192 -911
  464. package/src/i18n/locales/de.json +1148 -867
  465. package/src/i18n/locales/en.json +65 -4
  466. package/src/i18n/locales/es.json +1159 -878
  467. package/src/i18n/locales/fr.json +1159 -878
  468. package/src/i18n/locales/it.json +1159 -878
  469. package/src/i18n/locales/ja.json +1148 -866
  470. package/src/i18n/locales/ko.json +1148 -866
  471. package/src/i18n/locales/pt.json +1159 -878
  472. package/src/i18n/locales/ru.json +1170 -889
  473. package/src/i18n/locales/tr.json +1148 -867
  474. package/src/i18n/locales/zh-TW.json +1148 -866
  475. package/src/i18n/locales/zh.json +1148 -866
  476. package/src/i18n/rtl.test.ts +16 -7
  477. package/src/rich-text/VertesiaRichTextEditor.test.tsx +33 -1
  478. package/src/router/RouteComponent.test.tsx +139 -0
  479. package/src/router/RouteComponent.tsx +54 -9
  480. package/src/session/UserSessionProvider.tsx +20 -31
  481. package/src/session/auth/composable.scope.test.ts +1 -1
  482. package/src/session/auth/composable.test.ts +61 -1
  483. package/src/session/auth/composable.ts +29 -23
  484. package/src/session/auth/domainRouting.test.ts +24 -1
  485. package/src/session/auth/domainRouting.ts +29 -0
  486. package/src/session/auth/firebase.ts +1 -1
  487. package/src/session/useUXTracking.tsx +6 -1
  488. package/src/shell/VertesiaShell.tsx +2 -0
  489. package/src/shell/apps/IframeAppContextSync.test.tsx +196 -0
  490. package/src/shell/apps/IframeAppContextSync.tsx +101 -0
  491. package/src/shell/apps/iframe-auth.test.ts +118 -0
  492. package/src/shell/apps/iframe-auth.ts +193 -0
  493. package/src/shell/apps/index.ts +2 -0
  494. package/src/widgets/markdown/ArtifactEditingSurface.test.tsx +12 -3
  495. package/src/widgets/markdown/MarkdownRenderer.tsx +50 -2
  496. package/src/widgets/markdown/MermaidDiagram.tsx +38 -22
  497. package/src/widgets/monacoEditor/MonacoEditor.tsx +27 -20
  498. package/lib/features/magic-pdf/GroundedExtractionAssistantPanel.d.ts +0 -25
  499. package/lib/features/magic-pdf/GroundedExtractionAssistantPanel.d.ts.map +0 -1
  500. package/lib/features/magic-pdf/GroundedExtractionAssistantPanel.js +0 -42
  501. package/lib/features/magic-pdf/GroundedExtractionAssistantPanel.js.map +0 -1
  502. package/src/features/magic-pdf/GroundedExtractionAssistantPanel.tsx +0 -86
@@ -1,6 +1,9 @@
1
+ import { readdirSync, readFileSync } from 'node:fs';
2
+ import { dirname, join } from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
1
4
  import i18next from 'i18next';
2
5
  import { describe, expect, it } from 'vitest';
3
- import { i18nInstance, NAMESPACE } from './instance.js';
6
+ import { AVAILABLE_LOCALES, NAMESPACE } from './instance.js';
4
7
  import { isRTL, RTL_LANGUAGES, resolveLanguage, SUPPORTED_LANGUAGES } from './rtl.js';
5
8
 
6
9
  describe('isRTL', () => {
@@ -67,10 +70,10 @@ describe('RTL_LANGUAGES set', () => {
67
70
  });
68
71
 
69
72
  describe('SUPPORTED_LANGUAGES divergence guard', () => {
70
- it('matches exactly the locales registered in i18nInstance.options.resources', () => {
71
- const registered = Object.keys(i18nInstance.options.resources ?? {}).sort();
73
+ it('matches exactly the locales the i18n instance can serve', () => {
74
+ const available = [...AVAILABLE_LOCALES].sort();
72
75
  const supported = [...SUPPORTED_LANGUAGES].sort();
73
- expect(registered).toEqual(supported);
76
+ expect(available).toEqual(supported);
74
77
  });
75
78
  });
76
79
 
@@ -95,8 +98,10 @@ describe('empty translation fallback', () => {
95
98
  expect(t('test.emptyTranslationFallback')).toBe('English fallback');
96
99
  });
97
100
 
101
+ // Reads the locale files rather than `i18nInstance.options.resources`: only the `en` fallback is
102
+ // bundled there now, the rest are fetched on demand.
98
103
  it('does not ship parser-created empty locale entries', () => {
99
- const resources = i18nInstance.options.resources ?? {};
104
+ const localesDir = join(dirname(fileURLToPath(import.meta.url)), 'locales');
100
105
  const emptyEntries: string[] = [];
101
106
 
102
107
  const collectEmptyEntries = (value: unknown, path: string[]) => {
@@ -121,8 +126,12 @@ describe('empty translation fallback', () => {
121
126
  }
122
127
  };
123
128
 
124
- for (const [locale, resource] of Object.entries(resources)) {
125
- collectEmptyEntries(resource, [locale]);
129
+ const localeFiles = readdirSync(localesDir).filter((name) => name.endsWith('.json'));
130
+ expect(localeFiles.length).toBe(SUPPORTED_LANGUAGES.length);
131
+
132
+ for (const file of localeFiles) {
133
+ const resource: unknown = JSON.parse(readFileSync(join(localesDir, file), 'utf-8'));
134
+ collectEmptyEntries(resource, [file.replace(/\.json$/, '')]);
126
135
  }
127
136
 
128
137
  expect(emptyEntries).toEqual([]);
@@ -1,7 +1,12 @@
1
1
  /** @vitest-environment jsdom */
2
2
 
3
3
  import { act, fireEvent, render, screen, waitFor } from '@testing-library/react';
4
- import { MarkdownRichTextEditor, type MarkdownRichTextEditorProps, setEditorMarkdown } from '@vertesia/rich-text';
4
+ import {
5
+ DOCUMENT_EDITOR_CHANGE_DEBOUNCE_MS,
6
+ MarkdownRichTextEditor,
7
+ type MarkdownRichTextEditorProps,
8
+ setEditorMarkdown,
9
+ } from '@vertesia/rich-text';
5
10
  import { describe, expect, it, vi } from 'vitest';
6
11
  import { I18nProvider } from '../i18n/index.js';
7
12
  import {
@@ -174,6 +179,33 @@ describe('VertesiaMarkdownRichTextEditor', () => {
174
179
  expect(await screen.findByRole('heading', { name: 'Setext heading' })).not.toBeNull();
175
180
  expect(screen.getByRole('textbox', { name: 'Markdown document editor' })).not.toBeNull();
176
181
  expect(screen.queryByRole('heading', { name: 'Some Markdown formatting may change' })).toBeNull();
182
+ // The document editor debounces serialization, so wait past that window: otherwise this
183
+ // assertion passes merely because a spurious change has not been flushed yet.
184
+ await new Promise((resolve) => setTimeout(resolve, DOCUMENT_EDITOR_CHANGE_DEBOUNCE_MS * 2));
185
+ expect(onChange).not.toHaveBeenCalled();
186
+ });
187
+
188
+ it('does not report a change when the document is locked or unlocked', async () => {
189
+ const onChange = vi.fn();
190
+ const renderEditable = (editable: boolean) => (
191
+ <I18nProvider lng="en">
192
+ <VertesiaMarkdownDocumentEditor
193
+ value={'Setext heading\n=============='}
194
+ onChange={onChange}
195
+ editable={editable}
196
+ />
197
+ </I18nProvider>
198
+ );
199
+ const view = render(renderEditable(true));
200
+
201
+ expect(await screen.findByRole('heading', { name: 'Setext heading' })).not.toBeNull();
202
+ // Both directions matter: either toggle emits an editor update on its own.
203
+ view.rerender(renderEditable(false));
204
+ await new Promise((resolve) => setTimeout(resolve, DOCUMENT_EDITOR_CHANGE_DEBOUNCE_MS * 2));
205
+ expect(onChange).not.toHaveBeenCalled();
206
+
207
+ view.rerender(renderEditable(true));
208
+ await new Promise((resolve) => setTimeout(resolve, DOCUMENT_EDITOR_CHANGE_DEBOUNCE_MS * 2));
177
209
  expect(onChange).not.toHaveBeenCalled();
178
210
  });
179
211
 
@@ -0,0 +1,139 @@
1
+ import { act, cleanup, render, screen, waitFor } from '@testing-library/react';
2
+ import { afterEach, beforeEach, describe, expect, it } from 'vitest';
3
+ import { prefetchLazyRoutes, RouteComponent } from './RouteComponent';
4
+ import { type LazyRouteModule, useNavigate } from './Router';
5
+ import { RouterProvider } from './RouterProvider';
6
+
7
+ /**
8
+ * Lazy routes resolve their module asynchronously, which opens two windows for showing the wrong
9
+ * page: reusing the state of the previous lazy route while the next import is in flight, and a
10
+ * slower earlier import landing after a newer navigation already resolved. Both were real —
11
+ * RouteComponent now remounts per path and drops stale module resolutions.
12
+ */
13
+
14
+ function deferredModule(text: string) {
15
+ let resolve!: (module: LazyRouteModule) => void;
16
+ const promise = new Promise<LazyRouteModule>((r) => {
17
+ resolve = r;
18
+ });
19
+ return {
20
+ promise,
21
+ resolve: () => resolve({ default: () => <div>{text}</div> }),
22
+ };
23
+ }
24
+
25
+ let navigateFn: ReturnType<typeof useNavigate>;
26
+ function CaptureNavigate() {
27
+ navigateFn = useNavigate();
28
+ return null;
29
+ }
30
+
31
+ describe('RouteComponent lazy routes', () => {
32
+ beforeEach(() => {
33
+ window.history.pushState({}, '', '/a');
34
+ });
35
+
36
+ afterEach(() => {
37
+ cleanup();
38
+ window.history.pushState({}, '', '/');
39
+ });
40
+
41
+ it('stops showing the previous lazy route while the next one loads', async () => {
42
+ const pageA = deferredModule('Page A');
43
+ const pageB = deferredModule('Page B');
44
+ const routes = [
45
+ { path: '/a', LazyComponent: () => pageA.promise },
46
+ { path: '/b', LazyComponent: () => pageB.promise },
47
+ ];
48
+ render(
49
+ <RouterProvider routes={routes}>
50
+ <CaptureNavigate />
51
+ <RouteComponent spinner={<div>loading</div>} />
52
+ </RouterProvider>,
53
+ );
54
+ await act(async () => pageA.resolve());
55
+ await waitFor(() => expect(screen.getByText('Page A')).toBeDefined());
56
+
57
+ await act(async () => navigateFn('/b'));
58
+ // The old page must not linger while B's import is still pending.
59
+ expect(screen.queryByText('Page A')).toBeNull();
60
+ expect(screen.getByText('loading')).toBeDefined();
61
+
62
+ await act(async () => pageB.resolve());
63
+ await waitFor(() => expect(screen.getByText('Page B')).toBeDefined());
64
+ });
65
+
66
+ it('ignores a slow import that resolves after a newer navigation', async () => {
67
+ const pageA = deferredModule('Page A');
68
+ const pageB = deferredModule('Page B');
69
+ const routes = [
70
+ { path: '/a', LazyComponent: () => pageA.promise },
71
+ { path: '/b', LazyComponent: () => pageB.promise },
72
+ ];
73
+ render(
74
+ <RouterProvider routes={routes}>
75
+ <CaptureNavigate />
76
+ <RouteComponent />
77
+ </RouterProvider>,
78
+ );
79
+ // Navigate away from /a before its import resolves.
80
+ await act(async () => navigateFn('/b'));
81
+ await act(async () => pageB.resolve());
82
+ await waitFor(() => expect(screen.getByText('Page B')).toBeDefined());
83
+
84
+ // A's import resolving late must not replace the current page.
85
+ await act(async () => pageA.resolve());
86
+ expect(screen.queryByText('Page A')).toBeNull();
87
+ expect(screen.getByText('Page B')).toBeDefined();
88
+ });
89
+
90
+ it('renders a previously resolved lazy route synchronously on revisit', async () => {
91
+ const pageA = deferredModule('Page A');
92
+ const pageB = deferredModule('Page B');
93
+ const routes = [
94
+ { path: '/a', LazyComponent: () => pageA.promise },
95
+ { path: '/b', LazyComponent: () => pageB.promise },
96
+ ];
97
+ render(
98
+ <RouterProvider routes={routes}>
99
+ <CaptureNavigate />
100
+ <RouteComponent spinner={<div>loading</div>} />
101
+ </RouterProvider>,
102
+ );
103
+ await act(async () => pageA.resolve());
104
+ await waitFor(() => expect(screen.getByText('Page A')).toBeDefined());
105
+ await act(async () => navigateFn('/b'));
106
+ await act(async () => pageB.resolve());
107
+ await waitFor(() => expect(screen.getByText('Page B')).toBeDefined());
108
+
109
+ // Back to /a: its module is cached, so not even one spinner frame may show.
110
+ act(() => navigateFn('/a'));
111
+ expect(screen.getByText('Page A')).toBeDefined();
112
+ expect(screen.queryByText('loading')).toBeNull();
113
+ });
114
+
115
+ it('prefetched lazy routes render without a spinner on first navigation', async () => {
116
+ const pageA = deferredModule('Page A');
117
+ const pageB = deferredModule('Page B');
118
+ const routes = [
119
+ { path: '/a', LazyComponent: () => pageA.promise },
120
+ { path: '/b', LazyComponent: () => pageB.promise },
121
+ { path: '/c', Component: () => <div>Page C</div> },
122
+ ];
123
+ pageA.resolve();
124
+ pageB.resolve();
125
+ await prefetchLazyRoutes(routes);
126
+
127
+ render(
128
+ <RouterProvider routes={routes}>
129
+ <CaptureNavigate />
130
+ <RouteComponent spinner={<div>loading</div>} />
131
+ </RouterProvider>,
132
+ );
133
+ // Even the initial mount renders from the prefetch cache.
134
+ expect(screen.getByText('Page A')).toBeDefined();
135
+ act(() => navigateFn('/b'));
136
+ expect(screen.getByText('Page B')).toBeDefined();
137
+ expect(screen.queryByText('loading')).toBeNull();
138
+ });
139
+ });
@@ -1,5 +1,41 @@
1
1
  import { useEffect, useState } from 'react';
2
- import { type ComponentRoute, type LazyComponentRoute, type LazyRouteModule, useRouterContext } from './Router';
2
+ import {
3
+ type ComponentRoute,
4
+ type LazyComponentRoute,
5
+ type LazyRouteModule,
6
+ type Route,
7
+ useRouterContext,
8
+ } from './Router';
9
+
10
+ // Resolved lazy modules, keyed by the route's LazyComponent function (a stable identity: route
11
+ // tables are declared once). A revisited lazy route renders synchronously from this cache instead
12
+ // of unmounting to the spinner for the async import() round-trip — without it, every navigation
13
+ // between two lazy routes blanks the page for at least a frame, even when the module is loaded.
14
+ const resolvedComponents = new Map<LazyComponentRoute['LazyComponent'], LazyRouteModule['default']>();
15
+
16
+ function resolveLazyRoute(route: LazyComponentRoute): Promise<LazyRouteModule['default']> {
17
+ return route.LazyComponent().then((module) => {
18
+ if (!module.default) {
19
+ throw new Error(`Lazy module for ${route.path} does not have a default export`);
20
+ }
21
+ resolvedComponents.set(route.LazyComponent, module.default);
22
+ return module.default;
23
+ });
24
+ }
25
+
26
+ /**
27
+ * Start loading the given routes' lazy modules ahead of navigation (non-lazy routes are ignored).
28
+ * Call it during idle time after first paint: the first navigation to a prefetched route then
29
+ * renders synchronously instead of flashing the spinner while its chunk downloads. Failures are
30
+ * swallowed — navigation retries the import and reports the error the normal way.
31
+ */
32
+ export function prefetchLazyRoutes(routes: Route[]): Promise<unknown> {
33
+ return Promise.allSettled(
34
+ routes
35
+ .filter((route): route is LazyComponentRoute => !!(route as LazyComponentRoute).LazyComponent)
36
+ .map((route) => resolveLazyRoute(route)),
37
+ );
38
+ }
3
39
 
4
40
  interface RouteComponentProps {
5
41
  spinner?: React.ReactNode;
@@ -12,7 +48,9 @@ export function RouteComponent({ spinner }: RouteComponentProps) {
12
48
  const Component = (route as ComponentRoute).Component;
13
49
  return <Component {...ctx.params} />;
14
50
  } else if ((route as LazyComponentRoute).LazyComponent) {
15
- return <LazyRouteComponent route={route as LazyComponentRoute} spinner={spinner} />;
51
+ // Keyed per path so navigating between two lazy routes remounts: a reused instance would
52
+ // keep rendering the previous route's component while the next import resolves.
53
+ return <LazyRouteComponent key={route.path} route={route as LazyComponentRoute} spinner={spinner} />;
16
54
  } else {
17
55
  throw new Error(`Invalid route for ${route.path}. Either Component or LazyCOmponent must be specified.`);
18
56
  }
@@ -23,16 +61,23 @@ interface LazyRouteComponentProps {
23
61
  spinner?: React.ReactNode;
24
62
  }
25
63
  function LazyRouteComponent({ route, spinner }: LazyRouteComponentProps) {
26
- const [Component, setComponent] = useState<LazyRouteModule['default'] | null>(null);
64
+ const [Component, setComponent] = useState<LazyRouteModule['default'] | null>(
65
+ () => resolvedComponents.get(route.LazyComponent) ?? null,
66
+ );
27
67
  useEffect(() => {
28
- void route.LazyComponent().then((module) => {
29
- if (!module.default) {
30
- throw new Error(`Lazy module for ${route.path} does not have a default export`);
68
+ // A slow import must not land after this instance moved on (unmount, or a route object
69
+ // swap without a path change): the stale module would overwrite the current one.
70
+ let stale = false;
71
+ void resolveLazyRoute(route).then((component) => {
72
+ if (!stale) {
73
+ // we need to wrap the component type in an arrow function
74
+ // otherwise the setState function will execute the function as a state update function
75
+ setComponent(() => component);
31
76
  }
32
- // we need to wrap the component type in an arrow function
33
- // otherwise the setState function will execute the function as a state update function
34
- setComponent(() => module.default);
35
77
  });
78
+ return () => {
79
+ stale = true;
80
+ };
36
81
  }, [route]);
37
82
 
38
83
  return Component ? <Component /> : spinner || null;
@@ -12,7 +12,7 @@ import {
12
12
  resolveAuthSelection,
13
13
  UserNotFoundError,
14
14
  } from './auth/composable';
15
- import { authReturnUrl, shouldRedirectToCentralAuth } from './auth/domainRouting';
15
+ import { authReturnUrl, centralAuthRedirectUrl, shouldRedirectToCentralAuth } from './auth/domainRouting';
16
16
  import { getFirebaseAuth } from './auth/firebase';
17
17
  import { useAuthState } from './auth/useAuthState';
18
18
  import { UserSession, UserSessionContext } from './UserSession';
@@ -110,31 +110,29 @@ export function UserSessionProvider({ children, loadOnboardingStatus = true }: U
110
110
  return true;
111
111
  };
112
112
 
113
- const redirectToCentralAuth = (projectId?: string, accountId?: string) => {
114
- const url = new URL(`${CENTRAL_AUTH_REDIRECT}?sts=${Env.endpoints.sts ?? 'https://sts.vertesia.io'}`);
115
- const currentUrl = authReturnUrl();
116
- if (projectId) currentUrl.searchParams.set('p', projectId);
117
- if (accountId) currentUrl.searchParams.set('a', accountId);
118
- url.searchParams.set('redirect_uri', currentUrl.toString());
119
- url.searchParams.set('state', generateState());
113
+ const redirectToCentralAuth = (selection: { accountId?: string; projectId?: string }) => {
114
+ const url = centralAuthRedirectUrl({
115
+ centralAuthUrl: CENTRAL_AUTH_REDIRECT,
116
+ stsEndpoint: Env.endpoints.sts ?? 'https://sts.vertesia.io',
117
+ returnUrl: authReturnUrl(),
118
+ state: generateState(),
119
+ ...selection,
120
+ });
120
121
  location.replace(url.toString());
121
122
  };
122
123
 
123
124
  authFlowRef.current = () => {
124
125
  // Make this effect idempotent - only run auth flow once
125
126
  if (hasInitiatedAuthRef.current) {
126
- console.log('Auth: skipping duplicate auth flow initiation');
127
+ Env.logger.debug('Skipping duplicate auth flow initiation');
127
128
  return;
128
129
  }
129
130
  hasInitiatedAuthRef.current = true;
130
131
 
131
- console.log('Auth: starting auth flow');
132
- Env.logger.info('Starting auth flow');
132
+ Env.logger.debug('Starting auth flow');
133
133
  const currentUrl = new URL(window.location.href);
134
134
  const { accountId: selectedAccount, projectId: selectedProject } = resolveAuthSelection(currentUrl);
135
- console.log('Auth: selected account', selectedAccount);
136
- console.log('Auth: selected project', selectedProject);
137
- Env.logger.info('Selected account and project', {
135
+ Env.logger.debug('Selected account and project', {
138
136
  vertesia: {
139
137
  account_id: selectedAccount,
140
138
  project_id: selectedProject,
@@ -174,7 +172,7 @@ export function UserSessionProvider({ children, loadOnboardingStatus = true }: U
174
172
  state: state,
175
173
  },
176
174
  });
177
- redirectToCentralAuth();
175
+ redirectToCentralAuth({ accountId: selectedAccount, projectId: selectedProject });
178
176
  } else {
179
177
  clearState();
180
178
  }
@@ -194,7 +192,7 @@ export function UserSessionProvider({ children, loadOnboardingStatus = true }: U
194
192
  error: err,
195
193
  },
196
194
  });
197
- redirectToCentralAuth();
195
+ redirectToCentralAuth({ accountId: selectedAccount, projectId: selectedProject });
198
196
  });
199
197
  return;
200
198
  }
@@ -207,31 +205,24 @@ export function UserSessionProvider({ children, loadOnboardingStatus = true }: U
207
205
 
208
206
  // If the current host is not in the Firebase allowlist, central auth owns sign-in.
209
207
  if (!session.isLoggedIn()) {
210
- console.log('Auth: not logged in & no token/state');
211
- Env.logger.info('Not logged in & no token/state', {
208
+ Env.logger.debug('Not logged in & no token/state', {
212
209
  vertesia: {
213
210
  account_id: selectedAccount,
214
211
  project_id: selectedProject,
215
212
  },
216
213
  });
217
214
  if (shouldRedirectToCentralAuth()) {
218
- console.log(
219
- 'Auth: host is not in Firebase auth allowlist, redirecting to central auth with selection',
220
- selectedAccount,
221
- selectedProject,
222
- );
223
- Env.logger.info('Redirecting to central auth with selection', {
215
+ Env.logger.debug('Redirecting to central auth with selection', {
224
216
  vertesia: {
225
217
  account_id: selectedAccount,
226
218
  project_id: selectedProject,
227
219
  },
228
220
  });
229
- redirectToCentralAuth();
221
+ redirectToCentralAuth({ accountId: selectedAccount, projectId: selectedProject });
230
222
  return; // Don't register onAuthStateChanged listener when redirecting
231
223
  }
232
224
 
233
- console.log('Auth: host is in Firebase auth allowlist');
234
- Env.logger.info('Host is in Firebase auth allowlist', {
225
+ Env.logger.debug('Host is in Firebase auth allowlist', {
235
226
  vertesia: {
236
227
  account_id: selectedAccount,
237
228
  project_id: selectedProject,
@@ -241,8 +232,7 @@ export function UserSessionProvider({ children, loadOnboardingStatus = true }: U
241
232
 
242
233
  unsubscribe = onAuthStateChanged(getFirebaseAuth(), async (firebaseUser) => {
243
234
  if (firebaseUser) {
244
- console.log('Auth: successful login with firebase');
245
- Env.logger.info('Successful login with firebase', {
235
+ Env.logger.debug('Successful login with firebase', {
246
236
  vertesia: {
247
237
  account_id: selectedAccount,
248
238
  project_id: selectedProject,
@@ -274,8 +264,7 @@ export function UserSessionProvider({ children, loadOnboardingStatus = true }: U
274
264
  });
275
265
  } else {
276
266
  // anonymous user
277
- console.log('Auth: using anonymous user');
278
- Env.logger.info('Using anonymous user', {
267
+ Env.logger.debug('Using anonymous user', {
279
268
  vertesia: {
280
269
  account_id: selectedAccount,
281
270
  project_id: selectedProject,
@@ -1,7 +1,7 @@
1
1
  // @vitest-environment jsdom
2
2
  import { beforeEach, describe, expect, it, vi } from 'vitest';
3
3
 
4
- const logger = { info: vi.fn(), warn: vi.fn(), error: vi.fn() };
4
+ const logger = { debug: vi.fn(), info: vi.fn(), warn: vi.fn(), error: vi.fn() };
5
5
 
6
6
  vi.mock('@vertesia/ui/env', () => ({
7
7
  Env: {
@@ -5,7 +5,7 @@ function makeJwt(payload: Record<string, unknown>) {
5
5
  return `${encode({ alg: 'ES256', typ: 'JWT' })}.${encode(payload)}.signature`;
6
6
  }
7
7
 
8
- async function importComposableAuth() {
8
+ async function importComposableAuth(authTokenProvider?: () => Promise<string | undefined>) {
9
9
  vi.resetModules();
10
10
  const [{ Env }, composableAuth] = await Promise.all([import('@vertesia/ui/env'), import('./composable')]);
11
11
  Env.init({
@@ -19,6 +19,7 @@ async function importComposableAuth() {
19
19
  zeno: 'https://zeno-server-dev-feat-appgen.api.dev1.vertesia.io',
20
20
  sts: 'https://sts.dev1.vertesia.io',
21
21
  },
22
+ authTokenProvider,
22
23
  });
23
24
  return composableAuth;
24
25
  }
@@ -53,6 +54,65 @@ describe('getComposableToken', () => {
53
54
  expect(fetchMock).not.toHaveBeenCalled();
54
55
  });
55
56
 
57
+ it('reacquires a fresh injected token instead of reusing an expired cached credential', async () => {
58
+ const expiredToken = makeJwt({
59
+ iss: 'https://sts.dev1.vertesia.io',
60
+ exp: Math.floor(Date.now() / 1000) - 60,
61
+ account: { id: 'account-id', name: 'Account' },
62
+ project: { id: 'project-id', name: 'Project', account: 'account-id' },
63
+ project_roles: ['developer'],
64
+ });
65
+ const freshToken = makeJwt({
66
+ iss: 'https://sts.dev1.vertesia.io',
67
+ exp: Math.floor(Date.now() / 1000) + 3600,
68
+ account: { id: 'account-id', name: 'Account' },
69
+ project: { id: 'project-id', name: 'Project', account: 'account-id' },
70
+ project_roles: ['developer'],
71
+ });
72
+ const authTokenProvider = vi.fn(() => Promise.resolve(freshToken));
73
+ const fetchMock = vi.fn();
74
+ vi.stubGlobal('fetch', fetchMock);
75
+
76
+ const { getComposableToken } = await importComposableAuth(authTokenProvider);
77
+ const result = await getComposableToken('account-id', 'project-id', expiredToken, false, true);
78
+
79
+ expect(result.rawToken).toBe(freshToken);
80
+ expect(authTokenProvider).toHaveBeenCalledOnce();
81
+ expect(fetchMock).not.toHaveBeenCalled();
82
+ });
83
+
84
+ it('falls back to the cached credential when the injected provider is unavailable', async () => {
85
+ const expiringToken = makeJwt({
86
+ iss: 'https://sts.dev1.vertesia.io',
87
+ exp: Math.floor(Date.now() / 1000) + 60,
88
+ account: { id: 'account-id', name: 'Account' },
89
+ project: { id: 'project-id', name: 'Project', account: 'account-id' },
90
+ project_roles: ['developer'],
91
+ });
92
+ const refreshedToken = makeJwt({
93
+ iss: 'https://sts.dev1.vertesia.io',
94
+ exp: Math.floor(Date.now() / 1000) + 3600,
95
+ account: { id: 'account-id', name: 'Account' },
96
+ project: { id: 'project-id', name: 'Project', account: 'account-id' },
97
+ project_roles: ['developer'],
98
+ });
99
+ const authTokenProvider = vi.fn(() => Promise.resolve(undefined));
100
+ const fetchMock = vi.fn().mockResolvedValue({
101
+ ok: true,
102
+ status: 200,
103
+ json: () => Promise.resolve({ token: refreshedToken }),
104
+ });
105
+ vi.stubGlobal('fetch', fetchMock);
106
+
107
+ const { getComposableToken } = await importComposableAuth(authTokenProvider);
108
+ const result = await getComposableToken('account-id', 'project-id', expiringToken, false, true);
109
+
110
+ expect(result.rawToken).toBe(refreshedToken);
111
+ expect(authTokenProvider).toHaveBeenCalledOnce();
112
+ expect(fetchMock).toHaveBeenCalledOnce();
113
+ expect(fetchMock.mock.calls[0]?.[1]?.headers).toMatchObject({ Authorization: `Bearer ${expiringToken}` });
114
+ });
115
+
56
116
  it('exchanges a bare STS-issued Vertesia token so roles can be hydrated', async () => {
57
117
  const sourceToken = makeJwt({
58
118
  iss: 'https://sts.dev1.vertesia.io',