@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
@@ -0,0 +1,48 @@
1
+ import { emitDbQuery } from "../observability/standard-metrics.js";
2
+ import { runInRowLevelSecurityScope, tenantDbRowLevelSecurityScope, } from "./row-level-security-scope.js";
3
+ import { tableNameOf } from "./table-introspection.js";
4
+ export function createTenantDbStatementRunner({ tracer, meter, signal, mode, reason, tenantId, }) {
5
+ return function withDbSpan(operation, table, runner) {
6
+ signal?.throwIfAborted();
7
+ const scope = tenantDbRowLevelSecurityScope(mode === "system" ? { mode, reason } : { mode }, tenantId, table);
8
+ const scopedRunner = () => runInRowLevelSecurityScope(scope, runner);
9
+ if (!tracer && !meter)
10
+ return scopedRunner();
11
+ const tableName = tableNameOf(table);
12
+ const start = performance.now();
13
+ const emitMetric = () => {
14
+ if (meter) {
15
+ emitDbQuery(meter, { operation, table: tableName }, (performance.now() - start) / 1000);
16
+ }
17
+ };
18
+ if (!tracer) {
19
+ return (async () => {
20
+ try {
21
+ return await scopedRunner();
22
+ }
23
+ finally {
24
+ emitMetric();
25
+ }
26
+ })();
27
+ }
28
+ return tracer.withSpan("db.query", {
29
+ kind: "client",
30
+ attributes: {
31
+ "db.system": "postgresql",
32
+ "db.operation": operation,
33
+ "db.table": tableName,
34
+ },
35
+ }, async (span) => {
36
+ try {
37
+ const result = await scopedRunner();
38
+ if (Array.isArray(result)) {
39
+ span.setAttribute("db.row_count", result.length);
40
+ }
41
+ return result;
42
+ }
43
+ finally {
44
+ emitMetric();
45
+ }
46
+ });
47
+ };
48
+ }
@@ -0,0 +1,5 @@
1
+ import type { TenantDbMode, TenantDbUpsertOptions } from "@cosmicdrift/kumiko-types/tenant-db-types";
2
+ import { AccessDeniedError } from "../errors/index.ts";
3
+ import { type AnyDb, type TableLike } from "./query.ts";
4
+ export declare function upsertTableDenied(table: TableLike, mode: TenantDbMode): AccessDeniedError | undefined;
5
+ export declare function upsertTenantRow<TRow>(db: AnyDb, table: TableLike, values: Record<string, unknown>, options: TenantDbUpsertOptions): Promise<TRow | undefined>;
@@ -0,0 +1,91 @@
1
+ import { quoteIdent } from "../crypto/ciphertext-pattern.js";
2
+ import { AccessDeniedError } from "../errors/index.js";
3
+ import { isExecutorManagedTable } from "./executor-managed-tables.js";
4
+ import { buildInsertSql, coerceRow, conflictUpdateParts, insertEntries, unsafeLoggingClosedConnection, } from "./query.js";
5
+ import { extractTableInfo } from "./table-info.js";
6
+ import { asEntityTableMeta, tableNameOf } from "./table-introspection.js";
7
+ const TENANT_COLUMN = "tenant_id";
8
+ // Upsert is never allowed on event-fed tables (even with the write capability) and has no tenant-mode meaning for "global" ones.
9
+ export function upsertTableDenied(table, mode) {
10
+ if (isExecutorManagedTable(table)) {
11
+ return new AccessDeniedError({
12
+ message: `ctx.db.upsert(${tableNameOf(table)}): table is fed by events; upsert is not supported on it.`,
13
+ });
14
+ }
15
+ if (mode === "tenant" && asEntityTableMeta(table)?.tenancy === "global") {
16
+ return new AccessDeniedError({
17
+ message: `ctx.db.upsert(${tableNameOf(table)}): "global" table rows must carry SYSTEM_TENANT_ID; ` +
18
+ "use db.global(table) with escapeHatch instead.",
19
+ });
20
+ }
21
+ return undefined;
22
+ }
23
+ function sameColumnSet(a, b) {
24
+ return a.length === b.length && new Set(a).size === a.length && a.every((c) => b.includes(c));
25
+ }
26
+ function declaredUniqueColumnSets(meta) {
27
+ const sets = meta.indexes
28
+ .filter((i) => i.unique === true && i.whereSql === undefined && i.needsManualWhere !== true)
29
+ .map((i) => i.columns);
30
+ if (meta.compositePrimaryKey)
31
+ sets.push(meta.compositePrimaryKey.columns);
32
+ const primaryKeyColumns = meta.columns.filter((c) => c.primaryKey).map((c) => c.name);
33
+ if (primaryKeyColumns.length > 0)
34
+ sets.push(primaryKeyColumns);
35
+ return sets;
36
+ }
37
+ function primaryKeyColumnsOf(meta) {
38
+ return [
39
+ ...meta.columns.filter((c) => c.primaryKey).map((c) => c.name),
40
+ ...(meta.compositePrimaryKey?.columns ?? []),
41
+ ];
42
+ }
43
+ function assertTenantSafeConflictTarget(tableName, meta, conflictCols) {
44
+ if (conflictCols.length === 0 || !conflictCols.includes(TENANT_COLUMN)) {
45
+ throw new Error(`tenantDb.upsert(${tableName}): conflictTarget must include "tenantId" — a target without it ` +
46
+ "could match, and overwrite, another tenant's row.");
47
+ }
48
+ if (!declaredUniqueColumnSets(meta).some((set) => sameColumnSet(set, conflictCols))) {
49
+ throw new Error(`tenantDb.upsert(${tableName}): conflictTarget (${conflictCols.join(", ")}) matches no ` +
50
+ "declared unique index (without a WHERE clause) or primary key.");
51
+ }
52
+ }
53
+ // Handles a tenant's own row only: values carry the tenant already, and the DO UPDATE guard
54
+ // compares against the tenant being inserted, so a conflict on another tenant's row updates nothing.
55
+ export async function upsertTenantRow(db, table, values, options) {
56
+ const info = extractTableInfo(table);
57
+ const meta = asEntityTableMeta(table);
58
+ if (!info.hasColumn("tenantId")) {
59
+ throw new Error(`tenantDb.upsert(${info.name}): table has no tenant column — use the free upsertOnConflict ` +
60
+ "helper on an unsafeRaw runner instead.");
61
+ }
62
+ if (!meta) {
63
+ throw new Error(`tenantDb.upsert(${info.name}): needs an EntityTableMeta table (declared unique indexes and primary key), got a table without meta.`);
64
+ }
65
+ const conflictCols = options.conflictTarget.map((field) => info.columnOf(field));
66
+ assertTenantSafeConflictTarget(info.name, meta, conflictCols);
67
+ if (options.update &&
68
+ Object.keys(options.update).some((f) => info.columnOf(f) === TENANT_COLUMN)) {
69
+ throw new Error(`tenantDb.upsert(${info.name}): update must not set "tenantId" — it would move the row into another tenant.`);
70
+ }
71
+ const entries = insertEntries(info, values);
72
+ if (!entries.some((e) => e.col === TENANT_COLUMN)) {
73
+ throw new Error(`tenantDb.upsert(${info.name}): values carry no tenantId.`);
74
+ }
75
+ const { sqlPrefix, params } = buildInsertSql(info, entries);
76
+ const skipCols = new Set([...conflictCols, ...primaryKeyColumnsOf(meta), TENANT_COLUMN]);
77
+ const setParts = conflictUpdateParts(info, entries, options.update, skipCols, params);
78
+ if (setParts.length === 0) {
79
+ throw new Error(`tenantDb.upsert(${info.name}): nothing to update on conflict`);
80
+ }
81
+ const tenantRef = quoteIdent(TENANT_COLUMN);
82
+ const sqlText = `${sqlPrefix} ON CONFLICT (${conflictCols.map((c) => quoteIdent(c)).join(", ")}) ` +
83
+ `DO UPDATE SET ${setParts.join(", ")} ` +
84
+ `WHERE ${quoteIdent(info.name)}.${tenantRef} = EXCLUDED.${tenantRef} RETURNING *`;
85
+ const rows = await unsafeLoggingClosedConnection(db, sqlText, params, {
86
+ operation: "tenantDb.upsert",
87
+ table: info.name,
88
+ });
89
+ const first = rows[0];
90
+ return first ? coerceRow(first, info) : undefined;
91
+ }
@@ -1,13 +1,13 @@
1
1
  import type { EntityTableMeta } from "@cosmicdrift/kumiko-types/entity-table-meta-types";
2
2
  import type { ExecutorManagedRunner } from "@cosmicdrift/kumiko-types/executor-brand";
3
- import type { EscapeHatchDeclaration, EscapeHatchReporter, EscapeHatchTarget } from "@cosmicdrift/kumiko-types/handlers";
3
+ import type { EscapeHatchDeclaration, EscapeHatchReporter, EscapeHatchTarget, HandlerDb } from "@cosmicdrift/kumiko-types/handlers";
4
+ import type { Meter, Tracer } from "@cosmicdrift/kumiko-types/observability";
4
5
  import type { SchemaTable } from "@cosmicdrift/kumiko-types/schema-table-types";
5
- import { type ExecutorManagedTenantDb, type TenantDb, type TenantDbMode, type UncheckedSystemDb } from "@cosmicdrift/kumiko-types/tenant-db-types";
6
+ import { type ExecutorManagedTenantDb, type TenantDb, type UncheckedSystemDb } from "@cosmicdrift/kumiko-types/tenant-db-types";
6
7
  import { asRawClient } from "../db/query.ts";
7
8
  import type { EntityDefinition } from "../engine/types/fields.ts";
8
9
  import { type TenantId } from "../engine/types/identifiers.ts";
9
10
  import type { Registry } from "../engine/types/index.ts";
10
- import { type Meter, type Tracer } from "../observability/index.ts";
11
11
  import type { DbRunner } from "./connection.ts";
12
12
  import { tableNameOf } from "./table-introspection.ts";
13
13
  type Table = SchemaTable;
@@ -19,10 +19,9 @@ export declare function unsafeRawForDeclaredStep(holder: TenantDb | UncheckedSys
19
19
  export declare function withSystemDbUnsafeRawGrant<T extends object>(systemDb: T, grant: EscapeHatchDeclaration | undefined, deniedCallerLabel: string): T | UncheckedSystemDb;
20
20
  export declare function createUncheckedSystemDb(db: TenantDb, dbOutsideTransaction?: TenantDb, report?: EscapeHatchReporter): UncheckedSystemDb;
21
21
  export declare function createSystemDbView(db: TenantDb, dbOutsideTransaction?: TenantDb, report?: EscapeHatchReporter): UncheckedSystemDb;
22
- export declare function scopeTenantDbToTenant(db: TenantDb, tenantId: TenantId): TenantDb;
23
22
  export declare function castTenantRows<T>(rows: readonly Record<string, unknown>[]): readonly T[];
23
+ export { requestedTenantIds } from "./tenant-id-filter.ts";
24
24
  export { tableNameOf };
25
- export declare function requestedTenantIds(requested: unknown): readonly unknown[] | undefined;
26
25
  export declare function hasTenantColumn(table: Table | EntityTableMeta): boolean;
27
26
  export type TenantDbGrants = {
28
27
  readonly globalWrites?: EscapeHatchDeclaration;
@@ -40,26 +39,32 @@ export declare function acknowledgeConventionCrossTenant(tenantDb: TenantDb, rea
40
39
  }): TenantDb;
41
40
  export declare function reportConventionCrossTenantUse(acknowledged: TenantDb, target?: EscapeHatchTarget): void;
42
41
  export type OutsideTransactionContext = {
43
- readonly dbOutsideTransaction: TenantDb | undefined;
42
+ readonly db: Pick<HandlerDb, "outsideTransaction">;
44
43
  };
45
- export declare function hasOutsideTransactionDb(ctx: OutsideTransactionContext): ctx is OutsideTransactionContext & {
46
- readonly dbOutsideTransaction: TenantDb;
44
+ export declare function hasOutsideTransactionDb(ctx: OutsideTransactionContext): ctx is {
45
+ readonly db: {
46
+ readonly outsideTransaction: TenantDb;
47
+ };
47
48
  };
48
49
  export declare function requireOutsideTransactionDb(ctx: OutsideTransactionContext): TenantDb;
49
- export declare function runInOwnTransaction<T>(tenantDb: TenantDb, fn: (txDb: TenantDb) => Promise<T>): Promise<T>;
50
50
  export type CreateTenantDbOptions = {
51
51
  readonly db: DbRunner;
52
52
  readonly tenantId: TenantId;
53
- readonly mode?: TenantDbMode;
54
53
  readonly tracer?: Tracer;
55
54
  readonly meter?: Meter;
56
55
  readonly signal?: AbortSignal;
57
56
  readonly grants?: TenantDbGrants;
58
- };
57
+ } & ({
58
+ readonly mode?: "tenant";
59
+ readonly reason?: undefined;
60
+ } | {
61
+ readonly mode: "system";
62
+ readonly reason: string;
63
+ });
59
64
  export declare function createTenantDb(options: CreateTenantDbOptions & {
60
65
  readonly db: ExecutorManagedRunner;
61
66
  }): ExecutorManagedTenantDb;
62
67
  export declare function createTenantDb(options: CreateTenantDbOptions): TenantDb;
63
- export declare function createTenantDataDestroyDb(options: Omit<CreateTenantDbOptions, "mode">): ExecutorManagedTenantDb;
68
+ export declare function createTenantDataDestroyDb(options: Omit<CreateTenantDbOptions, "mode" | "reason">): ExecutorManagedTenantDb;
64
69
  export declare function createProjectingTenantDb(db: DbRunner, tenantId: TenantId, projectionRegistry: Registry | undefined): TenantDb;
65
70
  export { asRawClient };
@@ -1,16 +1,23 @@
1
1
  import { SYSTEM_SCOPE_CHECK_BRAND, } from "@cosmicdrift/kumiko-types/tenant-db-types";
2
- import { isPlainObject } from "@cosmicdrift/kumiko-types/type-guards";
3
- import { asEntityTableMeta, asRawClient, aggregateWhere as bunAggregateWhere, countWhere as bunCountWhere, deleteMany as bunDeleteMany, fetchOne as bunFetchOne, insertOne as bunInsertOne, selectMany as bunSelectMany, updateMany as bunUpdateMany, runInNewTransaction, } from "../db/query.js";
2
+ import { asEntityTableMeta, asRawClient, aggregateWhere as bunAggregateWhere, countWhere as bunCountWhere, deleteMany as bunDeleteMany, fetchOne as bunFetchOne, insertOne as bunInsertOne, selectMany as bunSelectMany, updateMany as bunUpdateMany, } from "../db/query.js";
4
3
  import { assertReason } from "../engine/escape-hatch-reason.js";
5
4
  import { SYSTEM_TENANT_ID } from "../engine/types/identifiers.js";
6
- import { AccessDeniedError, InternalError, memberResolutionReadOnlyDenied, } from "../errors/index.js";
7
- import { emitDbQuery, fallbackEscapeHatchReporter, registerStandardMetrics, } from "../observability/index.js";
5
+ import { AccessDeniedError, InternalError } from "../errors/index.js";
6
+ import { memberResolutionReadOnlyDenied } from "../errors/member-resolution.js";
7
+ import { fallbackEscapeHatchReporter } from "../observability/escape-hatch-report.js";
8
+ import { registerStandardMetrics } from "../observability/standard-metrics.js";
8
9
  import { assertWritableTable, executorManagedWriteDenied, hasExecutorManagedWriteCapability, registerExecutorManagedWriteRunner, } from "./executor-managed-tables.js";
9
10
  import { bindProjectionRegistry, projectionRegistryOf } from "./projection-registry-binding.js";
10
11
  import { acquireNamespacedAdvisoryLock } from "./queries/advisory-lock.js";
11
12
  import { queryDatabaseNow } from "./queries/database-now.js";
13
+ import { systemModeOptions, unsafeRawScopedRunner, unscopedRunnerOf, } from "./row-level-security-scope.js";
12
14
  import { hasFieldProperty, tableNameOf } from "./table-introspection.js";
13
- import { bindTenantDbRunner, denyTenantDbWrites, tenantDbRunner, tenantDbWritesDeniedError, tenantDbWritesDeniedReason, } from "./tenant-db-runner.js";
15
+ import { bindTenantDbRunner, denyTenantDbWrites, tenantDbRunner, tenantDbWritesDeniedError, } from "./tenant-db-runner.js";
16
+ import { registerScopedRebinder } from "./tenant-db-scoped-rebind.js";
17
+ import { createTenantDbStatementRunner } from "./tenant-db-statement-runner.js";
18
+ import { upsertTableDenied, upsertTenantRow } from "./tenant-db-upsert.js";
19
+ import { isForeignTenantId, requestedTenantIds, tenantIdsAfterExclusion, } from "./tenant-id-filter.js";
20
+ import { registerRunnerProxyTarget } from "./transaction-serialization.js";
14
21
  export { SYSTEM_SCOPE_CHECK_BRAND, } from "@cosmicdrift/kumiko-types/tenant-db-types";
15
22
  const declaredUnsafeRawRunners = new WeakMap();
16
23
  // The CRUD executor writes through tenantDbRunner, not insertOne, so it asks the
@@ -36,7 +43,7 @@ function boundRunner(runner, gate, projectionRegistry, executorManagedWrites) {
36
43
  if (typeof value !== "function")
37
44
  return value;
38
45
  if (prop === "reserve") {
39
- // postgres-js hands back a raw connection; re-wrap it so the gate survives.
46
+ // The driver hands back a raw connection; re-wrap it so the gate survives.
40
47
  return async (...args) => {
41
48
  const reserved = await Reflect.apply(value, target, args);
42
49
  return boundRunner(reserved, gate, projectionRegistry, executorManagedWrites);
@@ -66,6 +73,7 @@ function boundRunner(runner, gate, projectionRegistry, executorManagedWrites) {
66
73
  return value.bind(target);
67
74
  },
68
75
  });
76
+ registerRunnerProxyTarget(proxy, runner);
69
77
  if (gate)
70
78
  runnerPersonalDataGates.set(proxy, gate);
71
79
  if (projectionRegistry)
@@ -165,9 +173,10 @@ function buildUncheckedSystemDb(db, dbOutsideTransaction, report, gate) {
165
173
  `${gate.deniedCallerLabel} to allow unsafeRaw.`,
166
174
  });
167
175
  }
176
+ // A granted unsafeRaw is a declared, audited bypass of the TenantDb filter, so row-level security does not narrow it either.
168
177
  // Engine-forwarded steps carry their own declared reason; a caller-supplied one never reaches the audit trail.
169
178
  report("unsafe-raw", forwardedDeclaredStep ? reason : (gate?.grant?.reason ?? reason));
170
- const runner = withoutExecutorManagedWrites(tenantDbRunner(db));
179
+ const runner = unsafeRawScopedRunner(withoutExecutorManagedWrites(tenantDbRunner(db)));
171
180
  return boundRunner(runner, personalDataGates.get(db), projectionRegistryOf(db), false);
172
181
  }
173
182
  const uncheckedSystemDb = {
@@ -233,10 +242,9 @@ function buildUncheckedSystemDb(db, dbOutsideTransaction, report, gate) {
233
242
  // own tenantId, never a foreign one.
234
243
  //
235
244
  // dbOutsideTransaction is optional so every existing single-arg call site
236
- // (jobs/job-runner.ts, tests) keeps compiling — those callers have no
237
- // outside-tx source to hand in and never needed one. Only
238
- // buildHandlerContext passes it, which is also the only place `.outsideTransaction`
239
- // is reachable through `ctx.systemDb`.
245
+ // (jobs/job-runner.ts, tests) keeps compiling — those callers have no outside-tx
246
+ // source to hand in. Only buildHandlerContext passes it, which is also the only
247
+ // place `.outsideTransaction` is reachable through `ctx.systemDb`.
240
248
  //
241
249
  // Ungated here (the handler's own systemScope() is the grant); a hook's own
242
250
  // escapeHatch is layered on afterwards via withSystemDbUnsafeRawGrant. Public
@@ -251,55 +259,16 @@ export function createUncheckedSystemDb(db, dbOutsideTransaction, report = fallb
251
259
  export function createSystemDbView(db, dbOutsideTransaction, report = fallbackEscapeHatchReporter(db.tenantId)) {
252
260
  return buildUncheckedSystemDb(db, dbOutsideTransaction, report, { kind: "source-tenant-db" });
253
261
  }
254
- // Narrows a (possibly "system"-mode) TenantDb to a "tenant"-mode handle for one tenant on the
255
- // same connection/transaction. For code that must run caller-supplied callbacks (e.g. config
256
- // validators) without handing them a cross-tenant view.
257
- export function scopeTenantDbToTenant(db, tenantId) {
258
- const writesDeniedReason = tenantDbWritesDeniedReason(db);
259
- return createTenantDb({
260
- db: tenantDbRunner(db),
261
- tenantId,
262
- mode: "tenant",
263
- ...(writesDeniedReason !== undefined && { grants: { writesDeniedReason } }),
264
- });
265
- }
266
262
  // @cast-boundary tenant-db-row
267
263
  export function castTenantRows(rows) {
268
264
  return rows;
269
265
  }
266
+ export { requestedTenantIds } from "./tenant-id-filter.js";
270
267
  export { tableNameOf };
271
268
  // A grant is only real when its reason is non-empty — `{ reason: "" }` must not silently unlock it.
272
269
  function hasGrant(decl) {
273
270
  return decl !== undefined && decl.reason.trim().length > 0;
274
271
  }
275
- // Tenant ids left over when the caller excludes some via ne/notIn; undefined for other operator forms.
276
- function tenantIdsAfterExclusion(requested, allowed) {
277
- if (!isPlainObject(requested))
278
- return undefined;
279
- if ("ne" in requested)
280
- return allowed.filter((t) => t !== requested["ne"]);
281
- if (Array.isArray(requested["notIn"])) {
282
- const excluded = requested["notIn"];
283
- return allowed.filter((t) => !excluded.includes(t));
284
- }
285
- return undefined;
286
- }
287
- // Tenant ids a where.tenantId filter asks for; undefined for operator forms
288
- // that cannot narrow to a tenant list (ne, like, ...).
289
- export function requestedTenantIds(requested) {
290
- if (Array.isArray(requested))
291
- return requested;
292
- if (!isPlainObject(requested))
293
- return [requested];
294
- if (Array.isArray(requested["in"]))
295
- return requested["in"];
296
- if ("eq" in requested)
297
- return [requested["eq"]];
298
- return undefined;
299
- }
300
- function isForeignTenantId(tenantIdValue) {
301
- return tenantIdValue !== undefined && tenantIdValue !== SYSTEM_TENANT_ID;
302
- }
303
272
  // Checks the canonical EntityTableMeta (branded EntityTable's KUMIKO_META_SYMBOL
304
273
  // or a plain deriveEntityTableMeta/defineUnmanagedTable result), not a direct
305
274
  // `table.tenantId` property read — the latter only exists on branded EntityTables
@@ -346,28 +315,16 @@ export function reportConventionCrossTenantUse(acknowledged, target) {
346
315
  }
347
316
  reporter(target);
348
317
  }
349
- const ownTransactionRebinders = new WeakMap();
350
318
  export function hasOutsideTransactionDb(ctx) {
351
- return ctx.dbOutsideTransaction !== undefined;
319
+ return ctx.db.outsideTransaction !== undefined;
352
320
  }
353
321
  export function requireOutsideTransactionDb(ctx) {
354
322
  if (!hasOutsideTransactionDb(ctx)) {
355
323
  throw new InternalError({
356
- message: "ctx.dbOutsideTransaction is not available in this dispatch phase (member-resolution, before-transaction denial) or metering tenant mode.",
324
+ message: "ctx.db.outsideTransaction is not available in this dispatch phase (member-resolution, before-transaction denial) or metering tenant mode.",
357
325
  });
358
326
  }
359
- return ctx.dbOutsideTransaction;
360
- }
361
- export async function runInOwnTransaction(tenantDb, fn) {
362
- const rebind = ownTransactionRebinders.get(tenantDb);
363
- if (!rebind) {
364
- throw new InternalError({
365
- message: "runInOwnTransaction received a TenantDb without a transaction rebinder: either it was not " +
366
- "built by createTenantDb, or it is the fail-closed ctx.db/ctx.dbOutsideTransaction of an " +
367
- "r.systemScope() handler (use ctx.systemDb.outsideTransaction there).",
368
- });
369
- }
370
- return rebind(fn);
327
+ return ctx.db.outsideTransaction;
371
328
  }
372
329
  export function createTenantDb(options) {
373
330
  return buildTenantDb(options);
@@ -379,7 +336,9 @@ export function createTenantDataDestroyDb(options) {
379
336
  // Untyped JS callers or an `as` cast can still hand in undefined; a scoped handle
380
337
  // without a tenant would bind `tenant_id = NULL` instead of failing loudly.
381
338
  function buildTenantDb(options) {
382
- const { db, tenantId, mode = "tenant", tracer, meter, signal, grants } = options;
339
+ const { db: givenDb, tenantId, mode = "tenant", reason: systemReason, tracer, meter, signal, grants, } = options;
340
+ const modeOptions = mode === "system" ? systemModeOptions(systemReason) : { mode: "tenant" };
341
+ const db = mode === "system" ? givenDb : unscopedRunnerOf(givenDb);
383
342
  if (tenantId === undefined) {
384
343
  throw new InternalError({ message: "createTenantDb: tenantId is required" });
385
344
  }
@@ -392,47 +351,13 @@ function buildTenantDb(options) {
392
351
  const rebindGrants = projectionRegistry && grants?.projectionRegistry === undefined
393
352
  ? { ...grants, projectionRegistry }
394
353
  : grants;
395
- function withDbSpan(operation, table, runner) {
396
- signal?.throwIfAborted();
397
- if (!tracer && !meter)
398
- return runner();
399
- const tableName = tableNameOf(table);
400
- const start = performance.now();
401
- const emitMetric = () => {
402
- if (meter) {
403
- emitDbQuery(meter, { operation, table: tableName }, (performance.now() - start) / 1000);
404
- }
405
- };
406
- if (!tracer) {
407
- return (async () => {
408
- try {
409
- return await runner();
410
- }
411
- finally {
412
- emitMetric();
413
- }
414
- })();
415
- }
416
- return tracer.withSpan("db.query", {
417
- kind: "client",
418
- attributes: {
419
- "db.system": "postgresql",
420
- "db.operation": operation,
421
- "db.table": tableName,
422
- },
423
- }, async (span) => {
424
- try {
425
- const result = await runner();
426
- if (Array.isArray(result)) {
427
- span.setAttribute("db.row_count", result.length);
428
- }
429
- return result;
430
- }
431
- finally {
432
- emitMetric();
433
- }
434
- });
435
- }
354
+ const withDbSpan = createTenantDbStatementRunner({
355
+ tracer,
356
+ meter,
357
+ signal,
358
+ ...modeOptions,
359
+ tenantId,
360
+ });
436
361
  // Reads see own-tenant rows + reference data (tenantId === SYSTEM_TENANT_ID).
437
362
  // Writes never touch reference rows — those are system-mode only.
438
363
  // A caller-supplied `where.tenantId` may only NARROW the enforced scope
@@ -612,7 +537,7 @@ function buildTenantDb(options) {
612
537
  }
613
538
  // Engine-forwarded steps carry their own declared reason; otherwise the grant's reason is audited.
614
539
  report("unsafe-raw", declaredStepReason ?? grants?.unsafeRaw?.reason ?? "");
615
- return boundRunner(withoutExecutorManagedWrites(db), personalDataGate, projectionRegistry, false);
540
+ return boundRunner(unsafeRawScopedRunner(withoutExecutorManagedWrites(db)), personalDataGate, projectionRegistry, false);
616
541
  }
617
542
  const tenantDb = {
618
543
  tenantId,
@@ -662,6 +587,15 @@ function buildTenantDb(options) {
662
587
  const data = insertValues(table, values);
663
588
  return withDbSpan("insert", table, async () => insertRow(table, data));
664
589
  },
590
+ upsert(table, values, options) {
591
+ const denied = writesDenied("ctx.db.upsert") ??
592
+ upsertTableDenied(table, mode) ??
593
+ personalDataDenied(table, [...Object.keys(values), ...Object.keys(options.update ?? {})]);
594
+ if (denied)
595
+ return Promise.reject(denied);
596
+ const data = insertValues(table, values);
597
+ return withDbSpan("insert", table, () => upsertTenantRow(db, table, data, options));
598
+ },
665
599
  updateMany(table, set, where) {
666
600
  const writeDenied = writesDenied("ctx.db.updateMany");
667
601
  if (writeDenied)
@@ -702,7 +636,7 @@ function buildTenantDb(options) {
702
636
  unsafeRawRebinders.set(tenantDb, (grant) => createTenantDb({
703
637
  db,
704
638
  tenantId,
705
- mode,
639
+ ...modeOptions,
706
640
  tracer,
707
641
  meter,
708
642
  signal,
@@ -720,6 +654,7 @@ function buildTenantDb(options) {
720
654
  db,
721
655
  tenantId,
722
656
  mode: "system",
657
+ reason,
723
658
  tracer,
724
659
  meter,
725
660
  signal,
@@ -728,18 +663,22 @@ function buildTenantDb(options) {
728
663
  crossTenantUseReporters.set(acknowledged, (target) => report("acknowledge-cross-tenant", reason, target));
729
664
  return acknowledged;
730
665
  });
731
- ownTransactionRebinders.set(tenantDb, async (fn) => {
732
- if (grants?.memberReadOnly) {
733
- throw new InternalError({
734
- message: "runInOwnTransaction: memberReadOnly TenantDb — a fresh transaction would escape " +
735
- "the enforced read-only scope.",
736
- });
737
- }
738
- // Carries a runner-bound gate (grants.personalDataGate unset, resolved via the fallback above) forward explicitly, since the fresh tx-handle isn't itself registered in runnerPersonalDataGates.
739
- const txGrants = personalDataGate ? { ...rebindGrants, personalDataGate } : rebindGrants;
740
- return runInNewTransaction(db, (tx) => fn(createTenantDb({ db: tx, tenantId, mode, tracer, meter, signal, grants: txGrants })));
666
+ // Carries a runner-bound gate (grants.personalDataGate unset, resolved via the fallback above) forward explicitly, since a fresh tx-handle isn't itself registered in runnerPersonalDataGates.
667
+ const scopedGrants = personalDataGate ? { ...rebindGrants, personalDataGate } : rebindGrants;
668
+ registerScopedRebinder(tenantDb, {
669
+ memberReadOnly: grants?.memberReadOnly === true,
670
+ rebind: (runner) => createTenantDb({
671
+ db: runner,
672
+ tenantId,
673
+ ...modeOptions,
674
+ tracer,
675
+ meter,
676
+ signal,
677
+ grants: scopedGrants,
678
+ }),
741
679
  });
742
- bindTenantDbRunner(tenantDb, db);
680
+ // Framework code reading through the raw runner (executor list/detail) must follow the db's own mode, not the ambient scope.
681
+ bindTenantDbRunner(tenantDb, db, modeOptions, tenantId);
743
682
  if (grants?.writesDeniedReason !== undefined) {
744
683
  denyTenantDbWrites(tenantDb, grants.writesDeniedReason);
745
684
  }
@@ -0,0 +1,3 @@
1
+ export declare function tenantIdsAfterExclusion(requested: unknown, allowed: readonly unknown[]): readonly unknown[] | undefined;
2
+ export declare function requestedTenantIds(requested: unknown): readonly unknown[] | undefined;
3
+ export declare function isForeignTenantId(tenantIdValue: unknown): boolean;
@@ -0,0 +1,30 @@
1
+ import { isPlainObject } from "@cosmicdrift/kumiko-types/type-guards";
2
+ import { SYSTEM_TENANT_ID } from "../engine/types/identifiers.js";
3
+ // Tenant ids left over when the caller excludes some via ne/notIn; undefined for other operator forms.
4
+ export function tenantIdsAfterExclusion(requested, allowed) {
5
+ if (!isPlainObject(requested))
6
+ return undefined;
7
+ if ("ne" in requested)
8
+ return allowed.filter((t) => t !== requested["ne"]);
9
+ if (Array.isArray(requested["notIn"])) {
10
+ const excluded = requested["notIn"];
11
+ return allowed.filter((t) => !excluded.includes(t));
12
+ }
13
+ return undefined;
14
+ }
15
+ // Tenant ids a where.tenantId filter asks for; undefined for operator forms
16
+ // that cannot narrow to a tenant list (ne, like, ...).
17
+ export function requestedTenantIds(requested) {
18
+ if (Array.isArray(requested))
19
+ return requested;
20
+ if (!isPlainObject(requested))
21
+ return [requested];
22
+ if (Array.isArray(requested["in"]))
23
+ return requested["in"];
24
+ if ("eq" in requested)
25
+ return [requested["eq"]];
26
+ return undefined;
27
+ }
28
+ export function isForeignTenantId(tenantIdValue) {
29
+ return tenantIdValue !== undefined && tenantIdValue !== SYSTEM_TENANT_ID;
30
+ }
@@ -0,0 +1,6 @@
1
+ type HandleKey = object;
2
+ export declare function registerRunnerProxyTarget(proxy: HandleKey, target: HandleKey): void;
3
+ export declare function openSerializedSavepoint<T>(transactionHandle: HandleKey & {
4
+ savepoint: <R>(fn: (sp: unknown) => Promise<R>) => Promise<R>;
5
+ }, fn: (sp: unknown) => Promise<T>): Promise<T>;
6
+ export {};
@@ -0,0 +1,60 @@
1
+ import { AsyncLocalStorage } from "node:async_hooks";
2
+ const runnerProxyTargets = new WeakMap();
3
+ const savepointTransactionKeys = new WeakMap();
4
+ const rootChains = new WeakMap();
5
+ const nestedChainsInScope = new AsyncLocalStorage();
6
+ function isHandleKey(value) {
7
+ return typeof value === "function" || (typeof value === "object" && value !== null);
8
+ }
9
+ export function registerRunnerProxyTarget(proxy, target) {
10
+ runnerProxyTargets.set(proxy, target);
11
+ }
12
+ function driverHandleOf(handle) {
13
+ let current = handle;
14
+ let target = runnerProxyTargets.get(current);
15
+ while (target) {
16
+ current = target;
17
+ target = runnerProxyTargets.get(current);
18
+ }
19
+ return current;
20
+ }
21
+ function transactionKeyOf(handle) {
22
+ const driverHandle = driverHandleOf(handle);
23
+ return savepointTransactionKeys.get(driverHandle) ?? driverHandle;
24
+ }
25
+ function chainFor(transactionKey) {
26
+ const nested = nestedChainsInScope.getStore()?.get(transactionKey);
27
+ if (nested)
28
+ return nested;
29
+ const root = rootChains.get(transactionKey);
30
+ if (root)
31
+ return root;
32
+ const created = { tail: Promise.resolve() };
33
+ rootChains.set(transactionKey, created);
34
+ return created;
35
+ }
36
+ async function runOnChain(transactionKey, work) {
37
+ const chain = chainFor(transactionKey);
38
+ const previous = chain.tail;
39
+ let release = () => { };
40
+ chain.tail = new Promise((resolve) => {
41
+ release = resolve;
42
+ });
43
+ await previous;
44
+ try {
45
+ const scope = new Map(nestedChainsInScope.getStore());
46
+ scope.set(transactionKey, { tail: Promise.resolve() });
47
+ return await nestedChainsInScope.run(scope, work);
48
+ }
49
+ finally {
50
+ release();
51
+ }
52
+ }
53
+ export function openSerializedSavepoint(transactionHandle, fn) {
54
+ const transactionKey = transactionKeyOf(transactionHandle);
55
+ return runOnChain(transactionKey, () => transactionHandle.savepoint((sp) => {
56
+ if (isHandleKey(sp))
57
+ savepointTransactionKeys.set(driverHandleOf(sp), transactionKey);
58
+ return fn(sp);
59
+ }));
60
+ }
@@ -72,7 +72,7 @@ export async function deleteStoredFileAndDerivatives(originalKey, store, errorCo
72
72
  }
73
73
  return failedKeys;
74
74
  }
75
- // deleteStoredFileAndDerivatives through ctx.files for a key read from a tenant-filtered fileRef
75
+ // deleteStoredFileAndDerivatives through ctx.services.files for a key read from a tenant-filtered fileRef
76
76
  // row. After a tenant handover the key keeps the previous tenant's prefix, which ref() and list()
77
77
  // reject; every key the helper deletes is the original or one of its derivatives.
78
78
  export function deleteFileRefBytes(files, row, errorContext) {
@@ -1,6 +1,3 @@
1
- export type { StoredFileStore } from "./delete-stored-file.ts";
2
- export { deleteFileRefBytes, deleteStoredFileAndDerivatives, listDerivativeKeys, } from "./delete-stored-file.ts";
3
- export type { DerivativesContextDeps } from "./derivatives-context.ts";
4
- export { createDerivativesContext, resolveRenderer } from "./derivatives-context.ts";
1
+ export { deleteFileRefBytes, deleteStoredFileAndDerivatives, } from "./delete-stored-file.ts";
5
2
  export { resolveFieldVariant } from "./field-variants.ts";
6
- export { canonicalJson, derivativeListPrefix, isDerivativeKeyOf, parseDerivativeKey, specHash, VARIANT_NAME_PATTERN, variantSuffix, } from "./variant-key.ts";
3
+ export { derivativeListPrefix, parseDerivativeKey, variantSuffix, } from "./variant-key.ts";
@@ -1,4 +1,3 @@
1
- export { deleteFileRefBytes, deleteStoredFileAndDerivatives, listDerivativeKeys, } from "./delete-stored-file.js";
2
- export { createDerivativesContext, resolveRenderer } from "./derivatives-context.js";
1
+ export { deleteFileRefBytes, deleteStoredFileAndDerivatives, } from "./delete-stored-file.js";
3
2
  export { resolveFieldVariant } from "./field-variants.js";
4
- export { canonicalJson, derivativeListPrefix, isDerivativeKeyOf, parseDerivativeKey, specHash, VARIANT_NAME_PATTERN, variantSuffix, } from "./variant-key.js";
3
+ export { derivativeListPrefix, parseDerivativeKey, variantSuffix, } from "./variant-key.js";