@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
@@ -7,130 +7,39 @@
7
7
  // NO-MAGIC-ON-DATA: reads only checked-in artifacts (kumiko/schema.ts →
8
8
  // ENTITY_METAS, kumiko/migrations/*.sql). Never auto-generates at runtime,
9
9
  // never applies on app-boot — apply/baseline are explicit deploy-steps.
10
- var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx) {
11
- if (typeof path === "string" && /^\.\.?\//.test(path)) {
12
- return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {
13
- return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js");
14
- });
15
- }
16
- return path;
17
- };
18
- import { existsSync, mkdirSync, readdirSync, writeFileSync } from "node:fs";
19
- import { join, resolve as resolvePath } from "node:path";
20
- import { configureBlindIndexKey, configurePiiSubjectKms, resolveKmsWiringAsync, } from "./crypto/index.js";
21
- import { assertUniqueTableNames, assertValidMigrationName, baselineMigrations, createDbConnection, diffReplayAgainstSnapshot, fetchAppliedMigrations, findCommentedDropTables, generateMigration, isRetiredFrameworkTable, loadMigrationsFromDir, loadSnapshotJson, readMigrationSqlTexts, rebuildTablesFromDiff, replayMigrationsDir, runMigrationsFromDir, tableExists, writeRebuildMarker, writeSnapshotJson, } from "./db/index.js";
22
- import { validateBoot } from "./engine/boot-validator.js";
23
- import { FILE_STORAGE_PROVIDER_BOOT_SENTINEL, FILE_STORAGE_PROVIDER_ENV, } from "./engine/extension-names.js";
24
- import { createRegistry } from "./engine/registry.js";
25
- import { createEventsTable } from "./event-store/index.js";
26
- import { queueRebuildsFromMarkers, reportPendingRebuildRun, runPendingRebuilds, } from "./migrations/index.js";
27
- import { createEventConsumerStateTable, createProjectionStateTable } from "./pipeline/index.js";
10
+ import { resolve as resolvePath } from "node:path";
11
+ import { isOneOf } from "@cosmicdrift/kumiko-types/type-guards";
12
+ import { runApplyCommand } from "./schema-cli/apply-command.js";
13
+ import { runBaselineCommand } from "./schema-cli/baseline-command.js";
14
+ import { runGenerateCommand } from "./schema-cli/generate-command.js";
15
+ import { runStatusCommand } from "./schema-cli/status-command.js";
16
+ import { runValidateCommand } from "./schema-cli/validate-command.js";
28
17
  import { ensureTemporalPolyfill } from "./time/index.js";
29
- const SNAPSHOT_FILENAME = ".snapshot.json";
30
- // `validate` only sees the composed FEATURES. The file provider normally comes from
31
- // runProdApp's `fileStorage` option, which defaults FILE_STORAGE_PROVIDER at boot, so
32
- // an unset variable here is no misconfiguration. The deploy env is checked by the real boot.
33
- function withFileStoragePresence(env) {
34
- return env[FILE_STORAGE_PROVIDER_ENV] === undefined
35
- ? { ...env, [FILE_STORAGE_PROVIDER_ENV]: FILE_STORAGE_PROVIDER_BOOT_SENTINEL }
36
- : { ...env };
37
- }
38
- function isStringSet(value) {
39
- return value instanceof Set && [...value].every((entry) => typeof entry === "string");
40
- }
41
- function isNonEmptyStringArray(value) {
42
- return Array.isArray(value) && value.every((entry) => typeof entry === "string" && entry !== "");
43
- }
44
- function isBoolean(value) {
45
- return typeof value === "boolean";
46
- }
47
- function validateBootOptionsError(detail) {
48
- return new Error(`kumiko/schema.ts: \`VALIDATE_BOOT_OPTIONS\` ${detail}`);
49
- }
50
- function readOptionalOption(raw, key, isValid, expected) {
51
- const value = Reflect.get(raw, key);
52
- if (value === undefined)
53
- return undefined;
54
- if (!isValid(value))
55
- throw validateBootOptionsError(`\`${key}\` must be ${expected}.`);
56
- return value;
57
- }
58
- // Boundary check for `export const VALIDATE_BOOT_OPTIONS` in kumiko/schema.ts.
59
- // Only the options that change what validateBoot reports are honoured; `env` and
60
- // `entityFieldCipher` are runner-injected and deliberately ignored here.
61
- function parseValidateBootOptions(raw) {
62
- if (raw === undefined)
63
- return {};
64
- if (typeof raw !== "object" || raw === null || Array.isArray(raw)) {
65
- throw validateBootOptionsError("must be an object (ValidateBootOptions).");
66
- }
67
- const navAllowlist = readOptionalOption(raw, "navAllowlist", isStringSet, "a Set<string>");
68
- const navAllowlistExempt = readOptionalOption(raw, "navAllowlistExempt", isStringSet, "a Set<string>");
69
- const warnOnUniqueAccessRoles = readOptionalOption(raw, "warnOnUniqueAccessRoles", isBoolean, "a boolean");
70
- const requiredLocales = readOptionalOption(raw, "requiredLocales", isNonEmptyStringArray, "an array of non-empty strings");
71
- return {
72
- ...(requiredLocales !== undefined && { requiredLocales }),
73
- ...(navAllowlist !== undefined && { navAllowlist }),
74
- ...(navAllowlistExempt !== undefined && { navAllowlistExempt }),
75
- ...(warnOnUniqueAccessRoles !== undefined && { warnOnUniqueAccessRoles }),
76
- };
77
- }
78
- // Single load-path for kumiko/schema.ts (512/3) — `generate` and `validate`
79
- // both need ENTITY_METAS (and validate additionally wants FEATURES); this is
80
- // the one place that enforces "ENTITY_METAS must be an array" so the two
81
- // commands can't drift on the check or its wording. Throws — callers that
82
- // want a graceful exit code (validate) catch it themselves.
83
- async function loadSchemaModFromApp(schemaFile) {
84
- // bun imports TS directly — no spawn needed.
85
- const mod = await import(__rewriteRelativeImportExtension(schemaFile));
86
- if (!Array.isArray(mod["ENTITY_METAS"])) {
87
- throw new Error(`Schema file ${schemaFile} muss \`export const ENTITY_METAS: EntityTableMeta[]\` haben.`);
88
- }
89
- const entityMetas = mod["ENTITY_METAS"];
90
- assertUniqueTableNames(entityMetas);
91
- return {
92
- entityMetas,
93
- features: mod["FEATURES"],
94
- validateBootOptions: mod["VALIDATE_BOOT_OPTIONS"],
95
- };
96
- }
97
- function nextSequenceNumber(migrationsDir) {
98
- if (!existsSync(migrationsDir))
99
- return 1;
100
- const files = readdirSync(migrationsDir).filter((f) => f.endsWith(".sql"));
101
- let max = 0;
102
- for (const f of files) {
103
- const m = f.match(/^(\d+)_/);
104
- if (m) {
105
- const n = Number(m[1]);
106
- if (n > max)
107
- max = n;
108
- }
109
- }
110
- return max + 1;
111
- }
112
- // A table that a migration only drops as a commented DESTRUCTIVE marker and
113
- // that the snapshot no longer has is gone on paper but still in the live DB.
114
- async function reportLeftoverDroppedTables(db, migrationsDir, out) {
115
- const snapshotPath = join(migrationsDir, SNAPSHOT_FILENAME);
116
- const snapshot = existsSync(snapshotPath) ? loadSnapshotJson(snapshotPath) : null;
117
- const leftovers = [];
118
- for (const tableName of findCommentedDropTables(readMigrationSqlTexts(migrationsDir), snapshot)) {
119
- if (await tableExists(db, tableName))
120
- leftovers.push(tableName);
121
- }
122
- // skip: nothing left over, nothing to report
123
- if (leftovers.length === 0)
124
- return;
125
- out.log(" Tables dropped only as a commented DESTRUCTIVE marker but still in the database:");
126
- for (const tableName of leftovers) {
127
- out.log(isRetiredFrameworkTable(tableName)
128
- ? ` ! ${tableName} — retired framework table: the next \`schema generate <name>\` creates the drop`
129
- : ` ! ${tableName} — app table: after a backup, write a new migration with the drop`);
130
- }
18
+ const SCHEMA_SUBCOMMANDS = ["generate", "validate", "apply", "baseline", "status"];
19
+ const SCHEMA_SUBCOMMAND_HANDLERS = {
20
+ generate: runGenerateCommand,
21
+ validate: runValidateCommand,
22
+ apply: runApplyCommand,
23
+ baseline: runBaselineCommand,
24
+ status: runStatusCommand,
25
+ };
26
+ const HELP_ARGS = ["--help", "-h", "help"];
27
+ function printSchemaCliUsage(out) {
28
+ out.log("");
29
+ out.log(" Subcommands:");
30
+ out.log(" generate <name> Write a new migration from the EntityTableMeta diff");
31
+ out.log(" validate Static CI gate (no DB): schema drift + validateBoot");
32
+ out.log(" apply Apply pending checked-in SQL files");
33
+ out.log(" baseline Mark checked-in migrations as applied (no SQL run)");
34
+ out.log(" status List applied vs pending");
131
35
  out.log("");
36
+ return 0;
37
+ }
38
+ function reportUnknownSubcommand(out, sub) {
39
+ out.err(` Unknown subcommand: "${sub}"`);
40
+ out.err(` Allowed: ${SCHEMA_SUBCOMMANDS.join(" | ")}`);
41
+ return 1;
132
42
  }
133
- const SCHEMA_SUBCOMMANDS = ["generate", "validate", "apply", "baseline", "status"];
134
43
  /**
135
44
  * Runs a schema-CLI subcommand. `appCwd` is the app workspace root (where
136
45
  * `kumiko/schema.ts` + `kumiko/migrations/` live). Returns a process exit code.
@@ -150,394 +59,22 @@ export async function runSchemaCli(argv, appCwd, out, options = {}) {
150
59
  // migration, since the crashed process still records the migration as
151
60
  // applied and the rebuild is never retried.
152
61
  await ensureTemporalPolyfill();
153
- // `--help`/`-h`/`help` fall through to the same "no subcommand" usage
154
- // branch below (undefined) — a real request for help, not a typo that
155
- // should fail loud like an unrecognized subcommand does.
156
62
  const rawSub = argv[0];
157
- const sub = rawSub === "--help" || rawSub === "-h" || rawSub === "help" ? undefined : rawSub;
158
- const schemaFile = resolvePath(appCwd, "kumiko/schema.ts");
159
- const migrationsDir = resolvePath(appCwd, "kumiko/migrations");
160
- switch (sub) {
161
- case "generate": {
162
- const name = argv[1];
163
- if (name === "--help" || name === "-h") {
164
- out.log(" Usage: schema generate <name>");
165
- return 0;
166
- }
167
- if (!name) {
168
- out.err(" Usage: schema generate <name>");
169
- return 1;
170
- }
171
- // name lands unescaped in `${seq}_${name}.sql` (generateMigration) —
172
- // shared allowlist blocks flag-like names, path traversal, and
173
- // ENAMETOOLONG-length names.
174
- try {
175
- assertValidMigrationName(name);
176
- }
177
- catch (e) {
178
- const msg = e instanceof Error ? e.message : String(e);
179
- out.err(` ${msg}`);
180
- out.err(" Usage: schema generate <name>");
181
- return 1;
182
- }
183
- // Trailing args (e.g. a typo'd `--dry-run` — there is no such flag) were
184
- // silently ignored and the migration got written anyway. Reject them
185
- // before any IO instead of pretending they did something.
186
- if (argv.length > 2) {
187
- out.err(` Unrecognized argument(s): ${argv.slice(2).join(" ")}`);
188
- out.err(" Usage: schema generate <name>");
189
- return 1;
190
- }
191
- if (!existsSync(schemaFile)) {
192
- out.err(` ${schemaFile} fehlt.`);
193
- out.err(" App-Convention: kumiko/schema.ts mit");
194
- out.err(" export const ENTITY_METAS: EntityTableMeta[] = [...]");
195
- return 1;
196
- }
197
- let metas;
198
- try {
199
- ({ entityMetas: metas } = await loadSchemaModFromApp(schemaFile));
200
- }
201
- catch (e) {
202
- out.err(` ${e instanceof Error ? e.message : String(e)}`);
203
- return 1;
204
- }
205
- const snapshotPath = join(migrationsDir, SNAPSHOT_FILENAME);
206
- const prevSnapshot = existsSync(snapshotPath) ? loadSnapshotJson(snapshotPath) : null;
207
- const result = generateMigration({
208
- metas,
209
- prevSnapshot,
210
- name,
211
- sequenceNumber: nextSequenceNumber(migrationsDir),
212
- priorMigrationsSql: readMigrationSqlTexts(migrationsDir),
213
- });
214
- const isEmpty = result.diff.newTables.length === 0 &&
215
- result.diff.changedTables.length === 0 &&
216
- result.diff.droppedTables.length === 0 &&
217
- result.retiredDrops.length === 0;
218
- if (isEmpty) {
219
- out.log(" No schema changes detected — kein neues Migration-File geschrieben.");
220
- return 0;
221
- }
222
- if (!existsSync(migrationsDir))
223
- mkdirSync(migrationsDir, { recursive: true });
224
- writeFileSync(join(migrationsDir, result.filename), result.sqlContent);
225
- writeSnapshotJson(snapshotPath, result.snapshot);
226
- // Rebuild-Marker nur für inkrementelle Migrationen — die Init-Migration
227
- // (prevSnapshot===null) legt nur Tabellen an, es gibt keine historischen
228
- // Events zum Replayen.
229
- const rebuildTables = prevSnapshot === null ? [] : rebuildTablesFromDiff(result.diff);
230
- writeRebuildMarker(migrationsDir, result.filename, rebuildTables);
231
- out.log("");
232
- out.log(` ✓ ${result.filename}`);
233
- out.log(` new tables: ${result.diff.newTables.length}, changed: ${result.diff.changedTables.length}, dropped: ${result.diff.droppedTables.length}, retired framework tables dropped: ${result.retiredDrops.length}`);
234
- if (rebuildTables.length > 0) {
235
- out.log(` rebuild-marker: ${result.filename.replace(/\.sql$/, ".rebuild.json")} (${rebuildTables.length} table(s))`);
236
- }
237
- out.log("");
238
- out.log(" Review + ggf. hand-edit + git add + commit. Apply via: schema apply");
239
- out.log("");
240
- return 0;
241
- }
242
- case "validate": {
243
- // Static, DB-free boot-blocking checks for CI — catches "this won't boot"
244
- // before deploy. Three layers, no database:
245
- // 1. schema drift: would `generate` write a migration? (= an entity was
246
- // added/changed but never generated → missing table → prod 500)
247
- // 2. boot validity: validateBoot over the composed FEATURES (QN/screen/
248
- // nav/role refs). Runs only if kumiko/schema.ts exports FEATURES;
249
- // honours its optional VALIDATE_BOOT_OPTIONS export.
250
- // 3. migration-content drift: replay every committed *.sql file and
251
- // diff the result against .snapshot.json — catches a migration
252
- // file whose SQL body doesn't match what its own snapshot entry
253
- // claims (e.g. an accidental copy-paste from an earlier file).
254
- // Layer 1 alone misses this: it only compares ENTITY_METAS to the
255
- // snapshot, never the snapshot to the SQL that's supposed to have
256
- // produced it.
257
- // The DB-level gate (assertKumikoSchemaCurrent) stays at boot/deploy.
258
- if (!existsSync(schemaFile)) {
259
- out.err(` ${schemaFile} fehlt.`);
260
- out.err(" App-Convention: kumiko/schema.ts mit");
261
- out.err(" export const ENTITY_METAS: EntityTableMeta[] = [...]");
262
- return 1;
263
- }
264
- let schemaMod;
265
- try {
266
- schemaMod = await loadSchemaModFromApp(schemaFile);
267
- }
268
- catch (e) {
269
- out.err(` ${e instanceof Error ? e.message : String(e)}`);
270
- return 1;
271
- }
272
- const mod = { FEATURES: schemaMod.features };
273
- let ok = true;
274
- // 1. Schema drift — compute the diff, never write.
275
- const metas = schemaMod.entityMetas;
276
- const snapshotPath = join(migrationsDir, SNAPSHOT_FILENAME);
277
- const prevSnapshot = existsSync(snapshotPath) ? loadSnapshotJson(snapshotPath) : null;
278
- const drift = generateMigration({
279
- metas,
280
- prevSnapshot,
281
- name: "validate",
282
- sequenceNumber: nextSequenceNumber(migrationsDir),
283
- priorMigrationsSql: readMigrationSqlTexts(migrationsDir),
284
- });
285
- const pendingTables = [
286
- ...drift.diff.newTables.map((t) => t.tableName),
287
- ...drift.diff.changedTables.map((t) => t.tableName),
288
- ...drift.diff.droppedTables,
289
- ...drift.retiredDrops.map((t) => t.tableName),
290
- ];
291
- if (pendingTables.length === 0) {
292
- out.log(" ✓ schema: migrations match the entity definitions");
293
- }
294
- else {
295
- ok = false;
296
- out.err(" ✗ schema drift: entity definitions are ahead of kumiko/migrations.");
297
- out.err(` pending — new: ${drift.diff.newTables.length}, changed: ${drift.diff.changedTables.length}, dropped: ${drift.diff.droppedTables.length}`);
298
- out.err(` tables: ${pendingTables.join(", ")}`);
299
- out.err(" Fix: `kumiko-schema generate <name>`, then commit the migration.");
300
- }
301
- // 2. Boot validity — needs the composed feature set.
302
- if (Array.isArray(mod.FEATURES)) {
303
- try {
304
- validateBoot(mod.FEATURES, {
305
- ...parseValidateBootOptions(schemaMod.validateBootOptions),
306
- env: withFileStoragePresence(process.env),
307
- });
308
- out.log(" ✓ boot: feature configuration is valid");
309
- }
310
- catch (e) {
311
- ok = false;
312
- out.err(` ✗ boot: ${e instanceof Error ? e.message : String(e)}`);
313
- }
314
- }
315
- else {
316
- out.log(" · boot: skipped — add `export const FEATURES = composeFeatures(APP_FEATURES, { includeBundled: true })` to kumiko/schema.ts to enable validateBoot.");
317
- }
318
- // 3. Migration-content drift — replay the committed *.sql files and
319
- // diff the reconstructed schema against .snapshot.json.
320
- if (existsSync(migrationsDir) && prevSnapshot !== null) {
321
- try {
322
- const replayed = replayMigrationsDir(migrationsDir);
323
- const mismatches = diffReplayAgainstSnapshot(replayed, prevSnapshot);
324
- if (mismatches.length === 0) {
325
- out.log(" ✓ migrations: table/column names match .snapshot.json");
326
- }
327
- else {
328
- ok = false;
329
- out.err(" ✗ migration-content drift: committed *.sql files don't produce .snapshot.json.");
330
- for (const m of mismatches) {
331
- out.err(` ${m.tableName} (${m.kind}): ${m.detail}`);
332
- }
333
- if (mismatches.some((m) => m.kind === "unexpected-table")) {
334
- out.err(" Fix (unexpected-table): build a meta via `defineUnmanagedTable()` " +
335
- "from `@cosmicdrift/kumiko-framework/db`, then `r.storeTable(meta, { reason: ... })` " +
336
- "inside a feature — this adds it to ENTITY_METAS immediately; the .snapshot.json " +
337
- "only picks it up on the NEXT `kumiko-schema generate` run, which you still need " +
338
- "to run and commit. `table()` returns a query handle, not a storeTable()-compatible " +
339
- "meta — don't pass its result to storeTable(). See the bundled `jobs` feature's " +
340
- "job-run-log store table for the pattern.");
341
- }
342
- if (mismatches.some((m) => m.kind !== "unexpected-table")) {
343
- out.err(" Fix (missing-table/column-drift): a migration file's body doesn't match " +
344
- "what it (or the snapshot) claims — hand-fix the file, or ship a corrective " +
345
- "migration if it's already applied in prod.");
346
- }
347
- }
348
- }
349
- catch (e) {
350
- // replayMigrationsDir fail-loud's on a table-DDL statement it can't
351
- // parse — that must surface as a normal ✗ line like every other
352
- // check here, not a raw stack trace that kills the process before
353
- // any later check (or the Fix: help) ever runs (framework#1535).
354
- ok = false;
355
- out.err(` ✗ migration-content: ${e instanceof Error ? e.message : String(e)}`);
356
- out.err(" Fix: a statement in a migration file isn't recognizable to the replay parser — extend the parser's recognized patterns, or reword the migration to one it understands.");
357
- }
358
- }
359
- return ok ? 0 : 1;
360
- }
361
- case "apply": {
362
- const dbUrl = process.env["DATABASE_URL"];
363
- if (!dbUrl) {
364
- out.err(" DATABASE_URL not set.");
365
- return 1;
366
- }
367
- if (!existsSync(migrationsDir)) {
368
- out.err(` ${migrationsDir} fehlt — erst schema generate <name>.`);
369
- return 1;
370
- }
371
- const { db, close } = createDbConnection({ url: dbUrl });
372
- let wiring;
373
- try {
374
- const result = await runMigrationsFromDir(db, migrationsDir);
375
- // Framework-Infra-Tabellen (event-store + pipeline-state) — die erfasst
376
- // `generate` nicht (nur Entity-read-Tabellen). Bestehende DBs haben sie
377
- // aus dem legacy-drizzle-Fundament; eine Greenfield-DB (erste App ohne
378
- // Cutover) hätte sonst kein kumiko_events → runProdApp-Boot scheitert.
379
- // Alle drei sind idempotent (tableExists-Gate), also no-op für Bestands-DBs.
380
- await createEventsTable(db);
381
- await createEventConsumerStateTable(db);
382
- await createProjectionStateTable(db);
383
- out.log("");
384
- if (result.applied.length === 0) {
385
- out.log(` ✓ All ${result.skipped.length} migrations already applied.`);
386
- }
387
- else {
388
- out.log(` ✓ Applied ${result.applied.length}:`);
389
- for (const id of result.applied)
390
- out.log(` + ${id}`);
391
- if (result.skipped.length > 0)
392
- out.log(` (${result.skipped.length} already applied)`);
393
- }
394
- out.log("");
395
- // Projection-rebuild for tables a freshly applied migration changed
396
- // (marker NNNN_<name>.rebuild.json from `generate`). Needs the composed
397
- // feature set → only when the caller passed `features` (the app bin);
398
- // the dev CLI omits it and applies migrations only. Runs unconditionally
399
- // (not gated on result.applied.length > 0): a persistent queue
400
- // (kumiko_pending_rebuilds) survives a failed/crashed rebuild from an
401
- // earlier apply, so a later apply with zero new migrations still must
402
- // retry it — otherwise a failed rebuild is silently never retried,
403
- // since the migration itself is already tracked applied (#2464).
404
- if (options.features) {
405
- // A rebuild replays applyEntityEvent, which computes bidx columns from
406
- // configureBlindIndexKey/configurePiiSubjectKms — both boot-injected by
407
- // run{Prod,Dev}App but never by this standalone CLI (the migrate-db
408
- // initContainer). Without wiring them here, a rebuild would silently
409
- // null out bidx columns and, for ciphertext, throw only once it hits
410
- // the row (fw#3091).
411
- wiring = await resolveKmsWiringAsync(process.env, {
412
- logPrefix: "[kumiko schema apply]",
413
- log: out.log,
414
- slots: options.kmsSlots,
415
- });
416
- if ("kms" in wiring) {
417
- configurePiiSubjectKms(wiring.kms);
418
- configureBlindIndexKey(wiring.blindIndexKey);
419
- }
420
- const thisRunTables = await queueRebuildsFromMarkers(db, {
421
- migrationsDir,
422
- appliedIds: result.applied,
423
- });
424
- const registry = createRegistry(options.features);
425
- const rebuildRun = await runPendingRebuilds(db, registry, { thisRunTables });
426
- reportPendingRebuildRun(rebuildRun, out.log);
427
- }
428
- return 0;
429
- }
430
- catch (e) {
431
- out.err("");
432
- out.err(` ✗ ${e instanceof Error ? (e.stack ?? e.message) : String(e)}`);
433
- out.err("");
434
- return 1;
435
- }
436
- finally {
437
- await wiring?.close();
438
- await close();
439
- }
440
- }
441
- case "baseline": {
442
- // Adopt an existing DB: mark all checked-in migrations as applied WITHOUT
443
- // running their SQL (prod tables already exist — cutover from the legacy
444
- // drizzle system). Afterwards the boot-gate is drift-free.
445
- const dbUrl = process.env["DATABASE_URL"];
446
- if (!dbUrl) {
447
- out.err(" DATABASE_URL not set.");
448
- return 1;
449
- }
450
- if (!existsSync(migrationsDir)) {
451
- out.err(` ${migrationsDir} fehlt — erst schema generate <name>.`);
452
- return 1;
453
- }
454
- const { db, close } = createDbConnection({ url: dbUrl });
455
- try {
456
- const result = await baselineMigrations(db, loadMigrationsFromDir(migrationsDir));
457
- out.log("");
458
- out.log(` ✓ Marked ${result.marked.length} migration(s) as applied (no SQL run):`);
459
- for (const id of result.marked)
460
- out.log(` + ${id}`);
461
- if (result.alreadyTracked.length > 0) {
462
- out.log(` (${result.alreadyTracked.length} already tracked)`);
463
- }
464
- out.log("");
465
- return 0;
466
- }
467
- catch (e) {
468
- out.err(` ✗ ${e instanceof Error ? e.message : String(e)}`);
469
- return 1;
470
- }
471
- finally {
472
- await close();
473
- }
474
- }
475
- case "status": {
476
- const dbUrl = process.env["DATABASE_URL"];
477
- if (!dbUrl) {
478
- out.err(" DATABASE_URL not set.");
479
- return 1;
480
- }
481
- if (!existsSync(migrationsDir)) {
482
- out.log(" Kein kumiko/migrations/ — App ist noch auf dem alten drizzle-Pfad.");
483
- return 0;
484
- }
485
- const local = loadMigrationsFromDir(migrationsDir);
486
- const { db, close } = createDbConnection({ url: dbUrl });
487
- try {
488
- // Frische DB ohne je gelaufenes `kumiko schema apply` → tracking-table
489
- // fehlt = "nichts applied". Connection-/Permission-Fehler dagegen
490
- // sollen NICHT geschluckt werden (False-pending verschleiert das Problem) —
491
- // tableExists prüft gezielt nur Existenz, alles andere propagiert.
492
- const trackingExists = await tableExists(db, "_kumiko_migrations");
493
- const applied = trackingExists
494
- ? new Set((await fetchAppliedMigrations(db)).map((a) => a.id))
495
- : new Set();
496
- out.log("");
497
- out.log(` ${local.length} migrations in ${migrationsDir}:`);
498
- for (const m of local)
499
- out.log(` ${applied.has(m.id) ? "✓" : " "} ${m.id}`);
500
- const pending = local.filter((m) => !applied.has(m.id)).length;
501
- out.log("");
502
- out.log(` ${applied.size} applied, ${pending} pending.`);
503
- out.log("");
504
- await reportLeftoverDroppedTables(db, migrationsDir, out);
505
- return pending === 0 ? 0 : 1;
506
- }
507
- catch (e) {
508
- // Message only, never dbUrl: it can carry the password.
509
- out.err(` ✗ schema status failed: ${e instanceof Error ? e.message : String(e)}`);
510
- out.err(' Check that DATABASE_URL is reachable and the database exists (the scaffold\'s docker-compose creates "app").');
511
- return 1;
512
- }
513
- finally {
514
- try {
515
- await close();
516
- }
517
- catch {
518
- // The connection already failed and was reported above; a failing close must not throw again.
519
- }
520
- }
521
- }
522
- default: {
523
- // No subcommand (`kumiko schema`) is a help request → usage + exit 0.
524
- // An unrecognized one (typo, e.g. `schema cutover`) must fail loud —
525
- // silently exiting 0 here let a deploy's migrate step print help and
526
- // move on without ever running a migration.
527
- if (sub !== undefined) {
528
- out.err(` Unbekanntes Subcommand: "${sub}"`);
529
- out.err(` Erlaubt: ${SCHEMA_SUBCOMMANDS.join(" | ")}`);
530
- return 1;
531
- }
532
- out.log("");
533
- out.log(" Subcommands:");
534
- out.log(" generate <name> Schreibe neue Migration aus EntityTableMeta-Diff");
535
- out.log(" validate Static CI-Gate (kein DB): schema-drift + validateBoot");
536
- out.log(" apply Applied pending checked-in SQL-Files");
537
- out.log(" baseline Markiere checked-in Migrations als applied (kein SQL-Run)");
538
- out.log(" status Liste applied vs pending");
539
- out.log("");
540
- return 0;
541
- }
542
- }
63
+ // No subcommand (`kumiko schema`) is a help request → usage + exit 0.
64
+ // `--help`/`-h`/`help` are the same — a real request for help, not a typo
65
+ // that should fail loud like an unrecognized subcommand does.
66
+ if (rawSub === undefined || isOneOf(HELP_ARGS, rawSub))
67
+ return printSchemaCliUsage(out);
68
+ // An unrecognized subcommand (typo, e.g. `schema cutover`) must fail loud —
69
+ // silently exiting 0 here let a deploy's migrate step print help and
70
+ // move on without ever running a migration.
71
+ if (!isOneOf(SCHEMA_SUBCOMMANDS, rawSub))
72
+ return reportUnknownSubcommand(out, rawSub);
73
+ return SCHEMA_SUBCOMMAND_HANDLERS[rawSub]({
74
+ argv,
75
+ out,
76
+ options,
77
+ schemaFile: resolvePath(appCwd, "kumiko/schema.ts"),
78
+ migrationsDir: resolvePath(appCwd, "kumiko/migrations"),
79
+ });
543
80
  }
@@ -1,7 +1,7 @@
1
- // Meilisearch-Adapter lebt im Sub-Path-Export `@cosmicdrift/kumiko-framework/search/meilisearch`.
2
- // Damit lädt der Main-Barrel keinen Meilisearch-Client beim bloßen Anfassen
3
- // von SearchAdapter-Types. Apps die Meilisearch nicht nutzen, ziehen den
4
- // Client-Code nicht mit rein.
1
+ // The Meilisearch adapter is exposed through the subpath export
2
+ // `@cosmicdrift/kumiko-framework/search/meilisearch`. This keeps the main barrel from loading a
3
+ // Meilisearch client when consumers only use SearchAdapter types, so apps that do not use
4
+ // Meilisearch do not pull in the client code.
5
5
  export { collectSearchableFieldNames, configureTenantSearchIndex, } from "./configure-tenant-index.js";
6
6
  export { deriveSearchAdapterConfig } from "./derive-search-adapter-config.js";
7
7
  export { createInMemorySearchAdapter } from "./in-memory-adapter.js";
@@ -34,7 +34,8 @@ function isSubsetOf(stored, wanted) {
34
34
  }
35
35
  // A stored list that lies inside the current default and misses attributes is an
36
36
  // older default that gained fields since; anything with a foreign attribute is
37
- // an explicit configure() and stays untouched.
37
+ // an explicit configure() and stays untouched. Known limit: an explicit configure() that
38
+ // narrowed to a strict subset of the default is indistinguishable and gets widened again.
38
39
  function isOutdatedDefault(stored, wanted) {
39
40
  const pairs = [
40
41
  [stored.searchable, wanted.searchable],
@@ -1,4 +1,4 @@
1
- // Purge derived search documents for an erased PII subject (#1610).
1
+ // Purge derived search documents for an erased PII subject.
2
2
  //
3
3
  // After kms.eraseKey the projection/event ciphertext is unreadable, but Meili
4
4
  // still holds the plaintext that createSearchEventConsumer decrypted into the
@@ -152,7 +152,7 @@ subject) {
152
152
  if (declaredFields.length === 0)
153
153
  continue;
154
154
  const tableName = resolveTableName(entityName, entity, undefined);
155
- // Same post-eraseKey hazard as nullBlindIndexesForSubject (fw#2550):
155
+ // Same post-eraseKey hazard as nullBlindIndexesForSubject:
156
156
  // a mounted feature without its migration must not abort the purge
157
157
  // (and the audit event after it).
158
158
  if (!(await tableExists(db, tableName)))
@@ -178,13 +178,12 @@ subject) {
178
178
  for (const [tenantId, items] of byTenant) {
179
179
  if (items.length === 0)
180
180
  continue;
181
- const tid = tenantId;
182
181
  if (search.removeBatch) {
183
- await search.removeBatch(tid, items);
182
+ await search.removeBatch(tenantId, items);
184
183
  }
185
184
  else {
186
185
  for (const item of items) {
187
- await search.remove(tid, item.entityType, item.entityId);
186
+ await search.remove(tenantId, item.entityType, item.entityId);
188
187
  }
189
188
  }
190
189
  }