@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,17 +1,16 @@
|
|
|
1
|
-
// createInboundMailSupervisor —
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
1
|
+
// createInboundMailSupervisor — the long-lived Foundation sync process:
|
|
2
|
+
// starts `plugin.watch()` (IMAP IDLE, seconds-level push) for each active
|
|
3
|
+
// account with reconnect backoff, and also runs the periodic reconciliation
|
|
4
|
+
// poll (default: 5 min) through `plugin.fetch()`.
|
|
5
|
+
// Deduplication in the ingest handler makes watch/poll overlap idempotent:
|
|
6
|
+
// the poll is the correctness anchor, while watch only reduces latency.
|
|
7
7
|
//
|
|
8
|
-
// **
|
|
9
|
-
// cron trigger.
|
|
10
|
-
//
|
|
11
|
-
//
|
|
12
|
-
//
|
|
13
|
-
//
|
|
14
|
-
// app owner still wires the supervisor in bin/server.ts:
|
|
8
|
+
// **Documented deviation:** the poll was originally intended as an `r.job`
|
|
9
|
+
// cron trigger. JobContext previously had no dispatcher (see
|
|
10
|
+
// run-export-jobs.ts), but now has one (`ctx.write`/`ctx.queryAs`,
|
|
11
|
+
// job-runner.ts). Converting the poll to a cron job is a separate migration
|
|
12
|
+
// because it changes the concurrency model, so this dispatcher contract
|
|
13
|
+
// remains in place. The app owner wires the supervisor in bin/server.ts:
|
|
15
14
|
//
|
|
16
15
|
// const supervisor = createInboundMailSupervisor({
|
|
17
16
|
// providerCtx: { registry: deps.registry, secrets, metricsFor: deps.metricsFor },
|
|
@@ -20,29 +19,29 @@
|
|
|
20
19
|
// deps.dispatchSystemWrite({ handlerQn, payload, tenantId: tenantId as TenantId }),
|
|
21
20
|
// // Multi-worker deployments: share one DistributedLock (same Redis,
|
|
22
21
|
// // same key prefix) across every worker process so only one of them
|
|
23
|
-
// // holds the IMAP IDLE connection per account
|
|
22
|
+
// // holds the IMAP IDLE connection per account. Omit `lock`
|
|
24
23
|
// // for a single-process deployment — every active account gets
|
|
25
|
-
// // watched locally,
|
|
24
|
+
// // watched locally, as before.
|
|
26
25
|
// lock: createDistributedLock(redis, `${RedisKeys.lock}inbound-mail:watch:`),
|
|
27
26
|
// });
|
|
28
27
|
// await supervisor.start();
|
|
29
28
|
// // shutdown-hook: await supervisor.stop();
|
|
30
29
|
//
|
|
31
|
-
// **IDLE operational risk
|
|
32
|
-
//
|
|
33
|
-
//
|
|
30
|
+
// **IDLE operational risk:** long-lived sockets run in-process.
|
|
31
|
+
// Backoff restart on onError, clean shutdown of every watcher, and the poll
|
|
32
|
+
// covering every gap mitigate this risk.
|
|
34
33
|
//
|
|
35
|
-
// **Multi-worker coordination
|
|
36
|
-
//
|
|
37
|
-
//
|
|
38
|
-
//
|
|
39
|
-
//
|
|
40
|
-
// the account
|
|
41
|
-
//
|
|
42
|
-
//
|
|
43
|
-
//
|
|
44
|
-
//
|
|
45
|
-
//
|
|
34
|
+
// **Multi-worker coordination:** the reconciliation poll remains deliberately
|
|
35
|
+
// N-fold: every worker polls every active account, which is idempotent and
|
|
36
|
+
// cheap. Only `plugin.watch()` holds a long-lived connection, and only one
|
|
37
|
+
// worker may hold it per account. With `deps.lock`, `ensureWatcher` claims a
|
|
38
|
+
// TTL lease (`lock.acquire`) before connecting; a worker that fails to claim
|
|
39
|
+
// it leaves the account to its current holder, while the poll still covers
|
|
40
|
+
// it. The holder renews the lease via heartbeat (`lock.renew`, every ttl/3)
|
|
41
|
+
// for as long as the watcher state exists, including reconnect backoff, not
|
|
42
|
+
// only while the connection is open. Losing the claim (for example through
|
|
43
|
+
// a Redis outage or expired TTL) tears down the local watcher instead of
|
|
44
|
+
// racing a new holder.
|
|
46
45
|
import { configuredPiiSubjectKms, decryptPiiFieldValues, } from "@cosmicdrift/kumiko-framework/crypto";
|
|
47
46
|
import { fetchOne, insertOne, selectMany, updateMany } from "@cosmicdrift/kumiko-framework/db";
|
|
48
47
|
import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
|
|
@@ -64,9 +63,10 @@ const DEFAULT_MAX_MESSAGES_PER_POLL = 200;
|
|
|
64
63
|
const DEFAULT_WATCH_BACKOFF_INITIAL_MS = 5_000;
|
|
65
64
|
const DEFAULT_WATCH_BACKOFF_MAX_MS = 5 * 60 * 1000;
|
|
66
65
|
const DEFAULT_WATCH_LEASE_TTL_SECONDS = 90;
|
|
67
|
-
/**
|
|
68
|
-
*
|
|
66
|
+
/** One cursor per account (one mailbox inbox) for now; multi-folder support
|
|
67
|
+
* can add further scopes later without a schema change. */
|
|
69
68
|
const CURSOR_SCOPE = "default";
|
|
69
|
+
const SEEN_LOOKUP_CHUNK_SIZE = 1000;
|
|
70
70
|
export function createInboundMailSupervisor(deps) {
|
|
71
71
|
const pollIntervalMs = deps.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS;
|
|
72
72
|
const backfillWindowDays = deps.backfillWindowDays ?? DEFAULT_BACKFILL_WINDOW_DAYS;
|
|
@@ -103,8 +103,8 @@ export function createInboundMailSupervisor(deps) {
|
|
|
103
103
|
let pollInFlight = null;
|
|
104
104
|
const watchers = new Map();
|
|
105
105
|
// ---------------------------------------------------------------
|
|
106
|
-
// Account
|
|
107
|
-
// (
|
|
106
|
+
// Account snapshot: active accounts of all tenants with the address
|
|
107
|
+
// decrypted (providers never work with ciphertext).
|
|
108
108
|
// ---------------------------------------------------------------
|
|
109
109
|
async function listActiveAccounts() {
|
|
110
110
|
const rows = await selectMany(deps.db, mailAccountsProjectionTable, {
|
|
@@ -113,11 +113,20 @@ export function createInboundMailSupervisor(deps) {
|
|
|
113
113
|
const piiKms = configuredPiiSubjectKms();
|
|
114
114
|
const records = [];
|
|
115
115
|
for (const row of rows) {
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
116
|
+
let decrypted;
|
|
117
|
+
try {
|
|
118
|
+
decrypted = piiKms
|
|
119
|
+
? await decryptPiiFieldValues(row, MAIL_ACCOUNT_PII_FIELDS, piiKms, {
|
|
120
|
+
requestId: "inbound-mail-foundation:supervisor:list-accounts",
|
|
121
|
+
})
|
|
122
|
+
: row;
|
|
123
|
+
}
|
|
124
|
+
catch (error) {
|
|
125
|
+
// Class name only: the message may carry ciphertext or key details.
|
|
126
|
+
const errorName = error instanceof Error ? error.name : "unknown error";
|
|
127
|
+
log(`inbound-mail: account ${row.id} skipped — address did not decrypt (${errorName})`);
|
|
128
|
+
continue;
|
|
129
|
+
}
|
|
121
130
|
const decryptedAddress = decrypted["address"];
|
|
122
131
|
// Falling back to row.address would hand the ciphertext to a provider.
|
|
123
132
|
// One undecryptable account must not stop polling of every other tenant's accounts.
|
|
@@ -154,7 +163,7 @@ export function createInboundMailSupervisor(deps) {
|
|
|
154
163
|
return isPlainObject(parsed) ? parsed : null;
|
|
155
164
|
}
|
|
156
165
|
catch {
|
|
157
|
-
return null; //
|
|
166
|
+
return null; // a corrupt cursor counts as none → backfill; dedup catches duplicates
|
|
158
167
|
}
|
|
159
168
|
}
|
|
160
169
|
async function saveCursor(account, cursor) {
|
|
@@ -167,7 +176,7 @@ export function createInboundMailSupervisor(deps) {
|
|
|
167
176
|
});
|
|
168
177
|
if (existing) {
|
|
169
178
|
await updateMany(deps.db, syncCursorTable, { cursor: serialized, updatedAt: now }, { accountId, scope: CURSOR_SCOPE });
|
|
170
|
-
// skip: update
|
|
179
|
+
// skip: the update path is complete; do not fall through to the insert branch.
|
|
171
180
|
return;
|
|
172
181
|
}
|
|
173
182
|
await insertOne(deps.db, syncCursorTable, {
|
|
@@ -181,12 +190,12 @@ export function createInboundMailSupervisor(deps) {
|
|
|
181
190
|
});
|
|
182
191
|
}
|
|
183
192
|
async function resetCursor(accountId) {
|
|
184
|
-
//
|
|
185
|
-
//
|
|
193
|
+
// No deleteMany import is needed: an empty cursor parses to null, so the
|
|
194
|
+
// next fetch runs as a backfill.
|
|
186
195
|
await updateMany(deps.db, syncCursorTable, { cursor: "", updatedAt: Temporal.Now.instant().toString() }, { accountId, scope: CURSOR_SCOPE });
|
|
187
196
|
}
|
|
188
197
|
// ---------------------------------------------------------------
|
|
189
|
-
// Ingest
|
|
198
|
+
// Ingest: every message goes through the standard write handler.
|
|
190
199
|
// ---------------------------------------------------------------
|
|
191
200
|
async function ingestBatch(account, msgs, cursorSnapshot) {
|
|
192
201
|
for (const msg of msgs) {
|
|
@@ -214,9 +223,9 @@ export function createInboundMailSupervisor(deps) {
|
|
|
214
223
|
},
|
|
215
224
|
});
|
|
216
225
|
if (!result.isSuccess) {
|
|
217
|
-
//
|
|
218
|
-
//
|
|
219
|
-
//
|
|
226
|
+
// A single-message failure aborts the batch without persisting the cursor.
|
|
227
|
+
// The next tick refetches from the old cursor, and deduplication skips
|
|
228
|
+
// messages that were already processed.
|
|
220
229
|
throw new Error(`ingest-message failed for account ${account.id}: ${JSON.stringify(result.error ?? {})}`);
|
|
221
230
|
}
|
|
222
231
|
}
|
|
@@ -229,8 +238,8 @@ export function createInboundMailSupervisor(deps) {
|
|
|
229
238
|
});
|
|
230
239
|
}
|
|
231
240
|
// ---------------------------------------------------------------
|
|
232
|
-
//
|
|
233
|
-
//
|
|
241
|
+
// Error semantics, shared by poll and watch. Returns true when the
|
|
242
|
+
// account may keep running.
|
|
234
243
|
// ---------------------------------------------------------------
|
|
235
244
|
async function handleSyncError(account, err) {
|
|
236
245
|
if (isInboundAuthError(err)) {
|
|
@@ -241,14 +250,14 @@ export function createInboundMailSupervisor(deps) {
|
|
|
241
250
|
}
|
|
242
251
|
if (isInboundRateLimitError(err)) {
|
|
243
252
|
log(`inbound-mail: account ${account.id} rate-limited (retryAfter ${err.retryAfterMs}ms)`);
|
|
244
|
-
return true; //
|
|
253
|
+
return true; // The next tick retries it
|
|
245
254
|
}
|
|
246
255
|
if (isInboundCursorInvalidError(err)) {
|
|
247
256
|
log(`inbound-mail: account ${account.id} cursor invalid — full resync in backfill window`);
|
|
248
257
|
await resetCursor(account.id);
|
|
249
258
|
return true;
|
|
250
259
|
}
|
|
251
|
-
// Transient
|
|
260
|
+
// Transient or unknown error: log it and retry on the next tick.
|
|
252
261
|
log(`inbound-mail: account ${account.id} sync error: ${describeError(err)}`);
|
|
253
262
|
return true;
|
|
254
263
|
}
|
|
@@ -259,12 +268,19 @@ export function createInboundMailSupervisor(deps) {
|
|
|
259
268
|
return async (providerMessageIds) => {
|
|
260
269
|
if (providerMessageIds.length === 0)
|
|
261
270
|
return new Set();
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
271
|
+
// One bind parameter per id: a full-mailbox listing would exceed Postgres' 65535 limit.
|
|
272
|
+
const seenIds = new Set();
|
|
273
|
+
for (let start = 0; start < providerMessageIds.length; start += SEEN_LOOKUP_CHUNK_SIZE) {
|
|
274
|
+
const seen = await selectMany(deps.db, seenMessageTable, {
|
|
275
|
+
tenantId: account.tenantId,
|
|
276
|
+
accountId: account.id,
|
|
277
|
+
providerMessageId: {
|
|
278
|
+
in: providerMessageIds.slice(start, start + SEEN_LOOKUP_CHUNK_SIZE),
|
|
279
|
+
},
|
|
280
|
+
}, { fields: ["providerMessageId"] });
|
|
281
|
+
for (const row of seen)
|
|
282
|
+
seenIds.add(row.providerMessageId);
|
|
283
|
+
}
|
|
268
284
|
return new Set(providerMessageIds.filter((id) => !seenIds.has(id)));
|
|
269
285
|
};
|
|
270
286
|
}
|
|
@@ -272,7 +288,8 @@ export function createInboundMailSupervisor(deps) {
|
|
|
272
288
|
let cursor = await loadCursor(account.id);
|
|
273
289
|
let budget = maxMessagesPerPoll;
|
|
274
290
|
try {
|
|
275
|
-
// hasMore
|
|
291
|
+
// hasMore loop: paginate within this tick until the message budget is
|
|
292
|
+
// exhausted.
|
|
276
293
|
for (;;) {
|
|
277
294
|
const accessToken = await resolveAccessToken(account, plugin);
|
|
278
295
|
const result = await plugin.fetch(deps.providerCtx, account, cursor, {
|
|
@@ -308,7 +325,7 @@ export function createInboundMailSupervisor(deps) {
|
|
|
308
325
|
if (running)
|
|
309
326
|
await ensureWatcher(account, plugin);
|
|
310
327
|
}
|
|
311
|
-
//
|
|
328
|
+
// Remove watchers for accounts that are no longer active.
|
|
312
329
|
const activeIds = new Set(accounts.map((a) => a.id));
|
|
313
330
|
for (const accountId of watchers.keys()) {
|
|
314
331
|
if (!activeIds.has(accountId))
|
|
@@ -316,7 +333,7 @@ export function createInboundMailSupervisor(deps) {
|
|
|
316
333
|
}
|
|
317
334
|
}
|
|
318
335
|
// ---------------------------------------------------------------
|
|
319
|
-
// Watch
|
|
336
|
+
// Watch lifecycle with backoff restart.
|
|
320
337
|
// ---------------------------------------------------------------
|
|
321
338
|
// Heartbeat for a held watch lease. Independent of the connection's own
|
|
322
339
|
// lifecycle — it keeps renewing across reconnect backoff, not just while
|
|
@@ -368,7 +385,7 @@ export function createInboundMailSupervisor(deps) {
|
|
|
368
385
|
scheduleRenew(account, state, generation);
|
|
369
386
|
}
|
|
370
387
|
}
|
|
371
|
-
// kumiko-lint-ignore complexity-budget yield-point stale-map check after acquire is intentional
|
|
388
|
+
// kumiko-lint-ignore complexity-budget yield-point stale-map check after acquire is intentional
|
|
372
389
|
async function acquireWatchLease(account, state) {
|
|
373
390
|
if (!deps.lock || state.lockToken)
|
|
374
391
|
return "acquired";
|
|
@@ -390,11 +407,11 @@ export function createInboundMailSupervisor(deps) {
|
|
|
390
407
|
}
|
|
391
408
|
// kumiko-lint-ignore complexity-budget watch lifecycle (start/stop/restart) stays cohesive
|
|
392
409
|
async function ensureWatcher(account, plugin) {
|
|
393
|
-
// skip:
|
|
410
|
+
// skip: provider without live push; the reconciliation poll covers the account.
|
|
394
411
|
if (!plugin.watch)
|
|
395
412
|
return;
|
|
396
413
|
const existing = watchers.get(account.id);
|
|
397
|
-
// skip:
|
|
414
|
+
// skip: the watcher is already running, starting, or scheduled for restart.
|
|
398
415
|
if (existing?.stop || existing?.restartTimer || existing?.starting)
|
|
399
416
|
return;
|
|
400
417
|
const state = existing ?? {
|
|
@@ -425,7 +442,8 @@ export function createInboundMailSupervisor(deps) {
|
|
|
425
442
|
}
|
|
426
443
|
const generation = state.generation;
|
|
427
444
|
const scheduleRestart = (err) => {
|
|
428
|
-
// skip:
|
|
445
|
+
// skip: the supervisor stopped or the watcher generation changed; a restart
|
|
446
|
+
// would create a zombie watcher.
|
|
429
447
|
if (!running || state.generation !== generation)
|
|
430
448
|
return;
|
|
431
449
|
state.stop = null;
|
|
@@ -464,7 +482,7 @@ export function createInboundMailSupervisor(deps) {
|
|
|
464
482
|
}, accessToken !== undefined ? { accessToken } : undefined);
|
|
465
483
|
if (state.generation !== generation || !running) {
|
|
466
484
|
await stop();
|
|
467
|
-
// skip: stop()
|
|
485
|
+
// skip: stop() ran while connecting; the watcher was torn down right away.
|
|
468
486
|
return;
|
|
469
487
|
}
|
|
470
488
|
state.stop = stop;
|
|
@@ -492,7 +510,7 @@ export function createInboundMailSupervisor(deps) {
|
|
|
492
510
|
}
|
|
493
511
|
async function stopWatcher(accountId) {
|
|
494
512
|
const state = watchers.get(accountId);
|
|
495
|
-
// skip:
|
|
513
|
+
// skip: no watcher state for this account; it is already torn down.
|
|
496
514
|
if (!state)
|
|
497
515
|
return;
|
|
498
516
|
state.generation += 1;
|
|
@@ -533,7 +551,7 @@ export function createInboundMailSupervisor(deps) {
|
|
|
533
551
|
// Lifecycle.
|
|
534
552
|
// ---------------------------------------------------------------
|
|
535
553
|
function scheduleNextPoll() {
|
|
536
|
-
// skip:
|
|
554
|
+
// skip: the supervisor is stopped; do not schedule another poll tick.
|
|
537
555
|
if (!running)
|
|
538
556
|
return;
|
|
539
557
|
pollTimer = setTimeout(() => {
|
|
@@ -548,7 +566,7 @@ export function createInboundMailSupervisor(deps) {
|
|
|
548
566
|
}
|
|
549
567
|
return {
|
|
550
568
|
async start() {
|
|
551
|
-
// skip:
|
|
569
|
+
// skip: already started; start() is idempotent.
|
|
552
570
|
if (running)
|
|
553
571
|
return;
|
|
554
572
|
running = true;
|
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
// Connection
|
|
2
|
-
// (inboundCredentialSecretKey(accountId)
|
|
1
|
+
// Connection document stored in the per-account secret slot
|
|
2
|
+
// (inboundCredentialSecretKey(accountId)).
|
|
3
3
|
//
|
|
4
|
-
// **
|
|
5
|
-
// mail-transport-smtp (
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
//
|
|
4
|
+
// **Why JSON in the secret instead of tenant config keys:** unlike
|
|
5
|
+
// mail-transport-smtp (one SMTP configuration per tenant), inbound mail
|
|
6
|
+
// supports multiple accounts per tenant with different hosts, which
|
|
7
|
+
// per-tenant config keys cannot represent. Host, port, and user belong
|
|
8
|
+
// with the password in one connection document; the slot is encrypted
|
|
9
|
+
// at rest.
|
|
10
10
|
//
|
|
11
|
-
//
|
|
11
|
+
// The account's authMethod determines the interpretation:
|
|
12
12
|
// password → { host, port, secure, user, password }
|
|
13
|
-
// xoauth2 → { host, port, secure, user, accessToken } — V1
|
|
14
|
-
//
|
|
15
|
-
//
|
|
16
|
-
//
|
|
13
|
+
// xoauth2 → { host, port, secure, user, accessToken } — V1 fallback:
|
|
14
|
+
// OAuth providers (M365/Gmail) handle token acquisition and
|
|
15
|
+
// refresh; the imap provider only consumes a valid access
|
|
16
|
+
// token from the slot.
|
|
17
17
|
import * as z from "zod";
|
|
18
18
|
export const imapCredentialDocumentSchema = z.object({
|
|
19
19
|
host: z.string().min(1).max(255),
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { type InboundMailProviderPlugin } from "@cosmicdrift/kumiko-bundled-features/inbound-mail-foundation";
|
|
2
2
|
export declare const IMAP_PROVIDER_KEY = "imap";
|
|
3
3
|
export { setImapMailHostLookup } from "./imap-client.ts";
|
|
4
|
-
/**
|
|
5
|
-
*
|
|
4
|
+
/** Exported for the live test (imap-live.integration.test.ts) —
|
|
5
|
+
* applications use the feature, never the plugin directly. */
|
|
6
6
|
export declare const imapInboundMailPlugin: InboundMailProviderPlugin;
|
|
7
7
|
export declare function createInboundProviderImapFeature(): import("@cosmicdrift/kumiko-types/feature").FeatureDefinition & {
|
|
8
8
|
readonly exports: void;
|
|
@@ -1,27 +1,27 @@
|
|
|
1
1
|
// kumiko-feature-version: 1
|
|
2
2
|
//
|
|
3
|
-
// inbound-provider-imap — IMAP
|
|
4
|
-
// foundation
|
|
5
|
-
// Strato, GMX/Web.de, mailbox.org, Hetzner, all-inkl) via
|
|
6
|
-
//
|
|
7
|
-
// M365
|
|
8
|
-
//
|
|
3
|
+
// inbound-provider-imap — IMAP implementation of the inbound-mail-
|
|
4
|
+
// foundation plugin API. Covers the DACH long tail (IONOS, Telekom,
|
|
5
|
+
// Strato, GMX/Web.de, mailbox.org, Hetzner, all-inkl) via password/
|
|
6
|
+
// app-password authentication, without OAuth. XOAUTH2 is available as
|
|
7
|
+
// a fallback for M365/Gmail accounts (access token from the secret slot;
|
|
8
|
+
// token refresh is handled by the OAuth providers).
|
|
9
9
|
//
|
|
10
|
-
// **
|
|
11
|
-
// 1. Plugin
|
|
10
|
+
// **What this feature provides:**
|
|
11
|
+
// 1. Plugin registration via r.useExtension("inboundMailProvider",
|
|
12
12
|
// "imap", { verify, fetch, watch }).
|
|
13
|
-
// 2. verify: connect+logout
|
|
14
|
-
// 3. fetch:
|
|
15
|
-
// UIDVALIDITY
|
|
16
|
-
//
|
|
17
|
-
// SEARCH since=backfillWindowDays.
|
|
18
|
-
// 4. watch: IMAP IDLE via imapflow — 'exists'
|
|
19
|
-
//
|
|
20
|
-
//
|
|
13
|
+
// 2. verify: connect+logout with typed error mapping.
|
|
14
|
+
// 3. fetch: incremental sync using a UIDVALIDITY:lastUid cursor —
|
|
15
|
+
// a UIDVALIDITY change throws InboundCursorInvalidError (the
|
|
16
|
+
// foundation resets and resyncs within the backfill window). Initial
|
|
17
|
+
// population uses SEARCH since=backfillWindowDays.
|
|
18
|
+
// 4. watch: IMAP IDLE via imapflow — the 'exists' event triggers fetching
|
|
19
|
+
// new UIDs and then onMessages; connection loss triggers onError (the
|
|
20
|
+
// supervisor restarts with backoff; the provider does not reconnect).
|
|
21
21
|
//
|
|
22
|
-
// Credentials: JSON
|
|
23
|
-
// (credential-document.ts)
|
|
24
|
-
//
|
|
22
|
+
// Credentials: JSON document in the per-account secret slot
|
|
23
|
+
// (credential-document.ts), not tenant configuration, because one tenant
|
|
24
|
+
// can have multiple accounts with different hosts.
|
|
25
25
|
import { mailAllowedPrivateHostsEnvSchema } from "@cosmicdrift/kumiko-bundled-features/foundation-shared";
|
|
26
26
|
import { INBOUND_MAIL_PROVIDER_EXTENSION, InboundAuthError, inboundCredentialSecretKey, } from "@cosmicdrift/kumiko-bundled-features/inbound-mail-foundation";
|
|
27
27
|
import { requireSecretsContext } from "@cosmicdrift/kumiko-bundled-features/secrets";
|
|
@@ -63,18 +63,18 @@ async function fetchMessages(ctx, account, cursor, opts) {
|
|
|
63
63
|
const serverUidValidity = String(mailbox.uidValidity);
|
|
64
64
|
const parsedCursor = parseImapCursor(cursor);
|
|
65
65
|
assertUidValidity(parsedCursor, serverUidValidity);
|
|
66
|
-
// UID
|
|
67
|
-
//
|
|
66
|
+
// Determine the UID set: incrementally from lastUid+1, or use a backfill
|
|
67
|
+
// via SEARCH since (the window limits the initial population).
|
|
68
68
|
let uids;
|
|
69
69
|
if (parsedCursor) {
|
|
70
70
|
const found = await client.search({ uid: `${parsedCursor.lastUid + 1}:*` }, { uid: true });
|
|
71
|
-
// `N
|
|
72
|
-
//
|
|
71
|
+
// `N:*` gotcha: when N exceeds the highest UID, IMAP still returns the
|
|
72
|
+
// last message, so filter it out.
|
|
73
73
|
uids = (found || []).filter((uid) => uid > parsedCursor.lastUid);
|
|
74
74
|
}
|
|
75
75
|
else {
|
|
76
76
|
const since = Temporal.Now.instant().subtract({ hours: opts.backfillWindowDays * 24 });
|
|
77
|
-
// imapflow
|
|
77
|
+
// imapflow API boundary: search() requires a JS Date.
|
|
78
78
|
uids = (await client.search({ since: instantToLegacyDate(since) }, { uid: true })) || [];
|
|
79
79
|
}
|
|
80
80
|
uids.sort((a, b) => a - b);
|
|
@@ -111,8 +111,8 @@ async function fetchMessages(ctx, account, cursor, opts) {
|
|
|
111
111
|
}
|
|
112
112
|
}
|
|
113
113
|
// =============================================================================
|
|
114
|
-
// watch — IMAP IDLE (imapflow
|
|
115
|
-
//
|
|
114
|
+
// watch — IMAP IDLE (imapflow idles automatically while the mailbox is open
|
|
115
|
+
// and emits 'exists' for new messages).
|
|
116
116
|
// =============================================================================
|
|
117
117
|
async function watchMailbox(ctx, account, handlers) {
|
|
118
118
|
const doc = await readCredentialDocument(ctx, account);
|
|
@@ -122,13 +122,14 @@ async function watchMailbox(ctx, account, handlers) {
|
|
|
122
122
|
await client.connect();
|
|
123
123
|
const mailbox = (await client.mailboxOpen(IMAP_MAILBOX));
|
|
124
124
|
const uidValidity = String(mailbox.uidValidity);
|
|
125
|
-
// uidNext
|
|
125
|
+
// uidNext is the next UID to be assigned, so everything from here is
|
|
126
|
+
// "new".
|
|
126
127
|
let nextUid = Number(mailbox.uidNext ?? 1);
|
|
127
128
|
const drainNew = async () => {
|
|
128
129
|
const messages = [];
|
|
129
130
|
let maxSeen = nextUid - 1;
|
|
130
131
|
for await (const msg of client.fetch(`${nextUid}:*`, { uid: true, internalDate: true, source: true }, { uid: true })) {
|
|
131
|
-
// `N
|
|
132
|
+
// `N:*` gotcha (see fetch): filter out the previous last message.
|
|
132
133
|
if (msg.uid < nextUid || !msg.source)
|
|
133
134
|
continue;
|
|
134
135
|
messages.push(await toRawInboundMessage({
|
|
@@ -145,7 +146,7 @@ async function watchMailbox(ctx, account, handlers) {
|
|
|
145
146
|
await handlers.onMessages(messages);
|
|
146
147
|
};
|
|
147
148
|
client.on("exists", () => {
|
|
148
|
-
// skip:
|
|
149
|
+
// skip: ignore delayed exists events after the watcher has stopped.
|
|
149
150
|
if (stopped)
|
|
150
151
|
return;
|
|
151
152
|
void drainNew().catch((err) => {
|
|
@@ -154,7 +155,7 @@ async function watchMailbox(ctx, account, handlers) {
|
|
|
154
155
|
});
|
|
155
156
|
});
|
|
156
157
|
const die = (err) => {
|
|
157
|
-
// skip:
|
|
158
|
+
// skip: already stopped or terminated; fire onError only once.
|
|
158
159
|
if (stopped)
|
|
159
160
|
return;
|
|
160
161
|
stopped = true;
|
|
@@ -162,10 +163,10 @@ async function watchMailbox(ctx, account, handlers) {
|
|
|
162
163
|
};
|
|
163
164
|
client.on("error", die);
|
|
164
165
|
client.on("close", () => die(new Error("connection closed")));
|
|
165
|
-
// IDLE
|
|
166
|
-
// (
|
|
167
|
-
//
|
|
168
|
-
//
|
|
166
|
+
// IDLE loop: 'exists' fires ONLY while client.idle() is running
|
|
167
|
+
// (verified empirically against greenmail). Each intervening command
|
|
168
|
+
// (drainNew-fetch) ends idle(), so the loop re-enters idle() until
|
|
169
|
+
// stop() closes the connection.
|
|
169
170
|
void (async () => {
|
|
170
171
|
while (!stopped) {
|
|
171
172
|
try {
|
|
@@ -174,7 +175,8 @@ async function watchMailbox(ctx, account, handlers) {
|
|
|
174
175
|
catch (err) {
|
|
175
176
|
if (!stopped)
|
|
176
177
|
die(err);
|
|
177
|
-
// skip: idle
|
|
178
|
+
// skip: the idle loop ends; die() has informed the supervisor (or stop()
|
|
179
|
+
// was the cause).
|
|
178
180
|
return;
|
|
179
181
|
}
|
|
180
182
|
}
|
|
@@ -195,8 +197,8 @@ async function watchMailbox(ctx, account, handlers) {
|
|
|
195
197
|
// =============================================================================
|
|
196
198
|
// Plugin + Feature-definition
|
|
197
199
|
// =============================================================================
|
|
198
|
-
/**
|
|
199
|
-
*
|
|
200
|
+
/** Exported for the live test (imap-live.integration.test.ts) —
|
|
201
|
+
* applications use the feature, never the plugin directly. */
|
|
200
202
|
export const imapInboundMailPlugin = {
|
|
201
203
|
verify: async (ctx, account) => {
|
|
202
204
|
const doc = await readCredentialDocument(ctx, account);
|
|
@@ -213,9 +215,9 @@ export const imapInboundMailPlugin = {
|
|
|
213
215
|
},
|
|
214
216
|
fetch: fetchMessages,
|
|
215
217
|
watch: watchMailbox,
|
|
216
|
-
//
|
|
217
|
-
//
|
|
218
|
-
//
|
|
218
|
+
// No oauth block: password authentication runs through the credential
|
|
219
|
+
// form (connect-account + Secret-Write); XOAUTH2 token flows belong to
|
|
220
|
+
// the OAuth providers (M365/Gmail).
|
|
219
221
|
};
|
|
220
222
|
export function createInboundProviderImapFeature() {
|
|
221
223
|
return defineFeature(FEATURE_NAME, (r) => {
|
|
@@ -13,23 +13,24 @@ export type ImapCursor = {
|
|
|
13
13
|
readonly lastUid: number;
|
|
14
14
|
};
|
|
15
15
|
export declare function parseImapCursor(cursor: SyncCursorPayload | null): ImapCursor | null;
|
|
16
|
-
/**
|
|
17
|
-
*
|
|
18
|
-
*
|
|
16
|
+
/** Throws InboundCursorInvalidError when UIDVALIDITY changes; the
|
|
17
|
+
* foundation resets the cursor and performs a full resync within the
|
|
18
|
+
* backfill window (deduplication catches duplicates). */
|
|
19
19
|
export declare function assertUidValidity(cursor: ImapCursor | null, serverUidValidity: string): void;
|
|
20
|
-
/** References
|
|
21
|
-
* | undefined;
|
|
20
|
+
/** Normalizes the References chain: mailparser returns string | string[]
|
|
21
|
+
* | undefined; when References is missing, In-Reply-To provides the thread
|
|
22
|
+
* anchor. */
|
|
22
23
|
export declare function normalizeReferences(parsed: {
|
|
23
24
|
references?: string | string[];
|
|
24
25
|
inReplyTo?: string;
|
|
25
26
|
}): string[];
|
|
26
|
-
/** imapflow
|
|
27
|
-
*
|
|
28
|
-
* no-date-api)
|
|
29
|
-
* Date
|
|
27
|
+
/** imapflow provides internalDate as either a Date or string depending on
|
|
28
|
+
* the code path. The string form is deliberately discarded (no date parsing
|
|
29
|
+
* in feature code, no-date-api); toRawInboundMessage then falls back to the
|
|
30
|
+
* mailparser Date header, which is always a real Date. */
|
|
30
31
|
export declare function coerceDate(d: Date | string | undefined): Date | undefined;
|
|
31
|
-
/** providerMessageId: UID
|
|
32
|
-
*
|
|
32
|
+
/** providerMessageId: a UID is unique only within a UIDVALIDITY; together,
|
|
33
|
+
* they form the stable idempotency anchor. */
|
|
33
34
|
export declare function buildProviderMessageId(uidValidity: string, uid: number): string;
|
|
34
35
|
export declare function toRawInboundMessage(args: {
|
|
35
36
|
readonly source: Uint8Array;
|