@cosmicdrift/kumiko-framework 0.386.0 → 0.388.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (468) hide show
  1. package/AGENTS.md +6 -1
  2. package/LICENSE +21 -57
  3. package/README.md +2 -2
  4. package/agents/examples/anonymous-access.md +1 -1
  5. package/agents/examples/apex-landing.md +204 -0
  6. package/agents/examples/api-worker-split.md +64 -0
  7. package/agents/examples/app-config.md +14 -0
  8. package/agents/examples/auth-mfa.md +115 -0
  9. package/agents/examples/env-composition.md +28 -1
  10. package/agents/examples/legal-pages.md +1 -1
  11. package/agents/examples/prod-boot-options.md +16 -0
  12. package/agents/examples/rate-limiting.md +48 -0
  13. package/agents/examples/record-detail-layout.md +692 -0
  14. package/agents/examples/seed-migration.md +212 -0
  15. package/agents/examples/wizard-form.md +941 -0
  16. package/agents/examples/writeform-section.md +548 -0
  17. package/agents/features.md +19 -2
  18. package/agents/widgets.md +40 -39
  19. package/dist/api/api-constants.js +2 -2
  20. package/dist/api/auth-middleware.js +7 -7
  21. package/dist/api/auth-rate-limiters.js +7 -3
  22. package/dist/api/auth-routes-mfa.js +1 -1
  23. package/dist/api/auth-routes-session.js +1 -1
  24. package/dist/api/auth-routes-shared.js +7 -3
  25. package/dist/api/auth-routes-signup.js +1 -1
  26. package/dist/api/client-error-route.js +8 -2
  27. package/dist/api/client-ip.js +3 -1
  28. package/dist/api/extra-route.js +1 -1
  29. package/dist/api/index.d.ts +3 -1
  30. package/dist/api/index.js +3 -1
  31. package/dist/api/pii-leak-guard.js +4 -2
  32. package/dist/api/readiness.js +5 -5
  33. package/dist/api/redis-sse-broker.js +8 -6
  34. package/dist/api/request-context.d.ts +1 -1
  35. package/dist/api/request-context.js +1 -1
  36. package/dist/api/routes.js +2 -2
  37. package/dist/api/server-boot-checks.d.ts +10 -0
  38. package/dist/api/server-boot-checks.js +157 -0
  39. package/dist/api/server-event-dispatcher.d.ts +26 -0
  40. package/dist/api/server-event-dispatcher.js +208 -0
  41. package/dist/api/server-extra-routes.d.ts +11 -0
  42. package/dist/api/server-extra-routes.js +203 -0
  43. package/dist/api/server-middleware.d.ts +20 -0
  44. package/dist/api/server-middleware.js +211 -0
  45. package/dist/api/server-routes.d.ts +19 -0
  46. package/dist/api/server-routes.js +293 -0
  47. package/dist/api/server-websocket-routes.d.ts +4 -0
  48. package/dist/api/server-websocket-routes.js +108 -0
  49. package/dist/api/server-wiring.d.ts +32 -0
  50. package/dist/api/server-wiring.js +236 -0
  51. package/dist/api/server.d.ts +10 -15
  52. package/dist/api/server.js +48 -1250
  53. package/dist/api/session-cookies.js +4 -4
  54. package/dist/api/sse-broker.js +1 -1
  55. package/dist/api/sse-route.d.ts +13 -13
  56. package/dist/api/sse-route.js +31 -27
  57. package/dist/auth/index.js +4 -4
  58. package/dist/auth/roles.d.ts +4 -4
  59. package/dist/auth/roles.js +24 -24
  60. package/dist/compliance/duration-spec.js +18 -20
  61. package/dist/compliance/index.js +2 -3
  62. package/dist/compliance/override-schema.d.ts +4 -4
  63. package/dist/compliance/override-schema.js +19 -22
  64. package/dist/compliance/profiles.d.ts +26 -29
  65. package/dist/compliance/profiles.js +62 -69
  66. package/dist/compliance/sub-processors.d.ts +28 -30
  67. package/dist/compliance/sub-processors.js +17 -21
  68. package/dist/consumer-cli.js +4 -4
  69. package/dist/crypto/blind-index.js +18 -17
  70. package/dist/crypto/ciphertext-pattern.js +1 -1
  71. package/dist/crypto/event-pii.js +3 -3
  72. package/dist/crypto/kek-source.d.ts +1 -1
  73. package/dist/crypto/kek-source.js +3 -2
  74. package/dist/crypto/kms-adapter.d.ts +1 -1
  75. package/dist/crypto/kms-adapter.js +4 -6
  76. package/dist/crypto/kms-wiring.d.ts +1 -2
  77. package/dist/crypto/kms-wiring.js +2 -2
  78. package/dist/crypto/owner-transition-rekey.d.ts +5 -1
  79. package/dist/crypto/owner-transition-rekey.js +1 -1
  80. package/dist/crypto/pg-kms-adapter.js +2 -6
  81. package/dist/crypto/pii-field-encryption.d.ts +5 -1
  82. package/dist/crypto/pii-field-encryption.js +7 -5
  83. package/dist/crypto/subject-resolver.d.ts +1 -1
  84. package/dist/crypto/subject-resolver.js +2 -2
  85. package/dist/db/aggregate-sql.d.ts +21 -0
  86. package/dist/db/aggregate-sql.js +155 -0
  87. package/dist/db/apply-entity-event.d.ts +6 -6
  88. package/dist/db/apply-entity-event.js +55 -55
  89. package/dist/db/blind-index-cleanup.js +7 -7
  90. package/dist/db/closed-connection.d.ts +9 -0
  91. package/dist/db/closed-connection.js +95 -0
  92. package/dist/db/collect-table-metas.js +10 -11
  93. package/dist/db/compound-types.d.ts +1 -1
  94. package/dist/db/compound-types.js +12 -12
  95. package/dist/db/cursor.js +3 -4
  96. package/dist/db/dialect.d.ts +2 -2
  97. package/dist/db/dialect.js +3 -3
  98. package/dist/db/distinct-on.d.ts +1 -1
  99. package/dist/db/driver-row-coercion.d.ts +2 -0
  100. package/dist/db/driver-row-coercion.js +186 -0
  101. package/dist/db/driver-value-preparation.d.ts +16 -0
  102. package/dist/db/driver-value-preparation.js +99 -0
  103. package/dist/db/eagerload.d.ts +3 -3
  104. package/dist/db/eagerload.js +21 -12
  105. package/dist/db/entity-field-encryption.d.ts +1 -0
  106. package/dist/db/entity-field-encryption.js +1 -1
  107. package/dist/db/entity-table-meta.d.ts +2 -2
  108. package/dist/db/entity-table-meta.js +105 -112
  109. package/dist/db/event-store-executor-context.d.ts +3 -2
  110. package/dist/db/event-store-executor-context.js +13 -13
  111. package/dist/db/event-store-executor-read-aggregate.d.ts +8 -0
  112. package/dist/db/event-store-executor-read-aggregate.js +112 -0
  113. package/dist/db/event-store-executor-read-filter.d.ts +31 -0
  114. package/dist/db/event-store-executor-read-filter.js +203 -0
  115. package/dist/db/event-store-executor-read-paging.d.ts +14 -0
  116. package/dist/db/event-store-executor-read-paging.js +99 -0
  117. package/dist/db/event-store-executor-read-rows.d.ts +6 -0
  118. package/dist/db/event-store-executor-read-rows.js +32 -0
  119. package/dist/db/event-store-executor-read-search.d.ts +28 -0
  120. package/dist/db/event-store-executor-read-search.js +221 -0
  121. package/dist/db/event-store-executor-read-sort.d.ts +41 -0
  122. package/dist/db/event-store-executor-read-sort.js +130 -0
  123. package/dist/db/event-store-executor-read-where.d.ts +24 -0
  124. package/dist/db/event-store-executor-read-where.js +81 -0
  125. package/dist/db/event-store-executor-read.d.ts +2 -9
  126. package/dist/db/event-store-executor-read.js +50 -704
  127. package/dist/db/event-store-executor-write-steps.d.ts +20 -0
  128. package/dist/db/event-store-executor-write-steps.js +100 -0
  129. package/dist/db/event-store-executor-write.js +401 -510
  130. package/dist/db/index.d.ts +6 -2
  131. package/dist/db/index.js +5 -1
  132. package/dist/db/list-aggregate-labels.d.ts +14 -0
  133. package/dist/db/list-aggregate-labels.js +26 -0
  134. package/dist/db/located-timestamp.d.ts +11 -11
  135. package/dist/db/located-timestamp.js +29 -30
  136. package/dist/db/migrate-generator.d.ts +1 -1
  137. package/dist/db/migrate-generator.js +97 -105
  138. package/dist/db/migrate-runner.js +29 -26
  139. package/dist/db/money.d.ts +6 -6
  140. package/dist/db/money.js +29 -27
  141. package/dist/db/queries/backfill-pii.js +5 -5
  142. package/dist/db/queries/ddl.js +1 -1
  143. package/dist/db/queries/es-ops.d.ts +1 -1
  144. package/dist/db/queries/es-ops.js +1 -1
  145. package/dist/db/queries/event-consumer.js +3 -3
  146. package/dist/db/queries/event-store.js +4 -2
  147. package/dist/db/queries/projection-rebuild.js +3 -3
  148. package/dist/db/queries/raw-sql.d.ts +2 -2
  149. package/dist/db/queries/raw-sql.js +2 -2
  150. package/dist/db/queries/shadow-swap.js +19 -19
  151. package/dist/db/query.d.ts +3 -16
  152. package/dist/db/query.js +8 -761
  153. package/dist/db/rebuild-marker.js +20 -21
  154. package/dist/db/reference-data.js +6 -1
  155. package/dist/db/replay-migration-sql.js +2 -2
  156. package/dist/db/schema-inspection.js +4 -5
  157. package/dist/db/table-builder.d.ts +1 -2
  158. package/dist/db/table-builder.js +137 -190
  159. package/dist/db/table-info.d.ts +10 -0
  160. package/dist/db/table-info.js +45 -0
  161. package/dist/db/temporal-value-guards.d.ts +6 -0
  162. package/dist/db/temporal-value-guards.js +15 -0
  163. package/dist/db/tenant-db-runner.d.ts +1 -0
  164. package/dist/db/tenant-db-runner.js +3 -0
  165. package/dist/db/tenant-db.d.ts +2 -2
  166. package/dist/db/tenant-db.js +48 -11
  167. package/dist/db/where-clause.d.ts +6 -0
  168. package/dist/db/where-clause.js +236 -0
  169. package/dist/derivatives/delete-stored-file.js +6 -2
  170. package/dist/derivatives/derivatives-context.js +1 -1
  171. package/dist/engine/boot-validator/access-roles.js +4 -3
  172. package/dist/engine/boot-validator/api-ext.js +14 -14
  173. package/dist/engine/boot-validator/boot-check.js +1 -1
  174. package/dist/engine/boot-validator/config-deps.js +7 -6
  175. package/dist/engine/boot-validator/detail-screens.js +4 -4
  176. package/dist/engine/boot-validator/entity-handler.d.ts +1 -0
  177. package/dist/engine/boot-validator/entity-handler.js +77 -61
  178. package/dist/engine/boot-validator/form-derivations.js +35 -1
  179. package/dist/engine/boot-validator/gdpr-storage.js +4 -4
  180. package/dist/engine/boot-validator/i18n-keys.js +6 -4
  181. package/dist/engine/boot-validator/index.d.ts +2 -2
  182. package/dist/engine/boot-validator/index.js +22 -20
  183. package/dist/engine/boot-validator/nav.js +5 -5
  184. package/dist/engine/boot-validator/ownership.js +12 -9
  185. package/dist/engine/boot-validator/parent-ref.js +1 -1
  186. package/dist/engine/boot-validator/pii-retention.js +258 -187
  187. package/dist/engine/boot-validator/projection-list-screens.js +7 -7
  188. package/dist/engine/boot-validator/query-refs.js +1 -1
  189. package/dist/engine/boot-validator/screens-actions.d.ts +1 -0
  190. package/dist/engine/boot-validator/screens-actions.js +23 -17
  191. package/dist/engine/boot-validator/screens-dashboard.js +2 -5
  192. package/dist/engine/boot-validator/screens-forms.js +12 -17
  193. package/dist/engine/boot-validator/screens-kind-config-edit.d.ts +3 -0
  194. package/dist/engine/boot-validator/screens-kind-config-edit.js +88 -0
  195. package/dist/engine/boot-validator/screens-kind-entity-edit.d.ts +3 -0
  196. package/dist/engine/boot-validator/screens-kind-entity-edit.js +55 -0
  197. package/dist/engine/boot-validator/screens-kind-entity-list.d.ts +3 -0
  198. package/dist/engine/boot-validator/screens-kind-entity-list.js +228 -0
  199. package/dist/engine/boot-validator/screens-kind-projection-detail.d.ts +3 -0
  200. package/dist/engine/boot-validator/screens-kind-projection-detail.js +235 -0
  201. package/dist/engine/boot-validator/screens-kind-projection-list.d.ts +3 -0
  202. package/dist/engine/boot-validator/screens-kind-projection-list.js +52 -0
  203. package/dist/engine/boot-validator/screens-kind-secret-mint.d.ts +3 -0
  204. package/dist/engine/boot-validator/screens-kind-secret-mint.js +28 -0
  205. package/dist/engine/boot-validator/screens-kind-shared.d.ts +37 -0
  206. package/dist/engine/boot-validator/screens-kind-shared.js +142 -0
  207. package/dist/engine/boot-validator/screens-lists.d.ts +2 -1
  208. package/dist/engine/boot-validator/screens-lists.js +26 -24
  209. package/dist/engine/boot-validator/screens.d.ts +0 -2
  210. package/dist/engine/boot-validator/screens.js +102 -869
  211. package/dist/engine/boot-validator/security-baseline.js +3 -2
  212. package/dist/engine/boot-validator/transfer-graph.js +2 -2
  213. package/dist/engine/boot-validator/workspaces.js +3 -3
  214. package/dist/engine/bridge-stub.js +3 -4
  215. package/dist/engine/build-app-schema.js +130 -170
  216. package/dist/engine/build-config-feature-schema.js +50 -50
  217. package/dist/engine/build-target.js +20 -23
  218. package/dist/engine/codemod/pipeline-codemod.js +20 -13
  219. package/dist/engine/config-helpers.js +4 -4
  220. package/dist/engine/constants.js +2 -2
  221. package/dist/engine/create-app.js +2 -2
  222. package/dist/engine/define-feature.js +21 -13
  223. package/dist/engine/define-handler.js +13 -11
  224. package/dist/engine/define-step.js +1 -1
  225. package/dist/engine/define-workflow.d.ts +5 -5
  226. package/dist/engine/define-workflow.js +6 -6
  227. package/dist/engine/entity-handlers.d.ts +13 -0
  228. package/dist/engine/entity-handlers.js +22 -34
  229. package/dist/engine/entity-list-runtime-options.d.ts +8 -0
  230. package/dist/engine/entity-list-runtime-options.js +18 -0
  231. package/dist/engine/event-def.js +2 -2
  232. package/dist/engine/extension-names.d.ts +16 -17
  233. package/dist/engine/extension-names.js +37 -38
  234. package/dist/engine/extensions/escape-hatch-usage.js +1 -1
  235. package/dist/engine/extensions/tenant-data.js +2 -2
  236. package/dist/engine/extensions/user-data.d.ts +23 -24
  237. package/dist/engine/factories.d.ts +14 -13
  238. package/dist/engine/factories.js +38 -37
  239. package/dist/engine/feature-ast/entity-field-types.js +1 -1
  240. package/dist/engine/feature-ast/extractors/handlers.js +2 -1
  241. package/dist/engine/feature-ast/extractors/hooks.js +1 -1
  242. package/dist/engine/feature-ast/extractors/round2.js +25 -6
  243. package/dist/engine/feature-ast/extractors/shared.d.ts +2 -3
  244. package/dist/engine/feature-ast/extractors/shared.js +2 -3
  245. package/dist/engine/feature-ast/parse.js +13 -13
  246. package/dist/engine/feature-ast/patch.js +4 -182
  247. package/dist/engine/feature-ast/pattern-change-schema.d.ts +3 -0
  248. package/dist/engine/feature-ast/pattern-change-schema.js +2 -1
  249. package/dist/engine/feature-ast/pattern-id-matchers.d.ts +7 -0
  250. package/dist/engine/feature-ast/pattern-id-matchers.js +210 -0
  251. package/dist/engine/feature-ast/patterns.d.ts +11 -2
  252. package/dist/engine/feature-ast/patterns.js +43 -51
  253. package/dist/engine/feature-ast/render.js +50 -89
  254. package/dist/engine/feature-config-events-jobs.js +15 -12
  255. package/dist/engine/feature-entity-handlers.js +12 -5
  256. package/dist/engine/feature-manifest.d.ts +9 -9
  257. package/dist/engine/feature-manifest.js +6 -7
  258. package/dist/engine/feature-ui-extensions.d.ts +3 -3
  259. package/dist/engine/feature-ui-extensions.js +30 -22
  260. package/dist/engine/field-access.js +5 -6
  261. package/dist/engine/form-derivations.js +18 -7
  262. package/dist/engine/handler-field-references.js +1 -1
  263. package/dist/engine/index.d.ts +1 -0
  264. package/dist/engine/index.js +4 -4
  265. package/dist/engine/object-form.d.ts +1 -0
  266. package/dist/engine/object-form.js +14 -4
  267. package/dist/engine/ownership.js +3 -3
  268. package/dist/engine/parse-ref-target.js +5 -7
  269. package/dist/engine/pattern-library/index.js +2 -2
  270. package/dist/engine/pattern-library/library.js +2 -2
  271. package/dist/engine/pattern-library/types.js +3 -3
  272. package/dist/engine/pipeline.js +2 -2
  273. package/dist/engine/project-app-schema-for-roles.d.ts +2 -0
  274. package/dist/engine/project-app-schema-for-roles.js +7 -5
  275. package/dist/engine/projection-helpers.js +9 -9
  276. package/dist/engine/qualified-name.js +2 -2
  277. package/dist/engine/registry-facade.js +1 -1
  278. package/dist/engine/registry-ingest.js +13 -13
  279. package/dist/engine/registry-state.js +17 -19
  280. package/dist/engine/registry-validate.js +12 -12
  281. package/dist/engine/run-in.js +2 -2
  282. package/dist/engine/run-pipeline.js +7 -0
  283. package/dist/engine/schema-builder.js +251 -233
  284. package/dist/engine/screen-filter-ops.js +17 -20
  285. package/dist/engine/screen-helpers.js +4 -3
  286. package/dist/engine/screen-kind.d.ts +7 -0
  287. package/dist/engine/screen-kind.js +1 -0
  288. package/dist/engine/state-machine.d.ts +12 -12
  289. package/dist/engine/state-machine.js +7 -7
  290. package/dist/engine/steps/_resolver-utils.js +4 -3
  291. package/dist/engine/steps/for-each.js +4 -4
  292. package/dist/engine/steps/unsafe-projection-delete.js +1 -1
  293. package/dist/engine/steps/unsafe-projection-upsert.js +4 -4
  294. package/dist/engine/steps/wait-for-event.js +4 -4
  295. package/dist/engine/steps/workflow-system-events.js +3 -3
  296. package/dist/engine/strip-disabled-features-from-app-schema.js +51 -14
  297. package/dist/engine/tier-resolver-extension.d.ts +29 -27
  298. package/dist/engine/tier-resolver-extension.js +26 -26
  299. package/dist/engine/transfer-adjacency.js +2 -2
  300. package/dist/engine/validate-projection-allowlist.js +9 -28
  301. package/dist/engine/walk-step-instances.d.ts +2 -0
  302. package/dist/engine/walk-step-instances.js +38 -0
  303. package/dist/engine/where-rule-lint.js +1 -1
  304. package/dist/engine/write-handler-qn-extract.js +1 -1
  305. package/dist/entrypoint/index.d.ts +4 -1
  306. package/dist/entrypoint/index.js +10 -4
  307. package/dist/env/index.d.ts +7 -6
  308. package/dist/env/index.js +10 -9
  309. package/dist/errors/docs-url.d.ts +1 -1
  310. package/dist/errors/docs-url.js +22 -2
  311. package/dist/errors/transition-details.js +7 -7
  312. package/dist/errors/write-error-info.d.ts +6 -6
  313. package/dist/errors/write-error-info.js +6 -6
  314. package/dist/es-ops/context.d.ts +9 -9
  315. package/dist/es-ops/context.js +29 -29
  316. package/dist/es-ops/index.js +7 -9
  317. package/dist/es-ops/operations-schema.js +4 -10
  318. package/dist/es-ops/runner.d.ts +11 -11
  319. package/dist/es-ops/runner.js +49 -53
  320. package/dist/es-ops/types.d.ts +55 -55
  321. package/dist/es-ops/types.js +11 -11
  322. package/dist/event-store/admin-api.js +7 -8
  323. package/dist/event-store/errors.js +1 -1
  324. package/dist/event-store/event-store.js +12 -6
  325. package/dist/event-store/rebuild-dead-letter.js +1 -1
  326. package/dist/files/bind-pending-file-refs.js +3 -3
  327. package/dist/files/create-file-ref-from-bytes.js +4 -1
  328. package/dist/files/feature.js +9 -10
  329. package/dist/files/file-handle.js +7 -9
  330. package/dist/files/file-ref-entity.js +15 -15
  331. package/dist/files/file-ref-table.js +7 -8
  332. package/dist/files/file-routes.d.ts +7 -0
  333. package/dist/files/file-routes.js +22 -13
  334. package/dist/files/in-memory-provider.js +8 -9
  335. package/dist/files/local-provider.js +18 -25
  336. package/dist/files/provider-resolver.d.ts +7 -7
  337. package/dist/files/resolve-content-type.js +43 -0
  338. package/dist/files/storage-tracking.js +2 -2
  339. package/dist/files/upload-ledger.js +7 -0
  340. package/dist/files/zip-stream.d.ts +12 -19
  341. package/dist/files/zip-stream.js +44 -63
  342. package/dist/i18n/required-surface-keys.d.ts +1 -1
  343. package/dist/i18n/required-surface-keys.js +188 -212
  344. package/dist/internal/stack-support.d.ts +2 -1
  345. package/dist/internal/stack-support.js +1 -1
  346. package/dist/jobs/job-runner-context.d.ts +32 -0
  347. package/dist/jobs/job-runner-context.js +305 -0
  348. package/dist/jobs/job-runner-execution.d.ts +7 -0
  349. package/dist/jobs/job-runner-execution.js +160 -0
  350. package/dist/jobs/job-runner-gates.d.ts +19 -0
  351. package/dist/jobs/job-runner-gates.js +198 -0
  352. package/dist/jobs/job-runner-helpers.d.ts +17 -3
  353. package/dist/jobs/job-runner-helpers.js +69 -4
  354. package/dist/jobs/job-runner-schedulers.d.ts +1 -1
  355. package/dist/jobs/job-runner-schedulers.js +3 -4
  356. package/dist/jobs/job-runner-scope.d.ts +44 -0
  357. package/dist/jobs/job-runner-scope.js +102 -0
  358. package/dist/jobs/job-runner-types.d.ts +12 -0
  359. package/dist/jobs/job-runner.d.ts +0 -1
  360. package/dist/jobs/job-runner.js +57 -669
  361. package/dist/lifecycle/lifecycle.js +3 -5
  362. package/dist/lifecycle/signal-handlers.js +5 -4
  363. package/dist/logging/utils.d.ts +2 -1
  364. package/dist/logging/utils.js +38 -10
  365. package/dist/migrations/index.js +1 -1
  366. package/dist/migrations/kumiko-drift.js +14 -13
  367. package/dist/migrations/pending-rebuilds.d.ts +21 -20
  368. package/dist/migrations/pending-rebuilds.js +27 -27
  369. package/dist/migrations/projection-table-index.d.ts +3 -3
  370. package/dist/migrations/projection-table-index.js +8 -8
  371. package/dist/observability/escape-hatch-report.d.ts +3 -0
  372. package/dist/observability/escape-hatch-report.js +12 -1
  373. package/dist/observability/metric-validator.js +1 -1
  374. package/dist/observability/metrics-handle.js +3 -3
  375. package/dist/pipeline/append-event-core.js +11 -2
  376. package/dist/pipeline/cascade-handler.d.ts +1 -1
  377. package/dist/pipeline/cascade-handler.js +165 -138
  378. package/dist/pipeline/dispatch-batch.js +2 -2
  379. package/dist/pipeline/dispatch-query.js +20 -13
  380. package/dist/pipeline/dispatch-shared.d.ts +14 -3
  381. package/dist/pipeline/dispatch-shared.js +67 -721
  382. package/dist/pipeline/dispatch-stream.js +1 -1
  383. package/dist/pipeline/dispatch-write.js +297 -190
  384. package/dist/pipeline/dispatcher-utils.d.ts +1 -1
  385. package/dist/pipeline/dispatcher-utils.js +1 -1
  386. package/dist/pipeline/event-consumer-state.js +2 -2
  387. package/dist/pipeline/event-dispatcher-admin.js +2 -1
  388. package/dist/pipeline/event-dispatcher-delivery.js +4 -6
  389. package/dist/pipeline/event-dispatcher.js +17 -28
  390. package/dist/pipeline/handler-context-auth.d.ts +9 -0
  391. package/dist/pipeline/handler-context-auth.js +54 -0
  392. package/dist/pipeline/handler-context-config.d.ts +14 -0
  393. package/dist/pipeline/handler-context-config.js +113 -0
  394. package/dist/pipeline/handler-context-db.d.ts +24 -0
  395. package/dist/pipeline/handler-context-db.js +149 -0
  396. package/dist/pipeline/handler-context-dispatch.d.ts +21 -0
  397. package/dist/pipeline/handler-context-dispatch.js +89 -0
  398. package/dist/pipeline/handler-context-events.d.ts +43 -0
  399. package/dist/pipeline/handler-context-events.js +237 -0
  400. package/dist/pipeline/handler-context-notify.d.ts +12 -0
  401. package/dist/pipeline/handler-context-notify.js +55 -0
  402. package/dist/pipeline/handler-context-observability.d.ts +7 -0
  403. package/dist/pipeline/handler-context-observability.js +21 -0
  404. package/dist/pipeline/handler-context-scope.d.ts +48 -0
  405. package/dist/pipeline/handler-context-scope.js +88 -0
  406. package/dist/pipeline/irreversible-operation-gate.js +1 -1
  407. package/dist/pipeline/lifecycle-pipeline.js +9 -9
  408. package/dist/pipeline/member-read-only-transaction.js +1 -3
  409. package/dist/pipeline/msp-rebuild.js +1 -1
  410. package/dist/pipeline/notify-scope.js +12 -1
  411. package/dist/pipeline/pre-handler-gates.js +20 -4
  412. package/dist/pipeline/pre-transaction-reservations.d.ts +1 -0
  413. package/dist/pipeline/pre-transaction-reservations.js +9 -3
  414. package/dist/pipeline/projection-rebuild.js +15 -13
  415. package/dist/pipeline/system-hooks.js +39 -41
  416. package/dist/pipeline/system-identity-switch.js +1 -3
  417. package/dist/pipeline/tenant-timezone-cache.js +1 -1
  418. package/dist/random/generate.d.ts +29 -29
  419. package/dist/random/generate.js +30 -30
  420. package/dist/random/words.js +20 -20
  421. package/dist/rate-limit/middleware.js +9 -5
  422. package/dist/redis/client.js +2 -2
  423. package/dist/redis/pubsub-signal.js +14 -17
  424. package/dist/schema-cli/apply-command.d.ts +2 -0
  425. package/dist/schema-cli/apply-command.js +97 -0
  426. package/dist/schema-cli/baseline-command.d.ts +2 -0
  427. package/dist/schema-cli/baseline-command.js +33 -0
  428. package/dist/schema-cli/generate-command.d.ts +2 -0
  429. package/dist/schema-cli/generate-command.js +90 -0
  430. package/dist/schema-cli/shared.d.ts +39 -0
  431. package/dist/schema-cli/shared.js +95 -0
  432. package/dist/schema-cli/status-command.d.ts +2 -0
  433. package/dist/schema-cli/status-command.js +73 -0
  434. package/dist/schema-cli/validate-boot-input.d.ts +5 -0
  435. package/dist/schema-cli/validate-boot-input.js +130 -0
  436. package/dist/schema-cli/validate-command.d.ts +2 -0
  437. package/dist/schema-cli/validate-command.js +130 -0
  438. package/dist/schema-cli.d.ts +2 -18
  439. package/dist/schema-cli.js +47 -510
  440. package/dist/search/index.js +4 -4
  441. package/dist/search/meilisearch-adapter.js +2 -1
  442. package/dist/search/purge-subject.js +4 -5
  443. package/dist/search/reindex-entity.js +6 -9
  444. package/dist/time/boot-tz-warning.d.ts +2 -2
  445. package/dist/time/boot-tz-warning.js +8 -8
  446. package/dist/time/iana.js +10 -10
  447. package/dist/time/index.js +9 -9
  448. package/dist/time/legacy-date.d.ts +2 -2
  449. package/dist/time/legacy-date.js +6 -8
  450. package/dist/time/polyfill.js +1 -1
  451. package/dist/time/tz-context.d.ts +1 -1
  452. package/dist/time/tz-context.js +1 -1
  453. package/dist/ui-types/app-schema.js +7 -7
  454. package/dist/ui-types/list-row-meta.js +4 -4
  455. package/dist/upgrade-cli.js +159 -130
  456. package/dist/utils/compare.js +1 -1
  457. package/package.json +5 -5
  458. package/src/changes.json +358 -0
  459. package/src/scripts/codemod/crypto-shredding-testing-move.ts +2 -2
  460. package/src/scripts/codemod/feature-layout.ts +10 -2
  461. package/src/scripts/codemod/migrate-cross-tenant.ts +1 -1
  462. package/src/scripts/codemod/migrate-open-to-all.ts +1 -1
  463. package/src/scripts/codemod/object-form.ts +41 -4
  464. package/src/scripts/codemod/package-merge.ts +58 -8
  465. package/src/scripts/codemod/pii-personal-migration.ts +192 -153
  466. package/src/scripts/codemod/testing-injection.ts +122 -42
  467. package/src/scripts/codemod/testing-move.ts +29 -7
  468. package/src/scripts/codemod/unprocessable-error-details-reason.ts +2 -2
package/agents/widgets.md CHANGED
@@ -16,11 +16,12 @@ Value exports of `@cosmicdrift/kumiko-renderer/web`.
16
16
  | `BareFormProvider` | |
17
17
  | `BooleanField` | Checkbox/Switch = Field(layout:"inline") + Input(kind:"boolean"). |
18
18
  | `Card` | |
19
- | `CollapsibleSection` | Aufklappbare Sektion (native <details>, aber React-kontrolliert: sonst springt das open-Attribut bei jedem Parent-Re-Render auf den Initialwert zurück). |
20
- | `ComparisonTable` | Transponierte Vergleichstabelle: Zeile = Kennzahl, Spalte = Variante, je Kennzahl optional die beste Spalte hervorgehoben. |
21
- | `DateField` | Datumsfeld = Field + Input(kind:"date"), ISO yyyy-mm-dd. |
19
+ | `ChoiceCards` | Card-styled radio group for mutually exclusive choices that need a description or price line. |
20
+ | `CollapsibleSection` | Collapsible section using native <details> with React-controlled state; otherwise the open attribute resets to its initial value on every parent re-render. |
21
+ | `ComparisonTable` | Transposed comparison table: row = metric, column = variant, with the best column optionally highlighted for each metric. |
22
+ | `DateField` | Date field = Field + Input(kind:"date"), ISO yyyy-mm-dd. |
22
23
  | `DefaultAppShell` | |
23
- | `DetailList` | Read-only Schlüssel-Wert-Liste für Detail-Masken (Label links gedimmt, Wert rechts). |
24
+ | `DetailList` | Read-only key-value list for detail views (dimmed label on the left, value on the right). |
24
25
  | `DispatcherProvider` | |
25
26
  | `Drawer` | Slide-in panel beside a list (e.g. mail reader next to the inbox) — thin wrapper over the Sheet primitive with header/body/footer slots so screens skip per-route Radix boilerplate. |
26
27
  | `DropdownMenu` | |
@@ -32,10 +33,10 @@ Value exports of `@cosmicdrift/kumiko-renderer/web`.
32
33
  | `DropdownMenuSeparator` | |
33
34
  | `DropdownMenuTrigger` | |
34
35
  | `EditorPanel` | |
35
- | `EmptyState` | Leerer-Zustand mit optionalem Icon + CTA — die dashed-Box-Optik der entityList-Empty-States, als Standalone-Widget für Custom-Screens. |
36
- | `ErrorState` | Fehler-Zustand auf Basis des Banner-Primitives, mit Retry-Button. |
37
- | `FeedList` | Nicht-tabellarische Kurzliste (z.B. |
38
- | `FileField` | Datei-Upload = Field + Input(kind:"file"\|"image") — FileRef-basiert. |
36
+ | `EmptyState` | Empty state with an optional icon and CTA, using the dashed-box style of entityList empty states as a standalone widget for custom screens. |
37
+ | `ErrorState` | Error state based on the Banner primitive, with a retry button. |
38
+ | `FeedList` | Non-tabular compact list (e.g. "upcoming appointments") — primary text plus an optional right-aligned trailing value for each row. |
39
+ | `FileField` | File upload = Field + Input(kind:"file"\|"image"), based on FileRef. |
39
40
  | `FloatingPanel` | Non-modal panel floating above the page: draggable by its header, resizable from all edges and corners, clamped to the viewport, geometry optionally remembered. |
40
41
  | `FormScreenShell` | |
41
42
  | `HeaderActionGroup` | |
@@ -46,14 +47,14 @@ Value exports of `@cosmicdrift/kumiko-renderer/web`.
46
47
  | `LanguageMenuItems` | Locale choices as dropdown entries, for a user menu that carries the shell controls. |
47
48
  | `LanguageSwitcher` | |
48
49
  | `LiveEventsProvider` | |
49
- | `LoadingState` | Lade-Zustand: Skeleton-Zeilen in Card-Optik. |
50
+ | `LoadingState` | Loading state with skeleton rows styled like cards; `rows` controls the height. |
50
51
  | `LocaleProvider` | |
51
- | `MiniStat` | Kompakte Kennzahl-Kachel (ohne Icon) — für dichte KPI-Raster. |
52
- | `ModeSwitch` | Segmented-Control für sich ausschließende Modi — die prominente Alternative zum vergrabenen <select>. |
52
+ | `MiniStat` | Compact metric tile (without an icon) — for dense KPI grids. |
53
+ | `ModeSwitch` | Segmented control for mutually exclusive modes—the prominent alternative to the buried <select>. |
53
54
  | `MoneyField` | |
54
55
  | `NavProvider` | |
55
56
  | `NavTree` | |
56
- | `NumberField` | Zahlenfeld = Field + Input(kind:"number") in einem — nimmt der Screen die wiederholte id/name/value/onChange-Verdrahtung ab. |
57
+ | `NumberField` | Number field = Field + Input(kind:"number"); avoids repeating the id/name/value/onChange wiring at each screen. |
57
58
  | `PageSection` | |
58
59
  | `PdfPreview` | |
59
60
  | `PercentField` | |
@@ -64,22 +65,22 @@ Value exports of `@cosmicdrift/kumiko-renderer/web`.
64
65
  | `PrimitivesProvider` | |
65
66
  | `ProfileMenu` | |
66
67
  | `ProgressBar` | Progress bar, `value` 0..1 (clamped). |
67
- | `ProgressList` | Liste aus Label/Wert-Kopfzeile + Fortschrittsbalken pro Eintrag (z.B. |
68
+ | `ProgressList` | Label/value header and progress bar for each entry (for example, loan repayment progress). |
68
69
  | `PublicShell` | One header and footer for anonymous pages; `focus` narrows to a task column, `card` centers a single card (sign-in). |
69
70
  | `QueryTable` | |
70
- | `RangeField` | Schieberegler = Field + Input(kind:"range"). |
71
+ | `RangeField` | Slider = Field + Input(kind:"range"). |
71
72
  | `RenderEdit` | |
72
73
  | `RenderField` | |
73
74
  | `RenderList` | |
74
75
  | `ResizableHandle` | |
75
76
  | `ResizablePanel` | |
76
77
  | `ResizablePanelGroup` | |
77
- | `ResultPanel` | Ergebnis-Sektion eines Rechners: SectionCard mit Empty-Zustand (Banner) oder Kennzahl-Liste (DetailList) + optionalen Extras (Tabelle, Hinweise). |
78
- | `ResultTable` | Statische, prop-getriebene Ergebnistabelle für berechnete Zeilen (Tranchen, Szenarien). |
78
+ | `ResultPanel` | Result section for a calculator: SectionCard with an empty state (Banner) or a metric list (DetailList) plus optional extras (table, notes). |
79
+ | `ResultTable` | Static, prop-driven result table for calculated rows (tranches, scenarios). |
79
80
  | `RichContentEditor` | |
80
81
  | `ScreenWidthProvider` | |
81
- | `SectionCard` | Sektion mit Titel + optionalem Action-Slot (Range-Umschalter, Filter) — ersetzt die wiederholten `<section className={CARD}>…<h2>`-Blöcke in Custom-Screens. |
82
- | `SelectField` | Auswahlfeld = Field + Input(kind:"select"). |
82
+ | `SectionCard` | Section with a title and optional action slot (range switcher, filter) — replaces repeated `<section className={CARD}>…<h2>` blocks in custom screens. |
83
+ | `SelectField` | Select field = Field + Input(kind:"select"). |
83
84
  | `SideBySideTable` | Small read-only grid with real table semantics (`th scope`) whose cells are arbitrary React nodes — for side-by-side comparisons like "from the document" vs. |
84
85
  | `Sidebar` | |
85
86
  | `SidebarBrand` | |
@@ -91,15 +92,15 @@ Value exports of `@cosmicdrift/kumiko-renderer/web`.
91
92
  | `SidebarUser` | |
92
93
  | `Sparkline` | |
93
94
  | `Stack` | |
94
- | `StatCard` | Icon-tragende Kennzahl-Kachel mit optionalem Delta-Chip, Trend-Zeile und Sparkline. |
95
+ | `StatCard` | Icon-bearing metric tile with an optional delta chip, trend line, and sparkline. |
95
96
  | `StatusBadge` | Pill badge with a status dot. |
96
97
  | `StatusBarChart` | Status bar strip (e.g. 90-day uptime): variable-height bars with gradient fade + tick line on top; the last entry gets a "now" accent stripe. |
97
98
  | `StepBar` | Wizard step overview — numbered chips with a connector line between them. |
98
- | `TextField` | Textfeld = Field + Input(kind:"text"). |
99
- | `TextareaField` | Mehrzeiliges Textfeld = Field + Input(kind:"textarea"). |
99
+ | `TextField` | Text field = Field + Input(kind:"text"). |
100
+ | `TextareaField` | Multi-line text field = Field + Input(kind:"textarea"). |
100
101
  | `ThemeMenuItem` | Theme toggle as a dropdown entry, for a user menu that carries the shell controls. |
101
102
  | `ThemeToggle` | |
102
- | `TimeseriesChart` | Zeitreihen-Linien-Chart (geglättete Linie + Flächen-Verlauf). |
103
+ | `TimeseriesChart` | Time-series line chart (smoothed line with area fill). |
103
104
  | `ToastProvider` | |
104
105
  | `TokensProvider` | |
105
106
  | `Topbar` | |
@@ -112,16 +113,16 @@ Value exports of `@cosmicdrift/kumiko-renderer/web`.
112
113
 
113
114
  | Name | Description |
114
115
  | --- | --- |
115
- | `useBrowserNavApi` | React-Hook der eine NavApi aus der Browser-History baut. |
116
- | `useBrowserTokensApi` | Hook der eine TokensApi für den Browser baut. |
116
+ | `useBrowserNavApi` | React hook that builds a NavApi from browser history. |
117
+ | `useBrowserTokensApi` | Builds a TokensApi for the browser. |
117
118
  | `useDispatcher` | |
118
119
  | `useDispatcherStatus` | |
119
- | `useDraft` | Formular-State für Rechner-Screens: ein Draft-Objekt + `patch` für Teil-Updates + `field(name)` das die `{ id, name, value, onChange }`-Props fertig für die Feld-Widgets (NumberField/MoneyField/PercentField) liefert. |
120
+ | `useDraft` | Form state for calculator screens: a draft object plus `patch` for partial updates, and `field(name)` that provides `{ id, name, value, onChange }` props ready for field widgets (NumberField/MoneyField/PercentField). |
120
121
  | `useForm` | |
121
122
  | `useIsNarrowViewport` | |
122
123
  | `useIsViewportBelow` | |
123
- | `useLiveEvents` | Hook für useQuery-like Consumer. |
124
- | `useLocale` | Liefert den aktuellen LocaleResolver und abonniert automatisch Locale-Änderungen — der aufrufende Component re-rendert sobald die Sprache gewechselt wird. |
124
+ | `useLiveEvents` | Hook for a useQuery-like consumer. |
125
+ | `useLocale` | Provides the current LocaleResolver and automatically subscribes to locale changes — the calling component re-renders when the language changes. |
125
126
  | `useNav` | |
126
127
  | `usePrimitives` | |
127
128
  | `useQuery` | |
@@ -129,8 +130,8 @@ Value exports of `@cosmicdrift/kumiko-renderer/web`.
129
130
  | `useStore` | |
130
131
  | `useStoreSelector` | |
131
132
  | `useToast` | |
132
- | `useTokenController` | Volle API inkl. |
133
- | `useTokens` | Read-only Tokens-Hook. |
133
+ | `useTokenController` | Full API including theme toggling, for a dark/light switch button. |
134
+ | `useTokens` | Read-only tokens hook. |
134
135
  | `useTranslation` | `t("key", params)` resolves in this order: 1. |
135
136
  | `useUserRoles` | |
136
137
 
@@ -138,17 +139,17 @@ Value exports of `@cosmicdrift/kumiko-renderer/web`.
138
139
 
139
140
  | Name | Description |
140
141
  | --- | --- |
141
- | `applyTokensToCssVars` | Historisch: schrieb Tokens auf :root als CSS-vars. |
142
+ | `applyTokensToCssVars` | Historically wrote tokens to :root as CSS variables. |
142
143
  | `buildFileUploadFormData` | |
143
144
  | `buildNavRegistrySlice` | |
144
145
  | `buildNavRegistrySliceForApp` | |
145
- | `cn` | shadcn-Standard-Helper: clsx für konditionales Zusammenstecken, tailwind-merge für Konfliktauflösung (z.B. |
146
+ | `cn` | Standard shadcn helper: `clsx` combines conditional classes, while `tailwind-merge` resolves conflicts (for example, `px-2 px-4` → `px-4`). |
146
147
  | `createBrowserDraftStorage` | Default DraftStorage when createKumikoApp boots without one. |
147
- | `createBrowserLocaleResolver` | Default-Resolver wenn createKumikoApp ohne `locale`-Option gebootet wird. |
148
- | `createEventSourceLiveEvents` | Liefert einen `LiveEventSubscriber` der EventSource-backed ist. |
148
+ | `createBrowserLocaleResolver` | Default resolver when createKumikoApp is booted without a `locale` option. |
149
+ | `createEventSourceLiveEvents` | Returns an EventSource-backed `LiveEventSubscriber`. |
149
150
  | `createKumikoApp` | |
150
151
  | `createPublicSurface` | |
151
- | `createStaticLocaleResolver` | Default-Resolver für Apps ohne eigene i18n-Schicht. |
152
+ | `createStaticLocaleResolver` | Default resolver for apps without their own i18n layer. |
152
153
  | `downloadFileRef` | |
153
154
  | `fetchFileRefBlob` | |
154
155
  | `fileNameFromContentDisposition` | |
@@ -157,16 +158,16 @@ Value exports of `@cosmicdrift/kumiko-renderer/web`.
157
158
  | `formatMoney` | |
158
159
  | `formatPath` | |
159
160
  | `parsePath` | |
160
- | `parseTargetFromSearchParams` | Inverse — parse the current search-params back into a TargetRef. |
161
+ | `parseTargetFromSearchParams` | Parses the current search parameters back into a TargetRef. |
161
162
  | `postWithDownload` | |
162
163
  | `qualifyScreenId` | |
163
164
  | `readLoadedBuild` | |
164
165
  | `reparentAppSchemaNavs` | |
165
166
  | `resolveDefaultId` | |
166
167
  | `saveBlobAsFile` | |
167
- | `smoothPath` | Quadratic-durch-Mittelpunkte-Trick: glättet die Zick-Zack-Linie ohne Overshoot (~5 Zeilen statt Catmull-Rom/Bezier-Fit). |
168
- | `synthesizeActionFormEntity` | Baut eine minimale EntityDefinition aus den Inline-Fields eines ActionForm- oder SecretMint-Screens. |
169
- | `synthesizeActionFormScreen` | Wandelt ein ActionFormScreenDefinition oder SecretMintScreenDefinition in die EntityEditScreen-Shape die RenderEdit erwartet. |
168
+ | `smoothPath` | Quadratic midpoint technique: smooths the zigzag line without overshoot (~5 lines instead of a Catmull-Rom/Bezier fit). |
169
+ | `synthesizeActionFormEntity` | Builds a minimal EntityDefinition from the inline fields of an ActionForm or SecretMint screen. |
170
+ | `synthesizeActionFormScreen` | Converts an ActionFormScreenDefinition or SecretMintScreenDefinition to the EntityEditScreen shape expected by RenderEdit. |
170
171
  | `uploadFileRef` | Posts one file to the stack's file endpoint (double-submit CSRF) and returns the new FileRef id. |
171
172
 
172
173
  ## Constants
@@ -177,7 +178,7 @@ Value exports of `@cosmicdrift/kumiko-renderer/web`.
177
178
  | `STATUS_TONE_TEXT` | |
178
179
  | `cssVarTokens` | Tokens with var-string values. |
179
180
  | `defaultPrimitives` | |
180
- | `defaultTokens` | Default-Tokens — identisch zu `cssVarTokens` (var-string-refs). |
181
+ | `defaultTokens` | Default tokens—identical to `cssVarTokens` (variable-string references). |
181
182
  | `lightTokens` | |
182
183
 
183
184
  ## Classes
@@ -137,8 +137,8 @@ export const TENANT_HEADER_NAME = "X-Tenant";
137
137
  export const LOCALE_HEADER_NAME = "X-Locale";
138
138
  // Internal-only signal set by buildServer's app.notFound() to mark "no
139
139
  // route matched" 404s so tryHonoFirst (server-runtime) can tell them apart
140
- // from a matched route's own deliberate 404 (e.g. default-deny reads) —
141
- // see kumiko-framework#2435. Never reaches a client: tryHonoFirst and every
140
+ // from a matched route's own deliberate 404 (e.g. default-deny reads).
141
+ // Never reaches a client: tryHonoFirst and every
142
142
  // direct app.fetch() passthrough strip it before the response leaves the
143
143
  // process, since its presence would otherwise let a caller distinguish
144
144
  // "unregistered path" from "registered path, access denied" — a leak the
@@ -126,13 +126,13 @@ export function authMiddleware(jwt, options = {}) {
126
126
  // No JWT → either fall through as anonymous (when the server opts in)
127
127
  // or reject with 401 (preserving the pre-anonymous default).
128
128
  //
129
- // Auth-routes-Sonderfall: `/api/auth/*`-Pfade die NICHT in
130
- // PUBLIC_API_PATHS sind (tenants, switch-tenant, logout) brauchen
131
- // einen JWT — aber keinen Tenant-Resolve. Würden sie durch
132
- // handleAnonymous laufen, wirft resolveTenant 400 tenant_required
133
- // wenn kein Tenant declared ist. Falsche Diagnose: das Problem ist
134
- // missing authentication, nicht missing tenant. Daher hier direkt
135
- // 401, ohne den anonymous-Tenant-Flow zu durchlaufen.
129
+ // Special case for auth routes: `/api/auth/*` paths that are NOT in
130
+ // PUBLIC_API_PATHS (tenants, switch-tenant, logout) require a JWT —
131
+ // but not tenant resolution. If they went through handleAnonymous,
132
+ // resolveTenant would throw 400 tenant_required when no tenant is
133
+ // declared. That would be the wrong diagnosis: the problem is missing
134
+ // authentication, not a missing tenant. Therefore, return 401 here
135
+ // without entering the anonymous-tenant flow.
136
136
  if (anonymousAccess) {
137
137
  if (isSessionRequiredApiPath(c.req.path)) {
138
138
  return middlewareReject(c, {
@@ -93,10 +93,14 @@ export function createRedisLoginRateLimiter(redis, maxAttempts = 10, windowMs =
93
93
  // shipped (PTTL returns -1 for "no expiry set, key exists") — without
94
94
  // it, those pre-existing keys would grow forever with no way back to
95
95
  // a normal window.
96
- const count = (await redis.eval(`local c = redis.call('INCR', KEYS[1])
96
+ const count = await redis.eval(`local c = redis.call('INCR', KEYS[1])
97
97
  if c == 1 or redis.call('PTTL', KEYS[1]) < 0 then redis.call('PEXPIRE', KEYS[1], ARGV[1]) end
98
- return c`, 1, redisKey, windowMs));
99
- return count <= maxAttempts;
98
+ return c`, 1, redisKey, windowMs);
99
+ const attempts = typeof count === "string" && /^\d+$/.test(count) ? Number(count) : count;
100
+ if (typeof attempts !== "number" || !Number.isInteger(attempts)) {
101
+ throw new TypeError(`redis INCR script returned ${String(count)}, expected an integer`);
102
+ }
103
+ return attempts <= maxAttempts;
100
104
  },
101
105
  async reset(key) {
102
106
  await redis.del(`${prefix}${key}`);
@@ -130,7 +130,7 @@ export function registerMfaPreauthEnableStartRoute(ctx) {
130
130
  // Second axis, independent of the IP-derived bucket above: the
131
131
  // preauthSetupToken is minted by login.write.ts and not freely
132
132
  // choosable, so this cap survives an attacker rotating
133
- // x-forwarded-for to bypass the IP bucket (kumiko-framework#1522).
133
+ // x-forwarded-for to bypass the IP bucket.
134
134
  const tokenAllowed = await rateLimiter.check(preauthTokenKeyOf(body.preauthSetupToken));
135
135
  if (!tokenAllowed) {
136
136
  return c.json({ isSuccess: false, error: "rate_limited" }, 429);
@@ -121,7 +121,7 @@ export function registerSessionRoutes(ctx) {
121
121
  id: user.id,
122
122
  tenantId: targetTenantId,
123
123
  roles: sessionRoles,
124
- // Tenant-independent prefs must survive the switch (fw#2343).
124
+ // Tenant-independent prefs must survive the switch.
125
125
  ...tenantIndependentPrefs(user),
126
126
  };
127
127
  const claims = await dispatcher.resolveAuthClaims(targetSession);
@@ -2,8 +2,9 @@ import * as z from "zod";
2
2
  import { createAnonymousUser } from "../engine/system-user.js";
3
3
  import { SYSTEM_TENANT_ID } from "../engine/types/index.js";
4
4
  import { NotFoundError } from "../errors/index.js";
5
- // Cross-device try-first handover (kumiko-framework#3035 follow-up,
6
- // offlot-app#454): an optional tenant-handover grant the signup-request
5
+ import { createFallbackLogger } from "../logging/utils.js";
6
+ const log = createFallbackLogger("kumiko");
7
+ // Cross-device try-first handover: an optional tenant-handover grant the signup-request
7
8
  // route forwards to the handler for server-side verification and binding —
8
9
  // the grant itself never appears anywhere else (URL, mail, log, response).
9
10
  export const SignupRequestBody = z.object({
@@ -68,7 +69,10 @@ export function registerTokenRequestRoute(opts) {
68
69
  // rate_limited is an expected, attacker-triggerable outcome; logging it
69
70
  // would flood the sink and bury real misconfiguration errors.
70
71
  if (!result.isSuccess && result.error.code !== "rate_limited") {
71
- console.error(`[kumiko] token request handler "${opts.requestHandler}" failed: ${result.error.code}`);
72
+ log.error("token request handler failed", {
73
+ handler: opts.requestHandler,
74
+ code: result.error.code,
75
+ });
72
76
  }
73
77
  return c.json({ isSuccess: true });
74
78
  });
@@ -63,7 +63,7 @@ export function registerSignupRoutes(ctx) {
63
63
  // switcher), signup knows exactly ONE membership — the frontend UI uses
64
64
  // it directly as the redirect target.
65
65
  tenantKey: data.tenantKey,
66
- // Cross-device try-first handover (kumiko-framework#3035 follow-up):
66
+ // Cross-device try-first handover:
67
67
  // present only when signup-confirm actually claimed a bound grant —
68
68
  // absent, not null, so a client that doesn't know the field sees
69
69
  // nothing unusual.
@@ -37,8 +37,13 @@ function inMemoryIpRateLimit(clientIpResolver, now) {
37
37
  windows.delete(ip);
38
38
  }
39
39
  }
40
- if (windows.size > MAX_TRACKED_IPS)
41
- windows.clear();
40
+ // Map keeps insertion order and touched IPs are re-inserted, so the front is the least recently
41
+ // seen; clear() would let an attacker rotating addresses reset every other IP's window.
42
+ for (const ip of windows.keys()) {
43
+ if (windows.size <= MAX_TRACKED_IPS)
44
+ break;
45
+ windows.delete(ip);
46
+ }
42
47
  }
43
48
  return async (c, next) => {
44
49
  const ip = clientIpResolver.resolve(clientIpSourceFromHonoContext(c));
@@ -47,6 +52,7 @@ function inMemoryIpRateLimit(clientIpResolver, now) {
47
52
  const existing = windows.get(ip);
48
53
  const window = existing && nowMs - existing.startedAt < windowMs ? existing : { count: 0, startedAt: nowMs };
49
54
  window.count += 1;
55
+ windows.delete(ip);
50
56
  windows.set(ip, window);
51
57
  if (window.count > REPORTS_PER_WINDOW) {
52
58
  const resetAtMs = window.startedAt + windowMs;
@@ -1,3 +1,5 @@
1
+ import { createFallbackLogger } from "../logging/utils.js";
2
+ const log = createFallbackLogger("kumiko");
1
3
  // Single source for client-IP extraction, shared by every IP-keyed rate
2
4
  // limit and audit field. Deriving the caller IP independently per call site
3
5
  // makes it easy for one to silently trust the first XFF entry, which is
@@ -70,7 +72,7 @@ export function createClientIpResolver(trustedProxyHops, context = "resolveClien
70
72
  if (trustedProxyHops === 0) {
71
73
  if (xff !== undefined && xff.trim().length > 0 && !warnedUnexpectedForwardedFor) {
72
74
  warnedUnexpectedForwardedFor = true;
73
- console.warn("[kumiko] received X-Forwarded-For but trustedProxyHops is 0 (no proxy trusted) — " +
75
+ log.warn("received X-Forwarded-For but trustedProxyHops is 0 (no proxy trusted) — " +
74
76
  "ignoring it. Running behind a proxy? Set trustedProxyHops, otherwise all clients " +
75
77
  "share one rate-limit bucket.");
76
78
  }
@@ -1,5 +1,5 @@
1
1
  // ExtraRoute — declarative replacement for the old `extraRoutes: (app, deps)
2
- // => void` closure (kumiko-framework#3050). Every entry declares its access
2
+ // => void` closure. Every entry declares its access
3
3
  // tier (`entry`) up front; buildServer wires the matching guard + deps
4
4
  // instead of handing every route a raw db/redis escape hatch.
5
5
  export const ExtraRouteEntries = {
@@ -27,7 +27,9 @@ export type { MetricsRouteOptions } from "./route-registrars.ts";
27
27
  export { createMetricsApp, DEFAULT_MAX_REQUEST_BYTES, isPrometheusMeter, } from "./route-registrars.ts";
28
28
  export { createApiRoutes } from "./routes.ts";
29
29
  export type { KumikoServer, ServerOptions } from "./server.ts";
30
- export { buildServer, makeDispatchSystemQuery, makeDispatchSystemWrite, makeDispatchWriteAs, withFileProviderResolver, } from "./server.ts";
30
+ export { buildServer } from "./server.ts";
31
+ export { makeDispatchSystemQuery, makeDispatchSystemWrite, makeDispatchWriteAs, } from "./server-extra-routes.ts";
32
+ export { withFileProviderResolver } from "./server-wiring.ts";
31
33
  export type { ResolvedSessionCookies, SessionCookieBase, SessionCookieNames, } from "./session-cookies.ts";
32
34
  export { AUTH_COOKIE_BASE, CSRF_COOKIE_BASE, getSessionCookies, HOST_COOKIE_PREFIX, isHostPrefixedCookieName, resolveSessionCookieNames, resolveSessionCookies, sessionCookieName, sessionCookiesMiddleware, TENANT_COOKIE_BASE, } from "./session-cookies.ts";
33
35
  export type { SseBroker, SseClient, SseEvent } from "./sse-broker.ts";
package/dist/api/index.js CHANGED
@@ -16,7 +16,9 @@ export { readonlyRequestContext as requestContext, } from "./request-context.js"
16
16
  export { buildRequestContextDataFromRequest, requestIdMiddleware, } from "./request-id-middleware.js";
17
17
  export { createMetricsApp, DEFAULT_MAX_REQUEST_BYTES, isPrometheusMeter, } from "./route-registrars.js";
18
18
  export { createApiRoutes } from "./routes.js";
19
- export { buildServer, makeDispatchSystemQuery, makeDispatchSystemWrite, makeDispatchWriteAs, withFileProviderResolver, } from "./server.js";
19
+ export { buildServer } from "./server.js";
20
+ export { makeDispatchSystemQuery, makeDispatchSystemWrite, makeDispatchWriteAs, } from "./server-extra-routes.js";
21
+ export { withFileProviderResolver } from "./server-wiring.js";
20
22
  export { AUTH_COOKIE_BASE, CSRF_COOKIE_BASE, getSessionCookies, HOST_COOKIE_PREFIX, isHostPrefixedCookieName, resolveSessionCookieNames, resolveSessionCookies, sessionCookieName, sessionCookiesMiddleware, TENANT_COOKIE_BASE, } from "./session-cookies.js";
21
23
  export { createSseBroker } from "./sse-broker.js";
22
24
  export { createSseRoute, SSE_HEARTBEAT_INTERVAL_MS } from "./sse-route.js";
@@ -1,5 +1,7 @@
1
1
  import { PII_CIPHERTEXT_PREFIX } from "../crypto/index.js";
2
+ import { createFallbackLogger } from "../logging/utils.js";
2
3
  import { resolveRouteLabel } from "./route-label.js";
4
+ const log = createFallbackLogger("kumiko:pii-leak-guard");
3
5
  const isProductionEnv = () => process.env["NODE_ENV"] === "production";
4
6
  // Version-agnostic: catches both the current PII_CIPHERTEXT_PREFIX and any
5
7
  // older/decrypt-only format version still present in unmigrated rows.
@@ -28,7 +30,7 @@ export function piiCiphertextResponseGuard() {
28
30
  // skip: clean response — the common case
29
31
  if (!CIPHERTEXT_RE.test(text))
30
32
  return;
31
- const detail = `[api] JSON response for ${c.req.method} ${resolveRouteLabel(c)} contains a PII ciphertext ` +
33
+ const detail = `JSON response for ${c.req.method} ${resolveRouteLabel(c)} contains a PII ciphertext ` +
32
34
  `("${PII_CIPHERTEXT_PREFIX}…") — a raw DB read leaked to the API surface. ` +
33
35
  `Decrypt before returning (decryptStoredPii / executor read path).`;
34
36
  if (!isProductionEnv()) {
@@ -36,7 +38,7 @@ export function piiCiphertextResponseGuard() {
36
38
  // skip: response replaced with the loud 500 above — nothing left to do
37
39
  return;
38
40
  }
39
- console.error(detail);
41
+ log.error(detail);
40
42
  const headers = new Headers(c.res.headers);
41
43
  headers.delete("content-length");
42
44
  c.res = new Response(text.replace(CIPHERTEXT_REDACT_RE, "[pii-redacted]"), {
@@ -74,11 +74,11 @@ export function redisPingCheck(redis) {
74
74
  },
75
75
  };
76
76
  }
77
- // Lag-Check für den Async-Event-Dispatcher. Liest HWM + Consumer-Cursor aus
78
- // der DB — kein extra Redis/Runtime-State. Fail-Schwelle ist in EventIds
79
- // (bigint), weil das die natürliche Einheit ist (events sind monoton id'd).
80
- // Ein Tuning-Beispiel: maxLagEvents = 1_000 bedeutet "wenn die Projection
81
- // mehr als 1k Events hinter HWM ist, stoppe neue Traffic-Zuweisung".
77
+ // Lag check for the asynchronous event dispatcher. Reads the HWM and consumer cursor from
78
+ // the database, without relying on extra Redis or runtime state. The failure threshold is
79
+ // measured in event IDs (`bigint`), the natural unit because events have monotonically
80
+ // increasing IDs. For example, `maxLagEvents = 1_000` stops routing new traffic when the
81
+ // projection falls more than 1,000 events behind the HWM.
82
82
  export function dispatcherLagCheck(db, consumerNames, maxLagEvents) {
83
83
  return {
84
84
  name: "dispatcher_lag",
@@ -1,8 +1,10 @@
1
1
  import { isPlainObject } from "@cosmicdrift/kumiko-types/type-guards";
2
+ import { createFallbackLogger } from "../logging/utils.js";
2
3
  import { redisChannelPrefixFromEnv, redisClientOptionsFromEnv, } from "../redis/client.js";
3
4
  import { createRedisPubSubSignal } from "../redis/pubsub-signal.js";
4
5
  import { createSseBroker, readNonEmptyStringArray, } from "./sse-broker.js";
5
- // Channel namespace for cross-replica fanout (fw#2625). Every pod publishes
6
+ const log = createFallbackLogger("kumiko:sse-broker");
7
+ // Channel namespace for cross-replica fanout. Every pod publishes
6
8
  // here and every pod's psubscribe listens here, so a push on one instance
7
9
  // reaches SSE clients connected to any other instance without a shared
8
10
  // cursor — Pub/Sub for connected-client fanout, the event-store's shared
@@ -21,9 +23,9 @@ export function isRedisSseBroker(broker) {
21
23
  // runProdApp must funnel through this rather than each deciding on their
22
24
  // own — runProdApp doing exactly that (building an in-memory broker
23
25
  // unconditionally, then passing it in as ServerOptions.sseBroker) is why
24
- // fw#2625's fanout fix (fw#2630) shipped without ever taking effect in
25
- // production: an explicit ServerOptions.sseBroker always wins in
26
- // buildServer, so its own REDIS_URL-based default never ran.
26
+ // the fanout fix shipped without ever taking effect in production: an
27
+ // explicit ServerOptions.sseBroker always wins in buildServer, so its own
28
+ // REDIS_URL-based default never ran.
27
29
  export function createDefaultSseBroker(env = process.env) {
28
30
  const redisUrl = env["REDIS_URL"];
29
31
  const ownedRedisSseBroker = redisUrl
@@ -109,7 +111,7 @@ export function createRedisSseBroker(opts) {
109
111
  signal.onMessage((channel, payload) => {
110
112
  if (channel.startsWith(channelPrefix)) {
111
113
  if (!isSseEvent(payload)) {
112
- console.error(`[kumiko:sse-broker] dropping malformed event on "${channel}"`);
114
+ log.error(`dropping malformed event on "${channel}"`);
113
115
  // skip: malformed payload already logged above, nothing to deliver
114
116
  return;
115
117
  }
@@ -132,7 +134,7 @@ export function createRedisSseBroker(opts) {
132
134
  pushToChannel(channel, event) {
133
135
  return signal.publishConfirmed(`${channelPrefix}${channel}`, event);
134
136
  },
135
- // fw#1601: this is the security-critical call — a revoked session's
137
+ // This is the security-critical call — a revoked session's
136
138
  // stream must close on every replica, not just the one that observed
137
139
  // the revocation event. Publishing (rather than calling inner directly,
138
140
  // like the in-memory broker does) is what makes that true here.
@@ -41,6 +41,6 @@ export declare function runWithOrigin<T>(origin: {
41
41
  readonly risk: AgentRisk;
42
42
  };
43
43
  }, fn: () => T): T;
44
- export declare function runAsDirectCallEntry<T>(fn: () => T): T;
44
+ export declare function runAsAgentToolCallEntry<T>(fn: () => T): T;
45
45
  export declare function isAgentToolCallScope(): boolean;
46
46
  export declare function runWithWriteOrigin<T>(origin: WriteOrigin, fn: () => T): T;
@@ -53,7 +53,7 @@ export function runWithOrigin(origin, fn) {
53
53
  // surrounding turn/approve handler. Reserved for dispatchToolCall, so it also marks
54
54
  // the scope as an agent tool call; it always mints a scope, because an agent loop
55
55
  // running outside any request must still carry that marker.
56
- export function runAsDirectCallEntry(fn) {
56
+ export function runAsAgentToolCallEntry(fn) {
57
57
  const current = requestContext.get();
58
58
  const requestId = current?.requestId ?? requestContext.generateId();
59
59
  const { entryHandler: _entryHandler, ...rest } = current ?? {};
@@ -129,7 +129,7 @@ export function createApiRoutes(dispatcher, options = {}) {
129
129
  // dispatch gates (feature/rate-limit/access/validation) plus the handler's
130
130
  // first yield — is raced against a heartbeat timeout BEFORE streamSSE, so
131
131
  // a gate failure that settles in time maps to its real HTTP status via
132
- // queryErrorResponse instead of a flushed-200 error frame (framework#1517).
132
+ // queryErrorResponse instead of a flushed-200 error frame.
133
133
  api.post(Routes.stream, async (c) => {
134
134
  const user = getUser(c);
135
135
  const body = await readDispatchBody(c);
@@ -149,7 +149,7 @@ export function createApiRoutes(dispatcher, options = {}) {
149
149
  // Hook the raw request signal directly so a client disconnect during the
150
150
  // pre-pull still reclaims the generator instead of leaking a Redis
151
151
  // subscription/DB cursor held open inside its still-unresolved first
152
- // `.next()` (framework#1528).
152
+ // `.next()`.
153
153
  const signal = c.req.raw.signal;
154
154
  const onPrePullAbort = () => void generator.return(undefined);
155
155
  signal.addEventListener("abort", onPrePullAbort);
@@ -0,0 +1,10 @@
1
+ import { type AppContext, type Registry } from "../engine/types/index.ts";
2
+ import type { createFallbackLogger } from "../logging/index.ts";
3
+ import type { AuthRoutesConfig } from "./auth-routes.ts";
4
+ export type BootLogger = ReturnType<typeof createFallbackLogger>;
5
+ export declare function assertNoPayloadRateLimitsWithoutResolver(registry: Registry): void;
6
+ export declare function assertFileStorageProviderForFileFields(registry: Registry, context: AppContext): void;
7
+ export declare function warnSearchableScreensWithoutSearchAdapter(registry: Registry, context: AppContext, bootLog: BootLogger): void;
8
+ export declare function resolveServerInstanceId(explicitInstanceId: string | undefined, bootLog: BootLogger): string;
9
+ export declare function warnUnlimitedSystemScopeFeatures(registry: Registry, bootLog: BootLogger): void;
10
+ export declare function assertSinglePrincipalStatusProvider(registry: Registry, auth: AuthRoutesConfig): void;