@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
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
// Pre-transaction half of the content storage: original and attachments are written while no
|
|
2
|
+
// transaction holds a connection, so a slow or failing file store never pins the database. The
|
|
3
|
+
// handler transaction only creates the fileRef rows (finalizePreparedContent).
|
|
4
|
+
import { writeFailure } from "@cosmicdrift/kumiko-framework/errors";
|
|
5
|
+
import { createFileRefFromUploadedBytes, uploadFileBytesBeforeTransaction, } from "@cosmicdrift/kumiko-framework/files";
|
|
6
|
+
import { inboundMessageAggregateId } from "../aggregate-id.js";
|
|
7
|
+
import { seenMessageTable } from "../entities.js";
|
|
8
|
+
import { FileStorageWriteFailedError } from "../file-storage-failure.js";
|
|
9
|
+
import { INBOUND_SKIPPED_ATTACHMENTS_MAX_COUNT } from "../normalize-inbound-message.js";
|
|
10
|
+
import { contentWithoutFileStorage, inboundAttachmentMaxSize, inboundAttachmentTarget, inboundMessageBodyKey, originalOf, } from "./message-content.js";
|
|
11
|
+
function storageFailure(cause) {
|
|
12
|
+
return writeFailure(new FileStorageWriteFailedError(cause instanceof Error ? cause : undefined));
|
|
13
|
+
}
|
|
14
|
+
async function releaseAll(releases) {
|
|
15
|
+
for (const release of releases)
|
|
16
|
+
await release();
|
|
17
|
+
}
|
|
18
|
+
// The deterministic original key is never released: a concurrent winner owns it and writing it
|
|
19
|
+
// again is idempotent.
|
|
20
|
+
export async function prepareInboundContent(ctx, input) {
|
|
21
|
+
const { files } = ctx.services;
|
|
22
|
+
if (!files) {
|
|
23
|
+
const unavailable = contentWithoutFileStorage(input);
|
|
24
|
+
return {
|
|
25
|
+
isSuccess: true,
|
|
26
|
+
data: {
|
|
27
|
+
bodyRef: unavailable.bodyRef,
|
|
28
|
+
uploads: [],
|
|
29
|
+
skippedAttachments: unavailable.skippedAttachments,
|
|
30
|
+
contentStorage: unavailable.contentStorage,
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
let bodyRef = input.bodyRef;
|
|
35
|
+
const original = originalOf(input);
|
|
36
|
+
if (bodyRef === "" && original) {
|
|
37
|
+
bodyRef = inboundMessageBodyKey(ctx.user.tenantId, input.accountId, input.messageAggId, original.extension);
|
|
38
|
+
try {
|
|
39
|
+
await files.ref(bodyRef).write(original.data, original.mimeType);
|
|
40
|
+
}
|
|
41
|
+
catch (err) {
|
|
42
|
+
return storageFailure(err);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
const uploads = [];
|
|
46
|
+
const releases = [];
|
|
47
|
+
const skipped = [...(input.skippedAttachments ?? [])];
|
|
48
|
+
const maxSize = inboundAttachmentMaxSize(ctx.registry);
|
|
49
|
+
for (const attachment of input.attachments ?? []) {
|
|
50
|
+
let uploaded;
|
|
51
|
+
try {
|
|
52
|
+
uploaded = await uploadFileBytesBeforeTransaction(ctx, {
|
|
53
|
+
fileName: attachment.fileName,
|
|
54
|
+
mimeType: attachment.mimeType,
|
|
55
|
+
data: attachment.data,
|
|
56
|
+
attachTo: inboundAttachmentTarget(input.messageAggId),
|
|
57
|
+
maxSize,
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
catch (err) {
|
|
61
|
+
await releaseAll(releases);
|
|
62
|
+
return storageFailure(err);
|
|
63
|
+
}
|
|
64
|
+
// A rejected attachment (size, MIME) is a property of the mail, not an outage.
|
|
65
|
+
if (!uploaded.isSuccess) {
|
|
66
|
+
skipped.push({
|
|
67
|
+
mimeType: attachment.mimeType,
|
|
68
|
+
size: attachment.data.byteLength,
|
|
69
|
+
reason: "rejected",
|
|
70
|
+
});
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
uploads.push(uploaded.data);
|
|
74
|
+
if (uploaded.release)
|
|
75
|
+
releases.push(uploaded.release);
|
|
76
|
+
}
|
|
77
|
+
return {
|
|
78
|
+
isSuccess: true,
|
|
79
|
+
data: {
|
|
80
|
+
bodyRef,
|
|
81
|
+
uploads,
|
|
82
|
+
skippedAttachments: skipped.slice(0, INBOUND_SKIPPED_ATTACHMENTS_MAX_COUNT),
|
|
83
|
+
contentStorage: "stored",
|
|
84
|
+
},
|
|
85
|
+
release: () => releaseAll(releases),
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
/** Transaction half: creates the fileRef rows for the bytes the prepare phase wrote. */
|
|
89
|
+
export async function finalizePreparedContent(ctx, prepared) {
|
|
90
|
+
const attachmentFileIds = [];
|
|
91
|
+
const skipped = [...prepared.skippedAttachments];
|
|
92
|
+
for (const upload of prepared.uploads) {
|
|
93
|
+
const created = await createFileRefFromUploadedBytes(ctx, upload);
|
|
94
|
+
if (created.isSuccess)
|
|
95
|
+
attachmentFileIds.push(created.data.id);
|
|
96
|
+
else
|
|
97
|
+
skipped.push({ mimeType: upload.mimeType, size: upload.size, reason: "rejected" });
|
|
98
|
+
}
|
|
99
|
+
return {
|
|
100
|
+
bodyRef: prepared.bodyRef,
|
|
101
|
+
attachmentFileIds,
|
|
102
|
+
skippedAttachments: skipped.slice(0, INBOUND_SKIPPED_ATTACHMENTS_MAX_COUNT),
|
|
103
|
+
contentStorage: prepared.contentStorage,
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
/** Dedup read first: a duplicate uploads nothing. The in-transaction dedup stays the correctness anchor. */
|
|
107
|
+
export async function prepareIngestMessage(event, ctx) {
|
|
108
|
+
const { payload } = event;
|
|
109
|
+
const seen = await ctx.db.selectMany(seenMessageTable, {
|
|
110
|
+
accountId: payload.accountId,
|
|
111
|
+
providerMessageId: payload.providerMessageId,
|
|
112
|
+
});
|
|
113
|
+
if (seen.length > 0)
|
|
114
|
+
return { isSuccess: true, data: { duplicate: true } };
|
|
115
|
+
const prepared = await prepareInboundContent(ctx, {
|
|
116
|
+
accountId: payload.accountId,
|
|
117
|
+
messageAggId: inboundMessageAggregateId(payload.accountId, payload.providerMessageId),
|
|
118
|
+
bodyRef: payload.bodyRef,
|
|
119
|
+
rawMime: payload.rawMime,
|
|
120
|
+
bodyHtml: payload.bodyHtml,
|
|
121
|
+
attachments: payload.attachments,
|
|
122
|
+
skippedAttachments: payload.skippedAttachments,
|
|
123
|
+
});
|
|
124
|
+
if (!prepared.isSuccess)
|
|
125
|
+
return prepared;
|
|
126
|
+
return {
|
|
127
|
+
isSuccess: true,
|
|
128
|
+
data: { duplicate: false, content: prepared.data },
|
|
129
|
+
...(prepared.release && { release: prepared.release }),
|
|
130
|
+
};
|
|
131
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import * as z from "zod";
|
|
2
|
+
export declare const ingestMessageSchema: z.ZodObject<{
|
|
3
|
+
bodyText: z.ZodDefault<z.ZodString>;
|
|
4
|
+
bodyTextTruncated: z.ZodDefault<z.ZodBoolean>;
|
|
5
|
+
rawMime: z.ZodOptional<z.ZodInstanceOf<Uint8Array<ArrayBuffer>>>;
|
|
6
|
+
bodyHtml: z.ZodOptional<z.ZodString>;
|
|
7
|
+
attachments: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
8
|
+
fileName: z.ZodString;
|
|
9
|
+
mimeType: z.ZodString;
|
|
10
|
+
data: z.ZodInstanceOf<Uint8Array<ArrayBuffer>>;
|
|
11
|
+
}, z.core.$strip>>>;
|
|
12
|
+
skippedAttachments: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
13
|
+
mimeType: z.ZodString;
|
|
14
|
+
size: z.ZodNumber;
|
|
15
|
+
reason: z.ZodEnum<{
|
|
16
|
+
mail_too_large: "mail_too_large";
|
|
17
|
+
nesting_too_deep: "nesting_too_deep";
|
|
18
|
+
no_file_storage: "no_file_storage";
|
|
19
|
+
rejected: "rejected";
|
|
20
|
+
too_large: "too_large";
|
|
21
|
+
}>;
|
|
22
|
+
}, z.core.$strip>>>;
|
|
23
|
+
accountId: z.ZodUUID;
|
|
24
|
+
ownerUserId: z.ZodNullable<z.ZodString>;
|
|
25
|
+
providerName: z.ZodString;
|
|
26
|
+
providerMessageId: z.ZodString;
|
|
27
|
+
messageIdHeader: z.ZodNullable<z.ZodString>;
|
|
28
|
+
providerThreadId: z.ZodNullable<z.ZodString>;
|
|
29
|
+
references: z.ZodArray<z.ZodString>;
|
|
30
|
+
from: z.ZodString;
|
|
31
|
+
to: z.ZodArray<z.ZodString>;
|
|
32
|
+
cc: z.ZodArray<z.ZodString>;
|
|
33
|
+
subject: z.ZodString;
|
|
34
|
+
snippet: z.ZodString;
|
|
35
|
+
receivedAtIso: z.ZodString;
|
|
36
|
+
bodyRef: z.ZodString;
|
|
37
|
+
scope: z.ZodString;
|
|
38
|
+
providerCursor: z.ZodString;
|
|
39
|
+
senderAuthentication: z.ZodOptional<z.ZodNullable<z.ZodObject<{
|
|
40
|
+
authservId: z.ZodString;
|
|
41
|
+
spf: z.ZodEnum<{
|
|
42
|
+
fail: "fail";
|
|
43
|
+
none: "none";
|
|
44
|
+
pass: "pass";
|
|
45
|
+
unknown: "unknown";
|
|
46
|
+
}>;
|
|
47
|
+
dkim: z.ZodEnum<{
|
|
48
|
+
fail: "fail";
|
|
49
|
+
none: "none";
|
|
50
|
+
pass: "pass";
|
|
51
|
+
unknown: "unknown";
|
|
52
|
+
}>;
|
|
53
|
+
dkimDomains: z.ZodArray<z.ZodString>;
|
|
54
|
+
dmarc: z.ZodEnum<{
|
|
55
|
+
fail: "fail";
|
|
56
|
+
none: "none";
|
|
57
|
+
pass: "pass";
|
|
58
|
+
unknown: "unknown";
|
|
59
|
+
}>;
|
|
60
|
+
fromDomain: z.ZodString;
|
|
61
|
+
}, z.core.$strip>>>;
|
|
62
|
+
contentUnavailableReason: z.ZodOptional<z.ZodLiteral<"quarantined">>;
|
|
63
|
+
}, z.core.$strip>;
|
|
64
|
+
export type IngestMessagePayload = z.infer<typeof ingestMessageSchema>;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import * as z from "zod";
|
|
2
|
+
import { senderAuthenticationFieldSchema } from "../sender-auth.js";
|
|
3
|
+
import { inboundContentPayloadShape } from "./message-content.js";
|
|
4
|
+
// =============================================================================
|
|
5
|
+
// Input schema — the normalized provider output (RawInboundMessage,
|
|
6
|
+
// types.ts) plus the envelope (accountId/providerName/providerCursor). The
|
|
7
|
+
// original and attachments ride in-process as bytes and are persisted to file
|
|
8
|
+
// storage here; the event itself stays blob-free (references only).
|
|
9
|
+
// =============================================================================
|
|
10
|
+
export const ingestMessageSchema = z.object({
|
|
11
|
+
accountId: z.uuid(),
|
|
12
|
+
/** Scope inherited from the account — the supervisor knows the
|
|
13
|
+
* MailAccountRecord and passes ownerUserId through. */
|
|
14
|
+
ownerUserId: z.string().max(36).nullable(),
|
|
15
|
+
providerName: z.string().min(1).max(50),
|
|
16
|
+
/** Provider-native Message-ID — idempotency anchor with accountId. */
|
|
17
|
+
providerMessageId: z.string().min(1).max(500),
|
|
18
|
+
/** RFC-5322 Message-ID without <>; null → deterministic fallback. */
|
|
19
|
+
messageIdHeader: z.string().min(1).max(500).nullable(),
|
|
20
|
+
providerThreadId: z.string().min(1).max(500).nullable(),
|
|
21
|
+
/** References/In-Reply-To chain, oldest first. */
|
|
22
|
+
references: z.array(z.string().min(1).max(500)).max(200),
|
|
23
|
+
from: z.string().min(1).max(2000),
|
|
24
|
+
to: z.array(z.string().max(2000)).max(200),
|
|
25
|
+
cc: z.array(z.string().max(2000)).max(200),
|
|
26
|
+
subject: z.string().max(4000),
|
|
27
|
+
snippet: z.string().max(4000),
|
|
28
|
+
receivedAtIso: z.string().min(1),
|
|
29
|
+
/** From the app's storeBody hook; empty lets the handler store the original itself. */
|
|
30
|
+
bodyRef: z.string().max(500),
|
|
31
|
+
scope: z.string().min(1).max(200),
|
|
32
|
+
/** Cursor snapshot at ingest time — used for debugging/replay and stored in
|
|
33
|
+
* metadata.headers, never in the payload. */
|
|
34
|
+
providerCursor: z.string().max(2000),
|
|
35
|
+
senderAuthentication: senderAuthenticationFieldSchema.optional(),
|
|
36
|
+
/** Set when the message is imported from its headers only because it sits in quarantine. */
|
|
37
|
+
contentUnavailableReason: z.literal("quarantined").optional(),
|
|
38
|
+
...inboundContentPayloadShape,
|
|
39
|
+
});
|
|
@@ -1,21 +1,74 @@
|
|
|
1
|
-
import type
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
1
|
+
import { type PreparedIngest } from "./ingest-message-prepare.ts";
|
|
2
|
+
type IngestMessageData = {
|
|
3
|
+
readonly duplicate: true;
|
|
4
|
+
readonly inboundMessageAggregateId: string;
|
|
5
|
+
} | {
|
|
6
|
+
readonly duplicate: false;
|
|
7
|
+
readonly inboundMessageAggregateId: string;
|
|
8
|
+
readonly threadAggregateId: string;
|
|
9
|
+
readonly threadKey: string;
|
|
10
|
+
readonly contentStorage: "stored" | "unavailable";
|
|
11
|
+
};
|
|
12
|
+
export declare const ingestMessageHandler: import("@cosmicdrift/kumiko-types/define-handler").WriteHandlerDefinition<"ingest-message", import("zod").ZodObject<{
|
|
13
|
+
bodyText: import("zod").ZodDefault<import("zod").ZodString>;
|
|
14
|
+
bodyTextTruncated: import("zod").ZodDefault<import("zod").ZodBoolean>;
|
|
15
|
+
rawMime: import("zod").ZodOptional<import("zod").ZodInstanceOf<Uint8Array<ArrayBuffer>>>;
|
|
16
|
+
bodyHtml: import("zod").ZodOptional<import("zod").ZodString>;
|
|
17
|
+
attachments: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodObject<{
|
|
18
|
+
fileName: import("zod").ZodString;
|
|
19
|
+
mimeType: import("zod").ZodString;
|
|
20
|
+
data: import("zod").ZodInstanceOf<Uint8Array<ArrayBuffer>>;
|
|
21
|
+
}, import("zod/v4/core").$strip>>>;
|
|
22
|
+
skippedAttachments: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodObject<{
|
|
23
|
+
mimeType: import("zod").ZodString;
|
|
24
|
+
size: import("zod").ZodNumber;
|
|
25
|
+
reason: import("zod").ZodEnum<{
|
|
26
|
+
mail_too_large: "mail_too_large";
|
|
27
|
+
nesting_too_deep: "nesting_too_deep";
|
|
28
|
+
no_file_storage: "no_file_storage";
|
|
29
|
+
rejected: "rejected";
|
|
30
|
+
too_large: "too_large";
|
|
31
|
+
}>;
|
|
32
|
+
}, import("zod/v4/core").$strip>>>;
|
|
33
|
+
accountId: import("zod").ZodUUID;
|
|
34
|
+
ownerUserId: import("zod").ZodNullable<import("zod").ZodString>;
|
|
35
|
+
providerName: import("zod").ZodString;
|
|
36
|
+
providerMessageId: import("zod").ZodString;
|
|
37
|
+
messageIdHeader: import("zod").ZodNullable<import("zod").ZodString>;
|
|
38
|
+
providerThreadId: import("zod").ZodNullable<import("zod").ZodString>;
|
|
39
|
+
references: import("zod").ZodArray<import("zod").ZodString>;
|
|
40
|
+
from: import("zod").ZodString;
|
|
41
|
+
to: import("zod").ZodArray<import("zod").ZodString>;
|
|
42
|
+
cc: import("zod").ZodArray<import("zod").ZodString>;
|
|
43
|
+
subject: import("zod").ZodString;
|
|
44
|
+
snippet: import("zod").ZodString;
|
|
45
|
+
receivedAtIso: import("zod").ZodString;
|
|
46
|
+
bodyRef: import("zod").ZodString;
|
|
47
|
+
scope: import("zod").ZodString;
|
|
48
|
+
providerCursor: import("zod").ZodString;
|
|
49
|
+
senderAuthentication: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodObject<{
|
|
50
|
+
authservId: import("zod").ZodString;
|
|
51
|
+
spf: import("zod").ZodEnum<{
|
|
52
|
+
fail: "fail";
|
|
53
|
+
none: "none";
|
|
54
|
+
pass: "pass";
|
|
55
|
+
unknown: "unknown";
|
|
56
|
+
}>;
|
|
57
|
+
dkim: import("zod").ZodEnum<{
|
|
58
|
+
fail: "fail";
|
|
59
|
+
none: "none";
|
|
60
|
+
pass: "pass";
|
|
61
|
+
unknown: "unknown";
|
|
62
|
+
}>;
|
|
63
|
+
dkimDomains: import("zod").ZodArray<import("zod").ZodString>;
|
|
64
|
+
dmarc: import("zod").ZodEnum<{
|
|
65
|
+
fail: "fail";
|
|
66
|
+
none: "none";
|
|
67
|
+
pass: "pass";
|
|
68
|
+
unknown: "unknown";
|
|
69
|
+
}>;
|
|
70
|
+
fromDomain: import("zod").ZodString;
|
|
71
|
+
}, import("zod/v4/core").$strip>>>;
|
|
72
|
+
contentUnavailableReason: import("zod").ZodOptional<import("zod").ZodLiteral<"quarantined">>;
|
|
73
|
+
}, import("zod/v4/core").$strip>, IngestMessageData, import("@cosmicdrift/kumiko-types/event-type-map").KumikoEventTypeMap, PreparedIngest, "skip">;
|
|
74
|
+
export {};
|
|
@@ -2,11 +2,14 @@
|
|
|
2
2
|
// (watch callback + fetchSince sync). Accepts a normalized
|
|
3
3
|
// RawInboundMessage and performs atomically in ONE TX:
|
|
4
4
|
//
|
|
5
|
+
// 0. Per-message advisory lock, so a watch/poll race cannot store the same
|
|
6
|
+
// content twice (orphaned FileRefs) before the dedup checks run.
|
|
5
7
|
// 1. Idempotency check (cheap: store_mail_seen_messages; defense in
|
|
6
8
|
// depth: stream existence check on the deterministic aggregateId).
|
|
7
9
|
// 2. threadKey normalization (provider thread ID preferred, otherwise
|
|
8
10
|
// References chain root, otherwise Message-ID = single-message thread).
|
|
9
|
-
// 3.
|
|
11
|
+
// 3. Content storage (original + attachments, only after dedup) and PII
|
|
12
|
+
// encryption (from/to/cc/subject/snippet/bodyText) BEFORE the append —
|
|
10
13
|
// both the event log AND projection contain ciphertext.
|
|
11
14
|
// 4. inbound-message-received append (inline projection writes
|
|
12
15
|
// read_inbound_messages in the same TX). Savepoint-scoped
|
|
@@ -20,71 +23,17 @@
|
|
|
20
23
|
// SystemAdmin-only: the caller is the watch/sync supervisor or
|
|
21
24
|
// the poll cron with a programmatic SystemUser — never a tenant request.
|
|
22
25
|
import { configuredPiiSubjectKms, encryptPiiFieldValues, } from "@cosmicdrift/kumiko-framework/crypto";
|
|
23
|
-
import {
|
|
24
|
-
import { InternalError } from "@cosmicdrift/kumiko-framework/errors";
|
|
26
|
+
import { defineWriteHandler } from "@cosmicdrift/kumiko-framework/engine";
|
|
25
27
|
import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
|
|
26
|
-
import * as z from "zod";
|
|
27
28
|
import { inboundMessageAggregateId, mailThreadAggregateId } from "../aggregate-id.js";
|
|
28
|
-
import { INBOUND_MESSAGE_PII_FIELDS, inboundMessageEntity,
|
|
29
|
-
import { INBOUND_MESSAGE_AGGREGATE_TYPE, INBOUND_MESSAGE_RECEIVED_EVENT_QN,
|
|
30
|
-
import {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
// is intentionally excluded: the caller persists the body to
|
|
35
|
-
// file-foundation BEFORE the ingest call and passes only bodyRef — the
|
|
36
|
-
// handler payload remains blob-free (event-store discipline).
|
|
37
|
-
// =============================================================================
|
|
38
|
-
export const ingestMessageSchema = z.object({
|
|
39
|
-
accountId: z.uuid(),
|
|
40
|
-
/** Scope inherited from the account — the supervisor knows the
|
|
41
|
-
* MailAccountRecord and passes ownerUserId through. */
|
|
42
|
-
ownerUserId: z.string().max(36).nullable(),
|
|
43
|
-
providerName: z.string().min(1).max(50),
|
|
44
|
-
/** Provider-native Message-ID — idempotency anchor with accountId. */
|
|
45
|
-
providerMessageId: z.string().min(1).max(500),
|
|
46
|
-
/** RFC-5322 Message-ID without <>; null → deterministic fallback. */
|
|
47
|
-
messageIdHeader: z.string().min(1).max(500).nullable(),
|
|
48
|
-
providerThreadId: z.string().min(1).max(500).nullable(),
|
|
49
|
-
/** References/In-Reply-To chain, oldest first. */
|
|
50
|
-
references: z.array(z.string().min(1).max(500)).max(200),
|
|
51
|
-
from: z.string().min(1).max(2000),
|
|
52
|
-
to: z.array(z.string().max(2000)).max(200),
|
|
53
|
-
cc: z.array(z.string().max(2000)).max(200),
|
|
54
|
-
subject: z.string().max(4000),
|
|
55
|
-
snippet: z.string().max(4000),
|
|
56
|
-
receivedAtIso: z.string().min(1),
|
|
57
|
-
/** file-foundation-Ref; leer im snippet-only-Mode. */
|
|
58
|
-
bodyRef: z.string().max(500),
|
|
59
|
-
scope: z.string().min(1).max(200),
|
|
60
|
-
/** Cursor snapshot at ingest time — used for debugging/replay and stored in
|
|
61
|
-
* metadata.headers, never in the payload. */
|
|
62
|
-
providerCursor: z.string().max(2000),
|
|
63
|
-
});
|
|
64
|
-
/**
|
|
65
|
-
* Normalizes threadKey:
|
|
66
|
-
* 1. Use the provider thread ID when present — prefix it with the provider
|
|
67
|
-
* so IMAP References keys and Graph conversationIds never collide.
|
|
68
|
-
* 2. Otherwise use the root of the References chain (the oldest Message-ID,
|
|
69
|
-
* which is the thread anchor shared by all replies).
|
|
70
|
-
* 3. Otherwise use the own Message-ID → single-message thread; a later
|
|
71
|
-
* reply carries it as the References root and joins the same thread.
|
|
72
|
-
*/
|
|
73
|
-
function buildThreadKey(p, effectiveMessageIdHeader) {
|
|
74
|
-
if (p.providerThreadId)
|
|
75
|
-
return `${p.providerName}:${p.providerThreadId}`.slice(0, 500);
|
|
76
|
-
const referencesRoot = p.references[0];
|
|
77
|
-
if (referencesRoot)
|
|
78
|
-
return `mid:${referencesRoot}`.slice(0, 500);
|
|
79
|
-
return `mid:${effectiveMessageIdHeader}`.slice(0, 500);
|
|
80
|
-
}
|
|
81
|
-
const THREAD_ROLLUP_MAX_ATTEMPTS = 5;
|
|
82
|
-
// pg_advisory_xact_lock namespace (int4) for the step-5 thread-rollup lock
|
|
83
|
-
// — 'inbm' as ASCII, keeps it disjoint from the framework's other fixed
|
|
84
|
-
// single-int advisory-lock keys (schema bootstrap, es-ops boot).
|
|
85
|
-
const THREAD_ROLLUP_LOCK_NAMESPACE = 0x696e626d;
|
|
29
|
+
import { INBOUND_MESSAGE_PII_FIELDS, inboundMessageEntity, seenMessageTable } from "../entities.js";
|
|
30
|
+
import { INBOUND_MESSAGE_AGGREGATE_TYPE, INBOUND_MESSAGE_RECEIVED_EVENT_QN, } from "../events.js";
|
|
31
|
+
import { finalizePreparedContent, prepareIngestMessage, } from "./ingest-message-prepare.js";
|
|
32
|
+
import { ingestMessageSchema } from "./ingest-message-schema.js";
|
|
33
|
+
import { contentStateOf, MESSAGE_LOCK_NAMESPACE, storeInboundMessageContent, } from "./message-content.js";
|
|
34
|
+
import { appendThreadRollup, buildThreadKey } from "./thread-rollup.js";
|
|
86
35
|
const THREAD_ROLLUP_ADVISORY_LOCK_REASON = "takes the per-thread advisory lock and counts the caller tenant's thread messages; TenantDb has no lock/count API";
|
|
87
|
-
export const ingestMessageHandler = {
|
|
36
|
+
export const ingestMessageHandler = defineWriteHandler({
|
|
88
37
|
name: "ingest-message",
|
|
89
38
|
schema: ingestMessageSchema,
|
|
90
39
|
access: { roles: ["SystemAdmin"] },
|
|
@@ -93,11 +42,14 @@ export const ingestMessageHandler = {
|
|
|
93
42
|
grants: ["unsafeRaw"],
|
|
94
43
|
reason: THREAD_ROLLUP_ADVISORY_LOCK_REASON,
|
|
95
44
|
},
|
|
45
|
+
// Nested (an app handler dispatching ingest-message) there is no phase; the handler then stores in its own transaction.
|
|
46
|
+
beforeTransactionWhenNested: "skip",
|
|
47
|
+
beforeTransaction: prepareIngestMessage,
|
|
96
48
|
handler: async (event, ctx) => {
|
|
97
|
-
|
|
98
|
-
const payload = event.payload;
|
|
49
|
+
const { payload } = event;
|
|
99
50
|
const tenantId = event.user.tenantId;
|
|
100
51
|
const messageAggId = inboundMessageAggregateId(payload.accountId, payload.providerMessageId);
|
|
52
|
+
await ctx.db.advisoryXactLock(MESSAGE_LOCK_NAMESPACE, messageAggId);
|
|
101
53
|
// ---------------------------------------------------------------
|
|
102
54
|
// 1. Idempotency. Use the deduplication anchor row first because it is
|
|
103
55
|
// cheap. The stream check afterward provides defense in depth if
|
|
@@ -142,9 +94,24 @@ export const ingestMessageHandler = {
|
|
|
142
94
|
// (primitives only, upcaster-safe). If no KMS is configured, pass
|
|
143
95
|
// through plaintext (engine-off behavior).
|
|
144
96
|
// ---------------------------------------------------------------
|
|
97
|
+
const prepared = event.prepared;
|
|
98
|
+
const content = prepared?.duplicate === false
|
|
99
|
+
? await finalizePreparedContent(ctx, prepared.content)
|
|
100
|
+
: await storeInboundMessageContent(ctx, {
|
|
101
|
+
accountId: payload.accountId,
|
|
102
|
+
messageAggId,
|
|
103
|
+
bodyRef: payload.bodyRef,
|
|
104
|
+
rawMime: payload.rawMime,
|
|
105
|
+
bodyHtml: payload.bodyHtml,
|
|
106
|
+
attachments: payload.attachments,
|
|
107
|
+
skippedAttachments: payload.skippedAttachments,
|
|
108
|
+
});
|
|
109
|
+
const contentUnavailableReason = payload.contentUnavailableReason ??
|
|
110
|
+
(content.contentStorage === "unavailable" ? "no_file_storage" : null);
|
|
145
111
|
const piiKms = configuredPiiSubjectKms();
|
|
146
112
|
const messagePlainPii = {
|
|
147
113
|
tenantId,
|
|
114
|
+
bodyText: payload.bodyText,
|
|
148
115
|
from: payload.from,
|
|
149
116
|
to: JSON.stringify(payload.to),
|
|
150
117
|
cc: JSON.stringify(payload.cc),
|
|
@@ -169,8 +136,21 @@ export const ingestMessageHandler = {
|
|
|
169
136
|
subject: encryptedMessageFields.subject,
|
|
170
137
|
snippet: encryptedMessageFields.snippet,
|
|
171
138
|
receivedAtIso: payload.receivedAtIso,
|
|
172
|
-
bodyRef:
|
|
139
|
+
bodyRef: content.bodyRef,
|
|
173
140
|
scope: payload.scope,
|
|
141
|
+
senderAuthentication: payload.senderAuthentication ?? null,
|
|
142
|
+
bodyText: encryptedMessageFields.bodyText,
|
|
143
|
+
bodyTextTruncated: payload.bodyTextTruncated,
|
|
144
|
+
attachmentFileIds: content.attachmentFileIds,
|
|
145
|
+
skippedAttachments: content.skippedAttachments,
|
|
146
|
+
contentState: payload.contentUnavailableReason !== undefined
|
|
147
|
+
? "unavailable"
|
|
148
|
+
: contentStateOf({
|
|
149
|
+
bodyText: payload.bodyText,
|
|
150
|
+
hasOriginal: payload.rawMime !== undefined || payload.bodyHtml !== undefined,
|
|
151
|
+
contentStorage: content.contentStorage,
|
|
152
|
+
}),
|
|
153
|
+
contentUnavailableReason,
|
|
174
154
|
};
|
|
175
155
|
const messageHeaders = {
|
|
176
156
|
providerMessageId: payload.providerMessageId,
|
|
@@ -195,73 +175,15 @@ export const ingestMessageHandler = {
|
|
|
195
175
|
data: { duplicate: true, inboundMessageAggregateId: messageAggId },
|
|
196
176
|
};
|
|
197
177
|
}
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
// concurrent ingests on the same thread (Watch-Push vs.
|
|
208
|
-
// Poll-Reconciliation overlap, or two different messages of the
|
|
209
|
-
// same thread arriving at once) converge on the true count.
|
|
210
|
-
// acquireNamespacedAdvisoryLock below serializes this whole
|
|
211
|
-
// countWhere+append section per threadAggId — transaction-scoped,
|
|
212
|
-
// so it survives events.tryAppend's inner SAVEPOINT and releases at
|
|
213
|
-
// the enclosing TX's commit/rollback. Without it, a concurrent
|
|
214
|
-
// commit landing between countWhere and events.tryAppend's own fresh
|
|
215
|
-
// version-read makes the append succeed with a stale count instead
|
|
216
|
-
// of a VersionConflictError, so the retry loop below never sees it
|
|
217
|
-
// as a conflict to retry (the original gap). Unlike step 4, a
|
|
218
|
-
// lost version-conflict race here must NOT be treated as a no-op
|
|
219
|
-
// duplicate — skipping would leave this message's contribution to
|
|
220
|
-
// messageCount/lastMessageAt out of the thread forever. Exhausting
|
|
221
|
-
// all attempts throws, rolling back the whole TX (including the
|
|
222
|
-
// step-4 message append) for a clean re-ingest.
|
|
223
|
-
// ---------------------------------------------------------------
|
|
224
|
-
const threadPlainPii = { tenantId, subject: payload.subject };
|
|
225
|
-
const encryptedThreadFields = piiKms
|
|
226
|
-
? await encryptPiiFieldValues(threadPlainPii, mailThreadEntity, MAIL_THREAD_PII_FIELDS, piiKms, {
|
|
227
|
-
requestId: `inbound-mail-foundation:ingest-message:thread:${threadAggId}`,
|
|
228
|
-
tenantId,
|
|
229
|
-
}, { tenantId, entityName: MAIL_THREAD_AGGREGATE_TYPE })
|
|
230
|
-
: threadPlainPii;
|
|
231
|
-
const threadRollupRunner = ctx.db.unsafeRaw();
|
|
232
|
-
await acquireNamespacedAdvisoryLock(threadRollupRunner, THREAD_ROLLUP_LOCK_NAMESPACE, threadAggId);
|
|
233
|
-
let threadAppendOk = false;
|
|
234
|
-
for (let attempt = 1; attempt <= THREAD_ROLLUP_MAX_ATTEMPTS && !threadAppendOk; attempt++) {
|
|
235
|
-
const threadEvents = await ctx.events.load(threadAggId);
|
|
236
|
-
const lastThreadEvent = threadEvents[threadEvents.length - 1];
|
|
237
|
-
// @cast-boundary engine-payload — eigene events, shape via defineEvent
|
|
238
|
-
const previousThread = lastThreadEvent?.payload;
|
|
239
|
-
const previousLastAt = previousThread?.lastMessageAtIso ?? "";
|
|
240
|
-
const newLastAt = payload.receivedAtIso > previousLastAt ? payload.receivedAtIso : previousLastAt;
|
|
241
|
-
const messageCount = await countWhere(threadRollupRunner, inboundMessagesProjectionTable, {
|
|
242
|
-
tenantId,
|
|
243
|
-
threadKey,
|
|
244
|
-
});
|
|
245
|
-
const threadEventPayload = {
|
|
246
|
-
threadKey,
|
|
247
|
-
subject: encryptedThreadFields.subject,
|
|
248
|
-
lastMessageAtIso: newLastAt,
|
|
249
|
-
messageCount,
|
|
250
|
-
};
|
|
251
|
-
const threadAppend = await ctx.events.tryAppend({
|
|
252
|
-
aggregateId: threadAggId,
|
|
253
|
-
aggregateType: MAIL_THREAD_AGGREGATE_TYPE,
|
|
254
|
-
type: MAIL_THREAD_UPDATED_EVENT_QN,
|
|
255
|
-
payload: threadEventPayload,
|
|
256
|
-
headers: messageHeaders,
|
|
257
|
-
});
|
|
258
|
-
threadAppendOk = threadAppend.ok;
|
|
259
|
-
}
|
|
260
|
-
if (!threadAppendOk) {
|
|
261
|
-
throw new InternalError({
|
|
262
|
-
message: `ingest-message: thread-rollup append for "${threadAggId}" lost the version-conflict race ${THREAD_ROLLUP_MAX_ATTEMPTS} times in a row — aborting for a clean re-ingest instead of persisting a stale messageCount.`,
|
|
263
|
-
});
|
|
264
|
-
}
|
|
178
|
+
await appendThreadRollup(ctx, {
|
|
179
|
+
tenantId,
|
|
180
|
+
threadAggId,
|
|
181
|
+
threadKey,
|
|
182
|
+
subject: payload.subject,
|
|
183
|
+
receivedAtIso: payload.receivedAtIso,
|
|
184
|
+
headers: messageHeaders,
|
|
185
|
+
piiKms,
|
|
186
|
+
});
|
|
265
187
|
// ---------------------------------------------------------------
|
|
266
188
|
// 6. Deduplication anchor. It runs in the same TX as the appends, so
|
|
267
189
|
// if the handler fails, everything is rolled back together.
|
|
@@ -279,7 +201,8 @@ export const ingestMessageHandler = {
|
|
|
279
201
|
inboundMessageAggregateId: messageAggId,
|
|
280
202
|
threadAggregateId: threadAggId,
|
|
281
203
|
threadKey,
|
|
204
|
+
contentStorage: content.contentStorage,
|
|
282
205
|
},
|
|
283
206
|
};
|
|
284
207
|
},
|
|
285
|
-
};
|
|
208
|
+
});
|
|
@@ -1,2 +1,3 @@
|
|
|
1
1
|
import { type QueryHandlerDef } from "@cosmicdrift/kumiko-framework/engine";
|
|
2
|
-
|
|
2
|
+
import type { InboundMailRoles } from "../mail-roles.ts";
|
|
3
|
+
export declare function createListAccountsQuery({ memberRoles, adminRoles, }: InboundMailRoles): QueryHandlerDef;
|