@antelopejs/dms 0.8.3 → 0.9.1

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 (424) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/data/module-store/catalog.json +71 -0
  3. package/dist/config.d.ts +7 -0
  4. package/dist/config.js +8 -0
  5. package/dist/config.js.map +1 -1
  6. package/dist/implementations/dms/frontend-backend-proxies.d.ts +3 -0
  7. package/dist/implementations/dms/frontend-backend-proxies.js +39 -0
  8. package/dist/implementations/dms/frontend-backend-proxies.js.map +1 -0
  9. package/dist/implementations/dms/frontend-bootstrap.d.ts +1 -0
  10. package/dist/implementations/dms/frontend-bootstrap.js +13 -0
  11. package/dist/implementations/dms/frontend-bootstrap.js.map +1 -1
  12. package/dist/implementations/dms/frontend-modules.d.ts +6 -2
  13. package/dist/implementations/dms/frontend-modules.js +37 -8
  14. package/dist/implementations/dms/frontend-modules.js.map +1 -1
  15. package/dist/implementations/dms/frontend-ready.d.ts +8 -0
  16. package/dist/implementations/dms/frontend-ready.js +34 -0
  17. package/dist/implementations/dms/frontend-ready.js.map +1 -0
  18. package/dist/implementations/dms/manifest.d.ts +7 -0
  19. package/dist/implementations/dms/manifest.js +13 -0
  20. package/dist/implementations/dms/manifest.js.map +1 -1
  21. package/dist/implementations/dms/menu-categories.d.ts +16 -0
  22. package/dist/implementations/dms/menu-categories.js +30 -0
  23. package/dist/implementations/dms/menu-categories.js.map +1 -0
  24. package/dist/implementations/dms/nav-badges.d.ts +0 -8
  25. package/dist/implementations/dms/nav-badges.js +0 -16
  26. package/dist/implementations/dms/nav-badges.js.map +1 -1
  27. package/dist/implementations/dms/page.d.ts +13 -5
  28. package/dist/implementations/dms/page.js +72 -41
  29. package/dist/implementations/dms/page.js.map +1 -1
  30. package/dist/implementations/dms-html-render/index.js +5 -2
  31. package/dist/implementations/dms-html-render/index.js.map +1 -1
  32. package/dist/implementations/dms-notifications/index.d.ts +4 -3
  33. package/dist/implementations/dms-notifications/index.js +14 -6
  34. package/dist/implementations/dms-notifications/index.js.map +1 -1
  35. package/dist/pages/settings/settings-index.js +3 -2
  36. package/dist/pages/settings/settings-index.js.map +1 -1
  37. package/dist/pages/settings/users/invites.js +2 -2
  38. package/dist/pages/settings/users/invites.js.map +1 -1
  39. package/dist/pages/settings/users/member-change-notifications.js +17 -6
  40. package/dist/pages/settings/users/member-change-notifications.js.map +1 -1
  41. package/dist/pages/settings/users/member-invite-form.d.ts +3 -2
  42. package/dist/pages/settings/users/member-invite-form.js +7 -4
  43. package/dist/pages/settings/users/member-invite-form.js.map +1 -1
  44. package/dist/pages/settings/users/member-roles-field.js +2 -1
  45. package/dist/pages/settings/users/member-roles-field.js.map +1 -1
  46. package/dist/pages/settings/users/members.js +4 -1
  47. package/dist/pages/settings/users/members.js.map +1 -1
  48. package/dist/pages/settings/users/notifications.d.ts +6 -0
  49. package/dist/pages/settings/users/notifications.js +23 -15
  50. package/dist/pages/settings/users/notifications.js.map +1 -1
  51. package/dist/pages/settings/users/profile.js +1 -1
  52. package/dist/pages/settings/users/profile.js.map +1 -1
  53. package/dist/pages/settings/users/region-form.d.ts +1 -1
  54. package/dist/pages/settings/users/region-form.js +2 -1
  55. package/dist/pages/settings/users/region-form.js.map +1 -1
  56. package/dist/pages/settings/users/role-editor-store.d.ts +3 -1
  57. package/dist/pages/settings/users/role-editor-store.js +17 -4
  58. package/dist/pages/settings/users/role-editor-store.js.map +1 -1
  59. package/dist/pages/settings/users/roles.js +1 -0
  60. package/dist/pages/settings/users/roles.js.map +1 -1
  61. package/dist/realtime/registry.d.ts +1 -0
  62. package/dist/realtime/registry.js +5 -0
  63. package/dist/realtime/registry.js.map +1 -1
  64. package/dist/routes/index.d.ts +1 -0
  65. package/dist/routes/index.js +1 -0
  66. package/dist/routes/index.js.map +1 -1
  67. package/dist/routes/realtime.d.ts +5 -1
  68. package/dist/routes/realtime.js +16 -9
  69. package/dist/routes/realtime.js.map +1 -1
  70. package/dist/routes/store.d.ts +21 -0
  71. package/dist/routes/store.js +130 -0
  72. package/dist/routes/store.js.map +1 -0
  73. package/dist/store/activity.d.ts +2 -0
  74. package/dist/store/activity.js +12 -0
  75. package/dist/store/activity.js.map +1 -0
  76. package/dist/store/cache.d.ts +8 -0
  77. package/dist/store/cache.js +29 -0
  78. package/dist/store/cache.js.map +1 -0
  79. package/dist/store/catalog.d.ts +4 -0
  80. package/dist/store/catalog.js +69 -0
  81. package/dist/store/catalog.js.map +1 -0
  82. package/dist/store/compatibility.d.ts +3 -0
  83. package/dist/store/compatibility.js +45 -0
  84. package/dist/store/compatibility.js.map +1 -0
  85. package/dist/store/declarations.d.ts +18 -0
  86. package/dist/store/declarations.js +116 -0
  87. package/dist/store/declarations.js.map +1 -0
  88. package/dist/store/frontend-compatibility.d.ts +18 -0
  89. package/dist/store/frontend-compatibility.js +93 -0
  90. package/dist/store/frontend-compatibility.js.map +1 -0
  91. package/dist/store/interfaces.d.ts +6 -0
  92. package/dist/store/interfaces.js +126 -0
  93. package/dist/store/interfaces.js.map +1 -0
  94. package/dist/store/listing.d.ts +2 -0
  95. package/dist/store/listing.js +180 -0
  96. package/dist/store/listing.js.map +1 -0
  97. package/dist/store/operations.d.ts +8 -0
  98. package/dist/store/operations.js +254 -0
  99. package/dist/store/operations.js.map +1 -0
  100. package/dist/store/registry.d.ts +4 -0
  101. package/dist/store/registry.js +61 -0
  102. package/dist/store/registry.js.map +1 -0
  103. package/dist/store/requirements.d.ts +14 -0
  104. package/dist/store/requirements.js +81 -0
  105. package/dist/store/requirements.js.map +1 -0
  106. package/dist/store/runtime.d.ts +11 -0
  107. package/dist/store/runtime.js +78 -0
  108. package/dist/store/runtime.js.map +1 -0
  109. package/dist/store/tarball.d.ts +2 -0
  110. package/dist/store/tarball.js +80 -0
  111. package/dist/store/tarball.js.map +1 -0
  112. package/dist/store/types.d.ts +98 -0
  113. package/dist/store/types.js +3 -0
  114. package/dist/store/types.js.map +1 -0
  115. package/dist/test/integration/account-deletion.test.js +2 -2
  116. package/dist/test/integration/account-deletion.test.js.map +1 -1
  117. package/dist/test/integration/auth/auth-key-rotation.test.js +2 -1
  118. package/dist/test/integration/auth/auth-key-rotation.test.js.map +1 -1
  119. package/dist/test/integration/auth/current-password.test.js +2 -1
  120. package/dist/test/integration/auth/current-password.test.js.map +1 -1
  121. package/dist/test/integration/auth/session-revocation.test.js +2 -1
  122. package/dist/test/integration/auth/session-revocation.test.js.map +1 -1
  123. package/dist/test/integration/auth/sign-in-country.test.js +2 -1
  124. package/dist/test/integration/auth/sign-in-country.test.js.map +1 -1
  125. package/dist/test/integration/auth/two-factor-codes.test.js +2 -1
  126. package/dist/test/integration/auth/two-factor-codes.test.js.map +1 -1
  127. package/dist/test/integration/auth/two-factor-password.test.js +3 -2
  128. package/dist/test/integration/auth/two-factor-password.test.js.map +1 -1
  129. package/dist/test/integration/email-change.test.js +2 -1
  130. package/dist/test/integration/email-change.test.js.map +1 -1
  131. package/dist/test/integration/files/component-files.test.js +2 -2
  132. package/dist/test/integration/files/component-files.test.js.map +1 -1
  133. package/dist/test/integration/member-settings-access.test.js +8 -7
  134. package/dist/test/integration/member-settings-access.test.js.map +1 -1
  135. package/dist/test/integration/menu-access-events.test.d.ts +1 -0
  136. package/dist/test/integration/menu-access-events.test.js +148 -0
  137. package/dist/test/integration/menu-access-events.test.js.map +1 -0
  138. package/dist/test/integration/notification-inbox.test.js +4 -1
  139. package/dist/test/integration/notification-inbox.test.js.map +1 -1
  140. package/dist/test/integration/notification-locked-subjects.test.js +3 -2
  141. package/dist/test/integration/notification-locked-subjects.test.js.map +1 -1
  142. package/dist/test/integration/notification-unread-badge.test.js +51 -5
  143. package/dist/test/integration/notification-unread-badge.test.js.map +1 -1
  144. package/dist/test/integration/page-layout-route-guard.test.d.ts +1 -0
  145. package/dist/test/integration/page-layout-route-guard.test.js +56 -0
  146. package/dist/test/integration/page-layout-route-guard.test.js.map +1 -0
  147. package/dist/test/integration/permission-warnings.test.js +3 -2
  148. package/dist/test/integration/permission-warnings.test.js.map +1 -1
  149. package/dist/test/integration/removed-member-notifications.test.js +3 -2
  150. package/dist/test/integration/removed-member-notifications.test.js.map +1 -1
  151. package/dist/test/integration/role-delete-reassign.test.js +2 -1
  152. package/dist/test/integration/role-delete-reassign.test.js.map +1 -1
  153. package/dist/test/integration/role-permission-ancestors.test.js +2 -1
  154. package/dist/test/integration/role-permission-ancestors.test.js.map +1 -1
  155. package/dist/test/unit/frontend-bootstrap.test.js +13 -0
  156. package/dist/test/unit/frontend-bootstrap.test.js.map +1 -1
  157. package/dist/test/unit/implementations/dms/category-slug-registry.test.js +14 -5
  158. package/dist/test/unit/implementations/dms/category-slug-registry.test.js.map +1 -1
  159. package/dist/test/unit/implementations/dms/frontend-backend-proxies.test.d.ts +1 -0
  160. package/dist/test/unit/implementations/dms/frontend-backend-proxies.test.js +66 -0
  161. package/dist/test/unit/implementations/dms/frontend-backend-proxies.test.js.map +1 -0
  162. package/dist/test/unit/implementations/dms/manifest-strip.test.js +26 -0
  163. package/dist/test/unit/implementations/dms/manifest-strip.test.js.map +1 -1
  164. package/dist/test/unit/implementations/dms/nav-badges.test.js +23 -9
  165. package/dist/test/unit/implementations/dms/nav-badges.test.js.map +1 -1
  166. package/dist/test/unit/implementations/dms-html-render/generate-html.test.js +22 -4
  167. package/dist/test/unit/implementations/dms-html-render/generate-html.test.js.map +1 -1
  168. package/dist/test/unit/interfaces/dms/page-layout-query.test.js +12 -0
  169. package/dist/test/unit/interfaces/dms/page-layout-query.test.js.map +1 -1
  170. package/dist/test/unit/interfaces/dms/page-teardown.test.js +1 -1
  171. package/dist/test/unit/interfaces/dms/page-teardown.test.js.map +1 -1
  172. package/dist/test/unit/pages/settings/member-roles-field.test.js +1 -1
  173. package/dist/test/unit/pages/settings/member-roles-field.test.js.map +1 -1
  174. package/dist/test/unit/pages/settings/role-delete-confirm.test.js.map +1 -1
  175. package/dist/test/unit/realtime/menu-topics.test.d.ts +1 -0
  176. package/dist/test/unit/realtime/menu-topics.test.js +26 -0
  177. package/dist/test/unit/realtime/menu-topics.test.js.map +1 -0
  178. package/dist/test/unit/store/store.test.d.ts +1 -0
  179. package/dist/test/unit/store/store.test.js +127 -0
  180. package/dist/test/unit/store/store.test.js.map +1 -0
  181. package/dist/validation/store.schema.d.ts +39 -0
  182. package/dist/validation/store.schema.js +27 -0
  183. package/dist/validation/store.schema.js.map +1 -0
  184. package/frontend-vue/deferred-plugins.ts +3 -4
  185. package/frontend-vue/dms.email.ts +5 -1
  186. package/frontend-vue/dms.frontend.ts +15 -5
  187. package/frontend-vue/dms.server.ts +74 -0
  188. package/frontend-vue/layers/dms-auth/app/composables/useLogout.ts +1 -1
  189. package/frontend-vue/layers/dms-auth/app/composables/usePostLoginRedirect.ts +16 -3
  190. package/frontend-vue/layers/dms-auth/app/custom-pages/auth/2fa.vue +3 -1
  191. package/frontend-vue/layers/dms-auth/app/custom-pages/auth/backup.vue +3 -1
  192. package/frontend-vue/layers/dms-auth/app/custom-pages/auth/forgot-validation.vue +1 -1
  193. package/frontend-vue/layers/dms-auth/app/custom-pages/auth/oauth-complete.vue +26 -3
  194. package/frontend-vue/layers/dms-auth/app/custom-pages/auth/recover.vue +1 -1
  195. package/frontend-vue/layers/dms-auth/app/custom-pages/auth/signup.vue +22 -25
  196. package/frontend-vue/layers/dms-auth/app/custom-pages/auth/validate.vue +1 -1
  197. package/frontend-vue/layers/dms-auth/app/middleware/auth.ts +5 -7
  198. package/frontend-vue/layers/dms-auth/app/plugins/permissions-preload.ts +17 -0
  199. package/frontend-vue/layers/dms-auth/server/accounts.ts +135 -0
  200. package/frontend-vue/layers/dms-auth/server/actions.ts +251 -0
  201. package/frontend-vue/layers/dms-auth/server/oauth.ts +260 -0
  202. package/frontend-vue/layers/dms-auth/server/session.ts +158 -0
  203. package/frontend-vue/layers/dms-core/app/build/utils/asyncDataScope.ts +47 -0
  204. package/frontend-vue/layers/dms-core/app/build/utils/permission-preview.ts +6 -2
  205. package/frontend-vue/layers/dms-core/app/composables/auth/useApiData.ts +148 -0
  206. package/frontend-vue/layers/dms-core/app/composables/auth/useAuthFetch.ts +7 -20
  207. package/frontend-vue/layers/dms-core/app/composables/auth/useCurrentUser.ts +2 -2
  208. package/frontend-vue/layers/dms-core/app/composables/auth/useMultiAccount.ts +18 -5
  209. package/frontend-vue/layers/dms-core/app/composables/auth/usePermissions.ts +35 -6
  210. package/frontend-vue/layers/dms-core/app/composables/auth/useSessionRecovery.ts +1 -1
  211. package/frontend-vue/layers/dms-core/app/composables/period/compareResolvers.ts +20 -14
  212. package/frontend-vue/layers/dms-core/app/composables/period/periodClock.ts +121 -0
  213. package/frontend-vue/layers/dms-core/app/composables/period/periodRenderNow.ts +42 -0
  214. package/frontend-vue/layers/dms-core/app/composables/period/periodTimeZone.ts +31 -0
  215. package/frontend-vue/layers/dms-core/app/composables/period/presetResolvers.ts +48 -19
  216. package/frontend-vue/layers/dms-core/app/composables/period/usePeriod.ts +33 -4
  217. package/frontend-vue/layers/dms-core/app/composables/period/usePeriodScope.ts +78 -25
  218. package/frontend-vue/layers/dms-core/app/composables/realtime/usePageRealtime.ts +3 -0
  219. package/frontend-vue/layers/dms-core/app/composables/realtime/useUserRealtime.ts +36 -6
  220. package/frontend-vue/layers/dms-core/app/composables/user/useUserRegionalPreferences.ts +1 -1
  221. package/frontend-vue/layers/dms-core/app/plugins/async-data-scope.ts +26 -0
  222. package/frontend-vue/layers/dms-core/app/utils/pageRoutes.ts +22 -0
  223. package/frontend-vue/layers/dms-core/app/utils/regional.ts +36 -3
  224. package/frontend-vue/layers/dms-core/app/utils/trailingDeduper.ts +10 -1
  225. package/frontend-vue/layers/dms-core/shared/types/app-config.ts +48 -4
  226. package/frontend-vue/layers/dms-layout/app/app.config.ts +42 -23
  227. package/frontend-vue/layers/dms-layout/app/assets/css/main.css +72 -20
  228. package/frontend-vue/layers/dms-layout/app/build/components/layout/DashboardFrame.vue +9 -0
  229. package/frontend-vue/layers/dms-layout/app/build/components/layout/DashboardSidebar.vue +0 -3
  230. package/frontend-vue/layers/dms-layout/app/build/components/notification/NotificationPopover.vue +9 -3
  231. package/frontend-vue/layers/dms-layout/app/build/components/pages/modules/ModuleStoreDependencyPicker.vue +136 -0
  232. package/frontend-vue/layers/dms-layout/app/build/components/pages/modules/ModuleStoreRequirements.vue +98 -0
  233. package/frontend-vue/layers/dms-layout/app/build/components/pages/modules/ModuleStoreTile.vue +247 -29
  234. package/frontend-vue/layers/dms-layout/app/build/components/pages/modules/ModuleTile.vue +19 -2
  235. package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/members/MemberRolePicker.vue +13 -12
  236. package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/notification/NotificationInboxDisplay.vue +17 -7
  237. package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/notification/NotificationPreferencesForm.vue +0 -1
  238. package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/profile/ProfilePersonalInfo.vue +36 -33
  239. package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/profile/ProfileSecuritySummary.vue +1 -2
  240. package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/roles/role-types.ts +5 -4
  241. package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/security/SecuritySessions.vue +35 -28
  242. package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/security/SecurityStatus.vue +0 -1
  243. package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/security/SecurityTwoFactor.vue +1 -1
  244. package/frontend-vue/layers/dms-layout/app/build/composables/dev-reload/useDevReloadHolder.ts +7 -6
  245. package/frontend-vue/layers/dms-layout/app/build/composables/layout/sidePanelState.ts +1 -1
  246. package/frontend-vue/layers/dms-layout/app/build/composables/navigation/useVisitNavBadges.ts +26 -0
  247. package/frontend-vue/layers/dms-layout/app/build/composables/notification/useNotificationCatalog.ts +25 -23
  248. package/frontend-vue/layers/dms-layout/app/build/composables/notification/useNotificationPreferences.ts +44 -23
  249. package/frontend-vue/layers/dms-layout/app/build/composables/security/useSessionHandoff.ts +1 -1
  250. package/frontend-vue/layers/dms-layout/app/build/composables/settings/profile/preferencesSummary.ts +1 -1
  251. package/frontend-vue/layers/dms-layout/app/build/composables/settings/profile/useAccountData.ts +3 -2
  252. package/frontend-vue/layers/dms-layout/app/build/composables/settings/profile/useProfileAvatar.ts +1 -18
  253. package/frontend-vue/layers/dms-layout/app/build/composables/settings/profile/useProfilePreferences.ts +19 -23
  254. package/frontend-vue/layers/dms-layout/app/build/composables/settings/security/useSecurityFormat.ts +6 -3
  255. package/frontend-vue/layers/dms-layout/app/build/composables/settings/security/useSecurityOverview.ts +13 -18
  256. package/frontend-vue/layers/dms-layout/app/build/utils/module-store-catalog.ts +186 -120
  257. package/frontend-vue/layers/dms-layout/app/build/utils/module-store-install.ts +146 -0
  258. package/frontend-vue/layers/dms-layout/app/build/utils/modules-catalog.ts +8 -6
  259. package/frontend-vue/layers/dms-layout/app/build/utils/publicErrorMessage.ts +19 -0
  260. package/frontend-vue/layers/dms-layout/app/components/navigation/CollapsedMenuItem.vue +0 -11
  261. package/frontend-vue/layers/dms-layout/app/components/navigation/NavigationMenu.vue +3 -13
  262. package/frontend-vue/layers/dms-layout/app/composables/general/useSystemState.ts +7 -11
  263. package/frontend-vue/layers/dms-layout/app/composables/notification/useNotifications.ts +103 -22
  264. package/frontend-vue/layers/dms-layout/app/composables/page/useModuleStore.ts +109 -0
  265. package/frontend-vue/layers/dms-layout/app/composables/page/useModulesListing.ts +25 -102
  266. package/frontend-vue/layers/dms-layout/app/composables/page/usePageComponentPreload.ts +0 -10
  267. package/frontend-vue/layers/dms-layout/app/composables/page/useSiteLayout.ts +177 -96
  268. package/frontend-vue/layers/dms-layout/app/composables/profile/useUserLanguage.ts +3 -2
  269. package/frontend-vue/layers/dms-layout/app/custom-pages/modules.vue +341 -62
  270. package/frontend-vue/layers/dms-layout/app/emails/components/EmailLayout.vue +31 -11
  271. package/frontend-vue/layers/dms-layout/app/error.vue +5 -2
  272. package/frontend-vue/layers/dms-layout/app/middleware/module-routing.global.ts +1 -1
  273. package/frontend-vue/layers/dms-layout/app/middleware/page-leave-guard.global.ts +2 -2
  274. package/frontend-vue/layers/dms-layout/app/pages/[...slug].vue +12 -9
  275. package/frontend-vue/layers/dms-layout/app/plugins/dms-menu-sync.client.ts +31 -3
  276. package/frontend-vue/layers/dms-layout/app/plugins/favicon.ts +58 -0
  277. package/frontend-vue/layers/dms-layout/app/plugins/notification-stream.client.ts +15 -7
  278. package/frontend-vue/layers/dms-layout/app/plugins/profile-sync.client.ts +5 -1
  279. package/frontend-vue/layers/dms-layout/app/plugins/regional-preferences.ts +10 -4
  280. package/frontend-vue/layers/dms-layout/app/plugins/time-zone-cookie.client.ts +12 -0
  281. package/frontend-vue/layers/dms-layout/app/types/module-store.ts +134 -0
  282. package/frontend-vue/layers/dms-layout/app/types/page.ts +13 -0
  283. package/frontend-vue/layers/dms-layout/i18n/locales/layout-en-GB.json +107 -9
  284. package/frontend-vue/layers/dms-layout/i18n/locales/layout-fr-FR.json +107 -9
  285. package/frontend-vue/layers/dms-layout/server/html-render.ts +58 -0
  286. package/frontend-vue/layers/dms-layout/server/render-token.ts +95 -0
  287. package/frontend-vue/layers/dms-onboarding/app/composables/onboarding/useOnboarding.ts +25 -21
  288. package/frontend-vue/layers/dms-onboarding/app/middleware/onboarding.global.ts +1 -1
  289. package/frontend-vue/layers/dms-onboarding/app/plugins/onboarding-preload.ts +9 -0
  290. package/frontend-vue/layers/dms-ui/app/build/composables/data-types/registerDefaults.ts +4 -1
  291. package/frontend-vue/layers/dms-ui/app/build/composables/files/useFileMetadata.ts +162 -0
  292. package/frontend-vue/layers/dms-ui/app/build/composables/form/formRecordLoad.ts +23 -4
  293. package/frontend-vue/layers/dms-ui/app/build/composables/live/usePageDataRefresh.ts +101 -0
  294. package/frontend-vue/layers/dms-ui/app/build/composables/navigation/useNavBadges.ts +33 -6
  295. package/frontend-vue/layers/dms-ui/app/build/composables/period/periodDisplay.ts +19 -16
  296. package/frontend-vue/layers/dms-ui/app/build/composables/period/periodQuery.ts +40 -20
  297. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useTableFooter.ts +6 -8
  298. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useTableListData.ts +42 -14
  299. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useTableRows.ts +19 -8
  300. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useTableViews.ts +1 -1
  301. package/frontend-vue/layers/dms-ui/app/components/chart/ChartCard.vue +5 -2
  302. package/frontend-vue/layers/dms-ui/app/components/flow-canvas/FlowCanvas.vue +9 -9
  303. package/frontend-vue/layers/dms-ui/app/components/form/Form.vue +20 -18
  304. package/frontend-vue/layers/dms-ui/app/components/form/components/Cascader.vue +2 -1
  305. package/frontend-vue/layers/dms-ui/app/components/form/components/File.vue +26 -132
  306. package/frontend-vue/layers/dms-ui/app/components/form/components/Image.vue +40 -105
  307. package/frontend-vue/layers/dms-ui/app/components/form/components/InputAddress.vue +2 -0
  308. package/frontend-vue/layers/dms-ui/app/components/form/components/Relation.vue +4 -4
  309. package/frontend-vue/layers/dms-ui/app/components/period/PeriodSelector.vue +9 -13
  310. package/frontend-vue/layers/dms-ui/app/components/table-view/CascaderPath.vue +2 -1
  311. package/frontend-vue/layers/dms-ui/app/components/table-view/FilePreview.vue +12 -24
  312. package/frontend-vue/layers/dms-ui/app/components/table-view/ImagePreview.vue +17 -29
  313. package/frontend-vue/layers/dms-ui/app/components/table-view/KanbanBoard.vue +7 -3
  314. package/frontend-vue/layers/dms-ui/app/components/table-view/TableView.vue +20 -8
  315. package/frontend-vue/layers/dms-ui/app/components/top-list/TopListCard.vue +8 -11
  316. package/frontend-vue/layers/dms-ui/app/composables/chart/useChartFetch.ts +146 -182
  317. package/frontend-vue/layers/dms-ui/app/composables/live/usePageLiveRefresh.ts +8 -2
  318. package/frontend-vue/layers/dms-ui/app/composables/useFileReadUrls.ts +11 -99
  319. package/frontend-vue/layers/dms-ui/app/utils/blockRefresh.ts +32 -3
  320. package/frontend-vue/package.json +3 -3
  321. package/frontend-vue/pnpm-lock.yaml +16 -22
  322. package/frontend-vue/server/private-options.ts +27 -0
  323. package/frontend-vue/tests/async-data-scope.test.ts +121 -0
  324. package/frontend-vue/tests/auth-middleware-error.test.ts +3 -3
  325. package/frontend-vue/tests/banner-block-fetch.test.ts +3 -0
  326. package/frontend-vue/tests/block-fetch-options-forwarding.test.ts +3 -0
  327. package/frontend-vue/tests/block-items-period-realtime.test.ts +3 -0
  328. package/frontend-vue/tests/block-not-found.test.ts +16 -2
  329. package/frontend-vue/tests/block-page-refresh.test.ts +3 -0
  330. package/frontend-vue/tests/block-route-params.test.ts +3 -0
  331. package/frontend-vue/tests/branding-defaults.test.ts +34 -0
  332. package/frontend-vue/tests/builtin-emails.test.ts +23 -2
  333. package/frontend-vue/tests/chart-live-pause.test.ts +4 -1
  334. package/frontend-vue/tests/chart-value-propagation.test.ts +4 -1
  335. package/frontend-vue/tests/composed-text-blocks.test.ts +3 -0
  336. package/frontend-vue/tests/email-layout.test.ts +66 -4
  337. package/frontend-vue/tests/error-page-message.test.ts +25 -2
  338. package/frontend-vue/tests/favicon.test.ts +131 -0
  339. package/frontend-vue/tests/file-fields-ssr.test.ts +145 -0
  340. package/frontend-vue/tests/file-read-urls.test.ts +145 -34
  341. package/frontend-vue/tests/file-unavailable.test.ts +5 -1
  342. package/frontend-vue/tests/fixtures/dataEngine.ts +44 -0
  343. package/frontend-vue/tests/form-load-error.test.ts +55 -1
  344. package/frontend-vue/tests/helpers/api-data-runtime.ts +77 -0
  345. package/frontend-vue/tests/image-hydration-ids.test.ts +21 -16
  346. package/frontend-vue/tests/image-reference-preservation.test.ts +59 -53
  347. package/frontend-vue/tests/input-number-adjust.test.ts +14 -0
  348. package/frontend-vue/tests/key-value-list-copy.test.ts +3 -0
  349. package/frontend-vue/tests/member-role-picker.test.ts +4 -2
  350. package/frontend-vue/tests/menu-sync-reconnect.test.ts +47 -0
  351. package/frontend-vue/tests/metadata-retry.test.ts +5 -1
  352. package/frontend-vue/tests/module-routing.test.ts +2 -5
  353. package/frontend-vue/tests/module-store-catalog.test.ts +270 -51
  354. package/frontend-vue/tests/modules-catalog.test.ts +17 -4
  355. package/frontend-vue/tests/modules-listing-transfer.test.ts +95 -0
  356. package/frontend-vue/tests/multi-account-validate.test.ts +23 -1
  357. package/frontend-vue/tests/nav-badge-tones.test.ts +66 -3
  358. package/frontend-vue/tests/notification-counts-from-writes.test.ts +223 -0
  359. package/frontend-vue/tests/notification-counts-transfer.test.ts +88 -0
  360. package/frontend-vue/tests/notification-inbox-display.test.ts +57 -5
  361. package/frontend-vue/tests/notification-popover-errors.test.ts +21 -1
  362. package/frontend-vue/tests/oauth-complete-handoff.test.ts +209 -0
  363. package/frontend-vue/tests/onboarding-middleware.test.ts +1 -1
  364. package/frontend-vue/tests/onboarding-transfer.test.ts +106 -0
  365. package/frontend-vue/tests/page-data-refresh.test.ts +141 -0
  366. package/frontend-vue/tests/page-fill-height.test.ts +16 -3
  367. package/frontend-vue/tests/page-no-visible-blocks.test.ts +12 -2
  368. package/frontend-vue/tests/page-realtime-remount.test.ts +1 -1
  369. package/frontend-vue/tests/page-record-label.test.ts +0 -7
  370. package/frontend-vue/tests/page-validation-redirect.test.ts +12 -2
  371. package/frontend-vue/tests/period-hydration-now.test.ts +185 -0
  372. package/frontend-vue/tests/period-live-pause.test.ts +3 -0
  373. package/frontend-vue/tests/period-reader-zone.test.ts +137 -0
  374. package/frontend-vue/tests/period-scope-first-fetch.test.ts +17 -1
  375. package/frontend-vue/tests/period-ssr.test.ts +195 -0
  376. package/frontend-vue/tests/permission-preview-partial.test.ts +0 -2
  377. package/frontend-vue/tests/permissions-transfer.test.ts +194 -0
  378. package/frontend-vue/tests/post-login-redirect.test.ts +10 -5
  379. package/frontend-vue/tests/profile-personal-info-ssr.test.ts +150 -0
  380. package/frontend-vue/tests/profile-preferences-summary.test.ts +15 -11
  381. package/frontend-vue/tests/realtime-reconnect.test.ts +22 -3
  382. package/frontend-vue/tests/roles-name-errors.test.ts +1 -1
  383. package/frontend-vue/tests/row-side-panel.test.ts +1 -1
  384. package/frontend-vue/tests/security-sessions-load-error.test.ts +3 -1
  385. package/frontend-vue/tests/server-routes-vs-pages.test.ts +26 -0
  386. package/frontend-vue/tests/server-routes.test.ts +582 -0
  387. package/frontend-vue/tests/session-handoff.test.ts +1 -1
  388. package/frontend-vue/tests/settings-reads-ssr.test.ts +232 -0
  389. package/frontend-vue/tests/side-panels.test.ts +8 -1
  390. package/frontend-vue/tests/sign-in-exit-history.test.ts +219 -0
  391. package/frontend-vue/tests/signup-invitation-link.test.ts +56 -8
  392. package/frontend-vue/tests/site-layout-categories.test.ts +42 -0
  393. package/frontend-vue/tests/site-layout-hydration.test.ts +3 -3
  394. package/frontend-vue/tests/site-layout-rendered.test.ts +103 -0
  395. package/frontend-vue/tests/site-layout-resync.test.ts +87 -0
  396. package/frontend-vue/tests/ssr-guard-preload.test.ts +188 -0
  397. package/frontend-vue/tests/table-cell-tones.test.ts +36 -1
  398. package/frontend-vue/tests/table-data-ssr.test.ts +195 -0
  399. package/frontend-vue/tests/table-list-data-requests.test.ts +154 -0
  400. package/frontend-vue/tests/table-retry-loading.test.ts +37 -0
  401. package/frontend-vue/tests/table-source-navigation.test.ts +0 -1
  402. package/frontend-vue/tests/table-source-period-scope.test.ts +0 -1
  403. package/frontend-vue/tests/table-view-views.test.ts +1 -1
  404. package/frontend-vue/tests/top-list-card-actions.test.ts +3 -0
  405. package/frontend-vue/tests/top-list-card-period-badge-ssr.test.ts +212 -0
  406. package/frontend-vue/tests/top-list-card-period-badge.test.ts +79 -0
  407. package/frontend-vue/tests/top-list-card-value-suffix.test.ts +3 -0
  408. package/frontend-vue/tests/trailing-deduper.test.ts +22 -0
  409. package/frontend-vue/tests/use-api-data-update.test.ts +119 -0
  410. package/frontend-vue/tests/use-api-data.test.ts +410 -0
  411. package/frontend-vue/tests/user-language.test.ts +8 -5
  412. package/frontend-vue/tests/widget-label-i18n.test.ts +4 -1
  413. package/frontend-vue/vitest.config.ts +6 -0
  414. package/package.json +2 -2
  415. package/skills/dms/SKILL.md +2 -1
  416. package/skills/dms-module/SKILL.md +1 -1
  417. package/skills/dms-pages/SKILL.md +4 -1
  418. package/frontend-vue/layers/dms-core/app/build/composables/page/usePageRecordLabel.ts +0 -9
  419. package/frontend-vue/layers/dms-layout/app/composables/page/usePrefetch.ts +0 -21
  420. package/frontend-vue/layers/dms-ui/app/build/composables/form/useControlError.ts +0 -10
  421. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useServerRenderedAsyncData.ts +0 -23
  422. package/frontend-vue/tests/control-error-path.test.ts +0 -11
  423. package/frontend-vue/tests/modules-listing-per-request.test.ts +0 -104
  424. package/frontend-vue/tests/page-layout-background-refresh.test.ts +0 -321
@@ -1,105 +1,17 @@
1
- import { FORM_CONTENT_LANGUAGE_KEY } from "./form/types/content-language";
2
-
3
- interface FileMetadataUrlResponse {
4
- url: string;
5
- expiresAt?: number;
6
- }
7
-
8
- type CachedFileReadUrl = FileMetadataUrlResponse;
9
-
10
- const URL_REFRESH_LEAD_MS = 5000;
11
- const RETRY_DELAY_MS = 5000;
1
+ import { useFileMetadata } from "../build/composables/files/useFileMetadata";
12
2
 
13
3
  /**
14
4
  * Resolves stored file resource keys to read URLs through
15
- * `/api/files/metadata`. Expiring URLs refresh while visible, and failed
16
- * lookups remain retryable instead of permanently hiding the file.
5
+ * `/api/files/metadata`. A key resolved during the setup (an immediate
6
+ * watcher) is read with the page, the server render included; expiring URLs
7
+ * refresh while visible, and failed lookups that may heal are retried
8
+ * instead of permanently hiding the file.
17
9
  */
18
10
  export function useFileReadUrls(storage?: string) {
19
- const { $authFetch } = useAuthFetch();
20
- const contentLanguage = inject(FORM_CONTENT_LANGUAGE_KEY, undefined);
21
- const urls = ref<Map<string, CachedFileReadUrl>>(new Map());
22
- const pendingKeys = new Set<string>();
23
- const refreshTimers = new Map<string, ReturnType<typeof setTimeout>>();
24
- let isDisposed = false;
25
-
26
- function isFresh(metadata: CachedFileReadUrl): boolean {
27
- return (
28
- metadata.expiresAt === undefined ||
29
- metadata.expiresAt - URL_REFRESH_LEAD_MS > Date.now()
30
- );
31
- }
32
-
33
- function scheduleRefresh(key: string, expiresAt?: number): void {
34
- if (isDisposed || import.meta.env.SSR) return;
35
- const currentTimer = refreshTimers.get(key);
36
- if (currentTimer) clearTimeout(currentTimer);
37
- if (expiresAt === undefined) return;
38
- const remaining = Math.max(expiresAt - Date.now(), 0);
39
- const refreshLead = Math.min(URL_REFRESH_LEAD_MS, remaining / 2);
40
- const delay = Math.max(remaining - refreshLead, 0);
41
- refreshTimers.set(
42
- key,
43
- setTimeout(() => resolve(key, true), delay),
44
- );
45
- }
46
-
47
- async function resolve(key: string, force = false): Promise<void> {
48
- if (isDisposed) return;
49
- const cached = urls.value.get(key);
50
- if (!force && cached && isFresh(cached)) return;
51
- if (pendingKeys.has(key)) return;
52
-
53
- pendingKeys.add(key);
54
- try {
55
- const metadata = await $authFetch<FileMetadataUrlResponse>(
56
- "/api/files/metadata",
57
- {
58
- query: { resourceKey: key, storage },
59
- headers: contentLanguage
60
- ? { [CONTENT_LANGUAGE_HEADER]: contentLanguage }
61
- : undefined,
62
- },
63
- );
64
- if (isDisposed) return;
65
- urls.value.set(key, metadata);
66
- scheduleRefresh(key, metadata.expiresAt);
67
- } catch {
68
- if (isDisposed) return;
69
- if (cached?.expiresAt !== undefined && cached.expiresAt <= Date.now()) {
70
- urls.value.delete(key);
71
- } else if (cached?.expiresAt !== undefined) {
72
- scheduleRefresh(key, cached.expiresAt);
73
- }
74
- if (
75
- !import.meta.env.SSR &&
76
- (!cached ||
77
- (cached.expiresAt !== undefined && cached.expiresAt <= Date.now()))
78
- ) {
79
- refreshTimers.set(
80
- key,
81
- setTimeout(() => resolve(key, true), RETRY_DELAY_MS),
82
- );
83
- }
84
- }
85
- pendingKeys.delete(key);
86
- }
87
-
88
- function getUrl(key: string): string | undefined {
89
- const metadata = urls.value.get(key);
90
- if (
91
- !metadata ||
92
- (metadata.expiresAt !== undefined && metadata.expiresAt <= Date.now())
93
- ) {
94
- return undefined;
95
- }
96
- return metadata.url;
97
- }
98
-
99
- onScopeDispose(() => {
100
- isDisposed = true;
101
- refreshTimers.forEach(clearTimeout);
102
- });
103
-
104
- return { getUrl, resolve };
11
+ const files = useFileMetadata(storage);
12
+ return {
13
+ /** The URL to show `key` with, until it expires; undefined until read. */
14
+ getUrl: (key: string): string | undefined => files.metadata(key)?.url,
15
+ resolve: (key: string): Promise<void> => files.resolve(key),
16
+ };
105
17
  }
@@ -11,6 +11,15 @@ export const BLOCK_REFRESH_EVENT = "DmsComponent.Block.Refresh";
11
11
  */
12
12
  export const LIVE_BLOCK_REFRESH_EVENT = "DmsComponent.Block.LiveRefresh";
13
13
 
14
+ /**
15
+ * The detail of a `refreshPageBlocks()` event: a listener whose refresh
16
+ * takes time hands its promise to `waitUntil`, and the call resolves once
17
+ * every one settled.
18
+ */
19
+ export interface PageBlocksRefreshDetail {
20
+ waitUntil(work: Promise<unknown>): void;
21
+ }
22
+
14
23
  /** The watch functions every block can name (see interface-dms). */
15
24
  export const BlockFunctions = {
16
25
  REFRESH_PAGE: "DmsComponent.Block.RefreshPage",
@@ -23,10 +32,30 @@ export const BlockFunctions = {
23
32
  * through `BlockFunctions.REFRESH_PAGE` once it saved. A user action always
24
33
  * refreshes: on a page declared with `live` it reads even while paused, and
25
34
  * the blocks it reads no longer count what they had missed.
35
+ *
36
+ * @returns Resolves once the page's data refresh (its `useApiData` reads)
37
+ * is done, failed reads included: they keep their `error`
26
38
  */
27
- export function refreshPageBlocks(): void {
28
- if (typeof window === "undefined") return;
29
- window.dispatchEvent(new CustomEvent(BLOCK_REFRESH_EVENT));
39
+ export function refreshPageBlocks(): Promise<void> {
40
+ if (typeof window === "undefined") return Promise.resolve();
41
+ const pending: Array<Promise<unknown>> = [];
42
+ const detail: PageBlocksRefreshDetail = {
43
+ waitUntil: (work) => void pending.push(work),
44
+ };
45
+ window.dispatchEvent(new CustomEvent(BLOCK_REFRESH_EVENT, { detail }));
46
+ return Promise.allSettled(pending).then(() => undefined);
47
+ }
48
+
49
+ /**
50
+ * Has `refreshPageBlocks()` wait for `work` too, when `event` is one of its
51
+ * events.
52
+ */
53
+ export function waitForPageBlocksRefresh(
54
+ event: Event,
55
+ work: Promise<unknown>,
56
+ ): void {
57
+ const detail = (event as CustomEvent<PageBlocksRefreshDetail | null>).detail;
58
+ detail?.waitUntil(work);
30
59
  }
31
60
 
32
61
  /**
@@ -11,7 +11,7 @@
11
11
  "license": "Apache-2.0",
12
12
  "packageManager": "pnpm@10.6.5",
13
13
  "engines": {
14
- "@antelopejs/dms-frontend": ">=0.5.2 <0.6.0"
14
+ "@antelopejs/dms-frontend": ">=0.6.1 <0.7.0"
15
15
  },
16
16
  "scripts": {
17
17
  "typecheck": "ajs dms verify-source --layer \"$PWD\" --local-package @antelopejs/dms=.. --local-package @antelopejs/interface-dms=../../interface-dms",
@@ -73,8 +73,8 @@
73
73
  "zod": "^3.24.2"
74
74
  },
75
75
  "devDependencies": {
76
- "@antelopejs/core": ">=1.13.4 <2",
77
- "@antelopejs/dms-frontend": ">=0.5.6 <0.6.0",
76
+ "@antelopejs/core": ">=1.15.0 <2",
77
+ "@antelopejs/dms-frontend": ">=0.6.1 <0.7.0",
78
78
  "@eslint/js": "^8.57.0",
79
79
  "@inertiajs/vue3": "^3.7.0",
80
80
  "@nuxt/ui": "4.10.0",
@@ -157,11 +157,11 @@ importers:
157
157
  version: 3.25.76
158
158
  devDependencies:
159
159
  '@antelopejs/core':
160
- specifier: '>=1.13.4 <2'
161
- version: 1.13.5
160
+ specifier: '>=1.15.0 <2'
161
+ version: 1.15.0
162
162
  '@antelopejs/dms-frontend':
163
- specifier: '>=0.5.6 <0.6.0'
164
- version: 0.5.6(@antelopejs/core@1.13.5)
163
+ specifier: '>=0.6.1 <0.7.0'
164
+ version: 0.6.1(@antelopejs/core@1.15.0)
165
165
  '@eslint/js':
166
166
  specifier: ^8.57.0
167
167
  version: 8.57.0
@@ -232,20 +232,20 @@ packages:
232
232
  resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==}
233
233
  engines: {node: '>=10'}
234
234
 
235
- '@antelopejs/core@1.13.5':
236
- resolution: {integrity: sha512-a1Apu8dUvC18j7r7zK4WNpyjRy+xPlL/2bTG1PArrs/b4iWp2UI2ALDJfefJlSa7VNftDevHx7PqVWDl7pX0jg==}
235
+ '@antelopejs/core@1.15.0':
236
+ resolution: {integrity: sha512-QpcZqnzwq8uZz4rY0DBZB4OTqWXAGP5MqKXKdbgUbSeirW/ZeBMtCnCfpexKVS+MoJnFJ3RtVJvQcslOMD+8Bw==}
237
237
  engines: {node: '>=20.19'}
238
238
  hasBin: true
239
239
 
240
- '@antelopejs/dms-frontend@0.5.6':
241
- resolution: {integrity: sha512-bO7kacKMF1rVsIjS208rhPUoIxRYss6ZuQCdQ1Kpq5D3pG0qSvF2pNsi+WecvxTOKM8d6AQAoLl5facu5tyHFQ==}
240
+ '@antelopejs/dms-frontend@0.6.1':
241
+ resolution: {integrity: sha512-Dii4YhtlMsfJTjHWCvYdcJmoo7PoMOfW9MVAutNJGNIIMJ4zmF37vZVA2OskpaWFZGI+WdsgI2e2MMOm/8x9QQ==}
242
242
  engines: {node: '>=20.12.0'}
243
243
  hasBin: true
244
244
  peerDependencies:
245
245
  '@antelopejs/core': '>=1.13.2 <2'
246
246
 
247
- '@antelopejs/interface-core@0.1.1':
248
- resolution: {integrity: sha512-nGxElt51KGWIwGsUcFdGT7ikQEqDB+mLj4NQ/eFL/DI1+j65GJqq9PdkVT4x3/YKchNA48iMbzXyW7bKUsQ8Iw==}
247
+ '@antelopejs/interface-core@0.2.1':
248
+ resolution: {integrity: sha512-yVUov8QS1mnbKlU1GTpCXoB/0UkHFLHIPpowBu8LrR8xG1sEmyjitlRdxT/ClTRmQtF2Acf38LdwHj4I9JB7pA==}
249
249
 
250
250
  '@antfu/install-pkg@1.1.0':
251
251
  resolution: {integrity: sha512-MGQsmw10ZyI+EJo45CdSER4zEb+p31LpDAFp2Z3gkSd1yqVZGi0Ebx++YTEMonJy4oChEMLsxZ64j8FH6sSqtQ==}
@@ -2689,10 +2689,6 @@ packages:
2689
2689
  engines: {node: '>=10.0.0'}
2690
2690
  hasBin: true
2691
2691
 
2692
- jiti@2.6.1:
2693
- resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==}
2694
- hasBin: true
2695
-
2696
2692
  jiti@2.7.0:
2697
2693
  resolution: {integrity: sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==}
2698
2694
  hasBin: true
@@ -4193,9 +4189,9 @@ snapshots:
4193
4189
 
4194
4190
  '@alloc/quick-lru@5.2.0': {}
4195
4191
 
4196
- '@antelopejs/core@1.13.5':
4192
+ '@antelopejs/core@1.15.0':
4197
4193
  dependencies:
4198
- '@antelopejs/interface-core': 0.1.1
4194
+ '@antelopejs/interface-core': 0.2.1
4199
4195
  '@clack/prompts': 1.8.1
4200
4196
  '@types/proper-lockfile': 4.1.4
4201
4197
  commander: 13.1.0
@@ -4208,9 +4204,9 @@ snapshots:
4208
4204
  semver: 7.8.5
4209
4205
  typescript: 5.9.3
4210
4206
 
4211
- '@antelopejs/dms-frontend@0.5.6(@antelopejs/core@1.13.5)':
4207
+ '@antelopejs/dms-frontend@0.6.1(@antelopejs/core@1.15.0)':
4212
4208
  dependencies:
4213
- '@antelopejs/core': 1.13.5
4209
+ '@antelopejs/core': 1.15.0
4214
4210
  chokidar: 4.0.3
4215
4211
  commander: 13.1.0
4216
4212
  ignore: 7.0.6
@@ -4223,7 +4219,7 @@ snapshots:
4223
4219
  '@oxc-parser/binding-linux-x64-gnu': 0.95.0
4224
4220
  '@oxc-parser/binding-win32-x64-msvc': 0.95.0
4225
4221
 
4226
- '@antelopejs/interface-core@0.1.1':
4222
+ '@antelopejs/interface-core@0.2.1':
4227
4223
  dependencies:
4228
4224
  reflect-metadata: 0.2.2
4229
4225
 
@@ -6533,7 +6529,7 @@ snapshots:
6533
6529
  defu: 6.1.7
6534
6530
  esbuild: 0.27.7
6535
6531
  fontaine: 0.8.0
6536
- jiti: 2.6.1
6532
+ jiti: 2.7.0
6537
6533
  lightningcss: 1.30.2
6538
6534
  magic-string: 0.30.21
6539
6535
  ohash: 2.0.11
@@ -6796,8 +6792,6 @@ snapshots:
6796
6792
  tar-stream: 2.2.0
6797
6793
  try-to-catch: 3.0.1
6798
6794
 
6799
- jiti@2.6.1: {}
6800
-
6801
6795
  jiti@2.7.0: {}
6802
6796
 
6803
6797
  js-tokens@10.0.0: {}
@@ -0,0 +1,27 @@
1
+ import type { DmsServerEvent } from "#dms/server";
2
+
3
+ /**
4
+ * A secret of the DMS's private options, as the frontend server hands them
5
+ * to its routes. The manifest's value wins; the environment variable of the
6
+ * same secret is the fallback, read only when the manifest holds none. A
7
+ * frontend built without the bootstrap credential gets no private options at
8
+ * all, so the environment variable alone configures it there.
9
+ *
10
+ * @param event The route's event
11
+ * @param section The private options' section (`htmlRender`, `oauth`)
12
+ * @param key The secret's key in it
13
+ * @param variable The environment variable that configures it
14
+ */
15
+ export function privateSecret(
16
+ event: DmsServerEvent,
17
+ section: string,
18
+ key: string,
19
+ variable: string,
20
+ ): string | undefined {
21
+ const options = event.module.privateOptions[section] as
22
+ | Record<string, unknown>
23
+ | undefined;
24
+ const value = options?.[key];
25
+ if (typeof value === "string" && value) return value;
26
+ return process.env[variable] || undefined;
27
+ }
@@ -0,0 +1,121 @@
1
+ // @vitest-environment jsdom
2
+ /**
3
+ * Every key of the async data lives in the scope of the session's account and
4
+ * workspace: the browser finds what the server transferred under the same
5
+ * scope, and a switch of account or workspace drops the previous session's
6
+ * data instead of showing it under the new one.
7
+ */
8
+ import {
9
+ type App,
10
+ createApp,
11
+ createSSRApp,
12
+ defineComponent,
13
+ h,
14
+ nextTick,
15
+ Suspense,
16
+ } from "vue";
17
+ import { renderToString } from "vue/server-renderer";
18
+ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
19
+ import type { DmsFrontendRuntime } from "#dms/frontend-module";
20
+ import { asyncDataScopeOf } from "../layers/dms-core/app/build/utils/asyncDataScope";
21
+
22
+ const engine = await import("#dms/frontend-module");
23
+ const { default: asyncDataScopePlugin } = await import(
24
+ "../layers/dms-core/app/plugins/async-data-scope"
25
+ );
26
+
27
+ const ACCOUNT_A = { accountId: "account-a", activeTenantId: "tenant-1" };
28
+ const ACCOUNT_B = { accountId: "account-b", activeTenantId: "tenant-1" };
29
+
30
+ const handler = vi.fn(async () => "orders of account A");
31
+
32
+ const Page = defineComponent({
33
+ async setup() {
34
+ const { data } = await engine.useDmsAsyncData("orders", handler);
35
+ return () => h("p", data.value ?? "none");
36
+ },
37
+ });
38
+
39
+ const Root = defineComponent({
40
+ setup: () => () => h(Suspense, null, { default: () => h(Page) }),
41
+ });
42
+
43
+ const mounted: App[] = [];
44
+
45
+ function start(app: App, runtime: DmsFrontendRuntime, session: object) {
46
+ engine.provideDmsFrontendRuntime(app, runtime);
47
+ app.runWithContext(() => {
48
+ engine.useDmsState("dms-session", () => null).value = session;
49
+ void asyncDataScopePlugin({} as never);
50
+ });
51
+ }
52
+
53
+ async function settle(): Promise<void> {
54
+ await nextTick();
55
+ await new Promise((done) => setTimeout(done, 0));
56
+ }
57
+
58
+ beforeEach(async () => {
59
+ handler.mockClear();
60
+ await engine.setupFrontendModules([]);
61
+ });
62
+
63
+ afterEach(() => {
64
+ mounted.splice(0).forEach((app) => app.unmount());
65
+ });
66
+
67
+ describe("the async data scope", () => {
68
+ it("is a digest of the account and the workspace, none when signed out", () => {
69
+ const scope = asyncDataScopeOf(ACCOUNT_A);
70
+ expect(scope).toMatch(/^[0-9a-z]+$/);
71
+ expect(scope).not.toContain("account-a");
72
+ expect(asyncDataScopeOf({ ...ACCOUNT_A })).toBe(scope);
73
+ expect(asyncDataScopeOf(ACCOUNT_B)).not.toBe(scope);
74
+ expect(
75
+ asyncDataScopeOf({ ...ACCOUNT_A, activeTenantId: "tenant-2" }),
76
+ ).not.toBe(scope);
77
+ expect(asyncDataScopeOf(null)).toBeUndefined();
78
+ expect(asyncDataScopeOf({})).toBeUndefined();
79
+ });
80
+
81
+ it("hands the server's data to the browser under the same session", async () => {
82
+ const server = engine.createDmsFrontendRuntime(undefined, {}, true);
83
+ const serverApp = createSSRApp(Root);
84
+ start(serverApp, server, ACCOUNT_A);
85
+ expect(await renderToString(serverApp)).toBe("<p>orders of account A</p>");
86
+ const payload = structuredClone(engine.serializeDmsPayload(server));
87
+ expect(JSON.stringify(payload)).not.toContain("account-a");
88
+
89
+ handler.mockClear();
90
+ const browser = engine.createDmsFrontendRuntime(undefined, {});
91
+ const browserApp = createApp(Root);
92
+ start(browserApp, browser, ACCOUNT_A);
93
+ engine.restoreDmsPayload(browser, payload);
94
+ const host = document.createElement("div");
95
+ browserApp.mount(host);
96
+ mounted.push(browserApp);
97
+ await settle();
98
+
99
+ expect(handler).not.toHaveBeenCalled();
100
+ expect(host.textContent).toBe("orders of account A");
101
+ });
102
+
103
+ it("drops the previous account's data once the session switches", async () => {
104
+ const browser = engine.createDmsFrontendRuntime(undefined, {});
105
+ const browserApp = createApp(Root);
106
+ start(browserApp, browser, ACCOUNT_A);
107
+ const host = document.createElement("div");
108
+ browserApp.mount(host);
109
+ mounted.push(browserApp);
110
+ await settle();
111
+ expect(host.textContent).toBe("orders of account A");
112
+
113
+ browserApp.runWithContext(() => {
114
+ engine.useDmsState("dms-session", () => null).value = ACCOUNT_B;
115
+ });
116
+ await settle();
117
+
118
+ expect(browser.asyncData.size).toBe(0);
119
+ expect(host.textContent).toBe("none");
120
+ });
121
+ });
@@ -8,14 +8,14 @@ const navigateDms = vi.fn();
8
8
  beforeEach(() => {
9
9
  vi.resetModules();
10
10
  vi.stubGlobal("defineDmsMiddleware", (handler: Middleware) => handler);
11
- vi.stubGlobal("useError", () => pageError);
12
- vi.stubGlobal("abortNavigation", () => false);
11
+ vi.stubGlobal("useDmsError", () => pageError);
12
+ vi.stubGlobal("abortDmsNavigation", () => false);
13
13
  vi.stubGlobal("navigateDms", navigateDms);
14
14
  vi.stubGlobal("useSiteLayout", () => ({
15
15
  siteLayout: { value: {} },
16
16
  findMatchingRoute: () => ({ metadata: {} }),
17
17
  }));
18
- vi.stubGlobal("useUserSession", () => ({ loggedIn: { value: false } }));
18
+ vi.stubGlobal("useDmsUserSession", () => ({ loggedIn: { value: false } }));
19
19
  });
20
20
 
21
21
  afterEach(() => {
@@ -7,6 +7,7 @@
7
7
  */
8
8
  import { createApp, defineComponent, h, reactive, ref } from "vue";
9
9
  import { afterEach, beforeEach, expect, it, vi } from "vitest";
10
+ import { useRealDataEngine } from "./fixtures/dataEngine";
10
11
  import { refreshPageBlocks } from "../layers/dms-ui/app/utils/blockRefresh";
11
12
 
12
13
  const requests: string[] = [];
@@ -93,6 +94,8 @@ function mountBanner(props: Record<string, unknown>) {
93
94
  };
94
95
  }
95
96
 
97
+ beforeEach(() => useRealDataEngine());
98
+
96
99
  beforeEach(() => {
97
100
  requests.length = 0;
98
101
  pressed.length = 0;
@@ -6,6 +6,7 @@
6
6
  import { type Component, createSSRApp, defineComponent, h, ref } from "vue";
7
7
  import { renderToString } from "vue/server-renderer";
8
8
  import { afterEach, beforeEach, expect, it, vi } from "vitest";
9
+ import { useRealDataEngine } from "./fixtures/dataEngine";
9
10
  import type { UseChartFetchOptions } from "../layers/dms-ui/app/composables/chart/useChartFetch";
10
11
 
11
12
  const fetchOptions: Array<UseChartFetchOptions<unknown>> = [];
@@ -78,6 +79,8 @@ async function render(block: Component): Promise<void> {
78
79
  await renderToString(app);
79
80
  }
80
81
 
82
+ beforeEach(() => useRealDataEngine());
83
+
81
84
  beforeEach(() => {
82
85
  fetchOptions.length = 0;
83
86
  vi.stubGlobal("useI18n", () => ({ locale: ref("en-GB"), t: String }));
@@ -7,6 +7,7 @@
7
7
  */
8
8
  import { createApp, defineComponent, h, nextTick, reactive, ref } from "vue";
9
9
  import { afterEach, beforeEach, expect, it, vi } from "vitest";
10
+ import { useRealDataEngine } from "./fixtures/dataEngine";
10
11
  import type { RealtimeTopicHandler } from "../layers/dms-core/app/composables/realtime/useUserRealtime";
11
12
 
12
13
  const requests: string[] = [];
@@ -106,6 +107,8 @@ function mountRealtimeBlock(probe: ItemsProbe) {
106
107
  mounted.push(app);
107
108
  }
108
109
 
110
+ beforeEach(() => useRealDataEngine());
111
+
109
112
  beforeEach(() => {
110
113
  requests.length = 0;
111
114
  revision = 1;
@@ -16,6 +16,7 @@ import {
16
16
  ref,
17
17
  } from "vue";
18
18
  import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
19
+ import { useRealDataEngine } from "./fixtures/dataEngine";
19
20
  import { readFetchNotFound } from "../layers/dms-ui/app/build/utils/fetchNotFound";
20
21
 
21
22
  interface FetchFailure extends Error {
@@ -92,6 +93,8 @@ function mount(component: Component): HTMLElement {
92
93
  return host;
93
94
  }
94
95
 
96
+ beforeEach(() => useRealDataEngine());
97
+
95
98
  beforeEach(() => {
96
99
  answers.clear();
97
100
  route.query = { workspace: "web" };
@@ -157,12 +160,23 @@ describe("useChartFetch on a 404", () => {
157
160
  );
158
161
  });
159
162
 
160
- it("keeps them on any other failure", async () => {
163
+ it("keeps them when a read of the same request fails otherwise", async () => {
161
164
  const state = mountFetch();
162
165
  await settle();
163
- await switchWorkspace("down");
166
+ answers.set("/api/kpis?workspace=web", failure(500));
167
+ await state.refresh?.();
168
+ await settle();
164
169
  expect(state.data?.value).toEqual({ items: [{ label: "web" }] });
165
170
  });
171
+
172
+ it("never shows a record's values for another request that failed", async () => {
173
+ // They belong to another workspace: the card shows its failure instead.
174
+ const state = mountFetch();
175
+ await settle();
176
+ await switchWorkspace("down");
177
+ expect(state.data?.value).toBeNull();
178
+ expect(state.error?.value).toBeTruthy();
179
+ });
166
180
  });
167
181
 
168
182
  describe("useBlockItems on a 404", () => {
@@ -7,6 +7,7 @@
7
7
  */
8
8
  import { createApp, defineComponent, h, ref } from "vue";
9
9
  import { afterEach, beforeEach, expect, it, vi } from "vitest";
10
+ import { useRealDataEngine } from "./fixtures/dataEngine";
10
11
  import {
11
12
  BlockFunctions,
12
13
  refreshPageBlocks,
@@ -64,6 +65,8 @@ function mountBlock(fetchUrl: string) {
64
65
 
65
66
  const apps: Array<() => void> = [];
66
67
 
68
+ beforeEach(() => useRealDataEngine());
69
+
67
70
  beforeEach(() => {
68
71
  requests.length = 0;
69
72
  answer = 1;
@@ -15,6 +15,7 @@ import {
15
15
  ref,
16
16
  } from "vue";
17
17
  import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
18
+ import { useRealDataEngine } from "./fixtures/dataEngine";
18
19
  import {
19
20
  replaceUrlVariables,
20
21
  resolveTextVariables,
@@ -59,6 +60,8 @@ function mount(component: Component) {
59
60
  mounted.push(app);
60
61
  }
61
62
 
63
+ beforeEach(() => useRealDataEngine());
64
+
62
65
  beforeEach(() => {
63
66
  requests.length = 0;
64
67
  route.query = {};
@@ -0,0 +1,34 @@
1
+ import { defu } from "defu";
2
+ import { describe, expect, it } from "vitest";
3
+ import appConfig from "../layers/dms-layout/app/app.config";
4
+
5
+ const ANTELOPE_ICON = "/images/antelope-logo/icon.svg";
6
+
7
+ describe("branding defaults", () => {
8
+ it("hold the palettes and logos the layout ships", () => {
9
+ expect(appConfig.branding.defaults).toEqual({
10
+ colors: appConfig.ui.colors,
11
+ logo: appConfig.branding.logo,
12
+ });
13
+ expect(appConfig.branding.defaults.colors.primary).toBe("dms");
14
+ expect(appConfig.branding.logo.favicon).toEqual({
15
+ light: ANTELOPE_ICON,
16
+ dark: ANTELOPE_ICON,
17
+ });
18
+ });
19
+
20
+ it("survive a live edit of the merged palette and logos", () => {
21
+ // A clone keeps any object shared between the two places, like the
22
+ // loader's merge keeps the objects no layer overrides.
23
+ const merged = defu(
24
+ { branding: { footer: { githubStar: false } } },
25
+ structuredClone(appConfig),
26
+ );
27
+
28
+ merged.ui.colors.primary = "violet";
29
+ merged.branding.logo.favicon!.light = "/branding/icon.png";
30
+
31
+ expect(merged.branding.defaults.colors.primary).toBe("dms");
32
+ expect(merged.branding.defaults.logo.favicon?.light).toBe(ANTELOPE_ICON);
33
+ });
34
+ });