@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,16 +1,15 @@
1
1
  import { v5 as uuidv5 } from "uuid";
2
2
 
3
- // Fixed UUID-namespace für die cap-counter-aggregate-id-Ableitung.
4
- // Generiert einmalig (2026-05-02), in Stein gemeißelt: ein Wechsel würde
5
- // jeden existing aggregate-Stream re-keyen → kaputter event-replay,
6
- // kaputte counter-history, verlorener Audit-Trail. Drift-Pin in
7
- // __tests__/drift.test.ts pinnt den UUID-Wert.
3
+ // Fixed UUID namespace for deriving cap-counter aggregate IDs.
4
+ // Generated once (2026-05-02) and immutable: changing it would re-key every
5
+ // existing aggregate stream, breaking event replay and counter history and
6
+ // losing the audit trail. The drift test in __tests__/drift.test.ts pins the UUID.
8
7
  const CAP_COUNTER_NAMESPACE = "9c1bf2a3-6e4d-4f5b-8a9c-2d3e4f5a6b7c";
9
8
 
10
- // Separater Namespace für Rolling-Window-Counter (Sprint 4). Eigener
11
- // Namespace damit das aggregate-id NIE mit einem Calendar-Counter
12
- // kollidiert, selbst wenn jemand "1970-01-01..." als periodStart in
13
- // den Calendar-Pfad reinpasst. Drift-Pin in __tests__/drift.test.ts.
9
+ // Separate namespace for rolling-window counters. This prevents the aggregate ID
10
+ // from colliding with a calendar counter, even if "1970-01-01..." is passed as
11
+ // periodStart through the calendar path. The drift test in __tests__/drift.test.ts
12
+ // pins the UUID.
14
13
  const CAP_COUNTER_ROLLING_NAMESPACE = "8b2ad0c6-1f3e-4f7c-9b8a-3c4d5e6f7a8b";
15
14
 
16
15
  /**
@@ -3,20 +3,19 @@ export const CAP_COUNTER_FEATURE = "cap-counter" as const;
3
3
 
4
4
  export const CAP_COUNTER_LIST_SCREEN_ID = "cap-list" as const;
5
5
 
6
- // Aggregate types — calendar-period-Counter benutzt CRUD-Events der
7
- // projection-row. Rolling-Window-Counter benutzt einen eigenen
8
- // aggregate-type mit custom increment-events (no projection — der
9
- // Read summiert über die letzten N Tage Events). Sind getrennt damit
10
- // die r.entity-projection nicht auch noch rolling-counter-rows tracken
11
- // muss.
6
+ // Aggregate types: calendar-period counters use CRUD events for the
7
+ // projection row. Rolling-window counters use a separate aggregate type
8
+ // with custom increment events (no projection—the read sums events from
9
+ // the last N days). They are separate so `r.entity-projection` does not
10
+ // also have to track rolling-counter rows.
12
11
  export const CAP_COUNTER_ROLLING_AGGREGATE_TYPE = "cap-counter-rolling" as const;
13
12
 
14
- // Custom event-type für Rolling-Window-Counter. Symmetrisches Paar:
15
- // _SHORT — passt zu `r.defineEvent(short, schema)` im Registrar
16
- // (Framework prefixt automatisch zu QN)
17
- // _QN — qualifizierte Form für `ctx.unsafeAppendEvent({type})`
18
- // + `events.type`-Spalte + `registry.getEvent(qn)`-Lookup
19
- // Beide MÜSSEN konsistent sein (drift-pin im feature-test).
13
+ // Custom event types for rolling-window counters. The pair is symmetric:
14
+ // _SHORT — matches `r.defineEvent(short, schema)` in the registrar
15
+ // (the framework automatically prefixes it to the QN)
16
+ // _QN — qualified form for `ctx.unsafeAppendEvent({type})`, the
17
+ // `events.type` column, and `registry.getEvent(qn)` lookups
18
+ // Both MUST stay consistent; the feature test pins against drift.
20
19
  export const ROLLING_INCREMENTED_EVENT_SHORT = "rolling-incremented" as const;
21
20
  export const ROLLING_INCREMENTED_EVENT_QN = "cap-counter:event:rolling-incremented" as const;
22
21
 
@@ -16,16 +16,14 @@ const { table } = createEntityExecutor("cap-counter", capCounterEntity);
16
16
  // =============================================================================
17
17
 
18
18
  /**
19
- * Cap-Toleranz-Profile — pro Cap-Typ asymmetrisch. Quelle: Memory
20
- * `project_pricing_byok_caps` §3 + `docs/plans/marketing/produkt/
21
- * pricing.md` Cap-Verhalten-Block.
19
+ * Cap-tolerance profiles, asymmetric by cap type.
22
20
  *
23
- * **Soft** = Notification-Schwelle (Multiplier × Limit). Bei
24
- * Erreichen wird einmalig gewarnt (lastSoftWarnedAt setzt das Flag).
25
- * Caller-Code emittiert die echte Notification.
21
+ * **Soft** = notification threshold (multiplier × limit). Once reached,
22
+ * a warning is issued (`lastSoftWarnedAt` sets the flag); caller code emits
23
+ * the actual notification.
26
24
  *
27
- * **Hard** = Schreibe-Block (Multiplier × Limit). enforceCap throwt
28
- * mit `cap_exceeded`-Error → Dispatcher mapped 429 + Upgrade-Hint.
25
+ * **Hard** = write-block threshold (multiplier × limit). `enforceCap` throws
26
+ * a `cap_exceeded` error, which the dispatcher maps to 429 with an upgrade hint.
29
27
  */
30
28
  export type CapToleranceProfile = {
31
29
  readonly soft: number;
@@ -33,13 +31,13 @@ export type CapToleranceProfile = {
33
31
  };
34
32
 
35
33
  export const CAP_TOLERANCES = {
36
- /** Mails / Tokens — billig, BYOK ab Pro. Burst-Buffer großzügig. */
34
+ /** Mails / tokens — inexpensive, with BYOK available from Pro. Generous burst buffer. */
37
35
  burstable: { soft: 1.1, hard: 1.2 },
38
36
  /** DB-Storage / File-Storage — teuer + persistent. Strikter Cut. */
39
37
  storage: { soft: 1.0, hard: 1.05 },
40
- /** Apps-Count, Plattform-Slots — gebuchte Kapazität, kein Buffer. */
38
+ /** App count and platform slots — purchased capacity, with no buffer. */
41
39
  hardSlot: { soft: 1.0, hard: 1.0 },
42
- /** Egress — Bursty-Traffic legitim, nur extreme Spikes blockieren. */
40
+ /** Egress — bursty traffic is legitimate; only extreme spikes are blocked. */
43
41
  egress: { soft: 1.1, hard: 1.3 },
44
42
  } as const satisfies Readonly<Record<string, CapToleranceProfile>>;
45
43
 
@@ -176,28 +174,26 @@ export async function enforceCap(
176
174
  // =============================================================================
177
175
 
178
176
  /**
179
- * Synchronous read-and-check of the calling tenant's Rolling-Window-
180
- * Counter for `capName`. Reads the increment-events of the last
181
- * `windowDays` from the event-store and sums their `amount`. Returns:
177
+ * Synchronous read-and-check of the calling tenant's rolling-window
178
+ * counter for `capName`. Reads increment events from the last
179
+ * `windowDays` in the event store and sums their `amount`. Returns:
182
180
  * - "ok" when sum < soft-threshold
183
181
  * - "soft-hit" when soft ≤ sum < hard.
184
182
  *
185
183
  * **Throws** `CapExceededError` when sum ≥ hard-threshold.
186
184
  *
187
- * **`crossed`-flag fehlt absichtlich:** Anders als der Calendar-
188
- * Counter hat das Rolling-Aggregate keine projection-row mit
189
- * `lastSoftWarnedAt`-Flag. Dedup gegen Notification-Storm passiert
190
- * im Caller (eigener key in einer Cache-Tabelle, oder einfache
191
- * memoization für die Lebensdauer des Request). Der Result-Shape
192
- * matcht trotzdem `EnforceCapResult` damit der gleiche Caller-Code
193
- * gegen beide Funktionen funktioniert; `crossed` ist hier immer
194
- * `false` (= "wir tracken's nicht").
185
+ * **The `crossed` flag is intentionally absent:** Unlike the calendar
186
+ * counter, the rolling aggregate has no projection row with a
187
+ * `lastSoftWarnedAt` flag. The caller must deduplicate notification storms
188
+ * using its own mechanism, such as a cache-table key or request-lifetime
189
+ * memoization. The result shape still matches `EnforceCapResult` so the same
190
+ * caller code works with both functions; `crossed` is always `false` here
191
+ * (= "not tracked").
195
192
  *
196
- * **Performance-Note:** der Read summiert ALLE Events im Window für
197
- * (tenant, capName). Bei 10k+ Events/Tenant in der Window könnte
198
- * das langsam werden — dann Migration auf eine Multi-Stream-
199
- * Projection mit pre-aggregierten daily-buckets. Heute nicht
200
- * vorgezogen.
193
+ * **Performance note:** The read sums ALL events in the window for
194
+ * (tenant, capName). With 10k+ events per tenant in the window, this could
195
+ * become slow; migrate to a multi-stream projection with pre-aggregated
196
+ * daily buckets if needed.
201
197
  */
202
198
  export async function enforceRollingCap(
203
199
  ctx: CapCounterContext,
@@ -324,20 +320,20 @@ export function calendarMonthPeriodEndIso(periodStartIso: string): string {
324
320
  }
325
321
 
326
322
  // =============================================================================
327
- // Notification-Wiring helpers — convenience-wrapper für enforceCap +
328
- // enforceRollingCap, die einen Caller-supplied delivery-emit beim
329
- // soft-hit-crossing ausführen. Cap-counter kennt delivery-feature
330
- // nicht direkt — der Caller injiziert den emitter.
323
+ // Notification-wiring helpers — convenience wrappers for `enforceCap` and
324
+ // `enforceRollingCap` that execute a caller-supplied delivery emitter when
325
+ // a soft-hit threshold is crossed. The cap counter does not know about the
326
+ // delivery feature directly; the caller injects the emitter.
331
327
  // =============================================================================
332
328
 
333
329
  /**
334
- * Soft-hit-notifier callback. Caller liefert die Funktion die ein
335
- * delivery-event emittet (z.B. `delivery.send({to, template, payload})`).
336
- * Wird genau einmal pro Period beim Calendar-Counter aufgerufen
337
- * (`crossed === true` deduplicated via `markSoftWarnedHandler`).
330
+ * Soft-hit notifier callback. The caller supplies the function that emits
331
+ * a delivery event (for example, `delivery.send({to, template, payload})`).
332
+ * It is called exactly once per period for the calendar counter
333
+ * (`crossed === true`, deduplicated via `markSoftWarnedHandler`).
338
334
  *
339
- * Beim Rolling-Counter ist `crossed` immer `false` — der Caller muss
340
- * dort selbst dedup'en (oder bewusst pro request feuern lassen).
335
+ * For the rolling counter, `crossed` is always `false`; the caller must
336
+ * deduplicate notifications itself or intentionally send one per request.
341
337
  */
342
338
  export type SoftHitNotifier = (info: {
343
339
  readonly capName: string;
@@ -347,14 +343,14 @@ export type SoftHitNotifier = (info: {
347
343
  }) => Promise<void> | void;
348
344
 
349
345
  /**
350
- * Calendar-Period-enforcement + automatische soft-hit-Notification.
351
- * Ruft `enforceCap`, bei `crossed: true` den Notifier UND
352
- * `mark-soft-warned`-Handler (flippt `lastSoftWarnedAt` damit der
353
- * nächste Aufruf in derselben Period nicht erneut feuert).
346
+ * Calendar-period enforcement with automatic soft-hit notification.
347
+ * Calls `enforceCap`; when `crossed: true`, it calls the notifier and the
348
+ * `mark-soft-warned` handler, which flips `lastSoftWarnedAt` so that the
349
+ * same period does not trigger another notification.
354
350
  *
355
- * Returnt das `EnforceCapResult` weiter — Caller kann die Logik
356
- * verzweigen (z.B. UI-Toast bei soft-hit zusätzlich zur
357
- * Email-Notification).
351
+ * Returns the `EnforceCapResult` unchanged, allowing the caller to branch
352
+ * on the result, such as showing a UI toast in addition to the email
353
+ * notification.
358
354
  */
359
355
  export async function enforceCapAndMaybeNotify(
360
356
  ctx: CapCounterContext,
@@ -400,14 +396,14 @@ export async function enforceCapAndMaybeNotify(
400
396
  }
401
397
 
402
398
  /**
403
- * Rolling-Window-enforcement + immer-feuert-Notification beim soft-hit.
399
+ * Rolling-window enforcement that always sends a notification on a soft hit.
404
400
  *
405
- * **Achtung Storm-Risk:** Rolling-Counter trackt `lastSoftWarnedAt`
406
- * NICHT (kein projection-row). Bei jedem Aufruf während der Counter
407
- * im soft-Bereich ist, feuert der notifier. Der Caller muss
408
- * dedup'en — z.B. via Cache-Eintrag `lastNotified[capName]` mit TTL,
409
- * oder er ruft `enforceRollingCapAndMaybeNotify` nur einmal pro
410
- * Tag/Stunde auf (Hourly-Cron statt pro Request).
401
+ * **Storm risk:** The rolling counter does NOT track `lastSoftWarnedAt`
402
+ * (there is no projection row). On every call while the counter is in the
403
+ * soft range, the notifier fires. The caller must deduplicate, for example
404
+ * with a cache entry `lastNotified[capName]` and a TTL, or call
405
+ * `enforceRollingCapAndMaybeNotify` only once per day or hour
406
+ * (an hourly cron instead of per request).
411
407
  */
412
408
  export async function enforceRollingCapAndMaybeNotify(
413
409
  ctx: CapCounterContext,
@@ -439,7 +435,7 @@ export async function enforceRollingCapAndMaybeNotify(
439
435
  }
440
436
 
441
437
  // =============================================================================
442
- // Stock-Cap (Bestand) — live-gezählte Kardinalität gegen Tier-Limit
438
+ // Stock cap — live-counted cardinality checked against the tier limit
443
439
  // =============================================================================
444
440
 
445
441
  export type StockCapResult =
@@ -447,24 +443,25 @@ export type StockCapResult =
447
443
  | { readonly state: "exceeded"; readonly current: number; readonly limit: number };
448
444
 
449
445
  /**
450
- * Stock-Cap: prüft eine vom Caller LIVE gezählte Kardinalität (z.B. Anzahl
451
- * existierender Components eines Tenants) gegen ein Tier-Limit.
446
+ * Stock cap: checks a cardinality counted LIVE by the caller (for example,
447
+ * the number of existing components for a tenant) against a tier limit.
452
448
  *
453
- * Anders als {@link enforceCap}/{@link enforceRollingCap} gibt es KEINEN
454
- * gespeicherten Counter: der Caller zählt die Projektion selbst
455
- * (`count(*) WHERE tenant_id = …`) und übergibt `current`. Das ist drift-frei
456
- * (ein Delete gibt den Slot sofort frei), braucht keine Counter-Tabelle und
457
- * kein Increment/Decrement-Bookkeeping. Misst einen Bestand, keinen Fluss.
449
+ * Unlike {@link enforceCap}/{@link enforceRollingCap}, there is NO stored
450
+ * counter: the caller counts the projection itself
451
+ * (`count(*) WHERE tenant_id = …`) and passes `current`. This avoids drift
452
+ * (a delete immediately frees the slot), requires no counter table or
453
+ * increment/decrement bookkeeping, and measures a stock rather than a flow.
458
454
  *
459
- * **TOCTOU-Caveat:** Zählen und Schreiben sind nicht atomar — zwei parallele
460
- * Creates können beide `ok` sehen und das Limit um eins überschreiten (gleiche
461
- * Race wie bei {@link enforceCap}). Exakt harte Slots brauchen zusätzliche
462
- * Serialisierung im Create-Pfad (z.B. Unique-Index auf tenantId+slot).
455
+ * **TOCTOU caveat:** Counting and writing are not atomic—two concurrent
456
+ * creates can both see `ok` and exceed the limit by one (the same race as
457
+ * with {@link enforceCap}). Strictly hard slots need additional
458
+ * serialization in the create path, such as a unique index on
459
+ * tenantId+slot.
463
460
  *
464
- * Reine Funktion — wirft NICHT und mappt KEINEN HTTP-Status. Ein erreichtes
465
- * Stock-Limit heißt „Upgrade nötig", nicht „retry later" (429): der Caller
466
- * entscheidet die Reaktion, typisch ein app-eigener 422/`upgrade_required`
467
- * mit i18n. Mit `hardSlot` (soft=hard=1.0) ist die Grenze exakt `limit`.
461
+ * Pure function—it does NOT throw or map an HTTP status. Reaching a stock
462
+ * limit means "upgrade required", not "retry later" (429); the caller
463
+ * chooses the response, typically an app-specific 422/`upgrade_required`
464
+ * with i18n. With `hardSlot` (soft=hard=1.0), the boundary is exactly `limit`.
468
465
  */
469
466
  export function enforceStockCap(options: {
470
467
  readonly current: number;
@@ -5,38 +5,38 @@ import {
5
5
  createTimestampField,
6
6
  } from "@cosmicdrift/kumiko-framework/engine";
7
7
 
8
- // cap-counter — eine Row pro (tenantId, capName, periodStart). tenantId
9
- // kommt automatisch als Base-Column (Kumiko Multi-Tenant-Default).
8
+ // cap-counter — one row per (tenantId, capName, periodStart). tenantId
9
+ // is added automatically as a base column (Kumiko multi-tenant default).
10
10
  //
11
- // **Identity-Modell:**
12
- // - aggregate-id: UUID (Kumiko-ES-Pflicht)
13
- // - public natural-key: (tenantId, capName, periodStart) — die Counter-
14
- // Engine nutzt deterministic uuidv5 daraus, damit Increments gegen
15
- // denselben Stream gehen statt zwei Rows pro Tenant+Cap zu erzeugen
11
+ // **Identity model:**
12
+ // - aggregate-id: UUID (required by Kumiko ES)
13
+ // - public natural key: (tenantId, capName, periodStart) — the counter
14
+ // engine derives a deterministic uuidv5 from it so increments use the
15
+ // same stream instead of creating two rows per tenant and cap
16
16
  //
17
- // **Felder:**
18
- // - capName: das Domain-Konzept ("platform-mails", "ai-tokens-7day",
19
- // "db-storage-bytes"). Frei-form String — die App definiert ihre
20
- // Cap-Names, die Engine kennt sie nicht enumerated.
21
- // - value: aktueller Counter-Wert. Tokens, MB, Anzahl etc — Einheit
22
- // ist app-Sache, die Engine zählt nur Zahlen.
23
- // - periodStart: Timestamp wann das aktuelle Counter-Period begann.
24
- // Calendar-Month-Reset setzt einen neuen periodStart (= neue Aggregate-
25
- // Identität). Rolling-Window (z.B. KI-Tokens 7-day) setzt periodStart
26
- // einfach nicht zurück und filtert beim Read mit `WHERE timestamp >
27
- // now() - 7d` über den Event-Store-Stream — das ist Caller-Sache.
28
- // - lastSoftWarnedAt: Anti-Notification-Storm. Wenn Soft-Cap @ 110%
29
- // einmal erreicht ist, soll nicht jeder Folge-Increment eine Mail an
30
- // den Admin schicken. Pro Period maximal eine Soft-Warning, daher
31
- // diese Spalte; nullable, wird beim Reset auf null zurückgesetzt.
17
+ // **Fields:**
18
+ // - capName: the domain concept ("platform-mails", "ai-tokens-7day",
19
+ // "db-storage-bytes"). Free-form string — the app defines its cap
20
+ // names; the engine does not enumerate them.
21
+ // - value: the current counter value. Tokens, MB, count, etc. — the unit
22
+ // belongs to the app; the engine only counts numbers.
23
+ // - periodStart: timestamp when the current counter period began.
24
+ // A calendar-month reset sets a new periodStart (= new aggregate
25
+ // identity). A rolling window (e.g. AI tokens over 7 days) does not
26
+ // reset periodStart and filters on read with `WHERE timestamp >
27
+ // now() - 7d` over the event-store stream — this is the caller's
28
+ // responsibility.
29
+ // - lastSoftWarnedAt: prevents notification storms. Once the soft cap at
30
+ // 110% is reached, subsequent increments must not each send an email to
31
+ // the admin. There is at most one soft warning per period, so this
32
+ // nullable column is reset to null when the period resets.
32
33
  //
33
- // **Was bewusst NICHT in der Entity steht:**
34
- // - softLimit / hardLimit / cap-toleranz-multipliers — die kommen aus
35
- // der App-TierMap zur enforceCap-Aufruf-Zeit. Counter weiß nichts
36
- // vom Tier, nur von "wie viele zähle ich".
37
- // - userId / aggregate-Reference — Counter sind Plattform-Tenant-
38
- // scoped, nicht User-scoped (auch wenn ein User den Increment
39
- // auslöst).
34
+ // **What is intentionally not in the entity:**
35
+ // - softLimit / hardLimit / cap-tolerance multipliers — these come from
36
+ // the app's tier map when enforceCap is called. The counter knows
37
+ // nothing about the tier, only how much is being counted.
38
+ // - userId / aggregate reference — counters are scoped to the platform
39
+ // tenant, not to a user (even when a user triggers the increment).
40
40
  export const capCounterEntity = createEntity({
41
41
  table: "read_cap_counters",
42
42
  description:
@@ -1,49 +1,48 @@
1
- // cap-counter — Counter-Storage + Increment-API + Soft-Warn-State.
1
+ // cap-counter — Counter Storage + Increment API + Soft-Warn State.
2
2
  //
3
- // **Was diese Feature liefert:**
4
- // 1. r.entity({ name: "cap-counter" }) — Counter-Rows pro (tenant, capName,
5
- // period) für Calendar-Period-Caps (Mails/Monat, Egress/Monat).
6
- // 2. increment-Handler — atomic counter increment via deterministic
7
- // aggregate-id (try-create / executor-update). Race-frei via
8
- // event-store optimistic-lock.
9
- // 3. increment-rolling-Handler (Sprint 4) — append-only Custom-Event-
10
- // Stream für Rolling-Window-Caps (KI-Tokens-7d, Egress-24h). Kein
11
- // projection — der Wert kommt im Read aus dem Event-Stream.
12
- // 4. mark-soft-warned-Handler — flippt das Anti-Notification-Storm-
13
- // Flag (nur Calendar-Period-Counter).
14
- // 5. get-counter-Query — sync read der aktuellen Counter-Value
15
- // (Calendar).
16
- // 6. enforceCap + enforceRollingCap-Helper (siehe enforce-cap.ts) —
17
- // Pre-Save-Wrapper mit asymmetrischen Soft/Hard-Toleranzen pro
18
- // Cap-Profile.
3
+ // **What this feature provides:**
4
+ // 1. r.entity({ name: "cap-counter" }) — counter rows per (tenant, capName,
5
+ // period) for calendar-period caps (mail/month, egress/month).
6
+ // 2. increment handler — atomic counter increment via deterministic
7
+ // aggregate-id (try-create / executor-update), made race-free by the
8
+ // event-store optimistic lock.
9
+ // 3. increment-rolling handler — append-only custom-event stream for
10
+ // rolling-window caps (AI-tokens-7d, egress-24h). No projection; the
11
+ // value is read from the event stream.
12
+ // 4. mark-soft-warned handler — flips the anti-notification-storm flag
13
+ // (calendar-period counters only).
14
+ // 5. get-counter query — synchronous read of the current counter value
15
+ // (calendar period).
16
+ // 6. enforceCap + enforceRollingCap helpers (see enforce-cap.ts) —
17
+ // pre-save wrappers with asymmetric soft and hard tolerances per
18
+ // cap profile.
19
19
  //
20
- // **Calendar vs. Rolling — when to use which:**
20
+ // **Calendar vs. rolling — when to use which:**
21
21
  // - **Calendar period** (bookCapUsage + enforceCap): the cap resets at
22
- // period start (1st of the month etc.). The counter is one row in the
23
- // projection. Fast read.
22
+ // period start (the first of the month, etc.). The counter is one row in
23
+ // the projection, enabling fast reads.
24
24
  // - **Rolling window** (CapCounterHandlers.incrementRolling + enforceRollingCap):
25
- // the cap rolls continuously (e.g. "last 7 days"). Values expire
26
- // event by event without a reset. No projection; the read sums the
27
- // events of the last N days.
25
+ // the cap rolls continuously (e.g. "last 7 days"). Values expire event
26
+ // by event without a reset. There is no projection; reads sum the events
27
+ // from the last N days.
28
28
  //
29
29
  // **What this feature does NOT do:**
30
30
  // - **No foundation wiring.** mail-foundation / file-foundation /
31
- // ai-foundation are BYOK by default today and have no platform pool
31
+ // ai-foundation are BYOK by default and currently have no platform pool
32
32
  // to count. cap-counter is generic: an app owner who wants to use the
33
33
  // counter calls `bookCapUsage(...)` /
34
34
  // `ctx.write(CapCounterHandlers.incrementRolling, ...)` from their own handler.
35
- // - **No reset cron for the calendar period.** Works without one: the
36
- // periodStartIso part of the aggregate id rolls over to a fresh
37
- // counter at the period tick. Old rows stay for audit.
38
- // - **Kein Notification-Pfad als Hard-Wiring.** Cap-counter
39
- // entkoppelt — `enforceCapAndMaybeNotify` (siehe enforce-cap.ts)
40
- // ist ein Convenience-Helper, der einen Caller-supplied
41
- // emit-Callback ausführt; cap-counter kennt delivery-feature
42
- // nicht direkt.
35
+ // - **No reset cron for the calendar period.** It works without one: the
36
+ // periodStartIso part of the aggregate id rolls over to a fresh counter
37
+ // at the period boundary. Old rows remain for auditing.
38
+ // - **No notification path is hard-wired.** cap-counter is decoupled —
39
+ // `enforceCapAndMaybeNotify` (see enforce-cap.ts) is a convenience helper
40
+ // that invokes a caller-supplied emit callback; cap-counter does not know
41
+ // the delivery feature directly.
43
42
  //
44
- // **Boot-Dependencies:** keine. cap-counter ist Plain-Vanilla — kein
45
- // config, kein secrets, kein tenant-feature nötig. Tenant-Scoping kommt
46
- // vom Framework-Default (Base-Column tenantId).
43
+ // **Boot dependencies:** none. cap-counter is plain vanilla — it needs no
44
+ // config, secrets, or tenant feature. Tenant scoping comes from the framework
45
+ // default (Base-Column tenantId).
47
46
 
48
47
  import {
49
48
  access,
@@ -1,22 +1,21 @@
1
- // increment-rolling — Rolling-Window-Counter-Increment via Custom-
2
- // Event statt CRUD/projection. Designed für Caps deren Wert sich
3
- // kontinuierlich erneuern soll (KI-Tokens-7-Tage, Egress pro 24h).
1
+ // increment-rolling — Rolling-window counter increment via a custom
2
+ // event instead of CRUD/projection. Designed for caps whose values
3
+ // continuously renew (AI tokens over 7 days, egress over 24 hours).
4
4
  //
5
- // **Warum kein r.entity / CRUD wie der Calendar-Counter:** Der
6
- // Calendar-Counter speichert den kumulierten value in seiner
7
- // projection-row. Beim Period-Rollover wechselt die aggregate-id auf
8
- // den neuen Period-Start, das ist der "Reset". Bei Rolling-Window
9
- // gibt es keinen Rollover-Punkt — der Counter "rollt" kontinuierlich
10
- // raus. Ein einzelner kumulativer value wäre falsch (würde monoton
11
- // wachsen ohne Expiration). Die korrekte Read-Semantik ist: SUM aller
12
- // Increment-Amounts der letzten N Tage. Dafür brauchen wir die
13
- // einzelnen Increments als separate Events mit ihrem eigenen
14
- // `amount`-Feld; CRUD-Events tragen nur den kumulativen value.
5
+ // **Why not r.entity / CRUD like the calendar counter:** The calendar
6
+ // counter stores the cumulative value in its projection row. At the
7
+ // period rollover, the aggregate ID changes to the new period start;
8
+ // that is the "reset". A rolling window has no rollover point—the
9
+ // counter continuously rolls out. A single cumulative value would be
10
+ // incorrect because it would grow monotonically without expiration.
11
+ // The correct read semantics are SUM of all increment amounts from the
12
+ // last N days. Therefore, each increment must be a separate event with
13
+ // its own `amount` field; CRUD events carry only the cumulative value.
15
14
  //
16
- // **Aggregate-Stream:** ein Stream pro (tenant, capName) — siehe
17
- // `rollingCapAggregateId`. Alle Increments hängen am selben Stream
18
- // in monoton-steigender version. enforceRollingCap liest die letzten
19
- // N Tage aus diesem Stream.
15
+ // **Aggregate stream:** one stream per (tenant, capName)—see
16
+ // `rollingCapAggregateId`. All increments use the same stream in
17
+ // monotonically increasing version order. enforceRollingCap reads the
18
+ // last N days from this stream.
20
19
 
21
20
  import type { WriteHandlerDef } from "@cosmicdrift/kumiko-framework/engine";
22
21
  import * as z from "zod";
@@ -33,8 +32,8 @@ const incrementRollingSchema = z.object({
33
32
  });
34
33
  type IncrementRollingPayload = z.infer<typeof incrementRollingSchema>;
35
34
 
36
- /** Schema des emittierten Custom-Events. Identisch zum Input-Schema:
37
- * der Caller zahlt amount, wir hängen es 1:1 an den Stream. */
35
+ /** Schema of the emitted custom event. Identical to the input schema:
36
+ * the caller supplies amount, which we append unchanged to the stream. */
38
37
  export const rollingIncrementedSchema = incrementRollingSchema;
39
38
 
40
39
  /** Payload of the event that gives a reserved rolling amount back. */
@@ -44,27 +43,28 @@ export const rollingReleasedSchema = incrementRollingSchema.extend({
44
43
  incrementedAt: z.string().optional(),
45
44
  });
46
45
 
47
- // Rolling-Increment-Handler — append-only. Race-frei: zwei parallele
48
- // Increments für (tenant, cap) hängen sich am selben aggregate-stream
49
- // in unterschiedlichen versions auf, das event-store ordert.
46
+ // Rolling-increment handler — append-only. Race-free: two parallel
47
+ // increments for (tenant, cap) attach to the same aggregate stream at
48
+ // different versions, and the event store orders them.
50
49
  //
51
- // **Kein version_conflict-Pfad** wie beim Calendar-Counter: hier
52
- // liest niemand den projection-state vor dem Schreiben. Der
53
- // expectedVersion ist implizit "next-after-current", was der event-
54
- // store atomar ermittelt.
50
+ // **No version_conflict path** as with the calendar counter: nothing
51
+ // reads projection state before writing. The expectedVersion is
52
+ // implicitly "next-after-current", which the event store determines
53
+ // atomically.
55
54
  export const incrementRollingCapHandler: WriteHandlerDef = {
56
55
  name: "increment-rolling",
57
56
  agent: { expose: false },
58
57
  schema: incrementRollingSchema,
59
- // Internal handler — System-Caller (Plattform-foundations nach
60
- // erfolgreichem Side-Effect) ruft das auf. Tenant-end-users niemals
61
- // direkt. Audit-row zeigt welche subsystem-call-site zugehängt hat.
58
+ // Internal handler — a system caller (platform foundations after a
59
+ // successful side effect) invokes it. Tenant end users must never
60
+ // call it directly. The audit row shows which subsystem call site
61
+ // attached the operation.
62
62
  access: { roles: ["SystemAdmin"] },
63
63
  handler: async (event, ctx) => {
64
64
  // @cast-boundary engine-payload — dispatcher hands handler the
65
65
  // already-Zod-validated payload as `unknown`; cast to the typed
66
- // shape we declared via incrementRollingSchema. Mirror der
67
- // existing increment.write.ts-Cast — gleiche dispatcher-boundary.
66
+ // shape declared via incrementRollingSchema. Mirror the cast in
67
+ // existing increment.write.ts—the same dispatcher boundary.
68
68
  const payload = event.payload as IncrementRollingPayload;
69
69
  const aggregateId = rollingCapAggregateId(event.user.tenantId, payload.capName);
70
70
 
@@ -4,12 +4,11 @@ import { markCapSoftWarned } from "../book-cap-usage.ts";
4
4
 
5
5
  // mark-soft-warned — sets lastSoftWarnedAt on the counter so subsequent
6
6
  // soft-cap-hits in the same period don't re-trigger notifications.
7
- // Anti-Notification-Storm-Schutz aus Memory `project_pricing_byok_caps`.
7
+ // This prevents notification storms.
8
8
  //
9
- // **Caller-Pattern:** enforceCap-Helper checks if value crosses the
10
- // soft threshold AND lastSoftWarnedAt is null → calls this handler →
11
- // emits whatever notification (delivery-feature, ops-alert, etc.). The
12
- // emit-side is app-specific; this handler only sets the flag.
9
+ // **Caller pattern:** enforceCap-Helper checks whether the value crosses the
10
+ // soft threshold while lastSoftWarnedAt is null, then calls this handler and
11
+ // emits the application-specific notification. This handler only sets the flag.
13
12
  const markSoftWarnedSchema = z.object({
14
13
  capName: z.string().min(1).max(100),
15
14
  periodStartIso: z.string().min(1),
@@ -1,5 +1,5 @@
1
1
  // Generic stock-cap write-guard factory. Extracted from the near-identical
2
- // cap-guard.ts app copies in show-pony and publicstatus (infra#446) — the
2
+ // cap-guard.ts app copies in show-pony and publicstatus — the
3
3
  // only per-app variable was the Caps shape and how to resolve it for a
4
4
  // tenant, so both are now factory parameters.
5
5
 
@@ -44,11 +44,9 @@ import { chainReservations } from "./reservation-chain.ts";
44
44
  // =============================================================================
45
45
 
46
46
  /**
47
- * Pro-call dynamische Cap-Definition. Wird vor jedem Handler-Aufruf
48
- * neu evaluiert — typischer Caller liest hier den Tenant-Tier aus
49
- * dem ctx, mappt ihn auf einen Limit-Wert. `amount` default 1 (count-
50
- * events); für byte/token-cap übergibt der Caller die Größe aus
51
- * `event.payload`.
47
+ * Dynamic cap definition resolved for each handler invocation. A typical caller reads the tenant
48
+ * tier from `ctx` and maps it to a limit. `amount` defaults to 1 (counting events); for byte or
49
+ * token caps, the caller supplies the size from `event.payload`.
52
50
  */
53
51
  export type CalendarCapDef = {
54
52
  readonly capName: string;
@@ -3,7 +3,6 @@ import {
3
3
  defineQueryHandler,
4
4
  mayOverrideTenant,
5
5
  type QueryHandlerDefinition,
6
- type TenantId,
7
6
  } from "@cosmicdrift/kumiko-framework/engine";
8
7
  import {
9
8
  AccessDeniedError,
@@ -77,8 +76,7 @@ export function createCapsUsageQuery(
77
76
 
78
77
  // Override path: limits must read the TARGET tenant's config, not the
79
78
  // SystemAdmin caller's.
80
- const config =
81
- override === undefined ? ctx.config : ctx.configFor?.(targetTenantId as TenantId);
79
+ const config = override === undefined ? ctx.config : ctx.configFor?.(targetTenantId);
82
80
 
83
81
  const rows: CapUsageWithMeta[] = await Promise.all(
84
82
  caps.map(async (cap) => {
@@ -86,7 +86,7 @@ async function resolveLimitsByTenantAndCap(
86
86
  ): Promise<ReadonlyMap<string, number | null>> {
87
87
  const entries = await Promise.all(
88
88
  tenants.flatMap(({ tenantId, tier }) => {
89
- const context: CapLimitContext = { config: configFor?.(tenantId as TenantId) };
89
+ const context: CapLimitContext = { config: configFor?.(tenantId) };
90
90
  return caps.map(
91
91
  async (cap) => [tenantCapKey(tenantId, cap.id), await cap.limit(tier, context)] as const,
92
92
  );