@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
@@ -1,12 +1,12 @@
1
- // list-accounts — tenant-scoped Liste der verbundenen Postfächer fürs
2
- // Connect-/Settings-UI. PII (address) wird beim Read decrypted (Muster
3
- // billing-foundation list-subscriptions).
1
+ // list-accounts — tenant-scoped list of connected mailboxes for the
2
+ // Connect/Settings UI. PII (address) is decrypted on read, following the
3
+ // billing-foundation list-subscriptions pattern.
4
4
  //
5
- // **Scope-Sichtbarkeit (Plan Entscheidung 2):** shared-Postfächer
6
- // (ownerUserId=null) sieht jeder Berechtigte; persönliche nur der Owner
7
- // selbst + TenantAdmin/SystemAdmin (Compliance-Sicht). Filter läuft
8
- // in-memory nach dem tenant-scoped select — Volumen ist die Anzahl
9
- // verbundener Postfächer eines Tenants (einstellig bis zweistellig).
5
+ // **Scope visibility:** authorized users can see shared mailboxes
6
+ // (ownerUserId=null); personal mailboxes are visible only to their owner,
7
+ // TenantAdmin, or SystemAdmin for compliance access. Filtering runs in memory
8
+ // after the tenant-scoped select because a tenant has only a single- to
9
+ // double-digit number of connected mailboxes.
10
10
  import { configuredPiiSubjectKms, decryptPiiFieldValues, } from "@cosmicdrift/kumiko-framework/crypto";
11
11
  import { MAX_LIST_LIMIT } from "@cosmicdrift/kumiko-framework/engine";
12
12
  import * as z from "zod";
@@ -1,12 +1,12 @@
1
- // list-messages — tenant-scoped Message-Liste (Inbox-Cockpit).
2
- // Optionale Filter: accountId (ein Postfach), threadKey (eine
3
- // Konversation), scope (Folder-Hint). PII (from/to/cc/subject/snippet)
4
- // wird beim Read decrypted; to/cc bleiben JSON-stringified strings —
5
- // der Client parsed sie (dokumentiert im Event-Payload).
1
+ // list-messages — tenant-scoped message list for the inbox cockpit.
2
+ // Optional filters: accountId (one mailbox), threadKey (one conversation),
3
+ // scope (folder hint). PII (from/to/cc/subject/snippet) is decrypted on read;
4
+ // to/cc remain JSON-stringified strings, which the client parses as documented
5
+ // in the event payload.
6
6
  //
7
- // Bewusst KEINE Pagination in V1: die Projection ist tenant-scoped und
8
- // das Inbox-Cockpit lädt begrenzte Zeiträume; ein `limit`-Feld ist
9
- // vorwärtskompatibel ergänzbar ohne den QN zu brechen.
7
+ // Deliberately no pagination in V1: the projection is tenant-scoped and the
8
+ // inbox cockpit loads bounded time ranges; a `limit` field can be added
9
+ // compatibly without breaking the QN.
10
10
  import { configuredPiiSubjectKms, decryptPiiFieldValues, } from "@cosmicdrift/kumiko-framework/crypto";
11
11
  import * as z from "zod";
12
12
  import { INBOUND_MESSAGE_PII_FIELDS } from "../entities.js";
@@ -35,8 +35,8 @@ export const listMessagesQuery = {
35
35
  if (payload.scope)
36
36
  filter["scope"] = payload.scope;
37
37
  const allRows = await ctx.db.selectMany(inboundMessagesProjectionTable, filter);
38
- // Scope-Sichtbarkeit (Plan Entscheidung 2): Messages persönlicher
39
- // Postfächer nur für Owner + TenantAdmin/SystemAdmin.
38
+ // Scope visibility: messages in personal mailboxes are visible only to the
39
+ // owner or TenantAdmin/SystemAdmin.
40
40
  const rows = allRows.filter((row) => isVisibleToCaller(row, ctx.user));
41
41
  const piiKms = configuredPiiSubjectKms();
42
42
  if (!piiKms)
@@ -1,7 +1,6 @@
1
- // Scope-Sichtbarkeit (Plan Entscheidung 2): shared-Rows
2
- // (ownerUserId=null) sieht jeder Berechtigte; persönliche nur der Owner
3
- // selbst + TenantAdmin/SystemAdmin (Compliance-Sicht). Gilt identisch
4
- // für read_mail_accounts und read_inbound_messages (Scope-Vererbung).
1
+ // Scope visibility: shared rows (`ownerUserId=null`) are visible to any authorized caller;
2
+ // personal rows are visible only to the owner, `TenantAdmin`, or `SystemAdmin` for compliance.
3
+ // The same rule applies to `read_mail_accounts` and `read_inbound_messages`.
5
4
  export function isVisibleToCaller(row, user) {
6
5
  const owner = row["ownerUserId"];
7
6
  if (owner == null || owner === "")
@@ -1,7 +1,7 @@
1
- // update-account — Account-Status-Übergänge: Watch-Supervisor meldet
2
- // error/backoff, OAuth-Refresh scheitert (auth_error), Tenant-Admin
3
- // re-enabled nach Credential-Fix. Full-snapshot-Event: lädt den letzten
4
- // Stand, merged die Delta-Felder, appendet den neuen Snapshot.
1
+ // update-account — Account status transitions: the watch supervisor reports
2
+ // error/backoff, OAuth refresh fails (auth_error), or a tenant admin re-enables
3
+ // the account after fixing its credentials. Full-snapshot event: loads the
4
+ // latest state, merges the delta fields, and appends the new snapshot.
5
5
  import { failNotFound, failUnprocessable } from "@cosmicdrift/kumiko-framework/errors";
6
6
  import * as z from "zod";
7
7
  import { InboundMailAccountStatuses } from "../constants.js";
@@ -19,7 +19,7 @@ export const updateAccountSchema = z.object({
19
19
  /** Ops-Signal ("idle", "watching", "backoff:3", ...). */
20
20
  watchState: z.string().max(100).optional(),
21
21
  displayName: z.string().max(200).optional(),
22
- /** Audit-Grund für metadata.headers ("watch_supervisor",
22
+ /** Audit reason for metadata.headers ("watch_supervisor",
23
23
  * "oauth_refresh", "tenant_admin"). */
24
24
  reason: z.string().min(1).max(100),
25
25
  });
@@ -36,14 +36,14 @@ export const updateAccountHandler = {
36
36
  return failNotFound("mail-account", payload.accountId);
37
37
  }
38
38
  if (current.status === InboundMailAccountStatuses.disconnected) {
39
- // Getrennte Accounts sind final — Re-Enable läuft über einen
40
- // frischen connect (neuer Stream, neuer Secret-Slot). Verhindert
41
- // dass ein nachzügelnder Supervisor-Tick einen disconnected
42
- // Account wieder auf active hebt (Race Disconnect vs. Poll).
39
+ // Disconnected accounts are final; re-enabling requires a fresh connect
40
+ // (new stream, new secret slot). This prevents a delayed supervisor tick
41
+ // from restoring a disconnected account to active (disconnect vs. poll
42
+ // race).
43
43
  return failUnprocessable("account_disconnected", { accountId: payload.accountId });
44
44
  }
45
- // Merge: address/provider/authMethod kommen 1:1 aus dem letzten
46
- // Snapshot (address bleibt Ciphertext — nie re-encrypten).
45
+ // address/provider/authMethod come unchanged from the latest snapshot
46
+ // (address remains ciphertext—never re-encrypt it).
47
47
  const eventPayload = {
48
48
  ...current,
49
49
  ...(payload.status !== undefined ? { status: payload.status } : {}),
@@ -1,14 +1,14 @@
1
1
  import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
2
2
  export type OAuthStatePayload = {
3
3
  readonly tenantId: string;
4
- /** null = shared-Postfach, sonst persönliches Postfach dieses Users. */
4
+ /** null = shared mailbox; otherwise this user's personal mailbox. */
5
5
  readonly ownerUserId: string | null;
6
6
  readonly providerKey: string;
7
- /** Postfach-Adresse aus dem Connect-Request — landet nach dem
8
- * Token-Exchange im MailAccount. */
7
+ /** Mailbox address from the connect request; after token exchange, it is
8
+ * stored in the MailAccount. */
9
9
  readonly mailbox: string;
10
- /** Einmal-Nonce — macht jeden state einzigartig (kein Replay über
11
- * zwei parallele Connect-Flows hinweg). */
10
+ /** One-time nonce makes each state unique, preventing replay across
11
+ * two parallel connect flows. */
12
12
  readonly nonce: string;
13
13
  };
14
14
  export type VerifyOAuthStateResult = {
@@ -1,14 +1,15 @@
1
- // HMAC-signierter OAuth-`state`-Parameter für den Connect-Flow.
1
+ // HMAC-signed OAuth-`state` parameter for the connect flow.
2
2
  //
3
- // Bindet {tenantId, ownerUserId?, providerKey, mailbox, nonce} an den
4
- // Redirect: der anonyme Callback (außerhalb /api/*) vertraut NUR dem
5
- // verifizierten state — verhindert CSRF und Fremd-Claiming (ein
6
- // Angreifer kann den Callback nicht auf einen fremden Tenant/User
7
- // umbiegen, ohne die Signatur zu brechen).
3
+ // Binds {tenantId, ownerUserId?, providerKey, mailbox, nonce} to the
4
+ // redirect: the anonymous callback (outside /api/*) trusts only the
5
+ // verified state, preventing CSRF and cross-tenant or cross-user claiming
6
+ // because an attacker cannot redirect the callback to another tenant or
7
+ // user without breaking the signature.
8
8
  //
9
9
  // Format: <payload-base64url>.<expiresAtMs>.<hmac-base64url>
10
- // Muster: auth-email-password/signed-token.ts (HMAC-SHA256, purpose im
11
- // HMAC-Input, timing-safe compare, Expiry im Klartext-Segment).
10
+ // Patterned after auth-email-password/signed-token.ts (HMAC-SHA256, purpose
11
+ // in the HMAC input, timing-safe comparison, expiry in the clear-text
12
+ // segment).
12
13
  import { createHmac, randomUUID, timingSafeEqual } from "node:crypto";
13
14
  import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
14
15
  import { isPlainObject } from "@cosmicdrift/kumiko-types/type-guards";
@@ -40,8 +41,8 @@ export function verifyOAuthState(state, secret, now = Temporal.Now.instant()) {
40
41
  const expected = sign(hmacInput(payloadB64, expiresAtMs), secret);
41
42
  const expectedBuf = Buffer.from(expected, "base64url");
42
43
  const providedBuf = Buffer.from(providedSig, "base64url");
43
- // Length-check VOR timingSafeEqual — die würde bei Längen-Mismatch
44
- // werfen, und der Throw selbst leakt via Timing.
44
+ // Check the length before timingSafeEqual: it throws on a length mismatch,
45
+ // and the throw itself leaks information through timing.
45
46
  if (expectedBuf.length !== providedBuf.length)
46
47
  return { ok: false, reason: "bad_signature" };
47
48
  if (!timingSafeEqual(expectedBuf, providedBuf))
@@ -130,12 +130,12 @@ export declare const mailThreadsProjectionTable: import("@cosmicdrift/kumiko-fra
130
130
  }, "tenant">>;
131
131
  /** mail-account-connected → UPSERT full. */
132
132
  export declare const applyMailAccountConnected: import("@cosmicdrift/kumiko-types/projection").SingleStreamApplyFn;
133
- /** mail-account-updated → UPSERT full (status/watchState-Übergänge). */
133
+ /** mail-account-updated → full UPSERT for status/watchState transitions. */
134
134
  export declare const applyMailAccountUpdated: import("@cosmicdrift/kumiko-types/projection").SingleStreamApplyFn;
135
- /** mail-account-disconnected → UPSERT full (payload.status=disconnected).
136
- * Row bleibt (Audit-Sicht in der Account-Liste), Stream bleibt. */
135
+ /** mail-account-disconnected → full UPSERT (payload.status=disconnected).
136
+ * The row and stream remain for audit visibility in the account list. */
137
137
  export declare const applyMailAccountDisconnected: import("@cosmicdrift/kumiko-types/projection").SingleStreamApplyFn;
138
138
  /** inbound-message-received → INSERT ... ON CONFLICT DO NOTHING. */
139
139
  export declare const applyInboundMessageReceived: import("@cosmicdrift/kumiko-types/projection").SingleStreamApplyFn;
140
- /** mail-thread-updated → UPSERT full mit dem Payload-Snapshot. */
140
+ /** mail-thread-updated → full UPSERT with the payload snapshot. */
141
141
  export declare const applyMailThreadUpdated: import("@cosmicdrift/kumiko-types/projection").SingleStreamApplyFn;
@@ -1,26 +1,27 @@
1
- // Inline-projections für die drei event-sourced Streams:
1
+ // Inline projections for the three event-sourced streams:
2
2
  // mail-account → read_mail_accounts (UPSERT, current state)
3
3
  // inbound-message → read_inbound_messages (INSERT-ignore, append-only)
4
- // mail-thread → read_mail_threads (UPSERT, Rollup)
4
+ // mail-thread → read_mail_threads (UPSERT, rollup)
5
5
  //
6
- // Apply läuft in derselben TX wie ctx.unsafeAppendEvent — read-your-
7
- // own-write ohne dispatcher-tick (Muster billing-foundation).
6
+ // Apply runs in the same transaction as ctx.unsafeAppendEvent, providing
7
+ // read-your-own-write without waiting for a dispatcher tick (as in
8
+ // billing-foundation).
8
9
  //
9
- // **Production-deployment caveat** (gleich wie billing-foundation):
10
- // die Tables sind als raw drizzle-pgTable in r.projection registriert,
11
- // NICHT als r.entity — Apps müssen sie in ihre drizzle/generate.ts
12
- // aufnehmen (via *-ProjectionTable-Imports). setupTestStack pusht sie
13
- // automatisch via r.projection.table.
10
+ // **Production-deployment caveat** (same as billing-foundation):
11
+ // The tables are registered as raw drizzle-pgTable instances in r.projection,
12
+ // NOT as r.entity. Apps must include them in their drizzle/generate.ts
13
+ // (via *-ProjectionTable imports). setupTestStack pushes them automatically
14
+ // via r.projection.table.
14
15
  //
15
- // **PII:** die Payload-Felder (address/from/to/cc/subject/snippet)
16
- // kommen bereits als Ciphertext an — encrypted VOR dem append im
17
- // write-handler. Die applies kopieren nur durch; decrypted wird erst
18
- // in den list-queries.
16
+ // **PII:** The payload fields (address/from/to/cc/subject/snippet) already
17
+ // arrive as ciphertext because they are encrypted BEFORE the append in the
18
+ // write handler. The applies only copy them through; decryption happens only
19
+ // in the list queries.
19
20
  import { buildEntityTable, insertOnConflictDoNothing, requireEntityTableMeta, upsertOnConflict, } from "@cosmicdrift/kumiko-framework/db";
20
21
  import { defineApply } from "@cosmicdrift/kumiko-framework/engine";
21
22
  import { inboundMessageEntity, mailAccountEntity, mailThreadEntity } from "./entities.js";
22
- // Drizzle-table-instances aus den entity-shapes — geteilt zwischen
23
- // projection-applies und list-queries (ein column-namespace).
23
+ // Drizzle table instances derived from the entity shapes, shared between
24
+ // projection applies and list queries to provide one column namespace.
24
25
  export const mailAccountsProjectionTable = buildEntityTable("mail-account", mailAccountEntity);
25
26
  export const inboundMessagesProjectionTable = buildEntityTable("inbound-message", inboundMessageEntity);
26
27
  export const mailThreadsProjectionTable = buildEntityTable("mail-thread", mailThreadEntity);
@@ -30,9 +31,10 @@ const mailAccountsProjectionMeta = requireEntityTableMeta(mailAccountsProjection
30
31
  const inboundMessagesProjectionMeta = requireEntityTableMeta(inboundMessagesProjectionTable, "inbound-message");
31
32
  const mailThreadsProjectionMeta = requireEntityTableMeta(mailThreadsProjectionTable, "mail-thread");
32
33
  // =============================================================================
33
- // mail-account — connected/updated/disconnected teilen den payload-shape,
34
- // der event-type taggt was passiert ist. Alle drei UPSERT-full für
35
- // defensive consistency (rebuild-aus-dem-Nichts, out-of-order).
34
+ // mail-account — connected/updated/disconnected share the payload shape;
35
+ // the event type identifies what happened. All three perform a full UPSERT
36
+ // for defensive consistency during from-scratch rebuilds and out-of-order
37
+ // processing.
36
38
  // =============================================================================
37
39
  const applyMailAccountUpsert = defineApply(async (event, tx) => {
38
40
  const p = event.payload;
@@ -57,15 +59,15 @@ const applyMailAccountUpsert = defineApply(async (event, tx) => {
57
59
  });
58
60
  /** mail-account-connected → UPSERT full. */
59
61
  export const applyMailAccountConnected = applyMailAccountUpsert;
60
- /** mail-account-updated → UPSERT full (status/watchState-Übergänge). */
62
+ /** mail-account-updated → full UPSERT for status/watchState transitions. */
61
63
  export const applyMailAccountUpdated = applyMailAccountUpsert;
62
- /** mail-account-disconnected → UPSERT full (payload.status=disconnected).
63
- * Row bleibt (Audit-Sicht in der Account-Liste), Stream bleibt. */
64
+ /** mail-account-disconnected → full UPSERT (payload.status=disconnected).
65
+ * The row and stream remain for audit visibility in the account list. */
64
66
  export const applyMailAccountDisconnected = applyMailAccountUpsert;
65
67
  // =============================================================================
66
- // inbound-message — genau EIN received-event pro Stream (deterministic
67
- // aggregateId). INSERT-ignore: Replays no-op'en auf der PK statt zu
68
- // knallen; es gibt keinen update-Fall.
68
+ // inbound-message — exactly one received event per stream (deterministic
69
+ // aggregateId). INSERT-ignore makes replays no-ops on the primary key;
70
+ // there is no update case.
69
71
  // =============================================================================
70
72
  /** inbound-message-received → INSERT ... ON CONFLICT DO NOTHING. */
71
73
  export const applyInboundMessageReceived = defineApply(async (event, tx) => {
@@ -88,12 +90,12 @@ export const applyInboundMessageReceived = defineApply(async (event, tx) => {
88
90
  });
89
91
  });
90
92
  // =============================================================================
91
- // mail-thread — Rollup pro (tenantId, threadKey). Der write-handler
92
- // berechnet messageCount/lastMessageAt und appendet den updated-event
93
- // mit dem NEUEN Stand — die apply ist ein dummer UPSERT-full (kein
94
- // increment in der apply: Replays wären sonst nicht idempotent).
93
+ // mail-thread — rollup per (tenantId, threadKey). The write handler computes
94
+ // messageCount/lastMessageAt and appends the updated event with the NEW state.
95
+ // The apply performs a full UPSERT rather than incrementing, because
96
+ // replays would otherwise not be idempotent.
95
97
  // =============================================================================
96
- /** mail-thread-updated → UPSERT full mit dem Payload-Snapshot. */
98
+ /** mail-thread-updated → full UPSERT with the payload snapshot. */
97
99
  export const applyMailThreadUpdated = defineApply(async (event, tx) => {
98
100
  const p = event.payload;
99
101
  const mutable = {
@@ -1,7 +1,7 @@
1
1
  import { type InboundMailContext, type InboundMailProviderPlugin, type MailAccountRecord } from "./types.ts";
2
- /** Lookup per Provider-Key ("imap", "m365-graph", ...) — genutzt von den
3
- * OAuth-Connect-Routen, wo noch kein Account existiert. */
2
+ /** Looks up a provider by key ("imap", "m365-graph", ...); used by OAuth
3
+ * connect routes before an account exists. */
4
4
  export declare function resolveInboundProviderForKey(ctx: InboundMailContext, providerKey: string, handlerName?: string): InboundMailProviderPlugin;
5
- /** Lookup für einen konkreten Account — der Standard-Pfad in Poll-Job
6
- * und Watch-Supervisor. */
5
+ /** Looks up the provider for a specific account; the standard path for poll jobs
6
+ * and the watch supervisor. */
7
7
  export declare function resolveInboundProviderForAccount(ctx: InboundMailContext, account: MailAccountRecord, handlerName?: string): InboundMailProviderPlugin;
@@ -1,12 +1,12 @@
1
- // Provider-Factory — Mirror von mail-foundation's createTransportForTenant
2
- // inkl. der drei Fehlerpfade (kein registry / nicht registriert / falsche
3
- // Plugin-Shape). Abweichung zum Outbound-Muster (Plan §1.3): KEIN
4
- // per-Tenant-Config-Selector — der Provider steht pro MailAccount
5
- // (`account.provider`), ein Tenant kann mehrere Provider parallel nutzen.
1
+ // Provider factory — mirrors mail-foundation's createTransportForTenant, including
2
+ // the three error paths (missing registry, unregistered provider, invalid plugin
3
+ // shape). Unlike the outbound pattern, there is no per-tenant config selector:
4
+ // the provider is specified per MailAccount (`account.provider`), so a tenant can
5
+ // use multiple providers in parallel.
6
6
  import { INBOUND_MAIL_FOUNDATION_FEATURE, INBOUND_MAIL_PROVIDER_EXTENSION } from "./constants.js";
7
7
  import { isInboundMailProviderPlugin, } from "./types.js";
8
- /** Lookup per Provider-Key ("imap", "m365-graph", ...) — genutzt von den
9
- * OAuth-Connect-Routen, wo noch kein Account existiert. */
8
+ /** Looks up a provider by key ("imap", "m365-graph", ...); used by OAuth
9
+ * connect routes before an account exists. */
10
10
  export function resolveInboundProviderForKey(ctx, providerKey, handlerName = "inbound-mail-foundation:provider-factory") {
11
11
  if (!ctx.registry) {
12
12
  throw new Error(`${handlerName}: ctx.registry is missing — required to look up registered inbound-mail provider plugins`);
@@ -24,8 +24,8 @@ export function resolveInboundProviderForKey(ctx, providerKey, handlerName = "in
24
24
  }
25
25
  return usage.options;
26
26
  }
27
- /** Lookup für einen konkreten Account — der Standard-Pfad in Poll-Job
28
- * und Watch-Supervisor. */
27
+ /** Looks up the provider for a specific account; the standard path for poll jobs
28
+ * and the watch supervisor. */
29
29
  export function resolveInboundProviderForAccount(ctx, account, handlerName = "inbound-mail-foundation:provider-factory") {
30
30
  return resolveInboundProviderForKey(ctx, account.provider, handlerName);
31
31
  }
@@ -7,12 +7,14 @@ export declare const SEEN_RETENTION_DAYS = 90;
7
7
  export interface InboundRetentionArgs {
8
8
  readonly db: DbRunner;
9
9
  readonly tenantId: TenantId;
10
- /** Now-Injection — Tests pinnen den Wert ohne Date-Mock (Pattern keep-for.ts). */
10
+ /**
11
+ * Injects the current time so tests can pin it without a date mock (pattern from keep-for.ts).
12
+ */
11
13
  readonly now: Instant;
12
14
  readonly messageRetentionDays?: number;
13
15
  readonly seenRetentionDays?: number;
14
- /** Loescht ein file-storage-Body-Objekt per bodyRef-key. Vom Job lazy
15
- * verdrahtet (createFileProviderForTenant). Fehlt = kein Body-Delete. */
16
+ /** Deletes a file-storage body object by bodyRef key. Wired lazily by the job
17
+ * (createFileProviderForTenant); if absent, no body is deleted. */
16
18
  readonly deleteBodyObject?: (bodyRef: string) => Promise<void>;
17
19
  }
18
20
  export interface InboundRetentionReport {
@@ -1,28 +1,30 @@
1
- // Inbound-mail data-retention (#957). DSGVO Art. 5 (Datenminimierung):
2
- // ohne Retention wachsen read_inbound_messages + die File-Storage-Bodies
3
- // unbegrenzt. Zwei Targets, zwei Mechanismen — der Unterschied ist
4
- // event-sourced vs. unmanaged:
1
+ // Inbound-mail data retention. DSGVO Art. 5 (data minimization):
2
+ // without retention, read_inbound_messages and the file-storage bodies grow
3
+ // without bound. Two targets, two mechanisms—the difference is
4
+ // event-sourced versus unmanaged:
5
5
  //
6
- // read_inbound_messages (event-sourced, EXPLIZITE r.projection):
7
- // pro Row aelter als messageRetentionDays → archiveStream + Row-Delete
8
- // (+ bodyRef-Objekt loeschen). archiveStream statt executor.forget, weil
9
- // die Projection nur das received-Domain-Event mappt, nicht den
10
- // forgotten-Auto-Verb (den registriert nur ImplicitProjection). Ein
11
- // forget-Event wuerde beim Rebuild ignoriert und die Row aus dem
12
- // received-Event resurrecten (#648-Klasse). Der archivierte Stream macht
13
- // loadAggregate leer → received wird gar nicht erst repliziert. Gleiches
14
- // Muster wie tenant-destroy-hook, nur per-Row-cutoff statt ganzer Tenant.
6
+ // read_inbound_messages (event-sourced, EXPLICIT r.projection):
7
+ // each Row older than messageRetentionDays → archiveStream + Row delete
8
+ // (+ delete the bodyRef object). archiveStream instead of executor.forget
9
+ // because the projection maps only the received domain event, not the
10
+ // forgotten auto-verb (which only ImplicitProjection registers). A
11
+ // forget event would be ignored during a rebuild, causing the Row to be
12
+ // resurrected from the received event. The archived stream makes
13
+ // loadAggregate empty, so received is not replicated in the first place.
14
+ // Same pattern as tenant-destroy-hook, but with a per-Row cutoff instead
15
+ // of an entire Tenant.
15
16
  //
16
- // store_mail_seen_messages (unmanaged, direct-write, nicht event-sourced):
17
- // Dedup-Anker braucht nur das Backfill-/Replay-Fenster → seenAt-cutoff
18
- // via plain deleteMany, kein Stream/Archiv. Gescoped direkt über die
19
- // tenant_id-Spalte der Tabelle (table-builder-Konvention), kein Account-Join.
17
+ // store_mail_seen_messages (unmanaged, direct-write, not event-sourced):
18
+ // The deduplication anchor is needed only for the backfill/replay window →
19
+ // seenAt cutoff via plain deleteMany, with no stream/archive. Scoped
20
+ // directly through the table's tenant_id column (table-builder convention),
21
+ // without an Account join.
20
22
  //
21
- // GRENZE (#957 Teil 2, Plan §3.4): die PII in den Message-Events bleibt
22
- // unter dem TENANT-Subject-Key entschluesselbar — per-Row-Retention
23
- // shreddet keinen Key. Echte Art.-17-Erasure der Event-Payloads passiert
24
- // erst bei tenant-destroy (Key-Erase). Read-Row + Body-File sind nach dem
25
- // Sweep weg; das Event-Log ist append-only by design.
23
+ // LIMITATION: the PII in the message events remains decryptable under the
24
+ // TENANT subject key—per-Row retention does not shred a key. Actual Art.-17
25
+ // erasure of event payloads happens only during tenant-destroy (key erasure).
26
+ // The read Row and body file are gone after the sweep; the event log is
27
+ // append-only by design.
26
28
  import { deleteMany, selectMany } from "@cosmicdrift/kumiko-framework/db";
27
29
  import { archiveStream, deleteRowsWithoutReplayableStream, } from "@cosmicdrift/kumiko-framework/event-store";
28
30
  import { seenMessageTable } from "./entities.js";
@@ -46,18 +48,18 @@ async function purgeExpiredMessages(args, cutoff) {
46
48
  let messagesPurged = 0;
47
49
  let bodyObjectsDeleted = 0;
48
50
  let bodyObjectErrors = 0;
49
- // Drain-Loop: jede Page loescht die Rows die sie liest, die naechste ist
50
- // damit frisch. archiveStream VOR dem Delete (crash dazwischen → naechster
51
- // Lauf re-archiviert idempotent + loescht). Delete strikt nach den
52
- // archivierten ids, nie per cutoff-WHERE — sonst koennte eine zwischen
53
- // select und delete eingegangene Alt-Mail unarchiviert geloescht werden
54
- // und beim Rebuild resurrecten.
51
+ // Drain loop: each page deletes the Rows it reads, so the next page is fresh.
52
+ // Run archiveStream BEFORE deletion: if a crash occurs in between, the next
53
+ // run re-archives idempotently and deletes the Row. Delete strictly by the
54
+ // archived IDs, never with a cutoff WHERE; otherwise an old mail arriving
55
+ // between select and delete could be deleted without being archived and
56
+ // resurrected during a rebuild.
55
57
  //
56
- // Ein Row deren deleteBodyObject fehlschlaegt wird NICHT geloescht — sonst
57
- // ginge die einzige Referenz auf das (dann verwaiste) File-Objekt verloren
58
- // (kein Retry, kein Dead-Letter). Die Row bleibt fuer den naechsten Sweep
59
- // stehen (archiveStream ist idempotent). failedIds verhindert, dass so ein
60
- // Row innerhalb DIESES Laufs endlos re-selektiert wird.
58
+ // A Row whose deleteBodyObject fails is NOT deleted; otherwise the only
59
+ // reference to the now-orphaned file object would be lost (no retry or
60
+ // dead-letter). The Row remains for the next sweep (archiveStream is
61
+ // idempotent). failedIds prevents such a Row from being selected endlessly
62
+ // during THIS run.
61
63
  const failedIds = new Set();
62
64
  for (;;) {
63
65
  const rows = (await selectMany(args.db, inboundMessagesProjectionTable, { receivedAt: { lt: cutoff }, tenantId: args.tenantId }, { limit: BATCH_LIMIT })).filter((row) => !failedIds.has(row.id));
@@ -99,9 +101,9 @@ async function purgeExpiredMessages(args, cutoff) {
99
101
  return { messagesPurged, bodyObjectsDeleted, bodyObjectErrors };
100
102
  }
101
103
  async function purgeExpiredSeenAnchors(db, tenantId, cutoff) {
102
- // Seen-Anker erben tenantId (table-builder: jede Entity hat tenant_id) →
103
- // direkt tenant-scoped, kein Account-Join. Trifft auch Anker, deren Account
104
- // schon disconnected/geloescht ist.
104
+ // Seen anchors inherit tenantId (table-builder: every Entity has tenant_id) →
105
+ // scoped directly to the tenant, without an Account join. This also includes
106
+ // anchors whose Account has already been disconnected or deleted.
105
107
  const where = { tenantId, seenAt: { lt: cutoff } };
106
108
  const expired = await selectMany(db, seenMessageTable, where);
107
109
  if (expired.length === 0)
@@ -1,21 +1,19 @@
1
- // Tenant-destroy hooks — räumen beim Tenant-Destroy alle Inbound-Mail-
2
- // Spuren des Tenants ab. Ein Hook PRO tenant-subject-Entity (der
3
- // gdpr-storage-Boot-Validator prüft die EXT_TENANT_DATA-Registrierung
4
- // entity-genau), jeweils:
1
+ // Tenant-destroy hooks remove all inbound-mail traces belonging to the tenant.
2
+ // One hook per tenant-subject entity (the gdpr-storage boot validator checks
3
+ // the EXT_TENANT_DATA registration per entity), each of which:
5
4
  //
6
- // 1. Streams archivieren — ein künftiger Projection-Rebuild kann
7
- // Gelöschtes nicht resurrecten (Muster billing-foundation #800).
8
- // Message-Streams sind viele → Loop über die Projection-Rows
9
- // (Row-PK = Stream-ID); tenant-destroy ist ein seltener
10
- // Batch-Vorgang, O(n) ist ok.
11
- // 2. Projection-Rows löschen.
12
- // 3. Nur mail-account: unmanaged Sync-State (Cursors, Seen-Anchors)
13
- // löschen — gekeyt per accountId, deshalb aus den Account-Rows
14
- // VOR dem Delete eingesammelt.
5
+ // 1. Archives streams so a future projection rebuild cannot resurrect
6
+ // deleted data. Message streams are numerous, so loop over the
7
+ // projection rows (row PK = stream ID); tenant-destroy is a rare batch
8
+ // operation, so O(n) is acceptable.
9
+ // 2. Deletes the projection rows.
10
+ // 3. For mail-account only, deletes unmanaged sync state (cursors,
11
+ // seen anchors), which is keyed by accountId and must therefore be
12
+ // collected from the account rows BEFORE deletion.
15
13
  //
16
- // Die eigentliche PII-Erasure macht crypto-shredding: eraseSubjectKeys
17
- // löscht den Tenant-Subject-Key, damit werden Event-Log-Payloads UND
18
- // etwaige Ciphertext-Kopien unlesbar. Diese Hooks entsorgen die Rows.
14
+ // The actual PII erasure uses crypto-shredding: eraseSubjectKeys deletes the
15
+ // tenant subject key, making event-log payloads AND any ciphertext copies
16
+ // unreadable. These hooks dispose of the rows.
19
17
  import { declareEscapeHatch } from "@cosmicdrift/kumiko-framework/engine";
20
18
  import { archiveStream } from "@cosmicdrift/kumiko-framework/event-store";
21
19
  import { seenMessageTable, syncCursorTable } from "./entities.js";