@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
@@ -1,13 +1,13 @@
1
+ import { afterAll, beforeAll, describe, expect, it, mock } from "bun:test";
1
2
  import { mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
2
3
  import { join } from "node:path";
3
- import { afterAll, beforeAll, describe, expect, it, vi } from "vitest";
4
4
 
5
5
  // Bun.Glob is only used by scanForCandidates / runCodemod, not by
6
6
  // analyzeFile or convertFile. Those higher-level functions are tested
7
7
  // in the integration suite; unit tests here focus on file-level
8
8
  // operations which don't need Glob. A stub class prevents import
9
- // errors in vitest (which runs on Node, not Bun).
10
- vi.mock("bun", () => {
9
+ // errors in bun (which runs on Node, not Bun).
10
+ mock.module("bun", () => {
11
11
  class StubGlob {
12
12
  scanSync(): never {
13
13
  throw new Error("Bun.Glob is not available in unit-test mode");
@@ -1,4 +1,4 @@
1
- import { describe, expect, expectTypeOf, test } from "vitest";
1
+ import { describe, expect, expectTypeOf, test } from "bun:test";
2
2
  import {
3
3
  access,
4
4
  createSystemConfig,
@@ -1,4 +1,4 @@
1
- import { describe, expect, it } from "vitest";
1
+ import { describe, expect, it } from "bun:test";
2
2
  import { computeEffectiveFeatures, type ToggleReader } from "../effective-features";
3
3
  import type { FeatureDefinition, Registry } from "../types";
4
4
 
@@ -1,4 +1,4 @@
1
- import { describe, expect, test } from "vitest";
1
+ import { describe, expect, test } from "bun:test";
2
2
  import { z } from "zod";
3
3
  import { createTestUser } from "../../stack";
4
4
  import { rolesOf } from "../../testing/access-assertions";
@@ -1,4 +1,4 @@
1
- import { describe, expect, test, vi } from "vitest";
1
+ import { describe, expect, mock, test } from "bun:test";
2
2
  import {
3
3
  createEntityExecutor,
4
4
  defineEntityCreateHandler,
@@ -170,7 +170,7 @@ describe("defineProjectionQueryHandler", () => {
170
170
  );
171
171
  const fakeRows = [{ customer: "a", totalCents: 100 }];
172
172
  const ctx = {
173
- queryProjection: vi.fn().mockResolvedValue(fakeRows),
173
+ queryProjection: mock().mockResolvedValue(fakeRows),
174
174
  };
175
175
  const result = await def.handler(
176
176
  // biome-ignore lint/suspicious/noExplicitAny: test shim — handler only touches ctx.queryProjection here.
@@ -191,7 +191,7 @@ describe("defineProjectionQueryHandler", () => {
191
191
  "showcase:projection:customer-revenue",
192
192
  { unsafeAllTenants: true },
193
193
  );
194
- const ctx = { queryProjection: vi.fn().mockResolvedValue([]) };
194
+ const ctx = { queryProjection: mock().mockResolvedValue([]) };
195
195
  await def.handler(
196
196
  // biome-ignore lint/suspicious/noExplicitAny: test shim.
197
197
  { type: "revenue:list", user: {} as any, payload: {} },
@@ -1,4 +1,4 @@
1
- import { describe, expect, test, vi } from "vitest";
1
+ import { describe, expect, mock, test } from "bun:test";
2
2
  import { z } from "zod";
3
3
  import { emitEvent, typedPayload } from "../event-helpers";
4
4
  import type { EventDef } from "../types/handlers";
@@ -11,7 +11,7 @@ describe("emitEvent", () => {
11
11
  };
12
12
 
13
13
  test("delegates to ctx.appendEvent with eventDef.name as the type", async () => {
14
- const ctx = { unsafeAppendEvent: vi.fn().mockResolvedValue(undefined) };
14
+ const ctx = { unsafeAppendEvent: mock().mockResolvedValue(undefined) };
15
15
  await emitEvent(ctx, orderPlaced, {
16
16
  aggregateId: "agg-1",
17
17
  aggregateType: "pubsub-order",
@@ -26,7 +26,7 @@ describe("emitEvent", () => {
26
26
  });
27
27
 
28
28
  test("payload type is inferred from the eventDef — wrong shape is a compile error", async () => {
29
- const ctx = { unsafeAppendEvent: vi.fn().mockResolvedValue(undefined) };
29
+ const ctx = { unsafeAppendEvent: mock().mockResolvedValue(undefined) };
30
30
  // Runtime check: compile-time narrowing is the real win, but we also
31
31
  // make sure the value flows through unchanged.
32
32
  await emitEvent(ctx, orderPlaced, {
@@ -1,4 +1,4 @@
1
- import { describe, expect, test, vi } from "vitest";
1
+ import { describe, expect, mock, test } from "bun:test";
2
2
  import { z } from "zod";
3
3
  import { createEntity, createRegistry, createTextField, defineFeature } from "../index";
4
4
 
@@ -24,7 +24,7 @@ describe("extendsRegistrar", () => {
24
24
  });
25
25
 
26
26
  test("registry calls onRegister for each extension usage", () => {
27
- const onRegister = vi.fn();
27
+ const onRegister = mock();
28
28
 
29
29
  const ext = defineFeature("tags", (r) => {
30
30
  r.extendsRegistrar("tags", { onRegister });
@@ -99,7 +99,7 @@ describe("extendsRegistrar", () => {
99
99
  });
100
100
 
101
101
  test("extension preSave hooks fire for entity-scoped handlers", () => {
102
- const preSaveFn = vi.fn(async (changes: Record<string, unknown>) => changes);
102
+ const preSaveFn = mock(async (changes: Record<string, unknown>) => changes);
103
103
 
104
104
  const ext = defineFeature("audit", (r) => {
105
105
  r.extendsRegistrar("audited", {
@@ -137,7 +137,7 @@ describe("extendsRegistrar", () => {
137
137
  });
138
138
 
139
139
  test("extension postSave hooks are entity hooks", () => {
140
- const postSaveFn = vi.fn(async () => {});
140
+ const postSaveFn = mock(async () => {});
141
141
 
142
142
  const ext = defineFeature("audit", (r) => {
143
143
  r.extendsRegistrar("audited", {
@@ -8,7 +8,7 @@
8
8
  // source-code / markdown / blog-posts — explicitly NOT sortable /
9
9
  // searchable / filterable. Type-level enforcement statt soft-defaults.
10
10
 
11
- import { describe, expect, expectTypeOf, test } from "vitest";
11
+ import { describe, expect, expectTypeOf, test } from "bun:test";
12
12
  import { createLongTextField } from "../factories";
13
13
  import type { LongTextFieldDef } from "../types";
14
14
 
@@ -5,7 +5,7 @@
5
5
  // echte TZ-Konvertierung (Wall-Clock ↔ UTC) testen wir später beim
6
6
  // DB-Wrapper-Schritt.
7
7
 
8
- import { describe, expect, test } from "vitest";
8
+ import { describe, expect, test } from "bun:test";
9
9
  import {
10
10
  createLocatedTimestampField,
11
11
  createTimestampField,
@@ -1,4 +1,4 @@
1
- import { describe, expect, test } from "vitest";
1
+ import { describe, expect, test } from "bun:test";
2
2
  import type { AnyFileFieldDef, FieldDefinition } from "../types";
3
3
  import { isFileField } from "../types";
4
4
 
@@ -1,4 +1,4 @@
1
- import { describe, expect, test } from "vitest";
1
+ import { describe, expect, test } from "bun:test";
2
2
  import { z } from "zod";
3
3
  import { createEntity, createRegistry, defineFeature, HookPhases } from "../index";
4
4
  import type { PostSaveHookFn } from "../types";
@@ -1,4 +1,4 @@
1
- import { describe, expect, test } from "vitest";
1
+ import { describe, expect, test } from "bun:test";
2
2
  import { parseTenantId } from "../types/identifiers";
3
3
 
4
4
  describe("parseTenantId", () => {
@@ -1,4 +1,4 @@
1
- import { describe, expect, test } from "vitest";
1
+ import { describe, expect, test } from "bun:test";
2
2
  import { z } from "zod";
3
3
  import { createEntity, createRegistry, defineFeature } from "../index";
4
4
  import type { PostSaveHookFn, PreDeleteHookFn, PreSaveHookFn, SaveContext } from "../types";
@@ -1,4 +1,4 @@
1
- import { describe, expect, test } from "vitest";
1
+ import { describe, expect, test } from "bun:test";
2
2
  import { validateBoot } from "../boot-validator";
3
3
  import { defineFeature } from "../define-feature";
4
4
  import { createEntity, createTextField } from "../factories";
@@ -1,5 +1,4 @@
1
- import { sql } from "drizzle-orm";
2
- import { describe, expect, test } from "vitest";
1
+ import { describe, expect, test } from "bun:test";
3
2
  import {
4
3
  buildOwnershipClause,
5
4
  from,
@@ -268,14 +267,14 @@ describe("userCanWriteFieldRow() — Straddle-attack prevention", () => {
268
267
  // --- buildOwnershipClause() — SQL WHERE builder ---
269
268
 
270
269
  describe("buildOwnershipClause() — SQL WHERE builder", () => {
271
- // Fake Drizzle table — the builder only needs `table[columnName]` to
272
- // resolve an opaque column reference, and hands it to eq()/inArray().
273
- // We don't assert on the serialized SQL text (dialect-dependent); we
274
- // assert on the diskriminated OwnershipClause return.
275
- const fakeTable = {
276
- teamId: sql.raw("team_id"),
277
- assigneeId: sql.raw("assignee_id"),
278
- tenantId: sql.raw("tenant_id"),
270
+ // Fake table — buildOwnershipClause checks (table[field] !== undefined)
271
+ // and falls back to snake_case mapping for column names. The fixture
272
+ // shape mirrors drizzle's pgTable for the purposes of the assertions
273
+ // here; we don't assert on the serialized SQL text.
274
+ const fakeTable: Record<string, unknown> = {
275
+ teamId: { name: "team_id" },
276
+ assigneeId: { name: "assignee_id" },
277
+ tenantId: { name: "tenant_id" },
279
278
  };
280
279
 
281
280
  test("undefined access map → pass (public entity)", () => {
@@ -372,7 +371,7 @@ describe("buildOwnershipClause() — SQL WHERE builder", () => {
372
371
  test("where-rule escape hatch: caller's SQL passed through", () => {
373
372
  const user = mkUser({ roles: ["Auditor"] });
374
373
  const map: OwnershipMap = {
375
- Auditor: { kind: "where", where: () => sql`custom_expr_42 = 1` },
374
+ Auditor: { kind: "where", where: () => ({ sqlText: "custom_expr_42 = 1", params: [] }) },
376
375
  };
377
376
  const clause = buildOwnershipClause(user, map, fakeTable);
378
377
  expect(clause.kind).toBe("sql");
@@ -1,4 +1,4 @@
1
- import { describe, expect, test } from "vitest";
1
+ import { describe, expect, test } from "bun:test";
2
2
  import { parseRefTarget } from "../parse-ref-target";
3
3
 
4
4
  // Tier 2.7e Cross-Feature: parser-Konvention für ReferenceFieldDef.
@@ -3,8 +3,8 @@
3
3
  // Sub-step-builders (branch, forEach) live in pipeline-sub-pipelines.test.ts;
4
4
  // boot-validator in validate-projection-allowlist.test.ts.
5
5
 
6
+ import { describe, expect, it } from "bun:test";
6
7
  import { randomUUID } from "node:crypto";
7
- import { describe, expect, it } from "vitest";
8
8
  import { z } from "zod";
9
9
  import { TestUsers } from "../../stack";
10
10
  import { defineWriteHandler } from "../define-handler";
@@ -43,12 +43,12 @@
43
43
  // Unit-side tests in pipeline-vertical-slice.test.ts cover the same
44
44
  // surface against an empty ctx mock; this file is the real-stack gate.
45
45
 
46
- import { eq } from "drizzle-orm";
47
- import { pgTable, text, timestamp, uuid } from "drizzle-orm/pg-core";
48
- import { afterAll, beforeAll, beforeEach, describe, expect, test } from "vitest";
46
+ import { afterAll, beforeAll, beforeEach, describe, expect, test } from "bun:test";
49
47
  import { z } from "zod";
48
+ import { table, text, timestamp, uuid } from "../../db/dialect";
50
49
  import { createEventStoreExecutor } from "../../db/event-store-executor";
51
- import { buildDrizzleTable } from "../../db/table-builder";
50
+ import { asRawClient, selectMany } from "../../db/query";
51
+ import { buildEntityTable } from "../../db/table-builder";
52
52
  import { eventsTable } from "../../event-store";
53
53
  import {
54
54
  setupTestStack,
@@ -129,7 +129,7 @@ const compoundHandler = defineWriteHandler({
129
129
 
130
130
  // Read-side projection-table for the unsafeProjectionUpsert handler.
131
131
  // Plain pgTable (not r.entity) — it's a read-side log, not an aggregate.
132
- const pipelineDemoLogTable = pgTable("pipeline_demo_log", {
132
+ const pipelineDemoLogTable = table("pipeline_demo_log", {
133
133
  id: uuid("id").primaryKey().defaultRandom(),
134
134
  tenantId: uuid("tenant_id").notNull(),
135
135
  correlationId: text("correlation_id").notNull().unique(),
@@ -172,7 +172,7 @@ const widgetEntity = createEntity({
172
172
  table: "pipeline_widget",
173
173
  fields: { label: createTextField({ required: true }) },
174
174
  });
175
- const widgetTable = buildDrizzleTable("widget", widgetEntity);
175
+ const widgetTable = buildEntityTable("widget", widgetEntity);
176
176
  const widgetExecutor = createEventStoreExecutor(widgetTable, widgetEntity, {
177
177
  entityName: "widget",
178
178
  });
@@ -341,7 +341,7 @@ const lookupHandler = defineWriteHandler({
341
341
  ({ event, r }) => [
342
342
  r.step.read.findOne("widget", {
343
343
  table: widgetTable,
344
- where: () => eq(widgetTable.id, event.payload.id),
344
+ where: () => ({ id: event.payload.id }),
345
345
  }),
346
346
  r.step.return(({ steps }) => {
347
347
  const row = steps["widget"] as { label?: string } | null;
@@ -391,7 +391,7 @@ const purgeLogHandler = defineWriteHandler({
391
391
  perform: pipeline<z.infer<typeof purgeLogSchema>, { ok: true }>(({ event, r }) => [
392
392
  r.step.unsafeProjectionDelete({
393
393
  table: pipelineDemoLogTable,
394
- where: () => eq(pipelineDemoLogTable.correlationId, event.payload.correlationId),
394
+ where: () => ({ correlationId: event.payload.correlationId }),
395
395
  }),
396
396
  r.step.return({ isSuccess: true as const, data: { ok: true } }),
397
397
  ]),
@@ -496,8 +496,9 @@ describe("defineWriteHandler({ perform: pipeline(...) }) — real dispatcher pat
496
496
  // across runs — order-independent assertions are the only kind that
497
497
  // stay green when test-files grow (Memory `feedback_jsdom_lies_*`
498
498
  // analog: order-dependent tests are flaky-in-waiting).
499
- await stack.db.delete(pipelineDemoLogTable);
500
- await stack.db.delete(widgetTable);
499
+ // biome-ignore lint/suspicious/noExplicitAny: test cast
500
+ await asRawClient(stack.db).unsafe(`DELETE FROM "${(pipelineDemoLogTable as any).tableName}"`);
501
+ await asRawClient(stack.db).unsafe(`DELETE FROM "${widgetTable.tableName}"`);
501
502
  });
502
503
 
503
504
  test("HTTP write call goes through dispatcher → pipeline-runner → r.step.return", async () => {
@@ -571,7 +572,7 @@ describe("defineWriteHandler({ perform: pipeline(...) }) — real dispatcher pat
571
572
  );
572
573
  expect(res.status).toBe(200);
573
574
 
574
- const rows = await stack.db.select().from(pipelineDemoLogTable);
575
+ const rows = await selectMany(stack.db, pipelineDemoLogTable);
575
576
  expect(rows).toHaveLength(1);
576
577
  expect(rows[0]).toMatchObject({
577
578
  correlationId: "corr-1",
@@ -592,10 +593,7 @@ describe("defineWriteHandler({ perform: pipeline(...) }) — real dispatcher pat
592
593
  admin,
593
594
  );
594
595
 
595
- const rows = await stack.db
596
- .select()
597
- .from(pipelineDemoLogTable)
598
- .where(eq(pipelineDemoLogTable.correlationId, "corr-2"));
596
+ const rows = await selectMany(stack.db, pipelineDemoLogTable, { correlationId: "corr-2" });
599
597
  expect(rows).toHaveLength(1);
600
598
  expect(rows[0]?.message).toBe("v2 — overwritten");
601
599
  });
@@ -614,7 +612,7 @@ describe("defineWriteHandler({ perform: pipeline(...) }) — real dispatcher pat
614
612
 
615
613
  // Verify the projection-row landed too — the executor's inline
616
614
  // projection writes into the widget table in the same TX.
617
- const rows = await stack.db.select().from(widgetTable);
615
+ const rows = await selectMany(stack.db, widgetTable);
618
616
  expect(rows).toHaveLength(1);
619
617
  expect(rows[0]).toMatchObject({ label: "first widget", id: body.data.id });
620
618
  });
@@ -640,7 +638,7 @@ describe("defineWriteHandler({ perform: pipeline(...) }) — real dispatcher pat
640
638
  expect(updatedBody.data.id).toBe(widgetId);
641
639
 
642
640
  // Projection-row reflects the new label.
643
- const rows = await stack.db.select().from(widgetTable).where(eq(widgetTable.id, widgetId));
641
+ const rows = await selectMany(stack.db, widgetTable, { id: widgetId });
644
642
  expect(rows).toHaveLength(1);
645
643
  expect(rows[0]).toMatchObject({ id: widgetId, label: "after" });
646
644
  });
@@ -658,10 +656,7 @@ describe("defineWriteHandler({ perform: pipeline(...) }) — real dispatcher pat
658
656
  // The aggregate stream should carry both the auto-generated CRUD
659
657
  // event (widget.created) AND the appended annotated event. Direct
660
658
  // event-store query is the simplest assertion.
661
- const events = await stack.db
662
- .select()
663
- .from(eventsTable)
664
- .where(eq(eventsTable.aggregateId, widgetId));
659
+ const events = await selectMany(stack.db, eventsTable, { aggregateId: widgetId });
665
660
  const types = events.map((e) => e["type"]);
666
661
  expect(types).toContain("demo-pipeline:event:annotated");
667
662
  expect(types.length).toBeGreaterThanOrEqual(2); // created + annotated
@@ -679,7 +674,7 @@ describe("defineWriteHandler({ perform: pipeline(...) }) — real dispatcher pat
679
674
  // Capture row-count before — beforeEach doesn't truncate widget,
680
675
  // earlier tests in this run leave rows. We assert "broken did not
681
676
  // add a new row" by comparing before/after.
682
- const before = await stack.db.select().from(widgetTable);
677
+ const before = await selectMany(stack.db, widgetTable);
683
678
 
684
679
  const res = await stack.http.write("demo-pipeline:write:widget:create-broken", {}, admin);
685
680
  expect(res.status).not.toBe(200);
@@ -688,7 +683,7 @@ describe("defineWriteHandler({ perform: pipeline(...) }) — real dispatcher pat
688
683
  expect(body.isSuccess).toBe(false);
689
684
  expect(body.error.code).toBeDefined();
690
685
 
691
- const after = await stack.db.select().from(widgetTable);
686
+ const after = await selectMany(stack.db, widgetTable);
692
687
  expect(after).toHaveLength(before.length);
693
688
  });
694
689
 
@@ -728,7 +723,7 @@ describe("defineWriteHandler({ perform: pipeline(...) }) — real dispatcher pat
728
723
  });
729
724
 
730
725
  test("read.findMany returns the row array (count matches table state)", async () => {
731
- const before = await stack.db.select().from(widgetTable);
726
+ const before = await selectMany(stack.db, widgetTable);
732
727
  const res = await stack.http.write("demo-pipeline:write:widget:list", {}, admin);
733
728
  expect(res.status).toBe(200);
734
729
  const body = (await res.json()) as { isSuccess: true; data: { count: number } };
@@ -739,7 +734,7 @@ describe("defineWriteHandler({ perform: pipeline(...) }) — real dispatcher pat
739
734
  // Seed enough widgets so a limit-1 result is verifiably truncated.
740
735
  await stack.http.write("demo-pipeline:write:widget:create", { label: "limit-test-1" }, admin);
741
736
  await stack.http.write("demo-pipeline:write:widget:create", { label: "limit-test-2" }, admin);
742
- const total = await stack.db.select().from(widgetTable);
737
+ const total = await selectMany(stack.db, widgetTable);
743
738
  expect(total.length).toBeGreaterThanOrEqual(2);
744
739
 
745
740
  const res = await stack.http.write("demo-pipeline:write:widget:list-one", {}, admin);
@@ -750,10 +745,9 @@ describe("defineWriteHandler({ perform: pipeline(...) }) — real dispatcher pat
750
745
 
751
746
  test("unsafeProjectionDelete is a silent no-op when the where-clause matches no rows", async () => {
752
747
  // Precondition: nothing with this correlation-id exists.
753
- const before = await stack.db
754
- .select()
755
- .from(pipelineDemoLogTable)
756
- .where(eq(pipelineDemoLogTable.correlationId, "no-match-id"));
748
+ const before = await selectMany(stack.db, pipelineDemoLogTable, {
749
+ correlationId: "no-match-id",
750
+ });
757
751
  expect(before).toHaveLength(0);
758
752
 
759
753
  // Purge anyway — drizzle's DELETE-WHERE with no match commits silently.
@@ -774,10 +768,7 @@ describe("defineWriteHandler({ perform: pipeline(...) }) — real dispatcher pat
774
768
  { correlationId: "to-purge", message: "delete-me" },
775
769
  admin,
776
770
  );
777
- const seeded = await stack.db
778
- .select()
779
- .from(pipelineDemoLogTable)
780
- .where(eq(pipelineDemoLogTable.correlationId, "to-purge"));
771
+ const seeded = await selectMany(stack.db, pipelineDemoLogTable, { correlationId: "to-purge" });
781
772
  expect(seeded).toHaveLength(1);
782
773
 
783
774
  const res = await stack.http.write(
@@ -787,10 +778,7 @@ describe("defineWriteHandler({ perform: pipeline(...) }) — real dispatcher pat
787
778
  );
788
779
  expect(res.status).toBe(200);
789
780
 
790
- const after = await stack.db
791
- .select()
792
- .from(pipelineDemoLogTable)
793
- .where(eq(pipelineDemoLogTable.correlationId, "to-purge"));
781
+ const after = await selectMany(stack.db, pipelineDemoLogTable, { correlationId: "to-purge" });
794
782
  expect(after).toHaveLength(0);
795
783
  });
796
784
 
@@ -801,10 +789,9 @@ describe("defineWriteHandler({ perform: pipeline(...) }) — real dispatcher pat
801
789
  admin,
802
790
  );
803
791
  expect(res.status).toBe(200);
804
- const rows = await stack.db
805
- .select()
806
- .from(pipelineDemoLogTable)
807
- .where(eq(pipelineDemoLogTable.correlationId, "branch-truthy"));
792
+ const rows = await selectMany(stack.db, pipelineDemoLogTable, {
793
+ correlationId: "branch-truthy",
794
+ });
808
795
  expect(rows).toHaveLength(1);
809
796
  expect(rows[0]?.message).toBe("real");
810
797
  });
@@ -816,10 +803,9 @@ describe("defineWriteHandler({ perform: pipeline(...) }) — real dispatcher pat
816
803
  admin,
817
804
  );
818
805
  expect(res.status).toBe(200);
819
- const rows = await stack.db
820
- .select()
821
- .from(pipelineDemoLogTable)
822
- .where(eq(pipelineDemoLogTable.correlationId, "branch-falsy"));
806
+ const rows = await selectMany(stack.db, pipelineDemoLogTable, {
807
+ correlationId: "branch-falsy",
808
+ });
823
809
  expect(rows).toHaveLength(0);
824
810
  });
825
811
 
@@ -834,7 +820,7 @@ describe("defineWriteHandler({ perform: pipeline(...) }) — real dispatcher pat
834
820
  const body = (await res.json()) as { isSuccess: true; data: { count: number } };
835
821
  expect(body.data.count).toBe(3);
836
822
 
837
- const rows = await stack.db.select().from(pipelineDemoLogTable);
823
+ const rows = await selectMany(stack.db, pipelineDemoLogTable);
838
824
  const correlationIds = rows.map((r) => r["correlationId"]).sort();
839
825
  expect(correlationIds).toEqual(ids.slice().sort());
840
826
  });
@@ -858,8 +844,8 @@ describe("defineWriteHandler({ perform: pipeline(...) }) — real dispatcher pat
858
844
  // projection-row insert that aggregate.create performed must
859
845
  // disappear with the rollback. Otherwise pipeline-form handlers
860
846
  // silently leak partial state on mid-pipeline failures.
861
- const beforeWidgets = await stack.db.select().from(widgetTable);
862
- const beforeEvents = await stack.db.select().from(eventsTable);
847
+ const beforeWidgets = await selectMany(stack.db, widgetTable);
848
+ const beforeEvents = await selectMany(stack.db, eventsTable);
863
849
 
864
850
  const res = await stack.http.write(
865
851
  "demo-pipeline:write:widget:create-then-throw",
@@ -868,8 +854,8 @@ describe("defineWriteHandler({ perform: pipeline(...) }) — real dispatcher pat
868
854
  );
869
855
  expect(res.status).toBe(500);
870
856
 
871
- const afterWidgets = await stack.db.select().from(widgetTable);
872
- const afterEvents = await stack.db.select().from(eventsTable);
857
+ const afterWidgets = await selectMany(stack.db, widgetTable);
858
+ const afterEvents = await selectMany(stack.db, eventsTable);
873
859
  expect(afterWidgets.length).toBe(beforeWidgets.length);
874
860
  expect(afterEvents.length).toBe(beforeEvents.length);
875
861
  });
@@ -879,7 +865,7 @@ describe("defineWriteHandler({ perform: pipeline(...) }) — real dispatcher pat
879
865
  // its own scope save/restore + sub-step-list runner. A regression
880
866
  // there would let iteration-1's aggregate.create commit while
881
867
  // iteration-2's throw aborts the rest, leaving partial state.
882
- const beforeWidgets = await stack.db.select().from(widgetTable);
868
+ const beforeWidgets = await selectMany(stack.db, widgetTable);
883
869
 
884
870
  const res = await stack.http.write(
885
871
  "demo-pipeline:write:widget:foreach-then-throw",
@@ -888,7 +874,7 @@ describe("defineWriteHandler({ perform: pipeline(...) }) — real dispatcher pat
888
874
  );
889
875
  expect(res.status).toBe(500);
890
876
 
891
- const afterWidgets = await stack.db.select().from(widgetTable);
877
+ const afterWidgets = await selectMany(stack.db, widgetTable);
892
878
  expect(afterWidgets.length).toBe(beforeWidgets.length);
893
879
  });
894
880
  });
@@ -13,7 +13,7 @@
13
13
  // every step inside a pipeline-form handler would be untraceable —
14
14
  // and we wouldn't notice until a prod incident lacks the breadcrumbs.
15
15
 
16
- import { afterAll, beforeAll, beforeEach, describe, expect, test } from "vitest";
16
+ import { afterAll, beforeAll, beforeEach, describe, expect, test } from "bun:test";
17
17
  import { z } from "zod";
18
18
  import { setupTestStack, type TestStack, TestUsers, unsafeCreateEntityTable } from "../../stack";
19
19
  import { createRecordingProvider, type RecordingProvider } from "../../testing";
@@ -22,7 +22,7 @@
22
22
  // gate; if a future regression suspect needs that breakdown, extend
23
23
  // here with a longer-pipeline handler variant.
24
24
 
25
- import { afterAll, beforeAll, beforeEach, describe, expect, test } from "vitest";
25
+ import { afterAll, beforeAll, beforeEach, describe, expect, test } from "bun:test";
26
26
  import { z } from "zod";
27
27
  import { setupTestStack, type TestStack, TestUsers, unsafeCreateEntityTable } from "../../stack";
28
28
  import { defineFeature } from "../define-feature";
@@ -5,7 +5,7 @@
5
5
  // to steps/_no-return-guard.ts). Tests cover happy paths, scope
6
6
  // hygiene, error-propagation and build-time guards.
7
7
 
8
- import { describe, expect, it } from "vitest";
8
+ import { describe, expect, it } from "bun:test";
9
9
  import { z } from "zod";
10
10
  import { TestUsers } from "../../stack";
11
11
  import { defineWriteHandler } from "../define-handler";
@@ -1,4 +1,4 @@
1
- import { describe, expect, test } from "vitest";
1
+ import { describe, expect, test } from "bun:test";
2
2
  import { z } from "zod";
3
3
  import { createEntity, createRegistry, defineFeature } from "../index";
4
4
  import type { PostQueryHookFn } from "../types";
@@ -1,15 +1,19 @@
1
- import { describe, expect, test, vi } from "vitest";
1
+ import { describe, expect, mock, test } from "bun:test";
2
2
  import type { StoredEvent } from "../../event-store/event-store";
3
3
  import { setFields } from "../projection-helpers";
4
4
  import type { ProjectionTable } from "../types/projection";
5
5
 
6
- // Minimal fake table: only the `id` column is needed for setFields, and
7
- // setFields only hands it to `eq()` no actual SQL runs in the unit test.
8
- // The cast mirrors ProjectionTable's deliberate erasure: the framework
9
- // doesn't know user table shapes at compile time, so real Drizzle tables
10
- // go through the same `any`-ish generic parameter.
6
+ // Minimal fake table: only the `id` column is needed for setFields, plus
7
+ // the kumiko:schema:Name + kumiko:schema:Columns symbols that bun-db introspects for
8
+ // table-name + column-mapping. We don't run real SQL — unsafe() is mocked.
11
9
  const fakeIdCol = { name: "id" };
12
- const fakeTable = { id: fakeIdCol, __name: "fake_table" } as unknown as ProjectionTable;
10
+ const fakeTable = Object.assign(
11
+ { id: fakeIdCol },
12
+ {
13
+ [Symbol.for("kumiko:schema:Name")]: "fake_table",
14
+ [Symbol.for("kumiko:schema:Columns")]: { id: fakeIdCol },
15
+ },
16
+ ) as unknown as ProjectionTable;
13
17
 
14
18
  function makeFakeEvent(overrides: Partial<StoredEvent> = {}): StoredEvent {
15
19
  return {
@@ -29,30 +33,34 @@ function makeFakeEvent(overrides: Partial<StoredEvent> = {}): StoredEvent {
29
33
  };
30
34
  }
31
35
 
32
- // Drizzle's tx.update(...).set(...).where(...) chain — capture each step.
36
+ // bun-db path: setFields calls updateMany(tx, table, set, where) which lands
37
+ // on asRawClient(tx).unsafe(sqlText, params). Capture the SQL + params.
33
38
  function makeFakeTx() {
34
- const where = vi.fn().mockResolvedValue(undefined);
35
- const set = vi.fn(() => ({ where }));
36
- const update = vi.fn(() => ({ set }));
37
- return { fakeTx: { update } as never, update, set, where };
39
+ const unsafe = mock(async (_sqlText: string, _params: unknown[]) => [] as unknown[]);
40
+ const fakeTx = { unsafe, begin: mock() } as never;
41
+ return { fakeTx, unsafe };
38
42
  }
39
43
 
40
44
  describe("setFields", () => {
41
45
  test("returns an apply fn that UPDATEs the passed fields WHERE id = aggregateId", async () => {
42
46
  const apply = setFields(fakeTable, { status: "sent" });
43
- const { fakeTx, update, set } = makeFakeTx();
47
+ const { fakeTx, unsafe } = makeFakeTx();
44
48
  await apply(makeFakeEvent(), fakeTx);
45
- expect(update).toHaveBeenCalledWith(fakeTable);
46
- expect(set).toHaveBeenCalledWith({ status: "sent" });
49
+ expect(unsafe).toHaveBeenCalledTimes(1);
50
+ const [sqlText, params] = unsafe.mock.calls[0]!;
51
+ expect(sqlText).toMatch(/UPDATE "fake_table" SET "status" = \$1.*WHERE "id" = \$2/);
52
+ expect(params).toEqual(["sent", "agg-42"]);
47
53
  });
48
54
 
49
55
  test("fields as a function receives the event and returns the field values", async () => {
50
56
  const apply = setFields(fakeTable, (event) => ({
51
57
  status: (event.payload as { newStatus: string }).newStatus,
52
58
  }));
53
- const { fakeTx, set } = makeFakeTx();
59
+ const { fakeTx, unsafe } = makeFakeTx();
54
60
  await apply(makeFakeEvent({ payload: { newStatus: "cancelled" } }), fakeTx);
55
- expect(set).toHaveBeenCalledWith({ status: "cancelled" });
61
+ expect(unsafe).toHaveBeenCalledTimes(1);
62
+ const [, params] = unsafe.mock.calls[0]!;
63
+ expect(params).toEqual(["cancelled", "agg-42"]);
56
64
  });
57
65
 
58
66
  test("throws at construction time when the table has no 'id' column", () => {
@@ -1,5 +1,5 @@
1
- import { integer, pgTable, uuid } from "drizzle-orm/pg-core";
2
- import { describe, expect, test } from "vitest";
1
+ import { describe, expect, test } from "bun:test";
2
+ import { integer, type SchemaTable, table, uuid } from "../../db/dialect";
3
3
  import type { ProjectionDefinition } from "../../engine/types";
4
4
  import { defineFeature } from "../define-feature";
5
5
  import { createEntity, createTextField } from "../factories";
@@ -9,10 +9,10 @@ import { createRegistry } from "../registry";
9
9
  // the projection itself (apply, TX semantics) is covered by the MietNomade
10
10
  // integration suite; this file focuses on the registrar/registry contracts
11
11
  // that fire BEFORE any write happens.
12
- const testTable = pgTable("test_projection", {
12
+ const testTable = table("test_projection", {
13
13
  id: uuid("id").primaryKey(),
14
14
  count: integer("count").notNull().default(0),
15
- });
15
+ }) as unknown as SchemaTable;
16
16
 
17
17
  function exampleEntity(name = "unit") {
18
18
  return createEntity({
@@ -1,4 +1,4 @@
1
- import { describe, expect, test } from "vitest";
1
+ import { describe, expect, test } from "bun:test";
2
2
  import {
3
3
  isKebabSegment,
4
4
  isValidQn,