@cosmicdrift/kumiko-bundled-features 0.393.0 → 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 +96 -55
  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 +61 -45
  154. package/dist/inbound-mail-foundation/i18n.js +72 -3
  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 +13 -2
  195. package/dist/inbound-mail-foundation/screens.js +216 -89
  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 +21 -3
  228. package/dist/inbound-provider-imap/connect-mailbox.js +69 -20
  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 +2 -1
  232. package/dist/inbound-provider-imap/constants.js +2 -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 -37
  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 +8 -1
  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 +2 -0
  250. package/dist/inbound-provider-imap/reconnect-account.js +4 -6
  251. package/dist/inbound-provider-imap/reconnect-mailbox.d.ts +4 -2
  252. package/dist/inbound-provider-imap/reconnect-mailbox.js +35 -12
  253. package/dist/inbound-provider-imap/reconnect-prefill.query.d.ts +2 -1
  254. package/dist/inbound-provider-imap/reconnect-prefill.query.js +11 -8
  255. package/dist/inbound-provider-imap/screens.d.ts +6 -2
  256. package/dist/inbound-provider-imap/screens.js +171 -109
  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 +143 -0
  362. package/src/inbound-provider-imap/changes.json +30 -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
@@ -2,9 +2,10 @@
2
2
  // login of the outgoing server are checked before the transaction opens; only then the account
3
3
  // stream and its credential secret are written, both on the request transaction, so a failure
4
4
  // leaves neither behind.
5
- import { InboundAuthError, InboundMailAuthMethods, InboundMailFoundationHandlers, inboundCredentialSecretKey, } from "@cosmicdrift/kumiko-bundled-features/inbound-mail-foundation";
5
+ import { findMailboxByAddress, InboundAuthError, InboundMailAccountStatuses, InboundMailAuthMethods, InboundMailFoundationHandlers, inboundCredentialSecretKey, } from "@cosmicdrift/kumiko-bundled-features/inbound-mail-foundation";
6
6
  import { requireSecretsContext } from "@cosmicdrift/kumiko-bundled-features/secrets";
7
- import { defineWriteHandler, } from "@cosmicdrift/kumiko-framework/engine";
7
+ import { ROLES } from "@cosmicdrift/kumiko-framework/auth";
8
+ import { createSystemUser, defineWriteHandler, } from "@cosmicdrift/kumiko-framework/engine";
8
9
  import { UnprocessableError, writeFailure } from "@cosmicdrift/kumiko-framework/errors";
9
10
  import * as z from "zod";
10
11
  import { IMAP_CONNECT_ERRORS, IMAP_PROVIDER_KEY, SMTP_CONNECT_ERRORS } from "./constants.js";
@@ -22,7 +23,14 @@ export const connectMailboxSchema = imapCredentialDocumentSchema
22
23
  password: z.string().min(1).max(1000),
23
24
  smtpHost: z.union([z.literal(""), smtpHostSchema]).nullish(),
24
25
  smtpPort: z.number().int().min(1).max(65535),
26
+ trustedAuthservId: z.string().trim().max(255).nullish(),
25
27
  });
28
+ function isReopenableByThisForm(existing, ownerUserId) {
29
+ return (existing.status === InboundMailAccountStatuses.disconnected &&
30
+ existing.provider === IMAP_PROVIDER_KEY &&
31
+ existing.authMethod === InboundMailAuthMethods.password &&
32
+ existing.ownerUserId === ownerUserId);
33
+ }
26
34
  const connectedAccountSchema = z.object({ accountId: z.string() });
27
35
  // Matched on the mapped error text, which also carries the host, so only markers no host name
28
36
  // contains: a bare "tls" or "ssl" would misread a host like ssl.example.com.
@@ -30,7 +38,6 @@ const connectedAccountSchema = z.object({ accountId: z.string() });
30
38
  const TLS_FAILURE = /certificate|self[- ]signed|wrong[ _]version[ _]number|EPROTO|ERR_SSL|ERR_TLS/i;
31
39
  // A fixed preview: any slice of the JSON document would expose the host or the user.
32
40
  export const CREDENTIAL_PREVIEW = "IMAP login";
33
- const SECRET_TRANSACTION_REASON = "the credential secret is written on the request transaction so a failed account connect rolls it back too";
34
41
  // Most hosters name the outgoing server like the incoming one, or with smtp. for imap.
35
42
  export function deriveSmtpHost(imapHost) {
36
43
  return /^imap\./i.test(imapHost) ? `smtp.${imapHost.slice("imap.".length)}` : imapHost;
@@ -91,36 +98,78 @@ export async function checkMailboxLogin(doc, log) {
91
98
  }
92
99
  return { isSuccess: true, data: null };
93
100
  }
94
- export const connectMailboxHandler = defineWriteHandler({
101
+ export const SECRET_TRANSACTION_REASON = "the credential secret is written on the request transaction so a failed account connect rolls it back too";
102
+ // Shared by the admin form (shared mailbox) and the member form (personal mailbox, owner = caller).
103
+ // A disconnected password mailbox of the same scope and owner is brought back under its old account id,
104
+ // so cursor, seen anchors and threads survive; anything else keeps connect-account's conflict answer.
105
+ export async function connectPasswordMailbox(handlerName, event, ctx, mailbox, scope) {
106
+ const { displayName, address, credentialDocument } = mailbox;
107
+ const ownerUserId = scope === "user" ? event.user.id : null;
108
+ const existing = await findMailboxByAddress(ctx, event.user.tenantId, address);
109
+ const reopened = existing !== undefined && isReopenableByThisForm(existing, ownerUserId);
110
+ let accountId;
111
+ if (reopened) {
112
+ accountId = existing.id;
113
+ }
114
+ else {
115
+ const accountFields = {
116
+ provider: IMAP_PROVIDER_KEY,
117
+ authMethod: InboundMailAuthMethods.password,
118
+ displayName,
119
+ address,
120
+ scope,
121
+ };
122
+ // connect-account is admin-only, so a member's personal mailbox goes through the system identity
123
+ // with the owner taken from this session, like the OAuth callback does.
124
+ const connected = scope === "user"
125
+ ? await ctx.dispatch.writeAs(createSystemUser(ctx.user.tenantId, [ROLES.SystemAdmin]), InboundMailFoundationHandlers.connectAccount, { ...accountFields, ownerUserIdOverride: event.user.id })
126
+ : await ctx.dispatch.write(InboundMailFoundationHandlers.connectAccount, accountFields);
127
+ if (!connected.isSuccess)
128
+ return connected;
129
+ accountId = connectedAccountSchema.parse(connected.data).accountId;
130
+ }
131
+ const secrets = requireSecretsContext({ secrets: ctx.services.secrets, user: ctx.user }, handlerName).withRunner(ctx.db.unsafeRaw());
132
+ await secrets.set(event.user.tenantId, inboundCredentialSecretKey(accountId), JSON.stringify(credentialDocument), {
133
+ redact: () => CREDENTIAL_PREVIEW,
134
+ hint: `IMAP credentials for inbound mail account ${accountId}`,
135
+ updatedBy: event.user.id,
136
+ });
137
+ if (reopened) {
138
+ // Secret first: reactivating a disconnected account requires the credential to exist.
139
+ const reactivated = await ctx.dispatch.write(InboundMailFoundationHandlers.reactivateAccount, {
140
+ accountId,
141
+ });
142
+ if (!reactivated.isSuccess)
143
+ return reactivated;
144
+ }
145
+ return { isSuccess: true, data: { accountId } };
146
+ }
147
+ export const createConnectMailboxHandler = ({ adminRoles }) => defineWriteHandler({
95
148
  name: "connect-mailbox",
96
149
  description: "Connects a shared IMAP mailbox with a password over implicit TLS: checks the IMAP login and the SMTP login of the outgoing server (given, or derived from the IMAP host) first, then creates the mail account and stores both servers, user and password as its credential secret in one step.",
97
150
  // The payload carries the plaintext password: as a tool call it would reach the model provider.
98
151
  agent: { expose: false },
99
152
  schema: connectMailboxSchema,
100
- access: { roles: ["SystemAdmin", "TenantAdmin"] },
153
+ access: { roles: [...adminRoles] },
101
154
  // Each call opens a connection to a host the caller picks; the cap keeps the form from being
102
155
  // used to scan ports or to guess passwords at someone else's mail server.
103
156
  rateLimit: { per: "tenant+handler", limit: 10, windowSeconds: 600 },
104
157
  escapeHatch: { grants: ["unsafeRaw"], reason: SECRET_TRANSACTION_REASON },
105
158
  beforeTransaction: (event, ctx) => checkMailboxLogin(credentialDocumentOf(event.payload), ctx.obs.log),
106
159
  handler: async (event, ctx) => {
107
- const { displayName, address } = event.payload;
108
- const connected = await ctx.dispatch.write(InboundMailFoundationHandlers.connectAccount, {
109
- provider: IMAP_PROVIDER_KEY,
110
- authMethod: InboundMailAuthMethods.password,
111
- displayName,
112
- address,
113
- scope: "shared",
114
- });
160
+ const { displayName, address, trustedAuthservId } = event.payload;
161
+ const connected = await connectPasswordMailbox("connect-mailbox", event, ctx, { displayName, address, credentialDocument: credentialDocumentOf(event.payload) }, "shared");
115
162
  if (!connected.isSuccess)
116
163
  return connected;
117
- const { accountId } = connectedAccountSchema.parse(connected.data);
118
- const secrets = requireSecretsContext({ secrets: ctx.services.secrets, user: ctx.user }, "connect-mailbox").withRunner(ctx.db.unsafeRaw());
119
- await secrets.set(event.user.tenantId, inboundCredentialSecretKey(accountId), JSON.stringify(credentialDocumentOf(event.payload)), {
120
- redact: () => CREDENTIAL_PREVIEW,
121
- hint: `IMAP credentials for inbound mail account ${accountId}`,
122
- updatedBy: event.user.id,
123
- });
164
+ const { accountId } = connected.data;
165
+ if (trustedAuthservId) {
166
+ const trusted = await ctx.dispatch.write(InboundMailFoundationHandlers.setTrustedAuthservId, {
167
+ accountId,
168
+ trustedAuthservId,
169
+ });
170
+ if (!trusted.isSuccess)
171
+ return trusted;
172
+ }
124
173
  return { isSuccess: true, data: { accountId } };
125
174
  },
126
175
  });
@@ -0,0 +1,13 @@
1
+ import type { InboundMailRoles } from "@cosmicdrift/kumiko-bundled-features/inbound-mail-foundation";
2
+ export declare const createConnectMyMailboxHandler: ({ memberRoles }: InboundMailRoles) => import("@cosmicdrift/kumiko-types/define-handler").WriteHandlerDefinition<"connect-my-mailbox", import("zod").ZodObject<{
3
+ host: import("zod").ZodString;
4
+ port: import("zod").ZodDefault<import("zod").ZodNumber>;
5
+ user: import("zod").ZodString;
6
+ displayName: import("zod").ZodString;
7
+ address: import("zod").ZodEmail;
8
+ password: import("zod").ZodString;
9
+ smtpHost: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodUnion<readonly [import("zod").ZodLiteral<"">, import("zod").ZodString]>>>;
10
+ smtpPort: import("zod").ZodNumber;
11
+ }, import("zod/v4/core").$strip>, {
12
+ accountId: string;
13
+ }, import("@cosmicdrift/kumiko-types/event-type-map").KumikoEventTypeMap, null, undefined>;
@@ -0,0 +1,25 @@
1
+ // connect-my-mailbox: a member connects a personal password IMAP mailbox (owner = the caller).
2
+ // Same login check and secret write as connect-mailbox; the sender-check policy is tenant-wide and
3
+ // stays with the admin form.
4
+ import { defineWriteHandler } from "@cosmicdrift/kumiko-framework/engine";
5
+ import { checkMailboxLogin, connectMailboxSchema, connectPasswordMailbox, credentialDocumentOf, SECRET_TRANSACTION_REASON, } from "./connect-mailbox.js";
6
+ const connectMyMailboxSchema = connectMailboxSchema.omit({ trustedAuthservId: true });
7
+ const MY_MAILBOX_ESCAPE_REASON = `${SECRET_TRANSACTION_REASON}; the account is created with writeAs(system) on connect-account, which is admin-only, and the owner comes from the caller's session`;
8
+ export const createConnectMyMailboxHandler = ({ memberRoles }) => defineWriteHandler({
9
+ name: "connect-my-mailbox",
10
+ description: "Connects a personal IMAP mailbox of the caller with a password over implicit TLS: checks the IMAP login and the SMTP login of the outgoing server first, then creates the mail account owned by the caller and stores both servers, user and password as its credential secret in one step. A disconnected personal mailbox of the caller with the same address is reactivated under its old account id.",
11
+ // The payload carries the plaintext password: as a tool call it would reach the model provider.
12
+ agent: { expose: false },
13
+ schema: connectMyMailboxSchema,
14
+ access: { roles: [...memberRoles] },
15
+ // Each call opens a connection to a host the caller picks; per user, because any member may call it.
16
+ rateLimit: { per: "user", limit: 10, windowSeconds: 600 },
17
+ // connect-account is admin-only; the personal mailbox is created through the system identity. The owner
18
+ // is always event.user.id from the session, never a payload field.
19
+ escapeHatch: { grants: ["unsafeRaw", "systemIdentity"], reason: MY_MAILBOX_ESCAPE_REASON },
20
+ beforeTransaction: (event, ctx) => checkMailboxLogin(credentialDocumentOf(event.payload), ctx.obs.log),
21
+ handler: async (event, ctx) => {
22
+ const { displayName, address } = event.payload;
23
+ return connectPasswordMailbox("connect-my-mailbox", event, ctx, { displayName, address, credentialDocument: credentialDocumentOf(event.payload) }, "user");
24
+ },
25
+ });
@@ -1,7 +1,8 @@
1
1
  export declare const FEATURE_NAME = "inbound-provider-imap";
2
- export declare const IMAP_PROVIDER_KEY = "imap";
2
+ export { IMAP_PROVIDER_KEY } from "@cosmicdrift/kumiko-bundled-features/inbound-mail-foundation";
3
3
  export declare const ImapHandlers: {
4
4
  readonly connectMailbox: "inbound-provider-imap:write:connect-mailbox";
5
+ readonly connectMyMailbox: "inbound-provider-imap:write:connect-my-mailbox";
5
6
  readonly reconnectMailbox: "inbound-provider-imap:write:reconnect-mailbox";
6
7
  };
7
8
  export declare const ImapQueries: {
@@ -1,7 +1,8 @@
1
1
  export const FEATURE_NAME = "inbound-provider-imap";
2
- export const IMAP_PROVIDER_KEY = "imap";
2
+ export { IMAP_PROVIDER_KEY } from "@cosmicdrift/kumiko-bundled-features/inbound-mail-foundation";
3
3
  export const ImapHandlers = {
4
4
  connectMailbox: "inbound-provider-imap:write:connect-mailbox",
5
+ connectMyMailbox: "inbound-provider-imap:write:connect-my-mailbox",
5
6
  reconnectMailbox: "inbound-provider-imap:write:reconnect-mailbox",
6
7
  };
7
8
  export const ImapQueries = {
@@ -18,7 +18,7 @@
18
18
  // smtpHost is the outgoing server for sending from the mailbox, with the same user and password
19
19
  // over implicit TLS. Documents written before sending existed have none: sending reports
20
20
  // "not set up" instead of guessing a host.
21
- import { InboundAuthError, inboundCredentialSecretKey, } from "@cosmicdrift/kumiko-bundled-features/inbound-mail-foundation";
21
+ import { InboundAuthError, InboundCredentialNotStoredError, inboundCredentialSecretKey, } from "@cosmicdrift/kumiko-bundled-features/inbound-mail-foundation";
22
22
  import { requireSecretsContext } from "@cosmicdrift/kumiko-bundled-features/secrets";
23
23
  import * as z from "zod";
24
24
  import { FEATURE_NAME, SMTP_SUBMISSION_PORT } from "./constants.js";
@@ -60,7 +60,7 @@ export async function readCredentialDocument(ctx, account) {
60
60
  const secrets = requireSecretsContext({ secrets: ctx.secrets, auditUserId: ctx.auditUserId }, FEATURE_NAME);
61
61
  const secret = await secrets.get(account.tenantId, inboundCredentialSecretKey(account.id));
62
62
  if (!secret) {
63
- throw new InboundAuthError(`${FEATURE_NAME}: no credential document in secret slot for account ${account.id} — ` +
63
+ throw new InboundCredentialNotStoredError(`${FEATURE_NAME}: no credential document in secret slot for account ${account.id} — ` +
64
64
  `store the IMAP connection JSON under ${inboundCredentialSecretKey(account.id)} first`);
65
65
  }
66
66
  const parsed = parseImapCredentialDocument(secret.reveal());
@@ -0,0 +1,6 @@
1
+ import type { RawInboundMessage, RejectedInboundMessage } from "@cosmicdrift/kumiko-bundled-features/inbound-mail-foundation";
2
+ import type { ImapFlow } from "imapflow";
3
+ export declare function downloadBatch(client: ImapFlow, batch: readonly number[], uidValidity: string, trustedAuthservId: string | null): Promise<{
4
+ readonly messages: RawInboundMessage[];
5
+ readonly rejected: RejectedInboundMessage[];
6
+ }>;
@@ -0,0 +1,24 @@
1
+ import { coerceDate, parseOrReject } from "./parse-message.js";
2
+ export async function downloadBatch(client, batch, uidValidity, trustedAuthservId) {
3
+ const messages = [];
4
+ const rejected = [];
5
+ if (batch.length === 0)
6
+ return { messages, rejected };
7
+ for await (const msg of client.fetch(batch.join(","), { uid: true, internalDate: true, source: true, envelope: true }, { uid: true })) {
8
+ if (!msg.source)
9
+ continue;
10
+ const parsed = await parseOrReject({
11
+ source: msg.source,
12
+ uid: msg.uid,
13
+ uidValidity,
14
+ internalDate: coerceDate(msg.internalDate ?? undefined),
15
+ envelope: msg.envelope,
16
+ trustedAuthservId,
17
+ });
18
+ if ("message" in parsed)
19
+ messages.push(parsed.message);
20
+ else
21
+ rejected.push(parsed.rejected);
22
+ }
23
+ return { messages, rejected };
24
+ }
@@ -1,9 +1,9 @@
1
- import { type InboundMailProviderPlugin } from "@cosmicdrift/kumiko-bundled-features/inbound-mail-foundation";
1
+ import { type InboundMailProviderPlugin, type InboundMailRoleOptions } from "@cosmicdrift/kumiko-bundled-features/inbound-mail-foundation";
2
2
  export { IMAP_PROVIDER_KEY } from "./constants.ts";
3
3
  export { setImapMailHostLookup } from "./imap-client.ts";
4
4
  /** Exported for the live test (imap-live.integration.test.ts) —
5
5
  * applications use the feature, never the plugin directly. */
6
6
  export declare const imapInboundMailPlugin: InboundMailProviderPlugin;
7
- export declare function createInboundProviderImapFeature(): import("@cosmicdrift/kumiko-types/feature").FeatureDefinition & {
7
+ export declare function createInboundProviderImapFeature(options?: InboundMailRoleOptions): import("@cosmicdrift/kumiko-types/feature").FeatureDefinition & {
8
8
  readonly exports: void;
9
9
  };
@@ -23,27 +23,36 @@
23
23
  // (credential-document.ts), not tenant configuration, because one tenant
24
24
  // can have multiple accounts with different hosts.
25
25
  import { mailAllowedPrivateHostsEnvSchema } from "@cosmicdrift/kumiko-bundled-features/foundation-shared";
26
- import { INBOUND_MAIL_PROVIDER_EXTENSION, } from "@cosmicdrift/kumiko-bundled-features/inbound-mail-foundation";
26
+ import { assertRolesMatchFoundation, INBOUND_MAIL_PROVIDER_EXTENSION, resolveInboundMailRoles, roleDedupeOptions, } from "@cosmicdrift/kumiko-bundled-features/inbound-mail-foundation";
27
27
  import { defineFeature } from "@cosmicdrift/kumiko-framework/engine";
28
28
  import { instantToLegacyDate } from "@cosmicdrift/kumiko-framework/time";
29
29
  import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
30
- import { connectMailboxHandler } from "./connect-mailbox.js";
30
+ import { createConnectMailboxHandler } from "./connect-mailbox.js";
31
+ import { createConnectMyMailboxHandler } from "./connect-my-mailbox.js";
31
32
  import { FEATURE_NAME, IMAP_PROVIDER_KEY } from "./constants.js";
32
33
  import { readCredentialDocument } from "./credential-document.js";
34
+ import { downloadBatch } from "./download-batch.js";
35
+ import { fetchMessageContent } from "./fetch-content.js";
33
36
  import { INBOUND_PROVIDER_IMAP_I18N } from "./i18n.js";
34
- import { assertUidValidity, coerceDate, connectOnce, createImapClient, IMAP_MAILBOX, imapMailHostGuard, mapImapError, parseImapCursor, toRawInboundMessage, } from "./imap-client.js";
35
- import { reconnectMailboxHandler } from "./reconnect-mailbox.js";
36
- import { reconnectPrefillQuery } from "./reconnect-prefill.query.js";
37
- import { imapConnectScreen, imapReconnectScreen } from "./screens.js";
37
+ import { assertUidValidity, closeOnAbort, connectOnce, createImapClient, IMAP_MAILBOX, imapMailHostGuard, mapImapError, parseImapCursor, } from "./imap-client.js";
38
+ import { buildProviderMessageId, coerceDate, parseOrReject } from "./parse-message.js";
39
+ import { createReconnectMailboxHandler } from "./reconnect-mailbox.js";
40
+ import { createReconnectPrefillQuery } from "./reconnect-prefill.query.js";
41
+ import { createImapScreens } from "./screens.js";
38
42
  import { sendFromImapAccount } from "./send-mail.js";
39
43
  export { IMAP_PROVIDER_KEY } from "./constants.js";
40
44
  export { setImapMailHostLookup } from "./imap-client.js";
41
45
  // =============================================================================
42
46
  // fetch — inkrementeller UID-Sync
43
47
  // =============================================================================
48
+ async function unknownUidsOf(uids, uidValidity, filterUnknownMessageIds) {
49
+ const unknownIds = await filterUnknownMessageIds(uids.map((uid) => buildProviderMessageId(uidValidity, uid)));
50
+ return uids.filter((uid) => unknownIds.has(buildProviderMessageId(uidValidity, uid)));
51
+ }
44
52
  async function fetchMessages(ctx, account, cursor, opts) {
45
53
  const doc = await readCredentialDocument(ctx, account);
46
54
  const client = await createImapClient(doc, imapMailHostGuard());
55
+ const stopWatchingAbort = closeOnAbort(client, opts.signal);
47
56
  let lock;
48
57
  try {
49
58
  await client.connect();
@@ -67,27 +76,19 @@ async function fetchMessages(ctx, account, cursor, opts) {
67
76
  uids = (await client.search({ since: instantToLegacyDate(since) }, { uid: true })) || [];
68
77
  }
69
78
  uids.sort((a, b) => a - b);
70
- const batch = uids.slice(0, opts.maxMessages);
71
- const hasMore = uids.length > batch.length;
72
- const messages = [];
73
- let maxUid = parsedCursor?.lastUid ?? 0;
74
- if (batch.length > 0) {
75
- for await (const msg of client.fetch(batch.join(","), { uid: true, internalDate: true, source: true }, { uid: true })) {
76
- if (!msg.source)
77
- continue;
78
- messages.push(await toRawInboundMessage({
79
- source: msg.source,
80
- uid: msg.uid,
81
- uidValidity: serverUidValidity,
82
- internalDate: coerceDate(msg.internalDate ?? undefined),
83
- }));
84
- if (msg.uid > maxUid)
85
- maxUid = msg.uid;
86
- }
87
- }
79
+ // Known mails (ingested or quarantined) are not downloaded again; the cursor still moves past them.
80
+ const unknown = opts.filterUnknownMessageIds
81
+ ? await unknownUidsOf(uids, serverUidValidity, opts.filterUnknownMessageIds)
82
+ : uids;
83
+ const batch = unknown.slice(0, opts.maxMessages);
84
+ const hasMore = unknown.length > batch.length;
85
+ const { messages, rejected } = await downloadBatch(client, batch, serverUidValidity, account.trustedAuthservId ?? null);
86
+ // From the UIDs, not from what was downloaded: a known or skipped mail must not hold the cursor back.
87
+ const lastUid = Math.max(parsedCursor?.lastUid ?? 0, ...(hasMore ? batch : uids));
88
88
  return {
89
89
  messages,
90
- nextCursor: { uidValidity: serverUidValidity, lastUid: maxUid },
90
+ ...(rejected.length > 0 && { rejected }),
91
+ nextCursor: { uidValidity: serverUidValidity, lastUid },
91
92
  hasMore,
92
93
  };
93
94
  }
@@ -95,6 +96,7 @@ async function fetchMessages(ctx, account, cursor, opts) {
95
96
  throw err instanceof Error && "kind" in err ? err : mapImapError(err, doc.host);
96
97
  }
97
98
  finally {
99
+ stopWatchingAbort();
98
100
  lock?.release();
99
101
  await client.logout().catch(() => { });
100
102
  }
@@ -116,23 +118,29 @@ async function watchMailbox(ctx, account, handlers) {
116
118
  let nextUid = Number(mailbox.uidNext ?? 1);
117
119
  const drainNew = async () => {
118
120
  const messages = [];
121
+ const rejected = [];
119
122
  let maxSeen = nextUid - 1;
120
123
  for await (const msg of client.fetch(`${nextUid}:*`, { uid: true, internalDate: true, source: true }, { uid: true })) {
121
124
  // `N:*` gotcha (see fetch): filter out the previous last message.
122
125
  if (msg.uid < nextUid || !msg.source)
123
126
  continue;
124
- messages.push(await toRawInboundMessage({
127
+ const parsed = await parseOrReject({
125
128
  source: msg.source,
126
129
  uid: msg.uid,
127
130
  uidValidity,
128
131
  internalDate: coerceDate(msg.internalDate ?? undefined),
129
- }));
132
+ trustedAuthservId: account.trustedAuthservId ?? null,
133
+ });
134
+ if ("message" in parsed)
135
+ messages.push(parsed.message);
136
+ else
137
+ rejected.push(parsed.rejected);
130
138
  if (msg.uid > maxSeen)
131
139
  maxSeen = msg.uid;
132
140
  }
133
141
  nextUid = maxSeen + 1;
134
- if (messages.length > 0)
135
- await handlers.onMessages(messages);
142
+ if (messages.length > 0 || rejected.length > 0)
143
+ await handlers.onMessages(messages, rejected);
136
144
  };
137
145
  client.on("exists", () => {
138
146
  // skip: ignore delayed exists events after the watcher has stopped.
@@ -192,15 +200,17 @@ export const imapInboundMailPlugin = {
192
200
  verify: async (ctx, account) => connectOnce(await readCredentialDocument(ctx, account), false),
193
201
  probe: async (ctx, account) => connectOnce(await readCredentialDocument(ctx, account), true),
194
202
  fetch: fetchMessages,
203
+ fetchContent: fetchMessageContent,
195
204
  watch: watchMailbox,
196
205
  send: sendFromImapAccount,
197
206
  // No oauth block: password authentication runs through the credential
198
207
  // form (connect-account + Secret-Write); XOAUTH2 token flows belong to
199
208
  // the OAuth providers (M365/Gmail).
200
209
  };
201
- export function createInboundProviderImapFeature() {
210
+ export function createInboundProviderImapFeature(options = {}) {
211
+ const roles = resolveInboundMailRoles(options);
202
212
  return defineFeature(FEATURE_NAME, (r) => {
203
- r.describe('Registers the `"imap"` provider for `inbound-mail-foundation` using imapflow — password/app-password auth covers classic IMAP hosts without any OAuth (plus an XOAUTH2 fallback consuming an access token from the secret slot). Incremental sync via a UIDVALIDITY:lastUid cursor (UIDVALIDITY change triggers a cursor-invalid full resync), initial backfill bounded by the foundation backfill window, and live push via IMAP IDLE for the watch supervisor. Tenant admins connect a mailbox through the "Connect mailbox" form on the mail accounts list (`connect-mailbox` checks the IMAP login and the SMTP login of the outgoing server first, then creates the account and its credential secret in one transaction; `reconnect-mailbox` does the same check for an existing mailbox with a sign-in error and overwrites its credential secret); programmatic setups store the per-account connection JSON (host/port/secure/user/password, plus smtpHost/smtpPort for sending) in the account credential secret slot before the first sync. Implements the provider `send`: `sendMailFromAccount` sends over the SMTP server of the mailbox itself (implicit TLS, same login) with the mailbox address as From and stores a copy in its sent folder.');
213
+ r.describe('Registers the `"imap"` provider for `inbound-mail-foundation` using imapflow — password/app-password auth covers classic IMAP hosts without any OAuth (plus an XOAUTH2 fallback consuming an access token from the secret slot). Incremental sync via a UIDVALIDITY:lastUid cursor (UIDVALIDITY change triggers a cursor-invalid full resync), initial backfill bounded by the foundation backfill window, and live push via IMAP IDLE for the watch supervisor. Tenant admins connect a shared mailbox through the "Connect mailbox" form on the mail accounts list and members a personal one through the same form on "My mail accounts" (`connect-mailbox` and `connect-my-mailbox` check the IMAP login and the SMTP login of the outgoing server first, then creates the account and its credential secret in one transaction; `reconnect-mailbox` does the same check for an existing mailbox with a sign-in error and overwrites its credential secret); programmatic setups store the per-account connection JSON (host/port/secure/user/password, plus smtpHost/smtpPort for sending) in the account credential secret slot before the first sync. Implements the provider `send`: `sendMailFromAccount` sends over the SMTP server of the mailbox itself (implicit TLS, same login) with the mailbox address as From and stores a copy in its sent folder.');
204
214
  r.uiHints({
205
215
  displayLabel: "Inbound Mail · IMAP",
206
216
  category: "notifications",
@@ -210,11 +220,13 @@ export function createInboundProviderImapFeature() {
210
220
  r.requires({ features: ["secrets"] });
211
221
  r.envSchema(mailAllowedPrivateHostsEnvSchema);
212
222
  r.useExtension(INBOUND_MAIL_PROVIDER_EXTENSION, IMAP_PROVIDER_KEY, imapInboundMailPlugin);
213
- r.writeHandler(connectMailboxHandler);
214
- r.writeHandler(reconnectMailboxHandler);
215
- r.queryHandler(reconnectPrefillQuery);
216
- r.screen(imapConnectScreen);
217
- r.screen(imapReconnectScreen);
223
+ r.bootCheck(({ features }) => assertRolesMatchFoundation(FEATURE_NAME, roles, features));
224
+ r.writeHandler(createConnectMailboxHandler(roles));
225
+ r.writeHandler(createConnectMyMailboxHandler(roles));
226
+ r.writeHandler(createReconnectMailboxHandler(roles));
227
+ r.queryHandler(createReconnectPrefillQuery(roles));
228
+ for (const screen of createImapScreens(roles))
229
+ r.screen(screen);
218
230
  r.translations({ keys: INBOUND_PROVIDER_IMAP_I18N });
219
- }, { dedupeOptions: {} });
231
+ }, { dedupeOptions: roleDedupeOptions(roles) });
220
232
  }
@@ -0,0 +1,4 @@
1
+ import type { InboundContentFetchResult, InboundMailContext, MailAccountRecord } from "@cosmicdrift/kumiko-bundled-features/inbound-mail-foundation";
2
+ export declare function fetchMessageContent(ctx: InboundMailContext, account: MailAccountRecord, providerMessageIds: readonly string[], opts?: {
3
+ readonly signal?: AbortSignal;
4
+ }): Promise<InboundContentFetchResult>;
@@ -0,0 +1,68 @@
1
+ // Re-downloads already imported mails whose content was stored as snippet only. A provider message
2
+ // id is "<uidValidity>:<uid>"; ids from another UIDVALIDITY or gone from the server are "missing"
3
+ // (nothing to reload, ever), mails the parser cannot read are "rejected".
4
+ import { InboundTransientError } from "@cosmicdrift/kumiko-bundled-features/inbound-mail-foundation";
5
+ import { readCredentialDocument } from "./credential-document.js";
6
+ import { closeOnAbort, createImapClient, IMAP_MAILBOX, imapMailHostGuard, mapImapError, } from "./imap-client.js";
7
+ import { coerceDate, parseOrReject } from "./parse-message.js";
8
+ function uidOf(providerMessageId, serverUidValidity) {
9
+ const separator = providerMessageId.lastIndexOf(":");
10
+ if (separator < 0 || providerMessageId.slice(0, separator) !== serverUidValidity)
11
+ return null;
12
+ const uid = Number(providerMessageId.slice(separator + 1));
13
+ return Number.isInteger(uid) && uid > 0 ? uid : null;
14
+ }
15
+ export async function fetchMessageContent(ctx, account, providerMessageIds, opts) {
16
+ const doc = await readCredentialDocument(ctx, account);
17
+ const client = await createImapClient(doc, imapMailHostGuard());
18
+ const stopWatchingAbort = closeOnAbort(client, opts?.signal);
19
+ let lock;
20
+ try {
21
+ await client.connect();
22
+ lock = await client.getMailboxLock(IMAP_MAILBOX);
23
+ const mailbox = client.mailbox;
24
+ if (typeof mailbox === "boolean")
25
+ throw new InboundTransientError("mailbox not open");
26
+ const serverUidValidity = String(mailbox.uidValidity);
27
+ const idByUid = new Map();
28
+ const missing = [];
29
+ for (const id of providerMessageIds) {
30
+ const uid = uidOf(id, serverUidValidity);
31
+ if (uid === null)
32
+ missing.push(id);
33
+ else
34
+ idByUid.set(uid, id);
35
+ }
36
+ const messages = [];
37
+ const rejected = [];
38
+ if (idByUid.size > 0) {
39
+ for await (const msg of client.fetch([...idByUid.keys()].join(","), { uid: true, internalDate: true, source: true, envelope: true }, { uid: true })) {
40
+ if (!msg.source)
41
+ continue;
42
+ const parsed = await parseOrReject({
43
+ source: msg.source,
44
+ uid: msg.uid,
45
+ uidValidity: serverUidValidity,
46
+ internalDate: coerceDate(msg.internalDate ?? undefined),
47
+ envelope: msg.envelope,
48
+ });
49
+ idByUid.delete(msg.uid);
50
+ if ("message" in parsed)
51
+ messages.push(parsed.message);
52
+ else
53
+ rejected.push(parsed.rejected);
54
+ }
55
+ }
56
+ // What the server did not return is gone (expunged since the import).
57
+ missing.push(...idByUid.values());
58
+ return { messages, missing, rejected };
59
+ }
60
+ catch (err) {
61
+ throw err instanceof Error && "kind" in err ? err : mapImapError(err, doc.host);
62
+ }
63
+ finally {
64
+ stopWatchingAbort();
65
+ lock?.release();
66
+ await client.logout().catch(() => { });
67
+ }
68
+ }
@@ -1,4 +1,4 @@
1
- import { IMAP_CONNECT_SCREEN_ID, IMAP_RECONNECT_SCREEN_ID, } from "@cosmicdrift/kumiko-bundled-features/inbound-mail-foundation";
1
+ import { IMAP_CONNECT_SCREEN_ID, IMAP_RECONNECT_SCREEN_ID, MY_IMAP_CONNECT_SCREEN_ID, MY_IMAP_RECONNECT_SCREEN_ID, } from "@cosmicdrift/kumiko-bundled-features/inbound-mail-foundation";
2
2
  import { ACTION_FORM_ENTITY } from "@cosmicdrift/kumiko-framework/ui-types";
3
3
  import { fieldLabelKey } from "@cosmicdrift/kumiko-renderer/headless";
4
4
  import { FEATURE_NAME, IMAP_CONNECT_ERRORS, IMAP_RECONNECT_ERRORS, SMTP_CONNECT_ERRORS, } from "./constants.js";
@@ -6,6 +6,8 @@ const formFieldKey = (field) => fieldLabelKey(FEATURE_NAME, ACTION_FORM_ENTITY,
6
6
  export const INBOUND_PROVIDER_IMAP_I18N = {
7
7
  [`screen:${IMAP_CONNECT_SCREEN_ID}.title`]: { en: "Connect mailbox" },
8
8
  [`screen:${IMAP_RECONNECT_SCREEN_ID}.title`]: { en: "Reconnect mailbox" },
9
+ [`screen:${MY_IMAP_CONNECT_SCREEN_ID}.title`]: { en: "Connect mailbox" },
10
+ [`screen:${MY_IMAP_RECONNECT_SCREEN_ID}.title`]: { en: "Reconnect mailbox" },
9
11
  [formFieldKey("accountId")]: { en: "Mailbox" },
10
12
  [formFieldKey("displayName")]: { en: "Name" },
11
13
  [formFieldKey("address")]: { en: "Email address" },
@@ -20,6 +22,11 @@ export const INBOUND_PROVIDER_IMAP_I18N = {
20
22
  "inboundMail.imap.connect.outgoingHint": {
21
23
  en: "Replies go out from this address over your own mail server, with the same user name and password. Leave the field empty if the server is called like the IMAP server, with smtp. instead of imap. Usually 587, even when your provider lists 465/SSL.",
22
24
  },
25
+ [formFieldKey("trustedAuthservId")]: { en: "Mail server ID" },
26
+ "inboundMail.imap.connect.senderCheck": { en: "Sender check" },
27
+ "inboundMail.imap.connect.senderCheckHint": {
28
+ en: "Identifier of the mail server from the Authentication-Results header, for example mx.example.com. Only with it the system checks whether a sender is genuine. Leave empty if unknown.",
29
+ },
23
30
  "inboundMail.imap.connect.submit": { en: "Check and connect" },
24
31
  "inboundMail.imap.reconnect.hint": {
25
32
  en: "The sign-in is checked before saving. Then the system fetches the mail again.",
@@ -1,5 +1,5 @@
1
- import { type MailHostGuardOptions } from "@cosmicdrift/kumiko-bundled-features/foundation-shared";
2
- import { type RawInboundMessage, type SyncCursorPayload } from "@cosmicdrift/kumiko-bundled-features/inbound-mail-foundation";
1
+ import { type MailHostGuardOptions, resolveMailConnectTarget } from "@cosmicdrift/kumiko-bundled-features/foundation-shared";
2
+ import { type SyncCursorPayload } from "@cosmicdrift/kumiko-bundled-features/inbound-mail-foundation";
3
3
  import { ImapFlow } from "imapflow";
4
4
  import type { ImapCredentialDocument } from "./credential-document.ts";
5
5
  export declare const IMAP_MAILBOX = "INBOX";
@@ -7,6 +7,31 @@ export declare const IMAP_HOST_UNREACHABLE_MESSAGE = "IMAP host is not reachable
7
7
  export declare function setImapMailHostLookup(fn: MailHostGuardOptions["lookupFn"]): void;
8
8
  export declare function imapMailHostGuard(): MailHostGuardOptions;
9
9
  export declare function createImapClient(doc: ImapCredentialDocument, hostGuard?: MailHostGuardOptions): Promise<ImapFlow>;
10
+ export declare function imapClientOptions(doc: ImapCredentialDocument, target: Awaited<ReturnType<typeof resolveMailConnectTarget>>): {
11
+ host: string;
12
+ port: number;
13
+ secure: boolean;
14
+ servername?: string | undefined;
15
+ tls?: {
16
+ servername: undefined;
17
+ } | undefined;
18
+ auth: {
19
+ user: string;
20
+ pass: string;
21
+ accessToken?: undefined;
22
+ } | {
23
+ pass?: undefined;
24
+ user: string;
25
+ accessToken: string;
26
+ };
27
+ connectionTimeout: number;
28
+ greetingTimeout: number;
29
+ socketTimeout: number;
30
+ logger: false;
31
+ emitLogs: boolean;
32
+ };
33
+ /** Drops the connection when the supervisor abandons the sync, so a hung command does not keep the socket open. */
34
+ export declare function closeOnAbort(client: ImapFlow, signal: AbortSignal | undefined): () => void;
10
35
  /** Server-Fehler → typisierte Foundation-Fehlerklassen (Plan §2). */
11
36
  export declare function connectOnce(doc: ImapCredentialDocument, examineInbox: boolean): Promise<void>;
12
37
  export declare function mapImapError(err: unknown, host: string): Error;
@@ -19,24 +44,3 @@ export declare function parseImapCursor(cursor: SyncCursorPayload | null): ImapC
19
44
  * foundation resets the cursor and performs a full resync within the
20
45
  * backfill window (deduplication catches duplicates). */
21
46
  export declare function assertUidValidity(cursor: ImapCursor | null, serverUidValidity: string): void;
22
- /** Normalizes the References chain: mailparser returns string | string[]
23
- * | undefined; when References is missing, In-Reply-To provides the thread
24
- * anchor. */
25
- export declare function normalizeReferences(parsed: {
26
- references?: string | string[];
27
- inReplyTo?: string;
28
- }): string[];
29
- /** imapflow provides internalDate as either a Date or string depending on
30
- * the code path. The string form is deliberately discarded (no date parsing
31
- * in feature code, no-date-api); toRawInboundMessage then falls back to the
32
- * mailparser Date header, which is always a real Date. */
33
- export declare function coerceDate(d: Date | string | undefined): Date | undefined;
34
- /** providerMessageId: a UID is unique only within a UIDVALIDITY; together,
35
- * they form the stable idempotency anchor. */
36
- export declare function buildProviderMessageId(uidValidity: string, uid: number): string;
37
- export declare function toRawInboundMessage(args: {
38
- readonly source: Uint8Array;
39
- readonly uid: number;
40
- readonly uidValidity: string;
41
- readonly internalDate: Date | undefined;
42
- }): Promise<RawInboundMessage>;