@cosmicdrift/kumiko-framework 0.386.0 → 0.388.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 (468) hide show
  1. package/AGENTS.md +6 -1
  2. package/LICENSE +21 -57
  3. package/README.md +2 -2
  4. package/agents/examples/anonymous-access.md +1 -1
  5. package/agents/examples/apex-landing.md +204 -0
  6. package/agents/examples/api-worker-split.md +64 -0
  7. package/agents/examples/app-config.md +14 -0
  8. package/agents/examples/auth-mfa.md +115 -0
  9. package/agents/examples/env-composition.md +28 -1
  10. package/agents/examples/legal-pages.md +1 -1
  11. package/agents/examples/prod-boot-options.md +16 -0
  12. package/agents/examples/rate-limiting.md +48 -0
  13. package/agents/examples/record-detail-layout.md +692 -0
  14. package/agents/examples/seed-migration.md +212 -0
  15. package/agents/examples/wizard-form.md +941 -0
  16. package/agents/examples/writeform-section.md +548 -0
  17. package/agents/features.md +19 -2
  18. package/agents/widgets.md +40 -39
  19. package/dist/api/api-constants.js +2 -2
  20. package/dist/api/auth-middleware.js +7 -7
  21. package/dist/api/auth-rate-limiters.js +7 -3
  22. package/dist/api/auth-routes-mfa.js +1 -1
  23. package/dist/api/auth-routes-session.js +1 -1
  24. package/dist/api/auth-routes-shared.js +7 -3
  25. package/dist/api/auth-routes-signup.js +1 -1
  26. package/dist/api/client-error-route.js +8 -2
  27. package/dist/api/client-ip.js +3 -1
  28. package/dist/api/extra-route.js +1 -1
  29. package/dist/api/index.d.ts +3 -1
  30. package/dist/api/index.js +3 -1
  31. package/dist/api/pii-leak-guard.js +4 -2
  32. package/dist/api/readiness.js +5 -5
  33. package/dist/api/redis-sse-broker.js +8 -6
  34. package/dist/api/request-context.d.ts +1 -1
  35. package/dist/api/request-context.js +1 -1
  36. package/dist/api/routes.js +2 -2
  37. package/dist/api/server-boot-checks.d.ts +10 -0
  38. package/dist/api/server-boot-checks.js +157 -0
  39. package/dist/api/server-event-dispatcher.d.ts +26 -0
  40. package/dist/api/server-event-dispatcher.js +208 -0
  41. package/dist/api/server-extra-routes.d.ts +11 -0
  42. package/dist/api/server-extra-routes.js +203 -0
  43. package/dist/api/server-middleware.d.ts +20 -0
  44. package/dist/api/server-middleware.js +211 -0
  45. package/dist/api/server-routes.d.ts +19 -0
  46. package/dist/api/server-routes.js +293 -0
  47. package/dist/api/server-websocket-routes.d.ts +4 -0
  48. package/dist/api/server-websocket-routes.js +108 -0
  49. package/dist/api/server-wiring.d.ts +32 -0
  50. package/dist/api/server-wiring.js +236 -0
  51. package/dist/api/server.d.ts +10 -15
  52. package/dist/api/server.js +48 -1250
  53. package/dist/api/session-cookies.js +4 -4
  54. package/dist/api/sse-broker.js +1 -1
  55. package/dist/api/sse-route.d.ts +13 -13
  56. package/dist/api/sse-route.js +31 -27
  57. package/dist/auth/index.js +4 -4
  58. package/dist/auth/roles.d.ts +4 -4
  59. package/dist/auth/roles.js +24 -24
  60. package/dist/compliance/duration-spec.js +18 -20
  61. package/dist/compliance/index.js +2 -3
  62. package/dist/compliance/override-schema.d.ts +4 -4
  63. package/dist/compliance/override-schema.js +19 -22
  64. package/dist/compliance/profiles.d.ts +26 -29
  65. package/dist/compliance/profiles.js +62 -69
  66. package/dist/compliance/sub-processors.d.ts +28 -30
  67. package/dist/compliance/sub-processors.js +17 -21
  68. package/dist/consumer-cli.js +4 -4
  69. package/dist/crypto/blind-index.js +18 -17
  70. package/dist/crypto/ciphertext-pattern.js +1 -1
  71. package/dist/crypto/event-pii.js +3 -3
  72. package/dist/crypto/kek-source.d.ts +1 -1
  73. package/dist/crypto/kek-source.js +3 -2
  74. package/dist/crypto/kms-adapter.d.ts +1 -1
  75. package/dist/crypto/kms-adapter.js +4 -6
  76. package/dist/crypto/kms-wiring.d.ts +1 -2
  77. package/dist/crypto/kms-wiring.js +2 -2
  78. package/dist/crypto/owner-transition-rekey.d.ts +5 -1
  79. package/dist/crypto/owner-transition-rekey.js +1 -1
  80. package/dist/crypto/pg-kms-adapter.js +2 -6
  81. package/dist/crypto/pii-field-encryption.d.ts +5 -1
  82. package/dist/crypto/pii-field-encryption.js +7 -5
  83. package/dist/crypto/subject-resolver.d.ts +1 -1
  84. package/dist/crypto/subject-resolver.js +2 -2
  85. package/dist/db/aggregate-sql.d.ts +21 -0
  86. package/dist/db/aggregate-sql.js +155 -0
  87. package/dist/db/apply-entity-event.d.ts +6 -6
  88. package/dist/db/apply-entity-event.js +55 -55
  89. package/dist/db/blind-index-cleanup.js +7 -7
  90. package/dist/db/closed-connection.d.ts +9 -0
  91. package/dist/db/closed-connection.js +95 -0
  92. package/dist/db/collect-table-metas.js +10 -11
  93. package/dist/db/compound-types.d.ts +1 -1
  94. package/dist/db/compound-types.js +12 -12
  95. package/dist/db/cursor.js +3 -4
  96. package/dist/db/dialect.d.ts +2 -2
  97. package/dist/db/dialect.js +3 -3
  98. package/dist/db/distinct-on.d.ts +1 -1
  99. package/dist/db/driver-row-coercion.d.ts +2 -0
  100. package/dist/db/driver-row-coercion.js +186 -0
  101. package/dist/db/driver-value-preparation.d.ts +16 -0
  102. package/dist/db/driver-value-preparation.js +99 -0
  103. package/dist/db/eagerload.d.ts +3 -3
  104. package/dist/db/eagerload.js +21 -12
  105. package/dist/db/entity-field-encryption.d.ts +1 -0
  106. package/dist/db/entity-field-encryption.js +1 -1
  107. package/dist/db/entity-table-meta.d.ts +2 -2
  108. package/dist/db/entity-table-meta.js +105 -112
  109. package/dist/db/event-store-executor-context.d.ts +3 -2
  110. package/dist/db/event-store-executor-context.js +13 -13
  111. package/dist/db/event-store-executor-read-aggregate.d.ts +8 -0
  112. package/dist/db/event-store-executor-read-aggregate.js +112 -0
  113. package/dist/db/event-store-executor-read-filter.d.ts +31 -0
  114. package/dist/db/event-store-executor-read-filter.js +203 -0
  115. package/dist/db/event-store-executor-read-paging.d.ts +14 -0
  116. package/dist/db/event-store-executor-read-paging.js +99 -0
  117. package/dist/db/event-store-executor-read-rows.d.ts +6 -0
  118. package/dist/db/event-store-executor-read-rows.js +32 -0
  119. package/dist/db/event-store-executor-read-search.d.ts +28 -0
  120. package/dist/db/event-store-executor-read-search.js +221 -0
  121. package/dist/db/event-store-executor-read-sort.d.ts +41 -0
  122. package/dist/db/event-store-executor-read-sort.js +130 -0
  123. package/dist/db/event-store-executor-read-where.d.ts +24 -0
  124. package/dist/db/event-store-executor-read-where.js +81 -0
  125. package/dist/db/event-store-executor-read.d.ts +2 -9
  126. package/dist/db/event-store-executor-read.js +50 -704
  127. package/dist/db/event-store-executor-write-steps.d.ts +20 -0
  128. package/dist/db/event-store-executor-write-steps.js +100 -0
  129. package/dist/db/event-store-executor-write.js +401 -510
  130. package/dist/db/index.d.ts +6 -2
  131. package/dist/db/index.js +5 -1
  132. package/dist/db/list-aggregate-labels.d.ts +14 -0
  133. package/dist/db/list-aggregate-labels.js +26 -0
  134. package/dist/db/located-timestamp.d.ts +11 -11
  135. package/dist/db/located-timestamp.js +29 -30
  136. package/dist/db/migrate-generator.d.ts +1 -1
  137. package/dist/db/migrate-generator.js +97 -105
  138. package/dist/db/migrate-runner.js +29 -26
  139. package/dist/db/money.d.ts +6 -6
  140. package/dist/db/money.js +29 -27
  141. package/dist/db/queries/backfill-pii.js +5 -5
  142. package/dist/db/queries/ddl.js +1 -1
  143. package/dist/db/queries/es-ops.d.ts +1 -1
  144. package/dist/db/queries/es-ops.js +1 -1
  145. package/dist/db/queries/event-consumer.js +3 -3
  146. package/dist/db/queries/event-store.js +4 -2
  147. package/dist/db/queries/projection-rebuild.js +3 -3
  148. package/dist/db/queries/raw-sql.d.ts +2 -2
  149. package/dist/db/queries/raw-sql.js +2 -2
  150. package/dist/db/queries/shadow-swap.js +19 -19
  151. package/dist/db/query.d.ts +3 -16
  152. package/dist/db/query.js +8 -761
  153. package/dist/db/rebuild-marker.js +20 -21
  154. package/dist/db/reference-data.js +6 -1
  155. package/dist/db/replay-migration-sql.js +2 -2
  156. package/dist/db/schema-inspection.js +4 -5
  157. package/dist/db/table-builder.d.ts +1 -2
  158. package/dist/db/table-builder.js +137 -190
  159. package/dist/db/table-info.d.ts +10 -0
  160. package/dist/db/table-info.js +45 -0
  161. package/dist/db/temporal-value-guards.d.ts +6 -0
  162. package/dist/db/temporal-value-guards.js +15 -0
  163. package/dist/db/tenant-db-runner.d.ts +1 -0
  164. package/dist/db/tenant-db-runner.js +3 -0
  165. package/dist/db/tenant-db.d.ts +2 -2
  166. package/dist/db/tenant-db.js +48 -11
  167. package/dist/db/where-clause.d.ts +6 -0
  168. package/dist/db/where-clause.js +236 -0
  169. package/dist/derivatives/delete-stored-file.js +6 -2
  170. package/dist/derivatives/derivatives-context.js +1 -1
  171. package/dist/engine/boot-validator/access-roles.js +4 -3
  172. package/dist/engine/boot-validator/api-ext.js +14 -14
  173. package/dist/engine/boot-validator/boot-check.js +1 -1
  174. package/dist/engine/boot-validator/config-deps.js +7 -6
  175. package/dist/engine/boot-validator/detail-screens.js +4 -4
  176. package/dist/engine/boot-validator/entity-handler.d.ts +1 -0
  177. package/dist/engine/boot-validator/entity-handler.js +77 -61
  178. package/dist/engine/boot-validator/form-derivations.js +35 -1
  179. package/dist/engine/boot-validator/gdpr-storage.js +4 -4
  180. package/dist/engine/boot-validator/i18n-keys.js +6 -4
  181. package/dist/engine/boot-validator/index.d.ts +2 -2
  182. package/dist/engine/boot-validator/index.js +22 -20
  183. package/dist/engine/boot-validator/nav.js +5 -5
  184. package/dist/engine/boot-validator/ownership.js +12 -9
  185. package/dist/engine/boot-validator/parent-ref.js +1 -1
  186. package/dist/engine/boot-validator/pii-retention.js +258 -187
  187. package/dist/engine/boot-validator/projection-list-screens.js +7 -7
  188. package/dist/engine/boot-validator/query-refs.js +1 -1
  189. package/dist/engine/boot-validator/screens-actions.d.ts +1 -0
  190. package/dist/engine/boot-validator/screens-actions.js +23 -17
  191. package/dist/engine/boot-validator/screens-dashboard.js +2 -5
  192. package/dist/engine/boot-validator/screens-forms.js +12 -17
  193. package/dist/engine/boot-validator/screens-kind-config-edit.d.ts +3 -0
  194. package/dist/engine/boot-validator/screens-kind-config-edit.js +88 -0
  195. package/dist/engine/boot-validator/screens-kind-entity-edit.d.ts +3 -0
  196. package/dist/engine/boot-validator/screens-kind-entity-edit.js +55 -0
  197. package/dist/engine/boot-validator/screens-kind-entity-list.d.ts +3 -0
  198. package/dist/engine/boot-validator/screens-kind-entity-list.js +228 -0
  199. package/dist/engine/boot-validator/screens-kind-projection-detail.d.ts +3 -0
  200. package/dist/engine/boot-validator/screens-kind-projection-detail.js +235 -0
  201. package/dist/engine/boot-validator/screens-kind-projection-list.d.ts +3 -0
  202. package/dist/engine/boot-validator/screens-kind-projection-list.js +52 -0
  203. package/dist/engine/boot-validator/screens-kind-secret-mint.d.ts +3 -0
  204. package/dist/engine/boot-validator/screens-kind-secret-mint.js +28 -0
  205. package/dist/engine/boot-validator/screens-kind-shared.d.ts +37 -0
  206. package/dist/engine/boot-validator/screens-kind-shared.js +142 -0
  207. package/dist/engine/boot-validator/screens-lists.d.ts +2 -1
  208. package/dist/engine/boot-validator/screens-lists.js +26 -24
  209. package/dist/engine/boot-validator/screens.d.ts +0 -2
  210. package/dist/engine/boot-validator/screens.js +102 -869
  211. package/dist/engine/boot-validator/security-baseline.js +3 -2
  212. package/dist/engine/boot-validator/transfer-graph.js +2 -2
  213. package/dist/engine/boot-validator/workspaces.js +3 -3
  214. package/dist/engine/bridge-stub.js +3 -4
  215. package/dist/engine/build-app-schema.js +130 -170
  216. package/dist/engine/build-config-feature-schema.js +50 -50
  217. package/dist/engine/build-target.js +20 -23
  218. package/dist/engine/codemod/pipeline-codemod.js +20 -13
  219. package/dist/engine/config-helpers.js +4 -4
  220. package/dist/engine/constants.js +2 -2
  221. package/dist/engine/create-app.js +2 -2
  222. package/dist/engine/define-feature.js +21 -13
  223. package/dist/engine/define-handler.js +13 -11
  224. package/dist/engine/define-step.js +1 -1
  225. package/dist/engine/define-workflow.d.ts +5 -5
  226. package/dist/engine/define-workflow.js +6 -6
  227. package/dist/engine/entity-handlers.d.ts +13 -0
  228. package/dist/engine/entity-handlers.js +22 -34
  229. package/dist/engine/entity-list-runtime-options.d.ts +8 -0
  230. package/dist/engine/entity-list-runtime-options.js +18 -0
  231. package/dist/engine/event-def.js +2 -2
  232. package/dist/engine/extension-names.d.ts +16 -17
  233. package/dist/engine/extension-names.js +37 -38
  234. package/dist/engine/extensions/escape-hatch-usage.js +1 -1
  235. package/dist/engine/extensions/tenant-data.js +2 -2
  236. package/dist/engine/extensions/user-data.d.ts +23 -24
  237. package/dist/engine/factories.d.ts +14 -13
  238. package/dist/engine/factories.js +38 -37
  239. package/dist/engine/feature-ast/entity-field-types.js +1 -1
  240. package/dist/engine/feature-ast/extractors/handlers.js +2 -1
  241. package/dist/engine/feature-ast/extractors/hooks.js +1 -1
  242. package/dist/engine/feature-ast/extractors/round2.js +25 -6
  243. package/dist/engine/feature-ast/extractors/shared.d.ts +2 -3
  244. package/dist/engine/feature-ast/extractors/shared.js +2 -3
  245. package/dist/engine/feature-ast/parse.js +13 -13
  246. package/dist/engine/feature-ast/patch.js +4 -182
  247. package/dist/engine/feature-ast/pattern-change-schema.d.ts +3 -0
  248. package/dist/engine/feature-ast/pattern-change-schema.js +2 -1
  249. package/dist/engine/feature-ast/pattern-id-matchers.d.ts +7 -0
  250. package/dist/engine/feature-ast/pattern-id-matchers.js +210 -0
  251. package/dist/engine/feature-ast/patterns.d.ts +11 -2
  252. package/dist/engine/feature-ast/patterns.js +43 -51
  253. package/dist/engine/feature-ast/render.js +50 -89
  254. package/dist/engine/feature-config-events-jobs.js +15 -12
  255. package/dist/engine/feature-entity-handlers.js +12 -5
  256. package/dist/engine/feature-manifest.d.ts +9 -9
  257. package/dist/engine/feature-manifest.js +6 -7
  258. package/dist/engine/feature-ui-extensions.d.ts +3 -3
  259. package/dist/engine/feature-ui-extensions.js +30 -22
  260. package/dist/engine/field-access.js +5 -6
  261. package/dist/engine/form-derivations.js +18 -7
  262. package/dist/engine/handler-field-references.js +1 -1
  263. package/dist/engine/index.d.ts +1 -0
  264. package/dist/engine/index.js +4 -4
  265. package/dist/engine/object-form.d.ts +1 -0
  266. package/dist/engine/object-form.js +14 -4
  267. package/dist/engine/ownership.js +3 -3
  268. package/dist/engine/parse-ref-target.js +5 -7
  269. package/dist/engine/pattern-library/index.js +2 -2
  270. package/dist/engine/pattern-library/library.js +2 -2
  271. package/dist/engine/pattern-library/types.js +3 -3
  272. package/dist/engine/pipeline.js +2 -2
  273. package/dist/engine/project-app-schema-for-roles.d.ts +2 -0
  274. package/dist/engine/project-app-schema-for-roles.js +7 -5
  275. package/dist/engine/projection-helpers.js +9 -9
  276. package/dist/engine/qualified-name.js +2 -2
  277. package/dist/engine/registry-facade.js +1 -1
  278. package/dist/engine/registry-ingest.js +13 -13
  279. package/dist/engine/registry-state.js +17 -19
  280. package/dist/engine/registry-validate.js +12 -12
  281. package/dist/engine/run-in.js +2 -2
  282. package/dist/engine/run-pipeline.js +7 -0
  283. package/dist/engine/schema-builder.js +251 -233
  284. package/dist/engine/screen-filter-ops.js +17 -20
  285. package/dist/engine/screen-helpers.js +4 -3
  286. package/dist/engine/screen-kind.d.ts +7 -0
  287. package/dist/engine/screen-kind.js +1 -0
  288. package/dist/engine/state-machine.d.ts +12 -12
  289. package/dist/engine/state-machine.js +7 -7
  290. package/dist/engine/steps/_resolver-utils.js +4 -3
  291. package/dist/engine/steps/for-each.js +4 -4
  292. package/dist/engine/steps/unsafe-projection-delete.js +1 -1
  293. package/dist/engine/steps/unsafe-projection-upsert.js +4 -4
  294. package/dist/engine/steps/wait-for-event.js +4 -4
  295. package/dist/engine/steps/workflow-system-events.js +3 -3
  296. package/dist/engine/strip-disabled-features-from-app-schema.js +51 -14
  297. package/dist/engine/tier-resolver-extension.d.ts +29 -27
  298. package/dist/engine/tier-resolver-extension.js +26 -26
  299. package/dist/engine/transfer-adjacency.js +2 -2
  300. package/dist/engine/validate-projection-allowlist.js +9 -28
  301. package/dist/engine/walk-step-instances.d.ts +2 -0
  302. package/dist/engine/walk-step-instances.js +38 -0
  303. package/dist/engine/where-rule-lint.js +1 -1
  304. package/dist/engine/write-handler-qn-extract.js +1 -1
  305. package/dist/entrypoint/index.d.ts +4 -1
  306. package/dist/entrypoint/index.js +10 -4
  307. package/dist/env/index.d.ts +7 -6
  308. package/dist/env/index.js +10 -9
  309. package/dist/errors/docs-url.d.ts +1 -1
  310. package/dist/errors/docs-url.js +22 -2
  311. package/dist/errors/transition-details.js +7 -7
  312. package/dist/errors/write-error-info.d.ts +6 -6
  313. package/dist/errors/write-error-info.js +6 -6
  314. package/dist/es-ops/context.d.ts +9 -9
  315. package/dist/es-ops/context.js +29 -29
  316. package/dist/es-ops/index.js +7 -9
  317. package/dist/es-ops/operations-schema.js +4 -10
  318. package/dist/es-ops/runner.d.ts +11 -11
  319. package/dist/es-ops/runner.js +49 -53
  320. package/dist/es-ops/types.d.ts +55 -55
  321. package/dist/es-ops/types.js +11 -11
  322. package/dist/event-store/admin-api.js +7 -8
  323. package/dist/event-store/errors.js +1 -1
  324. package/dist/event-store/event-store.js +12 -6
  325. package/dist/event-store/rebuild-dead-letter.js +1 -1
  326. package/dist/files/bind-pending-file-refs.js +3 -3
  327. package/dist/files/create-file-ref-from-bytes.js +4 -1
  328. package/dist/files/feature.js +9 -10
  329. package/dist/files/file-handle.js +7 -9
  330. package/dist/files/file-ref-entity.js +15 -15
  331. package/dist/files/file-ref-table.js +7 -8
  332. package/dist/files/file-routes.d.ts +7 -0
  333. package/dist/files/file-routes.js +22 -13
  334. package/dist/files/in-memory-provider.js +8 -9
  335. package/dist/files/local-provider.js +18 -25
  336. package/dist/files/provider-resolver.d.ts +7 -7
  337. package/dist/files/resolve-content-type.js +43 -0
  338. package/dist/files/storage-tracking.js +2 -2
  339. package/dist/files/upload-ledger.js +7 -0
  340. package/dist/files/zip-stream.d.ts +12 -19
  341. package/dist/files/zip-stream.js +44 -63
  342. package/dist/i18n/required-surface-keys.d.ts +1 -1
  343. package/dist/i18n/required-surface-keys.js +188 -212
  344. package/dist/internal/stack-support.d.ts +2 -1
  345. package/dist/internal/stack-support.js +1 -1
  346. package/dist/jobs/job-runner-context.d.ts +32 -0
  347. package/dist/jobs/job-runner-context.js +305 -0
  348. package/dist/jobs/job-runner-execution.d.ts +7 -0
  349. package/dist/jobs/job-runner-execution.js +160 -0
  350. package/dist/jobs/job-runner-gates.d.ts +19 -0
  351. package/dist/jobs/job-runner-gates.js +198 -0
  352. package/dist/jobs/job-runner-helpers.d.ts +17 -3
  353. package/dist/jobs/job-runner-helpers.js +69 -4
  354. package/dist/jobs/job-runner-schedulers.d.ts +1 -1
  355. package/dist/jobs/job-runner-schedulers.js +3 -4
  356. package/dist/jobs/job-runner-scope.d.ts +44 -0
  357. package/dist/jobs/job-runner-scope.js +102 -0
  358. package/dist/jobs/job-runner-types.d.ts +12 -0
  359. package/dist/jobs/job-runner.d.ts +0 -1
  360. package/dist/jobs/job-runner.js +57 -669
  361. package/dist/lifecycle/lifecycle.js +3 -5
  362. package/dist/lifecycle/signal-handlers.js +5 -4
  363. package/dist/logging/utils.d.ts +2 -1
  364. package/dist/logging/utils.js +38 -10
  365. package/dist/migrations/index.js +1 -1
  366. package/dist/migrations/kumiko-drift.js +14 -13
  367. package/dist/migrations/pending-rebuilds.d.ts +21 -20
  368. package/dist/migrations/pending-rebuilds.js +27 -27
  369. package/dist/migrations/projection-table-index.d.ts +3 -3
  370. package/dist/migrations/projection-table-index.js +8 -8
  371. package/dist/observability/escape-hatch-report.d.ts +3 -0
  372. package/dist/observability/escape-hatch-report.js +12 -1
  373. package/dist/observability/metric-validator.js +1 -1
  374. package/dist/observability/metrics-handle.js +3 -3
  375. package/dist/pipeline/append-event-core.js +11 -2
  376. package/dist/pipeline/cascade-handler.d.ts +1 -1
  377. package/dist/pipeline/cascade-handler.js +165 -138
  378. package/dist/pipeline/dispatch-batch.js +2 -2
  379. package/dist/pipeline/dispatch-query.js +20 -13
  380. package/dist/pipeline/dispatch-shared.d.ts +14 -3
  381. package/dist/pipeline/dispatch-shared.js +67 -721
  382. package/dist/pipeline/dispatch-stream.js +1 -1
  383. package/dist/pipeline/dispatch-write.js +297 -190
  384. package/dist/pipeline/dispatcher-utils.d.ts +1 -1
  385. package/dist/pipeline/dispatcher-utils.js +1 -1
  386. package/dist/pipeline/event-consumer-state.js +2 -2
  387. package/dist/pipeline/event-dispatcher-admin.js +2 -1
  388. package/dist/pipeline/event-dispatcher-delivery.js +4 -6
  389. package/dist/pipeline/event-dispatcher.js +17 -28
  390. package/dist/pipeline/handler-context-auth.d.ts +9 -0
  391. package/dist/pipeline/handler-context-auth.js +54 -0
  392. package/dist/pipeline/handler-context-config.d.ts +14 -0
  393. package/dist/pipeline/handler-context-config.js +113 -0
  394. package/dist/pipeline/handler-context-db.d.ts +24 -0
  395. package/dist/pipeline/handler-context-db.js +149 -0
  396. package/dist/pipeline/handler-context-dispatch.d.ts +21 -0
  397. package/dist/pipeline/handler-context-dispatch.js +89 -0
  398. package/dist/pipeline/handler-context-events.d.ts +43 -0
  399. package/dist/pipeline/handler-context-events.js +237 -0
  400. package/dist/pipeline/handler-context-notify.d.ts +12 -0
  401. package/dist/pipeline/handler-context-notify.js +55 -0
  402. package/dist/pipeline/handler-context-observability.d.ts +7 -0
  403. package/dist/pipeline/handler-context-observability.js +21 -0
  404. package/dist/pipeline/handler-context-scope.d.ts +48 -0
  405. package/dist/pipeline/handler-context-scope.js +88 -0
  406. package/dist/pipeline/irreversible-operation-gate.js +1 -1
  407. package/dist/pipeline/lifecycle-pipeline.js +9 -9
  408. package/dist/pipeline/member-read-only-transaction.js +1 -3
  409. package/dist/pipeline/msp-rebuild.js +1 -1
  410. package/dist/pipeline/notify-scope.js +12 -1
  411. package/dist/pipeline/pre-handler-gates.js +20 -4
  412. package/dist/pipeline/pre-transaction-reservations.d.ts +1 -0
  413. package/dist/pipeline/pre-transaction-reservations.js +9 -3
  414. package/dist/pipeline/projection-rebuild.js +15 -13
  415. package/dist/pipeline/system-hooks.js +39 -41
  416. package/dist/pipeline/system-identity-switch.js +1 -3
  417. package/dist/pipeline/tenant-timezone-cache.js +1 -1
  418. package/dist/random/generate.d.ts +29 -29
  419. package/dist/random/generate.js +30 -30
  420. package/dist/random/words.js +20 -20
  421. package/dist/rate-limit/middleware.js +9 -5
  422. package/dist/redis/client.js +2 -2
  423. package/dist/redis/pubsub-signal.js +14 -17
  424. package/dist/schema-cli/apply-command.d.ts +2 -0
  425. package/dist/schema-cli/apply-command.js +97 -0
  426. package/dist/schema-cli/baseline-command.d.ts +2 -0
  427. package/dist/schema-cli/baseline-command.js +33 -0
  428. package/dist/schema-cli/generate-command.d.ts +2 -0
  429. package/dist/schema-cli/generate-command.js +90 -0
  430. package/dist/schema-cli/shared.d.ts +39 -0
  431. package/dist/schema-cli/shared.js +95 -0
  432. package/dist/schema-cli/status-command.d.ts +2 -0
  433. package/dist/schema-cli/status-command.js +73 -0
  434. package/dist/schema-cli/validate-boot-input.d.ts +5 -0
  435. package/dist/schema-cli/validate-boot-input.js +130 -0
  436. package/dist/schema-cli/validate-command.d.ts +2 -0
  437. package/dist/schema-cli/validate-command.js +130 -0
  438. package/dist/schema-cli.d.ts +2 -18
  439. package/dist/schema-cli.js +47 -510
  440. package/dist/search/index.js +4 -4
  441. package/dist/search/meilisearch-adapter.js +2 -1
  442. package/dist/search/purge-subject.js +4 -5
  443. package/dist/search/reindex-entity.js +6 -9
  444. package/dist/time/boot-tz-warning.d.ts +2 -2
  445. package/dist/time/boot-tz-warning.js +8 -8
  446. package/dist/time/iana.js +10 -10
  447. package/dist/time/index.js +9 -9
  448. package/dist/time/legacy-date.d.ts +2 -2
  449. package/dist/time/legacy-date.js +6 -8
  450. package/dist/time/polyfill.js +1 -1
  451. package/dist/time/tz-context.d.ts +1 -1
  452. package/dist/time/tz-context.js +1 -1
  453. package/dist/ui-types/app-schema.js +7 -7
  454. package/dist/ui-types/list-row-meta.js +4 -4
  455. package/dist/upgrade-cli.js +159 -130
  456. package/dist/utils/compare.js +1 -1
  457. package/package.json +5 -5
  458. package/src/changes.json +358 -0
  459. package/src/scripts/codemod/crypto-shredding-testing-move.ts +2 -2
  460. package/src/scripts/codemod/feature-layout.ts +10 -2
  461. package/src/scripts/codemod/migrate-cross-tenant.ts +1 -1
  462. package/src/scripts/codemod/migrate-open-to-all.ts +1 -1
  463. package/src/scripts/codemod/object-form.ts +41 -4
  464. package/src/scripts/codemod/package-merge.ts +58 -8
  465. package/src/scripts/codemod/pii-personal-migration.ts +192 -153
  466. package/src/scripts/codemod/testing-injection.ts +122 -42
  467. package/src/scripts/codemod/testing-move.ts +29 -7
  468. package/src/scripts/codemod/unprocessable-error-details-reason.ts +2 -2
@@ -1,3 +1,4 @@
1
+ export { isTimestamptzType } from "./aggregate-sql.ts";
1
2
  export { applyEntityEvent } from "./apply-entity-event.ts";
2
3
  export { assertExistsIn } from "./assert-exists-in.ts";
3
4
  export { nullBlindIndexesForSubject, recordEventsOwnedExclusivelyByTenant, recordRowExistsInTenant, recordRowOwningTenantId, subjectRowExistsInTenant, } from "./blind-index-cleanup.ts";
@@ -10,6 +11,7 @@ export type { CursorQueryOptions, CursorResult, DecodedKeysetCursor } from "./cu
10
11
  export { decodeCursor, decodeKeysetCursor, encodeCursor, encodeKeysetCursor } from "./cursor.ts";
11
12
  export type { SchemaTable, SelectQuery, TableColumns } from "./dialect.ts";
12
13
  export { bigint, bigserial, boolean, extractTableName, index, instant, instantToDriver, integer, jsonb, moneyAmount, numeric, primaryKey, serial, sql, table, text, timestamp, uniqueIndex, uuid, } from "./dialect.ts";
14
+ export { instantToTimestamptzParam } from "./driver-value-preparation.ts";
13
15
  export type { EagerLoadEntityResolver, EagerLoadViewer, EagerloadedRow } from "./eagerload.ts";
14
16
  export { collectReferenceFields, enrichRowWithReferences, enrichWithReferences, } from "./eagerload.ts";
15
17
  export { collectEncryptedFieldNames, configuredEntityFieldEncryption, configureEntityFieldEncryption, decryptEntityFieldValues, encryptEntityFieldValues, } from "./entity-field-encryption.ts";
@@ -19,6 +21,7 @@ export { defineUnmanagedTable, deriveEntityTableMeta, } from "./entity-table-met
19
21
  export type { EntityLifecycleVerb, EventStoreExecutor, EventStoreExecutorOptions, LockGuardOption, WritePurpose, } from "./event-store-executor.ts";
20
22
  export { createEventStoreExecutor, entityEventName, WritePurposes, } from "./event-store-executor.ts";
21
23
  export { enumerateFeatureTableSources, type FeatureTableSource, } from "./feature-table-sources.ts";
24
+ export { answerListAggregate, labelListAggregateGroups } from "./list-aggregate-labels.ts";
22
25
  export { flattenLocatedTimestamp, type LocatedTimestampRead, rehydrateLocatedTimestamp, } from "./located-timestamp.ts";
23
26
  export { assertUniqueTableNames, assertValidMigrationName, diffSnapshots, type GenerateMigrationInput, type GenerateMigrationOutput, generateMigration, loadSnapshotJson, renderMigrationSql, type SchemaDiff, type Snapshot, snapshotFromMetas, writeSnapshotJson, } from "./migrate-generator.ts";
24
27
  export { type AppliedMigration, type ApplyResult, type BaselineResult, baselineMigrations, fetchAppliedMigrations, loadMigrationsFromDir, type Migration, MigrationChecksumMismatchError, readMigrationSqlTexts, runMigrations, runMigrationsFromDir, splitSqlStatements, } from "./migrate-runner.ts";
@@ -28,8 +31,8 @@ export { acquireNamespacedAdvisoryLock } from "./queries/advisory-lock.ts";
28
31
  export { readDatabaseNow } from "./queries/database-now.ts";
29
32
  export { toPostgresArrayLiteral } from "./queries/postgres-array-literal.ts";
30
33
  export { executeRawQuery, executeRawQueryRead } from "./queries/raw-sql.ts";
31
- export type { DeleteManyBatchedOptions, DeleteManyBatchedResult, IncrementCounterOptions, InnerJoinRow, InnerJoinSpec, InsertOnConflictDoNothingOptions, JoinColumnPair, JsonTextMatch, SelectOptions, TableInfo, UpsertOnConflictOptions, WhereObject, WhereOperator, WhereValue, } from "./query.ts";
32
- export { aggregateWhere, asEntityTableMeta, asRawClient, countWhere, deleteMany, deleteManyBatched, extractTableInfo, fetchOne, incrementCounter, insertMany, insertOnConflictDoNothing, insertOne, instantToTimestamptzParam, isTimestamptzType, requireEntityTableMeta, runInSavepoint, runInSavepointIfSupported, runnerCanBeginTransaction, selectInnerJoin, selectMany, transaction, unsafeReadRetrying, updateMany, upsertByPk, upsertOnConflict, } from "./query.ts";
34
+ export type { DeleteManyBatchedOptions, DeleteManyBatchedResult, IncrementCounterOptions, InnerJoinRow, InnerJoinSpec, InsertOnConflictDoNothingOptions, JoinColumnPair, JsonTextMatch, SelectOptions, UpsertOnConflictOptions, WhereObject, WhereOperator, WhereValue, } from "./query.ts";
35
+ export { aggregateWhere, asEntityTableMeta, asRawClient, countWhere, deleteMany, deleteManyBatched, fetchOne, incrementCounter, insertMany, insertOnConflictDoNothing, insertOne, requireEntityTableMeta, runInSavepoint, runInSavepointIfSupported, runnerCanBeginTransaction, selectInnerJoin, selectMany, transaction, unsafeReadRetrying, updateMany, upsertByPk, upsertOnConflict, } from "./query.ts";
33
36
  export { readRebuildMarker, rebuildTablesFromDiff, writeRebuildMarker, } from "./rebuild-marker.ts";
34
37
  export { seedReferenceData } from "./reference-data.ts";
35
38
  export { renderTableDdl, renderTablesDdl } from "./render-ddl.ts";
@@ -38,5 +41,6 @@ export { findCommentedDropTables, isRetiredFrameworkTable, type RetiredFramework
38
41
  export { tableExists } from "./schema-inspection.ts";
39
42
  export { withoutStatementTimeout } from "./statement-timeout.ts";
40
43
  export { buildBaseColumns, buildEntityTable, declareGlobalTenancy, type EntityRow, type EntityTable, type ExecutorManagedRunner, type ExecutorManagedWriteCapability, physicalColumnName, toSnakeCase, toTableName, type Writable, type WritableSchemaTable, type WritableTable, } from "./table-builder.ts";
44
+ export { extractTableInfo, type TableInfo } from "./table-info.ts";
41
45
  export type { CreateTenantDbOptions, ExecutorManagedTenantDb, OutsideTransactionContext, TenantDb, TenantDbGrants, TenantDbMode, UncheckedSystemDb, } from "./tenant-db.ts";
42
46
  export { castTenantRows, createSystemDbView, createTenantDataDestroyDb, createTenantDb, hasOutsideTransactionDb, requireOutsideTransactionDb, runInOwnTransaction, SYSTEM_SCOPE_CHECK_BRAND, scopeTenantDbToTenant, } from "./tenant-db.ts";
package/dist/db/index.js CHANGED
@@ -1,3 +1,4 @@
1
+ export { isTimestamptzType } from "./aggregate-sql.js";
1
2
  export { applyEntityEvent } from "./apply-entity-event.js";
2
3
  export { assertExistsIn } from "./assert-exists-in.js";
3
4
  export { nullBlindIndexesForSubject, recordEventsOwnedExclusivelyByTenant, recordRowExistsInTenant, recordRowOwningTenantId, subjectRowExistsInTenant, } from "./blind-index-cleanup.js";
@@ -7,12 +8,14 @@ export { seedConfigValues } from "./config-seed.js";
7
8
  export { createDbConnection, DEFAULT_OUTSIDE_TRANSACTION_POOL_MAX, dbConnectionOptionsFromEnv, outsideTransactionPoolOptionsFromEnv, serverTimeoutOptionsFromEnv, } from "./connection.js";
8
9
  export { decodeCursor, decodeKeysetCursor, encodeCursor, encodeKeysetCursor } from "./cursor.js";
9
10
  export { bigint, bigserial, boolean, extractTableName, index, instant, instantToDriver, integer, jsonb, moneyAmount, numeric, primaryKey, serial, sql, table, text, timestamp, uniqueIndex, uuid, } from "./dialect.js";
11
+ export { instantToTimestamptzParam } from "./driver-value-preparation.js";
10
12
  export { collectReferenceFields, enrichRowWithReferences, enrichWithReferences, } from "./eagerload.js";
11
13
  export { collectEncryptedFieldNames, configuredEntityFieldEncryption, configureEntityFieldEncryption, decryptEntityFieldValues, encryptEntityFieldValues, } from "./entity-field-encryption.js";
12
14
  export { entityTableFromRegistry } from "./entity-table-from-registry.js";
13
15
  export { defineUnmanagedTable, deriveEntityTableMeta, } from "./entity-table-meta.js";
14
16
  export { createEventStoreExecutor, entityEventName, WritePurposes, } from "./event-store-executor.js";
15
17
  export { enumerateFeatureTableSources, } from "./feature-table-sources.js";
18
+ export { answerListAggregate, labelListAggregateGroups } from "./list-aggregate-labels.js";
16
19
  export { flattenLocatedTimestamp, rehydrateLocatedTimestamp, } from "./located-timestamp.js";
17
20
  export { assertUniqueTableNames, assertValidMigrationName, diffSnapshots, generateMigration, loadSnapshotJson, renderMigrationSql, snapshotFromMetas, writeSnapshotJson, } from "./migrate-generator.js";
18
21
  export { baselineMigrations, fetchAppliedMigrations, loadMigrationsFromDir, MigrationChecksumMismatchError, readMigrationSqlTexts, runMigrations, runMigrationsFromDir, splitSqlStatements, } from "./migrate-runner.js";
@@ -22,7 +25,7 @@ export { acquireNamespacedAdvisoryLock } from "./queries/advisory-lock.js";
22
25
  export { readDatabaseNow } from "./queries/database-now.js";
23
26
  export { toPostgresArrayLiteral } from "./queries/postgres-array-literal.js";
24
27
  export { executeRawQuery, executeRawQueryRead } from "./queries/raw-sql.js";
25
- export { aggregateWhere, asEntityTableMeta, asRawClient, countWhere, deleteMany, deleteManyBatched, extractTableInfo, fetchOne, incrementCounter, insertMany, insertOnConflictDoNothing, insertOne, instantToTimestamptzParam, isTimestamptzType, requireEntityTableMeta, runInSavepoint, runInSavepointIfSupported, runnerCanBeginTransaction, selectInnerJoin, selectMany, transaction, unsafeReadRetrying, updateMany, upsertByPk, upsertOnConflict, } from "./query.js";
28
+ export { aggregateWhere, asEntityTableMeta, asRawClient, countWhere, deleteMany, deleteManyBatched, fetchOne, incrementCounter, insertMany, insertOnConflictDoNothing, insertOne, requireEntityTableMeta, runInSavepoint, runInSavepointIfSupported, runnerCanBeginTransaction, selectInnerJoin, selectMany, transaction, unsafeReadRetrying, updateMany, upsertByPk, upsertOnConflict, } from "./query.js";
26
29
  export { readRebuildMarker, rebuildTablesFromDiff, writeRebuildMarker, } from "./rebuild-marker.js";
27
30
  export { seedReferenceData } from "./reference-data.js";
28
31
  export { renderTableDdl, renderTablesDdl } from "./render-ddl.js";
@@ -31,4 +34,5 @@ export { findCommentedDropTables, isRetiredFrameworkTable, retiredFrameworkTable
31
34
  export { tableExists } from "./schema-inspection.js";
32
35
  export { withoutStatementTimeout } from "./statement-timeout.js";
33
36
  export { buildBaseColumns, buildEntityTable, declareGlobalTenancy, physicalColumnName, toSnakeCase, toTableName, } from "./table-builder.js";
37
+ export { extractTableInfo } from "./table-info.js";
34
38
  export { castTenantRows, createSystemDbView, createTenantDataDestroyDb, createTenantDb, hasOutsideTransactionDb, requireOutsideTransactionDb, runInOwnTransaction, SYSTEM_SCOPE_CHECK_BRAND, scopeTenantDbToTenant, } from "./tenant-db.js";
@@ -0,0 +1,14 @@
1
+ import type { ListAggregateResult } from "@cosmicdrift/kumiko-types/list-aggregate-types";
2
+ import type { EntityDefinition } from "../engine/types/index.ts";
3
+ import type { EagerLoadEntityResolver, EagerLoadViewer } from "./eagerload.ts";
4
+ import type { EventStoreExecutor } from "./event-store-executor.ts";
5
+ import type { TenantDb } from "./tenant-db.ts";
6
+ type LabelDeps = {
7
+ readonly entity: EntityDefinition;
8
+ readonly resolveEntity: EagerLoadEntityResolver;
9
+ readonly viewer: EagerLoadViewer;
10
+ };
11
+ export declare function labelListAggregateGroups(result: ListAggregateResult, groupByField: string | undefined, deps: LabelDeps, db: TenantDb): Promise<ListAggregateResult>;
12
+ type AggregateRequest = Parameters<EventStoreExecutor["aggregate"]>[0];
13
+ export declare function answerListAggregate(executor: Pick<EventStoreExecutor, "aggregate">, request: AggregateRequest, user: Parameters<EventStoreExecutor["aggregate"]>[1], db: TenantDb, runtimeOptions: Parameters<EventStoreExecutor["aggregate"]>[3], labelDeps: LabelDeps): Promise<ListAggregateResult>;
14
+ export {};
@@ -0,0 +1,26 @@
1
+ import { enrichWithReferences } from "./eagerload.js";
2
+ function labelOf(ref, labelField) {
3
+ if (typeof ref !== "object" || ref === null || Array.isArray(ref))
4
+ return null;
5
+ const value = Reflect.get(ref, labelField);
6
+ return typeof value === "string" ? value : null;
7
+ }
8
+ // Labels come from the same eager-load path as list rows, so they carry its
9
+ // ownership and field-read gating instead of a second label query.
10
+ export async function labelListAggregateGroups(result, groupByField, deps, db) {
11
+ if (groupByField === undefined || result.groups.length === 0)
12
+ return result;
13
+ const def = deps.entity.fields[groupByField];
14
+ if (def?.type !== "reference" || def.multiple === true)
15
+ return result;
16
+ const enriched = await enrichWithReferences(result.groups.map((g) => ({ [groupByField]: g.key })), deps.entity, deps.resolveEntity, db, deps.viewer);
17
+ const groups = result.groups.map((group, i) => {
18
+ const ref = Reflect.get(enriched[i]?.["_refs"] ?? {}, groupByField);
19
+ return { ...group, label: labelOf(ref, def.labelField ?? "id") };
20
+ });
21
+ return { ...result, groups };
22
+ }
23
+ export async function answerListAggregate(executor, request, user, db, runtimeOptions, labelDeps) {
24
+ const result = await executor.aggregate(request, user, db, runtimeOptions);
25
+ return labelListAggregateGroups(result, request.aggregate.groupBy, labelDeps, db);
26
+ }
@@ -1,13 +1,13 @@
1
1
  import type { EntityDefinition } from "../engine/types/index.ts";
2
2
  /**
3
- * API → DB: locatedTimestamp-Felder zu zwei flachen Spalten flatten.
3
+ * API → DB: flatten locatedTimestamp fields into two flat columns.
4
4
  *
5
- * - `{ at, tz }` (UI-Form) → `{ <name>Utc, <name>Tz }` (utc via Temporal berechnet)
6
- * - `{ utc, tz }` (Server-Form) → utc gewinnt direkt
7
- * - `{ at, tz, utc }` → utc gewinnt; at wird ignoriert (Konsistenz-Check ist
8
- * Caller-Verantwortung)
5
+ * - `{ at, tz }` (UI form) → `{ <name>Utc, <name>Tz }` (`utc` calculated via Temporal)
6
+ * - `{ utc, tz }` (server form) → `utc` takes precedence
7
+ * - `{ at, tz, utc }` → `utc` takes precedence; `at` is ignored (the caller is
8
+ * responsible for the consistency check)
9
9
  *
10
- * Pure — mutiert nicht.
10
+ * Pure — does not mutate.
11
11
  */
12
12
  export declare function flattenLocatedTimestamp(payload: Record<string, unknown>, entity: EntityDefinition): Record<string, unknown>;
13
13
  /** Shape of a single rehydrated locatedTimestamp field. `at` is the wall clock in `tz`
@@ -18,12 +18,12 @@ export type LocatedTimestampRead = {
18
18
  readonly utc: string;
19
19
  };
20
20
  /**
21
- * DB → API: zwei flache Spalten zu combined { at, tz, utc } rehydraten.
21
+ * DB → API: rehydrate two flat columns into combined { at, tz, utc }.
22
22
  *
23
- * `at` ist immer Wall-Clock in der gespeicherten `tz` (Pickup-Ort-lokal).
24
- * Wer User-Sicht braucht, leitet aus `utc` selbst ab — der Server kennt
25
- * keine User-TZ.
23
+ * `at` is always the wall-clock time in the stored `tz` (local to the pickup
24
+ * location). To obtain a user-specific view, derive it from `utc` yourself —
25
+ * the server does not know the user's time zone.
26
26
  *
27
- * Pure — mutiert nicht.
27
+ * Pure — does not mutate.
28
28
  */
29
29
  export declare function rehydrateLocatedTimestamp(row: Record<string, unknown>, entity: EntityDefinition): Record<string, unknown>;
@@ -1,23 +1,22 @@
1
- // Auto-Convert für locatedTimestamp-Felder im DB-Layer.
1
+ // Automatically converts locatedTimestamp fields in the DB layer.
2
2
  //
3
- // Vertrag (siehe auch db/money.ts — gleicher Compound-Type-Pattern):
4
- // API-Form: { at, tz } | { utc, tz }
5
- // DB-Form: <name>Utc TIMESTAMPTZ + <name>Tz TEXT
6
- // Read-Form: { at, tz, utc }
3
+ // Contract (see also db/money.ts — the same compound-type pattern):
4
+ // API form: { at, tz } | { utc, tz }
5
+ // DB form: <name>Utc TIMESTAMPTZ + <name>Tz TEXT
6
+ // Read form: { at, tz, utc }
7
7
  //
8
- // `at`-Default-Sicht beim Read: Pickup-Ort-lokal (utc projiziert in
9
- // gespeicherter tz). Server kennt User-TZ nicht — User-spezifische
10
- // Anzeige passiert client-seitig aus utc.
8
+ // Default `at` view on read: local to the pickup location (`utc` projected into
9
+ // the stored `tz`). The server does not know the user's time zone, so
10
+ // user-specific display is derived from `utc` on the client.
11
11
  // Static import, not the ambient global: Bun doesn't expose Temporal on
12
12
  // globalThis, so this crashed with "Temporal is not defined" outside boot
13
- // paths that install it (#1480).
13
+ // paths that install it.
14
14
  import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
15
- // Sprint F: <name>Utc-Spalte ist jetzt instant() (siehe dialect.ts) —
16
- // Drizzle gibt direkt Temporal.Instant zurück. Vor Sprint F kam ein PG-
17
- // Wire-Format-String "2026-04-15 09:00:00+00" rein der via String-Massage
18
- // zu ISO-8601 gemacht werden musste. Heute übernimmt der customType die
19
- // Konversion DB↔Instant — diese Funktion ist nur noch defensive Glue für
20
- // Legacy-Code-Pfade die noch Strings durchreichen (z.B. raw SQL).
15
+ // The <name>Utc column uses instant() (see dialect.ts), so Drizzle returns Temporal.Instant.
16
+ // Previously, a PostgreSQL wire-format string "2026-04-15 09:00:00+00" had to be
17
+ // converted to ISO 8601 through string manipulation. The customType now handles
18
+ // DB↔Instant conversion, so this function is only defensive glue for legacy code
19
+ // paths that still pass strings (for example, raw SQL).
21
20
  function toInstant(value) {
22
21
  if (value instanceof Temporal.Instant)
23
22
  return value;
@@ -27,14 +26,14 @@ function toInstant(value) {
27
26
  return Temporal.Instant.from(iso);
28
27
  }
29
28
  /**
30
- * API → DB: locatedTimestamp-Felder zu zwei flachen Spalten flatten.
29
+ * API → DB: flatten locatedTimestamp fields into two flat columns.
31
30
  *
32
- * - `{ at, tz }` (UI-Form) → `{ <name>Utc, <name>Tz }` (utc via Temporal berechnet)
33
- * - `{ utc, tz }` (Server-Form) → utc gewinnt direkt
34
- * - `{ at, tz, utc }` → utc gewinnt; at wird ignoriert (Konsistenz-Check ist
35
- * Caller-Verantwortung)
31
+ * - `{ at, tz }` (UI form) → `{ <name>Utc, <name>Tz }` (`utc` calculated via Temporal)
32
+ * - `{ utc, tz }` (server form) → `utc` takes precedence
33
+ * - `{ at, tz, utc }` → `utc` takes precedence; `at` is ignored (the caller is
34
+ * responsible for the consistency check)
36
35
  *
37
- * Pure — mutiert nicht.
36
+ * Pure — does not mutate.
38
37
  */
39
38
  export function flattenLocatedTimestamp(payload, entity) {
40
39
  const T = Temporal;
@@ -53,10 +52,10 @@ export function flattenLocatedTimestamp(payload, entity) {
53
52
  if (pair.tz === undefined)
54
53
  continue;
55
54
  const tz = pair.tz;
56
- // Sprint F: <name>Utc-Spalte ist instant() — Drizzle erwartet
57
- // Temporal.Instant. Konvertierung pair.utc-string → Instant geht via
58
- // toInstant() (kennt String + Instant); pair.at + tz → Instant via
59
- // Temporal-Math.
55
+ // The <name>Utc column uses instant(); Drizzle expects
56
+ // Temporal.Instant. Conversion from pair.utc string → Instant goes through
57
+ // toInstant() (which handles strings and Instant values); pair.at + tz →
58
+ // Instant uses Temporal math.
60
59
  const instant = pair.utc !== undefined
61
60
  ? toInstant(pair.utc)
62
61
  : pair.at !== undefined
@@ -70,13 +69,13 @@ export function flattenLocatedTimestamp(payload, entity) {
70
69
  return result;
71
70
  }
72
71
  /**
73
- * DB → API: zwei flache Spalten zu combined { at, tz, utc } rehydraten.
72
+ * DB → API: rehydrate two flat columns into combined { at, tz, utc }.
74
73
  *
75
- * `at` ist immer Wall-Clock in der gespeicherten `tz` (Pickup-Ort-lokal).
76
- * Wer User-Sicht braucht, leitet aus `utc` selbst ab — der Server kennt
77
- * keine User-TZ.
74
+ * `at` is always the wall-clock time in the stored `tz` (local to the pickup
75
+ * location). To obtain a user-specific view, derive it from `utc` yourself —
76
+ * the server does not know the user's time zone.
78
77
  *
79
- * Pure — mutiert nicht.
78
+ * Pure — does not mutate.
80
79
  */
81
80
  export function rehydrateLocatedTimestamp(row, entity) {
82
81
  const result = { ...row };
@@ -3,7 +3,7 @@ import { type RetiredFrameworkTable } from "./retired-framework-tables.ts";
3
3
  declare const SNAPSHOT_VERSION: 1;
4
4
  export type Snapshot = {
5
5
  readonly version: typeof SNAPSHOT_VERSION;
6
- readonly generatedAt: string;
6
+ readonly generatedAt?: string;
7
7
  readonly tables: readonly EntityTableMeta[];
8
8
  };
9
9
  export type ColumnChange = {
@@ -1,31 +1,36 @@
1
- // Build-time Generator: EntityTableMeta[] → reviewbares SQL-Migration-File.
2
- // Ersatz für `drizzle-kit generate`.
1
+ // Build-time generator: EntityTableMeta[] → reviewable SQL migration file.
2
+ // Replacement for `drizzle-kit generate`.
3
3
  //
4
- // **NO-MAGIC-ON-DATA Kernprinzip** (siehe drizzle-replacement.md):
5
- // - Generator emittiert SQL-Files für PR-Review/Edit
6
- // - Generator wird NIE zur App-Runtime aufgerufen
7
- // - Output ist Start-Form; App-Author darf das SQL hand-editieren
8
- // (BRIN-Index, partial-Index, performance-tuning) bevor committed
9
- // - Append-only: bestehende Migration-Files werden NIE überschrieben.
10
- // Neue Schema-Diffs landen in einem NEUEN File mit incrementierter
11
- // Sequence-Number.
4
+ // **NO-MAGIC-ON-DATA core principle** (see drizzle-replacement.md):
5
+ // - The generator emits SQL files for PR review/editing.
6
+ // - The generator is NEVER called at app runtime.
7
+ // - The output is a starting point; app authors may hand-edit the SQL
8
+ // (BRIN index, partial index, performance tuning) before committing.
9
+ // - Append-only: existing migration files are NEVER overwritten.
10
+ // New schema diffs go into a NEW file with an incremented sequence number.
12
11
  //
13
- // **DESTRUCTIVE-ops** (DROP TABLE/COLUMN, INDEX-removal) werden als
14
- // AUSKOMMENTIERTE statements emittiert — Reviewer muss explizit
15
- // uncommenten + ggf. Data-Backup-Schritt vorlauf einfügen. Default:
16
- // niemals automatisch droppen.
12
+ // **DESTRUCTIVE operations** (DROP TABLE/COLUMN, index removal) are emitted
13
+ // as commented-out statements — reviewers must explicitly uncomment them
14
+ // and may need to add a data-backup step beforehand. Default:
15
+ // never drop automatically.
17
16
  import { readFileSync, writeFileSync } from "node:fs";
18
17
  import { errorCodeOf, isPlainObject } from "@cosmicdrift/kumiko-types/type-guards";
19
18
  import { compareByCodepoint } from "../utils/index.js";
20
19
  import { renderIndex, renderTableDdl } from "./render-ddl.js";
21
20
  import { findRetiredTableDrops } from "./retired-framework-tables.js";
22
21
  const SNAPSHOT_VERSION = 1;
22
+ function isSnapshot(value) {
23
+ return (isPlainObject(value) &&
24
+ value["version"] === SNAPSHOT_VERSION &&
25
+ (value["generatedAt"] === undefined || typeof value["generatedAt"] === "string") &&
26
+ Array.isArray(value["tables"]));
27
+ }
23
28
  export function snapshotFromMetas(metas) {
24
29
  // Stable ordering by tableName so the snapshot.json diff in PRs is
25
30
  // meaningful (table-add isn't a noisy re-sort of everything). Codepoint, not
26
31
  // localeCompare: the snapshot is serialized to byte-exact JSON and the table
27
32
  // order carries into the generated migration SQL — locale-dependent ordering
28
- // would drift between macOS-dev and Linux-CI (#367).
33
+ // would drift between macOS-dev and Linux-CI.
29
34
  const sorted = [...metas].sort((a, b) => compareByCodepoint(a.tableName, b.tableName));
30
35
  return {
31
36
  version: SNAPSHOT_VERSION,
@@ -41,6 +46,9 @@ export function loadSnapshotJson(path) {
41
46
  if (version !== SNAPSHOT_VERSION) {
42
47
  throw new Error(`Snapshot at ${path} has version ${String(version)}, expected ${SNAPSHOT_VERSION}`);
43
48
  }
49
+ if (!isSnapshot(parsed)) {
50
+ throw new Error(`Snapshot at ${path} is malformed: expected a tables list`);
51
+ }
44
52
  return parsed;
45
53
  }
46
54
  catch (err) {
@@ -53,7 +61,7 @@ export function writeSnapshotJson(path, snapshot) {
53
61
  writeFileSync(path, `${JSON.stringify(snapshot, null, 2)}\n`);
54
62
  }
55
63
  function indexMetaKey(idx) {
56
- // Index-Identität via Name (PG-Constraint: unique innerhalb der DB)
64
+ // Index identity is based on its name (PostgreSQL constraint: unique within the database).
57
65
  return idx.name;
58
66
  }
59
67
  function indexColumnsEqual(a, b) {
@@ -71,100 +79,85 @@ function indexesByName(meta) {
71
79
  m.set(indexMetaKey(i), i);
72
80
  return m;
73
81
  }
74
- function diffOneTable(prev, next) {
75
- const prevCols = columnsByName(prev);
76
- const nextCols = columnsByName(next);
77
- const newColumns = [];
78
- const droppedColumns = [];
79
- const changedColumns = [];
80
- for (const [name, nextCol] of nextCols) {
81
- const prevCol = prevCols.get(name);
82
- if (!prevCol) {
83
- newColumns.push(nextCol);
84
- continue;
85
- }
86
- const change = { name };
87
- if (prevCol.notNull !== nextCol.notNull) {
88
- Object.assign(change, {
89
- nullabilityChanged: { from: prevCol.notNull, to: nextCol.notNull },
90
- });
91
- }
92
- if (prevCol.defaultSql !== nextCol.defaultSql) {
93
- Object.assign(change, {
94
- defaultChanged: { from: prevCol.defaultSql, to: nextCol.defaultSql },
95
- });
96
- }
97
- if (prevCol.pgType !== nextCol.pgType) {
98
- Object.assign(change, {
99
- typeChanged: { from: prevCol.pgType, to: nextCol.pgType },
100
- });
101
- }
102
- if (change.nullabilityChanged || change.defaultChanged || change.typeChanged) {
103
- changedColumns.push(change);
104
- }
105
- }
106
- for (const name of prevCols.keys()) {
107
- if (!nextCols.has(name))
108
- droppedColumns.push(name);
109
- }
110
- const prevIdx = indexesByName(prev);
111
- const nextIdx = indexesByName(next);
112
- const newIndexes = [];
113
- const droppedIndexes = [];
114
- const changedIndexes = [];
115
- for (const [name, idx] of nextIdx) {
116
- const prevI = prevIdx.get(name);
117
- if (!prevI) {
118
- newIndexes.push(idx);
82
+ function strictEqual(a, b) {
83
+ return a === b;
84
+ }
85
+ function fromToWhenDifferent(from, to, isEqual = strictEqual) {
86
+ return isEqual(from, to) ? undefined : { from, to };
87
+ }
88
+ // added and changed follow next's order, dropped follows prev's order; the
89
+ // rendered migration depends on both.
90
+ function diffByName(prev, next, compare) {
91
+ const added = [];
92
+ const changed = [];
93
+ for (const [name, nextItem] of next) {
94
+ const prevItem = prev.get(name);
95
+ if (prevItem === undefined) {
96
+ added.push(nextItem);
119
97
  continue;
120
98
  }
121
- const columnsChanged = indexColumnsEqual(prevI.columns, idx.columns)
122
- ? undefined
123
- : { from: prevI.columns, to: idx.columns };
124
- const uniqueChanged = (prevI.unique ?? false) === (idx.unique ?? false)
125
- ? undefined
126
- : { from: prevI.unique ?? false, to: idx.unique ?? false };
127
- // Whitespace-only re-rendering of the predicate must not drop and rebuild a large index.
128
- const whereSqlChanged = whereSqlEqual(prevI.whereSql, idx.whereSql)
129
- ? undefined
130
- : { from: prevI.whereSql, to: idx.whereSql };
131
- const needsManualWhereChanged = (prevI.needsManualWhere ?? false) === (idx.needsManualWhere ?? false)
132
- ? undefined
133
- : { from: prevI.needsManualWhere ?? false, to: idx.needsManualWhere ?? false };
134
- if (columnsChanged || uniqueChanged || whereSqlChanged || needsManualWhereChanged) {
135
- // Single literal typed as IndexChange so a misspelled key fails to compile instead of silently dropping the change.
136
- const change = {
137
- name,
138
- ...(columnsChanged && { columnsChanged }),
139
- ...(uniqueChanged && { uniqueChanged }),
140
- ...(whereSqlChanged && { whereSqlChanged }),
141
- ...(needsManualWhereChanged && { needsManualWhereChanged }),
142
- };
143
- changedIndexes.push(change);
144
- }
99
+ const change = compare(name, prevItem, nextItem);
100
+ if (change !== undefined)
101
+ changed.push(change);
145
102
  }
146
- for (const name of prevIdx.keys()) {
147
- if (!nextIdx.has(name))
148
- droppedIndexes.push(name);
103
+ const dropped = [...prev.keys()].filter((name) => !next.has(name));
104
+ return { added, dropped, changed };
105
+ }
106
+ function compareColumns(name, prevCol, nextCol) {
107
+ const nullabilityChanged = fromToWhenDifferent(prevCol.notNull, nextCol.notNull);
108
+ const defaultChanged = fromToWhenDifferent(prevCol.defaultSql, nextCol.defaultSql);
109
+ const typeChanged = fromToWhenDifferent(prevCol.pgType, nextCol.pgType);
110
+ if (!nullabilityChanged && !defaultChanged && !typeChanged)
111
+ return undefined;
112
+ return {
113
+ name,
114
+ ...(nullabilityChanged && { nullabilityChanged }),
115
+ ...(defaultChanged && { defaultChanged }),
116
+ ...(typeChanged && { typeChanged }),
117
+ };
118
+ }
119
+ function compareIndexes(name, prevIndex, nextIndex) {
120
+ const columnsChanged = fromToWhenDifferent(prevIndex.columns, nextIndex.columns, indexColumnsEqual);
121
+ const uniqueChanged = fromToWhenDifferent(prevIndex.unique ?? false, nextIndex.unique ?? false);
122
+ // Whitespace-only re-rendering of the predicate must not drop and rebuild a large index.
123
+ const whereSqlChanged = fromToWhenDifferent(prevIndex.whereSql, nextIndex.whereSql, whereSqlEqual);
124
+ const needsManualWhereChanged = fromToWhenDifferent(prevIndex.needsManualWhere ?? false, nextIndex.needsManualWhere ?? false);
125
+ if (!columnsChanged && !uniqueChanged && !whereSqlChanged && !needsManualWhereChanged) {
126
+ return undefined;
149
127
  }
150
- const isEmpty = newColumns.length === 0 &&
151
- droppedColumns.length === 0 &&
152
- changedColumns.length === 0 &&
153
- newIndexes.length === 0 &&
154
- droppedIndexes.length === 0 &&
155
- changedIndexes.length === 0;
156
- if (isEmpty)
157
- return null;
128
+ // Single literal typed as IndexChange so a misspelled key fails to compile instead of silently dropping the change.
158
129
  return {
130
+ name,
131
+ ...(columnsChanged && { columnsChanged }),
132
+ ...(uniqueChanged && { uniqueChanged }),
133
+ ...(whereSqlChanged && { whereSqlChanged }),
134
+ ...(needsManualWhereChanged && { needsManualWhereChanged }),
135
+ };
136
+ }
137
+ function hasNoTableChanges(diff) {
138
+ return [
139
+ diff.newColumns,
140
+ diff.droppedColumns,
141
+ diff.changedColumns,
142
+ diff.newIndexes,
143
+ diff.droppedIndexes,
144
+ diff.changedIndexes,
145
+ ].every((list) => list.length === 0);
146
+ }
147
+ function diffOneTable(prev, next) {
148
+ const columns = diffByName(columnsByName(prev), columnsByName(next), compareColumns);
149
+ const indexes = diffByName(indexesByName(prev), indexesByName(next), compareIndexes);
150
+ const diff = {
159
151
  tableName: prev.tableName,
160
- newColumns,
161
- droppedColumns,
162
- changedColumns,
163
- newIndexes,
164
- droppedIndexes,
165
- changedIndexes,
152
+ newColumns: columns.added,
153
+ droppedColumns: columns.dropped,
154
+ changedColumns: columns.changed,
155
+ newIndexes: indexes.added,
156
+ droppedIndexes: indexes.dropped,
157
+ changedIndexes: indexes.changed,
166
158
  nextMeta: next,
167
159
  };
160
+ return hasNoTableChanges(diff) ? null : diff;
168
161
  }
169
162
  export function diffSnapshots(prev, next) {
170
163
  const prevByName = new Map();
@@ -273,8 +266,7 @@ function renderColumnChange(tableName, change) {
273
266
  // timestamptz → date: PG's implicit ::date cast (what a bare ALTER ...
274
267
  // TYPE without USING falls back to) reads the session TimeZone, so the
275
268
  // same row migrates to a different calendar day depending on who/where
276
- // runs it — exactly the non-determinism kumiko-framework#1924 fixes.
277
- // Anchor explicitly at UTC instead of trusting the session.
269
+ // runs it. Anchor explicitly at UTC instead of trusting the session.
278
270
  if ((from === "timestamptz" || from === "timestamptz(3)") && to === "date") {
279
271
  out.push(`-- ${from} → date: explicit UTC anchor — a bare cast would use the session TimeZone (non-deterministic).`);
280
272
  out.push(`ALTER TABLE ${tbl} ALTER COLUMN ${col} TYPE date USING (${col} AT TIME ZONE 'UTC')::date;`);
@@ -383,7 +375,7 @@ export function renderMigrationSql(diff, options) {
383
375
  // needsManualWhere renders CREATE as a commented WARN (renderIndex),
384
376
  // since the generator can't express the new WHERE — the DROP has to
385
377
  // stay commented too, or the live index gets dropped with no
386
- // executable replacement (kumiko-framework#2492 review).
378
+ // executable replacement.
387
379
  lines.push(nextIdxMeta.needsManualWhere === true
388
380
  ? `-- (review) DROP INDEX IF EXISTS ${quoteIdent(idxChange.name)};`
389
381
  : `DROP INDEX IF EXISTS ${quoteIdent(idxChange.name)};`);