@cosmicdrift/kumiko-samples 0.366.0 → 0.368.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 (411) hide show
  1. package/package.json +1 -1
  2. package/packages/bundled-features/package.json +16 -2
  3. package/packages/bundled-features/src/audit/handlers/details.query.ts +1 -1
  4. package/packages/bundled-features/src/audit/handlers/list.query.ts +1 -1
  5. package/packages/bundled-features/src/audit/run-escape-hatch-retention.ts +5 -5
  6. package/packages/bundled-features/src/auth-email-password/bootstrap.ts +1 -1
  7. package/packages/bundled-features/src/auth-email-password/handlers/invite-accept-with-login.write.ts +10 -3
  8. package/packages/bundled-features/src/auth-email-password/handlers/invite-accept.write.ts +10 -3
  9. package/packages/bundled-features/src/auth-email-password/handlers/invite-info.query.ts +1 -1
  10. package/packages/bundled-features/src/auth-email-password/handlers/invite-signup-complete.write.ts +6 -2
  11. package/packages/bundled-features/src/auth-email-password/handlers/signup-confirm.write.ts +1 -1
  12. package/packages/bundled-features/src/auth-email-password/seeding.ts +2 -2
  13. package/packages/bundled-features/src/auth-foundation/feature.ts +43 -34
  14. package/packages/bundled-features/src/auth-foundation/index.ts +1 -0
  15. package/packages/bundled-features/src/auth-mfa/db/queries.ts +5 -2
  16. package/packages/bundled-features/src/auth-mfa/handlers/enable-confirm-preauth.write.ts +1 -1
  17. package/packages/bundled-features/src/auth-mfa/handlers/enable-start-preauth.write.ts +1 -1
  18. package/packages/bundled-features/src/auth-mfa/handlers/reencrypt.job.ts +2 -2
  19. package/packages/bundled-features/src/auth-mfa/handlers/status.query.ts +1 -1
  20. package/packages/bundled-features/src/auth-mfa/handlers/verify.write.ts +1 -1
  21. package/packages/bundled-features/src/auth-mfa/mfa-code-verifier.ts +1 -1
  22. package/packages/bundled-features/src/auth-mfa/mfa-status-checker.ts +1 -1
  23. package/packages/bundled-features/src/auth-mfa-user-data/index.ts +19 -10
  24. package/packages/bundled-features/src/billing-foundation/billing-info-query.ts +1 -1
  25. package/packages/bundled-features/src/billing-foundation/feature.ts +138 -135
  26. package/packages/bundled-features/src/billing-foundation/handlers/create-portal-session.write.ts +1 -1
  27. package/packages/bundled-features/src/billing-foundation/projection.ts +3 -2
  28. package/packages/bundled-features/src/cap-counter/calendar-cap-usage-reservation.ts +52 -1
  29. package/packages/bundled-features/src/cap-counter/cap-reservation.ts +203 -15
  30. package/packages/bundled-features/src/cap-counter/changes.json +13 -0
  31. package/packages/bundled-features/src/cap-counter/feature.ts +84 -73
  32. package/packages/bundled-features/src/cap-counter/handlers/increment-rolling.write.ts +3 -4
  33. package/packages/bundled-features/src/cap-counter/index.ts +9 -1
  34. package/packages/bundled-features/src/cap-counter/tables.ts +10 -3
  35. package/packages/bundled-features/src/cap-overview/handlers/caps-usage.query.ts +1 -2
  36. package/packages/bundled-features/src/cap-overview/handlers/tenant-caps-list.query.ts +6 -2
  37. package/packages/bundled-features/src/cap-overview/handlers/tenant-options.query.ts +1 -1
  38. package/packages/bundled-features/src/channel-email/changes.json +6 -0
  39. package/packages/bundled-features/src/channel-email/email-channel.ts +12 -2
  40. package/packages/bundled-features/src/channel-email/feature.ts +1 -1
  41. package/packages/bundled-features/src/channel-in-app/handlers/inbox.query.ts +1 -1
  42. package/packages/bundled-features/src/channel-in-app/handlers/mark-all-read.write.ts +1 -1
  43. package/packages/bundled-features/src/channel-in-app/handlers/mark-read.write.ts +1 -1
  44. package/packages/bundled-features/src/channel-in-app/handlers/unread-count.query.ts +1 -1
  45. package/packages/bundled-features/src/channel-in-app/tables.ts +1 -1
  46. package/packages/bundled-features/src/compliance-profiles/handlers/for-tenant.query.ts +1 -1
  47. package/packages/bundled-features/src/compliance-profiles/handlers/needs-profile.query.ts +1 -1
  48. package/packages/bundled-features/src/compliance-profiles/handlers/set-profile.write.ts +1 -2
  49. package/packages/bundled-features/src/compliance-profiles/resolve-for-tenant.ts +1 -1
  50. package/packages/bundled-features/src/compliance-profiles/seeding.ts +8 -4
  51. package/packages/bundled-features/src/compliance-profiles-ops/index.ts +26 -17
  52. package/packages/bundled-features/src/config/db/queries/resolver.ts +1 -1
  53. package/packages/bundled-features/src/config/handlers/reencrypt.job.ts +2 -2
  54. package/packages/bundled-features/src/config/resolver.ts +1 -1
  55. package/packages/bundled-features/src/config/write-helpers.ts +1 -1
  56. package/packages/bundled-features/src/crypto-shredding/changes.json +6 -0
  57. package/packages/bundled-features/src/crypto-shredding/handlers/forget-subject.write.ts +9 -7
  58. package/packages/bundled-features/src/custom-fields/db/queries/field-access.ts +1 -1
  59. package/packages/bundled-features/src/custom-fields/db/queries/projection.ts +1 -1
  60. package/packages/bundled-features/src/custom-fields/db/queries/quota.ts +1 -1
  61. package/packages/bundled-features/src/custom-fields/db/queries/retention.ts +6 -2
  62. package/packages/bundled-features/src/custom-fields/db/queries/user-data-rights.ts +1 -1
  63. package/packages/bundled-features/src/custom-fields/feature.ts +11 -14
  64. package/packages/bundled-features/src/custom-fields/handlers/clear-custom-field.write.ts +2 -2
  65. package/packages/bundled-features/src/custom-fields/handlers/delete-system-field.write.ts +2 -2
  66. package/packages/bundled-features/src/custom-fields/handlers/delete-tenant-field.write.ts +2 -2
  67. package/packages/bundled-features/src/custom-fields/handlers/set-custom-field.write.ts +2 -2
  68. package/packages/bundled-features/src/custom-fields/wire-for-entity.ts +4 -4
  69. package/packages/bundled-features/src/data-retention/resolve-for-tenant.ts +1 -1
  70. package/packages/bundled-features/src/data-retention/run-retention-cleanup.ts +16 -10
  71. package/packages/bundled-features/src/delivery/address-opt-out.ts +5 -2
  72. package/packages/bundled-features/src/delivery/attempt-log-retention.ts +1 -1
  73. package/packages/bundled-features/src/delivery/changes.json +12 -0
  74. package/packages/bundled-features/src/delivery/channel-context.ts +2 -1
  75. package/packages/bundled-features/src/delivery/db/queries/address-opt-outs.ts +1 -1
  76. package/packages/bundled-features/src/delivery/db/queries/preferences.ts +1 -1
  77. package/packages/bundled-features/src/delivery/delivery-service.ts +70 -8
  78. package/packages/bundled-features/src/delivery/feature.ts +2 -2
  79. package/packages/bundled-features/src/delivery/handlers/log.query.ts +3 -2
  80. package/packages/bundled-features/src/delivery/handlers/preferences.query.ts +1 -1
  81. package/packages/bundled-features/src/delivery/handlers/unsubscribe-address.write.ts +10 -5
  82. package/packages/bundled-features/src/delivery/index.ts +6 -0
  83. package/packages/bundled-features/src/delivery/testing.ts +2 -0
  84. package/packages/bundled-features/src/delivery/types.ts +4 -0
  85. package/packages/bundled-features/src/delivery/unsubscribe-link.ts +73 -0
  86. package/packages/bundled-features/src/delivery/unsubscribe-page-strings.ts +17 -0
  87. package/packages/bundled-features/src/delivery/unsubscribe.ts +94 -31
  88. package/packages/bundled-features/src/delivery/upsert-preference.ts +5 -2
  89. package/packages/bundled-features/src/derivatives-sharp/feature.ts +21 -12
  90. package/packages/bundled-features/src/derivatives-sharp/index.ts +1 -1
  91. package/packages/bundled-features/src/document-ingest-foundation/feature.ts +112 -103
  92. package/packages/bundled-features/src/document-ingest-foundation/forget-extract-with-file-ref.ts +3 -3
  93. package/packages/bundled-features/src/document-ingest-foundation/index.ts +4 -1
  94. package/packages/bundled-features/src/feature-toggles/global-feature-state-table.ts +1 -1
  95. package/packages/bundled-features/src/feature-toggles/handlers/set.write.ts +3 -5
  96. package/packages/bundled-features/src/feature-toggles/toggle-runtime.ts +1 -1
  97. package/packages/bundled-features/src/file-derivatives/feature.ts +134 -129
  98. package/packages/bundled-features/src/file-derivatives/handlers/public-variant-by-file-ref.query.ts +1 -1
  99. package/packages/bundled-features/src/file-derivatives/handlers/public-variant.query.ts +1 -1
  100. package/packages/bundled-features/src/file-foundation/feature.ts +38 -29
  101. package/packages/bundled-features/src/file-foundation/index.ts +1 -0
  102. package/packages/bundled-features/src/file-foundation/read-file-ref-content.ts +1 -1
  103. package/packages/bundled-features/src/file-provider-inmemory/feature.ts +32 -21
  104. package/packages/bundled-features/src/file-provider-inmemory/index.ts +6 -1
  105. package/packages/bundled-features/src/file-provider-s3/changes.json +10 -1
  106. package/packages/bundled-features/src/file-provider-s3/env-feature.ts +62 -0
  107. package/packages/bundled-features/src/file-provider-s3/feature.ts +107 -73
  108. package/packages/bundled-features/src/file-provider-s3/index.ts +6 -1
  109. package/packages/bundled-features/src/file-provider-s3/lib/index.ts +3 -0
  110. package/packages/bundled-features/src/{files-provider-s3 → file-provider-s3/lib}/s3-provider.ts +19 -19
  111. package/packages/bundled-features/src/file-provider-s3-env/index.ts +7 -2
  112. package/packages/bundled-features/src/files-provider-s3/index.ts +11 -3
  113. package/packages/bundled-features/src/files-tenant-data/handlers/sweep-orphaned-derivatives.job.ts +1 -1
  114. package/packages/bundled-features/src/files-tenant-data/hooks.ts +1 -2
  115. package/packages/bundled-features/src/folders/feature.ts +8 -3
  116. package/packages/bundled-features/src/folders-user-data/index.ts +27 -18
  117. package/packages/bundled-features/src/form-draft/db/queries/cleanup.ts +1 -1
  118. package/packages/bundled-features/src/form-draft/db/queries/draft-count.ts +1 -1
  119. package/packages/bundled-features/src/form-draft/db/queries/owned-file-refs.ts +3 -2
  120. package/packages/bundled-features/src/form-draft/feature.ts +6 -1
  121. package/packages/bundled-features/src/form-draft/handlers/cleanup.job.ts +2 -2
  122. package/packages/bundled-features/src/form-draft/index.ts +1 -1
  123. package/packages/bundled-features/src/form-draft/lookup.ts +1 -1
  124. package/packages/bundled-features/src/form-draft-user-data/index.ts +19 -10
  125. package/packages/bundled-features/src/inbound-mail-foundation/feature.ts +165 -154
  126. package/packages/bundled-features/src/inbound-mail-foundation/handlers/ingest-message.write.ts +1 -2
  127. package/packages/bundled-features/src/inbound-mail-foundation/index.ts +1 -1
  128. package/packages/bundled-features/src/inbound-mail-foundation/oauth-access-token.ts +5 -2
  129. package/packages/bundled-features/src/inbound-mail-foundation/projection.ts +3 -2
  130. package/packages/bundled-features/src/inbound-mail-foundation/watch-supervisor.ts +1 -1
  131. package/packages/bundled-features/src/inbound-provider-imap/feature.ts +22 -13
  132. package/packages/bundled-features/src/inbound-provider-imap/index.ts +6 -1
  133. package/packages/bundled-features/src/inbound-provider-inmemory/feature.ts +20 -12
  134. package/packages/bundled-features/src/inbound-provider-inmemory/index.ts +1 -0
  135. package/packages/bundled-features/src/jobs/db/queries/retention.ts +1 -1
  136. package/packages/bundled-features/src/jobs/db/queries/stale-run-sweep.ts +1 -1
  137. package/packages/bundled-features/src/jobs/handlers/detail.query.ts +1 -1
  138. package/packages/bundled-features/src/jobs/handlers/list.query.ts +7 -2
  139. package/packages/bundled-features/src/jobs/handlers/retry.write.ts +1 -1
  140. package/packages/bundled-features/src/jobs/handlers/tenant-failures.query.ts +1 -1
  141. package/packages/bundled-features/src/jobs/handlers/tenant-runs.query.ts +1 -1
  142. package/packages/bundled-features/src/jobs/job-run-logger.ts +11 -10
  143. package/packages/bundled-features/src/jobs/tenant-job-failure-table.ts +1 -1
  144. package/packages/bundled-features/src/jobs/tenant-job-run-table.ts +1 -1
  145. package/packages/bundled-features/src/ledger/feature.ts +6 -3
  146. package/packages/bundled-features/src/mail-foundation/feature.ts +107 -55
  147. package/packages/bundled-features/src/mail-foundation/index.ts +4 -0
  148. package/packages/bundled-features/src/mail-transport-inmemory/feature.ts +25 -17
  149. package/packages/bundled-features/src/mail-transport-inmemory/index.ts +6 -1
  150. package/packages/bundled-features/src/mail-transport-smtp/feature.ts +91 -79
  151. package/packages/bundled-features/src/mail-transport-smtp/index.ts +1 -0
  152. package/packages/bundled-features/src/managed-pages/handlers/by-slug.query.ts +1 -1
  153. package/packages/bundled-features/src/managed-pages/handlers/by-tenant-published.query.ts +1 -2
  154. package/packages/bundled-features/src/managed-pages/handlers/set.write.ts +1 -2
  155. package/packages/bundled-features/src/managed-pages/seeding.ts +8 -4
  156. package/packages/bundled-features/src/metrics/compute.ts +1 -1
  157. package/packages/bundled-features/src/metrics/filters.ts +1 -1
  158. package/packages/bundled-features/src/metrics/validate.ts +1 -1
  159. package/packages/bundled-features/src/notes-history/feature.ts +6 -3
  160. package/packages/bundled-features/src/notes-history/handlers/add-note.write.ts +1 -1
  161. package/packages/bundled-features/src/notes-history-user-data/hooks.ts +1 -1
  162. package/packages/bundled-features/src/notes-history-user-data/index.ts +27 -18
  163. package/packages/bundled-features/src/personal-access-tokens/changes.json +6 -0
  164. package/packages/bundled-features/src/personal-access-tokens/feature.ts +17 -2
  165. package/packages/bundled-features/src/personal-access-tokens/handlers/create.write.ts +1 -1
  166. package/packages/bundled-features/src/personal-access-tokens/handlers/list.query.ts +2 -2
  167. package/packages/bundled-features/src/personal-access-tokens/handlers/revoke.write.ts +1 -1
  168. package/packages/bundled-features/src/personal-access-tokens/resolver.ts +1 -1
  169. package/packages/bundled-features/src/personal-access-tokens/revoke-for-user.ts +2 -2
  170. package/packages/bundled-features/src/personal-access-tokens/roles.ts +8 -6
  171. package/packages/bundled-features/src/personal-access-tokens/screens.ts +2 -0
  172. package/packages/bundled-features/src/readiness/feature.ts +25 -16
  173. package/packages/bundled-features/src/readiness/index.ts +1 -1
  174. package/packages/bundled-features/src/secrets/db/queries/read.ts +1 -1
  175. package/packages/bundled-features/src/secrets/feature.ts +8 -3
  176. package/packages/bundled-features/src/secrets/handlers/rotate.job.ts +2 -2
  177. package/packages/bundled-features/src/secrets/secrets-context.ts +4 -3
  178. package/packages/bundled-features/src/sessions/db/queries/cleanup.ts +1 -1
  179. package/packages/bundled-features/src/sessions/handlers/detail.query.ts +1 -1
  180. package/packages/bundled-features/src/sessions/handlers/list.query.ts +2 -2
  181. package/packages/bundled-features/src/sessions/handlers/mine.query.ts +1 -1
  182. package/packages/bundled-features/src/sessions/handlers/revoke-all-for-user.write.ts +1 -1
  183. package/packages/bundled-features/src/sessions/handlers/revoke-all-others.write.ts +1 -1
  184. package/packages/bundled-features/src/sessions/handlers/revoke.write.ts +1 -1
  185. package/packages/bundled-features/src/sessions/session-callbacks.ts +14 -7
  186. package/packages/bundled-features/src/sessions/testing.ts +1 -1
  187. package/packages/bundled-features/src/tags/feature.ts +6 -3
  188. package/packages/bundled-features/src/template-resolver/api.ts +1 -1
  189. package/packages/bundled-features/src/template-resolver/changes.json +25 -0
  190. package/packages/bundled-features/src/template-resolver/compile-document-body.ts +61 -9
  191. package/packages/bundled-features/src/template-resolver/document-sanitizer.ts +19 -0
  192. package/packages/bundled-features/src/template-resolver/document-schema.ts +33 -0
  193. package/packages/bundled-features/src/template-resolver/handlers/bundle-import.ts +10 -2
  194. package/packages/bundled-features/src/template-resolver/handlers/by-slug.query.ts +1 -1
  195. package/packages/bundled-features/src/template-resolver/handlers/by-tenant.query.ts +1 -2
  196. package/packages/bundled-features/src/template-resolver/handlers/collection-item.query.ts +1 -1
  197. package/packages/bundled-features/src/template-resolver/handlers/collection-list.query.ts +1 -2
  198. package/packages/bundled-features/src/template-resolver/handlers/collection-set.write.ts +1 -1
  199. package/packages/bundled-features/src/template-resolver/handlers/copy-locale.write.ts +9 -3
  200. package/packages/bundled-features/src/template-resolver/handlers/diff-to-system.query.ts +1 -1
  201. package/packages/bundled-features/src/template-resolver/handlers/export-bundle.query.ts +1 -1
  202. package/packages/bundled-features/src/template-resolver/handlers/find-by-id.query.ts +9 -2
  203. package/packages/bundled-features/src/template-resolver/handlers/layout-source.query.ts +1 -1
  204. package/packages/bundled-features/src/template-resolver/handlers/list.query.ts +7 -2
  205. package/packages/bundled-features/src/template-resolver/handlers/overview.query.ts +8 -3
  206. package/packages/bundled-features/src/template-resolver/handlers/reset-to-system.write.ts +1 -1
  207. package/packages/bundled-features/src/template-resolver/handlers/resource-remove.write.ts +1 -1
  208. package/packages/bundled-features/src/template-resolver/handlers/set.write.ts +1 -1
  209. package/packages/bundled-features/src/template-resolver/handlers/template-write.ts +22 -2
  210. package/packages/bundled-features/src/template-resolver/handlers/tenant-overrides.query.ts +1 -1
  211. package/packages/bundled-features/src/template-resolver/handlers/toggle-status.write.ts +1 -1
  212. package/packages/bundled-features/src/template-resolver/handlers/usage.query.ts +1 -1
  213. package/packages/bundled-features/src/template-resolver/handlers/validate.query.ts +1 -1
  214. package/packages/bundled-features/src/template-resolver/index.ts +4 -0
  215. package/packages/bundled-features/src/template-resolver/qualified-names.ts +1 -0
  216. package/packages/bundled-features/src/template-resolver/seeding.ts +57 -10
  217. package/packages/bundled-features/src/template-resolver/store-template-resource.ts +1 -1
  218. package/packages/bundled-features/src/template-resolver/template-preview.ts +3 -1
  219. package/packages/bundled-features/src/template-resolver/template-resources.ts +1 -1
  220. package/packages/bundled-features/src/template-resolver/template-system-only.ts +21 -0
  221. package/packages/bundled-features/src/template-resolver/template-validation.ts +48 -24
  222. package/packages/bundled-features/src/template-resolver/testing.ts +1 -1
  223. package/packages/bundled-features/src/template-resolver/web/i18n.ts +2 -0
  224. package/packages/bundled-features/src/template-resolver-user-data/index.ts +23 -14
  225. package/packages/bundled-features/src/tenant/handlers/active-tenant-ids.query.ts +1 -1
  226. package/packages/bundled-features/src/tenant/handlers/add-member.write.ts +1 -2
  227. package/packages/bundled-features/src/tenant/handlers/cancel-invitation.write.ts +1 -1
  228. package/packages/bundled-features/src/tenant/handlers/invitations.query.ts +1 -1
  229. package/packages/bundled-features/src/tenant/handlers/me.query.ts +1 -1
  230. package/packages/bundled-features/src/tenant/handlers/member-directory.query.ts +1 -1
  231. package/packages/bundled-features/src/tenant/handlers/members.query.ts +1 -1
  232. package/packages/bundled-features/src/tenant/handlers/memberships.query.ts +1 -1
  233. package/packages/bundled-features/src/tenant/handlers/remove-member.write.ts +2 -1
  234. package/packages/bundled-features/src/tenant/handlers/resolve-user-ids.query.ts +1 -1
  235. package/packages/bundled-features/src/tenant/handlers/team-list.query.ts +1 -1
  236. package/packages/bundled-features/src/tenant/handlers/tenant-directory.query.ts +1 -1
  237. package/packages/bundled-features/src/tenant/handlers/update-member-roles.write.ts +1 -2
  238. package/packages/bundled-features/src/tenant/invited-membership.ts +2 -2
  239. package/packages/bundled-features/src/tenant/last-tenant-admin.ts +1 -2
  240. package/packages/bundled-features/src/tenant/seeding.ts +12 -12
  241. package/packages/bundled-features/src/tenant-lifecycle/handlers/cancel-destruction.write.ts +1 -2
  242. package/packages/bundled-features/src/tenant-lifecycle/handlers/request-destruction.write.ts +1 -2
  243. package/packages/bundled-features/src/tenant-lifecycle/lib/revoke-tenant-sessions.ts +1 -1
  244. package/packages/bundled-features/src/tenant-lifecycle/lifecycle-gate.ts +1 -1
  245. package/packages/bundled-features/src/tenant-lifecycle/run-tenant-destroy.ts +3 -3
  246. package/packages/bundled-features/src/tenant-lifecycle/stages.ts +10 -5
  247. package/packages/bundled-features/src/tenant-lifecycle/testing.ts +3 -3
  248. package/packages/bundled-features/src/tenant-settings/feature.ts +34 -29
  249. package/packages/bundled-features/src/tier-engine/feature.ts +426 -428
  250. package/packages/bundled-features/src/tier-engine/handlers/get-tenant-tier.query.ts +2 -3
  251. package/packages/bundled-features/src/tier-engine/handlers/set-tenant-tier.write.ts +5 -2
  252. package/packages/bundled-features/src/user/changes.json +6 -0
  253. package/packages/bundled-features/src/user/db/queries/stream-tenant-backfill.ts +1 -1
  254. package/packages/bundled-features/src/user/handlers/create.write.ts +1 -2
  255. package/packages/bundled-features/src/user/handlers/find-for-auth.query.ts +1 -1
  256. package/packages/bundled-features/src/user/handlers/list.query.ts +1 -1
  257. package/packages/bundled-features/src/user/handlers/update-roles.ts +2 -1
  258. package/packages/bundled-features/src/user/index.ts +5 -1
  259. package/packages/bundled-features/src/user/invited-global-roles.ts +2 -2
  260. package/packages/bundled-features/src/user/principal-status.ts +13 -3
  261. package/packages/bundled-features/src/user/resolve-display-names.ts +1 -1
  262. package/packages/bundled-features/src/user/seeding.ts +5 -5
  263. package/packages/bundled-features/src/user-data-rights/audit-download.ts +2 -2
  264. package/packages/bundled-features/src/user-data-rights/changes.json +6 -0
  265. package/packages/bundled-features/src/user-data-rights/db/queries/export-jobs.ts +1 -1
  266. package/packages/bundled-features/src/user-data-rights/db/queries/forget-cleanup.ts +1 -1
  267. package/packages/bundled-features/src/user-data-rights/handlers/download-by-job.query.ts +1 -1
  268. package/packages/bundled-features/src/user-data-rights/handlers/download-by-token.query.ts +1 -1
  269. package/packages/bundled-features/src/user-data-rights/handlers/export-status.query.ts +1 -1
  270. package/packages/bundled-features/src/user-data-rights/handlers/list-download-attempts.query.ts +1 -1
  271. package/packages/bundled-features/src/user-data-rights/handlers/my-audit-log.query.ts +1 -1
  272. package/packages/bundled-features/src/user-data-rights/handlers/request-export.write.ts +1 -2
  273. package/packages/bundled-features/src/user-data-rights/handlers/run-forget-cleanup.write.ts +3 -3
  274. package/packages/bundled-features/src/user-data-rights/lib/deny-if-target-outside-admin-tenant.ts +1 -1
  275. package/packages/bundled-features/src/user-data-rights/lib/update-user-lifecycle.ts +7 -2
  276. package/packages/bundled-features/src/user-data-rights/run-export-jobs.ts +7 -3
  277. package/packages/bundled-features/src/user-data-rights/run-forget-cleanup.ts +11 -5
  278. package/packages/bundled-features/src/user-data-rights/run-user-export.ts +10 -5
  279. package/packages/bundled-features/src/waitlist/handlers/invite.write.ts +1 -2
  280. package/packages/bundled-features/src/waitlist/handlers/reject.write.ts +1 -1
  281. package/packages/bundled-features/src/waitlist/lib.ts +5 -2
  282. package/packages/bundled-features/src/workflow-runner/event-subscriber.ts +1 -1
  283. package/packages/bundled-features/src/workflow-runner/feature.ts +58 -47
  284. package/packages/bundled-features/src/workflow-runner/handlers/resume-run.write.ts +1 -1
  285. package/packages/bundled-features/src/workflow-runner/index.ts +1 -1
  286. package/packages/bundled-features/src/workflow-runner/pending-projection.ts +1 -1
  287. package/samples/apps/admin-console/src/run-config.ts +2 -2
  288. package/samples/apps/cap-billing-demo/package.json +3 -0
  289. package/samples/apps/cap-billing-demo/src/feature.ts +2 -2
  290. package/samples/apps/cap-billing-demo/src/run-config.ts +8 -8
  291. package/samples/apps/marketing-demo/src/app/seed.ts +1 -1
  292. package/samples/apps/marketing-demo/src/db/queries/seed-counts.ts +1 -1
  293. package/samples/apps/showcase/package.json +3 -0
  294. package/samples/apps/showcase/src/app/seed-items.ts +1 -1
  295. package/samples/apps/styleguide/src/app/seed.ts +2 -2
  296. package/samples/apps/styleguide/src/features/ai-settings/seed.ts +2 -2
  297. package/samples/apps/ui-walkthrough/scripts/emit-e2e-data.ts +1 -1
  298. package/samples/apps/ui-walkthrough/src/app/auth-constants.ts +1 -1
  299. package/samples/apps/ui-walkthrough/src/app/seed-rental.ts +2 -2
  300. package/samples/apps/ui-walkthrough/src/app/seed-templates.ts +2 -0
  301. package/samples/apps/ui-walkthrough/src/app/seed-vehicles.ts +1 -1
  302. package/samples/apps/ui-walkthrough/src/app/seed.ts +1 -1
  303. package/samples/apps/ui-walkthrough/src/app/template-seed-data.ts +12 -0
  304. package/samples/apps/ui-walkthrough/src/db/queries/row-counts.ts +1 -1
  305. package/samples/apps/ui-walkthrough/src/db/queries/task-counts.ts +1 -1
  306. package/samples/apps/ui-walkthrough/src/features/billing/feature.ts +7 -0
  307. package/samples/apps/ui-walkthrough/src/features/billing/i18n.ts +2 -0
  308. package/samples/apps/use-all-bundled/feature-manifest.json +4 -4
  309. package/samples/apps/use-all-bundled/package.json +4 -0
  310. package/samples/apps/use-all-bundled/scripts/check-coverage.ts +2 -2
  311. package/samples/apps/use-all-bundled/src/app/auth-constants.ts +1 -1
  312. package/samples/apps/use-all-bundled/src/app/cap-overview-caps.ts +2 -2
  313. package/samples/apps/use-all-bundled/src/app/dev-app-options.ts +1 -1
  314. package/samples/apps/use-all-bundled/src/app/seed-documents.ts +1 -1
  315. package/samples/apps/use-all-bundled/src/app/seed.ts +11 -5
  316. package/samples/apps/use-all-bundled/src/run-config.ts +55 -56
  317. package/samples/apps/user-data-rights-demo/README.md +2 -2
  318. package/samples/apps/user-data-rights-demo/package.json +3 -0
  319. package/samples/apps/user-data-rights-demo/src/run-config.ts +7 -7
  320. package/samples/apps/workspaces/package.json +3 -0
  321. package/samples/recipes/access-control/package.json +3 -0
  322. package/samples/recipes/anonymous-access/package.json +3 -0
  323. package/samples/recipes/anonymous-access-multitenant/package.json +3 -0
  324. package/samples/recipes/apex-landing/package.json +1 -0
  325. package/samples/recipes/apex-surface-auth/package.json +3 -0
  326. package/samples/recipes/apex-surface-auth/src/feature.ts +2 -2
  327. package/samples/recipes/api-worker-split/package.json +3 -0
  328. package/samples/recipes/api-worker-split/src/feature.ts +1 -2
  329. package/samples/recipes/auth-claims/package.json +3 -0
  330. package/samples/recipes/auth-foundation-providers/src/feature.ts +1 -1
  331. package/samples/recipes/auth-mfa/package.json +3 -0
  332. package/samples/recipes/basic-entity/package.json +3 -0
  333. package/samples/recipes/chat-channels/package.json +3 -0
  334. package/samples/recipes/compliance-profiles-demo/package.json +3 -0
  335. package/samples/recipes/cross-feature-events/package.json +3 -1
  336. package/samples/recipes/cross-feature-events/src/feature.ts +1 -1
  337. package/samples/recipes/crypto-shredding-hr/package.json +3 -0
  338. package/samples/recipes/currencies-global/package.json +3 -0
  339. package/samples/recipes/currencies-per-tenant/package.json +3 -0
  340. package/samples/recipes/custom-fields-basic/package.json +3 -0
  341. package/samples/recipes/custom-handlers/package.json +3 -0
  342. package/samples/recipes/dashboard-stats/package.json +3 -0
  343. package/samples/recipes/delivery-notifications/package.json +3 -0
  344. package/samples/recipes/e2e-generator/package.json +3 -0
  345. package/samples/recipes/embedded/package.json +3 -0
  346. package/samples/recipes/embedded-entity-form/package.json +1 -0
  347. package/samples/recipes/encrypted-tenant-config/README.md +1 -1
  348. package/samples/recipes/encrypted-tenant-config/package.json +3 -0
  349. package/samples/recipes/error-contract/package.json +3 -0
  350. package/samples/recipes/event-sourcing/package.json +3 -1
  351. package/samples/recipes/event-sourcing/src/feature.ts +16 -20
  352. package/samples/recipes/event-sourcing/tsconfig.json +2 -6
  353. package/samples/recipes/feature-toggles/package.json +3 -0
  354. package/samples/recipes/field-access/package.json +3 -0
  355. package/samples/recipes/files-post-processing/package.json +1 -0
  356. package/samples/recipes/golden-path/README.md +30 -0
  357. package/samples/recipes/golden-path/package.json +11 -0
  358. package/samples/recipes/golden-path/src/feature.ts +70 -0
  359. package/samples/recipes/idempotency/package.json +3 -0
  360. package/samples/recipes/inbound-mail-triage/package.json +3 -0
  361. package/samples/recipes/lane-routing/package.json +3 -0
  362. package/samples/recipes/ledger-banking/package.json +3 -0
  363. package/samples/recipes/ledger-invoicing/package.json +3 -0
  364. package/samples/recipes/legal-pages/package.json +3 -0
  365. package/samples/recipes/lifecycle-hooks/package.json +3 -0
  366. package/samples/recipes/managed-config/package.json +3 -0
  367. package/samples/recipes/managed-pages/package.json +3 -0
  368. package/samples/recipes/notes-history-basic/package.json +3 -0
  369. package/samples/recipes/ownership/package.json +3 -0
  370. package/samples/recipes/pdf-audit-export/package.json +1 -0
  371. package/samples/recipes/pipeline-basics/package.json +3 -0
  372. package/samples/recipes/public-share-token/package.json +3 -0
  373. package/samples/recipes/public-share-token/src/feature.ts +1 -1
  374. package/samples/recipes/rate-limiting/package.json +3 -0
  375. package/samples/recipes/realtime-sse/package.json +3 -0
  376. package/samples/recipes/record-detail-layout/package.json +1 -0
  377. package/samples/recipes/reference-data/package.json +3 -0
  378. package/samples/recipes/relations/package.json +3 -0
  379. package/samples/recipes/screens-nav/package.json +3 -0
  380. package/samples/recipes/search/package.json +3 -0
  381. package/samples/recipes/secrets-demo/package.json +3 -0
  382. package/samples/recipes/security-baseline/src/feature.ts +2 -2
  383. package/samples/recipes/session-revocation/README.md +1 -1
  384. package/samples/recipes/session-revocation/package.json +3 -0
  385. package/samples/recipes/session-revocation/src/feature.ts +1 -1
  386. package/samples/recipes/state-machine/package.json +3 -1
  387. package/samples/recipes/state-machine/src/entities/invoice.ts +2 -2
  388. package/samples/recipes/state-machine/src/events.ts +19 -0
  389. package/samples/recipes/state-machine/src/feature.ts +25 -30
  390. package/samples/recipes/state-machine/src/handlers/_helpers.ts +13 -14
  391. package/samples/recipes/state-machine/src/handlers/create.ts +1 -1
  392. package/samples/recipes/state-machine/src/handlers/transitions.ts +129 -122
  393. package/samples/recipes/state-machine/src/reducer.ts +1 -1
  394. package/samples/recipes/state-machine/tsconfig.json +2 -6
  395. package/samples/recipes/tags-basic/package.json +3 -0
  396. package/samples/recipes/tenant-isolation/package.json +3 -0
  397. package/samples/recipes/tenant-settings/package.json +3 -0
  398. package/samples/recipes/tier-admin/package.json +3 -0
  399. package/samples/recipes/timezones/package.json +3 -0
  400. package/samples/recipes/tsconfig.base.json +1 -1
  401. package/samples/recipes/user-data-rights/package.json +3 -0
  402. package/samples/recipes/user-data-rights/src/feature.ts +6 -2
  403. package/samples/recipes/user-profile/package.json +3 -0
  404. package/samples/recipes/user-profile/src/feature.ts +2 -2
  405. package/samples/recipes/webhook-step/package.json +3 -0
  406. package/samples/recipes/wizard-form/package.json +1 -0
  407. package/samples/recipes/workflow-engine/package.json +3 -0
  408. package/samples/recipes/workflow-engine/src/db/queries/suspended-runs.ts +5 -2
  409. package/samples/recipes/writeform-section/package.json +1 -0
  410. package/packages/bundled-features/src/file-provider-s3-env/feature.ts +0 -58
  411. /package/packages/bundled-features/src/{files-provider-s3 → file-provider-s3/lib}/env-helper.ts +0 -0
@@ -97,169 +97,180 @@ import {
97
97
  mailThreadTenantDestroyHook,
98
98
  } from "./tenant-destroy-hook.js";
99
99
 
100
- export const inboundMailFoundationFeature = defineFeature(INBOUND_MAIL_FOUNDATION_FEATURE, (r) => {
101
- r.describe(
102
- "Plugin host for inbound e-mail (inbox federation) — provider plugins (inbound-provider-imap, later M365 Graph / Gmail REST) register at the `inboundMailProvider` extension point with verify/fetch and optional oauth/watch (live push). The foundation owns three event-sourced streams (mail-account lifecycle, inbound-message with exactly-once ingest via deterministic aggregate ids, mail-thread rollup) and their projections `read_mail_accounts`/`read_inbound_messages`/`read_mail_threads`; PII fields are envelope-encrypted per tenant subject key before every append (crypto-shredding on tenant destroy). Wire `createInboundMailConnectRoutes` (OAuth connect + anonymous callback outside /api) and `createInboundMailSupervisor` (IDLE watch with backoff + reconciliation poll) in bin/server.ts. Consume `inbound-mail-foundation:event:inbound-message-received` from app features to attach business processes.",
103
- );
104
- r.uiHints({
105
- displayLabel: "Inbound Mail · Foundation",
106
- category: "notifications",
107
- recommended: false,
108
- });
109
- // EXT_TENANT_DATA-Hook braucht den tenant-lifecycle-Host.
110
- r.requires({ features: ["tenant-lifecycle"] });
100
+ export function createInboundMailFoundationFeature() {
101
+ return defineFeature(
102
+ INBOUND_MAIL_FOUNDATION_FEATURE,
103
+ (r) => {
104
+ r.describe(
105
+ "Plugin host for inbound e-mail (inbox federation) — provider plugins (inbound-provider-imap, later M365 Graph / Gmail REST) register at the `inboundMailProvider` extension point with verify/fetch and optional oauth/watch (live push). The foundation owns three event-sourced streams (mail-account lifecycle, inbound-message with exactly-once ingest via deterministic aggregate ids, mail-thread rollup) and their projections `read_mail_accounts`/`read_inbound_messages`/`read_mail_threads`; PII fields are envelope-encrypted per tenant subject key before every append (crypto-shredding on tenant destroy). Wire `createInboundMailConnectRoutes` (OAuth connect + anonymous callback outside /api) and `createInboundMailSupervisor` (IDLE watch with backoff + reconciliation poll) in bin/server.ts. Consume `inbound-mail-foundation:event:inbound-message-received` from app features to attach business processes.",
106
+ );
107
+ r.uiHints({
108
+ displayLabel: "Inbound Mail · Foundation",
109
+ category: "notifications",
110
+ recommended: false,
111
+ });
112
+ // EXT_TENANT_DATA-Hook braucht den tenant-lifecycle-Host.
113
+ r.requires({ features: ["tenant-lifecycle"] });
111
114
 
112
- // 5 fine-grained domain-events (Payload-Schemas: events.ts).
113
- // piiFields: "none" — address/subject/snippet are already ciphertext under the tenant subject key before append (see events.ts).
114
- // "displayName" stays plaintext (often the mailbox owner's real name for
115
- // personal accounts); encrypting it would break the entity-projection read
116
- // path that carries it as `personal: false`.
117
- r.defineEvent(MAIL_ACCOUNT_CONNECTED_EVENT_SHORT, mailAccountEventPayloadSchema, {
118
- piiFields: "none",
119
- });
120
- r.defineEvent(MAIL_ACCOUNT_UPDATED_EVENT_SHORT, mailAccountEventPayloadSchema, {
121
- piiFields: "none",
122
- });
123
- r.defineEvent(MAIL_ACCOUNT_DISCONNECTED_EVENT_SHORT, mailAccountEventPayloadSchema, {
124
- piiFields: "none",
125
- });
126
- r.defineEvent(INBOUND_MESSAGE_RECEIVED_EVENT_SHORT, inboundMessageEventPayloadSchema, {
127
- piiFields: "none",
128
- });
129
- r.defineEvent(MAIL_THREAD_UPDATED_EVENT_SHORT, mailThreadEventPayloadSchema, {
130
- piiFields: "none",
131
- });
115
+ // 5 fine-grained domain-events (Payload-Schemas: events.ts).
116
+ // piiFields: "none" — address/subject/snippet are already ciphertext under the tenant subject key before append (see events.ts).
117
+ // "displayName" stays plaintext (often the mailbox owner's real name for
118
+ // personal accounts); encrypting it would break the entity-projection read
119
+ // path that carries it as `personal: false`.
120
+ r.defineEvent(MAIL_ACCOUNT_CONNECTED_EVENT_SHORT, mailAccountEventPayloadSchema, {
121
+ piiFields: "none",
122
+ });
123
+ r.defineEvent(MAIL_ACCOUNT_UPDATED_EVENT_SHORT, mailAccountEventPayloadSchema, {
124
+ piiFields: "none",
125
+ });
126
+ r.defineEvent(MAIL_ACCOUNT_DISCONNECTED_EVENT_SHORT, mailAccountEventPayloadSchema, {
127
+ piiFields: "none",
128
+ });
129
+ r.defineEvent(INBOUND_MESSAGE_RECEIVED_EVENT_SHORT, inboundMessageEventPayloadSchema, {
130
+ piiFields: "none",
131
+ });
132
+ r.defineEvent(MAIL_THREAD_UPDATED_EVENT_SHORT, mailThreadEventPayloadSchema, {
133
+ piiFields: "none",
134
+ });
132
135
 
133
- // Inline projections — apply in derselben TX wie der Append.
134
- r.projection({
135
- name: "mail-account",
136
- source: MAIL_ACCOUNT_AGGREGATE_TYPE,
137
- table: mailAccountsProjectionTable,
138
- entity: mailAccountEntity,
139
- apply: {
140
- [MAIL_ACCOUNT_CONNECTED_EVENT_QN]: applyMailAccountConnected,
141
- [MAIL_ACCOUNT_UPDATED_EVENT_QN]: applyMailAccountUpdated,
142
- [MAIL_ACCOUNT_DISCONNECTED_EVENT_QN]: applyMailAccountDisconnected,
143
- },
144
- });
145
- r.projection({
146
- name: "inbound-message",
147
- source: INBOUND_MESSAGE_AGGREGATE_TYPE,
148
- table: inboundMessagesProjectionTable,
149
- entity: inboundMessageEntity,
150
- apply: {
151
- [INBOUND_MESSAGE_RECEIVED_EVENT_QN]: applyInboundMessageReceived,
152
- },
153
- });
154
- r.projection({
155
- name: "mail-thread",
156
- source: MAIL_THREAD_AGGREGATE_TYPE,
157
- table: mailThreadsProjectionTable,
158
- entity: mailThreadEntity,
159
- apply: {
160
- [MAIL_THREAD_UPDATED_EVENT_QN]: applyMailThreadUpdated,
161
- },
162
- });
136
+ // Inline projections — apply in derselben TX wie der Append.
137
+ r.projection({
138
+ name: "mail-account",
139
+ source: MAIL_ACCOUNT_AGGREGATE_TYPE,
140
+ table: mailAccountsProjectionTable,
141
+ entity: mailAccountEntity,
142
+ apply: {
143
+ [MAIL_ACCOUNT_CONNECTED_EVENT_QN]: applyMailAccountConnected,
144
+ [MAIL_ACCOUNT_UPDATED_EVENT_QN]: applyMailAccountUpdated,
145
+ [MAIL_ACCOUNT_DISCONNECTED_EVENT_QN]: applyMailAccountDisconnected,
146
+ },
147
+ });
148
+ r.projection({
149
+ name: "inbound-message",
150
+ source: INBOUND_MESSAGE_AGGREGATE_TYPE,
151
+ table: inboundMessagesProjectionTable,
152
+ entity: inboundMessageEntity,
153
+ apply: {
154
+ [INBOUND_MESSAGE_RECEIVED_EVENT_QN]: applyInboundMessageReceived,
155
+ },
156
+ });
157
+ r.projection({
158
+ name: "mail-thread",
159
+ source: MAIL_THREAD_AGGREGATE_TYPE,
160
+ table: mailThreadsProjectionTable,
161
+ entity: mailThreadEntity,
162
+ apply: {
163
+ [MAIL_THREAD_UPDATED_EVENT_QN]: applyMailThreadUpdated,
164
+ },
165
+ });
163
166
 
164
- // Plugin extension-point — Provider registrieren sich via
165
- // r.useExtension("inboundMailProvider", "<key>", plugin).
166
- r.extendsRegistrar(INBOUND_MAIL_PROVIDER_EXTENSION, {
167
- onRegister: () => {
168
- // No side-effects at register-time — Lookup läuft zur Laufzeit
169
- // über resolveInboundProviderForKey/-Account.
170
- },
171
- });
167
+ // Plugin extension point — providers register via
168
+ // r.useExtension("inboundMailProvider", "<key>", plugin).
169
+ r.extendsRegistrar(INBOUND_MAIL_PROVIDER_EXTENSION, {
170
+ onRegister: () => {
171
+ // No side-effects at register-time — lookup happens at runtime
172
+ // via resolveInboundProviderForKey/-Account.
173
+ },
174
+ });
175
+
176
+ // Sync machinery: high-frequency tick state, deliberately NOT
177
+ // event-sourced — r.storeTable keeps the migration DDL but excludes the
178
+ // tables from the projection rebuild (#494/#498 class).
179
+ r.storeTable(syncCursorTable, {
180
+ reason: "read_side.mail_sync_cursors_direct_write",
181
+ });
182
+ r.storeTable(seenMessageTable, {
183
+ reason: "read_side.mail_seen_messages_direct_write",
184
+ });
172
185
 
173
- // Sync-Maschinerie: hochfrequenter Tick-State, bewusst NICHT
174
- // event-sourced — r.storeTable hält die Migration-DDL, nimmt die
175
- // Tabellen aber aus dem Projection-Rebuild (#494/#498-Klasse).
176
- r.storeTable(syncCursorTable, {
177
- reason: "read_side.mail_sync_cursors_direct_write",
178
- });
179
- r.storeTable(seenMessageTable, {
180
- reason: "read_side.mail_seen_messages_direct_write",
181
- });
186
+ // Write-Handler:
187
+ // - ingest-message: programmatic (Supervisor/Poll, SystemAdmin)
188
+ // - connect/update/disconnect-account: Lifecycle
189
+ r.writeHandler(ingestMessageHandler);
190
+ r.writeHandler(connectAccountHandler);
191
+ r.writeHandler(updateAccountHandler);
192
+ r.writeHandler(disconnectAccountHandler);
182
193
 
183
- // Write-Handler:
184
- // - ingest-message: programmatic (Supervisor/Poll, SystemAdmin)
185
- // - connect/update/disconnect-account: Lifecycle
186
- r.writeHandler(ingestMessageHandler);
187
- r.writeHandler(connectAccountHandler);
188
- r.writeHandler(updateAccountHandler);
189
- r.writeHandler(disconnectAccountHandler);
194
+ // List-Queries (PII-decrypted, scope-gefiltert).
195
+ r.queryHandler(listAccountsQuery);
196
+ r.queryHandler(listMessagesQuery);
190
197
 
191
- // List-Queries (PII-decrypted, scope-gefiltert).
192
- r.queryHandler(listAccountsQuery);
193
- r.queryHandler(listMessagesQuery);
198
+ // Entity-genaue GDPR-Destroy-Hooks — der gdpr-storage-Boot-Validator
199
+ // prueft die EXT_TENANT_DATA-Registrierung pro tenant-subject-Entity.
200
+ r.useExtension(EXT_TENANT_DATA, "mail-account", {
201
+ destroy: mailAccountTenantDestroyHook,
202
+ escapeHatch: { reason: INBOUND_MAIL_TENANT_DESTROY_ARCHIVE_REASON },
203
+ });
204
+ r.useExtension(EXT_TENANT_DATA, "inbound-message", {
205
+ destroy: inboundMessageTenantDestroyHook,
206
+ escapeHatch: { reason: INBOUND_MAIL_TENANT_DESTROY_ARCHIVE_REASON },
207
+ });
208
+ r.useExtension(EXT_TENANT_DATA, "mail-thread", {
209
+ destroy: mailThreadTenantDestroyHook,
210
+ escapeHatch: { reason: INBOUND_MAIL_TENANT_DESTROY_ARCHIVE_REASON },
211
+ });
194
212
 
195
- // Entity-genaue GDPR-Destroy-Hooks — der gdpr-storage-Boot-Validator
196
- // prueft die EXT_TENANT_DATA-Registrierung pro tenant-subject-Entity.
197
- r.useExtension(EXT_TENANT_DATA, "mail-account", {
198
- destroy: mailAccountTenantDestroyHook,
199
- escapeHatch: { reason: INBOUND_MAIL_TENANT_DESTROY_ARCHIVE_REASON },
200
- });
201
- r.useExtension(EXT_TENANT_DATA, "inbound-message", {
202
- destroy: inboundMessageTenantDestroyHook,
203
- escapeHatch: { reason: INBOUND_MAIL_TENANT_DESTROY_ARCHIVE_REASON },
204
- });
205
- r.useExtension(EXT_TENANT_DATA, "mail-thread", {
206
- destroy: mailThreadTenantDestroyHook,
207
- escapeHatch: { reason: INBOUND_MAIL_TENANT_DESTROY_ARCHIVE_REASON },
208
- });
213
+ // Data-Retention (#957) — perTenant fan-out (one run per tenant, like
214
+ // data-retention:retention-cleanup): runInboundMailRetention's raw query
215
+ // helpers need the unfiltered runner, so the handler declares escapeHatch
216
+ // and reaches for ctx.db.unsafeRaw(). Without this cron, read_inbound_messages
217
+ // + the bodies grow unbounded (GDPR Art. 5).
218
+ const INBOUND_MAIL_RETENTION_REASON =
219
+ "inbound-mail retention runs raw deletes; every statement filters by this run's tenantId";
220
+ r.job({
221
+ name: "inbound-mail-retention",
222
+ trigger: { cron: "0 3 * * *" },
223
+ perTenant: true,
224
+ concurrency: "skip",
225
+ escapeHatch: { reason: INBOUND_MAIL_RETENTION_REASON },
226
+ handler: async (_payload, ctx) => {
227
+ if (!ctx.registry) {
228
+ throw new Error(
229
+ "inbound-mail-retention: ctx.registry required (JobContext incomplete)",
230
+ );
231
+ }
232
+ const tenantId = ctx.systemUser?.tenantId ?? ctx._tenantId;
233
+ if (tenantId === undefined) {
234
+ // skip: cron fired without a perTenant fan-out tenant — nothing scoped
235
+ return;
236
+ }
237
+ const T = (await import("@cosmicdrift/kumiko-framework/time")).getTemporal();
238
+ const retentionDb = ctx.db.unsafeRaw() as DbConnection; // @cast-boundary db-operator — jobs never run inside a DbTx
209
239
 
210
- // Data-Retention (#957) — perTenant fan-out (one run per tenant, like
211
- // data-retention:retention-cleanup): runInboundMailRetention's raw query
212
- // helpers need the unfiltered runner, so the handler declares escapeHatch
213
- // and reaches for ctx.db.unsafeRaw(). Without this cron, read_inbound_messages
214
- // + the bodies grow unbounded (GDPR Art. 5).
215
- const INBOUND_MAIL_RETENTION_REASON =
216
- "inbound-mail retention runs raw deletes; every statement filters by this run's tenantId";
217
- r.job({
218
- name: "inbound-mail-retention",
219
- trigger: { cron: "0 3 * * *" },
220
- perTenant: true,
221
- concurrency: "skip",
222
- escapeHatch: { reason: INBOUND_MAIL_RETENTION_REASON },
223
- handler: async (_payload, ctx) => {
224
- if (!ctx.registry) {
225
- throw new Error("inbound-mail-retention: ctx.registry required (JobContext incomplete)");
226
- }
227
- const tenantId = ctx.systemUser?.tenantId ?? ctx._tenantId;
228
- if (tenantId === undefined) {
229
- // skip: cron fired without a perTenant fan-out tenant — nothing scoped
230
- return;
231
- }
232
- const T = (await import("@cosmicdrift/kumiko-framework/time")).getTemporal();
233
- const retentionDb = ctx.db.unsafeRaw() as DbConnection; // @cast-boundary db-operator — jobs never run inside a DbTx
240
+ // Body-Objekte liegen in file-foundation. Provider lazy + memoized —
241
+ // heute schreibt der Ingest kein bodyRef (storeBody-Hook ungebunden),
242
+ // der Provider wird also nie gebaut. Sobald storeBody wired ist, raeumt
243
+ // die Retention die Bodies mit ab.
244
+ let providerPromise: Promise<FileStorageProvider> | null = null;
245
+ const deleteBodyObject = async (bodyRef: string): Promise<void> => {
246
+ if (!providerPromise) {
247
+ providerPromise = createFileProviderForTenant(
248
+ { config: ctx.config, registry: ctx.registry },
249
+ tenantId,
250
+ );
251
+ }
252
+ const provider = await providerPromise;
253
+ await provider.delete(bodyRef);
254
+ };
234
255
 
235
- // Body-Objekte liegen in file-foundation. Provider lazy + memoized —
236
- // heute schreibt der Ingest kein bodyRef (storeBody-Hook ungebunden),
237
- // der Provider wird also nie gebaut. Sobald storeBody wired ist, raeumt
238
- // die Retention die Bodies mit ab.
239
- let providerPromise: Promise<FileStorageProvider> | null = null;
240
- const deleteBodyObject = async (bodyRef: string): Promise<void> => {
241
- if (!providerPromise) {
242
- providerPromise = createFileProviderForTenant(
243
- { config: ctx.config, registry: ctx.registry },
256
+ const report = await runInboundMailRetention({
257
+ db: retentionDb,
244
258
  tenantId,
245
- );
246
- }
247
- const provider = await providerPromise;
248
- await provider.delete(bodyRef);
249
- };
250
-
251
- const report = await runInboundMailRetention({
252
- db: retentionDb,
253
- tenantId,
254
- now: T.Now.instant(),
255
- deleteBodyObject,
259
+ now: T.Now.instant(),
260
+ deleteBodyObject,
261
+ });
262
+ if (report.bodyObjectErrors > 0) {
263
+ // biome-ignore lint/suspicious/noConsole: operator-visibility for failed body deletes
264
+ console.warn(
265
+ `[inbound-mail-foundation:inbound-mail-retention] tenant=${tenantId} bodyObjectErrors=${report.bodyObjectErrors}`,
266
+ );
267
+ }
268
+ },
256
269
  });
257
- if (report.bodyObjectErrors > 0) {
258
- // biome-ignore lint/suspicious/noConsole: operator-visibility for failed body deletes
259
- console.warn(
260
- `[inbound-mail-foundation:inbound-mail-retention] tenant=${tenantId} bodyObjectErrors=${report.bodyObjectErrors}`,
261
- );
262
- }
263
270
  },
264
- });
265
- });
271
+ { dedupeOptions: {} },
272
+ );
273
+ }
274
+
275
+ /** @deprecated Use createInboundMailFoundationFeature(). Run `bun kumiko-upgrade --apply`. Removed in the first release after 2026-10-29. */
276
+ export const inboundMailFoundationFeature = createInboundMailFoundationFeature();
@@ -20,12 +20,11 @@
20
20
  // SystemAdmin-only: Aufrufer ist der Watch/Sync-Supervisor bzw. der
21
21
  // Poll-Cron mit programmatic SystemUser — nie ein Tenant-Request.
22
22
 
23
- import { countWhere } from "@cosmicdrift/kumiko-framework/bun-db";
24
23
  import {
25
24
  configuredPiiSubjectKms,
26
25
  encryptPiiFieldValues,
27
26
  } from "@cosmicdrift/kumiko-framework/crypto";
28
- import { acquireNamespacedAdvisoryLock } from "@cosmicdrift/kumiko-framework/db";
27
+ import { acquireNamespacedAdvisoryLock, countWhere } from "@cosmicdrift/kumiko-framework/db";
29
28
  import type { WriteHandlerDef } from "@cosmicdrift/kumiko-framework/engine";
30
29
  import { InternalError } from "@cosmicdrift/kumiko-framework/errors";
31
30
  import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
@@ -54,7 +54,7 @@ export {
54
54
  mailAccountEventPayloadSchema,
55
55
  mailThreadEventPayloadSchema,
56
56
  } from "./events.js";
57
- export { inboundMailFoundationFeature } from "./feature.js";
57
+ export { createInboundMailFoundationFeature, inboundMailFoundationFeature } from "./feature.js";
58
58
  export {
59
59
  createOAuthAccessTokenManager,
60
60
  inboundRefreshTokenSecretOptions,
@@ -16,8 +16,11 @@
16
16
  // audit context. SecretsContext does not cache values (only unwrapped DEKs),
17
17
  // so the read always reflects the latest committed write.
18
18
 
19
- import { transaction } from "@cosmicdrift/kumiko-framework/bun-db";
20
- import { acquireNamespacedAdvisoryLock, type DbConnection } from "@cosmicdrift/kumiko-framework/db";
19
+ import {
20
+ acquireNamespacedAdvisoryLock,
21
+ type DbConnection,
22
+ transaction,
23
+ } from "@cosmicdrift/kumiko-framework/db";
21
24
  import type { SecretsContext } from "@cosmicdrift/kumiko-framework/secrets";
22
25
  import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
23
26
  import { InboundMailAuthMethods, inboundCredentialSecretKey } from "./constants.js";
@@ -18,11 +18,12 @@
18
18
  // in den list-queries.
19
19
 
20
20
  import {
21
+ buildEntityTable,
22
+ type EntityTableMeta,
21
23
  insertOnConflictDoNothing,
22
24
  requireEntityTableMeta,
23
25
  upsertOnConflict,
24
- } from "@cosmicdrift/kumiko-framework/bun-db";
25
- import { buildEntityTable, type EntityTableMeta } from "@cosmicdrift/kumiko-framework/db";
26
+ } from "@cosmicdrift/kumiko-framework/db";
26
27
  import { defineApply } from "@cosmicdrift/kumiko-framework/engine";
27
28
  import { inboundMessageEntity, mailAccountEntity, mailThreadEntity } from "./entities.js";
28
29
  import type {
@@ -44,12 +44,12 @@
44
44
  // only while the connection is open. Losing the claim (Redis outage, TTL
45
45
  // exceeded) tears down the local watcher instead of racing a new holder.
46
46
 
47
- import { fetchOne, insertOne, selectMany, updateMany } from "@cosmicdrift/kumiko-framework/bun-db";
48
47
  import {
49
48
  configuredPiiSubjectKms,
50
49
  decryptPiiFieldValues,
51
50
  } from "@cosmicdrift/kumiko-framework/crypto";
52
51
  import type { DbConnection } from "@cosmicdrift/kumiko-framework/db";
52
+ import { fetchOne, insertOne, selectMany, updateMany } from "@cosmicdrift/kumiko-framework/db";
53
53
  import type { DistributedLock } from "@cosmicdrift/kumiko-framework/pipeline";
54
54
  import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
55
55
  import { isPlainObject } from "@cosmicdrift/kumiko-types/type-guards";
@@ -272,17 +272,26 @@ export const imapInboundMailPlugin: InboundMailProviderPlugin = {
272
272
  // gehören den OAuth-Providern (M365/Gmail).
273
273
  };
274
274
 
275
- export const inboundProviderImapFeature = defineFeature(FEATURE_NAME, (r) => {
276
- r.describe(
277
- 'Registers the `"imap"` provider for `inbound-mail-foundation` using imapflow — password/app-password auth covers classic IMAP hosts without any OAuth (plus an XOAUTH2 fallback consuming an access token from the secret slot). Incremental sync via a UIDVALIDITY:lastUid cursor (UIDVALIDITY change triggers a cursor-invalid full resync), initial backfill bounded by the foundation backfill window, and live push via IMAP IDLE for the watch supervisor. Store the per-account connection JSON (host/port/secure/user/password) in the account credential secret slot before the first sync.',
275
+ export function createInboundProviderImapFeature() {
276
+ return defineFeature(
277
+ FEATURE_NAME,
278
+ (r) => {
279
+ r.describe(
280
+ 'Registers the `"imap"` provider for `inbound-mail-foundation` using imapflow — password/app-password auth covers classic IMAP hosts without any OAuth (plus an XOAUTH2 fallback consuming an access token from the secret slot). Incremental sync via a UIDVALIDITY:lastUid cursor (UIDVALIDITY change triggers a cursor-invalid full resync), initial backfill bounded by the foundation backfill window, and live push via IMAP IDLE for the watch supervisor. Store the per-account connection JSON (host/port/secure/user/password) in the account credential secret slot before the first sync.',
281
+ );
282
+ r.uiHints({
283
+ displayLabel: "Inbound Mail · IMAP",
284
+ category: "notifications",
285
+ recommended: false,
286
+ });
287
+ r.requires({ features: ["inbound-mail-foundation"] });
288
+ r.requires({ features: ["secrets"] });
289
+ r.envSchema(mailAllowedPrivateHostsEnvSchema);
290
+ r.useExtension(INBOUND_MAIL_PROVIDER_EXTENSION, IMAP_PROVIDER_KEY, imapInboundMailPlugin);
291
+ },
292
+ { dedupeOptions: {} },
278
293
  );
279
- r.uiHints({
280
- displayLabel: "Inbound Mail · IMAP",
281
- category: "notifications",
282
- recommended: false,
283
- });
284
- r.requires({ features: ["inbound-mail-foundation"] });
285
- r.requires({ features: ["secrets"] });
286
- r.envSchema(mailAllowedPrivateHostsEnvSchema);
287
- r.useExtension(INBOUND_MAIL_PROVIDER_EXTENSION, IMAP_PROVIDER_KEY, imapInboundMailPlugin);
288
- });
294
+ }
295
+
296
+ /** @deprecated Use createInboundProviderImapFeature(). Run `bun kumiko-upgrade --apply`. Removed in the first release after 2026-10-29. */
297
+ export const inboundProviderImapFeature = createInboundProviderImapFeature();
@@ -6,7 +6,12 @@ export {
6
6
  type ParseCredentialResult,
7
7
  parseImapCredentialDocument,
8
8
  } from "./credential-document.js";
9
- export { IMAP_PROVIDER_KEY, inboundProviderImapFeature, setImapMailHostLookup } from "./feature.js";
9
+ export {
10
+ createInboundProviderImapFeature,
11
+ IMAP_PROVIDER_KEY,
12
+ inboundProviderImapFeature,
13
+ setImapMailHostLookup,
14
+ } from "./feature.js";
10
15
  export {
11
16
  assertUidValidity,
12
17
  buildProviderMessageId,
@@ -139,16 +139,24 @@ export const inMemoryInboundMailPlugin: InboundMailProviderPlugin = {
139
139
  // =============================================================================
140
140
  // Feature-definition
141
141
  // =============================================================================
142
-
143
- export const inboundProviderInMemoryFeature = defineFeature(FEATURE_NAME, (r) => {
144
- r.describe(
145
- 'Registers a scriptable in-process `"inmemory"` provider for `inbound-mail-foundation`. Seed messages with `seedInboundMessage(accountId, msg)` — an active watch pushes them immediately (IDLE simulation) and the cursor-based `fetch` re-delivers them on the reconciliation path, exercising the foundation dedup guarantee. Error injection via `failNextFetchWith`/`failNextVerifyWith`/`emitWatchError`; reset state with `resetInboundInMemory()`. For tests, demos and sample apps — not for production.',
142
+ export function createInboundProviderInMemoryFeature() {
143
+ return defineFeature(
144
+ FEATURE_NAME,
145
+ (r) => {
146
+ r.describe(
147
+ 'Registers a scriptable in-process `"inmemory"` provider for `inbound-mail-foundation`. Seed messages with `seedInboundMessage(accountId, msg)` — an active watch pushes them immediately (IDLE simulation) and the cursor-based `fetch` re-delivers them on the reconciliation path, exercising the foundation dedup guarantee. Error injection via `failNextFetchWith`/`failNextVerifyWith`/`emitWatchError`; reset state with `resetInboundInMemory()`. For tests, demos and sample apps — not for production.',
148
+ );
149
+ r.uiHints({
150
+ displayLabel: "Inbound Mail · In-Memory Provider",
151
+ category: "notifications",
152
+ recommended: false,
153
+ });
154
+ r.requires({ features: ["inbound-mail-foundation"] });
155
+ r.useExtension("inboundMailProvider", INMEMORY_PROVIDER_KEY, inMemoryInboundMailPlugin);
156
+ },
157
+ { dedupeOptions: {} },
146
158
  );
147
- r.uiHints({
148
- displayLabel: "Inbound Mail · In-Memory Provider",
149
- category: "notifications",
150
- recommended: false,
151
- });
152
- r.requires({ features: ["inbound-mail-foundation"] });
153
- r.useExtension("inboundMailProvider", INMEMORY_PROVIDER_KEY, inMemoryInboundMailPlugin);
154
- });
159
+ }
160
+
161
+ /** @deprecated Use createInboundProviderInMemoryFeature(). Run `bun kumiko-upgrade --apply`. Removed in the first release after 2026-10-29. */
162
+ export const inboundProviderInMemoryFeature = createInboundProviderInMemoryFeature();
@@ -1,6 +1,7 @@
1
1
  // Public API of the inbound-provider-inmemory bundled-feature.
2
2
 
3
3
  export {
4
+ createInboundProviderInMemoryFeature,
4
5
  emitWatchError,
5
6
  failNextFetchWith,
6
7
  failNextVerifyWith,
@@ -10,8 +10,8 @@
10
10
  // deleteManyBatched (typed query API, no raw SQL in this file) chunks each
11
11
  // delete so a large backlog doesn't hold one lock for the whole sweep.
12
12
 
13
- import { deleteManyBatched } from "@cosmicdrift/kumiko-framework/bun-db";
14
13
  import type { DbConnection } from "@cosmicdrift/kumiko-framework/db";
14
+ import { deleteManyBatched } from "@cosmicdrift/kumiko-framework/db";
15
15
  import { jobRunLogsTable, jobRunsTable } from "../../job-run-table.js";
16
16
  import { tenantJobFailuresTable } from "../../tenant-job-failure-table.js";
17
17
  import { tenantJobRunsTable } from "../../tenant-job-run-table.js";
@@ -12,8 +12,8 @@
12
12
  // the run becomes retriable via the existing jobs:write:retry gate
13
13
  // (retry.write.ts only allows retry from "failed").
14
14
 
15
- import { deleteManyBatched, selectMany, updateMany } from "@cosmicdrift/kumiko-framework/bun-db";
16
15
  import type { DbConnection } from "@cosmicdrift/kumiko-framework/db";
16
+ import { deleteManyBatched, selectMany, updateMany } from "@cosmicdrift/kumiko-framework/db";
17
17
  import { mapWithConcurrency } from "../../../shared/index.js";
18
18
  import { DEFAULT_JOB_RUN_RETENTION_DAYS } from "../../handlers/retention-cleanup.job.js";
19
19
  import { encryptFailureError } from "../../job-run-logger.js";
@@ -1,4 +1,4 @@
1
- import { fetchOne, selectMany } from "@cosmicdrift/kumiko-framework/bun-db";
1
+ import { fetchOne, selectMany } from "@cosmicdrift/kumiko-framework/db";
2
2
  import { defineQueryHandler } from "@cosmicdrift/kumiko-framework/engine";
3
3
  import { InternalError } from "@cosmicdrift/kumiko-framework/errors";
4
4
  import * as z from "zod";
@@ -1,5 +1,10 @@
1
- import { countWhere, selectMany, type WhereObject } from "@cosmicdrift/kumiko-framework/bun-db";
2
- import { decodeCursor, encodeCursor } from "@cosmicdrift/kumiko-framework/db";
1
+ import {
2
+ countWhere,
3
+ decodeCursor,
4
+ encodeCursor,
5
+ selectMany,
6
+ type WhereObject,
7
+ } from "@cosmicdrift/kumiko-framework/db";
3
8
  import { defineQueryHandler } from "@cosmicdrift/kumiko-framework/engine";
4
9
  import { InternalError, ValidationError } from "@cosmicdrift/kumiko-framework/errors";
5
10
  import * as z from "zod";
@@ -1,5 +1,5 @@
1
- import { fetchOne } from "@cosmicdrift/kumiko-framework/bun-db";
2
1
  import { isPiiCiphertext, PII_ERASED_SENTINEL } from "@cosmicdrift/kumiko-framework/crypto";
2
+ import { fetchOne } from "@cosmicdrift/kumiko-framework/db";
3
3
  import { defineWriteHandler } from "@cosmicdrift/kumiko-framework/engine";
4
4
  import {
5
5
  InternalError,
@@ -1,4 +1,4 @@
1
- import { selectMany } from "@cosmicdrift/kumiko-framework/bun-db";
1
+ import { selectMany } from "@cosmicdrift/kumiko-framework/db";
2
2
  import { access, defineQueryHandler } from "@cosmicdrift/kumiko-framework/engine";
3
3
  import { InternalError } from "@cosmicdrift/kumiko-framework/errors";
4
4
  import { serializeJobSubject } from "@cosmicdrift/kumiko-framework/jobs";
@@ -1,4 +1,4 @@
1
- import { selectMany } from "@cosmicdrift/kumiko-framework/bun-db";
1
+ import { selectMany } from "@cosmicdrift/kumiko-framework/db";
2
2
  import { access, defineQueryHandler } from "@cosmicdrift/kumiko-framework/engine";
3
3
  import { InternalError } from "@cosmicdrift/kumiko-framework/errors";
4
4
  import { serializeJobSubject } from "@cosmicdrift/kumiko-framework/jobs";
@@ -1,4 +1,14 @@
1
1
  import {
2
+ configuredPiiSubjectKms,
3
+ encryptPiiValueForSubject,
4
+ KeyErasedError,
5
+ type LocalKeyKmsAdapter,
6
+ PII_ERASED_SENTINEL,
7
+ type SubjectId,
8
+ } from "@cosmicdrift/kumiko-framework/crypto";
9
+ import {
10
+ acquireNamespacedAdvisoryLock,
11
+ type DbConnection,
2
12
  deleteMany,
3
13
  fetchOne,
4
14
  insertMany,
@@ -7,16 +17,7 @@ import {
7
17
  transaction,
8
18
  updateMany,
9
19
  upsertOnConflict,
10
- } from "@cosmicdrift/kumiko-framework/bun-db";
11
- import {
12
- configuredPiiSubjectKms,
13
- encryptPiiValueForSubject,
14
- KeyErasedError,
15
- type LocalKeyKmsAdapter,
16
- PII_ERASED_SENTINEL,
17
- type SubjectId,
18
- } from "@cosmicdrift/kumiko-framework/crypto";
19
- import { acquireNamespacedAdvisoryLock, type DbConnection } from "@cosmicdrift/kumiko-framework/db";
20
+ } from "@cosmicdrift/kumiko-framework/db";
20
21
  import { type Registry, SYSTEM_TENANT_ID } from "@cosmicdrift/kumiko-framework/engine";
21
22
  import type {
22
23
  JobDroppedMeta,
@@ -1,9 +1,9 @@
1
- import { requireEntityTableMeta } from "@cosmicdrift/kumiko-framework/bun-db";
2
1
  import {
3
2
  type EntityTableMeta,
4
3
  index,
5
4
  instant,
6
5
  table as pgTable,
6
+ requireEntityTableMeta,
7
7
  serial,
8
8
  sql,
9
9
  text,