@cosmicdrift/kumiko-samples 0.389.0 → 0.390.1

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 (301) hide show
  1. package/package.json +1 -1
  2. package/packages/bundled-features/package.json +27 -15
  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/changes.json +6 -0
  116. package/packages/bundled-features/src/inbound-provider-imap/feature.ts +4 -1
  117. package/packages/bundled-features/src/jobs/changes.json +6 -0
  118. package/packages/bundled-features/src/jobs/events.ts +1 -1
  119. package/packages/bundled-features/src/jobs/handlers/consumer.write.ts +7 -4
  120. package/packages/bundled-features/src/jobs/handlers/projection-rebuild.job.ts +1 -1
  121. package/packages/bundled-features/src/jobs/handlers/reindex-entity.job.ts +11 -5
  122. package/packages/bundled-features/src/jobs/handlers/retention-cleanup.job.ts +1 -1
  123. package/packages/bundled-features/src/jobs/handlers/retry.write.ts +1 -1
  124. package/packages/bundled-features/src/jobs/handlers/stale-run-sweep.job.ts +1 -1
  125. package/packages/bundled-features/src/jobs/handlers/trigger.write.ts +2 -2
  126. package/packages/bundled-features/src/jobs/job-run-logger.ts +139 -90
  127. package/packages/bundled-features/src/legal-pages/README.md +1 -1
  128. package/packages/bundled-features/src/legal-pages/lib/boot-check.ts +12 -8
  129. package/packages/bundled-features/src/mail-foundation/feature.ts +2 -2
  130. package/packages/bundled-features/src/mail-transport-smtp/changes.json +6 -0
  131. package/packages/bundled-features/src/mail-transport-smtp/feature.ts +4 -1
  132. package/packages/bundled-features/src/managed-pages/seeding.ts +13 -8
  133. package/packages/bundled-features/src/notes-history/handlers/add-note.write.ts +1 -1
  134. package/packages/bundled-features/src/personal-access-tokens/feature.ts +1 -1
  135. package/packages/bundled-features/src/personal-access-tokens/handlers/create.write.ts +2 -2
  136. package/packages/bundled-features/src/personal-access-tokens/handlers/revoke.write.ts +1 -1
  137. package/packages/bundled-features/src/rate-limiting/handlers/status.query.ts +2 -2
  138. package/packages/bundled-features/src/readiness/handlers/status.query.ts +4 -1
  139. package/packages/bundled-features/src/renderer-foundation/api.ts +3 -3
  140. package/packages/bundled-features/src/secrets/announce-secret-change.ts +4 -4
  141. package/packages/bundled-features/src/secrets/feature.ts +9 -9
  142. package/packages/bundled-features/src/secrets/handlers/delete.write.ts +4 -3
  143. package/packages/bundled-features/src/secrets/handlers/rotate.job.ts +13 -8
  144. package/packages/bundled-features/src/secrets/handlers/set.write.ts +4 -3
  145. package/packages/bundled-features/src/secrets/secrets-context.ts +16 -6
  146. package/packages/bundled-features/src/secrets/write-gate.ts +1 -1
  147. package/packages/bundled-features/src/seo/feature.ts +1 -1
  148. package/packages/bundled-features/src/sessions/changes.json +12 -0
  149. package/packages/bundled-features/src/sessions/feature.ts +1 -1
  150. package/packages/bundled-features/src/sessions/handlers/cleanup.job.ts +2 -2
  151. package/packages/bundled-features/src/sessions/handlers/detail.query.ts +5 -2
  152. package/packages/bundled-features/src/sessions/handlers/list.query.ts +5 -2
  153. package/packages/bundled-features/src/sessions/handlers/mine.query.ts +5 -2
  154. package/packages/bundled-features/src/sessions/handlers/revoke-all-for-user.write.ts +3 -3
  155. package/packages/bundled-features/src/sessions/handlers/revoke-all-others.write.ts +1 -1
  156. package/packages/bundled-features/src/sessions/handlers/revoke.write.ts +1 -1
  157. package/packages/bundled-features/src/sessions/screens.ts +8 -4
  158. package/packages/bundled-features/src/sessions/session-revoked-event.ts +1 -1
  159. package/packages/bundled-features/src/sessions/web/session-device-cell.tsx +10 -12
  160. package/packages/bundled-features/src/sessions/web/user-agent.ts +12 -0
  161. package/packages/bundled-features/src/shared/index.ts +15 -0
  162. package/packages/bundled-features/src/shared/purge-files-reaching-subject.ts +12 -2
  163. package/packages/bundled-features/src/shared/require-for-tenant.ts +7 -5
  164. package/packages/bundled-features/src/shared/stream-tenant-backfill.ts +201 -0
  165. package/packages/bundled-features/src/shared/stream-tenant-derived-state.ts +107 -0
  166. package/packages/bundled-features/src/step-dispatcher/feature.ts +1 -1
  167. package/packages/bundled-features/src/subscription-dodo/plugin-methods.ts +1 -1
  168. package/packages/bundled-features/src/subscription-dodo/runtime.ts +7 -7
  169. package/packages/bundled-features/src/subscription-stripe/plugin-methods.ts +5 -3
  170. package/packages/bundled-features/src/subscription-stripe/runtime.ts +7 -7
  171. package/packages/bundled-features/src/template-resolver/api.ts +3 -3
  172. package/packages/bundled-features/src/template-resolver/changes.json +18 -0
  173. package/packages/bundled-features/src/template-resolver/handlers/bundle-import.ts +5 -4
  174. package/packages/bundled-features/src/template-resolver/handlers/copy-locale.write.ts +2 -2
  175. package/packages/bundled-features/src/template-resolver/handlers/export-bundle.query.ts +1 -1
  176. package/packages/bundled-features/src/template-resolver/handlers/overview.query.ts +2 -2
  177. package/packages/bundled-features/src/template-resolver/handlers/send-test-shared.ts +1 -1
  178. package/packages/bundled-features/src/template-resolver/handlers/send-test.write.ts +2 -2
  179. package/packages/bundled-features/src/template-resolver/handlers/tenant-override-selection.ts +6 -2
  180. package/packages/bundled-features/src/template-resolver/handlers/tenant-overrides.query.ts +4 -2
  181. package/packages/bundled-features/src/template-resolver/handlers/usage.query.ts +1 -1
  182. package/packages/bundled-features/src/template-resolver/seeding.ts +12 -2
  183. package/packages/bundled-features/src/template-resolver/store-template-resource.ts +18 -13
  184. package/packages/bundled-features/src/template-resolver/template-resources.ts +4 -4
  185. package/packages/bundled-features/src/template-resolver/testing.ts +2 -2
  186. package/packages/bundled-features/src/template-resolver/web/document-insert-fields.tsx +222 -0
  187. package/packages/bundled-features/src/template-resolver/web/document-insert-model.ts +164 -0
  188. package/packages/bundled-features/src/template-resolver/web/document-insert-panel.tsx +115 -0
  189. package/packages/bundled-features/src/template-resolver/web/document-tiptap-bubble.tsx +177 -0
  190. package/packages/bundled-features/src/template-resolver/web/document-tiptap-content.tsx +38 -0
  191. package/packages/bundled-features/src/template-resolver/web/document-tiptap-context.ts +119 -0
  192. package/packages/bundled-features/src/template-resolver/web/document-tiptap-editor.tsx +51 -1098
  193. package/packages/bundled-features/src/template-resolver/web/document-tiptap-helpers.ts +161 -0
  194. package/packages/bundled-features/src/template-resolver/web/document-tiptap-layout.tsx +83 -0
  195. package/packages/bundled-features/src/template-resolver/web/document-tiptap-toolbar-groups.tsx +153 -0
  196. package/packages/bundled-features/src/template-resolver/web/document-tiptap-toolbar.tsx +182 -0
  197. package/packages/bundled-features/src/template-resolver/web/editor-handle.ts +18 -0
  198. package/packages/bundled-features/src/template-resolver/web/placeholder-line-editor.tsx +19 -6
  199. package/packages/bundled-features/src/template-resolver/web/use-document-tiptap-model.ts +138 -0
  200. package/packages/bundled-features/src/tenant/changes.json +19 -0
  201. package/packages/bundled-features/src/tenant/handlers/cancel-invitation.write.ts +1 -1
  202. package/packages/bundled-features/src/tenant/handlers/memberships.query.ts +1 -1
  203. package/packages/bundled-features/src/tenant/handlers/remove-member.write.ts +2 -2
  204. package/packages/bundled-features/src/tenant/handlers/update-member-roles.write.ts +1 -1
  205. package/packages/bundled-features/src/tenant/index.ts +5 -0
  206. package/packages/bundled-features/src/tenant/invited-membership.ts +6 -1
  207. package/packages/bundled-features/src/tenant/schema/tenant.ts +4 -1
  208. package/packages/bundled-features/src/tenant/seeding.ts +65 -62
  209. package/packages/bundled-features/src/tenant/stream-tenant-backfill.ts +115 -0
  210. package/packages/bundled-features/src/tenant/testing.ts +77 -0
  211. package/packages/bundled-features/src/tenant-handover/events.ts +1 -1
  212. package/packages/bundled-features/src/tenant-handover/handlers/claim.write.ts +1 -1
  213. package/packages/bundled-features/src/tenant-lifecycle/feature.ts +5 -5
  214. package/packages/bundled-features/src/tenant-lifecycle/handlers/cancel-destruction.write.ts +22 -10
  215. package/packages/bundled-features/src/tenant-lifecycle/handlers/request-destruction.write.ts +22 -11
  216. package/packages/bundled-features/src/tenant-lifecycle/run-tenant-destroy.ts +23 -12
  217. package/packages/bundled-features/src/tenant-lifecycle/stages.ts +7 -3
  218. package/packages/bundled-features/src/tenant-lifecycle/testing.ts +9 -8
  219. package/packages/bundled-features/src/tier-engine/entity.ts +1 -1
  220. package/packages/bundled-features/src/tier-engine/feature.ts +8 -3
  221. package/packages/bundled-features/src/tier-engine/handlers/active-tier.query.ts +3 -3
  222. package/packages/bundled-features/src/tier-engine/handlers/get-tenant-tier.query.ts +7 -1
  223. package/packages/bundled-features/src/tier-engine/handlers/set-tenant-tier.write.ts +3 -3
  224. package/packages/bundled-features/src/user/db/queries/stream-tenant-backfill.ts +71 -97
  225. package/packages/bundled-features/src/user/handlers/find-for-auth.query.ts +2 -2
  226. package/packages/bundled-features/src/user/handlers/update-roles.ts +2 -2
  227. package/packages/bundled-features/src/user/index.ts +2 -0
  228. package/packages/bundled-features/src/user/invited-global-roles.ts +6 -1
  229. package/packages/bundled-features/src/user/principal-status.ts +1 -1
  230. package/packages/bundled-features/src/user/seeding.ts +24 -6
  231. package/packages/bundled-features/src/user/testing.ts +22 -0
  232. package/packages/bundled-features/src/user-data-rights/COMPLIANCE.md +1 -1
  233. package/packages/bundled-features/src/user-data-rights/README.md +1 -1
  234. package/packages/bundled-features/src/user-data-rights/audit-download.ts +12 -2
  235. package/packages/bundled-features/src/user-data-rights/changes.json +24 -0
  236. package/packages/bundled-features/src/user-data-rights/feature.ts +29 -24
  237. package/packages/bundled-features/src/user-data-rights/handlers/confirm-deletion-by-token.write.ts +1 -1
  238. package/packages/bundled-features/src/user-data-rights/handlers/deletion-grace-period.ts +1 -1
  239. package/packages/bundled-features/src/user-data-rights/handlers/download-by-job.query.ts +2 -2
  240. package/packages/bundled-features/src/user-data-rights/handlers/download-by-token.query.ts +2 -2
  241. package/packages/bundled-features/src/user-data-rights/handlers/request-deletion.write.ts +1 -1
  242. package/packages/bundled-features/src/user-data-rights/handlers/restrict-account.write.ts +4 -4
  243. package/packages/bundled-features/src/user-data-rights/handlers/run-forget-cleanup.write.ts +12 -6
  244. package/packages/bundled-features/src/user-data-rights/index.ts +2 -0
  245. package/packages/bundled-features/src/user-data-rights/lib/mail-transport-resolver.ts +1 -1
  246. package/packages/bundled-features/src/user-data-rights/lib/storage-provider-resolver.ts +1 -1
  247. package/packages/bundled-features/src/user-data-rights/lib/update-user-lifecycle.ts +6 -1
  248. package/packages/bundled-features/src/user-data-rights/run-export-jobs.ts +8 -2
  249. package/packages/bundled-features/src/user-data-rights/run-forget-cleanup.ts +14 -3
  250. package/packages/bundled-features/src/user-data-rights/run-user-export.ts +11 -1
  251. package/packages/bundled-features/src/user-data-rights/web/constants.ts +10 -0
  252. package/packages/bundled-features/src/user-data-rights/web/index.ts +6 -1
  253. package/packages/bundled-features/src/user-profile/handlers/change-email.write.ts +8 -6
  254. package/packages/bundled-features/src/waitlist/handlers/export-purge.write.ts +1 -1
  255. package/packages/bundled-features/src/waitlist/handlers/invite.write.ts +2 -2
  256. package/packages/bundled-features/src/waitlist/handlers/reject.write.ts +1 -1
  257. package/packages/bundled-features/src/waitlist/handlers/submit.write.ts +9 -4
  258. package/packages/bundled-features/src/waitlist/legacy-migrate.ts +6 -1
  259. package/packages/bundled-features/src/waitlist/link-on-signup.ts +7 -1
  260. package/packages/bundled-features/src/workflow-runner/changes.json +6 -0
  261. package/packages/bundled-features/src/workflow-runner/db/queries/due-runs.ts +1 -1
  262. package/packages/bundled-features/src/workflow-runner/event-subscriber.ts +4 -3
  263. package/packages/bundled-features/src/workflow-runner/event-trigger.ts +2 -1
  264. package/packages/bundled-features/src/workflow-runner/feature.ts +2 -2
  265. package/packages/bundled-features/src/workflow-runner/handlers/resume-run.write.ts +8 -8
  266. package/packages/bundled-features/src/workflow-runner/runner.ts +6 -4
  267. package/samples/apps/cap-billing-demo/package.json +1 -1
  268. package/samples/apps/cap-billing-demo/src/feature.ts +19 -5
  269. package/samples/apps/config-demo/src/app/server.ts +1 -1
  270. package/samples/apps/styleguide/src/app/server.ts +2 -2
  271. package/samples/apps/ui-walkthrough/package.json +1 -1
  272. package/samples/apps/use-all-bundled/feature-manifest.json +1 -1
  273. package/samples/apps/use-all-bundled/package.json +1 -1
  274. package/samples/apps/use-all-bundled/src/app/seed.ts +12 -2
  275. package/samples/apps/user-data-rights-demo/README.md +1 -1
  276. package/samples/apps/user-data-rights-demo/package.json +1 -1
  277. package/samples/apps/user-data-rights-demo/src/feature.ts +3 -2
  278. package/samples/recipes/api-worker-split/README.md +2 -1
  279. package/samples/recipes/api-worker-split/src/feature.ts +2 -1
  280. package/samples/recipes/cross-feature-events/README.md +5 -5
  281. package/samples/recipes/cross-feature-events/package.json +1 -1
  282. package/samples/recipes/cross-feature-events/src/feature.ts +4 -4
  283. package/samples/recipes/event-sourcing/README.md +5 -5
  284. package/samples/recipes/event-sourcing/package.json +1 -1
  285. package/samples/recipes/event-sourcing/src/feature.ts +15 -15
  286. package/samples/recipes/files-post-processing/README.md +1 -1
  287. package/samples/recipes/files-post-processing/package.json +1 -1
  288. package/samples/recipes/files-post-processing/src/feature.ts +6 -4
  289. package/samples/recipes/lane-routing/package.json +1 -1
  290. package/samples/recipes/legal-pages/README.md +2 -2
  291. package/samples/recipes/lifecycle-hooks/README.md +2 -2
  292. package/samples/recipes/lifecycle-hooks/src/feature.ts +1 -1
  293. package/samples/recipes/managed-config/README.md +3 -3
  294. package/samples/recipes/search/README.md +1 -1
  295. package/samples/recipes/search/src/feature.ts +3 -3
  296. package/samples/recipes/secrets-demo/README.md +1 -1
  297. package/samples/recipes/secrets-demo/src/feature.ts +5 -2
  298. package/samples/recipes/state-machine/src/events.ts +1 -1
  299. package/samples/recipes/state-machine/src/reducer.ts +1 -1
  300. package/samples/recipes/workflow-engine/src/resume-loop.ts +4 -4
  301. package/samples/recipes/workflow-engine/src/workflow-runner.ts +2 -2
@@ -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
  }
@@ -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";
@@ -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({
@@ -15,6 +15,7 @@ import type {
15
15
  } from "@cosmicdrift/kumiko-framework/engine";
16
16
  import {
17
17
  assertNotificationVariables,
18
+ attachOutsideTransaction,
18
19
  bridgeStub,
19
20
  createSystemUser,
20
21
  } from "@cosmicdrift/kumiko-framework/engine";
@@ -98,7 +99,7 @@ export type DeliveryServiceOptions = {
98
99
  // inline delivery (job-less setups, unit tests).
99
100
  readonly jobRunner?: NotifyJobDispatcher;
100
101
  // Credentials source for inline-delivered chat channels (webhook URL / bot
101
- // token). Jobs get ctx.secrets from the job runner instead.
102
+ // token). Jobs get ctx.services.secrets from the job runner instead.
102
103
  readonly secrets?: SecretsContext;
103
104
  // Seals the recipient address inside queued job payloads (tenant scope). Absent means the
104
105
  // payload carries the plaintext address.
@@ -277,7 +278,7 @@ export function createDeliveryService(options: DeliveryServiceOptions): Delivery
277
278
  sink: escapeHatchAuditSink,
278
279
  log: logError,
279
280
  });
280
- // ctx.db/dbOutsideTransaction are tenant-filtered even for a systemScope handler:
281
+ // ctx.db/db.outsideTransaction are tenant-filtered even for a systemScope handler:
281
282
  // the dispatcher closes them off entirely there, so "system" mode would hand this
282
283
  // path a cross-tenant read the dispatcher never allows. Cross-tenant reach only
283
284
  // exists through the grant-carrying systemDb view below.
@@ -299,6 +300,7 @@ export function createDeliveryService(options: DeliveryServiceOptions): Delivery
299
300
  db: run.db,
300
301
  tenantId,
301
302
  mode: "system",
303
+ reason: "delivery fan-out of a systemScope handler resolves recipients across tenants",
302
304
  grants: {
303
305
  report,
304
306
  unsafeRaw: { reason: `r.systemScope() handler "${tenantUserIdsQuery}"` },
@@ -306,13 +308,12 @@ export function createDeliveryService(options: DeliveryServiceOptions): Delivery
306
308
  })
307
309
  : undefined;
308
310
  // Hand-built context, not routed through the dispatcher — this needs both
309
- // db and dbOutsideTransaction wired directly.
311
+ // db (with its outsideTransaction) wired directly.
310
312
  // @cast-boundary engine-payload — generic query-handler return for typed convention
311
313
  return (await handler.handler(
312
314
  { type: tenantUserIdsQuery, payload: { tenantId }, user: systemUser },
313
315
  {
314
- db: tenantDb,
315
- dbOutsideTransaction: tenantDb,
316
+ db: attachOutsideTransaction(tenantDb, tenantDb),
316
317
  systemDb: systemDbSourceTenantDb
317
318
  ? createSystemDbView(systemDbSourceTenantDb, undefined, report)
318
319
  : undefined,
@@ -206,10 +206,10 @@ export function createDeliveryFeature(options?: DeliveryFeatureOptions): Feature
206
206
  const pruned = await runAttemptLogRetention(db, {
207
207
  olderThanDays: attemptLogRetentionDays,
208
208
  });
209
- ctx.log.info("delivery attempt log pruned", pruned);
209
+ ctx.obs.log.info("delivery attempt log pruned", pruned);
210
210
  } catch (error) {
211
211
  if (!(error instanceof ConsumerLagError)) throw error;
212
- ctx.log.warn("delivery attempt log retention postponed: an event consumer lags", {
212
+ ctx.obs.log.warn("delivery attempt log retention postponed: an event consumer lags", {
213
213
  consumer: error.laggingConsumer,
214
214
  });
215
215
  }
@@ -150,21 +150,21 @@ function entryFor(
150
150
  };
151
151
  }
152
152
 
153
- // Assumes ctx.redis is the handle the service claimed on; runProdApp wires the same
153
+ // Assumes ctx.services.redis is the handle the service claimed on; runProdApp wires the same
154
154
  // instance into both.
155
155
  async function releaseIdempotencyKey(ctx: JobContext, p: RenderJobPayload): Promise<void> {
156
156
  // skip: no idempotency key was claimed for this notification
157
157
  if (!p.idempotencyKey) return;
158
- if (!ctx.redis) {
159
- ctx.log.warn("delivery: idempotency key not released, job context has no redis", {
158
+ if (!ctx.services.redis) {
159
+ ctx.obs.log.warn("delivery: idempotency key not released, job context has no redis", {
160
160
  notificationType: p.notificationType,
161
161
  });
162
162
  return;
163
163
  }
164
164
  try {
165
- await ctx.redis.del(deliveryIdempotencyRedisKey(p.tenantId, p.idempotencyKey));
165
+ await ctx.services.redis.del(deliveryIdempotencyRedisKey(p.tenantId, p.idempotencyKey));
166
166
  } catch (err) {
167
- ctx.log.warn(`delivery: idempotency key release failed: ${redactedMessageOf(err)}`, {
167
+ ctx.obs.log.warn(`delivery: idempotency key release failed: ${redactedMessageOf(err)}`, {
168
168
  notificationType: p.notificationType,
169
169
  });
170
170
  }
@@ -206,7 +206,7 @@ async function addressForAttemptLog(
206
206
  return await openRecipientAddress(
207
207
  p,
208
208
  p.tenantId as TenantId, // @cast-boundary engine-payload — job payload string is the stream tenant
209
- ctx.configEncryption,
209
+ ctx.services.configEncryption,
210
210
  );
211
211
  } catch {
212
212
  return null;
@@ -225,7 +225,7 @@ async function failAttempt(
225
225
  err: unknown,
226
226
  ): Promise<never> {
227
227
  const message = redactedMessageOf(err);
228
- ctx.log.error(`delivery.${p.channelName} ${code}: ${message}`, {
228
+ ctx.obs.log.error(`delivery.${p.channelName} ${code}: ${message}`, {
229
229
  notificationType: p.notificationType,
230
230
  channel: p.channelName,
231
231
  });
@@ -255,7 +255,7 @@ async function renderStep(p: RenderJobPayload, ctx: JobContext): Promise<void> {
255
255
  registry,
256
256
  undefined,
257
257
  tenantId,
258
- ctx.secrets,
258
+ ctx.services.secrets,
259
259
  ctx.config,
260
260
  (fileTenantId) => fileContextForTenant(ctx, ctx.systemUser.tenantId, fileTenantId),
261
261
  );
@@ -270,7 +270,7 @@ async function renderStep(p: RenderJobPayload, ctx: JobContext): Promise<void> {
270
270
  return failAttempt(ctx, db, registry, p, "render_failed", err);
271
271
  }
272
272
  try {
273
- const jobRunner = ctx["jobRunner"] as JobRunner; // @cast-boundary dynamic-key — dispatch lives on the concrete runner
273
+ const jobRunner = ctx.services.jobRunner as JobRunner; // @cast-boundary engine-bridge — dispatch lives on the concrete runner
274
274
  await jobRunner.dispatch(
275
275
  DeliveryJobs.send,
276
276
  { ...p, rendered: toSendRendered(rendered) },
@@ -298,13 +298,13 @@ async function sendStep(p: z.infer<typeof sendJobPayloadSchema>, ctx: JobContext
298
298
  registry,
299
299
  undefined,
300
300
  tenantId,
301
- ctx.secrets,
301
+ ctx.services.secrets,
302
302
  ctx.config,
303
303
  (fileTenantId) => fileContextForTenant(ctx, ctx.systemUser.tenantId, fileTenantId),
304
304
  );
305
305
 
306
306
  try {
307
- const address = await openRecipientAddress(p, tenantId, ctx.configEncryption);
307
+ const address = await openRecipientAddress(p, tenantId, ctx.services.configEncryption);
308
308
  const result = await channel.send(address, toMessage(p), channelCtx, p.rendered);
309
309
  await appendAttemptEvent(
310
310
  db,
@@ -25,7 +25,7 @@ export type CreateDeliveryTestContextOptions = {
25
25
  readonly log?: Logger;
26
26
  readonly jobRunner?: JobRunner;
27
27
  readonly secrets?: SecretsContext;
28
- // Seals queued job payload addresses and, like the boot wiring, doubles as the jobs' ctx.configEncryption.
28
+ // Seals queued job payload addresses and, like the boot wiring, doubles as the jobs' ctx.services.configEncryption.
29
29
  readonly addressCipher?: EnvelopeCipher;
30
30
  readonly idempotencyRedis?: Redis;
31
31
  readonly filesForTenant?: (tenantId: string) => FileContext | undefined;
@@ -14,7 +14,7 @@ export const DOCUMENT_EXTRACT_AGGREGATE_TYPE = "document-extract";
14
14
 
15
15
  export const DOCUMENT_INGEST_REQUESTED_EVENT_SHORT = "documentIngest.requested" as const;
16
16
 
17
- // Qualified name — what ctx.unsafeAppendEvent's `type` actually needs
17
+ // Qualified name — what ctx.events.unsafeAppend's `type` actually needs
18
18
  // (r.defineEvent registers under qn(toKebab(feature), "event",
19
19
  // toKebab(shortName)); appendEvent looks up the registry by QN, not the
20
20
  // short name — see MSP-apply "event not registered" error otherwise).
@@ -43,7 +43,7 @@ export const registeredQuery = defineQueryHandler({
43
43
  // The per-tenant signature requires SYSTEM_TENANT_ID; the app resolver
44
44
  // returns the union of all tier features. The sentinel convention is
45
45
  // documented in DispatcherOptions.effectiveFeatures.
46
- const effective = ctx.effectiveFeatures?.(SYSTEM_TENANT_ID);
46
+ const effective = ctx.services.effectiveFeatures?.(SYSTEM_TENANT_ID);
47
47
 
48
48
  const rows: Array<{
49
49
  id: string;
@@ -160,7 +160,7 @@ export function createSetWriteHandler(getRuntime: (() => GlobalFeatureToggleRunt
160
160
  // its config-changed events.
161
161
  // unsafeAppendEvent: the strict appendEvent is bound to an app's own event map, which
162
162
  // bundled-features cannot see. Schema validation still runs via r.defineEvent("toggle-set", ...).
163
- await ctx.unsafeAppendEvent({
163
+ await ctx.events.unsafeAppend({
164
164
  aggregateId: SYSTEM_TENANT_ID,
165
165
  aggregateType: FEATURE_TOGGLE_AGGREGATE_TYPE,
166
166
  type: FEATURE_TOGGLE_SET_EVENT_NAME,
@@ -52,7 +52,7 @@ export function createRedisToggleSyncSignal(
52
52
  onMessage(listener) {
53
53
  signal.onMessage((_channel, payload) => {
54
54
  if (!isTogglePayload(payload)) {
55
- // biome-ignore lint/suspicious/noConsole: ops-visible fallback — no ctx.log in a raw PubSubSignal handler.
55
+ // biome-ignore lint/suspicious/noConsole: ops-visible fallback — no ctx.obs.log in a raw PubSubSignal handler.
56
56
  console.error(
57
57
  `[kumiko:feature-toggles] dropping malformed cache-sync message on "${toggleSyncChannel}"`,
58
58
  );
@@ -53,7 +53,7 @@ export type FileDerivativesOptions = {
53
53
  * Without this option, neither the httpRoute NOR the `publicVariant`
54
54
  * query is registered — it is unreachable via the httpRoute path and via
55
55
  * the generic `/api` query dispatch. Existing consumers that only need
56
- * `ctx.derivatives` are unaffected. See {@link PublicVariantResolveApexTenant}
56
+ * `ctx.services.derivatives` are unaffected. See {@link PublicVariantResolveApexTenant}
57
57
  * for the in-memory/sync contract. */
58
58
  readonly resolveApexTenant?: PublicVariantResolveApexTenant;
59
59
  /** Base path of the public variant route. Default "/media". */
@@ -104,7 +104,7 @@ export function createFileDerivativesFeature(opts: FileDerivativesOptions = {}):
104
104
  FEATURE_NAME,
105
105
  (r) => {
106
106
  r.describe(
107
- "Declares the `derivativeRenderer` extension point. `ctx.derivatives.variant(fileRefId, spec, name)` derives a variant of a tracked FileRef the first time it's requested and reuses the stored result afterwards (derive-on-first-use, keyed by a hash of the spec). Mount at least one `derivatives-*` renderer feature alongside this one — without a registered renderer for the FileRef's MIME type, every `variant(...)` call throws. Also declares the `derivativePublicPredicate` extension point (`r.useExtension(EXT_DERIVATIVE_PUBLIC_PREDICATE, '<entityType>', { isPublic })`) and, when `createFileDerivativesFeature({resolveApexTenant})` is passed a host-resolver, mounts an anonymous `GET {basePath}/:fileRefId/:variant` route that serves any variant name the FileRef's field declared in its `variants` for a FileRef whose entityType has a registered predicate returning true — default-deny (404) otherwise, same as an unknown FileRef or an undeclared variant name. The route's only rate-limit (`per: \"ip\"`) depends on the server's `trustedProxyHops` matching the deployment's actual reverse-proxy count — at the default 0 it ignores `x-forwarded-for` entirely, so every caller shares one bucket until that's configured. `publicTenantResolution: \"fileRef\"` keeps resolveApexTenant as the host gate but reads the variant from the FileRef row's own tenant instead of the host's, so one shared platform host serves every tenant's public variants — each FileRef-tenant's own `isPublic` predicate still default-denies. Also declares the `derivativeOverlayResolver` extension point (`r.useExtension(EXT_DERIVATIVE_OVERLAY_RESOLVER, '<entityType>', { resolve })`), used to turn a variant's `overlays[].dataToken` into the actual QR payload for that FileRef's entityType before the variant is rendered — a variant declaring a `qr` overlay throws at request-time if no resolver is registered for the FileRef's entityType.",
107
+ "Declares the `derivativeRenderer` extension point. `ctx.services.derivatives.variant(fileRefId, spec, name)` derives a variant of a tracked FileRef the first time it's requested and reuses the stored result afterwards (derive-on-first-use, keyed by a hash of the spec). Mount at least one `derivatives-*` renderer feature alongside this one — without a registered renderer for the FileRef's MIME type, every `variant(...)` call throws. Also declares the `derivativePublicPredicate` extension point (`r.useExtension(EXT_DERIVATIVE_PUBLIC_PREDICATE, '<entityType>', { isPublic })`) and, when `createFileDerivativesFeature({resolveApexTenant})` is passed a host-resolver, mounts an anonymous `GET {basePath}/:fileRefId/:variant` route that serves any variant name the FileRef's field declared in its `variants` for a FileRef whose entityType has a registered predicate returning true — default-deny (404) otherwise, same as an unknown FileRef or an undeclared variant name. The route's only rate-limit (`per: \"ip\"`) depends on the server's `trustedProxyHops` matching the deployment's actual reverse-proxy count — at the default 0 it ignores `x-forwarded-for` entirely, so every caller shares one bucket until that's configured. `publicTenantResolution: \"fileRef\"` keeps resolveApexTenant as the host gate but reads the variant from the FileRef row's own tenant instead of the host's, so one shared platform host serves every tenant's public variants — each FileRef-tenant's own `isPublic` predicate still default-denies. Also declares the `derivativeOverlayResolver` extension point (`r.useExtension(EXT_DERIVATIVE_OVERLAY_RESOLVER, '<entityType>', { resolve })`), used to turn a variant's `overlays[].dataToken` into the actual QR payload for that FileRef's entityType before the variant is rendered — a variant declaring a `qr` overlay throws at request-time if no resolver is registered for the FileRef's entityType.",
108
108
  );
109
109
  r.uiHints({
110
110
  displayLabel: "File Derivatives",
@@ -52,6 +52,10 @@ export const publicVariantByFileRefQuery = defineQueryHandler({
52
52
  const tenant = await fetchOne<TenantGateRow>(db, tenantTable, { id: row.tenantId });
53
53
  if (!tenant || !isTenantServingPublicContent(tenant)) return null;
54
54
 
55
- return ctx.queryAs(createAnonymousUser(row.tenantId), PUBLIC_VARIANT_QN, query.payload);
55
+ return ctx.dispatch.queryAs(
56
+ createAnonymousUser(row.tenantId),
57
+ PUBLIC_VARIANT_QN,
58
+ query.payload,
59
+ );
56
60
  },
57
61
  });
@@ -18,7 +18,7 @@
18
18
  // consumer's `resolverTrust`/anonymousAccess setup, not the host.
19
19
  //
20
20
  // In `publicTenantResolution: "fileRef"` mode, this handler is also the
21
- // `ctx.queryAs(createAnonymousUser(fileRefTenantId), ...)` target of
21
+ // `ctx.dispatch.queryAs(createAnonymousUser(fileRefTenantId), ...)` target of
22
22
  // publicVariantByFileRefQuery — tenantId there comes from the FileRef row,
23
23
  // but this handler's own isPublic gate runs exactly the same either way.
24
24
 
@@ -133,14 +133,16 @@ export const publicVariantQuery = defineQueryHandler({
133
133
  );
134
134
  if (!isPublic) return null;
135
135
 
136
- // ctx.files/ctx.derivatives are optional on HandlerContext (only wired
136
+ // ctx.services.files/ctx.services.derivatives are optional on HandlerContext (only wired
137
137
  // when file-foundation resolved a provider) — narrow via a plain guard,
138
138
  // never `!`/`as`, and surface a real config error (not a silent deny)
139
139
  // when the feature isn't actually wired.
140
- const { files, derivatives } = ctx;
140
+ const {
141
+ services: { files, derivatives },
142
+ } = ctx;
141
143
  if (!files || !derivatives) {
142
144
  throw new Error(
143
- "file-derivatives requires ctx.files/ctx.derivatives — is file-foundation mounted?",
145
+ "file-derivatives requires ctx.services.files/ctx.services.derivatives — is file-foundation mounted?",
144
146
  );
145
147
  }
146
148
 
@@ -151,7 +153,7 @@ export const publicVariantQuery = defineQueryHandler({
151
153
 
152
154
  // ponytail: fully buffered (no streaming), +33% over the wire from
153
155
  // base64 — HttpRouteHandlerDeps only exposes {app, systemQuery} (no
154
- // direct ctx.files access from the Hono handler itself), and the local
156
+ // direct ctx.services.files access from the Hono handler itself), and the local
155
157
  // dev storage provider has no getSignedUrl (a redirect design wouldn't
156
158
  // work in dev). Upgrade path: a binary-passthrough dispatcher primitive
157
159
  // would be its own, larger issue.
@@ -4,7 +4,7 @@
4
4
  // extension point + the per-tenant `provider` config key. Provider RESOLUTION
5
5
  // (createFileProviderForTenant) + the plugin types now live in the framework
6
6
  // (packages/framework/src/files/provider-resolver.ts) so the upload routes,
7
- // `ctx.files` and the GDPR jobs resolve through ONE path — uploads, export and
7
+ // `ctx.services.files` and the GDPR jobs resolve through ONE path — uploads, export and
8
8
  // erasure hit the same store by construction. This feature re-exports the moved
9
9
  // symbols unchanged so existing imports keep working.
10
10
  //
@@ -22,19 +22,21 @@ type FileRefRow = {
22
22
  readonly size: number | bigint | string;
23
23
  };
24
24
 
25
- // Tenant-bound on purpose: without a resolver `ctx.files` only reaches the storage of the
25
+ // Tenant-bound on purpose: without a resolver `ctx.services.files` only reaches the storage of the
26
26
  // context's own tenant (`contextTenantId`), so a request for another tenant's files is
27
27
  // undefined instead of silently reading through the wrong tenant's storage.
28
28
  export function fileContextForTenant(
29
29
  ctx: {
30
- readonly _fileProviderResolver?: FileProviderResolver | undefined;
31
- readonly files?: FileContext | undefined;
30
+ readonly services: {
31
+ readonly _fileProviderResolver?: FileProviderResolver | undefined;
32
+ readonly files?: FileContext | undefined;
33
+ };
32
34
  },
33
35
  contextTenantId: string,
34
36
  tenantId: string,
35
37
  ): FileContext | undefined {
36
- const resolver = ctx._fileProviderResolver;
37
- if (resolver === undefined) return tenantId === contextTenantId ? ctx.files : undefined;
38
+ const resolver = ctx.services._fileProviderResolver;
39
+ if (resolver === undefined) return tenantId === contextTenantId ? ctx.services.files : undefined;
38
40
  return fileContextFromResolver(resolver, tenantId);
39
41
  }
40
42
 
@@ -201,7 +201,10 @@ async function buildS3Provider(
201
201
  }
202
202
 
203
203
  async function readSecretAccessKey(ctx: FileProviderContext, tenantId: string): Promise<string> {
204
- const secrets = requireSecretsContext(ctx, FEATURE_NAME);
204
+ const secrets = requireSecretsContext(
205
+ { secrets: ctx.secrets, auditUserId: ctx.auditUserId },
206
+ FEATURE_NAME,
207
+ );
205
208
  const branded = await secrets.get(tenantId, S3_SECRET_ACCESS_KEY);
206
209
  return requireSecretSet(branded, FEATURE_NAME, S3_SECRET_ACCESS_KEY.name).reveal();
207
210
  }
@@ -56,9 +56,9 @@ export async function sweepOrphanedDerivativesJob(
56
56
  db: DbConnection,
57
57
  ): Promise<void> {
58
58
  const payload = sweepOrphanedDerivativesPayloadSchema.parse(rawPayload ?? {});
59
- const maybeResolver = ctx._fileProviderResolver;
59
+ const maybeResolver = ctx.services._fileProviderResolver;
60
60
  if (!maybeResolver) {
61
- ctx.log?.warn(
61
+ ctx.obs.log?.warn(
62
62
  "[files-tenant-data:sweep] no _fileProviderResolver wired — nothing to sweep, skipping run",
63
63
  );
64
64
  return;
@@ -96,7 +96,7 @@ export async function sweepOrphanedDerivativesJob(
96
96
  try {
97
97
  provider = await resolver(tenantId);
98
98
  } catch (err) {
99
- ctx.log?.warn?.(
99
+ ctx.obs.log?.warn?.(
100
100
  `[files-tenant-data:sweep] no file provider resolvable for tenant=${tenantId}, skipping: ${err instanceof Error ? err.message : String(err)}`,
101
101
  );
102
102
  continue;
@@ -105,7 +105,7 @@ export async function sweepOrphanedDerivativesJob(
105
105
  try {
106
106
  keys = await provider.list(`${tenantId}/`);
107
107
  } catch (err) {
108
- ctx.log?.warn?.(
108
+ ctx.obs.log?.warn?.(
109
109
  `[files-tenant-data:sweep] provider.list() failed for tenant=${tenantId}, skipping: ${err instanceof Error ? err.message : String(err)}`,
110
110
  );
111
111
  continue;
@@ -140,7 +140,7 @@ export async function sweepOrphanedDerivativesJob(
140
140
  { limit: 1 },
141
141
  );
142
142
  if (owners.length > 0) return "skipped";
143
- // Binaries written through ctx.files.ref(key) (and their derive()d
143
+ // Binaries written through ctx.services.files.ref(key) (and their derive()d
144
144
  // variants) never get a fileRef row; an original still sitting in storage
145
145
  // means the derivative is not an orphan.
146
146
  if (await candidate.provider.exists(candidate.originalKey)) return "skipped";
@@ -158,15 +158,15 @@ export async function sweepOrphanedDerivativesJob(
158
158
  migrateRow,
159
159
  maxFailures,
160
160
  deadlineAt: deadline,
161
- signal: ctx.signal,
161
+ signal: ctx.lifecycle.signal,
162
162
  onRowError: (candidate, err) => {
163
- ctx.log?.warn?.(
163
+ ctx.obs.log?.warn?.(
164
164
  `[files-tenant-data:sweep] failed to delete key=${candidate.key} tenant=${candidate.tenantId}: ${err instanceof Error ? err.message : String(err)}`,
165
165
  );
166
166
  },
167
167
  });
168
168
 
169
- ctx.log?.info?.(
169
+ ctx.obs.log?.info?.(
170
170
  `[files-tenant-data:sweep] complete dryRun=${dryRun} deleted=${outcome.migrated} wouldDelete=${dryRunWouldDelete} skipped=${outcome.skipped} failed=${outcome.failed} batches=${outcome.batchesProcessed} stoppedReason=${outcome.stoppedReason}`,
171
171
  );
172
172
  }
@@ -27,7 +27,7 @@ function registerFormDraft(r: FeatureRegistrar<typeof FORM_DRAFT_FEATURE_NAME>):
27
27
  });
28
28
 
29
29
  // config is optional: the retention-days key only resolves when the
30
- // config feature is mounted (ctx.configResolver present) — the cleanup
30
+ // config feature is mounted (ctx.services.configResolver present) — the cleanup
31
31
  // job already falls back to FORM_DRAFT_DEFAULT_RETENTION_DAYS otherwise
32
32
  // (see handlers/cleanup.job.ts). A hard r.requires({ features: ["config"] }) would break
33
33
  // every app that mounts form-draft without config, which is a breaking