@cosmicdrift/kumiko-bundled-features 0.392.2 → 0.394.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/dist/account-security/feature.d.ts +2 -0
- package/dist/account-security/feature.js +3 -1
- package/dist/audit/event-classification.js +1 -0
- package/dist/auth-email-password/handlers/change-password.write.d.ts +1 -1
- package/dist/auth-email-password/handlers/confirm-account-unlock.write.d.ts +1 -1
- package/dist/auth-email-password/handlers/invite-accept-with-login.write.d.ts +1 -1
- package/dist/auth-email-password/handlers/invite-accept.write.d.ts +1 -1
- package/dist/auth-email-password/handlers/invite-create.write.d.ts +2 -2
- package/dist/auth-email-password/handlers/invite-signup-complete.write.d.ts +1 -1
- package/dist/auth-email-password/handlers/login.write.d.ts +1 -1
- package/dist/auth-email-password/handlers/logout.write.d.ts +1 -1
- package/dist/auth-email-password/handlers/request-account-unlock.write.d.ts +1 -1
- package/dist/auth-email-password/handlers/request-email-verification.write.d.ts +1 -1
- package/dist/auth-email-password/handlers/request-password-reset.write.d.ts +1 -1
- package/dist/auth-email-password/handlers/reset-password.write.d.ts +1 -1
- package/dist/auth-email-password/handlers/signup-confirm.write.d.ts +1 -1
- package/dist/auth-email-password/handlers/signup-request.write.d.ts +1 -1
- package/dist/auth-email-password/handlers/switch-tenant-mfa-gate.write.d.ts +1 -1
- package/dist/auth-email-password/handlers/token-request-handler.d.ts +1 -1
- package/dist/auth-email-password/handlers/verify-email.write.d.ts +1 -1
- package/dist/auth-email-password/web/auth-client.d.ts +3 -7
- package/dist/auth-email-password/web/auth-client.js +3 -24
- package/dist/auth-email-password/web/auth-gate.d.ts +2 -4
- package/dist/auth-email-password/web/auth-redirect.d.ts +2 -2
- package/dist/auth-email-password/web/auth-redirect.js +3 -12
- package/dist/auth-email-password/web/index.d.ts +2 -1
- package/dist/auth-email-password/web/index.js +1 -0
- package/dist/auth-email-password/web/login-failure.d.ts +9 -0
- package/dist/auth-email-password/web/login-failure.js +32 -0
- package/dist/auth-email-password/web/login-url.d.ts +5 -0
- package/dist/auth-email-password/web/login-url.js +13 -0
- package/dist/auth-email-password/web/static-login.d.ts +42 -0
- package/dist/auth-email-password/web/static-login.js +122 -0
- package/dist/auth-mfa/handlers/disable.write.d.ts +1 -1
- package/dist/auth-mfa/handlers/enable-confirm-preauth.write.d.ts +1 -1
- package/dist/auth-mfa/handlers/enable-confirm.write.d.ts +1 -1
- package/dist/auth-mfa/handlers/enable-start-preauth.write.d.ts +1 -1
- package/dist/auth-mfa/handlers/enable-start.write.d.ts +1 -1
- package/dist/auth-mfa/handlers/regenerate-recovery.write.d.ts +1 -1
- package/dist/auth-mfa/handlers/verify.write.d.ts +1 -1
- package/dist/auth-mfa/web/mfa-client.js +4 -43
- package/dist/billing-foundation/checkout-core.d.ts +2 -1
- package/dist/billing-foundation/checkout-core.js +2 -11
- package/dist/billing-foundation/events.d.ts +1 -0
- package/dist/billing-foundation/events.js +2 -0
- package/dist/billing-foundation/feature.js +1 -1
- package/dist/billing-foundation/handlers/create-checkout-session.write.js +9 -2
- package/dist/billing-foundation/handlers/process-payment-event.write.d.ts +1 -0
- package/dist/billing-foundation/handlers/process-payment-event.write.js +2 -0
- package/dist/billing-foundation/index.d.ts +1 -1
- package/dist/billing-foundation/one-off-checkout-gate.d.ts +9 -0
- package/dist/billing-foundation/one-off-checkout-gate.js +30 -0
- package/dist/billing-foundation/one-off-customer.d.ts +6 -0
- package/dist/billing-foundation/one-off-customer.js +12 -0
- package/dist/billing-foundation/plan-catalog.js +1 -0
- package/dist/billing-foundation/types.d.ts +25 -0
- package/dist/billing-foundation/web/billing-plans-panel.js +1 -0
- package/dist/billing-foundation/web/plan-switch-confirm-dialog.js +7 -3
- package/dist/billing-foundation/web/plan-switch-recurring.d.ts +16 -0
- package/dist/billing-foundation/web/plan-switch-recurring.js +10 -0
- package/dist/billing-foundation/webhook-handler.js +1 -0
- package/dist/cap-overview/handlers/caps-usage.query.js +3 -3
- package/dist/cap-overview/types.d.ts +2 -0
- package/dist/channel-in-app/handlers/mark-all-read.write.d.ts +1 -1
- package/dist/channel-in-app/handlers/mark-read.write.d.ts +1 -1
- package/dist/compliance-profiles/handlers/set-profile.write.d.ts +1 -1
- package/dist/compliance-profiles/web/compliance-profile-catalog.js +8 -1
- package/dist/config/handlers/reset.write.d.ts +1 -1
- package/dist/config/handlers/set.write.d.ts +1 -1
- package/dist/crypto-shredding/handlers/forget-subject.write.d.ts +1 -1
- package/dist/delivery/handlers/resubscribe-address.write.d.ts +1 -1
- package/dist/delivery/handlers/resubscribe-user.write.d.ts +1 -1
- package/dist/delivery/handlers/set-preference.write.d.ts +1 -1
- package/dist/delivery/handlers/unsubscribe-address.write.d.ts +1 -1
- package/dist/delivery/handlers/unsubscribe-user.write.d.ts +1 -1
- package/dist/feature-toggles/handlers/set.write.d.ts +1 -1
- package/dist/file-foundation/read-file-ref-content.d.ts +2 -0
- package/dist/file-foundation/read-file-ref-content.js +9 -3
- package/dist/form-draft/handlers/discard.write.d.ts +1 -1
- package/dist/form-draft/handlers/save.write.d.ts +1 -1
- package/dist/inbound-mail-foundation/account-health.d.ts +17 -0
- package/dist/inbound-mail-foundation/account-health.js +101 -0
- package/dist/inbound-mail-foundation/account-poll-schedule.d.ts +19 -0
- package/dist/inbound-mail-foundation/account-poll-schedule.js +44 -0
- package/dist/inbound-mail-foundation/account-poll.d.ts +24 -0
- package/dist/inbound-mail-foundation/account-poll.js +157 -0
- package/dist/inbound-mail-foundation/account-record.d.ts +1 -0
- package/dist/inbound-mail-foundation/account-record.js +1 -0
- package/dist/inbound-mail-foundation/account-wake.d.ts +3 -0
- package/dist/inbound-mail-foundation/account-wake.js +17 -0
- package/dist/inbound-mail-foundation/connect-callback-verify.d.ts +10 -0
- package/dist/inbound-mail-foundation/connect-callback-verify.js +31 -0
- package/dist/inbound-mail-foundation/connect-route-responses.d.ts +13 -0
- package/dist/inbound-mail-foundation/connect-route-responses.js +16 -0
- package/dist/inbound-mail-foundation/connect-routes.js +52 -33
- package/dist/inbound-mail-foundation/constants.d.ts +50 -2
- package/dist/inbound-mail-foundation/constants.js +53 -3
- package/dist/inbound-mail-foundation/content-refetch.d.ts +14 -0
- package/dist/inbound-mail-foundation/content-refetch.js +93 -0
- package/dist/inbound-mail-foundation/describe-error.d.ts +1 -0
- package/dist/inbound-mail-foundation/describe-error.js +5 -0
- package/dist/inbound-mail-foundation/entities.d.ts +26 -0
- package/dist/inbound-mail-foundation/entities.js +43 -3
- package/dist/inbound-mail-foundation/events.d.ts +97 -0
- package/dist/inbound-mail-foundation/events.js +57 -2
- package/dist/inbound-mail-foundation/feature.d.ts +5 -2
- package/dist/inbound-mail-foundation/feature.js +122 -106
- package/dist/inbound-mail-foundation/file-storage-failure.d.ts +8 -0
- package/dist/inbound-mail-foundation/file-storage-failure.js +19 -0
- package/dist/inbound-mail-foundation/handlers/account-address.d.ts +16 -0
- package/dist/inbound-mail-foundation/handlers/account-address.js +51 -0
- package/dist/inbound-mail-foundation/handlers/acknowledge-quarantine.write.d.ts +8 -0
- package/dist/inbound-mail-foundation/handlers/acknowledge-quarantine.write.js +39 -0
- package/dist/inbound-mail-foundation/handlers/attach-message-content.write.d.ts +60 -0
- package/dist/inbound-mail-foundation/handlers/attach-message-content.write.js +128 -0
- package/dist/inbound-mail-foundation/handlers/connect-account.write.d.ts +3 -2
- package/dist/inbound-mail-foundation/handlers/connect-account.write.js +97 -56
- package/dist/inbound-mail-foundation/handlers/disconnect-account.write.d.ts +2 -1
- package/dist/inbound-mail-foundation/handlers/disconnect-account.write.js +55 -42
- package/dist/inbound-mail-foundation/handlers/ingest-message-prepare.d.ts +26 -0
- package/dist/inbound-mail-foundation/handlers/ingest-message-prepare.js +131 -0
- package/dist/inbound-mail-foundation/handlers/ingest-message-schema.d.ts +64 -0
- package/dist/inbound-mail-foundation/handlers/ingest-message-schema.js +39 -0
- package/dist/inbound-mail-foundation/handlers/ingest-message.write.d.ts +74 -21
- package/dist/inbound-mail-foundation/handlers/ingest-message.write.js +57 -134
- package/dist/inbound-mail-foundation/handlers/list-accounts.query.d.ts +2 -1
- package/dist/inbound-mail-foundation/handlers/list-accounts.query.js +60 -26
- package/dist/inbound-mail-foundation/handlers/list-messages.query.d.ts +2 -1
- package/dist/inbound-mail-foundation/handlers/list-messages.query.js +43 -29
- package/dist/inbound-mail-foundation/handlers/list-quarantine.query.d.ts +3 -0
- package/dist/inbound-mail-foundation/handlers/list-quarantine.query.js +75 -0
- package/dist/inbound-mail-foundation/handlers/mark-credential-stored.write.d.ts +7 -0
- package/dist/inbound-mail-foundation/handlers/mark-credential-stored.write.js +38 -0
- package/dist/inbound-mail-foundation/handlers/message-content.d.ts +70 -0
- package/dist/inbound-mail-foundation/handlers/message-content.js +137 -0
- package/dist/inbound-mail-foundation/handlers/message-content.query.d.ts +19 -0
- package/dist/inbound-mail-foundation/handlers/message-content.query.js +59 -0
- package/dist/inbound-mail-foundation/handlers/message-detail.query.d.ts +3 -0
- package/dist/inbound-mail-foundation/handlers/message-detail.query.js +23 -0
- package/dist/inbound-mail-foundation/handlers/reactivate-account.write.d.ts +8 -0
- package/dist/inbound-mail-foundation/handlers/reactivate-account.write.js +84 -0
- package/dist/inbound-mail-foundation/handlers/retry-quarantined-message.write.d.ts +8 -0
- package/dist/inbound-mail-foundation/handlers/retry-quarantined-message.write.js +34 -0
- package/dist/inbound-mail-foundation/handlers/scope-visibility.d.ts +10 -2
- package/dist/inbound-mail-foundation/handlers/scope-visibility.js +27 -8
- package/dist/inbound-mail-foundation/handlers/set-trusted-authserv-id.write.d.ts +13 -0
- package/dist/inbound-mail-foundation/handlers/set-trusted-authserv-id.write.js +54 -0
- package/dist/inbound-mail-foundation/handlers/thread-rollup.d.ts +24 -0
- package/dist/inbound-mail-foundation/handlers/thread-rollup.js +98 -0
- package/dist/inbound-mail-foundation/handlers/trusted-authserv-id.d.ts +3 -0
- package/dist/inbound-mail-foundation/handlers/trusted-authserv-id.js +3 -0
- package/dist/inbound-mail-foundation/handlers/update-account.write.d.ts +13 -3
- package/dist/inbound-mail-foundation/handlers/update-account.write.js +62 -46
- package/dist/inbound-mail-foundation/i18n.js +72 -2
- package/dist/inbound-mail-foundation/inbound-oauth-flow.d.ts +43 -0
- package/dist/inbound-mail-foundation/inbound-oauth-flow.js +1 -0
- package/dist/inbound-mail-foundation/index.d.ts +19 -6
- package/dist/inbound-mail-foundation/index.js +17 -6
- package/dist/inbound-mail-foundation/ingest-failures.d.ts +77 -0
- package/dist/inbound-mail-foundation/ingest-failures.js +79 -0
- package/dist/inbound-mail-foundation/ingest-payload.d.ts +7 -0
- package/dist/inbound-mail-foundation/ingest-payload.js +34 -0
- package/dist/inbound-mail-foundation/mail-roles.d.ts +21 -0
- package/dist/inbound-mail-foundation/mail-roles.js +83 -0
- package/dist/inbound-mail-foundation/normalize-inbound-message.d.ts +17 -0
- package/dist/inbound-mail-foundation/normalize-inbound-message.js +90 -0
- package/dist/inbound-mail-foundation/oauth-access-token.d.ts +3 -1
- package/dist/inbound-mail-foundation/oauth-access-token.js +13 -2
- package/dist/inbound-mail-foundation/outbound-attachment-access.d.ts +5 -0
- package/dist/inbound-mail-foundation/outbound-attachment-access.js +16 -0
- package/dist/inbound-mail-foundation/outbound-attachments.d.ts +18 -0
- package/dist/inbound-mail-foundation/outbound-attachments.js +77 -0
- package/dist/inbound-mail-foundation/outbound-mail.d.ts +15 -1
- package/dist/inbound-mail-foundation/outbound-mail.js +4 -0
- package/dist/inbound-mail-foundation/probe.js +1 -1
- package/dist/inbound-mail-foundation/projection.d.ts +28 -0
- package/dist/inbound-mail-foundation/projection.js +25 -3
- package/dist/inbound-mail-foundation/provider-errors.d.ts +28 -0
- package/dist/inbound-mail-foundation/provider-errors.js +66 -0
- package/dist/inbound-mail-foundation/quarantine-entities.d.ts +61 -0
- package/dist/inbound-mail-foundation/quarantine-entities.js +47 -0
- package/dist/inbound-mail-foundation/quarantine-header-import.d.ts +9 -0
- package/dist/inbound-mail-foundation/quarantine-header-import.js +53 -0
- package/dist/inbound-mail-foundation/quarantine-retry.d.ts +13 -0
- package/dist/inbound-mail-foundation/quarantine-retry.js +97 -0
- package/dist/inbound-mail-foundation/quarantine-screens.d.ts +4 -0
- package/dist/inbound-mail-foundation/quarantine-screens.js +57 -0
- package/dist/inbound-mail-foundation/quarantine.d.ts +13 -0
- package/dist/inbound-mail-foundation/quarantine.js +46 -0
- package/dist/inbound-mail-foundation/retention-job.d.ts +2 -0
- package/dist/inbound-mail-foundation/retention-job.js +62 -0
- package/dist/inbound-mail-foundation/retention-sweep.d.ts +4 -0
- package/dist/inbound-mail-foundation/retention-sweep.js +35 -8
- package/dist/inbound-mail-foundation/screens.d.ts +14 -2
- package/dist/inbound-mail-foundation/screens.js +217 -79
- package/dist/inbound-mail-foundation/send-from-account.d.ts +11 -1
- package/dist/inbound-mail-foundation/send-from-account.js +19 -2
- package/dist/inbound-mail-foundation/sender-auth.d.ts +63 -0
- package/dist/inbound-mail-foundation/sender-auth.js +198 -0
- package/dist/inbound-mail-foundation/supervisor-ingest.d.ts +43 -0
- package/dist/inbound-mail-foundation/supervisor-ingest.js +195 -0
- package/dist/inbound-mail-foundation/sync-account-now.d.ts +22 -0
- package/dist/inbound-mail-foundation/sync-account-now.js +29 -0
- package/dist/inbound-mail-foundation/sync-cursor-store.d.ts +9 -0
- package/dist/inbound-mail-foundation/sync-cursor-store.js +54 -0
- package/dist/inbound-mail-foundation/syncable-accounts.d.ts +16 -0
- package/dist/inbound-mail-foundation/syncable-accounts.js +79 -0
- package/dist/inbound-mail-foundation/tenant-destroy-hook.js +5 -1
- package/dist/inbound-mail-foundation/types.d.ts +61 -62
- package/dist/inbound-mail-foundation/types.js +0 -54
- package/dist/inbound-mail-foundation/wake-consumer.d.ts +2 -0
- package/dist/inbound-mail-foundation/wake-consumer.js +30 -0
- package/dist/inbound-mail-foundation/watch-catch-up.d.ts +19 -0
- package/dist/inbound-mail-foundation/watch-catch-up.js +33 -0
- package/dist/inbound-mail-foundation/watch-lease.d.ts +15 -0
- package/dist/inbound-mail-foundation/watch-lease.js +81 -0
- package/dist/inbound-mail-foundation/watch-supervisor-types.d.ts +83 -0
- package/dist/inbound-mail-foundation/watch-supervisor-types.js +1 -0
- package/dist/inbound-mail-foundation/watch-supervisor.d.ts +1 -53
- package/dist/inbound-mail-foundation/watch-supervisor.js +123 -290
- package/dist/inbound-mail-foundation/web/client-plugin.d.ts +14 -0
- package/dist/inbound-mail-foundation/web/client-plugin.js +40 -0
- package/dist/inbound-mail-foundation/web/constants.d.ts +5 -0
- package/dist/inbound-mail-foundation/web/constants.js +6 -0
- package/dist/inbound-mail-foundation/web/index.d.ts +1 -0
- package/dist/inbound-mail-foundation/web/index.js +1 -0
- package/dist/inbound-provider-imap/connect-mailbox.d.ts +28 -5
- package/dist/inbound-provider-imap/connect-mailbox.js +91 -41
- package/dist/inbound-provider-imap/connect-my-mailbox.d.ts +13 -0
- package/dist/inbound-provider-imap/connect-my-mailbox.js +25 -0
- package/dist/inbound-provider-imap/constants.d.ts +12 -1
- package/dist/inbound-provider-imap/constants.js +12 -1
- package/dist/inbound-provider-imap/credential-document.js +2 -2
- package/dist/inbound-provider-imap/download-batch.d.ts +6 -0
- package/dist/inbound-provider-imap/download-batch.js +24 -0
- package/dist/inbound-provider-imap/feature.d.ts +2 -2
- package/dist/inbound-provider-imap/feature.js +49 -32
- package/dist/inbound-provider-imap/fetch-content.d.ts +4 -0
- package/dist/inbound-provider-imap/fetch-content.js +68 -0
- package/dist/inbound-provider-imap/i18n.js +18 -2
- package/dist/inbound-provider-imap/imap-client.d.ts +27 -23
- package/dist/inbound-provider-imap/imap-client.js +30 -68
- package/dist/inbound-provider-imap/index.d.ts +2 -1
- package/dist/inbound-provider-imap/index.js +2 -1
- package/dist/inbound-provider-imap/mime-content.d.ts +11 -0
- package/dist/inbound-provider-imap/mime-content.js +66 -0
- package/dist/inbound-provider-imap/parse-message.d.ts +35 -0
- package/dist/inbound-provider-imap/parse-message.js +113 -0
- package/dist/inbound-provider-imap/reconnect-account.d.ts +17 -0
- package/dist/inbound-provider-imap/reconnect-account.js +18 -0
- package/dist/inbound-provider-imap/reconnect-mailbox.d.ts +14 -0
- package/dist/inbound-provider-imap/reconnect-mailbox.js +71 -0
- package/dist/inbound-provider-imap/reconnect-prefill.query.d.ts +3 -0
- package/dist/inbound-provider-imap/reconnect-prefill.query.js +34 -0
- package/dist/inbound-provider-imap/screens.d.ts +6 -1
- package/dist/inbound-provider-imap/screens.js +174 -41
- package/dist/inbound-provider-imap/send-mail.d.ts +2 -2
- package/dist/inbound-provider-imap/send-mail.js +8 -1
- package/dist/inbound-provider-imap/sender-auth-headers.d.ts +3 -0
- package/dist/inbound-provider-imap/sender-auth-headers.js +18 -0
- package/dist/inbound-provider-inmemory/feature.d.ts +15 -0
- package/dist/inbound-provider-inmemory/feature.js +57 -2
- package/dist/inbound-provider-inmemory/index.d.ts +1 -1
- package/dist/inbound-provider-inmemory/index.js +1 -1
- package/dist/jobs/handlers/consumer.write.d.ts +4 -4
- package/dist/jobs/handlers/retry.write.d.ts +1 -1
- package/dist/jobs/handlers/trigger.write.d.ts +1 -1
- package/dist/managed-pages/handlers/set.write.d.ts +1 -1
- package/dist/managed-pages/web/i18n.js +1 -0
- package/dist/personal-access-tokens/handlers/create.write.d.ts +1 -1
- package/dist/personal-access-tokens/handlers/revoke.write.d.ts +1 -1
- package/dist/readiness/handlers/run-probes.write.d.ts +1 -1
- package/dist/secrets/handlers/delete.write.d.ts +1 -1
- package/dist/secrets/handlers/set.write.d.ts +1 -1
- package/dist/sessions/handlers/revoke-all-for-user.write.d.ts +1 -1
- package/dist/sessions/handlers/revoke-all-others.write.d.ts +1 -1
- package/dist/sessions/handlers/revoke.write.d.ts +1 -1
- package/dist/subscription-paddle/checkout-config.query.d.ts +3 -0
- package/dist/subscription-paddle/checkout-config.query.js +14 -0
- package/dist/subscription-paddle/checkout-methods.d.ts +6 -0
- package/dist/subscription-paddle/checkout-methods.js +85 -0
- package/dist/subscription-paddle/checkout-page.d.ts +19 -0
- package/dist/subscription-paddle/checkout-page.js +126 -0
- package/dist/subscription-paddle/client.d.ts +24 -0
- package/dist/subscription-paddle/client.js +60 -0
- package/dist/subscription-paddle/constants.d.ts +16 -0
- package/dist/subscription-paddle/constants.js +25 -0
- package/dist/subscription-paddle/feature.d.ts +49 -0
- package/dist/subscription-paddle/feature.js +192 -0
- package/dist/subscription-paddle/index.d.ts +2 -0
- package/dist/subscription-paddle/index.js +4 -0
- package/dist/subscription-paddle/plan-switch-methods.d.ts +6 -0
- package/dist/subscription-paddle/plan-switch-methods.js +114 -0
- package/dist/subscription-paddle/price-methods.d.ts +15 -0
- package/dist/subscription-paddle/price-methods.js +105 -0
- package/dist/subscription-paddle/runtime.d.ts +42 -0
- package/dist/subscription-paddle/runtime.js +109 -0
- package/dist/subscription-paddle/subscription-state.d.ts +34 -0
- package/dist/subscription-paddle/subscription-state.js +48 -0
- package/dist/subscription-paddle/tenant-binding.d.ts +8 -0
- package/dist/subscription-paddle/tenant-binding.js +26 -0
- package/dist/subscription-paddle/verify-webhook.d.ts +4 -0
- package/dist/subscription-paddle/verify-webhook.js +55 -0
- package/dist/subscription-paddle/webhook-events.d.ts +9 -0
- package/dist/subscription-paddle/webhook-events.js +124 -0
- package/dist/template-resolver/handlers/collection-item.query.js +2 -2
- package/dist/template-resolver/handlers/collection-list.query.js +4 -2
- package/dist/template-resolver/handlers/collection-set.write.d.ts +1 -1
- package/dist/template-resolver/handlers/collection-shared.d.ts +11 -0
- package/dist/template-resolver/handlers/collection-shared.js +16 -0
- package/dist/template-resolver/handlers/copy-locale.write.d.ts +1 -1
- package/dist/template-resolver/handlers/discard-draft.write.d.ts +2 -2
- package/dist/template-resolver/handlers/import-bundle-system.write.d.ts +1 -1
- package/dist/template-resolver/handlers/import-bundle.write.d.ts +1 -1
- package/dist/template-resolver/handlers/patch-draft.write.d.ts +1 -1
- package/dist/template-resolver/handlers/reset-to-system.write.d.ts +1 -1
- package/dist/template-resolver/handlers/resource-link-pdf.write.d.ts +1 -1
- package/dist/template-resolver/handlers/resource-remove.write.d.ts +1 -1
- package/dist/template-resolver/handlers/resource-upload.write.d.ts +1 -1
- package/dist/template-resolver/handlers/send-test.write.d.ts +1 -1
- package/dist/template-resolver/handlers/set.write.d.ts +1 -1
- package/dist/template-resolver/handlers/toggle-status.write.d.ts +4 -4
- package/dist/template-resolver/handlers/upsert-system.write.d.ts +1 -1
- package/dist/template-resolver/handlers/upsert-tenant.write.d.ts +1 -1
- package/dist/template-resolver/web/client-plugin.d.ts +4 -0
- package/dist/template-resolver/web/client-plugin.js +134 -52
- package/dist/template-resolver/web/i18n.js +1 -1
- package/dist/tenant/handlers/add-member.write.d.ts +1 -1
- package/dist/tenant/handlers/cancel-invitation.write.d.ts +1 -1
- package/dist/tenant/handlers/create.write.d.ts +1 -1
- package/dist/tenant/handlers/remove-member.write.d.ts +1 -1
- package/dist/tenant/handlers/toggle-enabled.write.d.ts +2 -2
- package/dist/tenant/handlers/update-member-roles.write.d.ts +1 -1
- package/dist/tenant/handlers/update.write.d.ts +1 -1
- package/dist/tenant-handover/handlers/claim.write.d.ts +1 -1
- package/dist/tenant-lifecycle/handlers/cancel-destruction.write.d.ts +1 -1
- package/dist/tenant-lifecycle/handlers/request-destruction.write.d.ts +1 -1
- package/dist/tier-engine/handlers/set-tenant-tier.write.d.ts +1 -1
- package/dist/user/handlers/create.write.d.ts +1 -1
- package/dist/user/handlers/update.write.d.ts +1 -1
- package/dist/user-data-rights/handlers/cancel-deletion.write.d.ts +1 -1
- package/dist/user-data-rights/handlers/confirm-deletion-by-token.write.d.ts +1 -1
- package/dist/user-data-rights/handlers/lift-restriction.write.d.ts +1 -1
- package/dist/user-data-rights/handlers/request-deletion-by-email.write.d.ts +1 -1
- package/dist/user-data-rights/handlers/request-deletion.write.d.ts +1 -1
- package/dist/user-data-rights/handlers/request-export.write.d.ts +1 -1
- package/dist/user-data-rights/handlers/restrict-account.write.d.ts +1 -1
- package/dist/user-data-rights/handlers/run-forget-cleanup.write.d.ts +1 -1
- package/dist/user-data-rights-defaults/hooks/file-ref.userdata-hook.js +2 -1
- package/dist/user-profile/handlers/change-email.write.d.ts +1 -1
- package/dist/waitlist/handlers/export-purge.write.d.ts +2 -2
- package/dist/waitlist/handlers/invite.write.d.ts +1 -1
- package/dist/waitlist/handlers/reject.write.d.ts +1 -1
- package/dist/waitlist/handlers/submit.write.d.ts +1 -1
- package/package.json +33 -17
- package/src/account-security/changes.json +6 -0
- package/src/auth-email-password/changes.json +6 -0
- package/src/billing-foundation/changes.json +30 -0
- package/src/cap-overview/changes.json +6 -0
- package/src/files/changes.json +18 -0
- package/src/inbound-mail-foundation/changes.json +155 -0
- package/src/inbound-provider-imap/changes.json +42 -0
- package/src/jobs/changes.json +18 -0
- package/src/subscription-paddle/changes.json +15 -0
- package/src/template-resolver/changes.json +12 -0
- package/dist/subscription-dodo/client.d.ts +0 -17
- package/dist/subscription-dodo/client.js +0 -31
- package/dist/subscription-dodo/constants.d.ts +0 -12
- package/dist/subscription-dodo/constants.js +0 -19
- package/dist/subscription-dodo/feature.d.ts +0 -37
- package/dist/subscription-dodo/feature.js +0 -144
- package/dist/subscription-dodo/index.d.ts +0 -2
- package/dist/subscription-dodo/index.js +0 -4
- package/dist/subscription-dodo/plugin-methods.d.ts +0 -23
- package/dist/subscription-dodo/plugin-methods.js +0 -260
- package/dist/subscription-dodo/runtime.d.ts +0 -27
- package/dist/subscription-dodo/runtime.js +0 -89
- package/dist/subscription-dodo/verify-webhook.d.ts +0 -37
- package/dist/subscription-dodo/verify-webhook.js +0 -189
- package/src/subscription-dodo/changes.json +0 -14
|
@@ -1,6 +1,9 @@
|
|
|
1
|
+
import { type InboundMailRoles } from "@cosmicdrift/kumiko-bundled-features/inbound-mail-foundation";
|
|
2
|
+
import { type BeforeTransactionResult, type HandlerContext } from "@cosmicdrift/kumiko-framework/engine";
|
|
3
|
+
import type { WriteResult } from "@cosmicdrift/kumiko-types/handlers";
|
|
1
4
|
import * as z from "zod";
|
|
2
5
|
import { type ImapCredentialDocument } from "./credential-document.ts";
|
|
3
|
-
declare const connectMailboxSchema: z.ZodObject<{
|
|
6
|
+
export declare const connectMailboxSchema: z.ZodObject<{
|
|
4
7
|
host: z.ZodString;
|
|
5
8
|
port: z.ZodDefault<z.ZodNumber>;
|
|
6
9
|
user: z.ZodString;
|
|
@@ -9,11 +12,30 @@ declare const connectMailboxSchema: z.ZodObject<{
|
|
|
9
12
|
password: z.ZodString;
|
|
10
13
|
smtpHost: z.ZodOptional<z.ZodNullable<z.ZodUnion<readonly [z.ZodLiteral<"">, z.ZodString]>>>;
|
|
11
14
|
smtpPort: z.ZodNumber;
|
|
15
|
+
trustedAuthservId: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
12
16
|
}, z.core.$strip>;
|
|
13
|
-
type
|
|
17
|
+
type ConnectMailboxLoginFields = Pick<z.infer<typeof connectMailboxSchema>, "host" | "port" | "user" | "password" | "smtpHost" | "smtpPort">;
|
|
18
|
+
export declare const CREDENTIAL_PREVIEW = "IMAP login";
|
|
14
19
|
export declare function deriveSmtpHost(imapHost: string): string;
|
|
15
|
-
export declare function credentialDocumentOf(payload:
|
|
16
|
-
export declare
|
|
20
|
+
export declare function credentialDocumentOf(payload: ConnectMailboxLoginFields): ImapCredentialDocument;
|
|
21
|
+
export declare function checkMailboxLogin(doc: ImapCredentialDocument, log: {
|
|
22
|
+
warn(message: string, data?: Record<string, unknown>): void;
|
|
23
|
+
}): Promise<BeforeTransactionResult<null>>;
|
|
24
|
+
export declare const SECRET_TRANSACTION_REASON = "the credential secret is written on the request transaction so a failed account connect rolls it back too";
|
|
25
|
+
type ConnectedMailbox = {
|
|
26
|
+
readonly displayName: string;
|
|
27
|
+
readonly address: string;
|
|
28
|
+
readonly credentialDocument: ImapCredentialDocument;
|
|
29
|
+
};
|
|
30
|
+
export declare function connectPasswordMailbox(handlerName: string, event: {
|
|
31
|
+
readonly user: {
|
|
32
|
+
readonly id: string;
|
|
33
|
+
readonly tenantId: string;
|
|
34
|
+
};
|
|
35
|
+
}, ctx: HandlerContext, mailbox: ConnectedMailbox, scope: "shared" | "user"): Promise<WriteResult<{
|
|
36
|
+
accountId: string;
|
|
37
|
+
}>>;
|
|
38
|
+
export declare const createConnectMailboxHandler: ({ adminRoles }: InboundMailRoles) => import("@cosmicdrift/kumiko-types/define-handler").WriteHandlerDefinition<"connect-mailbox", z.ZodObject<{
|
|
17
39
|
host: z.ZodString;
|
|
18
40
|
port: z.ZodDefault<z.ZodNumber>;
|
|
19
41
|
user: z.ZodString;
|
|
@@ -22,7 +44,8 @@ export declare const connectMailboxHandler: import("@cosmicdrift/kumiko-types/de
|
|
|
22
44
|
password: z.ZodString;
|
|
23
45
|
smtpHost: z.ZodOptional<z.ZodNullable<z.ZodUnion<readonly [z.ZodLiteral<"">, z.ZodString]>>>;
|
|
24
46
|
smtpPort: z.ZodNumber;
|
|
47
|
+
trustedAuthservId: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
25
48
|
}, z.core.$strip>, {
|
|
26
49
|
accountId: string;
|
|
27
|
-
}, import("@cosmicdrift/kumiko-types/event-type-map").KumikoEventTypeMap, null>;
|
|
50
|
+
}, import("@cosmicdrift/kumiko-types/event-type-map").KumikoEventTypeMap, null, undefined>;
|
|
28
51
|
export {};
|
|
@@ -2,9 +2,10 @@
|
|
|
2
2
|
// login of the outgoing server are checked before the transaction opens; only then the account
|
|
3
3
|
// stream and its credential secret are written, both on the request transaction, so a failure
|
|
4
4
|
// leaves neither behind.
|
|
5
|
-
import { InboundAuthError, InboundMailAuthMethods, InboundMailFoundationHandlers, inboundCredentialSecretKey, } from "@cosmicdrift/kumiko-bundled-features/inbound-mail-foundation";
|
|
5
|
+
import { findMailboxByAddress, InboundAuthError, InboundMailAccountStatuses, InboundMailAuthMethods, InboundMailFoundationHandlers, inboundCredentialSecretKey, } from "@cosmicdrift/kumiko-bundled-features/inbound-mail-foundation";
|
|
6
6
|
import { requireSecretsContext } from "@cosmicdrift/kumiko-bundled-features/secrets";
|
|
7
|
-
import {
|
|
7
|
+
import { ROLES } from "@cosmicdrift/kumiko-framework/auth";
|
|
8
|
+
import { createSystemUser, defineWriteHandler, } from "@cosmicdrift/kumiko-framework/engine";
|
|
8
9
|
import { UnprocessableError, writeFailure } from "@cosmicdrift/kumiko-framework/errors";
|
|
9
10
|
import * as z from "zod";
|
|
10
11
|
import { IMAP_CONNECT_ERRORS, IMAP_PROVIDER_KEY, SMTP_CONNECT_ERRORS } from "./constants.js";
|
|
@@ -14,23 +15,29 @@ import { SmtpFailureError, verifySmtpLogin } from "./smtp-client.js";
|
|
|
14
15
|
// No `secure`: the password never crosses the wire in clear text, so a payload's secure:false is
|
|
15
16
|
// stripped like any unknown key. IMAP uses implicit TLS; SMTP uses implicit TLS on 465 and
|
|
16
17
|
// enforced STARTTLS on every other port.
|
|
17
|
-
const connectMailboxSchema = imapCredentialDocumentSchema
|
|
18
|
+
export const connectMailboxSchema = imapCredentialDocumentSchema
|
|
18
19
|
.pick({ host: true, port: true, user: true })
|
|
19
20
|
.extend({
|
|
20
|
-
displayName: z.string().min(1).max(200),
|
|
21
|
+
displayName: z.string().trim().min(1).max(200),
|
|
21
22
|
address: z.email().max(320),
|
|
22
23
|
password: z.string().min(1).max(1000),
|
|
23
24
|
smtpHost: z.union([z.literal(""), smtpHostSchema]).nullish(),
|
|
24
25
|
smtpPort: z.number().int().min(1).max(65535),
|
|
26
|
+
trustedAuthservId: z.string().trim().max(255).nullish(),
|
|
25
27
|
});
|
|
28
|
+
function isReopenableByThisForm(existing, ownerUserId) {
|
|
29
|
+
return (existing.status === InboundMailAccountStatuses.disconnected &&
|
|
30
|
+
existing.provider === IMAP_PROVIDER_KEY &&
|
|
31
|
+
existing.authMethod === InboundMailAuthMethods.password &&
|
|
32
|
+
existing.ownerUserId === ownerUserId);
|
|
33
|
+
}
|
|
26
34
|
const connectedAccountSchema = z.object({ accountId: z.string() });
|
|
27
35
|
// Matched on the mapped error text, which also carries the host, so only markers no host name
|
|
28
36
|
// contains: a bare "tls" or "ssl" would misread a host like ssl.example.com.
|
|
29
37
|
// BoringSSL (Bun) spells the handshake error WRONG_VERSION_NUMBER, OpenSSL (Node) with spaces.
|
|
30
38
|
const TLS_FAILURE = /certificate|self[- ]signed|wrong[ _]version[ _]number|EPROTO|ERR_SSL|ERR_TLS/i;
|
|
31
39
|
// A fixed preview: any slice of the JSON document would expose the host or the user.
|
|
32
|
-
const CREDENTIAL_PREVIEW = "IMAP login";
|
|
33
|
-
const SECRET_TRANSACTION_REASON = "the credential secret is written on the request transaction so a failed account connect rolls it back too";
|
|
40
|
+
export const CREDENTIAL_PREVIEW = "IMAP login";
|
|
34
41
|
// Most hosters name the outgoing server like the incoming one, or with smtp. for imap.
|
|
35
42
|
export function deriveSmtpHost(imapHost) {
|
|
36
43
|
return /^imap\./i.test(imapHost) ? `smtp.${imapHost.slice("imap.".length)}` : imapHost;
|
|
@@ -73,53 +80,96 @@ async function checkSmtpLogin(doc) {
|
|
|
73
80
|
throw err;
|
|
74
81
|
}
|
|
75
82
|
}
|
|
76
|
-
|
|
83
|
+
// Checks the IMAP login, then the SMTP login of the outgoing server; shared by connect and reconnect.
|
|
84
|
+
export async function checkMailboxLogin(doc, log) {
|
|
85
|
+
try {
|
|
86
|
+
await connectOnce(doc, true);
|
|
87
|
+
}
|
|
88
|
+
catch (err) {
|
|
89
|
+
const { reason, i18nKey } = IMAP_CONNECT_ERRORS[imapConnectFailureOf(err)];
|
|
90
|
+
log.warn("imap connect check failed", { reason });
|
|
91
|
+
return writeFailure(new UnprocessableError(reason, { i18nKey }));
|
|
92
|
+
}
|
|
93
|
+
const smtpFailure = await checkSmtpLogin(doc);
|
|
94
|
+
if (smtpFailure) {
|
|
95
|
+
const { reason, i18nKey } = SMTP_CONNECT_ERRORS[smtpFailure];
|
|
96
|
+
log.warn("smtp connect check failed", { reason });
|
|
97
|
+
return writeFailure(new UnprocessableError(reason, { i18nKey, i18nParams: { port: doc.smtpPort } }));
|
|
98
|
+
}
|
|
99
|
+
return { isSuccess: true, data: null };
|
|
100
|
+
}
|
|
101
|
+
export const SECRET_TRANSACTION_REASON = "the credential secret is written on the request transaction so a failed account connect rolls it back too";
|
|
102
|
+
// Shared by the admin form (shared mailbox) and the member form (personal mailbox, owner = caller).
|
|
103
|
+
// A disconnected password mailbox of the same scope and owner is brought back under its old account id,
|
|
104
|
+
// so cursor, seen anchors and threads survive; anything else keeps connect-account's conflict answer.
|
|
105
|
+
export async function connectPasswordMailbox(handlerName, event, ctx, mailbox, scope) {
|
|
106
|
+
const { displayName, address, credentialDocument } = mailbox;
|
|
107
|
+
const ownerUserId = scope === "user" ? event.user.id : null;
|
|
108
|
+
const existing = await findMailboxByAddress(ctx, event.user.tenantId, address);
|
|
109
|
+
const reopened = existing !== undefined && isReopenableByThisForm(existing, ownerUserId);
|
|
110
|
+
let accountId;
|
|
111
|
+
if (reopened) {
|
|
112
|
+
accountId = existing.id;
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
const accountFields = {
|
|
116
|
+
provider: IMAP_PROVIDER_KEY,
|
|
117
|
+
authMethod: InboundMailAuthMethods.password,
|
|
118
|
+
displayName,
|
|
119
|
+
address,
|
|
120
|
+
scope,
|
|
121
|
+
};
|
|
122
|
+
// connect-account is admin-only, so a member's personal mailbox goes through the system identity
|
|
123
|
+
// with the owner taken from this session, like the OAuth callback does.
|
|
124
|
+
const connected = scope === "user"
|
|
125
|
+
? await ctx.dispatch.writeAs(createSystemUser(ctx.user.tenantId, [ROLES.SystemAdmin]), InboundMailFoundationHandlers.connectAccount, { ...accountFields, ownerUserIdOverride: event.user.id })
|
|
126
|
+
: await ctx.dispatch.write(InboundMailFoundationHandlers.connectAccount, accountFields);
|
|
127
|
+
if (!connected.isSuccess)
|
|
128
|
+
return connected;
|
|
129
|
+
accountId = connectedAccountSchema.parse(connected.data).accountId;
|
|
130
|
+
}
|
|
131
|
+
const secrets = requireSecretsContext({ secrets: ctx.services.secrets, user: ctx.user }, handlerName).withRunner(ctx.db.unsafeRaw());
|
|
132
|
+
await secrets.set(event.user.tenantId, inboundCredentialSecretKey(accountId), JSON.stringify(credentialDocument), {
|
|
133
|
+
redact: () => CREDENTIAL_PREVIEW,
|
|
134
|
+
hint: `IMAP credentials for inbound mail account ${accountId}`,
|
|
135
|
+
updatedBy: event.user.id,
|
|
136
|
+
});
|
|
137
|
+
if (reopened) {
|
|
138
|
+
// Secret first: reactivating a disconnected account requires the credential to exist.
|
|
139
|
+
const reactivated = await ctx.dispatch.write(InboundMailFoundationHandlers.reactivateAccount, {
|
|
140
|
+
accountId,
|
|
141
|
+
});
|
|
142
|
+
if (!reactivated.isSuccess)
|
|
143
|
+
return reactivated;
|
|
144
|
+
}
|
|
145
|
+
return { isSuccess: true, data: { accountId } };
|
|
146
|
+
}
|
|
147
|
+
export const createConnectMailboxHandler = ({ adminRoles }) => defineWriteHandler({
|
|
77
148
|
name: "connect-mailbox",
|
|
78
149
|
description: "Connects a shared IMAP mailbox with a password over implicit TLS: checks the IMAP login and the SMTP login of the outgoing server (given, or derived from the IMAP host) first, then creates the mail account and stores both servers, user and password as its credential secret in one step.",
|
|
79
150
|
// The payload carries the plaintext password: as a tool call it would reach the model provider.
|
|
80
151
|
agent: { expose: false },
|
|
81
152
|
schema: connectMailboxSchema,
|
|
82
|
-
access: { roles: [
|
|
153
|
+
access: { roles: [...adminRoles] },
|
|
83
154
|
// Each call opens a connection to a host the caller picks; the cap keeps the form from being
|
|
84
155
|
// used to scan ports or to guess passwords at someone else's mail server.
|
|
85
156
|
rateLimit: { per: "tenant+handler", limit: 10, windowSeconds: 600 },
|
|
86
157
|
escapeHatch: { grants: ["unsafeRaw"], reason: SECRET_TRANSACTION_REASON },
|
|
87
|
-
beforeTransaction:
|
|
88
|
-
const doc = credentialDocumentOf(event.payload);
|
|
89
|
-
try {
|
|
90
|
-
await connectOnce(doc, true);
|
|
91
|
-
}
|
|
92
|
-
catch (err) {
|
|
93
|
-
const { reason, i18nKey } = IMAP_CONNECT_ERRORS[imapConnectFailureOf(err)];
|
|
94
|
-
ctx.obs.log.warn("imap connect check failed", { reason });
|
|
95
|
-
return writeFailure(new UnprocessableError(reason, { i18nKey }));
|
|
96
|
-
}
|
|
97
|
-
const smtpFailure = await checkSmtpLogin(doc);
|
|
98
|
-
if (smtpFailure) {
|
|
99
|
-
const { reason, i18nKey } = SMTP_CONNECT_ERRORS[smtpFailure];
|
|
100
|
-
ctx.obs.log.warn("smtp connect check failed", { reason });
|
|
101
|
-
return writeFailure(new UnprocessableError(reason, { i18nKey, i18nParams: { port: doc.smtpPort } }));
|
|
102
|
-
}
|
|
103
|
-
return { isSuccess: true, data: null };
|
|
104
|
-
},
|
|
158
|
+
beforeTransaction: (event, ctx) => checkMailboxLogin(credentialDocumentOf(event.payload), ctx.obs.log),
|
|
105
159
|
handler: async (event, ctx) => {
|
|
106
|
-
const { displayName, address } = event.payload;
|
|
107
|
-
const connected = await ctx
|
|
108
|
-
provider: IMAP_PROVIDER_KEY,
|
|
109
|
-
authMethod: InboundMailAuthMethods.password,
|
|
110
|
-
displayName,
|
|
111
|
-
address,
|
|
112
|
-
scope: "shared",
|
|
113
|
-
});
|
|
160
|
+
const { displayName, address, trustedAuthservId } = event.payload;
|
|
161
|
+
const connected = await connectPasswordMailbox("connect-mailbox", event, ctx, { displayName, address, credentialDocument: credentialDocumentOf(event.payload) }, "shared");
|
|
114
162
|
if (!connected.isSuccess)
|
|
115
163
|
return connected;
|
|
116
|
-
const { accountId } =
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
164
|
+
const { accountId } = connected.data;
|
|
165
|
+
if (trustedAuthservId) {
|
|
166
|
+
const trusted = await ctx.dispatch.write(InboundMailFoundationHandlers.setTrustedAuthservId, {
|
|
167
|
+
accountId,
|
|
168
|
+
trustedAuthservId,
|
|
169
|
+
});
|
|
170
|
+
if (!trusted.isSuccess)
|
|
171
|
+
return trusted;
|
|
172
|
+
}
|
|
123
173
|
return { isSuccess: true, data: { accountId } };
|
|
124
174
|
},
|
|
125
175
|
});
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { InboundMailRoles } from "@cosmicdrift/kumiko-bundled-features/inbound-mail-foundation";
|
|
2
|
+
export declare const createConnectMyMailboxHandler: ({ memberRoles }: InboundMailRoles) => import("@cosmicdrift/kumiko-types/define-handler").WriteHandlerDefinition<"connect-my-mailbox", import("zod").ZodObject<{
|
|
3
|
+
host: import("zod").ZodString;
|
|
4
|
+
port: import("zod").ZodDefault<import("zod").ZodNumber>;
|
|
5
|
+
user: import("zod").ZodString;
|
|
6
|
+
displayName: import("zod").ZodString;
|
|
7
|
+
address: import("zod").ZodEmail;
|
|
8
|
+
password: import("zod").ZodString;
|
|
9
|
+
smtpHost: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodUnion<readonly [import("zod").ZodLiteral<"">, import("zod").ZodString]>>>;
|
|
10
|
+
smtpPort: import("zod").ZodNumber;
|
|
11
|
+
}, import("zod/v4/core").$strip>, {
|
|
12
|
+
accountId: string;
|
|
13
|
+
}, import("@cosmicdrift/kumiko-types/event-type-map").KumikoEventTypeMap, null, undefined>;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// connect-my-mailbox: a member connects a personal password IMAP mailbox (owner = the caller).
|
|
2
|
+
// Same login check and secret write as connect-mailbox; the sender-check policy is tenant-wide and
|
|
3
|
+
// stays with the admin form.
|
|
4
|
+
import { defineWriteHandler } from "@cosmicdrift/kumiko-framework/engine";
|
|
5
|
+
import { checkMailboxLogin, connectMailboxSchema, connectPasswordMailbox, credentialDocumentOf, SECRET_TRANSACTION_REASON, } from "./connect-mailbox.js";
|
|
6
|
+
const connectMyMailboxSchema = connectMailboxSchema.omit({ trustedAuthservId: true });
|
|
7
|
+
const MY_MAILBOX_ESCAPE_REASON = `${SECRET_TRANSACTION_REASON}; the account is created with writeAs(system) on connect-account, which is admin-only, and the owner comes from the caller's session`;
|
|
8
|
+
export const createConnectMyMailboxHandler = ({ memberRoles }) => defineWriteHandler({
|
|
9
|
+
name: "connect-my-mailbox",
|
|
10
|
+
description: "Connects a personal IMAP mailbox of the caller with a password over implicit TLS: checks the IMAP login and the SMTP login of the outgoing server first, then creates the mail account owned by the caller and stores both servers, user and password as its credential secret in one step. A disconnected personal mailbox of the caller with the same address is reactivated under its old account id.",
|
|
11
|
+
// The payload carries the plaintext password: as a tool call it would reach the model provider.
|
|
12
|
+
agent: { expose: false },
|
|
13
|
+
schema: connectMyMailboxSchema,
|
|
14
|
+
access: { roles: [...memberRoles] },
|
|
15
|
+
// Each call opens a connection to a host the caller picks; per user, because any member may call it.
|
|
16
|
+
rateLimit: { per: "user", limit: 10, windowSeconds: 600 },
|
|
17
|
+
// connect-account is admin-only; the personal mailbox is created through the system identity. The owner
|
|
18
|
+
// is always event.user.id from the session, never a payload field.
|
|
19
|
+
escapeHatch: { grants: ["unsafeRaw", "systemIdentity"], reason: MY_MAILBOX_ESCAPE_REASON },
|
|
20
|
+
beforeTransaction: (event, ctx) => checkMailboxLogin(credentialDocumentOf(event.payload), ctx.obs.log),
|
|
21
|
+
handler: async (event, ctx) => {
|
|
22
|
+
const { displayName, address } = event.payload;
|
|
23
|
+
return connectPasswordMailbox("connect-my-mailbox", event, ctx, { displayName, address, credentialDocument: credentialDocumentOf(event.payload) }, "user");
|
|
24
|
+
},
|
|
25
|
+
});
|
|
@@ -1,7 +1,18 @@
|
|
|
1
1
|
export declare const FEATURE_NAME = "inbound-provider-imap";
|
|
2
|
-
export
|
|
2
|
+
export { IMAP_PROVIDER_KEY } from "@cosmicdrift/kumiko-bundled-features/inbound-mail-foundation";
|
|
3
3
|
export declare const ImapHandlers: {
|
|
4
4
|
readonly connectMailbox: "inbound-provider-imap:write:connect-mailbox";
|
|
5
|
+
readonly connectMyMailbox: "inbound-provider-imap:write:connect-my-mailbox";
|
|
6
|
+
readonly reconnectMailbox: "inbound-provider-imap:write:reconnect-mailbox";
|
|
7
|
+
};
|
|
8
|
+
export declare const ImapQueries: {
|
|
9
|
+
readonly reconnectPrefill: "inbound-provider-imap:query:reconnect-prefill";
|
|
10
|
+
};
|
|
11
|
+
export declare const IMAP_RECONNECT_ERRORS: {
|
|
12
|
+
readonly notPasswordImap: {
|
|
13
|
+
readonly reason: "reconnect_not_password_imap";
|
|
14
|
+
readonly i18nKey: "inboundMail.imap.reconnect.errors.notPasswordImap";
|
|
15
|
+
};
|
|
5
16
|
};
|
|
6
17
|
export declare const IMAP_CONNECT_ERRORS: {
|
|
7
18
|
readonly hostUnreachable: {
|
|
@@ -1,7 +1,18 @@
|
|
|
1
1
|
export const FEATURE_NAME = "inbound-provider-imap";
|
|
2
|
-
export
|
|
2
|
+
export { IMAP_PROVIDER_KEY } from "@cosmicdrift/kumiko-bundled-features/inbound-mail-foundation";
|
|
3
3
|
export const ImapHandlers = {
|
|
4
4
|
connectMailbox: "inbound-provider-imap:write:connect-mailbox",
|
|
5
|
+
connectMyMailbox: "inbound-provider-imap:write:connect-my-mailbox",
|
|
6
|
+
reconnectMailbox: "inbound-provider-imap:write:reconnect-mailbox",
|
|
7
|
+
};
|
|
8
|
+
export const ImapQueries = {
|
|
9
|
+
reconnectPrefill: "inbound-provider-imap:query:reconnect-prefill",
|
|
10
|
+
};
|
|
11
|
+
export const IMAP_RECONNECT_ERRORS = {
|
|
12
|
+
notPasswordImap: {
|
|
13
|
+
reason: "reconnect_not_password_imap",
|
|
14
|
+
i18nKey: "inboundMail.imap.reconnect.errors.notPasswordImap",
|
|
15
|
+
},
|
|
5
16
|
};
|
|
6
17
|
export const IMAP_CONNECT_ERRORS = {
|
|
7
18
|
hostUnreachable: {
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
// smtpHost is the outgoing server for sending from the mailbox, with the same user and password
|
|
19
19
|
// over implicit TLS. Documents written before sending existed have none: sending reports
|
|
20
20
|
// "not set up" instead of guessing a host.
|
|
21
|
-
import { InboundAuthError, inboundCredentialSecretKey, } from "@cosmicdrift/kumiko-bundled-features/inbound-mail-foundation";
|
|
21
|
+
import { InboundAuthError, InboundCredentialNotStoredError, inboundCredentialSecretKey, } from "@cosmicdrift/kumiko-bundled-features/inbound-mail-foundation";
|
|
22
22
|
import { requireSecretsContext } from "@cosmicdrift/kumiko-bundled-features/secrets";
|
|
23
23
|
import * as z from "zod";
|
|
24
24
|
import { FEATURE_NAME, SMTP_SUBMISSION_PORT } from "./constants.js";
|
|
@@ -60,7 +60,7 @@ export async function readCredentialDocument(ctx, account) {
|
|
|
60
60
|
const secrets = requireSecretsContext({ secrets: ctx.secrets, auditUserId: ctx.auditUserId }, FEATURE_NAME);
|
|
61
61
|
const secret = await secrets.get(account.tenantId, inboundCredentialSecretKey(account.id));
|
|
62
62
|
if (!secret) {
|
|
63
|
-
throw new
|
|
63
|
+
throw new InboundCredentialNotStoredError(`${FEATURE_NAME}: no credential document in secret slot for account ${account.id} — ` +
|
|
64
64
|
`store the IMAP connection JSON under ${inboundCredentialSecretKey(account.id)} first`);
|
|
65
65
|
}
|
|
66
66
|
const parsed = parseImapCredentialDocument(secret.reveal());
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { RawInboundMessage, RejectedInboundMessage } from "@cosmicdrift/kumiko-bundled-features/inbound-mail-foundation";
|
|
2
|
+
import type { ImapFlow } from "imapflow";
|
|
3
|
+
export declare function downloadBatch(client: ImapFlow, batch: readonly number[], uidValidity: string, trustedAuthservId: string | null): Promise<{
|
|
4
|
+
readonly messages: RawInboundMessage[];
|
|
5
|
+
readonly rejected: RejectedInboundMessage[];
|
|
6
|
+
}>;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { coerceDate, parseOrReject } from "./parse-message.js";
|
|
2
|
+
export async function downloadBatch(client, batch, uidValidity, trustedAuthservId) {
|
|
3
|
+
const messages = [];
|
|
4
|
+
const rejected = [];
|
|
5
|
+
if (batch.length === 0)
|
|
6
|
+
return { messages, rejected };
|
|
7
|
+
for await (const msg of client.fetch(batch.join(","), { uid: true, internalDate: true, source: true, envelope: true }, { uid: true })) {
|
|
8
|
+
if (!msg.source)
|
|
9
|
+
continue;
|
|
10
|
+
const parsed = await parseOrReject({
|
|
11
|
+
source: msg.source,
|
|
12
|
+
uid: msg.uid,
|
|
13
|
+
uidValidity,
|
|
14
|
+
internalDate: coerceDate(msg.internalDate ?? undefined),
|
|
15
|
+
envelope: msg.envelope,
|
|
16
|
+
trustedAuthservId,
|
|
17
|
+
});
|
|
18
|
+
if ("message" in parsed)
|
|
19
|
+
messages.push(parsed.message);
|
|
20
|
+
else
|
|
21
|
+
rejected.push(parsed.rejected);
|
|
22
|
+
}
|
|
23
|
+
return { messages, rejected };
|
|
24
|
+
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { type InboundMailProviderPlugin } from "@cosmicdrift/kumiko-bundled-features/inbound-mail-foundation";
|
|
1
|
+
import { type InboundMailProviderPlugin, type InboundMailRoleOptions } from "@cosmicdrift/kumiko-bundled-features/inbound-mail-foundation";
|
|
2
2
|
export { IMAP_PROVIDER_KEY } from "./constants.ts";
|
|
3
3
|
export { setImapMailHostLookup } from "./imap-client.ts";
|
|
4
4
|
/** Exported for the live test (imap-live.integration.test.ts) —
|
|
5
5
|
* applications use the feature, never the plugin directly. */
|
|
6
6
|
export declare const imapInboundMailPlugin: InboundMailProviderPlugin;
|
|
7
|
-
export declare function createInboundProviderImapFeature(): import("@cosmicdrift/kumiko-types/feature").FeatureDefinition & {
|
|
7
|
+
export declare function createInboundProviderImapFeature(options?: InboundMailRoleOptions): import("@cosmicdrift/kumiko-types/feature").FeatureDefinition & {
|
|
8
8
|
readonly exports: void;
|
|
9
9
|
};
|
|
@@ -23,25 +23,36 @@
|
|
|
23
23
|
// (credential-document.ts), not tenant configuration, because one tenant
|
|
24
24
|
// can have multiple accounts with different hosts.
|
|
25
25
|
import { mailAllowedPrivateHostsEnvSchema } from "@cosmicdrift/kumiko-bundled-features/foundation-shared";
|
|
26
|
-
import { INBOUND_MAIL_PROVIDER_EXTENSION, } from "@cosmicdrift/kumiko-bundled-features/inbound-mail-foundation";
|
|
26
|
+
import { assertRolesMatchFoundation, INBOUND_MAIL_PROVIDER_EXTENSION, resolveInboundMailRoles, roleDedupeOptions, } from "@cosmicdrift/kumiko-bundled-features/inbound-mail-foundation";
|
|
27
27
|
import { defineFeature } from "@cosmicdrift/kumiko-framework/engine";
|
|
28
28
|
import { instantToLegacyDate } from "@cosmicdrift/kumiko-framework/time";
|
|
29
29
|
import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
|
|
30
|
-
import {
|
|
30
|
+
import { createConnectMailboxHandler } from "./connect-mailbox.js";
|
|
31
|
+
import { createConnectMyMailboxHandler } from "./connect-my-mailbox.js";
|
|
31
32
|
import { FEATURE_NAME, IMAP_PROVIDER_KEY } from "./constants.js";
|
|
32
33
|
import { readCredentialDocument } from "./credential-document.js";
|
|
34
|
+
import { downloadBatch } from "./download-batch.js";
|
|
35
|
+
import { fetchMessageContent } from "./fetch-content.js";
|
|
33
36
|
import { INBOUND_PROVIDER_IMAP_I18N } from "./i18n.js";
|
|
34
|
-
import { assertUidValidity,
|
|
35
|
-
import {
|
|
37
|
+
import { assertUidValidity, closeOnAbort, connectOnce, createImapClient, IMAP_MAILBOX, imapMailHostGuard, mapImapError, parseImapCursor, } from "./imap-client.js";
|
|
38
|
+
import { buildProviderMessageId, coerceDate, parseOrReject } from "./parse-message.js";
|
|
39
|
+
import { createReconnectMailboxHandler } from "./reconnect-mailbox.js";
|
|
40
|
+
import { createReconnectPrefillQuery } from "./reconnect-prefill.query.js";
|
|
41
|
+
import { createImapScreens } from "./screens.js";
|
|
36
42
|
import { sendFromImapAccount } from "./send-mail.js";
|
|
37
43
|
export { IMAP_PROVIDER_KEY } from "./constants.js";
|
|
38
44
|
export { setImapMailHostLookup } from "./imap-client.js";
|
|
39
45
|
// =============================================================================
|
|
40
46
|
// fetch — inkrementeller UID-Sync
|
|
41
47
|
// =============================================================================
|
|
48
|
+
async function unknownUidsOf(uids, uidValidity, filterUnknownMessageIds) {
|
|
49
|
+
const unknownIds = await filterUnknownMessageIds(uids.map((uid) => buildProviderMessageId(uidValidity, uid)));
|
|
50
|
+
return uids.filter((uid) => unknownIds.has(buildProviderMessageId(uidValidity, uid)));
|
|
51
|
+
}
|
|
42
52
|
async function fetchMessages(ctx, account, cursor, opts) {
|
|
43
53
|
const doc = await readCredentialDocument(ctx, account);
|
|
44
54
|
const client = await createImapClient(doc, imapMailHostGuard());
|
|
55
|
+
const stopWatchingAbort = closeOnAbort(client, opts.signal);
|
|
45
56
|
let lock;
|
|
46
57
|
try {
|
|
47
58
|
await client.connect();
|
|
@@ -65,27 +76,19 @@ async function fetchMessages(ctx, account, cursor, opts) {
|
|
|
65
76
|
uids = (await client.search({ since: instantToLegacyDate(since) }, { uid: true })) || [];
|
|
66
77
|
}
|
|
67
78
|
uids.sort((a, b) => a - b);
|
|
68
|
-
|
|
69
|
-
const
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
source: msg.source,
|
|
78
|
-
uid: msg.uid,
|
|
79
|
-
uidValidity: serverUidValidity,
|
|
80
|
-
internalDate: coerceDate(msg.internalDate ?? undefined),
|
|
81
|
-
}));
|
|
82
|
-
if (msg.uid > maxUid)
|
|
83
|
-
maxUid = msg.uid;
|
|
84
|
-
}
|
|
85
|
-
}
|
|
79
|
+
// Known mails (ingested or quarantined) are not downloaded again; the cursor still moves past them.
|
|
80
|
+
const unknown = opts.filterUnknownMessageIds
|
|
81
|
+
? await unknownUidsOf(uids, serverUidValidity, opts.filterUnknownMessageIds)
|
|
82
|
+
: uids;
|
|
83
|
+
const batch = unknown.slice(0, opts.maxMessages);
|
|
84
|
+
const hasMore = unknown.length > batch.length;
|
|
85
|
+
const { messages, rejected } = await downloadBatch(client, batch, serverUidValidity, account.trustedAuthservId ?? null);
|
|
86
|
+
// From the UIDs, not from what was downloaded: a known or skipped mail must not hold the cursor back.
|
|
87
|
+
const lastUid = Math.max(parsedCursor?.lastUid ?? 0, ...(hasMore ? batch : uids));
|
|
86
88
|
return {
|
|
87
89
|
messages,
|
|
88
|
-
|
|
90
|
+
...(rejected.length > 0 && { rejected }),
|
|
91
|
+
nextCursor: { uidValidity: serverUidValidity, lastUid },
|
|
89
92
|
hasMore,
|
|
90
93
|
};
|
|
91
94
|
}
|
|
@@ -93,6 +96,7 @@ async function fetchMessages(ctx, account, cursor, opts) {
|
|
|
93
96
|
throw err instanceof Error && "kind" in err ? err : mapImapError(err, doc.host);
|
|
94
97
|
}
|
|
95
98
|
finally {
|
|
99
|
+
stopWatchingAbort();
|
|
96
100
|
lock?.release();
|
|
97
101
|
await client.logout().catch(() => { });
|
|
98
102
|
}
|
|
@@ -114,23 +118,29 @@ async function watchMailbox(ctx, account, handlers) {
|
|
|
114
118
|
let nextUid = Number(mailbox.uidNext ?? 1);
|
|
115
119
|
const drainNew = async () => {
|
|
116
120
|
const messages = [];
|
|
121
|
+
const rejected = [];
|
|
117
122
|
let maxSeen = nextUid - 1;
|
|
118
123
|
for await (const msg of client.fetch(`${nextUid}:*`, { uid: true, internalDate: true, source: true }, { uid: true })) {
|
|
119
124
|
// `N:*` gotcha (see fetch): filter out the previous last message.
|
|
120
125
|
if (msg.uid < nextUid || !msg.source)
|
|
121
126
|
continue;
|
|
122
|
-
|
|
127
|
+
const parsed = await parseOrReject({
|
|
123
128
|
source: msg.source,
|
|
124
129
|
uid: msg.uid,
|
|
125
130
|
uidValidity,
|
|
126
131
|
internalDate: coerceDate(msg.internalDate ?? undefined),
|
|
127
|
-
|
|
132
|
+
trustedAuthservId: account.trustedAuthservId ?? null,
|
|
133
|
+
});
|
|
134
|
+
if ("message" in parsed)
|
|
135
|
+
messages.push(parsed.message);
|
|
136
|
+
else
|
|
137
|
+
rejected.push(parsed.rejected);
|
|
128
138
|
if (msg.uid > maxSeen)
|
|
129
139
|
maxSeen = msg.uid;
|
|
130
140
|
}
|
|
131
141
|
nextUid = maxSeen + 1;
|
|
132
|
-
if (messages.length > 0)
|
|
133
|
-
await handlers.onMessages(messages);
|
|
142
|
+
if (messages.length > 0 || rejected.length > 0)
|
|
143
|
+
await handlers.onMessages(messages, rejected);
|
|
134
144
|
};
|
|
135
145
|
client.on("exists", () => {
|
|
136
146
|
// skip: ignore delayed exists events after the watcher has stopped.
|
|
@@ -190,15 +200,17 @@ export const imapInboundMailPlugin = {
|
|
|
190
200
|
verify: async (ctx, account) => connectOnce(await readCredentialDocument(ctx, account), false),
|
|
191
201
|
probe: async (ctx, account) => connectOnce(await readCredentialDocument(ctx, account), true),
|
|
192
202
|
fetch: fetchMessages,
|
|
203
|
+
fetchContent: fetchMessageContent,
|
|
193
204
|
watch: watchMailbox,
|
|
194
205
|
send: sendFromImapAccount,
|
|
195
206
|
// No oauth block: password authentication runs through the credential
|
|
196
207
|
// form (connect-account + Secret-Write); XOAUTH2 token flows belong to
|
|
197
208
|
// the OAuth providers (M365/Gmail).
|
|
198
209
|
};
|
|
199
|
-
export function createInboundProviderImapFeature() {
|
|
210
|
+
export function createInboundProviderImapFeature(options = {}) {
|
|
211
|
+
const roles = resolveInboundMailRoles(options);
|
|
200
212
|
return defineFeature(FEATURE_NAME, (r) => {
|
|
201
|
-
r.describe('Registers the `"imap"` provider for `inbound-mail-foundation` using imapflow — password/app-password auth covers classic IMAP hosts without any OAuth (plus an XOAUTH2 fallback consuming an access token from the secret slot). Incremental sync via a UIDVALIDITY:lastUid cursor (UIDVALIDITY change triggers a cursor-invalid full resync), initial backfill bounded by the foundation backfill window, and live push via IMAP IDLE for the watch supervisor. Tenant admins connect a mailbox through the "Connect mailbox" form on the mail accounts list (`connect-mailbox`
|
|
213
|
+
r.describe('Registers the `"imap"` provider for `inbound-mail-foundation` using imapflow — password/app-password auth covers classic IMAP hosts without any OAuth (plus an XOAUTH2 fallback consuming an access token from the secret slot). Incremental sync via a UIDVALIDITY:lastUid cursor (UIDVALIDITY change triggers a cursor-invalid full resync), initial backfill bounded by the foundation backfill window, and live push via IMAP IDLE for the watch supervisor. Tenant admins connect a shared mailbox through the "Connect mailbox" form on the mail accounts list and members a personal one through the same form on "My mail accounts" (`connect-mailbox` and `connect-my-mailbox` check the IMAP login and the SMTP login of the outgoing server first, then creates the account and its credential secret in one transaction; `reconnect-mailbox` does the same check for an existing mailbox with a sign-in error and overwrites its credential secret); programmatic setups store the per-account connection JSON (host/port/secure/user/password, plus smtpHost/smtpPort for sending) in the account credential secret slot before the first sync. Implements the provider `send`: `sendMailFromAccount` sends over the SMTP server of the mailbox itself (implicit TLS, same login) with the mailbox address as From and stores a copy in its sent folder.');
|
|
202
214
|
r.uiHints({
|
|
203
215
|
displayLabel: "Inbound Mail · IMAP",
|
|
204
216
|
category: "notifications",
|
|
@@ -208,8 +220,13 @@ export function createInboundProviderImapFeature() {
|
|
|
208
220
|
r.requires({ features: ["secrets"] });
|
|
209
221
|
r.envSchema(mailAllowedPrivateHostsEnvSchema);
|
|
210
222
|
r.useExtension(INBOUND_MAIL_PROVIDER_EXTENSION, IMAP_PROVIDER_KEY, imapInboundMailPlugin);
|
|
211
|
-
r.
|
|
212
|
-
r.
|
|
223
|
+
r.bootCheck(({ features }) => assertRolesMatchFoundation(FEATURE_NAME, roles, features));
|
|
224
|
+
r.writeHandler(createConnectMailboxHandler(roles));
|
|
225
|
+
r.writeHandler(createConnectMyMailboxHandler(roles));
|
|
226
|
+
r.writeHandler(createReconnectMailboxHandler(roles));
|
|
227
|
+
r.queryHandler(createReconnectPrefillQuery(roles));
|
|
228
|
+
for (const screen of createImapScreens(roles))
|
|
229
|
+
r.screen(screen);
|
|
213
230
|
r.translations({ keys: INBOUND_PROVIDER_IMAP_I18N });
|
|
214
|
-
}, { dedupeOptions:
|
|
231
|
+
}, { dedupeOptions: roleDedupeOptions(roles) });
|
|
215
232
|
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { InboundContentFetchResult, InboundMailContext, MailAccountRecord } from "@cosmicdrift/kumiko-bundled-features/inbound-mail-foundation";
|
|
2
|
+
export declare function fetchMessageContent(ctx: InboundMailContext, account: MailAccountRecord, providerMessageIds: readonly string[], opts?: {
|
|
3
|
+
readonly signal?: AbortSignal;
|
|
4
|
+
}): Promise<InboundContentFetchResult>;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
// Re-downloads already imported mails whose content was stored as snippet only. A provider message
|
|
2
|
+
// id is "<uidValidity>:<uid>"; ids from another UIDVALIDITY or gone from the server are "missing"
|
|
3
|
+
// (nothing to reload, ever), mails the parser cannot read are "rejected".
|
|
4
|
+
import { InboundTransientError } from "@cosmicdrift/kumiko-bundled-features/inbound-mail-foundation";
|
|
5
|
+
import { readCredentialDocument } from "./credential-document.js";
|
|
6
|
+
import { closeOnAbort, createImapClient, IMAP_MAILBOX, imapMailHostGuard, mapImapError, } from "./imap-client.js";
|
|
7
|
+
import { coerceDate, parseOrReject } from "./parse-message.js";
|
|
8
|
+
function uidOf(providerMessageId, serverUidValidity) {
|
|
9
|
+
const separator = providerMessageId.lastIndexOf(":");
|
|
10
|
+
if (separator < 0 || providerMessageId.slice(0, separator) !== serverUidValidity)
|
|
11
|
+
return null;
|
|
12
|
+
const uid = Number(providerMessageId.slice(separator + 1));
|
|
13
|
+
return Number.isInteger(uid) && uid > 0 ? uid : null;
|
|
14
|
+
}
|
|
15
|
+
export async function fetchMessageContent(ctx, account, providerMessageIds, opts) {
|
|
16
|
+
const doc = await readCredentialDocument(ctx, account);
|
|
17
|
+
const client = await createImapClient(doc, imapMailHostGuard());
|
|
18
|
+
const stopWatchingAbort = closeOnAbort(client, opts?.signal);
|
|
19
|
+
let lock;
|
|
20
|
+
try {
|
|
21
|
+
await client.connect();
|
|
22
|
+
lock = await client.getMailboxLock(IMAP_MAILBOX);
|
|
23
|
+
const mailbox = client.mailbox;
|
|
24
|
+
if (typeof mailbox === "boolean")
|
|
25
|
+
throw new InboundTransientError("mailbox not open");
|
|
26
|
+
const serverUidValidity = String(mailbox.uidValidity);
|
|
27
|
+
const idByUid = new Map();
|
|
28
|
+
const missing = [];
|
|
29
|
+
for (const id of providerMessageIds) {
|
|
30
|
+
const uid = uidOf(id, serverUidValidity);
|
|
31
|
+
if (uid === null)
|
|
32
|
+
missing.push(id);
|
|
33
|
+
else
|
|
34
|
+
idByUid.set(uid, id);
|
|
35
|
+
}
|
|
36
|
+
const messages = [];
|
|
37
|
+
const rejected = [];
|
|
38
|
+
if (idByUid.size > 0) {
|
|
39
|
+
for await (const msg of client.fetch([...idByUid.keys()].join(","), { uid: true, internalDate: true, source: true, envelope: true }, { uid: true })) {
|
|
40
|
+
if (!msg.source)
|
|
41
|
+
continue;
|
|
42
|
+
const parsed = await parseOrReject({
|
|
43
|
+
source: msg.source,
|
|
44
|
+
uid: msg.uid,
|
|
45
|
+
uidValidity: serverUidValidity,
|
|
46
|
+
internalDate: coerceDate(msg.internalDate ?? undefined),
|
|
47
|
+
envelope: msg.envelope,
|
|
48
|
+
});
|
|
49
|
+
idByUid.delete(msg.uid);
|
|
50
|
+
if ("message" in parsed)
|
|
51
|
+
messages.push(parsed.message);
|
|
52
|
+
else
|
|
53
|
+
rejected.push(parsed.rejected);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
// What the server did not return is gone (expunged since the import).
|
|
57
|
+
missing.push(...idByUid.values());
|
|
58
|
+
return { messages, missing, rejected };
|
|
59
|
+
}
|
|
60
|
+
catch (err) {
|
|
61
|
+
throw err instanceof Error && "kind" in err ? err : mapImapError(err, doc.host);
|
|
62
|
+
}
|
|
63
|
+
finally {
|
|
64
|
+
stopWatchingAbort();
|
|
65
|
+
lock?.release();
|
|
66
|
+
await client.logout().catch(() => { });
|
|
67
|
+
}
|
|
68
|
+
}
|