@cosmicdrift/kumiko-framework 0.14.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 +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/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 -474
  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
package/src/db/dialect.ts CHANGED
@@ -1,89 +1,477 @@
1
- // Central re-export for all PostgreSQL-specific imports.
2
- // No other file in the framework should import from "drizzle-orm/pg-core" directly.
3
-
4
- import { customType } from "drizzle-orm/pg-core";
5
-
6
- export type {
7
- PgSelect as SelectQuery,
8
- PgTableWithColumns as TableColumns,
9
- } from "drizzle-orm/pg-core";
10
- export {
11
- bigint,
12
- bigserial,
13
- boolean,
14
- index,
15
- integer,
16
- jsonb,
17
- numeric,
18
- pgTable as table,
19
- primaryKey,
20
- serial,
21
- text,
22
- timestamp,
23
- uniqueIndex,
24
- uuid,
25
- } from "drizzle-orm/pg-core";
26
-
27
- /**
28
- * Money column: BIGINT storing the integer minor unit (cents for EUR, yen
29
- * for JPY). Range ±9.2e18 in the DB; JS `number` is safe to 2^53 ≈ 9e15
30
- * minor units = ~90 trillion EUR. INTEGER would cap at ~21 million EUR per
31
- * row which is too tight for real-world invoices, bank balances, or bills
32
- * of sale — hence bigint.
33
- */
34
- export const moneyAmount = customType<{ data: number; driverData: string | number }>({
35
- dataType() {
36
- return "bigint";
37
- },
38
- fromDriver(value: string | number): number {
39
- // node-postgres returns BIGINT as string by default; Bun's pg returns
40
- // number. Cast via Number() either way — safe because we stay under 2^53.
41
- return typeof value === "number" ? value : Number(value);
42
- },
43
- toDriver(value: number): number {
44
- return value;
45
- },
46
- });
47
-
48
- /**
49
- * Instant column: TIMESTAMPTZ storing a UTC instant, surfaced to JS as
50
- * `Temporal.Instant`. Replaces the old dual-mode situation (`mode:"date"`
51
- * for base fields vs `mode:"string"` for user-defined timestamp fields)
52
- * with a single round-trip type. See sprint-f-temporal.md for the migration.
53
- *
54
- * Driver-data is the ISO-8601 string the postgres driver actually exchanges.
55
- * `fromDriver` reads what the driver returns (postgres-js gives strings for
56
- * timestamptz) and parses through Temporal. `toDriver` writes the canonical
57
- * Temporal.Instant.toString() — the spike confirmed `eq/lte/gt/orderBy/
58
- * returning` accept Temporal.Instant directly without manual `.toString()`
59
- * at the call site.
60
- *
61
- * Boot-order note: `Temporal` must exist on globalThis before any
62
- * fromDriver/toDriver call. `ensureTemporalPolyfill()` runs at framework
63
- * boot. The closures here are lazy — they fire on read/write, not on
64
- * module load — so importing this file before the polyfill is safe.
65
- *
66
- * Optional `precision` (0..6) — fractional-second digits. Default 6 matches
67
- * PG's default `timestamptz`. Pass 3 for the events-table (ms precision —
68
- * matches what asOf-queries can compare reliably). Affects only CREATE TABLE
69
- * DDL via drizzle-kit; runtime parse handles any precision via Temporal.
70
- */
71
- // Forgiving overload: payloads from custom write-handlers sometimes
72
- // arrive as ISO strings rather than Temporal.Instant (Zod insert-
73
- // schemas use z.iso.datetime, not a Temporal validator). Coerce here
74
- // at the boundary so the DB always sees a normalised string — and
75
- // Temporal.Instant.from throws on bad input, which is the right failure
76
- // mode (vs. the obscure "x.toString is not a function" crash that hit
77
- // feature authors before this overload existed).
1
+ // Native dialect replaces drizzle-orm/pg-core re-exports.
78
2
  //
79
- // Date-only strings (YYYY-MM-DD) coercen wir auf start-of-day UTC.
80
- // Hintergrund: type:"date" ist heute auf instant() aliased (table-
81
- // builder.ts TODO Sprint G), aber die Zod-Validation akzeptiert nur
82
- // YYYY-MM-DD. Ohne diesen Coerce wirft Temporal mit "Cannot parse:
83
- // 2026-04-10" und der Author bekommt einen internal_error 500 statt
84
- // einen sauberen DB-Roundtrip.
3
+ // Produces table objects that simultaneously expose:
4
+ // 1. EntityTableMeta shape (source/columns/indexes) for bun-db's
5
+ // extractTableInfo + the migrate-runner's renderTableDdl
6
+ // 2. drizzle-compatible Symbol metadata so callers that introspect
7
+ // Symbol.for("kumiko:schema:Name") / Symbol.for("kumiko:schema:Columns") keep
8
+ // working (no caller updates needed)
9
+ // 3. Top-level column-handle properties (table.id, table.tenantId, ...)
10
+ // so legacy code that does `table[field].name` still resolves to the
11
+ // snake_case SQL column name.
85
12
  //
86
- // Exportiert für Tests; production-call läuft über instantBuilder.
13
+ // The framework no longer imports drizzle-orm at runtime — schema-files
14
+ // use only this module.
15
+
16
+ import type {
17
+ ColumnMeta,
18
+ CompositePrimaryKeyMeta,
19
+ EntityTableMeta,
20
+ IndexMeta,
21
+ PgType,
22
+ } from "./entity-table-meta";
23
+
24
+ // Public type aliases — historical compat for callers that used to import
25
+ // these from drizzle-orm/pg-core. SelectQuery is no longer a meaningful
26
+ // shape (no chain builder); TableColumns is the new SchemaTable union.
27
+ // biome-ignore lint/suspicious/noExplicitAny: variadic table shape
28
+ export type TableColumns<_T = any> = SchemaTable;
29
+ // biome-ignore lint/suspicious/noExplicitAny: legacy type — chain API is gone
30
+ export type SelectQuery = any;
31
+
32
+ // Column handle exposed on the SchemaTable. The `name` is the SQL column
33
+ // name (snake_case); legacy code accesses `table.fieldName.name` to
34
+ // produce raw SQL.
35
+ export type ColumnHandle = {
36
+ readonly name: string;
37
+ readonly pgType: PgType;
38
+ readonly getSQLType: () => string;
39
+ };
40
+
41
+ const KUMIKO_NAME_SYMBOL = Symbol.for("kumiko:schema:Name");
42
+ const KUMIKO_COLUMNS_SYMBOL = Symbol.for("kumiko:schema:Columns");
43
+
44
+ // SchemaTable — opaque shape with both EntityTableMeta + Symbol-based
45
+ // introspection. Returned by `table(...)`.
46
+ export type SchemaTable = EntityTableMeta & {
47
+ readonly [KUMIKO_NAME_SYMBOL]: string;
48
+ readonly [KUMIKO_COLUMNS_SYMBOL]: Record<string, ColumnHandle>;
49
+ readonly [field: string]: unknown;
50
+ };
51
+
52
+ export function pgTypeToSqlType(pgType: PgType): string {
53
+ switch (pgType) {
54
+ case "uuid":
55
+ return "uuid";
56
+ case "text":
57
+ return "text";
58
+ case "boolean":
59
+ return "boolean";
60
+ case "integer":
61
+ return "integer";
62
+ case "bigint":
63
+ return "bigint";
64
+ case "serial":
65
+ return "serial";
66
+ case "bigserial":
67
+ return "bigserial";
68
+ case "jsonb":
69
+ return "jsonb";
70
+ case "timestamptz":
71
+ return "timestamp with time zone";
72
+ case "timestamptz(3)":
73
+ return "timestamp(3) with time zone";
74
+ }
75
+ }
76
+
77
+ function _toSnakeCase(name: string): string {
78
+ return name.replace(/[A-Z]/g, (m) => `_${m.toLowerCase()}`).replace(/^_/, "");
79
+ }
80
+
81
+ // ---- Column builder ----
82
+ //
83
+ // Returned by uuid()/text()/etc. Chainable: notNull/primaryKey/default/unique.
84
+ // Internal state captured in the builder; finalised when handed to table().
85
+ // `name` is set explicitly on the first call (uuid("user_id")) and may be
86
+ // overridden by `withCamel(jsField)` so the handle exposes both the SQL name
87
+ // AND the JS field-name for type inference.
88
+
89
+ type ColumnFinal = {
90
+ readonly sqlName: string;
91
+ readonly pgType: PgType;
92
+ readonly notNull: boolean;
93
+ readonly primaryKey: boolean;
94
+ readonly unique: boolean;
95
+ readonly identity: boolean;
96
+ readonly defaultSql?: string;
97
+ };
98
+
99
+ export type ColumnBuilder<TValue = unknown> = {
100
+ readonly __column: true;
101
+ readonly finalise: () => ColumnFinal;
102
+ notNull(): ColumnBuilder<TValue>;
103
+ primaryKey(): ColumnBuilder<TValue>;
104
+ default(
105
+ value: TValue | SqlExpression | readonly unknown[] | number | string | boolean | null,
106
+ ): ColumnBuilder<TValue>;
107
+ defaultRandom(): ColumnBuilder<TValue>;
108
+ defaultNow(): ColumnBuilder<TValue>;
109
+ generatedAlwaysAsIdentity(): ColumnBuilder<TValue>;
110
+ unique(name?: string): ColumnBuilder<TValue>;
111
+ $type<T>(): ColumnBuilder<T>;
112
+ $onUpdate(fn: () => unknown): ColumnBuilder<TValue>;
113
+ };
114
+
115
+ function buildColumn(sqlName: string, pgType: PgType): ColumnBuilder<unknown> {
116
+ let notNull = false;
117
+ let primaryKey = false;
118
+ let unique = false;
119
+ let identity = false;
120
+ let defaultSql: string | undefined;
121
+
122
+ function literalDefault(value: unknown): string | null {
123
+ if (value === undefined) return null;
124
+ if (value === null) return "NULL";
125
+ if (typeof value === "string") return `'${value.replace(/'/g, "''")}'`;
126
+ if (typeof value === "number") return String(value);
127
+ if (typeof value === "boolean") return value ? "true" : "false";
128
+ if (typeof value === "bigint") return value.toString();
129
+ if (
130
+ value &&
131
+ typeof value === "object" &&
132
+ "kind" in value &&
133
+ (value as { kind: string }).kind === "sql-expr"
134
+ ) {
135
+ return (value as SqlExpression).text;
136
+ }
137
+ if (typeof value === "function") return null; // function-defaults stay JS-side
138
+ // Object/array → jsonb literal
139
+ const serialised = JSON.stringify(value);
140
+ if (serialised === undefined) return null;
141
+ return `'${serialised.replace(/'/g, "''")}'::jsonb`;
142
+ }
143
+
144
+ const builder: ColumnBuilder<unknown> = {
145
+ __column: true,
146
+ finalise(): ColumnFinal {
147
+ return {
148
+ sqlName,
149
+ pgType,
150
+ notNull,
151
+ primaryKey,
152
+ unique,
153
+ identity,
154
+ ...(defaultSql !== undefined && { defaultSql }),
155
+ };
156
+ },
157
+ notNull() {
158
+ notNull = true;
159
+ return builder;
160
+ },
161
+ primaryKey() {
162
+ primaryKey = true;
163
+ notNull = true;
164
+ return builder;
165
+ },
166
+ default(value: unknown) {
167
+ const rendered = literalDefault(value);
168
+ defaultSql = rendered === null ? undefined : rendered;
169
+ return builder;
170
+ },
171
+ defaultRandom() {
172
+ defaultSql = "gen_random_uuid()";
173
+ return builder;
174
+ },
175
+ defaultNow() {
176
+ defaultSql = "now()";
177
+ return builder;
178
+ },
179
+ generatedAlwaysAsIdentity() {
180
+ identity = true;
181
+ defaultSql = undefined;
182
+ return builder;
183
+ },
184
+ unique(_name?: string) {
185
+ unique = true;
186
+ return builder;
187
+ },
188
+ $type<T>() {
189
+ return builder as unknown as ColumnBuilder<T>;
190
+ },
191
+ $onUpdate(_fn: () => unknown) {
192
+ // Runtime $onUpdate is a no-op in the schema layer — the framework's
193
+ // event-driven projection write path sets modified_at explicitly.
194
+ return builder;
195
+ },
196
+ };
197
+ return builder;
198
+ }
199
+
200
+ // ---- Column factories ----
201
+
202
+ export function uuid(name: string): ColumnBuilder<string> {
203
+ return buildColumn(name, "uuid") as ColumnBuilder<string>;
204
+ }
205
+
206
+ export function text(name: string): ColumnBuilder<string> {
207
+ return buildColumn(name, "text") as ColumnBuilder<string>;
208
+ }
209
+
210
+ export function boolean(name: string): ColumnBuilder<boolean> {
211
+ return buildColumn(name, "boolean") as ColumnBuilder<boolean>;
212
+ }
213
+
214
+ export function integer(name: string): ColumnBuilder<number> {
215
+ return buildColumn(name, "integer") as ColumnBuilder<number>;
216
+ }
217
+
218
+ export function serial(name: string): ColumnBuilder<number> {
219
+ return buildColumn(name, "serial") as ColumnBuilder<number>;
220
+ }
221
+
222
+ export function bigint(
223
+ name: string,
224
+ _opts?: { mode?: "bigint" | "number" },
225
+ ): ColumnBuilder<bigint> {
226
+ return buildColumn(name, "bigint") as ColumnBuilder<bigint>;
227
+ }
228
+
229
+ export function bigserial(
230
+ name: string,
231
+ _opts?: { mode?: "bigint" | "number" },
232
+ ): ColumnBuilder<bigint> {
233
+ return buildColumn(name, "bigserial") as ColumnBuilder<bigint>;
234
+ }
235
+
236
+ export function jsonb(name: string): ColumnBuilder<Record<string, unknown>> {
237
+ return buildColumn(name, "jsonb") as ColumnBuilder<Record<string, unknown>>;
238
+ }
239
+
240
+ // Legacy alias kept for compat — timestamptz with no precision.
241
+ export function timestamp(
242
+ name: string,
243
+ _opts?: { withTimezone?: boolean; mode?: "string" | "date" },
244
+ ): ColumnBuilder<Temporal.Instant | string> {
245
+ return buildColumn(name, "timestamptz") as ColumnBuilder<Temporal.Instant | string>;
246
+ }
247
+
248
+ // numeric → text (we don't currently use Decimal); kept for compat with
249
+ // legacy schema imports that won't actually instantiate at runtime.
250
+ export function numeric(
251
+ name: string,
252
+ _opts?: { precision?: number; scale?: number },
253
+ ): ColumnBuilder<string> {
254
+ return buildColumn(name, "text") as ColumnBuilder<string>;
255
+ }
256
+
257
+ export function instant(
258
+ name: string,
259
+ opts?: { precision?: 0 | 1 | 2 | 3 | 4 | 5 | 6 },
260
+ ): ColumnBuilder<Temporal.Instant> {
261
+ const pgType: PgType = opts?.precision === 3 ? "timestamptz(3)" : "timestamptz";
262
+ return buildColumn(name, pgType) as ColumnBuilder<Temporal.Instant>;
263
+ }
264
+
265
+ // moneyAmount kept as a customType-style API but produces a bigint column.
266
+ export const moneyAmount = (name: string): ColumnBuilder<number> =>
267
+ buildColumn(name, "bigint") as ColumnBuilder<number>;
268
+
269
+ // ---- Index + primaryKey helpers ----
270
+
271
+ export type IndexBuilder = {
272
+ readonly __index: true;
273
+ on(...cols: ColumnHandle[]): IndexBuilderWithCols;
274
+ };
275
+
276
+ export type IndexBuilderWithCols = {
277
+ readonly __index: true;
278
+ readonly name: string;
279
+ readonly unique: boolean;
280
+ readonly columns: readonly string[];
281
+ where(expr: SqlExpression): IndexBuilderWithCols;
282
+ readonly whereSql?: string;
283
+ };
284
+
285
+ function makeIndex(name: string, unique: boolean): IndexBuilder {
286
+ return {
287
+ __index: true,
288
+ on(...cols: ColumnHandle[]): IndexBuilderWithCols {
289
+ const colNames = cols.map((c) => c.name);
290
+ let whereSql: string | undefined;
291
+ const finalised: IndexBuilderWithCols = {
292
+ __index: true,
293
+ name,
294
+ unique,
295
+ columns: colNames,
296
+ get whereSql() {
297
+ return whereSql;
298
+ },
299
+ where(expr: SqlExpression) {
300
+ whereSql = expr.text;
301
+ return finalised;
302
+ },
303
+ };
304
+ return finalised;
305
+ },
306
+ };
307
+ }
308
+
309
+ export function index(name: string): IndexBuilder {
310
+ return makeIndex(name, false);
311
+ }
312
+
313
+ export function uniqueIndex(name: string): IndexBuilder {
314
+ return makeIndex(name, true);
315
+ }
316
+
317
+ export type PrimaryKeyDescriptor = {
318
+ readonly __pk: true;
319
+ readonly columns: readonly string[];
320
+ readonly name?: string;
321
+ };
322
+
323
+ export function primaryKey(opts: {
324
+ columns: readonly ColumnHandle[];
325
+ name?: string;
326
+ }): PrimaryKeyDescriptor {
327
+ return {
328
+ __pk: true,
329
+ columns: opts.columns.map((c) => c.name),
330
+ ...(opts.name !== undefined && { name: opts.name }),
331
+ };
332
+ }
333
+
334
+ // ---- sql template ----
335
+ //
336
+ // A constrained sql template tag. Returns a SqlExpression carrying the
337
+ // composed text + params. Used in DEFAULT expressions in schema files
338
+ // (sql`now()`, sql`gen_random_uuid()`, sql`0`).
339
+ //
340
+ // Limits: no nested SqlExpression composition (drizzle's recursive
341
+ // `sql\`${other}\``) — schema-files use single-level expressions only.
342
+
343
+ export type SqlExpression = {
344
+ readonly kind: "sql-expr";
345
+ readonly text: string;
346
+ readonly params: readonly unknown[];
347
+ };
348
+
349
+ export function sql(strings: TemplateStringsArray, ...values: readonly unknown[]): SqlExpression {
350
+ const parts: string[] = [];
351
+ const params: unknown[] = [];
352
+ for (let i = 0; i < strings.length; i++) {
353
+ parts.push(strings[i] ?? "");
354
+ if (i < values.length) {
355
+ const v = values[i];
356
+ if (v && typeof v === "object" && "kind" in v && v.kind === "sql-expr") {
357
+ parts.push((v as SqlExpression).text);
358
+ } else {
359
+ parts.push(String(v));
360
+ }
361
+ }
362
+ }
363
+ return { kind: "sql-expr", text: parts.join(""), params };
364
+ }
365
+
366
+ sql.raw = (text: string): SqlExpression => ({ kind: "sql-expr", text, params: [] });
367
+
368
+ // ---- table() — the schema-table factory ----
369
+ //
370
+ // Produces a SchemaTable with:
371
+ // - EntityTableMeta shape (source/tableName/columns/indexes)
372
+ // - Drizzle Symbol metadata for compat with bun-db's introspection
373
+ // - Top-level column-handle properties (table.fieldName → ColumnHandle)
374
+ //
375
+ // Second arg is an object whose keys are JS field-names; values are
376
+ // ColumnBuilder. Third arg is the constraints/index callback receiving
377
+ // a record of ColumnHandle (so existing `(t) => ({ idx: index(...).on(t.col) })`
378
+ // patterns work).
379
+
380
+ export type ColumnMap = Record<string, ColumnBuilder<unknown>>;
381
+
382
+ type IndexOrPk = IndexBuilderWithCols | PrimaryKeyDescriptor;
383
+
384
+ export function table<TCols extends ColumnMap>(
385
+ tableName: string,
386
+ cols: TCols,
387
+ optsFn?: (
388
+ t: { [K in keyof TCols]: ColumnHandle },
389
+ ) => Record<string, IndexOrPk> | ReadonlyArray<IndexOrPk>,
390
+ ): SchemaTable {
391
+ // Finalise columns + build the column-handle map.
392
+ const handles: Record<string, ColumnHandle> = {};
393
+ const columnMetas: ColumnMeta[] = [];
394
+ const indexes: IndexMeta[] = [];
395
+ for (const [field, builder] of Object.entries(cols)) {
396
+ const final = builder.finalise();
397
+ const handle: ColumnHandle = {
398
+ name: final.sqlName,
399
+ pgType: final.pgType,
400
+ getSQLType: () => pgTypeToSqlType(final.pgType),
401
+ };
402
+ handles[field] = handle;
403
+ const meta: ColumnMeta = {
404
+ name: final.sqlName,
405
+ pgType: final.pgType,
406
+ notNull: final.notNull,
407
+ ...(final.primaryKey && { primaryKey: true }),
408
+ ...(final.identity && { identity: true }),
409
+ ...(final.defaultSql !== undefined && { defaultSql: final.defaultSql }),
410
+ };
411
+ columnMetas.push(meta);
412
+
413
+ // Per-column .unique() → single-column unique index
414
+ if (final.unique) {
415
+ indexes.push({
416
+ name: `${tableName}_${final.sqlName}_unique`,
417
+ columns: [final.sqlName],
418
+ unique: true,
419
+ });
420
+ }
421
+ }
422
+
423
+ // Evaluate index/pk callback with the column handles.
424
+ let compositePrimaryKey: CompositePrimaryKeyMeta | undefined;
425
+ if (optsFn) {
426
+ const tHandle = handles as { [K in keyof TCols]: ColumnHandle };
427
+ const opts = optsFn(tHandle);
428
+ const entries: Array<[string, IndexOrPk | undefined]> = Array.isArray(opts)
429
+ ? (opts as ReadonlyArray<IndexOrPk>).map((v, i) => [String(i), v])
430
+ : Object.entries(opts);
431
+ for (const [key, value] of entries) {
432
+ if (!value) continue;
433
+ if ("__pk" in value && value.__pk === true) {
434
+ compositePrimaryKey = {
435
+ name: value.name ?? `${tableName}_pk`,
436
+ columns: value.columns,
437
+ };
438
+ } else if ("__index" in value && value.__index === true) {
439
+ const idx = value as IndexBuilderWithCols;
440
+ indexes.push({
441
+ name: idx.name,
442
+ columns: idx.columns,
443
+ ...(idx.unique && { unique: true }),
444
+ ...(idx.whereSql !== undefined && { whereSql: idx.whereSql }),
445
+ });
446
+ } else {
447
+ // Inline unique-column declaration via .unique() — not implemented yet.
448
+ // Schema files don't currently use that path; pinned by the table-types
449
+ // test fixture if it's ever added.
450
+ const _k = key;
451
+ }
452
+ }
453
+ }
454
+
455
+ // Build the SchemaTable. Object.assign to layer the column handles + symbols
456
+ // onto the EntityTableMeta-shaped object so introspection works.
457
+ const base: EntityTableMeta = {
458
+ tableName,
459
+ columns: columnMetas,
460
+ indexes,
461
+ ...(compositePrimaryKey !== undefined && { compositePrimaryKey }),
462
+ source: "unmanaged",
463
+ };
464
+ const out = Object.assign({}, base, handles, {
465
+ [KUMIKO_NAME_SYMBOL]: tableName,
466
+ [KUMIKO_COLUMNS_SYMBOL]: handles,
467
+ }) as SchemaTable;
468
+ return out;
469
+ }
470
+
471
+ // Helper used by `instantToDriver` callers in legacy code — kept identical
472
+ // to the previous behaviour. The native dialect handles parse/serialize
473
+ // implicitly via the Bun driver; this function is a defensive coerce at
474
+ // the API boundary.
87
475
  export function instantToDriver(value: Temporal.Instant | string): string {
88
476
  if (typeof value === "string") {
89
477
  const dateOnly = /^\d{4}-\d{2}-\d{2}$/.test(value);
@@ -92,18 +480,3 @@ export function instantToDriver(value: Temporal.Instant | string): string {
92
480
  }
93
481
  return value.toString();
94
482
  }
95
-
96
- const instantBuilder = (config?: { precision?: 0 | 1 | 2 | 3 | 4 | 5 | 6 }) =>
97
- customType<{ data: Temporal.Instant; driverData: string }>({
98
- dataType() {
99
- const p = config?.precision;
100
- return p !== undefined ? `timestamp(${p}) with time zone` : "timestamptz";
101
- },
102
- fromDriver(value: string): Temporal.Instant {
103
- return Temporal.Instant.from(value);
104
- },
105
- toDriver: instantToDriver,
106
- });
107
- export function instant(name: string, config?: { precision?: 0 | 1 | 2 | 3 | 4 | 5 | 6 }) {
108
- return instantBuilder(config)(name);
109
- }
@@ -23,9 +23,9 @@
23
23
  // keine framework-engine-Internals und kann auch von custom
24
24
  // query-handlern manuell aufgerufen werden.
25
25
 
26
- import { inArray } from "drizzle-orm";
26
+ import { selectMany } from "../db/query";
27
27
  import type { EntityDefinition, FieldDefinition, ReferenceFieldDef } from "../engine/types";
28
- import { buildDrizzleTable } from "./table-builder";
28
+ import { buildEntityTable } from "./table-builder";
29
29
  import type { TenantDb } from "./tenant-db";
30
30
 
31
31
  // Minimaler Registry-Lookup-Contract: pro entity-name → EntityDefinition.
@@ -121,18 +121,11 @@ export async function enrichWithReferences(
121
121
  // UUID zurück, kein Crash.
122
122
  return { fieldName: rf.fieldName, multiple: rf.multiple, map: new Map() };
123
123
  }
124
- const refTable = buildDrizzleTable(rf.refEntityName, refEntity);
125
- const idCol = refTable["id"];
126
- if (idCol === undefined) {
127
- return { fieldName: rf.fieldName, multiple: rf.multiple, map: new Map() };
128
- }
124
+ const refTable = buildEntityTable(rf.refEntityName, refEntity);
129
125
  const idArray = [...ids];
130
- const refRows = (await db
131
- .select()
132
- .from(refTable)
133
- .where(inArray(idCol, idArray as never /* @cast-boundary db-operator */))) as Array<
126
+ const refRows = (await selectMany(db, refTable, { id: idArray })) as Array<
134
127
  Record<string, unknown>
135
- >; // @cast-boundary db-row
128
+ >;
136
129
  const map = new Map<string, Record<string, unknown>>();
137
130
  for (const r of refRows) {
138
131
  const id = r["id"];