@cosmicdrift/kumiko-samples 0.385.0 → 0.387.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -57
- package/README.md +1 -1
- package/package.json +2 -2
- package/packages/bundled-features/package.json +2 -2
- package/packages/bundled-features/src/agent-tools/tool-catalog.ts +1 -1
- package/packages/bundled-features/src/agent-tools/tool-dispatch.ts +0 -2
- package/packages/bundled-features/src/audit/screens.ts +1 -1
- package/packages/bundled-features/src/auth-email-password/auth-user-row.ts +10 -10
- package/packages/bundled-features/src/auth-email-password/feature.ts +6 -6
- package/packages/bundled-features/src/auth-email-password/handlers/change-password.write.ts +3 -3
- package/packages/bundled-features/src/auth-email-password/handlers/confirm-token-flow.ts +5 -5
- package/packages/bundled-features/src/auth-email-password/handlers/invite-accept-with-login.write.ts +1 -1
- package/packages/bundled-features/src/auth-email-password/handlers/invite-accept.write.ts +18 -18
- package/packages/bundled-features/src/auth-email-password/handlers/invite-create.write.ts +12 -12
- package/packages/bundled-features/src/auth-email-password/handlers/invite-info.query.ts +1 -1
- package/packages/bundled-features/src/auth-email-password/handlers/invite-signup-complete.write.ts +24 -26
- package/packages/bundled-features/src/auth-email-password/handlers/login.write.ts +1 -1
- package/packages/bundled-features/src/auth-email-password/handlers/self-registration-status.query.ts +1 -1
- package/packages/bundled-features/src/auth-email-password/handlers/signup-confirm.write.ts +34 -37
- package/packages/bundled-features/src/auth-email-password/handlers/signup-request.write.ts +6 -7
- package/packages/bundled-features/src/auth-email-password/handlers/switch-tenant-mfa-gate.write.ts +1 -5
- package/packages/bundled-features/src/auth-email-password/index.ts +5 -5
- package/packages/bundled-features/src/auth-email-password/lockout-store.ts +1 -1
- package/packages/bundled-features/src/auth-email-password/seeding.ts +63 -66
- package/packages/bundled-features/src/auth-email-password/signup-token-store.ts +8 -8
- package/packages/bundled-features/src/auth-email-password/testing.ts +3 -3
- package/packages/bundled-features/src/auth-email-password/web/auth-client.ts +57 -57
- package/packages/bundled-features/src/auth-email-password/web/auth-form-primitives.tsx +14 -14
- package/packages/bundled-features/src/auth-email-password/web/auth-gate.tsx +15 -16
- package/packages/bundled-features/src/auth-email-password/web/client-plugin.ts +11 -12
- package/packages/bundled-features/src/auth-email-password/web/confirm-account-unlock-screen.tsx +1 -1
- package/packages/bundled-features/src/auth-email-password/web/constants.ts +3 -3
- package/packages/bundled-features/src/auth-email-password/web/default-topbar-actions.tsx +14 -14
- package/packages/bundled-features/src/auth-email-password/web/forgot-password-screen.tsx +11 -11
- package/packages/bundled-features/src/auth-email-password/web/index.ts +5 -5
- package/packages/bundled-features/src/auth-email-password/web/invite-accept-screen.tsx +17 -17
- package/packages/bundled-features/src/auth-email-password/web/login-screen.tsx +3 -4
- package/packages/bundled-features/src/auth-email-password/web/reset-password-screen.tsx +16 -17
- package/packages/bundled-features/src/auth-email-password/web/session.tsx +34 -34
- package/packages/bundled-features/src/auth-email-password/web/signup-complete-screen.tsx +3 -3
- package/packages/bundled-features/src/auth-email-password/web/signup-screen.tsx +14 -14
- package/packages/bundled-features/src/auth-email-password/web/tenant-switcher.tsx +26 -27
- package/packages/bundled-features/src/auth-email-password/web/use-shell-user.ts +12 -13
- package/packages/bundled-features/src/auth-email-password/web/user-menu.tsx +17 -18
- package/packages/bundled-features/src/auth-email-password/web/verify-email-screen.tsx +11 -12
- package/packages/bundled-features/src/auth-foundation/boot-checks.ts +4 -4
- package/packages/bundled-features/src/auth-foundation/resolve-anonymous-access.ts +4 -4
- package/packages/bundled-features/src/auth-foundation/types.ts +2 -2
- package/packages/bundled-features/src/auth-mfa/handlers/disable.write.ts +3 -3
- package/packages/bundled-features/src/auth-mfa/handlers/enable-confirm-preauth.write.ts +4 -4
- package/packages/bundled-features/src/auth-mfa/handlers/enable-confirm.write.ts +2 -2
- package/packages/bundled-features/src/auth-mfa/handlers/enable-start-preauth.write.ts +1 -1
- package/packages/bundled-features/src/auth-mfa/handlers/reencrypt.job.ts +1 -1
- package/packages/bundled-features/src/auth-mfa/handlers/regenerate-recovery.write.ts +5 -5
- package/packages/bundled-features/src/auth-mfa/handlers/verify.write.ts +1 -1
- package/packages/bundled-features/src/auth-mfa/token-secrets.ts +1 -1
- package/packages/bundled-features/src/auth-mfa/web/client-plugin.ts +2 -2
- package/packages/bundled-features/src/auth-mfa/web/i18n.ts +3 -3
- package/packages/bundled-features/src/auth-mfa/web/index.ts +4 -4
- package/packages/bundled-features/src/auth-mfa/web/mfa-client.ts +17 -16
- package/packages/bundled-features/src/auth-mfa/web/mfa-verify-screen.tsx +6 -6
- package/packages/bundled-features/src/billing-foundation/aggregate-id.ts +10 -11
- package/packages/bundled-features/src/billing-foundation/entities.ts +27 -27
- package/packages/bundled-features/src/billing-foundation/events.ts +22 -21
- package/packages/bundled-features/src/billing-foundation/feature.ts +42 -43
- package/packages/bundled-features/src/billing-foundation/get-subscription-for-tenant.ts +3 -5
- package/packages/bundled-features/src/billing-foundation/handlers/create-checkout-session.write.ts +18 -17
- package/packages/bundled-features/src/billing-foundation/handlers/create-portal-session.write.ts +11 -12
- package/packages/bundled-features/src/billing-foundation/handlers/list-subscriptions.query.ts +4 -4
- package/packages/bundled-features/src/billing-foundation/handlers/process-event.write.ts +20 -20
- package/packages/bundled-features/src/billing-foundation/projection.ts +38 -37
- package/packages/bundled-features/src/billing-foundation/subscription-tier-sync.ts +3 -3
- package/packages/bundled-features/src/billing-foundation/tenant-destroy-hook.ts +7 -8
- package/packages/bundled-features/src/billing-foundation/types.ts +64 -65
- package/packages/bundled-features/src/billing-foundation/web/billing-plans-panel.tsx +4 -4
- package/packages/bundled-features/src/billing-foundation/webhook-handler.ts +1 -1
- package/packages/bundled-features/src/cap-counter/aggregate-id.ts +8 -9
- package/packages/bundled-features/src/cap-counter/constants.ts +11 -12
- package/packages/bundled-features/src/cap-counter/enforce-cap.ts +64 -67
- package/packages/bundled-features/src/cap-counter/entity.ts +29 -29
- package/packages/bundled-features/src/cap-counter/feature.ts +34 -35
- package/packages/bundled-features/src/cap-counter/handlers/increment-rolling.write.ts +31 -31
- package/packages/bundled-features/src/cap-counter/handlers/mark-soft-warned.write.ts +4 -5
- package/packages/bundled-features/src/cap-counter/stock-cap-guard.ts +1 -1
- package/packages/bundled-features/src/cap-counter/with-cap-enforcement.ts +3 -5
- package/packages/bundled-features/src/cap-overview/handlers/caps-usage.query.ts +1 -3
- package/packages/bundled-features/src/cap-overview/handlers/tenant-caps-list.query.ts +1 -1
- package/packages/bundled-features/src/channel-email/smtp-transport.ts +34 -31
- package/packages/bundled-features/src/channel-in-app/handlers/unread-count.query.ts +3 -4
- package/packages/bundled-features/src/compliance-profiles/feature.ts +15 -16
- package/packages/bundled-features/src/compliance-profiles/handlers/for-tenant.query.ts +3 -6
- package/packages/bundled-features/src/compliance-profiles/handlers/list-profiles.query.ts +5 -5
- package/packages/bundled-features/src/compliance-profiles/handlers/needs-profile.query.ts +4 -4
- package/packages/bundled-features/src/compliance-profiles/handlers/set-profile.write.ts +13 -14
- package/packages/bundled-features/src/compliance-profiles/handlers/sub-processors.query.ts +9 -11
- package/packages/bundled-features/src/compliance-profiles/resolve-for-tenant.ts +7 -7
- package/packages/bundled-features/src/compliance-profiles/schema/profile-selection.ts +18 -23
- package/packages/bundled-features/src/compliance-profiles/seeding.ts +14 -15
- package/packages/bundled-features/src/compliance-profiles-ops/handlers/tenants-missing-profile.query.ts +3 -3
- package/packages/bundled-features/src/compliance-profiles-ops/index.ts +2 -2
- package/packages/bundled-features/src/config/handlers/readiness.query.ts +7 -7
- package/packages/bundled-features/src/config/handlers/reencrypt.job.ts +4 -5
- package/packages/bundled-features/src/config/handlers/set.write.ts +4 -4
- package/packages/bundled-features/src/config/resolver.ts +4 -4
- package/packages/bundled-features/src/config/table.ts +10 -10
- package/packages/bundled-features/src/config/write-helpers.ts +1 -1
- package/packages/bundled-features/src/crypto-shredding/handlers/forget-subject.write.ts +13 -12
- package/packages/bundled-features/src/custom-fields/aggregate-id.ts +16 -17
- package/packages/bundled-features/src/custom-fields/entity.ts +49 -47
- package/packages/bundled-features/src/custom-fields/events.ts +7 -8
- package/packages/bundled-features/src/custom-fields/feature.ts +70 -72
- package/packages/bundled-features/src/custom-fields/handlers/clear-custom-field.write.ts +9 -8
- package/packages/bundled-features/src/custom-fields/handlers/define-tenant-field.write.ts +28 -26
- package/packages/bundled-features/src/custom-fields/handlers/delete-system-field.write.ts +6 -7
- package/packages/bundled-features/src/custom-fields/handlers/delete-tenant-field.write.ts +12 -13
- package/packages/bundled-features/src/custom-fields/handlers/set-custom-field.write.ts +25 -28
- package/packages/bundled-features/src/custom-fields/handlers/update-tenant-field.write.ts +6 -6
- package/packages/bundled-features/src/custom-fields/lib/field-access.ts +2 -2
- package/packages/bundled-features/src/custom-fields/lib/parse-serialized-field.ts +1 -1
- package/packages/bundled-features/src/custom-fields/lib/quota.ts +1 -1
- package/packages/bundled-features/src/custom-fields/lib/value-schema.ts +10 -12
- package/packages/bundled-features/src/custom-fields/run-retention.ts +3 -3
- package/packages/bundled-features/src/custom-fields/schemas.ts +14 -14
- package/packages/bundled-features/src/custom-fields/web/client-plugin.tsx +2 -5
- package/packages/bundled-features/src/custom-fields/web/constants.ts +2 -2
- package/packages/bundled-features/src/custom-fields/web/custom-fields-form-section.tsx +26 -26
- package/packages/bundled-features/src/custom-fields/wire-for-entity.ts +65 -67
- package/packages/bundled-features/src/custom-fields/wire-user-data-rights.ts +3 -3
- package/packages/bundled-features/src/data-retention/_internal/parse-override.ts +2 -3
- package/packages/bundled-features/src/data-retention/feature.ts +11 -18
- package/packages/bundled-features/src/data-retention/handlers/policy-for.query.ts +6 -6
- package/packages/bundled-features/src/data-retention/keep-for.ts +17 -17
- package/packages/bundled-features/src/data-retention/override-schema.ts +13 -15
- package/packages/bundled-features/src/data-retention/presets.ts +18 -23
- package/packages/bundled-features/src/data-retention/resolve-for-tenant.ts +1 -1
- package/packages/bundled-features/src/data-retention/resolve-tenant-preset.ts +17 -16
- package/packages/bundled-features/src/data-retention/resolver.ts +33 -32
- package/packages/bundled-features/src/data-retention/run-retention-cleanup.ts +71 -58
- package/packages/bundled-features/src/data-retention/schema/tenant-retention-override.ts +13 -11
- package/packages/bundled-features/src/delivery/feature.ts +3 -3
- package/packages/bundled-features/src/delivery/handlers/log.query.ts +1 -1
- package/packages/bundled-features/src/delivery/tables.ts +9 -8
- package/packages/bundled-features/src/delivery/unsubscribe.ts +4 -4
- package/packages/bundled-features/src/delivery/upsert-preference.ts +3 -4
- package/packages/bundled-features/src/document-ingest-foundation/entity.ts +5 -5
- package/packages/bundled-features/src/document-ingest-foundation/events.ts +2 -2
- package/packages/bundled-features/src/document-ingest-foundation/feature.ts +2 -2
- package/packages/bundled-features/src/document-ingest-foundation/pages.ts +1 -1
- package/packages/bundled-features/src/document-ingest-foundation/tenant-destroy-hook.ts +4 -4
- package/packages/bundled-features/src/feature-toggles/compose-tier-resolver.ts +1 -1
- package/packages/bundled-features/src/feature-toggles/feature.ts +1 -1
- package/packages/bundled-features/src/feature-toggles/global-feature-state-table.ts +1 -1
- package/packages/bundled-features/src/feature-toggles/handlers/registered.query.ts +5 -5
- package/packages/bundled-features/src/feature-toggles/toggle-runtime.ts +1 -1
- package/packages/bundled-features/src/feature-toggles/toggle-sync-signal.ts +1 -1
- package/packages/bundled-features/src/feature-toggles/web/constants.ts +1 -1
- package/packages/bundled-features/src/file-derivatives/feature.ts +2 -2
- package/packages/bundled-features/src/file-derivatives/handlers/public-variant.query.ts +1 -1
- package/packages/bundled-features/src/file-derivatives/presets.ts +1 -1
- package/packages/bundled-features/src/file-foundation/feature.ts +6 -6
- package/packages/bundled-features/src/file-provider-inmemory/feature.ts +16 -16
- package/packages/bundled-features/src/file-provider-s3/feature.ts +16 -16
- package/packages/bundled-features/src/file-provider-s3/lib/s3-provider.ts +6 -6
- package/packages/bundled-features/src/files/feature.ts +6 -6
- package/packages/bundled-features/src/files-tenant-data/handlers/sweep-orphaned-derivatives.job.ts +5 -5
- package/packages/bundled-features/src/files-tenant-data/hooks.ts +24 -26
- package/packages/bundled-features/src/files-tenant-data/index.ts +1 -1
- package/packages/bundled-features/src/folders/feature.ts +1 -1
- package/packages/bundled-features/src/folders/web/folder-manager.tsx +2 -2
- package/packages/bundled-features/src/folders/web/tree.ts +5 -5
- package/packages/bundled-features/src/form-draft/db/queries/cleanup.ts +1 -1
- package/packages/bundled-features/src/form-draft/db/queries/owned-file-refs.ts +1 -1
- package/packages/bundled-features/src/form-draft/entity.ts +3 -3
- package/packages/bundled-features/src/form-draft/feature.ts +4 -5
- package/packages/bundled-features/src/form-draft/handlers/discard.write.ts +1 -1
- package/packages/bundled-features/src/form-draft/release-file-refs.ts +6 -6
- package/packages/bundled-features/src/form-draft/schemas.ts +3 -3
- package/packages/bundled-features/src/form-draft/web/constants.ts +0 -2
- package/packages/bundled-features/src/inbound-mail-foundation/aggregate-id.ts +19 -19
- package/packages/bundled-features/src/inbound-mail-foundation/connect-routes.ts +4 -3
- package/packages/bundled-features/src/inbound-mail-foundation/constants.ts +30 -33
- package/packages/bundled-features/src/inbound-mail-foundation/entities.ts +47 -48
- package/packages/bundled-features/src/inbound-mail-foundation/events.ts +54 -50
- package/packages/bundled-features/src/inbound-mail-foundation/feature.ts +39 -39
- package/packages/bundled-features/src/inbound-mail-foundation/handlers/account-state.ts +8 -8
- package/packages/bundled-features/src/inbound-mail-foundation/handlers/connect-account.write.ts +25 -26
- package/packages/bundled-features/src/inbound-mail-foundation/handlers/disconnect-account.write.ts +7 -7
- package/packages/bundled-features/src/inbound-mail-foundation/handlers/ingest-message.write.ts +50 -51
- package/packages/bundled-features/src/inbound-mail-foundation/handlers/list-accounts.query.ts +8 -8
- package/packages/bundled-features/src/inbound-mail-foundation/handlers/list-messages.query.ts +10 -10
- package/packages/bundled-features/src/inbound-mail-foundation/handlers/scope-visibility.ts +3 -4
- package/packages/bundled-features/src/inbound-mail-foundation/handlers/update-account.write.ts +11 -11
- package/packages/bundled-features/src/inbound-mail-foundation/oauth-state.ts +16 -15
- package/packages/bundled-features/src/inbound-mail-foundation/projection.ts +31 -29
- package/packages/bundled-features/src/inbound-mail-foundation/provider-factory.ts +9 -9
- package/packages/bundled-features/src/inbound-mail-foundation/retention-sweep.ts +45 -41
- package/packages/bundled-features/src/inbound-mail-foundation/tenant-destroy-hook.ts +14 -16
- package/packages/bundled-features/src/inbound-mail-foundation/types.ts +66 -67
- package/packages/bundled-features/src/inbound-mail-foundation/watch-supervisor.ts +69 -68
- package/packages/bundled-features/src/inbound-provider-imap/credential-document.ts +13 -13
- package/packages/bundled-features/src/inbound-provider-imap/feature.ts +42 -40
- package/packages/bundled-features/src/inbound-provider-imap/imap-client.ts +20 -19
- package/packages/bundled-features/src/inbound-provider-inmemory/feature.ts +21 -21
- package/packages/bundled-features/src/jobs/db/queries/retention.ts +2 -2
- package/packages/bundled-features/src/jobs/db/queries/stale-run-sweep.ts +3 -3
- package/packages/bundled-features/src/jobs/events.ts +1 -1
- package/packages/bundled-features/src/jobs/feature.ts +6 -7
- package/packages/bundled-features/src/jobs/handlers/detail.query.ts +4 -4
- package/packages/bundled-features/src/jobs/handlers/list.query.ts +1 -1
- package/packages/bundled-features/src/jobs/handlers/projection-rebuild.job.ts +1 -1
- package/packages/bundled-features/src/jobs/handlers/reindex-entity.job.ts +1 -1
- package/packages/bundled-features/src/jobs/handlers/retry.write.ts +1 -1
- package/packages/bundled-features/src/jobs/job-instant.ts +1 -1
- package/packages/bundled-features/src/jobs/job-run-logger.ts +14 -15
- package/packages/bundled-features/src/jobs/job-run-table.ts +3 -3
- package/packages/bundled-features/src/jobs/screens.ts +1 -1
- package/packages/bundled-features/src/jobs/tenant-job-failure-table.ts +1 -1
- package/packages/bundled-features/src/jobs/tenant-job-run-table.ts +1 -1
- package/packages/bundled-features/src/ledger/entity.ts +5 -5
- package/packages/bundled-features/src/ledger/feature.ts +3 -3
- package/packages/bundled-features/src/ledger/handlers/confirm-schedule-period.write.ts +3 -3
- package/packages/bundled-features/src/ledger/recurring.ts +12 -12
- package/packages/bundled-features/src/ledger/schemas.ts +1 -1
- package/packages/bundled-features/src/ledger/web/constants.ts +2 -2
- package/packages/bundled-features/src/ledger/web/index.ts +7 -7
- package/packages/bundled-features/src/legal-pages/feature.ts +40 -41
- package/packages/bundled-features/src/legal-pages/markdown.ts +3 -3
- package/packages/bundled-features/src/legal-pages/web/client-plugin.ts +23 -24
- package/packages/bundled-features/src/legal-pages/web/index.ts +0 -2
- package/packages/bundled-features/src/mail-foundation/feature.ts +26 -27
- package/packages/bundled-features/src/mail-transport-inmemory/feature.ts +27 -28
- package/packages/bundled-features/src/mail-transport-smtp/feature.ts +20 -20
- package/packages/bundled-features/src/managed-pages/branding.ts +6 -6
- package/packages/bundled-features/src/managed-pages/feature.ts +62 -62
- package/packages/bundled-features/src/managed-pages/handlers/by-slug.query.ts +5 -6
- package/packages/bundled-features/src/managed-pages/handlers/by-tenant-published.query.ts +8 -8
- package/packages/bundled-features/src/managed-pages/handlers/set.write.ts +5 -7
- package/packages/bundled-features/src/managed-pages/screens/page-screens.ts +11 -11
- package/packages/bundled-features/src/managed-pages/seeding.ts +8 -8
- package/packages/bundled-features/src/managed-pages/table.ts +16 -15
- package/packages/bundled-features/src/managed-pages/web/client-plugin.tsx +6 -6
- package/packages/bundled-features/src/managed-pages/web/i18n.ts +1 -1
- package/packages/bundled-features/src/notes-history/entity.ts +4 -4
- package/packages/bundled-features/src/notes-history/feature.ts +2 -2
- package/packages/bundled-features/src/notes-history-user-data/hooks.ts +1 -1
- package/packages/bundled-features/src/page-render/layout.ts +9 -9
- package/packages/bundled-features/src/page-render/markdown.ts +11 -11
- package/packages/bundled-features/src/page-render/security-headers.ts +7 -6
- package/packages/bundled-features/src/personal-access-tokens/feature.ts +5 -5
- package/packages/bundled-features/src/personal-access-tokens/roles.ts +2 -2
- package/packages/bundled-features/src/readiness/handlers/status.query.ts +3 -3
- package/packages/bundled-features/src/renderer-foundation/api.ts +12 -13
- package/packages/bundled-features/src/renderer-foundation/constants.ts +2 -2
- package/packages/bundled-features/src/renderer-foundation/feature.ts +7 -7
- package/packages/bundled-features/src/renderer-foundation/types.ts +11 -12
- package/packages/bundled-features/src/secrets/feature.ts +9 -9
- package/packages/bundled-features/src/secrets/web/constants.ts +2 -2
- package/packages/bundled-features/src/seo/feature.ts +3 -3
- package/packages/bundled-features/src/sessions/constants.ts +1 -1
- package/packages/bundled-features/src/sessions/feature.ts +9 -9
- package/packages/bundled-features/src/sessions/handlers/revoke-all-for-user.write.ts +2 -2
- package/packages/bundled-features/src/sessions/handlers/revoke-all-others.write.ts +2 -2
- package/packages/bundled-features/src/sessions/handlers/revoke.write.ts +1 -1
- package/packages/bundled-features/src/sessions/schema/user-session.ts +4 -4
- package/packages/bundled-features/src/sessions/screens.ts +2 -2
- package/packages/bundled-features/src/sessions/session-callbacks.ts +2 -2
- package/packages/bundled-features/src/sessions/session-revoked-event.ts +2 -2
- package/packages/bundled-features/src/shared/assert-no-where-rule-in-ownership-write.ts +1 -1
- package/packages/bundled-features/src/shared/decrypt-stored-pii.ts +1 -1
- package/packages/bundled-features/src/shared/encrypt-for-direct-write.ts +1 -1
- package/packages/bundled-features/src/shared/map-with-concurrency.ts +5 -4
- package/packages/bundled-features/src/shared/parent-visibility.ts +2 -2
- package/packages/bundled-features/src/shared/password-hashing.ts +1 -1
- package/packages/bundled-features/src/shared/signup-handover.ts +1 -2
- package/packages/bundled-features/src/shared/single-use-token-store.ts +1 -1
- package/packages/bundled-features/src/subscription-mollie/constants.ts +15 -17
- package/packages/bundled-features/src/subscription-mollie/feature.ts +41 -42
- package/packages/bundled-features/src/subscription-mollie/index.ts +3 -3
- package/packages/bundled-features/src/subscription-mollie/plugin-methods.ts +17 -16
- package/packages/bundled-features/src/subscription-mollie/verify-webhook.ts +34 -34
- package/packages/bundled-features/src/subscription-stripe/constants.ts +4 -6
- package/packages/bundled-features/src/subscription-stripe/feature.ts +44 -43
- package/packages/bundled-features/src/subscription-stripe/index.ts +6 -6
- package/packages/bundled-features/src/subscription-stripe/plugin-methods.ts +22 -27
- package/packages/bundled-features/src/subscription-stripe/runtime.ts +2 -2
- package/packages/bundled-features/src/subscription-stripe/verify-webhook.ts +62 -64
- package/packages/bundled-features/src/tags/feature.ts +3 -3
- package/packages/bundled-features/src/tags/screens.ts +1 -1
- package/packages/bundled-features/src/template-resolver/api.ts +10 -10
- package/packages/bundled-features/src/template-resolver/handlers/find-by-id.query.ts +5 -5
- package/packages/bundled-features/src/template-resolver/handlers/list.query.ts +1 -1
- package/packages/bundled-features/src/template-resolver/handlers/shared.ts +2 -2
- package/packages/bundled-features/src/template-resolver/handlers/template-write.ts +3 -3
- package/packages/bundled-features/src/template-resolver/handlers/upsert-system.write.ts +3 -4
- package/packages/bundled-features/src/template-resolver/handlers/upsert-tenant.write.ts +4 -5
- package/packages/bundled-features/src/template-resolver/seeding.ts +4 -4
- package/packages/bundled-features/src/template-resolver/table.ts +13 -14
- package/packages/bundled-features/src/template-resolver/web/client-plugin.tsx +2 -2
- package/packages/bundled-features/src/tenant/feature.ts +7 -7
- package/packages/bundled-features/src/tenant/handlers/member-directory.query.ts +1 -1
- package/packages/bundled-features/src/tenant/handlers/members.query.ts +1 -1
- package/packages/bundled-features/src/tenant/handlers/memberships.query.ts +1 -1
- package/packages/bundled-features/src/tenant/handlers/team-list.query.ts +1 -1
- package/packages/bundled-features/src/tenant/handlers/tenant-directory.query.ts +1 -1
- package/packages/bundled-features/src/tenant/invitation-table.ts +37 -40
- package/packages/bundled-features/src/tenant/membership-table.ts +3 -3
- package/packages/bundled-features/src/tenant/schema/tenant.ts +7 -9
- package/packages/bundled-features/src/tenant/screens.ts +1 -1
- package/packages/bundled-features/src/tenant/seeding.ts +19 -18
- package/packages/bundled-features/src/tenant/testing.ts +5 -6
- package/packages/bundled-features/src/tenant/web/constants.ts +2 -2
- package/packages/bundled-features/src/tenant-handover/events.ts +5 -7
- package/packages/bundled-features/src/tenant-handover/feature.ts +1 -1
- package/packages/bundled-features/src/tenant-handover/grant.ts +1 -1
- package/packages/bundled-features/src/tenant-handover/handlers/claim.write.ts +1 -1
- package/packages/bundled-features/src/tenant-handover/move-entity-graph.ts +8 -9
- package/packages/bundled-features/src/tenant-handover/signup-handover-provider.ts +1 -2
- package/packages/bundled-features/src/tenant-handover/transfer-graph.ts +4 -5
- package/packages/bundled-features/src/tenant-lifecycle/boot-checks.ts +1 -1
- package/packages/bundled-features/src/tenant-lifecycle/feature.ts +1 -1
- package/packages/bundled-features/src/tenant-lifecycle/run-tenant-destroy.ts +2 -2
- package/packages/bundled-features/src/tenant-lifecycle/stages.ts +1 -1
- package/packages/bundled-features/src/tenant-settings/constants.ts +1 -1
- package/packages/bundled-features/src/tenant-settings/tenant-defaults.ts +12 -5
- package/packages/bundled-features/src/tier-engine/aggregate-id.ts +15 -16
- package/packages/bundled-features/src/tier-engine/compose-app.ts +14 -14
- package/packages/bundled-features/src/tier-engine/entity.ts +18 -19
- package/packages/bundled-features/src/tier-engine/feature.ts +88 -87
- package/packages/bundled-features/src/tier-engine/handlers/active-tier.query.ts +6 -7
- package/packages/bundled-features/src/tier-engine/handlers/get-tenant-tier.query.ts +4 -4
- package/packages/bundled-features/src/tier-engine/handlers/set-tenant-tier.write.ts +8 -8
- package/packages/bundled-features/src/tier-engine/tier-resolver.ts +2 -2
- package/packages/bundled-features/src/tier-engine/trial.ts +13 -13
- package/packages/bundled-features/src/tier-engine/web/index.ts +4 -4
- package/packages/bundled-features/src/user/db/queries/stream-tenant-backfill.ts +8 -8
- package/packages/bundled-features/src/user/handlers/create.write.ts +4 -4
- package/packages/bundled-features/src/user/schema/user.ts +45 -44
- package/packages/bundled-features/src/user/seeding.ts +40 -40
- package/packages/bundled-features/src/user/testing.ts +3 -3
- package/packages/bundled-features/src/user-data-rights/audit-download.ts +27 -28
- package/packages/bundled-features/src/user-data-rights/boot-checks.ts +1 -1
- package/packages/bundled-features/src/user-data-rights/deletion-token.ts +1 -1
- package/packages/bundled-features/src/user-data-rights/feature.ts +112 -113
- package/packages/bundled-features/src/user-data-rights/handlers/cancel-deletion.write.ts +9 -9
- package/packages/bundled-features/src/user-data-rights/handlers/confirm-deletion-by-token.write.ts +8 -8
- package/packages/bundled-features/src/user-data-rights/handlers/download-by-job.query.ts +29 -30
- package/packages/bundled-features/src/user-data-rights/handlers/download-by-token.query.ts +40 -42
- package/packages/bundled-features/src/user-data-rights/handlers/export-status.query.ts +8 -9
- package/packages/bundled-features/src/user-data-rights/handlers/lift-restriction.write.ts +7 -8
- package/packages/bundled-features/src/user-data-rights/handlers/list-download-attempts.query.ts +2 -2
- package/packages/bundled-features/src/user-data-rights/handlers/my-audit-log.query.ts +4 -4
- package/packages/bundled-features/src/user-data-rights/handlers/request-deletion-by-email.write.ts +30 -29
- package/packages/bundled-features/src/user-data-rights/handlers/request-deletion.write.ts +15 -18
- package/packages/bundled-features/src/user-data-rights/handlers/request-export.write.ts +42 -41
- package/packages/bundled-features/src/user-data-rights/handlers/restrict-account.write.ts +22 -19
- package/packages/bundled-features/src/user-data-rights/handlers/run-forget-cleanup.write.ts +8 -8
- package/packages/bundled-features/src/user-data-rights/index.ts +8 -10
- package/packages/bundled-features/src/user-data-rights/lib/default-mailers.ts +3 -3
- package/packages/bundled-features/src/user-data-rights/lib/update-user-lifecycle.ts +24 -27
- package/packages/bundled-features/src/user-data-rights/run-export-jobs.ts +166 -276
- package/packages/bundled-features/src/user-data-rights/run-forget-cleanup.ts +85 -107
- package/packages/bundled-features/src/user-data-rights/run-user-export.ts +67 -69
- package/packages/bundled-features/src/user-data-rights/schema/download-attempt.ts +11 -11
- package/packages/bundled-features/src/user-data-rights/schema/download-token.ts +37 -41
- package/packages/bundled-features/src/user-data-rights/schema/export-job.ts +65 -67
- package/packages/bundled-features/src/user-data-rights/token-helpers.ts +21 -25
- package/packages/bundled-features/src/user-data-rights/web/client-plugin.tsx +6 -6
- package/packages/bundled-features/src/user-data-rights/web/confirm-deletion-screen.tsx +6 -5
- package/packages/bundled-features/src/user-data-rights/web/constants.ts +1 -1
- package/packages/bundled-features/src/user-data-rights/web/index.ts +5 -5
- package/packages/bundled-features/src/user-data-rights/web/privacy-center-screen.tsx +14 -13
- package/packages/bundled-features/src/user-data-rights/web/public-deletion-gate.tsx +13 -12
- package/packages/bundled-features/src/user-data-rights/web/request-deletion-screen.tsx +6 -6
- package/packages/bundled-features/src/user-data-rights/zip-path.ts +41 -40
- package/packages/bundled-features/src/user-data-rights-defaults/feature.ts +15 -15
- package/packages/bundled-features/src/user-data-rights-defaults/hooks/delivery-attempt.userdata-hook.ts +3 -5
- package/packages/bundled-features/src/user-data-rights-defaults/hooks/file-ref.userdata-hook.ts +45 -51
- package/packages/bundled-features/src/user-data-rights-defaults/hooks/job-run.userdata-hook.ts +2 -2
- package/packages/bundled-features/src/user-data-rights-defaults/hooks/notification-preference.userdata-hook.ts +1 -1
- package/packages/bundled-features/src/user-data-rights-defaults/hooks/user-session.userdata-hook.ts +3 -3
- package/packages/bundled-features/src/user-data-rights-defaults/hooks/user.userdata-hook.ts +32 -31
- package/packages/bundled-features/src/user-profile/handlers/change-email.write.ts +13 -13
- package/packages/bundled-features/src/user-profile/index.ts +3 -3
- package/packages/bundled-features/src/user-profile/web/client-plugin.ts +1 -1
- package/packages/bundled-features/src/user-profile/web/constants.ts +1 -1
- package/packages/bundled-features/src/user-profile/web/profile-screen.tsx +1 -1
- package/packages/bundled-features/src/workflow-runner/aggregate-id.ts +1 -1
- package/packages/bundled-features/src/workflow-runner/event-subscriber.ts +4 -5
- package/packages/bundled-features/src/workflow-runner/event-trigger.ts +4 -15
- package/packages/bundled-features/src/workflow-runner/feature.ts +2 -2
- package/packages/bundled-features/src/workflow-runner/handlers/resume-run.write.ts +4 -4
- package/packages/bundled-features/src/workflow-runner/pending-projection.ts +6 -7
- package/packages/bundled-features/src/workflow-runner/runner.ts +6 -6
- package/packages/bundled-features/src/workflow-runner/tables.ts +6 -6
- package/packages/bundled-features/src/workflow-runner/workflow-registry.ts +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// kumiko-lint-ignore app-feature-structure
|
|
1
|
+
// kumiko-lint-ignore app-feature-structure feature.ts is over 300 lines and not yet split
|
|
2
2
|
import { UNKNOWN_CLIENT_IP } from "@cosmicdrift/kumiko-framework/api";
|
|
3
3
|
import {
|
|
4
4
|
createSystemConfig,
|
|
@@ -83,87 +83,85 @@ import {
|
|
|
83
83
|
} from "./web/constants.ts";
|
|
84
84
|
import { USER_DATA_RIGHTS_I18N } from "./web/i18n.ts";
|
|
85
85
|
|
|
86
|
-
// user-data-rights —
|
|
87
|
-
//
|
|
86
|
+
// user-data-rights — GDPR Articles 15 (access), 17 (erasure),
|
|
87
|
+
// 18 (restriction), and 20 (portability) as a core feature.
|
|
88
88
|
//
|
|
89
|
-
//
|
|
90
|
-
//
|
|
91
|
-
//
|
|
92
|
-
//
|
|
93
|
-
// -
|
|
94
|
-
//
|
|
95
|
-
//
|
|
96
|
-
// - Restriction: status-Flip auf user-Schema, Auth-Middleware-Guard
|
|
89
|
+
// Instead of making each feature implement its own forget/export logic,
|
|
90
|
+
// it registers through `r.useExtension(EXT_USER_DATA, "<entity>", {
|
|
91
|
+
// export, delete })`. user-data-rights orchestrates:
|
|
92
|
+
// - Export job: iterates over all extension registrations and collects JSON
|
|
93
|
+
// - Forget job: iterates over all registrations and calls each delete hook
|
|
94
|
+
// with the strategy from `retention.policyFor` (data-retention)
|
|
95
|
+
// - Restriction: flips the user-schema status and enables the auth guard
|
|
97
96
|
/**
|
|
98
|
-
* Options
|
|
99
|
-
*
|
|
97
|
+
* Options for createUserDataRightsFeature. Notification callbacks follow
|
|
98
|
+
* the password-reset pattern in auth-routes.ts.
|
|
100
99
|
*
|
|
101
|
-
*
|
|
102
|
-
*
|
|
103
|
-
* (
|
|
104
|
-
* `mailFoundation.send`
|
|
100
|
+
* The plain token is never stored in the DB, event store, or jobRunsTable.
|
|
101
|
+
* The worker passes it ephemerally as a callback argument to the app-author
|
|
102
|
+
* implementation (typically `delivery.notify(...)` with `r.notification`
|
|
103
|
+
* templates, `mailFoundation.send` directly, or custom Resend/SES).
|
|
105
104
|
*
|
|
106
|
-
* Worker-
|
|
107
|
-
* `jobs
|
|
105
|
+
* Worker-run tracking and retries are provided automatically by the existing
|
|
106
|
+
* `jobs` feature.
|
|
108
107
|
*/
|
|
109
108
|
export type UserDataRightsOptions = {
|
|
110
|
-
/** Email
|
|
111
|
-
*
|
|
112
|
-
*
|
|
113
|
-
*
|
|
114
|
-
*
|
|
115
|
-
*
|
|
116
|
-
* verarbeitet, retry findet niemand.) */
|
|
109
|
+
/** Email notification when the export completes. The app author connects it
|
|
110
|
+
* to an email provider. Best effort: a send failure for Job A does not stop
|
|
111
|
+
* the batch; remaining pending jobs continue, and the failure is exposed via
|
|
112
|
+
* console.warn. Previously, the error reached the r.job wrapper, so with
|
|
113
|
+
* multiple pending jobs A could commit while B/C/D were never processed and
|
|
114
|
+
* no retry could find them. */
|
|
117
115
|
readonly sendExportReadyEmail?: SendExportReadyEmailFn;
|
|
118
116
|
/** Email-Notification beim Export-failed. Best-effort analog
|
|
119
117
|
* sendExportReadyEmail. */
|
|
120
118
|
readonly sendExportFailedEmail?: SendExportFailedEmailFn;
|
|
121
|
-
/** Base
|
|
122
|
-
* "https://app.example.com/user-export/by-token".
|
|
123
|
-
* a URL fragment (`#token=<plain
|
|
124
|
-
* sendExportReadyEmail
|
|
125
|
-
*
|
|
119
|
+
/** Base URL for the magic link, e.g.
|
|
120
|
+
* "https://app.example.com/user-export/by-token". The worker builds
|
|
121
|
+
* a URL fragment (`#token=<plain>`). Required when
|
|
122
|
+
* sendExportReadyEmail is set. Routing uses the reverse-proxy host per
|
|
123
|
+
* tenant rather than a per-tenant config key. */
|
|
126
124
|
readonly appExportDownloadUrl?: string;
|
|
127
|
-
/**
|
|
128
|
-
*
|
|
129
|
-
*
|
|
125
|
+
/** Email notification when deletion is requested ("account deletion in
|
|
126
|
+
* 30 days"). Best effort: a send failure does not abort the status flip
|
|
127
|
+
* (see handlers/request-deletion.write.ts). */
|
|
130
128
|
readonly sendDeletionRequestedEmail?: SendDeletionRequestedEmailFn;
|
|
131
|
-
/**
|
|
132
|
-
*
|
|
133
|
-
*
|
|
134
|
-
*
|
|
135
|
-
*
|
|
129
|
+
/** Email notification after the cleanup runner completes ("account deleted").
|
|
130
|
+
* Best effort. Delivery occurs after the user hook anonymizes the user, so
|
|
131
|
+
* the worker caches userEmail+tenantIds before the transaction and passes
|
|
132
|
+
* them ephemerally to the callback implementation (see
|
|
133
|
+
* run-forget-cleanup.ts). */
|
|
136
134
|
readonly sendDeletionExecutedEmail?: SendDeletionExecutedEmailFn;
|
|
137
|
-
/**
|
|
138
|
-
* HMAC
|
|
139
|
-
*
|
|
140
|
-
* by-token
|
|
135
|
+
/** Anonymous, email-verified apex deletion flow that is safe against lockout.
|
|
136
|
+
* HMAC secret for signing the verification token. Without a secret, the
|
|
137
|
+
* flow remains disabled: request-by-email returns success silently, while
|
|
138
|
+
* confirm-by-token rejects generically. */
|
|
141
139
|
readonly deletionTokenSecret?: string;
|
|
142
|
-
/**
|
|
143
|
-
* "https://app.example.com/delete-account/confirm".
|
|
144
|
-
*
|
|
145
|
-
* deletionTokenSecret
|
|
140
|
+
/** Base URL of the apex confirmation screen, e.g.
|
|
141
|
+
* "https://app.example.com/delete-account/confirm". The handler appends
|
|
142
|
+
* the token as a URL fragment (`#token=<token>`). Required when
|
|
143
|
+
* deletionTokenSecret is set. */
|
|
146
144
|
readonly deletionVerifyUrl?: string;
|
|
147
|
-
/**
|
|
148
|
-
* Best
|
|
149
|
-
* delivery.notify)
|
|
150
|
-
*
|
|
151
|
-
*
|
|
152
|
-
*
|
|
145
|
+
/** Sends the verification magic link (step 1 of the anonymous flow).
|
|
146
|
+
* Best effort and wired by the app author. It MUST be non-blocking (enqueue,
|
|
147
|
+
* e.g. via delivery.notify): a synchronous send would reintroduce a timing
|
|
148
|
+
* oracle for account enumeration (see SendDeletionVerificationEmailFn-doc).
|
|
149
|
+
* There is deliberately no mail-foundation default because a synchronous
|
|
150
|
+
* default send would restore that enumeration oracle. */
|
|
153
151
|
readonly sendDeletionVerificationEmail?: SendDeletionVerificationEmailFn;
|
|
154
|
-
/**
|
|
155
|
-
*
|
|
156
|
-
*
|
|
157
|
-
*
|
|
158
|
-
* `mailDefaults`
|
|
159
|
-
*
|
|
160
|
-
*
|
|
152
|
+
/** Zero-callback GDPR mail: when mail-foundation and a mail-transport-* are
|
|
153
|
+
* mounted, user-data-rights sends export and deletion notifications itself
|
|
154
|
+
* (export-ready/-failed, deletion-requested/-executed) using the default
|
|
155
|
+
* templates (email-templates.ts), without an app callback.
|
|
156
|
+
* `mailDefaults` brands these default messages (locale and app name). It
|
|
157
|
+
* applies only when the relevant send*Email option is unset; export-ready
|
|
158
|
+
* also requires appExportDownloadUrl. */
|
|
161
159
|
readonly mailDefaults?: GdprMailDefaults;
|
|
162
160
|
/** Hides the Art. 17 deletion section + its request-deletion/cancel-deletion
|
|
163
161
|
* actions on the privacy-center screen — for apps that already offer
|
|
164
162
|
* account deletion elsewhere (e.g. a profile danger-zone), against
|
|
165
163
|
* duplication. Default `true` (deletion section shown).
|
|
166
|
-
* BREAKING
|
|
164
|
+
* BREAKING: replaces the removed client-side
|
|
167
165
|
* `userDataRightsClient({ privacyCenter: { showDeletion } })` option —
|
|
168
166
|
* the screen is now declared once, server-side (`type: "projectionDetail"`),
|
|
169
167
|
* so per-app visibility can only be a boot-time option, not a client-side
|
|
@@ -202,18 +200,18 @@ export function createUserDataRightsFeature(opts: UserDataRightsOptions = {}): F
|
|
|
202
200
|
r.envSchema(deletionTokenSecretEnvSchema);
|
|
203
201
|
r.usesApi("compliance.forTenant");
|
|
204
202
|
r.usesApi("retention.policyFor");
|
|
205
|
-
//
|
|
206
|
-
// r.usesApi
|
|
207
|
-
//
|
|
208
|
-
//
|
|
203
|
+
// restrict-account calls sessions.revokeAllForUser across features.
|
|
204
|
+
// r.usesApi enables boot validation: without the sessions feature, the app
|
|
205
|
+
// fails at boot instead of raising an opaque "handler not found" error
|
|
206
|
+
// on the first restrict call.
|
|
209
207
|
r.usesApi("sessions.revokeAllForUser");
|
|
210
|
-
// file-foundation
|
|
211
|
-
//
|
|
212
|
-
//
|
|
208
|
+
// file-foundation is a soft dependency: only the export worker needs it
|
|
209
|
+
// for storage writes. Apps that use only forget (not export) do not need
|
|
210
|
+
// to mount file-foundation.
|
|
213
211
|
|
|
214
212
|
r.extendsRegistrar(EXT_USER_DATA, {});
|
|
215
213
|
|
|
216
|
-
// GDPR-storage guards V2+V3
|
|
214
|
+
// GDPR-storage guards V2+V3 — moved off the framework-internal
|
|
217
215
|
// boot-validator onto this feature's own r.bootCheck(), since it's the
|
|
218
216
|
// EXT_USER_DATA channel owner: any r.useExtension(EXT_USER_DATA, ...)
|
|
219
217
|
// usage already requires user-data-rights to be mounted.
|
|
@@ -243,24 +241,24 @@ export function createUserDataRightsFeature(opts: UserDataRightsOptions = {}): F
|
|
|
243
241
|
}),
|
|
244
242
|
);
|
|
245
243
|
|
|
246
|
-
//
|
|
244
|
+
// ExportJob-Lifecycle-Entity.
|
|
247
245
|
r.entity({ name: "export-job", ...exportJobEntity });
|
|
248
246
|
|
|
249
|
-
//
|
|
250
|
-
//
|
|
251
|
-
//
|
|
247
|
+
// The worker generates the token when flipping the job to done (see
|
|
248
|
+
// run-export-jobs.ts). The hash is stored in the database, while the plain
|
|
249
|
+
// token is kept in RunExportJobsResult for email notification.
|
|
252
250
|
r.entity({ name: "export-download-token", ...exportDownloadTokenEntity });
|
|
253
251
|
|
|
254
|
-
//
|
|
252
|
+
// Audit-Trail invalid Download-Attempts (DPO Brute-Force-Detection).
|
|
255
253
|
r.entity({ name: "download-attempt", ...downloadAttemptEntity });
|
|
256
254
|
|
|
257
|
-
//
|
|
258
|
-
//
|
|
259
|
-
//
|
|
255
|
+
// GDPR Article 18 account freeze (pause processing).
|
|
256
|
+
// The endpoints restrict and lift the restriction. The login block for
|
|
257
|
+
// restricted users lives in auth-email-password/login.write.ts.
|
|
260
258
|
r.writeHandler(restrictAccountWrite);
|
|
261
259
|
r.writeHandler(liftRestrictionWrite);
|
|
262
260
|
|
|
263
|
-
//
|
|
261
|
+
// Endpoints for the GDPR Article 17 forget path with a grace period.
|
|
264
262
|
r.writeHandler(
|
|
265
263
|
createRequestDeletionHandler({
|
|
266
264
|
...(opts.sendDeletionRequestedEmail && {
|
|
@@ -293,10 +291,10 @@ export function createUserDataRightsFeature(opts: UserDataRightsOptions = {}): F
|
|
|
293
291
|
),
|
|
294
292
|
);
|
|
295
293
|
|
|
296
|
-
//
|
|
297
|
-
// sendDeletionExecutedEmail
|
|
298
|
-
//
|
|
299
|
-
//
|
|
294
|
+
// Cleanup runner as a privileged handler. When
|
|
295
|
+
// sendDeletionExecutedEmail is set, the handler passes the callback to
|
|
296
|
+
// runForgetCleanup; the worker caches userEmail+tenantIds before the
|
|
297
|
+
// transaction (see run-forget-cleanup.ts).
|
|
300
298
|
r.writeHandler(
|
|
301
299
|
createRunForgetCleanupHandler(
|
|
302
300
|
opts.sendDeletionExecutedEmail
|
|
@@ -306,20 +304,20 @@ export function createUserDataRightsFeature(opts: UserDataRightsOptions = {}): F
|
|
|
306
304
|
);
|
|
307
305
|
r.exposesApi("userDataRights.runForget");
|
|
308
306
|
|
|
309
|
-
//
|
|
307
|
+
// User touchpoints for the asynchronous export pipeline.
|
|
310
308
|
r.writeHandler(requestExportWrite);
|
|
311
309
|
r.queryHandler(exportStatusQuery);
|
|
312
310
|
r.exposesApi("userDataRights.runExport");
|
|
313
311
|
|
|
314
|
-
//
|
|
315
|
-
//
|
|
316
|
-
//
|
|
317
|
-
// r.httpRoute
|
|
312
|
+
// Download endpoints for token and session paths.
|
|
313
|
+
// Both query handlers verify the token or session, obtain a signed URL
|
|
314
|
+
// from the storage provider, and persist audit fields on the token row.
|
|
315
|
+
// The r.httpRoute wrappers below issue the 302 redirect to signedUrl.
|
|
318
316
|
r.queryHandler(downloadByTokenQuery);
|
|
319
317
|
r.queryHandler(downloadByJobQuery);
|
|
320
318
|
|
|
321
|
-
//
|
|
322
|
-
//
|
|
319
|
+
// User self-access under Article 15 and operator access to invalid download
|
|
320
|
+
// attempts (DPO).
|
|
323
321
|
r.queryHandler(myAuditLogQuery);
|
|
324
322
|
r.queryHandler(listDownloadAttemptsQuery);
|
|
325
323
|
|
|
@@ -483,12 +481,12 @@ export function createUserDataRightsFeature(opts: UserDataRightsOptions = {}): F
|
|
|
483
481
|
// Magic-link path (anonymous): the email link carries the token as a
|
|
484
482
|
// URL fragment (`#token=<plain>`) instead of a query param — fragments
|
|
485
483
|
// never leave the browser, so they never hit proxy/access logs
|
|
486
|
-
//
|
|
484
|
+
// This route only serves the interstitial page; the
|
|
487
485
|
// external script reads the fragment client-side and exchanges the
|
|
488
486
|
// token via POST for the signed URL.
|
|
489
487
|
//
|
|
490
|
-
// No `?token=` query fallback: framework is zero-legacy
|
|
491
|
-
// live customer data / no
|
|
488
|
+
// No `?token=` query fallback: framework is zero-legacy — no
|
|
489
|
+
// live customer data / no emails in flight that would need
|
|
492
490
|
// bridging, so there's nothing a fallback would need to cover. A query
|
|
493
491
|
// param reaches the server as part of the request URL and gets written
|
|
494
492
|
// to proxy/access logs regardless of what the handler does with it
|
|
@@ -532,7 +530,7 @@ export function createUserDataRightsFeature(opts: UserDataRightsOptions = {}): F
|
|
|
532
530
|
});
|
|
533
531
|
|
|
534
532
|
// Exchange endpoint for the interstitial page: the token arrives here
|
|
535
|
-
// as a POST body instead of a query string
|
|
533
|
+
// as a POST body instead of a query string. A dedicated
|
|
536
534
|
// route rather than letting the browser JS call /api/query directly,
|
|
537
535
|
// for two reasons:
|
|
538
536
|
// 1. IP/UA audit — extractAuditMeta needs the raw request headers and
|
|
@@ -571,7 +569,7 @@ export function createUserDataRightsFeature(opts: UserDataRightsOptions = {}): F
|
|
|
571
569
|
// defaults to 0, ignoring headers entirely) nor a socket, so every
|
|
572
570
|
// fragment-POST download would fall to the shared "unknown" bucket,
|
|
573
571
|
// turning the per-user 30/min backstop into one global bucket an
|
|
574
|
-
// attacker can exhaust for everyone
|
|
572
|
+
// attacker can exhaust for everyone. Passing `clientIp`
|
|
575
573
|
// directly as env — the same server-resolved, trustedProxyHops-
|
|
576
574
|
// aware value the outer request already trusted — reaches
|
|
577
575
|
// extractSocketAddress() without going through header/hop-count
|
|
@@ -602,7 +600,7 @@ export function createUserDataRightsFeature(opts: UserDataRightsOptions = {}): F
|
|
|
602
600
|
"Unix timestamp of the last export storage-cleanup pass that completed. Alert on time() minus this value exceeding the cron interval plus a buffer; the backlog-age gauge alone stays at its last value when the cron stops.",
|
|
603
601
|
});
|
|
604
602
|
|
|
605
|
-
//
|
|
603
|
+
// Worker for the asynchronous export pipeline, triggered by a cron job.
|
|
606
604
|
const RUN_EXPORT_JOBS_REASON = "processes pending export jobs across every tenant";
|
|
607
605
|
r.job({
|
|
608
606
|
name: "run-export-jobs",
|
|
@@ -614,9 +612,9 @@ export function createUserDataRightsFeature(opts: UserDataRightsOptions = {}): F
|
|
|
614
612
|
throw new Error("run-export-jobs: ctx.registry required (JobContext incomplete)");
|
|
615
613
|
}
|
|
616
614
|
const T = (await import("@cosmicdrift/kumiko-framework/time")).getTemporal();
|
|
617
|
-
// SYSTEM_USER_ID
|
|
618
|
-
//
|
|
619
|
-
//
|
|
615
|
+
// SYSTEM_USER_ID is the framework-wide convention. The job discriminator is
|
|
616
|
+
// recorded in the secret-read audit through
|
|
617
|
+
// handlerName="user-data-rights:run-export-jobs".
|
|
620
618
|
const exportUserId = SYSTEM_USER_ID;
|
|
621
619
|
const exportDb =
|
|
622
620
|
ctx.db.unsafeRaw() as import("@cosmicdrift/kumiko-framework/db").DbConnection; // @cast-boundary db-operator — jobs never run inside a DbTx
|
|
@@ -628,12 +626,13 @@ export function createUserDataRightsFeature(opts: UserDataRightsOptions = {}): F
|
|
|
628
626
|
? createMetricsHandle(ctx.meter, "user-data-rights")
|
|
629
627
|
: createNoopMetricsHandle();
|
|
630
628
|
|
|
631
|
-
//
|
|
632
|
-
//
|
|
633
|
-
//
|
|
634
|
-
//
|
|
635
|
-
// The cron runs across tenants
|
|
636
|
-
// recipient's tenant
|
|
629
|
+
// Without explicit send*Email options, a mounted mail transport sends the
|
|
630
|
+
// export notifications itself using the default templates. The resolver
|
|
631
|
+
// builds the per-tenant transport from configResolver, bridging it in
|
|
632
|
+
// the same way as buildStorageProvider.
|
|
633
|
+
// The cron runs across tenants, so each mail needs a notify function
|
|
634
|
+
// bound to the recipient's tenant for template overrides and channel
|
|
635
|
+
// configuration.
|
|
637
636
|
const notifyFactory = ctx._notifyFactory;
|
|
638
637
|
const exportNotifyFor =
|
|
639
638
|
notifyFactory !== undefined && isGdprMailDeliveryAvailable(exportRegistry)
|
|
@@ -678,9 +677,9 @@ export function createUserDataRightsFeature(opts: UserDataRightsOptions = {}): F
|
|
|
678
677
|
handlerName: "user-data-rights:run-export-jobs",
|
|
679
678
|
}),
|
|
680
679
|
now: T.Now.instant(),
|
|
681
|
-
// App-
|
|
682
|
-
//
|
|
683
|
-
//
|
|
680
|
+
// App-author callbacks take precedence; otherwise the mail-foundation default
|
|
681
|
+
// is used. Both are optional: without a mail transport or callback,
|
|
682
|
+
// clients continue polling via export-status.query.
|
|
684
683
|
...(sendExportReadyEmail && { sendExportReadyEmail }),
|
|
685
684
|
...(sendExportFailedEmail && { sendExportFailedEmail }),
|
|
686
685
|
...(opts.appExportDownloadUrl !== undefined && {
|
|
@@ -694,11 +693,11 @@ export function createUserDataRightsFeature(opts: UserDataRightsOptions = {}): F
|
|
|
694
693
|
},
|
|
695
694
|
});
|
|
696
695
|
|
|
697
|
-
//
|
|
698
|
-
//
|
|
699
|
-
// userDataRights.runForget
|
|
700
|
-
//
|
|
701
|
-
//
|
|
696
|
+
// Automatic Article 17 forget cron. After the grace period, it runs
|
|
697
|
+
// runForgetCleanup without supervision; the manual
|
|
698
|
+
// userDataRights.runForget API remains available for operator runs.
|
|
699
|
+
// Without this cron, deletion requests would remain in
|
|
700
|
+
// DeletionRequested indefinitely and Article 17 erasure would never run.
|
|
702
701
|
const RUN_FORGET_CLEANUP_REASON = "executes overdue Art.17 forget requests across every tenant";
|
|
703
702
|
r.job({
|
|
704
703
|
name: "run-forget-cleanup",
|
|
@@ -779,7 +778,7 @@ export function createUserDataRightsFeature(opts: UserDataRightsOptions = {}): F
|
|
|
779
778
|
actor: ctx.systemUser.id,
|
|
780
779
|
});
|
|
781
780
|
|
|
782
|
-
// Persist each incomplete report on the job-run log
|
|
781
|
+
// Persist each incomplete report on the job-run log. The write
|
|
783
782
|
// handler returns incomplete[] in its response; the cron path used to
|
|
784
783
|
// discard the array (only a console.warn for rolledBack cases).
|
|
785
784
|
// ctx.log feeds createJobRunLogger → store_job_run_logs.
|
|
@@ -8,17 +8,17 @@ import { updateUserLifecycle } from "../lib/update-user-lifecycle.ts";
|
|
|
8
8
|
const APPEND_LIFECYCLE_EVENT_REASON =
|
|
9
9
|
"appends the user lifecycle event on the SYSTEM_TENANT_ID user stream";
|
|
10
10
|
|
|
11
|
-
// POST /api/user/cancel-deletion
|
|
11
|
+
// POST /api/user/cancel-deletion.
|
|
12
12
|
//
|
|
13
|
-
//
|
|
14
|
-
//
|
|
13
|
+
// During the grace period, the user can withdraw a pending deletion request.
|
|
14
|
+
// This restores:
|
|
15
15
|
// - status = "active"
|
|
16
16
|
// - gracePeriodEnd = null
|
|
17
17
|
//
|
|
18
|
-
//
|
|
19
|
-
//
|
|
18
|
+
// After the grace period, return 422 because cleanup may already have triggered
|
|
19
|
+
// irreversible hooks.
|
|
20
20
|
//
|
|
21
|
-
//
|
|
21
|
+
// Cancelling as an "active" user also returns 422 because no deletion is pending.
|
|
22
22
|
export const cancelDeletionWrite = defineWriteHandler({
|
|
23
23
|
name: "cancel-deletion",
|
|
24
24
|
schema: z.object({}),
|
|
@@ -64,13 +64,13 @@ export const cancelDeletionWrite = defineWriteHandler({
|
|
|
64
64
|
await updateUserLifecycle(ctx.db.unsafeRaw(), event.user.id, {
|
|
65
65
|
status: USER_STATUS.Active,
|
|
66
66
|
gracePeriodEnd: null,
|
|
67
|
-
//
|
|
67
|
+
// Closes the replay-after-cancel window — a still-TTL-valid email
|
|
68
68
|
// token verified against the nulled requestId can no longer arm a second grace period.
|
|
69
69
|
pendingDeletionRequestId: null,
|
|
70
70
|
});
|
|
71
71
|
|
|
72
|
-
// gracePeriodEnd=null
|
|
73
|
-
// ISO
|
|
72
|
+
// gracePeriodEnd=null in the response mirrors request-deletion's
|
|
73
|
+
// ISO timestamp so the frontend can handle both endpoints uniformly.
|
|
74
74
|
const gracePeriodEnd: string | null = null;
|
|
75
75
|
return {
|
|
76
76
|
isSuccess: true as const,
|
package/packages/bundled-features/src/user-data-rights/handlers/confirm-deletion-by-token.write.ts
CHANGED
|
@@ -9,16 +9,16 @@ export type ConfirmDeletionByTokenOptions = {
|
|
|
9
9
|
readonly deletionTokenSecret?: string;
|
|
10
10
|
};
|
|
11
11
|
|
|
12
|
-
//
|
|
13
|
-
// expired /
|
|
12
|
+
// Use the same generic 422 for every token-error path (malformed / bad_signature /
|
|
13
|
+
// expired / missing secret) so callers cannot determine whether a token belongs to a user.
|
|
14
14
|
function invalidToken(): UnprocessableError {
|
|
15
15
|
return new UnprocessableError("invalid_or_expired_token");
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
// userId
|
|
19
|
-
//
|
|
20
|
-
//
|
|
21
|
-
//
|
|
18
|
+
// userId comes from the not-yet-verified token (attacker-controlled input). A failed
|
|
19
|
+
// lookup—for example, a type-mismatched id on an int/uuid column—must not surface as a
|
|
20
|
+
// 500; null is treated by the caller as "no pending request" (generic 422). HMAC
|
|
21
|
+
// verification remains the actual gate.
|
|
22
22
|
async function readPendingDeletionRequestId(
|
|
23
23
|
ctx: HandlerContext,
|
|
24
24
|
userId: string,
|
|
@@ -41,7 +41,7 @@ async function readPendingDeletionRequestId(
|
|
|
41
41
|
// the actual grace-period transition, so a crash after the spend can no
|
|
42
42
|
// longer lose the write step.
|
|
43
43
|
//
|
|
44
|
-
// Replay protection
|
|
44
|
+
// Replay protection: the row's requestId is part of the verify key.
|
|
45
45
|
// We read it via the (unverified, lookup-only) userId from the token, reject
|
|
46
46
|
// a missing entry, and verify the token against the CURRENT requestId. After
|
|
47
47
|
// a cancel-deletion (status → Active, pendingDeletionRequestId → null), a
|
|
@@ -51,7 +51,7 @@ async function readPendingDeletionRequestId(
|
|
|
51
51
|
// the same requestId and both verify the HMAC — commitDeletion spends the
|
|
52
52
|
// anchor AND writes the transition atomically (expect: status===Active &&
|
|
53
53
|
// pendingDeletionRequestId===requestId), so exactly one wins. The loser gets
|
|
54
|
-
// the same generic 422 as an invalid token — no status leak
|
|
54
|
+
// the same generic 422 as an invalid token — no status leak.
|
|
55
55
|
export function createConfirmDeletionByTokenHandler(opts: ConfirmDeletionByTokenOptions = {}) {
|
|
56
56
|
return defineWriteHandler({
|
|
57
57
|
name: "confirm-deletion-by-token",
|
|
@@ -1,26 +1,26 @@
|
|
|
1
|
-
// GET /api/query → user-data-rights:query:download-by-job
|
|
1
|
+
// GET /api/query → user-data-rights:query:download-by-job
|
|
2
2
|
//
|
|
3
|
-
// **UI
|
|
4
|
-
//
|
|
5
|
-
// job.userId
|
|
3
|
+
// **UI download flow** (session-auth): The user polls the status, sees
|
|
4
|
+
// "done", and clicks "Download" with the jobId. The server checks
|
|
5
|
+
// `session.userId == job.userId`; no token is needed because the session
|
|
6
|
+
// provides authentication.
|
|
6
7
|
//
|
|
7
|
-
// **Cross-
|
|
8
|
-
//
|
|
9
|
-
//
|
|
10
|
-
//
|
|
11
|
-
// Plan-Decision (Atom 4b Plan, User-Choice).
|
|
8
|
+
// **Cross-tenant same user:** Jobs are tenant-agnostic (one job per userId
|
|
9
|
+
// across all memberships). If Alice starts an export in Tenant A, later
|
|
10
|
+
// signs in to Tenant B, and clicks Download, the server accepts it:
|
|
11
|
+
// `session.userId == job.userId` is sufficient; no tenant-match check applies.
|
|
12
12
|
//
|
|
13
|
-
// **Cross-
|
|
14
|
-
// (
|
|
15
|
-
//
|
|
13
|
+
// **Cross-user isolation:** If session.userId != job.userId, return 404
|
|
14
|
+
// (not 403) to avoid leaking whether the job exists. Use the same error as
|
|
15
|
+
// for an unknown job ID.
|
|
16
16
|
//
|
|
17
|
-
//
|
|
18
|
-
// 1.
|
|
19
|
-
// 2. job.userId === session.userId (cross-user
|
|
20
|
-
// 3. job.status === "done"
|
|
21
|
-
// 4. job.downloadStorageKey != null
|
|
22
|
-
// 5. tokenRow
|
|
23
|
-
// 6.
|
|
17
|
+
// Verification pipeline:
|
|
18
|
+
// 1. Fetch the job by jobId
|
|
19
|
+
// 2. Check job.userId === session.userId (cross-user isolation)
|
|
20
|
+
// 3. Check job.status === "done"
|
|
21
|
+
// 4. Check job.downloadStorageKey != null
|
|
22
|
+
// 5. Look up tokenRow (audit-row update only)
|
|
23
|
+
// 6. Best-effort audit update: useCount + 1, IP, UA, lastUsedAt
|
|
24
24
|
// 7. Return {url, expiresAt}
|
|
25
25
|
|
|
26
26
|
import { requestContext } from "@cosmicdrift/kumiko-framework/api";
|
|
@@ -69,7 +69,7 @@ export const downloadByJobQuery = defineQueryHandler({
|
|
|
69
69
|
"each signed-in user downloads only their own finished export job; the job " +
|
|
70
70
|
"lookup checks jobRow.userId against the caller's own id and 404s otherwise",
|
|
71
71
|
},
|
|
72
|
-
}, // openToAll
|
|
72
|
+
}, // openToAll requires authentication; anonymous access is not allowed
|
|
73
73
|
description:
|
|
74
74
|
"Returns a short-lived signed download URL for the calling user's own finished data-export job named by job id, backing the download button in the privacy center once export-status reports the job done.",
|
|
75
75
|
escapeHatch: {
|
|
@@ -82,9 +82,8 @@ export const downloadByJobQuery = defineQueryHandler({
|
|
|
82
82
|
const userId = query.user.id;
|
|
83
83
|
const jobId = query.payload.jobId;
|
|
84
84
|
const tenantId = query.user.tenantId;
|
|
85
|
-
// IP
|
|
86
|
-
//
|
|
87
|
-
// Wert (603/2).
|
|
85
|
+
// IP and UA from the request-scoped context populated by
|
|
86
|
+
// requestIdMiddleware; these are server-trusted rather than client-supplied.
|
|
88
87
|
const auditIp = requestContext.get()?.ip ?? null;
|
|
89
88
|
const auditUa = requestContext.get()?.userAgent ?? null;
|
|
90
89
|
const runner = ctx.db.unsafeRaw();
|
|
@@ -187,10 +186,10 @@ export const downloadByJobQuery = defineQueryHandler({
|
|
|
187
186
|
now.epochMilliseconds + SIGNED_URL_TTL_SECONDS * 1000,
|
|
188
187
|
);
|
|
189
188
|
|
|
190
|
-
// Step 6:
|
|
191
|
-
//
|
|
192
|
-
//
|
|
193
|
-
//
|
|
189
|
+
// Step 6: Look up tokenRow for the audit update. The UI flow has no plain
|
|
190
|
+
// token, but its useCount must still be incremented so audit fields remain
|
|
191
|
+
// consistent and UI clicks count as uses. The jobId lookup is safe because
|
|
192
|
+
// the UNIQUE index guarantees at most one row.
|
|
194
193
|
const tokenRow = await fetchOne<TokenRow>(runner, exportDownloadTokensTable, {
|
|
195
194
|
jobId,
|
|
196
195
|
});
|
|
@@ -207,9 +206,9 @@ export const downloadByJobQuery = defineQueryHandler({
|
|
|
207
206
|
userAgent: auditUa,
|
|
208
207
|
});
|
|
209
208
|
}
|
|
210
|
-
//
|
|
211
|
-
//
|
|
212
|
-
//
|
|
209
|
+
// If tokenRow is missing (which should not happen when the preceding token
|
|
210
|
+
// creation flow completed), skip the audit update and continue the download;
|
|
211
|
+
// an audit failure must not block the user.
|
|
213
212
|
|
|
214
213
|
return {
|
|
215
214
|
url: signedUrl,
|