@cosmicdrift/kumiko-bundled-features 0.385.0 → 0.387.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (470) hide show
  1. package/LICENSE +21 -57
  2. package/dist/agent-tools/tool-catalog.js +1 -1
  3. package/dist/agent-tools/tool-dispatch.js +0 -2
  4. package/dist/audit/screens.js +1 -1
  5. package/dist/auth-email-password/feature.js +1 -1
  6. package/dist/auth-email-password/handlers/change-password.write.js +3 -3
  7. package/dist/auth-email-password/handlers/confirm-token-flow.js +5 -5
  8. package/dist/auth-email-password/handlers/invite-accept-with-login.write.js +1 -1
  9. package/dist/auth-email-password/handlers/invite-accept.write.js +18 -18
  10. package/dist/auth-email-password/handlers/invite-create.write.d.ts +2 -2
  11. package/dist/auth-email-password/handlers/invite-create.write.js +10 -10
  12. package/dist/auth-email-password/handlers/invite-info.query.js +1 -1
  13. package/dist/auth-email-password/handlers/invite-signup-complete.write.js +24 -26
  14. package/dist/auth-email-password/handlers/login.write.d.ts +1 -1
  15. package/dist/auth-email-password/handlers/login.write.js +1 -1
  16. package/dist/auth-email-password/handlers/self-registration-status.query.js +1 -1
  17. package/dist/auth-email-password/handlers/signup-confirm.write.js +34 -37
  18. package/dist/auth-email-password/handlers/signup-request.write.js +6 -7
  19. package/dist/auth-email-password/handlers/switch-tenant-mfa-gate.write.d.ts +1 -1
  20. package/dist/auth-email-password/handlers/switch-tenant-mfa-gate.write.js +1 -4
  21. package/dist/auth-email-password/index.js +5 -5
  22. package/dist/auth-email-password/lockout-store.js +1 -1
  23. package/dist/auth-email-password/seeding.d.ts +42 -45
  24. package/dist/auth-email-password/seeding.js +51 -53
  25. package/dist/auth-email-password/signup-token-store.js +8 -8
  26. package/dist/auth-email-password/testing.js +3 -3
  27. package/dist/auth-email-password/web/auth-client.d.ts +2 -2
  28. package/dist/auth-email-password/web/auth-client.js +36 -37
  29. package/dist/auth-email-password/web/auth-form-primitives.js +10 -10
  30. package/dist/auth-email-password/web/auth-gate.js +15 -16
  31. package/dist/auth-email-password/web/client-plugin.d.ts +7 -7
  32. package/dist/auth-email-password/web/client-plugin.js +4 -5
  33. package/dist/auth-email-password/web/confirm-account-unlock-screen.js +1 -1
  34. package/dist/auth-email-password/web/constants.js +3 -3
  35. package/dist/auth-email-password/web/default-topbar-actions.d.ts +8 -8
  36. package/dist/auth-email-password/web/default-topbar-actions.js +6 -6
  37. package/dist/auth-email-password/web/forgot-password-screen.d.ts +2 -2
  38. package/dist/auth-email-password/web/forgot-password-screen.js +9 -9
  39. package/dist/auth-email-password/web/index.js +5 -5
  40. package/dist/auth-email-password/web/invite-accept-screen.d.ts +1 -1
  41. package/dist/auth-email-password/web/invite-accept-screen.js +16 -16
  42. package/dist/auth-email-password/web/login-screen.d.ts +1 -1
  43. package/dist/auth-email-password/web/login-screen.js +2 -3
  44. package/dist/auth-email-password/web/reset-password-screen.d.ts +4 -4
  45. package/dist/auth-email-password/web/reset-password-screen.js +12 -13
  46. package/dist/auth-email-password/web/session.d.ts +10 -9
  47. package/dist/auth-email-password/web/session.js +28 -29
  48. package/dist/auth-email-password/web/signup-complete-screen.js +3 -3
  49. package/dist/auth-email-password/web/signup-screen.d.ts +1 -1
  50. package/dist/auth-email-password/web/signup-screen.js +13 -13
  51. package/dist/auth-email-password/web/tenant-switcher.d.ts +4 -4
  52. package/dist/auth-email-password/web/tenant-switcher.js +21 -22
  53. package/dist/auth-email-password/web/use-shell-user.js +12 -13
  54. package/dist/auth-email-password/web/user-menu.d.ts +4 -4
  55. package/dist/auth-email-password/web/user-menu.js +12 -13
  56. package/dist/auth-email-password/web/verify-email-screen.d.ts +2 -2
  57. package/dist/auth-email-password/web/verify-email-screen.js +9 -10
  58. package/dist/auth-foundation/boot-checks.js +4 -4
  59. package/dist/auth-foundation/resolve-anonymous-access.d.ts +1 -1
  60. package/dist/auth-foundation/resolve-anonymous-access.js +3 -3
  61. package/dist/auth-foundation/types.js +2 -2
  62. package/dist/auth-mfa/handlers/disable.write.js +3 -3
  63. package/dist/auth-mfa/handlers/enable-confirm-preauth.write.js +4 -4
  64. package/dist/auth-mfa/handlers/enable-confirm.write.js +2 -2
  65. package/dist/auth-mfa/handlers/enable-start-preauth.write.js +1 -1
  66. package/dist/auth-mfa/handlers/reencrypt.job.js +1 -1
  67. package/dist/auth-mfa/handlers/regenerate-recovery.write.js +5 -5
  68. package/dist/auth-mfa/handlers/verify.write.js +1 -1
  69. package/dist/auth-mfa/token-secrets.js +1 -1
  70. package/dist/auth-mfa/web/client-plugin.d.ts +1 -1
  71. package/dist/auth-mfa/web/client-plugin.js +1 -1
  72. package/dist/auth-mfa/web/i18n.js +3 -3
  73. package/dist/auth-mfa/web/index.js +4 -4
  74. package/dist/auth-mfa/web/mfa-client.js +17 -16
  75. package/dist/auth-mfa/web/mfa-verify-screen.js +6 -6
  76. package/dist/billing-foundation/aggregate-id.d.ts +5 -5
  77. package/dist/billing-foundation/aggregate-id.js +10 -11
  78. package/dist/billing-foundation/entities.js +27 -27
  79. package/dist/billing-foundation/events.js +18 -17
  80. package/dist/billing-foundation/feature.js +42 -43
  81. package/dist/billing-foundation/get-subscription-for-tenant.d.ts +3 -3
  82. package/dist/billing-foundation/get-subscription-for-tenant.js +3 -5
  83. package/dist/billing-foundation/handlers/create-checkout-session.write.js +18 -17
  84. package/dist/billing-foundation/handlers/create-portal-session.write.js +11 -12
  85. package/dist/billing-foundation/handlers/list-subscriptions.query.js +4 -4
  86. package/dist/billing-foundation/handlers/process-event.write.js +20 -20
  87. package/dist/billing-foundation/projection.d.ts +15 -11
  88. package/dist/billing-foundation/projection.js +38 -37
  89. package/dist/billing-foundation/subscription-tier-sync.js +3 -3
  90. package/dist/billing-foundation/tenant-destroy-hook.d.ts +2 -2
  91. package/dist/billing-foundation/tenant-destroy-hook.js +7 -7
  92. package/dist/billing-foundation/types.d.ts +40 -41
  93. package/dist/billing-foundation/types.js +20 -20
  94. package/dist/billing-foundation/web/billing-plans-panel.js +4 -4
  95. package/dist/cap-counter/aggregate-id.js +8 -9
  96. package/dist/cap-counter/constants.js +11 -12
  97. package/dist/cap-counter/enforce-cap.d.ts +59 -62
  98. package/dist/cap-counter/enforce-cap.js +47 -48
  99. package/dist/cap-counter/entity.js +29 -29
  100. package/dist/cap-counter/feature.js +34 -35
  101. package/dist/cap-counter/handlers/increment-rolling.write.d.ts +2 -2
  102. package/dist/cap-counter/handlers/increment-rolling.write.js +31 -31
  103. package/dist/cap-counter/handlers/mark-soft-warned.write.js +4 -5
  104. package/dist/cap-counter/stock-cap-guard.js +1 -1
  105. package/dist/cap-counter/with-cap-enforcement.d.ts +3 -5
  106. package/dist/channel-email/smtp-transport.d.ts +18 -17
  107. package/dist/channel-email/smtp-transport.js +24 -21
  108. package/dist/channel-in-app/handlers/unread-count.query.js +3 -4
  109. package/dist/compliance-profiles/feature.js +4 -4
  110. package/dist/compliance-profiles/handlers/for-tenant.query.js +3 -6
  111. package/dist/compliance-profiles/handlers/list-profiles.query.js +5 -5
  112. package/dist/compliance-profiles/handlers/needs-profile.query.js +4 -4
  113. package/dist/compliance-profiles/handlers/set-profile.write.js +13 -14
  114. package/dist/compliance-profiles/handlers/sub-processors.query.js +9 -11
  115. package/dist/compliance-profiles/resolve-for-tenant.js +7 -7
  116. package/dist/compliance-profiles/schema/profile-selection.js +18 -23
  117. package/dist/compliance-profiles/seeding.js +14 -15
  118. package/dist/compliance-profiles-ops/handlers/tenants-missing-profile.query.js +3 -3
  119. package/dist/compliance-profiles-ops/index.js +2 -2
  120. package/dist/config/handlers/readiness.query.d.ts +4 -4
  121. package/dist/config/handlers/readiness.query.js +1 -1
  122. package/dist/config/handlers/reencrypt.job.js +4 -5
  123. package/dist/config/handlers/set.write.js +4 -4
  124. package/dist/config/resolver.js +4 -4
  125. package/dist/config/table.js +10 -10
  126. package/dist/config/write-helpers.js +1 -1
  127. package/dist/crypto-shredding/handlers/forget-subject.write.d.ts +2 -2
  128. package/dist/crypto-shredding/handlers/forget-subject.write.js +12 -11
  129. package/dist/custom-fields/aggregate-id.d.ts +12 -13
  130. package/dist/custom-fields/aggregate-id.js +16 -17
  131. package/dist/custom-fields/entity.js +49 -47
  132. package/dist/custom-fields/events.js +7 -8
  133. package/dist/custom-fields/feature.d.ts +14 -14
  134. package/dist/custom-fields/feature.js +53 -54
  135. package/dist/custom-fields/handlers/clear-custom-field.write.d.ts +3 -2
  136. package/dist/custom-fields/handlers/clear-custom-field.write.js +9 -8
  137. package/dist/custom-fields/handlers/define-tenant-field.write.d.ts +1 -1
  138. package/dist/custom-fields/handlers/define-tenant-field.write.js +2 -2
  139. package/dist/custom-fields/handlers/delete-system-field.write.js +6 -7
  140. package/dist/custom-fields/handlers/delete-tenant-field.write.d.ts +1 -1
  141. package/dist/custom-fields/handlers/delete-tenant-field.write.js +3 -3
  142. package/dist/custom-fields/handlers/set-custom-field.write.d.ts +3 -3
  143. package/dist/custom-fields/handlers/set-custom-field.write.js +25 -28
  144. package/dist/custom-fields/handlers/update-tenant-field.write.d.ts +1 -1
  145. package/dist/custom-fields/handlers/update-tenant-field.write.js +1 -1
  146. package/dist/custom-fields/lib/field-access.js +2 -2
  147. package/dist/custom-fields/lib/parse-serialized-field.js +1 -1
  148. package/dist/custom-fields/lib/quota.js +1 -1
  149. package/dist/custom-fields/lib/value-schema.js +10 -12
  150. package/dist/custom-fields/run-retention.js +3 -3
  151. package/dist/custom-fields/schemas.js +14 -14
  152. package/dist/custom-fields/web/client-plugin.js +2 -5
  153. package/dist/custom-fields/web/constants.js +2 -2
  154. package/dist/custom-fields/web/custom-fields-form-section.d.ts +4 -4
  155. package/dist/custom-fields/web/custom-fields-form-section.js +22 -22
  156. package/dist/custom-fields/wire-for-entity.js +65 -67
  157. package/dist/custom-fields/wire-user-data-rights.js +3 -3
  158. package/dist/data-retention/_internal/parse-override.js +2 -3
  159. package/dist/data-retention/feature.js +11 -18
  160. package/dist/data-retention/handlers/policy-for.query.js +6 -6
  161. package/dist/data-retention/keep-for.d.ts +7 -7
  162. package/dist/data-retention/keep-for.js +15 -15
  163. package/dist/data-retention/override-schema.d.ts +3 -4
  164. package/dist/data-retention/override-schema.js +13 -15
  165. package/dist/data-retention/presets.d.ts +4 -5
  166. package/dist/data-retention/presets.js +18 -23
  167. package/dist/data-retention/resolve-tenant-preset.js +17 -16
  168. package/dist/data-retention/resolver.d.ts +12 -12
  169. package/dist/data-retention/resolver.js +24 -23
  170. package/dist/data-retention/run-retention-cleanup.d.ts +8 -3
  171. package/dist/data-retention/run-retention-cleanup.js +61 -51
  172. package/dist/data-retention/schema/tenant-retention-override.js +13 -11
  173. package/dist/delivery/feature.js +2 -2
  174. package/dist/delivery/handlers/log.query.js +1 -1
  175. package/dist/delivery/tables.js +9 -8
  176. package/dist/delivery/unsubscribe.js +4 -4
  177. package/dist/document-ingest-foundation/entity.js +4 -4
  178. package/dist/document-ingest-foundation/events.js +2 -2
  179. package/dist/document-ingest-foundation/feature.js +2 -2
  180. package/dist/document-ingest-foundation/pages.js +1 -1
  181. package/dist/document-ingest-foundation/tenant-destroy-hook.js +4 -4
  182. package/dist/feature-toggles/compose-tier-resolver.js +1 -1
  183. package/dist/feature-toggles/feature.js +1 -1
  184. package/dist/feature-toggles/global-feature-state-table.js +1 -1
  185. package/dist/feature-toggles/handlers/registered.query.js +5 -5
  186. package/dist/feature-toggles/toggle-sync-signal.js +1 -1
  187. package/dist/feature-toggles/web/constants.js +1 -1
  188. package/dist/file-derivatives/feature.d.ts +1 -1
  189. package/dist/file-derivatives/feature.js +1 -1
  190. package/dist/file-derivatives/handlers/public-variant.query.js +1 -1
  191. package/dist/file-derivatives/presets.js +1 -1
  192. package/dist/file-foundation/feature.js +6 -6
  193. package/dist/file-provider-inmemory/feature.d.ts +1 -1
  194. package/dist/file-provider-inmemory/feature.js +16 -16
  195. package/dist/file-provider-s3/feature.js +16 -16
  196. package/dist/file-provider-s3/lib/s3-provider.js +6 -6
  197. package/dist/files/feature.js +6 -6
  198. package/dist/files-tenant-data/handlers/sweep-orphaned-derivatives.job.js +4 -4
  199. package/dist/files-tenant-data/hooks.js +24 -26
  200. package/dist/files-tenant-data/index.js +1 -1
  201. package/dist/folders/feature.d.ts +1 -1
  202. package/dist/folders/web/folder-manager.js +2 -2
  203. package/dist/folders/web/tree.js +5 -5
  204. package/dist/form-draft/db/queries/cleanup.js +1 -1
  205. package/dist/form-draft/db/queries/owned-file-refs.js +1 -1
  206. package/dist/form-draft/entity.js +3 -3
  207. package/dist/form-draft/feature.js +4 -5
  208. package/dist/form-draft/handlers/discard.write.js +1 -1
  209. package/dist/form-draft/release-file-refs.js +6 -6
  210. package/dist/form-draft/schemas.js +3 -3
  211. package/dist/form-draft/web/constants.js +0 -2
  212. package/dist/inbound-mail-foundation/aggregate-id.d.ts +13 -13
  213. package/dist/inbound-mail-foundation/aggregate-id.js +19 -19
  214. package/dist/inbound-mail-foundation/connect-routes.js +4 -3
  215. package/dist/inbound-mail-foundation/constants.d.ts +22 -24
  216. package/dist/inbound-mail-foundation/constants.js +30 -33
  217. package/dist/inbound-mail-foundation/entities.d.ts +12 -12
  218. package/dist/inbound-mail-foundation/entities.js +47 -48
  219. package/dist/inbound-mail-foundation/events.d.ts +4 -3
  220. package/dist/inbound-mail-foundation/events.js +50 -47
  221. package/dist/inbound-mail-foundation/feature.js +39 -39
  222. package/dist/inbound-mail-foundation/handlers/account-state.js +8 -8
  223. package/dist/inbound-mail-foundation/handlers/connect-account.write.js +25 -26
  224. package/dist/inbound-mail-foundation/handlers/disconnect-account.write.js +7 -7
  225. package/dist/inbound-mail-foundation/handlers/ingest-message.write.js +50 -51
  226. package/dist/inbound-mail-foundation/handlers/list-accounts.query.js +8 -8
  227. package/dist/inbound-mail-foundation/handlers/list-messages.query.js +10 -10
  228. package/dist/inbound-mail-foundation/handlers/scope-visibility.js +3 -4
  229. package/dist/inbound-mail-foundation/handlers/update-account.write.js +11 -11
  230. package/dist/inbound-mail-foundation/oauth-state.d.ts +5 -5
  231. package/dist/inbound-mail-foundation/oauth-state.js +11 -10
  232. package/dist/inbound-mail-foundation/projection.d.ts +4 -4
  233. package/dist/inbound-mail-foundation/projection.js +31 -29
  234. package/dist/inbound-mail-foundation/provider-factory.d.ts +4 -4
  235. package/dist/inbound-mail-foundation/provider-factory.js +9 -9
  236. package/dist/inbound-mail-foundation/retention-sweep.d.ts +5 -3
  237. package/dist/inbound-mail-foundation/retention-sweep.js +38 -36
  238. package/dist/inbound-mail-foundation/tenant-destroy-hook.js +14 -16
  239. package/dist/inbound-mail-foundation/types.d.ts +45 -46
  240. package/dist/inbound-mail-foundation/types.js +21 -21
  241. package/dist/inbound-mail-foundation/watch-supervisor.d.ts +10 -10
  242. package/dist/inbound-mail-foundation/watch-supervisor.js +57 -56
  243. package/dist/inbound-provider-imap/credential-document.js +13 -13
  244. package/dist/inbound-provider-imap/feature.d.ts +2 -2
  245. package/dist/inbound-provider-imap/feature.js +42 -40
  246. package/dist/inbound-provider-imap/imap-client.d.ts +12 -11
  247. package/dist/inbound-provider-imap/imap-client.js +20 -19
  248. package/dist/inbound-provider-inmemory/feature.d.ts +9 -9
  249. package/dist/inbound-provider-inmemory/feature.js +19 -19
  250. package/dist/jobs/db/queries/retention.js +2 -2
  251. package/dist/jobs/db/queries/stale-run-sweep.js +3 -3
  252. package/dist/jobs/events.js +1 -1
  253. package/dist/jobs/feature.js +5 -6
  254. package/dist/jobs/handlers/detail.query.js +4 -4
  255. package/dist/jobs/handlers/list.query.js +1 -1
  256. package/dist/jobs/handlers/projection-rebuild.job.js +1 -1
  257. package/dist/jobs/handlers/reindex-entity.job.js +1 -1
  258. package/dist/jobs/handlers/retry.write.js +1 -1
  259. package/dist/jobs/job-instant.js +1 -1
  260. package/dist/jobs/job-run-logger.js +10 -11
  261. package/dist/jobs/job-run-table.js +3 -3
  262. package/dist/jobs/screens.js +1 -1
  263. package/dist/jobs/tenant-job-failure-table.js +1 -1
  264. package/dist/jobs/tenant-job-run-table.js +1 -1
  265. package/dist/ledger/entity.js +5 -5
  266. package/dist/ledger/feature.js +3 -3
  267. package/dist/ledger/handlers/confirm-schedule-period.write.js +3 -3
  268. package/dist/ledger/recurring.js +12 -12
  269. package/dist/ledger/schemas.js +1 -1
  270. package/dist/ledger/web/constants.js +2 -2
  271. package/dist/ledger/web/index.js +7 -7
  272. package/dist/legal-pages/feature.d.ts +4 -4
  273. package/dist/legal-pages/feature.js +25 -26
  274. package/dist/legal-pages/markdown.js +3 -3
  275. package/dist/legal-pages/web/client-plugin.js +23 -24
  276. package/dist/legal-pages/web/index.js +0 -1
  277. package/dist/mail-foundation/feature.d.ts +2 -2
  278. package/dist/mail-foundation/feature.js +24 -25
  279. package/dist/mail-transport-inmemory/feature.d.ts +4 -4
  280. package/dist/mail-transport-inmemory/feature.js +27 -28
  281. package/dist/mail-transport-smtp/feature.js +20 -20
  282. package/dist/managed-pages/branding.js +6 -6
  283. package/dist/managed-pages/feature.d.ts +26 -26
  284. package/dist/managed-pages/feature.js +34 -34
  285. package/dist/managed-pages/handlers/by-slug.query.js +5 -6
  286. package/dist/managed-pages/handlers/by-tenant-published.query.js +2 -2
  287. package/dist/managed-pages/handlers/set.write.js +5 -7
  288. package/dist/managed-pages/screens/page-screens.js +11 -11
  289. package/dist/managed-pages/seeding.js +8 -8
  290. package/dist/managed-pages/table.js +13 -12
  291. package/dist/managed-pages/web/client-plugin.d.ts +1 -1
  292. package/dist/managed-pages/web/client-plugin.js +5 -5
  293. package/dist/managed-pages/web/i18n.js +1 -1
  294. package/dist/notes-history/entity.js +4 -4
  295. package/dist/notes-history/feature.d.ts +2 -2
  296. package/dist/notes-history-user-data/hooks.js +1 -1
  297. package/dist/page-render/layout.js +9 -9
  298. package/dist/page-render/markdown.js +11 -11
  299. package/dist/page-render/security-headers.js +7 -6
  300. package/dist/personal-access-tokens/feature.js +5 -5
  301. package/dist/personal-access-tokens/roles.js +2 -2
  302. package/dist/readiness/handlers/status.query.js +3 -3
  303. package/dist/renderer-foundation/api.js +12 -13
  304. package/dist/renderer-foundation/constants.js +2 -2
  305. package/dist/renderer-foundation/feature.js +7 -7
  306. package/dist/secrets/feature.js +9 -9
  307. package/dist/secrets/web/constants.js +2 -2
  308. package/dist/seo/feature.js +3 -3
  309. package/dist/sessions/constants.d.ts +1 -1
  310. package/dist/sessions/constants.js +1 -1
  311. package/dist/sessions/feature.js +8 -8
  312. package/dist/sessions/handlers/revoke-all-for-user.write.js +2 -2
  313. package/dist/sessions/handlers/revoke-all-others.write.js +2 -2
  314. package/dist/sessions/handlers/revoke.write.js +1 -1
  315. package/dist/sessions/schema/user-session.js +4 -4
  316. package/dist/sessions/screens.js +2 -2
  317. package/dist/sessions/session-callbacks.js +2 -2
  318. package/dist/sessions/session-revoked-event.js +2 -2
  319. package/dist/shared/assert-no-where-rule-in-ownership-write.js +1 -1
  320. package/dist/shared/decrypt-stored-pii.js +1 -1
  321. package/dist/shared/encrypt-for-direct-write.js +1 -1
  322. package/dist/shared/map-with-concurrency.js +5 -4
  323. package/dist/shared/parent-visibility.js +2 -2
  324. package/dist/shared/password-hashing.js +1 -1
  325. package/dist/shared/signup-handover.js +1 -2
  326. package/dist/shared/single-use-token-store.js +1 -1
  327. package/dist/subscription-mollie/constants.js +15 -17
  328. package/dist/subscription-mollie/feature.d.ts +17 -18
  329. package/dist/subscription-mollie/feature.js +24 -24
  330. package/dist/subscription-mollie/index.js +3 -3
  331. package/dist/subscription-mollie/plugin-methods.d.ts +2 -2
  332. package/dist/subscription-mollie/plugin-methods.js +15 -14
  333. package/dist/subscription-mollie/verify-webhook.d.ts +10 -10
  334. package/dist/subscription-mollie/verify-webhook.js +27 -27
  335. package/dist/subscription-stripe/constants.js +4 -6
  336. package/dist/subscription-stripe/feature.d.ts +14 -14
  337. package/dist/subscription-stripe/feature.js +35 -34
  338. package/dist/subscription-stripe/index.js +6 -6
  339. package/dist/subscription-stripe/plugin-methods.js +18 -18
  340. package/dist/subscription-stripe/runtime.d.ts +1 -1
  341. package/dist/subscription-stripe/runtime.js +1 -1
  342. package/dist/subscription-stripe/verify-webhook.d.ts +11 -11
  343. package/dist/subscription-stripe/verify-webhook.js +59 -61
  344. package/dist/tags/feature.d.ts +3 -3
  345. package/dist/tags/screens.js +1 -1
  346. package/dist/template-resolver/api.js +10 -10
  347. package/dist/template-resolver/handlers/find-by-id.query.js +5 -5
  348. package/dist/template-resolver/handlers/list.query.js +1 -1
  349. package/dist/template-resolver/handlers/shared.js +2 -2
  350. package/dist/template-resolver/handlers/template-write.js +3 -3
  351. package/dist/template-resolver/handlers/upsert-system.write.js +3 -4
  352. package/dist/template-resolver/handlers/upsert-tenant.write.js +4 -5
  353. package/dist/template-resolver/seeding.js +4 -4
  354. package/dist/template-resolver/table.js +10 -11
  355. package/dist/template-resolver/web/client-plugin.js +2 -2
  356. package/dist/tenant/feature.js +7 -7
  357. package/dist/tenant/handlers/member-directory.query.js +1 -1
  358. package/dist/tenant/handlers/members.query.js +1 -1
  359. package/dist/tenant/handlers/team-list.query.js +1 -1
  360. package/dist/tenant/handlers/tenant-directory.query.js +1 -1
  361. package/dist/tenant/invitation-table.js +37 -40
  362. package/dist/tenant/membership-table.js +3 -3
  363. package/dist/tenant/schema/tenant.js +7 -9
  364. package/dist/tenant/screens.js +1 -1
  365. package/dist/tenant/seeding.d.ts +6 -5
  366. package/dist/tenant/seeding.js +12 -12
  367. package/dist/tenant/testing.js +5 -6
  368. package/dist/tenant/web/constants.js +2 -2
  369. package/dist/tenant-handover/events.js +5 -7
  370. package/dist/tenant-handover/feature.js +1 -1
  371. package/dist/tenant-handover/grant.js +1 -1
  372. package/dist/tenant-handover/handlers/claim.write.js +1 -1
  373. package/dist/tenant-handover/move-entity-graph.js +8 -9
  374. package/dist/tenant-handover/signup-handover-provider.js +1 -2
  375. package/dist/tenant-handover/transfer-graph.js +4 -5
  376. package/dist/tenant-lifecycle/boot-checks.js +1 -1
  377. package/dist/tenant-lifecycle/feature.js +1 -1
  378. package/dist/tenant-settings/constants.js +1 -1
  379. package/dist/tenant-settings/tenant-defaults.d.ts +1 -1
  380. package/dist/tenant-settings/tenant-defaults.js +9 -2
  381. package/dist/tier-engine/aggregate-id.d.ts +11 -11
  382. package/dist/tier-engine/aggregate-id.js +15 -16
  383. package/dist/tier-engine/compose-app.d.ts +14 -14
  384. package/dist/tier-engine/compose-app.js +1 -1
  385. package/dist/tier-engine/entity.js +18 -19
  386. package/dist/tier-engine/feature.d.ts +19 -17
  387. package/dist/tier-engine/feature.js +68 -69
  388. package/dist/tier-engine/handlers/active-tier.query.js +6 -7
  389. package/dist/tier-engine/handlers/get-tenant-tier.query.js +4 -4
  390. package/dist/tier-engine/handlers/set-tenant-tier.write.d.ts +5 -5
  391. package/dist/tier-engine/handlers/set-tenant-tier.write.js +3 -3
  392. package/dist/tier-engine/tier-resolver.js +2 -2
  393. package/dist/tier-engine/trial.js +8 -8
  394. package/dist/tier-engine/web/index.js +4 -4
  395. package/dist/user/db/queries/stream-tenant-backfill.js +8 -8
  396. package/dist/user/handlers/create.write.js +4 -4
  397. package/dist/user/schema/user.d.ts +11 -11
  398. package/dist/user/schema/user.js +45 -44
  399. package/dist/user/seeding.d.ts +15 -15
  400. package/dist/user/seeding.js +28 -28
  401. package/dist/user/testing.js +3 -3
  402. package/dist/user-data-rights/audit-download.d.ts +8 -8
  403. package/dist/user-data-rights/audit-download.js +19 -20
  404. package/dist/user-data-rights/boot-checks.js +1 -1
  405. package/dist/user-data-rights/deletion-token.js +1 -1
  406. package/dist/user-data-rights/feature.d.ts +49 -50
  407. package/dist/user-data-rights/feature.js +54 -53
  408. package/dist/user-data-rights/handlers/cancel-deletion.write.js +9 -9
  409. package/dist/user-data-rights/handlers/confirm-deletion-by-token.write.js +8 -8
  410. package/dist/user-data-rights/handlers/download-by-job.query.js +29 -30
  411. package/dist/user-data-rights/handlers/download-by-token.query.js +40 -42
  412. package/dist/user-data-rights/handlers/export-status.query.js +8 -9
  413. package/dist/user-data-rights/handlers/lift-restriction.write.js +7 -8
  414. package/dist/user-data-rights/handlers/list-download-attempts.query.js +2 -2
  415. package/dist/user-data-rights/handlers/my-audit-log.query.js +4 -4
  416. package/dist/user-data-rights/handlers/request-deletion-by-email.write.d.ts +5 -5
  417. package/dist/user-data-rights/handlers/request-deletion-by-email.write.js +16 -15
  418. package/dist/user-data-rights/handlers/request-deletion.write.d.ts +2 -2
  419. package/dist/user-data-rights/handlers/request-deletion.write.js +7 -9
  420. package/dist/user-data-rights/handlers/request-export.write.js +42 -41
  421. package/dist/user-data-rights/handlers/restrict-account.write.js +22 -19
  422. package/dist/user-data-rights/handlers/run-forget-cleanup.write.js +8 -8
  423. package/dist/user-data-rights/index.js +8 -10
  424. package/dist/user-data-rights/lib/default-mailers.js +3 -3
  425. package/dist/user-data-rights/lib/update-user-lifecycle.js +14 -17
  426. package/dist/user-data-rights/run-export-jobs.d.ts +38 -42
  427. package/dist/user-data-rights/run-export-jobs.js +127 -233
  428. package/dist/user-data-rights/run-forget-cleanup.d.ts +16 -20
  429. package/dist/user-data-rights/run-forget-cleanup.js +63 -82
  430. package/dist/user-data-rights/run-user-export.d.ts +34 -33
  431. package/dist/user-data-rights/run-user-export.js +55 -57
  432. package/dist/user-data-rights/schema/download-attempt.js +11 -11
  433. package/dist/user-data-rights/schema/download-token.js +37 -41
  434. package/dist/user-data-rights/schema/export-job.d.ts +4 -4
  435. package/dist/user-data-rights/schema/export-job.js +65 -67
  436. package/dist/user-data-rights/token-helpers.d.ts +8 -9
  437. package/dist/user-data-rights/token-helpers.js +21 -25
  438. package/dist/user-data-rights/web/client-plugin.d.ts +5 -5
  439. package/dist/user-data-rights/web/client-plugin.js +1 -1
  440. package/dist/user-data-rights/web/confirm-deletion-screen.js +6 -5
  441. package/dist/user-data-rights/web/constants.js +1 -1
  442. package/dist/user-data-rights/web/index.js +5 -5
  443. package/dist/user-data-rights/web/privacy-center-screen.js +14 -13
  444. package/dist/user-data-rights/web/public-deletion-gate.d.ts +4 -4
  445. package/dist/user-data-rights/web/request-deletion-screen.js +6 -6
  446. package/dist/user-data-rights/zip-path.d.ts +15 -15
  447. package/dist/user-data-rights/zip-path.js +41 -40
  448. package/dist/user-data-rights-defaults/feature.js +15 -15
  449. package/dist/user-data-rights-defaults/hooks/delivery-attempt.userdata-hook.js +3 -5
  450. package/dist/user-data-rights-defaults/hooks/file-ref.userdata-hook.js +45 -51
  451. package/dist/user-data-rights-defaults/hooks/job-run.userdata-hook.js +2 -2
  452. package/dist/user-data-rights-defaults/hooks/notification-preference.userdata-hook.js +1 -1
  453. package/dist/user-data-rights-defaults/hooks/user-session.userdata-hook.js +3 -3
  454. package/dist/user-data-rights-defaults/hooks/user.userdata-hook.js +32 -31
  455. package/dist/user-profile/handlers/change-email.write.js +13 -13
  456. package/dist/user-profile/index.js +3 -3
  457. package/dist/user-profile/web/client-plugin.js +1 -1
  458. package/dist/user-profile/web/constants.js +1 -1
  459. package/dist/user-profile/web/profile-screen.js +1 -1
  460. package/dist/workflow-runner/aggregate-id.d.ts +1 -1
  461. package/dist/workflow-runner/aggregate-id.js +1 -1
  462. package/dist/workflow-runner/event-subscriber.js +4 -5
  463. package/dist/workflow-runner/event-trigger.js +4 -17
  464. package/dist/workflow-runner/feature.js +2 -2
  465. package/dist/workflow-runner/handlers/resume-run.write.js +4 -4
  466. package/dist/workflow-runner/pending-projection.js +6 -7
  467. package/dist/workflow-runner/runner.js +6 -6
  468. package/dist/workflow-runner/tables.js +6 -6
  469. package/dist/workflow-runner/workflow-registry.js +1 -1
  470. package/package.json +10 -10
@@ -11,7 +11,7 @@ export const TENANT_SETTINGS_FEATURE_NAME = "tenant-settings";
11
11
  // strings (mirror tags' Handlers/Queries constants).
12
12
  export const TenantSettingsConfig = {
13
13
  // Shared with engine/constants.ts's TENANT_CURRENCY_CONFIG_KEY — a
14
- // `money` field's `currency: { kind: "tenant" }` declaration (fw#2933)
14
+ // `money` field's `currency: { kind: "tenant" }` declaration
15
15
  // resolves against this same key.
16
16
  currency: TENANT_CURRENCY_CONFIG_KEY,
17
17
  locale: "tenant-settings:config:locale",
@@ -2,7 +2,7 @@ import { type AccessRule, type EntityDefinition, type WriteHandlerDef } from "@c
2
2
  export declare function defineCreateWithTenantDefaults(entityName: string, entity: EntityDefinition, options: {
3
3
  /** Required — this is a write-path helper; making it optional let a
4
4
  * forgetful caller register a create handler with no access rule at
5
- * all (fw#1581). */
5
+ * all. */
6
6
  readonly access: AccessRule;
7
7
  /** Money field names whose `currency` is filled from tenant-settings when missing. */
8
8
  readonly currencyFields?: readonly string[];
@@ -8,6 +8,8 @@
8
8
  // a schema extension that makes those sub-keys optional, instead of the
9
9
  // generic defineEntityCreateHandler.
10
10
  import { buildInsertSchema, createEntityExecutor, } from "@cosmicdrift/kumiko-framework/engine";
11
+ import { InternalError } from "@cosmicdrift/kumiko-framework/errors";
12
+ import { isPlainObject } from "@cosmicdrift/kumiko-types/type-guards";
11
13
  import * as z from "zod";
12
14
  import { TenantSettingsConfig } from "./constants.js";
13
15
  const OPTIONAL_CURRENCY_MONEY = z.object({ amount: z.number(), currency: z.string().optional() });
@@ -31,10 +33,15 @@ export function defineCreateWithTenantDefaults(entityName, entity, options) {
31
33
  schema,
32
34
  access: options.access,
33
35
  handler: async (event, ctx) => {
36
+ if (!isPlainObject(event.payload)) {
37
+ throw new InternalError({
38
+ message: `${entityName}:create payload must be an object after schema validation`,
39
+ });
40
+ }
34
41
  const payload = { ...event.payload };
35
42
  for (const field of options.currencyFields ?? []) {
36
43
  const value = payload[field];
37
- if (value && typeof value === "object" && !value.currency) {
44
+ if (isPlainObject(value) && !value["currency"]) {
38
45
  const currency = await ctx.config?.(TenantSettingsConfig.currency);
39
46
  if (typeof currency === "string")
40
47
  payload[field] = { ...value, currency };
@@ -46,7 +53,7 @@ export function defineCreateWithTenantDefaults(entityName, entity, options) {
46
53
  payload[options.localeField] = locale;
47
54
  }
48
55
  // Re-validate against the unrelaxed entity schema so config-filled
49
- // values still honor select/enum field constraints (fw#1581) — and so
56
+ // values still honor select/enum field constraints — and so
50
57
  // a missing currency after failed/missing tenant-settings mount fails
51
58
  // loud instead of inserting half-filled money rows.
52
59
  const filled = baseSchema.parse(payload);
@@ -1,16 +1,16 @@
1
1
  /**
2
- * Deterministic aggregate-id für ein Tier-Assignment aus dem tenantId.
3
- * Pro Plattform-Tenant existiert genau ein Aggregat — uuidv5 ist
4
- * namespace-deterministic, identische Eingabe ergibt identischen UUID.
2
+ * Deterministic aggregate ID for a tier assignment derived from `tenantId`.
3
+ * Each platform tenant has exactly one aggregate; uuidv5 is namespace-
4
+ * deterministic, so identical input produces the same UUID.
5
5
  *
6
- * **Wann nutzen:** Sprint 5 (`stripe-sync`-Feature) wrapt einen
7
- * idempotent-set-tier-Handler darum: zweiter Stripe-Webhook-Retry mit
8
- * derselben tenantId → derselbe aggregate-Stream → version_conflict
9
- * vom Event-Store statt pg-23505 von der Read-Model-DB. ES-saubere
10
- * Path-Uniqueness statt DB-Constraint.
6
+ * **When to use:** The `stripe-sync` feature wraps an idempotent
7
+ * set-tier handler with this function: a second Stripe webhook retry for
8
+ * the same `tenantId` targets the same aggregate stream, causing
9
+ * `version_conflict` from the event store instead of `pg-23505` from the
10
+ * read-model database. This enforces path uniqueness rather than a database
11
+ * constraint.
11
12
  *
12
- * **Sprint 1 nutzt das nicht aktiv** — Standard-CRUD-Handlers vergeben
13
- * UUID via `gen_random_uuid()`. Die Funktion lebt hier als Utility-
14
- * Export bereit für Sprint 5.
13
+ * Standard CRUD handlers instead generate UUIDs via `gen_random_uuid()`.
14
+ * This utility is exported for use by the `stripe-sync` feature.
15
15
  */
16
16
  export declare function tierAssignmentAggregateId(tenantId: string): string;
@@ -1,24 +1,23 @@
1
1
  import { v5 as uuidv5 } from "uuid";
2
- // Fixed UUID-namespace für die tier-assignment-aggregate-id-Ableitung.
3
- // Generiert einmalig (2026-05-02), in Stein gemeißelt: ein Wechsel würde
4
- // jeden existing aggregate-Stream re-keyen → kaputter event-replay,
5
- // kaputte projection-rebuilds, verlorener Tier-Wechsel-Audit. Der
6
- // drift-pin-Test in feature.test.ts pinnt diese Konstante.
2
+ // Fixed UUID namespace for deriving tier-assignment aggregate IDs.
3
+ // Generated once and immutable: changing it would re-key every existing
4
+ // aggregate stream, breaking event replay and projection rebuilds and losing
5
+ // the tier-change audit. The drift-pin test in feature.test.ts pins this constant.
7
6
  const TIER_ASSIGNMENT_NAMESPACE = "8e91d2fc-8b7a-4d3e-9f4a-1c5d6e7f8a9b";
8
7
  /**
9
- * Deterministic aggregate-id für ein Tier-Assignment aus dem tenantId.
10
- * Pro Plattform-Tenant existiert genau ein Aggregat — uuidv5 ist
11
- * namespace-deterministic, identische Eingabe ergibt identischen UUID.
8
+ * Deterministic aggregate ID for a tier assignment derived from `tenantId`.
9
+ * Each platform tenant has exactly one aggregate; uuidv5 is namespace-
10
+ * deterministic, so identical input produces the same UUID.
12
11
  *
13
- * **Wann nutzen:** Sprint 5 (`stripe-sync`-Feature) wrapt einen
14
- * idempotent-set-tier-Handler darum: zweiter Stripe-Webhook-Retry mit
15
- * derselben tenantId → derselbe aggregate-Stream → version_conflict
16
- * vom Event-Store statt pg-23505 von der Read-Model-DB. ES-saubere
17
- * Path-Uniqueness statt DB-Constraint.
12
+ * **When to use:** The `stripe-sync` feature wraps an idempotent
13
+ * set-tier handler with this function: a second Stripe webhook retry for
14
+ * the same `tenantId` targets the same aggregate stream, causing
15
+ * `version_conflict` from the event store instead of `pg-23505` from the
16
+ * read-model database. This enforces path uniqueness rather than a database
17
+ * constraint.
18
18
  *
19
- * **Sprint 1 nutzt das nicht aktiv** — Standard-CRUD-Handlers vergeben
20
- * UUID via `gen_random_uuid()`. Die Funktion lebt hier als Utility-
21
- * Export bereit für Sprint 5.
19
+ * Standard CRUD handlers instead generate UUIDs via `gen_random_uuid()`.
20
+ * This utility is exported for use by the `stripe-sync` feature.
22
21
  */
23
22
  // @wrapper-known uuid-domain
24
23
  export function tierAssignmentAggregateId(tenantId) {
@@ -2,17 +2,17 @@ import type { FeatureDefinition } from "@cosmicdrift/kumiko-framework/engine";
2
2
  /**
3
3
  * Tier definition — a named bundle of features + caps.
4
4
  *
5
- * **Generic über `TCaps`:** die App definiert ihren Cap-Shape als konkreten
6
- * Type (z.B. `{ apps: number, mailsPerMonth: number, aiTokens: number }`)
7
- * und der composeApp-Aufruf liefert exakt diesen Shape zurück. Keine
8
- * `as Record<string, unknown>`-Casts in App-Code, alle Cap-Reads sind
9
- * compile-time-checked.
5
+ * **Generic over `TCaps`:** the app defines its cap shape as a concrete
6
+ * type (e.g. `{ apps: number, mailsPerMonth: number, aiTokens: number }`)
7
+ * and the composeApp call returns exactly that shape. No
8
+ * `as Record<string, unknown>` casts are needed in app code; all cap reads
9
+ * are compile-time checked.
10
10
  *
11
- * Die Tier-Engine selbst ist **agnostisch** zu konkreten Tier-Werten und
12
- * Cap-Dimensionen. Jede App definiert ihre TierMap: kumiko.rocks hat
13
- * free/pro/business/enterprise/self-host, PublicStatus hat
14
- * free/starter/team/agency. Die Engine speichert nur den Tier-Namen als
15
- * String und vertraut der App's TierMap, was das beim Boot bedeutet.
11
+ * The tier engine itself is **agnostic** to concrete tier values and cap
12
+ * dimensions. Each app defines its TierMap: kumiko.rocks has
13
+ * free/pro/business/enterprise/self-host, while PublicStatus has
14
+ * free/starter/team/agency. The engine stores only the tier name as a
15
+ * string and trusts the app's TierMap to define what it means at boot.
16
16
  */
17
17
  export type TierDefinition<TCaps extends Readonly<Record<string, unknown>>> = {
18
18
  /** Feature names to mount on top of the base set (no add-ons applied). */
@@ -24,9 +24,9 @@ export type TierDefinition<TCaps extends Readonly<Record<string, unknown>>> = {
24
24
  * Add-On definition — a tier-orthogonal feature bundle that can be added
25
25
  * to any tier (BYOK-Encryption, Dedicated-Stack, Custom-SLA, ...).
26
26
  *
27
- * `capOverrides` ist `Partial<TCaps>` weil ein Add-On nur einzelne Cap-
28
- * Werte überschreibt (z.B. „Dedicated-Stack erhöht mailsPerMonth auf
29
- * 100k"), nicht den ganzen Shape neu definiert.
27
+ * `capOverrides` is `Partial<TCaps>` because an add-on overrides only
28
+ * individual cap values (e.g. “Dedicated-Stack increases mailsPerMonth to
29
+ * 100k”), rather than redefining the entire shape.
30
30
  */
31
31
  export type AddOnDefinition<TCaps extends Readonly<Record<string, unknown>>> = {
32
32
  /** Feature names to mount additionally when this add-on is active. */
@@ -60,7 +60,7 @@ export type ComposedApp<TCaps extends Readonly<Record<string, unknown>>> = {
60
60
  * composeApp — compute the feature-set + caps for a platform-tenant.
61
61
  *
62
62
  * **Contract:**
63
- * 1. base features always mount (Tier-Engine itself ist Teil davon)
63
+ * 1. base features always mount (the Tier-Engine itself is part of them)
64
64
  * 2. plus tier-specific features (from tierMap[tier].features)
65
65
  * 3. plus add-on features (from addOnMap[addOn].features for each active add-on)
66
66
  * 4. caps = tier.caps ⊕ add-on.capOverrides (later add-ons override earlier)
@@ -2,7 +2,7 @@
2
2
  * composeApp — compute the feature-set + caps for a platform-tenant.
3
3
  *
4
4
  * **Contract:**
5
- * 1. base features always mount (Tier-Engine itself ist Teil davon)
5
+ * 1. base features always mount (the Tier-Engine itself is part of them)
6
6
  * 2. plus tier-specific features (from tierMap[tier].features)
7
7
  * 3. plus add-on features (from addOnMap[addOn].features for each active add-on)
8
8
  * 4. caps = tier.caps ⊕ add-on.capOverrides (later add-ons override earlier)
@@ -1,27 +1,26 @@
1
1
  import { createEntity, createSelectField, createTextField, } from "@cosmicdrift/kumiko-framework/engine";
2
2
  import { TierAssignmentSources } from "./web/constants.js";
3
- // tier-assignment — pro Plattform-Tenant genau ein Aggregat. Aggregate-ID
4
- // wird deterministisch aus tenantId abgeleitet (uuidv5, siehe aggregate-id.ts).
3
+ // tier-assignment — exactly one aggregate per platform tenant. The aggregate ID
4
+ // is derived deterministically from tenantId (uuidv5; see aggregate-id.ts).
5
5
  //
6
- // **Tenant-Scope:** automatisch via Kumiko's tenant-scoped projection — die
7
- // `tenantId`-Spalte wird vom Framework als Base-Column hinzugefügt, der
8
- // CrudExecutor befüllt sie aus `event.user.tenantId`. Pro Plattform-Tenant
9
- // gibt es genau eine Tier-Assignment-Row.
6
+ // **Tenant scope:** applied automatically by Kumiko's tenant-scoped projection —
7
+ // the framework adds `tenantId` as a base column, and the CrudExecutor populates
8
+ // it from `event.user.tenantId`. Each platform tenant has exactly one
9
+ // Tier-Assignment row.
10
10
  //
11
- // **Felder**
12
- // - tier: TierName-String (z.B. "free", "pro", "business", "enterprise",
13
- // "self-host"). Welche Tier-Werte gültig sind, definiert die App in
14
- // ihrer TierMap (siehe compose-app.ts) — die Engine selbst hat keine
15
- // enumerierte Tier-Liste.
11
+ // **Fields**
12
+ // - tier: a TierName string (for example, "free", "pro", "business",
13
+ // "enterprise", or "self-host"). The app defines valid tier values in its
14
+ // TierMap (see compose-app.ts); the engine has no enumerated tier list.
16
15
  //
17
- // **Was bewusst NICHT in der Entity steht**
18
- // - tenantId: kommt automatisch als Base-Column.
19
- // - validFrom/validTo: ES-redundant (Events tragen Timestamps nativ,
20
- // time-travel über `ctx.loadAggregate({ asOf })`).
21
- // - addOns: Sprint 1 hat keine Add-Ons. Sprint 4 fügt sie als separate
22
- // `tier-add-on`-Entity hinzu (1:n Relation, ES-saubere Add/Remove-Events
23
- // mit klarer Audit-Granularität statt JSON-Array-Replace).
24
- // - Caps-Werte: pro-Tier-Cap-Definitionen leben in der TierMap der App.
16
+ // **Intentionally omitted from the entity**
17
+ // - tenantId: added automatically as a base column.
18
+ // - validFrom/validTo: redundant for event sourcing (events carry timestamps
19
+ // natively; time travel uses `ctx.loadAggregate({ asOf })`).
20
+ // - addOns: represented by a separate `tier-add-on` entity (1:n relation),
21
+ // allowing event-sourced Add/Remove events with clear audit granularity
22
+ // instead of replacing a JSON array.
23
+ // - Cap values: per-tier cap definitions belong in the app's TierMap.
25
24
  export const tierAssignmentEntity = createEntity({
26
25
  table: "read_tier_assignments",
27
26
  description: "The pricing tier currently assigned to a tenant, plus where the assignment came from (manual grant, billing sync or signup default) — one row per tenant.",
@@ -2,33 +2,35 @@ import { type FeatureDefinition } from "@cosmicdrift/kumiko-framework/engine";
2
2
  import type { TierMap } from "./compose-app.ts";
3
3
  import { type TrialPolicy } from "./trial.ts";
4
4
  /**
5
- * Options for createTierEngineFeature. Both fields optional — wenn beide
6
- * leer, ist die feature nur Storage (back-compat zu legacy `tierEngineFeature`).
5
+ * Options for createTierEngineFeature. Both fields are optional; when both are
6
+ * omitted, the feature provides storage only (backward compatibility with the
7
+ * legacy `tierEngineFeature`).
7
8
  *
8
- * @template TCaps - App-spezifischer Cap-Shape. Type-leakt durch tierMap →
9
- * future capsFor() resolver returnt diesen Shape exakt.
9
+ * @template TCaps - App-specific capability shape. It flows through tierMap,
10
+ * so a future capsFor() resolver returns this exact shape.
10
11
  */
11
12
  export type CreateTierEngineOptions<TCaps extends Readonly<Record<string, unknown>>> = {
12
13
  /**
13
- * Tier-Name der bei Tenant-signup automatisch geschrieben wird. Erfordert
14
- * dass `tierMap` diesen Tier-Namen kennt (Boot-Validation).
15
- * Wenn weggelassen, kein auto-assign — App schreibt manuell.
14
+ * Tier name written automatically when a tenant signs up. `tierMap` must
15
+ * contain this tier name; this is validated at boot.
16
+ * When omitted, no tier is assigned automatically and the app writes it
17
+ * manually.
16
18
  */
17
19
  readonly defaultTier?: string;
18
20
  /**
19
- * App-spezifische Tier-Map. Wenn gesetzt, registriert das feature sich
20
- * als plugin für `tenantTierResolver`-extension → framework auto-wires
21
- * effectiveFeatures pro tenant.
22
- * Wenn weggelassen, keine Resolver-extension — App muss `composeApp`
23
- * oder eigene resolution-logic nutzen (legacy-pattern).
21
+ * App-specific tier map. When set, the feature registers as a plugin for the
22
+ * `tenantTierResolver` extension, so the framework automatically wires
23
+ * effectiveFeatures per tenant.
24
+ * When omitted, no resolver extension is registered; the app must use
25
+ * `composeApp` or its own resolution logic.
24
26
  */
25
27
  readonly tierMap?: TierMap<TCaps>;
26
28
  /**
27
- * Optionale Trial-Phase: jeder Tenant bekommt für `durationHours` ab seinem
28
- * Anlage-Datum zusätzlich die Features von `trial.tier` freigeschaltet,
29
- * danach fällt er automatisch auf sein gespeichertes Tier zurück. Erfordert
30
- * `tierMap` (der Trial-Tier muss ein Key sein). Zeit-abgeleitet aus
31
- * inserted_at — kein Stored-Flag, kein Scheduler.
29
+ * Optional trial phase: each tenant receives the features of `trial.tier` in
30
+ * addition to its stored tier for `durationHours` after creation, then
31
+ * automatically falls back to its stored tier. Requires `tierMap` to contain
32
+ * the trial tier. The result is derived from inserted_at; no stored flag or
33
+ * scheduler is used.
32
34
  */
33
35
  readonly trial?: TrialPolicy;
34
36
  };
@@ -1,45 +1,44 @@
1
- // tier-engine — Pricing-Tier-Mechanik als reguläres Bundled-Feature.
1
+ // tier-engine — pricing-tier mechanics as a regular bundled feature.
2
2
  //
3
- // **Was diese Feature macht:**
4
- // Speichert pro Plattform-Tenant ein Tier-Assignment (welcher Tier ist
5
- // aktiv). Optional (mit `tierMap` in Options): per-tenant feature-set
6
- // resolution via Framework's `tenantTierResolver`-extension — das
7
- // dispatcher-feature-gate fragt automatisch pro request den resolver
8
- // nach dem effective Set für den aktiven Tenant.
3
+ // **What this feature does:**
4
+ // Stores one tier assignment per platform tenant (the active tier). With
5
+ // `tierMap` in the options, it also resolves the per-tenant feature set via
6
+ // the framework's `tenantTierResolver` extension; the dispatcher feature gate
7
+ // automatically asks the resolver for the active tenant's effective set.
9
8
  //
10
- // **Zwei Use-Modes:**
11
- // 1. `createTierEngineFeature()` ohne opts — nur Storage (Standard-CRUD
12
- // für tier-assignment-Entity). Apps die composeApp() oder eigene
13
- // logic nutzen.
14
- // 2. `createTierEngineFeature({ defaultTier, tierMap })` — vollständige
15
- // Tier-Composition. Sprint-8a Pattern für multi-tenant SaaS-Apps.
16
- // Framework auto-wires effectiveFeatures via extension-pickup.
9
+ // **Two usage modes:**
10
+ // 1. `createTierEngineFeature()` without options — storage only (standard CRUD
11
+ // for the tier-assignment entity). Apps can use `composeApp()` or their
12
+ // own logic.
13
+ // 2. `createTierEngineFeature({ defaultTier, tierMap })` — complete tier
14
+ // composition for multi-tenant SaaS apps. The framework auto-wires
15
+ // effectiveFeatures through extension pickup.
17
16
  //
18
- // **Generic über Tier-Werte:** das Feature kennt keine "free"/"pro"/etc.
19
- // konkreten Tier-Werte. App definiert ihre TierMap.
17
+ // **Generic over tier values:** the feature knows no concrete `free`/`pro`/etc.
18
+ // tier values. The app defines its tier map.
20
19
  //
21
- // **Auto-Default-Tier on Tenant-Signup:** wenn `opts.defaultTier` gesetzt
22
- // ist, schreibt ein r.entityHook("postSave", "tenant", phase: inTransaction)
23
- // automatisch eine tier-assignment für den neuen Tenant. Atomic mit
24
- // tenant-create — wenn tier-assignment fail't, tenant-create rolled back.
25
- // Idempotent via deterministic aggregate-id (re-replay re-checkt stream-
26
- // version, skip wenn schon da). Plus: cache-miss-fallback returnt
27
- // defaultTier-features wenn assignment-row fehlt (defense-in-depth gegen
28
- // replay-races wo der hook noch nicht durch ist).
20
+ // **Auto-default tier on tenant signup:** when `opts.defaultTier` is set, an
21
+ // `r.entityHook("postSave", "tenant", phase: inTransaction)` automatically
22
+ // writes a tier assignment for the new tenant. The write is atomic with
23
+ // tenant creation: if it fails, tenant creation is rolled back. It is
24
+ // idempotent through a deterministic aggregate ID; replay re-checks the
25
+ // stream version and skips the write if it already exists. A cache-miss
26
+ // fallback also returns the default tier's features when the assignment row
27
+ // is missing, protecting against races while the hook is still running.
29
28
  //
30
- // **In-Memory-Cache mit Push-Invalidation:**
31
- // Closure-state pro feature-instance hält die effective Sets pro Tenant.
32
- // r.entityHook auf tier-assignment:postSave/postDelete hält cache aktuell.
33
- // Erste-Request-Cold-Cache: pre-load via build(deps) im extension-pickup
34
- // Pfad (boot-time via runDevApp/runProdApp).
29
+ // **In-memory cache with push invalidation:**
30
+ // Closure state per feature instance stores each tenant's effective sets.
31
+ // `r.entityHook` on tier-assignment postSave/postDelete keeps the cache
32
+ // current. The extension-pickup path pre-loads the cache through build(deps)
33
+ // at boot via runDevApp/runProdApp.
35
34
  //
36
- // **SYSTEM_TENANT_ID-Convention:**
37
- // resolver-callback bei call mit SYSTEM_TENANT_ID returnt union aller
38
- // tier-features (für event-dispatcher async-pass + operator-tooling).
39
- // Siehe DispatcherOptions.effectiveFeatures-doc.
35
+ // **SYSTEM_TENANT_ID convention:**
36
+ // A resolver callback invoked with SYSTEM_TENANT_ID returns the union of all
37
+ // tier features for asynchronous event dispatch and operator tooling.
38
+ // See the DispatcherOptions.effectiveFeatures documentation.
40
39
  //
41
- // **Boot-Dependencies:** config + tenant.
42
- // kumiko-lint-ignore app-feature-structure Phase-3 conversion tracked in #2312 (feature.ts > 300 lines)
40
+ // **Boot dependencies:** config + tenant.
41
+ // kumiko-lint-ignore app-feature-structure feature.ts is over 300 lines and not yet split
43
42
  import { buildEntityTable, createEventStoreExecutor, createTenantDb, fetchOne, selectMany, } from "@cosmicdrift/kumiko-framework/db";
44
43
  import { defineEntityCreateHandler, defineEntityListHandler, defineEntityUpdateHandler, defineFeature, defineQueryHandler, HookPhases, SYSTEM_TENANT_ID, TENANT_TIER_RESOLVER_EXT, } from "@cosmicdrift/kumiko-framework/engine";
45
44
  import { getUnscopedAggregateStreamMaxVersion } from "@cosmicdrift/kumiko-framework/event-store";
@@ -61,25 +60,25 @@ import { TIER_ENGINE_I18N } from "./web/i18n.js";
61
60
  // in the App's drizzle/schema.generated.ts.
62
61
  const tierAssignmentTable = buildEntityTable("tier-assignment", tierAssignmentEntity);
63
62
  const log = createFallbackLogger("tier-engine");
64
- // Event-store-executor für direct-write aus dem auto-default-tier-hook.
65
- // Pattern wie tenant/seeding.ts: hook sieht AppContext (kein ctx.write),
66
- // muss aber atomisch mit tenant-create im selben TX schreiben → executor
67
- // direkt aufrufen, nicht via dispatcher.
63
+ // Event-store executor for direct writes from the auto-default-tier hook.
64
+ // Like tenant/seeding.ts, the hook receives AppContext (not ctx.write), but it
65
+ // must write atomically with tenant creation in the same transaction. Call the
66
+ // executor directly rather than going through the dispatcher.
68
67
  const tierAssignmentExecutor = createEventStoreExecutor(tierAssignmentTable, tierAssignmentEntity, {
69
68
  entityName: "tier-assignment",
70
69
  });
71
70
  const adminAccess = { access: { roles: ["TenantAdmin", "SystemAdmin"] } };
72
- // Tier-Wechsel ist Plattform-/Billing-Hoheit — ein Tenant-Admin darf den
73
- // eigenen Tier NIE setzen (sonst Gratis-Self-Upgrade). Daher sind die
74
- // Writes SystemAdmin-only; Reads (list, get-active-tier) bleiben
75
- // TenantAdmin-sichtbar. Auto-default-Hook + Billing schreiben als System,
76
- // hängen also nicht an diesem Handler-Access.
71
+ // Tier changes are controlled by the platform and billing: a TenantAdmin must
72
+ // never set its own tier, which would allow a free self-upgrade. Writes are
73
+ // therefore SystemAdmin-only, while reads (list, get-active-tier) remain visible
74
+ // to TenantAdmin. The auto-default hook and billing write as the system, so they
75
+ // are not subject to this handler access.
77
76
  const writeAccess = { access: { roles: ["SystemAdmin"] } };
78
77
  /**
79
- * Compute the union of features across all tiers — verwendet bei
80
- * SYSTEM_TENANT_ID-resolver-call (operator-tooling, async-event-dispatch).
81
- * Operator-UI sieht alle features unabhängig vom tier-cut, async-events
82
- * laufen tier-agnostic durch.
78
+ * Computes the union of features across all tiers for a
79
+ * SYSTEM_TENANT_ID resolver call used by operator tooling and asynchronous
80
+ * event dispatch. The operator UI sees every feature regardless of tier, and
81
+ * asynchronous events run without tier restrictions.
83
82
  */
84
83
  function unionAllTierFeatures(tierMap) {
85
84
  const all = new Set();
@@ -90,9 +89,9 @@ function unionAllTierFeatures(tierMap) {
90
89
  return all;
91
90
  }
92
91
  /**
93
- * Compute the feature-set for a given tier-name. Unknown tier → empty Set
94
- * (defensive — verwendete tier-namen werden nicht an boot-time validiert
95
- * weil tier-engine generic über tier-Werte ist).
92
+ * Computes the feature set for a tier name. An unknown tier returns an empty
93
+ * Set defensively because tier names are not validated at boot; tier-engine is
94
+ * generic over tier values.
96
95
  */
97
96
  function featuresForTier(tierMap, tierName) {
98
97
  const tier = tierMap[tierName];
@@ -101,10 +100,10 @@ function featuresForTier(tierMap, tierName) {
101
100
  return new Set(tier.features);
102
101
  }
103
102
  /**
104
- * Merge always-on features (non-toggleable framework-base) mit tier-cut
105
- * features (toggleable per tier). Canonical Kumiko: dispatcher-gate
106
- * blockt nur features die explizit `r.toggleable()` haben — alle anderen
107
- * sind immer aktiv. Tier-resolver muss das selbe pattern liefern.
103
+ * Merges always-on features (non-toggleable framework base) with tier-specific
104
+ * features (toggleable per tier). The dispatcher gate blocks only features
105
+ * that explicitly register `r.toggleable()`; all others are always active.
106
+ * The tier resolver must provide the same shape.
108
107
  */
109
108
  function mergeAlwaysOn(alwaysOn, tierFeatures) {
110
109
  const merged = new Set(alwaysOn);
@@ -144,13 +143,14 @@ export function createTierEngineFeature(opts = {}) {
144
143
  description: "Lists the tier-assignment rows visible to the caller with tier name and assignment source; use it to see which plan is stored for a tenant.",
145
144
  }));
146
145
  r.queryHandler(getActiveTierQuery);
147
- // \u2500\u2500 Manueller Tier-Grant (SystemAdmin, ohne Billing) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
148
- // Cross-tenant set + read f\u00fcr den tier-admin-Screen. tier-options liefert
149
- // dem Client die App-Tier-Namen aus der tierMap-Closure (sonst hartkodiert).
146
+ // ── Manual tier grant (SystemAdmin, without billing) ───────────────────────
147
+ // Cross-tenant set and read for the tier-admin screen. tier-options gives
148
+ // the client the app's tier names from the tierMap closure rather than
149
+ // hard-coding them.
150
150
  //
151
151
  // onAssigned runs after commit (the direct executor write fires no postSave
152
- // hook). Late-bound: without tierMap it stays a no-op, the tierMap block
153
- // below installs the real cache update + publish.
152
+ // hook). It is late-bound: without tierMap it remains a no-op; the tierMap
153
+ // block below installs the actual cache update and publication.
154
154
  const onTierAssigned = { fn: () => { } };
155
155
  r.writeHandler(createSetTenantTierWrite({
156
156
  onAssigned: (tenantId, tier) => onTierAssigned.fn(tenantId, tier),
@@ -208,11 +208,11 @@ export function createTierEngineFeature(opts = {}) {
208
208
  dormant: true,
209
209
  });
210
210
  // ───────────────────────────────────────────────────────────────────
211
- // Resolver-extension (only when tierMap is configured)
211
+ // Resolver extension (only when tierMap is configured)
212
212
  // ───────────────────────────────────────────────────────────────────
213
- // skip: ohne tierMap ist die feature nur Storage (legacy back-compat
214
- // zu `tierEngineFeature`). Resolver-extension + invalidation-hooks
215
- // brauchen die tierMap zum Mapping tier-name → feature-set.
213
+ // skip: without tierMap, the feature provides storage only (backward
214
+ // compatibility with `tierEngineFeature`). The resolver extension and
215
+ // invalidation hooks need tierMap to map tier names to feature sets.
216
216
  if (!opts.tierMap)
217
217
  return;
218
218
  const tierMap = opts.tierMap;
@@ -307,7 +307,7 @@ export function createTierEngineFeature(opts = {}) {
307
307
  // tier-assignment.
308
308
  //
309
309
  // **Cross-tenant write:** the executor needs a systemUser WITH tenantId =
310
- // the new tenant (memory `feedback_event_store_tenant_consistency`).
310
+ // the new tenant.
311
311
  if (opts.defaultTier !== undefined) {
312
312
  const defaultTier = opts.defaultTier;
313
313
  const autoDefaultTierHookReason = "seeds the default tier-assignment stream of the tenant just created";
@@ -352,8 +352,7 @@ export function createTierEngineFeature(opts = {}) {
352
352
  // SystemUser for the NEW tenant — the hook is triggered by the signup
353
353
  // user (another tenant, or SystemAdmin), but the tier-assignment has
354
354
  // to land in the stream of the newly created tenant (= aggregate id
355
- // deterministic on newTenantId). Memory
356
- // `feedback_event_store_tenant_consistency`: by.tenantId must equal
355
+ // deterministic on newTenantId), so by.tenantId must equal
357
356
  // the target tenant.
358
357
  const systemUser = {
359
358
  id: "00000000-0000-4000-8000-000000000001",
@@ -458,8 +457,8 @@ export function createTierEngineFeature(opts = {}) {
458
457
  }
459
458
  // Cache miss: the tenant is not in the cache yet (e.g. brand new after
460
459
  // boot, or the defaultTier hook has not fired yet). The default set
461
- // is least-privileged — typically free-tier features. Memory
462
- // `feedback_security_default_on`: secure by default. The trial is NOT
460
+ // is least-privileged, secure by default: typically free-tier features.
461
+ // The trial is NOT
463
462
  // added here (sync/boot-cached, cannot see the passage of time) — the
464
463
  // trialGate below does that on the disabled-gate path.
465
464
  const fallbackTier = opts.defaultTier;
@@ -1,13 +1,12 @@
1
1
  import * as z from "zod";
2
- // get-active-tier — return the current tier-assignment for the calling tenant.
2
+ // get-active-tier — returns the current tier assignment for the calling tenant.
3
3
  //
4
- // **Convenience-wrapper** über `ctx.queryProjection` für die häufigste Frage
5
- // gegen die Engine: „welcher Tier ist gerade aktiv?". Returns null wenn
6
- // noch kein Tier gesetzt — der Caller (composeApp) mappt null → Default-Tier.
4
+ // Wraps `ctx.queryProjection` for the most common engine query: which tier is
5
+ // currently active. Returns null when no tier is assigned; the caller (composeApp)
6
+ // maps null to the default tier.
7
7
  //
8
- // **Tenant-scope:** ctx.queryProjection filtert automatisch nach tenantId.
9
- // Pro Plattform-Tenant existiert per Konvention genau eine
10
- // tier-assignment-Row.
8
+ // **Tenant scope:** `ctx.queryProjection` automatically filters by tenantId.
9
+ // By convention, each platform tenant has exactly one tier-assignment row.
11
10
  export const getActiveTierQuery = {
12
11
  name: "get-active-tier",
13
12
  description: "Returns the tier-assignment row currently active for the caller's own tenant, or null when none is assigned; use it to answer which plan the caller is on.",
@@ -2,10 +2,10 @@ import { buildEntityTable, createTenantDb, fetchOne } from "@cosmicdrift/kumiko-
2
2
  import { defineQueryHandler } from "@cosmicdrift/kumiko-framework/engine";
3
3
  import * as z from "zod";
4
4
  import { tierAssignmentEntity } from "../entity.js";
5
- // Liest das Tier-Assignment eines BELIEBIGEN Tenants (cross-tenant) für den
6
- // tier-admin-Screen. SystemAdmin-only. get-active-tier liest nur den eigenen
7
- // Tenant — hier ein "system"-mode TenantDb auf den Ziel-Tenant (kein Filter),
8
- // damit der Admin das Tier fremder Tenants sehen kann. null wenn noch keins.
5
+ // Reads the tier assignment of ANY tenant (cross-tenant) for the
6
+ // tier-admin screen. SystemAdmin-only. get-active-tier reads only its own
7
+ // tenant; this uses a "system"-mode TenantDb for the target tenant (no filter),
8
+ // so the admin can view another tenant's tier. Returns null if none exists yet.
9
9
  const tierAssignmentTable = buildEntityTable("tier-assignment", tierAssignmentEntity);
10
10
  const GET_TENANT_TIER_REASON = "SystemAdmin reads the tier of the tenant named in the payload";
11
11
  export const getTenantTierQuery = defineQueryHandler({
@@ -5,11 +5,11 @@ export type SetTenantTierOptions = {
5
5
  * and notify the other processes. Without a tierMap there is no resolver
6
6
  * and this is a no-op. */
7
7
  readonly onAssigned?: (tenantId: TenantId, tier: string) => void;
8
- /** Tier-Namen aus der tierMap-Closure — ohne sie (storage-only-Mode) bleibt
9
- * `tier` unvalidiert außer Length/Non-Empty. Mit ihr rejected der Handler
10
- * einen unbekannten Tier-Namen statt ihn stillschweigend durchzuschreiben
11
- * (featuresForTier gibt für unbekannte Namen defensiv ein leeres Set
12
- * zurück — der Tenant verliert sonst lautlos alle Tier-Gates). */
8
+ /** Without the tierMap closure (storage-only mode), `tier` is validated only for
9
+ * length and non-emptiness. With it, the handler rejects unknown tier names
10
+ * instead of silently writing them through. (featuresForTier defensively
11
+ * returns an empty set for unknown names; otherwise the tenant would silently
12
+ * lose all tier gates.) */
13
13
  readonly validTiers?: ReadonlySet<string>;
14
14
  };
15
15
  export declare function createSetTenantTierWrite(opts?: SetTenantTierOptions): import("@cosmicdrift/kumiko-types/define-handler").WriteHandlerDefinition<"set-tenant-tier", z.ZodObject<{
@@ -5,9 +5,9 @@ import { requireForTenant } from "../../shared/index.js";
5
5
  import { tierAssignmentAggregateId } from "../aggregate-id.js";
6
6
  import { tierAssignmentEntity } from "../entity.js";
7
7
  import { TierAssignmentSources } from "../web/constants.js";
8
- // SystemAdmin setzt das Tier eines BELIEBIGEN Tenants — manueller Grant ohne
9
- // Billing. Cross-tenant, daher SystemAdmin-only (kein TenantAdmin: sonst
10
- // Gratis-Self-Upgrade).
8
+ // A SystemAdmin can set the tier of ANY tenant as a manual grant without
9
+ // billing. This is cross-tenant, so it is restricted to SystemAdmin (not
10
+ // TenantAdmin, which would allow free self-upgrades).
11
11
  //
12
12
  // Cross-tenant mechanics: ctx.forTenant(tenantId) yields a tenant-mode db bound to the target plus
13
13
  // the streamTenantId, so the event lands in the target's stream with the operator as actor.