@cosmicdrift/kumiko-framework 0.386.0 → 0.388.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 (468) hide show
  1. package/AGENTS.md +6 -1
  2. package/LICENSE +21 -57
  3. package/README.md +2 -2
  4. package/agents/examples/anonymous-access.md +1 -1
  5. package/agents/examples/apex-landing.md +204 -0
  6. package/agents/examples/api-worker-split.md +64 -0
  7. package/agents/examples/app-config.md +14 -0
  8. package/agents/examples/auth-mfa.md +115 -0
  9. package/agents/examples/env-composition.md +28 -1
  10. package/agents/examples/legal-pages.md +1 -1
  11. package/agents/examples/prod-boot-options.md +16 -0
  12. package/agents/examples/rate-limiting.md +48 -0
  13. package/agents/examples/record-detail-layout.md +692 -0
  14. package/agents/examples/seed-migration.md +212 -0
  15. package/agents/examples/wizard-form.md +941 -0
  16. package/agents/examples/writeform-section.md +548 -0
  17. package/agents/features.md +19 -2
  18. package/agents/widgets.md +40 -39
  19. package/dist/api/api-constants.js +2 -2
  20. package/dist/api/auth-middleware.js +7 -7
  21. package/dist/api/auth-rate-limiters.js +7 -3
  22. package/dist/api/auth-routes-mfa.js +1 -1
  23. package/dist/api/auth-routes-session.js +1 -1
  24. package/dist/api/auth-routes-shared.js +7 -3
  25. package/dist/api/auth-routes-signup.js +1 -1
  26. package/dist/api/client-error-route.js +8 -2
  27. package/dist/api/client-ip.js +3 -1
  28. package/dist/api/extra-route.js +1 -1
  29. package/dist/api/index.d.ts +3 -1
  30. package/dist/api/index.js +3 -1
  31. package/dist/api/pii-leak-guard.js +4 -2
  32. package/dist/api/readiness.js +5 -5
  33. package/dist/api/redis-sse-broker.js +8 -6
  34. package/dist/api/request-context.d.ts +1 -1
  35. package/dist/api/request-context.js +1 -1
  36. package/dist/api/routes.js +2 -2
  37. package/dist/api/server-boot-checks.d.ts +10 -0
  38. package/dist/api/server-boot-checks.js +157 -0
  39. package/dist/api/server-event-dispatcher.d.ts +26 -0
  40. package/dist/api/server-event-dispatcher.js +208 -0
  41. package/dist/api/server-extra-routes.d.ts +11 -0
  42. package/dist/api/server-extra-routes.js +203 -0
  43. package/dist/api/server-middleware.d.ts +20 -0
  44. package/dist/api/server-middleware.js +211 -0
  45. package/dist/api/server-routes.d.ts +19 -0
  46. package/dist/api/server-routes.js +293 -0
  47. package/dist/api/server-websocket-routes.d.ts +4 -0
  48. package/dist/api/server-websocket-routes.js +108 -0
  49. package/dist/api/server-wiring.d.ts +32 -0
  50. package/dist/api/server-wiring.js +236 -0
  51. package/dist/api/server.d.ts +10 -15
  52. package/dist/api/server.js +48 -1250
  53. package/dist/api/session-cookies.js +4 -4
  54. package/dist/api/sse-broker.js +1 -1
  55. package/dist/api/sse-route.d.ts +13 -13
  56. package/dist/api/sse-route.js +31 -27
  57. package/dist/auth/index.js +4 -4
  58. package/dist/auth/roles.d.ts +4 -4
  59. package/dist/auth/roles.js +24 -24
  60. package/dist/compliance/duration-spec.js +18 -20
  61. package/dist/compliance/index.js +2 -3
  62. package/dist/compliance/override-schema.d.ts +4 -4
  63. package/dist/compliance/override-schema.js +19 -22
  64. package/dist/compliance/profiles.d.ts +26 -29
  65. package/dist/compliance/profiles.js +62 -69
  66. package/dist/compliance/sub-processors.d.ts +28 -30
  67. package/dist/compliance/sub-processors.js +17 -21
  68. package/dist/consumer-cli.js +4 -4
  69. package/dist/crypto/blind-index.js +18 -17
  70. package/dist/crypto/ciphertext-pattern.js +1 -1
  71. package/dist/crypto/event-pii.js +3 -3
  72. package/dist/crypto/kek-source.d.ts +1 -1
  73. package/dist/crypto/kek-source.js +3 -2
  74. package/dist/crypto/kms-adapter.d.ts +1 -1
  75. package/dist/crypto/kms-adapter.js +4 -6
  76. package/dist/crypto/kms-wiring.d.ts +1 -2
  77. package/dist/crypto/kms-wiring.js +2 -2
  78. package/dist/crypto/owner-transition-rekey.d.ts +5 -1
  79. package/dist/crypto/owner-transition-rekey.js +1 -1
  80. package/dist/crypto/pg-kms-adapter.js +2 -6
  81. package/dist/crypto/pii-field-encryption.d.ts +5 -1
  82. package/dist/crypto/pii-field-encryption.js +7 -5
  83. package/dist/crypto/subject-resolver.d.ts +1 -1
  84. package/dist/crypto/subject-resolver.js +2 -2
  85. package/dist/db/aggregate-sql.d.ts +21 -0
  86. package/dist/db/aggregate-sql.js +155 -0
  87. package/dist/db/apply-entity-event.d.ts +6 -6
  88. package/dist/db/apply-entity-event.js +55 -55
  89. package/dist/db/blind-index-cleanup.js +7 -7
  90. package/dist/db/closed-connection.d.ts +9 -0
  91. package/dist/db/closed-connection.js +95 -0
  92. package/dist/db/collect-table-metas.js +10 -11
  93. package/dist/db/compound-types.d.ts +1 -1
  94. package/dist/db/compound-types.js +12 -12
  95. package/dist/db/cursor.js +3 -4
  96. package/dist/db/dialect.d.ts +2 -2
  97. package/dist/db/dialect.js +3 -3
  98. package/dist/db/distinct-on.d.ts +1 -1
  99. package/dist/db/driver-row-coercion.d.ts +2 -0
  100. package/dist/db/driver-row-coercion.js +186 -0
  101. package/dist/db/driver-value-preparation.d.ts +16 -0
  102. package/dist/db/driver-value-preparation.js +99 -0
  103. package/dist/db/eagerload.d.ts +3 -3
  104. package/dist/db/eagerload.js +21 -12
  105. package/dist/db/entity-field-encryption.d.ts +1 -0
  106. package/dist/db/entity-field-encryption.js +1 -1
  107. package/dist/db/entity-table-meta.d.ts +2 -2
  108. package/dist/db/entity-table-meta.js +105 -112
  109. package/dist/db/event-store-executor-context.d.ts +3 -2
  110. package/dist/db/event-store-executor-context.js +13 -13
  111. package/dist/db/event-store-executor-read-aggregate.d.ts +8 -0
  112. package/dist/db/event-store-executor-read-aggregate.js +112 -0
  113. package/dist/db/event-store-executor-read-filter.d.ts +31 -0
  114. package/dist/db/event-store-executor-read-filter.js +203 -0
  115. package/dist/db/event-store-executor-read-paging.d.ts +14 -0
  116. package/dist/db/event-store-executor-read-paging.js +99 -0
  117. package/dist/db/event-store-executor-read-rows.d.ts +6 -0
  118. package/dist/db/event-store-executor-read-rows.js +32 -0
  119. package/dist/db/event-store-executor-read-search.d.ts +28 -0
  120. package/dist/db/event-store-executor-read-search.js +221 -0
  121. package/dist/db/event-store-executor-read-sort.d.ts +41 -0
  122. package/dist/db/event-store-executor-read-sort.js +130 -0
  123. package/dist/db/event-store-executor-read-where.d.ts +24 -0
  124. package/dist/db/event-store-executor-read-where.js +81 -0
  125. package/dist/db/event-store-executor-read.d.ts +2 -9
  126. package/dist/db/event-store-executor-read.js +50 -704
  127. package/dist/db/event-store-executor-write-steps.d.ts +20 -0
  128. package/dist/db/event-store-executor-write-steps.js +100 -0
  129. package/dist/db/event-store-executor-write.js +401 -510
  130. package/dist/db/index.d.ts +6 -2
  131. package/dist/db/index.js +5 -1
  132. package/dist/db/list-aggregate-labels.d.ts +14 -0
  133. package/dist/db/list-aggregate-labels.js +26 -0
  134. package/dist/db/located-timestamp.d.ts +11 -11
  135. package/dist/db/located-timestamp.js +29 -30
  136. package/dist/db/migrate-generator.d.ts +1 -1
  137. package/dist/db/migrate-generator.js +97 -105
  138. package/dist/db/migrate-runner.js +29 -26
  139. package/dist/db/money.d.ts +6 -6
  140. package/dist/db/money.js +29 -27
  141. package/dist/db/queries/backfill-pii.js +5 -5
  142. package/dist/db/queries/ddl.js +1 -1
  143. package/dist/db/queries/es-ops.d.ts +1 -1
  144. package/dist/db/queries/es-ops.js +1 -1
  145. package/dist/db/queries/event-consumer.js +3 -3
  146. package/dist/db/queries/event-store.js +4 -2
  147. package/dist/db/queries/projection-rebuild.js +3 -3
  148. package/dist/db/queries/raw-sql.d.ts +2 -2
  149. package/dist/db/queries/raw-sql.js +2 -2
  150. package/dist/db/queries/shadow-swap.js +19 -19
  151. package/dist/db/query.d.ts +3 -16
  152. package/dist/db/query.js +8 -761
  153. package/dist/db/rebuild-marker.js +20 -21
  154. package/dist/db/reference-data.js +6 -1
  155. package/dist/db/replay-migration-sql.js +2 -2
  156. package/dist/db/schema-inspection.js +4 -5
  157. package/dist/db/table-builder.d.ts +1 -2
  158. package/dist/db/table-builder.js +137 -190
  159. package/dist/db/table-info.d.ts +10 -0
  160. package/dist/db/table-info.js +45 -0
  161. package/dist/db/temporal-value-guards.d.ts +6 -0
  162. package/dist/db/temporal-value-guards.js +15 -0
  163. package/dist/db/tenant-db-runner.d.ts +1 -0
  164. package/dist/db/tenant-db-runner.js +3 -0
  165. package/dist/db/tenant-db.d.ts +2 -2
  166. package/dist/db/tenant-db.js +48 -11
  167. package/dist/db/where-clause.d.ts +6 -0
  168. package/dist/db/where-clause.js +236 -0
  169. package/dist/derivatives/delete-stored-file.js +6 -2
  170. package/dist/derivatives/derivatives-context.js +1 -1
  171. package/dist/engine/boot-validator/access-roles.js +4 -3
  172. package/dist/engine/boot-validator/api-ext.js +14 -14
  173. package/dist/engine/boot-validator/boot-check.js +1 -1
  174. package/dist/engine/boot-validator/config-deps.js +7 -6
  175. package/dist/engine/boot-validator/detail-screens.js +4 -4
  176. package/dist/engine/boot-validator/entity-handler.d.ts +1 -0
  177. package/dist/engine/boot-validator/entity-handler.js +77 -61
  178. package/dist/engine/boot-validator/form-derivations.js +35 -1
  179. package/dist/engine/boot-validator/gdpr-storage.js +4 -4
  180. package/dist/engine/boot-validator/i18n-keys.js +6 -4
  181. package/dist/engine/boot-validator/index.d.ts +2 -2
  182. package/dist/engine/boot-validator/index.js +22 -20
  183. package/dist/engine/boot-validator/nav.js +5 -5
  184. package/dist/engine/boot-validator/ownership.js +12 -9
  185. package/dist/engine/boot-validator/parent-ref.js +1 -1
  186. package/dist/engine/boot-validator/pii-retention.js +258 -187
  187. package/dist/engine/boot-validator/projection-list-screens.js +7 -7
  188. package/dist/engine/boot-validator/query-refs.js +1 -1
  189. package/dist/engine/boot-validator/screens-actions.d.ts +1 -0
  190. package/dist/engine/boot-validator/screens-actions.js +23 -17
  191. package/dist/engine/boot-validator/screens-dashboard.js +2 -5
  192. package/dist/engine/boot-validator/screens-forms.js +12 -17
  193. package/dist/engine/boot-validator/screens-kind-config-edit.d.ts +3 -0
  194. package/dist/engine/boot-validator/screens-kind-config-edit.js +88 -0
  195. package/dist/engine/boot-validator/screens-kind-entity-edit.d.ts +3 -0
  196. package/dist/engine/boot-validator/screens-kind-entity-edit.js +55 -0
  197. package/dist/engine/boot-validator/screens-kind-entity-list.d.ts +3 -0
  198. package/dist/engine/boot-validator/screens-kind-entity-list.js +228 -0
  199. package/dist/engine/boot-validator/screens-kind-projection-detail.d.ts +3 -0
  200. package/dist/engine/boot-validator/screens-kind-projection-detail.js +235 -0
  201. package/dist/engine/boot-validator/screens-kind-projection-list.d.ts +3 -0
  202. package/dist/engine/boot-validator/screens-kind-projection-list.js +52 -0
  203. package/dist/engine/boot-validator/screens-kind-secret-mint.d.ts +3 -0
  204. package/dist/engine/boot-validator/screens-kind-secret-mint.js +28 -0
  205. package/dist/engine/boot-validator/screens-kind-shared.d.ts +37 -0
  206. package/dist/engine/boot-validator/screens-kind-shared.js +142 -0
  207. package/dist/engine/boot-validator/screens-lists.d.ts +2 -1
  208. package/dist/engine/boot-validator/screens-lists.js +26 -24
  209. package/dist/engine/boot-validator/screens.d.ts +0 -2
  210. package/dist/engine/boot-validator/screens.js +102 -869
  211. package/dist/engine/boot-validator/security-baseline.js +3 -2
  212. package/dist/engine/boot-validator/transfer-graph.js +2 -2
  213. package/dist/engine/boot-validator/workspaces.js +3 -3
  214. package/dist/engine/bridge-stub.js +3 -4
  215. package/dist/engine/build-app-schema.js +130 -170
  216. package/dist/engine/build-config-feature-schema.js +50 -50
  217. package/dist/engine/build-target.js +20 -23
  218. package/dist/engine/codemod/pipeline-codemod.js +20 -13
  219. package/dist/engine/config-helpers.js +4 -4
  220. package/dist/engine/constants.js +2 -2
  221. package/dist/engine/create-app.js +2 -2
  222. package/dist/engine/define-feature.js +21 -13
  223. package/dist/engine/define-handler.js +13 -11
  224. package/dist/engine/define-step.js +1 -1
  225. package/dist/engine/define-workflow.d.ts +5 -5
  226. package/dist/engine/define-workflow.js +6 -6
  227. package/dist/engine/entity-handlers.d.ts +13 -0
  228. package/dist/engine/entity-handlers.js +22 -34
  229. package/dist/engine/entity-list-runtime-options.d.ts +8 -0
  230. package/dist/engine/entity-list-runtime-options.js +18 -0
  231. package/dist/engine/event-def.js +2 -2
  232. package/dist/engine/extension-names.d.ts +16 -17
  233. package/dist/engine/extension-names.js +37 -38
  234. package/dist/engine/extensions/escape-hatch-usage.js +1 -1
  235. package/dist/engine/extensions/tenant-data.js +2 -2
  236. package/dist/engine/extensions/user-data.d.ts +23 -24
  237. package/dist/engine/factories.d.ts +14 -13
  238. package/dist/engine/factories.js +38 -37
  239. package/dist/engine/feature-ast/entity-field-types.js +1 -1
  240. package/dist/engine/feature-ast/extractors/handlers.js +2 -1
  241. package/dist/engine/feature-ast/extractors/hooks.js +1 -1
  242. package/dist/engine/feature-ast/extractors/round2.js +25 -6
  243. package/dist/engine/feature-ast/extractors/shared.d.ts +2 -3
  244. package/dist/engine/feature-ast/extractors/shared.js +2 -3
  245. package/dist/engine/feature-ast/parse.js +13 -13
  246. package/dist/engine/feature-ast/patch.js +4 -182
  247. package/dist/engine/feature-ast/pattern-change-schema.d.ts +3 -0
  248. package/dist/engine/feature-ast/pattern-change-schema.js +2 -1
  249. package/dist/engine/feature-ast/pattern-id-matchers.d.ts +7 -0
  250. package/dist/engine/feature-ast/pattern-id-matchers.js +210 -0
  251. package/dist/engine/feature-ast/patterns.d.ts +11 -2
  252. package/dist/engine/feature-ast/patterns.js +43 -51
  253. package/dist/engine/feature-ast/render.js +50 -89
  254. package/dist/engine/feature-config-events-jobs.js +15 -12
  255. package/dist/engine/feature-entity-handlers.js +12 -5
  256. package/dist/engine/feature-manifest.d.ts +9 -9
  257. package/dist/engine/feature-manifest.js +6 -7
  258. package/dist/engine/feature-ui-extensions.d.ts +3 -3
  259. package/dist/engine/feature-ui-extensions.js +30 -22
  260. package/dist/engine/field-access.js +5 -6
  261. package/dist/engine/form-derivations.js +18 -7
  262. package/dist/engine/handler-field-references.js +1 -1
  263. package/dist/engine/index.d.ts +1 -0
  264. package/dist/engine/index.js +4 -4
  265. package/dist/engine/object-form.d.ts +1 -0
  266. package/dist/engine/object-form.js +14 -4
  267. package/dist/engine/ownership.js +3 -3
  268. package/dist/engine/parse-ref-target.js +5 -7
  269. package/dist/engine/pattern-library/index.js +2 -2
  270. package/dist/engine/pattern-library/library.js +2 -2
  271. package/dist/engine/pattern-library/types.js +3 -3
  272. package/dist/engine/pipeline.js +2 -2
  273. package/dist/engine/project-app-schema-for-roles.d.ts +2 -0
  274. package/dist/engine/project-app-schema-for-roles.js +7 -5
  275. package/dist/engine/projection-helpers.js +9 -9
  276. package/dist/engine/qualified-name.js +2 -2
  277. package/dist/engine/registry-facade.js +1 -1
  278. package/dist/engine/registry-ingest.js +13 -13
  279. package/dist/engine/registry-state.js +17 -19
  280. package/dist/engine/registry-validate.js +12 -12
  281. package/dist/engine/run-in.js +2 -2
  282. package/dist/engine/run-pipeline.js +7 -0
  283. package/dist/engine/schema-builder.js +251 -233
  284. package/dist/engine/screen-filter-ops.js +17 -20
  285. package/dist/engine/screen-helpers.js +4 -3
  286. package/dist/engine/screen-kind.d.ts +7 -0
  287. package/dist/engine/screen-kind.js +1 -0
  288. package/dist/engine/state-machine.d.ts +12 -12
  289. package/dist/engine/state-machine.js +7 -7
  290. package/dist/engine/steps/_resolver-utils.js +4 -3
  291. package/dist/engine/steps/for-each.js +4 -4
  292. package/dist/engine/steps/unsafe-projection-delete.js +1 -1
  293. package/dist/engine/steps/unsafe-projection-upsert.js +4 -4
  294. package/dist/engine/steps/wait-for-event.js +4 -4
  295. package/dist/engine/steps/workflow-system-events.js +3 -3
  296. package/dist/engine/strip-disabled-features-from-app-schema.js +51 -14
  297. package/dist/engine/tier-resolver-extension.d.ts +29 -27
  298. package/dist/engine/tier-resolver-extension.js +26 -26
  299. package/dist/engine/transfer-adjacency.js +2 -2
  300. package/dist/engine/validate-projection-allowlist.js +9 -28
  301. package/dist/engine/walk-step-instances.d.ts +2 -0
  302. package/dist/engine/walk-step-instances.js +38 -0
  303. package/dist/engine/where-rule-lint.js +1 -1
  304. package/dist/engine/write-handler-qn-extract.js +1 -1
  305. package/dist/entrypoint/index.d.ts +4 -1
  306. package/dist/entrypoint/index.js +10 -4
  307. package/dist/env/index.d.ts +7 -6
  308. package/dist/env/index.js +10 -9
  309. package/dist/errors/docs-url.d.ts +1 -1
  310. package/dist/errors/docs-url.js +22 -2
  311. package/dist/errors/transition-details.js +7 -7
  312. package/dist/errors/write-error-info.d.ts +6 -6
  313. package/dist/errors/write-error-info.js +6 -6
  314. package/dist/es-ops/context.d.ts +9 -9
  315. package/dist/es-ops/context.js +29 -29
  316. package/dist/es-ops/index.js +7 -9
  317. package/dist/es-ops/operations-schema.js +4 -10
  318. package/dist/es-ops/runner.d.ts +11 -11
  319. package/dist/es-ops/runner.js +49 -53
  320. package/dist/es-ops/types.d.ts +55 -55
  321. package/dist/es-ops/types.js +11 -11
  322. package/dist/event-store/admin-api.js +7 -8
  323. package/dist/event-store/errors.js +1 -1
  324. package/dist/event-store/event-store.js +12 -6
  325. package/dist/event-store/rebuild-dead-letter.js +1 -1
  326. package/dist/files/bind-pending-file-refs.js +3 -3
  327. package/dist/files/create-file-ref-from-bytes.js +4 -1
  328. package/dist/files/feature.js +9 -10
  329. package/dist/files/file-handle.js +7 -9
  330. package/dist/files/file-ref-entity.js +15 -15
  331. package/dist/files/file-ref-table.js +7 -8
  332. package/dist/files/file-routes.d.ts +7 -0
  333. package/dist/files/file-routes.js +22 -13
  334. package/dist/files/in-memory-provider.js +8 -9
  335. package/dist/files/local-provider.js +18 -25
  336. package/dist/files/provider-resolver.d.ts +7 -7
  337. package/dist/files/resolve-content-type.js +43 -0
  338. package/dist/files/storage-tracking.js +2 -2
  339. package/dist/files/upload-ledger.js +7 -0
  340. package/dist/files/zip-stream.d.ts +12 -19
  341. package/dist/files/zip-stream.js +44 -63
  342. package/dist/i18n/required-surface-keys.d.ts +1 -1
  343. package/dist/i18n/required-surface-keys.js +188 -212
  344. package/dist/internal/stack-support.d.ts +2 -1
  345. package/dist/internal/stack-support.js +1 -1
  346. package/dist/jobs/job-runner-context.d.ts +32 -0
  347. package/dist/jobs/job-runner-context.js +305 -0
  348. package/dist/jobs/job-runner-execution.d.ts +7 -0
  349. package/dist/jobs/job-runner-execution.js +160 -0
  350. package/dist/jobs/job-runner-gates.d.ts +19 -0
  351. package/dist/jobs/job-runner-gates.js +198 -0
  352. package/dist/jobs/job-runner-helpers.d.ts +17 -3
  353. package/dist/jobs/job-runner-helpers.js +69 -4
  354. package/dist/jobs/job-runner-schedulers.d.ts +1 -1
  355. package/dist/jobs/job-runner-schedulers.js +3 -4
  356. package/dist/jobs/job-runner-scope.d.ts +44 -0
  357. package/dist/jobs/job-runner-scope.js +102 -0
  358. package/dist/jobs/job-runner-types.d.ts +12 -0
  359. package/dist/jobs/job-runner.d.ts +0 -1
  360. package/dist/jobs/job-runner.js +57 -669
  361. package/dist/lifecycle/lifecycle.js +3 -5
  362. package/dist/lifecycle/signal-handlers.js +5 -4
  363. package/dist/logging/utils.d.ts +2 -1
  364. package/dist/logging/utils.js +38 -10
  365. package/dist/migrations/index.js +1 -1
  366. package/dist/migrations/kumiko-drift.js +14 -13
  367. package/dist/migrations/pending-rebuilds.d.ts +21 -20
  368. package/dist/migrations/pending-rebuilds.js +27 -27
  369. package/dist/migrations/projection-table-index.d.ts +3 -3
  370. package/dist/migrations/projection-table-index.js +8 -8
  371. package/dist/observability/escape-hatch-report.d.ts +3 -0
  372. package/dist/observability/escape-hatch-report.js +12 -1
  373. package/dist/observability/metric-validator.js +1 -1
  374. package/dist/observability/metrics-handle.js +3 -3
  375. package/dist/pipeline/append-event-core.js +11 -2
  376. package/dist/pipeline/cascade-handler.d.ts +1 -1
  377. package/dist/pipeline/cascade-handler.js +165 -138
  378. package/dist/pipeline/dispatch-batch.js +2 -2
  379. package/dist/pipeline/dispatch-query.js +20 -13
  380. package/dist/pipeline/dispatch-shared.d.ts +14 -3
  381. package/dist/pipeline/dispatch-shared.js +67 -721
  382. package/dist/pipeline/dispatch-stream.js +1 -1
  383. package/dist/pipeline/dispatch-write.js +297 -190
  384. package/dist/pipeline/dispatcher-utils.d.ts +1 -1
  385. package/dist/pipeline/dispatcher-utils.js +1 -1
  386. package/dist/pipeline/event-consumer-state.js +2 -2
  387. package/dist/pipeline/event-dispatcher-admin.js +2 -1
  388. package/dist/pipeline/event-dispatcher-delivery.js +4 -6
  389. package/dist/pipeline/event-dispatcher.js +17 -28
  390. package/dist/pipeline/handler-context-auth.d.ts +9 -0
  391. package/dist/pipeline/handler-context-auth.js +54 -0
  392. package/dist/pipeline/handler-context-config.d.ts +14 -0
  393. package/dist/pipeline/handler-context-config.js +113 -0
  394. package/dist/pipeline/handler-context-db.d.ts +24 -0
  395. package/dist/pipeline/handler-context-db.js +149 -0
  396. package/dist/pipeline/handler-context-dispatch.d.ts +21 -0
  397. package/dist/pipeline/handler-context-dispatch.js +89 -0
  398. package/dist/pipeline/handler-context-events.d.ts +43 -0
  399. package/dist/pipeline/handler-context-events.js +237 -0
  400. package/dist/pipeline/handler-context-notify.d.ts +12 -0
  401. package/dist/pipeline/handler-context-notify.js +55 -0
  402. package/dist/pipeline/handler-context-observability.d.ts +7 -0
  403. package/dist/pipeline/handler-context-observability.js +21 -0
  404. package/dist/pipeline/handler-context-scope.d.ts +48 -0
  405. package/dist/pipeline/handler-context-scope.js +88 -0
  406. package/dist/pipeline/irreversible-operation-gate.js +1 -1
  407. package/dist/pipeline/lifecycle-pipeline.js +9 -9
  408. package/dist/pipeline/member-read-only-transaction.js +1 -3
  409. package/dist/pipeline/msp-rebuild.js +1 -1
  410. package/dist/pipeline/notify-scope.js +12 -1
  411. package/dist/pipeline/pre-handler-gates.js +20 -4
  412. package/dist/pipeline/pre-transaction-reservations.d.ts +1 -0
  413. package/dist/pipeline/pre-transaction-reservations.js +9 -3
  414. package/dist/pipeline/projection-rebuild.js +15 -13
  415. package/dist/pipeline/system-hooks.js +39 -41
  416. package/dist/pipeline/system-identity-switch.js +1 -3
  417. package/dist/pipeline/tenant-timezone-cache.js +1 -1
  418. package/dist/random/generate.d.ts +29 -29
  419. package/dist/random/generate.js +30 -30
  420. package/dist/random/words.js +20 -20
  421. package/dist/rate-limit/middleware.js +9 -5
  422. package/dist/redis/client.js +2 -2
  423. package/dist/redis/pubsub-signal.js +14 -17
  424. package/dist/schema-cli/apply-command.d.ts +2 -0
  425. package/dist/schema-cli/apply-command.js +97 -0
  426. package/dist/schema-cli/baseline-command.d.ts +2 -0
  427. package/dist/schema-cli/baseline-command.js +33 -0
  428. package/dist/schema-cli/generate-command.d.ts +2 -0
  429. package/dist/schema-cli/generate-command.js +90 -0
  430. package/dist/schema-cli/shared.d.ts +39 -0
  431. package/dist/schema-cli/shared.js +95 -0
  432. package/dist/schema-cli/status-command.d.ts +2 -0
  433. package/dist/schema-cli/status-command.js +73 -0
  434. package/dist/schema-cli/validate-boot-input.d.ts +5 -0
  435. package/dist/schema-cli/validate-boot-input.js +130 -0
  436. package/dist/schema-cli/validate-command.d.ts +2 -0
  437. package/dist/schema-cli/validate-command.js +130 -0
  438. package/dist/schema-cli.d.ts +2 -18
  439. package/dist/schema-cli.js +47 -510
  440. package/dist/search/index.js +4 -4
  441. package/dist/search/meilisearch-adapter.js +2 -1
  442. package/dist/search/purge-subject.js +4 -5
  443. package/dist/search/reindex-entity.js +6 -9
  444. package/dist/time/boot-tz-warning.d.ts +2 -2
  445. package/dist/time/boot-tz-warning.js +8 -8
  446. package/dist/time/iana.js +10 -10
  447. package/dist/time/index.js +9 -9
  448. package/dist/time/legacy-date.d.ts +2 -2
  449. package/dist/time/legacy-date.js +6 -8
  450. package/dist/time/polyfill.js +1 -1
  451. package/dist/time/tz-context.d.ts +1 -1
  452. package/dist/time/tz-context.js +1 -1
  453. package/dist/ui-types/app-schema.js +7 -7
  454. package/dist/ui-types/list-row-meta.js +4 -4
  455. package/dist/upgrade-cli.js +159 -130
  456. package/dist/utils/compare.js +1 -1
  457. package/package.json +5 -5
  458. package/src/changes.json +358 -0
  459. package/src/scripts/codemod/crypto-shredding-testing-move.ts +2 -2
  460. package/src/scripts/codemod/feature-layout.ts +10 -2
  461. package/src/scripts/codemod/migrate-cross-tenant.ts +1 -1
  462. package/src/scripts/codemod/migrate-open-to-all.ts +1 -1
  463. package/src/scripts/codemod/object-form.ts +41 -4
  464. package/src/scripts/codemod/package-merge.ts +58 -8
  465. package/src/scripts/codemod/pii-personal-migration.ts +192 -153
  466. package/src/scripts/codemod/testing-injection.ts +122 -42
  467. package/src/scripts/codemod/testing-move.ts +29 -7
  468. package/src/scripts/codemod/unprocessable-error-details-reason.ts +2 -2
@@ -1,26 +1,26 @@
1
- // Migrate-Runner: applied checked-in SQL-Files gegen eine DB.
2
- // Ersatz für `drizzle-kit migrate` als Runtime-Komponente.
1
+ // Migration runner: applies checked-in SQL files to a database.
2
+ // Replaces `drizzle-kit migrate` as a runtime component.
3
3
  //
4
- // **NO-MAGIC-ON-DATA Kernprinzip** (siehe drizzle-replacement.md):
5
- // - Runner liest NUR checked-in `<dir>/*.sql` Files
6
- // - Kein Reach-back zu EntityDefinition zur Runtime
7
- // - Kein Auto-Apply-on-App-Boot — Deploy-Skript oder Init-Container ruft
8
- // `kumiko migrate apply` als eigenen Schritt
9
- // - Schema-Drift wird durch Checksum-Mismatch fail-loud detektiert
4
+ // **NO-MAGIC-ON-DATA core principle** (see drizzle-replacement.md):
5
+ // - The runner reads ONLY checked-in `<dir>/*.sql` files.
6
+ // - It does not reach back to EntityDefinition at runtime.
7
+ // - It does not auto-apply on app boot — a deploy script or init container
8
+ // invokes `kumiko migrate apply` as a separate step.
9
+ // - Schema drift is detected fail-loudly through checksum mismatches.
10
10
  //
11
- // Tracking-Table `_kumiko_migrations(id, applied_at, checksum)`. id = filename
12
- // ohne .sql-Endung. Checksum = sha256 vom File-Content beim Apply. Wenn ein
13
- // schon-appliedes File nachträglich editiert wird, schlägt der nächste Apply
14
- // fehl mit klarer Fehlermeldung (production-DBs haben das alte SQL drin —
15
- // edit nachträglich = production-state inkonsistent mit committed-state).
11
+ // Tracking table: `_kumiko_migrations(id, applied_at, checksum)`. `id` is the
12
+ // filename without the `.sql` suffix. The checksum is the sha256 hash of the
13
+ // file content at apply time. If an already-applied file is edited, the next
14
+ // apply fails with a clear error (production databases contain the old SQL —
15
+ // editing it makes production state inconsistent with committed state).
16
16
  import { createHash } from "node:crypto";
17
17
  import { existsSync, readdirSync, readFileSync } from "node:fs";
18
18
  import { join } from "node:path";
19
19
  import { propertyOf } from "@cosmicdrift/kumiko-types/type-guards";
20
20
  import { asRawClient, hasBegin, } from "./query.js";
21
- // Advisory-lock key (random 32-bit int, stable). Verhindert dass zwei
22
- // gleichzeitig bootende Pods beide migrate apply laufen lassen (zweiter
23
- // blockiert bis erster fertig).
21
+ // Advisory-lock key (random 32-bit integer, stable). Prevents two Pods
22
+ // booting at the same time from both running migrate apply (the second
23
+ // blocks until the first finishes).
24
24
  export const MIGRATION_ADVISORY_LOCK_KEY = 0x6b756d69; // "kumi" in ASCII
25
25
  const MIGRATIONS_TABLE_DDL = `
26
26
  CREATE TABLE IF NOT EXISTS "_kumiko_migrations" (
@@ -147,7 +147,7 @@ function sha256Hex(content) {
147
147
  // returns Migration[] with id + checksum + statements. `preprocess` is an
148
148
  // optional hook applied to each file's raw content before splitting/hashing
149
149
  // — used by replayMigrationsDir to expand its DESTRUCTIVE-marker comments
150
- // without a second, drifting copy of this file-discovery logic (#1522/9).
150
+ // without a second, drifting copy of this file-discovery logic.
151
151
  export function loadMigrationsFromDir(dir, preprocess) {
152
152
  const files = readdirSync(dir)
153
153
  .filter((f) => f.endsWith(".sql"))
@@ -230,9 +230,9 @@ export class MigrationChecksumMismatchError extends Error {
230
230
  this.name = "MigrationChecksumMismatchError";
231
231
  }
232
232
  }
233
- // Apply pending migrations. Idempotent: schon applied migrations werden via
234
- // _kumiko_migrations-Lookup übersprungen. Checksum-Mismatch wirft fail-loud.
235
- // Advisory-Lock verhindert concurrent-apply-races.
233
+ // Applies pending migrations. Idempotent: already-applied migrations are
234
+ // skipped via the _kumiko_migrations lookup. Checksum mismatches fail loudly.
235
+ // The advisory lock prevents concurrent-apply races.
236
236
  export async function runMigrations(db, migrations) {
237
237
  // Session-level advisory lock and per-migration BEGIN/COMMIT must share one
238
238
  // session. Pool calls may land on different connections (the pool round-robins),
@@ -256,9 +256,9 @@ export async function runMigrations(db, migrations) {
256
256
  skippedIds.push(m.id);
257
257
  continue;
258
258
  }
259
- // Apply file content + INSERT tracking-row in einer TX. Wenn ein
260
- // Statement bricht, Rollback inkl. Tracking-Row → kein partial-apply
261
- // stuck in den books.
259
+ // Applies the file content and INSERT tracking row in one transaction. If a
260
+ // statement fails, the rollback includes the tracking row, so no partial
261
+ // apply remains stuck in the books.
262
262
  await conn.unsafe("BEGIN");
263
263
  try {
264
264
  for (const stmt of m.statements) {
@@ -280,7 +280,10 @@ export async function runMigrations(db, migrations) {
280
280
  return { applied: appliedIds, skipped: skippedIds };
281
281
  }
282
282
  finally {
283
- await conn.unsafe(`SELECT pg_advisory_unlock(${MIGRATION_ADVISORY_LOCK_KEY})`);
283
+ // A dropped session already released its lock; failing here would mask the migration error.
284
+ await conn
285
+ .unsafe(`SELECT pg_advisory_unlock(${MIGRATION_ADVISORY_LOCK_KEY})`)
286
+ .catch(() => undefined);
284
287
  }
285
288
  }
286
289
  finally {
@@ -289,8 +292,8 @@ export async function runMigrations(db, migrations) {
289
292
  await conn.release();
290
293
  }
291
294
  }
292
- // Convenience: load + run in einem Call. Wird vom `kumiko migrate apply`
293
- // CLI-Command + von Test-Setup-Helfern verwendet.
295
+ // Convenience: loads and runs migrations in one call. Used by the
296
+ // `kumiko migrate apply` CLI command and by test setup helpers.
294
297
  export async function runMigrationsFromDir(db, dir) {
295
298
  const migrations = loadMigrationsFromDir(dir);
296
299
  return runMigrations(db, migrations);
@@ -15,17 +15,17 @@ export type MoneyRead = {
15
15
  * @deprecated Removed in 0.390.0. Use `amountScaled` — this name implies ISO-4217 minor units
16
16
  * (cents), which is wrong once a currency needing a different scale than
17
17
  * the current flat MINOR_UNIT_SCALE=100 lands (e.g. JPY, 0 decimals).
18
- * Alias of `amountScaled`, kept until #1976/4 and #1976/5 migrate their
19
- * consumers off it.
18
+ * Alias of `amountScaled`, kept until the consumers migrate off it.
20
19
  */
21
20
  readonly amountMinor: number;
22
21
  };
23
22
  /**
24
- * DB → API: zwei flache Spalten zu combined { amount, currency } rehydraten.
23
+ * Rehydrate two flat DB columns into a combined `{ amount, currency }` value.
25
24
  *
26
- * Wirft loud bei korrupter DB-Form (string das nicht zur Zahl wird) — silent
27
- * data-loss wäre Bug-Vektor. NULL/undefined amount → field aus Output entfernt.
25
+ * Throws loudly for corrupt DB values (for example, a string that cannot be
26
+ * converted to a number), because silent data loss would hide a bug. A
27
+ * NULL/undefined amount removes the field from the output.
28
28
  *
29
- * Pure — mutiert nicht.
29
+ * Pure — does not mutate its input.
30
30
  */
31
31
  export declare function rehydrateMoney(row: Record<string, unknown>, entity: EntityDefinition): Record<string, unknown>;
package/dist/db/money.js CHANGED
@@ -1,17 +1,17 @@
1
- // Auto-Convert für money-Felder im DB-Layer.
1
+ // Automatically convert money fields in the DB layer.
2
2
  //
3
- // Vertrag (siehe auch db/located-timestamp.ts — gleicher Compound-Type-Pattern):
4
- // API-Form: { amount, currency } | number — amount in MAJOR units (56799.16 EUR)
5
- // DB-Form: <name> BIGINT (minor units, e.g. cents) + <name>Currency TEXT
6
- // Read-Form: { amount, currency, amountScaled } — amount in MAJOR units again,
7
- // amountScaled sits alongside as the exact integer value in
8
- // MINOR_UNIT_SCALE units (fw#1830) for callers that need
9
- // scale-exact comparisons (e.g. invoice sums) instead of
10
- // round-tripping the float amount through /100·*100.
3
+ // Contract (see also db/located-timestamp.ts — the same compound-type pattern):
4
+ // API form: { amount, currency } | number — amount in MAJOR units (56799.16 EUR)
5
+ // DB form: <name> BIGINT (minor units, e.g. cents) + <name>Currency TEXT
6
+ // Read form: { amount, currency, amountScaled } — amount in MAJOR units again,
7
+ // amountScaled sits alongside as the exact integer value in
8
+ // MINOR_UNIT_SCALE units for callers that need scale-exact
9
+ // comparisons (e.g. invoice sums) instead of round-tripping the
10
+ // float amount through /100·*100.
11
11
  // `amountMinor` stays as a @deprecated alias of the same
12
- // value until #1976/4 and #1976/5 migrate their remaining
13
- // consumers (renderer/web/primitives/index.tsx,
14
- // renderer/components/render-field.tsx) off the old name.
12
+ // value until the remaining consumers
13
+ // (renderer/web/primitives/index.tsx,
14
+ // renderer/components/render-field.tsx) migrate off the old name.
15
15
  //
16
16
  // table-builder.ts's moneyAmount column has always documented BIGINT as
17
17
  // "the integer minor unit" — this file used to just pass the API amount
@@ -23,13 +23,13 @@
23
23
  // pass/receive ordinary decimal amounts; DB storage stays exact-integer
24
24
  // cents (no float drift in SUM()/aggregate queries).
25
25
  //
26
- // Permissiv-Insert: primitive number wird als amount akzeptiert (Legacy aus
27
- // pre-Stufe-3-Samples). Currency fällt dann auf entity.defaultCurrency
28
- // zurück (oder DEFAULT_CURRENCIES[0] = "EUR" als Framework-Fallback).
26
+ // Permissive insert: a primitive number is accepted as amount (legacy from
27
+ // pre-Stufe-3 samples). Currency then falls back to entity.defaultCurrency
28
+ // (or DEFAULT_CURRENCIES[0] = "EUR" as the framework fallback).
29
29
  //
30
- // Anders als locatedTimestamp behalten wir den Field-Namen `<name>` als
31
- // amount-Spalte (Legacy DB-Convention für Money — `SUM(buying_price)` bleibt
32
- // idiomatisch). `<name>Currency` ist die zusätzliche Spalte.
30
+ // Unlike locatedTimestamp, we retain the field name `<name>` as the
31
+ // amount column (legacy DB convention for money — `SUM(buying_price)` remains
32
+ // idiomatic). `<name>Currency` is the additional column.
33
33
  import { MINOR_UNIT_SCALE, toMinorUnits } from "../engine/minor-units.js";
34
34
  import { DEFAULT_CURRENCIES } from "../engine/types/index.js";
35
35
  const FRAMEWORK_DEFAULT_CURRENCY = DEFAULT_CURRENCIES[0]; // "EUR"
@@ -46,9 +46,9 @@ function toMajorUnits(amountScaled) {
46
46
  // scaled the same way. `applyTotalsMatchRefinements` (schema-builder.ts)
47
47
  // uses this internally for `EmbeddedFieldDef.totalsMatch`; exported so a
48
48
  // custom write-handler doing its own total check doesn't have to re-derive
49
- // this unwrap-and-scale step by hand (kumiko-framework#1972 — a hand-rolled
50
- // comparison of a raw `{amount}` against a raw minor-unit row sum is exactly
51
- // what silently fails 100x off).
49
+ // this unwrap-and-scale step by hand. A hand-rolled comparison of a raw
50
+ // `{amount}` against a raw minor-unit row sum is exactly what silently fails
51
+ // 100× off.
52
52
  export function moneyPayloadToMinorUnits(raw) {
53
53
  if (typeof raw === "number")
54
54
  return toMinorUnits(raw);
@@ -81,7 +81,7 @@ export function flattenMoney(payload, entity) {
81
81
  }
82
82
  else if (typeof raw === "number") {
83
83
  amount = raw;
84
- // Expliziter currency-key im Payload überschreibt den Default-Fallback.
84
+ // An explicit currency key in the payload overrides the default fallback.
85
85
  const explicitCurrency = result[`${name}Currency`];
86
86
  currency = typeof explicitCurrency === "string" ? explicitCurrency : fallbackCurrency;
87
87
  }
@@ -95,12 +95,13 @@ export function flattenMoney(payload, entity) {
95
95
  return result;
96
96
  }
97
97
  /**
98
- * DB → API: zwei flache Spalten zu combined { amount, currency } rehydraten.
98
+ * Rehydrate two flat DB columns into a combined `{ amount, currency }` value.
99
99
  *
100
- * Wirft loud bei korrupter DB-Form (string das nicht zur Zahl wird) — silent
101
- * data-loss wäre Bug-Vektor. NULL/undefined amount → field aus Output entfernt.
100
+ * Throws loudly for corrupt DB values (for example, a string that cannot be
101
+ * converted to a number), because silent data loss would hide a bug. A
102
+ * NULL/undefined amount removes the field from the output.
102
103
  *
103
- * Pure — mutiert nicht.
104
+ * Pure — does not mutate its input.
104
105
  */
105
106
  export function rehydrateMoney(row, entity) {
106
107
  const result = { ...row };
@@ -126,7 +127,8 @@ export function rehydrateMoney(row, entity) {
126
127
  }
127
128
  }
128
129
  else if (typeof amountRaw === "string" && amountRaw !== "") {
129
- // PG-driver liefert BIGINT manchmal als String (>2^53 sicher).
130
+ // The PG driver sometimes returns BIGINT as a string (when it exceeds the
131
+ // safe integer range of 2^53).
130
132
  amountScaled = Number(amountRaw);
131
133
  if (!Number.isSafeInteger(amountScaled)) {
132
134
  throw new Error(`rehydrateMoney: field "${name}" amount string "${amountRaw}" is not a safe integer — DB corruption?`);
@@ -1,18 +1,18 @@
1
- // One-time backfill for pre-KMS plaintext PII in kumiko_events (#799).
1
+ // One-time backfill for pre-KMS plaintext PII in kumiko_events.
2
2
  //
3
- // Crypto-shredding (#724/#818) only covers NEW writes — events appended
3
+ // Crypto-shredding only covers NEW writes — events appended
4
4
  // before a KMS was configured still carry plaintext (user.created email,
5
5
  // delivery attempt recipientAddress, job payloads). This tool re-encrypts
6
6
  // them in place, per field, under the owning subject's DEK:
7
7
  //
8
8
  // - entity lifecycle events (<entity>.created/updated/deleted/forgotten/
9
9
  // restored) for every entity with PII subject annotations — generic over
10
- // subject kind (user/tenant/record, fw#2790), since it goes through the
10
+ // subject kind (user/tenant/record), since it goes through the
11
11
  // same collectPiiEncryptedFields/resolveSubjectForField the live write
12
12
  // path uses
13
13
  // - custom events from the event-PII catalog (r.defineEvent piiFields) —
14
14
  // user/tenant/self subjects, via the same resolveEventSubject the live
15
- // append path uses (fw#2801)
15
+ // append path uses
16
16
  //
17
17
  // Already-forgotten subjects must NOT get a fresh key minted for their old
18
18
  // plaintext — three erased-detection layers write [[erased]] instead:
@@ -28,7 +28,7 @@
28
28
  // Owner resolution for entity-lifecycle events. The live write path
29
29
  // (event-store-executor-write.ts) resolves the same chain via
30
30
  // subject-resolver.ts: row owner, then the owner the same event sets, then
31
- // the field's whenAbsent (fw#3654). Backfill adds two opt-in stages and
31
+ // the field's whenAbsent. Backfill adds two opt-in stages and
32
32
  // delays whenAbsent behind the projection so a known owner is never shadowed:
33
33
  // 1. payload — the event section (plus the owner the same event sets) names
34
34
  // the owner field; whenAbsent is not applied yet.
@@ -12,7 +12,7 @@ export async function alterTableAddColumn(db, tableName, columnName, columnType,
12
12
  // throwing when a column already exists with a different shape than
13
13
  // EntityTableMeta expects — that's how it surfaces drift. Callers that
14
14
  // just need an idempotent, race-safe backfill (e.g. event-consumer-state's
15
- // multi-instance boot path, #1362) opt in explicitly.
15
+ // multi-instance boot path) opt in explicitly.
16
16
  ifNotExists = false) {
17
17
  await asRawClient(db).unsafe(`ALTER TABLE ${quoteTableIdent(tableName)} ADD COLUMN ${ifNotExists ? "IF NOT EXISTS " : ""}${quoteTableIdent(columnName)} ${columnType}${defaultClause}${notNull}`);
18
18
  }
@@ -1,5 +1,5 @@
1
1
  import type { AnyDb } from "../query.ts";
2
- /** Stabiler Lock-Key für pg_advisory_xact_lock — multi-replica seed boots. */
2
+ /** Stable lock key for pg_advisory_xact_lock across multi-replica seed boots. */
3
3
  export declare const ES_OPS_ADVISORY_LOCK_KEY = 1702063984;
4
4
  export declare function acquireEsOpsAdvisoryLock(db: AnyDb): Promise<void>;
5
5
  export declare function esOperationExists(db: AnyDb, operationId: string): Promise<boolean>;
@@ -1,5 +1,5 @@
1
1
  import { asRawClient } from "../query.js";
2
- /** Stabiler Lock-Key für pg_advisory_xact_lock — multi-replica seed boots. */
2
+ /** Stable lock key for pg_advisory_xact_lock across multi-replica seed boots. */
3
3
  export const ES_OPS_ADVISORY_LOCK_KEY = 0x65_73_6f_70; // 'esop'
4
4
  export async function acquireEsOpsAdvisoryLock(db) {
5
5
  await asRawClient(db).unsafe(`SELECT pg_advisory_xact_lock($1)`, [ES_OPS_ADVISORY_LOCK_KEY]);
@@ -24,7 +24,7 @@ export async function lockEventConsumersShareMode(db) {
24
24
  await asRawClient(db).unsafe(`LOCK TABLE "kumiko_event_consumers" IN SHARE MODE`);
25
25
  }
26
26
  // The MAX(id) horizon plus every currently-open id gap below it, read from a
27
- // single statement snapshot. Used both to seed startFrom "now" (#3231) and to
27
+ // single statement snapshot. Used both to seed startFrom "now" and to
28
28
  // seed an MSP rebuild's handoff to the live dispatcher (msp-rebuild.ts).
29
29
  //
30
30
  // Scan lower bound: the consumer with the highest cursor already tracks every
@@ -84,7 +84,7 @@ export async function selectEventIdHorizonWithMissingRanges(db) {
84
84
  // WithMissingRanges): a transaction holding a lower id can still be
85
85
  // in-flight at boot, and without seeding those gaps its event would commit
86
86
  // after the cursor already sits above it, so `id > cursor` would never
87
- // deliver it (#3231). The cheap existence check skips the scan entirely for
87
+ // deliver it. The cheap existence check skips the scan entirely for
88
88
  // the (overwhelmingly common) case of an already-registered consumer.
89
89
  // ON CONFLICT DO NOTHING keeps both branches safe for an existing row: the
90
90
  // subquery only ever affects the row this statement inserts.
@@ -144,7 +144,7 @@ export async function markConsumerProcessing(db, name, instanceId) {
144
144
  // repeated infra blips (the exact case this backoff exists for) dead-letter
145
145
  // the consumer on the next real handler failure instead of after
146
146
  // maxAttempts. Visibility is covered by last_error, updated_at, and the
147
- // caller's console.error — status and the cursor are left as-is too, since
147
+ // caller's error log — status and the cursor are left as-is too, since
148
148
  // we don't know at this point whether the consumer should be "dead" (that's
149
149
  // the deliverEvents/maxAttempts contract, which never ran this pass).
150
150
  //
@@ -1,7 +1,9 @@
1
+ import { createFallbackLogger } from "../../logging/utils.js";
1
2
  import { constraintOf, isLockNotAvailable, isTableAlreadyExists, isUniqueViolation, } from "../pg-error.js";
2
3
  import { asRawClient, runInNewTransaction, runnerCanBeginTransaction, unsafeReadRetrying, } from "../query.js";
3
4
  import { withoutStatementTimeout } from "../statement-timeout.js";
4
5
  import { toPostgresArrayLiteral } from "./postgres-array-literal.js";
6
+ const log = createFallbackLogger("event-store");
5
7
  // Gap-finality (event-dispatcher pending_gaps) needs every holder of an
6
8
  // event id to already have a *real* xact id by the time it inserts — Postgres
7
9
  // assigns those lazily on first write, so a bare INSERT alone doesn't
@@ -81,9 +83,9 @@ async function buildIdempotencyKeyIndex(db) {
81
83
  // skip: sibling pod already built a valid index — this race loser is done.
82
84
  if ((await indexValidity(client)) === true)
83
85
  return;
84
- console.warn(`ensureIdempotencyKeyIndex: backed off on a "benign" race (${String(e)}) but ` +
86
+ log.warn(`ensureIdempotencyKeyIndex: backed off on a "benign" race but ` +
85
87
  `"events_idempotency_uq" is still missing/invalid afterward — likely a ` +
86
- `lock_timeout during CREATE INDEX CONCURRENTLY, not an actual winner/loser race.`);
88
+ `lock_timeout during CREATE INDEX CONCURRENTLY, not an actual winner/loser race.`, { err: e });
87
89
  throw e;
88
90
  }
89
91
  throw duplicateIdempotencyKeyErrorOr(e);
@@ -14,7 +14,7 @@ export async function markProjectionRebuilding(db, projectionName) {
14
14
  export async function selectEventsForProjectionRebuildBatch(db, aggregateTypes, eventTypes, afterId, limit) {
15
15
  // Archived streams don't replay (Marten-aligned): their aggregates are
16
16
  // frozen ops-tombstones — replaying them would resurrect rows (or, for
17
- // stranded duplicate-aggregates like fw#832, collide on unique indexes).
17
+ // stranded duplicate-aggregates, collide on unique indexes).
18
18
  return unsafeReadRetrying(db, `SELECT * FROM "kumiko_events" e
19
19
  WHERE e."aggregate_type" = ANY($1::text[])
20
20
  AND e."type" = ANY($2::text[])
@@ -29,9 +29,9 @@ export async function selectEventsForProjectionRebuildBatch(db, aggregateTypes,
29
29
  // Total subscribed events in the log — same source/type filter as
30
30
  // selectEventsForProjectionRebuildBatch, no id cursor. Under the cutover fence
31
31
  // this is the ground-truth count the rebuild must have applied; a shortfall
32
- // means a lower-id event committed late and the id-cursor leapt past it (#443).
32
+ // means a lower-id event committed late and the id-cursor leapt past it.
33
33
  export async function countSubscribedEvents(db, aggregateTypes, eventTypes) {
34
- // Same archived-streams exclusion as the batch query — the #443 recompute
34
+ // Same archived-streams exclusion as the batch query — the recompute
35
35
  // compares this count against applied events; a filter mismatch would make
36
36
  // every rebuild with an archived stream loop the full-re-replay forever.
37
37
  const rows = await unsafeReadRetrying(db, `SELECT count(*)::bigint AS n FROM "kumiko_events" e
@@ -1,9 +1,9 @@
1
1
  import type { AnyDb } from "../query.ts";
2
2
  /** Escape hatch for caller-built SQL that may write (or lock). No closed-connection retry —
3
- * retrying an ambiguous write risks double-apply (#1358). Prefer {@link executeRawQueryRead}
3
+ * retrying an ambiguous write risks double-apply. Prefer {@link executeRawQueryRead}
4
4
  * for SELECT-only paths. */
5
5
  export declare function executeRawQuery<T = Record<string, unknown>>(db: AnyDb, sqlText: string, params?: readonly unknown[]): Promise<readonly T[]>;
6
- /** SELECT-only escape hatch with the #1163 closed-connection retry. Do not pass
6
+ /** SELECT-only escape hatch with the closed-connection retry. Do not pass
7
7
  * INSERT/UPDATE/DELETE — retry re-executes the statement. */
8
8
  export declare function executeRawQueryRead<T = Record<string, unknown>>(db: AnyDb, sqlText: string, params?: readonly unknown[]): Promise<readonly T[]>;
9
9
  export declare function pingDatabase(db: AnyDb): Promise<void>;
@@ -1,11 +1,11 @@
1
1
  import { asRawClient, unsafeReadRetrying } from "../query.js";
2
2
  /** Escape hatch for caller-built SQL that may write (or lock). No closed-connection retry —
3
- * retrying an ambiguous write risks double-apply (#1358). Prefer {@link executeRawQueryRead}
3
+ * retrying an ambiguous write risks double-apply. Prefer {@link executeRawQueryRead}
4
4
  * for SELECT-only paths. */
5
5
  export async function executeRawQuery(db, sqlText, params = []) {
6
6
  return await asRawClient(db).unsafe(sqlText, params);
7
7
  }
8
- /** SELECT-only escape hatch with the #1163 closed-connection retry. Do not pass
8
+ /** SELECT-only escape hatch with the closed-connection retry. Do not pass
9
9
  * INSERT/UPDATE/DELETE — retry re-executes the statement. */
10
10
  // @wrapper-known semantic-alias
11
11
  export async function executeRawQueryRead(db, sqlText, params = []) {
@@ -64,10 +64,10 @@ export function rebuildMetaOrThrow(table, projectionName) {
64
64
  return meta;
65
65
  }
66
66
  // Fence against a rebuild running with a registry that does not match the
67
- // migrated live schema (#835): during a rolling deploy, a pod still running
67
+ // migrated live schema: during a rolling deploy, a pod still running
68
68
  // the previous build can pick up an async rebuild job; its shadow — built from
69
69
  // the stale EntityTableMeta — would swap away a freshly-migrated column
70
- // (recurrence class of #494). Compares COLUMN NAMES only; a type-/nullability-
70
+ // (a recurring failure). Compares COLUMN NAMES only; a type-/nullability-
71
71
  // only drift passes (schema regression, not data loss — the boot gate of the
72
72
  // next deploy catches it). A missing live table is fine: nothing to wipe.
73
73
  // Must run BEFORE buildShadowTable; columnNamesOf pins table_schema='public',
@@ -93,7 +93,7 @@ export async function assertLiveColumnsMatchMeta(db, meta, projectionName) {
93
93
  "Rebuilding would swap away the difference. Likely cause: this pod runs a build whose registry is behind (or ahead of) the applied migrations — rolling deploy in progress? — or DDL was applied by hand. " +
94
94
  "Rebuild aborted; retry from a pod whose code matches the migrated schema.");
95
95
  }
96
- // EntityTableMeta carries no RLS/policies, so the swap would silently drop them (#2907).
96
+ // EntityTableMeta carries no RLS/policies, so the swap would silently drop them.
97
97
  export async function assertLiveTableHasNoRowLevelSecurity(tx, tableName, projectionName) {
98
98
  const rows = await asRawClient(tx).unsafe(`SELECT c.relrowsecurity AS rls_enabled, c.relforcerowsecurity AS rls_forced,
99
99
  (SELECT count(*)::int FROM pg_policy p WHERE p.polrelid = c.oid) AS policy_count
@@ -158,7 +158,7 @@ const UNREACHABLE_SAMPLE_LIMIT = 20;
158
158
  // Runs INSIDE the rebuild tx, under the fence, before swapShadowIntoLive. A live
159
159
  // row whose aggregate id has NO event in the projection's source streams is
160
160
  // UNREACHABLE: no replay can ever reconstruct it, so the swap would silently
161
- // drop it. That is the #498 ghost — a row direct-inserted without ever emitting
161
+ // drop it. That is a ghost row direct-inserted without ever emitting
162
162
  // a .created event. The static CI guard cannot see it in data that already
163
163
  // exists in production, or on table identifiers it couldn't resolve; this
164
164
  // catches it at cutover and aborts (tx rolls back, live untouched).
@@ -169,14 +169,14 @@ const UNREACHABLE_SAMPLE_LIMIT = 20;
169
169
  // - a blind-index column recomputed to NULL after the subject's key is
170
170
  // shredded (GDPR erase) — the NULL is the intended end state;
171
171
  // - a `sensitive` column stripped from the event log by design;
172
- // - an archived stream that stops replaying (fw#832) — the row's wipe is the
172
+ // - an archived stream that stops replaying — the row's wipe is the
173
173
  // intended tombstone behavior, reported via backfill's `failed` list;
174
174
  // - a legacy column direct-written before its handler emitted events, healed
175
- // by the #494 backfill-then-rebuild flow.
175
+ // by the backfill-then-rebuild flow.
176
176
  // Checking event existence INCLUDING archived streams leaves every one of them
177
177
  // alone: those rows all have a real event, so they are not ghosts. Column-level
178
- // drift is a SEPARATE, non-blocking check — see countColumnDrift below (#916,
179
- // resolves the #722 open question: observe, don't block).
178
+ // drift is a SEPARATE, non-blocking check — see countColumnDrift below,
179
+ // which resolves the open question: observe, don't block.
180
180
  //
181
181
  // Implicit projections only (caller-gated). aggregate_id and the entity id are
182
182
  // both uuid, so the anti-join probes the events index without a cast.
@@ -298,8 +298,8 @@ async function assertBlindIndexKeyMatchesLive(raw, tableName, quotedTable, bidxC
298
298
  `untouched.`);
299
299
  }
300
300
  // The bidx column is schema-driven, not key-driven: it exists NULL in a
301
- // plaintext install and in the fw#1610 case (KMS configured, no index key),
302
- // both of which are correct as-is. Only a POPULATED column with no key
301
+ // plaintext install and in the case where KMS is configured but no index key
302
+ // is present, both of which are correct as-is. Only a POPULATED column with no key
303
303
  // configured in THIS process means the rebuild is about to overwrite proof
304
304
  // of a real index with NULL — that's the one provable data-loss case.
305
305
  export async function assertNoBlindIndexLoss(tx, tableName, meta, projectionName) {
@@ -331,29 +331,29 @@ export async function assertNoBlindIndexLoss(tx, tableName, meta, projectionName
331
331
  // live-vs-shadow divergence. A blind-index column (`<field>_bidx`) is
332
332
  // recomputed to NULL on GDPR key-shredding; the NULL is the intended end
333
333
  // state, not drift. Everything else that legitimately diverges (archived
334
- // streams, #494 backfill) either never reaches this comparison (archived rows
334
+ // streams, backfill) either never reaches this comparison (archived rows
335
335
  // are absent from the shadow entirely, see swapShadowIntoLive) or IS real
336
- // column drift that the #494 backfill-then-rebuild flow relies on replay to
336
+ // column drift that the backfill-then-rebuild flow relies on replay to
337
337
  // heal — reporting it (without blocking) is correct, not a false positive.
338
338
  const COLUMN_DRIFT_SAMPLE_LIMIT = 20;
339
339
  // Runs INSIDE the rebuild tx, in the same slot as assertNoUnreachableLiveRows
340
340
  // (after replay settles, before swapShadowIntoLive). Non-blocking counterpart
341
341
  // to the ghost-row guard: reports live rows whose column values differ from
342
- // the freshly-replayed shadow, WITHOUT aborting the swap (#916, resolves the
343
- // #722 open question in favor of observe-not-block).
342
+ // the freshly-replayed shadow, WITHOUT aborting the swap (it resolves the
343
+ // open question in favor of observe-not-block).
344
344
  //
345
345
  // Why non-blocking: a legacy column direct-written before its handler emitted
346
- // events (#494) diverges from replay by design — that divergence is exactly
346
+ // events diverges from replay by design — that divergence is exactly
347
347
  // what the backfill-then-rebuild flow relies on replay to heal. Failing hard
348
348
  // here would make rebuild mutually exclusive with that shipped healing path.
349
- // There is no reliable metadata to distinguish "#494 healing in progress" from
349
+ // There is no reliable metadata to distinguish "healing in progress" from
350
350
  // "someone else corrupted this row" short of an open-ended per-column policy
351
351
  // blocklist — wrong-by-default whenever a class is missed. So: surface it,
352
352
  // don't police it. The caller logs the result; ops decides.
353
353
  //
354
- // Caveat: sensitive CUSTOM fields still diverge until #972 (Subject-DEK
355
- // design) — regular sensitive fields carry event-payload ciphertext parity
356
- // post-#973 and don't drift. Both are reported the same as any other column
354
+ // Caveat: sensitive CUSTOM fields still diverge until the Subject-DEK
355
+ // design — regular sensitive fields carry event-payload ciphertext parity
356
+ // post-design and don't drift. Both are reported the same as any other column
357
357
  // drift; this is deliberate (see module comment above), not an oversight.
358
358
  //
359
359
  // Relies on assertLiveColumnsMatchMeta having already run: live/shadow/meta
@@ -1,9 +1,9 @@
1
1
  import type { AggregateRow, AggregateSpec } from "@cosmicdrift/kumiko-types/aggregate-types";
2
2
  import type { DbRunner, DbTx } from "@cosmicdrift/kumiko-types/db-connection";
3
3
  import type { ExecutorManagedRunner, ExecutorManagedWriteCapability, WritableTable } from "@cosmicdrift/kumiko-types/executor-brand";
4
- import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
5
4
  import type { SelectOptions, WhereObject } from "@cosmicdrift/kumiko-types/where-clause-types";
6
5
  import type { EntityTableMeta } from "./entity-table-meta.ts";
6
+ import { type TableInfo } from "./table-info.ts";
7
7
  import { asEntityTableMeta, requireEntityTableMeta } from "./table-introspection.ts";
8
8
  export { asEntityTableMeta, requireEntityTableMeta };
9
9
  export type ReservedClient = {
@@ -24,26 +24,14 @@ export declare function hasBegin(client: RawClient): client is RawClientWithBegi
24
24
  export declare function asRawClient(db: unknown): RawClient;
25
25
  export declare function runnerCanBeginTransaction(db: unknown): boolean;
26
26
  export declare function runInSavepoint<T>(tx: ExecutorManagedRunner, fn: (sp: ExecutorManagedRunner) => Promise<T>): Promise<T>;
27
- export declare function runInSavepoint<T>(tx: unknown, fn: (sp: unknown) => Promise<T>): Promise<T>;
27
+ export declare function runInSavepoint<T>(tx: unknown, fn: (sp: DbRunner) => Promise<T>): Promise<T>;
28
28
  export declare function runInSavepointIfSupported<T>(db: ExecutorManagedRunner, fn: (sp: ExecutorManagedRunner) => Promise<T>): Promise<T>;
29
29
  export declare function runInSavepointIfSupported<T>(db: unknown, fn: (sp: DbRunner) => Promise<T>): Promise<T>;
30
30
  export type AnyDb = DbRunner | unknown;
31
31
  type AnyRow = any;
32
32
  export type { JsonTextMatch, OrderByClause, SelectOptions, WhereObject, WhereOperator, WhereValue, } from "@cosmicdrift/kumiko-types/where-clause-types";
33
- type TableLike = EntityTableMeta | any;
34
- export type TableInfo = {
35
- readonly name: string;
36
- readonly columnOf: (field: string) => string;
37
- readonly pgTypeOf: (column: string) => string | undefined;
38
- readonly bigintJsModeOf: (column: string) => "number" | "bigint" | undefined;
39
- readonly fieldOf: (column: string) => string;
40
- readonly hasColumn: (fieldOrColumn: string) => boolean;
41
- };
42
- export declare function extractTableInfo(table: TableLike): TableInfo;
33
+ export type TableLike = EntityTableMeta | any;
43
34
  export declare function coerceRow<TOut = Record<string, unknown>>(row: Record<string, unknown>, info: TableInfo): TOut;
44
- export declare function instantToTimestamptzParam(instant: Temporal.Instant): string;
45
- export declare function isClosedConnectionError(err: unknown): boolean;
46
- export declare function describeClosedConnectionFailure(raw: unknown, err: unknown, attempts: number): Record<string, unknown> | undefined;
47
35
  export declare function unsafeReadRetrying<TRow>(db: AnyDb, sqlText: string, params: readonly unknown[]): Promise<readonly TRow[]>;
48
36
  export declare function selectMany<TRow = AnyRow>(db: AnyDb, table: TableLike, where?: WhereObject, options?: SelectOptions): Promise<readonly TRow[]>;
49
37
  export declare function fetchOne<TRow = AnyRow>(db: AnyDb, table: TableLike, where: WhereObject): Promise<TRow | undefined>;
@@ -92,7 +80,6 @@ export type DeleteManyBatchedResult = {
92
80
  readonly batches: number;
93
81
  };
94
82
  export declare function countWhere(db: AnyDb, table: TableLike, where?: WhereObject): Promise<number>;
95
- export declare function isTimestamptzType(pgType: string | undefined): boolean;
96
83
  export declare function aggregateWhere(db: AnyDb, table: TableLike, spec: AggregateSpec, where?: WhereObject): Promise<readonly AggregateRow[]>;
97
84
  export declare function upsertOnConflict<TRow = AnyRow>(db: AnyDb, table: WritableTable, values: Record<string, unknown>, options: UpsertOnConflictOptions): Promise<TRow | undefined>;
98
85
  export declare function upsertOnConflict<TRow = AnyRow>(db: ExecutorManagedWriteCapability, table: EntityTableMeta, values: Record<string, unknown>, options: UpsertOnConflictOptions): Promise<TRow | undefined>;