@cosmicdrift/kumiko-bundled-features 0.385.0 → 0.387.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 (470) hide show
  1. package/LICENSE +21 -57
  2. package/dist/agent-tools/tool-catalog.js +1 -1
  3. package/dist/agent-tools/tool-dispatch.js +0 -2
  4. package/dist/audit/screens.js +1 -1
  5. package/dist/auth-email-password/feature.js +1 -1
  6. package/dist/auth-email-password/handlers/change-password.write.js +3 -3
  7. package/dist/auth-email-password/handlers/confirm-token-flow.js +5 -5
  8. package/dist/auth-email-password/handlers/invite-accept-with-login.write.js +1 -1
  9. package/dist/auth-email-password/handlers/invite-accept.write.js +18 -18
  10. package/dist/auth-email-password/handlers/invite-create.write.d.ts +2 -2
  11. package/dist/auth-email-password/handlers/invite-create.write.js +10 -10
  12. package/dist/auth-email-password/handlers/invite-info.query.js +1 -1
  13. package/dist/auth-email-password/handlers/invite-signup-complete.write.js +24 -26
  14. package/dist/auth-email-password/handlers/login.write.d.ts +1 -1
  15. package/dist/auth-email-password/handlers/login.write.js +1 -1
  16. package/dist/auth-email-password/handlers/self-registration-status.query.js +1 -1
  17. package/dist/auth-email-password/handlers/signup-confirm.write.js +34 -37
  18. package/dist/auth-email-password/handlers/signup-request.write.js +6 -7
  19. package/dist/auth-email-password/handlers/switch-tenant-mfa-gate.write.d.ts +1 -1
  20. package/dist/auth-email-password/handlers/switch-tenant-mfa-gate.write.js +1 -4
  21. package/dist/auth-email-password/index.js +5 -5
  22. package/dist/auth-email-password/lockout-store.js +1 -1
  23. package/dist/auth-email-password/seeding.d.ts +42 -45
  24. package/dist/auth-email-password/seeding.js +51 -53
  25. package/dist/auth-email-password/signup-token-store.js +8 -8
  26. package/dist/auth-email-password/testing.js +3 -3
  27. package/dist/auth-email-password/web/auth-client.d.ts +2 -2
  28. package/dist/auth-email-password/web/auth-client.js +36 -37
  29. package/dist/auth-email-password/web/auth-form-primitives.js +10 -10
  30. package/dist/auth-email-password/web/auth-gate.js +15 -16
  31. package/dist/auth-email-password/web/client-plugin.d.ts +7 -7
  32. package/dist/auth-email-password/web/client-plugin.js +4 -5
  33. package/dist/auth-email-password/web/confirm-account-unlock-screen.js +1 -1
  34. package/dist/auth-email-password/web/constants.js +3 -3
  35. package/dist/auth-email-password/web/default-topbar-actions.d.ts +8 -8
  36. package/dist/auth-email-password/web/default-topbar-actions.js +6 -6
  37. package/dist/auth-email-password/web/forgot-password-screen.d.ts +2 -2
  38. package/dist/auth-email-password/web/forgot-password-screen.js +9 -9
  39. package/dist/auth-email-password/web/index.js +5 -5
  40. package/dist/auth-email-password/web/invite-accept-screen.d.ts +1 -1
  41. package/dist/auth-email-password/web/invite-accept-screen.js +16 -16
  42. package/dist/auth-email-password/web/login-screen.d.ts +1 -1
  43. package/dist/auth-email-password/web/login-screen.js +2 -3
  44. package/dist/auth-email-password/web/reset-password-screen.d.ts +4 -4
  45. package/dist/auth-email-password/web/reset-password-screen.js +12 -13
  46. package/dist/auth-email-password/web/session.d.ts +10 -9
  47. package/dist/auth-email-password/web/session.js +28 -29
  48. package/dist/auth-email-password/web/signup-complete-screen.js +3 -3
  49. package/dist/auth-email-password/web/signup-screen.d.ts +1 -1
  50. package/dist/auth-email-password/web/signup-screen.js +13 -13
  51. package/dist/auth-email-password/web/tenant-switcher.d.ts +4 -4
  52. package/dist/auth-email-password/web/tenant-switcher.js +21 -22
  53. package/dist/auth-email-password/web/use-shell-user.js +12 -13
  54. package/dist/auth-email-password/web/user-menu.d.ts +4 -4
  55. package/dist/auth-email-password/web/user-menu.js +12 -13
  56. package/dist/auth-email-password/web/verify-email-screen.d.ts +2 -2
  57. package/dist/auth-email-password/web/verify-email-screen.js +9 -10
  58. package/dist/auth-foundation/boot-checks.js +4 -4
  59. package/dist/auth-foundation/resolve-anonymous-access.d.ts +1 -1
  60. package/dist/auth-foundation/resolve-anonymous-access.js +3 -3
  61. package/dist/auth-foundation/types.js +2 -2
  62. package/dist/auth-mfa/handlers/disable.write.js +3 -3
  63. package/dist/auth-mfa/handlers/enable-confirm-preauth.write.js +4 -4
  64. package/dist/auth-mfa/handlers/enable-confirm.write.js +2 -2
  65. package/dist/auth-mfa/handlers/enable-start-preauth.write.js +1 -1
  66. package/dist/auth-mfa/handlers/reencrypt.job.js +1 -1
  67. package/dist/auth-mfa/handlers/regenerate-recovery.write.js +5 -5
  68. package/dist/auth-mfa/handlers/verify.write.js +1 -1
  69. package/dist/auth-mfa/token-secrets.js +1 -1
  70. package/dist/auth-mfa/web/client-plugin.d.ts +1 -1
  71. package/dist/auth-mfa/web/client-plugin.js +1 -1
  72. package/dist/auth-mfa/web/i18n.js +3 -3
  73. package/dist/auth-mfa/web/index.js +4 -4
  74. package/dist/auth-mfa/web/mfa-client.js +17 -16
  75. package/dist/auth-mfa/web/mfa-verify-screen.js +6 -6
  76. package/dist/billing-foundation/aggregate-id.d.ts +5 -5
  77. package/dist/billing-foundation/aggregate-id.js +10 -11
  78. package/dist/billing-foundation/entities.js +27 -27
  79. package/dist/billing-foundation/events.js +18 -17
  80. package/dist/billing-foundation/feature.js +42 -43
  81. package/dist/billing-foundation/get-subscription-for-tenant.d.ts +3 -3
  82. package/dist/billing-foundation/get-subscription-for-tenant.js +3 -5
  83. package/dist/billing-foundation/handlers/create-checkout-session.write.js +18 -17
  84. package/dist/billing-foundation/handlers/create-portal-session.write.js +11 -12
  85. package/dist/billing-foundation/handlers/list-subscriptions.query.js +4 -4
  86. package/dist/billing-foundation/handlers/process-event.write.js +20 -20
  87. package/dist/billing-foundation/projection.d.ts +15 -11
  88. package/dist/billing-foundation/projection.js +38 -37
  89. package/dist/billing-foundation/subscription-tier-sync.js +3 -3
  90. package/dist/billing-foundation/tenant-destroy-hook.d.ts +2 -2
  91. package/dist/billing-foundation/tenant-destroy-hook.js +7 -7
  92. package/dist/billing-foundation/types.d.ts +40 -41
  93. package/dist/billing-foundation/types.js +20 -20
  94. package/dist/billing-foundation/web/billing-plans-panel.js +4 -4
  95. package/dist/cap-counter/aggregate-id.js +8 -9
  96. package/dist/cap-counter/constants.js +11 -12
  97. package/dist/cap-counter/enforce-cap.d.ts +59 -62
  98. package/dist/cap-counter/enforce-cap.js +47 -48
  99. package/dist/cap-counter/entity.js +29 -29
  100. package/dist/cap-counter/feature.js +34 -35
  101. package/dist/cap-counter/handlers/increment-rolling.write.d.ts +2 -2
  102. package/dist/cap-counter/handlers/increment-rolling.write.js +31 -31
  103. package/dist/cap-counter/handlers/mark-soft-warned.write.js +4 -5
  104. package/dist/cap-counter/stock-cap-guard.js +1 -1
  105. package/dist/cap-counter/with-cap-enforcement.d.ts +3 -5
  106. package/dist/channel-email/smtp-transport.d.ts +18 -17
  107. package/dist/channel-email/smtp-transport.js +24 -21
  108. package/dist/channel-in-app/handlers/unread-count.query.js +3 -4
  109. package/dist/compliance-profiles/feature.js +4 -4
  110. package/dist/compliance-profiles/handlers/for-tenant.query.js +3 -6
  111. package/dist/compliance-profiles/handlers/list-profiles.query.js +5 -5
  112. package/dist/compliance-profiles/handlers/needs-profile.query.js +4 -4
  113. package/dist/compliance-profiles/handlers/set-profile.write.js +13 -14
  114. package/dist/compliance-profiles/handlers/sub-processors.query.js +9 -11
  115. package/dist/compliance-profiles/resolve-for-tenant.js +7 -7
  116. package/dist/compliance-profiles/schema/profile-selection.js +18 -23
  117. package/dist/compliance-profiles/seeding.js +14 -15
  118. package/dist/compliance-profiles-ops/handlers/tenants-missing-profile.query.js +3 -3
  119. package/dist/compliance-profiles-ops/index.js +2 -2
  120. package/dist/config/handlers/readiness.query.d.ts +4 -4
  121. package/dist/config/handlers/readiness.query.js +1 -1
  122. package/dist/config/handlers/reencrypt.job.js +4 -5
  123. package/dist/config/handlers/set.write.js +4 -4
  124. package/dist/config/resolver.js +4 -4
  125. package/dist/config/table.js +10 -10
  126. package/dist/config/write-helpers.js +1 -1
  127. package/dist/crypto-shredding/handlers/forget-subject.write.d.ts +2 -2
  128. package/dist/crypto-shredding/handlers/forget-subject.write.js +12 -11
  129. package/dist/custom-fields/aggregate-id.d.ts +12 -13
  130. package/dist/custom-fields/aggregate-id.js +16 -17
  131. package/dist/custom-fields/entity.js +49 -47
  132. package/dist/custom-fields/events.js +7 -8
  133. package/dist/custom-fields/feature.d.ts +14 -14
  134. package/dist/custom-fields/feature.js +53 -54
  135. package/dist/custom-fields/handlers/clear-custom-field.write.d.ts +3 -2
  136. package/dist/custom-fields/handlers/clear-custom-field.write.js +9 -8
  137. package/dist/custom-fields/handlers/define-tenant-field.write.d.ts +1 -1
  138. package/dist/custom-fields/handlers/define-tenant-field.write.js +2 -2
  139. package/dist/custom-fields/handlers/delete-system-field.write.js +6 -7
  140. package/dist/custom-fields/handlers/delete-tenant-field.write.d.ts +1 -1
  141. package/dist/custom-fields/handlers/delete-tenant-field.write.js +3 -3
  142. package/dist/custom-fields/handlers/set-custom-field.write.d.ts +3 -3
  143. package/dist/custom-fields/handlers/set-custom-field.write.js +25 -28
  144. package/dist/custom-fields/handlers/update-tenant-field.write.d.ts +1 -1
  145. package/dist/custom-fields/handlers/update-tenant-field.write.js +1 -1
  146. package/dist/custom-fields/lib/field-access.js +2 -2
  147. package/dist/custom-fields/lib/parse-serialized-field.js +1 -1
  148. package/dist/custom-fields/lib/quota.js +1 -1
  149. package/dist/custom-fields/lib/value-schema.js +10 -12
  150. package/dist/custom-fields/run-retention.js +3 -3
  151. package/dist/custom-fields/schemas.js +14 -14
  152. package/dist/custom-fields/web/client-plugin.js +2 -5
  153. package/dist/custom-fields/web/constants.js +2 -2
  154. package/dist/custom-fields/web/custom-fields-form-section.d.ts +4 -4
  155. package/dist/custom-fields/web/custom-fields-form-section.js +22 -22
  156. package/dist/custom-fields/wire-for-entity.js +65 -67
  157. package/dist/custom-fields/wire-user-data-rights.js +3 -3
  158. package/dist/data-retention/_internal/parse-override.js +2 -3
  159. package/dist/data-retention/feature.js +11 -18
  160. package/dist/data-retention/handlers/policy-for.query.js +6 -6
  161. package/dist/data-retention/keep-for.d.ts +7 -7
  162. package/dist/data-retention/keep-for.js +15 -15
  163. package/dist/data-retention/override-schema.d.ts +3 -4
  164. package/dist/data-retention/override-schema.js +13 -15
  165. package/dist/data-retention/presets.d.ts +4 -5
  166. package/dist/data-retention/presets.js +18 -23
  167. package/dist/data-retention/resolve-tenant-preset.js +17 -16
  168. package/dist/data-retention/resolver.d.ts +12 -12
  169. package/dist/data-retention/resolver.js +24 -23
  170. package/dist/data-retention/run-retention-cleanup.d.ts +8 -3
  171. package/dist/data-retention/run-retention-cleanup.js +61 -51
  172. package/dist/data-retention/schema/tenant-retention-override.js +13 -11
  173. package/dist/delivery/feature.js +2 -2
  174. package/dist/delivery/handlers/log.query.js +1 -1
  175. package/dist/delivery/tables.js +9 -8
  176. package/dist/delivery/unsubscribe.js +4 -4
  177. package/dist/document-ingest-foundation/entity.js +4 -4
  178. package/dist/document-ingest-foundation/events.js +2 -2
  179. package/dist/document-ingest-foundation/feature.js +2 -2
  180. package/dist/document-ingest-foundation/pages.js +1 -1
  181. package/dist/document-ingest-foundation/tenant-destroy-hook.js +4 -4
  182. package/dist/feature-toggles/compose-tier-resolver.js +1 -1
  183. package/dist/feature-toggles/feature.js +1 -1
  184. package/dist/feature-toggles/global-feature-state-table.js +1 -1
  185. package/dist/feature-toggles/handlers/registered.query.js +5 -5
  186. package/dist/feature-toggles/toggle-sync-signal.js +1 -1
  187. package/dist/feature-toggles/web/constants.js +1 -1
  188. package/dist/file-derivatives/feature.d.ts +1 -1
  189. package/dist/file-derivatives/feature.js +1 -1
  190. package/dist/file-derivatives/handlers/public-variant.query.js +1 -1
  191. package/dist/file-derivatives/presets.js +1 -1
  192. package/dist/file-foundation/feature.js +6 -6
  193. package/dist/file-provider-inmemory/feature.d.ts +1 -1
  194. package/dist/file-provider-inmemory/feature.js +16 -16
  195. package/dist/file-provider-s3/feature.js +16 -16
  196. package/dist/file-provider-s3/lib/s3-provider.js +6 -6
  197. package/dist/files/feature.js +6 -6
  198. package/dist/files-tenant-data/handlers/sweep-orphaned-derivatives.job.js +4 -4
  199. package/dist/files-tenant-data/hooks.js +24 -26
  200. package/dist/files-tenant-data/index.js +1 -1
  201. package/dist/folders/feature.d.ts +1 -1
  202. package/dist/folders/web/folder-manager.js +2 -2
  203. package/dist/folders/web/tree.js +5 -5
  204. package/dist/form-draft/db/queries/cleanup.js +1 -1
  205. package/dist/form-draft/db/queries/owned-file-refs.js +1 -1
  206. package/dist/form-draft/entity.js +3 -3
  207. package/dist/form-draft/feature.js +4 -5
  208. package/dist/form-draft/handlers/discard.write.js +1 -1
  209. package/dist/form-draft/release-file-refs.js +6 -6
  210. package/dist/form-draft/schemas.js +3 -3
  211. package/dist/form-draft/web/constants.js +0 -2
  212. package/dist/inbound-mail-foundation/aggregate-id.d.ts +13 -13
  213. package/dist/inbound-mail-foundation/aggregate-id.js +19 -19
  214. package/dist/inbound-mail-foundation/connect-routes.js +4 -3
  215. package/dist/inbound-mail-foundation/constants.d.ts +22 -24
  216. package/dist/inbound-mail-foundation/constants.js +30 -33
  217. package/dist/inbound-mail-foundation/entities.d.ts +12 -12
  218. package/dist/inbound-mail-foundation/entities.js +47 -48
  219. package/dist/inbound-mail-foundation/events.d.ts +4 -3
  220. package/dist/inbound-mail-foundation/events.js +50 -47
  221. package/dist/inbound-mail-foundation/feature.js +39 -39
  222. package/dist/inbound-mail-foundation/handlers/account-state.js +8 -8
  223. package/dist/inbound-mail-foundation/handlers/connect-account.write.js +25 -26
  224. package/dist/inbound-mail-foundation/handlers/disconnect-account.write.js +7 -7
  225. package/dist/inbound-mail-foundation/handlers/ingest-message.write.js +50 -51
  226. package/dist/inbound-mail-foundation/handlers/list-accounts.query.js +8 -8
  227. package/dist/inbound-mail-foundation/handlers/list-messages.query.js +10 -10
  228. package/dist/inbound-mail-foundation/handlers/scope-visibility.js +3 -4
  229. package/dist/inbound-mail-foundation/handlers/update-account.write.js +11 -11
  230. package/dist/inbound-mail-foundation/oauth-state.d.ts +5 -5
  231. package/dist/inbound-mail-foundation/oauth-state.js +11 -10
  232. package/dist/inbound-mail-foundation/projection.d.ts +4 -4
  233. package/dist/inbound-mail-foundation/projection.js +31 -29
  234. package/dist/inbound-mail-foundation/provider-factory.d.ts +4 -4
  235. package/dist/inbound-mail-foundation/provider-factory.js +9 -9
  236. package/dist/inbound-mail-foundation/retention-sweep.d.ts +5 -3
  237. package/dist/inbound-mail-foundation/retention-sweep.js +38 -36
  238. package/dist/inbound-mail-foundation/tenant-destroy-hook.js +14 -16
  239. package/dist/inbound-mail-foundation/types.d.ts +45 -46
  240. package/dist/inbound-mail-foundation/types.js +21 -21
  241. package/dist/inbound-mail-foundation/watch-supervisor.d.ts +10 -10
  242. package/dist/inbound-mail-foundation/watch-supervisor.js +57 -56
  243. package/dist/inbound-provider-imap/credential-document.js +13 -13
  244. package/dist/inbound-provider-imap/feature.d.ts +2 -2
  245. package/dist/inbound-provider-imap/feature.js +42 -40
  246. package/dist/inbound-provider-imap/imap-client.d.ts +12 -11
  247. package/dist/inbound-provider-imap/imap-client.js +20 -19
  248. package/dist/inbound-provider-inmemory/feature.d.ts +9 -9
  249. package/dist/inbound-provider-inmemory/feature.js +19 -19
  250. package/dist/jobs/db/queries/retention.js +2 -2
  251. package/dist/jobs/db/queries/stale-run-sweep.js +3 -3
  252. package/dist/jobs/events.js +1 -1
  253. package/dist/jobs/feature.js +5 -6
  254. package/dist/jobs/handlers/detail.query.js +4 -4
  255. package/dist/jobs/handlers/list.query.js +1 -1
  256. package/dist/jobs/handlers/projection-rebuild.job.js +1 -1
  257. package/dist/jobs/handlers/reindex-entity.job.js +1 -1
  258. package/dist/jobs/handlers/retry.write.js +1 -1
  259. package/dist/jobs/job-instant.js +1 -1
  260. package/dist/jobs/job-run-logger.js +10 -11
  261. package/dist/jobs/job-run-table.js +3 -3
  262. package/dist/jobs/screens.js +1 -1
  263. package/dist/jobs/tenant-job-failure-table.js +1 -1
  264. package/dist/jobs/tenant-job-run-table.js +1 -1
  265. package/dist/ledger/entity.js +5 -5
  266. package/dist/ledger/feature.js +3 -3
  267. package/dist/ledger/handlers/confirm-schedule-period.write.js +3 -3
  268. package/dist/ledger/recurring.js +12 -12
  269. package/dist/ledger/schemas.js +1 -1
  270. package/dist/ledger/web/constants.js +2 -2
  271. package/dist/ledger/web/index.js +7 -7
  272. package/dist/legal-pages/feature.d.ts +4 -4
  273. package/dist/legal-pages/feature.js +25 -26
  274. package/dist/legal-pages/markdown.js +3 -3
  275. package/dist/legal-pages/web/client-plugin.js +23 -24
  276. package/dist/legal-pages/web/index.js +0 -1
  277. package/dist/mail-foundation/feature.d.ts +2 -2
  278. package/dist/mail-foundation/feature.js +24 -25
  279. package/dist/mail-transport-inmemory/feature.d.ts +4 -4
  280. package/dist/mail-transport-inmemory/feature.js +27 -28
  281. package/dist/mail-transport-smtp/feature.js +20 -20
  282. package/dist/managed-pages/branding.js +6 -6
  283. package/dist/managed-pages/feature.d.ts +26 -26
  284. package/dist/managed-pages/feature.js +34 -34
  285. package/dist/managed-pages/handlers/by-slug.query.js +5 -6
  286. package/dist/managed-pages/handlers/by-tenant-published.query.js +2 -2
  287. package/dist/managed-pages/handlers/set.write.js +5 -7
  288. package/dist/managed-pages/screens/page-screens.js +11 -11
  289. package/dist/managed-pages/seeding.js +8 -8
  290. package/dist/managed-pages/table.js +13 -12
  291. package/dist/managed-pages/web/client-plugin.d.ts +1 -1
  292. package/dist/managed-pages/web/client-plugin.js +5 -5
  293. package/dist/managed-pages/web/i18n.js +1 -1
  294. package/dist/notes-history/entity.js +4 -4
  295. package/dist/notes-history/feature.d.ts +2 -2
  296. package/dist/notes-history-user-data/hooks.js +1 -1
  297. package/dist/page-render/layout.js +9 -9
  298. package/dist/page-render/markdown.js +11 -11
  299. package/dist/page-render/security-headers.js +7 -6
  300. package/dist/personal-access-tokens/feature.js +5 -5
  301. package/dist/personal-access-tokens/roles.js +2 -2
  302. package/dist/readiness/handlers/status.query.js +3 -3
  303. package/dist/renderer-foundation/api.js +12 -13
  304. package/dist/renderer-foundation/constants.js +2 -2
  305. package/dist/renderer-foundation/feature.js +7 -7
  306. package/dist/secrets/feature.js +9 -9
  307. package/dist/secrets/web/constants.js +2 -2
  308. package/dist/seo/feature.js +3 -3
  309. package/dist/sessions/constants.d.ts +1 -1
  310. package/dist/sessions/constants.js +1 -1
  311. package/dist/sessions/feature.js +8 -8
  312. package/dist/sessions/handlers/revoke-all-for-user.write.js +2 -2
  313. package/dist/sessions/handlers/revoke-all-others.write.js +2 -2
  314. package/dist/sessions/handlers/revoke.write.js +1 -1
  315. package/dist/sessions/schema/user-session.js +4 -4
  316. package/dist/sessions/screens.js +2 -2
  317. package/dist/sessions/session-callbacks.js +2 -2
  318. package/dist/sessions/session-revoked-event.js +2 -2
  319. package/dist/shared/assert-no-where-rule-in-ownership-write.js +1 -1
  320. package/dist/shared/decrypt-stored-pii.js +1 -1
  321. package/dist/shared/encrypt-for-direct-write.js +1 -1
  322. package/dist/shared/map-with-concurrency.js +5 -4
  323. package/dist/shared/parent-visibility.js +2 -2
  324. package/dist/shared/password-hashing.js +1 -1
  325. package/dist/shared/signup-handover.js +1 -2
  326. package/dist/shared/single-use-token-store.js +1 -1
  327. package/dist/subscription-mollie/constants.js +15 -17
  328. package/dist/subscription-mollie/feature.d.ts +17 -18
  329. package/dist/subscription-mollie/feature.js +24 -24
  330. package/dist/subscription-mollie/index.js +3 -3
  331. package/dist/subscription-mollie/plugin-methods.d.ts +2 -2
  332. package/dist/subscription-mollie/plugin-methods.js +15 -14
  333. package/dist/subscription-mollie/verify-webhook.d.ts +10 -10
  334. package/dist/subscription-mollie/verify-webhook.js +27 -27
  335. package/dist/subscription-stripe/constants.js +4 -6
  336. package/dist/subscription-stripe/feature.d.ts +14 -14
  337. package/dist/subscription-stripe/feature.js +35 -34
  338. package/dist/subscription-stripe/index.js +6 -6
  339. package/dist/subscription-stripe/plugin-methods.js +18 -18
  340. package/dist/subscription-stripe/runtime.d.ts +1 -1
  341. package/dist/subscription-stripe/runtime.js +1 -1
  342. package/dist/subscription-stripe/verify-webhook.d.ts +11 -11
  343. package/dist/subscription-stripe/verify-webhook.js +59 -61
  344. package/dist/tags/feature.d.ts +3 -3
  345. package/dist/tags/screens.js +1 -1
  346. package/dist/template-resolver/api.js +10 -10
  347. package/dist/template-resolver/handlers/find-by-id.query.js +5 -5
  348. package/dist/template-resolver/handlers/list.query.js +1 -1
  349. package/dist/template-resolver/handlers/shared.js +2 -2
  350. package/dist/template-resolver/handlers/template-write.js +3 -3
  351. package/dist/template-resolver/handlers/upsert-system.write.js +3 -4
  352. package/dist/template-resolver/handlers/upsert-tenant.write.js +4 -5
  353. package/dist/template-resolver/seeding.js +4 -4
  354. package/dist/template-resolver/table.js +10 -11
  355. package/dist/template-resolver/web/client-plugin.js +2 -2
  356. package/dist/tenant/feature.js +7 -7
  357. package/dist/tenant/handlers/member-directory.query.js +1 -1
  358. package/dist/tenant/handlers/members.query.js +1 -1
  359. package/dist/tenant/handlers/team-list.query.js +1 -1
  360. package/dist/tenant/handlers/tenant-directory.query.js +1 -1
  361. package/dist/tenant/invitation-table.js +37 -40
  362. package/dist/tenant/membership-table.js +3 -3
  363. package/dist/tenant/schema/tenant.js +7 -9
  364. package/dist/tenant/screens.js +1 -1
  365. package/dist/tenant/seeding.d.ts +6 -5
  366. package/dist/tenant/seeding.js +12 -12
  367. package/dist/tenant/testing.js +5 -6
  368. package/dist/tenant/web/constants.js +2 -2
  369. package/dist/tenant-handover/events.js +5 -7
  370. package/dist/tenant-handover/feature.js +1 -1
  371. package/dist/tenant-handover/grant.js +1 -1
  372. package/dist/tenant-handover/handlers/claim.write.js +1 -1
  373. package/dist/tenant-handover/move-entity-graph.js +8 -9
  374. package/dist/tenant-handover/signup-handover-provider.js +1 -2
  375. package/dist/tenant-handover/transfer-graph.js +4 -5
  376. package/dist/tenant-lifecycle/boot-checks.js +1 -1
  377. package/dist/tenant-lifecycle/feature.js +1 -1
  378. package/dist/tenant-settings/constants.js +1 -1
  379. package/dist/tenant-settings/tenant-defaults.d.ts +1 -1
  380. package/dist/tenant-settings/tenant-defaults.js +9 -2
  381. package/dist/tier-engine/aggregate-id.d.ts +11 -11
  382. package/dist/tier-engine/aggregate-id.js +15 -16
  383. package/dist/tier-engine/compose-app.d.ts +14 -14
  384. package/dist/tier-engine/compose-app.js +1 -1
  385. package/dist/tier-engine/entity.js +18 -19
  386. package/dist/tier-engine/feature.d.ts +19 -17
  387. package/dist/tier-engine/feature.js +68 -69
  388. package/dist/tier-engine/handlers/active-tier.query.js +6 -7
  389. package/dist/tier-engine/handlers/get-tenant-tier.query.js +4 -4
  390. package/dist/tier-engine/handlers/set-tenant-tier.write.d.ts +5 -5
  391. package/dist/tier-engine/handlers/set-tenant-tier.write.js +3 -3
  392. package/dist/tier-engine/tier-resolver.js +2 -2
  393. package/dist/tier-engine/trial.js +8 -8
  394. package/dist/tier-engine/web/index.js +4 -4
  395. package/dist/user/db/queries/stream-tenant-backfill.js +8 -8
  396. package/dist/user/handlers/create.write.js +4 -4
  397. package/dist/user/schema/user.d.ts +11 -11
  398. package/dist/user/schema/user.js +45 -44
  399. package/dist/user/seeding.d.ts +15 -15
  400. package/dist/user/seeding.js +28 -28
  401. package/dist/user/testing.js +3 -3
  402. package/dist/user-data-rights/audit-download.d.ts +8 -8
  403. package/dist/user-data-rights/audit-download.js +19 -20
  404. package/dist/user-data-rights/boot-checks.js +1 -1
  405. package/dist/user-data-rights/deletion-token.js +1 -1
  406. package/dist/user-data-rights/feature.d.ts +49 -50
  407. package/dist/user-data-rights/feature.js +54 -53
  408. package/dist/user-data-rights/handlers/cancel-deletion.write.js +9 -9
  409. package/dist/user-data-rights/handlers/confirm-deletion-by-token.write.js +8 -8
  410. package/dist/user-data-rights/handlers/download-by-job.query.js +29 -30
  411. package/dist/user-data-rights/handlers/download-by-token.query.js +40 -42
  412. package/dist/user-data-rights/handlers/export-status.query.js +8 -9
  413. package/dist/user-data-rights/handlers/lift-restriction.write.js +7 -8
  414. package/dist/user-data-rights/handlers/list-download-attempts.query.js +2 -2
  415. package/dist/user-data-rights/handlers/my-audit-log.query.js +4 -4
  416. package/dist/user-data-rights/handlers/request-deletion-by-email.write.d.ts +5 -5
  417. package/dist/user-data-rights/handlers/request-deletion-by-email.write.js +16 -15
  418. package/dist/user-data-rights/handlers/request-deletion.write.d.ts +2 -2
  419. package/dist/user-data-rights/handlers/request-deletion.write.js +7 -9
  420. package/dist/user-data-rights/handlers/request-export.write.js +42 -41
  421. package/dist/user-data-rights/handlers/restrict-account.write.js +22 -19
  422. package/dist/user-data-rights/handlers/run-forget-cleanup.write.js +8 -8
  423. package/dist/user-data-rights/index.js +8 -10
  424. package/dist/user-data-rights/lib/default-mailers.js +3 -3
  425. package/dist/user-data-rights/lib/update-user-lifecycle.js +14 -17
  426. package/dist/user-data-rights/run-export-jobs.d.ts +38 -42
  427. package/dist/user-data-rights/run-export-jobs.js +127 -233
  428. package/dist/user-data-rights/run-forget-cleanup.d.ts +16 -20
  429. package/dist/user-data-rights/run-forget-cleanup.js +63 -82
  430. package/dist/user-data-rights/run-user-export.d.ts +34 -33
  431. package/dist/user-data-rights/run-user-export.js +55 -57
  432. package/dist/user-data-rights/schema/download-attempt.js +11 -11
  433. package/dist/user-data-rights/schema/download-token.js +37 -41
  434. package/dist/user-data-rights/schema/export-job.d.ts +4 -4
  435. package/dist/user-data-rights/schema/export-job.js +65 -67
  436. package/dist/user-data-rights/token-helpers.d.ts +8 -9
  437. package/dist/user-data-rights/token-helpers.js +21 -25
  438. package/dist/user-data-rights/web/client-plugin.d.ts +5 -5
  439. package/dist/user-data-rights/web/client-plugin.js +1 -1
  440. package/dist/user-data-rights/web/confirm-deletion-screen.js +6 -5
  441. package/dist/user-data-rights/web/constants.js +1 -1
  442. package/dist/user-data-rights/web/index.js +5 -5
  443. package/dist/user-data-rights/web/privacy-center-screen.js +14 -13
  444. package/dist/user-data-rights/web/public-deletion-gate.d.ts +4 -4
  445. package/dist/user-data-rights/web/request-deletion-screen.js +6 -6
  446. package/dist/user-data-rights/zip-path.d.ts +15 -15
  447. package/dist/user-data-rights/zip-path.js +41 -40
  448. package/dist/user-data-rights-defaults/feature.js +15 -15
  449. package/dist/user-data-rights-defaults/hooks/delivery-attempt.userdata-hook.js +3 -5
  450. package/dist/user-data-rights-defaults/hooks/file-ref.userdata-hook.js +45 -51
  451. package/dist/user-data-rights-defaults/hooks/job-run.userdata-hook.js +2 -2
  452. package/dist/user-data-rights-defaults/hooks/notification-preference.userdata-hook.js +1 -1
  453. package/dist/user-data-rights-defaults/hooks/user-session.userdata-hook.js +3 -3
  454. package/dist/user-data-rights-defaults/hooks/user.userdata-hook.js +32 -31
  455. package/dist/user-profile/handlers/change-email.write.js +13 -13
  456. package/dist/user-profile/index.js +3 -3
  457. package/dist/user-profile/web/client-plugin.js +1 -1
  458. package/dist/user-profile/web/constants.js +1 -1
  459. package/dist/user-profile/web/profile-screen.js +1 -1
  460. package/dist/workflow-runner/aggregate-id.d.ts +1 -1
  461. package/dist/workflow-runner/aggregate-id.js +1 -1
  462. package/dist/workflow-runner/event-subscriber.js +4 -5
  463. package/dist/workflow-runner/event-trigger.js +4 -17
  464. package/dist/workflow-runner/feature.js +2 -2
  465. package/dist/workflow-runner/handlers/resume-run.write.js +4 -4
  466. package/dist/workflow-runner/pending-projection.js +6 -7
  467. package/dist/workflow-runner/runner.js +6 -6
  468. package/dist/workflow-runner/tables.js +6 -6
  469. package/dist/workflow-runner/workflow-registry.js +1 -1
  470. package/package.json +10 -10
@@ -22,23 +22,23 @@ export type InboundMailContext = {
22
22
  readonly metricsFor?: (featureName: string) => MetricsHandle;
23
23
  };
24
24
  /**
25
- * Plaintext-Sicht auf ein verbundenes Postfach, wie Provider sie sehen.
26
- * Die Foundation decryptet `address` VOR dem Provider-Call — Provider
27
- * arbeiten nie mit `kumiko-pii:`-Ciphertext (Guard analog
28
- * withPiiCiphertextGuard im Transport-Pfad).
25
+ * Plaintext view of a connected mailbox exposed to providers.
26
+ * The Foundation decrypts `address` BEFORE the provider call; providers
27
+ * never receive `kumiko-pii:` ciphertext (guard analogous to
28
+ * withPiiCiphertextGuard in the transport path).
29
29
  */
30
30
  export type MailAccountRecord = {
31
- /** = aggregateId des mail-account-Streams; zugleich Secret-Slot-Key. */
31
+ /** = aggregateId of the mail-account stream and the secret-slot key. */
32
32
  readonly id: string;
33
33
  readonly tenantId: string;
34
- /** Provider-Key wie bei der Extension registriert ("imap", "m365-graph",
34
+ /** Provider key registered with the extension ("imap", "m365-graph",
35
35
  * "gmail-rest"). */
36
36
  readonly provider: string;
37
- /** "password" | "xoauth2" | "oauth" — imap unterscheidet hierüber
38
- * Formular-Connect vs. XOAUTH2-Fallback (Plan §2). */
37
+ /** "password" | "xoauth2" | "oauth" — imap uses this to distinguish
38
+ * form-based connect from the XOAUTH2 fallback. */
39
39
  readonly authMethod: string;
40
- /** null = tenant-geteiltes Postfach, sonst persönliches Postfach
41
- * dieses Users (Sichtbarkeits-Scope, Plan Entscheidung 2). */
40
+ /** null = tenant-shared mailbox; otherwise this user's personal mailbox
41
+ * (visibility scope). */
42
42
  readonly ownerUserId: string | null;
43
43
  /** Postfach-Adresse, Plaintext (decrypted). */
44
44
  readonly address: string;
@@ -47,36 +47,35 @@ export type MailAccountRecord = {
47
47
  readonly watchState: string;
48
48
  };
49
49
  /**
50
- * Normalisierte eingehende Mail — Provider-Output, Ingest-Input.
51
- * Provider-raw-Strukturen (IMAP-Flags, Graph-Objekte) bleiben im
52
- * Provider; hier nur der domain-clean Schnitt.
50
+ * Normalized incoming mail — provider output and ingest input.
51
+ * Provider-specific structures (IMAP flags, Graph objects) remain in the
52
+ * provider; this type contains only the domain-level boundary.
53
53
  */
54
54
  export type RawInboundMessage = {
55
- /** Provider-native Message-ID (IMAP UID, Graph id, Gmail id) —
56
- * Idempotency-Anchor zusammen mit providerName. */
55
+ /** Provider-native message ID (IMAP UID, Graph id, Gmail id) — the
56
+ * idempotency anchor together with providerName. */
57
57
  readonly providerMessageId: string;
58
- /** RFC-5322 Message-ID-Header ohne <>; null wenn der Header fehlt
59
- * (Foundation fällt auf deterministischen Ersatz zurück). */
58
+ /** RFC-5322 Message-ID header without <>; null when the header is missing
59
+ * (the Foundation falls back to a deterministic replacement). */
60
60
  readonly messageIdHeader: string | null;
61
- /** Provider-native Thread-/Conversation-ID falls vorhanden (Graph
62
- * conversationId, Gmail threadId); Foundation bevorzugt sie vor der
63
- * References-Chain beim threadKey-Bau. */
61
+ /** Provider-native thread/conversation ID when available (Graph
62
+ * conversationId, Gmail threadId); the Foundation prefers it over the
63
+ * References chain when building threadKey. */
64
64
  readonly providerThreadId: string | null;
65
- /** References/In-Reply-To-Chain (Message-IDs ohne <>), älteste zuerst. */
65
+ /** References/In-Reply-To chain (message IDs without <>), oldest first. */
66
66
  readonly references: readonly string[];
67
67
  readonly from: string;
68
68
  readonly to: readonly string[];
69
69
  readonly cc: readonly string[];
70
70
  readonly subject: string;
71
- /** Plaintext-Vorschau, provider-generiert oder aus dem Body geschnitten. */
71
+ /** Plaintext preview generated by the provider or truncated from the body. */
72
72
  readonly snippet: string;
73
- /** ISO-Instant — INTERNALDATE bzw. receivedDateTime, nicht Ingest-Zeit. */
73
+ /** ISO instant — INTERNALDATE or receivedDateTime, not ingest time. */
74
74
  readonly receivedAtIso: string;
75
- /** Raw MIME; null im snippet-only-Mode. Foundation persisted ihn nach
76
- * file-foundation und schreibt bodyRef — der Event-Store bleibt
77
- * blob-frei. */
75
+ /** Raw MIME; null in snippet-only mode. The Foundation persists it through
76
+ * file-foundation and writes bodyRef, so the event store remains blob-free. */
78
77
  readonly rawMime: Uint8Array | null;
79
- /** Generischer Scope-Hint ("inbox", Folder-Name) — keine App-Semantik. */
78
+ /** Generic scope hint ("inbox", folder name), with no application semantics. */
80
79
  readonly scope: string;
81
80
  };
82
81
  /** Provider-opaker Cursor: IMAP {uidValidity,lastUid} · Graph {deltaLink}
@@ -86,8 +85,8 @@ export type SyncCursorPayload = Readonly<Record<string, unknown>>;
86
85
  export type InboundFetchResult = {
87
86
  readonly messages: readonly RawInboundMessage[];
88
87
  readonly nextCursor: SyncCursorPayload;
89
- /** true ⇒ Foundation ruft fetch im selben Poll-Tick erneut auf
90
- * (Pagination), bis false oder maxMessages-Budget erschöpft. */
88
+ /** true ⇒ the Foundation calls fetch again in the same poll tick
89
+ * (pagination) until false or the maxMessages budget is exhausted. */
91
90
  readonly hasMore: boolean;
92
91
  };
93
92
  export type OAuthTokenSet = {
@@ -98,13 +97,13 @@ export type OAuthTokenSet = {
98
97
  readonly scopesGranted: readonly string[];
99
98
  };
100
99
  /**
101
- * OAuth-Teil des Contracts — nur OAuth-Provider; imap (Passwort-Modus)
102
- * lässt `oauth` weg. Die Routen (`/inbound-mail/connect`,
103
- * `/inbound-mail/oauth/callback`) stellt die Foundation generisch —
104
- * Provider registrieren KEINE eigenen Routen.
100
+ * OAuth portion of the contract — OAuth providers only; imap in password
101
+ * mode omits `oauth`. The Foundation provides the routes
102
+ * (`/inbound-mail/connect`, `/inbound-mail/oauth/callback`) generically;
103
+ * providers MUST NOT register their own routes.
105
104
  */
106
105
  export type InboundOAuthFlow = {
107
- /** Scopes: Empfang UND Send in EINEM Consent — Re-Consent ist teuer. */
106
+ /** Scopes: request receive AND send in a SINGLE consent; re-consent is costly. */
108
107
  readonly scopes: {
109
108
  readonly receive: readonly string[];
110
109
  readonly send?: readonly string[];
@@ -128,17 +127,17 @@ export type InboundOAuthFlow = {
128
127
  }) => Promise<OAuthTokenSet>;
129
128
  };
130
129
  /**
131
- * Inbound-Mail-Provider-Plugin contract. Jedes Provider-Feature
132
- * (inbound-provider-imap, -m365-graph, -gmail-rest) registriert eine
133
- * Implementation via `r.useExtension(INBOUND_MAIL_PROVIDER_EXTENSION,
130
+ * Inbound-mail provider plugin contract. Each provider feature
131
+ * (inbound-provider-imap, -m365-graph, -gmail-rest) registers an
132
+ * implementation via `r.useExtension(INBOUND_MAIL_PROVIDER_EXTENSION,
134
133
  * "<key>", plugin)`.
135
134
  */
136
135
  export type InboundMailProviderPlugin = {
137
- /** Credentials-/Erreichbarkeits-Check beim Connect-Flow — wirft
138
- * typisiert (InboundAuthError etc.), kein Rückgabewert. */
136
+ /** Credential/reachability check during the connect flow — throws a
137
+ * typed error (InboundAuthError, etc.) and returns no value. */
139
138
  readonly verify: (ctx: InboundMailContext, account: MailAccountRecord) => Promise<void>;
140
- /** Pull seit cursor. `cursor === null` ⇒ Erst-Befüllung, begrenzt
141
- * durch backfillWindowDays. */
139
+ /** Fetch since cursor. `cursor === null` means initial population,
140
+ * limited by backfillWindowDays. */
142
141
  readonly fetch: (ctx: InboundMailContext, account: MailAccountRecord, cursor: SyncCursorPayload | null, opts: {
143
142
  readonly backfillWindowDays: number;
144
143
  readonly maxMessages: number;
@@ -154,11 +153,11 @@ export type InboundMailProviderPlugin = {
154
153
  }) => Promise<InboundFetchResult>;
155
154
  /** Nur OAuth-Provider. */
156
155
  readonly oauth?: InboundOAuthFlow;
157
- /** Optional: Live-Push (IMAP IDLE, später Graph/Gmail-Webhooks).
158
- * Liefert stop(). Poll bleibt Reconciliation — watch ist Latenz-
159
- * Optimierung, nie Korrektheits-Anker. `onError` meldet den Tod der
160
- * Live-Verbindung (Drop, Auth-Revoke) an den Supervisor, der mit
161
- * Backoff neu startet — der Provider reconnected NICHT selbst. */
156
+ /** Optional live push (IMAP IDLE, later Graph/Gmail webhooks).
157
+ * Returns stop(). Polling remains reconciliation: watch optimizes
158
+ * latency but is never the correctness anchor. `onError` reports a dead
159
+ * live connection (drop, auth revocation) to the supervisor, which
160
+ * restarts it with backoff; the provider does NOT reconnect itself. */
162
161
  readonly watch?: (ctx: InboundMailContext, account: MailAccountRecord, handlers: {
163
162
  readonly onMessages: (msgs: readonly RawInboundMessage[]) => Promise<void>;
164
163
  readonly onError: (err: unknown) => void;
@@ -1,17 +1,18 @@
1
- // Provider-Contract für inbound-mail-Provider-Plugins (Plan §2).
1
+ // Provider contract for inbound-mail provider plugins.
2
2
  //
3
- // Gespiegelt von mail-foundation's MailTransportContext/-Plugin —
4
- // gleiche Trennung Foundation ↔ Provider, gleicher Slim-Context.
3
+ // Mirrored from mail-foundation's MailTransportContext/-Plugin —
4
+ // the Foundation/provider separation and slim context are identical.
5
5
  //
6
- // **Warum kein voller HandlerContext?** fetch()/watch() laufen im
7
- // Worker-Pfad (Poll-Cron, IDLE-Supervisor) — dort gibt es keinen
8
- // per-request `tx`/`actor`. Ein Plugin das mehr liest würde den
9
- // Worker-Pfad zur Runtime brechen, und das fiele nur in production
10
- // auf. Plugin das mehr braucht: InboundMailContext explizit erweitern
11
- // (sichtbarer breaking change) statt ctx-cast.
6
+ // **Why not a full HandlerContext?** fetch()/watch() run in the worker
7
+ // path (poll cron, IDLE supervisor), where there is no per-request
8
+ // `tx`/`actor`. A plugin that reads more would break the worker path at
9
+ // runtime, and this would only be noticed in production. Plugins that need
10
+ // more must explicitly extend InboundMailContext (a visible breaking change)
11
+ // instead of casting ctx.
12
12
  import { INBOUND_MAIL_PROVIDER_EXTENSION } from "./constants.js";
13
- // extension-usage `options` ist engine-payload (unknown) — strukturell
14
- // validieren statt blind casten (Muster isMailTransportPlugin).
13
+ // `options` in the extension usage is an engine payload (unknown), so
14
+ // validate its structure instead of casting blindly (patterned after
15
+ // isMailTransportPlugin).
15
16
  export function isInboundMailProviderPlugin(o) {
16
17
  return (typeof o === "object" &&
17
18
  o !== null &&
@@ -21,18 +22,17 @@ export function isInboundMailProviderPlugin(o) {
21
22
  typeof o.fetch === "function");
22
23
  }
23
24
  // =============================================================================
24
- // Typisierte Fehlerklassen — Foundation reagiert einheitlich im Poll
25
- // (Plan §2, Fehler-Tabelle):
26
- // InboundAuthError → status=auth_error, kein Retry
27
- // InboundRateLimitError → Poll-Abbruch, nächster Cron-Tick
28
- // InboundCursorInvalidError → Cursor-Reset + Voll-Resync im Backfill-
29
- // Fenster; Dedup fängt Dubletten
30
- // InboundTransientError → Job-Retry (retries: 3, exponential)
25
+ // Typed errors handled uniformly by the Foundation during polling:
26
+ // InboundAuthError → status=auth_error, no retry
27
+ // InboundRateLimitError → abort poll, wait for the next cron tick
28
+ // InboundCursorInvalidError → reset cursor + full resync in the backfill
29
+ // window; deduplication handles duplicates
30
+ // InboundTransientError → job retry (retries: 3, exponential)
31
31
  // =============================================================================
32
32
  //
33
- // `kind`-Discriminant statt instanceof: Plugin und Foundation können in
34
- // getrennten Bundles leben (dual-package-hazard), instanceof über
35
- // Realm-/Kopie-Grenzen ist unzuverlässig.
33
+ // Use a `kind` discriminant instead of instanceof: plugins and the Foundation
34
+ // may run in separate bundles (dual-package-hazard), and instanceof is
35
+ // unreliable across realm or package-copy boundaries.
36
36
  export class InboundAuthError extends Error {
37
37
  kind = "inbound-auth-error";
38
38
  constructor(message) {
@@ -3,13 +3,13 @@ import type { DistributedLock } from "@cosmicdrift/kumiko-framework/pipeline";
3
3
  import { type OAuthAccessTokenManager } from "./oauth-access-token.ts";
4
4
  import { type InboundMailContext, type MailAccountRecord, type RawInboundMessage } from "./types.ts";
5
5
  export type InboundMailSupervisorDeps = {
6
- /** Slim-Context für Provider-Calls (registry Pflicht, secrets für
7
- * Credential-Reads der Provider). */
6
+ /** Slim context for provider calls (`registry` is required; `secrets` is
7
+ * used for provider credential reads). */
8
8
  readonly providerCtx: InboundMailContext;
9
- /** App-DB — direct reads auf read_mail_accounts (Account-Snapshot)
10
- * + direct writes auf store_mail_sync_cursors (unmanaged store). */
9
+ /** App database — direct reads from read_mail_accounts (account snapshot)
10
+ * and direct writes to store_mail_sync_cursors (unmanaged store). */
11
11
  readonly db: DbConnection;
12
- /** Standard-Dispatcher mit SystemUser — trägt ingest-message +
12
+ /** Standard dispatcher with SystemUser — carries ingest-message and
13
13
  * update-account. */
14
14
  readonly dispatchWrite: (args: {
15
15
  readonly handlerQn: string;
@@ -20,8 +20,8 @@ export type InboundMailSupervisorDeps = {
20
20
  readonly data?: unknown;
21
21
  readonly error?: unknown;
22
22
  }>;
23
- /** Persisted den raw MIME-Body (file-foundation) und liefert den
24
- * bodyRef fürs Event. Fehlt der Hook, läuft snippet-only-Mode
23
+ /** Persists the raw MIME body (file-foundation) and returns its bodyRef
24
+ * for the event. Without this hook, runs in snippet-only mode
25
25
  * (bodyRef = ""). */
26
26
  readonly storeBody?: (account: MailAccountRecord, msg: RawInboundMessage) => Promise<string>;
27
27
  readonly pollIntervalMs?: number;
@@ -33,7 +33,7 @@ export type InboundMailSupervisorDeps = {
33
33
  * before `plugin.watch()`, ensureWatcher claims a TTL lease for the
34
34
  * account via `lock.acquire` and renews it via `lock.renew` while the
35
35
  * watcher lives. Omit for single-process deployments — every active
36
- * account is watched locally, same as before #1719. */
36
+ * account is watched locally, same as before. */
37
37
  readonly lock?: DistributedLock;
38
38
  /** Access-token lifecycle for OAuth accounts. Defaults to a manager built
39
39
  * from `db` + `providerCtx.secrets`; pass the instance shared with
@@ -46,8 +46,8 @@ export type InboundMailSupervisorDeps = {
46
46
  };
47
47
  export type InboundMailSupervisor = {
48
48
  readonly start: () => Promise<void>;
49
- /** Ein Reconciliation-Durchlauf über alle aktiven Accounts — auch
50
- * standalone nutzbar (Tests, manueller Ops-Trigger). */
49
+ /** Reconciliation run across all active accounts; also usable standalone
50
+ * for tests and manual operational triggers. */
51
51
  readonly pollOnce: () => Promise<void>;
52
52
  readonly stop: () => Promise<void>;
53
53
  };
@@ -1,17 +1,16 @@
1
- // createInboundMailSupervisor — der langlebige Sync-Prozess der
2
- // Foundation: startet pro aktivem Account `plugin.watch()` (IMAP IDLE,
3
- // Push in Sekunden) mit Reconnect-Backoff und fährt zusätzlich den
4
- // periodischen Reconciliation-Poll (Default 5 min) über `plugin.fetch()`.
5
- // Dedup im ingest-Handler macht Watch/Poll-Überschneidung idempotent —
6
- // der Poll ist Korrektheits-Anker, watch nur Latenz-Optimierung.
1
+ // createInboundMailSupervisor — the long-lived Foundation sync process:
2
+ // starts `plugin.watch()` (IMAP IDLE, seconds-level push) for each active
3
+ // account with reconnect backoff, and also runs the periodic reconciliation
4
+ // poll (default: 5 min) through `plugin.fetch()`.
5
+ // Deduplication in the ingest handler makes watch/poll overlap idempotent:
6
+ // the poll is the correctness anchor, while watch only reduces latency.
7
7
  //
8
- // **Plan deviation (documented):** the plan had the poll as an `r.job`
9
- // cron trigger. At the time this was written, JobContext had no
10
- // dispatcher (verified against run-export-jobs.ts). It now does
11
- // (`ctx.write`/`ctx.queryAs`, job-runner.ts) — but converting the poll to
12
- // a cron job is a separate migration (job concurrency instead of this
13
- // dispatcher contract), not part of #1719, and stays untouched here. The
14
- // app owner still wires the supervisor in bin/server.ts:
8
+ // **Documented deviation:** the poll was originally intended as an `r.job`
9
+ // cron trigger. JobContext previously had no dispatcher (see
10
+ // run-export-jobs.ts), but now has one (`ctx.write`/`ctx.queryAs`,
11
+ // job-runner.ts). Converting the poll to a cron job is a separate migration
12
+ // because it changes the concurrency model, so this dispatcher contract
13
+ // remains in place. The app owner wires the supervisor in bin/server.ts:
15
14
  //
16
15
  // const supervisor = createInboundMailSupervisor({
17
16
  // providerCtx: { registry: deps.registry, secrets, metricsFor: deps.metricsFor },
@@ -20,29 +19,29 @@
20
19
  // deps.dispatchSystemWrite({ handlerQn, payload, tenantId: tenantId as TenantId }),
21
20
  // // Multi-worker deployments: share one DistributedLock (same Redis,
22
21
  // // same key prefix) across every worker process so only one of them
23
- // // holds the IMAP IDLE connection per account (#1719). Omit `lock`
22
+ // // holds the IMAP IDLE connection per account. Omit `lock`
24
23
  // // for a single-process deployment — every active account gets
25
- // // watched locally, same as before.
24
+ // // watched locally, as before.
26
25
  // lock: createDistributedLock(redis, `${RedisKeys.lock}inbound-mail:watch:`),
27
26
  // });
28
27
  // await supervisor.start();
29
28
  // // shutdown-hook: await supervisor.stop();
30
29
  //
31
- // **IDLE operational risk (plan §7.3):** long-lived sockets in-process.
32
- // Mitigated here via backoff-restart on onError, a clean stop() of every
33
- // watcher on shutdown, and the poll covering every gap.
30
+ // **IDLE operational risk:** long-lived sockets run in-process.
31
+ // Backoff restart on onError, clean shutdown of every watcher, and the poll
32
+ // covering every gap mitigate this risk.
34
33
  //
35
- // **Multi-worker coordination (#1719):** the reconciliation poll stays
36
- // deliberately N-fold — every worker polls every active account, which
37
- // is idempotent and cheap. Only `plugin.watch()` holds a long-lived
38
- // connection, and only one worker may hold it per account. With
39
- // `deps.lock`, `ensureWatcher` claims a TTL lease (`lock.acquire`) for
40
- // the account before connecting; a worker that doesn't get it leaves the
41
- // account to its current holder — the poll still covers it. The holder
42
- // renews the claim via heartbeat (`lock.renew`, every ttl/3) for as long
43
- // as the watcher state lives, including across reconnect backoff, not
44
- // only while the connection is open. Losing the claim (Redis outage, TTL
45
- // exceeded) tears down the local watcher instead of racing a new holder.
34
+ // **Multi-worker coordination:** the reconciliation poll remains deliberately
35
+ // N-fold: every worker polls every active account, which is idempotent and
36
+ // cheap. Only `plugin.watch()` holds a long-lived connection, and only one
37
+ // worker may hold it per account. With `deps.lock`, `ensureWatcher` claims a
38
+ // TTL lease (`lock.acquire`) before connecting; a worker that fails to claim
39
+ // it leaves the account to its current holder, while the poll still covers
40
+ // it. The holder renews the lease via heartbeat (`lock.renew`, every ttl/3)
41
+ // for as long as the watcher state exists, including reconnect backoff, not
42
+ // only while the connection is open. Losing the claim (for example through
43
+ // a Redis outage or expired TTL) tears down the local watcher instead of
44
+ // racing a new holder.
46
45
  import { configuredPiiSubjectKms, decryptPiiFieldValues, } from "@cosmicdrift/kumiko-framework/crypto";
47
46
  import { fetchOne, insertOne, selectMany, updateMany } from "@cosmicdrift/kumiko-framework/db";
48
47
  import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
@@ -64,8 +63,8 @@ const DEFAULT_MAX_MESSAGES_PER_POLL = 200;
64
63
  const DEFAULT_WATCH_BACKOFF_INITIAL_MS = 5_000;
65
64
  const DEFAULT_WATCH_BACKOFF_MAX_MS = 5 * 60 * 1000;
66
65
  const DEFAULT_WATCH_LEASE_TTL_SECONDS = 90;
67
- /** V1: ein Cursor pro Account (eine Mailbox-Inbox). Multi-Folder später
68
- * über weitere scopes ohne Schema-Änderung. */
66
+ /** One cursor per account (one mailbox inbox) for now; multi-folder support
67
+ * can add further scopes later without a schema change. */
69
68
  const CURSOR_SCOPE = "default";
70
69
  export function createInboundMailSupervisor(deps) {
71
70
  const pollIntervalMs = deps.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS;
@@ -103,8 +102,8 @@ export function createInboundMailSupervisor(deps) {
103
102
  let pollInFlight = null;
104
103
  const watchers = new Map();
105
104
  // ---------------------------------------------------------------
106
- // Account-Snapshot: aktive Accounts aller Tenants, address decrypted
107
- // (Provider arbeiten nie mit Ciphertext).
105
+ // Account snapshot: active accounts of all tenants with the address
106
+ // decrypted (providers never work with ciphertext).
108
107
  // ---------------------------------------------------------------
109
108
  async function listActiveAccounts() {
110
109
  const rows = await selectMany(deps.db, mailAccountsProjectionTable, {
@@ -154,7 +153,7 @@ export function createInboundMailSupervisor(deps) {
154
153
  return isPlainObject(parsed) ? parsed : null;
155
154
  }
156
155
  catch {
157
- return null; // korrupter Cursor = wie kein Cursor → Backfill, Dedup fängt Dubletten
156
+ return null; // a corrupt cursor counts as none → backfill; dedup catches duplicates
158
157
  }
159
158
  }
160
159
  async function saveCursor(account, cursor) {
@@ -167,7 +166,7 @@ export function createInboundMailSupervisor(deps) {
167
166
  });
168
167
  if (existing) {
169
168
  await updateMany(deps.db, syncCursorTable, { cursor: serialized, updatedAt: now }, { accountId, scope: CURSOR_SCOPE });
170
- // skip: update-Pfad fertig — nicht in den insert-Zweig durchfallen.
169
+ // skip: the update path is complete; do not fall through to the insert branch.
171
170
  return;
172
171
  }
173
172
  await insertOne(deps.db, syncCursorTable, {
@@ -181,12 +180,12 @@ export function createInboundMailSupervisor(deps) {
181
180
  });
182
181
  }
183
182
  async function resetCursor(accountId) {
184
- // Kein deleteMany-Import nötig: leerer Cursor-String parsed zu null
185
- // → nächster fetch läuft als Backfill.
183
+ // No deleteMany import is needed: an empty cursor parses to null, so the
184
+ // next fetch runs as a backfill.
186
185
  await updateMany(deps.db, syncCursorTable, { cursor: "", updatedAt: Temporal.Now.instant().toString() }, { accountId, scope: CURSOR_SCOPE });
187
186
  }
188
187
  // ---------------------------------------------------------------
189
- // Ingest — jede Message durch den Standard-Write-Handler.
188
+ // Ingest: every message goes through the standard write handler.
190
189
  // ---------------------------------------------------------------
191
190
  async function ingestBatch(account, msgs, cursorSnapshot) {
192
191
  for (const msg of msgs) {
@@ -214,9 +213,9 @@ export function createInboundMailSupervisor(deps) {
214
213
  },
215
214
  });
216
215
  if (!result.isSuccess) {
217
- // Einzel-Message-Fehler bricht den Batch: Cursor wird NICHT
218
- // persistiert → nächster Tick re-fetcht ab altem Cursor, Dedup
219
- // überspringt die bereits verarbeiteten.
216
+ // A single-message failure aborts the batch without persisting the cursor.
217
+ // The next tick refetches from the old cursor, and deduplication skips
218
+ // messages that were already processed.
220
219
  throw new Error(`ingest-message failed for account ${account.id}: ${JSON.stringify(result.error ?? {})}`);
221
220
  }
222
221
  }
@@ -229,8 +228,8 @@ export function createInboundMailSupervisor(deps) {
229
228
  });
230
229
  }
231
230
  // ---------------------------------------------------------------
232
- // Fehler-Semantik (Plan §2-Tabelle) — geteilt von Poll und Watch.
233
- // Liefert true wenn der Account weiterlaufen darf.
231
+ // Error semantics, shared by poll and watch. Returns true when the
232
+ // account may keep running.
234
233
  // ---------------------------------------------------------------
235
234
  async function handleSyncError(account, err) {
236
235
  if (isInboundAuthError(err)) {
@@ -241,14 +240,14 @@ export function createInboundMailSupervisor(deps) {
241
240
  }
242
241
  if (isInboundRateLimitError(err)) {
243
242
  log(`inbound-mail: account ${account.id} rate-limited (retryAfter ${err.retryAfterMs}ms)`);
244
- return true; // nächster Tick versucht es erneut
243
+ return true; // The next tick retries it
245
244
  }
246
245
  if (isInboundCursorInvalidError(err)) {
247
246
  log(`inbound-mail: account ${account.id} cursor invalid — full resync in backfill window`);
248
247
  await resetCursor(account.id);
249
248
  return true;
250
249
  }
251
- // Transient/unbekannt: loggen, nächster Tick retried.
250
+ // Transient or unknown error: log it and retry on the next tick.
252
251
  log(`inbound-mail: account ${account.id} sync error: ${describeError(err)}`);
253
252
  return true;
254
253
  }
@@ -272,7 +271,8 @@ export function createInboundMailSupervisor(deps) {
272
271
  let cursor = await loadCursor(account.id);
273
272
  let budget = maxMessagesPerPoll;
274
273
  try {
275
- // hasMore-Schleife: Pagination innerhalb eines Ticks bis Budget.
274
+ // hasMore loop: paginate within this tick until the message budget is
275
+ // exhausted.
276
276
  for (;;) {
277
277
  const accessToken = await resolveAccessToken(account, plugin);
278
278
  const result = await plugin.fetch(deps.providerCtx, account, cursor, {
@@ -308,7 +308,7 @@ export function createInboundMailSupervisor(deps) {
308
308
  if (running)
309
309
  await ensureWatcher(account, plugin);
310
310
  }
311
- // Accounts die nicht mehr aktiv sind: Watcher abbauen.
311
+ // Remove watchers for accounts that are no longer active.
312
312
  const activeIds = new Set(accounts.map((a) => a.id));
313
313
  for (const accountId of watchers.keys()) {
314
314
  if (!activeIds.has(accountId))
@@ -316,7 +316,7 @@ export function createInboundMailSupervisor(deps) {
316
316
  }
317
317
  }
318
318
  // ---------------------------------------------------------------
319
- // Watch-Lifecycle mit Backoff-Restart.
319
+ // Watch lifecycle with backoff restart.
320
320
  // ---------------------------------------------------------------
321
321
  // Heartbeat for a held watch lease. Independent of the connection's own
322
322
  // lifecycle — it keeps renewing across reconnect backoff, not just while
@@ -368,7 +368,7 @@ export function createInboundMailSupervisor(deps) {
368
368
  scheduleRenew(account, state, generation);
369
369
  }
370
370
  }
371
- // kumiko-lint-ignore complexity-budget yield-point stale-map check after acquire is intentional (#2460)
371
+ // kumiko-lint-ignore complexity-budget yield-point stale-map check after acquire is intentional
372
372
  async function acquireWatchLease(account, state) {
373
373
  if (!deps.lock || state.lockToken)
374
374
  return "acquired";
@@ -390,11 +390,11 @@ export function createInboundMailSupervisor(deps) {
390
390
  }
391
391
  // kumiko-lint-ignore complexity-budget watch lifecycle (start/stop/restart) stays cohesive
392
392
  async function ensureWatcher(account, plugin) {
393
- // skip: Provider ohne Live-Push — der Reconciliation-Poll deckt den Account ab.
393
+ // skip: provider without live push; the reconciliation poll covers the account.
394
394
  if (!plugin.watch)
395
395
  return;
396
396
  const existing = watchers.get(account.id);
397
- // skip: Watcher läuft bereits, startet gerade, oder Restart ist geplant.
397
+ // skip: the watcher is already running, starting, or scheduled for restart.
398
398
  if (existing?.stop || existing?.restartTimer || existing?.starting)
399
399
  return;
400
400
  const state = existing ?? {
@@ -425,7 +425,8 @@ export function createInboundMailSupervisor(deps) {
425
425
  }
426
426
  const generation = state.generation;
427
427
  const scheduleRestart = (err) => {
428
- // skip: Supervisor gestoppt oder Watcher-Generation gewechselt — Restart wäre ein Zombie.
428
+ // skip: the supervisor stopped or the watcher generation changed; a restart
429
+ // would create a zombie watcher.
429
430
  if (!running || state.generation !== generation)
430
431
  return;
431
432
  state.stop = null;
@@ -464,7 +465,7 @@ export function createInboundMailSupervisor(deps) {
464
465
  }, accessToken !== undefined ? { accessToken } : undefined);
465
466
  if (state.generation !== generation || !running) {
466
467
  await stop();
467
- // skip: stop() kam während des Connects — Watcher wurde sofort wieder abgebaut.
468
+ // skip: stop() ran while connecting; the watcher was torn down right away.
468
469
  return;
469
470
  }
470
471
  state.stop = stop;
@@ -492,7 +493,7 @@ export function createInboundMailSupervisor(deps) {
492
493
  }
493
494
  async function stopWatcher(accountId) {
494
495
  const state = watchers.get(accountId);
495
- // skip: kein Watcher-State für diesen Account — bereits abgebaut.
496
+ // skip: no watcher state for this account; it is already torn down.
496
497
  if (!state)
497
498
  return;
498
499
  state.generation += 1;
@@ -533,7 +534,7 @@ export function createInboundMailSupervisor(deps) {
533
534
  // Lifecycle.
534
535
  // ---------------------------------------------------------------
535
536
  function scheduleNextPoll() {
536
- // skip: Supervisor gestoppt — keinen weiteren Poll-Tick planen.
537
+ // skip: the supervisor is stopped; do not schedule another poll tick.
537
538
  if (!running)
538
539
  return;
539
540
  pollTimer = setTimeout(() => {
@@ -548,7 +549,7 @@ export function createInboundMailSupervisor(deps) {
548
549
  }
549
550
  return {
550
551
  async start() {
551
- // skip: bereits gestartet — start() ist idempotent.
552
+ // skip: already started; start() is idempotent.
552
553
  if (running)
553
554
  return;
554
555
  running = true;
@@ -1,19 +1,19 @@
1
- // Connection-Dokument im per-Account-Secret-Slot
2
- // (inboundCredentialSecretKey(accountId), Plan §4).
1
+ // Connection document stored in the per-account secret slot
2
+ // (inboundCredentialSecretKey(accountId)).
3
3
  //
4
- // **Warum JSON im Secret statt Tenant-Config-Keys:** anders als
5
- // mail-transport-smtp (EIN SMTP pro Tenant) hat Inbound MEHRERE
6
- // Accounts pro Tenant mit verschiedenen Hosts — per-Tenant-Config-Keys
7
- // können das nicht tragen. Host/Port/User sind zusammen mit dem
8
- // Passwort ein zusammengehöriges Verbindungs-Dokument; der Slot ist
9
- // ohnehin encrypted-at-rest.
4
+ // **Why JSON in the secret instead of tenant config keys:** unlike
5
+ // mail-transport-smtp (one SMTP configuration per tenant), inbound mail
6
+ // supports multiple accounts per tenant with different hosts, which
7
+ // per-tenant config keys cannot represent. Host, port, and user belong
8
+ // with the password in one connection document; the slot is encrypted
9
+ // at rest.
10
10
  //
11
- // authMethod des Accounts bestimmt die Interpretation:
11
+ // The account's authMethod determines the interpretation:
12
12
  // password → { host, port, secure, user, password }
13
- // xoauth2 → { host, port, secure, user, accessToken } — V1-Fallback:
14
- // Token-Beschaffung/-Refresh gehört den OAuth-Providern
15
- // (M365/Gmail, Phase 4/5); der imap-Provider konsumiert
16
- // nur einen gültigen Access-Token aus dem Slot.
13
+ // xoauth2 → { host, port, secure, user, accessToken } — V1 fallback:
14
+ // OAuth providers (M365/Gmail) handle token acquisition and
15
+ // refresh; the imap provider only consumes a valid access
16
+ // token from the slot.
17
17
  import * as z from "zod";
18
18
  export const imapCredentialDocumentSchema = z.object({
19
19
  host: z.string().min(1).max(255),
@@ -1,8 +1,8 @@
1
1
  import { type InboundMailProviderPlugin } from "@cosmicdrift/kumiko-bundled-features/inbound-mail-foundation";
2
2
  export declare const IMAP_PROVIDER_KEY = "imap";
3
3
  export { setImapMailHostLookup } from "./imap-client.ts";
4
- /** Exportiert für den Live-Test (imap-live.integration.test.ts) —
5
- * Apps nutzen das Feature, nie das Plugin direkt. */
4
+ /** Exported for the live test (imap-live.integration.test.ts) —
5
+ * applications use the feature, never the plugin directly. */
6
6
  export declare const imapInboundMailPlugin: InboundMailProviderPlugin;
7
7
  export declare function createInboundProviderImapFeature(): import("@cosmicdrift/kumiko-types/feature").FeatureDefinition & {
8
8
  readonly exports: void;