@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
@@ -1,49 +1,3 @@
1
- // applyEntityEvent — the ONLY write logic for r.entity tables from
2
- // StoredEvents. Both callers use it:
3
- //
4
- // - createEventStoreExecutor (live, in the write TX) passes the just-appended
5
- // StoredEvent directly; sensitive fields are table ciphertext in the payload
6
- // (validated at boot as pii/encrypted).
7
- // - rebuildProjection via ImplicitProjection (replay, in the rebuild TX)
8
- // passes the same StoredEvent; apply copies ciphertext byte-for-byte,
9
- // while bidx is recalculated below.
10
- //
11
- // Live==Rebuild equivalence therefore holds by construction for ALL fields —
12
- // changed write logic needs to be maintained in only ONE place, with no sync
13
- // contract. The only legitimate divergence is crypto-shredding
14
- // (DEK erased → value unreadable, bidx NULL). Load-bearing test:
15
- // db/__tests__/implicit-projection-equivalence.integration.test.ts.
16
- //
17
- // Tenant isolation: applyEntityEvent expects an ExecutorManagedRunner (tx or pool), NOT
18
- // a TenantDb wrapper. Two sources keep it safe:
19
- // 1. The live path reads the target row through the tenant-scoped TenantDb
20
- // before writing — loadById() for update/delete/forget, db.fetchOne() for
21
- // restore — so the aggregateId is already tenant-validated on arrival.
22
- // 2. create sets tenantId explicitly from event.tenantId, never derived from
23
- // the TenantDb wrapper default.
24
- // The missing TenantDb wrapper in this function is therefore not a hole.
25
- //
26
- // Auto-verbs:
27
- // <entity>.created → INSERT
28
- // <entity>.updated → UPDATE WHERE id=aggregateId
29
- // <entity>.deleted → soft-delete-UPDATE if entity.softDelete, otherwise hard-DELETE
30
- // <entity>.restored → undelete-UPDATE (meaningful only for softDelete)
31
- // <entity>.forgotten → always hard-DELETE (Art.17 purge, including softDelete);
32
- // via executor.forget(). Rebuild replays created→forgotten
33
- // → the row is gone, making this rebuild-safe (unlike a
34
- // direct deleteMany).
35
- //
36
- // Domain events (r.defineEvent) on the same aggregate are NOT handled here —
37
- // they never went through the Executor in the live path and must be handled by
38
- // explicit r.projection-apply handlers or r.multiStreamProjection.
39
- // ImplicitProjection registers the auto-verbs.
40
- //
41
- // Return shape: ApplyResult with `kind` and an optional `row`.
42
- // - "applied" → the write completed. `row` contains the written row for
43
- // create/update/soft-delete/restore. For hard-delete, `row` is null
44
- // (DELETE statements do not provide a returning row).
45
- // - "skipped" → the event is not an auto-verb (a domain event on the same
46
- // aggregate). Caller no-op.
47
1
  import { isOneOf } from "@cosmicdrift/kumiko-types/type-guards";
48
2
  import { requestContext } from "../api/request-context.js";
49
3
  import { collectLookupableFields, computeBlindIndexValues } from "../crypto/blind-index.js";
@@ -51,6 +5,8 @@ import { configuredPiiSubjectKms, decryptPiiFieldValues, isPiiCiphertext, PII_ER
51
5
  import { collectPiiFileReferenceFields } from "../crypto/subject-resolver.js";
52
6
  import { deleteMany, insertOne, updateMany } from "../db/query.js";
53
7
  import { InternalError } from "../errors/index.js";
8
+ import { activeRowLevelSecurityScope, runInSystemRowLevelSecurityScope, } from "./row-level-security-scope.js";
9
+ import { asEntityTableMeta } from "./table-introspection.js";
54
10
  const AUTO_VERBS = ["created", "updated", "deleted", "restored", "forgotten"];
55
11
  /** Parses event.type into an AutoVerb when the event is an auto-verb
56
12
  * for the given aggregate; otherwise returns null (a domain event). */
@@ -85,7 +41,19 @@ async function decryptFileReferenceCiphertext(entity, values) {
85
41
  /** Applies an auto-event idempotently to the entity table.
86
42
  * Called both during live append (inside the write TX) and during rebuild
87
43
  * (inside the rebuild TX), using identical logic. */
88
- export async function applyEntityEvent(event, table, entity, tx) {
44
+ // An ambient tenant scope stays, so a live write cannot land a row in another tenant (row-level security
45
+ // rejects it). Replay, rebuild and boot seeds run without a tenant scope and global tables live on the system
46
+ // tenant, so only those write system scoped.
47
+ export function applyEntityEvent(event, table, entity, tx) {
48
+ if (keepsAmbientTenantScope(table))
49
+ return applyEntityEventInScope(event, table, entity, tx);
50
+ return runInSystemRowLevelSecurityScope("replay, rebuild and global-table projection writes carry no tenant scope of their own", () => applyEntityEventInScope(event, table, entity, tx));
51
+ }
52
+ function keepsAmbientTenantScope(table) {
53
+ return (activeRowLevelSecurityScope()?.kind === "tenant" &&
54
+ asEntityTableMeta(table)?.tenancy !== "global");
55
+ }
56
+ async function applyEntityEventInScope(event, table, entity, tx) {
89
57
  const verb = parseAutoVerb(event);
90
58
  if (verb === null)
91
59
  return { kind: "skipped" };
@@ -17,41 +17,47 @@ import { toSnakeCase } from "../utils/case.js";
17
17
  import { resolveTableName } from "./entity-table-meta.js";
18
18
  import { toPostgresArrayLiteral } from "./queries/postgres-array-literal.js";
19
19
  import { executeRawQuery, executeRawQueryRead } from "./queries/raw-sql.js";
20
+ import { runInSystemRowLevelSecurityScope } from "./row-level-security-scope.js";
20
21
  import { columnNamesOf, tableExists } from "./schema-inspection.js";
21
22
  export async function nullBlindIndexesForSubject(db, features, subjectKey) {
22
- const likePattern = subjectCiphertextLikePattern(subjectKey);
23
- const candidates = [];
24
- for (const feature of features.values()) {
25
- for (const [entityName, entity] of Object.entries(feature.entities ?? {})) {
26
- const lookupable = collectLookupableFields(entity);
27
- if (lookupable.length === 0)
28
- continue;
29
- // No featureName prefix — the dispatcher builds entity tables without
30
- // one (buildEntityTable with no featureName option), the sweep has to
31
- // hit the same names.
32
- candidates.push({ tableName: resolveTableName(entityName, entity, undefined), lookupable });
23
+ return runInSystemRowLevelSecurityScope("blind index nulling for a forgotten subject spans tenants", async () => {
24
+ const likePattern = subjectCiphertextLikePattern(subjectKey);
25
+ const candidates = [];
26
+ for (const feature of features.values()) {
27
+ for (const [entityName, entity] of Object.entries(feature.entities ?? {})) {
28
+ const lookupable = collectLookupableFields(entity);
29
+ if (lookupable.length === 0)
30
+ continue;
31
+ // No featureName prefix — the dispatcher builds entity tables without
32
+ // one (buildEntityTable with no featureName option), the sweep has to
33
+ // hit the same names.
34
+ candidates.push({
35
+ tableName: resolveTableName(entityName, entity, undefined),
36
+ lookupable,
37
+ });
38
+ }
33
39
  }
34
- }
35
- // Skip entities whose projection was never migrated — same class as
36
- // subjectRowExistsInTenant. A throw here runs AFTER eraseKey
37
- // in forget-subject and would leave deterministic bidx columns still
38
- // linkable. One batched existence query instead of one
39
- // roundtrip per entity.
40
- const existing = await existingTableNames(db, candidates.map((c) => c.tableName));
41
- for (const { tableName, lookupable } of candidates) {
42
- if (!existing.has(tableName))
43
- continue;
44
- // Same hazard for a migrated table that predates a later-added
45
- // lookupable field: skip fields whose columns are missing instead of
46
- // aborting the sweep for the remaining ones.
47
- const columns = await columnNamesOf(db, tableName);
48
- for (const fieldName of lookupable) {
49
- const snake = toSnakeCase(fieldName);
50
- if (!columns.has(snake) || !columns.has(`${snake}_bidx`))
40
+ // Skip entities whose projection was never migrated — same class as
41
+ // subjectRowExistsInTenant. A throw here runs AFTER eraseKey
42
+ // in forget-subject and would leave deterministic bidx columns still
43
+ // linkable. One batched existence query instead of one
44
+ // roundtrip per entity.
45
+ const existing = await existingTableNames(db, candidates.map((c) => c.tableName));
46
+ for (const { tableName, lookupable } of candidates) {
47
+ if (!existing.has(tableName))
51
48
  continue;
52
- await executeRawQuery(db, `UPDATE ${quoteIdent(tableName)} SET ${quoteIdent(`${snake}_bidx`)} = NULL WHERE ${quoteIdent(snake)} LIKE $1`, [likePattern]);
49
+ // Same hazard for a migrated table that predates a later-added
50
+ // lookupable field: skip fields whose columns are missing instead of
51
+ // aborting the sweep for the remaining ones.
52
+ const columns = await columnNamesOf(db, tableName);
53
+ for (const fieldName of lookupable) {
54
+ const snake = toSnakeCase(fieldName);
55
+ if (!columns.has(snake) || !columns.has(`${snake}_bidx`))
56
+ continue;
57
+ await executeRawQuery(db, `UPDATE ${quoteIdent(tableName)} SET ${quoteIdent(`${snake}_bidx`)} = NULL WHERE ${quoteIdent(snake)} LIKE $1`, [likePattern]);
58
+ }
53
59
  }
54
- }
60
+ });
55
61
  }
56
62
  async function existingTableNames(db, tableNames) {
57
63
  if (tableNames.length === 0)
@@ -75,37 +81,39 @@ async function existingTableNames(db, tableNames) {
75
81
  // (`aggregate_id = subjectId` under the actor tenant) when apps need
76
82
  // client-supplied ids.
77
83
  export async function subjectRowExistsInTenant(db, features, subjectId, tenantId) {
78
- // Prefetch which self-PII projection tables actually exist — probing a
79
- // missing relation used to throw (and get swallowed), which both hid
80
- // real schema bugs and risked poisoning the driver connection for the
81
- // rest of the forget TX.
82
- const candidateTables = [];
83
- for (const feature of features.values()) {
84
- for (const [entityName, entity] of Object.entries(feature.entities ?? {})) {
85
- const hasSelfPiiField = Object.values(entity.fields).some(isSelfPiiField);
86
- if (!hasSelfPiiField)
87
- continue;
88
- // Subject ids are uuids; comparing one to a serial id column makes
89
- // postgres throw (invalid input syntax for integer) mid forget-TX.
90
- if (entity.idType === "serial")
84
+ return runInSystemRowLevelSecurityScope("subject existence check spans tenants", async () => {
85
+ // Prefetch which self-PII projection tables actually exist — probing a
86
+ // missing relation used to throw (and get swallowed), which both hid
87
+ // real schema bugs and risked poisoning the driver connection for the
88
+ // rest of the forget TX.
89
+ const candidateTables = [];
90
+ for (const feature of features.values()) {
91
+ for (const [entityName, entity] of Object.entries(feature.entities ?? {})) {
92
+ const hasSelfPiiField = Object.values(entity.fields).some(isSelfPiiField);
93
+ if (!hasSelfPiiField)
94
+ continue;
95
+ // Subject ids are uuids; comparing one to a serial id column makes
96
+ // postgres throw (invalid input syntax for integer) mid forget-TX.
97
+ if (entity.idType === "serial")
98
+ continue;
99
+ candidateTables.push(resolveTableName(entityName, entity, undefined));
100
+ }
101
+ }
102
+ const existing = new Set();
103
+ for (const tableName of candidateTables) {
104
+ const rows = await executeRawQueryRead(db, `SELECT to_regclass(quote_ident($1)) IS NOT NULL AS exists`, [tableName]);
105
+ if (rows[0]?.exists === true)
106
+ existing.add(tableName);
107
+ }
108
+ for (const tableName of candidateTables) {
109
+ if (!existing.has(tableName))
91
110
  continue;
92
- candidateTables.push(resolveTableName(entityName, entity, undefined));
111
+ const rows = await executeRawQueryRead(db, `SELECT 1 FROM ${quoteIdent(tableName)} WHERE id = $1 AND tenant_id = $2 LIMIT 1`, [subjectId, tenantId]);
112
+ if (rows.length > 0)
113
+ return true;
93
114
  }
94
- }
95
- const existing = new Set();
96
- for (const tableName of candidateTables) {
97
- const rows = await executeRawQueryRead(db, `SELECT to_regclass(quote_ident($1)) IS NOT NULL AS exists`, [tableName]);
98
- if (rows[0]?.exists === true)
99
- existing.add(tableName);
100
- }
101
- for (const tableName of candidateTables) {
102
- if (!existing.has(tableName))
103
- continue;
104
- const rows = await executeRawQueryRead(db, `SELECT 1 FROM ${quoteIdent(tableName)} WHERE id = $1 AND tenant_id = $2 LIMIT 1`, [subjectId, tenantId]);
105
- if (rows.length > 0)
106
- return true;
107
- }
108
- return false;
115
+ return false;
116
+ });
109
117
  }
110
118
  function findEntityByExactName(features, entityName) {
111
119
  for (const feature of features.values()) {
@@ -123,14 +131,16 @@ function findEntityByExactName(features, entityName) {
123
131
  // table (globally unique, unspoofable via a client-supplied explicitId
124
132
  // at create) — a composite PK or shared table would break this.
125
133
  export async function recordRowExistsInTenant(db, features, entityName, recordId, tenantId) {
126
- const entity = findEntityByExactName(features, entityName);
127
- if (!entity)
128
- return false;
129
- const tableName = resolveTableName(entityName, entity, undefined);
130
- if (!(await tableExists(db, tableName)))
131
- return false;
132
- const rows = await executeRawQueryRead(db, `SELECT 1 FROM ${quoteIdent(tableName)} WHERE id = $1 AND tenant_id = $2 LIMIT 1`, [recordId, tenantId]);
133
- return rows.length > 0;
134
+ return runInSystemRowLevelSecurityScope("record existence check spans tenants", async () => {
135
+ const entity = findEntityByExactName(features, entityName);
136
+ if (!entity)
137
+ return false;
138
+ const tableName = resolveTableName(entityName, entity, undefined);
139
+ if (!(await tableExists(db, tableName)))
140
+ return false;
141
+ const rows = await executeRawQueryRead(db, `SELECT 1 FROM ${quoteIdent(tableName)} WHERE id = $1 AND tenant_id = $2 LIMIT 1`, [recordId, tenantId]);
142
+ return rows.length > 0;
143
+ });
134
144
  }
135
145
  // Provenance fallback for record subjects whose projection row is gone (hard
136
146
  // delete) or that have no registered entity at all (custom aggregates): the
@@ -138,20 +148,24 @@ export async function recordRowExistsInTenant(db, features, entityName, recordId
138
148
  // and the subject key is global, so another tenant could open a stream under
139
149
  // the same aggregate id; any foreign event voids the proof.
140
150
  export async function recordEventsOwnedExclusivelyByTenant(db, aggregateType, aggregateId, tenantId) {
141
- const rows = await executeRawQueryRead(db, `SELECT 1 FROM "kumiko_events" WHERE aggregate_type = $1 AND aggregate_id = $2::uuid AND tenant_id = $3::uuid
151
+ return runInSystemRowLevelSecurityScope("record event ownership check spans tenants", async () => {
152
+ const rows = await executeRawQueryRead(db, `SELECT 1 FROM "kumiko_events" WHERE aggregate_type = $1 AND aggregate_id = $2::uuid AND tenant_id = $3::uuid
142
153
  AND NOT EXISTS (SELECT 1 FROM "kumiko_events" WHERE aggregate_type = $1 AND aggregate_id = $2::uuid AND tenant_id <> $3::uuid)
143
154
  LIMIT 1`, [aggregateType, aggregateId, tenantId]);
144
- return rows.length > 0;
155
+ return rows.length > 0;
156
+ });
145
157
  }
146
158
  // Owning tenant of a record subject's row, for callers that must evaluate
147
159
  // tenant-scoped policy for the row's real owner (not the acting user's tenant).
148
160
  export async function recordRowOwningTenantId(db, features, entityName, recordId) {
149
- const entity = findEntityByExactName(features, entityName);
150
- if (!entity)
151
- return undefined;
152
- const tableName = resolveTableName(entityName, entity, undefined);
153
- if (!(await tableExists(db, tableName)))
154
- return undefined;
155
- const rows = await executeRawQueryRead(db, `SELECT tenant_id FROM ${quoteIdent(tableName)} WHERE id = $1 LIMIT 1`, [recordId]);
156
- return rows[0]?.tenant_id;
161
+ return runInSystemRowLevelSecurityScope("record owner lookup spans tenants", async () => {
162
+ const entity = findEntityByExactName(features, entityName);
163
+ if (!entity)
164
+ return undefined;
165
+ const tableName = resolveTableName(entityName, entity, undefined);
166
+ if (!(await tableExists(db, tableName)))
167
+ return undefined;
168
+ const rows = await executeRawQueryRead(db, `SELECT tenant_id FROM ${quoteIdent(tableName)} WHERE id = $1 LIMIT 1`, [recordId]);
169
+ return rows[0]?.tenant_id;
170
+ });
157
171
  }
@@ -5,7 +5,7 @@ import { extractPgError } from "./pg-error.js";
5
5
  // A pool can briefly keep handing out connections the server just closed.
6
6
  // Each failed attempt discards one, so retries are bounded by pool size.
7
7
  const CLOSED_CONNECTION_CODES = new Set([
8
- "CONNECTION_CLOSED", // postgres-js
8
+ "ERR_POSTGRES_CONNECTION_CLOSED", // Bun.SQL
9
9
  "57P01", // PG SQLSTATE: admin_shutdown / terminated backend
10
10
  ]);
11
11
  export function isClosedConnectionError(err) {
@@ -21,40 +21,33 @@ export function isPooledClient(raw) {
21
21
  typeof propertyOf(raw, "savepoint") !== "function" &&
22
22
  typeof propertyOf(raw, "release") !== "function");
23
23
  }
24
- const closedConnectionLog = createFallbackLogger("postgres-js");
25
- // The driver rejects in-flight queries with this AbortError (no code) when the
26
- // pool closes under them, so isClosedConnectionError can't see it.
27
- const DRIVER_CLOSED_ABORT_MESSAGE = "The connection was closed.";
28
- function isDriverClosedAbort(err) {
29
- return (err instanceof Error && err.name === "AbortError" && err.message === DRIVER_CLOSED_ABORT_MESSAGE);
30
- }
24
+ const closedConnectionLog = createFallbackLogger("bun-sql");
31
25
  function isHandleLike(raw) {
32
26
  return raw !== null && (typeof raw === "object" || typeof raw === "function");
33
27
  }
34
- // postgres-js pool and tx handles both carry `typed`.
28
+ // Bun.SQL pool and tx handles both carry `flush`.
35
29
  function driverOf(raw) {
36
30
  if (!isHandleLike(raw))
37
31
  return "unknown";
38
- if (typeof raw["typed"] === "function")
39
- return "postgres-js";
32
+ if (typeof raw["flush"] === "function")
33
+ return "bun-sql";
40
34
  return "unknown";
41
35
  }
42
36
  function positiveNumber(v) {
43
37
  return typeof v === "number" && Number.isFinite(v) && v > 0 ? v : undefined;
44
38
  }
45
- // postgres-js configures timeouts in seconds.
39
+ // Bun.SQL reports its timeout options in milliseconds.
46
40
  function timeoutOptionMs(options, driver, optionName) {
47
- if (driver !== "postgres-js")
41
+ if (driver !== "bun-sql")
48
42
  return undefined;
49
- const seconds = positiveNumber(options[optionName]);
50
- return seconds === undefined ? undefined : seconds * 1000;
43
+ return positiveNumber(options[optionName]);
51
44
  }
52
45
  function errorProp(err, name) {
53
46
  return isHandleLike(err) ? err[name] : undefined;
54
47
  }
55
48
  // Deliberately excludes SQL text and parameters: app SQL can carry PII.
56
49
  export function describeClosedConnectionFailure(raw, err, attempts) {
57
- if (!isClosedConnectionError(err) && !isDriverClosedAbort(err))
50
+ if (!isClosedConnectionError(err))
58
51
  return undefined;
59
52
  const driver = driverOf(raw);
60
53
  const rawOptions = isHandleLike(raw) ? raw["options"] : undefined;
@@ -64,9 +57,9 @@ export function describeClosedConnectionFailure(raw, err, attempts) {
64
57
  pooled: isPooledClient(raw),
65
58
  attempts,
66
59
  poolMax: positiveNumber(options["max"]),
67
- idleTimeoutMs: timeoutOptionMs(options, driver, "idle_timeout"),
68
- maxLifetimeMs: timeoutOptionMs(options, driver, "max_lifetime"),
69
- connectionTimeoutMs: timeoutOptionMs(options, driver, "connect_timeout"),
60
+ idleTimeoutMs: timeoutOptionMs(options, driver, "idleTimeout"),
61
+ maxLifetimeMs: timeoutOptionMs(options, driver, "maxLifetime"),
62
+ connectionTimeoutMs: timeoutOptionMs(options, driver, "connectionTimeout"),
70
63
  errorName: errorProp(err, "name"),
71
64
  errorCode: extractPgError(err)?.code ?? errorProp(err, "code"),
72
65
  errorErrno: errorProp(err, "errno"),
@@ -1,7 +1,7 @@
1
1
  // Canonical table source for both `kumiko schema generate` and setupTestStack
2
2
  // (entities, storeTables, projections, multiStreamProjections). One shared
3
3
  // source so the test-DB push and migrations cannot drift apart again.
4
- import { compareByCodepoint } from "../utils/index.js";
4
+ import { compareByCodepoint } from "../utils/compare.js";
5
5
  import { assertBackingTableSuperset, deriveEntityTableMeta, } from "./entity-table-meta.js";
6
6
  import { enumerateFeatureTableSources } from "./feature-table-sources.js";
7
7
  import { asEntityTableMeta } from "./query.js";
@@ -1,4 +1,4 @@
1
- import type { EntityDefinition } from "../engine/types/index.ts";
1
+ import type { EntityDefinition } from "@cosmicdrift/kumiko-types/fields";
2
2
  /**
3
3
  * API-Form (combined) → DB-Form (flat). Wird vor jedem Insert/Update aufgerufen.
4
4
  */
@@ -1,10 +1,3 @@
1
- // Compound-type pipeline for the executor.
2
- //
3
- // A compound type is a field represented by ONE API object and MULTIPLE
4
- // DB columns. Examples:
5
- // - locatedTimestamp: { at, tz, utc } ↔ <name>Utc + <name>Tz
6
- // - money: { amount, currency } ↔ <name> + <name>Currency
7
- // - (upcoming) address: { street, zip, city } ↔ <name>Street + <name>Zip + <name>City
8
1
  //
9
2
  // Instead of nesting every helper in the executor at four different points,
10
3
  // this function pipelines all compound-type conversions in one pass. Adding
@@ -1,5 +1,6 @@
1
+ import type { ConfigSeedDef } from "@cosmicdrift/kumiko-types/config";
1
2
  import type { EntityDefinition } from "../engine/index.ts";
2
- import type { ConfigSeedDef, Registry } from "../engine/types/index.ts";
3
+ import type { Registry } from "../engine/types/index.ts";
3
4
  import type { EnvelopeCipher } from "../secrets/envelope-cipher.ts";
4
5
  import type { DbConnection } from "./connection.ts";
5
6
  import type { EntityTable } from "./table-builder.ts";
@@ -24,7 +24,12 @@ export async function seedConfigValues(seeds, table, entity, registry, db, ciphe
24
24
  return { created, skipped };
25
25
  const systemUser = createSystemUser(SYSTEM_TENANT_ID);
26
26
  const executor = createEventStoreExecutor(table, entity, { entityName: "config-value" });
27
- const tdb = createTenantDb({ db, tenantId: SYSTEM_TENANT_ID, mode: "system" });
27
+ const tdb = createTenantDb({
28
+ db,
29
+ tenantId: SYSTEM_TENANT_ID,
30
+ mode: "system",
31
+ reason: "config seeds are system-tenant defaults",
32
+ });
28
33
  for (const seed of seeds) {
29
34
  const keyDef = registry.getConfigKey(seed.key);
30
35
  if (!keyDef) {
@@ -1,24 +1,25 @@
1
- import type { DbConnection, PgClient } from "@cosmicdrift/kumiko-types/db-connection";
2
- import postgres from "postgres";
1
+ import type { DbConnection, PgClient, PgListenClient } from "@cosmicdrift/kumiko-types/db-connection";
2
+ import { type RowLevelSecurityMode } from "./render-rls-ddl.ts";
3
3
  export type * from "@cosmicdrift/kumiko-types/db-connection";
4
- type PostgresDriverOptions = NonNullable<Parameters<typeof postgres>[1]>;
4
+ type BunSqlOptions = Bun.SQL.PostgresOrMySQLOptions;
5
5
  export type DbConnectionOptions = {
6
6
  readonly maxConnections?: number;
7
7
  readonly idleTimeoutSeconds?: number;
8
8
  readonly connectTimeoutSeconds?: number;
9
9
  readonly closeTimeoutSeconds?: number;
10
- readonly ssl?: PostgresDriverOptions["ssl"];
11
- readonly onNotice?: (notice: postgres.Notice) => void;
10
+ readonly ssl?: BunSqlOptions["tls"];
12
11
  readonly statementTimeoutMs?: number;
13
12
  readonly idleInTransactionSessionTimeoutMs?: number;
14
13
  readonly lockTimeoutMs?: number;
15
14
  };
16
15
  export type CreateDbConnectionOptions = DbConnectionOptions & {
17
16
  readonly url: string;
17
+ readonly rowLevelSecurity?: RowLevelSecurityMode;
18
18
  };
19
19
  export type DbConnectionHandle = {
20
20
  db: DbConnection;
21
21
  client: PgClient;
22
+ listenClient: PgListenClient;
22
23
  close: () => Promise<void>;
23
24
  };
24
25
  export declare const DEFAULT_DB_CLOSE_TIMEOUT_SECONDS = 5;
@@ -27,7 +28,7 @@ export type UnboundedSiblingPool = {
27
28
  readonly close: (timeoutSeconds: number) => Promise<void>;
28
29
  };
29
30
  export declare function openUnboundedSiblingPool(db: unknown): UnboundedSiblingPool | undefined;
30
- export declare function createDbConnection({ url, ...options }: CreateDbConnectionOptions): DbConnectionHandle;
31
+ export declare function createDbConnection({ url, rowLevelSecurity, ...options }: CreateDbConnectionOptions): DbConnectionHandle;
31
32
  export declare function dbConnectionOptionsFromEnv(env?: Readonly<Record<string, string | undefined>>): DbConnectionOptions;
32
33
  export declare const DEFAULT_SERVER_STATEMENT_TIMEOUT_MS = 60000;
33
34
  export declare const DEFAULT_SERVER_IDLE_IN_TRANSACTION_TIMEOUT_MS = 300000;
@@ -1,7 +1,8 @@
1
- import postgres from "postgres";
2
1
  import { readPositiveIntEnv } from "../utils/env-parse.js";
2
+ import { DEFAULT_ROW_LEVEL_SECURITY_MODE } from "./render-rls-ddl.js";
3
+ import { enforceRowLevelSecurity } from "./row-level-security-connection.js";
3
4
  // A DB outage can leave an in-flight query referenced on a dead connection,
4
- // so a plain end() (no timeout = wait for queries to finish) hangs forever —
5
+ // so a plain close() (no timeout = wait for queries to finish) hangs forever —
5
6
  // close() must always bound how long shutdown waits.
6
7
  export const DEFAULT_DB_CLOSE_TIMEOUT_SECONDS = 5;
7
8
  // Keyed by the pool so withoutStatementTimeout can open a sibling with identical connect options.
@@ -11,20 +12,28 @@ export function openUnboundedSiblingPool(db) {
11
12
  return undefined;
12
13
  return unboundedSiblingFactories.get(db)?.();
13
14
  }
14
- export function createDbConnection({ url, ...options }) {
15
- const pgOptions = {};
15
+ // Bun.SQL treats `true` and a TLS object without rejectUnauthorized as sslmode=require, which
16
+ // skips certificate checks; postgres-js verified in both cases, so keep that unless turned off.
17
+ function verifiedTls(ssl) {
18
+ if (ssl === true)
19
+ return "verify-full";
20
+ if (typeof ssl === "object" && !(ssl instanceof Blob) && ssl.rejectUnauthorized === undefined) {
21
+ return { ...ssl, rejectUnauthorized: true };
22
+ }
23
+ return ssl;
24
+ }
25
+ export function createDbConnection({ url, rowLevelSecurity = DEFAULT_ROW_LEVEL_SECURITY_MODE, ...options }) {
26
+ const sqlOptions = {};
16
27
  if (options.maxConnections !== undefined)
17
- pgOptions.max = options.maxConnections;
28
+ sqlOptions.max = options.maxConnections;
18
29
  if (options.idleTimeoutSeconds !== undefined) {
19
- pgOptions.idle_timeout = options.idleTimeoutSeconds;
30
+ sqlOptions.idleTimeout = options.idleTimeoutSeconds;
20
31
  }
21
32
  if (options.connectTimeoutSeconds !== undefined) {
22
- pgOptions.connect_timeout = options.connectTimeoutSeconds;
33
+ sqlOptions.connectionTimeout = options.connectTimeoutSeconds;
23
34
  }
24
35
  if (options.ssl !== undefined)
25
- pgOptions.ssl = options.ssl;
26
- if (options.onNotice !== undefined)
27
- pgOptions.onnotice = options.onNotice;
36
+ sqlOptions.tls = verifiedTls(options.ssl);
28
37
  const serverParameters = {};
29
38
  if (options.statementTimeoutMs !== undefined) {
30
39
  serverParameters["statement_timeout"] = options.statementTimeoutMs;
@@ -36,48 +45,58 @@ export function createDbConnection({ url, ...options }) {
36
45
  if (options.lockTimeoutMs !== undefined)
37
46
  serverParameters["lock_timeout"] = options.lockTimeoutMs;
38
47
  if (Object.keys(serverParameters).length > 0)
39
- pgOptions.connection = serverParameters;
40
- const client = postgres(url, pgOptions);
48
+ sqlOptions.connection = serverParameters;
49
+ // Bun.SQL opens all `max` connections on the first query, so a pool always costs `max` backends.
50
+ const rawClient = new Bun.SQL(url, sqlOptions);
51
+ const enforced = rowLevelSecurity === "on";
52
+ const client = enforced ? enforceRowLevelSecurity(rawClient) : rawClient;
41
53
  // A run that never settles (a caller gave up on it via its own timeout) never reaches the
42
54
  // sibling's own close; close() ends it so shutdown and DROP DATABASE are not blocked by it.
43
55
  const openSiblings = new Set();
44
- unboundedSiblingFactories.set(client, () => {
56
+ const registerFactory = (factory) => {
57
+ unboundedSiblingFactories.set(rawClient, factory);
58
+ if (client !== rawClient)
59
+ unboundedSiblingFactories.set(client, factory);
60
+ };
61
+ registerFactory(() => {
45
62
  // Two connections are enough for lock-in-tx plus DDL; the cap keeps parallel rebuilds from exhausting max_connections.
46
- const sibling = postgres(url, {
47
- ...pgOptions,
63
+ const sibling = new Bun.SQL(url, {
64
+ ...sqlOptions,
48
65
  max: 4,
49
- connection: { ...pgOptions.connection, statement_timeout: 0 },
66
+ connection: { ...sqlOptions.connection, statement_timeout: 0 },
50
67
  });
51
68
  openSiblings.add(sibling);
52
69
  return {
53
- client: sibling,
70
+ client: enforced ? enforceRowLevelSecurity(sibling) : sibling,
54
71
  close: async (timeoutSeconds) => {
55
72
  openSiblings.delete(sibling);
56
- await sibling.end({ timeout: timeoutSeconds });
73
+ await sibling.close({ timeout: timeoutSeconds });
57
74
  },
58
75
  };
59
76
  });
60
77
  return {
61
78
  db: client,
62
79
  client,
80
+ listenClient: client,
63
81
  close: async () => {
64
82
  const timeout = options.closeTimeoutSeconds ?? DEFAULT_DB_CLOSE_TIMEOUT_SECONDS;
83
+ unboundedSiblingFactories.delete(rawClient);
65
84
  unboundedSiblingFactories.delete(client);
66
- const pools = [client, ...openSiblings];
85
+ const pools = [rawClient, ...openSiblings];
67
86
  openSiblings.clear();
68
- const results = await Promise.allSettled(pools.map((pool) => pool.end({ timeout })));
87
+ const results = await Promise.allSettled(pools.map((pool) => pool.close({ timeout })));
69
88
  const failure = results.find((result) => result.status === "rejected");
70
89
  if (failure !== undefined)
71
90
  throw failure.reason;
72
91
  },
73
92
  };
74
93
  }
75
- // DB_PROVIDER=bun selected the removed Bun.SQL driver; ignoring it would boot
76
- // postgres-js under a config that still claims Bun.SQL.
94
+ // DB_PROVIDER once selected between drivers; a config that still sets it is stale,
95
+ // so fail loudly instead of silently ignoring it.
77
96
  function assertNoRemovedDbProvider(env) {
78
97
  const provider = env["DB_PROVIDER"];
79
- if (provider !== undefined && provider !== "" && provider !== "postgres") {
80
- throw new Error(`DB_PROVIDER="${provider}" is no longer supported: postgres-js is the only driver. Remove DB_PROVIDER from the environment.`);
98
+ if (provider !== undefined && provider !== "") {
99
+ throw new Error(`DB_PROVIDER="${provider}" is no longer supported: Bun.SQL is the only driver. Remove DB_PROVIDER from the environment.`);
81
100
  }
82
101
  }
83
102
  export function dbConnectionOptionsFromEnv(env = process.env) {
@@ -1,5 +1,5 @@
1
+ import type { EscapeHatchReporter } from "@cosmicdrift/kumiko-types/handlers";
1
2
  import type { CrossTenantReads } from "@cosmicdrift/kumiko-types/tenant-db-types";
2
- import type { EscapeHatchReporter } from "../engine/types/index.ts";
3
3
  import { type CreateTenantDbOptions, type TenantDb } from "./tenant-db.ts";
4
4
  export declare function createCrossTenantReads(systemModeDb: TenantDb, reason: string, report: EscapeHatchReporter): CrossTenantReads;
5
5
  export declare function createHandlerCrossTenantReads(options: Omit<CreateTenantDbOptions, "mode"> & {
@@ -18,6 +18,6 @@ export function createCrossTenantReads(systemModeDb, reason, report) {
18
18
  // Own system-mode TenantDb without unsafeRaw/globalWrites: the handler gets the read surface only.
19
19
  export function createHandlerCrossTenantReads(options) {
20
20
  const { reason, report, ...dbOptions } = options;
21
- const systemModeDb = createTenantDb({ ...dbOptions, mode: "system" });
21
+ const systemModeDb = createTenantDb({ ...dbOptions, mode: "system", reason });
22
22
  return createCrossTenantReads(systemModeDb, reason, report);
23
23
  }
@@ -4,7 +4,6 @@ import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
4
4
  import type { PgType } from "./entity-table-meta.ts";
5
5
  export type { ColumnHandle, SchemaTable } from "@cosmicdrift/kumiko-types/schema-table-types";
6
6
  export type TableColumns<_T = unknown> = SchemaTable;
7
- export type SelectQuery = unknown;
8
7
  export declare function pgTypeToSqlType(pgType: PgType): string;
9
8
  type ColumnFinal = {
10
9
  readonly sqlName: string;
@@ -46,10 +45,6 @@ export declare function timestamp(name: string, _opts?: {
46
45
  withTimezone?: boolean;
47
46
  mode?: "string" | "date";
48
47
  }): ColumnBuilder<Temporal.Instant | string>;
49
- export declare function numeric(name: string, _opts?: {
50
- precision?: number;
51
- scale?: number;
52
- }): ColumnBuilder<string>;
53
48
  export declare function instant(name: string, opts?: {
54
49
  precision?: 0 | 1 | 2 | 3 | 4 | 5 | 6;
55
50
  }): ColumnBuilder<Temporal.Instant>;
@@ -180,9 +180,6 @@ export function timestamp(name, _opts) {
180
180
  }
181
181
  // numeric → text (we don't currently use Decimal); kept for compat with
182
182
  // legacy schema imports that won't actually instantiate at runtime.
183
- export function numeric(name, _opts) {
184
- return buildColumn(name, "text");
185
- }
186
183
  export function instant(name, opts) {
187
184
  const pgType = opts?.precision === 3 ? "timestamptz(3)" : "timestamptz";
188
185
  return buildColumn(name, pgType);