@cosmicdrift/kumiko-framework 0.1.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 (388) hide show
  1. package/README.md +159 -0
  2. package/package.json +91 -0
  3. package/src/__tests__/anonymous-access.integration.ts +325 -0
  4. package/src/__tests__/error-contract.integration.ts +435 -0
  5. package/src/__tests__/field-access.integration.ts +269 -0
  6. package/src/__tests__/full-stack.integration.ts +914 -0
  7. package/src/__tests__/ownership.integration.ts +449 -0
  8. package/src/__tests__/reference-data.integration.ts +198 -0
  9. package/src/__tests__/transition-guard.integration.ts +340 -0
  10. package/src/api/__tests__/api.test.ts +337 -0
  11. package/src/api/__tests__/auth-middleware-transport.test.ts +80 -0
  12. package/src/api/__tests__/auth-routes-cookie.test.ts +179 -0
  13. package/src/api/__tests__/batch.integration.ts +404 -0
  14. package/src/api/__tests__/body-limit.test.ts +88 -0
  15. package/src/api/__tests__/csrf-middleware.test.ts +97 -0
  16. package/src/api/__tests__/dispatcher-live.integration.ts +216 -0
  17. package/src/api/__tests__/metrics-endpoint.test.ts +126 -0
  18. package/src/api/__tests__/nested-write.integration.ts +213 -0
  19. package/src/api/__tests__/readiness.test.ts +76 -0
  20. package/src/api/__tests__/request-id-middleware.test.ts +72 -0
  21. package/src/api/__tests__/sse-broker.test.ts +58 -0
  22. package/src/api/__tests__/sse-route.test.ts +112 -0
  23. package/src/api/anonymous-cookie.ts +60 -0
  24. package/src/api/api-constants.ts +64 -0
  25. package/src/api/auth-middleware.ts +418 -0
  26. package/src/api/auth-routes.ts +982 -0
  27. package/src/api/csrf-middleware.ts +77 -0
  28. package/src/api/index.ts +31 -0
  29. package/src/api/jwt.ts +66 -0
  30. package/src/api/observability-middleware.ts +89 -0
  31. package/src/api/readiness.ts +132 -0
  32. package/src/api/request-context.ts +49 -0
  33. package/src/api/request-id-middleware.ts +50 -0
  34. package/src/api/route-registrars.ts +195 -0
  35. package/src/api/routes.ts +135 -0
  36. package/src/api/server.ts +640 -0
  37. package/src/api/sse-broker.ts +71 -0
  38. package/src/api/sse-route.ts +62 -0
  39. package/src/api/tokens.ts +16 -0
  40. package/src/db/__tests__/apply-entity-event-tenant.integration.ts +159 -0
  41. package/src/db/__tests__/compound-types.test.ts +114 -0
  42. package/src/db/__tests__/connection-options.test.ts +68 -0
  43. package/src/db/__tests__/cursor.test.ts +41 -0
  44. package/src/db/__tests__/db-helpers.test.ts +369 -0
  45. package/src/db/__tests__/dialect-instant.test.ts +50 -0
  46. package/src/db/__tests__/drizzle-helpers.integration.ts +186 -0
  47. package/src/db/__tests__/drizzle-table-types.test.ts +162 -0
  48. package/src/db/__tests__/encryption.test.ts +39 -0
  49. package/src/db/__tests__/event-store-executor-list.integration.ts +313 -0
  50. package/src/db/__tests__/event-store-executor.integration.ts +235 -0
  51. package/src/db/__tests__/implicit-projection-equivalence.integration.ts +304 -0
  52. package/src/db/__tests__/located-timestamp.test.ts +184 -0
  53. package/src/db/__tests__/money.test.ts +199 -0
  54. package/src/db/__tests__/multi-row-insert.integration.ts +76 -0
  55. package/src/db/__tests__/parse-auto-verb.test.ts +70 -0
  56. package/src/db/__tests__/required-not-null-migration-safety.integration.ts +105 -0
  57. package/src/db/__tests__/row-helpers.test.ts +59 -0
  58. package/src/db/__tests__/schema-migration.integration.ts +273 -0
  59. package/src/db/__tests__/table-builder-indexes.test.ts +153 -0
  60. package/src/db/__tests__/table-builder-required.test.ts +216 -0
  61. package/src/db/__tests__/tenant-db.integration.ts +606 -0
  62. package/src/db/__tests__/unique-violation-mapping.integration.ts +166 -0
  63. package/src/db/apply-entity-event.ts +188 -0
  64. package/src/db/assert-exists-in.ts +59 -0
  65. package/src/db/compound-types.ts +47 -0
  66. package/src/db/connection.ts +104 -0
  67. package/src/db/cursor.ts +83 -0
  68. package/src/db/dialect.ts +109 -0
  69. package/src/db/eagerload.ts +174 -0
  70. package/src/db/encryption.ts +39 -0
  71. package/src/db/event-store-executor.ts +906 -0
  72. package/src/db/index.ts +55 -0
  73. package/src/db/located-timestamp.ts +114 -0
  74. package/src/db/money.ts +120 -0
  75. package/src/db/pg-error.ts +46 -0
  76. package/src/db/reference-data.ts +77 -0
  77. package/src/db/row-helpers.ts +53 -0
  78. package/src/db/schema-inspection.ts +25 -0
  79. package/src/db/table-builder.ts +475 -0
  80. package/src/db/tenant-db.ts +434 -0
  81. package/src/engine/__tests__/auth-claims-registrar.test.ts +74 -0
  82. package/src/engine/__tests__/boot-validator-located-timestamps.test.ts +108 -0
  83. package/src/engine/__tests__/boot-validator.test.ts +1865 -0
  84. package/src/engine/__tests__/build-app-schema.test.ts +154 -0
  85. package/src/engine/__tests__/claim-keys.test.ts +274 -0
  86. package/src/engine/__tests__/config-helpers.test.ts +236 -0
  87. package/src/engine/__tests__/effective-features.test.ts +86 -0
  88. package/src/engine/__tests__/engine.test.ts +1461 -0
  89. package/src/engine/__tests__/entity-handlers.test.ts +274 -0
  90. package/src/engine/__tests__/event-helpers.test.ts +68 -0
  91. package/src/engine/__tests__/extends-registrar.test.ts +159 -0
  92. package/src/engine/__tests__/factories-long-text.test.ts +84 -0
  93. package/src/engine/__tests__/factories-time.test.ts +158 -0
  94. package/src/engine/__tests__/field-predicates.test.ts +48 -0
  95. package/src/engine/__tests__/hook-phases.test.ts +132 -0
  96. package/src/engine/__tests__/identifiers.test.ts +35 -0
  97. package/src/engine/__tests__/lifecycle-hooks.test.ts +237 -0
  98. package/src/engine/__tests__/nav.test.ts +267 -0
  99. package/src/engine/__tests__/ownership.test.ts +421 -0
  100. package/src/engine/__tests__/parse-ref-target.test.ts +43 -0
  101. package/src/engine/__tests__/projection-helpers.test.ts +62 -0
  102. package/src/engine/__tests__/projection.test.ts +191 -0
  103. package/src/engine/__tests__/qualified-name.test.ts +264 -0
  104. package/src/engine/__tests__/resolve-config-or-param.test.ts +315 -0
  105. package/src/engine/__tests__/run-in.test.ts +38 -0
  106. package/src/engine/__tests__/schema-builder.test.ts +380 -0
  107. package/src/engine/__tests__/screen.test.ts +408 -0
  108. package/src/engine/__tests__/state-machine.test.ts +148 -0
  109. package/src/engine/__tests__/system-user.test.ts +57 -0
  110. package/src/engine/__tests__/validation-hooks.test.ts +71 -0
  111. package/src/engine/access.ts +23 -0
  112. package/src/engine/boot-validator.ts +1528 -0
  113. package/src/engine/build-app-schema.ts +125 -0
  114. package/src/engine/config-helpers.ts +115 -0
  115. package/src/engine/constants.ts +85 -0
  116. package/src/engine/create-app.ts +98 -0
  117. package/src/engine/define-feature.ts +702 -0
  118. package/src/engine/define-handler.ts +78 -0
  119. package/src/engine/define-roles.ts +19 -0
  120. package/src/engine/effective-features.ts +87 -0
  121. package/src/engine/entity-handlers.ts +364 -0
  122. package/src/engine/event-helpers.ts +73 -0
  123. package/src/engine/factories.ts +328 -0
  124. package/src/engine/feature-ast/__tests__/canonical-form.test.ts +416 -0
  125. package/src/engine/feature-ast/__tests__/parse-happy-path.test.ts +197 -0
  126. package/src/engine/feature-ast/__tests__/parse-real-features.test.ts +128 -0
  127. package/src/engine/feature-ast/__tests__/parse.test.ts +888 -0
  128. package/src/engine/feature-ast/__tests__/patch.test.ts +360 -0
  129. package/src/engine/feature-ast/__tests__/patcher.test.ts +469 -0
  130. package/src/engine/feature-ast/__tests__/render-roundtrip.test.ts +287 -0
  131. package/src/engine/feature-ast/extractors.ts +2562 -0
  132. package/src/engine/feature-ast/index.ts +105 -0
  133. package/src/engine/feature-ast/parse.ts +369 -0
  134. package/src/engine/feature-ast/patch.ts +525 -0
  135. package/src/engine/feature-ast/patcher.ts +518 -0
  136. package/src/engine/feature-ast/patterns.ts +434 -0
  137. package/src/engine/feature-ast/render.ts +602 -0
  138. package/src/engine/feature-ast/source-location.ts +45 -0
  139. package/src/engine/field-access.ts +120 -0
  140. package/src/engine/index.ts +254 -0
  141. package/src/engine/ownership.ts +337 -0
  142. package/src/engine/parse-ref-target.ts +22 -0
  143. package/src/engine/pattern-library/__tests__/library.test.ts +351 -0
  144. package/src/engine/pattern-library/index.ts +24 -0
  145. package/src/engine/pattern-library/library.ts +1117 -0
  146. package/src/engine/pattern-library/types.ts +255 -0
  147. package/src/engine/projection-helpers.ts +85 -0
  148. package/src/engine/qualified-name.ts +122 -0
  149. package/src/engine/read-claim.ts +31 -0
  150. package/src/engine/registry.ts +1325 -0
  151. package/src/engine/resolve-config-or-param.ts +153 -0
  152. package/src/engine/run-in.ts +29 -0
  153. package/src/engine/schema-builder.ts +175 -0
  154. package/src/engine/screen-filter-ops.ts +51 -0
  155. package/src/engine/state-machine.ts +70 -0
  156. package/src/engine/system-user.ts +32 -0
  157. package/src/engine/types/config.ts +306 -0
  158. package/src/engine/types/event-type-map.ts +37 -0
  159. package/src/engine/types/feature.ts +574 -0
  160. package/src/engine/types/fields.ts +422 -0
  161. package/src/engine/types/handlers.ts +742 -0
  162. package/src/engine/types/hooks.ts +142 -0
  163. package/src/engine/types/http-route.ts +54 -0
  164. package/src/engine/types/identifiers.ts +47 -0
  165. package/src/engine/types/index.ts +208 -0
  166. package/src/engine/types/nav.ts +46 -0
  167. package/src/engine/types/projection.ts +132 -0
  168. package/src/engine/types/relations.ts +51 -0
  169. package/src/engine/types/screen.ts +452 -0
  170. package/src/engine/types/workspace.ts +42 -0
  171. package/src/engine/validation.ts +33 -0
  172. package/src/entrypoint/__tests__/entrypoint-job-wiring.integration.ts +173 -0
  173. package/src/entrypoint/__tests__/split-deploy.integration.ts +297 -0
  174. package/src/entrypoint/index.ts +442 -0
  175. package/src/errors/__tests__/classes.test.ts +371 -0
  176. package/src/errors/__tests__/write-failures.test.ts +109 -0
  177. package/src/errors/classes.ts +249 -0
  178. package/src/errors/i18n/de.yaml +83 -0
  179. package/src/errors/i18n/en.yaml +80 -0
  180. package/src/errors/index.ts +41 -0
  181. package/src/errors/kumiko-error.ts +67 -0
  182. package/src/errors/reasons.ts +36 -0
  183. package/src/errors/serialize.ts +136 -0
  184. package/src/errors/transition-details.ts +30 -0
  185. package/src/errors/write-error-info.ts +123 -0
  186. package/src/errors/zod-bridge.ts +49 -0
  187. package/src/event-store/__tests__/admin-api.integration.ts +361 -0
  188. package/src/event-store/__tests__/event-store.integration.ts +584 -0
  189. package/src/event-store/__tests__/get-stream-version-perf.integration.ts +83 -0
  190. package/src/event-store/__tests__/perf.integration.ts +255 -0
  191. package/src/event-store/__tests__/snapshot.integration.ts +267 -0
  192. package/src/event-store/__tests__/upcaster-dead-letter.integration.ts +204 -0
  193. package/src/event-store/__tests__/upcaster.integration.ts +460 -0
  194. package/src/event-store/admin-api.ts +257 -0
  195. package/src/event-store/archive.ts +106 -0
  196. package/src/event-store/errors.ts +35 -0
  197. package/src/event-store/event-store.ts +405 -0
  198. package/src/event-store/events-schema.ts +90 -0
  199. package/src/event-store/index.ts +50 -0
  200. package/src/event-store/snapshot.ts +210 -0
  201. package/src/event-store/upcaster-dead-letter.ts +119 -0
  202. package/src/event-store/upcaster.ts +147 -0
  203. package/src/files/__tests__/content-disposition.test.ts +123 -0
  204. package/src/files/__tests__/file-field-column.integration.ts +103 -0
  205. package/src/files/__tests__/file-field-pipeline.integration.ts +211 -0
  206. package/src/files/__tests__/file-handle.test.ts +122 -0
  207. package/src/files/__tests__/files.integration.ts +830 -0
  208. package/src/files/__tests__/storage-tracking.integration.ts +153 -0
  209. package/src/files/content-disposition.ts +55 -0
  210. package/src/files/file-handle.ts +63 -0
  211. package/src/files/file-ref-table.ts +22 -0
  212. package/src/files/file-routes.ts +353 -0
  213. package/src/files/in-memory-provider.ts +62 -0
  214. package/src/files/index.ts +29 -0
  215. package/src/files/local-provider.ts +35 -0
  216. package/src/files/storage-tracking.ts +60 -0
  217. package/src/files/types.ts +118 -0
  218. package/src/i18n/__tests__/i18n.test.ts +72 -0
  219. package/src/i18n/index.ts +29 -0
  220. package/src/jobs/__tests__/job-event-trigger.integration.ts +172 -0
  221. package/src/jobs/__tests__/job-multi-trigger.integration.ts +144 -0
  222. package/src/jobs/__tests__/jobs.integration.ts +566 -0
  223. package/src/jobs/index.ts +2 -0
  224. package/src/jobs/job-runner.ts +574 -0
  225. package/src/lifecycle/__tests__/create-test-lifecycle.ts +19 -0
  226. package/src/lifecycle/__tests__/lifecycle-server.integration.ts +108 -0
  227. package/src/lifecycle/__tests__/lifecycle.test.ts +212 -0
  228. package/src/lifecycle/__tests__/signal-handlers.test.ts +106 -0
  229. package/src/lifecycle/index.ts +13 -0
  230. package/src/lifecycle/lifecycle.ts +160 -0
  231. package/src/lifecycle/signal-handlers.ts +62 -0
  232. package/src/logging/__tests__/pino-trace-bridge.test.ts +50 -0
  233. package/src/logging/index.ts +3 -0
  234. package/src/logging/pino-logger.ts +64 -0
  235. package/src/logging/types.ts +7 -0
  236. package/src/migrations/__tests__/compare-snapshots.test.ts +150 -0
  237. package/src/migrations/__tests__/detect-drift.integration.ts +320 -0
  238. package/src/migrations/__tests__/detect-projections-to-rebuild.integration.ts +134 -0
  239. package/src/migrations/__tests__/rebuild-marker.test.ts +79 -0
  240. package/src/migrations/index.ts +28 -0
  241. package/src/migrations/projection-detection.ts +149 -0
  242. package/src/migrations/rebuild-marker.ts +64 -0
  243. package/src/migrations/schema-drift.ts +395 -0
  244. package/src/observability/__tests__/console-provider.test.ts +67 -0
  245. package/src/observability/__tests__/metric-validator.test.ts +87 -0
  246. package/src/observability/__tests__/noop-provider.test.ts +82 -0
  247. package/src/observability/__tests__/observability.integration.ts +559 -0
  248. package/src/observability/__tests__/prometheus-meter.test.ts +144 -0
  249. package/src/observability/__tests__/recording-meter.test.ts +101 -0
  250. package/src/observability/__tests__/recording-tracer.test.ts +110 -0
  251. package/src/observability/__tests__/sensitive-filter.test.ts +98 -0
  252. package/src/observability/console-provider.ts +130 -0
  253. package/src/observability/context.ts +26 -0
  254. package/src/observability/fallback.ts +34 -0
  255. package/src/observability/ids.ts +25 -0
  256. package/src/observability/index.ts +79 -0
  257. package/src/observability/metric-validator.ts +86 -0
  258. package/src/observability/metrics-handle.ts +56 -0
  259. package/src/observability/noop-provider.ts +146 -0
  260. package/src/observability/prometheus-meter.ts +284 -0
  261. package/src/observability/recording-meter.ts +156 -0
  262. package/src/observability/recording-tracer.ts +198 -0
  263. package/src/observability/redis-wrapper.ts +132 -0
  264. package/src/observability/sensitive-filter.ts +108 -0
  265. package/src/observability/standard-metrics.ts +213 -0
  266. package/src/observability/types/index.ts +29 -0
  267. package/src/observability/types/metric.ts +56 -0
  268. package/src/observability/types/provider.ts +32 -0
  269. package/src/observability/types/span.ts +64 -0
  270. package/src/pipeline/__tests__/archive-stream.integration.ts +220 -0
  271. package/src/pipeline/__tests__/auth-claims-resolver.test.ts +279 -0
  272. package/src/pipeline/__tests__/cascade-handler.integration.ts +419 -0
  273. package/src/pipeline/__tests__/cascade-handler.test.ts +52 -0
  274. package/src/pipeline/__tests__/causation-chain.integration.ts +206 -0
  275. package/src/pipeline/__tests__/ctx-bridge.integration.ts +234 -0
  276. package/src/pipeline/__tests__/dispatcher.test.ts +379 -0
  277. package/src/pipeline/__tests__/distributed-lock.integration.ts +67 -0
  278. package/src/pipeline/__tests__/domain-events-projections.integration.ts +323 -0
  279. package/src/pipeline/__tests__/event-dedup.integration.ts +153 -0
  280. package/src/pipeline/__tests__/event-define-event-strict.integration.ts +202 -0
  281. package/src/pipeline/__tests__/event-dispatcher-lifecycle.integration.ts +220 -0
  282. package/src/pipeline/__tests__/event-dispatcher-multi-instance.integration.ts +423 -0
  283. package/src/pipeline/__tests__/event-dispatcher-pg-listen.integration.ts +123 -0
  284. package/src/pipeline/__tests__/event-dispatcher-recovery.integration.ts +202 -0
  285. package/src/pipeline/__tests__/event-dispatcher-second-audit.integration.ts +290 -0
  286. package/src/pipeline/__tests__/event-dispatcher-strict.test.ts +65 -0
  287. package/src/pipeline/__tests__/event-dispatcher.integration.ts +287 -0
  288. package/src/pipeline/__tests__/event-retention.integration.ts +239 -0
  289. package/src/pipeline/__tests__/fetch-for-writing.integration.ts +281 -0
  290. package/src/pipeline/__tests__/lifecycle-pipeline.test.ts +430 -0
  291. package/src/pipeline/__tests__/load-aggregate-query.integration.ts +266 -0
  292. package/src/pipeline/__tests__/msp-error-mode.integration.ts +149 -0
  293. package/src/pipeline/__tests__/msp-multi-hop.integration.ts +228 -0
  294. package/src/pipeline/__tests__/msp-rebuild.integration.ts +368 -0
  295. package/src/pipeline/__tests__/multi-stream-projection.integration.ts +341 -0
  296. package/src/pipeline/__tests__/perf-rebuild.integration.ts +147 -0
  297. package/src/pipeline/__tests__/projection-rebuild.integration.ts +551 -0
  298. package/src/pipeline/__tests__/query-projection.integration.ts +201 -0
  299. package/src/pipeline/__tests__/redis-pipeline.integration.ts +306 -0
  300. package/src/pipeline/append-event-core.ts +117 -0
  301. package/src/pipeline/auth-claims-resolver.ts +103 -0
  302. package/src/pipeline/cascade-handler.ts +113 -0
  303. package/src/pipeline/dispatcher.ts +1585 -0
  304. package/src/pipeline/distributed-lock.ts +37 -0
  305. package/src/pipeline/entity-cache.ts +113 -0
  306. package/src/pipeline/event-consumer-state.ts +108 -0
  307. package/src/pipeline/event-dedup.ts +23 -0
  308. package/src/pipeline/event-dispatcher.ts +1016 -0
  309. package/src/pipeline/event-retention.ts +154 -0
  310. package/src/pipeline/idempotency.ts +76 -0
  311. package/src/pipeline/index.ts +66 -0
  312. package/src/pipeline/lifecycle-pipeline.ts +409 -0
  313. package/src/pipeline/msp-rebuild.ts +242 -0
  314. package/src/pipeline/multi-stream-apply-context.ts +115 -0
  315. package/src/pipeline/projection-rebuild.ts +334 -0
  316. package/src/pipeline/projection-state.ts +72 -0
  317. package/src/pipeline/projections-runner.ts +56 -0
  318. package/src/pipeline/redis-keys.ts +11 -0
  319. package/src/pipeline/system-hooks.ts +190 -0
  320. package/src/random/__tests__/generate.test.ts +149 -0
  321. package/src/random/generate.ts +141 -0
  322. package/src/random/index.ts +8 -0
  323. package/src/random/words.ts +392 -0
  324. package/src/rate-limit/__tests__/dispatcher-l3.integration.ts +111 -0
  325. package/src/rate-limit/__tests__/middleware.integration.ts +189 -0
  326. package/src/rate-limit/__tests__/resolver.integration.ts +189 -0
  327. package/src/rate-limit/bucket.ts +36 -0
  328. package/src/rate-limit/index.ts +14 -0
  329. package/src/rate-limit/middleware.ts +152 -0
  330. package/src/rate-limit/resolver.ts +267 -0
  331. package/src/redis/__tests__/redis-options.test.ts +54 -0
  332. package/src/redis/index.ts +74 -0
  333. package/src/search/__tests__/meilisearch-adapter.integration.ts +236 -0
  334. package/src/search/__tests__/search-adapter.test.ts +256 -0
  335. package/src/search/in-memory-adapter.ts +123 -0
  336. package/src/search/index.ts +12 -0
  337. package/src/search/meilisearch-adapter.ts +106 -0
  338. package/src/search/types.ts +39 -0
  339. package/src/secrets/__tests__/dek-cache.test.ts +213 -0
  340. package/src/secrets/__tests__/env-master-key-provider.test.ts +119 -0
  341. package/src/secrets/__tests__/envelope.test.ts +74 -0
  342. package/src/secrets/__tests__/leak-guard.test.ts +92 -0
  343. package/src/secrets/__tests__/rotation.test.ts +149 -0
  344. package/src/secrets/dek-cache.ts +116 -0
  345. package/src/secrets/env-master-key-provider.ts +162 -0
  346. package/src/secrets/envelope.ts +55 -0
  347. package/src/secrets/index.ts +19 -0
  348. package/src/secrets/leak-guard.ts +87 -0
  349. package/src/secrets/rotation.ts +34 -0
  350. package/src/secrets/types.ts +107 -0
  351. package/src/stack/db.ts +104 -0
  352. package/src/stack/event-collector.ts +23 -0
  353. package/src/stack/index.ts +32 -0
  354. package/src/stack/redis.ts +44 -0
  355. package/src/stack/request-helper.ts +168 -0
  356. package/src/stack/table-helpers.ts +104 -0
  357. package/src/stack/test-stack.ts +357 -0
  358. package/src/stack/test-users.ts +37 -0
  359. package/src/testing/__tests__/e2e-generator.test.ts +230 -0
  360. package/src/testing/__tests__/ensure-entity-table.integration.ts +54 -0
  361. package/src/testing/access-assertions.ts +15 -0
  362. package/src/testing/assertions.ts +35 -0
  363. package/src/testing/e2e-generator.ts +465 -0
  364. package/src/testing/expect-error.ts +25 -0
  365. package/src/testing/handler-context.ts +125 -0
  366. package/src/testing/http-cookies.ts +52 -0
  367. package/src/testing/index.ts +41 -0
  368. package/src/testing/late-bound.ts +39 -0
  369. package/src/testing/mutable-master-key-provider.ts +31 -0
  370. package/src/testing/observability-recorder.ts +54 -0
  371. package/src/testing/shared-entities.ts +49 -0
  372. package/src/testing/utils.ts +1 -0
  373. package/src/testing/wait-for.ts +31 -0
  374. package/src/time/__tests__/polyfill.test.ts +73 -0
  375. package/src/time/__tests__/tz-context.test.ts +121 -0
  376. package/src/time/index.ts +21 -0
  377. package/src/time/polyfill.ts +70 -0
  378. package/src/time/tz-context.ts +107 -0
  379. package/src/ui-types/app-schema.ts +57 -0
  380. package/src/ui-types/index.ts +65 -0
  381. package/src/utils/__tests__/assert.test.ts +17 -0
  382. package/src/utils/__tests__/env-parse.test.ts +54 -0
  383. package/src/utils/assert.ts +18 -0
  384. package/src/utils/env-parse.ts +16 -0
  385. package/src/utils/ids.ts +16 -0
  386. package/src/utils/index.ts +5 -0
  387. package/src/utils/safe-json.ts +30 -0
  388. package/src/utils/serialization.ts +7 -0
@@ -0,0 +1,328 @@
1
+ import type {
2
+ BooleanFieldDef,
3
+ DateFieldDef,
4
+ EmbeddedFieldDef,
5
+ EntityDefinition,
6
+ FieldsMap,
7
+ FileFieldDef,
8
+ FilesFieldDef,
9
+ ImageFieldDef,
10
+ ImagesFieldDef,
11
+ LocatedTimestampFieldDef,
12
+ LongTextFieldDef,
13
+ MoneyFieldDef,
14
+ MultiSelectFieldDef,
15
+ NumberFieldDef,
16
+ SelectFieldDef,
17
+ TextFieldDef,
18
+ TimestampFieldDef,
19
+ TzFieldDef,
20
+ } from "./types";
21
+
22
+ // Generic über `R extends true | false` (statt `boolean`) damit
23
+ // `createTextField({ required: true })` literal `required: true` im
24
+ // Return-Type behält. `boolean` würde widenen — DrizzleTable<E>'s
25
+ // Mapped-Type könnte dann nicht zwischen `required: true` und
26
+ // `required: false` dispatchen, jede Column würde zu nullable
27
+ // degradieren. Default `R = false` matcht den runtime-default. Pattern
28
+ // in jeder required-bearing factory unten.
29
+ export function createTextField<R extends true | false = false>(
30
+ overrides?: Partial<Omit<TextFieldDef, "type" | "required">> & { required?: R },
31
+ ): TextFieldDef & { required: R } {
32
+ return {
33
+ type: "text",
34
+ maxLength: 200,
35
+ required: false,
36
+ searchable: false,
37
+ sortable: false,
38
+ ...overrides,
39
+ } as TextFieldDef & { required: R };
40
+ }
41
+
42
+ /**
43
+ * Long-form text field for source-code, markdown, blog-posts, email-
44
+ * templates — anything that can be megabytes large. Type-level differs
45
+ * from `text`: keine sortable/searchable/filterable/format options.
46
+ * DB-mapping ist identisch zu text (PG text ist unbounded).
47
+ *
48
+ * Soft-cap default: kein maxLength (PG text ist 1 GB hart begrenzt).
49
+ * Setze einen explicit `maxLength` wenn du ein verirrtes Browser-Paste
50
+ * früh ablehnen willst (z.B. 1_000_000 = 1 MB).
51
+ */
52
+ export function createLongTextField<R extends true | false = false>(
53
+ overrides?: Partial<Omit<LongTextFieldDef, "type" | "required">> & { required?: R },
54
+ ): LongTextFieldDef & { required: R } {
55
+ return {
56
+ type: "longText",
57
+ required: false,
58
+ ...overrides,
59
+ } as LongTextFieldDef & { required: R };
60
+ }
61
+
62
+ export function createBooleanField<R extends true | false = false>(
63
+ overrides?: Partial<Omit<BooleanFieldDef, "type" | "required">> & { required?: R },
64
+ ): BooleanFieldDef & { required: R } {
65
+ return {
66
+ type: "boolean",
67
+ required: false,
68
+ default: false,
69
+ ...overrides,
70
+ } as BooleanFieldDef & { required: R };
71
+ }
72
+
73
+ export function createSelectField<
74
+ const TOptions extends readonly string[],
75
+ R extends true | false = false,
76
+ >(
77
+ opts: { options: TOptions } & Partial<
78
+ Omit<SelectFieldDef<TOptions>, "type" | "options" | "required">
79
+ > & { required?: R },
80
+ ): SelectFieldDef<TOptions> & { required: R } {
81
+ return {
82
+ type: "select",
83
+ required: false,
84
+ ...opts,
85
+ } as SelectFieldDef<TOptions> & { required: R };
86
+ }
87
+
88
+ /**
89
+ * Multi-Select-Field — N Werte aus einer festen Options-Liste.
90
+ *
91
+ * Storage: jsonb-Array<string>. Jeder Eintrag muss in `options` enthalten
92
+ * sein (Boot-Validator). UI-Renderer rendert das als Checkbox-Group oder
93
+ * Multi-Select-Dropdown.
94
+ *
95
+ * ```ts
96
+ * licenceClasses: createMultiSelectField({
97
+ * options: ["B", "BE", "C", "C1", "CE", "C1E", "D", "D1"] as const,
98
+ * default: ["B"],
99
+ * }),
100
+ * ```
101
+ *
102
+ * Caller-API:
103
+ * Write: `{ licenceClasses: ["B", "BE", "C1"] }`
104
+ * Read: `{ licenceClasses: ["B", "BE", "C1"] }`
105
+ *
106
+ * Wann statt `select`: wenn mehrere Werte gleichzeitig erlaubt sind.
107
+ * Wann statt `embedded` mit Booleans: bei mehr als ~5 Optionen.
108
+ */
109
+ export function createMultiSelectField<const TOptions extends readonly string[]>(
110
+ opts: { options: TOptions } & Partial<Omit<MultiSelectFieldDef<TOptions>, "type" | "options">>,
111
+ ): MultiSelectFieldDef<TOptions> {
112
+ return {
113
+ type: "multiSelect",
114
+ required: false,
115
+ ...opts,
116
+ };
117
+ }
118
+
119
+ export function createNumberField<R extends true | false = false>(
120
+ overrides?: Partial<Omit<NumberFieldDef, "type" | "required">> & { required?: R },
121
+ ): NumberFieldDef & { required: R } {
122
+ return {
123
+ type: "number",
124
+ required: false,
125
+ ...overrides,
126
+ } as NumberFieldDef & { required: R };
127
+ }
128
+
129
+ export function createMoneyField<R extends true | false = false>(
130
+ overrides?: Partial<Omit<MoneyFieldDef, "type" | "required">> & { required?: R },
131
+ ): MoneyFieldDef & { required: R } {
132
+ return {
133
+ type: "money",
134
+ ...overrides,
135
+ } as MoneyFieldDef & { required: R };
136
+ }
137
+
138
+ export function createEmbeddedField(
139
+ schema: EmbeddedFieldDef["schema"],
140
+ overrides?: Partial<Omit<EmbeddedFieldDef, "type" | "schema">>,
141
+ ): EmbeddedFieldDef {
142
+ return {
143
+ type: "embedded",
144
+ schema,
145
+ ...overrides,
146
+ };
147
+ }
148
+
149
+ export function createDateField<R extends true | false = false>(
150
+ overrides?: Partial<Omit<DateFieldDef, "type" | "required">> & { required?: R },
151
+ ): DateFieldDef & { required: R } {
152
+ return {
153
+ type: "date",
154
+ required: false,
155
+ ...overrides,
156
+ } as DateFieldDef & { required: R };
157
+ }
158
+
159
+ /**
160
+ * UTC-Instant — für Ereignisse die zu einem bestimmten Zeitpunkt passieren
161
+ * (createdAt, loginAt, actualPickupAt). Temporal.Instant intern.
162
+ *
163
+ * Mit `locatedBy: "<name>Tz"` wird das Feld zum Wall-Clock-Pair eines
164
+ * Termins an einem Ort — bevorzuge dafür den `locatedTimestamp(name)`
165
+ * Helper, der Pair + Marker atomar erzeugt.
166
+ */
167
+ export function createTimestampField<R extends true | false = false>(
168
+ overrides?: Partial<Omit<TimestampFieldDef, "type" | "required">> & { required?: R },
169
+ ): TimestampFieldDef & { required: R } {
170
+ // Object-Build vermeidet hartcodiertes `required: false` im literal —
171
+ // das würde TS dazu bringen, R auf `boolean` zu widenen statt das
172
+ // literal `true`/`false` aus dem overrides-Argument zu inferieren.
173
+ return {
174
+ ...overrides,
175
+ type: "timestamp",
176
+ required: (overrides?.required ?? false) as R,
177
+ };
178
+ }
179
+
180
+ /**
181
+ * IANA-Zonenname (z.B. "Europe/Berlin"). Wird im Boot/Schema-Validator
182
+ * via `Intl.supportedValuesOf("timeZone")` geprüft (kommt im Zod-Schritt).
183
+ */
184
+ export function createTzField<R extends true | false = false>(
185
+ overrides?: Partial<Omit<TzFieldDef, "type" | "required">> & { required?: R },
186
+ ): TzFieldDef & { required: R } {
187
+ return {
188
+ type: "tz",
189
+ required: false,
190
+ ...overrides,
191
+ } as TzFieldDef & { required: R };
192
+ }
193
+
194
+ /**
195
+ * Wall-Clock-Termin an einem Ort als ATOMARES Field. Empfohlene Form für
196
+ * jeden Date-Wert mit Location-Bezug (Pickup, Delivery, Meeting, Schedule).
197
+ *
198
+ * EIN Schema-Feld → ZWEI DB-Spalten (`<name>_utc TIMESTAMPTZ` + `<name>_tz TEXT`)
199
+ * → DREI API-Felder beim Read (`{ at, tz, utc }`).
200
+ *
201
+ * ```ts
202
+ * r.entity("order", {
203
+ * fields: {
204
+ * pickup: createLocatedTimestampField(),
205
+ * delivery: createLocatedTimestampField(),
206
+ * },
207
+ * });
208
+ *
209
+ * // Write — Caller schickt at+tz, Framework rechnet utc aus
210
+ * await create({ pickup: { at: "2026-04-15T10:00:00", tz: "Europe/Lisbon" } });
211
+ *
212
+ * // Read — Framework liefert alle drei Felder zurück
213
+ * // → { pickup: { at: "10:00", tz: "Europe/Lisbon", utc: "09:00Z" } }
214
+ *
215
+ * // Sort/Filter über die UTC-Spalte
216
+ * orderBy(asc(orderTable.pickupUtc))
217
+ * where(between(orderTable.pickupUtc, start, end))
218
+ * ```
219
+ *
220
+ * Default-Sicht für `at` ist Pickup-Ort-lokal (was eingegeben wurde, kommt
221
+ * mit demselben Tag zurück). User-lokale Sicht kommt aus `utc` per
222
+ * separater Berechnung.
223
+ */
224
+ export function createLocatedTimestampField<R extends true | false = false>(
225
+ overrides?: Partial<Omit<LocatedTimestampFieldDef, "type" | "required">> & { required?: R },
226
+ ): LocatedTimestampFieldDef & { required: R } {
227
+ return {
228
+ type: "locatedTimestamp",
229
+ required: false,
230
+ ...overrides,
231
+ } as LocatedTimestampFieldDef & { required: R };
232
+ }
233
+
234
+ /**
235
+ * @deprecated Verwende stattdessen `createLocatedTimestampField()` —
236
+ * EIN Field-Type statt zwei lose Pair-Felder. Migration: ersetze
237
+ * `...locatedTimestamp("pickup")` durch `pickup: createLocatedTimestampField()`.
238
+ *
239
+ * Wall-Clock-Termin an einem Ort — Helper der ZWEI verbundene Felder
240
+ * erzeugt. Bevorzugte Form für jeden Date-Wert mit Location-Bezug
241
+ * (Pickup, Delivery, Meeting, Schedule).
242
+ *
243
+ * ```ts
244
+ * r.entity("order", {
245
+ * fields: {
246
+ * ...locatedTimestamp("pickup"), // → pickupAt + pickupTz
247
+ * ...locatedTimestamp("delivery"), // → deliveryAt + deliveryTz
248
+ * },
249
+ * });
250
+ * ```
251
+ *
252
+ * Zur Laufzeit wird:
253
+ * - DB: `<name>_at TIMESTAMPTZ` (UTC) + `<name>_tz TEXT` (IANA-Name)
254
+ * - JSON: `{ <name>At: "2026-04-03T10:00:00", <name>Tz: "Europe/Lisbon" }`
255
+ * (Wall-Clock OHNE Offset, plus IANA-Name — zwei getrennte Felder)
256
+ * - Reducer/Apply: kann mit Temporal.ZonedDateTime arbeiten
257
+ *
258
+ * Optionen pro Feld (z.B. `required` auf den At-Teil) per zweitem Argument.
259
+ */
260
+ export function locatedTimestamp(
261
+ name: string,
262
+ overrides?: { readonly required?: boolean; readonly access?: TimestampFieldDef["access"] },
263
+ ): Readonly<Record<string, TimestampFieldDef | TzFieldDef>> {
264
+ const atName = `${name}At`;
265
+ const tzName = `${name}Tz`;
266
+ return {
267
+ [atName]: {
268
+ type: "timestamp",
269
+ locatedBy: tzName,
270
+ required: overrides?.required,
271
+ access: overrides?.access,
272
+ },
273
+ [tzName]: {
274
+ type: "tz",
275
+ required: overrides?.required,
276
+ access: overrides?.access,
277
+ },
278
+ };
279
+ }
280
+
281
+ export function createFileField(overrides?: Partial<Omit<FileFieldDef, "type">>): FileFieldDef {
282
+ return { type: "file", ...overrides };
283
+ }
284
+
285
+ export function createImageField(overrides?: Partial<Omit<ImageFieldDef, "type">>): ImageFieldDef {
286
+ return { type: "image", ...overrides };
287
+ }
288
+
289
+ export function createFilesField(overrides?: Partial<Omit<FilesFieldDef, "type">>): FilesFieldDef {
290
+ return { type: "files", ...overrides };
291
+ }
292
+
293
+ export function createImagesField(
294
+ overrides?: Partial<Omit<ImagesFieldDef, "type">>,
295
+ ): ImagesFieldDef {
296
+ return { type: "images", ...overrides };
297
+ }
298
+
299
+ // `F` läuft OHNE Constraint im Generic-Param damit TS die literal-types
300
+ // einzelner Field-Defs durchzieht (required: true bleibt true, nicht
301
+ // boolean). Constraint-Match gegen FieldsMap würde widenen — siehe TS-
302
+ // Issue um Constraint-Inferenz auf strukturellen Records. Stattdessen
303
+ // validieren wir die Conformance via conditional return type: wenn F
304
+ // nicht FieldsMap-compat ist, kollabiert der Return zu `never`.
305
+ export function createEntity<F>(def: {
306
+ readonly table?: string;
307
+ readonly fields: F;
308
+ readonly softDelete?: boolean;
309
+ readonly searchWeight?: number;
310
+ readonly defaultCurrency?: string;
311
+ readonly transitions?: Readonly<Record<string, Readonly<Record<string, readonly string[]>>>>;
312
+ readonly indexes?: readonly {
313
+ readonly columns: readonly [string, ...string[]];
314
+ readonly unique?: boolean;
315
+ readonly name?: string;
316
+ }[];
317
+ readonly idType?: "serial" | "uuid";
318
+ readonly access?: EntityDefinition["access"];
319
+ }): F extends FieldsMap ? EntityDefinition<F> : never {
320
+ return {
321
+ softDelete: false,
322
+ searchWeight: 1,
323
+ // Default to UUID — post-ES-pivot every entity is event-sourced and
324
+ // aggregate-ids are UUID. Opt-out with `idType: "serial"` for pre-ES
325
+ // legacy tables (should be rare).
326
+ ...def,
327
+ } as F extends FieldsMap ? EntityDefinition<F> : never;
328
+ }