@cosmicdrift/kumiko-framework 0.14.0 → 0.16.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 (342) hide show
  1. package/package.json +6 -6
  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/auth-routes.ts +2 -5
  24. package/src/api/readiness.ts +2 -2
  25. package/src/auth/__tests__/roles.test.ts +2 -2
  26. package/src/bun-db/__tests__/PATTERN.md +73 -0
  27. package/src/bun-db/__tests__/_helpers.ts +103 -0
  28. package/src/bun-db/__tests__/batch-methods.integration.test.ts +143 -0
  29. package/src/bun-db/__tests__/batch-methods.test.ts +20 -0
  30. package/src/bun-db/__tests__/bun-test-db.ts +19 -0
  31. package/src/bun-db/__tests__/bun-test-stack.ts +6 -0
  32. package/src/bun-db/__tests__/column-types.integration.test.ts +132 -0
  33. package/src/bun-db/__tests__/compound-types.integration.test.ts +134 -0
  34. package/src/bun-db/__tests__/jsonb-edge-cases.integration.test.ts +235 -0
  35. package/src/bun-db/__tests__/smoke.integration.test.ts +43 -0
  36. package/src/bun-db/__tests__/sql-methods.integration.test.ts +231 -0
  37. package/src/bun-db/__tests__/where-patterns.integration.test.ts +185 -0
  38. package/src/bun-db/connection.ts +84 -0
  39. package/src/bun-db/index.ts +31 -0
  40. package/src/bun-db/query.ts +842 -0
  41. package/src/compliance/__tests__/duration-spec.test.ts +1 -1
  42. package/src/compliance/__tests__/profiles.test.ts +1 -1
  43. package/src/compliance/__tests__/sub-processors.test.ts +1 -1
  44. package/src/compliance/profiles.ts +1 -4
  45. package/src/db/__tests__/{apply-entity-event-tenant.integration.ts → apply-entity-event-tenant.integration.test.ts} +13 -11
  46. package/src/db/__tests__/big-int-field.test.ts +15 -14
  47. package/src/db/__tests__/column-ddl.integration.test.ts +113 -0
  48. package/src/db/__tests__/compound-types.test.ts +1 -1
  49. package/src/db/__tests__/{config-seed.integration.ts → config-seed.integration.test.ts} +32 -27
  50. package/src/db/__tests__/connection-options.test.ts +1 -1
  51. package/src/db/__tests__/cursor.test.ts +8 -32
  52. package/src/db/__tests__/dialect-instant.test.ts +1 -1
  53. package/src/db/__tests__/encryption.test.ts +1 -1
  54. package/src/db/__tests__/{drizzle-table-types.test.ts → entity-table-types.test.ts} +16 -16
  55. package/src/db/__tests__/{event-store-executor-list.integration.ts → event-store-executor-list.integration.test.ts} +12 -7
  56. package/src/db/__tests__/{event-store-executor.integration.ts → event-store-executor.integration.test.ts} +19 -12
  57. package/src/db/__tests__/{implicit-projection-equivalence.integration.ts → implicit-projection-equivalence.integration.test.ts} +35 -29
  58. package/src/db/__tests__/located-timestamp.test.ts +1 -1
  59. package/src/db/__tests__/migrate-generator.test.ts +71 -0
  60. package/src/db/__tests__/migrate-runner.test.ts +19 -0
  61. package/src/db/__tests__/money.test.ts +1 -1
  62. package/src/db/__tests__/{multi-row-insert.integration.ts → multi-row-insert.integration.test.ts} +18 -11
  63. package/src/db/__tests__/parse-auto-verb.test.ts +1 -1
  64. package/src/db/__tests__/pg-error.test.ts +43 -0
  65. package/src/db/__tests__/{required-not-null-migration-safety.integration.ts → required-not-null-migration-safety.integration.test.ts} +28 -24
  66. package/src/db/__tests__/{schema-migration.integration.ts → schema-migration.integration.test.ts} +32 -28
  67. package/src/db/__tests__/sql-inventory.test.ts +56 -0
  68. package/src/db/__tests__/table-builder-indexes.test.ts +30 -11
  69. package/src/db/__tests__/table-builder-required.test.ts +20 -22
  70. package/src/db/__tests__/{tenant-db.integration.ts → tenant-db.integration.test.ts} +106 -144
  71. package/src/db/__tests__/{unique-violation-mapping.integration.ts → unique-violation-mapping.integration.test.ts} +13 -8
  72. package/src/db/api.ts +46 -0
  73. package/src/db/apply-entity-event.ts +45 -36
  74. package/src/db/assert-exists-in.ts +5 -16
  75. package/src/db/bun-provider.ts +37 -0
  76. package/src/db/config-seed.ts +4 -4
  77. package/src/db/connection.ts +14 -57
  78. package/src/db/cursor.ts +5 -56
  79. package/src/db/dialect.ts +472 -99
  80. package/src/db/eagerload.ts +5 -12
  81. package/src/db/entity-table-meta.ts +390 -0
  82. package/src/db/event-store-executor.ts +158 -100
  83. package/src/db/index.ts +33 -5
  84. package/src/db/migrate-generator.ts +350 -0
  85. package/src/db/migrate-runner.ts +206 -0
  86. package/src/db/postgres-provider.ts +25 -0
  87. package/src/db/queries/entity-read.ts +15 -0
  88. package/src/db/queries/es-ops.ts +17 -0
  89. package/src/db/queries/event-consumer.ts +170 -0
  90. package/src/db/queries/event-store-admin.ts +127 -0
  91. package/src/db/queries/event-store.ts +155 -0
  92. package/src/db/queries/projection-rebuild.ts +59 -0
  93. package/src/db/queries/raw-sql.ts +15 -0
  94. package/src/db/queries/schema-drift.ts +35 -0
  95. package/src/db/queries/seed-context.ts +58 -0
  96. package/src/db/queries/table-ops.ts +11 -0
  97. package/src/db/queries/test-stack.ts +56 -0
  98. package/src/db/query-api.ts +22 -0
  99. package/src/db/query.ts +30 -0
  100. package/src/db/reference-data.ts +19 -22
  101. package/src/db/render-ddl.ts +57 -0
  102. package/src/db/row-helpers.ts +3 -52
  103. package/src/db/schema-inspection.ts +17 -4
  104. package/src/db/sql-inventory.ts +208 -0
  105. package/src/db/table-builder.ts +54 -46
  106. package/src/db/tenant-db.ts +105 -326
  107. package/src/engine/__tests__/auth-claims-registrar.test.ts +1 -1
  108. package/src/engine/__tests__/boot-validator-api-exposure.test.ts +3 -3
  109. package/src/engine/__tests__/boot-validator-located-timestamps.test.ts +1 -1
  110. package/src/engine/__tests__/boot-validator-pii-retention.test.ts +5 -5
  111. package/src/engine/__tests__/boot-validator-s0-integration.test.ts +3 -3
  112. package/src/engine/__tests__/boot-validator.test.ts +4 -3
  113. package/src/engine/__tests__/build-app-schema.test.ts +1 -1
  114. package/src/engine/__tests__/build-target.test.ts +1 -1
  115. package/src/engine/__tests__/claim-keys.test.ts +1 -1
  116. package/src/engine/__tests__/codemod-pipeline.test.ts +3 -3
  117. package/src/engine/__tests__/config-helpers.test.ts +1 -1
  118. package/src/engine/__tests__/duration-utils.test.ts +16 -0
  119. package/src/engine/__tests__/effective-features.test.ts +1 -1
  120. package/src/engine/__tests__/engine.test.ts +1 -1
  121. package/src/engine/__tests__/entity-handlers.test.ts +3 -3
  122. package/src/engine/__tests__/event-helpers.test.ts +3 -3
  123. package/src/engine/__tests__/extends-registrar.test.ts +4 -4
  124. package/src/engine/__tests__/factories-long-text.test.ts +1 -1
  125. package/src/engine/__tests__/factories-time.test.ts +1 -1
  126. package/src/engine/__tests__/field-access.test.ts +38 -0
  127. package/src/engine/__tests__/field-predicates.test.ts +1 -1
  128. package/src/engine/__tests__/hook-phases.test.ts +1 -1
  129. package/src/engine/__tests__/identifiers.test.ts +1 -1
  130. package/src/engine/__tests__/lifecycle-hooks.test.ts +1 -1
  131. package/src/engine/__tests__/nav.test.ts +1 -1
  132. package/src/engine/__tests__/no-return-guard.test.ts +17 -0
  133. package/src/engine/__tests__/ownership.test.ts +10 -11
  134. package/src/engine/__tests__/parse-ref-target.test.ts +1 -1
  135. package/src/engine/__tests__/pipeline-engine.test.ts +1 -1
  136. package/src/engine/__tests__/{pipeline-handler.integration.ts → pipeline-handler.integration.test.ts} +38 -52
  137. package/src/engine/__tests__/{pipeline-observability.integration.ts → pipeline-observability.integration.test.ts} +1 -1
  138. package/src/engine/__tests__/{pipeline-performance.integration.ts → pipeline-performance.integration.test.ts} +1 -1
  139. package/src/engine/__tests__/pipeline-sub-pipelines.test.ts +1 -1
  140. package/src/engine/__tests__/post-query-hook.test.ts +1 -1
  141. package/src/engine/__tests__/projection-helpers.test.ts +25 -17
  142. package/src/engine/__tests__/projection.test.ts +4 -4
  143. package/src/engine/__tests__/qualified-name.test.ts +1 -1
  144. package/src/engine/__tests__/raw-table.test.ts +9 -8
  145. package/src/engine/__tests__/resolve-config-or-param.test.ts +5 -5
  146. package/src/engine/__tests__/run-in.test.ts +1 -1
  147. package/src/engine/__tests__/schema-builder.test.ts +1 -1
  148. package/src/engine/__tests__/screen.test.ts +1 -1
  149. package/src/engine/__tests__/search-payload-extension.test.ts +3 -3
  150. package/src/engine/__tests__/state-machine.test.ts +1 -1
  151. package/src/engine/__tests__/steps-aggregate-append-event.test.ts +7 -7
  152. package/src/engine/__tests__/steps-aggregate-create.test.ts +4 -4
  153. package/src/engine/__tests__/steps-aggregate-update.test.ts +3 -3
  154. package/src/engine/__tests__/steps-call-feature.test.ts +5 -5
  155. package/src/engine/__tests__/steps-mail-send.test.ts +7 -7
  156. package/src/engine/__tests__/steps-read.test.ts +34 -40
  157. package/src/engine/__tests__/steps-resolver-utils.test.ts +6 -6
  158. package/src/engine/__tests__/steps-unsafe-projection-delete.test.ts +24 -19
  159. package/src/engine/__tests__/steps-unsafe-projection-upsert.test.ts +28 -17
  160. package/src/engine/__tests__/steps-webhook-send.test.ts +6 -6
  161. package/src/engine/__tests__/steps-workflow.test.ts +7 -7
  162. package/src/engine/__tests__/system-user.test.ts +1 -1
  163. package/src/engine/__tests__/unmanaged-table.test.ts +98 -0
  164. package/src/engine/__tests__/validate-projection-allowlist.test.ts +4 -5
  165. package/src/engine/__tests__/validation-hooks.test.ts +1 -1
  166. package/src/engine/__tests__/visual-tree-patterns.test.ts +1 -1
  167. package/src/engine/boot-validator/entity-handler.ts +3 -3
  168. package/src/engine/boot-validator/ownership.ts +1 -1
  169. package/src/engine/define-feature.ts +37 -2
  170. package/src/engine/entity-handlers.ts +5 -5
  171. package/src/engine/factories.ts +1 -1
  172. package/src/engine/feature-ast/__tests__/canonical-form.test.ts +1 -1
  173. package/src/engine/feature-ast/__tests__/parse-happy-path.test.ts +1 -1
  174. package/src/engine/feature-ast/__tests__/parse-real-features.test.ts +2 -2
  175. package/src/engine/feature-ast/__tests__/parse.test.ts +1 -1
  176. package/src/engine/feature-ast/__tests__/patch.test.ts +1 -1
  177. package/src/engine/feature-ast/__tests__/patcher.test.ts +1 -1
  178. package/src/engine/feature-ast/__tests__/render-roundtrip.test.ts +1 -1
  179. package/src/engine/feature-ast/__tests__/visual-tree-parse.test.ts +1 -1
  180. package/src/engine/feature-ast/extractors/shared.ts +2 -3
  181. package/src/engine/ownership.ts +113 -41
  182. package/src/engine/pattern-library/__tests__/library.test.ts +2 -2
  183. package/src/engine/projection-helpers.ts +2 -11
  184. package/src/engine/registry.ts +21 -2
  185. package/src/engine/steps/read-find-many.ts +13 -13
  186. package/src/engine/steps/read-find-one.ts +7 -9
  187. package/src/engine/steps/unsafe-projection-delete.ts +4 -5
  188. package/src/engine/steps/unsafe-projection-upsert.ts +63 -31
  189. package/src/engine/types/feature.ts +47 -2
  190. package/src/engine/types/fields.ts +4 -5
  191. package/src/engine/types/index.ts +2 -0
  192. package/src/engine/types/step.ts +10 -10
  193. package/src/engine/validate-projection-allowlist.ts +23 -3
  194. package/src/entrypoint/__tests__/{entrypoint-job-wiring.integration.ts → entrypoint-job-wiring.integration.test.ts} +4 -3
  195. package/src/entrypoint/__tests__/{split-deploy.integration.ts → split-deploy.integration.test.ts} +4 -3
  196. package/src/env/__tests__/compose-env-schema.test.ts +1 -1
  197. package/src/env/__tests__/dry-run.test.ts +1 -1
  198. package/src/errors/__tests__/classes.test.ts +1 -1
  199. package/src/errors/__tests__/error-helpers.test.ts +44 -0
  200. package/src/errors/__tests__/field-issue-compat.test.ts +16 -0
  201. package/src/errors/__tests__/write-failures.test.ts +1 -1
  202. package/src/errors/classes.ts +5 -19
  203. package/src/errors/field-issue.ts +11 -0
  204. package/src/errors/index.ts +1 -0
  205. package/src/errors/zod-bridge.ts +3 -2
  206. package/src/es-ops/__tests__/{context.integration.ts → context.integration.test.ts} +43 -29
  207. package/src/es-ops/__tests__/{runner.integration.ts → runner.integration.test.ts} +25 -23
  208. package/src/es-ops/__tests__/runner.test.ts +29 -19
  209. package/src/es-ops/context.ts +11 -56
  210. package/src/es-ops/operations-schema.ts +2 -2
  211. package/src/es-ops/runner.ts +12 -26
  212. package/src/event-store/__tests__/{admin-api.integration.ts → admin-api.integration.test.ts} +71 -45
  213. package/src/event-store/__tests__/{event-store.integration.ts → event-store.integration.test.ts} +7 -5
  214. package/src/event-store/__tests__/{get-stream-version-perf.integration.ts → get-stream-version-perf.integration.test.ts} +5 -3
  215. package/src/event-store/__tests__/{perf.integration.ts → perf.integration.test.ts} +24 -16
  216. package/src/event-store/__tests__/{snapshot.integration.ts → snapshot.integration.test.ts} +34 -28
  217. package/src/event-store/__tests__/{upcaster-dead-letter.integration.ts → upcaster-dead-letter.integration.test.ts} +11 -12
  218. package/src/event-store/__tests__/{upcaster.integration.ts → upcaster.integration.test.ts} +19 -32
  219. package/src/event-store/admin-api.ts +55 -83
  220. package/src/event-store/archive.ts +15 -39
  221. package/src/event-store/event-store.ts +92 -86
  222. package/src/event-store/events-schema.ts +2 -1
  223. package/src/event-store/index.ts +1 -0
  224. package/src/event-store/snapshot.ts +26 -24
  225. package/src/event-store/upcaster-dead-letter.ts +19 -18
  226. package/src/files/__tests__/content-disposition.test.ts +1 -1
  227. package/src/files/__tests__/{file-field-pipeline.integration.ts → file-field-pipeline.integration.test.ts} +8 -5
  228. package/src/files/__tests__/file-handle.test.ts +1 -1
  229. package/src/files/__tests__/{files.integration.ts → files.integration.test.ts} +32 -17
  230. package/src/files/__tests__/read-stream.test.ts +1 -1
  231. package/src/files/__tests__/{storage-tracking.integration.ts → storage-tracking.integration.test.ts} +26 -30
  232. package/src/files/__tests__/write-stream.test.ts +1 -1
  233. package/src/files/__tests__/zip-stream.test.ts +1 -1
  234. package/src/files/file-ref-table.ts +2 -2
  235. package/src/files/file-routes.ts +7 -9
  236. package/src/files/storage-tracking.ts +9 -17
  237. package/src/i18n/__tests__/i18n.test.ts +1 -1
  238. package/src/jobs/__tests__/{job-event-trigger.integration.ts → job-event-trigger.integration.test.ts} +6 -3
  239. package/src/jobs/__tests__/{job-multi-trigger.integration.ts → job-multi-trigger.integration.test.ts} +6 -3
  240. package/src/jobs/__tests__/{jobs.integration.ts → jobs.integration.test.ts} +5 -7
  241. package/src/lifecycle/__tests__/{lifecycle-server.integration.ts → lifecycle-server.integration.test.ts} +1 -1
  242. package/src/lifecycle/__tests__/lifecycle.test.ts +6 -6
  243. package/src/lifecycle/__tests__/signal-handlers.test.ts +6 -6
  244. package/src/logging/__tests__/pino-trace-bridge.test.ts +1 -1
  245. package/src/migrations/__tests__/compare-snapshots.test.ts +1 -1
  246. package/src/migrations/__tests__/{detect-drift.integration.ts → detect-drift.integration.test.ts} +34 -26
  247. package/src/migrations/__tests__/{detect-projections-to-rebuild.integration.ts → detect-projections-to-rebuild.integration.test.ts} +1 -1
  248. package/src/migrations/__tests__/rebuild-marker.test.ts +1 -1
  249. package/src/migrations/projection-detection.ts +12 -1
  250. package/src/migrations/schema-drift.ts +7 -23
  251. package/src/observability/__tests__/console-provider.test.ts +1 -1
  252. package/src/observability/__tests__/metric-validator.test.ts +1 -1
  253. package/src/observability/__tests__/noop-provider.test.ts +1 -1
  254. package/src/observability/__tests__/{observability.integration.ts → observability.integration.test.ts} +5 -8
  255. package/src/observability/__tests__/prometheus-meter.test.ts +1 -1
  256. package/src/observability/__tests__/recording-meter.test.ts +1 -1
  257. package/src/observability/__tests__/recording-tracer.test.ts +1 -1
  258. package/src/observability/__tests__/sensitive-filter.test.ts +1 -1
  259. package/src/pipeline/__tests__/{archive-stream.integration.ts → archive-stream.integration.test.ts} +3 -3
  260. package/src/pipeline/__tests__/auth-claims-resolver.test.ts +9 -9
  261. package/src/pipeline/__tests__/{cascade-handler.integration.ts → cascade-handler.integration.test.ts} +18 -15
  262. package/src/pipeline/__tests__/cascade-handler.test.ts +1 -1
  263. package/src/pipeline/__tests__/{causation-chain.integration.ts → causation-chain.integration.test.ts} +12 -13
  264. package/src/pipeline/__tests__/{ctx-bridge.integration.ts → ctx-bridge.integration.test.ts} +12 -11
  265. package/src/pipeline/__tests__/dispatcher-utils.test.ts +107 -0
  266. package/src/pipeline/__tests__/dispatcher.test.ts +2 -2
  267. package/src/pipeline/__tests__/{distributed-lock.integration.ts → distributed-lock.integration.test.ts} +1 -1
  268. package/src/pipeline/__tests__/{domain-events-projections.integration.ts → domain-events-projections.integration.test.ts} +13 -15
  269. package/src/pipeline/__tests__/{event-dedup.integration.ts → event-dedup.integration.test.ts} +1 -1
  270. package/src/pipeline/__tests__/{event-define-event-strict.integration.ts → event-define-event-strict.integration.test.ts} +6 -16
  271. package/src/pipeline/__tests__/{event-dispatcher-lifecycle.integration.ts → event-dispatcher-lifecycle.integration.test.ts} +1 -1
  272. package/src/pipeline/__tests__/{event-dispatcher-multi-instance.integration.ts → event-dispatcher-multi-instance.integration.test.ts} +3 -2
  273. package/src/pipeline/__tests__/{event-dispatcher-pg-listen.integration.ts → event-dispatcher-pg-listen.integration.test.ts} +1 -1
  274. package/src/pipeline/__tests__/{event-dispatcher-recovery.integration.ts → event-dispatcher-recovery.integration.test.ts} +2 -2
  275. package/src/pipeline/__tests__/{event-dispatcher-second-audit.integration.ts → event-dispatcher-second-audit.integration.test.ts} +17 -16
  276. package/src/pipeline/__tests__/event-dispatcher-strict.test.ts +14 -12
  277. package/src/pipeline/__tests__/{event-dispatcher.integration.ts → event-dispatcher.integration.test.ts} +8 -15
  278. package/src/pipeline/__tests__/{event-retention.integration.ts → event-retention.integration.test.ts} +28 -25
  279. package/src/pipeline/__tests__/{fetch-for-writing.integration.ts → fetch-for-writing.integration.test.ts} +6 -6
  280. package/src/pipeline/__tests__/lifecycle-pipeline.test.ts +4 -4
  281. package/src/pipeline/__tests__/{load-aggregate-query.integration.ts → load-aggregate-query.integration.test.ts} +9 -5
  282. package/src/pipeline/__tests__/{msp-error-mode.integration.ts → msp-error-mode.integration.test.ts} +1 -1
  283. package/src/pipeline/__tests__/{msp-multi-hop.integration.ts → msp-multi-hop.integration.test.ts} +9 -8
  284. package/src/pipeline/__tests__/{msp-rebuild.integration.ts → msp-rebuild.integration.test.ts} +47 -55
  285. package/src/pipeline/__tests__/{multi-stream-projection.integration.ts → multi-stream-projection.integration.test.ts} +19 -53
  286. package/src/pipeline/__tests__/{perf-rebuild.integration.ts → perf-rebuild.integration.test.ts} +36 -34
  287. package/src/pipeline/__tests__/{post-query-hook.integration.ts → post-query-hook.integration.test.ts} +1 -1
  288. package/src/pipeline/__tests__/{projection-rebuild.integration.ts → projection-rebuild.integration.test.ts} +21 -30
  289. package/src/pipeline/__tests__/{query-projection.integration.ts → query-projection.integration.test.ts} +6 -5
  290. package/src/pipeline/__tests__/redis-keys.test.ts +12 -0
  291. package/src/pipeline/__tests__/{redis-pipeline.integration.ts → redis-pipeline.integration.test.ts} +3 -1
  292. package/src/pipeline/cascade-handler.ts +13 -21
  293. package/src/pipeline/dispatcher-utils.ts +8 -7
  294. package/src/pipeline/dispatcher.ts +43 -48
  295. package/src/pipeline/event-consumer-state.ts +11 -2
  296. package/src/pipeline/event-dispatcher.ts +86 -146
  297. package/src/pipeline/event-retention.ts +14 -24
  298. package/src/pipeline/msp-rebuild.ts +54 -78
  299. package/src/pipeline/projection-rebuild.ts +65 -67
  300. package/src/pipeline/projection-state.ts +2 -2
  301. package/src/random/__tests__/generate.test.ts +13 -13
  302. package/src/rate-limit/__tests__/{dispatcher-l3.integration.ts → dispatcher-l3.integration.test.ts} +1 -1
  303. package/src/rate-limit/__tests__/{middleware.integration.ts → middleware.integration.test.ts} +1 -1
  304. package/src/rate-limit/__tests__/{resolver.integration.ts → resolver.integration.test.ts} +1 -1
  305. package/src/redis/__tests__/redis-options.test.ts +1 -1
  306. package/src/search/__tests__/{meilisearch-adapter.integration.ts → meilisearch-adapter.integration.test.ts} +1 -1
  307. package/src/search/__tests__/search-adapter.test.ts +1 -1
  308. package/src/secrets/__tests__/dek-cache.test.ts +1 -3
  309. package/src/secrets/__tests__/env-master-key-provider.test.ts +1 -1
  310. package/src/secrets/__tests__/envelope.test.ts +1 -1
  311. package/src/secrets/__tests__/leak-guard.test.ts +1 -1
  312. package/src/secrets/__tests__/rotation.test.ts +1 -1
  313. package/src/stack/db.ts +25 -48
  314. package/src/stack/push-entity-projection-tables.ts +2 -4
  315. package/src/stack/table-helpers.ts +98 -61
  316. package/src/stack/test-stack.ts +10 -9
  317. package/src/testing/__tests__/db-cleanup.test.ts +40 -0
  318. package/src/testing/__tests__/e2e-generator.test.ts +1 -1
  319. package/src/testing/__tests__/{ensure-entity-table.integration.ts → ensure-entity-table.integration.test.ts} +7 -14
  320. package/src/testing/db-cleanup.ts +44 -0
  321. package/src/testing/expect-error.ts +1 -1
  322. package/src/testing/index.ts +2 -0
  323. package/src/testing/multipart-helper.ts +94 -0
  324. package/src/testing/shared-entities.ts +5 -5
  325. package/src/time/__tests__/polyfill.test.ts +1 -1
  326. package/src/time/__tests__/tz-context.test.ts +1 -1
  327. package/src/utils/__tests__/assert.test.ts +1 -1
  328. package/src/utils/__tests__/case.test.ts +16 -0
  329. package/src/utils/__tests__/env-parse.test.ts +1 -1
  330. package/src/utils/__tests__/is-plain-object.test.ts +16 -0
  331. package/src/utils/__tests__/parse-string-array-json.test.ts +16 -0
  332. package/src/utils/__tests__/safe-json.test.ts +22 -0
  333. package/src/utils/case.ts +6 -0
  334. package/src/utils/index.ts +3 -0
  335. package/src/utils/is-plain-object.ts +4 -0
  336. package/src/utils/parse-string-array-json.ts +14 -0
  337. package/CHANGELOG.md +0 -474
  338. package/src/db/__tests__/db-helpers.test.ts +0 -369
  339. package/src/db/__tests__/drizzle-helpers.integration.ts +0 -186
  340. package/src/db/__tests__/row-helpers.test.ts +0 -59
  341. package/src/engine/steps/_drizzle-boundary.ts +0 -19
  342. package/src/files/__tests__/file-field-column.integration.ts +0 -103
@@ -1,4 +1,4 @@
1
- import { afterAll, beforeAll, describe, expect, test } from "vitest";
1
+ import { afterAll, beforeAll, describe, expect, test } from "bun:test";
2
2
  import { requestContext } from "../../api/request-context";
3
3
  import { createRegistry, defineFeature } from "../../engine";
4
4
  import type { AppContext, Registry } from "../../engine/types";
@@ -192,7 +192,7 @@ describe("scenario 2: scheduled job", () => {
192
192
 
193
193
  // BullMQ's repeatable scheduler needs a second or two to register its
194
194
  // first tick — a generous delay schedule covers the startup window.
195
- test("cron job fires via BullMQ scheduler", { timeout: 15_000 }, async () => {
195
+ test("cron job fires via BullMQ scheduler", async () => {
196
196
  clearLog();
197
197
  await withRunner(async () => {
198
198
  await waitFor(
@@ -278,7 +278,7 @@ describe("concurrency: skip", () => {
278
278
  });
279
279
 
280
280
  describe("concurrency: sequential", () => {
281
- test("same-name dispatches run strictly one after the other", { timeout: 15_000 }, async () => {
281
+ test("same-name dispatches run strictly one after the other", async () => {
282
282
  clearLog();
283
283
  await withRunner(async (runner) => {
284
284
  // Three rapid dispatches. Parallel mode would land all entries
@@ -318,7 +318,7 @@ describe("concurrency: sequential", () => {
318
318
  });
319
319
  });
320
320
 
321
- test("lock is released even when the handler throws", { timeout: 10_000 }, async () => {
321
+ test("lock is released even when the handler throws", async () => {
322
322
  clearLog();
323
323
  await withRunner(async (runner) => {
324
324
  // First dispatch fails. If the finally-path didn't release the lock,
@@ -355,9 +355,7 @@ describe("concurrency: sequential", () => {
355
355
  });
356
356
  });
357
357
 
358
- test("lock release is value-matched: foreign tokens survive expiration races", {
359
- timeout: 5_000,
360
- }, async () => {
358
+ test("lock release is value-matched: foreign tokens survive expiration races", async () => {
361
359
  // Pin the contract that distributed-lock's release script enforces:
362
360
  // a release call from a worker whose token has already expired and
363
361
  // been claimed by someone else must NOT delete the new owner's lock.
@@ -1,7 +1,7 @@
1
1
  // Full-stack proof for lifecycle ↔ buildServer wiring.
2
2
  // Drives drain() directly — SIGTERM plumbing has its own unit test.
3
3
 
4
- import { afterAll, afterEach, beforeAll, describe, expect, test } from "vitest";
4
+ import { afterAll, afterEach, beforeAll, describe, expect, test } from "bun:test";
5
5
  import { defineFeature } from "../../engine";
6
6
  import { setupTestStack, type TestStack } from "../../stack";
7
7
  import { sharedWidgetEntity } from "../../testing";
@@ -1,4 +1,4 @@
1
- import { describe, expect, test, vi } from "vitest";
1
+ import { describe, expect, mock, test } from "bun:test";
2
2
  import { createLifecycle } from "../lifecycle";
3
3
 
4
4
  describe("lifecycle — state machine", () => {
@@ -20,7 +20,7 @@ describe("lifecycle — state machine", () => {
20
20
 
21
21
  test("markReady from 'ready' is a no-op", () => {
22
22
  const lc = createLifecycle({ startReady: true });
23
- const listener = vi.fn();
23
+ const listener = mock();
24
24
  lc.onStateChange(listener);
25
25
  lc.markReady();
26
26
  expect(listener).not.toHaveBeenCalled();
@@ -70,7 +70,7 @@ describe("lifecycle — shutdown hooks", () => {
70
70
  });
71
71
 
72
72
  test("one failing hook does not block the others, and the error is logged", async () => {
73
- const logger = { error: vi.fn() };
73
+ const logger = { error: mock() };
74
74
  const lc = createLifecycle({ startReady: true, logger });
75
75
  const calls: string[] = [];
76
76
  lc.registerShutdownHook("healthy-a", async () => {
@@ -171,7 +171,7 @@ describe("lifecycle — onStateChange", () => {
171
171
 
172
172
  test("unsubscribe stops further callbacks", () => {
173
173
  const lc = createLifecycle();
174
- const cb = vi.fn();
174
+ const cb = mock();
175
175
  const unsubscribe = lc.onStateChange(cb);
176
176
  lc.markReady();
177
177
  expect(cb).toHaveBeenCalledTimes(1);
@@ -184,9 +184,9 @@ describe("lifecycle — onStateChange", () => {
184
184
  });
185
185
 
186
186
  test("broken listener does not break others, and the error is logged", () => {
187
- const logger = { error: vi.fn() };
187
+ const logger = { error: mock() };
188
188
  const lc = createLifecycle({ logger });
189
- const healthy = vi.fn();
189
+ const healthy = mock();
190
190
  lc.onStateChange(() => {
191
191
  throw new Error("subscriber exploded");
192
192
  });
@@ -1,4 +1,4 @@
1
- import { describe, expect, test, vi } from "vitest";
1
+ import { describe, expect, mock, test } from "bun:test";
2
2
  import { createLifecycle } from "../lifecycle";
3
3
  import { attachSignalHandlers } from "../signal-handlers";
4
4
  import { createTestLifecycle } from "./create-test-lifecycle";
@@ -6,7 +6,7 @@ import { createTestLifecycle } from "./create-test-lifecycle";
6
6
  describe("attachSignalHandlers", () => {
7
7
  test("SIGTERM triggers drain and calls exit(0)", async () => {
8
8
  const lc = createLifecycle({ startReady: true });
9
- const exit = vi.fn();
9
+ const exit = mock();
10
10
  const hookCalls: string[] = [];
11
11
  lc.registerShutdownHook("spy", async (signal) => {
12
12
  hookCalls.push(signal);
@@ -25,7 +25,7 @@ describe("attachSignalHandlers", () => {
25
25
 
26
26
  test("SIGINT path drains with the right signal label", async () => {
27
27
  const lc = createLifecycle({ startReady: true });
28
- const exit = vi.fn();
28
+ const exit = mock();
29
29
  const seen: string[] = [];
30
30
  lc.registerShutdownHook("spy", async (signal) => {
31
31
  seen.push(signal);
@@ -44,7 +44,7 @@ describe("attachSignalHandlers", () => {
44
44
 
45
45
  test("multiple SIGTERMs still call exit exactly once", async () => {
46
46
  const lc = createLifecycle({ startReady: true });
47
- const exit = vi.fn();
47
+ const exit = mock();
48
48
  // Slow hook so we can fire additional signals while drain is in-flight.
49
49
  lc.registerShutdownHook("slow", async () => {
50
50
  await new Promise((r) => setTimeout(r, 30));
@@ -74,7 +74,7 @@ describe("attachSignalHandlers", () => {
74
74
  throw new Error("drain itself exploded");
75
75
  },
76
76
  });
77
- const exit = vi.fn();
77
+ const exit = mock();
78
78
  const handle = attachSignalHandlers(brokenLifecycle, { exit, signals: ["SIGTERM"] });
79
79
  try {
80
80
  process.emit("SIGTERM");
@@ -87,7 +87,7 @@ describe("attachSignalHandlers", () => {
87
87
 
88
88
  test("detach() removes the process listeners", () => {
89
89
  const lc = createLifecycle({ startReady: true });
90
- const exit = vi.fn();
90
+ const exit = mock();
91
91
  const before = process.listenerCount("SIGTERM");
92
92
  const handle = attachSignalHandlers(lc, { exit, signals: ["SIGTERM"] });
93
93
  expect(process.listenerCount("SIGTERM")).toBe(before + 1);
@@ -1,4 +1,4 @@
1
- import { describe, expect, it } from "vitest";
1
+ import { describe, expect, it } from "bun:test";
2
2
  import { createConsoleProvider } from "../../observability";
3
3
  import { mergeTraceFields } from "../pino-logger";
4
4
 
@@ -3,7 +3,7 @@
3
3
  // Projection-Tabelle muss der Detector die richtigen Tabellen-Namen
4
4
  // melden, damit migrate apply den richtigen Rebuild triggert.
5
5
 
6
- import { describe, expect, test } from "vitest";
6
+ import { describe, expect, test } from "bun:test";
7
7
  import { compareSnapshots } from "../projection-detection";
8
8
  import type { Snapshot, SnapshotTable } from "../schema-drift";
9
9
 
@@ -4,18 +4,20 @@
4
4
  // hier blockiert Container-Starts; jeder False-Negative lässt
5
5
  // Schema-Drift unentdeckt durch.
6
6
 
7
+ import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, test } from "bun:test";
7
8
  import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
8
9
  import { tmpdir } from "node:os";
9
10
  import { join } from "node:path";
10
- import { sql } from "drizzle-orm";
11
- import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, test } from "vitest";
12
- import { createTestDb, type TestDb } from "../../stack";
11
+ import { type BunTestDb, createTestDb } from "../../bun-db/__tests__/bun-test-db";
12
+ import { asRawClient } from "../../db/query";
13
+ import { ensureTemporalPolyfill } from "../../time/polyfill";
13
14
  import { detectDrift } from "../schema-drift";
14
15
 
15
- let testDb: TestDb;
16
+ let testDb: BunTestDb;
16
17
  let migrationsDir: string;
17
18
 
18
19
  beforeAll(async () => {
20
+ await ensureTemporalPolyfill();
19
21
  testDb = await createTestDb();
20
22
  });
21
23
 
@@ -82,8 +84,8 @@ function writeSnapshotSimple(idx: number, tableNames: string[]): void {
82
84
  }
83
85
 
84
86
  async function ensureDrizzleMigrationsTable(): Promise<void> {
85
- await testDb.db.execute(sql`CREATE SCHEMA IF NOT EXISTS drizzle`);
86
- await testDb.db.execute(sql`
87
+ await asRawClient(testDb.db).unsafe(`CREATE SCHEMA IF NOT EXISTS drizzle`);
88
+ await asRawClient(testDb.db).unsafe(`
87
89
  CREATE TABLE IF NOT EXISTS drizzle.__drizzle_migrations (
88
90
  id serial PRIMARY KEY,
89
91
  hash text NOT NULL,
@@ -93,12 +95,13 @@ async function ensureDrizzleMigrationsTable(): Promise<void> {
93
95
  }
94
96
 
95
97
  async function dropDrizzleMigrationsTable(): Promise<void> {
96
- await testDb.db.execute(sql`DROP TABLE IF EXISTS drizzle.__drizzle_migrations`);
98
+ await asRawClient(testDb.db).unsafe(`DROP TABLE IF EXISTS drizzle.__drizzle_migrations`);
97
99
  }
98
100
 
99
101
  async function insertAppliedMigration(hash: string): Promise<void> {
100
- await testDb.db.execute(
101
- sql`INSERT INTO drizzle.__drizzle_migrations (hash, created_at) VALUES (${hash}, ${Date.now()})`,
102
+ await asRawClient(testDb.db).unsafe(
103
+ `INSERT INTO drizzle.__drizzle_migrations (hash, created_at) VALUES ($1, $2)`,
104
+ [hash, Date.now()],
102
105
  );
103
106
  }
104
107
 
@@ -106,8 +109,8 @@ describe("detectDrift", () => {
106
109
  beforeEach(async () => {
107
110
  await dropDrizzleMigrationsTable();
108
111
  // Cleanup test tables that might still exist from earlier runs
109
- await testDb.db.execute(sql`DROP TABLE IF EXISTS drift_test_users`);
110
- await testDb.db.execute(sql`DROP TABLE IF EXISTS drift_test_orders`);
112
+ await asRawClient(testDb.db).unsafe(`DROP TABLE IF EXISTS drift_test_users`);
113
+ await asRawClient(testDb.db).unsafe(`DROP TABLE IF EXISTS drift_test_orders`);
111
114
  });
112
115
 
113
116
  test("frische DB ohne __drizzle_migrations + 1 Migration im Journal → 1 pending + table missing", async () => {
@@ -124,7 +127,7 @@ describe("detectDrift", () => {
124
127
  test("alle Migrations applied + alle Tabellen existieren → ok", async () => {
125
128
  writeJournal([{ idx: 0, tag: "0000_init" }]);
126
129
  writeSnapshotSimple(0, ["drift_test_users"]);
127
- await testDb.db.execute(sql`CREATE TABLE drift_test_users (id uuid PRIMARY KEY)`);
130
+ await asRawClient(testDb.db).unsafe(`CREATE TABLE drift_test_users (id uuid PRIMARY KEY)`);
128
131
  await ensureDrizzleMigrationsTable();
129
132
  await insertAppliedMigration("hash-0000");
130
133
 
@@ -140,8 +143,8 @@ describe("detectDrift", () => {
140
143
  { idx: 1, tag: "0001_add_orders" },
141
144
  ]);
142
145
  writeSnapshotSimple(1, ["drift_test_users", "drift_test_orders"]);
143
- await testDb.db.execute(sql`CREATE TABLE drift_test_users (id uuid PRIMARY KEY)`);
144
- await testDb.db.execute(sql`CREATE TABLE drift_test_orders (id uuid PRIMARY KEY)`);
146
+ await asRawClient(testDb.db).unsafe(`CREATE TABLE drift_test_users (id uuid PRIMARY KEY)`);
147
+ await asRawClient(testDb.db).unsafe(`CREATE TABLE drift_test_orders (id uuid PRIMARY KEY)`);
145
148
  await ensureDrizzleMigrationsTable();
146
149
  await insertAppliedMigration("hash-0000"); // nur eine applied
147
150
 
@@ -155,7 +158,7 @@ describe("detectDrift", () => {
155
158
  test("alle Migrations applied aber Tabelle fehlt manuell → drift", async () => {
156
159
  writeJournal([{ idx: 0, tag: "0000_init" }]);
157
160
  writeSnapshotSimple(0, ["drift_test_users", "drift_test_orders"]);
158
- await testDb.db.execute(sql`CREATE TABLE drift_test_users (id uuid PRIMARY KEY)`);
161
+ await asRawClient(testDb.db).unsafe(`CREATE TABLE drift_test_users (id uuid PRIMARY KEY)`);
159
162
  // drift_test_orders bewusst NICHT angelegt (simuliert manuellen DROP)
160
163
  await ensureDrizzleMigrationsTable();
161
164
  await insertAppliedMigration("hash-0000");
@@ -179,7 +182,9 @@ describe("detectDrift", () => {
179
182
  },
180
183
  ]);
181
184
  // DB hat email NULLABLE — drift.
182
- await testDb.db.execute(sql`CREATE TABLE drift_test_users (id uuid PRIMARY KEY, email text)`);
185
+ await asRawClient(testDb.db).unsafe(
186
+ `CREATE TABLE drift_test_users (id uuid PRIMARY KEY, email text)`,
187
+ );
183
188
  await ensureDrizzleMigrationsTable();
184
189
  await insertAppliedMigration("hash-0000");
185
190
 
@@ -204,7 +209,7 @@ describe("detectDrift", () => {
204
209
  },
205
210
  ]);
206
211
  // DB hat KEINE email-Spalte.
207
- await testDb.db.execute(sql`CREATE TABLE drift_test_users (id uuid PRIMARY KEY)`);
212
+ await asRawClient(testDb.db).unsafe(`CREATE TABLE drift_test_users (id uuid PRIMARY KEY)`);
208
213
  await ensureDrizzleMigrationsTable();
209
214
  await insertAppliedMigration("hash-0000");
210
215
 
@@ -226,8 +231,8 @@ describe("detectDrift", () => {
226
231
  },
227
232
  ]);
228
233
  // DB hat zusätzliche Spalte (z.B. manueller ALTER TABLE in Prod).
229
- await testDb.db.execute(
230
- sql`CREATE TABLE drift_test_users (id uuid PRIMARY KEY, secret_legacy text)`,
234
+ await asRawClient(testDb.db).unsafe(
235
+ `CREATE TABLE drift_test_users (id uuid PRIMARY KEY, secret_legacy text)`,
231
236
  );
232
237
  await ensureDrizzleMigrationsTable();
233
238
  await insertAppliedMigration("hash-0000");
@@ -251,7 +256,9 @@ describe("detectDrift", () => {
251
256
  },
252
257
  ]);
253
258
  // DB hat age als TEXT statt INTEGER.
254
- await testDb.db.execute(sql`CREATE TABLE drift_test_users (id uuid PRIMARY KEY, age text)`);
259
+ await asRawClient(testDb.db).unsafe(
260
+ `CREATE TABLE drift_test_users (id uuid PRIMARY KEY, age text)`,
261
+ );
255
262
  await ensureDrizzleMigrationsTable();
256
263
  await insertAppliedMigration("hash-0000");
257
264
 
@@ -278,7 +285,7 @@ describe("detectDrift", () => {
278
285
  },
279
286
  },
280
287
  ]);
281
- await testDb.db.execute(sql`
288
+ await asRawClient(testDb.db).unsafe(`
282
289
  CREATE TABLE drift_test_users (
283
290
  id uuid PRIMARY KEY,
284
291
  email text NOT NULL,
@@ -297,10 +304,10 @@ describe("detectDrift", () => {
297
304
  test("public.__drizzle_migrations Fallback (Pre-0.20-Drizzle)", async () => {
298
305
  writeJournal([{ idx: 0, tag: "0000_init" }]);
299
306
  writeSnapshotSimple(0, ["drift_test_users"]);
300
- await testDb.db.execute(sql`CREATE TABLE drift_test_users (id uuid PRIMARY KEY)`);
307
+ await asRawClient(testDb.db).unsafe(`CREATE TABLE drift_test_users (id uuid PRIMARY KEY)`);
301
308
  // Legacy: Tabelle in public-Schema statt drizzle-Schema
302
309
  await dropDrizzleMigrationsTable();
303
- await testDb.db.execute(sql`
310
+ await asRawClient(testDb.db).unsafe(`
304
311
  CREATE TABLE public.__drizzle_migrations (
305
312
  id serial PRIMARY KEY,
306
313
  hash text NOT NULL,
@@ -308,13 +315,14 @@ describe("detectDrift", () => {
308
315
  )
309
316
  `);
310
317
  try {
311
- await testDb.db.execute(
312
- sql`INSERT INTO public.__drizzle_migrations (hash, created_at) VALUES ('hash-0000', ${Date.now()})`,
318
+ await asRawClient(testDb.db).unsafe(
319
+ `INSERT INTO public.__drizzle_migrations (hash, created_at) VALUES ('hash-0000', $1)`,
320
+ [Date.now()],
313
321
  );
314
322
  const report = await detectDrift(testDb.db, migrationsDir);
315
323
  expect(report.ok).toBe(true);
316
324
  } finally {
317
- await testDb.db.execute(sql`DROP TABLE public.__drizzle_migrations`);
325
+ await asRawClient(testDb.db).unsafe(`DROP TABLE public.__drizzle_migrations`);
318
326
  }
319
327
  });
320
328
  });
@@ -8,10 +8,10 @@
8
8
  // Sprint-G-Pieces nebeneinander leben aber sich nicht treffen — Marker
9
9
  // wäre leer, kein Rebuild würde ausgelöst.
10
10
 
11
+ import { afterEach, beforeEach, describe, expect, test } from "bun:test";
11
12
  import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
12
13
  import { tmpdir } from "node:os";
13
14
  import { join } from "node:path";
14
- import { afterEach, beforeEach, describe, expect, test } from "vitest";
15
15
  import { createBooleanField, createEntity, createTextField, defineFeature } from "../../engine";
16
16
  import { createRegistry } from "../../engine/registry";
17
17
  import { detectProjectionsToRebuild } from "../projection-detection";
@@ -4,10 +4,10 @@
4
4
  // - schemaVersion-Mismatch wirft (verhindert dass alte Markers gegen
5
5
  // neue Lese-Logik fahren)
6
6
 
7
+ import { afterEach, beforeEach, describe, expect, test } from "bun:test";
7
8
  import { mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
8
9
  import { tmpdir } from "node:os";
9
10
  import { join } from "node:path";
10
- import { afterEach, beforeEach, describe, expect, test } from "vitest";
11
11
  import { readRebuildMarker, writeRebuildMarker } from "../rebuild-marker";
12
12
 
13
13
  let tmpDir: string;
@@ -11,7 +11,6 @@
11
11
  // Damit muss niemand Tabellen-Namen doppelt pflegen (Truth liegt in der
12
12
  // Projection-Definition).
13
13
 
14
- import { getTableName } from "drizzle-orm";
15
14
  import type { Registry } from "../engine/types/feature";
16
15
  import {
17
16
  type ColumnSpec,
@@ -90,6 +89,18 @@ function sameColumns(
90
89
  return true;
91
90
  }
92
91
 
92
+ const KUMIKO_NAME_SYMBOL = Symbol.for("kumiko:schema:Name");
93
+ function getTableName(table: unknown): string {
94
+ if (typeof table !== "object" || table === null) {
95
+ throw new Error("projection-detection: table is not a pgTable object");
96
+ }
97
+ const name = (table as Record<symbol, unknown>)[KUMIKO_NAME_SYMBOL];
98
+ if (typeof name !== "string") {
99
+ throw new Error("projection-detection: table missing drizzle name symbol");
100
+ }
101
+ return name;
102
+ }
103
+
93
104
  /** Index `tableName → projection-name` aus der Registry. Nur Projections
94
105
  * mit table-Definition (single-stream + multi-stream-with-table) zählen.
95
106
  * Side-effect-only MSPs (table omitted) haben keinen Rebuild-Sinn. */
@@ -9,7 +9,7 @@
9
9
  // 3. Column-Diff: information_schema-Vergleich gegen Snapshot —
10
10
  // missing-/extra-column, type-mismatch, nullability-mismatch. Fängt
11
11
  // manuelle ALTER TABLEs in Prod sowie doppelte pgTable-Definitionen
12
- // pro Tabelle (eine hand-written, eine via buildDrizzleTable), die
12
+ // pro Tabelle (eine hand-written, eine via buildEntityTable), die
13
13
  // stillschweigend gegen den Snapshot driften.
14
14
  //
15
15
  // Drizzle-kit's eigene Garantie: nach `migrate apply` ist der DB-Stand
@@ -19,8 +19,8 @@
19
19
 
20
20
  import { readFileSync } from "node:fs";
21
21
  import { resolve } from "node:path";
22
- import { sql } from "drizzle-orm";
23
22
  import type { DbConnection } from "../db/connection";
23
+ import { selectAppliedMigrations, selectPublicTableColumns } from "../db/queries/schema-drift";
24
24
  import { tableExists } from "../db/schema-inspection";
25
25
  import { parseJsonOrThrow } from "../utils/safe-json";
26
26
 
@@ -125,16 +125,10 @@ export async function loadAppliedMigrations(db: DbConnection): Promise<AppliedMi
125
125
  ? false
126
126
  : await tableExists(db, "public.__drizzle_migrations");
127
127
  if (!drizzleSchemaExists && !publicSchemaExists) return [];
128
- // sql.identifier mit qualifiziertem Namen: erstes Argument = Schema,
129
- // zweites = Tabellenname. Drizzle quotet beides defensiv.
130
- const tableRef = drizzleSchemaExists
131
- ? sql`drizzle.__drizzle_migrations`
132
- : sql`public.__drizzle_migrations`;
133
- const rows = await db.execute<{ hash: string; created_at: bigint | number | null }>(sql`
134
- SELECT hash, created_at
135
- FROM ${tableRef}
136
- ORDER BY id
137
- `);
128
+ const rows = await selectAppliedMigrations(
129
+ db,
130
+ drizzleSchemaExists ? "drizzle.__drizzle_migrations" : "public.__drizzle_migrations",
131
+ );
138
132
  return rows.map((r) => ({
139
133
  hash: r.hash,
140
134
  createdAt: typeof r.created_at === "bigint" ? Number(r.created_at) : (r.created_at ?? 0),
@@ -143,12 +137,6 @@ export async function loadAppliedMigrations(db: DbConnection): Promise<AppliedMi
143
137
 
144
138
  // --- Column-Diff (Welle 2 Boot-Gate Layer 3) ---
145
139
 
146
- type DbColumnRow = {
147
- readonly column_name: string;
148
- readonly data_type: string;
149
- readonly is_nullable: "YES" | "NO";
150
- };
151
-
152
140
  /** Liest information_schema.columns für eine Tabelle im public-Schema.
153
141
  * Map by column_name. Default-Werte werden bewusst ausgelassen — die
154
142
  * drift'en über drizzle-Versionen / PG-Reformulierungen hinweg ohne dass
@@ -158,11 +146,7 @@ async function loadDbColumns(
158
146
  db: DbConnection,
159
147
  tableName: string,
160
148
  ): Promise<ReadonlyMap<string, { type: string; notNull: boolean }>> {
161
- const rows = await db.execute<DbColumnRow>(sql`
162
- SELECT column_name, data_type, is_nullable
163
- FROM information_schema.columns
164
- WHERE table_schema = 'public' AND table_name = ${tableName}
165
- `);
149
+ const rows = await selectPublicTableColumns(db, tableName);
166
150
  const map = new Map<string, { type: string; notNull: boolean }>();
167
151
  for (const r of rows) {
168
152
  map.set(r.column_name, {
@@ -1,4 +1,4 @@
1
- import { describe, expect, it } from "vitest";
1
+ import { describe, expect, it } from "bun:test";
2
2
  import { createConsoleProvider } from "../console-provider";
3
3
 
4
4
  function makeProvider() {
@@ -1,4 +1,4 @@
1
- import { describe, expect, it } from "vitest";
1
+ import { describe, expect, it } from "bun:test";
2
2
  import { buildMetricName, validateLabelKey, validateMetricName } from "../metric-validator";
3
3
 
4
4
  describe("validateMetricName", () => {
@@ -1,4 +1,4 @@
1
- import { describe, expect, it } from "vitest";
1
+ import { describe, expect, it } from "bun:test";
2
2
  import { createNoopProvider } from "../noop-provider";
3
3
 
4
4
  describe("NoopProvider", () => {
@@ -1,6 +1,6 @@
1
- import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
1
+ import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it } from "bun:test";
2
2
  import { z } from "zod";
3
- import { buildDrizzleTable } from "../../db/table-builder";
3
+ import { buildEntityTable } from "../../db/table-builder";
4
4
  import { createRegistry, defineFeature } from "../../engine";
5
5
  import type { AppContext, SaveContext } from "../../engine/types";
6
6
  import { createJobRunner } from "../../jobs";
@@ -65,18 +65,15 @@ const todoEntity = {
65
65
 
66
66
  let postSaveInvocations = 0;
67
67
  const todoFeature = defineFeature("todo", (r) => {
68
- const todoTable = buildDrizzleTable("todo", todoEntity);
68
+ const todoTable = buildEntityTable("todo", todoEntity);
69
69
  r.entity("todo", todoEntity);
70
70
 
71
71
  r.writeHandler(
72
72
  "create",
73
73
  z.object({ title: z.string() }),
74
74
  async (event, ctx) => {
75
- const rows = await ctx.db
76
- .insert(todoTable)
77
- .values({ title: event.payload.title })
78
- .returning();
79
- const row = rows[0] as { id: number; title: string };
75
+ const rows = await ctx.db.insertOne(todoTable, { title: event.payload.title });
76
+ const row = rows as { id: number; title: string };
80
77
  return {
81
78
  isSuccess: true,
82
79
  data: {
@@ -1,4 +1,4 @@
1
- import { describe, expect, test } from "vitest";
1
+ import { describe, expect, test } from "bun:test";
2
2
  import { createPrometheusMeter, serializeOpenMetrics } from "../prometheus-meter";
3
3
 
4
4
  describe("PrometheusMeter — accumulation", () => {
@@ -1,4 +1,4 @@
1
- import { describe, expect, it } from "vitest";
1
+ import { describe, expect, it } from "bun:test";
2
2
  import { type MetricEvent, RecordingMeter } from "../recording-meter";
3
3
 
4
4
  function makeMeter() {
@@ -1,4 +1,4 @@
1
- import { describe, expect, it } from "vitest";
1
+ import { describe, expect, it } from "bun:test";
2
2
  import { type RecordedSpan, RecordingTracer } from "../recording-tracer";
3
3
  import { DEFAULT_SENSITIVE_CONFIG } from "../sensitive-filter";
4
4
 
@@ -1,4 +1,4 @@
1
- import { describe, expect, it } from "vitest";
1
+ import { describe, expect, it } from "bun:test";
2
2
  import {
3
3
  DEFAULT_SENSITIVE_CONFIG,
4
4
  mergeSensitiveConfig,
@@ -5,10 +5,10 @@
5
5
  // Kumiko carries this as a sparse kumiko_archived_streams table so active
6
6
  // streams never pay for extra metadata writes.
7
7
 
8
- import { afterAll, afterEach, beforeAll, describe, expect, test } from "vitest";
8
+ import { afterAll, afterEach, beforeAll, describe, expect, test } from "bun:test";
9
9
  import { z } from "zod";
10
10
  import { createEventStoreExecutor } from "../../db/event-store-executor";
11
- import { buildDrizzleTable } from "../../db/table-builder";
11
+ import { buildEntityTable } from "../../db/table-builder";
12
12
  import { createEntity, createTextField, defineFeature } from "../../engine";
13
13
  import {
14
14
  ArchivedStreamError,
@@ -27,7 +27,7 @@ const itemEntity = createEntity({
27
27
  table: "read_arch_items",
28
28
  fields: { label: createTextField({ required: true }) },
29
29
  });
30
- const itemTable = buildDrizzleTable("arch-item", itemEntity);
30
+ const itemTable = buildEntityTable("arch-item", itemEntity);
31
31
 
32
32
  const archFeature = defineFeature("archtest", (r) => {
33
33
  r.entity("arch-item", itemEntity);
@@ -1,18 +1,18 @@
1
- import { describe, expect, test, vi } from "vitest";
1
+ import { describe, expect, mock, test } from "bun:test";
2
2
  import type { AuthClaimsContext, AuthClaimsHookDef, SessionUser } from "../../engine/types";
3
3
  import type { Logger } from "../../logging/types";
4
4
  import { resolveAuthClaims } from "../auth-claims-resolver";
5
5
 
6
6
  type TestLogger = {
7
7
  readonly log: Logger;
8
- readonly warn: ReturnType<typeof vi.fn>;
8
+ readonly warn: ReturnType<typeof mock>;
9
9
  };
10
10
 
11
11
  function makeTestLogger(): TestLogger {
12
- const warn = vi.fn();
13
- const info = vi.fn();
14
- const error = vi.fn();
15
- const debug = vi.fn();
12
+ const warn = mock();
13
+ const info = mock();
14
+ const error = mock();
15
+ const debug = mock();
16
16
  const logger: Logger = {
17
17
  warn,
18
18
  info,
@@ -45,7 +45,7 @@ function hooks(...entries: AuthClaimsHookDef[]): readonly AuthClaimsHookDef[] {
45
45
 
46
46
  describe("resolveAuthClaims — empty", () => {
47
47
  test("zero hooks registered → empty record, contextFactory not called", async () => {
48
- const factory = vi.fn();
48
+ const factory = mock();
49
49
  const result = await resolveAuthClaims({
50
50
  user: testUser,
51
51
  hooks: [],
@@ -73,8 +73,8 @@ describe("resolveAuthClaims — single hook", () => {
73
73
  });
74
74
 
75
75
  test("receives the user and context handed in", async () => {
76
- const fn = vi.fn(async () => ({}));
77
- const factory = vi.fn(() => stubContext);
76
+ const fn = mock(async () => ({}));
77
+ const factory = mock(() => stubContext);
78
78
  await resolveAuthClaims({
79
79
  user: testUser,
80
80
  hooks: hooks({ featureName: "any", fn }),