@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
@@ -27,7 +27,6 @@ export class FileStorageUnavailableError extends Error {
27
27
  super("readFileRefContent: no file storage is available for the file's tenant");
28
28
  }
29
29
  }
30
- // fileName of the row is never used: it is personal data and may be a PII ciphertext.
31
30
  export async function readFileRefContent(args) {
32
31
  if (!isUuid(args.fileRefId))
33
32
  return null;
@@ -44,7 +43,8 @@ export async function readFileRefContent(args) {
44
43
  if (row === undefined)
45
44
  return null;
46
45
  const size = Number(row.size);
47
- if (args.maxBytes !== undefined && size > args.maxBytes) {
46
+ // A size that is not a number counts as too large, so the limit cannot be skipped.
47
+ if (args.maxBytes !== undefined && !(size <= args.maxBytes)) {
48
48
  throw new FileRefTooLargeError(size);
49
49
  }
50
50
  const files = args.filesForTenant(row.tenantId);
@@ -52,5 +52,11 @@ export async function readFileRefContent(args) {
52
52
  throw new FileStorageUnavailableError();
53
53
  }
54
54
  const content = await files.refFromFileRef(row).read();
55
- return { content, contentType: row.mimeType, tenantId: row.tenantId, size };
55
+ return {
56
+ content,
57
+ contentType: row.mimeType,
58
+ tenantId: row.tenantId,
59
+ size,
60
+ fileName: row.fileName,
61
+ };
56
62
  }
@@ -3,4 +3,4 @@ export declare const discardDraftWrite: import("@cosmicdrift/kumiko-types/define
3
3
  releaseFiles: import("zod").ZodOptional<import("zod").ZodBoolean>;
4
4
  }, import("zod/v4/core").$strip>, {
5
5
  discarded: boolean;
6
- }, import("@cosmicdrift/kumiko-types/event-type-map").KumikoEventTypeMap, undefined>;
6
+ }, import("@cosmicdrift/kumiko-types/event-type-map").KumikoEventTypeMap, undefined, undefined>;
@@ -2,4 +2,4 @@ export declare const saveDraftWrite: import("@cosmicdrift/kumiko-types/define-ha
2
2
  draftKey: import("zod").ZodString;
3
3
  values: import("zod").ZodRecord<import("zod").ZodString, import("zod").ZodUnknown>;
4
4
  stepIndex: import("zod").ZodNumber;
5
- }, import("zod/v4/core").$strip>, import("@cosmicdrift/kumiko-types/hooks").SaveContext, import("@cosmicdrift/kumiko-types/event-type-map").KumikoEventTypeMap, undefined>;
5
+ }, import("zod/v4/core").$strip>, import("@cosmicdrift/kumiko-types/hooks").SaveContext, import("@cosmicdrift/kumiko-types/event-type-map").KumikoEventTypeMap, undefined, undefined>;
@@ -0,0 +1,17 @@
1
+ import type { DbConnection } from "@cosmicdrift/kumiko-framework/db";
2
+ import type { DispatchWrite, IngestBatchOutcome, IngestBlockedReason } from "./supervisor-ingest.ts";
3
+ import type { AccountHealthRef, SyncableAccount } from "./syncable-accounts.ts";
4
+ export type PollFailureKind = "transient" | "rate_limited";
5
+ export type AccountHealth = {
6
+ readonly onPollSuccess: (account: SyncableAccount, outcome: Pick<IngestBatchOutcome, "storageUnavailable" | "storageHealthy">) => Promise<void>;
7
+ readonly onPollFailure: (account: SyncableAccount, kind: PollFailureKind) => Promise<void>;
8
+ /** The cursor stayed before a failing mail: either the mail waits for its count or the ingest is down. */
9
+ readonly onIngestBlocked: (account: SyncableAccount, blocked: IngestBlockedReason, outcome: Pick<IngestBatchOutcome, "storageHealthy">) => Promise<void>;
10
+ /** The address did not decrypt because the key store is down, so the account could not be polled. */
11
+ readonly onKeyStoreUnavailable: (account: AccountHealthRef) => Promise<void>;
12
+ };
13
+ export declare function createAccountHealth(deps: {
14
+ readonly db: DbConnection;
15
+ readonly dispatchWrite: DispatchWrite;
16
+ readonly log: (line: string) => void;
17
+ }): AccountHealth;
@@ -0,0 +1,101 @@
1
+ // Account health: maps what the supervisor observes (repeated poll failures, quarantined mails, file
2
+ // storage, KMS or ingest outage) onto the account status "degraded" plus a lastError code, and back to "active" once
3
+ // nothing is wrong any more. Auth errors and disconnects are never touched here. An update is
4
+ // dispatched only when status or lastError really changes, so a healthy mailbox causes no events.
5
+ import { InboundMailAccountStatuses, InboundMailFoundationHandlers, InboundMailLastErrors, } from "./constants.js";
6
+ import { hasOpenQuarantine } from "./quarantine.js";
7
+ const FAILURES_BEFORE_DEGRADED = 3;
8
+ const OUTAGE_LAST_ERRORS = new Set([
9
+ InboundMailLastErrors.encryptionUnavailable,
10
+ InboundMailLastErrors.ingestUnavailable,
11
+ InboundMailLastErrors.fileStorageUnavailable,
12
+ ]);
13
+ const SUPERVISOR_AUDIT_REASON = "watch_supervisor";
14
+ export function createAccountHealth(deps) {
15
+ const consecutiveFailures = new Map();
16
+ const storageUnavailable = new Set();
17
+ // The account snapshot of a tick is stale after our own update; this keeps the "real change" check honest.
18
+ // Per process: a drift between workers costs at most one redundant update-account.
19
+ const applied = new Map();
20
+ async function apply(account, lastError) {
21
+ const known = applied.get(account.id) ?? {
22
+ status: account.status,
23
+ lastError: account.lastError,
24
+ };
25
+ const status = lastError === null ? InboundMailAccountStatuses.active : InboundMailAccountStatuses.degraded;
26
+ // skip: the stored health already matches, nothing to write.
27
+ if (known.status === status && known.lastError === lastError)
28
+ return;
29
+ const result = await deps.dispatchWrite({
30
+ handlerQn: InboundMailFoundationHandlers.updateAccount,
31
+ tenantId: account.tenantId,
32
+ payload: { accountId: account.id, status, lastError, reason: SUPERVISOR_AUDIT_REASON },
33
+ });
34
+ if (!result.isSuccess) {
35
+ deps.log(`inbound-mail: account ${account.id} health update was rejected (${rejectionCode(result.error)})`);
36
+ // skip: not recorded as applied, so the next tick retries the update.
37
+ return;
38
+ }
39
+ applied.set(account.id, { status, lastError });
40
+ }
41
+ async function lastErrorWithoutOutage(account) {
42
+ if (await hasOpenQuarantine(deps.db, account.id)) {
43
+ return InboundMailLastErrors.messageQuarantined;
44
+ }
45
+ if (storageUnavailable.has(account.id))
46
+ return InboundMailLastErrors.fileStorageUnavailable;
47
+ return null;
48
+ }
49
+ return {
50
+ async onPollSuccess(account, outcome) {
51
+ consecutiveFailures.delete(account.id);
52
+ if (outcome.storageUnavailable)
53
+ storageUnavailable.add(account.id);
54
+ else if (outcome.storageHealthy)
55
+ storageUnavailable.delete(account.id);
56
+ return apply(account, await lastErrorWithoutOutage(account));
57
+ },
58
+ async onIngestBlocked(account, blocked, outcome) {
59
+ consecutiveFailures.delete(account.id);
60
+ if (blocked === "message_failing") {
61
+ deps.log(`inbound-mail: account ${account.id} waits for a failing message to be counted`);
62
+ if (outcome.storageHealthy)
63
+ storageUnavailable.delete(account.id);
64
+ // A counted failure proves the ingest works again, so a shown outage is over; anything else stays.
65
+ const shown = (applied.get(account.id) ?? account).lastError;
66
+ // skip: no outage is shown, the status stays as it is
67
+ if (shown === null || !OUTAGE_LAST_ERRORS.has(shown))
68
+ return;
69
+ return apply(account, await lastErrorWithoutOutage(account));
70
+ }
71
+ // KMS and ingest outages need no memory like storage: the next unblocked poll proves they are over.
72
+ if (blocked === "encryption_unavailable") {
73
+ return apply(account, InboundMailLastErrors.encryptionUnavailable);
74
+ }
75
+ if (blocked === "ingest_unavailable") {
76
+ return apply(account, InboundMailLastErrors.ingestUnavailable);
77
+ }
78
+ storageUnavailable.add(account.id);
79
+ return apply(account, InboundMailLastErrors.fileStorageUnavailable);
80
+ },
81
+ async onKeyStoreUnavailable(account) {
82
+ consecutiveFailures.delete(account.id);
83
+ return apply(account, InboundMailLastErrors.encryptionUnavailable);
84
+ },
85
+ async onPollFailure(account, kind) {
86
+ const count = (consecutiveFailures.get(account.id) ?? 0) + 1;
87
+ consecutiveFailures.set(account.id, count);
88
+ // skip: below the failure threshold the mailbox stays as it is.
89
+ if (count < FAILURES_BEFORE_DEGRADED)
90
+ return;
91
+ return apply(account, kind === "rate_limited"
92
+ ? InboundMailLastErrors.rateLimited
93
+ : InboundMailLastErrors.connectionFailed);
94
+ },
95
+ };
96
+ }
97
+ function rejectionCode(error) {
98
+ if (typeof error === "object" && error !== null && "code" in error)
99
+ return String(error.code);
100
+ return "unknown";
101
+ }
@@ -0,0 +1,19 @@
1
+ import type { PollAccountOptions, PollAccountResult } from "./sync-account-now.ts";
2
+ import type { SyncableAccount } from "./syncable-accounts.ts";
3
+ import type { InboundMailProviderPlugin } from "./types.ts";
4
+ export declare const DEFAULT_POLL_CONCURRENCY = 4;
5
+ export declare const DEFAULT_ACCOUNT_POLL_DEADLINE_MS: number;
6
+ export declare function pollScheduleOf(options: {
7
+ readonly pollConcurrency?: number;
8
+ readonly accountPollDeadlineMs?: number;
9
+ }): {
10
+ readonly pollConcurrency: number;
11
+ readonly accountPollDeadlineMs: number;
12
+ };
13
+ type PollAccount = (account: SyncableAccount, plugin: InboundMailProviderPlugin, options: PollAccountOptions) => Promise<PollAccountResult>;
14
+ /** A sync past the deadline counts as one failed poll and its in-flight slot is freed. */
15
+ export declare function withPollDeadline(pollAccount: PollAccount, deadline: {
16
+ readonly ms: number;
17
+ readonly onDeadline: (account: SyncableAccount) => Promise<void>;
18
+ }): PollAccount;
19
+ export {};
@@ -0,0 +1,44 @@
1
+ // How the supervisor tick spreads its accounts: a bounded number of syncs side by side, and a
2
+ // deadline after which a sync that never answers is abandoned instead of holding the tick.
3
+ export const DEFAULT_POLL_CONCURRENCY = 4;
4
+ export const DEFAULT_ACCOUNT_POLL_DEADLINE_MS = 10 * 60 * 1000;
5
+ export function pollScheduleOf(options) {
6
+ return {
7
+ pollConcurrency: options.pollConcurrency ?? DEFAULT_POLL_CONCURRENCY,
8
+ accountPollDeadlineMs: options.accountPollDeadlineMs ?? DEFAULT_ACCOUNT_POLL_DEADLINE_MS,
9
+ };
10
+ }
11
+ /** Aborts the signal when the deadline passes. The abandoned work may still settle later; its
12
+ * outcome is dropped and a late rejection is swallowed. */
13
+ async function runWithDeadline(deadlineMs, run) {
14
+ const controller = new AbortController();
15
+ const work = run(controller.signal);
16
+ let timer;
17
+ const deadline = new Promise((resolve) => {
18
+ timer = setTimeout(() => resolve({ timedOut: true }), deadlineMs);
19
+ });
20
+ try {
21
+ const outcome = await Promise.race([
22
+ work.then((value) => ({ timedOut: false, value })),
23
+ deadline,
24
+ ]);
25
+ if (outcome.timedOut) {
26
+ controller.abort();
27
+ work.catch(() => { });
28
+ }
29
+ return outcome;
30
+ }
31
+ finally {
32
+ clearTimeout(timer);
33
+ }
34
+ }
35
+ /** A sync past the deadline counts as one failed poll and its in-flight slot is freed. */
36
+ export function withPollDeadline(pollAccount, deadline) {
37
+ return async (account, plugin, options) => {
38
+ const outcome = await runWithDeadline(deadline.ms, (signal) => pollAccount(account, plugin, { ...options, signal }));
39
+ if (!outcome.timedOut)
40
+ return outcome.value;
41
+ await deadline.onDeadline(account);
42
+ return "done";
43
+ };
44
+ }
@@ -0,0 +1,24 @@
1
+ import type { DbConnection } from "@cosmicdrift/kumiko-framework/db";
2
+ import type { AccountHealth } from "./account-health.ts";
3
+ import type { DispatchWrite, MessageIngester } from "./supervisor-ingest.ts";
4
+ import type { PollAccountOptions, PollAccountResult } from "./sync-account-now.ts";
5
+ import type { SyncCursorStore } from "./sync-cursor-store.ts";
6
+ import type { SyncableAccount } from "./syncable-accounts.ts";
7
+ import type { InboundMailContext, InboundMailProviderPlugin, MailAccountRecord } from "./types.ts";
8
+ export type AccountPollerDeps = {
9
+ readonly systemDb: DbConnection;
10
+ readonly cursors: SyncCursorStore;
11
+ readonly ingester: MessageIngester;
12
+ readonly health: AccountHealth;
13
+ readonly providerCtx: InboundMailContext;
14
+ readonly dispatchWrite: DispatchWrite;
15
+ readonly backfillWindowDays: number;
16
+ readonly maxMessagesPerPoll: number;
17
+ readonly resolveAccessToken: (account: MailAccountRecord, plugin: InboundMailProviderPlugin) => Promise<string | undefined>;
18
+ /** Returns true when the account may keep running. */
19
+ readonly handleSyncError: (account: MailAccountRecord, err: unknown) => Promise<boolean>;
20
+ readonly log: (line: string) => void;
21
+ };
22
+ export declare function createAccountPoller(deps: AccountPollerDeps): {
23
+ readonly pollAccount: (account: SyncableAccount, plugin: InboundMailProviderPlugin, options?: PollAccountOptions) => Promise<PollAccountResult>;
24
+ };
@@ -0,0 +1,157 @@
1
+ import { selectMany } from "@cosmicdrift/kumiko-framework/db";
2
+ import { refetchSnippetOnlyMessages } from "./content-refetch.js";
3
+ import { describeError } from "./describe-error.js";
4
+ import { seenMessageTable } from "./entities.js";
5
+ import { isInboundAuthError, isInboundCredentialNotStoredError, isInboundCursorInvalidError, isInboundRateLimitError, } from "./provider-errors.js";
6
+ import { quarantinedMessageIds } from "./quarantine.js";
7
+ import { retryQuarantinedMessages } from "./quarantine-retry.js";
8
+ const SEEN_LOOKUP_CHUNK_SIZE = 1000;
9
+ export function createAccountPoller(deps) {
10
+ const { systemDb, cursors, ingester, health, providerCtx, backfillWindowDays, maxMessagesPerPoll, resolveAccessToken, handleSyncError, log, } = deps;
11
+ function unknownMessageIdsFilterFor(account) {
12
+ return async (providerMessageIds) => {
13
+ if (providerMessageIds.length === 0)
14
+ return new Set();
15
+ // One bind parameter per id: a full-mailbox listing would exceed Postgres' 65535 limit.
16
+ const seenIds = new Set();
17
+ for (let start = 0; start < providerMessageIds.length; start += SEEN_LOOKUP_CHUNK_SIZE) {
18
+ const seen = await selectMany(systemDb, seenMessageTable, {
19
+ tenantId: account.tenantId,
20
+ accountId: account.id,
21
+ providerMessageId: {
22
+ in: providerMessageIds.slice(start, start + SEEN_LOOKUP_CHUNK_SIZE),
23
+ },
24
+ }, { fields: ["providerMessageId"] });
25
+ for (const row of seen)
26
+ seenIds.add(row.providerMessageId);
27
+ }
28
+ // A quarantined message counts as seen: re-fetching it would only fail the same way again.
29
+ for (const id of await quarantinedMessageIds(systemDb, account.id, providerMessageIds)) {
30
+ seenIds.add(id);
31
+ }
32
+ return new Set(providerMessageIds.filter((id) => !seenIds.has(id)));
33
+ };
34
+ }
35
+ function pollFailureKindOf(err) {
36
+ if (isInboundAuthError(err) || isInboundCursorInvalidError(err))
37
+ return null;
38
+ return isInboundRateLimitError(err) ? "rate_limited" : "transient";
39
+ }
40
+ async function refetchContentSafely(account, plugin, signal) {
41
+ // skip: the provider cannot reload content.
42
+ if (!plugin.fetchContent)
43
+ return;
44
+ try {
45
+ const accessToken = await resolveAccessToken(account, plugin);
46
+ await refetchSnippetOnlyMessages({
47
+ db: systemDb,
48
+ dispatchWrite: deps.dispatchWrite,
49
+ providerCtx,
50
+ account,
51
+ plugin,
52
+ windowDays: backfillWindowDays,
53
+ accessToken,
54
+ signal,
55
+ });
56
+ }
57
+ catch (err) {
58
+ // Best effort: the sync itself succeeded, the next tick retries the reload.
59
+ log(`inbound-mail: content reload for account ${account.id} failed: ${describeError(err)}`);
60
+ }
61
+ }
62
+ async function retryQuarantineSafely(account, plugin, signal) {
63
+ try {
64
+ const accessToken = await resolveAccessToken(account, plugin);
65
+ await retryQuarantinedMessages({
66
+ db: systemDb,
67
+ dispatchWrite: deps.dispatchWrite,
68
+ providerCtx,
69
+ account,
70
+ plugin,
71
+ accessToken,
72
+ signal,
73
+ log,
74
+ });
75
+ }
76
+ catch (err) {
77
+ // Best effort: the sync itself succeeded, the flag stays and the next tick retries.
78
+ log(`inbound-mail: quarantine retry for account ${account.id} failed: ${describeError(err)}`);
79
+ }
80
+ }
81
+ // Fetches and ingests batch after batch until the provider has no more or the message budget of
82
+ // this tick is used up. An abandoned sync (deadline) throws out of the loop.
83
+ async function ingestBatches(account, plugin, options) {
84
+ const { signal } = options;
85
+ let cursor = await cursors.load(account.id);
86
+ let budget = maxMessagesPerPoll;
87
+ const totals = { storageUnavailable: false, storageHealthy: false, ingested: false };
88
+ for (;;) {
89
+ const accessToken = await resolveAccessToken(account, plugin);
90
+ const result = await plugin.fetch(providerCtx, account, cursor, {
91
+ backfillWindowDays,
92
+ maxMessages: budget,
93
+ filterUnknownMessageIds: unknownMessageIdsFilterFor(account),
94
+ ...(accessToken !== undefined && { accessToken }),
95
+ ...(signal && { signal }),
96
+ });
97
+ // The sync was abandoned while the provider was busy; its late result is dropped.
98
+ signal?.throwIfAborted();
99
+ const outcome = await ingester.ingestBatch(account, result.messages, result.rejected ?? [], JSON.stringify(result.nextCursor), {
100
+ ...(options.countBucket !== undefined && { countBucket: options.countBucket }),
101
+ ...(signal && { signal }),
102
+ proof: { ingested: totals.ingested, storageHealthy: totals.storageHealthy },
103
+ });
104
+ totals.storageUnavailable ||= outcome.storageUnavailable;
105
+ totals.storageHealthy ||= outcome.storageHealthy;
106
+ totals.ingested ||= outcome.ingested;
107
+ // Blocked: the cursor stays before the stuck mail, the next tick fetches it again.
108
+ if (outcome.blocked)
109
+ return { ...totals, blocked: outcome.blocked };
110
+ // A newer poll may already own the account; an abandoned one must not move its cursor back.
111
+ signal?.throwIfAborted();
112
+ await cursors.save(account, result.nextCursor);
113
+ cursor = result.nextCursor;
114
+ budget -= result.messages.length;
115
+ if (!result.hasMore || budget <= 0)
116
+ return totals;
117
+ }
118
+ }
119
+ async function pollAccount(account, plugin, options = {}) {
120
+ let totals;
121
+ try {
122
+ totals = await ingestBatches(account, plugin, options);
123
+ }
124
+ catch (err) {
125
+ // skip: an error caused by abandoning the sync is already counted as the deadline failure.
126
+ if (options.signal?.aborted)
127
+ return "done";
128
+ if (options.fromWake && isInboundCredentialNotStoredError(err)) {
129
+ // The secret is written after the account is created; the next tick picks it up.
130
+ log(`inbound-mail: account ${account.id} credential not stored yet, wake sync skipped`);
131
+ return "credential_pending";
132
+ }
133
+ const stillRunning = await handleSyncError(account, err);
134
+ const failureKind = pollFailureKindOf(err);
135
+ if (stillRunning && failureKind)
136
+ await health.onPollFailure(account, failureKind);
137
+ return "done";
138
+ }
139
+ // skip: abandoned during the last batch; the deadline already counted this poll as failed.
140
+ if (options.signal?.aborted)
141
+ return "done";
142
+ if (totals.blocked) {
143
+ await health.onIngestBlocked(account, totals.blocked, totals);
144
+ // A retry asked for by an admin does not depend on the cursor, so a stuck mail must not hold it.
145
+ // During an outage it would fail the same way; the flag stays and runs after the recovery.
146
+ if (totals.blocked === "message_failing") {
147
+ await retryQuarantineSafely(account, plugin, options.signal);
148
+ }
149
+ return "done";
150
+ }
151
+ await health.onPollSuccess(account, totals);
152
+ await retryQuarantineSafely(account, plugin, options.signal);
153
+ await refetchContentSafely(account, plugin, options.signal);
154
+ return "done";
155
+ }
156
+ return { pollAccount };
157
+ }
@@ -9,5 +9,6 @@ export type MailAccountRow = {
9
9
  readonly displayName?: string | null;
10
10
  readonly status?: string | null;
11
11
  readonly watchState?: string | null;
12
+ readonly trustedAuthservId?: string | null;
12
13
  };
13
14
  export declare function toMailAccountRecord(row: MailAccountRow, tenantId: string, requestId: string): Promise<MailAccountRecord>;
@@ -23,5 +23,6 @@ export async function toMailAccountRecord(row, tenantId, requestId) {
23
23
  displayName: row.displayName ?? "",
24
24
  status: isAccountStatus(row.status) ? row.status : InboundMailAccountStatuses.active,
25
25
  watchState: row.watchState ?? "idle",
26
+ trustedAuthservId: row.trustedAuthservId ?? null,
26
27
  };
27
28
  }
@@ -0,0 +1,3 @@
1
+ export type MailAccountWakeListener = (tenantId: string, accountId: string) => void;
2
+ export declare function registerMailAccountWakeListener(listener: MailAccountWakeListener): () => void;
3
+ export declare function wakeMailAccount(tenantId: string, accountId: string): void;
@@ -0,0 +1,17 @@
1
+ // Process-local wake channel between the account-event consumer (feature.ts) and the sync supervisor.
2
+ // A freshly connected, reconnected or re-activated mailbox is synced right away instead of waiting
3
+ // for the next poll tick. The consumer runs "per-instance", so every process wakes its own supervisor.
4
+ //
5
+ // Without a running event dispatcher in the process (or without a supervisor) nothing wakes anyone;
6
+ // the regular poll tick then picks the account up, so this is purely a latency optimisation.
7
+ const listeners = new Set();
8
+ export function registerMailAccountWakeListener(listener) {
9
+ listeners.add(listener);
10
+ return () => {
11
+ listeners.delete(listener);
12
+ };
13
+ }
14
+ export function wakeMailAccount(tenantId, accountId) {
15
+ for (const listener of listeners)
16
+ listener(tenantId, accountId);
17
+ }
@@ -0,0 +1,10 @@
1
+ import type { SignatureExtraRouteVerifyRequest } from "@cosmicdrift/kumiko-framework/api";
2
+ import type { Context } from "hono";
3
+ import type { OAuthCodeExchange } from "./inbound-oauth-flow.ts";
4
+ import { type OAuthStatePayload } from "./oauth-state.ts";
5
+ export type VerifiedCallback = {
6
+ readonly code: string;
7
+ readonly state: OAuthStatePayload;
8
+ };
9
+ export declare function verifyCallbackRequest(request: SignatureExtraRouteVerifyRequest, stateSecret: string): VerifiedCallback;
10
+ export declare function refreshTokenOrRefusal(c: Context, state: OAuthStatePayload, tokens: OAuthCodeExchange): string | Response;
@@ -0,0 +1,31 @@
1
+ import { ExtraRouteRejection } from "@cosmicdrift/kumiko-framework/api";
2
+ import { errorJson } from "./connect-route-responses.js";
3
+ import { normalizeMailAddress } from "./handlers/account-address.js";
4
+ import { verifyOAuthState } from "./oauth-state.js";
5
+ export function verifyCallbackRequest(request, stateSecret) {
6
+ const code = request.query["code"] ?? "";
7
+ const rawState = request.query["state"] ?? "";
8
+ if (!code || !rawState) {
9
+ throw new ExtraRouteRejection(400, { error: { code: "invalid_callback", message: "missing code or state" } }, "inbound-mail oauth callback missing code or state");
10
+ }
11
+ const verified = verifyOAuthState(rawState, stateSecret);
12
+ if (!verified.ok) {
13
+ throw new ExtraRouteRejection(400, { error: { code: "invalid_state", message: `state rejected: ${verified.reason}` } }, `inbound-mail oauth callback state rejected: ${verified.reason}`);
14
+ }
15
+ return { code, state: verified.payload };
16
+ }
17
+ // The refresh token the account needs, or the response that refuses the exchange result.
18
+ export function refreshTokenOrRefusal(c, state, tokens) {
19
+ // Personal only: a shared mailbox is often an M365 shared mailbox the admin opens with their own
20
+ // login (delegated access). A token without access to it shows up as auth_error on the first sync.
21
+ if (state.ownerUserId &&
22
+ normalizeMailAddress(tokens.accountAddress) !== normalizeMailAddress(state.mailbox)) {
23
+ return errorJson(c, 403, "mailbox_address_mismatch", `the account you signed in with is not ${state.mailbox}; sign in with that mailbox's account`);
24
+ }
25
+ // No refresh token, no server-side sync. Consent must request offline_access (or
26
+ // access_type=offline); the provider's oauth block owns the scopes.
27
+ if (!tokens.refreshToken) {
28
+ return errorJson(c, 502, "no_refresh_token", `provider "${state.providerKey}" returned no refresh token — check the offline-access scope in the provider's oauth.scopes`);
29
+ }
30
+ return tokens.refreshToken;
31
+ }
@@ -0,0 +1,13 @@
1
+ import type { Context } from "hono";
2
+ export declare function connectFailureResponse(c: Context, error: unknown): Response & import("hono").TypedResponse<{
3
+ error: {
4
+ code: string;
5
+ message: string;
6
+ };
7
+ }, 400 | 401 | 403 | 404 | 409 | 500 | 502, "json">;
8
+ export declare function errorJson(c: Context, status: 400 | 401 | 403 | 404 | 409 | 500 | 502, code: string, message: string): Response & import("hono").TypedResponse<{
9
+ error: {
10
+ code: string;
11
+ message: string;
12
+ };
13
+ }, 400 | 401 | 403 | 404 | 409 | 500 | 502, "json">;
@@ -0,0 +1,16 @@
1
+ import { propertyOf } from "@cosmicdrift/kumiko-types/type-guards";
2
+ import { InboundMailConnectErrors } from "./constants.js";
3
+ const CONNECT_CONFLICT_MESSAGES = {
4
+ [InboundMailConnectErrors.addressAlreadyConnected.reason]: "this mailbox address is already connected",
5
+ [InboundMailConnectErrors.addressDisconnected.reason]: "this mailbox was disconnected before; reconnect it from the mailbox list instead",
6
+ };
7
+ export function connectFailureResponse(c, error) {
8
+ const reason = propertyOf(propertyOf(error, "details"), "reason");
9
+ const conflict = typeof reason === "string" ? CONNECT_CONFLICT_MESSAGES[reason] : undefined;
10
+ if (typeof reason === "string" && conflict)
11
+ return errorJson(c, 409, reason, conflict);
12
+ return errorJson(c, 502, "account_create_failed", JSON.stringify(error ?? {}));
13
+ }
14
+ export function errorJson(c, status, code, message) {
15
+ return c.json({ error: { code, message } }, status);
16
+ }