@cosmicdrift/kumiko-samples 0.389.0 → 0.390.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 (296) hide show
  1. package/package.json +1 -1
  2. package/packages/bundled-features/package.json +25 -13
  3. package/packages/bundled-features/src/audit/feature.ts +1 -1
  4. package/packages/bundled-features/src/auth-email-password/auth-user-row.ts +1 -1
  5. package/packages/bundled-features/src/auth-email-password/bootstrap.ts +13 -1
  6. package/packages/bundled-features/src/auth-email-password/changes.json +6 -0
  7. package/packages/bundled-features/src/auth-email-password/feature.ts +2 -2
  8. package/packages/bundled-features/src/auth-email-password/handlers/change-password.write.ts +7 -7
  9. package/packages/bundled-features/src/auth-email-password/handlers/confirm-account-unlock.write.ts +3 -3
  10. package/packages/bundled-features/src/auth-email-password/handlers/confirm-token-flow.ts +5 -5
  11. package/packages/bundled-features/src/auth-email-password/handlers/invite-accept-with-login.write.ts +9 -7
  12. package/packages/bundled-features/src/auth-email-password/handlers/invite-accept.write.ts +11 -7
  13. package/packages/bundled-features/src/auth-email-password/handlers/invite-create.write.ts +4 -4
  14. package/packages/bundled-features/src/auth-email-password/handlers/invite-info.query.ts +2 -2
  15. package/packages/bundled-features/src/auth-email-password/handlers/invite-signup-complete.write.ts +9 -7
  16. package/packages/bundled-features/src/auth-email-password/handlers/login.write.ts +23 -16
  17. package/packages/bundled-features/src/auth-email-password/handlers/reset-password.write.ts +3 -2
  18. package/packages/bundled-features/src/auth-email-password/handlers/signup-confirm.write.ts +12 -12
  19. package/packages/bundled-features/src/auth-email-password/handlers/signup-request.write.ts +12 -8
  20. package/packages/bundled-features/src/auth-email-password/handlers/switch-tenant-mfa-gate.write.ts +4 -2
  21. package/packages/bundled-features/src/auth-email-password/handlers/token-request-handler.ts +2 -2
  22. package/packages/bundled-features/src/auth-email-password/handlers/verify-email.write.ts +3 -2
  23. package/packages/bundled-features/src/auth-email-password/seeding.ts +14 -9
  24. package/packages/bundled-features/src/auth-foundation/feature.ts +13 -4
  25. package/packages/bundled-features/src/auth-mfa/handlers/disable.write.ts +5 -5
  26. package/packages/bundled-features/src/auth-mfa/handlers/enable-confirm-preauth.write.ts +24 -14
  27. package/packages/bundled-features/src/auth-mfa/handlers/enable-confirm.write.ts +9 -3
  28. package/packages/bundled-features/src/auth-mfa/handlers/enable-start-preauth.write.ts +6 -1
  29. package/packages/bundled-features/src/auth-mfa/handlers/enable-start.write.ts +3 -1
  30. package/packages/bundled-features/src/auth-mfa/handlers/reencrypt.job.ts +14 -9
  31. package/packages/bundled-features/src/auth-mfa/handlers/regenerate-recovery.write.ts +5 -4
  32. package/packages/bundled-features/src/auth-mfa/handlers/verify.write.ts +25 -14
  33. package/packages/bundled-features/src/auth-mfa/mfa-code-verifier.ts +10 -4
  34. package/packages/bundled-features/src/auth-mfa/mfa-status-checker.ts +9 -3
  35. package/packages/bundled-features/src/auth-mfa/verify-factor.ts +1 -1
  36. package/packages/bundled-features/src/billing-foundation/billing-info-query.ts +2 -2
  37. package/packages/bundled-features/src/billing-foundation/changes.json +6 -0
  38. package/packages/bundled-features/src/billing-foundation/consumer-protection/consent-gate.ts +1 -1
  39. package/packages/bundled-features/src/billing-foundation/consumer-protection/issue-confirmation.ts +5 -5
  40. package/packages/bundled-features/src/billing-foundation/consumer-protection/register-consent.ts +10 -7
  41. package/packages/bundled-features/src/billing-foundation/consumer-protection/register-termination.ts +15 -12
  42. package/packages/bundled-features/src/billing-foundation/consumer-protection/termination-open-cancels.ts +22 -0
  43. package/packages/bundled-features/src/billing-foundation/consumer-protection/termination-provider-lock.ts +4 -0
  44. package/packages/bundled-features/src/billing-foundation/consumer-protection/termination-receipt-limit.ts +4 -4
  45. package/packages/bundled-features/src/billing-foundation/consumer-protection/termination-record.ts +17 -58
  46. package/packages/bundled-features/src/billing-foundation/consumer-protection/termination-request.ts +10 -8
  47. package/packages/bundled-features/src/billing-foundation/consumer-protection/termination-revoke.ts +18 -15
  48. package/packages/bundled-features/src/billing-foundation/events.ts +1 -1
  49. package/packages/bundled-features/src/billing-foundation/feature.ts +8 -3
  50. package/packages/bundled-features/src/billing-foundation/get-subscription-for-tenant.ts +1 -1
  51. package/packages/bundled-features/src/billing-foundation/handlers/process-event.write.ts +5 -5
  52. package/packages/bundled-features/src/billing-foundation/handlers/process-payment-event.write.ts +3 -3
  53. package/packages/bundled-features/src/billing-foundation/plan-catalog.ts +2 -2
  54. package/packages/bundled-features/src/billing-foundation/projection.ts +1 -1
  55. package/packages/bundled-features/src/billing-foundation/types.ts +1 -1
  56. package/packages/bundled-features/src/cap-counter/aggregate-id.ts +1 -1
  57. package/packages/bundled-features/src/cap-counter/book-cap-usage.ts +5 -4
  58. package/packages/bundled-features/src/cap-counter/cap-reservation.ts +1 -1
  59. package/packages/bundled-features/src/cap-counter/constants.ts +1 -1
  60. package/packages/bundled-features/src/cap-counter/feature.ts +2 -2
  61. package/packages/bundled-features/src/cap-counter/handlers/increment-rolling.write.ts +1 -1
  62. package/packages/bundled-features/src/cap-counter/reservation-chain.ts +1 -1
  63. package/packages/bundled-features/src/cap-counter/with-cap-enforcement.ts +4 -4
  64. package/packages/bundled-features/src/cap-overview/handlers/caps-usage.query.ts +1 -1
  65. package/packages/bundled-features/src/cap-overview/handlers/tenant-caps-list.query.ts +1 -1
  66. package/packages/bundled-features/src/compliance-profiles/seeding.ts +12 -7
  67. package/packages/bundled-features/src/config/feature.ts +6 -6
  68. package/packages/bundled-features/src/config/handlers/cascade.query.ts +1 -1
  69. package/packages/bundled-features/src/config/handlers/readiness.query.ts +1 -1
  70. package/packages/bundled-features/src/config/handlers/reencrypt.job.ts +23 -13
  71. package/packages/bundled-features/src/config/handlers/reset.write.ts +3 -3
  72. package/packages/bundled-features/src/config/handlers/selected-extensions.query.ts +1 -1
  73. package/packages/bundled-features/src/config/handlers/set.write.ts +4 -4
  74. package/packages/bundled-features/src/config/handlers/values.query.ts +1 -1
  75. package/packages/bundled-features/src/crypto-shredding/handlers/forget-subject.write.ts +8 -8
  76. package/packages/bundled-features/src/crypto-shredding/resolve-file-bytes-deleter.ts +3 -3
  77. package/packages/bundled-features/src/custom-fields/changes.json +6 -0
  78. package/packages/bundled-features/src/custom-fields/handlers/clear-custom-field.write.ts +1 -1
  79. package/packages/bundled-features/src/custom-fields/handlers/delete-system-field.write.ts +1 -1
  80. package/packages/bundled-features/src/custom-fields/handlers/delete-tenant-field.write.ts +1 -1
  81. package/packages/bundled-features/src/custom-fields/handlers/set-custom-field.write.ts +1 -1
  82. package/packages/bundled-features/src/custom-fields/index.ts +4 -0
  83. package/packages/bundled-features/src/data-retention/feature.ts +1 -1
  84. package/packages/bundled-features/src/data-retention/run-retention-cleanup.ts +12 -2
  85. package/packages/bundled-features/src/delivery/attempt-log.ts +1 -1
  86. package/packages/bundled-features/src/delivery/delivery-service.ts +6 -5
  87. package/packages/bundled-features/src/delivery/feature.ts +2 -2
  88. package/packages/bundled-features/src/delivery/jobs.ts +11 -11
  89. package/packages/bundled-features/src/delivery/testing.ts +1 -1
  90. package/packages/bundled-features/src/document-ingest-foundation/events.ts +1 -1
  91. package/packages/bundled-features/src/feature-toggles/handlers/registered.query.ts +1 -1
  92. package/packages/bundled-features/src/feature-toggles/handlers/set.write.ts +1 -1
  93. package/packages/bundled-features/src/feature-toggles/toggle-sync-signal.ts +1 -1
  94. package/packages/bundled-features/src/file-derivatives/feature.ts +2 -2
  95. package/packages/bundled-features/src/file-derivatives/handlers/public-variant-by-file-ref.query.ts +5 -1
  96. package/packages/bundled-features/src/file-derivatives/handlers/public-variant.query.ts +7 -5
  97. package/packages/bundled-features/src/file-foundation/feature.ts +1 -1
  98. package/packages/bundled-features/src/file-foundation/read-file-ref-content.ts +7 -5
  99. package/packages/bundled-features/src/file-provider-s3/feature.ts +4 -1
  100. package/packages/bundled-features/src/files-tenant-data/handlers/sweep-orphaned-derivatives.job.ts +8 -8
  101. package/packages/bundled-features/src/form-draft/feature.ts +1 -1
  102. package/packages/bundled-features/src/form-draft/handlers/cleanup.job.ts +22 -12
  103. package/packages/bundled-features/src/form-draft/handlers/discard.write.ts +3 -3
  104. package/packages/bundled-features/src/form-draft/handlers/get.query.ts +1 -1
  105. package/packages/bundled-features/src/foundation-shared/config-helpers.ts +1 -1
  106. package/packages/bundled-features/src/inbound-mail-foundation/events.ts +1 -1
  107. package/packages/bundled-features/src/inbound-mail-foundation/feature.ts +1 -1
  108. package/packages/bundled-features/src/inbound-mail-foundation/handlers/account-state.ts +2 -2
  109. package/packages/bundled-features/src/inbound-mail-foundation/handlers/connect-account.write.ts +1 -1
  110. package/packages/bundled-features/src/inbound-mail-foundation/handlers/disconnect-account.write.ts +1 -1
  111. package/packages/bundled-features/src/inbound-mail-foundation/handlers/ingest-message.write.ts +10 -10
  112. package/packages/bundled-features/src/inbound-mail-foundation/handlers/update-account.write.ts +1 -1
  113. package/packages/bundled-features/src/inbound-mail-foundation/projection.ts +1 -1
  114. package/packages/bundled-features/src/inbound-mail-foundation/watch-supervisor.ts +1 -1
  115. package/packages/bundled-features/src/inbound-provider-imap/feature.ts +4 -1
  116. package/packages/bundled-features/src/jobs/changes.json +6 -0
  117. package/packages/bundled-features/src/jobs/events.ts +1 -1
  118. package/packages/bundled-features/src/jobs/handlers/consumer.write.ts +7 -4
  119. package/packages/bundled-features/src/jobs/handlers/projection-rebuild.job.ts +1 -1
  120. package/packages/bundled-features/src/jobs/handlers/reindex-entity.job.ts +11 -5
  121. package/packages/bundled-features/src/jobs/handlers/retention-cleanup.job.ts +1 -1
  122. package/packages/bundled-features/src/jobs/handlers/retry.write.ts +1 -1
  123. package/packages/bundled-features/src/jobs/handlers/stale-run-sweep.job.ts +1 -1
  124. package/packages/bundled-features/src/jobs/handlers/trigger.write.ts +2 -2
  125. package/packages/bundled-features/src/jobs/job-run-logger.ts +139 -90
  126. package/packages/bundled-features/src/legal-pages/README.md +1 -1
  127. package/packages/bundled-features/src/legal-pages/lib/boot-check.ts +12 -8
  128. package/packages/bundled-features/src/mail-foundation/feature.ts +2 -2
  129. package/packages/bundled-features/src/mail-transport-smtp/changes.json +6 -0
  130. package/packages/bundled-features/src/mail-transport-smtp/feature.ts +4 -1
  131. package/packages/bundled-features/src/managed-pages/seeding.ts +13 -8
  132. package/packages/bundled-features/src/notes-history/handlers/add-note.write.ts +1 -1
  133. package/packages/bundled-features/src/personal-access-tokens/feature.ts +1 -1
  134. package/packages/bundled-features/src/personal-access-tokens/handlers/create.write.ts +2 -2
  135. package/packages/bundled-features/src/personal-access-tokens/handlers/revoke.write.ts +1 -1
  136. package/packages/bundled-features/src/rate-limiting/handlers/status.query.ts +2 -2
  137. package/packages/bundled-features/src/readiness/handlers/status.query.ts +4 -1
  138. package/packages/bundled-features/src/renderer-foundation/api.ts +3 -3
  139. package/packages/bundled-features/src/secrets/announce-secret-change.ts +4 -4
  140. package/packages/bundled-features/src/secrets/feature.ts +9 -9
  141. package/packages/bundled-features/src/secrets/handlers/delete.write.ts +4 -3
  142. package/packages/bundled-features/src/secrets/handlers/rotate.job.ts +13 -8
  143. package/packages/bundled-features/src/secrets/handlers/set.write.ts +4 -3
  144. package/packages/bundled-features/src/secrets/secrets-context.ts +16 -6
  145. package/packages/bundled-features/src/secrets/write-gate.ts +1 -1
  146. package/packages/bundled-features/src/seo/feature.ts +1 -1
  147. package/packages/bundled-features/src/sessions/changes.json +12 -0
  148. package/packages/bundled-features/src/sessions/feature.ts +1 -1
  149. package/packages/bundled-features/src/sessions/handlers/cleanup.job.ts +2 -2
  150. package/packages/bundled-features/src/sessions/handlers/detail.query.ts +5 -2
  151. package/packages/bundled-features/src/sessions/handlers/list.query.ts +5 -2
  152. package/packages/bundled-features/src/sessions/handlers/mine.query.ts +5 -2
  153. package/packages/bundled-features/src/sessions/handlers/revoke-all-for-user.write.ts +3 -3
  154. package/packages/bundled-features/src/sessions/handlers/revoke-all-others.write.ts +1 -1
  155. package/packages/bundled-features/src/sessions/handlers/revoke.write.ts +1 -1
  156. package/packages/bundled-features/src/sessions/screens.ts +8 -4
  157. package/packages/bundled-features/src/sessions/session-revoked-event.ts +1 -1
  158. package/packages/bundled-features/src/sessions/web/session-device-cell.tsx +10 -12
  159. package/packages/bundled-features/src/sessions/web/user-agent.ts +12 -0
  160. package/packages/bundled-features/src/shared/index.ts +15 -0
  161. package/packages/bundled-features/src/shared/purge-files-reaching-subject.ts +12 -2
  162. package/packages/bundled-features/src/shared/require-for-tenant.ts +7 -5
  163. package/packages/bundled-features/src/shared/stream-tenant-backfill.ts +201 -0
  164. package/packages/bundled-features/src/shared/stream-tenant-derived-state.ts +107 -0
  165. package/packages/bundled-features/src/step-dispatcher/feature.ts +1 -1
  166. package/packages/bundled-features/src/subscription-dodo/plugin-methods.ts +1 -1
  167. package/packages/bundled-features/src/subscription-dodo/runtime.ts +7 -7
  168. package/packages/bundled-features/src/subscription-stripe/plugin-methods.ts +5 -3
  169. package/packages/bundled-features/src/subscription-stripe/runtime.ts +7 -7
  170. package/packages/bundled-features/src/template-resolver/api.ts +3 -3
  171. package/packages/bundled-features/src/template-resolver/changes.json +18 -0
  172. package/packages/bundled-features/src/template-resolver/handlers/bundle-import.ts +5 -4
  173. package/packages/bundled-features/src/template-resolver/handlers/copy-locale.write.ts +2 -2
  174. package/packages/bundled-features/src/template-resolver/handlers/export-bundle.query.ts +1 -1
  175. package/packages/bundled-features/src/template-resolver/handlers/overview.query.ts +2 -2
  176. package/packages/bundled-features/src/template-resolver/handlers/send-test-shared.ts +1 -1
  177. package/packages/bundled-features/src/template-resolver/handlers/send-test.write.ts +2 -2
  178. package/packages/bundled-features/src/template-resolver/handlers/tenant-override-selection.ts +6 -2
  179. package/packages/bundled-features/src/template-resolver/handlers/tenant-overrides.query.ts +4 -2
  180. package/packages/bundled-features/src/template-resolver/handlers/usage.query.ts +1 -1
  181. package/packages/bundled-features/src/template-resolver/seeding.ts +12 -2
  182. package/packages/bundled-features/src/template-resolver/store-template-resource.ts +18 -13
  183. package/packages/bundled-features/src/template-resolver/template-resources.ts +4 -4
  184. package/packages/bundled-features/src/template-resolver/testing.ts +2 -2
  185. package/packages/bundled-features/src/template-resolver/web/document-insert-fields.tsx +222 -0
  186. package/packages/bundled-features/src/template-resolver/web/document-insert-model.ts +164 -0
  187. package/packages/bundled-features/src/template-resolver/web/document-insert-panel.tsx +115 -0
  188. package/packages/bundled-features/src/template-resolver/web/document-tiptap-bubble.tsx +177 -0
  189. package/packages/bundled-features/src/template-resolver/web/document-tiptap-content.tsx +38 -0
  190. package/packages/bundled-features/src/template-resolver/web/document-tiptap-context.ts +119 -0
  191. package/packages/bundled-features/src/template-resolver/web/document-tiptap-editor.tsx +51 -1098
  192. package/packages/bundled-features/src/template-resolver/web/document-tiptap-helpers.ts +161 -0
  193. package/packages/bundled-features/src/template-resolver/web/document-tiptap-layout.tsx +83 -0
  194. package/packages/bundled-features/src/template-resolver/web/document-tiptap-toolbar-groups.tsx +153 -0
  195. package/packages/bundled-features/src/template-resolver/web/document-tiptap-toolbar.tsx +182 -0
  196. package/packages/bundled-features/src/template-resolver/web/editor-handle.ts +18 -0
  197. package/packages/bundled-features/src/template-resolver/web/placeholder-line-editor.tsx +19 -6
  198. package/packages/bundled-features/src/template-resolver/web/use-document-tiptap-model.ts +138 -0
  199. package/packages/bundled-features/src/tenant/changes.json +19 -0
  200. package/packages/bundled-features/src/tenant/handlers/cancel-invitation.write.ts +1 -1
  201. package/packages/bundled-features/src/tenant/handlers/memberships.query.ts +1 -1
  202. package/packages/bundled-features/src/tenant/handlers/remove-member.write.ts +2 -2
  203. package/packages/bundled-features/src/tenant/handlers/update-member-roles.write.ts +1 -1
  204. package/packages/bundled-features/src/tenant/index.ts +5 -0
  205. package/packages/bundled-features/src/tenant/invited-membership.ts +6 -1
  206. package/packages/bundled-features/src/tenant/schema/tenant.ts +4 -1
  207. package/packages/bundled-features/src/tenant/seeding.ts +65 -62
  208. package/packages/bundled-features/src/tenant/stream-tenant-backfill.ts +115 -0
  209. package/packages/bundled-features/src/tenant/testing.ts +77 -0
  210. package/packages/bundled-features/src/tenant-handover/events.ts +1 -1
  211. package/packages/bundled-features/src/tenant-handover/handlers/claim.write.ts +1 -1
  212. package/packages/bundled-features/src/tenant-lifecycle/feature.ts +5 -5
  213. package/packages/bundled-features/src/tenant-lifecycle/handlers/cancel-destruction.write.ts +22 -10
  214. package/packages/bundled-features/src/tenant-lifecycle/handlers/request-destruction.write.ts +22 -11
  215. package/packages/bundled-features/src/tenant-lifecycle/run-tenant-destroy.ts +23 -12
  216. package/packages/bundled-features/src/tenant-lifecycle/stages.ts +7 -3
  217. package/packages/bundled-features/src/tenant-lifecycle/testing.ts +9 -8
  218. package/packages/bundled-features/src/tier-engine/entity.ts +1 -1
  219. package/packages/bundled-features/src/tier-engine/feature.ts +8 -3
  220. package/packages/bundled-features/src/tier-engine/handlers/active-tier.query.ts +3 -3
  221. package/packages/bundled-features/src/tier-engine/handlers/get-tenant-tier.query.ts +7 -1
  222. package/packages/bundled-features/src/tier-engine/handlers/set-tenant-tier.write.ts +3 -3
  223. package/packages/bundled-features/src/user/db/queries/stream-tenant-backfill.ts +71 -97
  224. package/packages/bundled-features/src/user/handlers/find-for-auth.query.ts +2 -2
  225. package/packages/bundled-features/src/user/handlers/update-roles.ts +2 -2
  226. package/packages/bundled-features/src/user/index.ts +2 -0
  227. package/packages/bundled-features/src/user/invited-global-roles.ts +6 -1
  228. package/packages/bundled-features/src/user/principal-status.ts +1 -1
  229. package/packages/bundled-features/src/user/seeding.ts +24 -6
  230. package/packages/bundled-features/src/user/testing.ts +22 -0
  231. package/packages/bundled-features/src/user-data-rights/COMPLIANCE.md +1 -1
  232. package/packages/bundled-features/src/user-data-rights/README.md +1 -1
  233. package/packages/bundled-features/src/user-data-rights/audit-download.ts +12 -2
  234. package/packages/bundled-features/src/user-data-rights/changes.json +24 -0
  235. package/packages/bundled-features/src/user-data-rights/feature.ts +29 -24
  236. package/packages/bundled-features/src/user-data-rights/handlers/confirm-deletion-by-token.write.ts +1 -1
  237. package/packages/bundled-features/src/user-data-rights/handlers/deletion-grace-period.ts +1 -1
  238. package/packages/bundled-features/src/user-data-rights/handlers/download-by-job.query.ts +2 -2
  239. package/packages/bundled-features/src/user-data-rights/handlers/download-by-token.query.ts +2 -2
  240. package/packages/bundled-features/src/user-data-rights/handlers/request-deletion.write.ts +1 -1
  241. package/packages/bundled-features/src/user-data-rights/handlers/restrict-account.write.ts +4 -4
  242. package/packages/bundled-features/src/user-data-rights/handlers/run-forget-cleanup.write.ts +12 -6
  243. package/packages/bundled-features/src/user-data-rights/index.ts +2 -0
  244. package/packages/bundled-features/src/user-data-rights/lib/mail-transport-resolver.ts +1 -1
  245. package/packages/bundled-features/src/user-data-rights/lib/storage-provider-resolver.ts +1 -1
  246. package/packages/bundled-features/src/user-data-rights/lib/update-user-lifecycle.ts +6 -1
  247. package/packages/bundled-features/src/user-data-rights/run-export-jobs.ts +8 -2
  248. package/packages/bundled-features/src/user-data-rights/run-forget-cleanup.ts +14 -3
  249. package/packages/bundled-features/src/user-data-rights/run-user-export.ts +11 -1
  250. package/packages/bundled-features/src/user-data-rights/web/constants.ts +10 -0
  251. package/packages/bundled-features/src/user-data-rights/web/index.ts +6 -1
  252. package/packages/bundled-features/src/user-profile/handlers/change-email.write.ts +8 -6
  253. package/packages/bundled-features/src/waitlist/handlers/export-purge.write.ts +1 -1
  254. package/packages/bundled-features/src/waitlist/handlers/invite.write.ts +2 -2
  255. package/packages/bundled-features/src/waitlist/handlers/reject.write.ts +1 -1
  256. package/packages/bundled-features/src/waitlist/handlers/submit.write.ts +9 -4
  257. package/packages/bundled-features/src/waitlist/legacy-migrate.ts +6 -1
  258. package/packages/bundled-features/src/waitlist/link-on-signup.ts +7 -1
  259. package/packages/bundled-features/src/workflow-runner/changes.json +6 -0
  260. package/packages/bundled-features/src/workflow-runner/db/queries/due-runs.ts +1 -1
  261. package/packages/bundled-features/src/workflow-runner/event-subscriber.ts +4 -3
  262. package/packages/bundled-features/src/workflow-runner/event-trigger.ts +2 -1
  263. package/packages/bundled-features/src/workflow-runner/feature.ts +2 -2
  264. package/packages/bundled-features/src/workflow-runner/handlers/resume-run.write.ts +8 -8
  265. package/packages/bundled-features/src/workflow-runner/runner.ts +6 -4
  266. package/samples/apps/cap-billing-demo/src/feature.ts +19 -5
  267. package/samples/apps/config-demo/src/app/server.ts +1 -1
  268. package/samples/apps/styleguide/src/app/server.ts +2 -2
  269. package/samples/apps/use-all-bundled/feature-manifest.json +1 -1
  270. package/samples/apps/use-all-bundled/src/app/seed.ts +12 -2
  271. package/samples/apps/user-data-rights-demo/README.md +1 -1
  272. package/samples/apps/user-data-rights-demo/src/feature.ts +3 -2
  273. package/samples/recipes/api-worker-split/README.md +2 -1
  274. package/samples/recipes/api-worker-split/src/feature.ts +2 -1
  275. package/samples/recipes/cross-feature-events/README.md +5 -5
  276. package/samples/recipes/cross-feature-events/package.json +1 -1
  277. package/samples/recipes/cross-feature-events/src/feature.ts +4 -4
  278. package/samples/recipes/event-sourcing/README.md +5 -5
  279. package/samples/recipes/event-sourcing/package.json +1 -1
  280. package/samples/recipes/event-sourcing/src/feature.ts +15 -15
  281. package/samples/recipes/files-post-processing/README.md +1 -1
  282. package/samples/recipes/files-post-processing/package.json +1 -1
  283. package/samples/recipes/files-post-processing/src/feature.ts +6 -4
  284. package/samples/recipes/lane-routing/package.json +1 -1
  285. package/samples/recipes/legal-pages/README.md +2 -2
  286. package/samples/recipes/lifecycle-hooks/README.md +2 -2
  287. package/samples/recipes/lifecycle-hooks/src/feature.ts +1 -1
  288. package/samples/recipes/managed-config/README.md +3 -3
  289. package/samples/recipes/search/README.md +1 -1
  290. package/samples/recipes/search/src/feature.ts +3 -3
  291. package/samples/recipes/secrets-demo/README.md +1 -1
  292. package/samples/recipes/secrets-demo/src/feature.ts +5 -2
  293. package/samples/recipes/state-machine/src/events.ts +1 -1
  294. package/samples/recipes/state-machine/src/reducer.ts +1 -1
  295. package/samples/recipes/workflow-engine/src/resume-loop.ts +4 -4
  296. package/samples/recipes/workflow-engine/src/workflow-runner.ts +2 -2
@@ -4,4 +4,81 @@
4
4
  // stable contract here; test-specific options do not belong in this module,
5
5
  // because they could break development boots when a lockout-test option is added.
6
6
 
7
+ import type { DbConnection } from "@cosmicdrift/kumiko-framework/db";
8
+ import type { TenantId } from "@cosmicdrift/kumiko-framework/engine";
9
+ import { TestUsers } from "@cosmicdrift/kumiko-framework/seeding";
10
+ import {
11
+ deleteRowViaEventStore,
12
+ updateRowViaEventStore,
13
+ } from "@cosmicdrift/kumiko-testing/helpers";
14
+ import { tenantInvitationEntity, tenantInvitationsTable } from "./invitation-table.ts";
15
+ import { tenantMembershipEntity, tenantMembershipsTable } from "./membership-table.ts";
16
+ import { tenantEntity, tenantTable } from "./schema/tenant.ts";
17
+
7
18
  export * from "./seeding.ts";
19
+
20
+ const membershipTarget = {
21
+ table: tenantMembershipsTable,
22
+ entity: tenantMembershipEntity,
23
+ entityName: "tenant-membership",
24
+ } as const;
25
+
26
+ const tenantTarget = { table: tenantTable, entity: tenantEntity, entityName: "tenant" } as const;
27
+
28
+ type MembershipKey = { readonly userId: string; readonly tenantId: TenantId };
29
+
30
+ // The membership stream lives on the membership's own tenant, so actor and stream tenant both use it.
31
+ export function setMembershipRolesViaEventStore(
32
+ db: DbConnection,
33
+ params: MembershipKey & { readonly roles: readonly string[] },
34
+ ): Promise<void> {
35
+ const { userId, tenantId, roles } = params;
36
+ return updateRowViaEventStore(
37
+ db,
38
+ membershipTarget,
39
+ { userId, tenantId },
40
+ { roles: JSON.stringify(roles) },
41
+ { tenantId, streamTenantId: tenantId },
42
+ );
43
+ }
44
+
45
+ export function deleteMembershipViaEventStore(db: DbConnection, key: MembershipKey): Promise<void> {
46
+ return deleteRowViaEventStore(
47
+ db,
48
+ membershipTarget,
49
+ { userId: key.userId, tenantId: key.tenantId },
50
+ { tenantId: key.tenantId, streamTenantId: key.tenantId },
51
+ );
52
+ }
53
+
54
+ // Tenant streams live on the creator's tenant, which is the seed SystemAdmin's for every tenant a test creates.
55
+ export function updateTenantViaEventStore(
56
+ db: DbConnection,
57
+ tenantId: TenantId,
58
+ changes: Readonly<Record<string, unknown>>,
59
+ actorTenantId: TenantId = TestUsers.systemAdmin.tenantId,
60
+ ): Promise<void> {
61
+ return updateRowViaEventStore(db, tenantTarget, { id: tenantId }, changes, {
62
+ tenantId: actorTenantId,
63
+ });
64
+ }
65
+
66
+ // Invitation streams live on the inviting tenant.
67
+ export function updateInvitationViaEventStore(
68
+ db: DbConnection,
69
+ email: string,
70
+ changes: Readonly<Record<string, unknown>>,
71
+ tenantId: TenantId,
72
+ ): Promise<void> {
73
+ return updateRowViaEventStore(
74
+ db,
75
+ {
76
+ table: tenantInvitationsTable,
77
+ entity: tenantInvitationEntity,
78
+ entityName: "tenant-invitation",
79
+ },
80
+ { email },
81
+ changes,
82
+ { tenantId },
83
+ );
84
+ }
@@ -8,7 +8,7 @@ import * as z from "zod";
8
8
  //
9
9
  // _SHORT — r.defineEvent(short, schema) in feature.ts, framework prefixes it
10
10
  // to the QN below.
11
- // _QN — ctx.unsafeAppendEvent({ type })'s `type` field.
11
+ // _QN — ctx.events.unsafeAppend({ type })'s `type` field.
12
12
  export const TENANT_HANDOVER_CLAIMED_EVENT_SHORT = "claimed" as const;
13
13
  export const TENANT_HANDOVER_CLAIMED_EVENT_QN = "tenant-handover:event:claimed" as const;
14
14
  export const TENANT_HANDOVER_CLAIM_AGGREGATE_TYPE = "tenant-handover-claim" as const;
@@ -92,7 +92,7 @@ export function createClaimTenantHandoverHandler(opts: ClaimTenantHandoverOption
92
92
  // Own aggregate, decoupled from the transferred root's stream (see
93
93
  // events.ts) — a fresh id needs no predecessor version and can't
94
94
  // conflict with a concurrent write on the entity it describes.
95
- await ctx.unsafeAppendEvent({
95
+ await ctx.events.unsafeAppend({
96
96
  aggregateId: generateId(),
97
97
  aggregateType: TENANT_HANDOVER_CLAIM_AGGREGATE_TYPE,
98
98
  type: TENANT_HANDOVER_CLAIMED_EVENT_QN,
@@ -150,11 +150,11 @@ export function createTenantLifecycleFeature(): FeatureDefinition {
150
150
  db: ctx.db.unsafeRaw() as import("@cosmicdrift/kumiko-framework/db").DbConnection, // @cast-boundary db-operator — jobs never run inside a DbTx
151
151
  registry: ctx.registry,
152
152
  now,
153
- log: (message) => ctx.log?.warn(message),
154
- fileProviderResolver: ctx._fileProviderResolver,
155
- searchAdapter: ctx.searchAdapter,
156
- escapeHatchAuditSink: ctx._escapeHatchAuditSink,
157
- escapeHatchAuditLog: ctx.log,
153
+ log: (message) => ctx.obs.log?.warn(message),
154
+ fileProviderResolver: ctx.services._fileProviderResolver,
155
+ searchAdapter: ctx.services.searchAdapter,
156
+ escapeHatchAuditSink: ctx.services._escapeHatchAuditSink,
157
+ escapeHatchAuditLog: ctx.obs.log,
158
158
  actor: ctx.systemUser.id,
159
159
  });
160
160
  },
@@ -1,10 +1,11 @@
1
1
  import { createEventStoreExecutor, fetchOne } from "@cosmicdrift/kumiko-framework/db";
2
- import { defineWriteHandler } from "@cosmicdrift/kumiko-framework/engine";
2
+ import { defineWriteHandler, SYSTEM_TENANT_ID } from "@cosmicdrift/kumiko-framework/engine";
3
3
  import { UnprocessableError, writeFailure } from "@cosmicdrift/kumiko-framework/errors";
4
+ import { appendDomainEventCore } from "@cosmicdrift/kumiko-framework/pipeline";
4
5
  import * as z from "zod";
5
6
  import { isWithinGracePeriod } from "../../shared/index.ts";
6
7
  import { type TenantLifecycleStatus, tenantEntity, tenantTable } from "../../tenant/index.ts";
7
- import { DESTRUCTION_CANCELLED_EVENT_QN } from "../constants.ts";
8
+ import { DESTRUCTION_CANCELLED_EVENT_QN, TENANT_LIFECYCLE_FEATURE } from "../constants.ts";
8
9
  import { invalidateTenantLifecycleGate } from "../lifecycle-gate.ts";
9
10
 
10
11
  const crud = createEventStoreExecutor(tenantTable, tenantEntity, { entityName: "tenant" });
@@ -15,7 +16,7 @@ type TenantLifecycleRow = {
15
16
  };
16
17
 
17
18
  const CANCEL_DESTRUCTION_TENANT_ROW_REASON =
18
- "reads the caller's tenant row, whose tenant_id is the creating tenant, not the row's own id";
19
+ "reads the caller's tenant row (a global row on the system tenant) and appends to the tenant stream on the system tenant";
19
20
 
20
21
  export const cancelDestructionWrite = defineWriteHandler({
21
22
  name: "cancel-destruction",
@@ -29,7 +30,8 @@ export const cancelDestructionWrite = defineWriteHandler({
29
30
  },
30
31
  handler: async (event, ctx) => {
31
32
  const tenantId = event.user.tenantId;
32
- const row = await fetchOne<TenantLifecycleRow>(ctx.db.unsafeRaw(), tenantTable, {
33
+ const runner = ctx.db.unsafeRaw();
34
+ const row = await fetchOne<TenantLifecycleRow>(runner, tenantTable, {
33
35
  id: tenantId,
34
36
  });
35
37
  if (!row) {
@@ -64,12 +66,22 @@ export const cancelDestructionWrite = defineWriteHandler({
64
66
  if (!update.isSuccess) return update;
65
67
  invalidateTenantLifecycleGate(tenantId);
66
68
 
67
- await ctx.unsafeAppendEvent({
68
- aggregateId: tenantId,
69
- aggregateType: "tenant",
70
- type: DESTRUCTION_CANCELLED_EVENT_QN,
71
- payload: { cancelledBy: event.user.id },
72
- });
69
+ await appendDomainEventCore(
70
+ {
71
+ registry: ctx.registry,
72
+ db: runner,
73
+ tenantId: SYSTEM_TENANT_ID,
74
+ userId: String(event.user.id),
75
+ callSiteLabel: "tenant-lifecycle cancel-destruction",
76
+ callerFeature: TENANT_LIFECYCLE_FEATURE,
77
+ },
78
+ {
79
+ aggregateId: tenantId,
80
+ aggregateType: "tenant",
81
+ type: DESTRUCTION_CANCELLED_EVENT_QN,
82
+ payload: { cancelledBy: event.user.id },
83
+ },
84
+ );
73
85
 
74
86
  const gracePeriodEnd: string | null = null;
75
87
  return {
@@ -1,12 +1,13 @@
1
1
  import { addDurationSpec } from "@cosmicdrift/kumiko-framework/compliance";
2
2
  import { createEventStoreExecutor, fetchOne } from "@cosmicdrift/kumiko-framework/db";
3
- import { defineWriteHandler } from "@cosmicdrift/kumiko-framework/engine";
3
+ import { defineWriteHandler, SYSTEM_TENANT_ID } from "@cosmicdrift/kumiko-framework/engine";
4
4
  import { UnprocessableError, writeFailure } from "@cosmicdrift/kumiko-framework/errors";
5
+ import { appendDomainEventCore } from "@cosmicdrift/kumiko-framework/pipeline";
5
6
  import { getTemporal } from "@cosmicdrift/kumiko-framework/time";
6
7
  import * as z from "zod";
7
8
  import { resolveProfileForTenant } from "../../compliance-profiles/index.ts";
8
9
  import { type TenantLifecycleStatus, tenantEntity, tenantTable } from "../../tenant/index.ts";
9
- import { DESTRUCTION_REQUESTED_EVENT_QN } from "../constants.ts";
10
+ import { DESTRUCTION_REQUESTED_EVENT_QN, TENANT_LIFECYCLE_FEATURE } from "../constants.ts";
10
11
  import { revokeTenantSessions } from "../lib/revoke-tenant-sessions.ts";
11
12
  import { invalidateTenantLifecycleGate } from "../lifecycle-gate.ts";
12
13
 
@@ -18,7 +19,7 @@ type TenantLifecycleRow = {
18
19
  };
19
20
 
20
21
  const REQUEST_DESTRUCTION_TENANT_ROW_REASON =
21
- "reads the caller's tenant row, whose tenant_id is the creating tenant, its compliance profile, and revokes its sessions via DbRunner helpers";
22
+ "reads the caller's tenant row (a global row on the system tenant), its compliance profile, appends to the tenant stream on the system tenant and revokes its sessions via DbRunner helpers";
22
23
 
23
24
  export const requestDestructionWrite = defineWriteHandler({
24
25
  name: "request-destruction",
@@ -67,15 +68,25 @@ export const requestDestructionWrite = defineWriteHandler({
67
68
  if (!update.isSuccess) return update;
68
69
  invalidateTenantLifecycleGate(tenantId);
69
70
 
70
- await ctx.unsafeAppendEvent({
71
- aggregateId: tenantId,
72
- aggregateType: "tenant",
73
- type: DESTRUCTION_REQUESTED_EVENT_QN,
74
- payload: {
75
- requestedBy: event.user.id,
76
- gracePeriodEnd: gracePeriodEnd.toString(),
71
+ await appendDomainEventCore(
72
+ {
73
+ registry: ctx.registry,
74
+ db: runner,
75
+ tenantId: SYSTEM_TENANT_ID,
76
+ userId: String(event.user.id),
77
+ callSiteLabel: "tenant-lifecycle request-destruction",
78
+ callerFeature: TENANT_LIFECYCLE_FEATURE,
79
+ },
80
+ {
81
+ aggregateId: tenantId,
82
+ aggregateType: "tenant",
83
+ type: DESTRUCTION_REQUESTED_EVENT_QN,
84
+ payload: {
85
+ requestedBy: event.user.id,
86
+ gracePeriodEnd: gracePeriodEnd.toString(),
87
+ },
77
88
  },
78
- });
89
+ );
79
90
 
80
91
  if (await ctx.hasFeature("sessions")) {
81
92
  await revokeTenantSessions(runner, tenantId);
@@ -10,6 +10,7 @@ import {
10
10
  createSystemUser,
11
11
  type EscapeHatchAuditSink,
12
12
  type Registry,
13
+ SYSTEM_TENANT_ID,
13
14
  type TenantId,
14
15
  } from "@cosmicdrift/kumiko-framework/engine";
15
16
  import {
@@ -133,7 +134,7 @@ async function appendTenantStageEvent(
133
134
  await append(db, {
134
135
  aggregateId: tenantId,
135
136
  aggregateType: TENANT_AGGREGATE_TYPE,
136
- tenantId,
137
+ tenantId: SYSTEM_TENANT_ID,
137
138
  expectedVersion,
138
139
  type,
139
140
  payload,
@@ -153,14 +154,14 @@ async function appendTenantStageEventIdempotent(
153
154
  alreadyRecorded: boolean,
154
155
  ): Promise<number> {
155
156
  if (alreadyRecorded) {
156
- const events = await loadAggregate(db, tenantId, tenantId);
157
+ const events = await loadAggregate(db, tenantId, SYSTEM_TENANT_ID);
157
158
  return lastEventVersion(events);
158
159
  }
159
160
  try {
160
161
  await appendTenantStageEvent(db, tenantId, type, payload, expectedVersion);
161
162
  } catch (err) {
162
163
  if (!(err instanceof VersionConflictError)) throw err;
163
- const events = await loadAggregate(db, tenantId, tenantId);
164
+ const events = await loadAggregate(db, tenantId, SYSTEM_TENANT_ID);
164
165
  const stage = String(payload["stage"] ?? "");
165
166
  if (stageOutcomeRecorded(events, stage, TENANT_DESTRUCTION_STAGE_SUCCEEDED_EVENT_SHORT)) {
166
167
  // skip: idempotent retry — stage already recorded before version conflict
@@ -168,13 +169,18 @@ async function appendTenantStageEventIdempotent(
168
169
  }
169
170
  throw err;
170
171
  }
171
- const events = await loadAggregate(db, tenantId, tenantId);
172
+ const events = await loadAggregate(db, tenantId, SYSTEM_TENANT_ID);
172
173
  return lastEventVersion(events);
173
174
  }
174
175
 
175
176
  async function markTenantDestroyFailed(db: DbRunner, tenantId: TenantId): Promise<void> {
176
177
  const user = createSystemUser(tenantId);
177
- const scopedDb = createTenantDb({ db, tenantId, mode: "system" });
178
+ const scopedDb = createTenantDb({
179
+ db,
180
+ tenantId,
181
+ mode: "system",
182
+ reason: "tenant destruction updates the tenant being destroyed, outside its request scope",
183
+ });
178
184
  await tenantCrud.update(
179
185
  {
180
186
  id: tenantId,
@@ -200,7 +206,7 @@ async function haltPipelineOnAbandon(args: {
200
206
  // stage's own run() may have appended to this same aggregate (e.g.
201
207
  // tombstoneTenantRow's tenantCrud.update) before throwing, so any version
202
208
  // captured earlier in the pipeline is stale and would VersionConflict here.
203
- const eventsBeforeAbandon = await loadAggregate(args.db, args.tenantId, args.tenantId);
209
+ const eventsBeforeAbandon = await loadAggregate(args.db, args.tenantId, SYSTEM_TENANT_ID);
204
210
  await appendTenantStageEvent(
205
211
  args.db,
206
212
  args.tenantId,
@@ -208,7 +214,7 @@ async function haltPipelineOnAbandon(args: {
208
214
  { stage: args.stage, attempts: args.attempts, error: args.error },
209
215
  lastEventVersion(eventsBeforeAbandon),
210
216
  );
211
- const eventsAfterAbandon = await loadAggregate(args.db, args.tenantId, args.tenantId);
217
+ const eventsAfterAbandon = await loadAggregate(args.db, args.tenantId, SYSTEM_TENANT_ID);
212
218
  const versionAfterAbandon = lastEventVersion(eventsAfterAbandon);
213
219
  await appendTenantStageEvent(
214
220
  args.db,
@@ -229,7 +235,7 @@ async function maybeAppendDestructionCompleted(
229
235
  // skip: pipeline still has pending stages
230
236
  return;
231
237
  }
232
- const events = await loadAggregate(db, tenantId, tenantId);
238
+ const events = await loadAggregate(db, tenantId, SYSTEM_TENANT_ID);
233
239
  if (events.some((event) => event.type === TENANT_DESTRUCTION_COMPLETED_EVENT_QN)) {
234
240
  // skip: idempotent — completion event already recorded
235
241
  return;
@@ -293,7 +299,7 @@ export async function runNextDestructionStage(args: {
293
299
  readonly actor?: string;
294
300
  readonly deadlineAt?: number;
295
301
  }): Promise<StageTickResult> {
296
- const events = await loadAggregate(args.db, args.tenantId, args.tenantId);
302
+ const events = await loadAggregate(args.db, args.tenantId, SYSTEM_TENANT_ID);
297
303
  const { completed, abandoned, attemptsByStage } = replayStageState(events);
298
304
 
299
305
  if (abandoned.size > 0) {
@@ -339,7 +345,7 @@ export async function runNextDestructionStage(args: {
339
345
  // tombstoneTenantRow updates the tenant row on the same stream) — reload
340
346
  // the version fresh instead of trusting the pre-run `version`, or this
341
347
  // append throws VersionConflictError on every stage whose run() writes.
342
- const eventsAfterRun = await loadAggregate(args.db, args.tenantId, args.tenantId);
348
+ const eventsAfterRun = await loadAggregate(args.db, args.tenantId, SYSTEM_TENANT_ID);
343
349
  // A tick that neither finishes nor processes anything would otherwise loop
344
350
  // forever, because progressed events do not count as attempts.
345
351
  if (!outcome.done && outcome.processed === 0) {
@@ -429,10 +435,15 @@ export async function runTenantDestructionSweep(args: {
429
435
  let triggered = 0;
430
436
  for (const row of due) {
431
437
  const tenantId = row.id;
432
- const events = await loadAggregate(args.db, tenantId, tenantId);
438
+ const events = await loadAggregate(args.db, tenantId, SYSTEM_TENANT_ID);
433
439
  const version = lastEventVersion(events);
434
440
  const user = createSystemUser(tenantId);
435
- const scopedDb = createTenantDb({ db: args.db, tenantId, mode: "system" });
441
+ const scopedDb = createTenantDb({
442
+ db: args.db,
443
+ tenantId,
444
+ mode: "system",
445
+ reason: "tenant destruction updates the tenant being destroyed, outside its request scope",
446
+ });
436
447
  // Version-guarded (no skipOptimisticLock): a concurrent cancel-destruction
437
448
  // between the `due` select above and this write also appends to the same
438
449
  // tenant stream, so an unguarded overwrite here would silently revert the
@@ -57,8 +57,7 @@ export type DestructionStageCtx = {
57
57
  // "destroyTenant" hooks) — undefined when no file-provider is wired,
58
58
  // which those hooks must treat as "nothing to clean up", not an error.
59
59
  readonly fileProviderResolver?: FileProviderResolver;
60
- // Derived search docs of the tenant record (its name) live in the writer's
61
- // index, not the destroyed tenant's, so the subject-keys stage purges them.
60
+ // The tenant record's derived search docs (its name) sit in the SYSTEM bucket; the subject-keys stage purges them.
62
61
  readonly searchAdapter?: SearchAdapter;
63
62
  // Sourced from the owning job's ctx (_escapeHatchAuditSink,
64
63
  // systemUser.id); runTenantDataHooks uses them to attribute+audit any
@@ -241,7 +240,12 @@ async function purgeTenantCache(ctx: DestructionStageCtx): Promise<StageRunOutco
241
240
  async function tombstoneTenantRow(ctx: DestructionStageCtx): Promise<StageRunOutcome> {
242
241
  const now = getTemporal().Now.instant();
243
242
  const user = createSystemUser(ctx.tenantId);
244
- const db = createTenantDb({ db: ctx.db, tenantId: ctx.tenantId, mode: "system" });
243
+ const db = createTenantDb({
244
+ db: ctx.db,
245
+ tenantId: ctx.tenantId,
246
+ mode: "system",
247
+ reason: "destruction stage tombstones the row of the tenant being destroyed",
248
+ });
245
249
  // Per-row forget() through the executor, not a bulk deleteMany: memberships
246
250
  // are an ES-managed projection (add/remove/update-roles all go through
247
251
  // tenantMembershipCrud), so a store table write here is eventless — a future
@@ -1,12 +1,12 @@
1
1
  import type { DbConnection } from "@cosmicdrift/kumiko-framework/db";
2
2
  import { selectMany } from "@cosmicdrift/kumiko-framework/db";
3
- import type { TenantId } from "@cosmicdrift/kumiko-framework/engine";
3
+ import { SYSTEM_TENANT_ID, type TenantId } from "@cosmicdrift/kumiko-framework/engine";
4
4
  import { append, loadAggregate } from "@cosmicdrift/kumiko-framework/event-store";
5
5
  import type { SearchAdapter } from "@cosmicdrift/kumiko-framework/search";
6
6
  import { getTemporal } from "@cosmicdrift/kumiko-framework/time";
7
- import { updateRows } from "@cosmicdrift/kumiko-testing/helpers";
7
+ import { updateRowViaEventStore } from "@cosmicdrift/kumiko-testing/helpers";
8
8
  import type { TestStack } from "@cosmicdrift/kumiko-testing/stack";
9
- import { tenantTable } from "../tenant/index.ts";
9
+ import { tenantEntity, tenantTable } from "../tenant/index.ts";
10
10
  import { TENANT_AGGREGATE_TYPE, TENANT_DESTRUCTION_STARTED_EVENT_QN } from "./constants.ts";
11
11
  import { runTenantDestructionSweep } from "./run-tenant-destroy.ts";
12
12
 
@@ -14,17 +14,18 @@ import { runTenantDestructionSweep } from "./run-tenant-destroy.ts";
14
14
  // features wired) by seeding the same "destroying" state it would produce.
15
15
  export async function seedDestroyingTenant(db: DbConnection, tenantId: TenantId): Promise<void> {
16
16
  const now = getTemporal().Now.instant();
17
- await updateRows(
17
+ await updateRowViaEventStore(
18
18
  db,
19
- tenantTable,
20
- { status: "destroying", destroyStartedAt: now },
19
+ { table: tenantTable, entity: tenantEntity, entityName: "tenant" },
21
20
  { id: tenantId },
21
+ { status: "destroying", destroyStartedAt: now },
22
+ { tenantId: SYSTEM_TENANT_ID },
22
23
  );
23
24
  await append(db, {
24
25
  aggregateId: tenantId,
25
26
  aggregateType: TENANT_AGGREGATE_TYPE,
26
- tenantId,
27
- expectedVersion: (await loadAggregate(db, tenantId, tenantId)).at(-1)?.version ?? 0,
27
+ tenantId: SYSTEM_TENANT_ID,
28
+ expectedVersion: (await loadAggregate(db, tenantId, SYSTEM_TENANT_ID)).at(-1)?.version ?? 0,
28
29
  type: TENANT_DESTRUCTION_STARTED_EVENT_QN,
29
30
  payload: { startedAt: now.toString() },
30
31
  metadata: { userId: "system", requestId: "test:destruction-started" },
@@ -21,7 +21,7 @@ import { type TierAssignmentSource, TierAssignmentSources } from "./web/constant
21
21
  // **Intentionally omitted from the entity**
22
22
  // - tenantId: added automatically as a base column.
23
23
  // - validFrom/validTo: redundant for event sourcing (events carry timestamps
24
- // natively; time travel uses `ctx.loadAggregate({ asOf })`).
24
+ // natively; time travel uses `ctx.events.load({ asOf })`).
25
25
  // - addOns: represented by a separate `tier-add-on` entity (1:n relation),
26
26
  // allowing event-sourced Add/Remove events with clear audit granularity
27
27
  // instead of replacing a JSON array.
@@ -95,7 +95,7 @@ const tierAssignmentTable = buildEntityTable("tier-assignment", tierAssignmentEn
95
95
  const log = createFallbackLogger("tier-engine");
96
96
 
97
97
  // Event-store executor for direct writes from the auto-default-tier hook.
98
- // Like tenant/seeding.ts, the hook receives AppContext (not ctx.write), but it
98
+ // Like tenant/seeding.ts, the hook receives AppContext (not ctx.dispatch.write), but it
99
99
  // must write atomically with tenant creation in the same transaction. Call the
100
100
  // executor directly rather than going through the dispatcher.
101
101
  const tierAssignmentExecutor = createEventStoreExecutor(tierAssignmentTable, tierAssignmentEntity, {
@@ -406,7 +406,7 @@ export function createTierEngineFeature<
406
406
 
407
407
  // Auto-default-tier-on-tenant-signup: the hook fires inTransaction (atomic
408
408
  // with the tenant-create rollback) and writes the tier-assignment via the
409
- // direct executor (not ctx.write — the hook has an AppContext). Same
409
+ // direct executor (not ctx.dispatch.write — the hook has an AppContext). Same
410
410
  // pattern as seedTenant in tenant/seeding.ts.
411
411
  //
412
412
  // **Idempotency:** deterministic aggregate id derived from tenantId. A
@@ -468,7 +468,12 @@ export function createTierEngineFeature<
468
468
  tenantId: newTenantId,
469
469
  roles: ["SystemAdmin"],
470
470
  };
471
- const tdb = createTenantDb({ db: rawDb, tenantId: newTenantId, mode: "system" });
471
+ const tdb = createTenantDb({
472
+ db: rawDb,
473
+ tenantId: newTenantId,
474
+ mode: "system",
475
+ reason: "tier assignment for a newly created tenant is written in that tenant",
476
+ });
472
477
 
473
478
  await tierAssignmentExecutor.create(
474
479
  { id: aggregateId, tier: defaultTier, source: TierAssignmentSources.default },
@@ -3,11 +3,11 @@ import * as z from "zod";
3
3
 
4
4
  // get-active-tier — returns the current tier assignment for the calling tenant.
5
5
  //
6
- // Wraps `ctx.queryProjection` for the most common engine query: which tier is
6
+ // Wraps `ctx.dispatch.queryProjection` for the most common engine query: which tier is
7
7
  // currently active. Returns null when no tier is assigned; the caller (composeApp)
8
8
  // maps null to the default tier.
9
9
  //
10
- // **Tenant scope:** `ctx.queryProjection` automatically filters by tenantId.
10
+ // **Tenant scope:** `ctx.dispatch.queryProjection` automatically filters by tenantId.
11
11
  // By convention, each platform tenant has exactly one tier-assignment row.
12
12
  export const getActiveTierQuery: QueryHandlerDef = {
13
13
  name: "get-active-tier",
@@ -16,7 +16,7 @@ export const getActiveTierQuery: QueryHandlerDef = {
16
16
  schema: z.object({}),
17
17
  access: { roles: ["TenantAdmin", "SystemAdmin"] },
18
18
  handler: async (_query, ctx) => {
19
- const rows = await ctx.queryProjection<Record<string, unknown>>(
19
+ const rows = await ctx.dispatch.queryProjection<Record<string, unknown>>(
20
20
  "tier-engine:projection:tier-assignment-entity",
21
21
  );
22
22
  return rows[0] ?? null;
@@ -24,7 +24,13 @@ export const getTenantTierQuery = defineQueryHandler({
24
24
  },
25
25
  handler: async (query, ctx) => {
26
26
  const tenantId = query.payload.tenantId as TenantId; // @cast-boundary engine-bridge
27
- const tdb = createTenantDb({ db: ctx.db.unsafeRaw(), tenantId, mode: "system" });
27
+ const tdb = createTenantDb({
28
+ db: ctx.db.unsafeRaw(),
29
+ tenantId,
30
+ mode: "system",
31
+ reason:
32
+ "tier lookup reads the assignment of the queried tenant, the escape hatch is declared on the handler",
33
+ });
28
34
  const row = await fetchOne<TierAssignmentRow>(tdb, tierAssignmentTable, { tenantId });
29
35
  return row ?? null;
30
36
  },
@@ -14,7 +14,7 @@ import { type TierAssignmentSource, TierAssignmentSources } from "../web/constan
14
14
  // billing. This is cross-tenant, so it is restricted to SystemAdmin (not
15
15
  // TenantAdmin, which would allow free self-upgrades).
16
16
  //
17
- // Cross-tenant mechanics: ctx.forTenant(tenantId) yields a tenant-mode db bound to the target plus
17
+ // Cross-tenant mechanics: ctx.tenants.writeTarget(tenantId) yields a tenant-mode db bound to the target plus
18
18
  // the streamTenantId, so the event lands in the target's stream with the operator as actor.
19
19
  //
20
20
  // `source` defaults to manual and marks the grant so the billing sync skips it; passing
@@ -25,7 +25,7 @@ import { type TierAssignmentSource, TierAssignmentSources } from "../web/constan
25
25
  // `tier-assignment:postSave` entity hook, and a per-handler postSave would not
26
26
  // fire either because this handler returns no lifecycle result (kind "save").
27
27
  // Without an explicit update the feature gate would stay on the old tier, so
28
- // `opts.onAssigned(tenantId, tier)` runs after commit (ctx.scheduleAfterCommit).
28
+ // `opts.onAssigned(tenantId, tier)` runs after commit (ctx.lifecycle.afterCommit).
29
29
  // feature.ts uses it to update its cache and notify the other processes; in
30
30
  // storage-only mode without a tierMap it is a no-op.
31
31
 
@@ -70,7 +70,7 @@ export function createSetTenantTierWrite(opts: SetTenantTierOptions = {}) {
70
70
  // Without a commit sink (unit harness) there is no transaction to wait for.
71
71
  const afterCommit = (tenantId: TenantId, tier: string): void => {
72
72
  const notify = async (): Promise<void> => opts.onAssigned?.(tenantId, tier);
73
- if (ctx.scheduleAfterCommit) ctx.scheduleAfterCommit(notify);
73
+ if (ctx.lifecycle.afterCommit) ctx.lifecycle.afterCommit(notify);
74
74
  else opts.onAssigned?.(tenantId, tier);
75
75
  };
76
76
  const tenantId = event.payload.tenantId as TenantId; // @cast-boundary engine-bridge