@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
@@ -24,7 +24,7 @@ function resolvePersonalFlags(personal, reason) {
24
24
  userOwned: { ownerField: personal.of, ...(whenAbsent !== undefined && { whenAbsent }) },
25
25
  };
26
26
  }
27
- // Resolves the author-facing `personal`/`find` annotations (kumiko-framework#2250)
27
+ // Resolves the author-facing `personal`/`find` annotations
28
28
  // into the internal ResolvedPiiFlags every factory below merges into its
29
29
  // return value. `personal`, `find`, `reason` never survive into the field def.
30
30
  function expandPersonalAnnotations(overrides) {
@@ -73,7 +73,7 @@ function missingTextFieldStanceError(factoryName) {
73
73
  function isNonEmptyString(value) {
74
74
  return typeof value === "string" && value.trim().length > 0;
75
75
  }
76
- // Fail-closed stance gate (kumiko-framework#2921) for the two text-shaped
76
+ // Fail-closed stance gate for the two text-shaped
77
77
  // factories — runs before expandPersonalAnnotations so an untyped JS caller
78
78
  // (no compiler to stop it) can't slip an unannotated text field past the
79
79
  // type layer either. The typed signature above already rejects a
@@ -109,13 +109,12 @@ function assertTextFieldStance(factoryName, overrides) {
109
109
  throw missingTextFieldStanceError(factoryName);
110
110
  }
111
111
  }
112
- // Generic über `R extends true | false` (statt `boolean`) damit
113
- // `createTextField({ required: true })` literal `required: true` im
114
- // Return-Type behält. `boolean` würde widenen — EntityTable<E>'s
115
- // Mapped-Type könnte dann nicht zwischen `required: true` und
116
- // `required: false` dispatchen, jede Column würde zu nullable
117
- // degradieren. Default `R = false` matcht den runtime-default. Pattern
118
- // in jeder required-bearing factory unten.
112
+ // Use generic `R extends true | false` instead of `boolean` so
113
+ // `createTextField({ required: true })` preserves the literal `required: true`
114
+ // in the return type. Widening to `boolean` would prevent EntityTable<E>'s
115
+ // Mapped-Type from distinguishing `required: true` from `required: false`,
116
+ // making every column nullable. Default `R = false` matches the runtime
117
+ // default. This pattern is used in every required-bearing factory below.
119
118
  export function createTextField(overrides) {
120
119
  assertTextFieldStance("createTextField", overrides);
121
120
  return {
@@ -129,13 +128,13 @@ export function createTextField(overrides) {
129
128
  }
130
129
  /**
131
130
  * Long-form text field for source-code, markdown, blog-posts, email-
132
- * templates — anything that can be megabytes large. Type-level differs
133
- * from `text`: keine sortable/searchable/filterable/format options.
134
- * DB-mapping ist identisch zu text (PG text ist unbounded).
131
+ * templates — anything that can be megabytes large. Its type-level API
132
+ * differs from `text`: it has no sortable/searchable/filterable/format options.
133
+ * The DB mapping is identical to text (`PG text` is unbounded).
135
134
  *
136
- * Soft-cap default: kein maxLength (PG text ist 1 GB hart begrenzt).
137
- * Setze einen explicit `maxLength` wenn du ein verirrtes Browser-Paste
138
- * früh ablehnen willst (z.B. 1_000_000 = 1 MB).
135
+ * Soft-cap default: no maxLength (`PG text` has a 1 GB hard limit).
136
+ * Set an explicit `maxLength` to reject an accidental browser paste early
137
+ * (for example, `1_000_000 = 1 MB`).
139
138
  */
140
139
  /**
141
140
  * Read-time computed field for `EntityDefinition.derivedFields` (NOT `fields`).
@@ -277,10 +276,10 @@ export function createEmbeddedListField(schema, overrides) {
277
276
  multiple: true,
278
277
  };
279
278
  }
280
- // Free-form jsonb-Spalte — siehe `JsonbFieldDef`-Doku. Schema-less, default
281
- // `{}`, NOT NULL. Hauptnutzer: custom-fields-Bundle (host-entity's
282
- // `customFields`-Spalte). Andere valid uses: tenant-config-blobs, AI-
283
- // inferred-metadata, future tags-arrays.
279
+ // Free-form jsonb column — see the `JsonbFieldDef` documentation. Schema-less,
280
+ // defaults to `{}`, and is NOT NULL. Primarily used by the custom-fields
281
+ // bundle for the host entity's `customFields` column; other valid uses include
282
+ // tenant configuration blobs, AI-inferred metadata, and future tag arrays.
284
283
  export function createJsonbField(overrides) {
285
284
  return {
286
285
  type: "jsonb",
@@ -295,17 +294,17 @@ export function createDateField(overrides) {
295
294
  }; // @cast-boundary engine-payload
296
295
  }
297
296
  /**
298
- * UTC-Instant — für Ereignisse die zu einem bestimmten Zeitpunkt passieren
299
- * (createdAt, loginAt, actualPickupAt). Temporal.Instant intern.
297
+ * UTC instant for events occurring at a specific point in time
298
+ * (createdAt, loginAt, actualPickupAt). Uses Temporal.Instant internally.
300
299
  *
301
- * Mit `locatedBy: "<name>Tz"` wird das Feld zum Wall-Clock-Pair eines
302
- * Termins an einem Ort — bevorzuge dafür `createLocatedTimestampField()`,
303
- * das EIN atomares Feld statt eines lose verdrahteten Pairs erzeugt.
300
+ * With `locatedBy: "<name>Tz"`, the field becomes a wall-clock pair for an
301
+ * appointment at a location — prefer `createLocatedTimestampField()` instead,
302
+ * which creates one atomic field rather than a loosely connected pair.
304
303
  */
305
304
  export function createTimestampField(overrides) {
306
- // Object-Build vermeidet hartcodiertes `required: false` im literal —
307
- // das würde TS dazu bringen, R auf `boolean` zu widenen statt das
308
- // literal `true`/`false` aus dem overrides-Argument zu inferieren.
305
+ // Building the object this way avoids hardcoding `required: false` in the
306
+ // literal, which would make TypeScript widen R to `boolean` instead of
307
+ // inferring the `true`/`false` literal from the overrides argument.
309
308
  return {
310
309
  ...expandPersonalAnnotations(overrides),
311
310
  type: "timestamp",
@@ -313,8 +312,9 @@ export function createTimestampField(overrides) {
313
312
  };
314
313
  }
315
314
  /**
316
- * IANA-Zonenname (z.B. "Europe/Berlin"). Wird im Boot/Schema-Validator
317
- * via `Intl.supportedValuesOf("timeZone")` geprüft (kommt im Zod-Schritt).
315
+ * IANA time-zone name (for example, "Europe/Berlin"). The boot/schema
316
+ * validator checks it using `Intl.supportedValuesOf("timeZone")` during the
317
+ * Zod step.
318
318
  */
319
319
  export function createTzField(overrides) {
320
320
  return {
@@ -372,14 +372,15 @@ export function createFilesField(overrides) {
372
372
  export function createImagesField(overrides) {
373
373
  return { type: "images", ...expandPersonalAnnotations(overrides) };
374
374
  }
375
- // `F` läuft OHNE Constraint im Generic-Param damit TS die literal-types
376
- // einzelner Field-Defs durchzieht (required: true bleibt true, nicht
377
- // boolean). Constraint-Match gegen FieldsMap würde widenen — siehe TS-
378
- // Issue um Constraint-Inferenz auf strukturellen Records. Stattdessen
379
- // validieren wir die Conformance via conditional return type: wenn F
380
- // nicht FieldsMap-compat ist, kollabiert der Return zu `never`.
381
- // `const F`: inline field literals (`{ type: "reference", ... }`) keep their
382
- // `type` literal without `as const`; otherwise it widens to string → `never`.
375
+ // Leave `F` unconstrained so TypeScript preserves the literal types of
376
+ // individual field definitions (`required: true` remains `true`, not
377
+ // `boolean`). Constraining it to FieldsMap would widen them — see the
378
+ // TypeScript issue concerning constraint inference for structural records.
379
+ // Instead, conformance is validated through the conditional return type: if F
380
+ // is not compatible with FieldsMap, the return type collapses to `never`.
381
+ // `const F` preserves the `type` literal in inline field literals
382
+ // (`{ type: "reference", ... }`) without `as const`; otherwise it widens to
383
+ // string and produces `never`.
383
384
  export function createEntity(def) {
384
385
  return {
385
386
  softDelete: false,
@@ -1,7 +1,7 @@
1
1
  // Shared field-type validation for EntityDefinition. Used by both the
2
2
  // static extractor (extractEntity, parse-time ParseError) and the runtime
3
3
  // PatternChange validator (pattern-change-schema.ts) so the two never drift
4
- // into reporting different "unknown field type" catalogues (#3137).
4
+ // into reporting different "unknown field type" catalogues.
5
5
  import { FIELD_TYPE_NAMES } from "@cosmicdrift/kumiko-types/fields";
6
6
  import { isPlainObject, isRawRefSentinel } from "./extractors/shared.js";
7
7
  /**
@@ -33,6 +33,7 @@ const WRITE_HANDLER_KEY_KINDS = {
33
33
  unsafeSkipTransitionGuard: "modeled",
34
34
  rateLimit: "modeled",
35
35
  additionalRateLimits: "modeled",
36
+ rateLimitCost: "opaque",
36
37
  escapeHatch: "modeled",
37
38
  tenantlessAnonymous: "opaque",
38
39
  reserveBeforeTransaction: "opaque",
@@ -256,7 +257,7 @@ export function parseHandlerCall(call, sourceFile, methodName) {
256
257
  // (`r.writeHandler(eventCreateHandler)`, `r.queryHandler(someQuery())`)
257
258
  // that resolveObjectLiteralArg above couldn't turn into an object literal
258
259
  // (imported binding, factory call, ...). Keep it recognised as this kind
259
- // instead of ParseErroring — see #1007. Opaque: renderWriteHandler/
260
+ // instead of ParseErroring. Opaque: renderWriteHandler/
260
261
  // renderQueryHandler re-emit `source.raw` verbatim when handlerName is
261
262
  // undefined.
262
263
  if (args.length === 1 && isRawRefSentinel(readDataLiteralNode(first))) {
@@ -230,7 +230,7 @@ export function extractHook(call, sourceFile) {
230
230
  ...escapeHatchOutcome,
231
231
  });
232
232
  }
233
- // guard:dup-ok — intentionale Parallele zu extractTree (round6); verschiedene Feature-AST-Extraktoren by design
233
+ // guard:dup-ok — intentional parallel to extractTree; different Feature-AST extractors by design
234
234
  export function extractAuthClaims(call, sourceFile) {
235
235
  const arg = call.getArguments()[0];
236
236
  if (!arg) {
@@ -2,19 +2,36 @@ import { SyntaxKind } from "ts-morph";
2
2
  import { describeUnknownFieldType, findUnknownEntityFieldTypes } from "../entity-field-types.js";
3
3
  import { sourceLocationFromNode } from "../source-location.js";
4
4
  import { fail, isPlainObject, isRawRefSentinel, ok, readDataLiteralNode, readNameLiteral, readNameOrRef, } from "./shared.js";
5
+ function readBackingTableRef(property) {
6
+ const initializer = property.asKind(SyntaxKind.PropertyAssignment)?.getInitializer() ??
7
+ property.asKind(SyntaxKind.ShorthandPropertyAssignment)?.getNameNode();
8
+ const reference = initializer ? readDataLiteralNode(initializer) : undefined;
9
+ return isRawRefSentinel(reference) ? reference : undefined;
10
+ }
5
11
  // `{ name: "x", ...xEntity }` — the definition is a reference the parser cannot
6
12
  // inline, so it is kept as a raw-ref sentinel and re-rendered as the same spread.
7
13
  // `backingTable` is runtime wiring (a table identifier), not part of the
8
- // definition data, so it does not take part in the shape check.
14
+ // definition data, so it is carried next to the definition and skipped by the shape check.
9
15
  function readSpreadOnlyDefinition(obj) {
10
- const properties = obj
11
- .getProperties()
12
- .filter((property) => property.asKind(SyntaxKind.PropertyAssignment)?.getName() !== "backingTable");
16
+ const isBackingTable = (property) => {
17
+ const name = property.asKind(SyntaxKind.PropertyAssignment)?.getName() ??
18
+ property.asKind(SyntaxKind.ShorthandPropertyAssignment)?.getName();
19
+ return name === "backingTable";
20
+ };
21
+ const allProperties = obj.getProperties();
22
+ const properties = allProperties.filter((property) => !isBackingTable(property));
13
23
  const spread = properties.length === 2 ? properties[1]?.asKind(SyntaxKind.SpreadAssignment) : undefined;
14
24
  if (!spread)
15
25
  return undefined;
16
26
  const reference = readDataLiteralNode(spread.getExpression());
17
- return isRawRefSentinel(reference) ? reference : undefined;
27
+ if (!isRawRefSentinel(reference))
28
+ return undefined;
29
+ const backingTableProperty = allProperties.find(isBackingTable);
30
+ const backingTable = backingTableProperty ? readBackingTableRef(backingTableProperty) : undefined;
31
+ // A backingTable that is not a plain reference cannot be re-rendered; fall back to the data reader.
32
+ if (backingTableProperty && !backingTable)
33
+ return undefined;
34
+ return { definition: reference, backingTable };
18
35
  }
19
36
  export function extractEntity(call, sourceFile) {
20
37
  const args = call.getArguments();
@@ -32,7 +49,8 @@ export function extractEntity(call, sourceFile) {
32
49
  if (!nameInit) {
33
50
  return fail("entity", sourceLocationFromNode(call, sourceFile), "object form requires a string-literal `name` property");
34
51
  }
35
- const definition = readSpreadOnlyDefinition(obj) ?? readDataLiteralNode(obj);
52
+ const spreadOnly = readSpreadOnlyDefinition(obj);
53
+ const definition = spreadOnly?.definition ?? readDataLiteralNode(obj);
36
54
  if (!isPlainObject(definition)) {
37
55
  return fail("entity", sourceLocationFromNode(call, sourceFile), "definition could not be read as a plain object (contains functions or identifiers)");
38
56
  }
@@ -49,6 +67,7 @@ export function extractEntity(call, sourceFile) {
49
67
  // Field-type membership is checked above; the cast is the extractor's
50
68
  // existing narrowing contract (readDataLiteralNode returns unknown).
51
69
  definition: defWithoutName,
70
+ ...(spreadOnly?.backingTable && { backingTable: spreadOnly.backingTable }),
52
71
  });
53
72
  }
54
73
  const entityName = readNameLiteral(first);
@@ -47,8 +47,7 @@ export declare function readStringOrRaw(node: Node): string | RawRefSentinel | u
47
47
  * Like readStringLiteralArgs, but an argument that resolves to a raw-ref
48
48
  * sentinel is kept as that sentinel instead of failing the whole call. Used
49
49
  * where a value stands in for a single name/key and inlining its resolved
50
- * string would corrupt the render roundtrip (e.g. `r.requires(someFeature.name)`
51
- * — see #1009).
50
+ * string would corrupt the render roundtrip (e.g. `r.requires(someFeature.name)`).
52
51
  */
53
52
  export declare function readStringOrRawArgs(call: CallExpression): readonly (string | RawRefSentinel)[] | undefined;
54
53
  export { isPlainObject } from "../../../utils/is-plain-object.ts";
@@ -67,7 +66,7 @@ export type NameLiteralRef = {
67
66
  };
68
67
  /**
69
68
  * Like `readNameLiteral`, but for callers that must preserve an
70
- * identifier-authored name across a render → parse round-trip (see #2111).
69
+ * identifier-authored name across a render → parse round-trip.
71
70
  * `raw` is populated only when the node resolved via an identifier — a
72
71
  * string-literal node has nothing worth preserving beyond its value, and
73
72
  * setting `raw` for it too would make `JSON.stringify(value)` and
@@ -147,8 +147,7 @@ export function readStringOrRaw(node) {
147
147
  * Like readStringLiteralArgs, but an argument that resolves to a raw-ref
148
148
  * sentinel is kept as that sentinel instead of failing the whole call. Used
149
149
  * where a value stands in for a single name/key and inlining its resolved
150
- * string would corrupt the render roundtrip (e.g. `r.requires(someFeature.name)`
151
- * — see #1009).
150
+ * string would corrupt the render roundtrip (e.g. `r.requires(someFeature.name)`).
152
151
  */
153
152
  export function readStringOrRawArgs(call) {
154
153
  const out = [];
@@ -229,7 +228,7 @@ function resolveIdentifierToStringLiteral(identifier) {
229
228
  }
230
229
  /**
231
230
  * Like `readNameLiteral`, but for callers that must preserve an
232
- * identifier-authored name across a render → parse round-trip (see #2111).
231
+ * identifier-authored name across a render → parse round-trip.
233
232
  * `raw` is populated only when the node resolved via an identifier — a
234
233
  * string-literal node has nothing worth preserving beyond its value, and
235
234
  * setting `raw` for it too would make `JSON.stringify(value)` and
@@ -17,8 +17,8 @@
17
17
  // - Top-level code outside `defineFeature(...)`. Designer/AI treat
18
18
  // such files as "not a feature file".
19
19
  //
20
- // **Skeleton status (C1.3):** interface fixed, extractors are TODO.
21
- // Per-pattern extractors fill in iteratively (C1.5) — each round adds
20
+ // **Skeleton status:** interface fixed, extractors are TODO.
21
+ // Per-pattern extractors fill in iteratively — each iteration adds
22
22
  // one extractor + a focused test.
23
23
  import { Project, SyntaxKind } from "ts-morph";
24
24
  import { extractAiClassify, extractAiExtract, extractAiGenerate, extractAuthClaims, extractBootCheck, extractClaimKey, extractConfig, extractDefineEvent, extractDescribe, extractEntity, extractEnvSchema, extractExposesApi, extractExtendsRegistrar, extractHook, extractHttpRoute, extractJob, extractMetric, extractMultiStreamProjection, extractNav, extractNotification, extractOptionalRequires, extractProjection, extractQueryHandler, extractReadsConfig, extractReferenceData, extractRelation, extractRequires, extractScreen, extractSecret, extractSecretNamespace, extractStoreTable, extractStreamHandler, extractSystemScope, extractToggleable, extractTranslations, extractTreeActions, extractUiHints, extractUseExtension, extractUsesApi, extractWorkspace, extractWriteHandler, findFunctionLiteral, findImportBindingForLocalName, readObjectPropertyInitializer, resolveModuleFile, resolveSameFileObjectLiteral, } from "./extractors/index.js";
@@ -185,7 +185,7 @@ function walkSetupCallback(body, registrarParamName, sourceFile, patterns, error
185
185
  // a registrar-wrapper call — a function that receives the registrar as
186
186
  // a bare argument, e.g. `registerShowPonyScreens(r)`. Such wrappers are
187
187
  // invisible to a receiver-shape match, so we resolve the callee (same
188
- // file, or the declaring file of a named import — #1008) and recurse
188
+ // file, or the declaring file of a named import) and recurse
189
189
  // into its body with its own parameter name for the registrar slot.
190
190
  const wrapper = resolveRegistrarWrapperCall(call, registrarParamName);
191
191
  if (!wrapper)
@@ -368,7 +368,7 @@ function walkAiStepCalls(body, registrarParamName, sourceFile, patterns, errors,
368
368
  }
369
369
  }
370
370
  // =============================================================================
371
- // Internal — pattern extractors (skeleton, implementation in C1.5)
371
+ // Internal — pattern extractors
372
372
  // =============================================================================
373
373
  /**
374
374
  * Route an `<r>.<method>(...)` call to its concrete extractor. New
@@ -377,12 +377,12 @@ function walkAiStepCalls(body, registrarParamName, sourceFile, patterns, errors,
377
377
  * commit to the new kind via compile errors.
378
378
  *
379
379
  * Skeleton: every recognised method currently returns an UnknownPattern
380
- * with the right method name. C1.5 replaces the cases with concrete
381
- * extractors one at a time.
380
+ * with the right method name. Extractors replace the cases with concrete
381
+ * implementations one at a time.
382
382
  */
383
383
  function dispatchExtractor(methodName, call, sourceFile) {
384
384
  switch (methodName) {
385
- // Round 1 — simplest static patterns
385
+ // Simplest static patterns
386
386
  case "requires":
387
387
  return extractRequires(call, sourceFile);
388
388
  case "optionalRequires":
@@ -397,7 +397,7 @@ function dispatchExtractor(methodName, call, sourceFile) {
397
397
  return extractDescribe(call, sourceFile);
398
398
  case "uiHints":
399
399
  return extractUiHints(call, sourceFile);
400
- // Round 2 — object-literal-based static patterns
400
+ // Object-literal-based static patterns
401
401
  case "entity":
402
402
  return extractEntity(call, sourceFile);
403
403
  case "relation":
@@ -406,7 +406,7 @@ function dispatchExtractor(methodName, call, sourceFile) {
406
406
  return extractNav(call, sourceFile);
407
407
  case "workspace":
408
408
  return extractWorkspace(call, sourceFile);
409
- // Round 3 — complex static patterns
409
+ // Complex static patterns
410
410
  case "config":
411
411
  return extractConfig(call, sourceFile);
412
412
  case "translations":
@@ -423,7 +423,7 @@ function dispatchExtractor(methodName, call, sourceFile) {
423
423
  return extractReferenceData(call, sourceFile);
424
424
  case "useExtension":
425
425
  return extractUseExtension(call, sourceFile);
426
- // Round 4 — mixed (header + body) patterns
426
+ // Mixed (header + body) patterns
427
427
  case "hook":
428
428
  return extractHook(call, sourceFile);
429
429
  case "authClaims":
@@ -448,7 +448,7 @@ function dispatchExtractor(methodName, call, sourceFile) {
448
448
  return extractMultiStreamProjection(call, sourceFile);
449
449
  case "screen":
450
450
  return extractScreen(call, sourceFile);
451
- // Round 5 — opaque patterns
451
+ // Opaque patterns
452
452
  case "extendsRegistrar":
453
453
  return extractExtendsRegistrar(call, sourceFile);
454
454
  case "usesApi":
@@ -459,10 +459,10 @@ function dispatchExtractor(methodName, call, sourceFile) {
459
459
  return extractStoreTable(call, sourceFile);
460
460
  case "bootCheck":
461
461
  return extractBootCheck(call, sourceFile);
462
- // Round 6 — Tree-Actions pattern
462
+ // Tree-Actions pattern
463
463
  case "treeActions":
464
464
  return extractTreeActions(call, sourceFile);
465
- // Round 7 — env-schema contract (opaque, Zod-expression argument)
465
+ // Env-schema contract (opaque, Zod-expression argument)
466
466
  case "envSchema":
467
467
  return extractEnvSchema(call, sourceFile);
468
468
  // Unknown method — UnknownPattern signal so Designer/AI surface it
@@ -33,7 +33,8 @@
33
33
  // roadmap C-Notes for the canonical-comment-attach Pattern that would
34
34
  // preserve prefixed `// kumiko-comment:` markers across roundtrips.
35
35
  import { SyntaxKind, } from "ts-morph";
36
- import { readNameLiteral, readNameOrRef, readPropertyKey, resolveSameFileObjectLiteral, } from "./extractors/shared.js";
36
+ import { readPropertyKey } from "./extractors/shared.js";
37
+ import { callMatchesId } from "./pattern-id-matchers.js";
37
38
  import { indent, PATTERN_INDENT, renderPattern, renderValue } from "./render.js";
38
39
  /**
39
40
  * Apply a sequence of changes to the source file in-place. The list is
@@ -523,7 +524,7 @@ function findCallForId(sourceFile, id) {
523
524
  continue;
524
525
  if (propAccess.getName() !== id.kind)
525
526
  continue;
526
- if (callMatchesId(call, id))
527
+ if (callMatchesId(call, id.kind, id))
527
528
  matches.push(call);
528
529
  }
529
530
  if (SINGLETON_KINDS.has(id.kind) && matches.length > 1) {
@@ -536,28 +537,6 @@ const AI_STEP_FACTORY = {
536
537
  "ai.extract": "aiExtractStep",
537
538
  "ai.classify": "aiClassifyStep",
538
539
  };
539
- function readAiStepKey(call) {
540
- const arg = call.getArguments()[0];
541
- if (!arg)
542
- return undefined;
543
- const obj = resolveSameFileObjectLiteral(arg);
544
- if (!obj)
545
- return undefined;
546
- const prop = obj.getProperty("stepKey");
547
- if (!prop)
548
- return undefined;
549
- const assign = prop.asKind(SyntaxKind.PropertyAssignment);
550
- if (assign) {
551
- const init = assign.getInitializer();
552
- if (!init)
553
- return undefined;
554
- return readNameLiteral(init);
555
- }
556
- const shorthand = prop.asKind(SyntaxKind.ShorthandPropertyAssignment);
557
- if (shorthand)
558
- return readNameLiteral(shorthand.getNameNode());
559
- return undefined;
560
- }
561
540
  function findAiStepCall(sourceFile, id) {
562
541
  if (!isAiStepId(id))
563
542
  return undefined;
@@ -566,7 +545,7 @@ function findAiStepCall(sourceFile, id) {
566
545
  for (const call of sourceFile.getDescendantsOfKind(SyntaxKind.CallExpression)) {
567
546
  if (call.getExpression().getText() !== factory)
568
547
  continue;
569
- if (callMatchesId(call, id))
548
+ if (callMatchesId(call, id.kind, id))
570
549
  matches.push(call);
571
550
  }
572
551
  if (matches.length > 1) {
@@ -574,163 +553,6 @@ function findAiStepCall(sourceFile, id) {
574
553
  }
575
554
  return matches[0];
576
555
  }
577
- function callMatchesId(call, id) {
578
- switch (id.kind) {
579
- // Singletons: kind alone identifies the call.
580
- case "requires":
581
- case "optionalRequires":
582
- case "readsConfig":
583
- case "systemScope":
584
- case "toggleable":
585
- case "describe":
586
- case "uiHints":
587
- case "config":
588
- case "translations":
589
- case "authClaims":
590
- case "treeActions":
591
- return true;
592
- case "entity":
593
- return (matchFirstArgString(call, id.entityName) || matchObjectProperty(call, "name", id.entityName));
594
- case "relation":
595
- // Positional: r.relation(entity, name, def) | Object: { entity, name, ... }
596
- if (matchFirstArgString(call, id.entityName)) {
597
- return matchArgString(call, 1, id.relationName);
598
- }
599
- return (matchObjectProperty(call, "entity", id.entityName) &&
600
- matchObjectProperty(call, "name", id.relationName));
601
- case "nav":
602
- case "workspace":
603
- case "screen":
604
- return matchObjectProperty(call, "id", id.id);
605
- case "writeHandler":
606
- case "queryHandler":
607
- case "streamHandler":
608
- return (matchFirstArgString(call, id.handlerName) ||
609
- matchObjectProperty(call, "name", id.handlerName));
610
- case "hook":
611
- // Positional: r.hook(type, target, fn) | Object: { type, target }
612
- if (typeof id.target === "object") {
613
- // Entity-wide { allOf } target — only ever appears as the object
614
- // literal { allOf: entity } (positional or nested in the object
615
- // form), never as a bare string, so check both call shapes.
616
- if (matchFirstArgString(call, id.hookType)) {
617
- return matchAllOfArg(call.getArguments()[1], id.target.allOf);
618
- }
619
- return (matchObjectProperty(call, "type", id.hookType) &&
620
- matchObjectAllOfProperty(call, "target", id.target.allOf));
621
- }
622
- if (matchFirstArgString(call, id.hookType)) {
623
- return matchArgNameOrRef(call, 1, id.target);
624
- }
625
- return (matchObjectProperty(call, "type", id.hookType) &&
626
- matchObjectProperty(call, "target", id.target));
627
- case "metric":
628
- case "secret":
629
- case "secretNamespace":
630
- case "claimKey":
631
- return (matchFirstArgString(call, id.shortName) || matchObjectProperty(call, "name", id.shortName));
632
- case "referenceData":
633
- return (matchFirstArgString(call, id.entityName) ||
634
- matchObjectProperty(call, "entity", id.entityName));
635
- case "useExtension":
636
- // Positional: r.useExtension(name, entity) | Object: { name, entity }
637
- if (matchFirstArgString(call, id.extensionName)) {
638
- return matchArgNameOrRef(call, 1, id.entityName);
639
- }
640
- return (matchObjectProperty(call, "name", id.extensionName) &&
641
- matchObjectProperty(call, "entity", id.entityName));
642
- case "job":
643
- return matchFirstArgString(call, id.jobName) || matchObjectProperty(call, "name", id.jobName);
644
- case "notification":
645
- return (matchFirstArgString(call, id.notificationName) ||
646
- matchObjectProperty(call, "name", id.notificationName));
647
- case "httpRoute":
648
- // Object form only; positional doesn't apply.
649
- return (matchObjectProperty(call, "method", id.method) && matchObjectProperty(call, "path", id.path));
650
- case "projection":
651
- case "multiStreamProjection":
652
- return matchObjectProperty(call, "name", id.name);
653
- case "defineEvent":
654
- return (matchFirstArgString(call, id.eventName) || matchObjectProperty(call, "name", id.eventName));
655
- case "extendsRegistrar":
656
- return matchFirstArgString(call, id.extensionName);
657
- case "ai.generate":
658
- case "ai.extract":
659
- case "ai.classify":
660
- return readAiStepKey(call) === id.stepKey;
661
- default: {
662
- const _exhaustive = id;
663
- return _exhaustive;
664
- }
665
- }
666
- }
667
- // Resolves an argument the same way the extractors do (readNameLiteral):
668
- // a string literal directly, or a bare identifier following its
669
- // declaration (same-file or imported) to a string-literal initializer —
670
- // the dominant naming style in the framework's own bundled-features
671
- // (`r.entity(ENTITY, ...)`, `r.useExtension(EXT_X, ...)`, see #1746).
672
- //
673
- // Narrow on purpose: every kind's arg-0 (and relation's arg-1) is parsed
674
- // via readNameLiteral, never readNameOrRef (see round2.ts/round3.ts) —
675
- // widening this shared helper to readNameOrRef would let an object-form
676
- // call's first argument (an ObjectLiteralExpression) match here too,
677
- // short-circuiting the object-form branch in callMatchesId. Positions
678
- // where the parser itself accepts an inline `{ name: "..." }` ref use
679
- // `matchArgNameOrRef` below instead.
680
- function matchArgString(call, index, expected) {
681
- const arg = call.getArguments()[index];
682
- if (!arg)
683
- return false;
684
- return readNameLiteral(arg) === expected;
685
- }
686
- // @wrapper-known semantic-alias
687
- function matchFirstArgString(call, expected) {
688
- return matchArgString(call, 0, expected);
689
- }
690
- // Like matchArgString, but via readNameOrRef — for the specific positional
691
- // slots where the parser accepts an inline `{ name: "..." }` object ref in
692
- // addition to a literal/identifier (useExtension's entity arg, hook's
693
- // target arg; see round3.ts:445 / hooks.ts:75). Not a drop-in replacement
694
- // for matchArgString: applying it to an arg-0 position would match an
695
- // object-form call's first (and only) argument, see the comment above.
696
- function matchArgNameOrRef(call, index, expected) {
697
- const arg = call.getArguments()[index];
698
- if (!arg)
699
- return false;
700
- return readNameOrRef(arg) === expected;
701
- }
702
- // Object-form property values are resolved via readNameOrRef, not the
703
- // narrower readNameLiteral — some properties (useExtension's `entity`,
704
- // hook's `target`/`allOf`) accept an inline `{ name: "..." }` ref in the
705
- // parser (see extractors/round3.ts, extractors/hooks.ts), not just a
706
- // literal or identifier. readNameOrRef is a superset of readNameLiteral,
707
- // so this is safe for every other property too.
708
- function matchObjectProperty(call, propName, expected) {
709
- const obj = call.getArguments()[0]?.asKind(SyntaxKind.ObjectLiteralExpression);
710
- if (!obj)
711
- return false;
712
- const init = obj.getProperty(propName)?.asKind(SyntaxKind.PropertyAssignment)?.getInitializer();
713
- if (!init)
714
- return false;
715
- return readNameOrRef(init) === expected;
716
- }
717
- // Matches an r.hook `{ allOf: entity }` target — as the arg node directly
718
- // (positional call form) or as a nested object property (object call form).
719
- function matchAllOfArg(node, expectedEntity) {
720
- const obj = node?.asKind(SyntaxKind.ObjectLiteralExpression);
721
- const init = obj?.getProperty("allOf")?.asKind(SyntaxKind.PropertyAssignment)?.getInitializer();
722
- if (!init)
723
- return false;
724
- return readNameOrRef(init) === expectedEntity;
725
- }
726
- function matchObjectAllOfProperty(call, propName, expectedEntity) {
727
- const obj = call.getArguments()[0]?.asKind(SyntaxKind.ObjectLiteralExpression);
728
- const propInit = obj
729
- ?.getProperty(propName)
730
- ?.asKind(SyntaxKind.PropertyAssignment)
731
- ?.getInitializer();
732
- return matchAllOfArg(propInit, expectedEntity);
733
- }
734
556
  // =============================================================================
735
557
  // Format helpers — line boundaries / blank-line collapse
736
558
  // (indent / PATTERN_INDENT live in render.ts and are imported above.)
@@ -7,6 +7,7 @@ import type { RelationDefinition } from "../types/relations.ts";
7
7
  import type { ScreenDefinition } from "../types/screen.ts";
8
8
  import type { TreeActionDef } from "../types/tree-node.ts";
9
9
  import type { WorkspaceDefinition } from "../types/workspace.ts";
10
+ import type { RawRefSentinel } from "./extractors/shared.ts";
10
11
  import type { PatternChange } from "./patch.ts";
11
12
  import type { SourceLocation } from "./source-location.ts";
12
13
  export type PatternChangeIssue = {
@@ -26,6 +27,7 @@ export declare const PATTERN_SCHEMAS_BY_KIND: {
26
27
  source: z.ZodType<SourceLocation, unknown, z.core.$ZodTypeInternals<SourceLocation, unknown>>;
27
28
  entityName: z.ZodString;
28
29
  definition: z.ZodType<EntityDefinition, unknown, z.core.$ZodTypeInternals<EntityDefinition, unknown>>;
30
+ backingTable: z.ZodOptional<z.ZodType<RawRefSentinel, unknown, z.core.$ZodTypeInternals<RawRefSentinel, unknown>>>;
29
31
  }, z.core.$strict>;
30
32
  relation: z.ZodObject<{
31
33
  kind: z.ZodLiteral<"relation">;
@@ -648,6 +650,7 @@ export declare const patternSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
648
650
  source: z.ZodType<SourceLocation, unknown, z.core.$ZodTypeInternals<SourceLocation, unknown>>;
649
651
  entityName: z.ZodString;
650
652
  definition: z.ZodType<EntityDefinition, unknown, z.core.$ZodTypeInternals<EntityDefinition, unknown>>;
653
+ backingTable: z.ZodOptional<z.ZodType<RawRefSentinel, unknown, z.core.$ZodTypeInternals<RawRefSentinel, unknown>>>;
651
654
  }, z.core.$strict>, z.ZodObject<{
652
655
  kind: z.ZodLiteral<"relation">;
653
656
  source: z.ZodType<SourceLocation, unknown, z.core.$ZodTypeInternals<SourceLocation, unknown>>;
@@ -2,7 +2,7 @@
2
2
  // tool (or any external caller) hands us JSON; before it ever reaches
3
3
  // `applyChanges` it must pass through here. Every rejection carries an
4
4
  // exact dotted/bracketed path so the caller (frequently an LLM) can
5
- // self-correct without a human in the loop — see kumiko-framework#3137.
5
+ // self-correct without a human in the loop.
6
6
  //
7
7
  // **Zod v4 constraint driving this file's shape:** every discriminated-
8
8
  // union member below stays a plain `z.object(...)` (or `.superRefine`
@@ -332,6 +332,7 @@ const entitySchema = z
332
332
  source: sourceFieldSchema,
333
333
  entityName: z.string(),
334
334
  definition: entityDefinitionSchema,
335
+ backingTable: passthroughSchema().optional(),
335
336
  })
336
337
  .strict();
337
338
  const relationSchema = z
@@ -0,0 +1,7 @@
1
+ import { type CallExpression } from "ts-morph";
2
+ import type { PatternId } from "./patch.ts";
3
+ import type { MembersByKind } from "./patterns.ts";
4
+ type PatternIdKind = PatternId["kind"];
5
+ type PatternIdOfKind = MembersByKind<PatternId>;
6
+ export declare function callMatchesId<K extends PatternIdKind>(call: CallExpression, kind: K, id: PatternIdOfKind[K]): boolean;
7
+ export {};