@cosmicdrift/kumiko-framework 0.368.0 → 0.370.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 (453) hide show
  1. package/AGENTS.md +14 -1
  2. package/agents/examples/apex-surface-auth.md +2 -1
  3. package/agents/examples/app-config.md +98 -0
  4. package/agents/examples/auth-mfa.md +72 -0
  5. package/agents/examples/compose-stacks.md +188 -0
  6. package/agents/examples/env-composition.md +268 -0
  7. package/agents/examples/host-routing.md +181 -0
  8. package/agents/examples/legal-pages.md +52 -3
  9. package/agents/examples/managed-config.md +1 -0
  10. package/agents/examples/managed-pages.md +1 -0
  11. package/agents/examples/prod-boot-options.md +180 -0
  12. package/agents/examples/relations.md +4 -0
  13. package/agents/examples/secrets-demo.md +4 -2
  14. package/agents/examples/security-baseline.md +20 -17
  15. package/agents/examples.md +6 -1
  16. package/agents/features.md +17 -5
  17. package/dist/api/anonymous-cookie.d.ts +1 -1
  18. package/dist/api/anonymous-live-entities.d.ts +1 -1
  19. package/dist/api/auth-middleware.d.ts +2 -2
  20. package/dist/api/auth-routes.d.ts +7 -7
  21. package/dist/api/extra-route.d.ts +2 -2
  22. package/dist/api/index.d.ts +37 -37
  23. package/dist/api/jwt.d.ts +1 -1
  24. package/dist/api/observability-middleware.d.ts +1 -1
  25. package/dist/api/readiness.d.ts +1 -1
  26. package/dist/api/redis-sse-broker.d.ts +2 -2
  27. package/dist/api/request-context.d.ts +1 -1
  28. package/dist/api/request-id-middleware.d.ts +3 -3
  29. package/dist/api/route-registrars.d.ts +4 -4
  30. package/dist/api/routes.d.ts +1 -1
  31. package/dist/api/server.d.ts +16 -16
  32. package/dist/api/sse-broker.d.ts +1 -1
  33. package/dist/api/sse-route.d.ts +1 -1
  34. package/dist/api/websocket-route.d.ts +3 -3
  35. package/dist/auth/index.d.ts +2 -2
  36. package/dist/compliance/duration-spec.d.ts +2 -2
  37. package/dist/compliance/index.d.ts +6 -6
  38. package/dist/compliance/profiles.d.ts +1 -1
  39. package/dist/config/index.d.ts +44 -0
  40. package/dist/config/index.js +61 -0
  41. package/dist/crypto/blind-index.d.ts +1 -1
  42. package/dist/crypto/event-pii.d.ts +1 -1
  43. package/dist/crypto/in-memory-kms-adapter.d.ts +1 -1
  44. package/dist/crypto/index.d.ts +11 -11
  45. package/dist/crypto/is-self-pii-field.d.ts +1 -1
  46. package/dist/crypto/kms-wiring.d.ts +2 -2
  47. package/dist/crypto/owner-transition-rekey.d.ts +1 -1
  48. package/dist/crypto/pg-kms-adapter.d.ts +1 -1
  49. package/dist/crypto/pii-field-encryption.d.ts +4 -4
  50. package/dist/crypto/request-kms-cache.d.ts +1 -1
  51. package/dist/crypto/subject-resolver.d.ts +3 -3
  52. package/dist/db/apply-entity-event.d.ts +4 -4
  53. package/dist/db/assert-exists-in.d.ts +4 -4
  54. package/dist/db/blind-index-cleanup.d.ts +2 -2
  55. package/dist/db/collect-table-metas.d.ts +2 -2
  56. package/dist/db/compound-types.d.ts +1 -1
  57. package/dist/db/config-seed.d.ts +5 -5
  58. package/dist/db/connection.d.ts +1 -6
  59. package/dist/db/connection.js +15 -4
  60. package/dist/db/dialect.d.ts +1 -1
  61. package/dist/db/eagerload.d.ts +3 -3
  62. package/dist/db/entity-field-encryption.d.ts +3 -3
  63. package/dist/db/entity-field-encryption.js +3 -1
  64. package/dist/db/entity-table-from-registry.d.ts +3 -3
  65. package/dist/db/entity-table-meta.d.ts +3 -3
  66. package/dist/db/event-store-executor-context.d.ts +9 -9
  67. package/dist/db/event-store-executor-read.d.ts +2 -2
  68. package/dist/db/event-store-executor-write.d.ts +2 -2
  69. package/dist/db/event-store-executor.d.ts +8 -8
  70. package/dist/db/feature-table-sources.d.ts +1 -1
  71. package/dist/db/index.d.ts +39 -39
  72. package/dist/db/located-timestamp.d.ts +1 -1
  73. package/dist/db/lock-guard.d.ts +2 -2
  74. package/dist/db/migrate-generator.d.ts +2 -2
  75. package/dist/db/migrate-runner.d.ts +1 -1
  76. package/dist/db/money.d.ts +1 -1
  77. package/dist/db/parent-ref-clause.d.ts +4 -4
  78. package/dist/db/projection-registry-binding.d.ts +1 -1
  79. package/dist/db/queries/advisory-lock.d.ts +1 -1
  80. package/dist/db/queries/backfill-pii.d.ts +2 -2
  81. package/dist/db/queries/ddl.d.ts +1 -1
  82. package/dist/db/queries/entity-read.d.ts +1 -1
  83. package/dist/db/queries/es-ops.d.ts +1 -1
  84. package/dist/db/queries/event-consumer.d.ts +2 -2
  85. package/dist/db/queries/event-store-admin.d.ts +1 -1
  86. package/dist/db/queries/event-store-transfer.d.ts +1 -1
  87. package/dist/db/queries/event-store.d.ts +1 -1
  88. package/dist/db/queries/pii-backfill-state.d.ts +1 -1
  89. package/dist/db/queries/projection-rebuild.d.ts +1 -1
  90. package/dist/db/queries/raw-sql.d.ts +1 -1
  91. package/dist/db/queries/seed-context.d.ts +2 -2
  92. package/dist/db/queries/shadow-swap.d.ts +3 -3
  93. package/dist/db/queries/table-ops.d.ts +1 -1
  94. package/dist/db/queries/test-stack.d.ts +2 -2
  95. package/dist/db/query.d.ts +3 -3
  96. package/dist/db/rebuild-marker.d.ts +1 -1
  97. package/dist/db/reference-data.d.ts +3 -3
  98. package/dist/db/render-ddl.d.ts +1 -1
  99. package/dist/db/replay-migration-sql.d.ts +1 -1
  100. package/dist/db/retired-framework-tables.d.ts +1 -1
  101. package/dist/db/schema-inspection.d.ts +1 -1
  102. package/dist/db/table-builder.d.ts +4 -4
  103. package/dist/db/table-push.d.ts +3 -3
  104. package/dist/db/tenant-db-runner.d.ts +2 -2
  105. package/dist/db/tenant-db.d.ts +7 -9
  106. package/dist/db/tenant-db.js +2 -12
  107. package/dist/derivatives/derivatives-context.d.ts +3 -3
  108. package/dist/derivatives/field-variants.d.ts +1 -1
  109. package/dist/derivatives/index.d.ts +6 -6
  110. package/dist/engine/access.d.ts +1 -1
  111. package/dist/engine/active-membership.d.ts +2 -2
  112. package/dist/engine/boot-validator/access-declarations.d.ts +1 -1
  113. package/dist/engine/boot-validator/access-roles.d.ts +1 -1
  114. package/dist/engine/boot-validator/action-wiring.d.ts +1 -1
  115. package/dist/engine/boot-validator/api-ext.d.ts +1 -1
  116. package/dist/engine/boot-validator/boot-check.d.ts +1 -1
  117. package/dist/engine/boot-validator/card-meta-overflow.d.ts +1 -1
  118. package/dist/engine/boot-validator/config-deps.d.ts +1 -1
  119. package/dist/engine/boot-validator/detail-screens.d.ts +2 -2
  120. package/dist/engine/boot-validator/entity-handler.d.ts +1 -1
  121. package/dist/engine/boot-validator/entity-list-screens.d.ts +1 -1
  122. package/dist/engine/boot-validator/gdpr-storage.d.ts +1 -1
  123. package/dist/engine/boot-validator/global-tenancy.d.ts +1 -1
  124. package/dist/engine/boot-validator/handler-field-references.d.ts +1 -1
  125. package/dist/engine/boot-validator/i18n-keys.d.ts +1 -1
  126. package/dist/engine/boot-validator/index.d.ts +7 -7
  127. package/dist/engine/boot-validator/nav.d.ts +1 -1
  128. package/dist/engine/boot-validator/ownership.d.ts +2 -2
  129. package/dist/engine/boot-validator/parent-ref.d.ts +1 -1
  130. package/dist/engine/boot-validator/pii-retention.d.ts +2 -2
  131. package/dist/engine/boot-validator/projection-list-screens.d.ts +1 -1
  132. package/dist/engine/boot-validator/query-output-columns.d.ts +1 -1
  133. package/dist/engine/boot-validator/query-refs.d.ts +1 -1
  134. package/dist/engine/boot-validator/record-owned.d.ts +1 -1
  135. package/dist/engine/boot-validator/screens.d.ts +2 -2
  136. package/dist/engine/boot-validator/screens.js +29 -0
  137. package/dist/engine/boot-validator/security-baseline.d.ts +1 -1
  138. package/dist/engine/boot-validator/selector-owner-panels.d.ts +1 -1
  139. package/dist/engine/boot-validator/transfer-graph.d.ts +2 -2
  140. package/dist/engine/boot-validator/url-prefill-fields.d.ts +1 -1
  141. package/dist/engine/boot-validator/workspaces.d.ts +1 -1
  142. package/dist/engine/boot-validator.d.ts +1 -1
  143. package/dist/engine/bridge-stub.d.ts +1 -1
  144. package/dist/engine/build-app-schema.d.ts +2 -2
  145. package/dist/engine/build-config-feature-schema.d.ts +5 -5
  146. package/dist/engine/build-config-feature-schema.js +197 -65
  147. package/dist/engine/build-target.d.ts +2 -2
  148. package/dist/engine/changeset-changes.d.ts +1 -1
  149. package/dist/engine/codemod/index.d.ts +2 -2
  150. package/dist/engine/config-helpers.d.ts +1 -1
  151. package/dist/engine/constants.d.ts +1 -1
  152. package/dist/engine/create-app.d.ts +2 -2
  153. package/dist/engine/cross-tenant.d.ts +2 -2
  154. package/dist/engine/dedupe-features.d.ts +1 -1
  155. package/dist/engine/define-feature.d.ts +1 -1
  156. package/dist/engine/define-feature.js +2 -2
  157. package/dist/engine/define-handler.d.ts +4 -4
  158. package/dist/engine/define-step.d.ts +1 -1
  159. package/dist/engine/define-workflow.d.ts +2 -2
  160. package/dist/engine/effective-features.d.ts +1 -1
  161. package/dist/engine/embedded-derived.d.ts +1 -1
  162. package/dist/engine/entity-handlers.d.ts +6 -5
  163. package/dist/engine/entity-handlers.js +6 -3
  164. package/dist/engine/event-def.d.ts +15 -0
  165. package/dist/engine/event-def.js +123 -0
  166. package/dist/engine/event-helpers.d.ts +1 -1
  167. package/dist/engine/extension-names.d.ts +8 -8
  168. package/dist/engine/extension-selector-plugins.d.ts +4 -1
  169. package/dist/engine/extension-selector-plugins.js +14 -0
  170. package/dist/engine/extensions/escape-hatch-usage.d.ts +1 -1
  171. package/dist/engine/extensions/storage-provider.d.ts +1 -1
  172. package/dist/engine/extensions/tenant-data.d.ts +3 -3
  173. package/dist/engine/extensions/tenant-resource.d.ts +2 -2
  174. package/dist/engine/extensions/user-data.d.ts +2 -2
  175. package/dist/engine/factories.d.ts +1 -1
  176. package/dist/engine/feature-ast/extractors/ai-steps.d.ts +2 -2
  177. package/dist/engine/feature-ast/extractors/events.d.ts +2 -2
  178. package/dist/engine/feature-ast/extractors/handlers.d.ts +4 -4
  179. package/dist/engine/feature-ast/extractors/hooks.d.ts +5 -5
  180. package/dist/engine/feature-ast/extractors/index.d.ts +14 -14
  181. package/dist/engine/feature-ast/extractors/jobs-routes.d.ts +3 -3
  182. package/dist/engine/feature-ast/extractors/projections-screens.d.ts +3 -3
  183. package/dist/engine/feature-ast/extractors/round1.d.ts +2 -2
  184. package/dist/engine/feature-ast/extractors/round2.d.ts +2 -2
  185. package/dist/engine/feature-ast/extractors/round3.d.ts +4 -4
  186. package/dist/engine/feature-ast/extractors/round5.d.ts +2 -2
  187. package/dist/engine/feature-ast/extractors/round6.d.ts +2 -2
  188. package/dist/engine/feature-ast/extractors/shared.d.ts +2 -2
  189. package/dist/engine/feature-ast/index.d.ts +16 -16
  190. package/dist/engine/feature-ast/parse.d.ts +2 -2
  191. package/dist/engine/feature-ast/patch.d.ts +1 -1
  192. package/dist/engine/feature-ast/patcher.d.ts +15 -15
  193. package/dist/engine/feature-ast/pattern-change-schema.d.ts +10 -10
  194. package/dist/engine/feature-ast/patterns.d.ts +15 -15
  195. package/dist/engine/feature-ast/render.d.ts +1 -1
  196. package/dist/engine/feature-builder-state.d.ts +5 -5
  197. package/dist/engine/feature-config-events-jobs.d.ts +5 -3
  198. package/dist/engine/feature-config-events-jobs.js +9 -130
  199. package/dist/engine/feature-entity-handlers.d.ts +4 -4
  200. package/dist/engine/feature-entity-handlers.js +11 -5
  201. package/dist/engine/feature-manifest.d.ts +1 -1
  202. package/dist/engine/feature-ui-extensions.d.ts +7 -7
  203. package/dist/engine/feature-ui-extensions.js +2 -2
  204. package/dist/engine/field-access.d.ts +1 -1
  205. package/dist/engine/field-helpers.d.ts +1 -1
  206. package/dist/engine/handler-helpers.d.ts +1 -1
  207. package/dist/engine/index.d.ts +89 -88
  208. package/dist/engine/index.js +1 -0
  209. package/dist/engine/instruction-fields.d.ts +1 -1
  210. package/dist/engine/object-form.d.ts +1 -1
  211. package/dist/engine/object-form.js +5 -6
  212. package/dist/engine/ownership.d.ts +3 -3
  213. package/dist/engine/pattern-library/index.d.ts +2 -2
  214. package/dist/engine/pattern-library/library.d.ts +2 -2
  215. package/dist/engine/pattern-library/mixed-schemas.d.ts +1 -1
  216. package/dist/engine/pattern-library/opaque-schemas.d.ts +1 -1
  217. package/dist/engine/pattern-library/shared-fields.d.ts +1 -1
  218. package/dist/engine/pattern-library/static-schemas.d.ts +1 -1
  219. package/dist/engine/pattern-library/types.d.ts +1 -1
  220. package/dist/engine/personal-data-fields.d.ts +2 -2
  221. package/dist/engine/pipeline.d.ts +2 -2
  222. package/dist/engine/project-app-schema-for-roles.d.ts +1 -1
  223. package/dist/engine/projection-helpers.d.ts +4 -4
  224. package/dist/engine/read-claim.d.ts +1 -1
  225. package/dist/engine/registry-facade.d.ts +2 -2
  226. package/dist/engine/registry-ingest.d.ts +2 -2
  227. package/dist/engine/registry-state.d.ts +2 -2
  228. package/dist/engine/registry-validate.d.ts +3 -3
  229. package/dist/engine/registry.d.ts +1 -1
  230. package/dist/engine/resolve-config-or-param.d.ts +2 -2
  231. package/dist/engine/role-assignment.d.ts +1 -1
  232. package/dist/engine/run-in.d.ts +1 -1
  233. package/dist/engine/run-pipeline.d.ts +3 -3
  234. package/dist/engine/schema-builder.d.ts +1 -1
  235. package/dist/engine/screen-filter-ops.d.ts +1 -1
  236. package/dist/engine/screen-helpers.d.ts +2 -2
  237. package/dist/engine/soft-delete-cleanup.d.ts +2 -2
  238. package/dist/engine/steps/_event-match.d.ts +1 -1
  239. package/dist/engine/steps/_no-return-guard.d.ts +1 -1
  240. package/dist/engine/steps/_read-source.d.ts +4 -4
  241. package/dist/engine/steps/_resolver-utils.d.ts +1 -1
  242. package/dist/engine/steps/aggregate-append-event.d.ts +1 -1
  243. package/dist/engine/steps/aggregate-create.d.ts +2 -2
  244. package/dist/engine/steps/aggregate-update.d.ts +3 -3
  245. package/dist/engine/steps/branch.d.ts +1 -1
  246. package/dist/engine/steps/call-feature.d.ts +2 -2
  247. package/dist/engine/steps/compute.d.ts +1 -1
  248. package/dist/engine/steps/for-each.d.ts +1 -1
  249. package/dist/engine/steps/mail-send.d.ts +1 -1
  250. package/dist/engine/steps/read-find-many.d.ts +2 -2
  251. package/dist/engine/steps/read-find-one.d.ts +2 -2
  252. package/dist/engine/steps/retry.d.ts +1 -1
  253. package/dist/engine/steps/return.d.ts +2 -2
  254. package/dist/engine/steps/unsafe-projection-delete.d.ts +2 -2
  255. package/dist/engine/steps/unsafe-projection-upsert.d.ts +1 -1
  256. package/dist/engine/steps/wait-for-event.d.ts +1 -1
  257. package/dist/engine/steps/wait.d.ts +1 -1
  258. package/dist/engine/steps/webhook-send.d.ts +1 -1
  259. package/dist/engine/strip-disabled-features-from-app-schema.d.ts +4 -4
  260. package/dist/engine/system-user.d.ts +2 -2
  261. package/dist/engine/template-variables.d.ts +1 -1
  262. package/dist/engine/tier-resolver-extension.d.ts +4 -4
  263. package/dist/engine/transfer-adjacency.d.ts +1 -1
  264. package/dist/engine/types/index.d.ts +6 -6
  265. package/dist/engine/validate-projection-allowlist.d.ts +1 -1
  266. package/dist/engine/validation.d.ts +1 -1
  267. package/dist/entrypoint/index.d.ts +12 -12
  268. package/dist/env/dry-run.d.ts +14 -1
  269. package/dist/env/dry-run.js +50 -0
  270. package/dist/env/index.d.ts +54 -16
  271. package/dist/env/index.js +60 -6
  272. package/dist/errors/classes.d.ts +3 -3
  273. package/dist/errors/docs-url.d.ts +1 -1
  274. package/dist/errors/index.d.ts +18 -18
  275. package/dist/errors/member-resolution.d.ts +1 -1
  276. package/dist/errors/serialize.d.ts +2 -2
  277. package/dist/errors/subject-erased.d.ts +1 -1
  278. package/dist/errors/to-kumiko-error.d.ts +1 -1
  279. package/dist/errors/write-error-info.d.ts +1 -1
  280. package/dist/errors/zod-bridge.d.ts +1 -1
  281. package/dist/es-ops/context.d.ts +4 -4
  282. package/dist/es-ops/index.d.ts +4 -4
  283. package/dist/es-ops/operations-schema.d.ts +1 -1
  284. package/dist/es-ops/runner.d.ts +3 -3
  285. package/dist/es-ops/runner.js +9 -1
  286. package/dist/es-ops/types.d.ts +2 -2
  287. package/dist/event-store/admin-api.d.ts +3 -3
  288. package/dist/event-store/archive.d.ts +2 -2
  289. package/dist/event-store/event-store.d.ts +2 -2
  290. package/dist/event-store/events-schema.d.ts +1 -1
  291. package/dist/event-store/index.d.ts +15 -15
  292. package/dist/event-store/provenance-append.d.ts +3 -3
  293. package/dist/event-store/rebuild-dead-letter.d.ts +2 -2
  294. package/dist/event-store/row-to-stored-event.d.ts +2 -2
  295. package/dist/event-store/snapshot.d.ts +2 -2
  296. package/dist/event-store/tenant-db-append.d.ts +2 -2
  297. package/dist/event-store/transfer.d.ts +3 -3
  298. package/dist/event-store/upcaster-dead-letter.d.ts +2 -2
  299. package/dist/event-store/upcaster.d.ts +3 -3
  300. package/dist/files/assert-file-refs-belong-to-tenant.d.ts +2 -2
  301. package/dist/files/bind-pending-file-refs.d.ts +3 -3
  302. package/dist/files/create-file-ref-from-bytes.d.ts +4 -4
  303. package/dist/files/create-file-ref.d.ts +3 -3
  304. package/dist/files/dispose-removed-file-refs.d.ts +2 -2
  305. package/dist/files/feature.d.ts +3 -3
  306. package/dist/files/file-handle.d.ts +1 -1
  307. package/dist/files/file-ref-entity.d.ts +1 -1
  308. package/dist/files/file-ref-table.d.ts +1 -1
  309. package/dist/files/file-routes.d.ts +5 -5
  310. package/dist/files/in-memory-provider.d.ts +1 -1
  311. package/dist/files/index.d.ts +20 -20
  312. package/dist/files/load-save-file-refs.d.ts +2 -2
  313. package/dist/files/local-provider.d.ts +1 -1
  314. package/dist/files/provider-resolver.d.ts +5 -5
  315. package/dist/files/purge-expired-file-ref-bytes.d.ts +2 -2
  316. package/dist/files/record-read-check.d.ts +1 -1
  317. package/dist/files/record-write-check.d.ts +3 -3
  318. package/dist/files/storage-tracking.d.ts +2 -2
  319. package/dist/files/types.d.ts +1 -1
  320. package/dist/files/zip-stream.d.ts +1 -1
  321. package/dist/i18n/index.d.ts +4 -4
  322. package/dist/i18n/mail-registry.d.ts +1 -1
  323. package/dist/i18n/required-surface-keys.d.ts +1 -1
  324. package/dist/i18n/settings-hub-keys.d.ts +1 -1
  325. package/dist/i18n/settings-hub-keys.js +1 -2
  326. package/dist/internal/stack-support.d.ts +12 -12
  327. package/dist/internal/testing.d.ts +4 -4
  328. package/dist/jobs/index.d.ts +2 -2
  329. package/dist/jobs/job-runner.d.ts +1 -1
  330. package/dist/jobs/max-per-tenant.d.ts +1 -1
  331. package/dist/lifecycle/index.d.ts +2 -2
  332. package/dist/lifecycle/lifecycle.d.ts +1 -1
  333. package/dist/lifecycle/signal-handlers.d.ts +1 -1
  334. package/dist/logging/index.d.ts +4 -4
  335. package/dist/logging/pino-logger.d.ts +1 -1
  336. package/dist/logging/utils.d.ts +1 -1
  337. package/dist/migrations/index.d.ts +4 -4
  338. package/dist/migrations/kumiko-drift.d.ts +1 -1
  339. package/dist/migrations/pending-rebuilds.d.ts +5 -5
  340. package/dist/migrations/pii-event-backfill.d.ts +4 -4
  341. package/dist/migrations/projection-table-index.d.ts +1 -1
  342. package/dist/observability/console-provider.d.ts +1 -1
  343. package/dist/observability/context.d.ts +1 -1
  344. package/dist/observability/escape-hatch-report.d.ts +3 -3
  345. package/dist/observability/fallback.d.ts +1 -1
  346. package/dist/observability/index.d.ts +16 -16
  347. package/dist/observability/metric-validator.d.ts +1 -1
  348. package/dist/observability/metrics-handle.d.ts +1 -1
  349. package/dist/observability/metrics-wiring.d.ts +2 -2
  350. package/dist/observability/noop-provider.d.ts +1 -1
  351. package/dist/observability/prometheus-meter.d.ts +1 -1
  352. package/dist/observability/recording-meter.d.ts +1 -1
  353. package/dist/observability/recording-tracer.d.ts +1 -1
  354. package/dist/observability/redis-wrapper.d.ts +1 -1
  355. package/dist/observability/sensitive-filter.d.ts +1 -1
  356. package/dist/observability/standard-metrics.d.ts +1 -1
  357. package/dist/pipeline/active-membership.d.ts +4 -4
  358. package/dist/pipeline/append-event-core.d.ts +3 -3
  359. package/dist/pipeline/auth-claims-resolver.d.ts +2 -2
  360. package/dist/pipeline/cascade-handler.d.ts +3 -3
  361. package/dist/pipeline/dispatch-batch.d.ts +2 -2
  362. package/dist/pipeline/dispatch-query.d.ts +4 -4
  363. package/dist/pipeline/dispatch-shared.d.ts +17 -17
  364. package/dist/pipeline/dispatch-stream.d.ts +2 -2
  365. package/dist/pipeline/dispatch-write.d.ts +4 -4
  366. package/dist/pipeline/dispatcher-utils.d.ts +2 -2
  367. package/dist/pipeline/dispatcher.d.ts +12 -12
  368. package/dist/pipeline/event-consumer-state.d.ts +1 -1
  369. package/dist/pipeline/event-dispatcher-admin.d.ts +1 -1
  370. package/dist/pipeline/event-dispatcher-delivery.d.ts +7 -7
  371. package/dist/pipeline/event-dispatcher.d.ts +7 -7
  372. package/dist/pipeline/event-retention.d.ts +1 -1
  373. package/dist/pipeline/handler-access-error.d.ts +2 -2
  374. package/dist/pipeline/index.d.ts +42 -42
  375. package/dist/pipeline/irreversible-operation-gate.d.ts +1 -1
  376. package/dist/pipeline/lifecycle-pipeline.d.ts +2 -2
  377. package/dist/pipeline/member-read-only-transaction.d.ts +2 -2
  378. package/dist/pipeline/member-reader.d.ts +5 -5
  379. package/dist/pipeline/msp-rebuild.d.ts +4 -4
  380. package/dist/pipeline/multi-stream-apply-context.d.ts +3 -3
  381. package/dist/pipeline/notify-scope.d.ts +3 -3
  382. package/dist/pipeline/pending-gap-ranges.d.ts +2 -2
  383. package/dist/pipeline/pre-handler-gates.d.ts +3 -3
  384. package/dist/pipeline/pre-transaction-reservations.d.ts +4 -4
  385. package/dist/pipeline/projection-rebuild.d.ts +3 -3
  386. package/dist/pipeline/projection-state.d.ts +1 -1
  387. package/dist/pipeline/projections-runner.d.ts +3 -3
  388. package/dist/pipeline/projections-runner.js +3 -4
  389. package/dist/pipeline/system-hooks.d.ts +4 -4
  390. package/dist/pipeline/system-identity-switch.d.ts +3 -3
  391. package/dist/pipeline/tenant-timezone-cache.d.ts +1 -1
  392. package/dist/pipeline/write-origin.d.ts +3 -3
  393. package/dist/pipeline/write-result-masking.d.ts +2 -2
  394. package/dist/random/index.d.ts +2 -2
  395. package/dist/rate-limit/bucket.d.ts +1 -1
  396. package/dist/rate-limit/index.d.ts +3 -3
  397. package/dist/rate-limit/middleware.d.ts +3 -3
  398. package/dist/redis/cache-sync-bus.d.ts +2 -2
  399. package/dist/redis/cache-sync-topics.d.ts +1 -1
  400. package/dist/redis/index.d.ts +8 -8
  401. package/dist/redis/pubsub-signal.d.ts +1 -1
  402. package/dist/schema-cli.d.ts +1 -1
  403. package/dist/schema-cli.js +9 -1
  404. package/dist/search/derive-search-adapter-config.d.ts +2 -2
  405. package/dist/search/in-memory-adapter.d.ts +1 -1
  406. package/dist/search/index.d.ts +6 -6
  407. package/dist/search/meilisearch-adapter.d.ts +2 -2
  408. package/dist/search/purge-subject.d.ts +4 -4
  409. package/dist/search/reindex-entity.d.ts +3 -3
  410. package/dist/secrets/dek-cache.d.ts +1 -1
  411. package/dist/secrets/env-master-key-provider.d.ts +1 -1
  412. package/dist/secrets/env-master-key-provider.js +26 -11
  413. package/dist/secrets/envelope-cipher.d.ts +2 -2
  414. package/dist/secrets/envelope.d.ts +1 -1
  415. package/dist/secrets/index.d.ts +9 -9
  416. package/dist/secrets/rotation.d.ts +1 -1
  417. package/dist/secrets/stored-envelope.d.ts +1 -1
  418. package/dist/seeding/entity-seed.d.ts +1 -1
  419. package/dist/seeding/index.d.ts +3 -3
  420. package/dist/seeding/seed-users.d.ts +1 -1
  421. package/dist/time/index.d.ts +6 -6
  422. package/dist/ui-types/app-schema.d.ts +5 -5
  423. package/dist/ui-types/index.d.ts +23 -23
  424. package/dist/upgrade-cli.js +18 -6
  425. package/dist/utils/index.d.ts +9 -9
  426. package/package.json +19 -66
  427. package/presets/biome-app.json +80 -0
  428. package/presets/tsconfig.app.json +19 -0
  429. package/src/changes.json +84 -2
  430. package/src/scripts/codemod/README.md +18 -0
  431. package/src/scripts/codemod/codemod-support.ts +1 -1
  432. package/src/scripts/codemod/db-factory.ts +1 -1
  433. package/src/scripts/codemod/feature-factory.ts +1 -1
  434. package/src/scripts/codemod/import-extensions.ts +118 -0
  435. package/src/scripts/codemod/migrate-cross-tenant.ts +2 -2
  436. package/src/scripts/codemod/migrate-db-raw.ts +1 -1
  437. package/src/scripts/codemod/migrate-open-to-all.ts +1 -1
  438. package/src/scripts/codemod/object-form.ts +1 -1
  439. package/src/scripts/codemod/s3-imports.ts +1 -1
  440. package/src/scripts/codemod/tenant-db-options.ts +1 -1
  441. package/src/scripts/codemod/testing-move.ts +2 -2
  442. package/dist/db/bun-db-deprecated.d.ts +0 -10
  443. package/dist/db/bun-db-deprecated.js +0 -5
  444. package/dist/stack/index.d.ts +0 -10
  445. package/dist/stack/index.js +0 -11
  446. package/dist/testing/e2e-generator.d.ts +0 -5
  447. package/dist/testing/e2e-generator.js +0 -5
  448. package/dist/testing/handler-context.d.ts +0 -5
  449. package/dist/testing/handler-context.js +0 -5
  450. package/dist/testing/index.d.ts +0 -10
  451. package/dist/testing/index.js +0 -10
  452. package/dist/testing/real-providers.d.ts +0 -5
  453. package/dist/testing/real-providers.js +0 -5
@@ -17,9 +17,10 @@
17
17
  import { isOptionsQueryFieldRef } from "@cosmicdrift/kumiko-types/fields";
18
18
  import { CONFIG_EDIT_ENTITY, fieldLabelKey } from "../i18n/required-surface-keys.js";
19
19
  import { isEncryptedAtRest } from "./config-helpers.js";
20
- import { EXTENSION_SELECTOR_HINT_KEY, SELECTED_EXTENSIONS_QUERY, selectablePluginIds, } from "./extension-selector-plugins.js";
20
+ import { EXTENSION_SELECTOR_HINT_KEY, isSelectableInSettings, settingsSelectablePluginIds, } from "./extension-selector-plugins.js";
21
21
  import { createBooleanField, createNumberField, createSelectField, createTextField, } from "./factories.js";
22
22
  import { isKebabSegment, toKebab } from "./qualified-name.js";
23
+ import { isFieldsEditSection, sectionFieldSpecs } from "./screen-helpers.js";
23
24
  import { isOpenToAllGranted } from "./types/handlers.js";
24
25
  // Namespace, unter dem buildAppSchema die generierten Screens/Navs einhängt
25
26
  // (find-or-create FeatureSchema). MUSS gleich CONFIG_FEATURE aus dem config
@@ -45,7 +46,7 @@ const PROVIDER_PANEL_TITLE_ENTRY = {
45
46
  es: "Proveedor",
46
47
  };
47
48
  const PROVIDER_SECTION_TITLE_KEY = "config.settings.provider";
48
- const SAVE_PROVIDER_LABEL_KEY = "config.settings.saveProvider";
49
+ const SECRETS_SECTION_DESCRIPTION_KEY = "config.secrets.description";
49
50
  const audienceNavShortId = (scope) => `audience-${scope}`;
50
51
  // Generated post-boot, never via r.nav() — the boot validator exempts exactly these QNs (an app references one to place the settings group inline).
51
52
  export const SETTINGS_HUB_AUDIENCE_NAV_QNS = SCOPES_BROAD_TO_DEEP.map((scope) => `${SETTINGS_HUB_FEATURE}:nav:${audienceNavShortId(scope)}`);
@@ -73,25 +74,43 @@ const NO_SELECTOR_GATING = {
73
74
  };
74
75
  // Verbatim (unprefixed) keys as the client sees them — NOT getAllTranslations()
75
76
  // (server-merged, "feature:"-prefixed, see build-app-schema.ts:77-81).
77
+ // Merged per locale: a locale feature (localeDe) declares the same key with only its
78
+ // own language, and mounted first it must not drop the owning feature's en text.
76
79
  function collectDeclaredTranslations(registry) {
77
80
  const declared = new Map();
78
81
  for (const f of registry.features.values()) {
79
82
  for (const [key, values] of Object.entries(f.translations ?? {})) {
80
- if (!declared.has(key))
81
- declared.set(key, values);
83
+ declared.set(key, { ...values, ...declared.get(key) });
82
84
  }
83
85
  }
84
86
  return declared;
85
87
  }
88
+ // A selector whose plugins are all hidden from settings still renders as a select
89
+ // (with no option), never as a free text field.
86
90
  function collectSelectorOptions(registry) {
87
91
  const options = new Map();
88
92
  for (const [extensionName, selectorKey] of registry.getAllExtensionSelectors()) {
89
- const pluginIds = selectablePluginIds(registry, extensionName);
90
- if (pluginIds.length > 0)
91
- options.set(selectorKey, pluginIds);
93
+ if (registry.getExtensionUsages(extensionName).length === 0)
94
+ continue;
95
+ options.set(selectorKey, settingsSelectablePluginIds(registry, extensionName));
92
96
  }
93
97
  return options;
94
98
  }
99
+ // selector key → plugin id → plugin feature, for every selectable plugin, also those
100
+ // without settings of their own (no panel, but still an option with a name).
101
+ function collectSelectorOptionFeatures(registry) {
102
+ const byKey = new Map();
103
+ for (const [extensionName, selectorKey] of registry.getAllExtensionSelectors()) {
104
+ const featureByPluginId = new Map();
105
+ for (const usage of registry.getExtensionUsages(extensionName).filter(isSelectableInSettings)) {
106
+ if (usage.featureName === undefined || featureByPluginId.has(usage.entityName))
107
+ continue;
108
+ featureByPluginId.set(usage.entityName, toKebab(usage.featureName));
109
+ }
110
+ byKey.set(selectorKey, featureByPluginId);
111
+ }
112
+ return byKey;
113
+ }
95
114
  function collectVisibleSelectorOwners(registry, visible) {
96
115
  const ownerGroupByExtension = new Map();
97
116
  const selectorFeatures = new Set();
@@ -141,6 +160,9 @@ function planSelectorGating(registry, visible, declaredSecrets, secretsEnabled)
141
160
  const secretQns = new Set();
142
161
  for (const [extension, ownerGroup] of [...ownerGroupByExtension].sort(([a], [b]) => a.localeCompare(b))) {
143
162
  const usages = [...registry.getExtensionUsages(extension)].sort((a, b) => (a.featureName ?? "").localeCompare(b.featureName ?? ""));
163
+ const selectorQn = registry.getAllExtensionSelectors().get(extension);
164
+ if (selectorQn === undefined)
165
+ continue;
144
166
  for (const usage of usages) {
145
167
  if (usage.featureName === undefined)
146
168
  continue;
@@ -148,11 +170,22 @@ function planSelectorGating(registry, visible, declaredSecrets, secretsEnabled)
148
170
  if (usageCountByFeature.get(feature) !== 1 || selectorFeatures.has(feature))
149
171
  continue;
150
172
  const scopedKeys = visible.filter((v) => v.key.ownerFeature === feature);
151
- const secrets = secretsEnabled ? declaredSecrets.filter((s) => s.feature === feature) : [];
173
+ // The provider form has no per-field access gate, so a secret with its own write
174
+ // roles stays on the secrets screen, which enforces them.
175
+ const secrets = secretsEnabled
176
+ ? declaredSecrets.filter((s) => s.feature === feature && s.def.writeRoles === undefined)
177
+ : [];
152
178
  if (scopedKeys.length === 0 && secrets.length === 0)
153
179
  continue;
154
180
  const plugins = pluginsByOwnerGroup.get(ownerGroup) ?? [];
155
- plugins.push({ feature, extension, pluginId: usage.entityName, scopedKeys, secrets });
181
+ plugins.push({
182
+ feature,
183
+ extension,
184
+ selectorQn,
185
+ pluginId: usage.entityName,
186
+ scopedKeys,
187
+ secrets,
188
+ });
156
189
  pluginsByOwnerGroup.set(ownerGroup, plugins);
157
190
  pluginFeatures.add(feature);
158
191
  for (const s of secrets)
@@ -204,9 +237,6 @@ function buildFeatureScreensAndNavs(scope, visible, hub, gating, secretsAccess)
204
237
  }
205
238
  return out;
206
239
  }
207
- function pluginTenantScreenId(plugin) {
208
- return `${plugin.feature}-tenant`;
209
- }
210
240
  function assertUniquePanelIds(ownerGroup, panels) {
211
241
  const seen = new Set();
212
242
  for (const panel of panels) {
@@ -218,63 +248,38 @@ function assertUniquePanelIds(ownerGroup, panels) {
218
248
  }
219
249
  return panels;
220
250
  }
221
- // Plugin screens keep their `${F}-tenant` ids so consumer title keys stay valid;
222
- // they are dormant because only this dashboard embeds them.
251
+ // One form for the provider and the settings of every provider: a single save writes
252
+ // all of it, so switching sections can't drop typed input. Each plugin's fields are
253
+ // shown only while its provider is picked in the form; hidden fields are not saved.
223
254
  function buildSelectorOwnerDashboard(ownerGroup, ownerKeys, ownerAccess, plugins, ownerPanels, hub, secretsAccess) {
224
255
  const selectionScreenId = `${ownerGroup}-tenant-selection`;
225
- const selectionScreen = {
226
- ...buildScreen(selectionScreenId, "tenant", ownerGroup, ownerKeys, ownerAccess, hub, {
227
- description: EXTENSION_SELECTOR_HINT_KEY,
228
- sectionTitle: PROVIDER_SECTION_TITLE_KEY,
229
- submitLabel: SAVE_PROVIDER_LABEL_KEY,
230
- }),
231
- dormant: true,
232
- };
233
- const screens = [selectionScreen];
234
- const configPanels = [];
235
- const secretsPanels = [];
256
+ const form = new ProviderFormBuilder(selectionScreenId, buildScreen(selectionScreenId, "tenant", ownerGroup, ownerKeys, ownerAccess, hub, {
257
+ description: EXTENSION_SELECTOR_HINT_KEY,
258
+ sectionTitle: PROVIDER_SECTION_TITLE_KEY,
259
+ }));
236
260
  const accessRules = [ownerAccess];
237
261
  const translations = {};
238
262
  translations[`screen:${selectionScreenId}.title`] = PROVIDER_PANEL_TITLE_ENTRY;
239
- Object.assign(translations, providerOptionTranslations(selectionScreen, plugins, hub));
263
+ Object.assign(translations, providerOptionTranslations(form.base, hub));
240
264
  for (const plugin of plugins) {
241
- const visibleWhen = {
242
- query: SELECTED_EXTENSIONS_QUERY,
243
- field: plugin.extension,
244
- eq: plugin.pluginId,
245
- };
265
+ const providerFieldId = form.fieldIdOfConfigKey(plugin.selectorQn);
266
+ const visible = { field: providerFieldId, eq: plugin.pluginId };
267
+ let pluginSection;
246
268
  if (plugin.scopedKeys.length > 0) {
247
269
  const pluginAccess = rolesToAccess(plugin.scopedKeys.flatMap((v) => v.roles));
248
- const ordered = sortByMaskOrder(plugin.scopedKeys.map((v) => v.key));
249
- screens.push({
250
- ...buildScreen(pluginTenantScreenId(plugin), "tenant", plugin.feature, ordered, pluginAccess, hub, { description: null }),
251
- dormant: true,
252
- });
270
+ const pluginScreen = buildScreen(`${plugin.feature}-tenant`, "tenant", plugin.feature, sortByMaskOrder(plugin.scopedKeys.map((v) => v.key)), pluginAccess, hub, { description: null, fieldIdOf: qualifiedFieldId });
271
+ pluginSection = form.addConfigFields(pluginScreen, visible);
253
272
  accessRules.push(pluginAccess);
254
- configPanels.push({
255
- kind: "screen",
256
- id: `${plugin.feature}-config`,
257
- screen: pluginTenantScreenId(plugin),
258
- visibleWhen,
259
- chromeless: true,
260
- });
261
273
  }
262
274
  if (plugin.secrets.length > 0) {
263
- const secretsScreenId = `${plugin.feature}-tenant-secrets`;
264
- const generated = buildSecretsEditScreen(secretsScreenId, plugin.secrets, secretsAccess, hub.declaredTranslationKeys);
265
- screens.push({ ...generated.screen, dormant: true });
275
+ const generated = buildSecretsEditScreen(`${plugin.feature}-tenant-secrets`, plugin.secrets, secretsAccess, hub.declaredTranslationKeys);
276
+ form.addSecretFields(generated.screen, plugin.feature, visible, pluginSection);
266
277
  Object.assign(translations, generated.translations);
267
278
  accessRules.push(secretsAccess);
268
- secretsPanels.push({
269
- kind: "screen",
270
- id: `${plugin.feature}-secrets`,
271
- screen: secretsScreenId,
272
- visibleWhen,
273
- chromeless: true,
274
- });
275
279
  }
276
280
  }
277
281
  const access = unionAccessRules(accessRules);
282
+ const selectionScreen = { ...form.build(access), dormant: true };
278
283
  const dashboard = {
279
284
  id: `${ownerGroup}-tenant`,
280
285
  type: "dashboard",
@@ -282,16 +287,136 @@ function buildSelectorOwnerDashboard(ownerGroup, ownerKeys, ownerAccess, plugins
282
287
  panels: assertUniquePanelIds(ownerGroup, [
283
288
  { kind: "screen", id: "selection", screen: selectionScreenId, chromeless: true },
284
289
  ...ownerPanels,
285
- ...configPanels,
286
- ...secretsPanels,
287
290
  ]),
288
291
  access,
289
292
  };
290
- return { screens: [dashboard, ...screens], access, translations };
293
+ return { screens: [dashboard, selectionScreen], access, translations };
294
+ }
295
+ // A plugin key keeps its feature in the field id: the provider form holds the keys of
296
+ // several features side by side.
297
+ function qualifiedFieldId(k) {
298
+ return `${k.ownerFeature}-${k.shortKey}`;
299
+ }
300
+ class ProviderFormBuilder {
301
+ screenId;
302
+ base;
303
+ configKeys;
304
+ secretKeys = {};
305
+ fields;
306
+ fieldLabels;
307
+ fieldDescriptions;
308
+ requiredFields;
309
+ sections;
310
+ constructor(screenId, base) {
311
+ this.screenId = screenId;
312
+ this.base = base;
313
+ this.configKeys = { ...base.configKeys };
314
+ this.fields = { ...base.fields };
315
+ this.fieldLabels = { ...base.fieldLabels };
316
+ this.fieldDescriptions = { ...base.fieldDescriptions };
317
+ this.requiredFields = [...(base.requiredFields ?? [])];
318
+ this.sections = base.layout.sections.filter(isFieldsEditSection);
319
+ }
320
+ fieldIdOfConfigKey(qn) {
321
+ const entry = Object.entries(this.base.configKeys).find(([, keyQn]) => keyQn === qn);
322
+ if (entry === undefined) {
323
+ throw new Error(`[Settings-Hub] selector key "${qn}" is not on "${this.screenId}".`);
324
+ }
325
+ return entry[0];
326
+ }
327
+ addConfigFields(pluginScreen, visible) {
328
+ for (const [id, qn] of Object.entries(pluginScreen.configKeys)) {
329
+ this.claim(id, qn);
330
+ this.configKeys[id] = qn;
331
+ const field = pluginScreen.fields[id];
332
+ if (field !== undefined)
333
+ this.fields[id] = field;
334
+ }
335
+ Object.assign(this.fieldLabels, pluginScreen.fieldLabels);
336
+ Object.assign(this.fieldDescriptions, pluginScreen.fieldDescriptions);
337
+ this.requiredFields.push(...(pluginScreen.requiredFields ?? []));
338
+ const section = pluginScreen.layout.sections.find(isFieldsEditSection);
339
+ if (section === undefined)
340
+ return undefined;
341
+ const { groups: _groups, ...flatSection } = section;
342
+ const gated = {
343
+ ...flatSection,
344
+ fields: gateFields(sectionFieldSpecs(section), visible),
345
+ };
346
+ this.sections.push(gated);
347
+ return gated;
348
+ }
349
+ // A plugin's sign-in data gets its own section when the plugin names one, else it
350
+ // continues the plugin's settings section.
351
+ addSecretFields(secretsScreen, feature, visible, pluginSection) {
352
+ for (const [id, qn] of Object.entries(secretsScreen.secretKeys)) {
353
+ this.claim(id, qn);
354
+ this.secretKeys[id] = qn;
355
+ this.fields[id] = createTextField({
356
+ personal: false,
357
+ reason: "system_metadata",
358
+ writeOnly: true,
359
+ });
360
+ }
361
+ Object.assign(this.fieldLabels, secretsScreen.fieldLabels);
362
+ Object.assign(this.fieldDescriptions, secretsScreen.fieldHints);
363
+ this.requiredFields.push(...(secretsScreen.requiredFields ?? []));
364
+ const secretsTitleKey = `${feature}.settings.secrets`;
365
+ for (const section of secretsScreen.sections) {
366
+ // kumiko-lint-ignore section-fields-raw a secretsEdit section is a flat key list without groups
367
+ const fields = gateFields(section.fields, visible);
368
+ const ownSection = section.title === secretsTitleKey || pluginSection === undefined;
369
+ if (ownSection) {
370
+ this.sections.push({
371
+ title: section.title ?? `${feature}.settings`,
372
+ description: SECRETS_SECTION_DESCRIPTION_KEY,
373
+ fields,
374
+ });
375
+ continue;
376
+ }
377
+ const index = this.sections.indexOf(pluginSection);
378
+ this.sections[index] = {
379
+ ...pluginSection,
380
+ fields: [...sectionFieldSpecs(pluginSection), ...fields],
381
+ };
382
+ }
383
+ }
384
+ build(access) {
385
+ const { fieldDescriptions: _baseDescriptions, requiredFields: _baseRequired, ...base } = this.base;
386
+ return {
387
+ ...base,
388
+ configKeys: this.configKeys,
389
+ ...(Object.keys(this.secretKeys).length > 0 && { secretKeys: this.secretKeys }),
390
+ fields: this.fields,
391
+ fieldLabels: this.fieldLabels,
392
+ ...(Object.keys(this.fieldDescriptions).length > 0 && {
393
+ fieldDescriptions: this.fieldDescriptions,
394
+ }),
395
+ ...(this.requiredFields.length > 0 && { requiredFields: this.requiredFields }),
396
+ layout: { ...base.layout, sections: this.sections },
397
+ access,
398
+ };
399
+ }
400
+ claim(id, qn) {
401
+ const previous = this.configKeys[id] ?? this.secretKeys[id];
402
+ if (previous !== undefined) {
403
+ throw new Error(`[Settings-Hub] "${previous}" and "${qn}" both resolve to field id "${id}" on "${this.screenId}" — rename one key.`);
404
+ }
405
+ }
406
+ }
407
+ function gateFields(fields, visible) {
408
+ return fields.map((spec) => typeof spec === "string" ? { field: spec, visible } : { ...spec, visible });
291
409
  }
292
410
  // Everything generated for one audience scope: the audience-parent nav, the
293
411
  // per-feature configEdit screens+navs, and (tenant-scope only, when secrets
294
412
  // are enabled) the secrets screen. Null when nothing is visible at this scope.
413
+ // The secrets set handler also admits the machine role for server-side writes; like the
414
+ // config keys' write roles, that role must not reach a screen or nav access gate.
415
+ function withoutMachineRole(rule) {
416
+ if (rule === undefined || !("roles" in rule))
417
+ return rule;
418
+ return { ...rule, roles: rule.roles.filter((role) => role !== MACHINE_WRITE_ROLE) };
419
+ }
295
420
  function buildScopeResult(scope, masked, secretsEnabled, secretsWriteHandler, declaredSecrets, hub, registry) {
296
421
  const visible = scopedKeysAt(masked, scope);
297
422
  // Secrets attach to the tenant-audience nav regardless of whether any
@@ -300,7 +425,7 @@ function buildScopeResult(scope, masked, secretsEnabled, secretsWriteHandler, de
300
425
  if (visible.length === 0 && !includeSecrets)
301
426
  return null;
302
427
  const configAccess = rolesToAccess(visible.flatMap((v) => v.roles));
303
- const secretsAccess = secretsWriteHandler?.access;
428
+ const secretsAccess = withoutMachineRole(secretsWriteHandler?.access);
304
429
  const gating = scope === "tenant"
305
430
  ? planSelectorGating(registry, visible, declaredSecrets, secretsEnabled)
306
431
  : NO_SELECTOR_GATING;
@@ -346,6 +471,7 @@ export function buildConfigFeatureSchema(registry) {
346
471
  const hub = {
347
472
  declaredTranslationKeys: new Set(translationsByKey.keys()),
348
473
  selectorOptions: collectSelectorOptions(registry),
474
+ selectorOptionFeatures: collectSelectorOptionFeatures(registry),
349
475
  translationsByKey,
350
476
  };
351
477
  const screens = [];
@@ -440,7 +566,12 @@ function buildSecretsEditScreen(screenId, secrets, access, declaredTranslationKe
440
566
  if (s.def.writeRoles !== undefined)
441
567
  fieldAccess[fieldId] = { roles: [...s.def.writeRoles] };
442
568
  }
443
- const titleKey = `${feature}.settings`;
569
+ // Opt-in `${feature}.settings.secrets`: in a selector dashboard this section sits right
570
+ // under the plugin's own settings section, which already carries `${feature}.settings`.
571
+ const secretsTitleKey = `${feature}.settings.secrets`;
572
+ const titleKey = declaredTranslationKeys.has(secretsTitleKey)
573
+ ? secretsTitleKey
574
+ : `${feature}.settings`;
444
575
  sections.push({
445
576
  ...(declaredTranslationKeys.has(titleKey) && { title: titleKey }),
446
577
  fields: fieldIds,
@@ -514,7 +645,8 @@ function buildScreen(shortId, scope, feature, keys, access, hub, options = {}) {
514
645
  // feature's group (100% of today's apps — byte-identical output). Only a
515
646
  // cross-feature `group` (feature !== ownerFeature) needs the owner prefix,
516
647
  // to keep two features sharing a group from clobbering the same shortKey.
517
- const fieldId = (k) => k.feature === k.ownerFeature ? k.shortKey : `${k.ownerFeature}-${k.shortKey}`;
648
+ const fieldId = options.fieldIdOf ??
649
+ ((k) => (k.feature === k.ownerFeature ? k.shortKey : qualifiedFieldId(k)));
518
650
  const seenFieldIds = new Map();
519
651
  for (const k of keys) {
520
652
  const id = fieldId(k);
@@ -544,7 +676,6 @@ function buildScreen(shortId, scope, feature, keys, access, hub, options = {}) {
544
676
  ...(Object.keys(fieldDescriptions).length > 0 && { fieldDescriptions }),
545
677
  ...(requiredFields.length > 0 && { requiredFields }),
546
678
  ...(screenDescription !== undefined && { description: screenDescription }),
547
- ...(options.submitLabel !== undefined && { submitLabel: options.submitLabel }),
548
679
  layout: { sections: [section], width: "full", variant: "settings-list" },
549
680
  access,
550
681
  };
@@ -589,16 +720,17 @@ function buildSettingsSection(feature, scope, fieldIds, hub, options) {
589
720
  }
590
721
  // Option labels of the provider select: each plugin feature's `<feature>.settings`
591
722
  // copy, under the option-label key the configEdit renderer already derives.
592
- function providerOptionTranslations(selectionScreen, plugins, hub) {
723
+ function providerOptionTranslations(selectionScreen, hub) {
593
724
  const out = {};
594
725
  for (const [fieldId, qn] of Object.entries(selectionScreen.configKeys)) {
595
- if (!hub.selectorOptions.has(qn))
726
+ const featureByPluginId = hub.selectorOptionFeatures.get(qn);
727
+ if (featureByPluginId === undefined)
596
728
  continue;
597
- for (const plugin of plugins) {
598
- const label = hub.translationsByKey.get(`${plugin.feature}.settings`);
729
+ for (const [pluginId, feature] of featureByPluginId) {
730
+ const label = hub.translationsByKey.get(`${feature}.settings`);
599
731
  if (label === undefined)
600
732
  continue;
601
- const key = `${fieldLabelKey(SETTINGS_HUB_FEATURE, CONFIG_EDIT_ENTITY, fieldId)}:option:${plugin.pluginId}`;
733
+ const key = `${fieldLabelKey(SETTINGS_HUB_FEATURE, CONFIG_EDIT_ENTITY, fieldId)}:option:${pluginId}`;
602
734
  out[key] = label;
603
735
  }
604
736
  }
@@ -1,5 +1,5 @@
1
- import type { TargetRef } from "./types/target-ref.js";
2
- import type { TreeActionDef } from "./types/tree-node.js";
1
+ import type { TargetRef } from "./types/target-ref.ts";
2
+ import type { TreeActionDef } from "./types/tree-node.ts";
3
3
  type FeatureWithTreeActions<TActions extends Record<string, TreeActionDef>> = {
4
4
  readonly id: string;
5
5
  readonly treeActions: TActions;
@@ -1,4 +1,4 @@
1
- import { type ChangelogType } from "./feature-changelog.js";
1
+ import { type ChangelogType } from "./feature-changelog.ts";
2
2
  export type PendingChange = {
3
3
  readonly feature: string;
4
4
  readonly type: ChangelogType;
@@ -1,2 +1,2 @@
1
- export type { CodemodOptions, CodemodReport, CodemodResult, FileAnalysis, ParsedHandlerInfo, } from "./pipeline-codemod.js";
2
- export { analyzeFile, analyzeHandlerArrow, convertFile, generatePerformBlock, runCodemod, scanForCandidates, } from "./pipeline-codemod.js";
1
+ export type { CodemodOptions, CodemodReport, CodemodResult, FileAnalysis, ParsedHandlerInfo, } from "./pipeline-codemod.ts";
2
+ export { analyzeFile, analyzeHandlerArrow, convertFile, generatePerformBlock, runCodemod, scanForCandidates, } from "./pipeline-codemod.ts";
@@ -1,4 +1,4 @@
1
- import type { ConfigBacking, ConfigBounds, ConfigComputedFn, ConfigKeyDefinition, ConfigKeyType, ConfigMask, ConfigSeedDef, ConfigValidateFn, ConfigValue, CreateSeedOptions, CreateTenantSeedOptions, CreateUserSeedOptions, OptionsQueryPayload } from "./types/index.js";
1
+ import type { ConfigBacking, ConfigBounds, ConfigComputedFn, ConfigKeyDefinition, ConfigKeyType, ConfigMask, ConfigSeedDef, ConfigValidateFn, ConfigValue, CreateSeedOptions, CreateTenantSeedOptions, CreateUserSeedOptions, OptionsQueryPayload } from "./types/index.ts";
2
2
  export declare function isEncryptedAtRest(def: Pick<ConfigKeyDefinition, "encrypted" | "backing">): boolean;
3
3
  export declare const access: {
4
4
  readonly all: readonly string[];
@@ -1,7 +1,7 @@
1
1
  import type { ConcurrencyMode } from "@cosmicdrift/kumiko-types/concurrency-mode";
2
2
  import type { ConfigScope } from "@cosmicdrift/kumiko-types/config-scope";
3
3
  import type { OnDeleteStrategy as OnDeleteStrategyType } from "@cosmicdrift/kumiko-types/relations";
4
- import type { TenantId } from "./types/identifiers.js";
4
+ import type { TenantId } from "./types/identifiers.ts";
5
5
  export declare const SystemHookNames: {
6
6
  readonly cascadeDelete: "system:hook:cascade-delete";
7
7
  };
@@ -1,5 +1,5 @@
1
- import { type ValidateBootOptions } from "./boot-validator.js";
2
- import type { FeatureDefinition, Registry } from "./types/index.js";
1
+ import { type ValidateBootOptions } from "./boot-validator.ts";
2
+ import type { FeatureDefinition, Registry } from "./types/index.ts";
3
3
  export type AppConfig = {
4
4
  roles: readonly string[];
5
5
  features: readonly FeatureDefinition[];
@@ -1,4 +1,4 @@
1
- import { AccessDeniedError } from "../errors/index.js";
2
- import type { SessionUser } from "./types/index.js";
1
+ import { AccessDeniedError } from "../errors/index.ts";
2
+ import type { SessionUser } from "./types/index.ts";
3
3
  export declare function mayOverrideTenant(user: SessionUser): boolean;
4
4
  export declare function tenantOverrideDenied(user: SessionUser, parsedPayload: unknown): AccessDeniedError | undefined;
@@ -1,2 +1,2 @@
1
- import type { FeatureDefinition } from "./types/index.js";
1
+ import type { FeatureDefinition } from "./types/index.ts";
2
2
  export declare function dedupeFeatures(features: readonly FeatureDefinition[]): FeatureDefinition[];
@@ -1,4 +1,4 @@
1
- import type { FeatureDefinition, FeatureRegistrar } from "./types/index.js";
1
+ import type { FeatureDefinition, FeatureRegistrar } from "./types/index.ts";
2
2
  export type DefineFeatureSettings = {
3
3
  readonly dedupeOptions?: Readonly<Record<string, unknown>>;
4
4
  };
@@ -2,7 +2,7 @@ import { createInitialFeatureBuilderState } from "./feature-builder-state.js";
2
2
  import { buildConfigEventsJobsMethods } from "./feature-config-events-jobs.js";
3
3
  import { buildEntityHandlerMethods } from "./feature-entity-handlers.js";
4
4
  import { buildUiExtensionsMethods } from "./feature-ui-extensions.js";
5
- import { isObjectArgument, throwPositionalFormRemoved, unwrapArrayForm } from "./object-form.js";
5
+ import { isObjectArgument, throwObjectArgumentRequired, unwrapArrayForm } from "./object-form.js";
6
6
  // `TExports` lets the setup callback hand back a typed object that
7
7
  // downstream features can import (e.g. `tenantFeature.exports.config`). The
8
8
  // runtime always packs whatever setup returns into `featureDef.exports` —
@@ -49,7 +49,7 @@ export function defineFeature(name, setup, settings) {
49
49
  requires: (() => {
50
50
  const fn = (...args) => {
51
51
  if (!args.every(isObjectArgument))
52
- throwPositionalFormRemoved(name, "requires");
52
+ throwObjectArgumentRequired(name, "requires");
53
53
  state.requires.push(...resolveFeatureNamesArgs(args));
54
54
  };
55
55
  fn.projection = (tableName) => {
@@ -1,9 +1,9 @@
1
1
  import type { CursorResult } from "@cosmicdrift/kumiko-types/cursor-types";
2
2
  import type { ZodType } from "zod";
3
- import type { ContainsSecret } from "../secrets/types.js";
4
- import type { QueryHandlerDefinition, WriteHandlerDefinition, WriteHandlerInput } from "./types/define-handler.js";
5
- import type { KumikoEventTypeMap } from "./types/index.js";
6
- export type { QueryHandlerDefinition, StreamHandlerDefinition, WriteHandlerDefinition, WriteHandlerInput, } from "./types/define-handler.js";
3
+ import type { ContainsSecret } from "../secrets/types.ts";
4
+ import type { QueryHandlerDefinition, WriteHandlerDefinition, WriteHandlerInput } from "./types/define-handler.ts";
5
+ import type { KumikoEventTypeMap } from "./types/index.ts";
6
+ export type { QueryHandlerDefinition, StreamHandlerDefinition, WriteHandlerDefinition, WriteHandlerInput, } from "./types/define-handler.ts";
7
7
  export declare function defineWriteHandler<const TName extends string, TSchema extends ZodType, TData = unknown, TMap extends object = KumikoEventTypeMap, TPrepared = undefined>(def: WriteHandlerInput<TName, TSchema, TData, TMap, TPrepared>, ..._noSecretInResponse: true extends ContainsSecret<TData> ? [
8
8
  secretLeak: "A handler response must not contain a Secret<> — call .reveal() and return the plaintext, or drop the field."
9
9
  ] : []): WriteHandlerDefinition<TName, TSchema, TData, TMap, TPrepared>;
@@ -1,4 +1,4 @@
1
- import type { StepDef, StepKind } from "./types/step.js";
1
+ import type { StepDef, StepKind } from "./types/step.ts";
2
2
  export declare function defineStep<TArgs, TResult>(def: StepDef<TArgs, TResult>): StepDef<TArgs, TResult>;
3
3
  export declare function getStep(kind: StepKind): StepDef | undefined;
4
4
  export declare function listStepKinds(): readonly StepKind[];
@@ -1,5 +1,5 @@
1
- import type { WriteEvent } from "./types/handlers.js";
2
- import type { AwaitedEventType, PipelineDef } from "./types/step.js";
1
+ import type { WriteEvent } from "./types/handlers.ts";
2
+ import type { AwaitedEventType, PipelineDef } from "./types/step.ts";
3
3
  /**
4
4
  * Trigger configuration for a workflow. Determines what starts a run.
5
5
  */
@@ -1,4 +1,4 @@
1
- import type { FeatureDefinition, Registry } from "./types/index.js";
1
+ import type { FeatureDefinition, Registry } from "./types/index.ts";
2
2
  export type ToggleReader = (featureName: string) => boolean | undefined;
3
3
  export declare function isToggleableFeature(feature: FeatureDefinition): feature is FeatureDefinition & {
4
4
  toggleableDefault: boolean;
@@ -1,4 +1,4 @@
1
- import type { EmbeddedDerivedCellDef, EmbeddedSubFieldDef } from "./types/index.js";
1
+ import type { EmbeddedDerivedCellDef, EmbeddedSubFieldDef } from "./types/index.ts";
2
2
  /** Computes a derived cell from its source values. Missing/non-numeric
3
3
  * sources: "multiply" with any missing source → undefined; "sum"/"subtract"
4
4
  * treat missing as 0 only when at least one source is present — if every
@@ -1,9 +1,10 @@
1
1
  import * as z from "zod";
2
- import { type EventStoreExecutor } from "../db/event-store-executor.js";
3
- import { type EntityTable } from "../db/table-builder.js";
4
- import type { EntityCrudRegistrar, EntityHandlerOptions, EntityQueryHandlerOptions, EntityWriteHandlerOptions, RegisterEntityCrudOptions } from "./types/entity-handlers.js";
5
- import type { AccessRule, EntityDefinition, EscapeHatchDeclaration, QueryHandlerDef, WriteHandlerDef } from "./types/index.js";
6
- export type { EntityCrudHandlerDefaults, EntityCrudRegistrar, EntityCrudVerb, EntityHandlerOptions, EntityQueryHandlerOptions, EntityWriteHandlerOptions, RegisterEntityCrudOptions, } from "./types/entity-handlers.js";
2
+ import { type EventStoreExecutor } from "../db/event-store-executor.ts";
3
+ import { type EntityTable } from "../db/table-builder.ts";
4
+ import type { EntityCrudRegistrar, EntityHandlerOptions, EntityQueryHandlerOptions, EntityWriteHandlerOptions, RegisterEntityCrudOptions } from "./types/entity-handlers.ts";
5
+ import type { AccessRule, EntityDefinition, EscapeHatchDeclaration, QueryHandlerDef, WriteHandlerDef } from "./types/index.ts";
6
+ export type { EntityCrudHandlerDefaults, EntityCrudRegistrar, EntityCrudVerb, EntityHandlerOptions, EntityQueryHandlerOptions, EntityWriteHandlerOptions, RegisterEntityCrudOptions, } from "./types/entity-handlers.ts";
7
+ export declare function assertEscapeHatchAccessIsSystemAdminOnly(name: string, kind: "write" | "query", access: AccessRule): void;
7
8
  export declare const MAX_LIST_LIMIT = 200;
8
9
  export declare const entityListSchema: z.ZodObject<{
9
10
  cursor: z.ZodOptional<z.ZodString>;
@@ -66,11 +66,14 @@ function resolveCrossTenantReason(name, options, kind) {
66
66
  const placeholderProblem = codemodPlaceholderReasonProblem(options.escapeHatch.reason);
67
67
  if (placeholderProblem !== undefined)
68
68
  throw new Error(`"${name}": ${placeholderProblem}`);
69
- if (!isSystemAdminOnly(options.access)) {
70
- throw new Error(`"${name}": a ${kind} handler with escapeHatch reaches across every tenant, so its access must be SystemAdmin-only ({ roles: ["${SYSTEM_ADMIN_ROLE}"] }); got ${JSON.stringify(options.access)}.`);
71
- }
69
+ assertEscapeHatchAccessIsSystemAdminOnly(name, kind, options.access);
72
70
  return options.escapeHatch.reason;
73
71
  }
72
+ export function assertEscapeHatchAccessIsSystemAdminOnly(name, kind, access) {
73
+ if (!isSystemAdminOnly(access)) {
74
+ throw new Error(`"${name}": a ${kind} handler with escapeHatch reaches across every tenant, so its access must be SystemAdmin-only ({ roles: ["${SYSTEM_ADMIN_ROLE}"] }); got ${JSON.stringify(access)}.`);
75
+ }
76
+ }
74
77
  // Upper bound on entity-list `limit`: unbounded/fractional values ran
75
78
  // straight into the raw `LIMIT ${limit}` SQL string (event-store-executor-
76
79
  // read.ts), letting a client demand a full-table materialisation or trip a
@@ -0,0 +1,15 @@
1
+ import { type ZodType } from "zod";
2
+ import type { EventDef, EventPiiStance, QualifiedEventName } from "./types/index.ts";
3
+ export type CreateEventDefOptions<TFeature extends string, TInner extends string, TPayload> = {
4
+ readonly feature: TFeature;
5
+ readonly name: TInner;
6
+ readonly schema: ZodType<TPayload>;
7
+ readonly version?: number;
8
+ readonly piiFields: EventPiiStance;
9
+ };
10
+ /**
11
+ * The EventDef that `r.defineEvent` returns, built outside a feature's setup
12
+ * callback, so a module can hand the definition to `emitEvent` without the
13
+ * feature instance. Registration still goes through `r.defineEvent`.
14
+ */
15
+ export declare function createEventDef<const TFeature extends string, const TInner extends string, TPayload>(options: CreateEventDefOptions<TFeature, TInner, TPayload>): EventDef<TPayload, QualifiedEventName<TFeature, TInner>>;