@cosmicdrift/kumiko-framework 0.385.0 → 0.387.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 (298) hide show
  1. package/LICENSE +21 -57
  2. package/README.md +2 -2
  3. package/agents/widgets.md +39 -39
  4. package/dist/api/api-constants.js +2 -2
  5. package/dist/api/auth-middleware.js +7 -7
  6. package/dist/api/auth-rate-limiters.js +7 -3
  7. package/dist/api/auth-routes-mfa.js +1 -1
  8. package/dist/api/auth-routes-session.js +1 -1
  9. package/dist/api/auth-routes-shared.js +7 -3
  10. package/dist/api/auth-routes-signup.js +1 -1
  11. package/dist/api/client-ip.js +3 -1
  12. package/dist/api/extra-route.js +1 -1
  13. package/dist/api/pii-leak-guard.js +4 -2
  14. package/dist/api/readiness.js +5 -5
  15. package/dist/api/redis-sse-broker.js +8 -6
  16. package/dist/api/request-context.d.ts +2 -0
  17. package/dist/api/request-context.js +16 -7
  18. package/dist/api/routes.js +2 -2
  19. package/dist/api/server.js +34 -33
  20. package/dist/api/sse-broker.js +1 -1
  21. package/dist/api/sse-route.d.ts +13 -13
  22. package/dist/api/sse-route.js +15 -15
  23. package/dist/auth/index.js +4 -4
  24. package/dist/auth/roles.d.ts +4 -4
  25. package/dist/auth/roles.js +24 -24
  26. package/dist/compliance/duration-spec.js +18 -20
  27. package/dist/compliance/index.js +2 -3
  28. package/dist/compliance/override-schema.d.ts +4 -4
  29. package/dist/compliance/override-schema.js +19 -22
  30. package/dist/compliance/profiles.d.ts +26 -29
  31. package/dist/compliance/profiles.js +62 -69
  32. package/dist/compliance/sub-processors.d.ts +28 -30
  33. package/dist/compliance/sub-processors.js +17 -21
  34. package/dist/consumer-cli.js +4 -4
  35. package/dist/crypto/blind-index.js +18 -17
  36. package/dist/crypto/ciphertext-pattern.js +1 -1
  37. package/dist/crypto/event-pii.js +3 -3
  38. package/dist/crypto/kek-source.d.ts +1 -1
  39. package/dist/crypto/kek-source.js +3 -2
  40. package/dist/crypto/kms-adapter.d.ts +1 -1
  41. package/dist/crypto/kms-adapter.js +4 -6
  42. package/dist/crypto/kms-wiring.d.ts +1 -2
  43. package/dist/crypto/kms-wiring.js +2 -2
  44. package/dist/crypto/pg-kms-adapter.js +2 -6
  45. package/dist/crypto/pii-field-encryption.js +4 -4
  46. package/dist/crypto/subject-resolver.d.ts +1 -1
  47. package/dist/crypto/subject-resolver.js +2 -2
  48. package/dist/db/apply-entity-event.d.ts +6 -6
  49. package/dist/db/apply-entity-event.js +55 -55
  50. package/dist/db/blind-index-cleanup.js +7 -7
  51. package/dist/db/collect-table-metas.js +10 -11
  52. package/dist/db/compound-types.d.ts +1 -1
  53. package/dist/db/compound-types.js +12 -12
  54. package/dist/db/cross-tenant-reads.d.ts +8 -0
  55. package/dist/db/cross-tenant-reads.js +23 -0
  56. package/dist/db/cursor.js +3 -4
  57. package/dist/db/dialect.d.ts +2 -2
  58. package/dist/db/dialect.js +2 -2
  59. package/dist/db/eagerload.d.ts +3 -3
  60. package/dist/db/eagerload.js +21 -12
  61. package/dist/db/entity-table-meta.d.ts +2 -2
  62. package/dist/db/entity-table-meta.js +4 -4
  63. package/dist/db/event-store-executor-context.d.ts +1 -1
  64. package/dist/db/event-store-executor-context.js +13 -13
  65. package/dist/db/event-store-executor-read.js +27 -28
  66. package/dist/db/event-store-executor-write.js +65 -70
  67. package/dist/db/located-timestamp.d.ts +11 -11
  68. package/dist/db/located-timestamp.js +29 -30
  69. package/dist/db/migrate-generator.d.ts +1 -1
  70. package/dist/db/migrate-generator.js +26 -19
  71. package/dist/db/migrate-runner.js +25 -25
  72. package/dist/db/money.d.ts +6 -6
  73. package/dist/db/money.js +29 -27
  74. package/dist/db/queries/backfill-pii.js +5 -5
  75. package/dist/db/queries/ddl.js +1 -1
  76. package/dist/db/queries/es-ops.d.ts +1 -1
  77. package/dist/db/queries/es-ops.js +1 -1
  78. package/dist/db/queries/event-consumer.js +3 -3
  79. package/dist/db/queries/event-store.js +4 -2
  80. package/dist/db/queries/projection-rebuild.js +3 -3
  81. package/dist/db/queries/raw-sql.d.ts +2 -2
  82. package/dist/db/queries/raw-sql.js +2 -2
  83. package/dist/db/queries/shadow-swap.js +19 -19
  84. package/dist/db/queries/test-stack.d.ts +4 -1
  85. package/dist/db/queries/test-stack.js +15 -2
  86. package/dist/db/query.d.ts +1 -1
  87. package/dist/db/query.js +6 -6
  88. package/dist/db/rebuild-marker.js +20 -21
  89. package/dist/db/replay-migration-sql.js +2 -2
  90. package/dist/db/schema-inspection.js +4 -5
  91. package/dist/db/table-builder.d.ts +1 -2
  92. package/dist/db/table-builder.js +82 -82
  93. package/dist/db/tenant-db.d.ts +2 -2
  94. package/dist/db/tenant-db.js +9 -2
  95. package/dist/derivatives/delete-stored-file.js +5 -2
  96. package/dist/derivatives/derivatives-context.js +1 -1
  97. package/dist/engine/boot-validator/access-roles.js +4 -3
  98. package/dist/engine/boot-validator/api-ext.js +14 -14
  99. package/dist/engine/boot-validator/config-deps.js +7 -6
  100. package/dist/engine/boot-validator/detail-screens.js +3 -3
  101. package/dist/engine/boot-validator/entity-handler.js +60 -61
  102. package/dist/engine/boot-validator/gdpr-storage.js +4 -4
  103. package/dist/engine/boot-validator/i18n-keys.js +1 -1
  104. package/dist/engine/boot-validator/index.d.ts +2 -2
  105. package/dist/engine/boot-validator/index.js +20 -20
  106. package/dist/engine/boot-validator/nav.js +5 -5
  107. package/dist/engine/boot-validator/ownership.js +12 -9
  108. package/dist/engine/boot-validator/parent-ref.js +1 -1
  109. package/dist/engine/boot-validator/pii-retention.js +50 -57
  110. package/dist/engine/boot-validator/projection-list-screens.js +7 -7
  111. package/dist/engine/boot-validator/query-refs.js +1 -1
  112. package/dist/engine/boot-validator/screens-actions.js +15 -16
  113. package/dist/engine/boot-validator/screens-forms.js +10 -11
  114. package/dist/engine/boot-validator/screens-lists.js +14 -15
  115. package/dist/engine/boot-validator/screens.js +34 -40
  116. package/dist/engine/boot-validator/security-baseline.js +3 -2
  117. package/dist/engine/boot-validator/transfer-graph.js +2 -2
  118. package/dist/engine/boot-validator/workspaces.js +3 -3
  119. package/dist/engine/bridge-stub.js +3 -4
  120. package/dist/engine/build-app-schema.js +75 -75
  121. package/dist/engine/build-config-feature-schema.js +50 -50
  122. package/dist/engine/build-target.js +20 -23
  123. package/dist/engine/codemod/pipeline-codemod.js +20 -13
  124. package/dist/engine/config-helpers.js +4 -4
  125. package/dist/engine/constants.js +2 -2
  126. package/dist/engine/create-app.js +2 -2
  127. package/dist/engine/define-feature.js +12 -11
  128. package/dist/engine/define-handler.js +12 -11
  129. package/dist/engine/define-step.js +1 -1
  130. package/dist/engine/define-workflow.d.ts +5 -5
  131. package/dist/engine/define-workflow.js +6 -6
  132. package/dist/engine/entity-handlers.js +13 -14
  133. package/dist/engine/event-def.js +2 -2
  134. package/dist/engine/extension-names.d.ts +16 -17
  135. package/dist/engine/extension-names.js +37 -38
  136. package/dist/engine/extensions/escape-hatch-usage.js +1 -1
  137. package/dist/engine/extensions/tenant-data.js +2 -2
  138. package/dist/engine/extensions/user-data.d.ts +23 -24
  139. package/dist/engine/factories.d.ts +14 -13
  140. package/dist/engine/factories.js +38 -37
  141. package/dist/engine/feature-ast/entity-field-types.js +1 -1
  142. package/dist/engine/feature-ast/extractors/handlers.js +1 -1
  143. package/dist/engine/feature-ast/extractors/hooks.js +1 -1
  144. package/dist/engine/feature-ast/extractors/shared.d.ts +2 -3
  145. package/dist/engine/feature-ast/extractors/shared.js +2 -3
  146. package/dist/engine/feature-ast/parse.js +13 -13
  147. package/dist/engine/feature-ast/patch.js +1 -1
  148. package/dist/engine/feature-ast/pattern-change-schema.d.ts +8 -0
  149. package/dist/engine/feature-ast/pattern-change-schema.js +1 -1
  150. package/dist/engine/feature-ast/patterns.d.ts +2 -2
  151. package/dist/engine/feature-ast/render.js +2 -2
  152. package/dist/engine/feature-config-events-jobs.js +15 -12
  153. package/dist/engine/feature-entity-handlers.js +9 -5
  154. package/dist/engine/feature-manifest.d.ts +9 -9
  155. package/dist/engine/feature-manifest.js +6 -7
  156. package/dist/engine/feature-ui-extensions.d.ts +3 -3
  157. package/dist/engine/feature-ui-extensions.js +30 -22
  158. package/dist/engine/field-access.js +5 -6
  159. package/dist/engine/index.d.ts +1 -0
  160. package/dist/engine/index.js +4 -4
  161. package/dist/engine/object-form.d.ts +1 -0
  162. package/dist/engine/object-form.js +14 -4
  163. package/dist/engine/ownership.js +3 -3
  164. package/dist/engine/parse-ref-target.js +5 -7
  165. package/dist/engine/pattern-library/index.js +2 -2
  166. package/dist/engine/pattern-library/library.js +2 -2
  167. package/dist/engine/pattern-library/types.js +3 -3
  168. package/dist/engine/pipeline.js +2 -2
  169. package/dist/engine/project-app-schema-for-roles.js +1 -1
  170. package/dist/engine/projection-helpers.js +9 -9
  171. package/dist/engine/qualified-name.js +2 -2
  172. package/dist/engine/registry-facade.js +1 -1
  173. package/dist/engine/registry-ingest.js +12 -12
  174. package/dist/engine/registry-state.js +17 -19
  175. package/dist/engine/registry-validate.js +12 -12
  176. package/dist/engine/run-in.js +2 -2
  177. package/dist/engine/run-pipeline.js +7 -0
  178. package/dist/engine/schema-builder.js +40 -38
  179. package/dist/engine/screen-filter-ops.js +17 -20
  180. package/dist/engine/screen-helpers.js +4 -3
  181. package/dist/engine/state-machine.d.ts +12 -12
  182. package/dist/engine/state-machine.js +7 -7
  183. package/dist/engine/steps/_resolver-utils.js +4 -3
  184. package/dist/engine/steps/for-each.js +4 -4
  185. package/dist/engine/steps/unsafe-projection-delete.js +1 -1
  186. package/dist/engine/steps/unsafe-projection-upsert.js +4 -4
  187. package/dist/engine/steps/wait-for-event.js +4 -4
  188. package/dist/engine/steps/workflow-system-events.js +3 -3
  189. package/dist/engine/tier-resolver-extension.d.ts +29 -27
  190. package/dist/engine/tier-resolver-extension.js +26 -26
  191. package/dist/engine/transfer-adjacency.js +2 -2
  192. package/dist/engine/validate-projection-allowlist.js +7 -27
  193. package/dist/engine/walk-step-instances.d.ts +2 -0
  194. package/dist/engine/walk-step-instances.js +38 -0
  195. package/dist/engine/where-rule-lint.js +1 -1
  196. package/dist/engine/write-handler-qn-extract.js +1 -1
  197. package/dist/entrypoint/index.js +3 -3
  198. package/dist/env/index.d.ts +7 -6
  199. package/dist/env/index.js +10 -9
  200. package/dist/errors/transition-details.js +7 -7
  201. package/dist/errors/write-error-info.d.ts +6 -6
  202. package/dist/errors/write-error-info.js +6 -6
  203. package/dist/es-ops/context.d.ts +9 -9
  204. package/dist/es-ops/context.js +28 -28
  205. package/dist/es-ops/index.js +7 -9
  206. package/dist/es-ops/operations-schema.js +4 -10
  207. package/dist/es-ops/runner.d.ts +11 -11
  208. package/dist/es-ops/runner.js +49 -53
  209. package/dist/es-ops/types.d.ts +55 -55
  210. package/dist/es-ops/types.js +11 -11
  211. package/dist/event-store/admin-api.js +6 -7
  212. package/dist/event-store/errors.js +1 -1
  213. package/dist/event-store/event-store.js +2 -2
  214. package/dist/event-store/rebuild-dead-letter.js +1 -1
  215. package/dist/files/feature.js +9 -10
  216. package/dist/files/file-handle.js +5 -6
  217. package/dist/files/file-ref-entity.js +15 -15
  218. package/dist/files/file-ref-table.js +7 -8
  219. package/dist/files/file-routes.d.ts +7 -0
  220. package/dist/files/file-routes.js +11 -5
  221. package/dist/files/in-memory-provider.js +8 -9
  222. package/dist/files/local-provider.js +18 -25
  223. package/dist/files/provider-resolver.d.ts +7 -7
  224. package/dist/files/storage-tracking.js +2 -2
  225. package/dist/files/zip-stream.d.ts +12 -19
  226. package/dist/files/zip-stream.js +44 -63
  227. package/dist/i18n/required-surface-keys.d.ts +1 -1
  228. package/dist/i18n/required-surface-keys.js +8 -8
  229. package/dist/internal/stack-support.d.ts +1 -1
  230. package/dist/internal/stack-support.js +1 -1
  231. package/dist/jobs/job-runner-helpers.d.ts +1 -2
  232. package/dist/jobs/job-runner-helpers.js +8 -18
  233. package/dist/jobs/job-runner-schedulers.d.ts +1 -1
  234. package/dist/jobs/job-runner-schedulers.js +3 -4
  235. package/dist/jobs/job-runner.js +17 -18
  236. package/dist/lifecycle/lifecycle.js +3 -5
  237. package/dist/lifecycle/signal-handlers.js +5 -4
  238. package/dist/logging/utils.d.ts +2 -1
  239. package/dist/logging/utils.js +38 -10
  240. package/dist/migrations/index.js +1 -1
  241. package/dist/migrations/kumiko-drift.js +14 -13
  242. package/dist/migrations/pending-rebuilds.d.ts +21 -20
  243. package/dist/migrations/pending-rebuilds.js +27 -27
  244. package/dist/migrations/projection-table-index.d.ts +3 -3
  245. package/dist/migrations/projection-table-index.js +8 -8
  246. package/dist/observability/metric-validator.js +1 -1
  247. package/dist/observability/metrics-handle.js +3 -3
  248. package/dist/pipeline/append-event-core.js +11 -2
  249. package/dist/pipeline/cascade-handler.d.ts +1 -1
  250. package/dist/pipeline/dispatch-batch.js +2 -2
  251. package/dist/pipeline/dispatch-query.js +10 -10
  252. package/dist/pipeline/dispatch-shared.d.ts +1 -0
  253. package/dist/pipeline/dispatch-shared.js +42 -19
  254. package/dist/pipeline/dispatch-stream.js +1 -1
  255. package/dist/pipeline/dispatch-write.js +3 -3
  256. package/dist/pipeline/dispatcher-utils.d.ts +1 -1
  257. package/dist/pipeline/dispatcher-utils.js +1 -1
  258. package/dist/pipeline/event-consumer-state.js +2 -2
  259. package/dist/pipeline/event-dispatcher-delivery.js +1 -1
  260. package/dist/pipeline/event-dispatcher.js +17 -28
  261. package/dist/pipeline/irreversible-operation-gate.js +1 -1
  262. package/dist/pipeline/lifecycle-pipeline.js +9 -9
  263. package/dist/pipeline/member-read-only-transaction.js +1 -3
  264. package/dist/pipeline/msp-rebuild.js +1 -1
  265. package/dist/pipeline/projection-rebuild.js +13 -12
  266. package/dist/pipeline/system-hooks.js +39 -41
  267. package/dist/pipeline/system-identity-switch.js +1 -3
  268. package/dist/pipeline/tenant-timezone-cache.js +1 -1
  269. package/dist/random/generate.d.ts +29 -29
  270. package/dist/random/generate.js +30 -30
  271. package/dist/random/words.js +20 -20
  272. package/dist/rate-limit/middleware.js +9 -5
  273. package/dist/redis/client.js +2 -2
  274. package/dist/redis/pubsub-signal.js +14 -17
  275. package/dist/schema-cli.js +116 -22
  276. package/dist/search/index.js +4 -4
  277. package/dist/search/purge-subject.js +4 -5
  278. package/dist/search/reindex-entity.js +6 -9
  279. package/dist/time/boot-tz-warning.d.ts +2 -2
  280. package/dist/time/boot-tz-warning.js +8 -8
  281. package/dist/time/iana.js +10 -10
  282. package/dist/time/index.js +9 -9
  283. package/dist/time/legacy-date.d.ts +2 -2
  284. package/dist/time/legacy-date.js +6 -8
  285. package/dist/time/polyfill.js +1 -1
  286. package/dist/time/tz-context.d.ts +1 -1
  287. package/dist/time/tz-context.js +1 -1
  288. package/dist/ui-types/app-schema.js +7 -7
  289. package/dist/ui-types/list-row-meta.js +4 -4
  290. package/dist/upgrade-cli.js +10 -9
  291. package/dist/utils/compare.js +1 -1
  292. package/package.json +4 -4
  293. package/src/changes.json +54 -0
  294. package/src/scripts/codemod/crypto-shredding-testing-move.ts +2 -2
  295. package/src/scripts/codemod/migrate-cross-tenant.ts +1 -1
  296. package/src/scripts/codemod/migrate-open-to-all.ts +1 -1
  297. package/src/scripts/codemod/pii-personal-migration.ts +17 -8
  298. package/src/scripts/codemod/unprocessable-error-details-reason.ts +2 -2
@@ -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
@@ -668,7 +668,7 @@ function callMatchesId(call, id) {
668
668
  // a string literal directly, or a bare identifier following its
669
669
  // declaration (same-file or imported) to a string-literal initializer —
670
670
  // the dominant naming style in the framework's own bundled-features
671
- // (`r.entity(ENTITY, ...)`, `r.useExtension(EXT_X, ...)`, see #1746).
671
+ // (`r.entity(ENTITY, ...)`, `r.useExtension(EXT_X, ...)`).
672
672
  //
673
673
  // Narrow on purpose: every kind's arg-0 (and relation's arg-1) is parsed
674
674
  // via readNameLiteral, never readNameOrRef (see round2.ts/round3.ts) —
@@ -233,6 +233,7 @@ export declare const PATTERN_SCHEMAS_BY_KIND: {
233
233
  escapeHatch: z.ZodOptional<z.ZodUnion<readonly [z.ZodObject<{
234
234
  reason: z.ZodString;
235
235
  grants: z.ZodOptional<z.ZodArray<z.ZodEnum<{
236
+ crossTenantReads: "crossTenantReads";
236
237
  globalWrites: "globalWrites";
237
238
  systemIdentity: "systemIdentity";
238
239
  unsafeRaw: "unsafeRaw";
@@ -314,6 +315,7 @@ export declare const PATTERN_SCHEMAS_BY_KIND: {
314
315
  escapeHatch: z.ZodOptional<z.ZodUnion<readonly [z.ZodObject<{
315
316
  reason: z.ZodString;
316
317
  grants: z.ZodOptional<z.ZodArray<z.ZodEnum<{
318
+ crossTenantReads: "crossTenantReads";
317
319
  globalWrites: "globalWrites";
318
320
  systemIdentity: "systemIdentity";
319
321
  unsafeRaw: "unsafeRaw";
@@ -384,6 +386,7 @@ export declare const PATTERN_SCHEMAS_BY_KIND: {
384
386
  escapeHatch: z.ZodOptional<z.ZodUnion<readonly [z.ZodObject<{
385
387
  reason: z.ZodString;
386
388
  grants: z.ZodOptional<z.ZodArray<z.ZodEnum<{
389
+ crossTenantReads: "crossTenantReads";
387
390
  globalWrites: "globalWrites";
388
391
  systemIdentity: "systemIdentity";
389
392
  unsafeRaw: "unsafeRaw";
@@ -420,6 +423,7 @@ export declare const PATTERN_SCHEMAS_BY_KIND: {
420
423
  escapeHatch: z.ZodOptional<z.ZodUnion<readonly [z.ZodObject<{
421
424
  reason: z.ZodString;
422
425
  grants: z.ZodOptional<z.ZodArray<z.ZodEnum<{
426
+ crossTenantReads: "crossTenantReads";
423
427
  globalWrites: "globalWrites";
424
428
  systemIdentity: "systemIdentity";
425
429
  unsafeRaw: "unsafeRaw";
@@ -828,6 +832,7 @@ export declare const patternSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
828
832
  escapeHatch: z.ZodOptional<z.ZodUnion<readonly [z.ZodObject<{
829
833
  reason: z.ZodString;
830
834
  grants: z.ZodOptional<z.ZodArray<z.ZodEnum<{
835
+ crossTenantReads: "crossTenantReads";
831
836
  globalWrites: "globalWrites";
832
837
  systemIdentity: "systemIdentity";
833
838
  unsafeRaw: "unsafeRaw";
@@ -908,6 +913,7 @@ export declare const patternSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
908
913
  escapeHatch: z.ZodOptional<z.ZodUnion<readonly [z.ZodObject<{
909
914
  reason: z.ZodString;
910
915
  grants: z.ZodOptional<z.ZodArray<z.ZodEnum<{
916
+ crossTenantReads: "crossTenantReads";
911
917
  globalWrites: "globalWrites";
912
918
  systemIdentity: "systemIdentity";
913
919
  unsafeRaw: "unsafeRaw";
@@ -977,6 +983,7 @@ export declare const patternSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
977
983
  escapeHatch: z.ZodOptional<z.ZodUnion<readonly [z.ZodObject<{
978
984
  reason: z.ZodString;
979
985
  grants: z.ZodOptional<z.ZodArray<z.ZodEnum<{
986
+ crossTenantReads: "crossTenantReads";
980
987
  globalWrites: "globalWrites";
981
988
  systemIdentity: "systemIdentity";
982
989
  unsafeRaw: "unsafeRaw";
@@ -1012,6 +1019,7 @@ export declare const patternSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
1012
1019
  escapeHatch: z.ZodOptional<z.ZodUnion<readonly [z.ZodObject<{
1013
1020
  reason: z.ZodString;
1014
1021
  grants: z.ZodOptional<z.ZodArray<z.ZodEnum<{
1022
+ crossTenantReads: "crossTenantReads";
1015
1023
  globalWrites: "globalWrites";
1016
1024
  systemIdentity: "systemIdentity";
1017
1025
  unsafeRaw: "unsafeRaw";
@@ -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`
@@ -258,14 +258,14 @@ export type EnvSchemaPattern = {
258
258
  readonly source: SourceLocation;
259
259
  readonly schemaBody: SourceLocation;
260
260
  };
261
- /** Live-editable policy defaults for an AI pipeline step instance (#256). */
261
+ /** Live-editable policy defaults for an AI pipeline step instance. */
262
262
  export type AiStepPolicy = {
263
263
  readonly enabled: boolean;
264
264
  readonly providerId?: string;
265
265
  readonly model?: string;
266
266
  readonly params: Record<string, unknown>;
267
267
  };
268
- /** Preserves an unresolvable argument reference across parse → render (#998). */
268
+ /** Preserves an unresolvable argument reference across parse → render. */
269
269
  export type AiStepOpaqueArgs = {
270
270
  readonly __raw: string;
271
271
  };
@@ -278,7 +278,7 @@ function renderUseExtension(p) {
278
278
  if (p.extensionNameRaw !== undefined) {
279
279
  // A raw-ref name can't be spread into the merged Object-Form without
280
280
  // losing it to renderValue's plain-string serialization — fall back
281
- // to positional form, which keeps the reference verbatim (#2111).
281
+ // to positional form, which keeps the reference verbatim.
282
282
  const optionsArg = p.options !== undefined ? `, ${renderValue(p.options)}` : "";
283
283
  return `r.useExtension(${nameLiteral}, ${JSON.stringify(p.entityName)}${optionsArg});`;
284
284
  }
@@ -568,7 +568,7 @@ function renderMultiStreamProjection(p) {
568
568
  function renderDefineEvent(p) {
569
569
  const nameLiteral = p.eventNameRaw ?? JSON.stringify(p.eventName);
570
570
  const migrationEntries = p.migrations !== undefined ? Object.entries(p.migrations) : [];
571
- // piiFields is a mandatory option (fw#2558) — the options object is
571
+ // piiFields is a mandatory option — the options object is
572
572
  // always rendered, unlike the old version/migrations-only shortcut.
573
573
  const lines = [`r.defineEvent(${nameLiteral}, ${p.schemaSource.raw}, {`];
574
574
  lines.push(` piiFields: ${p.piiFields.raw},`);
@@ -4,7 +4,7 @@ import { isValidIanaTimeZone } from "../time/iana.js";
4
4
  import { reasonProblem } from "./escape-hatch-reason.js";
5
5
  import { createEventDef } from "./event-def.js";
6
6
  import { resolveName } from "./handler-helpers.js";
7
- import { splitNamedDefinition, unwrapArrayForm } from "./object-form.js";
7
+ import { requireArgument, splitNamedDefinition, unwrapArrayForm } from "./object-form.js";
8
8
  import { QnTypes, qn, toKebab } from "./qualified-name.js";
9
9
  // Builds config/secrets/claims/events/jobs/notifications registrar methods.
10
10
  export function buildConfigEventsJobsMethods(state, name) {
@@ -49,7 +49,7 @@ export function buildConfigEventsJobsMethods(state, name) {
49
49
  }
50
50
  // Shared by defineEvent's `migrations` option — each entry registers a
51
51
  // single upcast step, same validation/dedup as the old standalone
52
- // r.eventMigration() call (folded into defineEvent, #1082 step 8).
52
+ // r.eventMigration() call (folded into defineEvent).
53
53
  function registerEventMigration(eventName, fromVersion, toVersion, transform) {
54
54
  if (toVersion !== fromVersion + 1) {
55
55
  throw new Error(`[Feature ${name}] defineEvent("${eventName}") migrations: only single-step migrations are allowed — toVersion must be fromVersion + 1 (got ${fromVersion} -> ${toVersion}). ` +
@@ -73,8 +73,8 @@ export function buildConfigEventsJobsMethods(state, name) {
73
73
  const [jobName, jobOptions, jobHandler] = typeof jobNameOrDefinition === "string"
74
74
  ? [
75
75
  jobNameOrDefinition,
76
- options,
77
- handler,
76
+ requireArgument(options, name, "job", "options"),
77
+ requireArgument(handler, name, "job", "handler"),
78
78
  ]
79
79
  : (() => {
80
80
  const { name: definedJobName, handler: h, ...rest } = jobNameOrDefinition;
@@ -97,9 +97,9 @@ export function buildConfigEventsJobsMethods(state, name) {
97
97
  'tz must be an IANA time zone name such as "Europe/Berlin".');
98
98
  }
99
99
  }
100
- // Resolve NameOrRef(s) in trigger.on. Multi-Trigger-Form: Array
101
- // wird zu Array von resolved strings, Single bleibt single string —
102
- // job-runner unterscheidet anhand Array.isArray.
100
+ // Resolve NameOrRef(s) in trigger.on. For the multi-trigger form, arrays
101
+ // become arrays of resolved strings while a single value remains a string;
102
+ // the job runner distinguishes them with Array.isArray.
103
103
  const trigger = "on" in jobOptions.trigger
104
104
  ? {
105
105
  on: Array.isArray(jobOptions.trigger.on)
@@ -114,7 +114,10 @@ export function buildConfigEventsJobsMethods(state, name) {
114
114
  },
115
115
  notification(notificationNameOrDefinition, definition) {
116
116
  const [notificationName, resolvedDefinition] = typeof notificationNameOrDefinition === "string"
117
- ? [notificationNameOrDefinition, definition]
117
+ ? [
118
+ notificationNameOrDefinition,
119
+ requireArgument(definition, name, "notification", "definition"),
120
+ ]
118
121
  : splitNamedDefinition(notificationNameOrDefinition);
119
122
  state.notifications[notificationName] = {
120
123
  name: notificationName,
@@ -167,7 +170,7 @@ export function buildConfigEventsJobsMethods(state, name) {
167
170
  },
168
171
  metric(shortNameOrDefinition, options) {
169
172
  const [shortName, metricOptions] = typeof shortNameOrDefinition === "string"
170
- ? [shortNameOrDefinition, options]
173
+ ? [shortNameOrDefinition, requireArgument(options, name, "metric", "options")]
171
174
  : splitNamedDefinition(shortNameOrDefinition);
172
175
  if (state.metrics[shortName]) {
173
176
  throw new Error(`[Feature ${name}] Metric "${shortName}" already registered. ` +
@@ -183,7 +186,7 @@ export function buildConfigEventsJobsMethods(state, name) {
183
186
  },
184
187
  secret(shortNameOrDefinition, options) {
185
188
  const [shortName, secretOptions] = typeof shortNameOrDefinition === "string"
186
- ? [shortNameOrDefinition, options]
189
+ ? [shortNameOrDefinition, requireArgument(options, name, "secret", "options")]
187
190
  : splitNamedDefinition(shortNameOrDefinition);
188
191
  if (state.secretKeys[shortName]) {
189
192
  throw new Error(`[Feature ${name}] Secret "${shortName}" already registered. ` +
@@ -208,7 +211,7 @@ export function buildConfigEventsJobsMethods(state, name) {
208
211
  },
209
212
  secretNamespace(shortNameOrDefinition, options) {
210
213
  const [shortName, namespaceOptions] = typeof shortNameOrDefinition === "string"
211
- ? [shortNameOrDefinition, options]
214
+ ? [shortNameOrDefinition, requireArgument(options, name, "secretNamespace", "options")]
212
215
  : splitNamedDefinition(shortNameOrDefinition);
213
216
  if (state.secretNamespaces[shortName]) {
214
217
  throw new Error(`[Feature ${name}] Secret namespace "${shortName}" already registered. ` +
@@ -227,7 +230,7 @@ export function buildConfigEventsJobsMethods(state, name) {
227
230
  ? shortNameOrDefinition
228
231
  : shortNameOrDefinition.name;
229
232
  const claimType = typeof shortNameOrDefinition === "string"
230
- ? options.type
233
+ ? requireArgument(options, name, "claimKey", "options").type
231
234
  : shortNameOrDefinition.type;
232
235
  if (state.claimKeys[shortName]) {
233
236
  throw new Error(`[Feature ${name}] Claim key "${shortName}" already declared. ` +
@@ -3,7 +3,7 @@ import { toTableName } from "../db/table-builder.js";
3
3
  import { isEntityConventionQueryHandler, isPagedQueryHandler, PAGED_QUERY_HANDLER_BRAND, } from "./define-handler.js";
4
4
  import { assertEscapeHatchAccessIsSystemAdminOnly, registerCrudHandlers, } from "./entity-handlers.js";
5
5
  import { resolveName } from "./handler-helpers.js";
6
- import { isObjectArgument, throwObjectArgumentRequired } from "./object-form.js";
6
+ import { isObjectArgument, requireArgument, throwObjectArgumentRequired } from "./object-form.js";
7
7
  const CRUD_VERBS = new Set(["create", "update", "delete"]);
8
8
  const CRUD_REGISTERED_VERBS = new Set([...CRUD_VERBS, "restore", "list", "detail"]);
9
9
  // A silent overwrite would drop framework behaviour that rides on the r.crud
@@ -42,9 +42,9 @@ function tryMapEntity(state, name, handlerName) {
42
42
  // skip: feature-name entity match is the preferred mapping
43
43
  return;
44
44
  }
45
- const entityKeys = Object.keys(state.entities);
46
- if (entityKeys.length === 1) {
47
- state.handlerEntityMappings[handlerName] = entityKeys[0];
45
+ const [onlyEntityName, ...otherEntityNames] = Object.keys(state.entities);
46
+ if (onlyEntityName !== undefined && otherEntityNames.length === 0) {
47
+ state.handlerEntityMappings[handlerName] = onlyEntityName;
48
48
  }
49
49
  }
50
50
  }
@@ -97,7 +97,11 @@ export function buildEntityHandlerMethods(state, name) {
97
97
  const { entity, name: innerName, ...rest } = entityRefOrDefinition;
98
98
  return [entity, innerName, rest];
99
99
  })()
100
- : [entityRefOrDefinition, relationName, definition];
100
+ : [
101
+ entityRefOrDefinition,
102
+ requireArgument(relationName, name, "relation", "relation name"),
103
+ requireArgument(definition, name, "relation", "definition"),
104
+ ];
101
105
  const entityName = resolveName(entityRef);
102
106
  if (!state.relations[entityName])
103
107
  state.relations[entityName] = {};
@@ -48,10 +48,10 @@ export type ManifestFeature = {
48
48
  readonly extensionsUsed: readonly ManifestExtension[];
49
49
  readonly configKeys: readonly ManifestConfigKey[];
50
50
  readonly secrets: readonly ManifestSecret[];
51
- /** Alle registrierten Write-Handler-QNs dieses Features
52
- * (z.B. "user:write:user:create", "auth-email-password:write:login").
53
- * Von `collectWriteHandlerQns` abgeleitet — dient als Source-of-Truth
54
- * für den Client-seitigen Typcheck von `dispatcher.write`-Calls. */
51
+ /** All registered write-handler QNs for this feature
52
+ * (e.g. "user:write:user:create", "auth-email-password:write:login").
53
+ * Derived from `collectWriteHandlerQns` and used as the source of truth
54
+ * for client-side type checking of `dispatcher.write` calls. */
55
55
  readonly writeHandlers: readonly string[];
56
56
  /** Picker/scaffolder UI metadata declared via r.uiHints(). Optional —
57
57
  * absent for features that haven't been annotated yet (the picker falls
@@ -68,13 +68,13 @@ export type FeatureManifest = {
68
68
  readonly tier?: string;
69
69
  };
70
70
  export type BuildManifestOptions = {
71
- /** Herkunfts-Beschreibung fürs Manifest (landet 1:1 im JSON). */
71
+ /** Description of the manifest's origin, included unchanged in the JSON. */
72
72
  readonly source: string;
73
- /** Nur diese Features emittieren (z.B. die 16 enterprise-Features einer
74
- * Registry, die auch deren bundled-requires gemountet hat). Default:
75
- * alle Features der Registry. */
73
+ /** Emit only these features (e.g. the 16 enterprise features from a
74
+ * Registry that also mounted their bundled requirements). Default:
75
+ * all features in the Registry. */
76
76
  readonly featureNames?: ReadonlySet<string>;
77
- /** Taggt jedes Feature + das Manifest top-level (z.B. "enterprise"). */
77
+ /** Tags each feature and the top-level manifest (e.g. "enterprise"). */
78
78
  readonly tier?: string;
79
79
  };
80
80
  export declare function buildManifestFromRegistry(registry: Registry, options: BuildManifestOptions): FeatureManifest;
@@ -1,10 +1,9 @@
1
- // Runtime-introspected feature-manifest — die geteilte Extraktionslogik
2
- // hinter `gen-feature-manifest.ts` (use-all-bundled) und dem enterprise-
3
- // Generator. Vorher waren das zwei fast wortgleiche Forks mit divergentem
4
- // Schema (enterprise#95): erweitert das Framework die Introspektion, driftete
5
- // die Kopie still. Quelle der Wahrheit ist die GEBOOTETE Registry — der
6
- // AST-Parser kann die imperativen Factory-Helper der bundled features nicht
7
- // lesen.
1
+ // Runtime-introspected feature manifest — shared extraction logic for
2
+ // `gen-feature-manifest.ts` (use-all-bundled) and the enterprise generator.
3
+ // These were previously two nearly identical forks with diverging schemas:
4
+ // when framework introspection was extended, the copy silently drifted. The
5
+ // booted Registry is authoritative because the AST parser cannot read the
6
+ // imperative factory helpers of bundled features.
8
7
  import { SYSTEM_EVENT_PREFIX } from "../crypto/system-event-pii.js";
9
8
  import { compareByCodepoint } from "../utils/index.js";
10
9
  import { isEncryptedAtRest } from "./config-helpers.js";
@@ -38,9 +38,9 @@ export declare function buildUiExtensionsMethods<TName extends string>(state: Fe
38
38
  */
39
39
  exposesApi(apiName: string): void;
40
40
  /**
41
- * Declares that this feature calls a cross-feature API. Boot-Validator
42
- * checkt dass irgendein anderes Feature `r.exposesApi(name)` macht und
43
- * dass dieses Feature `r.requires` darauf hat.
41
+ * Declares that this feature calls a cross-feature API. The boot validator
42
+ * checks that another feature calls `r.exposesApi(name)` and that this
43
+ * feature declares a corresponding `r.requires` dependency.
44
44
  */
45
45
  usesApi(apiName: string): void;
46
46
  bootCheck(fn: BootCheckFn): void;
@@ -6,7 +6,7 @@ import { bindHookEscapeHatchGrant } from "../pipeline/system-identity-switch.js"
6
6
  import { LifecycleHookTypes } from "./constants.js";
7
7
  import { reasonProblem } from "./escape-hatch-reason.js";
8
8
  import { resolveName } from "./handler-helpers.js";
9
- import { isObjectArgument, throwObjectArgumentRequired } from "./object-form.js";
9
+ import { isObjectArgument, requireArgument, throwObjectArgumentRequired } from "./object-form.js";
10
10
  import { isKebabSegment, isValidQn, qualifyEntityName, toKebab } from "./qualified-name.js";
11
11
  import { HookPhases } from "./types/index.js";
12
12
  // Builds hooks/extensions/projections/screens/nav/workspace/tables/tree-actions
@@ -159,7 +159,7 @@ export function buildUiExtensionsMethods(state, name) {
159
159
  }
160
160
  const targets = Array.isArray(target) ? target : [target];
161
161
  const names = targets.map(resolveName);
162
- // Hook-fn casts unten alle: @cast-boundary engine-bridge
162
+ // All hook-function casts below: @cast-boundary engine-bridge
163
163
  // — typed Dev-API (LifecycleHookFn|ValidationHookFn) → erased Map<name, fn>.
164
164
  if (type === "validation") {
165
165
  for (const n of names) {
@@ -211,7 +211,11 @@ export function buildUiExtensionsMethods(state, name) {
211
211
  },
212
212
  useExtension(extensionNameOrDefinition, entityRef, options) {
213
213
  const [extensionName, resolvedEntityRef, resolvedOptions] = typeof extensionNameOrDefinition === "string"
214
- ? [extensionNameOrDefinition, entityRef, options]
214
+ ? [
215
+ extensionNameOrDefinition,
216
+ requireArgument(entityRef, name, "useExtension", "entity"),
217
+ options,
218
+ ]
215
219
  : (() => {
216
220
  const { name, entity, ...rest } = extensionNameOrDefinition;
217
221
  return [name, entity, rest];
@@ -219,13 +223,14 @@ export function buildUiExtensionsMethods(state, name) {
219
223
  const resolvedEntityName = resolveName(resolvedEntityRef);
220
224
  // @cast-boundary engine-bridge — typed per-extension options → erased registration bag
221
225
  const optionsBag = resolvedOptions;
222
- // fw#2914 — cross-cutting escapeHatch convention for hook-context db
226
+ // Cross-cutting escapeHatch convention for hook-context db
223
227
  // access (mirrors r.hook's validation above). Validated the same way
224
228
  // for every extension regardless of its typed hook shape.
225
229
  const escapeHatch = optionsBag?.["escapeHatch"];
226
230
  if (escapeHatch !== undefined) {
227
- const reason = isPlainObject(escapeHatch) ? escapeHatch["reason"] : undefined;
228
- if (typeof reason !== "string") {
231
+ const escapeHatchObject = isPlainObject(escapeHatch) ? escapeHatch : undefined;
232
+ const reason = escapeHatchObject?.["reason"];
233
+ if (escapeHatchObject === undefined || typeof reason !== "string") {
229
234
  throw new Error(`[Feature ${name}] r.useExtension("${extensionName}", "${resolvedEntityName}", ...) declares an invalid { escapeHatch } — ` +
230
235
  `must be { reason: "<explanation>" } explaining why this usage needs unfiltered db access.`);
231
236
  }
@@ -233,7 +238,7 @@ export function buildUiExtensionsMethods(state, name) {
233
238
  if (extReasonProblem !== undefined) {
234
239
  throw new Error(`[Feature ${name}] r.useExtension("${extensionName}", "${resolvedEntityName}", ...) declares an invalid { escapeHatch } — ${extReasonProblem}`);
235
240
  }
236
- const extGrantsProblem = escapeHatchGrantsProblem(escapeHatch);
241
+ const extGrantsProblem = escapeHatchGrantsProblem(escapeHatchObject);
237
242
  if (extGrantsProblem) {
238
243
  throw new Error(`[Feature ${name}] r.useExtension("${extensionName}", "${resolvedEntityName}", ...) declares an invalid { escapeHatch } — ${extGrantsProblem}`);
239
244
  }
@@ -282,9 +287,9 @@ export function buildUiExtensionsMethods(state, name) {
282
287
  state.exposedApis.add(apiName);
283
288
  },
284
289
  /**
285
- * Declares that this feature calls a cross-feature API. Boot-Validator
286
- * checkt dass irgendein anderes Feature `r.exposesApi(name)` macht und
287
- * dass dieses Feature `r.requires` darauf hat.
290
+ * Declares that this feature calls a cross-feature API. The boot validator
291
+ * checks that another feature calls `r.exposesApi(name)` and that this
292
+ * feature declares a corresponding `r.requires` dependency.
288
293
  */
289
294
  usesApi(apiName) {
290
295
  state.usedApis.add(apiName);
@@ -344,7 +349,11 @@ export function buildUiExtensionsMethods(state, name) {
344
349
  entityRefOrDefinition.data,
345
350
  entityRefOrDefinition.upsertKey,
346
351
  ]
347
- : [entityRefOrDefinition, data, options?.upsertKey];
352
+ : [
353
+ entityRefOrDefinition,
354
+ requireArgument(data, name, "referenceData", "data"),
355
+ options?.upsertKey,
356
+ ];
348
357
  state.referenceData.push({
349
358
  entityName: resolveName(entityRef),
350
359
  data: resolvedData,
@@ -424,10 +433,9 @@ export function buildUiExtensionsMethods(state, name) {
424
433
  state.workspaces[definition.id] = definition;
425
434
  },
426
435
  httpRoute(definition) {
427
- // Path-Validation: muss mit "/" beginnen, keine /api/-Routes (die
428
- // sind dem Dispatcher reserviert; eine HTTP-Route die /api/foo
429
- // belegt, würde die Auth-Middleware umgehen ohne dass der Author
430
- // das ausgesprochen hat — bewusster Block).
436
+ // Path validation: must start with "/"; /api/ routes are reserved for the
437
+ // dispatcher. An HTTP route occupying /api/foo could bypass the auth
438
+ // middleware without the author explicitly intending it, so block it.
431
439
  if (!definition.path.startsWith("/")) {
432
440
  throw new Error(`[Feature ${name}] httpRoute path "${definition.path}" must start with "/". ` +
433
441
  `Got "${definition.path}".`);
@@ -505,7 +513,7 @@ export function buildUiExtensionsMethods(state, name) {
505
513
  }
506
514
  // `read_` is reserved for r.entity()/r.projection() (managed,
507
515
  // event-sourced, rebuildable). storeTable is the unmanaged
508
- // direct-write escape hatch — the prefix must say so (#1220).
516
+ // direct-write escape hatch — the prefix must say so.
509
517
  if (tableName.startsWith("read_")) {
510
518
  throw new Error(`[Feature ${name}] r.storeTable("${tableName}"): the "read_" prefix is reserved ` +
511
519
  `for managed r.entity()/r.projection() tables. Pick an unprefixed name or a ` +
@@ -514,7 +522,7 @@ export function buildUiExtensionsMethods(state, name) {
514
522
  // meta.source must agree with the r.storeTable() escape hatch, or the
515
523
  // migrate-generator treats schema drift on this table as safe to
516
524
  // DROP+rebuild-from-events — wiping direct-write data with no events
517
- // to replay it from (#1209).
525
+ // to replay it from.
518
526
  if (meta.source !== "unmanaged") {
519
527
  throw new Error(`[Feature ${name}] r.storeTable("${tableName}") was given an EntityTableMeta with ` +
520
528
  `source: "${meta.source}". r.storeTable() requires source: "unmanaged" (via ` +
@@ -538,16 +546,16 @@ export function buildUiExtensionsMethods(state, name) {
538
546
  };
539
547
  },
540
548
  treeActions(actions) {
541
- // Only-once-guard: zweiter Aufruf ist Author-Bug, soll am
542
- // Feature-File aufschlagen (gleicher Stil wie r.toggleable).
549
+ // Only-once guard: a second call is an authoring error that should surface in
550
+ // the feature file (matching the behavior of r.toggleable).
543
551
  if (state.treeActions !== undefined) {
544
552
  throw new Error(`[Feature ${name}] r.treeActions() already called. ` +
545
553
  `Each feature may declare a single tree-actions schema.`);
546
554
  }
547
555
  state.treeActions = actions;
548
- // Return typed handle für setup-export. Frozen damit Caller die
549
- // Map nicht nachträglich mutieren (würde Pattern-AST + Runtime-
550
- // Lookup divergieren lassen).
556
+ // Return a typed handle for the setup export. Freeze it so callers cannot
557
+ // mutate the map afterward, which would make the pattern AST and runtime
558
+ // lookup diverge.
551
559
  return Object.freeze({
552
560
  id: name,
553
561
  treeActions: actions,
@@ -119,18 +119,17 @@ export function checkWriteFieldRoles(entity, changes, user) {
119
119
  // row. For creates, pass oldRow = undefined; the check degenerates to a
120
120
  // newRow-only evaluation.
121
121
  //
122
- // `submittedChanges` and `rowContext` are deliberately separate (fw#1685):
122
+ // `submittedChanges` and `rowContext` are deliberately separate:
123
123
  // - `submittedChanges` drives WHICH fields get checked — only what the user
124
124
  // actually wrote in the request. A preSave-hook-derived field the user
125
125
  // never touched (e.g. a system hook setting `assignedTo`) must not be
126
126
  // field-ownership-checked against the user at all.
127
127
  // - `rowContext` drives what a checked field's rule is evaluated AGAINST —
128
128
  // this needs the full post-hook row, because an ownership rule can
129
- // reference a DIFFERENT column that only a hook populates (kumiko-
130
- // framework#1672: a hook derives `authorId`, a user-submitted `secretNote`
131
- // field's rule is `from("user:id", "authorId")` — the check needs the
132
- // hook-derived `authorId` in scope even though the user only wrote
133
- // `secretNote`). Defaults to `submittedChanges` when omitted.
129
+ // reference a DIFFERENT column that only a hook populates (a hook derives
130
+ // `authorId`, a user-submitted `secretNote` field's rule is `from("user:id", "authorId")`
131
+ // — the check needs the hook-derived `authorId` in scope even though the
132
+ // user only wrote `secretNote`). Defaults to `submittedChanges` when omitted.
134
133
  //
135
134
  // Returns the denied field name for the caller to wrap into an
136
135
  // `ownership_denied` error with scope: "field", or null if all fields pass.
@@ -91,4 +91,5 @@ export type { AccessRule, ActionFormScreenDefinition, ActiveMembership, ActiveMe
91
91
  export { DEFAULT_CURRENCIES, DEFAULT_LOCALES, DELIVERY_FAILURE_CODES, DELIVERY_SKIP_REASONS, HookPhases, HTTP_ERROR_CODE_PATTERN, isAgentVisibleScreen, isDeliveryErrorCode, isOpenToAllGranted, resolveAgentExposure, } from "./types/index.ts";
92
92
  export type { AwaitedEventType, PipelineBuildCtx, PipelineCtx, PipelineDef, StepBuilder, StepDef, StepFailureStrategy, StepInstance, StepKind, StepNamespace, StepResolver, } from "./types/step.ts";
93
93
  export { runValidation } from "./validation.ts";
94
+ export { walkStepInstances } from "./walk-step-instances.ts";
94
95
  export { formDerivationsOfSchema, withFormDerivations } from "./with-form-derivations.ts";
@@ -22,10 +22,9 @@ export { defineStep, getStep, listStepKinds } from "./define-step.js";
22
22
  export { computeDefinitionFingerprint, defineWorkflow } from "./define-workflow.js";
23
23
  export { computeEffectiveFeatures, isToggleableFeature } from "./effective-features.js";
24
24
  export { createEntityExecutor, defineEntityCreateHandler, defineEntityDeleteHandler, defineEntityDetailHandler, defineEntityListHandler,
25
- // Legacy single-fn-with-verb-string API. Backwards-compat — neue
26
- // Apps nehmen die verb-spezifischen Wrapper oben. Existierende
27
- // Caller (Integration-Tests, alte bundled-features) bleiben so
28
- // unverändert lauffähig.
25
+ // Legacy single-fn-with-verb-string API. Backwards compatibility — new
26
+ // apps use the verb-specific wrappers above. Existing callers (integration
27
+ // tests, old bundled-features) remain runnable without changes.
29
28
  defineEntityQueryHandler, defineEntityRestoreHandler, defineEntityUpdateHandler, defineEntityWriteHandler, defineProjectionQueryHandler, entityListSchema, MAX_LIST_LIMIT, } from "./entity-handlers.js";
30
29
  export { declareEscapeHatch } from "./escape-hatch-declaration.js";
31
30
  export { createEventDef } from "./event-def.js";
@@ -81,4 +80,5 @@ export { findOverDeepTransferChain, resolveTransferAdjacency as resolveEntityTra
81
80
  export { isSystemTenant, isUuid, parseTenantId, SYSTEM_TENANT_ID } from "./types/identifiers.js";
82
81
  export { DEFAULT_CURRENCIES, DEFAULT_LOCALES, DELIVERY_FAILURE_CODES, DELIVERY_SKIP_REASONS, HookPhases, HTTP_ERROR_CODE_PATTERN, isAgentVisibleScreen, isDeliveryErrorCode, isOpenToAllGranted, resolveAgentExposure, } from "./types/index.js";
83
82
  export { runValidation } from "./validation.js";
83
+ export { walkStepInstances } from "./walk-step-instances.js";
84
84
  export { formDerivationsOfSchema, withFormDerivations } from "./with-form-derivations.js";
@@ -1,6 +1,7 @@
1
1
  export declare function splitNamedDefinition<T extends {
2
2
  readonly name: string;
3
3
  }>(definition: T): [string, Omit<T, "name">];
4
+ export declare function requireArgument<T>(value: T | undefined, featureName: string, method: string, argument: string): T;
4
5
  export declare function unwrapArrayForm<K extends string>(args: readonly [Record<K, readonly string[]>] | readonly string[], key: K): readonly string[];
5
6
  export declare function isObjectArgument(value: unknown): boolean;
6
7
  export declare function throwObjectArgumentRequired(featureName: string, method: string): never;