@cosmicdrift/kumiko-bundled-features 0.386.0 → 0.387.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/LICENSE +21 -57
- package/dist/agent-tools/tool-catalog.js +1 -1
- package/dist/audit/screens.js +1 -1
- package/dist/auth-email-password/feature.js +1 -1
- package/dist/auth-email-password/handlers/change-password.write.js +3 -3
- package/dist/auth-email-password/handlers/confirm-token-flow.js +5 -5
- package/dist/auth-email-password/handlers/invite-accept-with-login.write.js +1 -1
- package/dist/auth-email-password/handlers/invite-accept.write.js +18 -18
- package/dist/auth-email-password/handlers/invite-create.write.d.ts +2 -2
- package/dist/auth-email-password/handlers/invite-create.write.js +10 -10
- package/dist/auth-email-password/handlers/invite-info.query.js +1 -1
- package/dist/auth-email-password/handlers/invite-signup-complete.write.js +24 -26
- package/dist/auth-email-password/handlers/login.write.d.ts +1 -1
- package/dist/auth-email-password/handlers/login.write.js +1 -1
- package/dist/auth-email-password/handlers/self-registration-status.query.js +1 -1
- package/dist/auth-email-password/handlers/signup-confirm.write.js +34 -37
- package/dist/auth-email-password/handlers/signup-request.write.js +6 -7
- package/dist/auth-email-password/handlers/switch-tenant-mfa-gate.write.d.ts +1 -1
- package/dist/auth-email-password/handlers/switch-tenant-mfa-gate.write.js +1 -4
- package/dist/auth-email-password/index.js +5 -5
- package/dist/auth-email-password/lockout-store.js +1 -1
- package/dist/auth-email-password/seeding.d.ts +42 -45
- package/dist/auth-email-password/seeding.js +51 -53
- package/dist/auth-email-password/signup-token-store.js +8 -8
- package/dist/auth-email-password/testing.js +3 -3
- package/dist/auth-email-password/web/auth-client.d.ts +2 -2
- package/dist/auth-email-password/web/auth-client.js +36 -37
- package/dist/auth-email-password/web/auth-form-primitives.js +10 -10
- package/dist/auth-email-password/web/auth-gate.js +15 -16
- package/dist/auth-email-password/web/client-plugin.d.ts +7 -7
- package/dist/auth-email-password/web/client-plugin.js +4 -5
- package/dist/auth-email-password/web/confirm-account-unlock-screen.js +1 -1
- package/dist/auth-email-password/web/constants.js +3 -3
- package/dist/auth-email-password/web/default-topbar-actions.d.ts +8 -8
- package/dist/auth-email-password/web/default-topbar-actions.js +6 -6
- package/dist/auth-email-password/web/forgot-password-screen.d.ts +2 -2
- package/dist/auth-email-password/web/forgot-password-screen.js +9 -9
- package/dist/auth-email-password/web/index.js +5 -5
- package/dist/auth-email-password/web/invite-accept-screen.d.ts +1 -1
- package/dist/auth-email-password/web/invite-accept-screen.js +16 -16
- package/dist/auth-email-password/web/login-screen.d.ts +1 -1
- package/dist/auth-email-password/web/login-screen.js +2 -3
- package/dist/auth-email-password/web/reset-password-screen.d.ts +4 -4
- package/dist/auth-email-password/web/reset-password-screen.js +12 -13
- package/dist/auth-email-password/web/session.d.ts +10 -9
- package/dist/auth-email-password/web/session.js +28 -29
- package/dist/auth-email-password/web/signup-complete-screen.js +3 -3
- package/dist/auth-email-password/web/signup-screen.d.ts +1 -1
- package/dist/auth-email-password/web/signup-screen.js +13 -13
- package/dist/auth-email-password/web/tenant-switcher.d.ts +4 -4
- package/dist/auth-email-password/web/tenant-switcher.js +21 -22
- package/dist/auth-email-password/web/use-shell-user.js +12 -13
- package/dist/auth-email-password/web/user-menu.d.ts +4 -4
- package/dist/auth-email-password/web/user-menu.js +12 -13
- package/dist/auth-email-password/web/verify-email-screen.d.ts +2 -2
- package/dist/auth-email-password/web/verify-email-screen.js +9 -10
- package/dist/auth-foundation/boot-checks.js +4 -4
- package/dist/auth-foundation/resolve-anonymous-access.d.ts +1 -1
- package/dist/auth-foundation/resolve-anonymous-access.js +3 -3
- package/dist/auth-foundation/types.js +2 -2
- package/dist/auth-mfa/handlers/disable.write.js +3 -3
- package/dist/auth-mfa/handlers/enable-confirm-preauth.write.js +4 -4
- package/dist/auth-mfa/handlers/enable-confirm.write.js +2 -2
- package/dist/auth-mfa/handlers/enable-start-preauth.write.js +1 -1
- package/dist/auth-mfa/handlers/reencrypt.job.js +1 -1
- package/dist/auth-mfa/handlers/regenerate-recovery.write.js +5 -5
- package/dist/auth-mfa/handlers/verify.write.js +1 -1
- package/dist/auth-mfa/token-secrets.js +1 -1
- package/dist/auth-mfa/web/client-plugin.d.ts +1 -1
- package/dist/auth-mfa/web/client-plugin.js +1 -1
- package/dist/auth-mfa/web/i18n.js +3 -3
- package/dist/auth-mfa/web/index.js +4 -4
- package/dist/auth-mfa/web/mfa-client.js +17 -16
- package/dist/auth-mfa/web/mfa-verify-screen.js +6 -6
- package/dist/billing-foundation/aggregate-id.d.ts +5 -5
- package/dist/billing-foundation/aggregate-id.js +10 -11
- package/dist/billing-foundation/entities.js +27 -27
- package/dist/billing-foundation/events.js +18 -17
- package/dist/billing-foundation/feature.js +42 -43
- package/dist/billing-foundation/get-subscription-for-tenant.d.ts +3 -3
- package/dist/billing-foundation/get-subscription-for-tenant.js +3 -5
- package/dist/billing-foundation/handlers/create-checkout-session.write.js +18 -17
- package/dist/billing-foundation/handlers/create-portal-session.write.js +11 -12
- package/dist/billing-foundation/handlers/list-subscriptions.query.js +4 -4
- package/dist/billing-foundation/handlers/process-event.write.js +20 -20
- package/dist/billing-foundation/projection.d.ts +15 -11
- package/dist/billing-foundation/projection.js +38 -37
- package/dist/billing-foundation/subscription-tier-sync.js +3 -3
- package/dist/billing-foundation/tenant-destroy-hook.d.ts +2 -2
- package/dist/billing-foundation/tenant-destroy-hook.js +7 -7
- package/dist/billing-foundation/types.d.ts +40 -41
- package/dist/billing-foundation/types.js +20 -20
- package/dist/billing-foundation/web/billing-plans-panel.js +4 -4
- package/dist/cap-counter/aggregate-id.js +8 -9
- package/dist/cap-counter/constants.js +11 -12
- package/dist/cap-counter/enforce-cap.d.ts +59 -62
- package/dist/cap-counter/enforce-cap.js +47 -48
- package/dist/cap-counter/entity.js +29 -29
- package/dist/cap-counter/feature.js +34 -35
- package/dist/cap-counter/handlers/increment-rolling.write.d.ts +2 -2
- package/dist/cap-counter/handlers/increment-rolling.write.js +31 -31
- package/dist/cap-counter/handlers/mark-soft-warned.write.js +4 -5
- package/dist/cap-counter/stock-cap-guard.js +1 -1
- package/dist/cap-counter/with-cap-enforcement.d.ts +3 -5
- package/dist/channel-email/smtp-transport.d.ts +18 -17
- package/dist/channel-email/smtp-transport.js +24 -21
- package/dist/channel-in-app/handlers/unread-count.query.js +3 -4
- package/dist/compliance-profiles/feature.js +4 -4
- package/dist/compliance-profiles/handlers/for-tenant.query.js +3 -6
- package/dist/compliance-profiles/handlers/list-profiles.query.js +5 -5
- package/dist/compliance-profiles/handlers/needs-profile.query.js +4 -4
- package/dist/compliance-profiles/handlers/set-profile.write.js +13 -14
- package/dist/compliance-profiles/handlers/sub-processors.query.js +9 -11
- package/dist/compliance-profiles/resolve-for-tenant.js +7 -7
- package/dist/compliance-profiles/schema/profile-selection.js +18 -23
- package/dist/compliance-profiles/seeding.js +14 -15
- package/dist/compliance-profiles-ops/handlers/tenants-missing-profile.query.js +3 -3
- package/dist/compliance-profiles-ops/index.js +2 -2
- package/dist/config/handlers/readiness.query.d.ts +4 -4
- package/dist/config/handlers/readiness.query.js +1 -1
- package/dist/config/handlers/reencrypt.job.js +4 -5
- package/dist/config/handlers/set.write.js +4 -4
- package/dist/config/resolver.js +4 -4
- package/dist/config/table.js +10 -10
- package/dist/config/write-helpers.js +1 -1
- package/dist/crypto-shredding/handlers/forget-subject.write.d.ts +2 -2
- package/dist/crypto-shredding/handlers/forget-subject.write.js +12 -11
- package/dist/custom-fields/aggregate-id.d.ts +12 -13
- package/dist/custom-fields/aggregate-id.js +16 -17
- package/dist/custom-fields/entity.js +49 -47
- package/dist/custom-fields/events.js +7 -8
- package/dist/custom-fields/feature.d.ts +14 -14
- package/dist/custom-fields/feature.js +53 -54
- package/dist/custom-fields/handlers/clear-custom-field.write.d.ts +3 -2
- package/dist/custom-fields/handlers/clear-custom-field.write.js +9 -8
- package/dist/custom-fields/handlers/define-tenant-field.write.d.ts +1 -1
- package/dist/custom-fields/handlers/define-tenant-field.write.js +2 -2
- package/dist/custom-fields/handlers/delete-system-field.write.js +6 -7
- package/dist/custom-fields/handlers/delete-tenant-field.write.d.ts +1 -1
- package/dist/custom-fields/handlers/delete-tenant-field.write.js +3 -3
- package/dist/custom-fields/handlers/set-custom-field.write.d.ts +3 -3
- package/dist/custom-fields/handlers/set-custom-field.write.js +25 -28
- package/dist/custom-fields/handlers/update-tenant-field.write.d.ts +1 -1
- package/dist/custom-fields/handlers/update-tenant-field.write.js +1 -1
- package/dist/custom-fields/lib/field-access.js +2 -2
- package/dist/custom-fields/lib/parse-serialized-field.js +1 -1
- package/dist/custom-fields/lib/quota.js +1 -1
- package/dist/custom-fields/lib/value-schema.js +10 -12
- package/dist/custom-fields/run-retention.js +3 -3
- package/dist/custom-fields/schemas.js +14 -14
- package/dist/custom-fields/web/client-plugin.js +2 -5
- package/dist/custom-fields/web/constants.js +2 -2
- package/dist/custom-fields/web/custom-fields-form-section.d.ts +4 -4
- package/dist/custom-fields/web/custom-fields-form-section.js +22 -22
- package/dist/custom-fields/wire-for-entity.js +65 -67
- package/dist/custom-fields/wire-user-data-rights.js +3 -3
- package/dist/data-retention/_internal/parse-override.js +2 -3
- package/dist/data-retention/feature.js +11 -18
- package/dist/data-retention/handlers/policy-for.query.js +6 -6
- package/dist/data-retention/keep-for.d.ts +7 -7
- package/dist/data-retention/keep-for.js +15 -15
- package/dist/data-retention/override-schema.d.ts +3 -4
- package/dist/data-retention/override-schema.js +13 -15
- package/dist/data-retention/presets.d.ts +4 -5
- package/dist/data-retention/presets.js +18 -23
- package/dist/data-retention/resolve-tenant-preset.js +17 -16
- package/dist/data-retention/resolver.d.ts +12 -12
- package/dist/data-retention/resolver.js +24 -23
- package/dist/data-retention/run-retention-cleanup.d.ts +8 -3
- package/dist/data-retention/run-retention-cleanup.js +61 -51
- package/dist/data-retention/schema/tenant-retention-override.js +13 -11
- package/dist/delivery/feature.js +2 -2
- package/dist/delivery/handlers/log.query.js +1 -1
- package/dist/delivery/tables.js +9 -8
- package/dist/delivery/unsubscribe.js +4 -4
- package/dist/document-ingest-foundation/entity.js +4 -4
- package/dist/document-ingest-foundation/events.js +2 -2
- package/dist/document-ingest-foundation/feature.js +2 -2
- package/dist/document-ingest-foundation/pages.js +1 -1
- package/dist/document-ingest-foundation/tenant-destroy-hook.js +4 -4
- package/dist/feature-toggles/compose-tier-resolver.js +1 -1
- package/dist/feature-toggles/feature.js +1 -1
- package/dist/feature-toggles/global-feature-state-table.js +1 -1
- package/dist/feature-toggles/handlers/registered.query.js +5 -5
- package/dist/feature-toggles/toggle-sync-signal.js +1 -1
- package/dist/feature-toggles/web/constants.js +1 -1
- package/dist/file-derivatives/feature.d.ts +1 -1
- package/dist/file-derivatives/feature.js +1 -1
- package/dist/file-derivatives/handlers/public-variant.query.js +1 -1
- package/dist/file-derivatives/presets.js +1 -1
- package/dist/file-foundation/feature.js +6 -6
- package/dist/file-provider-inmemory/feature.d.ts +1 -1
- package/dist/file-provider-inmemory/feature.js +16 -16
- package/dist/file-provider-s3/feature.js +16 -16
- package/dist/file-provider-s3/lib/s3-provider.js +6 -6
- package/dist/files/feature.js +6 -6
- package/dist/files-tenant-data/handlers/sweep-orphaned-derivatives.job.js +4 -4
- package/dist/files-tenant-data/hooks.js +24 -26
- package/dist/files-tenant-data/index.js +1 -1
- package/dist/folders/feature.d.ts +1 -1
- package/dist/folders/web/folder-manager.js +2 -2
- package/dist/folders/web/tree.js +5 -5
- package/dist/form-draft/db/queries/cleanup.js +1 -1
- package/dist/form-draft/db/queries/owned-file-refs.js +1 -1
- package/dist/form-draft/entity.js +3 -3
- package/dist/form-draft/feature.js +4 -5
- package/dist/form-draft/handlers/discard.write.js +1 -1
- package/dist/form-draft/release-file-refs.js +6 -6
- package/dist/form-draft/schemas.js +3 -3
- package/dist/form-draft/web/constants.js +0 -2
- package/dist/inbound-mail-foundation/aggregate-id.d.ts +13 -13
- package/dist/inbound-mail-foundation/aggregate-id.js +19 -19
- package/dist/inbound-mail-foundation/connect-routes.js +4 -3
- package/dist/inbound-mail-foundation/constants.d.ts +22 -24
- package/dist/inbound-mail-foundation/constants.js +30 -33
- package/dist/inbound-mail-foundation/entities.d.ts +12 -12
- package/dist/inbound-mail-foundation/entities.js +47 -48
- package/dist/inbound-mail-foundation/events.d.ts +4 -3
- package/dist/inbound-mail-foundation/events.js +50 -47
- package/dist/inbound-mail-foundation/feature.js +39 -39
- package/dist/inbound-mail-foundation/handlers/account-state.js +8 -8
- package/dist/inbound-mail-foundation/handlers/connect-account.write.js +25 -26
- package/dist/inbound-mail-foundation/handlers/disconnect-account.write.js +7 -7
- package/dist/inbound-mail-foundation/handlers/ingest-message.write.js +50 -51
- package/dist/inbound-mail-foundation/handlers/list-accounts.query.js +8 -8
- package/dist/inbound-mail-foundation/handlers/list-messages.query.js +10 -10
- package/dist/inbound-mail-foundation/handlers/scope-visibility.js +3 -4
- package/dist/inbound-mail-foundation/handlers/update-account.write.js +11 -11
- package/dist/inbound-mail-foundation/oauth-state.d.ts +5 -5
- package/dist/inbound-mail-foundation/oauth-state.js +11 -10
- package/dist/inbound-mail-foundation/projection.d.ts +4 -4
- package/dist/inbound-mail-foundation/projection.js +31 -29
- package/dist/inbound-mail-foundation/provider-factory.d.ts +4 -4
- package/dist/inbound-mail-foundation/provider-factory.js +9 -9
- package/dist/inbound-mail-foundation/retention-sweep.d.ts +5 -3
- package/dist/inbound-mail-foundation/retention-sweep.js +38 -36
- package/dist/inbound-mail-foundation/tenant-destroy-hook.js +14 -16
- package/dist/inbound-mail-foundation/types.d.ts +45 -46
- package/dist/inbound-mail-foundation/types.js +21 -21
- package/dist/inbound-mail-foundation/watch-supervisor.d.ts +10 -10
- package/dist/inbound-mail-foundation/watch-supervisor.js +57 -56
- package/dist/inbound-provider-imap/credential-document.js +13 -13
- package/dist/inbound-provider-imap/feature.d.ts +2 -2
- package/dist/inbound-provider-imap/feature.js +42 -40
- package/dist/inbound-provider-imap/imap-client.d.ts +12 -11
- package/dist/inbound-provider-imap/imap-client.js +20 -19
- package/dist/inbound-provider-inmemory/feature.d.ts +9 -9
- package/dist/inbound-provider-inmemory/feature.js +19 -19
- package/dist/jobs/db/queries/retention.js +2 -2
- package/dist/jobs/db/queries/stale-run-sweep.js +3 -3
- package/dist/jobs/events.js +1 -1
- package/dist/jobs/feature.js +5 -6
- package/dist/jobs/handlers/detail.query.js +4 -4
- package/dist/jobs/handlers/list.query.js +1 -1
- package/dist/jobs/handlers/projection-rebuild.job.js +1 -1
- package/dist/jobs/handlers/reindex-entity.job.js +1 -1
- package/dist/jobs/handlers/retry.write.js +1 -1
- package/dist/jobs/job-instant.js +1 -1
- package/dist/jobs/job-run-logger.js +10 -11
- package/dist/jobs/job-run-table.js +3 -3
- package/dist/jobs/screens.js +1 -1
- package/dist/jobs/tenant-job-failure-table.js +1 -1
- package/dist/jobs/tenant-job-run-table.js +1 -1
- package/dist/ledger/entity.js +5 -5
- package/dist/ledger/feature.js +3 -3
- package/dist/ledger/handlers/confirm-schedule-period.write.js +3 -3
- package/dist/ledger/recurring.js +12 -12
- package/dist/ledger/schemas.js +1 -1
- package/dist/ledger/web/constants.js +2 -2
- package/dist/ledger/web/index.js +7 -7
- package/dist/legal-pages/feature.d.ts +4 -4
- package/dist/legal-pages/feature.js +25 -26
- package/dist/legal-pages/markdown.js +3 -3
- package/dist/legal-pages/web/client-plugin.js +23 -24
- package/dist/legal-pages/web/index.js +0 -1
- package/dist/mail-foundation/feature.d.ts +2 -2
- package/dist/mail-foundation/feature.js +24 -25
- package/dist/mail-transport-inmemory/feature.d.ts +4 -4
- package/dist/mail-transport-inmemory/feature.js +27 -28
- package/dist/mail-transport-smtp/feature.js +20 -20
- package/dist/managed-pages/branding.js +6 -6
- package/dist/managed-pages/feature.d.ts +26 -26
- package/dist/managed-pages/feature.js +34 -34
- package/dist/managed-pages/handlers/by-slug.query.js +5 -6
- package/dist/managed-pages/handlers/by-tenant-published.query.js +2 -2
- package/dist/managed-pages/handlers/set.write.js +5 -7
- package/dist/managed-pages/screens/page-screens.js +11 -11
- package/dist/managed-pages/seeding.js +8 -8
- package/dist/managed-pages/table.js +13 -12
- package/dist/managed-pages/web/client-plugin.d.ts +1 -1
- package/dist/managed-pages/web/client-plugin.js +5 -5
- package/dist/managed-pages/web/i18n.js +1 -1
- package/dist/notes-history/entity.js +4 -4
- package/dist/notes-history/feature.d.ts +2 -2
- package/dist/notes-history-user-data/hooks.js +1 -1
- package/dist/page-render/layout.js +9 -9
- package/dist/page-render/markdown.js +11 -11
- package/dist/page-render/security-headers.js +7 -6
- package/dist/personal-access-tokens/feature.js +5 -5
- package/dist/personal-access-tokens/roles.js +2 -2
- package/dist/readiness/handlers/status.query.js +3 -3
- package/dist/renderer-foundation/api.js +12 -13
- package/dist/renderer-foundation/constants.js +2 -2
- package/dist/renderer-foundation/feature.js +7 -7
- package/dist/secrets/feature.js +9 -9
- package/dist/secrets/web/constants.js +2 -2
- package/dist/seo/feature.js +3 -3
- package/dist/sessions/constants.d.ts +1 -1
- package/dist/sessions/constants.js +1 -1
- package/dist/sessions/feature.js +8 -8
- package/dist/sessions/handlers/revoke-all-for-user.write.js +2 -2
- package/dist/sessions/handlers/revoke-all-others.write.js +2 -2
- package/dist/sessions/handlers/revoke.write.js +1 -1
- package/dist/sessions/schema/user-session.js +4 -4
- package/dist/sessions/screens.js +2 -2
- package/dist/sessions/session-callbacks.js +2 -2
- package/dist/sessions/session-revoked-event.js +2 -2
- package/dist/shared/assert-no-where-rule-in-ownership-write.js +1 -1
- package/dist/shared/decrypt-stored-pii.js +1 -1
- package/dist/shared/encrypt-for-direct-write.js +1 -1
- package/dist/shared/map-with-concurrency.js +5 -4
- package/dist/shared/parent-visibility.js +2 -2
- package/dist/shared/password-hashing.js +1 -1
- package/dist/shared/signup-handover.js +1 -2
- package/dist/shared/single-use-token-store.js +1 -1
- package/dist/subscription-mollie/constants.js +15 -17
- package/dist/subscription-mollie/feature.d.ts +17 -18
- package/dist/subscription-mollie/feature.js +24 -24
- package/dist/subscription-mollie/index.js +3 -3
- package/dist/subscription-mollie/plugin-methods.d.ts +2 -2
- package/dist/subscription-mollie/plugin-methods.js +15 -14
- package/dist/subscription-mollie/verify-webhook.d.ts +10 -10
- package/dist/subscription-mollie/verify-webhook.js +27 -27
- package/dist/subscription-stripe/constants.js +4 -6
- package/dist/subscription-stripe/feature.d.ts +14 -14
- package/dist/subscription-stripe/feature.js +35 -34
- package/dist/subscription-stripe/index.js +6 -6
- package/dist/subscription-stripe/plugin-methods.js +18 -18
- package/dist/subscription-stripe/runtime.d.ts +1 -1
- package/dist/subscription-stripe/runtime.js +1 -1
- package/dist/subscription-stripe/verify-webhook.d.ts +11 -11
- package/dist/subscription-stripe/verify-webhook.js +59 -61
- package/dist/tags/feature.d.ts +3 -3
- package/dist/tags/screens.js +1 -1
- package/dist/template-resolver/api.js +10 -10
- package/dist/template-resolver/handlers/find-by-id.query.js +5 -5
- package/dist/template-resolver/handlers/list.query.js +1 -1
- package/dist/template-resolver/handlers/shared.js +2 -2
- package/dist/template-resolver/handlers/template-write.js +3 -3
- package/dist/template-resolver/handlers/upsert-system.write.js +3 -4
- package/dist/template-resolver/handlers/upsert-tenant.write.js +4 -5
- package/dist/template-resolver/seeding.js +4 -4
- package/dist/template-resolver/table.js +10 -11
- package/dist/template-resolver/web/client-plugin.js +2 -2
- package/dist/tenant/feature.js +7 -7
- package/dist/tenant/handlers/member-directory.query.js +1 -1
- package/dist/tenant/handlers/members.query.js +1 -1
- package/dist/tenant/handlers/team-list.query.js +1 -1
- package/dist/tenant/handlers/tenant-directory.query.js +1 -1
- package/dist/tenant/invitation-table.js +37 -40
- package/dist/tenant/membership-table.js +3 -3
- package/dist/tenant/schema/tenant.js +7 -9
- package/dist/tenant/screens.js +1 -1
- package/dist/tenant/seeding.d.ts +6 -5
- package/dist/tenant/seeding.js +12 -12
- package/dist/tenant/testing.js +5 -6
- package/dist/tenant/web/constants.js +2 -2
- package/dist/tenant-handover/events.js +5 -7
- package/dist/tenant-handover/feature.js +1 -1
- package/dist/tenant-handover/grant.js +1 -1
- package/dist/tenant-handover/handlers/claim.write.js +1 -1
- package/dist/tenant-handover/move-entity-graph.js +8 -9
- package/dist/tenant-handover/signup-handover-provider.js +1 -2
- package/dist/tenant-handover/transfer-graph.js +4 -5
- package/dist/tenant-lifecycle/boot-checks.js +1 -1
- package/dist/tenant-lifecycle/feature.js +1 -1
- package/dist/tenant-settings/constants.js +1 -1
- package/dist/tenant-settings/tenant-defaults.d.ts +1 -1
- package/dist/tenant-settings/tenant-defaults.js +9 -2
- package/dist/tier-engine/aggregate-id.d.ts +11 -11
- package/dist/tier-engine/aggregate-id.js +15 -16
- package/dist/tier-engine/compose-app.d.ts +14 -14
- package/dist/tier-engine/compose-app.js +1 -1
- package/dist/tier-engine/entity.js +18 -19
- package/dist/tier-engine/feature.d.ts +19 -17
- package/dist/tier-engine/feature.js +68 -69
- package/dist/tier-engine/handlers/active-tier.query.js +6 -7
- package/dist/tier-engine/handlers/get-tenant-tier.query.js +4 -4
- package/dist/tier-engine/handlers/set-tenant-tier.write.d.ts +5 -5
- package/dist/tier-engine/handlers/set-tenant-tier.write.js +3 -3
- package/dist/tier-engine/tier-resolver.js +2 -2
- package/dist/tier-engine/trial.js +8 -8
- package/dist/tier-engine/web/index.js +4 -4
- package/dist/user/db/queries/stream-tenant-backfill.js +8 -8
- package/dist/user/handlers/create.write.js +4 -4
- package/dist/user/schema/user.d.ts +11 -11
- package/dist/user/schema/user.js +45 -44
- package/dist/user/seeding.d.ts +15 -15
- package/dist/user/seeding.js +28 -28
- package/dist/user/testing.js +3 -3
- package/dist/user-data-rights/audit-download.d.ts +8 -8
- package/dist/user-data-rights/audit-download.js +19 -20
- package/dist/user-data-rights/boot-checks.js +1 -1
- package/dist/user-data-rights/deletion-token.js +1 -1
- package/dist/user-data-rights/feature.d.ts +49 -50
- package/dist/user-data-rights/feature.js +54 -53
- package/dist/user-data-rights/handlers/cancel-deletion.write.js +9 -9
- package/dist/user-data-rights/handlers/confirm-deletion-by-token.write.js +8 -8
- package/dist/user-data-rights/handlers/download-by-job.query.js +29 -30
- package/dist/user-data-rights/handlers/download-by-token.query.js +40 -42
- package/dist/user-data-rights/handlers/export-status.query.js +8 -9
- package/dist/user-data-rights/handlers/lift-restriction.write.js +7 -8
- package/dist/user-data-rights/handlers/list-download-attempts.query.js +2 -2
- package/dist/user-data-rights/handlers/my-audit-log.query.js +4 -4
- package/dist/user-data-rights/handlers/request-deletion-by-email.write.d.ts +5 -5
- package/dist/user-data-rights/handlers/request-deletion-by-email.write.js +16 -15
- package/dist/user-data-rights/handlers/request-deletion.write.d.ts +2 -2
- package/dist/user-data-rights/handlers/request-deletion.write.js +7 -9
- package/dist/user-data-rights/handlers/request-export.write.js +42 -41
- package/dist/user-data-rights/handlers/restrict-account.write.js +22 -19
- package/dist/user-data-rights/handlers/run-forget-cleanup.write.js +8 -8
- package/dist/user-data-rights/index.js +8 -10
- package/dist/user-data-rights/lib/default-mailers.js +3 -3
- package/dist/user-data-rights/lib/update-user-lifecycle.js +14 -17
- package/dist/user-data-rights/run-export-jobs.d.ts +38 -42
- package/dist/user-data-rights/run-export-jobs.js +127 -233
- package/dist/user-data-rights/run-forget-cleanup.d.ts +16 -20
- package/dist/user-data-rights/run-forget-cleanup.js +63 -82
- package/dist/user-data-rights/run-user-export.d.ts +34 -33
- package/dist/user-data-rights/run-user-export.js +55 -57
- package/dist/user-data-rights/schema/download-attempt.js +11 -11
- package/dist/user-data-rights/schema/download-token.js +37 -41
- package/dist/user-data-rights/schema/export-job.d.ts +4 -4
- package/dist/user-data-rights/schema/export-job.js +65 -67
- package/dist/user-data-rights/token-helpers.d.ts +8 -9
- package/dist/user-data-rights/token-helpers.js +21 -25
- package/dist/user-data-rights/web/client-plugin.d.ts +5 -5
- package/dist/user-data-rights/web/client-plugin.js +1 -1
- package/dist/user-data-rights/web/confirm-deletion-screen.js +6 -5
- package/dist/user-data-rights/web/constants.js +1 -1
- package/dist/user-data-rights/web/index.js +5 -5
- package/dist/user-data-rights/web/privacy-center-screen.js +14 -13
- package/dist/user-data-rights/web/public-deletion-gate.d.ts +4 -4
- package/dist/user-data-rights/web/request-deletion-screen.js +6 -6
- package/dist/user-data-rights/zip-path.d.ts +15 -15
- package/dist/user-data-rights/zip-path.js +41 -40
- package/dist/user-data-rights-defaults/feature.js +15 -15
- package/dist/user-data-rights-defaults/hooks/delivery-attempt.userdata-hook.js +3 -5
- package/dist/user-data-rights-defaults/hooks/file-ref.userdata-hook.js +45 -51
- package/dist/user-data-rights-defaults/hooks/job-run.userdata-hook.js +2 -2
- package/dist/user-data-rights-defaults/hooks/notification-preference.userdata-hook.js +1 -1
- package/dist/user-data-rights-defaults/hooks/user-session.userdata-hook.js +3 -3
- package/dist/user-data-rights-defaults/hooks/user.userdata-hook.js +32 -31
- package/dist/user-profile/handlers/change-email.write.js +13 -13
- package/dist/user-profile/index.js +3 -3
- package/dist/user-profile/web/client-plugin.js +1 -1
- package/dist/user-profile/web/constants.js +1 -1
- package/dist/user-profile/web/profile-screen.js +1 -1
- package/dist/workflow-runner/aggregate-id.d.ts +1 -1
- package/dist/workflow-runner/aggregate-id.js +1 -1
- package/dist/workflow-runner/event-subscriber.js +4 -5
- package/dist/workflow-runner/event-trigger.js +4 -17
- package/dist/workflow-runner/feature.js +2 -2
- package/dist/workflow-runner/handlers/resume-run.write.js +4 -4
- package/dist/workflow-runner/pending-projection.js +6 -7
- package/dist/workflow-runner/runner.js +6 -6
- package/dist/workflow-runner/tables.js +6 -6
- package/dist/workflow-runner/workflow-registry.js +1 -1
- package/package.json +10 -10
package/LICENSE
CHANGED
|
@@ -1,57 +1,21 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
controlling, or under common control with the Licensor ("Affiliates"), or
|
|
23
|
-
contractors acting on their behalf. The Licensor remains free to use the
|
|
24
|
-
Licensed Work for any purpose, including for the operation of kumiko.rocks.
|
|
25
|
-
|
|
26
|
-
Change Date: 2030-05-05
|
|
27
|
-
Change License: Apache License, Version 2.0
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
Terms
|
|
31
|
-
|
|
32
|
-
The Licensor hereby grants you the right to copy, modify, create derivative works,
|
|
33
|
-
redistribute, and make non-production use of the Licensed Work. The Licensor may
|
|
34
|
-
make an Additional Use Grant, above, permitting limited production use.
|
|
35
|
-
|
|
36
|
-
Effective on the Change Date, or the fourth anniversary of the first publicly
|
|
37
|
-
available distribution of the Licensed Work under this License, whichever comes
|
|
38
|
-
first, this License will convert to the Change License.
|
|
39
|
-
|
|
40
|
-
This Business Source License governs use of the Licensed Work in all cases, except
|
|
41
|
-
as to any use that is explicitly granted in the Additional Use Grant above or
|
|
42
|
-
under the Change License after the Change Date.
|
|
43
|
-
|
|
44
|
-
If your use of the Licensed Work does not comply with the requirements of this
|
|
45
|
-
License, you must cease use of the Licensed Work immediately.
|
|
46
|
-
|
|
47
|
-
All copies of the Licensed Work, and all derivative works thereof, must include
|
|
48
|
-
this License.
|
|
49
|
-
|
|
50
|
-
This License does not grant you any right, title, or interest in any trademark,
|
|
51
|
-
logo, or branding of the Licensor, except as required to comply with this License.
|
|
52
|
-
|
|
53
|
-
TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON AN
|
|
54
|
-
“AS IS” BASIS. LICENSOR DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
|
|
55
|
-
WITHOUT LIMITATION WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
|
|
56
|
-
TITLE, AND NON-INFRINGEMENT. IN NO EVENT WILL LICENSOR BE LIABLE FOR ANY DAMAGES
|
|
57
|
-
ARISING OUT OF OR RELATED TO THIS LICENSE OR THE USE OF THE LICENSED WORK.
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Marc Frost
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -68,7 +68,7 @@ function isListHandlerQn(qn, entityName) {
|
|
|
68
68
|
function isDetailHandlerQn(qn, entityName) {
|
|
69
69
|
return qn.endsWith(`:${entityName}:detail`);
|
|
70
70
|
}
|
|
71
|
-
/**
|
|
71
|
+
/** The entity CRUD tools are enumerated off the registry, not off the manifest, so
|
|
72
72
|
* `resolveAgentExposure` never runs for them. Only an EXPLICIT opt-out may hide one here —
|
|
73
73
|
* the resolver's own default is fail-closed on a missing `description`, and CRUD-generated
|
|
74
74
|
* handlers never carry one, so reusing it would delete every entity tool in every app. */
|
package/dist/audit/screens.js
CHANGED
|
@@ -85,7 +85,7 @@ export function auditLogDetailLayout(options) {
|
|
|
85
85
|
"id",
|
|
86
86
|
],
|
|
87
87
|
},
|
|
88
|
-
// No section `title` here (
|
|
88
|
+
// No section `title` here (label-dedup fix): each section
|
|
89
89
|
// holds exactly one field, so a title would repeat the field's own
|
|
90
90
|
// label (rendered by RenderField as the Field's heading) verbatim.
|
|
91
91
|
{ fields: [{ field: "payload", renderer: { format: "json" } }] },
|
|
@@ -66,7 +66,7 @@ export function createAuthEmailPasswordFeature(opts = {}) {
|
|
|
66
66
|
const strictVerification = opts.emailVerification !== undefined && (opts.emailVerification.mode ?? "strict") === "strict";
|
|
67
67
|
const feature = defineFeature("auth-email-password", (r) => {
|
|
68
68
|
r.describe("Provides email+password authentication: the always-on handlers are `login`, `changePassword`, and `logout`; optional flows — password reset, email verification, magic-link self-signup, tenant invite, and account-unlock — are registered only when you pass their respective option objects (`passwordReset`, `emailVerification`, `signup`, `invite`, `accountUnlock`) to `createAuthEmailPasswordFeature(opts)`. All five magic-link flows dispatch their mail through the `delivery` feature via `ctx.notify`, so mounting any of them additionally requires `delivery`. Tokens are HMAC-signed (reset/verify/unlock) or opaque-random in Redis (signup/invite). `accountUnlock` is the self-service escape hatch for `accountLockout`'s monotonic failure-counter (#1266): confirming the mailed token clears the Redis lockout state without touching the user entity. Requires the `user` and `tenant` features, and declares `JWT_SECRET` (≥ 32 chars) in `authEmailPasswordEnvSchema` so a missing secret surfaces at boot validation rather than on the first login attempt.");
|
|
69
|
-
// kumiko-lint-ignore i18n-ui-strings uiHints labels are feature-registry metadata for the admin feature catalog, not yet wired to the i18n system
|
|
69
|
+
// kumiko-lint-ignore i18n-ui-strings uiHints labels are feature-registry metadata for the admin feature catalog, not yet wired to the i18n system
|
|
70
70
|
r.uiHints({
|
|
71
71
|
displayLabel: "Auth \u00b7 Email + Password",
|
|
72
72
|
category: "identity",
|
|
@@ -42,9 +42,9 @@ export const changePasswordWrite = defineWriteHandler({
|
|
|
42
42
|
return invalidCredentials();
|
|
43
43
|
}
|
|
44
44
|
const newHash = await hashPassword(event.payload.newPassword);
|
|
45
|
-
// The user aggregate is systemStream
|
|
46
|
-
// SYSTEM_TENANT_ID deterministically.
|
|
47
|
-
// one-time backfillUserStreamTenants migration
|
|
45
|
+
// The user aggregate is systemStream: its event stream lives on
|
|
46
|
+
// SYSTEM_TENANT_ID deterministically. Previously scattered streams need the
|
|
47
|
+
// one-time backfillUserStreamTenants migration.
|
|
48
48
|
const writer = createSystemUser(SYSTEM_TENANT_ID);
|
|
49
49
|
// Apply via user feature's update handler — writeAs(system) satisfies
|
|
50
50
|
// the privileged-only write rule on passwordHash. Pass the current version
|
|
@@ -15,11 +15,11 @@
|
|
|
15
15
|
// else — including future branches a maintainer adds — releases
|
|
16
16
|
// automatically.
|
|
17
17
|
//
|
|
18
|
-
// The user aggregate
|
|
18
|
+
// The user aggregate uses systemStream: its event stream lives on
|
|
19
19
|
// SYSTEM_TENANT_ID deterministically, so the write targets exactly one
|
|
20
20
|
// stream. The former membership-probing (`tryWriteAcrossTenants`) existed
|
|
21
|
-
// for
|
|
22
|
-
// backfillUserStreamTenants migration
|
|
21
|
+
// for scattered streams; those need the one-time
|
|
22
|
+
// backfillUserStreamTenants migration — probing them stopped working
|
|
23
23
|
// the moment the executor's stream choke-point landed anyway.
|
|
24
24
|
import { createSystemUser, declareEscapeHatch, SYSTEM_TENANT_ID, } from "@cosmicdrift/kumiko-framework/engine";
|
|
25
25
|
import { InternalError, writeFailure } from "@cosmicdrift/kumiko-framework/errors";
|
|
@@ -61,8 +61,8 @@ export async function runConfirmTokenFlow(ctx, userId, expiresAtMs, spec) {
|
|
|
61
61
|
committed = true;
|
|
62
62
|
return { isSuccess: true, data: spec.successData };
|
|
63
63
|
}
|
|
64
|
-
// version_conflict = concurrent modification (or an un-migrated
|
|
65
|
-
// stream
|
|
64
|
+
// version_conflict = concurrent modification (or an un-migrated
|
|
65
|
+
// stream) → token-level failure. Anything else (DB down,
|
|
66
66
|
// access denied) bubbles unchanged so ops sees the real failure class.
|
|
67
67
|
if (writeRes.error.code === "version_conflict")
|
|
68
68
|
return spec.invalidToken();
|
|
@@ -88,7 +88,7 @@ export function createInviteAcceptWithLoginHandler(opts = {}) {
|
|
|
88
88
|
}
|
|
89
89
|
// Password check against userTable, through the same gates
|
|
90
90
|
// login.write.ts runs (see login-gates.test.ts for the gate contracts).
|
|
91
|
-
// Email uniqueness is partial on live rows
|
|
91
|
+
// Email uniqueness is partial on live rows — without
|
|
92
92
|
// this filter the lookup can resolve a soft-deleted row.
|
|
93
93
|
const userRow = await ctx.db.global(userTable).fetchOne({
|
|
94
94
|
email: invitationEmail,
|
|
@@ -1,31 +1,31 @@
|
|
|
1
|
-
// Tenant
|
|
1
|
+
// Tenant invitation — logged-in user accepts.
|
|
2
2
|
//
|
|
3
|
-
//
|
|
3
|
+
// The user is signed in to some tenant and clicks the Accept link.
|
|
4
4
|
// Server:
|
|
5
5
|
// 1. Token → invitationId (Redis)
|
|
6
6
|
// 2. Burn (single-use)
|
|
7
|
-
// 3.
|
|
8
|
-
// 4. Email
|
|
7
|
+
// 3. Load the invitation row from the database
|
|
8
|
+
// 4. Email match: invitation.email === user.email (otherwise inviteEmailMismatch)
|
|
9
9
|
// 5+6. grantInvitedMembershipRole: create the membership, or add the
|
|
10
10
|
// invited role to an existing one (add-only)
|
|
11
|
-
// 7. Invitation
|
|
12
|
-
// 8. Redis
|
|
11
|
+
// 7. Invitation row → status=accepted
|
|
12
|
+
// 8. Delete Redis keys (the burn key remains for replay protection)
|
|
13
13
|
//
|
|
14
|
-
//
|
|
15
|
-
//
|
|
16
|
-
//
|
|
14
|
+
// This is the classic "shared workspace with a logged-in session" flow.
|
|
15
|
+
// Branch 2 (anonymous + existing email) and Branch 3 (anonymous + new
|
|
16
|
+
// email) are handled separately.
|
|
17
17
|
import { createEventStoreExecutor, createTenantDb, fetchOne, } from "@cosmicdrift/kumiko-framework/db";
|
|
18
18
|
import { createSystemUser, defineWriteHandler, } from "@cosmicdrift/kumiko-framework/engine";
|
|
19
19
|
import { InternalError, writeFailure } from "@cosmicdrift/kumiko-framework/errors";
|
|
20
20
|
import * as z from "zod";
|
|
21
21
|
import { decryptStoredPii } from "../../shared/index.js";
|
|
22
|
-
// kumiko-lint-ignore cross-feature-import invite
|
|
22
|
+
// kumiko-lint-ignore cross-feature-import the invite flow lives in auth-email-password (Magic-Link), while the DB-row owner is a tenant feature
|
|
23
23
|
import { INVITATION_STATUS, tenantInvitationEntity, tenantInvitationsTable, } from "../../tenant/invitation-table.js";
|
|
24
24
|
// kumiko-lint-ignore cross-feature-import membership grant for a privileged cross-tenant add (like provisionSignupAccount)
|
|
25
25
|
import { grantInvitedMembershipRole } from "../../tenant/invited-membership.js";
|
|
26
26
|
// kumiko-lint-ignore cross-feature-import global roles granted on invite accept live on the user row
|
|
27
27
|
import { grantInvitedGlobalRoles, parseInvitedGlobalRoles, } from "../../user/invited-global-roles.js";
|
|
28
|
-
// kumiko-lint-ignore cross-feature-import auth handler reads user
|
|
28
|
+
// kumiko-lint-ignore cross-feature-import the auth handler reads the user row for the email match
|
|
29
29
|
import { userTable } from "../../user/schema/user.js";
|
|
30
30
|
import { invalidInviteToken, inviteEmailMismatch } from "../errors.js";
|
|
31
31
|
import { burnInviteToken, deleteInviteToken, getInvitationIdForToken, unburnInviteToken, } from "../invite-token-store.js";
|
|
@@ -73,9 +73,9 @@ export function createInviteAcceptHandler() {
|
|
|
73
73
|
const invitationEmail = await decryptStoredPii(invitation.email, "email", "auth:invite-accept");
|
|
74
74
|
const invitationRole = invitation.role;
|
|
75
75
|
const invitationVersion = invitation.version;
|
|
76
|
-
// Email
|
|
77
|
-
//
|
|
78
|
-
//
|
|
76
|
+
// Email match: the user must match the invited email.
|
|
77
|
+
// Otherwise, anyone with access to the invitee's email could add
|
|
78
|
+
// their own account to the tenant.
|
|
79
79
|
const userRow = await ctx.db.global(userTable).fetchOne({
|
|
80
80
|
id: event.user.id,
|
|
81
81
|
});
|
|
@@ -103,10 +103,10 @@ export function createInviteAcceptHandler() {
|
|
|
103
103
|
});
|
|
104
104
|
if (!globalGrant.isSuccess)
|
|
105
105
|
return globalGrant;
|
|
106
|
-
// Invitation
|
|
107
|
-
// Tenant
|
|
108
|
-
// (
|
|
109
|
-
// invitation
|
|
106
|
+
// Invitation status → accepted via event-store-executor.
|
|
107
|
+
// Tenant scoping: ctx.db is scoped to event.user.tenantId
|
|
108
|
+
// (not the invitation tenant). Build a TenantDb for the
|
|
109
|
+
// invitation tenant so the executor can find the row.
|
|
110
110
|
const invitationTdb = createTenantDb({
|
|
111
111
|
db: dbConn,
|
|
112
112
|
tenantId: invitationTenantId,
|
|
@@ -11,7 +11,7 @@ export type InviteCreateData = {
|
|
|
11
11
|
readonly expiresAt: string;
|
|
12
12
|
};
|
|
13
13
|
export type InviteCreateOptions = {
|
|
14
|
-
/** TTL
|
|
14
|
+
/** TTL for the activation token. Default: 7 days. */
|
|
15
15
|
readonly tokenTtlMinutes?: number;
|
|
16
16
|
/** App page that receives the magic-link; the handler appends `?token=…`
|
|
17
17
|
* and dispatches the invite mail via delivery (ctx.notify). Apps with
|
|
@@ -25,7 +25,7 @@ export type InviteCreateOptions = {
|
|
|
25
25
|
readonly locale?: AuthMailLocale;
|
|
26
26
|
readonly canAssignRole?: (inviterRoles: readonly string[], targetRole: string) => boolean;
|
|
27
27
|
/** Opt-in allow-list for app-defined (unranked) roles the elevation guard
|
|
28
|
-
* would otherwise reject with unassignable_membership_role
|
|
28
|
+
* would otherwise reject with unassignable_membership_role.
|
|
29
29
|
* Rank-aware alternative: declare roles via EXT_ASSIGNABLE_ROLE. */
|
|
30
30
|
readonly additionalAssignableRoles?: readonly string[];
|
|
31
31
|
};
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
// Tenant-Invite Step 1 (create).
|
|
2
2
|
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
3
|
+
// An admin invites an email address → a DB row is created via
|
|
4
|
+
// event-store-executor (or reused for a re-invite), a random token is stored
|
|
5
|
+
// bidirectionally in Redis, and the handler sends the invite email to the
|
|
6
|
+
// invitee via delivery (ctx.notify), as with reset/verify/signup. The token
|
|
7
|
+
// is NOT returned to the admin, so the admin cannot impersonate acceptance.
|
|
8
8
|
//
|
|
9
9
|
// Re-invite for the same (tenantId, email): the existing row is reused
|
|
10
10
|
// regardless of its prior status (pending/cancelled/accepted), reset to
|
|
@@ -12,10 +12,10 @@
|
|
|
12
12
|
// still live for that invitation is invalidated first, so the previous
|
|
13
13
|
// mail's link stops working (see invite-token-store.ts).
|
|
14
14
|
//
|
|
15
|
-
// Always-200
|
|
16
|
-
//
|
|
17
|
-
//
|
|
18
|
-
//
|
|
15
|
+
// Always-200 for an unknown user: an invite is created even when the
|
|
16
|
+
// invitee's email does not exist in users — the Branch-3-Accept-Flow
|
|
17
|
+
// permits new-user-signup with the token. invite-create does not enable
|
|
18
|
+
// enumeration.
|
|
19
19
|
import { generateToken } from "@cosmicdrift/kumiko-framework/api";
|
|
20
20
|
import { createEventStoreExecutor } from "@cosmicdrift/kumiko-framework/db";
|
|
21
21
|
import { access, assignableAppRolesOf, defineWriteHandler, } from "@cosmicdrift/kumiko-framework/engine";
|
|
@@ -23,7 +23,7 @@ import { InternalError, writeFailure, } from "@cosmicdrift/kumiko-framework/erro
|
|
|
23
23
|
import { isValidLocaleTag } from "@cosmicdrift/kumiko-framework/i18n";
|
|
24
24
|
import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
|
|
25
25
|
import * as z from "zod";
|
|
26
|
-
// kumiko-lint-ignore cross-feature-import invite
|
|
26
|
+
// kumiko-lint-ignore cross-feature-import invite flow lives in auth-email-password (Magic-Link-Pattern); DB-row owner is the tenant feature
|
|
27
27
|
import { INVITATION_STATUS, tenantInvitationEntity, tenantInvitationsTable, } from "../../tenant/invitation-table.js";
|
|
28
28
|
// kumiko-lint-ignore cross-feature-import membership version read is owned by the tenant feature
|
|
29
29
|
import { membershipVersionOf } from "../../tenant/invited-membership.js";
|
|
@@ -9,7 +9,7 @@ import { defineQueryHandler } from "@cosmicdrift/kumiko-framework/engine";
|
|
|
9
9
|
import { UnprocessableError } from "@cosmicdrift/kumiko-framework/errors";
|
|
10
10
|
import * as z from "zod";
|
|
11
11
|
import { decryptStoredPii } from "../../shared/index.js";
|
|
12
|
-
// kumiko-lint-ignore cross-feature-import invite-flow
|
|
12
|
+
// kumiko-lint-ignore cross-feature-import invite-flow lives in auth-email-password (Magic-Link), DB-row-owner belongs to the tenant feature
|
|
13
13
|
import { INVITATION_STATUS, tenantInvitationsTable } from "../../tenant/invitation-table.js";
|
|
14
14
|
// kumiko-lint-ignore cross-feature-import login-style account lookup, same as invite-accept-with-login
|
|
15
15
|
import { userTable } from "../../user/schema/user.js";
|
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
// Tenant-Invite Step 2 — Branch 3 (
|
|
1
|
+
// Tenant-Invite Step 2 — Branch 3 (anonymous user, email NOT registered).
|
|
2
2
|
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
3
|
+
// Unlike signup-confirm, no new tenant is created. The tenant already
|
|
4
|
+
// exists in the invitation row; only the user and membership are created.
|
|
5
5
|
//
|
|
6
6
|
// Flow:
|
|
7
|
-
// 1. User
|
|
8
|
-
// 2.
|
|
9
|
-
//
|
|
10
|
-
// 3. User
|
|
7
|
+
// 1. User clicks the invite link → /invite/signup?token=...
|
|
8
|
+
// 2. The frontend shows the password form (the email comes from the
|
|
9
|
+
// invitation, not user input, so an email mismatch is impossible)
|
|
10
|
+
// 3. User submits the password and token
|
|
11
11
|
// 4. Server:
|
|
12
12
|
// a. Token → invitationId → invitation row
|
|
13
|
-
// b. User-
|
|
14
|
-
//
|
|
15
|
-
// c. Create user (emailVerified=true
|
|
16
|
-
// d. Add membership
|
|
17
|
-
// e.
|
|
18
|
-
// 5. Response: SessionUser + tenantId
|
|
13
|
+
// b. User-existence check: invitation.email must NOT exist in userTable
|
|
14
|
+
// (otherwise Branch 2 or Branch 1 must be used)
|
|
15
|
+
// c. Create the user (emailVerified=true because of the magic link)
|
|
16
|
+
// d. Add membership to the invited tenant
|
|
17
|
+
// e. Mark the invitation accepted and delete the token
|
|
18
|
+
// 5. Response: SessionUser + tenantId for automatic login
|
|
19
19
|
import { createEventStoreExecutor, createTenantDb, fetchOne, } from "@cosmicdrift/kumiko-framework/db";
|
|
20
20
|
import { buildSessionRoles, createSystemUser, defineWriteHandler, } from "@cosmicdrift/kumiko-framework/engine";
|
|
21
21
|
import { InternalError, writeFailure } from "@cosmicdrift/kumiko-framework/errors";
|
|
@@ -25,7 +25,7 @@ import { decryptStoredPii, registrationLocaleFromRequest } from "../../shared/in
|
|
|
25
25
|
import { INVITATION_STATUS, tenantInvitationEntity, tenantInvitationsTable, } from "../../tenant/invitation-table.js";
|
|
26
26
|
// kumiko-lint-ignore cross-feature-import reserved-role check owned by tenant-feature
|
|
27
27
|
import { findForbiddenMembershipRole, reservedMembershipRoleError, } from "../../tenant/membership-roles.js";
|
|
28
|
-
// kumiko-lint-ignore cross-feature-import membership-seed-helper
|
|
28
|
+
// kumiko-lint-ignore cross-feature-import membership-seed-helper for privileged cross-tenant addition
|
|
29
29
|
import { seedTenantMembership } from "../../tenant/seeding.js";
|
|
30
30
|
// kumiko-lint-ignore cross-feature-import global roles granted on invite accept live on the user row
|
|
31
31
|
import { parseInvitedGlobalRoles } from "../../user/invited-global-roles.js";
|
|
@@ -74,20 +74,19 @@ export function createInviteSignupCompleteHandler(opts = {}) {
|
|
|
74
74
|
const invitationRole = invitation.role;
|
|
75
75
|
const invitationGlobalRoles = parseInvitedGlobalRoles(invitation.globalRoles);
|
|
76
76
|
const invitationVersion = invitation.version;
|
|
77
|
-
//
|
|
78
|
-
//
|
|
79
|
-
//
|
|
80
|
-
//
|
|
81
|
-
//
|
|
82
|
-
// this filter the lookup can resolve a soft-deleted row.
|
|
77
|
+
// If the email is already registered, the user must use Branch 2
|
|
78
|
+
// (acceptWithLogin). This flow explicitly requires a new email;
|
|
79
|
+
// otherwise there would be two ways to set a password for the same user.
|
|
80
|
+
// Email uniqueness is partial on live rows — without this filter,
|
|
81
|
+
// the lookup can resolve a soft-deleted row.
|
|
83
82
|
const existingUser = await ctx.db.global(userTable).fetchOne({
|
|
84
83
|
email: invitationEmail,
|
|
85
84
|
isDeleted: false,
|
|
86
85
|
});
|
|
87
86
|
if (existingUser)
|
|
88
87
|
return invalidInviteToken();
|
|
89
|
-
//
|
|
90
|
-
//
|
|
88
|
+
// Create the user through seedUserWithPassword so the magic-link flow
|
|
89
|
+
// records emailVerified=true.
|
|
91
90
|
// @cast-boundary db-runner — helpers use only the query API that
|
|
92
91
|
// DbConnection and DbTx share.
|
|
93
92
|
const dbConn = ctx.db.unsafeRaw();
|
|
@@ -100,9 +99,8 @@ export function createInviteSignupCompleteHandler(opts = {}) {
|
|
|
100
99
|
...registrationLocale,
|
|
101
100
|
...(invitationGlobalRoles.length > 0 && { roles: invitationGlobalRoles }),
|
|
102
101
|
});
|
|
103
|
-
//
|
|
104
|
-
//
|
|
105
|
-
// weil createSystemUser nicht ["SystemAdmin"] matcht).
|
|
102
|
+
// The seed helper bypasses addMember's access check because
|
|
103
|
+
// createSystemUser does not match ["SystemAdmin"].
|
|
106
104
|
const forbiddenInviteRole = findForbiddenMembershipRole([invitationRole]);
|
|
107
105
|
if (forbiddenInviteRole !== undefined) {
|
|
108
106
|
return writeFailure(reservedMembershipRoleError(forbiddenInviteRole));
|
|
@@ -112,7 +110,7 @@ export function createInviteSignupCompleteHandler(opts = {}) {
|
|
|
112
110
|
tenantId: invitationTenantId,
|
|
113
111
|
roles: [invitationRole],
|
|
114
112
|
});
|
|
115
|
-
//
|
|
113
|
+
// Update the invitation in the invited tenant's database context.
|
|
116
114
|
const invitationTdb = createTenantDb({
|
|
117
115
|
db: dbConn,
|
|
118
116
|
tenantId: invitationTenantId,
|
|
@@ -45,7 +45,7 @@ type GateOutcome<T> = GateReject | GateOk<T>;
|
|
|
45
45
|
type AuthenticatableUserRow = AuthUserRow & {
|
|
46
46
|
readonly passwordHash: string;
|
|
47
47
|
};
|
|
48
|
-
/** Uniform response on any credential miss — burns argon2 cost
|
|
48
|
+
/** Uniform response on any credential miss — burns argon2 cost. */
|
|
49
49
|
export declare function gateResolveAuthUser(found: AuthUserRow | null, password: string): Promise<GateOutcome<AuthenticatableUserRow>>;
|
|
50
50
|
export declare function gateCountUnknownUser(ctx: HandlerContext, email: string, maxFailedAttempts: number, lockoutDurationMinutes: number): Promise<GateOutcome<undefined>>;
|
|
51
51
|
/**
|
|
@@ -14,7 +14,7 @@ function reject(result) {
|
|
|
14
14
|
function ok(value) {
|
|
15
15
|
return { ok: true, value };
|
|
16
16
|
}
|
|
17
|
-
/** Uniform response on any credential miss — burns argon2 cost
|
|
17
|
+
/** Uniform response on any credential miss — burns argon2 cost. */
|
|
18
18
|
export async function gateResolveAuthUser(found, password) {
|
|
19
19
|
if (!found?.passwordHash || found.isDeleted) {
|
|
20
20
|
await verifyDummyPassword(password);
|
|
@@ -16,7 +16,7 @@ export const selfRegistrationStatusQuery = defineQueryHandler({
|
|
|
16
16
|
rateLimit: { per: "ip+handler", limit: 30, windowSeconds: 60 },
|
|
17
17
|
description: "Reports whether self-registration is currently switched on, readable without signing in, so a signup page can hide its own form instead of collecting an address that would be silently ignored.",
|
|
18
18
|
handler: async (_query, ctx) => {
|
|
19
|
-
// Same fail-open reasoning as signup-request.write.ts
|
|
19
|
+
// Same fail-open reasoning as signup-request.write.ts: only
|
|
20
20
|
// report disabled when the toggle feature is actually composed.
|
|
21
21
|
const gated = ctx.registry.getFeature(AUTH_SELF_REGISTRATION_FEATURE) !== undefined;
|
|
22
22
|
return { enabled: gated ? await ctx.hasFeature(AUTH_SELF_REGISTRATION_FEATURE) : true };
|
|
@@ -1,23 +1,22 @@
|
|
|
1
|
-
// Magic-Link
|
|
1
|
+
// Magic-Link signup, step 2 (confirmation).
|
|
2
2
|
//
|
|
3
|
-
// Token
|
|
4
|
-
//
|
|
5
|
-
//
|
|
3
|
+
// Token from the URL + password from the user → redeem the token in Redis
|
|
4
|
+
// and atomically create the tenant, user, and TenantAdmin membership.
|
|
5
|
+
// emailVerified is set to true immediately—the magic link IS the proof.
|
|
6
6
|
//
|
|
7
7
|
// Pipeline:
|
|
8
8
|
// 1. Redis check: token → email lookup
|
|
9
|
-
// 2. Single-
|
|
10
|
-
//
|
|
11
|
-
//
|
|
12
|
-
//
|
|
13
|
-
//
|
|
14
|
-
//
|
|
15
|
-
//
|
|
16
|
-
// 5. Token-Keys löschen (burn-key bleibt für TTL-Replay-Protection)
|
|
9
|
+
// 2. Single-use burn (SETNX)—only one of two simultaneous tab clicks wins
|
|
10
|
+
// 3. Generate the tenant key (generateUniqueName with a DB isAvailable
|
|
11
|
+
// check against tenants.key)
|
|
12
|
+
// 4. provisionSignupAccount: create the tenant, user, and membership in one
|
|
13
|
+
// operation (through event-store-executor; events, projection, and MSPs
|
|
14
|
+
// see this as a regular create)
|
|
15
|
+
// 5. Delete the token keys (the burn key remains for TTL replay protection)
|
|
17
16
|
//
|
|
18
|
-
// Failure
|
|
19
|
-
//
|
|
20
|
-
//
|
|
17
|
+
// Failure recovery: every path after the burn checks the `committed` flag;
|
|
18
|
+
// when !committed, the burn is released so a legitimate retry is not blocked
|
|
19
|
+
// by a stale marker, as with reset/verify.
|
|
21
20
|
import { fetchOne } from "@cosmicdrift/kumiko-framework/db";
|
|
22
21
|
import { defineWriteHandler, } from "@cosmicdrift/kumiko-framework/engine";
|
|
23
22
|
import { ConflictError, InternalError, reraiseAsKumikoError, writeFailure, } from "@cosmicdrift/kumiko-framework/errors";
|
|
@@ -87,21 +86,21 @@ export function createSignupConfirmHandler(opts = {}) {
|
|
|
87
86
|
message: "signup-confirm requires ctx.redis for token consumption",
|
|
88
87
|
}));
|
|
89
88
|
}
|
|
90
|
-
// Token
|
|
91
|
-
//
|
|
89
|
+
// Token lookup: nonexistent, expired, and already-consumed tokens all
|
|
90
|
+
// collapse to invalid_signup_token to prevent enumeration.
|
|
92
91
|
const email = await getEmailForSignupToken(ctx.redis, event.payload.token);
|
|
93
92
|
if (!email)
|
|
94
93
|
return invalidSignupToken();
|
|
95
|
-
// Single-
|
|
96
|
-
//
|
|
94
|
+
// Single-use burn: of two parallel confirmations from different tabs,
|
|
95
|
+
// one succeeds and the other receives invalid_signup_token.
|
|
97
96
|
const burn = await burnSignupToken(ctx.redis, event.payload.token);
|
|
98
97
|
if (burn === "already-used")
|
|
99
98
|
return invalidSignupToken();
|
|
100
99
|
let committed = false;
|
|
101
100
|
try {
|
|
102
|
-
// Tenant
|
|
103
|
-
//
|
|
104
|
-
//
|
|
101
|
+
// Tenant key: a two-word slug from framework/random, with a DB conflict
|
|
102
|
+
// check against tenants.key. 22,500 default combinations plus a
|
|
103
|
+
// suffix fallback in case of collision (see generateUniqueName).
|
|
105
104
|
// @cast-boundary db-runner — helpers use only the query API that
|
|
106
105
|
// DbConnection and DbTx share.
|
|
107
106
|
const dbConn = ctx.db.unsafeRaw();
|
|
@@ -112,8 +111,8 @@ export function createSignupConfirmHandler(opts = {}) {
|
|
|
112
111
|
},
|
|
113
112
|
});
|
|
114
113
|
const tenantId = generateId(); // @cast-boundary engine-payload
|
|
115
|
-
//
|
|
116
|
-
//
|
|
114
|
+
// Use the email prefix as a meaningful default display name; the user can
|
|
115
|
+
// change the tenant name and their own displayName later.
|
|
117
116
|
const displayName = email.split("@")[0] ?? email;
|
|
118
117
|
const registrationLocale = registrationLocaleFromRequest();
|
|
119
118
|
let provisioned;
|
|
@@ -128,25 +127,24 @@ export function createSignupConfirmHandler(opts = {}) {
|
|
|
128
127
|
tenantName: tenantKey,
|
|
129
128
|
...registrationLocale,
|
|
130
129
|
},
|
|
131
|
-
//
|
|
130
|
+
// seedTenant's postSave hooks (tier-engine's auto-default-
|
|
132
131
|
// tier, an app's auto-default-compliance) must fire on self-signup
|
|
133
132
|
// exactly like they do on the regular TenantHandlers.create path.
|
|
134
133
|
{ registry: ctx.registry, context: ctx });
|
|
135
134
|
}
|
|
136
135
|
catch (err) {
|
|
137
|
-
//
|
|
138
|
-
//
|
|
139
|
-
// committed
|
|
140
|
-
//
|
|
136
|
+
// The email already has an account—provisionSignupAccount is create-only:
|
|
137
|
+
// return a clean user error and never create a session for that account.
|
|
138
|
+
// committed remains false, so finally releases the burn; a retry fails
|
|
139
|
+
// the same way without being blocked by a stale marker.
|
|
141
140
|
if (err instanceof ConflictError)
|
|
142
141
|
return signupEmailAlreadyRegistered();
|
|
143
142
|
throw err;
|
|
144
143
|
}
|
|
145
|
-
// SessionUser
|
|
146
|
-
//
|
|
147
|
-
//
|
|
148
|
-
//
|
|
149
|
-
// und JWT erzeugen.
|
|
144
|
+
// Build the SessionUser for JWT minting. Use roles from INITIAL_SIGNUP_ROLES
|
|
145
|
+
// so the database write (provisionSignupAccount) and session claim share
|
|
146
|
+
// one source; otherwise two hardcoded "TenantAdmin" values could drift
|
|
147
|
+
// during a refactor and create a role mismatch between the DB and JWT.
|
|
150
148
|
const session = {
|
|
151
149
|
id: provisioned.userId,
|
|
152
150
|
tenantId: provisioned.tenantId,
|
|
@@ -195,9 +193,8 @@ export function createSignupConfirmHandler(opts = {}) {
|
|
|
195
193
|
}
|
|
196
194
|
finally {
|
|
197
195
|
if (!committed && ctx.redis) {
|
|
198
|
-
//
|
|
199
|
-
//
|
|
200
|
-
// erneut klicken.
|
|
196
|
+
// Release the burn so a retry after a DB hiccup is not blocked.
|
|
197
|
+
// Keep the token lookup keys so the user can click the email link again.
|
|
201
198
|
await unburnSignupToken(ctx.redis, event.payload.token);
|
|
202
199
|
}
|
|
203
200
|
}
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
// Always-200 (enumeration-safe): the response looks the same for every
|
|
16
16
|
// email, whether it's already registered or not. An email CAN already have
|
|
17
17
|
// an account (seeding or an earlier signup) — the actual gate sits
|
|
18
|
-
// deliberately in the confirm step
|
|
18
|
+
// deliberately in the confirm step: signup-confirm rejects an
|
|
19
19
|
// already-registered email instead of reusing the existing user. Here it
|
|
20
20
|
// stays always-200 + resend-idempotent so the request path leaks nothing;
|
|
21
21
|
// suppressing the link on the request side would be defense-in-depth, but
|
|
@@ -31,10 +31,9 @@ import { issueSignupActivation } from "../signup-activation.js";
|
|
|
31
31
|
import { storeSignupHandover, takeOverSignupHandoverForResend } from "../signup-token-store.js";
|
|
32
32
|
const SignupRequestSchema = z.object({
|
|
33
33
|
email: z.email(),
|
|
34
|
-
// Cross-device try-first handover
|
|
35
|
-
//
|
|
36
|
-
//
|
|
37
|
-
// carrying it through the activation link.
|
|
34
|
+
// Cross-device try-first handover: see shared/signup-handover.ts for why the
|
|
35
|
+
// grant is verified here and rebound to the signup token instead of the
|
|
36
|
+
// client carrying it through the activation link.
|
|
38
37
|
handover: z
|
|
39
38
|
.object({
|
|
40
39
|
entityType: z.string().min(1),
|
|
@@ -64,8 +63,8 @@ export function createSignupRequestHandler(opts) {
|
|
|
64
63
|
// ctx.hasFeature() is fail-closed for *unregistered* names the moment
|
|
65
64
|
// feature-toggles/tier-engine is wired, which silently kills
|
|
66
65
|
// self-signup for every existing app that mounts auth-email-password
|
|
67
|
-
// without also composing createAuthSelfRegistrationToggleFeature()
|
|
68
|
-
//
|
|
66
|
+
// without also composing createAuthSelfRegistrationToggleFeature().
|
|
67
|
+
// Only gate when the toggle actually exists.
|
|
69
68
|
const gated = ctx.registry.getFeature(AUTH_SELF_REGISTRATION_FEATURE) !== undefined;
|
|
70
69
|
if (gated && !(await ctx.hasFeature(AUTH_SELF_REGISTRATION_FEATURE))) {
|
|
71
70
|
// No email address here — this fires on every no-op request, PII
|