@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,24 +1,29 @@
1
- import { and, type Column, eq, getTableName, or, type SQL } from "drizzle-orm";
1
+ import {
2
+ asRawClient,
3
+ deleteMany as bunDeleteMany,
4
+ fetchOne as bunFetchOne,
5
+ insertOne as bunInsertOne,
6
+ selectMany as bunSelectMany,
7
+ updateMany as bunUpdateMany,
8
+ type SelectOptions,
9
+ type WhereObject,
10
+ } from "../db/query";
2
11
  import { SYSTEM_TENANT_ID, type TenantId } from "../engine/types/identifiers";
3
12
  import { emitDbQuery, type Meter, registerStandardMetrics, type Tracer } from "../observability";
4
13
  import type { DbRunner } from "./connection";
5
14
  import type { TableColumns } from "./dialect";
6
15
 
7
- // biome-ignore lint/suspicious/noExplicitAny: Drizzle dynamic tables
16
+ // biome-ignore lint/suspicious/noExplicitAny: Dynamic tables — keys depend on user-defined schema.
8
17
  type Table = TableColumns<any>;
9
18
 
10
- // biome-ignore lint/suspicious/noExplicitAny: Drizzle column selection
11
- type ColumnSelection = Record<string, any>;
12
-
13
19
  /**
14
20
  * TenantDb scope modes:
15
21
  *
16
- * - "tenant" (default): SELECT/UPDATE/DELETE filtered by tenantId + reference data (tenantId=0).
22
+ * - "tenant" (default): SELECT/UPDATE/DELETE filtered by tenantId + reference data (tenantId=SYSTEM_TENANT_ID).
17
23
  * INSERT forces tenantId — handler cannot override.
18
24
  *
19
25
  * - "system" (r.systemScope()): No tenant filter on reads/updates/deletes.
20
- * INSERT uses tenantId as default but handler can override (e.g. write a
21
- * cross-tenant row to a shared sentinel like SYSTEM_TENANT_ID).
26
+ * INSERT uses tenantId as default but handler can override.
22
27
  *
23
28
  * Tables without a tenantId column are always unfiltered regardless of mode.
24
29
  */
@@ -29,143 +34,62 @@ export type TenantDb = {
29
34
  readonly mode: TenantDbMode;
30
35
  /**
31
36
  * Underlying DbRunner. Framework-internal use (event-store, migrations) —
32
- * bypasses tenant-filter. Feature code should stick to the typed wrappers
33
- * above so the automatic scoping stays intact.
37
+ * bypasses tenant-filter. Feature code uses the typed helpers above so the
38
+ * automatic scoping stays intact.
34
39
  */
35
40
  readonly raw: DbRunner;
36
- select(): TenantSelect;
37
- select(columns: ColumnSelection): TenantSelect;
38
- insert(table: Table): TenantInsert;
39
- update(table: Table): TenantUpdate;
40
- delete(table: Table): TenantDelete;
41
- };
42
-
43
- type TenantSelect = {
44
- from(table: Table): TenantSelectQuery;
45
- };
46
-
47
- type WhereCondition = SQL | undefined;
48
-
49
- type RowLockStrength = "update" | "no key update" | "share" | "key share";
50
-
51
- type TenantSelectQuery = PromiseLike<Record<string, unknown>[]> & {
52
- where(condition: WhereCondition): TenantSelectQuery;
53
- limit(n: number): TenantSelectQuery;
54
- offset(n: number): TenantSelectQuery;
55
- orderBy(...columns: (SQL | Column)[]): TenantSelectQuery;
56
- /** Row-level locking (FOR UPDATE / FOR SHARE). Must be called inside a tx. */
57
- for(strength: RowLockStrength): TenantSelectQuery;
58
- };
59
-
60
- type TenantInsert = {
61
- values(data: Record<string, unknown>): TenantInsertValues;
62
- };
63
-
64
- type ConflictTarget = Column | readonly Column[];
65
- type ConflictUpdate = {
66
- target: ConflictTarget;
67
- set: Record<string, unknown>;
68
- };
69
-
70
- type TenantInsertValues = PromiseLike<void> & {
71
- returning(): PromiseLike<Record<string, unknown>[]>;
72
- onConflictDoUpdate(spec: ConflictUpdate): PromiseLike<void>;
73
- onConflictDoNothing(spec?: { target: ConflictTarget }): PromiseLike<void>;
74
- };
75
-
76
- type TenantUpdate = {
77
- set(data: Record<string, unknown>): TenantUpdateSet;
78
- };
79
-
80
- type TenantUpdateSet = PromiseLike<void> & {
81
- where(condition: WhereCondition): TenantUpdateWhere;
82
- returning(): PromiseLike<Record<string, unknown>[]>;
83
- };
84
-
85
- type TenantUpdateWhere = PromiseLike<void> & {
86
- returning(): PromiseLike<Record<string, unknown>[]>;
87
- };
88
-
89
- type TenantDelete = {
90
- where(condition: WhereCondition): PromiseLike<void>;
41
+ selectMany<T = Record<string, unknown>>(
42
+ table: Table,
43
+ where?: WhereObject,
44
+ options?: SelectOptions,
45
+ ): Promise<readonly T[]>;
46
+ fetchOne<T = Record<string, unknown>>(table: Table, where: WhereObject): Promise<T | undefined>;
47
+ insertOne<T = Record<string, unknown>>(
48
+ table: Table,
49
+ values: Record<string, unknown>,
50
+ ): Promise<T | undefined>;
51
+ updateMany<T = Record<string, unknown>>(
52
+ table: Table,
53
+ set: Record<string, unknown>,
54
+ where: WhereObject,
55
+ ): Promise<readonly T[]>;
56
+ deleteMany(table: Table, where: WhereObject): Promise<void>;
91
57
  };
92
58
 
93
- /**
94
- * Cast helper for the `Record<string, unknown>[]` rows that
95
- * `TenantDb.select()` returns.
96
- *
97
- * Usage:
98
- * const rows = castTenantRows<MyRow>(
99
- * await ctx.db.select({...}).from(myTable),
100
- * );
101
- *
102
- * Why this exists: drizzle's `.select({col1: t.col1, ...})` natively
103
- * returns `Array<{col1: T1, ...}>`, but our TenantDb wrapper erases
104
- * that shape to `Record<string, unknown>[]` so it can centralize tenant-
105
- * scoping. Until the wrapper preserves the typed-row shape (see memory:
106
- * project_tenant_db_typed_rows), call sites need to assert the column
107
- * shape they just selected. This helper:
108
- * - centralises the cast (single grep target for the future refactor)
109
- * - tags it with `@cast-boundary tenant-db-row` for the as-cast audit
110
- * - documents the trade-off once instead of N times
111
- *
112
- * Removal plan: when TenantSelectQuery becomes generic over the
113
- * column-shape, every `castTenantRows<T>(...)` call is just `await ...`
114
- * and this helper goes away.
115
- */
116
59
  // @cast-boundary tenant-db-row
117
60
  export function castTenantRows<T>(rows: readonly Record<string, unknown>[]): readonly T[] {
118
61
  return rows as unknown as readonly T[];
119
62
  }
120
63
 
64
+ const KUMIKO_NAME_SYMBOL = Symbol.for("kumiko:schema:Name");
65
+
66
+ function tableNameOf(table: Table): string {
67
+ const sym = (table as unknown as Record<symbol, unknown>)[KUMIKO_NAME_SYMBOL];
68
+ return typeof sym === "string" ? sym : "<unknown>";
69
+ }
70
+
71
+ function hasTenantColumn(table: Table): boolean {
72
+ return (table as Record<string, unknown>)["tenantId"] !== undefined;
73
+ }
74
+
121
75
  export function createTenantDb(
122
76
  db: DbRunner,
123
77
  tenantId: TenantId,
124
78
  mode: TenantDbMode = "tenant",
125
79
  tracer?: Tracer,
126
80
  meter?: Meter,
127
- // Pre-flight cancellation: when set, every query check
128
- // `signal.throwIfAborted()` BEFORE issuing the SQL. The currently
129
- // running query is not actively cancelled (postgres-js connection
130
- // cancel is a separate, riskier feature). This still saves the bulk
131
- // of the wasted work in handlers that fire many sequential queries
132
- // — once the client disconnects, the next query throws and the rest
133
- // of the chain falls away.
134
81
  signal?: AbortSignal,
135
82
  ): TenantDb {
136
- // If a meter was passed, make sure standard metrics are registered on it
137
- // before we try to emit. Idempotent — buildServer typically registers them
138
- // up front; this guards against test call-sites that wire up a TenantDb
139
- // directly with a fresh meter.
140
83
  if (meter) registerStandardMetrics(meter);
141
84
 
142
- function hasTenantColumn(table: Table): boolean {
143
- return table["tenantId"] !== undefined;
144
- }
145
-
146
- // Drizzle's terminal builders (insert, update().where, delete().where) are
147
- // thenable — `.then` is there so `await` works — but the declared return
148
- // types don't include PromiseLike. Cast via this helper so the double-
149
- // cast is named and lives in exactly one place per scope.
150
- function asDrizzleThenable<T>(builder: unknown): PromiseLike<T> {
151
- return builder as PromiseLike<T>; // @cast-boundary engine-bridge
152
- }
153
-
154
- // Wrap a DB query promise in a `db.query` span + emit the DB duration
155
- // histogram. Row count is recorded when the result is an array (SELECTs
156
- // + *.returning()). Metric is emitted both on success and on throw so
157
- // slow failing queries show up too.
158
85
  function withDbSpan<T>(
159
86
  operation: "select" | "insert" | "update" | "delete",
160
87
  table: Table,
161
- exec: () => PromiseLike<T>,
162
- ): PromiseLike<T> {
163
- // Pre-flight cancellation. Sits above the early-return so the check
164
- // fires regardless of observability config — cancellation is a
165
- // correctness feature, not an observability one.
88
+ runner: () => Promise<T>,
89
+ ): Promise<T> {
166
90
  signal?.throwIfAborted();
167
- if (!tracer && !meter) return exec();
168
- const tableName = getTableName(table);
91
+ if (!tracer && !meter) return runner();
92
+ const tableName = tableNameOf(table);
169
93
  const start = performance.now();
170
94
  const emitMetric = () => {
171
95
  if (meter) {
@@ -174,10 +98,9 @@ export function createTenantDb(
174
98
  };
175
99
 
176
100
  if (!tracer) {
177
- // Tracer absent but meter present: just time + emit, no span.
178
101
  return (async () => {
179
102
  try {
180
- return await exec();
103
+ return await runner();
181
104
  } finally {
182
105
  emitMetric();
183
106
  }
@@ -196,7 +119,7 @@ export function createTenantDb(
196
119
  },
197
120
  async (span) => {
198
121
  try {
199
- const result = await exec();
122
+ const result = await runner();
200
123
  if (Array.isArray(result)) {
201
124
  span.setAttribute("db.row_count", result.length);
202
125
  }
@@ -208,227 +131,83 @@ export function createTenantDb(
208
131
  );
209
132
  }
210
133
 
211
- // --- Read filter (SELECT WHERE clause) ---
212
- //
213
- // Reads in tenant mode see their own rows AND global reference data (rows
214
- // with tenantId = SYSTEM_TENANT_ID). Writes explicitly do NOT see writeFilter.
215
-
216
- function readFilter(table: Table, ...extra: SQL[]): SQL | undefined {
217
- if (!hasTenantColumn(table)) {
218
- return extra.length > 0 ? and(...extra) : undefined;
219
- }
220
-
221
- if (mode === "system") {
222
- // System mode: no tenant restriction, only pass through extra conditions
223
- return extra.length > 0 ? and(...extra) : undefined;
224
- }
225
-
226
- // Tenant mode: own data + reference data (zero-UUID tenantId for global rows).
227
- // Drizzle's `or()` is typed `SQL | undefined` (variadic-empty case); both
228
- // `eq()` args always produce SQL, so the cast documents that assumption.
229
- const ownOrGlobal = or(
230
- eq(table["tenantId"], tenantId),
231
- eq(table["tenantId"], SYSTEM_TENANT_ID),
232
- ) as SQL; // @cast-boundary db-operator
233
- return extra.length > 0 ? and(ownOrGlobal, ...extra) : ownOrGlobal;
134
+ // Reads see own-tenant rows + reference data (tenantId === SYSTEM_TENANT_ID).
135
+ // Writes never touch reference rows — those are system-mode only.
136
+ function readWhere(table: Table, where?: WhereObject): WhereObject | undefined {
137
+ if (!hasTenantColumn(table) || mode === "system") return where;
138
+ const tenantFilter: WhereObject = { tenantId: [tenantId, SYSTEM_TENANT_ID] };
139
+ return where ? { ...tenantFilter, ...where } : tenantFilter;
234
140
  }
235
141
 
236
- // --- Write filter (UPDATE/DELETE WHERE clause) ---
237
- //
238
- // Writes in tenant mode must NEVER match reference rows — otherwise a tenant
239
- // could mutate global data by coincidence of id/condition. Only system-scope
240
- // (r.systemScope()) may modify reference data.
241
-
242
- function writeFilter(table: Table, ...extra: SQL[]): SQL | undefined {
243
- if (!hasTenantColumn(table)) {
244
- return extra.length > 0 ? and(...extra) : undefined;
245
- }
246
-
247
- if (mode === "system") {
248
- return extra.length > 0 ? and(...extra) : undefined;
249
- }
250
-
251
- const ownOnly = eq(table["tenantId"], tenantId);
252
- return extra.length > 0 ? and(ownOnly, ...extra) : ownOnly;
142
+ function writeWhere(table: Table, where: WhereObject): WhereObject {
143
+ if (!hasTenantColumn(table) || mode === "system") return where;
144
+ return { tenantId, ...where };
253
145
  }
254
146
 
255
- // --- Write values (INSERT tenantId handling) ---
256
-
257
147
  function insertValues(table: Table, data: Record<string, unknown>): Record<string, unknown> {
258
148
  if (!hasTenantColumn(table)) return data;
259
-
260
- if (mode === "system") {
261
- // System mode: tenantId is a default the handler can override —
262
- // e.g. to write a cross-tenant row under SYSTEM_TENANT_ID, or to
263
- // target a foreign tenant's projection from a SystemAdmin action.
264
- return { tenantId, ...data };
265
- }
266
-
267
- // Tenant mode: tenantId is forced, handler cannot override
149
+ if (mode === "system") return { tenantId, ...data };
268
150
  return { ...data, tenantId };
269
151
  }
270
152
 
271
- // --- Select wrapper (lazy filter + chainable) ---
272
-
273
- function wrapSelect(
274
- // biome-ignore lint/suspicious/noExplicitAny: Drizzle internal query type
275
- query: any,
276
- table: Table,
277
- filtered: boolean,
278
- ): TenantSelectQuery {
279
- function ensureFiltered() {
280
- if (filtered) return query;
281
- const filter = readFilter(table);
282
- return filter ? query.where(filter) : query;
283
- }
284
-
285
- return {
286
- where(condition: SQL) {
287
- const filter = readFilter(table, condition);
288
- return wrapSelect(filter ? query.where(filter) : query.where(condition), table, true);
289
- },
290
- limit(n: number) {
291
- return wrapSelect(ensureFiltered().limit(n), table, true);
292
- },
293
- offset(n: number) {
294
- return wrapSelect(ensureFiltered().offset(n), table, true);
295
- },
296
- orderBy(...columns: SQL[]) {
297
- return wrapSelect(ensureFiltered().orderBy(...columns), table, true);
298
- },
299
- for(strength: RowLockStrength) {
300
- return wrapSelect(ensureFiltered().for(strength), table, true);
301
- },
302
- // biome-ignore lint/suspicious/noThenProperty: thenable for await
303
- then(
304
- resolve: ((value: Record<string, unknown>[]) => void) | null,
305
- reject: ((reason: unknown) => void) | null,
306
- ) {
307
- return withDbSpan<Record<string, unknown>[]>("select", table, () => ensureFiltered()).then(
308
- (rows) => resolve?.(rows),
309
- reject ?? undefined,
310
- );
311
- },
312
- } as TenantSelectQuery; // @cast-boundary drizzle-bridge
313
- }
314
-
315
- // --- Where helper for update/delete ---
316
-
317
- function whereClause(table: Table, condition: SQL): SQL {
318
- const filter = writeFilter(table, condition);
319
- return filter ?? condition;
320
- }
321
-
322
153
  return {
323
154
  tenantId,
324
155
  mode,
325
156
  raw: db,
326
157
 
327
- select(columns?: ColumnSelection) {
328
- return {
329
- from(table: Table) {
330
- const baseQuery = columns ? db.select(columns).from(table) : db.select().from(table);
331
- return wrapSelect(baseQuery, table, false);
332
- },
333
- };
158
+ selectMany<T = Record<string, unknown>>(
159
+ table: Table,
160
+ where?: WhereObject,
161
+ options?: SelectOptions,
162
+ ): Promise<readonly T[]> {
163
+ const filter = readWhere(table, where);
164
+ return withDbSpan("select", table, async () => bunSelectMany<T>(db, table, filter, options));
334
165
  },
335
166
 
336
- insert(table: Table) {
337
- return {
338
- values(data: Record<string, unknown>) {
339
- const q = db.insert(table).values(insertValues(table, data));
340
- return {
341
- returning() {
342
- return withDbSpan<Record<string, unknown>[]>(
343
- "insert",
344
- table,
345
- () => q.returning() as PromiseLike<Record<string, unknown>[]>, // @cast-boundary db-runner
346
- );
347
- },
348
- onConflictDoUpdate(spec: ConflictUpdate) {
349
- return withDbSpan<void>("insert", table, () =>
350
- (
351
- q as unknown as {
352
- onConflictDoUpdate: (s: ConflictUpdate) => PromiseLike<void>;
353
- }
354
- ).onConflictDoUpdate(spec),
355
- );
356
- },
357
- onConflictDoNothing(spec?: { target: ConflictTarget }) {
358
- return withDbSpan<void>("insert", table, () =>
359
- (
360
- q as unknown as {
361
- onConflictDoNothing: (s?: { target: ConflictTarget }) => PromiseLike<void>;
362
- }
363
- ).onConflictDoNothing(spec),
364
- );
365
- },
366
- // biome-ignore lint/suspicious/noThenProperty: thenable for await
367
- then(resolve, reject) {
368
- return withDbSpan<void>("insert", table, () => asDrizzleThenable<void>(q)).then(
369
- resolve,
370
- reject,
371
- );
372
- },
373
- } as TenantInsertValues; // @cast-boundary drizzle-bridge
374
- },
375
- };
167
+ fetchOne<T = Record<string, unknown>>(
168
+ table: Table,
169
+ where: WhereObject,
170
+ ): Promise<T | undefined> {
171
+ const filter = readWhere(table, where) ?? {};
172
+ return withDbSpan("select", table, async () => bunFetchOne<T>(db, table, filter));
376
173
  },
377
174
 
378
- update(table: Table) {
379
- return {
380
- set(data: Record<string, unknown>) {
381
- const q = db.update(table).set(data);
382
- return {
383
- where(condition: SQL) {
384
- const wq = q.where(whereClause(table, condition));
385
- return {
386
- returning() {
387
- return withDbSpan<Record<string, unknown>[]>(
388
- "update",
389
- table,
390
- () => wq.returning() as PromiseLike<Record<string, unknown>[]>, // @cast-boundary db-runner
391
- );
392
- },
393
- // biome-ignore lint/suspicious/noThenProperty: thenable for await
394
- then(resolve, reject) {
395
- return withDbSpan<void>("update", table, () => asDrizzleThenable<void>(wq)).then(
396
- resolve,
397
- reject,
398
- );
399
- },
400
- } as TenantUpdateWhere; // @cast-boundary drizzle-bridge
401
- },
402
- returning(): PromiseLike<Record<string, unknown>[]> {
403
- return Promise.reject(
404
- new Error(
405
- "TenantDb.update().set().returning() without .where() would mass-update all tenant rows. " +
406
- "Add .where(...) first, or call .set(...).where(...).returning().",
407
- ),
408
- );
409
- },
410
- // biome-ignore lint/suspicious/noThenProperty: thenable for await
411
- then(resolve, reject) {
412
- return Promise.reject(
413
- new Error(
414
- "TenantDb.update().set() awaited without .where() would mass-update all tenant rows. " +
415
- "Add .where(...) before awaiting.",
416
- ),
417
- ).then(resolve, reject);
418
- },
419
- } as TenantUpdateSet; // @cast-boundary drizzle-bridge
420
- },
421
- };
175
+ insertOne<T = Record<string, unknown>>(
176
+ table: Table,
177
+ values: Record<string, unknown>,
178
+ ): Promise<T | undefined> {
179
+ const data = insertValues(table, values);
180
+ return withDbSpan("insert", table, async () => bunInsertOne<T>(db, table, data));
422
181
  },
423
182
 
424
- delete(table: Table) {
425
- return {
426
- where(condition: SQL) {
427
- return withDbSpan<void>("delete", table, () =>
428
- asDrizzleThenable<void>(db.delete(table).where(whereClause(table, condition))),
429
- );
430
- },
431
- };
183
+ updateMany<T = Record<string, unknown>>(
184
+ table: Table,
185
+ set: Record<string, unknown>,
186
+ where: WhereObject,
187
+ ): Promise<readonly T[]> {
188
+ if (!where || Object.keys(where).length === 0) {
189
+ return Promise.reject(
190
+ new Error(
191
+ "TenantDb.updateMany without where would mass-update all tenant rows. Pass at least one where condition.",
192
+ ),
193
+ );
194
+ }
195
+ const filter = writeWhere(table, where);
196
+ return withDbSpan("update", table, async () => bunUpdateMany<T>(db, table, set, filter));
197
+ },
198
+
199
+ deleteMany(table: Table, where: WhereObject): Promise<void> {
200
+ if (!where || Object.keys(where).length === 0) {
201
+ return Promise.reject(
202
+ new Error(
203
+ "TenantDb.deleteMany without where would mass-delete all tenant rows. Pass at least one where condition.",
204
+ ),
205
+ );
206
+ }
207
+ const filter = writeWhere(table, where);
208
+ return withDbSpan("delete", table, async () => bunDeleteMany(db, table, filter));
432
209
  },
433
210
  };
434
211
  }
212
+
213
+ export { asRawClient };
@@ -1,4 +1,4 @@
1
- import { describe, expect, test } from "vitest";
1
+ import { describe, expect, test } from "bun:test";
2
2
  import { createRegistry, defineFeature } from "../index";
3
3
 
4
4
  describe("r.authClaims() — registrar collection", () => {
@@ -9,15 +9,15 @@
9
9
  // Soft-Warning (console.warn):
10
10
  // - Feature ruft eigene exposesApi via usesApi (Refactor-Leftover)
11
11
 
12
- import { afterEach, beforeEach, describe, expect, test, vi } from "vitest";
12
+ import { afterEach, beforeEach, describe, expect, spyOn, test } from "bun:test";
13
13
  import { validateBoot } from "../boot-validator";
14
14
  import { defineFeature } from "../define-feature";
15
15
 
16
16
  describe("validateBoot — r.exposesApi / r.usesApi", () => {
17
- let warnSpy: ReturnType<typeof vi.spyOn>;
17
+ let warnSpy: ReturnType<typeof spyOn>;
18
18
 
19
19
  beforeEach(() => {
20
- warnSpy = vi.spyOn(console, "warn").mockImplementation(() => {});
20
+ warnSpy = spyOn(console, "warn").mockImplementation(() => {});
21
21
  });
22
22
 
23
23
  afterEach(() => {
@@ -4,7 +4,7 @@
4
4
  // in derselben Entity referenzieren. Sonst silent data loss — wir wollen
5
5
  // fail-fast beim Boot.
6
6
 
7
- import { describe, expect, test } from "vitest";
7
+ import { describe, expect, test } from "bun:test";
8
8
  import { validateBoot } from "../boot-validator";
9
9
  import { defineFeature } from "../define-feature";
10
10
  import { createEntity, createTimestampField, createTzField, locatedTimestamp } from "../factories";
@@ -14,7 +14,7 @@
14
14
  //
15
15
  // allowPlaintext-Marker unterdrückt Heuristik-Warnings.
16
16
 
17
- import { afterEach, beforeEach, describe, expect, test, vi } from "vitest";
17
+ import { afterEach, beforeEach, describe, expect, spyOn, test } from "bun:test";
18
18
  import { z } from "zod";
19
19
  import { validateBoot } from "../boot-validator";
20
20
  import { defineFeature } from "../define-feature";
@@ -48,10 +48,10 @@ function stubListHandler(r: any, entityName: string): void {
48
48
  }
49
49
 
50
50
  describe("validateBoot — PII annotations", () => {
51
- let warnSpy: ReturnType<typeof vi.spyOn>;
51
+ let warnSpy: ReturnType<typeof spyOn>;
52
52
 
53
53
  beforeEach(() => {
54
- warnSpy = vi.spyOn(console, "warn").mockImplementation(() => {});
54
+ warnSpy = spyOn(console, "warn").mockImplementation(() => {});
55
55
  });
56
56
 
57
57
  afterEach(() => {
@@ -428,10 +428,10 @@ describe("validateBoot — PII annotations", () => {
428
428
  });
429
429
 
430
430
  describe("validateBoot — retention", () => {
431
- let warnSpy: ReturnType<typeof vi.spyOn>;
431
+ let warnSpy: ReturnType<typeof spyOn>;
432
432
 
433
433
  beforeEach(() => {
434
- warnSpy = vi.spyOn(console, "warn").mockImplementation(() => {});
434
+ warnSpy = spyOn(console, "warn").mockImplementation(() => {});
435
435
  });
436
436
 
437
437
  afterEach(() => {
@@ -13,7 +13,7 @@
13
13
  // + retention.blockDelete + anonymize-Funktion
14
14
  // + handler-access mit ROLES.TenantAdmin
15
15
 
16
- import { afterEach, beforeEach, describe, expect, test, vi } from "vitest";
16
+ import { afterEach, beforeEach, describe, expect, spyOn, test } from "bun:test";
17
17
  import { z } from "zod";
18
18
  import { ROLES } from "../../auth";
19
19
  import { validateBoot } from "../boot-validator";
@@ -27,10 +27,10 @@ import {
27
27
  } from "../index";
28
28
 
29
29
  describe("S0 Integration — full surface stack", () => {
30
- let warnSpy: ReturnType<typeof vi.spyOn>;
30
+ let warnSpy: ReturnType<typeof spyOn>;
31
31
 
32
32
  beforeEach(() => {
33
- warnSpy = vi.spyOn(console, "warn").mockImplementation(() => {});
33
+ warnSpy = spyOn(console, "warn").mockImplementation(() => {});
34
34
  });
35
35
 
36
36
  afterEach(() => {
@@ -1,6 +1,7 @@
1
- import { pgTable, text } from "drizzle-orm/pg-core";
2
- import { describe, expect, test } from "vitest";
1
+ import { describe, expect, test } from "bun:test";
3
2
  import { z } from "zod";
3
+ import type { SchemaTable } from "../../db/dialect";
4
+ import { table, text } from "../../db/dialect";
4
5
  import { validateBoot } from "../boot-validator";
5
6
  import { createSystemConfig, createTenantConfig } from "../config-helpers";
6
7
  import {
@@ -904,7 +905,7 @@ describe("boot-validator", () => {
904
905
  // --- MultiStreamProjection delivery invariant (Welle 2.7) ---
905
906
 
906
907
  describe("MultiStreamProjection delivery", () => {
907
- const sinkTable = pgTable("sink", { id: text("id").primaryKey() });
908
+ const sinkTable = table("sink", { id: text("id").primaryKey() }) as unknown as SchemaTable;
908
909
 
909
910
  test("rejects delivery='per-instance' combined with a backing table", () => {
910
911
  const features = [
@@ -7,7 +7,7 @@
7
7
  // projection-Schritt rausgefiltert — sonst landet Server-Runtime
8
8
  // im Browser-Bundle.
9
9
 
10
- import { describe, expect, test } from "vitest";
10
+ import { describe, expect, test } from "bun:test";
11
11
  import { buildAppSchema } from "../build-app-schema";
12
12
  import { defineFeature } from "../define-feature";
13
13
  import { createRegistry } from "../registry";
@@ -1,4 +1,4 @@
1
- import { describe, expect, test } from "vitest";
1
+ import { describe, expect, test } from "bun:test";
2
2
  import { buildTarget, type TreeActionDef } from "../index";
3
3
 
4
4
  // createTreeActionsStub — Test-Helper für Phase-0-Stub-Features. Das
@@ -1,4 +1,4 @@
1
- import { describe, expect, test } from "vitest";
1
+ import { describe, expect, test } from "bun:test";
2
2
  import { createRegistry, defineFeature, readClaim } from "../index";
3
3
  import type { ClaimKeyHandle, SessionUser } from "../types";
4
4