okengine 0.1.4

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 (674) hide show
  1. package/AGENTS.md +91 -0
  2. package/README.md +327 -0
  3. package/docs/spec/complete-example.md +1188 -0
  4. package/docs/spec/console.md +739 -0
  5. package/docs/spec/four-applications.md +1188 -0
  6. package/docs/spec/unified-theory.md +489 -0
  7. package/package.json +152 -0
  8. package/spec/manifest.v1.schema.json +624 -0
  9. package/src/auth/api-keys.ts +168 -0
  10. package/src/auth/attenuation.ts +116 -0
  11. package/src/auth/auth.test.ts +273 -0
  12. package/src/auth/cross-plane.ts +98 -0
  13. package/src/auth/index.ts +112 -0
  14. package/src/auth/invites.ts +66 -0
  15. package/src/auth/invoke-as.ts +49 -0
  16. package/src/auth/operator.ts +178 -0
  17. package/src/auth/planes.ts +102 -0
  18. package/src/auth/plugin.ts +44 -0
  19. package/src/auth/roles.ts +84 -0
  20. package/src/auth/sessions.ts +418 -0
  21. package/src/auth/tables.ts +131 -0
  22. package/src/cli/args.ts +50 -0
  23. package/src/cli/branch.ts +75 -0
  24. package/src/cli/build.ts +86 -0
  25. package/src/cli/client-add.test.ts +140 -0
  26. package/src/cli/client-add.ts +164 -0
  27. package/src/cli/completion.test.ts +58 -0
  28. package/src/cli/completion.ts +296 -0
  29. package/src/cli/dev-app-runner.ts +77 -0
  30. package/src/cli/dev.test.ts +435 -0
  31. package/src/cli/dev.ts +594 -0
  32. package/src/cli/doc-drift.test.ts +146 -0
  33. package/src/cli/doc-drift.ts +397 -0
  34. package/src/cli/docker-cli.test.ts +221 -0
  35. package/src/cli/docker.ts +127 -0
  36. package/src/cli/doctor-diff-examples.ts +92 -0
  37. package/src/cli/doctor-diff.test.ts +91 -0
  38. package/src/cli/doctor-diff.ts +274 -0
  39. package/src/cli/doctor-pii.test.ts +98 -0
  40. package/src/cli/doctor-pii.ts +151 -0
  41. package/src/cli/doctor.test.ts +150 -0
  42. package/src/cli/doctor.ts +223 -0
  43. package/src/cli/eval.ts +122 -0
  44. package/src/cli/exit.ts +19 -0
  45. package/src/cli/gates-list.test.ts +47 -0
  46. package/src/cli/gates-list.ts +84 -0
  47. package/src/cli/images.ts +277 -0
  48. package/src/cli/index.ts +99 -0
  49. package/src/cli/json-out.test.ts +129 -0
  50. package/src/cli/load-config.ts +71 -0
  51. package/src/cli/mcp-from-console.ts +50 -0
  52. package/src/cli/privacy-erase.ts +73 -0
  53. package/src/cli/registry.ts +455 -0
  54. package/src/cli/safe-defaults.test.ts +92 -0
  55. package/src/cli/schema.ts +196 -0
  56. package/src/cli/stack.ts +82 -0
  57. package/src/cli/start.ts +106 -0
  58. package/src/cli/upgrade.ts +105 -0
  59. package/src/cli/vault-cmd.ts +140 -0
  60. package/src/client/budget-entry.ts +34 -0
  61. package/src/client/budget.test.ts +17 -0
  62. package/src/client/create.test.ts +159 -0
  63. package/src/client/create.ts +152 -0
  64. package/src/client/errors.ts +60 -0
  65. package/src/client/index.ts +35 -0
  66. package/src/client/notes-contract.test.ts +289 -0
  67. package/src/client/transport.test.ts +123 -0
  68. package/src/client/transport.ts +254 -0
  69. package/src/client/types.ts +282 -0
  70. package/src/compiler/aot.test.ts +248 -0
  71. package/src/compiler/aot.ts +182 -0
  72. package/src/compiler/differential.test.ts +241 -0
  73. package/src/compiler/dynamic.ts +54 -0
  74. package/src/compiler/effects-infer.ts +541 -0
  75. package/src/compiler/emit.ts +40 -0
  76. package/src/compiler/extract.test.ts +177 -0
  77. package/src/compiler/extract.ts +1368 -0
  78. package/src/compiler/fixtures/raw/raw-unannotated.ts +28 -0
  79. package/src/compiler/fixtures/skyport/oke.config.ts +24 -0
  80. package/src/compiler/fixtures/skyport/src/ai.ts +15 -0
  81. package/src/compiler/fixtures/skyport/src/app.ts +10 -0
  82. package/src/compiler/fixtures/skyport/src/channels.ts +6 -0
  83. package/src/compiler/fixtures/skyport/src/core.ts +3 -0
  84. package/src/compiler/fixtures/skyport/src/flows/bookings/index.ts +57 -0
  85. package/src/compiler/fixtures/skyport/src/flows/bookings/signals.ts +11 -0
  86. package/src/compiler/fixtures/skyport/src/flows/payments/index.ts +14 -0
  87. package/src/compiler/fixtures/skyport/src/flows/support/index.ts +20 -0
  88. package/src/compiler/fixtures/skyport/src/gates.ts +14 -0
  89. package/src/compiler/fixtures/skyport/src/journeys.ts +9 -0
  90. package/src/compiler/fixtures/skyport/src/schema.ts +3 -0
  91. package/src/compiler/fixtures/skyport/src/vault.ts +6 -0
  92. package/src/compiler/fixtures/skyport.expected.json +241 -0
  93. package/src/compiler/fixtures/triggers/five-triggers.ts +69 -0
  94. package/src/compiler/http-parse.ts +214 -0
  95. package/src/compiler/index.ts +67 -0
  96. package/src/compiler/response.ts +89 -0
  97. package/src/compiler/sucrose.ts +238 -0
  98. package/src/config/index.ts +167 -0
  99. package/src/console/budget.test.ts +73 -0
  100. package/src/console/index.ts +30 -0
  101. package/src/console/server/access.test.ts +370 -0
  102. package/src/console/server/access.ts +777 -0
  103. package/src/console/server/ai.test.ts +172 -0
  104. package/src/console/server/ai.ts +632 -0
  105. package/src/console/server/app.ts +294 -0
  106. package/src/console/server/auth-rate.test.ts +81 -0
  107. package/src/console/server/auth-rate.ts +72 -0
  108. package/src/console/server/bind.ts +25 -0
  109. package/src/console/server/channels.test.ts +179 -0
  110. package/src/console/server/channels.ts +469 -0
  111. package/src/console/server/claim.test.ts +66 -0
  112. package/src/console/server/claim.ts +134 -0
  113. package/src/console/server/clock.test.ts +239 -0
  114. package/src/console/server/clock.ts +390 -0
  115. package/src/console/server/console.test.ts +338 -0
  116. package/src/console/server/diff.test.ts +299 -0
  117. package/src/console/server/diff.ts +352 -0
  118. package/src/console/server/dry-run.audit.test.ts +118 -0
  119. package/src/console/server/flows-invoke.test.ts +148 -0
  120. package/src/console/server/flows.ts +3633 -0
  121. package/src/console/server/gates.test.ts +360 -0
  122. package/src/console/server/gates.ts +869 -0
  123. package/src/console/server/index.ts +141 -0
  124. package/src/console/server/live.test.ts +30 -0
  125. package/src/console/server/live.ts +109 -0
  126. package/src/console/server/plugin.ts +50 -0
  127. package/src/console/server/plugins.test.ts +131 -0
  128. package/src/console/server/plugins.ts +429 -0
  129. package/src/console/server/runs-pii.ts +98 -0
  130. package/src/console/server/security-headers.ts +97 -0
  131. package/src/console/server/security.gate.test.ts +286 -0
  132. package/src/console/server/serve.ts +319 -0
  133. package/src/console/server/signals.test.ts +88 -0
  134. package/src/console/server/signals.ts +282 -0
  135. package/src/console/server/state.ts +982 -0
  136. package/src/console/server/store.test.ts +233 -0
  137. package/src/console/server/store.ts +861 -0
  138. package/src/console/server/structural.ts +95 -0
  139. package/src/console/server/vault.test.ts +251 -0
  140. package/src/console/server/vault.ts +430 -0
  141. package/src/console/ui/access/AccessA11yView.tsx +237 -0
  142. package/src/console/ui/access/a11y.test.tsx +122 -0
  143. package/src/console/ui/access/acknowledgement.test.ts +13 -0
  144. package/src/console/ui/access/acknowledgement.ts +35 -0
  145. package/src/console/ui/access/blast-radius.test.ts +26 -0
  146. package/src/console/ui/access/blast-radius.ts +40 -0
  147. package/src/console/ui/access/confirmation.test.ts +38 -0
  148. package/src/console/ui/access/confirmation.ts +36 -0
  149. package/src/console/ui/access/fixture.ts +203 -0
  150. package/src/console/ui/access/grantable.test.ts +17 -0
  151. package/src/console/ui/access/grantable.ts +36 -0
  152. package/src/console/ui/access/hygiene.test.ts +12 -0
  153. package/src/console/ui/access/hygiene.ts +39 -0
  154. package/src/console/ui/access/index.ts +54 -0
  155. package/src/console/ui/access/provenance.test.ts +12 -0
  156. package/src/console/ui/access/provenance.ts +29 -0
  157. package/src/console/ui/access/search.test.ts +17 -0
  158. package/src/console/ui/access/search.ts +72 -0
  159. package/src/console/ui/access/types.ts +111 -0
  160. package/src/console/ui/ai/AiA11yView.tsx +265 -0
  161. package/src/console/ui/ai/a11y.test.tsx +99 -0
  162. package/src/console/ui/ai/findings.ts +41 -0
  163. package/src/console/ui/ai/fixture.ts +182 -0
  164. package/src/console/ui/ai/format.ts +90 -0
  165. package/src/console/ui/ai/group.test.ts +37 -0
  166. package/src/console/ui/ai/group.ts +88 -0
  167. package/src/console/ui/ai/index.ts +66 -0
  168. package/src/console/ui/ai/promotion.test.ts +77 -0
  169. package/src/console/ui/ai/promotion.ts +150 -0
  170. package/src/console/ui/ai/search.test.ts +40 -0
  171. package/src/console/ui/ai/search.ts +89 -0
  172. package/src/console/ui/ai/types.ts +139 -0
  173. package/src/console/ui/architecture/ArchitectureA11yView.tsx +163 -0
  174. package/src/console/ui/architecture/a11y.test.tsx +97 -0
  175. package/src/console/ui/architecture/boundary.ts +42 -0
  176. package/src/console/ui/architecture/declared.ts +165 -0
  177. package/src/console/ui/architecture/fixture.ts +74 -0
  178. package/src/console/ui/architecture/index.ts +84 -0
  179. package/src/console/ui/architecture/layers.ts +64 -0
  180. package/src/console/ui/architecture/layout.ts +68 -0
  181. package/src/console/ui/architecture/pathologies.ts +260 -0
  182. package/src/console/ui/architecture/search.ts +145 -0
  183. package/src/console/ui/architecture/traffic.ts +102 -0
  184. package/src/console/ui/architecture/types.ts +144 -0
  185. package/src/console/ui/architecture/view.test.ts +165 -0
  186. package/src/console/ui/architecture/view.ts +516 -0
  187. package/src/console/ui/channels/ChannelsA11yView.tsx +180 -0
  188. package/src/console/ui/channels/a11y.test.tsx +96 -0
  189. package/src/console/ui/channels/confirmation.test.ts +37 -0
  190. package/src/console/ui/channels/confirmation.ts +27 -0
  191. package/src/console/ui/channels/fallback.test.ts +15 -0
  192. package/src/console/ui/channels/fallback.ts +20 -0
  193. package/src/console/ui/channels/findings.ts +38 -0
  194. package/src/console/ui/channels/fixture.ts +134 -0
  195. package/src/console/ui/channels/group.ts +25 -0
  196. package/src/console/ui/channels/index.ts +57 -0
  197. package/src/console/ui/channels/locale.test.ts +17 -0
  198. package/src/console/ui/channels/locale.ts +31 -0
  199. package/src/console/ui/channels/mask.test.ts +14 -0
  200. package/src/console/ui/channels/mask.ts +12 -0
  201. package/src/console/ui/channels/search.ts +58 -0
  202. package/src/console/ui/channels/taxonomy.test.ts +17 -0
  203. package/src/console/ui/channels/taxonomy.ts +49 -0
  204. package/src/console/ui/channels/types.ts +117 -0
  205. package/src/console/ui/clock/ClockA11yView.tsx +182 -0
  206. package/src/console/ui/clock/a11y.test.tsx +99 -0
  207. package/src/console/ui/clock/confirmation.test.ts +32 -0
  208. package/src/console/ui/clock/confirmation.ts +34 -0
  209. package/src/console/ui/clock/findings.ts +40 -0
  210. package/src/console/ui/clock/fixture.ts +111 -0
  211. package/src/console/ui/clock/health.test.ts +25 -0
  212. package/src/console/ui/clock/health.ts +61 -0
  213. package/src/console/ui/clock/index.ts +49 -0
  214. package/src/console/ui/clock/search.test.ts +39 -0
  215. package/src/console/ui/clock/search.ts +76 -0
  216. package/src/console/ui/clock/timeline.test.ts +44 -0
  217. package/src/console/ui/clock/timeline.ts +41 -0
  218. package/src/console/ui/clock/types.ts +78 -0
  219. package/src/console/ui/clock/waiting-on.test.ts +34 -0
  220. package/src/console/ui/clock/waiting-on.ts +83 -0
  221. package/src/console/ui/confirmation.unify.test.ts +92 -0
  222. package/src/console/ui/diff/DiffA11yView.tsx +85 -0
  223. package/src/console/ui/diff/a11y.test.tsx +99 -0
  224. package/src/console/ui/diff/fixture.ts +85 -0
  225. package/src/console/ui/diff/group.test.ts +58 -0
  226. package/src/console/ui/diff/group.ts +97 -0
  227. package/src/console/ui/diff/index.ts +38 -0
  228. package/src/console/ui/diff/search.test.ts +32 -0
  229. package/src/console/ui/diff/search.ts +75 -0
  230. package/src/console/ui/diff/summary.ts +74 -0
  231. package/src/console/ui/diff/types.ts +48 -0
  232. package/src/console/ui/dist/assets/index-B71Yl_SS.js +10 -0
  233. package/src/console/ui/dist/assets/panel-access-Dd37LU2c.js +64 -0
  234. package/src/console/ui/dist/assets/panel-ai-CC7LR6-J.js +1 -0
  235. package/src/console/ui/dist/assets/panel-architecture-B5b3iKCz.js +1 -0
  236. package/src/console/ui/dist/assets/panel-channels-CeNjTKXp.js +1 -0
  237. package/src/console/ui/dist/assets/panel-clock-DgFTLoHV.js +1 -0
  238. package/src/console/ui/dist/assets/panel-diff-DxehccqB.js +1 -0
  239. package/src/console/ui/dist/assets/panel-flows-BtrVn-Eg.js +45 -0
  240. package/src/console/ui/dist/assets/panel-gates-Z9MKRGdH.js +1 -0
  241. package/src/console/ui/dist/assets/panel-overview-Bd48d9km.js +1 -0
  242. package/src/console/ui/dist/assets/panel-plugins-DWd0TowH.js +1 -0
  243. package/src/console/ui/dist/assets/panel-runs-BwsWqKeB.js +1 -0
  244. package/src/console/ui/dist/assets/panel-signals-9najbZY2.js +1 -0
  245. package/src/console/ui/dist/assets/panel-store-OHkP2pDp.js +1 -0
  246. package/src/console/ui/dist/assets/panel-traces-tn2JoY8U.js +1 -0
  247. package/src/console/ui/dist/assets/panel-vault-BbfWdox0.js +1 -0
  248. package/src/console/ui/dist/assets/rolldown-runtime-CNC7AqOf.js +1 -0
  249. package/src/console/ui/dist/assets/style-Cnl7WLya.css +3 -0
  250. package/src/console/ui/dist/index.html +14 -0
  251. package/src/console/ui/flows/FlowsA11yView.tsx +155 -0
  252. package/src/console/ui/flows/a11y.test.tsx +105 -0
  253. package/src/console/ui/flows/buffer.test.ts +91 -0
  254. package/src/console/ui/flows/buffer.ts +118 -0
  255. package/src/console/ui/flows/confirmation.ts +131 -0
  256. package/src/console/ui/flows/contract.test.ts +89 -0
  257. package/src/console/ui/flows/contract.ts +353 -0
  258. package/src/console/ui/flows/fixture.ts +81 -0
  259. package/src/console/ui/flows/graph.test.ts +101 -0
  260. package/src/console/ui/flows/graph.ts +549 -0
  261. package/src/console/ui/flows/index.ts +87 -0
  262. package/src/console/ui/flows/save-as-test.test.ts +47 -0
  263. package/src/console/ui/flows/save-as-test.ts +99 -0
  264. package/src/console/ui/flows/search.ts +255 -0
  265. package/src/console/ui/flows/tiers.ts +140 -0
  266. package/src/console/ui/gates/GatesA11yView.tsx +192 -0
  267. package/src/console/ui/gates/a11y.test.tsx +116 -0
  268. package/src/console/ui/gates/audit.test.ts +40 -0
  269. package/src/console/ui/gates/audit.ts +63 -0
  270. package/src/console/ui/gates/denial.test.ts +36 -0
  271. package/src/console/ui/gates/denial.ts +51 -0
  272. package/src/console/ui/gates/findings.ts +19 -0
  273. package/src/console/ui/gates/fixture.ts +189 -0
  274. package/src/console/ui/gates/group.test.ts +30 -0
  275. package/src/console/ui/gates/group.ts +102 -0
  276. package/src/console/ui/gates/index.ts +47 -0
  277. package/src/console/ui/gates/search.test.ts +49 -0
  278. package/src/console/ui/gates/search.ts +115 -0
  279. package/src/console/ui/gates/types.ts +121 -0
  280. package/src/console/ui/overview/OverviewA11yView.tsx +152 -0
  281. package/src/console/ui/overview/a11y.test.tsx +113 -0
  282. package/src/console/ui/overview/busiest.ts +26 -0
  283. package/src/console/ui/overview/compose.ts +133 -0
  284. package/src/console/ui/overview/cost.test.ts +39 -0
  285. package/src/console/ui/overview/cost.ts +138 -0
  286. package/src/console/ui/overview/fixture.ts +161 -0
  287. package/src/console/ui/overview/golden.ts +57 -0
  288. package/src/console/ui/overview/index.ts +59 -0
  289. package/src/console/ui/overview/rank.test.ts +136 -0
  290. package/src/console/ui/overview/rank.ts +210 -0
  291. package/src/console/ui/overview/slo.test.ts +73 -0
  292. package/src/console/ui/overview/slo.ts +229 -0
  293. package/src/console/ui/overview/types.ts +121 -0
  294. package/src/console/ui/overview/verdict.ts +131 -0
  295. package/src/console/ui/plugins/PluginsA11yView.tsx +227 -0
  296. package/src/console/ui/plugins/a11y.test.tsx +97 -0
  297. package/src/console/ui/plugins/command.test.ts +22 -0
  298. package/src/console/ui/plugins/command.ts +27 -0
  299. package/src/console/ui/plugins/findings.ts +39 -0
  300. package/src/console/ui/plugins/fixture.ts +233 -0
  301. package/src/console/ui/plugins/group.test.ts +38 -0
  302. package/src/console/ui/plugins/group.ts +67 -0
  303. package/src/console/ui/plugins/index.ts +40 -0
  304. package/src/console/ui/plugins/search.ts +67 -0
  305. package/src/console/ui/plugins/types.ts +115 -0
  306. package/src/console/ui/runs/RunsA11yView.tsx +267 -0
  307. package/src/console/ui/runs/a11y.test.tsx +99 -0
  308. package/src/console/ui/runs/explain.test.ts +23 -0
  309. package/src/console/ui/runs/explain.ts +32 -0
  310. package/src/console/ui/runs/fixture.ts +189 -0
  311. package/src/console/ui/runs/group.test.ts +24 -0
  312. package/src/console/ui/runs/group.ts +85 -0
  313. package/src/console/ui/runs/histogram.test.ts +31 -0
  314. package/src/console/ui/runs/histogram.ts +85 -0
  315. package/src/console/ui/runs/index.ts +75 -0
  316. package/src/console/ui/runs/project.ts +122 -0
  317. package/src/console/ui/runs/query.test.ts +50 -0
  318. package/src/console/ui/runs/query.ts +283 -0
  319. package/src/console/ui/runs/search.test.ts +45 -0
  320. package/src/console/ui/runs/search.ts +141 -0
  321. package/src/console/ui/runs/trace-link.test.ts +30 -0
  322. package/src/console/ui/runs/trace-link.ts +99 -0
  323. package/src/console/ui/runs/types.ts +137 -0
  324. package/src/console/ui/shell/App.tsx +56 -0
  325. package/src/console/ui/shell/client.ts +1715 -0
  326. package/src/console/ui/shell/components/ui.tsx +110 -0
  327. package/src/console/ui/shell/index.html +12 -0
  328. package/src/console/ui/shell/layout/Shell.tsx +95 -0
  329. package/src/console/ui/shell/main.tsx +281 -0
  330. package/src/console/ui/shell/panels/Access.tsx +5 -0
  331. package/src/console/ui/shell/panels/Ai.tsx +5 -0
  332. package/src/console/ui/shell/panels/Architecture.tsx +5 -0
  333. package/src/console/ui/shell/panels/Channels.tsx +5 -0
  334. package/src/console/ui/shell/panels/Clock.tsx +5 -0
  335. package/src/console/ui/shell/panels/Diff.tsx +5 -0
  336. package/src/console/ui/shell/panels/Flows.tsx +5 -0
  337. package/src/console/ui/shell/panels/Gates.tsx +5 -0
  338. package/src/console/ui/shell/panels/Overview.tsx +6 -0
  339. package/src/console/ui/shell/panels/Plugins.tsx +5 -0
  340. package/src/console/ui/shell/panels/Runs.tsx +5 -0
  341. package/src/console/ui/shell/panels/Signals.tsx +5 -0
  342. package/src/console/ui/shell/panels/Store.tsx +5 -0
  343. package/src/console/ui/shell/panels/Traces.tsx +5 -0
  344. package/src/console/ui/shell/panels/Vault.tsx +5 -0
  345. package/src/console/ui/shell/panels/access/AccessPanel.tsx +813 -0
  346. package/src/console/ui/shell/panels/ai/AiPanel.tsx +563 -0
  347. package/src/console/ui/shell/panels/architecture/ArchitecturePanel.tsx +377 -0
  348. package/src/console/ui/shell/panels/channels/ChannelsPanel.tsx +454 -0
  349. package/src/console/ui/shell/panels/clock/ClockPanel.tsx +479 -0
  350. package/src/console/ui/shell/panels/diff/DiffPanel.tsx +275 -0
  351. package/src/console/ui/shell/panels/flows/ContractEditor.tsx +301 -0
  352. package/src/console/ui/shell/panels/flows/FlowDrawer.tsx +350 -0
  353. package/src/console/ui/shell/panels/flows/FlowsPanel.tsx +502 -0
  354. package/src/console/ui/shell/panels/gates/GatesPanel.tsx +482 -0
  355. package/src/console/ui/shell/panels/overview/OverviewPanel.tsx +428 -0
  356. package/src/console/ui/shell/panels/plugins/PluginsPanel.tsx +413 -0
  357. package/src/console/ui/shell/panels/runs/RunsPanel.tsx +649 -0
  358. package/src/console/ui/shell/panels/signals/SignalsPanel.tsx +840 -0
  359. package/src/console/ui/shell/panels/store/StorePanel.tsx +787 -0
  360. package/src/console/ui/shell/panels/traces/TracesPanel.tsx +539 -0
  361. package/src/console/ui/shell/panels/vault/VaultPanel.tsx +449 -0
  362. package/src/console/ui/shell/plugin/Sandbox.tsx +29 -0
  363. package/src/console/ui/shell/setup/Wizard.tsx +189 -0
  364. package/src/console/ui/shell/styles.css +75 -0
  365. package/src/console/ui/signals/SignalsA11yView.tsx +276 -0
  366. package/src/console/ui/signals/a11y.test.tsx +99 -0
  367. package/src/console/ui/signals/confirmation.test.ts +39 -0
  368. package/src/console/ui/signals/confirmation.ts +63 -0
  369. package/src/console/ui/signals/dry-run.test.ts +18 -0
  370. package/src/console/ui/signals/dry-run.ts +36 -0
  371. package/src/console/ui/signals/durable.test.ts +22 -0
  372. package/src/console/ui/signals/durable.ts +41 -0
  373. package/src/console/ui/signals/findings.ts +33 -0
  374. package/src/console/ui/signals/fixture.ts +242 -0
  375. package/src/console/ui/signals/group.test.ts +32 -0
  376. package/src/console/ui/signals/group.ts +49 -0
  377. package/src/console/ui/signals/index.ts +52 -0
  378. package/src/console/ui/signals/monitor.test.ts +30 -0
  379. package/src/console/ui/signals/monitor.ts +79 -0
  380. package/src/console/ui/signals/schema-form.test.ts +34 -0
  381. package/src/console/ui/signals/schema-form.ts +112 -0
  382. package/src/console/ui/signals/search.ts +102 -0
  383. package/src/console/ui/signals/types.ts +71 -0
  384. package/src/console/ui/store/StoreA11yView.tsx +199 -0
  385. package/src/console/ui/store/a11y.test.tsx +99 -0
  386. package/src/console/ui/store/cache-view.test.ts +13 -0
  387. package/src/console/ui/store/cache-view.ts +36 -0
  388. package/src/console/ui/store/confirmation.test.ts +38 -0
  389. package/src/console/ui/store/confirmation.ts +55 -0
  390. package/src/console/ui/store/dry-run.test.ts +15 -0
  391. package/src/console/ui/store/dry-run.ts +29 -0
  392. package/src/console/ui/store/fixture.ts +163 -0
  393. package/src/console/ui/store/group.test.ts +21 -0
  394. package/src/console/ui/store/group.ts +41 -0
  395. package/src/console/ui/store/index.ts +40 -0
  396. package/src/console/ui/store/search.ts +78 -0
  397. package/src/console/ui/store/types.ts +65 -0
  398. package/src/console/ui/store/will-not-fire.test.ts +19 -0
  399. package/src/console/ui/store/will-not-fire.ts +40 -0
  400. package/src/console/ui/traces/TracesA11yView.tsx +200 -0
  401. package/src/console/ui/traces/a11y.test.tsx +97 -0
  402. package/src/console/ui/traces/chain.test.ts +61 -0
  403. package/src/console/ui/traces/chain.ts +144 -0
  404. package/src/console/ui/traces/critical-path.test.ts +24 -0
  405. package/src/console/ui/traces/critical-path.ts +59 -0
  406. package/src/console/ui/traces/filter.test.ts +78 -0
  407. package/src/console/ui/traces/filter.ts +112 -0
  408. package/src/console/ui/traces/fixture.ts +126 -0
  409. package/src/console/ui/traces/fold.test.ts +67 -0
  410. package/src/console/ui/traces/fold.ts +170 -0
  411. package/src/console/ui/traces/index.ts +64 -0
  412. package/src/console/ui/traces/mini.ts +65 -0
  413. package/src/console/ui/traces/replay.test.ts +24 -0
  414. package/src/console/ui/traces/replay.ts +35 -0
  415. package/src/console/ui/traces/sampling.test.ts +26 -0
  416. package/src/console/ui/traces/sampling.ts +66 -0
  417. package/src/console/ui/traces/search.ts +148 -0
  418. package/src/console/ui/traces/tier.ts +72 -0
  419. package/src/console/ui/traces/types.ts +125 -0
  420. package/src/console/ui/tsconfig.json +20 -0
  421. package/src/console/ui/vault/VaultA11yView.tsx +177 -0
  422. package/src/console/ui/vault/a11y.test.tsx +97 -0
  423. package/src/console/ui/vault/blast-radius.test.ts +35 -0
  424. package/src/console/ui/vault/blast-radius.ts +55 -0
  425. package/src/console/ui/vault/confirmation.test.ts +41 -0
  426. package/src/console/ui/vault/confirmation.ts +39 -0
  427. package/src/console/ui/vault/dormant.test.ts +37 -0
  428. package/src/console/ui/vault/dormant.ts +28 -0
  429. package/src/console/ui/vault/export-safe.test.ts +30 -0
  430. package/src/console/ui/vault/export-safe.ts +65 -0
  431. package/src/console/ui/vault/fixture.ts +75 -0
  432. package/src/console/ui/vault/group.test.ts +25 -0
  433. package/src/console/ui/vault/group.ts +50 -0
  434. package/src/console/ui/vault/index.ts +45 -0
  435. package/src/console/ui/vault/search.ts +62 -0
  436. package/src/console/ui/vault/types.ts +57 -0
  437. package/src/console/ui/vite.config.ts +84 -0
  438. package/src/console/xss.gate.test.ts +118 -0
  439. package/src/docker/compose.ts +226 -0
  440. package/src/docker/credentials.ts +25 -0
  441. package/src/docker/derive.ts +83 -0
  442. package/src/docker/docker.test.ts +185 -0
  443. package/src/docker/dockerfile.integration.test.ts +170 -0
  444. package/src/docker/dockerfile.ts +39 -0
  445. package/src/docker/helpers.ts +103 -0
  446. package/src/docker/index.ts +52 -0
  447. package/src/docker/pin.ts +90 -0
  448. package/src/docker/recipes/index.ts +33 -0
  449. package/src/docker/recipes/postgres.ts +18 -0
  450. package/src/docker/recipes/redis.ts +18 -0
  451. package/src/docker/stack.integration.test.ts +140 -0
  452. package/src/docker/stack.ts +62 -0
  453. package/src/docker/types.ts +134 -0
  454. package/src/drivers/ai-anthropic.ts +128 -0
  455. package/src/drivers/ai-mock.ts +82 -0
  456. package/src/drivers/ai-openai-compatible.ts +139 -0
  457. package/src/drivers/ai-providers.test.ts +163 -0
  458. package/src/drivers/ai-types.ts +83 -0
  459. package/src/drivers/bun-native-completeness.test.ts +155 -0
  460. package/src/drivers/channel-console.ts +118 -0
  461. package/src/drivers/channel-fcm.ts +96 -0
  462. package/src/drivers/channel-resend.ts +27 -0
  463. package/src/drivers/channel-smtp.ts +33 -0
  464. package/src/drivers/channel-types.ts +160 -0
  465. package/src/drivers/channel-unifonic.ts +79 -0
  466. package/src/drivers/channel-wa-cloud.ts +84 -0
  467. package/src/drivers/channel-webpush.ts +317 -0
  468. package/src/drivers/conformance.test.ts +89 -0
  469. package/src/drivers/conformance.ts +162 -0
  470. package/src/drivers/fs.ts +73 -0
  471. package/src/drivers/index.ts +194 -0
  472. package/src/drivers/kv-lua.ts +222 -0
  473. package/src/drivers/memory.ts +472 -0
  474. package/src/drivers/pgvector.ts +130 -0
  475. package/src/drivers/postgres.ts +221 -0
  476. package/src/drivers/redis.ts +254 -0
  477. package/src/drivers/s3.ts +129 -0
  478. package/src/drivers/signal-engine.ts +690 -0
  479. package/src/drivers/signal-memory.ts +27 -0
  480. package/src/drivers/signal-nats.ts +131 -0
  481. package/src/drivers/signal-postgres.ts +1089 -0
  482. package/src/drivers/signal-redis.ts +275 -0
  483. package/src/drivers/signal-types.ts +328 -0
  484. package/src/drivers/sqlite.ts +53 -0
  485. package/src/drivers/types.ts +334 -0
  486. package/src/drivers/vault-dotenv-parse.ts +56 -0
  487. package/src/drivers/vault-env.ts +101 -0
  488. package/src/drivers/vault-infisical.ts +61 -0
  489. package/src/drivers/vault-managed.ts +42 -0
  490. package/src/drivers/vault-memory.ts +38 -0
  491. package/src/drivers/vault-openbao.ts +80 -0
  492. package/src/drivers/vault-sops.ts +252 -0
  493. package/src/drivers/vault-types.ts +84 -0
  494. package/src/elements/ai/declare.ts +206 -0
  495. package/src/elements/ai/eval.ts +113 -0
  496. package/src/elements/ai/pii.ts +108 -0
  497. package/src/elements/ai/runtime.ts +540 -0
  498. package/src/elements/ai/schema.ts +194 -0
  499. package/src/elements/ai.test.ts +393 -0
  500. package/src/elements/ai.ts +56 -0
  501. package/src/elements/channel/consent.ts +81 -0
  502. package/src/elements/channel/costs.test.ts +62 -0
  503. package/src/elements/channel/costs.ts +130 -0
  504. package/src/elements/channel/declare.ts +141 -0
  505. package/src/elements/channel/email-auth.test.ts +47 -0
  506. package/src/elements/channel/email-auth.ts +109 -0
  507. package/src/elements/channel/locale.ts +97 -0
  508. package/src/elements/channel/mask.test.ts +19 -0
  509. package/src/elements/channel/mask.ts +60 -0
  510. package/src/elements/channel/mime.ts +23 -0
  511. package/src/elements/channel/outcomes.test.ts +40 -0
  512. package/src/elements/channel/outcomes.ts +126 -0
  513. package/src/elements/channel/receipts.ts +121 -0
  514. package/src/elements/channel/runtime.ts +500 -0
  515. package/src/elements/channel/suppression.ts +136 -0
  516. package/src/elements/channel.test.ts +232 -0
  517. package/src/elements/channel.ts +109 -0
  518. package/src/elements/clock/actions.ts +170 -0
  519. package/src/elements/clock/declare.ts +58 -0
  520. package/src/elements/clock/dst.ts +197 -0
  521. package/src/elements/clock/durable.ts +140 -0
  522. package/src/elements/clock/duration.ts +29 -0
  523. package/src/elements/clock/health.test.ts +103 -0
  524. package/src/elements/clock/health.ts +112 -0
  525. package/src/elements/clock/leader.ts +127 -0
  526. package/src/elements/clock/reconcile.ts +241 -0
  527. package/src/elements/clock/runtime.ts +243 -0
  528. package/src/elements/clock/schedule.ts +262 -0
  529. package/src/elements/clock/time-travel.ts +53 -0
  530. package/src/elements/clock.test.ts +365 -0
  531. package/src/elements/clock.ts +80 -0
  532. package/src/elements/gate/declare.ts +134 -0
  533. package/src/elements/gate/permissions.ts +104 -0
  534. package/src/elements/gate/runtime.ts +177 -0
  535. package/src/elements/gate/strategies.ts +388 -0
  536. package/src/elements/gate.test.ts +145 -0
  537. package/src/elements/gate.ts +41 -0
  538. package/src/elements/index.ts +169 -0
  539. package/src/elements/signal/chaos-child.ts +47 -0
  540. package/src/elements/signal/declare.ts +77 -0
  541. package/src/elements/signal/dry-run-replay.test.ts +95 -0
  542. package/src/elements/signal/dry-run-write-isolation.test.ts +94 -0
  543. package/src/elements/signal/reconcile.test.ts +23 -0
  544. package/src/elements/signal/reconcile.ts +122 -0
  545. package/src/elements/signal/runtime.ts +94 -0
  546. package/src/elements/signal.test.ts +457 -0
  547. package/src/elements/signal.ts +26 -0
  548. package/src/elements/store/cache.ts +197 -0
  549. package/src/elements/store/classify.ts +125 -0
  550. package/src/elements/store/declare.ts +200 -0
  551. package/src/elements/store/files-policy.test.ts +31 -0
  552. package/src/elements/store/files-policy.ts +70 -0
  553. package/src/elements/store/replica.ts +68 -0
  554. package/src/elements/store/runtime.ts +393 -0
  555. package/src/elements/store/sql-condition.ts +205 -0
  556. package/src/elements/store/sql-session.ts +579 -0
  557. package/src/elements/store/table.ts +282 -0
  558. package/src/elements/store.test.ts +370 -0
  559. package/src/elements/store.ts +99 -0
  560. package/src/elements/vault/declare.ts +143 -0
  561. package/src/elements/vault/fingerprint.ts +30 -0
  562. package/src/elements/vault/redact.ts +52 -0
  563. package/src/elements/vault/runtime.ts +461 -0
  564. package/src/elements/vault.test.ts +296 -0
  565. package/src/elements/vault.ts +44 -0
  566. package/src/index.ts +183 -0
  567. package/src/kernel/adopt-routes.ts +194 -0
  568. package/src/kernel/app.ts +1068 -0
  569. package/src/kernel/auth-resolve.ts +93 -0
  570. package/src/kernel/boot.test.ts +173 -0
  571. package/src/kernel/boot.ts +439 -0
  572. package/src/kernel/budget-entry.ts +55 -0
  573. package/src/kernel/budget.test.ts +19 -0
  574. package/src/kernel/call.test.ts +83 -0
  575. package/src/kernel/capability.ts +113 -0
  576. package/src/kernel/dry-run.test.ts +64 -0
  577. package/src/kernel/dry-run.ts +171 -0
  578. package/src/kernel/effects.test.ts +89 -0
  579. package/src/kernel/effects.ts +140 -0
  580. package/src/kernel/errors.registry.test.ts +39 -0
  581. package/src/kernel/errors.ts +225 -0
  582. package/src/kernel/flow.test.ts +154 -0
  583. package/src/kernel/flow.ts +290 -0
  584. package/src/kernel/fx.test.ts +245 -0
  585. package/src/kernel/fx.ts +996 -0
  586. package/src/kernel/hook-timing.test.ts +72 -0
  587. package/src/kernel/hook-timing.ts +190 -0
  588. package/src/kernel/hooks.test.ts +181 -0
  589. package/src/kernel/hooks.ts +275 -0
  590. package/src/kernel/index.ts +278 -0
  591. package/src/kernel/journal.ts +405 -0
  592. package/src/kernel/journey.ts +75 -0
  593. package/src/kernel/on.ts +74 -0
  594. package/src/kernel/pipeline.test.ts +349 -0
  595. package/src/kernel/pipeline.ts +245 -0
  596. package/src/kernel/plug.ts +82 -0
  597. package/src/kernel/plugin/capabilities.test.ts +84 -0
  598. package/src/kernel/plugin/conflicts.test.ts +106 -0
  599. package/src/kernel/plugin/decorate.test.ts +111 -0
  600. package/src/kernel/plugin/scoping.test.ts +138 -0
  601. package/src/kernel/plugin.ts +485 -0
  602. package/src/kernel/rate-limit.ts +25 -0
  603. package/src/kernel/registry.ts +398 -0
  604. package/src/kernel/router.test.ts +114 -0
  605. package/src/kernel/router.ts +556 -0
  606. package/src/kernel/routing-budget.test.ts +19 -0
  607. package/src/kernel/run-telemetry.ts +70 -0
  608. package/src/kernel/triggers.ts +324 -0
  609. package/src/kernel/unit.ts +88 -0
  610. package/src/manifest/diff.test.ts +866 -0
  611. package/src/manifest/diff.ts +1670 -0
  612. package/src/manifest/fixtures/base.manifest.json +112 -0
  613. package/src/manifest/fixtures/skyport.excerpt.json +51 -0
  614. package/src/manifest/fixtures/skyport.manifest.json +153 -0
  615. package/src/manifest/index.ts +27 -0
  616. package/src/manifest/types.ts +358 -0
  617. package/src/manifest/undeclared.test.ts +82 -0
  618. package/src/manifest/undeclared.ts +65 -0
  619. package/src/manifest/validate.test.ts +105 -0
  620. package/src/manifest/validate.ts +174 -0
  621. package/src/mcp/authorization.ts +340 -0
  622. package/src/mcp/confirmation.ts +174 -0
  623. package/src/mcp/data.ts +90 -0
  624. package/src/mcp/index.ts +80 -0
  625. package/src/mcp/injection.gate.test.ts +176 -0
  626. package/src/mcp/mcp.test.ts +348 -0
  627. package/src/mcp/protocol.ts +172 -0
  628. package/src/mcp/server.ts +283 -0
  629. package/src/mcp/session.ts +139 -0
  630. package/src/mcp/tools.ts +391 -0
  631. package/src/plugins/catalogue.test.ts +48 -0
  632. package/src/plugins/catalogue.ts +113 -0
  633. package/src/plugins/node-import-scan.test.ts +28 -0
  634. package/src/plugins/node-import-scan.ts +98 -0
  635. package/src/plugins/supply-chain.test.ts +48 -0
  636. package/src/plugins/supply-chain.ts +460 -0
  637. package/src/release/index.ts +30 -0
  638. package/src/release/limits.ts +20 -0
  639. package/src/release/measure.ts +443 -0
  640. package/src/release/publish.ts +56 -0
  641. package/src/runs/bench.test.ts +93 -0
  642. package/src/runs/collect.ts +144 -0
  643. package/src/runs/drivers/clickhouse.ts +108 -0
  644. package/src/runs/drivers/files.ts +201 -0
  645. package/src/runs/drivers/memory.ts +94 -0
  646. package/src/runs/drivers/postgres.ts +110 -0
  647. package/src/runs/duckdb.ts +99 -0
  648. package/src/runs/index.ts +82 -0
  649. package/src/runs/outlier.ts +180 -0
  650. package/src/runs/parquet.ts +210 -0
  651. package/src/runs/privacy.ts +49 -0
  652. package/src/runs/runs.test.ts +324 -0
  653. package/src/runs/runtime.ts +229 -0
  654. package/src/runs/shred.ts +243 -0
  655. package/src/runs/telemetry.ts +10 -0
  656. package/src/runs/types.ts +179 -0
  657. package/src/runtime/bun.ts +140 -0
  658. package/src/runtime/cold-start.bench.ts +20 -0
  659. package/src/runtime/index.ts +46 -0
  660. package/src/runtime/primitives.ts +242 -0
  661. package/src/runtime/security.test.ts +170 -0
  662. package/src/runtime/security.ts +168 -0
  663. package/src/runtime/serve.test.ts +223 -0
  664. package/src/runtime/types.ts +217 -0
  665. package/src/runtime/web-standard.ts +77 -0
  666. package/src/test/create-test-app.test.ts +161 -0
  667. package/src/test/create-test-app.ts +533 -0
  668. package/src/test/index.ts +21 -0
  669. package/src/test/provisions.integration.test.ts +174 -0
  670. package/src/upgrade/codemods.test.ts +58 -0
  671. package/src/upgrade/codemods.ts +83 -0
  672. package/src/validation/index.ts +23 -0
  673. package/src/validation/standard-schema.test.ts +96 -0
  674. package/src/validation/standard-schema.ts +316 -0
@@ -0,0 +1,869 @@
1
+ /**
2
+ * Console Gates projection — two inquiries, simulator, continuous audit
3
+ * (console §9.7).
4
+ *
5
+ * The simulator evaluates the real gate chain via {@link GateRuntime.check}
6
+ * only — never the flow handler, never application data. Rate takes use an
7
+ * ephemeral memory KV so production counters are untouched.
8
+ */
9
+
10
+ import {
11
+ createApiKeyStore,
12
+ createRoleStore,
13
+ listRoleGrants,
14
+ scopesForRoles,
15
+ setRoleGrants,
16
+ upsertRole,
17
+ type ApiKeyStore,
18
+ type RoleStore,
19
+ } from "../../auth/index.ts";
20
+ import { memoryKvDriver } from "../../drivers/memory.ts";
21
+ import {
22
+ createGateRuntime,
23
+ deriveModuleActions,
24
+ gate,
25
+ type GateDecl,
26
+ type GateEvaluation,
27
+ type GatePolicyContext,
28
+ type GateRuntime,
29
+ type RateGateDecl,
30
+ } from "../../elements/gate.ts";
31
+ import { statusForFailure } from "../../compiler/response.ts";
32
+ import { gateDenialFailure } from "../../kernel/index.ts";
33
+ import { diffManifest } from "../../manifest/diff.ts";
34
+ import type {
35
+ Gate as ManifestGate,
36
+ Manifest,
37
+ ManifestChange,
38
+ } from "../../manifest/types.ts";
39
+
40
+ /** Identity slice needed for Gates (avoids circular import with state). */
41
+ export interface GatesIdentity {
42
+ readonly id: string;
43
+ readonly email: string;
44
+ readonly name: string;
45
+ readonly status: "active" | "disabled";
46
+ readonly scopes: readonly string[];
47
+ }
48
+
49
+ /** Principal kinds in the Gates inquiry (console §9.7). */
50
+ export type GatePrincipalKind = "role" | "key" | "user";
51
+
52
+ /** One Module:Action / flow / gate surface row. */
53
+ export interface ConsoleGateDefRow {
54
+ readonly name: string;
55
+ readonly kind: "policy" | "rate";
56
+ readonly scopes: readonly string[];
57
+ readonly roles: readonly string[];
58
+ readonly strategy?: string;
59
+ readonly max?: number;
60
+ readonly per?: string;
61
+ readonly keyBy?: string;
62
+ readonly overridable: boolean;
63
+ /** Flow ids that attach this gate (registration order preserved per flow). */
64
+ readonly attachedTo: readonly string[];
65
+ }
66
+
67
+ /** One flow's gate chain in registration order. */
68
+ export interface ConsoleFlowGatesRow {
69
+ readonly flowId: string;
70
+ readonly plane: "user" | "operator";
71
+ readonly gates: readonly string[];
72
+ /** User-plane with empty chain — public. */
73
+ readonly unguarded: boolean;
74
+ }
75
+
76
+ /**
77
+ * A principal shown as a normal row.
78
+ * Operators holding application scopes never appear here — see violations.
79
+ */
80
+ export interface ConsolePrincipalRow {
81
+ readonly kind: GatePrincipalKind;
82
+ readonly id: string;
83
+ readonly name: string;
84
+ readonly plane: "user" | "operator";
85
+ readonly scopes: readonly string[];
86
+ /** Role membership count (roles only). */
87
+ readonly memberCount?: number;
88
+ readonly email?: string;
89
+ }
90
+
91
+ /** Operator holding an application scope — violation, never a normal row. */
92
+ export interface ConsolePlaneViolation {
93
+ readonly kind: "operator-application-scope";
94
+ readonly operatorId: string;
95
+ readonly name: string;
96
+ readonly email: string;
97
+ readonly applicationScopes: readonly string[];
98
+ }
99
+
100
+ /** Continuous security audit findings (console §9.7). */
101
+ export interface ConsoleGateAudit {
102
+ readonly unguardedFlows: readonly string[];
103
+ readonly orphanPermissions: readonly string[];
104
+ readonly emptyRoles: readonly string[];
105
+ readonly unattachedGates: readonly string[];
106
+ }
107
+
108
+ /** Full Gates panel projection. */
109
+ export interface GatesPanelProjection {
110
+ readonly moduleActions: readonly string[];
111
+ readonly flows: readonly ConsoleFlowGatesRow[];
112
+ readonly gates: readonly ConsoleGateDefRow[];
113
+ readonly principals: readonly ConsolePrincipalRow[];
114
+ readonly violations: readonly ConsolePlaneViolation[];
115
+ readonly audit: ConsoleGateAudit;
116
+ readonly widenings: readonly ManifestChange[];
117
+ }
118
+
119
+ /** Input to the evaluate-only simulator. */
120
+ export interface SimulateGatesInput {
121
+ readonly flowId: string;
122
+ readonly principal: {
123
+ readonly kind: GatePrincipalKind;
124
+ readonly id: string;
125
+ };
126
+ readonly meta?: {
127
+ readonly ip?: string;
128
+ };
129
+ }
130
+
131
+ /** Typed denial the client would receive. */
132
+ export interface SimulateGateDenial {
133
+ readonly code: "Unauthorized" | "Forbidden" | "RateLimited";
134
+ readonly data: Readonly<Record<string, unknown>>;
135
+ readonly status: 401 | 403 | 429;
136
+ }
137
+
138
+ /** Simulator result — ordered evaluations + first denial. */
139
+ export interface SimulateGatesResult {
140
+ readonly flowId: string;
141
+ readonly gates: readonly string[];
142
+ readonly evaluations: readonly GateEvaluation[];
143
+ readonly deniedAt: string | null;
144
+ readonly denial: SimulateGateDenial | null;
145
+ readonly allowed: boolean;
146
+ }
147
+
148
+ /** Options for {@link projectGatesPanel}. */
149
+ export interface ProjectGatesOptions {
150
+ readonly manifest: Manifest | null;
151
+ readonly roles: RoleStore;
152
+ readonly apiKeys: ApiKeyStore;
153
+ readonly identities: readonly GatesIdentity[];
154
+ /** operatorId → role ids. */
155
+ readonly operatorRoles: ReadonlyMap<string, readonly string[]>;
156
+ /** operatorId → { name, email }. */
157
+ readonly operators: ReadonlyMap<
158
+ string,
159
+ { readonly name: string; readonly email: string }
160
+ >;
161
+ /** roleId → member principal ids (users + operators). */
162
+ readonly roleMembers: ReadonlyMap<string, readonly string[]>;
163
+ /** Previous Manifest for deploy-diff widenings (optional). */
164
+ readonly previousManifest?: Manifest | null;
165
+ }
166
+
167
+ /** Options for {@link simulateGates}. */
168
+ export interface SimulateGatesOptions extends SimulateGatesInput {
169
+ readonly manifest: Manifest | null;
170
+ /** Live GateRuntime from boot (A) — preferred. */
171
+ readonly gateRuntime: GateRuntime | null;
172
+ readonly roles: RoleStore;
173
+ readonly apiKeys: ApiKeyStore;
174
+ readonly identities: readonly GatesIdentity[];
175
+ readonly now?: () => number;
176
+ }
177
+
178
+ /**
179
+ * Whether a Module:Action is an application (user-plane) scope.
180
+ * Console scopes are `console:*` (console §3.4 · §9.7 · §9.14).
181
+ *
182
+ * @param action - Module:Action pair
183
+ */
184
+ export function isApplicationScope(action: string): boolean {
185
+ return !action.startsWith("console:");
186
+ }
187
+
188
+ /**
189
+ * Project Manifest + auth data into the Gates panel.
190
+ *
191
+ * @param options - Manifest, roles, keys, identities, operators
192
+ */
193
+ export function projectGatesPanel(
194
+ options: ProjectGatesOptions,
195
+ ): GatesPanelProjection {
196
+ const manifest = options.manifest;
197
+ const moduleActions = manifest ? deriveModuleActions(manifest) : [];
198
+ const flows = projectFlows(manifest);
199
+ const gates = projectGateDefs(manifest, flows);
200
+ const { principals, violations } = projectPrincipals(options);
201
+ const audit = buildAudit({
202
+ moduleActions,
203
+ flows,
204
+ gates,
205
+ roles: options.roles,
206
+ roleMembers: options.roleMembers,
207
+ });
208
+ const widenings = projectWidenings(
209
+ options.previousManifest ?? null,
210
+ manifest,
211
+ );
212
+
213
+ return {
214
+ moduleActions,
215
+ flows,
216
+ gates,
217
+ principals,
218
+ violations,
219
+ audit,
220
+ widenings,
221
+ };
222
+ }
223
+
224
+ /**
225
+ * Simulate one call: evaluate the flow's gate chain in registration order
226
+ * via the real GateRuntime, stop at first denial, map to the typed client
227
+ * error. Never invokes the flow handler.
228
+ *
229
+ * @param options - Flow, principal, runtime
230
+ */
231
+ export async function simulateGates(
232
+ options: SimulateGatesOptions,
233
+ ): Promise<SimulateGatesResult> {
234
+ const flow = options.manifest?.flows?.[options.flowId];
235
+ if (!flow) {
236
+ return {
237
+ flowId: options.flowId,
238
+ gates: [],
239
+ evaluations: [],
240
+ deniedAt: null,
241
+ denial: {
242
+ code: "Forbidden",
243
+ data: { gate: options.flowId, reason: "unknown flow" },
244
+ status: 403,
245
+ },
246
+ allowed: false,
247
+ };
248
+ }
249
+
250
+ const names = [...(flow.gates ?? [])];
251
+ const resolved = resolvePrincipalContext(options);
252
+ if (!resolved) {
253
+ return {
254
+ flowId: options.flowId,
255
+ gates: names,
256
+ evaluations: [],
257
+ deniedAt: null,
258
+ denial: {
259
+ code: "Unauthorized",
260
+ data: {},
261
+ status: 401,
262
+ },
263
+ allowed: false,
264
+ };
265
+ }
266
+
267
+ const { runtime, close } = await openSimulationRuntime(
268
+ options.gateRuntime,
269
+ options.manifest,
270
+ options.now ?? (() => Date.now()),
271
+ );
272
+
273
+ try {
274
+ if (names.length === 0) {
275
+ return {
276
+ flowId: options.flowId,
277
+ gates: names,
278
+ evaluations: [],
279
+ deniedAt: null,
280
+ denial: null,
281
+ allowed: true,
282
+ };
283
+ }
284
+
285
+ const evaluations = await runtime.check(names, resolved.ctx);
286
+ const denied = evaluations.find((e) => !e.allowed);
287
+ if (!denied) {
288
+ return {
289
+ flowId: options.flowId,
290
+ gates: names,
291
+ evaluations,
292
+ deniedAt: null,
293
+ denial: null,
294
+ allowed: true,
295
+ };
296
+ }
297
+
298
+ const failure = gateDenialFailure(denied, resolved.ctx);
299
+ const status = statusForFailure(failure) as 401 | 403 | 429;
300
+ const code = failure.error.code as SimulateGateDenial["code"];
301
+ return {
302
+ flowId: options.flowId,
303
+ gates: names,
304
+ evaluations,
305
+ deniedAt: denied.name,
306
+ denial: {
307
+ code,
308
+ data: (failure.error.data ?? {}) as Record<string, unknown>,
309
+ status,
310
+ },
311
+ allowed: false,
312
+ };
313
+ } finally {
314
+ await close();
315
+ }
316
+ }
317
+
318
+ /**
319
+ * What a principal can do — scopes plus flows whose full gate chain allows.
320
+ *
321
+ * @param options - Principal + runtime context
322
+ */
323
+ export async function powersForPrincipal(options: {
324
+ readonly kind: GatePrincipalKind;
325
+ readonly id: string;
326
+ readonly manifest: Manifest | null;
327
+ readonly gateRuntime: GateRuntime | null;
328
+ readonly roles: RoleStore;
329
+ readonly apiKeys: ApiKeyStore;
330
+ readonly identities: readonly GatesIdentity[];
331
+ readonly now?: () => number;
332
+ }): Promise<{
333
+ readonly scopes: readonly string[];
334
+ readonly allowedFlowIds: readonly string[];
335
+ readonly deniedFlowIds: readonly string[];
336
+ }> {
337
+ const flows = projectFlows(options.manifest);
338
+ let scopes: string[] = [];
339
+ if (options.kind === "user") {
340
+ scopes = [
341
+ ...(options.identities.find((u) => u.id === options.id)?.scopes ?? []),
342
+ ];
343
+ } else if (options.kind === "role") {
344
+ scopes = [...(options.roles.grants.get(options.id) ?? [])];
345
+ } else {
346
+ scopes = [...(options.apiKeys.keys.get(options.id)?.scopes ?? [])];
347
+ }
348
+ scopes.sort((a, b) => a.localeCompare(b));
349
+
350
+ const allowedFlowIds: string[] = [];
351
+ const deniedFlowIds: string[] = [];
352
+
353
+ for (const flow of flows) {
354
+ // User/key inquiry is application power; skip operator-plane flows.
355
+ if (
356
+ flow.plane === "operator" &&
357
+ (options.kind === "user" || options.kind === "key")
358
+ ) {
359
+ continue;
360
+ }
361
+ const result = await simulateGates({
362
+ flowId: flow.flowId,
363
+ principal: { kind: options.kind, id: options.id },
364
+ manifest: options.manifest,
365
+ gateRuntime: options.gateRuntime,
366
+ roles: options.roles,
367
+ apiKeys: options.apiKeys,
368
+ identities: options.identities,
369
+ now: options.now,
370
+ });
371
+ if (result.allowed) allowedFlowIds.push(flow.flowId);
372
+ else deniedFlowIds.push(flow.flowId);
373
+ }
374
+
375
+ return { scopes, allowedFlowIds, deniedFlowIds };
376
+ }
377
+
378
+ /**
379
+ * Build a GateRuntime from Manifest gate defs when no live runtime is bound.
380
+ * Policy predicates honour scopes / verified — rate gates use real strategies.
381
+ *
382
+ * @param manifest - Manifest snapshot
383
+ * @param now - Clock
384
+ */
385
+ export async function createManifestGateRuntime(
386
+ manifest: Manifest,
387
+ now: () => number = () => Date.now(),
388
+ ): Promise<{ readonly runtime: GateRuntime; readonly close: () => Promise<void> }> {
389
+ const kv = await memoryKvDriver.open({
390
+ name: `oke:gates:manifest:${crypto.randomUUID()}`,
391
+ });
392
+ const decls = declsFromManifest(manifest);
393
+ return {
394
+ runtime: createGateRuntime({ gates: decls, kv, now }),
395
+ close: async () => {
396
+ await kv.close();
397
+ },
398
+ };
399
+ }
400
+
401
+ /**
402
+ * Seed a RoleStore + ApiKeyStore for Console / tests (console §3.2–3.3).
403
+ */
404
+ export function createDefaultGateAuthStores(): {
405
+ readonly roles: RoleStore;
406
+ readonly apiKeys: ApiKeyStore;
407
+ readonly roleMembers: Map<string, string[]>;
408
+ } {
409
+ const roles = createRoleStore();
410
+ upsertRole(roles, {
411
+ id: "role_member",
412
+ name: "member",
413
+ plane: "user",
414
+ description: "Verified members",
415
+ });
416
+ upsertRole(roles, {
417
+ id: "role_staff",
418
+ name: "staff",
419
+ plane: "user",
420
+ description: "Staff",
421
+ });
422
+ upsertRole(roles, {
423
+ id: "role_ops",
424
+ name: "ops",
425
+ plane: "operator",
426
+ description: "Console operators",
427
+ });
428
+ setRoleGrants(roles, "role_member", ["member", "booking:create"]);
429
+ setRoleGrants(roles, "role_staff", [
430
+ "member",
431
+ "booking:create",
432
+ "staff",
433
+ "reports:export",
434
+ ]);
435
+ setRoleGrants(roles, "role_ops", [
436
+ "console:store.sql:read",
437
+ "console:store.sql:write",
438
+ "console:flows:invoke-as",
439
+ ]);
440
+
441
+ const apiKeys = createApiKeyStore();
442
+ apiKeys.keys.set("key_demo", {
443
+ id: "key_demo",
444
+ plane: "user",
445
+ hash: "demo",
446
+ name: "Demo key",
447
+ scopes: ["member", "booking:create"],
448
+ expiresAt: null,
449
+ rateLimit: null,
450
+ ipAllowlist: [],
451
+ creatorId: "user_demo",
452
+ creatorScopes: ["member", "booking:create"],
453
+ createdAt: 0,
454
+ lastUsedAt: null,
455
+ revokedAt: null,
456
+ });
457
+
458
+ const roleMembers = new Map<string, string[]>([
459
+ ["role_member", ["user_demo", "user_member"]],
460
+ ["role_staff", []],
461
+ ["role_ops", []],
462
+ ]);
463
+
464
+ return { roles, apiKeys, roleMembers };
465
+ }
466
+
467
+ // ── internals ──────────────────────────────────────────────────────────────
468
+
469
+ function projectFlows(manifest: Manifest | null): ConsoleFlowGatesRow[] {
470
+ if (!manifest?.flows) return [];
471
+ const rows: ConsoleFlowGatesRow[] = [];
472
+ for (const [flowId, flow] of Object.entries(manifest.flows)) {
473
+ const plane = flow.plane === "operator" ? "operator" : "user";
474
+ const gates = [...(flow.gates ?? [])];
475
+ rows.push({
476
+ flowId,
477
+ plane,
478
+ gates,
479
+ unguarded: plane === "user" && gates.length === 0,
480
+ });
481
+ }
482
+ return rows.sort((a, b) => a.flowId.localeCompare(b.flowId));
483
+ }
484
+
485
+ function projectGateDefs(
486
+ manifest: Manifest | null,
487
+ flows: readonly ConsoleFlowGatesRow[],
488
+ ): ConsoleGateDefRow[] {
489
+ const attached = new Map<string, string[]>();
490
+ for (const flow of flows) {
491
+ for (const name of flow.gates) {
492
+ const list = attached.get(name) ?? [];
493
+ list.push(flow.flowId);
494
+ attached.set(name, list);
495
+ }
496
+ }
497
+
498
+ const rows: ConsoleGateDefRow[] = [];
499
+ for (const [name, def] of Object.entries(manifest?.gates ?? {})) {
500
+ const kind: "policy" | "rate" =
501
+ def.kind === "rate" || name.startsWith("rate:") ? "rate" : "policy";
502
+ rows.push({
503
+ name,
504
+ kind,
505
+ scopes: [...(def.scopes ?? [])],
506
+ roles: [...(def.roles ?? [])],
507
+ strategy: def.strategy,
508
+ max: def.max,
509
+ per: def.per,
510
+ keyBy: def.keyBy,
511
+ overridable: Boolean(
512
+ (def as ManifestGate & { overridable?: boolean }).overridable,
513
+ ),
514
+ attachedTo: attached.get(name) ?? [],
515
+ });
516
+ }
517
+
518
+ // Gates attached on flows but missing from manifest.gates still surface.
519
+ for (const [name, flowIds] of attached) {
520
+ if (rows.some((r) => r.name === name)) continue;
521
+ const kind: "policy" | "rate" = name.startsWith("rate:") ? "rate" : "policy";
522
+ rows.push({
523
+ name,
524
+ kind,
525
+ scopes: [],
526
+ roles: [],
527
+ overridable: false,
528
+ attachedTo: flowIds,
529
+ });
530
+ }
531
+
532
+ return rows.sort((a, b) => a.name.localeCompare(b.name));
533
+ }
534
+
535
+ function projectPrincipals(options: ProjectGatesOptions): {
536
+ readonly principals: ConsolePrincipalRow[];
537
+ readonly violations: ConsolePlaneViolation[];
538
+ } {
539
+ const principals: ConsolePrincipalRow[] = [];
540
+ const violations: ConsolePlaneViolation[] = [];
541
+
542
+ for (const role of options.roles.roles.values()) {
543
+ const scopes = [...(options.roles.grants.get(role.id) ?? [])].sort();
544
+ if (role.plane === "operator") {
545
+ const appScopes = scopes.filter(isApplicationScope);
546
+ if (appScopes.length > 0) {
547
+ // Role itself is poisoned — surface as violation via synthetic id.
548
+ violations.push({
549
+ kind: "operator-application-scope",
550
+ operatorId: `role:${role.id}`,
551
+ name: `role ${role.name}`,
552
+ email: "",
553
+ applicationScopes: appScopes,
554
+ });
555
+ continue;
556
+ }
557
+ }
558
+ principals.push({
559
+ kind: "role",
560
+ id: role.id,
561
+ name: role.name,
562
+ plane: role.plane,
563
+ scopes,
564
+ memberCount: options.roleMembers.get(role.id)?.length ?? 0,
565
+ });
566
+ }
567
+
568
+ for (const key of options.apiKeys.keys.values()) {
569
+ const scopes = [...key.scopes].sort();
570
+ if (key.plane === "operator") {
571
+ const appScopes = scopes.filter(isApplicationScope);
572
+ if (appScopes.length > 0) {
573
+ violations.push({
574
+ kind: "operator-application-scope",
575
+ operatorId: `key:${key.id}`,
576
+ name: key.name,
577
+ email: "",
578
+ applicationScopes: appScopes,
579
+ });
580
+ continue;
581
+ }
582
+ }
583
+ principals.push({
584
+ kind: "key",
585
+ id: key.id,
586
+ name: key.name,
587
+ plane: key.plane,
588
+ scopes,
589
+ });
590
+ }
591
+
592
+ for (const user of options.identities) {
593
+ principals.push({
594
+ kind: "user",
595
+ id: user.id,
596
+ name: user.name,
597
+ plane: "user",
598
+ scopes: [...user.scopes].sort(),
599
+ email: user.email,
600
+ });
601
+ }
602
+
603
+ // Operators: only those with clean console scopes appear… but Access owns
604
+ // operator listing. Gates only surfaces the violation when they hold app scopes.
605
+ for (const [operatorId, roleIds] of options.operatorRoles) {
606
+ const scopes = [
607
+ ...scopesForRoles(options.roles, roleIds, "operator"),
608
+ ].sort();
609
+ const appScopes = scopes.filter(isApplicationScope);
610
+ if (appScopes.length === 0) continue;
611
+ const op = options.operators.get(operatorId);
612
+ violations.push({
613
+ kind: "operator-application-scope",
614
+ operatorId,
615
+ name: op?.name ?? operatorId,
616
+ email: op?.email ?? "",
617
+ applicationScopes: appScopes,
618
+ });
619
+ }
620
+
621
+ principals.sort((a, b) => {
622
+ const kindOrder = { role: 0, key: 1, user: 2 } as const;
623
+ const d = kindOrder[a.kind] - kindOrder[b.kind];
624
+ return d !== 0 ? d : a.name.localeCompare(b.name);
625
+ });
626
+
627
+ return { principals, violations };
628
+ }
629
+
630
+ function buildAudit(options: {
631
+ readonly moduleActions: readonly string[];
632
+ readonly flows: readonly ConsoleFlowGatesRow[];
633
+ readonly gates: readonly ConsoleGateDefRow[];
634
+ readonly roles: RoleStore;
635
+ readonly roleMembers: ReadonlyMap<string, readonly string[]>;
636
+ }): ConsoleGateAudit {
637
+ const granted = new Set<string>();
638
+ for (const row of listRoleGrants(options.roles)) {
639
+ granted.add(row.action);
640
+ }
641
+
642
+ const orphanPermissions = options.moduleActions
643
+ .filter((a) => !granted.has(a))
644
+ .sort((a, b) => a.localeCompare(b));
645
+
646
+ const emptyRoles = [...options.roles.roles.values()]
647
+ .filter((r) => (options.roleMembers.get(r.id)?.length ?? 0) === 0)
648
+ .map((r) => r.id)
649
+ .sort((a, b) => a.localeCompare(b));
650
+
651
+ const unattachedGates = options.gates
652
+ .filter((g) => g.attachedTo.length === 0)
653
+ .map((g) => g.name)
654
+ .sort((a, b) => a.localeCompare(b));
655
+
656
+ const unguardedFlows = options.flows
657
+ .filter((f) => f.unguarded)
658
+ .map((f) => f.flowId);
659
+
660
+ return {
661
+ unguardedFlows,
662
+ orphanPermissions,
663
+ emptyRoles,
664
+ unattachedGates,
665
+ };
666
+ }
667
+
668
+ function projectWidenings(
669
+ before: Manifest | null,
670
+ after: Manifest | null,
671
+ ): ManifestChange[] {
672
+ if (!before || !after) return [];
673
+ const diff = diffManifest(before, after);
674
+ return diff.changes.filter((c) => c.category === "permission-widening");
675
+ }
676
+
677
+ function resolvePrincipalContext(options: SimulateGatesOptions): {
678
+ readonly ctx: GatePolicyContext;
679
+ } | null {
680
+ const { kind, id } = options.principal;
681
+ if (kind === "user") {
682
+ const user = options.identities.find((u) => u.id === id);
683
+ if (!user || user.status === "disabled") return null;
684
+ return {
685
+ ctx: {
686
+ auth: {
687
+ userId: user.id,
688
+ scopes: new Set(user.scopes),
689
+ verified: true,
690
+ },
691
+ operator: { id: null },
692
+ meta: {
693
+ ip: options.meta?.ip,
694
+ userId: user.id,
695
+ },
696
+ },
697
+ };
698
+ }
699
+ if (kind === "role") {
700
+ const role = options.roles.roles.get(id);
701
+ if (!role) return null;
702
+ const scopes = options.roles.grants.get(id) ?? new Set();
703
+ if (role.plane === "operator") {
704
+ return {
705
+ ctx: {
706
+ auth: { userId: null, scopes: new Set(), verified: false },
707
+ operator: { id: `role:${id}` },
708
+ meta: { ip: options.meta?.ip },
709
+ },
710
+ };
711
+ }
712
+ return {
713
+ ctx: {
714
+ auth: {
715
+ userId: `role:${id}`,
716
+ scopes: new Set(scopes),
717
+ verified: scopes.has("member") || scopes.size > 0,
718
+ },
719
+ operator: { id: null },
720
+ meta: { ip: options.meta?.ip, userId: `role:${id}` },
721
+ },
722
+ };
723
+ }
724
+ // key
725
+ const key = options.apiKeys.keys.get(id);
726
+ if (!key) return null;
727
+ if (key.plane === "operator") {
728
+ return {
729
+ ctx: {
730
+ auth: { userId: null, scopes: new Set(), verified: false },
731
+ operator: { id: `key:${id}` },
732
+ meta: { ip: options.meta?.ip },
733
+ },
734
+ };
735
+ }
736
+ return {
737
+ ctx: {
738
+ auth: {
739
+ userId: `key:${id}`,
740
+ scopes: new Set(key.scopes),
741
+ verified: true,
742
+ },
743
+ operator: { id: null },
744
+ meta: { ip: options.meta?.ip, userId: `key:${id}` },
745
+ },
746
+ };
747
+ }
748
+
749
+ async function openSimulationRuntime(
750
+ live: GateRuntime | null,
751
+ manifest: Manifest | null,
752
+ now: () => number,
753
+ ): Promise<{
754
+ readonly runtime: GateRuntime;
755
+ readonly close: () => Promise<void>;
756
+ }> {
757
+ const kv = await memoryKvDriver.open({
758
+ name: `oke:gates:sim:${crypto.randomUUID()}`,
759
+ });
760
+ const decls: GateDecl[] = live
761
+ ? [...live.gates.values()]
762
+ : manifest
763
+ ? declsFromManifest(manifest)
764
+ : [];
765
+ return {
766
+ runtime: createGateRuntime({ gates: decls, kv, now }),
767
+ close: async () => {
768
+ await kv.close();
769
+ },
770
+ };
771
+ }
772
+
773
+ /**
774
+ * Reconstruct GateDecl list from Manifest for Console-only boots.
775
+ * Live apps should bind the real GateRuntime instead.
776
+ *
777
+ * @param manifest - Manifest
778
+ */
779
+ export function declsFromManifest(manifest: Manifest): GateDecl[] {
780
+ const decls: GateDecl[] = [];
781
+ const seen = new Set<string>();
782
+
783
+ for (const [name, def] of Object.entries(manifest.gates ?? {})) {
784
+ seen.add(name);
785
+ decls.push(declFromManifestGate(name, def));
786
+ }
787
+
788
+ // Flow-attached names missing from manifest.gates.
789
+ for (const flow of Object.values(manifest.flows ?? {})) {
790
+ for (const name of flow.gates ?? []) {
791
+ if (seen.has(name)) continue;
792
+ seen.add(name);
793
+ if (name.startsWith("rate:")) {
794
+ const parsed = parseRateName(name);
795
+ decls.push({
796
+ kind: "rate",
797
+ name,
798
+ strategy: parsed.strategy,
799
+ max: parsed.max,
800
+ per: parsed.per,
801
+ keyBy: "user",
802
+ overridable: false,
803
+ } satisfies RateGateDecl);
804
+ } else {
805
+ decls.push(
806
+ gate.policy(name, (ctx) => {
807
+ if (name.includes(":")) return ctx.auth.scopes.has(name);
808
+ return Boolean(ctx.auth.verified);
809
+ }),
810
+ );
811
+ }
812
+ }
813
+ }
814
+
815
+ return decls;
816
+ }
817
+
818
+ function declFromManifestGate(name: string, def: ManifestGate): GateDecl {
819
+ if (def.kind === "rate" || name.startsWith("rate:")) {
820
+ const parsed = name.startsWith("rate:")
821
+ ? parseRateName(name)
822
+ : {
823
+ strategy: def.strategy ?? "sliding-window-counter",
824
+ max: def.max ?? 1,
825
+ per: def.per ?? "1m",
826
+ };
827
+ return {
828
+ kind: "rate",
829
+ name,
830
+ strategy: (def.strategy ?? parsed.strategy) as RateGateDecl["strategy"],
831
+ max: def.max ?? parsed.max,
832
+ per: def.per ?? parsed.per,
833
+ keyBy: def.keyBy,
834
+ overridable: Boolean(
835
+ (def as ManifestGate & { overridable?: boolean }).overridable,
836
+ ),
837
+ };
838
+ }
839
+
840
+ const scopes = def.scopes ?? [];
841
+ return gate.policy(name, (ctx) => {
842
+ if (scopes.length > 0) {
843
+ return scopes.every((s) => ctx.auth.scopes.has(s));
844
+ }
845
+ if (name.includes(":")) return ctx.auth.scopes.has(name);
846
+ return Boolean(ctx.auth.verified);
847
+ });
848
+ }
849
+
850
+ /** Parse `rate:{strategy}:{max}/{per}`. */
851
+ function parseRateName(name: string): {
852
+ strategy: RateGateDecl["strategy"];
853
+ max: number;
854
+ per: string;
855
+ } {
856
+ // rate:sliding-window-counter:300/1m
857
+ const rest = name.slice("rate:".length);
858
+ const lastColon = rest.lastIndexOf(":");
859
+ if (lastColon === -1) {
860
+ return { strategy: "sliding-window-counter", max: 1, per: "1m" };
861
+ }
862
+ const strategy = rest.slice(0, lastColon) as RateGateDecl["strategy"];
863
+ const [maxStr, per = "1m"] = rest.slice(lastColon + 1).split("/");
864
+ return {
865
+ strategy: strategy || "sliding-window-counter",
866
+ max: Number(maxStr) || 1,
867
+ per,
868
+ };
869
+ }