okengine 0.10.2 → 0.11.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 (343) hide show
  1. package/package.json +76 -10
  2. package/site/content/docs/ai/mcp.mdx +0 -1
  3. package/site/content/docs/deployment/docker-swarm.mdx +48 -111
  4. package/site/content/docs/deployment/docker.mdx +43 -36
  5. package/site/content/docs/deployment/index.mdx +9 -9
  6. package/site/content/docs/deployment/kubernetes.mdx +4 -4
  7. package/site/content/docs/elements/ai.mdx +7 -13
  8. package/site/content/docs/elements/channel.mdx +9 -13
  9. package/site/content/docs/elements/clock.mdx +8 -14
  10. package/site/content/docs/elements/flow.mdx +46 -54
  11. package/site/content/docs/elements/gate.mdx +6 -11
  12. package/site/content/docs/elements/signal.mdx +2 -8
  13. package/site/content/docs/elements/store.mdx +79 -93
  14. package/site/content/docs/elements/vault.mdx +89 -76
  15. package/site/content/docs/get-started/basic-usage.mdx +8 -14
  16. package/site/content/docs/get-started/installation.mdx +36 -36
  17. package/site/content/docs/get-started/introduction.mdx +11 -0
  18. package/site/content/docs/get-started/why.mdx +3 -4
  19. package/site/content/docs/index.mdx +0 -1
  20. package/site/content/docs/meta.json +0 -1
  21. package/site/content/docs/plugins/anonymous.mdx +1 -1
  22. package/site/content/docs/plugins/magic-link.mdx +11 -11
  23. package/site/content/docs/plugins/otp.mdx +2 -2
  24. package/site/content/docs/plugins/passkey.mdx +1 -1
  25. package/site/content/docs/plugins/two-factor.mdx +1 -1
  26. package/site/content/docs/plugins/username.mdx +1 -1
  27. package/site/content/docs/recipes/caddy.mdx +1 -1
  28. package/site/content/docs/recipes/cockroachdb.mdx +2 -2
  29. package/site/content/docs/recipes/dragonfly.mdx +1 -1
  30. package/site/content/docs/recipes/index.mdx +1 -2
  31. package/site/content/docs/recipes/llama-cpp.mdx +21 -23
  32. package/site/content/docs/recipes/mailpit.mdx +11 -11
  33. package/site/content/docs/recipes/meilisearch.mdx +10 -10
  34. package/site/content/docs/recipes/meta.json +0 -1
  35. package/site/content/docs/recipes/ollama.mdx +1 -1
  36. package/site/content/docs/recipes/pgdog.mdx +12 -9
  37. package/site/content/docs/recipes/postgres.mdx +3 -3
  38. package/site/content/docs/recipes/redis.mdx +2 -2
  39. package/site/content/docs/recipes/rustfs.mdx +10 -7
  40. package/site/content/docs/recipes/sglang.mdx +1 -1
  41. package/site/content/docs/recipes/supabase-docker.mdx +1 -1
  42. package/site/content/docs/recipes/timescale.mdx +2 -2
  43. package/site/content/docs/recipes/valkey.mdx +1 -1
  44. package/site/content/docs/recipes/vllm.mdx +1 -1
  45. package/site/content/docs/recipes/yugabytedb.mdx +2 -2
  46. package/site/content/docs/reference/cli.md +61 -38
  47. package/site/content/docs/reference/configuration.mdx +145 -70
  48. package/site/content/docs/reference/environment-variables.mdx +36 -28
  49. package/site/content/docs/reference/errors.mdx +28 -29
  50. package/site/content/docs/reference/fx.mdx +14 -7
  51. package/site/content/docs/reference/i18n.mdx +17 -6
  52. package/site/content/docs/reference/index.mdx +5 -0
  53. package/site/content/docs/reference/meta.json +1 -0
  54. package/site/content/docs/reference/migrating-environments.mdx +158 -0
  55. package/site/content/docs/reference/plugins.mdx +2 -2
  56. package/src/auth/gate-auth.test.ts +12 -10
  57. package/src/cli/ai-setup/ai-setup.test.ts +30 -16
  58. package/src/cli/ai-setup/apply.ts +111 -15
  59. package/src/cli/ai-setup/catalog.ts +3 -3
  60. package/src/cli/ai-setup/index.ts +1 -1
  61. package/src/cli/ai-setup/prompts.ts +1 -1
  62. package/src/cli/ai-setup/recommend.test.ts +1 -1
  63. package/src/cli/ask-seed.test.ts +3 -3
  64. package/src/cli/build.ts +8 -9
  65. package/src/cli/db-auto-push.test.ts +6 -3
  66. package/src/cli/db-auto-push.ts +7 -5
  67. package/src/cli/db-seed.ts +7 -8
  68. package/src/cli/db.test.ts +70 -71
  69. package/src/cli/db.ts +86 -12
  70. package/src/cli/dev-controller.test.ts +35 -0
  71. package/src/cli/dev-controller.ts +298 -0
  72. package/src/cli/dev-controls.ts +11 -65
  73. package/src/cli/dev-db-push.test.ts +47 -15
  74. package/src/cli/dev-schema-sync.test.ts +11 -11
  75. package/src/cli/dev-schema-sync.ts +10 -10
  76. package/src/cli/dev-session-lock.test.ts +106 -0
  77. package/src/cli/dev-session-lock.ts +209 -0
  78. package/src/cli/dev.test.ts +246 -114
  79. package/src/cli/dev.ts +153 -205
  80. package/src/cli/doc-staleness.test.ts +3 -6
  81. package/src/cli/docker-clean.test.ts +33 -1
  82. package/src/cli/docker-clean.ts +28 -33
  83. package/src/cli/docker-cli.test.ts +12 -11
  84. package/src/cli/docker.ts +95 -20
  85. package/src/cli/doctor.test.ts +40 -0
  86. package/src/cli/doctor.ts +142 -9
  87. package/src/cli/drizzle-env.test.ts +11 -13
  88. package/src/cli/drizzle-env.ts +18 -11
  89. package/src/cli/ensure-drizzle-config.ts +11 -14
  90. package/src/cli/hero-meta.test.ts +15 -15
  91. package/src/cli/hero-meta.ts +10 -9
  92. package/src/cli/index.ts +36 -6
  93. package/src/cli/load-config.images.test.ts +44 -10
  94. package/src/cli/load-config.source.test.ts +50 -0
  95. package/src/cli/load-config.ts +35 -29
  96. package/src/cli/meilisearch-local.ts +1 -2
  97. package/src/cli/mode.ts +7 -58
  98. package/src/cli/registry.ts +175 -19
  99. package/src/cli/resolve-dev-sql-env.test.ts +8 -16
  100. package/src/cli/resolve-dev-sql-env.ts +13 -15
  101. package/src/cli/safe-defaults.test.ts +29 -11
  102. package/src/cli/schema.ts +65 -16
  103. package/src/cli/test.ts +58 -0
  104. package/src/cli/tui/App.tsx +252 -0
  105. package/src/cli/tui/DevLive.tsx +116 -0
  106. package/src/cli/tui/components/ConfirmDialog.tsx +48 -0
  107. package/src/cli/tui/components/HeaderBar.tsx +67 -0
  108. package/src/cli/tui/components/LogStream.tsx +47 -0
  109. package/src/cli/tui/components/PanelCard.tsx +39 -0
  110. package/src/cli/tui/components/SelectRow.tsx +37 -0
  111. package/src/cli/tui/components/SlashPalette.tsx +172 -0
  112. package/src/cli/tui/components/Spinner.tsx +32 -0
  113. package/src/cli/tui/components/StatusBar.tsx +51 -0
  114. package/src/cli/tui/components/StatusDot.tsx +37 -0
  115. package/src/cli/tui/components/TabBar.tsx +49 -0
  116. package/src/cli/tui/components/Wordmark.tsx +43 -0
  117. package/src/cli/tui/format.ts +38 -0
  118. package/src/cli/tui/keys.test.ts +18 -0
  119. package/src/cli/tui/keys.ts +26 -0
  120. package/src/cli/tui/launch.test.ts +18 -0
  121. package/src/cli/tui/launch.ts +57 -0
  122. package/src/cli/tui/panels/Dashboard.tsx +201 -0
  123. package/src/cli/tui/panels/Database.tsx +198 -0
  124. package/src/cli/tui/panels/Dev.tsx +257 -0
  125. package/src/cli/tui/panels/Docker.tsx +357 -0
  126. package/src/cli/tui/panels/Navigator.test.ts +22 -0
  127. package/src/cli/tui/panels/Navigator.tsx +213 -0
  128. package/src/cli/tui/slash-catalog.test.ts +31 -0
  129. package/src/cli/tui/slash-catalog.ts +184 -0
  130. package/src/cli/tui/slash-run.ts +54 -0
  131. package/src/cli/tui/state/ports.ts +95 -0
  132. package/src/cli/tui/theme.ts +24 -0
  133. package/src/cli/vault-cmd.test.ts +402 -0
  134. package/src/cli/vault-cmd.ts +727 -69
  135. package/src/cli/vault-secure-input.test.ts +56 -0
  136. package/src/cli/vault-secure-input.ts +124 -0
  137. package/src/compiler/effects-infer.ts +7 -0
  138. package/src/compiler/extract.ts +12 -0
  139. package/src/compiler/fixtures/skyport/oke.config.ts +7 -5
  140. package/src/compiler/fixtures/skyport/src/flows/payments/index.ts +1 -1
  141. package/src/compiler/fixtures/skyport.expected.json +1 -1
  142. package/src/compiler/generate-adopt.ts +27 -1
  143. package/src/compiler-entry.ts +7 -0
  144. package/src/config/define-config.test.ts +111 -47
  145. package/src/config/driver-defaults.test.ts +115 -0
  146. package/src/config/driver-defaults.ts +156 -0
  147. package/src/config/index.ts +246 -131
  148. package/src/config/resolve-driver.test.ts +14 -19
  149. package/src/console/server/app.ts +4 -2
  150. package/src/console/server/console.test.ts +58 -1
  151. package/src/console/server/flows.ts +22 -2
  152. package/src/console/server/index.ts +3 -0
  153. package/src/console/server/operator-db.test.ts +55 -13
  154. package/src/console/server/operator-db.ts +305 -263
  155. package/src/console/server/serve.ts +16 -7
  156. package/src/console/server/state.ts +31 -9
  157. package/src/console/server/vault.test.ts +120 -5
  158. package/src/console/server/vault.ts +208 -12
  159. package/src/console/ui/dist/assets/{index-D-9KFce5.js → index--Y0Uaz-m.js} +2 -2
  160. package/src/console/ui/dist/assets/panel-vault-BkZdJPX8.js +1 -0
  161. package/src/console/ui/dist/assets/style-C3L349iZ.css +3 -0
  162. package/src/console/ui/dist/index.html +2 -2
  163. package/src/console/ui/shell/client.ts +16 -0
  164. package/src/console/ui/shell/panels/vault/VaultPanel.tsx +54 -1
  165. package/src/console/ui/vault/VaultA11yView.tsx +33 -1
  166. package/src/console/ui/vault/backend.test.ts +75 -0
  167. package/src/console/ui/vault/backend.ts +117 -0
  168. package/src/console/ui/vault/fixture.ts +21 -2
  169. package/src/console/ui/vault/index.ts +11 -1
  170. package/src/console/ui/vault/types.ts +26 -0
  171. package/src/docker/compose.ts +164 -61
  172. package/src/docker/derive.ts +106 -12
  173. package/src/docker/docker.test.ts +156 -110
  174. package/src/docker/helpers.ts +98 -0
  175. package/src/docker/images-config.test.ts +163 -0
  176. package/src/docker/index.ts +30 -5
  177. package/src/docker/recipes/index.ts +0 -3
  178. package/src/docker/recipes/llama-cpp.ts +4 -4
  179. package/src/docker/recipes/pgdog.ts +9 -2
  180. package/src/docker/resources.test.ts +71 -0
  181. package/src/docker/resources.ts +176 -0
  182. package/src/docker/stack-id.test.ts +11 -4
  183. package/src/docker/stack-id.ts +42 -32
  184. package/src/docker/stack.integration.test.ts +4 -15
  185. package/src/docker/types.ts +35 -3
  186. package/src/drivers/ai-ollama.integration.test.ts +2 -2
  187. package/src/drivers/conformance.test.ts +11 -12
  188. package/src/drivers/drizzle-dialect.test.ts +0 -4
  189. package/src/drivers/drizzle-dialect.ts +7 -13
  190. package/src/drivers/index.ts +24 -7
  191. package/src/drivers/journal-postgres.test.ts +3 -1
  192. package/src/drivers/journal-postgres.ts +4 -2
  193. package/src/drivers/meilisearch.ts +1 -1
  194. package/src/drivers/pglite.ts +28 -5
  195. package/src/drivers/types.ts +9 -11
  196. package/src/drivers/vault-aws-secrets-manager.test.ts +159 -0
  197. package/src/drivers/vault-aws-secrets-manager.ts +333 -0
  198. package/src/drivers/vault-builtin.test.ts +110 -0
  199. package/src/drivers/vault-builtin.ts +184 -0
  200. package/src/drivers/vault-driver-removal.test.ts +13 -0
  201. package/src/drivers/vault-managed.test.ts +95 -0
  202. package/src/drivers/vault-managed.ts +101 -25
  203. package/src/drivers/vault-types.ts +25 -5
  204. package/src/elements/ai/runtime.ts +1 -1
  205. package/src/elements/clock/chaos.test.ts +4 -1
  206. package/src/elements/clock/durable.ts +57 -4
  207. package/src/elements/clock.test.ts +13 -14
  208. package/src/elements/gate/constants.ts +18 -0
  209. package/src/elements/gate.test.ts +1 -1
  210. package/src/elements/gate.ts +2 -2
  211. package/src/elements/store/domain-ddl.test.ts +5 -12
  212. package/src/elements/store/emit-drizzle.ts +44 -19
  213. package/src/elements/store/index-boot.test.ts +15 -116
  214. package/src/elements/store/load-plugin-tables.ts +1 -1
  215. package/src/elements/store/resource-list-docs.fixture.ts +12 -6
  216. package/src/elements/store/resource-list-docs.test.ts +64 -44
  217. package/src/elements/store/resource.test.ts +17 -10
  218. package/src/elements/store/runtime.ts +9 -12
  219. package/src/elements/store/schema-decl.test.ts +16 -32
  220. package/src/elements/store/seed.test.ts +1 -2
  221. package/src/elements/store/seed.ts +7 -8
  222. package/src/elements/store/sql-condition.test.ts +2 -2
  223. package/src/elements/store/sql-session.test.ts +8 -10
  224. package/src/elements/store/sql-session.ts +10 -2
  225. package/src/elements/store.test.ts +13 -13
  226. package/src/elements/vault/audit.ts +233 -0
  227. package/src/elements/vault/boot-chain.test.ts +78 -0
  228. package/src/elements/vault/boot-chain.ts +43 -39
  229. package/src/elements/vault/builtin-adapter.test.ts +479 -0
  230. package/src/elements/vault/builtin-adapter.ts +1184 -0
  231. package/src/elements/vault/crypto.test.ts +237 -0
  232. package/src/elements/vault/crypto.ts +431 -0
  233. package/src/elements/vault/declare.ts +164 -3
  234. package/src/elements/vault/errors.ts +56 -0
  235. package/src/elements/vault/kms-unseal.test.ts +76 -0
  236. package/src/elements/vault/kms-unseal.ts +181 -0
  237. package/src/elements/vault/path.ts +90 -0
  238. package/src/elements/vault/resilience.test.ts +102 -0
  239. package/src/elements/vault/resilience.ts +107 -0
  240. package/src/elements/vault/runtime.ts +36 -4
  241. package/src/elements/vault/security-checklist.test.ts +130 -0
  242. package/src/elements/vault/storage.ts +448 -0
  243. package/src/elements/vault/types.ts +288 -0
  244. package/src/elements/vault/unseal.ts +150 -0
  245. package/src/elements/vault.test.ts +72 -4
  246. package/src/elements/vault.ts +91 -2
  247. package/src/full.ts +248 -0
  248. package/src/http.ts +41 -0
  249. package/src/i18n/interpolate-simple.ts +37 -0
  250. package/src/i18n/messages.ts +51 -4
  251. package/src/i18n-entry.ts +7 -0
  252. package/src/index.ts +35 -145
  253. package/src/journal-entry.ts +20 -0
  254. package/src/kernel/adopt-barrel-fresh.test.ts +25 -10
  255. package/src/kernel/app.ts +40 -42
  256. package/src/kernel/auto-registry.test.ts +2 -2
  257. package/src/kernel/boot-bind/ai.test.ts +5 -5
  258. package/src/kernel/boot-bind/ai.ts +2 -1
  259. package/src/kernel/boot-bind/channel.test.ts +6 -6
  260. package/src/kernel/boot-bind/channel.ts +5 -4
  261. package/src/kernel/boot-bind/clock.ts +5 -5
  262. package/src/kernel/boot-bind/gate.ts +6 -7
  263. package/src/kernel/boot-bind/honor-config.test.ts +42 -42
  264. package/src/kernel/boot-bind/journal.ts +5 -5
  265. package/src/kernel/boot-bind/signal.ts +3 -1
  266. package/src/kernel/boot-bind/store.test.ts +55 -37
  267. package/src/kernel/boot-bind/store.ts +24 -34
  268. package/src/kernel/boot-bind/vault.ts +19 -4
  269. package/src/kernel/boot.test.ts +12 -4
  270. package/src/kernel/boot.ts +31 -19
  271. package/src/kernel/budget-entry.ts +1 -1
  272. package/src/kernel/compensate.test.ts +288 -1
  273. package/src/kernel/compensate.ts +126 -0
  274. package/src/kernel/concurrency.test.ts +10 -9
  275. package/src/kernel/effects-stamping.test.ts +27 -2
  276. package/src/kernel/element-registries.ts +5 -3
  277. package/src/kernel/flow.ts +4 -2
  278. package/src/kernel/fx.test.ts +119 -3
  279. package/src/kernel/fx.ts +215 -40
  280. package/src/kernel/index.ts +14 -0
  281. package/src/kernel/journal.ts +130 -7
  282. package/src/kernel/pipeline.test.ts +20 -6
  283. package/src/kernel/redacted.test.ts +35 -0
  284. package/src/kernel/redacted.ts +24 -2
  285. package/src/kernel/router/create-default.ts +16 -0
  286. package/src/kernel/router/create-edge.ts +18 -0
  287. package/src/kernel/router/create.ts +23 -0
  288. package/src/kernel/router/index.ts +23 -0
  289. package/src/kernel/router/linear.ts +88 -0
  290. package/src/kernel/router/regexp.ts +188 -0
  291. package/src/kernel/router/smart.ts +120 -0
  292. package/src/kernel/router/trie.ts +108 -0
  293. package/src/kernel/router/types.ts +56 -0
  294. package/src/kernel/router.ts +18 -532
  295. package/src/kernel-entry.ts +43 -0
  296. package/src/manifest/fixtures/skyport.excerpt.json +1 -1
  297. package/src/manifest/fixtures/skyport.manifest.json +1 -1
  298. package/src/plugins/config-source.test.ts +7 -7
  299. package/src/release/build-lib.ts +58 -0
  300. package/src/release/exports.test.ts +4 -2
  301. package/src/release/exports.ts +30 -4
  302. package/src/release/measure.ts +101 -22
  303. package/src/runs/duckdb.ts +7 -2
  304. package/src/shared/optional-peer.ts +41 -0
  305. package/src/term.test.ts +3 -44
  306. package/src/test/create-test-app.ts +12 -0
  307. package/src/test/provisions.integration.test.ts +1 -1
  308. package/src/test/reset-element-registries.ts +2 -0
  309. package/src/upgrade/codemods.test.ts +7 -20
  310. package/src/upgrade/codemods.ts +93 -60
  311. package/site/content/docs/console/access.mdx +0 -29
  312. package/site/content/docs/console/ai.mdx +0 -35
  313. package/site/content/docs/console/architecture.mdx +0 -35
  314. package/site/content/docs/console/channels.mdx +0 -37
  315. package/site/content/docs/console/clock.mdx +0 -51
  316. package/site/content/docs/console/flows.mdx +0 -31
  317. package/site/content/docs/console/gates.mdx +0 -73
  318. package/site/content/docs/console/index.mdx +0 -54
  319. package/site/content/docs/console/manifest-diff.mdx +0 -34
  320. package/site/content/docs/console/meta.json +0 -24
  321. package/site/content/docs/console/overview.mdx +0 -40
  322. package/site/content/docs/console/plugins.mdx +0 -41
  323. package/site/content/docs/console/privacy.mdx +0 -32
  324. package/site/content/docs/console/runs.mdx +0 -50
  325. package/site/content/docs/console/signals.mdx +0 -40
  326. package/site/content/docs/console/store.mdx +0 -32
  327. package/site/content/docs/console/tenancy.mdx +0 -32
  328. package/site/content/docs/console/traces.mdx +0 -38
  329. package/site/content/docs/console/vault.mdx +0 -41
  330. package/site/content/docs/recipes/openbao.mdx +0 -141
  331. package/src/cli/ask-dev-mode.ts +0 -40
  332. package/src/cli/dev-mode.test.ts +0 -45
  333. package/src/cli/dev-mode.ts +0 -78
  334. package/src/cli/openbao-bootstrap.test.ts +0 -150
  335. package/src/cli/openbao-bootstrap.ts +0 -321
  336. package/src/cli/openbao-restart.integration.test.ts +0 -145
  337. package/src/console/ui/dist/assets/panel-vault-Za1GyJfM.js +0 -1
  338. package/src/console/ui/dist/assets/style-C8MxEWPd.css +0 -3
  339. package/src/docker/recipes/openbao.ts +0 -47
  340. package/src/drivers/libsql.ts +0 -179
  341. package/src/drivers/sqlite.ts +0 -44
  342. package/src/drivers/vault-openbao.test.ts +0 -97
  343. package/src/drivers/vault-openbao.ts +0 -143
@@ -0,0 +1 @@
1
+ import{a as e,r as t}from"./rolldown-runtime-B0Z9INg1.js";import{C as n,Q as r,Z as i,a,b as o,c as s,d as c,et as l,g as u,nt as d,o as f,tt as p,u as m,w as h,y as g}from"./panel-access-ri1X9Otj.js";import{n as _}from"./panel-channels-BDYWX29p.js";var v=g({q:o().optional(),name:o().optional(),action:u([`set`,`rotate`]).optional()});function y(e){let t=v.safeParse(e);return t.success?t.data:{}}function b(e){let t={};return e.q&&(t.q=e.q),e.name&&(t.name=e.name),e.action&&(t.action=e.action),t}function x(e,t){return{...e,name:t,action:void 0}}var S={vault:`okengine's own store — encrypted at rest, sealed until unsealed with the master key`,env:`Environment layers only — process.env, .env.local, docker/.env.docker`,managed:`Managed KMS / provider secret store`,memory:`In-memory bag — test only, nothing survives restart`};function C(e){if(!e)return null;let t=`Backend ${e.driverId}`,n=S[e.driverId]??`Custom vault backend`;if(!e.builtin)return{title:t,description:n,badges:[],facts:[],hint:null};let r=e.status;if(!r)return{title:t,description:n,badges:[{id:`unreachable`,label:`status unavailable`,tone:`warn`}],facts:[],hint:e.unavailable??"Run `oke vault status` to inspect the backend directly"};if(!r.initialized)return{title:t,description:n,badges:[{id:`uninitialized`,label:`not initialized`,tone:`warn`}],facts:[],hint:"Run `oke vault init` to create the vault and print its master key once"};let i=[{id:`initialized`,label:`initialized`,tone:`ok`},r.sealed?{id:`sealed`,label:`sealed`,tone:`warn`}:{id:`unsealed`,label:`unsealed`,tone:`ok`}];r.rewrapTargetKekVersion!==null&&i.push({id:`rewrap`,label:`rewrap → kek v${r.rewrapTargetKekVersion}`,tone:`warn`});let a=[{label:`KEK generation`,value:`v${r.kekVersion}`},{label:`Secrets stored`,value:String(r.secretCount)},{label:`Seal count`,value:String(r.sealCount)}];return r.lastUnsealedAt!==null&&a.push({label:`Last unsealed`,value:new Date(r.lastUnsealedAt).toISOString()}),r.lastSealedAt!==null&&a.push({label:`Last sealed`,value:new Date(r.lastSealedAt).toISOString()}),{title:t,description:n,badges:i,facts:a,hint:r.sealed?"This process holds no master key — export OKE_VAULT_MASTER_KEY or run `oke vault unseal`":null}}function w(e,t=``){let n=t.trim().toLowerCase(),r=n?e.filter(e=>e.name.toLowerCase().includes(n)||(e.description?.toLowerCase().includes(n)??!1)):e,i=[`secret`,`config`],a={secret:`Secrets`,config:`Config`};return i.map(e=>({kind:e,label:a[e],secrets:r.filter(t=>t.kind===e)})).filter(e=>e.secrets.length>0)}function T(e={production:!0}){return e.production?{kind:`typed`,phrase:`SET`,requireReason:!0}:{kind:`undo`,windowMs:15e3}}function E(e={production:!0}){return{kind:`typed`,phrase:`ROTATE`,requireReason:!0}}function D(e){if(e.count===0)return{summary:`No in-flight durable runs hold this secret`,detail:null,warn:!1};let t=e.longestOutstandingMs==null?null:O(e.longestOutstandingMs);return{summary:`${e.count} in-flight durable run(s) will wake holding a new key`,detail:t?`Longest outstanding wake in ${t}`:e.longestWakeAt==null?null:`Longest wake at ${new Date(e.longestWakeAt).toISOString()}`,warn:!0}}function O(e){if(e<1e3)return`${e}ms`;let t=Math.floor(e/1e3);if(t<60)return`${t}s`;let n=Math.floor(t/60);if(n<60)return`${n}m`;let r=Math.floor(n/60);return r<48?`${r}h`:`${Math.floor(r/24)}d`}function k(e){return{name:e.name,kind:e.kind,sensitive:e.sensitive,description:e.description??null,rotate:e.rotate??null,fingerprints:{...e.fingerprints},fingerprint:e.fingerprint,cleartext:e.sensitive?null:e.cleartext,winner:e.winner,resolution:e.resolution.map(e=>({...e})),readers:[...e.readers],blastRadius:{count:e.blastRadius.count,longestWakeAt:e.blastRadius.longestWakeAt,longestOutstandingMs:e.blastRadius.longestOutstandingMs,runIds:[...e.blastRadius.runIds]},lastReadAt:e.lastReadAt,sharedFingerprintEnvs:[...e.sharedFingerprintEnvs]}}function A(e){return JSON.stringify(e.map(e=>k(e)),null,2)}var j=e(d(),1),M=p();function N(){let e=h({from:`/vault`}),t=n({from:`/vault`}),o=l(),[u,d]=(0,j.useState)(``),[p,g]=(0,j.useState)(``),[v,y]=(0,j.useState)(``),[S,O]=(0,j.useState)(null),k=e=>{t({search:b(e),replace:!0})},N=r({queryKey:[`console.vault.list`],queryFn:async()=>{let e=await c.vaultList();if(e.error)throw Error(e.error.code);return e.data},refetchInterval:1e4}),P=N.data?.secrets??[],F=N.data?.env??`local`,I=N.data?.backend??null,L=(0,j.useMemo)(()=>C(I),[I]),R=(0,j.useMemo)(()=>w(P,e.q??``),[P,e.q]),z=P.find(t=>t.name===e.name),B=z?D(z.blastRadius):null,V=T({production:!0}),H=E({production:!0}),U=e.action;(0,j.useEffect)(()=>{d(``),g(``),y(``),O(null)},[z?.name,U]);let W=i({mutationFn:async()=>{if(!z)throw Error(`no secret`);if(V.kind===`typed`){let e=a({typed:u,reason:p,phrase:V.phrase});if(e)throw Error(e.typed??e.reason??`confirm`)}let e=await c.vaultSet({name:z.name,value:v,confirmation:V.kind===`typed`?u:void 0,reason:p||void 0});if(e.error)throw Error(e.error.code);return e.data},onSuccess:async()=>{y(``),d(``),g(``),k({...e,action:void 0}),await o.invalidateQueries({queryKey:[`console.vault.list`]})}}),G=i({mutationFn:async()=>{if(!z)throw Error(`no secret`);let e=a({typed:u,reason:p,phrase:H.kind===`typed`?H.phrase:`ROTATE`});if(e)throw Error(e.typed??e.reason??`confirm`);let t=await c.vaultRotate({name:z.name,value:v,confirmation:u,reason:p});if(t.error)throw Error(t.error.code);return t.data},onSuccess:async()=>{y(``),d(``),g(``),k({...e,action:void 0}),await o.invalidateQueries({queryKey:[`console.vault.list`]})}});return(0,M.jsxs)(`div`,{className:`flex h-full min-h-0 flex-col`,children:[(0,M.jsxs)(`header`,{className:`flex shrink-0 flex-wrap items-end gap-3 border-b border-[var(--oke-line)] px-4 py-3`,children:[(0,M.jsxs)(`div`,{children:[(0,M.jsx)(`h1`,{className:`text-lg font-medium text-[var(--oke-fg)]`,children:`Vault`}),(0,M.jsx)(`p`,{className:`text-sm text-[var(--oke-muted)]`,children:`Fingerprints only — secrets are write-only`})]}),(0,M.jsxs)(`p`,{className:`text-sm text-[var(--oke-muted)]`,role:`status`,children:[`Environment `,F]}),(0,M.jsxs)(`label`,{className:`ml-auto flex min-w-[12rem] flex-col gap-1 text-sm`,children:[(0,M.jsx)(`span`,{className:`text-[var(--oke-muted)]`,children:`Filter vault`}),(0,M.jsx)(s,{"aria-label":`Filter vault`,value:e.q??``,onChange:t=>k({...e,q:t.currentTarget.value||void 0})})]}),(0,M.jsx)(f,{type:`button`,variant:`ghost`,onClick:()=>{let e=A(P);navigator.clipboard?.writeText(e),O(`Exported fingerprints only (no secret values)`)},children:`Export`})]}),S?(0,M.jsx)(`p`,{className:`px-4 py-2 text-sm text-[var(--oke-muted)]`,role:`status`,children:S}):null,L?(0,M.jsxs)(`section`,{"aria-label":`Vault backend`,className:`shrink-0 border-b border-[var(--oke-line)] px-4 py-3`,children:[(0,M.jsxs)(`div`,{className:`flex flex-wrap items-center gap-2`,children:[(0,M.jsx)(`h2`,{className:`text-sm font-medium text-[var(--oke-fg)]`,children:L.title}),L.badges.map(e=>(0,M.jsx)(`span`,{role:e.tone===`warn`?`alert`:`status`,className:m(`border border-[var(--oke-line)] px-2 py-0.5 text-xs`,e.tone===`warn`?`text-[var(--oke-danger)]`:e.tone===`ok`?`text-[var(--oke-fg)]`:`text-[var(--oke-muted)]`),children:e.label},e.id))]}),(0,M.jsx)(`p`,{className:`mt-1 text-sm text-[var(--oke-muted)]`,children:L.description}),L.facts.length>0?(0,M.jsx)(`dl`,{className:`mt-2 flex flex-wrap gap-x-6 gap-y-1 text-sm`,children:L.facts.map(e=>(0,M.jsxs)(`div`,{className:`flex gap-2`,children:[(0,M.jsx)(`dt`,{className:`text-[var(--oke-muted)]`,children:e.label}),(0,M.jsx)(`dd`,{className:`font-mono`,children:e.value})]},e.label))}):null,L.hint?(0,M.jsx)(`p`,{className:`mt-1 text-sm text-[var(--oke-muted)]`,role:`status`,children:L.hint}):null,I?.builtin?(0,M.jsxs)(`p`,{className:`mt-1 text-sm text-[var(--oke-muted)]`,children:[`Every read, write, seal and rotate is recorded in a hash-chained audit log. Read it with `,(0,M.jsx)(`code`,{className:`font-mono`,children:`oke vault audit`}),`; verify the chain with`,` `,(0,M.jsx)(`code`,{className:`font-mono`,children:`oke vault audit verify`}),`.`]}):null]}):null,(0,M.jsxs)(`div`,{className:`flex min-h-0 flex-1`,children:[(0,M.jsxs)(`section`,{"aria-label":`Vault list`,className:`w-80 shrink-0 overflow-y-auto border-r border-[var(--oke-line)]`,children:[(0,M.jsx)(`h2`,{className:`sr-only`,children:`Contracts`}),N.isLoading?(0,M.jsx)(`p`,{className:`p-4 text-sm text-[var(--oke-muted)]`,children:`Loading…`}):null,R.map(t=>(0,M.jsxs)(`section`,{"aria-label":t.label,className:`py-2`,children:[(0,M.jsx)(`h3`,{className:`px-4 py-1 text-xs uppercase tracking-wide text-[var(--oke-muted)]`,children:t.label}),(0,M.jsx)(`ul`,{children:t.secrets.map(t=>(0,M.jsx)(`li`,{children:(0,M.jsxs)(`button`,{type:`button`,"aria-pressed":t.name===z?.name,className:m(`flex min-h-10 w-full flex-col items-start px-4 py-2 text-left text-sm`,t.name===z?.name?`bg-[var(--oke-line)] text-[var(--oke-fg)]`:`text-[var(--oke-muted)] hover:text-[var(--oke-fg)]`),onClick:()=>k(x(e,t.name)),children:[(0,M.jsx)(`span`,{children:_(t.name,t.description)}),t.description?(0,M.jsx)(`span`,{className:`font-mono text-xs text-[var(--oke-muted)]`,children:t.name}):null,(0,M.jsx)(`span`,{className:`truncate text-xs`,children:t.sensitive?t.fingerprint??`unset`:t.cleartext??`unset`}),t.blastRadius.count>0?(0,M.jsxs)(`span`,{role:`status`,className:`text-xs text-[var(--oke-danger)]`,children:[`blast `,t.blastRadius.count]}):null,t.sharedFingerprintEnvs.length>0?(0,M.jsx)(`span`,{role:`status`,className:`text-xs`,children:`shared fingerprint`}):null]})},t.name))})]},t.kind))]}),(0,M.jsx)(`section`,{"aria-label":`Vault detail`,"aria-live":`polite`,className:`min-w-0 flex-1 overflow-y-auto p-4`,children:z?(0,M.jsxs)(`div`,{className:`flex max-w-2xl flex-col gap-6`,children:[(0,M.jsxs)(`div`,{children:[(0,M.jsx)(`h2`,{className:`text-lg text-[var(--oke-fg)]`,children:_(z.name,z.description)}),z.description?(0,M.jsx)(`p`,{className:`font-mono text-sm text-[var(--oke-muted)]`,children:z.name}):null,z.rotate?(0,M.jsxs)(`p`,{className:`text-sm text-[var(--oke-muted)]`,children:[`Rotate hint: `,z.rotate]}):null]}),(0,M.jsxs)(`section`,{"aria-label":`Fingerprints by environment`,children:[(0,M.jsx)(`h3`,{className:`mb-2 text-sm font-medium`,children:`Fingerprints`}),z.sensitive?(0,M.jsxs)(`ul`,{className:`space-y-1 font-mono text-sm`,children:[Object.entries(z.fingerprints).map(([e,t])=>(0,M.jsxs)(`li`,{children:[(0,M.jsxs)(`span`,{className:`text-[var(--oke-muted)]`,children:[e,`:`]}),` `,t,z.sharedFingerprintEnvs.includes(e)?(0,M.jsxs)(`span`,{role:`status`,className:`ml-2 text-[var(--oke-warn,var(--oke-muted))]`,children:[`(matches `,F,` — warning, may be deliberate)`]}):null]},e)),Object.keys(z.fingerprints).length===0?(0,M.jsx)(`li`,{className:`text-[var(--oke-muted)]`,children:`Unset`}):null]}):(0,M.jsx)(`p`,{className:`font-mono text-sm`,role:`status`,children:z.cleartext??`unset`})]}),(0,M.jsxs)(`section`,{"aria-label":`Resolution chain`,children:[(0,M.jsx)(`h3`,{className:`mb-2 text-sm font-medium`,children:`Resolution chain`}),(0,M.jsx)(`ol`,{className:`list-decimal space-y-1 pl-5 text-sm`,children:z.resolution.map(e=>(0,M.jsxs)(`li`,{className:e.won?`text-[var(--oke-fg)]`:`text-[var(--oke-muted)]`,children:[(0,M.jsx)(`span`,{className:`font-mono`,children:e.source}),e.won?` — won`:e.present?` — present (lost)`:` — absent`]},e.source))}),(0,M.jsxs)(`p`,{className:`mt-2 text-sm`,role:`status`,children:[`Winner: `,(0,M.jsx)(`span`,{className:`font-mono`,children:z.winner??`none`})]})]}),(0,M.jsxs)(`section`,{"aria-label":`Readers`,children:[(0,M.jsx)(`h3`,{className:`mb-2 text-sm font-medium`,children:`Readers`}),(0,M.jsxs)(`p`,{className:`text-sm text-[var(--oke-muted)]`,children:[`Flows that declare `,(0,M.jsxs)(`code`,{className:`font-mono`,children:[`fx.vault.get(`,z.name,`)`]})]}),(0,M.jsx)(`ul`,{className:`mt-1 list-disc pl-5 font-mono text-sm`,children:z.readers.length===0?(0,M.jsx)(`li`,{className:`text-[var(--oke-muted)]`,children:`none`}):z.readers.map(e=>(0,M.jsx)(`li`,{children:e},e))})]}),(0,M.jsxs)(`section`,{"aria-label":`Rotation blast radius`,children:[(0,M.jsx)(`h3`,{className:`mb-2 text-sm font-medium`,children:`Rotation blast radius`}),B?(0,M.jsxs)(M.Fragment,{children:[(0,M.jsx)(`p`,{className:`text-sm`,role:B.warn?`alert`:`status`,children:B.summary}),B.detail?(0,M.jsx)(`p`,{className:`text-sm text-[var(--oke-muted)]`,children:B.detail}):null,z.blastRadius.runIds.length>0?(0,M.jsx)(`p`,{className:`mt-1 font-mono text-xs text-[var(--oke-muted)]`,children:z.blastRadius.runIds.join(`, `)}):null]}):null]}),(0,M.jsxs)(`section`,{"aria-label":`Last read`,children:[(0,M.jsx)(`h3`,{className:`mb-2 text-sm font-medium`,children:`Last read`}),(0,M.jsx)(`p`,{className:`text-sm`,role:`status`,children:z.lastReadAt==null?`Never read — possible dead secret`:new Date(z.lastReadAt).toISOString()})]}),(0,M.jsxs)(`section`,{"aria-label":`Set or rotate`,className:`space-y-3`,children:[(0,M.jsx)(`h3`,{className:`text-sm font-medium`,children:`Set / rotate`}),(0,M.jsx)(`p`,{className:`text-sm text-[var(--oke-muted)]`,children:`Write-only. Values are never revealed after submit. No preview.`}),(0,M.jsxs)(`div`,{className:`flex gap-2`,children:[(0,M.jsx)(f,{type:`button`,variant:U===`set`?`primary`:`ghost`,"aria-pressed":U===`set`,onClick:()=>k({...e,action:`set`}),children:`Set`}),(0,M.jsx)(f,{type:`button`,variant:U===`rotate`?`danger`:`ghost`,"aria-pressed":U===`rotate`,onClick:()=>k({...e,action:`rotate`}),children:`Rotate`})]}),U?(0,M.jsxs)(`div`,{className:`space-y-3 border border-[var(--oke-line)] p-3`,children:[(0,M.jsxs)(`label`,{className:`flex flex-col gap-1 text-sm`,children:[(0,M.jsx)(`span`,{children:`New value`}),(0,M.jsx)(s,{"aria-label":`New vault value`,type:`password`,autoComplete:`off`,value:v,onChange:e=>y(e.currentTarget.value)})]}),(U===`rotate`||V.kind===`typed`)&&(0,M.jsxs)(M.Fragment,{children:[(0,M.jsxs)(`label`,{className:`flex flex-col gap-1 text-sm`,children:[(0,M.jsxs)(`span`,{children:[`Type`,` `,U===`rotate`?H.kind===`typed`?H.phrase:`ROTATE`:V.kind===`typed`?V.phrase:`SET`,` `,`to confirm`]}),(0,M.jsx)(s,{"aria-label":`Confirmation phrase`,value:u,onChange:e=>d(e.currentTarget.value)})]}),(0,M.jsxs)(`label`,{className:`flex flex-col gap-1 text-sm`,children:[(0,M.jsx)(`span`,{children:`Reason`}),(0,M.jsx)(s,{"aria-label":`Reason for vault write`,value:p,onChange:e=>g(e.currentTarget.value)})]})]}),(0,M.jsx)(f,{type:`button`,variant:U===`rotate`?`danger`:`primary`,disabled:!v||(U===`set`?W.isPending:G.isPending),onClick:()=>{U===`set`?W.mutate():G.mutate()},children:U===`set`?`Commit set`:`Commit rotate`}),(W.isError||G.isError)&&(0,M.jsx)(`p`,{role:`alert`,className:`text-sm text-[var(--oke-danger)]`,children:(W.error??G.error)?.message??`Failed`})]}):null]})]}):(0,M.jsx)(`p`,{className:`text-sm text-[var(--oke-muted)]`,children:`Select a contract to inspect fingerprints, resolution, and readers.`})})]})]})}var P=t({default:()=>N});export{y as n,P as t};
@@ -0,0 +1,3 @@
1
+ /*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */
2
+ @layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-space-y-reverse:0;--tw-divide-y-reverse:0;--tw-border-style:solid;--tw-leading:initial;--tw-font-weight:initial;--tw-tracking:initial;--tw-ordinal:initial;--tw-slashed-zero:initial;--tw-numeric-figure:initial;--tw-numeric-spacing:initial;--tw-numeric-fraction:initial;--tw-outline-style:solid;--tw-duration:initial}}}@layer theme{:root,:host{--font-sans:-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--color-red-600:oklch(57.7% .245 27.325);--color-red-700:oklch(50.5% .213 27.518);--color-amber-800:oklch(47.3% .137 46.201);--color-black:#000;--color-white:#fff;--spacing:.25rem;--container-xs:20rem;--container-sm:24rem;--container-md:28rem;--container-lg:32rem;--container-2xl:42rem;--container-5xl:64rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-base:1rem;--text-base--line-height:calc(1.5 / 1);--text-lg:1.125rem;--text-lg--line-height:calc(1.75 / 1.125);--text-xl:1.25rem;--text-xl--line-height:calc(1.75 / 1.25);--text-2xl:1.5rem;--text-2xl--line-height:calc(2 / 1.5);--text-3xl:1.875rem;--text-3xl--line-height:calc(2.25 / 1.875);--font-weight-normal:400;--font-weight-medium:500;--font-weight-semibold:600;--tracking-tight:-.025em;--tracking-wide:.025em;--tracking-wider:.05em;--leading-snug:1.375;--leading-relaxed:1.625;--radius-sm:.25rem;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring:where(:not(iframe)){outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab, currentcolor 50%, transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.visible{visibility:visible}.sr-only{clip-path:inset(50%);white-space:nowrap;border-width:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.sticky{position:sticky}.inset-0{inset:0}.inset-y-0{inset-block:0}.top-0{top:0}.right-\[min\(28\%\,20rem\)\]{right:min(28%,20rem)}.left-\[min\(28\%\,20rem\)\]{left:min(28%,20rem)}.z-10{z-index:10}.z-20{z-index:20}.z-50{z-index:50}.col-span-2{grid-column:span 2/span 2}.mx-auto{margin-inline:auto}.mt-1{margin-top:var(--spacing)}.mt-2{margin-top:calc(var(--spacing) * 2)}.mt-3{margin-top:calc(var(--spacing) * 3)}.mt-4{margin-top:calc(var(--spacing) * 4)}.mt-6{margin-top:calc(var(--spacing) * 6)}.mt-8{margin-top:calc(var(--spacing) * 8)}.mt-auto{margin-top:auto}.mr-2{margin-right:calc(var(--spacing) * 2)}.mr-3{margin-right:calc(var(--spacing) * 3)}.mr-auto{margin-right:auto}.mb-1{margin-bottom:var(--spacing)}.mb-2{margin-bottom:calc(var(--spacing) * 2)}.mb-3{margin-bottom:calc(var(--spacing) * 3)}.mb-4{margin-bottom:calc(var(--spacing) * 4)}.mb-8{margin-bottom:calc(var(--spacing) * 8)}.ml-1{margin-left:var(--spacing)}.ml-2{margin-left:calc(var(--spacing) * 2)}.ml-auto{margin-left:auto}.block{display:block}.contents{display:contents}.flex{display:flex}.grid{display:grid}.inline-block{display:inline-block}.inline-flex{display:inline-flex}.size-1\.5{width:calc(var(--spacing) * 1.5);height:calc(var(--spacing) * 1.5)}.h-1\.5{height:calc(var(--spacing) * 1.5)}.h-2{height:calc(var(--spacing) * 2)}.h-4{height:calc(var(--spacing) * 4)}.h-6{height:calc(var(--spacing) * 6)}.h-7{height:calc(var(--spacing) * 7)}.h-12{height:calc(var(--spacing) * 12)}.h-16{height:calc(var(--spacing) * 16)}.h-40{height:calc(var(--spacing) * 40)}.h-64{height:calc(var(--spacing) * 64)}.h-\[calc\(100vh-3rem\)\]{height:calc(100vh - 3rem)}.h-auto{height:auto}.h-full{height:100%}.max-h-48{max-height:calc(var(--spacing) * 48)}.min-h-0{min-height:0}.min-h-2{min-height:calc(var(--spacing) * 2)}.min-h-8{min-height:calc(var(--spacing) * 8)}.min-h-10{min-height:calc(var(--spacing) * 10)}.min-h-20{min-height:calc(var(--spacing) * 20)}.min-h-24{min-height:calc(var(--spacing) * 24)}.w-2{width:calc(var(--spacing) * 2)}.w-5{width:calc(var(--spacing) * 5)}.w-6{width:calc(var(--spacing) * 6)}.w-16{width:calc(var(--spacing) * 16)}.w-24{width:calc(var(--spacing) * 24)}.w-56{width:calc(var(--spacing) * 56)}.w-64{width:calc(var(--spacing) * 64)}.w-72{width:calc(var(--spacing) * 72)}.w-80{width:calc(var(--spacing) * 80)}.w-auto{width:auto}.w-full{width:100%}.max-w-2xl{max-width:var(--container-2xl)}.max-w-5xl{max-width:var(--container-5xl)}.max-w-lg{max-width:var(--container-lg)}.max-w-md{max-width:var(--container-md)}.max-w-prose{max-width:65ch}.max-w-sm{max-width:var(--container-sm)}.max-w-xs{max-width:var(--container-xs)}.min-w-0{min-width:0}.min-w-2{min-width:calc(var(--spacing) * 2)}.min-w-8{min-width:calc(var(--spacing) * 8)}.min-w-\[4px\]{min-width:4px}.min-w-\[8rem\]{min-width:8rem}.min-w-\[12rem\]{min-width:12rem}.min-w-\[16rem\]{min-width:16rem}.flex-1{flex:1}.shrink-0{flex-shrink:0}.basis-full{flex-basis:100%}.border-collapse{border-collapse:collapse}.cursor-pointer{cursor:pointer}.list-inside{list-style-position:inside}.list-decimal{list-style-type:decimal}.list-disc{list-style-type:disc}.list-none{list-style-type:none}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-cols-\[minmax\(0\,8rem\)_1fr\]{grid-template-columns:minmax(0,8rem) 1fr}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.place-items-center{place-items:center}.items-baseline{align-items:baseline}.items-center{align-items:center}.items-end{align-items:flex-end}.items-start{align-items:flex-start}.items-stretch{align-items:stretch}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.gap-0{gap:0}.gap-0\.5{gap:calc(var(--spacing) * .5)}.gap-1{gap:var(--spacing)}.gap-1\.5{gap:calc(var(--spacing) * 1.5)}.gap-2{gap:calc(var(--spacing) * 2)}.gap-3{gap:calc(var(--spacing) * 3)}.gap-4{gap:calc(var(--spacing) * 4)}.gap-6{gap:calc(var(--spacing) * 6)}.gap-8{gap:calc(var(--spacing) * 8)}.gap-px{gap:1px}:where(.space-y-0\.5>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * .5) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * .5) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-1>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(var(--spacing) * var(--tw-space-y-reverse));margin-block-end:calc(var(--spacing) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-2>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 2) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 2) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-3>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 3) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 3) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-4>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 4) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 4) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-6>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 6) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 6) * calc(1 - var(--tw-space-y-reverse)))}.gap-x-4{column-gap:calc(var(--spacing) * 4)}.gap-x-6{column-gap:calc(var(--spacing) * 6)}.gap-y-1{row-gap:var(--spacing)}.gap-y-2{row-gap:calc(var(--spacing) * 2)}:where(.divide-y>:not(:last-child)){--tw-divide-y-reverse:0;border-bottom-style:var(--tw-border-style);border-top-style:var(--tw-border-style);border-top-width:calc(1px * var(--tw-divide-y-reverse));border-bottom-width:calc(1px * calc(1 - var(--tw-divide-y-reverse)))}:where(.divide-\[var\(--oke-line\)\]>:not(:last-child)){border-color:var(--oke-line)}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.rounded{border-radius:.25rem}.rounded-full{border-radius:2147483647px}.rounded-sm{border-radius:var(--radius-sm)}.border{border-style:var(--tw-border-style);border-width:1px}.border-x{border-inline-style:var(--tw-border-style);border-inline-width:1px}.border-y{border-block-style:var(--tw-border-style);border-block-width:1px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-r{border-right-style:var(--tw-border-style);border-right-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-l{border-left-style:var(--tw-border-style);border-left-width:1px}.border-dashed{--tw-border-style:dashed;border-style:dashed}.border-\[var\(--oke-accent\)\]{border-color:var(--oke-accent)}.border-\[var\(--oke-external\)\]{border-color:var(--oke-external)}.border-\[var\(--oke-line\)\],.border-\[var\(--oke-line\)\]\/50{border-color:var(--oke-line)}@supports (color:color-mix(in lab, red, red)){.border-\[var\(--oke-line\)\]\/50{border-color:color-mix(in oklab, var(--oke-line) 50%, transparent)}}.border-\[var\(--oke-muted\)\]{border-color:var(--oke-muted)}.bg-\[color-mix\(in_oklab\,var\(--oke-accent\)_55\%\,transparent\)\]{background-color:var(--oke-accent)}@supports (color:color-mix(in lab, red, red)){.bg-\[color-mix\(in_oklab\,var\(--oke-accent\)_55\%\,transparent\)\]{background-color:color-mix(in oklab,var(--oke-accent) 55%,transparent)}}.bg-\[color-mix\(in_oklab\,var\(--oke-fg\)_3\%\,transparent\)\]{background-color:var(--oke-fg)}@supports (color:color-mix(in lab, red, red)){.bg-\[color-mix\(in_oklab\,var\(--oke-fg\)_3\%\,transparent\)\]{background-color:color-mix(in oklab,var(--oke-fg) 3%,transparent)}}.bg-\[color-mix\(in_oklab\,var\(--oke-fg\)_6\%\,transparent\)\]{background-color:var(--oke-fg)}@supports (color:color-mix(in lab, red, red)){.bg-\[color-mix\(in_oklab\,var\(--oke-fg\)_6\%\,transparent\)\]{background-color:color-mix(in oklab,var(--oke-fg) 6%,transparent)}}.bg-\[color-mix\(in_oklab\,var\(--oke-fg\)_35\%\,transparent\)\]{background-color:var(--oke-fg)}@supports (color:color-mix(in lab, red, red)){.bg-\[color-mix\(in_oklab\,var\(--oke-fg\)_35\%\,transparent\)\]{background-color:color-mix(in oklab,var(--oke-fg) 35%,transparent)}}.bg-\[var\(--oke-accent\)\],.bg-\[var\(--oke-accent\)\]\/15{background-color:var(--oke-accent)}@supports (color:color-mix(in lab, red, red)){.bg-\[var\(--oke-accent\)\]\/15{background-color:color-mix(in oklab, var(--oke-accent) 15%, transparent)}}.bg-\[var\(--oke-bg\)\]{background-color:var(--oke-bg)}.bg-\[var\(--oke-danger\)\],.bg-\[var\(--oke-danger\)\]\/10{background-color:var(--oke-danger)}@supports (color:color-mix(in lab, red, red)){.bg-\[var\(--oke-danger\)\]\/10{background-color:color-mix(in oklab, var(--oke-danger) 10%, transparent)}}.bg-\[var\(--oke-external\)\]{background-color:var(--oke-external)}.bg-\[var\(--oke-fg\)\]{background-color:var(--oke-fg)}.bg-\[var\(--oke-line\)\],.bg-\[var\(--oke-line\)\]\/40{background-color:var(--oke-line)}@supports (color:color-mix(in lab, red, red)){.bg-\[var\(--oke-line\)\]\/40{background-color:color-mix(in oklab, var(--oke-line) 40%, transparent)}}.bg-black\/20{background-color:#0003}@supports (color:color-mix(in lab, red, red)){.bg-black\/20{background-color:color-mix(in oklab, var(--color-black) 20%, transparent)}}.bg-black\/50{background-color:#00000080}@supports (color:color-mix(in lab, red, red)){.bg-black\/50{background-color:color-mix(in oklab, var(--color-black) 50%, transparent)}}.bg-transparent{background-color:#0000}.fill-\[var\(--oke-fg\)\]{fill:var(--oke-fg)}.fill-\[var\(--oke-muted\)\]{fill:var(--oke-muted)}.p-0{padding:0}.p-2{padding:calc(var(--spacing) * 2)}.p-3{padding:calc(var(--spacing) * 3)}.p-4{padding:calc(var(--spacing) * 4)}.p-6{padding:calc(var(--spacing) * 6)}.px-1{padding-inline:var(--spacing)}.px-1\.5{padding-inline:calc(var(--spacing) * 1.5)}.px-2{padding-inline:calc(var(--spacing) * 2)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-4{padding-inline:calc(var(--spacing) * 4)}.px-5{padding-inline:calc(var(--spacing) * 5)}.px-6{padding-inline:calc(var(--spacing) * 6)}.py-0\.5{padding-block:calc(var(--spacing) * .5)}.py-1{padding-block:var(--spacing)}.py-1\.5{padding-block:calc(var(--spacing) * 1.5)}.py-2{padding-block:calc(var(--spacing) * 2)}.py-3{padding-block:calc(var(--spacing) * 3)}.py-4{padding-block:calc(var(--spacing) * 4)}.py-5{padding-block:calc(var(--spacing) * 5)}.py-6{padding-block:calc(var(--spacing) * 6)}.py-8{padding-block:calc(var(--spacing) * 8)}.py-16{padding-block:calc(var(--spacing) * 16)}.pt-3{padding-top:calc(var(--spacing) * 3)}.pt-4{padding-top:calc(var(--spacing) * 4)}.pr-2{padding-right:calc(var(--spacing) * 2)}.pr-3{padding-right:calc(var(--spacing) * 3)}.pr-4{padding-right:calc(var(--spacing) * 4)}.pb-1{padding-bottom:var(--spacing)}.pb-2{padding-bottom:calc(var(--spacing) * 2)}.pb-4{padding-bottom:calc(var(--spacing) * 4)}.pl-4{padding-left:calc(var(--spacing) * 4)}.pl-5{padding-left:calc(var(--spacing) * 5)}.text-center{text-align:center}.text-left{text-align:left}.align-top{vertical-align:top}.font-mono{font-family:var(--font-mono)}.text-2xl{font-size:var(--text-2xl);line-height:var(--tw-leading,var(--text-2xl--line-height))}.text-3xl{font-size:var(--text-3xl);line-height:var(--tw-leading,var(--text-3xl--line-height))}.text-base{font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height))}.text-lg{font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xl{font-size:var(--text-xl);line-height:var(--tw-leading,var(--text-xl--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.text-\[10px\]{font-size:10px}.text-\[11px\]{font-size:11px}.text-\[13px\]{font-size:13px}.leading-10{--tw-leading:calc(var(--spacing) * 10);line-height:calc(var(--spacing) * 10)}.leading-relaxed{--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed)}.leading-snug{--tw-leading:var(--leading-snug);line-height:var(--leading-snug)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-normal{--tw-font-weight:var(--font-weight-normal);font-weight:var(--font-weight-normal)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.tracking-\[0\.2em\]{--tw-tracking:.2em;letter-spacing:.2em}.tracking-\[0\.14em\]{--tw-tracking:.14em;letter-spacing:.14em}.tracking-\[0\.15em\]{--tw-tracking:.15em;letter-spacing:.15em}.tracking-tight{--tw-tracking:var(--tracking-tight);letter-spacing:var(--tracking-tight)}.tracking-wide{--tw-tracking:var(--tracking-wide);letter-spacing:var(--tracking-wide)}.tracking-wider{--tw-tracking:var(--tracking-wider);letter-spacing:var(--tracking-wider)}.break-all{word-break:break-all}.whitespace-pre-wrap{white-space:pre-wrap}.text-\[var\(--oke-accent\)\]{color:var(--oke-accent)}.text-\[var\(--oke-danger\)\]{color:var(--oke-danger)}.text-\[var\(--oke-external\)\]{color:var(--oke-external)}.text-\[var\(--oke-fg\)\]{color:var(--oke-fg)}.text-\[var\(--oke-muted\)\]{color:var(--oke-muted)}.text-\[var\(--oke-warn\,var\(--oke-muted\)\)\]{color:var(--oke-warn,var(--oke-muted))}.text-amber-800{color:var(--color-amber-800)}.text-black{color:var(--color-black)}.text-red-600{color:var(--color-red-600)}.text-red-700{color:var(--color-red-700)}.text-white{color:var(--color-white)}.normal-case{text-transform:none}.uppercase{text-transform:uppercase}.tabular-nums{--tw-numeric-spacing:tabular-nums;font-variant-numeric:var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,)}.line-through{text-decoration-line:line-through}.underline{text-decoration-line:underline}.decoration-\[var\(--oke-line\)\]{-webkit-text-decoration-color:var(--oke-line);-webkit-text-decoration-color:var(--oke-line);text-decoration-color:var(--oke-line)}.underline-offset-2{text-underline-offset:2px}.opacity-40{opacity:.4}.opacity-70{opacity:.7}.outline{outline-style:var(--tw-outline-style);outline-width:1px}.outline-2{outline-style:var(--tw-outline-style);outline-width:2px}.outline-\[var\(--oke-danger\)\]{outline-color:var(--oke-danger)}.transition-opacity{transition-property:opacity;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.duration-150{--tw-duration:.15s;transition-duration:.15s}.placeholder\:text-\[var\(--oke-muted\)\]::placeholder{color:var(--oke-muted)}@media (hover:hover){.hover\:bg-\[color-mix\(in_oklab\,var\(--oke-fg\)_3\%\,transparent\)\]:hover{background-color:var(--oke-fg)}@supports (color:color-mix(in lab, red, red)){.hover\:bg-\[color-mix\(in_oklab\,var\(--oke-fg\)_3\%\,transparent\)\]:hover{background-color:color-mix(in oklab,var(--oke-fg) 3%,transparent)}}.hover\:bg-\[var\(--oke-line\)\]\/20:hover{background-color:var(--oke-line)}@supports (color:color-mix(in lab, red, red)){.hover\:bg-\[var\(--oke-line\)\]\/20:hover{background-color:color-mix(in oklab, var(--oke-line) 20%, transparent)}}.hover\:bg-\[var\(--oke-line\)\]\/40:hover{background-color:var(--oke-line)}@supports (color:color-mix(in lab, red, red)){.hover\:bg-\[var\(--oke-line\)\]\/40:hover{background-color:color-mix(in oklab, var(--oke-line) 40%, transparent)}}.hover\:text-\[var\(--oke-fg\)\]:hover{color:var(--oke-fg)}.hover\:underline:hover{text-decoration-line:underline}}.focus\:not-sr-only:focus{clip-path:none;white-space:normal;width:auto;height:auto;margin:0;padding:0;position:static;overflow:visible}.focus\:absolute:focus{position:absolute}.focus\:top-2:focus{top:calc(var(--spacing) * 2)}.focus\:left-2:focus{left:calc(var(--spacing) * 2)}.focus\:z-50:focus{z-index:50}.focus\:bg-\[var\(--oke-bg\)\]:focus{background-color:var(--oke-bg)}.focus\:px-3:focus{padding-inline:calc(var(--spacing) * 3)}.focus\:py-2:focus{padding-block:calc(var(--spacing) * 2)}.disabled\:opacity-40:disabled{opacity:.4}@media (width>=40rem){.sm\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.sm\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}}@media (width>=48rem){.md\:max-w-xs{max-width:var(--container-xs)}.md\:grid-cols-\[minmax\(0\,1fr\)_minmax\(0\,1\.4fr\)\]{grid-template-columns:minmax(0,1fr) minmax(0,1.4fr)}.md\:grid-cols-\[minmax\(0\,1fr\)_minmax\(0\,1\.5fr\)\]{grid-template-columns:minmax(0,1fr) minmax(0,1.5fr)}}@media (width>=64rem){.lg\:w-80{width:calc(var(--spacing) * 80)}.lg\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.lg\:grid-cols-\[1fr_1fr_1\.2fr\]{grid-template-columns:1fr 1fr 1.2fr}.lg\:grid-cols-\[14rem_1fr_18rem\]{grid-template-columns:14rem 1fr 18rem}.lg\:grid-cols-\[minmax\(0\,1\.2fr\)_minmax\(0\,1fr\)\]{grid-template-columns:minmax(0,1.2fr) minmax(0,1fr)}.lg\:flex-row{flex-direction:row}.lg\:border-t-0{border-top-style:var(--tw-border-style);border-top-width:0}.lg\:border-r{border-right-style:var(--tw-border-style);border-right-width:1px}.lg\:border-b-0{border-bottom-style:var(--tw-border-style);border-bottom-width:0}.lg\:border-l{border-left-style:var(--tw-border-style);border-left-width:1px}}}:root{--oke-bg:#0e1116;--oke-fg:#e8eaed;--oke-muted:#9aa3b2;--oke-line:var(--oke-fg)}@supports (color:color-mix(in lab, red, red)){:root{--oke-line:color-mix(in oklab, var(--oke-fg) 12%, transparent)}}:root{--oke-accent:#3d9a6a;--oke-external:#d97706;--oke-danger:#c44b4b;--oke-font:"IBM Plex Sans", "Segoe UI", sans-serif;--oke-mono:"IBM Plex Mono", ui-monospace, monospace;--oke-dim:.38}@font-face{font-family:IBM Plex Sans;font-style:normal;font-weight:400 600;font-display:swap;src:local(IBM Plex Sans)}html,body,#root{height:100%}body{font-family:var(--oke-font);background:radial-gradient(1200px 600px at 10% -10%, #1a2433 0%, transparent 55%), radial-gradient(900px 500px at 100% 0%, #13201a 0%, transparent 50%), var(--oke-bg);color:var(--oke-fg);font-variant-numeric:tabular-nums;margin:0}*{box-sizing:border-box}a{color:inherit;text-decoration:none}:focus-visible{outline:2px solid var(--oke-accent);outline-offset:2px}@media (prefers-reduced-motion:reduce){*,:before,:after{transition:none!important;animation:none!important}}.sr-only{clip:rect(0, 0, 0, 0);white-space:nowrap;border-width:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}@property --tw-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-divide-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-ordinal{syntax:"*";inherits:false}@property --tw-slashed-zero{syntax:"*";inherits:false}@property --tw-numeric-figure{syntax:"*";inherits:false}@property --tw-numeric-spacing{syntax:"*";inherits:false}@property --tw-numeric-fraction{syntax:"*";inherits:false}@property --tw-outline-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-duration{syntax:"*";inherits:false}
3
+ /*$vite$:1*/
@@ -5,9 +5,9 @@
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
6
  <link rel="icon" href="/favicon.svg" type="image/svg+xml" />
7
7
  <title>oke Console</title>
8
- <script type="module" crossorigin src="/assets/index-D-9KFce5.js"></script>
8
+ <script type="module" crossorigin src="/assets/index--Y0Uaz-m.js"></script>
9
9
  <link rel="modulepreload" crossorigin href="/assets/rolldown-runtime-B0Z9INg1.js">
10
- <link rel="stylesheet" crossorigin href="/assets/style-C8MxEWPd.css">
10
+ <link rel="stylesheet" crossorigin href="/assets/style-C3L349iZ.css">
11
11
  </head>
12
12
  <body>
13
13
  <div id="root"></div>
@@ -484,6 +484,22 @@ interface ConsoleClient {
484
484
  sharedFingerprintEnvs: string[];
485
485
  }>;
486
486
  env: string;
487
+ backend: {
488
+ driverId: "env" | "vault" | "managed" | "memory";
489
+ builtin: boolean;
490
+ status: {
491
+ initialized: boolean;
492
+ sealed: boolean;
493
+ masterKeyPresent: boolean;
494
+ kekVersion: number;
495
+ secretCount: number;
496
+ sealCount: number;
497
+ lastSealedAt: number | null;
498
+ lastUnsealedAt: number | null;
499
+ rewrapTargetKekVersion: number | null;
500
+ } | null;
501
+ unavailable: string | null;
502
+ } | null;
487
503
  }>;
488
504
  vaultSet: (input: {
489
505
  name: string;
@@ -11,6 +11,7 @@ import { useEffect, useMemo, useState } from "react";
11
11
  import {
12
12
  exportSafeList,
13
13
  formatBlastRadius,
14
+ formatVaultBackend,
14
15
  groupByKind,
15
16
  openVault,
16
17
  rotateConfirmation,
@@ -55,6 +56,8 @@ export function VaultPanel() {
55
56
 
56
57
  const secrets = listQuery.data?.secrets ?? [];
57
58
  const env = listQuery.data?.env ?? "local";
59
+ const backend = listQuery.data?.backend ?? null;
60
+ const backendCard = useMemo(() => formatVaultBackend(backend), [backend]);
58
61
  const groups = useMemo(() => groupByKind(secrets, search.q ?? ""), [secrets, search.q]);
59
62
  const open = secrets.find((s) => s.name === search.name);
60
63
  const blast = open ? formatBlastRadius(open.blastRadius) : null;
@@ -164,6 +167,56 @@ export function VaultPanel() {
164
167
  </p>
165
168
  ) : null}
166
169
 
170
+ {backendCard ? (
171
+ <section
172
+ aria-label="Vault backend"
173
+ className="shrink-0 border-b border-[var(--oke-line)] px-4 py-3"
174
+ >
175
+ <div className="flex flex-wrap items-center gap-2">
176
+ <h2 className="text-sm font-medium text-[var(--oke-fg)]">{backendCard.title}</h2>
177
+ {backendCard.badges.map((badge) => (
178
+ <span
179
+ key={badge.id}
180
+ role={badge.tone === "warn" ? "alert" : "status"}
181
+ className={clsx(
182
+ "border border-[var(--oke-line)] px-2 py-0.5 text-xs",
183
+ badge.tone === "warn"
184
+ ? "text-[var(--oke-danger)]"
185
+ : badge.tone === "ok"
186
+ ? "text-[var(--oke-fg)]"
187
+ : "text-[var(--oke-muted)]",
188
+ )}
189
+ >
190
+ {badge.label}
191
+ </span>
192
+ ))}
193
+ </div>
194
+ <p className="mt-1 text-sm text-[var(--oke-muted)]">{backendCard.description}</p>
195
+ {backendCard.facts.length > 0 ? (
196
+ <dl className="mt-2 flex flex-wrap gap-x-6 gap-y-1 text-sm">
197
+ {backendCard.facts.map((fact) => (
198
+ <div key={fact.label} className="flex gap-2">
199
+ <dt className="text-[var(--oke-muted)]">{fact.label}</dt>
200
+ <dd className="font-mono">{fact.value}</dd>
201
+ </div>
202
+ ))}
203
+ </dl>
204
+ ) : null}
205
+ {backendCard.hint ? (
206
+ <p className="mt-1 text-sm text-[var(--oke-muted)]" role="status">
207
+ {backendCard.hint}
208
+ </p>
209
+ ) : null}
210
+ {backend?.builtin ? (
211
+ <p className="mt-1 text-sm text-[var(--oke-muted)]">
212
+ Every read, write, seal and rotate is recorded in a hash-chained audit log. Read it
213
+ with <code className="font-mono">oke vault audit</code>; verify the chain with{" "}
214
+ <code className="font-mono">oke vault audit verify</code>.
215
+ </p>
216
+ ) : null}
217
+ </section>
218
+ ) : null}
219
+
167
220
  <div className="flex min-h-0 flex-1">
168
221
  <section
169
222
  aria-label="Vault list"
@@ -289,7 +342,7 @@ export function VaultPanel() {
289
342
  <section aria-label="Readers">
290
343
  <h3 className="mb-2 text-sm font-medium">Readers</h3>
291
344
  <p className="text-sm text-[var(--oke-muted)]">
292
- Flows that declare <code className="font-mono">fx.vault({open.name})</code>
345
+ Flows that declare <code className="font-mono">fx.vault.get({open.name})</code>
293
346
  </p>
294
347
  <ul className="mt-1 list-disc pl-5 font-mono text-sm">
295
348
  {open.readers.length === 0 ? (
@@ -2,6 +2,7 @@
2
2
  * Static Vault markup for the axe gate — same landmarks as the live panel.
3
3
  */
4
4
 
5
+ import { formatVaultBackend } from "./backend.ts";
5
6
  import { formatBlastRadius } from "./blast-radius.ts";
6
7
  import { VAULT_LIST_FIXTURE } from "./fixture.ts";
7
8
  import { groupByKind } from "./group.ts";
@@ -23,6 +24,8 @@ export function VaultA11yView(props: VaultA11yViewProps) {
23
24
  const open = VAULT_LIST_FIXTURE.secrets.find((s) => s.name === openName);
24
25
  const blast = open ? formatBlastRadius(open.blastRadius) : null;
25
26
  const env = VAULT_LIST_FIXTURE.env;
27
+ const backend = VAULT_LIST_FIXTURE.backend;
28
+ const backendCard = formatVaultBackend(backend);
26
29
 
27
30
  return (
28
31
  <div className="vault-a11y">
@@ -37,6 +40,35 @@ export function VaultA11yView(props: VaultA11yViewProps) {
37
40
  </label>
38
41
  </header>
39
42
  <main id="vault-main">
43
+ {backendCard ? (
44
+ <section aria-label="Vault backend">
45
+ <h2>{backendCard.title}</h2>
46
+ <p>{backendCard.description}</p>
47
+ <p>
48
+ {backendCard.badges.map((badge) => (
49
+ <span key={badge.id} role={badge.tone === "warn" ? "alert" : "status"}>
50
+ {badge.label}{" "}
51
+ </span>
52
+ ))}
53
+ </p>
54
+ <dl>
55
+ {backendCard.facts.map((fact) => (
56
+ <div key={fact.label}>
57
+ <dt>{fact.label}</dt>
58
+ <dd>{fact.value}</dd>
59
+ </div>
60
+ ))}
61
+ </dl>
62
+ {backendCard.hint ? <p role="status">{backendCard.hint}</p> : null}
63
+ {backend?.builtin ? (
64
+ <p>
65
+ Audit trail is hash-chained in the backend — read it with `oke vault audit`, verify
66
+ it with `oke vault audit verify`.
67
+ </p>
68
+ ) : null}
69
+ </section>
70
+ ) : null}
71
+
40
72
  <section aria-label="Vault list">
41
73
  <h2>Contracts</h2>
42
74
  {groups.map((group) => (
@@ -111,7 +143,7 @@ export function VaultA11yView(props: VaultA11yViewProps) {
111
143
  <section aria-label="Readers">
112
144
  <h3>Readers</h3>
113
145
  <p>
114
- Flows that declare fx.vault({open.name}): {open.readers.join(", ") || "none"}
146
+ Flows that declare fx.vault.get({open.name}): {open.readers.join(", ") || "none"}
115
147
  </p>
116
148
  </section>
117
149
 
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Vault backend status card — badges, facts, operator hint.
3
+ */
4
+
5
+ import { describe, expect, test } from "bun:test";
6
+ import { formatVaultBackend } from "./backend.ts";
7
+ import { VAULT_BACKEND_FIXTURE } from "./fixture.ts";
8
+ import type { VaultBackend } from "./types.ts";
9
+
10
+ describe("formatVaultBackend", () => {
11
+ test("null backend renders no card", () => {
12
+ expect(formatVaultBackend(null)).toBeNull();
13
+ });
14
+
15
+ test("non-builtin driver shows the id with no seal badges", () => {
16
+ const card = formatVaultBackend({
17
+ driverId: "managed",
18
+ builtin: false,
19
+ status: null,
20
+ unavailable: null,
21
+ });
22
+ expect(card?.title).toBe("Backend managed");
23
+ expect(card?.badges).toEqual([]);
24
+ expect(card?.facts).toEqual([]);
25
+ expect(card?.hint).toBeNull();
26
+ });
27
+
28
+ test("sealed builtin backend warns and points at the master key", () => {
29
+ const card = formatVaultBackend(VAULT_BACKEND_FIXTURE);
30
+ expect(card?.badges.map((b) => b.id)).toEqual(["initialized", "sealed"]);
31
+ expect(card?.badges.find((b) => b.id === "sealed")?.tone).toBe("warn");
32
+ expect(card?.facts).toContainEqual({ label: "KEK generation", value: "v2" });
33
+ expect(card?.facts).toContainEqual({ label: "Secrets stored", value: "7" });
34
+ expect(card?.hint).toContain("OKE_VAULT_MASTER_KEY");
35
+ });
36
+
37
+ test("unsealed builtin backend has no hint", () => {
38
+ const backend: VaultBackend = {
39
+ ...VAULT_BACKEND_FIXTURE,
40
+ status: { ...VAULT_BACKEND_FIXTURE.status!, sealed: false },
41
+ };
42
+ const card = formatVaultBackend(backend);
43
+ expect(card?.badges.map((b) => b.id)).toEqual(["initialized", "unsealed"]);
44
+ expect(card?.hint).toBeNull();
45
+ });
46
+
47
+ test("uninitialized backend points at `oke vault init`", () => {
48
+ const backend: VaultBackend = {
49
+ ...VAULT_BACKEND_FIXTURE,
50
+ status: { ...VAULT_BACKEND_FIXTURE.status!, initialized: false },
51
+ };
52
+ const card = formatVaultBackend(backend);
53
+ expect(card?.badges.map((b) => b.id)).toEqual(["uninitialized"]);
54
+ expect(card?.hint).toContain("oke vault init");
55
+ });
56
+
57
+ test("an in-flight master rotation surfaces the rewrap target", () => {
58
+ const backend: VaultBackend = {
59
+ ...VAULT_BACKEND_FIXTURE,
60
+ status: { ...VAULT_BACKEND_FIXTURE.status!, rewrapTargetKekVersion: 3 },
61
+ };
62
+ expect(formatVaultBackend(backend)?.badges.map((b) => b.label)).toContain("rewrap → kek v3");
63
+ });
64
+
65
+ test("unreachable builtin backend surfaces the reason", () => {
66
+ const card = formatVaultBackend({
67
+ driverId: "vault",
68
+ builtin: true,
69
+ status: null,
70
+ unavailable: "connection refused",
71
+ });
72
+ expect(card?.badges.map((b) => b.id)).toEqual(["unreachable"]);
73
+ expect(card?.hint).toBe("connection refused");
74
+ });
75
+ });
@@ -0,0 +1,117 @@
1
+ /**
2
+ * Format the Vault backend status card (console §9.8).
3
+ *
4
+ * Only the built-in `vault` driver has a seal lifecycle; every other driver
5
+ * shows its id alone so the operator still knows which layer terminates the
6
+ * resolution chain.
7
+ */
8
+
9
+ import type { VaultBackend } from "./types.ts";
10
+
11
+ /** One badge in the status card. */
12
+ export interface VaultBackendBadge {
13
+ /** Stable id for keys and tests. */
14
+ readonly id: string;
15
+ /** Short badge text. */
16
+ readonly label: string;
17
+ /** `warn` renders as an alert; `ok` and `neutral` are status text. */
18
+ readonly tone: "ok" | "warn" | "neutral";
19
+ }
20
+
21
+ /** Rendered status card. */
22
+ export interface VaultBackendCard {
23
+ /** Driver id headline (`Backend vault`). */
24
+ readonly title: string;
25
+ /** One-line explanation of what that backend is. */
26
+ readonly description: string;
27
+ /** Seal / initialization badges — empty for non-builtin drivers. */
28
+ readonly badges: readonly VaultBackendBadge[];
29
+ /** `label: value` facts (KEK generation, secret count, …). */
30
+ readonly facts: readonly { readonly label: string; readonly value: string }[];
31
+ /** Operator next step, when one applies. */
32
+ readonly hint: string | null;
33
+ }
34
+
35
+ /** What each driver id means, in one line. */
36
+ const DRIVER_DESCRIPTION: Readonly<Record<string, string>> = {
37
+ vault: "okengine's own store — encrypted at rest, sealed until unsealed with the master key",
38
+ env: "Environment layers only — process.env, .env.local, docker/.env.docker",
39
+ managed: "Managed KMS / provider secret store",
40
+ memory: "In-memory bag — test only, nothing survives restart",
41
+ };
42
+
43
+ /**
44
+ * Build the status card for a backend.
45
+ *
46
+ * @param backend - Server-reported backend, or `null` when unresolved
47
+ */
48
+ export function formatVaultBackend(backend: VaultBackend | null): VaultBackendCard | null {
49
+ if (!backend) return null;
50
+
51
+ const title = `Backend ${backend.driverId}`;
52
+ const description = DRIVER_DESCRIPTION[backend.driverId] ?? "Custom vault backend";
53
+
54
+ if (!backend.builtin) {
55
+ return { title, description, badges: [], facts: [], hint: null };
56
+ }
57
+
58
+ const status = backend.status;
59
+ if (!status) {
60
+ return {
61
+ title,
62
+ description,
63
+ badges: [{ id: "unreachable", label: "status unavailable", tone: "warn" }],
64
+ facts: [],
65
+ hint: backend.unavailable ?? "Run `oke vault status` to inspect the backend directly",
66
+ };
67
+ }
68
+
69
+ if (!status.initialized) {
70
+ return {
71
+ title,
72
+ description,
73
+ badges: [{ id: "uninitialized", label: "not initialized", tone: "warn" }],
74
+ facts: [],
75
+ hint: "Run `oke vault init` to create the vault and print its master key once",
76
+ };
77
+ }
78
+
79
+ const badges: VaultBackendBadge[] = [
80
+ { id: "initialized", label: "initialized", tone: "ok" },
81
+ status.sealed
82
+ ? { id: "sealed", label: "sealed", tone: "warn" }
83
+ : { id: "unsealed", label: "unsealed", tone: "ok" },
84
+ ];
85
+ if (status.rewrapTargetKekVersion !== null) {
86
+ badges.push({
87
+ id: "rewrap",
88
+ label: `rewrap → kek v${status.rewrapTargetKekVersion}`,
89
+ tone: "warn",
90
+ });
91
+ }
92
+
93
+ const facts: { label: string; value: string }[] = [
94
+ { label: "KEK generation", value: `v${status.kekVersion}` },
95
+ { label: "Secrets stored", value: String(status.secretCount) },
96
+ { label: "Seal count", value: String(status.sealCount) },
97
+ ];
98
+ if (status.lastUnsealedAt !== null) {
99
+ facts.push({
100
+ label: "Last unsealed",
101
+ value: new Date(status.lastUnsealedAt).toISOString(),
102
+ });
103
+ }
104
+ if (status.lastSealedAt !== null) {
105
+ facts.push({ label: "Last sealed", value: new Date(status.lastSealedAt).toISOString() });
106
+ }
107
+
108
+ return {
109
+ title,
110
+ description,
111
+ badges,
112
+ facts,
113
+ hint: status.sealed
114
+ ? "This process holds no master key — export OKE_VAULT_MASTER_KEY or run `oke vault unseal`"
115
+ : null,
116
+ };
117
+ }
@@ -2,7 +2,7 @@
2
2
  * Vault panel fixture — fingerprints only; never real secret values.
3
3
  */
4
4
 
5
- import type { VaultListResponse, VaultRecord } from "./types.ts";
5
+ import type { VaultBackend, VaultListResponse, VaultRecord } from "./types.ts";
6
6
 
7
7
  /** Fixture secret used only for leak-detection tests (never in panel rows). */
8
8
  export const FIXTURE_SECRET_VALUE = "sk_live_DO_NOT_LEAK_fixture";
@@ -68,8 +68,27 @@ export const VAULT_FIXTURE: readonly VaultRecord[] = [
68
68
  },
69
69
  ];
70
70
 
71
+ /** Built-in backend, initialized and sealed in this process. */
72
+ export const VAULT_BACKEND_FIXTURE: VaultBackend = {
73
+ driverId: "vault",
74
+ builtin: true,
75
+ status: {
76
+ initialized: true,
77
+ sealed: true,
78
+ masterKeyPresent: true,
79
+ kekVersion: 2,
80
+ secretCount: 7,
81
+ sealCount: 1,
82
+ lastSealedAt: 1_700_000_100_000,
83
+ lastUnsealedAt: 1_700_000_000_000,
84
+ rewrapTargetKekVersion: null,
85
+ },
86
+ unavailable: null,
87
+ };
88
+
71
89
  /** List response matching `console.vault.list`. */
72
90
  export const VAULT_LIST_FIXTURE: VaultListResponse = {
73
91
  secrets: VAULT_FIXTURE,
74
- env: "local",
92
+ env: "dev",
93
+ backend: VAULT_BACKEND_FIXTURE,
75
94
  };
@@ -3,7 +3,10 @@
3
3
  */
4
4
 
5
5
  export type {
6
+ VaultBackend,
6
7
  VaultBlastRadius,
8
+ VaultBuiltinStatus,
9
+ VaultDriverId,
7
10
  VaultKindGroup,
8
11
  VaultListResponse,
9
12
  VaultRecord,
@@ -11,7 +14,14 @@ export type {
11
14
  VaultResolutionStep,
12
15
  } from "./types.ts";
13
16
 
14
- export { VAULT_FIXTURE, VAULT_LIST_FIXTURE, FIXTURE_SECRET_VALUE } from "./fixture.ts";
17
+ export { formatVaultBackend, type VaultBackendBadge, type VaultBackendCard } from "./backend.ts";
18
+
19
+ export {
20
+ VAULT_BACKEND_FIXTURE,
21
+ VAULT_FIXTURE,
22
+ VAULT_LIST_FIXTURE,
23
+ FIXTURE_SECRET_VALUE,
24
+ } from "./fixture.ts";
15
25
 
16
26
  export {
17
27
  parseVaultSearch,
@@ -43,10 +43,36 @@ export interface VaultRecord {
43
43
  readonly sharedFingerprintEnvs: readonly string[];
44
44
  }
45
45
 
46
+ /** Vault backend driver id — matches `drivers.vault`. */
47
+ export type VaultDriverId = "env" | "vault" | "managed" | "memory";
48
+
49
+ /** Built-in Vault backend state (epoch-ms timestamps). */
50
+ export interface VaultBuiltinStatus {
51
+ readonly initialized: boolean;
52
+ readonly sealed: boolean;
53
+ readonly masterKeyPresent: boolean;
54
+ readonly kekVersion: number;
55
+ readonly secretCount: number;
56
+ readonly sealCount: number;
57
+ readonly lastSealedAt: number | null;
58
+ readonly lastUnsealedAt: number | null;
59
+ readonly rewrapTargetKekVersion: number | null;
60
+ }
61
+
62
+ /** Backend serving the terminal layer of the resolution chain. */
63
+ export interface VaultBackend {
64
+ readonly driverId: VaultDriverId;
65
+ readonly builtin: boolean;
66
+ readonly status: VaultBuiltinStatus | null;
67
+ readonly unavailable: string | null;
68
+ }
69
+
46
70
  /** `console.vault.list` response. */
47
71
  export interface VaultListResponse {
48
72
  readonly secrets: readonly VaultRecord[];
49
73
  readonly env: string;
74
+ /** `null` when the server could not resolve a backend. */
75
+ readonly backend: VaultBackend | null;
50
76
  }
51
77
 
52
78
  /** Grouped list section (secrets vs config). */