@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
@@ -2,16 +2,17 @@
2
2
  // aggregation. Full DB roundtrip (setupTestStack pushes the table → INSERT
3
3
  // / SELECT) lives in src/__tests__/raw-table.integration.ts.
4
4
 
5
- import { pgTable, text } from "drizzle-orm/pg-core";
6
- import { describe, expect, test } from "vitest";
5
+ import { describe, expect, test } from "bun:test";
6
+ import type { SchemaTable } from "../../db/dialect";
7
+ import { table, text } from "../../db/dialect";
7
8
  import { defineFeature } from "../define-feature";
8
9
  import { createRegistry } from "../registry";
9
10
  import type { ProjectionDefinition } from "../types";
10
11
 
11
- const probeTable = pgTable("rt_probe_table", {
12
+ const probeTable = table("rt_probe_table", {
12
13
  id: text("id").primaryKey(),
13
14
  });
14
- const probeTableTwo = pgTable("rt_probe_table_two", {
15
+ const probeTableTwo = table("rt_probe_table_two", {
15
16
  id: text("id").primaryKey(),
16
17
  });
17
18
 
@@ -107,9 +108,9 @@ describe("createRegistry — rawTable aggregation", () => {
107
108
  // when one role writes (primary cache) and a second role reads
108
109
  // (alias view). Push-time dedupe keeps the boot to a single CREATE;
109
110
  // the registry keeps both entries so callers can resolve either name.
110
- const sharedT = pgTable("rt_shared_dedupe", {
111
+ const sharedT = table("rt_shared_dedupe", {
111
112
  id: text("id").primaryKey(),
112
- });
113
+ }) as unknown as SchemaTable;
113
114
  const feat = defineFeature("dedupe", (r) => {
114
115
  r.rawTable("primary", sharedT, { reason: "main writer" });
115
116
  r.rawTable("alias", sharedT, { reason: "alias for read consumers" });
@@ -126,9 +127,9 @@ describe("createRegistry — rawTable aggregation", () => {
126
127
  // r.projection() is almost always an authoring bug — two owners on
127
128
  // the same physical table, one event-sourced, one bypass. Boot
128
129
  // throws so the failure points at the misconfiguration site.
129
- const sharedT = pgTable("rt_collision_phys", {
130
+ const sharedT = table("rt_collision_phys", {
130
131
  id: text("id").primaryKey(),
131
- });
132
+ }) as unknown as SchemaTable;
132
133
  const projection: ProjectionDefinition = {
133
134
  name: "shared-summary",
134
135
  source: "shared",
@@ -1,4 +1,4 @@
1
- import { describe, expect, test, vi } from "vitest";
1
+ import { describe, expect, mock, test } from "bun:test";
2
2
  import { createTenantConfig, createUserConfig } from "../config-helpers";
3
3
  import { type ClampInfo, resolveConfigOrParam } from "../resolve-config-or-param";
4
4
  import type {
@@ -25,7 +25,7 @@ function makeCtx(entries: Record<string, { def: KeyEntry; fallback: unknown }>)
25
25
  getConfigKey: (key: string) => entries[key]?.def,
26
26
  } as unknown as Registry;
27
27
 
28
- const configFn = vi.fn(async <T extends ConfigKeyType>(handle: ConfigKeyHandle<T>) => {
28
+ const configFn = mock(async <T extends ConfigKeyType>(handle: ConfigKeyHandle<T>) => {
29
29
  return entries[handle.name]?.fallback as ConfigValue<T> | undefined;
30
30
  });
31
31
 
@@ -273,14 +273,14 @@ describe("resolveConfigOrParam — onClamp audit hook", () => {
273
273
 
274
274
  test("onClamp does NOT fire when value is within bounds", async () => {
275
275
  const { ctx } = makeCtx({ k: { def: boundedDef, fallback: 10 } });
276
- const onClamp = vi.fn();
276
+ const onClamp = mock();
277
277
  await resolveConfigOrParam(ctx, handleFor("k", "number"), 50, { onClamp });
278
278
  expect(onClamp).not.toHaveBeenCalled();
279
279
  });
280
280
 
281
281
  test("onClamp does NOT fire on exact boundary values", async () => {
282
282
  const { ctx } = makeCtx({ k: { def: boundedDef, fallback: 10 } });
283
- const onClamp = vi.fn();
283
+ const onClamp = mock();
284
284
  await resolveConfigOrParam(ctx, handleFor("k", "number"), 1, { onClamp });
285
285
  await resolveConfigOrParam(ctx, handleFor("k", "number"), 100, { onClamp });
286
286
  expect(onClamp).not.toHaveBeenCalled();
@@ -288,7 +288,7 @@ describe("resolveConfigOrParam — onClamp audit hook", () => {
288
288
 
289
289
  test("onClamp does NOT fire when value is coerced to NaN (no clamp happens, config fallback used)", async () => {
290
290
  const { ctx } = makeCtx({ k: { def: boundedDef, fallback: 10 } });
291
- const onClamp = vi.fn();
291
+ const onClamp = mock();
292
292
  await resolveConfigOrParam(ctx, handleFor("k", "number"), "abc", { onClamp });
293
293
  expect(onClamp).not.toHaveBeenCalled();
294
294
  });
@@ -1,4 +1,4 @@
1
- import { describe, expect, test } from "vitest";
1
+ import { describe, expect, test } from "bun:test";
2
2
  import { runsInLane } from "../run-in";
3
3
 
4
4
  describe("runsInLane", () => {
@@ -1,4 +1,4 @@
1
- import { describe, expect, test } from "vitest";
1
+ import { describe, expect, test } from "bun:test";
2
2
  import {
3
3
  createBooleanField,
4
4
  createDateField,
@@ -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,4 +1,4 @@
1
- import { describe, expect, test } from "vitest";
1
+ import { describe, expect, test } from "bun:test";
2
2
  import { createEntity, createRegistry, defineFeature } from "../index";
3
3
  import type { SearchPayloadContributorFn } from "../types";
4
4
 
@@ -21,7 +21,7 @@ describe("searchPayloadExtension registration", () => {
21
21
  r.searchPayloadExtension(thing, noop);
22
22
  });
23
23
 
24
- const entry = feature.searchPayloadExtensions["thing"];
24
+ const entry = feature.searchPayloadExtensions!["thing"];
25
25
  expect(entry).toHaveLength(1);
26
26
  });
27
27
 
@@ -35,7 +35,7 @@ describe("searchPayloadExtension registration", () => {
35
35
  r.searchPayloadExtension(thing, c2);
36
36
  });
37
37
 
38
- expect(feature.searchPayloadExtensions["thing"]).toHaveLength(2);
38
+ expect(feature.searchPayloadExtensions!["thing"]).toHaveLength(2);
39
39
  });
40
40
  });
41
41
 
@@ -1,4 +1,4 @@
1
- import { describe, expect, test } from "vitest";
1
+ import { describe, expect, test } from "bun:test";
2
2
  import { UnprocessableError } from "../../errors";
3
3
  import { defineTransitions, guardTransition } from "../state-machine";
4
4
 
@@ -1,9 +1,9 @@
1
- import { beforeEach, describe, expect, it, vi } from "vitest";
1
+ import { beforeEach, describe, expect, it, mock } from "bun:test";
2
2
  import { getStep } from "../define-step";
3
3
  import { buildAggregateAppendEventStep } from "../steps/aggregate-append-event";
4
4
  import type { PipelineCtx } from "../types/step";
5
5
 
6
- const mockUnsafeAppendEvent = vi.fn();
6
+ const mockUnsafeAppendEvent = mock();
7
7
 
8
8
  const mockCtx = {
9
9
  unsafeAppendEvent: mockUnsafeAppendEvent,
@@ -39,7 +39,7 @@ describe("buildAggregateAppendEventStep", () => {
39
39
 
40
40
  describe("aggregate.appendEvent run", () => {
41
41
  beforeEach(() => {
42
- vi.clearAllMocks();
42
+ mock.clearAllMocks();
43
43
  });
44
44
 
45
45
  it("calls ctx.unsafeAppendEvent with resolved aggregateId and payload", async () => {
@@ -56,7 +56,7 @@ describe("aggregate.appendEvent run", () => {
56
56
  mockCtx,
57
57
  );
58
58
 
59
- expect(mockUnsafeAppendEvent).toHaveBeenCalledOnce();
59
+ expect(mockUnsafeAppendEvent).toHaveBeenCalledTimes(1);
60
60
  const call = mockUnsafeAppendEvent.mock.calls[0]![0];
61
61
  expect(call).toMatchObject({
62
62
  aggregateId: "abc-123",
@@ -68,9 +68,9 @@ describe("aggregate.appendEvent run", () => {
68
68
 
69
69
  it("resolves function resolvers before calling unsafeAppendEvent", async () => {
70
70
  const stepDef = getStep("aggregate.appendEvent");
71
- const idFn = vi.fn(() => "dynamic-id");
72
- const payloadFn = vi.fn(() => ({ note: "dynamic" }));
73
- const headersFn = vi.fn(() => ({ key: "val" }));
71
+ const idFn = mock(() => "dynamic-id");
72
+ const payloadFn = mock(() => ({ note: "dynamic" }));
73
+ const headersFn = mock(() => ({ key: "val" }));
74
74
 
75
75
  await stepDef!.run(
76
76
  {
@@ -1,10 +1,10 @@
1
- import { beforeEach, describe, expect, it, vi } from "vitest";
1
+ import { beforeEach, describe, expect, it, mock } from "bun:test";
2
2
  import type { EventStoreExecutor } from "../../db/event-store-executor";
3
3
  import { getStep } from "../define-step";
4
4
  import { buildAggregateCreateStep } from "../steps/aggregate-create";
5
5
  import type { PipelineCtx } from "../types/step";
6
6
 
7
- const mockCreate = vi.fn();
7
+ const mockCreate = mock();
8
8
  const mockExecutor = { create: mockCreate } as unknown as EventStoreExecutor & {
9
9
  create: typeof mockCreate;
10
10
  };
@@ -39,7 +39,7 @@ describe("buildAggregateCreateStep", () => {
39
39
 
40
40
  describe("aggregate.create run", () => {
41
41
  beforeEach(() => {
42
- vi.clearAllMocks();
42
+ mock.clearAllMocks();
43
43
  });
44
44
 
45
45
  it("resolves data and calls executor.create with user and db", async () => {
@@ -64,7 +64,7 @@ describe("aggregate.create run", () => {
64
64
 
65
65
  it("resolves a function data resolver before calling executor.create", async () => {
66
66
  const stepDef = getStep("aggregate.create");
67
- const dataFn = vi.fn((ctx: PipelineCtx) => ({
67
+ const dataFn = mock((ctx: PipelineCtx) => ({
68
68
  label: (ctx.event.payload as { label: string }).label,
69
69
  }));
70
70
  mockExecutor.create.mockResolvedValue({
@@ -1,10 +1,10 @@
1
- import { beforeEach, describe, expect, it, vi } from "vitest";
1
+ import { beforeEach, describe, expect, it, mock } from "bun:test";
2
2
  import type { EventStoreExecutor } from "../../db/event-store-executor";
3
3
  import { getStep } from "../define-step";
4
4
  import { buildAggregateUpdateStep } from "../steps/aggregate-update";
5
5
  import type { PipelineCtx } from "../types/step";
6
6
 
7
- const mockUpdate = vi.fn();
7
+ const mockUpdate = mock();
8
8
  const mockExecutor = { update: mockUpdate } as unknown as EventStoreExecutor & {
9
9
  update: typeof mockUpdate;
10
10
  };
@@ -61,7 +61,7 @@ describe("buildAggregateUpdateStep", () => {
61
61
 
62
62
  describe("aggregate.update run", () => {
63
63
  beforeEach(() => {
64
- vi.clearAllMocks();
64
+ mock.clearAllMocks();
65
65
  });
66
66
 
67
67
  it("resolves id, changes, version and calls executor.update", async () => {
@@ -1,10 +1,10 @@
1
- import { beforeEach, describe, expect, it, vi } from "vitest";
1
+ import { beforeEach, describe, expect, it, mock } from "bun:test";
2
2
  import { getStep } from "../define-step";
3
3
  import { buildCallFeatureStep } from "../steps/call-feature";
4
4
  import type { PipelineCtx } from "../types/step";
5
5
 
6
- const mockWrite = vi.fn();
7
- const mockWriteAs = vi.fn();
6
+ const mockWrite = mock();
7
+ const mockWriteAs = mock();
8
8
 
9
9
  const mockCtx = {
10
10
  write: mockWrite,
@@ -37,7 +37,7 @@ describe("buildCallFeatureStep", () => {
37
37
 
38
38
  describe("callFeature run", () => {
39
39
  beforeEach(() => {
40
- vi.clearAllMocks();
40
+ mock.clearAllMocks();
41
41
  });
42
42
 
43
43
  it("calls ctx.write with the resolved payload and handler name", async () => {
@@ -64,7 +64,7 @@ describe("callFeature run", () => {
64
64
 
65
65
  it("resolves a function payload resolver before calling ctx.write", async () => {
66
66
  const stepDef = getStep("callFeature");
67
- const payloadFn = vi.fn((ctx: PipelineCtx) => ({
67
+ const payloadFn = mock((ctx: PipelineCtx) => ({
68
68
  title: (ctx.event.payload as { title: string }).title,
69
69
  }));
70
70
  mockWrite.mockResolvedValue({
@@ -1,4 +1,4 @@
1
- import { beforeEach, describe, expect, it, vi } from "vitest";
1
+ import { beforeEach, describe, expect, it, mock } from "bun:test";
2
2
  import { getStep } from "../define-step";
3
3
  import {
4
4
  STEP_DISPATCH_AGGREGATE_TYPE,
@@ -7,7 +7,7 @@ import {
7
7
  import { buildMailSendStep } from "../steps/mail-send";
8
8
  import type { PipelineCtx } from "../types/step";
9
9
 
10
- const mockUnsafeAppendEvent = vi.fn();
10
+ const mockUnsafeAppendEvent = mock();
11
11
 
12
12
  const mockCtx = {
13
13
  unsafeAppendEvent: mockUnsafeAppendEvent,
@@ -61,7 +61,7 @@ describe("buildMailSendStep", () => {
61
61
 
62
62
  describe("mail.send run", () => {
63
63
  beforeEach(() => {
64
- vi.clearAllMocks();
64
+ mock.clearAllMocks();
65
65
  });
66
66
 
67
67
  it("appends a step.dispatch-requested system event with the mail spec", async () => {
@@ -78,7 +78,7 @@ describe("mail.send run", () => {
78
78
  mockCtx,
79
79
  );
80
80
 
81
- expect(mockUnsafeAppendEvent).toHaveBeenCalledOnce();
81
+ expect(mockUnsafeAppendEvent).toHaveBeenCalledTimes(1);
82
82
  const eventArg = mockUnsafeAppendEvent.mock.calls[0]![0];
83
83
 
84
84
  expect(eventArg.aggregateType).toBe(STEP_DISPATCH_AGGREGATE_TYPE);
@@ -93,9 +93,9 @@ describe("mail.send run", () => {
93
93
 
94
94
  it("resolves function-based resolvers", async () => {
95
95
  const stepDef = getStep("mail.send");
96
- const toFn = vi.fn(() => "resolved@example.com");
97
- const subjectFn = vi.fn(() => "Resolved Subject");
98
- const bodyFn = vi.fn(() => "Resolved Body");
96
+ const toFn = mock(() => "resolved@example.com");
97
+ const subjectFn = mock(() => "Resolved Subject");
98
+ const bodyFn = mock(() => "Resolved Body");
99
99
 
100
100
  await stepDef!.run({ to: toFn, subject: subjectFn, body: bodyFn, mode: "deferred" }, mockCtx);
101
101
 
@@ -1,36 +1,27 @@
1
- import type { SQL } from "drizzle-orm";
2
- import { pgTable, text, uuid } from "drizzle-orm/pg-core";
3
- import { beforeEach, describe, expect, it, vi } from "vitest";
1
+ import { beforeEach, describe, expect, it, mock } from "bun:test";
2
+ import { table, text, uuid } from "../../db/dialect";
4
3
  import { getStep } from "../define-step";
5
4
  import { buildReadFindManyStep } from "../steps/read-find-many";
6
5
  import { buildReadFindOneStep } from "../steps/read-find-one";
7
6
  import type { PipelineCtx } from "../types/step";
8
7
 
9
- const testTable = pgTable("test_read", {
8
+ const testTable = table("test_read", {
10
9
  id: uuid("id").primaryKey().defaultRandom(),
11
10
  tenantId: uuid("tenant_id").notNull(),
12
11
  label: text("label"),
13
12
  });
14
13
 
15
- class MockQuery {
16
- rows: Record<string, unknown>[] = [];
17
- where = vi.fn(() => this);
18
- limit = vi.fn(() => this);
19
- // biome-ignore lint/suspicious/noThenProperty: mock query builder is intentionally thenable so await resolves rows
20
- then: Promise<Record<string, unknown>[]>["then"];
21
-
22
- constructor(rows?: Record<string, unknown>[]) {
23
- if (rows) this.rows = rows;
24
- const promise = Promise.resolve(this.rows);
25
- // biome-ignore lint/suspicious/noThenProperty: see above
26
- this.then = promise.then.bind(promise);
27
- }
28
- }
29
-
30
- const mockDb = { select: vi.fn(() => ({ from: vi.fn(() => new MockQuery([])) })) };
14
+ // bun-db path: read-find-many/one call selectMany(ctx.db.raw, table, where, opts)
15
+ // which goes through asRawClient(ctx.db.raw).unsafe(sqlText, params).
16
+ // Mock the .unsafe() return value to feed back rows.
17
+ const unsafeMock = mock(
18
+ async (_sqlText: string, _params: unknown[]): Promise<Record<string, unknown>[]> => [],
19
+ );
20
+ const rawDb = { unsafe: unsafeMock, begin: mock() };
21
+ const ctxDb = { raw: rawDb };
31
22
 
32
23
  const mockCtx = {
33
- db: mockDb,
24
+ db: ctxDb,
34
25
  event: { type: "test", payload: {} },
35
26
  steps: {},
36
27
  scope: {},
@@ -40,7 +31,7 @@ describe("buildReadFindOneStep", () => {
40
31
  it("returns a StepInstance with kind read.findOne", () => {
41
32
  const step = buildReadFindOneStep("myLookup", {
42
33
  table: testTable,
43
- where: undefined as unknown as SQL,
34
+ where: { id: "x" },
44
35
  });
45
36
  expect(step.kind).toBe("read.findOne");
46
37
  expect((step.args as { name: string }).name).toBe("myLookup");
@@ -49,7 +40,7 @@ describe("buildReadFindOneStep", () => {
49
40
  it("stores the result key from the name arg", () => {
50
41
  const step = buildReadFindOneStep("lookupResult", {
51
42
  table: testTable,
52
- where: undefined as unknown as SQL,
43
+ where: { id: "x" },
53
44
  });
54
45
  const def = getStep("read.findOne");
55
46
  expect(def?.resultKey?.(step.args as { name: string })).toBe("lookupResult");
@@ -58,16 +49,16 @@ describe("buildReadFindOneStep", () => {
58
49
 
59
50
  describe("read.findOne run", () => {
60
51
  beforeEach(() => {
61
- vi.clearAllMocks();
52
+ mock.clearAllMocks();
53
+ unsafeMock.mockResolvedValue([]);
62
54
  });
63
55
 
64
56
  it("returns null when no row is found", async () => {
65
57
  const stepDef = getStep("read.findOne");
66
- const query = new MockQuery([]);
67
- mockDb.select.mockReturnValue({ from: vi.fn().mockReturnValue(query) });
58
+ unsafeMock.mockResolvedValueOnce([]);
68
59
 
69
60
  const result = await stepDef!.run(
70
- { name: "lookup", table: testTable, where: undefined as unknown as SQL },
61
+ { name: "lookup", table: testTable, where: { id: "x" } },
71
62
  mockCtx,
72
63
  );
73
64
 
@@ -77,11 +68,10 @@ describe("read.findOne run", () => {
77
68
  it("returns the first row when found", async () => {
78
69
  const stepDef = getStep("read.findOne");
79
70
  const row = { id: "abc", tenantId: "t1", label: "hello" };
80
- const query = new MockQuery([row]);
81
- mockDb.select.mockReturnValue({ from: vi.fn().mockReturnValue(query) });
71
+ unsafeMock.mockResolvedValueOnce([row]);
82
72
 
83
73
  const result = await stepDef!.run(
84
- { name: "lookup", table: testTable, where: undefined as unknown as SQL },
74
+ { name: "lookup", table: testTable, where: { id: "abc" } },
85
75
  mockCtx,
86
76
  );
87
77
 
@@ -90,14 +80,17 @@ describe("read.findOne run", () => {
90
80
 
91
81
  it("resolves a function where-clause before querying", async () => {
92
82
  const stepDef = getStep("read.findOne");
93
- const whereFn = vi.fn(() => "dynamic where" as unknown as SQL);
94
- const query = new MockQuery([]);
95
- mockDb.select.mockReturnValue({ from: vi.fn().mockReturnValue(query) });
83
+ const whereFn = mock(() => ({ tenantId: "dyn-tenant" }));
84
+ unsafeMock.mockResolvedValueOnce([]);
96
85
 
97
86
  await stepDef!.run({ name: "lookup", table: testTable, where: whereFn }, mockCtx);
98
87
 
99
88
  expect(whereFn).toHaveBeenCalledWith(mockCtx);
100
- expect(query.where).toHaveBeenCalledWith("dynamic where");
89
+ expect(unsafeMock).toHaveBeenCalledTimes(1);
90
+ const [sqlText, params] = unsafeMock.mock.calls[0]!;
91
+ expect(sqlText).toMatch(/SELECT \* FROM "test_read"/);
92
+ expect(sqlText).toMatch(/"tenant_id" = \$1/);
93
+ expect(params).toEqual(["dyn-tenant"]);
101
94
  });
102
95
  });
103
96
 
@@ -116,13 +109,13 @@ describe("buildReadFindManyStep", () => {
116
109
 
117
110
  describe("read.findMany run", () => {
118
111
  beforeEach(() => {
119
- vi.clearAllMocks();
112
+ mock.clearAllMocks();
113
+ unsafeMock.mockResolvedValue([]);
120
114
  });
121
115
 
122
116
  it("returns an empty array when no rows exist", async () => {
123
117
  const stepDef = getStep("read.findMany");
124
- const query = new MockQuery([]);
125
- mockDb.select.mockReturnValue({ from: vi.fn().mockReturnValue(query) });
118
+ unsafeMock.mockResolvedValueOnce([]);
126
119
 
127
120
  const result = await stepDef!.run({ name: "list", table: testTable }, mockCtx);
128
121
 
@@ -132,11 +125,12 @@ describe("read.findMany run", () => {
132
125
  it("applies the limit when specified", async () => {
133
126
  const stepDef = getStep("read.findMany");
134
127
  const rows = [{ id: "a" }, { id: "b" }];
135
- const query = new MockQuery(rows);
136
- mockDb.select.mockReturnValue({ from: vi.fn().mockReturnValue(query) });
128
+ unsafeMock.mockResolvedValueOnce(rows);
137
129
 
138
130
  await stepDef!.run({ name: "list", table: testTable, limit: 2 }, mockCtx);
139
131
 
140
- expect(query.limit).toHaveBeenCalledWith(2);
132
+ expect(unsafeMock).toHaveBeenCalledTimes(1);
133
+ const [sqlText] = unsafeMock.mock.calls[0]!;
134
+ expect(sqlText).toMatch(/LIMIT 2/);
141
135
  });
142
136
  });
@@ -1,4 +1,4 @@
1
- import { describe, expect, it, vi } from "vitest";
1
+ import { describe, expect, it, mock } from "bun:test";
2
2
  import { resolveOptional, resolveRequired } from "../steps/_resolver-utils";
3
3
  import type { PipelineCtx } from "../types/step";
4
4
 
@@ -13,15 +13,15 @@ describe("resolveRequired", () => {
13
13
  });
14
14
 
15
15
  it("calls a function resolver with the ctx and returns its result", () => {
16
- const fn = vi.fn((_ctx: PipelineCtx) => "from-fn");
16
+ const fn = mock((_ctx: PipelineCtx) => "from-fn");
17
17
  expect(resolveRequired(fn, dummyCtx)).toBe("from-fn");
18
- expect(fn).toHaveBeenCalledOnce();
18
+ expect(fn).toHaveBeenCalledTimes(1);
19
19
  expect(fn).toHaveBeenCalledWith(dummyCtx);
20
20
  });
21
21
 
22
22
  it("passes the full ctx to the resolver function", () => {
23
23
  const ctx = { event: { type: "test" }, steps: { x: 1 }, scope: {} } as unknown as PipelineCtx;
24
- const fn = vi.fn((c: PipelineCtx) => c.event.type);
24
+ const fn = mock((c: PipelineCtx) => c.event.type);
25
25
  expect(resolveRequired(fn, ctx)).toBe("test");
26
26
  });
27
27
  });
@@ -39,9 +39,9 @@ describe("resolveOptional", () => {
39
39
  });
40
40
 
41
41
  it("calls a function resolver when defined", () => {
42
- const fn = vi.fn(() => "resolved");
42
+ const fn = mock(() => "resolved");
43
43
  expect(resolveOptional(fn, dummyCtx)).toBe("resolved");
44
- expect(fn).toHaveBeenCalledOnce();
44
+ expect(fn).toHaveBeenCalledTimes(1);
45
45
  });
46
46
 
47
47
  it("returns undefined for undefined function resolver", () => {
@@ -1,21 +1,23 @@
1
- import type { SQL } from "drizzle-orm";
2
- import { pgTable, text, uuid } from "drizzle-orm/pg-core";
3
- import { beforeEach, describe, expect, it, vi } from "vitest";
1
+ import { beforeEach, describe, expect, it, mock } from "bun:test";
2
+ import { table, text, uuid } from "../../db/dialect";
4
3
  import { getStep } from "../define-step";
5
4
  import { buildUnsafeProjectionDeleteStep } from "../steps/unsafe-projection-delete";
6
5
  import type { PipelineCtx } from "../types/step";
7
6
 
8
- const testTable = pgTable("test_projection", {
7
+ const testTable = table("test_projection", {
9
8
  id: uuid("id").primaryKey().defaultRandom(),
10
9
  tenantId: uuid("tenant_id").notNull(),
11
10
  label: text("label"),
12
11
  });
13
12
 
14
- const mockDb = { delete: vi.fn() };
15
- const mockDeleteBuilder = { where: vi.fn() };
13
+ // bun-db path: step calls deleteMany(ctx.db.raw, table, where) which lands on
14
+ // asRawClient(ctx.db.raw).unsafe(sqlText, params).
15
+ const unsafeMock = mock(async (_sqlText: string, _params: unknown[]): Promise<unknown[]> => []);
16
+ const rawDb = { unsafe: unsafeMock, begin: mock() };
17
+ const ctxDb = { raw: rawDb };
16
18
 
17
19
  const mockCtx = {
18
- db: mockDb,
20
+ db: ctxDb,
19
21
  event: { type: "test", payload: {} },
20
22
  steps: {},
21
23
  scope: {},
@@ -25,16 +27,16 @@ describe("buildUnsafeProjectionDeleteStep", () => {
25
27
  it("returns a StepInstance with kind unsafeProjectionDelete", () => {
26
28
  const step = buildUnsafeProjectionDeleteStep({
27
29
  table: testTable,
28
- where: () => undefined as unknown as SQL,
30
+ where: () => ({}),
29
31
  });
30
32
  expect(step.kind).toBe("unsafeProjectionDelete");
31
33
  expect(step.args).toMatchObject({ table: testTable });
32
34
  });
33
35
 
34
- it("accepts a static SQL where clause", () => {
36
+ it("accepts a static where clause", () => {
35
37
  const step = buildUnsafeProjectionDeleteStep({
36
38
  table: testTable,
37
- where: undefined as unknown as SQL,
39
+ where: { id: "x" },
38
40
  });
39
41
  expect(step.args).toHaveProperty("table");
40
42
  });
@@ -42,28 +44,31 @@ describe("buildUnsafeProjectionDeleteStep", () => {
42
44
 
43
45
  describe("unsafeProjectionDelete run", () => {
44
46
  beforeEach(() => {
45
- vi.clearAllMocks();
46
- mockDb.delete.mockReturnValue(mockDeleteBuilder);
47
+ mock.clearAllMocks();
47
48
  });
48
49
 
49
- it("calls db.delete().where() with the resolved where clause", async () => {
50
+ it("issues DELETE ... WHERE ... with the resolved where clause", async () => {
50
51
  const stepDef = getStep("unsafeProjectionDelete");
51
52
  expect(stepDef).toBeDefined();
52
53
 
53
- const whereClause = "fake sql" as unknown as SQL;
54
- await stepDef!.run({ table: testTable, where: whereClause }, mockCtx);
54
+ await stepDef!.run({ table: testTable, where: { id: "abc" } }, mockCtx);
55
55
 
56
- expect(mockDb.delete).toHaveBeenCalledOnce();
57
- expect(mockDeleteBuilder.where).toHaveBeenCalledWith(whereClause);
56
+ expect(unsafeMock).toHaveBeenCalledTimes(1);
57
+ const [sqlText, params] = unsafeMock.mock.calls[0]!;
58
+ expect(sqlText).toMatch(/DELETE FROM "test_projection"/);
59
+ expect(sqlText).toMatch(/"id" = \$1/);
60
+ expect(params).toEqual(["abc"]);
58
61
  });
59
62
 
60
63
  it("resolves a function where-clause before calling delete", async () => {
61
64
  const stepDef = getStep("unsafeProjectionDelete");
62
65
 
63
- const whereFn = vi.fn(() => "dynamic where" as unknown as SQL);
66
+ const whereFn = mock(() => ({ tenantId: "t1" }));
64
67
  await stepDef!.run({ table: testTable, where: whereFn }, mockCtx);
65
68
 
66
69
  expect(whereFn).toHaveBeenCalledWith(mockCtx);
67
- expect(mockDeleteBuilder.where).toHaveBeenCalledWith("dynamic where");
70
+ expect(unsafeMock).toHaveBeenCalledTimes(1);
71
+ const [, params] = unsafeMock.mock.calls[0]!;
72
+ expect(params).toEqual(["t1"]);
68
73
  });
69
74
  });