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