@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,25 +1,26 @@
|
|
|
1
|
-
// Public
|
|
1
|
+
// Public gate for anonymous account deletion. Matches window.location.pathname:
|
|
2
2
|
// requestPath → RequestAccountDeletionScreen, confirmPath →
|
|
3
|
-
// ConfirmAccountDeletionScreen,
|
|
4
|
-
// (auth-email-password) — userDataRightsClient
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
// (
|
|
3
|
+
// ConfirmAccountDeletionScreen, otherwise passes through to the app. Mirrors
|
|
4
|
+
// makeAuthGate (auth-email-password) — userDataRightsClient adds it as a gate,
|
|
5
|
+
// and the app lists this client BEFORE the auth client so an anonymous visitor
|
|
6
|
+
// sees the deletion screen instead of the login screen. Matching during render:
|
|
7
|
+
// Apex transitions (the verification link) are full-page loads, not client-router
|
|
8
|
+
// transitions.
|
|
8
9
|
//
|
|
9
|
-
// confirmPath
|
|
10
|
-
//
|
|
10
|
+
// confirmPath MUST match the path of the server-side deletionVerifyUrl —
|
|
11
|
+
// ConfirmScreen reads the ?token from that URL.
|
|
11
12
|
|
|
12
13
|
import type { ComponentType, ReactNode } from "react";
|
|
13
14
|
import { ConfirmAccountDeletionScreen } from "./confirm-deletion-screen.tsx";
|
|
14
15
|
import { RequestAccountDeletionScreen } from "./request-deletion-screen.tsx";
|
|
15
16
|
|
|
16
17
|
export type PublicDeletionRoutes = {
|
|
17
|
-
/** Login-
|
|
18
|
+
/** Login-free route for the email request screen (e.g. "/account/delete"). */
|
|
18
19
|
readonly requestPath: string;
|
|
19
|
-
/** Login-
|
|
20
|
+
/** Login-free route for token confirmation; path of deletionVerifyUrl. */
|
|
20
21
|
readonly confirmPath: string;
|
|
21
|
-
/**
|
|
22
|
-
* defaultShell). Apps
|
|
22
|
+
/** Shell around the screen card. Default: full-screen centered (like the auth-
|
|
23
|
+
* defaultShell). Apps can provide their own shell (e.g. a marketing header). */
|
|
23
24
|
readonly shell?: (screen: ReactNode) => ReactNode;
|
|
24
25
|
};
|
|
25
26
|
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
// RequestAccountDeletionScreen —
|
|
2
|
-
// → user-data-rights:write:request-deletion-by-email. Enumeration-safe:
|
|
3
|
-
//
|
|
4
|
-
//
|
|
1
|
+
// RequestAccountDeletionScreen — anonymous Apex screen, step 1: email form
|
|
2
|
+
// → user-data-rights:write:request-deletion-by-email. Enumeration-safe: always
|
|
3
|
+
// shows a "If an account exists, the email is on its way" confirmation, even
|
|
4
|
+
// when the server has determined internally that the email does not exist.
|
|
5
5
|
//
|
|
6
|
-
//
|
|
7
|
-
// createPublicSurface;
|
|
6
|
+
// The app mounts this screen at an Apex route (e.g. /delete-account) via
|
|
7
|
+
// createPublicSurface; the page shell provides the surrounding chrome.
|
|
8
8
|
|
|
9
9
|
import { useDispatcher, usePrimitives, useTranslation } from "@cosmicdrift/kumiko-renderer";
|
|
10
10
|
import { type FormEvent, type ReactNode, useState } from "react";
|
|
@@ -1,52 +1,52 @@
|
|
|
1
|
-
// Shared helper
|
|
1
|
+
// Shared helper for computing ZIP paths from fileRefs.
|
|
2
2
|
//
|
|
3
|
-
//
|
|
4
|
-
// 1. bundle.json:
|
|
5
|
-
//
|
|
6
|
-
// 2. ZIP
|
|
3
|
+
// The bundle has two views of the same fileRefs:
|
|
4
|
+
// 1. bundle.json: A flat list with `zipPath` for each fileRef. Reader
|
|
5
|
+
// tools can use this to link JSON to files/-paths.
|
|
6
|
+
// 2. ZIP entries: Bytes are stored under exactly these `zipPath` keys.
|
|
7
7
|
//
|
|
8
|
-
//
|
|
9
|
-
//
|
|
10
|
-
// run-export-jobs's bundleToZipEntries
|
|
11
|
-
// Keys.
|
|
8
|
+
// To keep both views synchronized, path computation lives EXACTLY ONCE here.
|
|
9
|
+
// run-user-export fills zipPath in the fileRef item, and
|
|
10
|
+
// run-export-jobs's bundleToZipEntries uses the same paths as entry keys.
|
|
12
11
|
|
|
13
12
|
import type { TenantId } from "@cosmicdrift/kumiko-framework/engine";
|
|
14
13
|
|
|
15
14
|
/**
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
* (PKWARE
|
|
19
|
-
*
|
|
15
|
+
* Maximum length of the sanitized fileName without its extension. Realistic
|
|
16
|
+
* filenames are <50; 100 is a safe limit for ZIP compatibility
|
|
17
|
+
* (the PKWARE spec has no hard limit, but many readers struggle with
|
|
18
|
+
* extremely long names).
|
|
20
19
|
*/
|
|
21
20
|
const MAX_SANITIZED_BASENAME_LENGTH = 100;
|
|
22
21
|
|
|
23
22
|
/**
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
* relative
|
|
23
|
+
* Allowed filename chars: alphanumerics, dot, dash, underscore. Everything
|
|
24
|
+
* else is replaced with an underscore. This excludes path separators (`/`,
|
|
25
|
+
* `\`) and null bytes in particular; relative traversal (`..`) is handled
|
|
26
|
+
* by the basename and leading-dot rules below.
|
|
27
27
|
*/
|
|
28
28
|
const FILENAME_SAFE_CHARS = /[^a-zA-Z0-9._-]/g;
|
|
29
29
|
|
|
30
30
|
/**
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
* -
|
|
34
|
-
* -
|
|
35
|
-
* -
|
|
36
|
-
* - Reserved-Names: "." / ".." / "..." → "file"
|
|
31
|
+
* Sanitizes a user-provided fileName for use as a ZIP-internal-path suffix.
|
|
32
|
+
* - Path traversal: "../../etc/passwd" → "file.etc_passwd"
|
|
33
|
+
* - Null bytes: "report\x00.pdf" → "report_.pdf"
|
|
34
|
+
* - Path separators: "sub/dir/file.txt" → "sub_dir_file.txt"
|
|
35
|
+
* - Reserved names: "." / ".." / "..." → "file"
|
|
37
36
|
* - Empty input: "" / null / undef → "unnamed"
|
|
38
|
-
* -
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
37
|
+
* - Excessive length: long strings are truncated to
|
|
38
|
+
* MAX_SANITIZED_BASENAME_LENGTH
|
|
39
|
+
* (the extension is preserved when present)
|
|
40
|
+
* - Unicode: non-ASCII characters → underscores. Leading stripping
|
|
41
|
+
* can also cause all-Unicode names to become "file".
|
|
42
42
|
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
43
|
+
* The output is guaranteed to be non-empty, contain no path separators, obey
|
|
44
|
+
* the maximum length, and contain no `..` sequence.
|
|
45
45
|
*/
|
|
46
46
|
export function sanitizeZipFilename(raw: string): string {
|
|
47
47
|
if (raw === undefined || raw === null || raw === "") return "unnamed";
|
|
48
48
|
|
|
49
|
-
//
|
|
49
|
+
// Extract the extension (the last ".X" where X contains no ".").
|
|
50
50
|
const lastDot = raw.lastIndexOf(".");
|
|
51
51
|
const hasExt = lastDot > 0 && lastDot < raw.length - 1;
|
|
52
52
|
const baseName = hasExt ? raw.slice(0, lastDot) : raw;
|
|
@@ -55,20 +55,21 @@ export function sanitizeZipFilename(raw: string): string {
|
|
|
55
55
|
const safeBase = collapseUnsafe(baseName).slice(0, MAX_SANITIZED_BASENAME_LENGTH);
|
|
56
56
|
const safeExt = collapseUnsafe(extension).slice(0, 20);
|
|
57
57
|
|
|
58
|
-
// Empty
|
|
58
|
+
// Empty or all-underscore input → "file" as a reproducible fallback.
|
|
59
59
|
const finalBase = safeBase.length === 0 ? "file" : safeBase;
|
|
60
60
|
|
|
61
61
|
return safeExt.length > 0 ? `${finalBase}.${safeExt}` : finalBase;
|
|
62
62
|
}
|
|
63
63
|
|
|
64
64
|
/**
|
|
65
|
-
*
|
|
66
|
-
* 1. Replace
|
|
67
|
-
* 2. Collapse `..` (
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
*
|
|
71
|
-
*
|
|
65
|
+
* Three-step sanitization:
|
|
66
|
+
* 1. Replace everything except [a-zA-Z0-9._-] with "_".
|
|
67
|
+
* 2. Collapse `..` (or more) to "_"—this prevents `..` from surviving
|
|
68
|
+
* sanitization (for example, when the input contains only dots and
|
|
69
|
+
* slashes).
|
|
70
|
+
* 3. Strip leading [._-]+—this prevents hidden-file patterns, empty
|
|
71
|
+
* basenames, and leading segments that would consist entirely of
|
|
72
|
+
* underscores after the first two steps.
|
|
72
73
|
*/
|
|
73
74
|
function collapseUnsafe(s: string): string {
|
|
74
75
|
let out = s.replace(FILENAME_SAFE_CHARS, "_");
|
|
@@ -78,11 +79,11 @@ function collapseUnsafe(s: string): string {
|
|
|
78
79
|
}
|
|
79
80
|
|
|
80
81
|
/**
|
|
81
|
-
*
|
|
82
|
+
* Computes the ZIP-internal path for a fileRef. Layout:
|
|
82
83
|
* files/<tenantId>/<fileRefId>-<sanitized-fileName>
|
|
83
84
|
*
|
|
84
|
-
* tenantId
|
|
85
|
-
* sanitizeZipFilename.
|
|
85
|
+
* tenantId and fileRefId have UUID shapes and are safe; fileName is passed
|
|
86
|
+
* through sanitizeZipFilename. Path traversal is guaranteed to be excluded.
|
|
86
87
|
*/
|
|
87
88
|
export function buildFileRefZipPath(args: {
|
|
88
89
|
readonly tenantId: TenantId;
|
|
@@ -36,23 +36,23 @@ import {
|
|
|
36
36
|
userSessionExportHook,
|
|
37
37
|
} from "./hooks/user-session.userdata-hook.ts";
|
|
38
38
|
|
|
39
|
-
// user-data-rights-defaults — Default
|
|
40
|
-
// `user`
|
|
39
|
+
// user-data-rights-defaults — Default hooks for the core entities
|
|
40
|
+
// `user` and `fileRef`.
|
|
41
41
|
//
|
|
42
|
-
//
|
|
43
|
-
//
|
|
44
|
-
//
|
|
45
|
-
//
|
|
46
|
-
//
|
|
42
|
+
// Architectural decision: user-data-rights itself cannot call
|
|
43
|
+
// r.requires({ features: ["user", "files"] }) + r.useExtension(EXT_USER_DATA, ...)
|
|
44
|
+
// because it provides EXT_USER_DATA itself (the boot validator rejects
|
|
45
|
+
// self-extension). The solution is a third, optionally mountable feature
|
|
46
|
+
// that requires both sources and makes the useExtension calls.
|
|
47
47
|
//
|
|
48
|
-
// App
|
|
49
|
-
//
|
|
50
|
-
//
|
|
51
|
-
//
|
|
48
|
+
// App authors can omit this feature if they want to register custom hooks
|
|
49
|
+
// instead (for example, "anonymize should hard-delete the user row" — an
|
|
50
|
+
// app-specific compliance decision). The default implementation covers 95%
|
|
51
|
+
// of apps.
|
|
52
52
|
//
|
|
53
|
-
//
|
|
54
|
-
//
|
|
55
|
-
//
|
|
53
|
+
// This follows the file-foundation + file-provider-s3 pattern (separate
|
|
54
|
+
// plugin features): user/files do not define their own hooks because that
|
|
55
|
+
// would create circular requires.
|
|
56
56
|
// Binary storage for the fileRef delete-hook is resolved at run time from the
|
|
57
57
|
// mounted file-foundation via ctx.buildStorageProvider (injected by the forget
|
|
58
58
|
// orchestrator) — no provider is captured here, so a single app-wide store and
|
|
@@ -123,7 +123,7 @@ export function createUserDataRightsDefaultsFeature(): FeatureDefinition {
|
|
|
123
123
|
delete: configValueDeleteHook,
|
|
124
124
|
});
|
|
125
125
|
|
|
126
|
-
// Events-only aggregates
|
|
126
|
+
// Events-only aggregates: export reads the projected rows, the
|
|
127
127
|
// delete hooks are deliberate no-ops — erasure happens via crypto-
|
|
128
128
|
// shredding (forget erases the user's DEK; recipientAddress / job
|
|
129
129
|
// payload become unreadable in events AND rows).
|
|
@@ -9,11 +9,9 @@ import {
|
|
|
9
9
|
} from "../../delivery/index.ts";
|
|
10
10
|
import { featureMounted } from "./feature-mounted.ts";
|
|
11
11
|
|
|
12
|
-
// userData-Hooks for delivery's attempt log
|
|
13
|
-
//
|
|
14
|
-
//
|
|
15
|
-
// the export runner's central decrypt sweep resolves to plaintext (or
|
|
16
|
-
// [[erased]] after a forget).
|
|
12
|
+
// userData-Hooks for delivery's attempt log. deliveryAttempt is an events-only aggregate — the
|
|
13
|
+
// export reads the projected rows; recipientAddress may be ciphertext (kumiko-pii:), which the
|
|
14
|
+
// export runner's central decrypt sweep resolves to plaintext (or [[erased]] after a forget).
|
|
17
15
|
|
|
18
16
|
export const deliveryAttemptExportHook: UserDataExportHook = async (ctx) => {
|
|
19
17
|
if (!featureMounted(ctx, "delivery")) return null;
|
package/packages/bundled-features/src/user-data-rights-defaults/hooks/file-ref.userdata-hook.ts
CHANGED
|
@@ -30,68 +30,64 @@ const ERROR_CONTEXT = "user-data-rights-defaults:fileRef";
|
|
|
30
30
|
// per-user forget flows are rare, so per-row events are acceptable.
|
|
31
31
|
const crud = createEventStoreExecutor(fileRefsTable, fileRefEntity, { entityName: "fileRef" });
|
|
32
32
|
|
|
33
|
-
//
|
|
33
|
+
// User-data hook for the fileRef entity.
|
|
34
34
|
//
|
|
35
|
-
//
|
|
36
|
-
//
|
|
37
|
-
//
|
|
38
|
-
//
|
|
35
|
+
// The export hook returns metadata for all of the user's FileRefs, with the
|
|
36
|
+
// subject resolved through insertedById. Storage-provider binary streams are
|
|
37
|
+
// not included directly; signed download URLs package them into the ZIP
|
|
38
|
+
// separately.
|
|
39
39
|
//
|
|
40
|
-
//
|
|
40
|
+
// The delete hook removes the fileRef row and binary:
|
|
41
41
|
// "delete": storageProvider.delete() per file + row hard-delete — but
|
|
42
42
|
// ONLY for rows whose field is marked as PII of the person
|
|
43
|
-
// (isPersonalFileRow
|
|
44
|
-
//
|
|
45
|
-
//
|
|
46
|
-
//
|
|
47
|
-
//
|
|
48
|
-
// "anonymize": insertedById=null
|
|
49
|
-
// point at it; person-link removed)
|
|
43
|
+
// (isPersonalFileRow). All other rows (business/tenant data,
|
|
44
|
+
// no resolvable field, no annotation) go through
|
|
45
|
+
// severPersonLink instead, even when the entity strategy is
|
|
46
|
+
// "delete" — the uploader axis (insertedById) is not the
|
|
47
|
+
// subject axis.
|
|
48
|
+
// "anonymize": insertedById=null; row and binary survive (FK refs can still
|
|
49
|
+
// point at it; person-link removed). This applies to ALL rows
|
|
50
50
|
// when a retention override on fileRef (anonymize or
|
|
51
51
|
// blockDelete, e.g. a statutory retention duty) sets the
|
|
52
52
|
// strategy, regardless of the field.
|
|
53
53
|
//
|
|
54
|
-
// **Provider
|
|
55
|
-
// `ctx.buildStorageProvider(ctx.tenantId)
|
|
56
|
-
//
|
|
57
|
-
//
|
|
58
|
-
//
|
|
54
|
+
// **Provider resolution:** the provider is obtained at runtime from
|
|
55
|
+
// `ctx.buildStorageProvider(ctx.tenantId)`. The forget orchestrator builds it
|
|
56
|
+
// from the mounted file-foundation, using the SAME store as upload and export
|
|
57
|
+
// (delete-target == upload-target by construction). No provider is captured at
|
|
58
|
+
// mount time.
|
|
59
59
|
//
|
|
60
|
-
// **
|
|
61
|
-
// 1. Resolution
|
|
62
|
-
//
|
|
63
|
-
//
|
|
64
|
-
//
|
|
65
|
-
//
|
|
66
|
-
//
|
|
67
|
-
//
|
|
68
|
-
//
|
|
69
|
-
//
|
|
70
|
-
//
|
|
71
|
-
//
|
|
72
|
-
//
|
|
73
|
-
// Rollback" der Sprint-2-Atomicity bleibt gewahrt: nur DIESE Sub-Tx rollt
|
|
74
|
-
// zurueck. Der anonymize-Pfad behaelt Row+binary, hat nichts zu schlucken.
|
|
60
|
+
// **Two error classes are handled differently:**
|
|
61
|
+
// 1. Resolution fails (no provider configured / configResolver missing) →
|
|
62
|
+
// NOT fail-closed: warn per invocation and perform a row-only delete. A
|
|
63
|
+
// misconfigured store must not permanently block the Art. 17 deletion;
|
|
64
|
+
// the boot guard exposes the misconfiguration, and binaries are removed
|
|
65
|
+
// once a provider exists.
|
|
66
|
+
// 2. Binary DELETE fails even though a provider exists → FAIL-CLOSED: the
|
|
67
|
+
// hook throws after the loop, the per-user sub-transaction rolls back,
|
|
68
|
+
// the user remains DeletionRequested, and the next run retries (delete is
|
|
69
|
+
// idempotent → converges). Swallowing the error and deleting the row would
|
|
70
|
+
// mark erasure as "done" while leaving the bytes behind. Only this
|
|
71
|
+
// sub-transaction rolls back; there is no global rollback. The anonymize
|
|
72
|
+
// path retains the row and binary, so it has no error to swallow.
|
|
75
73
|
//
|
|
76
|
-
// Caveat: hard-delete via deleteMany
|
|
77
|
-
//
|
|
78
|
-
//
|
|
79
|
-
//
|
|
80
|
-
// bounded; ein executor.purge-API folgt mit dem trashed-files-GC.
|
|
74
|
+
// Caveat: hard-delete via deleteMany emits no fileRef.deleted event, so
|
|
75
|
+
// storage-tracking does not decrement. If the files being deleted were not
|
|
76
|
+
// soft-deleted first, `tenant_storage_usage` remains inflated. Forget flows are
|
|
77
|
+
// rare and bounded; an executor.purge API will follow with trashed-files GC.
|
|
81
78
|
|
|
82
79
|
export const fileRefExportHook: UserDataExportHook = async (ctx) => {
|
|
83
|
-
// isDeleted:false — soft-deleted (trashed)
|
|
84
|
-
//
|
|
80
|
+
// isDeleted:false — soft-deleted (trashed) files are excluded from the
|
|
81
|
+
// export bundle. The forget hook below still processes them.
|
|
85
82
|
const rawRows = await ctx.db.selectMany(fileRefsTable, {
|
|
86
83
|
tenantId: ctx.tenantId,
|
|
87
84
|
insertedById: ctx.userId,
|
|
88
85
|
isDeleted: false,
|
|
89
86
|
});
|
|
90
87
|
|
|
91
|
-
// @cast-boundary db-row: drizzle
|
|
92
|
-
// (framework-customType).
|
|
93
|
-
// .toString()
|
|
94
|
-
// Date.
|
|
88
|
+
// @cast-boundary db-row: drizzle returns insertedAt as an Instant
|
|
89
|
+
// (framework-customType). JSON export requires a string —
|
|
90
|
+
// .toString() works for both Temporal.Instant and Date.
|
|
95
91
|
const rows = rawRows.map((r) => {
|
|
96
92
|
const row = r as Record<string, unknown>; // @cast-boundary recursive-walk
|
|
97
93
|
return {
|
|
@@ -115,9 +111,8 @@ export const fileRefExportHook: UserDataExportHook = async (ctx) => {
|
|
|
115
111
|
size: r.size,
|
|
116
112
|
insertedAt: r.insertedAt,
|
|
117
113
|
})),
|
|
118
|
-
//
|
|
119
|
-
//
|
|
120
|
-
// UserDataExportSnippet.fileRefs).
|
|
114
|
+
// The fileRefs list is passed to the storage provider, which generates
|
|
115
|
+
// signed URLs and adds the files to the ZIP.
|
|
121
116
|
fileRefs: rows.map((r) => ({
|
|
122
117
|
fileRefId: r.id,
|
|
123
118
|
storageKey: r.storageKey,
|
|
@@ -142,7 +137,7 @@ async function resolveProvider(ctx: UserDataHookCtx): Promise<UserDataStoragePro
|
|
|
142
137
|
}
|
|
143
138
|
}
|
|
144
139
|
|
|
145
|
-
// Per-row Art.17 decision
|
|
140
|
+
// Per-row Art.17 decision: whether THIS file's field
|
|
146
141
|
// carries personal data of the forgotten person, or is business/tenant data
|
|
147
142
|
// that merely loses its uploader-attribution. insertedById names who
|
|
148
143
|
// UPLOADED the file, not whose data it is — a dealer's vehicle photo
|
|
@@ -163,8 +158,7 @@ function isPersonalPiiField(field: FieldDefinition | undefined): boolean {
|
|
|
163
158
|
);
|
|
164
159
|
}
|
|
165
160
|
|
|
166
|
-
// Three cases the field-lookup itself can't resolve
|
|
167
|
-
// the non-resolvable cases):
|
|
161
|
+
// Three cases the field-lookup itself can't resolve:
|
|
168
162
|
// 1. Unattached upload (entityType/fieldName both null) → hard-delete: a
|
|
169
163
|
// file with no entity binding belongs to nobody but its uploader.
|
|
170
164
|
// 2. Field exists but carries no PII annotation → anonymize (the
|
|
@@ -244,7 +238,7 @@ export const fileRefDeleteHook: UserDataDeleteHook = async (ctx, strategy) => {
|
|
|
244
238
|
}
|
|
245
239
|
|
|
246
240
|
// strategy="delete" decides PER ROW based on the field, not uniformly
|
|
247
|
-
//
|
|
241
|
+
// only rows whose field is marked as PII of the person (or
|
|
248
242
|
// unattached, see isPersonalFileRow) take the hard path. Everything else
|
|
249
243
|
// only loses the uploader link.
|
|
250
244
|
const personalRows: Record<string, unknown>[] = [];
|
package/packages/bundled-features/src/user-data-rights-defaults/hooks/job-run.userdata-hook.ts
CHANGED
|
@@ -2,7 +2,7 @@ import type { UserDataDeleteHook, UserDataExportHook } from "@cosmicdrift/kumiko
|
|
|
2
2
|
import { jobRunsTable } from "../../jobs/index.ts";
|
|
3
3
|
import { featureMounted } from "./feature-mounted.ts";
|
|
4
4
|
|
|
5
|
-
// userData-Hooks for the jobs run log
|
|
5
|
+
// userData-Hooks for the jobs run log.
|
|
6
6
|
// Job runs live on the SYSTEM tenant regardless of who triggered them, so
|
|
7
7
|
// the export filters by triggeredById only — Art. 15 covers everything the
|
|
8
8
|
// user caused, across tenants. payload may be ciphertext (kumiko-pii:); the
|
|
@@ -29,6 +29,6 @@ export const jobRunExportHook: UserDataExportHook = async (ctx) => {
|
|
|
29
29
|
export const jobRunDeleteHook: UserDataDeleteHook = async () => {
|
|
30
30
|
// Deliberate no-op: erasure runs via crypto-shredding — the forget pipeline
|
|
31
31
|
// erases the triggering user's DEK, which makes the payload unreadable in
|
|
32
|
-
// BOTH the append-only events and the projected rows
|
|
32
|
+
// BOTH the append-only events and the projected rows. triggeredById
|
|
33
33
|
// itself is a pseudonymous fk (plaintext by design, like config.userId).
|
|
34
34
|
};
|
|
@@ -17,7 +17,7 @@ import { featureMounted } from "./feature-mounted.ts";
|
|
|
17
17
|
// the forget verb.
|
|
18
18
|
//
|
|
19
19
|
// The delivery ATTEMPTS log is covered separately: export via
|
|
20
|
-
// delivery-attempt.userdata-hook.ts, erasure via crypto-shredding
|
|
20
|
+
// delivery-attempt.userdata-hook.ts, erasure via crypto-shredding.
|
|
21
21
|
|
|
22
22
|
const crud = createEventStoreExecutor(notificationPreferencesTable, notificationPreferenceEntity, {
|
|
23
23
|
entityName: "notification-preference",
|
package/packages/bundled-features/src/user-data-rights-defaults/hooks/user-session.userdata-hook.ts
CHANGED
|
@@ -5,9 +5,9 @@ import { featureMounted } from "./feature-mounted.ts";
|
|
|
5
5
|
// userData-Hooks for the sessions feature's user-session rows (ip, userAgent).
|
|
6
6
|
//
|
|
7
7
|
// user-session is an unmanaged direct-write store (no event stream, excluded
|
|
8
|
-
// from projection rebuilds
|
|
9
|
-
//
|
|
10
|
-
//
|
|
8
|
+
// from projection rebuilds, see sessions/feature.ts), so a direct DELETE is
|
|
9
|
+
// legal here and survives rebuilds; the executor path the ES entities use does
|
|
10
|
+
// not apply.
|
|
11
11
|
//
|
|
12
12
|
// Both forget strategies hard-delete: a session row without its user is
|
|
13
13
|
// worthless (revocation audit trail loses its subject), and ip/userAgent are
|
|
@@ -20,25 +20,25 @@ import {
|
|
|
20
20
|
// A direct write would be wiped on rebuild — the Art.17 hole this fixes.
|
|
21
21
|
const crud = createEventStoreExecutor(userTable, userEntity, { entityName: "user" });
|
|
22
22
|
|
|
23
|
-
//
|
|
23
|
+
// The user-data hook for the user entity.
|
|
24
24
|
//
|
|
25
|
-
//
|
|
26
|
-
// (passwordHash, roles, status —
|
|
27
|
-
//
|
|
28
|
-
//
|
|
25
|
+
// The export hook returns profile data without security-sensitive fields
|
|
26
|
+
// (passwordHash, roles, status — GDPR Art. 20 covers portability of data
|
|
27
|
+
// the user provided themselves, not lifecycle metadata or authorization
|
|
28
|
+
// state).
|
|
29
29
|
//
|
|
30
|
-
//
|
|
31
|
-
// softDelete
|
|
32
|
-
//
|
|
33
|
-
//
|
|
30
|
+
// The delete hook anonymizes PII and sets status=deleted. The actual
|
|
31
|
+
// softDelete flag is set through Drizzle's deletedAt column; the row remains
|
|
32
|
+
// for the audit trail (all foreign-key references to user.id remain valid).
|
|
33
|
+
// This complies with GDPR through PII anonymization.
|
|
34
34
|
//
|
|
35
35
|
// Strategy:
|
|
36
|
-
// "delete": softDelete + email/displayName/passwordHash
|
|
37
|
-
// status=deleted (
|
|
38
|
-
// "anonymize": email/displayName
|
|
39
|
-
//
|
|
40
|
-
//
|
|
41
|
-
//
|
|
36
|
+
// "delete": softDelete + clear email/displayName/passwordHash,
|
|
37
|
+
// status=deleted (login blocked)
|
|
38
|
+
// "anonymize": replace email/displayName with pseudonyms; the row remains
|
|
39
|
+
// active when the user row is still needed as a foreign-key
|
|
40
|
+
// target but PII must be removed (for example, anonymization
|
|
41
|
+
// with a blockDelete deadline on a foreign-key target entity)
|
|
42
42
|
|
|
43
43
|
export const userExportHook: UserDataExportHook = async (ctx) => {
|
|
44
44
|
const row = await ctx.db.fetchOne<{
|
|
@@ -66,11 +66,11 @@ export const userExportHook: UserDataExportHook = async (ctx) => {
|
|
|
66
66
|
};
|
|
67
67
|
|
|
68
68
|
export const userDeleteHook: UserDataDeleteHook = async (ctx, strategy) => {
|
|
69
|
-
// Idempotent:
|
|
70
|
-
//
|
|
71
|
-
//
|
|
72
|
-
//
|
|
73
|
-
//
|
|
69
|
+
// Idempotent: a second call finds the row already anonymized and skips
|
|
70
|
+
// implicitly (UPDATE with the same values). Event-store tenant
|
|
71
|
+
// consistency requires ctx.tenantId to correlate with the row in
|
|
72
|
+
// the user table — user.id is tenant-agnostic (a user can be a member in
|
|
73
|
+
// multiple tenants), so no tenantId filter is needed.
|
|
74
74
|
|
|
75
75
|
// System actor + skipOptimisticLock: the forget pipeline has no read
|
|
76
76
|
// version and writes privileged identity columns ("system" is privileged).
|
|
@@ -81,12 +81,13 @@ export const userDeleteHook: UserDataDeleteHook = async (ctx, strategy) => {
|
|
|
81
81
|
const systemUser = createSystemUser(ctx.tenantId);
|
|
82
82
|
|
|
83
83
|
if (strategy === "delete") {
|
|
84
|
-
// PII
|
|
85
|
-
//
|
|
86
|
-
//
|
|
87
|
-
// loadById (isDeleted:false)
|
|
88
|
-
// (not_found). status=Deleted
|
|
89
|
-
// idempotent
|
|
84
|
+
// Remove PII and set status=deleted via an event, so a rebuild replays
|
|
85
|
+
// the forget operation. Do NOT use softDelete: user is systemStream (a
|
|
86
|
+
// tenant-agnostic row), and forgetting runs once per tenant. Setting
|
|
87
|
+
// isDeleted would cause loadById (isDeleted:false) to miss the row for
|
|
88
|
+
// the second tenant (not_found). status=Deleted blocks login; the row
|
|
89
|
+
// remains findable and idempotent across tenant passes, as with the old
|
|
90
|
+
// raw UPDATE.
|
|
90
91
|
await crud.update(
|
|
91
92
|
{
|
|
92
93
|
id: ctx.userId,
|
|
@@ -105,11 +106,11 @@ export const userDeleteHook: UserDataDeleteHook = async (ctx, strategy) => {
|
|
|
105
106
|
{ skipOptimisticLock: true, writePurpose: WritePurposes.erasure },
|
|
106
107
|
);
|
|
107
108
|
} else {
|
|
108
|
-
//
|
|
109
|
-
//
|
|
110
|
-
//
|
|
111
|
-
//
|
|
112
|
-
//
|
|
109
|
+
// Anonymize PII, but keep the row active so foreign-key references
|
|
110
|
+
// remain resolvable. The account can still be used if the user
|
|
111
|
+
// authenticates again — pragmatically acceptable because "anonymize"
|
|
112
|
+
// on the user entity is a rare edge case (hard deletion is typical for
|
|
113
|
+
// users).
|
|
113
114
|
await crud.update(
|
|
114
115
|
{
|
|
115
116
|
id: ctx.userId,
|
|
@@ -10,9 +10,9 @@ import { decryptStoredPii, verifyPassword } from "../../shared/index.ts";
|
|
|
10
10
|
import { UserErrors, UserHandlers, UserQueries } from "../../user/index.ts";
|
|
11
11
|
import { UserProfileErrors } from "../web/constants.ts";
|
|
12
12
|
|
|
13
|
-
//
|
|
14
|
-
//
|
|
15
|
-
//
|
|
13
|
+
// Same failure shape as auth-email-password (anti-enumeration):
|
|
14
|
+
// its errors.ts is not part of the feature barrel, but the reason code
|
|
15
|
+
// and i18nKey are stable public API.
|
|
16
16
|
// @wrapper-known error-helper
|
|
17
17
|
function invalidCredentials() {
|
|
18
18
|
return writeFailure(
|
|
@@ -22,13 +22,13 @@ function invalidCredentials() {
|
|
|
22
22
|
);
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
// Change-email — authenticated, self-only.
|
|
26
|
-
//
|
|
27
|
-
//
|
|
28
|
-
// `email` field-level privileged
|
|
29
|
-
//
|
|
30
|
-
//
|
|
31
|
-
//
|
|
25
|
+
// Change-email — authenticated, self-only. The user confirms with their
|
|
26
|
+
// current password (re-authentication as with change-password); the new
|
|
27
|
+
// address is written through the user-update handler via ctx.writeAs(system)
|
|
28
|
+
// because `email` is field-level privileged and would otherwise be silently
|
|
29
|
+
// stripped during self-updates. emailVerified is set to false — the app then
|
|
30
|
+
// triggers the verification flow (request-email-verification is public; the
|
|
31
|
+
// ProfileScreen calls it after success).
|
|
32
32
|
export const changeEmailWrite = defineWriteHandler({
|
|
33
33
|
name: "change-email",
|
|
34
34
|
schema: z.object({
|
|
@@ -88,9 +88,9 @@ export const changeEmailWrite = defineWriteHandler({
|
|
|
88
88
|
);
|
|
89
89
|
}
|
|
90
90
|
|
|
91
|
-
// user
|
|
92
|
-
//
|
|
93
|
-
// backfillUserStreamTenants
|
|
91
|
+
// user is systemStream: the event stream is deterministically located
|
|
92
|
+
// on SYSTEM_TENANT_ID. Older streams require a one-time
|
|
93
|
+
// backfillUserStreamTenants.
|
|
94
94
|
const writer = createSystemUser(SYSTEM_TENANT_ID);
|
|
95
95
|
|
|
96
96
|
const writeRes = await ctx.writeAs(writer, UserHandlers.update, {
|