@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,30 +1,30 @@
1
- // 3-Schicht-Retention-Resolver.
1
+ // Three-layer retention resolver.
2
2
  //
3
- // Layer 1: Entity-Default — Feature-Author setzt r.entity({retention})
4
- // Layer 2: Tenant-Preset — Tenant-Admin wählt Bundle (RETENTION_PRESETS)
5
- // Layer 3: Tenant-Override — per (tenantId, entityName) JSON-Override
3
+ // Layer 1: Entity default — Feature author sets r.entity({retention})
4
+ // Layer 2: Tenant preset — Tenant admin selects a bundle (RETENTION_PRESETS)
5
+ // Layer 3: Tenant override — per (tenantId, entityName) JSON override
6
6
  //
7
- // Resolver-Reihenfolge:
7
+ // Resolution order:
8
8
  // effective = override(tenantId, entityName)
9
9
  // ?? preset[tenant.retentionPreset][entityName]
10
- // ?? entity.retention (Code-Default aus EntityDefinition)
11
- // ?? null (keine Auto-Aktion)
10
+ // ?? entity.retention (code default from EntityDefinition)
11
+ // ?? null (no automatic action)
12
12
  //
13
- // Cleanup-Job in S2.D2 ruft das pro (tenantId, entityName) und
14
- // entscheidet was zu tun ist (hardDelete / softDelete / anonymize /
15
- // blockDelete-mit-Frist-Check).
13
+ // The cleanup job resolves this for each (tenantId, entityName) and
14
+ // decides what to do (hardDelete / softDelete / anonymize /
15
+ // blockDelete with a grace-period check).
16
16
  //
17
- // Cross-Feature-API r.exposesApi("retention.policyFor") (S2.D3)
18
- // macht das aus user-data-rights heraus konsumierbar — Forget-Flow
19
- // fragt blockDelete-Felder ab + anonymisiert sie statt zu löschen.
17
+ // The cross-feature API r.exposesApi("retention.policyFor")
18
+ // makes this consumable by user-data-rights — the forget flow
19
+ // queries blockDelete fields and anonymizes them instead of deleting them.
20
20
 
21
21
  import type { EntityDefinition, RetentionDef } from "@cosmicdrift/kumiko-framework/engine";
22
22
  import { RETENTION_PRESETS, type RetentionPresetKey } from "./presets.ts";
23
23
 
24
24
  /**
25
- * Roh-Override aus der DB-Tabelle (config-Spalte als JSON-String).
26
- * Nicht das gleiche wie RetentionDef weil hier alles optional ist —
27
- * Override darf einzelne Properties überschreiben.
25
+ * Raw override from the database table (the config column as a JSON string).
26
+ * Unlike RetentionDef, every property is optional because an override may
27
+ * replace individual properties.
28
28
  */
29
29
  export interface RetentionOverride {
30
30
  readonly keepFor?: string;
@@ -33,13 +33,13 @@ export interface RetentionOverride {
33
33
  }
34
34
 
35
35
  /**
36
- * Effektive Policy nach Resolver-Lauf. Source dokumentiert WELCHE
37
- * Schicht den Wert geliefert hat — Audit-Trail für DPO.
36
+ * Effective policy after the resolver ran. `source` records WHICH layer
37
+ * supplied the value, as an audit trail for the DPO.
38
38
  *
39
- * `override-incomplete` bedeutet: Tenant-Override ist gesetzt, aber
40
- * füllt keepFor weder selbst noch via Preset-/Entity-Fallback.
41
- * Cleanup-Job logt eine Warning + skippt — anstatt mit Default-"0d"
42
- * sofort alles zu löschen.
39
+ * `override-incomplete` means a tenant override is set but fills keepFor
40
+ * neither itself nor through the preset/entity fallback. The cleanup job
41
+ * logs a warning and skips instead of deleting everything at once with a
42
+ * default "0d".
43
43
  */
44
44
  export interface EffectiveRetentionPolicy {
45
45
  readonly entityName: string;
@@ -55,15 +55,15 @@ export interface ResolveRetentionPolicyArgs {
55
55
  }
56
56
 
57
57
  /**
58
- * Auswertung der drei Schichten. Pure Function — kein DB-Access, alle
59
- * Inputs werden vom Caller besorgt (Cleanup-Job aggregiert pro Tenant
60
- * vorher).
58
+ * Resolves the three layers. This is a pure function with no database
59
+ * access; the caller supplies all inputs (the cleanup job aggregates them
60
+ * per tenant beforehand).
61
61
  */
62
62
  export function resolveRetentionPolicy(args: ResolveRetentionPolicyArgs): EffectiveRetentionPolicy {
63
63
  const { entityName, entityDef, tenantPreset, tenantOverride } = args;
64
64
 
65
- // Layer 3: Override wins, aber Override darf Felder weglassen — dann
66
- // fallen die einzelnen Properties auf Layer 2/1 zurück.
65
+ // Layer 3: Override wins, but it may omit fields, which then
66
+ // fall back to the individual properties from Layer 2 or 1.
67
67
  if (tenantOverride !== null) {
68
68
  const baseFromPreset =
69
69
  tenantPreset !== null ? (RETENTION_PRESETS[tenantPreset]?.[entityName] ?? null) : null;
@@ -73,10 +73,11 @@ export function resolveRetentionPolicy(args: ResolveRetentionPolicyArgs): Effect
73
73
  const keepFor = tenantOverride.keepFor ?? base?.keepFor;
74
74
  const strategy = tenantOverride.strategy ?? base?.strategy;
75
75
 
76
- // keepFor + strategy sind Pflicht für jede aktive Policy. Wenn
77
- // weder Override noch Base sie liefert, ist das Override semantisch
78
- // unvollständig — Cleanup-Job soll WARNEN statt mit Default-"0d"
79
- // sofort alles löschen. Source-Marker dokumentiert das.
76
+ // keepFor + strategy are required for every active policy. If
77
+ // neither the override nor the base supplies them, the override is
78
+ // semantically incomplete — the cleanup job must warn instead of
79
+ // immediately deleting everything with the default "0d". The source
80
+ // marker documents this.
80
81
  if (keepFor === undefined || strategy === undefined) {
81
82
  return { entityName, policy: null, source: "override-incomplete" };
82
83
  }
@@ -102,6 +103,6 @@ export function resolveRetentionPolicy(args: ResolveRetentionPolicyArgs): Effect
102
103
  return { entityName, policy: entityDef.retention, source: "entity-default" };
103
104
  }
104
105
 
105
- // Nichts da — Cleanup-Job überspringt diese Entity für diesen Tenant.
106
+ // No policy is defined, so the cleanup job skips this entity for this tenant.
106
107
  return { entityName, policy: null, source: "none" };
107
108
  }
@@ -1,42 +1,41 @@
1
- // Retention-Cleanup-Runner (S2.D2b) — pure Function, vom retention-cleanup-Cron
2
- // pro fan-out-Tenant aufgerufen.
1
+ // Retention-Cleanup-Runner — pure function, called by the retention-cleanup cron
2
+ // for each fan-out tenant.
3
3
  //
4
- // Iteriert alle implicit-Entity-Projektionen, loest pro Entity die effektive
5
- // Retention-Policy (3-Schicht-Resolver, siehe resolver.ts) und wendet die
6
- // Strategy auf Rows an deren reference-Timestamp aelter als der keepFor-Cutoff
7
- // ist:
4
+ // Iterates all implicit entity projections, resolves the effective retention
5
+ // policy per entity (3-layer resolver, see resolver.ts), and applies the
6
+ // strategy to rows whose reference timestamp is older than the keepFor cutoff:
8
7
  //
9
- // - hardDelete → executor.forget pro Row (Event → rebuild-safe hard purge).
8
+ // - hardDelete → executor.forget per row (event → rebuild-safe hard purge).
10
9
  // Entities with file/image/files/images fields: bytes first
11
10
  // (incl. derivatives), then the fileRef row(s), then the row;
12
11
  // shared fileRefs (other owner, other row of the same table)
13
12
  // stay untouched.
14
- // - softDelete → executor.delete pro Row (Event → rebuild-safe soft-delete),
15
- // nur auf noch-nicht-geloeschte (isDeleted:false-Filter)
16
- // - anonymize → executor.update pro Row mit den Werten der per-Feld
17
- // anonymize-Funktionen; Row bleibt (fields.ts-Contract)
18
- // - blockDelete → waehrend keepFor unangetastet (Aufbewahrungs-Pflicht;
19
- // user-forget loest anonymize aus). NACH Ablauf laufen die
20
- // anonymize-Funktionen — Geschaeftsdaten bleiben, Personen-
21
- // Bezug raus (fields.ts:44-47).
13
+ // - softDelete → executor.delete per row (event → rebuild-safe soft-delete),
14
+ // only on not-yet-deleted rows (isDeleted:false filter)
15
+ // - anonymize → executor.update per row with the values of the per-field
16
+ // anonymize functions; row remains (fields.ts contract)
17
+ // - blockDelete → untouched during keepFor (retention requirement;
18
+ // user-forget triggers anonymize). AFTER expiration, the
19
+ // anonymize functions run — business data remains, the person-
20
+ // identifying link is removed (fields.ts:44-47).
22
21
  //
23
- // Über den Executor statt Batch-deleteMany/updateMany: ein eventloser Batch-Write
24
- // auf die (erased) Projektions-Tabelle wird beim Projection-Rebuild
25
- // gewischt/resurrektiert — das #648-Loch. Kosten: N Events pro Cleanup statt ein
26
- // Batch-Statement (per-Row-Ceiling, Batch-Event-Variante als Follow-up).
22
+ // Via the executor instead of batch-deleteMany/updateMany: an eventless batch write
23
+ // to the (erased) projection table is wiped/resurrected during a projection rebuild.
24
+ // Cost: N events per cleanup instead of one batch statement (per-row ceiling, with
25
+ // a batch-event variant later).
27
26
  //
28
- // **Schaerfer als soft-delete-cleanup:** dieser Cron hardDeleted LIVE Rows
29
- // (keyed auf reference, Default createdAt), nicht bereits-soft-geloeschte.
30
- // Darum die Spalten-Existenz-Pruefung vor jedem WHERE — eine fehlende/vertippte
31
- // reference-Spalte wuerde sonst ein malformed/all-matching WHERE ergeben und
32
- // pauschal loeschen.
27
+ // **Stricter than soft-delete-cleanup:** this cron hard-deletes LIVE rows
28
+ // (keyed on reference, default createdAt), not already-soft-deleted ones.
29
+ // Therefore the column-existence check comes before every WHERE — a missing/mistyped
30
+ // reference column would otherwise produce a malformed/all-matching WHERE and
31
+ // delete everything.
33
32
  //
34
- // **anonymize-Idempotenz ohne Marker-Spalte:** die anonymize-Funktionen sind
35
- // row-unabhaengig (`() => unknown`) — einmal pro Entity ausgewertet ergeben
36
- // sie die Ziel-Werte. Eine Row die sie schon traegt wird uebersprungen, der
37
- // taegliche Re-Lauf appended also null Events. Der WHERE matcht anonymisierte
38
- // Rows weiter (reference bleibt alt), deshalb id-Cursor-Paging statt einer
39
- // einzelnen Page — sonst verstopfen erledigte Rows das batchLimit-Fenster.
33
+ // **anonymize idempotence without a marker column:** the anonymize functions are
34
+ // row-independent (`() => unknown`) — evaluated once per entity, they produce
35
+ // the target values. A row that already carries them is skipped, so the
36
+ // daily rerun appends zero events. The WHERE continues to match anonymized
37
+ // rows (reference remains old), hence id-cursor paging instead of a single
38
+ // page — otherwise completed rows clog the batchLimit window.
40
39
 
41
40
  import {
42
41
  collectPiiSubjectFields,
@@ -68,6 +67,7 @@ import {
68
67
  type SessionUser,
69
68
  type TenantId,
70
69
  } from "@cosmicdrift/kumiko-framework/engine";
70
+ import { InternalError } from "@cosmicdrift/kumiko-framework/errors";
71
71
  import {
72
72
  type FileContext,
73
73
  fileRefEntity,
@@ -89,13 +89,13 @@ import { tenantRetentionOverrideTable } from "./schema/tenant-retention-override
89
89
  const DEFAULT_BATCH_LIMIT = 1000;
90
90
  const DEFAULT_REFERENCE_FIELD = "createdAt";
91
91
 
92
- // Der Boot-Validator (boot-validator/pii-retention.ts FRAMEWORK_TIMESTAMP_FIELDS)
93
- // erlaubt diese Aliase als retention.reference, auch wenn sie nicht in
94
- // entity.fields deklariert sind — die physischen Spalten heissen aber anders
95
- // (table-builder.ts: inserted_at/modified_at). Hier zur Cleanup-Zeit auf das
96
- // echte Entity-Feld mappen, sonst trifft die Spalten-Existenz-Pruefung unten
97
- // und der Cron wuerde lautlos nichts tun. deletedAt/lastSeenAt sind echte
98
- // Felder (softDelete bzw. session) und brauchen keine Uebersetzung.
92
+ // The boot validator (boot-validator/pii-retention.ts FRAMEWORK_TIMESTAMP_FIELDS)
93
+ // permits these aliases as retention.reference even when they are not declared in
94
+ // entity.fields, but the physical columns use different names
95
+ // (table-builder.ts: inserted_at/modified_at). Map them to the actual entity field
96
+ // during cleanup; otherwise the column existence check below would cause the cron
97
+ // to do nothing silently. deletedAt/lastSeenAt are real fields (softDelete and
98
+ // session respectively) and need no translation.
99
99
  const FRAMEWORK_REFERENCE_ALIAS: Readonly<Record<string, string>> = {
100
100
  createdAt: "insertedAt",
101
101
  updatedAt: "modifiedAt",
@@ -108,14 +108,16 @@ export interface RunRetentionCleanupArgs {
108
108
  /** Layer-2 preset from resolveTenantRetentionPreset, resolved once per tenant
109
109
  * by the caller rather than per entity here. null = layers 1 and 3 only. */
110
110
  readonly preloadedTenantPreset: RetentionPresetKey | null;
111
- /** Now-Injection — Tests pinnen den Wert ohne Date-Mock (Pattern keep-for.ts). */
111
+ /**
112
+ * Injects the current time so tests can pin it without mocking the date (pattern keep-for.ts).
113
+ */
112
114
  readonly now: Instant;
113
115
  readonly batchLimit?: number;
114
116
  /** Storage access for hardDelete entities with file/image/files/images fields.
115
117
  * Missing while fileRefs are due → the row stays (skipped "missing_file_storage"),
116
118
  * fail-closed instead of orphaning bytes. */
117
119
  readonly files?: FileContext;
118
- /** KMS for erasing a hardDeleted row's own subject key (Refs #2057). Defaults
120
+ /** KMS for erasing a hardDeleted row's own subject key. Defaults
119
121
  * to configuredPiiSubjectKms() (same fallback as run-forget-cleanup.ts);
120
122
  * undefined/no-KMS-configured skips erasure entirely — the row is still
121
123
  * hard-deleted, only crypto-shredding of its DEK is not attempted. */
@@ -137,7 +139,10 @@ export interface RunRetentionCleanupResult {
137
139
  readonly softDeleted: number;
138
140
  /** Rows deren anonymize-Feld-Funktionen angewendet wurden (anonymize + abgelaufene blockDelete). */
139
141
  readonly anonymized: number;
140
- /** Anomalien: Policy referenziert eine Spalte die die Tabelle nicht hat, oder anonymize ohne anonymize-Felder. */
142
+ /**
143
+ * Anomalies where the policy references a missing table column or anonymize has no anonymize
144
+ * fields.
145
+ */
141
146
  readonly skipped: readonly RetentionCleanupSkip[];
142
147
  }
143
148
 
@@ -159,7 +164,7 @@ async function purgeMatchingRows(
159
164
  return count;
160
165
  }
161
166
 
162
- // --- hardDelete crypto-shredding (Refs #2057) ---
167
+ // --- hardDelete crypto-shredding ---
163
168
  //
164
169
  // recordOwned/self-pii resolution (subject-resolver.ts) only ever reads
165
170
  // `row.id` for these two kinds — resolveRecordSubject uses opts.entityName +
@@ -243,17 +248,14 @@ async function forgetRowAndEraseKeys(args: {
243
248
  readonly entityName: string;
244
249
  readonly tenantId: TenantId;
245
250
  readonly systemUser: SessionUser;
251
+ readonly rowId: EntityId;
246
252
  readonly row: Record<string, unknown>;
247
253
  readonly kms: KmsAdapter | undefined;
248
254
  readonly registry: Registry;
249
255
  }): Promise<{ readonly isSuccess: boolean }> {
250
256
  return runInSubTransaction(args.db, async (sp) => {
251
257
  const tdb = createTenantDb({ db: sp, tenantId: args.tenantId, mode: "system" });
252
- const result = await args.executor.forget(
253
- { id: args.row["id"] as EntityId },
254
- args.systemUser,
255
- tdb,
256
- );
258
+ const result = await args.executor.forget({ id: args.rowId }, args.systemUser, tdb);
257
259
  if (!result.isSuccess) return { isSuccess: false };
258
260
  await eraseHardDeletedRowKeys({
259
261
  kms: args.kms,
@@ -268,7 +270,7 @@ async function forgetRowAndEraseKeys(args: {
268
270
  });
269
271
  }
270
272
 
271
- // --- hardDelete + file-fields (kumiko-framework#3089) ---
273
+ // --- hardDelete + file-fields ---
272
274
 
273
275
  // Throws (unsafe key, missing list permission) must fail this row closed,
274
276
  // not abort the whole tenant run.
@@ -298,6 +300,7 @@ async function purgeHardDeleteRowWithFiles(args: {
298
300
  readonly tenantId: TenantId;
299
301
  readonly entityName: string;
300
302
  readonly entity: EntityDefinition;
303
+ readonly rowId: EntityId;
301
304
  readonly row: Record<string, unknown>;
302
305
  readonly files: FileContext | undefined;
303
306
  readonly entityExecutor: ReturnType<typeof createEventStoreExecutor>;
@@ -308,8 +311,7 @@ async function purgeHardDeleteRowWithFiles(args: {
308
311
  readonly registry: Registry;
309
312
  readonly onSkip: (reason: "missing_file_storage" | "file_delete_failed") => void;
310
313
  }): Promise<boolean> {
311
- const rowId = String(args.row["id"]);
312
- const logContext = `tenant=${args.tenantId} entity=${args.entityName} row=${rowId}`;
314
+ const logContext = `tenant=${args.tenantId} entity=${args.entityName} row=${String(args.rowId)}`;
313
315
  const files = args.files;
314
316
  const outcome = await purgeRowFileRefs({
315
317
  db: args.db,
@@ -341,6 +343,7 @@ async function purgeHardDeleteRowWithFiles(args: {
341
343
  entityName: args.entityName,
342
344
  tenantId: args.tenantId,
343
345
  systemUser: args.systemUser,
346
+ rowId: args.rowId,
344
347
  row: args.row,
345
348
  kms: args.kms,
346
349
  registry: args.registry,
@@ -392,7 +395,14 @@ async function purgeHardDeleteRowsWithFiles(args: {
392
395
  });
393
396
  if (rows.length === 0) break;
394
397
  for (const row of rows) {
395
- cursor = row["id"] as EntityId; // @cast-boundary db-row
398
+ const rawId = row["id"];
399
+ if (typeof rawId !== "string" && typeof rawId !== "number") {
400
+ throw new InternalError({
401
+ message: `data-retention: ${args.entityName} row has no usable id (got ${typeof rawId})`,
402
+ });
403
+ }
404
+ const rowId = rawId;
405
+ cursor = rowId;
396
406
  const ok = await purgeHardDeleteRowWithFiles({
397
407
  db: args.db,
398
408
  table: args.table,
@@ -400,6 +410,7 @@ async function purgeHardDeleteRowsWithFiles(args: {
400
410
  tenantId: args.tenantId,
401
411
  entityName: args.entityName,
402
412
  entity: args.entity,
413
+ rowId,
403
414
  row,
404
415
  files: args.files,
405
416
  entityExecutor: args.entityExecutor,
@@ -490,9 +501,9 @@ export async function runRetentionCleanup(
490
501
 
491
502
  // Retention writes go through the executor (events) so a projection rebuild
492
503
  // replays the cleanup — a batch deleteMany/updateMany on the (erased)
493
- // projection table is eventless and gets wiped/resurrected on rebuild (the
494
- // #648 hole this closes). The cron acts as the system actor; the WHERE already
495
- // tenant-scopes, so a system-mode TenantDb (no extra filter) is correct.
504
+ // projection table is eventless and gets wiped/resurrected on rebuild.
505
+ // The cron acts as the system actor; the WHERE already tenant-scopes, so a
506
+ // system-mode TenantDb (no extra filter) is correct.
496
507
  // ponytail: per-row events, one batchLimit-sized page per entity per run —
497
508
  // the daily cron converges (hardDelete removes rows, softDelete's isDeleted
498
509
  // filter shrinks the set). A single batched forget/delete event is a follow-up.
@@ -511,8 +522,9 @@ export async function runRetentionCleanup(
511
522
  const overrideByEntity = new Map(overrideRows.map((r) => [r.entityName, { config: r.config }]));
512
523
 
513
524
  for (const proj of registry.getAllProjections().values()) {
514
- // Nur implicit-Entity-Projektionen mit Tabelle — wie soft-delete-cleanup.
515
- // Custom-Projektionen + unmanaged-Tables (z.B. sessions) sind kein Target.
525
+ // Only implicit entity projections with a table are targets, as in
526
+ // soft-delete-cleanup. Custom projections and unmanaged tables (such as
527
+ // sessions) are excluded.
516
528
  if (proj.isImplicit !== true || typeof proj.source !== "string" || !proj.table) continue;
517
529
  const entityName = proj.source;
518
530
 
@@ -539,9 +551,9 @@ export async function runRetentionCleanup(
539
551
 
540
552
  const cutoff = computeCutoff(policy.keepFor, now);
541
553
  const where: WhereObject = { [referenceField]: { lt: cutoff } };
542
- // Tenant-Scope nur wenn die Tabelle eine tenantId-Spalte hat — identisch zu
543
- // soft-delete-cleanup. Ohne diesen Filter wuerde ein Tenant die Rows eines
544
- // anderen treffen.
554
+ // Apply tenant scoping only when the table has a tenantId column, as in
555
+ // soft-delete-cleanup. Without this filter, one tenant could affect another
556
+ // tenant's rows.
545
557
  if (propertyOf(proj.table, "tenantId") !== undefined) {
546
558
  where["tenantId"] = tenantId;
547
559
  }
@@ -559,6 +571,7 @@ export async function runRetentionCleanup(
559
571
  entityName,
560
572
  tenantId,
561
573
  systemUser,
574
+ rowId: id,
562
575
  row: { id },
563
576
  kms,
564
577
  registry,
@@ -5,21 +5,23 @@ import {
5
5
  createTextField,
6
6
  } from "@cosmicdrift/kumiko-framework/engine";
7
7
 
8
- // tenantRetentionOverride — Layer 3 im 3-Schicht-Resolver.
8
+ // tenantRetentionOverride — Layer 3 in the three-layer resolver.
9
9
  //
10
- // Per (tenantId, entityName) eine optionale Override-Config die das
11
- // Preset (Layer 2) für genau diese eine Entity überschreibt. Use-Cases:
12
- // - Anwaltskanzlei in DE: caseFile 6y blockDelete (nicht im Preset)
13
- // - Pilot-Tenant der länger speichert für Test
14
- // - Branchenspezifische verkürzte Fristen
10
+ // One optional override config per (tenantId, entityName) replaces the
11
+ // preset (Layer 2) for that entity only. Use cases:
12
+ // - Law firm in DE: caseFile 6y blockDelete (not in the preset)
13
+ // - Pilot tenant retaining data longer for testing
14
+ // - Industry-specific shorter retention periods
15
15
  //
16
- // reason ist Pflicht — Audit für DPO + Aufsichtsbehörde nachvollziehbar.
16
+ // reason is required so the decision is auditable by the DPO and supervisory
17
+ // authorities.
17
18
  //
18
- // config ist JSON-String mit `{ keepFor, strategy, reference? }`. Zod-
19
- // Schema validiert beim set-override-Call (S2.D2 ggf. erweitert).
19
+ // config is a JSON string with `{ keepFor, strategy, reference? }`. The Zod
20
+ // schema validates it when set-override is called.
20
21
  //
21
- // Tenant-1-zu-N: pro Tenant beliebig viele Entity-Overrides. UNIQUE-
22
- // Index auf (tenantId, entityName) damit pro Entity max ein Override.
22
+ // Tenant one-to-many: each tenant can have any number of entity overrides.
23
+ // A UNIQUE index on (tenantId, entityName) allows at most one override per
24
+ // entity.
23
25
  export const tenantRetentionOverrideEntity = createEntity({
24
26
  table: "read_tenant_retention_overrides",
25
27
  fields: {
@@ -46,7 +46,7 @@ import {
46
46
  export type DeliveryFeatureOptions = {
47
47
  // Access gate for the delivery-log screen and the `log` query it reads —
48
48
  // both move together so the nav entry a role sees always matches a
49
- // callable handler (#2033). Default access.admin includes TenantAdmin,
49
+ // callable handler. Default access.admin includes TenantAdmin,
50
50
  // who in a line-of-business app is the operator, not the platform — pass
51
51
  // access.systemAdmin to keep this platform-only and out of their nav.
52
52
  readonly access?: readonly string[];
@@ -99,10 +99,10 @@ export function createDeliveryFeature(options?: DeliveryFeatureOptions): Feature
99
99
  // boot-validator accepts the projection below because at least one
100
100
  // apply-key is a registered domain-event (DELIVERY_ATTEMPT_EVENT).
101
101
  // recipientAddress is the real PII (email address); recipientId stays
102
- // plaintext — pseudonymous fk, same line as config.userId (#821).
102
+ // plaintext — pseudonymous fk, same line as config.userId.
103
103
  // recipientId is nullable (system-triggered sends to non-users), so the
104
104
  // address falls back to the tenant key instead of the plaintext it used
105
- // to be — still shreddable, one tenant wide (fw#2776).
105
+ // to be — still shreddable, one tenant wide.
106
106
  r.defineEvent("attempt", deliveryAttemptSchema, {
107
107
  piiFields: {
108
108
  recipientAddress: { personal: { of: "recipientId", whenAbsent: "tenant" } },
@@ -208,7 +208,7 @@ export const logQuery = definePagedQueryHandler({
208
208
  const nextCursor =
209
209
  rows.length === limit && lastRow ? encodeSortCursor(sortColumn, lastRow) : null;
210
210
 
211
- // recipientAddress is stored encrypted under the recipient's DEK (#799)
211
+ // recipientAddress is stored encrypted under the recipient's DEK
212
212
  // — decrypt for the admin log view; forgotten subjects show [[erased]].
213
213
  // The notificationType/recipientAddress → type/recipient rename happens
214
214
  // here, not in the client: a projectionList screen has no entity to
@@ -53,14 +53,15 @@ export const deliveryAttemptsTable = pgTable(
53
53
  (t) => [index(DELIVERY_ATTEMPTS_TENANT_CREATED_INDEX).on(t.tenantId, t.createdAt)],
54
54
  );
55
55
 
56
- // **Unmanaged table** — bewusst KEIN createEntity. Begründung:
57
- // - id kommt aus dem Aggregate-Stream (kein gen_random_uuid()-DEFAULT)
58
- // - kein version/inserted_by/modified_by/modified_at — keine in-place-
59
- // Edits, keine Audit-Spalten nötig (idempotent-on-replay via PK-Konflikt)
60
- // - created_at statt inserted_at — historischer Naming-Drift, kein Bug
61
- // App trägt Verantwortung für tenant-scoping in Queries + replay-idempotency.
62
- // pgTable bleibt source-of-truth für Query-API; Phase 4 leitet das pgTable
63
- // aus dieser Meta ab.
56
+ // **Unmanaged table** — deliberately has no createEntity because:
57
+ // - id comes from the aggregate stream (no gen_random_uuid()-DEFAULT)
58
+ // - no version/inserted_by/modified_by/modified_at: no in-place edits or
59
+ // audit columns are needed (idempotent-on-replay via PK conflict)
60
+ // - created_at rather than inserted_at reflects historical naming drift, not
61
+ // a bug
62
+ // The app is responsible for tenant scoping in queries and replay idempotency.
63
+ // pgTable remains the source of truth for the query API; the pgTable is derived
64
+ // from this metadata.
64
65
  export const deliveryAttemptsTableMeta: EntityTableMeta = defineUnmanagedTable({
65
66
  tableName: "store_delivery_attempts",
66
67
  indexes: [{ name: DELIVERY_ATTEMPTS_TENANT_CREATED_INDEX, columns: ["tenant_id", "created_at"] }],
@@ -31,13 +31,13 @@ const localeClaimSchema = z
31
31
  .regex(/^[A-Za-z]{2,3}(?:-[A-Za-z0-9]{1,8})*$/)
32
32
  .optional();
33
33
 
34
- // Shape des verified-JWT-payloads. tenantId kommt als string aus jose und
35
- // wird NACH erfolgreichem parse() zur Branded TenantId — kein blind-cast.
34
+ // Shape of verified JWT payloads. `tenantId` arrives from jose as a string and
35
+ // becomes a branded `TenantId` only after successful `parse()`—never via a blind cast.
36
36
  //
37
37
  // `kind` is explicitly typed as "absent or undefined, nothing else" here
38
38
  // (not bare `.optional()`, which would also accept any other value on an
39
- // unrelated key) so an address-token payload — which always carries
40
- // `kind: "address"` — fails this schema instead of silently parsing with
39
+ // unrelated key) so an address-token payload—which always carries
40
+ // `kind: "address"`—fails this schema instead of silently parsing with
41
41
  // `addressHash` mistaken for a userId.
42
42
  const unsubscribeJwtPayloadSchema = z.object({
43
43
  kind: z.undefined().optional(),
@@ -28,10 +28,9 @@ const executor = createEventStoreExecutor(
28
28
  { entityName: "notification-preference" },
29
29
  );
30
30
 
31
- // Konkretes Lookup-Result-Shape — nur die Felder die der upsert
32
- // tatsächlich für den Update-Path braucht. Vermeidet `row["x"] as T` index-
33
- // access casts; der Generic-Param am fetchOne macht den Cast zentralisiert
34
- // im Helper (db-row-boundary), nicht 4× pro Callsite.
31
+ // Concrete lookup result shape containing only the fields needed by the upsert update path. Avoids
32
+ // `row["x"] as T` index-access casts; the generic parameter on fetchOne centralizes the cast in the
33
+ // helper (`db-row-boundary`) instead of repeating it at each call site.
35
34
  type PreferenceLookupRow = {
36
35
  readonly id: string;
37
36
  readonly version: number;
@@ -6,7 +6,7 @@ import {
6
6
  createTextField,
7
7
  } from "@cosmicdrift/kumiko-framework/engine";
8
8
 
9
- // Phase-1 (MVP) page shape — LiteParse fills this in (kumiko-enterprise#273).
9
+ // (MVP) page shape — LiteParse fills this in.
10
10
  // Kept minimal on purpose: downstream themes (provider, recipe) extend it.
11
11
  // Stored as JSON.stringify(IngestPage[]) in the encrypted `pages` column —
12
12
  // jsonb has no encryption support in the engine, and this column holds the
@@ -29,7 +29,7 @@ export type DocumentExtractMeta = {
29
29
 
30
30
  // documentExtract — implicit entity-projection (r.entity, NOT r.projection):
31
31
  // an explicit r.projection would make `forget` non-rebuild-safe and require
32
- // archiveStream instead of the regular forget path (kumiko-framework#1495).
32
+ // archiveStream instead of the regular forget path.
33
33
  // fileRefId points at the source file_refs row; storageKey duplicates it for
34
34
  // direct provider access without a join.
35
35
  export const documentExtractEntity = createEntity({
@@ -42,11 +42,11 @@ export const documentExtractEntity = createEntity({
42
42
  reason: "technical_reference",
43
43
  }),
44
44
  // Holds the full extracted document text (PII). `personal: "tenant"`,
45
- // NOT `encrypted: true` (#1621): the master-key path has no erasure subject,
45
+ // NOT `encrypted: true`: the master-key path has no erasure subject,
46
46
  // so nothing here would ever be shreddable. Tenant-subject ciphertext
47
- // dies with eraseSubjectKeys on tenant-destroy (#800 pattern). Whose
47
+ // dies with eraseSubjectKeys on tenant-destroy. Whose
48
48
  // subject a third party named inside a document is stays open, same as
49
- // inbound-mail-foundation (#957). meta is provider telemetry only and
49
+ // inbound-mail-foundation. meta is provider telemetry only and
50
50
  // stays plaintext jsonb.
51
51
  pages: createLongTextField({
52
52
  personal: "tenant",
@@ -4,8 +4,8 @@ import * as z from "zod";
4
4
  // stream per fileRef with aggregateId derived from the fileRefId
5
5
  // (documentIngestAggregateId), never the fileRefId itself: foreign events on
6
6
  // the fileRef stream would break the fileRef's optimistic lock. Not backed by an r.entity;
7
- // this is a pure saga-anchor event (kumiko-framework#1497) that the Phase-2
8
- // worker job (kumiko-enterprise LiteParse provider) subscribes to.
7
+ // this is a pure saga-anchor event that the worker job (kumiko-enterprise LiteParse provider)
8
+ // subscribes to.
9
9
  export const DOCUMENT_INGEST_AGGREGATE_TYPE = "document-ingest";
10
10
 
11
11
  // Stream name of stored extract events; differs from the camelCase r.entity name
@@ -166,7 +166,7 @@ export function createDocumentIngestFoundationFeature() {
166
166
  default: "deu+eng",
167
167
  // Tesseract -l argument syntax: one or more 3-letter language codes
168
168
  // joined by "+" (e.g. "deu+eng"). Unconstrained free text here would
169
- // reach the OCR provider call unvalidated (#1501).
169
+ // reach the OCR provider call unvalidated.
170
170
  pattern: { regex: "^[a-z]{3}(\\+[a-z]{3})*$" },
171
171
  write: access.roles("TenantAdmin", "SystemAdmin"),
172
172
  read: access.roles("TenantAdmin", "SystemAdmin", "User"),
@@ -178,7 +178,7 @@ export function createDocumentIngestFoundationFeature() {
178
178
  default: 50,
179
179
  // Without a bound a tenant could set 0 (silently kills ingest) or an
180
180
  // unbounded value (OCR worker runs per-file for as long as the PDF
181
- // has pages — job-queue starvation) (#1501).
181
+ // has pages — job-queue starvation).
182
182
  bounds: { min: 1, max: 500 },
183
183
  write: access.roles("TenantAdmin", "SystemAdmin"),
184
184
  read: access.roles("TenantAdmin", "SystemAdmin", "User"),
@@ -2,7 +2,7 @@
2
2
  // longText (jsonb has no encryption support), so writers must persist
3
3
  // JSON.stringify(IngestPage[]) and readers must parse back. Centralising
4
4
  // the codec here keeps liteparse + recipe consumers lockstep with the
5
- // entity shape (kumiko-framework#1549/1).
5
+ // entity shape.
6
6
 
7
7
  import { isPlainObject } from "@cosmicdrift/kumiko-types/type-guards";
8
8
  import type { IngestPage } from "./entity.ts";
@@ -1,4 +1,4 @@
1
- // Tenant-destroy hook for the documentExtract entity-projection (#1621).
1
+ // Tenant-destroy hook for the documentExtract entity-projection.
2
2
  //
3
3
  // Per-row forget() through the executor, not a bulk deleteMany: documentExtract
4
4
  // is an ES-managed implicit projection, so a store-table write here would be
@@ -6,9 +6,9 @@
6
6
  // resurrect every row this hook removed. forget() (Art. 17 hard-purge) is
7
7
  // replayed by the implicit projection itself, which keeps the erasure
8
8
  // rebuild-safe — the same reasoning as tenant-lifecycle's membership stage,
9
- // and the reason the feature owns an r.entity instead of an r.projection
10
- // (kumiko-framework#1495). The `pages` ciphertext dies separately when the
11
- // pipeline's later `subject-keys` stage erases the tenant subject key.
9
+ // and the reason the feature owns an r.entity instead of an r.projection.
10
+ // The `pages` ciphertext dies separately when the pipeline's later
11
+ // `subject-keys` stage erases the tenant subject key.
12
12
 
13
13
  import { createSystemUser, type TenantDataDestroyHook } from "@cosmicdrift/kumiko-framework/engine";
14
14
  import { documentExtractsTable } from "./entity.ts";
@@ -66,7 +66,7 @@ export function composeTierResolverWithGlobalToggles(
66
66
  // Non-toggleable (always-on) names must keep reaching `result` through the
67
67
  // globalCascade loop below even if this resolver's SYSTEM_TENANT_ID answer
68
68
  // satisfies the emptiness guard above without also merging always-on into
69
- // every per-tenant tierSet (framework#1528).
69
+ // every per-tenant tierSet.
70
70
  tierManaged = new Set(
71
71
  [...managed].filter((name) => {
72
72
  const feature = registry.getFeature(name);