@cosmicdrift/kumiko-framework 0.388.0 → 0.390.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 (711) hide show
  1. package/AGENTS.md +12 -4
  2. package/README.md +1 -1
  3. package/agents/examples/apex-surface-auth.md +2 -3
  4. package/agents/examples/api-worker-split.md +9 -2
  5. package/agents/examples/auth-claims.md +1 -1
  6. package/agents/examples/cross-feature-events.md +12 -12
  7. package/agents/examples/crypto-shredding-hr.md +2 -2
  8. package/agents/examples/encrypted-tenant-config.md +1 -1
  9. package/agents/examples/error-contract.md +12 -7
  10. package/agents/examples/event-sourcing.md +29 -29
  11. package/agents/examples/files-post-processing.md +10 -8
  12. package/agents/examples/golden-path.md +13 -1
  13. package/agents/examples/inbound-mail-triage.md +1 -0
  14. package/agents/examples/lane-routing.md +2 -1
  15. package/agents/examples/legal-pages.md +2 -2
  16. package/agents/examples/lifecycle-hooks.md +55 -2
  17. package/agents/examples/list-table-options.md +466 -0
  18. package/agents/examples/managed-config.md +4 -4
  19. package/agents/examples/managed-pages.md +1 -1
  20. package/agents/examples/pdf-audit-export.md +4 -2
  21. package/agents/examples/relations.md +19 -4
  22. package/agents/examples/search.md +4 -4
  23. package/agents/examples/secrets-demo.md +9 -6
  24. package/agents/examples/state-machine.md +5 -4
  25. package/agents/examples/tenant-isolation.md +73 -1
  26. package/agents/examples/tenant-settings.md +1 -1
  27. package/agents/examples/user-data-rights.md +3 -6
  28. package/agents/examples/workflow-engine.md +53 -47
  29. package/agents/examples.md +5 -4
  30. package/agents/features.md +1 -1
  31. package/agents/widgets.md +1 -0
  32. package/dist/api/api-constants.d.ts +1 -0
  33. package/dist/api/api-constants.js +2 -0
  34. package/dist/api/auth-middleware.js +1 -1
  35. package/dist/api/auth-routes-invite.js +2 -1
  36. package/dist/api/auth-routes-shared.d.ts +2 -0
  37. package/dist/api/auth-routes-shared.js +5 -0
  38. package/dist/api/client-error-route.js +2 -3
  39. package/dist/api/entity-read-access.d.ts +4 -1
  40. package/dist/api/entity-read-access.js +14 -0
  41. package/dist/api/export/export-cells-reference.d.ts +9 -0
  42. package/dist/api/export/export-cells-reference.js +21 -0
  43. package/dist/api/export/export-cells.d.ts +11 -0
  44. package/dist/api/export/export-cells.js +136 -0
  45. package/dist/api/export/export-ciphertext-guard.d.ts +2 -0
  46. package/dist/api/export/export-ciphertext-guard.js +27 -0
  47. package/dist/api/export/export-columns.d.ts +31 -0
  48. package/dist/api/export/export-columns.js +85 -0
  49. package/dist/api/export/export-errors.d.ts +4 -0
  50. package/dist/api/export/export-errors.js +14 -0
  51. package/dist/api/export/export-route.d.ts +4 -0
  52. package/dist/api/export/export-route.js +75 -0
  53. package/dist/api/export/export-rows.d.ts +13 -0
  54. package/dist/api/export/export-rows.js +62 -0
  55. package/dist/api/export/export-screen.d.ts +13 -0
  56. package/dist/api/export/export-screen.js +47 -0
  57. package/dist/api/export/export-xlsx-writer.d.ts +4 -0
  58. package/dist/api/export/export-xlsx-writer.js +21 -0
  59. package/dist/api/extra-route.d.ts +7 -1
  60. package/dist/api/index.d.ts +23 -27
  61. package/dist/api/index.js +13 -15
  62. package/dist/api/jwt.js +1 -1
  63. package/dist/api/observability-middleware.d.ts +1 -1
  64. package/dist/api/observability-middleware.js +2 -1
  65. package/dist/api/pii-leak-guard.d.ts +3 -0
  66. package/dist/api/pii-leak-guard.js +3 -2
  67. package/dist/api/request-context-internals.d.ts +31 -0
  68. package/dist/api/request-context-internals.js +11 -0
  69. package/dist/api/request-context-scopes.d.ts +14 -0
  70. package/dist/api/request-context-scopes.js +69 -0
  71. package/dist/api/request-context.d.ts +1 -40
  72. package/dist/api/request-context.js +22 -51
  73. package/dist/api/request-id-middleware.d.ts +1 -1
  74. package/dist/api/route-registrars.d.ts +2 -1
  75. package/dist/api/route-registrars.js +1 -1
  76. package/dist/api/routes.d.ts +16 -0
  77. package/dist/api/routes.js +9 -5
  78. package/dist/api/server-boot-checks.d.ts +1 -1
  79. package/dist/api/server-boot-checks.js +2 -2
  80. package/dist/api/server-event-dispatcher.d.ts +6 -1
  81. package/dist/api/server-event-dispatcher.js +3 -4
  82. package/dist/api/server-extra-routes.d.ts +1 -1
  83. package/dist/api/server-extra-routes.js +5 -1
  84. package/dist/api/server-middleware.js +3 -1
  85. package/dist/api/server-routes.d.ts +3 -2
  86. package/dist/api/server-routes.js +8 -2
  87. package/dist/api/server-wiring.js +8 -4
  88. package/dist/api/server.d.ts +2 -1
  89. package/dist/api/sse-route.d.ts +3 -1
  90. package/dist/api/sse-route.js +11 -1
  91. package/dist/api/tenant-scoped-secrets.d.ts +2 -0
  92. package/dist/api/tenant-scoped-secrets.js +13 -0
  93. package/dist/api/websocket-route.d.ts +1 -1
  94. package/dist/auth/index.d.ts +0 -1
  95. package/dist/auth/roles.d.ts +0 -5
  96. package/dist/compliance/duration-spec.d.ts +0 -1
  97. package/dist/compliance/duration-spec.js +0 -5
  98. package/dist/compliance/index.d.ts +4 -4
  99. package/dist/compliance/index.js +2 -2
  100. package/dist/compliance/profiles.d.ts +0 -15
  101. package/dist/compliance/profiles.js +0 -23
  102. package/dist/config/index.d.ts +11 -9
  103. package/dist/config/index.js +13 -1
  104. package/dist/config/internals.d.ts +9 -0
  105. package/dist/config/internals.js +1 -0
  106. package/dist/consumer-cli-internals.d.ts +4 -0
  107. package/dist/consumer-cli-internals.js +1 -0
  108. package/dist/consumer-cli.d.ts +1 -4
  109. package/dist/consumer-cli.js +5 -1
  110. package/dist/crypto/event-pii.js +1 -1
  111. package/dist/crypto/index.d.ts +8 -9
  112. package/dist/crypto/index.js +7 -8
  113. package/dist/crypto/pg-kms-adapter.d.ts +1 -0
  114. package/dist/crypto/pg-kms-adapter.js +17 -18
  115. package/dist/db/aggregate-sql.d.ts +2 -0
  116. package/dist/db/aggregate-sql.js +10 -0
  117. package/dist/db/apply-entity-event.d.ts +1 -1
  118. package/dist/db/apply-entity-event.js +15 -47
  119. package/dist/db/blind-index-cleanup.js +91 -77
  120. package/dist/db/closed-connection.js +12 -19
  121. package/dist/db/collect-table-metas.js +1 -1
  122. package/dist/db/compound-types.d.ts +1 -1
  123. package/dist/db/compound-types.js +0 -7
  124. package/dist/db/config-seed.d.ts +2 -1
  125. package/dist/db/config-seed.js +6 -1
  126. package/dist/db/connection.d.ts +7 -6
  127. package/dist/db/connection.js +43 -24
  128. package/dist/db/cross-tenant-reads.d.ts +1 -1
  129. package/dist/db/cross-tenant-reads.js +1 -1
  130. package/dist/db/dialect.d.ts +0 -5
  131. package/dist/db/dialect.js +0 -3
  132. package/dist/db/driver-row-coercion.js +4 -4
  133. package/dist/db/driver-value-preparation.js +6 -4
  134. package/dist/db/eagerload.d.ts +2 -1
  135. package/dist/db/entity-field-encryption.d.ts +1 -1
  136. package/dist/db/entity-table-meta.d.ts +1 -1
  137. package/dist/db/event-store-executor-context.d.ts +3 -1
  138. package/dist/db/event-store-executor-context.js +4 -3
  139. package/dist/db/event-store-executor-read-aggregate-currencies.d.ts +17 -0
  140. package/dist/db/event-store-executor-read-aggregate-currencies.js +40 -0
  141. package/dist/db/event-store-executor-read-aggregate.js +36 -5
  142. package/dist/db/event-store-executor-read-filter.d.ts +1 -1
  143. package/dist/db/event-store-executor-read-filter.js +6 -3
  144. package/dist/db/event-store-executor-read-rows.d.ts +2 -1
  145. package/dist/db/event-store-executor-read-search.d.ts +2 -1
  146. package/dist/db/event-store-executor-read-sort.d.ts +2 -1
  147. package/dist/db/event-store-executor-read.js +2 -2
  148. package/dist/db/event-store-executor-write-atomic.d.ts +4 -0
  149. package/dist/db/event-store-executor-write-atomic.js +42 -0
  150. package/dist/db/event-store-executor-write-steps.d.ts +3 -5
  151. package/dist/db/event-store-executor-write-steps.js +0 -5
  152. package/dist/db/event-store-executor-write.js +22 -19
  153. package/dist/db/event-store-executor.d.ts +1 -1
  154. package/dist/db/event-store-executor.js +2 -1
  155. package/dist/db/executor-managed-tables.d.ts +7 -1
  156. package/dist/db/executor-managed-tables.js +12 -3
  157. package/dist/db/index.d.ts +29 -28
  158. package/dist/db/index.js +22 -20
  159. package/dist/db/known-table-names.d.ts +6 -0
  160. package/dist/db/known-table-names.js +21 -0
  161. package/dist/db/list-aggregate-labels.d.ts +1 -1
  162. package/dist/db/located-timestamp.d.ts +1 -1
  163. package/dist/db/located-timestamp.js +0 -5
  164. package/dist/db/migrate-generator.d.ts +17 -1
  165. package/dist/db/migrate-generator.js +50 -20
  166. package/dist/db/migrate-primary-key.d.ts +12 -0
  167. package/dist/db/migrate-primary-key.js +45 -0
  168. package/dist/db/migrate-rls-diff.d.ts +20 -0
  169. package/dist/db/migrate-rls-diff.js +61 -0
  170. package/dist/db/migrate-runner.js +7 -3
  171. package/dist/db/money.d.ts +1 -1
  172. package/dist/db/money.js +1 -1
  173. package/dist/db/parent-ref-clause.d.ts +2 -1
  174. package/dist/db/pg-error.d.ts +2 -0
  175. package/dist/db/pg-error.js +37 -21
  176. package/dist/db/queries/backfill-pii.js +3 -6
  177. package/dist/db/queries/database-now.js +2 -1
  178. package/dist/db/queries/ddl.d.ts +3 -0
  179. package/dist/db/queries/ddl.js +34 -1
  180. package/dist/db/queries/event-store.js +4 -2
  181. package/dist/db/queries/event-tenants.d.ts +2 -0
  182. package/dist/db/queries/event-tenants.js +17 -0
  183. package/dist/db/queries/rebuild-rls-guard.d.ts +2 -0
  184. package/dist/db/queries/rebuild-rls-guard.js +29 -0
  185. package/dist/db/queries/rls-boot-catalog.d.ts +16 -0
  186. package/dist/db/queries/rls-boot-catalog.js +39 -0
  187. package/dist/db/queries/rls-catalog.d.ts +6 -0
  188. package/dist/db/queries/rls-catalog.js +82 -0
  189. package/dist/db/queries/rls-scope.d.ts +3 -0
  190. package/dist/db/queries/rls-scope.js +17 -0
  191. package/dist/db/queries/rls-shape.d.ts +10 -0
  192. package/dist/db/queries/rls-shape.js +42 -0
  193. package/dist/db/queries/session-advisory-lock.d.ts +2 -0
  194. package/dist/db/queries/session-advisory-lock.js +23 -0
  195. package/dist/db/queries/shadow-swap.d.ts +1 -2
  196. package/dist/db/queries/shadow-swap.js +11 -28
  197. package/dist/db/queries/test-stack.d.ts +4 -1
  198. package/dist/db/queries/test-stack.js +83 -2
  199. package/dist/db/query.d.ts +14 -0
  200. package/dist/db/query.js +77 -48
  201. package/dist/db/reference-data.d.ts +1 -1
  202. package/dist/db/reference-data.js +20 -3
  203. package/dist/db/render-ddl.d.ts +6 -2
  204. package/dist/db/render-ddl.js +7 -7
  205. package/dist/db/render-rls-ddl.d.ts +35 -0
  206. package/dist/db/render-rls-ddl.js +127 -0
  207. package/dist/db/replay-migration-sql.d.ts +3 -1
  208. package/dist/db/replay-migration-sql.js +22 -5
  209. package/dist/db/replay-rls.d.ts +25 -0
  210. package/dist/db/replay-rls.js +156 -0
  211. package/dist/db/row-level-security-boot-check.d.ts +5 -0
  212. package/dist/db/row-level-security-boot-check.js +85 -0
  213. package/dist/db/row-level-security-connection.d.ts +3 -0
  214. package/dist/db/row-level-security-connection.js +213 -0
  215. package/dist/db/row-level-security-scope.d.ts +33 -0
  216. package/dist/db/row-level-security-scope.js +127 -0
  217. package/dist/db/scope-tenant-db-to-tenant.d.ts +3 -0
  218. package/dist/db/scope-tenant-db-to-tenant.js +14 -0
  219. package/dist/db/sql-identifier.d.ts +1 -0
  220. package/dist/db/sql-identifier.js +3 -0
  221. package/dist/db/statement-timeout.js +2 -1
  222. package/dist/db/table-builder.d.ts +2 -1
  223. package/dist/db/table-builder.js +1 -1
  224. package/dist/db/table-info.js +1 -1
  225. package/dist/db/table-push.d.ts +11 -2
  226. package/dist/db/table-push.js +15 -2
  227. package/dist/db/tenant-db-runner.d.ts +3 -1
  228. package/dist/db/tenant-db-runner.js +4 -3
  229. package/dist/db/tenant-db-scoped-rebind.d.ts +10 -0
  230. package/dist/db/tenant-db-scoped-rebind.js +33 -0
  231. package/dist/db/tenant-db-statement-runner.d.ts +13 -0
  232. package/dist/db/tenant-db-statement-runner.js +48 -0
  233. package/dist/db/tenant-db-upsert.d.ts +5 -0
  234. package/dist/db/tenant-db-upsert.js +91 -0
  235. package/dist/db/tenant-db.d.ts +17 -12
  236. package/dist/db/tenant-db.js +60 -121
  237. package/dist/db/tenant-id-filter.d.ts +3 -0
  238. package/dist/db/tenant-id-filter.js +30 -0
  239. package/dist/db/transaction-serialization.d.ts +6 -0
  240. package/dist/db/transaction-serialization.js +60 -0
  241. package/dist/derivatives/delete-stored-file.js +1 -1
  242. package/dist/derivatives/index.d.ts +2 -5
  243. package/dist/derivatives/index.js +2 -3
  244. package/dist/engine/access.d.ts +2 -1
  245. package/dist/engine/access.js +1 -1
  246. package/dist/engine/boot-validator/bundled-lists-table.d.ts +2 -0
  247. package/dist/engine/boot-validator/bundled-lists-table.js +36 -0
  248. package/dist/engine/boot-validator/entity-handler.d.ts +2 -1
  249. package/dist/engine/boot-validator/entity-handler.js +1 -1
  250. package/dist/engine/boot-validator/entity-list-aggregate-options.d.ts +3 -0
  251. package/dist/engine/boot-validator/entity-list-aggregate-options.js +23 -0
  252. package/dist/engine/boot-validator/list-bulk-actions.d.ts +3 -0
  253. package/dist/engine/boot-validator/list-bulk-actions.js +49 -0
  254. package/dist/engine/boot-validator/list-column-layout.d.ts +8 -0
  255. package/dist/engine/boot-validator/list-column-layout.js +41 -0
  256. package/dist/engine/boot-validator/list-table-aggregate-options.d.ts +24 -0
  257. package/dist/engine/boot-validator/list-table-aggregate-options.js +145 -0
  258. package/dist/engine/boot-validator/list-table-aggregate-query.d.ts +11 -0
  259. package/dist/engine/boot-validator/list-table-aggregate-query.js +31 -0
  260. package/dist/engine/boot-validator/list-table-export-options.d.ts +1 -0
  261. package/dist/engine/boot-validator/list-table-export-options.js +27 -0
  262. package/dist/engine/boot-validator/list-table-options.d.ts +3 -0
  263. package/dist/engine/boot-validator/list-table-options.js +77 -0
  264. package/dist/engine/boot-validator/list-table-reject-unknown-keys.d.ts +1 -0
  265. package/dist/engine/boot-validator/list-table-reject-unknown-keys.js +7 -0
  266. package/dist/engine/boot-validator/nav.d.ts +3 -1
  267. package/dist/engine/boot-validator/nav.js +1 -1
  268. package/dist/engine/boot-validator/ownership.d.ts +2 -1
  269. package/dist/engine/boot-validator/parent-ref.d.ts +2 -1
  270. package/dist/engine/boot-validator/projection-list-screens.d.ts +2 -1
  271. package/dist/engine/boot-validator/projection-list-screens.js +3 -13
  272. package/dist/engine/boot-validator/query-refs.d.ts +2 -1
  273. package/dist/engine/boot-validator/related-list-table-rules.d.ts +4 -0
  274. package/dist/engine/boot-validator/related-list-table-rules.js +42 -0
  275. package/dist/engine/boot-validator/screens-forms.d.ts +2 -1
  276. package/dist/engine/boot-validator/screens-kind-entity-list.js +7 -0
  277. package/dist/engine/boot-validator/screens-kind-projection-list.js +4 -0
  278. package/dist/engine/boot-validator/screens-kind-shared.d.ts +3 -1
  279. package/dist/engine/boot-validator/screens-lists.js +12 -2
  280. package/dist/engine/boot-validator/screens.d.ts +2 -1
  281. package/dist/engine/boot-validator/workspaces.d.ts +3 -1
  282. package/dist/engine/bridge-stub.d.ts +5 -2
  283. package/dist/engine/bridge-stub.js +39 -24
  284. package/dist/engine/build-app-schema.d.ts +2 -1
  285. package/dist/engine/build-app-schema.js +9 -1
  286. package/dist/engine/build-config-feature-schema.js +6 -1
  287. package/dist/engine/config-helpers.d.ts +2 -2
  288. package/dist/engine/config-helpers.js +0 -9
  289. package/dist/engine/constants.d.ts +0 -10
  290. package/dist/engine/constants.js +0 -8
  291. package/dist/engine/create-app.js +1 -1
  292. package/dist/engine/define-feature.d.ts +2 -1
  293. package/dist/engine/define-feature.js +5 -2
  294. package/dist/engine/define-handler.d.ts +1 -1
  295. package/dist/engine/define-step.d.ts +0 -1
  296. package/dist/engine/define-step.js +0 -3
  297. package/dist/engine/embedded-derived.d.ts +1 -1
  298. package/dist/engine/entity-handlers.d.ts +2 -1
  299. package/dist/engine/entity-handlers.js +7 -7
  300. package/dist/engine/entity-list-runtime-options.js +3 -1
  301. package/dist/engine/entity-list-searchability.d.ts +2 -1
  302. package/dist/engine/event-def.d.ts +2 -1
  303. package/dist/engine/event-helpers.d.ts +3 -1
  304. package/dist/engine/event-helpers.js +3 -3
  305. package/dist/engine/extension-names.d.ts +2 -8
  306. package/dist/engine/extension-names.js +2 -2
  307. package/dist/engine/extension-selector-plugins.d.ts +1 -1
  308. package/dist/engine/extensions/storage-provider.d.ts +1 -2
  309. package/dist/engine/extensions/user-data.d.ts +0 -8
  310. package/dist/engine/factories.d.ts +2 -1
  311. package/dist/engine/feature-builder-state.d.ts +9 -1
  312. package/dist/engine/feature-builder-state.js +1 -0
  313. package/dist/engine/feature-changelog.d.ts +1 -1
  314. package/dist/engine/feature-config-events-jobs.d.ts +4 -1
  315. package/dist/engine/feature-entity-handlers.d.ts +5 -1
  316. package/dist/engine/feature-manifest.d.ts +1 -0
  317. package/dist/engine/feature-manifest.js +2 -1
  318. package/dist/engine/feature-ui-extensions.d.ts +7 -1
  319. package/dist/engine/feature-ui-extensions.js +6 -4
  320. package/dist/engine/field-access.d.ts +3 -1
  321. package/dist/engine/field-access.js +12 -0
  322. package/dist/engine/handler-field-references.d.ts +0 -4
  323. package/dist/engine/index.d.ts +58 -55
  324. package/dist/engine/index.js +23 -28
  325. package/dist/engine/instruction-fields.d.ts +1 -1
  326. package/dist/engine/personal-data-fields.d.ts +1 -1
  327. package/dist/engine/qualified-name.d.ts +0 -1
  328. package/dist/engine/read-claim.d.ts +2 -1
  329. package/dist/engine/registry-facade.js +0 -3
  330. package/dist/engine/registry-ingest.d.ts +2 -1
  331. package/dist/engine/registry-ingest.js +1 -2
  332. package/dist/engine/registry-state.d.ts +12 -2
  333. package/dist/engine/registry-state.js +2 -3
  334. package/dist/engine/registry-validate.d.ts +3 -1
  335. package/dist/engine/registry-validate.js +7 -7
  336. package/dist/engine/run-in.d.ts +1 -1
  337. package/dist/engine/run-in.js +0 -1
  338. package/dist/engine/schema-builder.d.ts +1 -1
  339. package/dist/engine/schema-builder.js +1 -1
  340. package/dist/engine/screen-filter-ops.d.ts +2 -1
  341. package/dist/engine/screen-filter-ops.js +2 -5
  342. package/dist/engine/soft-delete-cleanup.d.ts +1 -1
  343. package/dist/engine/soft-delete-cleanup.js +4 -4
  344. package/dist/engine/state-machine.js +2 -1
  345. package/dist/engine/steps/_read-source.js +1 -1
  346. package/dist/engine/steps/aggregate-append-event.js +2 -2
  347. package/dist/engine/steps/call-feature.js +2 -2
  348. package/dist/engine/steps/mail-send.js +1 -1
  349. package/dist/engine/steps/retry.js +1 -1
  350. package/dist/engine/steps/wait-for-event.js +1 -1
  351. package/dist/engine/steps/wait.js +1 -1
  352. package/dist/engine/steps/webhook-send.js +1 -1
  353. package/dist/engine/strip-disabled-features-from-app-schema.js +7 -3
  354. package/dist/engine/template-variables.d.ts +2 -1
  355. package/dist/engine/transfer-adjacency.d.ts +1 -1
  356. package/dist/engine/types/feature.d.ts +1 -0
  357. package/dist/engine/types/index.d.ts +8 -30
  358. package/dist/engine/types/index.js +2 -10
  359. package/dist/engine/types/screen.d.ts +1 -1
  360. package/dist/engine/types/screen.js +1 -1
  361. package/dist/engine/validation.d.ts +2 -1
  362. package/dist/entrypoint/index.d.ts +9 -35
  363. package/dist/entrypoint/index.js +10 -1
  364. package/dist/entrypoint/internals.d.ts +40 -0
  365. package/dist/entrypoint/internals.js +1 -0
  366. package/dist/entrypoint/row-level-security-mode-check.d.ts +3 -0
  367. package/dist/entrypoint/row-level-security-mode-check.js +19 -0
  368. package/dist/env/dry-run-internals.d.ts +10 -0
  369. package/dist/env/dry-run-internals.js +1 -0
  370. package/dist/env/dry-run.d.ts +1 -10
  371. package/dist/env/dry-run.js +2 -1
  372. package/dist/env/index.d.ts +1 -85
  373. package/dist/env/index.js +6 -50
  374. package/dist/env/internals.d.ts +87 -0
  375. package/dist/env/internals.js +53 -0
  376. package/dist/errors/classes.js +2 -2
  377. package/dist/errors/index.d.ts +5 -14
  378. package/dist/errors/index.js +4 -9
  379. package/dist/errors/member-resolution.js +1 -1
  380. package/dist/errors/reasons.d.ts +0 -1
  381. package/dist/errors/reasons.js +7 -7
  382. package/dist/errors/serialize.d.ts +0 -18
  383. package/dist/errors/serialize.js +0 -27
  384. package/dist/es-ops/index.d.ts +4 -4
  385. package/dist/es-ops/index.js +2 -2
  386. package/dist/es-ops/operations-schema.d.ts +1 -1
  387. package/dist/es-ops/types.d.ts +4 -5
  388. package/dist/event-store/admin-api-internals.d.ts +14 -0
  389. package/dist/event-store/admin-api-internals.js +1 -0
  390. package/dist/event-store/admin-api.d.ts +1 -14
  391. package/dist/event-store/admin-api.js +11 -6
  392. package/dist/event-store/archive.js +4 -2
  393. package/dist/event-store/errors.js +2 -2
  394. package/dist/event-store/event-store.d.ts +1 -0
  395. package/dist/event-store/event-store.js +42 -32
  396. package/dist/event-store/events-schema.js +4 -1
  397. package/dist/event-store/index.d.ts +11 -13
  398. package/dist/event-store/index.js +7 -9
  399. package/dist/event-store/provenance-append.js +1 -1
  400. package/dist/event-store/rebuild-dead-letter.js +4 -2
  401. package/dist/event-store/snapshot.js +4 -3
  402. package/dist/event-store/stream-scope.d.ts +2 -0
  403. package/dist/event-store/stream-scope.js +6 -0
  404. package/dist/event-store/upcaster-dead-letter.js +4 -2
  405. package/dist/event-store/upcaster.d.ts +2 -1
  406. package/dist/files/action-form-upload.d.ts +2 -1
  407. package/dist/files/action-form-upload.js +1 -1
  408. package/dist/files/assert-file-refs-belong-to-tenant.d.ts +2 -1
  409. package/dist/files/assert-file-refs-belong-to-tenant.js +1 -1
  410. package/dist/files/bind-pending-file-refs.d.ts +2 -1
  411. package/dist/files/bind-pending-file-refs.js +2 -1
  412. package/dist/files/bind-referenced-files.write.js +1 -1
  413. package/dist/files/create-file-ref-from-bytes.d.ts +6 -3
  414. package/dist/files/create-file-ref-from-bytes.js +6 -3
  415. package/dist/files/create-file-ref.d.ts +6 -2
  416. package/dist/files/create-file-ref.js +13 -4
  417. package/dist/files/dispose-removed-file-refs.d.ts +2 -1
  418. package/dist/files/dispose-removed-file-refs.js +1 -1
  419. package/dist/files/feature.js +2 -2
  420. package/dist/files/file-handle.js +1 -1
  421. package/dist/files/file-routes.d.ts +3 -1
  422. package/dist/files/file-routes.js +41 -4
  423. package/dist/files/index.d.ts +11 -13
  424. package/dist/files/index.js +5 -7
  425. package/dist/files/load-save-file-refs.d.ts +2 -1
  426. package/dist/files/load-save-file-refs.js +1 -1
  427. package/dist/files/provider-resolver.d.ts +6 -4
  428. package/dist/files/provider-resolver.js +5 -5
  429. package/dist/files/record-write-check.d.ts +6 -0
  430. package/dist/files/record-write-check.js +13 -0
  431. package/dist/files/storage-tracking.js +4 -2
  432. package/dist/files/sweep-orphaned-uploads.d.ts +1 -1
  433. package/dist/files/sweep-orphaned-uploads.js +1 -1
  434. package/dist/files/upload-ledger.d.ts +2 -2
  435. package/dist/files/upload-ledger.js +4 -4
  436. package/dist/i18n/index.d.ts +2 -8
  437. package/dist/i18n/index.js +1 -1
  438. package/dist/i18n/internals.d.ts +7 -0
  439. package/dist/i18n/internals.js +1 -0
  440. package/dist/i18n/required-surface-keys.d.ts +4 -1
  441. package/dist/i18n/required-surface-keys.js +7 -2
  442. package/dist/internal/row-level-security.d.ts +3 -0
  443. package/dist/internal/row-level-security.js +3 -0
  444. package/dist/internal/stack-support.d.ts +1 -1
  445. package/dist/internal/stack-support.js +1 -1
  446. package/dist/internal/testing.d.ts +1 -0
  447. package/dist/internal/testing.js +10 -6
  448. package/dist/jobs/index.d.ts +1 -1
  449. package/dist/jobs/job-append-event.d.ts +12 -0
  450. package/dist/jobs/job-append-event.js +30 -0
  451. package/dist/jobs/job-runner-context.d.ts +2 -2
  452. package/dist/jobs/job-runner-context.js +46 -16
  453. package/dist/jobs/job-runner-execution.d.ts +1 -1
  454. package/dist/jobs/job-runner-execution.js +6 -4
  455. package/dist/jobs/job-runner-gates.d.ts +1 -1
  456. package/dist/jobs/job-runner-gates.js +0 -1
  457. package/dist/jobs/job-runner-helpers.d.ts +11 -4
  458. package/dist/jobs/job-runner-helpers.js +10 -1
  459. package/dist/jobs/job-runner-scope.d.ts +5 -2
  460. package/dist/jobs/job-runner-scope.js +6 -6
  461. package/dist/jobs/job-runner-types.d.ts +2 -1
  462. package/dist/jobs/job-runner.js +22 -6
  463. package/dist/jobs/max-per-tenant.d.ts +1 -1
  464. package/dist/logging/index.d.ts +1 -2
  465. package/dist/logging/index.js +1 -1
  466. package/dist/logging/pino-logger.js +1 -1
  467. package/dist/logging/utils.d.ts +1 -0
  468. package/dist/logging/utils.js +6 -0
  469. package/dist/migrations/index.d.ts +3 -3
  470. package/dist/migrations/index.js +3 -3
  471. package/dist/migrations/pending-rebuilds.d.ts +1 -1
  472. package/dist/migrations/pending-rebuilds.js +1 -1
  473. package/dist/migrations/pii-event-backfill.js +4 -1
  474. package/dist/observability/escape-hatch-report.d.ts +2 -1
  475. package/dist/observability/escape-hatch-report.js +9 -2
  476. package/dist/observability/index.d.ts +7 -15
  477. package/dist/observability/index.js +4 -12
  478. package/dist/observability/metric-validator.js +1 -1
  479. package/dist/observability/metrics-handle.d.ts +0 -1
  480. package/dist/observability/metrics-handle.js +2 -15
  481. package/dist/observability/recording-tracer.d.ts +1 -2
  482. package/dist/observability/recording-tracer.js +0 -6
  483. package/dist/observability/sensitive-filter.d.ts +0 -2
  484. package/dist/observability/sensitive-filter.js +0 -29
  485. package/dist/pipeline/active-membership.d.ts +2 -1
  486. package/dist/pipeline/active-membership.js +6 -2
  487. package/dist/pipeline/after-rollback-sink.d.ts +6 -0
  488. package/dist/pipeline/after-rollback-sink.js +32 -0
  489. package/dist/pipeline/append-event-core.d.ts +2 -1
  490. package/dist/pipeline/append-event-core.js +2 -2
  491. package/dist/pipeline/attach-outside-transaction.d.ts +3 -0
  492. package/dist/pipeline/attach-outside-transaction.js +13 -0
  493. package/dist/pipeline/auth-claims-resolver.d.ts +2 -1
  494. package/dist/pipeline/cascade-handler.d.ts +2 -1
  495. package/dist/pipeline/cascade-handler.js +3 -2
  496. package/dist/pipeline/config-accessor-factory.d.ts +1 -1
  497. package/dist/pipeline/config-accessor-factory.js +1 -1
  498. package/dist/pipeline/context-services.d.ts +56 -0
  499. package/dist/pipeline/context-services.js +73 -0
  500. package/dist/pipeline/dispatch-batch.d.ts +2 -1
  501. package/dist/pipeline/dispatch-batch.js +39 -19
  502. package/dist/pipeline/dispatch-query.js +5 -4
  503. package/dist/pipeline/dispatch-scope.d.ts +6 -0
  504. package/dist/pipeline/dispatch-scope.js +27 -0
  505. package/dist/pipeline/dispatch-shared.d.ts +13 -9
  506. package/dist/pipeline/dispatch-shared.js +75 -194
  507. package/dist/pipeline/dispatch-stream.js +8 -4
  508. package/dist/pipeline/dispatch-write.d.ts +2 -1
  509. package/dist/pipeline/dispatch-write.js +10 -8
  510. package/dist/pipeline/dispatcher-utils.d.ts +3 -1
  511. package/dist/pipeline/dispatcher-utils.js +8 -2
  512. package/dist/pipeline/dispatcher.d.ts +3 -2
  513. package/dist/pipeline/dispatcher.js +4 -3
  514. package/dist/pipeline/event-consumer-state.d.ts +0 -1
  515. package/dist/pipeline/event-dispatcher-delivery.d.ts +1 -1
  516. package/dist/pipeline/event-dispatcher-delivery.js +7 -3
  517. package/dist/pipeline/event-dispatcher.d.ts +3 -2
  518. package/dist/pipeline/event-dispatcher.js +13 -12
  519. package/dist/pipeline/event-retention.js +59 -56
  520. package/dist/pipeline/handler-access-error.js +2 -1
  521. package/dist/pipeline/handler-context-auth.d.ts +5 -6
  522. package/dist/pipeline/handler-context-auth.js +7 -4
  523. package/dist/pipeline/handler-context-config.d.ts +2 -5
  524. package/dist/pipeline/handler-context-config.js +2 -2
  525. package/dist/pipeline/handler-context-db.d.ts +32 -7
  526. package/dist/pipeline/handler-context-db.js +26 -17
  527. package/dist/pipeline/handler-context-dispatch.d.ts +14 -6
  528. package/dist/pipeline/handler-context-dispatch.js +18 -5
  529. package/dist/pipeline/handler-context-events.d.ts +22 -38
  530. package/dist/pipeline/handler-context-events.js +42 -35
  531. package/dist/pipeline/handler-context-member-resolution.d.ts +2 -0
  532. package/dist/pipeline/handler-context-member-resolution.js +110 -0
  533. package/dist/pipeline/handler-context-notify.d.ts +3 -2
  534. package/dist/pipeline/handler-context-notify.js +1 -1
  535. package/dist/pipeline/handler-context-observability.d.ts +2 -4
  536. package/dist/pipeline/handler-context-observability.js +7 -5
  537. package/dist/pipeline/handler-context-phase-denials.d.ts +11 -0
  538. package/dist/pipeline/handler-context-phase-denials.js +98 -0
  539. package/dist/pipeline/handler-context-scope.d.ts +7 -10
  540. package/dist/pipeline/handler-context-scope.js +18 -20
  541. package/dist/pipeline/index.d.ts +9 -21
  542. package/dist/pipeline/index.js +5 -7
  543. package/dist/pipeline/irreversible-operation-gate.d.ts +1 -1
  544. package/dist/pipeline/irreversible-operation-gate.js +2 -2
  545. package/dist/pipeline/lifecycle-pipeline.d.ts +8 -7
  546. package/dist/pipeline/lifecycle-pipeline.js +9 -15
  547. package/dist/pipeline/member-read-only-transaction.js +11 -3
  548. package/dist/pipeline/member-reader.d.ts +1 -1
  549. package/dist/pipeline/member-reader.js +2 -2
  550. package/dist/pipeline/msp-rebuild.js +5 -3
  551. package/dist/pipeline/multi-stream-apply-context.js +3 -2
  552. package/dist/pipeline/notify-scope.d.ts +2 -1
  553. package/dist/pipeline/pre-handler-gates.d.ts +2 -1
  554. package/dist/pipeline/pre-transaction-reservations.d.ts +3 -3
  555. package/dist/pipeline/pre-transaction-reservations.js +9 -7
  556. package/dist/pipeline/projection-rebuild.js +12 -5
  557. package/dist/pipeline/projection-state.d.ts +0 -6
  558. package/dist/pipeline/projection-state.js +0 -5
  559. package/dist/pipeline/projections-runner.d.ts +2 -1
  560. package/dist/pipeline/projections-runner.js +10 -6
  561. package/dist/pipeline/system-hooks.d.ts +6 -2
  562. package/dist/pipeline/system-hooks.js +61 -10
  563. package/dist/pipeline/system-identity-switch.d.ts +4 -2
  564. package/dist/pipeline/system-identity-switch.js +51 -36
  565. package/dist/pipeline/typed-append-event.d.ts +2 -0
  566. package/dist/pipeline/typed-append-event.js +4 -0
  567. package/dist/pipeline/write-origin.js +2 -2
  568. package/dist/pipeline/write-result-masking.d.ts +1 -1
  569. package/dist/pipeline/write-result-masking.js +13 -10
  570. package/dist/random/index.d.ts +1 -2
  571. package/dist/random/index.js +1 -2
  572. package/dist/rate-limit/bucket.d.ts +2 -1
  573. package/dist/rate-limit/middleware.js +2 -1
  574. package/dist/redis/index.d.ts +3 -4
  575. package/dist/redis/index.js +2 -2
  576. package/dist/schema-cli/apply-command.js +5 -2
  577. package/dist/schema-cli/baseline-command.js +7 -2
  578. package/dist/schema-cli/generate-command.js +7 -9
  579. package/dist/schema-cli/shared.d.ts +4 -0
  580. package/dist/schema-cli/shared.js +21 -2
  581. package/dist/schema-cli/status-command.js +8 -2
  582. package/dist/schema-cli/validate-command.js +52 -4
  583. package/dist/schema-cli.d.ts +0 -1
  584. package/dist/search/configure-tenant-index.d.ts +1 -3
  585. package/dist/search/configure-tenant-index.js +0 -4
  586. package/dist/search/index.d.ts +1 -4
  587. package/dist/search/index.js +0 -2
  588. package/dist/search/meilisearch-adapter-internals.d.ts +8 -0
  589. package/dist/search/meilisearch-adapter-internals.js +9 -0
  590. package/dist/search/meilisearch-adapter.d.ts +1 -8
  591. package/dist/search/meilisearch-adapter.js +6 -7
  592. package/dist/search/meilisearch-peer.d.ts +2 -0
  593. package/dist/search/meilisearch-peer.js +5 -0
  594. package/dist/search/reindex-entity.js +107 -91
  595. package/dist/secrets/index.d.ts +3 -4
  596. package/dist/secrets/index.js +2 -3
  597. package/dist/seeding/index.d.ts +2 -2
  598. package/dist/seeding/index.js +1 -2
  599. package/dist/time/index.d.ts +2 -2
  600. package/dist/time/index.js +1 -1
  601. package/dist/time/tz-context.d.ts +0 -5
  602. package/dist/time/tz-context.js +0 -9
  603. package/dist/ui-types/index.d.ts +8 -11
  604. package/dist/ui-types/index.js +3 -3
  605. package/dist/upgrade-changelog.d.ts +3 -0
  606. package/dist/upgrade-changelog.js +18 -0
  607. package/dist/upgrade-cli-internals.d.ts +8 -0
  608. package/dist/upgrade-cli-internals.js +63 -0
  609. package/dist/upgrade-cli.d.ts +1 -18
  610. package/dist/upgrade-cli.js +29 -137
  611. package/dist/upgrade-marker-parse.d.ts +32 -0
  612. package/dist/upgrade-marker-parse.js +73 -0
  613. package/dist/utils/import-optional-peer.d.ts +6 -0
  614. package/dist/utils/import-optional-peer.js +19 -0
  615. package/dist/utils/index.d.ts +1 -4
  616. package/dist/utils/index.js +1 -4
  617. package/package.json +27 -20
  618. package/src/changes.json +451 -0
  619. package/dist/crypto/request-kms-cache.d.ts +0 -8
  620. package/dist/crypto/request-kms-cache.js +0 -21
  621. package/dist/engine/codemod/index.d.ts +0 -2
  622. package/dist/engine/codemod/index.js +0 -1
  623. package/dist/engine/codemod/pipeline-codemod.d.ts +0 -50
  624. package/dist/engine/codemod/pipeline-codemod.js +0 -536
  625. package/dist/engine/feature-ast/entity-field-types.d.ts +0 -13
  626. package/dist/engine/feature-ast/entity-field-types.js +0 -35
  627. package/dist/engine/feature-ast/extractors/ai-steps.d.ts +0 -6
  628. package/dist/engine/feature-ast/extractors/ai-steps.js +0 -254
  629. package/dist/engine/feature-ast/extractors/events.d.ts +0 -5
  630. package/dist/engine/feature-ast/extractors/events.js +0 -275
  631. package/dist/engine/feature-ast/extractors/handlers.d.ts +0 -24
  632. package/dist/engine/feature-ast/extractors/handlers.js +0 -358
  633. package/dist/engine/feature-ast/extractors/hooks.d.ts +0 -24
  634. package/dist/engine/feature-ast/extractors/hooks.js +0 -248
  635. package/dist/engine/feature-ast/extractors/index.d.ts +0 -14
  636. package/dist/engine/feature-ast/extractors/index.js +0 -13
  637. package/dist/engine/feature-ast/extractors/jobs-routes.d.ts +0 -7
  638. package/dist/engine/feature-ast/extractors/jobs-routes.js +0 -145
  639. package/dist/engine/feature-ast/extractors/projections-screens.d.ts +0 -10
  640. package/dist/engine/feature-ast/extractors/projections-screens.js +0 -195
  641. package/dist/engine/feature-ast/extractors/resolve-import.d.ts +0 -21
  642. package/dist/engine/feature-ast/extractors/resolve-import.js +0 -180
  643. package/dist/engine/feature-ast/extractors/round1.d.ts +0 -10
  644. package/dist/engine/feature-ast/extractors/round1.js +0 -81
  645. package/dist/engine/feature-ast/extractors/round2.d.ts +0 -7
  646. package/dist/engine/feature-ast/extractors/round2.js +0 -191
  647. package/dist/engine/feature-ast/extractors/round3.d.ts +0 -23
  648. package/dist/engine/feature-ast/extractors/round3.js +0 -292
  649. package/dist/engine/feature-ast/extractors/round5.d.ts +0 -9
  650. package/dist/engine/feature-ast/extractors/round5.js +0 -68
  651. package/dist/engine/feature-ast/extractors/round6.d.ts +0 -4
  652. package/dist/engine/feature-ast/extractors/round6.js +0 -17
  653. package/dist/engine/feature-ast/extractors/shared.d.ts +0 -94
  654. package/dist/engine/feature-ast/extractors/shared.js +0 -343
  655. package/dist/engine/feature-ast/index.d.ts +0 -16
  656. package/dist/engine/feature-ast/index.js +0 -10
  657. package/dist/engine/feature-ast/parse.d.ts +0 -31
  658. package/dist/engine/feature-ast/parse.js +0 -483
  659. package/dist/engine/feature-ast/patch.d.ts +0 -210
  660. package/dist/engine/feature-ast/patch.js +0 -610
  661. package/dist/engine/feature-ast/patcher.d.ts +0 -217
  662. package/dist/engine/feature-ast/patcher.js +0 -281
  663. package/dist/engine/feature-ast/pattern-change-schema.d.ts +0 -1476
  664. package/dist/engine/feature-ast/pattern-change-schema.js +0 -1226
  665. package/dist/engine/feature-ast/pattern-id-matchers.d.ts +0 -7
  666. package/dist/engine/feature-ast/pattern-id-matchers.js +0 -210
  667. package/dist/engine/feature-ast/patterns.d.ts +0 -318
  668. package/dist/engine/feature-ast/patterns.js +0 -106
  669. package/dist/engine/feature-ast/render.d.ts +0 -47
  670. package/dist/engine/feature-ast/render.js +0 -662
  671. package/dist/engine/feature-ast/source-location.d.ts +0 -17
  672. package/dist/engine/feature-ast/source-location.js +0 -27
  673. package/dist/engine/pattern-library/index.d.ts +0 -2
  674. package/dist/engine/pattern-library/index.js +0 -3
  675. package/dist/engine/pattern-library/library.d.ts +0 -14
  676. package/dist/engine/pattern-library/library.js +0 -93
  677. package/dist/engine/pattern-library/mixed-schemas.d.ts +0 -16
  678. package/dist/engine/pattern-library/mixed-schemas.js +0 -559
  679. package/dist/engine/pattern-library/opaque-schemas.d.ts +0 -7
  680. package/dist/engine/pattern-library/opaque-schemas.js +0 -115
  681. package/dist/engine/pattern-library/shared-fields.d.ts +0 -122
  682. package/dist/engine/pattern-library/shared-fields.js +0 -88
  683. package/dist/engine/pattern-library/static-schemas.d.ts +0 -20
  684. package/dist/engine/pattern-library/static-schemas.js +0 -478
  685. package/dist/engine/pattern-library/types.d.ts +0 -158
  686. package/dist/engine/pattern-library/types.js +0 -36
  687. package/dist/engine/provider-plugin-context.d.ts +0 -3
  688. package/dist/engine/provider-plugin-context.js +0 -28
  689. package/dist/engine/resolve-config-or-param.d.ts +0 -18
  690. package/dist/engine/resolve-config-or-param.js +0 -76
  691. package/src/scripts/codemod/README.md +0 -187
  692. package/src/scripts/codemod/codemod-support.ts +0 -334
  693. package/src/scripts/codemod/collect-source-files.ts +0 -48
  694. package/src/scripts/codemod/crypto-shredding-testing-move.ts +0 -119
  695. package/src/scripts/codemod/db-factory.ts +0 -810
  696. package/src/scripts/codemod/feature-factory.ts +0 -429
  697. package/src/scripts/codemod/feature-layout.ts +0 -424
  698. package/src/scripts/codemod/import-extensions.ts +0 -118
  699. package/src/scripts/codemod/migrate-cross-tenant.ts +0 -328
  700. package/src/scripts/codemod/migrate-db-raw.ts +0 -401
  701. package/src/scripts/codemod/migrate-open-to-all.ts +0 -235
  702. package/src/scripts/codemod/object-form.ts +0 -746
  703. package/src/scripts/codemod/package-merge.ts +0 -299
  704. package/src/scripts/codemod/pii-personal-migration.ts +0 -816
  705. package/src/scripts/codemod/remove-engine-payload-casts.ts +0 -318
  706. package/src/scripts/codemod/s3-imports.ts +0 -236
  707. package/src/scripts/codemod/tenant-db-options.ts +0 -454
  708. package/src/scripts/codemod/testing-injection.ts +0 -215
  709. package/src/scripts/codemod/testing-move-targets.ts +0 -161
  710. package/src/scripts/codemod/testing-move.ts +0 -542
  711. package/src/scripts/codemod/unprocessable-error-details-reason.ts +0 -411
@@ -4,13 +4,13 @@ import { parseJsonSafe } from "../utils/safe-json.js";
4
4
  import { isTemporalInstant, isTemporalPlainDate } from "./temporal-value-guards.js";
5
5
  // --- Value coercion at the driver boundary ------------------------------
6
6
  //
7
- // postgres-js returns timestamptz as JS Date (or ISO string depending on
7
+ // The driver returns timestamptz as JS Date (or ISO string depending on
8
8
  // driver config). Framework contract says timestamptz surfaces as
9
9
  // Temporal.Instant — without coercion every read hands callers a Date and
10
10
  // downstream code that does .epochMilliseconds / .add(...) crashes.
11
11
  //
12
- // Symmetric on write: Temporal.Instant doesn't bind directly into postgres-js
13
- // params — convert to ISO string when the column pgType is timestamptz.
12
+ // Symmetric on write: Temporal.Instant doesn't bind directly as a driver
13
+ // param — convert to ISO string when the column pgType is timestamptz.
14
14
  // Postgres bigint → JS: safe integers become `number` (matches createBigIntField /
15
15
  // drizzle mode:"number"); values outside ±2^53 stay `bigint` (money cents, raw
16
16
  // unmanaged columns). Uses BigInt equality check so 9007199254740993n never
@@ -72,7 +72,7 @@ function instantFromDriver(value) {
72
72
  // the day, so say so once per column instead of returning the wrong day quietly.
73
73
  const warnedNonMidnightDateColumns = new Set();
74
74
  const MS_PER_DAY = 86_400_000;
75
- const dateColumnDriftLog = createFallbackLogger("postgres-js");
75
+ const dateColumnDriftLog = createFallbackLogger("bun-sql");
76
76
  function warnIfNotDateColumn(epochMs, column) {
77
77
  // skip: midnight value is a correct date column, and an already-warned column is deduped
78
78
  if (epochMs % MS_PER_DAY === 0 || warnedNonMidnightDateColumns.has(column))
@@ -33,7 +33,9 @@ function prepareDateValue(value) {
33
33
  // structured values bind directly with an ::jsonb cast; JSON.stringify first
34
34
  // would produce a JSON-string scalar instead of the structured value.
35
35
  export function prepareJsonbValue(value) {
36
- if (typeof value === "boolean") {
36
+ // Bun.SQL types JS numbers as int4/float8 params, which Postgres refuses for a jsonb column.
37
+ // Non-finite numbers fall through so Postgres rejects them instead of storing JSON null.
38
+ if (typeof value === "boolean" || (typeof value === "number" && Number.isFinite(value))) {
37
39
  return { kind: "param", sql: "::text::jsonb", bound: JSON.stringify(value) };
38
40
  }
39
41
  if (typeof value !== "object" || isTemporalInstant(value)) {
@@ -42,7 +44,7 @@ export function prepareJsonbValue(value) {
42
44
  if (!Array.isArray(value)) {
43
45
  return { kind: "param", sql: "::jsonb", bound: value };
44
46
  }
45
- // All-boolean arrays are inferred as boolean[] by postgres-js; route via text::jsonb.
47
+ // All-boolean arrays are inferred as boolean[] by the driver; route via text::jsonb.
46
48
  if (value.length > 0 && value.every((entry) => typeof entry === "boolean")) {
47
49
  return { kind: "param", sql: "::text::jsonb", bound: JSON.stringify(value) };
48
50
  }
@@ -59,7 +61,7 @@ const INTEGER_PG_TYPES = new Set([
59
61
  "bigserial",
60
62
  ]);
61
63
  // Postgres rounds sub-millisecond params into timestamptz(3); truncating to ms here keeps the
62
- // stored instant identical across drivers and equal to what postgres.js sends via Date.
64
+ // stored instant identical across drivers and equal to what a Date param would store.
63
65
  export function instantToTimestamptzParam(instant) {
64
66
  return Temporal.Instant.fromEpochMilliseconds(instant.epochMilliseconds).toString();
65
67
  }
@@ -67,7 +69,7 @@ function prepareDriverNeutralScalar(value, pgType) {
67
69
  if ((pgType === "timestamptz" || pgType === "timestamptz(3)") && isTemporalInstant(value)) {
68
70
  return { kind: "param", sql: "", bound: instantToTimestamptzParam(value) };
69
71
  }
70
- // postgres.js sends text, so Postgres rejects 3.5 for an integer column instead of rounding it.
72
+ // Sent as text, so Postgres rejects 3.5 for an integer column instead of rounding it.
71
73
  if (typeof value === "number" && pgType !== undefined && INTEGER_PG_TYPES.has(pgType)) {
72
74
  return { kind: "param", sql: "", bound: String(value) };
73
75
  }
@@ -1,4 +1,5 @@
1
- import type { EntityDefinition, SessionUser } from "../engine/types/index.ts";
1
+ import type { EntityDefinition } from "@cosmicdrift/kumiko-types/fields";
2
+ import type { SessionUser } from "../engine/types/index.ts";
2
3
  import { type ParentVisibilityOption } from "./parent-ref-clause.ts";
3
4
  import type { TenantDb } from "./tenant-db.ts";
4
5
  export type EagerLoadEntityResolver = (entityName: string) => EntityDefinition | undefined;
@@ -1,4 +1,4 @@
1
- import type { EntityDefinition } from "../engine/types/index.ts";
1
+ import type { EntityDefinition } from "@cosmicdrift/kumiko-types/fields";
2
2
  import { type Logger } from "../logging/index.ts";
3
3
  import type { EnvelopeCipher } from "../secrets/envelope-cipher.ts";
4
4
  export declare function collectEncryptedFieldNames(entity: EntityDefinition): ReadonlySet<string>;
@@ -1,6 +1,6 @@
1
1
  import type { Writable } from "@cosmicdrift/kumiko-types/executor-brand";
2
+ import type { EntityDefinition } from "@cosmicdrift/kumiko-types/fields";
2
3
  import type { EntityTenancy, TenancyBrand } from "@cosmicdrift/kumiko-types/tenancy-brand";
3
- import type { EntityDefinition } from "../engine/types/index.ts";
4
4
  import type { BuildEntityTableMetaOptions, EntityTableMeta, UnmanagedTableInput } from "./entity-table-meta-types.ts";
5
5
  export type { BuildEntityTableMetaOptions, ColumnMeta, CompositePrimaryKeyMeta, EntityTableMeta, IndexMeta, PgType, UnmanagedTableInput, } from "./entity-table-meta-types.ts";
6
6
  export declare function resolveTableName(entityName: string, entity: EntityDefinition, featureName: string | undefined): string;
@@ -1,6 +1,8 @@
1
+ import type { EntityDefinition } from "@cosmicdrift/kumiko-types/fields";
2
+ import type { EntityId } from "@cosmicdrift/kumiko-types/identifiers";
1
3
  import type { ErasedSubjectHandling } from "../crypto/pii-field-encryption.ts";
2
4
  import type { WhereObject } from "../db/query.ts";
3
- import type { EntityDefinition, EntityId, SessionUser, TenantId } from "../engine/types/index.ts";
5
+ import type { SessionUser, TenantId } from "../engine/types/index.ts";
4
6
  import { type WriteFailure } from "../errors/index.ts";
5
7
  import { type EventMetadata } from "../event-store/index.ts";
6
8
  import type { EntityCache } from "../pipeline/entity-cache.ts";
@@ -5,7 +5,8 @@ import { executeRawQueryRead } from "../db/queries/raw-sql.js";
5
5
  import { shiftParams } from "../engine/ownership.js";
6
6
  import { SYSTEM_TENANT_ID } from "../engine/types/identifiers.js";
7
7
  import { AccessDeniedError, InternalError, subjectErasedConflict, UniqueViolationError, writeFailure, } from "../errors/index.js";
8
- import { ArchivedStreamError, isStreamArchived } from "../event-store/index.js";
8
+ import { ArchivedStreamError } from "../event-store/errors.js";
9
+ import { isStreamArchived } from "../event-store/index.js";
9
10
  import { assertUnreachable } from "../utils/index.js";
10
11
  import { rehydrateCompoundTypes } from "./compound-types.js";
11
12
  import { collectEncryptedFieldNames, decryptEntityFieldValues, encryptEntityFieldValues, logUndecryptableField, resolveEntityFieldEncryption, } from "./entity-field-encryption.js";
@@ -120,7 +121,7 @@ export function buildExecutorContext(table, entity, options) {
120
121
  // old hardcoded user.tenantId). Single source of truth for the stream key.
121
122
  const streamTenantFor = (user, requestedStreamTenantId) => entity.systemStream ? SYSTEM_TENANT_ID : (requestedStreamTenantId ?? user.tenantId);
122
123
  // Only a system-mode db (r.systemScope() / acknowledged cross-tenant) or a tenant-mode db bound
123
- // to exactly that stream tenant (ctx.forTenant) may address another tenant's stream, and only
124
+ // to exactly that stream tenant (ctx.tenants.writeTarget) may address another tenant's stream, and only
124
125
  // the tenant of the row it just loaded.
125
126
  const streamTenantOverrideFailure = (db, row, requestedStreamTenantId) => {
126
127
  if (requestedStreamTenantId === undefined)
@@ -293,7 +294,7 @@ export function buildExecutorContext(table, entity, options) {
293
294
  return await decryptForRead(rehydrateCompoundTypes(row, entity));
294
295
  }
295
296
  // Archive guard for the CRUD write paths. Archived streams are read-only —
296
- // ctx.appendEvent (append-event-core) already enforces this, but the
297
+ // ctx.events.append (append-event-core) already enforces this, but the
297
298
  // executor appends directly via append() and getStreamVersion() ignores
298
299
  // the archive flag, so without this check a PATCH/DELETE on an archived
299
300
  // entity would silently land an event and break the read-only contract
@@ -0,0 +1,17 @@
1
+ import type { FieldDefinition } from "@cosmicdrift/kumiko-types/fields";
2
+ import type { ListAggregateCurrencyAmount, ListAggregateMeasureKind } from "@cosmicdrift/kumiko-types/list-aggregate-types";
3
+ import type { OwnershipClause } from "../engine/ownership.ts";
4
+ import type { ExecutorContext } from "./event-store-executor-context.ts";
5
+ import { type ListWhere } from "./event-store-executor-read-filter.ts";
6
+ import type { TenantDb } from "./tenant-db.ts";
7
+ export type CurrencyMeasureCandidate = {
8
+ readonly kind: ListAggregateMeasureKind;
9
+ readonly field: string;
10
+ readonly def: FieldDefinition;
11
+ readonly clause: OwnershipClause;
12
+ };
13
+ export type MeasureCurrencies = ReadonlyMap<string, readonly string[]>;
14
+ export declare function currencyColumnOf(field: string): string;
15
+ export declare function loadMeasureCurrencies(ctx: ExecutorContext, measures: readonly CurrencyMeasureCandidate[], where: ListWhere, db: TenantDb): Promise<MeasureCurrencies>;
16
+ export declare function currencyMeasureAlias(measureIndex: number, currencyIndex: number): string;
17
+ export declare function decodeCurrencyAmounts(row: Readonly<Record<string, unknown>>, measureIndex: number, currencies: readonly string[]): readonly ListAggregateCurrencyAmount[];
@@ -0,0 +1,40 @@
1
+ import { isPerCurrencyMeasure } from "./aggregate-sql.js";
2
+ import { bindShiftedClause } from "./event-store-executor-read-filter.js";
3
+ import { executeRawQueryRead } from "./queries/raw-sql.js";
4
+ import { schemaTableName } from "./table-introspection.js";
5
+ import { tenantDbRunner } from "./tenant-db-runner.js";
6
+ // Above the ~180 ISO 4217 codes, so the cap only bounds malformed data.
7
+ const MAX_AGGREGATE_CURRENCIES = 200;
8
+ export function currencyColumnOf(field) {
9
+ return `${field}Currency`;
10
+ }
11
+ // Runs before the measure query mutates `where`, on a copy of its params, and
12
+ // under the money field's own read clause: an unreadable amount must not reveal
13
+ // which currencies exist.
14
+ export async function loadMeasureCurrencies(ctx, measures, where, db) {
15
+ const byField = new Map();
16
+ const tableName = String(schemaTableName(ctx.table));
17
+ for (const m of measures) {
18
+ if (!isPerCurrencyMeasure(m.kind, m.def.type) || byField.has(m.field))
19
+ continue;
20
+ if (!Object.hasOwn(ctx.table, currencyColumnOf(m.field)))
21
+ continue;
22
+ const params = [...where.params];
23
+ const conditions = [...where.whereSql, `${where.colSql(m.field)} IS NOT NULL`];
24
+ if (m.clause.kind === "sql")
25
+ conditions.push(`(${bindShiftedClause(params, m.clause)})`);
26
+ const currencySql = where.colSql(currencyColumnOf(m.field));
27
+ const rows = await executeRawQueryRead(tenantDbRunner(db), `SELECT DISTINCT ${currencySql} AS cur FROM "${tableName}" WHERE ${conditions.join(" AND ")} AND ${currencySql} IS NOT NULL ORDER BY 1 LIMIT ${MAX_AGGREGATE_CURRENCIES}`, params);
28
+ byField.set(m.field, rows.map((row) => String(row.cur)));
29
+ }
30
+ return byField;
31
+ }
32
+ export function currencyMeasureAlias(measureIndex, currencyIndex) {
33
+ return `m${measureIndex}_${currencyIndex}`;
34
+ }
35
+ export function decodeCurrencyAmounts(row, measureIndex, currencies) {
36
+ return currencies.flatMap((currency, j) => {
37
+ const raw = row[currencyMeasureAlias(measureIndex, j)];
38
+ return raw === null || raw === undefined ? [] : [{ currency, value: Number(raw) }];
39
+ });
40
+ }
@@ -1,6 +1,7 @@
1
1
  import { ValidationError } from "../errors/index.js";
2
- import { aggregateKeyOf, decodeListAggregateValue, emptyListAggregateValue, groupedKeyOrderLimitSql, isListAggregateGroupable, isListAggregateMeasureSupported, listAggregateKeySql, listAggregateMeasureSql, } from "./aggregate-sql.js";
2
+ import { aggregateKeyOf, decodeListAggregateValue, emptyListAggregateValue, groupedKeyOrderLimitSql, isListAggregateGroupable, isListAggregateMeasureSupported, isPerCurrencyMeasure, listAggregateKeySql, listAggregateMeasureSql, listCurrencyMeasureSql, } from "./aggregate-sql.js";
3
3
  import { holdsCiphertextOrSecret } from "./entity-field-encryption.js";
4
+ import { currencyColumnOf, currencyMeasureAlias, decodeCurrencyAmounts, loadMeasureCurrencies, } from "./event-store-executor-read-aggregate-currencies.js";
4
5
  import { appendShiftedClause, bindShiftedClause, } from "./event-store-executor-read-filter.js";
5
6
  import { buildListWhere, createFieldReadClause, } from "./event-store-executor-read-where.js";
6
7
  import { executeRawQueryRead } from "./queries/raw-sql.js";
@@ -61,9 +62,26 @@ function planAggregate(ctx, fieldReadClause, aggregate) {
61
62
  return { groupBy, measures };
62
63
  }
63
64
  function emptyMeasureValues(plan) {
64
- return plan.measures.map((m) => m.gate.kind === "silent" ? null : emptyListAggregateValue(m.kind));
65
+ return plan.measures.map((m) => {
66
+ if (m.gate.kind === "silent")
67
+ return null;
68
+ return isPerCurrencyMeasure(m.kind, m.gate.def.type) ? [] : emptyListAggregateValue(m.kind);
69
+ });
70
+ }
71
+ function currencyCandidates(plan) {
72
+ return plan.measures.flatMap((m) => m.gate.kind === "ok"
73
+ ? [{ kind: m.kind, field: m.field, def: m.gate.def, clause: m.gate.clause }]
74
+ : []);
65
75
  }
66
- function renderSelectList(plan, where) {
76
+ function currencyMeasureSelects(measureIndex, kind, field, readFilterSql, currencies, where) {
77
+ return currencies.map((currency, j) => {
78
+ where.params.push(currency);
79
+ const currencyMatch = `${where.colSql(currencyColumnOf(field))} = $${where.params.length}`;
80
+ const filterSql = readFilterSql === undefined ? currencyMatch : `${currencyMatch} AND (${readFilterSql})`;
81
+ return `${listCurrencyMeasureSql(kind, where.colSql(field), filterSql)} AS ${currencyMeasureAlias(measureIndex, j)}`;
82
+ });
83
+ }
84
+ function renderSelectList(plan, where, currencies) {
67
85
  const parts = [];
68
86
  if (plan.groupBy?.gate.kind === "ok") {
69
87
  const { def, clause } = plan.groupBy.gate;
@@ -77,6 +95,11 @@ function renderSelectList(plan, where) {
77
95
  if (m.gate.kind === "silent")
78
96
  continue; // skip: an unreadable measure stays out of the SELECT and decodes to null
79
97
  const filterSql = m.gate.clause.kind === "sql" ? bindShiftedClause(where.params, m.gate.clause) : undefined;
98
+ if (isPerCurrencyMeasure(m.kind, m.gate.def.type)) {
99
+ const fieldCurrencies = currencies.get(m.field) ?? [];
100
+ parts.push(...currencyMeasureSelects(i, m.kind, m.field, filterSql, fieldCurrencies, where));
101
+ continue;
102
+ }
80
103
  parts.push(`${listAggregateMeasureSql(m.kind, m.gate.def.type, where.colSql(m.field), filterSql)} AS m${i}`);
81
104
  }
82
105
  return parts.join(", ");
@@ -93,7 +116,8 @@ export async function aggregateList(ctx, payload, user, db, runtimeOptions) {
93
116
  };
94
117
  }
95
118
  const { where, searchTruncated } = built;
96
- const selectList = renderSelectList(plan, where);
119
+ const currencies = await loadMeasureCurrencies(ctx, currencyCandidates(plan), where, db);
120
+ const selectList = renderSelectList(plan, where, currencies);
97
121
  const whereText = where.whereSql.length > 0 ? ` WHERE ${where.whereSql.join(" AND ")}` : "";
98
122
  const groupText = grouped ? groupedKeyOrderLimitSql(MAX_AGGREGATE_GROUPS + 1) : "";
99
123
  const tableName = String(schemaTableName(ctx.table));
@@ -102,7 +126,14 @@ export async function aggregateList(ctx, payload, user, db, runtimeOptions) {
102
126
  const groups = rows.slice(0, MAX_AGGREGATE_GROUPS).map((row) => ({
103
127
  key: grouped ? aggregateKeyOf(row["k0"]) : null,
104
128
  count: Number(row["c"]),
105
- measures: plan.measures.map((m, i) => m.gate.kind === "silent" ? null : decodeListAggregateValue(row[`m${i}`])),
129
+ measures: plan.measures.map((m, i) => {
130
+ if (m.gate.kind === "silent")
131
+ return null;
132
+ if (isPerCurrencyMeasure(m.kind, m.gate.def.type)) {
133
+ return decodeCurrencyAmounts(row, i, currencies.get(m.field) ?? []);
134
+ }
135
+ return decodeListAggregateValue(row[`m${i}`]);
136
+ }),
106
137
  }));
107
138
  return {
108
139
  groups,
@@ -1,5 +1,5 @@
1
+ import type { EntityDefinition } from "@cosmicdrift/kumiko-types/fields";
1
2
  import { type OwnershipClause } from "../engine/ownership.ts";
2
- import type { EntityDefinition } from "../engine/types/index.ts";
3
3
  import { type Table } from "./event-store-executor-context.ts";
4
4
  export type ListWhere = {
5
5
  readonly whereSql: string[];
@@ -58,7 +58,7 @@ function applyMultiSelectFilter(colSql, whereSql, params, f) {
58
58
  // skip: empty candidate list is unsatisfiable
59
59
  return;
60
60
  }
61
- // Bound as text then cast: a JS array makes postgres.js infer boolean[]/int4[]
61
+ // Bound as text then cast: a JS array makes the driver infer boolean[]/int4[]
62
62
  // for client-supplied non-string values, and `boolean[]::jsonb` is rejected
63
63
  // (500 on client input). An array value means "contains all of these".
64
64
  params.push(JSON.stringify(candidates));
@@ -163,6 +163,9 @@ export function collectListFilters(payload) {
163
163
  const single = payload.filter !== undefined ? [payload.filter] : [];
164
164
  return payload.filters !== undefined ? [...single, ...payload.filters] : single;
165
165
  }
166
+ function isJsonbArrayField(field) {
167
+ return field?.type === "multiSelect" || (field?.type === "reference" && field.multiple === true);
168
+ }
166
169
  export function applyListFilter(where, f, table, entity, fieldReadClause) {
167
170
  if (!Object.hasOwn(table, f.field)) {
168
171
  // skip: unknown field — not a real column, drop the filter (injection guard)
@@ -194,9 +197,9 @@ export function applyListFilter(where, f, table, entity, fieldReadClause) {
194
197
  }
195
198
  if (readClause.kind === "sql")
196
199
  appendShiftedClause(where, readClause);
197
- if (entity.fields[f.field]?.type === "multiSelect") {
200
+ if (isJsonbArrayField(entity.fields[f.field])) {
198
201
  applyMultiSelectFilter(where.colSql, where.whereSql, where.params, f);
199
- // skip: multiSelect already handled — don't fall through to applyScreenFilter
202
+ // skip: jsonb-array field already handled — don't fall through to applyScreenFilter
200
203
  return;
201
204
  }
202
205
  applyScreenFilter(table, where.colSql, where.whereSql, where.params, f);
@@ -1,4 +1,5 @@
1
- import type { EntityDefinition, TenantId } from "../engine/types/index.ts";
1
+ import type { EntityDefinition } from "@cosmicdrift/kumiko-types/fields";
2
+ import type { TenantId } from "../engine/types/index.ts";
2
3
  import type { TableInfo } from "./table-info.ts";
3
4
  export declare function withStreamVersion(row: Record<string, unknown>, streamVersion: number): Record<string, unknown>;
4
5
  export declare function coerceAndRehydrateRow(raw: Record<string, unknown>, tableInfo: TableInfo, entity: EntityDefinition): Record<string, unknown>;
@@ -1,5 +1,6 @@
1
+ import type { EntityDefinition } from "@cosmicdrift/kumiko-types/fields";
1
2
  import { type OwnershipClause } from "../engine/ownership.ts";
2
- import type { EntityDefinition, SessionUser, TenantId } from "../engine/types/index.ts";
3
+ import type { SessionUser, TenantId } from "../engine/types/index.ts";
3
4
  import type { SearchAdapter } from "../search/types.ts";
4
5
  import type { EventStoreExecutor } from "./event-store-executor.ts";
5
6
  import type { Table } from "./event-store-executor-context.ts";
@@ -1,5 +1,6 @@
1
+ import type { EntityDefinition } from "@cosmicdrift/kumiko-types/fields";
1
2
  import { type OwnershipClause } from "../engine/ownership.ts";
2
- import type { EntityDefinition, SessionUser } from "../engine/types/index.ts";
3
+ import type { SessionUser } from "../engine/types/index.ts";
3
4
  import type { EventStoreExecutor } from "./event-store-executor.ts";
4
5
  import type { Table } from "./event-store-executor-context.ts";
5
6
  import type { ListWhere } from "./event-store-executor-read-filter.ts";
@@ -59,7 +59,7 @@ export function createReadVerbs(ctx) {
59
59
  const tableInfo = extractTableInfo(table);
60
60
  const encryptedRows = rawRows.map((r) => coerceAndRehydrateRow(r, tableInfo, entity));
61
61
  const decryptedRows = await Promise.all(encryptedRows.map((r) => decryptForRead(r, { degradeUndecryptable: () => { } })));
62
- // Stream version is authoritative (see detail()): ctx.appendEvent bumps the
62
+ // Stream version is authoritative (see detail()): ctx.events.append bumps the
63
63
  // stream without touching row.version, so the raw row version would hand
64
64
  // clients a stale optimistic-lock base. Rows without events keep theirs.
65
65
  const rows = decryptedRows.map((r, i) => withStreamVersion(r, streamVersions[i] ?? 0));
@@ -101,7 +101,7 @@ export function createReadVerbs(ctx) {
101
101
  return null;
102
102
  const idWhere = idFilter(payload.id);
103
103
  // Stream-version authoritative (same policy as update/Block 0):
104
- // ctx.appendEvent (lifecycle-writes like incident:post-update) bumps
104
+ // ctx.events.append (lifecycle-writes like incident:post-update) bumps
105
105
  // the stream WITHOUT touching row.version — a detail-read that hands
106
106
  // out the stale row.version dooms the next CRUD update built on it
107
107
  // (entityEdit loads detail.version as its optimistic-lock base) to a
@@ -0,0 +1,4 @@
1
+ import type { EventStoreExecutor } from "@cosmicdrift/kumiko-types/event-store-executor-types";
2
+ type WriteVerbs = Pick<EventStoreExecutor, "create" | "update" | "delete" | "forget" | "restore">;
3
+ export declare function withOwnTransactionOnPool(verbs: WriteVerbs): WriteVerbs;
4
+ export {};
@@ -0,0 +1,42 @@
1
+ import { runnerCanBeginTransaction } from "./query.js";
2
+ import { isBoundTenantDb, tenantDbRunner, tenantDbWritesDeniedReason } from "./tenant-db-runner.js";
3
+ import { runInOwnSavepoint, runInOwnTransaction } from "./tenant-db-scoped-rebind.js";
4
+ // Aborts the surrounding transaction when a verb returns a failure instead of throwing.
5
+ class RollbackOnFailure extends Error {
6
+ }
7
+ // Append, projection and hooks commit or roll back together, also when a handler swallows a failed
8
+ // verb inside its transaction. Savepoints on one tx are serialized, so parallel verbs cannot interleave.
9
+ async function runVerbAtomically(db, run) {
10
+ // Unbound and denied handles keep their original error, a fresh transaction would reword it.
11
+ if (!isBoundTenantDb(db) || tenantDbWritesDeniedReason(db) !== undefined) {
12
+ return run(db);
13
+ }
14
+ const runInOwnScope = runnerCanBeginTransaction(tenantDbRunner(db))
15
+ ? runInOwnTransaction
16
+ : runInOwnSavepoint;
17
+ let failure;
18
+ try {
19
+ return await runInOwnScope(db, async (txDb) => {
20
+ const result = await run(txDb);
21
+ if (!result.isSuccess) {
22
+ failure = result;
23
+ throw new RollbackOnFailure();
24
+ }
25
+ return result;
26
+ });
27
+ }
28
+ catch (error) {
29
+ if (error instanceof RollbackOnFailure && failure !== undefined)
30
+ return failure;
31
+ throw error;
32
+ }
33
+ }
34
+ export function withOwnTransactionOnPool(verbs) {
35
+ return {
36
+ create: (payload, user, db, options) => runVerbAtomically(db, (txDb) => verbs.create(payload, user, txDb, options)),
37
+ update: (payload, user, db, options) => runVerbAtomically(db, (txDb) => verbs.update(payload, user, txDb, options)),
38
+ delete: (payload, user, db, options) => runVerbAtomically(db, (txDb) => verbs.delete(payload, user, txDb, options)),
39
+ forget: (payload, user, db, options) => runVerbAtomically(db, (txDb) => verbs.forget(payload, user, txDb, options)),
40
+ restore: (payload, user, db, options) => runVerbAtomically(db, (txDb) => verbs.restore(payload, user, txDb, options)),
41
+ };
42
+ }
@@ -1,13 +1,11 @@
1
+ import type { EntityId } from "@cosmicdrift/kumiko-types/identifiers";
1
2
  import type { TenantDb } from "@cosmicdrift/kumiko-types/tenant-db-types";
2
3
  import type { ZodType } from "zod";
3
4
  import type { UnavailableSelectOption } from "../engine/screen-helpers.ts";
4
- import type { EntityId } from "../engine/types/index.ts";
5
- import { type UnprocessableOpts, type WriteFailure, writeFailure } from "../errors/index.ts";
5
+ import type { UnprocessableOpts } from "../errors/classes.ts";
6
+ import { type WriteFailure, writeFailure } from "../errors/index.ts";
6
7
  import type { StoredEvent } from "../event-store/index.ts";
7
8
  import type { DbRow, DbRunner } from "./connection.ts";
8
- export declare function withoutEventInJson<T extends {
9
- readonly event: unknown;
10
- }>(result: T): T;
11
9
  export declare function projectEntityEvent(db: TenantDb, runner: DbRunner, event: StoredEvent): Promise<void>;
12
10
  export declare function selectOptionNotAvailableFailure(entries: readonly UnavailableSelectOption[]): WriteFailure | undefined;
13
11
  export type PreSaveFn = (changes: Record<string, unknown>, previous: Record<string, unknown>, isNew: boolean) => Promise<Record<string, unknown>>;
@@ -2,11 +2,6 @@ import { VersionConflictError as FrameworkVersionConflict, UnprocessableError, w
2
2
  import { hasLiveProjectionsForEvent, runProjectionsForEvent, } from "../pipeline/projections-runner.js";
3
3
  import { projectionRegistryOf } from "./projection-registry-binding.js";
4
4
  import { runInSavepointIfSupported } from "./query.js";
5
- // The echoed event carries entity PII and must never reach a handler's JSON response, while
6
- // hooks and projections still read it by property. Non-enumerable keeps it out of spread/stringify.
7
- export function withoutEventInJson(result) {
8
- return Object.defineProperty(result, "event", { value: result.event, enumerable: false });
9
- }
10
5
  // Custom projections for a write that did not go through the dispatcher (hook or
11
6
  // job writing a second aggregate). Savepoint like applyEntityEvent: a throwing
12
7
  // projection fails the write and the caller's transaction rolls it back.
@@ -4,15 +4,18 @@ import { instructionFieldNames } from "../engine/instruction-fields.js";
4
4
  import { userCanCreateFieldRow, userCanWriteFieldRow } from "../engine/ownership.js";
5
5
  import { buildInsertSchema, buildUpdateSchema } from "../engine/schema-builder.js";
6
6
  import { findUnavailableSelectOptions, isRecordLocked, isUnchangedValue, } from "../engine/screen-helpers.js";
7
- import { AccessDeniedError, VersionConflictError as FrameworkVersionConflict, IdempotentReplayError, InternalError, isSubjectErasedConflict, NotFoundError, PreconditionFailedError, RecordLockedError, UnprocessableError, writeFailure, } from "../errors/index.js";
8
- import { append, IdempotentAppendConflictError as EventStoreIdempotentAppendConflict, VersionConflictError as EventStoreVersionConflict, getStreamVersion, } from "../event-store/index.js";
7
+ import { IdempotentReplayError, PreconditionFailedError, RecordLockedError, } from "../errors/classes.js";
8
+ import { AccessDeniedError, VersionConflictError as FrameworkVersionConflict, InternalError, NotFoundError, UnprocessableError, writeFailure, } from "../errors/index.js";
9
+ import { isSubjectErasedConflict } from "../errors/subject-erased.js";
10
+ import { IdempotentAppendConflictError as EventStoreIdempotentAppendConflict } from "../event-store/errors.js";
11
+ import { append, VersionConflictError as EventStoreVersionConflict, getStreamVersion, } from "../event-store/index.js";
9
12
  import { assertInstructionFieldWriteAllowed, assertIrreversibleOperationAllowed, isIrreversibleEntityVerb, } from "../pipeline/irreversible-operation-gate.js";
10
13
  import { generateId } from "../utils/index.js";
11
14
  import { applyEntityEvent } from "./apply-entity-event.js";
12
15
  import { flattenCompoundTypes, rehydrateCompoundTypes } from "./compound-types.js";
13
16
  import { WritePurposes, } from "./event-store-executor.js";
14
17
  import { buildEventMetadata, entityEventName, isForeignTenantOnGlobalEntity, ownershipSubject, tryMapUniqueViolation, } from "./event-store-executor-context.js";
15
- import { optimisticLockFailure, ownershipDeniedFailure, projectEntityEvent, runPreSave, selectOptionNotAvailableFailure, withoutEventInJson, } from "./event-store-executor-write-steps.js";
18
+ import { optimisticLockFailure, ownershipDeniedFailure, projectEntityEvent, runPreSave, selectOptionNotAvailableFailure, } from "./event-store-executor-write-steps.js";
16
19
  import { isFrameworkSystemUser, isLockGuardBypassed } from "./lock-guard.js";
17
20
  import { runInSavepointIfSupported } from "./query.js";
18
21
  import { assertPersonalDataWrite, tableNameOf, withExecutorManagedWrites } from "./tenant-db.js";
@@ -131,7 +134,7 @@ export function createWriteVerbs(ctx) {
131
134
  }
132
135
  throw error;
133
136
  }
134
- // Stream-version is authoritative, not row.version. `ctx.appendEvent`
137
+ // Stream-version is authoritative, not row.version. `ctx.events.append`
135
138
  // can bump the stream between CRUD writes (domain event on the same
136
139
  // aggregate); a stale row.version here would make the next CRUD write
137
140
  // trip `events_aggregate_version_uq` (tenant_id, aggregate_id, version)
@@ -244,14 +247,14 @@ export function createWriteVerbs(ctx) {
244
247
  // legitimately collide — the same ID has an existing stream — so return
245
248
  // version_conflict instead of internal_error. Update uses the same catch.
246
249
  try {
247
- // Savepoint-scoped: postgres.js poisons the WHOLE surrounding
248
- // begin() once any statement inside it errors, even if the JS error
250
+ // Savepoint-scoped: Postgres aborts the WHOLE surrounding
251
+ // transaction once any statement inside it errors, even if the JS error
249
252
  // is caught — a losing concurrent create's unique-violation
250
253
  // would otherwise abort the caller's outer transaction and surface as
251
254
  // internal_error at commit time instead of the version_conflict this
252
255
  // catch classifies. runInSavepointIfSupported confines the failed
253
256
  // INSERT to a nested scope that rolls back on its own (same pattern as
254
- // ctx.tryAppendEvent), and falls back to a plain call when the runner
257
+ // ctx.events.tryAppend), and falls back to a plain call when the runner
255
258
  // is a bare pool connection with no active transaction to poison
256
259
  // (seeds/tests calling the executor directly).
257
260
  const event = await runInSavepointIfSupported(runner, async (sp) => append(sp, {
@@ -287,8 +290,8 @@ export function createWriteVerbs(ctx) {
287
290
  // designer/frontend can show a clear "duplicate" message instead of a cryptic
288
291
  // "internal server error".
289
292
  // Savepoint like the append: an unclassified DB error from the projection
290
- // write would otherwise poison the enclosing transaction (postgres-js rejects the
291
- // whole begin() once any statement in it fails). The savepoint rolls back the failed
293
+ // write would otherwise poison the enclosing transaction (Postgres aborts the
294
+ // whole transaction once any statement in it fails). The savepoint rolls back the failed
292
295
  // write while allowing the error to propagate and remain catchable.
293
296
  async function applyProjection(runner, event, noRowMessage) {
294
297
  let result;
@@ -462,7 +465,7 @@ export function createWriteVerbs(ctx) {
462
465
  await projectEntityEvent(db, runner, echoEvent);
463
466
  return {
464
467
  isSuccess: true,
465
- data: withoutEventInJson({
468
+ data: {
466
469
  kind: "save",
467
470
  id: aggregateId,
468
471
  data: projection,
@@ -473,7 +476,7 @@ export function createWriteVerbs(ctx) {
473
476
  // Persisted event carries ciphertext by design — the caller-facing
474
477
  // echo must be plaintext like every other response field.
475
478
  event: echoEvent,
476
- }),
479
+ },
477
480
  };
478
481
  },
479
482
  async update(payload, user, db, updateOptions) {
@@ -526,7 +529,7 @@ export function createWriteVerbs(ctx) {
526
529
  const { data, echoEvent } = persisted;
527
530
  return {
528
531
  isSuccess: true,
529
- data: withoutEventInJson({
532
+ data: {
530
533
  kind: "save",
531
534
  id: data["id"], // @cast-boundary engine-payload
532
535
  data,
@@ -535,7 +538,7 @@ export function createWriteVerbs(ctx) {
535
538
  isNew: false,
536
539
  entityName,
537
540
  event: echoEvent,
538
- }),
541
+ },
539
542
  };
540
543
  }
541
544
  catch (e) {
@@ -622,14 +625,14 @@ export function createWriteVerbs(ctx) {
622
625
  await projectEntityEvent(db, runner, echoEvent);
623
626
  return {
624
627
  isSuccess: true,
625
- data: withoutEventInJson({
628
+ data: {
626
629
  kind: "delete",
627
630
  id: payload.id,
628
631
  data: existing,
629
632
  entityName,
630
633
  event: echoEvent,
631
634
  ...(isLockGuardBypassed(user, options) && { lockGuardBypassed: true }),
632
- }),
635
+ },
633
636
  };
634
637
  },
635
638
  // Hard-purge (Art. 17). Same shape as delete(), but emits `forgotten` which
@@ -695,14 +698,14 @@ export function createWriteVerbs(ctx) {
695
698
  await projectEntityEvent(db, runner, echoEvent);
696
699
  return {
697
700
  isSuccess: true,
698
- data: withoutEventInJson({
701
+ data: {
699
702
  kind: "delete",
700
703
  id: payload.id,
701
704
  data: existing,
702
705
  entityName,
703
706
  event: echoEvent,
704
707
  lockGuardBypassed: true,
705
- }),
708
+ },
706
709
  };
707
710
  },
708
711
  async restore(payload, user, db, options) {
@@ -761,7 +764,7 @@ export function createWriteVerbs(ctx) {
761
764
  await projectEntityEvent(db, runner, echoEvent);
762
765
  return {
763
766
  isSuccess: true,
764
- data: withoutEventInJson({
767
+ data: {
765
768
  kind: "save",
766
769
  id: payload.id,
767
770
  data: restoredHydrated,
@@ -770,7 +773,7 @@ export function createWriteVerbs(ctx) {
770
773
  isNew: false,
771
774
  entityName,
772
775
  event: echoEvent,
773
- }),
776
+ },
774
777
  };
775
778
  },
776
779
  };
@@ -1,6 +1,6 @@
1
1
  import type { EventStoreExecutor } from "@cosmicdrift/kumiko-types/event-store-executor-types";
2
+ import type { EntityDefinition } from "@cosmicdrift/kumiko-types/fields";
2
3
  import type { LocalKeyKmsAdapter } from "../crypto/index.ts";
3
- import type { EntityDefinition } from "../engine/types/index.ts";
4
4
  import type { EntityCache } from "../pipeline/entity-cache.ts";
5
5
  import type { SearchAdapter } from "../search/types.ts";
6
6
  import type { EnvelopeCipher } from "../secrets/envelope-cipher.ts";
@@ -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
  }
@@ -1,6 +1,12 @@
1
1
  import type { ExecutorManagedWriteCapability, Writable } from "@cosmicdrift/kumiko-types/executor-brand";
2
+ import type { EntityDefinition } from "@cosmicdrift/kumiko-types/fields";
2
3
  import { AccessDeniedError } from "../errors/index.ts";
3
- export declare function markExecutorManagedTable(table: object): void;
4
+ export type ExecutorManagedEntitySource = {
5
+ readonly entityName: string;
6
+ readonly entity: EntityDefinition;
7
+ };
8
+ export declare function markExecutorManagedTable(table: object, entitySource?: ExecutorManagedEntitySource): void;
9
+ export declare function executorManagedEntitySourceOf(table: unknown): ExecutorManagedEntitySource | undefined;
4
10
  export declare function isExecutorManagedTable(table: unknown): boolean;
5
11
  export declare function registerExecutorManagedWriteRunner(runner: object): void;
6
12
  export declare function hasExecutorManagedWriteCapability(runner: unknown): runner is ExecutorManagedWriteCapability;