@cosmicdrift/kumiko-samples 0.386.0 → 0.388.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/README.md +1 -1
- package/package.json +2 -2
- package/packages/bundled-features/package.json +9 -2
- package/packages/bundled-features/src/agent-tools/changes.json +6 -0
- package/packages/bundled-features/src/agent-tools/tool-catalog.ts +1 -1
- package/packages/bundled-features/src/agent-tools/tool-dispatch.ts +9 -9
- package/packages/bundled-features/src/audit/changes.json +12 -0
- package/packages/bundled-features/src/audit/handlers/audit-events.ts +1 -1
- package/packages/bundled-features/src/audit/screens.ts +1 -1
- package/packages/bundled-features/src/auth-email-password/auth-user-row.ts +10 -10
- package/packages/bundled-features/src/auth-email-password/feature.ts +6 -6
- package/packages/bundled-features/src/auth-email-password/handlers/change-password.write.ts +3 -3
- package/packages/bundled-features/src/auth-email-password/handlers/confirm-token-flow.ts +5 -5
- package/packages/bundled-features/src/auth-email-password/handlers/invite-accept-with-login.write.ts +1 -1
- package/packages/bundled-features/src/auth-email-password/handlers/invite-accept.write.ts +18 -18
- package/packages/bundled-features/src/auth-email-password/handlers/invite-create.write.ts +12 -12
- package/packages/bundled-features/src/auth-email-password/handlers/invite-info.query.ts +1 -1
- package/packages/bundled-features/src/auth-email-password/handlers/invite-signup-complete.write.ts +24 -26
- package/packages/bundled-features/src/auth-email-password/handlers/login.write.ts +1 -1
- package/packages/bundled-features/src/auth-email-password/handlers/self-registration-status.query.ts +1 -1
- package/packages/bundled-features/src/auth-email-password/handlers/signup-confirm.write.ts +34 -37
- package/packages/bundled-features/src/auth-email-password/handlers/signup-request.write.ts +6 -7
- package/packages/bundled-features/src/auth-email-password/handlers/switch-tenant-mfa-gate.write.ts +1 -5
- package/packages/bundled-features/src/auth-email-password/index.ts +5 -5
- package/packages/bundled-features/src/auth-email-password/lockout-store.ts +1 -1
- package/packages/bundled-features/src/auth-email-password/seeding.ts +63 -66
- package/packages/bundled-features/src/auth-email-password/signup-token-store.ts +8 -8
- package/packages/bundled-features/src/auth-email-password/testing.ts +3 -3
- package/packages/bundled-features/src/auth-email-password/web/auth-client.ts +57 -57
- package/packages/bundled-features/src/auth-email-password/web/auth-form-primitives.tsx +14 -14
- package/packages/bundled-features/src/auth-email-password/web/auth-gate.tsx +15 -16
- package/packages/bundled-features/src/auth-email-password/web/client-plugin.ts +11 -12
- package/packages/bundled-features/src/auth-email-password/web/confirm-account-unlock-screen.tsx +1 -1
- package/packages/bundled-features/src/auth-email-password/web/constants.ts +3 -3
- package/packages/bundled-features/src/auth-email-password/web/default-topbar-actions.tsx +14 -14
- package/packages/bundled-features/src/auth-email-password/web/forgot-password-screen.tsx +11 -11
- package/packages/bundled-features/src/auth-email-password/web/index.ts +5 -5
- package/packages/bundled-features/src/auth-email-password/web/invite-accept-screen.tsx +17 -17
- package/packages/bundled-features/src/auth-email-password/web/login-screen.tsx +3 -4
- package/packages/bundled-features/src/auth-email-password/web/reset-password-screen.tsx +16 -17
- package/packages/bundled-features/src/auth-email-password/web/session.tsx +34 -34
- package/packages/bundled-features/src/auth-email-password/web/signup-complete-screen.tsx +3 -3
- package/packages/bundled-features/src/auth-email-password/web/signup-screen.tsx +14 -14
- package/packages/bundled-features/src/auth-email-password/web/tenant-switcher.tsx +26 -27
- package/packages/bundled-features/src/auth-email-password/web/use-shell-user.ts +12 -13
- package/packages/bundled-features/src/auth-email-password/web/user-menu.tsx +17 -18
- package/packages/bundled-features/src/auth-email-password/web/verify-email-screen.tsx +11 -12
- package/packages/bundled-features/src/auth-foundation/boot-checks.ts +4 -4
- package/packages/bundled-features/src/auth-foundation/resolve-anonymous-access.ts +4 -4
- package/packages/bundled-features/src/auth-foundation/types.ts +2 -2
- package/packages/bundled-features/src/auth-mfa/changes.json +6 -0
- package/packages/bundled-features/src/auth-mfa/feature-exports.ts +2 -2
- package/packages/bundled-features/src/auth-mfa/feature.ts +6 -0
- package/packages/bundled-features/src/auth-mfa/handlers/disable.write.ts +3 -3
- package/packages/bundled-features/src/auth-mfa/handlers/enable-confirm-preauth.write.ts +4 -4
- package/packages/bundled-features/src/auth-mfa/handlers/enable-confirm.write.ts +2 -2
- package/packages/bundled-features/src/auth-mfa/handlers/enable-start-preauth.write.ts +1 -1
- package/packages/bundled-features/src/auth-mfa/handlers/reencrypt.job.ts +1 -1
- package/packages/bundled-features/src/auth-mfa/handlers/regenerate-recovery.write.ts +5 -5
- package/packages/bundled-features/src/auth-mfa/handlers/verify.write.ts +1 -1
- package/packages/bundled-features/src/auth-mfa/token-secrets.ts +1 -1
- package/packages/bundled-features/src/auth-mfa/web/client-plugin.ts +2 -2
- package/packages/bundled-features/src/auth-mfa/web/i18n.ts +9 -4
- package/packages/bundled-features/src/auth-mfa/web/index.ts +4 -4
- package/packages/bundled-features/src/auth-mfa/web/mfa-client.ts +17 -16
- package/packages/bundled-features/src/auth-mfa/web/mfa-code-or-recovery-field.tsx +68 -0
- package/packages/bundled-features/src/auth-mfa/web/mfa-disable-dialog.tsx +23 -13
- package/packages/bundled-features/src/auth-mfa/web/mfa-regenerate-recovery-dialog.tsx +23 -13
- package/packages/bundled-features/src/auth-mfa/web/mfa-setup-preauth-screen.tsx +15 -6
- package/packages/bundled-features/src/auth-mfa/web/mfa-verify-screen.tsx +71 -24
- package/packages/bundled-features/src/billing-foundation/aggregate-id.ts +10 -11
- package/packages/bundled-features/src/billing-foundation/changes.json +55 -0
- package/packages/bundled-features/src/billing-foundation/checkout-core.ts +32 -42
- package/packages/bundled-features/src/billing-foundation/consumer-protection/confirmation-mail.ts +8 -2
- package/packages/bundled-features/src/billing-foundation/consumer-protection/consent-gate.ts +2 -0
- package/packages/bundled-features/src/billing-foundation/consumer-protection/issue-confirmation.ts +14 -3
- package/packages/bundled-features/src/billing-foundation/consumer-protection/mail-notifications.ts +3 -4
- package/packages/bundled-features/src/billing-foundation/consumer-protection/termination-receipt-limit.ts +12 -6
- package/packages/bundled-features/src/billing-foundation/consumer-protection/termination-record.ts +35 -19
- package/packages/bundled-features/src/billing-foundation/consumer-protection/termination-request.ts +12 -8
- package/packages/bundled-features/src/billing-foundation/consumer-protection/termination-revoke.ts +14 -8
- package/packages/bundled-features/src/billing-foundation/consumer-protection/termination-texts.ts +5 -0
- package/packages/bundled-features/src/billing-foundation/consumer-protection/withdrawal-period.ts +8 -10
- package/packages/bundled-features/src/billing-foundation/entities.ts +27 -27
- package/packages/bundled-features/src/billing-foundation/events.ts +23 -21
- package/packages/bundled-features/src/billing-foundation/feature.ts +45 -44
- package/packages/bundled-features/src/billing-foundation/get-subscription-for-tenant.ts +3 -5
- package/packages/bundled-features/src/billing-foundation/handlers/billing-plans.query.ts +71 -6
- package/packages/bundled-features/src/billing-foundation/handlers/create-checkout-session.write.ts +19 -17
- package/packages/bundled-features/src/billing-foundation/handlers/create-portal-session.write.ts +11 -12
- package/packages/bundled-features/src/billing-foundation/handlers/list-subscriptions.query.ts +4 -4
- package/packages/bundled-features/src/billing-foundation/handlers/plan-switch-preview.query.ts +65 -0
- package/packages/bundled-features/src/billing-foundation/handlers/process-event.write.ts +29 -22
- package/packages/bundled-features/src/billing-foundation/handlers/start-plan-checkout.write.ts +44 -8
- package/packages/bundled-features/src/billing-foundation/handlers/switch-plan.write.ts +72 -82
- package/packages/bundled-features/src/billing-foundation/handlers/sync-subscription.write.ts +14 -1
- package/packages/bundled-features/src/billing-foundation/i18n.ts +22 -0
- package/packages/bundled-features/src/billing-foundation/index.ts +2 -0
- package/packages/bundled-features/src/billing-foundation/plan-catalog.ts +62 -27
- package/packages/bundled-features/src/billing-foundation/plan-switch.ts +84 -0
- package/packages/bundled-features/src/billing-foundation/projection.ts +38 -37
- package/packages/bundled-features/src/billing-foundation/subscription-tier-sync.ts +3 -3
- package/packages/bundled-features/src/billing-foundation/tenant-destroy-hook.ts +7 -8
- package/packages/bundled-features/src/billing-foundation/types.ts +144 -66
- package/packages/bundled-features/src/billing-foundation/validate-options.ts +19 -0
- package/packages/bundled-features/src/billing-foundation/web/billing-plans-panel.tsx +123 -51
- package/packages/bundled-features/src/billing-foundation/web/checkout-consent-dialog.tsx +89 -42
- package/packages/bundled-features/src/billing-foundation/web/constants.ts +4 -0
- package/packages/bundled-features/src/billing-foundation/web/plan-price.ts +55 -0
- package/packages/bundled-features/src/billing-foundation/web/plan-switch-confirm-dialog.tsx +224 -0
- package/packages/bundled-features/src/billing-foundation/webhook-handler.ts +1 -1
- package/packages/bundled-features/src/cap-counter/aggregate-id.ts +8 -9
- package/packages/bundled-features/src/cap-counter/cap-reservation.ts +5 -1
- package/packages/bundled-features/src/cap-counter/changes.json +18 -0
- package/packages/bundled-features/src/cap-counter/constants.ts +11 -12
- package/packages/bundled-features/src/cap-counter/enforce-cap.ts +66 -68
- package/packages/bundled-features/src/cap-counter/entity.ts +29 -29
- package/packages/bundled-features/src/cap-counter/feature.ts +34 -35
- package/packages/bundled-features/src/cap-counter/handlers/increment-rolling.write.ts +31 -31
- package/packages/bundled-features/src/cap-counter/handlers/mark-soft-warned.write.ts +4 -5
- package/packages/bundled-features/src/cap-counter/stock-cap-guard.ts +9 -2
- package/packages/bundled-features/src/cap-counter/with-cap-enforcement.ts +3 -5
- package/packages/bundled-features/src/cap-overview/handlers/caps-usage.query.ts +1 -3
- package/packages/bundled-features/src/cap-overview/handlers/tenant-caps-list.query.ts +1 -1
- package/packages/bundled-features/src/channel-email/changes.json +6 -0
- package/packages/bundled-features/src/channel-email/feature.ts +1 -1
- package/packages/bundled-features/src/channel-email/smtp-transport.ts +34 -31
- package/packages/bundled-features/src/channel-in-app/handlers/unread-count.query.ts +3 -4
- package/packages/bundled-features/src/compliance-profiles/feature.ts +15 -16
- package/packages/bundled-features/src/compliance-profiles/handlers/for-tenant.query.ts +3 -6
- package/packages/bundled-features/src/compliance-profiles/handlers/list-profiles.query.ts +5 -5
- package/packages/bundled-features/src/compliance-profiles/handlers/needs-profile.query.ts +4 -4
- package/packages/bundled-features/src/compliance-profiles/handlers/set-profile.write.ts +13 -14
- package/packages/bundled-features/src/compliance-profiles/handlers/sub-processors.query.ts +9 -11
- package/packages/bundled-features/src/compliance-profiles/resolve-for-tenant.ts +7 -7
- package/packages/bundled-features/src/compliance-profiles/schema/profile-selection.ts +18 -23
- package/packages/bundled-features/src/compliance-profiles/seeding.ts +14 -15
- package/packages/bundled-features/src/compliance-profiles-ops/handlers/tenants-missing-profile.query.ts +3 -3
- package/packages/bundled-features/src/compliance-profiles-ops/index.ts +2 -2
- package/packages/bundled-features/src/config/changes.json +12 -0
- package/packages/bundled-features/src/config/handlers/cascade.query.ts +4 -2
- package/packages/bundled-features/src/config/handlers/readiness.query.ts +7 -7
- package/packages/bundled-features/src/config/handlers/reencrypt.job.ts +4 -5
- package/packages/bundled-features/src/config/handlers/set.write.ts +4 -4
- package/packages/bundled-features/src/config/handlers/values.query.ts +4 -2
- package/packages/bundled-features/src/config/resolver.ts +4 -4
- package/packages/bundled-features/src/config/table.ts +10 -10
- package/packages/bundled-features/src/config/write-helpers.ts +28 -9
- package/packages/bundled-features/src/crypto-shredding/changes.json +6 -0
- package/packages/bundled-features/src/crypto-shredding/handlers/forget-subject.write.ts +23 -21
- package/packages/bundled-features/src/custom-fields/aggregate-id.ts +16 -17
- package/packages/bundled-features/src/custom-fields/entity.ts +49 -47
- package/packages/bundled-features/src/custom-fields/events.ts +7 -8
- package/packages/bundled-features/src/custom-fields/feature.ts +70 -72
- package/packages/bundled-features/src/custom-fields/handlers/clear-custom-field.write.ts +9 -8
- package/packages/bundled-features/src/custom-fields/handlers/define-tenant-field.write.ts +28 -26
- package/packages/bundled-features/src/custom-fields/handlers/delete-system-field.write.ts +6 -7
- package/packages/bundled-features/src/custom-fields/handlers/delete-tenant-field.write.ts +12 -13
- package/packages/bundled-features/src/custom-fields/handlers/set-custom-field.write.ts +25 -28
- package/packages/bundled-features/src/custom-fields/handlers/update-tenant-field.write.ts +6 -6
- package/packages/bundled-features/src/custom-fields/lib/field-access.ts +2 -2
- package/packages/bundled-features/src/custom-fields/lib/parse-serialized-field.ts +1 -1
- package/packages/bundled-features/src/custom-fields/lib/quota.ts +1 -1
- package/packages/bundled-features/src/custom-fields/lib/value-schema.ts +10 -12
- package/packages/bundled-features/src/custom-fields/run-retention.ts +3 -3
- package/packages/bundled-features/src/custom-fields/schemas.ts +14 -14
- package/packages/bundled-features/src/custom-fields/web/client-plugin.tsx +2 -5
- package/packages/bundled-features/src/custom-fields/web/constants.ts +2 -2
- package/packages/bundled-features/src/custom-fields/web/custom-fields-form-section.tsx +26 -26
- package/packages/bundled-features/src/custom-fields/wire-for-entity.ts +65 -67
- package/packages/bundled-features/src/custom-fields/wire-user-data-rights.ts +3 -3
- package/packages/bundled-features/src/data-retention/_internal/parse-override.ts +2 -3
- package/packages/bundled-features/src/data-retention/feature.ts +11 -18
- package/packages/bundled-features/src/data-retention/handlers/policy-for.query.ts +6 -6
- package/packages/bundled-features/src/data-retention/keep-for.ts +17 -17
- package/packages/bundled-features/src/data-retention/override-schema.ts +13 -15
- package/packages/bundled-features/src/data-retention/presets.ts +18 -23
- package/packages/bundled-features/src/data-retention/resolve-for-tenant.ts +1 -1
- package/packages/bundled-features/src/data-retention/resolve-tenant-preset.ts +17 -16
- package/packages/bundled-features/src/data-retention/resolver.ts +33 -32
- package/packages/bundled-features/src/data-retention/run-retention-cleanup.ts +71 -58
- package/packages/bundled-features/src/data-retention/schema/tenant-retention-override.ts +13 -11
- package/packages/bundled-features/src/delivery/changes.json +30 -0
- package/packages/bundled-features/src/delivery/channel-context.ts +9 -3
- package/packages/bundled-features/src/delivery/db/queries/preferences.ts +2 -2
- package/packages/bundled-features/src/delivery/delivery-service.ts +35 -5
- package/packages/bundled-features/src/delivery/feature.ts +3 -3
- package/packages/bundled-features/src/delivery/handlers/log.query.ts +1 -1
- package/packages/bundled-features/src/delivery/handlers/preferences.query.ts +20 -1
- package/packages/bundled-features/src/delivery/handlers/unsubscribe-page-chrome.query.ts +1 -1
- package/packages/bundled-features/src/delivery/tables.ts +9 -8
- package/packages/bundled-features/src/delivery/unsubscribe-link.ts +3 -1
- package/packages/bundled-features/src/delivery/unsubscribe-page-strings.ts +1 -0
- package/packages/bundled-features/src/delivery/unsubscribe-page.ts +6 -0
- package/packages/bundled-features/src/delivery/unsubscribe.ts +40 -19
- package/packages/bundled-features/src/delivery/upsert-preference.ts +3 -4
- package/packages/bundled-features/src/document-ingest-foundation/entity.ts +5 -5
- package/packages/bundled-features/src/document-ingest-foundation/events.ts +2 -2
- package/packages/bundled-features/src/document-ingest-foundation/feature.ts +2 -2
- package/packages/bundled-features/src/document-ingest-foundation/pages.ts +1 -1
- package/packages/bundled-features/src/document-ingest-foundation/tenant-destroy-hook.ts +4 -4
- package/packages/bundled-features/src/feature-toggles/compose-tier-resolver.ts +1 -1
- package/packages/bundled-features/src/feature-toggles/feature.ts +1 -1
- package/packages/bundled-features/src/feature-toggles/global-feature-state-table.ts +1 -1
- package/packages/bundled-features/src/feature-toggles/handlers/registered.query.ts +5 -5
- package/packages/bundled-features/src/feature-toggles/toggle-runtime.ts +1 -1
- package/packages/bundled-features/src/feature-toggles/toggle-sync-signal.ts +1 -1
- package/packages/bundled-features/src/feature-toggles/web/constants.ts +1 -1
- package/packages/bundled-features/src/file-derivatives/feature.ts +2 -2
- package/packages/bundled-features/src/file-derivatives/handlers/public-variant.query.ts +1 -1
- package/packages/bundled-features/src/file-derivatives/presets.ts +1 -1
- package/packages/bundled-features/src/file-foundation/feature.ts +6 -6
- package/packages/bundled-features/src/file-foundation/index.ts +1 -0
- package/packages/bundled-features/src/file-foundation/read-file-ref-content.ts +7 -1
- package/packages/bundled-features/src/file-provider-inmemory/feature.ts +16 -16
- package/packages/bundled-features/src/file-provider-s3/env-named-feature.ts +0 -2
- package/packages/bundled-features/src/file-provider-s3/feature.ts +16 -16
- package/packages/bundled-features/src/file-provider-s3/lib/s3-provider.ts +6 -6
- package/packages/bundled-features/src/files/README.md +1 -1
- package/packages/bundled-features/src/files/feature.ts +6 -6
- package/packages/bundled-features/src/files-tenant-data/handlers/sweep-orphaned-derivatives.job.ts +5 -5
- package/packages/bundled-features/src/files-tenant-data/hooks.ts +24 -26
- package/packages/bundled-features/src/files-tenant-data/index.ts +1 -1
- package/packages/bundled-features/src/folders/feature.ts +1 -1
- package/packages/bundled-features/src/folders/web/folder-manager.tsx +2 -2
- package/packages/bundled-features/src/folders/web/tree.ts +5 -5
- package/packages/bundled-features/src/form-draft/changes.json +6 -0
- package/packages/bundled-features/src/form-draft/db/queries/cleanup.ts +3 -3
- package/packages/bundled-features/src/form-draft/db/queries/owned-file-refs.ts +1 -1
- package/packages/bundled-features/src/form-draft/decrypt-draft.ts +4 -1
- package/packages/bundled-features/src/form-draft/entity.ts +3 -3
- package/packages/bundled-features/src/form-draft/feature.ts +4 -5
- package/packages/bundled-features/src/form-draft/handlers/discard.write.ts +1 -1
- package/packages/bundled-features/src/form-draft/release-file-refs.ts +6 -6
- package/packages/bundled-features/src/form-draft/schemas.ts +3 -3
- package/packages/bundled-features/src/form-draft/web/constants.ts +0 -2
- package/packages/bundled-features/src/host-routing/README.md +1 -1
- package/packages/bundled-features/src/host-routing/changes.json +6 -0
- package/packages/bundled-features/src/host-routing/dispatch.ts +16 -17
- package/packages/bundled-features/src/host-routing/options.ts +2 -1
- package/packages/bundled-features/src/inbound-mail-foundation/aggregate-id.ts +19 -19
- package/packages/bundled-features/src/inbound-mail-foundation/changes.json +18 -0
- package/packages/bundled-features/src/inbound-mail-foundation/connect-routes.ts +4 -3
- package/packages/bundled-features/src/inbound-mail-foundation/constants.ts +30 -33
- package/packages/bundled-features/src/inbound-mail-foundation/entities.ts +47 -48
- package/packages/bundled-features/src/inbound-mail-foundation/events.ts +54 -50
- package/packages/bundled-features/src/inbound-mail-foundation/feature.ts +39 -39
- package/packages/bundled-features/src/inbound-mail-foundation/handlers/account-state.ts +8 -8
- package/packages/bundled-features/src/inbound-mail-foundation/handlers/connect-account.write.ts +25 -26
- package/packages/bundled-features/src/inbound-mail-foundation/handlers/disconnect-account.write.ts +7 -7
- package/packages/bundled-features/src/inbound-mail-foundation/handlers/ingest-message.write.ts +50 -51
- package/packages/bundled-features/src/inbound-mail-foundation/handlers/list-accounts.query.ts +8 -8
- package/packages/bundled-features/src/inbound-mail-foundation/handlers/list-messages.query.ts +10 -10
- package/packages/bundled-features/src/inbound-mail-foundation/handlers/scope-visibility.ts +3 -4
- package/packages/bundled-features/src/inbound-mail-foundation/handlers/update-account.write.ts +27 -15
- package/packages/bundled-features/src/inbound-mail-foundation/i18n.ts +0 -1
- package/packages/bundled-features/src/inbound-mail-foundation/oauth-state.ts +16 -15
- package/packages/bundled-features/src/inbound-mail-foundation/projection.ts +31 -29
- package/packages/bundled-features/src/inbound-mail-foundation/provider-factory.ts +9 -9
- package/packages/bundled-features/src/inbound-mail-foundation/retention-sweep.ts +45 -41
- package/packages/bundled-features/src/inbound-mail-foundation/screens.ts +0 -3
- package/packages/bundled-features/src/inbound-mail-foundation/tenant-destroy-hook.ts +14 -16
- package/packages/bundled-features/src/inbound-mail-foundation/types.ts +70 -70
- package/packages/bundled-features/src/inbound-mail-foundation/watch-supervisor.ts +101 -84
- package/packages/bundled-features/src/inbound-provider-imap/credential-document.ts +13 -13
- package/packages/bundled-features/src/inbound-provider-imap/feature.ts +42 -40
- package/packages/bundled-features/src/inbound-provider-imap/imap-client.ts +20 -19
- package/packages/bundled-features/src/inbound-provider-inmemory/feature.ts +21 -21
- package/packages/bundled-features/src/jobs/changes.json +13 -0
- package/packages/bundled-features/src/jobs/db/queries/retention.ts +2 -2
- package/packages/bundled-features/src/jobs/db/queries/stale-run-sweep.ts +3 -3
- package/packages/bundled-features/src/jobs/events.ts +1 -1
- package/packages/bundled-features/src/jobs/feature.ts +20 -11
- package/packages/bundled-features/src/jobs/handlers/detail.query.ts +4 -4
- package/packages/bundled-features/src/jobs/handlers/list.query.ts +1 -1
- package/packages/bundled-features/src/jobs/handlers/projection-rebuild.job.ts +1 -1
- package/packages/bundled-features/src/jobs/handlers/reindex-entity.job.ts +1 -1
- package/packages/bundled-features/src/jobs/handlers/retry.write.ts +1 -1
- package/packages/bundled-features/src/jobs/handlers/tenant-failures.query.ts +45 -40
- package/packages/bundled-features/src/jobs/handlers/tenant-runs.query.ts +63 -59
- package/packages/bundled-features/src/jobs/job-instant.ts +1 -1
- package/packages/bundled-features/src/jobs/job-run-logger.ts +19 -19
- package/packages/bundled-features/src/jobs/job-run-table.ts +3 -3
- package/packages/bundled-features/src/jobs/screens.ts +1 -1
- package/packages/bundled-features/src/jobs/tenant-job-failure-table.ts +1 -1
- package/packages/bundled-features/src/jobs/tenant-job-run-table.ts +1 -1
- package/packages/bundled-features/src/ledger/entity.ts +5 -5
- package/packages/bundled-features/src/ledger/feature.ts +3 -3
- package/packages/bundled-features/src/ledger/handlers/confirm-schedule-period.write.ts +3 -3
- package/packages/bundled-features/src/ledger/recurring.ts +12 -12
- package/packages/bundled-features/src/ledger/schemas.ts +1 -1
- package/packages/bundled-features/src/ledger/web/constants.ts +2 -2
- package/packages/bundled-features/src/ledger/web/index.ts +7 -7
- package/packages/bundled-features/src/legal-pages/README.md +1 -1
- package/packages/bundled-features/src/legal-pages/feature.ts +40 -41
- package/packages/bundled-features/src/legal-pages/markdown.ts +3 -3
- package/packages/bundled-features/src/legal-pages/web/client-plugin.ts +23 -24
- package/packages/bundled-features/src/legal-pages/web/index.ts +0 -2
- package/packages/bundled-features/src/mail-foundation/changes.json +6 -0
- package/packages/bundled-features/src/mail-foundation/feature.ts +31 -30
- package/packages/bundled-features/src/mail-transport-inmemory/feature.ts +27 -28
- package/packages/bundled-features/src/mail-transport-smtp/feature.ts +20 -20
- package/packages/bundled-features/src/managed-pages/branding.ts +6 -6
- package/packages/bundled-features/src/managed-pages/feature.ts +62 -62
- package/packages/bundled-features/src/managed-pages/handlers/by-slug.query.ts +5 -6
- package/packages/bundled-features/src/managed-pages/handlers/by-tenant-published.query.ts +8 -8
- package/packages/bundled-features/src/managed-pages/handlers/set.write.ts +5 -7
- package/packages/bundled-features/src/managed-pages/screens/page-screens.ts +11 -11
- package/packages/bundled-features/src/managed-pages/seeding.ts +8 -8
- package/packages/bundled-features/src/managed-pages/table.ts +16 -15
- package/packages/bundled-features/src/managed-pages/web/client-plugin.tsx +6 -6
- package/packages/bundled-features/src/managed-pages/web/i18n.ts +1 -1
- package/packages/bundled-features/src/notes-history/entity.ts +4 -4
- package/packages/bundled-features/src/notes-history/feature.ts +2 -2
- package/packages/bundled-features/src/notes-history-user-data/hooks.ts +1 -1
- package/packages/bundled-features/src/page-render/layout.ts +9 -9
- package/packages/bundled-features/src/page-render/markdown.ts +11 -11
- package/packages/bundled-features/src/page-render/security-headers.ts +7 -6
- package/packages/bundled-features/src/personal-access-tokens/feature.ts +9 -6
- package/packages/bundled-features/src/personal-access-tokens/roles.ts +2 -2
- package/packages/bundled-features/src/readiness/handlers/status.query.ts +3 -3
- package/packages/bundled-features/src/renderer-foundation/api.ts +12 -13
- package/packages/bundled-features/src/renderer-foundation/constants.ts +2 -2
- package/packages/bundled-features/src/renderer-foundation/feature.ts +7 -7
- package/packages/bundled-features/src/renderer-foundation/types.ts +11 -12
- package/packages/bundled-features/src/renderer-pdf/changes.json +6 -0
- package/packages/bundled-features/src/renderer-pdf/render-table-pdf.ts +27 -10
- package/packages/bundled-features/src/secrets/feature.ts +9 -9
- package/packages/bundled-features/src/secrets/web/constants.ts +2 -2
- package/packages/bundled-features/src/seo/feature.ts +3 -3
- package/packages/bundled-features/src/sessions/constants.ts +1 -1
- package/packages/bundled-features/src/sessions/feature.ts +16 -11
- package/packages/bundled-features/src/sessions/handlers/revoke-all-for-user.write.ts +2 -2
- package/packages/bundled-features/src/sessions/handlers/revoke-all-others.write.ts +2 -2
- package/packages/bundled-features/src/sessions/handlers/revoke.write.ts +1 -1
- package/packages/bundled-features/src/sessions/schema/user-session.ts +4 -4
- package/packages/bundled-features/src/sessions/screens.ts +2 -2
- package/packages/bundled-features/src/sessions/session-callbacks.ts +2 -2
- package/packages/bundled-features/src/sessions/session-revoked-event.ts +2 -2
- package/packages/bundled-features/src/shared/assert-no-where-rule-in-ownership-write.ts +1 -1
- package/packages/bundled-features/src/shared/decrypt-stored-pii.ts +11 -1
- package/packages/bundled-features/src/shared/encrypt-for-direct-write.ts +1 -1
- package/packages/bundled-features/src/shared/index.ts +1 -1
- package/packages/bundled-features/src/shared/mail-template-body.ts +10 -3
- package/packages/bundled-features/src/shared/map-with-concurrency.ts +5 -4
- package/packages/bundled-features/src/shared/parent-visibility.ts +2 -2
- package/packages/bundled-features/src/shared/password-hashing.ts +1 -1
- package/packages/bundled-features/src/shared/signup-handover.ts +1 -2
- package/packages/bundled-features/src/shared/single-use-token-store.ts +1 -1
- package/packages/bundled-features/src/step-dispatcher/changes.json +6 -0
- package/packages/bundled-features/src/step-dispatcher/feature.ts +1 -0
- package/packages/bundled-features/src/subscription-dodo/changes.json +14 -0
- package/packages/bundled-features/src/subscription-dodo/client.ts +45 -0
- package/packages/bundled-features/src/subscription-dodo/constants.ts +24 -0
- package/packages/bundled-features/src/subscription-dodo/feature.ts +207 -0
- package/packages/bundled-features/src/subscription-dodo/index.ts +16 -0
- package/packages/bundled-features/src/subscription-dodo/plugin-methods.ts +345 -0
- package/packages/bundled-features/src/subscription-dodo/runtime.ts +126 -0
- package/packages/bundled-features/src/subscription-dodo/verify-webhook.ts +262 -0
- package/packages/bundled-features/src/subscription-mollie/constants.ts +15 -17
- package/packages/bundled-features/src/subscription-mollie/feature.ts +41 -42
- package/packages/bundled-features/src/subscription-mollie/index.ts +3 -3
- package/packages/bundled-features/src/subscription-mollie/plugin-methods.ts +17 -16
- package/packages/bundled-features/src/subscription-mollie/verify-webhook.ts +34 -34
- package/packages/bundled-features/src/subscription-stripe/changes.json +12 -0
- package/packages/bundled-features/src/subscription-stripe/constants.ts +4 -6
- package/packages/bundled-features/src/subscription-stripe/feature.ts +45 -43
- package/packages/bundled-features/src/subscription-stripe/index.ts +6 -6
- package/packages/bundled-features/src/subscription-stripe/plugin-methods.ts +22 -27
- package/packages/bundled-features/src/subscription-stripe/runtime.ts +9 -8
- package/packages/bundled-features/src/subscription-stripe/verify-webhook.ts +62 -64
- package/packages/bundled-features/src/tags/feature.ts +3 -3
- package/packages/bundled-features/src/tags/screens.ts +1 -1
- package/packages/bundled-features/src/template-resolver/api.ts +41 -14
- package/packages/bundled-features/src/template-resolver/changes.json +48 -0
- package/packages/bundled-features/src/template-resolver/compile-document-body.ts +1 -0
- package/packages/bundled-features/src/template-resolver/feature.ts +2 -2
- package/packages/bundled-features/src/template-resolver/handlers/bundle-import.ts +3 -2
- package/packages/bundled-features/src/template-resolver/handlers/copy-locale.write.ts +27 -5
- package/packages/bundled-features/src/template-resolver/handlers/diff-to-system.query.ts +3 -2
- package/packages/bundled-features/src/template-resolver/handlers/document-base.ts +3 -2
- package/packages/bundled-features/src/template-resolver/handlers/find-by-id.query.ts +8 -7
- package/packages/bundled-features/src/template-resolver/handlers/list.query.ts +19 -20
- package/packages/bundled-features/src/template-resolver/handlers/overview.query.ts +15 -5
- package/packages/bundled-features/src/template-resolver/handlers/shared.ts +2 -2
- package/packages/bundled-features/src/template-resolver/handlers/template-write.ts +3 -3
- package/packages/bundled-features/src/template-resolver/handlers/tenant-override-counts.query.ts +9 -5
- package/packages/bundled-features/src/template-resolver/handlers/tenant-override-selection.ts +8 -6
- package/packages/bundled-features/src/template-resolver/handlers/tenant-overrides.query.ts +44 -5
- package/packages/bundled-features/src/template-resolver/handlers/upsert-system.write.ts +3 -4
- package/packages/bundled-features/src/template-resolver/handlers/upsert-tenant.write.ts +4 -5
- package/packages/bundled-features/src/template-resolver/handlers/usage.query.ts +37 -26
- package/packages/bundled-features/src/template-resolver/handlers/validate.query.ts +7 -2
- package/packages/bundled-features/src/template-resolver/seeding.ts +36 -18
- package/packages/bundled-features/src/template-resolver/store-template-resource.ts +22 -4
- package/packages/bundled-features/src/template-resolver/table.ts +13 -14
- package/packages/bundled-features/src/template-resolver/template-delivery-policy.ts +0 -11
- package/packages/bundled-features/src/template-resolver/template-meta.ts +12 -4
- package/packages/bundled-features/src/template-resolver/template-preview.ts +11 -3
- package/packages/bundled-features/src/template-resolver/web/client-plugin.tsx +2 -2
- package/packages/bundled-features/src/template-resolver/web/constants.ts +7 -5
- package/packages/bundled-features/src/template-resolver/web/index.ts +7 -0
- package/packages/bundled-features/src/template-resolver/web/mail-layout-constants.ts +8 -0
- package/packages/bundled-features/src/tenant/changes.json +6 -0
- package/packages/bundled-features/src/tenant/feature.ts +7 -7
- package/packages/bundled-features/src/tenant/handlers/member-directory.query.ts +10 -4
- package/packages/bundled-features/src/tenant/handlers/members.query.ts +1 -1
- package/packages/bundled-features/src/tenant/handlers/memberships.query.ts +1 -1
- package/packages/bundled-features/src/tenant/handlers/team-list.query.ts +1 -1
- package/packages/bundled-features/src/tenant/handlers/tenant-directory.query.ts +8 -5
- package/packages/bundled-features/src/tenant/invitation-table.ts +37 -40
- package/packages/bundled-features/src/tenant/membership-table.ts +3 -3
- package/packages/bundled-features/src/tenant/schema/tenant.ts +7 -9
- package/packages/bundled-features/src/tenant/screens.ts +1 -1
- package/packages/bundled-features/src/tenant/seeding.ts +19 -18
- package/packages/bundled-features/src/tenant/testing.ts +5 -6
- package/packages/bundled-features/src/tenant/web/constants.ts +2 -2
- package/packages/bundled-features/src/tenant-handover/events.ts +5 -7
- package/packages/bundled-features/src/tenant-handover/feature.ts +1 -1
- package/packages/bundled-features/src/tenant-handover/grant.ts +1 -1
- package/packages/bundled-features/src/tenant-handover/handlers/claim.write.ts +1 -1
- package/packages/bundled-features/src/tenant-handover/move-entity-graph.ts +8 -9
- package/packages/bundled-features/src/tenant-handover/signup-handover-provider.ts +1 -2
- package/packages/bundled-features/src/tenant-handover/transfer-graph.ts +4 -5
- package/packages/bundled-features/src/tenant-lifecycle/boot-checks.ts +1 -1
- package/packages/bundled-features/src/tenant-lifecycle/changes.json +6 -0
- package/packages/bundled-features/src/tenant-lifecycle/constants.ts +5 -0
- package/packages/bundled-features/src/tenant-lifecycle/feature.ts +1 -1
- package/packages/bundled-features/src/tenant-lifecycle/run-tenant-destroy.ts +7 -3
- package/packages/bundled-features/src/tenant-lifecycle/stages.ts +1 -1
- package/packages/bundled-features/src/tenant-settings/constants.ts +1 -1
- package/packages/bundled-features/src/tenant-settings/tenant-defaults.ts +12 -5
- package/packages/bundled-features/src/tier-engine/aggregate-id.ts +15 -16
- package/packages/bundled-features/src/tier-engine/changes.json +6 -0
- package/packages/bundled-features/src/tier-engine/compose-app.ts +14 -14
- package/packages/bundled-features/src/tier-engine/entity.ts +18 -19
- package/packages/bundled-features/src/tier-engine/feature.ts +88 -87
- package/packages/bundled-features/src/tier-engine/handlers/active-tier.query.ts +6 -7
- package/packages/bundled-features/src/tier-engine/handlers/get-tenant-tier.query.ts +4 -4
- package/packages/bundled-features/src/tier-engine/handlers/set-tenant-tier.write.ts +12 -9
- package/packages/bundled-features/src/tier-engine/tier-resolver.ts +2 -2
- package/packages/bundled-features/src/tier-engine/trial.ts +13 -13
- package/packages/bundled-features/src/tier-engine/web/constants.ts +3 -3
- package/packages/bundled-features/src/tier-engine/web/index.ts +4 -4
- package/packages/bundled-features/src/user/db/queries/stream-tenant-backfill.ts +8 -8
- package/packages/bundled-features/src/user/handlers/create.write.ts +4 -4
- package/packages/bundled-features/src/user/schema/user.ts +45 -44
- package/packages/bundled-features/src/user/seeding.ts +40 -40
- package/packages/bundled-features/src/user/testing.ts +3 -3
- package/packages/bundled-features/src/user-data-rights/audit-download.ts +27 -28
- package/packages/bundled-features/src/user-data-rights/boot-checks.ts +1 -1
- package/packages/bundled-features/src/user-data-rights/deletion-token.ts +1 -1
- package/packages/bundled-features/src/user-data-rights/feature.ts +112 -113
- package/packages/bundled-features/src/user-data-rights/handlers/cancel-deletion.write.ts +9 -9
- package/packages/bundled-features/src/user-data-rights/handlers/confirm-deletion-by-token.write.ts +8 -8
- package/packages/bundled-features/src/user-data-rights/handlers/download-by-job.query.ts +29 -30
- package/packages/bundled-features/src/user-data-rights/handlers/download-by-token.query.ts +40 -42
- package/packages/bundled-features/src/user-data-rights/handlers/export-status.query.ts +8 -9
- package/packages/bundled-features/src/user-data-rights/handlers/lift-restriction.write.ts +7 -8
- package/packages/bundled-features/src/user-data-rights/handlers/list-download-attempts.query.ts +2 -2
- package/packages/bundled-features/src/user-data-rights/handlers/my-audit-log.query.ts +4 -4
- package/packages/bundled-features/src/user-data-rights/handlers/request-deletion-by-email.write.ts +30 -29
- package/packages/bundled-features/src/user-data-rights/handlers/request-deletion.write.ts +15 -18
- package/packages/bundled-features/src/user-data-rights/handlers/request-export.write.ts +42 -41
- package/packages/bundled-features/src/user-data-rights/handlers/restrict-account.write.ts +22 -19
- package/packages/bundled-features/src/user-data-rights/handlers/run-forget-cleanup.write.ts +8 -8
- package/packages/bundled-features/src/user-data-rights/index.ts +8 -10
- package/packages/bundled-features/src/user-data-rights/lib/default-mailers.ts +3 -3
- package/packages/bundled-features/src/user-data-rights/lib/update-user-lifecycle.ts +24 -27
- package/packages/bundled-features/src/user-data-rights/run-export-jobs.ts +169 -280
- package/packages/bundled-features/src/user-data-rights/run-forget-cleanup.ts +87 -108
- package/packages/bundled-features/src/user-data-rights/run-user-export.ts +67 -69
- package/packages/bundled-features/src/user-data-rights/schema/download-attempt.ts +11 -11
- package/packages/bundled-features/src/user-data-rights/schema/download-token.ts +37 -41
- package/packages/bundled-features/src/user-data-rights/schema/export-job.ts +65 -67
- package/packages/bundled-features/src/user-data-rights/token-helpers.ts +21 -25
- package/packages/bundled-features/src/user-data-rights/web/client-plugin.tsx +6 -6
- package/packages/bundled-features/src/user-data-rights/web/confirm-deletion-screen.tsx +6 -5
- package/packages/bundled-features/src/user-data-rights/web/constants.ts +1 -1
- package/packages/bundled-features/src/user-data-rights/web/index.ts +5 -5
- package/packages/bundled-features/src/user-data-rights/web/privacy-center-screen.tsx +14 -13
- package/packages/bundled-features/src/user-data-rights/web/public-deletion-gate.tsx +13 -12
- package/packages/bundled-features/src/user-data-rights/web/request-deletion-screen.tsx +6 -6
- package/packages/bundled-features/src/user-data-rights/zip-path.ts +41 -40
- package/packages/bundled-features/src/user-data-rights-defaults/feature.ts +15 -15
- package/packages/bundled-features/src/user-data-rights-defaults/hooks/delivery-attempt.userdata-hook.ts +3 -5
- package/packages/bundled-features/src/user-data-rights-defaults/hooks/file-ref.userdata-hook.ts +45 -51
- package/packages/bundled-features/src/user-data-rights-defaults/hooks/job-run.userdata-hook.ts +2 -2
- package/packages/bundled-features/src/user-data-rights-defaults/hooks/notification-preference.userdata-hook.ts +1 -1
- package/packages/bundled-features/src/user-data-rights-defaults/hooks/user-session.userdata-hook.ts +3 -3
- package/packages/bundled-features/src/user-data-rights-defaults/hooks/user.userdata-hook.ts +32 -31
- package/packages/bundled-features/src/user-profile/handlers/change-email.write.ts +13 -13
- package/packages/bundled-features/src/user-profile/index.ts +3 -3
- package/packages/bundled-features/src/user-profile/web/client-plugin.ts +1 -1
- package/packages/bundled-features/src/user-profile/web/constants.ts +1 -1
- package/packages/bundled-features/src/user-profile/web/profile-screen.tsx +1 -1
- package/packages/bundled-features/src/waitlist/changes.json +18 -0
- package/packages/bundled-features/src/waitlist/handlers/export-purge.write.ts +2 -1
- package/packages/bundled-features/src/waitlist/handlers/submit.write.ts +5 -5
- package/packages/bundled-features/src/waitlist/import.ts +5 -0
- package/packages/bundled-features/src/waitlist/legacy-migrate.ts +22 -3
- package/packages/bundled-features/src/waitlist/link-on-signup.ts +20 -10
- package/packages/bundled-features/src/waitlist/options.ts +3 -0
- package/packages/bundled-features/src/workflow-runner/aggregate-id.ts +1 -1
- package/packages/bundled-features/src/workflow-runner/event-subscriber.ts +4 -5
- package/packages/bundled-features/src/workflow-runner/event-trigger.ts +4 -15
- package/packages/bundled-features/src/workflow-runner/feature.ts +2 -2
- package/packages/bundled-features/src/workflow-runner/handlers/resume-run.write.ts +4 -4
- package/packages/bundled-features/src/workflow-runner/pending-projection.ts +6 -7
- package/packages/bundled-features/src/workflow-runner/runner.ts +6 -6
- package/packages/bundled-features/src/workflow-runner/tables.ts +6 -6
- package/packages/bundled-features/src/workflow-runner/workflow-registry.ts +1 -1
- package/samples/apps/styleguide/src/features/widgets/i18n.ts +11 -0
- package/samples/apps/styleguide/src/features/widgets/web/Widgets.tsx +24 -0
- package/samples/apps/use-all-bundled/e2e-billing-gallery/gallery-constants.ts +5 -0
- package/samples/apps/use-all-bundled/e2e-billing-gallery/gallery-features.ts +90 -15
- package/samples/apps/use-all-bundled/e2e-billing-gallery/server.ts +16 -6
- package/samples/apps/use-all-bundled/feature-manifest.json +120 -3
- package/samples/apps/use-all-bundled/src/run-config.ts +9 -3
- package/samples/recipes/auth-mfa/README.md +5 -0
- package/samples/recipes/auth-mfa/package.json +5 -2
- package/samples/recipes/auth-mfa/src/web/confirmation-code-step.tsx +49 -0
- package/samples/recipes/auth-mfa/tsconfig.json +8 -0
- package/samples/recipes/env-composition/README.md +3 -1
- package/samples/recipes/env-composition/src/env.ts +2 -0
- package/samples/recipes/legal-pages/README.md +1 -1
- package/samples/recipes/rate-limiting/README.md +18 -0
- package/samples/recipes/rate-limiting/src/feature.ts +12 -0
- package/packages/bundled-features/src/billing-foundation/consumer-protection/stored-user-email.ts +0 -12
|
@@ -8,7 +8,7 @@ import type { MfaTokenSecretsEnv } from "./token-secrets.ts";
|
|
|
8
8
|
|
|
9
9
|
export type BindMfaRevokeAllOtherSessions = (
|
|
10
10
|
revoker: (userId: string, currentSid: string | undefined) => Promise<number>,
|
|
11
|
-
) => void;
|
|
11
|
+
) => () => void;
|
|
12
12
|
|
|
13
13
|
// Reads the late-bind setter off a mounted auth-mfa feature's exports —
|
|
14
14
|
// mirrors sessions' own bindAutoRevokeFromFeature. run{Prod,Dev}App call
|
|
@@ -79,7 +79,7 @@ export function bindMfaTokenSecretsFromFeature(
|
|
|
79
79
|
return undefined;
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
-
export type BindRevokeAllPatTokens = (revoker: (userId: string) => Promise<number>) => void;
|
|
82
|
+
export type BindRevokeAllPatTokens = (revoker: (userId: string) => Promise<number>) => () => void;
|
|
83
83
|
|
|
84
84
|
// Reads the late-bind setter off a mounted auth-mfa feature's exports —
|
|
85
85
|
// run{Prod,Dev}App call this once the personal-access-tokens feature (if
|
|
@@ -220,10 +220,16 @@ export function createAuthMfaFeature(
|
|
|
220
220
|
|
|
221
221
|
const bindRevokeAllOtherSessions: BindMfaRevokeAllOtherSessions = (revoker) => {
|
|
222
222
|
revokeAllOtherSessions = revoker;
|
|
223
|
+
return () => {
|
|
224
|
+
if (revokeAllOtherSessions === revoker) revokeAllOtherSessions = undefined;
|
|
225
|
+
};
|
|
223
226
|
};
|
|
224
227
|
|
|
225
228
|
const bindRevokeAllPatTokens: BindRevokeAllPatTokens = (revoker) => {
|
|
226
229
|
revokeAllPatTokens = revoker;
|
|
230
|
+
return () => {
|
|
231
|
+
if (revokeAllPatTokens === revoker) revokeAllPatTokens = undefined;
|
|
232
|
+
};
|
|
227
233
|
};
|
|
228
234
|
|
|
229
235
|
return {
|
|
@@ -45,9 +45,9 @@ export function createDisableHandler(opts: DisableOptions) {
|
|
|
45
45
|
if (!row) return mfaNotEnabled();
|
|
46
46
|
|
|
47
47
|
// Fail closed, matching verify.write.ts/enable-confirm-preauth.write.ts
|
|
48
|
-
//
|
|
49
|
-
//
|
|
50
|
-
//
|
|
48
|
+
// without ctx.redis, verifyMfaFactor's TOTP-replay burn is skipped, and
|
|
49
|
+
// a code observed once (phishing proxy/shoulder-surfing) could be
|
|
50
|
+
// replayed within the ±1-step window to disable MFA outright.
|
|
51
51
|
// "no ctx.redis means no one gets through MFA login" doesn't cover
|
|
52
52
|
// this route — it's session-authed, and JWTs issued before Redis was
|
|
53
53
|
// unwired stay valid until they expire.
|
|
@@ -150,8 +150,8 @@ export function createEnableConfirmPreauthHandler(opts: EnableConfirmPreauthOpti
|
|
|
150
150
|
// re-enrollment until an operator manually disables MFA. NOT fixed by
|
|
151
151
|
// this ordering: burnToken() above still runs before this check, so a
|
|
152
152
|
// mid-flight restricted/deleted user still burns their setup token
|
|
153
|
-
//
|
|
154
|
-
//
|
|
153
|
+
// — moving the burn later would need care around the
|
|
154
|
+
// existing userId-unique-constraint backstop between the
|
|
155
155
|
// `existing` check above and executor.create() below.
|
|
156
156
|
const systemUser = createSystemUser(tenantId, ["SystemAdmin"]);
|
|
157
157
|
const userRow = (await ctx.queryAs(systemUser, UserQueries.findForAuth, {
|
|
@@ -207,10 +207,10 @@ export function createEnableConfirmPreauthHandler(opts: EnableConfirmPreauthOpti
|
|
|
207
207
|
id: userId,
|
|
208
208
|
tenantId,
|
|
209
209
|
roles: mergedRoles,
|
|
210
|
-
// This endpoint logs the user in directly
|
|
210
|
+
// This endpoint logs the user in directly, so a stored
|
|
211
211
|
// timezone must survive the preauth-MFA-enrollment login just like
|
|
212
212
|
// a plain password login does — same helper as verify.write.ts /
|
|
213
|
-
// invite-accept-with-login.write.ts
|
|
213
|
+
// invite-accept-with-login.write.ts.
|
|
214
214
|
...sessionTimezoneField(userRow?.timezone),
|
|
215
215
|
...sessionLocaleField(userRow?.locale),
|
|
216
216
|
};
|
|
@@ -56,8 +56,8 @@ export function createEnableConfirmHandler(opts: EnableConfirmOptions) {
|
|
|
56
56
|
// already rules that out).
|
|
57
57
|
if (verify.payload.userId !== event.user.id) return invalidSetupToken();
|
|
58
58
|
|
|
59
|
-
// Fail closed, matching verify.write.ts/enable-confirm-preauth.write.ts
|
|
60
|
-
//
|
|
59
|
+
// Fail closed, matching verify.write.ts/enable-confirm-preauth.write.ts:
|
|
60
|
+
// session-authed (lower risk — the caller already has a
|
|
61
61
|
// valid JWT), but silently skipping the single-use burn here would
|
|
62
62
|
// still let a double-confirm race complete twice instead of the
|
|
63
63
|
// second seeing invalidSetupToken(). Checked before the TOTP verify
|
|
@@ -55,7 +55,7 @@ export function createEnableStartPreauthHandler(opts: EnableStartPreauthOptions)
|
|
|
55
55
|
);
|
|
56
56
|
// Same generic "sign in again" error as an expired/invalid MFA
|
|
57
57
|
// challenge token — both mean the login-flow token expired, no
|
|
58
|
-
// distinct i18n needed
|
|
58
|
+
// distinct i18n needed.
|
|
59
59
|
if (!verified.ok) return invalidChallengeToken();
|
|
60
60
|
const { userId, tenantId } = verified.payload;
|
|
61
61
|
|
|
@@ -154,7 +154,7 @@ export async function mfaReencryptJob(
|
|
|
154
154
|
|
|
155
155
|
// After PII peel (when configured), values must be current-cipher
|
|
156
156
|
// envelopes — non-JSON/non-envelope is not a supported legacy decrypt
|
|
157
|
-
// path
|
|
157
|
+
// path, matching config behavior.
|
|
158
158
|
const totpClass = classifyStoredEnvelope(envelopeValues.totpSecret, targetVersion);
|
|
159
159
|
const recoveryClass = classifyStoredEnvelope(envelopeValues.recoveryCodes, targetVersion);
|
|
160
160
|
if (totpClass === "unrecognized" || recoveryClass === "unrecognized") {
|
|
@@ -47,11 +47,11 @@ export function createRegenerateRecoveryHandler(opts: RegenerateRecoveryOptions)
|
|
|
47
47
|
// count, since either way the presented code is consumed/irrelevant
|
|
48
48
|
// afterward.
|
|
49
49
|
//
|
|
50
|
-
// Fail closed, matching verify.write.ts/enable-confirm-preauth.write.ts
|
|
51
|
-
//
|
|
52
|
-
//
|
|
53
|
-
//
|
|
54
|
-
//
|
|
50
|
+
// Fail closed, matching verify.write.ts/enable-confirm-preauth.write.ts:
|
|
51
|
+
// without ctx.redis, verifyMfaFactor's TOTP-replay burn is skipped,
|
|
52
|
+
// letting an observed code be replayed within the ±1-step window to
|
|
53
|
+
// regenerate (and thus invalidate) recovery codes — a session-authed
|
|
54
|
+
// route, so pre-unwiring JWTs stay a valid attack path.
|
|
55
55
|
if (!ctx.redis) {
|
|
56
56
|
return writeFailure(
|
|
57
57
|
new InternalError({
|
|
@@ -67,7 +67,7 @@ export function createMfaVerifyHandler(opts: MfaVerifyOptions) {
|
|
|
67
67
|
if (!verified.ok) return invalidChallengeToken();
|
|
68
68
|
const { userId, tenantId } = verified.payload;
|
|
69
69
|
|
|
70
|
-
// Fail closed, matching enable-confirm-preauth.write.ts
|
|
70
|
+
// Fail closed, matching enable-confirm-preauth.write.ts:
|
|
71
71
|
// this route sits behind a challenge token from a successful login,
|
|
72
72
|
// but its own secret is still just a short TOTP/recovery code —
|
|
73
73
|
// silently skipping the brute-force cap and single-use burn when
|
|
@@ -18,7 +18,7 @@ const CHALLENGE_TOKEN_PURPOSE = "mfa-challenge-token-v1";
|
|
|
18
18
|
|
|
19
19
|
// A blank or whitespace-only override is treated as absent — an empty env
|
|
20
20
|
// var (MFA_SETUP_TOKEN_SECRET="") must fall back to derivation, not sign
|
|
21
|
-
// tokens with an empty/near-empty HMAC key
|
|
21
|
+
// tokens with an empty/near-empty HMAC key.
|
|
22
22
|
function resolveSecret(override: string | undefined, fallback: () => string): string {
|
|
23
23
|
return override !== undefined && override.trim() !== "" ? override : fallback();
|
|
24
24
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// Client
|
|
1
|
+
// Client feature factory for auth-mfa — mirrors emailPasswordClient()'s
|
|
2
2
|
// shape so apps register both the same way:
|
|
3
3
|
// createKumikoApp({ clientFeatures: [emailPasswordClient(), authMfaClient()] }).
|
|
4
4
|
// No gates: MfaVerifyScreen isn't a route gate, it's a state swap wired
|
|
@@ -12,7 +12,7 @@ import type { ComponentType, ReactNode } from "react";
|
|
|
12
12
|
import { defaultTranslations, mergeTranslations } from "./i18n.ts";
|
|
13
13
|
|
|
14
14
|
export type AuthMfaClientOptions = {
|
|
15
|
-
/** Key
|
|
15
|
+
/** Key overrides per locale, merged with the default bundles (de/en). */
|
|
16
16
|
readonly translations?: TranslationsByLocale;
|
|
17
17
|
};
|
|
18
18
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
// Default
|
|
2
|
-
// authMfaClient()
|
|
3
|
-
// Keys
|
|
1
|
+
// Default bundles for the auth-mfa feature UI, merged by
|
|
2
|
+
// authMfaClient() analogously to emailPasswordClient() from auth-email-password.
|
|
3
|
+
// Keys follow `auth.mfa.<area>.<slug>`.
|
|
4
4
|
|
|
5
5
|
import type { TranslationsByLocale } from "@cosmicdrift/kumiko-renderer";
|
|
6
6
|
|
|
@@ -13,6 +13,11 @@ export const defaultTranslations: TranslationsByLocale = {
|
|
|
13
13
|
"auth.mfa.verify.submit": "Verify",
|
|
14
14
|
"auth.mfa.verify.submitting": "…",
|
|
15
15
|
"auth.mfa.verify.backToLogin": "Back to login",
|
|
16
|
+
"auth.mfa.verify.recoveryCode": "Recovery code",
|
|
17
|
+
"auth.mfa.verify.recoverySubtitle":
|
|
18
|
+
"Enter one of the recovery codes you saved when you set up two-factor authentication.",
|
|
19
|
+
"auth.mfa.verify.useAuthenticatorCode": "Use the code from your app",
|
|
20
|
+
"auth.mfa.verify.useRecoveryCode": "Use a recovery code instead",
|
|
16
21
|
"auth.mfa.errors.invalidCode": "Invalid code. Please try again.",
|
|
17
22
|
"auth.mfa.errors.invalidTotpCode": "Invalid code. Please try again.",
|
|
18
23
|
"auth.mfa.errors.invalidChallengeToken": "Your sign-in has expired. Please sign in again.",
|
|
@@ -43,7 +48,7 @@ export const defaultTranslations: TranslationsByLocale = {
|
|
|
43
48
|
"auth.mfa.disable.title": "Disable two-factor authentication",
|
|
44
49
|
"auth.mfa.disable.description":
|
|
45
50
|
"Confirm with a code from your authenticator app or a recovery code. Your account will then be protected by your password alone.",
|
|
46
|
-
"auth.mfa.disable.code": "Code from your authenticator app
|
|
51
|
+
"auth.mfa.disable.code": "Code from your authenticator app",
|
|
47
52
|
"auth.mfa.disable.confirm": "Disable",
|
|
48
53
|
"auth.mfa.disable.cancel": "Cancel",
|
|
49
54
|
"auth.mfa.disable.trigger": "Disable two-factor authentication",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
// Public exports
|
|
2
|
-
//
|
|
3
|
-
// (defineFeature)
|
|
4
|
-
// password/web/index.ts
|
|
1
|
+
// Public exports for the browser side of the auth-mfa feature. The subpath
|
|
2
|
+
// export `@cosmicdrift/kumiko-bundled-features/auth-mfa/web` keeps the server
|
|
3
|
+
// side (`defineFeature`) free of React/DOM dependencies, matching the same
|
|
4
|
+
// separation in auth-email-password/web/index.ts.
|
|
5
5
|
|
|
6
6
|
export type { AuthMfaClientFeature, AuthMfaClientOptions } from "./client-plugin.ts";
|
|
7
7
|
export { authMfaClient } from "./client-plugin.ts";
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
// Browser
|
|
2
|
-
// login LoginScreen started when the server responded mfaRequired.
|
|
3
|
-
// fetch/CSRF pattern as auth-email-password's login()
|
|
4
|
-
//
|
|
1
|
+
// Browser side of POST /api/auth/mfa/verify — completes the two-step
|
|
2
|
+
// login that LoginScreen started when the server responded with mfaRequired.
|
|
3
|
+
// Uses the same fetch/CSRF pattern as auth-email-password's login(), but runs
|
|
4
|
+
// before a session exists, so it does not call csrfHeader(). The response is
|
|
5
5
|
// byte-identical to /auth/login's ({isSuccess, token, user} | {isSuccess:
|
|
6
|
-
// false, error})
|
|
7
|
-
//
|
|
6
|
+
// false, error}) because auth-routes.ts uses mintSessionAndRespond() for both
|
|
7
|
+
// routes.
|
|
8
8
|
|
|
9
9
|
// kumiko-lint-ignore cross-feature-import client-only types, the feature's server barrel has no web/ re-export
|
|
10
10
|
import {
|
|
@@ -76,11 +76,12 @@ export type MfaSetupPreauthStartResult =
|
|
|
76
76
|
| { readonly kind: "success"; readonly data: MfaSetupPreauthStart }
|
|
77
77
|
| { readonly kind: "failure"; readonly error: LoginFailure };
|
|
78
78
|
|
|
79
|
-
// Browser
|
|
79
|
+
// Browser side of POST /api/auth/mfa/preauth-enable-start — lets a user
|
|
80
80
|
// blocked at login by MFA enforcement generate a TOTP secret/QR without a
|
|
81
|
-
// session, using the preauthSetupToken login()'s
|
|
82
|
-
//
|
|
83
|
-
//
|
|
81
|
+
// session, using the preauthSetupToken carried by login()'s
|
|
82
|
+
// mfa-setup-required result. No JWT/cookie is issued here (see the route
|
|
83
|
+
// comment in auth-routes.ts); the response's
|
|
84
|
+
// setupToken is consumed by confirmMfaSetupPreauth below.
|
|
84
85
|
export async function startMfaSetupPreauth(
|
|
85
86
|
preauthSetupToken: string,
|
|
86
87
|
accountLabel: string,
|
|
@@ -139,12 +140,12 @@ export async function startMfaSetupPreauth(
|
|
|
139
140
|
};
|
|
140
141
|
}
|
|
141
142
|
|
|
142
|
-
// Browser
|
|
143
|
-
//
|
|
144
|
-
// required block.
|
|
145
|
-
// the same mintSessionAndRespond()
|
|
146
|
-
//
|
|
147
|
-
//
|
|
143
|
+
// Browser side of POST /api/auth/mfa/preauth-confirm — completes both the
|
|
144
|
+
// enrollment started by startMfaSetupPreauth and the login
|
|
145
|
+
// mfa-setup-required block. Its response mirrors /auth/mfa/verify's and is
|
|
146
|
+
// minted via the same mintSessionAndRespond(). It remains a separate function
|
|
147
|
+
// so this file's two already-tested request shapes stay independently
|
|
148
|
+
// editable.
|
|
148
149
|
export async function confirmMfaSetupPreauth(
|
|
149
150
|
setupToken: string,
|
|
150
151
|
code: string,
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { usePrimitives, useTranslation } from "@cosmicdrift/kumiko-renderer";
|
|
2
|
+
import type { ReactNode } from "react";
|
|
3
|
+
|
|
4
|
+
export type MfaCodeOrRecoveryFieldProps = {
|
|
5
|
+
readonly id: string;
|
|
6
|
+
readonly codeLabel: string;
|
|
7
|
+
readonly code: string;
|
|
8
|
+
readonly onCodeChange: (code: string) => void;
|
|
9
|
+
readonly useRecovery: boolean;
|
|
10
|
+
readonly onUseRecoveryChange: (useRecovery: boolean) => void;
|
|
11
|
+
readonly disabled?: boolean;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export function MfaCodeOrRecoveryField({
|
|
15
|
+
id,
|
|
16
|
+
codeLabel,
|
|
17
|
+
code,
|
|
18
|
+
onCodeChange,
|
|
19
|
+
useRecovery,
|
|
20
|
+
onUseRecoveryChange,
|
|
21
|
+
disabled,
|
|
22
|
+
}: MfaCodeOrRecoveryFieldProps): ReactNode {
|
|
23
|
+
const t = useTranslation();
|
|
24
|
+
const { Button, Field, Input } = usePrimitives();
|
|
25
|
+
|
|
26
|
+
return (
|
|
27
|
+
<>
|
|
28
|
+
<Field id={id} label={useRecovery ? t("auth.mfa.verify.recoveryCode") : codeLabel} required>
|
|
29
|
+
{useRecovery ? (
|
|
30
|
+
<Input
|
|
31
|
+
kind="text"
|
|
32
|
+
id={id}
|
|
33
|
+
name={id}
|
|
34
|
+
value={code}
|
|
35
|
+
onChange={onCodeChange}
|
|
36
|
+
disabled={disabled}
|
|
37
|
+
autoFocus
|
|
38
|
+
autoComplete="off"
|
|
39
|
+
/>
|
|
40
|
+
) : (
|
|
41
|
+
<Input
|
|
42
|
+
kind="code"
|
|
43
|
+
length={6}
|
|
44
|
+
id={id}
|
|
45
|
+
name={id}
|
|
46
|
+
value={code}
|
|
47
|
+
onChange={onCodeChange}
|
|
48
|
+
disabled={disabled}
|
|
49
|
+
autoFocus
|
|
50
|
+
/>
|
|
51
|
+
)}
|
|
52
|
+
</Field>
|
|
53
|
+
<Button
|
|
54
|
+
type="button"
|
|
55
|
+
variant="link"
|
|
56
|
+
disabled={disabled}
|
|
57
|
+
onClick={() => {
|
|
58
|
+
onUseRecoveryChange(!useRecovery);
|
|
59
|
+
onCodeChange("");
|
|
60
|
+
}}
|
|
61
|
+
>
|
|
62
|
+
{useRecovery
|
|
63
|
+
? t("auth.mfa.verify.useAuthenticatorCode")
|
|
64
|
+
: t("auth.mfa.verify.useRecoveryCode")}
|
|
65
|
+
</Button>
|
|
66
|
+
</>
|
|
67
|
+
);
|
|
68
|
+
}
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
import { useDispatcher, usePrimitives, useTranslation } from "@cosmicdrift/kumiko-renderer";
|
|
13
13
|
import { type ReactNode, useState } from "react";
|
|
14
14
|
import { AuthMfaHandlers } from "./constants.ts";
|
|
15
|
+
import { MfaCodeOrRecoveryField } from "./mfa-code-or-recovery-field.tsx";
|
|
15
16
|
|
|
16
17
|
export type MfaDisableDialogProps = {
|
|
17
18
|
readonly open: boolean;
|
|
@@ -28,13 +29,24 @@ export function MfaDisableDialog({
|
|
|
28
29
|
onError,
|
|
29
30
|
}: MfaDisableDialogProps): ReactNode {
|
|
30
31
|
const t = useTranslation();
|
|
31
|
-
const { Dialog
|
|
32
|
+
const { Dialog } = usePrimitives();
|
|
32
33
|
const dispatcher = useDispatcher();
|
|
33
34
|
const [code, setCode] = useState("");
|
|
35
|
+
const [useRecovery, setUseRecovery] = useState(false);
|
|
36
|
+
|
|
37
|
+
const reset = (): void => {
|
|
38
|
+
setCode("");
|
|
39
|
+
setUseRecovery(false);
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
const handleOpenChange = (nextOpen: boolean): void => {
|
|
43
|
+
if (!nextOpen) reset();
|
|
44
|
+
onOpenChange(nextOpen);
|
|
45
|
+
};
|
|
34
46
|
|
|
35
47
|
const confirm = async (): Promise<void> => {
|
|
36
48
|
const res = await dispatcher.write<{ disabled: boolean }>(AuthMfaHandlers.disable, { code });
|
|
37
|
-
|
|
49
|
+
reset();
|
|
38
50
|
if (!res.isSuccess) {
|
|
39
51
|
onError(res.error.i18nKey);
|
|
40
52
|
return;
|
|
@@ -45,7 +57,7 @@ export function MfaDisableDialog({
|
|
|
45
57
|
return (
|
|
46
58
|
<Dialog
|
|
47
59
|
open={open}
|
|
48
|
-
onOpenChange={
|
|
60
|
+
onOpenChange={handleOpenChange}
|
|
49
61
|
variant="danger"
|
|
50
62
|
title={t("auth.mfa.disable.title")}
|
|
51
63
|
description={t("auth.mfa.disable.description")}
|
|
@@ -54,16 +66,14 @@ export function MfaDisableDialog({
|
|
|
54
66
|
onConfirm={confirm}
|
|
55
67
|
testId="mfa-disable-dialog"
|
|
56
68
|
>
|
|
57
|
-
<
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
/>
|
|
66
|
-
</Field>
|
|
69
|
+
<MfaCodeOrRecoveryField
|
|
70
|
+
id="mfa-disable-code"
|
|
71
|
+
codeLabel={t("auth.mfa.disable.code")}
|
|
72
|
+
code={code}
|
|
73
|
+
onCodeChange={setCode}
|
|
74
|
+
useRecovery={useRecovery}
|
|
75
|
+
onUseRecoveryChange={setUseRecovery}
|
|
76
|
+
/>
|
|
67
77
|
</Dialog>
|
|
68
78
|
);
|
|
69
79
|
}
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
import { useDispatcher, usePrimitives, useTranslation } from "@cosmicdrift/kumiko-renderer";
|
|
10
10
|
import { type ReactNode, useState } from "react";
|
|
11
11
|
import { AuthMfaHandlers } from "./constants.ts";
|
|
12
|
+
import { MfaCodeOrRecoveryField } from "./mfa-code-or-recovery-field.tsx";
|
|
12
13
|
|
|
13
14
|
export type MfaRegenerateRecoveryDialogProps = {
|
|
14
15
|
readonly open: boolean;
|
|
@@ -25,16 +26,27 @@ export function MfaRegenerateRecoveryDialog({
|
|
|
25
26
|
onError,
|
|
26
27
|
}: MfaRegenerateRecoveryDialogProps): ReactNode {
|
|
27
28
|
const t = useTranslation();
|
|
28
|
-
const { Dialog
|
|
29
|
+
const { Dialog } = usePrimitives();
|
|
29
30
|
const dispatcher = useDispatcher();
|
|
30
31
|
const [code, setCode] = useState("");
|
|
32
|
+
const [useRecovery, setUseRecovery] = useState(false);
|
|
33
|
+
|
|
34
|
+
const reset = (): void => {
|
|
35
|
+
setCode("");
|
|
36
|
+
setUseRecovery(false);
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const handleOpenChange = (nextOpen: boolean): void => {
|
|
40
|
+
if (!nextOpen) reset();
|
|
41
|
+
onOpenChange(nextOpen);
|
|
42
|
+
};
|
|
31
43
|
|
|
32
44
|
const confirm = async (): Promise<void> => {
|
|
33
45
|
const res = await dispatcher.write<{ recoveryCodes: readonly string[] }>(
|
|
34
46
|
AuthMfaHandlers.regenerateRecovery,
|
|
35
47
|
{ code },
|
|
36
48
|
);
|
|
37
|
-
|
|
49
|
+
reset();
|
|
38
50
|
if (!res.isSuccess) {
|
|
39
51
|
onError(res.error.i18nKey);
|
|
40
52
|
return;
|
|
@@ -45,7 +57,7 @@ export function MfaRegenerateRecoveryDialog({
|
|
|
45
57
|
return (
|
|
46
58
|
<Dialog
|
|
47
59
|
open={open}
|
|
48
|
-
onOpenChange={
|
|
60
|
+
onOpenChange={handleOpenChange}
|
|
49
61
|
title={t("auth.mfa.regenerate.title")}
|
|
50
62
|
description={t("auth.mfa.regenerate.description")}
|
|
51
63
|
confirmLabel={t("auth.mfa.regenerate.confirm")}
|
|
@@ -53,16 +65,14 @@ export function MfaRegenerateRecoveryDialog({
|
|
|
53
65
|
onConfirm={confirm}
|
|
54
66
|
testId="mfa-regenerate-recovery-dialog"
|
|
55
67
|
>
|
|
56
|
-
<
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
/>
|
|
65
|
-
</Field>
|
|
68
|
+
<MfaCodeOrRecoveryField
|
|
69
|
+
id="mfa-regenerate-code"
|
|
70
|
+
codeLabel={t("auth.mfa.regenerate.code")}
|
|
71
|
+
code={code}
|
|
72
|
+
onCodeChange={setCode}
|
|
73
|
+
useRecovery={useRecovery}
|
|
74
|
+
onUseRecoveryChange={setUseRecovery}
|
|
75
|
+
/>
|
|
66
76
|
</Dialog>
|
|
67
77
|
);
|
|
68
78
|
}
|
|
@@ -79,6 +79,7 @@ export function MfaSetupPreauthScreen({
|
|
|
79
79
|
const [setup, setSetup] = useState<SetupState | null>(null);
|
|
80
80
|
const [acknowledged, setAcknowledged] = useState(false);
|
|
81
81
|
const [code, setCode] = useState("");
|
|
82
|
+
const [attempt, setAttempt] = useState(0);
|
|
82
83
|
const [busy, setBusy] = useState(false);
|
|
83
84
|
const [error, setError] = useState<string | null>(null);
|
|
84
85
|
const [retryAfterSeconds, setRetryAfterSeconds] = useState<number | null>(null);
|
|
@@ -109,13 +110,13 @@ export function MfaSetupPreauthScreen({
|
|
|
109
110
|
}
|
|
110
111
|
};
|
|
111
112
|
|
|
112
|
-
const confirmSetup = async (): Promise<void> => {
|
|
113
|
-
if (!setup) return;
|
|
113
|
+
const confirmSetup = async (submittedCode: string): Promise<void> => {
|
|
114
|
+
if (!setup || busy) return;
|
|
114
115
|
setBusy(true);
|
|
115
116
|
setError(null);
|
|
116
117
|
setRetryAfterSeconds(null);
|
|
117
118
|
try {
|
|
118
|
-
const res = await confirmMfaSetupPreauth(setup.setupToken,
|
|
119
|
+
const res = await confirmMfaSetupPreauth(setup.setupToken, submittedCode);
|
|
119
120
|
if (res.kind !== "success") {
|
|
120
121
|
setError(res.error.reason);
|
|
121
122
|
setRetryAfterSeconds(res.error.retryAfterSeconds ?? null);
|
|
@@ -130,7 +131,11 @@ export function MfaSetupPreauthScreen({
|
|
|
130
131
|
setSetup(null);
|
|
131
132
|
setAcknowledged(false);
|
|
132
133
|
setCode("");
|
|
134
|
+
return;
|
|
133
135
|
}
|
|
136
|
+
// Remount: the field was disabled during confirm and lost focus.
|
|
137
|
+
setCode("");
|
|
138
|
+
setAttempt((n) => n + 1);
|
|
134
139
|
return;
|
|
135
140
|
}
|
|
136
141
|
onSuccess?.(res.data.landingPath);
|
|
@@ -143,7 +148,7 @@ export function MfaSetupPreauthScreen({
|
|
|
143
148
|
|
|
144
149
|
const onSubmit = (e?: FormEvent): void => {
|
|
145
150
|
e?.preventDefault();
|
|
146
|
-
void confirmSetup();
|
|
151
|
+
void confirmSetup(code);
|
|
147
152
|
};
|
|
148
153
|
|
|
149
154
|
return (
|
|
@@ -226,13 +231,17 @@ export function MfaSetupPreauthScreen({
|
|
|
226
231
|
|
|
227
232
|
<Field id="mfa-setup-preauth-code" label={t("auth.mfa.enable.code")} required>
|
|
228
233
|
<Input
|
|
229
|
-
|
|
234
|
+
key={attempt}
|
|
235
|
+
kind="code"
|
|
236
|
+
length={6}
|
|
230
237
|
id="mfa-setup-preauth-code"
|
|
231
238
|
name="mfa-setup-preauth-code"
|
|
232
239
|
value={code}
|
|
233
240
|
onChange={setCode}
|
|
241
|
+
onComplete={(next) => void confirmSetup(next)}
|
|
234
242
|
disabled={busy || !acknowledged}
|
|
235
|
-
|
|
243
|
+
hasError={error !== null}
|
|
244
|
+
autoFocus={attempt > 0}
|
|
236
245
|
/>
|
|
237
246
|
</Field>
|
|
238
247
|
|