@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
@@ -77,7 +77,12 @@ async function releaseRowFileRefs(
77
77
  isCreateMode,
78
78
  );
79
79
  const systemUser = createSystemUser(row.tenantId);
80
- const tenantDb = createTenantDb({ db, tenantId: row.tenantId, mode: "system" });
80
+ const tenantDb = createTenantDb({
81
+ db,
82
+ tenantId: row.tenantId,
83
+ mode: "system",
84
+ reason: "stale-draft cleanup job removes drafts of each tenant, outside any request scope",
85
+ });
81
86
  for (const ref of ownedRefs) {
82
87
  const forgetResult = await fileRefExecutor.forget({ id: ref.id }, systemUser, tenantDb);
83
88
  if (!forgetResult.isSuccess) {
@@ -137,7 +142,12 @@ export async function deleteStaleDraftsBatch(
137
142
  const byId = new Map(batch.map((row) => [row.id, row]));
138
143
  for (const [tenantId, ids] of groupStaleDraftIdsByTenant(batch)) {
139
144
  const systemUser = createSystemUser(tenantId);
140
- const tenantDb = createTenantDb({ db, tenantId, mode: "system" });
145
+ const tenantDb = createTenantDb({
146
+ db,
147
+ tenantId,
148
+ mode: "system",
149
+ reason: "stale-draft cleanup job removes drafts of each tenant, outside any request scope",
150
+ });
141
151
  for (const id of ids) {
142
152
  // skip: an unreadable blob hides its FileRefs; deleting now would orphan them, so the next run retries.
143
153
  if (byId.get(id)?.draftUnreadable) {
@@ -171,8 +181,8 @@ export async function cleanupDraftsJob(
171
181
  ctx: JobContext,
172
182
  db: DbConnection,
173
183
  ): Promise<void> {
174
- const resolved = ctx.configResolver
175
- ? await ctx.configResolver.get(
184
+ const resolved = ctx.services.configResolver
185
+ ? await ctx.services.configResolver.get(
176
186
  FORM_DRAFT_RETENTION_DAYS_CONFIG_KEY,
177
187
  formDraftRetentionDaysConfig,
178
188
  SYSTEM_TENANT_ID,
@@ -184,26 +194,26 @@ export async function cleanupDraftsJob(
184
194
  // configResolver missing is the legitimate no-config case (r.optionalRequires,
185
195
  // see feature.ts) — nothing to warn about there. A resolver that IS wired but
186
196
  // returns something unusable means an admin set an invalid value.
187
- if (ctx.configResolver && !isValidRetention) {
188
- ctx.log?.warn?.(
197
+ if (ctx.services.configResolver && !isValidRetention) {
198
+ ctx.obs.log?.warn?.(
189
199
  `[form-draft:cleanup] configResolver returned invalid retention-days value=${String(resolved)} — falling back to default=${FORM_DRAFT_DEFAULT_RETENTION_DAYS}`,
190
200
  );
191
201
  }
192
202
  const retentionDays = isValidRetention ? resolved : FORM_DRAFT_DEFAULT_RETENTION_DAYS;
193
203
 
194
- const fileProviderResolver = ctx._fileProviderResolver;
204
+ const fileProviderResolver = ctx.services._fileProviderResolver;
195
205
 
196
206
  let deleted = 0;
197
207
  const deferred = new Set<string>();
198
208
  while (true) {
199
- if (ctx.signal?.aborted) break;
209
+ if (ctx.lifecycle.signal?.aborted) break;
200
210
  const batch = await selectStaleDraftsBatch(db, retentionDays, DEFAULT_BATCH_SIZE, [
201
211
  ...deferred,
202
212
  ]);
203
213
  if (batch.length === 0) break;
204
214
 
205
215
  // Rows span arbitrary tenants (this job sweeps the whole table under
206
- // SYSTEM_TENANT_ID, not per-tenant) — ctx.files is resolved for a single
216
+ // SYSTEM_TENANT_ID, not per-tenant) — ctx.services.files is resolved for a single
207
217
  // tenant per job run and would be wrong here, so each row resolves its
208
218
  // own tenant's provider via _fileProviderResolver instead. Skipped
209
219
  // entirely for rows with no FileRefs in the blob, the common case.
@@ -213,11 +223,11 @@ export async function cleanupDraftsJob(
213
223
  batch,
214
224
  db,
215
225
  retentionDays,
216
- ctx.log,
226
+ ctx.obs.log,
217
227
  );
218
228
  for (const id of deferredIds) deferred.add(id);
219
229
  for (const row of deletedRows) {
220
- await releaseRowFileRefs(row, db, fileProviderResolver, ctx.log);
230
+ await releaseRowFileRefs(row, db, fileProviderResolver, ctx.obs.log);
221
231
  }
222
232
  deleted += deletedRows.length;
223
233
  // A skipped row is no longer stale, so the next select drops it — a fully
@@ -229,5 +239,5 @@ export async function cleanupDraftsJob(
229
239
  )
230
240
  break;
231
241
  }
232
- ctx.log?.info?.(`[form-draft:cleanup] deleted=${deleted} retentionDays=${retentionDays}`);
242
+ ctx.obs.log?.info?.(`[form-draft:cleanup] deleted=${deleted} retentionDays=${retentionDays}`);
233
243
  }
@@ -56,7 +56,7 @@ export const discardDraftWrite = defineWriteHandler({
56
56
  // releaseFiles: a successful-submit discard must NOT release — the
57
57
  // domain entity the submit just wrote carries the same storageKeys
58
58
  // forward (see schemas.ts comment on discardDraftPayloadSchema).
59
- const files = ctx.files;
59
+ const files = ctx.services.files;
60
60
  if (files && event.payload.releaseFiles === true) {
61
61
  const candidateKeys = collectDraftFileRefKeys(existing.draft);
62
62
  // Only storageKeys with a real file_refs row owned by THIS caller are
@@ -87,8 +87,8 @@ export const discardDraftWrite = defineWriteHandler({
87
87
  // Binary delete only after commit — in-tx delete would orphan pointers
88
88
  // if the surrounding write transaction rolls back after this handler.
89
89
  const keys = ownedRefs.map((ref) => ref.storageKey);
90
- const log = ctx.log;
91
- const schedule = ctx.scheduleAfterCommit;
90
+ const log = ctx.obs.log;
91
+ const schedule = ctx.lifecycle.afterCommit;
92
92
  const release = async (): Promise<void> => {
93
93
  await releaseDraftFileRefs(
94
94
  keys,
@@ -27,7 +27,7 @@ export const getDraftQuery = defineQueryHandler({
27
27
  if (!row.draft) {
28
28
  // Schema evolution or a corrupt/erased row: surface it to operators
29
29
  // instead of silently making the user's draft vanish.
30
- ctx.log?.warn?.(
30
+ ctx.obs.log?.warn?.(
31
31
  `[form-draft:get] stored blob for draftKey=${query.payload.draftKey} failed schema or decryption, treating as absent`,
32
32
  );
33
33
  return { draft: null };
@@ -77,7 +77,7 @@ export function requireNonEmpty(
77
77
  }
78
78
 
79
79
  /**
80
- * Narrow a `ctx.secrets.get()` result → set secret. The secrets-counterpart
80
+ * Narrow a `ctx.services.secrets.get()` result → set secret. The secrets-counterpart
81
81
  * to requireNonEmpty: a missing secret is a tenant-configuration gap, not a
82
82
  * crash — same 422 contract, so clients route to the settings screen.
83
83
  *
@@ -29,7 +29,7 @@ export const INBOUND_MESSAGE_AGGREGATE_TYPE = "inbound-message" as const;
29
29
  export const MAIL_THREAD_AGGREGATE_TYPE = "mail-thread" as const;
30
30
 
31
31
  // Event-name constants — short forms (for r.defineEvent) and qualified
32
- // FQNs (for ctx.unsafeAppendEvent and projection-apply keys).
32
+ // FQNs (for ctx.events.unsafeAppend and projection-apply keys).
33
33
  export const MAIL_ACCOUNT_CONNECTED_EVENT_SHORT = "mail-account-connected" as const;
34
34
  export const MAIL_ACCOUNT_UPDATED_EVENT_SHORT = "mail-account-updated" as const;
35
35
  export const MAIL_ACCOUNT_DISCONNECTED_EVENT_SHORT = "mail-account-disconnected" as const;
@@ -254,7 +254,7 @@ export function createInboundMailFoundationFeature() {
254
254
  const deleteBodyObject = async (bodyRef: string): Promise<void> => {
255
255
  if (!providerPromise) {
256
256
  providerPromise = createFileProviderForTenant(
257
- { config: ctx.config, registry: ctx.registry },
257
+ { config: ctx.config, registry: ctx.registry, secrets: ctx.services.secrets },
258
258
  tenantId,
259
259
  );
260
260
  }
@@ -13,10 +13,10 @@ import type { HandlerContext } from "@cosmicdrift/kumiko-framework/engine";
13
13
  import type { MailAccountEventPayload } from "../events.ts";
14
14
 
15
15
  export async function loadCurrentMailAccountPayload(
16
- ctx: Pick<HandlerContext, "loadAggregate">,
16
+ ctx: { readonly events: Pick<HandlerContext["events"], "load"> },
17
17
  accountId: string,
18
18
  ): Promise<MailAccountEventPayload | undefined> {
19
- const events = await ctx.loadAggregate(accountId);
19
+ const events = await ctx.events.load(accountId);
20
20
  const last = events[events.length - 1];
21
21
  // @cast-boundary engine-payload — eigene events, shape via defineEvent
22
22
  return last?.payload as MailAccountEventPayload | undefined;
@@ -104,7 +104,7 @@ export const connectAccountHandler: WriteHandlerDef = {
104
104
  providerName: payload.provider,
105
105
  reason: "connect_flow",
106
106
  };
107
- await ctx.unsafeAppendEvent({
107
+ await ctx.events.unsafeAppend({
108
108
  aggregateId: accountId,
109
109
  aggregateType: MAIL_ACCOUNT_AGGREGATE_TYPE,
110
110
  type: MAIL_ACCOUNT_CONNECTED_EVENT_QN,
@@ -56,7 +56,7 @@ export const disconnectAccountHandler: WriteHandlerDef = {
56
56
  providerName: current.provider,
57
57
  reason: payload.reason,
58
58
  };
59
- await ctx.unsafeAppendEvent({
59
+ await ctx.events.unsafeAppend({
60
60
  aggregateId: payload.accountId,
61
61
  aggregateType: MAIL_ACCOUNT_AGGREGATE_TYPE,
62
62
  type: MAIL_ACCOUNT_DISCONNECTED_EVENT_QN,
@@ -10,7 +10,7 @@
10
10
  // both the event log AND projection contain ciphertext.
11
11
  // 4. inbound-message-received append (inline projection writes
12
12
  // read_inbound_messages in the same TX). Savepoint-scoped
13
- // (ctx.tryAppendEvent) — a losing concurrent ingest for the same
13
+ // (ctx.events.tryAppend) — a losing concurrent ingest for the same
14
14
  // messageAggId returns { duplicate: true } instead of failing the TX.
15
15
  // 5. Thread rollup: mail-thread-updated append with a recalculated
16
16
  // snapshot (count+1, max(lastMessageAt)) — the apply is a
@@ -140,7 +140,7 @@ export const ingestMessageHandler: WriteHandlerDef = {
140
140
  data: { duplicate: true as const, inboundMessageAggregateId: messageAggId },
141
141
  };
142
142
  }
143
- const existingEvents = await ctx.loadAggregate(messageAggId);
143
+ const existingEvents = await ctx.events.load(messageAggId);
144
144
  if (existingEvents.length > 0) {
145
145
  // Stream existiert, Anchor fehlte → Anchor nachziehen, dann raus.
146
146
  await ctx.db.insertOne(seenMessageTable, {
@@ -211,7 +211,7 @@ export const ingestMessageHandler: WriteHandlerDef = {
211
211
  providerName: payload.providerName,
212
212
  providerCursor: payload.providerCursor,
213
213
  };
214
- const messageAppend = await ctx.tryAppendEvent({
214
+ const messageAppend = await ctx.events.tryAppend({
215
215
  aggregateId: messageAggId,
216
216
  aggregateType: INBOUND_MESSAGE_AGGREGATE_TYPE,
217
217
  type: INBOUND_MESSAGE_RECEIVED_EVENT_QN,
@@ -222,8 +222,8 @@ export const ingestMessageHandler: WriteHandlerDef = {
222
222
  // Lost the race against a concurrent ingest for the same messageAggId
223
223
  // (Watch-Push vs. Poll-Reconciliation overlap). The winner already
224
224
  // writes thread-rollup + seen-anchor for this message — steps 5+6
225
- // skip here. tryAppendEvent's savepoint keeps this TX usable despite
226
- // the caught VersionConflictError (see ctx.tryAppendEvent doc).
225
+ // skip here. events.tryAppend's savepoint keeps this TX usable despite
226
+ // the caught VersionConflictError (see ctx.events.tryAppend doc).
227
227
  return {
228
228
  isSuccess: true as const,
229
229
  data: { duplicate: true as const, inboundMessageAggregateId: messageAggId },
@@ -232,7 +232,7 @@ export const ingestMessageHandler: WriteHandlerDef = {
232
232
 
233
233
  // ---------------------------------------------------------------
234
234
  // 5. Thread-Rollup. New snapshot (live COUNT + max(lastMessageAt)) via
235
- // ctx.tryAppendEvent in a bounded retry loop — the apply stays a
235
+ // ctx.events.tryAppend in a bounded retry loop — the apply stays a
236
236
  // dumb, replay-idempotent UPSERT. lastMessageAtIso is not PII (a
237
237
  // timestamp), so it stays plaintext-comparable; subject is
238
238
  // encrypted once up front (constant across retries, doesn't
@@ -244,9 +244,9 @@ export const ingestMessageHandler: WriteHandlerDef = {
244
244
  // same thread arriving at once) converge on the true count.
245
245
  // acquireNamespacedAdvisoryLock below serializes this whole
246
246
  // countWhere+append section per threadAggId — transaction-scoped,
247
- // so it survives tryAppendEvent's inner SAVEPOINT and releases at
247
+ // so it survives events.tryAppend's inner SAVEPOINT and releases at
248
248
  // the enclosing TX's commit/rollback. Without it, a concurrent
249
- // commit landing between countWhere and tryAppendEvent's own fresh
249
+ // commit landing between countWhere and events.tryAppend's own fresh
250
250
  // version-read makes the append succeed with a stale count instead
251
251
  // of a VersionConflictError, so the retry loop below never sees it
252
252
  // as a conflict to retry (the original gap). Unlike step 4, a
@@ -280,7 +280,7 @@ export const ingestMessageHandler: WriteHandlerDef = {
280
280
 
281
281
  let threadAppendOk = false;
282
282
  for (let attempt = 1; attempt <= THREAD_ROLLUP_MAX_ATTEMPTS && !threadAppendOk; attempt++) {
283
- const threadEvents = await ctx.loadAggregate(threadAggId);
283
+ const threadEvents = await ctx.events.load(threadAggId);
284
284
  const lastThreadEvent = threadEvents[threadEvents.length - 1];
285
285
  // @cast-boundary engine-payload — eigene events, shape via defineEvent
286
286
  const previousThread = lastThreadEvent?.payload as MailThreadEventPayload | undefined;
@@ -298,7 +298,7 @@ export const ingestMessageHandler: WriteHandlerDef = {
298
298
  lastMessageAtIso: newLastAt,
299
299
  messageCount,
300
300
  };
301
- const threadAppend = await ctx.tryAppendEvent({
301
+ const threadAppend = await ctx.events.tryAppend({
302
302
  aggregateId: threadAggId,
303
303
  aggregateType: MAIL_THREAD_AGGREGATE_TYPE,
304
304
  type: MAIL_THREAD_UPDATED_EVENT_QN,
@@ -79,7 +79,7 @@ export const updateAccountHandler: WriteHandlerDef = {
79
79
  providerName: current.provider,
80
80
  reason: auditReasonFor(event.user, payload.reason),
81
81
  };
82
- await ctx.unsafeAppendEvent({
82
+ await ctx.events.unsafeAppend({
83
83
  aggregateId: payload.accountId,
84
84
  aggregateType: MAIL_ACCOUNT_AGGREGATE_TYPE,
85
85
  type: MAIL_ACCOUNT_UPDATED_EVENT_QN,
@@ -3,7 +3,7 @@
3
3
  // inbound-message → read_inbound_messages (INSERT-ignore, append-only)
4
4
  // mail-thread → read_mail_threads (UPSERT, rollup)
5
5
  //
6
- // Apply runs in the same transaction as ctx.unsafeAppendEvent, providing
6
+ // Apply runs in the same transaction as ctx.events.unsafeAppend, providing
7
7
  // read-your-own-write without waiting for a dispatcher tick (as in
8
8
  // billing-foundation).
9
9
  //
@@ -7,7 +7,7 @@
7
7
  //
8
8
  // **Documented deviation:** the poll was originally intended as an `r.job`
9
9
  // cron trigger. JobContext previously had no dispatcher (see
10
- // run-export-jobs.ts), but now has one (`ctx.write`/`ctx.queryAs`,
10
+ // run-export-jobs.ts), but now has one (`ctx.dispatch.write`/`ctx.dispatch.queryAs`,
11
11
  // job-runner.ts). Converting the poll to a cron job is a separate migration
12
12
  // because it changes the concurrency model, so this dispatcher contract
13
13
  // remains in place. The app owner wires the supervisor in bin/server.ts:
@@ -64,7 +64,10 @@ async function readCredentialDocument(
64
64
  ctx: InboundMailContext,
65
65
  account: MailAccountRecord,
66
66
  ): Promise<ImapCredentialDocument> {
67
- const secrets = requireSecretsContext(ctx, FEATURE_NAME);
67
+ const secrets = requireSecretsContext(
68
+ { secrets: ctx.secrets, auditUserId: ctx.auditUserId },
69
+ FEATURE_NAME,
70
+ );
68
71
  const secret = await secrets.get(account.tenantId, inboundCredentialSecretKey(account.id));
69
72
  if (!secret) {
70
73
  throw new InboundAuthError(
@@ -1,4 +1,10 @@
1
1
  [
2
+ {
3
+ "version": "0.390.0",
4
+ "type": "fix",
5
+ "title": "Tenant job run rows are written in the tenant's scope",
6
+ "detail": "With row level security on, the queued, started and finished rows of tenant-visible job runs were rejected by Postgres when the job was dispatched outside a request scope, and the logger only logged the error. The logger now scopes its tenant writes to the job's tenant and logs a rejected write as a missing row-level-security scope instead of a generic write failure."
7
+ },
2
8
  {
3
9
  "version": "0.388.0",
4
10
  "type": "improvement",
@@ -2,7 +2,7 @@
2
2
  // backed jobRun's event-store payloads (r.defineEvent + inline projections);
3
3
  // now job-run-logger.ts parses against them before writing straight into
4
4
  // jobRunsTable/jobRunLogsTable, so an out-of-dispatcher write still gets the
5
- // same validation guarantee ctx.appendEvent used to give it.
5
+ // same validation guarantee ctx.events.append used to give it.
6
6
 
7
7
  import * as z from "zod";
8
8
 
@@ -65,10 +65,13 @@ function defineConsumerWrite(name: string, description: string, transition: Cons
65
65
  ? rejected(JobErrors.consumerUnknown, "jobs.errors.consumerUnknown")
66
66
  : rejected(JobErrors.consumerWrongStatus, "jobs.errors.consumerWrongStatus");
67
67
  }
68
- ctx.log?.error(`jobs:write:${name} failed: ${e instanceof Error ? e.message : String(e)}`, {
69
- consumer: event.payload.name,
70
- instanceId: event.payload.instanceId,
71
- });
68
+ ctx.obs.log?.error(
69
+ `jobs:write:${name} failed: ${e instanceof Error ? e.message : String(e)}`,
70
+ {
71
+ consumer: event.payload.name,
72
+ instanceId: event.payload.instanceId,
73
+ },
74
+ );
72
75
  return rejected(JobErrors.consumerTransitionFailed, "jobs.errors.consumerTransitionFailed");
73
76
  }
74
77
  },
@@ -36,7 +36,7 @@ export const projectionRebuildJob: JobHandlerFn = async (rawPayload, ctx): Promi
36
36
  registry: ctx.registry,
37
37
  ...(skipApplyErrors === true && { errorPolicy: { skipApplyErrors: true } }),
38
38
  });
39
- ctx.log?.info?.(
39
+ ctx.obs.log?.info?.(
40
40
  `[jobs:projection-rebuild] rebuilt ${projection}: ${result.eventsProcessed} events` +
41
41
  `${result.eventsSkipped > 0 ? ` (${result.eventsSkipped} quarantined)` : ""} in ${result.durationMs}ms`,
42
42
  );
@@ -20,16 +20,16 @@ export const reindexEntityJob: JobHandlerFn = async (rawPayload, ctx): Promise<v
20
20
  message: "[jobs:reindex-entity] ctx.registry missing — job context requires the registry.",
21
21
  });
22
22
  }
23
- if (!ctx.searchAdapter) {
23
+ if (!ctx.services.searchAdapter) {
24
24
  throw new InternalError({
25
25
  message:
26
- "[jobs:reindex-entity] ctx.searchAdapter missing — mount a search adapter to run this job.",
26
+ "[jobs:reindex-entity] ctx.services.searchAdapter missing — mount a search adapter to run this job.",
27
27
  });
28
28
  }
29
29
  // perTenant fan-out — the job-runner enqueues one child run per active
30
30
  // tenant with ctx.systemUser scoped to it; a run without one (e.g.
31
31
  // misconfigured manual dispatch outside the fan-out) has nothing scoped
32
- // to reindex. ctx._tenantId is never populated per-dispatch (only
32
+ // to reindex. ctx.user.tenantId is never populated per-dispatch (only
33
33
  // ctx.systemUser is), so it is not a valid fallback here.
34
34
  const tenantId = ctx.systemUser?.tenantId;
35
35
  if (tenantId === undefined) {
@@ -48,8 +48,14 @@ export const reindexEntityJob: JobHandlerFn = async (rawPayload, ctx): Promise<v
48
48
  const db = ctx.systemDb.unsafeRaw(
49
49
  "reindexEntity filters WHERE tenant_id = $1 itself with this job's tenantId",
50
50
  );
51
- const result = await reindexEntity(db, ctx.registry, ctx.searchAdapter, entity, tenantId);
52
- ctx.log?.info?.(
51
+ const result = await reindexEntity(
52
+ db,
53
+ ctx.registry,
54
+ ctx.services.searchAdapter,
55
+ entity,
56
+ tenantId,
57
+ );
58
+ ctx.obs.log?.info?.(
53
59
  `[jobs:reindex-entity] tenant=${tenantId} reindexed ${entity}: ${result.indexedRows}/${result.scannedRows} rows indexed` +
54
60
  `${result.failures.length > 0 ? ` (${result.failures.length} failed)` : ""}`,
55
61
  );
@@ -18,6 +18,6 @@ export function createRetentionCleanupJob(retentionDays: number): JobHandlerFn {
18
18
  "store_job_runs retention purges finished runs of every tenant",
19
19
  ) as DbConnection; // @cast-boundary db-operator — DbRunner narrows to DbConnection, jobs never run inside a DbTx
20
20
  const result = await deleteStaleJobRuns(db, retentionDays);
21
- ctx.log?.info?.(`[jobs:retention-cleanup] complete: ${JSON.stringify(result)}`);
21
+ ctx.obs.log?.info?.(`[jobs:retention-cleanup] complete: ${JSON.stringify(result)}`);
22
22
  };
23
23
  }
@@ -37,7 +37,7 @@ export const retryWrite = defineWriteHandler({
37
37
  }
38
38
  const db = ctx.systemDb.acknowledgeCrossTenant("cross-tenant job monitoring");
39
39
  // @cast-boundary engine-payload — JobRunner attached by app-boot via ctx-extension
40
- const jobRunner = ctx["jobRunner"] as JobRunner;
40
+ const jobRunner = ctx.services.jobRunner as JobRunner;
41
41
 
42
42
  const run = await fetchOne<JobRunRow>(db, jobRunsTable, { id: event.payload.runId });
43
43
 
@@ -28,6 +28,6 @@ export function createStaleRunSweepJob(
28
28
  "stale-run sweep marks stuck runs of every tenant as failed",
29
29
  ) as DbConnection; // @cast-boundary db-operator — DbRunner narrows to DbConnection, jobs never run inside a DbTx
30
30
  const result = await markStaleJobRunsFailed(db, timeoutHours, queuedRetentionDays);
31
- ctx.log?.info?.(`[jobs:stale-run-sweep] complete: ${JSON.stringify(result)}`);
31
+ ctx.obs.log?.info?.(`[jobs:stale-run-sweep] complete: ${JSON.stringify(result)}`);
32
32
  };
33
33
  }
@@ -28,8 +28,8 @@ export const triggerWrite = defineWriteHandler({
28
28
  access: { roles: ["SystemAdmin"] },
29
29
  handler: async (event, ctx) => {
30
30
  const registry = ctx.registry;
31
- // `jobRunner` is a dynamic context extension — not a core HandlerContext field.
32
- const jobRunner = ctx["jobRunner"] as JobRunner; // @cast-boundary dynamic-key
31
+ // `services.jobRunner` is typed as the handleEvent-only JobRunnerRef; dispatch lives on the concrete runner.
32
+ const jobRunner = ctx.services.jobRunner as JobRunner; // @cast-boundary engine-bridge
33
33
 
34
34
  const jobDef = registry.getJob(event.payload.jobName);
35
35
  if (!jobDef) {