@cosmicdrift/kumiko-bundled-features 0.388.0 → 0.390.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/dist/agent-tools/index.d.ts +1 -1
- package/dist/agent-tools/index.js +1 -1
- package/dist/agent-tools/tool-dispatch.d.ts +8 -3
- package/dist/agent-tools/tool-dispatch.js +36 -25
- package/dist/audit/feature.js +2 -1
- package/dist/auth-email-password/auth-user-row.js +1 -1
- package/dist/auth-email-password/bootstrap.js +6 -1
- package/dist/auth-email-password/feature.js +1 -1
- package/dist/auth-email-password/handlers/change-password.write.js +7 -7
- package/dist/auth-email-password/handlers/confirm-account-unlock.write.js +3 -3
- package/dist/auth-email-password/handlers/confirm-token-flow.js +4 -4
- package/dist/auth-email-password/handlers/invite-accept-with-login.write.js +8 -7
- package/dist/auth-email-password/handlers/invite-accept.write.js +10 -7
- package/dist/auth-email-password/handlers/invite-create.write.js +4 -4
- package/dist/auth-email-password/handlers/invite-info.query.js +2 -2
- package/dist/auth-email-password/handlers/invite-signup-complete.write.js +8 -7
- package/dist/auth-email-password/handlers/login.write.js +17 -15
- package/dist/auth-email-password/handlers/request-account-unlock.write.d.ts +1 -0
- package/dist/auth-email-password/handlers/request-account-unlock.write.js +1 -0
- package/dist/auth-email-password/handlers/request-email-verification.write.d.ts +1 -0
- package/dist/auth-email-password/handlers/request-email-verification.write.js +1 -0
- package/dist/auth-email-password/handlers/request-password-reset.write.d.ts +1 -0
- package/dist/auth-email-password/handlers/request-password-reset.write.js +1 -0
- package/dist/auth-email-password/handlers/reset-password.write.js +2 -2
- package/dist/auth-email-password/handlers/signup-confirm.write.js +12 -12
- package/dist/auth-email-password/handlers/signup-request.write.d.ts +1 -0
- package/dist/auth-email-password/handlers/signup-request.write.js +16 -8
- package/dist/auth-email-password/handlers/switch-tenant-mfa-gate.write.js +4 -2
- package/dist/auth-email-password/handlers/token-request-handler.d.ts +2 -0
- package/dist/auth-email-password/handlers/token-request-handler.js +7 -2
- package/dist/auth-email-password/handlers/verify-email.write.js +2 -2
- package/dist/auth-email-password/magic-link-mail.d.ts +2 -0
- package/dist/auth-email-password/magic-link-mail.js +7 -3
- package/dist/auth-email-password/seeding.d.ts +1 -1
- package/dist/auth-email-password/seeding.js +9 -8
- package/dist/auth-email-password/signup-activation.d.ts +1 -0
- package/dist/auth-email-password/signup-activation.js +1 -0
- package/dist/auth-email-password/web/auth-client.d.ts +2 -2
- package/dist/auth-email-password/web/auth-client.js +8 -4
- package/dist/auth-email-password/web/auth-redirect.d.ts +5 -1
- package/dist/auth-email-password/web/auth-redirect.js +20 -25
- package/dist/auth-email-password/web/default-auth-pages-gate.js +6 -3
- package/dist/auth-email-password/web/forgot-password-screen.d.ts +4 -1
- package/dist/auth-email-password/web/forgot-password-screen.js +7 -2
- package/dist/auth-email-password/web/index.d.ts +1 -0
- package/dist/auth-email-password/web/index.js +1 -0
- package/dist/auth-email-password/web/login-screen.js +11 -6
- package/dist/auth-email-password/web/reset-password-screen.js +7 -1
- package/dist/auth-email-password/web/return-path.d.ts +4 -0
- package/dist/auth-email-password/web/return-path.js +34 -0
- package/dist/auth-email-password/web/session.js +6 -1
- package/dist/auth-email-password/web/signup-complete-screen.js +11 -3
- package/dist/auth-email-password/web/signup-screen.d.ts +4 -1
- package/dist/auth-email-password/web/signup-screen.js +8 -3
- package/dist/auth-foundation/feature.js +12 -4
- package/dist/auth-mfa/config.d.ts +1 -1
- package/dist/auth-mfa/config.js +3 -7
- package/dist/auth-mfa/handlers/disable.write.js +5 -5
- package/dist/auth-mfa/handlers/enable-confirm-preauth.write.js +19 -14
- package/dist/auth-mfa/handlers/enable-confirm.write.js +3 -3
- package/dist/auth-mfa/handlers/enable-start-preauth.write.js +6 -1
- package/dist/auth-mfa/handlers/enable-start.write.js +1 -1
- package/dist/auth-mfa/handlers/reencrypt.job.js +14 -9
- package/dist/auth-mfa/handlers/regenerate-recovery.write.js +4 -4
- package/dist/auth-mfa/handlers/verify.write.js +19 -14
- package/dist/auth-mfa/mfa-code-verifier.js +9 -4
- package/dist/auth-mfa/mfa-status-checker.js +13 -6
- package/dist/auth-mfa/verify-factor.js +1 -1
- package/dist/billing-foundation/billing-info-query.js +2 -2
- package/dist/billing-foundation/consumer-protection/consent-gate.js +1 -1
- package/dist/billing-foundation/consumer-protection/issue-confirmation.js +5 -5
- package/dist/billing-foundation/consumer-protection/register-consent.js +1 -1
- package/dist/billing-foundation/consumer-protection/register-termination.js +1 -1
- package/dist/billing-foundation/consumer-protection/termination-open-cancels.d.ts +4 -0
- package/dist/billing-foundation/consumer-protection/termination-open-cancels.js +14 -0
- package/dist/billing-foundation/consumer-protection/termination-provider-lock.d.ts +2 -0
- package/dist/billing-foundation/consumer-protection/termination-provider-lock.js +3 -0
- package/dist/billing-foundation/consumer-protection/termination-receipt-limit.js +4 -4
- package/dist/billing-foundation/consumer-protection/termination-record.js +11 -48
- package/dist/billing-foundation/consumer-protection/termination-request.js +10 -8
- package/dist/billing-foundation/consumer-protection/termination-revoke.js +10 -12
- package/dist/billing-foundation/events.js +1 -1
- package/dist/billing-foundation/feature.js +3 -3
- package/dist/billing-foundation/get-subscription-for-tenant.d.ts +1 -1
- package/dist/billing-foundation/handlers/process-event.write.js +5 -5
- package/dist/billing-foundation/handlers/process-payment-event.write.js +3 -3
- package/dist/billing-foundation/plan-catalog.js +2 -2
- package/dist/billing-foundation/projection.js +1 -1
- package/dist/billing-foundation/types.js +1 -1
- package/dist/cap-counter/aggregate-id.d.ts +1 -1
- package/dist/cap-counter/aggregate-id.js +1 -1
- package/dist/cap-counter/book-cap-usage.d.ts +2 -2
- package/dist/cap-counter/book-cap-usage.js +3 -3
- package/dist/cap-counter/cap-reservation.js +16 -7
- package/dist/cap-counter/constants.js +1 -1
- package/dist/cap-counter/feature.js +3 -2
- package/dist/cap-counter/handlers/increment-rolling.write.js +1 -1
- package/dist/cap-counter/reservation-chain.js +1 -1
- package/dist/cap-counter/with-cap-enforcement.d.ts +3 -3
- package/dist/cap-counter/with-cap-enforcement.js +1 -1
- package/dist/cap-overview/feature.js +1 -0
- package/dist/cap-overview/handlers/caps-usage.query.js +1 -1
- package/dist/cap-overview/handlers/tenant-caps-list.query.js +1 -1
- package/dist/compliance-profiles/seeding.d.ts +1 -1
- package/dist/compliance-profiles/seeding.js +9 -3
- package/dist/config/feature.js +6 -6
- package/dist/config/handlers/cascade.query.js +1 -1
- package/dist/config/handlers/readiness.query.js +1 -1
- package/dist/config/handlers/reencrypt.job.js +23 -13
- package/dist/config/handlers/reset.write.js +3 -3
- package/dist/config/handlers/selected-extensions.query.js +1 -1
- package/dist/config/handlers/set.write.js +15 -5
- package/dist/config/handlers/values.query.js +1 -1
- package/dist/crypto-shredding/handlers/forget-subject.write.js +9 -9
- package/dist/crypto-shredding/resolve-file-bytes-deleter.js +3 -3
- package/dist/custom-fields/handlers/clear-custom-field.write.js +1 -1
- package/dist/custom-fields/handlers/delete-system-field.write.js +1 -1
- package/dist/custom-fields/handlers/delete-tenant-field.write.js +1 -1
- package/dist/custom-fields/handlers/set-custom-field.write.js +1 -1
- package/dist/custom-fields/index.d.ts +1 -0
- package/dist/custom-fields/index.js +1 -0
- package/dist/custom-fields/lib/parse-serialized-field.js +1 -1
- package/dist/data-retention/feature.js +1 -1
- package/dist/data-retention/run-retention-cleanup.js +12 -2
- package/dist/delivery/attempt-log.js +1 -1
- package/dist/delivery/delivery-service.js +5 -5
- package/dist/delivery/feature.js +3 -2
- package/dist/delivery/index.d.ts +1 -0
- package/dist/delivery/index.js +1 -0
- package/dist/delivery/jobs.js +11 -11
- package/dist/delivery/system-channel-context.d.ts +15 -0
- package/dist/delivery/system-channel-context.js +5 -0
- package/dist/document-ingest-foundation/append-missing-extract-event.d.ts +21 -0
- package/dist/document-ingest-foundation/append-missing-extract-event.js +42 -0
- package/dist/document-ingest-foundation/events.d.ts +11 -0
- package/dist/document-ingest-foundation/events.js +12 -1
- package/dist/document-ingest-foundation/index.d.ts +2 -1
- package/dist/document-ingest-foundation/index.js +2 -1
- package/dist/feature-toggles/feature.js +1 -0
- package/dist/feature-toggles/handlers/registered.query.js +1 -1
- package/dist/feature-toggles/handlers/set.write.js +1 -1
- package/dist/feature-toggles/toggle-sync-signal.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-by-file-ref.query.js +1 -1
- package/dist/file-derivatives/handlers/public-variant.query.js +5 -5
- package/dist/file-foundation/feature.js +1 -1
- package/dist/file-foundation/read-file-ref-content.d.ts +4 -2
- package/dist/file-foundation/read-file-ref-content.js +3 -3
- package/dist/file-provider-s3/feature.js +1 -1
- package/dist/files-tenant-data/handlers/sweep-orphaned-derivatives.job.js +8 -8
- package/dist/form-draft/feature.js +1 -1
- package/dist/form-draft/handlers/cleanup.job.js +22 -12
- package/dist/form-draft/handlers/discard.write.js +3 -3
- package/dist/form-draft/handlers/get.query.js +1 -1
- package/dist/foundation-shared/config-helpers.d.ts +1 -1
- package/dist/foundation-shared/config-helpers.js +1 -1
- package/dist/host-routing/validate-options.js +3 -0
- package/dist/inbound-mail-foundation/events.js +1 -1
- package/dist/inbound-mail-foundation/feature.js +2 -1
- package/dist/inbound-mail-foundation/handlers/account-state.d.ts +3 -1
- package/dist/inbound-mail-foundation/handlers/account-state.js +1 -1
- package/dist/inbound-mail-foundation/handlers/connect-account.write.js +1 -1
- package/dist/inbound-mail-foundation/handlers/disconnect-account.write.js +1 -1
- package/dist/inbound-mail-foundation/handlers/ingest-message.write.js +10 -10
- package/dist/inbound-mail-foundation/handlers/update-account.write.js +1 -1
- package/dist/inbound-mail-foundation/projection.js +1 -1
- package/dist/inbound-mail-foundation/watch-supervisor.js +1 -1
- package/dist/inbound-provider-imap/feature.js +1 -1
- package/dist/jobs/events.js +1 -1
- package/dist/jobs/feature.js +1 -0
- package/dist/jobs/handlers/consumer.write.js +1 -1
- package/dist/jobs/handlers/projection-rebuild.job.js +1 -1
- package/dist/jobs/handlers/reindex-entity.job.js +5 -5
- package/dist/jobs/handlers/retention-cleanup.job.js +1 -1
- package/dist/jobs/handlers/retry.write.js +1 -1
- package/dist/jobs/handlers/stale-run-sweep.job.js +1 -1
- package/dist/jobs/handlers/trigger.write.js +2 -2
- package/dist/jobs/job-run-logger.d.ts +1 -0
- package/dist/jobs/job-run-logger.js +38 -18
- package/dist/ledger/web/index.js +1 -1
- package/dist/legal-pages/lib/boot-check.d.ts +10 -4
- package/dist/legal-pages/lib/boot-check.js +2 -2
- package/dist/legal-pages/seed.d.ts +3 -1
- package/dist/legal-pages/seed.js +2 -2
- package/dist/mail-foundation/feature.d.ts +2 -2
- package/dist/mail-transport-smtp/config-keys.js +1 -1
- package/dist/mail-transport-smtp/feature.js +7 -6
- package/dist/managed-pages/constants.d.ts +1 -0
- package/dist/managed-pages/constants.js +1 -0
- package/dist/managed-pages/feature.js +3 -1
- package/dist/managed-pages/index.d.ts +1 -0
- package/dist/managed-pages/index.js +1 -0
- package/dist/managed-pages/seeding.d.ts +1 -1
- package/dist/managed-pages/seeding.js +10 -4
- package/dist/notes-history/handlers/add-note.write.js +2 -2
- package/dist/personal-access-tokens/feature.js +2 -1
- package/dist/personal-access-tokens/handlers/create.write.js +2 -2
- package/dist/personal-access-tokens/handlers/revoke.write.js +1 -1
- package/dist/rate-limiting/handlers/status.query.js +2 -2
- package/dist/readiness/handlers/status.query.js +1 -1
- package/dist/renderer-foundation/api.d.ts +4 -2
- package/dist/renderer-foundation/api.js +2 -2
- package/dist/secrets/announce-secret-change.d.ts +6 -2
- package/dist/secrets/announce-secret-change.js +3 -3
- package/dist/secrets/feature.d.ts +1 -1
- package/dist/secrets/feature.js +8 -8
- package/dist/secrets/handlers/delete.write.js +1 -1
- package/dist/secrets/handlers/rotate.job.js +13 -8
- package/dist/secrets/handlers/set.write.js +1 -1
- package/dist/secrets/secrets-context.js +16 -6
- package/dist/secrets/write-gate.js +8 -2
- package/dist/seo/feature.js +1 -1
- package/dist/sessions/feature.js +2 -1
- package/dist/sessions/handlers/cleanup.job.js +2 -2
- package/dist/sessions/handlers/detail.query.d.ts +1 -0
- package/dist/sessions/handlers/detail.query.js +5 -2
- package/dist/sessions/handlers/list.query.d.ts +1 -0
- package/dist/sessions/handlers/list.query.js +5 -2
- package/dist/sessions/handlers/mine.query.d.ts +1 -0
- package/dist/sessions/handlers/mine.query.js +5 -2
- package/dist/sessions/handlers/revoke-all-for-user.write.js +3 -3
- package/dist/sessions/handlers/revoke-all-others.write.js +1 -1
- package/dist/sessions/handlers/revoke.write.js +1 -1
- package/dist/sessions/index.d.ts +1 -1
- package/dist/sessions/index.js +1 -1
- package/dist/sessions/screens.js +8 -4
- package/dist/sessions/session-callbacks.d.ts +0 -2
- package/dist/sessions/session-callbacks.js +1 -3
- package/dist/sessions/session-revoked-event.js +1 -1
- package/dist/sessions/web/session-device-cell.js +10 -12
- package/dist/sessions/web/user-agent.d.ts +1 -0
- package/dist/sessions/web/user-agent.js +11 -0
- package/dist/shared/index.d.ts +2 -0
- package/dist/shared/index.js +2 -0
- package/dist/shared/purge-files-reaching-subject.d.ts +1 -0
- package/dist/shared/purge-files-reaching-subject.js +31 -4
- package/dist/shared/require-for-tenant.d.ts +1 -1
- package/dist/shared/require-for-tenant.js +6 -4
- package/dist/shared/run-in-sub-transaction.js +5 -5
- package/dist/shared/stream-tenant-backfill.d.ts +28 -0
- package/dist/shared/stream-tenant-backfill.js +119 -0
- package/dist/shared/stream-tenant-derived-state.d.ts +25 -0
- package/dist/shared/stream-tenant-derived-state.js +68 -0
- package/dist/step-dispatcher/deliver-dispatch-request.js +16 -3
- package/dist/step-dispatcher/feature.js +1 -1
- package/dist/step-dispatcher/mail-runner.d.ts +1 -0
- package/dist/subscription-dodo/plugin-methods.js +1 -1
- package/dist/subscription-dodo/runtime.js +4 -4
- package/dist/subscription-stripe/plugin-methods.js +3 -3
- package/dist/subscription-stripe/runtime.js +4 -4
- package/dist/tags/feature.js +1 -0
- package/dist/template-resolver/api.d.ts +4 -2
- package/dist/template-resolver/api.js +2 -2
- package/dist/template-resolver/document-ops.d.ts +5 -0
- package/dist/template-resolver/document-ops.js +18 -2
- package/dist/template-resolver/feature.js +2 -2
- package/dist/template-resolver/handlers/bundle-import.d.ts +4 -3
- package/dist/template-resolver/handlers/export-bundle.query.js +1 -1
- package/dist/template-resolver/handlers/layout-source.query.d.ts +4 -0
- package/dist/template-resolver/handlers/layout-source.query.js +26 -6
- package/dist/template-resolver/handlers/overview.query.js +17 -9
- package/dist/template-resolver/handlers/patch-draft.write.js +1 -1
- package/dist/template-resolver/handlers/send-test-shared.js +1 -1
- package/dist/template-resolver/handlers/send-test-status.query.d.ts +2 -1
- package/dist/template-resolver/handlers/send-test-status.query.js +18 -15
- package/dist/template-resolver/handlers/send-test.write.js +2 -2
- package/dist/template-resolver/handlers/tenant-override-selection.d.ts +3 -1
- package/dist/template-resolver/handlers/tenant-override-selection.js +1 -1
- package/dist/template-resolver/handlers/tenant-overrides.query.js +1 -1
- package/dist/template-resolver/handlers/usage.query.js +1 -1
- package/dist/template-resolver/seeding.d.ts +1 -0
- package/dist/template-resolver/seeding.js +17 -4
- package/dist/template-resolver/store-template-resource.d.ts +7 -6
- package/dist/template-resolver/store-template-resource.js +48 -8
- package/dist/template-resolver/template-resources.d.ts +2 -2
- package/dist/template-resolver/template-resources.js +2 -2
- package/dist/template-resolver/testing.js +2 -2
- package/dist/template-resolver/web/document-insert-fields.d.ts +4 -0
- package/dist/template-resolver/web/document-insert-fields.js +69 -0
- package/dist/template-resolver/web/document-insert-model.d.ts +43 -0
- package/dist/template-resolver/web/document-insert-model.js +106 -0
- package/dist/template-resolver/web/document-insert-panel.d.ts +13 -0
- package/dist/template-resolver/web/document-insert-panel.js +49 -0
- package/dist/template-resolver/web/document-tiptap-bubble.d.ts +4 -0
- package/dist/template-resolver/web/document-tiptap-bubble.js +85 -0
- package/dist/template-resolver/web/document-tiptap-content.d.ts +3 -0
- package/dist/template-resolver/web/document-tiptap-content.js +12 -0
- package/dist/template-resolver/web/document-tiptap-context.d.ts +41 -0
- package/dist/template-resolver/web/document-tiptap-context.js +43 -0
- package/dist/template-resolver/web/document-tiptap-editor.js +50 -495
- package/dist/template-resolver/web/document-tiptap-helpers.d.ts +44 -0
- package/dist/template-resolver/web/document-tiptap-helpers.js +129 -0
- package/dist/template-resolver/web/document-tiptap-layout.d.ts +4 -0
- package/dist/template-resolver/web/document-tiptap-layout.js +24 -0
- package/dist/template-resolver/web/document-tiptap-toolbar-groups.d.ts +6 -0
- package/dist/template-resolver/web/document-tiptap-toolbar-groups.js +33 -0
- package/dist/template-resolver/web/document-tiptap-toolbar.d.ts +3 -0
- package/dist/template-resolver/web/document-tiptap-toolbar.js +91 -0
- package/dist/template-resolver/web/editor-handle.d.ts +1 -0
- package/dist/template-resolver/web/editor-handle.js +15 -0
- package/dist/template-resolver/web/i18n.js +3 -0
- package/dist/template-resolver/web/placeholder-line-editor.js +16 -5
- package/dist/template-resolver/web/qualified-names.d.ts +1 -0
- package/dist/template-resolver/web/qualified-names.js +1 -0
- package/dist/template-resolver/web/use-document-tiptap-model.d.ts +54 -0
- package/dist/template-resolver/web/use-document-tiptap-model.js +96 -0
- package/dist/tenant/feature.js +1 -0
- package/dist/tenant/handlers/cancel-invitation.write.js +1 -1
- package/dist/tenant/handlers/memberships.query.js +1 -1
- package/dist/tenant/handlers/remove-member.write.js +2 -2
- package/dist/tenant/handlers/team-list.query.js +3 -3
- package/dist/tenant/handlers/update-member-roles.write.js +1 -1
- package/dist/tenant/index.d.ts +1 -0
- package/dist/tenant/index.js +1 -0
- package/dist/tenant/invited-membership.js +6 -1
- package/dist/tenant/schema/tenant.d.ts +2 -2
- package/dist/tenant/schema/tenant.js +4 -1
- package/dist/tenant/seeding.d.ts +2 -2
- package/dist/tenant/seeding.js +52 -52
- package/dist/tenant/stream-tenant-backfill.d.ts +21 -0
- package/dist/tenant/stream-tenant-backfill.js +63 -0
- package/dist/tenant/testing.d.ts +12 -0
- package/dist/tenant/testing.js +33 -0
- package/dist/tenant-handover/events.js +1 -1
- package/dist/tenant-handover/handlers/claim.write.js +1 -1
- package/dist/tenant-lifecycle/feature.js +5 -5
- package/dist/tenant-lifecycle/handlers/cancel-destruction.write.js +14 -5
- package/dist/tenant-lifecycle/handlers/request-destruction.write.js +12 -4
- package/dist/tenant-lifecycle/run-tenant-destroy.js +23 -13
- package/dist/tenant-lifecycle/stages.js +28 -2
- package/dist/tenant-lifecycle/testing.d.ts +1 -1
- package/dist/tenant-lifecycle/testing.js +6 -5
- package/dist/tier-engine/entity.js +1 -1
- package/dist/tier-engine/feature.js +8 -3
- package/dist/tier-engine/handlers/active-tier.query.js +3 -3
- package/dist/tier-engine/handlers/get-tenant-tier.query.js +6 -1
- package/dist/tier-engine/handlers/set-tenant-tier.write.js +4 -4
- package/dist/user/db/queries/stream-tenant-backfill.d.ts +20 -1
- package/dist/user/db/queries/stream-tenant-backfill.js +40 -77
- package/dist/user/feature.js +1 -0
- package/dist/user/handlers/find-for-auth.query.js +2 -2
- package/dist/user/handlers/update-roles.js +2 -2
- package/dist/user/index.d.ts +1 -1
- package/dist/user/index.js +1 -1
- package/dist/user/invited-global-roles.js +6 -1
- package/dist/user/principal-status.js +1 -1
- package/dist/user/seeding.d.ts +1 -1
- package/dist/user/seeding.js +20 -5
- package/dist/user/testing.d.ts +3 -0
- package/dist/user/testing.js +10 -0
- package/dist/user-data-rights/audit-download.js +12 -2
- package/dist/user-data-rights/feature.js +30 -26
- package/dist/user-data-rights/handlers/confirm-deletion-by-token.write.js +1 -1
- package/dist/user-data-rights/handlers/deletion-grace-period.js +1 -1
- package/dist/user-data-rights/handlers/download-by-job.query.js +2 -2
- package/dist/user-data-rights/handlers/download-by-token.query.js +2 -2
- package/dist/user-data-rights/handlers/request-deletion.write.js +1 -1
- package/dist/user-data-rights/handlers/restrict-account.write.js +4 -4
- package/dist/user-data-rights/handlers/run-forget-cleanup.write.js +8 -6
- package/dist/user-data-rights/index.d.ts +1 -1
- package/dist/user-data-rights/index.js +1 -1
- package/dist/user-data-rights/lib/mail-transport-resolver.js +1 -1
- package/dist/user-data-rights/lib/storage-provider-resolver.js +1 -1
- package/dist/user-data-rights/lib/update-user-lifecycle.js +6 -1
- package/dist/user-data-rights/run-export-jobs.js +7 -2
- package/dist/user-data-rights/run-forget-cleanup.d.ts +1 -0
- package/dist/user-data-rights/run-forget-cleanup.js +9 -1
- package/dist/user-data-rights/run-user-export.js +7 -1
- package/dist/user-data-rights/web/constants.d.ts +14 -0
- package/dist/user-data-rights/web/constants.js +14 -0
- package/dist/user-data-rights/web/index.d.ts +1 -0
- package/dist/user-data-rights/web/index.js +1 -0
- package/dist/user-profile/handlers/change-email.write.js +8 -6
- package/dist/waitlist/feature.js +1 -0
- package/dist/waitlist/handlers/export-purge.write.js +1 -1
- package/dist/waitlist/handlers/invite.write.js +2 -2
- package/dist/waitlist/handlers/reject.write.js +1 -1
- package/dist/waitlist/handlers/submit.write.js +20 -11
- package/dist/waitlist/import.d.ts +2 -1
- package/dist/waitlist/import.js +22 -2
- package/dist/waitlist/legacy-migrate.js +8 -3
- package/dist/waitlist/link-on-signup.js +6 -1
- package/dist/waitlist/options.d.ts +2 -1
- package/dist/workflow-runner/db/queries/due-runs.js +1 -1
- package/dist/workflow-runner/event-subscriber.js +4 -3
- package/dist/workflow-runner/event-trigger.js +2 -1
- package/dist/workflow-runner/feature.js +2 -2
- package/dist/workflow-runner/handlers/resume-run.write.js +6 -6
- package/dist/workflow-runner/runner.d.ts +3 -1
- package/dist/workflow-runner/runner.js +3 -3
- package/package.json +41 -23
- package/src/agent-tools/changes.json +6 -0
- package/src/auth-email-password/changes.json +18 -0
- package/src/auth-mfa/changes.json +6 -0
- package/src/billing-foundation/changes.json +6 -0
- package/src/cap-counter/changes.json +12 -0
- package/src/config/changes.json +6 -0
- package/src/crypto-shredding/changes.json +12 -0
- package/src/custom-fields/changes.json +6 -0
- package/src/delivery/changes.json +12 -0
- package/src/document-ingest-foundation/changes.json +6 -0
- package/src/host-routing/changes.json +6 -0
- package/src/jobs/changes.json +6 -0
- package/src/mail-transport-smtp/changes.json +12 -0
- package/src/managed-pages/changes.json +6 -0
- package/src/secrets/changes.json +6 -0
- package/src/sessions/changes.json +19 -0
- package/src/step-dispatcher/changes.json +6 -0
- package/src/template-resolver/changes.json +54 -0
- package/src/tenant/changes.json +19 -0
- package/src/tenant-lifecycle/changes.json +6 -0
- package/src/user-data-rights/changes.json +36 -0
- package/src/waitlist/changes.json +18 -0
- package/src/workflow-runner/changes.json +6 -0
|
@@ -4,5 +4,5 @@ export { buildAgentManifest } from "./agent-manifest.ts";
|
|
|
4
4
|
export { AGENT_TOOLS_FEATURE_NAME, createAgentToolsFeature } from "./feature.ts";
|
|
5
5
|
export { buildToolCatalog, OPEN_FORM_TOOL_NAME, toolNameForQn } from "./tool-catalog.ts";
|
|
6
6
|
export type { ToolCallRequest, ToolCallResult, ToolDispatcher } from "./tool-dispatch.ts";
|
|
7
|
-
export { dispatchToolCall } from "./tool-dispatch.ts";
|
|
7
|
+
export { dispatchToolCall, TOOL_CALL_ERROR_CODES } from "./tool-dispatch.ts";
|
|
8
8
|
export type { AgentManifest, AgentManifestEntity, AgentManifestFeature, AgentManifestField, AgentManifestHandler, AgentManifestNav, AgentManifestOptions, AgentManifestScreen, AgentManifestWorkspace, AgentToolMode, RegistryManifestView, RegistrySearchView, ToolCatalog, ToolCatalogOptions, ToolDefinition, ToolDispatchDescriptor, } from "./types.ts";
|
|
@@ -2,4 +2,4 @@ export { AgentDocGapKinds, findAgentDocGaps, findHandlerTranslationGaps, formatA
|
|
|
2
2
|
export { buildAgentManifest } from "./agent-manifest.js";
|
|
3
3
|
export { AGENT_TOOLS_FEATURE_NAME, createAgentToolsFeature } from "./feature.js";
|
|
4
4
|
export { buildToolCatalog, OPEN_FORM_TOOL_NAME, toolNameForQn } from "./tool-catalog.js";
|
|
5
|
-
export { dispatchToolCall } from "./tool-dispatch.js";
|
|
5
|
+
export { dispatchToolCall, TOOL_CALL_ERROR_CODES } from "./tool-dispatch.js";
|
|
@@ -37,11 +37,16 @@ export type ToolCallRequest = {
|
|
|
37
37
|
/** Receives the cause of unexpected (5xx) failures, which the tool result never carries. */
|
|
38
38
|
readonly log?: Pick<Logger, "error">;
|
|
39
39
|
};
|
|
40
|
+
export declare const TOOL_CALL_ERROR_CODES: {
|
|
41
|
+
readonly invalidToolCall: "invalid_tool_call";
|
|
42
|
+
readonly unknownTool: "unknown_tool";
|
|
43
|
+
};
|
|
40
44
|
/** Executes one LLM-issued tool call. Never throws: every failure comes back as `{ ok: false }`
|
|
41
45
|
* so the agent loop can feed the error back to the model instead of crashing.
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
46
|
+
* Every failure carries a `code`: the handler's own code for handler and dispatcher failures
|
|
47
|
+
* (429 adds `retryable`), `invalid_tool_call` for bad arguments and `unknown_tool` for a tool
|
|
48
|
+
* that is not in the table. Client errors (< 500) keep their message, server failures (>= 500,
|
|
49
|
+
* unknown throws) are logged and returned as a generic message.
|
|
45
50
|
* `request.user` must be the caller's real identity: server-kind tools run through the same
|
|
46
51
|
* permission-checked pipeline as an HTTP request. */
|
|
47
52
|
export declare function dispatchToolCall(request: ToolCallRequest): Promise<ToolCallResult>;
|
|
@@ -3,6 +3,16 @@ import { runAsAgentToolCallEntry } from "@cosmicdrift/kumiko-framework/internal/
|
|
|
3
3
|
import { createFallbackLogger } from "@cosmicdrift/kumiko-framework/logging";
|
|
4
4
|
import { isOneOf } from "@cosmicdrift/kumiko-types/type-guards";
|
|
5
5
|
import { FILTER_OPS, isRecord } from "./filter-ops.js";
|
|
6
|
+
export const TOOL_CALL_ERROR_CODES = {
|
|
7
|
+
invalidToolCall: "invalid_tool_call",
|
|
8
|
+
unknownTool: "unknown_tool",
|
|
9
|
+
};
|
|
10
|
+
function invalidToolCall(error) {
|
|
11
|
+
return { ok: false, error, code: TOOL_CALL_ERROR_CODES.invalidToolCall };
|
|
12
|
+
}
|
|
13
|
+
function unknownTool(error) {
|
|
14
|
+
return { ok: false, error, code: TOOL_CALL_ERROR_CODES.unknownTool };
|
|
15
|
+
}
|
|
6
16
|
const HTTP_TOO_MANY_REQUESTS = 429;
|
|
7
17
|
const HTTP_SERVER_ERROR = 500;
|
|
8
18
|
const UNEXPECTED_FAILURE_MESSAGE = "Tool failed unexpectedly";
|
|
@@ -52,14 +62,14 @@ function isFilterOp(value) {
|
|
|
52
62
|
function buildSearchPayload(toolName, toolInput) {
|
|
53
63
|
const query = toolInput["query"];
|
|
54
64
|
if (typeof query !== "string" || query.length === 0) {
|
|
55
|
-
return
|
|
65
|
+
return invalidToolCall(`Tool "${toolName}" requires a non-empty string "query" argument`);
|
|
56
66
|
}
|
|
57
67
|
return { ok: true, value: { search: query, limit: SEARCH_RESULT_LIMIT } };
|
|
58
68
|
}
|
|
59
69
|
function buildFindByPayload(toolName, fieldName, toolInput) {
|
|
60
70
|
const value = toolInput[fieldName];
|
|
61
71
|
if (value === undefined) {
|
|
62
|
-
return
|
|
72
|
+
return invalidToolCall(`Tool "${toolName}" requires a "${fieldName}" argument`);
|
|
63
73
|
}
|
|
64
74
|
return {
|
|
65
75
|
ok: true,
|
|
@@ -75,28 +85,28 @@ function buildEntityListPayload(list, input) {
|
|
|
75
85
|
const search = input["search"];
|
|
76
86
|
if (search !== undefined) {
|
|
77
87
|
if (typeof search !== "string") {
|
|
78
|
-
return
|
|
88
|
+
return invalidToolCall(`"search" must be a string`);
|
|
79
89
|
}
|
|
80
90
|
if (list.searchableFields.length === 0) {
|
|
81
|
-
return
|
|
91
|
+
return invalidToolCall("This entity has no searchable fields");
|
|
82
92
|
}
|
|
83
93
|
payload["search"] = search;
|
|
84
94
|
}
|
|
85
95
|
const filters = input["filters"];
|
|
86
96
|
if (filters !== undefined) {
|
|
87
97
|
if (!Array.isArray(filters)) {
|
|
88
|
-
return
|
|
98
|
+
return invalidToolCall(`"filters" must be an array`);
|
|
89
99
|
}
|
|
90
100
|
const validated = [];
|
|
91
101
|
for (const entry of filters) {
|
|
92
102
|
if (!isRecord(entry) || typeof entry["field"] !== "string" || !("value" in entry)) {
|
|
93
|
-
return
|
|
103
|
+
return invalidToolCall(`Each filter must be { field, op, value }`);
|
|
94
104
|
}
|
|
95
105
|
if (!list.filterableFields.includes(entry["field"])) {
|
|
96
|
-
return
|
|
106
|
+
return invalidToolCall(`Field "${entry["field"]}" is not filterable on this entity`);
|
|
97
107
|
}
|
|
98
108
|
if (!isFilterOp(entry["op"])) {
|
|
99
|
-
return
|
|
109
|
+
return invalidToolCall(`Unsupported filter operator "${String(entry["op"])}"`);
|
|
100
110
|
}
|
|
101
111
|
validated.push({ field: entry["field"], op: entry["op"], value: entry["value"] });
|
|
102
112
|
}
|
|
@@ -147,7 +157,7 @@ async function dispatchServerQuery(descriptor, dispatcher, user, input) {
|
|
|
147
157
|
if (descriptor.detail) {
|
|
148
158
|
const id = input["id"];
|
|
149
159
|
if (typeof id !== "string" || id.length === 0) {
|
|
150
|
-
return
|
|
160
|
+
return invalidToolCall(`This tool requires a non-empty string "id" argument`);
|
|
151
161
|
}
|
|
152
162
|
const data = await dispatcher.query(descriptor.qn, { id }, user);
|
|
153
163
|
return { ok: true, data };
|
|
@@ -171,15 +181,15 @@ async function dispatchServerWrite(descriptor, dispatcher, user, input, runId, t
|
|
|
171
181
|
if (descriptor.injectsVersion) {
|
|
172
182
|
const id = input["id"];
|
|
173
183
|
if (typeof id !== "string" || id.length === 0) {
|
|
174
|
-
return
|
|
184
|
+
return invalidToolCall(`This tool requires a non-empty string "id" argument`);
|
|
175
185
|
}
|
|
176
186
|
if (!descriptor.detailQn) {
|
|
177
|
-
return
|
|
187
|
+
return invalidToolCall("Tool is misconfigured: no detail handler to read version from");
|
|
178
188
|
}
|
|
179
189
|
const current = await dispatcher.query(descriptor.detailQn, { id }, user);
|
|
180
190
|
const version = isRecord(current) && typeof current["version"] === "number" ? current["version"] : undefined;
|
|
181
191
|
if (version === undefined) {
|
|
182
|
-
return
|
|
192
|
+
return invalidToolCall(`Could not read the current "version" for id "${id}"`);
|
|
183
193
|
}
|
|
184
194
|
payload = { ...input, version };
|
|
185
195
|
}
|
|
@@ -211,37 +221,37 @@ function dispatchClientNavigate(descriptor, input) {
|
|
|
211
221
|
if (typeof entity === "string") {
|
|
212
222
|
const screenId = descriptor.entityScreens.get(entity);
|
|
213
223
|
if (!screenId)
|
|
214
|
-
return
|
|
224
|
+
return invalidToolCall(`Unknown entity "${entity}" for navigation`);
|
|
215
225
|
const id = input["id"];
|
|
216
226
|
if (typeof id !== "string" || id.length === 0) {
|
|
217
|
-
return
|
|
227
|
+
return invalidToolCall(`Navigating to "${entity}" requires a non-empty string "id"`);
|
|
218
228
|
}
|
|
219
229
|
return { ok: true, data: { kind: "navigate", screenId, params: { id } } };
|
|
220
230
|
}
|
|
221
231
|
const screenId = input["screenId"];
|
|
222
232
|
if (typeof screenId === "string") {
|
|
223
233
|
if (!descriptor.screenIds.has(screenId)) {
|
|
224
|
-
return
|
|
234
|
+
return invalidToolCall(`Unknown screen "${screenId}"`);
|
|
225
235
|
}
|
|
226
236
|
const params = input["params"];
|
|
227
237
|
if (params !== undefined) {
|
|
228
238
|
if (!isRecord(params) || Object.values(params).some((value) => typeof value !== "string")) {
|
|
229
|
-
return
|
|
239
|
+
return invalidToolCall(`"params" must be an object of string values`);
|
|
230
240
|
}
|
|
231
241
|
return { ok: true, data: { kind: "navigate", screenId, params } };
|
|
232
242
|
}
|
|
233
243
|
return { ok: true, data: { kind: "navigate", screenId, params: {} } };
|
|
234
244
|
}
|
|
235
|
-
return
|
|
245
|
+
return invalidToolCall(`navigate requires either { entity, id } or { screenId }`);
|
|
236
246
|
}
|
|
237
247
|
function dispatchClientOpenForm(descriptor, input) {
|
|
238
248
|
const handlerQn = input["handlerQn"];
|
|
239
249
|
if (typeof handlerQn !== "string") {
|
|
240
|
-
return
|
|
250
|
+
return invalidToolCall(`open_form requires a string "handlerQn" argument`);
|
|
241
251
|
}
|
|
242
252
|
const screenId = descriptor.formScreens.get(handlerQn);
|
|
243
253
|
if (!screenId)
|
|
244
|
-
return
|
|
254
|
+
return invalidToolCall(`No form screen mounted for handler "${handlerQn}"`);
|
|
245
255
|
return {
|
|
246
256
|
ok: true,
|
|
247
257
|
data: { kind: "open_form", screenId, handlerQn, prefill: input["prefill"] ?? {} },
|
|
@@ -253,14 +263,14 @@ function isStringArray(value) {
|
|
|
253
263
|
function dispatchClientAskUser(input) {
|
|
254
264
|
const question = input["question"];
|
|
255
265
|
if (typeof question !== "string" || question.length === 0) {
|
|
256
|
-
return
|
|
266
|
+
return invalidToolCall(`ask_user requires a non-empty string "question" argument`);
|
|
257
267
|
}
|
|
258
268
|
const options = input["options"];
|
|
259
269
|
if (options === undefined) {
|
|
260
270
|
return { ok: true, data: { kind: "ask_user", question } };
|
|
261
271
|
}
|
|
262
272
|
if (!isStringArray(options)) {
|
|
263
|
-
return
|
|
273
|
+
return invalidToolCall(`ask_user "options" argument must be an array of strings`);
|
|
264
274
|
}
|
|
265
275
|
return { ok: true, data: { kind: "ask_user", question, options } };
|
|
266
276
|
}
|
|
@@ -276,9 +286,10 @@ function dispatchClient(descriptor, input) {
|
|
|
276
286
|
}
|
|
277
287
|
/** Executes one LLM-issued tool call. Never throws: every failure comes back as `{ ok: false }`
|
|
278
288
|
* so the agent loop can feed the error back to the model instead of crashing.
|
|
279
|
-
*
|
|
280
|
-
*
|
|
281
|
-
*
|
|
289
|
+
* Every failure carries a `code`: the handler's own code for handler and dispatcher failures
|
|
290
|
+
* (429 adds `retryable`), `invalid_tool_call` for bad arguments and `unknown_tool` for a tool
|
|
291
|
+
* that is not in the table. Client errors (< 500) keep their message, server failures (>= 500,
|
|
292
|
+
* unknown throws) are logged and returned as a generic message.
|
|
282
293
|
* `request.user` must be the caller's real identity: server-kind tools run through the same
|
|
283
294
|
* permission-checked pipeline as an HTTP request. */
|
|
284
295
|
export async function dispatchToolCall(request) {
|
|
@@ -286,7 +297,7 @@ export async function dispatchToolCall(request) {
|
|
|
286
297
|
const classifyFailure = createFailureClassifier(toolName, request.log ?? fallbackLog);
|
|
287
298
|
const descriptor = dispatchTable.get(toolName);
|
|
288
299
|
if (!descriptor) {
|
|
289
|
-
return
|
|
300
|
+
return unknownTool(`Unknown tool "${toolName}"`);
|
|
290
301
|
}
|
|
291
302
|
try {
|
|
292
303
|
return await runAsAgentToolCallEntry(async () => {
|
package/dist/audit/feature.js
CHANGED
|
@@ -23,6 +23,7 @@ import { AUDIT_I18N } from "./web/i18n.js";
|
|
|
23
23
|
// framework).
|
|
24
24
|
export function createAuditFeature() {
|
|
25
25
|
return defineFeature("audit", (r) => {
|
|
26
|
+
r.adoptsBundledLists();
|
|
26
27
|
r.describe("Exposes the framework's event store as a paginated, filterable audit log via the `audit:query:list` handler (accessible to `Admin` and `SystemAdmin` roles). No separate table or projection \u2014 the event store is the audit trail by construction: every entity write already records who, when, what entity, and the event payload with PII stripped. A SystemAdmin can pass `scope: \"system\"` to read the app-instance system events such as `app.started`, and reads the events of every tenant (system tenant excluded) through `audit:query:list-all-tenants` and the `audit-log-all-tenants` screen. Filter by `aggregateType`, `aggregateId`, `eventType`, `userId`, or time range. Also records `audit:event:escape-hatch-used` whenever a handler uses one of the framework's escape hatches (unsafeRaw, acknowledgeCrossTenant, db.global() writes, or a granted identity switch).");
|
|
27
28
|
r.uiHints({
|
|
28
29
|
displayLabel: "Audit Log",
|
|
@@ -56,7 +57,7 @@ export function createAuditFeature() {
|
|
|
56
57
|
await runEscapeHatchRetention({
|
|
57
58
|
db: ctx.db.unsafeRaw(),
|
|
58
59
|
registry: ctx.registry,
|
|
59
|
-
configResolver: ctx.configResolver,
|
|
60
|
+
configResolver: ctx.services.configResolver,
|
|
60
61
|
userId: SYSTEM_USER_ID,
|
|
61
62
|
});
|
|
62
63
|
},
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// Narrow cross-feature query results (ctx.queryAs → Promise<unknown>) into
|
|
1
|
+
// Narrow cross-feature query results (ctx.dispatch.queryAs → Promise<unknown>) into
|
|
2
2
|
// the shape the auth handlers actually read. Replaces a bare
|
|
3
3
|
// `as AuthUserRow | null` at the system boundary — the coding standard
|
|
4
4
|
// requires a TypeGuard in place of unchecked casts from unknown.
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
import { makeDispatchSystemWrite, makeDispatchWriteAs, } from "@cosmicdrift/kumiko-framework/api";
|
|
8
8
|
import { fetchOne } from "@cosmicdrift/kumiko-framework/db";
|
|
9
9
|
import { ConfigScopes, createSystemUser, } from "@cosmicdrift/kumiko-framework/engine";
|
|
10
|
+
import { runInSystemRowLevelSecurityScope } from "@cosmicdrift/kumiko-framework/internal/row-level-security";
|
|
10
11
|
import { parseRoles } from "@cosmicdrift/kumiko-framework/utils";
|
|
11
12
|
// kumiko-lint-ignore cross-feature-import bootstrap sets per-tenant config through the config feature's write handler
|
|
12
13
|
import { ConfigHandlers } from "../config/web/constants.js";
|
|
@@ -139,7 +140,11 @@ async function decideInvite(deps, invite) {
|
|
|
139
140
|
function isMailingOutcome(outcome) {
|
|
140
141
|
return outcome === "invited" || outcome === "resent";
|
|
141
142
|
}
|
|
142
|
-
|
|
143
|
+
// A one-shot operator process, not a tenant request: it looks up users, memberships and invitations across tenants.
|
|
144
|
+
export function bootstrapTenants(deps, plan) {
|
|
145
|
+
return runInSystemRowLevelSecurityScope("boot tenant bootstrap creates tenants and memberships before any tenant exists", () => bootstrapTenantsInScope(deps, plan));
|
|
146
|
+
}
|
|
147
|
+
async function bootstrapTenantsInScope(deps, plan) {
|
|
143
148
|
const plannedInvites = planInvites(plan);
|
|
144
149
|
const dispatchSystemWrite = makeDispatchSystemWrite(deps.dispatcher);
|
|
145
150
|
const dispatchWriteAsRoles = makeDispatchWriteAs(deps.dispatcher);
|
|
@@ -48,7 +48,7 @@ export const authEmailPasswordEnvSchema = z.object({
|
|
|
48
48
|
.describe("Optional `iss` claim pinned on every minted JWT."),
|
|
49
49
|
});
|
|
50
50
|
// Auth feature — email+password login. Depends on the user feature for
|
|
51
|
-
// identity lookups (via ctx.queryAs) and on the tenant feature for
|
|
51
|
+
// identity lookups (via ctx.dispatch.queryAs) and on the tenant feature for
|
|
52
52
|
// membership resolution. No direct imports of foreign tables.
|
|
53
53
|
export function createAuthEmailPasswordFeature(opts = {}) {
|
|
54
54
|
// ≥32 chars, symmetric to the JWT_SECRET env check: a short HMAC secret
|
|
@@ -5,7 +5,7 @@ import { UserHandlers, UserQueries } from "../../user/index.js";
|
|
|
5
5
|
import { invalidCredentials } from "../errors.js";
|
|
6
6
|
import { passwordSchema } from "../password-policy.js";
|
|
7
7
|
// Change-password — authenticated. The user supplies their current password
|
|
8
|
-
// (re-auth) and the new one. The new hash is written via ctx.writeAs(system)
|
|
8
|
+
// (re-auth) and the new one. The new hash is written via ctx.dispatch.writeAs(system)
|
|
9
9
|
// against the user feature's update handler; field-access on passwordHash
|
|
10
10
|
// (privileged-only) lets the system identity through.
|
|
11
11
|
export const changePasswordWrite = defineWriteHandler({
|
|
@@ -21,8 +21,8 @@ export const changePasswordWrite = defineWriteHandler({
|
|
|
21
21
|
},
|
|
22
22
|
escapeHatch: {
|
|
23
23
|
grants: ["systemIdentity"],
|
|
24
|
-
reason: "Reads the caller's own passwordHash (privileged-only field) via ctx.queryAs(SYSTEM, ...) " +
|
|
25
|
-
"and writes the new hash via ctx.writeAs(SYSTEM, user:update) — the caller's own " +
|
|
24
|
+
reason: "Reads the caller's own passwordHash (privileged-only field) via ctx.dispatch.queryAs(SYSTEM, ...) " +
|
|
25
|
+
"and writes the new hash via ctx.dispatch.writeAs(SYSTEM, user:update) — the caller's own " +
|
|
26
26
|
"identity can't reach either, field-access on passwordHash is privileged-only.",
|
|
27
27
|
},
|
|
28
28
|
// Payload carries the old and new password.
|
|
@@ -31,7 +31,7 @@ export const changePasswordWrite = defineWriteHandler({
|
|
|
31
31
|
handler: async (event, ctx) => {
|
|
32
32
|
const systemUser = createSystemUser(event.user.tenantId);
|
|
33
33
|
// Load self with passwordHash — only visible to the privileged caller.
|
|
34
|
-
const me = (await ctx.queryAs(systemUser, UserQueries.findForAuth, {
|
|
34
|
+
const me = (await ctx.dispatch.queryAs(systemUser, UserQueries.findForAuth, {
|
|
35
35
|
id: event.user.id,
|
|
36
36
|
})); // @cast-boundary db-runner
|
|
37
37
|
if (!me?.passwordHash) {
|
|
@@ -43,13 +43,13 @@ export const changePasswordWrite = defineWriteHandler({
|
|
|
43
43
|
}
|
|
44
44
|
const newHash = await hashPassword(event.payload.newPassword);
|
|
45
45
|
// The user aggregate is systemStream: its event stream lives on
|
|
46
|
-
// SYSTEM_TENANT_ID deterministically. Previously scattered streams
|
|
47
|
-
//
|
|
46
|
+
// SYSTEM_TENANT_ID deterministically. Previously scattered streams are moved by the
|
|
47
|
+
// boot-time stream-tenant backfill (runStreamTenantBackfillOnBoot).
|
|
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
|
|
51
51
|
// through so optimistic locking still applies end-to-end.
|
|
52
|
-
const writeRes = await ctx.writeAs(writer, UserHandlers.update, {
|
|
52
|
+
const writeRes = await ctx.dispatch.writeAs(writer, UserHandlers.update, {
|
|
53
53
|
id: me.id,
|
|
54
54
|
version: me.version,
|
|
55
55
|
changes: { passwordHash: newHash },
|
|
@@ -29,9 +29,9 @@ export function createConfirmAccountUnlockHandler(opts) {
|
|
|
29
29
|
i18nKey: "auth.errors.unlockNotConfigured",
|
|
30
30
|
}));
|
|
31
31
|
}
|
|
32
|
-
if (!ctx.redis) {
|
|
32
|
+
if (!ctx.services.redis) {
|
|
33
33
|
return writeFailure(new InternalError({
|
|
34
|
-
message: "account-unlock requires ctx.redis to clear lockout state",
|
|
34
|
+
message: "account-unlock requires ctx.services.redis to clear lockout state",
|
|
35
35
|
}));
|
|
36
36
|
}
|
|
37
37
|
// All verify failures (malformed / bad_signature / expired) fold into
|
|
@@ -40,7 +40,7 @@ export function createConfirmAccountUnlockHandler(opts) {
|
|
|
40
40
|
const verify = verifyUnlockToken(event.payload.token, opts.hmacSecret);
|
|
41
41
|
if (!verify.ok)
|
|
42
42
|
return invalidUnlockToken();
|
|
43
|
-
await clearLockoutState(ctx.redis, verify.userId);
|
|
43
|
+
await clearLockoutState(ctx.services.redis, verify.userId);
|
|
44
44
|
return { isSuccess: true, data: { kind: "account-unlocked" } };
|
|
45
45
|
},
|
|
46
46
|
});
|
|
@@ -30,10 +30,10 @@ export async function runConfirmTokenFlow(ctx, userId, expiresAtMs, spec) {
|
|
|
30
30
|
declareEscapeHatch({
|
|
31
31
|
reason: "writes the confirming user's row via UserHandlers.update on the caller's handler context, using a SYSTEM_TENANT-scoped identity; the calling handler declares its own escapeHatch",
|
|
32
32
|
});
|
|
33
|
-
if (!ctx.redis) {
|
|
33
|
+
if (!ctx.services.redis) {
|
|
34
34
|
return writeFailure(new InternalError({ message: spec.redisRequiredMessage }));
|
|
35
35
|
}
|
|
36
|
-
const redis = ctx.redis;
|
|
36
|
+
const redis = ctx.services.redis;
|
|
37
37
|
const burn = await burnToken(redis, spec.purpose, userId, expiresAtMs);
|
|
38
38
|
if (burn === "already-used")
|
|
39
39
|
return spec.invalidToken();
|
|
@@ -52,7 +52,7 @@ export async function runConfirmTokenFlow(ctx, userId, expiresAtMs, spec) {
|
|
|
52
52
|
return { isSuccess: true, data: spec.alreadyDone.data };
|
|
53
53
|
}
|
|
54
54
|
const changes = await spec.buildChanges(me);
|
|
55
|
-
const writeRes = await ctx.writeAs(systemUser, UserHandlers.update, {
|
|
55
|
+
const writeRes = await ctx.dispatch.writeAs(systemUser, UserHandlers.update, {
|
|
56
56
|
id: me.id,
|
|
57
57
|
version: me.version,
|
|
58
58
|
changes,
|
|
@@ -89,7 +89,7 @@ async function loadValidatedUser(ctx, systemUser, userId) {
|
|
|
89
89
|
declareEscapeHatch({
|
|
90
90
|
reason: "reads the confirming user's row via UserQueries.findForAuth on the caller's handler context, using a SYSTEM_TENANT-scoped identity; the calling handler declares its own escapeHatch",
|
|
91
91
|
});
|
|
92
|
-
const me = parseAuthUserRow(await ctx.queryAs(systemUser, UserQueries.findForAuth, { id: userId }));
|
|
92
|
+
const me = parseAuthUserRow(await ctx.dispatch.queryAs(systemUser, UserQueries.findForAuth, { id: userId }));
|
|
93
93
|
if (!me || me.isDeleted || me.version === undefined || me.version < 1)
|
|
94
94
|
return null;
|
|
95
95
|
return { ...me, version: me.version };
|
|
@@ -64,13 +64,13 @@ export function createInviteAcceptWithLoginHandler(opts = {}) {
|
|
|
64
64
|
agent: { expose: false },
|
|
65
65
|
// kumiko-lint-ignore complexity-budget reuses login.write.ts's gate chain (lockout/password/email/status/membership/mfa) plus invite-specific branches (email match, already-member check, invitation update, unburn-on-failure) — splitting would scatter gate order across functions without reducing risk
|
|
66
66
|
handler: async (event, ctx) => {
|
|
67
|
-
if (!ctx.redis) {
|
|
68
|
-
return writeFailure(new InternalError({ message: "invite-accept-with-login requires ctx.redis" }));
|
|
67
|
+
if (!ctx.services.redis) {
|
|
68
|
+
return writeFailure(new InternalError({ message: "invite-accept-with-login requires ctx.services.redis" }));
|
|
69
69
|
}
|
|
70
|
-
const invitationId = await getInvitationIdForToken(ctx.redis, event.payload.token);
|
|
70
|
+
const invitationId = await getInvitationIdForToken(ctx.services.redis, event.payload.token);
|
|
71
71
|
if (!invitationId)
|
|
72
72
|
return invalidInviteToken();
|
|
73
|
-
const burn = await burnInviteToken(ctx.redis, event.payload.token);
|
|
73
|
+
const burn = await burnInviteToken(ctx.services.redis, event.payload.token);
|
|
74
74
|
if (burn === "already-used")
|
|
75
75
|
return invalidInviteToken();
|
|
76
76
|
let committed = false;
|
|
@@ -131,6 +131,7 @@ export function createInviteAcceptWithLoginHandler(opts = {}) {
|
|
|
131
131
|
db: dbConn,
|
|
132
132
|
tenantId: invitationTenantId,
|
|
133
133
|
mode: "system",
|
|
134
|
+
reason: "invitation tenant differs from the caller's tenant, the accept step updates the invitation row there",
|
|
134
135
|
});
|
|
135
136
|
const updateResult = await invitationExecutor.update({
|
|
136
137
|
id: invitationId,
|
|
@@ -139,7 +140,7 @@ export function createInviteAcceptWithLoginHandler(opts = {}) {
|
|
|
139
140
|
}, createSystemUser(invitationTenantId), invitationTdb);
|
|
140
141
|
if (!updateResult.isSuccess)
|
|
141
142
|
return updateResult;
|
|
142
|
-
await deleteInviteToken(ctx.redis, { invitationId, token: event.payload.token });
|
|
143
|
+
await deleteInviteToken(ctx.services.redis, { invitationId, token: event.payload.token });
|
|
143
144
|
// buildSessionRoles calls stripForbiddenMembershipRoles internally —
|
|
144
145
|
// a reserved role on an existing membership must never reach the session.
|
|
145
146
|
const mergedRoles = buildSessionRoles(globalGrant.data.roles, grant.data.roles);
|
|
@@ -172,8 +173,8 @@ export function createInviteAcceptWithLoginHandler(opts = {}) {
|
|
|
172
173
|
};
|
|
173
174
|
}
|
|
174
175
|
finally {
|
|
175
|
-
if (!committed && ctx.redis) {
|
|
176
|
-
await unburnInviteToken(ctx.redis, event.payload.token);
|
|
176
|
+
if (!committed && ctx.services.redis) {
|
|
177
|
+
await unburnInviteToken(ctx.services.redis, event.payload.token);
|
|
177
178
|
}
|
|
178
179
|
}
|
|
179
180
|
},
|
|
@@ -55,13 +55,15 @@ export function createInviteAcceptHandler() {
|
|
|
55
55
|
},
|
|
56
56
|
// kumiko-lint-ignore complexity-budget invite branches (auth/anon/burn) stay in one handler
|
|
57
57
|
handler: async (event, ctx) => {
|
|
58
|
-
if (!ctx.redis) {
|
|
59
|
-
return writeFailure(new InternalError({
|
|
58
|
+
if (!ctx.services.redis) {
|
|
59
|
+
return writeFailure(new InternalError({
|
|
60
|
+
message: "invite-accept requires ctx.services.redis for token consumption",
|
|
61
|
+
}));
|
|
60
62
|
}
|
|
61
|
-
const invitationId = await getInvitationIdForToken(ctx.redis, event.payload.token);
|
|
63
|
+
const invitationId = await getInvitationIdForToken(ctx.services.redis, event.payload.token);
|
|
62
64
|
if (!invitationId)
|
|
63
65
|
return invalidInviteToken();
|
|
64
|
-
const burn = await burnInviteToken(ctx.redis, event.payload.token);
|
|
66
|
+
const burn = await burnInviteToken(ctx.services.redis, event.payload.token);
|
|
65
67
|
if (burn === "already-used")
|
|
66
68
|
return invalidInviteToken();
|
|
67
69
|
let committed = false;
|
|
@@ -111,6 +113,7 @@ export function createInviteAcceptHandler() {
|
|
|
111
113
|
db: dbConn,
|
|
112
114
|
tenantId: invitationTenantId,
|
|
113
115
|
mode: "system",
|
|
116
|
+
reason: "invitation tenant differs from the caller's tenant, the accept step updates the invitation row there",
|
|
114
117
|
});
|
|
115
118
|
const updateResult = await invitationExecutor.update({
|
|
116
119
|
id: invitationId,
|
|
@@ -119,7 +122,7 @@ export function createInviteAcceptHandler() {
|
|
|
119
122
|
}, createSystemUser(invitationTenantId), invitationTdb);
|
|
120
123
|
if (!updateResult.isSuccess)
|
|
121
124
|
return updateResult;
|
|
122
|
-
await deleteInviteToken(ctx.redis, { invitationId, token: event.payload.token });
|
|
125
|
+
await deleteInviteToken(ctx.services.redis, { invitationId, token: event.payload.token });
|
|
123
126
|
committed = true;
|
|
124
127
|
return {
|
|
125
128
|
isSuccess: true,
|
|
@@ -132,8 +135,8 @@ export function createInviteAcceptHandler() {
|
|
|
132
135
|
};
|
|
133
136
|
}
|
|
134
137
|
finally {
|
|
135
|
-
if (!committed && ctx.redis) {
|
|
136
|
-
await unburnInviteToken(ctx.redis, event.payload.token);
|
|
138
|
+
if (!committed && ctx.services.redis) {
|
|
139
|
+
await unburnInviteToken(ctx.services.redis, event.payload.token);
|
|
137
140
|
}
|
|
138
141
|
}
|
|
139
142
|
},
|
|
@@ -76,8 +76,8 @@ async function currentMembershipVersion(ctx, tenantId, email) {
|
|
|
76
76
|
return membershipVersionOf(ctx.db, tenantId, user.id);
|
|
77
77
|
}
|
|
78
78
|
async function issueInvitation(opts, ttlSeconds, request, inviter, ctx, refuseAccepted = false) {
|
|
79
|
-
if (!ctx.redis) {
|
|
80
|
-
return writeFailure(new InternalError({ message: "invite-create requires ctx.redis for token store" }));
|
|
79
|
+
if (!ctx.services.redis) {
|
|
80
|
+
return writeFailure(new InternalError({ message: "invite-create requires ctx.services.redis for token store" }));
|
|
81
81
|
}
|
|
82
82
|
const email = request.email.toLowerCase();
|
|
83
83
|
const tenantId = inviter.tenantId;
|
|
@@ -100,7 +100,7 @@ async function issueInvitation(opts, ttlSeconds, request, inviter, ctx, refuseAc
|
|
|
100
100
|
const existingVersion = existing["version"]; // @cast-boundary db-row
|
|
101
101
|
// At most one live invite token per invitation: invalidate
|
|
102
102
|
// whatever's there before minting the new one.
|
|
103
|
-
await invalidateExistingInviteToken(ctx.redis, invitationId);
|
|
103
|
+
await invalidateExistingInviteToken(ctx.services.redis, invitationId);
|
|
104
104
|
const updateResult = await executor.update({
|
|
105
105
|
id: invitationId,
|
|
106
106
|
version: existingVersion,
|
|
@@ -133,7 +133,7 @@ async function issueInvitation(opts, ttlSeconds, request, inviter, ctx, refuseAc
|
|
|
133
133
|
invitationId = createResult.data.id; // @cast-boundary engine-payload
|
|
134
134
|
}
|
|
135
135
|
const token = generateToken();
|
|
136
|
-
await storeInviteToken(ctx.redis, { invitationId, token, ttlSeconds });
|
|
136
|
+
await storeInviteToken(ctx.services.redis, { invitationId, token, ttlSeconds });
|
|
137
137
|
const locale = request.locale ?? resolveHandlerMailLocale(ctx, opts.locale);
|
|
138
138
|
await dispatchMagicLinkMail(ctx.notify, {
|
|
139
139
|
handlerName: "invite-create",
|
|
@@ -40,9 +40,9 @@ export const inviteInfoQuery = defineQueryHandler({
|
|
|
40
40
|
description: "Anonymous, read-only invite lookup for the invite-acceptance page: reveals the invited " +
|
|
41
41
|
"email and whether an account already exists for it, without consuming the token.",
|
|
42
42
|
handler: async (query, ctx) => {
|
|
43
|
-
if (!ctx.redis)
|
|
43
|
+
if (!ctx.services.redis)
|
|
44
44
|
throwInvalidInviteToken();
|
|
45
|
-
const invitationId = await getInvitationIdForToken(ctx.redis, query.payload.token);
|
|
45
|
+
const invitationId = await getInvitationIdForToken(ctx.services.redis, query.payload.token);
|
|
46
46
|
if (!invitationId)
|
|
47
47
|
throwInvalidInviteToken();
|
|
48
48
|
const invitation = await fetchOne(ctx.db.unsafeRaw(), tenantInvitationsTable, {
|
|
@@ -55,13 +55,13 @@ export function createInviteSignupCompleteHandler(opts = {}) {
|
|
|
55
55
|
reason: INVITE_SIGNUP_COMPLETE_ESCAPE_HATCH_REASON,
|
|
56
56
|
},
|
|
57
57
|
handler: async (event, ctx) => {
|
|
58
|
-
if (!ctx.redis) {
|
|
59
|
-
return writeFailure(new InternalError({ message: "invite-signup-complete requires ctx.redis" }));
|
|
58
|
+
if (!ctx.services.redis) {
|
|
59
|
+
return writeFailure(new InternalError({ message: "invite-signup-complete requires ctx.services.redis" }));
|
|
60
60
|
}
|
|
61
|
-
const invitationId = await getInvitationIdForToken(ctx.redis, event.payload.token);
|
|
61
|
+
const invitationId = await getInvitationIdForToken(ctx.services.redis, event.payload.token);
|
|
62
62
|
if (!invitationId)
|
|
63
63
|
return invalidInviteToken();
|
|
64
|
-
const burn = await burnInviteToken(ctx.redis, event.payload.token);
|
|
64
|
+
const burn = await burnInviteToken(ctx.services.redis, event.payload.token);
|
|
65
65
|
if (burn === "already-used")
|
|
66
66
|
return invalidInviteToken();
|
|
67
67
|
let committed = false;
|
|
@@ -115,6 +115,7 @@ export function createInviteSignupCompleteHandler(opts = {}) {
|
|
|
115
115
|
db: dbConn,
|
|
116
116
|
tenantId: invitationTenantId,
|
|
117
117
|
mode: "system",
|
|
118
|
+
reason: "invitation tenant differs from the caller's tenant, the accept step updates the invitation row there",
|
|
118
119
|
});
|
|
119
120
|
const updateResult = await invitationExecutor.update({
|
|
120
121
|
id: invitationId,
|
|
@@ -130,7 +131,7 @@ export function createInviteSignupCompleteHandler(opts = {}) {
|
|
|
130
131
|
// call, but an MFA-gated role gets the MFA step instead of a session.
|
|
131
132
|
// It runs before the token is deleted so a throwing check leaves the link retryable.
|
|
132
133
|
const mfaGate = await gateEnforceMfa(ctx, { mfaStatusChecker: opts.mfaStatusChecker }, userId, invitationTenantId, mergedRoles);
|
|
133
|
-
await deleteInviteToken(ctx.redis, { invitationId, token: event.payload.token });
|
|
134
|
+
await deleteInviteToken(ctx.services.redis, { invitationId, token: event.payload.token });
|
|
134
135
|
if (mfaGate !== undefined) {
|
|
135
136
|
committed = true;
|
|
136
137
|
return { isSuccess: true, data: mfaGate };
|
|
@@ -153,8 +154,8 @@ export function createInviteSignupCompleteHandler(opts = {}) {
|
|
|
153
154
|
};
|
|
154
155
|
}
|
|
155
156
|
finally {
|
|
156
|
-
if (!committed && ctx.redis) {
|
|
157
|
-
await unburnInviteToken(ctx.redis, event.payload.token);
|
|
157
|
+
if (!committed && ctx.services.redis) {
|
|
158
|
+
await unburnInviteToken(ctx.services.redis, event.payload.token);
|
|
158
159
|
}
|
|
159
160
|
}
|
|
160
161
|
},
|