@antelopejs/dms 0.15.0 → 0.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +47 -0
- package/README.md +36 -26
- package/bin/control/base.mjs +9 -4
- package/bin/control/browser-client.mjs +24 -5
- package/bin/control/browser-wire.mjs +41 -0
- package/bin/control/browser-wire.test.mjs +96 -0
- package/bin/control/browser.mjs +78 -27
- package/bin/control/commands-stack.mjs +58 -8
- package/bin/control/commands-verify.mjs +47 -1
- package/bin/control/doctor.mjs +49 -4
- package/bin/control/failure.mjs +9 -0
- package/bin/control/journey.mjs +163 -30
- package/bin/control/journey.test.mjs +61 -0
- package/bin/control/json.mjs +229 -0
- package/bin/control/json.test.mjs +130 -0
- package/bin/control/mail.mjs +57 -7
- package/bin/control/mail.test.mjs +55 -0
- package/bin/control/mongo.mjs +205 -27
- package/bin/control/mongo.test.mjs +298 -0
- package/bin/control/options.mjs +33 -0
- package/bin/control/processes.mjs +24 -2
- package/bin/control/renderer.mjs +39 -0
- package/bin/control/renderer.test.mjs +324 -0
- package/bin/control/run-state.mjs +119 -6
- package/bin/control/run-state.test.mjs +171 -0
- package/bin/control/session.mjs +31 -14
- package/bin/control/stack.mjs +96 -24
- package/bin/control/tab.mjs +117 -18
- package/bin/control/verify/behaviour.mjs +44 -6
- package/bin/control/verify/behaviour.test.mjs +130 -22
- package/bin/control/verify/decode.mjs +220 -0
- package/bin/control/verify/decode.test.mjs +245 -0
- package/bin/control/verify/doors.mjs +1 -1
- package/bin/control/verify/doors.test.mjs +40 -0
- package/bin/control/verify/emit.mjs +135 -9
- package/bin/control/verify/formal.mjs +61 -10
- package/bin/control/verify/formal.test.mjs +19 -3
- package/bin/control/verify/judgement.mjs +22 -3
- package/bin/control/verify/map.mjs +25 -5
- package/bin/control/verify/publish.mjs +20 -14
- package/bin/control/verify/seeded.mjs +65 -16
- package/bin/control/verify/skill.mjs +27 -6
- package/bin/control/verify/types.mjs +29 -0
- package/bin/control/verify/verdict.mjs +72 -7
- package/bin/dms-control.mjs +8 -28
- package/checks/api-error-presentation.d.mts +61 -0
- package/dist/attachments/access.js +1 -1
- package/dist/attachments/access.js.map +1 -1
- package/dist/attachments/fields.d.ts +2 -2
- package/dist/attachments/fields.js +26 -13
- package/dist/attachments/fields.js.map +1 -1
- package/dist/attachments/index.d.ts +1 -0
- package/dist/attachments/index.js +1 -0
- package/dist/attachments/index.js.map +1 -1
- package/dist/attachments/read.js.map +1 -1
- package/dist/attachments/save.d.ts +1 -1
- package/dist/attachments/save.js +49 -17
- package/dist/attachments/save.js.map +1 -1
- package/dist/attachments/table-view.d.ts +1 -2
- package/dist/attachments/table-view.js +23 -13
- package/dist/attachments/table-view.js.map +1 -1
- package/dist/automation/events.d.ts +10 -10
- package/dist/automation/index.js +3 -4
- package/dist/automation/index.js.map +1 -1
- package/dist/automation/send-notification.d.ts +2 -2
- package/dist/automation/send-notification.js +4 -6
- package/dist/automation/send-notification.js.map +1 -1
- package/dist/config/internal/state.d.ts +7 -0
- package/dist/config/internal/state.js +9 -0
- package/dist/config/internal/state.js.map +1 -1
- package/dist/config/startup-config.d.ts +1 -0
- package/dist/config/startup-config.js +11 -0
- package/dist/config/startup-config.js.map +1 -1
- package/dist/crons/cleanup-user-invites.js.map +1 -1
- package/dist/crons/sweep-expired-sessions.js.map +1 -1
- package/dist/crons/sweep-stale-exports.js.map +1 -1
- package/dist/db/guard-row.d.ts +2 -3
- package/dist/db/guard-row.js +1 -2
- package/dist/db/guard-row.js.map +1 -1
- package/dist/db/index.d.ts +1 -0
- package/dist/db/index.js +1 -0
- package/dist/db/index.js.map +1 -1
- package/dist/db/models/attachments.model.d.ts +7 -5
- package/dist/db/models/index.d.ts +1 -0
- package/dist/db/models/index.js +1 -0
- package/dist/db/models/index.js.map +1 -1
- package/dist/db/models/setupToken.model.d.ts +31 -0
- package/dist/db/models/setupToken.model.js +62 -0
- package/dist/db/models/setupToken.model.js.map +1 -0
- package/dist/db/models/signInAttempts.model.d.ts +7 -5
- package/dist/db/models/systemState.model.d.ts +7 -5
- package/dist/db/models/userEmailChanges.model.d.ts +7 -5
- package/dist/db/models/userKnownDevices.model.d.ts +7 -5
- package/dist/db/models/userNotificationPreferences.model.d.ts +7 -5
- package/dist/db/models/userNotifications.model.d.ts +9 -6
- package/dist/db/models/userNotifications.model.js.map +1 -1
- package/dist/db/setup-token.d.ts +2 -0
- package/dist/db/setup-token.js +28 -0
- package/dist/db/setup-token.js.map +1 -0
- package/dist/db/tables/index.d.ts +1 -0
- package/dist/db/tables/index.js +1 -0
- package/dist/db/tables/index.js.map +1 -1
- package/dist/db/tables/setupToken.table.d.ts +7 -0
- package/dist/db/tables/setupToken.table.js +34 -0
- package/dist/db/tables/setupToken.table.js.map +1 -0
- package/dist/dev/module-update-notifications.js.map +1 -1
- package/dist/hooks/internal/sign-in-monitor.js +6 -6
- package/dist/hooks/internal/sign-in-monitor.js.map +1 -1
- package/dist/implementations/dms/page/controller.d.ts +2 -2
- package/dist/implementations/dms/page/controller.js +3 -1
- package/dist/implementations/dms/page/controller.js.map +1 -1
- package/dist/implementations/dms/page/dynamic-menu.js +3 -2
- package/dist/implementations/dms/page/dynamic-menu.js.map +1 -1
- package/dist/implementations/dms/page/notifications.d.ts +6 -2
- package/dist/implementations/dms/page/notifications.js +1 -0
- package/dist/implementations/dms/page/notifications.js.map +1 -1
- package/dist/implementations/dms/page/payloads.js +6 -10
- package/dist/implementations/dms/page/payloads.js.map +1 -1
- package/dist/implementations/dms/page/preview-pages.js +6 -3
- package/dist/implementations/dms/page/preview-pages.js.map +1 -1
- package/dist/implementations/dms/page/public-layout.d.ts +2 -0
- package/dist/implementations/dms/page/public-layout.js +45 -0
- package/dist/implementations/dms/page/public-layout.js.map +1 -0
- package/dist/implementations/dms/page/registry.js +10 -4
- package/dist/implementations/dms/page/registry.js.map +1 -1
- package/dist/implementations/dms/permissions.js +12 -12
- package/dist/implementations/dms/permissions.js.map +1 -1
- package/dist/implementations/dms-base/bulk-selection.d.ts +3 -4
- package/dist/implementations/dms-base/bulk-selection.js +18 -6
- package/dist/implementations/dms-base/bulk-selection.js.map +1 -1
- package/dist/implementations/dms-base/filter-tokens.js.map +1 -1
- package/dist/implementations/dms-base/footer-summary.js +44 -27
- package/dist/implementations/dms-base/footer-summary.js.map +1 -1
- package/dist/implementations/dms-base/row-rule-operand.d.ts +6 -0
- package/dist/implementations/dms-base/row-rule-operand.js +41 -0
- package/dist/implementations/dms-base/row-rule-operand.js.map +1 -0
- package/dist/implementations/dms-base/search-route.d.ts +9 -13
- package/dist/implementations/dms-base/search-route.js +7 -6
- package/dist/implementations/dms-base/search-route.js.map +1 -1
- package/dist/implementations/dms-base/services.d.ts +1 -0
- package/dist/implementations/dms-base/services.js +1 -0
- package/dist/implementations/dms-base/services.js.map +1 -1
- package/dist/implementations/dms-base/table-view.d.ts +5 -6
- package/dist/implementations/dms-base/table-view.js +17 -6
- package/dist/implementations/dms-base/table-view.js.map +1 -1
- package/dist/implementations/dms-html-render/index.js +16 -6
- package/dist/implementations/dms-html-render/index.js.map +1 -1
- package/dist/implementations/dms-notifications/delivery-guard.d.ts +3 -2
- package/dist/implementations/dms-notifications/delivery-guard.js.map +1 -1
- package/dist/implementations/dms-notifications/index.js.map +1 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.js +6 -2
- package/dist/index.js.map +1 -1
- package/dist/pages/public/preview/block-types.d.ts +1 -2
- package/dist/pages/public/preview/block-types.js.map +1 -1
- package/dist/pages/settings/overview/account-summary.js +4 -1
- package/dist/pages/settings/overview/account-summary.js.map +1 -1
- package/dist/pages/settings/users/account-activity-feed.js +3 -2
- package/dist/pages/settings/users/account-activity-feed.js.map +1 -1
- package/dist/pages/settings/users/account-credentials.d.ts +1 -1
- package/dist/pages/settings/users/account-credentials.js +1 -2
- package/dist/pages/settings/users/account-credentials.js.map +1 -1
- package/dist/pages/settings/users/account-data-store.d.ts +1 -1
- package/dist/pages/settings/users/account-data-store.js +1 -3
- package/dist/pages/settings/users/account-data-store.js.map +1 -1
- package/dist/pages/settings/users/current-password.js +1 -1
- package/dist/pages/settings/users/current-password.js.map +1 -1
- package/dist/pages/settings/users/email-change.d.ts +2 -2
- package/dist/pages/settings/users/email-change.js +2 -3
- package/dist/pages/settings/users/email-change.js.map +1 -1
- package/dist/pages/settings/users/invite-extension-routes.d.ts +2 -2
- package/dist/pages/settings/users/invite-extension-routes.js +11 -4
- package/dist/pages/settings/users/invite-extension-routes.js.map +1 -1
- package/dist/pages/settings/users/invites.d.ts +2 -2
- package/dist/pages/settings/users/member-invite-batch.d.ts +2 -2
- package/dist/pages/settings/users/member-invite-batch.js +7 -3
- package/dist/pages/settings/users/member-invite-batch.js.map +1 -1
- package/dist/pages/settings/users/member-roles-field.js +1 -4
- package/dist/pages/settings/users/member-roles-field.js.map +1 -1
- package/dist/pages/settings/users/members.d.ts +2 -3
- package/dist/pages/settings/users/members.js.map +1 -1
- package/dist/pages/settings/users/notifications.d.ts +2 -3
- package/dist/pages/settings/users/notifications.js +2 -1
- package/dist/pages/settings/users/notifications.js.map +1 -1
- package/dist/pages/settings/users/profile-helpers.d.ts +0 -1
- package/dist/pages/settings/users/profile-helpers.js +0 -17
- package/dist/pages/settings/users/profile-helpers.js.map +1 -1
- package/dist/pages/settings/users/profile.d.ts +3 -4
- package/dist/pages/settings/users/profile.js +12 -12
- package/dist/pages/settings/users/profile.js.map +1 -1
- package/dist/pages/settings/users/region.d.ts +3 -4
- package/dist/pages/settings/users/region.js.map +1 -1
- package/dist/pages/settings/users/regional-preferences.d.ts +8 -1
- package/dist/pages/settings/users/regional-preferences.js +10 -6
- package/dist/pages/settings/users/regional-preferences.js.map +1 -1
- package/dist/pages/settings/users/role-preview.js +3 -2
- package/dist/pages/settings/users/role-preview.js.map +1 -1
- package/dist/pages/settings/users/roles.d.ts +4 -5
- package/dist/pages/settings/users/roles.js.map +1 -1
- package/dist/pages/settings/users/security.d.ts +9 -12
- package/dist/pages/settings/users/security.js +11 -9
- package/dist/pages/settings/users/security.js.map +1 -1
- package/dist/pages/settings/users/two-factor-operations.d.ts +7 -7
- package/dist/pages/settings/users/two-factor-operations.js +5 -7
- package/dist/pages/settings/users/two-factor-operations.js.map +1 -1
- package/dist/realtime/broker.js.map +1 -1
- package/dist/realtime/heartbeat.js.map +1 -1
- package/dist/realtime/redis-broker.js.map +1 -1
- package/dist/realtime/sessions.js.map +1 -1
- package/dist/realtime/sse.js +1 -2
- package/dist/realtime/sse.js.map +1 -1
- package/dist/routes/auth/forgot-password.d.ts +1 -1
- package/dist/routes/auth/forgot-password.js +1 -3
- package/dist/routes/auth/forgot-password.js.map +1 -1
- package/dist/routes/auth/login.d.ts +2 -2
- package/dist/routes/auth/login.js +8 -4
- package/dist/routes/auth/login.js.map +1 -1
- package/dist/routes/auth/logout.d.ts +1 -1
- package/dist/routes/auth/logout.js +1 -2
- package/dist/routes/auth/logout.js.map +1 -1
- package/dist/routes/auth/oauth/providers.js +30 -6
- package/dist/routes/auth/oauth/providers.js.map +1 -1
- package/dist/routes/auth/oauth/state.js +8 -5
- package/dist/routes/auth/oauth/state.js.map +1 -1
- package/dist/routes/auth/oauth/token-exchange.js +8 -1
- package/dist/routes/auth/oauth/token-exchange.js.map +1 -1
- package/dist/routes/auth/password-hash-upgrade.d.ts +2 -0
- package/dist/routes/auth/password-hash-upgrade.js +22 -0
- package/dist/routes/auth/password-hash-upgrade.js.map +1 -0
- package/dist/routes/auth/refresh.d.ts +1 -1
- package/dist/routes/auth/refresh.js +1 -2
- package/dist/routes/auth/refresh.js.map +1 -1
- package/dist/routes/auth/request-2fa-email.d.ts +1 -1
- package/dist/routes/auth/request-2fa-email.js +1 -2
- package/dist/routes/auth/request-2fa-email.js.map +1 -1
- package/dist/routes/auth/reset-password.d.ts +1 -1
- package/dist/routes/auth/reset-password.js +1 -3
- package/dist/routes/auth/reset-password.js.map +1 -1
- package/dist/routes/auth/session-handoff.d.ts +1 -1
- package/dist/routes/auth/session-handoff.js +1 -2
- package/dist/routes/auth/session-handoff.js.map +1 -1
- package/dist/routes/auth/signup.d.ts +1 -1
- package/dist/routes/auth/signup.js +1 -2
- package/dist/routes/auth/signup.js.map +1 -1
- package/dist/routes/auth/switch-tenant.d.ts +2 -3
- package/dist/routes/auth/switch-tenant.js +3 -2
- package/dist/routes/auth/switch-tenant.js.map +1 -1
- package/dist/routes/auth/validate-forgot-password-token.d.ts +1 -1
- package/dist/routes/auth/validate-forgot-password-token.js +1 -3
- package/dist/routes/auth/validate-forgot-password-token.js.map +1 -1
- package/dist/routes/auth/validate-invite-token.d.ts +1 -1
- package/dist/routes/auth/validate-invite-token.js +1 -3
- package/dist/routes/auth/validate-invite-token.js.map +1 -1
- package/dist/routes/auth/verify-2fa.d.ts +1 -1
- package/dist/routes/auth/verify-2fa.js +1 -2
- package/dist/routes/auth/verify-2fa.js.map +1 -1
- package/dist/routes/auth/verify-email.d.ts +1 -1
- package/dist/routes/auth/verify-email.js +1 -2
- package/dist/routes/auth/verify-email.js.map +1 -1
- package/dist/routes/auth.d.ts +14 -15
- package/dist/routes/auth.js +15 -13
- package/dist/routes/auth.js.map +1 -1
- package/dist/routes/authentication.d.ts +2 -0
- package/dist/routes/authentication.js +2 -0
- package/dist/routes/authentication.js.map +1 -1
- package/dist/routes/files.d.ts +1 -2
- package/dist/routes/files.js.map +1 -1
- package/dist/routes/onboarding.d.ts +4 -3
- package/dist/routes/onboarding.js +20 -3
- package/dist/routes/onboarding.js.map +1 -1
- package/dist/routes/realtime.js +5 -6
- package/dist/routes/realtime.js.map +1 -1
- package/dist/routes/store.d.ts +6 -7
- package/dist/routes/store.js +19 -13
- package/dist/routes/store.js.map +1 -1
- package/dist/store/catalog.d.ts +13 -5
- package/dist/store/catalog.js +19 -9
- package/dist/store/catalog.js.map +1 -1
- package/dist/store/compatibility.d.ts +1 -0
- package/dist/store/compatibility.js +24 -8
- package/dist/store/compatibility.js.map +1 -1
- package/dist/store/frontend-compatibility.js +15 -3
- package/dist/store/frontend-compatibility.js.map +1 -1
- package/dist/store/interfaces.js +35 -13
- package/dist/store/interfaces.js.map +1 -1
- package/dist/store/internal/frontend/frontend-modules.js +7 -3
- package/dist/store/internal/frontend/frontend-modules.js.map +1 -1
- package/dist/store/internal/frontend/frontend-ready.d.ts +2 -1
- package/dist/store/internal/frontend/frontend-ready.js +6 -4
- package/dist/store/internal/frontend/frontend-ready.js.map +1 -1
- package/dist/store/internal/frontend/manifest.js +6 -7
- package/dist/store/internal/frontend/manifest.js.map +1 -1
- package/dist/store/operations.js.map +1 -1
- package/dist/store/registry.js.map +1 -1
- package/dist/store/runtime.d.ts +13 -0
- package/dist/store/runtime.js +9 -1
- package/dist/store/runtime.js.map +1 -1
- package/dist/utils/admin-invite-email.js +3 -1
- package/dist/utils/admin-invite-email.js.map +1 -1
- package/dist/utils/email-subjects.js +3 -1
- package/dist/utils/email-subjects.js.map +1 -1
- package/dist/utils/ensure-default-tenant.d.ts +2 -1
- package/dist/utils/ensure-default-tenant.js +126 -8
- package/dist/utils/ensure-default-tenant.js.map +1 -1
- package/dist/utils/export-jobs-run.js.map +1 -1
- package/dist/utils/export-jobs.js +3 -9
- package/dist/utils/export-jobs.js.map +1 -1
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.js +1 -0
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/own-value.d.ts +1 -0
- package/dist/utils/own-value.js +7 -0
- package/dist/utils/own-value.js.map +1 -0
- package/dist/utils/row-action-rule-evaluator.js +31 -35
- package/dist/utils/row-action-rule-evaluator.js.map +1 -1
- package/dist/utils/sign-in-country.js +4 -2
- package/dist/utils/sign-in-country.js.map +1 -1
- package/dist/utils/tenant-export-archive.js +9 -14
- package/dist/utils/tenant-export-archive.js.map +1 -1
- package/dist/utils/user-agent.js +2 -1
- package/dist/utils/user-agent.js.map +1 -1
- package/dist/validation/auth.schema.d.ts +10 -10
- package/dist/validation/onboarding/register-admin.schema.d.ts +5 -0
- package/dist/validation/onboarding/register-admin.schema.js +3 -0
- package/dist/validation/onboarding/register-admin.schema.js.map +1 -1
- package/dist/validation/regional-preferences.schema.d.ts +2 -2
- package/dist/validation/role-editor.schema.d.ts +1 -1
- package/frontend-vue/build/backend-boundary.ts +49 -18
- package/frontend-vue/dms.frontend.ts +8 -12
- package/frontend-vue/layers/dms-auth/server/accounts.ts +44 -3
- package/frontend-vue/layers/dms-auth/server/actions.ts +17 -4
- package/frontend-vue/layers/dms-auth/server/oauth.ts +42 -4
- package/frontend-vue/layers/dms-core/app/types/watch.ts +1 -2
- package/frontend-vue/layers/dms-core/i18n/locales/core-en-GB.json +1 -0
- package/frontend-vue/layers/dms-core/i18n/locales/core-fr-FR.json +1 -0
- package/frontend-vue/layers/dms-core/shared/types/app-config.ts +5 -0
- package/frontend-vue/layers/dms-layout/app/app.config.ts +1 -0
- package/frontend-vue/layers/dms-layout/app/build/components/layout/DashboardSidebar.vue +9 -9
- package/frontend-vue/layers/dms-layout/app/components/layout/AppLogo.vue +1 -0
- package/frontend-vue/layers/dms-layout/app/composables/page/useInstalledModules.ts +78 -0
- package/frontend-vue/layers/dms-layout/app/custom-pages/modules.vue +5 -24
- package/frontend-vue/layers/dms-layout/i18n/locales/layout-en-GB.json +2 -1
- package/frontend-vue/layers/dms-layout/i18n/locales/layout-fr-FR.json +2 -1
- package/frontend-vue/layers/dms-onboarding/app/components/onboarding/steps/register.vue +21 -1
- package/frontend-vue/layers/dms-onboarding/app/custom-pages/onboarding.vue +14 -0
- package/frontend-vue/layers/dms-onboarding/i18n/locales/onboarding-en-GB.json +2 -0
- package/frontend-vue/layers/dms-onboarding/i18n/locales/onboarding-fr-FR.json +2 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/form/fieldValueRule.ts +57 -6
- package/frontend-vue/layers/dms-ui/app/build/composables/form/registerFormFunctions.ts +7 -9
- package/frontend-vue/layers/dms-ui/app/entries/composables/form/registerFormFunctions.ts +1 -0
- package/frontend-vue/lazy-plugin.ts +18 -0
- package/frontend-vue/package.json +2 -2
- package/package.json +19 -13
- package/skills/dms-project/SKILL.md +4 -3
|
@@ -10,20 +10,32 @@ const QUERY_OR_HASH = /[?#].*$/;
|
|
|
10
10
|
|
|
11
11
|
const backendRoots = new Map<string, string | null>();
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
/** Whether a parsed manifest names its package. */
|
|
14
|
+
function isNamedManifest(value: unknown): value is { name: string } {
|
|
15
|
+
return (
|
|
16
|
+
typeof value === "object" &&
|
|
17
|
+
value !== null &&
|
|
18
|
+
"name" in value &&
|
|
19
|
+
typeof value.name === "string"
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** The package name a `package.json` declares, or `undefined`. */
|
|
24
|
+
function packageName(manifest: string): string | undefined {
|
|
14
25
|
try {
|
|
15
|
-
const parsed:
|
|
16
|
-
|
|
17
|
-
);
|
|
18
|
-
return parsed.name;
|
|
26
|
+
const parsed: unknown = JSON.parse(readFileSync(manifest, "utf8"));
|
|
27
|
+
return isNamedManifest(parsed) ? parsed.name : undefined;
|
|
19
28
|
} catch {
|
|
20
29
|
return undefined;
|
|
21
30
|
}
|
|
22
31
|
}
|
|
23
32
|
|
|
33
|
+
/** The directory of the backend package that holds `directory`, or null. */
|
|
24
34
|
function backendRoot(directory: string): string | null {
|
|
25
35
|
const known = backendRoots.get(directory);
|
|
26
|
-
if (known !== undefined)
|
|
36
|
+
if (known !== undefined) {
|
|
37
|
+
return known;
|
|
38
|
+
}
|
|
27
39
|
const manifest = join(directory, "package.json");
|
|
28
40
|
const parent = dirname(directory);
|
|
29
41
|
let root: string | null = null;
|
|
@@ -44,7 +56,9 @@ function backendRoot(directory: string): string | null {
|
|
|
44
56
|
*/
|
|
45
57
|
function backendSourceFile(id: string): string | undefined {
|
|
46
58
|
const path = id.replace(QUERY_OR_HASH, "");
|
|
47
|
-
if (!isAbsolute(path))
|
|
59
|
+
if (!isAbsolute(path)) {
|
|
60
|
+
return undefined;
|
|
61
|
+
}
|
|
48
62
|
let real: string;
|
|
49
63
|
try {
|
|
50
64
|
real = realpathSync(path);
|
|
@@ -52,39 +66,56 @@ function backendSourceFile(id: string): string | undefined {
|
|
|
52
66
|
return undefined;
|
|
53
67
|
}
|
|
54
68
|
const root = backendRoot(dirname(real));
|
|
55
|
-
if (root === null)
|
|
69
|
+
if (root === null) {
|
|
70
|
+
return undefined;
|
|
71
|
+
}
|
|
56
72
|
return relative(root, real).split(sep)[0] === BACKEND_SOURCE
|
|
57
73
|
? real
|
|
58
74
|
: undefined;
|
|
59
75
|
}
|
|
60
76
|
|
|
61
77
|
/**
|
|
62
|
-
* Fails the build
|
|
63
|
-
*
|
|
78
|
+
* Fails the build and the dev server when a module of the frontend resolves to
|
|
79
|
+
* a file under the `src` of the backend package: the browser reaches the
|
|
64
80
|
* backend only through its HTTP interface. It checks what the whole resolution
|
|
65
|
-
* chain returns, so an alias is seen through
|
|
66
|
-
* returns is followed to its real path, and it runs
|
|
67
|
-
* (`enforce: "pre"`).
|
|
68
|
-
*
|
|
81
|
+
* chain returns, an id marked external included, so an alias is seen through
|
|
82
|
+
* and a symlink the resolver returns is followed to its real path, and it runs
|
|
83
|
+
* before the other plugins (`enforce: "pre"`). Vite builds workers with their
|
|
84
|
+
* own plugin list, so the plugin adds itself there too.
|
|
85
|
+
*
|
|
86
|
+
* antelopejs-sync writes this file from `@antelopejs/tooling-configs` and
|
|
87
|
+
* restores it on every run: change the plugin in the pack, not here.
|
|
69
88
|
*/
|
|
70
89
|
export function backendBoundary(): VitePlugin {
|
|
71
90
|
return {
|
|
72
|
-
|
|
91
|
+
...boundaryCheck(),
|
|
92
|
+
config: () => ({ worker: { plugins: () => [boundaryCheck()] } }),
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/** The check alone, as a worker build runs it. */
|
|
97
|
+
function boundaryCheck(): VitePlugin {
|
|
98
|
+
return {
|
|
99
|
+
name: `${BACKEND_PACKAGE}:backend-boundary`,
|
|
73
100
|
enforce: "pre",
|
|
74
101
|
async resolveId(source, importer, options) {
|
|
75
102
|
const resolved = await this.resolve(source, importer, {
|
|
76
103
|
...options,
|
|
77
104
|
skipSelf: true,
|
|
78
105
|
});
|
|
79
|
-
if (resolved === null
|
|
106
|
+
if (resolved === null) {
|
|
107
|
+
return resolved;
|
|
108
|
+
}
|
|
80
109
|
const file = backendSourceFile(resolved.id);
|
|
81
|
-
if (file === undefined)
|
|
110
|
+
if (file === undefined) {
|
|
111
|
+
return resolved;
|
|
112
|
+
}
|
|
82
113
|
const from =
|
|
83
114
|
importer === undefined
|
|
84
115
|
? "an entry point"
|
|
85
116
|
: importer.replace(QUERY_OR_HASH, "");
|
|
86
117
|
return this.error(
|
|
87
|
-
`Backend boundary: ${from} imports ${file}, which is under
|
|
118
|
+
`Backend boundary: ${from} imports ${file}, which is under the src of ${BACKEND_PACKAGE}. The frontend reaches the backend only through its HTTP interface.`,
|
|
88
119
|
);
|
|
89
120
|
},
|
|
90
121
|
};
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
type DmsFrontendSdk,
|
|
9
9
|
useDmsRuntimeConfig,
|
|
10
10
|
} from "#dms/frontend-module";
|
|
11
|
+
import { lazyPlugin } from "./lazy-plugin";
|
|
11
12
|
import authMiddleware from "./layers/dms-auth/app/middleware/auth";
|
|
12
13
|
import permissionsPreloadPlugin from "./layers/dms-auth/app/plugins/permissions-preload";
|
|
13
14
|
import asyncDataScopePlugin from "./layers/dms-core/app/plugins/async-data-scope";
|
|
@@ -164,20 +165,15 @@ function registerDeferredPlugins(
|
|
|
164
165
|
function registerPlugins(sdk: Parameters<DmsFrontendModule["setup"]>[0]): void {
|
|
165
166
|
const clientOnly = { clientOnly: true };
|
|
166
167
|
if (import.meta.env.DEV) {
|
|
167
|
-
sdk.registerPlugin(
|
|
168
|
-
|
|
169
|
-
"./layers/dms-layout/app/plugins/dms-dev-reload.client"
|
|
170
|
-
)
|
|
171
|
-
|
|
172
|
-
|
|
168
|
+
sdk.registerPlugin(
|
|
169
|
+
lazyPlugin(
|
|
170
|
+
() => import("./layers/dms-layout/app/plugins/dms-dev-reload.client"),
|
|
171
|
+
),
|
|
172
|
+
clientOnly,
|
|
173
|
+
);
|
|
173
174
|
|
|
174
175
|
sdk.registerPlugin(
|
|
175
|
-
|
|
176
|
-
const plugin = await import(
|
|
177
|
-
"./layers/dms-core/app/plugins/dev-error-log"
|
|
178
|
-
);
|
|
179
|
-
await plugin.default(context);
|
|
180
|
-
},
|
|
176
|
+
lazyPlugin(() => import("./layers/dms-core/app/plugins/dev-error-log")),
|
|
181
177
|
{ ...clientOnly, enforce: "pre" },
|
|
182
178
|
);
|
|
183
179
|
}
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
2
|
import type { DmsServerEvent, DmsSession } from "#dms/server";
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
isBoolean,
|
|
5
|
+
isObject,
|
|
6
|
+
isString,
|
|
7
|
+
} from "../../dms-core/app/utils/type-check";
|
|
4
8
|
|
|
5
9
|
/**
|
|
6
10
|
* The accounts this browser is signed in to: an index of their descriptors,
|
|
@@ -68,8 +72,42 @@ function descriptor(session: DmsSession, accountId: string): AccountDescriptor {
|
|
|
68
72
|
};
|
|
69
73
|
}
|
|
70
74
|
|
|
75
|
+
function isOptionalText(value: unknown): value is string | undefined {
|
|
76
|
+
return value === undefined || isString(value);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function isAccountDescriptor(value: unknown): value is AccountDescriptor {
|
|
80
|
+
return (
|
|
81
|
+
isObject(value) &&
|
|
82
|
+
value !== null &&
|
|
83
|
+
isString(value.accountId) &&
|
|
84
|
+
isOptionalText(value.userId) &&
|
|
85
|
+
isOptionalText(value.email) &&
|
|
86
|
+
isOptionalText(value.name) &&
|
|
87
|
+
isOptionalText(value.activeTenantId) &&
|
|
88
|
+
isBoolean(value.persistent)
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function isStoredAccount(value: unknown): value is StoredAccount {
|
|
93
|
+
return (
|
|
94
|
+
isAccountDescriptor(value) &&
|
|
95
|
+
isObject(value) &&
|
|
96
|
+
isOptionalText(value.refreshToken)
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function isAccountIndex(value: unknown): value is AccountIndex {
|
|
101
|
+
return (
|
|
102
|
+
isObject(value) &&
|
|
103
|
+
value !== null &&
|
|
104
|
+
!Array.isArray(value) &&
|
|
105
|
+
Object.values(value).every(isAccountDescriptor)
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
|
|
71
109
|
export function readAccounts(event: DmsServerEvent): AccountIndex {
|
|
72
|
-
return event.cookies.readSealed
|
|
110
|
+
return event.cookies.readSealed(ACCOUNT_INDEX_COOKIE, isAccountIndex) ?? {};
|
|
73
111
|
}
|
|
74
112
|
|
|
75
113
|
function writeAccountIndex(event: DmsServerEvent, accounts: AccountIndex) {
|
|
@@ -84,7 +122,10 @@ export function readAccount(
|
|
|
84
122
|
accountId: Parameters<typeof isString>[0],
|
|
85
123
|
): StoredAccount | undefined {
|
|
86
124
|
if (!isString(accountId) || !UUID.test(accountId)) return undefined;
|
|
87
|
-
return event.cookies.readSealed
|
|
125
|
+
return event.cookies.readSealed(
|
|
126
|
+
accountCookieName(accountId),
|
|
127
|
+
isStoredAccount,
|
|
128
|
+
);
|
|
88
129
|
}
|
|
89
130
|
|
|
90
131
|
export function storeAccount(
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
isBoolean,
|
|
3
|
+
isObject,
|
|
4
|
+
isString,
|
|
5
|
+
} from "../../dms-core/app/utils/type-check";
|
|
2
6
|
import type { DmsBackendRequest, DmsServerEvent } from "#dms/server";
|
|
3
7
|
import {
|
|
4
8
|
isPersistent,
|
|
@@ -30,6 +34,15 @@ interface PendingLogin {
|
|
|
30
34
|
persistent: boolean;
|
|
31
35
|
}
|
|
32
36
|
|
|
37
|
+
function isPendingLogin(value: unknown): value is PendingLogin {
|
|
38
|
+
return (
|
|
39
|
+
isObject(value) &&
|
|
40
|
+
value !== null &&
|
|
41
|
+
isString(value.token) &&
|
|
42
|
+
isBoolean(value.persistent)
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
33
46
|
/**
|
|
34
47
|
* Calls a backend endpoint that opens a session and, unless it asks for a
|
|
35
48
|
* second step, writes the session and stores the account.
|
|
@@ -51,7 +64,7 @@ async function establishWith(
|
|
|
51
64
|
{ maxAge: PENDING_LOGIN_LIFETIME_S, path: PENDING_LOGIN_PATH },
|
|
52
65
|
);
|
|
53
66
|
if (result.requires_2fa || result.requires_tenant_assignment) return result;
|
|
54
|
-
if (event.cookies.readSealed(PENDING_LOGIN))
|
|
67
|
+
if (event.cookies.readSealed(PENDING_LOGIN, isPendingLogin))
|
|
55
68
|
event.cookies.clear(PENDING_LOGIN, { path: PENDING_LOGIN_PATH });
|
|
56
69
|
const account = persistAccountSession(event, sessionFrom(result, persistent));
|
|
57
70
|
return { user: result.user, account };
|
|
@@ -83,9 +96,9 @@ export async function signup(event: DmsServerEvent) {
|
|
|
83
96
|
*/
|
|
84
97
|
export async function verifyTwoFactor(event: DmsServerEvent) {
|
|
85
98
|
const input = await event.readJson<Input>();
|
|
86
|
-
const pending = event.cookies.readSealed
|
|
99
|
+
const pending = event.cookies.readSealed(PENDING_LOGIN, isPendingLogin);
|
|
87
100
|
const persistent =
|
|
88
|
-
|
|
101
|
+
pending !== undefined && pending.token === input.token
|
|
89
102
|
? isPersistent(pending)
|
|
90
103
|
: true;
|
|
91
104
|
return establishWith(event, "/api/auth/verify-2fa", input, persistent);
|
|
@@ -3,7 +3,16 @@ import type { DmsServerEvent } from "#dms/server";
|
|
|
3
3
|
import { privateSecret } from "../../../server/private-options";
|
|
4
4
|
import { persistAccountSession } from "./accounts";
|
|
5
5
|
import { type SessionTokens, sessionFrom } from "./session";
|
|
6
|
-
import {
|
|
6
|
+
import type {
|
|
7
|
+
NoHandoff,
|
|
8
|
+
NoWorkspaceHandoff,
|
|
9
|
+
TwoFactorHandoff,
|
|
10
|
+
} from "../shared/oauth";
|
|
11
|
+
import {
|
|
12
|
+
isNumber,
|
|
13
|
+
isObject,
|
|
14
|
+
isString,
|
|
15
|
+
} from "../../dms-core/app/utils/type-check";
|
|
7
16
|
|
|
8
17
|
const FLOW = "dms_oauth_flow";
|
|
9
18
|
const HANDOFF = "dms_oauth_handoff";
|
|
@@ -43,6 +52,35 @@ interface OAuthResult extends SessionTokens {
|
|
|
43
52
|
|
|
44
53
|
const attempts = new Map<string, RateWindow>();
|
|
45
54
|
|
|
55
|
+
function isOAuthFlow(value: unknown): value is OAuthFlow {
|
|
56
|
+
return (
|
|
57
|
+
isObject(value) &&
|
|
58
|
+
value !== null &&
|
|
59
|
+
isString(value.state) &&
|
|
60
|
+
isNumber(value.expiresAt) &&
|
|
61
|
+
isString(value.redirect) &&
|
|
62
|
+
isString(value.language) &&
|
|
63
|
+
isString(value.invite)
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function isTextList(value: unknown): value is string[] {
|
|
68
|
+
return Array.isArray(value) && value.every(isString);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function isOAuthHandoff(
|
|
72
|
+
value: unknown,
|
|
73
|
+
): value is TwoFactorHandoff | NoWorkspaceHandoff {
|
|
74
|
+
if (!isObject(value) || value === null) return false;
|
|
75
|
+
if (value.kind === "2fa")
|
|
76
|
+
return isString(value.token) && isTextList(value.methods);
|
|
77
|
+
return (
|
|
78
|
+
value.kind === "no-workspace" &&
|
|
79
|
+
isString(value.token) &&
|
|
80
|
+
isString(value.provider)
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
|
|
46
84
|
function sweepAttempts(now: number) {
|
|
47
85
|
for (const [key, window] of attempts)
|
|
48
86
|
if (now - window.startedAt >= RATE_WINDOW_MS) attempts.delete(key);
|
|
@@ -155,7 +193,6 @@ function sameState(
|
|
|
155
193
|
left: OAuthFlow["state"],
|
|
156
194
|
right: OAuthFlow["state"],
|
|
157
195
|
): boolean {
|
|
158
|
-
if (!isString(left) || !isString(right)) return false;
|
|
159
196
|
const a = Buffer.from(left);
|
|
160
197
|
const b = Buffer.from(right);
|
|
161
198
|
return a.length === b.length && timingSafeEqual(a, b);
|
|
@@ -239,7 +276,7 @@ export async function oauthCallback(event: DmsServerEvent): Promise<Response> {
|
|
|
239
276
|
const { provider } = event.params;
|
|
240
277
|
if (!isValidOAuthProvider(provider) || rateLimited(event, "callback"))
|
|
241
278
|
return errorRedirect(FAILED);
|
|
242
|
-
const flow = event.cookies.readSealed
|
|
279
|
+
const flow = event.cookies.readSealed(FLOW, isOAuthFlow);
|
|
243
280
|
event.cookies.clear(FLOW, { path: FLOW_PATH });
|
|
244
281
|
const query = event.url.searchParams;
|
|
245
282
|
if (query.has("error")) return errorRedirect("error.oauth.cancelled");
|
|
@@ -253,7 +290,8 @@ export async function oauthCallback(event: DmsServerEvent): Promise<Response> {
|
|
|
253
290
|
* finish (a 2FA step, a workspace to pick), once.
|
|
254
291
|
*/
|
|
255
292
|
export function oauthHandoff(event: DmsServerEvent) {
|
|
256
|
-
const handoff
|
|
293
|
+
const handoff: TwoFactorHandoff | NoWorkspaceHandoff | NoHandoff =
|
|
294
|
+
event.cookies.readSealed(HANDOFF, isOAuthHandoff) ?? { kind: "none" };
|
|
257
295
|
event.cookies.clear(HANDOFF, { path: FLOW_PATH });
|
|
258
296
|
return handoff;
|
|
259
297
|
}
|
|
@@ -21,7 +21,6 @@ export interface WatchAction {
|
|
|
21
21
|
component: string;
|
|
22
22
|
event: string;
|
|
23
23
|
functionId: string;
|
|
24
|
-
|
|
25
|
-
params?: Record<string, unknown>;
|
|
24
|
+
params?: object;
|
|
26
25
|
onParam?: WatchActionCondition | WatchActionCondition[];
|
|
27
26
|
}
|
|
@@ -64,6 +64,7 @@
|
|
|
64
64
|
"invite_used": "This invitation was already used. Please log in.",
|
|
65
65
|
"onboarding_already_completed": "Onboarding already completed.",
|
|
66
66
|
"admin_already_set": "An administrator account already exists.",
|
|
67
|
+
"invalid_setup_token": "The setup token is missing or wrong. Use the address in the server log, or the value of DMS_SETUP_TOKEN.",
|
|
67
68
|
"user_creation_failed": "The user account could not be created. Please try again.",
|
|
68
69
|
"settings_not_found": "General settings not found.",
|
|
69
70
|
"token_expired": "The validation code has expired.",
|
|
@@ -64,6 +64,7 @@
|
|
|
64
64
|
"invite_used": "Cette invitation a déjà été utilisée. Veuillez vous connecter.",
|
|
65
65
|
"onboarding_already_completed": "L'onboarding a déjà été completé.",
|
|
66
66
|
"admin_already_set": "Un compte administrateur existe déjà.",
|
|
67
|
+
"invalid_setup_token": "Le jeton d'installation est absent ou incorrect. Utilisez l'adresse affichée dans les logs du serveur, ou la valeur de DMS_SETUP_TOKEN.",
|
|
67
68
|
"user_creation_failed": "Le compte utilisateur n'a pas pu être créé. Veuillez réessayer.",
|
|
68
69
|
"settings_not_found": "Les paramètres généraux n'ont pas été trouvés.",
|
|
69
70
|
"token_expired": "Le code de validation a expiré.",
|
|
@@ -14,6 +14,11 @@ export interface DmsLogoSources {
|
|
|
14
14
|
|
|
15
15
|
/** The logos of an instance, one per place it is drawn. */
|
|
16
16
|
export interface DmsBrandingLogo {
|
|
17
|
+
/**
|
|
18
|
+
* The name a screen reader announces for the logo: the application's name.
|
|
19
|
+
* Set it with a logo of your own.
|
|
20
|
+
*/
|
|
21
|
+
alt?: string;
|
|
17
22
|
/** The expanded sidebar and the auth pages. */
|
|
18
23
|
default: DmsLogoSources;
|
|
19
24
|
/** The icon-only sidebar. */
|
|
@@ -13,6 +13,7 @@ import { useSidebarState } from "./sidebarState";
|
|
|
13
13
|
import { useKeyboardPlatform } from "#dms-ui/app/composables/global/keyboardPlatform";
|
|
14
14
|
import { useMediaQuery } from "@vueuse/core";
|
|
15
15
|
import DmsSidebarUserMenu from "./SidebarUserMenu.vue";
|
|
16
|
+
import { useInstalledModuleCount } from "../../../composables/page/useInstalledModules";
|
|
16
17
|
|
|
17
18
|
const MODULES_PATH = "/modules";
|
|
18
19
|
|
|
@@ -205,14 +206,7 @@ watch(
|
|
|
205
206
|
{ immediate: true },
|
|
206
207
|
);
|
|
207
208
|
|
|
208
|
-
const moduleCount =
|
|
209
|
-
const modulesNode =
|
|
210
|
-
siteLayout.siteLayoutTree.value?.children[MODULES_TREE_KEY];
|
|
211
|
-
if (!modulesNode) return 0;
|
|
212
|
-
return modulesNode.childrenOrders.filter(
|
|
213
|
-
(childId) => modulesNode.children[childId]?.isModuleRoot,
|
|
214
|
-
).length;
|
|
215
|
-
});
|
|
209
|
+
const moduleCount = useInstalledModuleCount();
|
|
216
210
|
|
|
217
211
|
const footerItems = computed((): NavigationMenuItem[] => {
|
|
218
212
|
const result: NavigationMenuItem[] = [];
|
|
@@ -297,7 +291,13 @@ const footerItems = computed((): NavigationMenuItem[] => {
|
|
|
297
291
|
"
|
|
298
292
|
:class="isRail(sidebarRail) ? 'size-7' : 'h-12 w-auto'"
|
|
299
293
|
class="object-contain"
|
|
300
|
-
:alt="
|
|
294
|
+
:alt="
|
|
295
|
+
appConfig.branding?.logo?.alt
|
|
296
|
+
? t('navigation.goToBrandHomepage', {
|
|
297
|
+
name: appConfig.branding.logo.alt,
|
|
298
|
+
})
|
|
299
|
+
: t('navigation.goToHomepage')
|
|
300
|
+
"
|
|
301
301
|
/>
|
|
302
302
|
</DmsLink>
|
|
303
303
|
</template>
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import type { StoreListing } from "#dms-core/app/types/module-store";
|
|
2
|
+
import type { ModuleCatalogEntry } from "#dms-core/app/types/page";
|
|
3
|
+
import type { Ref } from "vue";
|
|
4
|
+
import {
|
|
5
|
+
sortStoreModules,
|
|
6
|
+
storeOnlyModules,
|
|
7
|
+
toModuleStoreEntry,
|
|
8
|
+
withStoreDetails,
|
|
9
|
+
} from "../../build/utils/module-store-catalog";
|
|
10
|
+
import { ENDPOINT_STORE_LISTING } from "./useModuleStore";
|
|
11
|
+
import { useModulesListing } from "./useModulesListing";
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* The installed modules, as the Modules page lists them and the sidebar
|
|
15
|
+
* counts them: the modules that register pages, with the store's details,
|
|
16
|
+
* and the installed store modules that register none, such as the Builder.
|
|
17
|
+
* Both read it here, so the badge and the page never count differently.
|
|
18
|
+
*
|
|
19
|
+
* @param modulesListing The registered modules
|
|
20
|
+
* @param moduleStore The module store
|
|
21
|
+
*/
|
|
22
|
+
export const useInstalledModules = (
|
|
23
|
+
modulesListing: ReturnType<typeof useModulesListing>,
|
|
24
|
+
moduleStore: { listing: Readonly<Ref<StoreListing | undefined>> },
|
|
25
|
+
) => {
|
|
26
|
+
const { locale } = useI18n();
|
|
27
|
+
const { processI18n } = useTranslation();
|
|
28
|
+
|
|
29
|
+
const storeModules = computed(() =>
|
|
30
|
+
sortStoreModules(
|
|
31
|
+
(moduleStore.listing.value?.modules ?? []).map((entry) =>
|
|
32
|
+
toModuleStoreEntry(entry, modulesListing.modules.value ?? []),
|
|
33
|
+
),
|
|
34
|
+
processI18n,
|
|
35
|
+
locale.value,
|
|
36
|
+
),
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
const modules = computed<ModuleCatalogEntry[]>(() => {
|
|
40
|
+
const registered = withStoreDetails(
|
|
41
|
+
(modulesListing.modules.value ?? []).filter((entry) => entry.hasAccess),
|
|
42
|
+
storeModules.value,
|
|
43
|
+
);
|
|
44
|
+
return [...registered, ...storeOnlyModules(storeModules.value, registered)];
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
return { storeModules, modules };
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* How many modules are installed, for the sidebar's badge. The store listing
|
|
52
|
+
* waits on the npm registry, so a server render must not wait for it: the
|
|
53
|
+
* browser reads it, and the count shows once mounted and the read is over,
|
|
54
|
+
* whether it answered or failed. Until then the badge is absent, on the server
|
|
55
|
+
* and on the browser's first render, which a page that handed the listing
|
|
56
|
+
* over (the Modules page) would otherwise have filled in and mismatched, and
|
|
57
|
+
* while the read runs, so the count never shows without the store's modules.
|
|
58
|
+
*/
|
|
59
|
+
export const useInstalledModuleCount = () => {
|
|
60
|
+
const isOwner = useIsOwner();
|
|
61
|
+
const storeListing = useApiData<StoreListing>(
|
|
62
|
+
() => (isOwner.value ? ENDPOINT_STORE_LISTING : null),
|
|
63
|
+
{ server: false },
|
|
64
|
+
);
|
|
65
|
+
const { modules } = useInstalledModules(useModulesListing(), {
|
|
66
|
+
listing: computed(() => storeListing.data.value ?? undefined),
|
|
67
|
+
});
|
|
68
|
+
const isMounted = ref(false);
|
|
69
|
+
onMounted(() => (isMounted.value = true));
|
|
70
|
+
const isSettled = computed(
|
|
71
|
+
() =>
|
|
72
|
+
storeListing.status.value === "success" ||
|
|
73
|
+
storeListing.status.value === "error",
|
|
74
|
+
);
|
|
75
|
+
return computed(() =>
|
|
76
|
+
isMounted.value && isSettled.value ? modules.value.length : 0,
|
|
77
|
+
);
|
|
78
|
+
};
|
|
@@ -20,7 +20,6 @@ import {
|
|
|
20
20
|
useModulesListing,
|
|
21
21
|
} from "../composables/page/useModulesListing";
|
|
22
22
|
import { useModuleHistory } from "../composables/page/useModuleHistory";
|
|
23
|
-
import type { ModuleCatalogEntry } from "#dms-core/app/types/page";
|
|
24
23
|
import {
|
|
25
24
|
MODULE_CATEGORY_ALL,
|
|
26
25
|
MODULE_STORE_PATH,
|
|
@@ -33,13 +32,8 @@ import {
|
|
|
33
32
|
summarizeModules,
|
|
34
33
|
type ModuleSortMode,
|
|
35
34
|
} from "../build/utils/modules-catalog";
|
|
36
|
-
import {
|
|
37
|
-
|
|
38
|
-
storeOnlyModules,
|
|
39
|
-
storeOpenTarget,
|
|
40
|
-
toModuleStoreEntry,
|
|
41
|
-
withStoreDetails,
|
|
42
|
-
} from "../build/utils/module-store-catalog";
|
|
35
|
+
import { storeOpenTarget } from "../build/utils/module-store-catalog";
|
|
36
|
+
import { useInstalledModules } from "../composables/page/useInstalledModules";
|
|
43
37
|
import { useModuleStore } from "../composables/page/useModuleStore";
|
|
44
38
|
import { useModuleStoreActions } from "../composables/page/useModuleStoreActions";
|
|
45
39
|
import DmsSearchInput from "#dms-ui/app/entries/components/form/SearchInput";
|
|
@@ -123,26 +117,13 @@ const isInitiallyLoading = computed(
|
|
|
123
117
|
);
|
|
124
118
|
const isRetrying = ref(false);
|
|
125
119
|
|
|
126
|
-
const storeModules =
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
toModuleStoreEntry(entry, modulesListing.modules.value ?? []),
|
|
130
|
-
),
|
|
131
|
-
processI18n,
|
|
132
|
-
locale.value,
|
|
133
|
-
),
|
|
120
|
+
const { storeModules, modules } = useInstalledModules(
|
|
121
|
+
modulesListing,
|
|
122
|
+
moduleStore,
|
|
134
123
|
);
|
|
135
124
|
const storeEntries = computed(
|
|
136
125
|
() => new Map(storeModules.value.map((entry) => [entry.id, entry])),
|
|
137
126
|
);
|
|
138
|
-
|
|
139
|
-
const modules = computed<ModuleCatalogEntry[]>(() => {
|
|
140
|
-
const registered = withStoreDetails(
|
|
141
|
-
(modulesListing.modules.value ?? []).filter((entry) => entry.hasAccess),
|
|
142
|
-
storeModules.value,
|
|
143
|
-
);
|
|
144
|
-
return [...registered, ...storeOnlyModules(storeModules.value, registered)];
|
|
145
|
-
});
|
|
146
127
|
const summary = computed(() => summarizeModules(modules.value));
|
|
147
128
|
|
|
148
129
|
const visitedAt = computed(
|
|
@@ -23,6 +23,8 @@ import {
|
|
|
23
23
|
|
|
24
24
|
interface RegisterStepProps {
|
|
25
25
|
platform: OnboardingPlatform;
|
|
26
|
+
/** The token the address carried; empty when the wizard has to ask for it. */
|
|
27
|
+
setupToken: string;
|
|
26
28
|
}
|
|
27
29
|
|
|
28
30
|
interface RegisterStepEmits {
|
|
@@ -43,6 +45,7 @@ const MAX_NAME_PART_LENGTH = 100;
|
|
|
43
45
|
|
|
44
46
|
const isLoading = ref(false);
|
|
45
47
|
const isRegistered = ref(false);
|
|
48
|
+
const asksForSetupToken = !props.setupToken;
|
|
46
49
|
|
|
47
50
|
const namePart = z.string().trim().min(1).max(MAX_NAME_PART_LENGTH);
|
|
48
51
|
|
|
@@ -52,12 +55,14 @@ const fields = z
|
|
|
52
55
|
lastName: namePart,
|
|
53
56
|
email: z.string().trim().email(),
|
|
54
57
|
password: passwordSchema,
|
|
58
|
+
setupToken: z.string().trim().min(1),
|
|
55
59
|
})
|
|
56
60
|
.transform((data) => ({
|
|
57
61
|
firstName: striptags(data.firstName),
|
|
58
62
|
lastName: striptags(data.lastName),
|
|
59
63
|
email: striptags(data.email),
|
|
60
64
|
password: data.password,
|
|
65
|
+
setupToken: data.setupToken,
|
|
61
66
|
}));
|
|
62
67
|
|
|
63
68
|
type Schema = z.output<typeof fields>;
|
|
@@ -68,6 +73,7 @@ const state = reactive<Partial<Schema>>({
|
|
|
68
73
|
lastName: undefined,
|
|
69
74
|
email: undefined,
|
|
70
75
|
password: undefined,
|
|
76
|
+
setupToken: props.setupToken,
|
|
71
77
|
});
|
|
72
78
|
useLiveFormErrors(form, state);
|
|
73
79
|
|
|
@@ -106,7 +112,7 @@ async function onSubmit(event: FormSubmitEvent<Schema>) {
|
|
|
106
112
|
}
|
|
107
113
|
|
|
108
114
|
await showError(error, "page.onboarding.administrator.error_title", {
|
|
109
|
-
fields: ["firstName", "lastName", "email", "password"],
|
|
115
|
+
fields: ["firstName", "lastName", "email", "password", "setupToken"],
|
|
110
116
|
form,
|
|
111
117
|
});
|
|
112
118
|
} finally {
|
|
@@ -139,6 +145,20 @@ async function onSubmit(event: FormSubmitEvent<Schema>) {
|
|
|
139
145
|
>
|
|
140
146
|
<AuthFormAlert :error="formError" />
|
|
141
147
|
|
|
148
|
+
<UFormField
|
|
149
|
+
v-if="asksForSetupToken"
|
|
150
|
+
:label="$t('page.onboarding.administrator.setup_token')"
|
|
151
|
+
:help="$t('page.onboarding.administrator.setup_token_help')"
|
|
152
|
+
name="setupToken"
|
|
153
|
+
>
|
|
154
|
+
<UInput
|
|
155
|
+
v-model="state.setupToken"
|
|
156
|
+
autocomplete="off"
|
|
157
|
+
size="lg"
|
|
158
|
+
class="w-full"
|
|
159
|
+
/>
|
|
160
|
+
</UFormField>
|
|
161
|
+
|
|
142
162
|
<div class="grid gap-3 sm:grid-cols-2">
|
|
143
163
|
<UFormField
|
|
144
164
|
:label="$t('page.onboarding.administrator.first_name')"
|