@cosmicdrift/kumiko-samples 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/package.json +1 -1
- package/packages/bundled-features/package.json +25 -13
- package/packages/bundled-features/src/agent-tools/changes.json +6 -0
- package/packages/bundled-features/src/agent-tools/index.ts +1 -1
- package/packages/bundled-features/src/agent-tools/tool-dispatch.ts +42 -26
- package/packages/bundled-features/src/audit/feature.ts +2 -1
- package/packages/bundled-features/src/auth-email-password/auth-user-row.ts +1 -1
- package/packages/bundled-features/src/auth-email-password/bootstrap.ts +13 -1
- package/packages/bundled-features/src/auth-email-password/changes.json +18 -0
- package/packages/bundled-features/src/auth-email-password/feature.ts +2 -2
- package/packages/bundled-features/src/auth-email-password/handlers/change-password.write.ts +7 -7
- package/packages/bundled-features/src/auth-email-password/handlers/confirm-account-unlock.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 +9 -7
- package/packages/bundled-features/src/auth-email-password/handlers/invite-accept.write.ts +11 -7
- package/packages/bundled-features/src/auth-email-password/handlers/invite-create.write.ts +4 -4
- package/packages/bundled-features/src/auth-email-password/handlers/invite-info.query.ts +2 -2
- package/packages/bundled-features/src/auth-email-password/handlers/invite-signup-complete.write.ts +9 -7
- package/packages/bundled-features/src/auth-email-password/handlers/login.write.ts +23 -16
- package/packages/bundled-features/src/auth-email-password/handlers/request-account-unlock.write.ts +1 -0
- package/packages/bundled-features/src/auth-email-password/handlers/request-email-verification.write.ts +1 -0
- package/packages/bundled-features/src/auth-email-password/handlers/request-password-reset.write.ts +1 -0
- package/packages/bundled-features/src/auth-email-password/handlers/reset-password.write.ts +3 -2
- package/packages/bundled-features/src/auth-email-password/handlers/signup-confirm.write.ts +12 -12
- package/packages/bundled-features/src/auth-email-password/handlers/signup-request.write.ts +16 -8
- package/packages/bundled-features/src/auth-email-password/handlers/switch-tenant-mfa-gate.write.ts +4 -2
- package/packages/bundled-features/src/auth-email-password/handlers/token-request-handler.ts +10 -2
- package/packages/bundled-features/src/auth-email-password/handlers/verify-email.write.ts +3 -2
- package/packages/bundled-features/src/auth-email-password/magic-link-mail.ts +16 -3
- package/packages/bundled-features/src/auth-email-password/seeding.ts +14 -9
- package/packages/bundled-features/src/auth-email-password/signup-activation.ts +2 -0
- package/packages/bundled-features/src/auth-email-password/web/auth-client.ts +8 -2
- package/packages/bundled-features/src/auth-email-password/web/auth-redirect.ts +23 -21
- package/packages/bundled-features/src/auth-email-password/web/default-auth-pages-gate.tsx +6 -3
- package/packages/bundled-features/src/auth-email-password/web/forgot-password-screen.tsx +11 -1
- package/packages/bundled-features/src/auth-email-password/web/index.ts +5 -0
- package/packages/bundled-features/src/auth-email-password/web/login-screen.tsx +16 -5
- package/packages/bundled-features/src/auth-email-password/web/reset-password-screen.tsx +7 -1
- package/packages/bundled-features/src/auth-email-password/web/return-path.ts +35 -0
- package/packages/bundled-features/src/auth-email-password/web/session.tsx +6 -1
- package/packages/bundled-features/src/auth-email-password/web/signup-complete-screen.tsx +11 -3
- package/packages/bundled-features/src/auth-email-password/web/signup-screen.tsx +12 -2
- package/packages/bundled-features/src/auth-foundation/feature.ts +13 -4
- package/packages/bundled-features/src/auth-mfa/changes.json +6 -0
- package/packages/bundled-features/src/auth-mfa/config.ts +3 -7
- package/packages/bundled-features/src/auth-mfa/handlers/disable.write.ts +5 -5
- package/packages/bundled-features/src/auth-mfa/handlers/enable-confirm-preauth.write.ts +24 -14
- package/packages/bundled-features/src/auth-mfa/handlers/enable-confirm.write.ts +9 -3
- package/packages/bundled-features/src/auth-mfa/handlers/enable-start-preauth.write.ts +6 -1
- package/packages/bundled-features/src/auth-mfa/handlers/enable-start.write.ts +3 -1
- package/packages/bundled-features/src/auth-mfa/handlers/reencrypt.job.ts +14 -9
- package/packages/bundled-features/src/auth-mfa/handlers/regenerate-recovery.write.ts +5 -4
- package/packages/bundled-features/src/auth-mfa/handlers/verify.write.ts +25 -14
- package/packages/bundled-features/src/auth-mfa/mfa-code-verifier.ts +10 -4
- package/packages/bundled-features/src/auth-mfa/mfa-status-checker.ts +17 -8
- package/packages/bundled-features/src/auth-mfa/verify-factor.ts +1 -1
- package/packages/bundled-features/src/billing-foundation/billing-info-query.ts +2 -2
- package/packages/bundled-features/src/billing-foundation/changes.json +6 -0
- package/packages/bundled-features/src/billing-foundation/consumer-protection/consent-gate.ts +1 -1
- package/packages/bundled-features/src/billing-foundation/consumer-protection/issue-confirmation.ts +5 -5
- package/packages/bundled-features/src/billing-foundation/consumer-protection/register-consent.ts +10 -7
- package/packages/bundled-features/src/billing-foundation/consumer-protection/register-termination.ts +15 -12
- package/packages/bundled-features/src/billing-foundation/consumer-protection/termination-open-cancels.ts +22 -0
- package/packages/bundled-features/src/billing-foundation/consumer-protection/termination-provider-lock.ts +4 -0
- package/packages/bundled-features/src/billing-foundation/consumer-protection/termination-receipt-limit.ts +4 -4
- package/packages/bundled-features/src/billing-foundation/consumer-protection/termination-record.ts +17 -58
- package/packages/bundled-features/src/billing-foundation/consumer-protection/termination-request.ts +10 -8
- package/packages/bundled-features/src/billing-foundation/consumer-protection/termination-revoke.ts +18 -15
- package/packages/bundled-features/src/billing-foundation/events.ts +1 -1
- package/packages/bundled-features/src/billing-foundation/feature.ts +8 -3
- package/packages/bundled-features/src/billing-foundation/get-subscription-for-tenant.ts +1 -1
- package/packages/bundled-features/src/billing-foundation/handlers/process-event.write.ts +5 -5
- package/packages/bundled-features/src/billing-foundation/handlers/process-payment-event.write.ts +3 -3
- package/packages/bundled-features/src/billing-foundation/plan-catalog.ts +2 -2
- package/packages/bundled-features/src/billing-foundation/projection.ts +1 -1
- package/packages/bundled-features/src/billing-foundation/types.ts +1 -1
- package/packages/bundled-features/src/cap-counter/aggregate-id.ts +1 -1
- package/packages/bundled-features/src/cap-counter/book-cap-usage.ts +5 -4
- package/packages/bundled-features/src/cap-counter/cap-reservation.ts +21 -8
- package/packages/bundled-features/src/cap-counter/changes.json +12 -0
- package/packages/bundled-features/src/cap-counter/constants.ts +1 -1
- package/packages/bundled-features/src/cap-counter/feature.ts +3 -2
- package/packages/bundled-features/src/cap-counter/handlers/increment-rolling.write.ts +1 -1
- package/packages/bundled-features/src/cap-counter/reservation-chain.ts +1 -1
- package/packages/bundled-features/src/cap-counter/with-cap-enforcement.ts +4 -4
- package/packages/bundled-features/src/cap-overview/feature.ts +1 -0
- package/packages/bundled-features/src/cap-overview/handlers/caps-usage.query.ts +1 -1
- package/packages/bundled-features/src/cap-overview/handlers/tenant-caps-list.query.ts +1 -1
- package/packages/bundled-features/src/compliance-profiles/seeding.ts +12 -7
- package/packages/bundled-features/src/config/changes.json +6 -0
- package/packages/bundled-features/src/config/feature.ts +6 -6
- package/packages/bundled-features/src/config/handlers/cascade.query.ts +1 -1
- package/packages/bundled-features/src/config/handlers/readiness.query.ts +1 -1
- package/packages/bundled-features/src/config/handlers/reencrypt.job.ts +23 -13
- package/packages/bundled-features/src/config/handlers/reset.write.ts +3 -3
- package/packages/bundled-features/src/config/handlers/selected-extensions.query.ts +1 -1
- package/packages/bundled-features/src/config/handlers/set.write.ts +22 -5
- package/packages/bundled-features/src/config/handlers/values.query.ts +1 -1
- package/packages/bundled-features/src/crypto-shredding/changes.json +12 -0
- package/packages/bundled-features/src/crypto-shredding/handlers/forget-subject.write.ts +9 -9
- package/packages/bundled-features/src/crypto-shredding/resolve-file-bytes-deleter.ts +3 -3
- package/packages/bundled-features/src/custom-fields/changes.json +6 -0
- package/packages/bundled-features/src/custom-fields/handlers/clear-custom-field.write.ts +1 -1
- package/packages/bundled-features/src/custom-fields/handlers/delete-system-field.write.ts +1 -1
- package/packages/bundled-features/src/custom-fields/handlers/delete-tenant-field.write.ts +1 -1
- package/packages/bundled-features/src/custom-fields/handlers/set-custom-field.write.ts +1 -1
- package/packages/bundled-features/src/custom-fields/index.ts +4 -0
- package/packages/bundled-features/src/custom-fields/lib/parse-serialized-field.ts +1 -1
- package/packages/bundled-features/src/data-retention/feature.ts +1 -1
- package/packages/bundled-features/src/data-retention/run-retention-cleanup.ts +12 -2
- package/packages/bundled-features/src/delivery/attempt-log.ts +1 -1
- package/packages/bundled-features/src/delivery/changes.json +12 -0
- package/packages/bundled-features/src/delivery/delivery-service.ts +6 -5
- package/packages/bundled-features/src/delivery/feature.ts +3 -2
- package/packages/bundled-features/src/delivery/index.ts +5 -0
- package/packages/bundled-features/src/delivery/jobs.ts +11 -11
- package/packages/bundled-features/src/delivery/system-channel-context.ts +33 -0
- package/packages/bundled-features/src/delivery/testing.ts +1 -1
- package/packages/bundled-features/src/document-ingest-foundation/append-missing-extract-event.ts +84 -0
- package/packages/bundled-features/src/document-ingest-foundation/changes.json +6 -0
- package/packages/bundled-features/src/document-ingest-foundation/events.ts +16 -1
- package/packages/bundled-features/src/document-ingest-foundation/index.ts +11 -0
- package/packages/bundled-features/src/feature-toggles/feature.ts +1 -0
- package/packages/bundled-features/src/feature-toggles/handlers/registered.query.ts +1 -1
- package/packages/bundled-features/src/feature-toggles/handlers/set.write.ts +1 -1
- package/packages/bundled-features/src/feature-toggles/toggle-sync-signal.ts +1 -1
- package/packages/bundled-features/src/file-derivatives/feature.ts +2 -2
- package/packages/bundled-features/src/file-derivatives/handlers/public-variant-by-file-ref.query.ts +5 -1
- package/packages/bundled-features/src/file-derivatives/handlers/public-variant.query.ts +7 -5
- package/packages/bundled-features/src/file-foundation/feature.ts +1 -1
- package/packages/bundled-features/src/file-foundation/read-file-ref-content.ts +7 -5
- package/packages/bundled-features/src/file-provider-s3/feature.ts +4 -1
- package/packages/bundled-features/src/files-tenant-data/handlers/sweep-orphaned-derivatives.job.ts +8 -8
- package/packages/bundled-features/src/form-draft/feature.ts +1 -1
- package/packages/bundled-features/src/form-draft/handlers/cleanup.job.ts +22 -12
- package/packages/bundled-features/src/form-draft/handlers/discard.write.ts +3 -3
- package/packages/bundled-features/src/form-draft/handlers/get.query.ts +1 -1
- package/packages/bundled-features/src/foundation-shared/config-helpers.ts +1 -1
- package/packages/bundled-features/src/host-routing/changes.json +6 -0
- package/packages/bundled-features/src/host-routing/validate-options.ts +5 -0
- package/packages/bundled-features/src/inbound-mail-foundation/events.ts +1 -1
- package/packages/bundled-features/src/inbound-mail-foundation/feature.ts +2 -1
- package/packages/bundled-features/src/inbound-mail-foundation/handlers/account-state.ts +2 -2
- package/packages/bundled-features/src/inbound-mail-foundation/handlers/connect-account.write.ts +1 -1
- package/packages/bundled-features/src/inbound-mail-foundation/handlers/disconnect-account.write.ts +1 -1
- package/packages/bundled-features/src/inbound-mail-foundation/handlers/ingest-message.write.ts +10 -10
- package/packages/bundled-features/src/inbound-mail-foundation/handlers/update-account.write.ts +1 -1
- package/packages/bundled-features/src/inbound-mail-foundation/projection.ts +1 -1
- package/packages/bundled-features/src/inbound-mail-foundation/watch-supervisor.ts +1 -1
- package/packages/bundled-features/src/inbound-provider-imap/feature.ts +4 -1
- package/packages/bundled-features/src/jobs/changes.json +6 -0
- package/packages/bundled-features/src/jobs/events.ts +1 -1
- package/packages/bundled-features/src/jobs/feature.ts +1 -0
- package/packages/bundled-features/src/jobs/handlers/consumer.write.ts +7 -4
- package/packages/bundled-features/src/jobs/handlers/projection-rebuild.job.ts +1 -1
- package/packages/bundled-features/src/jobs/handlers/reindex-entity.job.ts +11 -5
- package/packages/bundled-features/src/jobs/handlers/retention-cleanup.job.ts +1 -1
- package/packages/bundled-features/src/jobs/handlers/retry.write.ts +1 -1
- package/packages/bundled-features/src/jobs/handlers/stale-run-sweep.job.ts +1 -1
- package/packages/bundled-features/src/jobs/handlers/trigger.write.ts +2 -2
- package/packages/bundled-features/src/jobs/job-run-logger.ts +139 -90
- package/packages/bundled-features/src/ledger/web/index.ts +1 -1
- package/packages/bundled-features/src/legal-pages/README.md +1 -1
- package/packages/bundled-features/src/legal-pages/lib/boot-check.ts +12 -8
- package/packages/bundled-features/src/legal-pages/seed.ts +5 -2
- package/packages/bundled-features/src/mail-foundation/feature.ts +2 -2
- package/packages/bundled-features/src/mail-transport-smtp/changes.json +12 -0
- package/packages/bundled-features/src/mail-transport-smtp/config-keys.ts +1 -1
- package/packages/bundled-features/src/mail-transport-smtp/feature.ts +13 -12
- package/packages/bundled-features/src/managed-pages/changes.json +6 -0
- package/packages/bundled-features/src/managed-pages/constants.ts +1 -0
- package/packages/bundled-features/src/managed-pages/feature.ts +3 -1
- package/packages/bundled-features/src/managed-pages/index.ts +1 -0
- package/packages/bundled-features/src/managed-pages/seeding.ts +13 -8
- package/packages/bundled-features/src/notes-history/handlers/add-note.write.ts +2 -2
- package/packages/bundled-features/src/personal-access-tokens/feature.ts +2 -1
- package/packages/bundled-features/src/personal-access-tokens/handlers/create.write.ts +2 -2
- package/packages/bundled-features/src/personal-access-tokens/handlers/revoke.write.ts +1 -1
- package/packages/bundled-features/src/rate-limiting/handlers/status.query.ts +2 -2
- package/packages/bundled-features/src/readiness/handlers/status.query.ts +4 -1
- package/packages/bundled-features/src/renderer-foundation/api.ts +3 -3
- package/packages/bundled-features/src/secrets/announce-secret-change.ts +4 -4
- package/packages/bundled-features/src/secrets/changes.json +6 -0
- package/packages/bundled-features/src/secrets/feature.ts +9 -9
- package/packages/bundled-features/src/secrets/handlers/delete.write.ts +4 -3
- package/packages/bundled-features/src/secrets/handlers/rotate.job.ts +13 -8
- package/packages/bundled-features/src/secrets/handlers/set.write.ts +4 -3
- package/packages/bundled-features/src/secrets/secrets-context.ts +16 -6
- package/packages/bundled-features/src/secrets/write-gate.ts +10 -3
- package/packages/bundled-features/src/seo/feature.ts +1 -1
- package/packages/bundled-features/src/sessions/changes.json +19 -0
- package/packages/bundled-features/src/sessions/feature.ts +2 -1
- package/packages/bundled-features/src/sessions/handlers/cleanup.job.ts +2 -2
- package/packages/bundled-features/src/sessions/handlers/detail.query.ts +5 -2
- package/packages/bundled-features/src/sessions/handlers/list.query.ts +5 -2
- package/packages/bundled-features/src/sessions/handlers/mine.query.ts +5 -2
- package/packages/bundled-features/src/sessions/handlers/revoke-all-for-user.write.ts +3 -3
- package/packages/bundled-features/src/sessions/handlers/revoke-all-others.write.ts +1 -1
- package/packages/bundled-features/src/sessions/handlers/revoke.write.ts +1 -1
- package/packages/bundled-features/src/sessions/index.ts +1 -1
- package/packages/bundled-features/src/sessions/screens.ts +8 -4
- package/packages/bundled-features/src/sessions/session-callbacks.ts +1 -9
- package/packages/bundled-features/src/sessions/session-revoked-event.ts +1 -1
- package/packages/bundled-features/src/sessions/web/session-device-cell.tsx +10 -12
- package/packages/bundled-features/src/sessions/web/user-agent.ts +12 -0
- package/packages/bundled-features/src/shared/index.ts +15 -0
- package/packages/bundled-features/src/shared/purge-files-reaching-subject.ts +36 -4
- package/packages/bundled-features/src/shared/require-for-tenant.ts +7 -5
- package/packages/bundled-features/src/shared/run-in-sub-transaction.ts +5 -5
- package/packages/bundled-features/src/shared/stream-tenant-backfill.ts +201 -0
- package/packages/bundled-features/src/shared/stream-tenant-derived-state.ts +107 -0
- package/packages/bundled-features/src/step-dispatcher/changes.json +6 -0
- package/packages/bundled-features/src/step-dispatcher/deliver-dispatch-request.ts +17 -3
- package/packages/bundled-features/src/step-dispatcher/feature.ts +1 -1
- package/packages/bundled-features/src/step-dispatcher/mail-runner.ts +2 -1
- package/packages/bundled-features/src/subscription-dodo/plugin-methods.ts +1 -1
- package/packages/bundled-features/src/subscription-dodo/runtime.ts +7 -7
- package/packages/bundled-features/src/subscription-stripe/plugin-methods.ts +5 -3
- package/packages/bundled-features/src/subscription-stripe/runtime.ts +7 -7
- package/packages/bundled-features/src/tags/feature.ts +1 -0
- package/packages/bundled-features/src/template-resolver/api.ts +3 -3
- package/packages/bundled-features/src/template-resolver/changes.json +54 -0
- package/packages/bundled-features/src/template-resolver/document-ops.ts +20 -1
- package/packages/bundled-features/src/template-resolver/feature.ts +2 -2
- package/packages/bundled-features/src/template-resolver/handlers/bundle-import.ts +5 -4
- package/packages/bundled-features/src/template-resolver/handlers/copy-locale.write.ts +2 -2
- package/packages/bundled-features/src/template-resolver/handlers/export-bundle.query.ts +1 -1
- package/packages/bundled-features/src/template-resolver/handlers/layout-source.query.ts +36 -11
- package/packages/bundled-features/src/template-resolver/handlers/overview.query.ts +32 -7
- package/packages/bundled-features/src/template-resolver/handlers/patch-draft.write.ts +1 -1
- package/packages/bundled-features/src/template-resolver/handlers/send-test-shared.ts +1 -1
- package/packages/bundled-features/src/template-resolver/handlers/send-test-status.query.ts +22 -19
- package/packages/bundled-features/src/template-resolver/handlers/send-test.write.ts +2 -2
- package/packages/bundled-features/src/template-resolver/handlers/tenant-override-selection.ts +6 -2
- package/packages/bundled-features/src/template-resolver/handlers/tenant-overrides.query.ts +4 -2
- package/packages/bundled-features/src/template-resolver/handlers/usage.query.ts +1 -1
- package/packages/bundled-features/src/template-resolver/seeding.ts +22 -5
- package/packages/bundled-features/src/template-resolver/store-template-resource.ts +68 -19
- package/packages/bundled-features/src/template-resolver/template-resources.ts +4 -4
- package/packages/bundled-features/src/template-resolver/testing.ts +2 -2
- package/packages/bundled-features/src/template-resolver/web/document-insert-fields.tsx +222 -0
- package/packages/bundled-features/src/template-resolver/web/document-insert-model.ts +164 -0
- package/packages/bundled-features/src/template-resolver/web/document-insert-panel.tsx +115 -0
- package/packages/bundled-features/src/template-resolver/web/document-tiptap-bubble.tsx +177 -0
- package/packages/bundled-features/src/template-resolver/web/document-tiptap-content.tsx +38 -0
- package/packages/bundled-features/src/template-resolver/web/document-tiptap-context.ts +119 -0
- package/packages/bundled-features/src/template-resolver/web/document-tiptap-editor.tsx +51 -1098
- package/packages/bundled-features/src/template-resolver/web/document-tiptap-helpers.ts +161 -0
- package/packages/bundled-features/src/template-resolver/web/document-tiptap-layout.tsx +83 -0
- package/packages/bundled-features/src/template-resolver/web/document-tiptap-toolbar-groups.tsx +153 -0
- package/packages/bundled-features/src/template-resolver/web/document-tiptap-toolbar.tsx +182 -0
- package/packages/bundled-features/src/template-resolver/web/editor-handle.ts +18 -0
- package/packages/bundled-features/src/template-resolver/web/i18n.ts +6 -0
- package/packages/bundled-features/src/template-resolver/web/placeholder-line-editor.tsx +19 -6
- package/packages/bundled-features/src/template-resolver/web/qualified-names.ts +1 -0
- package/packages/bundled-features/src/template-resolver/web/use-document-tiptap-model.ts +138 -0
- package/packages/bundled-features/src/tenant/changes.json +19 -0
- package/packages/bundled-features/src/tenant/feature.ts +1 -0
- package/packages/bundled-features/src/tenant/handlers/cancel-invitation.write.ts +1 -1
- package/packages/bundled-features/src/tenant/handlers/memberships.query.ts +1 -1
- package/packages/bundled-features/src/tenant/handlers/remove-member.write.ts +2 -2
- package/packages/bundled-features/src/tenant/handlers/team-list.query.ts +3 -3
- package/packages/bundled-features/src/tenant/handlers/update-member-roles.write.ts +1 -1
- package/packages/bundled-features/src/tenant/index.ts +5 -0
- package/packages/bundled-features/src/tenant/invited-membership.ts +6 -1
- package/packages/bundled-features/src/tenant/schema/tenant.ts +4 -1
- package/packages/bundled-features/src/tenant/seeding.ts +65 -62
- package/packages/bundled-features/src/tenant/stream-tenant-backfill.ts +115 -0
- package/packages/bundled-features/src/tenant/testing.ts +77 -0
- package/packages/bundled-features/src/tenant-handover/events.ts +1 -1
- package/packages/bundled-features/src/tenant-handover/handlers/claim.write.ts +1 -1
- package/packages/bundled-features/src/tenant-lifecycle/changes.json +6 -0
- package/packages/bundled-features/src/tenant-lifecycle/feature.ts +5 -5
- package/packages/bundled-features/src/tenant-lifecycle/handlers/cancel-destruction.write.ts +22 -10
- package/packages/bundled-features/src/tenant-lifecycle/handlers/request-destruction.write.ts +22 -11
- package/packages/bundled-features/src/tenant-lifecycle/run-tenant-destroy.ts +23 -12
- package/packages/bundled-features/src/tenant-lifecycle/stages.ts +42 -4
- package/packages/bundled-features/src/tenant-lifecycle/testing.ts +9 -8
- package/packages/bundled-features/src/tier-engine/entity.ts +1 -1
- package/packages/bundled-features/src/tier-engine/feature.ts +8 -3
- package/packages/bundled-features/src/tier-engine/handlers/active-tier.query.ts +3 -3
- package/packages/bundled-features/src/tier-engine/handlers/get-tenant-tier.query.ts +7 -1
- package/packages/bundled-features/src/tier-engine/handlers/set-tenant-tier.write.ts +3 -3
- package/packages/bundled-features/src/user/db/queries/stream-tenant-backfill.ts +71 -97
- package/packages/bundled-features/src/user/feature.ts +1 -0
- package/packages/bundled-features/src/user/handlers/find-for-auth.query.ts +2 -2
- package/packages/bundled-features/src/user/handlers/update-roles.ts +2 -2
- package/packages/bundled-features/src/user/index.ts +2 -0
- package/packages/bundled-features/src/user/invited-global-roles.ts +6 -1
- package/packages/bundled-features/src/user/principal-status.ts +1 -1
- package/packages/bundled-features/src/user/seeding.ts +24 -6
- package/packages/bundled-features/src/user/testing.ts +22 -0
- package/packages/bundled-features/src/user-data-rights/COMPLIANCE.md +1 -1
- package/packages/bundled-features/src/user-data-rights/README.md +1 -1
- package/packages/bundled-features/src/user-data-rights/audit-download.ts +12 -2
- package/packages/bundled-features/src/user-data-rights/changes.json +36 -0
- package/packages/bundled-features/src/user-data-rights/feature.ts +30 -24
- package/packages/bundled-features/src/user-data-rights/handlers/confirm-deletion-by-token.write.ts +1 -1
- package/packages/bundled-features/src/user-data-rights/handlers/deletion-grace-period.ts +1 -1
- package/packages/bundled-features/src/user-data-rights/handlers/download-by-job.query.ts +2 -2
- package/packages/bundled-features/src/user-data-rights/handlers/download-by-token.query.ts +2 -2
- package/packages/bundled-features/src/user-data-rights/handlers/request-deletion.write.ts +1 -1
- package/packages/bundled-features/src/user-data-rights/handlers/restrict-account.write.ts +4 -4
- package/packages/bundled-features/src/user-data-rights/handlers/run-forget-cleanup.write.ts +12 -6
- package/packages/bundled-features/src/user-data-rights/index.ts +8 -1
- package/packages/bundled-features/src/user-data-rights/lib/mail-transport-resolver.ts +1 -1
- package/packages/bundled-features/src/user-data-rights/lib/storage-provider-resolver.ts +1 -1
- package/packages/bundled-features/src/user-data-rights/lib/update-user-lifecycle.ts +6 -1
- package/packages/bundled-features/src/user-data-rights/run-export-jobs.ts +8 -2
- package/packages/bundled-features/src/user-data-rights/run-forget-cleanup.ts +14 -3
- package/packages/bundled-features/src/user-data-rights/run-user-export.ts +11 -1
- package/packages/bundled-features/src/user-data-rights/web/constants.ts +16 -0
- package/packages/bundled-features/src/user-data-rights/web/index.ts +6 -0
- package/packages/bundled-features/src/user-profile/handlers/change-email.write.ts +8 -6
- package/packages/bundled-features/src/waitlist/changes.json +18 -0
- package/packages/bundled-features/src/waitlist/feature.ts +1 -0
- package/packages/bundled-features/src/waitlist/handlers/export-purge.write.ts +1 -1
- package/packages/bundled-features/src/waitlist/handlers/invite.write.ts +2 -2
- package/packages/bundled-features/src/waitlist/handlers/reject.write.ts +1 -1
- package/packages/bundled-features/src/waitlist/handlers/submit.write.ts +34 -10
- package/packages/bundled-features/src/waitlist/import.ts +23 -3
- package/packages/bundled-features/src/waitlist/legacy-migrate.ts +8 -2
- package/packages/bundled-features/src/waitlist/link-on-signup.ts +7 -1
- package/packages/bundled-features/src/waitlist/options.ts +2 -1
- package/packages/bundled-features/src/workflow-runner/changes.json +6 -0
- package/packages/bundled-features/src/workflow-runner/db/queries/due-runs.ts +1 -1
- package/packages/bundled-features/src/workflow-runner/event-subscriber.ts +4 -3
- package/packages/bundled-features/src/workflow-runner/event-trigger.ts +2 -1
- package/packages/bundled-features/src/workflow-runner/feature.ts +2 -2
- package/packages/bundled-features/src/workflow-runner/handlers/resume-run.write.ts +8 -8
- package/packages/bundled-features/src/workflow-runner/runner.ts +6 -4
- package/samples/apps/cap-billing-demo/src/feature.ts +19 -5
- package/samples/apps/config-demo/src/app/server.ts +1 -1
- package/samples/apps/styleguide/src/app/client.tsx +2 -0
- package/samples/apps/styleguide/src/app/seed.ts +6 -4
- package/samples/apps/styleguide/src/app/server.ts +6 -3
- package/samples/apps/styleguide/src/features/widgets/feature.ts +15 -4
- package/samples/apps/styleguide/src/features/workboard/feature.ts +185 -0
- package/samples/apps/styleguide/src/features/workboard/i18n.ts +27 -0
- package/samples/apps/styleguide/src/features/workboard/seed.ts +121 -0
- package/samples/apps/styleguide/src/features/workboard/web.ts +13 -0
- package/samples/apps/ui-walkthrough/src/features/rental/i18n.ts +2 -0
- package/samples/apps/ui-walkthrough/src/features/rental/screens.ts +9 -0
- package/samples/apps/use-all-bundled/bin/main.ts +2 -0
- package/samples/apps/use-all-bundled/feature-manifest.json +17 -1
- package/samples/apps/use-all-bundled/kumiko/schema.ts +2 -0
- package/samples/apps/use-all-bundled/kumiko.config.ts +2 -0
- package/samples/apps/use-all-bundled/package.json +2 -1
- package/samples/apps/use-all-bundled/src/app/dev-app-options.ts +2 -0
- package/samples/apps/use-all-bundled/src/app/notes-feature.ts +2 -0
- package/samples/apps/use-all-bundled/src/app/seed.ts +12 -2
- package/samples/apps/use-all-bundled/src/bundled-lists.ts +15 -0
- package/samples/apps/user-data-rights-demo/README.md +1 -1
- package/samples/apps/user-data-rights-demo/src/feature.ts +3 -2
- package/samples/recipes/api-worker-split/README.md +2 -1
- package/samples/recipes/api-worker-split/src/feature.ts +2 -1
- package/samples/recipes/cross-feature-events/README.md +5 -5
- package/samples/recipes/cross-feature-events/package.json +1 -1
- package/samples/recipes/cross-feature-events/src/feature.ts +4 -4
- package/samples/recipes/event-sourcing/README.md +5 -5
- package/samples/recipes/event-sourcing/package.json +1 -1
- package/samples/recipes/event-sourcing/src/feature.ts +15 -15
- package/samples/recipes/files-post-processing/README.md +1 -1
- package/samples/recipes/files-post-processing/package.json +1 -1
- package/samples/recipes/files-post-processing/src/feature.ts +6 -4
- package/samples/recipes/golden-path/src/feature.ts +2 -1
- package/samples/recipes/lane-routing/package.json +1 -1
- package/samples/recipes/legal-pages/README.md +2 -2
- package/samples/recipes/lifecycle-hooks/README.md +4 -0
- package/samples/recipes/lifecycle-hooks/src/feature.ts +26 -1
- package/samples/recipes/list-table-options/README.md +50 -0
- package/samples/recipes/list-table-options/package.json +11 -0
- package/samples/recipes/list-table-options/src/feature.ts +221 -0
- package/samples/recipes/managed-config/README.md +3 -3
- package/samples/recipes/pdf-audit-export/src/feature.ts +2 -1
- package/samples/recipes/search/README.md +1 -1
- package/samples/recipes/search/src/feature.ts +3 -3
- package/samples/recipes/secrets-demo/README.md +1 -1
- package/samples/recipes/secrets-demo/src/feature.ts +5 -2
- package/samples/recipes/state-machine/src/events.ts +4 -3
- package/samples/recipes/state-machine/src/reducer.ts +1 -1
- package/samples/recipes/tenant-isolation/README.md +1 -0
- package/samples/recipes/tenant-isolation/src/feature.ts +36 -0
- package/samples/recipes/workflow-engine/src/resume-loop.ts +4 -4
- package/samples/recipes/workflow-engine/src/workflow-runner.ts +2 -2
|
@@ -1,32 +1,20 @@
|
|
|
1
|
-
//
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
// against the empty SYSTEM stream. The raw UPDATE breaks as soon as an
|
|
7
|
-
// aggregate has BOTH a legacy stream and newer SYSTEM events
|
|
8
|
-
// (split stream — e.g. a skipOptimisticLock
|
|
9
|
-
// lifecycle write appended v1 on SYSTEM while v1..n live on the old
|
|
10
|
-
// tenant): retenanting then trips events_aggregate_version_uq.
|
|
11
|
-
//
|
|
12
|
-
// This tool merges per aggregate: all user events, ordered by global event
|
|
13
|
-
// id, are renumbered 1..n and retenanted to SYSTEM_TENANT_ID — two-phase
|
|
14
|
-
// version writes (negative interim values) dodge the unique index while the
|
|
15
|
-
// per-aggregate transaction is in flight. Snapshots of migrated aggregates
|
|
16
|
-
// are dropped (version numbering changed; the next snapshotting load
|
|
17
|
-
// recreates them); archived-stream markers move with the stream.
|
|
18
|
-
//
|
|
19
|
-
// Idempotent: the candidate query only matches aggregates that still have
|
|
20
|
-
// non-SYSTEM events. One failing aggregate does not abort the run — the
|
|
21
|
-
// rest of the estate migrates, failures are reported.
|
|
22
|
-
//
|
|
23
|
-
// After a run, rebuild the user projection so read_users.tenant_id reflects
|
|
24
|
-
// the stream move: rebuildProjection("user:projection:user-entity", ...) or
|
|
25
|
-
// the jobs:job:projection-rebuild job.
|
|
1
|
+
// Moves legacy user streams onto SYSTEM_TENANT_ID (user is a systemStream
|
|
2
|
+
// entity). After a run, rebuild the user projection so read_users.tenant_id
|
|
3
|
+
// reflects the move: rebuildProjection("user:projection:user-entity", ...) or
|
|
4
|
+
// the jobs:job:projection-rebuild job. `backfillUserStreamTenantsWithDerivedState`
|
|
5
|
+
// does the move, the old-bucket search cleanup, the rebuild and the reindex in one call.
|
|
26
6
|
|
|
27
7
|
import type { DbConnection } from "@cosmicdrift/kumiko-framework/db";
|
|
28
|
-
import {
|
|
29
|
-
import {
|
|
8
|
+
import type { Registry } from "@cosmicdrift/kumiko-framework/engine";
|
|
9
|
+
import type { SearchAdapter } from "@cosmicdrift/kumiko-framework/search";
|
|
10
|
+
import {
|
|
11
|
+
backfillAggregateStreamTenants,
|
|
12
|
+
createSearchBucketCleanup,
|
|
13
|
+
type DerivedStateMode,
|
|
14
|
+
rebuildAndReindex,
|
|
15
|
+
type StreamBackfillStepFailure,
|
|
16
|
+
stepFailures,
|
|
17
|
+
} from "../../../shared/index.ts";
|
|
30
18
|
|
|
31
19
|
export type UserStreamBackfillResult = {
|
|
32
20
|
readonly aggregatesMigrated: number;
|
|
@@ -34,80 +22,66 @@ export type UserStreamBackfillResult = {
|
|
|
34
22
|
readonly failed: ReadonlyArray<{ readonly aggregateId: string; readonly error: string }>;
|
|
35
23
|
};
|
|
36
24
|
|
|
37
|
-
|
|
25
|
+
const USER_AGGREGATE = "user";
|
|
26
|
+
const USER_PROJECTION = "user:projection:user-entity";
|
|
27
|
+
|
|
28
|
+
export function backfillUserStreamTenants(
|
|
38
29
|
db: DbConnection,
|
|
30
|
+
options: { readonly scanTenantIds?: readonly string[] } = {},
|
|
39
31
|
): Promise<UserStreamBackfillResult> {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
);
|
|
46
|
-
|
|
47
|
-
let aggregatesMigrated = 0;
|
|
48
|
-
let eventsMigrated = 0;
|
|
49
|
-
const failed: Array<{ aggregateId: string; error: string }> = [];
|
|
50
|
-
|
|
51
|
-
for (const { aggregate_id } of candidates) {
|
|
52
|
-
try {
|
|
53
|
-
eventsMigrated += await migrateAggregate(db, aggregate_id);
|
|
54
|
-
aggregatesMigrated++;
|
|
55
|
-
} catch (e) {
|
|
56
|
-
failed.push({
|
|
57
|
-
aggregateId: aggregate_id,
|
|
58
|
-
error: e instanceof Error ? e.message : String(e),
|
|
59
|
-
});
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
return { aggregatesMigrated, eventsMigrated, failed };
|
|
32
|
+
return backfillAggregateStreamTenants(db, {
|
|
33
|
+
aggregateType: USER_AGGREGATE,
|
|
34
|
+
target: { kind: "system" },
|
|
35
|
+
...options,
|
|
36
|
+
});
|
|
63
37
|
}
|
|
64
38
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
`SELECT "id" FROM "kumiko_events"
|
|
72
|
-
WHERE "aggregate_type" = 'user' AND "aggregate_id" = $1::uuid
|
|
73
|
-
ORDER BY "id" ASC
|
|
74
|
-
FOR UPDATE`,
|
|
75
|
-
[aggregateId],
|
|
76
|
-
);
|
|
77
|
-
|
|
78
|
-
// Negative interim versions — real versions are always >= 1, so
|
|
79
|
-
// nothing can collide with events_aggregate_version_uq mid-migration.
|
|
80
|
-
for (const [i, ev] of events.entries()) {
|
|
81
|
-
await raw.unsafe(
|
|
82
|
-
`UPDATE "kumiko_events" SET "tenant_id" = $1::uuid, "version" = $2 WHERE "id" = $3`,
|
|
83
|
-
[SYSTEM_TENANT_ID, -(i + 1), ev.id],
|
|
84
|
-
);
|
|
85
|
-
}
|
|
86
|
-
// Final contiguous 1..n.
|
|
87
|
-
for (const [i, ev] of events.entries()) {
|
|
88
|
-
await raw.unsafe(`UPDATE "kumiko_events" SET "version" = $1 WHERE "id" = $2`, [i + 1, ev.id]);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
// Version numbering changed → any snapshot of this aggregate is stale.
|
|
92
|
-
await raw.unsafe(`DELETE FROM "kumiko_snapshots" WHERE "aggregate_id" = $1::uuid`, [
|
|
93
|
-
aggregateId,
|
|
94
|
-
]);
|
|
95
|
-
|
|
96
|
-
// Archived markers key on (tenant_id, aggregate_id) — move them with the
|
|
97
|
-
// stream, keeping an existing SYSTEM marker if both exist.
|
|
98
|
-
await raw.unsafe(
|
|
99
|
-
`INSERT INTO "kumiko_archived_streams" ("tenant_id", "aggregate_id", "aggregate_type", "archived_at", "archived_by", "reason")
|
|
100
|
-
SELECT $1::uuid, "aggregate_id", "aggregate_type", "archived_at", "archived_by", "reason"
|
|
101
|
-
FROM "kumiko_archived_streams"
|
|
102
|
-
WHERE "aggregate_id" = $2::uuid AND "tenant_id" <> $1::uuid
|
|
103
|
-
ON CONFLICT DO NOTHING`,
|
|
104
|
-
[SYSTEM_TENANT_ID, aggregateId],
|
|
105
|
-
);
|
|
106
|
-
await raw.unsafe(
|
|
107
|
-
`DELETE FROM "kumiko_archived_streams" WHERE "aggregate_id" = $1::uuid AND "tenant_id" <> $2::uuid`,
|
|
108
|
-
[aggregateId, SYSTEM_TENANT_ID],
|
|
109
|
-
);
|
|
39
|
+
export type UserStreamBackfillWithDerivedStateResult = {
|
|
40
|
+
readonly streams: UserStreamBackfillResult;
|
|
41
|
+
readonly projectionsRebuilt: readonly string[];
|
|
42
|
+
readonly reindexedUsers: number;
|
|
43
|
+
readonly failures: readonly StreamBackfillStepFailure[];
|
|
44
|
+
};
|
|
110
45
|
|
|
111
|
-
|
|
46
|
+
export async function backfillUserStreamTenantsWithDerivedState(deps: {
|
|
47
|
+
readonly db: DbConnection;
|
|
48
|
+
readonly registry: Registry;
|
|
49
|
+
readonly searchAdapter?: SearchAdapter;
|
|
50
|
+
readonly derived?: DerivedStateMode;
|
|
51
|
+
readonly scanTenantIds?: readonly string[];
|
|
52
|
+
readonly onFirstCandidate?: () => Promise<"proceed" | "skip">;
|
|
53
|
+
}): Promise<UserStreamBackfillWithDerivedStateResult> {
|
|
54
|
+
const {
|
|
55
|
+
db,
|
|
56
|
+
registry,
|
|
57
|
+
searchAdapter,
|
|
58
|
+
derived = "if-moved",
|
|
59
|
+
scanTenantIds,
|
|
60
|
+
onFirstCandidate,
|
|
61
|
+
} = deps;
|
|
62
|
+
const searchCleanup = createSearchBucketCleanup(searchAdapter, USER_AGGREGATE);
|
|
63
|
+
const streams = await backfillAggregateStreamTenants(db, {
|
|
64
|
+
aggregateType: USER_AGGREGATE,
|
|
65
|
+
target: { kind: "system" },
|
|
66
|
+
beforeMove: searchCleanup.beforeMove,
|
|
67
|
+
...(scanTenantIds && { scanTenantIds }),
|
|
68
|
+
...(onFirstCandidate && { onFirstCandidate }),
|
|
69
|
+
});
|
|
70
|
+
const failures = stepFailures("user-streams", streams.failed);
|
|
71
|
+
if (streams.aggregatesMigrated === 0 && derived === "if-moved") {
|
|
72
|
+
return { streams, projectionsRebuilt: [], reindexedUsers: 0, failures };
|
|
73
|
+
}
|
|
74
|
+
const rebuilt = await rebuildAndReindex({
|
|
75
|
+
db,
|
|
76
|
+
registry,
|
|
77
|
+
...(searchAdapter && { searchAdapter }),
|
|
78
|
+
projections: [USER_PROJECTION],
|
|
79
|
+
searchEntity: USER_AGGREGATE,
|
|
112
80
|
});
|
|
81
|
+
return {
|
|
82
|
+
streams,
|
|
83
|
+
projectionsRebuilt: rebuilt.projectionsRebuilt,
|
|
84
|
+
reindexedUsers: rebuilt.reindexedRows,
|
|
85
|
+
failures: [...failures, ...rebuilt.failures],
|
|
86
|
+
};
|
|
113
87
|
}
|
|
@@ -19,6 +19,7 @@ import { userEditScreen, userListScreen } from "./screens.ts";
|
|
|
19
19
|
// Membership + tenant-specific roles live in the tenant feature.
|
|
20
20
|
export function createUserFeature(): FeatureDefinition {
|
|
21
21
|
return defineFeature("user", (r) => {
|
|
22
|
+
r.adoptsBundledLists();
|
|
22
23
|
r.describe(
|
|
23
24
|
"Manages the cross-tenant user identity: the `read_users` table holds each user's email, `displayName`, global `roles`, `emailVerified` flag, and lifecycle `status` (active / restricted / deletionRequested / deleted). Because users exist above any individual tenant, the feature runs with `r.systemScope()` \u2014 membership and tenant-specific roles live in the `tenant` feature instead. Add this feature whenever your app needs a persistent, tenant-agnostic user record that auth and GDPR pipelines can reference.",
|
|
24
25
|
);
|
|
@@ -6,14 +6,14 @@ import { userTable } from "../schema/user.ts";
|
|
|
6
6
|
|
|
7
7
|
// Privileged auth lookup: returns the full user row — including passwordHash —
|
|
8
8
|
// by email OR id (exactly one, enforced by the schema). Used by the auth
|
|
9
|
-
// features via ctx.queryAs(systemUser, ...).
|
|
9
|
+
// features via ctx.dispatch.queryAs(systemUser, ...).
|
|
10
10
|
//
|
|
11
11
|
// Access is system-only, NOT access.privileged: every query handler is
|
|
12
12
|
// reachable via POST /api/query, and "SystemAdmin" is an assignable app
|
|
13
13
|
// role — privileged would hand any SystemAdmin the raw passwordHash over
|
|
14
14
|
// HTTP. The "system" role can't be minted into a session (only
|
|
15
15
|
// createSystemUser() carries it), so system-only keeps this handler
|
|
16
|
-
// internal to ctx.queryAs(systemUser, ...) callers.
|
|
16
|
+
// internal to ctx.dispatch.queryAs(systemUser, ...) callers.
|
|
17
17
|
export const findForAuthQuery = defineQueryHandler({
|
|
18
18
|
name: "user:find-for-auth",
|
|
19
19
|
schema: z
|
|
@@ -164,7 +164,7 @@ export async function applyUserRolesUpdate(
|
|
|
164
164
|
|
|
165
165
|
const revoker = ctx.registry.getWriteHandler(REVOKE_ALL_SESSIONS_QN);
|
|
166
166
|
if (revoker) {
|
|
167
|
-
const revokeResult = await ctx.writeAs(
|
|
167
|
+
const revokeResult = await ctx.dispatch.writeAs(
|
|
168
168
|
createSystemUser(event.user.tenantId ?? SYSTEM_TENANT_ID),
|
|
169
169
|
REVOKE_ALL_SESSIONS_QN,
|
|
170
170
|
{
|
|
@@ -176,7 +176,7 @@ export async function applyUserRolesUpdate(
|
|
|
176
176
|
// skip: sessions feature not mounted — no live JWTs to revoke; role update
|
|
177
177
|
// still commits. Apps that mount user without sessions accept stale claims
|
|
178
178
|
// until JWT TTL.
|
|
179
|
-
ctx.log?.warn(
|
|
179
|
+
ctx.obs.log?.warn(
|
|
180
180
|
"user:update-roles: sessions revoke-all handler missing; role change commits without session invalidation",
|
|
181
181
|
{
|
|
182
182
|
userId: event.payload.id,
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
export { UserCommandSchemas } from "./command-schemas.ts";
|
|
2
2
|
export {
|
|
3
3
|
backfillUserStreamTenants,
|
|
4
|
+
backfillUserStreamTenantsWithDerivedState,
|
|
4
5
|
type UserStreamBackfillResult,
|
|
6
|
+
type UserStreamBackfillWithDerivedStateResult,
|
|
5
7
|
} from "./db/queries/stream-tenant-backfill.ts";
|
|
6
8
|
export { createUserFeature } from "./feature.ts";
|
|
7
9
|
export {
|
|
@@ -45,7 +45,12 @@ export async function grantInvitedGlobalRoles(
|
|
|
45
45
|
const updateResult = await userExecutor.update(
|
|
46
46
|
{ id: existing.id, version: existing.version, changes: { roles } },
|
|
47
47
|
createSystemUser(SYSTEM_TENANT_ID),
|
|
48
|
-
createTenantDb({
|
|
48
|
+
createTenantDb({
|
|
49
|
+
db,
|
|
50
|
+
tenantId: SYSTEM_TENANT_ID,
|
|
51
|
+
mode: "system",
|
|
52
|
+
reason: "global roles live on the tenant-agnostic user row in the system tenant",
|
|
53
|
+
}),
|
|
49
54
|
);
|
|
50
55
|
if (!updateResult.isSuccess) return updateResult;
|
|
51
56
|
return grantedGlobalRoles(roles);
|
|
@@ -39,7 +39,7 @@ export const principalStatusPlugin: PrincipalStatusPlugin = {
|
|
|
39
39
|
return isPrincipalRowBlocked(row) ? "blocked" : "active";
|
|
40
40
|
},
|
|
41
41
|
|
|
42
|
-
// ctx.queryAsMember's global-roles/timezone/locale source — same fields
|
|
42
|
+
// ctx.dispatch.queryAsMember's global-roles/timezone/locale source — same fields
|
|
43
43
|
// login mints a session from (see login.write.ts gateBuildSession).
|
|
44
44
|
async resolveProfile(userId, { db }): Promise<PrincipalProfile | null> {
|
|
45
45
|
const row = await fetchOne<{ roles: unknown; timezone: string | null; locale: string | null }>(
|
|
@@ -17,8 +17,11 @@ import {
|
|
|
17
17
|
type DbConnection,
|
|
18
18
|
fetchOne,
|
|
19
19
|
} from "@cosmicdrift/kumiko-framework/db";
|
|
20
|
-
import
|
|
21
|
-
|
|
20
|
+
import {
|
|
21
|
+
createSystemUser,
|
|
22
|
+
type SessionUser,
|
|
23
|
+
SYSTEM_TENANT_ID,
|
|
24
|
+
} from "@cosmicdrift/kumiko-framework/engine";
|
|
22
25
|
// kumiko-lint-ignore cross-feature-import shares the postSave-hooks fixture contract with tenant/seeding
|
|
23
26
|
import { fireEntityPostSave, type SeedTenantHooks } from "../tenant/seeding.ts";
|
|
24
27
|
import { userEntity, userTable } from "./schema/user.ts";
|
|
@@ -61,11 +64,16 @@ export async function seedUser(
|
|
|
61
64
|
// that opt in. Omit to keep today's hook-less behavior.
|
|
62
65
|
hooks?: SeedTenantHooks,
|
|
63
66
|
): Promise<{ id: string }> {
|
|
64
|
-
const by = options.by ??
|
|
67
|
+
const by = options.by ?? createSystemUser(SYSTEM_TENANT_ID);
|
|
65
68
|
// executor.create expects a TenantDb (with an .insert() API). Although
|
|
66
69
|
// User is tenant-agnostic (it has no tenant_id column), the runtime
|
|
67
70
|
// interface requires this wrapper.
|
|
68
|
-
const tdb = createTenantDb({
|
|
71
|
+
const tdb = createTenantDb({
|
|
72
|
+
db,
|
|
73
|
+
tenantId: by.tenantId,
|
|
74
|
+
mode: "system",
|
|
75
|
+
reason: "User is tenant-agnostic, seeding writes it through a system-mode handle",
|
|
76
|
+
});
|
|
69
77
|
|
|
70
78
|
const existing = await fetchOne(db, userTable, { email: options.email, isDeleted: false });
|
|
71
79
|
// @cast-boundary db-row: users.id is a uuid column (string), and fetchOne
|
|
@@ -111,7 +119,12 @@ export async function reconcileSeededUserEmailVerified(
|
|
|
111
119
|
// @cast-boundary db-row: users.id is a uuid column (string), and fetchOne
|
|
112
120
|
// returns the projection row as Record<string, unknown>.
|
|
113
121
|
const id = existingRow["id"] as string;
|
|
114
|
-
const tdb = createTenantDb({
|
|
122
|
+
const tdb = createTenantDb({
|
|
123
|
+
db,
|
|
124
|
+
tenantId: by.tenantId,
|
|
125
|
+
mode: "system",
|
|
126
|
+
reason: "User is tenant-agnostic, seeding writes it through a system-mode handle",
|
|
127
|
+
});
|
|
115
128
|
const result = await userExecutor.update(
|
|
116
129
|
{ id, version: existingRow["version"] as number, changes: { emailVerified: true } },
|
|
117
130
|
by,
|
|
@@ -157,7 +170,12 @@ export async function rewriteSeededUserEmail(
|
|
|
157
170
|
// skip: the stored blind index already matches, a rewrite would only append a no-op event.
|
|
158
171
|
if (indexed) return;
|
|
159
172
|
}
|
|
160
|
-
const tdb = createTenantDb({
|
|
173
|
+
const tdb = createTenantDb({
|
|
174
|
+
db,
|
|
175
|
+
tenantId: by.tenantId,
|
|
176
|
+
mode: "system",
|
|
177
|
+
reason: "User is tenant-agnostic, seeding writes it through a system-mode handle",
|
|
178
|
+
});
|
|
161
179
|
const result = await userExecutor.update({ id, version, changes: { email } }, by, tdb);
|
|
162
180
|
// version_conflict: a concurrent write already changed the row — fine for a seed helper.
|
|
163
181
|
// unique_violation: a duplicate row already holds the blind index; the repair
|
|
@@ -2,4 +2,26 @@
|
|
|
2
2
|
// reason: helpers are shared between tests and Dev-Server bootstrap,
|
|
3
3
|
// and /seeding is the stable home.
|
|
4
4
|
|
|
5
|
+
import type { DbConnection } from "@cosmicdrift/kumiko-framework/db";
|
|
6
|
+
import {
|
|
7
|
+
deleteRowViaEventStore,
|
|
8
|
+
updateRowViaEventStore,
|
|
9
|
+
} from "@cosmicdrift/kumiko-testing/helpers";
|
|
10
|
+
import { userEntity, userTable } from "./schema/user.ts";
|
|
11
|
+
|
|
5
12
|
export * from "./seeding.ts";
|
|
13
|
+
|
|
14
|
+
const userTarget = { table: userTable, entity: userEntity, entityName: "user" } as const;
|
|
15
|
+
|
|
16
|
+
// The user stream is systemStream, so the default system-tenant actor addresses it.
|
|
17
|
+
export function updateUserViaEventStore(
|
|
18
|
+
db: DbConnection,
|
|
19
|
+
userId: string,
|
|
20
|
+
changes: Readonly<Record<string, unknown>>,
|
|
21
|
+
): Promise<void> {
|
|
22
|
+
return updateRowViaEventStore(db, userTarget, { id: userId }, changes);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function softDeleteUserViaEventStore(db: DbConnection, userId: string): Promise<void> {
|
|
26
|
+
return deleteRowViaEventStore(db, userTarget, { id: userId });
|
|
27
|
+
}
|
|
@@ -18,7 +18,7 @@ Dieses Dokument bündelt die **technischen Fakten** zur DSGVO-Pipeline
|
|
|
18
18
|
|
|
19
19
|
| Artikel | Endpoint / Runner | Wer ruft auf | Was passiert |
|
|
20
20
|
|---------|-------------------|--------------|--------------|
|
|
21
|
-
| **Art. 15 (Auskunft, light)** | `user-data-rights:query:my-audit-log` | User | Liest eigene Framework-Events aus `kumiko_events` (account-weit über alle Memberships). Filterbar nach `eventType`, `aggregateType`, `from`/`to`. Domain-Entities ohne `ctx.
|
|
21
|
+
| **Art. 15 (Auskunft, light)** | `user-data-rights:query:my-audit-log` | User | Liest eigene Framework-Events aus `kumiko_events` (account-weit über alle Memberships). Filterbar nach `eventType`, `aggregateType`, `from`/`to`. Domain-Entities ohne `ctx.events.append` erscheinen NICHT — die kommen im Export-Bundle (Art. 20). |
|
|
22
22
|
| **Art. 15 + 20 (Auskunft + Portabilität)** | `user-data-rights:write:request-export` | User | Async Job → ZIP mit user-Profil + fileRefs + alle EXT_USER_DATA-Provider-Daten (cross-tenant) + signed Magic-Link per Email. Idempotent: nur 1 active Job pro User (`ACTIVE_JOB_CONSTRAINT`). |
|
|
23
23
|
| **Art. 15 + 20** | `GET /user-export/by-token` (interstitial) + `POST /user-export/by-token` (exchange) | Anonym (Magic-Link-Pfad) | Email-Link trägt den Token als URL-Fragment (`#token=`, nie an den Server gesendet, issue #1271); Interstitial-Script liest das Fragment client-seitig und tauscht es per POST-Body gegen die signed Storage-URL. Kein `?token=`-Query-Fallback (#1512) — Query-Param landet unveränderlich in Proxy-/Access-Logs. Multi-use innerhalb TTL. Audit: `lastUsedAt`, `lastUsedFromIp`, `lastUsedUserAgent`. |
|
|
24
24
|
| **Art. 15 + 20** | `GET /user-export/by-job/:jobId` | User (Session-Auth) | UI-Klick-Pfad. Cross-tenant-same-user: User in Tenant B kann Job aus Tenant A laden wenn er der Owner ist. |
|
|
@@ -44,7 +44,7 @@ Hook-Signaturen in `framework/src/engine/extensions/user-data.ts`:
|
|
|
44
44
|
|
|
45
45
|
| Article | Handler | Zweck |
|
|
46
46
|
|---------|---------|-------|
|
|
47
|
-
| Art. 15 | `user-data-rights:query:my-audit-log` | User sieht eigene Framework-Events (account-weit über alle Memberships). Domain-Entities ohne `ctx.
|
|
47
|
+
| Art. 15 | `user-data-rights:query:my-audit-log` | User sieht eigene Framework-Events (account-weit über alle Memberships). Domain-Entities ohne `ctx.events.append` erscheinen NICHT — nur im Export-Bundle. |
|
|
48
48
|
| Art. 15+20 | `user-data-rights:write:request-export` | Async Job → ZIP mit user-Profil + fileRefs + alle EXT_USER_DATA-Provider-Daten + signed Magic-Link |
|
|
49
49
|
| Art. 17 | `user-data-rights:write:request-deletion` | Soft-Delete mit Grace-Period, anschließend Cron anonymisiert User + cleant Domain-Entities |
|
|
50
50
|
| Art. 17 | `user-data-rights:write:cancel-deletion` | User widerruft seinen Forget-Request während der Grace |
|
|
@@ -53,7 +53,12 @@ export interface RecordDownloadUseArgs {
|
|
|
53
53
|
export async function recordDownloadUse(args: RecordDownloadUseArgs): Promise<void> {
|
|
54
54
|
const { db, tokenId, tokenVersion, tokenUseCount, tenantId, now, ip, userAgent } = args;
|
|
55
55
|
const executor = createSystemUser(tenantId);
|
|
56
|
-
const tdb = createTenantDb({
|
|
56
|
+
const tdb = createTenantDb({
|
|
57
|
+
db,
|
|
58
|
+
tenantId,
|
|
59
|
+
mode: "system",
|
|
60
|
+
reason: "download audit writes into the token's tenant, outside a request scope",
|
|
61
|
+
});
|
|
57
62
|
|
|
58
63
|
await tokenCrud
|
|
59
64
|
.update(
|
|
@@ -102,7 +107,12 @@ export interface RecordInvalidAttemptArgs {
|
|
|
102
107
|
export async function recordInvalidAttempt(args: RecordInvalidAttemptArgs): Promise<void> {
|
|
103
108
|
const { db, tenantId, now } = args;
|
|
104
109
|
const executor = createSystemUser(tenantId);
|
|
105
|
-
const tdb = createTenantDb({
|
|
110
|
+
const tdb = createTenantDb({
|
|
111
|
+
db,
|
|
112
|
+
tenantId,
|
|
113
|
+
mode: "system",
|
|
114
|
+
reason: "download audit writes into the token's tenant, outside a request scope",
|
|
115
|
+
});
|
|
106
116
|
await attemptCrud
|
|
107
117
|
.create(
|
|
108
118
|
{
|
|
@@ -1,4 +1,40 @@
|
|
|
1
1
|
[
|
|
2
|
+
{
|
|
3
|
+
"version": "0.390.0",
|
|
4
|
+
"type": "fix",
|
|
5
|
+
"title": "export cleanup stays quiet when metrics are off",
|
|
6
|
+
"detail": "The cleanup gauges are not registered without metrics, so the job logged \"Gauge not registered\" on every pass."
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
"version": "0.390.0",
|
|
10
|
+
"type": "fix",
|
|
11
|
+
"title": "User data export and forget cleanup run in system scope",
|
|
12
|
+
"detail": "runUserExport and runForgetCleanup walk every tenant of a user, so they enter the system scope themselves instead of depending on the caller's scope. A direct call outside a job no longer exports or erases nothing under row level security \"on\"."
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"version": "0.390.0",
|
|
16
|
+
"type": "improvement",
|
|
17
|
+
"title": "QN constants for the forget-cleanup job and the download-attempt list screen",
|
|
18
|
+
"detail": "UserDataRightsJobs.runForgetCleanup (\"user-data-rights:job:run-forget-cleanup\") and UserDataRightsScreens.downloadAttemptList (\"user-data-rights:screen:download-attempt-list\") are exported next to the existing QN constants, from the feature barrel and from user-data-rights/web. Use the screen constant in an app's r.nav instead of the literal string."
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"version": "0.390.0",
|
|
22
|
+
"type": "improvement",
|
|
23
|
+
"title": "QN constants for the export job and the export job list screen",
|
|
24
|
+
"detail": "UserDataRightsJobs.runExportJobs (\"user-data-rights:job:run-export-jobs\") and UserDataRightsScreens.exportJobList (\"user-data-rights:screen:export-job-list\") are exported next to UserDataRightsQueries and UserDataRightsHandlers, from the feature barrel and from user-data-rights/web. Use the screen constant in an app's r.nav instead of the literal string."
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"version": "0.389.0",
|
|
28
|
+
"type": "improvement",
|
|
29
|
+
"title": "USER_DATA_RIGHTS_FEATURE is exported from the barrel",
|
|
30
|
+
"detail": "The feature name constant that lived in web/constants.ts is now part of the public barrel."
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"version": "0.389.0",
|
|
34
|
+
"type": "improvement",
|
|
35
|
+
"title": "Complete, exported handler name constants",
|
|
36
|
+
"detail": "UserDataRightsHandlers now covers all eight write handlers and UserDataRightsQueries all five explicit query handlers, and both are exported from user-data-rights and user-data-rights/web. A test compares them with the feature's registered handlers."
|
|
37
|
+
},
|
|
2
38
|
{
|
|
3
39
|
"version": "0.384.0",
|
|
4
40
|
"type": "fix",
|
|
@@ -12,8 +12,8 @@ import {
|
|
|
12
12
|
} from "@cosmicdrift/kumiko-framework/engine";
|
|
13
13
|
import { createFallbackLogger } from "@cosmicdrift/kumiko-framework/logging";
|
|
14
14
|
import {
|
|
15
|
-
createMetricsHandle,
|
|
16
15
|
createNoopMetricsHandle,
|
|
16
|
+
createSafeMetricsHandle,
|
|
17
17
|
} from "@cosmicdrift/kumiko-framework/observability";
|
|
18
18
|
import { isPlainObject } from "@cosmicdrift/kumiko-types/type-guards";
|
|
19
19
|
import { createConfigAccessor } from "../config/index.ts";
|
|
@@ -62,6 +62,7 @@ import {
|
|
|
62
62
|
type SendExportReadyEmailFn,
|
|
63
63
|
} from "./run-export-jobs.ts";
|
|
64
64
|
import {
|
|
65
|
+
FORGET_CLEANUP_HANDLER_NAME,
|
|
65
66
|
runForgetCleanup,
|
|
66
67
|
type SendDeletionExecutedEmailFn,
|
|
67
68
|
sanitizeReasonForLog,
|
|
@@ -80,6 +81,7 @@ import {
|
|
|
80
81
|
STATUS_OPTION_KEY_PREFIX,
|
|
81
82
|
USER_ME_QUERY,
|
|
82
83
|
UserDataRightsHandlers,
|
|
84
|
+
UserDataRightsScreens,
|
|
83
85
|
} from "./web/constants.ts";
|
|
84
86
|
import { USER_DATA_RIGHTS_I18N } from "./web/i18n.ts";
|
|
85
87
|
|
|
@@ -188,6 +190,7 @@ export function createUserDataRightsFeature(opts: UserDataRightsOptions = {}): F
|
|
|
188
190
|
let warnedMissingMailDelivery = false;
|
|
189
191
|
const showDeletion = opts.privacyCenterShowDeletion ?? true;
|
|
190
192
|
return defineFeature("user-data-rights", (r) => {
|
|
193
|
+
r.adoptsBundledLists();
|
|
191
194
|
r.describe(
|
|
192
195
|
'Implements GDPR Art. 15 (access / `my-audit-log` query), Art. 17 (erasure / `request-deletion` + `cancel-deletion`, plus the anonymous email-verified `request-deletion-by-email` + `confirm-deletion-by-token` flow for lockout-safe self-service, + cron cleanup with grace period), Art. 18 (restriction / `restrict-account` + `lift-restriction`), and Art. 20 (portability / async `request-export` \u2192 ZIP via `file-foundation`, Magic-Link download) as first-class HTTP handlers and cron jobs. Each domain feature opts in by calling `r.useExtension(EXT_USER_DATA, "<entity>", { export, delete })` \u2014 the feature then orchestrates the export and forget pipelines across all registered hooks automatically. When `mail-foundation` and a `mail-transport-*` are mounted, it also sends the four GDPR notifications (export ready/failed, deletion requested/executed) itself with no app callback code, rendered in each recipient’s locale. Requires `user`, `data-retention`, `compliance-profiles`, and `sessions`.',
|
|
193
196
|
);
|
|
@@ -333,7 +336,7 @@ export function createUserDataRightsFeature(opts: UserDataRightsOptions = {}): F
|
|
|
333
336
|
id: "export-job-list",
|
|
334
337
|
label: "user-data-rights:nav.exportJobs",
|
|
335
338
|
icon: "download",
|
|
336
|
-
screen:
|
|
339
|
+
screen: UserDataRightsScreens.exportJobList,
|
|
337
340
|
order: 25,
|
|
338
341
|
access: { roles: ["SystemAdmin"] },
|
|
339
342
|
});
|
|
@@ -619,11 +622,12 @@ export function createUserDataRightsFeature(opts: UserDataRightsOptions = {}): F
|
|
|
619
622
|
const exportDb =
|
|
620
623
|
ctx.db.unsafeRaw() as import("@cosmicdrift/kumiko-framework/db").DbConnection; // @cast-boundary db-operator — jobs never run inside a DbTx
|
|
621
624
|
const exportRegistry = ctx.registry;
|
|
622
|
-
// JobContext carries ctx.meter (raw), not ctx.metrics — that bound
|
|
625
|
+
// JobContext carries ctx.meter (raw), not ctx.obs.metrics — that bound
|
|
623
626
|
// handle only exists on HandlerContext (built per write/query call
|
|
624
|
-
// in dispatch-shared.ts). Build the
|
|
625
|
-
|
|
626
|
-
|
|
627
|
+
// in dispatch-shared.ts). Build the handle explicitly; the safe variant is a no-op when
|
|
628
|
+
// metrics are off and the gauges were never registered on the meter.
|
|
629
|
+
const exportMetrics = ctx.obs.meter
|
|
630
|
+
? createSafeMetricsHandle(ctx.obs.meter, "user-data-rights")
|
|
627
631
|
: createNoopMetricsHandle();
|
|
628
632
|
|
|
629
633
|
// Without explicit send*Email options, a mounted mail transport sends the
|
|
@@ -633,7 +637,7 @@ export function createUserDataRightsFeature(opts: UserDataRightsOptions = {}): F
|
|
|
633
637
|
// The cron runs across tenants, so each mail needs a notify function
|
|
634
638
|
// bound to the recipient's tenant for template overrides and channel
|
|
635
639
|
// configuration.
|
|
636
|
-
const notifyFactory = ctx._notifyFactory;
|
|
640
|
+
const notifyFactory = ctx.services._notifyFactory;
|
|
637
641
|
const exportNotifyFor =
|
|
638
642
|
notifyFactory !== undefined && isGdprMailDeliveryAvailable(exportRegistry)
|
|
639
643
|
? (tenantId: TenantId) => notifyFactory(createSystemUser(tenantId), tenantId)
|
|
@@ -670,8 +674,8 @@ export function createUserDataRightsFeature(opts: UserDataRightsOptions = {}): F
|
|
|
670
674
|
// createFileProviderForTenant throws and every export lands on failed.
|
|
671
675
|
buildStorageProvider: makeTenantStorageProviderResolver({
|
|
672
676
|
registry: exportRegistry,
|
|
673
|
-
configResolver: ctx.configResolver,
|
|
674
|
-
secrets: ctx.secrets,
|
|
677
|
+
configResolver: ctx.services.configResolver,
|
|
678
|
+
secrets: ctx.services.secrets,
|
|
675
679
|
db: exportDb,
|
|
676
680
|
userId: exportUserId,
|
|
677
681
|
handlerName: "user-data-rights:run-export-jobs",
|
|
@@ -685,8 +689,8 @@ export function createUserDataRightsFeature(opts: UserDataRightsOptions = {}): F
|
|
|
685
689
|
...(opts.appExportDownloadUrl !== undefined && {
|
|
686
690
|
appExportDownloadUrl: opts.appExportDownloadUrl,
|
|
687
691
|
}),
|
|
688
|
-
escapeHatchAuditSink: ctx._escapeHatchAuditSink,
|
|
689
|
-
escapeHatchAuditLog: ctx.log,
|
|
692
|
+
escapeHatchAuditSink: ctx.services._escapeHatchAuditSink,
|
|
693
|
+
escapeHatchAuditLog: ctx.obs.log,
|
|
690
694
|
actor: ctx.systemUser.id,
|
|
691
695
|
metrics: exportMetrics,
|
|
692
696
|
});
|
|
@@ -715,7 +719,7 @@ export function createUserDataRightsFeature(opts: UserDataRightsOptions = {}): F
|
|
|
715
719
|
const forgetRegistry = ctx.registry;
|
|
716
720
|
const tenantModel = await resolveAppTenantModel({
|
|
717
721
|
registry: forgetRegistry,
|
|
718
|
-
configResolver: ctx.configResolver,
|
|
722
|
+
configResolver: ctx.services.configResolver,
|
|
719
723
|
db: forgetDb,
|
|
720
724
|
userId: forgetUserId,
|
|
721
725
|
});
|
|
@@ -723,7 +727,7 @@ export function createUserDataRightsFeature(opts: UserDataRightsOptions = {}): F
|
|
|
723
727
|
// Without an app callback the default mail goes out when an email channel or a
|
|
724
728
|
// mail transport, plus a mail renderer, are mounted. The user is already erased
|
|
725
729
|
// here, so it bypasses the delivery log: an attempt row would be new personal data.
|
|
726
|
-
const forgetConfigResolver = ctx.configResolver;
|
|
730
|
+
const forgetConfigResolver = ctx.services.configResolver;
|
|
727
731
|
const sendDeletionExecutedEmail =
|
|
728
732
|
opts.sendDeletionExecutedEmail ??
|
|
729
733
|
((isGdprMailDeliveryAvailable(forgetRegistry) ||
|
|
@@ -733,14 +737,14 @@ export function createUserDataRightsFeature(opts: UserDataRightsOptions = {}): F
|
|
|
733
737
|
{
|
|
734
738
|
registry: forgetRegistry,
|
|
735
739
|
db: forgetDb,
|
|
736
|
-
...(ctx.secrets !== undefined && { secrets: ctx.secrets }),
|
|
740
|
+
...(ctx.services.secrets !== undefined && { secrets: ctx.services.secrets }),
|
|
737
741
|
resolveTransport: makeTenantMailTransportResolver({
|
|
738
742
|
registry: forgetRegistry,
|
|
739
743
|
configResolver: forgetConfigResolver,
|
|
740
|
-
secrets: ctx.secrets,
|
|
744
|
+
secrets: ctx.services.secrets,
|
|
741
745
|
db: forgetDb,
|
|
742
746
|
userId: forgetUserId,
|
|
743
|
-
handlerName:
|
|
747
|
+
handlerName: FORGET_CLEANUP_HANDLER_NAME,
|
|
744
748
|
}),
|
|
745
749
|
configFor: (tenantId) =>
|
|
746
750
|
forgetConfigResolver &&
|
|
@@ -761,29 +765,31 @@ export function createUserDataRightsFeature(opts: UserDataRightsOptions = {}): F
|
|
|
761
765
|
registry: forgetRegistry,
|
|
762
766
|
now: T.Now.instant(),
|
|
763
767
|
tenantModel,
|
|
764
|
-
...(ctx.searchAdapter !== undefined && {
|
|
768
|
+
...(ctx.services.searchAdapter !== undefined && {
|
|
769
|
+
searchAdapter: ctx.services.searchAdapter,
|
|
770
|
+
}),
|
|
765
771
|
// Same per-tenant provider resolution as the export cron — forget
|
|
766
772
|
// deletes binaries from the store upload + export use.
|
|
767
773
|
buildStorageProvider: makeTenantStorageProviderResolver({
|
|
768
774
|
registry: forgetRegistry,
|
|
769
|
-
configResolver: ctx.configResolver,
|
|
770
|
-
secrets: ctx.secrets,
|
|
775
|
+
configResolver: ctx.services.configResolver,
|
|
776
|
+
secrets: ctx.services.secrets,
|
|
771
777
|
db: forgetDb,
|
|
772
778
|
userId: forgetUserId,
|
|
773
|
-
handlerName:
|
|
779
|
+
handlerName: FORGET_CLEANUP_HANDLER_NAME,
|
|
774
780
|
}),
|
|
775
781
|
...(sendDeletionExecutedEmail && { sendDeletionExecutedEmail }),
|
|
776
|
-
escapeHatchAuditSink: ctx._escapeHatchAuditSink,
|
|
777
|
-
escapeHatchAuditLog: ctx.log,
|
|
782
|
+
escapeHatchAuditSink: ctx.services._escapeHatchAuditSink,
|
|
783
|
+
escapeHatchAuditLog: ctx.obs.log,
|
|
778
784
|
actor: ctx.systemUser.id,
|
|
779
785
|
});
|
|
780
786
|
|
|
781
787
|
// Persist each incomplete report on the job-run log. The write
|
|
782
788
|
// handler returns incomplete[] in its response; the cron path used to
|
|
783
789
|
// discard the array (only a console.warn for rolledBack cases).
|
|
784
|
-
// ctx.log feeds createJobRunLogger → store_job_run_logs.
|
|
790
|
+
// ctx.obs.log feeds createJobRunLogger → store_job_run_logs.
|
|
785
791
|
for (const entry of forgetResult.incomplete) {
|
|
786
|
-
ctx.log?.warn?.(
|
|
792
|
+
ctx.obs.log?.warn?.(
|
|
787
793
|
`[user-data-rights:run-forget-cleanup] incomplete hook ` +
|
|
788
794
|
`userId=${entry.userId} tenantId=${entry.tenantId} ` +
|
|
789
795
|
`entityName=${entry.entityName} rolledBack=${entry.rolledBack} ` +
|
package/packages/bundled-features/src/user-data-rights/handlers/confirm-deletion-by-token.write.ts
CHANGED
|
@@ -59,7 +59,7 @@ export function createConfirmDeletionByTokenHandler(opts: ConfirmDeletionByToken
|
|
|
59
59
|
access: { roles: ["anonymous", "Member", "User", "TenantAdmin", "SystemAdmin"] },
|
|
60
60
|
escapeHatch: {
|
|
61
61
|
reason:
|
|
62
|
-
"resolveGracePeriod reads the tenant compliance profile via ctx.queryAs(SYSTEM, " +
|
|
62
|
+
"resolveGracePeriod reads the tenant compliance profile via ctx.dispatch.queryAs(SYSTEM, " +
|
|
63
63
|
"...) to compute the grace period end — the anonymous token holder has no read access " +
|
|
64
64
|
"to that tenant-config projection. startDeletionGracePeriod also appends the user " +
|
|
65
65
|
"lifecycle event on the SYSTEM_TENANT_ID user stream.",
|
|
@@ -29,7 +29,7 @@ export async function resolveGracePeriod(
|
|
|
29
29
|
reason:
|
|
30
30
|
"reads the tenant compliance profile via queryAs(SYSTEM, ...) to compute the grace period end; the calling user's own identity has no read access to that tenant-config projection",
|
|
31
31
|
});
|
|
32
|
-
const profile = (await ctx.queryAs(
|
|
32
|
+
const profile = (await ctx.dispatch.queryAs(
|
|
33
33
|
createSystemUser(tenantId),
|
|
34
34
|
"compliance-profiles:query:for-tenant",
|
|
35
35
|
{},
|
|
@@ -149,8 +149,8 @@ export const downloadByJobQuery = defineQueryHandler({
|
|
|
149
149
|
// can differ from query.user.tenantId).
|
|
150
150
|
const provider = await makeTenantStorageProviderResolver({
|
|
151
151
|
registry: ctx.registry,
|
|
152
|
-
configResolver: ctx.configResolver,
|
|
153
|
-
secrets: ctx.secrets,
|
|
152
|
+
configResolver: ctx.services.configResolver,
|
|
153
|
+
secrets: ctx.services.secrets,
|
|
154
154
|
// @cast-boundary db-runner — helpers use only the query API that
|
|
155
155
|
// DbConnection and DbTx share.
|
|
156
156
|
db: runner as import("@cosmicdrift/kumiko-types/db-connection").DbConnection,
|