@cosmicdrift/kumiko-framework 0.13.0 → 0.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (314) hide show
  1. package/package.json +7 -7
  2. package/src/__tests__/{anonymous-access.integration.ts → anonymous-access.integration.test.ts} +12 -9
  3. package/src/__tests__/{error-contract.integration.ts → error-contract.integration.test.ts} +5 -4
  4. package/src/__tests__/{field-access.integration.ts → field-access.integration.test.ts} +3 -3
  5. package/src/__tests__/{full-stack.integration.ts → full-stack.integration.test.ts} +7 -16
  6. package/src/__tests__/{ownership.integration.ts → ownership.integration.test.ts} +3 -2
  7. package/src/__tests__/{raw-table.integration.ts → raw-table.integration.test.ts} +18 -30
  8. package/src/__tests__/{reference-data.integration.ts → reference-data.integration.test.ts} +24 -11
  9. package/src/__tests__/{transition-guard.integration.ts → transition-guard.integration.test.ts} +12 -10
  10. package/src/api/__tests__/api.test.ts +1 -1
  11. package/src/api/__tests__/auth-middleware-transport.test.ts +1 -1
  12. package/src/api/__tests__/auth-routes-cookie.test.ts +1 -1
  13. package/src/api/__tests__/{batch.integration.ts → batch.integration.test.ts} +30 -30
  14. package/src/api/__tests__/body-limit.test.ts +1 -1
  15. package/src/api/__tests__/csrf-middleware.test.ts +1 -1
  16. package/src/api/__tests__/{dispatcher-live.integration.ts → dispatcher-live.integration.test.ts} +10 -9
  17. package/src/api/__tests__/metrics-endpoint.test.ts +1 -1
  18. package/src/api/__tests__/{nested-write.integration.ts → nested-write.integration.test.ts} +13 -16
  19. package/src/api/__tests__/readiness.test.ts +1 -1
  20. package/src/api/__tests__/request-id-middleware.test.ts +1 -1
  21. package/src/api/__tests__/sse-broker.test.ts +12 -12
  22. package/src/api/__tests__/sse-route.test.ts +1 -1
  23. package/src/api/readiness.ts +2 -2
  24. package/src/auth/__tests__/roles.test.ts +2 -2
  25. package/src/bun-db/__tests__/PATTERN.md +73 -0
  26. package/src/bun-db/__tests__/_helpers.ts +103 -0
  27. package/src/bun-db/__tests__/batch-methods.integration.test.ts +143 -0
  28. package/src/bun-db/__tests__/batch-methods.test.ts +20 -0
  29. package/src/bun-db/__tests__/bun-test-db.ts +19 -0
  30. package/src/bun-db/__tests__/bun-test-stack.ts +6 -0
  31. package/src/bun-db/__tests__/column-types.integration.test.ts +132 -0
  32. package/src/bun-db/__tests__/compound-types.integration.test.ts +134 -0
  33. package/src/bun-db/__tests__/jsonb-edge-cases.integration.test.ts +235 -0
  34. package/src/bun-db/__tests__/smoke.integration.test.ts +43 -0
  35. package/src/bun-db/__tests__/sql-methods.integration.test.ts +231 -0
  36. package/src/bun-db/__tests__/where-patterns.integration.test.ts +185 -0
  37. package/src/bun-db/connection.ts +84 -0
  38. package/src/bun-db/index.ts +31 -0
  39. package/src/bun-db/query.ts +845 -0
  40. package/src/compliance/__tests__/duration-spec.test.ts +1 -1
  41. package/src/compliance/__tests__/profiles.test.ts +1 -1
  42. package/src/compliance/__tests__/sub-processors.test.ts +1 -1
  43. package/src/db/__tests__/{apply-entity-event-tenant.integration.ts → apply-entity-event-tenant.integration.test.ts} +13 -11
  44. package/src/db/__tests__/big-int-field.test.ts +15 -14
  45. package/src/db/__tests__/column-ddl.integration.test.ts +113 -0
  46. package/src/db/__tests__/compound-types.test.ts +1 -1
  47. package/src/db/__tests__/{config-seed.integration.ts → config-seed.integration.test.ts} +32 -27
  48. package/src/db/__tests__/connection-options.test.ts +1 -1
  49. package/src/db/__tests__/dialect-instant.test.ts +1 -1
  50. package/src/db/__tests__/encryption.test.ts +1 -1
  51. package/src/db/__tests__/{drizzle-table-types.test.ts → entity-table-types.test.ts} +16 -16
  52. package/src/db/__tests__/{event-store-executor-list.integration.ts → event-store-executor-list.integration.test.ts} +12 -7
  53. package/src/db/__tests__/{event-store-executor.integration.ts → event-store-executor.integration.test.ts} +19 -12
  54. package/src/db/__tests__/{implicit-projection-equivalence.integration.ts → implicit-projection-equivalence.integration.test.ts} +35 -29
  55. package/src/db/__tests__/located-timestamp.test.ts +1 -1
  56. package/src/db/__tests__/money.test.ts +1 -1
  57. package/src/db/__tests__/{multi-row-insert.integration.ts → multi-row-insert.integration.test.ts} +18 -11
  58. package/src/db/__tests__/parse-auto-verb.test.ts +1 -1
  59. package/src/db/__tests__/{required-not-null-migration-safety.integration.ts → required-not-null-migration-safety.integration.test.ts} +28 -24
  60. package/src/db/__tests__/{schema-migration.integration.ts → schema-migration.integration.test.ts} +32 -28
  61. package/src/db/__tests__/sql-inventory.test.ts +56 -0
  62. package/src/db/__tests__/table-builder-indexes.test.ts +30 -11
  63. package/src/db/__tests__/table-builder-required.test.ts +20 -22
  64. package/src/db/__tests__/{tenant-db.integration.ts → tenant-db.integration.test.ts} +106 -144
  65. package/src/db/__tests__/{unique-violation-mapping.integration.ts → unique-violation-mapping.integration.test.ts} +13 -8
  66. package/src/db/api.ts +46 -0
  67. package/src/db/apply-entity-event.ts +45 -36
  68. package/src/db/assert-exists-in.ts +5 -16
  69. package/src/db/bun-provider.ts +37 -0
  70. package/src/db/config-seed.ts +4 -4
  71. package/src/db/connection.ts +14 -57
  72. package/src/db/cursor.ts +5 -56
  73. package/src/db/dialect.ts +472 -99
  74. package/src/db/eagerload.ts +5 -12
  75. package/src/db/entity-table-meta.ts +390 -0
  76. package/src/db/event-store-executor.ts +158 -100
  77. package/src/db/index.ts +33 -5
  78. package/src/db/migrate-generator.ts +350 -0
  79. package/src/db/migrate-runner.ts +206 -0
  80. package/src/db/postgres-provider.ts +25 -0
  81. package/src/db/queries/entity-read.ts +15 -0
  82. package/src/db/queries/es-ops.ts +17 -0
  83. package/src/db/queries/event-consumer.ts +170 -0
  84. package/src/db/queries/event-store-admin.ts +127 -0
  85. package/src/db/queries/event-store.ts +155 -0
  86. package/src/db/queries/projection-rebuild.ts +59 -0
  87. package/src/db/queries/raw-sql.ts +15 -0
  88. package/src/db/queries/schema-drift.ts +35 -0
  89. package/src/db/queries/seed-context.ts +58 -0
  90. package/src/db/queries/table-ops.ts +11 -0
  91. package/src/db/queries/test-stack.ts +56 -0
  92. package/src/db/query-api.ts +22 -0
  93. package/src/db/query.ts +30 -0
  94. package/src/db/reference-data.ts +19 -22
  95. package/src/db/render-ddl.ts +57 -0
  96. package/src/db/row-helpers.ts +3 -52
  97. package/src/db/schema-inspection.ts +17 -4
  98. package/src/db/sql-inventory.ts +208 -0
  99. package/src/db/table-builder.ts +48 -40
  100. package/src/db/tenant-db.ts +105 -326
  101. package/src/engine/__tests__/auth-claims-registrar.test.ts +1 -1
  102. package/src/engine/__tests__/boot-validator-api-exposure.test.ts +3 -3
  103. package/src/engine/__tests__/boot-validator-located-timestamps.test.ts +1 -1
  104. package/src/engine/__tests__/boot-validator-pii-retention.test.ts +5 -5
  105. package/src/engine/__tests__/boot-validator-s0-integration.test.ts +3 -3
  106. package/src/engine/__tests__/boot-validator.test.ts +4 -3
  107. package/src/engine/__tests__/build-app-schema.test.ts +1 -1
  108. package/src/engine/__tests__/build-target.test.ts +1 -1
  109. package/src/engine/__tests__/claim-keys.test.ts +1 -1
  110. package/src/engine/__tests__/codemod-pipeline.test.ts +3 -3
  111. package/src/engine/__tests__/config-helpers.test.ts +1 -1
  112. package/src/engine/__tests__/effective-features.test.ts +1 -1
  113. package/src/engine/__tests__/engine.test.ts +1 -1
  114. package/src/engine/__tests__/entity-handlers.test.ts +3 -3
  115. package/src/engine/__tests__/event-helpers.test.ts +3 -3
  116. package/src/engine/__tests__/extends-registrar.test.ts +4 -4
  117. package/src/engine/__tests__/factories-long-text.test.ts +1 -1
  118. package/src/engine/__tests__/factories-time.test.ts +1 -1
  119. package/src/engine/__tests__/field-predicates.test.ts +1 -1
  120. package/src/engine/__tests__/hook-phases.test.ts +1 -1
  121. package/src/engine/__tests__/identifiers.test.ts +1 -1
  122. package/src/engine/__tests__/lifecycle-hooks.test.ts +1 -1
  123. package/src/engine/__tests__/nav.test.ts +1 -1
  124. package/src/engine/__tests__/ownership.test.ts +10 -11
  125. package/src/engine/__tests__/parse-ref-target.test.ts +1 -1
  126. package/src/engine/__tests__/pipeline-engine.test.ts +1 -1
  127. package/src/engine/__tests__/{pipeline-handler.integration.ts → pipeline-handler.integration.test.ts} +38 -52
  128. package/src/engine/__tests__/{pipeline-observability.integration.ts → pipeline-observability.integration.test.ts} +1 -1
  129. package/src/engine/__tests__/{pipeline-performance.integration.ts → pipeline-performance.integration.test.ts} +1 -1
  130. package/src/engine/__tests__/pipeline-sub-pipelines.test.ts +1 -1
  131. package/src/engine/__tests__/post-query-hook.test.ts +1 -1
  132. package/src/engine/__tests__/projection-helpers.test.ts +25 -17
  133. package/src/engine/__tests__/projection.test.ts +4 -4
  134. package/src/engine/__tests__/qualified-name.test.ts +1 -1
  135. package/src/engine/__tests__/raw-table.test.ts +9 -8
  136. package/src/engine/__tests__/resolve-config-or-param.test.ts +5 -5
  137. package/src/engine/__tests__/run-in.test.ts +1 -1
  138. package/src/engine/__tests__/schema-builder.test.ts +1 -1
  139. package/src/engine/__tests__/screen.test.ts +1 -1
  140. package/src/engine/__tests__/search-payload-extension.test.ts +3 -3
  141. package/src/engine/__tests__/state-machine.test.ts +1 -1
  142. package/src/engine/__tests__/steps-aggregate-append-event.test.ts +7 -7
  143. package/src/engine/__tests__/steps-aggregate-create.test.ts +4 -4
  144. package/src/engine/__tests__/steps-aggregate-update.test.ts +3 -3
  145. package/src/engine/__tests__/steps-call-feature.test.ts +5 -5
  146. package/src/engine/__tests__/steps-mail-send.test.ts +7 -7
  147. package/src/engine/__tests__/steps-read.test.ts +34 -40
  148. package/src/engine/__tests__/steps-resolver-utils.test.ts +6 -6
  149. package/src/engine/__tests__/steps-unsafe-projection-delete.test.ts +24 -19
  150. package/src/engine/__tests__/steps-unsafe-projection-upsert.test.ts +28 -17
  151. package/src/engine/__tests__/steps-webhook-send.test.ts +6 -6
  152. package/src/engine/__tests__/steps-workflow.test.ts +7 -7
  153. package/src/engine/__tests__/system-user.test.ts +1 -1
  154. package/src/engine/__tests__/validate-projection-allowlist.test.ts +4 -5
  155. package/src/engine/__tests__/validation-hooks.test.ts +1 -1
  156. package/src/engine/__tests__/visual-tree-patterns.test.ts +1 -1
  157. package/src/engine/boot-validator/entity-handler.ts +3 -3
  158. package/src/engine/boot-validator/ownership.ts +1 -1
  159. package/src/engine/define-feature.ts +1 -2
  160. package/src/engine/entity-handlers.ts +5 -5
  161. package/src/engine/factories.ts +1 -1
  162. package/src/engine/feature-ast/__tests__/canonical-form.test.ts +1 -1
  163. package/src/engine/feature-ast/__tests__/parse-happy-path.test.ts +1 -1
  164. package/src/engine/feature-ast/__tests__/parse-real-features.test.ts +2 -2
  165. package/src/engine/feature-ast/__tests__/parse.test.ts +1 -1
  166. package/src/engine/feature-ast/__tests__/patch.test.ts +1 -1
  167. package/src/engine/feature-ast/__tests__/patcher.test.ts +1 -1
  168. package/src/engine/feature-ast/__tests__/render-roundtrip.test.ts +1 -1
  169. package/src/engine/feature-ast/__tests__/visual-tree-parse.test.ts +1 -1
  170. package/src/engine/ownership.ts +113 -41
  171. package/src/engine/pattern-library/__tests__/library.test.ts +2 -2
  172. package/src/engine/projection-helpers.ts +2 -11
  173. package/src/engine/registry.ts +2 -2
  174. package/src/engine/steps/read-find-many.ts +13 -13
  175. package/src/engine/steps/read-find-one.ts +7 -9
  176. package/src/engine/steps/unsafe-projection-delete.ts +4 -5
  177. package/src/engine/steps/unsafe-projection-upsert.ts +63 -31
  178. package/src/engine/types/feature.ts +7 -2
  179. package/src/engine/types/fields.ts +4 -5
  180. package/src/engine/types/step.ts +10 -10
  181. package/src/engine/validate-projection-allowlist.ts +23 -3
  182. package/src/entrypoint/__tests__/{entrypoint-job-wiring.integration.ts → entrypoint-job-wiring.integration.test.ts} +4 -3
  183. package/src/entrypoint/__tests__/{split-deploy.integration.ts → split-deploy.integration.test.ts} +4 -3
  184. package/src/env/__tests__/compose-env-schema.test.ts +1 -1
  185. package/src/env/__tests__/dry-run.test.ts +1 -1
  186. package/src/errors/__tests__/classes.test.ts +1 -1
  187. package/src/errors/__tests__/write-failures.test.ts +1 -1
  188. package/src/es-ops/__tests__/{context.integration.ts → context.integration.test.ts} +43 -29
  189. package/src/es-ops/__tests__/{runner.integration.ts → runner.integration.test.ts} +25 -23
  190. package/src/es-ops/__tests__/runner.test.ts +29 -19
  191. package/src/es-ops/context.ts +9 -43
  192. package/src/es-ops/operations-schema.ts +2 -2
  193. package/src/es-ops/runner.ts +12 -26
  194. package/src/event-store/__tests__/{admin-api.integration.ts → admin-api.integration.test.ts} +71 -45
  195. package/src/event-store/__tests__/{event-store.integration.ts → event-store.integration.test.ts} +7 -5
  196. package/src/event-store/__tests__/{get-stream-version-perf.integration.ts → get-stream-version-perf.integration.test.ts} +5 -3
  197. package/src/event-store/__tests__/{perf.integration.ts → perf.integration.test.ts} +24 -16
  198. package/src/event-store/__tests__/{snapshot.integration.ts → snapshot.integration.test.ts} +34 -28
  199. package/src/event-store/__tests__/{upcaster-dead-letter.integration.ts → upcaster-dead-letter.integration.test.ts} +11 -12
  200. package/src/event-store/__tests__/{upcaster.integration.ts → upcaster.integration.test.ts} +19 -32
  201. package/src/event-store/admin-api.ts +55 -83
  202. package/src/event-store/archive.ts +15 -39
  203. package/src/event-store/event-store.ts +92 -86
  204. package/src/event-store/events-schema.ts +2 -1
  205. package/src/event-store/index.ts +1 -0
  206. package/src/event-store/snapshot.ts +26 -24
  207. package/src/event-store/upcaster-dead-letter.ts +19 -18
  208. package/src/files/__tests__/content-disposition.test.ts +1 -1
  209. package/src/files/__tests__/{file-field-pipeline.integration.ts → file-field-pipeline.integration.test.ts} +8 -5
  210. package/src/files/__tests__/file-handle.test.ts +1 -1
  211. package/src/files/__tests__/{files.integration.ts → files.integration.test.ts} +32 -17
  212. package/src/files/__tests__/read-stream.test.ts +1 -1
  213. package/src/files/__tests__/{storage-tracking.integration.ts → storage-tracking.integration.test.ts} +26 -30
  214. package/src/files/__tests__/write-stream.test.ts +1 -1
  215. package/src/files/__tests__/zip-stream.test.ts +1 -1
  216. package/src/files/file-ref-table.ts +2 -2
  217. package/src/files/file-routes.ts +7 -9
  218. package/src/files/storage-tracking.ts +9 -17
  219. package/src/i18n/__tests__/i18n.test.ts +1 -1
  220. package/src/jobs/__tests__/{job-event-trigger.integration.ts → job-event-trigger.integration.test.ts} +6 -3
  221. package/src/jobs/__tests__/{job-multi-trigger.integration.ts → job-multi-trigger.integration.test.ts} +6 -3
  222. package/src/jobs/__tests__/{jobs.integration.ts → jobs.integration.test.ts} +5 -7
  223. package/src/lifecycle/__tests__/{lifecycle-server.integration.ts → lifecycle-server.integration.test.ts} +1 -1
  224. package/src/lifecycle/__tests__/lifecycle.test.ts +6 -6
  225. package/src/lifecycle/__tests__/signal-handlers.test.ts +6 -6
  226. package/src/logging/__tests__/pino-trace-bridge.test.ts +1 -1
  227. package/src/migrations/__tests__/compare-snapshots.test.ts +1 -1
  228. package/src/migrations/__tests__/{detect-drift.integration.ts → detect-drift.integration.test.ts} +34 -26
  229. package/src/migrations/__tests__/{detect-projections-to-rebuild.integration.ts → detect-projections-to-rebuild.integration.test.ts} +1 -1
  230. package/src/migrations/__tests__/rebuild-marker.test.ts +1 -1
  231. package/src/migrations/projection-detection.ts +12 -1
  232. package/src/migrations/schema-drift.ts +7 -23
  233. package/src/observability/__tests__/console-provider.test.ts +1 -1
  234. package/src/observability/__tests__/metric-validator.test.ts +1 -1
  235. package/src/observability/__tests__/noop-provider.test.ts +1 -1
  236. package/src/observability/__tests__/{observability.integration.ts → observability.integration.test.ts} +5 -8
  237. package/src/observability/__tests__/prometheus-meter.test.ts +1 -1
  238. package/src/observability/__tests__/recording-meter.test.ts +1 -1
  239. package/src/observability/__tests__/recording-tracer.test.ts +1 -1
  240. package/src/observability/__tests__/sensitive-filter.test.ts +1 -1
  241. package/src/pipeline/__tests__/{archive-stream.integration.ts → archive-stream.integration.test.ts} +3 -3
  242. package/src/pipeline/__tests__/auth-claims-resolver.test.ts +9 -9
  243. package/src/pipeline/__tests__/{cascade-handler.integration.ts → cascade-handler.integration.test.ts} +18 -15
  244. package/src/pipeline/__tests__/cascade-handler.test.ts +1 -1
  245. package/src/pipeline/__tests__/{causation-chain.integration.ts → causation-chain.integration.test.ts} +12 -13
  246. package/src/pipeline/__tests__/{ctx-bridge.integration.ts → ctx-bridge.integration.test.ts} +12 -11
  247. package/src/pipeline/__tests__/dispatcher.test.ts +2 -2
  248. package/src/pipeline/__tests__/{distributed-lock.integration.ts → distributed-lock.integration.test.ts} +1 -1
  249. package/src/pipeline/__tests__/{domain-events-projections.integration.ts → domain-events-projections.integration.test.ts} +13 -15
  250. package/src/pipeline/__tests__/{event-dedup.integration.ts → event-dedup.integration.test.ts} +1 -1
  251. package/src/pipeline/__tests__/{event-define-event-strict.integration.ts → event-define-event-strict.integration.test.ts} +6 -16
  252. package/src/pipeline/__tests__/{event-dispatcher-lifecycle.integration.ts → event-dispatcher-lifecycle.integration.test.ts} +1 -1
  253. package/src/pipeline/__tests__/{event-dispatcher-multi-instance.integration.ts → event-dispatcher-multi-instance.integration.test.ts} +3 -2
  254. package/src/pipeline/__tests__/{event-dispatcher-pg-listen.integration.ts → event-dispatcher-pg-listen.integration.test.ts} +1 -1
  255. package/src/pipeline/__tests__/{event-dispatcher-recovery.integration.ts → event-dispatcher-recovery.integration.test.ts} +2 -2
  256. package/src/pipeline/__tests__/{event-dispatcher-second-audit.integration.ts → event-dispatcher-second-audit.integration.test.ts} +17 -16
  257. package/src/pipeline/__tests__/event-dispatcher-strict.test.ts +14 -12
  258. package/src/pipeline/__tests__/{event-dispatcher.integration.ts → event-dispatcher.integration.test.ts} +8 -15
  259. package/src/pipeline/__tests__/{event-retention.integration.ts → event-retention.integration.test.ts} +28 -25
  260. package/src/pipeline/__tests__/{fetch-for-writing.integration.ts → fetch-for-writing.integration.test.ts} +6 -6
  261. package/src/pipeline/__tests__/lifecycle-pipeline.test.ts +4 -4
  262. package/src/pipeline/__tests__/{load-aggregate-query.integration.ts → load-aggregate-query.integration.test.ts} +9 -5
  263. package/src/pipeline/__tests__/{msp-error-mode.integration.ts → msp-error-mode.integration.test.ts} +1 -1
  264. package/src/pipeline/__tests__/{msp-multi-hop.integration.ts → msp-multi-hop.integration.test.ts} +9 -8
  265. package/src/pipeline/__tests__/{msp-rebuild.integration.ts → msp-rebuild.integration.test.ts} +47 -55
  266. package/src/pipeline/__tests__/{multi-stream-projection.integration.ts → multi-stream-projection.integration.test.ts} +19 -53
  267. package/src/pipeline/__tests__/{perf-rebuild.integration.ts → perf-rebuild.integration.test.ts} +36 -34
  268. package/src/pipeline/__tests__/{post-query-hook.integration.ts → post-query-hook.integration.test.ts} +1 -1
  269. package/src/pipeline/__tests__/{projection-rebuild.integration.ts → projection-rebuild.integration.test.ts} +21 -30
  270. package/src/pipeline/__tests__/{query-projection.integration.ts → query-projection.integration.test.ts} +6 -5
  271. package/src/pipeline/__tests__/{redis-pipeline.integration.ts → redis-pipeline.integration.test.ts} +3 -1
  272. package/src/pipeline/cascade-handler.ts +13 -21
  273. package/src/pipeline/dispatcher.ts +43 -48
  274. package/src/pipeline/event-consumer-state.ts +11 -2
  275. package/src/pipeline/event-dispatcher.ts +86 -146
  276. package/src/pipeline/event-retention.ts +14 -24
  277. package/src/pipeline/msp-rebuild.ts +54 -78
  278. package/src/pipeline/projection-rebuild.ts +65 -67
  279. package/src/pipeline/projection-state.ts +2 -2
  280. package/src/random/__tests__/generate.test.ts +13 -13
  281. package/src/rate-limit/__tests__/{dispatcher-l3.integration.ts → dispatcher-l3.integration.test.ts} +1 -1
  282. package/src/rate-limit/__tests__/{middleware.integration.ts → middleware.integration.test.ts} +1 -1
  283. package/src/rate-limit/__tests__/{resolver.integration.ts → resolver.integration.test.ts} +1 -1
  284. package/src/redis/__tests__/redis-options.test.ts +1 -1
  285. package/src/search/__tests__/{meilisearch-adapter.integration.ts → meilisearch-adapter.integration.test.ts} +1 -1
  286. package/src/search/__tests__/search-adapter.test.ts +1 -1
  287. package/src/secrets/__tests__/dek-cache.test.ts +1 -3
  288. package/src/secrets/__tests__/env-master-key-provider.test.ts +1 -1
  289. package/src/secrets/__tests__/envelope.test.ts +1 -1
  290. package/src/secrets/__tests__/leak-guard.test.ts +1 -1
  291. package/src/secrets/__tests__/rotation.test.ts +1 -1
  292. package/src/stack/db.ts +25 -48
  293. package/src/stack/push-entity-projection-tables.ts +2 -4
  294. package/src/stack/table-helpers.ts +98 -61
  295. package/src/stack/test-stack.ts +8 -7
  296. package/src/testing/__tests__/db-cleanup.test.ts +40 -0
  297. package/src/testing/__tests__/e2e-generator.test.ts +1 -1
  298. package/src/testing/__tests__/{ensure-entity-table.integration.ts → ensure-entity-table.integration.test.ts} +7 -14
  299. package/src/testing/db-cleanup.ts +44 -0
  300. package/src/testing/expect-error.ts +1 -1
  301. package/src/testing/index.ts +2 -0
  302. package/src/testing/multipart-helper.ts +94 -0
  303. package/src/testing/shared-entities.ts +5 -5
  304. package/src/time/__tests__/polyfill.test.ts +1 -1
  305. package/src/time/__tests__/tz-context.test.ts +1 -1
  306. package/src/utils/__tests__/assert.test.ts +1 -1
  307. package/src/utils/__tests__/env-parse.test.ts +1 -1
  308. package/CHANGELOG.md +0 -472
  309. package/src/db/__tests__/cursor.test.ts +0 -41
  310. package/src/db/__tests__/db-helpers.test.ts +0 -369
  311. package/src/db/__tests__/drizzle-helpers.integration.ts +0 -186
  312. package/src/db/__tests__/row-helpers.test.ts +0 -59
  313. package/src/engine/steps/_drizzle-boundary.ts +0 -19
  314. package/src/files/__tests__/file-field-column.integration.ts +0 -103
@@ -10,10 +10,9 @@
10
10
  // it hits the events-table. Mismatches throw ValidationError.
11
11
  // 3. r.defineEvent returns `{ name: qualifiedName, schema }` — callers
12
12
  // pass `def.name` to ctx.appendEvent without building the qn manually.
13
-
14
- import { eq } from "drizzle-orm";
15
- import { afterEach, beforeAll, describe, expect, test } from "vitest";
13
+ import { afterEach, beforeAll, describe, expect, test } from "bun:test";
16
14
  import { z } from "zod";
15
+ import { selectMany } from "../../db/query";
17
16
  import { defineFeature } from "../../engine";
18
17
  import { eventsTable } from "../../event-store";
19
18
  import {
@@ -146,10 +145,7 @@ describe("E.3 — ctx.appendEvent strict validation", () => {
146
145
  );
147
146
  expect(res.status).toBe(200);
148
147
 
149
- const stored = await stack.db
150
- .select()
151
- .from(eventsTable)
152
- .where(eq(eventsTable.type, welcomeEventName));
148
+ const stored = await selectMany(stack.db, eventsTable, { type: welcomeEventName });
153
149
  expect(stored).toHaveLength(1);
154
150
  expect(stored[0]?.payload).toEqual({ userId, email: "welcome@test.de" });
155
151
  expect(stored[0]?.aggregateType).toBe("user");
@@ -164,7 +160,7 @@ describe("E.3 — ctx.appendEvent strict validation", () => {
164
160
  // Non-Kumiko throw inside a handler → wrapped as InternalError → 500.
165
161
  expect(res.status).toBe(500);
166
162
 
167
- const stored = await stack.db.select().from(eventsTable);
163
+ const stored = await selectMany(stack.db, eventsTable);
168
164
  // TX rolled back: no event landed.
169
165
  expect(stored).toHaveLength(0);
170
166
  });
@@ -175,10 +171,7 @@ describe("E.3 — ctx.appendEvent strict validation", () => {
175
171
  // ValidationError is a first-class Kumiko error → 400.
176
172
  expect(res.status).toBe(400);
177
173
 
178
- const stored = await stack.db
179
- .select()
180
- .from(eventsTable)
181
- .where(eq(eventsTable.type, welcomeEventName));
174
+ const stored = await selectMany(stack.db, eventsTable, { type: welcomeEventName });
182
175
  expect(stored).toHaveLength(0);
183
176
  });
184
177
  });
@@ -193,10 +186,7 @@ describe("E.3 — cross-feature ownership guard", () => {
193
186
  const res = await stack.http.write("emitter:write:emit:foreign-event", { userId }, admin);
194
187
  expect(res.status).toBe(500);
195
188
 
196
- const stored = await stack.db
197
- .select()
198
- .from(eventsTable)
199
- .where(eq(eventsTable.type, foreignEventName));
189
+ const stored = await selectMany(stack.db, eventsTable, { type: foreignEventName });
200
190
  expect(stored).toHaveLength(0);
201
191
  });
202
192
  });
@@ -12,7 +12,7 @@
12
12
  // via payload, not via a wrapped DB handle. Tenant-isolation-via-MSP is
13
13
  // tested in multi-stream-projection.integration.ts.
14
14
 
15
- import { afterEach, beforeAll, describe, expect, test } from "vitest";
15
+ import { afterEach, beforeAll, describe, expect, test } from "bun:test";
16
16
  import { createEventStoreExecutor } from "../../db/event-store-executor";
17
17
  import { createTenantDb, type TenantDb } from "../../db/tenant-db";
18
18
  import { defineFeature } from "../../engine";
@@ -18,8 +18,9 @@
18
18
  // single-instance runs. Any regression in the locking strategy shows up
19
19
  // here first.
20
20
 
21
- import { afterEach, beforeAll, describe, expect, test } from "vitest";
21
+ import { afterEach, beforeAll, describe, expect, test } from "bun:test";
22
22
  import { createEventStoreExecutor } from "../../db/event-store-executor";
23
+ import { insertMany } from "../../db/query";
23
24
  import { createTenantDb, type TenantDb } from "../../db/tenant-db";
24
25
  import { defineFeature } from "../../engine";
25
26
  import { eventsTable, type StoredEvent } from "../../event-store";
@@ -91,7 +92,7 @@ async function bulkSeedWidgetCreated(count: number, namePrefix: string): Promise
91
92
  metadata: { userId: admin.id },
92
93
  createdBy: admin.id,
93
94
  }));
94
- await stack.db.insert(eventsTable).values(rows);
95
+ await insertMany(stack.db, eventsTable, rows);
95
96
  }
96
97
 
97
98
  function buildDispatcherWith(consumers: readonly EventConsumer[]): EventDispatcher {
@@ -11,7 +11,7 @@
11
11
  // 2. The dispatcher starts cleanly when pgClient is wired and stops
12
12
  // without leaking the LISTEN connection.
13
13
 
14
- import { afterAll, beforeAll, describe, expect, test } from "vitest";
14
+ import { afterAll, beforeAll, describe, expect, test } from "bun:test";
15
15
  import { createEventStoreExecutor } from "../../db/event-store-executor";
16
16
  import { createTenantDb, type TenantDb } from "../../db/tenant-db";
17
17
  import { defineFeature } from "../../engine";
@@ -14,7 +14,7 @@
14
14
  // will never succeed (broken payload, removed code).
15
15
  // (list/status are read-only; covered by event-dispatcher wiring tests.)
16
16
 
17
- import { afterEach, beforeAll, describe, expect, test } from "vitest";
17
+ import { afterEach, beforeAll, describe, expect, test } from "bun:test";
18
18
  import { createEventStoreExecutor } from "../../db/event-store-executor";
19
19
  import { createTenantDb, type TenantDb } from "../../db/tenant-db";
20
20
  import { defineFeature } from "../../engine";
@@ -110,7 +110,7 @@ describe("E.9 — restartConsumer", () => {
110
110
  expect(after.attempts).toBe(0);
111
111
  expect(after.lastError).toBeNull();
112
112
  // Cursor unchanged — next pass retries the SAME failing event.
113
- expect(after.lastProcessedEventId).toBe(cursorBefore);
113
+ expect(after.lastProcessedEventId).toBe(cursorBefore!);
114
114
 
115
115
  // Retry still poisoned (handler still throws) — attempts climbs again.
116
116
  await stack.eventDispatcher?.runOnce();
@@ -14,8 +14,8 @@
14
14
  // moment delivery latency regresses from TCP-round-trip to
15
15
  // pollIntervalMs.
16
16
 
17
- import { eq, sql } from "drizzle-orm";
18
- import { afterEach, beforeAll, describe, expect, test } from "vitest";
17
+ import { afterEach, beforeAll, describe, expect, test } from "bun:test";
18
+ import { asRawClient, insertOne, selectMany, updateMany } from "../../db/query";
19
19
  import { defineFeature } from "../../engine";
20
20
  import { eventsTable } from "../../event-store";
21
21
  import {
@@ -70,7 +70,7 @@ afterEach(async () => {
70
70
  });
71
71
 
72
72
  async function seedOldWidgetEvent(createdAt: Temporal.Instant): Promise<void> {
73
- await stack.db.insert(eventsTable).values({
73
+ await insertOne(stack.db, eventsTable, {
74
74
  aggregateId: generateId(),
75
75
  aggregateType: "widget",
76
76
  tenantId: admin.tenantId,
@@ -94,7 +94,7 @@ describe("Second audit — consumer pre-registration on start()", () => {
94
94
  // every consumer at cursor=0, refuses to prune past them.
95
95
  await stack.eventDispatcher?.start();
96
96
  try {
97
- const rows = await stack.db.select().from(eventConsumerStateTable);
97
+ const rows = await selectMany(stack.db, eventConsumerStateTable);
98
98
  const names = new Set(rows.map((r) => r.name));
99
99
 
100
100
  // The test-stack wires only feature MSP consumers (systemHooks: []),
@@ -138,17 +138,18 @@ describe("Second audit — consumer pre-registration on start()", () => {
138
138
 
139
139
  // Advance the cursor explicitly so we can prove the second start
140
140
  // doesn't clobber it back to 0.
141
- await stack.db
142
- .update(eventConsumerStateTable)
143
- .set({ lastProcessedEventId: 42n })
144
- .where(eq(eventConsumerStateTable.name, "audit:projection:default-scope"));
141
+ await updateMany(
142
+ stack.db,
143
+ eventConsumerStateTable,
144
+ { lastProcessedEventId: 42n },
145
+ { name: "audit:projection:default-scope" },
146
+ );
145
147
 
146
148
  await stack.eventDispatcher?.start();
147
149
  try {
148
- const [row] = await stack.db
149
- .select()
150
- .from(eventConsumerStateTable)
151
- .where(eq(eventConsumerStateTable.name, "audit:projection:default-scope"));
150
+ const [row] = await selectMany(stack.db, eventConsumerStateTable, {
151
+ name: "audit:projection:default-scope",
152
+ });
152
153
  expect(row?.lastProcessedEventId).toBe(42n);
153
154
  } finally {
154
155
  await stack.eventDispatcher?.stop();
@@ -255,13 +256,13 @@ describe("Second audit — LISTEN gauge", () => {
255
256
  // `LISTEN "kumiko_events_new"` and is now idle. pg_terminate_backend
256
257
  // on it closes the TCP; postgres.js's onclose handler re-subscribes
257
258
  // and fires onlisten again.
258
- await recStack.db.execute(
259
- sql`SELECT pg_terminate_backend(pid) FROM pg_stat_activity
259
+ await asRawClient(
260
+ recStack.db,
261
+ ).unsafe(`SELECT pg_terminate_backend(pid) FROM pg_stat_activity
260
262
  WHERE datname = current_database()
261
263
  AND query ILIKE 'listen%'
262
264
  AND state = 'idle'
263
- AND pid <> pg_backend_pid()`,
264
- );
265
+ AND pid <> pg_backend_pid()`);
265
266
 
266
267
  // Wait for the SECOND gauge.set(1) — the reconnect. Generous timeout
267
268
  // because postgres.js's reconnect loop includes backoff.
@@ -8,7 +8,7 @@
8
8
  // Unit-level because the check happens before any DB call — no pgClient,
9
9
  // no event-store schema, no setupTestStack needed.
10
10
 
11
- import { describe, expect, test } from "vitest";
11
+ import { describe, expect, test } from "bun:test";
12
12
  import type { AppContext, Registry } from "../../engine/types";
13
13
  import { createEventDispatcher, type EventConsumer } from "../event-dispatcher";
14
14
 
@@ -35,18 +35,20 @@ describe("event-dispatcher — strict runOnce precondition", () => {
35
35
  test("ensureRegistered() is a valid alternative to start() — runOnce no longer throws", async () => {
36
36
  const consumers: EventConsumer[] = [{ name: "noop", handler: async () => {} }];
37
37
  let insertCalls = 0;
38
+ // bun-db path: dispatcher uses db/queries/ for transition guard + transaction().
39
+ // INSERT/SELECT/UPDATE. Match by SQL substring so we count INSERTs and
40
+ // hand back empty rows for SELECT.
41
+ const unsafe = async (sqlText: string): Promise<unknown[]> => {
42
+ if (/INSERT INTO "kumiko_event_consumers"/.test(sqlText)) {
43
+ insertCalls += 1;
44
+ return [];
45
+ }
46
+ return [];
47
+ };
38
48
  const stubDb = {
39
- insert: () => ({
40
- values: () => ({ onConflictDoNothing: async () => ++insertCalls }),
41
- }),
42
- transaction: async (fn: (tx: unknown) => Promise<unknown>) =>
43
- fn({
44
- select: () => ({
45
- from: () => ({ where: () => ({ for: () => [] }) }),
46
- }),
47
- execute: async () => [],
48
- update: () => ({ set: () => ({ where: () => Promise.resolve() }) }),
49
- }),
49
+ unsafe,
50
+ begin: async (fn: (tx: unknown) => Promise<unknown>) => fn(stubDb),
51
+ transaction: async (fn: (tx: unknown) => Promise<unknown>) => fn(stubDb),
50
52
  };
51
53
  const dispatcher = createEventDispatcher({
52
54
  db: stubDb as never,
@@ -13,14 +13,10 @@
13
13
  // production would take once ops wires CreateApp. No createEventDispatcher
14
14
  // calls in the test — only the registry round-trip.
15
15
 
16
- import { sql } from "drizzle-orm";
17
- import { afterEach, beforeAll, describe, expect, test } from "vitest";
18
- import {
19
- integer as drizzleInteger,
20
- table as drizzlePgTable,
21
- uuid as drizzleUuid,
22
- } from "../../db/dialect";
16
+ import { afterEach, beforeAll, describe, expect, test } from "bun:test";
17
+ import { integer, table as pgTable, uuid } from "../../db/dialect";
23
18
  import { createEventStoreExecutor } from "../../db/event-store-executor";
19
+ import { selectMany } from "../../db/query";
24
20
  import { createTenantDb, type TenantDb } from "../../db/tenant-db";
25
21
  import { defineFeature, type FeatureDefinition } from "../../engine";
26
22
  import type { StoredEvent } from "../../event-store";
@@ -40,10 +36,10 @@ import { sharedWidgetEntity, sharedWidgetTable } from "../../testing";
40
36
  // A tiny state table a subscriber mutates so we can observe "the handler was
41
37
  // called with this event" without relying on in-memory arrays — the state row
42
38
  // survives even if the test framework resets process state.
43
- const subscriberLogTable = drizzlePgTable("read_dispatcher_subscriber_log", {
44
- id: drizzleUuid("id").primaryKey().defaultRandom(),
45
- eventId: drizzleInteger("event_id").notNull(),
46
- eventType: drizzleUuid("event_type"), // unused, kept to avoid another drizzle type import
39
+ const subscriberLogTable = pgTable("read_dispatcher_subscriber_log", {
40
+ id: uuid("id").primaryKey().defaultRandom(),
41
+ eventId: integer("event_id").notNull(),
42
+ eventType: uuid("event_type"), // unused, kept to avoid another drizzle type import
47
43
  });
48
44
 
49
45
  // Per-test capture. The subscriber handlers push here; beforeEach resets.
@@ -195,10 +191,7 @@ describe("event-dispatcher — isolation between consumers", () => {
195
191
  // the per-consumer transaction boundary holds.
196
192
  // Pre-registered state rows exist from boot (strict Sprint-E mode) — at
197
193
  // this point they're at cursor=0 / status=idle for both observers.
198
- const state = await stack.db
199
- .select()
200
- .from(eventConsumerStateTable)
201
- .where(sql`${eventConsumerStateTable.name} = ${qnA}`);
194
+ const state = await selectMany(stack.db, eventConsumerStateTable, { name: qnA });
202
195
  expect(state).toHaveLength(1);
203
196
  expect(state[0]?.lastProcessedEventId).toBe(0n);
204
197
 
@@ -10,9 +10,9 @@
10
10
  // 4. olderThanDays / olderThan convenience: both resolve to the same
11
11
  // cutoff semantics (createdAt < cutoff).
12
12
 
13
- import { eq, sql } from "drizzle-orm";
14
- import { afterEach, beforeAll, describe, expect, test } from "vitest";
13
+ import { afterEach, beforeAll, describe, expect, test } from "bun:test";
15
14
  import { createEventStoreExecutor } from "../../db/event-store-executor";
15
+ import { asRawClient, insertOne, selectMany, updateMany } from "../../db/query";
16
16
  import { createTenantDb, type TenantDb } from "../../db/tenant-db";
17
17
  import { defineFeature } from "../../engine";
18
18
  import { eventsTable } from "../../event-store";
@@ -77,20 +77,17 @@ async function seedOldAggregateEvent(
77
77
  type: string,
78
78
  aggregateType = "widget",
79
79
  ): Promise<bigint> {
80
- const [row] = await stack.db
81
- .insert(eventsTable)
82
- .values({
83
- aggregateId: generateId(),
84
- aggregateType,
85
- tenantId: admin.tenantId,
86
- version: 1,
87
- type,
88
- payload: {},
89
- metadata: { userId: admin.id },
90
- createdAt,
91
- createdBy: admin.id,
92
- })
93
- .returning({ id: eventsTable.id });
80
+ const row = await insertOne<{ id: bigint }>(stack.db, eventsTable, {
81
+ aggregateId: generateId(),
82
+ aggregateType,
83
+ tenantId: admin.tenantId,
84
+ version: 1,
85
+ type,
86
+ payload: {},
87
+ metadata: { userId: admin.id },
88
+ createdAt,
89
+ createdBy: admin.id,
90
+ });
94
91
  if (!row) throw new Error("seed failed");
95
92
  return row.id;
96
93
  }
@@ -121,7 +118,7 @@ describe("E.2 — explicit-aggregateTypes pruning", () => {
121
118
  expect(result.deletedCount).toBe(1);
122
119
  expect(result.aggregateTypes).toEqual(["obsolete"]);
123
120
 
124
- const remaining = await stack.db.select().from(eventsTable);
121
+ const remaining = await selectMany(stack.db, eventsTable);
125
122
  const ids = remaining.map((r) => r.id);
126
123
  expect(ids).toContain(widgetId);
127
124
  expect(ids).not.toContain(obsoleteId);
@@ -146,7 +143,7 @@ describe("E.2 — explicit-aggregateTypes pruning", () => {
146
143
  });
147
144
  expect(result.deletedCount).toBe(1);
148
145
 
149
- const remaining = await stack.db.select().from(eventsTable);
146
+ const remaining = await selectMany(stack.db, eventsTable);
150
147
  const ids = remaining.map((r) => r.id).sort();
151
148
  expect(ids).toEqual([freshId]);
152
149
  expect(ids.includes(staleId)).toBe(false);
@@ -165,7 +162,7 @@ describe("E.2 — explicit-aggregateTypes pruning", () => {
165
162
  expect(result.deletedCount).toBe(1);
166
163
  expect(result.dryRun).toBe(true);
167
164
 
168
- const remaining = await stack.db.select().from(eventsTable);
165
+ const remaining = await selectMany(stack.db, eventsTable);
169
166
  expect(remaining).toHaveLength(1);
170
167
  });
171
168
  });
@@ -182,13 +179,17 @@ describe("E.2 — consumer-lag guard", () => {
182
179
  // Only let the first one through.
183
180
  await stack.eventDispatcher?.runOnce();
184
181
  // Force cursor to 1 so the guard sees "consumer at 1, max candidate 3".
185
- await stack.db
186
- .update(eventConsumerStateTable)
187
- .set({ lastProcessedEventId: 1n, status: "idle" })
188
- .where(eq(eventConsumerStateTable.name, observerQn));
182
+ await updateMany(
183
+ stack.db,
184
+ eventConsumerStateTable,
185
+ { lastProcessedEventId: 1n, status: "idle" },
186
+ { name: observerQn },
187
+ );
189
188
 
190
189
  // Age all three events past the cutoff.
191
- await stack.db.execute(sql`UPDATE kumiko_events SET created_at = now() - interval '30 days'`);
190
+ await asRawClient(stack.db).unsafe(
191
+ `UPDATE kumiko_events SET created_at = now() - interval '30 days'`,
192
+ );
192
193
 
193
194
  await expect(
194
195
  pruneEvents(stack.db, {
@@ -204,7 +205,9 @@ describe("E.2 — consumer-lag guard", () => {
204
205
  await disableConsumer(stack.db, observerQn);
205
206
 
206
207
  // Cursor is at 1 but consumer is disabled — should be skipped.
207
- await stack.db.execute(sql`UPDATE kumiko_events SET created_at = now() - interval '30 days'`);
208
+ await asRawClient(stack.db).unsafe(
209
+ `UPDATE kumiko_events SET created_at = now() - interval '30 days'`,
210
+ );
208
211
 
209
212
  const result = await pruneEvents(stack.db, {
210
213
  olderThanDays: 7,
@@ -7,11 +7,11 @@
7
7
  // the stream version internally — a sequence of appendOne calls writes
8
8
  // consecutive versions without re-reading the DB.
9
9
 
10
- import { sql } from "drizzle-orm";
11
- import { afterAll, afterEach, beforeAll, describe, expect, test } from "vitest";
10
+ import { afterAll, afterEach, beforeAll, describe, expect, test } from "bun:test";
12
11
  import { z } from "zod";
13
12
  import { createEventStoreExecutor } from "../../db/event-store-executor";
14
- import { buildDrizzleTable } from "../../db/table-builder";
13
+ import { asRawClient } from "../../db/query-api";
14
+ import { buildEntityTable } from "../../db/table-builder";
15
15
  import { createEntity, createTextField, defineFeature } from "../../engine";
16
16
  import { UnprocessableError, writeFailure } from "../../errors";
17
17
  import { loadAggregate } from "../../event-store";
@@ -26,7 +26,7 @@ const cartEntity = createEntity({
26
26
  },
27
27
  });
28
28
 
29
- const cartTable = buildDrizzleTable("f4wCart", cartEntity);
29
+ const cartTable = buildEntityTable("f4wCart", cartEntity);
30
30
 
31
31
  const cartFeature = defineFeature("f4w", (r) => {
32
32
  r.entity("f4wCart", cartEntity);
@@ -144,8 +144,8 @@ afterAll(async () => {
144
144
  });
145
145
 
146
146
  afterEach(async () => {
147
- await stack.db.execute(
148
- sql`TRUNCATE kumiko_events, read_f4w_carts, kumiko_event_consumers RESTART IDENTITY CASCADE`,
147
+ await asRawClient(stack.db).unsafe(
148
+ `TRUNCATE kumiko_events, read_f4w_carts, kumiko_event_consumers RESTART IDENTITY CASCADE`,
149
149
  );
150
150
  await stack.eventDispatcher?.ensureRegistered();
151
151
  });
@@ -1,4 +1,4 @@
1
- import { describe, expect, test, vi } from "vitest";
1
+ import { describe, expect, spyOn, test } from "bun:test";
2
2
  import { z } from "zod";
3
3
  import {
4
4
  createEntity,
@@ -200,7 +200,7 @@ describe("runPostSave", () => {
200
200
 
201
201
  test("postSave errors don't throw — logged and continued", async () => {
202
202
  const calls: string[] = [];
203
- const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => {});
203
+ const consoleSpy = spyOn(console, "error").mockImplementation(() => {});
204
204
 
205
205
  const registry = makeRegistry({
206
206
  postSave: [
@@ -234,7 +234,7 @@ describe("runPostSave", () => {
234
234
 
235
235
  test("system hook failure doesn't block other system hooks", async () => {
236
236
  const calls: string[] = [];
237
- const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => {});
237
+ const consoleSpy = spyOn(console, "error").mockImplementation(() => {});
238
238
 
239
239
  const registry = makeRegistry();
240
240
 
@@ -334,7 +334,7 @@ describe("runPostSave phase routing", () => {
334
334
  });
335
335
 
336
336
  test("afterCommit phase: hook errors are logged, never thrown", async () => {
337
- const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => {});
337
+ const consoleSpy = spyOn(console, "error").mockImplementation(() => {});
338
338
  const afterRan: string[] = [];
339
339
  const feature = defineFeature("phases", (r) => {
340
340
  r.entity("user", createEntity({ table: "Users", fields: {} }));
@@ -5,11 +5,15 @@
5
5
  // returned events into whatever domain-state shape the feature wants.
6
6
  // Events are upcasted by the dispatcher, so the reducer sees the current
7
7
  // payload shape even for old v1 events.
8
+ //
9
+ // Bun.SQL-only setup. KEIN postgres-js, KEIN setupTestStack.
8
10
 
9
- import { afterAll, afterEach, beforeAll, describe, expect, test } from "vitest";
11
+ import { afterAll, afterEach, beforeAll, describe, expect, test } from "bun:test";
10
12
  import { z } from "zod";
13
+ import type { DbConnection, DbTx } from "../../db/connection";
11
14
  import { createEventStoreExecutor } from "../../db/event-store-executor";
12
- import { buildDrizzleTable } from "../../db/table-builder";
15
+ import { insertOne } from "../../db/query";
16
+ import { buildEntityTable } from "../../db/table-builder";
13
17
  import { createEntity, createTextField, defineFeature } from "../../engine";
14
18
  import { append, loadAggregate as loadAggregateRaw } from "../../event-store";
15
19
  import {
@@ -29,7 +33,7 @@ const invoiceEntity = createEntity({
29
33
  status: createTextField({ required: true }),
30
34
  },
31
35
  });
32
- const invoiceTable = buildDrizzleTable("asof-invoice", invoiceEntity);
36
+ const invoiceTable = buildEntityTable("asof-invoice", invoiceEntity);
33
37
 
34
38
  // --- Feature ---
35
39
 
@@ -214,8 +218,8 @@ describe("ctx.loadAggregate via queryHandler — Marten AggregateStreamAsync equ
214
218
  // against v2 (integer cents) — without upcasting it would blow up or
215
219
  // produce garbage.
216
220
  const invoiceId = "00000000-0000-4000-8000-000000000042";
217
- await stack.db.transaction(async (tx) => {
218
- await tx.insert(invoiceTable).values({
221
+ await (stack.db as DbConnection).begin(async (tx: DbTx) => {
222
+ await insertOne(tx, invoiceTable, {
219
223
  id: invoiceId,
220
224
  tenantId: admin.tenantId,
221
225
  customer: "LegacyCo",
@@ -9,7 +9,7 @@
9
9
  // error on the skip counter, advances the cursor, and keeps delivering. The
10
10
  // consumer stays "idle".
11
11
 
12
- import { afterAll, afterEach, beforeAll, describe, expect, test } from "vitest";
12
+ import { afterAll, afterEach, beforeAll, describe, expect, test } from "bun:test";
13
13
  import { createEventStoreExecutor } from "../../db/event-store-executor";
14
14
  import { createTenantDb, type TenantDb } from "../../db/tenant-db";
15
15
  import { defineFeature } from "../../engine";
@@ -10,10 +10,11 @@
10
10
  // a three-hop causal chain (order.placed → order.confirmed → order.shipped).
11
11
  // 5. ctx.loadAggregate reads the triggering stream's full history.
12
12
 
13
- import { afterAll, afterEach, beforeAll, describe, expect, test } from "vitest";
13
+ import { afterAll, afterEach, beforeAll, describe, expect, test } from "bun:test";
14
14
  import { z } from "zod";
15
15
  import { createEventStoreExecutor } from "../../db/event-store-executor";
16
- import { buildDrizzleTable } from "../../db/table-builder";
16
+ import { selectMany } from "../../db/query";
17
+ import { buildEntityTable } from "../../db/table-builder";
17
18
  import { createEntity, createTextField, defineFeature } from "../../engine";
18
19
  import { eventsTable } from "../../event-store";
19
20
  import {
@@ -33,7 +34,7 @@ const orderEntity = createEntity({
33
34
  },
34
35
  });
35
36
 
36
- const orderTable = buildDrizzleTable("mmh-order", orderEntity);
37
+ const orderTable = buildEntityTable("mmh-order", orderEntity);
37
38
 
38
39
  // Snapshot what each MSP-apply observed via ctx.loadAggregate.
39
40
  const confirmLoadCounts: number[] = [];
@@ -132,7 +133,7 @@ async function postWrite(correlationId: string, item: string) {
132
133
  async function drainUntilShipped(aggregateId: string, maxPasses = 10): Promise<void> {
133
134
  for (let i = 0; i < maxPasses; i++) {
134
135
  await stack.eventDispatcher?.runOnce();
135
- const rows = await stack.db.select().from(eventsTable);
136
+ const rows = await selectMany(stack.db, eventsTable);
136
137
  if (rows.some((r) => r.aggregateId === aggregateId && r.type === "mmh:event:shipped")) return;
137
138
  }
138
139
  throw new Error(`drainUntilShipped: never saw shipped event for ${aggregateId}`);
@@ -147,7 +148,7 @@ describe("Runde 3 / C.2b — MSP-apply ctx cascades", () => {
147
148
 
148
149
  await stack.eventDispatcher?.runOnce();
149
150
 
150
- const rows = await stack.db.select().from(eventsTable);
151
+ const rows = await selectMany(stack.db, eventsTable);
151
152
  const types = rows.map((r) => r.type).sort();
152
153
  // Order: CRUD create, placed, confirmed (hop 1 fired).
153
154
  expect(types).toContain("mmh-order.created");
@@ -160,7 +161,7 @@ describe("Runde 3 / C.2b — MSP-apply ctx cascades", () => {
160
161
 
161
162
  // Find the aggregateId from the first placed event.
162
163
  await stack.eventDispatcher?.runOnce();
163
- const placedRow = (await stack.db.select().from(eventsTable)).find(
164
+ const placedRow = (await selectMany(stack.db, eventsTable)).find(
164
165
  (r) => r.type === "mmh:event:placed",
165
166
  );
166
167
  expect(placedRow).toBeDefined();
@@ -168,7 +169,7 @@ describe("Runde 3 / C.2b — MSP-apply ctx cascades", () => {
168
169
 
169
170
  await drainUntilShipped(aggregateId);
170
171
 
171
- const rows = (await stack.db.select().from(eventsTable))
172
+ const rows = (await selectMany(stack.db, eventsTable))
172
173
  .filter((r) => r.aggregateId === aggregateId)
173
174
  .sort((a, b) => Number(a.id - b.id));
174
175
 
@@ -220,7 +221,7 @@ describe("Runde 3 / C.2b — MSP-apply ctx cascades", () => {
220
221
  await stack.eventDispatcher?.runOnce();
221
222
 
222
223
  // Every event written on this chain belongs to the admin's tenant.
223
- const rows = await stack.db.select().from(eventsTable);
224
+ const rows = await selectMany(stack.db, eventsTable);
224
225
  for (const row of rows) {
225
226
  expect(row.tenantId).toBe(admin.tenantId);
226
227
  }