@cosmicdrift/kumiko-bundled-features 1.0.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +41 -7
- package/src/__tests__/access-invalidation-consumer.integration.test.ts +279 -0
- package/src/__tests__/access-invalidation-stream.integration.test.ts +217 -0
- package/src/admin-shell/__tests__/admin-shell-security.integration.test.ts +200 -0
- package/src/admin-shell/__tests__/admin-shell.boot.test.ts +147 -0
- package/src/admin-shell/__tests__/overview-allowlist.test.ts +43 -0
- package/src/admin-shell/__tests__/overview-screens.boot.test.ts +35 -0
- package/src/admin-shell/constants.ts +11 -0
- package/src/admin-shell/feature.ts +135 -0
- package/src/admin-shell/i18n.ts +36 -0
- package/src/admin-shell/index.ts +17 -0
- package/src/admin-shell/overview-allowlist.ts +37 -0
- package/src/admin-shell/web/client-plugin.tsx +26 -0
- package/src/admin-shell/web/i18n.ts +16 -0
- package/src/admin-shell/web/index.ts +2 -0
- package/src/admin-shell/web/overview-layout.tsx +69 -0
- package/src/admin-shell/web/overview-query.ts +15 -0
- package/src/admin-shell/web/platform-overview-screen.tsx +90 -0
- package/src/admin-shell/web/tenant-overview-screen.tsx +90 -0
- package/src/agent-tools/__tests__/tool-catalog.test.ts +179 -0
- package/src/agent-tools/__tests__/tool-dispatch.integration.test.ts +100 -0
- package/src/agent-tools/__tests__/tool-dispatch.test.ts +126 -0
- package/src/agent-tools/index.ts +9 -0
- package/src/agent-tools/tool-catalog.ts +130 -0
- package/src/agent-tools/tool-dispatch.ts +82 -0
- package/src/agent-tools/types.ts +38 -0
- package/src/audit/__tests__/audit-screens.boot.test.ts +51 -0
- package/src/audit/__tests__/audit-security.integration.test.ts +201 -0
- package/src/audit/__tests__/audit.integration.test.ts +50 -25
- package/src/audit/constants.ts +9 -2
- package/src/audit/feature.ts +33 -1
- package/src/audit/handlers/details.query.ts +47 -0
- package/src/audit/handlers/list.query.ts +3 -2
- package/src/audit/i18n.ts +31 -0
- package/src/audit/web/audit-log-detail-screen.tsx +131 -0
- package/src/audit/web/audit-log-screen.tsx +250 -0
- package/src/audit/web/client-plugin.tsx +22 -0
- package/src/audit/web/i18n.ts +12 -0
- package/src/audit/web/index.ts +5 -0
- package/src/auth-email-password/__tests__/account-lockout-no-redis.integration.test.ts +4 -4
- package/src/auth-email-password/__tests__/account-lockout.integration.test.ts +4 -4
- package/src/auth-email-password/__tests__/account-unlock.integration.test.ts +283 -0
- package/src/auth-email-password/__tests__/auth-claims.integration.test.ts +10 -11
- package/src/auth-email-password/__tests__/auth-user-row.test.ts +36 -0
- package/src/auth-email-password/__tests__/auth.integration.test.ts +33 -6
- package/src/auth-email-password/__tests__/email-verification.integration.test.ts +9 -6
- package/src/auth-email-password/__tests__/feature-options.test.ts +33 -0
- package/src/auth-email-password/__tests__/identity-v3-login.integration.test.ts +3 -3
- package/src/auth-email-password/__tests__/invite-flow-kms.integration.test.ts +283 -0
- package/src/auth-email-password/__tests__/invite-flow.integration.test.ts +35 -1
- package/src/auth-email-password/__tests__/login-mfa-setup-required.integration.test.ts +129 -0
- package/src/auth-email-password/__tests__/multi-roles.integration.test.ts +1 -1
- package/src/auth-email-password/__tests__/password-policy.test.ts +15 -0
- package/src/auth-email-password/__tests__/password-reset.integration.test.ts +19 -6
- package/src/auth-email-password/__tests__/public-routes-rate-limit.integration.test.ts +3 -3
- package/src/auth-email-password/__tests__/seed-admin.integration.test.ts +1 -1
- package/src/auth-email-password/__tests__/self-registration-toggle.integration.test.ts +264 -0
- package/src/auth-email-password/__tests__/session-callbacks.integration.test.ts +20 -4
- package/src/auth-email-password/__tests__/session-strict-mode.integration.test.ts +7 -14
- package/src/auth-email-password/__tests__/signup-flow.integration.test.ts +91 -0
- package/src/auth-email-password/constants.ts +25 -0
- package/src/auth-email-password/email-templates.ts +32 -0
- package/src/auth-email-password/errors.ts +9 -0
- package/src/auth-email-password/feature.ts +59 -11
- package/src/auth-email-password/handlers/change-password.write.ts +14 -13
- package/src/auth-email-password/handlers/confirm-account-unlock.write.ts +59 -0
- package/src/auth-email-password/handlers/confirm-token-flow.ts +34 -105
- package/src/auth-email-password/handlers/invite-accept-with-login.write.ts +12 -5
- package/src/auth-email-password/handlers/invite-accept.write.ts +9 -2
- package/src/auth-email-password/handlers/invite-create.write.ts +2 -2
- package/src/auth-email-password/handlers/invite-signup-complete.write.ts +12 -4
- package/src/auth-email-password/handlers/login.write.ts +86 -16
- package/src/auth-email-password/handlers/logout.write.ts +4 -2
- package/src/auth-email-password/handlers/request-account-unlock.write.ts +38 -0
- package/src/auth-email-password/handlers/reset-password.write.ts +3 -2
- package/src/auth-email-password/handlers/self-registration-status.query.ts +23 -0
- package/src/auth-email-password/handlers/signup-confirm.write.ts +19 -11
- package/src/auth-email-password/handlers/signup-request.write.ts +22 -0
- package/src/auth-email-password/handlers/token-request-handler.ts +4 -2
- package/src/auth-email-password/i18n.ts +52 -0
- package/src/auth-email-password/index.ts +13 -2
- package/src/auth-email-password/lockout-store.ts +10 -5
- package/src/auth-email-password/password-policy.ts +2108 -0
- package/src/auth-email-password/seeding.ts +55 -27
- package/src/auth-email-password/self-registration-toggle.ts +25 -0
- package/src/auth-email-password/signed-token.ts +1 -0
- package/src/auth-email-password/unlock-token.ts +28 -0
- package/src/auth-email-password/web/__tests__/auth-client.test.ts +542 -0
- package/src/auth-email-password/web/__tests__/auth-form-logic.test.ts +44 -0
- package/src/auth-email-password/web/__tests__/auth-gate.test.tsx +194 -6
- package/src/auth-email-password/web/__tests__/client-plugin.test.tsx +34 -0
- package/src/auth-email-password/web/__tests__/confirm-account-unlock-screen.test.tsx +64 -0
- package/src/auth-email-password/web/__tests__/forgot-password-screen.test.tsx +5 -1
- package/src/auth-email-password/web/__tests__/invite-accept-screen.test.tsx +129 -2
- package/src/auth-email-password/web/__tests__/login-screen.test.tsx +149 -5
- package/src/auth-email-password/web/__tests__/request-account-unlock-screen.test.tsx +137 -0
- package/src/auth-email-password/web/__tests__/reset-password-screen.test.tsx +5 -1
- package/src/auth-email-password/web/__tests__/signup-complete-screen.test.tsx +134 -0
- package/src/auth-email-password/web/__tests__/signup-screen.test.tsx +93 -0
- package/src/auth-email-password/web/__tests__/test-utils.tsx +12 -2
- package/src/auth-email-password/web/__tests__/use-url-token.test.tsx +29 -0
- package/src/auth-email-password/web/__tests__/verify-email-screen.test.tsx +5 -1
- package/src/auth-email-password/web/auth-client.ts +96 -18
- package/src/auth-email-password/web/auth-form-logic.ts +30 -0
- package/src/auth-email-password/web/auth-form-primitives.tsx +22 -20
- package/src/auth-email-password/web/auth-gate.tsx +140 -19
- package/src/auth-email-password/web/client-plugin.ts +24 -2
- package/src/auth-email-password/web/confirm-account-unlock-screen.tsx +95 -0
- package/src/auth-email-password/web/forgot-password-screen.tsx +6 -6
- package/src/auth-email-password/web/index.ts +16 -4
- package/src/auth-email-password/web/invite-accept-screen.tsx +5 -5
- package/src/auth-email-password/web/login-screen.tsx +78 -22
- package/src/auth-email-password/web/request-account-unlock-screen.tsx +112 -0
- package/src/auth-email-password/web/reset-password-screen.tsx +15 -18
- package/src/auth-email-password/web/session.tsx +11 -6
- package/src/auth-email-password/web/signup-complete-screen.tsx +13 -15
- package/src/auth-email-password/web/signup-screen.tsx +8 -10
- package/src/auth-email-password/web/use-shell-user.ts +5 -2
- package/src/auth-email-password/web/user-menu.tsx +3 -1
- package/src/auth-email-password/web/verify-email-screen.tsx +10 -14
- package/src/auth-foundation/__tests__/feature.test.ts +46 -0
- package/src/auth-foundation/__tests__/session-store.test.ts +77 -0
- package/src/auth-foundation/__tests__/tenant-providers.test.ts +160 -0
- package/src/auth-foundation/__tests__/token-verifier.test.ts +150 -0
- package/src/auth-foundation/boot-checks.ts +150 -0
- package/src/auth-foundation/feature.ts +157 -0
- package/src/auth-foundation/index.ts +37 -0
- package/src/auth-foundation/resolve-anonymous-access.ts +62 -0
- package/src/auth-foundation/types.ts +170 -0
- package/src/auth-mfa/__tests__/base32.test.ts +28 -0
- package/src/auth-mfa/__tests__/disable-and-regenerate.integration.test.ts +265 -0
- package/src/auth-mfa/__tests__/enable-confirm-preauth.integration.test.ts +321 -0
- package/src/auth-mfa/__tests__/enable-flow.integration.test.ts +322 -0
- package/src/auth-mfa/__tests__/enable-start-preauth.integration.test.ts +237 -0
- package/src/auth-mfa/__tests__/errors-i18n-parity.test.ts +39 -0
- package/src/auth-mfa/__tests__/mfa-preauth-setup-token.test.ts +113 -0
- package/src/auth-mfa/__tests__/no-redis.integration.test.ts +209 -0
- package/src/auth-mfa/__tests__/pii-subject-encryption.integration.test.ts +139 -0
- package/src/auth-mfa/__tests__/reencrypt-job.integration.test.ts +247 -0
- package/src/auth-mfa/__tests__/session-auto-revoke.integration.test.ts +169 -0
- package/src/auth-mfa/__tests__/totp.test.ts +131 -0
- package/src/auth-mfa/__tests__/verify.integration.test.ts +319 -0
- package/src/auth-mfa/base32.ts +51 -0
- package/src/auth-mfa/config.ts +26 -0
- package/src/auth-mfa/constants.ts +45 -0
- package/src/auth-mfa/db/queries.ts +45 -0
- package/src/auth-mfa/errors.ts +66 -0
- package/src/auth-mfa/feature.ts +170 -0
- package/src/auth-mfa/handlers/disable.write.ts +67 -0
- package/src/auth-mfa/handlers/enable-confirm-preauth.write.ts +200 -0
- package/src/auth-mfa/handlers/enable-confirm.write.ts +106 -0
- package/src/auth-mfa/handlers/enable-start-preauth.write.ts +87 -0
- package/src/auth-mfa/handlers/enable-start.write.ts +66 -0
- package/src/auth-mfa/handlers/reencrypt.job.ts +234 -0
- package/src/auth-mfa/handlers/regenerate-recovery.write.ts +77 -0
- package/src/auth-mfa/handlers/status.query.ts +23 -0
- package/src/auth-mfa/handlers/verify.write.ts +179 -0
- package/src/auth-mfa/i18n.ts +12 -0
- package/src/auth-mfa/index.ts +19 -0
- package/src/auth-mfa/mfa-challenge-token.ts +90 -0
- package/src/auth-mfa/mfa-preauth-setup-token.ts +86 -0
- package/src/auth-mfa/mfa-setup-token.ts +96 -0
- package/src/auth-mfa/mfa-status-checker.ts +84 -0
- package/src/auth-mfa/mfa-verify-attempts.ts +90 -0
- package/src/auth-mfa/otpauth-uri.ts +21 -0
- package/src/auth-mfa/recovery-codes.ts +54 -0
- package/src/auth-mfa/schema/user-mfa.ts +60 -0
- package/src/auth-mfa/testing.ts +5 -0
- package/src/auth-mfa/totp.ts +67 -0
- package/src/auth-mfa/verify-factor.ts +58 -0
- package/src/auth-mfa/web/__tests__/mfa-client.test.ts +265 -0
- package/src/auth-mfa/web/__tests__/mfa-enable-screen.test.tsx +182 -0
- package/src/auth-mfa/web/__tests__/mfa-setup-preauth-screen.test.tsx +379 -0
- package/src/auth-mfa/web/__tests__/mfa-verify-screen.test.tsx +104 -0
- package/src/auth-mfa/web/client-plugin.ts +37 -0
- package/src/auth-mfa/web/i18n.ts +136 -0
- package/src/auth-mfa/web/index.ts +27 -0
- package/src/auth-mfa/web/mfa-client.ts +184 -0
- package/src/auth-mfa/web/mfa-disable-dialog.tsx +69 -0
- package/src/auth-mfa/web/mfa-enable-screen.tsx +228 -0
- package/src/auth-mfa/web/mfa-recovery-codes-reveal.tsx +53 -0
- package/src/auth-mfa/web/mfa-regenerate-recovery-dialog.tsx +68 -0
- package/src/auth-mfa/web/mfa-setup-preauth-screen.tsx +267 -0
- package/src/auth-mfa/web/mfa-verify-screen.tsx +117 -0
- package/src/auth-mfa/web/qrcode-browser.d.ts +12 -0
- package/src/auth-mfa-user-data/__tests__/hooks.integration.test.ts +134 -0
- package/src/auth-mfa-user-data/hooks.ts +53 -0
- package/src/auth-mfa-user-data/index.ts +21 -0
- package/src/billing-foundation/__tests__/billing-foundation.integration.test.ts +206 -2
- package/src/billing-foundation/__tests__/subscription-provider-contract.ts +93 -0
- package/src/billing-foundation/entities.ts +28 -4
- package/src/billing-foundation/events.ts +6 -2
- package/src/billing-foundation/feature.ts +9 -1
- package/src/billing-foundation/get-subscription-for-tenant.ts +16 -5
- package/src/billing-foundation/handlers/create-portal-session.write.ts +17 -1
- package/src/billing-foundation/handlers/list-subscriptions.query.ts +15 -1
- package/src/billing-foundation/handlers/process-event.write.ts +39 -3
- package/src/billing-foundation/tenant-destroy-hook.ts +46 -0
- package/src/cap-counter/__tests__/cap-list.boot.test.ts +27 -0
- package/src/cap-counter/__tests__/cap-list.security.integration.test.ts +53 -0
- package/src/cap-counter/__tests__/entity-ddl.test.ts +15 -0
- package/src/cap-counter/__tests__/with-cap-enforcement.integration.test.ts +8 -5
- package/src/cap-counter/constants.ts +2 -0
- package/src/cap-counter/enforce-cap.ts +15 -18
- package/src/cap-counter/entity.ts +3 -3
- package/src/cap-counter/feature.ts +28 -1
- package/src/cap-counter/i18n.ts +12 -0
- package/src/cap-counter/with-cap-enforcement.ts +2 -2
- package/src/channel-email/__tests__/pii-guard.test.ts +56 -0
- package/src/channel-email/email-channel.ts +2 -1
- package/src/channel-email/index.ts +1 -0
- package/src/channel-email/pii-guard.ts +39 -0
- package/src/compliance-profiles/__tests__/profile-picker.boot.test.ts +28 -0
- package/src/compliance-profiles/__tests__/profile-picker.security.integration.test.ts +91 -0
- package/src/compliance-profiles/constants.ts +15 -0
- package/src/compliance-profiles/feature.ts +22 -1
- package/src/compliance-profiles/handlers/set-profile.write.ts +2 -2
- package/src/compliance-profiles/i18n.ts +6 -0
- package/src/compliance-profiles/index.ts +6 -0
- package/src/compliance-profiles/web/client-plugin.tsx +22 -0
- package/src/compliance-profiles/web/compliance-profile-screen.tsx +152 -0
- package/src/compliance-profiles/web/i18n.ts +25 -0
- package/src/compliance-profiles/web/index.ts +6 -0
- package/src/config/__tests__/app-overrides.test.ts +11 -0
- package/src/config/__tests__/backing-secrets.integration.test.ts +22 -0
- package/src/config/__tests__/cascade.integration.test.ts +35 -0
- package/src/config/__tests__/config.integration.test.ts +71 -10
- package/src/config/__tests__/deserialize-value.test.ts +5 -8
- package/src/config/__tests__/inherited-redaction.integration.test.ts +4 -3
- package/src/config/__tests__/pii-encrypted.integration.test.ts +179 -0
- package/src/config/__tests__/reencrypt-job-concurrent-write-race.integration.test.ts +234 -0
- package/src/config/__tests__/reencrypt-job-kek-rotation.integration.test.ts +243 -0
- package/src/config/__tests__/write-helpers.test.ts +23 -0
- package/src/config/db/queries/resolver.ts +3 -3
- package/src/config/feature.ts +15 -8
- package/src/config/handlers/cascade.query.ts +2 -1
- package/src/config/handlers/reencrypt.job.ts +209 -0
- package/src/config/handlers/set.write.ts +55 -3
- package/src/config/handlers/values.query.ts +2 -1
- package/src/config/i18n.ts +9 -0
- package/src/config/index.ts +5 -4
- package/src/config/resolver.ts +75 -61
- package/src/config/table.ts +1 -1
- package/src/config/write-helpers.ts +22 -0
- package/src/crypto-shredding/__tests__/forget-subject.integration.test.ts +148 -0
- package/src/crypto-shredding/constants.ts +5 -0
- package/src/crypto-shredding/feature.ts +18 -0
- package/src/crypto-shredding/handlers/forget-subject.write.ts +91 -0
- package/src/crypto-shredding/index.ts +11 -0
- package/src/custom-fields/__tests__/audit-integration.integration.test.ts +1 -1
- package/src/custom-fields/__tests__/custom-fields.integration.test.ts +92 -53
- package/src/custom-fields/__tests__/field-access.integration.test.ts +25 -0
- package/src/custom-fields/__tests__/parse-serialized-field.test.ts +11 -3
- package/src/custom-fields/__tests__/retention.integration.test.ts +40 -0
- package/src/custom-fields/__tests__/user-data-rights.integration.test.ts +26 -79
- package/src/custom-fields/constants.ts +1 -0
- package/src/custom-fields/db/queries/user-data-rights.ts +0 -20
- package/src/custom-fields/entity.ts +1 -1
- package/src/custom-fields/events.ts +4 -3
- package/src/custom-fields/feature.ts +8 -0
- package/src/custom-fields/handlers/delete-system-field.write.ts +2 -1
- package/src/custom-fields/handlers/delete-tenant-field.write.ts +2 -1
- package/src/custom-fields/handlers/set-custom-field.write.ts +3 -44
- package/src/custom-fields/handlers/update-tenant-field.write.ts +0 -17
- package/src/custom-fields/lib/field-access.ts +8 -1
- package/src/custom-fields/lib/parse-serialized-field.ts +12 -4
- package/src/custom-fields/lib/value-schema.ts +1 -1
- package/src/custom-fields/run-retention.ts +9 -1
- package/src/custom-fields/schemas.ts +9 -9
- package/src/custom-fields/wire-for-entity.ts +110 -78
- package/src/custom-fields/wire-user-data-rights.ts +5 -54
- package/src/data-retention/__tests__/parse-override.test.ts +14 -13
- package/src/data-retention/__tests__/retention-cleanup.integration.test.ts +145 -8
- package/src/data-retention/feature.ts +3 -3
- package/src/data-retention/run-retention-cleanup.ts +102 -19
- package/src/delivery/__tests__/delivery-pii-kms.integration.test.ts +171 -0
- package/src/delivery/__tests__/delivery-screens.boot.test.ts +27 -0
- package/src/delivery/__tests__/delivery-security.integration.test.ts +106 -0
- package/src/delivery/constants.ts +13 -51
- package/src/delivery/feature.ts +29 -5
- package/src/delivery/handlers/log.query.ts +28 -7
- package/src/delivery/i18n.ts +6 -0
- package/src/delivery/index.ts +6 -1
- package/src/delivery/public-names.ts +36 -0
- package/src/delivery/tables.ts +3 -3
- package/src/delivery/web/client-plugin.tsx +20 -0
- package/src/delivery/web/delivery-log-screen.tsx +103 -0
- package/src/delivery/web/i18n.ts +25 -0
- package/src/delivery/web/index.ts +3 -0
- package/src/document-ingest-foundation/__tests__/feature.integration.test.ts +147 -0
- package/src/document-ingest-foundation/__tests__/feature.test.ts +105 -0
- package/src/document-ingest-foundation/__tests__/pages.test.ts +37 -0
- package/src/document-ingest-foundation/entity.ts +43 -0
- package/src/document-ingest-foundation/events.ts +25 -0
- package/src/document-ingest-foundation/feature.ts +126 -0
- package/src/document-ingest-foundation/index.ts +12 -0
- package/src/document-ingest-foundation/pages.ts +34 -0
- package/src/feature-toggles/__tests__/compose-tier-resolver.test.ts +304 -0
- package/src/feature-toggles/__tests__/feature-toggles.integration.test.ts +7 -6
- package/src/feature-toggles/__tests__/toggle-admin.boot.test.ts +31 -0
- package/src/feature-toggles/__tests__/toggle-admin.security.integration.test.ts +69 -0
- package/src/feature-toggles/compose-tier-resolver.ts +134 -0
- package/src/feature-toggles/constants.ts +14 -0
- package/src/feature-toggles/feature.ts +23 -3
- package/src/feature-toggles/global-feature-state-table.ts +20 -1
- package/src/feature-toggles/handlers/list.query.ts +1 -1
- package/src/feature-toggles/handlers/registered.query.ts +1 -1
- package/src/feature-toggles/i18n.ts +6 -0
- package/src/feature-toggles/index.ts +8 -0
- package/src/feature-toggles/toggle-runtime.ts +14 -0
- package/src/feature-toggles/web/client-plugin.tsx +22 -0
- package/src/feature-toggles/web/i18n.ts +29 -0
- package/src/feature-toggles/web/index.ts +6 -0
- package/src/feature-toggles/web/toggle-admin-screen.tsx +136 -0
- package/src/file-foundation/__tests__/feature.test.ts +5 -5
- package/src/file-foundation/__tests__/file-foundation.integration.test.ts +4 -3
- package/src/file-foundation/feature.ts +10 -11
- package/src/files-provider-s3/__tests__/s3-provider.integration.test.ts +27 -2
- package/src/files-provider-s3/s3-provider.ts +12 -1
- package/src/folders/__tests__/folders.integration.test.ts +3 -0
- package/src/folders/web/__tests__/folder-manager.test.tsx +43 -2
- package/src/folders/web/__tests__/tree.test.ts +8 -0
- package/src/folders/web/folder-manager.tsx +2 -3
- package/src/folders/web/i18n.ts +0 -2
- package/src/folders/web/tree.ts +13 -2
- package/src/folders-user-data/__tests__/hooks.integration.test.ts +1 -0
- package/src/folders-user-data/index.ts +4 -4
- package/src/inbound-mail-foundation/__tests__/account-state.test.ts +30 -0
- package/src/inbound-mail-foundation/__tests__/connect-routes.integration.test.ts +307 -0
- package/src/inbound-mail-foundation/__tests__/feature.test.ts +169 -0
- package/src/inbound-mail-foundation/__tests__/inbound-mail-foundation.integration.test.ts +644 -0
- package/src/inbound-mail-foundation/__tests__/inbound-mail-provider-contract.ts +111 -0
- package/src/inbound-mail-foundation/__tests__/retention.integration.test.ts +237 -0
- package/src/inbound-mail-foundation/__tests__/watch-supervisor.integration.test.ts +433 -0
- package/src/inbound-mail-foundation/aggregate-id.ts +40 -0
- package/src/inbound-mail-foundation/connect-routes.ts +230 -0
- package/src/inbound-mail-foundation/constants.ts +80 -0
- package/src/inbound-mail-foundation/db/queries/inbound-projections.ts +38 -0
- package/src/inbound-mail-foundation/entities.ts +172 -0
- package/src/inbound-mail-foundation/events.ts +147 -0
- package/src/inbound-mail-foundation/feature.ts +243 -0
- package/src/inbound-mail-foundation/handlers/account-state.ts +23 -0
- package/src/inbound-mail-foundation/handlers/connect-account.write.ts +112 -0
- package/src/inbound-mail-foundation/handlers/disconnect-account.write.ts +69 -0
- package/src/inbound-mail-foundation/handlers/ingest-message.write.ts +333 -0
- package/src/inbound-mail-foundation/handlers/list-accounts.query.ts +44 -0
- package/src/inbound-mail-foundation/handlers/list-messages.query.ts +58 -0
- package/src/inbound-mail-foundation/handlers/scope-visibility.ts +14 -0
- package/src/inbound-mail-foundation/handlers/update-account.write.ts +78 -0
- package/src/inbound-mail-foundation/index.ts +97 -0
- package/src/inbound-mail-foundation/oauth-state.ts +103 -0
- package/src/inbound-mail-foundation/projection.ts +152 -0
- package/src/inbound-mail-foundation/provider-factory.ts +53 -0
- package/src/inbound-mail-foundation/retention-sweep.ts +168 -0
- package/src/inbound-mail-foundation/tenant-destroy-hook.ts +93 -0
- package/src/inbound-mail-foundation/types.ts +250 -0
- package/src/inbound-mail-foundation/watch-supervisor.ts +482 -0
- package/src/inbound-provider-imap/__tests__/feature.test.ts +115 -0
- package/src/inbound-provider-imap/__tests__/imap-foundation.integration.test.ts +302 -0
- package/src/inbound-provider-imap/__tests__/imap-live.integration.test.ts +206 -0
- package/src/inbound-provider-imap/__tests__/plugin-mocked.test.ts +358 -0
- package/src/inbound-provider-imap/credential-document.ts +51 -0
- package/src/inbound-provider-imap/feature.ts +283 -0
- package/src/inbound-provider-imap/imap-client.ts +158 -0
- package/src/inbound-provider-imap/index.ts +17 -0
- package/src/inbound-provider-inmemory/__tests__/feature.test.ts +52 -0
- package/src/inbound-provider-inmemory/feature.ts +154 -0
- package/src/inbound-provider-inmemory/index.ts +12 -0
- package/src/jobs/__tests__/entity-ddl.test.ts +15 -0
- package/src/jobs/__tests__/job-instant.test.ts +15 -0
- package/src/jobs/__tests__/job-system-user.integration.test.ts +4 -8
- package/src/jobs/__tests__/jobs-events.integration.test.ts +37 -1
- package/src/jobs/__tests__/jobs-pii-kms.integration.test.ts +120 -0
- package/src/jobs/__tests__/jobs-screens.boot.test.ts +36 -0
- package/src/jobs/__tests__/jobs-security.integration.test.ts +108 -0
- package/src/jobs/__tests__/reindex-entity-job.integration.test.ts +169 -0
- package/src/jobs/constants.ts +8 -1
- package/src/jobs/feature.ts +52 -8
- package/src/jobs/handlers/detail.query.ts +6 -0
- package/src/jobs/handlers/list.query.ts +8 -1
- package/src/jobs/handlers/projection-rebuild.job.ts +14 -4
- package/src/jobs/handlers/reindex-entity.job.ts +49 -0
- package/src/jobs/i18n.ts +37 -0
- package/src/jobs/job-instant.ts +9 -0
- package/src/jobs/job-run-table.ts +4 -4
- package/src/jobs/web/client-plugin.tsx +22 -0
- package/src/jobs/web/i18n.ts +12 -0
- package/src/jobs/web/index.ts +4 -0
- package/src/jobs/web/job-run-detail-screen.tsx +180 -0
- package/src/jobs/web/job-runs-screen.tsx +146 -0
- package/src/ledger/__tests__/ledger.integration.test.ts +8 -3
- package/src/ledger/handlers/confirm-schedule-period.write.ts +17 -4
- package/src/ledger/recurring.ts +17 -8
- package/src/ledger/web/index.ts +3 -2
- package/src/legal-pages/__tests__/legal-pages.integration.test.ts +55 -0
- package/src/legal-pages/feature.ts +24 -31
- package/src/legal-pages/index.ts +1 -0
- package/src/mail-foundation/__tests__/feature.test.ts +5 -6
- package/src/mail-foundation/__tests__/mail-foundation.integration.test.ts +4 -3
- package/src/mail-foundation/__tests__/mail-transport-contract.ts +58 -0
- package/src/mail-foundation/feature.ts +26 -24
- package/src/mail-transport-inmemory/__tests__/feature.test.ts +23 -0
- package/src/mail-transport-smtp/__tests__/feature.test.ts +65 -0
- package/src/managed-pages/__tests__/branding-coerce.test.ts +2 -6
- package/src/managed-pages/__tests__/i18n-surface.boot.test.ts +30 -0
- package/src/managed-pages/__tests__/managed-pages.integration.test.ts +137 -0
- package/src/managed-pages/feature.ts +45 -47
- package/src/managed-pages/handlers/branding.query.ts +5 -1
- package/src/managed-pages/handlers/by-tenant-published.query.ts +52 -0
- package/src/managed-pages/i18n.ts +66 -0
- package/src/managed-pages/screens/page-screens.ts +5 -1
- package/src/managed-pages/web/client-plugin.tsx +22 -0
- package/src/managed-pages/web/i18n.ts +24 -0
- package/src/managed-pages/web/index.ts +3 -0
- package/src/page-render/__tests__/layout.test.ts +63 -0
- package/src/page-render/__tests__/markdown.test.ts +29 -0
- package/src/page-render/branding.ts +4 -3
- package/src/page-render/index.ts +1 -1
- package/src/page-render/layout.ts +18 -3
- package/src/page-render/markdown.ts +1 -9
- package/src/page-render/web.ts +13 -0
- package/src/personal-access-tokens/__tests__/feature.test.ts +42 -0
- package/src/personal-access-tokens/__tests__/pat.integration.test.ts +239 -0
- package/src/personal-access-tokens/__tests__/scopes.test.ts +42 -0
- package/src/personal-access-tokens/constants.ts +33 -0
- package/src/personal-access-tokens/feature.ts +105 -0
- package/src/personal-access-tokens/handlers/available-scopes.query.ts +21 -0
- package/src/personal-access-tokens/handlers/create.write.ts +47 -0
- package/src/personal-access-tokens/handlers/list.query.ts +50 -0
- package/src/personal-access-tokens/handlers/revoke.write.ts +37 -0
- package/src/personal-access-tokens/hash.ts +17 -0
- package/src/personal-access-tokens/i18n.ts +5 -0
- package/src/personal-access-tokens/index.ts +31 -0
- package/src/personal-access-tokens/resolver.ts +58 -0
- package/src/personal-access-tokens/roles.ts +29 -0
- package/src/personal-access-tokens/schema/api-token.ts +63 -0
- package/src/personal-access-tokens/scopes.ts +43 -0
- package/src/personal-access-tokens/web/client-plugin.tsx +29 -0
- package/src/personal-access-tokens/web/i18n.ts +69 -0
- package/src/personal-access-tokens/web/index.ts +7 -0
- package/src/personal-access-tokens/web/pat-tokens-screen.tsx +265 -0
- package/src/readiness/__tests__/readiness.integration.test.ts +4 -3
- package/src/renderer-simple/__tests__/resolve-variables.test.ts +37 -0
- package/src/renderer-simple/resolve-variables.ts +3 -1
- package/src/secrets/__tests__/rotate.integration.test.ts +115 -18
- package/src/secrets/handlers/rotate.job.ts +77 -98
- package/src/secrets/secrets-context.ts +7 -38
- package/src/secrets/table.ts +7 -8
- package/src/seo/__tests__/llms-txt.test.ts +38 -0
- package/src/seo/__tests__/robots-txt.test.ts +18 -0
- package/src/seo/__tests__/schema-builders.test.ts +57 -0
- package/src/seo/__tests__/seo.integration.test.ts +350 -0
- package/src/seo/__tests__/sitemap.test.ts +38 -0
- package/src/seo/constants.ts +60 -0
- package/src/seo/feature.ts +316 -0
- package/src/seo/handlers/seo-config.query.ts +35 -0
- package/src/seo/index.ts +19 -0
- package/src/seo/llms-txt.ts +33 -0
- package/src/seo/robots-txt.ts +13 -0
- package/src/seo/schema-builders.ts +57 -0
- package/src/seo/sitemap.ts +33 -0
- package/src/sessions/__tests__/auto-revoke-binding.test.ts +71 -0
- package/src/sessions/__tests__/cleanup.integration.test.ts +2 -1
- package/src/sessions/__tests__/password-auto-revoke.integration.test.ts +11 -7
- package/src/sessions/__tests__/rebuild-survival.integration.test.ts +18 -7
- package/src/sessions/__tests__/session-store-registration.test.ts +21 -0
- package/src/sessions/__tests__/sessions-screens.boot.test.ts +55 -0
- package/src/sessions/__tests__/sessions.integration.test.ts +272 -20
- package/src/sessions/__tests__/test-helpers.ts +16 -3
- package/src/sessions/constants.ts +5 -0
- package/src/sessions/db/queries/cleanup.ts +2 -2
- package/src/sessions/feature.ts +175 -26
- package/src/sessions/handlers/detail.query.ts +36 -0
- package/src/sessions/handlers/list.query.ts +14 -9
- package/src/sessions/handlers/mine.query.ts +13 -8
- package/src/sessions/handlers/revoke-all-for-user.write.ts +51 -12
- package/src/sessions/handlers/revoke-all-others.write.ts +19 -1
- package/src/sessions/handlers/revoke.write.ts +13 -0
- package/src/sessions/i18n.ts +23 -0
- package/src/sessions/index.ts +9 -2
- package/src/sessions/schema/user-session.ts +8 -2
- package/src/sessions/session-callbacks.ts +99 -14
- package/src/sessions/session-checker-fail-open.test.ts +77 -0
- package/src/sessions/session-revoked-event.ts +29 -0
- package/src/sessions/testing.ts +14 -1
- package/src/shared/__tests__/chunked-entity-migration.test.ts +145 -0
- package/src/shared/chunked-entity-migration.ts +89 -0
- package/src/shared/decrypt-stored-pii.ts +26 -0
- package/src/shared/encrypt-for-direct-write.ts +23 -0
- package/src/shared/entities-of.ts +17 -0
- package/src/shared/grace-period.test.ts +26 -0
- package/src/shared/grace-period.ts +20 -0
- package/src/{auth-email-password/__tests__ → shared}/identity-v3-hash.test.ts +2 -2
- package/src/shared/index.ts +16 -0
- package/src/shared/map-with-concurrency.test.ts +104 -0
- package/src/shared/map-with-concurrency.ts +38 -0
- package/src/shared/password-hashing.test.ts +35 -0
- package/src/{auth-email-password → shared}/password-hashing.ts +11 -0
- package/src/shared/system-query.ts +5 -0
- package/src/{auth-email-password → shared}/token-burn-store.ts +1 -1
- package/src/subscription-mollie/__tests__/feature.test.ts +97 -0
- package/src/subscription-mollie/__tests__/mollie-foundation.integration.test.ts +12 -1
- package/src/subscription-mollie/__tests__/verify-webhook.test.ts +21 -0
- package/src/subscription-mollie/verify-webhook.ts +1 -0
- package/src/subscription-stripe/__tests__/feature.test.ts +127 -1
- package/src/subscription-stripe/__tests__/runtime.test.ts +14 -24
- package/src/subscription-stripe/__tests__/stripe-foundation.integration.test.ts +15 -5
- package/src/subscription-stripe/__tests__/verify-webhook.test.ts +20 -0
- package/src/subscription-stripe/feature.ts +2 -0
- package/src/subscription-stripe/verify-webhook.ts +3 -2
- package/src/tags/__tests__/schemas.test.ts +34 -0
- package/src/tags/__tests__/tags.integration.test.ts +12 -1
- package/src/tags/entity.ts +6 -1
- package/src/tags/feature.ts +2 -0
- package/src/tags/i18n.ts +5 -0
- package/src/tags/schemas.ts +9 -2
- package/src/tags/web/__tests__/tag-manager.test.tsx +333 -0
- package/src/tags/web/__tests__/tag-section.test.tsx +47 -1
- package/src/tags/web/tag-manager.tsx +1 -1
- package/src/tags/web/tag-section.tsx +6 -3
- package/src/template-resolver/testing.ts +2 -1
- package/src/tenant/__tests__/members-query-kms.integration.test.ts +98 -0
- package/src/tenant/__tests__/members-screens.boot.test.ts +51 -0
- package/src/tenant/__tests__/multi-tenant.integration.test.ts +1 -1
- package/src/tenant/__tests__/tenant-security.integration.test.ts +310 -0
- package/src/tenant/__tests__/tenant.integration.test.ts +8 -4
- package/src/tenant/constants.ts +5 -0
- package/src/tenant/feature.ts +19 -0
- package/src/tenant/handlers/active-tenant-ids.query.ts +8 -2
- package/src/tenant/handlers/cancel-invitation.write.ts +2 -2
- package/src/tenant/handlers/invitations.query.ts +21 -4
- package/src/tenant/handlers/members.query.ts +41 -6
- package/src/tenant/i18n.ts +28 -0
- package/src/tenant/index.ts +7 -2
- package/src/tenant/invitation-table.ts +3 -2
- package/src/tenant/schema/tenant.ts +27 -2
- package/src/tenant/screens.ts +3 -2
- package/src/tenant/seeding.ts +136 -3
- package/src/tenant/web/client-plugin.tsx +20 -0
- package/src/tenant/web/i18n.ts +43 -0
- package/src/tenant/web/index.ts +4 -0
- package/src/tenant/web/members-screen.tsx +270 -0
- package/src/tenant-lifecycle/__tests__/stages.test.ts +22 -0
- package/src/tenant-lifecycle/__tests__/tenant-lifecycle.integration.test.ts +471 -0
- package/src/tenant-lifecycle/boot-checks.ts +45 -0
- package/src/tenant-lifecycle/constants.ts +56 -0
- package/src/tenant-lifecycle/events.ts +46 -0
- package/src/tenant-lifecycle/feature.ts +112 -0
- package/src/tenant-lifecycle/handlers/cancel-destruction.write.ts +79 -0
- package/src/tenant-lifecycle/handlers/request-destruction.write.ts +83 -0
- package/src/tenant-lifecycle/index.ts +7 -0
- package/src/tenant-lifecycle/lib/revoke-tenant-sessions.ts +16 -0
- package/src/tenant-lifecycle/lifecycle-gate.ts +65 -0
- package/src/tenant-lifecycle/run-tenant-destroy.ts +368 -0
- package/src/tenant-lifecycle/stages.ts +206 -0
- package/src/tenant-settings/__tests__/tenant-settings.integration.test.ts +115 -0
- package/src/tenant-settings/config.ts +44 -0
- package/src/tenant-settings/constants.ts +16 -0
- package/src/tenant-settings/feature.ts +49 -0
- package/src/tenant-settings/index.ts +8 -0
- package/src/tenant-settings/tenant-defaults.ts +67 -0
- package/src/text-content/web/__tests__/editor-read-only.test.tsx +33 -6
- package/src/text-content/web/__tests__/group-blocks.test.ts +28 -3
- package/src/text-content/web/client-plugin.tsx +126 -104
- package/src/tier-engine/__tests__/auto-default-tier.integration.test.ts +1 -1
- package/src/tier-engine/__tests__/resolver.integration.test.ts +1 -1
- package/src/tier-engine/__tests__/tier-engine.integration.test.ts +7 -4
- package/src/tier-engine/__tests__/trial-config-validation.test.ts +30 -0
- package/src/tier-engine/feature.ts +13 -6
- package/src/tier-engine/i18n.ts +8 -0
- package/src/tier-engine/web/tier-admin-screen.tsx +26 -19
- package/src/user/__tests__/stream-tenant-backfill.integration.test.ts +186 -0
- package/src/user/__tests__/user.integration.test.ts +26 -0
- package/src/user/constants.ts +1 -0
- package/src/user/db/queries/stream-tenant-backfill.ts +112 -0
- package/src/user/feature.ts +3 -0
- package/src/user/handlers/find-for-auth.query.ts +8 -6
- package/src/user/i18n.ts +20 -0
- package/src/user/index.ts +4 -0
- package/src/user/schema/user.ts +6 -2
- package/src/user/screens.ts +3 -15
- package/src/user/seeding.ts +8 -0
- package/src/user-data-rights/COMPLIANCE.md +21 -1
- package/src/user-data-rights/__tests__/anonymous-deletion-kms.integration.test.ts +145 -0
- package/src/user-data-rights/__tests__/anonymous-deletion.integration.test.ts +3 -0
- package/src/user-data-rights/__tests__/audit-log.integration.test.ts +67 -0
- package/src/user-data-rights/__tests__/boot-checks.test.ts +170 -0
- package/src/user-data-rights/__tests__/cross-data-matrix.integration.test.ts +4 -1
- package/src/user-data-rights/__tests__/download-by-token-resolver-trust.integration.test.ts +169 -0
- package/src/user-data-rights/__tests__/download.integration.test.ts +101 -33
- package/src/user-data-rights/__tests__/email-templates.test.ts +15 -0
- package/src/user-data-rights/__tests__/export-encrypted-fields.integration.test.ts +154 -0
- package/src/user-data-rights/__tests__/export-job-idempotency.integration.test.ts +2 -0
- package/src/user-data-rights/__tests__/export-job-list-cross-tenant.integration.test.ts +2 -0
- package/src/user-data-rights/__tests__/file-binary-forget-cleanup.integration.test.ts +4 -1
- package/src/user-data-rights/__tests__/file-binary-forget-failure.integration.test.ts +4 -1
- package/src/user-data-rights/__tests__/file-retention.integration.test.ts +4 -1
- package/src/user-data-rights/__tests__/file-storage-unification.integration.test.ts +4 -1
- package/src/user-data-rights/__tests__/forget-cleanup-hook-ordering.integration.test.ts +41 -62
- package/src/user-data-rights/__tests__/forget-hook-registry.integration.test.ts +110 -0
- package/src/user-data-rights/__tests__/inspector-screens.boot.test.ts +14 -0
- package/src/user-data-rights/__tests__/mail-default-bridge.integration.test.ts +19 -2
- package/src/user-data-rights/__tests__/read-users-rebuild-survives-lifecycle.integration.test.ts +25 -14
- package/src/user-data-rights/__tests__/request-cancel-deletion.integration.test.ts +2 -0
- package/src/user-data-rights/__tests__/request-deletion-callback.integration.test.ts +4 -1
- package/src/user-data-rights/__tests__/request-export.integration.test.ts +2 -0
- package/src/user-data-rights/__tests__/restriction-flow.integration.test.ts +172 -19
- package/src/user-data-rights/__tests__/run-export-jobs-cron-context.integration.test.ts +2 -0
- package/src/user-data-rights/__tests__/run-export-jobs.integration.test.ts +257 -26
- package/src/user-data-rights/__tests__/run-forget-cleanup.integration.test.ts +339 -5
- package/src/user-data-rights/__tests__/run-user-export.integration.test.ts +77 -1
- package/src/user-data-rights/__tests__/tenant-model-erasure.integration.test.ts +2 -0
- package/src/user-data-rights/__tests__/user-data-rights.integration.test.ts +9 -1
- package/src/user-data-rights/boot-checks.ts +70 -0
- package/src/user-data-rights/db/queries/__tests__/forget-cleanup.integration.test.ts +69 -0
- package/src/user-data-rights/db/queries/forget-cleanup.ts +9 -2
- package/src/user-data-rights/email-templates.ts +6 -6
- package/src/user-data-rights/feature.ts +162 -43
- package/src/user-data-rights/handlers/cancel-deletion.write.ts +8 -11
- package/src/user-data-rights/handlers/deletion-grace-period.ts +4 -1
- package/src/user-data-rights/handlers/download-by-job.query.ts +26 -18
- package/src/user-data-rights/handlers/download-by-token.query.ts +23 -15
- package/src/user-data-rights/handlers/lift-restriction.write.ts +44 -19
- package/src/user-data-rights/handlers/list-download-attempts.query.ts +1 -0
- package/src/user-data-rights/handlers/my-audit-log.query.ts +1 -0
- package/src/user-data-rights/handlers/request-deletion-by-email.write.ts +3 -1
- package/src/user-data-rights/handlers/restrict-account.write.ts +58 -7
- package/src/user-data-rights/handlers/run-forget-cleanup.write.ts +2 -0
- package/src/user-data-rights/i18n.ts +35 -32
- package/src/user-data-rights/lib/is-admin-actor.ts +19 -0
- package/src/user-data-rights/lib/storage-provider-resolver.ts +6 -5
- package/src/user-data-rights/lib/update-user-lifecycle.ts +8 -24
- package/src/user-data-rights/run-export-jobs.ts +55 -19
- package/src/user-data-rights/run-forget-cleanup.ts +112 -7
- package/src/user-data-rights/run-user-export.ts +70 -4
- package/src/user-data-rights/schema/download-token.ts +5 -3
- package/src/user-data-rights/schema/export-job.ts +2 -0
- package/src/user-data-rights/screens.ts +2 -1
- package/src/user-data-rights/web/__tests__/privacy-center-screen.test.tsx +1 -0
- package/src/user-data-rights/web/__tests__/public-deletion-gate.test.tsx +7 -1
- package/src/user-data-rights/web/client-plugin.tsx +6 -1
- package/src/user-data-rights/web/i18n.ts +30 -10
- package/src/user-data-rights/web/privacy-center-screen.tsx +5 -3
- package/src/user-data-rights-defaults/__tests__/bundled-entities.userdata-hooks.integration.test.ts +455 -0
- package/src/user-data-rights-defaults/__tests__/feature-mounted.test.ts +24 -0
- package/src/user-data-rights-defaults/__tests__/user-data-rights-defaults.integration.test.ts +33 -9
- package/src/user-data-rights-defaults/feature.ts +78 -1
- package/src/user-data-rights-defaults/hooks/api-token.userdata-hook.ts +37 -0
- package/src/user-data-rights-defaults/hooks/config-value.userdata-hook.ts +51 -0
- package/src/user-data-rights-defaults/hooks/delivery-attempt.userdata-hook.ts +37 -0
- package/src/user-data-rights-defaults/hooks/feature-mounted.ts +10 -0
- package/src/user-data-rights-defaults/hooks/in-app-message.userdata-hook.ts +38 -0
- package/src/user-data-rights-defaults/hooks/job-run.userdata-hook.ts +35 -0
- package/src/user-data-rights-defaults/hooks/notification-preference.userdata-hook.ts +54 -0
- package/src/user-data-rights-defaults/hooks/tenant-invitation.userdata-hook.ts +112 -0
- package/src/user-data-rights-defaults/hooks/user-session.userdata-hook.ts +42 -0
- package/src/user-data-rights-defaults/index.ts +26 -0
- package/src/user-profile/__tests__/change-email.integration.test.ts +7 -1
- package/src/user-profile/__tests__/profile-screen.test.tsx +5 -0
- package/src/user-profile/feature.ts +4 -1
- package/src/user-profile/handlers/change-email.write.ts +15 -10
- package/src/user-profile/web/profile-screen.tsx +15 -3
- package/src/auth-email-password/stream-tenant.ts +0 -31
- package/src/feature-toggles/db/queries/toggle-state.ts +0 -25
- package/src/legal-pages/security-headers.ts +0 -1
- package/src/sessions/schema/index.ts +0 -5
- package/src/tenant/schema/index.ts +0 -5
- package/src/user/schema/index.ts +0 -5
- /package/src/{auth-email-password → shared}/identity-v3-hash.ts +0 -0
|
@@ -33,7 +33,12 @@
|
|
|
33
33
|
// retried automatisch).
|
|
34
34
|
|
|
35
35
|
import { fetchOne, selectMany } from "@cosmicdrift/kumiko-framework/bun-db";
|
|
36
|
-
import
|
|
36
|
+
import {
|
|
37
|
+
configuredPiiSubjectKms,
|
|
38
|
+
type KmsAdapter,
|
|
39
|
+
subjectIdToKey,
|
|
40
|
+
} from "@cosmicdrift/kumiko-framework/crypto";
|
|
41
|
+
import { type DbRunner, nullBlindIndexesForSubject } from "@cosmicdrift/kumiko-framework/db";
|
|
37
42
|
import {
|
|
38
43
|
EXT_USER_DATA,
|
|
39
44
|
EXT_USER_DATA_ORDER,
|
|
@@ -46,6 +51,7 @@ import {
|
|
|
46
51
|
} from "@cosmicdrift/kumiko-framework/engine";
|
|
47
52
|
import type { getTemporal } from "@cosmicdrift/kumiko-framework/time";
|
|
48
53
|
import { resolveRetentionPolicyForTenant } from "../data-retention";
|
|
54
|
+
import { decryptStoredPii } from "../shared";
|
|
49
55
|
import { tenantMembershipsTable } from "../tenant";
|
|
50
56
|
import { USER_STATUS, userTable } from "../user";
|
|
51
57
|
import { selectUsersDueForForgetCleanup } from "./db/queries/forget-cleanup";
|
|
@@ -101,6 +107,15 @@ export interface RunForgetCleanupArgs {
|
|
|
101
107
|
tenantId: TenantId,
|
|
102
108
|
) => Promise<UserDataStorageProvider | undefined>;
|
|
103
109
|
|
|
110
|
+
/**
|
|
111
|
+
* KMS for crypto-shredding: erases the per-user subject key after the
|
|
112
|
+
* delete-hooks, inside the per-user sub-tx, right before the status flip.
|
|
113
|
+
* Defaults to the boot-configured adapter (configurePiiSubjectKms);
|
|
114
|
+
* explicit arg is the test seam. Omitted + none configured → plaintext
|
|
115
|
+
* deployment, nothing to shred.
|
|
116
|
+
*/
|
|
117
|
+
readonly kms?: KmsAdapter;
|
|
118
|
+
|
|
104
119
|
/**
|
|
105
120
|
* App-level tenant-occupancy model (resolved from the `tenantModel` config by
|
|
106
121
|
* the cron/handler). The pipeline refines it PER TENANT with a sole-member
|
|
@@ -118,6 +133,24 @@ export interface ForgetCleanupError {
|
|
|
118
133
|
readonly message: string;
|
|
119
134
|
}
|
|
120
135
|
|
|
136
|
+
/** A hook reporting `{status:"incomplete", reason}` — no throw, no
|
|
137
|
+
* rollback, the user still gets flipped to Deleted (see Header
|
|
138
|
+
* "incomplete is not a hard failure"). Collected for operator
|
|
139
|
+
* visibility, NOT in `errors` (those stand for hook throws + rollback). */
|
|
140
|
+
export interface ForgetCleanupIncomplete {
|
|
141
|
+
readonly userId: string;
|
|
142
|
+
readonly tenantId: TenantId;
|
|
143
|
+
readonly entityName: string;
|
|
144
|
+
readonly reason: string;
|
|
145
|
+
/** True when a LATER hook in the same user's sub-tx threw, rolling back
|
|
146
|
+
* the DB rows (including the status flip) — but this hook's own
|
|
147
|
+
* non-transactional side effect (e.g. an already-issued S3 delete,
|
|
148
|
+
* a provider API call) already ran and does NOT get undone by that
|
|
149
|
+
* rollback. The user is still DeletionRequested and will retry, but
|
|
150
|
+
* this partial external effect needs its own operator follow-up. */
|
|
151
|
+
readonly rolledBack: boolean;
|
|
152
|
+
}
|
|
153
|
+
|
|
121
154
|
export interface RunForgetCleanupResult {
|
|
122
155
|
/** User die in diesem Lauf von DeletionRequested → Deleted geflippt wurden. */
|
|
123
156
|
readonly processedUserIds: readonly string[];
|
|
@@ -125,6 +158,8 @@ export interface RunForgetCleanupResult {
|
|
|
125
158
|
readonly hookCallsAttempted: number;
|
|
126
159
|
/** Hook-Errors fuer Operator-Visibility. Lauf bricht nicht ab — siehe Header. */
|
|
127
160
|
readonly errors: readonly ForgetCleanupError[];
|
|
161
|
+
/** Hooks that reported `{status:"incomplete"}` — partial success, user still Deleted. */
|
|
162
|
+
readonly incomplete: readonly ForgetCleanupIncomplete[];
|
|
128
163
|
}
|
|
129
164
|
|
|
130
165
|
interface HookEntry {
|
|
@@ -140,21 +175,31 @@ interface HookEntry {
|
|
|
140
175
|
// hook that nulls that column. See custom-fields wire-user-data-rights.ts.
|
|
141
176
|
const HOOK_ORDER_DEFAULT = EXT_USER_DATA_ORDER.DEFAULT;
|
|
142
177
|
|
|
178
|
+
// Hook-reported reasons are external input (provider error messages can embed
|
|
179
|
+
// user-controlled filenames/emails) — strip newlines before a single-line
|
|
180
|
+
// console.warn so a crafted reason can't forge extra log lines, and cap the
|
|
181
|
+
// length against a log-flood. The unsanitized reason still lands in the
|
|
182
|
+
// returned `incomplete` entry untouched.
|
|
183
|
+
export function sanitizeReasonForLog(reason: string): string {
|
|
184
|
+
return reason.replace(/[\r\n]+/g, " ").slice(0, 500);
|
|
185
|
+
}
|
|
186
|
+
|
|
143
187
|
export async function runForgetCleanup(
|
|
144
188
|
args: RunForgetCleanupArgs,
|
|
145
189
|
): Promise<RunForgetCleanupResult> {
|
|
146
190
|
const { db, registry, now, sendDeletionExecutedEmail, buildStorageProvider } = args;
|
|
191
|
+
const kms = args.kms ?? configuredPiiSubjectKms();
|
|
147
192
|
const appTenantModel: TenantUserModel = args.tenantModel ?? "multi-user";
|
|
148
193
|
|
|
149
194
|
// Step 1: Find users with expired grace period.
|
|
150
195
|
const dueUsers = await selectUsersDueForForgetCleanup(
|
|
151
|
-
db,
|
|
196
|
+
db as import("@cosmicdrift/kumiko-types/db-connection").DbConnection,
|
|
152
197
|
USER_STATUS.DeletionRequested,
|
|
153
198
|
now.toString(),
|
|
154
199
|
);
|
|
155
200
|
|
|
156
201
|
if (dueUsers.length === 0) {
|
|
157
|
-
return { processedUserIds: [], hookCallsAttempted: 0, errors: [] };
|
|
202
|
+
return { processedUserIds: [], hookCallsAttempted: 0, errors: [], incomplete: [] };
|
|
158
203
|
}
|
|
159
204
|
|
|
160
205
|
// Step 2: Sammle alle EXT_USER_DATA-Usages einmalig — Liste der
|
|
@@ -176,6 +221,7 @@ export async function runForgetCleanup(
|
|
|
176
221
|
.sort((a, b) => a.order - b.order);
|
|
177
222
|
|
|
178
223
|
const errors: ForgetCleanupError[] = [];
|
|
224
|
+
const incomplete: ForgetCleanupIncomplete[] = [];
|
|
179
225
|
const processedUserIds: string[] = [];
|
|
180
226
|
let hookCallsAttempted = 0;
|
|
181
227
|
|
|
@@ -188,9 +234,11 @@ export async function runForgetCleanup(
|
|
|
188
234
|
hookEntries,
|
|
189
235
|
buildStorageProvider,
|
|
190
236
|
appTenantModel,
|
|
237
|
+
kms,
|
|
191
238
|
});
|
|
192
239
|
hookCallsAttempted += userResult.hookCallsAttempted;
|
|
193
240
|
errors.push(...userResult.errors);
|
|
241
|
+
incomplete.push(...userResult.incomplete);
|
|
194
242
|
if (userResult.success) {
|
|
195
243
|
processedUserIds.push(user.id);
|
|
196
244
|
|
|
@@ -224,13 +272,14 @@ export async function runForgetCleanup(
|
|
|
224
272
|
}
|
|
225
273
|
}
|
|
226
274
|
|
|
227
|
-
return { processedUserIds, hookCallsAttempted, errors };
|
|
275
|
+
return { processedUserIds, hookCallsAttempted, errors, incomplete };
|
|
228
276
|
}
|
|
229
277
|
|
|
230
278
|
interface ProcessUserResult {
|
|
231
279
|
readonly success: boolean;
|
|
232
280
|
readonly hookCallsAttempted: number;
|
|
233
281
|
readonly errors: readonly ForgetCleanupError[];
|
|
282
|
+
readonly incomplete: readonly ForgetCleanupIncomplete[];
|
|
234
283
|
/** Atom 5b: userEmail VOR Tx gecacht (user-Hook anonymisiert in Tx).
|
|
235
284
|
* null wenn user-Row beim Pre-Tx-Lookup nicht (mehr) existiert oder
|
|
236
285
|
* email leer ist. */
|
|
@@ -248,9 +297,11 @@ async function processUser(args: {
|
|
|
248
297
|
hookEntries: readonly HookEntry[];
|
|
249
298
|
buildStorageProvider?: (tenantId: TenantId) => Promise<UserDataStorageProvider | undefined>;
|
|
250
299
|
appTenantModel: TenantUserModel;
|
|
300
|
+
kms?: KmsAdapter;
|
|
251
301
|
}): Promise<ProcessUserResult> {
|
|
252
|
-
const { db, registry, userId, hookEntries, buildStorageProvider, appTenantModel } = args;
|
|
302
|
+
const { db, registry, userId, hookEntries, buildStorageProvider, appTenantModel, kms } = args;
|
|
253
303
|
const errors: ForgetCleanupError[] = [];
|
|
304
|
+
const incomplete: Omit<ForgetCleanupIncomplete, "rolledBack">[] = [];
|
|
254
305
|
let hookCallsAttempted = 0;
|
|
255
306
|
|
|
256
307
|
// Atom 5b — userEmail VOR der Tx cachen. user-Hook (user-data-rights-
|
|
@@ -262,7 +313,9 @@ async function processUser(args: {
|
|
|
262
313
|
id: userId,
|
|
263
314
|
});
|
|
264
315
|
const userEmailBeforeDelete =
|
|
265
|
-
userPreTx?.email && userPreTx.email.length > 0
|
|
316
|
+
userPreTx?.email && userPreTx.email.length > 0
|
|
317
|
+
? await decryptStoredPii(userPreTx.email, "email", "user-data-rights:forget-cleanup")
|
|
318
|
+
: null;
|
|
266
319
|
const userLocaleBeforeDelete = userPreTx?.locale ?? null;
|
|
267
320
|
|
|
268
321
|
// Memberships fuer diesen User holen — alle Tenants in denen er Mitglied ist.
|
|
@@ -313,9 +366,10 @@ async function processUser(args: {
|
|
|
313
366
|
const strategy = policyToStrategy(policy.policy?.strategy ?? null);
|
|
314
367
|
|
|
315
368
|
hookCallsAttempted++;
|
|
316
|
-
await entry.deleteHook(
|
|
369
|
+
const hookResult = await entry.deleteHook(
|
|
317
370
|
{
|
|
318
371
|
db: tx,
|
|
372
|
+
registry,
|
|
319
373
|
tenantId,
|
|
320
374
|
userId,
|
|
321
375
|
buildStorageProvider,
|
|
@@ -324,9 +378,52 @@ async function processUser(args: {
|
|
|
324
378
|
},
|
|
325
379
|
strategy,
|
|
326
380
|
);
|
|
381
|
+
// "incomplete" is not a hard failure (see Header): no throw,
|
|
382
|
+
// no rollback, eraseKey + status flip proceed unchanged.
|
|
383
|
+
// Only collected + logged for operator visibility.
|
|
384
|
+
if (hookResult?.status === "incomplete") {
|
|
385
|
+
incomplete.push({
|
|
386
|
+
userId,
|
|
387
|
+
tenantId,
|
|
388
|
+
entityName: entry.entityName,
|
|
389
|
+
reason: hookResult.reason,
|
|
390
|
+
});
|
|
391
|
+
// biome-ignore lint/suspicious/noConsole: operator-visibility for partial hook completion
|
|
392
|
+
console.warn(
|
|
393
|
+
`[user-data-rights:run-forget-cleanup] hook incomplete userId=${userId} tenantId=${tenantId} entityName=${entry.entityName} reason=${sanitizeReasonForLog(hookResult.reason)}`,
|
|
394
|
+
);
|
|
395
|
+
}
|
|
327
396
|
}
|
|
328
397
|
}
|
|
329
398
|
|
|
399
|
+
// Crypto-shredding: erase the user's subject key AFTER the hooks and
|
|
400
|
+
// BEFORE the status flip. The KMS is not a tx participant, so ordering
|
|
401
|
+
// is what makes this crash-safe: eraseKey-throw → tx rollback → user
|
|
402
|
+
// stays DeletionRequested → next run retries; flip-throw after a
|
|
403
|
+
// successful erase → retry re-runs the idempotent hooks and eraseKey
|
|
404
|
+
// (contractually a no-op on an erased/unknown subject). Erasing after
|
|
405
|
+
// the flip instead would risk a permanent silent miss: user already
|
|
406
|
+
// Deleted, no run ever picks him up again, key stays live.
|
|
407
|
+
if (kms) {
|
|
408
|
+
await kms.eraseKey(
|
|
409
|
+
{ kind: "user", userId },
|
|
410
|
+
{
|
|
411
|
+
requestId: "user-data-rights:run-forget-cleanup",
|
|
412
|
+
userId,
|
|
413
|
+
eraseReason: "user-data-rights:forget",
|
|
414
|
+
},
|
|
415
|
+
);
|
|
416
|
+
// Blind-Index-Sweep (#818): bidx-Spalten des erased Subjects sofort
|
|
417
|
+
// nullen — sonst bliebe der deterministische HMAC bis zum nächsten
|
|
418
|
+
// Rebuild equality-matchbar (Linkage-Fenster). In der Sub-Tx, damit
|
|
419
|
+
// ein Rollback auch den Sweep zurücknimmt.
|
|
420
|
+
await nullBlindIndexesForSubject(
|
|
421
|
+
tx,
|
|
422
|
+
registry.features,
|
|
423
|
+
subjectIdToKey({ kind: "user", userId }),
|
|
424
|
+
);
|
|
425
|
+
}
|
|
426
|
+
|
|
330
427
|
// Status-Flip in derselben Sub-Tx. Falls einer der Hooks oben
|
|
331
428
|
// geworfen hat, kommen wir hier nicht an — die Tx rollback'd
|
|
332
429
|
// alles, der User bleibt im DeletionRequested-Status, naechster
|
|
@@ -350,6 +447,14 @@ async function processUser(args: {
|
|
|
350
447
|
success: txSucceeded,
|
|
351
448
|
hookCallsAttempted,
|
|
352
449
|
errors,
|
|
450
|
+
// Reported either way — a rolled-back sub-tx doesn't undo an
|
|
451
|
+
// "incomplete" hook's own non-transactional side effect (S3 delete,
|
|
452
|
+
// provider call), so dropping the report entirely would hide exactly
|
|
453
|
+
// the case its own reason string describes ("would report a
|
|
454
|
+
// not-yet-deleted user as partially cleaned up" — true of the DB rows,
|
|
455
|
+
// not of that external effect). `rolledBack` lets the operator tell
|
|
456
|
+
// the two situations apart instead of losing the signal outright.
|
|
457
|
+
incomplete: incomplete.map((i) => ({ ...i, rolledBack: !txSucceeded })),
|
|
353
458
|
userEmailBeforeDelete,
|
|
354
459
|
userLocaleBeforeDelete,
|
|
355
460
|
tenantIdsBeforeDelete,
|
|
@@ -21,7 +21,17 @@
|
|
|
21
21
|
// expliziert KEIN passwordHash + KEINE roles (privileged columns).
|
|
22
22
|
|
|
23
23
|
import { selectMany } from "@cosmicdrift/kumiko-framework/bun-db";
|
|
24
|
+
import {
|
|
25
|
+
configuredPiiSubjectKms,
|
|
26
|
+
decryptPiiFieldValues,
|
|
27
|
+
isPiiCiphertext,
|
|
28
|
+
} from "@cosmicdrift/kumiko-framework/crypto";
|
|
24
29
|
import type { DbRunner } from "@cosmicdrift/kumiko-framework/db";
|
|
30
|
+
import {
|
|
31
|
+
collectEncryptedFieldNames,
|
|
32
|
+
configuredEntityFieldEncryption,
|
|
33
|
+
decryptEntityFieldValues,
|
|
34
|
+
} from "@cosmicdrift/kumiko-framework/db";
|
|
25
35
|
import {
|
|
26
36
|
EXT_USER_DATA,
|
|
27
37
|
type Registry,
|
|
@@ -137,8 +147,9 @@ export async function runUserExport(args: RunUserExportArgs): Promise<UserExport
|
|
|
137
147
|
for (const tenantId of tenantList) {
|
|
138
148
|
const entities: UserDataExportSnippet[] = [];
|
|
139
149
|
for (const entry of hookEntries) {
|
|
140
|
-
const
|
|
141
|
-
if (
|
|
150
|
+
const rawSnippet = await entry.exportHook({ db, registry, tenantId, userId });
|
|
151
|
+
if (rawSnippet === null) continue;
|
|
152
|
+
const snippet = await decryptSnippetFields(registry, entry.entityName, rawSnippet);
|
|
142
153
|
entities.push(snippet);
|
|
143
154
|
if (snippet.fileRefs) {
|
|
144
155
|
for (const ref of snippet.fileRefs) {
|
|
@@ -169,12 +180,14 @@ export async function runUserExport(args: RunUserExportArgs): Promise<UserExport
|
|
|
169
180
|
if (tenantList.length === 0 && hookEntries.length > 0) {
|
|
170
181
|
const orphanEntities: UserDataExportSnippet[] = [];
|
|
171
182
|
for (const entry of hookEntries) {
|
|
172
|
-
const
|
|
183
|
+
const rawSnippet = await entry.exportHook({
|
|
173
184
|
db,
|
|
185
|
+
registry,
|
|
174
186
|
tenantId: SYSTEM_TENANT_ID_FOR_ORPHANS,
|
|
175
187
|
userId,
|
|
176
188
|
});
|
|
177
|
-
if (
|
|
189
|
+
if (rawSnippet === null) continue;
|
|
190
|
+
const snippet = await decryptSnippetFields(registry, entry.entityName, rawSnippet);
|
|
178
191
|
orphanEntities.push(snippet);
|
|
179
192
|
if (snippet.fileRefs) {
|
|
180
193
|
for (const ref of snippet.fileRefs) {
|
|
@@ -203,6 +216,59 @@ export async function runUserExport(args: RunUserExportArgs): Promise<UserExport
|
|
|
203
216
|
};
|
|
204
217
|
}
|
|
205
218
|
|
|
219
|
+
// Art. 20 verlangt die DATEN, nicht deren Ciphertext: Export-Hooks lesen
|
|
220
|
+
// raw rows an der Executor-Decrypt-Schicht vorbei, darum entschluesselt
|
|
221
|
+
// dieser zentrale Pass encrypted entity fields nach jedem Hook. Ohne
|
|
222
|
+
// konfigurierten Cipher wird ein expliziter Marker exportiert statt den
|
|
223
|
+
// base64-Blob als "Wert" auszuliefern (leak-by-confusion).
|
|
224
|
+
const ENCRYPTED_UNAVAILABLE = "[encrypted:unavailable]";
|
|
225
|
+
|
|
226
|
+
async function decryptSnippetFields(
|
|
227
|
+
registry: Registry,
|
|
228
|
+
hookEntityName: string,
|
|
229
|
+
snippet: UserDataExportSnippet,
|
|
230
|
+
): Promise<UserDataExportSnippet> {
|
|
231
|
+
let rows = snippet.rows;
|
|
232
|
+
|
|
233
|
+
const entity = registry.getEntity(snippet.entity) ?? registry.getEntity(hookEntityName);
|
|
234
|
+
if (entity) {
|
|
235
|
+
const encryptedFields = collectEncryptedFieldNames(entity);
|
|
236
|
+
if (encryptedFields.size > 0) {
|
|
237
|
+
const cipher = configuredEntityFieldEncryption();
|
|
238
|
+
rows = await Promise.all(
|
|
239
|
+
rows.map(async (row) => {
|
|
240
|
+
if (cipher) return decryptEntityFieldValues(row, encryptedFields, cipher);
|
|
241
|
+
const out = { ...row };
|
|
242
|
+
for (const name of encryptedFields) {
|
|
243
|
+
if (typeof out[name] === "string") out[name] = ENCRYPTED_UNAVAILABLE;
|
|
244
|
+
}
|
|
245
|
+
return out;
|
|
246
|
+
}),
|
|
247
|
+
);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// PII-Subject-Ciphertexte (kumiko-pii:) sind self-describing — kein
|
|
252
|
+
// Entity-Kontext noetig, deckt jeden heutigen und kuenftigen Hook ab.
|
|
253
|
+
// Erased Subject → Sentinel (ehrlich: der Wert ist geshreddet).
|
|
254
|
+
const kms = configuredPiiSubjectKms();
|
|
255
|
+
rows = await Promise.all(
|
|
256
|
+
rows.map(async (row) => {
|
|
257
|
+
const piiKeys = Object.keys(row).filter((k) => isPiiCiphertext(row[k]));
|
|
258
|
+
if (piiKeys.length === 0) return row;
|
|
259
|
+
if (!kms) {
|
|
260
|
+
const out = { ...row };
|
|
261
|
+
for (const k of piiKeys) out[k] = ENCRYPTED_UNAVAILABLE;
|
|
262
|
+
return out;
|
|
263
|
+
}
|
|
264
|
+
return decryptPiiFieldValues(row, piiKeys, kms, {
|
|
265
|
+
requestId: "user-data-rights:export",
|
|
266
|
+
});
|
|
267
|
+
}),
|
|
268
|
+
);
|
|
269
|
+
return { ...snippet, rows };
|
|
270
|
+
}
|
|
271
|
+
|
|
206
272
|
// Pseudo-Tenant fuer User ohne aktive Memberships. Identisch zum
|
|
207
273
|
// Pattern in run-forget-cleanup.ts — RFC4122-Null-UUID. Tenant-scoped
|
|
208
274
|
// Hooks finden hier nichts (no-op).
|
|
@@ -93,9 +93,11 @@ export const exportDownloadTokenEntity = createEntity({
|
|
|
93
93
|
}),
|
|
94
94
|
},
|
|
95
95
|
|
|
96
|
-
// 1 Token pro Job. UNIQUE auf jobId —
|
|
97
|
-
//
|
|
98
|
-
//
|
|
96
|
+
// 1 Token pro Job. UNIQUE auf jobId — Backstop fuer Worker-Idempotency
|
|
97
|
+
// (Atom 3b's "2× run done-Job → no-op"). Der Worker created NIE ein
|
|
98
|
+
// zweites Aggregat fuers gleiche jobId: Re-Runs rotieren das Token
|
|
99
|
+
// in place via update (fw#832) — sonst kollidiert der Projection-
|
|
100
|
+
// Rebuild an genau diesem Index.
|
|
99
101
|
indexes: [
|
|
100
102
|
{
|
|
101
103
|
unique: true,
|
|
@@ -73,6 +73,7 @@ export const exportJobEntity = createEntity({
|
|
|
73
73
|
// nur Storage.
|
|
74
74
|
userId: createTextField({
|
|
75
75
|
required: true,
|
|
76
|
+
searchable: true,
|
|
76
77
|
}),
|
|
77
78
|
|
|
78
79
|
// **requestedFromTenantId** — der Tenant aus dem der User den Antrag
|
|
@@ -102,6 +103,7 @@ export const exportJobEntity = createEntity({
|
|
|
102
103
|
// entsteht ohne Klick.
|
|
103
104
|
requestedAt: createTimestampField({
|
|
104
105
|
required: true,
|
|
106
|
+
sortable: true,
|
|
105
107
|
}),
|
|
106
108
|
|
|
107
109
|
// Wann hat der Worker mit dem Pickup angefangen. NULL solange
|
|
@@ -71,6 +71,7 @@ function makeDispatcher(
|
|
|
71
71
|
query,
|
|
72
72
|
batch: (async () => ({ isSuccess: true, results: [] })) as unknown as Dispatcher["batch"],
|
|
73
73
|
statusStore,
|
|
74
|
+
async *stream() {},
|
|
74
75
|
pendingWrites: () => [],
|
|
75
76
|
pendingFiles: () => [],
|
|
76
77
|
} as unknown as Dispatcher; // @cast-boundary test-stub
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
// Provider-Wrapper lokal (Dependency-Richtung renderer-web → bundled-features
|
|
6
6
|
// verbietet test-utils-Import).
|
|
7
7
|
|
|
8
|
-
import { describe, expect, test } from "bun:test";
|
|
8
|
+
import { afterEach, describe, expect, test } from "bun:test";
|
|
9
9
|
import type { Dispatcher } from "@cosmicdrift/kumiko-headless";
|
|
10
10
|
import {
|
|
11
11
|
createStaticLocaleResolver,
|
|
@@ -27,6 +27,12 @@ const stubDispatcher = {
|
|
|
27
27
|
|
|
28
28
|
const ROUTES = { requestPath: "/account/delete", confirmPath: "/account/delete/confirm" };
|
|
29
29
|
|
|
30
|
+
// renderGate mutates the shared happy-dom document's history (570/1) — reset
|
|
31
|
+
// so a later, unrelated test file doesn't inherit this suite's last path.
|
|
32
|
+
afterEach(() => {
|
|
33
|
+
window.history.replaceState({}, "", "/");
|
|
34
|
+
});
|
|
35
|
+
|
|
30
36
|
function renderGate(path: string, gate: ReactNode): ReturnType<typeof within> {
|
|
31
37
|
window.history.replaceState({}, "", path);
|
|
32
38
|
const { container } = render(
|
|
@@ -45,5 +45,10 @@ export function userDataRightsClient(
|
|
|
45
45
|
},
|
|
46
46
|
};
|
|
47
47
|
if (options?.publicDeletion === undefined) return base;
|
|
48
|
-
|
|
48
|
+
// Extend, not overwrite (570/2) — base.gates is empty today, but a spread
|
|
49
|
+
// that clobbers it instead of appending would silently drop future gates.
|
|
50
|
+
return {
|
|
51
|
+
...base,
|
|
52
|
+
gates: [...(base.gates ?? []), makePublicDeletionGate(options.publicDeletion)],
|
|
53
|
+
};
|
|
49
54
|
}
|
|
@@ -5,8 +5,24 @@
|
|
|
5
5
|
// deletion.<step>.<slug>`.
|
|
6
6
|
|
|
7
7
|
import type { TranslationsByLocale } from "@cosmicdrift/kumiko-renderer";
|
|
8
|
+
import { USER_DATA_RIGHTS_I18N } from "../i18n";
|
|
8
9
|
|
|
9
|
-
|
|
10
|
+
const LOCALES = ["de", "en"] as const;
|
|
11
|
+
|
|
12
|
+
// Operator keys (export-job list/detail titles + entity field labels + nav)
|
|
13
|
+
// live in the server i18n; the SystemAdmin entityList screens render them
|
|
14
|
+
// client-side, so the web bundle must carry them too — otherwise raw keys
|
|
15
|
+
// show. Derive from the single server source instead of duplicating.
|
|
16
|
+
const operatorTranslations: TranslationsByLocale = Object.fromEntries(
|
|
17
|
+
LOCALES.map((locale) => [
|
|
18
|
+
locale,
|
|
19
|
+
Object.fromEntries(
|
|
20
|
+
Object.entries(USER_DATA_RIGHTS_I18N).map(([key, value]) => [key, value[locale]]),
|
|
21
|
+
),
|
|
22
|
+
]),
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
const apexTranslations: TranslationsByLocale = {
|
|
10
26
|
de: {
|
|
11
27
|
"userDataRights.deletion.request.title": "Account-Löschung beantragen",
|
|
12
28
|
"userDataRights.deletion.request.intro":
|
|
@@ -74,11 +90,6 @@ export const defaultTranslations: TranslationsByLocale = {
|
|
|
74
90
|
"userDataRights.privacyCenter.deletion.dialogTitle": "Konto wirklich löschen?",
|
|
75
91
|
"userDataRights.privacyCenter.deletion.dialogDescription":
|
|
76
92
|
"Mit dem Bestätigen startet die Lösch-Frist. Du kannst die Löschung bis zu ihrem Ablauf wieder abbrechen.",
|
|
77
|
-
|
|
78
|
-
"userDataRights.privacyCenter.audit.title": "Aktivitätsprotokoll (Art. 15)",
|
|
79
|
-
"userDataRights.privacyCenter.audit.intro":
|
|
80
|
-
"Die letzten Ereignisse zu deinem Konto über alle Tenants hinweg.",
|
|
81
|
-
"userDataRights.privacyCenter.audit.empty": "Noch keine Ereignisse.",
|
|
82
93
|
},
|
|
83
94
|
en: {
|
|
84
95
|
"userDataRights.deletion.request.title": "Request account deletion",
|
|
@@ -147,9 +158,18 @@ export const defaultTranslations: TranslationsByLocale = {
|
|
|
147
158
|
"userDataRights.privacyCenter.deletion.dialogDescription":
|
|
148
159
|
"Confirming starts the deletion grace period. You can cancel the deletion until it ends.",
|
|
149
160
|
|
|
150
|
-
"userDataRights.
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
161
|
+
"userDataRights.errors.download.notFound":
|
|
162
|
+
"The download link is invalid or belongs to a different account.",
|
|
163
|
+
"userDataRights.errors.download.expired":
|
|
164
|
+
"Your download has expired. Please request a new export.",
|
|
165
|
+
"userDataRights.errors.download.unavailable":
|
|
166
|
+
"The export is not yet ready or has failed. Please check the status endpoint.",
|
|
167
|
+
"userDataRights.errors.download.signedUrlNotSupported":
|
|
168
|
+
"The download is currently unavailable due to a server configuration issue. The operator has been notified.",
|
|
154
169
|
},
|
|
155
170
|
};
|
|
171
|
+
|
|
172
|
+
export const defaultTranslations: TranslationsByLocale = {
|
|
173
|
+
de: { ...apexTranslations["de"], ...operatorTranslations["de"] },
|
|
174
|
+
en: { ...apexTranslations["en"], ...operatorTranslations["en"] },
|
|
175
|
+
};
|
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
useQuery,
|
|
20
20
|
useTranslation,
|
|
21
21
|
} from "@cosmicdrift/kumiko-renderer";
|
|
22
|
-
import { postWithDownload } from "@cosmicdrift/kumiko-renderer-web";
|
|
22
|
+
import { FormScreenShell, postWithDownload } from "@cosmicdrift/kumiko-renderer-web";
|
|
23
23
|
import { type ReactNode, useEffect, useState } from "react";
|
|
24
24
|
import {
|
|
25
25
|
EXPORT_JOB_STATUS,
|
|
@@ -224,6 +224,7 @@ function RestrictionSection({
|
|
|
224
224
|
<Section
|
|
225
225
|
title={t("userDataRights.privacyCenter.restriction.title")}
|
|
226
226
|
testId="privacy-restriction"
|
|
227
|
+
variant="destructive"
|
|
227
228
|
actions={
|
|
228
229
|
restricted ? undefined : (
|
|
229
230
|
<Button
|
|
@@ -303,6 +304,7 @@ function DeletionSection({
|
|
|
303
304
|
<Section
|
|
304
305
|
title={t("userDataRights.privacyCenter.deletion.title")}
|
|
305
306
|
testId="privacy-deletion"
|
|
307
|
+
variant="destructive"
|
|
306
308
|
actions={
|
|
307
309
|
deletionRequested ? (
|
|
308
310
|
<Button
|
|
@@ -384,12 +386,12 @@ export function PrivacyCenterScreen({
|
|
|
384
386
|
};
|
|
385
387
|
|
|
386
388
|
return (
|
|
387
|
-
<
|
|
389
|
+
<FormScreenShell className="flex flex-col gap-6" testId="privacy-center-screen">
|
|
388
390
|
<Heading variant="page">{t("userDataRights.privacyCenter.title")}</Heading>
|
|
389
391
|
<p className="text-sm text-muted-foreground">{t("userDataRights.privacyCenter.intro")}</p>
|
|
390
392
|
<ExportSection />
|
|
391
393
|
<RestrictionSection me={me} onChanged={refetch} />
|
|
392
394
|
{showDeletion && <DeletionSection me={me} onChanged={refetch} />}
|
|
393
|
-
</
|
|
395
|
+
</FormScreenShell>
|
|
394
396
|
);
|
|
395
397
|
}
|