@cosmicdrift/kumiko-bundled-features 0.386.0 → 0.388.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.d.ts +7 -7
- package/dist/agent-tools/tool-dispatch.js +9 -9
- package/dist/audit/handlers/audit-events.js +1 -1
- 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/feature-exports.d.ts +2 -2
- package/dist/auth-mfa/feature.js +8 -0
- 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 +8 -4
- 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-code-or-recovery-field.d.ts +11 -0
- package/dist/auth-mfa/web/mfa-code-or-recovery-field.js +12 -0
- package/dist/auth-mfa/web/mfa-disable-dialog.js +14 -3
- package/dist/auth-mfa/web/mfa-regenerate-recovery-dialog.js +14 -3
- package/dist/auth-mfa/web/mfa-setup-preauth-screen.js +10 -5
- package/dist/auth-mfa/web/mfa-verify-screen.js +32 -11
- package/dist/billing-foundation/aggregate-id.d.ts +5 -5
- package/dist/billing-foundation/aggregate-id.js +10 -11
- package/dist/billing-foundation/checkout-core.d.ts +9 -14
- package/dist/billing-foundation/checkout-core.js +24 -39
- package/dist/billing-foundation/consumer-protection/confirmation-mail.js +8 -2
- package/dist/billing-foundation/consumer-protection/consent-gate.d.ts +1 -0
- package/dist/billing-foundation/consumer-protection/consent-gate.js +1 -0
- package/dist/billing-foundation/consumer-protection/issue-confirmation.js +9 -3
- package/dist/billing-foundation/consumer-protection/mail-notifications.js +3 -1
- package/dist/billing-foundation/consumer-protection/termination-receipt-limit.d.ts +4 -2
- package/dist/billing-foundation/consumer-protection/termination-receipt-limit.js +6 -5
- package/dist/billing-foundation/consumer-protection/termination-record.d.ts +5 -1
- package/dist/billing-foundation/consumer-protection/termination-record.js +27 -17
- package/dist/billing-foundation/consumer-protection/termination-request.js +12 -7
- package/dist/billing-foundation/consumer-protection/termination-revoke.js +12 -7
- package/dist/billing-foundation/consumer-protection/termination-texts.d.ts +1 -1
- package/dist/billing-foundation/consumer-protection/termination-texts.js +3 -0
- package/dist/billing-foundation/consumer-protection/withdrawal-period.d.ts +5 -2
- package/dist/billing-foundation/consumer-protection/withdrawal-period.js +8 -9
- package/dist/billing-foundation/entities.js +27 -27
- package/dist/billing-foundation/events.d.ts +1 -0
- package/dist/billing-foundation/events.js +19 -17
- package/dist/billing-foundation/feature.js +45 -44
- 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/billing-plans.query.js +35 -5
- package/dist/billing-foundation/handlers/create-checkout-session.write.js +19 -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/plan-switch-preview.query.d.ts +13 -0
- package/dist/billing-foundation/handlers/plan-switch-preview.query.js +48 -0
- package/dist/billing-foundation/handlers/process-event.write.d.ts +6 -0
- package/dist/billing-foundation/handlers/process-event.write.js +28 -22
- package/dist/billing-foundation/handlers/start-plan-checkout.write.js +32 -5
- package/dist/billing-foundation/handlers/switch-plan.write.d.ts +2 -2
- package/dist/billing-foundation/handlers/switch-plan.write.js +56 -64
- package/dist/billing-foundation/handlers/sync-subscription.write.js +12 -1
- package/dist/billing-foundation/i18n.js +22 -0
- package/dist/billing-foundation/index.d.ts +1 -1
- package/dist/billing-foundation/plan-catalog.d.ts +21 -5
- package/dist/billing-foundation/plan-catalog.js +25 -16
- package/dist/billing-foundation/plan-switch.d.ts +12 -0
- package/dist/billing-foundation/plan-switch.js +60 -0
- 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 +97 -42
- package/dist/billing-foundation/types.js +29 -20
- package/dist/billing-foundation/validate-options.js +17 -0
- package/dist/billing-foundation/web/billing-plans-panel.js +82 -36
- package/dist/billing-foundation/web/checkout-consent-dialog.d.ts +17 -3
- package/dist/billing-foundation/web/checkout-consent-dialog.js +14 -10
- package/dist/billing-foundation/web/constants.d.ts +4 -0
- package/dist/billing-foundation/web/constants.js +4 -0
- package/dist/billing-foundation/web/plan-price.d.ts +15 -0
- package/dist/billing-foundation/web/plan-price.js +32 -0
- package/dist/billing-foundation/web/plan-switch-confirm-dialog.d.ts +15 -0
- package/dist/billing-foundation/web/plan-switch-confirm-dialog.js +66 -0
- package/dist/cap-counter/aggregate-id.js +8 -9
- package/dist/cap-counter/cap-reservation.js +5 -1
- 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 +49 -49
- 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 +8 -2
- package/dist/cap-counter/with-cap-enforcement.d.ts +3 -5
- package/dist/channel-email/feature.js +1 -1
- 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/cascade.query.d.ts +5 -0
- package/dist/config/handlers/cascade.query.js +4 -3
- 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/handlers/values.query.d.ts +5 -0
- package/dist/config/handlers/values.query.js +4 -3
- package/dist/config/resolver.js +4 -4
- package/dist/config/table.js +10 -10
- package/dist/config/write-helpers.d.ts +1 -0
- package/dist/config/write-helpers.js +19 -10
- package/dist/crypto-shredding/handlers/forget-subject.write.d.ts +2 -2
- package/dist/crypto-shredding/handlers/forget-subject.write.js +25 -21
- 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/channel-context.js +6 -3
- package/dist/delivery/db/queries/preferences.js +2 -2
- package/dist/delivery/delivery-service.js +22 -7
- package/dist/delivery/feature.js +2 -2
- package/dist/delivery/handlers/log.query.js +1 -1
- package/dist/delivery/handlers/preferences.query.d.ts +1 -1
- package/dist/delivery/handlers/preferences.query.js +20 -1
- package/dist/delivery/handlers/unsubscribe-page-chrome.query.js +1 -1
- package/dist/delivery/tables.js +9 -8
- package/dist/delivery/unsubscribe-link.d.ts +3 -1
- package/dist/delivery/unsubscribe-page-strings.d.ts +1 -0
- package/dist/delivery/unsubscribe-page-strings.js +1 -0
- package/dist/delivery/unsubscribe-page.d.ts +2 -0
- package/dist/delivery/unsubscribe-page.js +5 -0
- package/dist/delivery/unsubscribe.js +29 -11
- 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-foundation/index.d.ts +1 -1
- package/dist/file-foundation/index.js +1 -1
- package/dist/file-foundation/read-file-ref-content.d.ts +3 -0
- package/dist/file-foundation/read-file-ref-content.js +6 -1
- package/dist/file-provider-inmemory/feature.d.ts +1 -1
- package/dist/file-provider-inmemory/feature.js +16 -16
- package/dist/file-provider-s3/env-named-feature.d.ts +0 -2
- 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 +3 -3
- package/dist/form-draft/db/queries/owned-file-refs.js +1 -1
- package/dist/form-draft/decrypt-draft.js +5 -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/host-routing/dispatch.js +11 -20
- 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.d.ts +2 -2
- package/dist/inbound-mail-foundation/handlers/update-account.write.js +22 -14
- package/dist/inbound-mail-foundation/i18n.js +0 -1
- 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/screens.js +0 -3
- package/dist/inbound-mail-foundation/tenant-destroy-hook.js +14 -16
- package/dist/inbound-mail-foundation/types.d.ts +49 -49
- 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 +85 -67
- 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.d.ts +1 -0
- package/dist/jobs/feature.js +13 -10
- 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/handlers/tenant-failures.query.d.ts +1 -1
- package/dist/jobs/handlers/tenant-failures.query.js +45 -41
- package/dist/jobs/handlers/tenant-runs.query.d.ts +1 -1
- package/dist/jobs/handlers/tenant-runs.query.js +54 -50
- package/dist/jobs/job-instant.js +1 -1
- package/dist/jobs/job-run-logger.js +15 -15
- 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 +5 -5
- package/dist/mail-foundation/feature.js +27 -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.d.ts +1 -1
- package/dist/personal-access-tokens/feature.js +9 -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/renderer-pdf/render-table-pdf.d.ts +1 -1
- package/dist/renderer-pdf/render-table-pdf.js +22 -10
- 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.d.ts +2 -2
- package/dist/sessions/feature.js +12 -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.d.ts +1 -0
- package/dist/shared/decrypt-stored-pii.js +7 -2
- package/dist/shared/encrypt-for-direct-write.js +1 -1
- package/dist/shared/index.d.ts +1 -1
- package/dist/shared/index.js +1 -1
- package/dist/shared/mail-template-body.d.ts +6 -2
- package/dist/shared/mail-template-body.js +7 -4
- 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/step-dispatcher/feature.js +1 -0
- package/dist/subscription-dodo/client.d.ts +17 -0
- package/dist/subscription-dodo/client.js +31 -0
- package/dist/subscription-dodo/constants.d.ts +12 -0
- package/dist/subscription-dodo/constants.js +19 -0
- package/dist/subscription-dodo/feature.d.ts +37 -0
- package/dist/subscription-dodo/feature.js +144 -0
- package/dist/subscription-dodo/index.d.ts +2 -0
- package/dist/subscription-dodo/index.js +4 -0
- package/dist/subscription-dodo/plugin-methods.d.ts +23 -0
- package/dist/subscription-dodo/plugin-methods.js +260 -0
- package/dist/subscription-dodo/runtime.d.ts +27 -0
- package/dist/subscription-dodo/runtime.js +89 -0
- package/dist/subscription-dodo/verify-webhook.d.ts +37 -0
- package/dist/subscription-dodo/verify-webhook.js +189 -0
- 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 +36 -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 +8 -7
- 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.d.ts +3 -2
- package/dist/template-resolver/api.js +34 -12
- package/dist/template-resolver/compile-document-body.js +1 -0
- package/dist/template-resolver/feature.js +2 -2
- package/dist/template-resolver/handlers/bundle-import.js +3 -3
- package/dist/template-resolver/handlers/copy-locale.write.d.ts +5 -1
- package/dist/template-resolver/handlers/copy-locale.write.js +22 -7
- package/dist/template-resolver/handlers/diff-to-system.query.js +3 -2
- package/dist/template-resolver/handlers/document-base.js +3 -2
- package/dist/template-resolver/handlers/find-by-id.query.js +8 -7
- package/dist/template-resolver/handlers/list.query.js +6 -7
- package/dist/template-resolver/handlers/overview.query.d.ts +3 -0
- package/dist/template-resolver/handlers/overview.query.js +6 -3
- package/dist/template-resolver/handlers/shared.js +2 -2
- package/dist/template-resolver/handlers/template-write.js +3 -3
- package/dist/template-resolver/handlers/tenant-override-counts.query.js +1 -3
- package/dist/template-resolver/handlers/tenant-override-selection.d.ts +2 -1
- package/dist/template-resolver/handlers/tenant-overrides.query.js +28 -5
- 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/handlers/usage.query.d.ts +2 -1
- package/dist/template-resolver/handlers/usage.query.js +26 -16
- package/dist/template-resolver/handlers/validate.query.js +7 -2
- package/dist/template-resolver/seeding.js +30 -14
- package/dist/template-resolver/store-template-resource.d.ts +1 -0
- package/dist/template-resolver/store-template-resource.js +19 -4
- package/dist/template-resolver/table.js +10 -11
- package/dist/template-resolver/template-delivery-policy.d.ts +0 -5
- package/dist/template-resolver/template-delivery-policy.js +0 -6
- package/dist/template-resolver/template-meta.js +7 -4
- package/dist/template-resolver/template-preview.js +4 -3
- package/dist/template-resolver/web/client-plugin.js +2 -2
- package/dist/template-resolver/web/constants.d.ts +2 -2
- package/dist/template-resolver/web/constants.js +3 -3
- package/dist/template-resolver/web/index.d.ts +1 -0
- package/dist/template-resolver/web/index.js +1 -0
- package/dist/template-resolver/web/mail-layout-constants.d.ts +5 -0
- package/dist/template-resolver/web/mail-layout-constants.js +7 -0
- package/dist/tenant/feature.js +7 -7
- package/dist/tenant/handlers/member-directory.query.d.ts +1 -0
- package/dist/tenant/handlers/member-directory.query.js +11 -4
- 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.d.ts +1 -0
- package/dist/tenant/handlers/tenant-directory.query.js +9 -5
- 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/constants.d.ts +1 -0
- package/dist/tenant-lifecycle/constants.js +4 -0
- package/dist/tenant-lifecycle/feature.js +1 -1
- package/dist/tenant-lifecycle/run-tenant-destroy.js +2 -2
- 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 +7 -8
- package/dist/tier-engine/handlers/set-tenant-tier.write.js +7 -4
- package/dist/tier-engine/tier-resolver.js +2 -2
- package/dist/tier-engine/trial.js +8 -8
- package/dist/tier-engine/web/constants.js +2 -2
- 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 +130 -237
- package/dist/user-data-rights/run-forget-cleanup.d.ts +16 -20
- package/dist/user-data-rights/run-forget-cleanup.js +65 -83
- 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/waitlist/handlers/export-purge.write.js +2 -1
- package/dist/waitlist/handlers/submit.write.js +5 -5
- package/dist/waitlist/import.d.ts +1 -0
- package/dist/waitlist/import.js +4 -0
- package/dist/waitlist/legacy-migrate.js +17 -6
- package/dist/waitlist/link-on-signup.js +18 -6
- package/dist/waitlist/options.d.ts +3 -0
- 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 +20 -10
- package/src/agent-tools/changes.json +6 -0
- package/src/audit/changes.json +12 -0
- package/src/auth-mfa/changes.json +6 -0
- package/src/billing-foundation/changes.json +55 -0
- package/src/cap-counter/changes.json +18 -0
- package/src/channel-email/changes.json +6 -0
- package/src/config/changes.json +12 -0
- package/src/crypto-shredding/changes.json +6 -0
- package/src/delivery/changes.json +30 -0
- package/src/form-draft/changes.json +6 -0
- package/src/host-routing/changes.json +6 -0
- package/src/inbound-mail-foundation/changes.json +18 -0
- package/src/jobs/changes.json +13 -0
- package/src/mail-foundation/changes.json +6 -0
- package/src/renderer-pdf/changes.json +6 -0
- package/src/step-dispatcher/changes.json +6 -0
- package/src/subscription-dodo/changes.json +14 -0
- package/src/subscription-stripe/changes.json +12 -0
- package/src/template-resolver/changes.json +48 -0
- package/src/tenant/changes.json +6 -0
- package/src/tenant-lifecycle/changes.json +6 -0
- package/src/tier-engine/changes.json +6 -0
- package/src/waitlist/changes.json +18 -0
- package/dist/billing-foundation/consumer-protection/stored-user-email.d.ts +0 -1
- package/dist/billing-foundation/consumer-protection/stored-user-email.js +0 -8
|
@@ -1,55 +1,29 @@
|
|
|
1
|
-
// Async
|
|
1
|
+
// Async export-job worker — a pure pipeline function.
|
|
2
2
|
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
3
|
+
// A cron-triggered pass (see the r.job wrap in feature.ts) processes all
|
|
4
|
+
// pending jobs. Each job is claimed with optimistic locking through the version
|
|
5
|
+
// column: when two worker replicas pick the same job, the second one gets a
|
|
6
|
+
// VersionConflictError and skips it. The export bundle is built by
|
|
7
|
+
// run-user-export.ts, which also owns the cross-tenant iteration over the
|
|
8
|
+
// user's memberships. The requesting tenant's compliance profile supplies
|
|
9
|
+
// exportDownloadTtl for expiresAt, and the storage provider is resolved per
|
|
10
|
+
// tenant (S3 or local). The ZIP is streamed into storage atomically (tmp+rename
|
|
11
|
+
// locally, multipart upload on S3), so a throw anywhere in the pipeline marks
|
|
12
|
+
// the job failed without leaving a half-written ZIP at the final path.
|
|
6
13
|
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
//
|
|
10
|
-
// kriegt VersionConflictError + skippt.
|
|
14
|
+
// Before pickup, a stale pass fails running jobs whose
|
|
15
|
+
// startedAt + exportStaleTimeoutMinutes lies in the past, so worker crashes,
|
|
16
|
+
// OOM kills and replica restarts do not leave jobs stuck in running.
|
|
11
17
|
//
|
|
12
|
-
//
|
|
13
|
-
//
|
|
14
|
-
//
|
|
15
|
-
//
|
|
16
|
-
// 3. Profile-Resolution: `resolveProfileForTenant(requestedFromTenantId)`
|
|
17
|
-
// liefert effective compliance-profile. exportDownloadTtl wird
|
|
18
|
-
// fuer expiresAt-Berechnung gebraucht.
|
|
19
|
-
//
|
|
20
|
-
// 4. Storage-Provider builden: `buildStorageProvider(ctx, requestedFromTenantId)`
|
|
21
|
-
// — file-foundation's createFileProviderForTenant-Pattern.
|
|
22
|
-
// Pro Tenant unterschiedlicher Provider moeglich (S3 vs lokal).
|
|
23
|
-
//
|
|
24
|
-
// 5. ZIP-Stream: `createZipStream(bundleAsZipEntries(bundle))` →
|
|
25
|
-
// AsyncIterable<Uint8Array>. Wir wrappen das in einen tracking-
|
|
26
|
-
// Iterator der bytesWritten zaehlt.
|
|
27
|
-
//
|
|
28
|
-
// 6. Storage-Write: provider.writeStream(storageKey, zipStream).
|
|
29
|
-
// Atomar via tmp+rename (lokal) bzw. multipart-upload (S3).
|
|
30
|
-
//
|
|
31
|
-
// 7. Job=done: `crud.update({status: "done", completedAt, expiresAt,
|
|
32
|
-
// downloadStorageKey, bytesWritten})`.
|
|
33
|
-
//
|
|
34
|
-
// Bei Throw zwischen 2-7: Job=failed mit errorMessage. Storage-Write
|
|
35
|
-
// ist atomar (writeStream rollback bei Error im Source-Stream), keine
|
|
36
|
-
// halb-fertigen ZIPs am final-Pfad.
|
|
37
|
-
//
|
|
38
|
-
// **Stale-Detection:** vor dem Pickup-Pass laeuft ein separater
|
|
39
|
-
// Stale-Pass: Jobs in `running` mit `startedAt + exportStaleTimeoutMinutes
|
|
40
|
-
// < now` werden auf `failed` geflippt. Worker-Crashes / OOM-Kills /
|
|
41
|
-
// Replica-Restarts hinterlassen sonst stuck-running-Jobs.
|
|
42
|
-
//
|
|
43
|
-
// **Storage-Cleanup:** dritter Pass loescht abgelaufene downloadStorageKeys
|
|
44
|
-
// (`expiresAt + exportStorageCleanupGraceHours < now`) — abgelaufene ZIPs
|
|
45
|
-
// auf S3 sollen nicht ewig liegen.
|
|
18
|
+
// A final cleanup pass deletes downloadStorageKeys past
|
|
19
|
+
// expiresAt + exportStorageCleanupGraceHours, so expired ZIPs do not stay in
|
|
20
|
+
// storage indefinitely.
|
|
46
21
|
import { addDurationSpec } from "@cosmicdrift/kumiko-framework/compliance";
|
|
47
|
-
import { PII_ERASED_SENTINEL } from "@cosmicdrift/kumiko-framework/crypto";
|
|
48
22
|
import { createEventStoreExecutor, createTenantDb, fetchOne, selectMany, } from "@cosmicdrift/kumiko-framework/db";
|
|
49
23
|
import { createSystemUser } from "@cosmicdrift/kumiko-framework/engine";
|
|
50
24
|
import { createZipStream, tenantExportPrefix, } from "@cosmicdrift/kumiko-framework/files";
|
|
51
25
|
import { resolveProfileForTenant } from "../compliance-profiles/index.js";
|
|
52
|
-
import {
|
|
26
|
+
import { decryptStoredUserEmail } from "../shared/index.js";
|
|
53
27
|
import { userTable } from "../user/index.js";
|
|
54
28
|
import { selectExportJobsForStorageCleanup } from "./db/queries/export-jobs.js";
|
|
55
29
|
import { runUserExport } from "./run-user-export.js";
|
|
@@ -68,28 +42,23 @@ export const EXPORT_CLEANUP_LAST_RUN_TIMESTAMP_METRIC = "export_cleanup_last_run
|
|
|
68
42
|
const crud = createEventStoreExecutor(exportJobsTable, exportJobEntity, {
|
|
69
43
|
entityName: "export-job",
|
|
70
44
|
});
|
|
71
|
-
//
|
|
72
|
-
//
|
|
73
|
-
//
|
|
74
|
-
// (Memory `feedback_no_fake_dispatcher`).
|
|
45
|
+
// Separate event-store executor for download tokens. `crud.create` emits
|
|
46
|
+
// `exportDownloadToken.created` and synchronously updates
|
|
47
|
+
// `read_export_download_tokens`; direct inserts would bypass that projection.
|
|
75
48
|
//
|
|
76
|
-
//
|
|
77
|
-
//
|
|
49
|
+
// Exported because the download handler uses tokenCrud.update for audit fields
|
|
50
|
+
// while preserving event-store consistency.
|
|
78
51
|
export const tokenCrud = createEventStoreExecutor(exportDownloadTokensTable, exportDownloadTokenEntity, { entityName: "export-download-token" });
|
|
79
52
|
export async function runExportJobs(args) {
|
|
80
53
|
const { db, registry, buildStorageProvider, now, sendExportReadyEmail, sendExportFailedEmail } = args;
|
|
81
|
-
//
|
|
82
|
-
//
|
|
83
|
-
//
|
|
84
|
-
// Runtime-Callback-Failures sind best-effort, Boot-Misconfig ist hard-
|
|
85
|
-
// fail (App-Author-Bug, kein Network-Hiccup).
|
|
54
|
+
// Validate this configuration before the pass loop so a missing URL is not
|
|
55
|
+
// swallowed by the per-job try/catch. Callback failures are best-effort, but
|
|
56
|
+
// this is a hard application configuration error.
|
|
86
57
|
if (sendExportReadyEmail && args.appExportDownloadUrl === undefined) {
|
|
87
58
|
throw new Error("user-data-rights: sendExportReadyEmail gesetzt aber appExportDownloadUrl fehlt — beide muessen zusammen konfiguriert sein");
|
|
88
59
|
}
|
|
89
|
-
//
|
|
90
|
-
//
|
|
91
|
-
// Wird VOR dem pickup-pass ausgefuehrt damit ein neuer Worker-Run
|
|
92
|
-
// den vorhergehenden Crash erstmal als failed markiert.
|
|
60
|
+
// Fail running jobs whose tenant-specific stale timeout has elapsed before
|
|
61
|
+
// pickup, so a new run recovers jobs left behind by an earlier crash.
|
|
93
62
|
const staleFailedJobIds = await staleDetectionPass({ db, now });
|
|
94
63
|
// Pass 2: Pickup pending jobs + Process them.
|
|
95
64
|
const completedJobIds = [];
|
|
@@ -110,20 +79,13 @@ export async function runExportJobs(args) {
|
|
|
110
79
|
});
|
|
111
80
|
if (outcome.kind === "done") {
|
|
112
81
|
completedJobIds.push(job.id);
|
|
113
|
-
//
|
|
114
|
-
//
|
|
115
|
-
// NICHT in Logs/Telemetry/jobRunsTable.
|
|
82
|
+
// Keep the plain token only in memory for downstream callbacks; never put it
|
|
83
|
+
// in logs, telemetry, or jobRunsTable.
|
|
116
84
|
tokenByJobId.set(job.id, outcome.tokenPlain);
|
|
117
|
-
//
|
|
118
|
-
//
|
|
119
|
-
//
|
|
120
|
-
//
|
|
121
|
-
// pending-Jobs muessen noch verarbeitet werden. Throw waere ein
|
|
122
|
-
// Bug: r.job-Wrap markiert den Run failed, retry findet keinen
|
|
123
|
-
// pending-Job mehr (Status=done) → silent miss + ZIP laeuft nach
|
|
124
|
-
// TTL ab ohne dass der User die Email je bekommt. console.warn ist
|
|
125
|
-
// die einzige Operator-Sichtbarkeit (runExportJobs-args fuehren
|
|
126
|
-
// AppContext.log nicht durch — pure-function-Pattern).
|
|
85
|
+
// A notification failure must not abort the batch: the job is already done,
|
|
86
|
+
// and retrying the worker would find no pending job and silently miss the
|
|
87
|
+
// notification. `console.warn` is the only available operator visibility
|
|
88
|
+
// because these arguments do not carry AppContext.log.
|
|
127
89
|
if (sendExportReadyEmail) {
|
|
128
90
|
try {
|
|
129
91
|
await fireExportReadyCallback({
|
|
@@ -145,10 +107,8 @@ export async function runExportJobs(args) {
|
|
|
145
107
|
else if (outcome.kind === "failed") {
|
|
146
108
|
failedJobIds.push(job.id);
|
|
147
109
|
errors.push(outcome.error);
|
|
148
|
-
//
|
|
149
|
-
//
|
|
150
|
-
// sendExportReadyEmail (Atom 5.fix3) — Email-Send-Throw darf den
|
|
151
|
-
// Batch nicht killen.
|
|
110
|
+
// A failed-job notification is best-effort so an email-send failure cannot
|
|
111
|
+
// abort processing of the remaining pending jobs.
|
|
152
112
|
if (sendExportFailedEmail) {
|
|
153
113
|
try {
|
|
154
114
|
await fireExportFailedCallback({
|
|
@@ -164,12 +124,11 @@ export async function runExportJobs(args) {
|
|
|
164
124
|
}
|
|
165
125
|
}
|
|
166
126
|
}
|
|
167
|
-
//
|
|
168
|
-
//
|
|
127
|
+
// A claim race means another worker already owns the job; skip it without
|
|
128
|
+
// reporting an error.
|
|
169
129
|
}
|
|
170
|
-
//
|
|
171
|
-
//
|
|
172
|
-
// + im DB-Row genullt.
|
|
130
|
+
// Storage cleanup: expired done jobs (expiresAt + grace < now) get their
|
|
131
|
+
// storage object deleted and downloadStorageKey cleared in the database.
|
|
173
132
|
const cleanedJobIds = await storageCleanupPass({
|
|
174
133
|
db,
|
|
175
134
|
buildStorageProvider,
|
|
@@ -194,19 +153,14 @@ async function fetchPendingJobs(db) {
|
|
|
194
153
|
async function processJob(args) {
|
|
195
154
|
const { db, registry, buildStorageProvider, now, job } = args;
|
|
196
155
|
const executor = createSystemUser(job.requestedFromTenantId);
|
|
197
|
-
//
|
|
198
|
-
//
|
|
199
|
-
//
|
|
200
|
-
// konsistent gehalten.
|
|
156
|
+
// The event-store stream lookup requires a TenantDb even though an export job
|
|
157
|
+
// is tenant-agnostic. System mode bypasses the automatic tenant filter while
|
|
158
|
+
// `requestedFromTenantId` preserves the stream identity.
|
|
201
159
|
const tdb = systemTenantDb(db, job.requestedFromTenantId);
|
|
202
|
-
//
|
|
203
|
-
//
|
|
204
|
-
//
|
|
205
|
-
//
|
|
206
|
-
// persistiert (deterministischer Pfad aus job.id). Begründung: wenn
|
|
207
|
-
// Worker zwischen ZIP-write und done-flip crashed, hat der Job-Row
|
|
208
|
-
// bereits den Pfad → storageCleanupPass kann den orphan-ZIP via
|
|
209
|
-
// failed-Job-Cleanup-Pass loeschen (sonst forever-leak im S3).
|
|
160
|
+
// Claim with a version check so a concurrent worker causes a conflict.
|
|
161
|
+
// Persist downloadStorageKey during the claim: if the worker crashes after
|
|
162
|
+
// writing the ZIP but before marking the job done, cleanup can find the
|
|
163
|
+
// orphaned object instead of leaving it in storage indefinitely.
|
|
210
164
|
const storageKey = buildExportStorageKey(job);
|
|
211
165
|
const claimResult = await crud.update({
|
|
212
166
|
id: job.id,
|
|
@@ -218,11 +172,11 @@ async function processJob(args) {
|
|
|
218
172
|
},
|
|
219
173
|
}, executor, tdb);
|
|
220
174
|
if (!claimResult.isSuccess) {
|
|
221
|
-
//
|
|
175
|
+
// Another worker won the claim race, so skip this job without logging an error.
|
|
222
176
|
return { kind: "skipped" };
|
|
223
177
|
}
|
|
224
|
-
//
|
|
225
|
-
//
|
|
178
|
+
// Build the bundle, stream the ZIP, and write it to storage. Errors before
|
|
179
|
+
// completion are materialized as a failed job.
|
|
226
180
|
try {
|
|
227
181
|
const bundle = await runUserExport({
|
|
228
182
|
db,
|
|
@@ -238,11 +192,10 @@ async function processJob(args) {
|
|
|
238
192
|
tenantId: job.requestedFromTenantId,
|
|
239
193
|
});
|
|
240
194
|
const ttl = profile.profile.userRights.exportDownloadTtl;
|
|
241
|
-
//
|
|
242
|
-
//
|
|
243
|
-
//
|
|
244
|
-
//
|
|
245
|
-
// ueber den fileRef.tenantId.
|
|
195
|
+
// Cross-tenant file references require a provider per tenant because storage
|
|
196
|
+
// configuration may differ. Cache each provider so a tenant is initialized
|
|
197
|
+
// only once; the requested tenant owns the write path, while reads use each
|
|
198
|
+
// file reference's tenantId.
|
|
246
199
|
const providerCache = new Map();
|
|
247
200
|
const cachedProvider = async (tenantId) => {
|
|
248
201
|
let p = providerCache.get(tenantId);
|
|
@@ -253,32 +206,26 @@ async function processJob(args) {
|
|
|
253
206
|
return p;
|
|
254
207
|
};
|
|
255
208
|
const writeProvider = await cachedProvider(job.requestedFromTenantId);
|
|
256
|
-
//
|
|
257
|
-
//
|
|
209
|
+
// The provider type requires both methods, so runtime optional checks are
|
|
210
|
+
// unnecessary.
|
|
258
211
|
const tracker = countingStream(createZipStream(bundleToZipEntries(bundle, now, cachedProvider)));
|
|
259
212
|
await writeProvider.writeStream(storageKey, tracker.stream, {
|
|
260
213
|
mimeType: "application/zip",
|
|
261
214
|
});
|
|
262
|
-
//
|
|
263
|
-
//
|
|
264
|
-
//
|
|
265
|
-
//
|
|
266
|
-
// VOR und done-flip NACH: tightes Race-Window in dem ein Worker-
|
|
267
|
-
// Crash zwischen den zwei calls einen Token + ZIP orphans. Beides
|
|
268
|
-
// catched die Stale-Detection im naechsten Pass — Job=failed,
|
|
269
|
-
// Storage-Cleanup-Pass clearted den ZIP (path-pre-claim oben).
|
|
215
|
+
// Create the token before the done transition: if token creation fails, the
|
|
216
|
+
// job is still running and the catch path marks it failed (monotonic status).
|
|
217
|
+
// A crash between the two calls can orphan a token and a ZIP; the next
|
|
218
|
+
// stale-detection pass fails the job and the cleanup pass removes the ZIP.
|
|
270
219
|
//
|
|
271
|
-
//
|
|
272
|
-
//
|
|
273
|
-
// ES via tokenCrud.create — kein direct-INSERT.
|
|
220
|
+
// The plain token stays in worker memory and reaches the notification
|
|
221
|
+
// through RunExportJobsResult; only its hash is stored.
|
|
274
222
|
//
|
|
275
|
-
// **
|
|
276
|
-
//
|
|
277
|
-
//
|
|
278
|
-
//
|
|
279
|
-
//
|
|
280
|
-
//
|
|
281
|
-
// (update mit frischem Hash + Reset der Audit-Felder).
|
|
223
|
+
// **Reruns:** when an operator flips a done or failed job back to pending
|
|
224
|
+
// (lost plain token, email failure), a token row already exists for the
|
|
225
|
+
// jobId. A second create would emit another created event on a fresh
|
|
226
|
+
// aggregate, and projection rebuilds would keep colliding on the
|
|
227
|
+
// one_per_job index. Rotate the token in place on the existing aggregate
|
|
228
|
+
// instead (fresh hash, audit fields reset).
|
|
282
229
|
const expiresAt = addDurationSpec(now, ttl);
|
|
283
230
|
const { plain: tokenPlain, hash: tokenHash } = await generateDownloadToken();
|
|
284
231
|
const existingToken = await fetchOne(db, exportDownloadTokensTable, { jobId: job.id });
|
|
@@ -301,39 +248,33 @@ async function processJob(args) {
|
|
|
301
248
|
tokenHash,
|
|
302
249
|
issuedAt: now,
|
|
303
250
|
expiresAt,
|
|
304
|
-
//
|
|
305
|
-
//
|
|
306
|
-
// Defensiv-Code.
|
|
251
|
+
// Set useCount explicitly to 0 so verification can increment it with
|
|
252
|
+
// `useCount + 1` without defensive COALESCE logic.
|
|
307
253
|
useCount: 0,
|
|
308
254
|
}, executor, tdb);
|
|
309
255
|
if (!tokenCreateResult.isSuccess) {
|
|
310
|
-
// Token
|
|
311
|
-
//
|
|
312
|
-
//
|
|
313
|
-
// persistiert).
|
|
256
|
+
// Token creation failed before the done transition. The catch path marks the
|
|
257
|
+
// job failed, and cleanup can remove the ZIP whose path was persisted at
|
|
258
|
+
// claim time.
|
|
314
259
|
throw new Error(`Job ${job.id}: Token-Creation failed before done-flip. ` +
|
|
315
260
|
`${tokenCreateResult.error?.code ?? "unknown"}`);
|
|
316
261
|
}
|
|
317
|
-
//
|
|
318
|
-
// hier persistiert (denormalisiert in beiden Tabellen).
|
|
262
|
+
// Persist the same expiresAt used for the token on the job row as well.
|
|
319
263
|
const doneResult = await crud.update({
|
|
320
264
|
id: job.id,
|
|
321
|
-
version: job.version + 1, // +1
|
|
265
|
+
version: job.version + 1, // +1 because the claim already performed one update
|
|
322
266
|
changes: {
|
|
323
267
|
status: EXPORT_JOB_STATUS.Done,
|
|
324
268
|
completedAt: now,
|
|
325
|
-
// downloadStorageKey
|
|
326
|
-
//
|
|
269
|
+
// downloadStorageKey was set during the claim, so it does not need to be
|
|
270
|
+
// written again.
|
|
327
271
|
expiresAt,
|
|
328
272
|
bytesWritten: tracker.bytes,
|
|
329
273
|
},
|
|
330
274
|
}, executor, tdb);
|
|
331
275
|
if (!doneResult.isSuccess) {
|
|
332
|
-
//
|
|
333
|
-
//
|
|
334
|
-
// failed damit der Operator das sieht. Token-Row bleibt orphan
|
|
335
|
-
// bis Atom-spaeter-Cleanup; Storage-ZIP wird via failed-Cleanup
|
|
336
|
-
// gecleared.
|
|
276
|
+
// The done transition failed after claiming. Mark the job failed so the
|
|
277
|
+
// operator can see the error; the token and ZIP remain for later cleanup.
|
|
337
278
|
throw new Error(`Job ${job.id}: failed to flip status=done after successful Token-Create. ` +
|
|
338
279
|
`${doneResult.error?.code ?? "unknown"}`);
|
|
339
280
|
}
|
|
@@ -341,9 +282,8 @@ async function processJob(args) {
|
|
|
341
282
|
}
|
|
342
283
|
catch (e) {
|
|
343
284
|
const message = e instanceof Error ? e.message : String(e);
|
|
344
|
-
//
|
|
345
|
-
//
|
|
346
|
-
// Worker-Run faengt ihn dann auf.
|
|
285
|
+
// Failure handling is best-effort. If the failure transition also fails, the
|
|
286
|
+
// job remains running and stale detection will recover it on a later run.
|
|
347
287
|
await crud
|
|
348
288
|
.update({
|
|
349
289
|
id: job.id,
|
|
@@ -370,12 +310,10 @@ async function processJob(args) {
|
|
|
370
310
|
}
|
|
371
311
|
async function staleDetectionPass(args) {
|
|
372
312
|
const { db, now } = args;
|
|
373
|
-
//
|
|
374
|
-
//
|
|
375
|
-
//
|
|
376
|
-
//
|
|
377
|
-
// 60s, zu jedem Zeitpunkt sind nur wenige Jobs in `running` —
|
|
378
|
-
// alle fetchen + profile-resolve im Loop ist bezahlbar + korrekt.
|
|
313
|
+
// Fetch all running jobs instead of applying a coarse one-hour filter:
|
|
314
|
+
// exportStaleTimeoutMinutes is tenant-specific and may be as low as five
|
|
315
|
+
// minutes, so a coarse filter could miss stale jobs. The expected number of
|
|
316
|
+
// running jobs makes resolving each tenant's profile practical.
|
|
379
317
|
const candidates = await selectMany(db, exportJobsTable, { status: EXPORT_JOB_STATUS.Running });
|
|
380
318
|
const failed = [];
|
|
381
319
|
for (const c of candidates) {
|
|
@@ -397,41 +335,21 @@ async function staleDetectionPass(args) {
|
|
|
397
335
|
}, createSystemUser(c.requestedFromTenantId), systemTenantDb(db, c.requestedFromTenantId));
|
|
398
336
|
if (result.isSuccess)
|
|
399
337
|
failed.push(c.id);
|
|
400
|
-
//
|
|
338
|
+
// Another worker completed the job, so skip it.
|
|
401
339
|
}
|
|
402
340
|
}
|
|
403
341
|
return failed;
|
|
404
342
|
}
|
|
405
343
|
async function storageCleanupPass(args) {
|
|
406
344
|
const { db, buildStorageProvider, now, metrics } = args;
|
|
407
|
-
//
|
|
408
|
-
//
|
|
409
|
-
//
|
|
410
|
-
//
|
|
411
|
-
//
|
|
412
|
-
//
|
|
413
|
-
//
|
|
414
|
-
//
|
|
415
|
-
// schiefgegangen (Token-Create-Fail, done-flip-Fail, Stale-
|
|
416
|
-
// Detection mid-write). Job=failed mit gesetztem downloadStorageKey =
|
|
417
|
-
// ZIP-Orphan in Storage, kein User-Pfad zum download.
|
|
418
|
-
//
|
|
419
|
-
// **Strategie failed-Jobs: SOFORTIGE Cleanup ohne Grace.**
|
|
420
|
-
//
|
|
421
|
-
// Trade-off (DSGVO vs Audit-Forensik):
|
|
422
|
-
// - DSGVO: User-Daten-ZIP einer failed-export-Anfrage hat keinen
|
|
423
|
-
// legitimen Aufbewahrungs-Grund — hier ueberwiegt das Recht auf
|
|
424
|
-
// Loeschung
|
|
425
|
-
// - Audit-Forensik: forensische Untersuchung ("was ist im ZIP gelandet,
|
|
426
|
-
// warum failed der Job") wuerde von einer Grace-Periode profitieren —
|
|
427
|
-
// ABER: Token wurde nie ausgegeben (kein User hat das ZIP gesehen),
|
|
428
|
-
// also keine User-Schaden-Forensik. Operator-Audit hat job.errorMessage
|
|
429
|
-
// + Stack-Trace, das reicht
|
|
430
|
-
// → Trade-off zugunsten DSGVO entschieden. Wenn ein Operator forensik
|
|
431
|
-
// braucht, muss er das vor dem Cleanup-Pass capturen (out-of-band).
|
|
432
|
-
//
|
|
433
|
-
// **SQL-Filter:** status IN (done, failed) + downloadStorageKey IS NOT NULL
|
|
434
|
-
// via selectMany (db/queries/export-jobs.ts).
|
|
345
|
+
// Done jobs are cleaned after expiresAt plus the tenant's grace period
|
|
346
|
+
// (default 24h after expiry, so re-downloads after a dropped connection still
|
|
347
|
+
// work). Failed jobs with a persisted downloadStorageKey are orphaned ZIPs:
|
|
348
|
+
// the worker wrote the ZIP but failed before the done flip, so no token was
|
|
349
|
+
// ever issued and no user has seen it. They are removed immediately, without
|
|
350
|
+
// grace: the right to erasure outweighs forensics here, and the job's
|
|
351
|
+
// errorMessage and stack trace are the operator's audit record. An operator
|
|
352
|
+
// who needs the ZIP itself must capture it out of band before this pass.
|
|
435
353
|
const candidates = await selectExportJobsForStorageCleanup(db, EXPORT_JOB_STATUS.Done, EXPORT_JOB_STATUS.Failed);
|
|
436
354
|
const cleaned = [];
|
|
437
355
|
// Candidates past their due-instant, keyed by that instant — used below to
|
|
@@ -539,11 +457,9 @@ function reportCleanupLastRun(metrics, now) {
|
|
|
539
457
|
console.warn(`[user-data-rights:run-export-jobs] metrics.set(${EXPORT_CLEANUP_LAST_RUN_TIMESTAMP_METRIC}) failed err=${err instanceof Error ? err.message : String(err)}`);
|
|
540
458
|
}
|
|
541
459
|
}
|
|
542
|
-
//
|
|
543
|
-
// (
|
|
544
|
-
//
|
|
545
|
-
// — wir nutzen `requestedFromTenantId` als Stream-Identity damit der
|
|
546
|
-
// Stream-Counter konsistent bleibt (Memory feedback_event_store_tenant_consistency).
|
|
460
|
+
// `crud.update` requires a TenantDb for event-store stream lookup. Export jobs are tenant-agnostic
|
|
461
|
+
// (one job per userId), so system mode bypasses the automatic tenant filter while
|
|
462
|
+
// `requestedFromTenantId` preserves stream identity and keeps the stream counter consistent.
|
|
547
463
|
// @wrapper-known semantic-alias
|
|
548
464
|
function systemTenantDb(db, tenantId) {
|
|
549
465
|
return createTenantDb({ db, tenantId, mode: "system" });
|
|
@@ -552,41 +468,31 @@ function buildExportStorageKey(job) {
|
|
|
552
468
|
return `${tenantExportPrefix(job.requestedFromTenantId)}${job.id}.zip`;
|
|
553
469
|
}
|
|
554
470
|
/**
|
|
555
|
-
*
|
|
556
|
-
*
|
|
471
|
+
* Converts a UserExportBundle to an `AsyncIterable<ZipEntry>` for
|
|
472
|
+
* createZipStream. `bundle.json` contains the bundle metadata and file
|
|
473
|
+
* references; each file is streamed from the provider at its `zipPath`, so
|
|
474
|
+
* large files do not require an in-memory copy.
|
|
557
475
|
*
|
|
558
|
-
*
|
|
559
|
-
*
|
|
560
|
-
* + tenant-sections + flat
|
|
561
|
-
* fileRefs[] mit zipPath
|
|
562
|
-
* pro Datei
|
|
563
|
-
* files/<tenantId>/<fileRefId>-<name> — File-Binaries, Pfad
|
|
564
|
-
* identisch zu fileRef.zipPath
|
|
565
|
-
* im JSON. Bytes via
|
|
566
|
-
* provider.readStream — kein
|
|
567
|
-
* Memory-Spike, auch grosse
|
|
568
|
-
* PDFs streamen durch.
|
|
569
|
-
*
|
|
570
|
-
* `getProvider` ist ein async-cached Resolver pro tenantId. Caller
|
|
571
|
-
* (processJob) baut die Caching-Map damit jeder Tenant nur EINMAL
|
|
572
|
-
* via `buildStorageProvider` materialisiert wird.
|
|
476
|
+
* `getProvider` caches providers by tenantId, ensuring each tenant is built
|
|
477
|
+
* only once while processing cross-tenant file references.
|
|
573
478
|
*/
|
|
574
479
|
async function* bundleToZipEntries(bundle, mtime, getProvider) {
|
|
575
|
-
// bundle.json
|
|
480
|
+
// Emit bundle.json first so readers can parse the metadata before the file
|
|
481
|
+
// entries arrive.
|
|
576
482
|
const bundleJson = JSON.stringify(bundle, null, 2);
|
|
577
483
|
yield {
|
|
578
484
|
path: "bundle.json",
|
|
579
485
|
data: oneShot(new TextEncoder().encode(bundleJson)),
|
|
580
486
|
mtime,
|
|
581
487
|
};
|
|
582
|
-
// File
|
|
583
|
-
//
|
|
584
|
-
//
|
|
585
|
-
//
|
|
488
|
+
// File binaries: one ZIP entry per fileRef. `data` is the readStream directly,
|
|
489
|
+
// so the ZIP builder consumes chunks without an upfront memory spike. Even
|
|
490
|
+
// with 50 PDFs at 10MB each, at most about 64KB (default highWaterMark) is
|
|
491
|
+
// held in the heap at once.
|
|
586
492
|
for (const ref of bundle.fileRefs) {
|
|
587
493
|
const provider = await getProvider(ref.tenantId);
|
|
588
|
-
// readStream
|
|
589
|
-
//
|
|
494
|
+
// `readStream` is required by the FileStorageProvider type, so no runtime
|
|
495
|
+
// optional check is needed.
|
|
590
496
|
yield {
|
|
591
497
|
path: ref.zipPath,
|
|
592
498
|
data: provider.readStream(ref.storageKey),
|
|
@@ -598,9 +504,9 @@ async function* oneShot(bytes) {
|
|
|
598
504
|
yield bytes;
|
|
599
505
|
}
|
|
600
506
|
/**
|
|
601
|
-
* Wraps an `AsyncIterable<Uint8Array>`
|
|
602
|
-
* `for await
|
|
603
|
-
* bytesWritten
|
|
507
|
+
* Wraps an `AsyncIterable<Uint8Array>` and counts the total bytes. After
|
|
508
|
+
* `for await`, `tracker.bytes` contains the final value used for
|
|
509
|
+
* `bytesWritten` in the job row.
|
|
604
510
|
*/
|
|
605
511
|
function countingStream(source) {
|
|
606
512
|
const tracker = { bytes: 0 };
|
|
@@ -619,46 +525,34 @@ function countingStream(source) {
|
|
|
619
525
|
},
|
|
620
526
|
};
|
|
621
527
|
}
|
|
622
|
-
//
|
|
623
|
-
//
|
|
624
|
-
//
|
|
625
|
-
//
|
|
626
|
-
// runUserExport's Cross-Tenant-Iteration die ebenso direkt
|
|
627
|
-
// tenantMembershipsTable liest. Cross-feature-API via dispatcher
|
|
628
|
-
// haette einen JobContext-Wrapper gebraucht den der framework noch
|
|
629
|
-
// nicht hat — wenn das mal kommt, ist der hier Refactor-Kandidat.
|
|
528
|
+
// Reads directly from the database because the worker's AppContext has no
|
|
529
|
+
// queryAs, unlike HandlerContext in the request path. The cross-tenant
|
|
530
|
+
// export iteration uses the same approach; a dispatcher-based cross-feature
|
|
531
|
+
// API would require a JobContext wrapper that the framework does not provide.
|
|
630
532
|
//
|
|
631
|
-
//
|
|
632
|
-
//
|
|
633
|
-
//
|
|
634
|
-
// aus jedem Worker-Tenant-Context.
|
|
533
|
+
// userTable.id is globally unique. Even when a user belongs to multiple
|
|
534
|
+
// tenants, there is only one user row with its home tenant as tenantId, so a
|
|
535
|
+
// lookup without a tenantId filter works from any worker tenant context.
|
|
635
536
|
async function lookupUserContact(db, userId) {
|
|
636
537
|
// @cast-boundary db-row.
|
|
637
538
|
const row = (await fetchOne(db, userTable, { id: userId }));
|
|
638
539
|
if (!row?.email)
|
|
639
540
|
return null;
|
|
640
|
-
const email = await
|
|
641
|
-
if (email ===
|
|
541
|
+
const email = await decryptStoredUserEmail(row.email, "user-data-rights:export-ready");
|
|
542
|
+
if (email === null)
|
|
642
543
|
return null;
|
|
643
544
|
return { email, locale: row.locale ?? null };
|
|
644
545
|
}
|
|
645
|
-
//
|
|
646
|
-
//
|
|
647
|
-
//
|
|
648
|
-
// den Worker-Run erneut anstossen — der Job selbst bleibt done, das
|
|
649
|
-
// retry findet keinen pending-Job mehr aber die Audit-Log zeigt den
|
|
650
|
-
// Failure.
|
|
546
|
+
// The callback is best-effort: its failure must not abort the batch because
|
|
547
|
+
// the job is already done, and retrying the worker will not find it pending.
|
|
548
|
+
// The failure remains visible in the worker-run audit log.
|
|
651
549
|
async function fireExportReadyCallback(args) {
|
|
652
550
|
const contact = await lookupUserContact(args.db, args.job.userId);
|
|
653
551
|
if (!contact) {
|
|
654
|
-
//
|
|
655
|
-
//
|
|
656
|
-
//
|
|
657
|
-
//
|
|
658
|
-
// aktuell nicht durch (Worker-pure-function-Pattern). console.warn ist
|
|
659
|
-
// die einzige Operator-Sichtbarkeit fuer den missing-user-edge-case.
|
|
660
|
-
// Wenn jobs-Feature spaeter ctx.log threadet oder Worker-args erweitert
|
|
661
|
-
// werden, hier Refactor-Kandidat.
|
|
552
|
+
// If the user row is missing, skip the notification instead of throwing:
|
|
553
|
+
// the job remains done, and the token remains available through
|
|
554
|
+
// export-status.query. console.warn is used because the worker arguments
|
|
555
|
+
// do not currently carry AppContext.log.
|
|
662
556
|
// biome-ignore lint/suspicious/noConsole: operator-visibility for missing-user edge-case
|
|
663
557
|
console.warn(`[user-data-rights:run-export-jobs] userId=${args.job.userId} hat kein userEmail — sendExportReadyEmail skipped`);
|
|
664
558
|
// skip: missing user-email row; console.warn above provides operator visibility
|
|
@@ -680,7 +574,6 @@ async function fireExportReadyCallback(args) {
|
|
|
680
574
|
bytesWritten: args.bytesWritten,
|
|
681
575
|
});
|
|
682
576
|
}
|
|
683
|
-
// Atom 5 — Email-Notification beim failed-flip.
|
|
684
577
|
async function fireExportFailedCallback(args) {
|
|
685
578
|
const contact = await lookupUserContact(args.db, args.job.userId);
|
|
686
579
|
if (!contact) {
|