@cosmicdrift/kumiko-samples 0.388.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 (385) hide show
  1. package/package.json +1 -1
  2. package/packages/bundled-features/package.json +25 -13
  3. package/packages/bundled-features/src/agent-tools/changes.json +6 -0
  4. package/packages/bundled-features/src/agent-tools/index.ts +1 -1
  5. package/packages/bundled-features/src/agent-tools/tool-dispatch.ts +42 -26
  6. package/packages/bundled-features/src/audit/feature.ts +2 -1
  7. package/packages/bundled-features/src/auth-email-password/auth-user-row.ts +1 -1
  8. package/packages/bundled-features/src/auth-email-password/bootstrap.ts +13 -1
  9. package/packages/bundled-features/src/auth-email-password/changes.json +18 -0
  10. package/packages/bundled-features/src/auth-email-password/feature.ts +2 -2
  11. package/packages/bundled-features/src/auth-email-password/handlers/change-password.write.ts +7 -7
  12. package/packages/bundled-features/src/auth-email-password/handlers/confirm-account-unlock.write.ts +3 -3
  13. package/packages/bundled-features/src/auth-email-password/handlers/confirm-token-flow.ts +5 -5
  14. package/packages/bundled-features/src/auth-email-password/handlers/invite-accept-with-login.write.ts +9 -7
  15. package/packages/bundled-features/src/auth-email-password/handlers/invite-accept.write.ts +11 -7
  16. package/packages/bundled-features/src/auth-email-password/handlers/invite-create.write.ts +4 -4
  17. package/packages/bundled-features/src/auth-email-password/handlers/invite-info.query.ts +2 -2
  18. package/packages/bundled-features/src/auth-email-password/handlers/invite-signup-complete.write.ts +9 -7
  19. package/packages/bundled-features/src/auth-email-password/handlers/login.write.ts +23 -16
  20. package/packages/bundled-features/src/auth-email-password/handlers/request-account-unlock.write.ts +1 -0
  21. package/packages/bundled-features/src/auth-email-password/handlers/request-email-verification.write.ts +1 -0
  22. package/packages/bundled-features/src/auth-email-password/handlers/request-password-reset.write.ts +1 -0
  23. package/packages/bundled-features/src/auth-email-password/handlers/reset-password.write.ts +3 -2
  24. package/packages/bundled-features/src/auth-email-password/handlers/signup-confirm.write.ts +12 -12
  25. package/packages/bundled-features/src/auth-email-password/handlers/signup-request.write.ts +16 -8
  26. package/packages/bundled-features/src/auth-email-password/handlers/switch-tenant-mfa-gate.write.ts +4 -2
  27. package/packages/bundled-features/src/auth-email-password/handlers/token-request-handler.ts +10 -2
  28. package/packages/bundled-features/src/auth-email-password/handlers/verify-email.write.ts +3 -2
  29. package/packages/bundled-features/src/auth-email-password/magic-link-mail.ts +16 -3
  30. package/packages/bundled-features/src/auth-email-password/seeding.ts +14 -9
  31. package/packages/bundled-features/src/auth-email-password/signup-activation.ts +2 -0
  32. package/packages/bundled-features/src/auth-email-password/web/auth-client.ts +8 -2
  33. package/packages/bundled-features/src/auth-email-password/web/auth-redirect.ts +23 -21
  34. package/packages/bundled-features/src/auth-email-password/web/default-auth-pages-gate.tsx +6 -3
  35. package/packages/bundled-features/src/auth-email-password/web/forgot-password-screen.tsx +11 -1
  36. package/packages/bundled-features/src/auth-email-password/web/index.ts +5 -0
  37. package/packages/bundled-features/src/auth-email-password/web/login-screen.tsx +16 -5
  38. package/packages/bundled-features/src/auth-email-password/web/reset-password-screen.tsx +7 -1
  39. package/packages/bundled-features/src/auth-email-password/web/return-path.ts +35 -0
  40. package/packages/bundled-features/src/auth-email-password/web/session.tsx +6 -1
  41. package/packages/bundled-features/src/auth-email-password/web/signup-complete-screen.tsx +11 -3
  42. package/packages/bundled-features/src/auth-email-password/web/signup-screen.tsx +12 -2
  43. package/packages/bundled-features/src/auth-foundation/feature.ts +13 -4
  44. package/packages/bundled-features/src/auth-mfa/changes.json +6 -0
  45. package/packages/bundled-features/src/auth-mfa/config.ts +3 -7
  46. package/packages/bundled-features/src/auth-mfa/handlers/disable.write.ts +5 -5
  47. package/packages/bundled-features/src/auth-mfa/handlers/enable-confirm-preauth.write.ts +24 -14
  48. package/packages/bundled-features/src/auth-mfa/handlers/enable-confirm.write.ts +9 -3
  49. package/packages/bundled-features/src/auth-mfa/handlers/enable-start-preauth.write.ts +6 -1
  50. package/packages/bundled-features/src/auth-mfa/handlers/enable-start.write.ts +3 -1
  51. package/packages/bundled-features/src/auth-mfa/handlers/reencrypt.job.ts +14 -9
  52. package/packages/bundled-features/src/auth-mfa/handlers/regenerate-recovery.write.ts +5 -4
  53. package/packages/bundled-features/src/auth-mfa/handlers/verify.write.ts +25 -14
  54. package/packages/bundled-features/src/auth-mfa/mfa-code-verifier.ts +10 -4
  55. package/packages/bundled-features/src/auth-mfa/mfa-status-checker.ts +17 -8
  56. package/packages/bundled-features/src/auth-mfa/verify-factor.ts +1 -1
  57. package/packages/bundled-features/src/billing-foundation/billing-info-query.ts +2 -2
  58. package/packages/bundled-features/src/billing-foundation/changes.json +6 -0
  59. package/packages/bundled-features/src/billing-foundation/consumer-protection/consent-gate.ts +1 -1
  60. package/packages/bundled-features/src/billing-foundation/consumer-protection/issue-confirmation.ts +5 -5
  61. package/packages/bundled-features/src/billing-foundation/consumer-protection/register-consent.ts +10 -7
  62. package/packages/bundled-features/src/billing-foundation/consumer-protection/register-termination.ts +15 -12
  63. package/packages/bundled-features/src/billing-foundation/consumer-protection/termination-open-cancels.ts +22 -0
  64. package/packages/bundled-features/src/billing-foundation/consumer-protection/termination-provider-lock.ts +4 -0
  65. package/packages/bundled-features/src/billing-foundation/consumer-protection/termination-receipt-limit.ts +4 -4
  66. package/packages/bundled-features/src/billing-foundation/consumer-protection/termination-record.ts +17 -58
  67. package/packages/bundled-features/src/billing-foundation/consumer-protection/termination-request.ts +10 -8
  68. package/packages/bundled-features/src/billing-foundation/consumer-protection/termination-revoke.ts +18 -15
  69. package/packages/bundled-features/src/billing-foundation/events.ts +1 -1
  70. package/packages/bundled-features/src/billing-foundation/feature.ts +8 -3
  71. package/packages/bundled-features/src/billing-foundation/get-subscription-for-tenant.ts +1 -1
  72. package/packages/bundled-features/src/billing-foundation/handlers/process-event.write.ts +5 -5
  73. package/packages/bundled-features/src/billing-foundation/handlers/process-payment-event.write.ts +3 -3
  74. package/packages/bundled-features/src/billing-foundation/plan-catalog.ts +2 -2
  75. package/packages/bundled-features/src/billing-foundation/projection.ts +1 -1
  76. package/packages/bundled-features/src/billing-foundation/types.ts +1 -1
  77. package/packages/bundled-features/src/cap-counter/aggregate-id.ts +1 -1
  78. package/packages/bundled-features/src/cap-counter/book-cap-usage.ts +5 -4
  79. package/packages/bundled-features/src/cap-counter/cap-reservation.ts +21 -8
  80. package/packages/bundled-features/src/cap-counter/changes.json +12 -0
  81. package/packages/bundled-features/src/cap-counter/constants.ts +1 -1
  82. package/packages/bundled-features/src/cap-counter/feature.ts +3 -2
  83. package/packages/bundled-features/src/cap-counter/handlers/increment-rolling.write.ts +1 -1
  84. package/packages/bundled-features/src/cap-counter/reservation-chain.ts +1 -1
  85. package/packages/bundled-features/src/cap-counter/with-cap-enforcement.ts +4 -4
  86. package/packages/bundled-features/src/cap-overview/feature.ts +1 -0
  87. package/packages/bundled-features/src/cap-overview/handlers/caps-usage.query.ts +1 -1
  88. package/packages/bundled-features/src/cap-overview/handlers/tenant-caps-list.query.ts +1 -1
  89. package/packages/bundled-features/src/compliance-profiles/seeding.ts +12 -7
  90. package/packages/bundled-features/src/config/changes.json +6 -0
  91. package/packages/bundled-features/src/config/feature.ts +6 -6
  92. package/packages/bundled-features/src/config/handlers/cascade.query.ts +1 -1
  93. package/packages/bundled-features/src/config/handlers/readiness.query.ts +1 -1
  94. package/packages/bundled-features/src/config/handlers/reencrypt.job.ts +23 -13
  95. package/packages/bundled-features/src/config/handlers/reset.write.ts +3 -3
  96. package/packages/bundled-features/src/config/handlers/selected-extensions.query.ts +1 -1
  97. package/packages/bundled-features/src/config/handlers/set.write.ts +22 -5
  98. package/packages/bundled-features/src/config/handlers/values.query.ts +1 -1
  99. package/packages/bundled-features/src/crypto-shredding/changes.json +12 -0
  100. package/packages/bundled-features/src/crypto-shredding/handlers/forget-subject.write.ts +9 -9
  101. package/packages/bundled-features/src/crypto-shredding/resolve-file-bytes-deleter.ts +3 -3
  102. package/packages/bundled-features/src/custom-fields/changes.json +6 -0
  103. package/packages/bundled-features/src/custom-fields/handlers/clear-custom-field.write.ts +1 -1
  104. package/packages/bundled-features/src/custom-fields/handlers/delete-system-field.write.ts +1 -1
  105. package/packages/bundled-features/src/custom-fields/handlers/delete-tenant-field.write.ts +1 -1
  106. package/packages/bundled-features/src/custom-fields/handlers/set-custom-field.write.ts +1 -1
  107. package/packages/bundled-features/src/custom-fields/index.ts +4 -0
  108. package/packages/bundled-features/src/custom-fields/lib/parse-serialized-field.ts +1 -1
  109. package/packages/bundled-features/src/data-retention/feature.ts +1 -1
  110. package/packages/bundled-features/src/data-retention/run-retention-cleanup.ts +12 -2
  111. package/packages/bundled-features/src/delivery/attempt-log.ts +1 -1
  112. package/packages/bundled-features/src/delivery/changes.json +12 -0
  113. package/packages/bundled-features/src/delivery/delivery-service.ts +6 -5
  114. package/packages/bundled-features/src/delivery/feature.ts +3 -2
  115. package/packages/bundled-features/src/delivery/index.ts +5 -0
  116. package/packages/bundled-features/src/delivery/jobs.ts +11 -11
  117. package/packages/bundled-features/src/delivery/system-channel-context.ts +33 -0
  118. package/packages/bundled-features/src/delivery/testing.ts +1 -1
  119. package/packages/bundled-features/src/document-ingest-foundation/append-missing-extract-event.ts +84 -0
  120. package/packages/bundled-features/src/document-ingest-foundation/changes.json +6 -0
  121. package/packages/bundled-features/src/document-ingest-foundation/events.ts +16 -1
  122. package/packages/bundled-features/src/document-ingest-foundation/index.ts +11 -0
  123. package/packages/bundled-features/src/feature-toggles/feature.ts +1 -0
  124. package/packages/bundled-features/src/feature-toggles/handlers/registered.query.ts +1 -1
  125. package/packages/bundled-features/src/feature-toggles/handlers/set.write.ts +1 -1
  126. package/packages/bundled-features/src/feature-toggles/toggle-sync-signal.ts +1 -1
  127. package/packages/bundled-features/src/file-derivatives/feature.ts +2 -2
  128. package/packages/bundled-features/src/file-derivatives/handlers/public-variant-by-file-ref.query.ts +5 -1
  129. package/packages/bundled-features/src/file-derivatives/handlers/public-variant.query.ts +7 -5
  130. package/packages/bundled-features/src/file-foundation/feature.ts +1 -1
  131. package/packages/bundled-features/src/file-foundation/read-file-ref-content.ts +7 -5
  132. package/packages/bundled-features/src/file-provider-s3/feature.ts +4 -1
  133. package/packages/bundled-features/src/files-tenant-data/handlers/sweep-orphaned-derivatives.job.ts +8 -8
  134. package/packages/bundled-features/src/form-draft/feature.ts +1 -1
  135. package/packages/bundled-features/src/form-draft/handlers/cleanup.job.ts +22 -12
  136. package/packages/bundled-features/src/form-draft/handlers/discard.write.ts +3 -3
  137. package/packages/bundled-features/src/form-draft/handlers/get.query.ts +1 -1
  138. package/packages/bundled-features/src/foundation-shared/config-helpers.ts +1 -1
  139. package/packages/bundled-features/src/host-routing/changes.json +6 -0
  140. package/packages/bundled-features/src/host-routing/validate-options.ts +5 -0
  141. package/packages/bundled-features/src/inbound-mail-foundation/events.ts +1 -1
  142. package/packages/bundled-features/src/inbound-mail-foundation/feature.ts +2 -1
  143. package/packages/bundled-features/src/inbound-mail-foundation/handlers/account-state.ts +2 -2
  144. package/packages/bundled-features/src/inbound-mail-foundation/handlers/connect-account.write.ts +1 -1
  145. package/packages/bundled-features/src/inbound-mail-foundation/handlers/disconnect-account.write.ts +1 -1
  146. package/packages/bundled-features/src/inbound-mail-foundation/handlers/ingest-message.write.ts +10 -10
  147. package/packages/bundled-features/src/inbound-mail-foundation/handlers/update-account.write.ts +1 -1
  148. package/packages/bundled-features/src/inbound-mail-foundation/projection.ts +1 -1
  149. package/packages/bundled-features/src/inbound-mail-foundation/watch-supervisor.ts +1 -1
  150. package/packages/bundled-features/src/inbound-provider-imap/feature.ts +4 -1
  151. package/packages/bundled-features/src/jobs/changes.json +6 -0
  152. package/packages/bundled-features/src/jobs/events.ts +1 -1
  153. package/packages/bundled-features/src/jobs/feature.ts +1 -0
  154. package/packages/bundled-features/src/jobs/handlers/consumer.write.ts +7 -4
  155. package/packages/bundled-features/src/jobs/handlers/projection-rebuild.job.ts +1 -1
  156. package/packages/bundled-features/src/jobs/handlers/reindex-entity.job.ts +11 -5
  157. package/packages/bundled-features/src/jobs/handlers/retention-cleanup.job.ts +1 -1
  158. package/packages/bundled-features/src/jobs/handlers/retry.write.ts +1 -1
  159. package/packages/bundled-features/src/jobs/handlers/stale-run-sweep.job.ts +1 -1
  160. package/packages/bundled-features/src/jobs/handlers/trigger.write.ts +2 -2
  161. package/packages/bundled-features/src/jobs/job-run-logger.ts +139 -90
  162. package/packages/bundled-features/src/ledger/web/index.ts +1 -1
  163. package/packages/bundled-features/src/legal-pages/README.md +1 -1
  164. package/packages/bundled-features/src/legal-pages/lib/boot-check.ts +12 -8
  165. package/packages/bundled-features/src/legal-pages/seed.ts +5 -2
  166. package/packages/bundled-features/src/mail-foundation/feature.ts +2 -2
  167. package/packages/bundled-features/src/mail-transport-smtp/changes.json +12 -0
  168. package/packages/bundled-features/src/mail-transport-smtp/config-keys.ts +1 -1
  169. package/packages/bundled-features/src/mail-transport-smtp/feature.ts +13 -12
  170. package/packages/bundled-features/src/managed-pages/changes.json +6 -0
  171. package/packages/bundled-features/src/managed-pages/constants.ts +1 -0
  172. package/packages/bundled-features/src/managed-pages/feature.ts +3 -1
  173. package/packages/bundled-features/src/managed-pages/index.ts +1 -0
  174. package/packages/bundled-features/src/managed-pages/seeding.ts +13 -8
  175. package/packages/bundled-features/src/notes-history/handlers/add-note.write.ts +2 -2
  176. package/packages/bundled-features/src/personal-access-tokens/feature.ts +2 -1
  177. package/packages/bundled-features/src/personal-access-tokens/handlers/create.write.ts +2 -2
  178. package/packages/bundled-features/src/personal-access-tokens/handlers/revoke.write.ts +1 -1
  179. package/packages/bundled-features/src/rate-limiting/handlers/status.query.ts +2 -2
  180. package/packages/bundled-features/src/readiness/handlers/status.query.ts +4 -1
  181. package/packages/bundled-features/src/renderer-foundation/api.ts +3 -3
  182. package/packages/bundled-features/src/secrets/announce-secret-change.ts +4 -4
  183. package/packages/bundled-features/src/secrets/changes.json +6 -0
  184. package/packages/bundled-features/src/secrets/feature.ts +9 -9
  185. package/packages/bundled-features/src/secrets/handlers/delete.write.ts +4 -3
  186. package/packages/bundled-features/src/secrets/handlers/rotate.job.ts +13 -8
  187. package/packages/bundled-features/src/secrets/handlers/set.write.ts +4 -3
  188. package/packages/bundled-features/src/secrets/secrets-context.ts +16 -6
  189. package/packages/bundled-features/src/secrets/write-gate.ts +10 -3
  190. package/packages/bundled-features/src/seo/feature.ts +1 -1
  191. package/packages/bundled-features/src/sessions/changes.json +19 -0
  192. package/packages/bundled-features/src/sessions/feature.ts +2 -1
  193. package/packages/bundled-features/src/sessions/handlers/cleanup.job.ts +2 -2
  194. package/packages/bundled-features/src/sessions/handlers/detail.query.ts +5 -2
  195. package/packages/bundled-features/src/sessions/handlers/list.query.ts +5 -2
  196. package/packages/bundled-features/src/sessions/handlers/mine.query.ts +5 -2
  197. package/packages/bundled-features/src/sessions/handlers/revoke-all-for-user.write.ts +3 -3
  198. package/packages/bundled-features/src/sessions/handlers/revoke-all-others.write.ts +1 -1
  199. package/packages/bundled-features/src/sessions/handlers/revoke.write.ts +1 -1
  200. package/packages/bundled-features/src/sessions/index.ts +1 -1
  201. package/packages/bundled-features/src/sessions/screens.ts +8 -4
  202. package/packages/bundled-features/src/sessions/session-callbacks.ts +1 -9
  203. package/packages/bundled-features/src/sessions/session-revoked-event.ts +1 -1
  204. package/packages/bundled-features/src/sessions/web/session-device-cell.tsx +10 -12
  205. package/packages/bundled-features/src/sessions/web/user-agent.ts +12 -0
  206. package/packages/bundled-features/src/shared/index.ts +15 -0
  207. package/packages/bundled-features/src/shared/purge-files-reaching-subject.ts +36 -4
  208. package/packages/bundled-features/src/shared/require-for-tenant.ts +7 -5
  209. package/packages/bundled-features/src/shared/run-in-sub-transaction.ts +5 -5
  210. package/packages/bundled-features/src/shared/stream-tenant-backfill.ts +201 -0
  211. package/packages/bundled-features/src/shared/stream-tenant-derived-state.ts +107 -0
  212. package/packages/bundled-features/src/step-dispatcher/changes.json +6 -0
  213. package/packages/bundled-features/src/step-dispatcher/deliver-dispatch-request.ts +17 -3
  214. package/packages/bundled-features/src/step-dispatcher/feature.ts +1 -1
  215. package/packages/bundled-features/src/step-dispatcher/mail-runner.ts +2 -1
  216. package/packages/bundled-features/src/subscription-dodo/plugin-methods.ts +1 -1
  217. package/packages/bundled-features/src/subscription-dodo/runtime.ts +7 -7
  218. package/packages/bundled-features/src/subscription-stripe/plugin-methods.ts +5 -3
  219. package/packages/bundled-features/src/subscription-stripe/runtime.ts +7 -7
  220. package/packages/bundled-features/src/tags/feature.ts +1 -0
  221. package/packages/bundled-features/src/template-resolver/api.ts +3 -3
  222. package/packages/bundled-features/src/template-resolver/changes.json +54 -0
  223. package/packages/bundled-features/src/template-resolver/document-ops.ts +20 -1
  224. package/packages/bundled-features/src/template-resolver/feature.ts +2 -2
  225. package/packages/bundled-features/src/template-resolver/handlers/bundle-import.ts +5 -4
  226. package/packages/bundled-features/src/template-resolver/handlers/copy-locale.write.ts +2 -2
  227. package/packages/bundled-features/src/template-resolver/handlers/export-bundle.query.ts +1 -1
  228. package/packages/bundled-features/src/template-resolver/handlers/layout-source.query.ts +36 -11
  229. package/packages/bundled-features/src/template-resolver/handlers/overview.query.ts +32 -7
  230. package/packages/bundled-features/src/template-resolver/handlers/patch-draft.write.ts +1 -1
  231. package/packages/bundled-features/src/template-resolver/handlers/send-test-shared.ts +1 -1
  232. package/packages/bundled-features/src/template-resolver/handlers/send-test-status.query.ts +22 -19
  233. package/packages/bundled-features/src/template-resolver/handlers/send-test.write.ts +2 -2
  234. package/packages/bundled-features/src/template-resolver/handlers/tenant-override-selection.ts +6 -2
  235. package/packages/bundled-features/src/template-resolver/handlers/tenant-overrides.query.ts +4 -2
  236. package/packages/bundled-features/src/template-resolver/handlers/usage.query.ts +1 -1
  237. package/packages/bundled-features/src/template-resolver/seeding.ts +22 -5
  238. package/packages/bundled-features/src/template-resolver/store-template-resource.ts +68 -19
  239. package/packages/bundled-features/src/template-resolver/template-resources.ts +4 -4
  240. package/packages/bundled-features/src/template-resolver/testing.ts +2 -2
  241. package/packages/bundled-features/src/template-resolver/web/document-insert-fields.tsx +222 -0
  242. package/packages/bundled-features/src/template-resolver/web/document-insert-model.ts +164 -0
  243. package/packages/bundled-features/src/template-resolver/web/document-insert-panel.tsx +115 -0
  244. package/packages/bundled-features/src/template-resolver/web/document-tiptap-bubble.tsx +177 -0
  245. package/packages/bundled-features/src/template-resolver/web/document-tiptap-content.tsx +38 -0
  246. package/packages/bundled-features/src/template-resolver/web/document-tiptap-context.ts +119 -0
  247. package/packages/bundled-features/src/template-resolver/web/document-tiptap-editor.tsx +51 -1098
  248. package/packages/bundled-features/src/template-resolver/web/document-tiptap-helpers.ts +161 -0
  249. package/packages/bundled-features/src/template-resolver/web/document-tiptap-layout.tsx +83 -0
  250. package/packages/bundled-features/src/template-resolver/web/document-tiptap-toolbar-groups.tsx +153 -0
  251. package/packages/bundled-features/src/template-resolver/web/document-tiptap-toolbar.tsx +182 -0
  252. package/packages/bundled-features/src/template-resolver/web/editor-handle.ts +18 -0
  253. package/packages/bundled-features/src/template-resolver/web/i18n.ts +6 -0
  254. package/packages/bundled-features/src/template-resolver/web/placeholder-line-editor.tsx +19 -6
  255. package/packages/bundled-features/src/template-resolver/web/qualified-names.ts +1 -0
  256. package/packages/bundled-features/src/template-resolver/web/use-document-tiptap-model.ts +138 -0
  257. package/packages/bundled-features/src/tenant/changes.json +19 -0
  258. package/packages/bundled-features/src/tenant/feature.ts +1 -0
  259. package/packages/bundled-features/src/tenant/handlers/cancel-invitation.write.ts +1 -1
  260. package/packages/bundled-features/src/tenant/handlers/memberships.query.ts +1 -1
  261. package/packages/bundled-features/src/tenant/handlers/remove-member.write.ts +2 -2
  262. package/packages/bundled-features/src/tenant/handlers/team-list.query.ts +3 -3
  263. package/packages/bundled-features/src/tenant/handlers/update-member-roles.write.ts +1 -1
  264. package/packages/bundled-features/src/tenant/index.ts +5 -0
  265. package/packages/bundled-features/src/tenant/invited-membership.ts +6 -1
  266. package/packages/bundled-features/src/tenant/schema/tenant.ts +4 -1
  267. package/packages/bundled-features/src/tenant/seeding.ts +65 -62
  268. package/packages/bundled-features/src/tenant/stream-tenant-backfill.ts +115 -0
  269. package/packages/bundled-features/src/tenant/testing.ts +77 -0
  270. package/packages/bundled-features/src/tenant-handover/events.ts +1 -1
  271. package/packages/bundled-features/src/tenant-handover/handlers/claim.write.ts +1 -1
  272. package/packages/bundled-features/src/tenant-lifecycle/changes.json +6 -0
  273. package/packages/bundled-features/src/tenant-lifecycle/feature.ts +5 -5
  274. package/packages/bundled-features/src/tenant-lifecycle/handlers/cancel-destruction.write.ts +22 -10
  275. package/packages/bundled-features/src/tenant-lifecycle/handlers/request-destruction.write.ts +22 -11
  276. package/packages/bundled-features/src/tenant-lifecycle/run-tenant-destroy.ts +23 -12
  277. package/packages/bundled-features/src/tenant-lifecycle/stages.ts +42 -4
  278. package/packages/bundled-features/src/tenant-lifecycle/testing.ts +9 -8
  279. package/packages/bundled-features/src/tier-engine/entity.ts +1 -1
  280. package/packages/bundled-features/src/tier-engine/feature.ts +8 -3
  281. package/packages/bundled-features/src/tier-engine/handlers/active-tier.query.ts +3 -3
  282. package/packages/bundled-features/src/tier-engine/handlers/get-tenant-tier.query.ts +7 -1
  283. package/packages/bundled-features/src/tier-engine/handlers/set-tenant-tier.write.ts +3 -3
  284. package/packages/bundled-features/src/user/db/queries/stream-tenant-backfill.ts +71 -97
  285. package/packages/bundled-features/src/user/feature.ts +1 -0
  286. package/packages/bundled-features/src/user/handlers/find-for-auth.query.ts +2 -2
  287. package/packages/bundled-features/src/user/handlers/update-roles.ts +2 -2
  288. package/packages/bundled-features/src/user/index.ts +2 -0
  289. package/packages/bundled-features/src/user/invited-global-roles.ts +6 -1
  290. package/packages/bundled-features/src/user/principal-status.ts +1 -1
  291. package/packages/bundled-features/src/user/seeding.ts +24 -6
  292. package/packages/bundled-features/src/user/testing.ts +22 -0
  293. package/packages/bundled-features/src/user-data-rights/COMPLIANCE.md +1 -1
  294. package/packages/bundled-features/src/user-data-rights/README.md +1 -1
  295. package/packages/bundled-features/src/user-data-rights/audit-download.ts +12 -2
  296. package/packages/bundled-features/src/user-data-rights/changes.json +36 -0
  297. package/packages/bundled-features/src/user-data-rights/feature.ts +30 -24
  298. package/packages/bundled-features/src/user-data-rights/handlers/confirm-deletion-by-token.write.ts +1 -1
  299. package/packages/bundled-features/src/user-data-rights/handlers/deletion-grace-period.ts +1 -1
  300. package/packages/bundled-features/src/user-data-rights/handlers/download-by-job.query.ts +2 -2
  301. package/packages/bundled-features/src/user-data-rights/handlers/download-by-token.query.ts +2 -2
  302. package/packages/bundled-features/src/user-data-rights/handlers/request-deletion.write.ts +1 -1
  303. package/packages/bundled-features/src/user-data-rights/handlers/restrict-account.write.ts +4 -4
  304. package/packages/bundled-features/src/user-data-rights/handlers/run-forget-cleanup.write.ts +12 -6
  305. package/packages/bundled-features/src/user-data-rights/index.ts +8 -1
  306. package/packages/bundled-features/src/user-data-rights/lib/mail-transport-resolver.ts +1 -1
  307. package/packages/bundled-features/src/user-data-rights/lib/storage-provider-resolver.ts +1 -1
  308. package/packages/bundled-features/src/user-data-rights/lib/update-user-lifecycle.ts +6 -1
  309. package/packages/bundled-features/src/user-data-rights/run-export-jobs.ts +8 -2
  310. package/packages/bundled-features/src/user-data-rights/run-forget-cleanup.ts +14 -3
  311. package/packages/bundled-features/src/user-data-rights/run-user-export.ts +11 -1
  312. package/packages/bundled-features/src/user-data-rights/web/constants.ts +16 -0
  313. package/packages/bundled-features/src/user-data-rights/web/index.ts +6 -0
  314. package/packages/bundled-features/src/user-profile/handlers/change-email.write.ts +8 -6
  315. package/packages/bundled-features/src/waitlist/changes.json +18 -0
  316. package/packages/bundled-features/src/waitlist/feature.ts +1 -0
  317. package/packages/bundled-features/src/waitlist/handlers/export-purge.write.ts +1 -1
  318. package/packages/bundled-features/src/waitlist/handlers/invite.write.ts +2 -2
  319. package/packages/bundled-features/src/waitlist/handlers/reject.write.ts +1 -1
  320. package/packages/bundled-features/src/waitlist/handlers/submit.write.ts +34 -10
  321. package/packages/bundled-features/src/waitlist/import.ts +23 -3
  322. package/packages/bundled-features/src/waitlist/legacy-migrate.ts +8 -2
  323. package/packages/bundled-features/src/waitlist/link-on-signup.ts +7 -1
  324. package/packages/bundled-features/src/waitlist/options.ts +2 -1
  325. package/packages/bundled-features/src/workflow-runner/changes.json +6 -0
  326. package/packages/bundled-features/src/workflow-runner/db/queries/due-runs.ts +1 -1
  327. package/packages/bundled-features/src/workflow-runner/event-subscriber.ts +4 -3
  328. package/packages/bundled-features/src/workflow-runner/event-trigger.ts +2 -1
  329. package/packages/bundled-features/src/workflow-runner/feature.ts +2 -2
  330. package/packages/bundled-features/src/workflow-runner/handlers/resume-run.write.ts +8 -8
  331. package/packages/bundled-features/src/workflow-runner/runner.ts +6 -4
  332. package/samples/apps/cap-billing-demo/src/feature.ts +19 -5
  333. package/samples/apps/config-demo/src/app/server.ts +1 -1
  334. package/samples/apps/styleguide/src/app/client.tsx +2 -0
  335. package/samples/apps/styleguide/src/app/seed.ts +6 -4
  336. package/samples/apps/styleguide/src/app/server.ts +6 -3
  337. package/samples/apps/styleguide/src/features/widgets/feature.ts +15 -4
  338. package/samples/apps/styleguide/src/features/workboard/feature.ts +185 -0
  339. package/samples/apps/styleguide/src/features/workboard/i18n.ts +27 -0
  340. package/samples/apps/styleguide/src/features/workboard/seed.ts +121 -0
  341. package/samples/apps/styleguide/src/features/workboard/web.ts +13 -0
  342. package/samples/apps/ui-walkthrough/src/features/rental/i18n.ts +2 -0
  343. package/samples/apps/ui-walkthrough/src/features/rental/screens.ts +9 -0
  344. package/samples/apps/use-all-bundled/bin/main.ts +2 -0
  345. package/samples/apps/use-all-bundled/feature-manifest.json +17 -1
  346. package/samples/apps/use-all-bundled/kumiko/schema.ts +2 -0
  347. package/samples/apps/use-all-bundled/kumiko.config.ts +2 -0
  348. package/samples/apps/use-all-bundled/package.json +2 -1
  349. package/samples/apps/use-all-bundled/src/app/dev-app-options.ts +2 -0
  350. package/samples/apps/use-all-bundled/src/app/notes-feature.ts +2 -0
  351. package/samples/apps/use-all-bundled/src/app/seed.ts +12 -2
  352. package/samples/apps/use-all-bundled/src/bundled-lists.ts +15 -0
  353. package/samples/apps/user-data-rights-demo/README.md +1 -1
  354. package/samples/apps/user-data-rights-demo/src/feature.ts +3 -2
  355. package/samples/recipes/api-worker-split/README.md +2 -1
  356. package/samples/recipes/api-worker-split/src/feature.ts +2 -1
  357. package/samples/recipes/cross-feature-events/README.md +5 -5
  358. package/samples/recipes/cross-feature-events/package.json +1 -1
  359. package/samples/recipes/cross-feature-events/src/feature.ts +4 -4
  360. package/samples/recipes/event-sourcing/README.md +5 -5
  361. package/samples/recipes/event-sourcing/package.json +1 -1
  362. package/samples/recipes/event-sourcing/src/feature.ts +15 -15
  363. package/samples/recipes/files-post-processing/README.md +1 -1
  364. package/samples/recipes/files-post-processing/package.json +1 -1
  365. package/samples/recipes/files-post-processing/src/feature.ts +6 -4
  366. package/samples/recipes/golden-path/src/feature.ts +2 -1
  367. package/samples/recipes/lane-routing/package.json +1 -1
  368. package/samples/recipes/legal-pages/README.md +2 -2
  369. package/samples/recipes/lifecycle-hooks/README.md +4 -0
  370. package/samples/recipes/lifecycle-hooks/src/feature.ts +26 -1
  371. package/samples/recipes/list-table-options/README.md +50 -0
  372. package/samples/recipes/list-table-options/package.json +11 -0
  373. package/samples/recipes/list-table-options/src/feature.ts +221 -0
  374. package/samples/recipes/managed-config/README.md +3 -3
  375. package/samples/recipes/pdf-audit-export/src/feature.ts +2 -1
  376. package/samples/recipes/search/README.md +1 -1
  377. package/samples/recipes/search/src/feature.ts +3 -3
  378. package/samples/recipes/secrets-demo/README.md +1 -1
  379. package/samples/recipes/secrets-demo/src/feature.ts +5 -2
  380. package/samples/recipes/state-machine/src/events.ts +4 -3
  381. package/samples/recipes/state-machine/src/reducer.ts +1 -1
  382. package/samples/recipes/tenant-isolation/README.md +1 -0
  383. package/samples/recipes/tenant-isolation/src/feature.ts +36 -0
  384. package/samples/recipes/workflow-engine/src/resume-loop.ts +4 -4
  385. package/samples/recipes/workflow-engine/src/workflow-runner.ts +2 -2
@@ -12,7 +12,7 @@
12
12
  // after a rollback, failure result or failed COMMIT only gives back what is still booked, so an
13
13
  // unknown COMMIT outcome cannot under-count. No connection is held across the handler. Rows a
14
14
  // crashed process left behind expire after CAP_RESERVATION_TTL_MINUTES and are given back before the
15
- // next reserve of the same cap. Reached through a nested ctx.write the cap is not reserved, so the
15
+ // next reserve of the same cap. Reached through a nested ctx.dispatch.write the cap is not reserved, so the
16
16
  // dispatcher rejects that call unless the top-level batch reserved the same handler.
17
17
  //
18
18
  // The wrapper spreads the wrapped handler and chains its reserveBeforeTransaction: inner reserves
@@ -25,7 +25,7 @@
25
25
  // (enforce-cap.ts).
26
26
 
27
27
  import type {
28
- HandlerContext,
28
+ ReservationContext,
29
29
  WriteEvent,
30
30
  WriteHandlerDef,
31
31
  } from "@cosmicdrift/kumiko-framework/engine";
@@ -67,7 +67,7 @@ export type CalendarCapDef = {
67
67
  * tier from DB. */
68
68
  export type CalendarCapResolver = (
69
69
  event: WriteEvent,
70
- ctx: HandlerContext,
70
+ ctx: ReservationContext,
71
71
  ) => Promise<CalendarCapDef> | CalendarCapDef;
72
72
 
73
73
  /**
@@ -111,7 +111,7 @@ export type RollingCapDef = {
111
111
 
112
112
  export type RollingCapResolver = (
113
113
  event: WriteEvent,
114
- ctx: HandlerContext,
114
+ ctx: ReservationContext,
115
115
  ) => Promise<RollingCapDef> | RollingCapDef;
116
116
 
117
117
  /**
@@ -61,6 +61,7 @@ export function createCapOverviewFeature(opts: CreateCapOverviewOptions): Featur
61
61
  }
62
62
 
63
63
  return defineFeature(CAP_OVERVIEW_FEATURE, (r) => {
64
+ r.adoptsBundledLists();
64
65
  r.describe(
65
66
  "Read-only visibility into per-tenant tier assignment and cap usage. SystemAdmin gets a platform-wide tenant list with usage bars; tenant admins (or the roles in `usageVisibleTo`) get their own tenant's usage as dashboard cards. Reads tier-engine, billing-foundation, and tenant data plus app-owned usage tables via caller-supplied CapSpec callbacks — never writes.",
66
67
  );
@@ -76,7 +76,7 @@ export function createCapsUsageQuery(
76
76
 
77
77
  // Override path: limits must read the TARGET tenant's config, not the
78
78
  // SystemAdmin caller's.
79
- const config = override === undefined ? ctx.config : ctx.configFor?.(targetTenantId);
79
+ const config = override === undefined ? ctx.config : ctx.tenants.config?.(targetTenantId);
80
80
 
81
81
  const rows: CapUsageWithMeta[] = await Promise.all(
82
82
  caps.map(async (cap) => {
@@ -251,7 +251,7 @@ export function createTenantCapsListQuery(caps: readonly CapSpec[], listCaps: re
251
251
  const limitByTenantAndCap = await resolveLimitsByTenantAndCap(
252
252
  listedCaps,
253
253
  page,
254
- ctx.configFor,
254
+ ctx.tenants.config,
255
255
  );
256
256
 
257
257
  const rows: TenantCapsListRow[] = page.map((row) => {
@@ -20,12 +20,12 @@ import {
20
20
  type DbConnection,
21
21
  fetchOne,
22
22
  } from "@cosmicdrift/kumiko-framework/db";
23
- import type { SessionUser, TenantId } from "@cosmicdrift/kumiko-framework/engine";
24
23
  import {
25
- runEventStoreSeed,
26
- type SeedIfExists,
27
- TestUsers,
28
- } from "@cosmicdrift/kumiko-framework/seeding";
24
+ createSystemUser,
25
+ type SessionUser,
26
+ type TenantId,
27
+ } from "@cosmicdrift/kumiko-framework/engine";
28
+ import { runEventStoreSeed, type SeedIfExists } from "@cosmicdrift/kumiko-framework/seeding";
29
29
 
30
30
  import {
31
31
  tenantComplianceProfileEntity,
@@ -52,8 +52,13 @@ export async function seedComplianceProfile(
52
52
  ): Promise<{ id: string }> {
53
53
  // user.tenantId must equal opts.tenantId so the Event Store stream
54
54
  // and projection remain in the same tenant bucket.
55
- const by = opts.by ?? { ...TestUsers.systemAdmin, tenantId: opts.tenantId };
56
- const tdb = createTenantDb({ db, tenantId: opts.tenantId, mode: "system" });
55
+ const by = opts.by ?? createSystemUser(opts.tenantId);
56
+ const tdb = createTenantDb({
57
+ db,
58
+ tenantId: opts.tenantId,
59
+ mode: "system",
60
+ reason: "seeding writes the compliance profile into an explicitly named tenant",
61
+ });
57
62
  const overrideJson = opts.override !== undefined ? JSON.stringify(opts.override) : null;
58
63
 
59
64
  const existing = (await fetchOne(db, tenantComplianceProfileTable, {
@@ -1,4 +1,10 @@
1
1
  [
2
+ {
3
+ "version": "0.389.0",
4
+ "type": "improvement",
5
+ "title": "config:write:set passes readCascade to validators",
6
+ "detail": "The set handler binds readCascade to the config resolver, the tenant-scoped db and the secrets reader, so validators see the same cascade as the value queries."
7
+ },
2
8
  {
3
9
  "version": "0.388.0",
4
10
  "type": "improvement",
@@ -111,15 +111,15 @@ export function createConfigAccessorFactory(
111
111
  // session reads "config feature not wired into AppContext" instead of a
112
112
  // generic "configResolver missing".
113
113
  export function requireConfigResolver(ctx: HandlerContext, handlerName: string): ConfigResolver {
114
- if (!ctx.configResolver) {
114
+ if (!ctx.services.configResolver) {
115
115
  throw new InternalError({
116
116
  message:
117
- `[${handlerName}] ctx.configResolver missing — pass createConfigAccessorFactory's ` +
117
+ `[${handlerName}] ctx.services.configResolver missing — pass createConfigAccessorFactory's ` +
118
118
  `output via extraContext.configAccessorFactory and the resolver via ` +
119
119
  `extraContext.configResolver at boot.`,
120
120
  });
121
121
  }
122
- return ctx.configResolver;
122
+ return ctx.services.configResolver;
123
123
  }
124
124
 
125
125
  // Config declares r.systemScope() (raw ctx.db is unfiltered across tenants
@@ -156,14 +156,14 @@ export function requireSystemDb(
156
156
  // if a handler tries to write an encrypted key without the provider in
157
157
  // place, pointing at the exact wiring gap).
158
158
  export function requireConfigEncryption(ctx: HandlerContext, handlerName: string): EnvelopeCipher {
159
- if (!ctx.configEncryption) {
159
+ if (!ctx.services.configEncryption) {
160
160
  throw new InternalError({
161
161
  message:
162
- `[${handlerName}] ctx.configEncryption missing — at least one config key declares ` +
162
+ `[${handlerName}] ctx.services.configEncryption missing — at least one config key declares ` +
163
163
  `encrypted: true, so the boot wiring must pass an EnvelopeCipher via ` +
164
164
  `extraContext.configEncryption (run{Prod,Dev}App wire it automatically from ` +
165
165
  `KUMIKO_SECRETS_MASTER_KEY_V<n>; same instance the resolver was built with).`,
166
166
  });
167
167
  }
168
- return ctx.configEncryption;
168
+ return ctx.services.configEncryption;
169
169
  }
@@ -59,7 +59,7 @@ export const cascadeQuery = defineQueryHandler({
59
59
  query.user.tenantId,
60
60
  query.user.id,
61
61
  db,
62
- ctx.secrets,
62
+ ctx.services.secrets,
63
63
  );
64
64
 
65
65
  const result: Record<string, ConfigCascade> = {};
@@ -106,7 +106,7 @@ export async function collectMissingRequiredConfig(
106
106
  user.tenantId,
107
107
  user.id,
108
108
  db,
109
- ctx.secrets,
109
+ ctx.services.secrets,
110
110
  );
111
111
  for (const [qualifiedKey, keyDef] of candidates) {
112
112
  // Deliberately the unredacted cascade value: readiness asks "does this
@@ -69,22 +69,22 @@ export type ReencryptJobResult = {
69
69
 
70
70
  export const reencryptJob: JobHandlerFn = async (rawPayload, ctx): Promise<void> => {
71
71
  const payload = rawPayload as ReencryptJobPayload; // @cast-boundary engine-payload
72
- const maybeCipher = ctx.configEncryption;
72
+ const maybeCipher = ctx.services.configEncryption;
73
73
  if (!maybeCipher) {
74
74
  throw new InternalError({
75
75
  message:
76
- "[config:reencrypt] ctx.configEncryption missing — provide a master key " +
76
+ "[config:reencrypt] ctx.services.configEncryption missing — provide a master key " +
77
77
  "(KUMIKO_SECRETS_MASTER_KEY_V<n>) so the boot wires the envelope cipher.",
78
78
  });
79
79
  }
80
80
  // hoisted function declarations below capture these — pin the narrowed
81
81
  // type explicitly so TS keeps it inside the closures
82
82
  const cipher: EnvelopeCipher = maybeCipher;
83
- const provider = ctx.masterKeyProvider;
83
+ const provider = ctx.services.masterKeyProvider;
84
84
  if (!provider) {
85
85
  throw new InternalError({
86
86
  message:
87
- "[config:reencrypt] ctx.masterKeyProvider missing — wire it via extraContext.masterKeyProvider at boot.",
87
+ "[config:reencrypt] ctx.services.masterKeyProvider missing — wire it via extraContext.masterKeyProvider at boot.",
88
88
  });
89
89
  }
90
90
  if (!ctx.registry) {
@@ -116,8 +116,8 @@ export const reencryptJob: JobHandlerFn = async (rawPayload, ctx): Promise<void>
116
116
  handler: "config:job:reencrypt",
117
117
  tenantId,
118
118
  actor: "system",
119
- sink: ctx._escapeHatchAuditSink,
120
- log: ctx.log,
119
+ sink: ctx.services._escapeHatchAuditSink,
120
+ log: ctx.obs.log,
121
121
  });
122
122
  }
123
123
 
@@ -125,7 +125,12 @@ export const reencryptJob: JobHandlerFn = async (rawPayload, ctx): Promise<void>
125
125
  function tdbFor(tenantId: TenantId): TenantDb {
126
126
  let existing = tdbCache.get(tenantId);
127
127
  if (!existing) {
128
- existing = createTenantDb({ db, tenantId, mode: "system" });
128
+ existing = createTenantDb({
129
+ db,
130
+ tenantId,
131
+ mode: "system",
132
+ reason: "KEK rotation job re-encrypts config values of every tenant",
133
+ });
129
134
  tdbCache.set(tenantId, existing);
130
135
  }
131
136
  return existing;
@@ -146,7 +151,12 @@ export const reencryptJob: JobHandlerFn = async (rawPayload, ctx): Promise<void>
146
151
  // tenant's writes — sharing it with sdbFor(SYSTEM_TENANT_ID) would make a
147
152
  // write-path cache entry double as the scan's ack gate.
148
153
  const scanDb = createSystemDbView(
149
- createTenantDb({ db, tenantId: SYSTEM_TENANT_ID, mode: "system" }),
154
+ createTenantDb({
155
+ db,
156
+ tenantId: SYSTEM_TENANT_ID,
157
+ mode: "system",
158
+ reason: "KEK rotation scan enumerates config values across all tenants",
159
+ }),
150
160
  undefined,
151
161
  reportEscapeHatchFor(SYSTEM_TENANT_ID),
152
162
  );
@@ -219,7 +229,7 @@ export const reencryptJob: JobHandlerFn = async (rawPayload, ctx): Promise<void>
219
229
  // format) — never a supported re-encrypt input, so fail loudly
220
230
  // instead of relying on cipher.decrypt to reject it. Log only the
221
231
  // row id, never the value (ciphertext-adjacent).
222
- ctx.log?.warn?.(
232
+ ctx.obs.log?.warn?.(
223
233
  `[config:reencrypt] row ${row.id} is not a current-cipher envelope, not re-encryptable`,
224
234
  );
225
235
  return "failed";
@@ -244,7 +254,7 @@ export const reencryptJob: JobHandlerFn = async (rawPayload, ctx): Promise<void>
244
254
  // holds a fresh envelope written by the set handler — already fine.
245
255
  if (!result.isSuccess) {
246
256
  if (result.error.code === "version_conflict") return "skipped";
247
- ctx.log?.warn?.(`[config:reencrypt] executor rejected row ${row.id}`, {
257
+ ctx.obs.log?.warn?.(`[config:reencrypt] executor rejected row ${row.id}`, {
248
258
  code: result.error.code,
249
259
  });
250
260
  return "failed";
@@ -257,9 +267,9 @@ export const reencryptJob: JobHandlerFn = async (rawPayload, ctx): Promise<void>
257
267
  migrateRow,
258
268
  maxFailures,
259
269
  deadlineAt: deadline,
260
- signal: ctx.signal,
270
+ signal: ctx.lifecycle.signal,
261
271
  onRowError: ({ row }, err) => {
262
- ctx.log?.warn?.(`[config:reencrypt] failed to re-encrypt row ${row.id}`, { err });
272
+ ctx.obs.log?.warn?.(`[config:reencrypt] failed to re-encrypt row ${row.id}`, { err });
263
273
  },
264
274
  });
265
275
 
@@ -269,5 +279,5 @@ export const reencryptJob: JobHandlerFn = async (rawPayload, ctx): Promise<void>
269
279
  alreadyCurrent,
270
280
  stoppedReason: outcome.stoppedReason,
271
281
  };
272
- ctx.log?.info?.(`[config:reencrypt] complete: ${JSON.stringify(result)}`);
282
+ ctx.obs.log?.info?.(`[config:reencrypt] complete: ${JSON.stringify(result)}`);
273
283
  };
@@ -48,14 +48,14 @@ export const resetWrite = defineWriteHandler({
48
48
  // backing="secrets": clear the secret from the secrets store. delete() is
49
49
  // idempotent (returns false if absent) — mirrors the config no-op contract.
50
50
  if (keyDef.backing === "secrets") {
51
- if (!ctx.secrets) {
51
+ if (!ctx.services.secrets) {
52
52
  throw new InternalError({
53
53
  message:
54
54
  `[config:write:reset] key "${event.payload.key}" declares backing="secrets" but ` +
55
- `ctx.secrets is not wired — provide extraContext.secrets (and a MasterKeyProvider).`,
55
+ `ctx.services.secrets is not wired — provide extraContext.secrets (and a MasterKeyProvider).`,
56
56
  });
57
57
  }
58
- await ctx.secrets.delete(SYSTEM_TENANT_ID, event.payload.key, {
58
+ await ctx.services.secrets.delete(SYSTEM_TENANT_ID, event.payload.key, {
59
59
  deletedBy: event.user.id,
60
60
  });
61
61
  return { isSuccess: true, data: { key: event.payload.key, scope } };
@@ -53,7 +53,7 @@ export const selectedExtensionsQuery = defineQueryHandler({
53
53
  query.user.tenantId,
54
54
  query.user.id,
55
55
  db,
56
- ctx.secrets,
56
+ ctx.services.secrets,
57
57
  );
58
58
  const selected: Record<string, string> = {};
59
59
  for (const [selectorKey, keyDef] of readableSelectors) {
@@ -18,7 +18,7 @@ import {
18
18
  writeFailure,
19
19
  } from "@cosmicdrift/kumiko-framework/errors";
20
20
  import * as z from "zod";
21
- import { requireConfigEncryption, requireSystemDb } from "../feature.ts";
21
+ import { requireConfigEncryption, requireConfigResolver, requireSystemDb } from "../feature.ts";
22
22
  import { MASKED } from "../read-redaction.ts";
23
23
  import { configValueEntity, configValuesTable } from "../table.ts";
24
24
  import {
@@ -106,13 +106,30 @@ export const setWrite = defineWriteHandler({
106
106
  if (patternError) return writeFailure(patternError);
107
107
 
108
108
  if (keyDef.validate) {
109
+ const validateDb = scopeTenantDbToTenant(db, tenantId);
109
110
  try {
110
111
  await keyDef.validate(event.payload.value, {
111
112
  key: event.payload.key,
112
113
  scope,
113
114
  tenantId,
114
115
  userId,
115
- db: scopeTenantDbToTenant(db, tenantId),
116
+ db: validateDb,
117
+ readCascade: (qualifiedKey) => {
118
+ const cascadeKeyDef = ctx.registry.getConfigKey(qualifiedKey);
119
+ if (!cascadeKeyDef) {
120
+ throw new InternalError({
121
+ message: `[config:write:set] readCascade: unknown config key "${qualifiedKey}"`,
122
+ });
123
+ }
124
+ return requireConfigResolver(ctx, "config:write:set").getCascade(
125
+ qualifiedKey,
126
+ cascadeKeyDef,
127
+ tenantId,
128
+ event.user.id,
129
+ validateDb,
130
+ ctx.services.secrets,
131
+ );
132
+ },
116
133
  });
117
134
  } catch (error) {
118
135
  if (isKumikoError(error)) return writeFailure(error);
@@ -129,14 +146,14 @@ export const setWrite = defineWriteHandler({
129
146
  // serialization as a config row so the read path round-trips via
130
147
  // deserializeValue. system-scope is guaranteed by the boot-guard.
131
148
  if (keyDef.backing === "secrets") {
132
- if (!ctx.secrets) {
149
+ if (!ctx.services.secrets) {
133
150
  throw new InternalError({
134
151
  message:
135
152
  `[config:write:set] key "${event.payload.key}" declares backing="secrets" but ` +
136
- `ctx.secrets is not wired — provide extraContext.secrets (and a MasterKeyProvider).`,
153
+ `ctx.services.secrets is not wired — provide extraContext.secrets (and a MasterKeyProvider).`,
137
154
  });
138
155
  }
139
- await ctx.secrets.set(
156
+ await ctx.services.secrets.set(
140
157
  SYSTEM_TENANT_ID,
141
158
  event.payload.key,
142
159
  JSON.stringify(event.payload.value),
@@ -59,7 +59,7 @@ export const valuesQuery = defineQueryHandler({
59
59
  query.user.tenantId,
60
60
  query.user.id,
61
61
  db,
62
- ctx.secrets,
62
+ ctx.services.secrets,
63
63
  );
64
64
 
65
65
  const result: Record<
@@ -1,4 +1,16 @@
1
1
  [
2
+ {
3
+ "version": "0.389.0",
4
+ "type": "improvement",
5
+ "title": "Tests pin the erasure write purpose in forget-subject and the forget cleanup",
6
+ "detail": "A pre-KMS user whose key was already erased still ends deleted, loses its tokens and gets the erased sentinel in the update event."
7
+ },
8
+ {
9
+ "version": "0.389.0",
10
+ "type": "improvement",
11
+ "title": "The subject file purge reads candidate rows in pages",
12
+ "detail": "A user owning many records no longer loads them all into memory at once; every page is purged, not only the first."
13
+ },
2
14
  {
3
15
  "version": "0.388.0",
4
16
  "type": "fix",
@@ -257,7 +257,7 @@ async function appendDenialAuditEvent(
257
257
  new InternalError({
258
258
  message:
259
259
  "[crypto-shredding] forget-subject denial audit event cannot be appended without " +
260
- "ctx.dbOutsideTransaction — dispatch wiring is missing the outside-tx db source.",
260
+ "ctx.db.outsideTransaction — dispatch wiring is missing the outside-tx db source.",
261
261
  }),
262
262
  );
263
263
  }
@@ -340,11 +340,11 @@ async function sweepDerivedSubjectData(
340
340
 
341
341
  // Derived search index still holds plaintext — purge next to the
342
342
  // blind-index sweep. No adapter → no-op (apps without search).
343
- if (ctx.searchAdapter) {
343
+ if (ctx.services.searchAdapter) {
344
344
  await purgeSearchDocumentsForSubject(
345
345
  crossTenantSubjectRunner,
346
346
  ctx.registry.features,
347
- ctx.searchAdapter,
347
+ ctx.services.searchAdapter,
348
348
  subjectKey,
349
349
  subject,
350
350
  );
@@ -432,7 +432,7 @@ async function appendSubjectForgotten(
432
432
  outsideRunner: DbRunner | undefined,
433
433
  ): Promise<void> {
434
434
  if (!outsideRunner) {
435
- await ctx.unsafeAppendEvent({
435
+ await ctx.events.unsafeAppend({
436
436
  aggregateId,
437
437
  aggregateType: CRYPTO_SHREDDING_AGGREGATE_TYPE,
438
438
  type: SUBJECT_FORGOTTEN_EVENT_NAME,
@@ -521,7 +521,7 @@ export const forgetSubjectWrite = defineWriteHandler({
521
521
  subjectKey,
522
522
  raw.kind,
523
523
  denialReasonOf(tenantScopeDenial),
524
- ctx.dbOutsideTransaction?.unsafeRaw(),
524
+ ctx.db.outsideTransaction?.unsafeRaw(),
525
525
  );
526
526
  return auditFailure ?? tenantScopeDenial;
527
527
  }
@@ -537,7 +537,7 @@ export const forgetSubjectWrite = defineWriteHandler({
537
537
  subjectKey,
538
538
  raw.kind,
539
539
  TARGET_RECORD_RETENTION_BLOCK_DELETE,
540
- ctx.dbOutsideTransaction?.unsafeRaw(),
540
+ ctx.db.outsideTransaction?.unsafeRaw(),
541
541
  );
542
542
  return auditFailure ?? retentionDenial;
543
543
  }
@@ -562,7 +562,7 @@ export const forgetSubjectWrite = defineWriteHandler({
562
562
  // - user.updated as lifecycle event (updateUserLifecycle), so a
563
563
  // read_users rebuild doesn't wipe the flip
564
564
  // - sessions don't need active revocation — session-callbacks
565
- // re-validate user.status on every request (isPrincipalBlocked
565
+ // re-validate the user row on every request (isPrincipalRowBlocked
566
566
  // blocks Deleted).
567
567
  // Both idempotent (status set / revokedAt IS NULL filter), retry after
568
568
  // crash recovery is safe. User-feature guard: without the user feature
@@ -575,7 +575,7 @@ export const forgetSubjectWrite = defineWriteHandler({
575
575
  await closeUserLoginDoor(
576
576
  ctx,
577
577
  raw.userId,
578
- ctx.dbOutsideTransaction?.unsafeRaw(),
578
+ ctx.db.outsideTransaction?.unsafeRaw(),
579
579
  ctx.db.unsafeRaw(),
580
580
  );
581
581
  }
@@ -599,7 +599,7 @@ export const forgetSubjectWrite = defineWriteHandler({
599
599
  forgottenBy: event.user.id,
600
600
  ...(cleanupError !== undefined && { cleanupError }),
601
601
  },
602
- ctx.dbOutsideTransaction?.unsafeRaw(),
602
+ ctx.db.outsideTransaction?.unsafeRaw(),
603
603
  );
604
604
 
605
605
  if (cleanupError !== undefined) {
@@ -5,16 +5,16 @@ import type { DeleteFileBytes } from "../shared/index.ts";
5
5
 
6
6
  const ERROR_CONTEXT = "crypto-shredding:forget-subject";
7
7
 
8
- // The upload resolver, not ctx.files: ctx.files is bound to the acting user's tenant, while a
8
+ // The upload resolver, not ctx.services.files: ctx.services.files is bound to the acting user's tenant, while a
9
9
  // subject's rows can live in any tenant. Resolved eagerly so a missing provider surfaces as
10
10
  // missing_file_storage instead of a failed delete.
11
11
  export function resolveFileBytesDeleter(
12
12
  ctx: HandlerContext,
13
13
  ): (tenantId: TenantId) => Promise<DeleteFileBytes | undefined> {
14
14
  return async (tenantId) => {
15
- const resolver = ctx._fileProviderResolver;
15
+ const resolver = ctx.services._fileProviderResolver;
16
16
  if (resolver === undefined) {
17
- const own = tenantId === ctx.user.tenantId ? ctx.files : undefined;
17
+ const own = tenantId === ctx.user.tenantId ? ctx.services.files : undefined;
18
18
  return own && ((key) => deleteFileRefBytes(own, { storageKey: key }, ERROR_CONTEXT));
19
19
  }
20
20
  try {
@@ -1,4 +1,10 @@
1
1
  [
2
+ {
3
+ "version": "0.390.0",
4
+ "type": "fix",
5
+ "title": "wireCustomFieldsUserDataRightsFor is exported from ./custom-fields",
6
+ "detail": "The helper that adds custom fields to the user-data-rights export is documented as an app call but was missing from the subpath exports. It is exported again together with its options type."
7
+ },
2
8
  {
3
9
  "version": "0.370.0",
4
10
  "type": "breaking",
@@ -59,7 +59,7 @@ export const clearCustomFieldHandler: WriteHandlerDef = {
59
59
  });
60
60
  }
61
61
 
62
- await ctx.unsafeAppendEvent({
62
+ await ctx.events.unsafeAppend({
63
63
  aggregateId: payload.entityId,
64
64
  aggregateType: payload.entityName,
65
65
  type: createCustomFieldsFeature().exports.clearedEvent.name,
@@ -34,7 +34,7 @@ export const deleteSystemFieldHandler: WriteHandlerDef = {
34
34
  // Cascade-cleanup event — host-entity MSPs remove orphaned values from their
35
35
  // customFields jsonb in the same transaction for atomicity.
36
36
  if (result.isSuccess) {
37
- await ctx.unsafeAppendEvent({
37
+ await ctx.events.unsafeAppend({
38
38
  aggregateId,
39
39
  aggregateType: FIELD_DEFINITION_AGGREGATE_TYPE,
40
40
  type: createCustomFieldsFeature().exports.fieldDefinitionDeletedEvent.name,
@@ -55,7 +55,7 @@ export function createDeleteTenantFieldHandler(
55
55
  // registered via wireCustomFieldsFor consume it and remove orphaned values
56
56
  // from their customFields jsonb. The same transaction makes cleanup atomic.
57
57
  if (result.isSuccess) {
58
- await ctx.unsafeAppendEvent({
58
+ await ctx.events.unsafeAppend({
59
59
  aggregateId,
60
60
  aggregateType: FIELD_DEFINITION_AGGREGATE_TYPE,
61
61
  type: createCustomFieldsFeature().exports.fieldDefinitionDeletedEvent.name,
@@ -97,7 +97,7 @@ export const setCustomFieldHandler: WriteHandlerDef = {
97
97
  // cross-feature augmentation for this event type; the qualified string
98
98
  // name is used directly. The value is ALWAYS included in the event
99
99
  // (custom fields carry no PII), so replay fully reproduces the projection.
100
- await ctx.unsafeAppendEvent({
100
+ await ctx.events.unsafeAppend({
101
101
  aggregateId: payload.entityId,
102
102
  aggregateType: payload.entityName,
103
103
  type: createCustomFieldsFeature().exports.setEvent.name,
@@ -37,3 +37,7 @@ export {
37
37
  type SupportedFieldType,
38
38
  } from "./web/constants.ts";
39
39
  export { customFieldsField, wireCustomFieldsFor } from "./wire-for-entity.ts";
40
+ export {
41
+ type WireCustomFieldsUserDataRightsOptions,
42
+ wireCustomFieldsUserDataRightsFor,
43
+ } from "./wire-user-data-rights.ts";
@@ -1,7 +1,7 @@
1
1
  // Centralised parser for `fieldDefinition.serializedField`.
2
2
  //
3
3
  // The column is stored as `text` in B1 (entity.ts) — what the db row hands
4
- // back depends on the driver: postgres-js returns text as a `string`, but
4
+ // back depends on the driver: text normally arrives as a `string`, but
5
5
  // jsonb-tolerant drivers and middleware can deliver an already-parsed
6
6
  // object. This helper normalises both, validates the shape, and centralises
7
7
  // the single boundary cast so callers don't sprinkle `as { … }`-narrowings
@@ -101,7 +101,7 @@ export function createDataRetentionFeature(): FeatureDefinition {
101
101
  tenantId,
102
102
  preloadedTenantPreset: tenantPreset,
103
103
  now: T.Now.instant(),
104
- files: ctx.files,
104
+ files: ctx.services.files,
105
105
  });
106
106
  if (result.skipped.length > 0) {
107
107
  // biome-ignore lint/suspicious/noConsole: operator-visibility for skipped entities
@@ -254,7 +254,12 @@ async function forgetRowAndEraseKeys(args: {
254
254
  readonly registry: Registry;
255
255
  }): Promise<{ readonly isSuccess: boolean }> {
256
256
  return runInSubTransaction(args.db, async (sp) => {
257
- const tdb = createTenantDb({ db: sp, tenantId: args.tenantId, mode: "system" });
257
+ const tdb = createTenantDb({
258
+ db: sp,
259
+ tenantId: args.tenantId,
260
+ mode: "system",
261
+ reason: "retention sweep forgets rows of the tenant being swept, outside any request scope",
262
+ });
258
263
  const result = await args.executor.forget({ id: args.rowId }, args.systemUser, tdb);
259
264
  if (!result.isSuccess) return { isSuccess: false };
260
265
  await eraseHardDeletedRowKeys({
@@ -508,7 +513,12 @@ export async function runRetentionCleanup(
508
513
  // the daily cron converges (hardDelete removes rows, softDelete's isDeleted
509
514
  // filter shrinks the set). A single batched forget/delete event is a follow-up.
510
515
  const systemUser = createSystemUser(tenantId);
511
- const tdb = createTenantDb({ db, tenantId, mode: "system" });
516
+ const tdb = createTenantDb({
517
+ db,
518
+ tenantId,
519
+ mode: "system",
520
+ reason: "retention sweep forgets rows of the tenant being swept, outside any request scope",
521
+ });
512
522
  const fileHolders = collectSingleFileHolders(registry);
513
523
 
514
524
  // Pre-load every override row for this tenant ONCE — N entities × M
@@ -63,7 +63,7 @@ async function writeAttemptEvent(
63
63
  ): Promise<void> {
64
64
  const { tenantId, ...rest } = entry;
65
65
  // Masked here, the only place attempt events are written, so no event or projection row ever holds the full address.
66
- // Schema-parse to match ctx.appendEvent's guarantee: a payload drift between
66
+ // Schema-parse to match ctx.events.append's guarantee: a payload drift between
67
67
  // service/job + feature-registration fails loudly here instead of landing on
68
68
  // the events-table and crashing a consumer later.
69
69
  const payload = deliveryAttemptSchema.parse({
@@ -1,4 +1,16 @@
1
1
  [
2
+ {
3
+ "version": "0.389.0",
4
+ "type": "fix",
5
+ "title": "Unsubscribe link origin is looked up once per notify call",
6
+ "detail": "The tenantOrigin callback runs once per tenant for a notify call with many recipients, and a fallback warning is logged once. A callback that hangs is still not guarded by a timeout, so keep it fast."
7
+ },
8
+ {
9
+ "version": "0.389.0",
10
+ "type": "improvement",
11
+ "title": "buildSystemChannelContext for system tenant mails outside a handler",
12
+ "detail": "buildSystemChannelContext(deps, { config, secrets }) returns a ChannelContext for the system tenant whose readAttachment reads file and inline attachments. SystemWireDeps (wire hook and runWorkerApp wireComponents) has a new required filesForTenant that deps can pass straight in."
13
+ },
2
14
  {
3
15
  "version": "0.388.0",
4
16
  "type": "fix",