@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
@@ -0,0 +1,390 @@
1
+ // EntityTableMeta — plain-data Schema-Meta für eine Read-Model-Tabelle.
2
+ // Single source of truth statt verheirateter drizzle-pgTable-Builder.
3
+ //
4
+ // Phase 3a (Drizzle-Replacement Plan): Type + Generator existieren parallel
5
+ // zu buildEntityTable. Konsumenten bleiben auf EntityTable (via Adapter
6
+ // `entityTableMetaToEntityTable`), bis Phase 4 die Query-API auf Bun.sql
7
+ // umstellt.
8
+ //
9
+ // Designed für zwei Quellen:
10
+ // 1. **Managed** — EntityDefinition via buildEntityTableMeta(name, entity).
11
+ // Standard-Pfad mit base-columns (id, tenant_id, version, inserted_at,
12
+ // modified_at, inserted_by_id, modified_by_id, ggf. softDelete-Cols),
13
+ // automatischer tenant_id-Index, audit-fähig.
14
+ // 2. **Unmanaged** — defineUnmanagedTable(input). Escape-Hatch für Tabellen
15
+ // die NICHT durch das Entity-System gemanagt werden — keine erzwungenen
16
+ // base-columns, kein Standard-Audit-Trail. App-Author trägt Verantwortung
17
+ // für Tenant-Scoping, Version-Tracking, audit-by-Spalten. Verwendung
18
+ // auf Sondercases beschränken (child-projection-tables ohne tenant,
19
+ // append-only-logs mit serial PK, aggregate-ID ohne DEFAULT, …).
20
+
21
+ import type {
22
+ EntityDefinition,
23
+ EntityIndexDef,
24
+ EntityRelations,
25
+ FieldDefinition,
26
+ } from "../engine/types";
27
+ import { READ_MODEL_PREFIX, toSnakeCase, toTableName } from "./table-builder";
28
+
29
+ // PG-Type-Repertoire das die Read-Model-Tabellen brauchen. Bewusst
30
+ // schmal — keine Vendor-spezifischen Typen (TSVECTOR, HSTORE, etc.).
31
+ // App-Author die solche braucht greift in der reviewten SQL-Migration
32
+ // hand-edit ein, nicht im Generator.
33
+ export type PgType =
34
+ | "uuid"
35
+ | "text"
36
+ | "boolean"
37
+ | "integer"
38
+ | "bigint"
39
+ | "serial"
40
+ | "bigserial"
41
+ | "jsonb"
42
+ | "timestamptz"
43
+ | "timestamptz(3)";
44
+
45
+ export type ColumnMeta = {
46
+ readonly name: string; // snake_case PG column name
47
+ readonly pgType: PgType;
48
+ readonly notNull: boolean;
49
+ // Raw SQL-default-expression (e.g. `now()`, `gen_random_uuid()`,
50
+ // `'[]'::jsonb`). undefined = no DEFAULT clause.
51
+ readonly defaultSql?: string;
52
+ readonly primaryKey?: boolean;
53
+ readonly identity?: boolean;
54
+ };
55
+
56
+ export type IndexMeta = {
57
+ readonly name: string;
58
+ readonly columns: readonly string[]; // snake_case PG column names
59
+ readonly unique?: boolean;
60
+ // Raw SQL-where-expression for partial indexes. Caller is responsible
61
+ // for safety — emitted verbatim.
62
+ readonly whereSql?: string;
63
+ // Set wenn die EntityDefinition ein partial-Index hat (def.where als
64
+ // drizzle SQL-AST), der vom Generator nicht zuverlässig renderbar ist.
65
+ // Renderer emittiert das Statement dann AUSKOMMENTIERT mit Warn-Hint —
66
+ // App-Author muss das WHERE manuell im generierten SQL hinzufügen.
67
+ readonly needsManualWhere?: boolean;
68
+ };
69
+
70
+ export type CompositePrimaryKeyMeta = {
71
+ readonly name: string;
72
+ readonly columns: readonly string[];
73
+ };
74
+
75
+ export type EntityTableMeta = {
76
+ readonly tableName: string;
77
+ readonly columns: readonly ColumnMeta[];
78
+ readonly indexes: readonly IndexMeta[];
79
+ // For tables with composite PK (no single id column, e.g. snapshots
80
+ // keyed by aggregate_id+version). When set, no column should have
81
+ // primaryKey:true; the constraint is emitted at table-level.
82
+ readonly compositePrimaryKey?: CompositePrimaryKeyMeta;
83
+ // Source-hint für Diagnose/Tests — nicht funktional verwendet.
84
+ // "managed" = aus EntityDefinition (mit base-columns + audit-trail).
85
+ // "unmanaged" = via defineUnmanagedTable — kein Standard-Audit, App
86
+ // trägt Verantwortung. Migration-Generator + Tooling können den
87
+ // discriminator nutzen um Warnungen zu rendern ("X tables are unmanaged").
88
+ readonly source: "managed" | "unmanaged";
89
+ };
90
+
91
+ // Standard base-columns für event-sourced Read-Model-Tabellen. Spiegelt
92
+ // `buildBaseColumns()` aus table-builder.ts (drizzle-Variante).
93
+ function fullBaseColumns(idType: "uuid" | "serial", softDelete: boolean): readonly ColumnMeta[] {
94
+ const idCol: ColumnMeta =
95
+ idType === "uuid"
96
+ ? {
97
+ name: "id",
98
+ pgType: "uuid",
99
+ notNull: true,
100
+ defaultSql: "gen_random_uuid()",
101
+ primaryKey: true,
102
+ }
103
+ : { name: "id", pgType: "serial", notNull: true, primaryKey: true };
104
+
105
+ const cols: ColumnMeta[] = [
106
+ idCol,
107
+ { name: "tenant_id", pgType: "uuid", notNull: true },
108
+ { name: "version", pgType: "integer", notNull: true, defaultSql: "1" },
109
+ { name: "inserted_at", pgType: "timestamptz", notNull: true, defaultSql: "now()" },
110
+ { name: "modified_at", pgType: "timestamptz", notNull: false },
111
+ { name: "inserted_by_id", pgType: "text", notNull: false },
112
+ { name: "modified_by_id", pgType: "text", notNull: false },
113
+ ];
114
+
115
+ if (softDelete) {
116
+ cols.push(
117
+ { name: "is_deleted", pgType: "boolean", notNull: true, defaultSql: "false" },
118
+ { name: "deleted_at", pgType: "timestamptz", notNull: false },
119
+ { name: "deleted_by_id", pgType: "text", notNull: false },
120
+ );
121
+ }
122
+ return cols;
123
+ }
124
+
125
+ function quoteSql(literal: string): string {
126
+ return `'${literal.replace(/'/g, "''")}'`;
127
+ }
128
+
129
+ function fieldDefaultLiteral(field: FieldDefinition): string | undefined {
130
+ if (!("default" in field) || field.default === undefined) return undefined;
131
+ const v = field.default;
132
+ if (typeof v === "string") return quoteSql(v);
133
+ if (typeof v === "number") return String(v);
134
+ if (typeof v === "boolean") return v ? "true" : "false";
135
+ return undefined;
136
+ }
137
+
138
+ // Spiegelt `fieldToColumns()` aus table-builder.ts (Drizzle-Variante).
139
+ // Lock-step: jeder Field-Type produziert dieselben PG-Spalten wie heute.
140
+ function fieldToColumnMeta(
141
+ name: string,
142
+ field: FieldDefinition,
143
+ entity: EntityDefinition,
144
+ ): readonly ColumnMeta[] {
145
+ const snake = toSnakeCase(name);
146
+ switch (field.type) {
147
+ case "text":
148
+ case "longText": {
149
+ const def = fieldDefaultLiteral(field);
150
+ return [
151
+ {
152
+ name: snake,
153
+ pgType: "text",
154
+ notNull: field.required === true,
155
+ ...(def !== undefined && { defaultSql: def }),
156
+ },
157
+ ];
158
+ }
159
+ case "boolean": {
160
+ const def = fieldDefaultLiteral(field);
161
+ const hasDefault = def !== undefined;
162
+ return [
163
+ {
164
+ name: snake,
165
+ pgType: "boolean",
166
+ notNull: hasDefault || field.required === true,
167
+ ...(hasDefault && { defaultSql: def }),
168
+ },
169
+ ];
170
+ }
171
+ case "select": {
172
+ const def = fieldDefaultLiteral(field);
173
+ return [
174
+ {
175
+ name: snake,
176
+ pgType: "text",
177
+ notNull: field.required === true,
178
+ ...(def !== undefined && { defaultSql: def }),
179
+ },
180
+ ];
181
+ }
182
+ case "multiSelect":
183
+ return [{ name: snake, pgType: "jsonb", notNull: true, defaultSql: "'[]'::jsonb" }];
184
+ case "number": {
185
+ const def = fieldDefaultLiteral(field);
186
+ return [
187
+ {
188
+ name: snake,
189
+ pgType: "integer",
190
+ notNull: field.required === true,
191
+ ...(def !== undefined && { defaultSql: def }),
192
+ },
193
+ ];
194
+ }
195
+ case "bigInt": {
196
+ const def = fieldDefaultLiteral(field);
197
+ return [
198
+ {
199
+ name: snake,
200
+ pgType: "bigint",
201
+ notNull: field.required === true,
202
+ ...(def !== undefined && { defaultSql: def }),
203
+ },
204
+ ];
205
+ }
206
+ case "reference":
207
+ if (field.multiple === true) {
208
+ return [{ name: snake, pgType: "jsonb", notNull: true, defaultSql: "'[]'::jsonb" }];
209
+ }
210
+ return [{ name: snake, pgType: "uuid", notNull: field.required === true }];
211
+ case "money": {
212
+ const cur = entity.defaultCurrency ?? "EUR";
213
+ return [
214
+ { name: snake, pgType: "bigint", notNull: field.required === true },
215
+ {
216
+ name: `${snake}_currency`,
217
+ pgType: "text",
218
+ notNull: true,
219
+ defaultSql: quoteSql(cur),
220
+ },
221
+ ];
222
+ }
223
+ case "embedded":
224
+ return [{ name: snake, pgType: "jsonb", notNull: true, defaultSql: "'{}'::jsonb" }];
225
+ case "jsonb":
226
+ return [{ name: snake, pgType: "jsonb", notNull: true, defaultSql: "'{}'::jsonb" }];
227
+ case "date":
228
+ case "timestamp":
229
+ return [{ name: snake, pgType: "timestamptz", notNull: field.required === true }];
230
+ case "tz":
231
+ return [{ name: snake, pgType: "text", notNull: field.required === true }];
232
+ case "locatedTimestamp":
233
+ return [
234
+ {
235
+ name: `${snake}_utc`,
236
+ pgType: "timestamptz",
237
+ notNull: field.required === true,
238
+ },
239
+ { name: `${snake}_tz`, pgType: "text", notNull: field.required === true },
240
+ ];
241
+ case "file":
242
+ case "image":
243
+ return [{ name: snake, pgType: "uuid", notNull: field.required === true }];
244
+ case "files":
245
+ case "images":
246
+ return [];
247
+ default:
248
+ return [];
249
+ }
250
+ }
251
+
252
+ function resolveTableName(
253
+ entityName: string,
254
+ entity: EntityDefinition,
255
+ featureName: string | undefined,
256
+ ): string {
257
+ const baseName = entity.table ?? toTableName(entityName);
258
+ if (!featureName) return baseName;
259
+ if (baseName.startsWith(READ_MODEL_PREFIX)) {
260
+ return `${READ_MODEL_PREFIX}${featureName}_${baseName.slice(READ_MODEL_PREFIX.length)}`;
261
+ }
262
+ return `${featureName}_${baseName}`;
263
+ }
264
+
265
+ export type BuildEntityTableMetaOptions = {
266
+ readonly featureName?: string;
267
+ readonly relations?: EntityRelations;
268
+ };
269
+
270
+ export function buildEntityTableMeta(
271
+ entityName: string,
272
+ entity: EntityDefinition,
273
+ options?: BuildEntityTableMetaOptions,
274
+ ): EntityTableMeta {
275
+ const tableName = resolveTableName(entityName, entity, options?.featureName);
276
+ const idType = entity.idType ?? "uuid";
277
+
278
+ // Base-columns first, then user-fields. User-fields with the same
279
+ // pg-name as a base-column OVERRIDE the base-column (last-wins, gleiches
280
+ // Verhalten wie drizzle's `{ ...base, ...fields }` Spread im table-
281
+ // builder). Use-case: user-session hat `tenantId` als field um access-
282
+ // control aufzudrücken, fileRef hat `insertedAt` als field für sortable/
283
+ // filterable-marker. Die DB-Spalte bleibt die gleiche, nur Application-
284
+ // Metadata auf der Field-Seite ändert sich.
285
+ const baseCols = fullBaseColumns(idType, entity.softDelete === true);
286
+ const colByName = new Map<string, ColumnMeta>();
287
+ for (const c of baseCols) colByName.set(c.name, c);
288
+
289
+ const fieldNameToSnake = new Map<string, string>();
290
+ for (const [name, field] of Object.entries(entity.fields)) {
291
+ const fieldCols = fieldToColumnMeta(name, field, entity);
292
+ for (const c of fieldCols) colByName.set(c.name, c);
293
+ if (fieldCols.length === 1 && fieldCols[0]) fieldNameToSnake.set(name, fieldCols[0].name);
294
+ }
295
+
296
+ // Preserve base-col order, then any new user-col-names in fields-order.
297
+ const columns: ColumnMeta[] = [];
298
+ const seen = new Set<string>();
299
+ for (const c of baseCols) {
300
+ const final = colByName.get(c.name);
301
+ if (final && !seen.has(final.name)) {
302
+ columns.push(final);
303
+ seen.add(final.name);
304
+ }
305
+ }
306
+ for (const c of colByName.values()) {
307
+ if (!seen.has(c.name)) {
308
+ columns.push(c);
309
+ seen.add(c.name);
310
+ }
311
+ }
312
+
313
+ const indexes: IndexMeta[] = [{ name: `${tableName}_tenant_id_idx`, columns: ["tenant_id"] }];
314
+
315
+ // FK-Indexes: file/image-Felder + belongsTo-Relations
316
+ const fkSnakeNames = new Set<string>();
317
+ for (const [name, field] of Object.entries(entity.fields)) {
318
+ if (field.type === "file" || field.type === "image") fkSnakeNames.add(toSnakeCase(name));
319
+ }
320
+ if (options?.relations) {
321
+ for (const rel of Object.values(options.relations)) {
322
+ if (rel.type === "belongsTo") {
323
+ const snake = fieldNameToSnake.get(rel.foreignKey) ?? toSnakeCase(rel.foreignKey);
324
+ fkSnakeNames.add(snake);
325
+ }
326
+ }
327
+ }
328
+ for (const snake of fkSnakeNames) {
329
+ indexes.push({ name: `${tableName}_${snake}_idx`, columns: [snake] });
330
+ }
331
+
332
+ // Explizit deklarierte indexes (EntityIndexDef). `def.where` ist heute
333
+ // ein drizzle SQL-AST — wir können daraus keinen zuverlässigen Raw-SQL-
334
+ // String rendern (queryChunks sind internal). Wenn ein where gesetzt
335
+ // ist, markieren wir den IndexMeta mit needsManualWhere=true; der DDL-
336
+ // Renderer emittiert das Statement dann als AUSKOMMENTIERT mit Warn-
337
+ // Hinweis. App-Author muss das im generierten SQL-File hand-editieren.
338
+ for (const def of (entity.indexes ?? []) as readonly EntityIndexDef[]) {
339
+ const cols = def.columns.map(
340
+ (fieldName) => fieldNameToSnake.get(fieldName) ?? toSnakeCase(fieldName),
341
+ );
342
+ const suffix = def.unique === true ? "unique" : "idx";
343
+ const indexName = def.name ?? `${tableName}_${cols.join("_")}_${suffix}`;
344
+ indexes.push({
345
+ name: indexName,
346
+ columns: cols,
347
+ ...(def.unique === true && { unique: true }),
348
+ ...(def.where !== undefined && { needsManualWhere: true }),
349
+ });
350
+ }
351
+
352
+ return {
353
+ tableName,
354
+ columns,
355
+ indexes,
356
+ source: "managed",
357
+ };
358
+ }
359
+
360
+ // Escape-Hatch für Tabellen die NICHT durch das Entity-System gemanagt
361
+ // werden. Kein Audit-Trail (keine version, inserted_at, modified_by etc.),
362
+ // kein automatischer tenant_id-Index, kein softDelete-Support.
363
+ //
364
+ // **Vorsicht-vor-Use:** wenn du das hier benutzt, gibst du das Standard-
365
+ // Audit-Pattern auf. Begründe im Code WARUM (child-projection ohne tenant-
366
+ // scope, aggregate-id-PK ohne DEFAULT, append-only-log mit serial PK,
367
+ // performance-critical hot-path ohne version-check, …). Reviewer sollten
368
+ // jede neue defineUnmanagedTable-Stelle prüfen.
369
+ //
370
+ // Heutige use-cases im framework:
371
+ // - `read_delivery_attempts` — id kommt aus dem Aggregate-Stream
372
+ // - `read_job_run_logs` — child-table, serial PK, kein tenant-scope
373
+ export type UnmanagedTableInput = {
374
+ readonly tableName: string;
375
+ readonly columns: readonly ColumnMeta[];
376
+ readonly indexes?: readonly IndexMeta[];
377
+ readonly compositePrimaryKey?: CompositePrimaryKeyMeta;
378
+ };
379
+
380
+ export function defineUnmanagedTable(input: UnmanagedTableInput): EntityTableMeta {
381
+ return {
382
+ tableName: input.tableName,
383
+ columns: input.columns,
384
+ indexes: input.indexes ?? [],
385
+ ...(input.compositePrimaryKey !== undefined && {
386
+ compositePrimaryKey: input.compositePrimaryKey,
387
+ }),
388
+ source: "unmanaged",
389
+ };
390
+ }