@cosmicdrift/kumiko-framework 0.387.0 → 0.389.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 (375) hide show
  1. package/AGENTS.md +9 -1
  2. package/agents/examples/anonymous-access.md +1 -1
  3. package/agents/examples/apex-landing.md +204 -0
  4. package/agents/examples/api-worker-split.md +64 -0
  5. package/agents/examples/app-config.md +14 -0
  6. package/agents/examples/auth-mfa.md +115 -0
  7. package/agents/examples/env-composition.md +28 -1
  8. package/agents/examples/golden-path.md +13 -1
  9. package/agents/examples/legal-pages.md +1 -1
  10. package/agents/examples/lifecycle-hooks.md +55 -2
  11. package/agents/examples/list-table-options.md +466 -0
  12. package/agents/examples/pdf-audit-export.md +4 -2
  13. package/agents/examples/prod-boot-options.md +16 -0
  14. package/agents/examples/rate-limiting.md +48 -0
  15. package/agents/examples/record-detail-layout.md +692 -0
  16. package/agents/examples/seed-migration.md +212 -0
  17. package/agents/examples/state-machine.md +3 -2
  18. package/agents/examples/tenant-isolation.md +73 -1
  19. package/agents/examples/wizard-form.md +941 -0
  20. package/agents/examples/writeform-section.md +548 -0
  21. package/agents/examples.md +1 -0
  22. package/agents/features.md +19 -2
  23. package/agents/widgets.md +2 -0
  24. package/dist/api/api-constants.d.ts +1 -0
  25. package/dist/api/api-constants.js +2 -0
  26. package/dist/api/auth-routes-shared.d.ts +2 -0
  27. package/dist/api/auth-routes-shared.js +5 -0
  28. package/dist/api/client-error-route.js +10 -5
  29. package/dist/api/entity-read-access.d.ts +2 -1
  30. package/dist/api/entity-read-access.js +14 -0
  31. package/dist/api/export/export-cells-reference.d.ts +9 -0
  32. package/dist/api/export/export-cells-reference.js +21 -0
  33. package/dist/api/export/export-cells.d.ts +11 -0
  34. package/dist/api/export/export-cells.js +136 -0
  35. package/dist/api/export/export-ciphertext-guard.d.ts +2 -0
  36. package/dist/api/export/export-ciphertext-guard.js +27 -0
  37. package/dist/api/export/export-columns.d.ts +29 -0
  38. package/dist/api/export/export-columns.js +85 -0
  39. package/dist/api/export/export-errors.d.ts +4 -0
  40. package/dist/api/export/export-errors.js +14 -0
  41. package/dist/api/export/export-route.d.ts +4 -0
  42. package/dist/api/export/export-route.js +74 -0
  43. package/dist/api/export/export-rows.d.ts +13 -0
  44. package/dist/api/export/export-rows.js +62 -0
  45. package/dist/api/export/export-screen.d.ts +12 -0
  46. package/dist/api/export/export-screen.js +47 -0
  47. package/dist/api/export/export-xlsx-writer.d.ts +4 -0
  48. package/dist/api/export/export-xlsx-writer.js +21 -0
  49. package/dist/api/extra-route.d.ts +4 -0
  50. package/dist/api/index.d.ts +3 -1
  51. package/dist/api/index.js +3 -1
  52. package/dist/api/pii-leak-guard.d.ts +3 -0
  53. package/dist/api/pii-leak-guard.js +3 -2
  54. package/dist/api/request-context.d.ts +1 -1
  55. package/dist/api/request-context.js +1 -1
  56. package/dist/api/routes.d.ts +16 -0
  57. package/dist/api/routes.js +2 -2
  58. package/dist/api/server-boot-checks.d.ts +10 -0
  59. package/dist/api/server-boot-checks.js +157 -0
  60. package/dist/api/server-event-dispatcher.d.ts +26 -0
  61. package/dist/api/server-event-dispatcher.js +208 -0
  62. package/dist/api/server-extra-routes.d.ts +11 -0
  63. package/dist/api/server-extra-routes.js +206 -0
  64. package/dist/api/server-middleware.d.ts +20 -0
  65. package/dist/api/server-middleware.js +211 -0
  66. package/dist/api/server-routes.d.ts +19 -0
  67. package/dist/api/server-routes.js +299 -0
  68. package/dist/api/server-websocket-routes.d.ts +4 -0
  69. package/dist/api/server-websocket-routes.js +108 -0
  70. package/dist/api/server-wiring.d.ts +32 -0
  71. package/dist/api/server-wiring.js +238 -0
  72. package/dist/api/server.d.ts +10 -15
  73. package/dist/api/server.js +48 -1251
  74. package/dist/api/session-cookies.js +4 -4
  75. package/dist/api/sse-route.d.ts +2 -1
  76. package/dist/api/sse-route.js +27 -13
  77. package/dist/config/index.d.ts +3 -1
  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.d.ts +1 -0
  81. package/dist/crypto/pg-kms-adapter.js +12 -18
  82. package/dist/crypto/pii-field-encryption.d.ts +5 -1
  83. package/dist/crypto/pii-field-encryption.js +3 -1
  84. package/dist/db/aggregate-sql.d.ts +23 -0
  85. package/dist/db/aggregate-sql.js +165 -0
  86. package/dist/db/closed-connection.d.ts +9 -0
  87. package/dist/db/closed-connection.js +88 -0
  88. package/dist/db/connection.d.ts +4 -5
  89. package/dist/db/connection.js +29 -20
  90. package/dist/db/dialect.js +1 -1
  91. package/dist/db/distinct-on.d.ts +1 -1
  92. package/dist/db/driver-row-coercion.d.ts +2 -0
  93. package/dist/db/driver-row-coercion.js +186 -0
  94. package/dist/db/driver-value-preparation.d.ts +16 -0
  95. package/dist/db/driver-value-preparation.js +101 -0
  96. package/dist/db/entity-field-encryption.d.ts +1 -0
  97. package/dist/db/entity-field-encryption.js +1 -1
  98. package/dist/db/entity-table-meta.js +103 -110
  99. package/dist/db/event-store-executor-context.d.ts +2 -1
  100. package/dist/db/event-store-executor-read-aggregate-currencies.d.ts +17 -0
  101. package/dist/db/event-store-executor-read-aggregate-currencies.js +40 -0
  102. package/dist/db/event-store-executor-read-aggregate.d.ts +8 -0
  103. package/dist/db/event-store-executor-read-aggregate.js +143 -0
  104. package/dist/db/event-store-executor-read-filter.d.ts +31 -0
  105. package/dist/db/event-store-executor-read-filter.js +206 -0
  106. package/dist/db/event-store-executor-read-paging.d.ts +14 -0
  107. package/dist/db/event-store-executor-read-paging.js +99 -0
  108. package/dist/db/event-store-executor-read-rows.d.ts +6 -0
  109. package/dist/db/event-store-executor-read-rows.js +32 -0
  110. package/dist/db/event-store-executor-read-search.d.ts +28 -0
  111. package/dist/db/event-store-executor-read-search.js +221 -0
  112. package/dist/db/event-store-executor-read-sort.d.ts +41 -0
  113. package/dist/db/event-store-executor-read-sort.js +130 -0
  114. package/dist/db/event-store-executor-read-where.d.ts +24 -0
  115. package/dist/db/event-store-executor-read-where.js +81 -0
  116. package/dist/db/event-store-executor-read.d.ts +2 -9
  117. package/dist/db/event-store-executor-read.js +48 -701
  118. package/dist/db/event-store-executor-write-atomic.d.ts +4 -0
  119. package/dist/db/event-store-executor-write-atomic.js +41 -0
  120. package/dist/db/event-store-executor-write-steps.d.ts +17 -0
  121. package/dist/db/event-store-executor-write-steps.js +95 -0
  122. package/dist/db/event-store-executor-write.js +405 -509
  123. package/dist/db/event-store-executor.js +2 -1
  124. package/dist/db/executor-managed-tables.js +1 -1
  125. package/dist/db/index.d.ts +7 -3
  126. package/dist/db/index.js +6 -2
  127. package/dist/db/list-aggregate-labels.d.ts +14 -0
  128. package/dist/db/list-aggregate-labels.js +26 -0
  129. package/dist/db/migrate-generator.js +71 -86
  130. package/dist/db/migrate-runner.js +7 -4
  131. package/dist/db/pg-error.js +26 -21
  132. package/dist/db/queries/backfill-pii.js +3 -6
  133. package/dist/db/queries/database-now.js +2 -1
  134. package/dist/db/queries/shadow-swap.js +2 -3
  135. package/dist/db/query.d.ts +16 -15
  136. package/dist/db/query.js +76 -804
  137. package/dist/db/reference-data.js +19 -2
  138. package/dist/db/statement-timeout.js +2 -1
  139. package/dist/db/table-builder.js +113 -166
  140. package/dist/db/table-info.d.ts +10 -0
  141. package/dist/db/table-info.js +45 -0
  142. package/dist/db/temporal-value-guards.d.ts +6 -0
  143. package/dist/db/temporal-value-guards.js +15 -0
  144. package/dist/db/tenant-db-runner.d.ts +1 -0
  145. package/dist/db/tenant-db-runner.js +3 -0
  146. package/dist/db/tenant-db-upsert.d.ts +5 -0
  147. package/dist/db/tenant-db-upsert.js +91 -0
  148. package/dist/db/tenant-db.js +50 -10
  149. package/dist/db/where-clause.d.ts +6 -0
  150. package/dist/db/where-clause.js +236 -0
  151. package/dist/derivatives/delete-stored-file.js +2 -1
  152. package/dist/engine/boot-validator/boot-check.js +1 -1
  153. package/dist/engine/boot-validator/bundled-lists-table.d.ts +2 -0
  154. package/dist/engine/boot-validator/bundled-lists-table.js +36 -0
  155. package/dist/engine/boot-validator/detail-screens.js +2 -2
  156. package/dist/engine/boot-validator/entity-handler.d.ts +1 -0
  157. package/dist/engine/boot-validator/entity-handler.js +17 -0
  158. package/dist/engine/boot-validator/entity-list-aggregate-options.d.ts +3 -0
  159. package/dist/engine/boot-validator/entity-list-aggregate-options.js +23 -0
  160. package/dist/engine/boot-validator/form-derivations.js +35 -1
  161. package/dist/engine/boot-validator/i18n-keys.js +5 -3
  162. package/dist/engine/boot-validator/index.js +2 -0
  163. package/dist/engine/boot-validator/list-bulk-actions.d.ts +3 -0
  164. package/dist/engine/boot-validator/list-bulk-actions.js +49 -0
  165. package/dist/engine/boot-validator/list-column-layout.d.ts +8 -0
  166. package/dist/engine/boot-validator/list-column-layout.js +41 -0
  167. package/dist/engine/boot-validator/list-table-aggregate-options.d.ts +24 -0
  168. package/dist/engine/boot-validator/list-table-aggregate-options.js +145 -0
  169. package/dist/engine/boot-validator/list-table-aggregate-query.d.ts +10 -0
  170. package/dist/engine/boot-validator/list-table-aggregate-query.js +31 -0
  171. package/dist/engine/boot-validator/list-table-export-options.d.ts +1 -0
  172. package/dist/engine/boot-validator/list-table-export-options.js +27 -0
  173. package/dist/engine/boot-validator/list-table-options.d.ts +3 -0
  174. package/dist/engine/boot-validator/list-table-options.js +77 -0
  175. package/dist/engine/boot-validator/list-table-reject-unknown-keys.d.ts +1 -0
  176. package/dist/engine/boot-validator/list-table-reject-unknown-keys.js +7 -0
  177. package/dist/engine/boot-validator/pii-retention.js +233 -155
  178. package/dist/engine/boot-validator/projection-list-screens.d.ts +1 -1
  179. package/dist/engine/boot-validator/projection-list-screens.js +3 -13
  180. package/dist/engine/boot-validator/related-list-table-rules.d.ts +4 -0
  181. package/dist/engine/boot-validator/related-list-table-rules.js +42 -0
  182. package/dist/engine/boot-validator/screens-actions.d.ts +1 -0
  183. package/dist/engine/boot-validator/screens-actions.js +8 -1
  184. package/dist/engine/boot-validator/screens-dashboard.js +2 -5
  185. package/dist/engine/boot-validator/screens-forms.js +2 -6
  186. package/dist/engine/boot-validator/screens-kind-config-edit.d.ts +3 -0
  187. package/dist/engine/boot-validator/screens-kind-config-edit.js +88 -0
  188. package/dist/engine/boot-validator/screens-kind-entity-edit.d.ts +3 -0
  189. package/dist/engine/boot-validator/screens-kind-entity-edit.js +55 -0
  190. package/dist/engine/boot-validator/screens-kind-entity-list.d.ts +3 -0
  191. package/dist/engine/boot-validator/screens-kind-entity-list.js +235 -0
  192. package/dist/engine/boot-validator/screens-kind-projection-detail.d.ts +3 -0
  193. package/dist/engine/boot-validator/screens-kind-projection-detail.js +235 -0
  194. package/dist/engine/boot-validator/screens-kind-projection-list.d.ts +3 -0
  195. package/dist/engine/boot-validator/screens-kind-projection-list.js +56 -0
  196. package/dist/engine/boot-validator/screens-kind-secret-mint.d.ts +3 -0
  197. package/dist/engine/boot-validator/screens-kind-secret-mint.js +28 -0
  198. package/dist/engine/boot-validator/screens-kind-shared.d.ts +37 -0
  199. package/dist/engine/boot-validator/screens-kind-shared.js +142 -0
  200. package/dist/engine/boot-validator/screens-lists.d.ts +2 -1
  201. package/dist/engine/boot-validator/screens-lists.js +24 -11
  202. package/dist/engine/boot-validator/screens.d.ts +0 -2
  203. package/dist/engine/boot-validator/screens.js +99 -860
  204. package/dist/engine/build-app-schema.d.ts +2 -1
  205. package/dist/engine/build-app-schema.js +65 -97
  206. package/dist/engine/build-config-feature-schema.js +6 -1
  207. package/dist/engine/define-feature.js +13 -2
  208. package/dist/engine/define-handler.js +1 -0
  209. package/dist/engine/entity-handlers.d.ts +13 -0
  210. package/dist/engine/entity-handlers.js +10 -21
  211. package/dist/engine/entity-list-runtime-options.d.ts +8 -0
  212. package/dist/engine/entity-list-runtime-options.js +18 -0
  213. package/dist/engine/feature-ast/extractors/handlers.js +1 -0
  214. package/dist/engine/feature-ast/extractors/index.d.ts +1 -1
  215. package/dist/engine/feature-ast/extractors/index.js +1 -1
  216. package/dist/engine/feature-ast/extractors/round1.d.ts +2 -1
  217. package/dist/engine/feature-ast/extractors/round1.js +6 -0
  218. package/dist/engine/feature-ast/extractors/round2.js +25 -6
  219. package/dist/engine/feature-ast/index.d.ts +1 -1
  220. package/dist/engine/feature-ast/parse.js +3 -1
  221. package/dist/engine/feature-ast/patch.d.ts +2 -0
  222. package/dist/engine/feature-ast/patch.js +5 -182
  223. package/dist/engine/feature-ast/pattern-change-schema.d.ts +10 -245
  224. package/dist/engine/feature-ast/pattern-change-schema.js +10 -163
  225. package/dist/engine/feature-ast/pattern-id-matchers.d.ts +7 -0
  226. package/dist/engine/feature-ast/pattern-id-matchers.js +211 -0
  227. package/dist/engine/feature-ast/pattern-id-schema.d.ts +251 -0
  228. package/dist/engine/feature-ast/pattern-id-schema.js +166 -0
  229. package/dist/engine/feature-ast/patterns.d.ts +14 -1
  230. package/dist/engine/feature-ast/patterns.js +44 -51
  231. package/dist/engine/feature-ast/render.js +52 -87
  232. package/dist/engine/feature-builder-state.d.ts +1 -0
  233. package/dist/engine/feature-builder-state.js +1 -0
  234. package/dist/engine/feature-entity-handlers.js +3 -0
  235. package/dist/engine/feature-manifest.d.ts +1 -0
  236. package/dist/engine/feature-manifest.js +1 -0
  237. package/dist/engine/field-access.d.ts +1 -0
  238. package/dist/engine/field-access.js +12 -0
  239. package/dist/engine/form-derivations.js +18 -7
  240. package/dist/engine/handler-field-references.js +1 -1
  241. package/dist/engine/index.d.ts +2 -2
  242. package/dist/engine/index.js +1 -1
  243. package/dist/engine/pattern-library/library.js +2 -1
  244. package/dist/engine/pattern-library/static-schemas.d.ts +1 -0
  245. package/dist/engine/pattern-library/static-schemas.js +9 -0
  246. package/dist/engine/project-app-schema-for-roles.d.ts +2 -0
  247. package/dist/engine/project-app-schema-for-roles.js +6 -4
  248. package/dist/engine/registry-ingest.js +1 -1
  249. package/dist/engine/schema-builder.js +228 -212
  250. package/dist/engine/screen-filter-ops.js +2 -0
  251. package/dist/engine/screen-helpers.js +1 -1
  252. package/dist/engine/screen-kind.d.ts +7 -0
  253. package/dist/engine/screen-kind.js +1 -0
  254. package/dist/engine/strip-disabled-features-from-app-schema.js +58 -17
  255. package/dist/engine/types/feature.d.ts +1 -0
  256. package/dist/engine/types/index.d.ts +4 -3
  257. package/dist/engine/types/screen.d.ts +1 -1
  258. package/dist/engine/types/screen.js +1 -1
  259. package/dist/engine/validate-projection-allowlist.js +2 -1
  260. package/dist/entrypoint/index.d.ts +6 -1
  261. package/dist/entrypoint/index.js +10 -1
  262. package/dist/errors/docs-url.d.ts +1 -1
  263. package/dist/errors/docs-url.js +22 -2
  264. package/dist/es-ops/context.js +1 -1
  265. package/dist/event-store/admin-api.js +1 -1
  266. package/dist/event-store/event-store.d.ts +1 -0
  267. package/dist/event-store/event-store.js +17 -8
  268. package/dist/event-store/provenance-append.js +1 -1
  269. package/dist/files/bind-pending-file-refs.js +3 -3
  270. package/dist/files/create-file-ref-from-bytes.js +7 -1
  271. package/dist/files/create-file-ref.d.ts +3 -0
  272. package/dist/files/create-file-ref.js +11 -2
  273. package/dist/files/file-handle.js +2 -3
  274. package/dist/files/file-routes.d.ts +2 -0
  275. package/dist/files/file-routes.js +40 -10
  276. package/dist/files/provider-resolver.d.ts +1 -0
  277. package/dist/files/provider-resolver.js +1 -1
  278. package/dist/files/record-write-check.d.ts +6 -0
  279. package/dist/files/record-write-check.js +13 -0
  280. package/dist/files/resolve-content-type.js +43 -0
  281. package/dist/files/upload-ledger.d.ts +2 -2
  282. package/dist/files/upload-ledger.js +11 -4
  283. package/dist/i18n/required-surface-keys.js +189 -208
  284. package/dist/internal/stack-support.d.ts +2 -1
  285. package/dist/internal/stack-support.js +1 -1
  286. package/dist/internal/testing.js +1 -1
  287. package/dist/jobs/job-runner-context.d.ts +32 -0
  288. package/dist/jobs/job-runner-context.js +305 -0
  289. package/dist/jobs/job-runner-execution.d.ts +7 -0
  290. package/dist/jobs/job-runner-execution.js +160 -0
  291. package/dist/jobs/job-runner-gates.d.ts +19 -0
  292. package/dist/jobs/job-runner-gates.js +198 -0
  293. package/dist/jobs/job-runner-helpers.d.ts +17 -3
  294. package/dist/jobs/job-runner-helpers.js +61 -2
  295. package/dist/jobs/job-runner-scope.d.ts +44 -0
  296. package/dist/jobs/job-runner-scope.js +102 -0
  297. package/dist/jobs/job-runner-types.d.ts +12 -0
  298. package/dist/jobs/job-runner.d.ts +0 -1
  299. package/dist/jobs/job-runner.js +50 -657
  300. package/dist/observability/escape-hatch-report.d.ts +3 -0
  301. package/dist/observability/escape-hatch-report.js +21 -3
  302. package/dist/pipeline/after-rollback-sink.d.ts +6 -0
  303. package/dist/pipeline/after-rollback-sink.js +32 -0
  304. package/dist/pipeline/cascade-handler.js +165 -138
  305. package/dist/pipeline/dispatch-batch.js +8 -1
  306. package/dist/pipeline/dispatch-query.js +10 -3
  307. package/dist/pipeline/dispatch-shared.d.ts +13 -3
  308. package/dist/pipeline/dispatch-shared.js +62 -710
  309. package/dist/pipeline/dispatch-write.js +296 -189
  310. package/dist/pipeline/event-dispatcher-admin.js +2 -1
  311. package/dist/pipeline/event-dispatcher-delivery.js +6 -6
  312. package/dist/pipeline/event-dispatcher.d.ts +1 -0
  313. package/dist/pipeline/event-dispatcher.js +6 -9
  314. package/dist/pipeline/handler-context-auth.d.ts +9 -0
  315. package/dist/pipeline/handler-context-auth.js +54 -0
  316. package/dist/pipeline/handler-context-config.d.ts +14 -0
  317. package/dist/pipeline/handler-context-config.js +113 -0
  318. package/dist/pipeline/handler-context-db.d.ts +24 -0
  319. package/dist/pipeline/handler-context-db.js +149 -0
  320. package/dist/pipeline/handler-context-dispatch.d.ts +23 -0
  321. package/dist/pipeline/handler-context-dispatch.js +101 -0
  322. package/dist/pipeline/handler-context-events.d.ts +41 -0
  323. package/dist/pipeline/handler-context-events.js +239 -0
  324. package/dist/pipeline/handler-context-notify.d.ts +12 -0
  325. package/dist/pipeline/handler-context-notify.js +55 -0
  326. package/dist/pipeline/handler-context-observability.d.ts +7 -0
  327. package/dist/pipeline/handler-context-observability.js +21 -0
  328. package/dist/pipeline/handler-context-scope.d.ts +48 -0
  329. package/dist/pipeline/handler-context-scope.js +88 -0
  330. package/dist/pipeline/notify-scope.js +12 -1
  331. package/dist/pipeline/pre-handler-gates.js +20 -4
  332. package/dist/pipeline/pre-transaction-reservations.d.ts +1 -0
  333. package/dist/pipeline/pre-transaction-reservations.js +9 -3
  334. package/dist/pipeline/projection-rebuild.js +2 -1
  335. package/dist/pipeline/system-hooks.d.ts +3 -1
  336. package/dist/pipeline/system-hooks.js +55 -6
  337. package/dist/pipeline/write-result-masking.js +13 -10
  338. package/dist/schema-cli/apply-command.d.ts +2 -0
  339. package/dist/schema-cli/apply-command.js +97 -0
  340. package/dist/schema-cli/baseline-command.d.ts +2 -0
  341. package/dist/schema-cli/baseline-command.js +33 -0
  342. package/dist/schema-cli/generate-command.d.ts +2 -0
  343. package/dist/schema-cli/generate-command.js +90 -0
  344. package/dist/schema-cli/shared.d.ts +39 -0
  345. package/dist/schema-cli/shared.js +95 -0
  346. package/dist/schema-cli/status-command.d.ts +2 -0
  347. package/dist/schema-cli/status-command.js +73 -0
  348. package/dist/schema-cli/validate-boot-input.d.ts +5 -0
  349. package/dist/schema-cli/validate-boot-input.js +130 -0
  350. package/dist/schema-cli/validate-command.d.ts +2 -0
  351. package/dist/schema-cli/validate-command.js +130 -0
  352. package/dist/schema-cli.d.ts +2 -18
  353. package/dist/schema-cli.js +47 -604
  354. package/dist/search/meilisearch-adapter.js +2 -1
  355. package/dist/search/reindex-entity.js +15 -5
  356. package/dist/ui-types/index.d.ts +2 -2
  357. package/dist/ui-types/index.js +1 -1
  358. package/dist/upgrade-changelog.d.ts +2 -0
  359. package/dist/upgrade-changelog.js +14 -0
  360. package/dist/upgrade-cli.d.ts +3 -12
  361. package/dist/upgrade-cli.js +171 -197
  362. package/dist/upgrade-marker-parse.d.ts +32 -0
  363. package/dist/upgrade-marker-parse.js +73 -0
  364. package/package.json +9 -6
  365. package/src/changes.json +555 -0
  366. package/src/scripts/codemod/codemod-support.ts +1 -1
  367. package/src/scripts/codemod/db-factory.ts +1 -1
  368. package/src/scripts/codemod/feature-layout.ts +10 -2
  369. package/src/scripts/codemod/object-form.ts +41 -4
  370. package/src/scripts/codemod/package-merge.ts +58 -8
  371. package/src/scripts/codemod/pii-personal-migration.ts +175 -145
  372. package/src/scripts/codemod/testing-injection.ts +122 -42
  373. package/src/scripts/codemod/testing-move.ts +29 -7
  374. package/dist/engine/provider-plugin-context.d.ts +0 -3
  375. package/dist/engine/provider-plugin-context.js +0 -28
@@ -97,3 +97,215 @@ Wenn eine kaputte Migration den Boot blockiert: setze `skippable: true` im seed-
97
97
  ## See also
98
98
 
99
99
  - **Driver-Use-Case:** `seeds/2026-02-01-fix-admin-roles.ts` in this recipe
100
+
101
+ ## Source files
102
+
103
+ ### scripts/smoke.ts
104
+
105
+ ```ts
106
+ // biome-ignore-all lint/suspicious/noConsole: CLI tool output
107
+ //
108
+ // Lokaler Smoke-Test für seed-migrations.
109
+ //
110
+ // Was er prüft (offline, ohne Pod-Deploy):
111
+ // 1. Alle seed-files in ./seeds/ können dynamic-import geladen werden
112
+ // → catched syntax-errors + missing default-exports + falsche paths
113
+ // 2. Jeder handler-QN den die seeds referenzieren ist in der echten
114
+ // App-Registry registriert → catched camelCase-typos + drift
115
+ // (Bug-Klasse 3 aus Phase 1 retro)
116
+ // 3. Jeder system-user (mit oder ohne tenantIdOverride) hat Access auf
117
+ // die referenzierten Handler → catched access-rule-Drift
118
+ // (Bug-Klasse 4 aus Phase 1 retro)
119
+ //
120
+ // Schreibt NICHTS in die DB. Reine Read-only Validation.
121
+ //
122
+ // Usage:
123
+ // bun scripts/smoke.ts (gegen ./seeds/)
124
+ // bun scripts/smoke.ts --seeds-dir foo (custom path)
125
+ //
126
+ // In CI: vor `build`-Step laufen lassen — fängt 80% der Phase-1-Bugs
127
+ // lokal in <5 Sekunden statt nach 8-Minuten-Docker-Build im Pod-Boot.
128
+
129
+ import { existsSync, readdirSync, readFileSync } from "node:fs";
130
+ import { resolve } from "node:path";
131
+ // App-spezifisch: nimm die EFFEKTIVEN Features die deine App zur Runtime
132
+ // nutzt. Im typischen Setup mit `runProdApp({ features, auth })`:
133
+ //
134
+ // import { composeFeatures } from "@cosmicdrift/kumiko-dev-server";
135
+ // import { APP_FEATURES } from "../src/run-config";
136
+ // const composed = composeFeatures(APP_FEATURES, { includeBundled: true, ... });
137
+ // const features = composed.features;
138
+ //
139
+ // Bei reiner App-Feature-Setup (kein auth-mode) reicht ein direkter
140
+ // Import der App-Features. Hier im Recipe der minimale set für die
141
+ // referenzierten Recipe-Seeds (tenant + config) — App-Author tauscht
142
+ // gegen sein eigenes Feature-Set.
143
+ import { createConfigFeature } from "@cosmicdrift/kumiko-bundled-features/config";
144
+ import { createTenantFeature } from "@cosmicdrift/kumiko-bundled-features/tenant";
145
+ import {
146
+ createRegistry,
147
+ createSystemUser,
148
+ SYSTEM_TENANT_ID,
149
+ } from "@cosmicdrift/kumiko-framework/engine";
150
+
151
+ const features = [createConfigFeature(), createTenantFeature()];
152
+
153
+ const seedsDir = (() => {
154
+ const idx = process.argv.indexOf("--seeds-dir");
155
+ return idx >= 0 ? resolve(process.argv[idx + 1] ?? "./seeds") : resolve("./seeds");
156
+ })();
157
+
158
+ if (!existsSync(seedsDir)) {
159
+ console.log(`✓ no seeds-dir at ${seedsDir} — nothing to smoke-test`);
160
+ process.exit(0);
161
+ }
162
+
163
+ const seedFiles = readdirSync(seedsDir)
164
+ .filter((n) => n.endsWith(".ts") && !n.startsWith("_") && !n.startsWith("."))
165
+ .sort();
166
+
167
+ if (seedFiles.length === 0) {
168
+ console.log(`✓ ${seedsDir} is empty — nothing to smoke-test`);
169
+ process.exit(0);
170
+ }
171
+
172
+ const registry = createRegistry(features);
173
+
174
+ let failed = 0;
175
+
176
+ for (const file of seedFiles) {
177
+ const filePath = resolve(seedsDir, file);
178
+ console.log(`\nseed: ${file}`);
179
+
180
+ // 1. Module-load
181
+ try {
182
+ const mod = await import(filePath);
183
+ if (!mod.default || typeof mod.default.run !== "function") {
184
+ console.error(" ✗ missing valid SeedMigration default-export");
185
+ failed++;
186
+ continue;
187
+ }
188
+ console.log(` ✓ loads: "${mod.default.description}"`);
189
+ } catch (err) {
190
+ console.error(` ✗ load fail: ${err instanceof Error ? err.message : String(err)}`);
191
+ failed++;
192
+ continue;
193
+ }
194
+
195
+ // 2 + 3. QN-Resolution + Access (regex-based, gleiche Logik wie runner's
196
+ // dry-run-validator). Pattern matched inline-string-QNs:
197
+ const source = readFileSync(filePath, "utf-8");
198
+ const qnPattern = /systemWriteAs\s*\(\s*["']([^"']+)["']/g;
199
+ const qns = new Set<string>();
200
+ for (const m of source.matchAll(qnPattern)) {
201
+ const qn = m[1];
202
+ if (qn) qns.add(qn);
203
+ }
204
+
205
+ for (const qn of qns) {
206
+ const handler = registry.getWriteHandler(qn);
207
+ if (!handler) {
208
+ console.error(` ✗ handler "${qn}" not registered`);
209
+ failed++;
210
+ continue;
211
+ }
212
+ const accessRoles = (handler.access as { roles?: readonly string[] }).roles ?? [];
213
+ const systemUserRoles = createSystemUser(SYSTEM_TENANT_ID).roles;
214
+ const hasAccess = systemUserRoles.some((r) => accessRoles.includes(r));
215
+ if (!hasAccess) {
216
+ console.error(
217
+ ` ✗ system-user roles=${JSON.stringify([...systemUserRoles])} NOT in access.roles=${JSON.stringify([...accessRoles])} for "${qn}"`,
218
+ );
219
+ failed++;
220
+ continue;
221
+ }
222
+ console.log(` ✓ "${qn}" registered + accessible`);
223
+ }
224
+ }
225
+
226
+ if (failed > 0) {
227
+ console.error(`\n${failed} issue(s) — fix before push.`);
228
+ process.exit(1);
229
+ }
230
+ console.log(`\n✓ all ${seedFiles.length} seed-file(s) pass smoke.`);
231
+ ```
232
+
233
+ ### seeds/2026-01-01-initial-tenants.ts
234
+
235
+ ```ts
236
+ // Initial-Seed: Demo-Tenants anlegen.
237
+ //
238
+ // Note: in real apps wäre "initial tenants" wahrscheinlich nicht als
239
+ // seed-migration sondern als `r.config({seeds})` oder `auth.admin`-
240
+ // Config umgesetzt — die laufen jedes-Boot idempotent. Hier ist es als
241
+ // seed-migration gezeigt um das Pattern zu demonstrieren.
242
+ //
243
+ // Pattern: jede seed-migration arbeitet write-only via `systemWriteAs`
244
+ // damit alles als Event-Stream persistiert wird. Read-only Lookups
245
+ // (find*) am Context oder direkt via ctx.db.
246
+
247
+ import type { SeedMigration } from "@cosmicdrift/kumiko-framework/es-ops";
248
+
249
+ export default {
250
+ description: "initial demo tenants (alice-corp, beta-inc)",
251
+ run: async (ctx) => {
252
+ // Idempotent-Check: wenn Tenants schon existieren (z.B. via auth.admin-
253
+ // seed), skip diese Migration. Verhindert Konflikt beim re-boot wenn
254
+ // jemand den Marker manuell gelöscht hat.
255
+ const existing = await ctx.findTenants();
256
+ if (existing.some((t) => t.tenantKey === "alice-corp")) return;
257
+
258
+ await ctx.systemWriteAs("tenant:write:create", {
259
+ name: "Alice Corp",
260
+ tenantKey: "alice-corp",
261
+ });
262
+ await ctx.systemWriteAs("tenant:write:create", {
263
+ name: "Beta Inc",
264
+ tenantKey: "beta-inc",
265
+ });
266
+ },
267
+ } satisfies SeedMigration;
268
+ ```
269
+
270
+ ### seeds/2026-02-01-fix-admin-roles.ts
271
+
272
+ ```ts
273
+ // Driver-Pattern: ergänze fehlende Rolle auf existierenden Memberships.
274
+ // Spiegelt den realen publicstatus-Bug 2026-05-20 (admin@publicstatus.eu
275
+ // hatte "Admin" aber nicht "TenantAdmin" → text-content + legal-pages
276
+ // access_denied weil bundled-features TenantAdmin erwarten).
277
+ //
278
+ // Funktioniert für jede App mit dem gleichen Pattern: User-Lookup per
279
+ // E-Mail → alle Memberships durchgehen → bei Bedarf via existierendem
280
+ // updateMemberRoles-Handler korrigieren.
281
+
282
+ import type { SeedMigration } from "@cosmicdrift/kumiko-framework/es-ops";
283
+
284
+ export default {
285
+ description: "ergänze TenantAdmin-Rolle für admin@example.com auf allen Memberships",
286
+ run: async (ctx) => {
287
+ const admin = await ctx.findUserByEmail("admin@example.com");
288
+ if (!admin) return; // idempotent: admin nicht (mehr) vorhanden
289
+
290
+ for (const m of await ctx.findMembershipsOfUser(admin.id)) {
291
+ if (m.roles.includes("TenantAdmin")) continue; // bereits korrigiert
292
+
293
+ await ctx.systemWriteAs(
294
+ "tenant:write:update-member-roles", // kebab-case QN — wird vom Dry-Run-Validator gecheckt
295
+ {
296
+ userId: admin.id,
297
+ tenantId: m.tenantId,
298
+ roles: Array.from(new Set([...m.roles, "TenantAdmin"])),
299
+ },
300
+ // tenantIdOverride: stream-tenant aus kumiko_events.v1 — NICHT
301
+ // m.tenantId (payload-tenant). Beide stimmen oft überein, weichen
302
+ // aber ab wenn das Aggregate ursprünglich von einem fremden
303
+ // Executor angelegt wurde (seedTenantMembership by=systemAdmin —
304
+ // publicstatus-Pattern). findMembershipsOfUser liefert beide,
305
+ // kein eigener JOIN nötig.
306
+ m.streamTenantId,
307
+ );
308
+ }
309
+ },
310
+ } satisfies SeedMigration;
311
+ ```
@@ -492,6 +492,7 @@ export const invoiceTable = buildEntityTable("invoice", invoiceEntity);
492
492
 
493
493
  import type { EventDef } from "@cosmicdrift/kumiko-framework/engine";
494
494
  import { z } from "zod";
495
+ import { INVOICE_STATES } from "./entities/invoice.ts";
495
496
 
496
497
  export const FEATURE_NAME = "billing";
497
498
  export const ENTITY_NAME = "invoice";
@@ -523,8 +524,8 @@ export const INVOICE_CREATED_EVENT = `${ENTITY_NAME}.created` as const;
523
524
 
524
525
  export const emptyEventPayload = z.object({});
525
526
  export const statusForcedPayload = z.object({
526
- newStatus: z.enum(["draft", "sent", "paid", "cancelled"]),
527
- fromStatus: z.enum(["draft", "sent", "paid", "cancelled"]),
527
+ newStatus: z.enum(INVOICE_STATES),
528
+ fromStatus: z.enum(INVOICE_STATES),
528
529
  });
529
530
 
530
531
  // The EventDefs r.defineEvent returns inside the feature setup. Handlers receive them so that
@@ -13,6 +13,7 @@ Multi-tenant data isolation by default.
13
13
  ## What it shows
14
14
 
15
15
  - Tenant filter on ordinary handlers
16
+ - `ctx.db.upsert`: insert-or-update on a tenant-scoped, non-event-sourced table. `conflictTarget` must contain `tenantId` and match a declared unique index (here `tenant_id, key`); event-fed tables are rejected
16
17
  - What breaks if you forget tenancy (and how the framework prevents it)
17
18
 
18
19
  ## Source
@@ -37,6 +38,7 @@ bun test
37
38
  // Proves: tenant_id scopes all data, cross-tenant access returns nothing
38
39
 
39
40
  import { afterAll, beforeAll, beforeEach, describe, expect, test } from "bun:test";
41
+ import { selectMany } from "@cosmicdrift/kumiko-framework/db";
40
42
  import type { SaveContext } from "@cosmicdrift/kumiko-framework/engine";
41
43
  import { createEventsTable } from "@cosmicdrift/kumiko-framework/event-store";
42
44
  import { createTestUser, TestUsers } from "@cosmicdrift/kumiko-framework/seeding";
@@ -45,7 +47,7 @@ import {
45
47
  type TestStack,
46
48
  unsafeCreateEntityTable,
47
49
  } from "@cosmicdrift/kumiko-testing/stack";
48
- import { noteEntity, noteFeature } from "../feature";
50
+ import { noteEntity, noteFeature, preferenceTable } from "../feature";
49
51
 
50
52
  let stack: TestStack;
51
53
 
@@ -136,12 +138,48 @@ describe("tenant isolation", () => {
136
138
  expect(listB.rows.some((r) => r["title"] === "A-Note")).toBe(false);
137
139
  });
138
140
  });
141
+
142
+ describe("ctx.db.upsert", () => {
143
+ const setPreference = (user: typeof tenantBAdmin, key: string, value: string) =>
144
+ stack.http.writeOk<{ value: string }>("notes:write:preference:set", { key, value }, user);
145
+
146
+ test("a second upsert with the same key updates the tenant's row instead of inserting", async () => {
147
+ await setPreference(tenantAAdmin, "theme", "light");
148
+ const second = await setPreference(tenantAAdmin, "theme", "dark");
149
+
150
+ expect(second.value).toBe("dark");
151
+ const rows = await selectMany(stack.db, preferenceTable, {
152
+ tenantId: tenantAAdmin.tenantId,
153
+ key: "theme",
154
+ });
155
+ expect(rows).toHaveLength(1);
156
+ expect(rows[0]?.["value"]).toBe("dark");
157
+ });
158
+
159
+ test("the same key in another tenant creates a separate row and leaves A's value alone", async () => {
160
+ await setPreference(tenantAAdmin, "language", "de");
161
+ await setPreference(tenantBAdmin, "language", "en");
162
+
163
+ const rowsA = await selectMany(stack.db, preferenceTable, {
164
+ tenantId: tenantAAdmin.tenantId,
165
+ key: "language",
166
+ });
167
+ const rowsB = await selectMany(stack.db, preferenceTable, {
168
+ tenantId: tenantBAdmin.tenantId,
169
+ key: "language",
170
+ });
171
+ expect(rowsA.map((row) => row["value"])).toEqual(["de"]);
172
+ expect(rowsB.map((row) => row["value"])).toEqual(["en"]);
173
+ });
174
+ });
139
175
  ```
140
176
 
141
177
  ### src/feature.ts
142
178
 
143
179
  ```ts
180
+ import { defineUnmanagedTable } from "@cosmicdrift/kumiko-framework/db";
144
181
  import { createEntity, createTextField, defineFeature } from "@cosmicdrift/kumiko-framework/engine";
182
+ import * as z from "zod";
145
183
 
146
184
  export const noteEntity = createEntity({
147
185
  table: "read_sample_notes",
@@ -151,6 +189,26 @@ export const noteEntity = createEntity({
151
189
  },
152
190
  });
153
191
 
192
+ // Not event-sourced: ctx.db.upsert rejects executor-managed tables.
193
+ export const preferenceTable = defineUnmanagedTable({
194
+ tableName: "sample_tenant_preferences",
195
+ columns: [
196
+ {
197
+ name: "id",
198
+ pgType: "uuid",
199
+ notNull: true,
200
+ primaryKey: true,
201
+ defaultSql: "gen_random_uuid()",
202
+ },
203
+ { name: "tenant_id", pgType: "uuid", notNull: true },
204
+ { name: "key", pgType: "text", notNull: true },
205
+ { name: "value", pgType: "text", notNull: true },
206
+ ],
207
+ indexes: [
208
+ { name: "sample_tenant_preferences_tenant_key", columns: ["tenant_id", "key"], unique: true },
209
+ ],
210
+ });
211
+
154
212
  const adminWrite = { access: { roles: ["Admin"] } } as const;
155
213
  const openRead = {
156
214
  access: {
@@ -168,5 +226,19 @@ export const noteFeature = defineFeature("notes", (r) => {
168
226
  read: openRead,
169
227
  verbs: { update: false, delete: false, restore: false },
170
228
  });
229
+
230
+ r.storeTable(preferenceTable, { reason: "settings.tenant_preferences" });
231
+
232
+ r.writeHandler({
233
+ name: "preference:set",
234
+ schema: z.object({ key: z.string().min(1), value: z.string() }),
235
+ handler: async (event, ctx) => {
236
+ const row = await ctx.db.upsert<{ value: string }>(preferenceTable, event.payload, {
237
+ conflictTarget: ["tenantId", "key"],
238
+ });
239
+ return { isSuccess: true, data: { value: row?.value } };
240
+ },
241
+ ...adminWrite,
242
+ });
171
243
  });
172
244
  ```