@cosmicdrift/kumiko-bundled-features 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/dist/agent-tools/tool-catalog.js +1 -1
- package/dist/agent-tools/tool-dispatch.js +0 -2
- package/dist/audit/screens.js +1 -1
- package/dist/auth-email-password/feature.js +1 -1
- package/dist/auth-email-password/handlers/change-password.write.js +3 -3
- package/dist/auth-email-password/handlers/confirm-token-flow.js +5 -5
- package/dist/auth-email-password/handlers/invite-accept-with-login.write.js +1 -1
- package/dist/auth-email-password/handlers/invite-accept.write.js +18 -18
- package/dist/auth-email-password/handlers/invite-create.write.d.ts +2 -2
- package/dist/auth-email-password/handlers/invite-create.write.js +10 -10
- package/dist/auth-email-password/handlers/invite-info.query.js +1 -1
- package/dist/auth-email-password/handlers/invite-signup-complete.write.js +24 -26
- package/dist/auth-email-password/handlers/login.write.d.ts +1 -1
- package/dist/auth-email-password/handlers/login.write.js +1 -1
- package/dist/auth-email-password/handlers/self-registration-status.query.js +1 -1
- package/dist/auth-email-password/handlers/signup-confirm.write.js +34 -37
- package/dist/auth-email-password/handlers/signup-request.write.js +6 -7
- package/dist/auth-email-password/handlers/switch-tenant-mfa-gate.write.d.ts +1 -1
- package/dist/auth-email-password/handlers/switch-tenant-mfa-gate.write.js +1 -4
- package/dist/auth-email-password/index.js +5 -5
- package/dist/auth-email-password/lockout-store.js +1 -1
- package/dist/auth-email-password/seeding.d.ts +42 -45
- package/dist/auth-email-password/seeding.js +51 -53
- package/dist/auth-email-password/signup-token-store.js +8 -8
- package/dist/auth-email-password/testing.js +3 -3
- package/dist/auth-email-password/web/auth-client.d.ts +2 -2
- package/dist/auth-email-password/web/auth-client.js +36 -37
- package/dist/auth-email-password/web/auth-form-primitives.js +10 -10
- package/dist/auth-email-password/web/auth-gate.js +15 -16
- package/dist/auth-email-password/web/client-plugin.d.ts +7 -7
- package/dist/auth-email-password/web/client-plugin.js +4 -5
- package/dist/auth-email-password/web/confirm-account-unlock-screen.js +1 -1
- package/dist/auth-email-password/web/constants.js +3 -3
- package/dist/auth-email-password/web/default-topbar-actions.d.ts +8 -8
- package/dist/auth-email-password/web/default-topbar-actions.js +6 -6
- package/dist/auth-email-password/web/forgot-password-screen.d.ts +2 -2
- package/dist/auth-email-password/web/forgot-password-screen.js +9 -9
- package/dist/auth-email-password/web/index.js +5 -5
- package/dist/auth-email-password/web/invite-accept-screen.d.ts +1 -1
- package/dist/auth-email-password/web/invite-accept-screen.js +16 -16
- package/dist/auth-email-password/web/login-screen.d.ts +1 -1
- package/dist/auth-email-password/web/login-screen.js +2 -3
- package/dist/auth-email-password/web/reset-password-screen.d.ts +4 -4
- package/dist/auth-email-password/web/reset-password-screen.js +12 -13
- package/dist/auth-email-password/web/session.d.ts +10 -9
- package/dist/auth-email-password/web/session.js +28 -29
- package/dist/auth-email-password/web/signup-complete-screen.js +3 -3
- package/dist/auth-email-password/web/signup-screen.d.ts +1 -1
- package/dist/auth-email-password/web/signup-screen.js +13 -13
- package/dist/auth-email-password/web/tenant-switcher.d.ts +4 -4
- package/dist/auth-email-password/web/tenant-switcher.js +21 -22
- package/dist/auth-email-password/web/use-shell-user.js +12 -13
- package/dist/auth-email-password/web/user-menu.d.ts +4 -4
- package/dist/auth-email-password/web/user-menu.js +12 -13
- package/dist/auth-email-password/web/verify-email-screen.d.ts +2 -2
- package/dist/auth-email-password/web/verify-email-screen.js +9 -10
- package/dist/auth-foundation/boot-checks.js +4 -4
- package/dist/auth-foundation/resolve-anonymous-access.d.ts +1 -1
- package/dist/auth-foundation/resolve-anonymous-access.js +3 -3
- package/dist/auth-foundation/types.js +2 -2
- package/dist/auth-mfa/handlers/disable.write.js +3 -3
- package/dist/auth-mfa/handlers/enable-confirm-preauth.write.js +4 -4
- package/dist/auth-mfa/handlers/enable-confirm.write.js +2 -2
- package/dist/auth-mfa/handlers/enable-start-preauth.write.js +1 -1
- package/dist/auth-mfa/handlers/reencrypt.job.js +1 -1
- package/dist/auth-mfa/handlers/regenerate-recovery.write.js +5 -5
- package/dist/auth-mfa/handlers/verify.write.js +1 -1
- package/dist/auth-mfa/token-secrets.js +1 -1
- package/dist/auth-mfa/web/client-plugin.d.ts +1 -1
- package/dist/auth-mfa/web/client-plugin.js +1 -1
- package/dist/auth-mfa/web/i18n.js +3 -3
- package/dist/auth-mfa/web/index.js +4 -4
- package/dist/auth-mfa/web/mfa-client.js +17 -16
- package/dist/auth-mfa/web/mfa-verify-screen.js +6 -6
- package/dist/billing-foundation/aggregate-id.d.ts +5 -5
- package/dist/billing-foundation/aggregate-id.js +10 -11
- package/dist/billing-foundation/entities.js +27 -27
- package/dist/billing-foundation/events.js +18 -17
- package/dist/billing-foundation/feature.js +42 -43
- package/dist/billing-foundation/get-subscription-for-tenant.d.ts +3 -3
- package/dist/billing-foundation/get-subscription-for-tenant.js +3 -5
- package/dist/billing-foundation/handlers/create-checkout-session.write.js +18 -17
- package/dist/billing-foundation/handlers/create-portal-session.write.js +11 -12
- package/dist/billing-foundation/handlers/list-subscriptions.query.js +4 -4
- package/dist/billing-foundation/handlers/process-event.write.js +20 -20
- package/dist/billing-foundation/projection.d.ts +15 -11
- package/dist/billing-foundation/projection.js +38 -37
- package/dist/billing-foundation/subscription-tier-sync.js +3 -3
- package/dist/billing-foundation/tenant-destroy-hook.d.ts +2 -2
- package/dist/billing-foundation/tenant-destroy-hook.js +7 -7
- package/dist/billing-foundation/types.d.ts +40 -41
- package/dist/billing-foundation/types.js +20 -20
- package/dist/billing-foundation/web/billing-plans-panel.js +4 -4
- package/dist/cap-counter/aggregate-id.js +8 -9
- package/dist/cap-counter/constants.js +11 -12
- package/dist/cap-counter/enforce-cap.d.ts +59 -62
- package/dist/cap-counter/enforce-cap.js +47 -48
- package/dist/cap-counter/entity.js +29 -29
- package/dist/cap-counter/feature.js +34 -35
- package/dist/cap-counter/handlers/increment-rolling.write.d.ts +2 -2
- package/dist/cap-counter/handlers/increment-rolling.write.js +31 -31
- package/dist/cap-counter/handlers/mark-soft-warned.write.js +4 -5
- package/dist/cap-counter/stock-cap-guard.js +1 -1
- package/dist/cap-counter/with-cap-enforcement.d.ts +3 -5
- package/dist/channel-email/smtp-transport.d.ts +18 -17
- package/dist/channel-email/smtp-transport.js +24 -21
- package/dist/channel-in-app/handlers/unread-count.query.js +3 -4
- package/dist/compliance-profiles/feature.js +4 -4
- package/dist/compliance-profiles/handlers/for-tenant.query.js +3 -6
- package/dist/compliance-profiles/handlers/list-profiles.query.js +5 -5
- package/dist/compliance-profiles/handlers/needs-profile.query.js +4 -4
- package/dist/compliance-profiles/handlers/set-profile.write.js +13 -14
- package/dist/compliance-profiles/handlers/sub-processors.query.js +9 -11
- package/dist/compliance-profiles/resolve-for-tenant.js +7 -7
- package/dist/compliance-profiles/schema/profile-selection.js +18 -23
- package/dist/compliance-profiles/seeding.js +14 -15
- package/dist/compliance-profiles-ops/handlers/tenants-missing-profile.query.js +3 -3
- package/dist/compliance-profiles-ops/index.js +2 -2
- package/dist/config/handlers/readiness.query.d.ts +4 -4
- package/dist/config/handlers/readiness.query.js +1 -1
- package/dist/config/handlers/reencrypt.job.js +4 -5
- package/dist/config/handlers/set.write.js +4 -4
- package/dist/config/resolver.js +4 -4
- package/dist/config/table.js +10 -10
- package/dist/config/write-helpers.js +1 -1
- package/dist/crypto-shredding/handlers/forget-subject.write.d.ts +2 -2
- package/dist/crypto-shredding/handlers/forget-subject.write.js +12 -11
- package/dist/custom-fields/aggregate-id.d.ts +12 -13
- package/dist/custom-fields/aggregate-id.js +16 -17
- package/dist/custom-fields/entity.js +49 -47
- package/dist/custom-fields/events.js +7 -8
- package/dist/custom-fields/feature.d.ts +14 -14
- package/dist/custom-fields/feature.js +53 -54
- package/dist/custom-fields/handlers/clear-custom-field.write.d.ts +3 -2
- package/dist/custom-fields/handlers/clear-custom-field.write.js +9 -8
- package/dist/custom-fields/handlers/define-tenant-field.write.d.ts +1 -1
- package/dist/custom-fields/handlers/define-tenant-field.write.js +2 -2
- package/dist/custom-fields/handlers/delete-system-field.write.js +6 -7
- package/dist/custom-fields/handlers/delete-tenant-field.write.d.ts +1 -1
- package/dist/custom-fields/handlers/delete-tenant-field.write.js +3 -3
- package/dist/custom-fields/handlers/set-custom-field.write.d.ts +3 -3
- package/dist/custom-fields/handlers/set-custom-field.write.js +25 -28
- package/dist/custom-fields/handlers/update-tenant-field.write.d.ts +1 -1
- package/dist/custom-fields/handlers/update-tenant-field.write.js +1 -1
- package/dist/custom-fields/lib/field-access.js +2 -2
- package/dist/custom-fields/lib/parse-serialized-field.js +1 -1
- package/dist/custom-fields/lib/quota.js +1 -1
- package/dist/custom-fields/lib/value-schema.js +10 -12
- package/dist/custom-fields/run-retention.js +3 -3
- package/dist/custom-fields/schemas.js +14 -14
- package/dist/custom-fields/web/client-plugin.js +2 -5
- package/dist/custom-fields/web/constants.js +2 -2
- package/dist/custom-fields/web/custom-fields-form-section.d.ts +4 -4
- package/dist/custom-fields/web/custom-fields-form-section.js +22 -22
- package/dist/custom-fields/wire-for-entity.js +65 -67
- package/dist/custom-fields/wire-user-data-rights.js +3 -3
- package/dist/data-retention/_internal/parse-override.js +2 -3
- package/dist/data-retention/feature.js +11 -18
- package/dist/data-retention/handlers/policy-for.query.js +6 -6
- package/dist/data-retention/keep-for.d.ts +7 -7
- package/dist/data-retention/keep-for.js +15 -15
- package/dist/data-retention/override-schema.d.ts +3 -4
- package/dist/data-retention/override-schema.js +13 -15
- package/dist/data-retention/presets.d.ts +4 -5
- package/dist/data-retention/presets.js +18 -23
- package/dist/data-retention/resolve-tenant-preset.js +17 -16
- package/dist/data-retention/resolver.d.ts +12 -12
- package/dist/data-retention/resolver.js +24 -23
- package/dist/data-retention/run-retention-cleanup.d.ts +8 -3
- package/dist/data-retention/run-retention-cleanup.js +61 -51
- package/dist/data-retention/schema/tenant-retention-override.js +13 -11
- package/dist/delivery/feature.js +2 -2
- package/dist/delivery/handlers/log.query.js +1 -1
- package/dist/delivery/tables.js +9 -8
- package/dist/delivery/unsubscribe.js +4 -4
- package/dist/document-ingest-foundation/entity.js +4 -4
- package/dist/document-ingest-foundation/events.js +2 -2
- package/dist/document-ingest-foundation/feature.js +2 -2
- package/dist/document-ingest-foundation/pages.js +1 -1
- package/dist/document-ingest-foundation/tenant-destroy-hook.js +4 -4
- package/dist/feature-toggles/compose-tier-resolver.js +1 -1
- package/dist/feature-toggles/feature.js +1 -1
- package/dist/feature-toggles/global-feature-state-table.js +1 -1
- package/dist/feature-toggles/handlers/registered.query.js +5 -5
- package/dist/feature-toggles/toggle-sync-signal.js +1 -1
- package/dist/feature-toggles/web/constants.js +1 -1
- package/dist/file-derivatives/feature.d.ts +1 -1
- package/dist/file-derivatives/feature.js +1 -1
- package/dist/file-derivatives/handlers/public-variant.query.js +1 -1
- package/dist/file-derivatives/presets.js +1 -1
- package/dist/file-foundation/feature.js +6 -6
- package/dist/file-provider-inmemory/feature.d.ts +1 -1
- package/dist/file-provider-inmemory/feature.js +16 -16
- package/dist/file-provider-s3/feature.js +16 -16
- package/dist/file-provider-s3/lib/s3-provider.js +6 -6
- package/dist/files/feature.js +6 -6
- package/dist/files-tenant-data/handlers/sweep-orphaned-derivatives.job.js +4 -4
- package/dist/files-tenant-data/hooks.js +24 -26
- package/dist/files-tenant-data/index.js +1 -1
- package/dist/folders/feature.d.ts +1 -1
- package/dist/folders/web/folder-manager.js +2 -2
- package/dist/folders/web/tree.js +5 -5
- package/dist/form-draft/db/queries/cleanup.js +1 -1
- package/dist/form-draft/db/queries/owned-file-refs.js +1 -1
- package/dist/form-draft/entity.js +3 -3
- package/dist/form-draft/feature.js +4 -5
- package/dist/form-draft/handlers/discard.write.js +1 -1
- package/dist/form-draft/release-file-refs.js +6 -6
- package/dist/form-draft/schemas.js +3 -3
- package/dist/form-draft/web/constants.js +0 -2
- package/dist/inbound-mail-foundation/aggregate-id.d.ts +13 -13
- package/dist/inbound-mail-foundation/aggregate-id.js +19 -19
- package/dist/inbound-mail-foundation/connect-routes.js +4 -3
- package/dist/inbound-mail-foundation/constants.d.ts +22 -24
- package/dist/inbound-mail-foundation/constants.js +30 -33
- package/dist/inbound-mail-foundation/entities.d.ts +12 -12
- package/dist/inbound-mail-foundation/entities.js +47 -48
- package/dist/inbound-mail-foundation/events.d.ts +4 -3
- package/dist/inbound-mail-foundation/events.js +50 -47
- package/dist/inbound-mail-foundation/feature.js +39 -39
- package/dist/inbound-mail-foundation/handlers/account-state.js +8 -8
- package/dist/inbound-mail-foundation/handlers/connect-account.write.js +25 -26
- package/dist/inbound-mail-foundation/handlers/disconnect-account.write.js +7 -7
- package/dist/inbound-mail-foundation/handlers/ingest-message.write.js +50 -51
- package/dist/inbound-mail-foundation/handlers/list-accounts.query.js +8 -8
- package/dist/inbound-mail-foundation/handlers/list-messages.query.js +10 -10
- package/dist/inbound-mail-foundation/handlers/scope-visibility.js +3 -4
- package/dist/inbound-mail-foundation/handlers/update-account.write.js +11 -11
- package/dist/inbound-mail-foundation/oauth-state.d.ts +5 -5
- package/dist/inbound-mail-foundation/oauth-state.js +11 -10
- package/dist/inbound-mail-foundation/projection.d.ts +4 -4
- package/dist/inbound-mail-foundation/projection.js +31 -29
- package/dist/inbound-mail-foundation/provider-factory.d.ts +4 -4
- package/dist/inbound-mail-foundation/provider-factory.js +9 -9
- package/dist/inbound-mail-foundation/retention-sweep.d.ts +5 -3
- package/dist/inbound-mail-foundation/retention-sweep.js +38 -36
- package/dist/inbound-mail-foundation/tenant-destroy-hook.js +14 -16
- package/dist/inbound-mail-foundation/types.d.ts +45 -46
- package/dist/inbound-mail-foundation/types.js +21 -21
- package/dist/inbound-mail-foundation/watch-supervisor.d.ts +10 -10
- package/dist/inbound-mail-foundation/watch-supervisor.js +57 -56
- package/dist/inbound-provider-imap/credential-document.js +13 -13
- package/dist/inbound-provider-imap/feature.d.ts +2 -2
- package/dist/inbound-provider-imap/feature.js +42 -40
- package/dist/inbound-provider-imap/imap-client.d.ts +12 -11
- package/dist/inbound-provider-imap/imap-client.js +20 -19
- package/dist/inbound-provider-inmemory/feature.d.ts +9 -9
- package/dist/inbound-provider-inmemory/feature.js +19 -19
- package/dist/jobs/db/queries/retention.js +2 -2
- package/dist/jobs/db/queries/stale-run-sweep.js +3 -3
- package/dist/jobs/events.js +1 -1
- package/dist/jobs/feature.js +5 -6
- package/dist/jobs/handlers/detail.query.js +4 -4
- package/dist/jobs/handlers/list.query.js +1 -1
- package/dist/jobs/handlers/projection-rebuild.job.js +1 -1
- package/dist/jobs/handlers/reindex-entity.job.js +1 -1
- package/dist/jobs/handlers/retry.write.js +1 -1
- package/dist/jobs/job-instant.js +1 -1
- package/dist/jobs/job-run-logger.js +10 -11
- package/dist/jobs/job-run-table.js +3 -3
- package/dist/jobs/screens.js +1 -1
- package/dist/jobs/tenant-job-failure-table.js +1 -1
- package/dist/jobs/tenant-job-run-table.js +1 -1
- package/dist/ledger/entity.js +5 -5
- package/dist/ledger/feature.js +3 -3
- package/dist/ledger/handlers/confirm-schedule-period.write.js +3 -3
- package/dist/ledger/recurring.js +12 -12
- package/dist/ledger/schemas.js +1 -1
- package/dist/ledger/web/constants.js +2 -2
- package/dist/ledger/web/index.js +7 -7
- package/dist/legal-pages/feature.d.ts +4 -4
- package/dist/legal-pages/feature.js +25 -26
- package/dist/legal-pages/markdown.js +3 -3
- package/dist/legal-pages/web/client-plugin.js +23 -24
- package/dist/legal-pages/web/index.js +0 -1
- package/dist/mail-foundation/feature.d.ts +2 -2
- package/dist/mail-foundation/feature.js +24 -25
- package/dist/mail-transport-inmemory/feature.d.ts +4 -4
- package/dist/mail-transport-inmemory/feature.js +27 -28
- package/dist/mail-transport-smtp/feature.js +20 -20
- package/dist/managed-pages/branding.js +6 -6
- package/dist/managed-pages/feature.d.ts +26 -26
- package/dist/managed-pages/feature.js +34 -34
- package/dist/managed-pages/handlers/by-slug.query.js +5 -6
- package/dist/managed-pages/handlers/by-tenant-published.query.js +2 -2
- package/dist/managed-pages/handlers/set.write.js +5 -7
- package/dist/managed-pages/screens/page-screens.js +11 -11
- package/dist/managed-pages/seeding.js +8 -8
- package/dist/managed-pages/table.js +13 -12
- package/dist/managed-pages/web/client-plugin.d.ts +1 -1
- package/dist/managed-pages/web/client-plugin.js +5 -5
- package/dist/managed-pages/web/i18n.js +1 -1
- package/dist/notes-history/entity.js +4 -4
- package/dist/notes-history/feature.d.ts +2 -2
- package/dist/notes-history-user-data/hooks.js +1 -1
- package/dist/page-render/layout.js +9 -9
- package/dist/page-render/markdown.js +11 -11
- package/dist/page-render/security-headers.js +7 -6
- package/dist/personal-access-tokens/feature.js +5 -5
- package/dist/personal-access-tokens/roles.js +2 -2
- package/dist/readiness/handlers/status.query.js +3 -3
- package/dist/renderer-foundation/api.js +12 -13
- package/dist/renderer-foundation/constants.js +2 -2
- package/dist/renderer-foundation/feature.js +7 -7
- package/dist/secrets/feature.js +9 -9
- package/dist/secrets/web/constants.js +2 -2
- package/dist/seo/feature.js +3 -3
- package/dist/sessions/constants.d.ts +1 -1
- package/dist/sessions/constants.js +1 -1
- package/dist/sessions/feature.js +8 -8
- package/dist/sessions/handlers/revoke-all-for-user.write.js +2 -2
- package/dist/sessions/handlers/revoke-all-others.write.js +2 -2
- package/dist/sessions/handlers/revoke.write.js +1 -1
- package/dist/sessions/schema/user-session.js +4 -4
- package/dist/sessions/screens.js +2 -2
- package/dist/sessions/session-callbacks.js +2 -2
- package/dist/sessions/session-revoked-event.js +2 -2
- package/dist/shared/assert-no-where-rule-in-ownership-write.js +1 -1
- package/dist/shared/decrypt-stored-pii.js +1 -1
- package/dist/shared/encrypt-for-direct-write.js +1 -1
- package/dist/shared/map-with-concurrency.js +5 -4
- package/dist/shared/parent-visibility.js +2 -2
- package/dist/shared/password-hashing.js +1 -1
- package/dist/shared/signup-handover.js +1 -2
- package/dist/shared/single-use-token-store.js +1 -1
- package/dist/subscription-mollie/constants.js +15 -17
- package/dist/subscription-mollie/feature.d.ts +17 -18
- package/dist/subscription-mollie/feature.js +24 -24
- package/dist/subscription-mollie/index.js +3 -3
- package/dist/subscription-mollie/plugin-methods.d.ts +2 -2
- package/dist/subscription-mollie/plugin-methods.js +15 -14
- package/dist/subscription-mollie/verify-webhook.d.ts +10 -10
- package/dist/subscription-mollie/verify-webhook.js +27 -27
- package/dist/subscription-stripe/constants.js +4 -6
- package/dist/subscription-stripe/feature.d.ts +14 -14
- package/dist/subscription-stripe/feature.js +35 -34
- package/dist/subscription-stripe/index.js +6 -6
- package/dist/subscription-stripe/plugin-methods.js +18 -18
- package/dist/subscription-stripe/runtime.d.ts +1 -1
- package/dist/subscription-stripe/runtime.js +1 -1
- package/dist/subscription-stripe/verify-webhook.d.ts +11 -11
- package/dist/subscription-stripe/verify-webhook.js +59 -61
- package/dist/tags/feature.d.ts +3 -3
- package/dist/tags/screens.js +1 -1
- package/dist/template-resolver/api.js +10 -10
- package/dist/template-resolver/handlers/find-by-id.query.js +5 -5
- package/dist/template-resolver/handlers/list.query.js +1 -1
- package/dist/template-resolver/handlers/shared.js +2 -2
- package/dist/template-resolver/handlers/template-write.js +3 -3
- package/dist/template-resolver/handlers/upsert-system.write.js +3 -4
- package/dist/template-resolver/handlers/upsert-tenant.write.js +4 -5
- package/dist/template-resolver/seeding.js +4 -4
- package/dist/template-resolver/table.js +10 -11
- package/dist/template-resolver/web/client-plugin.js +2 -2
- package/dist/tenant/feature.js +7 -7
- package/dist/tenant/handlers/member-directory.query.js +1 -1
- package/dist/tenant/handlers/members.query.js +1 -1
- package/dist/tenant/handlers/team-list.query.js +1 -1
- package/dist/tenant/handlers/tenant-directory.query.js +1 -1
- package/dist/tenant/invitation-table.js +37 -40
- package/dist/tenant/membership-table.js +3 -3
- package/dist/tenant/schema/tenant.js +7 -9
- package/dist/tenant/screens.js +1 -1
- package/dist/tenant/seeding.d.ts +6 -5
- package/dist/tenant/seeding.js +12 -12
- package/dist/tenant/testing.js +5 -6
- package/dist/tenant/web/constants.js +2 -2
- package/dist/tenant-handover/events.js +5 -7
- package/dist/tenant-handover/feature.js +1 -1
- package/dist/tenant-handover/grant.js +1 -1
- package/dist/tenant-handover/handlers/claim.write.js +1 -1
- package/dist/tenant-handover/move-entity-graph.js +8 -9
- package/dist/tenant-handover/signup-handover-provider.js +1 -2
- package/dist/tenant-handover/transfer-graph.js +4 -5
- package/dist/tenant-lifecycle/boot-checks.js +1 -1
- package/dist/tenant-lifecycle/feature.js +1 -1
- package/dist/tenant-settings/constants.js +1 -1
- package/dist/tenant-settings/tenant-defaults.d.ts +1 -1
- package/dist/tenant-settings/tenant-defaults.js +9 -2
- package/dist/tier-engine/aggregate-id.d.ts +11 -11
- package/dist/tier-engine/aggregate-id.js +15 -16
- package/dist/tier-engine/compose-app.d.ts +14 -14
- package/dist/tier-engine/compose-app.js +1 -1
- package/dist/tier-engine/entity.js +18 -19
- package/dist/tier-engine/feature.d.ts +19 -17
- package/dist/tier-engine/feature.js +68 -69
- package/dist/tier-engine/handlers/active-tier.query.js +6 -7
- package/dist/tier-engine/handlers/get-tenant-tier.query.js +4 -4
- package/dist/tier-engine/handlers/set-tenant-tier.write.d.ts +5 -5
- package/dist/tier-engine/handlers/set-tenant-tier.write.js +3 -3
- package/dist/tier-engine/tier-resolver.js +2 -2
- package/dist/tier-engine/trial.js +8 -8
- package/dist/tier-engine/web/index.js +4 -4
- package/dist/user/db/queries/stream-tenant-backfill.js +8 -8
- package/dist/user/handlers/create.write.js +4 -4
- package/dist/user/schema/user.d.ts +11 -11
- package/dist/user/schema/user.js +45 -44
- package/dist/user/seeding.d.ts +15 -15
- package/dist/user/seeding.js +28 -28
- package/dist/user/testing.js +3 -3
- package/dist/user-data-rights/audit-download.d.ts +8 -8
- package/dist/user-data-rights/audit-download.js +19 -20
- package/dist/user-data-rights/boot-checks.js +1 -1
- package/dist/user-data-rights/deletion-token.js +1 -1
- package/dist/user-data-rights/feature.d.ts +49 -50
- package/dist/user-data-rights/feature.js +54 -53
- package/dist/user-data-rights/handlers/cancel-deletion.write.js +9 -9
- package/dist/user-data-rights/handlers/confirm-deletion-by-token.write.js +8 -8
- package/dist/user-data-rights/handlers/download-by-job.query.js +29 -30
- package/dist/user-data-rights/handlers/download-by-token.query.js +40 -42
- package/dist/user-data-rights/handlers/export-status.query.js +8 -9
- package/dist/user-data-rights/handlers/lift-restriction.write.js +7 -8
- package/dist/user-data-rights/handlers/list-download-attempts.query.js +2 -2
- package/dist/user-data-rights/handlers/my-audit-log.query.js +4 -4
- package/dist/user-data-rights/handlers/request-deletion-by-email.write.d.ts +5 -5
- package/dist/user-data-rights/handlers/request-deletion-by-email.write.js +16 -15
- package/dist/user-data-rights/handlers/request-deletion.write.d.ts +2 -2
- package/dist/user-data-rights/handlers/request-deletion.write.js +7 -9
- package/dist/user-data-rights/handlers/request-export.write.js +42 -41
- package/dist/user-data-rights/handlers/restrict-account.write.js +22 -19
- package/dist/user-data-rights/handlers/run-forget-cleanup.write.js +8 -8
- package/dist/user-data-rights/index.js +8 -10
- package/dist/user-data-rights/lib/default-mailers.js +3 -3
- package/dist/user-data-rights/lib/update-user-lifecycle.js +14 -17
- package/dist/user-data-rights/run-export-jobs.d.ts +38 -42
- package/dist/user-data-rights/run-export-jobs.js +127 -233
- package/dist/user-data-rights/run-forget-cleanup.d.ts +16 -20
- package/dist/user-data-rights/run-forget-cleanup.js +63 -82
- package/dist/user-data-rights/run-user-export.d.ts +34 -33
- package/dist/user-data-rights/run-user-export.js +55 -57
- package/dist/user-data-rights/schema/download-attempt.js +11 -11
- package/dist/user-data-rights/schema/download-token.js +37 -41
- package/dist/user-data-rights/schema/export-job.d.ts +4 -4
- package/dist/user-data-rights/schema/export-job.js +65 -67
- package/dist/user-data-rights/token-helpers.d.ts +8 -9
- package/dist/user-data-rights/token-helpers.js +21 -25
- package/dist/user-data-rights/web/client-plugin.d.ts +5 -5
- package/dist/user-data-rights/web/client-plugin.js +1 -1
- package/dist/user-data-rights/web/confirm-deletion-screen.js +6 -5
- package/dist/user-data-rights/web/constants.js +1 -1
- package/dist/user-data-rights/web/index.js +5 -5
- package/dist/user-data-rights/web/privacy-center-screen.js +14 -13
- package/dist/user-data-rights/web/public-deletion-gate.d.ts +4 -4
- package/dist/user-data-rights/web/request-deletion-screen.js +6 -6
- package/dist/user-data-rights/zip-path.d.ts +15 -15
- package/dist/user-data-rights/zip-path.js +41 -40
- package/dist/user-data-rights-defaults/feature.js +15 -15
- package/dist/user-data-rights-defaults/hooks/delivery-attempt.userdata-hook.js +3 -5
- package/dist/user-data-rights-defaults/hooks/file-ref.userdata-hook.js +45 -51
- package/dist/user-data-rights-defaults/hooks/job-run.userdata-hook.js +2 -2
- package/dist/user-data-rights-defaults/hooks/notification-preference.userdata-hook.js +1 -1
- package/dist/user-data-rights-defaults/hooks/user-session.userdata-hook.js +3 -3
- package/dist/user-data-rights-defaults/hooks/user.userdata-hook.js +32 -31
- package/dist/user-profile/handlers/change-email.write.js +13 -13
- package/dist/user-profile/index.js +3 -3
- package/dist/user-profile/web/client-plugin.js +1 -1
- package/dist/user-profile/web/constants.js +1 -1
- package/dist/user-profile/web/profile-screen.js +1 -1
- package/dist/workflow-runner/aggregate-id.d.ts +1 -1
- package/dist/workflow-runner/aggregate-id.js +1 -1
- package/dist/workflow-runner/event-subscriber.js +4 -5
- package/dist/workflow-runner/event-trigger.js +4 -17
- package/dist/workflow-runner/feature.js +2 -2
- package/dist/workflow-runner/handlers/resume-run.write.js +4 -4
- package/dist/workflow-runner/pending-projection.js +6 -7
- package/dist/workflow-runner/runner.js +6 -6
- package/dist/workflow-runner/tables.js +6 -6
- package/dist/workflow-runner/workflow-registry.js +1 -1
- package/package.json +10 -10
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
// list-accounts — tenant-scoped
|
|
2
|
-
// Connect
|
|
3
|
-
// billing-foundation list-subscriptions
|
|
1
|
+
// list-accounts — tenant-scoped list of connected mailboxes for the
|
|
2
|
+
// Connect/Settings UI. PII (address) is decrypted on read, following the
|
|
3
|
+
// billing-foundation list-subscriptions pattern.
|
|
4
4
|
//
|
|
5
|
-
// **Scope
|
|
6
|
-
// (ownerUserId=null)
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
//
|
|
5
|
+
// **Scope visibility:** authorized users can see shared mailboxes
|
|
6
|
+
// (ownerUserId=null); personal mailboxes are visible only to their owner,
|
|
7
|
+
// TenantAdmin, or SystemAdmin for compliance access. Filtering runs in memory
|
|
8
|
+
// after the tenant-scoped select because a tenant has only a single- to
|
|
9
|
+
// double-digit number of connected mailboxes.
|
|
10
10
|
import { configuredPiiSubjectKms, decryptPiiFieldValues, } from "@cosmicdrift/kumiko-framework/crypto";
|
|
11
11
|
import { MAX_LIST_LIMIT } from "@cosmicdrift/kumiko-framework/engine";
|
|
12
12
|
import * as z from "zod";
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
// list-messages — tenant-scoped
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
1
|
+
// list-messages — tenant-scoped message list for the inbox cockpit.
|
|
2
|
+
// Optional filters: accountId (one mailbox), threadKey (one conversation),
|
|
3
|
+
// scope (folder hint). PII (from/to/cc/subject/snippet) is decrypted on read;
|
|
4
|
+
// to/cc remain JSON-stringified strings, which the client parses as documented
|
|
5
|
+
// in the event payload.
|
|
6
6
|
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
//
|
|
7
|
+
// Deliberately no pagination in V1: the projection is tenant-scoped and the
|
|
8
|
+
// inbox cockpit loads bounded time ranges; a `limit` field can be added
|
|
9
|
+
// compatibly without breaking the QN.
|
|
10
10
|
import { configuredPiiSubjectKms, decryptPiiFieldValues, } from "@cosmicdrift/kumiko-framework/crypto";
|
|
11
11
|
import * as z from "zod";
|
|
12
12
|
import { INBOUND_MESSAGE_PII_FIELDS } from "../entities.js";
|
|
@@ -35,8 +35,8 @@ export const listMessagesQuery = {
|
|
|
35
35
|
if (payload.scope)
|
|
36
36
|
filter["scope"] = payload.scope;
|
|
37
37
|
const allRows = await ctx.db.selectMany(inboundMessagesProjectionTable, filter);
|
|
38
|
-
// Scope
|
|
39
|
-
//
|
|
38
|
+
// Scope visibility: messages in personal mailboxes are visible only to the
|
|
39
|
+
// owner or TenantAdmin/SystemAdmin.
|
|
40
40
|
const rows = allRows.filter((row) => isVisibleToCaller(row, ctx.user));
|
|
41
41
|
const piiKms = configuredPiiSubjectKms();
|
|
42
42
|
if (!piiKms)
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
// Scope
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
// für read_mail_accounts und read_inbound_messages (Scope-Vererbung).
|
|
1
|
+
// Scope visibility: shared rows (`ownerUserId=null`) are visible to any authorized caller;
|
|
2
|
+
// personal rows are visible only to the owner, `TenantAdmin`, or `SystemAdmin` for compliance.
|
|
3
|
+
// The same rule applies to `read_mail_accounts` and `read_inbound_messages`.
|
|
5
4
|
export function isVisibleToCaller(row, user) {
|
|
6
5
|
const owner = row["ownerUserId"];
|
|
7
6
|
if (owner == null || owner === "")
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
// update-account — Account
|
|
2
|
-
// error/backoff, OAuth
|
|
3
|
-
//
|
|
4
|
-
//
|
|
1
|
+
// update-account — Account status transitions: the watch supervisor reports
|
|
2
|
+
// error/backoff, OAuth refresh fails (auth_error), or a tenant admin re-enables
|
|
3
|
+
// the account after fixing its credentials. Full-snapshot event: loads the
|
|
4
|
+
// latest state, merges the delta fields, and appends the new snapshot.
|
|
5
5
|
import { failNotFound, failUnprocessable } from "@cosmicdrift/kumiko-framework/errors";
|
|
6
6
|
import * as z from "zod";
|
|
7
7
|
import { InboundMailAccountStatuses } from "../constants.js";
|
|
@@ -19,7 +19,7 @@ export const updateAccountSchema = z.object({
|
|
|
19
19
|
/** Ops-Signal ("idle", "watching", "backoff:3", ...). */
|
|
20
20
|
watchState: z.string().max(100).optional(),
|
|
21
21
|
displayName: z.string().max(200).optional(),
|
|
22
|
-
/** Audit
|
|
22
|
+
/** Audit reason for metadata.headers ("watch_supervisor",
|
|
23
23
|
* "oauth_refresh", "tenant_admin"). */
|
|
24
24
|
reason: z.string().min(1).max(100),
|
|
25
25
|
});
|
|
@@ -36,14 +36,14 @@ export const updateAccountHandler = {
|
|
|
36
36
|
return failNotFound("mail-account", payload.accountId);
|
|
37
37
|
}
|
|
38
38
|
if (current.status === InboundMailAccountStatuses.disconnected) {
|
|
39
|
-
//
|
|
40
|
-
//
|
|
41
|
-
//
|
|
42
|
-
//
|
|
39
|
+
// Disconnected accounts are final; re-enabling requires a fresh connect
|
|
40
|
+
// (new stream, new secret slot). This prevents a delayed supervisor tick
|
|
41
|
+
// from restoring a disconnected account to active (disconnect vs. poll
|
|
42
|
+
// race).
|
|
43
43
|
return failUnprocessable("account_disconnected", { accountId: payload.accountId });
|
|
44
44
|
}
|
|
45
|
-
//
|
|
46
|
-
//
|
|
45
|
+
// address/provider/authMethod come unchanged from the latest snapshot
|
|
46
|
+
// (address remains ciphertext—never re-encrypt it).
|
|
47
47
|
const eventPayload = {
|
|
48
48
|
...current,
|
|
49
49
|
...(payload.status !== undefined ? { status: payload.status } : {}),
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
|
|
2
2
|
export type OAuthStatePayload = {
|
|
3
3
|
readonly tenantId: string;
|
|
4
|
-
/** null = shared
|
|
4
|
+
/** null = shared mailbox; otherwise this user's personal mailbox. */
|
|
5
5
|
readonly ownerUserId: string | null;
|
|
6
6
|
readonly providerKey: string;
|
|
7
|
-
/**
|
|
8
|
-
*
|
|
7
|
+
/** Mailbox address from the connect request; after token exchange, it is
|
|
8
|
+
* stored in the MailAccount. */
|
|
9
9
|
readonly mailbox: string;
|
|
10
|
-
/**
|
|
11
|
-
*
|
|
10
|
+
/** One-time nonce makes each state unique, preventing replay across
|
|
11
|
+
* two parallel connect flows. */
|
|
12
12
|
readonly nonce: string;
|
|
13
13
|
};
|
|
14
14
|
export type VerifyOAuthStateResult = {
|
|
@@ -1,14 +1,15 @@
|
|
|
1
|
-
// HMAC-
|
|
1
|
+
// HMAC-signed OAuth-`state` parameter for the connect flow.
|
|
2
2
|
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
3
|
+
// Binds {tenantId, ownerUserId?, providerKey, mailbox, nonce} to the
|
|
4
|
+
// redirect: the anonymous callback (outside /api/*) trusts only the
|
|
5
|
+
// verified state, preventing CSRF and cross-tenant or cross-user claiming
|
|
6
|
+
// because an attacker cannot redirect the callback to another tenant or
|
|
7
|
+
// user without breaking the signature.
|
|
8
8
|
//
|
|
9
9
|
// Format: <payload-base64url>.<expiresAtMs>.<hmac-base64url>
|
|
10
|
-
//
|
|
11
|
-
// HMAC
|
|
10
|
+
// Patterned after auth-email-password/signed-token.ts (HMAC-SHA256, purpose
|
|
11
|
+
// in the HMAC input, timing-safe comparison, expiry in the clear-text
|
|
12
|
+
// segment).
|
|
12
13
|
import { createHmac, randomUUID, timingSafeEqual } from "node:crypto";
|
|
13
14
|
import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
|
|
14
15
|
import { isPlainObject } from "@cosmicdrift/kumiko-types/type-guards";
|
|
@@ -40,8 +41,8 @@ export function verifyOAuthState(state, secret, now = Temporal.Now.instant()) {
|
|
|
40
41
|
const expected = sign(hmacInput(payloadB64, expiresAtMs), secret);
|
|
41
42
|
const expectedBuf = Buffer.from(expected, "base64url");
|
|
42
43
|
const providedBuf = Buffer.from(providedSig, "base64url");
|
|
43
|
-
//
|
|
44
|
-
//
|
|
44
|
+
// Check the length before timingSafeEqual: it throws on a length mismatch,
|
|
45
|
+
// and the throw itself leaks information through timing.
|
|
45
46
|
if (expectedBuf.length !== providedBuf.length)
|
|
46
47
|
return { ok: false, reason: "bad_signature" };
|
|
47
48
|
if (!timingSafeEqual(expectedBuf, providedBuf))
|
|
@@ -130,12 +130,12 @@ export declare const mailThreadsProjectionTable: import("@cosmicdrift/kumiko-fra
|
|
|
130
130
|
}, "tenant">>;
|
|
131
131
|
/** mail-account-connected → UPSERT full. */
|
|
132
132
|
export declare const applyMailAccountConnected: import("@cosmicdrift/kumiko-types/projection").SingleStreamApplyFn;
|
|
133
|
-
/** mail-account-updated → UPSERT
|
|
133
|
+
/** mail-account-updated → full UPSERT for status/watchState transitions. */
|
|
134
134
|
export declare const applyMailAccountUpdated: import("@cosmicdrift/kumiko-types/projection").SingleStreamApplyFn;
|
|
135
|
-
/** mail-account-disconnected → UPSERT
|
|
136
|
-
*
|
|
135
|
+
/** mail-account-disconnected → full UPSERT (payload.status=disconnected).
|
|
136
|
+
* The row and stream remain for audit visibility in the account list. */
|
|
137
137
|
export declare const applyMailAccountDisconnected: import("@cosmicdrift/kumiko-types/projection").SingleStreamApplyFn;
|
|
138
138
|
/** inbound-message-received → INSERT ... ON CONFLICT DO NOTHING. */
|
|
139
139
|
export declare const applyInboundMessageReceived: import("@cosmicdrift/kumiko-types/projection").SingleStreamApplyFn;
|
|
140
|
-
/** mail-thread-updated → UPSERT
|
|
140
|
+
/** mail-thread-updated → full UPSERT with the payload snapshot. */
|
|
141
141
|
export declare const applyMailThreadUpdated: import("@cosmicdrift/kumiko-types/projection").SingleStreamApplyFn;
|
|
@@ -1,26 +1,27 @@
|
|
|
1
|
-
// Inline
|
|
1
|
+
// Inline projections for the three event-sourced streams:
|
|
2
2
|
// mail-account → read_mail_accounts (UPSERT, current state)
|
|
3
3
|
// inbound-message → read_inbound_messages (INSERT-ignore, append-only)
|
|
4
|
-
// mail-thread → read_mail_threads (UPSERT,
|
|
4
|
+
// mail-thread → read_mail_threads (UPSERT, rollup)
|
|
5
5
|
//
|
|
6
|
-
// Apply
|
|
7
|
-
// own-write
|
|
6
|
+
// Apply runs in the same transaction as ctx.unsafeAppendEvent, providing
|
|
7
|
+
// read-your-own-write without waiting for a dispatcher tick (as in
|
|
8
|
+
// billing-foundation).
|
|
8
9
|
//
|
|
9
|
-
// **Production-deployment caveat** (
|
|
10
|
-
//
|
|
11
|
-
//
|
|
12
|
-
//
|
|
13
|
-
//
|
|
10
|
+
// **Production-deployment caveat** (same as billing-foundation):
|
|
11
|
+
// The tables are registered as raw drizzle-pgTable instances in r.projection,
|
|
12
|
+
// NOT as r.entity. Apps must include them in their drizzle/generate.ts
|
|
13
|
+
// (via *-ProjectionTable imports). setupTestStack pushes them automatically
|
|
14
|
+
// via r.projection.table.
|
|
14
15
|
//
|
|
15
|
-
// **PII:**
|
|
16
|
-
//
|
|
17
|
-
// write
|
|
18
|
-
// in
|
|
16
|
+
// **PII:** The payload fields (address/from/to/cc/subject/snippet) already
|
|
17
|
+
// arrive as ciphertext because they are encrypted BEFORE the append in the
|
|
18
|
+
// write handler. The applies only copy them through; decryption happens only
|
|
19
|
+
// in the list queries.
|
|
19
20
|
import { buildEntityTable, insertOnConflictDoNothing, requireEntityTableMeta, upsertOnConflict, } from "@cosmicdrift/kumiko-framework/db";
|
|
20
21
|
import { defineApply } from "@cosmicdrift/kumiko-framework/engine";
|
|
21
22
|
import { inboundMessageEntity, mailAccountEntity, mailThreadEntity } from "./entities.js";
|
|
22
|
-
// Drizzle
|
|
23
|
-
// projection
|
|
23
|
+
// Drizzle table instances derived from the entity shapes, shared between
|
|
24
|
+
// projection applies and list queries to provide one column namespace.
|
|
24
25
|
export const mailAccountsProjectionTable = buildEntityTable("mail-account", mailAccountEntity);
|
|
25
26
|
export const inboundMessagesProjectionTable = buildEntityTable("inbound-message", inboundMessageEntity);
|
|
26
27
|
export const mailThreadsProjectionTable = buildEntityTable("mail-thread", mailThreadEntity);
|
|
@@ -30,9 +31,10 @@ const mailAccountsProjectionMeta = requireEntityTableMeta(mailAccountsProjection
|
|
|
30
31
|
const inboundMessagesProjectionMeta = requireEntityTableMeta(inboundMessagesProjectionTable, "inbound-message");
|
|
31
32
|
const mailThreadsProjectionMeta = requireEntityTableMeta(mailThreadsProjectionTable, "mail-thread");
|
|
32
33
|
// =============================================================================
|
|
33
|
-
// mail-account — connected/updated/disconnected
|
|
34
|
-
//
|
|
35
|
-
// defensive consistency
|
|
34
|
+
// mail-account — connected/updated/disconnected share the payload shape;
|
|
35
|
+
// the event type identifies what happened. All three perform a full UPSERT
|
|
36
|
+
// for defensive consistency during from-scratch rebuilds and out-of-order
|
|
37
|
+
// processing.
|
|
36
38
|
// =============================================================================
|
|
37
39
|
const applyMailAccountUpsert = defineApply(async (event, tx) => {
|
|
38
40
|
const p = event.payload;
|
|
@@ -57,15 +59,15 @@ const applyMailAccountUpsert = defineApply(async (event, tx) => {
|
|
|
57
59
|
});
|
|
58
60
|
/** mail-account-connected → UPSERT full. */
|
|
59
61
|
export const applyMailAccountConnected = applyMailAccountUpsert;
|
|
60
|
-
/** mail-account-updated → UPSERT
|
|
62
|
+
/** mail-account-updated → full UPSERT for status/watchState transitions. */
|
|
61
63
|
export const applyMailAccountUpdated = applyMailAccountUpsert;
|
|
62
|
-
/** mail-account-disconnected → UPSERT
|
|
63
|
-
*
|
|
64
|
+
/** mail-account-disconnected → full UPSERT (payload.status=disconnected).
|
|
65
|
+
* The row and stream remain for audit visibility in the account list. */
|
|
64
66
|
export const applyMailAccountDisconnected = applyMailAccountUpsert;
|
|
65
67
|
// =============================================================================
|
|
66
|
-
// inbound-message —
|
|
67
|
-
// aggregateId). INSERT-ignore
|
|
68
|
-
//
|
|
68
|
+
// inbound-message — exactly one received event per stream (deterministic
|
|
69
|
+
// aggregateId). INSERT-ignore makes replays no-ops on the primary key;
|
|
70
|
+
// there is no update case.
|
|
69
71
|
// =============================================================================
|
|
70
72
|
/** inbound-message-received → INSERT ... ON CONFLICT DO NOTHING. */
|
|
71
73
|
export const applyInboundMessageReceived = defineApply(async (event, tx) => {
|
|
@@ -88,12 +90,12 @@ export const applyInboundMessageReceived = defineApply(async (event, tx) => {
|
|
|
88
90
|
});
|
|
89
91
|
});
|
|
90
92
|
// =============================================================================
|
|
91
|
-
// mail-thread —
|
|
92
|
-
//
|
|
93
|
-
//
|
|
94
|
-
//
|
|
93
|
+
// mail-thread — rollup per (tenantId, threadKey). The write handler computes
|
|
94
|
+
// messageCount/lastMessageAt and appends the updated event with the NEW state.
|
|
95
|
+
// The apply performs a full UPSERT rather than incrementing, because
|
|
96
|
+
// replays would otherwise not be idempotent.
|
|
95
97
|
// =============================================================================
|
|
96
|
-
/** mail-thread-updated → UPSERT
|
|
98
|
+
/** mail-thread-updated → full UPSERT with the payload snapshot. */
|
|
97
99
|
export const applyMailThreadUpdated = defineApply(async (event, tx) => {
|
|
98
100
|
const p = event.payload;
|
|
99
101
|
const mutable = {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type InboundMailContext, type InboundMailProviderPlugin, type MailAccountRecord } from "./types.ts";
|
|
2
|
-
/**
|
|
3
|
-
*
|
|
2
|
+
/** Looks up a provider by key ("imap", "m365-graph", ...); used by OAuth
|
|
3
|
+
* connect routes before an account exists. */
|
|
4
4
|
export declare function resolveInboundProviderForKey(ctx: InboundMailContext, providerKey: string, handlerName?: string): InboundMailProviderPlugin;
|
|
5
|
-
/**
|
|
6
|
-
*
|
|
5
|
+
/** Looks up the provider for a specific account; the standard path for poll jobs
|
|
6
|
+
* and the watch supervisor. */
|
|
7
7
|
export declare function resolveInboundProviderForAccount(ctx: InboundMailContext, account: MailAccountRecord, handlerName?: string): InboundMailProviderPlugin;
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
// Provider
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
// per
|
|
5
|
-
//
|
|
1
|
+
// Provider factory — mirrors mail-foundation's createTransportForTenant, including
|
|
2
|
+
// the three error paths (missing registry, unregistered provider, invalid plugin
|
|
3
|
+
// shape). Unlike the outbound pattern, there is no per-tenant config selector:
|
|
4
|
+
// the provider is specified per MailAccount (`account.provider`), so a tenant can
|
|
5
|
+
// use multiple providers in parallel.
|
|
6
6
|
import { INBOUND_MAIL_FOUNDATION_FEATURE, INBOUND_MAIL_PROVIDER_EXTENSION } from "./constants.js";
|
|
7
7
|
import { isInboundMailProviderPlugin, } from "./types.js";
|
|
8
|
-
/**
|
|
9
|
-
*
|
|
8
|
+
/** Looks up a provider by key ("imap", "m365-graph", ...); used by OAuth
|
|
9
|
+
* connect routes before an account exists. */
|
|
10
10
|
export function resolveInboundProviderForKey(ctx, providerKey, handlerName = "inbound-mail-foundation:provider-factory") {
|
|
11
11
|
if (!ctx.registry) {
|
|
12
12
|
throw new Error(`${handlerName}: ctx.registry is missing — required to look up registered inbound-mail provider plugins`);
|
|
@@ -24,8 +24,8 @@ export function resolveInboundProviderForKey(ctx, providerKey, handlerName = "in
|
|
|
24
24
|
}
|
|
25
25
|
return usage.options;
|
|
26
26
|
}
|
|
27
|
-
/**
|
|
28
|
-
*
|
|
27
|
+
/** Looks up the provider for a specific account; the standard path for poll jobs
|
|
28
|
+
* and the watch supervisor. */
|
|
29
29
|
export function resolveInboundProviderForAccount(ctx, account, handlerName = "inbound-mail-foundation:provider-factory") {
|
|
30
30
|
return resolveInboundProviderForKey(ctx, account.provider, handlerName);
|
|
31
31
|
}
|
|
@@ -7,12 +7,14 @@ export declare const SEEN_RETENTION_DAYS = 90;
|
|
|
7
7
|
export interface InboundRetentionArgs {
|
|
8
8
|
readonly db: DbRunner;
|
|
9
9
|
readonly tenantId: TenantId;
|
|
10
|
-
/**
|
|
10
|
+
/**
|
|
11
|
+
* Injects the current time so tests can pin it without a date mock (pattern from keep-for.ts).
|
|
12
|
+
*/
|
|
11
13
|
readonly now: Instant;
|
|
12
14
|
readonly messageRetentionDays?: number;
|
|
13
15
|
readonly seenRetentionDays?: number;
|
|
14
|
-
/**
|
|
15
|
-
*
|
|
16
|
+
/** Deletes a file-storage body object by bodyRef key. Wired lazily by the job
|
|
17
|
+
* (createFileProviderForTenant); if absent, no body is deleted. */
|
|
16
18
|
readonly deleteBodyObject?: (bodyRef: string) => Promise<void>;
|
|
17
19
|
}
|
|
18
20
|
export interface InboundRetentionReport {
|
|
@@ -1,28 +1,30 @@
|
|
|
1
|
-
// Inbound-mail data
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
// event-sourced
|
|
1
|
+
// Inbound-mail data retention. DSGVO Art. 5 (data minimization):
|
|
2
|
+
// without retention, read_inbound_messages and the file-storage bodies grow
|
|
3
|
+
// without bound. Two targets, two mechanisms—the difference is
|
|
4
|
+
// event-sourced versus unmanaged:
|
|
5
5
|
//
|
|
6
|
-
// read_inbound_messages (event-sourced,
|
|
7
|
-
//
|
|
8
|
-
// (+ bodyRef
|
|
9
|
-
//
|
|
10
|
-
// forgotten-
|
|
11
|
-
// forget
|
|
12
|
-
// received
|
|
13
|
-
// loadAggregate
|
|
14
|
-
//
|
|
6
|
+
// read_inbound_messages (event-sourced, EXPLICIT r.projection):
|
|
7
|
+
// each Row older than messageRetentionDays → archiveStream + Row delete
|
|
8
|
+
// (+ delete the bodyRef object). archiveStream instead of executor.forget
|
|
9
|
+
// because the projection maps only the received domain event, not the
|
|
10
|
+
// forgotten auto-verb (which only ImplicitProjection registers). A
|
|
11
|
+
// forget event would be ignored during a rebuild, causing the Row to be
|
|
12
|
+
// resurrected from the received event. The archived stream makes
|
|
13
|
+
// loadAggregate empty, so received is not replicated in the first place.
|
|
14
|
+
// Same pattern as tenant-destroy-hook, but with a per-Row cutoff instead
|
|
15
|
+
// of an entire Tenant.
|
|
15
16
|
//
|
|
16
|
-
// store_mail_seen_messages (unmanaged, direct-write,
|
|
17
|
-
//
|
|
18
|
-
// via plain deleteMany,
|
|
19
|
-
// tenant_id
|
|
17
|
+
// store_mail_seen_messages (unmanaged, direct-write, not event-sourced):
|
|
18
|
+
// The deduplication anchor is needed only for the backfill/replay window →
|
|
19
|
+
// seenAt cutoff via plain deleteMany, with no stream/archive. Scoped
|
|
20
|
+
// directly through the table's tenant_id column (table-builder convention),
|
|
21
|
+
// without an Account join.
|
|
20
22
|
//
|
|
21
|
-
//
|
|
22
|
-
//
|
|
23
|
-
//
|
|
24
|
-
//
|
|
25
|
-
//
|
|
23
|
+
// LIMITATION: the PII in the message events remains decryptable under the
|
|
24
|
+
// TENANT subject key—per-Row retention does not shred a key. Actual Art.-17
|
|
25
|
+
// erasure of event payloads happens only during tenant-destroy (key erasure).
|
|
26
|
+
// The read Row and body file are gone after the sweep; the event log is
|
|
27
|
+
// append-only by design.
|
|
26
28
|
import { deleteMany, selectMany } from "@cosmicdrift/kumiko-framework/db";
|
|
27
29
|
import { archiveStream, deleteRowsWithoutReplayableStream, } from "@cosmicdrift/kumiko-framework/event-store";
|
|
28
30
|
import { seenMessageTable } from "./entities.js";
|
|
@@ -46,18 +48,18 @@ async function purgeExpiredMessages(args, cutoff) {
|
|
|
46
48
|
let messagesPurged = 0;
|
|
47
49
|
let bodyObjectsDeleted = 0;
|
|
48
50
|
let bodyObjectErrors = 0;
|
|
49
|
-
// Drain
|
|
50
|
-
//
|
|
51
|
-
//
|
|
52
|
-
//
|
|
53
|
-
// select
|
|
54
|
-
//
|
|
51
|
+
// Drain loop: each page deletes the Rows it reads, so the next page is fresh.
|
|
52
|
+
// Run archiveStream BEFORE deletion: if a crash occurs in between, the next
|
|
53
|
+
// run re-archives idempotently and deletes the Row. Delete strictly by the
|
|
54
|
+
// archived IDs, never with a cutoff WHERE; otherwise an old mail arriving
|
|
55
|
+
// between select and delete could be deleted without being archived and
|
|
56
|
+
// resurrected during a rebuild.
|
|
55
57
|
//
|
|
56
|
-
//
|
|
57
|
-
//
|
|
58
|
-
//
|
|
59
|
-
//
|
|
60
|
-
//
|
|
58
|
+
// A Row whose deleteBodyObject fails is NOT deleted; otherwise the only
|
|
59
|
+
// reference to the now-orphaned file object would be lost (no retry or
|
|
60
|
+
// dead-letter). The Row remains for the next sweep (archiveStream is
|
|
61
|
+
// idempotent). failedIds prevents such a Row from being selected endlessly
|
|
62
|
+
// during THIS run.
|
|
61
63
|
const failedIds = new Set();
|
|
62
64
|
for (;;) {
|
|
63
65
|
const rows = (await selectMany(args.db, inboundMessagesProjectionTable, { receivedAt: { lt: cutoff }, tenantId: args.tenantId }, { limit: BATCH_LIMIT })).filter((row) => !failedIds.has(row.id));
|
|
@@ -99,9 +101,9 @@ async function purgeExpiredMessages(args, cutoff) {
|
|
|
99
101
|
return { messagesPurged, bodyObjectsDeleted, bodyObjectErrors };
|
|
100
102
|
}
|
|
101
103
|
async function purgeExpiredSeenAnchors(db, tenantId, cutoff) {
|
|
102
|
-
// Seen
|
|
103
|
-
//
|
|
104
|
-
//
|
|
104
|
+
// Seen anchors inherit tenantId (table-builder: every Entity has tenant_id) →
|
|
105
|
+
// scoped directly to the tenant, without an Account join. This also includes
|
|
106
|
+
// anchors whose Account has already been disconnected or deleted.
|
|
105
107
|
const where = { tenantId, seenAt: { lt: cutoff } };
|
|
106
108
|
const expired = await selectMany(db, seenMessageTable, where);
|
|
107
109
|
if (expired.length === 0)
|
|
@@ -1,21 +1,19 @@
|
|
|
1
|
-
// Tenant-destroy hooks
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
// entity-genau), jeweils:
|
|
1
|
+
// Tenant-destroy hooks remove all inbound-mail traces belonging to the tenant.
|
|
2
|
+
// One hook per tenant-subject entity (the gdpr-storage boot validator checks
|
|
3
|
+
// the EXT_TENANT_DATA registration per entity), each of which:
|
|
5
4
|
//
|
|
6
|
-
// 1.
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
//
|
|
10
|
-
//
|
|
11
|
-
//
|
|
12
|
-
//
|
|
13
|
-
//
|
|
14
|
-
// VOR dem Delete eingesammelt.
|
|
5
|
+
// 1. Archives streams so a future projection rebuild cannot resurrect
|
|
6
|
+
// deleted data. Message streams are numerous, so loop over the
|
|
7
|
+
// projection rows (row PK = stream ID); tenant-destroy is a rare batch
|
|
8
|
+
// operation, so O(n) is acceptable.
|
|
9
|
+
// 2. Deletes the projection rows.
|
|
10
|
+
// 3. For mail-account only, deletes unmanaged sync state (cursors,
|
|
11
|
+
// seen anchors), which is keyed by accountId and must therefore be
|
|
12
|
+
// collected from the account rows BEFORE deletion.
|
|
15
13
|
//
|
|
16
|
-
//
|
|
17
|
-
//
|
|
18
|
-
//
|
|
14
|
+
// The actual PII erasure uses crypto-shredding: eraseSubjectKeys deletes the
|
|
15
|
+
// tenant subject key, making event-log payloads AND any ciphertext copies
|
|
16
|
+
// unreadable. These hooks dispose of the rows.
|
|
19
17
|
import { declareEscapeHatch } from "@cosmicdrift/kumiko-framework/engine";
|
|
20
18
|
import { archiveStream } from "@cosmicdrift/kumiko-framework/event-store";
|
|
21
19
|
import { seenMessageTable, syncCursorTable } from "./entities.js";
|