@cosmicdrift/kumiko-samples 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 (395) hide show
  1. package/LICENSE +21 -57
  2. package/README.md +1 -1
  3. package/package.json +2 -2
  4. package/packages/bundled-features/package.json +2 -2
  5. package/packages/bundled-features/src/agent-tools/tool-catalog.ts +1 -1
  6. package/packages/bundled-features/src/agent-tools/tool-dispatch.ts +0 -2
  7. package/packages/bundled-features/src/audit/screens.ts +1 -1
  8. package/packages/bundled-features/src/auth-email-password/auth-user-row.ts +10 -10
  9. package/packages/bundled-features/src/auth-email-password/feature.ts +6 -6
  10. package/packages/bundled-features/src/auth-email-password/handlers/change-password.write.ts +3 -3
  11. package/packages/bundled-features/src/auth-email-password/handlers/confirm-token-flow.ts +5 -5
  12. package/packages/bundled-features/src/auth-email-password/handlers/invite-accept-with-login.write.ts +1 -1
  13. package/packages/bundled-features/src/auth-email-password/handlers/invite-accept.write.ts +18 -18
  14. package/packages/bundled-features/src/auth-email-password/handlers/invite-create.write.ts +12 -12
  15. package/packages/bundled-features/src/auth-email-password/handlers/invite-info.query.ts +1 -1
  16. package/packages/bundled-features/src/auth-email-password/handlers/invite-signup-complete.write.ts +24 -26
  17. package/packages/bundled-features/src/auth-email-password/handlers/login.write.ts +1 -1
  18. package/packages/bundled-features/src/auth-email-password/handlers/self-registration-status.query.ts +1 -1
  19. package/packages/bundled-features/src/auth-email-password/handlers/signup-confirm.write.ts +34 -37
  20. package/packages/bundled-features/src/auth-email-password/handlers/signup-request.write.ts +6 -7
  21. package/packages/bundled-features/src/auth-email-password/handlers/switch-tenant-mfa-gate.write.ts +1 -5
  22. package/packages/bundled-features/src/auth-email-password/index.ts +5 -5
  23. package/packages/bundled-features/src/auth-email-password/lockout-store.ts +1 -1
  24. package/packages/bundled-features/src/auth-email-password/seeding.ts +63 -66
  25. package/packages/bundled-features/src/auth-email-password/signup-token-store.ts +8 -8
  26. package/packages/bundled-features/src/auth-email-password/testing.ts +3 -3
  27. package/packages/bundled-features/src/auth-email-password/web/auth-client.ts +57 -57
  28. package/packages/bundled-features/src/auth-email-password/web/auth-form-primitives.tsx +14 -14
  29. package/packages/bundled-features/src/auth-email-password/web/auth-gate.tsx +15 -16
  30. package/packages/bundled-features/src/auth-email-password/web/client-plugin.ts +11 -12
  31. package/packages/bundled-features/src/auth-email-password/web/confirm-account-unlock-screen.tsx +1 -1
  32. package/packages/bundled-features/src/auth-email-password/web/constants.ts +3 -3
  33. package/packages/bundled-features/src/auth-email-password/web/default-topbar-actions.tsx +14 -14
  34. package/packages/bundled-features/src/auth-email-password/web/forgot-password-screen.tsx +11 -11
  35. package/packages/bundled-features/src/auth-email-password/web/index.ts +5 -5
  36. package/packages/bundled-features/src/auth-email-password/web/invite-accept-screen.tsx +17 -17
  37. package/packages/bundled-features/src/auth-email-password/web/login-screen.tsx +3 -4
  38. package/packages/bundled-features/src/auth-email-password/web/reset-password-screen.tsx +16 -17
  39. package/packages/bundled-features/src/auth-email-password/web/session.tsx +34 -34
  40. package/packages/bundled-features/src/auth-email-password/web/signup-complete-screen.tsx +3 -3
  41. package/packages/bundled-features/src/auth-email-password/web/signup-screen.tsx +14 -14
  42. package/packages/bundled-features/src/auth-email-password/web/tenant-switcher.tsx +26 -27
  43. package/packages/bundled-features/src/auth-email-password/web/use-shell-user.ts +12 -13
  44. package/packages/bundled-features/src/auth-email-password/web/user-menu.tsx +17 -18
  45. package/packages/bundled-features/src/auth-email-password/web/verify-email-screen.tsx +11 -12
  46. package/packages/bundled-features/src/auth-foundation/boot-checks.ts +4 -4
  47. package/packages/bundled-features/src/auth-foundation/resolve-anonymous-access.ts +4 -4
  48. package/packages/bundled-features/src/auth-foundation/types.ts +2 -2
  49. package/packages/bundled-features/src/auth-mfa/handlers/disable.write.ts +3 -3
  50. package/packages/bundled-features/src/auth-mfa/handlers/enable-confirm-preauth.write.ts +4 -4
  51. package/packages/bundled-features/src/auth-mfa/handlers/enable-confirm.write.ts +2 -2
  52. package/packages/bundled-features/src/auth-mfa/handlers/enable-start-preauth.write.ts +1 -1
  53. package/packages/bundled-features/src/auth-mfa/handlers/reencrypt.job.ts +1 -1
  54. package/packages/bundled-features/src/auth-mfa/handlers/regenerate-recovery.write.ts +5 -5
  55. package/packages/bundled-features/src/auth-mfa/handlers/verify.write.ts +1 -1
  56. package/packages/bundled-features/src/auth-mfa/token-secrets.ts +1 -1
  57. package/packages/bundled-features/src/auth-mfa/web/client-plugin.ts +2 -2
  58. package/packages/bundled-features/src/auth-mfa/web/i18n.ts +3 -3
  59. package/packages/bundled-features/src/auth-mfa/web/index.ts +4 -4
  60. package/packages/bundled-features/src/auth-mfa/web/mfa-client.ts +17 -16
  61. package/packages/bundled-features/src/auth-mfa/web/mfa-verify-screen.tsx +6 -6
  62. package/packages/bundled-features/src/billing-foundation/aggregate-id.ts +10 -11
  63. package/packages/bundled-features/src/billing-foundation/entities.ts +27 -27
  64. package/packages/bundled-features/src/billing-foundation/events.ts +22 -21
  65. package/packages/bundled-features/src/billing-foundation/feature.ts +42 -43
  66. package/packages/bundled-features/src/billing-foundation/get-subscription-for-tenant.ts +3 -5
  67. package/packages/bundled-features/src/billing-foundation/handlers/create-checkout-session.write.ts +18 -17
  68. package/packages/bundled-features/src/billing-foundation/handlers/create-portal-session.write.ts +11 -12
  69. package/packages/bundled-features/src/billing-foundation/handlers/list-subscriptions.query.ts +4 -4
  70. package/packages/bundled-features/src/billing-foundation/handlers/process-event.write.ts +20 -20
  71. package/packages/bundled-features/src/billing-foundation/projection.ts +38 -37
  72. package/packages/bundled-features/src/billing-foundation/subscription-tier-sync.ts +3 -3
  73. package/packages/bundled-features/src/billing-foundation/tenant-destroy-hook.ts +7 -8
  74. package/packages/bundled-features/src/billing-foundation/types.ts +64 -65
  75. package/packages/bundled-features/src/billing-foundation/web/billing-plans-panel.tsx +4 -4
  76. package/packages/bundled-features/src/billing-foundation/webhook-handler.ts +1 -1
  77. package/packages/bundled-features/src/cap-counter/aggregate-id.ts +8 -9
  78. package/packages/bundled-features/src/cap-counter/constants.ts +11 -12
  79. package/packages/bundled-features/src/cap-counter/enforce-cap.ts +64 -67
  80. package/packages/bundled-features/src/cap-counter/entity.ts +29 -29
  81. package/packages/bundled-features/src/cap-counter/feature.ts +34 -35
  82. package/packages/bundled-features/src/cap-counter/handlers/increment-rolling.write.ts +31 -31
  83. package/packages/bundled-features/src/cap-counter/handlers/mark-soft-warned.write.ts +4 -5
  84. package/packages/bundled-features/src/cap-counter/stock-cap-guard.ts +1 -1
  85. package/packages/bundled-features/src/cap-counter/with-cap-enforcement.ts +3 -5
  86. package/packages/bundled-features/src/cap-overview/handlers/caps-usage.query.ts +1 -3
  87. package/packages/bundled-features/src/cap-overview/handlers/tenant-caps-list.query.ts +1 -1
  88. package/packages/bundled-features/src/channel-email/smtp-transport.ts +34 -31
  89. package/packages/bundled-features/src/channel-in-app/handlers/unread-count.query.ts +3 -4
  90. package/packages/bundled-features/src/compliance-profiles/feature.ts +15 -16
  91. package/packages/bundled-features/src/compliance-profiles/handlers/for-tenant.query.ts +3 -6
  92. package/packages/bundled-features/src/compliance-profiles/handlers/list-profiles.query.ts +5 -5
  93. package/packages/bundled-features/src/compliance-profiles/handlers/needs-profile.query.ts +4 -4
  94. package/packages/bundled-features/src/compliance-profiles/handlers/set-profile.write.ts +13 -14
  95. package/packages/bundled-features/src/compliance-profiles/handlers/sub-processors.query.ts +9 -11
  96. package/packages/bundled-features/src/compliance-profiles/resolve-for-tenant.ts +7 -7
  97. package/packages/bundled-features/src/compliance-profiles/schema/profile-selection.ts +18 -23
  98. package/packages/bundled-features/src/compliance-profiles/seeding.ts +14 -15
  99. package/packages/bundled-features/src/compliance-profiles-ops/handlers/tenants-missing-profile.query.ts +3 -3
  100. package/packages/bundled-features/src/compliance-profiles-ops/index.ts +2 -2
  101. package/packages/bundled-features/src/config/handlers/readiness.query.ts +7 -7
  102. package/packages/bundled-features/src/config/handlers/reencrypt.job.ts +4 -5
  103. package/packages/bundled-features/src/config/handlers/set.write.ts +4 -4
  104. package/packages/bundled-features/src/config/resolver.ts +4 -4
  105. package/packages/bundled-features/src/config/table.ts +10 -10
  106. package/packages/bundled-features/src/config/write-helpers.ts +1 -1
  107. package/packages/bundled-features/src/crypto-shredding/handlers/forget-subject.write.ts +13 -12
  108. package/packages/bundled-features/src/custom-fields/aggregate-id.ts +16 -17
  109. package/packages/bundled-features/src/custom-fields/entity.ts +49 -47
  110. package/packages/bundled-features/src/custom-fields/events.ts +7 -8
  111. package/packages/bundled-features/src/custom-fields/feature.ts +70 -72
  112. package/packages/bundled-features/src/custom-fields/handlers/clear-custom-field.write.ts +9 -8
  113. package/packages/bundled-features/src/custom-fields/handlers/define-tenant-field.write.ts +28 -26
  114. package/packages/bundled-features/src/custom-fields/handlers/delete-system-field.write.ts +6 -7
  115. package/packages/bundled-features/src/custom-fields/handlers/delete-tenant-field.write.ts +12 -13
  116. package/packages/bundled-features/src/custom-fields/handlers/set-custom-field.write.ts +25 -28
  117. package/packages/bundled-features/src/custom-fields/handlers/update-tenant-field.write.ts +6 -6
  118. package/packages/bundled-features/src/custom-fields/lib/field-access.ts +2 -2
  119. package/packages/bundled-features/src/custom-fields/lib/parse-serialized-field.ts +1 -1
  120. package/packages/bundled-features/src/custom-fields/lib/quota.ts +1 -1
  121. package/packages/bundled-features/src/custom-fields/lib/value-schema.ts +10 -12
  122. package/packages/bundled-features/src/custom-fields/run-retention.ts +3 -3
  123. package/packages/bundled-features/src/custom-fields/schemas.ts +14 -14
  124. package/packages/bundled-features/src/custom-fields/web/client-plugin.tsx +2 -5
  125. package/packages/bundled-features/src/custom-fields/web/constants.ts +2 -2
  126. package/packages/bundled-features/src/custom-fields/web/custom-fields-form-section.tsx +26 -26
  127. package/packages/bundled-features/src/custom-fields/wire-for-entity.ts +65 -67
  128. package/packages/bundled-features/src/custom-fields/wire-user-data-rights.ts +3 -3
  129. package/packages/bundled-features/src/data-retention/_internal/parse-override.ts +2 -3
  130. package/packages/bundled-features/src/data-retention/feature.ts +11 -18
  131. package/packages/bundled-features/src/data-retention/handlers/policy-for.query.ts +6 -6
  132. package/packages/bundled-features/src/data-retention/keep-for.ts +17 -17
  133. package/packages/bundled-features/src/data-retention/override-schema.ts +13 -15
  134. package/packages/bundled-features/src/data-retention/presets.ts +18 -23
  135. package/packages/bundled-features/src/data-retention/resolve-for-tenant.ts +1 -1
  136. package/packages/bundled-features/src/data-retention/resolve-tenant-preset.ts +17 -16
  137. package/packages/bundled-features/src/data-retention/resolver.ts +33 -32
  138. package/packages/bundled-features/src/data-retention/run-retention-cleanup.ts +71 -58
  139. package/packages/bundled-features/src/data-retention/schema/tenant-retention-override.ts +13 -11
  140. package/packages/bundled-features/src/delivery/feature.ts +3 -3
  141. package/packages/bundled-features/src/delivery/handlers/log.query.ts +1 -1
  142. package/packages/bundled-features/src/delivery/tables.ts +9 -8
  143. package/packages/bundled-features/src/delivery/unsubscribe.ts +4 -4
  144. package/packages/bundled-features/src/delivery/upsert-preference.ts +3 -4
  145. package/packages/bundled-features/src/document-ingest-foundation/entity.ts +5 -5
  146. package/packages/bundled-features/src/document-ingest-foundation/events.ts +2 -2
  147. package/packages/bundled-features/src/document-ingest-foundation/feature.ts +2 -2
  148. package/packages/bundled-features/src/document-ingest-foundation/pages.ts +1 -1
  149. package/packages/bundled-features/src/document-ingest-foundation/tenant-destroy-hook.ts +4 -4
  150. package/packages/bundled-features/src/feature-toggles/compose-tier-resolver.ts +1 -1
  151. package/packages/bundled-features/src/feature-toggles/feature.ts +1 -1
  152. package/packages/bundled-features/src/feature-toggles/global-feature-state-table.ts +1 -1
  153. package/packages/bundled-features/src/feature-toggles/handlers/registered.query.ts +5 -5
  154. package/packages/bundled-features/src/feature-toggles/toggle-runtime.ts +1 -1
  155. package/packages/bundled-features/src/feature-toggles/toggle-sync-signal.ts +1 -1
  156. package/packages/bundled-features/src/feature-toggles/web/constants.ts +1 -1
  157. package/packages/bundled-features/src/file-derivatives/feature.ts +2 -2
  158. package/packages/bundled-features/src/file-derivatives/handlers/public-variant.query.ts +1 -1
  159. package/packages/bundled-features/src/file-derivatives/presets.ts +1 -1
  160. package/packages/bundled-features/src/file-foundation/feature.ts +6 -6
  161. package/packages/bundled-features/src/file-provider-inmemory/feature.ts +16 -16
  162. package/packages/bundled-features/src/file-provider-s3/feature.ts +16 -16
  163. package/packages/bundled-features/src/file-provider-s3/lib/s3-provider.ts +6 -6
  164. package/packages/bundled-features/src/files/feature.ts +6 -6
  165. package/packages/bundled-features/src/files-tenant-data/handlers/sweep-orphaned-derivatives.job.ts +5 -5
  166. package/packages/bundled-features/src/files-tenant-data/hooks.ts +24 -26
  167. package/packages/bundled-features/src/files-tenant-data/index.ts +1 -1
  168. package/packages/bundled-features/src/folders/feature.ts +1 -1
  169. package/packages/bundled-features/src/folders/web/folder-manager.tsx +2 -2
  170. package/packages/bundled-features/src/folders/web/tree.ts +5 -5
  171. package/packages/bundled-features/src/form-draft/db/queries/cleanup.ts +1 -1
  172. package/packages/bundled-features/src/form-draft/db/queries/owned-file-refs.ts +1 -1
  173. package/packages/bundled-features/src/form-draft/entity.ts +3 -3
  174. package/packages/bundled-features/src/form-draft/feature.ts +4 -5
  175. package/packages/bundled-features/src/form-draft/handlers/discard.write.ts +1 -1
  176. package/packages/bundled-features/src/form-draft/release-file-refs.ts +6 -6
  177. package/packages/bundled-features/src/form-draft/schemas.ts +3 -3
  178. package/packages/bundled-features/src/form-draft/web/constants.ts +0 -2
  179. package/packages/bundled-features/src/inbound-mail-foundation/aggregate-id.ts +19 -19
  180. package/packages/bundled-features/src/inbound-mail-foundation/connect-routes.ts +4 -3
  181. package/packages/bundled-features/src/inbound-mail-foundation/constants.ts +30 -33
  182. package/packages/bundled-features/src/inbound-mail-foundation/entities.ts +47 -48
  183. package/packages/bundled-features/src/inbound-mail-foundation/events.ts +54 -50
  184. package/packages/bundled-features/src/inbound-mail-foundation/feature.ts +39 -39
  185. package/packages/bundled-features/src/inbound-mail-foundation/handlers/account-state.ts +8 -8
  186. package/packages/bundled-features/src/inbound-mail-foundation/handlers/connect-account.write.ts +25 -26
  187. package/packages/bundled-features/src/inbound-mail-foundation/handlers/disconnect-account.write.ts +7 -7
  188. package/packages/bundled-features/src/inbound-mail-foundation/handlers/ingest-message.write.ts +50 -51
  189. package/packages/bundled-features/src/inbound-mail-foundation/handlers/list-accounts.query.ts +8 -8
  190. package/packages/bundled-features/src/inbound-mail-foundation/handlers/list-messages.query.ts +10 -10
  191. package/packages/bundled-features/src/inbound-mail-foundation/handlers/scope-visibility.ts +3 -4
  192. package/packages/bundled-features/src/inbound-mail-foundation/handlers/update-account.write.ts +11 -11
  193. package/packages/bundled-features/src/inbound-mail-foundation/oauth-state.ts +16 -15
  194. package/packages/bundled-features/src/inbound-mail-foundation/projection.ts +31 -29
  195. package/packages/bundled-features/src/inbound-mail-foundation/provider-factory.ts +9 -9
  196. package/packages/bundled-features/src/inbound-mail-foundation/retention-sweep.ts +45 -41
  197. package/packages/bundled-features/src/inbound-mail-foundation/tenant-destroy-hook.ts +14 -16
  198. package/packages/bundled-features/src/inbound-mail-foundation/types.ts +66 -67
  199. package/packages/bundled-features/src/inbound-mail-foundation/watch-supervisor.ts +69 -68
  200. package/packages/bundled-features/src/inbound-provider-imap/credential-document.ts +13 -13
  201. package/packages/bundled-features/src/inbound-provider-imap/feature.ts +42 -40
  202. package/packages/bundled-features/src/inbound-provider-imap/imap-client.ts +20 -19
  203. package/packages/bundled-features/src/inbound-provider-inmemory/feature.ts +21 -21
  204. package/packages/bundled-features/src/jobs/db/queries/retention.ts +2 -2
  205. package/packages/bundled-features/src/jobs/db/queries/stale-run-sweep.ts +3 -3
  206. package/packages/bundled-features/src/jobs/events.ts +1 -1
  207. package/packages/bundled-features/src/jobs/feature.ts +6 -7
  208. package/packages/bundled-features/src/jobs/handlers/detail.query.ts +4 -4
  209. package/packages/bundled-features/src/jobs/handlers/list.query.ts +1 -1
  210. package/packages/bundled-features/src/jobs/handlers/projection-rebuild.job.ts +1 -1
  211. package/packages/bundled-features/src/jobs/handlers/reindex-entity.job.ts +1 -1
  212. package/packages/bundled-features/src/jobs/handlers/retry.write.ts +1 -1
  213. package/packages/bundled-features/src/jobs/job-instant.ts +1 -1
  214. package/packages/bundled-features/src/jobs/job-run-logger.ts +14 -15
  215. package/packages/bundled-features/src/jobs/job-run-table.ts +3 -3
  216. package/packages/bundled-features/src/jobs/screens.ts +1 -1
  217. package/packages/bundled-features/src/jobs/tenant-job-failure-table.ts +1 -1
  218. package/packages/bundled-features/src/jobs/tenant-job-run-table.ts +1 -1
  219. package/packages/bundled-features/src/ledger/entity.ts +5 -5
  220. package/packages/bundled-features/src/ledger/feature.ts +3 -3
  221. package/packages/bundled-features/src/ledger/handlers/confirm-schedule-period.write.ts +3 -3
  222. package/packages/bundled-features/src/ledger/recurring.ts +12 -12
  223. package/packages/bundled-features/src/ledger/schemas.ts +1 -1
  224. package/packages/bundled-features/src/ledger/web/constants.ts +2 -2
  225. package/packages/bundled-features/src/ledger/web/index.ts +7 -7
  226. package/packages/bundled-features/src/legal-pages/feature.ts +40 -41
  227. package/packages/bundled-features/src/legal-pages/markdown.ts +3 -3
  228. package/packages/bundled-features/src/legal-pages/web/client-plugin.ts +23 -24
  229. package/packages/bundled-features/src/legal-pages/web/index.ts +0 -2
  230. package/packages/bundled-features/src/mail-foundation/feature.ts +26 -27
  231. package/packages/bundled-features/src/mail-transport-inmemory/feature.ts +27 -28
  232. package/packages/bundled-features/src/mail-transport-smtp/feature.ts +20 -20
  233. package/packages/bundled-features/src/managed-pages/branding.ts +6 -6
  234. package/packages/bundled-features/src/managed-pages/feature.ts +62 -62
  235. package/packages/bundled-features/src/managed-pages/handlers/by-slug.query.ts +5 -6
  236. package/packages/bundled-features/src/managed-pages/handlers/by-tenant-published.query.ts +8 -8
  237. package/packages/bundled-features/src/managed-pages/handlers/set.write.ts +5 -7
  238. package/packages/bundled-features/src/managed-pages/screens/page-screens.ts +11 -11
  239. package/packages/bundled-features/src/managed-pages/seeding.ts +8 -8
  240. package/packages/bundled-features/src/managed-pages/table.ts +16 -15
  241. package/packages/bundled-features/src/managed-pages/web/client-plugin.tsx +6 -6
  242. package/packages/bundled-features/src/managed-pages/web/i18n.ts +1 -1
  243. package/packages/bundled-features/src/notes-history/entity.ts +4 -4
  244. package/packages/bundled-features/src/notes-history/feature.ts +2 -2
  245. package/packages/bundled-features/src/notes-history-user-data/hooks.ts +1 -1
  246. package/packages/bundled-features/src/page-render/layout.ts +9 -9
  247. package/packages/bundled-features/src/page-render/markdown.ts +11 -11
  248. package/packages/bundled-features/src/page-render/security-headers.ts +7 -6
  249. package/packages/bundled-features/src/personal-access-tokens/feature.ts +5 -5
  250. package/packages/bundled-features/src/personal-access-tokens/roles.ts +2 -2
  251. package/packages/bundled-features/src/readiness/handlers/status.query.ts +3 -3
  252. package/packages/bundled-features/src/renderer-foundation/api.ts +12 -13
  253. package/packages/bundled-features/src/renderer-foundation/constants.ts +2 -2
  254. package/packages/bundled-features/src/renderer-foundation/feature.ts +7 -7
  255. package/packages/bundled-features/src/renderer-foundation/types.ts +11 -12
  256. package/packages/bundled-features/src/secrets/feature.ts +9 -9
  257. package/packages/bundled-features/src/secrets/web/constants.ts +2 -2
  258. package/packages/bundled-features/src/seo/feature.ts +3 -3
  259. package/packages/bundled-features/src/sessions/constants.ts +1 -1
  260. package/packages/bundled-features/src/sessions/feature.ts +9 -9
  261. package/packages/bundled-features/src/sessions/handlers/revoke-all-for-user.write.ts +2 -2
  262. package/packages/bundled-features/src/sessions/handlers/revoke-all-others.write.ts +2 -2
  263. package/packages/bundled-features/src/sessions/handlers/revoke.write.ts +1 -1
  264. package/packages/bundled-features/src/sessions/schema/user-session.ts +4 -4
  265. package/packages/bundled-features/src/sessions/screens.ts +2 -2
  266. package/packages/bundled-features/src/sessions/session-callbacks.ts +2 -2
  267. package/packages/bundled-features/src/sessions/session-revoked-event.ts +2 -2
  268. package/packages/bundled-features/src/shared/assert-no-where-rule-in-ownership-write.ts +1 -1
  269. package/packages/bundled-features/src/shared/decrypt-stored-pii.ts +1 -1
  270. package/packages/bundled-features/src/shared/encrypt-for-direct-write.ts +1 -1
  271. package/packages/bundled-features/src/shared/map-with-concurrency.ts +5 -4
  272. package/packages/bundled-features/src/shared/parent-visibility.ts +2 -2
  273. package/packages/bundled-features/src/shared/password-hashing.ts +1 -1
  274. package/packages/bundled-features/src/shared/signup-handover.ts +1 -2
  275. package/packages/bundled-features/src/shared/single-use-token-store.ts +1 -1
  276. package/packages/bundled-features/src/subscription-mollie/constants.ts +15 -17
  277. package/packages/bundled-features/src/subscription-mollie/feature.ts +41 -42
  278. package/packages/bundled-features/src/subscription-mollie/index.ts +3 -3
  279. package/packages/bundled-features/src/subscription-mollie/plugin-methods.ts +17 -16
  280. package/packages/bundled-features/src/subscription-mollie/verify-webhook.ts +34 -34
  281. package/packages/bundled-features/src/subscription-stripe/constants.ts +4 -6
  282. package/packages/bundled-features/src/subscription-stripe/feature.ts +44 -43
  283. package/packages/bundled-features/src/subscription-stripe/index.ts +6 -6
  284. package/packages/bundled-features/src/subscription-stripe/plugin-methods.ts +22 -27
  285. package/packages/bundled-features/src/subscription-stripe/runtime.ts +2 -2
  286. package/packages/bundled-features/src/subscription-stripe/verify-webhook.ts +62 -64
  287. package/packages/bundled-features/src/tags/feature.ts +3 -3
  288. package/packages/bundled-features/src/tags/screens.ts +1 -1
  289. package/packages/bundled-features/src/template-resolver/api.ts +10 -10
  290. package/packages/bundled-features/src/template-resolver/handlers/find-by-id.query.ts +5 -5
  291. package/packages/bundled-features/src/template-resolver/handlers/list.query.ts +1 -1
  292. package/packages/bundled-features/src/template-resolver/handlers/shared.ts +2 -2
  293. package/packages/bundled-features/src/template-resolver/handlers/template-write.ts +3 -3
  294. package/packages/bundled-features/src/template-resolver/handlers/upsert-system.write.ts +3 -4
  295. package/packages/bundled-features/src/template-resolver/handlers/upsert-tenant.write.ts +4 -5
  296. package/packages/bundled-features/src/template-resolver/seeding.ts +4 -4
  297. package/packages/bundled-features/src/template-resolver/table.ts +13 -14
  298. package/packages/bundled-features/src/template-resolver/web/client-plugin.tsx +2 -2
  299. package/packages/bundled-features/src/tenant/feature.ts +7 -7
  300. package/packages/bundled-features/src/tenant/handlers/member-directory.query.ts +1 -1
  301. package/packages/bundled-features/src/tenant/handlers/members.query.ts +1 -1
  302. package/packages/bundled-features/src/tenant/handlers/memberships.query.ts +1 -1
  303. package/packages/bundled-features/src/tenant/handlers/team-list.query.ts +1 -1
  304. package/packages/bundled-features/src/tenant/handlers/tenant-directory.query.ts +1 -1
  305. package/packages/bundled-features/src/tenant/invitation-table.ts +37 -40
  306. package/packages/bundled-features/src/tenant/membership-table.ts +3 -3
  307. package/packages/bundled-features/src/tenant/schema/tenant.ts +7 -9
  308. package/packages/bundled-features/src/tenant/screens.ts +1 -1
  309. package/packages/bundled-features/src/tenant/seeding.ts +19 -18
  310. package/packages/bundled-features/src/tenant/testing.ts +5 -6
  311. package/packages/bundled-features/src/tenant/web/constants.ts +2 -2
  312. package/packages/bundled-features/src/tenant-handover/events.ts +5 -7
  313. package/packages/bundled-features/src/tenant-handover/feature.ts +1 -1
  314. package/packages/bundled-features/src/tenant-handover/grant.ts +1 -1
  315. package/packages/bundled-features/src/tenant-handover/handlers/claim.write.ts +1 -1
  316. package/packages/bundled-features/src/tenant-handover/move-entity-graph.ts +8 -9
  317. package/packages/bundled-features/src/tenant-handover/signup-handover-provider.ts +1 -2
  318. package/packages/bundled-features/src/tenant-handover/transfer-graph.ts +4 -5
  319. package/packages/bundled-features/src/tenant-lifecycle/boot-checks.ts +1 -1
  320. package/packages/bundled-features/src/tenant-lifecycle/feature.ts +1 -1
  321. package/packages/bundled-features/src/tenant-lifecycle/run-tenant-destroy.ts +2 -2
  322. package/packages/bundled-features/src/tenant-lifecycle/stages.ts +1 -1
  323. package/packages/bundled-features/src/tenant-settings/constants.ts +1 -1
  324. package/packages/bundled-features/src/tenant-settings/tenant-defaults.ts +12 -5
  325. package/packages/bundled-features/src/tier-engine/aggregate-id.ts +15 -16
  326. package/packages/bundled-features/src/tier-engine/compose-app.ts +14 -14
  327. package/packages/bundled-features/src/tier-engine/entity.ts +18 -19
  328. package/packages/bundled-features/src/tier-engine/feature.ts +88 -87
  329. package/packages/bundled-features/src/tier-engine/handlers/active-tier.query.ts +6 -7
  330. package/packages/bundled-features/src/tier-engine/handlers/get-tenant-tier.query.ts +4 -4
  331. package/packages/bundled-features/src/tier-engine/handlers/set-tenant-tier.write.ts +8 -8
  332. package/packages/bundled-features/src/tier-engine/tier-resolver.ts +2 -2
  333. package/packages/bundled-features/src/tier-engine/trial.ts +13 -13
  334. package/packages/bundled-features/src/tier-engine/web/index.ts +4 -4
  335. package/packages/bundled-features/src/user/db/queries/stream-tenant-backfill.ts +8 -8
  336. package/packages/bundled-features/src/user/handlers/create.write.ts +4 -4
  337. package/packages/bundled-features/src/user/schema/user.ts +45 -44
  338. package/packages/bundled-features/src/user/seeding.ts +40 -40
  339. package/packages/bundled-features/src/user/testing.ts +3 -3
  340. package/packages/bundled-features/src/user-data-rights/audit-download.ts +27 -28
  341. package/packages/bundled-features/src/user-data-rights/boot-checks.ts +1 -1
  342. package/packages/bundled-features/src/user-data-rights/deletion-token.ts +1 -1
  343. package/packages/bundled-features/src/user-data-rights/feature.ts +112 -113
  344. package/packages/bundled-features/src/user-data-rights/handlers/cancel-deletion.write.ts +9 -9
  345. package/packages/bundled-features/src/user-data-rights/handlers/confirm-deletion-by-token.write.ts +8 -8
  346. package/packages/bundled-features/src/user-data-rights/handlers/download-by-job.query.ts +29 -30
  347. package/packages/bundled-features/src/user-data-rights/handlers/download-by-token.query.ts +40 -42
  348. package/packages/bundled-features/src/user-data-rights/handlers/export-status.query.ts +8 -9
  349. package/packages/bundled-features/src/user-data-rights/handlers/lift-restriction.write.ts +7 -8
  350. package/packages/bundled-features/src/user-data-rights/handlers/list-download-attempts.query.ts +2 -2
  351. package/packages/bundled-features/src/user-data-rights/handlers/my-audit-log.query.ts +4 -4
  352. package/packages/bundled-features/src/user-data-rights/handlers/request-deletion-by-email.write.ts +30 -29
  353. package/packages/bundled-features/src/user-data-rights/handlers/request-deletion.write.ts +15 -18
  354. package/packages/bundled-features/src/user-data-rights/handlers/request-export.write.ts +42 -41
  355. package/packages/bundled-features/src/user-data-rights/handlers/restrict-account.write.ts +22 -19
  356. package/packages/bundled-features/src/user-data-rights/handlers/run-forget-cleanup.write.ts +8 -8
  357. package/packages/bundled-features/src/user-data-rights/index.ts +8 -10
  358. package/packages/bundled-features/src/user-data-rights/lib/default-mailers.ts +3 -3
  359. package/packages/bundled-features/src/user-data-rights/lib/update-user-lifecycle.ts +24 -27
  360. package/packages/bundled-features/src/user-data-rights/run-export-jobs.ts +166 -276
  361. package/packages/bundled-features/src/user-data-rights/run-forget-cleanup.ts +85 -107
  362. package/packages/bundled-features/src/user-data-rights/run-user-export.ts +67 -69
  363. package/packages/bundled-features/src/user-data-rights/schema/download-attempt.ts +11 -11
  364. package/packages/bundled-features/src/user-data-rights/schema/download-token.ts +37 -41
  365. package/packages/bundled-features/src/user-data-rights/schema/export-job.ts +65 -67
  366. package/packages/bundled-features/src/user-data-rights/token-helpers.ts +21 -25
  367. package/packages/bundled-features/src/user-data-rights/web/client-plugin.tsx +6 -6
  368. package/packages/bundled-features/src/user-data-rights/web/confirm-deletion-screen.tsx +6 -5
  369. package/packages/bundled-features/src/user-data-rights/web/constants.ts +1 -1
  370. package/packages/bundled-features/src/user-data-rights/web/index.ts +5 -5
  371. package/packages/bundled-features/src/user-data-rights/web/privacy-center-screen.tsx +14 -13
  372. package/packages/bundled-features/src/user-data-rights/web/public-deletion-gate.tsx +13 -12
  373. package/packages/bundled-features/src/user-data-rights/web/request-deletion-screen.tsx +6 -6
  374. package/packages/bundled-features/src/user-data-rights/zip-path.ts +41 -40
  375. package/packages/bundled-features/src/user-data-rights-defaults/feature.ts +15 -15
  376. package/packages/bundled-features/src/user-data-rights-defaults/hooks/delivery-attempt.userdata-hook.ts +3 -5
  377. package/packages/bundled-features/src/user-data-rights-defaults/hooks/file-ref.userdata-hook.ts +45 -51
  378. package/packages/bundled-features/src/user-data-rights-defaults/hooks/job-run.userdata-hook.ts +2 -2
  379. package/packages/bundled-features/src/user-data-rights-defaults/hooks/notification-preference.userdata-hook.ts +1 -1
  380. package/packages/bundled-features/src/user-data-rights-defaults/hooks/user-session.userdata-hook.ts +3 -3
  381. package/packages/bundled-features/src/user-data-rights-defaults/hooks/user.userdata-hook.ts +32 -31
  382. package/packages/bundled-features/src/user-profile/handlers/change-email.write.ts +13 -13
  383. package/packages/bundled-features/src/user-profile/index.ts +3 -3
  384. package/packages/bundled-features/src/user-profile/web/client-plugin.ts +1 -1
  385. package/packages/bundled-features/src/user-profile/web/constants.ts +1 -1
  386. package/packages/bundled-features/src/user-profile/web/profile-screen.tsx +1 -1
  387. package/packages/bundled-features/src/workflow-runner/aggregate-id.ts +1 -1
  388. package/packages/bundled-features/src/workflow-runner/event-subscriber.ts +4 -5
  389. package/packages/bundled-features/src/workflow-runner/event-trigger.ts +4 -15
  390. package/packages/bundled-features/src/workflow-runner/feature.ts +2 -2
  391. package/packages/bundled-features/src/workflow-runner/handlers/resume-run.write.ts +4 -4
  392. package/packages/bundled-features/src/workflow-runner/pending-projection.ts +6 -7
  393. package/packages/bundled-features/src/workflow-runner/runner.ts +6 -6
  394. package/packages/bundled-features/src/workflow-runner/tables.ts +6 -6
  395. package/packages/bundled-features/src/workflow-runner/workflow-registry.ts +1 -1
@@ -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
 
13
14
  import { createHmac, randomUUID, timingSafeEqual } from "node:crypto";
14
15
  import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
@@ -18,14 +19,14 @@ const STATE_PURPOSE = "inbound-mail-oauth-connect";
18
19
 
19
20
  export type OAuthStatePayload = {
20
21
  readonly tenantId: string;
21
- /** null = shared-Postfach, sonst persönliches Postfach dieses Users. */
22
+ /** null = shared mailbox; otherwise this user's personal mailbox. */
22
23
  readonly ownerUserId: string | null;
23
24
  readonly providerKey: string;
24
- /** Postfach-Adresse aus dem Connect-Request — landet nach dem
25
- * Token-Exchange im MailAccount. */
25
+ /** Mailbox address from the connect request; after token exchange, it is
26
+ * stored in the MailAccount. */
26
27
  readonly mailbox: string;
27
- /** Einmal-Nonce — macht jeden state einzigartig (kein Replay über
28
- * zwei parallele Connect-Flows hinweg). */
28
+ /** One-time nonce makes each state unique, preventing replay across
29
+ * two parallel connect flows. */
29
30
  readonly nonce: string;
30
31
  };
31
32
 
@@ -72,8 +73,8 @@ export function verifyOAuthState(
72
73
  const expected = sign(hmacInput(payloadB64, expiresAtMs), secret);
73
74
  const expectedBuf = Buffer.from(expected, "base64url");
74
75
  const providedBuf = Buffer.from(providedSig, "base64url");
75
- // Length-check VOR timingSafeEqual — die würde bei Längen-Mismatch
76
- // werfen, und der Throw selbst leakt via Timing.
76
+ // Check the length before timingSafeEqual: it throws on a length mismatch,
77
+ // and the throw itself leaks information through timing.
77
78
  if (expectedBuf.length !== providedBuf.length) return { ok: false, reason: "bad_signature" };
78
79
  if (!timingSafeEqual(expectedBuf, providedBuf)) return { ok: false, reason: "bad_signature" };
79
80
 
@@ -1,21 +1,22 @@
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
 
20
21
  import {
21
22
  buildEntityTable,
@@ -32,8 +33,8 @@ import type {
32
33
  MailThreadEventPayload,
33
34
  } from "./events.ts";
34
35
 
35
- // Drizzle-table-instances aus den entity-shapes — geteilt zwischen
36
- // projection-applies und list-queries (ein column-namespace).
36
+ // Drizzle table instances derived from the entity shapes, shared between
37
+ // projection applies and list queries to provide one column namespace.
37
38
  export const mailAccountsProjectionTable = buildEntityTable("mail-account", mailAccountEntity);
38
39
  export const inboundMessagesProjectionTable = buildEntityTable(
39
40
  "inbound-message",
@@ -57,9 +58,10 @@ const mailThreadsProjectionMeta: EntityTableMeta = requireEntityTableMeta(
57
58
  );
58
59
 
59
60
  // =============================================================================
60
- // mail-account — connected/updated/disconnected teilen den payload-shape,
61
- // der event-type taggt was passiert ist. Alle drei UPSERT-full für
62
- // defensive consistency (rebuild-aus-dem-Nichts, out-of-order).
61
+ // mail-account — connected/updated/disconnected share the payload shape;
62
+ // the event type identifies what happened. All three perform a full UPSERT
63
+ // for defensive consistency during from-scratch rebuilds and out-of-order
64
+ // processing.
63
65
  // =============================================================================
64
66
 
65
67
  const applyMailAccountUpsert = defineApply<MailAccountEventPayload>(async (event, tx) => {
@@ -91,16 +93,16 @@ const applyMailAccountUpsert = defineApply<MailAccountEventPayload>(async (event
91
93
 
92
94
  /** mail-account-connected → UPSERT full. */
93
95
  export const applyMailAccountConnected = applyMailAccountUpsert;
94
- /** mail-account-updated → UPSERT full (status/watchState-Übergänge). */
96
+ /** mail-account-updated → full UPSERT for status/watchState transitions. */
95
97
  export const applyMailAccountUpdated = applyMailAccountUpsert;
96
- /** mail-account-disconnected → UPSERT full (payload.status=disconnected).
97
- * Row bleibt (Audit-Sicht in der Account-Liste), Stream bleibt. */
98
+ /** mail-account-disconnected → full UPSERT (payload.status=disconnected).
99
+ * The row and stream remain for audit visibility in the account list. */
98
100
  export const applyMailAccountDisconnected = applyMailAccountUpsert;
99
101
 
100
102
  // =============================================================================
101
- // inbound-message — genau EIN received-event pro Stream (deterministic
102
- // aggregateId). INSERT-ignore: Replays no-op'en auf der PK statt zu
103
- // knallen; es gibt keinen update-Fall.
103
+ // inbound-message — exactly one received event per stream (deterministic
104
+ // aggregateId). INSERT-ignore makes replays no-ops on the primary key;
105
+ // there is no update case.
104
106
  // =============================================================================
105
107
 
106
108
  /** inbound-message-received → INSERT ... ON CONFLICT DO NOTHING. */
@@ -127,13 +129,13 @@ export const applyInboundMessageReceived = defineApply<InboundMessageEventPayloa
127
129
  );
128
130
 
129
131
  // =============================================================================
130
- // mail-thread — Rollup pro (tenantId, threadKey). Der write-handler
131
- // berechnet messageCount/lastMessageAt und appendet den updated-event
132
- // mit dem NEUEN Stand — die apply ist ein dummer UPSERT-full (kein
133
- // increment in der apply: Replays wären sonst nicht idempotent).
132
+ // mail-thread — rollup per (tenantId, threadKey). The write handler computes
133
+ // messageCount/lastMessageAt and appends the updated event with the NEW state.
134
+ // The apply performs a full UPSERT rather than incrementing, because
135
+ // replays would otherwise not be idempotent.
134
136
  // =============================================================================
135
137
 
136
- /** mail-thread-updated → UPSERT full mit dem Payload-Snapshot. */
138
+ /** mail-thread-updated → full UPSERT with the payload snapshot. */
137
139
  export const applyMailThreadUpdated = defineApply<MailThreadEventPayload>(async (event, tx) => {
138
140
  const p = event.payload;
139
141
  const mutable = {
@@ -1,8 +1,8 @@
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
 
7
7
  import { INBOUND_MAIL_FOUNDATION_FEATURE, INBOUND_MAIL_PROVIDER_EXTENSION } from "./constants.ts";
8
8
  import {
@@ -12,8 +12,8 @@ import {
12
12
  type MailAccountRecord,
13
13
  } from "./types.ts";
14
14
 
15
- /** Lookup per Provider-Key ("imap", "m365-graph", ...) — genutzt von den
16
- * OAuth-Connect-Routen, wo noch kein Account existiert. */
15
+ /** Looks up a provider by key ("imap", "m365-graph", ...); used by OAuth
16
+ * connect routes before an account exists. */
17
17
  export function resolveInboundProviderForKey(
18
18
  ctx: InboundMailContext,
19
19
  providerKey: string,
@@ -42,8 +42,8 @@ export function resolveInboundProviderForKey(
42
42
  return usage.options;
43
43
  }
44
44
 
45
- /** Lookup für einen konkreten Account — der Standard-Pfad in Poll-Job
46
- * und Watch-Supervisor. */
45
+ /** Looks up the provider for a specific account; the standard path for poll jobs
46
+ * and the watch supervisor. */
47
47
  export function resolveInboundProviderForAccount(
48
48
  ctx: InboundMailContext,
49
49
  account: MailAccountRecord,
@@ -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
 
27
29
  import { type DbRunner, deleteMany, selectMany } from "@cosmicdrift/kumiko-framework/db";
28
30
  import type { TenantId } from "@cosmicdrift/kumiko-framework/engine";
@@ -35,8 +37,8 @@ import { seenMessageTable } from "./entities.ts";
35
37
  import { INBOUND_MESSAGE_AGGREGATE_TYPE } from "./events.ts";
36
38
  import { inboundMessagesProjectionTable } from "./projection.ts";
37
39
 
38
- // Temporal.Instant ohne den Caller zwingen es aus globalThis zu ziehen
39
- // (Muster data-retention/keep-for.ts).
40
+ // Provides Temporal.Instant without forcing the caller to obtain it from
41
+ // globalThis (same pattern as data-retention/keep-for.ts).
40
42
  type Instant = InstanceType<ReturnType<typeof getTemporal>["Instant"]>;
41
43
 
42
44
  export const MESSAGE_RETENTION_DAYS = 365;
@@ -48,12 +50,14 @@ const REASON = "retention_expired";
48
50
  export interface InboundRetentionArgs {
49
51
  readonly db: DbRunner;
50
52
  readonly tenantId: TenantId;
51
- /** Now-Injection — Tests pinnen den Wert ohne Date-Mock (Pattern keep-for.ts). */
53
+ /**
54
+ * Injects the current time so tests can pin it without a date mock (pattern from keep-for.ts).
55
+ */
52
56
  readonly now: Instant;
53
57
  readonly messageRetentionDays?: number;
54
58
  readonly seenRetentionDays?: number;
55
- /** Loescht ein file-storage-Body-Objekt per bodyRef-key. Vom Job lazy
56
- * verdrahtet (createFileProviderForTenant). Fehlt = kein Body-Delete. */
59
+ /** Deletes a file-storage body object by bodyRef key. Wired lazily by the job
60
+ * (createFileProviderForTenant); if absent, no body is deleted. */
57
61
  readonly deleteBodyObject?: (bodyRef: string) => Promise<void>;
58
62
  }
59
63
 
@@ -88,18 +92,18 @@ async function purgeExpiredMessages(
88
92
  let bodyObjectsDeleted = 0;
89
93
  let bodyObjectErrors = 0;
90
94
 
91
- // Drain-Loop: jede Page loescht die Rows die sie liest, die naechste ist
92
- // damit frisch. archiveStream VOR dem Delete (crash dazwischen → naechster
93
- // Lauf re-archiviert idempotent + loescht). Delete strikt nach den
94
- // archivierten ids, nie per cutoff-WHERE — sonst koennte eine zwischen
95
- // select und delete eingegangene Alt-Mail unarchiviert geloescht werden
96
- // und beim Rebuild resurrecten.
95
+ // Drain loop: each page deletes the Rows it reads, so the next page is fresh.
96
+ // Run archiveStream BEFORE deletion: if a crash occurs in between, the next
97
+ // run re-archives idempotently and deletes the Row. Delete strictly by the
98
+ // archived IDs, never with a cutoff WHERE; otherwise an old mail arriving
99
+ // between select and delete could be deleted without being archived and
100
+ // resurrected during a rebuild.
97
101
  //
98
- // Ein Row deren deleteBodyObject fehlschlaegt wird NICHT geloescht — sonst
99
- // ginge die einzige Referenz auf das (dann verwaiste) File-Objekt verloren
100
- // (kein Retry, kein Dead-Letter). Die Row bleibt fuer den naechsten Sweep
101
- // stehen (archiveStream ist idempotent). failedIds verhindert, dass so ein
102
- // Row innerhalb DIESES Laufs endlos re-selektiert wird.
102
+ // A Row whose deleteBodyObject fails is NOT deleted; otherwise the only
103
+ // reference to the now-orphaned file object would be lost (no retry or
104
+ // dead-letter). The Row remains for the next sweep (archiveStream is
105
+ // idempotent). failedIds prevents such a Row from being selected endlessly
106
+ // during THIS run.
103
107
  const failedIds = new Set<string>();
104
108
  for (;;) {
105
109
  const rows = (
@@ -153,9 +157,9 @@ async function purgeExpiredSeenAnchors(
153
157
  tenantId: TenantId,
154
158
  cutoff: Instant,
155
159
  ): Promise<number> {
156
- // Seen-Anker erben tenantId (table-builder: jede Entity hat tenant_id) →
157
- // direkt tenant-scoped, kein Account-Join. Trifft auch Anker, deren Account
158
- // schon disconnected/geloescht ist.
160
+ // Seen anchors inherit tenantId (table-builder: every Entity has tenant_id) →
161
+ // scoped directly to the tenant, without an Account join. This also includes
162
+ // anchors whose Account has already been disconnected or deleted.
159
163
  const where = { tenantId, seenAt: { lt: cutoff } };
160
164
  const expired = await selectMany<{ accountId: string }>(db, seenMessageTable, where);
161
165
  if (expired.length === 0) return 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
 
20
18
  import type { EntityTableMeta } from "@cosmicdrift/kumiko-framework/db";
21
19
  import { declareEscapeHatch, type TenantDataHookCtx } from "@cosmicdrift/kumiko-framework/engine";
@@ -1,14 +1,14 @@
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
 
13
13
  import type { ConfigAccessor, Registry } from "@cosmicdrift/kumiko-framework/engine";
14
14
  import type { MetricsHandle } from "@cosmicdrift/kumiko-framework/observability";
@@ -36,23 +36,23 @@ export type InboundMailContext = {
36
36
  };
37
37
 
38
38
  /**
39
- * Plaintext-Sicht auf ein verbundenes Postfach, wie Provider sie sehen.
40
- * Die Foundation decryptet `address` VOR dem Provider-Call — Provider
41
- * arbeiten nie mit `kumiko-pii:`-Ciphertext (Guard analog
42
- * withPiiCiphertextGuard im Transport-Pfad).
39
+ * Plaintext view of a connected mailbox exposed to providers.
40
+ * The Foundation decrypts `address` BEFORE the provider call; providers
41
+ * never receive `kumiko-pii:` ciphertext (guard analogous to
42
+ * withPiiCiphertextGuard in the transport path).
43
43
  */
44
44
  export type MailAccountRecord = {
45
- /** = aggregateId des mail-account-Streams; zugleich Secret-Slot-Key. */
45
+ /** = aggregateId of the mail-account stream and the secret-slot key. */
46
46
  readonly id: string;
47
47
  readonly tenantId: string;
48
- /** Provider-Key wie bei der Extension registriert ("imap", "m365-graph",
48
+ /** Provider key registered with the extension ("imap", "m365-graph",
49
49
  * "gmail-rest"). */
50
50
  readonly provider: string;
51
- /** "password" | "xoauth2" | "oauth" — imap unterscheidet hierüber
52
- * Formular-Connect vs. XOAUTH2-Fallback (Plan §2). */
51
+ /** "password" | "xoauth2" | "oauth" — imap uses this to distinguish
52
+ * form-based connect from the XOAUTH2 fallback. */
53
53
  readonly authMethod: string;
54
- /** null = tenant-geteiltes Postfach, sonst persönliches Postfach
55
- * dieses Users (Sichtbarkeits-Scope, Plan Entscheidung 2). */
54
+ /** null = tenant-shared mailbox; otherwise this user's personal mailbox
55
+ * (visibility scope). */
56
56
  readonly ownerUserId: string | null;
57
57
  /** Postfach-Adresse, Plaintext (decrypted). */
58
58
  readonly address: string;
@@ -62,36 +62,35 @@ export type MailAccountRecord = {
62
62
  };
63
63
 
64
64
  /**
65
- * Normalisierte eingehende Mail — Provider-Output, Ingest-Input.
66
- * Provider-raw-Strukturen (IMAP-Flags, Graph-Objekte) bleiben im
67
- * Provider; hier nur der domain-clean Schnitt.
65
+ * Normalized incoming mail — provider output and ingest input.
66
+ * Provider-specific structures (IMAP flags, Graph objects) remain in the
67
+ * provider; this type contains only the domain-level boundary.
68
68
  */
69
69
  export type RawInboundMessage = {
70
- /** Provider-native Message-ID (IMAP UID, Graph id, Gmail id) —
71
- * Idempotency-Anchor zusammen mit providerName. */
70
+ /** Provider-native message ID (IMAP UID, Graph id, Gmail id) — the
71
+ * idempotency anchor together with providerName. */
72
72
  readonly providerMessageId: string;
73
- /** RFC-5322 Message-ID-Header ohne <>; null wenn der Header fehlt
74
- * (Foundation fällt auf deterministischen Ersatz zurück). */
73
+ /** RFC-5322 Message-ID header without <>; null when the header is missing
74
+ * (the Foundation falls back to a deterministic replacement). */
75
75
  readonly messageIdHeader: string | null;
76
- /** Provider-native Thread-/Conversation-ID falls vorhanden (Graph
77
- * conversationId, Gmail threadId); Foundation bevorzugt sie vor der
78
- * References-Chain beim threadKey-Bau. */
76
+ /** Provider-native thread/conversation ID when available (Graph
77
+ * conversationId, Gmail threadId); the Foundation prefers it over the
78
+ * References chain when building threadKey. */
79
79
  readonly providerThreadId: string | null;
80
- /** References/In-Reply-To-Chain (Message-IDs ohne <>), älteste zuerst. */
80
+ /** References/In-Reply-To chain (message IDs without <>), oldest first. */
81
81
  readonly references: readonly string[];
82
82
  readonly from: string;
83
83
  readonly to: readonly string[];
84
84
  readonly cc: readonly string[];
85
85
  readonly subject: string;
86
- /** Plaintext-Vorschau, provider-generiert oder aus dem Body geschnitten. */
86
+ /** Plaintext preview generated by the provider or truncated from the body. */
87
87
  readonly snippet: string;
88
- /** ISO-Instant — INTERNALDATE bzw. receivedDateTime, nicht Ingest-Zeit. */
88
+ /** ISO instant — INTERNALDATE or receivedDateTime, not ingest time. */
89
89
  readonly receivedAtIso: string;
90
- /** Raw MIME; null im snippet-only-Mode. Foundation persisted ihn nach
91
- * file-foundation und schreibt bodyRef — der Event-Store bleibt
92
- * blob-frei. */
90
+ /** Raw MIME; null in snippet-only mode. The Foundation persists it through
91
+ * file-foundation and writes bodyRef, so the event store remains blob-free. */
93
92
  readonly rawMime: Uint8Array | null;
94
- /** Generischer Scope-Hint ("inbox", Folder-Name) — keine App-Semantik. */
93
+ /** Generic scope hint ("inbox", folder name), with no application semantics. */
95
94
  readonly scope: string;
96
95
  };
97
96
 
@@ -103,8 +102,8 @@ export type SyncCursorPayload = Readonly<Record<string, unknown>>;
103
102
  export type InboundFetchResult = {
104
103
  readonly messages: readonly RawInboundMessage[];
105
104
  readonly nextCursor: SyncCursorPayload;
106
- /** true ⇒ Foundation ruft fetch im selben Poll-Tick erneut auf
107
- * (Pagination), bis false oder maxMessages-Budget erschöpft. */
105
+ /** true ⇒ the Foundation calls fetch again in the same poll tick
106
+ * (pagination) until false or the maxMessages budget is exhausted. */
108
107
  readonly hasMore: boolean;
109
108
  };
110
109
 
@@ -117,13 +116,13 @@ export type OAuthTokenSet = {
117
116
  };
118
117
 
119
118
  /**
120
- * OAuth-Teil des Contracts — nur OAuth-Provider; imap (Passwort-Modus)
121
- * lässt `oauth` weg. Die Routen (`/inbound-mail/connect`,
122
- * `/inbound-mail/oauth/callback`) stellt die Foundation generisch —
123
- * Provider registrieren KEINE eigenen Routen.
119
+ * OAuth portion of the contract — OAuth providers only; imap in password
120
+ * mode omits `oauth`. The Foundation provides the routes
121
+ * (`/inbound-mail/connect`, `/inbound-mail/oauth/callback`) generically;
122
+ * providers MUST NOT register their own routes.
124
123
  */
125
124
  export type InboundOAuthFlow = {
126
- /** Scopes: Empfang UND Send in EINEM Consent — Re-Consent ist teuer. */
125
+ /** Scopes: request receive AND send in a SINGLE consent; re-consent is costly. */
127
126
  readonly scopes: {
128
127
  readonly receive: readonly string[];
129
128
  readonly send?: readonly string[];
@@ -150,17 +149,17 @@ export type InboundOAuthFlow = {
150
149
  };
151
150
 
152
151
  /**
153
- * Inbound-Mail-Provider-Plugin contract. Jedes Provider-Feature
154
- * (inbound-provider-imap, -m365-graph, -gmail-rest) registriert eine
155
- * Implementation via `r.useExtension(INBOUND_MAIL_PROVIDER_EXTENSION,
152
+ * Inbound-mail provider plugin contract. Each provider feature
153
+ * (inbound-provider-imap, -m365-graph, -gmail-rest) registers an
154
+ * implementation via `r.useExtension(INBOUND_MAIL_PROVIDER_EXTENSION,
156
155
  * "<key>", plugin)`.
157
156
  */
158
157
  export type InboundMailProviderPlugin = {
159
- /** Credentials-/Erreichbarkeits-Check beim Connect-Flow — wirft
160
- * typisiert (InboundAuthError etc.), kein Rückgabewert. */
158
+ /** Credential/reachability check during the connect flow — throws a
159
+ * typed error (InboundAuthError, etc.) and returns no value. */
161
160
  readonly verify: (ctx: InboundMailContext, account: MailAccountRecord) => Promise<void>;
162
- /** Pull seit cursor. `cursor === null` ⇒ Erst-Befüllung, begrenzt
163
- * durch backfillWindowDays. */
161
+ /** Fetch since cursor. `cursor === null` means initial population,
162
+ * limited by backfillWindowDays. */
164
163
  readonly fetch: (
165
164
  ctx: InboundMailContext,
166
165
  account: MailAccountRecord,
@@ -183,11 +182,11 @@ export type InboundMailProviderPlugin = {
183
182
  ) => Promise<InboundFetchResult>;
184
183
  /** Nur OAuth-Provider. */
185
184
  readonly oauth?: InboundOAuthFlow;
186
- /** Optional: Live-Push (IMAP IDLE, später Graph/Gmail-Webhooks).
187
- * Liefert stop(). Poll bleibt Reconciliation — watch ist Latenz-
188
- * Optimierung, nie Korrektheits-Anker. `onError` meldet den Tod der
189
- * Live-Verbindung (Drop, Auth-Revoke) an den Supervisor, der mit
190
- * Backoff neu startet — der Provider reconnected NICHT selbst. */
185
+ /** Optional live push (IMAP IDLE, later Graph/Gmail webhooks).
186
+ * Returns stop(). Polling remains reconciliation: watch optimizes
187
+ * latency but is never the correctness anchor. `onError` reports a dead
188
+ * live connection (drop, auth revocation) to the supervisor, which
189
+ * restarts it with backoff; the provider does NOT reconnect itself. */
191
190
  readonly watch?: (
192
191
  ctx: InboundMailContext,
193
192
  account: MailAccountRecord,
@@ -201,8 +200,9 @@ export type InboundMailProviderPlugin = {
201
200
  ) => Promise<() => Promise<void>>;
202
201
  };
203
202
 
204
- // extension-usage `options` ist engine-payload (unknown) — strukturell
205
- // validieren statt blind casten (Muster isMailTransportPlugin).
203
+ // `options` in the extension usage is an engine payload (unknown), so
204
+ // validate its structure instead of casting blindly (patterned after
205
+ // isMailTransportPlugin).
206
206
  export function isInboundMailProviderPlugin(o: unknown): o is InboundMailProviderPlugin {
207
207
  return (
208
208
  typeof o === "object" &&
@@ -222,18 +222,17 @@ declare module "@cosmicdrift/kumiko-framework/engine" {
222
222
  }
223
223
 
224
224
  // =============================================================================
225
- // Typisierte Fehlerklassen — Foundation reagiert einheitlich im Poll
226
- // (Plan §2, Fehler-Tabelle):
227
- // InboundAuthError → status=auth_error, kein Retry
228
- // InboundRateLimitError → Poll-Abbruch, nächster Cron-Tick
229
- // InboundCursorInvalidError → Cursor-Reset + Voll-Resync im Backfill-
230
- // Fenster; Dedup fängt Dubletten
231
- // InboundTransientError → Job-Retry (retries: 3, exponential)
225
+ // Typed errors handled uniformly by the Foundation during polling:
226
+ // InboundAuthError → status=auth_error, no retry
227
+ // InboundRateLimitError → abort poll, wait for the next cron tick
228
+ // InboundCursorInvalidError → reset cursor + full resync in the backfill
229
+ // window; deduplication handles duplicates
230
+ // InboundTransientError → job retry (retries: 3, exponential)
232
231
  // =============================================================================
233
232
  //
234
- // `kind`-Discriminant statt instanceof: Plugin und Foundation können in
235
- // getrennten Bundles leben (dual-package-hazard), instanceof über
236
- // Realm-/Kopie-Grenzen ist unzuverlässig.
233
+ // Use a `kind` discriminant instead of instanceof: plugins and the Foundation
234
+ // may run in separate bundles (dual-package-hazard), and instanceof is
235
+ // unreliable across realm or package-copy boundaries.
237
236
 
238
237
  export class InboundAuthError extends Error {
239
238
  readonly kind = "inbound-auth-error" as const;