@cosmicdrift/kumiko-framework 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 (617) hide show
  1. package/AGENTS.md +9 -4
  2. package/README.md +1 -1
  3. package/agents/examples/apex-surface-auth.md +2 -3
  4. package/agents/examples/api-worker-split.md +9 -2
  5. package/agents/examples/auth-claims.md +1 -1
  6. package/agents/examples/cross-feature-events.md +12 -12
  7. package/agents/examples/crypto-shredding-hr.md +2 -2
  8. package/agents/examples/encrypted-tenant-config.md +1 -1
  9. package/agents/examples/error-contract.md +12 -7
  10. package/agents/examples/event-sourcing.md +29 -29
  11. package/agents/examples/files-post-processing.md +10 -8
  12. package/agents/examples/inbound-mail-triage.md +1 -0
  13. package/agents/examples/lane-routing.md +2 -1
  14. package/agents/examples/legal-pages.md +2 -2
  15. package/agents/examples/lifecycle-hooks.md +3 -3
  16. package/agents/examples/managed-config.md +4 -4
  17. package/agents/examples/managed-pages.md +1 -1
  18. package/agents/examples/relations.md +19 -4
  19. package/agents/examples/search.md +4 -4
  20. package/agents/examples/secrets-demo.md +9 -6
  21. package/agents/examples/state-machine.md +2 -2
  22. package/agents/examples/tenant-settings.md +1 -1
  23. package/agents/examples/user-data-rights.md +3 -6
  24. package/agents/examples/workflow-engine.md +53 -47
  25. package/agents/examples.md +4 -4
  26. package/agents/features.md +1 -1
  27. package/dist/api/auth-middleware.js +1 -1
  28. package/dist/api/auth-routes-invite.js +2 -1
  29. package/dist/api/entity-read-access.d.ts +3 -1
  30. package/dist/api/export/export-columns.d.ts +3 -1
  31. package/dist/api/export/export-route.js +3 -2
  32. package/dist/api/export/export-screen.d.ts +2 -1
  33. package/dist/api/extra-route.d.ts +3 -1
  34. package/dist/api/index.d.ts +23 -27
  35. package/dist/api/index.js +13 -15
  36. package/dist/api/jwt.js +1 -1
  37. package/dist/api/observability-middleware.d.ts +1 -1
  38. package/dist/api/observability-middleware.js +2 -1
  39. package/dist/api/request-context-internals.d.ts +31 -0
  40. package/dist/api/request-context-internals.js +11 -0
  41. package/dist/api/request-context-scopes.d.ts +14 -0
  42. package/dist/api/request-context-scopes.js +69 -0
  43. package/dist/api/request-context.d.ts +1 -40
  44. package/dist/api/request-context.js +22 -51
  45. package/dist/api/request-id-middleware.d.ts +1 -1
  46. package/dist/api/route-registrars.d.ts +2 -1
  47. package/dist/api/route-registrars.js +1 -1
  48. package/dist/api/routes.js +7 -3
  49. package/dist/api/server-boot-checks.d.ts +1 -1
  50. package/dist/api/server-boot-checks.js +2 -2
  51. package/dist/api/server-event-dispatcher.d.ts +6 -1
  52. package/dist/api/server-event-dispatcher.js +3 -4
  53. package/dist/api/server-extra-routes.d.ts +1 -1
  54. package/dist/api/server-extra-routes.js +2 -1
  55. package/dist/api/server-middleware.js +3 -1
  56. package/dist/api/server-routes.d.ts +2 -1
  57. package/dist/api/server-wiring.js +6 -4
  58. package/dist/api/server.d.ts +2 -1
  59. package/dist/api/sse-route.d.ts +2 -1
  60. package/dist/api/tenant-scoped-secrets.d.ts +2 -0
  61. package/dist/api/tenant-scoped-secrets.js +13 -0
  62. package/dist/api/websocket-route.d.ts +1 -1
  63. package/dist/auth/index.d.ts +0 -1
  64. package/dist/auth/roles.d.ts +0 -5
  65. package/dist/compliance/duration-spec.d.ts +0 -1
  66. package/dist/compliance/duration-spec.js +0 -5
  67. package/dist/compliance/index.d.ts +4 -4
  68. package/dist/compliance/index.js +2 -2
  69. package/dist/compliance/profiles.d.ts +0 -15
  70. package/dist/compliance/profiles.js +0 -23
  71. package/dist/config/index.d.ts +10 -10
  72. package/dist/config/index.js +13 -1
  73. package/dist/config/internals.d.ts +9 -0
  74. package/dist/config/internals.js +1 -0
  75. package/dist/consumer-cli-internals.d.ts +4 -0
  76. package/dist/consumer-cli-internals.js +1 -0
  77. package/dist/consumer-cli.d.ts +1 -4
  78. package/dist/consumer-cli.js +5 -1
  79. package/dist/crypto/event-pii.js +1 -1
  80. package/dist/crypto/index.d.ts +8 -9
  81. package/dist/crypto/index.js +7 -8
  82. package/dist/crypto/pg-kms-adapter.js +6 -1
  83. package/dist/db/apply-entity-event.d.ts +1 -1
  84. package/dist/db/apply-entity-event.js +15 -47
  85. package/dist/db/blind-index-cleanup.js +91 -77
  86. package/dist/db/collect-table-metas.js +1 -1
  87. package/dist/db/compound-types.d.ts +1 -1
  88. package/dist/db/compound-types.js +0 -7
  89. package/dist/db/config-seed.d.ts +2 -1
  90. package/dist/db/config-seed.js +6 -1
  91. package/dist/db/connection.d.ts +3 -1
  92. package/dist/db/connection.js +15 -5
  93. package/dist/db/cross-tenant-reads.d.ts +1 -1
  94. package/dist/db/cross-tenant-reads.js +1 -1
  95. package/dist/db/dialect.d.ts +0 -5
  96. package/dist/db/dialect.js +0 -3
  97. package/dist/db/driver-value-preparation.js +23 -2
  98. package/dist/db/eagerload.d.ts +2 -1
  99. package/dist/db/entity-field-encryption.d.ts +1 -1
  100. package/dist/db/entity-table-meta.d.ts +1 -1
  101. package/dist/db/event-store-executor-context.d.ts +3 -1
  102. package/dist/db/event-store-executor-context.js +4 -3
  103. package/dist/db/event-store-executor-read-filter.d.ts +1 -1
  104. package/dist/db/event-store-executor-read-rows.d.ts +2 -1
  105. package/dist/db/event-store-executor-read-search.d.ts +2 -1
  106. package/dist/db/event-store-executor-read-sort.d.ts +2 -1
  107. package/dist/db/event-store-executor-read.js +2 -2
  108. package/dist/db/event-store-executor-write-atomic.js +8 -7
  109. package/dist/db/event-store-executor-write-steps.d.ts +3 -2
  110. package/dist/db/event-store-executor-write.js +7 -4
  111. package/dist/db/event-store-executor.d.ts +1 -1
  112. package/dist/db/executor-managed-tables.d.ts +7 -1
  113. package/dist/db/executor-managed-tables.js +11 -2
  114. package/dist/db/index.d.ts +29 -28
  115. package/dist/db/index.js +22 -20
  116. package/dist/db/known-table-names.d.ts +6 -0
  117. package/dist/db/known-table-names.js +21 -0
  118. package/dist/db/list-aggregate-labels.d.ts +1 -1
  119. package/dist/db/located-timestamp.d.ts +1 -1
  120. package/dist/db/located-timestamp.js +0 -5
  121. package/dist/db/migrate-generator.d.ts +17 -1
  122. package/dist/db/migrate-generator.js +50 -20
  123. package/dist/db/migrate-primary-key.d.ts +12 -0
  124. package/dist/db/migrate-primary-key.js +45 -0
  125. package/dist/db/migrate-rls-diff.d.ts +20 -0
  126. package/dist/db/migrate-rls-diff.js +61 -0
  127. package/dist/db/migrate-runner.js +4 -0
  128. package/dist/db/money.d.ts +1 -1
  129. package/dist/db/money.js +1 -1
  130. package/dist/db/parent-ref-clause.d.ts +2 -1
  131. package/dist/db/pg-error.d.ts +2 -0
  132. package/dist/db/pg-error.js +11 -0
  133. package/dist/db/queries/ddl.d.ts +3 -0
  134. package/dist/db/queries/ddl.js +34 -1
  135. package/dist/db/queries/event-store.js +4 -2
  136. package/dist/db/queries/event-tenants.d.ts +2 -0
  137. package/dist/db/queries/event-tenants.js +17 -0
  138. package/dist/db/queries/rebuild-rls-guard.d.ts +2 -0
  139. package/dist/db/queries/rebuild-rls-guard.js +29 -0
  140. package/dist/db/queries/rls-boot-catalog.d.ts +16 -0
  141. package/dist/db/queries/rls-boot-catalog.js +39 -0
  142. package/dist/db/queries/rls-catalog.d.ts +6 -0
  143. package/dist/db/queries/rls-catalog.js +82 -0
  144. package/dist/db/queries/rls-scope.d.ts +3 -0
  145. package/dist/db/queries/rls-scope.js +17 -0
  146. package/dist/db/queries/rls-shape.d.ts +10 -0
  147. package/dist/db/queries/rls-shape.js +42 -0
  148. package/dist/db/queries/session-advisory-lock.d.ts +2 -0
  149. package/dist/db/queries/session-advisory-lock.js +23 -0
  150. package/dist/db/queries/shadow-swap.d.ts +1 -2
  151. package/dist/db/queries/shadow-swap.js +9 -25
  152. package/dist/db/queries/test-stack.d.ts +4 -1
  153. package/dist/db/queries/test-stack.js +84 -2
  154. package/dist/db/query.js +11 -7
  155. package/dist/db/reference-data.d.ts +1 -1
  156. package/dist/db/reference-data.js +6 -1
  157. package/dist/db/render-ddl.d.ts +6 -2
  158. package/dist/db/render-ddl.js +7 -7
  159. package/dist/db/render-rls-ddl.d.ts +35 -0
  160. package/dist/db/render-rls-ddl.js +127 -0
  161. package/dist/db/replay-migration-sql.d.ts +3 -1
  162. package/dist/db/replay-migration-sql.js +22 -5
  163. package/dist/db/replay-rls.d.ts +25 -0
  164. package/dist/db/replay-rls.js +156 -0
  165. package/dist/db/row-level-security-boot-check.d.ts +6 -0
  166. package/dist/db/row-level-security-boot-check.js +86 -0
  167. package/dist/db/row-level-security-connection.d.ts +3 -0
  168. package/dist/db/row-level-security-connection.js +213 -0
  169. package/dist/db/row-level-security-scope.d.ts +33 -0
  170. package/dist/db/row-level-security-scope.js +127 -0
  171. package/dist/db/scope-tenant-db-to-tenant.d.ts +3 -0
  172. package/dist/db/scope-tenant-db-to-tenant.js +14 -0
  173. package/dist/db/sql-identifier.d.ts +1 -0
  174. package/dist/db/sql-identifier.js +3 -0
  175. package/dist/db/table-builder.d.ts +2 -1
  176. package/dist/db/table-builder.js +1 -1
  177. package/dist/db/table-info.js +1 -1
  178. package/dist/db/table-push.d.ts +11 -2
  179. package/dist/db/table-push.js +15 -2
  180. package/dist/db/tenant-db-runner.d.ts +3 -1
  181. package/dist/db/tenant-db-runner.js +4 -3
  182. package/dist/db/tenant-db-scoped-rebind.d.ts +10 -0
  183. package/dist/db/tenant-db-scoped-rebind.js +33 -0
  184. package/dist/db/tenant-db-statement-runner.d.ts +13 -0
  185. package/dist/db/tenant-db-statement-runner.js +48 -0
  186. package/dist/db/tenant-db.d.ts +17 -12
  187. package/dist/db/tenant-db.js +49 -120
  188. package/dist/db/tenant-id-filter.d.ts +3 -0
  189. package/dist/db/tenant-id-filter.js +30 -0
  190. package/dist/db/transaction-serialization.d.ts +6 -0
  191. package/dist/db/transaction-serialization.js +60 -0
  192. package/dist/derivatives/delete-stored-file.js +1 -1
  193. package/dist/derivatives/index.d.ts +2 -5
  194. package/dist/derivatives/index.js +2 -3
  195. package/dist/engine/access.d.ts +2 -1
  196. package/dist/engine/access.js +1 -1
  197. package/dist/engine/boot-validator/entity-handler.d.ts +2 -1
  198. package/dist/engine/boot-validator/entity-handler.js +1 -1
  199. package/dist/engine/boot-validator/entity-list-aggregate-options.d.ts +1 -1
  200. package/dist/engine/boot-validator/list-table-aggregate-options.d.ts +1 -1
  201. package/dist/engine/boot-validator/list-table-aggregate-query.d.ts +2 -1
  202. package/dist/engine/boot-validator/nav.d.ts +3 -1
  203. package/dist/engine/boot-validator/nav.js +1 -1
  204. package/dist/engine/boot-validator/ownership.d.ts +2 -1
  205. package/dist/engine/boot-validator/parent-ref.d.ts +2 -1
  206. package/dist/engine/boot-validator/projection-list-screens.d.ts +2 -1
  207. package/dist/engine/boot-validator/query-refs.d.ts +2 -1
  208. package/dist/engine/boot-validator/screens-forms.d.ts +2 -1
  209. package/dist/engine/boot-validator/screens-kind-shared.d.ts +3 -1
  210. package/dist/engine/boot-validator/screens.d.ts +2 -1
  211. package/dist/engine/boot-validator/workspaces.d.ts +3 -1
  212. package/dist/engine/bridge-stub.d.ts +5 -2
  213. package/dist/engine/bridge-stub.js +39 -24
  214. package/dist/engine/config-helpers.d.ts +2 -2
  215. package/dist/engine/config-helpers.js +0 -9
  216. package/dist/engine/constants.d.ts +0 -10
  217. package/dist/engine/constants.js +0 -8
  218. package/dist/engine/create-app.js +1 -1
  219. package/dist/engine/define-feature.d.ts +2 -1
  220. package/dist/engine/define-feature.js +1 -2
  221. package/dist/engine/define-handler.d.ts +1 -1
  222. package/dist/engine/define-step.d.ts +0 -1
  223. package/dist/engine/define-step.js +0 -3
  224. package/dist/engine/embedded-derived.d.ts +1 -1
  225. package/dist/engine/entity-handlers.d.ts +2 -1
  226. package/dist/engine/entity-handlers.js +7 -7
  227. package/dist/engine/entity-list-runtime-options.js +3 -1
  228. package/dist/engine/entity-list-searchability.d.ts +2 -1
  229. package/dist/engine/event-def.d.ts +2 -1
  230. package/dist/engine/event-helpers.d.ts +3 -1
  231. package/dist/engine/event-helpers.js +3 -3
  232. package/dist/engine/extension-names.d.ts +2 -8
  233. package/dist/engine/extension-names.js +2 -2
  234. package/dist/engine/extension-selector-plugins.d.ts +1 -1
  235. package/dist/engine/extensions/storage-provider.d.ts +1 -2
  236. package/dist/engine/extensions/user-data.d.ts +0 -8
  237. package/dist/engine/factories.d.ts +2 -1
  238. package/dist/engine/feature-builder-state.d.ts +8 -1
  239. package/dist/engine/feature-changelog.d.ts +1 -1
  240. package/dist/engine/feature-config-events-jobs.d.ts +4 -1
  241. package/dist/engine/feature-entity-handlers.d.ts +5 -1
  242. package/dist/engine/feature-manifest.js +1 -1
  243. package/dist/engine/feature-ui-extensions.d.ts +7 -1
  244. package/dist/engine/feature-ui-extensions.js +6 -4
  245. package/dist/engine/field-access.d.ts +2 -1
  246. package/dist/engine/handler-field-references.d.ts +0 -4
  247. package/dist/engine/index.d.ts +57 -54
  248. package/dist/engine/index.js +22 -27
  249. package/dist/engine/instruction-fields.d.ts +1 -1
  250. package/dist/engine/personal-data-fields.d.ts +1 -1
  251. package/dist/engine/qualified-name.d.ts +0 -1
  252. package/dist/engine/read-claim.d.ts +2 -1
  253. package/dist/engine/registry-facade.js +0 -3
  254. package/dist/engine/registry-ingest.d.ts +2 -1
  255. package/dist/engine/registry-ingest.js +1 -2
  256. package/dist/engine/registry-state.d.ts +12 -2
  257. package/dist/engine/registry-state.js +2 -3
  258. package/dist/engine/registry-validate.d.ts +3 -1
  259. package/dist/engine/registry-validate.js +7 -7
  260. package/dist/engine/run-in.d.ts +1 -1
  261. package/dist/engine/run-in.js +0 -1
  262. package/dist/engine/schema-builder.d.ts +1 -1
  263. package/dist/engine/schema-builder.js +1 -1
  264. package/dist/engine/screen-filter-ops.d.ts +2 -1
  265. package/dist/engine/screen-filter-ops.js +0 -5
  266. package/dist/engine/soft-delete-cleanup.d.ts +1 -1
  267. package/dist/engine/soft-delete-cleanup.js +4 -4
  268. package/dist/engine/state-machine.js +2 -1
  269. package/dist/engine/steps/_read-source.js +1 -1
  270. package/dist/engine/steps/aggregate-append-event.js +2 -2
  271. package/dist/engine/steps/call-feature.js +2 -2
  272. package/dist/engine/steps/mail-send.js +1 -1
  273. package/dist/engine/steps/retry.js +1 -1
  274. package/dist/engine/steps/wait-for-event.js +1 -1
  275. package/dist/engine/steps/wait.js +1 -1
  276. package/dist/engine/steps/webhook-send.js +1 -1
  277. package/dist/engine/template-variables.d.ts +2 -1
  278. package/dist/engine/transfer-adjacency.d.ts +1 -1
  279. package/dist/engine/types/index.d.ts +8 -31
  280. package/dist/engine/types/index.js +2 -10
  281. package/dist/engine/validation.d.ts +2 -1
  282. package/dist/entrypoint/index.d.ts +7 -35
  283. package/dist/entrypoint/index.js +7 -1
  284. package/dist/entrypoint/internals.d.ts +40 -0
  285. package/dist/entrypoint/internals.js +1 -0
  286. package/dist/entrypoint/row-level-security-mode-check.d.ts +3 -0
  287. package/dist/entrypoint/row-level-security-mode-check.js +19 -0
  288. package/dist/env/dry-run-internals.d.ts +10 -0
  289. package/dist/env/dry-run-internals.js +1 -0
  290. package/dist/env/dry-run.d.ts +1 -10
  291. package/dist/env/dry-run.js +2 -1
  292. package/dist/env/index.d.ts +1 -85
  293. package/dist/env/index.js +6 -50
  294. package/dist/env/internals.d.ts +87 -0
  295. package/dist/env/internals.js +53 -0
  296. package/dist/errors/classes.js +2 -2
  297. package/dist/errors/index.d.ts +5 -14
  298. package/dist/errors/index.js +4 -9
  299. package/dist/errors/member-resolution.js +1 -1
  300. package/dist/errors/reasons.d.ts +0 -1
  301. package/dist/errors/reasons.js +7 -7
  302. package/dist/errors/serialize.d.ts +0 -18
  303. package/dist/errors/serialize.js +0 -27
  304. package/dist/es-ops/index.d.ts +4 -4
  305. package/dist/es-ops/index.js +2 -2
  306. package/dist/es-ops/operations-schema.d.ts +1 -1
  307. package/dist/es-ops/types.d.ts +4 -5
  308. package/dist/event-store/admin-api-internals.d.ts +14 -0
  309. package/dist/event-store/admin-api-internals.js +1 -0
  310. package/dist/event-store/admin-api.d.ts +1 -14
  311. package/dist/event-store/admin-api.js +11 -6
  312. package/dist/event-store/archive.js +4 -2
  313. package/dist/event-store/errors.js +2 -2
  314. package/dist/event-store/event-store.js +41 -34
  315. package/dist/event-store/events-schema.js +4 -1
  316. package/dist/event-store/index.d.ts +11 -13
  317. package/dist/event-store/index.js +7 -9
  318. package/dist/event-store/rebuild-dead-letter.js +4 -2
  319. package/dist/event-store/snapshot.js +4 -3
  320. package/dist/event-store/stream-scope.d.ts +2 -0
  321. package/dist/event-store/stream-scope.js +6 -0
  322. package/dist/event-store/upcaster-dead-letter.js +4 -2
  323. package/dist/event-store/upcaster.d.ts +2 -1
  324. package/dist/files/action-form-upload.d.ts +2 -1
  325. package/dist/files/action-form-upload.js +1 -1
  326. package/dist/files/assert-file-refs-belong-to-tenant.d.ts +2 -1
  327. package/dist/files/assert-file-refs-belong-to-tenant.js +1 -1
  328. package/dist/files/bind-pending-file-refs.d.ts +2 -1
  329. package/dist/files/bind-pending-file-refs.js +2 -1
  330. package/dist/files/bind-referenced-files.write.js +1 -1
  331. package/dist/files/create-file-ref-from-bytes.d.ts +6 -3
  332. package/dist/files/create-file-ref-from-bytes.js +3 -3
  333. package/dist/files/create-file-ref.d.ts +3 -2
  334. package/dist/files/create-file-ref.js +2 -2
  335. package/dist/files/dispose-removed-file-refs.d.ts +2 -1
  336. package/dist/files/dispose-removed-file-refs.js +1 -1
  337. package/dist/files/feature.js +2 -2
  338. package/dist/files/file-handle.js +1 -1
  339. package/dist/files/file-routes.d.ts +1 -1
  340. package/dist/files/file-routes.js +12 -2
  341. package/dist/files/index.d.ts +11 -13
  342. package/dist/files/index.js +5 -7
  343. package/dist/files/load-save-file-refs.d.ts +2 -1
  344. package/dist/files/load-save-file-refs.js +1 -1
  345. package/dist/files/provider-resolver.d.ts +5 -4
  346. package/dist/files/provider-resolver.js +4 -4
  347. package/dist/files/storage-tracking.js +4 -2
  348. package/dist/files/sweep-orphaned-uploads.d.ts +1 -1
  349. package/dist/files/sweep-orphaned-uploads.js +1 -1
  350. package/dist/i18n/index.d.ts +2 -8
  351. package/dist/i18n/index.js +1 -1
  352. package/dist/i18n/internals.d.ts +7 -0
  353. package/dist/i18n/internals.js +1 -0
  354. package/dist/i18n/required-surface-keys.d.ts +4 -1
  355. package/dist/internal/row-level-security.d.ts +3 -0
  356. package/dist/internal/row-level-security.js +3 -0
  357. package/dist/internal/stack-support.d.ts +1 -1
  358. package/dist/internal/stack-support.js +1 -1
  359. package/dist/internal/testing.d.ts +1 -0
  360. package/dist/internal/testing.js +9 -5
  361. package/dist/jobs/index.d.ts +1 -1
  362. package/dist/jobs/job-append-event.d.ts +12 -0
  363. package/dist/jobs/job-append-event.js +30 -0
  364. package/dist/jobs/job-runner-context.d.ts +2 -2
  365. package/dist/jobs/job-runner-context.js +46 -16
  366. package/dist/jobs/job-runner-execution.d.ts +1 -1
  367. package/dist/jobs/job-runner-execution.js +6 -4
  368. package/dist/jobs/job-runner-gates.d.ts +1 -1
  369. package/dist/jobs/job-runner-gates.js +0 -1
  370. package/dist/jobs/job-runner-helpers.d.ts +11 -4
  371. package/dist/jobs/job-runner-helpers.js +10 -1
  372. package/dist/jobs/job-runner-scope.d.ts +5 -2
  373. package/dist/jobs/job-runner-types.d.ts +2 -1
  374. package/dist/jobs/job-runner.js +19 -6
  375. package/dist/jobs/max-per-tenant.d.ts +1 -1
  376. package/dist/logging/index.d.ts +1 -2
  377. package/dist/logging/index.js +1 -1
  378. package/dist/logging/pino-logger.js +1 -1
  379. package/dist/logging/utils.d.ts +1 -0
  380. package/dist/logging/utils.js +6 -0
  381. package/dist/migrations/index.d.ts +3 -3
  382. package/dist/migrations/index.js +3 -3
  383. package/dist/migrations/pending-rebuilds.d.ts +1 -1
  384. package/dist/migrations/pending-rebuilds.js +1 -1
  385. package/dist/migrations/pii-event-backfill.js +4 -1
  386. package/dist/observability/escape-hatch-report.d.ts +2 -1
  387. package/dist/observability/index.d.ts +7 -15
  388. package/dist/observability/index.js +4 -12
  389. package/dist/observability/metric-validator.js +1 -1
  390. package/dist/observability/metrics-handle.d.ts +0 -1
  391. package/dist/observability/metrics-handle.js +2 -15
  392. package/dist/observability/recording-tracer.d.ts +1 -2
  393. package/dist/observability/recording-tracer.js +0 -6
  394. package/dist/observability/sensitive-filter.d.ts +0 -2
  395. package/dist/observability/sensitive-filter.js +0 -29
  396. package/dist/pipeline/active-membership.d.ts +2 -1
  397. package/dist/pipeline/active-membership.js +6 -2
  398. package/dist/pipeline/append-event-core.d.ts +2 -1
  399. package/dist/pipeline/append-event-core.js +2 -2
  400. package/dist/pipeline/attach-outside-transaction.d.ts +3 -0
  401. package/dist/pipeline/attach-outside-transaction.js +13 -0
  402. package/dist/pipeline/auth-claims-resolver.d.ts +2 -1
  403. package/dist/pipeline/cascade-handler.d.ts +2 -1
  404. package/dist/pipeline/cascade-handler.js +3 -2
  405. package/dist/pipeline/config-accessor-factory.d.ts +1 -1
  406. package/dist/pipeline/config-accessor-factory.js +1 -1
  407. package/dist/pipeline/context-services.d.ts +56 -0
  408. package/dist/pipeline/context-services.js +73 -0
  409. package/dist/pipeline/dispatch-batch.d.ts +2 -1
  410. package/dist/pipeline/dispatch-batch.js +31 -18
  411. package/dist/pipeline/dispatch-query.js +5 -4
  412. package/dist/pipeline/dispatch-scope.d.ts +6 -0
  413. package/dist/pipeline/dispatch-scope.js +27 -0
  414. package/dist/pipeline/dispatch-shared.d.ts +13 -9
  415. package/dist/pipeline/dispatch-shared.js +75 -198
  416. package/dist/pipeline/dispatch-stream.js +8 -4
  417. package/dist/pipeline/dispatch-write.d.ts +2 -1
  418. package/dist/pipeline/dispatch-write.js +10 -8
  419. package/dist/pipeline/dispatcher-utils.d.ts +3 -1
  420. package/dist/pipeline/dispatcher-utils.js +8 -2
  421. package/dist/pipeline/dispatcher.d.ts +3 -2
  422. package/dist/pipeline/dispatcher.js +4 -3
  423. package/dist/pipeline/event-consumer-state.d.ts +0 -1
  424. package/dist/pipeline/event-dispatcher-delivery.d.ts +1 -1
  425. package/dist/pipeline/event-dispatcher-delivery.js +4 -2
  426. package/dist/pipeline/event-dispatcher.d.ts +2 -2
  427. package/dist/pipeline/event-dispatcher.js +7 -3
  428. package/dist/pipeline/event-retention.js +59 -56
  429. package/dist/pipeline/handler-access-error.js +2 -1
  430. package/dist/pipeline/handler-context-auth.d.ts +5 -6
  431. package/dist/pipeline/handler-context-auth.js +7 -4
  432. package/dist/pipeline/handler-context-config.d.ts +2 -5
  433. package/dist/pipeline/handler-context-config.js +2 -2
  434. package/dist/pipeline/handler-context-db.d.ts +32 -7
  435. package/dist/pipeline/handler-context-db.js +26 -17
  436. package/dist/pipeline/handler-context-dispatch.d.ts +13 -7
  437. package/dist/pipeline/handler-context-dispatch.js +9 -8
  438. package/dist/pipeline/handler-context-events.d.ts +22 -36
  439. package/dist/pipeline/handler-context-events.js +36 -31
  440. package/dist/pipeline/handler-context-member-resolution.d.ts +2 -0
  441. package/dist/pipeline/handler-context-member-resolution.js +110 -0
  442. package/dist/pipeline/handler-context-notify.d.ts +3 -2
  443. package/dist/pipeline/handler-context-notify.js +1 -1
  444. package/dist/pipeline/handler-context-observability.d.ts +2 -4
  445. package/dist/pipeline/handler-context-observability.js +7 -5
  446. package/dist/pipeline/handler-context-phase-denials.d.ts +11 -0
  447. package/dist/pipeline/handler-context-phase-denials.js +98 -0
  448. package/dist/pipeline/handler-context-scope.d.ts +7 -10
  449. package/dist/pipeline/handler-context-scope.js +18 -20
  450. package/dist/pipeline/index.d.ts +9 -21
  451. package/dist/pipeline/index.js +5 -7
  452. package/dist/pipeline/irreversible-operation-gate.d.ts +1 -1
  453. package/dist/pipeline/irreversible-operation-gate.js +2 -2
  454. package/dist/pipeline/lifecycle-pipeline.d.ts +8 -7
  455. package/dist/pipeline/lifecycle-pipeline.js +9 -15
  456. package/dist/pipeline/member-read-only-transaction.js +11 -3
  457. package/dist/pipeline/member-reader.d.ts +1 -1
  458. package/dist/pipeline/member-reader.js +2 -2
  459. package/dist/pipeline/msp-rebuild.js +5 -3
  460. package/dist/pipeline/multi-stream-apply-context.js +3 -2
  461. package/dist/pipeline/notify-scope.d.ts +2 -1
  462. package/dist/pipeline/pre-handler-gates.d.ts +2 -1
  463. package/dist/pipeline/pre-transaction-reservations.d.ts +3 -3
  464. package/dist/pipeline/pre-transaction-reservations.js +9 -7
  465. package/dist/pipeline/projection-rebuild.js +12 -5
  466. package/dist/pipeline/projection-state.d.ts +0 -6
  467. package/dist/pipeline/projection-state.js +0 -5
  468. package/dist/pipeline/projections-runner.d.ts +2 -1
  469. package/dist/pipeline/projections-runner.js +10 -6
  470. package/dist/pipeline/system-hooks.d.ts +3 -1
  471. package/dist/pipeline/system-hooks.js +6 -4
  472. package/dist/pipeline/system-identity-switch.d.ts +4 -2
  473. package/dist/pipeline/system-identity-switch.js +51 -36
  474. package/dist/pipeline/typed-append-event.d.ts +2 -0
  475. package/dist/pipeline/typed-append-event.js +4 -0
  476. package/dist/pipeline/write-origin.js +2 -2
  477. package/dist/pipeline/write-result-masking.d.ts +1 -1
  478. package/dist/random/index.d.ts +1 -2
  479. package/dist/random/index.js +1 -2
  480. package/dist/rate-limit/bucket.d.ts +2 -1
  481. package/dist/rate-limit/middleware.js +2 -1
  482. package/dist/redis/index.d.ts +3 -4
  483. package/dist/redis/index.js +2 -2
  484. package/dist/schema-cli/apply-command.js +5 -2
  485. package/dist/schema-cli/baseline-command.js +7 -2
  486. package/dist/schema-cli/generate-command.js +7 -9
  487. package/dist/schema-cli/shared.d.ts +12 -2
  488. package/dist/schema-cli/shared.js +24 -2
  489. package/dist/schema-cli/status-command.js +8 -2
  490. package/dist/schema-cli/validate-command.js +48 -4
  491. package/dist/schema-cli.d.ts +0 -1
  492. package/dist/search/configure-tenant-index.d.ts +1 -3
  493. package/dist/search/configure-tenant-index.js +0 -4
  494. package/dist/search/index.d.ts +1 -4
  495. package/dist/search/index.js +0 -2
  496. package/dist/search/meilisearch-adapter-internals.d.ts +8 -0
  497. package/dist/search/meilisearch-adapter-internals.js +9 -0
  498. package/dist/search/meilisearch-adapter.d.ts +1 -8
  499. package/dist/search/meilisearch-adapter.js +6 -7
  500. package/dist/search/meilisearch-peer.d.ts +2 -0
  501. package/dist/search/meilisearch-peer.js +5 -0
  502. package/dist/search/reindex-entity.js +93 -87
  503. package/dist/secrets/index.d.ts +3 -4
  504. package/dist/secrets/index.js +2 -3
  505. package/dist/seeding/index.d.ts +2 -2
  506. package/dist/seeding/index.js +1 -2
  507. package/dist/time/index.d.ts +2 -2
  508. package/dist/time/index.js +1 -1
  509. package/dist/time/tz-context.d.ts +0 -5
  510. package/dist/time/tz-context.js +0 -9
  511. package/dist/ui-types/index.d.ts +8 -11
  512. package/dist/ui-types/index.js +3 -3
  513. package/dist/upgrade-changelog.d.ts +3 -2
  514. package/dist/upgrade-changelog.js +12 -8
  515. package/dist/upgrade-cli-internals.d.ts +8 -0
  516. package/dist/upgrade-cli-internals.js +63 -0
  517. package/dist/upgrade-cli.d.ts +2 -9
  518. package/dist/upgrade-cli.js +28 -70
  519. package/dist/utils/import-optional-peer.d.ts +6 -0
  520. package/dist/utils/import-optional-peer.js +19 -0
  521. package/dist/utils/index.d.ts +1 -4
  522. package/dist/utils/index.js +1 -4
  523. package/package.json +23 -19
  524. package/src/changes.json +236 -0
  525. package/dist/crypto/request-kms-cache.d.ts +0 -8
  526. package/dist/crypto/request-kms-cache.js +0 -21
  527. package/dist/engine/codemod/index.d.ts +0 -2
  528. package/dist/engine/codemod/index.js +0 -1
  529. package/dist/engine/codemod/pipeline-codemod.d.ts +0 -50
  530. package/dist/engine/codemod/pipeline-codemod.js +0 -536
  531. package/dist/engine/feature-ast/entity-field-types.d.ts +0 -13
  532. package/dist/engine/feature-ast/entity-field-types.js +0 -35
  533. package/dist/engine/feature-ast/extractors/ai-steps.d.ts +0 -6
  534. package/dist/engine/feature-ast/extractors/ai-steps.js +0 -254
  535. package/dist/engine/feature-ast/extractors/events.d.ts +0 -5
  536. package/dist/engine/feature-ast/extractors/events.js +0 -275
  537. package/dist/engine/feature-ast/extractors/handlers.d.ts +0 -24
  538. package/dist/engine/feature-ast/extractors/handlers.js +0 -358
  539. package/dist/engine/feature-ast/extractors/hooks.d.ts +0 -24
  540. package/dist/engine/feature-ast/extractors/hooks.js +0 -248
  541. package/dist/engine/feature-ast/extractors/index.d.ts +0 -14
  542. package/dist/engine/feature-ast/extractors/index.js +0 -13
  543. package/dist/engine/feature-ast/extractors/jobs-routes.d.ts +0 -7
  544. package/dist/engine/feature-ast/extractors/jobs-routes.js +0 -145
  545. package/dist/engine/feature-ast/extractors/projections-screens.d.ts +0 -10
  546. package/dist/engine/feature-ast/extractors/projections-screens.js +0 -195
  547. package/dist/engine/feature-ast/extractors/resolve-import.d.ts +0 -21
  548. package/dist/engine/feature-ast/extractors/resolve-import.js +0 -180
  549. package/dist/engine/feature-ast/extractors/round1.d.ts +0 -11
  550. package/dist/engine/feature-ast/extractors/round1.js +0 -87
  551. package/dist/engine/feature-ast/extractors/round2.d.ts +0 -7
  552. package/dist/engine/feature-ast/extractors/round2.js +0 -191
  553. package/dist/engine/feature-ast/extractors/round3.d.ts +0 -23
  554. package/dist/engine/feature-ast/extractors/round3.js +0 -292
  555. package/dist/engine/feature-ast/extractors/round5.d.ts +0 -9
  556. package/dist/engine/feature-ast/extractors/round5.js +0 -68
  557. package/dist/engine/feature-ast/extractors/round6.d.ts +0 -4
  558. package/dist/engine/feature-ast/extractors/round6.js +0 -17
  559. package/dist/engine/feature-ast/extractors/shared.d.ts +0 -94
  560. package/dist/engine/feature-ast/extractors/shared.js +0 -343
  561. package/dist/engine/feature-ast/index.d.ts +0 -16
  562. package/dist/engine/feature-ast/index.js +0 -10
  563. package/dist/engine/feature-ast/parse.d.ts +0 -31
  564. package/dist/engine/feature-ast/parse.js +0 -485
  565. package/dist/engine/feature-ast/patch.d.ts +0 -212
  566. package/dist/engine/feature-ast/patch.js +0 -611
  567. package/dist/engine/feature-ast/patcher.d.ts +0 -217
  568. package/dist/engine/feature-ast/patcher.js +0 -281
  569. package/dist/engine/feature-ast/pattern-change-schema.d.ts +0 -1238
  570. package/dist/engine/feature-ast/pattern-change-schema.js +0 -1072
  571. package/dist/engine/feature-ast/pattern-id-matchers.d.ts +0 -7
  572. package/dist/engine/feature-ast/pattern-id-matchers.js +0 -211
  573. package/dist/engine/feature-ast/pattern-id-schema.d.ts +0 -251
  574. package/dist/engine/feature-ast/pattern-id-schema.js +0 -166
  575. package/dist/engine/feature-ast/patterns.d.ts +0 -322
  576. package/dist/engine/feature-ast/patterns.js +0 -107
  577. package/dist/engine/feature-ast/render.d.ts +0 -47
  578. package/dist/engine/feature-ast/render.js +0 -666
  579. package/dist/engine/feature-ast/source-location.d.ts +0 -17
  580. package/dist/engine/feature-ast/source-location.js +0 -27
  581. package/dist/engine/pattern-library/index.d.ts +0 -2
  582. package/dist/engine/pattern-library/index.js +0 -3
  583. package/dist/engine/pattern-library/library.d.ts +0 -14
  584. package/dist/engine/pattern-library/library.js +0 -94
  585. package/dist/engine/pattern-library/mixed-schemas.d.ts +0 -16
  586. package/dist/engine/pattern-library/mixed-schemas.js +0 -559
  587. package/dist/engine/pattern-library/opaque-schemas.d.ts +0 -7
  588. package/dist/engine/pattern-library/opaque-schemas.js +0 -115
  589. package/dist/engine/pattern-library/shared-fields.d.ts +0 -122
  590. package/dist/engine/pattern-library/shared-fields.js +0 -88
  591. package/dist/engine/pattern-library/static-schemas.d.ts +0 -21
  592. package/dist/engine/pattern-library/static-schemas.js +0 -487
  593. package/dist/engine/pattern-library/types.d.ts +0 -158
  594. package/dist/engine/pattern-library/types.js +0 -36
  595. package/dist/engine/resolve-config-or-param.d.ts +0 -18
  596. package/dist/engine/resolve-config-or-param.js +0 -76
  597. package/src/scripts/codemod/README.md +0 -187
  598. package/src/scripts/codemod/codemod-support.ts +0 -334
  599. package/src/scripts/codemod/collect-source-files.ts +0 -48
  600. package/src/scripts/codemod/crypto-shredding-testing-move.ts +0 -119
  601. package/src/scripts/codemod/db-factory.ts +0 -810
  602. package/src/scripts/codemod/feature-factory.ts +0 -429
  603. package/src/scripts/codemod/feature-layout.ts +0 -424
  604. package/src/scripts/codemod/import-extensions.ts +0 -118
  605. package/src/scripts/codemod/migrate-cross-tenant.ts +0 -328
  606. package/src/scripts/codemod/migrate-db-raw.ts +0 -401
  607. package/src/scripts/codemod/migrate-open-to-all.ts +0 -235
  608. package/src/scripts/codemod/object-form.ts +0 -746
  609. package/src/scripts/codemod/package-merge.ts +0 -299
  610. package/src/scripts/codemod/pii-personal-migration.ts +0 -816
  611. package/src/scripts/codemod/remove-engine-payload-casts.ts +0 -318
  612. package/src/scripts/codemod/s3-imports.ts +0 -236
  613. package/src/scripts/codemod/tenant-db-options.ts +0 -454
  614. package/src/scripts/codemod/testing-injection.ts +0 -215
  615. package/src/scripts/codemod/testing-move-targets.ts +0 -161
  616. package/src/scripts/codemod/testing-move.ts +0 -542
  617. package/src/scripts/codemod/unprocessable-error-details-reason.ts +0 -411
@@ -212,7 +212,7 @@ beforeAll(async () => {
212
212
  // Wire ctx.config() so the branding query resolves the tenant's cascade.
213
213
  extraContext: ({ registry }) => ({
214
214
  configResolver: resolver,
215
- _configAccessorFactory: createConfigAccessorFactory(registry, resolver),
215
+ configAccessorFactory: createConfigAccessorFactory(registry, resolver),
216
216
  }),
217
217
  });
218
218
  await unsafeCreateEntityTable(stack.db, pageEntity);
@@ -38,7 +38,12 @@ bun test
38
38
 
39
39
  import { afterAll, beforeAll, beforeEach, describe, expect, test } from "bun:test";
40
40
  import { createTenantDb } from "@cosmicdrift/kumiko-framework/db";
41
- import type { SaveContext } from "@cosmicdrift/kumiko-framework/engine";
41
+ import {
42
+ attachOutsideTransaction,
43
+ bridgeStub,
44
+ type HandlerContext,
45
+ type SaveContext,
46
+ } from "@cosmicdrift/kumiko-framework/engine";
42
47
  import { createEventsTable } from "@cosmicdrift/kumiko-framework/event-store";
43
48
  import { createCascadeDeleteHook } from "@cosmicdrift/kumiko-framework/pipeline";
44
49
  import { TestUsers } from "@cosmicdrift/kumiko-framework/seeding";
@@ -77,6 +82,16 @@ beforeEach(() => {
77
82
  stack.events.reset();
78
83
  });
79
84
 
85
+ // The cascade hook runs against the same tenant-scoped db a dispatcher would hand it.
86
+ function hookContext(): HandlerContext {
87
+ const db = createTenantDb({ db: stack.db, tenantId: admin.tenantId });
88
+ return {
89
+ ...bridgeStub({ user: admin }),
90
+ registry: stack.registry,
91
+ db: attachOutsideTransaction(db, undefined),
92
+ };
93
+ }
94
+
80
95
  describe("restrict: team cannot be deleted with members", () => {
81
96
  test("delete team with members fails", async () => {
82
97
  const team = await stack.http.writeOk<SaveContext>(
@@ -105,7 +120,7 @@ describe("restrict: team cannot be deleted with members", () => {
105
120
  entityName: "team",
106
121
  event: createTestStoredEvent(),
107
122
  },
108
- { db: stack.db },
123
+ hookContext(),
109
124
  ),
110
125
  ).rejects.toMatchObject({ code: "conflict", details: { reason: "delete_restricted" } });
111
126
  });
@@ -128,7 +143,7 @@ describe("restrict: team cannot be deleted with members", () => {
128
143
  entityName: "team",
129
144
  event: createTestStoredEvent(),
130
145
  },
131
- { db: stack.db },
146
+ hookContext(),
132
147
  ),
133
148
  ).resolves.toBeUndefined();
134
149
  });
@@ -178,7 +193,7 @@ describe("cascade: deleting member removes tasks", () => {
178
193
  entityName: "member",
179
194
  event: createTestStoredEvent(),
180
195
  },
181
- { db: createTenantDb({ db: stack.db, tenantId: admin.tenantId }) },
196
+ hookContext(),
182
197
  );
183
198
 
184
199
  // Tasks should be gone
@@ -13,7 +13,7 @@ Tenant-scoped full-text search (Meilisearch / in-memory adapter).
13
13
  ## What it shows
14
14
 
15
15
  - `searchable` / `searchWeight` on fields
16
- - Handler reads via `ctx.searchAdapter`
16
+ - Handler reads via `ctx.services.searchAdapter`
17
17
 
18
18
  ## Source
19
19
 
@@ -160,7 +160,7 @@ describe("search indexing", () => {
160
160
  ```ts
161
161
  // Search Sample
162
162
  // Shows: searchable fields, searchWeight, search via InMemory SearchAdapter.
163
- // Each handler builds its executor inline so `ctx.searchAdapter` is read fresh
163
+ // Each handler builds its executor inline so `ctx.services.searchAdapter` is read fresh
164
164
  // per call — tests swap the adapter between runs.
165
165
 
166
166
  import { buildEntityTable, createEventStoreExecutor } from "@cosmicdrift/kumiko-framework/db";
@@ -198,7 +198,7 @@ export const productFeature = defineFeature("shop", (r) => {
198
198
  }),
199
199
  handler: async (event, ctx) => {
200
200
  const crud = createEventStoreExecutor(productTable, productEntity, {
201
- searchAdapter: ctx.searchAdapter,
201
+ searchAdapter: ctx.services.searchAdapter,
202
202
  entityName: "product",
203
203
  });
204
204
  return crud.create(event.payload, event.user, ctx.db);
@@ -214,7 +214,7 @@ export const productFeature = defineFeature("shop", (r) => {
214
214
  }),
215
215
  handler: async (query, ctx) => {
216
216
  const crud = createEventStoreExecutor(productTable, productEntity, {
217
- searchAdapter: ctx.searchAdapter,
217
+ searchAdapter: ctx.services.searchAdapter,
218
218
  entityName: "product",
219
219
  });
220
220
  return crud.list(query.payload, query.user, ctx.db);
@@ -12,7 +12,7 @@ Tenant-owned secrets with envelope encryption, DEK cache, and KEK rotation.
12
12
 
13
13
  ## What it shows
14
14
 
15
- - `r.secret` + `ctx.secrets.get` (audited reads)
15
+ - `r.secret` + `ctx.services.secrets.get` (audited reads)
16
16
  - Charge-style handler that never returns the plaintext key
17
17
 
18
18
  ## Source
@@ -39,7 +39,7 @@ bun test
39
39
  // function calls into framework internals):
40
40
  // 1. A TenantAdmin sets a secret over HTTP → DB holds only an envelope.
41
41
  // 2. list handler returns a redacted preview, never plaintext.
42
- // 3. Feature code (ctx.secrets.get) decrypts through the audited wrapper.
42
+ // 3. Feature code (ctx.services.secrets.get) decrypts through the audited wrapper.
43
43
  // Every read writes a tenantSecretRead event to the events-table.
44
44
  // 4. The response-guard catches accidental Secret<> leaks: a handler
45
45
  // that tries to return the branded value triggers a 500 at the
@@ -129,7 +129,7 @@ beforeAll(async () => {
129
129
  features: [createJobsFeature(), createSecretsFeature(), createBillingFeature(), leakyFeature],
130
130
  // Typed masterKeyProvider option: lands in AppContext as a typed field,
131
131
  // no Record<string, unknown>-via-extraContext. The rotation job reads
132
- // it from ctx.masterKeyProvider directly.
132
+ // it from ctx.services.masterKeyProvider directly.
133
133
  masterKeyProvider: providerRef,
134
134
  extraContext: ({ db, registry }) => ({
135
135
  // SecretsContext sees the mutable ref — any replace() flips what
@@ -299,7 +299,7 @@ describe("5. KEK rotation via the core job + real BullMQ dispatch", () => {
299
299
 
300
300
  test("subsequent ctx.secrets.get after rotation still returns the original plaintext", async () => {
301
301
  // Goes through the whole real stack: HTTP → dispatcher → billing
302
- // handler → ctx.secrets.get → cached DEK-unwrap with V2 → decrypt.
302
+ // handler → ctx.services.secrets.get → cached DEK-unwrap with V2 → decrypt.
303
303
  // If rotation broke anything, fingerprint would differ or the call
304
304
  // would throw.
305
305
  const result = await stack.http.writeOk<{ keyFingerprint: string }>(
@@ -328,7 +328,7 @@ describe("5. KEK rotation via the core job + real BullMQ dispatch", () => {
328
328
  ### src/feature.ts
329
329
 
330
330
  ```ts
331
- // A miniature "billing" feature that reads a Stripe API key from ctx.secrets
331
+ // A miniature "billing" feature that reads a Stripe API key from ctx.services.secrets
332
332
  // and simulates a charge. The point is to show how feature code uses the
333
333
  // plaintext secret without ever exposing it to clients — the charge endpoint
334
334
  // returns { chargeId } but never the apiKey.
@@ -357,7 +357,10 @@ const chargeWrite = defineWriteHandler({
357
357
  }),
358
358
  access: { roles: ["TenantAdmin", "User"] },
359
359
  handler: async (event, ctx) => {
360
- const secrets = requireSecretsContext(ctx, "billing:write:charge");
360
+ const secrets = requireSecretsContext(
361
+ { secrets: ctx.services.secrets, user: ctx.user },
362
+ "billing:write:charge",
363
+ );
361
364
  // requireSecretsContext returned a wrapper that auto-fills the audit
362
365
  // context (userId + "billing:write:charge") on every .get — the read
363
366
  // lands in tenant_secret_reads without the handler having to remember.
@@ -510,7 +510,7 @@ export const INVOICE_EVENTS = {
510
510
  // Qualifier used by the reducer to match events from the stream.
511
511
  // `<const TShort>` preserves the literal-string at the call-site, so
512
512
  // `eventName(INVOICE_EVENTS.sent)` carries `"billing:event:invoice-sent"`
513
- // as a literal type. That literal is what `ctx.appendEvent({ type, ... })`
513
+ // as a literal type. That literal is what `ctx.events.append({ type, ... })`
514
514
  // strict-checks against the augmented `KumikoEventTypeMap`.
515
515
  export function eventName<const TShort extends string>(
516
516
  short: TShort,
@@ -927,7 +927,7 @@ export async function loadInvoiceState(
927
927
  ctx: HandlerContext,
928
928
  id: string,
929
929
  ): Promise<InvoiceState | null> {
930
- const events = await ctx.loadAggregate(id);
930
+ const events = await ctx.events.load(id);
931
931
  if (events.length === 0) return null;
932
932
  const state: InvoiceState = { ...initialInvoiceState };
933
933
  for (const evt of events) reduceInvoice(state, evt);
@@ -158,7 +158,7 @@ beforeAll(async () => {
158
158
  features: [createConfigFeature(), createTenantSettingsFeature(), invoiceFeature],
159
159
  extraContext: ({ registry }) => ({
160
160
  configResolver: resolver,
161
- _configAccessorFactory: createConfigAccessorFactory(registry, resolver),
161
+ configAccessorFactory: createConfigAccessorFactory(registry, resolver),
162
162
  }),
163
163
  });
164
164
  await unsafePushTables(stack.db, { configValuesTable });
@@ -173,7 +173,7 @@ import {
173
173
  import { insertOne, selectMany } from "@cosmicdrift/kumiko-framework/db";
174
174
  import { EXT_USER_DATA } from "@cosmicdrift/kumiko-framework/engine";
175
175
  import { getTemporal } from "@cosmicdrift/kumiko-framework/time";
176
- import { seedRow } from "@cosmicdrift/kumiko-testing/helpers";
176
+ import { seedRowViaEventStore } from "@cosmicdrift/kumiko-testing/helpers";
177
177
  import {
178
178
  setupTestStack,
179
179
  type TestStack,
@@ -183,8 +183,6 @@ import { noteEntity, notesFeature, notesTable } from "../feature";
183
183
 
184
184
  let stack: TestStack;
185
185
 
186
- const TENANT_SYSTEM = "00000000-0000-4000-8000-000000000001";
187
-
188
186
  // Each test gets its own tenant and user, so rows from other tests never show up.
189
187
  let testNumber = 0;
190
188
  let TENANT_A = "";
@@ -231,9 +229,8 @@ function noteId(index: number): string {
231
229
  }
232
230
 
233
231
  async function seedAlice(opts: { gracePeriodEnd?: Instant; status?: string } = {}): Promise<void> {
234
- await seedRow(stack.db, userTable, {
232
+ await seedRowViaEventStore(stack.db, userTable, {
235
233
  id: ALICE_ID,
236
- tenantId: TENANT_SYSTEM,
237
234
  email: ALICE_EMAIL,
238
235
  passwordHash: "h",
239
236
  displayName: "Alice",
@@ -243,7 +240,7 @@ async function seedAlice(opts: { gracePeriodEnd?: Instant; status?: string } = {
243
240
  status: opts.status ?? USER_STATUS.Active,
244
241
  gracePeriodEnd: opts.gracePeriodEnd ?? null,
245
242
  });
246
- await seedRow(stack.db, tenantMembershipsTable, {
243
+ await seedRowViaEventStore(stack.db, tenantMembershipsTable, {
247
244
  tenantId: TENANT_A,
248
245
  userId: ALICE_ID,
249
246
  roles: '["Member"]',
@@ -325,7 +325,7 @@ describe("workflow-engine", () => {
325
325
  });
326
326
 
327
327
  it("webhook-delivery completes with exactly one dispatch request", async () => {
328
- const ctx = { unsafeAppendEvent: mock().mockResolvedValue(undefined) };
328
+ const ctx = { events: { unsafeAppend: mock().mockResolvedValue(undefined) } };
329
329
 
330
330
  const result = await startAndRunWorkflow({
331
331
  runId: "wf-webhook-delivery-1",
@@ -339,7 +339,7 @@ describe("workflow-engine", () => {
339
339
  });
340
340
 
341
341
  expect(result.outcome).toBe("completed");
342
- const dispatchRequests = ctx.unsafeAppendEvent.mock.calls
342
+ const dispatchRequests = ctx.events.unsafeAppend.mock.calls
343
343
  .map(([event]) => event as { type: string; payload: Record<string, unknown> })
344
344
  .filter((event) => event.type === STEP_DISPATCH_REQUESTED_TYPE);
345
345
  expect(dispatchRequests).toHaveLength(1);
@@ -367,7 +367,7 @@ describe("workflow-engine", () => {
367
367
 
368
368
  describe("workflow-runner", () => {
369
369
  function makeAppendOnlyCtx() {
370
- return { unsafeAppendEvent: mock().mockResolvedValue(undefined) };
370
+ return { events: { unsafeAppend: mock().mockResolvedValue(undefined) } };
371
371
  }
372
372
 
373
373
  it("startAndRunWorkflow writes run.started with Q7 snapshot fingerprint, then runs the pipeline to completion when no suspension", async () => {
@@ -386,15 +386,15 @@ describe("workflow-runner", () => {
386
386
  });
387
387
 
388
388
  expect(result.outcome).toBe("completed");
389
- expect(ctx.unsafeAppendEvent).toHaveBeenCalledTimes(2);
390
- const started = ctx.unsafeAppendEvent.mock.calls[0]![0] as {
389
+ expect(ctx.events.unsafeAppend).toHaveBeenCalledTimes(2);
390
+ const started = ctx.events.unsafeAppend.mock.calls[0]![0] as {
391
391
  type: string;
392
392
  payload: Record<string, unknown>;
393
393
  };
394
394
  expect(started.type).toBe("kumiko:system:workflow.run-started");
395
395
  expect(started.payload["definitionFingerprint"]).toBe(computeDefinitionFingerprint(workflow));
396
396
  expect(started.payload["triggerEventType"]).toBe("demo.fired");
397
- const completed = ctx.unsafeAppendEvent.mock.calls[1]![0] as { type: string };
397
+ const completed = ctx.events.unsafeAppend.mock.calls[1]![0] as { type: string };
398
398
  expect(completed.type).toBe("kumiko:system:workflow.run-completed");
399
399
  });
400
400
 
@@ -418,8 +418,8 @@ describe("workflow-runner", () => {
418
418
 
419
419
  expect(result.outcome).toBe("suspended");
420
420
  // run.started + workflow.step.waiting — no run-completed yet
421
- expect(ctx.unsafeAppendEvent).toHaveBeenCalledTimes(2);
422
- const waiting = ctx.unsafeAppendEvent.mock.calls[1]![0] as {
421
+ expect(ctx.events.unsafeAppend).toHaveBeenCalledTimes(2);
422
+ const waiting = ctx.events.unsafeAppend.mock.calls[1]![0] as {
423
423
  type: string;
424
424
  payload: Record<string, unknown>;
425
425
  };
@@ -444,14 +444,16 @@ describe("workflow-runner", () => {
444
444
  handlerCtx: ctx as never,
445
445
  });
446
446
 
447
- const started = ctx.unsafeAppendEvent.mock.calls[0]![0] as { payload: Record<string, unknown> };
447
+ const started = ctx.events.unsafeAppend.mock.calls[0]![0] as {
448
+ payload: Record<string, unknown>;
449
+ };
448
450
  expect(started.payload["idempotencyKey"]).toBe("id:abc");
449
451
  });
450
452
  });
451
453
 
452
454
  describe("userOnboardingWorkflow (end-to-end, in-memory)", () => {
453
455
  it("suspends on the first wait, then resume-loop runs it through to completion", async () => {
454
- const ctx = { unsafeAppendEvent: mock().mockResolvedValue(undefined) };
456
+ const ctx = { events: { unsafeAppend: mock().mockResolvedValue(undefined) } };
455
457
  const trigger = {
456
458
  aggregateId: "agg_user_42",
457
459
  type: "user.signed-up",
@@ -469,16 +471,16 @@ describe("userOnboardingWorkflow (end-to-end, in-memory)", () => {
469
471
 
470
472
  expect(result.outcome).toBe("suspended");
471
473
  // Calls: run.started, mail.send dispatch-requested, workflow.step.waiting
472
- expect(ctx.unsafeAppendEvent).toHaveBeenCalledTimes(3);
473
- const startedCall = ctx.unsafeAppendEvent.mock.calls[0]![0] as {
474
+ expect(ctx.events.unsafeAppend).toHaveBeenCalledTimes(3);
475
+ const startedCall = ctx.events.unsafeAppend.mock.calls[0]![0] as {
474
476
  type: string;
475
477
  payload: Record<string, unknown>;
476
478
  };
477
- const mailCall = ctx.unsafeAppendEvent.mock.calls[1]![0] as {
479
+ const mailCall = ctx.events.unsafeAppend.mock.calls[1]![0] as {
478
480
  type: string;
479
481
  payload: Record<string, unknown>;
480
482
  };
481
- const waitingCall = ctx.unsafeAppendEvent.mock.calls[2]![0] as {
483
+ const waitingCall = ctx.events.unsafeAppend.mock.calls[2]![0] as {
482
484
  type: string;
483
485
  payload: Record<string, unknown>;
484
486
  };
@@ -514,7 +516,7 @@ describe("userOnboardingWorkflow (end-to-end, in-memory)", () => {
514
516
  definitionFingerprint: waitingCall.payload["definitionFingerprint"] as string,
515
517
  };
516
518
 
517
- const resumeCtx = { unsafeAppendEvent: mock().mockResolvedValue(undefined) };
519
+ const resumeCtx = { events: { unsafeAppend: mock().mockResolvedValue(undefined) } };
518
520
  const count = await runResumeLoop(
519
521
  createInMemorySuspendedRunFetcher([suspendedRun]),
520
522
  resumeCtx as never,
@@ -525,7 +527,7 @@ describe("userOnboardingWorkflow (end-to-end, in-memory)", () => {
525
527
  // because userId starts with "active-"), second WAITING for P7D.
526
528
  // The run is suspended again before the webhook, so no RUN_COMPLETED
527
529
  // yet — this is one resume-cycle, not the whole workflow.
528
- const resumeTypes = resumeCtx.unsafeAppendEvent.mock.calls.map(
530
+ const resumeTypes = resumeCtx.events.unsafeAppend.mock.calls.map(
529
531
  (c) => (c[0] as { type: string }).type,
530
532
  );
531
533
  expect(resumeTypes).toEqual([
@@ -533,14 +535,14 @@ describe("userOnboardingWorkflow (end-to-end, in-memory)", () => {
533
535
  "kumiko:system:step.dispatch-requested",
534
536
  "kumiko:system:workflow.step.waiting",
535
537
  ]);
536
- const tipsMail = resumeCtx.unsafeAppendEvent.mock.calls[1]![0] as {
538
+ const tipsMail = resumeCtx.events.unsafeAppend.mock.calls[1]![0] as {
537
539
  payload: { subject: string };
538
540
  };
539
541
  expect(tipsMail.payload.subject).toBe("Engagement tips");
540
542
  });
541
543
 
542
544
  it("not-engaged path picks the reminder branch", async () => {
543
- const ctx = { unsafeAppendEvent: mock().mockResolvedValue(undefined) };
545
+ const ctx = { events: { unsafeAppend: mock().mockResolvedValue(undefined) } };
544
546
  const trigger = {
545
547
  aggregateId: "agg_user_cold",
546
548
  type: "user.signed-up",
@@ -553,7 +555,9 @@ describe("userOnboardingWorkflow (end-to-end, in-memory)", () => {
553
555
  triggerEventRef: { eventId: "2", aggregateId: trigger.aggregateId, version: 1 },
554
556
  handlerCtx: ctx as never,
555
557
  });
556
- const waiting = ctx.unsafeAppendEvent.mock.calls[2]![0] as { payload: Record<string, unknown> };
558
+ const waiting = ctx.events.unsafeAppend.mock.calls[2]![0] as {
559
+ payload: Record<string, unknown>;
560
+ };
557
561
  const suspendedRun: SuspendableRun = {
558
562
  runId: "wf-onboarding-cold-1",
559
563
  workflowName: "user-onboarding",
@@ -564,10 +568,10 @@ describe("userOnboardingWorkflow (end-to-end, in-memory)", () => {
564
568
  triggerEvent: trigger as never,
565
569
  definitionFingerprint: waiting.payload["definitionFingerprint"] as string,
566
570
  };
567
- const resumeCtx = { unsafeAppendEvent: mock().mockResolvedValue(undefined) };
571
+ const resumeCtx = { events: { unsafeAppend: mock().mockResolvedValue(undefined) } };
568
572
  await runResumeLoop(createInMemorySuspendedRunFetcher([suspendedRun]), resumeCtx as never);
569
573
 
570
- const reminderMail = resumeCtx.unsafeAppendEvent.mock.calls[1]![0] as {
574
+ const reminderMail = resumeCtx.events.unsafeAppend.mock.calls[1]![0] as {
571
575
  payload: { subject: string };
572
576
  };
573
577
  expect(reminderMail.payload.subject).toBe("Getting started");
@@ -696,7 +700,7 @@ describe("cron-scheduler", () => {
696
700
  steps: stepsPipeline(({ r }) => [r.step.return({ isSuccess: true, data: undefined })]),
697
701
  });
698
702
 
699
- const handlerCtx = { unsafeAppendEvent: mock() };
703
+ const handlerCtx = { events: { unsafeAppend: mock() } };
700
704
  const lastRuns = new Map<string, Temporal.Instant>();
701
705
  const now = Temporal.Instant.from("2025-06-01T08:00:00Z");
702
706
 
@@ -708,7 +712,7 @@ describe("cron-scheduler", () => {
708
712
  );
709
713
 
710
714
  expect(count).toBe(0);
711
- expect(handlerCtx.unsafeAppendEvent).not.toHaveBeenCalled();
715
+ expect(handlerCtx.events.unsafeAppend).not.toHaveBeenCalled();
712
716
  });
713
717
 
714
718
  it("runDueCronWorkflows runs due workflows through the full start path", async () => {
@@ -718,7 +722,7 @@ describe("cron-scheduler", () => {
718
722
  steps: stepsPipeline(({ r }) => [r.step.return({ isSuccess: true, data: undefined })]),
719
723
  });
720
724
 
721
- const handlerCtx = { unsafeAppendEvent: mock().mockResolvedValue(undefined) };
725
+ const handlerCtx = { events: { unsafeAppend: mock().mockResolvedValue(undefined) } };
722
726
  const lastRuns = new Map<string, Temporal.Instant>();
723
727
  const lastRun = Temporal.Instant.from("2025-05-31T08:00:00Z");
724
728
  lastRuns.set("test-daily", lastRun);
@@ -733,10 +737,10 @@ describe("cron-scheduler", () => {
733
737
 
734
738
  expect(count).toBe(1);
735
739
  // run.started + run-completed (no suspension, pipeline returns immediately).
736
- expect(handlerCtx.unsafeAppendEvent).toHaveBeenCalledTimes(2);
737
- const started = handlerCtx.unsafeAppendEvent.mock.calls[0]![0] as Record<string, unknown>;
740
+ expect(handlerCtx.events.unsafeAppend).toHaveBeenCalledTimes(2);
741
+ const started = handlerCtx.events.unsafeAppend.mock.calls[0]![0] as Record<string, unknown>;
738
742
  expect(started["type"]).toBe("kumiko:system:workflow.run-started");
739
- const completed = handlerCtx.unsafeAppendEvent.mock.calls[1]![0] as Record<string, unknown>;
743
+ const completed = handlerCtx.events.unsafeAppend.mock.calls[1]![0] as Record<string, unknown>;
740
744
  expect(completed["type"]).toBe("kumiko:system:workflow.run-completed");
741
745
  });
742
746
  });
@@ -744,12 +748,12 @@ describe("cron-scheduler", () => {
744
748
  describe("resume-loop", () => {
745
749
  it("returns 0 when no suspended runs exist", async () => {
746
750
  const fetchRuns = createInMemorySuspendedRunFetcher([]);
747
- const handlerCtx = { unsafeAppendEvent: mock() };
751
+ const handlerCtx = { events: { unsafeAppend: mock() } };
748
752
 
749
753
  const count = await runResumeLoop(fetchRuns, handlerCtx as never);
750
754
 
751
755
  expect(count).toBe(0);
752
- expect(handlerCtx.unsafeAppendEvent).not.toHaveBeenCalled();
756
+ expect(handlerCtx.events.unsafeAppend).not.toHaveBeenCalled();
753
757
  });
754
758
 
755
759
  it("resumes a suspended run", async () => {
@@ -766,19 +770,19 @@ describe("resume-loop", () => {
766
770
  };
767
771
 
768
772
  const fetchRuns = createInMemorySuspendedRunFetcher([suspendedRun]);
769
- const handlerCtx = { unsafeAppendEvent: mock().mockResolvedValue(undefined) };
773
+ const handlerCtx = { events: { unsafeAppend: mock().mockResolvedValue(undefined) } };
770
774
 
771
775
  const count = await runResumeLoop(fetchRuns, handlerCtx as never);
772
776
 
773
777
  expect(count).toBe(1);
774
- expect(handlerCtx.unsafeAppendEvent).toHaveBeenCalledTimes(2);
775
- expect(handlerCtx.unsafeAppendEvent).toHaveBeenNthCalledWith(1, {
778
+ expect(handlerCtx.events.unsafeAppend).toHaveBeenCalledTimes(2);
779
+ expect(handlerCtx.events.unsafeAppend).toHaveBeenNthCalledWith(1, {
776
780
  aggregateId: "wf-test-run_123",
777
781
  aggregateType: "workflow-run",
778
782
  type: "kumiko:system:workflow.step.resumed",
779
783
  payload: { stepIndex: 0, retryAttempt: undefined },
780
784
  });
781
- expect(handlerCtx.unsafeAppendEvent).toHaveBeenNthCalledWith(2, {
785
+ expect(handlerCtx.events.unsafeAppend).toHaveBeenNthCalledWith(2, {
782
786
  aggregateId: "wf-test-run_123",
783
787
  aggregateType: "workflow-run",
784
788
  type: "kumiko:system:workflow.run-completed",
@@ -800,13 +804,13 @@ describe("resume-loop", () => {
800
804
  };
801
805
 
802
806
  const fetchRuns = createInMemorySuspendedRunFetcher([suspendedRun]);
803
- const handlerCtx = { unsafeAppendEvent: mock().mockResolvedValue(undefined) };
807
+ const handlerCtx = { events: { unsafeAppend: mock().mockResolvedValue(undefined) } };
804
808
 
805
809
  const count = await runResumeLoop(fetchRuns, handlerCtx as never);
806
810
 
807
811
  expect(count).toBe(0);
808
- expect(handlerCtx.unsafeAppendEvent).toHaveBeenCalledTimes(1);
809
- const failed = handlerCtx.unsafeAppendEvent.mock.calls[0]![0] as {
812
+ expect(handlerCtx.events.unsafeAppend).toHaveBeenCalledTimes(1);
813
+ const failed = handlerCtx.events.unsafeAppend.mock.calls[0]![0] as {
810
814
  type: string;
811
815
  payload: Record<string, unknown>;
812
816
  };
@@ -830,16 +834,18 @@ describe("resume-loop", () => {
830
834
 
831
835
  const fetchRuns = createInMemorySuspendedRunFetcher([suspendedRun]);
832
836
  const handlerCtx = {
833
- unsafeAppendEvent: mock()
834
- .mockRejectedValueOnce(new VersionConflictError("wf-conflict-run", 1))
835
- .mockResolvedValue(undefined),
837
+ events: {
838
+ unsafeAppend: mock()
839
+ .mockRejectedValueOnce(new VersionConflictError("wf-conflict-run", 1))
840
+ .mockResolvedValue(undefined),
841
+ },
836
842
  };
837
843
 
838
844
  const count = await runResumeLoop(fetchRuns, handlerCtx as never);
839
845
 
840
846
  expect(count).toBe(0);
841
- expect(handlerCtx.unsafeAppendEvent).toHaveBeenCalledTimes(1);
842
- expect((handlerCtx.unsafeAppendEvent.mock.calls[0]![0] as { type: string }).type).toBe(
847
+ expect(handlerCtx.events.unsafeAppend).toHaveBeenCalledTimes(1);
848
+ expect((handlerCtx.events.unsafeAppend.mock.calls[0]![0] as { type: string }).type).toBe(
843
849
  "kumiko:system:workflow.step.resumed",
844
850
  );
845
851
  });
@@ -1509,7 +1515,7 @@ export async function runResumeLoop(
1509
1515
  if (run.definitionFingerprint !== undefined) {
1510
1516
  const currentFingerprint = computeDefinitionFingerprint(run.workflow);
1511
1517
  if (currentFingerprint !== run.definitionFingerprint) {
1512
- await handlerCtx.unsafeAppendEvent({
1518
+ await handlerCtx.events.unsafeAppend({
1513
1519
  aggregateId: run.runId,
1514
1520
  aggregateType: WORKFLOW_AGGREGATE_TYPE,
1515
1521
  type: WORKFLOW_RUN_FAILED_TYPE,
@@ -1537,7 +1543,7 @@ export async function runResumeLoop(
1537
1543
  // no FAILED-event. Stale WAITING-rows in the fetcher result also
1538
1544
  // hit this branch on the second poll-tick.
1539
1545
  try {
1540
- await handlerCtx.unsafeAppendEvent({
1546
+ await handlerCtx.events.unsafeAppend({
1541
1547
  aggregateId: run.runId,
1542
1548
  aggregateType: WORKFLOW_AGGREGATE_TYPE,
1543
1549
  type: WORKFLOW_RESUMED_TYPE,
@@ -1589,7 +1595,7 @@ export async function runResumeLoop(
1589
1595
  // returned. A second suspension (e.g. `wait` further down the
1590
1596
  // pipeline) leaves the run pending for the next resume-loop tick.
1591
1597
  if (outcome.kind !== "suspended") {
1592
- await handlerCtx.unsafeAppendEvent({
1598
+ await handlerCtx.events.unsafeAppend({
1593
1599
  aggregateId: run.runId,
1594
1600
  aggregateType: WORKFLOW_AGGREGATE_TYPE,
1595
1601
  type: WORKFLOW_RUN_COMPLETED_TYPE,
@@ -1606,7 +1612,7 @@ export async function runResumeLoop(
1606
1612
  stepIndex: run.stepIndex,
1607
1613
  error: String(error),
1608
1614
  });
1609
- await handlerCtx.unsafeAppendEvent({
1615
+ await handlerCtx.events.unsafeAppend({
1610
1616
  aggregateId: run.runId,
1611
1617
  aggregateType: WORKFLOW_AGGREGATE_TYPE,
1612
1618
  type: WORKFLOW_RUN_FAILED_TYPE,
@@ -1697,7 +1703,7 @@ export async function startAndRunWorkflow(args: {
1697
1703
  ...(args.idempotencyKey && { idempotencyKey: args.idempotencyKey }),
1698
1704
  };
1699
1705
 
1700
- await args.handlerCtx.unsafeAppendEvent({
1706
+ await args.handlerCtx.events.unsafeAppend({
1701
1707
  aggregateId: args.runId,
1702
1708
  aggregateType: WORKFLOW_AGGREGATE_TYPE,
1703
1709
  type: WORKFLOW_RUN_STARTED_TYPE,
@@ -1724,7 +1730,7 @@ export async function startAndRunWorkflow(args: {
1724
1730
  return { outcome: "suspended" };
1725
1731
  }
1726
1732
 
1727
- await args.handlerCtx.unsafeAppendEvent({
1733
+ await args.handlerCtx.events.unsafeAppend({
1728
1734
  aggregateId: args.runId,
1729
1735
  aggregateType: WORKFLOW_AGGREGATE_TYPE,
1730
1736
  type: WORKFLOW_RUN_COMPLETED_TYPE,
@@ -19,7 +19,7 @@
19
19
  | `chat-channels` | Chat channels. Delivery notifications to Slack, minus the browser tab. | `examples/chat-channels.md` |
20
20
  | `compliance-profiles-demo` | Two-tenant demo: EU + Swiss compliance profiles deliver different authority contacts, languages, and grace periods through the same App-code. | `examples/compliance-profiles-demo.md` |
21
21
  | `compose-stacks` | compose*Stack helpers for auth, security, GDPR and SaaS billing, and the runProdApp check that names a stack whose boot option is missing. | `examples/compose-stacks.md` |
22
- | `cross-feature-events` | Feature appends a typed domain event via ctx.appendEvent; a r.multiStreamProjection reacts asynchronously. | `examples/cross-feature-events.md` |
22
+ | `cross-feature-events` | Feature appends a typed domain event via ctx.events.append; a r.multiStreamProjection reacts asynchronously. | `examples/cross-feature-events.md` |
23
23
  | `crypto-shredding-hr` | Crypto-shredding: PII fields encrypted per subject key; forgetting the subject erases the key and every field it protected. | `examples/crypto-shredding-hr.md` |
24
24
  | `currencies-global` | Shared money fields across tenants. Commas still matter. | `examples/currencies-global.md` |
25
25
  | `currencies-per-tenant` | Tenant-scoped money fields. Commas matter. | `examples/currencies-per-tenant.md` |
@@ -34,16 +34,16 @@
34
34
  | `encrypted-tenant-config` | Per-tenant secrets via config-key encryption — Stripe-API-key pattern. | `examples/encrypted-tenant-config.md` |
35
35
  | `env-composition` | Typed app env from the env blocks bundled features register, plus app-level blocks in extend. | `examples/env-composition.md` |
36
36
  | `error-contract` | Typed errors on the wire. With snake_case reasons, because we care. | `examples/error-contract.md` |
37
- | `event-sourcing` | Production-pattern ES sample: r.defineEvent (versioned + migrations) + ctx.appendEvent + r.projection + r.multiStreamProjection + ctx.loadAggregate (asOf) + ctx.archiveStream + ctx.queryProjection. | `examples/event-sourcing.md` |
37
+ | `event-sourcing` | Production-pattern ES sample: r.defineEvent (versioned + migrations) + ctx.events.append + r.projection + r.multiStreamProjection + ctx.events.load (asOf) + ctx.events.archive + ctx.dispatch.queryProjection. | `examples/event-sourcing.md` |
38
38
  | `feature-toggles` | Runtime feature-toggle flip — two toggleable features, one registers a cross-feature hook on the other; disabling either has the documented effect without reboot. | `examples/feature-toggles.md` |
39
39
  | `field-access` | Field-level access control. When entity-level roles aren't granular enough. | `examples/field-access.md` |
40
- | `files-post-processing` | The three ways to generate an image variant: declarative field variants, imperative ctx.derivatives.variant() with region-blur, and the public route behind a default-deny predicate. | `examples/files-post-processing.md` |
40
+ | `files-post-processing` | The three ways to generate an image variant: declarative field variants, imperative ctx.services.derivatives.variant() with region-blur, and the public route behind a default-deny predicate. | `examples/files-post-processing.md` |
41
41
  | `golden-path` | The smallest complete feature: entity, write handler, event, projection, screen and an integration test. | `examples/golden-path.md` |
42
42
  | `host-routing` | createHostRoutingFeature + createHostDispatch — tenant per subdomain, per-host HTML and CSP, locale redirect, shared by runProdApp and the dev server. | `examples/host-routing.md` |
43
43
  | `i18n` | Feature-scoped translations. 'Hallo' and 'Hello' in the same app. | `examples/i18n.md` |
44
44
  | `idempotency` | Same request, same result. Dedupes on request ID. | `examples/idempotency.md` |
45
45
  | `inbound-mail-triage` | Inbound-mail consumer pattern: inbound-mail-foundation + in-memory provider, a worker-lane triage job attached to the ingest handler, verified end-to-end through createAllInOneEntrypoint. | `examples/inbound-mail-triage.md` |
46
- | `lane-routing` | runIn lane-routing: r.job pinned to api/worker deploy-lanes, event-chain via ctx.appendEvent, verified end-to-end through createAllInOneEntrypoint. | `examples/lane-routing.md` |
46
+ | `lane-routing` | runIn lane-routing: r.job pinned to api/worker deploy-lanes, event-chain via ctx.events.append, verified end-to-end through createAllInOneEntrypoint. | `examples/lane-routing.md` |
47
47
  | `ledger-banking` | Bank accounts + transfers on the ledger primitive — balances are pure queries, never stored. | `examples/ledger-banking.md` |
48
48
  | `ledger-invoicing` | Accrual invoicing on the ledger primitive — revenue at invoice time, VAT as a liability, receivable cleared on payment. | `examples/ledger-invoicing.md` |
49
49
  | `legal-pages` | Auto-rendered Impressum + Datenschutzerklärung pages — template-resolver + legal-pages bundled features wired up with anonymousAccess for DACH-compliance. | `examples/legal-pages.md` |
@@ -257,7 +257,7 @@ Category: operations
257
257
 
258
258
  ## file-derivatives
259
259
 
260
- 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.
260
+ 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.
261
261
 
262
262
  Category: storage
263
263
 
@@ -5,7 +5,7 @@ import { createAnonymousUser } from "../engine/system-user.js";
5
5
  import { parseTenantId, SYSTEM_TENANT_ID } from "../engine/types/identifiers.js";
6
6
  import { isSessionRequiredApiPath, TENANT_HEADER_NAME } from "./api-constants.js";
7
7
  import { isForeignCookieOrigin } from "./origin-middleware.js";
8
- import { setRequestIdentity } from "./request-context.js";
8
+ import { setRequestIdentity } from "./request-context-internals.js";
9
9
  import { clearSessionCookies, getSessionCookies, hasDuplicateSessionCookie, } from "./session-cookies.js";
10
10
  const USER_KEY = "pipelineUser";
11
11
  const AUTH_TRANSPORT_KEY = "authTransport";
@@ -1,7 +1,8 @@
1
1
  import * as z from "zod";
2
2
  import { createAnonymousUser } from "../engine/system-user.js";
3
3
  import { SYSTEM_TENANT_ID } from "../engine/types/index.js";
4
- import { toKumikoError, toWriteErrorInfo } from "../errors/index.js";
4
+ import { toKumikoError } from "../errors/to-kumiko-error.js";
5
+ import { toWriteErrorInfo } from "../errors/write-error-info.js";
5
6
  import { Routes } from "./api-constants.js";
6
7
  import { getUser } from "./auth-middleware.js";
7
8
  import { pendingMfaStepResponse } from "./auth-routes-shared.js";
@@ -1,3 +1,5 @@
1
- import type { AccessRule, OwnershipMap, Registry } from "../engine/types/index.ts";
1
+ import type { AccessRule } from "@cosmicdrift/kumiko-types/handlers";
2
+ import type { OwnershipMap } from "@cosmicdrift/kumiko-types/ownership";
3
+ import type { Registry } from "../engine/types/index.ts";
2
4
  export declare function collectEntityReadAccess(registry: Registry): ReadonlyMap<string, readonly AccessRule[]>;
3
5
  export declare function collectEntityRowReadMaps(registry: Registry): ReadonlyMap<string, OwnershipMap>;
@@ -1,4 +1,6 @@
1
- import type { EntityDefinition, ListColumnSpec, SessionUser } from "../../engine/types/index.ts";
1
+ import type { EntityDefinition } from "@cosmicdrift/kumiko-types/fields";
2
+ import type { ListColumnSpec } from "@cosmicdrift/kumiko-types/screen";
3
+ import type { SessionUser } from "../../engine/types/index.ts";
2
4
  import type { ReferenceCellKind } from "./export-cells-reference.ts";
3
5
  export type SimpleCellKind = "text" | "number" | "decimal" | "bigInt" | "money" | "date" | "timestamp" | "locatedTimestamp" | "boolean" | "auto";
4
6
  export type ExportCellKind = {