@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
|
@@ -5,10 +5,10 @@ import {
|
|
|
5
5
|
createTimestampField,
|
|
6
6
|
} from "@cosmicdrift/kumiko-framework/engine";
|
|
7
7
|
|
|
8
|
-
// Audit
|
|
9
|
-
//
|
|
10
|
-
//
|
|
11
|
-
//
|
|
8
|
+
// Audit trail for rejected download attempts.
|
|
9
|
+
// Writes one row per 4xx response on the download-by-{token,job} path, allowing the DPO
|
|
10
|
+
// to detect brute-force probing and anomalies such as many invalid attempts from one IP.
|
|
11
|
+
// Successful downloads are recorded in download-token.lastUsedAt instead.
|
|
12
12
|
export const downloadAttemptEntity = createEntity({
|
|
13
13
|
table: "read_download_attempts",
|
|
14
14
|
idType: "uuid",
|
|
@@ -29,11 +29,11 @@ export const downloadAttemptEntity = createEntity({
|
|
|
29
29
|
personal: false,
|
|
30
30
|
reason: "technical_reference",
|
|
31
31
|
}),
|
|
32
|
-
// Token
|
|
32
|
+
// Token hash for the token path, or NULL for the job path or an unknown token.
|
|
33
33
|
tokenHash: createTextField({ maxLength: 64, personal: false, reason: "technical_reference" }),
|
|
34
|
-
// Job
|
|
34
|
+
// Job ID when the attempt identified one; NULL for an unknown token.
|
|
35
35
|
jobId: createTextField({ personal: false, reason: "technical_reference" }),
|
|
36
|
-
// User
|
|
36
|
+
// User ID for the authenticated job path; NULL for anonymous token-path requests.
|
|
37
37
|
attemptedByUserId: createTextField({ personal: false, reason: "pseudonymous_fk" }),
|
|
38
38
|
// The anonymous token path has no owner, so those rows fall back to the tenant key;
|
|
39
39
|
// find "exact" on ip because list-download-attempts filters by IP.
|
|
@@ -49,10 +49,10 @@ export const downloadAttemptEntity = createEntity({
|
|
|
49
49
|
}),
|
|
50
50
|
attemptedAt: createTimestampField({ required: true }),
|
|
51
51
|
},
|
|
52
|
-
// 90d hardDelete: unbounded growth
|
|
53
|
-
//
|
|
54
|
-
//
|
|
55
|
-
//
|
|
52
|
+
// 90d hardDelete: unbounded growth would create a disk bomb targeting the system
|
|
53
|
+
// that detects brute-force activity. Brute-force patterns are short-lived (hours to days),
|
|
54
|
+
// while a 90d window covers forensic reviews and quarterly DPO audits.
|
|
55
|
+
// The tenant can extend retention through an override for HR compliance.
|
|
56
56
|
retention: { keepFor: "90d", strategy: "hardDelete", reference: "attemptedAt" },
|
|
57
57
|
});
|
|
58
58
|
|
|
@@ -6,43 +6,42 @@ import {
|
|
|
6
6
|
createTimestampField,
|
|
7
7
|
} from "@cosmicdrift/kumiko-framework/engine";
|
|
8
8
|
|
|
9
|
-
// Export-Download-Token
|
|
9
|
+
// Export-Download-Token.
|
|
10
10
|
//
|
|
11
|
-
//
|
|
12
|
-
// 1. Worker
|
|
13
|
-
//
|
|
14
|
-
// 2. crud.create(downloadTokenEntity, ...)
|
|
15
|
-
// `exportDownloadToken.created`-Event in
|
|
16
|
-
//
|
|
17
|
-
// direct
|
|
18
|
-
// 3. Plain
|
|
19
|
-
//
|
|
20
|
-
// 4.
|
|
21
|
-
//
|
|
11
|
+
// Security token for the download endpoint. Pattern:
|
|
12
|
+
// 1. Worker generates a plain token (32 random bytes, base64url) +
|
|
13
|
+
// hash (SHA256 hex) when flipping to done.
|
|
14
|
+
// 2. crud.create(downloadTokenEntity, ...) emits
|
|
15
|
+
// `exportDownloadToken.created`-Event in the event store. The DB row
|
|
16
|
+
// is written synchronously via the projection (Marten pattern, NOT
|
|
17
|
+
// direct INSERT).
|
|
18
|
+
// 3. Plain token remains in worker memory + is passed via
|
|
19
|
+
// RunExportJobsResult to the notification flow. NEVER plain in DB.
|
|
20
|
+
// 4. The download endpoint hashes the incoming token + looks up the
|
|
21
|
+
// hash entry. Constant-time comparison against timing attacks.
|
|
22
22
|
//
|
|
23
|
-
// **Multi-use within TTL
|
|
24
|
-
//
|
|
25
|
-
//
|
|
26
|
-
//
|
|
23
|
+
// **Multi-use within TTL**: Token is not "consumed" on download.
|
|
24
|
+
// Multiple downloads until expiresAt are allowed — better UX for connection
|
|
25
|
+
// interruptions, no forced re-export. Pattern matches Google Takeout (7d)
|
|
26
|
+
// + Facebook Data Download (4d).
|
|
27
27
|
//
|
|
28
|
-
// **TTL = job.expiresAt** (denormalized,
|
|
29
|
-
// Storage
|
|
30
|
-
// expiresAt + exportStorageCleanupGraceHours.
|
|
31
|
-
// (
|
|
32
|
-
// != null
|
|
28
|
+
// **TTL = job.expiresAt** (denormalized, same value as the job row).
|
|
29
|
+
// Storage cleanup nulls downloadStorageKey after
|
|
30
|
+
// expiresAt + exportStorageCleanupGraceHours. The token row remains
|
|
31
|
+
// (audit trail) — the download endpoint checks job.downloadStorageKey
|
|
32
|
+
// != null before streaming + returns 410 Gone when storage is cleared.
|
|
33
33
|
//
|
|
34
|
-
// **idType: "uuid"**
|
|
35
|
-
//
|
|
34
|
+
// **idType: "uuid"** matches ExportJob — token IDs cross process
|
|
35
|
+
// boundaries (audit events for the DPO, possible re-issue paths).
|
|
36
36
|
|
|
37
37
|
export const exportDownloadTokenEntity = createEntity({
|
|
38
38
|
table: "read_export_download_tokens",
|
|
39
39
|
idType: "uuid",
|
|
40
40
|
|
|
41
41
|
fields: {
|
|
42
|
-
//
|
|
43
|
-
//
|
|
44
|
-
//
|
|
45
|
-
// Job gehoeren.
|
|
42
|
+
// Foreign key to export jobs. UNIQUE (see indexes) enforces one token per
|
|
43
|
+
// job. A separate token row keeps token-specific audit fields
|
|
44
|
+
// (`lastUsedAt`/IP/UA) separate from the job.
|
|
46
45
|
jobId: createTextField({
|
|
47
46
|
required: true,
|
|
48
47
|
personal: false,
|
|
@@ -58,25 +57,24 @@ export const exportDownloadTokenEntity = createEntity({
|
|
|
58
57
|
reason: "technical_reference",
|
|
59
58
|
}),
|
|
60
59
|
|
|
61
|
-
//
|
|
60
|
+
// The time the token was issued, when the job was marked done.
|
|
62
61
|
issuedAt: createTimestampField({
|
|
63
62
|
required: true,
|
|
64
63
|
}),
|
|
65
64
|
|
|
66
|
-
//
|
|
67
|
-
//
|
|
65
|
+
// The token expires at the same time as `job.expiresAt`; the worker sets both
|
|
66
|
+
// values when marking the job done.
|
|
68
67
|
expiresAt: createTimestampField({
|
|
69
68
|
required: true,
|
|
70
69
|
}),
|
|
71
70
|
|
|
72
|
-
// Audit
|
|
73
|
-
//
|
|
74
|
-
//
|
|
71
|
+
// Audit timestamp for the most recent download. NULL means the token has
|
|
72
|
+
// never been downloaded; the endpoint updates it after each successful
|
|
73
|
+
// stream.
|
|
75
74
|
lastUsedAt: createTimestampField({}),
|
|
76
75
|
|
|
77
|
-
// Audit
|
|
78
|
-
//
|
|
79
|
-
// (z.B. broken Sync-Tool).
|
|
76
|
+
// Audit count of downloads. `bigInt` accommodates pathological re-download
|
|
77
|
+
// loops, such as those caused by a broken sync tool.
|
|
80
78
|
useCount: createBigIntField({}),
|
|
81
79
|
|
|
82
80
|
// Audit: source IP of the last download. Helps the DPO investigate
|
|
@@ -99,11 +97,9 @@ export const exportDownloadTokenEntity = createEntity({
|
|
|
99
97
|
}),
|
|
100
98
|
},
|
|
101
99
|
|
|
102
|
-
//
|
|
103
|
-
//
|
|
104
|
-
//
|
|
105
|
-
// in place via update (fw#832) — sonst kollidiert der Projection-
|
|
106
|
-
// Rebuild an genau diesem Index.
|
|
100
|
+
// UNIQUE on `jobId` provides an idempotency backstop: rerunning a completed
|
|
101
|
+
// job must not create a second token aggregate. Re-runs update the existing
|
|
102
|
+
// token in place; otherwise projection rebuilds would collide on this index.
|
|
107
103
|
indexes: [
|
|
108
104
|
{
|
|
109
105
|
unique: true,
|
|
@@ -8,19 +8,18 @@ import {
|
|
|
8
8
|
createTimestampField,
|
|
9
9
|
} from "@cosmicdrift/kumiko-framework/engine";
|
|
10
10
|
|
|
11
|
-
// Export-
|
|
11
|
+
// Export-job lifecycle.
|
|
12
12
|
//
|
|
13
|
-
//
|
|
14
|
-
//
|
|
15
|
-
// pickt auf → "running" → erfolgreich "done" + downloadStorageKey gesetzt
|
|
13
|
+
// User triggers `request-export` → ExportJob (status="pending"). The worker
|
|
14
|
+
// picks it up → "running" → on success, "done" + downloadStorageKey set
|
|
16
15
|
// + expiresAt = completedAt + compliance-profile.userRights.exportDownloadTtl
|
|
17
|
-
// (per
|
|
18
|
-
//
|
|
19
|
-
//
|
|
16
|
+
// (configurable per tenant via override, default 7 days). On throw or stale
|
|
17
|
+
// timeout → "failed" with errorMessage. Stale timeout and storage-cleanup
|
|
18
|
+
// grace are also read from the compliance profile.
|
|
20
19
|
//
|
|
21
|
-
// Status
|
|
22
|
-
//
|
|
23
|
-
//
|
|
20
|
+
// Status values are constants—the single source of truth for the worker,
|
|
21
|
+
// application code (`request-export` handler), UI polling banner, and test
|
|
22
|
+
// drift guard.
|
|
24
23
|
export const EXPORT_JOB_STATUS = {
|
|
25
24
|
Pending: "pending",
|
|
26
25
|
Running: "running",
|
|
@@ -31,10 +30,10 @@ export const EXPORT_JOB_STATUS = {
|
|
|
31
30
|
export type ExportJobStatus = (typeof EXPORT_JOB_STATUS)[keyof typeof EXPORT_JOB_STATUS];
|
|
32
31
|
|
|
33
32
|
/**
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
* `expectUniqueViolation
|
|
33
|
+
* Database constraint name for the partial UNIQUE index (one active job per
|
|
34
|
+
* user). This is the single source of truth: request-export.write catches
|
|
35
|
+
* 23505 with this name as race protection, and tests pin it as the
|
|
36
|
+
* `expectUniqueViolation` argument. Renaming it propagates automatically.
|
|
38
37
|
*/
|
|
39
38
|
export const ACTIVE_JOB_CONSTRAINT = "read_export_jobs_one_active_per_user";
|
|
40
39
|
|
|
@@ -48,17 +47,16 @@ const EXPORT_JOB_STATUS_OPTIONS = [
|
|
|
48
47
|
// **Tenant-agnostic** like userTable — one job per userId across all
|
|
49
48
|
// memberships; the worker iterates cross-tenant via ctx.db.unsafeRaw (same pattern as runForgetCleanup).
|
|
50
49
|
//
|
|
51
|
-
// **Idempotency:** Partial
|
|
52
|
-
// `status IN ('pending', 'running')`.
|
|
53
|
-
//
|
|
54
|
-
//
|
|
55
|
-
//
|
|
56
|
-
//
|
|
57
|
-
// (Audit-Historie).
|
|
50
|
+
// **Idempotency:** Partial UNIQUE index on `(userId)` WHERE
|
|
51
|
+
// `status IN ('pending', 'running')`. A user with a pending job cannot start
|
|
52
|
+
// a second parallel job—the insert fails with a constraint violation, which
|
|
53
|
+
// the request-export handler catches and uses to return the existing pending
|
|
54
|
+
// job (insert-or-return). This closes the race window. Done/failed jobs can
|
|
55
|
+
// be retained indefinitely per user for audit history.
|
|
58
56
|
//
|
|
59
|
-
// **idType: "uuid"** —
|
|
60
|
-
//
|
|
61
|
-
//
|
|
57
|
+
// **idType: "uuid"** — job IDs cross process boundaries (BullMQ payloads,
|
|
58
|
+
// job-run logger, and audit events for the DPO). Serial IDs are only reliable
|
|
59
|
+
// within one process; UUIDs remain stable across processes.
|
|
62
60
|
export const exportJobEntity = createEntity({
|
|
63
61
|
table: "read_export_jobs",
|
|
64
62
|
idType: "uuid",
|
|
@@ -66,11 +64,11 @@ export const exportJobEntity = createEntity({
|
|
|
66
64
|
"One user's GDPR Art. 20 data-export request and its lifecycle: who asked, from which tenant, the pending/running/done/failed status, the timestamps, the download storage key and expiry, and any error the export worker hit.",
|
|
67
65
|
|
|
68
66
|
fields: {
|
|
69
|
-
// Tenant-
|
|
70
|
-
//
|
|
71
|
-
//
|
|
72
|
-
// (
|
|
73
|
-
//
|
|
67
|
+
// Tenant-agnostic: set when writing because the framework requires a
|
|
68
|
+
// tenant_id column, but ignored at the domain level.
|
|
69
|
+
// No maxLength — follows userTable.id and tenantMembershipsTable.userId
|
|
70
|
+
// (both have no maxLength). The userId shape is platform-wide; here it is
|
|
71
|
+
// only used for storage.
|
|
74
72
|
userId: createTextField({
|
|
75
73
|
required: true,
|
|
76
74
|
searchable: true,
|
|
@@ -78,19 +76,19 @@ export const exportJobEntity = createEntity({
|
|
|
78
76
|
reason: "pseudonymous_fk",
|
|
79
77
|
}),
|
|
80
78
|
|
|
81
|
-
// **requestedFromTenantId** —
|
|
82
|
-
//
|
|
83
|
-
//
|
|
84
|
-
//
|
|
85
|
-
//
|
|
86
|
-
//
|
|
87
|
-
//
|
|
79
|
+
// **requestedFromTenantId** — the tenant from which the user submitted the
|
|
80
|
+
// request. This persisted audit path tells the worker which compliance
|
|
81
|
+
// profile applies to the job TTL, stale timeout, and cleanup. This keeps
|
|
82
|
+
// one effective profile per request instead of changing with every
|
|
83
|
+
// cross-tenant click. The tenant is taken from the first click (option a).
|
|
84
|
+
// The column is not simply named "tenantId" to avoid confusion with the
|
|
85
|
+
// framework-generated tenant_id column.
|
|
88
86
|
//
|
|
89
|
-
// **
|
|
90
|
-
//
|
|
91
|
-
// "compliance-profiles:query:for-tenant", {})`),
|
|
92
|
-
// `executor.tenantId
|
|
93
|
-
//
|
|
87
|
+
// **Worker note:** Profile resolution must use `requestedFromTenantId`
|
|
88
|
+
// (`queryAs(systemUserOf(requestedFromTenantId),
|
|
89
|
+
// "compliance-profiles:query:for-tenant", {})`), not
|
|
90
|
+
// `executor.tenantId`; otherwise a job picked up from another tenant
|
|
91
|
+
// context would use the wrong profile.
|
|
94
92
|
requestedFromTenantId: createTextField({
|
|
95
93
|
required: true,
|
|
96
94
|
personal: false,
|
|
@@ -103,40 +101,40 @@ export const exportJobEntity = createEntity({
|
|
|
103
101
|
options: EXPORT_JOB_STATUS_OPTIONS,
|
|
104
102
|
}),
|
|
105
103
|
|
|
106
|
-
//
|
|
107
|
-
//
|
|
104
|
+
// When the user requested the job. Required because no job row exists
|
|
105
|
+
// without a request.
|
|
108
106
|
requestedAt: createTimestampField({
|
|
109
107
|
required: true,
|
|
110
108
|
sortable: true,
|
|
111
109
|
}),
|
|
112
110
|
|
|
113
|
-
//
|
|
114
|
-
//
|
|
111
|
+
// When the worker began processing the job. NULL while `pending`.
|
|
112
|
+
// Stale detection uses this together with
|
|
115
113
|
// compliance-profile.userRights.exportStaleTimeoutMinutes.
|
|
116
114
|
startedAt: createTimestampField({}),
|
|
117
115
|
|
|
118
|
-
//
|
|
119
|
-
//
|
|
116
|
+
// When the worker completed the job, successfully or with failure. NULL
|
|
117
|
+
// while `running`.
|
|
120
118
|
completedAt: createTimestampField({}),
|
|
121
119
|
|
|
122
|
-
// Storage
|
|
123
|
-
//
|
|
124
|
-
//
|
|
125
|
-
// signed
|
|
120
|
+
// Storage key of the completed ZIP file. NULL until `done`.
|
|
121
|
+
// The worker sets this and writes the ZIP bytes via
|
|
122
|
+
// storage-provider.write(key).
|
|
123
|
+
// This is not a signed URL—the download endpoint generates the signed URL
|
|
124
|
+
// on demand through the storage provider.
|
|
126
125
|
downloadStorageKey: createTextField({
|
|
127
126
|
maxLength: 500,
|
|
128
127
|
personal: false,
|
|
129
128
|
reason: "technical_reference",
|
|
130
129
|
}),
|
|
131
130
|
|
|
132
|
-
//
|
|
131
|
+
// When the download is no longer available. The worker sets
|
|
133
132
|
// `completedAt + compliance-profile.userRights.exportDownloadTtl`
|
|
134
|
-
//
|
|
133
|
+
// when switching to `done`. NULL for pending, running, and failed jobs.
|
|
135
134
|
//
|
|
136
|
-
// Storage
|
|
137
|
-
// `expiresAt + compliance-profile.userRights.exportStorageCleanupGraceHours
|
|
138
|
-
//
|
|
139
|
-
// verbleiben.
|
|
135
|
+
// Storage cleanup requirement: after
|
|
136
|
+
// `expiresAt + compliance-profile.userRights.exportStorageCleanupGraceHours`,
|
|
137
|
+
// a separate pass deletes expired ZIPs so they do not remain on S3.
|
|
140
138
|
expiresAt: createTimestampField({}),
|
|
141
139
|
|
|
142
140
|
// Failed-state diagnostics. longText because hook errors with stack
|
|
@@ -147,20 +145,20 @@ export const exportJobEntity = createEntity({
|
|
|
147
145
|
reason: "is_business_data",
|
|
148
146
|
}),
|
|
149
147
|
|
|
150
|
-
// Audit
|
|
151
|
-
//
|
|
152
|
-
//
|
|
153
|
-
// silent
|
|
148
|
+
// Audit information for operators: the export size. This supports capacity
|
|
149
|
+
// planning and detects pathological cases (a streaming ZIP containing 5 GB
|
|
150
|
+
// of files writes several billion bytes, so integer overflow would cause
|
|
151
|
+
// silent audit drift).
|
|
154
152
|
//
|
|
155
|
-
// bigInt
|
|
156
|
-
//
|
|
153
|
+
// bigInt provides a JS-`number` round trip via mode:"number", safe up to
|
|
154
|
+
// 2^53 ≈ 9 PB and suitable for JSON-based status polling.
|
|
157
155
|
bytesWritten: createBigIntField({}),
|
|
158
156
|
},
|
|
159
157
|
|
|
160
|
-
// Partial
|
|
161
|
-
//
|
|
162
|
-
//
|
|
163
|
-
//
|
|
158
|
+
// Partial UNIQUE index: only one active job per user; done/failed history
|
|
159
|
+
// is unlimited. request-export.write uses an application-side pre-check as
|
|
160
|
+
// the primary path and catches this constraint's 23505 as race protection
|
|
161
|
+
// for the <1ms window between fetchOne and crud.create.
|
|
164
162
|
indexes: [
|
|
165
163
|
{
|
|
166
164
|
unique: true,
|
|
@@ -1,30 +1,27 @@
|
|
|
1
|
-
//
|
|
1
|
+
// Generates a cryptographically secure token to authorize the export ZIP download.
|
|
2
|
+
// Follows the Magic-Link/Bearer-Token pattern with a hash stored in the database:
|
|
2
3
|
//
|
|
3
|
-
//
|
|
4
|
-
// Export-ZIP-Downloads. Pattern matched Magic-Link/Bearer-Token mit DB-
|
|
5
|
-
// gespeichertem Hash:
|
|
6
|
-
//
|
|
7
|
-
// 1. Worker generiert plain-Token (32 byte random base64url) + Hash
|
|
4
|
+
// 1. The worker generates a plain token (32 random bytes, base64url) and its hash
|
|
8
5
|
// (SHA256 hex).
|
|
9
|
-
// 2.
|
|
10
|
-
// 3.
|
|
11
|
-
// 4.
|
|
12
|
-
//
|
|
6
|
+
// 2. The database stores ONLY the hash. The plain token remains in worker memory.
|
|
7
|
+
// 3. The notification step sends the plain token to the user by email.
|
|
8
|
+
// 4. The download endpoint hashes the incoming token and compares it with the
|
|
9
|
+
// database hash using a constant-time comparison to prevent timing attacks.
|
|
13
10
|
//
|
|
14
|
-
// **Multi-use within TTL
|
|
15
|
-
//
|
|
16
|
-
//
|
|
11
|
+
// **Multi-use within TTL:** The token is NOT "consumed" on download, so the user
|
|
12
|
+
// can download repeatedly until expiresAt. This matches Google-Takeout (7d) and
|
|
13
|
+
// Facebook-Data-Download (4d).
|
|
17
14
|
//
|
|
18
15
|
// **Universal Web-Crypto API:** crypto.getRandomValues + crypto.subtle.digest
|
|
19
|
-
//
|
|
20
|
-
//
|
|
16
|
+
// runs identically in Bun, Node 19+, and browsers, avoiding platform-specific
|
|
17
|
+
// imports.
|
|
21
18
|
|
|
22
19
|
/**
|
|
23
|
-
*
|
|
24
|
-
*
|
|
20
|
+
* Generates a new download token. The plain token is sent to the user by email;
|
|
21
|
+
* the hash is stored in the token database row.
|
|
25
22
|
*
|
|
26
|
-
* Token
|
|
27
|
-
*
|
|
23
|
+
* Token format: 32 random bytes → base64url-encoded (~43 chars). URL-safe for
|
|
24
|
+
* Magic-Link use (no +/= characters that would need to be URL-encoded).
|
|
28
25
|
*/
|
|
29
26
|
export async function generateDownloadToken(): Promise<{
|
|
30
27
|
readonly plain: string;
|
|
@@ -37,11 +34,10 @@ export async function generateDownloadToken(): Promise<{
|
|
|
37
34
|
}
|
|
38
35
|
|
|
39
36
|
/**
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
* compare-helper).
|
|
37
|
+
* Hashes a plain token into its database representation. In the verification path,
|
|
38
|
+
* the download endpoint hashes the incoming token and looks up the hash in the
|
|
39
|
+
* database. A constant-time string comparison prevents timing attacks; the caller
|
|
40
|
+
* performs it via `crypto.subtle` or a secure comparison helper.
|
|
45
41
|
*/
|
|
46
42
|
export async function hashDownloadToken(plain: string): Promise<string> {
|
|
47
43
|
const encoded = new TextEncoder().encode(plain);
|
|
@@ -50,7 +46,7 @@ export async function hashDownloadToken(plain: string): Promise<string> {
|
|
|
50
46
|
}
|
|
51
47
|
|
|
52
48
|
function uint8ArrayToBase64Url(bytes: Uint8Array): string {
|
|
53
|
-
// btoa
|
|
49
|
+
// btoa expects a binary string. atob/btoa are universal in Bun, Node, and browsers.
|
|
54
50
|
let binary = "";
|
|
55
51
|
for (let i = 0; i < bytes.length; i++) {
|
|
56
52
|
binary += String.fromCharCode(bytes[i] as number); // @cast-boundary dynamic-key
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
// createKumikoApp({ clientFeatures: [userDataRightsClient()] }); the screen
|
|
7
7
|
// has no own r.nav, the app places it via r.nav.
|
|
8
8
|
//
|
|
9
|
-
//
|
|
9
|
+
// The former `privacyCenter: { showDeletion }` option is gone — a
|
|
10
10
|
// declarative screen is now registered server-side once for all apps, so a
|
|
11
11
|
// client prop can no longer toggle its sections/actions per app. Its
|
|
12
12
|
// replacement is the server-side
|
|
@@ -22,12 +22,12 @@ import { ExportSection } from "./privacy-center-screen.tsx";
|
|
|
22
22
|
import { makePublicDeletionGate, type PublicDeletionRoutes } from "./public-deletion-gate.tsx";
|
|
23
23
|
|
|
24
24
|
export type UserDataRightsClientOptions = {
|
|
25
|
-
/**
|
|
25
|
+
/** Overrides merged into the default bundles (de/en). */
|
|
26
26
|
readonly translations?: TranslationsByLocale;
|
|
27
|
-
/**
|
|
28
|
-
*
|
|
29
|
-
* privacy-center
|
|
30
|
-
*
|
|
27
|
+
/** When set, registers the anonymous (login-free) deletion screens as a
|
|
28
|
+
* gate on the specified paths. If omitted, only the authenticated
|
|
29
|
+
* privacy-center screen is available. Register this client BEFORE the auth
|
|
30
|
+
* client; otherwise, anonymous visitors are redirected to the login screen. */
|
|
31
31
|
readonly publicDeletion?: PublicDeletionRoutes;
|
|
32
32
|
};
|
|
33
33
|
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
// ConfirmAccountDeletionScreen —
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
// user-data-rights:write:confirm-deletion-by-token
|
|
1
|
+
// ConfirmAccountDeletionScreen — anonymous Apex screen, step 2. Reads the
|
|
2
|
+
// token from the URL fragment (`#token=…`, never sent to the server, so it does
|
|
3
|
+
// not appear in proxy/access logs) and dispatches
|
|
4
|
+
// user-data-rights:write:confirm-deletion-by-token on confirmation to start the
|
|
5
|
+
// grace period.
|
|
5
6
|
//
|
|
6
|
-
//
|
|
7
|
+
// The app mounts this screen at the deletionVerifyUrl route (for example,
|
|
7
8
|
// /delete-account/confirm) via createPublicSurface.
|
|
8
9
|
|
|
9
10
|
import { useDispatcher, usePrimitives, useTranslation } from "@cosmicdrift/kumiko-renderer";
|
|
@@ -17,7 +17,7 @@ export const PRIVACY_CENTER_SCREEN_ID = "privacy-center" as const;
|
|
|
17
17
|
export const EXPORT_SECTION_EXTENSION_NAME = "UserDataRightsExportSection" as const;
|
|
18
18
|
|
|
19
19
|
// enumOption keyPrefix for the privacy-center screen's `status` field
|
|
20
|
-
//
|
|
20
|
+
// pattern — resolves the raw user-lifecycle enum value
|
|
21
21
|
// (active/restricted/deletionRequested/deleted) to a translated label
|
|
22
22
|
// instead of showing the raw string.
|
|
23
23
|
export const STATUS_OPTION_KEY_PREFIX =
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
// Public exports
|
|
2
|
-
//
|
|
3
|
-
// `@cosmicdrift/kumiko-bundled-features/user-data-rights/web`.
|
|
4
|
-
//
|
|
5
|
-
//
|
|
1
|
+
// Public exports for the browser side of the user-data-rights feature —
|
|
2
|
+
// the anonymous Apex deletion screens. Consumed via the subpath export
|
|
3
|
+
// `@cosmicdrift/kumiko-bundled-features/user-data-rights/web`. The server
|
|
4
|
+
// side (defineFeature, Handler) lives under `.../user-data-rights` and has
|
|
5
|
+
// no React/DOM dependencies.
|
|
6
6
|
|
|
7
7
|
export { type UserDataRightsClientOptions, userDataRightsClient } from "./client-plugin.tsx";
|
|
8
8
|
export type { ConfirmAccountDeletionScreenProps } from "./confirm-deletion-screen.tsx";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { EMPTY_VALUE_PLACEHOLDER } from "@cosmicdrift/kumiko-renderer/headless";
|
|
2
2
|
// Export section (Art. 20) — the one part of user-data-rights' privacy-center
|
|
3
|
-
// screen that stays custom
|
|
3
|
+
// screen that stays custom. Registered as an EditExtensionSection
|
|
4
4
|
// component (see web/client-plugin.tsx); the projectionDetail screen
|
|
5
5
|
// (feature.ts) supplies the surrounding Section chrome (title, testId), so
|
|
6
6
|
// this component renders only its own body content.
|
|
@@ -26,9 +26,9 @@ import {
|
|
|
26
26
|
UserDataRightsQueries,
|
|
27
27
|
} from "./constants.ts";
|
|
28
28
|
|
|
29
|
-
//
|
|
30
|
-
//
|
|
31
|
-
//
|
|
29
|
+
// The export job runs asynchronously (worker-Lane-Cron, ~1 Min). While it is
|
|
30
|
+
// pending/running, the screen polls its status so the download appears without
|
|
31
|
+
// a manual reload.
|
|
32
32
|
const EXPORT_POLL_MS = 4000;
|
|
33
33
|
|
|
34
34
|
type ExportJob = {
|
|
@@ -47,15 +47,16 @@ type SectionStatus =
|
|
|
47
47
|
| { kind: "success"; messageKey: string }
|
|
48
48
|
| { kind: "error"; messageKey: string };
|
|
49
49
|
|
|
50
|
-
// Dispatcher
|
|
51
|
-
//
|
|
50
|
+
// Dispatcher failures include i18nKey only when the handler sets one; read it
|
|
51
|
+
// at the boundary with a generic fallback.
|
|
52
52
|
function failureKey(error: unknown): string {
|
|
53
53
|
const key = propertyOf(error, "i18nKey");
|
|
54
54
|
return typeof key === "string" ? key : "userDataRights.privacyCenter.errors.generic";
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
-
//
|
|
58
|
-
//
|
|
57
|
+
// Only the date portion of the raw ISO instant is relevant; use a string slice
|
|
58
|
+
// instead of the Date API (no-date-api-Guard) for universal support. Empty/null
|
|
59
|
+
// values become "—".
|
|
59
60
|
export function formatDate(iso: string | null | undefined): string {
|
|
60
61
|
if (!iso) return EMPTY_VALUE_PLACEHOLDER;
|
|
61
62
|
const tIndex = iso.indexOf("T");
|
|
@@ -97,10 +98,10 @@ export function ExportSection(): ReactNode {
|
|
|
97
98
|
void statusQuery.refetch?.();
|
|
98
99
|
};
|
|
99
100
|
|
|
100
|
-
// Download
|
|
101
|
-
//
|
|
102
|
-
//
|
|
103
|
-
// attachment →
|
|
101
|
+
// Download runs through the dispatcher (which supplies X-CSRF-Token) instead of
|
|
102
|
+
// an <a>-navigation: download-by-job returns a signed URL, which
|
|
103
|
+
// postWithDownload navigates the browser to (content-disposition:
|
|
104
|
+
// attachment → triggers a download).
|
|
104
105
|
const downloadExport = async (jobId: string): Promise<void> => {
|
|
105
106
|
const err = await postWithDownload(dispatcher, UserDataRightsQueries.downloadByJob, { jobId });
|
|
106
107
|
if (err) setStatus({ kind: "error", messageKey: failureKey(err) });
|
|
@@ -116,7 +117,7 @@ export function ExportSection(): ReactNode {
|
|
|
116
117
|
|
|
117
118
|
// While the job is running: poll until Done/Failed, then auto-stop.
|
|
118
119
|
const refetch = statusQuery.refetch;
|
|
119
|
-
// kumiko-lint-ignore no-raw-hooks
|
|
120
|
+
// kumiko-lint-ignore no-raw-hooks not yet converted to the framework hook set
|
|
120
121
|
useEffect(() => {
|
|
121
122
|
if (!inProgress || !refetch) return;
|
|
122
123
|
const id = setInterval(() => void refetch(), EXPORT_POLL_MS);
|