@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.
Files changed (380) hide show
  1. package/dist/account-security/feature.d.ts +2 -0
  2. package/dist/account-security/feature.js +3 -1
  3. package/dist/audit/event-classification.js +1 -0
  4. package/dist/auth-email-password/handlers/change-password.write.d.ts +1 -1
  5. package/dist/auth-email-password/handlers/confirm-account-unlock.write.d.ts +1 -1
  6. package/dist/auth-email-password/handlers/invite-accept-with-login.write.d.ts +1 -1
  7. package/dist/auth-email-password/handlers/invite-accept.write.d.ts +1 -1
  8. package/dist/auth-email-password/handlers/invite-create.write.d.ts +2 -2
  9. package/dist/auth-email-password/handlers/invite-signup-complete.write.d.ts +1 -1
  10. package/dist/auth-email-password/handlers/login.write.d.ts +1 -1
  11. package/dist/auth-email-password/handlers/logout.write.d.ts +1 -1
  12. package/dist/auth-email-password/handlers/request-account-unlock.write.d.ts +1 -1
  13. package/dist/auth-email-password/handlers/request-email-verification.write.d.ts +1 -1
  14. package/dist/auth-email-password/handlers/request-password-reset.write.d.ts +1 -1
  15. package/dist/auth-email-password/handlers/reset-password.write.d.ts +1 -1
  16. package/dist/auth-email-password/handlers/signup-confirm.write.d.ts +1 -1
  17. package/dist/auth-email-password/handlers/signup-request.write.d.ts +1 -1
  18. package/dist/auth-email-password/handlers/switch-tenant-mfa-gate.write.d.ts +1 -1
  19. package/dist/auth-email-password/handlers/token-request-handler.d.ts +1 -1
  20. package/dist/auth-email-password/handlers/verify-email.write.d.ts +1 -1
  21. package/dist/auth-email-password/web/auth-client.d.ts +3 -7
  22. package/dist/auth-email-password/web/auth-client.js +3 -24
  23. package/dist/auth-email-password/web/auth-gate.d.ts +2 -4
  24. package/dist/auth-email-password/web/auth-redirect.d.ts +2 -2
  25. package/dist/auth-email-password/web/auth-redirect.js +3 -12
  26. package/dist/auth-email-password/web/index.d.ts +2 -1
  27. package/dist/auth-email-password/web/index.js +1 -0
  28. package/dist/auth-email-password/web/login-failure.d.ts +9 -0
  29. package/dist/auth-email-password/web/login-failure.js +32 -0
  30. package/dist/auth-email-password/web/login-url.d.ts +5 -0
  31. package/dist/auth-email-password/web/login-url.js +13 -0
  32. package/dist/auth-email-password/web/static-login.d.ts +42 -0
  33. package/dist/auth-email-password/web/static-login.js +122 -0
  34. package/dist/auth-mfa/handlers/disable.write.d.ts +1 -1
  35. package/dist/auth-mfa/handlers/enable-confirm-preauth.write.d.ts +1 -1
  36. package/dist/auth-mfa/handlers/enable-confirm.write.d.ts +1 -1
  37. package/dist/auth-mfa/handlers/enable-start-preauth.write.d.ts +1 -1
  38. package/dist/auth-mfa/handlers/enable-start.write.d.ts +1 -1
  39. package/dist/auth-mfa/handlers/regenerate-recovery.write.d.ts +1 -1
  40. package/dist/auth-mfa/handlers/verify.write.d.ts +1 -1
  41. package/dist/auth-mfa/web/mfa-client.js +4 -43
  42. package/dist/billing-foundation/checkout-core.d.ts +2 -1
  43. package/dist/billing-foundation/checkout-core.js +2 -11
  44. package/dist/billing-foundation/events.d.ts +1 -0
  45. package/dist/billing-foundation/events.js +2 -0
  46. package/dist/billing-foundation/feature.js +1 -1
  47. package/dist/billing-foundation/handlers/create-checkout-session.write.js +9 -2
  48. package/dist/billing-foundation/handlers/process-payment-event.write.d.ts +1 -0
  49. package/dist/billing-foundation/handlers/process-payment-event.write.js +2 -0
  50. package/dist/billing-foundation/index.d.ts +1 -1
  51. package/dist/billing-foundation/one-off-checkout-gate.d.ts +9 -0
  52. package/dist/billing-foundation/one-off-checkout-gate.js +30 -0
  53. package/dist/billing-foundation/one-off-customer.d.ts +6 -0
  54. package/dist/billing-foundation/one-off-customer.js +12 -0
  55. package/dist/billing-foundation/plan-catalog.js +1 -0
  56. package/dist/billing-foundation/types.d.ts +25 -0
  57. package/dist/billing-foundation/web/billing-plans-panel.js +1 -0
  58. package/dist/billing-foundation/web/plan-switch-confirm-dialog.js +7 -3
  59. package/dist/billing-foundation/web/plan-switch-recurring.d.ts +16 -0
  60. package/dist/billing-foundation/web/plan-switch-recurring.js +10 -0
  61. package/dist/billing-foundation/webhook-handler.js +1 -0
  62. package/dist/cap-overview/handlers/caps-usage.query.js +3 -3
  63. package/dist/cap-overview/types.d.ts +2 -0
  64. package/dist/channel-in-app/handlers/mark-all-read.write.d.ts +1 -1
  65. package/dist/channel-in-app/handlers/mark-read.write.d.ts +1 -1
  66. package/dist/compliance-profiles/handlers/set-profile.write.d.ts +1 -1
  67. package/dist/compliance-profiles/web/compliance-profile-catalog.js +8 -1
  68. package/dist/config/handlers/reset.write.d.ts +1 -1
  69. package/dist/config/handlers/set.write.d.ts +1 -1
  70. package/dist/crypto-shredding/handlers/forget-subject.write.d.ts +1 -1
  71. package/dist/delivery/handlers/resubscribe-address.write.d.ts +1 -1
  72. package/dist/delivery/handlers/resubscribe-user.write.d.ts +1 -1
  73. package/dist/delivery/handlers/set-preference.write.d.ts +1 -1
  74. package/dist/delivery/handlers/unsubscribe-address.write.d.ts +1 -1
  75. package/dist/delivery/handlers/unsubscribe-user.write.d.ts +1 -1
  76. package/dist/feature-toggles/handlers/set.write.d.ts +1 -1
  77. package/dist/file-foundation/read-file-ref-content.d.ts +2 -0
  78. package/dist/file-foundation/read-file-ref-content.js +9 -3
  79. package/dist/form-draft/handlers/discard.write.d.ts +1 -1
  80. package/dist/form-draft/handlers/save.write.d.ts +1 -1
  81. package/dist/inbound-mail-foundation/account-health.d.ts +17 -0
  82. package/dist/inbound-mail-foundation/account-health.js +101 -0
  83. package/dist/inbound-mail-foundation/account-poll-schedule.d.ts +19 -0
  84. package/dist/inbound-mail-foundation/account-poll-schedule.js +44 -0
  85. package/dist/inbound-mail-foundation/account-poll.d.ts +24 -0
  86. package/dist/inbound-mail-foundation/account-poll.js +157 -0
  87. package/dist/inbound-mail-foundation/account-record.d.ts +1 -0
  88. package/dist/inbound-mail-foundation/account-record.js +1 -0
  89. package/dist/inbound-mail-foundation/account-wake.d.ts +3 -0
  90. package/dist/inbound-mail-foundation/account-wake.js +17 -0
  91. package/dist/inbound-mail-foundation/connect-callback-verify.d.ts +10 -0
  92. package/dist/inbound-mail-foundation/connect-callback-verify.js +31 -0
  93. package/dist/inbound-mail-foundation/connect-route-responses.d.ts +13 -0
  94. package/dist/inbound-mail-foundation/connect-route-responses.js +16 -0
  95. package/dist/inbound-mail-foundation/connect-routes.js +52 -33
  96. package/dist/inbound-mail-foundation/constants.d.ts +50 -2
  97. package/dist/inbound-mail-foundation/constants.js +53 -3
  98. package/dist/inbound-mail-foundation/content-refetch.d.ts +14 -0
  99. package/dist/inbound-mail-foundation/content-refetch.js +93 -0
  100. package/dist/inbound-mail-foundation/describe-error.d.ts +1 -0
  101. package/dist/inbound-mail-foundation/describe-error.js +5 -0
  102. package/dist/inbound-mail-foundation/entities.d.ts +26 -0
  103. package/dist/inbound-mail-foundation/entities.js +43 -3
  104. package/dist/inbound-mail-foundation/events.d.ts +97 -0
  105. package/dist/inbound-mail-foundation/events.js +57 -2
  106. package/dist/inbound-mail-foundation/feature.d.ts +5 -2
  107. package/dist/inbound-mail-foundation/feature.js +122 -106
  108. package/dist/inbound-mail-foundation/file-storage-failure.d.ts +8 -0
  109. package/dist/inbound-mail-foundation/file-storage-failure.js +19 -0
  110. package/dist/inbound-mail-foundation/handlers/account-address.d.ts +16 -0
  111. package/dist/inbound-mail-foundation/handlers/account-address.js +51 -0
  112. package/dist/inbound-mail-foundation/handlers/acknowledge-quarantine.write.d.ts +8 -0
  113. package/dist/inbound-mail-foundation/handlers/acknowledge-quarantine.write.js +39 -0
  114. package/dist/inbound-mail-foundation/handlers/attach-message-content.write.d.ts +60 -0
  115. package/dist/inbound-mail-foundation/handlers/attach-message-content.write.js +128 -0
  116. package/dist/inbound-mail-foundation/handlers/connect-account.write.d.ts +3 -2
  117. package/dist/inbound-mail-foundation/handlers/connect-account.write.js +97 -56
  118. package/dist/inbound-mail-foundation/handlers/disconnect-account.write.d.ts +2 -1
  119. package/dist/inbound-mail-foundation/handlers/disconnect-account.write.js +55 -42
  120. package/dist/inbound-mail-foundation/handlers/ingest-message-prepare.d.ts +26 -0
  121. package/dist/inbound-mail-foundation/handlers/ingest-message-prepare.js +131 -0
  122. package/dist/inbound-mail-foundation/handlers/ingest-message-schema.d.ts +64 -0
  123. package/dist/inbound-mail-foundation/handlers/ingest-message-schema.js +39 -0
  124. package/dist/inbound-mail-foundation/handlers/ingest-message.write.d.ts +74 -21
  125. package/dist/inbound-mail-foundation/handlers/ingest-message.write.js +57 -134
  126. package/dist/inbound-mail-foundation/handlers/list-accounts.query.d.ts +2 -1
  127. package/dist/inbound-mail-foundation/handlers/list-accounts.query.js +60 -26
  128. package/dist/inbound-mail-foundation/handlers/list-messages.query.d.ts +2 -1
  129. package/dist/inbound-mail-foundation/handlers/list-messages.query.js +43 -29
  130. package/dist/inbound-mail-foundation/handlers/list-quarantine.query.d.ts +3 -0
  131. package/dist/inbound-mail-foundation/handlers/list-quarantine.query.js +75 -0
  132. package/dist/inbound-mail-foundation/handlers/mark-credential-stored.write.d.ts +7 -0
  133. package/dist/inbound-mail-foundation/handlers/mark-credential-stored.write.js +38 -0
  134. package/dist/inbound-mail-foundation/handlers/message-content.d.ts +70 -0
  135. package/dist/inbound-mail-foundation/handlers/message-content.js +137 -0
  136. package/dist/inbound-mail-foundation/handlers/message-content.query.d.ts +19 -0
  137. package/dist/inbound-mail-foundation/handlers/message-content.query.js +59 -0
  138. package/dist/inbound-mail-foundation/handlers/message-detail.query.d.ts +3 -0
  139. package/dist/inbound-mail-foundation/handlers/message-detail.query.js +23 -0
  140. package/dist/inbound-mail-foundation/handlers/reactivate-account.write.d.ts +8 -0
  141. package/dist/inbound-mail-foundation/handlers/reactivate-account.write.js +84 -0
  142. package/dist/inbound-mail-foundation/handlers/retry-quarantined-message.write.d.ts +8 -0
  143. package/dist/inbound-mail-foundation/handlers/retry-quarantined-message.write.js +34 -0
  144. package/dist/inbound-mail-foundation/handlers/scope-visibility.d.ts +10 -2
  145. package/dist/inbound-mail-foundation/handlers/scope-visibility.js +27 -8
  146. package/dist/inbound-mail-foundation/handlers/set-trusted-authserv-id.write.d.ts +13 -0
  147. package/dist/inbound-mail-foundation/handlers/set-trusted-authserv-id.write.js +54 -0
  148. package/dist/inbound-mail-foundation/handlers/thread-rollup.d.ts +24 -0
  149. package/dist/inbound-mail-foundation/handlers/thread-rollup.js +98 -0
  150. package/dist/inbound-mail-foundation/handlers/trusted-authserv-id.d.ts +3 -0
  151. package/dist/inbound-mail-foundation/handlers/trusted-authserv-id.js +3 -0
  152. package/dist/inbound-mail-foundation/handlers/update-account.write.d.ts +13 -3
  153. package/dist/inbound-mail-foundation/handlers/update-account.write.js +62 -46
  154. package/dist/inbound-mail-foundation/i18n.js +72 -2
  155. package/dist/inbound-mail-foundation/inbound-oauth-flow.d.ts +43 -0
  156. package/dist/inbound-mail-foundation/inbound-oauth-flow.js +1 -0
  157. package/dist/inbound-mail-foundation/index.d.ts +19 -6
  158. package/dist/inbound-mail-foundation/index.js +17 -6
  159. package/dist/inbound-mail-foundation/ingest-failures.d.ts +77 -0
  160. package/dist/inbound-mail-foundation/ingest-failures.js +79 -0
  161. package/dist/inbound-mail-foundation/ingest-payload.d.ts +7 -0
  162. package/dist/inbound-mail-foundation/ingest-payload.js +34 -0
  163. package/dist/inbound-mail-foundation/mail-roles.d.ts +21 -0
  164. package/dist/inbound-mail-foundation/mail-roles.js +83 -0
  165. package/dist/inbound-mail-foundation/normalize-inbound-message.d.ts +17 -0
  166. package/dist/inbound-mail-foundation/normalize-inbound-message.js +90 -0
  167. package/dist/inbound-mail-foundation/oauth-access-token.d.ts +3 -1
  168. package/dist/inbound-mail-foundation/oauth-access-token.js +13 -2
  169. package/dist/inbound-mail-foundation/outbound-attachment-access.d.ts +5 -0
  170. package/dist/inbound-mail-foundation/outbound-attachment-access.js +16 -0
  171. package/dist/inbound-mail-foundation/outbound-attachments.d.ts +18 -0
  172. package/dist/inbound-mail-foundation/outbound-attachments.js +77 -0
  173. package/dist/inbound-mail-foundation/outbound-mail.d.ts +15 -1
  174. package/dist/inbound-mail-foundation/outbound-mail.js +4 -0
  175. package/dist/inbound-mail-foundation/probe.js +1 -1
  176. package/dist/inbound-mail-foundation/projection.d.ts +28 -0
  177. package/dist/inbound-mail-foundation/projection.js +25 -3
  178. package/dist/inbound-mail-foundation/provider-errors.d.ts +28 -0
  179. package/dist/inbound-mail-foundation/provider-errors.js +66 -0
  180. package/dist/inbound-mail-foundation/quarantine-entities.d.ts +61 -0
  181. package/dist/inbound-mail-foundation/quarantine-entities.js +47 -0
  182. package/dist/inbound-mail-foundation/quarantine-header-import.d.ts +9 -0
  183. package/dist/inbound-mail-foundation/quarantine-header-import.js +53 -0
  184. package/dist/inbound-mail-foundation/quarantine-retry.d.ts +13 -0
  185. package/dist/inbound-mail-foundation/quarantine-retry.js +97 -0
  186. package/dist/inbound-mail-foundation/quarantine-screens.d.ts +4 -0
  187. package/dist/inbound-mail-foundation/quarantine-screens.js +57 -0
  188. package/dist/inbound-mail-foundation/quarantine.d.ts +13 -0
  189. package/dist/inbound-mail-foundation/quarantine.js +46 -0
  190. package/dist/inbound-mail-foundation/retention-job.d.ts +2 -0
  191. package/dist/inbound-mail-foundation/retention-job.js +62 -0
  192. package/dist/inbound-mail-foundation/retention-sweep.d.ts +4 -0
  193. package/dist/inbound-mail-foundation/retention-sweep.js +35 -8
  194. package/dist/inbound-mail-foundation/screens.d.ts +14 -2
  195. package/dist/inbound-mail-foundation/screens.js +217 -79
  196. package/dist/inbound-mail-foundation/send-from-account.d.ts +11 -1
  197. package/dist/inbound-mail-foundation/send-from-account.js +19 -2
  198. package/dist/inbound-mail-foundation/sender-auth.d.ts +63 -0
  199. package/dist/inbound-mail-foundation/sender-auth.js +198 -0
  200. package/dist/inbound-mail-foundation/supervisor-ingest.d.ts +43 -0
  201. package/dist/inbound-mail-foundation/supervisor-ingest.js +195 -0
  202. package/dist/inbound-mail-foundation/sync-account-now.d.ts +22 -0
  203. package/dist/inbound-mail-foundation/sync-account-now.js +29 -0
  204. package/dist/inbound-mail-foundation/sync-cursor-store.d.ts +9 -0
  205. package/dist/inbound-mail-foundation/sync-cursor-store.js +54 -0
  206. package/dist/inbound-mail-foundation/syncable-accounts.d.ts +16 -0
  207. package/dist/inbound-mail-foundation/syncable-accounts.js +79 -0
  208. package/dist/inbound-mail-foundation/tenant-destroy-hook.js +5 -1
  209. package/dist/inbound-mail-foundation/types.d.ts +61 -62
  210. package/dist/inbound-mail-foundation/types.js +0 -54
  211. package/dist/inbound-mail-foundation/wake-consumer.d.ts +2 -0
  212. package/dist/inbound-mail-foundation/wake-consumer.js +30 -0
  213. package/dist/inbound-mail-foundation/watch-catch-up.d.ts +19 -0
  214. package/dist/inbound-mail-foundation/watch-catch-up.js +33 -0
  215. package/dist/inbound-mail-foundation/watch-lease.d.ts +15 -0
  216. package/dist/inbound-mail-foundation/watch-lease.js +81 -0
  217. package/dist/inbound-mail-foundation/watch-supervisor-types.d.ts +83 -0
  218. package/dist/inbound-mail-foundation/watch-supervisor-types.js +1 -0
  219. package/dist/inbound-mail-foundation/watch-supervisor.d.ts +1 -53
  220. package/dist/inbound-mail-foundation/watch-supervisor.js +123 -290
  221. package/dist/inbound-mail-foundation/web/client-plugin.d.ts +14 -0
  222. package/dist/inbound-mail-foundation/web/client-plugin.js +40 -0
  223. package/dist/inbound-mail-foundation/web/constants.d.ts +5 -0
  224. package/dist/inbound-mail-foundation/web/constants.js +6 -0
  225. package/dist/inbound-mail-foundation/web/index.d.ts +1 -0
  226. package/dist/inbound-mail-foundation/web/index.js +1 -0
  227. package/dist/inbound-provider-imap/connect-mailbox.d.ts +28 -5
  228. package/dist/inbound-provider-imap/connect-mailbox.js +91 -41
  229. package/dist/inbound-provider-imap/connect-my-mailbox.d.ts +13 -0
  230. package/dist/inbound-provider-imap/connect-my-mailbox.js +25 -0
  231. package/dist/inbound-provider-imap/constants.d.ts +12 -1
  232. package/dist/inbound-provider-imap/constants.js +12 -1
  233. package/dist/inbound-provider-imap/credential-document.js +2 -2
  234. package/dist/inbound-provider-imap/download-batch.d.ts +6 -0
  235. package/dist/inbound-provider-imap/download-batch.js +24 -0
  236. package/dist/inbound-provider-imap/feature.d.ts +2 -2
  237. package/dist/inbound-provider-imap/feature.js +49 -32
  238. package/dist/inbound-provider-imap/fetch-content.d.ts +4 -0
  239. package/dist/inbound-provider-imap/fetch-content.js +68 -0
  240. package/dist/inbound-provider-imap/i18n.js +18 -2
  241. package/dist/inbound-provider-imap/imap-client.d.ts +27 -23
  242. package/dist/inbound-provider-imap/imap-client.js +30 -68
  243. package/dist/inbound-provider-imap/index.d.ts +2 -1
  244. package/dist/inbound-provider-imap/index.js +2 -1
  245. package/dist/inbound-provider-imap/mime-content.d.ts +11 -0
  246. package/dist/inbound-provider-imap/mime-content.js +66 -0
  247. package/dist/inbound-provider-imap/parse-message.d.ts +35 -0
  248. package/dist/inbound-provider-imap/parse-message.js +113 -0
  249. package/dist/inbound-provider-imap/reconnect-account.d.ts +17 -0
  250. package/dist/inbound-provider-imap/reconnect-account.js +18 -0
  251. package/dist/inbound-provider-imap/reconnect-mailbox.d.ts +14 -0
  252. package/dist/inbound-provider-imap/reconnect-mailbox.js +71 -0
  253. package/dist/inbound-provider-imap/reconnect-prefill.query.d.ts +3 -0
  254. package/dist/inbound-provider-imap/reconnect-prefill.query.js +34 -0
  255. package/dist/inbound-provider-imap/screens.d.ts +6 -1
  256. package/dist/inbound-provider-imap/screens.js +174 -41
  257. package/dist/inbound-provider-imap/send-mail.d.ts +2 -2
  258. package/dist/inbound-provider-imap/send-mail.js +8 -1
  259. package/dist/inbound-provider-imap/sender-auth-headers.d.ts +3 -0
  260. package/dist/inbound-provider-imap/sender-auth-headers.js +18 -0
  261. package/dist/inbound-provider-inmemory/feature.d.ts +15 -0
  262. package/dist/inbound-provider-inmemory/feature.js +57 -2
  263. package/dist/inbound-provider-inmemory/index.d.ts +1 -1
  264. package/dist/inbound-provider-inmemory/index.js +1 -1
  265. package/dist/jobs/handlers/consumer.write.d.ts +4 -4
  266. package/dist/jobs/handlers/retry.write.d.ts +1 -1
  267. package/dist/jobs/handlers/trigger.write.d.ts +1 -1
  268. package/dist/managed-pages/handlers/set.write.d.ts +1 -1
  269. package/dist/managed-pages/web/i18n.js +1 -0
  270. package/dist/personal-access-tokens/handlers/create.write.d.ts +1 -1
  271. package/dist/personal-access-tokens/handlers/revoke.write.d.ts +1 -1
  272. package/dist/readiness/handlers/run-probes.write.d.ts +1 -1
  273. package/dist/secrets/handlers/delete.write.d.ts +1 -1
  274. package/dist/secrets/handlers/set.write.d.ts +1 -1
  275. package/dist/sessions/handlers/revoke-all-for-user.write.d.ts +1 -1
  276. package/dist/sessions/handlers/revoke-all-others.write.d.ts +1 -1
  277. package/dist/sessions/handlers/revoke.write.d.ts +1 -1
  278. package/dist/subscription-paddle/checkout-config.query.d.ts +3 -0
  279. package/dist/subscription-paddle/checkout-config.query.js +14 -0
  280. package/dist/subscription-paddle/checkout-methods.d.ts +6 -0
  281. package/dist/subscription-paddle/checkout-methods.js +85 -0
  282. package/dist/subscription-paddle/checkout-page.d.ts +19 -0
  283. package/dist/subscription-paddle/checkout-page.js +126 -0
  284. package/dist/subscription-paddle/client.d.ts +24 -0
  285. package/dist/subscription-paddle/client.js +60 -0
  286. package/dist/subscription-paddle/constants.d.ts +16 -0
  287. package/dist/subscription-paddle/constants.js +25 -0
  288. package/dist/subscription-paddle/feature.d.ts +49 -0
  289. package/dist/subscription-paddle/feature.js +192 -0
  290. package/dist/subscription-paddle/index.d.ts +2 -0
  291. package/dist/subscription-paddle/index.js +4 -0
  292. package/dist/subscription-paddle/plan-switch-methods.d.ts +6 -0
  293. package/dist/subscription-paddle/plan-switch-methods.js +114 -0
  294. package/dist/subscription-paddle/price-methods.d.ts +15 -0
  295. package/dist/subscription-paddle/price-methods.js +105 -0
  296. package/dist/subscription-paddle/runtime.d.ts +42 -0
  297. package/dist/subscription-paddle/runtime.js +109 -0
  298. package/dist/subscription-paddle/subscription-state.d.ts +34 -0
  299. package/dist/subscription-paddle/subscription-state.js +48 -0
  300. package/dist/subscription-paddle/tenant-binding.d.ts +8 -0
  301. package/dist/subscription-paddle/tenant-binding.js +26 -0
  302. package/dist/subscription-paddle/verify-webhook.d.ts +4 -0
  303. package/dist/subscription-paddle/verify-webhook.js +55 -0
  304. package/dist/subscription-paddle/webhook-events.d.ts +9 -0
  305. package/dist/subscription-paddle/webhook-events.js +124 -0
  306. package/dist/template-resolver/handlers/collection-item.query.js +2 -2
  307. package/dist/template-resolver/handlers/collection-list.query.js +4 -2
  308. package/dist/template-resolver/handlers/collection-set.write.d.ts +1 -1
  309. package/dist/template-resolver/handlers/collection-shared.d.ts +11 -0
  310. package/dist/template-resolver/handlers/collection-shared.js +16 -0
  311. package/dist/template-resolver/handlers/copy-locale.write.d.ts +1 -1
  312. package/dist/template-resolver/handlers/discard-draft.write.d.ts +2 -2
  313. package/dist/template-resolver/handlers/import-bundle-system.write.d.ts +1 -1
  314. package/dist/template-resolver/handlers/import-bundle.write.d.ts +1 -1
  315. package/dist/template-resolver/handlers/patch-draft.write.d.ts +1 -1
  316. package/dist/template-resolver/handlers/reset-to-system.write.d.ts +1 -1
  317. package/dist/template-resolver/handlers/resource-link-pdf.write.d.ts +1 -1
  318. package/dist/template-resolver/handlers/resource-remove.write.d.ts +1 -1
  319. package/dist/template-resolver/handlers/resource-upload.write.d.ts +1 -1
  320. package/dist/template-resolver/handlers/send-test.write.d.ts +1 -1
  321. package/dist/template-resolver/handlers/set.write.d.ts +1 -1
  322. package/dist/template-resolver/handlers/toggle-status.write.d.ts +4 -4
  323. package/dist/template-resolver/handlers/upsert-system.write.d.ts +1 -1
  324. package/dist/template-resolver/handlers/upsert-tenant.write.d.ts +1 -1
  325. package/dist/template-resolver/web/client-plugin.d.ts +4 -0
  326. package/dist/template-resolver/web/client-plugin.js +134 -52
  327. package/dist/template-resolver/web/i18n.js +1 -1
  328. package/dist/tenant/handlers/add-member.write.d.ts +1 -1
  329. package/dist/tenant/handlers/cancel-invitation.write.d.ts +1 -1
  330. package/dist/tenant/handlers/create.write.d.ts +1 -1
  331. package/dist/tenant/handlers/remove-member.write.d.ts +1 -1
  332. package/dist/tenant/handlers/toggle-enabled.write.d.ts +2 -2
  333. package/dist/tenant/handlers/update-member-roles.write.d.ts +1 -1
  334. package/dist/tenant/handlers/update.write.d.ts +1 -1
  335. package/dist/tenant-handover/handlers/claim.write.d.ts +1 -1
  336. package/dist/tenant-lifecycle/handlers/cancel-destruction.write.d.ts +1 -1
  337. package/dist/tenant-lifecycle/handlers/request-destruction.write.d.ts +1 -1
  338. package/dist/tier-engine/handlers/set-tenant-tier.write.d.ts +1 -1
  339. package/dist/user/handlers/create.write.d.ts +1 -1
  340. package/dist/user/handlers/update.write.d.ts +1 -1
  341. package/dist/user-data-rights/handlers/cancel-deletion.write.d.ts +1 -1
  342. package/dist/user-data-rights/handlers/confirm-deletion-by-token.write.d.ts +1 -1
  343. package/dist/user-data-rights/handlers/lift-restriction.write.d.ts +1 -1
  344. package/dist/user-data-rights/handlers/request-deletion-by-email.write.d.ts +1 -1
  345. package/dist/user-data-rights/handlers/request-deletion.write.d.ts +1 -1
  346. package/dist/user-data-rights/handlers/request-export.write.d.ts +1 -1
  347. package/dist/user-data-rights/handlers/restrict-account.write.d.ts +1 -1
  348. package/dist/user-data-rights/handlers/run-forget-cleanup.write.d.ts +1 -1
  349. package/dist/user-data-rights-defaults/hooks/file-ref.userdata-hook.js +2 -1
  350. package/dist/user-profile/handlers/change-email.write.d.ts +1 -1
  351. package/dist/waitlist/handlers/export-purge.write.d.ts +2 -2
  352. package/dist/waitlist/handlers/invite.write.d.ts +1 -1
  353. package/dist/waitlist/handlers/reject.write.d.ts +1 -1
  354. package/dist/waitlist/handlers/submit.write.d.ts +1 -1
  355. package/package.json +33 -17
  356. package/src/account-security/changes.json +6 -0
  357. package/src/auth-email-password/changes.json +6 -0
  358. package/src/billing-foundation/changes.json +30 -0
  359. package/src/cap-overview/changes.json +6 -0
  360. package/src/files/changes.json +18 -0
  361. package/src/inbound-mail-foundation/changes.json +155 -0
  362. package/src/inbound-provider-imap/changes.json +42 -0
  363. package/src/jobs/changes.json +18 -0
  364. package/src/subscription-paddle/changes.json +15 -0
  365. package/src/template-resolver/changes.json +12 -0
  366. package/dist/subscription-dodo/client.d.ts +0 -17
  367. package/dist/subscription-dodo/client.js +0 -31
  368. package/dist/subscription-dodo/constants.d.ts +0 -12
  369. package/dist/subscription-dodo/constants.js +0 -19
  370. package/dist/subscription-dodo/feature.d.ts +0 -37
  371. package/dist/subscription-dodo/feature.js +0 -144
  372. package/dist/subscription-dodo/index.d.ts +0 -2
  373. package/dist/subscription-dodo/index.js +0 -4
  374. package/dist/subscription-dodo/plugin-methods.d.ts +0 -23
  375. package/dist/subscription-dodo/plugin-methods.js +0 -260
  376. package/dist/subscription-dodo/runtime.d.ts +0 -27
  377. package/dist/subscription-dodo/runtime.js +0 -89
  378. package/dist/subscription-dodo/verify-webhook.d.ts +0 -37
  379. package/dist/subscription-dodo/verify-webhook.js +0 -189
  380. package/src/subscription-dodo/changes.json +0 -14
@@ -0,0 +1,90 @@
1
+ // Provider-agnostic hardening of a fetched message before it is dispatched to
2
+ // ingest-message. The ingest schema rejects oversized or empty fields; one such
3
+ // mail would otherwise block the cursor of its mailbox forever.
4
+ export const INBOUND_MISSING_SENDER = "(no sender)";
5
+ export const INBOUND_BODY_TEXT_MAX_CHARS = 32_000;
6
+ export const INBOUND_BODY_HTML_MAX_CHARS = 5_000_000;
7
+ export const INBOUND_ATTACHMENT_MAX_BYTES = 25 * 1024 * 1024;
8
+ export const INBOUND_MAIL_ATTACHMENTS_MAX_BYTES = 50 * 1024 * 1024;
9
+ // The .eml holds every attachment again, so it shares the per-mail byte budget.
10
+ export const INBOUND_RAW_MIME_MAX_BYTES = INBOUND_MAIL_ATTACHMENTS_MAX_BYTES;
11
+ export const INBOUND_ATTACHMENTS_MAX_COUNT = 50;
12
+ export const INBOUND_SKIPPED_ATTACHMENTS_MAX_COUNT = 200;
13
+ const FROM_MAX = 2000;
14
+ const ADDRESS_MAX = 2000;
15
+ const ADDRESS_LIST_MAX = 200;
16
+ const REFERENCE_MAX = 500;
17
+ const REFERENCES_MAX = 200;
18
+ const SUBJECT_MAX = 4000;
19
+ const SNIPPET_MAX = 4000;
20
+ const MESSAGE_ID_HEADER_MAX = 500;
21
+ function isHighSurrogate(code) {
22
+ return code >= 0xd800 && code <= 0xdbff;
23
+ }
24
+ // Cuts at UTF-16 units like the zod max, but never leaves half a surrogate pair behind.
25
+ function clip(value, max) {
26
+ if (value.length <= max)
27
+ return value;
28
+ const cut = isHighSurrogate(value.charCodeAt(max - 1)) ? max - 1 : max;
29
+ return value.slice(0, cut);
30
+ }
31
+ function limitReferences(references) {
32
+ const usable = references.filter((r) => r.length > 0 && r.length <= REFERENCE_MAX);
33
+ if (usable.length <= REFERENCES_MAX)
34
+ return usable;
35
+ // The root keeps the thread anchor, the newest entries keep the reply chain.
36
+ return [...usable.slice(0, 1), ...usable.slice(usable.length - (REFERENCES_MAX - 1))];
37
+ }
38
+ function splitAttachmentsByLimits(attachments) {
39
+ const stored = [];
40
+ const skipped = [];
41
+ let totalBytes = 0;
42
+ for (const attachment of attachments) {
43
+ const size = attachment.data.byteLength;
44
+ if (size > INBOUND_ATTACHMENT_MAX_BYTES) {
45
+ skipped.push({ mimeType: attachment.mimeType, size, reason: "too_large" });
46
+ }
47
+ else if (totalBytes + size > INBOUND_MAIL_ATTACHMENTS_MAX_BYTES ||
48
+ stored.length >= INBOUND_ATTACHMENTS_MAX_COUNT) {
49
+ skipped.push({ mimeType: attachment.mimeType, size, reason: "mail_too_large" });
50
+ }
51
+ else {
52
+ totalBytes += size;
53
+ stored.push({
54
+ fileName: clip(attachment.fileName, 255),
55
+ mimeType: clip(attachment.mimeType, 255),
56
+ data: attachment.data,
57
+ });
58
+ }
59
+ }
60
+ return { stored, skipped };
61
+ }
62
+ export function normalizeRawInboundMessage(msg) {
63
+ const { text, html, attachments, skippedAttachments, ...envelope } = msg;
64
+ const from = msg.from.trim();
65
+ const fullText = text ?? "";
66
+ const split = splitAttachmentsByLimits(attachments ?? []);
67
+ const bodyHtml = html ?? null;
68
+ const rawMimeTooLarge = msg.rawMime !== null && msg.rawMime.byteLength > INBOUND_RAW_MIME_MAX_BYTES;
69
+ const skippedRawMime = rawMimeTooLarge && msg.rawMime !== null
70
+ ? [{ mimeType: "message/rfc822", size: msg.rawMime.byteLength, reason: "too_large" }]
71
+ : [];
72
+ return {
73
+ ...envelope,
74
+ rawMime: rawMimeTooLarge ? null : msg.rawMime,
75
+ messageIdHeader: msg.messageIdHeader !== null && msg.messageIdHeader.length <= MESSAGE_ID_HEADER_MAX
76
+ ? msg.messageIdHeader
77
+ : null,
78
+ references: limitReferences(msg.references),
79
+ from: from.length === 0 ? INBOUND_MISSING_SENDER : clip(from, FROM_MAX),
80
+ to: msg.to.slice(0, ADDRESS_LIST_MAX).map((a) => clip(a, ADDRESS_MAX)),
81
+ cc: msg.cc.slice(0, ADDRESS_LIST_MAX).map((a) => clip(a, ADDRESS_MAX)),
82
+ subject: clip(msg.subject, SUBJECT_MAX),
83
+ snippet: clip(msg.snippet, SNIPPET_MAX),
84
+ bodyText: clip(fullText, INBOUND_BODY_TEXT_MAX_CHARS),
85
+ bodyTextTruncated: fullText.length > INBOUND_BODY_TEXT_MAX_CHARS,
86
+ bodyHtml: bodyHtml !== null && bodyHtml.length <= INBOUND_BODY_HTML_MAX_CHARS ? bodyHtml : null,
87
+ attachments: split.stored,
88
+ skippedAttachments: [...(skippedAttachments ?? []), ...split.skipped, ...skippedRawMime].slice(0, INBOUND_SKIPPED_ATTACHMENTS_MAX_COUNT),
89
+ };
90
+ }
@@ -1,7 +1,8 @@
1
1
  import { type DbConnection } from "@cosmicdrift/kumiko-framework/db";
2
2
  import type { SecretsContext } from "@cosmicdrift/kumiko-framework/secrets";
3
3
  import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
4
- import { type InboundMailContext, type InboundMailProviderPlugin, type MailAccountRecord, type OAuthTokenSet } from "./types.ts";
4
+ import type { OAuthTokenSet } from "./inbound-oauth-flow.ts";
5
+ import type { InboundMailContext, InboundMailProviderPlugin, MailAccountRecord } from "./types.ts";
5
6
  /** Shared by the OAuth callback and the refresh path so both write the slot identically. */
6
7
  export declare function inboundRefreshTokenSecretOptions(accountId: string): {
7
8
  redact: (plaintext: string) => string;
@@ -26,3 +27,4 @@ export type OAuthAccessTokenManager = {
26
27
  readonly invalidate: (accountId: string) => void;
27
28
  };
28
29
  export declare function createOAuthAccessTokenManager(deps: OAuthAccessTokenManagerDeps): OAuthAccessTokenManager;
30
+ export declare function storeOAuthCallbackCredential(manager: OAuthAccessTokenManager | undefined, secrets: SecretsContext, account: Pick<MailAccountRecord, "id" | "tenantId">, tokens: OAuthTokenSet, refreshToken: string): Promise<void>;
@@ -18,7 +18,7 @@
18
18
  import { acquireNamespacedAdvisoryLock, transaction, } from "@cosmicdrift/kumiko-framework/db";
19
19
  import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
20
20
  import { InboundMailAuthMethods, inboundCredentialSecretKey } from "./constants.js";
21
- import { InboundAuthError, } from "./types.js";
21
+ import { InboundAuthError, InboundCredentialNotStoredError } from "./provider-errors.js";
22
22
  // 'inoa' as ASCII — disjoint from the other fixed advisory-lock namespaces.
23
23
  const OAUTH_REFRESH_LOCK_NAMESPACE = 0x696e6f61;
24
24
  const ACCESS_TOKEN_EXPIRY_MARGIN = Temporal.Duration.from({ minutes: 2 });
@@ -86,7 +86,7 @@ export function createOAuthAccessTokenManager(deps) {
86
86
  const secrets = deps.secrets.withRunner(tx);
87
87
  const stored = await secrets.get(account.tenantId, secretKey);
88
88
  if (!stored) {
89
- throw new InboundAuthError("no refresh token stored for account");
89
+ throw new InboundCredentialNotStoredError("no refresh token stored for account");
90
90
  }
91
91
  const currentRefreshToken = stored.reveal();
92
92
  const tokens = await refreshWithTimeout(plugin, account, currentRefreshToken);
@@ -133,3 +133,14 @@ export function createOAuthAccessTokenManager(deps) {
133
133
  },
134
134
  };
135
135
  }
136
+ // Refresh token into the per-account secret slot (slot = accountId); access tokens (~1h) are never
137
+ // persisted. A shared manager writes under the account's refresh lock and primes its cache.
138
+ export async function storeOAuthCallbackCredential(manager, secrets, account, tokens, refreshToken) {
139
+ if (manager) {
140
+ await manager.storeRefreshToken(account, refreshToken);
141
+ manager.primeFromExchange(account, tokens);
142
+ }
143
+ else {
144
+ await secrets.set(account.tenantId, inboundCredentialSecretKey(account.id), refreshToken, inboundRefreshTokenSecretOptions(account.id));
145
+ }
146
+ }
@@ -0,0 +1,5 @@
1
+ import { type CanReadFileRefContext, type FileRef } from "@cosmicdrift/kumiko-framework/files";
2
+ import type { ResolveOutboundAttachmentsContext } from "./outbound-attachments.ts";
3
+ export type OutboundAttachmentAccessContext = ResolveOutboundAttachmentsContext & CanReadFileRefContext;
4
+ /** The file of the sender's tenant, or null: another tenant's and a deleted file read like a missing one. */
5
+ export declare function loadAttachableFileRef(ctx: OutboundAttachmentAccessContext, fileRefId: string): Promise<FileRef | null>;
@@ -0,0 +1,16 @@
1
+ // Who may attach a stored file to an outgoing mail: exactly who may download it. Attachments of
2
+ // imported mails are bound to the mail, so the file guard answers with the mail's visibility.
3
+ import { selectMany } from "@cosmicdrift/kumiko-framework/db";
4
+ import { isUuid } from "@cosmicdrift/kumiko-framework/engine";
5
+ import { fileRefsTable, } from "@cosmicdrift/kumiko-framework/files";
6
+ /** The file of the sender's tenant, or null: another tenant's and a deleted file read like a missing one. */
7
+ export async function loadAttachableFileRef(ctx, fileRefId) {
8
+ if (!isUuid(fileRefId))
9
+ return null;
10
+ const [fileRef] = await selectMany(ctx.db, fileRefsTable, {
11
+ id: fileRefId,
12
+ tenantId: ctx.user.tenantId,
13
+ isDeleted: false,
14
+ });
15
+ return fileRef ?? null;
16
+ }
@@ -0,0 +1,18 @@
1
+ import type { HandlerContext } from "@cosmicdrift/kumiko-framework/engine";
2
+ import { type OutboundAttachment } from "./outbound-mail.ts";
3
+ export type ResolveOutboundAttachmentsContext = Pick<HandlerContext, "db" | "user" | "services" | "obs" | "registry"> & {
4
+ readonly dispatch: Pick<HandlerContext["dispatch"], "query">;
5
+ };
6
+ export type ResolvedOutboundAttachments = {
7
+ readonly isSuccess: true;
8
+ readonly attachments: readonly OutboundAttachment[];
9
+ readonly fileIds: readonly string[];
10
+ } | {
11
+ readonly isSuccess: false;
12
+ readonly failure: "attachmentInvalid" | "attachmentsTooLarge";
13
+ };
14
+ export declare function readableFileName(file: {
15
+ readonly id: string;
16
+ readonly fileName: string;
17
+ }): Promise<string>;
18
+ export declare function resolveOutboundAttachments(ctx: ResolveOutboundAttachmentsContext, fileIds: readonly string[]): Promise<ResolvedOutboundAttachments>;
@@ -0,0 +1,77 @@
1
+ // Turns the file references of an outgoing mail into bytes. Only the sender's own tenant is
2
+ // searched, so another tenant's file reads exactly like a missing one; a file the caller may not
3
+ // read counts as missing too (outbound-attachment-access.ts).
4
+ import { collectPiiSubjectFields, configuredPiiSubjectKms, decryptPiiFieldValues, isPiiCiphertext, PII_ERASED_SENTINEL, } from "@cosmicdrift/kumiko-framework/crypto";
5
+ import { canCallerReadFileRef, fileRefEntity } from "@cosmicdrift/kumiko-framework/files";
6
+ import { FileRefTooLargeError, fileContextForTenant, readFileRefContent, } from "../file-foundation/index.js";
7
+ import { loadAttachableFileRef } from "./outbound-attachment-access.js";
8
+ import { OUTBOUND_ATTACHMENTS_MAX_BYTES } from "./outbound-mail.js";
9
+ const FALLBACK_ATTACHMENT_NAME = "attachment";
10
+ const PII_SUBJECT_FIELDS = collectPiiSubjectFields(fileRefEntity);
11
+ // The stored name is personal data and may be ciphertext; a name that cannot be read must not
12
+ // stop the mail, and ciphertext or the erased marker never goes into a header.
13
+ export async function readableFileName(file) {
14
+ const storedName = file.fileName;
15
+ if (!isPiiCiphertext(storedName))
16
+ return storedName;
17
+ const kms = configuredPiiSubjectKms();
18
+ if (!kms)
19
+ return FALLBACK_ATTACHMENT_NAME;
20
+ try {
21
+ const decrypted = await decryptPiiFieldValues({ fileName: storedName }, PII_SUBJECT_FIELDS, kms, { requestId: `outbound-attachment:${file.id}` });
22
+ const name = decrypted["fileName"];
23
+ if (typeof name !== "string" || isPiiCiphertext(name) || name === PII_ERASED_SENTINEL) {
24
+ return FALLBACK_ATTACHMENT_NAME;
25
+ }
26
+ return name;
27
+ }
28
+ catch {
29
+ // skip: broken crypto metadata must not block the mail; the attachment keeps a neutral name.
30
+ return FALLBACK_ATTACHMENT_NAME;
31
+ }
32
+ }
33
+ export async function resolveOutboundAttachments(ctx, fileIds) {
34
+ const uniqueIds = [...new Set(fileIds)];
35
+ const attachments = [];
36
+ let remainingBytes = OUTBOUND_ATTACHMENTS_MAX_BYTES;
37
+ const tenantId = ctx.user.tenantId;
38
+ for (const fileRefId of uniqueIds) {
39
+ // A file the caller may not read answers like an unknown id, so ids cannot be probed.
40
+ const fileRef = await loadAttachableFileRef(ctx, fileRefId);
41
+ if (fileRef === null || !(await canCallerReadFileRef(ctx, fileRef))) {
42
+ return { isSuccess: false, failure: "attachmentInvalid" };
43
+ }
44
+ let found;
45
+ try {
46
+ found = await readFileRefContent({
47
+ db: ctx.db,
48
+ filesForTenant: (forTenantId) => fileContextForTenant(ctx, tenantId, forTenantId),
49
+ fileRefId,
50
+ allowedTenantIds: [tenantId],
51
+ maxBytes: remainingBytes,
52
+ });
53
+ }
54
+ catch (err) {
55
+ if (err instanceof FileRefTooLargeError) {
56
+ return { isSuccess: false, failure: "attachmentsTooLarge" };
57
+ }
58
+ ctx.obs.log.warn("outbound attachment could not be read", {
59
+ fileRefId,
60
+ errorName: err instanceof Error ? err.name : typeof err,
61
+ });
62
+ return { isSuccess: false, failure: "attachmentInvalid" };
63
+ }
64
+ if (found === null)
65
+ return { isSuccess: false, failure: "attachmentInvalid" };
66
+ if (found.content.byteLength > remainingBytes) {
67
+ return { isSuccess: false, failure: "attachmentsTooLarge" };
68
+ }
69
+ remainingBytes -= found.content.byteLength;
70
+ attachments.push({
71
+ fileName: await readableFileName({ id: fileRefId, fileName: found.fileName }),
72
+ mimeType: found.contentType,
73
+ data: found.content,
74
+ });
75
+ }
76
+ return { isSuccess: true, attachments, fileIds: uniqueIds };
77
+ }
@@ -1,4 +1,6 @@
1
1
  import * as z from "zod";
2
+ /** Raw bytes, not the encoded size: base64 grows them by a third, which stays under the usual 25 MB SMTP limit. */
3
+ export declare const OUTBOUND_ATTACHMENTS_MAX_BYTES: number;
2
4
  export declare const outboundMailMessageSchema: z.ZodObject<{
3
5
  to: z.ZodArray<z.ZodEmail>;
4
6
  cc: z.ZodOptional<z.ZodArray<z.ZodEmail>>;
@@ -7,12 +9,24 @@ export declare const outboundMailMessageSchema: z.ZodObject<{
7
9
  html: z.ZodOptional<z.ZodString>;
8
10
  inReplyTo: z.ZodOptional<z.ZodString>;
9
11
  references: z.ZodOptional<z.ZodArray<z.ZodString>>;
12
+ attachmentFileIds: z.ZodOptional<z.ZodArray<z.ZodUUID>>;
10
13
  }, z.core.$strip>;
11
14
  export type OutboundMailMessage = z.infer<typeof outboundMailMessageSchema>;
12
- export type OutboundMailSent = {
15
+ /** An attachment whose file reference was resolved to bytes before the provider sends. */
16
+ export type OutboundAttachment = {
17
+ readonly fileName: string;
18
+ readonly mimeType: string;
19
+ readonly data: Uint8Array;
20
+ };
21
+ /** What a provider plugin reports about a mail it sent. */
22
+ export type ProviderSentMail = {
13
23
  /** Message-ID header of the sent mail, without angle brackets. */
14
24
  readonly messageIdHeader: string;
15
25
  };
26
+ export type OutboundMailSent = ProviderSentMail & {
27
+ /** The file references that went out as attachments, for the caller's own record of the mail. */
28
+ readonly attachmentFileIds: readonly string[];
29
+ };
16
30
  /** The mailbox has no outgoing server stored, for example a credential document from before
17
31
  * sending existed. The tenant has to connect the mailbox again. */
18
32
  export declare class MailSendNotConfiguredError extends Error {
@@ -3,6 +3,9 @@
3
3
  import * as z from "zod";
4
4
  const MAX_RECIPIENTS = 50;
5
5
  const MAX_REFERENCES = 100;
6
+ const MAX_ATTACHMENTS = 10;
7
+ /** Raw bytes, not the encoded size: base64 grows them by a third, which stays under the usual 25 MB SMTP limit. */
8
+ export const OUTBOUND_ATTACHMENTS_MAX_BYTES = 18 * 1024 * 1024;
6
9
  // Message ids travel without angle brackets, like RawInboundMessage.references. Anything that
7
10
  // could close the bracket or start a new header is refused instead of being encoded.
8
11
  const messageIdSchema = z
@@ -22,6 +25,7 @@ export const outboundMailMessageSchema = z
22
25
  html: z.string().optional(),
23
26
  inReplyTo: messageIdSchema.optional(),
24
27
  references: z.array(messageIdSchema).max(MAX_REFERENCES).optional(),
28
+ attachmentFileIds: z.array(z.uuid()).max(MAX_ATTACHMENTS).optional(),
25
29
  })
26
30
  .refine((message) => message.text !== undefined || message.html !== undefined, {
27
31
  message: "needs text or html",
@@ -4,9 +4,9 @@ import { toMailAccountRecord } from "./account-record.js";
4
4
  import { InboundMailAccountStatuses } from "./constants.js";
5
5
  import { INBOUND_PROBE_KEYS } from "./probe-keys.js";
6
6
  import { mailAccountsProjectionTable } from "./projection.js";
7
+ import { isInboundAuthError } from "./provider-errors.js";
7
8
  import { resolveInboundProviderForAccount } from "./provider-factory.js";
8
9
  import { MAIL_ACCOUNT_LIST_SCREEN_QN } from "./screens.js";
9
- import { isInboundAuthError } from "./types.js";
10
10
  const SHORT_ID_LENGTH = 8;
11
11
  function providerContext(ctx) {
12
12
  const { configResolver, secrets } = ctx.services;
@@ -17,9 +17,15 @@ export declare const mailAccountsProjectionTable: import("@cosmicdrift/kumiko-fr
17
17
  readonly status: import("@cosmicdrift/kumiko-types/fields").EntityTextFieldDef & {
18
18
  required: true;
19
19
  };
20
+ readonly lastError: import("@cosmicdrift/kumiko-types/fields").EntityTextFieldDef & {
21
+ required: false;
22
+ };
20
23
  readonly watchState: import("@cosmicdrift/kumiko-types/fields").EntityTextFieldDef & {
21
24
  required: false;
22
25
  };
26
+ readonly trustedAuthservId: import("@cosmicdrift/kumiko-types/fields").EntityTextFieldDef & {
27
+ required: false;
28
+ };
23
29
  readonly connectedAt: {
24
30
  readonly type: "timestamp";
25
31
  readonly description?: string;
@@ -85,6 +91,26 @@ export declare const inboundMessagesProjectionTable: import("@cosmicdrift/kumiko
85
91
  readonly scope: import("@cosmicdrift/kumiko-types/fields").EntityTextFieldDef & {
86
92
  required: false;
87
93
  };
94
+ readonly bodyText: import("@cosmicdrift/kumiko-types/fields").EntityLongTextFieldDef & {
95
+ required: false;
96
+ };
97
+ readonly bodyTextTruncated: import("@cosmicdrift/kumiko-types/fields").BooleanFieldDef & {
98
+ required: false;
99
+ default: boolean;
100
+ };
101
+ readonly attachmentFileIds: import("@cosmicdrift/kumiko-types/fields").FilesFieldDef;
102
+ readonly skippedAttachments: import("@cosmicdrift/kumiko-types/fields").EntityTextFieldDef & {
103
+ required: false;
104
+ };
105
+ readonly senderAuthentication: import("@cosmicdrift/kumiko-types/fields").EntityTextFieldDef & {
106
+ required: false;
107
+ };
108
+ readonly contentState: import("@cosmicdrift/kumiko-types/fields").EntityTextFieldDef & {
109
+ required: false;
110
+ };
111
+ readonly contentUnavailableReason: import("@cosmicdrift/kumiko-types/fields").EntityTextFieldDef & {
112
+ required: false;
113
+ };
88
114
  }, "tenant">>;
89
115
  export declare const mailThreadsProjectionTable: import("@cosmicdrift/kumiko-framework/db").EntityTable<import("@cosmicdrift/kumiko-types/fields").EntityDefinition<{
90
116
  readonly threadKey: import("@cosmicdrift/kumiko-types/fields").EntityTextFieldDef & {
@@ -137,5 +163,7 @@ export declare const applyMailAccountUpdated: import("@cosmicdrift/kumiko-types/
137
163
  export declare const applyMailAccountDisconnected: import("@cosmicdrift/kumiko-types/projection").SingleStreamApplyFn;
138
164
  /** inbound-message-received → INSERT ... ON CONFLICT DO NOTHING. */
139
165
  export declare const applyInboundMessageReceived: import("@cosmicdrift/kumiko-types/projection").SingleStreamApplyFn;
166
+ /** inbound-message-content-fetched → fills the content columns of the already projected row. */
167
+ export declare const applyInboundMessageContentFetched: import("@cosmicdrift/kumiko-types/projection").SingleStreamApplyFn;
140
168
  /** mail-thread-updated → full UPSERT with the payload snapshot. */
141
169
  export declare const applyMailThreadUpdated: import("@cosmicdrift/kumiko-types/projection").SingleStreamApplyFn;
@@ -17,7 +17,7 @@
17
17
  // arrive as ciphertext because they are encrypted BEFORE the append in the
18
18
  // write handler. The applies only copy them through; decryption happens only
19
19
  // in the list queries.
20
- import { buildEntityTable, insertOnConflictDoNothing, requireEntityTableMeta, upsertOnConflict, } from "@cosmicdrift/kumiko-framework/db";
20
+ import { buildEntityTable, insertOnConflictDoNothing, requireEntityTableMeta, updateMany, upsertOnConflict, } from "@cosmicdrift/kumiko-framework/db";
21
21
  import { defineApply } from "@cosmicdrift/kumiko-framework/engine";
22
22
  import { inboundMessageEntity, mailAccountEntity, mailThreadEntity } from "./entities.js";
23
23
  // Drizzle table instances derived from the entity shapes, shared between
@@ -46,6 +46,8 @@ const applyMailAccountUpsert = defineApply(async (event, tx) => {
46
46
  address: p.address,
47
47
  status: p.status,
48
48
  watchState: p.watchState,
49
+ lastError: p.lastError,
50
+ trustedAuthservId: p.trustedAuthservId,
49
51
  };
50
52
  await upsertOnConflict(tx, mailAccountsProjectionMeta, {
51
53
  id: event.aggregateId,
@@ -66,8 +68,8 @@ export const applyMailAccountUpdated = applyMailAccountUpsert;
66
68
  export const applyMailAccountDisconnected = applyMailAccountUpsert;
67
69
  // =============================================================================
68
70
  // inbound-message — exactly one received event per stream (deterministic
69
- // aggregateId). INSERT-ignore makes replays no-ops on the primary key;
70
- // there is no update case.
71
+ // aggregateId). INSERT-ignore makes replays no-ops on the primary key; the
72
+ // only later change is the content-fetched event for snippet-only imports.
71
73
  // =============================================================================
72
74
  /** inbound-message-received → INSERT ... ON CONFLICT DO NOTHING. */
73
75
  export const applyInboundMessageReceived = defineApply(async (event, tx) => {
@@ -87,8 +89,28 @@ export const applyInboundMessageReceived = defineApply(async (event, tx) => {
87
89
  receivedAt: p.receivedAtIso,
88
90
  bodyRef: p.bodyRef,
89
91
  scope: p.scope,
92
+ bodyText: p.bodyText,
93
+ bodyTextTruncated: p.bodyTextTruncated,
94
+ attachmentFileIds: p.attachmentFileIds,
95
+ skippedAttachments: JSON.stringify(p.skippedAttachments),
96
+ senderAuthentication: JSON.stringify(p.senderAuthentication),
97
+ contentState: p.contentState,
98
+ contentUnavailableReason: p.contentUnavailableReason,
90
99
  });
91
100
  });
101
+ /** inbound-message-content-fetched → fills the content columns of the already projected row. */
102
+ export const applyInboundMessageContentFetched = defineApply(async (event, tx) => {
103
+ const p = event.payload;
104
+ await updateMany(tx, inboundMessagesProjectionMeta, {
105
+ bodyRef: p.bodyRef,
106
+ bodyText: p.bodyText,
107
+ bodyTextTruncated: p.bodyTextTruncated,
108
+ attachmentFileIds: p.attachmentFileIds,
109
+ skippedAttachments: JSON.stringify(p.skippedAttachments),
110
+ contentState: p.contentState,
111
+ contentUnavailableReason: p.contentUnavailableReason,
112
+ }, { id: event.aggregateId });
113
+ });
92
114
  // =============================================================================
93
115
  // mail-thread — rollup per (tenantId, threadKey). The write handler computes
94
116
  // messageCount/lastMessageAt and appends the updated event with the NEW state.
@@ -0,0 +1,28 @@
1
+ export declare class InboundAuthError extends Error {
2
+ readonly kind: "inbound-auth-error";
3
+ constructor(message: string);
4
+ }
5
+ /** The credential secret is not there (yet). Still an auth error for a regular poll; a sync woken
6
+ * right after connect treats it as "not ready" because the secret is written after the account. */
7
+ export declare class InboundCredentialNotStoredError extends InboundAuthError {
8
+ readonly credentialNotStored: true;
9
+ constructor(message: string);
10
+ }
11
+ export declare class InboundRateLimitError extends Error {
12
+ readonly kind: "inbound-rate-limit-error";
13
+ readonly retryAfterMs: number;
14
+ constructor(message: string, retryAfterMs: number);
15
+ }
16
+ export declare class InboundCursorInvalidError extends Error {
17
+ readonly kind: "inbound-cursor-invalid-error";
18
+ constructor(message: string);
19
+ }
20
+ export declare class InboundTransientError extends Error {
21
+ readonly kind: "inbound-transient-error";
22
+ constructor(message: string);
23
+ }
24
+ export declare function isInboundAuthError(e: unknown): e is InboundAuthError;
25
+ export declare function isInboundCredentialNotStoredError(e: unknown): e is InboundCredentialNotStoredError;
26
+ export declare function isInboundRateLimitError(e: unknown): e is InboundRateLimitError;
27
+ export declare function isInboundCursorInvalidError(e: unknown): e is InboundCursorInvalidError;
28
+ export declare function isInboundTransientError(e: unknown): e is InboundTransientError;
@@ -0,0 +1,66 @@
1
+ // =============================================================================
2
+ // Typed errors handled uniformly by the Foundation during polling:
3
+ // InboundAuthError → status=auth_error, no retry
4
+ // InboundRateLimitError → abort poll, wait for the next cron tick
5
+ // InboundCursorInvalidError → reset cursor + full resync in the backfill
6
+ // window; deduplication handles duplicates
7
+ // InboundTransientError → job retry (retries: 3, exponential)
8
+ // =============================================================================
9
+ //
10
+ // Use a `kind` discriminant instead of instanceof: plugins and the Foundation
11
+ // may run in separate bundles (dual-package-hazard), and instanceof is
12
+ // unreliable across realm or package-copy boundaries.
13
+ export class InboundAuthError extends Error {
14
+ kind = "inbound-auth-error";
15
+ constructor(message) {
16
+ super(message);
17
+ this.name = "InboundAuthError";
18
+ }
19
+ }
20
+ /** The credential secret is not there (yet). Still an auth error for a regular poll; a sync woken
21
+ * right after connect treats it as "not ready" because the secret is written after the account. */
22
+ export class InboundCredentialNotStoredError extends InboundAuthError {
23
+ credentialNotStored = true;
24
+ constructor(message) {
25
+ super(message);
26
+ this.name = "InboundCredentialNotStoredError";
27
+ }
28
+ }
29
+ export class InboundRateLimitError extends Error {
30
+ kind = "inbound-rate-limit-error";
31
+ retryAfterMs;
32
+ constructor(message, retryAfterMs) {
33
+ super(message);
34
+ this.name = "InboundRateLimitError";
35
+ this.retryAfterMs = retryAfterMs;
36
+ }
37
+ }
38
+ export class InboundCursorInvalidError extends Error {
39
+ kind = "inbound-cursor-invalid-error";
40
+ constructor(message) {
41
+ super(message);
42
+ this.name = "InboundCursorInvalidError";
43
+ }
44
+ }
45
+ export class InboundTransientError extends Error {
46
+ kind = "inbound-transient-error";
47
+ constructor(message) {
48
+ super(message);
49
+ this.name = "InboundTransientError";
50
+ }
51
+ }
52
+ export function isInboundAuthError(e) {
53
+ return e instanceof Error && "kind" in e && e.kind === "inbound-auth-error";
54
+ }
55
+ export function isInboundCredentialNotStoredError(e) {
56
+ return isInboundAuthError(e) && "credentialNotStored" in e && e.credentialNotStored === true;
57
+ }
58
+ export function isInboundRateLimitError(e) {
59
+ return e instanceof Error && "kind" in e && e.kind === "inbound-rate-limit-error";
60
+ }
61
+ export function isInboundCursorInvalidError(e) {
62
+ return e instanceof Error && "kind" in e && e.kind === "inbound-cursor-invalid-error";
63
+ }
64
+ export function isInboundTransientError(e) {
65
+ return e instanceof Error && "kind" in e && e.kind === "inbound-transient-error";
66
+ }
@@ -0,0 +1,61 @@
1
+ export declare const QUARANTINE_REASON_CODES: readonly ["unparseable", "invalid_message", "ingest_failed"];
2
+ export type QuarantineReasonCode = (typeof QUARANTINE_REASON_CODES)[number];
3
+ /** A provider message the ingest cannot take. No subject or sender, so nothing here is personal data;
4
+ * the UID is enough for the operator to find the mail in the mailbox. */
5
+ export declare const quarantineEntity: import("@cosmicdrift/kumiko-types/fields").EntityDefinition<{
6
+ readonly accountId: import("@cosmicdrift/kumiko-types/fields").EntityTextFieldDef & {
7
+ required: true;
8
+ };
9
+ readonly providerMessageId: import("@cosmicdrift/kumiko-types/fields").EntityTextFieldDef & {
10
+ required: true;
11
+ };
12
+ readonly reasonCode: import("@cosmicdrift/kumiko-types/fields").EntityTextFieldDef & {
13
+ required: true;
14
+ };
15
+ readonly quarantinedAt: {
16
+ readonly type: "timestamp";
17
+ readonly description?: string;
18
+ readonly required?: boolean;
19
+ readonly sortable?: boolean;
20
+ readonly filterable?: boolean;
21
+ readonly sensitive?: boolean;
22
+ readonly access?: import("@cosmicdrift/kumiko-types/fields").FieldAccess;
23
+ readonly locatedBy?: string;
24
+ readonly min?: string;
25
+ readonly max?: string;
26
+ readonly locale?: string;
27
+ } & import("@cosmicdrift/kumiko-types/fields").ResolvedPiiFlags & {
28
+ required: true;
29
+ };
30
+ readonly acknowledgedAt: {
31
+ readonly type: "timestamp";
32
+ readonly description?: string;
33
+ readonly required?: boolean;
34
+ readonly sortable?: boolean;
35
+ readonly filterable?: boolean;
36
+ readonly sensitive?: boolean;
37
+ readonly access?: import("@cosmicdrift/kumiko-types/fields").FieldAccess;
38
+ readonly locatedBy?: string;
39
+ readonly min?: string;
40
+ readonly max?: string;
41
+ readonly locale?: string;
42
+ } & import("@cosmicdrift/kumiko-types/fields").ResolvedPiiFlags & {
43
+ required: false;
44
+ };
45
+ readonly retryRequestedAt: {
46
+ readonly type: "timestamp";
47
+ readonly description?: string;
48
+ readonly required?: boolean;
49
+ readonly sortable?: boolean;
50
+ readonly filterable?: boolean;
51
+ readonly sensitive?: boolean;
52
+ readonly access?: import("@cosmicdrift/kumiko-types/fields").FieldAccess;
53
+ readonly locatedBy?: string;
54
+ readonly min?: string;
55
+ readonly max?: string;
56
+ readonly locale?: string;
57
+ } & import("@cosmicdrift/kumiko-types/fields").ResolvedPiiFlags & {
58
+ required: false;
59
+ };
60
+ }, "tenant">;
61
+ export declare const quarantineTable: import("@cosmicdrift/kumiko-types/entity-table-meta-types").EntityTableMeta & import("@cosmicdrift/kumiko-types/executor-brand").Writable;
@@ -0,0 +1,47 @@
1
+ import { deriveEntityTableMeta } from "@cosmicdrift/kumiko-framework/db";
2
+ import { access, createEntity, createTextField, createTimestampField, } from "@cosmicdrift/kumiko-framework/engine";
3
+ export const QUARANTINE_REASON_CODES = ["unparseable", "invalid_message", "ingest_failed"];
4
+ /** A provider message the ingest cannot take. No subject or sender, so nothing here is personal data;
5
+ * the UID is enough for the operator to find the mail in the mailbox. */
6
+ export const quarantineEntity = createEntity({
7
+ table: "store_mail_quarantine",
8
+ softDelete: false,
9
+ indexes: [{ unique: true, columns: ["tenantId", "accountId", "providerMessageId"] }],
10
+ fields: {
11
+ accountId: createTextField({
12
+ required: true,
13
+ maxLength: 36,
14
+ access: { write: access.privileged },
15
+ personal: false,
16
+ reason: "technical_reference",
17
+ }),
18
+ providerMessageId: createTextField({
19
+ required: true,
20
+ maxLength: 500,
21
+ access: { write: access.privileged },
22
+ personal: false,
23
+ reason: "technical_reference",
24
+ }),
25
+ reasonCode: createTextField({
26
+ required: true,
27
+ maxLength: 30,
28
+ access: { write: access.privileged },
29
+ personal: false,
30
+ reason: "technical_reference",
31
+ }),
32
+ quarantinedAt: createTimestampField({
33
+ required: true,
34
+ access: { write: access.privileged },
35
+ }),
36
+ acknowledgedAt: createTimestampField({
37
+ access: { write: access.privileged },
38
+ }),
39
+ // Set by retry-quarantined-message; the next successful sync of the mailbox reloads the mail and clears the row.
40
+ retryRequestedAt: createTimestampField({
41
+ access: { write: access.privileged },
42
+ }),
43
+ },
44
+ });
45
+ export const quarantineTable = deriveEntityTableMeta("mail-quarantine", quarantineEntity, {
46
+ source: "unmanaged",
47
+ });
@@ -0,0 +1,9 @@
1
+ import type { DispatchWrite } from "./supervisor-ingest.ts";
2
+ import type { MailAccountRecord, RawInboundMessage, RejectedInboundMessage } from "./types.ts";
3
+ export declare function headerOnlyOf(msg: RawInboundMessage): RawInboundMessage;
4
+ /** Null when the provider reported no headers for the mail: nothing meaningful to show. */
5
+ export declare function headerOnlyOfRejected(entry: RejectedInboundMessage): RawInboundMessage | null;
6
+ export declare function importQuarantinedHeaders(deps: {
7
+ readonly dispatchWrite: DispatchWrite;
8
+ readonly log: (line: string) => void;
9
+ }, account: MailAccountRecord, headerOnly: RawInboundMessage | null): Promise<void>;