@cosmicdrift/kumiko-framework 0.387.0 → 0.389.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 (375) hide show
  1. package/AGENTS.md +9 -1
  2. package/agents/examples/anonymous-access.md +1 -1
  3. package/agents/examples/apex-landing.md +204 -0
  4. package/agents/examples/api-worker-split.md +64 -0
  5. package/agents/examples/app-config.md +14 -0
  6. package/agents/examples/auth-mfa.md +115 -0
  7. package/agents/examples/env-composition.md +28 -1
  8. package/agents/examples/golden-path.md +13 -1
  9. package/agents/examples/legal-pages.md +1 -1
  10. package/agents/examples/lifecycle-hooks.md +55 -2
  11. package/agents/examples/list-table-options.md +466 -0
  12. package/agents/examples/pdf-audit-export.md +4 -2
  13. package/agents/examples/prod-boot-options.md +16 -0
  14. package/agents/examples/rate-limiting.md +48 -0
  15. package/agents/examples/record-detail-layout.md +692 -0
  16. package/agents/examples/seed-migration.md +212 -0
  17. package/agents/examples/state-machine.md +3 -2
  18. package/agents/examples/tenant-isolation.md +73 -1
  19. package/agents/examples/wizard-form.md +941 -0
  20. package/agents/examples/writeform-section.md +548 -0
  21. package/agents/examples.md +1 -0
  22. package/agents/features.md +19 -2
  23. package/agents/widgets.md +2 -0
  24. package/dist/api/api-constants.d.ts +1 -0
  25. package/dist/api/api-constants.js +2 -0
  26. package/dist/api/auth-routes-shared.d.ts +2 -0
  27. package/dist/api/auth-routes-shared.js +5 -0
  28. package/dist/api/client-error-route.js +10 -5
  29. package/dist/api/entity-read-access.d.ts +2 -1
  30. package/dist/api/entity-read-access.js +14 -0
  31. package/dist/api/export/export-cells-reference.d.ts +9 -0
  32. package/dist/api/export/export-cells-reference.js +21 -0
  33. package/dist/api/export/export-cells.d.ts +11 -0
  34. package/dist/api/export/export-cells.js +136 -0
  35. package/dist/api/export/export-ciphertext-guard.d.ts +2 -0
  36. package/dist/api/export/export-ciphertext-guard.js +27 -0
  37. package/dist/api/export/export-columns.d.ts +29 -0
  38. package/dist/api/export/export-columns.js +85 -0
  39. package/dist/api/export/export-errors.d.ts +4 -0
  40. package/dist/api/export/export-errors.js +14 -0
  41. package/dist/api/export/export-route.d.ts +4 -0
  42. package/dist/api/export/export-route.js +74 -0
  43. package/dist/api/export/export-rows.d.ts +13 -0
  44. package/dist/api/export/export-rows.js +62 -0
  45. package/dist/api/export/export-screen.d.ts +12 -0
  46. package/dist/api/export/export-screen.js +47 -0
  47. package/dist/api/export/export-xlsx-writer.d.ts +4 -0
  48. package/dist/api/export/export-xlsx-writer.js +21 -0
  49. package/dist/api/extra-route.d.ts +4 -0
  50. package/dist/api/index.d.ts +3 -1
  51. package/dist/api/index.js +3 -1
  52. package/dist/api/pii-leak-guard.d.ts +3 -0
  53. package/dist/api/pii-leak-guard.js +3 -2
  54. package/dist/api/request-context.d.ts +1 -1
  55. package/dist/api/request-context.js +1 -1
  56. package/dist/api/routes.d.ts +16 -0
  57. package/dist/api/routes.js +2 -2
  58. package/dist/api/server-boot-checks.d.ts +10 -0
  59. package/dist/api/server-boot-checks.js +157 -0
  60. package/dist/api/server-event-dispatcher.d.ts +26 -0
  61. package/dist/api/server-event-dispatcher.js +208 -0
  62. package/dist/api/server-extra-routes.d.ts +11 -0
  63. package/dist/api/server-extra-routes.js +206 -0
  64. package/dist/api/server-middleware.d.ts +20 -0
  65. package/dist/api/server-middleware.js +211 -0
  66. package/dist/api/server-routes.d.ts +19 -0
  67. package/dist/api/server-routes.js +299 -0
  68. package/dist/api/server-websocket-routes.d.ts +4 -0
  69. package/dist/api/server-websocket-routes.js +108 -0
  70. package/dist/api/server-wiring.d.ts +32 -0
  71. package/dist/api/server-wiring.js +238 -0
  72. package/dist/api/server.d.ts +10 -15
  73. package/dist/api/server.js +48 -1251
  74. package/dist/api/session-cookies.js +4 -4
  75. package/dist/api/sse-route.d.ts +2 -1
  76. package/dist/api/sse-route.js +27 -13
  77. package/dist/config/index.d.ts +3 -1
  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.d.ts +1 -0
  81. package/dist/crypto/pg-kms-adapter.js +12 -18
  82. package/dist/crypto/pii-field-encryption.d.ts +5 -1
  83. package/dist/crypto/pii-field-encryption.js +3 -1
  84. package/dist/db/aggregate-sql.d.ts +23 -0
  85. package/dist/db/aggregate-sql.js +165 -0
  86. package/dist/db/closed-connection.d.ts +9 -0
  87. package/dist/db/closed-connection.js +88 -0
  88. package/dist/db/connection.d.ts +4 -5
  89. package/dist/db/connection.js +29 -20
  90. package/dist/db/dialect.js +1 -1
  91. package/dist/db/distinct-on.d.ts +1 -1
  92. package/dist/db/driver-row-coercion.d.ts +2 -0
  93. package/dist/db/driver-row-coercion.js +186 -0
  94. package/dist/db/driver-value-preparation.d.ts +16 -0
  95. package/dist/db/driver-value-preparation.js +101 -0
  96. package/dist/db/entity-field-encryption.d.ts +1 -0
  97. package/dist/db/entity-field-encryption.js +1 -1
  98. package/dist/db/entity-table-meta.js +103 -110
  99. package/dist/db/event-store-executor-context.d.ts +2 -1
  100. package/dist/db/event-store-executor-read-aggregate-currencies.d.ts +17 -0
  101. package/dist/db/event-store-executor-read-aggregate-currencies.js +40 -0
  102. package/dist/db/event-store-executor-read-aggregate.d.ts +8 -0
  103. package/dist/db/event-store-executor-read-aggregate.js +143 -0
  104. package/dist/db/event-store-executor-read-filter.d.ts +31 -0
  105. package/dist/db/event-store-executor-read-filter.js +206 -0
  106. package/dist/db/event-store-executor-read-paging.d.ts +14 -0
  107. package/dist/db/event-store-executor-read-paging.js +99 -0
  108. package/dist/db/event-store-executor-read-rows.d.ts +6 -0
  109. package/dist/db/event-store-executor-read-rows.js +32 -0
  110. package/dist/db/event-store-executor-read-search.d.ts +28 -0
  111. package/dist/db/event-store-executor-read-search.js +221 -0
  112. package/dist/db/event-store-executor-read-sort.d.ts +41 -0
  113. package/dist/db/event-store-executor-read-sort.js +130 -0
  114. package/dist/db/event-store-executor-read-where.d.ts +24 -0
  115. package/dist/db/event-store-executor-read-where.js +81 -0
  116. package/dist/db/event-store-executor-read.d.ts +2 -9
  117. package/dist/db/event-store-executor-read.js +48 -701
  118. package/dist/db/event-store-executor-write-atomic.d.ts +4 -0
  119. package/dist/db/event-store-executor-write-atomic.js +41 -0
  120. package/dist/db/event-store-executor-write-steps.d.ts +17 -0
  121. package/dist/db/event-store-executor-write-steps.js +95 -0
  122. package/dist/db/event-store-executor-write.js +405 -509
  123. package/dist/db/event-store-executor.js +2 -1
  124. package/dist/db/executor-managed-tables.js +1 -1
  125. package/dist/db/index.d.ts +7 -3
  126. package/dist/db/index.js +6 -2
  127. package/dist/db/list-aggregate-labels.d.ts +14 -0
  128. package/dist/db/list-aggregate-labels.js +26 -0
  129. package/dist/db/migrate-generator.js +71 -86
  130. package/dist/db/migrate-runner.js +7 -4
  131. package/dist/db/pg-error.js +26 -21
  132. package/dist/db/queries/backfill-pii.js +3 -6
  133. package/dist/db/queries/database-now.js +2 -1
  134. package/dist/db/queries/shadow-swap.js +2 -3
  135. package/dist/db/query.d.ts +16 -15
  136. package/dist/db/query.js +76 -804
  137. package/dist/db/reference-data.js +19 -2
  138. package/dist/db/statement-timeout.js +2 -1
  139. package/dist/db/table-builder.js +113 -166
  140. package/dist/db/table-info.d.ts +10 -0
  141. package/dist/db/table-info.js +45 -0
  142. package/dist/db/temporal-value-guards.d.ts +6 -0
  143. package/dist/db/temporal-value-guards.js +15 -0
  144. package/dist/db/tenant-db-runner.d.ts +1 -0
  145. package/dist/db/tenant-db-runner.js +3 -0
  146. package/dist/db/tenant-db-upsert.d.ts +5 -0
  147. package/dist/db/tenant-db-upsert.js +91 -0
  148. package/dist/db/tenant-db.js +50 -10
  149. package/dist/db/where-clause.d.ts +6 -0
  150. package/dist/db/where-clause.js +236 -0
  151. package/dist/derivatives/delete-stored-file.js +2 -1
  152. package/dist/engine/boot-validator/boot-check.js +1 -1
  153. package/dist/engine/boot-validator/bundled-lists-table.d.ts +2 -0
  154. package/dist/engine/boot-validator/bundled-lists-table.js +36 -0
  155. package/dist/engine/boot-validator/detail-screens.js +2 -2
  156. package/dist/engine/boot-validator/entity-handler.d.ts +1 -0
  157. package/dist/engine/boot-validator/entity-handler.js +17 -0
  158. package/dist/engine/boot-validator/entity-list-aggregate-options.d.ts +3 -0
  159. package/dist/engine/boot-validator/entity-list-aggregate-options.js +23 -0
  160. package/dist/engine/boot-validator/form-derivations.js +35 -1
  161. package/dist/engine/boot-validator/i18n-keys.js +5 -3
  162. package/dist/engine/boot-validator/index.js +2 -0
  163. package/dist/engine/boot-validator/list-bulk-actions.d.ts +3 -0
  164. package/dist/engine/boot-validator/list-bulk-actions.js +49 -0
  165. package/dist/engine/boot-validator/list-column-layout.d.ts +8 -0
  166. package/dist/engine/boot-validator/list-column-layout.js +41 -0
  167. package/dist/engine/boot-validator/list-table-aggregate-options.d.ts +24 -0
  168. package/dist/engine/boot-validator/list-table-aggregate-options.js +145 -0
  169. package/dist/engine/boot-validator/list-table-aggregate-query.d.ts +10 -0
  170. package/dist/engine/boot-validator/list-table-aggregate-query.js +31 -0
  171. package/dist/engine/boot-validator/list-table-export-options.d.ts +1 -0
  172. package/dist/engine/boot-validator/list-table-export-options.js +27 -0
  173. package/dist/engine/boot-validator/list-table-options.d.ts +3 -0
  174. package/dist/engine/boot-validator/list-table-options.js +77 -0
  175. package/dist/engine/boot-validator/list-table-reject-unknown-keys.d.ts +1 -0
  176. package/dist/engine/boot-validator/list-table-reject-unknown-keys.js +7 -0
  177. package/dist/engine/boot-validator/pii-retention.js +233 -155
  178. package/dist/engine/boot-validator/projection-list-screens.d.ts +1 -1
  179. package/dist/engine/boot-validator/projection-list-screens.js +3 -13
  180. package/dist/engine/boot-validator/related-list-table-rules.d.ts +4 -0
  181. package/dist/engine/boot-validator/related-list-table-rules.js +42 -0
  182. package/dist/engine/boot-validator/screens-actions.d.ts +1 -0
  183. package/dist/engine/boot-validator/screens-actions.js +8 -1
  184. package/dist/engine/boot-validator/screens-dashboard.js +2 -5
  185. package/dist/engine/boot-validator/screens-forms.js +2 -6
  186. package/dist/engine/boot-validator/screens-kind-config-edit.d.ts +3 -0
  187. package/dist/engine/boot-validator/screens-kind-config-edit.js +88 -0
  188. package/dist/engine/boot-validator/screens-kind-entity-edit.d.ts +3 -0
  189. package/dist/engine/boot-validator/screens-kind-entity-edit.js +55 -0
  190. package/dist/engine/boot-validator/screens-kind-entity-list.d.ts +3 -0
  191. package/dist/engine/boot-validator/screens-kind-entity-list.js +235 -0
  192. package/dist/engine/boot-validator/screens-kind-projection-detail.d.ts +3 -0
  193. package/dist/engine/boot-validator/screens-kind-projection-detail.js +235 -0
  194. package/dist/engine/boot-validator/screens-kind-projection-list.d.ts +3 -0
  195. package/dist/engine/boot-validator/screens-kind-projection-list.js +56 -0
  196. package/dist/engine/boot-validator/screens-kind-secret-mint.d.ts +3 -0
  197. package/dist/engine/boot-validator/screens-kind-secret-mint.js +28 -0
  198. package/dist/engine/boot-validator/screens-kind-shared.d.ts +37 -0
  199. package/dist/engine/boot-validator/screens-kind-shared.js +142 -0
  200. package/dist/engine/boot-validator/screens-lists.d.ts +2 -1
  201. package/dist/engine/boot-validator/screens-lists.js +24 -11
  202. package/dist/engine/boot-validator/screens.d.ts +0 -2
  203. package/dist/engine/boot-validator/screens.js +99 -860
  204. package/dist/engine/build-app-schema.d.ts +2 -1
  205. package/dist/engine/build-app-schema.js +65 -97
  206. package/dist/engine/build-config-feature-schema.js +6 -1
  207. package/dist/engine/define-feature.js +13 -2
  208. package/dist/engine/define-handler.js +1 -0
  209. package/dist/engine/entity-handlers.d.ts +13 -0
  210. package/dist/engine/entity-handlers.js +10 -21
  211. package/dist/engine/entity-list-runtime-options.d.ts +8 -0
  212. package/dist/engine/entity-list-runtime-options.js +18 -0
  213. package/dist/engine/feature-ast/extractors/handlers.js +1 -0
  214. package/dist/engine/feature-ast/extractors/index.d.ts +1 -1
  215. package/dist/engine/feature-ast/extractors/index.js +1 -1
  216. package/dist/engine/feature-ast/extractors/round1.d.ts +2 -1
  217. package/dist/engine/feature-ast/extractors/round1.js +6 -0
  218. package/dist/engine/feature-ast/extractors/round2.js +25 -6
  219. package/dist/engine/feature-ast/index.d.ts +1 -1
  220. package/dist/engine/feature-ast/parse.js +3 -1
  221. package/dist/engine/feature-ast/patch.d.ts +2 -0
  222. package/dist/engine/feature-ast/patch.js +5 -182
  223. package/dist/engine/feature-ast/pattern-change-schema.d.ts +10 -245
  224. package/dist/engine/feature-ast/pattern-change-schema.js +10 -163
  225. package/dist/engine/feature-ast/pattern-id-matchers.d.ts +7 -0
  226. package/dist/engine/feature-ast/pattern-id-matchers.js +211 -0
  227. package/dist/engine/feature-ast/pattern-id-schema.d.ts +251 -0
  228. package/dist/engine/feature-ast/pattern-id-schema.js +166 -0
  229. package/dist/engine/feature-ast/patterns.d.ts +14 -1
  230. package/dist/engine/feature-ast/patterns.js +44 -51
  231. package/dist/engine/feature-ast/render.js +52 -87
  232. package/dist/engine/feature-builder-state.d.ts +1 -0
  233. package/dist/engine/feature-builder-state.js +1 -0
  234. package/dist/engine/feature-entity-handlers.js +3 -0
  235. package/dist/engine/feature-manifest.d.ts +1 -0
  236. package/dist/engine/feature-manifest.js +1 -0
  237. package/dist/engine/field-access.d.ts +1 -0
  238. package/dist/engine/field-access.js +12 -0
  239. package/dist/engine/form-derivations.js +18 -7
  240. package/dist/engine/handler-field-references.js +1 -1
  241. package/dist/engine/index.d.ts +2 -2
  242. package/dist/engine/index.js +1 -1
  243. package/dist/engine/pattern-library/library.js +2 -1
  244. package/dist/engine/pattern-library/static-schemas.d.ts +1 -0
  245. package/dist/engine/pattern-library/static-schemas.js +9 -0
  246. package/dist/engine/project-app-schema-for-roles.d.ts +2 -0
  247. package/dist/engine/project-app-schema-for-roles.js +6 -4
  248. package/dist/engine/registry-ingest.js +1 -1
  249. package/dist/engine/schema-builder.js +228 -212
  250. package/dist/engine/screen-filter-ops.js +2 -0
  251. package/dist/engine/screen-helpers.js +1 -1
  252. package/dist/engine/screen-kind.d.ts +7 -0
  253. package/dist/engine/screen-kind.js +1 -0
  254. package/dist/engine/strip-disabled-features-from-app-schema.js +58 -17
  255. package/dist/engine/types/feature.d.ts +1 -0
  256. package/dist/engine/types/index.d.ts +4 -3
  257. package/dist/engine/types/screen.d.ts +1 -1
  258. package/dist/engine/types/screen.js +1 -1
  259. package/dist/engine/validate-projection-allowlist.js +2 -1
  260. package/dist/entrypoint/index.d.ts +6 -1
  261. package/dist/entrypoint/index.js +10 -1
  262. package/dist/errors/docs-url.d.ts +1 -1
  263. package/dist/errors/docs-url.js +22 -2
  264. package/dist/es-ops/context.js +1 -1
  265. package/dist/event-store/admin-api.js +1 -1
  266. package/dist/event-store/event-store.d.ts +1 -0
  267. package/dist/event-store/event-store.js +17 -8
  268. package/dist/event-store/provenance-append.js +1 -1
  269. package/dist/files/bind-pending-file-refs.js +3 -3
  270. package/dist/files/create-file-ref-from-bytes.js +7 -1
  271. package/dist/files/create-file-ref.d.ts +3 -0
  272. package/dist/files/create-file-ref.js +11 -2
  273. package/dist/files/file-handle.js +2 -3
  274. package/dist/files/file-routes.d.ts +2 -0
  275. package/dist/files/file-routes.js +40 -10
  276. package/dist/files/provider-resolver.d.ts +1 -0
  277. package/dist/files/provider-resolver.js +1 -1
  278. package/dist/files/record-write-check.d.ts +6 -0
  279. package/dist/files/record-write-check.js +13 -0
  280. package/dist/files/resolve-content-type.js +43 -0
  281. package/dist/files/upload-ledger.d.ts +2 -2
  282. package/dist/files/upload-ledger.js +11 -4
  283. package/dist/i18n/required-surface-keys.js +189 -208
  284. package/dist/internal/stack-support.d.ts +2 -1
  285. package/dist/internal/stack-support.js +1 -1
  286. package/dist/internal/testing.js +1 -1
  287. package/dist/jobs/job-runner-context.d.ts +32 -0
  288. package/dist/jobs/job-runner-context.js +305 -0
  289. package/dist/jobs/job-runner-execution.d.ts +7 -0
  290. package/dist/jobs/job-runner-execution.js +160 -0
  291. package/dist/jobs/job-runner-gates.d.ts +19 -0
  292. package/dist/jobs/job-runner-gates.js +198 -0
  293. package/dist/jobs/job-runner-helpers.d.ts +17 -3
  294. package/dist/jobs/job-runner-helpers.js +61 -2
  295. package/dist/jobs/job-runner-scope.d.ts +44 -0
  296. package/dist/jobs/job-runner-scope.js +102 -0
  297. package/dist/jobs/job-runner-types.d.ts +12 -0
  298. package/dist/jobs/job-runner.d.ts +0 -1
  299. package/dist/jobs/job-runner.js +50 -657
  300. package/dist/observability/escape-hatch-report.d.ts +3 -0
  301. package/dist/observability/escape-hatch-report.js +21 -3
  302. package/dist/pipeline/after-rollback-sink.d.ts +6 -0
  303. package/dist/pipeline/after-rollback-sink.js +32 -0
  304. package/dist/pipeline/cascade-handler.js +165 -138
  305. package/dist/pipeline/dispatch-batch.js +8 -1
  306. package/dist/pipeline/dispatch-query.js +10 -3
  307. package/dist/pipeline/dispatch-shared.d.ts +13 -3
  308. package/dist/pipeline/dispatch-shared.js +62 -710
  309. package/dist/pipeline/dispatch-write.js +296 -189
  310. package/dist/pipeline/event-dispatcher-admin.js +2 -1
  311. package/dist/pipeline/event-dispatcher-delivery.js +6 -6
  312. package/dist/pipeline/event-dispatcher.d.ts +1 -0
  313. package/dist/pipeline/event-dispatcher.js +6 -9
  314. package/dist/pipeline/handler-context-auth.d.ts +9 -0
  315. package/dist/pipeline/handler-context-auth.js +54 -0
  316. package/dist/pipeline/handler-context-config.d.ts +14 -0
  317. package/dist/pipeline/handler-context-config.js +113 -0
  318. package/dist/pipeline/handler-context-db.d.ts +24 -0
  319. package/dist/pipeline/handler-context-db.js +149 -0
  320. package/dist/pipeline/handler-context-dispatch.d.ts +23 -0
  321. package/dist/pipeline/handler-context-dispatch.js +101 -0
  322. package/dist/pipeline/handler-context-events.d.ts +41 -0
  323. package/dist/pipeline/handler-context-events.js +239 -0
  324. package/dist/pipeline/handler-context-notify.d.ts +12 -0
  325. package/dist/pipeline/handler-context-notify.js +55 -0
  326. package/dist/pipeline/handler-context-observability.d.ts +7 -0
  327. package/dist/pipeline/handler-context-observability.js +21 -0
  328. package/dist/pipeline/handler-context-scope.d.ts +48 -0
  329. package/dist/pipeline/handler-context-scope.js +88 -0
  330. package/dist/pipeline/notify-scope.js +12 -1
  331. package/dist/pipeline/pre-handler-gates.js +20 -4
  332. package/dist/pipeline/pre-transaction-reservations.d.ts +1 -0
  333. package/dist/pipeline/pre-transaction-reservations.js +9 -3
  334. package/dist/pipeline/projection-rebuild.js +2 -1
  335. package/dist/pipeline/system-hooks.d.ts +3 -1
  336. package/dist/pipeline/system-hooks.js +55 -6
  337. package/dist/pipeline/write-result-masking.js +13 -10
  338. package/dist/schema-cli/apply-command.d.ts +2 -0
  339. package/dist/schema-cli/apply-command.js +97 -0
  340. package/dist/schema-cli/baseline-command.d.ts +2 -0
  341. package/dist/schema-cli/baseline-command.js +33 -0
  342. package/dist/schema-cli/generate-command.d.ts +2 -0
  343. package/dist/schema-cli/generate-command.js +90 -0
  344. package/dist/schema-cli/shared.d.ts +39 -0
  345. package/dist/schema-cli/shared.js +95 -0
  346. package/dist/schema-cli/status-command.d.ts +2 -0
  347. package/dist/schema-cli/status-command.js +73 -0
  348. package/dist/schema-cli/validate-boot-input.d.ts +5 -0
  349. package/dist/schema-cli/validate-boot-input.js +130 -0
  350. package/dist/schema-cli/validate-command.d.ts +2 -0
  351. package/dist/schema-cli/validate-command.js +130 -0
  352. package/dist/schema-cli.d.ts +2 -18
  353. package/dist/schema-cli.js +47 -604
  354. package/dist/search/meilisearch-adapter.js +2 -1
  355. package/dist/search/reindex-entity.js +15 -5
  356. package/dist/ui-types/index.d.ts +2 -2
  357. package/dist/ui-types/index.js +1 -1
  358. package/dist/upgrade-changelog.d.ts +2 -0
  359. package/dist/upgrade-changelog.js +14 -0
  360. package/dist/upgrade-cli.d.ts +3 -12
  361. package/dist/upgrade-cli.js +171 -197
  362. package/dist/upgrade-marker-parse.d.ts +32 -0
  363. package/dist/upgrade-marker-parse.js +73 -0
  364. package/package.json +9 -6
  365. package/src/changes.json +555 -0
  366. package/src/scripts/codemod/codemod-support.ts +1 -1
  367. package/src/scripts/codemod/db-factory.ts +1 -1
  368. package/src/scripts/codemod/feature-layout.ts +10 -2
  369. package/src/scripts/codemod/object-form.ts +41 -4
  370. package/src/scripts/codemod/package-merge.ts +58 -8
  371. package/src/scripts/codemod/pii-personal-migration.ts +175 -145
  372. package/src/scripts/codemod/testing-injection.ts +122 -42
  373. package/src/scripts/codemod/testing-move.ts +29 -7
  374. package/dist/engine/provider-plugin-context.d.ts +0 -3
  375. package/dist/engine/provider-plugin-context.js +0 -28
package/src/changes.json CHANGED
@@ -1,4 +1,559 @@
1
1
  [
2
+ {
3
+ "version": "0.389.0",
4
+ "type": "breaking",
5
+ "title": "Bun.SQL replaces postgres-js as the only Postgres driver",
6
+ "detail": "createDbConnection opens a Bun.SQL pool and needs Bun 1.4.4 or newer, the first release that drops a cached statement plan after DDL on the same connection. The handle gains listenClient for LISTEN/NOTIFY. Server errors carry the code ERR_POSTGRES_SERVER_ERROR with the SQLSTATE in errno and the constraint name in constraint; connection failures carry ERR_POSTGRES_CONNECTION_CLOSED, ERR_POSTGRES_CONNECTION_REFUSED, ERR_POSTGRES_CONNECTION_TIMEOUT or ERR_POSTGRES_CONNECTION_FAILED. extractPgError, isUniqueViolation, isTableAlreadyExists, constraintOf and the newly exported isUndefinedTable read that shape. The onNotice option is removed, because Bun.SQL has no notice hook and drops server notices. The ssl option takes Bun's tls value (a boolean, \"disable\", \"prefer\", \"require\", \"verify-ca\", \"verify-full\" or a TLS options object); ssl true and a TLS object without rejectUnauthorized still verify the server certificate, as they did with postgres-js. DB_PROVIDER is refused at boot for every non-empty value, \"postgres\" included.",
7
+ "migration": "Read SQLSTATE and constraint only through extractPgError or the is* helpers from @cosmicdrift/kumiko-framework/db; a direct err.code === \"23505\" check or an err.constraint_name read no longer matches. Replace checks for CONNECTION_CLOSED, CONNECTION_ENDED, CONNECTION_DESTROYED or CONNECT_TIMEOUT with the ERR_POSTGRES_CONNECTION_* codes. Drop onNotice from createDbConnection calls. Remove DB_PROVIDER from every environment. Run on Bun 1.4.4 or newer in engines, CI and images. Code that imports postgres itself must declare its own dependency or move to Bun.SQL, since the framework no longer installs it. Manual migration, there is no codemod."
8
+ },
9
+ {
10
+ "version": "0.389.0",
11
+ "type": "improvement",
12
+ "title": "schema status and baseline use one connection, bun-types is a peer dependency",
13
+ "detail": "kumiko schema status and baseline open a pool of one connection instead of the default size, because Bun.SQL dials every pool connection on the first query. bun-types is now a peer dependency (^1.4.4) of framework, types, server-runtime and dev-server instead of a regular dependency, so install it next to the framework."
14
+ },
15
+ {
16
+ "version": "0.389.0",
17
+ "type": "improvement",
18
+ "title": "validateBundledListsOptions and the BundledListsOptions type",
19
+ "detail": "BundledListsOptions is exported from the types package and the engine barrel. validateBundledListsOptions rejects unknown keys, grouping, totals and pinFirstColumn without table.pinning with a message that names the key, and checks the remaining keys like a screen's own table block."
20
+ },
21
+ {
22
+ "version": "0.389.0",
23
+ "type": "improvement",
24
+ "title": "r.adoptsBundledLists() marks features that take the bundledLists block",
25
+ "detail": "The registrar method r.adoptsBundledLists() marks a feature whose list screens take the app-wide bundledLists block; the flag appears as FeatureDefinition.adoptsBundledLists and in feature-manifest.json, and the feature-ast parser knows the call as an opaque singleton pattern."
26
+ },
27
+ {
28
+ "version": "0.389.0",
29
+ "type": "improvement",
30
+ "title": "table block on entityList, projectionList and relatedList",
31
+ "detail": "The new optional table block (rememberState, resetAll, columnPicker, density with default and userChoice) is validated at boot; unknown keys, hidden columns without columnPicker and invalid density values are rejected. Columns accept hidden: true. Remembered state lives in sessionStorage per tenant and user and is cleared on logout or identity change."
32
+ },
33
+ {
34
+ "version": "0.389.0",
35
+ "type": "improvement",
36
+ "title": "table.pinning, table.resizing and table.keyboardNavigation, column pinned, width and minWidth",
37
+ "detail": "The boot validator rejects pinned without table.pinning, a pinned value other than left or right, width or minWidth without table.resizing, values that are not finite numbers above 0, and a minWidth above the width."
38
+ },
39
+ {
40
+ "version": "0.389.0",
41
+ "type": "breaking",
42
+ "title": "Money list aggregates answer one value per currency",
43
+ "detail": "A sum, avg, min or max measure over a money field in a list aggregate now answers [{ currency, value }] with value in minor units, one entry per currency in the matching rows, and never adds amounts of different currencies. Before, it answered one plain number over all currencies.",
44
+ "migration": "code reading measures of a money field from a list aggregate answer (executor.aggregate, answerListAggregate or the list query with aggregate) reads an array of { currency, value } instead of a number; take the entry of the wanted currency, value stays in minor units"
45
+ },
46
+ {
47
+ "version": "0.389.0",
48
+ "type": "improvement",
49
+ "title": "table.grouping, table.totals and range facets validated at boot",
50
+ "detail": "The table block takes grouping ({ field, label?, labels?, collapsedWhen?, userChoice?, fields? }) and totals ([{ field, kind }]). The boot validator checks the fields against the entity or the columns, rejects measures a field type cannot carry and requires the list query to accept aggregate (entityListSchema does; hand-written queries answer it with answerListAggregate). facets.<field>.display \"range\" needs a filterable number, decimal, money or bigInt field."
51
+ },
52
+ {
53
+ "version": "0.389.0",
54
+ "type": "improvement",
55
+ "title": "bulkActions on entityList, projectionList and relatedList",
56
+ "detail": "Each entry is { id, rowAction, confirm? } and points at a writeHandler entry of the same screen's rowActions. The boot validator rejects unknown keys, a non-kebab or duplicate id, an unknown rowAction and a rowAction of kind clientAction, navigate or drawer."
57
+ },
58
+ {
59
+ "version": "0.389.0",
60
+ "type": "improvement",
61
+ "title": "XLSX export for entityList and projectionList via table.export",
62
+ "detail": "The new table.export block ({ xlsx: true, maxRows? }) is validated at boot and is only accepted on entityList and projectionList. POST /api/export/xlsx runs the list query again with the caller's session, pages through the whole filtered list and answers 413 above maxRows (default 10000, hard cap 100000). Encrypted, sensitive, write-only and unreadable fields and virtual columns are left out of the sheet. Reference columns export the label of the target (joined with commas for multiple references), not the id. Timestamp cells use the browser time zone sent with the request, else the profile zone, else UTC. Personal access tokens are rejected. A projectionList query must honor offset or return nextCursor. Adds the write-excel-file dependency."
63
+ },
64
+ {
65
+ "version": "0.389.0",
66
+ "type": "fix",
67
+ "title": "Executor writes on a pool runner are atomic",
68
+ "detail": "executor.create/update/delete/forget/restore on a TenantDb that is not inside a transaction used to run append, projection and custom projections as separate autocommit statements, so a failing projection left an event without its row. They now run in their own transaction, and a returned failure such as version_conflict rolls it back too. Calls inside a handler transaction keep their savepoint behavior. Callers that wrapped executor writes in runInOwnTransaction as a workaround can drop it."
69
+ },
70
+ {
71
+ "version": "0.389.0",
72
+ "type": "breaking",
73
+ "title": "FeatureRegistrar types moved to @cosmicdrift/kumiko-types/feature-registrar",
74
+ "migration": "Import FeatureRegistrar, HookDefinition, EntityObjectDefinition and RequiresApi from @cosmicdrift/kumiko-types/feature-registrar or from the engine barrel of @cosmicdrift/kumiko-framework; @cosmicdrift/kumiko-types/feature no longer exports them."
75
+ },
76
+ {
77
+ "version": "0.389.0",
78
+ "type": "fix",
79
+ "title": "maxPerTenant counts active and waiting jobs in one snapshot",
80
+ "detail": "The guard read the active and the waiting list with separate Redis calls, so a job that moved from waiting to active between them was missing from both and a dispatch over the cap got through. It now reads both lists with one getJobs snapshot per queue. The integration tests hold the cap jobs on a release gate instead of sleeping."
81
+ },
82
+ {
83
+ "version": "0.389.0",
84
+ "type": "breaking",
85
+ "title": "relatedList groupBy replaced by table.grouping",
86
+ "detail": "The groupBy key on a relatedList section and an entityList expandableRow is removed together with the RelatedListGroupBy type. Both group through table.grouping ({ field, label?, labels?, collapsedWhen? }): groups, counts and header measures come from one aggregate query over all matching rows instead of the loaded page, and each open group loads its own rows. An expandableRow takes only table.grouping with a fixed field; userChoice, fields and every other table option stay boot errors there. The boot validator reports a leftover groupBy with a pointer to table.grouping. ExpandableRowGrouping is the new type of an expandableRow's grouping.",
87
+ "migration": "move groupBy { field, collapsedWhen, label, labels } to table: { grouping: { field, collapsedWhen, label, labels } }; the bound query must accept aggregate (entityListSchema does, a hand-written query answers it with answerListAggregate). dateField and the {lastDate} placeholder have no replacement on an expandableRow, where totals stay off; on a relatedList a max measure in table.totals shows the latest date. Every group now gets a header: a group without label or labels entry shows its value instead of rendering headerless."
88
+ },
89
+ {
90
+ "version": "0.389.0",
91
+ "type": "improvement",
92
+ "title": "ctx.loadAggregate can read a single event by version",
93
+ "detail": "The new atVersion option returns the event at that version of the stream (or nothing), with upcasting and the tenant filter. It cannot be combined with asOf. Workflow resume uses it for event references."
94
+ },
95
+ {
96
+ "version": "0.389.0",
97
+ "type": "fix",
98
+ "title": "Access invalidation survives a Redis outage",
99
+ "detail": "The consumer that pushes session, token and membership revocations to open streams does not count failed publishes towards the attempt limit and backs off between them, instead of dying after 10 failed deliveries and silently dropping later revocations. Other failures keep the limit. New EventConsumerErrorPolicy.isTransientError."
100
+ },
101
+ {
102
+ "version": "0.389.0",
103
+ "type": "fix",
104
+ "title": "file upload rechecks the record lock when inserting the row",
105
+ "detail": "POST /files with an entityId reads the stored row again through the inserting transaction and refuses with 409 record_locked when lockedWhen holds. The window between that read and the commit stays open, like for any other write that checks the lock before its own commit."
106
+ },
107
+ {
108
+ "version": "0.389.0",
109
+ "type": "fix",
110
+ "title": "Meilisearch default upgrade cannot tell a narrowed configure() from an older default",
111
+ "detail": "A tenant that called configure() with a strict subset of the default attributes gets the full default back after the next process restart, because Meilisearch stores no marker for an explicit configure(). Configure the full attribute set, or a set that contains an attribute outside the default, to keep it."
112
+ },
113
+ {
114
+ "version": "0.389.0",
115
+ "type": "fix",
116
+ "title": "Cross-tenant-read crons audit once per day, not once per foreign row",
117
+ "detail": "The process dedup key of a declared system cron hatch includes the target only for global-write (a table). Row targets of cross-tenant-read no longer grow the in-memory map or write one audit event per row."
118
+ },
119
+ {
120
+ "version": "0.389.0",
121
+ "type": "fix",
122
+ "title": "Failed job-runner start waits for the timed-out boot gate",
123
+ "detail": "start() now waits a bounded time for an abandoned boot gate before throwing, instead of leaving that to stop(). The scheduler-seen timer is only started after every step that can fail, so no timer outlives a failed start."
124
+ },
125
+ {
126
+ "version": "0.389.0",
127
+ "type": "fix",
128
+ "title": "disabled feature no longer removes another feature's workspace with the same id",
129
+ "detail": "buildAppSchema records which feature owns each workspace and the feature strip removes only the workspaces of the disabled features. Two features that use the same short workspace id keep their own entries."
130
+ },
131
+ {
132
+ "version": "0.389.0",
133
+ "type": "fix",
134
+ "title": "upload ledger uses the injected clock",
135
+ "detail": "createFileUploadLedger and withUploadLedger take an optional now function, and the file provider resolver wires AppContext.clock into it. Without a clock the system time is used as before."
136
+ },
137
+ {
138
+ "version": "0.389.0",
139
+ "type": "fix",
140
+ "title": "anonymous save leaves foreign pending uploads unbound",
141
+ "detail": "Integration test through the real write route with anonymous access, covering the save pipeline path of the pending-upload ownership check."
142
+ },
143
+ {
144
+ "version": "0.389.0",
145
+ "type": "breaking",
146
+ "title": "Unused ProviderPluginContext helpers removed",
147
+ "detail": "ProviderPluginContext, providerPluginContextFromHandler and providerPluginContextFromJob are gone. No plugin type or resolver used them, and the type exposed db handles without an audit user. Provider contexts stay the narrow FileProviderContext, MailTransportContext and InboundMailContext.",
148
+ "migration": "no known callers; use FileProviderContext, MailTransportContext or InboundMailContext"
149
+ },
150
+ {
151
+ "version": "0.389.0",
152
+ "type": "breaking",
153
+ "title": "provider selector option labels are unique per owner",
154
+ "detail": "The selector field id of a provider form is qualified with its owner feature, so the translation keys of its option labels change.",
155
+ "migration": "move app translation overrides from config:entity:__config-edit__:field:provider:option:<value> to the owner-qualified field id, field:mail-foundation-provider:option:<value> or field:file-foundation-provider:option:<value>"
156
+ },
157
+ {
158
+ "version": "0.389.0",
159
+ "type": "fix",
160
+ "title": "live signals hide row ids from row-filtered roles",
161
+ "detail": "createSseRoute takes an optional entityRowReadMaps option, built from entity access.read by the server routes. A signed-in connection receives id and version only if the entity has no read ownership map or one of its roles is mapped to all; otherwise the signal carries just the entity and event type so the client refetches."
162
+ },
163
+ {
164
+ "version": "0.389.0",
165
+ "type": "fix",
166
+ "title": "write handlers that spread the executor result keep projections and postSave hooks",
167
+ "detail": "The event is stripped from lifecycle results when the dispatcher masks the response, no longer made non-enumerable on the result, so copying the result does not lose it. Responses still carry no event."
168
+ },
169
+ {
170
+ "version": "0.389.0",
171
+ "type": "improvement",
172
+ "title": "event-free write results proven for non-HTTP entry points",
173
+ "detail": "Integration tests assert that dispatcher.write, dispatcher.batch and the agent tool dispatch return no event. No runtime change: all of them already pass through the dispatcher masking."
174
+ },
175
+ {
176
+ "version": "0.389.0",
177
+ "type": "fix",
178
+ "title": "reference-data seed adopts rows that have no event stream",
179
+ "detail": "Rows from installs that seeded reference data by direct insert are re-created under the same id through the executor on the next boot, so updates apply and the rows survive a rebuild. No action is needed; the row id is unchanged, only its version restarts at 1."
180
+ },
181
+ {
182
+ "version": "0.389.0",
183
+ "type": "fix",
184
+ "title": "client-errors route keeps an in-memory floor limit",
185
+ "detail": "The in-memory per-IP limiter now runs in front of the Redis-backed limiter instead of only when no resolver is wired, so a failing resolver can no longer lift the limit on the public client-errors endpoint."
186
+ },
187
+ {
188
+ "version": "0.389.0",
189
+ "type": "fix",
190
+ "title": "reindex job batches are no longer cut off by the server statement timeout",
191
+ "detail": "reindexEntity reads each batch in its own transaction with statement_timeout lifted for that transaction, on the caller's own runner, so the job path through ctx.systemDb.unsafeRaw() keeps its gates."
192
+ },
193
+ {
194
+ "version": "0.389.0",
195
+ "type": "fix",
196
+ "title": "files meta batch route is rate limited by id count",
197
+ "detail": "createFileRoutes takes an optional metaBatchRateLimitResolver, wired by the server from the rate-limit resolver or Redis. A user over 1000 requested ids per minute gets 429 rate_limited; a failing limiter fails open and is reported like the other limiters."
198
+ },
199
+ {
200
+ "version": "0.389.0",
201
+ "type": "fix",
202
+ "title": "kumiko-upgrade explains that --apply writes the CHANGELOG",
203
+ "detail": "The preview run never wrote the upgrade CHANGELOG or the marker, and consumers running it without --apply got no entry and no explanation. It now prints a hint; the exit code is unchanged."
204
+ },
205
+ {
206
+ "version": "0.389.0",
207
+ "type": "fix",
208
+ "title": "Codemod imports no longer land inside header comments",
209
+ "detail": "ensureNamedImport appends the new import after the last existing import, so a file with a header comment block keeps the comment intact."
210
+ },
211
+ {
212
+ "version": "0.389.0",
213
+ "type": "fix",
214
+ "title": "Database now is rounded to milliseconds",
215
+ "detail": "The Postgres clock read behind readDatabaseNow is cast to timestamptz(3), the precision of events.created_at, so a comparison with a stored event time is exact."
216
+ },
217
+ {
218
+ "version": "0.389.0",
219
+ "type": "improvement",
220
+ "title": "E2E seeders and signature routes can write with explicit roles",
221
+ "detail": "dispatchWriteAs on signature route deps and writeAs on the E2E seeder context run a write as the tenant's system user with the \"system\" role plus the given roles, without SystemAdmin. write() keeps running as SystemAdmin."
222
+ },
223
+ {
224
+ "version": "0.389.0",
225
+ "type": "fix",
226
+ "title": "List filter on multiple references matches array contents",
227
+ "detail": "eq, ne and in on a multi-reference field now check jsonb containment instead of scalar equality, and screen filters on such fields allow the equality operators. Consumers no longer need a full scan."
228
+ },
229
+ {
230
+ "version": "0.389.0",
231
+ "type": "fix",
232
+ "title": "kumiko-upgrade --resolve updates CHANGELOG.md",
233
+ "detail": "The Manual migrations lines of every CHANGELOG.md section change from [open] to the chosen resolution for the resolved ids; other entries and files without a CHANGELOG.md are left alone."
234
+ },
235
+ {
236
+ "version": "0.389.0",
237
+ "type": "improvement",
238
+ "title": "ctx.scheduleAfterRollback for outside-transaction compensation",
239
+ "detail": "ctx.scheduleAfterRollback(fn) runs fn when the handler transaction does not commit, or when the enclosing savepoint of a nested ctx.write rolls back (after the outer transaction ends). It never runs on commit, errors are logged and do not change the write result, and it is absent outside a transaction scope (perCommand, post-commit, beforeTransaction, member resolution). A failed COMMIT also triggers it, so callbacks must be idempotent and outcome-safe, for example releasing a reservation row that may already be gone."
240
+ },
241
+ {
242
+ "version": "0.389.0",
243
+ "type": "improvement",
244
+ "title": "Tenant-safe upsert on ctx.db",
245
+ "detail": "ctx.db.upsert(table, values, { conflictTarget, update? }) requires tenantId in conflictTarget and the target to match a declared unique index or primary key. The update only touches the row of the inserted tenant, update may not set tenantId, and the default update leaves conflict, primary-key and tenant columns alone. Event-fed tables are rejected. Replaces unsafeRaw plus upsertOnConflict for tenant-scoped upserts."
246
+ },
247
+ {
248
+ "version": "0.388.0",
249
+ "type": "fix",
250
+ "title": "runProdApp passes errorDocs and instanceId to the server",
251
+ "detail": "ApiEntrypointOptions now carries errorDocs and instanceId and createApiEntrypoint forwards them to the server. Before, runProdApp dropped its errorDocs option, and a KUMIKO_INSTANCE_ID set only in a custom envSource never reached the server, which fell back to process.env. The boot-abort cleanup of runProdApp also moved into a helper that swallows synchronously throwing cleanups."
252
+ },
253
+ {
254
+ "version": "0.388.0",
255
+ "type": "fix",
256
+ "title": "Physical-table collisions use the DDL table name",
257
+ "detail": "createRegistry compared entity tables under a feature-prefixed name that no DDL path creates, so an entity whose explicit table equals another feature's derived table name, or two entities with the same explicit table in different features, registered fine and then emitted the same CREATE TABLE twice. The check now uses the unprefixed physical name, the same as the store-table check and the migrate runner.",
258
+ "migration": "Apps where two entities share a physical table name fail at boot with \"has physical table ... which collides with entity ...\". Give one of them a different `table`."
259
+ },
260
+ {
261
+ "version": "0.388.0",
262
+ "type": "fix",
263
+ "title": "Worker entrypoint takes instanceId",
264
+ "detail": "WorkerEntrypointOptions now carries instanceId (moved to BaseEntrypointOptions, so the API and all-in-one options keep it) and createWorkerEntrypoint forwards it to the server. runWorkerApp reads KUMIKO_INSTANCE_ID from its envSource like runProdApp, so with KUMIKO_INSTANCE_ID set, per-instance consumers in the worker and its app.started event use the same id. Before, the worker server only saw process.env."
265
+ },
266
+ {
267
+ "version": "0.388.0",
268
+ "type": "improvement",
269
+ "title": "PII, retention and cascade-delete rules as tables, English dev messages",
270
+ "detail": "validatePiiAndRetention runs one checker per rule in a fixed order, and the cascade-delete hook dispatches each relation through a table of onDelete strategies. Error and warning texts, their order, transaction boundaries and event order are unchanged. buildAppSchema forwards field properties through an ordered table, and kumiko-upgrade and the pii-personal-migration codemod run one function per step; their output is byte-identical. The dev warnings of normalizeListColumn and buildAppSchema are now English."
271
+ },
272
+ {
273
+ "version": "0.388.0",
274
+ "type": "improvement",
275
+ "title": "Named steps for list reads, field columns, table metadata and table diffs",
276
+ "detail": "The list read verb runs search, sort, cursor boundary, filters, stream-version projection, row rehydration and the next cursor as named steps in their own files next to event-store-executor-read.ts, and detail() shares the ownership and row rehydration steps. Field columns come from one emitter per field type in a typed table, so a new field type fails the typecheck until it has an emitter, and an unknown type from untyped input still throws \"unhandled field type\". deriveEntityTableMeta collects columns, foreign-key, blind-index and declared indexes in separate steps with the same overloads and error texts. diffOneTable compares columns and indexes through one comparator per kind and keeps the order of added, dropped and changed entries."
277
+ },
278
+ {
279
+ "version": "0.388.0",
280
+ "type": "improvement",
281
+ "title": "Per-kind tables for feature-AST id matching, editability and rendering",
282
+ "detail": "callMatchesId() looks up one matcher per PatternId kind in a typed table in feature-ast/pattern-id-matchers.ts next to patch.ts. getEditability() reads a table keyed by pattern kind, and renderPattern() dispatches through one renderer per pattern kind. All three tables are typed over their kind union, so a new kind does not compile until it has an entry. The feature-ast barrel exports the same names as before."
283
+ },
284
+ {
285
+ "version": "0.388.0",
286
+ "type": "fix",
287
+ "title": "Boot enforces the projection allowlist",
288
+ "detail": "The projection allowlist validator existed but was never called from validateBoot. It now runs as the last cross-feature check. It also keys aggregate tables by the physical table name (entity.table or the derived read_* name) instead of the entity name, so unsafeProjection steps on the table of an entity without an explicit table, and duplicate tables between a derived and an explicit name, are detected.",
289
+ "migration": "Apps with such violations fail at boot. Add the missing r.requires.projection or r.requires.step declaration, or use r.step.aggregate.* for aggregate tables."
290
+ },
291
+ {
292
+ "version": "0.388.0",
293
+ "type": "improvement",
294
+ "title": "Recipe for Input kind \"code\" in a confirmation step",
295
+ "detail": "samples/recipes/auth-mfa has a ConfirmationCodeStep for e-mail or invite codes that uses Input kind \"code\" with length, autoFocus and onComplete, clears and refocuses after a rejected code, and has a DOM test. The agent example for auth-mfa includes it."
296
+ },
297
+ {
298
+ "version": "0.388.0",
299
+ "type": "improvement",
300
+ "title": "Groups and sums on the entity list query",
301
+ "detail": "Pass aggregate with an optional groupBy field and up to 20 measures (sum, avg, count, min, max per field) to a list query. The answer is groups with key, count, one value per measure in request order and, for a reference groupBy, the label of the referenced row. Screen filters, search, ownership and field read access apply exactly as for rows; a field the caller may not read yields null or no groups, and encrypted, personal or secret fields and unsuitable field types are rejected with a validation error. At most 200 groups are returned, with truncated set beyond that. Custom query handlers use executor.aggregate or answerListAggregate."
302
+ },
303
+ {
304
+ "version": "0.388.0",
305
+ "type": "improvement",
306
+ "title": "buildServer split into middleware installers and route mounters",
307
+ "detail": "buildServer() keeps its signature and behavior. Boot checks, pre-app wiring, the event dispatcher, middleware installers and route mounters now live in server-*.ts files next to server.ts. withFileProviderResolver and makeDispatchSystemWrite/makeDispatchWriteAs/makeDispatchSystemQuery are still exported from the api barrel under the same names."
308
+ },
309
+ {
310
+ "version": "0.388.0",
311
+ "type": "improvement",
312
+ "title": "Where-clause emitters, coercer table and named write steps",
313
+ "detail": "buildWhereClause() now dispatches through one emitter per WhereOperator key in a typed table, and coerceDriverRow() looks up one coercer per pgType. Table introspection, value preparation, row coercion, closed-connection handling and aggregate SQL live in their own files next to db/query.ts. The create and update write verbs run preSave, field and ownership checks, the record-lock guard, select-option checks, the version check, the append and the projection as named steps. The db barrel exports the same names as before."
314
+ },
315
+ {
316
+ "version": "0.388.0",
317
+ "type": "improvement",
318
+ "title": "Job runner run path split into named steps",
319
+ "detail": "handleJob() in jobs/job-runner.ts now composes the perTenant fan-out, the unknown-job check, the maxPerTenant defer gate and the sequential lock (job-runner-gates.ts), the run context with its db, service and dispatch facets (job-runner-context.ts), the job.execute span with success and failure recording (job-runner-execution.ts) and the handler deferral. The runner's shared state travels in one scope object (job-runner-scope.ts). The jobs barrel exports the same names as before. New integration tests cover unknown jobs taken from the queue, a perTenant wrapper for an unknown job, a perTenant job without a tenant resolver and ctx.defer with a non-positive delay."
320
+ },
321
+ {
322
+ "version": "0.388.0",
323
+ "type": "improvement",
324
+ "title": "Handler context and write pipeline split into named steps",
325
+ "detail": "buildHandlerContext() in pipeline/dispatch-shared.ts now composes one builder per facet of the flat HandlerContext: the shared scope (handler-context-scope.ts), the tenant-scoped db handles, forTenant and file contexts (handler-context-db.ts), the commit sinks with ctx.query/write/queryAs/writeAs and nested writes in savepoints (handler-context-dispatch.ts), ctx.notify (handler-context-notify.ts), config, configFor, tz and locale (handler-context-config.ts), the event store surfaces and ctx.queryProjection (handler-context-events.ts), the identity-gated auth surfaces and ctx.hasFeature (handler-context-auth.ts) and log, tracer and metrics (handler-context-observability.ts). executeWriteInner() in pipeline/dispatch-write.ts runs the entry checks, the pre-handler gates with the reservation, the transition guard, the handler call and the settle step with reservation confirm, lifecycle and after-commit hooks as separate functions; executeNestedWrite() checks the nested foreign keys, verifies the parent row and writes the children in their own steps. Public exports are unchanged. New tests cover the ctx.snapshotAggregate/ctx.loadAggregateWithSnapshot roundtrip with tenant isolation and the no-database error text of the event store surfaces."
326
+ },
327
+ {
328
+ "version": "0.388.0",
329
+ "type": "improvement",
330
+ "title": "kumiko-schema output in English, schema CLI and screen key collection split per kind",
331
+ "detail": "Visible change: kumiko-schema (and the dev `kumiko schema` command) now prints \"is missing\", \"App convention\", \"No schema changes detected — no new migration file written.\", \"Review, hand-edit if needed, then git add + commit.\", \"is missing — run schema generate <name> first.\", \"No kumiko/migrations/ — the app is still on the legacy drizzle path.\", \"Unknown subcommand\" / \"Allowed\", \"must declare `export const ENTITY_METAS: EntityTableMeta[]`\" and an English help text instead of the German lines. The standalone `kumiko schema apply` of production bundles prints \"Creating framework infrastructure tables (idempotent)…\", \"Applying kumiko migrations (…)…\", \"… is missing — kumiko/migrations/ must be part of the image.\" and \"Unknown command: kumiko … / The standalone bundle only supports 'kumiko schema apply'.\". Scripts that matched the German text need the English one. Exit codes, the order of the output lines and which lines go to stderr are unchanged. runSchemaCli() keeps its signature; each subcommand lives in its own file under schema-cli/. requiredKeysFromScreen() returns the same keys in the same order; a screen with an unknown type (only reachable through a cast) yields just its title key."
332
+ },
333
+ {
334
+ "version": "0.388.0",
335
+ "type": "improvement",
336
+ "title": "validateScreens split into one validator per screen kind",
337
+ "detail": "validateScreens() keeps its signature, its error messages and the order in which it reports the first error. The per-kind validators live in screens-kind-*.ts next to screens.ts, and checks shared by several kinds (empty columns or sections, header actions, write-handler registration) live in screens-kind-shared.ts and screens-actions.ts. A screen whose type is not a known kind now fails boot with an explicit \"unknown type\" error."
338
+ },
339
+ {
340
+ "version": "0.388.0",
341
+ "type": "fix",
342
+ "title": "Sequential job lock released when run setup fails",
343
+ "detail": "handleJob() claimed the sequential lock before prepareJobRun() and the onJobStart hook, but only released it in the finally block that started after them. A throwing onJobStart left the lock until its TTL (305 s) and every further invocation of that job was requeued behind it. Both calls now run inside the try and the lock is released by job name. A failure there is logged and, on the final attempt, reported through onJobFailed. The seed-migration failure message starts with systemWriteAs(...) instead of the duplicated [es-ops/seed-migration] prefix."
344
+ },
345
+ {
346
+ "version": "0.388.0",
347
+ "type": "fix",
348
+ "title": "Reconnect after an outage no longer waits out connect_timeout",
349
+ "detail": "The postgres.js fork left the write buffer of a dead socket in place, so the first query after a database outage queued its startup message behind stale bytes and failed with CONNECT_TIMEOUT after 30 seconds. The fork now resets the buffer when the socket closes, and the next query opens a fresh connection immediately."
350
+ },
351
+ {
352
+ "version": "0.388.0",
353
+ "type": "improvement",
354
+ "title": "rateLimitCost for write handlers",
355
+ "detail": "A write handler can declare `rateLimitCost: (payload) => number`. The result is booked on every declared `rateLimit` bucket instead of the options' static `cost`; values below 1 count as 1 and non-finite values fail the request. The bucket is charged after schema validation, so an invalid payload costs nothing, and a rejected request consumes no tokens. Boot fails when `rateLimitCost` is set without an active `rateLimit`, or on an anonymous or ip-limited handler, because the cost books after the parse and such a handler would lose its pre-parse protection.",
356
+ "migration": "Optional. Bulk handlers should add `rateLimitCost: (p) => p.files.length` so a request with many items is not counted as one."
357
+ },
358
+ {
359
+ "version": "0.388.0",
360
+ "type": "fix",
361
+ "title": "Codemods no longer drop side-effect imports or miss moved index files",
362
+ "detail": "The testing-move codemod repoints side-effect and empty imports instead of deleting them. The feature-layout codemod rewrites directory imports such as \"./components\" when the moved file is components/index.ts."
363
+ },
364
+ {
365
+ "version": "0.388.0",
366
+ "type": "fix",
367
+ "title": "Review fixes for notify, form derivations, i18n keys, feature AST, nav stripping and escape-hatch audit",
368
+ "detail": "A deferred ctx.notify with Temporal values in data no longer fails the write. Form derivations take the literal currency or the source currency before the client value, reject mixed-currency operands, and the boot validator now rejects derive definitions that mix money with number/decimal units or use non-numeric sources. Metric labels of projectionDetail screens are required i18n keys. The feature AST keeps backingTable on spread entity definitions. Pure grouping navs emptied by disabled features are removed. db.global() writes are audited per table."
369
+ },
370
+ {
371
+ "version": "0.388.0",
372
+ "type": "fix",
373
+ "title": "Client-error rate limit survives address rotation",
374
+ "detail": "Without Redis, the per-process limiter now drops the least recently seen IPs when more than 10000 are tracked, so a flood of fresh addresses no longer resets the window of every other IP."
375
+ },
376
+ {
377
+ "version": "0.388.0",
378
+ "type": "fix",
379
+ "title": "Stalled SSE clients are dropped without further broadcasts",
380
+ "detail": "The heartbeat ping is written and tracked like entity frames instead of awaited, so a client that stopped reading is aborted at the next heartbeat after the stall timeout and releases its broker slot."
381
+ },
382
+ {
383
+ "version": "0.388.0",
384
+ "type": "fix",
385
+ "title": "Leftover __Host- cookies are expired with secureCookies:false too",
386
+ "detail": "Clearing the session cookies now always sends the Secure delete for the __Host- auth and csrf variants when the configured names are unprefixed, so an app switched to secureCookies:false behind a TLS proxy no longer keeps a stale __Host- csrf cookie."
387
+ },
388
+ {
389
+ "version": "0.388.0",
390
+ "type": "breaking",
391
+ "title": "runAsDirectCallEntry renamed to runAsAgentToolCallEntry",
392
+ "detail": "The internal request-context helper also marks its scope as an agent tool call, so the name now says so; it stays reserved for dispatchToolCall.",
393
+ "migration": "replace imports of runAsDirectCallEntry from @cosmicdrift/kumiko-framework/internal/request-context with runAsAgentToolCallEntry; the signature is unchanged"
394
+ },
395
+ {
396
+ "version": "0.388.0",
397
+ "type": "fix",
398
+ "title": "Version conflicts skip the extra stream-version lookup",
399
+ "detail": "The CRUD executor reports the current version carried by the event store conflict and queries the stream again only when the conflict carries none."
400
+ },
401
+ {
402
+ "version": "0.388.0",
403
+ "type": "fix",
404
+ "title": "distinctOn documents that system reference rows compete for newest",
405
+ "detail": "The tenant-scoped read set includes system reference rows, so they take part in the newest-row pick; the docs name the tenantId filter that restricts it to own rows, and tests pin both behaviours. Tests also cover the createDbConnection ssl and onNotice options, the version-conflict race over HTTP, and the advisory-lock waiter probe is scoped to its own lock."
406
+ },
407
+ {
408
+ "version": "0.388.0",
409
+ "type": "fix",
410
+ "title": "Empty and exclusion tenant filters no longer widen a read",
411
+ "detail": "A where.tenantId of { in: [] } now returns no rows, and { ne } or { notIn } keep excluding the named tenants instead of falling back to the caller's full scope. scopeTenantDbToTenant keeps the write denial of its source TenantDb."
412
+ },
413
+ {
414
+ "version": "0.388.0",
415
+ "type": "fix",
416
+ "title": "Boot seeding re-creates soft-deleted reference rows",
417
+ "detail": "The seed lookup only considers live system-tenant rows, so a soft-deleted reference row is created anew instead of aborting the boot with a not-found error."
418
+ },
419
+ {
420
+ "version": "0.388.0",
421
+ "type": "fix",
422
+ "title": "Version conflict on update reports the appended-against version",
423
+ "detail": "The racing update path now reports expectedVersion as the stream version it appended against, also with skipOptimisticLock or an expect precondition. A failed advisory unlock after a dropped session no longer hides the migration error."
424
+ },
425
+ {
426
+ "version": "0.388.0",
427
+ "type": "fix",
428
+ "title": "Unknown keys in a handler field references meta fail the boot",
429
+ "detail": "A references meta such as `{ entity: \"channel\", bY: \"key\" }` is reported as invalid instead of silently reading as an id reference, so a misspelled `by` can no longer turn a business-key field into an id field."
430
+ },
431
+ {
432
+ "version": "0.388.0",
433
+ "type": "fix",
434
+ "title": "r.requires rejects malformed arguments",
435
+ "detail": "`r.requires` now throws when called with more than one argument or without a `features` string array, instead of dropping extra arguments or registering the object as a dependency name."
436
+ },
437
+ {
438
+ "version": "0.388.0",
439
+ "type": "fix",
440
+ "title": "r.bootCheck failures keep the check's own message",
441
+ "detail": "The boot error no longer appends a generic sentence, so messages ending in a period are not doubled and the check's text is the whole explanation."
442
+ },
443
+ {
444
+ "version": "0.388.0",
445
+ "type": "fix",
446
+ "title": "Embedded list minimum stays in the JSON schema",
447
+ "detail": "A required or `minItems` embedded list again reports `minItems` in `z.toJSONSchema` output, so agent manifests tell callers that at least one row is needed."
448
+ },
449
+ {
450
+ "version": "0.388.0",
451
+ "type": "fix",
452
+ "title": "Failing trial gate no longer breaks GET /api/schema",
453
+ "detail": "The trial gates of all disabled toggleable features run in parallel; a gate that throws counts as not unlocked, hides the add-on and is logged, so the client still boots."
454
+ },
455
+ {
456
+ "version": "0.388.0",
457
+ "type": "fix",
458
+ "title": "No docsUrl for app error codes without a framework page",
459
+ "detail": "An app subclass that overrides the error code with an uncovered reason no longer links to a framework page that does not exist; the field is absent unless errorDocs covers the reason."
460
+ },
461
+ {
462
+ "version": "0.388.0",
463
+ "type": "fix",
464
+ "title": "Anonymous sessions cannot bind pending uploads on save",
465
+ "detail": "The save pipeline now applies the same anonymous-session exclusion as the pending file ref helpers, so one visitor cannot attach another visitor's pending upload to their record."
466
+ },
467
+ {
468
+ "version": "0.388.0",
469
+ "type": "fix",
470
+ "title": "Failed uploads drop their upload ledger row",
471
+ "detail": "When the fileRef create fails after the bytes were written, POST /files and createFileRefFromBytes now delete the bytes and forget the ledger row instead of leaving it for the next sweep."
472
+ },
473
+ {
474
+ "version": "0.388.0",
475
+ "type": "fix",
476
+ "title": "More HTML roots are kept out of the XML content type",
477
+ "detail": "Uploads without a declared content type whose root element is a common HTML element (form, iframe, input, table parts, media and others) are no longer labelled application/xml."
478
+ },
479
+ {
480
+ "version": "0.388.0",
481
+ "type": "fix",
482
+ "title": "POST /files uses the tenant file context and a transaction-safe upload ledger",
483
+ "detail": "The upload route records and forgets upload bytes through the resolver's ledger like every other file context, and createFileUploadLedger throws when given a connection already inside a transaction."
484
+ },
485
+ {
486
+ "version": "0.388.0",
487
+ "type": "fix",
488
+ "title": "A failed runner start no longer leaves a scheduler refresh timer behind",
489
+ "detail": "The scheduler-seen refresh timer starts only after the rest of start() succeeded, so a failed start does not keep stamping for a runner that is not running."
490
+ },
491
+ {
492
+ "version": "0.388.0",
493
+ "type": "fix",
494
+ "title": "Job runs survive a failing tenant timezone config read",
495
+ "detail": "A throwing tenant timezone config read now logs a warning and falls back to UTC for ctx.tz instead of failing a job that never uses ctx.tz."
496
+ },
497
+ {
498
+ "version": "0.388.0",
499
+ "type": "fix",
500
+ "title": "Escape-hatch process dedup no longer grows without bound",
501
+ "detail": "Entries older than the daily re-audit interval are swept, so row-level cross-tenant read targets in long-lived workers are not kept forever."
502
+ },
503
+ {
504
+ "version": "0.388.0",
505
+ "type": "fix",
506
+ "title": "Handler cross-tenant reads count in the escape-hatch metric",
507
+ "detail": "Handlers now report to the escape-hatch meter like jobs do, so every ctx.crossTenantReads call is counted while the audit event stays deduplicated per report window."
508
+ },
509
+ {
510
+ "version": "0.388.0",
511
+ "type": "fix",
512
+ "title": "beforeTransaction phase and handler share one parsed payload",
513
+ "detail": "The payload parsed for the pre-transaction phases is handed to the handler as is, so schema defaults or transforms that generate values no longer differ between the phase and the handler."
514
+ },
515
+ {
516
+ "version": "0.388.0",
517
+ "type": "fix",
518
+ "title": "Cascade delete and set-null load only child ids",
519
+ "detail": "The cascade handler selects the id column instead of full child rows before calling the executor per child."
520
+ },
521
+ {
522
+ "version": "0.388.0",
523
+ "type": "fix",
524
+ "title": "Codemods stop miscompiling or skipping ambiguous sites",
525
+ "detail": "testing-injection rewrites named re-exports of moved names and reports export-star, testing-move reports namespace destructuring and qualified type references of split names, and object-form no longer rewrites r.requires(identifier) but reports it for a manual check."
526
+ },
527
+ {
528
+ "version": "0.388.0",
529
+ "type": "fix",
530
+ "title": "schema validate names the violated FeatureDefinition key",
531
+ "detail": "A malformed FEATURES entry now reports the first key that is missing or has the wrong type instead of always pointing at the name."
532
+ },
533
+ {
534
+ "version": "0.388.0",
535
+ "type": "fix",
536
+ "title": "Upgrade check names the codemod an improvement runs on apply",
537
+ "detail": "kumiko-upgrade without --apply now prints the codemod of each improvement entry, the same way it prints the migration of breaking entries."
538
+ },
539
+ {
540
+ "version": "0.388.0",
541
+ "type": "fix",
542
+ "title": "Package-merge codemod keeps one entry per target package",
543
+ "detail": "When the merge target is already listed in dependencies, the old devDependencies entry is dropped; when the old entry is in dependencies and the target only in devDependencies, the target moves to dependencies so the runtime entry wins."
544
+ },
545
+ {
546
+ "version": "0.388.0",
547
+ "type": "fix",
548
+ "title": "NotificationTemplateMeta declares senderName and replyTo",
549
+ "detail": "The type now matches the mail template meta schema of the template resolver, which accepts senderName and replyTo."
550
+ },
551
+ {
552
+ "version": "0.388.0",
553
+ "type": "fix",
554
+ "title": "Seed writes run the save lifecycle, so seeded files bind to their records",
555
+ "detail": "runProdApp built the boot seed dispatcher without lifecycle hooks, so seed writes and seed migrations skipped file binding (entity_id stayed null, other users got 404), the pre/post save and delete hooks, the tenant check of file references and the disposal of removed file references. The seed dispatcher now reuses the lifecycle hooks of the API dispatcher, exposed as lifecycleHooks on the entrypoints and on KumikoServer. A hook that throws inside the transaction now fails the seed and the boot."
556
+ },
2
557
  {
3
558
  "version": "0.387.0",
4
559
  "type": "improvement",
@@ -155,7 +155,7 @@ export function ensureNamedImport(
155
155
  declaration.getNamedImports().length > 0,
156
156
  );
157
157
  if (target === undefined) {
158
- sourceFile.insertImportDeclaration(declarations.length, {
158
+ sourceFile.addImportDeclaration({
159
159
  moduleSpecifier: specifier,
160
160
  namedImports: [name],
161
161
  isTypeOnly,
@@ -623,7 +623,7 @@ function reportRemovedProviderEnv(
623
623
  file: filePath,
624
624
  line: node.getStartLineNumber(),
625
625
  kind: "call",
626
- description: `${REMOVED_ENV_NAME}: the Bun.SQL provider is gone, postgres-js is the only driver`,
626
+ description: `${REMOVED_ENV_NAME}: DB_PROVIDER is gone, Bun.SQL is the only driver`,
627
627
  });
628
628
  };
629
629
  for (const literal of sourceFile.getDescendantsOfKind(SyntaxKind.StringLiteral)) {
@@ -122,16 +122,24 @@ function movedTargetOf(
122
122
  moved: ReadonlyMap<string, string>,
123
123
  ): string | undefined {
124
124
  const { base, extension } = stripScriptExtension(absoluteSpecifier);
125
- const candidates =
125
+ const candidates: string[] =
126
126
  extension === ".js" || extension === ".ts" || extension === ".tsx" || extension === ""
127
127
  ? [absoluteSpecifier, `${base}.ts`, `${base}.tsx`]
128
128
  : [absoluteSpecifier];
129
+ if (extension === "")
130
+ candidates.push(`${absoluteSpecifier}/index.ts`, `${absoluteSpecifier}/index.tsx`);
129
131
  for (const candidate of candidates) {
130
132
  if (moved.has(candidate)) return candidate;
131
133
  }
132
134
  return undefined;
133
135
  }
134
136
 
137
+ // A moved `<dir>/index.ts` is imported as `<dir>`, so the file name alone never appears in the importer.
138
+ function importableNameOf(file: string): string {
139
+ const { base } = stripScriptExtension(baseName(file));
140
+ return base === "index" ? baseName(dirname(file)) : base;
141
+ }
142
+
135
143
  function relativeSpecifierFrom(fromDir: string, target: string): string {
136
144
  const path = relative(fromDir, target).split("\\").join("/");
137
145
  return path.startsWith(".") ? path : `./${path}`;
@@ -258,7 +266,7 @@ function buildWrites(
258
266
  importRewrites: CodemodSite[],
259
267
  ): Map<string, string> {
260
268
  const writes = new Map<string, string>();
261
- const basenames = [...moved.keys()].map((file) => stripScriptExtension(baseName(file)).base);
269
+ const basenames = [...moved.keys()].map(importableNameOf);
262
270
  for (const [file, original] of files) {
263
271
  const content = stripped.get(file) ?? original;
264
272
  const newFile = moved.get(file) ?? file;