@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
@@ -1,12 +1,13 @@
1
1
  import { buildExecutorContext } from "./event-store-executor-context.js";
2
2
  import { createReadVerbs } from "./event-store-executor-read.js";
3
3
  import { createWriteVerbs } from "./event-store-executor-write.js";
4
+ import { withOwnTransactionOnPool } from "./event-store-executor-write-atomic.js";
4
5
  export { WritePurposes } from "@cosmicdrift/kumiko-types/event-store-executor-types";
5
6
  export { entityEventName } from "./event-store-executor-context.js";
6
7
  export function createEventStoreExecutor(table, entity, options) {
7
8
  const ctx = buildExecutorContext(table, entity, options);
8
9
  return {
9
- ...createWriteVerbs(ctx),
10
+ ...withOwnTransactionOnPool(createWriteVerbs(ctx)),
10
11
  ...createReadVerbs(ctx),
11
12
  };
12
13
  }
@@ -20,7 +20,7 @@ export function registerExecutorManagedWriteRunner(runner) {
20
20
  executorManagedWriteRunners.add(runner);
21
21
  }
22
22
  // WeakSet.has never reads a property off runner, so a fail-closed guard Proxy stays untouched.
23
- // postgres.js clients are callable (tagged templates), so a runner can be a function.
23
+ // Bun.SQL clients are callable (tagged templates), so a runner can be a function.
24
24
  export function hasExecutorManagedWriteCapability(runner) {
25
25
  if (typeof runner !== "object" && typeof runner !== "function")
26
26
  return false;
@@ -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,17 +21,18 @@ 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";
25
28
  export { flattenMoney, type MoneyRead, moneyPayloadToMinorUnits, rehydrateMoney } from "./money.ts";
26
- export { constraintOf, extractPgError, isTableAlreadyExists, isUniqueViolation, type PgErrorInfo, } from "./pg-error.ts";
29
+ export { constraintOf, extractPgError, isTableAlreadyExists, isUndefinedTable, isUniqueViolation, type PgErrorInfo, } from "./pg-error.ts";
27
30
  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,22 +8,24 @@ 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";
19
22
  export { flattenMoney, moneyPayloadToMinorUnits, rehydrateMoney } from "./money.js";
20
- export { constraintOf, extractPgError, isTableAlreadyExists, isUniqueViolation, } from "./pg-error.js";
23
+ export { constraintOf, extractPgError, isTableAlreadyExists, isUndefinedTable, isUniqueViolation, } from "./pg-error.js";
21
24
  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
+ }
@@ -79,100 +79,85 @@ function indexesByName(meta) {
79
79
  m.set(indexMetaKey(i), i);
80
80
  return m;
81
81
  }
82
- function diffOneTable(prev, next) {
83
- const prevCols = columnsByName(prev);
84
- const nextCols = columnsByName(next);
85
- const newColumns = [];
86
- const droppedColumns = [];
87
- const changedColumns = [];
88
- for (const [name, nextCol] of nextCols) {
89
- const prevCol = prevCols.get(name);
90
- if (!prevCol) {
91
- newColumns.push(nextCol);
92
- continue;
93
- }
94
- const change = { name };
95
- if (prevCol.notNull !== nextCol.notNull) {
96
- Object.assign(change, {
97
- nullabilityChanged: { from: prevCol.notNull, to: nextCol.notNull },
98
- });
99
- }
100
- if (prevCol.defaultSql !== nextCol.defaultSql) {
101
- Object.assign(change, {
102
- defaultChanged: { from: prevCol.defaultSql, to: nextCol.defaultSql },
103
- });
104
- }
105
- if (prevCol.pgType !== nextCol.pgType) {
106
- Object.assign(change, {
107
- typeChanged: { from: prevCol.pgType, to: nextCol.pgType },
108
- });
109
- }
110
- if (change.nullabilityChanged || change.defaultChanged || change.typeChanged) {
111
- changedColumns.push(change);
112
- }
113
- }
114
- for (const name of prevCols.keys()) {
115
- if (!nextCols.has(name))
116
- droppedColumns.push(name);
117
- }
118
- const prevIdx = indexesByName(prev);
119
- const nextIdx = indexesByName(next);
120
- const newIndexes = [];
121
- const droppedIndexes = [];
122
- const changedIndexes = [];
123
- for (const [name, idx] of nextIdx) {
124
- const prevI = prevIdx.get(name);
125
- if (!prevI) {
126
- 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);
127
97
  continue;
128
98
  }
129
- const columnsChanged = indexColumnsEqual(prevI.columns, idx.columns)
130
- ? undefined
131
- : { from: prevI.columns, to: idx.columns };
132
- const uniqueChanged = (prevI.unique ?? false) === (idx.unique ?? false)
133
- ? undefined
134
- : { from: prevI.unique ?? false, to: idx.unique ?? false };
135
- // Whitespace-only re-rendering of the predicate must not drop and rebuild a large index.
136
- const whereSqlChanged = whereSqlEqual(prevI.whereSql, idx.whereSql)
137
- ? undefined
138
- : { from: prevI.whereSql, to: idx.whereSql };
139
- const needsManualWhereChanged = (prevI.needsManualWhere ?? false) === (idx.needsManualWhere ?? false)
140
- ? undefined
141
- : { from: prevI.needsManualWhere ?? false, to: idx.needsManualWhere ?? false };
142
- if (columnsChanged || uniqueChanged || whereSqlChanged || needsManualWhereChanged) {
143
- // Single literal typed as IndexChange so a misspelled key fails to compile instead of silently dropping the change.
144
- const change = {
145
- name,
146
- ...(columnsChanged && { columnsChanged }),
147
- ...(uniqueChanged && { uniqueChanged }),
148
- ...(whereSqlChanged && { whereSqlChanged }),
149
- ...(needsManualWhereChanged && { needsManualWhereChanged }),
150
- };
151
- changedIndexes.push(change);
152
- }
99
+ const change = compare(name, prevItem, nextItem);
100
+ if (change !== undefined)
101
+ changed.push(change);
153
102
  }
154
- for (const name of prevIdx.keys()) {
155
- if (!nextIdx.has(name))
156
- 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;
157
127
  }
158
- const isEmpty = newColumns.length === 0 &&
159
- droppedColumns.length === 0 &&
160
- changedColumns.length === 0 &&
161
- newIndexes.length === 0 &&
162
- droppedIndexes.length === 0 &&
163
- changedIndexes.length === 0;
164
- if (isEmpty)
165
- return null;
128
+ // Single literal typed as IndexChange so a misspelled key fails to compile instead of silently dropping the change.
166
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 = {
167
151
  tableName: prev.tableName,
168
- newColumns,
169
- droppedColumns,
170
- changedColumns,
171
- newIndexes,
172
- droppedIndexes,
173
- 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,
174
158
  nextMeta: next,
175
159
  };
160
+ return hasNoTableChanges(diff) ? null : diff;
176
161
  }
177
162
  export function diffSnapshots(prev, next) {
178
163
  const prevByName = new Map();
@@ -188,16 +188,16 @@ function migrationClient(db) {
188
188
  if (hasBegin(client))
189
189
  return client;
190
190
  }
191
- throw new Error("migrate-runner: db argument has no .unsafe() and .begin() (need a postgres-js Sql or drizzle DbConnection)");
191
+ throw new Error("migrate-runner: db argument has no .unsafe() and .begin() (need a Bun.SQL pool or a DbConnection)");
192
192
  }
193
- // Raw-SQL via postgres-js .unsafe().
193
+ // Raw-SQL via Bun.SQL .unsafe().
194
194
  async function executeRaw(db, sqlText) {
195
195
  await migrationClient(db).unsafe(sqlText);
196
196
  }
197
197
  async function reserveConnection(db) {
198
198
  const client = migrationClient(db);
199
199
  if (typeof client.reserve !== "function") {
200
- throw new Error("migrate-runner: db argument has no .reserve() (need a postgres-js Sql)");
200
+ throw new Error("migrate-runner: db argument has no .reserve() (need a Bun.SQL pool)");
201
201
  }
202
202
  return client.reserve();
203
203
  }
@@ -280,7 +280,10 @@ export async function runMigrations(db, migrations) {
280
280
  return { applied: appliedIds, skipped: skippedIds };
281
281
  }
282
282
  finally {
283
- await conn.unsafe(`SELECT pg_advisory_unlock(${MIGRATION_ADVISORY_LOCK_KEY})`);
283
+ // A dropped session already released its lock; failing here would mask the migration error.
284
+ await conn
285
+ .unsafe(`SELECT pg_advisory_unlock(${MIGRATION_ADVISORY_LOCK_KEY})`)
286
+ .catch(() => undefined);
284
287
  }
285
288
  }
286
289
  finally {
@@ -1,28 +1,33 @@
1
- // Drizzle wraps postgres-js errors in `DrizzleQueryError`; the original PG
2
- // error (with SQLSTATE `code` and `constraint_name`) lives in `.cause`. We
3
- // unwrap both layers so callers don't have to know which layer produced the
4
- // error. Used by the event-store to distinguish a unique-violation on the
5
- // aggregate-version index (optimistic-concurrency conflict) from the one on
6
- // the idempotency-key index (caller-side replay signal).
1
+ // Bun.SQL server errors carry the SQLSTATE in `errno` and the constraint in
2
+ // `constraint` (`code` is the generic ERR_POSTGRES_SERVER_ERROR). Client-side
3
+ // failures have no `errno`, so their `code` (e.g. ERR_POSTGRES_CONNECTION_CLOSED)
4
+ // is returned instead. The `.cause` chain is walked so wrapped errors resolve too.
5
+ import { propertyOf } from "@cosmicdrift/kumiko-types/type-guards";
7
6
  const MAX_CAUSE_DEPTH = 8;
7
+ function stringOrUndefined(value) {
8
+ return typeof value === "string" ? value : undefined;
9
+ }
10
+ function infoOfLayer(layer) {
11
+ const sqlState = stringOrUndefined(propertyOf(layer, "errno"));
12
+ if (sqlState !== undefined) {
13
+ return {
14
+ code: sqlState,
15
+ constraint_name: stringOrUndefined(propertyOf(layer, "constraint")),
16
+ };
17
+ }
18
+ const code = stringOrUndefined(propertyOf(layer, "code"));
19
+ return code === undefined ? null : { code, constraint_name: undefined };
20
+ }
8
21
  export function extractPgError(e) {
9
- if (typeof e !== "object" || e === null)
10
- return null;
11
- const layers = [];
12
22
  let current = e;
13
23
  // Depth cap doubles as cycle protection for self-referential causes.
14
- while (typeof current === "object" && current !== null && layers.length < MAX_CAUSE_DEPTH) {
15
- layers.push(current);
16
- // @cast-boundary error-details — DrizzleQueryError wraps PG-error in .cause
17
- current = current.cause;
18
- }
19
- for (const layer of layers) {
20
- // @cast-boundary error-details — postgres-js error shape (code, constraint_name)
21
- const code = layer.code;
22
- const constraintName = layer.constraint_name; // @cast-boundary error-details
23
- if (code !== undefined || constraintName !== undefined) {
24
- return { code, constraint_name: constraintName };
25
- }
24
+ for (let depth = 0; depth < MAX_CAUSE_DEPTH; depth++) {
25
+ if (typeof current !== "object" || current === null)
26
+ return null;
27
+ const info = infoOfLayer(current);
28
+ if (info !== null)
29
+ return info;
30
+ current = propertyOf(current, "cause");
26
31
  }
27
32
  return null;
28
33
  }
@@ -499,7 +499,7 @@ async function rekeyTenantKeyedValue(deps, target) {
499
499
  const userSubject = keyedUnder?.kind === "tenant" && keyedUnder.tenantId === target.tenantId
500
500
  ? rekeyTargetOfTenantKeyedValue(target)
501
501
  : keyedUnder?.kind === "user"
502
- ? currentProjectionOwnerIfOther(target, keyedUnder.userId)
502
+ ? currentProjectionOwnerIfOther(target, fieldDef.userOwned.ownerField, keyedUnder.userId)
503
503
  : null;
504
504
  if (userSubject === null)
505
505
  return { kind: "unchanged" };
@@ -536,11 +536,8 @@ function rekeyTargetOfTenantKeyedValue(target) {
536
536
  // A value keyed under a previous owner moves to the owner the row has now. The
537
537
  // projection of the event's own tenant is authoritative here: the payload of
538
538
  // an old created event still names the owner the row had back then.
539
- function currentProjectionOwnerIfOther(target, keyedUserId) {
540
- const fieldDef = target.entity.fields[target.field];
541
- if (fieldDef === undefined || !("userOwned" in fieldDef) || !fieldDef.userOwned)
542
- return null;
543
- const owner = nonEmptyString(target.projectionOwnerRow?.[fieldDef.userOwned.ownerField]);
539
+ function currentProjectionOwnerIfOther(target, ownerField, keyedUserId) {
540
+ const owner = nonEmptyString(target.projectionOwnerRow?.[ownerField]);
544
541
  return owner === null || owner === keyedUserId ? null : { kind: "user", userId: owner };
545
542
  }
546
543
  // Only the row's own tenant key or a user key counts: another tenant's key is
@@ -1,7 +1,8 @@
1
1
  import { executeRawQueryRead } from "./raw-sql.js";
2
2
  // Called by createTenantDb with its inner runner; keeps raw SQL out of consumers.
3
+ // timestamptz(3): events.created_at has millisecond precision, a microsecond now() would compare later.
3
4
  export async function queryDatabaseNow(runner) {
4
- const [row] = await executeRawQueryRead(runner, "SELECT now() AS now");
5
+ const [row] = await executeRawQueryRead(runner, "SELECT now()::timestamptz(3) AS now");
5
6
  if (!row)
6
7
  throw new Error("SELECT now() returned no row");
7
8
  return row.now;
@@ -19,6 +19,7 @@
19
19
  // partial index whose WHERE the renderer can't express is rejected up-front.
20
20
  import { isUuid, parseTenantId } from "@cosmicdrift/kumiko-types/identifiers";
21
21
  import { configuredBlindIndexKey } from "../../crypto/index.js";
22
+ import { extractPgError } from "../pg-error.js";
22
23
  import { asEntityTableMeta, asRawClient } from "../query.js";
23
24
  import { renderTableDdl } from "../render-ddl.js";
24
25
  import { columnNamesOf, tableExists } from "../schema-inspection.js";
@@ -27,9 +28,7 @@ import { quoteTableIdent } from "./table-ops.js";
27
28
  export const PROJECTION_REBUILD_SCHEMA = "kumiko_rebuild";
28
29
  const SCHEMA_IDENT = quoteTableIdent(PROJECTION_REBUILD_SCHEMA);
29
30
  function isDuplicateSchemaError(e) {
30
- if (typeof e !== "object" || e === null || !("code" in e))
31
- return false;
32
- const { code } = e;
31
+ const code = extractPgError(e)?.code;
33
32
  // 42P06 duplicate_schema, 23505 unique_violation on pg_namespace — both
34
33
  // surface from the well-known CREATE SCHEMA IF NOT EXISTS race.
35
34
  return code === "42P06" || code === "23505";
@@ -1,9 +1,11 @@
1
1
  import type { AggregateRow, AggregateSpec } from "@cosmicdrift/kumiko-types/aggregate-types";
2
2
  import type { DbRunner, DbTx } from "@cosmicdrift/kumiko-types/db-connection";
3
3
  import type { ExecutorManagedRunner, ExecutorManagedWriteCapability, WritableTable } from "@cosmicdrift/kumiko-types/executor-brand";
4
- import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
5
4
  import type { SelectOptions, WhereObject } from "@cosmicdrift/kumiko-types/where-clause-types";
5
+ import { type ClosedConnectionContext } from "./closed-connection.ts";
6
+ import { type PreparedValue } from "./driver-value-preparation.ts";
6
7
  import type { EntityTableMeta } from "./entity-table-meta.ts";
8
+ import { type TableInfo } from "./table-info.ts";
7
9
  import { asEntityTableMeta, requireEntityTableMeta } from "./table-introspection.ts";
8
10
  export { asEntityTableMeta, requireEntityTableMeta };
9
11
  export type ReservedClient = {
@@ -30,20 +32,9 @@ export declare function runInSavepointIfSupported<T>(db: unknown, fn: (sp: DbRun
30
32
  export type AnyDb = DbRunner | unknown;
31
33
  type AnyRow = any;
32
34
  export type { JsonTextMatch, OrderByClause, SelectOptions, WhereObject, WhereOperator, WhereValue, } from "@cosmicdrift/kumiko-types/where-clause-types";
33
- type TableLike = EntityTableMeta | any;
34
- export type TableInfo = {
35
- readonly name: string;
36
- readonly columnOf: (field: string) => string;
37
- readonly pgTypeOf: (column: string) => string | undefined;
38
- readonly bigintJsModeOf: (column: string) => "number" | "bigint" | undefined;
39
- readonly fieldOf: (column: string) => string;
40
- readonly hasColumn: (fieldOrColumn: string) => boolean;
41
- };
42
- export declare function extractTableInfo(table: TableLike): TableInfo;
35
+ export type TableLike = EntityTableMeta | any;
43
36
  export declare function coerceRow<TOut = Record<string, unknown>>(row: Record<string, unknown>, info: TableInfo): TOut;
44
- export declare function instantToTimestamptzParam(instant: Temporal.Instant): string;
45
- export declare function isClosedConnectionError(err: unknown): boolean;
46
- export declare function describeClosedConnectionFailure(raw: unknown, err: unknown, attempts: number): Record<string, unknown> | undefined;
37
+ export declare function unsafeLoggingClosedConnection<TRow = unknown>(db: AnyDb, sqlText: string, params: readonly unknown[], context: ClosedConnectionContext): Promise<readonly TRow[]>;
47
38
  export declare function unsafeReadRetrying<TRow>(db: AnyDb, sqlText: string, params: readonly unknown[]): Promise<readonly TRow[]>;
48
39
  export declare function selectMany<TRow = AnyRow>(db: AnyDb, table: TableLike, where?: WhereObject, options?: SelectOptions): Promise<readonly TRow[]>;
49
40
  export declare function fetchOne<TRow = AnyRow>(db: AnyDb, table: TableLike, where: WhereObject): Promise<TRow | undefined>;
@@ -75,7 +66,18 @@ export declare function updateMany<TRow = AnyRow>(db: AnyDb, table: WritableTabl
75
66
  export declare function updateMany<TRow = AnyRow>(db: ExecutorManagedWriteCapability, table: EntityTableMeta, set: Record<string, unknown>, where: WhereObject): Promise<readonly TRow[]>;
76
67
  export declare function deleteMany(db: AnyDb, table: WritableTable, where: WhereObject): Promise<number>;
77
68
  export declare function deleteMany(db: ExecutorManagedWriteCapability, table: EntityTableMeta, where: WhereObject): Promise<number>;
69
+ export type InsertEntry = {
70
+ readonly field: string;
71
+ readonly col: string;
72
+ readonly prepared: PreparedValue;
73
+ };
74
+ export declare function insertEntries(info: TableInfo, values: Record<string, unknown>): InsertEntry[];
78
75
  export declare function resolveConflictColumns(table: TableLike, info: TableInfo, conflictKeys: readonly string[] | undefined): readonly string[];
76
+ export declare function conflictUpdateParts(info: TableInfo, entries: readonly InsertEntry[], update: Record<string, unknown> | undefined, skipCols: ReadonlySet<string>, params: unknown[]): string[];
77
+ export declare function buildInsertSql(info: TableInfo, entries: readonly InsertEntry[]): {
78
+ sqlPrefix: string;
79
+ params: unknown[];
80
+ };
79
81
  export type UpsertOnConflictOptions = {
80
82
  readonly conflictKeys: readonly string[];
81
83
  /** Columns to set on conflict. Default: EXCLUDED for every inserted non-key column. */
@@ -92,7 +94,6 @@ export type DeleteManyBatchedResult = {
92
94
  readonly batches: number;
93
95
  };
94
96
  export declare function countWhere(db: AnyDb, table: TableLike, where?: WhereObject): Promise<number>;
95
- export declare function isTimestamptzType(pgType: string | undefined): boolean;
96
97
  export declare function aggregateWhere(db: AnyDb, table: TableLike, spec: AggregateSpec, where?: WhereObject): Promise<readonly AggregateRow[]>;
97
98
  export declare function upsertOnConflict<TRow = AnyRow>(db: AnyDb, table: WritableTable, values: Record<string, unknown>, options: UpsertOnConflictOptions): Promise<TRow | undefined>;
98
99
  export declare function upsertOnConflict<TRow = AnyRow>(db: ExecutorManagedWriteCapability, table: EntityTableMeta, values: Record<string, unknown>, options: UpsertOnConflictOptions): Promise<TRow | undefined>;