@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,5 +1,5 @@
1
- import { eq } from "drizzle-orm";
2
1
  import type { TableColumns } from "../db/dialect";
2
+ import { deleteMany, fetchOne, updateMany } from "../db/query";
3
3
  import { OnDeleteStrategies, SystemHookNames, SystemHookPriorities } from "../engine/constants";
4
4
  import type { PreDeleteHookFn, Registry } from "../engine/types";
5
5
  import { ConflictError, FrameworkReasons } from "../errors";
@@ -44,12 +44,8 @@ export function createCascadeDeleteHook(
44
44
  if (!targetTable) continue;
45
45
 
46
46
  if (strategy === OnDeleteStrategies.restrict) {
47
- const rows = await db
48
- .select({ id: targetTable["id"] })
49
- .from(targetTable)
50
- .where(eq(targetTable[relation.foreignKey], payload.id))
51
- .limit(1);
52
- if (rows.length > 0) {
47
+ const row = await fetchOne(db, targetTable, { [relation.foreignKey]: payload.id });
48
+ if (row) {
53
49
  throw new ConflictError({
54
50
  message: `${relation.target} has records referencing ${entityName}#${payload.id}`,
55
51
  i18nKey: "errors.deleteRestricted",
@@ -64,14 +60,16 @@ export function createCascadeDeleteHook(
64
60
  }
65
61
 
66
62
  if (strategy === OnDeleteStrategies.cascade) {
67
- await db.delete(targetTable).where(eq(targetTable[relation.foreignKey], payload.id));
63
+ await deleteMany(db, targetTable, { [relation.foreignKey]: payload.id });
68
64
  }
69
65
 
70
66
  if (strategy === OnDeleteStrategies.setNull) {
71
- await db
72
- .update(targetTable)
73
- .set({ [relation.foreignKey]: null })
74
- .where(eq(targetTable[relation.foreignKey], payload.id));
67
+ await updateMany(
68
+ db,
69
+ targetTable,
70
+ { [relation.foreignKey]: null },
71
+ { [relation.foreignKey]: payload.id },
72
+ );
75
73
  }
76
74
  }
77
75
 
@@ -79,17 +77,11 @@ export function createCascadeDeleteHook(
79
77
  const throughTable = tables.get(relation.through.table);
80
78
  if (!throughTable) continue;
81
79
  // sourceKey points at the owner side (the entity being deleted).
82
- // targetKey would point at the other side — filtering by it here
83
- // would miss every through-row for this entity.
84
80
  const sourceKey = relation.through.sourceKey;
85
81
 
86
82
  if (strategy === OnDeleteStrategies.restrict) {
87
- const rows = await db
88
- .select({ id: throughTable["id"] })
89
- .from(throughTable)
90
- .where(eq(throughTable[sourceKey], payload.id))
91
- .limit(1);
92
- if (rows.length > 0) {
83
+ const row = await fetchOne(db, throughTable, { [sourceKey]: payload.id });
84
+ if (row) {
93
85
  throw new ConflictError({
94
86
  message: `${relation.through.table} has records referencing ${entityName}#${payload.id}`,
95
87
  i18nKey: "errors.deleteRestricted",
@@ -104,7 +96,7 @@ export function createCascadeDeleteHook(
104
96
  }
105
97
 
106
98
  if (strategy === OnDeleteStrategies.cascade) {
107
- await db.delete(throughTable).where(eq(throughTable[sourceKey], payload.id));
99
+ await deleteMany(db, throughTable, { [sourceKey]: payload.id });
108
100
  }
109
101
  }
110
102
  }
@@ -1,7 +1,8 @@
1
- import { type AnyColumn, eq } from "drizzle-orm";
2
1
  import { requestContext } from "../api/request-context";
3
2
  import type { DbConnection, DbRow, DbTx } from "../db/connection";
4
- import { buildDrizzleTable } from "../db/table-builder";
3
+ import { selectRowForUpdateById } from "../db/queries/entity-read";
4
+ import { selectMany, transaction } from "../db/query";
5
+ import { buildEntityTable, toSnakeCase } from "../db/table-builder";
5
6
  import { createTenantDb } from "../db/tenant-db";
6
7
  import { hasAccess } from "../engine/access";
7
8
  import { checkWriteFieldRoles, filterReadFields } from "../engine/field-access";
@@ -173,15 +174,22 @@ export function createDispatcher(
173
174
  ): Dispatcher {
174
175
  const { idempotency, lifecycle, jobRunner, effectiveFeatures } = options;
175
176
 
177
+ // Narrowing-helper: AppContext.db ist DbConnection|TenantDb|undefined. Die
178
+ // dispatch-Pfade brauchen DbConnection (oder DbTx aus Caller-Scope) für
179
+ // appendEvent/projection-writes; TenantDb-Branch wird hier ausgeschlossen.
180
+ function resolveDbSource(tx: DbTx | undefined): DbConnection | DbTx | undefined {
181
+ return tx ?? (context.db as DbConnection | undefined); // @cast-boundary db-operator
182
+ }
183
+
176
184
  // Pre-build tables and transition maps for auto-guard (avoid per-request allocation)
177
- const tableCache = new Map<string, ReturnType<typeof buildDrizzleTable>>();
185
+ const tableCache = new Map<string, ReturnType<typeof buildEntityTable>>();
178
186
  const transitionCache = new Map<string, ReturnType<typeof defineTransitions>>();
179
187
 
180
- function getTable(entityName: string): ReturnType<typeof buildDrizzleTable> | undefined {
188
+ function getTable(entityName: string): ReturnType<typeof buildEntityTable> | undefined {
181
189
  if (tableCache.has(entityName)) return tableCache.get(entityName);
182
190
  const entity = registry.getEntity(entityName);
183
191
  if (!entity) return undefined;
184
- const table = buildDrizzleTable(entityName, entity, {
192
+ const table = buildEntityTable(entityName, entity, {
185
193
  relations: registry.getRelations(entityName),
186
194
  });
187
195
  tableCache.set(entityName, table);
@@ -215,8 +223,7 @@ export function createDispatcher(
215
223
  tx: DbTx | undefined,
216
224
  callerFeature: string | undefined,
217
225
  ): Promise<void> {
218
- const dbSource: DbConnection | DbTx | undefined =
219
- tx ?? (context.db as DbConnection | undefined); // @cast-boundary db-operator
226
+ const dbSource = resolveDbSource(tx);
220
227
  if (!dbSource) {
221
228
  throw new InternalError({
222
229
  message: `ctx.appendEvent("${args.type}") requires a database connection — none is configured.`,
@@ -245,8 +252,7 @@ export function createDispatcher(
245
252
  // The outer dispatcher receives a DbConnection from the server/stack;
246
253
  // AppContext's `db` union also allows TenantDb (for downstream hook calls),
247
254
  // but at this point we're the root of the pipeline — cast is safe.
248
- const dbSource: DbConnection | DbTx | undefined =
249
- tx ?? (context.db as DbConnection | undefined); // @cast-boundary db-operator
255
+ const dbSource = resolveDbSource(tx);
250
256
  const reqCtx = requestContext.get();
251
257
  const db = dbSource
252
258
  ? createTenantDb(
@@ -313,8 +319,7 @@ export function createDispatcher(
313
319
  await appendDomainEvent(args, user, tx, registry.getHandlerFeature(type));
314
320
  },
315
321
  fetchForWriting: async (args: FetchForWritingArgs): Promise<AggregateStreamHandle> => {
316
- const dbSource: DbConnection | DbTx | undefined =
317
- tx ?? (context.db as DbConnection | undefined); // @cast-boundary db-operator
322
+ const dbSource = resolveDbSource(tx);
318
323
  if (!dbSource) {
319
324
  throw new InternalError({
320
325
  message: `ctx.fetchForWriting("${args.aggregateId}") requires a database connection — none is configured.`,
@@ -377,8 +382,7 @@ export function createDispatcher(
377
382
  aggregateId: string,
378
383
  loadOptions?: { readonly asOf?: Temporal.Instant },
379
384
  ): Promise<readonly StoredEvent[]> => {
380
- const dbSource: DbConnection | DbTx | undefined =
381
- tx ?? (context.db as DbConnection | undefined); // @cast-boundary db-operator
385
+ const dbSource = resolveDbSource(tx);
382
386
  if (!dbSource) {
383
387
  throw new InternalError({
384
388
  message: `ctx.loadAggregate("${aggregateId}") requires a database connection — none is configured.`,
@@ -396,8 +400,7 @@ export function createDispatcher(
396
400
  aggregateId: string,
397
401
  archiveArgs: { readonly aggregateType: string; readonly reason?: string },
398
402
  ): Promise<void> => {
399
- const dbSource: DbConnection | DbTx | undefined =
400
- tx ?? (context.db as DbConnection | undefined); // @cast-boundary db-operator
403
+ const dbSource = resolveDbSource(tx);
401
404
  if (!dbSource) {
402
405
  throw new InternalError({
403
406
  message: `ctx.archiveStream("${aggregateId}") requires a database connection — none is configured.`,
@@ -412,8 +415,7 @@ export function createDispatcher(
412
415
  });
413
416
  },
414
417
  restoreStream: async (aggregateId: string): Promise<void> => {
415
- const dbSource: DbConnection | DbTx | undefined =
416
- tx ?? (context.db as DbConnection | undefined); // @cast-boundary db-operator
418
+ const dbSource = resolveDbSource(tx);
417
419
  if (!dbSource) {
418
420
  throw new InternalError({
419
421
  message: `ctx.restoreStream("${aggregateId}") requires a database connection — none is configured.`,
@@ -422,8 +424,7 @@ export function createDispatcher(
422
424
  await restoreStreamHelper(dbSource, user.tenantId, aggregateId);
423
425
  },
424
426
  isStreamArchived: async (aggregateId: string): Promise<boolean> => {
425
- const dbSource: DbConnection | DbTx | undefined =
426
- tx ?? (context.db as DbConnection | undefined); // @cast-boundary db-operator
427
+ const dbSource = resolveDbSource(tx);
427
428
  if (!dbSource) {
428
429
  throw new InternalError({
429
430
  message: `ctx.isStreamArchived("${aggregateId}") requires a database connection — none is configured.`,
@@ -437,8 +438,7 @@ export function createDispatcher(
437
438
  readonly version: number;
438
439
  readonly state: Record<string, unknown>;
439
440
  }): Promise<void> => {
440
- const dbSource: DbConnection | DbTx | undefined =
441
- tx ?? (context.db as DbConnection | undefined); // @cast-boundary db-operator
441
+ const dbSource = resolveDbSource(tx);
442
442
  if (!dbSource) {
443
443
  throw new InternalError({
444
444
  message: `ctx.snapshotAggregate("${snapshotArgs.aggregateId}") requires a database connection — none is configured.`,
@@ -457,8 +457,7 @@ export function createDispatcher(
457
457
  reducer: SnapshotReducer<TState>,
458
458
  initial: TState,
459
459
  ): Promise<LoadAggregateWithSnapshotResult<TState>> => {
460
- const dbSource: DbConnection | DbTx | undefined =
461
- tx ?? (context.db as DbConnection | undefined); // @cast-boundary db-operator
460
+ const dbSource = resolveDbSource(tx);
462
461
  if (!dbSource) {
463
462
  throw new InternalError({
464
463
  message: `ctx.loadAggregateWithSnapshot("${aggregateId}") requires a database connection — none is configured.`,
@@ -502,8 +501,7 @@ export function createDispatcher(
502
501
  `table-less MSP (side-effect-only). Known queryable projections: ${all.join(", ") || "(none)"}`,
503
502
  });
504
503
  }
505
- const dbSource: DbConnection | DbTx | undefined =
506
- tx ?? (context.db as DbConnection | undefined); // @cast-boundary db-operator
504
+ const dbSource = resolveDbSource(tx);
507
505
  if (!dbSource) {
508
506
  throw new InternalError({
509
507
  message: `ctx.queryProjection("${qualifiedName}") requires a database connection — none is configured.`,
@@ -513,17 +511,10 @@ export function createDispatcher(
513
511
  // filter keeps cross-tenant leaks out unless the handler explicitly
514
512
  // opts in. Works with any drizzle-table whose tenant column is named
515
513
  // tenantId on the JS side.
516
- // @cast-boundary dynamic-key drizzle's PgTable columns are schema-dependent
517
- const tenantCol = (projTable as Record<string, AnyColumn | undefined>)["tenantId"]; // @cast-boundary dynamic-key
518
- let rows: readonly Record<string, unknown>[];
519
- if (tenantCol && !queryOptions?.unsafeAllTenants) {
520
- rows = (await dbSource
521
- .select()
522
- .from(projTable)
523
- .where(eq(tenantCol, user.tenantId))) as readonly Record<string, unknown>[]; // @cast-boundary db-row
524
- } else {
525
- rows = (await dbSource.select().from(projTable)) as readonly Record<string, unknown>[]; // @cast-boundary db-row
526
- }
514
+ const tenantCol = (projTable as Record<string, unknown>)["tenantId"];
515
+ const where =
516
+ tenantCol && !queryOptions?.unsafeAllTenants ? { tenantId: user.tenantId } : undefined;
517
+ const rows = await selectMany<Record<string, unknown>>(dbSource, projTable, where);
527
518
  return rows as readonly T[]; // @cast-boundary engine-payload
528
519
  },
529
520
  // Thin pass-through: one resolve impl lives on the dispatcher, the
@@ -1123,9 +1114,12 @@ export function createDispatcher(
1123
1114
  // can false-pass; optimistic locking would catch it later, but with
1124
1115
  // a less specific error. Falls back to a plain SELECT if no tx is
1125
1116
  // active (tests without a DB connection).
1126
- const selectQuery = handlerContext.db.select().from(table);
1127
- const filtered = selectQuery.where(eq(table["id"], id));
1128
- const rows = tx ? await filtered.for("update") : await filtered;
1117
+ const tableName = String(
1118
+ (table as { [key: symbol]: unknown })[Symbol.for("kumiko:schema:Name")],
1119
+ );
1120
+ const rows = tx
1121
+ ? await selectRowForUpdateById(handlerContext.db, tableName, id)
1122
+ : await selectMany(handlerContext.db, table, { id });
1129
1123
  const row = rows[0];
1130
1124
 
1131
1125
  if (!row) continue;
@@ -1133,10 +1127,13 @@ export function createDispatcher(
1133
1127
  // at all; a handler that wants to move a deleted row should use
1134
1128
  // unsafeSkipTransitionGuard or restore first.
1135
1129
  const rowAsRow = row as DbRow; // @cast-boundary engine-payload
1136
- if (entity.softDelete && rowAsRow["isDeleted"] === true) {
1130
+ const isDeleted = rowAsRow["isDeleted"] ?? rowAsRow["is_deleted"];
1131
+ if (entity.softDelete && isDeleted === true) {
1137
1132
  continue;
1138
1133
  }
1139
- const currentValue = (row as DbRow)[fieldName] as string; // @cast-boundary engine-bridge
1134
+ const currentValue =
1135
+ ((row as DbRow)[fieldName] as string | undefined) ??
1136
+ ((row as DbRow)[toSnakeCase(fieldName)] as string); // @cast-boundary engine-bridge
1140
1137
  guardTransition(
1141
1138
  getTransitions({ entityName, fieldName, map: transitionMap }),
1142
1139
  currentValue,
@@ -1278,7 +1275,9 @@ export function createDispatcher(
1278
1275
  }
1279
1276
  };
1280
1277
 
1281
- const db = context.db as DbConnection | undefined; // @cast-boundary db-operator
1278
+ // batch() opens its own outer transaction needs the top-level
1279
+ // connection's `.begin()` (TransactionSql exposes only `.savepoint()`).
1280
+ const db = resolveDbSource(undefined) as DbConnection | undefined;
1282
1281
  if (!db) {
1283
1282
  // Without a DB connection there is no transaction to open. Fall back to
1284
1283
  // sequential execution — useful for unit tests that don't touch the DB.
@@ -1306,7 +1305,7 @@ export function createDispatcher(
1306
1305
  }
1307
1306
 
1308
1307
  try {
1309
- await db.transaction(async (tx) => {
1308
+ await transaction(db, async (tx) => {
1310
1309
  for (let i = 0; i < commands.length; i++) {
1311
1310
  const cmd = commands[i];
1312
1311
  if (!cmd) continue;
@@ -1326,10 +1325,6 @@ export function createDispatcher(
1326
1325
  results,
1327
1326
  });
1328
1327
  }
1329
- // Unexpected throw — typically a DB driver error from commit/rollback.
1330
- // executeWrite already traps handler + lifecycle throws into WriteResult,
1331
- // so anything reaching here is infrastructure-level. Wrap as InternalError
1332
- // so the contract ("non-Kumiko → InternalError") holds uniformly.
1333
1328
  return finalize({
1334
1329
  isSuccess: false,
1335
1330
  error: toWriteErrorInfo(wrapToKumiko(e)),
@@ -1368,7 +1363,7 @@ export function createDispatcher(
1368
1363
  // scoped as "tenant" and no tx is threaded through. Hooks that need
1369
1364
  // cross-tenant lookups opt in explicitly via queryAs(systemUser, ...).
1370
1365
  function buildAuthClaimsContext(user: SessionUser): AuthClaimsContext {
1371
- const dbSource: DbConnection | undefined = context.db as DbConnection | undefined; // @cast-boundary db-operator
1366
+ const dbSource = resolveDbSource(undefined);
1372
1367
  if (!dbSource) {
1373
1368
  throw new InternalError({
1374
1369
  message:
@@ -1,6 +1,15 @@
1
- import { sql } from "drizzle-orm";
1
+ // sql now comes from native dialect
2
2
  import type { DbConnection } from "../db/connection";
3
- import { bigint, index, instant, integer, table as pgTable, primaryKey, text } from "../db/dialect";
3
+ import {
4
+ bigint,
5
+ index,
6
+ instant,
7
+ integer,
8
+ table as pgTable,
9
+ primaryKey,
10
+ sql,
11
+ text,
12
+ } from "../db/dialect";
4
13
  import { tableExists } from "../db/schema-inspection";
5
14
  import { unsafePushTables } from "../stack";
6
15