@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,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 { WriteHandlerDef } from "@cosmicdrift/kumiko-framework/engine";
2
- import * as z from "zod";
3
- export declare const ingestMessageSchema: z.ZodObject<{
4
- accountId: z.ZodUUID;
5
- ownerUserId: z.ZodNullable<z.ZodString>;
6
- providerName: z.ZodString;
7
- providerMessageId: z.ZodString;
8
- messageIdHeader: z.ZodNullable<z.ZodString>;
9
- providerThreadId: z.ZodNullable<z.ZodString>;
10
- references: z.ZodArray<z.ZodString>;
11
- from: z.ZodString;
12
- to: z.ZodArray<z.ZodString>;
13
- cc: z.ZodArray<z.ZodString>;
14
- subject: z.ZodString;
15
- snippet: z.ZodString;
16
- receivedAtIso: z.ZodString;
17
- bodyRef: z.ZodString;
18
- scope: z.ZodString;
19
- providerCursor: z.ZodString;
20
- }, z.core.$strip>;
21
- export declare const ingestMessageHandler: WriteHandlerDef;
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. PII encryption (from/to/cc/subject/snippet) BEFORE the append —
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 { acquireNamespacedAdvisoryLock, countWhere } from "@cosmicdrift/kumiko-framework/db";
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, MAIL_THREAD_PII_FIELDS, mailThreadEntity, seenMessageTable, } from "../entities.js";
29
- import { INBOUND_MESSAGE_AGGREGATE_TYPE, INBOUND_MESSAGE_RECEIVED_EVENT_QN, MAIL_THREAD_AGGREGATE_TYPE, MAIL_THREAD_UPDATED_EVENT_QN, } from "../events.js";
30
- import { inboundMessagesProjectionTable } from "../projection.js";
31
- // =============================================================================
32
- // Input schema — the normalized provider output (RawInboundMessage,
33
- // types.ts) plus the envelope (accountId/providerName/providerCursor). rawMime
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
- // @cast-boundary engine-payload — dispatcher-zod-validated payload
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: payload.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
- // 5. Thread-Rollup. New snapshot (live COUNT + max(lastMessageAt)) via
200
- // ctx.events.tryAppend in a bounded retry loop — the apply stays a
201
- // dumb, replay-idempotent UPSERT. lastMessageAtIso is not PII (a
202
- // timestamp), so it stays plaintext-comparable; subject is
203
- // encrypted once up front (constant across retries, doesn't
204
- // depend on the thread's prior state).
205
- //
206
- // messageCount is a live COUNT, not previousCount+1, so two
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
- export declare const listAccountsQuery: QueryHandlerDef;
2
+ import type { InboundMailRoles } from "../mail-roles.ts";
3
+ export declare function createListAccountsQuery({ memberRoles, adminRoles, }: InboundMailRoles): QueryHandlerDef;