@antelopejs/interface-dms 0.10.3 → 0.12.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 +21 -10
- package/dist/attachments.d.ts +15 -2
- package/dist/attachments.js +14 -1
- package/dist/attachments.js.map +1 -1
- package/dist/auth/db/models/sessions.model.d.ts +7 -5
- package/dist/auth/db/models/sessions.model.js +2 -9
- package/dist/auth/db/models/sessions.model.js.map +1 -1
- package/dist/auth/db/models/userExternalIdentities.model.d.ts +7 -5
- package/dist/auth/db/models/users.model.d.ts +7 -5
- package/dist/auth/db/tables/users.table.d.ts +4 -2
- package/dist/auth/db/tables/users.table.js.map +1 -1
- package/dist/auth/index.d.ts +4 -4
- package/dist/auth/internal/jwt-auth-decorator.d.ts +1 -1
- package/dist/auth/internal/jwt-auth-decorator.js +6 -3
- package/dist/auth/internal/jwt-auth-decorator.js.map +1 -1
- package/dist/auth/internal/request-authenticators.d.ts +12 -0
- package/dist/auth/internal/request-authenticators.js +53 -10
- package/dist/auth/internal/request-authenticators.js.map +1 -1
- package/dist/base/activity-feed.d.ts +34 -32
- package/dist/base/activity-feed.js +2 -0
- package/dist/base/activity-feed.js.map +1 -1
- package/dist/base/banner.d.ts +12 -10
- package/dist/base/banner.js +2 -0
- package/dist/base/banner.js.map +1 -1
- package/dist/base/block-registry/internal/describe.js +3 -9
- package/dist/base/block-registry/internal/describe.js.map +1 -1
- package/dist/base/block-registry/internal/ui.js +1 -1
- package/dist/base/block-registry/internal/ui.js.map +1 -1
- package/dist/base/card.d.ts +11 -9
- package/dist/base/card.js +2 -0
- package/dist/base/card.js.map +1 -1
- package/dist/base/chart-card.d.ts +4 -2
- package/dist/base/chart-card.js +2 -0
- package/dist/base/chart-card.js.map +1 -1
- package/dist/base/chart-schemas.d.ts +148 -148
- package/dist/base/chart.d.ts +65 -0
- package/dist/base/chart.js +65 -0
- package/dist/base/chart.js.map +1 -1
- package/dist/base/code-block.d.ts +5 -3
- package/dist/base/code-block.js +2 -0
- package/dist/base/code-block.js.map +1 -1
- package/dist/base/custom.d.ts +5 -0
- package/dist/base/custom.js +5 -0
- package/dist/base/custom.js.map +1 -1
- package/dist/base/data-types/default/address.d.ts +5 -0
- package/dist/base/data-types/default/address.js +5 -0
- package/dist/base/data-types/default/address.js.map +1 -1
- package/dist/base/data-types/default/choices.d.ts +20 -0
- package/dist/base/data-types/default/choices.js +20 -0
- package/dist/base/data-types/default/choices.js.map +1 -1
- package/dist/base/data-types/default/files.d.ts +22 -5
- package/dist/base/data-types/default/files.js +20 -0
- package/dist/base/data-types/default/files.js.map +1 -1
- package/dist/base/data-types/default/numbers.d.ts +15 -0
- package/dist/base/data-types/default/numbers.js +25 -9
- package/dist/base/data-types/default/numbers.js.map +1 -1
- package/dist/base/data-types/default/relations.d.ts +10 -2
- package/dist/base/data-types/default/relations.js +9 -6
- package/dist/base/data-types/default/relations.js.map +1 -1
- package/dist/base/data-types/default/strings.d.ts +25 -0
- package/dist/base/data-types/default/strings.js +25 -0
- package/dist/base/data-types/default/strings.js.map +1 -1
- package/dist/base/data-types/default-types.d.ts +1 -1
- package/dist/base/data-types/field-types.d.ts +10 -0
- package/dist/base/data-types/field-types.js +10 -0
- package/dist/base/data-types/field-types.js.map +1 -1
- package/dist/base/data-types/internal/relation-endpoints.js +1 -0
- package/dist/base/data-types/internal/relation-endpoints.js.map +1 -1
- package/dist/base/data-types/status-type.d.ts +5 -0
- package/dist/base/data-types/status-type.js +5 -0
- package/dist/base/data-types/status-type.js.map +1 -1
- package/dist/base/display.d.ts +6 -6
- package/dist/base/empty-state.d.ts +15 -13
- package/dist/base/empty-state.js +2 -0
- package/dist/base/empty-state.js.map +1 -1
- package/dist/base/form-block-schema.d.ts +50 -50
- package/dist/base/form-schema.d.ts +2 -0
- package/dist/base/form-schema.js +2 -0
- package/dist/base/form-schema.js.map +1 -1
- package/dist/base/grid.d.ts +4 -0
- package/dist/base/grid.js +4 -0
- package/dist/base/grid.js.map +1 -1
- package/dist/base/guard.d.ts +30 -28
- package/dist/base/guard.js +2 -0
- package/dist/base/guard.js.map +1 -1
- package/dist/base/helpers/archive-mode-helpers.d.ts +1 -1
- package/dist/base/helpers/file-refs.js +15 -15
- package/dist/base/helpers/file-refs.js.map +1 -1
- package/dist/base/internal/form-schema-validation.js +7 -1
- package/dist/base/internal/form-schema-validation.js.map +1 -1
- package/dist/base/internal/realtime-topics.js.map +1 -1
- package/dist/base/internal/searchable.d.ts +2 -1
- package/dist/base/internal/searchable.js +1 -3
- package/dist/base/internal/searchable.js.map +1 -1
- package/dist/base/key-value-list.d.ts +21 -19
- package/dist/base/key-value-list.js +2 -0
- package/dist/base/key-value-list.js.map +1 -1
- package/dist/base/kpi-card.d.ts +4 -2
- package/dist/base/kpi-card.js +2 -0
- package/dist/base/kpi-card.js.map +1 -1
- package/dist/base/live-toggle.d.ts +2 -0
- package/dist/base/live-toggle.js +2 -0
- package/dist/base/live-toggle.js.map +1 -1
- package/dist/base/meter.d.ts +23 -21
- package/dist/base/meter.js +2 -0
- package/dist/base/meter.js.map +1 -1
- package/dist/base/nav-card-grid.d.ts +24 -19
- package/dist/base/nav-card-grid.js +5 -0
- package/dist/base/nav-card-grid.js.map +1 -1
- package/dist/base/page-toolbar.d.ts +2 -0
- package/dist/base/page-toolbar.js +2 -0
- package/dist/base/page-toolbar.js.map +1 -1
- package/dist/base/period-selector.d.ts +3 -1
- package/dist/base/period-selector.js +2 -0
- package/dist/base/period-selector.js.map +1 -1
- package/dist/base/placeholder.d.ts +2 -0
- package/dist/base/placeholder.js +2 -0
- package/dist/base/placeholder.js.map +1 -1
- package/dist/base/resource-form-schema.d.ts +2 -2
- package/dist/base/searchable.d.ts +3 -2
- package/dist/base/searchable.js +2 -2
- package/dist/base/searchable.js.map +1 -1
- package/dist/base/section.d.ts +6 -2
- package/dist/base/section.js +4 -0
- package/dist/base/section.js.map +1 -1
- package/dist/base/stack.d.ts +6 -0
- package/dist/base/stack.js +6 -0
- package/dist/base/stack.js.map +1 -1
- package/dist/base/stat-group.d.ts +16 -14
- package/dist/base/stat-group.js +2 -0
- package/dist/base/stat-group.js.map +1 -1
- package/dist/base/tab.d.ts +10 -8
- package/dist/base/tab.js +2 -0
- package/dist/base/tab.js.map +1 -1
- package/dist/base/table-view/column-display.d.ts +1 -1
- package/dist/base/table-view/column-display.js.map +1 -1
- package/dist/base/table-view/data-functions.d.ts +10 -4
- package/dist/base/table-view/data-functions.js.map +1 -1
- package/dist/base/table-view/factory.d.ts +5 -0
- package/dist/base/table-view/factory.js +8 -4
- package/dist/base/table-view/factory.js.map +1 -1
- package/dist/base/table-view/internal/auth.d.ts +17 -3
- package/dist/base/table-view/internal/auth.js +26 -5
- package/dist/base/table-view/internal/auth.js.map +1 -1
- package/dist/base/table-view/internal/column-conditions.d.ts +8 -1
- package/dist/base/table-view/internal/column-conditions.js +25 -13
- package/dist/base/table-view/internal/column-conditions.js.map +1 -1
- package/dist/base/table-view/internal/column-display.d.ts +1 -2
- package/dist/base/table-view/internal/column-display.js +3 -9
- package/dist/base/table-view/internal/column-display.js.map +1 -1
- package/dist/base/table-view/internal/factory-helpers.d.ts +1 -1
- package/dist/base/table-view/internal/factory-helpers.js +17 -14
- package/dist/base/table-view/internal/factory-helpers.js.map +1 -1
- package/dist/base/table-view/internal/factory-lifecycle-created.d.ts +2 -3
- package/dist/base/table-view/internal/factory-lifecycle-created.js +5 -5
- package/dist/base/table-view/internal/factory-lifecycle-created.js.map +1 -1
- package/dist/base/table-view/internal/factory-lifecycle-filter.d.ts +2 -2
- package/dist/base/table-view/internal/factory-private-actions.d.ts +2 -2
- package/dist/base/table-view/internal/files.d.ts +2 -1
- package/dist/base/table-view/internal/files.js +14 -5
- package/dist/base/table-view/internal/files.js.map +1 -1
- package/dist/base/table-view/internal/footer.d.ts +3 -3
- package/dist/base/table-view/internal/footer.js +16 -15
- package/dist/base/table-view/internal/footer.js.map +1 -1
- package/dist/base/table-view/internal/guards.d.ts +27 -5
- package/dist/base/table-view/internal/guards.js +127 -49
- package/dist/base/table-view/internal/guards.js.map +1 -1
- package/dist/base/table-view/internal/meta-helpers.d.ts +1 -1
- package/dist/base/table-view/internal/meta-helpers.js +3 -4
- package/dist/base/table-view/internal/meta-helpers.js.map +1 -1
- package/dist/base/table-view/internal/meta.js +2 -3
- package/dist/base/table-view/internal/meta.js.map +1 -1
- package/dist/base/table-view/internal/option-contract.d.ts +1 -1
- package/dist/base/table-view/internal/option-footer.d.ts +2 -2
- package/dist/base/table-view/internal/option-row-actions.d.ts +1 -1
- package/dist/base/table-view/internal/realtime.d.ts +52 -11
- package/dist/base/table-view/internal/realtime.js +23 -16
- package/dist/base/table-view/internal/realtime.js.map +1 -1
- package/dist/base/table-view/internal/resource-form.d.ts +1 -1
- package/dist/base/table-view/internal/resource-form.js +1 -1
- package/dist/base/table-view/internal/resource-form.js.map +1 -1
- package/dist/base/table-view/internal/row-actions-schema.d.ts +12 -12
- package/dist/base/table-view/internal/row-rule-shape.d.ts +11 -5
- package/dist/base/table-view/internal/row-rule-shape.js +60 -30
- package/dist/base/table-view/internal/row-rule-shape.js.map +1 -1
- package/dist/base/table-view/internal/row-rules.d.ts +28 -1
- package/dist/base/table-view/internal/row-rules.js +8 -19
- package/dist/base/table-view/internal/row-rules.js.map +1 -1
- package/dist/base/table-view/internal/tabs.d.ts +1 -1
- package/dist/base/table-view/internal/tabs.js +1 -4
- package/dist/base/table-view/internal/tabs.js.map +1 -1
- package/dist/base/table-view/internal/validation.d.ts +2 -2
- package/dist/base/table-view/internal/validation.js +7 -7
- package/dist/base/table-view/internal/validation.js.map +1 -1
- package/dist/base/table-view/meta.d.ts +7 -6
- package/dist/base/table-view/meta.js +12 -7
- package/dist/base/table-view/meta.js.map +1 -1
- package/dist/base/table-view/resource-form.d.ts +3 -1
- package/dist/base/table-view/resource-form.js +2 -0
- package/dist/base/table-view/resource-form.js.map +1 -1
- package/dist/base/table-view/routes.d.ts +73 -21
- package/dist/base/table-view/routes.js +13 -10
- package/dist/base/table-view/routes.js.map +1 -1
- package/dist/base/table-view/schema.d.ts +152 -152
- package/dist/base/table-view/source.js +4 -1
- package/dist/base/table-view/source.js.map +1 -1
- package/dist/base/table-view.d.ts +1 -1
- package/dist/base/table-view.js.map +1 -1
- package/dist/base/top-list-card.d.ts +35 -33
- package/dist/base/top-list-card.js +2 -0
- package/dist/base/top-list-card.js.map +1 -1
- package/dist/base/types/error.js +5 -2
- package/dist/base/types/error.js.map +1 -1
- package/dist/base/types/guards.d.ts +4 -4
- package/dist/base/types/json.d.ts +1 -10
- package/dist/base/types/row-action.d.ts +7 -7
- package/dist/component-options/confirm-dialog.d.ts +2 -0
- package/dist/component-options/confirm-dialog.js.map +1 -1
- package/dist/component-options/data-type.d.ts +2 -2
- package/dist/component-options/data-type.js +7 -7
- package/dist/component-options/data-type.js.map +1 -1
- package/dist/component-options/row-action.d.ts +14 -9
- package/dist/component-slots.d.ts +11 -2
- package/dist/component-slots.js +1 -0
- package/dist/component-slots.js.map +1 -1
- package/dist/component.d.ts +7 -8
- package/dist/component.js +17 -25
- package/dist/component.js.map +1 -1
- package/dist/data-controllers/members.d.ts +11 -7
- package/dist/data-controllers/members.js +1 -1
- package/dist/data-controllers/members.js.map +1 -1
- package/dist/data-controllers/roles.d.ts +32 -10
- package/dist/db/internal/exportJobs.model.d.ts +7 -5
- package/dist/db/internal/inviteResolutions.model.d.ts +7 -5
- package/dist/db/internal/tenantLifecycle.model.d.ts +7 -5
- package/dist/db/models/roles.model.d.ts +7 -5
- package/dist/db/models/tenantMembers.model.d.ts +7 -5
- package/dist/db/models/tenants.model.d.ts +7 -5
- package/dist/db/models/user_invites.model.d.ts +7 -5
- package/dist/db/tables/tenants.table.d.ts +9 -0
- package/dist/db/tables/tenants.table.js +4 -0
- package/dist/db/tables/tenants.table.js.map +1 -1
- package/dist/guards.d.ts +1 -1
- package/dist/hooks.d.ts +10 -9
- package/dist/hooks.js +42 -33
- package/dist/hooks.js.map +1 -1
- package/dist/internal/attachments.d.ts +2 -2
- package/dist/internal/component-builder.js +2 -1
- package/dist/internal/component-builder.js.map +1 -1
- package/dist/internal/component-serialization.d.ts +2 -4
- package/dist/internal/component-serialization.js +4 -3
- package/dist/internal/component-serialization.js.map +1 -1
- package/dist/internal/component-slots.d.ts +19 -2
- package/dist/internal/component-slots.js +35 -12
- package/dist/internal/component-slots.js.map +1 -1
- package/dist/internal/component-watch-filter.d.ts +11 -0
- package/dist/internal/component-watch-filter.js +22 -0
- package/dist/internal/component-watch-filter.js.map +1 -0
- package/dist/internal/component-watches.js +0 -1
- package/dist/internal/component-watches.js.map +1 -1
- package/dist/internal/own-entry.d.ts +7 -0
- package/dist/internal/own-entry.js +13 -0
- package/dist/internal/own-entry.js.map +1 -0
- package/dist/invite-extension-payloads.d.ts +14 -2
- package/dist/invite-extensions/internal/delivery.js +1 -2
- package/dist/invite-extensions/internal/delivery.js.map +1 -1
- package/dist/invite-extensions/internal/edit.d.ts +2 -1
- package/dist/invite-extensions/internal/edit.js +8 -9
- package/dist/invite-extensions/internal/edit.js.map +1 -1
- package/dist/invite-extensions/internal/form-slot.js +8 -15
- package/dist/invite-extensions/internal/form-slot.js.map +1 -1
- package/dist/invite-extensions/internal/payload-slices.d.ts +33 -3
- package/dist/invite-extensions/internal/payload-slices.js +84 -19
- package/dist/invite-extensions/internal/payload-slices.js.map +1 -1
- package/dist/invite-extensions/internal/types.d.ts +10 -1
- package/dist/invite-resolution.js +6 -4
- package/dist/invite-resolution.js.map +1 -1
- package/dist/json.d.ts +10 -0
- package/dist/json.js +3 -0
- package/dist/json.js.map +1 -0
- package/dist/layout-banners.d.ts +5 -2
- package/dist/layout-banners.js.map +1 -1
- package/dist/page/controllers.d.ts +2 -2
- package/dist/page/internal/extension-validation.js +3 -2
- package/dist/page/internal/extension-validation.js.map +1 -1
- package/dist/page/internal/metadata-layout.js +1 -1
- package/dist/page/internal/metadata-layout.js.map +1 -1
- package/dist/page/internal/metadata-publish.js +3 -2
- package/dist/page/internal/metadata-publish.js.map +1 -1
- package/dist/page/internal/metadata-registration.js +5 -4
- package/dist/page/internal/metadata-registration.js.map +1 -1
- package/dist/page/internal/metadata-upload-registration.d.ts +3 -1
- package/dist/page/internal/metadata-upload-registration.js +9 -0
- package/dist/page/internal/metadata-upload-registration.js.map +1 -1
- package/dist/page/internal/metadata-uploads.d.ts +18 -5
- package/dist/page/internal/metadata-uploads.js +7 -8
- package/dist/page/internal/metadata-uploads.js.map +1 -1
- package/dist/page/internal/page-record.d.ts +2 -3
- package/dist/page/internal/page-record.js +19 -14
- package/dist/page/internal/page-record.js.map +1 -1
- package/dist/page/layout-filter.js +17 -6
- package/dist/page/layout-filter.js.map +1 -1
- package/dist/page/metadata.js +5 -7
- package/dist/page/metadata.js.map +1 -1
- package/dist/request-tenant.d.ts +10 -4
- package/dist/request-tenant.js +16 -34
- package/dist/request-tenant.js.map +1 -1
- package/dist/tenant-export.d.ts +2 -1
- package/dist/tenant-lifecycle.d.ts +13 -4
- package/dist/tenant-lifecycle.js +51 -18
- package/dist/tenant-lifecycle.js.map +1 -1
- package/dist/types.d.ts +20 -0
- package/dist/uploads.js +42 -59
- package/dist/uploads.js.map +1 -1
- package/dist/utils/fire-and-forget.js.map +1 -1
- package/dist/utils/internal/decorated-class.d.ts +14 -0
- package/dist/utils/internal/decorated-class.js +37 -0
- package/dist/utils/internal/decorated-class.js.map +1 -0
- package/dist/utils/internal/type-check.d.ts +9 -0
- package/dist/utils/internal/type-check.js +13 -5
- package/dist/utils/internal/type-check.js.map +1 -1
- package/dist/utils/internal/value-parser.d.ts +1 -1
- package/dist/utils/internal/value-parser.js +22 -9
- package/dist/utils/internal/value-parser.js.map +1 -1
- package/dist/watch-actions.d.ts +1 -1
- package/docs/1.core/1.introduction.md +82 -77
- package/docs/1.core/10.layout-banners.md +57 -45
- package/docs/1.core/11.modules-and-dynamic-menus.md +178 -0
- package/docs/1.core/12.frontend-modules-and-request-helpers.md +155 -0
- package/docs/1.core/13.tenant-data-export.md +120 -0
- package/docs/1.core/2.pages-and-modules.md +140 -367
- package/docs/1.core/3.components.md +21 -22
- package/docs/1.core/4.permissions.md +92 -71
- package/docs/1.core/5.tenancy.md +112 -86
- package/docs/1.core/6.invites.md +90 -65
- package/docs/1.core/7.hooks.md +96 -166
- package/docs/1.core/8.realtime.md +44 -45
- package/docs/1.core/9.quick-actions.md +37 -30
- package/docs/2.auth/1.introduction.md +33 -35
- package/docs/2.auth/2.authentication.md +60 -38
- package/docs/2.auth/3.tokens-and-sessions.md +56 -55
- package/docs/2.auth/4.users.md +82 -52
- package/docs/2.auth/5.external-identities.md +25 -26
- package/docs/3.base/1.introduction.md +64 -60
- package/docs/3.base/10.display-blocks.md +15 -16
- package/docs/3.base/11.page-layouts.md +273 -0
- package/docs/3.base/12.table-row-actions.md +122 -0
- package/docs/3.base/13.table-filters-and-forms.md +104 -0
- package/docs/3.base/14.table-events-and-helpers.md +114 -0
- package/docs/3.base/15.table-sources-and-gates.md +24 -0
- package/docs/3.base/2.types.md +44 -41
- package/docs/3.base/3.forms.md +27 -28
- package/docs/3.base/4.tables.md +34 -367
- package/docs/3.base/5.charts-and-widgets.md +28 -29
- package/docs/3.base/6.layout.md +21 -270
- package/docs/3.base/8.data-types.md +39 -40
- package/docs/3.base/9.helpers.md +36 -38
- package/docs/4.notifications/1.introduction.md +22 -26
- package/docs/4.notifications/2.categories-and-subjects.md +58 -55
- package/docs/4.notifications/3.sending.md +72 -68
- package/docs/5.html-render/1.introduction.md +119 -81
- package/docs/5.html-render/2.built-in-emails.md +71 -51
- package/docs/index.md +18 -29
- package/docs/tsconfig.json +4 -0
- package/package.json +12 -12
- package/docs/images/emails-admin-invite.png +0 -0
- package/docs/images/emails-change-notice.png +0 -0
- package/docs/images/emails-change-verification.png +0 -0
- package/docs/images/emails-digest-logo-dark.png +0 -0
- package/docs/images/emails-digest-logo-light.png +0 -0
- package/docs/images/emails-digest.png +0 -0
- package/docs/images/emails-export-partial.png +0 -0
- package/docs/images/emails-export-ready.png +0 -0
- package/docs/images/emails-reset-password.png +0 -0
- package/docs/images/emails-two-factor.png +0 -0
- package/docs/images/emails-user-validation.png +0 -0
package/docs/2.auth/4.users.md
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: "Users"
|
|
3
|
-
description: "The `User` table
|
|
3
|
+
description: "The `User` table and `UserModel`, password hashing and policy, `sanitizeUser`, the account mail functions, and `announceRegistration`."
|
|
4
|
+
mode: reference
|
|
4
5
|
---
|
|
5
6
|
|
|
6
|
-
# Users
|
|
7
|
-
|
|
8
7
|
## Overview
|
|
9
8
|
|
|
10
|
-
The `User` table is the identity record
|
|
9
|
+
The `User` table is the identity record the rest of this interface points at. The authentication decorators resolve a request to a user, the token generators sign for one, and `Session` rows reference one. The table, its constant and its model live in `@antelopejs/interface-dms/auth/db`. The sanitizer and the mail functions live in `@antelopejs/interface-dms/auth`.
|
|
11
10
|
|
|
12
11
|
```typescript
|
|
13
12
|
import { sanitizeUser } from "@antelopejs/interface-dms/auth";
|
|
@@ -18,9 +17,9 @@ import {
|
|
|
18
17
|
} from "@antelopejs/interface-dms/auth/db";
|
|
19
18
|
```
|
|
20
19
|
|
|
21
|
-
## The
|
|
20
|
+
## The user table
|
|
22
21
|
|
|
23
|
-
`User` extends `Table.with(HashModifier)` and is registered as the `users` table
|
|
22
|
+
`User` extends `Table.with(HashModifier)` and is registered as the `users` table in the DMS core schema. Its rows are shared across tenants, and you obtain its model without a tenant instance. `USERS_TABLE_NAME` holds the table name, `"users"`.
|
|
24
23
|
|
|
25
24
|
| Field | Type | Description |
|
|
26
25
|
| ----- | ---- | ----------- |
|
|
@@ -29,32 +28,45 @@ import {
|
|
|
29
28
|
| `updatedAt` | `Date` | Set on write by the update-time decorator. Indexed. |
|
|
30
29
|
| `email` | `string` | Login identifier. Indexed. |
|
|
31
30
|
| `name` | `string` | Display name. |
|
|
32
|
-
| `avatar` | `
|
|
31
|
+
| `avatar` | `ImageValue \| null` | Profile picture as an image value (`{ key, alt? }`) in the default storage, downscaled in the browser to a square of at most 100 by 100 pixels. |
|
|
33
32
|
| `language` | `string` | Preferred language or locale, for example `"en"` or `"fr"`. Indexed. |
|
|
34
|
-
| `
|
|
35
|
-
| `
|
|
33
|
+
| `timeZone` | `string \| null`, optional | IANA time zone that dates and times are shown in, for example `"Europe/Brussels"`. |
|
|
34
|
+
| `weekStart` | `UserWeekStart \| null`, optional | First day of the week in calendars and date pickers: `0` Sunday, `1` Monday, `6` Saturday. |
|
|
35
|
+
| `timeFormat` | `UserTimeFormat \| null`, optional | Clock used for times: `"h23"` for a 24-hour clock, `"h12"` for a 12-hour clock. |
|
|
36
|
+
| `dateFormat` | `UserDateFormat \| null`, optional | How full dates are written: `"numeric"` (01/10/2026) or `"text"` (1 Oct 2026). |
|
|
37
|
+
| `password` | `string \| null` | Hashed by `HashModifier`. Reads back as the hash, not the plaintext. `null` for accounts with no password. |
|
|
38
|
+
| `passwordChangedAt` | `Date \| null` | When the user last set the password, by a change or a recovery. `null` for an account that never changed it since the field was added. |
|
|
39
|
+
| `authKey` | `string` | Per-user secret that is part of the JWT signing secret. Rotating it invalidates every token already issued to the user. |
|
|
36
40
|
| `isValidated` | `boolean` | Whether the email address has been validated. Indexed. |
|
|
37
41
|
| `validationToken` | `string \| null` | Current email-validation code. Indexed. |
|
|
38
42
|
| `validationRequestedAt` | `Date \| null` | When the validation code was issued, for expiry and rate limiting. |
|
|
39
43
|
| `forgotPasswordToken` | `string \| null` | Current password-reset code. Indexed. |
|
|
40
44
|
| `forgotPasswordRequestedAt` | `Date \| null` | When the reset code was issued, for expiry and rate limiting. |
|
|
41
|
-
| `owner` | `boolean` | Platform owner flag.
|
|
45
|
+
| `owner` | `boolean` | Platform owner flag. `AuthOwnerOnly` checks it. See [Authentication](/docs/interfaces/auth/authentication). |
|
|
46
|
+
| `lastActiveAt` | `Date \| null` | The last time the user made a request with a valid access token. The DMS writes it at most once a minute, so it is accurate to that interval. `null` until the first authenticated request. |
|
|
42
47
|
| `twoFactorMethods` | `string[]` | Second factors enabled on the account. |
|
|
43
48
|
| `twoFactorSecret` | `string \| null` | Active TOTP secret. |
|
|
44
|
-
| `twoFactorPendingSecret` | `string \| null` | TOTP secret
|
|
45
|
-
| `twoFactorTotpLastStep` | `number \| null
|
|
49
|
+
| `twoFactorPendingSecret` | `string \| null` | TOTP secret that awaits confirmation during enrollment. |
|
|
50
|
+
| `twoFactorTotpLastStep` | `number \| null`, optional | The 30-second time step of the last TOTP code accepted. A code from that step or an earlier one is refused, so each code works once. Unset until a code is accepted. |
|
|
46
51
|
| `twoFactorBackupCodes` | `string[]` | Remaining single-use backup codes. |
|
|
47
|
-
| `
|
|
52
|
+
| `twoFactorBackupCodesGeneratedAt` | `Date \| null` | When the current set of backup codes was generated. |
|
|
53
|
+
| `twoFactorBackupCodesSavedAt` | `Date \| null` | When the user confirmed they kept the current backup codes, by download, copy or acknowledgment. `null` until then. |
|
|
54
|
+
| `twoFactorEmailCode` | `string \| null` | Hash of the current emailed second-factor code, never the code itself. The hash is the hex SHA-256 of `JSON.stringify([userId, code])`. |
|
|
48
55
|
| `twoFactorEmailCodeRequestedAt` | `Date \| null` | When the emailed code was issued, for expiry and rate limiting. |
|
|
49
56
|
|
|
50
|
-
|
|
57
|
+
`UserWeekStart`, `UserTimeFormat` and `UserDateFormat` are exported next to `User`. `ImageValue` comes from `@antelopejs/interface-dms/types`.
|
|
58
|
+
|
|
59
|
+
The indexed fields are `createdAt`, `updatedAt`, `email`, `language`, `isValidated`, `validationToken` and `forgotPasswordToken`. You can look a user up by these fields through `getAll` on the underlying table or `getBy` on the model. `UserModel.getByEmail` works this way.
|
|
51
60
|
|
|
52
|
-
## Store and
|
|
61
|
+
## Store and check a password
|
|
53
62
|
|
|
54
|
-
`password` carries the `@Hashed` decorator, and the table composes `HashModifier`. Assign a plaintext value on write and
|
|
63
|
+
`password` carries the `@Hashed` decorator, and the table composes `HashModifier`. Assign a plaintext value on write, and the modifier hashes it on the way into the database. Read it back, and you get the hash.
|
|
55
64
|
|
|
56
65
|
```typescript
|
|
57
|
-
import
|
|
66
|
+
import {
|
|
67
|
+
normalizeEmail,
|
|
68
|
+
type UserModel,
|
|
69
|
+
} from "@antelopejs/interface-dms/auth/db";
|
|
58
70
|
import randomstring from "randomstring";
|
|
59
71
|
|
|
60
72
|
const AUTH_KEY_LENGTH = 64;
|
|
@@ -69,7 +81,7 @@ export async function createUser(
|
|
|
69
81
|
createdAt: new Date(),
|
|
70
82
|
updatedAt: new Date(),
|
|
71
83
|
name,
|
|
72
|
-
email: email
|
|
84
|
+
email: normalizeEmail(email),
|
|
73
85
|
password, // hashed by the modifier on insert
|
|
74
86
|
authKey: randomstring.generate({ length: AUTH_KEY_LENGTH }),
|
|
75
87
|
owner: false,
|
|
@@ -79,7 +91,7 @@ export async function createUser(
|
|
|
79
91
|
}
|
|
80
92
|
```
|
|
81
93
|
|
|
82
|
-
To check a candidate password, call `
|
|
94
|
+
To check a candidate password, call `testHashAsync` on the loaded row. The mixin hashes the candidate on the thread pool, with the salt and the cost that the stored hash holds, and compares the result with the stored hash.
|
|
83
95
|
|
|
84
96
|
```typescript
|
|
85
97
|
import { HTTPResult } from "@antelopejs/interface-api";
|
|
@@ -92,27 +104,29 @@ export async function checkCredentials(
|
|
|
92
104
|
email: string,
|
|
93
105
|
password: string,
|
|
94
106
|
) {
|
|
95
|
-
const user = await userModel.getByEmail(email
|
|
96
|
-
if (!user || !user.
|
|
107
|
+
const user = await userModel.getByEmail(email);
|
|
108
|
+
if (!user || !(await user.testHashAsync("password", password))) {
|
|
97
109
|
throw new HTTPResult(UNAUTHORIZED, "error.invalid_credentials");
|
|
98
110
|
}
|
|
99
111
|
return user;
|
|
100
112
|
}
|
|
101
113
|
```
|
|
102
114
|
|
|
103
|
-
|
|
115
|
+
A successful sign-in through `/auth/login` also writes the password again when `isHashOutdated("password")` reports an older hash on the row.
|
|
116
|
+
|
|
117
|
+
Emails are stored trimmed and lowercased. `getByEmail` normalizes its argument itself. Before you write an email, normalize it with `normalizeEmail`, exported next to `UserModel`.
|
|
104
118
|
|
|
105
|
-
## Query
|
|
119
|
+
## Query users with `UserModel`
|
|
106
120
|
|
|
107
|
-
`UserModel` extends `BasicDataModel(User, USERS_TABLE_NAME)
|
|
121
|
+
`UserModel` extends `BasicDataModel(User, USERS_TABLE_NAME)`. It has the standard `get`, `getBy`, `getAll`, `insert`, `update` and `delete` operations, plus three lookups of its own.
|
|
108
122
|
|
|
109
123
|
| Method | Signature | Description |
|
|
110
124
|
| ------ | --------- | ----------- |
|
|
111
|
-
| `getByEmail` | `(email: string) => Promise<User \| undefined>` | The user with this email, trimmed and lowercased
|
|
125
|
+
| `getByEmail` | `(email: string) => Promise<User \| undefined>` | The user with this email, or `undefined`. The email is trimmed and lowercased, then looked up through the `email` index. |
|
|
112
126
|
| `getOwners` | `() => Promise<User[]>` | Every user with `owner === true`. |
|
|
113
127
|
| `countOwnersExcluding` | `(excludedIds: string[]) => Promise<number>` | How many owners remain once the given user ids are set aside. Pass an empty array to count all owners. |
|
|
114
128
|
|
|
115
|
-
`countOwnersExcluding`
|
|
129
|
+
`countOwnersExcluding` serves the last-owner check. Before you remove the owner flag from a set of users, count who would remain, and refuse the operation if the answer is zero.
|
|
116
130
|
|
|
117
131
|
```typescript
|
|
118
132
|
import { HTTPResult } from "@antelopejs/interface-api";
|
|
@@ -132,9 +146,9 @@ export async function demoteOwners(userModel: UserModel, userIds: string[]) {
|
|
|
132
146
|
}
|
|
133
147
|
```
|
|
134
148
|
|
|
135
|
-
## Invalidate
|
|
149
|
+
## Invalidate every token for a user
|
|
136
150
|
|
|
137
|
-
`authKey`
|
|
151
|
+
`authKey` is part of the signing secret of every token issued for the user. Replacing it makes all outstanding access, refresh, two-factor and tenant-assignment tokens fail validation at once. Combine it with `SessionModel.deleteByUserId` from [Tokens and sessions](/docs/interfaces/auth/tokens-and-sessions) to sign a user out everywhere.
|
|
138
152
|
|
|
139
153
|
```typescript
|
|
140
154
|
import type {
|
|
@@ -157,17 +171,25 @@ export async function signOutEverywhere(
|
|
|
157
171
|
}
|
|
158
172
|
```
|
|
159
173
|
|
|
160
|
-
`userModel.update(user)` takes the primary key from the object
|
|
174
|
+
`userModel.update(user)` takes the primary key from the object. The two-argument form `update(id, partial)` updates a subset of fields.
|
|
161
175
|
|
|
162
|
-
## Strip
|
|
176
|
+
## Strip secrets before responding
|
|
163
177
|
|
|
164
|
-
A `User` loaded from the database carries authentication secrets. `sanitizeUser` returns a copy without them
|
|
178
|
+
A `User` loaded from the database carries authentication secrets. `sanitizeUser` returns a copy without them. Return that copy over HTTP.
|
|
165
179
|
|
|
166
|
-
```typescript
|
|
180
|
+
```typescript fragment
|
|
167
181
|
sanitizeUser(user: User): Promise<Partial<User>>
|
|
168
182
|
```
|
|
169
183
|
|
|
170
|
-
It removes
|
|
184
|
+
It removes these fields:
|
|
185
|
+
|
|
186
|
+
- `authKey`;
|
|
187
|
+
- `validationToken` and `validationRequestedAt`;
|
|
188
|
+
- `forgotPasswordToken` and `forgotPasswordRequestedAt`;
|
|
189
|
+
- `twoFactorSecret`, `twoFactorPendingSecret`, `twoFactorTotpLastStep` and `twoFactorBackupCodes`;
|
|
190
|
+
- `twoFactorEmailCode` and `twoFactorEmailCodeRequestedAt`.
|
|
191
|
+
|
|
192
|
+
It also removes the keys the deployment lists in the `userSensitiveKeys` setting of its authentication configuration. A dotted key such as `profile.secret` removes a nested property. Because the removed set is configurable, the return type is `Partial<User>`. Treat every field as possibly absent.
|
|
171
193
|
|
|
172
194
|
```typescript
|
|
173
195
|
import { Controller, Get } from "@antelopejs/interface-api";
|
|
@@ -185,18 +207,26 @@ export class MeController extends Controller("/api/me") {
|
|
|
185
207
|
}
|
|
186
208
|
```
|
|
187
209
|
|
|
188
|
-
## Send
|
|
210
|
+
## Send account emails
|
|
189
211
|
|
|
190
|
-
Four
|
|
212
|
+
Four functions send the account emails the authentication flows depend on. Each returns a promise that resolves once the mail provider accepts the message, and rejects when the provider reports a failure. Decide at each call site whether to await it or send it in the background.
|
|
191
213
|
|
|
192
214
|
| Function | Signature | Sends |
|
|
193
215
|
| -------- | --------- | ----- |
|
|
194
216
|
| `send2FAEmail` | `(user: User, code: string) => Promise<void>` | The emailed second-factor code, to `user.email`. |
|
|
195
|
-
| `sendEmailValidationEmail` | `(user: User) => Promise<void>` | The email-validation message,
|
|
196
|
-
| `sendEmailForgotEmail` | `(user: User) => Promise<void>` | The password-reset message,
|
|
197
|
-
| `sendAdminInviteEmail` | `(email: string, token: string, inviteeName?: string) => Promise<void>` | An invite
|
|
217
|
+
| `sendEmailValidationEmail` | `(user: User) => Promise<void>` | The email-validation message, with the `validationToken` currently stored on the user. |
|
|
218
|
+
| `sendEmailForgotEmail` | `(user: User) => Promise<void>` | The password-reset message, with the `forgotPasswordToken` currently stored on the user. |
|
|
219
|
+
| `sendAdminInviteEmail` | `(email: string, token: string, inviteeName?: string, context?: AdminInviteEmailContext) => Promise<void>` | An invite with a signup link built from `token`, to an address that has no user row yet. `inviteeName` addresses the invitee by name when the invite carried one. |
|
|
220
|
+
|
|
221
|
+
`AdminInviteEmailContext` has three optional fields. Without them, the invite email keeps its generic wording.
|
|
198
222
|
|
|
199
|
-
|
|
223
|
+
| Field | Type | Description |
|
|
224
|
+
| ----- | ---- | ----------- |
|
|
225
|
+
| `workspaceName` | `string` | The workspace the invitee joins. |
|
|
226
|
+
| `inviterName` | `string` | Who sent the invitation. |
|
|
227
|
+
| `language` | `string` | The invitee's language (`en`, `fr`, and others). English when the language is not supported. |
|
|
228
|
+
|
|
229
|
+
`sendEmailValidationEmail` and `sendEmailForgotEmail` read the code from the user. Generate the code, persist it, and only then send.
|
|
200
230
|
|
|
201
231
|
```typescript
|
|
202
232
|
import { sendEmailForgotEmail } from "@antelopejs/interface-dms/auth";
|
|
@@ -209,7 +239,7 @@ export async function requestPasswordReset(
|
|
|
209
239
|
userModel: UserModel,
|
|
210
240
|
email: string,
|
|
211
241
|
) {
|
|
212
|
-
const user = await userModel.getByEmail(email
|
|
242
|
+
const user = await userModel.getByEmail(email);
|
|
213
243
|
if (!user) return; // answer identically whether or not the address exists
|
|
214
244
|
|
|
215
245
|
user.forgotPasswordToken = randomstring.generate({
|
|
@@ -223,23 +253,23 @@ export async function requestPasswordReset(
|
|
|
223
253
|
}
|
|
224
254
|
```
|
|
225
255
|
|
|
226
|
-
`sendAdminInviteEmail` takes a bare address and a token instead of a `User`, because an invitee has no user row until they sign up. The invite record
|
|
256
|
+
`sendAdminInviteEmail` takes a bare address and a token instead of a `User`, because an invitee has no user row until they sign up. The invite record, its token and its expiry belong to the [Core](/docs/interfaces/core/invites) domain, whose `inviteUserToTenant` sends this email for you.
|
|
227
257
|
|
|
228
|
-
## Password
|
|
258
|
+
## Password policy
|
|
229
259
|
|
|
230
|
-
`@antelopejs/interface-dms/auth/password` exports the policy every DMS flow applies when a password is set
|
|
260
|
+
`@antelopejs/interface-dms/auth/password` exports the policy every DMS flow applies when a password is set. A password needs at least `PASSWORD_MIN_LENGTH` (8) characters, with at least one uppercase letter, one digit, and one of `@$!%*?&`. It may contain only ASCII letters, digits and those special characters. `PASSWORD_PATTERN` holds the character rules without the length.
|
|
231
261
|
|
|
232
|
-
```typescript
|
|
262
|
+
```typescript fragment
|
|
233
263
|
isPasswordCompliant(password: string): boolean
|
|
234
264
|
```
|
|
235
265
|
|
|
236
|
-
|
|
266
|
+
`isPasswordCompliant` is a pure function, not an interface call, so it works without the DMS loaded. Call it from any flow you own that stores a password, such as a public signup, before you hash the password. Your module then accepts exactly the passwords the DMS accepts.
|
|
237
267
|
|
|
238
|
-
## Announce a
|
|
268
|
+
## Announce a registration
|
|
239
269
|
|
|
240
|
-
`announceRegistration` runs
|
|
270
|
+
`announceRegistration` runs what must happen once an account has joined a tenant. It sends the welcome notification and the collaborator notification to the platform owners, then fires the `USER_REGISTERED` hook with `tenantId`, `userId`, `email` and `name`.
|
|
241
271
|
|
|
242
|
-
```typescript
|
|
272
|
+
```typescript fragment
|
|
243
273
|
announceRegistration(
|
|
244
274
|
userModel: UserModel,
|
|
245
275
|
user: User,
|
|
@@ -247,10 +277,10 @@ announceRegistration(
|
|
|
247
277
|
): Promise<void>
|
|
248
278
|
```
|
|
249
279
|
|
|
250
|
-
Call it from any registration flow you own
|
|
280
|
+
Call it from any registration flow you own: a module with its own signup, or a SaaS transactional flow once provisioning has committed. The DMS password signup and a provider login that consumes an invitation both go through it. Notifications and automations therefore run the same way, whichever flow created the account.
|
|
251
281
|
|
|
252
|
-
The hook
|
|
282
|
+
The hook only observes. Registration is already complete when it runs, so a failing subscriber is logged and does not fail the request. Failing the request would leave a user whose account exists but whose retry token is gone. The notifications are sent in the background, and a failure there is logged, not propagated.
|
|
253
283
|
|
|
254
|
-
## Next
|
|
284
|
+
## Next steps
|
|
255
285
|
|
|
256
|
-
[External
|
|
286
|
+
[External identities](/docs/interfaces/auth/external-identities) covers binding a user to the accounts they own on a login provider.
|
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
---
|
|
2
|
-
title: "External
|
|
3
|
-
description: "
|
|
2
|
+
title: "External identities"
|
|
3
|
+
description: "Bind the accounts a user owns on external login providers, list them, and read the `UserExternalIdentity` table and model."
|
|
4
|
+
mode: reference
|
|
4
5
|
---
|
|
5
6
|
|
|
6
|
-
# External Identities
|
|
7
|
-
|
|
8
7
|
## Overview
|
|
9
8
|
|
|
10
|
-
An external identity binds an account a user owns on a login provider
|
|
9
|
+
An external identity binds an account a user owns on a login provider, such as GitHub, Google, or any provider the deployment configures, to a `User` row. Signing in through that provider then resolves to the same account every time. The provider login flow reads the binding. The provider account id identifies it, not the email.
|
|
11
10
|
|
|
12
|
-
The two functions live
|
|
11
|
+
The two functions live in `@antelopejs/interface-dms/auth`. The table and its model live in `@antelopejs/interface-dms/auth/db`.
|
|
13
12
|
|
|
14
13
|
```typescript
|
|
15
14
|
import {
|
|
@@ -24,11 +23,11 @@ import {
|
|
|
24
23
|
} from "@antelopejs/interface-dms/auth/db";
|
|
25
24
|
```
|
|
26
25
|
|
|
27
|
-
|
|
26
|
+
These rows serve authentication only. A provider connection behind a product feature, such as repository access or deployments, owns its own storage and must never be derived from these rows. They say who the user is, not what the deployment may do on the user's behalf.
|
|
28
27
|
|
|
29
|
-
## Bind a
|
|
28
|
+
## Bind a provider account
|
|
30
29
|
|
|
31
|
-
```typescript
|
|
30
|
+
```typescript fragment
|
|
32
31
|
linkExternalIdentity(
|
|
33
32
|
userId: string,
|
|
34
33
|
identity: ExternalIdentityInput,
|
|
@@ -49,13 +48,13 @@ interface ExternalIdentityLinkResult {
|
|
|
49
48
|
|
|
50
49
|
| Field | Description |
|
|
51
50
|
| ----- | ----------- |
|
|
52
|
-
| `provider` | Provider identifier, as declared in the
|
|
53
|
-
| `providerAccountId` | Immutable account identifier on the provider side. Never the email
|
|
51
|
+
| `provider` | Provider identifier, as declared in the OAuth configuration of the instance. |
|
|
52
|
+
| `providerAccountId` | Immutable account identifier on the provider side. Never the email, because users change their provider email without changing account. |
|
|
54
53
|
| `email` | Email the provider reported, stored lowercased for support and audit only. |
|
|
55
54
|
|
|
56
|
-
`wasCreated`
|
|
55
|
+
`wasCreated` is `true` for a first binding and `false` for a refresh. A login flow reads it to tell whether the user just connected a new provider or signed in again.
|
|
57
56
|
|
|
58
|
-
```typescript
|
|
57
|
+
```typescript fragment
|
|
59
58
|
import { linkExternalIdentity } from "@antelopejs/interface-dms/auth";
|
|
60
59
|
|
|
61
60
|
const { wasCreated } = await linkExternalIdentity(user._id, {
|
|
@@ -65,25 +64,25 @@ const { wasCreated } = await linkExternalIdentity(user._id, {
|
|
|
65
64
|
});
|
|
66
65
|
```
|
|
67
66
|
|
|
68
|
-
The call is idempotent for the owning user
|
|
67
|
+
The call is idempotent for the owning user. Linking the same provider account again only refreshes its `email` and `lastLoginAt`. Binding an account that another user already owns throws `409` with the message `error.oauth.identity_already_linked`, because a provider account is a single-user credential.
|
|
69
68
|
|
|
70
|
-
|
|
69
|
+
The deterministic primary key of the row enforces uniqueness, not a secondary index. Two concurrent bindings of the same provider account therefore collide instead of creating a duplicate. The call that loses reads the row again, and either refreshes it or throws the `409`.
|
|
71
70
|
|
|
72
|
-
## List a
|
|
71
|
+
## List a user's identities
|
|
73
72
|
|
|
74
|
-
```typescript
|
|
73
|
+
```typescript fragment
|
|
75
74
|
getExternalIdentities(userId: string): Promise<UserExternalIdentity[]>
|
|
76
75
|
```
|
|
77
76
|
|
|
78
|
-
|
|
77
|
+
It returns an empty array for a user who only signs in with a password. An account settings screen reads it to decide whether to offer disconnecting a provider.
|
|
79
78
|
|
|
80
|
-
## The `UserExternalIdentity`
|
|
79
|
+
## The `UserExternalIdentity` table
|
|
81
80
|
|
|
82
|
-
Table `user_external_identities` in the DMS core schema
|
|
81
|
+
Table `user_external_identities` in the DMS core schema. Like `users`, its rows are shared across tenants. `USER_EXTERNAL_IDENTITIES_TABLE_NAME` holds the name.
|
|
83
82
|
|
|
84
83
|
| Field | Type | Description |
|
|
85
84
|
| ----- | ---- | ----------- |
|
|
86
|
-
| `_id` | `string` | `<provider>:<providerAccountId>`.
|
|
85
|
+
| `_id` | `string` | `<provider>:<providerAccountId>`. As the primary key, it makes the binding unique. |
|
|
87
86
|
| `userId` | `string` | Owning user. Indexed, related to `User`. |
|
|
88
87
|
| `provider` | `string` | Provider identifier. |
|
|
89
88
|
| `providerAccountId` | `string` | Account identifier on the provider side. |
|
|
@@ -91,7 +90,7 @@ Table `user_external_identities` in the DMS core schema, so its rows are shared
|
|
|
91
90
|
| `createdAt` | `Date` | Set on insert. Indexed. |
|
|
92
91
|
| `lastLoginAt` | `Date` | Refreshed on every successful login through this identity. |
|
|
93
92
|
|
|
94
|
-
`buildExternalIdentityId(provider, providerAccountId)` composes the id. Use it
|
|
93
|
+
`buildExternalIdentityId(provider, providerAccountId)` composes the id. Use it instead of formatting the string yourself, so a lookup by id keeps matching what `linkExternalIdentity` writes.
|
|
95
94
|
|
|
96
95
|
## `UserExternalIdentityModel`
|
|
97
96
|
|
|
@@ -101,11 +100,11 @@ Table `user_external_identities` in the DMS core schema, so its rows are shared
|
|
|
101
100
|
| ------ | --------- | ----------- |
|
|
102
101
|
| `getByProviderAccount` | `(provider: string, providerAccountId: string) => Promise<UserExternalIdentity \| undefined>` | The identity a provider account is bound to, or `undefined` when the account is unknown. |
|
|
103
102
|
| `getByUserId` | `(userId: string) => Promise<UserExternalIdentity[]>` | Every identity bound to a user, read through the `userId` index. |
|
|
104
|
-
| `deleteByUserId` | `(userId: string) => Promise<void>` |
|
|
103
|
+
| `deleteByUserId` | `(userId: string) => Promise<void>` | Deletes every identity of a user. |
|
|
105
104
|
|
|
106
|
-
`getByProviderAccount` is the login
|
|
105
|
+
`getByProviderAccount` is the lookup on the login side. Resolve the provider profile to an identity, then its `userId` to the account to sign in.
|
|
107
106
|
|
|
108
|
-
```typescript
|
|
107
|
+
```typescript fragment
|
|
109
108
|
import { GetModel } from "@antelopejs/interface-database-decorators";
|
|
110
109
|
import {
|
|
111
110
|
UserExternalIdentityModel,
|
|
@@ -119,4 +118,4 @@ const user = identity
|
|
|
119
118
|
: undefined;
|
|
120
119
|
```
|
|
121
120
|
|
|
122
|
-
An unknown provider account means no account exists for it yet
|
|
121
|
+
An unknown provider account means no account exists for it yet. Hand the flow to signup or to invite redemption, and do not create an account implicitly. `deleteByUserId` belongs to account deletion. Identities left behind would let a recycled provider account resolve to a user row that no longer exists.
|
|
@@ -1,52 +1,51 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: "Introduction"
|
|
3
3
|
description: "The base domain is the component vocabulary of the DMS: forms, tables, charts and cards, layout containers, data types and shared prop types."
|
|
4
|
+
mode: explanation
|
|
4
5
|
---
|
|
5
6
|
|
|
6
|
-
# Introduction
|
|
7
|
-
|
|
8
7
|
## Overview
|
|
9
8
|
|
|
10
9
|
The `base` domain of `@antelopejs/interface-dms` is the component vocabulary of the DMS: forms, tables, charts and cards, layout containers, trees, the data types behind every field, and the shared prop types they all draw from.
|
|
11
10
|
|
|
12
|
-
Every component here is a builder. `Form({...})`, `TableView(controller, {...})` and `ChartLine({...})` do not render anything
|
|
11
|
+
Every component here is a builder. `Form({...})`, `TableView(controller, {...})` and `ChartLine({...})` do not render anything. They return a `ComponentBuilder` from `@antelopejs/interface-dms/component`, which is a serializable description of a component: its name, its options, and its children. You assign that description to a static field of a page class, and the frontend reads the page's tree and draws it. The options you set are therefore data, and the components that need data are given a `fetchUrl` and a `submitUrl` pointing back at routes you declare on the same page or on a data controller.
|
|
13
12
|
|
|
14
|
-
Two consequences shape the whole domain. First, a component's contract is its props interface: what you can express is exactly what the props allow, which is why this reference documents them field by field. Second, anything the frontend must receive has to survive serialization, so a builder that accepts a nested `Component
|
|
13
|
+
Two consequences shape the whole domain. First, a component's contract is its props interface: what you can express is exactly what the props allow, which is why this reference documents them field by field. Second, anything the frontend must receive has to survive serialization, so a builder that accepts a nested `Component`, such as a modal target, a kanban card or a chart inside a card, stores its serialized form instead.
|
|
15
14
|
|
|
16
15
|
The DMS documentation carries task-shaped chapters on the same components, organised around what you are building. This folder is the contract behind them: the exact symbol names, option fields and return types.
|
|
17
16
|
|
|
18
|
-
### Subpath
|
|
17
|
+
### Subpath map
|
|
19
18
|
|
|
20
19
|
`@antelopejs/interface-dms/base` is the barrel over the modules below, and re-exports most of them. The ones marked as not in the barrel are imported from their own subpath. Every row is a subpath of `@antelopejs/interface-dms/base`.
|
|
21
20
|
|
|
22
21
|
| Subpath | Holds | In the root barrel | Documented in |
|
|
23
22
|
| --- | --- | --- | --- |
|
|
24
|
-
| `types` | Base props, colours, tones (`TONES`, `Tone`, `ICON_TONES`, `IconTone`), sizes, buttons, action targets, row-action rules, guards, watch actions, enums | yes | [Shared
|
|
23
|
+
| `types` | Base props, colours, tones (`TONES`, `Tone`, `ICON_TONES`, `IconTone`), sizes, buttons, action targets, row-action rules, guards, watch actions, enums | yes | [Shared types](/docs/interfaces/base/types) |
|
|
25
24
|
| `form` | `Form`, the field and group shapes, `FormComponents`, `FormEvents`, the schema helpers | yes | [Forms](/docs/interfaces/base/forms) |
|
|
26
25
|
| `table-view` | `TableView`, `@Column`, `TableViewRoutes`, guards, row actions | yes | [Tables](/docs/interfaces/base/tables) |
|
|
27
|
-
| `chart` | Chart builders, series and point shapes, chart props | yes | [Charts and
|
|
28
|
-
| `chart-card` | `ChartCard` | yes | [Charts and
|
|
29
|
-
| `kpi-card` | `KpiCard` | yes | [Charts and
|
|
30
|
-
| `top-list-card` | `TopListCard` | yes | [Charts and
|
|
31
|
-
| `period-selector` | `PeriodSelector` | yes | [Charts and
|
|
32
|
-
| `live-toggle` | `LiveToggle` | yes | [Display
|
|
33
|
-
| `page-toolbar` | `PageToolbar`, `pageToolbar` | yes | [Display
|
|
34
|
-
| `grid` | `Grid`, `GridRow` | yes | [Layout and
|
|
35
|
-
| `stack` | `HStack`, `VStack`, `Spacer` | yes | [Layout and
|
|
36
|
-
| `tab` | `Tab` | yes | [Layout and
|
|
37
|
-
| `guard` | `Guard` | yes | [Layout and
|
|
38
|
-
| `layouts` | `DefaultLayout`, `FormPageLayout`, `SettingsLayout`, `EmptyLayout` | yes | [Layout and
|
|
39
|
-
| `placeholder` | `Placeholder` | yes | [Layout and
|
|
40
|
-
| `display` | `BlockLinkAction`, `BlockItemsSource`, `BlockEmptyText` | yes | [Display
|
|
41
|
-
| `stat-group` | `StatGroup` | yes | [Display
|
|
42
|
-
| `key-value-list` | `KeyValueList` | yes | [Display
|
|
43
|
-
| `nav-card-grid` | `NavCardGrid` | yes | [Display
|
|
44
|
-
| `empty-state` | `EmptyState` | yes | [Display
|
|
45
|
-
| `banner` | `Banner` | yes | [Display
|
|
46
|
-
| `card` | `Card` | yes | [Display
|
|
47
|
-
| `code-block` | `CodeBlock` | yes | [Display
|
|
48
|
-
| `custom` | `CustomComponent` | no | [Layout and
|
|
49
|
-
| `data-types` | `DataType`, the registration decorators, `DefaultDataTypes`, `DefaultDataCompareTypes`, `StatusType` | no | [Data
|
|
26
|
+
| `chart` | Chart builders, series and point shapes, chart props | yes | [Charts and widgets](/docs/interfaces/base/charts-and-widgets) |
|
|
27
|
+
| `chart-card` | `ChartCard` | yes | [Charts and widgets](/docs/interfaces/base/charts-and-widgets) |
|
|
28
|
+
| `kpi-card` | `KpiCard` | yes | [Charts and widgets](/docs/interfaces/base/charts-and-widgets) |
|
|
29
|
+
| `top-list-card` | `TopListCard` | yes | [Charts and widgets](/docs/interfaces/base/charts-and-widgets) |
|
|
30
|
+
| `period-selector` | `PeriodSelector` | yes | [Charts and widgets](/docs/interfaces/base/charts-and-widgets) |
|
|
31
|
+
| `live-toggle` | `LiveToggle` | yes | [Display blocks](/docs/interfaces/base/display-blocks#live-toggle) |
|
|
32
|
+
| `page-toolbar` | `PageToolbar`, `pageToolbar` | yes | [Display blocks](/docs/interfaces/base/display-blocks#page-toolbar) |
|
|
33
|
+
| `grid` | `Grid`, `GridRow` | yes | [Layout and containers](/docs/interfaces/base/layout) |
|
|
34
|
+
| `stack` | `HStack`, `VStack`, `Spacer` | yes | [Layout and containers](/docs/interfaces/base/layout) |
|
|
35
|
+
| `tab` | `Tab` | yes | [Layout and containers](/docs/interfaces/base/layout) |
|
|
36
|
+
| `guard` | `Guard` | yes | [Layout and containers](/docs/interfaces/base/layout#guard) |
|
|
37
|
+
| `layouts` | `DefaultLayout`, `FormPageLayout`, `SettingsLayout`, `EmptyLayout` | yes | [Layout and containers](/docs/interfaces/base/layout) |
|
|
38
|
+
| `placeholder` | `Placeholder` | yes | [Layout and containers](/docs/interfaces/base/layout) |
|
|
39
|
+
| `display` | `BlockLinkAction`, `BlockItemsSource`, `BlockEmptyText` | yes | [Display blocks](/docs/interfaces/base/display-blocks) |
|
|
40
|
+
| `stat-group` | `StatGroup` | yes | [Display blocks](/docs/interfaces/base/display-blocks) |
|
|
41
|
+
| `key-value-list` | `KeyValueList` | yes | [Display blocks](/docs/interfaces/base/display-blocks) |
|
|
42
|
+
| `nav-card-grid` | `NavCardGrid` | yes | [Display blocks](/docs/interfaces/base/display-blocks) |
|
|
43
|
+
| `empty-state` | `EmptyState` | yes | [Display blocks](/docs/interfaces/base/display-blocks) |
|
|
44
|
+
| `banner` | `Banner` | yes | [Display blocks](/docs/interfaces/base/display-blocks) |
|
|
45
|
+
| `card` | `Card` | yes | [Display blocks](/docs/interfaces/base/display-blocks) |
|
|
46
|
+
| `code-block` | `CodeBlock` | yes | [Display blocks](/docs/interfaces/base/display-blocks) |
|
|
47
|
+
| `custom` | `CustomComponent` | no | [Layout and containers](/docs/interfaces/base/layout) |
|
|
48
|
+
| `data-types` | `DataType`, the registration decorators, `DefaultDataTypes`, `DefaultDataCompareTypes`, `StatusType` | no | [Data types](/docs/interfaces/base/data-types) |
|
|
50
49
|
| `searchable` | `Searchable`, `SearchableMeta` | yes | [Helpers](/docs/interfaces/base/helpers) |
|
|
51
50
|
| `export-jobs` | `runExportJob` and the export-job lifecycle | yes | [Helpers](/docs/interfaces/base/helpers) |
|
|
52
51
|
| `tenant-export-archive` | `startTenantExportJob`, `buildTenantExportArchive` | yes | [Helpers](/docs/interfaces/base/helpers) |
|
|
@@ -55,33 +54,33 @@ The DMS documentation carries task-shaped chapters on the same components, organ
|
|
|
55
54
|
|
|
56
55
|
Within `types`, four modules are outside that subpath's barrel and are imported from `types/action-target`, `types/row-action`, `types/row-action-operators` and `types/guards`; the guard types and `RowActionRule` are also re-exported by `table-view`.
|
|
57
56
|
|
|
58
|
-
##
|
|
57
|
+
## What the package provides
|
|
59
58
|
|
|
60
|
-
- **Builders that produce data
|
|
61
|
-
- **Forms from typed fields
|
|
62
|
-
- **Tables from data controllers
|
|
63
|
-
- **Server-enforced row rules and guards
|
|
64
|
-
- **A chart and widget set with a shared period scope
|
|
65
|
-
- **Layout without a frontend build
|
|
66
|
-
- **An extensible data-type registry
|
|
67
|
-
- **Shared prop vocabulary
|
|
59
|
+
- **Builders that produce data.** Every component function returns a `ComponentBuilder`, so a page's UI is a plain value you can factor, reuse and compose with `.child()`.
|
|
60
|
+
- **Forms from typed fields.** A field names a `DataType`, and the type supplies both the input component and the Zod schema; `Form` compiles the field list into one schema and ships its JSON Schema form with the component.
|
|
61
|
+
- **Tables from data controllers.** `TableView` reads a controller's data-api metadata and its `@Column` declarations to build the columns, the `new` / `edit` / `view` forms, and the permission-carrying actions in one call.
|
|
62
|
+
- **Server-enforced row rules and guards.** Row-action rules are a small algebra evaluated on both sides, and guards run inside the mutating routes, so what the row menu offers is what the server accepts.
|
|
63
|
+
- **A chart and widget set with a shared period scope.** Thirteen chart types plus KPI, chart and top-list cards; one `PeriodSelector` id ties them to the same range and comparison.
|
|
64
|
+
- **Layout without a frontend build.** Grids, stacks, tabs and page layouts arrange components, and `CustomComponent` names a Vue component when the vocabulary runs out.
|
|
65
|
+
- **An extensible data-type registry.** `@RegisterDataType` and `@RegisterDataCompareMode` add your own types and filter operators to the catalogue the forms, columns and filters draw from.
|
|
66
|
+
- **Shared prop vocabulary.** Colors, sizes, HTTP methods, action targets, readonly behaviour and watch actions are declared once in `types` and reused by every component.
|
|
68
67
|
|
|
69
68
|
## Dependencies
|
|
70
69
|
|
|
71
70
|
This interface relies on the following AntelopeJS packages:
|
|
72
71
|
|
|
73
|
-
- [
|
|
74
|
-
- [
|
|
75
|
-
- [
|
|
76
|
-
- [
|
|
77
|
-
- [
|
|
78
|
-
- [
|
|
79
|
-
- [
|
|
80
|
-
- [zod](https://www.npmjs.com/package/zod) and [zod-to-json-schema](https://www.npmjs.com/package/zod-to-json-schema) - Field validation schemas and their JSON Schema form.
|
|
72
|
+
- [`@antelopejs/interface-api`](https://github.com/AntelopeJS/interface-api): Request context, controller metadata and route parameters.
|
|
73
|
+
- [`@antelopejs/interface-api-util`](https://github.com/AntelopeJS/interface-api-util): `assert` for failing a route with an HTTP status.
|
|
74
|
+
- [`@antelopejs/interface-core`](https://github.com/AntelopeJS/interface-core): Metadata storage, decorator factories, interface functions and logging.
|
|
75
|
+
- [`@antelopejs/interface-data-api`](https://github.com/AntelopeJS/interface-data-api): Data controllers, default routes, list parameters and field metadata.
|
|
76
|
+
- [`@antelopejs/interface-database`](https://github.com/AntelopeJS/interface-database): The value proxies compare modes build their filters from.
|
|
77
|
+
- [`@antelopejs/interface-database-decorators`](https://github.com/AntelopeJS/interface-database-decorators): Models and the localization modifier.
|
|
78
|
+
- [`@antelopejs/interface-file-storage`](https://github.com/AntelopeJS/interface-file-storage): Upload constraints, staged-key promotion and file deletion behind the file and image types.
|
|
79
|
+
- [`zod`](https://www.npmjs.com/package/zod) and [`zod-to-json-schema`](https://www.npmjs.com/package/zod-to-json-schema) - Field validation schemas and their JSON Schema form.
|
|
81
80
|
|
|
82
81
|
It also builds on other domains of the same package: `/component` for `Component` and `ComponentBuilder`, `/page` for the page a component is registered on, `/permissions` for the action permissions a table view declares, and `/auth` for the authenticated user its routes receive.
|
|
83
82
|
|
|
84
|
-
##
|
|
83
|
+
## A first page
|
|
85
84
|
|
|
86
85
|
A page declaring one component. The `Form` builder describes the fields; the two routes on the same class serve and accept the values. Define the backing model first; `SettingsModel` is application code, not a DMS export.
|
|
87
86
|
|
|
@@ -108,7 +107,7 @@ export class SettingsModel extends BasicDataModel(Settings, "settings") {}
|
|
|
108
107
|
|
|
109
108
|
The page edits one module-wide record, so restrict it to platform owners. It returns defaults before the first save and upserts only `SETTINGS_ROW_ID`, rather than updating every row in the table.
|
|
110
109
|
|
|
111
|
-
```typescript [settings-page.ts]
|
|
110
|
+
```typescript fragment [settings-page.ts]
|
|
112
111
|
import { Get, JSONBody, Post } from "@antelopejs/interface-api";
|
|
113
112
|
import { assert } from "@antelopejs/interface-api-util";
|
|
114
113
|
import { GetModel } from "@antelopejs/interface-database-decorators";
|
|
@@ -180,7 +179,7 @@ export class SettingsPage extends PageController(
|
|
|
180
179
|
|
|
181
180
|
Import the page and provision the schema from your module's entry file. Merge this into an existing `start()` if your module already has one:
|
|
182
181
|
|
|
183
|
-
```typescript [index.ts]
|
|
182
|
+
```typescript fragment [index.ts]
|
|
184
183
|
import "./settings-page";
|
|
185
184
|
import { RegisterSchema } from "@antelopejs/interface-database-decorators";
|
|
186
185
|
import { SETTINGS_SCHEMA } from "./db";
|
|
@@ -190,14 +189,19 @@ export async function start(): Promise<void> {
|
|
|
190
189
|
}
|
|
191
190
|
```
|
|
192
191
|
|
|
193
|
-
The page registers itself at import time, and its routes are mounted under the page's slug
|
|
194
|
-
|
|
195
|
-
##
|
|
196
|
-
|
|
197
|
-
- [Shared
|
|
198
|
-
- [Forms](/docs/interfaces/base/forms)
|
|
199
|
-
- [Tables](/docs/interfaces/base/tables)
|
|
200
|
-
- [
|
|
201
|
-
- [
|
|
202
|
-
- [
|
|
203
|
-
- [
|
|
192
|
+
The page registers itself at import time, and its routes are mounted under the page's slug, so the form fetches from and submits to `/settings/`. `Form` serializes the field descriptions and JSON Schema for the frontend; the custom write route must still validate the request on the server, as the `formSchema` call does here. For per-tenant settings, use a tenant-scoped schema and model instead of this module-wide record.
|
|
193
|
+
|
|
194
|
+
## Pages in this section
|
|
195
|
+
|
|
196
|
+
- [Shared types](/docs/interfaces/base/types): Base props, colours, sizes, action targets, row-action rules, guards and the small enums.
|
|
197
|
+
- [Forms](/docs/interfaces/base/forms): The `Form` builder, fields and groups, input components and the validation schema.
|
|
198
|
+
- [Tables](/docs/interfaces/base/tables): Table views over a data controller: the controller, its routes, columns and table view options.
|
|
199
|
+
- [Table sources and tenant gates](/docs/interfaces/base/table-sources-and-gates): Table views over a module's route, and behind a tenant gate.
|
|
200
|
+
- [Table row actions](/docs/interfaces/base/table-row-actions): Row actions, archive mode and guards.
|
|
201
|
+
- [Table filters and forms](/docs/interfaces/base/table-filters-and-forms): Filters, tabs, displays and generated forms.
|
|
202
|
+
- [Table events and helpers](/docs/interfaces/base/table-events-and-helpers): Exports, realtime, metadata, route helpers and events.
|
|
203
|
+
- [Charts and widgets](/docs/interfaces/base/charts-and-widgets): Chart types and props, chart cards, KPI cards, top lists and the period selector.
|
|
204
|
+
- [Layout and containers](/docs/interfaces/base/layout): Grids, stacks, tabs, the guard, the placeholder and `CustomComponent`.
|
|
205
|
+
- [Page layouts](/docs/interfaces/base/page-layouts): The layouts a page renders in, its header actions, and pages that fill the panel.
|
|
206
|
+
- [Data types](/docs/interfaces/base/data-types): The `DataType` contract, the registries, the default catalogue and a custom type.
|
|
207
|
+
- [Helpers](/docs/interfaces/base/helpers): Searchable columns, export jobs, file references and the archive-mode defaults.
|