okengine 0.3.5 → 0.3.6
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.
- package/AGENTS.md +4 -0
- package/manifest.v1.schema.json +43 -1
- package/package.json +16 -1
- package/site/content/docs/ai/skills.mdx +9 -7
- package/site/content/docs/console/vault.mdx +4 -0
- package/site/content/docs/elements/channel.mdx +5 -4
- package/site/content/docs/elements/clock.mdx +1 -0
- package/site/content/docs/elements/flow.mdx +15 -0
- package/site/content/docs/elements/gate.mdx +16 -11
- package/site/content/docs/elements/signal.mdx +8 -7
- package/site/content/docs/elements/store.mdx +48 -8
- package/site/content/docs/elements/vault.mdx +1 -1
- package/site/content/docs/plugins/ip-allowlist.mdx +2 -2
- package/site/content/docs/reference/configuration.mdx +2 -2
- package/site/content/docs/reference/environment-variables.mdx +8 -0
- package/site/content/docs/reference/fx.mdx +40 -0
- package/site/content/docs/reference/plugins.mdx +18 -18
- package/src/compiler/extract.test.ts +63 -0
- package/src/compiler/extract.ts +36 -15
- package/src/console/server/channels.ts +2 -0
- package/src/console/server/clock.ts +3 -0
- package/src/console/server/flows.ts +13 -0
- package/src/console/server/gates.ts +2 -0
- package/src/console/server/plugins.ts +20 -1
- package/src/console/server/signals.ts +5 -0
- package/src/console/server/store.test.ts +17 -0
- package/src/console/server/store.ts +24 -0
- package/src/console/ui/channels/types.ts +1 -0
- package/src/console/ui/clock/types.ts +1 -0
- package/src/console/ui/display.test.ts +14 -0
- package/src/console/ui/display.ts +9 -0
- package/src/console/ui/dist/assets/{index-BWo8R7NR.js → index-CrKMmO__.js} +2 -2
- package/src/console/ui/dist/assets/panel-channels-DCDd4WAC.js +1 -0
- package/src/console/ui/dist/assets/panel-clock-DjGGFPzr.js +1 -0
- package/src/console/ui/dist/assets/panel-gates-B5eTE8XH.js +1 -0
- package/src/console/ui/dist/assets/{panel-overview-BznEOTnb.js → panel-overview-BsFvDdts.js} +1 -1
- package/src/console/ui/dist/assets/panel-plugins-Cj7DK1er.js +1 -0
- package/src/console/ui/dist/assets/{panel-runs-CGWNHLR4.js → panel-runs-C0gmnoYL.js} +1 -1
- package/src/console/ui/dist/assets/panel-signals-whmDXIg3.js +1 -0
- package/src/console/ui/dist/assets/panel-store-CEMHLvaw.js +1 -0
- package/src/console/ui/dist/assets/{panel-traces-DBLx2ilD.js → panel-traces-BDiAuVSK.js} +1 -1
- package/src/console/ui/dist/assets/panel-vault-C9wjbki8.js +1 -0
- package/src/console/ui/dist/index.html +1 -1
- package/src/console/ui/gates/types.ts +1 -0
- package/src/console/ui/plugins/fixture.ts +7 -0
- package/src/console/ui/plugins/types.ts +3 -0
- package/src/console/ui/shell/client.ts +3 -0
- package/src/console/ui/shell/panels/channels/ChannelsPanel.tsx +7 -2
- package/src/console/ui/shell/panels/clock/ClockPanel.tsx +9 -2
- package/src/console/ui/shell/panels/gates/GatesPanel.tsx +12 -5
- package/src/console/ui/shell/panels/plugins/PluginsPanel.tsx +18 -4
- package/src/console/ui/shell/panels/signals/SignalsPanel.tsx +13 -2
- package/src/console/ui/shell/panels/store/StorePanel.tsx +11 -4
- package/src/console/ui/shell/panels/vault/VaultPanel.tsx +9 -3
- package/src/console/ui/signals/types.ts +1 -0
- package/src/console/ui/store/fixture.ts +5 -0
- package/src/console/ui/store/types.ts +2 -0
- package/src/drivers/conformance.test.ts +11 -0
- package/src/drivers/drizzle-dialect.test.ts +4 -0
- package/src/drivers/drizzle-dialect.ts +8 -4
- package/src/drivers/index.ts +4 -0
- package/src/drivers/libsql.ts +179 -0
- package/src/drivers/pglite.ts +79 -0
- package/src/drivers/pgvector.ts +54 -19
- package/src/drivers/types.ts +16 -7
- package/src/elements/channel/declare.ts +5 -0
- package/src/elements/clock/declare.ts +5 -0
- package/src/elements/clock/durable.ts +7 -1
- package/src/elements/gate/declare.ts +28 -5
- package/src/elements/gate.ts +1 -0
- package/src/elements/signal/declare.ts +5 -0
- package/src/elements/store/declare.ts +10 -2
- package/src/elements/store/index-boot.test.ts +257 -0
- package/src/elements/store/runtime.ts +67 -9
- package/src/elements/store/schema-decl.ts +7 -0
- package/src/kernel/abort-scope.ts +116 -0
- package/src/kernel/app.ts +12 -2
- package/src/kernel/boot-bind/store.test.ts +59 -1
- package/src/kernel/boot-bind/store.ts +64 -2
- package/src/kernel/concurrency.test.ts +236 -0
- package/src/kernel/concurrency.ts +172 -0
- package/src/kernel/flow.ts +9 -0
- package/src/kernel/fx.test.ts +12 -0
- package/src/kernel/fx.ts +44 -0
- package/src/kernel/index.ts +14 -0
- package/src/kernel/journal.ts +9 -0
- package/src/kernel/plugin/capabilities.test.ts +18 -0
- package/src/kernel/plugin.ts +11 -3
- package/src/kernel/registry.ts +29 -6
- package/src/manifest/types.ts +21 -0
- package/src/release/measure.ts +4 -0
- package/src/console/ui/dist/assets/panel-channels-BOmQ-onL.js +0 -1
- package/src/console/ui/dist/assets/panel-clock-giAq0Ccv.js +0 -1
- package/src/console/ui/dist/assets/panel-gates-XclZxWD5.js +0 -1
- package/src/console/ui/dist/assets/panel-plugins-CcGM1g64.js +0 -1
- package/src/console/ui/dist/assets/panel-signals-CNywkdak.js +0 -1
- package/src/console/ui/dist/assets/panel-store-KmTbFHMH.js +0 -1
- package/src/console/ui/dist/assets/panel-vault-CEnFc0dk.js +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
import{a as e,r as t}from"./rolldown-runtime-CNC7AqOf.js";import{C as n,Q as r,Z as i,b as a,d as o,et as s,l as c,nt as l,o as u,tt as d,u as f,w as p,y as m}from"./panel-access-C0J2D-a2.js";import{r as h}from"./panel-runs-CGWNHLR4.js";import{n as g,t as _}from"./panel-flows-DlCU5zjA.js";var v=e(l(),1);function y(e,t){if(!t)return!0;switch(t.kind){case`wrote`:return e.effects.some(e=>e.kind===`write`&&e.resource===t.resource);case`asked`:return e.effects.some(e=>e.kind===`ask`);case`sent`:return e.effects.some(e=>e.kind===`send`&&(t.resource===void 0||e.resource===t.resource));case`secret`:return e.effects.some(e=>e.kind===`secret`&&(t.resource===void 0||e.resource===t.resource));case`cost`:return(e.cost??0)>t.min}}function b(e,t){return!t||e.some(e=>y(e,t))}function x(e){if(!e?.trim())return null;let t=e.trim();if(t===`asked`)return{kind:`asked`};if(t===`sent`)return{kind:`sent`};if(t.startsWith(`wrote:`))return{kind:`wrote`,resource:t.slice(6)};if(t.startsWith(`sent:`))return{kind:`sent`,resource:t.slice(5)};if(t.startsWith(`secret:`))return{kind:`secret`,resource:t.slice(7)};if(t===`secret`)return{kind:`secret`};if(t.startsWith(`cost:`)){let e=Number(t.slice(5));return Number.isFinite(e)?{kind:`cost`,min:e}:null}return null}function S(e){if(e)switch(e.kind){case`wrote`:return`wrote:${e.resource}`;case`asked`:return`asked`;case`sent`:return e.resource?`sent:${e.resource}`:`sent`;case`secret`:return e.resource?`secret:${e.resource}`:`secret`;case`cost`:return`cost:${e.min}`}}var C=m({trace:a().optional(),span:a().optional(),effect:a().optional(),q:a().optional(),folds:a().optional(),boost:a().optional()});function w(e){let t=C.safeParse(e??{});return t.success?t.data:C.parse({})}function T(e){let t={};return e.trace&&(t.trace=e.trace),e.span&&(t.span=e.span),e.effect&&(t.effect=e.effect),e.q&&(t.q=e.q),e.folds&&(t.folds=e.folds),e.boost&&(t.boost=e.boost),t}function E(e){return e.folds?new Set(e.folds.split(`,`).map(e=>e.trim()).filter(Boolean)):new Set}function D(e,t,n){return{...e,trace:t,span:n}}function ee(e){return{...e,trace:void 0,span:void 0,folds:void 0}}function te(e,t){let n=E(e);n.has(t)?n.delete(t):n.add(t);let r=[...n].join(`,`);return{...e,folds:r||void 0}}function O(e,t){return{...e,effect:S(t)}}function k(e){let t=new Map,n=new Map;for(let n of e)t.set(n.id,n);for(let t of e){if(!t.parentId)continue;let e=n.get(t.parentId)??[];e.push(t),n.set(t.parentId,e)}for(let[,e]of n)e.sort((e,t)=>e.startedAt-t.startedAt);return{byId:t,childrenOf:n}}function A(e,t){let{byId:n,childrenOf:r}=k(e),i=n.get(t);if(!i)return null;let a=[],o=i,s=new Set;for(;o?.parentId&&!s.has(o.parentId);){s.add(o.parentId);let e=n.get(o.parentId);if(!e)break;a.unshift(e),o=e}return{parents:a,current:i,children:r.get(i.id)??[],connected:N((a[0]??i).id,n,r)}}function j(e){let{byId:t,childrenOf:n}=k(e),r=e.filter(e=>!e.parentId||!t.has(e.parentId));return r.sort((e,t)=>t.startedAt-e.startedAt),r.map(e=>({rootId:e.id,root:e,spans:N(e.id,t,n)}))}function M(e,t){if(t&&e.some(e=>e.id===t))return t;let n=e.find(e=>e.errorCode!=null&&e.errorCode!==``);return n?n.id:e.find(t=>!t.parentId||!e.some(e=>e.id===t.parentId))?.id??e[0]?.id}function N(e,t,n){let r=[],i=e=>{let a=t.get(e);if(a){r.push(a);for(let t of n.get(e)??[])i(t.id)}};return i(e),r.sort((e,t)=>e.startedAt-t.startedAt),r}function P(e){if(e.length===0)return new Set;let{byId:t,childrenOf:n}=k(e),r=e.filter(e=>!e.parentId||!t.has(e.parentId)),i=[],a=-1,o=(e,r,s)=>{let c=n.get(e)??[],l=t.get(e);if(!l)return;let u=s+F(l),d=[...r,e];if(c.length===0){u>a&&(a=u,i=d);return}for(let e of c)o(e.id,d,u)};for(let e of r)o(e.id,[],0);return new Set(i)}function F(e){return e.effects.length===0?Math.max(0,e.durationMs):e.effects.reduce((e,t)=>e+Math.max(0,t.duration),0)}function I(e){switch(e){case`read`:return`reads`;case`write`:return`writes`;case`emit`:return`emits`;case`send`:case`ask`:return`external`;case`secret`:return`capabilities`;case`call`:return`reads`}}function L(e){let t=`none`;for(let n of e){let e=I(n.kind);z(e)>z(t)&&(t=e)}return t}function R(e){return e.some(e=>L(e.effects)===`external`)}function z(e){switch(e){case`external`:return 5;case`capabilities`:return 4;case`emits`:return 3;case`writes`:return 2;case`reads`:return 1;case`none`:return 0}}function B(e){let t=Math.max(0,Math.round(e));if(t<1e3)return`${t}ms idle`;let n=t/1e3;if(n<60)return`${U(n)}s idle`;let r=n/60;if(r<60)return`${U(r)}m idle`;let i=r/60;return i<48?`${U(i)}h idle`:`${U(i/24)}d idle`}function V(e,t={},n=new Set){let r=t.foldThresholdMs??50,i=t.expandedFolds??new Set,a=[...e].sort((e,t)=>e.startMs-t.startMs);if(a.length===0)return{segments:[],displayDurationMs:0,wallDurationMs:0};let o=a[0],s=a[a.length-1];if(!o||!s)return{segments:[],displayDurationMs:0,wallDurationMs:0};let c=o.startMs,l=Math.max(...a.map(e=>e.endMs)),u=[],d=c;for(let e of a){let t=e.startMs-d;if(t>=r){let n=`fold:${d}:${e.startMs}`,r=i.has(n),a=t;u.push({kind:`fold`,id:n,startMs:d,endMs:e.startMs,durationMs:a,label:B(a),expanded:r,displayMs:r?a:40})}let a=Math.max(0,e.endMs-e.startMs);u.push({kind:`work`,id:e.id,label:e.label,startMs:e.startMs,endMs:e.endMs,durationMs:a,tier:e.tier,spanId:e.spanId,critical:n.has(e.spanId),failed:e.failed===!0,displayMs:Math.max(1,a)}),d=Math.max(d,e.endMs)}let f=u.reduce((e,t)=>e+t.displayMs,0);return{segments:u,displayDurationMs:Math.max(1,f),wallDurationMs:l-c}}function H(e){let t=[];for(let n of e)if(n.effects.length>0)for(let e of n.effects)t.push({id:`${n.id}:${e.kind}:${e.resource}:${e.timestamp}`,label:`${e.kind} ${e.resource}`,startMs:e.timestamp,endMs:e.timestamp+Math.max(1,e.duration),tier:I(e.kind),spanId:n.id,failed:n.errorCode!=null&&e===n.effects[n.effects.length-1]});else t.push({id:n.id,label:n.flow,startMs:n.startedAt,endMs:n.endedAt,tier:`none`,spanId:n.id,failed:n.errorCode!=null});return t}function U(e){let t=Math.round(e*10)/10;return Number.isInteger(t)?String(t):t.toFixed(1)}function W(e){if(e.length===0)return[];let t=Math.min(...e.map(e=>e.startedAt)),n=Math.max(...e.map(e=>e.endedAt)),r=Math.max(1,n-t);if(e.every(e=>e.effects.length===0))return e.map(e=>({start:(e.startedAt-t)/r,width:Math.max(.02,e.durationMs/r),tier:L(e.effects),failed:e.errorCode!=null}));let i=[];for(let n of e){if(n.effects.length===0){i.push({start:(n.startedAt-t)/r,width:Math.max(.02,n.durationMs/r),tier:`none`,failed:n.errorCode!=null});continue}for(let e=0;e<n.effects.length;e++){let a=n.effects[e];a&&i.push({start:(a.timestamp-t)/r,width:Math.max(.02,a.duration/r),tier:I(a.kind),failed:n.errorCode!=null&&e===n.effects.length-1})}}return i}function G(e){for(let t of e)if(t.errorCode)return t.errorCode;return null}function K(e){return R(e)?{mode:`dry-run`,reason:`This trace contains an external effect. Replay runs as a dry run with external effects stubbed.`}:{mode:`replay`}}var q=`10% + all errors`,J=600*1e3;function Y(e,t=Date.now()){let n=e.filter(e=>e.until>t);return n.length===0?q:`${q} · full: ${n.map(e=>e.flow).join(`, `)}`}function X(e,t,n=Date.now()){let r=n+J;return[...e.filter(e=>e.flow!==t&&e.until>n),{flow:t,until:r}]}function ne(e,t=Date.now()){return e.filter(e=>e.until>t)}var Z=d();function Q(){let e=p({from:`/traces`}),t=n({from:`/traces`}),a=s(),[l,d]=(0,v.useState)([]),[m]=(0,v.useState)(()=>_()),[y,S]=(0,v.useState)(0),[,C]=(0,v.useState)(0),w=e=>{t({search:T(e),replace:!0})},k=r({queryKey:[`console.runs.list`],queryFn:async()=>{let e=await o.runsList();if(e.error)throw Error(e.error.code);return e.data.runs},refetchInterval:5e3}),N=(0,v.useMemo)(()=>(k.data??[]).map(re),[k.data]);(0,v.useEffect)(()=>{if(N.length===0)return;if(m.visible.length===0){for(let e of N)m.offer({id:e.id,value:e,arrivedAt:e.startedAt});m.flush(),S(0),C(e=>e+1);return}let e=new Set(m.visible.map(e=>e.id));for(let t of m.pending)e.add(t.id);for(let t of N)e.has(t.id)?m.updateInPlace(t.id,t):m.offer({id:t.id,value:t,arrivedAt:Date.now()});S(m.pendingCount),C(e=>e+1)},[N,m]);let F=m.visible.map(e=>e.value),I=x(e.effect),R=(0,v.useMemo)(()=>j(F).filter(t=>{let n=g([t.root.flow,t.root.id,G(t.spans)??``],e.q),r=b(t.spans,I);return n&&r}),[F,e.q,I]),z=R.find(t=>t.rootId===e.trace)??(e.trace?j(F).find(t=>t.rootId===e.trace):void 0),B=z?M(z.spans,e.span):void 0,U=B?A(F,B):null,q=U?P(U.connected):new Set,J=U?V(H(U.connected),{expandedFolds:E(e)},q):null,Q=U?K(U.connected):null,$=i({mutationFn:async()=>{if(!U||!Q)return;let e=await o.tracesReplay({rootId:U.connected[0]?.id??U.current.id,dryRun:Q.mode===`dry-run`});if(e.error)throw Error(e.error.code);return e.data},onSuccess:()=>{a.invalidateQueries({queryKey:[`console.runs.list`]})}}),ae=ne(l);return(0,Z.jsxs)(`div`,{className:`flex h-full min-h-0 flex-col`,children:[(0,Z.jsxs)(`header`,{className:`flex shrink-0 flex-wrap items-end gap-4 border-b border-[var(--oke-line)] px-6 py-4`,children:[(0,Z.jsxs)(`div`,{className:`flex flex-col gap-1`,children:[(0,Z.jsx)(`p`,{className:`text-xs uppercase tracking-[0.2em] text-[var(--oke-muted)]`,children:`Traces`}),(0,Z.jsx)(`h1`,{className:`text-xl font-semibold tracking-tight`,children:`Causal chain`}),(0,Z.jsxs)(`p`,{className:`text-xs text-[var(--oke-muted)]`,children:[`Sampling: `,Y(ae)]})]}),(0,Z.jsxs)(`label`,{className:`flex flex-col gap-1 text-sm`,children:[(0,Z.jsx)(`span`,{className:`text-[var(--oke-muted)]`,children:`Filter by effect`}),(0,Z.jsxs)(`select`,{"aria-label":`Filter by effect`,className:`min-h-8 border border-[var(--oke-line)] bg-transparent px-2 text-sm`,value:e.effect??``,onChange:t=>{let n=t.target.value;w(O(e,n?x(n):null))},children:[(0,Z.jsx)(`option`,{value:``,children:`All effects`}),(0,Z.jsx)(`option`,{value:`wrote:sql:bookings`,children:`Wrote sql:bookings`}),(0,Z.jsx)(`option`,{value:`sent`,children:`Sent (channel)`}),(0,Z.jsx)(`option`,{value:`asked`,children:`Asked a model`}),(0,Z.jsx)(`option`,{value:`secret`,children:`Read a secret`}),(0,Z.jsx)(`option`,{value:`cost:0.05`,children:`Cost > $0.05`})]})]}),(0,Z.jsxs)(`div`,{className:`flex flex-wrap items-center gap-2`,children:[(0,Z.jsx)(u,{type:`button`,variant:`ghost`,onClick:()=>{let e=z?.root.flow??R[0]?.root.flow??`bookings.create`;d(t=>X(t,e))},children:`Trace flow fully for 10 minutes`}),(0,Z.jsx)(c,{count:y,onFlush:()=>{m.flush(),S(0),C(e=>e+1)}})]})]}),(0,Z.jsxs)(`div`,{className:`grid min-h-0 flex-1 grid-cols-1 md:grid-cols-[minmax(0,1fr)_minmax(0,1.4fr)]`,children:[(0,Z.jsx)(`section`,{"aria-label":`Trace list`,className:`min-h-0 overflow-auto border-r border-[var(--oke-line)]`,children:k.isLoading?(0,Z.jsx)(`p`,{className:`px-6 py-8 text-sm text-[var(--oke-muted)]`,children:`Loading traces…`}):R.length===0?(0,Z.jsx)(`p`,{className:`px-6 py-8 text-sm text-[var(--oke-muted)]`,children:`No traces yet. Invoke a flow or wait for traffic.`}):(0,Z.jsx)(`ul`,{className:`divide-y divide-[var(--oke-line)]`,children:R.map(t=>{let n=G(t.spans),r=W(t.spans),i=t.rootId===e.trace;return(0,Z.jsx)(`li`,{children:(0,Z.jsxs)(`button`,{type:`button`,"aria-pressed":i,className:f(`flex w-full min-h-10 flex-col gap-1 px-4 py-3 text-left text-sm`,i?`bg-[color-mix(in_oklab,var(--oke-fg)_6%,transparent)]`:`hover:bg-[color-mix(in_oklab,var(--oke-fg)_3%,transparent)]`),onClick:()=>{let n=M(t.spans);w(D(e,t.rootId,n))},children:[(0,Z.jsxs)(`div`,{className:`flex items-center justify-between gap-3`,children:[(0,Z.jsx)(`span`,{className:`font-medium`,children:t.root.flow}),n?(0,Z.jsx)(`span`,{role:`status`,className:`font-mono text-xs text-[var(--oke-danger)]`,children:n}):(0,Z.jsxs)(`span`,{className:`font-mono text-xs text-[var(--oke-muted)]`,children:[t.root.durationMs,`ms`]})]}),(0,Z.jsx)(ie,{bars:r})]})},t.rootId)})})}),(0,Z.jsx)(`section`,{"aria-label":`Trace detail`,className:`min-h-0 overflow-auto px-6 py-6`,"aria-live":`polite`,children:!U||!J?(0,Z.jsx)(`p`,{className:`text-sm text-[var(--oke-muted)]`,children:`Select a trace to see the causal chain and folded-time waterfall.`}):(0,Z.jsxs)(`div`,{className:`flex flex-col gap-6`,children:[(0,Z.jsxs)(`div`,{className:`flex flex-wrap items-start justify-between gap-3`,children:[(0,Z.jsxs)(`div`,{children:[(0,Z.jsx)(`h2`,{className:`text-lg font-semibold`,children:U.current.flow}),(0,Z.jsxs)(`p`,{className:`text-xs text-[var(--oke-muted)]`,children:[U.connected.length,` span`,U.connected.length===1?``:`s`,` · wall `,J.wallDurationMs,`ms · display scale `,Math.round(J.displayDurationMs),`ms`]})]}),(0,Z.jsxs)(`div`,{className:`flex flex-wrap gap-2`,children:[(0,Z.jsx)(h,{to:`/runs`,search:{run:U.current.id},className:`inline-flex min-h-8 items-center border border-[var(--oke-line)] px-3 text-sm`,children:`Open in Runs`}),(0,Z.jsx)(u,{type:`button`,variant:Q?.mode===`dry-run`?`external`:`primary`,disabled:$.isPending,title:Q?.mode===`dry-run`?Q.reason:`Replay from the journal`,onClick:()=>$.mutate(),children:Q?.mode===`dry-run`?`Dry-run replay`:`Replay`}),(0,Z.jsx)(u,{type:`button`,variant:`ghost`,onClick:()=>w(ee(e)),children:`Close`})]})]}),Q?.mode===`dry-run`?(0,Z.jsx)(`p`,{role:`note`,className:`text-sm text-[var(--oke-external)]`,children:Q.reason}):null,(0,Z.jsxs)(`div`,{children:[(0,Z.jsx)(`h3`,{className:`mb-2 text-sm font-medium`,children:`Causal chain`}),(0,Z.jsxs)(`ol`,{className:`flex flex-col gap-1 border-l border-[var(--oke-line)] pl-4`,children:[U.parents.map(t=>(0,Z.jsx)(`li`,{children:(0,Z.jsx)(`button`,{type:`button`,className:`min-h-8 text-sm text-[var(--oke-muted)]`,onClick:()=>w({...e,span:t.id}),children:t.flow})},t.id)),(0,Z.jsxs)(`li`,{"aria-current":`true`,children:[(0,Z.jsx)(`span`,{className:`text-sm font-medium`,children:U.current.flow}),U.current.errorCode?(0,Z.jsx)(`span`,{role:`status`,className:`ml-2 font-mono text-xs text-[var(--oke-danger)]`,children:U.current.errorCode}):null,L(U.current.effects)===`external`?(0,Z.jsx)(`span`,{"aria-label":`external effect`,children:` ↗`}):null]}),U.children.map(t=>(0,Z.jsx)(`li`,{children:(0,Z.jsxs)(`button`,{type:`button`,className:`min-h-8 text-sm text-[var(--oke-muted)]`,onClick:()=>w({...e,span:t.id}),children:[t.flow,L(t.effects)===`external`?(0,Z.jsx)(`span`,{"aria-label":`external effect`,children:` ↗`}):null]})},t.id))]})]}),(0,Z.jsxs)(`div`,{children:[(0,Z.jsx)(`h3`,{id:`waterfall-heading`,className:`mb-2 text-sm font-medium`,children:`Waterfall`}),(0,Z.jsx)(`ul`,{"aria-labelledby":`waterfall-heading`,className:`flex min-h-10 list-none items-stretch gap-0.5 p-0`,children:J.segments.map(t=>t.kind===`fold`?(0,Z.jsx)(`li`,{style:{flex:`${t.displayMs} 1 0`,minWidth:24},children:(0,Z.jsx)(`button`,{type:`button`,"aria-expanded":t.expanded,className:`h-full min-h-10 w-full border border-dashed border-[var(--oke-line)] px-1 font-mono text-[10px] text-[var(--oke-muted)]`,onClick:()=>w(te(e,t.id)),children:t.label})},t.id):(0,Z.jsx)(`li`,{title:t.label,className:f(`min-h-10 px-1 text-[10px] leading-10`,t.tier===`external`?`bg-[var(--oke-external)] text-black`:`bg-[color-mix(in_oklab,var(--oke-accent)_55%,transparent)]`,t.failed&&`outline outline-2 outline-[var(--oke-danger)]`),style:{flex:`${t.displayMs} 1 0`,opacity:t.critical?1:.38,minWidth:4},children:(0,Z.jsxs)(`span`,{className:`sr-only`,children:[t.label,t.critical?` (critical path)`:``,t.failed?` (failed)`:``]})},t.id))}),(0,Z.jsx)(`p`,{className:`mt-2 text-xs text-[var(--oke-muted)]`,children:`Critical path at full opacity · dead time folded into expandable bars`})]})]})})]})]})}function re(e){return{id:e.id,...e.parentId?{parentId:e.parentId}:{},flow:e.flow,...e.unit?{unit:e.unit}:{},trigger:e.trigger,startedAt:e.startedAt,endedAt:e.endedAt,durationMs:e.durationMs,errorCode:e.error,cost:e.cost??void 0,sampled:e.sampled??(e.error?`error`:`sample`),effects:e.effects??[]}}function ie({bars:e}){return(0,Z.jsx)(`div`,{"aria-hidden":`true`,className:`relative h-2 w-full overflow-hidden bg-[color-mix(in_oklab,var(--oke-fg)_6%,transparent)]`,children:e.map((e,t)=>(0,Z.jsx)(`span`,{className:f(`absolute inset-y-0`,e.tier===`external`?`bg-[var(--oke-external)]`:e.failed?`bg-[var(--oke-danger)]`:`bg-[var(--oke-accent)]`),style:{left:`${e.start*100}%`,width:`${Math.max(2,e.width*100)}%`}},t))})}var $=t({default:()=>Q});export{w as n,$ as t};
|
|
1
|
+
import{a as e,r as t}from"./rolldown-runtime-CNC7AqOf.js";import{C as n,Q as r,Z as i,b as a,d as o,et as s,l as c,nt as l,o as u,tt as d,u as f,w as p,y as m}from"./panel-access-C0J2D-a2.js";import{r as h}from"./panel-runs-C0gmnoYL.js";import{n as g,t as _}from"./panel-flows-DlCU5zjA.js";var v=e(l(),1);function y(e,t){if(!t)return!0;switch(t.kind){case`wrote`:return e.effects.some(e=>e.kind===`write`&&e.resource===t.resource);case`asked`:return e.effects.some(e=>e.kind===`ask`);case`sent`:return e.effects.some(e=>e.kind===`send`&&(t.resource===void 0||e.resource===t.resource));case`secret`:return e.effects.some(e=>e.kind===`secret`&&(t.resource===void 0||e.resource===t.resource));case`cost`:return(e.cost??0)>t.min}}function b(e,t){return!t||e.some(e=>y(e,t))}function x(e){if(!e?.trim())return null;let t=e.trim();if(t===`asked`)return{kind:`asked`};if(t===`sent`)return{kind:`sent`};if(t.startsWith(`wrote:`))return{kind:`wrote`,resource:t.slice(6)};if(t.startsWith(`sent:`))return{kind:`sent`,resource:t.slice(5)};if(t.startsWith(`secret:`))return{kind:`secret`,resource:t.slice(7)};if(t===`secret`)return{kind:`secret`};if(t.startsWith(`cost:`)){let e=Number(t.slice(5));return Number.isFinite(e)?{kind:`cost`,min:e}:null}return null}function S(e){if(e)switch(e.kind){case`wrote`:return`wrote:${e.resource}`;case`asked`:return`asked`;case`sent`:return e.resource?`sent:${e.resource}`:`sent`;case`secret`:return e.resource?`secret:${e.resource}`:`secret`;case`cost`:return`cost:${e.min}`}}var C=m({trace:a().optional(),span:a().optional(),effect:a().optional(),q:a().optional(),folds:a().optional(),boost:a().optional()});function w(e){let t=C.safeParse(e??{});return t.success?t.data:C.parse({})}function T(e){let t={};return e.trace&&(t.trace=e.trace),e.span&&(t.span=e.span),e.effect&&(t.effect=e.effect),e.q&&(t.q=e.q),e.folds&&(t.folds=e.folds),e.boost&&(t.boost=e.boost),t}function E(e){return e.folds?new Set(e.folds.split(`,`).map(e=>e.trim()).filter(Boolean)):new Set}function D(e,t,n){return{...e,trace:t,span:n}}function ee(e){return{...e,trace:void 0,span:void 0,folds:void 0}}function te(e,t){let n=E(e);n.has(t)?n.delete(t):n.add(t);let r=[...n].join(`,`);return{...e,folds:r||void 0}}function O(e,t){return{...e,effect:S(t)}}function k(e){let t=new Map,n=new Map;for(let n of e)t.set(n.id,n);for(let t of e){if(!t.parentId)continue;let e=n.get(t.parentId)??[];e.push(t),n.set(t.parentId,e)}for(let[,e]of n)e.sort((e,t)=>e.startedAt-t.startedAt);return{byId:t,childrenOf:n}}function A(e,t){let{byId:n,childrenOf:r}=k(e),i=n.get(t);if(!i)return null;let a=[],o=i,s=new Set;for(;o?.parentId&&!s.has(o.parentId);){s.add(o.parentId);let e=n.get(o.parentId);if(!e)break;a.unshift(e),o=e}return{parents:a,current:i,children:r.get(i.id)??[],connected:N((a[0]??i).id,n,r)}}function j(e){let{byId:t,childrenOf:n}=k(e),r=e.filter(e=>!e.parentId||!t.has(e.parentId));return r.sort((e,t)=>t.startedAt-e.startedAt),r.map(e=>({rootId:e.id,root:e,spans:N(e.id,t,n)}))}function M(e,t){if(t&&e.some(e=>e.id===t))return t;let n=e.find(e=>e.errorCode!=null&&e.errorCode!==``);return n?n.id:e.find(t=>!t.parentId||!e.some(e=>e.id===t.parentId))?.id??e[0]?.id}function N(e,t,n){let r=[],i=e=>{let a=t.get(e);if(a){r.push(a);for(let t of n.get(e)??[])i(t.id)}};return i(e),r.sort((e,t)=>e.startedAt-t.startedAt),r}function P(e){if(e.length===0)return new Set;let{byId:t,childrenOf:n}=k(e),r=e.filter(e=>!e.parentId||!t.has(e.parentId)),i=[],a=-1,o=(e,r,s)=>{let c=n.get(e)??[],l=t.get(e);if(!l)return;let u=s+F(l),d=[...r,e];if(c.length===0){u>a&&(a=u,i=d);return}for(let e of c)o(e.id,d,u)};for(let e of r)o(e.id,[],0);return new Set(i)}function F(e){return e.effects.length===0?Math.max(0,e.durationMs):e.effects.reduce((e,t)=>e+Math.max(0,t.duration),0)}function I(e){switch(e){case`read`:return`reads`;case`write`:return`writes`;case`emit`:return`emits`;case`send`:case`ask`:return`external`;case`secret`:return`capabilities`;case`call`:return`reads`}}function L(e){let t=`none`;for(let n of e){let e=I(n.kind);z(e)>z(t)&&(t=e)}return t}function R(e){return e.some(e=>L(e.effects)===`external`)}function z(e){switch(e){case`external`:return 5;case`capabilities`:return 4;case`emits`:return 3;case`writes`:return 2;case`reads`:return 1;case`none`:return 0}}function B(e){let t=Math.max(0,Math.round(e));if(t<1e3)return`${t}ms idle`;let n=t/1e3;if(n<60)return`${U(n)}s idle`;let r=n/60;if(r<60)return`${U(r)}m idle`;let i=r/60;return i<48?`${U(i)}h idle`:`${U(i/24)}d idle`}function V(e,t={},n=new Set){let r=t.foldThresholdMs??50,i=t.expandedFolds??new Set,a=[...e].sort((e,t)=>e.startMs-t.startMs);if(a.length===0)return{segments:[],displayDurationMs:0,wallDurationMs:0};let o=a[0],s=a[a.length-1];if(!o||!s)return{segments:[],displayDurationMs:0,wallDurationMs:0};let c=o.startMs,l=Math.max(...a.map(e=>e.endMs)),u=[],d=c;for(let e of a){let t=e.startMs-d;if(t>=r){let n=`fold:${d}:${e.startMs}`,r=i.has(n),a=t;u.push({kind:`fold`,id:n,startMs:d,endMs:e.startMs,durationMs:a,label:B(a),expanded:r,displayMs:r?a:40})}let a=Math.max(0,e.endMs-e.startMs);u.push({kind:`work`,id:e.id,label:e.label,startMs:e.startMs,endMs:e.endMs,durationMs:a,tier:e.tier,spanId:e.spanId,critical:n.has(e.spanId),failed:e.failed===!0,displayMs:Math.max(1,a)}),d=Math.max(d,e.endMs)}let f=u.reduce((e,t)=>e+t.displayMs,0);return{segments:u,displayDurationMs:Math.max(1,f),wallDurationMs:l-c}}function H(e){let t=[];for(let n of e)if(n.effects.length>0)for(let e of n.effects)t.push({id:`${n.id}:${e.kind}:${e.resource}:${e.timestamp}`,label:`${e.kind} ${e.resource}`,startMs:e.timestamp,endMs:e.timestamp+Math.max(1,e.duration),tier:I(e.kind),spanId:n.id,failed:n.errorCode!=null&&e===n.effects[n.effects.length-1]});else t.push({id:n.id,label:n.flow,startMs:n.startedAt,endMs:n.endedAt,tier:`none`,spanId:n.id,failed:n.errorCode!=null});return t}function U(e){let t=Math.round(e*10)/10;return Number.isInteger(t)?String(t):t.toFixed(1)}function W(e){if(e.length===0)return[];let t=Math.min(...e.map(e=>e.startedAt)),n=Math.max(...e.map(e=>e.endedAt)),r=Math.max(1,n-t);if(e.every(e=>e.effects.length===0))return e.map(e=>({start:(e.startedAt-t)/r,width:Math.max(.02,e.durationMs/r),tier:L(e.effects),failed:e.errorCode!=null}));let i=[];for(let n of e){if(n.effects.length===0){i.push({start:(n.startedAt-t)/r,width:Math.max(.02,n.durationMs/r),tier:`none`,failed:n.errorCode!=null});continue}for(let e=0;e<n.effects.length;e++){let a=n.effects[e];a&&i.push({start:(a.timestamp-t)/r,width:Math.max(.02,a.duration/r),tier:I(a.kind),failed:n.errorCode!=null&&e===n.effects.length-1})}}return i}function G(e){for(let t of e)if(t.errorCode)return t.errorCode;return null}function K(e){return R(e)?{mode:`dry-run`,reason:`This trace contains an external effect. Replay runs as a dry run with external effects stubbed.`}:{mode:`replay`}}var q=`10% + all errors`,J=600*1e3;function Y(e,t=Date.now()){let n=e.filter(e=>e.until>t);return n.length===0?q:`${q} · full: ${n.map(e=>e.flow).join(`, `)}`}function X(e,t,n=Date.now()){let r=n+J;return[...e.filter(e=>e.flow!==t&&e.until>n),{flow:t,until:r}]}function ne(e,t=Date.now()){return e.filter(e=>e.until>t)}var Z=d();function Q(){let e=p({from:`/traces`}),t=n({from:`/traces`}),a=s(),[l,d]=(0,v.useState)([]),[m]=(0,v.useState)(()=>_()),[y,S]=(0,v.useState)(0),[,C]=(0,v.useState)(0),w=e=>{t({search:T(e),replace:!0})},k=r({queryKey:[`console.runs.list`],queryFn:async()=>{let e=await o.runsList();if(e.error)throw Error(e.error.code);return e.data.runs},refetchInterval:5e3}),N=(0,v.useMemo)(()=>(k.data??[]).map(re),[k.data]);(0,v.useEffect)(()=>{if(N.length===0)return;if(m.visible.length===0){for(let e of N)m.offer({id:e.id,value:e,arrivedAt:e.startedAt});m.flush(),S(0),C(e=>e+1);return}let e=new Set(m.visible.map(e=>e.id));for(let t of m.pending)e.add(t.id);for(let t of N)e.has(t.id)?m.updateInPlace(t.id,t):m.offer({id:t.id,value:t,arrivedAt:Date.now()});S(m.pendingCount),C(e=>e+1)},[N,m]);let F=m.visible.map(e=>e.value),I=x(e.effect),R=(0,v.useMemo)(()=>j(F).filter(t=>{let n=g([t.root.flow,t.root.id,G(t.spans)??``],e.q),r=b(t.spans,I);return n&&r}),[F,e.q,I]),z=R.find(t=>t.rootId===e.trace)??(e.trace?j(F).find(t=>t.rootId===e.trace):void 0),B=z?M(z.spans,e.span):void 0,U=B?A(F,B):null,q=U?P(U.connected):new Set,J=U?V(H(U.connected),{expandedFolds:E(e)},q):null,Q=U?K(U.connected):null,$=i({mutationFn:async()=>{if(!U||!Q)return;let e=await o.tracesReplay({rootId:U.connected[0]?.id??U.current.id,dryRun:Q.mode===`dry-run`});if(e.error)throw Error(e.error.code);return e.data},onSuccess:()=>{a.invalidateQueries({queryKey:[`console.runs.list`]})}}),ae=ne(l);return(0,Z.jsxs)(`div`,{className:`flex h-full min-h-0 flex-col`,children:[(0,Z.jsxs)(`header`,{className:`flex shrink-0 flex-wrap items-end gap-4 border-b border-[var(--oke-line)] px-6 py-4`,children:[(0,Z.jsxs)(`div`,{className:`flex flex-col gap-1`,children:[(0,Z.jsx)(`p`,{className:`text-xs uppercase tracking-[0.2em] text-[var(--oke-muted)]`,children:`Traces`}),(0,Z.jsx)(`h1`,{className:`text-xl font-semibold tracking-tight`,children:`Causal chain`}),(0,Z.jsxs)(`p`,{className:`text-xs text-[var(--oke-muted)]`,children:[`Sampling: `,Y(ae)]})]}),(0,Z.jsxs)(`label`,{className:`flex flex-col gap-1 text-sm`,children:[(0,Z.jsx)(`span`,{className:`text-[var(--oke-muted)]`,children:`Filter by effect`}),(0,Z.jsxs)(`select`,{"aria-label":`Filter by effect`,className:`min-h-8 border border-[var(--oke-line)] bg-transparent px-2 text-sm`,value:e.effect??``,onChange:t=>{let n=t.target.value;w(O(e,n?x(n):null))},children:[(0,Z.jsx)(`option`,{value:``,children:`All effects`}),(0,Z.jsx)(`option`,{value:`wrote:sql:bookings`,children:`Wrote sql:bookings`}),(0,Z.jsx)(`option`,{value:`sent`,children:`Sent (channel)`}),(0,Z.jsx)(`option`,{value:`asked`,children:`Asked a model`}),(0,Z.jsx)(`option`,{value:`secret`,children:`Read a secret`}),(0,Z.jsx)(`option`,{value:`cost:0.05`,children:`Cost > $0.05`})]})]}),(0,Z.jsxs)(`div`,{className:`flex flex-wrap items-center gap-2`,children:[(0,Z.jsx)(u,{type:`button`,variant:`ghost`,onClick:()=>{let e=z?.root.flow??R[0]?.root.flow??`bookings.create`;d(t=>X(t,e))},children:`Trace flow fully for 10 minutes`}),(0,Z.jsx)(c,{count:y,onFlush:()=>{m.flush(),S(0),C(e=>e+1)}})]})]}),(0,Z.jsxs)(`div`,{className:`grid min-h-0 flex-1 grid-cols-1 md:grid-cols-[minmax(0,1fr)_minmax(0,1.4fr)]`,children:[(0,Z.jsx)(`section`,{"aria-label":`Trace list`,className:`min-h-0 overflow-auto border-r border-[var(--oke-line)]`,children:k.isLoading?(0,Z.jsx)(`p`,{className:`px-6 py-8 text-sm text-[var(--oke-muted)]`,children:`Loading traces…`}):R.length===0?(0,Z.jsx)(`p`,{className:`px-6 py-8 text-sm text-[var(--oke-muted)]`,children:`No traces yet. Invoke a flow or wait for traffic.`}):(0,Z.jsx)(`ul`,{className:`divide-y divide-[var(--oke-line)]`,children:R.map(t=>{let n=G(t.spans),r=W(t.spans),i=t.rootId===e.trace;return(0,Z.jsx)(`li`,{children:(0,Z.jsxs)(`button`,{type:`button`,"aria-pressed":i,className:f(`flex w-full min-h-10 flex-col gap-1 px-4 py-3 text-left text-sm`,i?`bg-[color-mix(in_oklab,var(--oke-fg)_6%,transparent)]`:`hover:bg-[color-mix(in_oklab,var(--oke-fg)_3%,transparent)]`),onClick:()=>{let n=M(t.spans);w(D(e,t.rootId,n))},children:[(0,Z.jsxs)(`div`,{className:`flex items-center justify-between gap-3`,children:[(0,Z.jsx)(`span`,{className:`font-medium`,children:t.root.flow}),n?(0,Z.jsx)(`span`,{role:`status`,className:`font-mono text-xs text-[var(--oke-danger)]`,children:n}):(0,Z.jsxs)(`span`,{className:`font-mono text-xs text-[var(--oke-muted)]`,children:[t.root.durationMs,`ms`]})]}),(0,Z.jsx)(ie,{bars:r})]})},t.rootId)})})}),(0,Z.jsx)(`section`,{"aria-label":`Trace detail`,className:`min-h-0 overflow-auto px-6 py-6`,"aria-live":`polite`,children:!U||!J?(0,Z.jsx)(`p`,{className:`text-sm text-[var(--oke-muted)]`,children:`Select a trace to see the causal chain and folded-time waterfall.`}):(0,Z.jsxs)(`div`,{className:`flex flex-col gap-6`,children:[(0,Z.jsxs)(`div`,{className:`flex flex-wrap items-start justify-between gap-3`,children:[(0,Z.jsxs)(`div`,{children:[(0,Z.jsx)(`h2`,{className:`text-lg font-semibold`,children:U.current.flow}),(0,Z.jsxs)(`p`,{className:`text-xs text-[var(--oke-muted)]`,children:[U.connected.length,` span`,U.connected.length===1?``:`s`,` · wall `,J.wallDurationMs,`ms · display scale `,Math.round(J.displayDurationMs),`ms`]})]}),(0,Z.jsxs)(`div`,{className:`flex flex-wrap gap-2`,children:[(0,Z.jsx)(h,{to:`/runs`,search:{run:U.current.id},className:`inline-flex min-h-8 items-center border border-[var(--oke-line)] px-3 text-sm`,children:`Open in Runs`}),(0,Z.jsx)(u,{type:`button`,variant:Q?.mode===`dry-run`?`external`:`primary`,disabled:$.isPending,title:Q?.mode===`dry-run`?Q.reason:`Replay from the journal`,onClick:()=>$.mutate(),children:Q?.mode===`dry-run`?`Dry-run replay`:`Replay`}),(0,Z.jsx)(u,{type:`button`,variant:`ghost`,onClick:()=>w(ee(e)),children:`Close`})]})]}),Q?.mode===`dry-run`?(0,Z.jsx)(`p`,{role:`note`,className:`text-sm text-[var(--oke-external)]`,children:Q.reason}):null,(0,Z.jsxs)(`div`,{children:[(0,Z.jsx)(`h3`,{className:`mb-2 text-sm font-medium`,children:`Causal chain`}),(0,Z.jsxs)(`ol`,{className:`flex flex-col gap-1 border-l border-[var(--oke-line)] pl-4`,children:[U.parents.map(t=>(0,Z.jsx)(`li`,{children:(0,Z.jsx)(`button`,{type:`button`,className:`min-h-8 text-sm text-[var(--oke-muted)]`,onClick:()=>w({...e,span:t.id}),children:t.flow})},t.id)),(0,Z.jsxs)(`li`,{"aria-current":`true`,children:[(0,Z.jsx)(`span`,{className:`text-sm font-medium`,children:U.current.flow}),U.current.errorCode?(0,Z.jsx)(`span`,{role:`status`,className:`ml-2 font-mono text-xs text-[var(--oke-danger)]`,children:U.current.errorCode}):null,L(U.current.effects)===`external`?(0,Z.jsx)(`span`,{"aria-label":`external effect`,children:` ↗`}):null]}),U.children.map(t=>(0,Z.jsx)(`li`,{children:(0,Z.jsxs)(`button`,{type:`button`,className:`min-h-8 text-sm text-[var(--oke-muted)]`,onClick:()=>w({...e,span:t.id}),children:[t.flow,L(t.effects)===`external`?(0,Z.jsx)(`span`,{"aria-label":`external effect`,children:` ↗`}):null]})},t.id))]})]}),(0,Z.jsxs)(`div`,{children:[(0,Z.jsx)(`h3`,{id:`waterfall-heading`,className:`mb-2 text-sm font-medium`,children:`Waterfall`}),(0,Z.jsx)(`ul`,{"aria-labelledby":`waterfall-heading`,className:`flex min-h-10 list-none items-stretch gap-0.5 p-0`,children:J.segments.map(t=>t.kind===`fold`?(0,Z.jsx)(`li`,{style:{flex:`${t.displayMs} 1 0`,minWidth:24},children:(0,Z.jsx)(`button`,{type:`button`,"aria-expanded":t.expanded,className:`h-full min-h-10 w-full border border-dashed border-[var(--oke-line)] px-1 font-mono text-[10px] text-[var(--oke-muted)]`,onClick:()=>w(te(e,t.id)),children:t.label})},t.id):(0,Z.jsx)(`li`,{title:t.label,className:f(`min-h-10 px-1 text-[10px] leading-10`,t.tier===`external`?`bg-[var(--oke-external)] text-black`:`bg-[color-mix(in_oklab,var(--oke-accent)_55%,transparent)]`,t.failed&&`outline outline-2 outline-[var(--oke-danger)]`),style:{flex:`${t.displayMs} 1 0`,opacity:t.critical?1:.38,minWidth:4},children:(0,Z.jsxs)(`span`,{className:`sr-only`,children:[t.label,t.critical?` (critical path)`:``,t.failed?` (failed)`:``]})},t.id))}),(0,Z.jsx)(`p`,{className:`mt-2 text-xs text-[var(--oke-muted)]`,children:`Critical path at full opacity · dead time folded into expandable bars`})]})]})})]})]})}function re(e){return{id:e.id,...e.parentId?{parentId:e.parentId}:{},flow:e.flow,...e.unit?{unit:e.unit}:{},trigger:e.trigger,startedAt:e.startedAt,endedAt:e.endedAt,durationMs:e.durationMs,errorCode:e.error,cost:e.cost??void 0,sampled:e.sampled??(e.error?`error`:`sample`),effects:e.effects??[]}}function ie({bars:e}){return(0,Z.jsx)(`div`,{"aria-hidden":`true`,className:`relative h-2 w-full overflow-hidden bg-[color-mix(in_oklab,var(--oke-fg)_6%,transparent)]`,children:e.map((e,t)=>(0,Z.jsx)(`span`,{className:f(`absolute inset-y-0`,e.tier===`external`?`bg-[var(--oke-external)]`:e.failed?`bg-[var(--oke-danger)]`:`bg-[var(--oke-accent)]`),style:{left:`${e.start*100}%`,width:`${Math.max(2,e.width*100)}%`}},t))})}var $=t({default:()=>Q});export{w as n,$ as t};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{a as e,r as t}from"./rolldown-runtime-CNC7AqOf.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-C0J2D-a2.js";import{n as _}from"./panel-channels-DCDd4WAC.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}}function S(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 C(e={production:!0}){return e.production?{kind:`typed`,phrase:`SET`,requireReason:!0}:{kind:`undo`,windowMs:15e3}}function w(e={production:!0}){return{kind:`typed`,phrase:`ROTATE`,requireReason:!0}}function T(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:E(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 E(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 D(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 O(e){return JSON.stringify(e.map(e=>D(e)),null,2)}var k=e(d(),1),A=p();function j(){let e=h({from:`/vault`}),t=n({from:`/vault`}),o=l(),[u,d]=(0,k.useState)(``),[p,g]=(0,k.useState)(``),[v,y]=(0,k.useState)(``),[E,D]=(0,k.useState)(null),j=e=>{t({search:b(e),replace:!0})},M=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}),N=M.data?.secrets??[],P=M.data?.env??`local`,F=(0,k.useMemo)(()=>S(N,e.q??``),[N,e.q]),I=N.find(t=>t.name===e.name),L=I?T(I.blastRadius):null,R=C({production:!0}),z=w({production:!0}),B=e.action;(0,k.useEffect)(()=>{d(``),g(``),y(``),D(null)},[I?.name,B]);let V=i({mutationFn:async()=>{if(!I)throw Error(`no secret`);if(R.kind===`typed`){let e=a({typed:u,reason:p,phrase:R.phrase});if(e)throw Error(e.typed??e.reason??`confirm`)}let e=await c.vaultSet({name:I.name,value:v,confirmation:R.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(``),j({...e,action:void 0}),await o.invalidateQueries({queryKey:[`console.vault.list`]})}}),H=i({mutationFn:async()=>{if(!I)throw Error(`no secret`);let e=a({typed:u,reason:p,phrase:z.kind===`typed`?z.phrase:`ROTATE`});if(e)throw Error(e.typed??e.reason??`confirm`);let t=await c.vaultRotate({name:I.name,value:v,confirmation:u,reason:p});if(t.error)throw Error(t.error.code);return t.data},onSuccess:async()=>{y(``),d(``),g(``),j({...e,action:void 0}),await o.invalidateQueries({queryKey:[`console.vault.list`]})}});return(0,A.jsxs)(`div`,{className:`flex h-full min-h-0 flex-col`,children:[(0,A.jsxs)(`header`,{className:`flex shrink-0 flex-wrap items-end gap-3 border-b border-[var(--oke-line)] px-4 py-3`,children:[(0,A.jsxs)(`div`,{children:[(0,A.jsx)(`h1`,{className:`text-lg font-medium text-[var(--oke-fg)]`,children:`Vault`}),(0,A.jsx)(`p`,{className:`text-sm text-[var(--oke-muted)]`,children:`Fingerprints only — secrets are write-only`})]}),(0,A.jsxs)(`p`,{className:`text-sm text-[var(--oke-muted)]`,role:`status`,children:[`Environment `,P]}),(0,A.jsxs)(`label`,{className:`ml-auto flex min-w-[12rem] flex-col gap-1 text-sm`,children:[(0,A.jsx)(`span`,{className:`text-[var(--oke-muted)]`,children:`Filter vault`}),(0,A.jsx)(s,{"aria-label":`Filter vault`,value:e.q??``,onChange:t=>j({...e,q:t.currentTarget.value||void 0})})]}),(0,A.jsx)(f,{type:`button`,variant:`ghost`,onClick:()=>{let e=O(N);navigator.clipboard?.writeText(e),D(`Exported fingerprints only (no secret values)`)},children:`Export`})]}),E?(0,A.jsx)(`p`,{className:`px-4 py-2 text-sm text-[var(--oke-muted)]`,role:`status`,children:E}):null,(0,A.jsxs)(`div`,{className:`flex min-h-0 flex-1`,children:[(0,A.jsxs)(`section`,{"aria-label":`Vault list`,className:`w-80 shrink-0 overflow-y-auto border-r border-[var(--oke-line)]`,children:[(0,A.jsx)(`h2`,{className:`sr-only`,children:`Contracts`}),M.isLoading?(0,A.jsx)(`p`,{className:`p-4 text-sm text-[var(--oke-muted)]`,children:`Loading…`}):null,F.map(t=>(0,A.jsxs)(`section`,{"aria-label":t.label,className:`py-2`,children:[(0,A.jsx)(`h3`,{className:`px-4 py-1 text-xs uppercase tracking-wide text-[var(--oke-muted)]`,children:t.label}),(0,A.jsx)(`ul`,{children:t.secrets.map(t=>(0,A.jsx)(`li`,{children:(0,A.jsxs)(`button`,{type:`button`,"aria-pressed":t.name===I?.name,className:m(`flex min-h-10 w-full flex-col items-start px-4 py-2 text-left text-sm`,t.name===I?.name?`bg-[var(--oke-line)] text-[var(--oke-fg)]`:`text-[var(--oke-muted)] hover:text-[var(--oke-fg)]`),onClick:()=>j(x(e,t.name)),children:[(0,A.jsx)(`span`,{children:_(t.name,t.description)}),t.description?(0,A.jsx)(`span`,{className:`font-mono text-xs text-[var(--oke-muted)]`,children:t.name}):null,(0,A.jsx)(`span`,{className:`truncate text-xs`,children:t.sensitive?t.fingerprint??`unset`:t.cleartext??`unset`}),t.blastRadius.count>0?(0,A.jsxs)(`span`,{role:`status`,className:`text-xs text-[var(--oke-danger)]`,children:[`blast `,t.blastRadius.count]}):null,t.sharedFingerprintEnvs.length>0?(0,A.jsx)(`span`,{role:`status`,className:`text-xs`,children:`shared fingerprint`}):null]})},t.name))})]},t.kind))]}),(0,A.jsx)(`section`,{"aria-label":`Vault detail`,"aria-live":`polite`,className:`min-w-0 flex-1 overflow-y-auto p-4`,children:I?(0,A.jsxs)(`div`,{className:`flex max-w-2xl flex-col gap-6`,children:[(0,A.jsxs)(`div`,{children:[(0,A.jsx)(`h2`,{className:`text-lg text-[var(--oke-fg)]`,children:_(I.name,I.description)}),I.description?(0,A.jsx)(`p`,{className:`font-mono text-sm text-[var(--oke-muted)]`,children:I.name}):null,I.rotate?(0,A.jsxs)(`p`,{className:`text-sm text-[var(--oke-muted)]`,children:[`Rotate hint: `,I.rotate]}):null]}),(0,A.jsxs)(`section`,{"aria-label":`Fingerprints by environment`,children:[(0,A.jsx)(`h3`,{className:`mb-2 text-sm font-medium`,children:`Fingerprints`}),I.sensitive?(0,A.jsxs)(`ul`,{className:`space-y-1 font-mono text-sm`,children:[Object.entries(I.fingerprints).map(([e,t])=>(0,A.jsxs)(`li`,{children:[(0,A.jsxs)(`span`,{className:`text-[var(--oke-muted)]`,children:[e,`:`]}),` `,t,I.sharedFingerprintEnvs.includes(e)?(0,A.jsxs)(`span`,{role:`status`,className:`ml-2 text-[var(--oke-warn,var(--oke-muted))]`,children:[`(matches `,P,` — warning, may be deliberate)`]}):null]},e)),Object.keys(I.fingerprints).length===0?(0,A.jsx)(`li`,{className:`text-[var(--oke-muted)]`,children:`Unset`}):null]}):(0,A.jsx)(`p`,{className:`font-mono text-sm`,role:`status`,children:I.cleartext??`unset`})]}),(0,A.jsxs)(`section`,{"aria-label":`Resolution chain`,children:[(0,A.jsx)(`h3`,{className:`mb-2 text-sm font-medium`,children:`Resolution chain`}),(0,A.jsx)(`ol`,{className:`list-decimal space-y-1 pl-5 text-sm`,children:I.resolution.map(e=>(0,A.jsxs)(`li`,{className:e.won?`text-[var(--oke-fg)]`:`text-[var(--oke-muted)]`,children:[(0,A.jsx)(`span`,{className:`font-mono`,children:e.source}),e.won?` — won`:e.present?` — present (lost)`:` — absent`]},e.source))}),(0,A.jsxs)(`p`,{className:`mt-2 text-sm`,role:`status`,children:[`Winner: `,(0,A.jsx)(`span`,{className:`font-mono`,children:I.winner??`none`})]})]}),(0,A.jsxs)(`section`,{"aria-label":`Readers`,children:[(0,A.jsx)(`h3`,{className:`mb-2 text-sm font-medium`,children:`Readers`}),(0,A.jsxs)(`p`,{className:`text-sm text-[var(--oke-muted)]`,children:[`Flows that declare `,(0,A.jsxs)(`code`,{className:`font-mono`,children:[`fx.vault(`,I.name,`)`]})]}),(0,A.jsx)(`ul`,{className:`mt-1 list-disc pl-5 font-mono text-sm`,children:I.readers.length===0?(0,A.jsx)(`li`,{className:`text-[var(--oke-muted)]`,children:`none`}):I.readers.map(e=>(0,A.jsx)(`li`,{children:e},e))})]}),(0,A.jsxs)(`section`,{"aria-label":`Rotation blast radius`,children:[(0,A.jsx)(`h3`,{className:`mb-2 text-sm font-medium`,children:`Rotation blast radius`}),L?(0,A.jsxs)(A.Fragment,{children:[(0,A.jsx)(`p`,{className:`text-sm`,role:L.warn?`alert`:`status`,children:L.summary}),L.detail?(0,A.jsx)(`p`,{className:`text-sm text-[var(--oke-muted)]`,children:L.detail}):null,I.blastRadius.runIds.length>0?(0,A.jsx)(`p`,{className:`mt-1 font-mono text-xs text-[var(--oke-muted)]`,children:I.blastRadius.runIds.join(`, `)}):null]}):null]}),(0,A.jsxs)(`section`,{"aria-label":`Last read`,children:[(0,A.jsx)(`h3`,{className:`mb-2 text-sm font-medium`,children:`Last read`}),(0,A.jsx)(`p`,{className:`text-sm`,role:`status`,children:I.lastReadAt==null?`Never read — possible dead secret`:new Date(I.lastReadAt).toISOString()})]}),(0,A.jsxs)(`section`,{"aria-label":`Set or rotate`,className:`space-y-3`,children:[(0,A.jsx)(`h3`,{className:`text-sm font-medium`,children:`Set / rotate`}),(0,A.jsx)(`p`,{className:`text-sm text-[var(--oke-muted)]`,children:`Write-only. Values are never revealed after submit. No preview.`}),(0,A.jsxs)(`div`,{className:`flex gap-2`,children:[(0,A.jsx)(f,{type:`button`,variant:B===`set`?`primary`:`ghost`,"aria-pressed":B===`set`,onClick:()=>j({...e,action:`set`}),children:`Set`}),(0,A.jsx)(f,{type:`button`,variant:B===`rotate`?`danger`:`ghost`,"aria-pressed":B===`rotate`,onClick:()=>j({...e,action:`rotate`}),children:`Rotate`})]}),B?(0,A.jsxs)(`div`,{className:`space-y-3 border border-[var(--oke-line)] p-3`,children:[(0,A.jsxs)(`label`,{className:`flex flex-col gap-1 text-sm`,children:[(0,A.jsx)(`span`,{children:`New value`}),(0,A.jsx)(s,{"aria-label":`New vault value`,type:`password`,autoComplete:`off`,value:v,onChange:e=>y(e.currentTarget.value)})]}),(B===`rotate`||R.kind===`typed`)&&(0,A.jsxs)(A.Fragment,{children:[(0,A.jsxs)(`label`,{className:`flex flex-col gap-1 text-sm`,children:[(0,A.jsxs)(`span`,{children:[`Type`,` `,B===`rotate`?z.kind===`typed`?z.phrase:`ROTATE`:R.kind===`typed`?R.phrase:`SET`,` `,`to confirm`]}),(0,A.jsx)(s,{"aria-label":`Confirmation phrase`,value:u,onChange:e=>d(e.currentTarget.value)})]}),(0,A.jsxs)(`label`,{className:`flex flex-col gap-1 text-sm`,children:[(0,A.jsx)(`span`,{children:`Reason`}),(0,A.jsx)(s,{"aria-label":`Reason for vault write`,value:p,onChange:e=>g(e.currentTarget.value)})]})]}),(0,A.jsx)(f,{type:`button`,variant:B===`rotate`?`danger`:`primary`,disabled:!v||(B===`set`?V.isPending:H.isPending),onClick:()=>{B===`set`?V.mutate():H.mutate()},children:B===`set`?`Commit set`:`Commit rotate`}),(V.isError||H.isError)&&(0,A.jsx)(`p`,{role:`alert`,className:`text-sm text-[var(--oke-danger)]`,children:(V.error??H.error)?.message??`Failed`})]}):null]})]}):(0,A.jsx)(`p`,{className:`text-sm text-[var(--oke-muted)]`,children:`Select a contract to inspect fingerprints, resolution, and readers.`})})]})]})}var M=t({default:()=>j});export{y as n,M as t};
|
|
@@ -5,7 +5,7 @@
|
|
|
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-
|
|
8
|
+
<script type="module" crossorigin src="/assets/index-CrKMmO__.js"></script>
|
|
9
9
|
<link rel="modulepreload" crossorigin href="/assets/rolldown-runtime-CNC7AqOf.js">
|
|
10
10
|
<link rel="stylesheet" crossorigin href="/assets/style-C8MxEWPd.css">
|
|
11
11
|
</head>
|
|
@@ -16,6 +16,7 @@ export interface FlowGatesRecord {
|
|
|
16
16
|
/** Declared gate definition. */
|
|
17
17
|
export interface GateDefRecord {
|
|
18
18
|
readonly name: string;
|
|
19
|
+
readonly description?: string;
|
|
19
20
|
readonly kind: "policy" | "rate";
|
|
20
21
|
readonly scopes: readonly string[];
|
|
21
22
|
readonly roles: readonly string[];
|
|
@@ -81,6 +81,7 @@ export const PLUGINS_LIST_FIXTURE: PluginsListResponse = {
|
|
|
81
81
|
summary: "Hybrid session, two planes, roles as data",
|
|
82
82
|
scopes: [{ kind: "app" }],
|
|
83
83
|
declares: ["table:oke_identities", "table:oke_operators"],
|
|
84
|
+
tables: {},
|
|
84
85
|
intercepts: [{ stage: "onAuth", meanMs: 0.4, count: 12 }],
|
|
85
86
|
hookCost: {
|
|
86
87
|
count: 12,
|
|
@@ -103,6 +104,7 @@ export const PLUGINS_LIST_FIXTURE: PluginsListResponse = {
|
|
|
103
104
|
summary: "Operator Console on :6533",
|
|
104
105
|
scopes: [{ kind: "app" }],
|
|
105
106
|
declares: ["consolePanel:overview", "consolePanel:traces", "table:oke_console_prefs"],
|
|
107
|
+
tables: {},
|
|
106
108
|
intercepts: [{ stage: "beforeHandle", meanMs: 0.2, count: 40 }],
|
|
107
109
|
hookCost: {
|
|
108
110
|
count: 40,
|
|
@@ -125,6 +127,7 @@ export const PLUGINS_LIST_FIXTURE: PluginsListResponse = {
|
|
|
125
127
|
summary: "Attachment-scoped request rate limits",
|
|
126
128
|
scopes: [],
|
|
127
129
|
declares: [],
|
|
130
|
+
tables: {},
|
|
128
131
|
intercepts: [],
|
|
129
132
|
hookCost: null,
|
|
130
133
|
supplyChain: SUPPLY_CHAIN_CORE_NA,
|
|
@@ -141,6 +144,7 @@ export const PLUGINS_LIST_FIXTURE: PluginsListResponse = {
|
|
|
141
144
|
summary: "Multi-tenant isolation (row · schema · database)",
|
|
142
145
|
scopes: [],
|
|
143
146
|
declares: [],
|
|
147
|
+
tables: {},
|
|
144
148
|
intercepts: [],
|
|
145
149
|
hookCost: null,
|
|
146
150
|
supplyChain: SUPPLY_CHAIN_CORE_NA,
|
|
@@ -157,6 +161,7 @@ export const PLUGINS_LIST_FIXTURE: PluginsListResponse = {
|
|
|
157
161
|
summary: "PII classification, redact, export/erase tooling",
|
|
158
162
|
scopes: [],
|
|
159
163
|
declares: [],
|
|
164
|
+
tables: {},
|
|
160
165
|
intercepts: [],
|
|
161
166
|
hookCost: null,
|
|
162
167
|
supplyChain: SUPPLY_CHAIN_CORE_NA,
|
|
@@ -173,6 +178,7 @@ export const PLUGINS_LIST_FIXTURE: PluginsListResponse = {
|
|
|
173
178
|
summary: null,
|
|
174
179
|
scopes: [{ kind: "app" }],
|
|
175
180
|
declares: ["consolePanel:audit", "table:oke_audit"],
|
|
181
|
+
tables: {},
|
|
176
182
|
intercepts: [{ stage: "afterHandle", meanMs: 1.2, count: 8 }],
|
|
177
183
|
hookCost: {
|
|
178
184
|
count: 8,
|
|
@@ -219,6 +225,7 @@ export const PLUGINS_LIST_FIXTURE: PluginsListResponse = {
|
|
|
219
225
|
summary: null,
|
|
220
226
|
scopes: [{ kind: "app" }],
|
|
221
227
|
declares: ["channel:slack"],
|
|
228
|
+
tables: {},
|
|
222
229
|
intercepts: [{ stage: "onResponse", meanMs: null, count: 0 }],
|
|
223
230
|
hookCost: null,
|
|
224
231
|
supplyChain: SUPPLY_CHAIN_COMMUNITY,
|
|
@@ -86,6 +86,9 @@ export interface PluginRecord {
|
|
|
86
86
|
readonly summary: string | null;
|
|
87
87
|
readonly scopes: readonly PluginScopeRecord[];
|
|
88
88
|
readonly declares: readonly string[];
|
|
89
|
+
readonly tables: Readonly<
|
|
90
|
+
Record<string, { readonly plane?: string; readonly description?: string }>
|
|
91
|
+
>;
|
|
89
92
|
readonly intercepts: readonly PluginInterceptRecord[];
|
|
90
93
|
readonly hookCost: {
|
|
91
94
|
readonly count: number;
|
|
@@ -333,6 +333,7 @@ interface ConsoleClient {
|
|
|
333
333
|
ref: string;
|
|
334
334
|
facet: "sql" | "kv" | "files" | "index";
|
|
335
335
|
name: string;
|
|
336
|
+
description?: string;
|
|
336
337
|
children: Array<{
|
|
337
338
|
name: string;
|
|
338
339
|
effectRef: string;
|
|
@@ -349,6 +350,7 @@ interface ConsoleClient {
|
|
|
349
350
|
channels: string[];
|
|
350
351
|
};
|
|
351
352
|
piiColumns: string[];
|
|
353
|
+
columnDescriptions: Record<string, string>;
|
|
352
354
|
}>;
|
|
353
355
|
replicaLagMs: number | null;
|
|
354
356
|
migrationDrift: {
|
|
@@ -987,6 +989,7 @@ interface ConsoleClient {
|
|
|
987
989
|
summary: string | null;
|
|
988
990
|
scopes: Array<{ kind: "app" | "unit" | "flow"; name?: string }>;
|
|
989
991
|
declares: string[];
|
|
992
|
+
tables: Record<string, { plane?: string; description?: string }>;
|
|
990
993
|
intercepts: Array<{
|
|
991
994
|
stage: string;
|
|
992
995
|
meanMs: number | null;
|
|
@@ -25,6 +25,7 @@ import {
|
|
|
25
25
|
} from "../../../channels/index.ts";
|
|
26
26
|
import { consoleCalls } from "../../client.ts";
|
|
27
27
|
import { Button } from "../../components/ui.tsx";
|
|
28
|
+
import { displayLabel } from "../../../display.ts";
|
|
28
29
|
|
|
29
30
|
/**
|
|
30
31
|
* Channels panel.
|
|
@@ -183,7 +184,7 @@ export function ChannelsPanel() {
|
|
|
183
184
|
)}
|
|
184
185
|
onClick={() => setSearch(openTemplate(search, t.name))}
|
|
185
186
|
>
|
|
186
|
-
<span>{t.name}</span>
|
|
187
|
+
<span>{displayLabel(t.name, t.description)}</span>
|
|
187
188
|
<span className="font-mono text-xs">{t.medium}</span>
|
|
188
189
|
</button>
|
|
189
190
|
</li>
|
|
@@ -260,8 +261,12 @@ export function ChannelsPanel() {
|
|
|
260
261
|
|
|
261
262
|
{open ? (
|
|
262
263
|
<section aria-label="Template detail" className="mb-8">
|
|
263
|
-
<h2 className="text-base text-[var(--oke-fg)]">
|
|
264
|
+
<h2 className="text-base text-[var(--oke-fg)]">
|
|
265
|
+
{displayLabel(open.name, open.description)}
|
|
266
|
+
</h2>
|
|
264
267
|
<p className="mt-1 text-sm text-[var(--oke-muted)]">
|
|
268
|
+
{open.description ? <span className="font-mono">{open.name}</span> : null}
|
|
269
|
+
{open.description ? " · " : ""}
|
|
265
270
|
From {open.from ?? "unset"} · Locales {open.locales.join(", ") || "none"}
|
|
266
271
|
</p>
|
|
267
272
|
|
|
@@ -27,6 +27,7 @@ import {
|
|
|
27
27
|
} from "../../../clock/index.ts";
|
|
28
28
|
import { consoleCalls } from "../../client.ts";
|
|
29
29
|
import { Button, Input } from "../../components/ui.tsx";
|
|
30
|
+
import { displayLabel } from "../../../display.ts";
|
|
30
31
|
|
|
31
32
|
/**
|
|
32
33
|
* Clock panel. Timeline + waiting-on + schedules; actions through `fx`.
|
|
@@ -264,7 +265,7 @@ export function ClockPanel() {
|
|
|
264
265
|
onClick={() => setSearch(openCron(search, c.name))}
|
|
265
266
|
>
|
|
266
267
|
<span className="flex items-center gap-1">
|
|
267
|
-
{c.name}
|
|
268
|
+
{displayLabel(c.name, c.description)}
|
|
268
269
|
{c.external ? <span aria-label="external effect">↗</span> : null}
|
|
269
270
|
{c.health.overdue ? (
|
|
270
271
|
<span role="status" className="text-[var(--oke-danger)]">
|
|
@@ -288,8 +289,14 @@ export function ClockPanel() {
|
|
|
288
289
|
aria-live="polite"
|
|
289
290
|
className="space-y-3 border-t border-[var(--oke-line)] pt-3"
|
|
290
291
|
>
|
|
291
|
-
<h3 className="text-base font-medium">
|
|
292
|
+
<h3 className="text-base font-medium">
|
|
293
|
+
{displayLabel(openCronRow.name, openCronRow.description)}
|
|
294
|
+
</h3>
|
|
292
295
|
<p className="text-sm text-[var(--oke-muted)]">
|
|
296
|
+
{openCronRow.description ? (
|
|
297
|
+
<span className="font-mono">{openCronRow.name}</span>
|
|
298
|
+
) : null}
|
|
299
|
+
{openCronRow.description ? " · " : ""}
|
|
293
300
|
{openCronRow.effectiveCron ?? openCronRow.effectiveEvery} · {openCronRow.timezone}
|
|
294
301
|
{openCronRow.status !== "active" ? ` · ${openCronRow.status}` : ""}
|
|
295
302
|
</p>
|
|
@@ -24,6 +24,7 @@ import {
|
|
|
24
24
|
} from "../../../gates/index.ts";
|
|
25
25
|
import { consoleCalls } from "../../client.ts";
|
|
26
26
|
import { Button, Input } from "../../components/ui.tsx";
|
|
27
|
+
import { displayLabel } from "../../../display.ts";
|
|
27
28
|
|
|
28
29
|
/**
|
|
29
30
|
* Gates panel. Inquiry direction and selection live in URL search params.
|
|
@@ -282,11 +283,17 @@ export function GatesPanel() {
|
|
|
282
283
|
aria-label="Gate chain"
|
|
283
284
|
className="mt-3 list-decimal space-y-1 pl-5 text-sm"
|
|
284
285
|
>
|
|
285
|
-
{openFlowRow.gates.map((g) =>
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
286
|
+
{openFlowRow.gates.map((g) => {
|
|
287
|
+
const def = data?.gates.find((d) => d.name === g);
|
|
288
|
+
return (
|
|
289
|
+
<li key={g}>
|
|
290
|
+
<span>{displayLabel(g, def?.description)}</span>
|
|
291
|
+
{def?.description ? (
|
|
292
|
+
<code className="ml-2 font-mono text-[var(--oke-muted)]">{g}</code>
|
|
293
|
+
) : null}
|
|
294
|
+
</li>
|
|
295
|
+
);
|
|
296
|
+
})}
|
|
290
297
|
</ol>
|
|
291
298
|
)}
|
|
292
299
|
</div>
|
|
@@ -21,6 +21,7 @@ import {
|
|
|
21
21
|
} from "../../../plugins/index.ts";
|
|
22
22
|
import { consoleCalls } from "../../client.ts";
|
|
23
23
|
import { Button, Input } from "../../components/ui.tsx";
|
|
24
|
+
import { displayLabel } from "../../../display.ts";
|
|
24
25
|
|
|
25
26
|
/**
|
|
26
27
|
* Plugins panel — read-only catalogue + supply-chain surface.
|
|
@@ -176,10 +177,23 @@ function PluginDetail(props: {
|
|
|
176
177
|
{p.declares.length === 0 ? (
|
|
177
178
|
<p className="mt-2 text-sm text-[var(--oke-muted)]">None</p>
|
|
178
179
|
) : (
|
|
179
|
-
<ul className="mt-2 list-inside list-disc
|
|
180
|
-
{p.declares.map((d) =>
|
|
181
|
-
|
|
182
|
-
|
|
180
|
+
<ul className="mt-2 list-inside list-disc text-sm">
|
|
181
|
+
{p.declares.map((d) => {
|
|
182
|
+
const tableName = d.startsWith("table:") ? d.slice("table:".length) : null;
|
|
183
|
+
const description = tableName ? p.tables[tableName]?.description : undefined;
|
|
184
|
+
return (
|
|
185
|
+
<li key={d}>
|
|
186
|
+
{tableName && description ? (
|
|
187
|
+
<>
|
|
188
|
+
<span>{displayLabel(tableName, description)}</span>
|
|
189
|
+
<code className="ml-2 font-mono text-[var(--oke-muted)]">{d}</code>
|
|
190
|
+
</>
|
|
191
|
+
) : (
|
|
192
|
+
<code className="font-mono">{d}</code>
|
|
193
|
+
)}
|
|
194
|
+
</li>
|
|
195
|
+
);
|
|
196
|
+
})}
|
|
183
197
|
</ul>
|
|
184
198
|
)}
|
|
185
199
|
</section>
|
|
@@ -31,6 +31,7 @@ import {
|
|
|
31
31
|
} from "../../../signals/index.ts";
|
|
32
32
|
import { consoleCalls } from "../../client.ts";
|
|
33
33
|
import { Button } from "../../components/ui.tsx";
|
|
34
|
+
import { displayLabel } from "../../../display.ts";
|
|
34
35
|
|
|
35
36
|
/**
|
|
36
37
|
* Signals panel. List + detail + DLQ state lives in URL search params.
|
|
@@ -248,13 +249,18 @@ export function SignalsPanel() {
|
|
|
248
249
|
onClick={() => setSearch(openSignal(search, s.name))}
|
|
249
250
|
>
|
|
250
251
|
<span className="font-medium">
|
|
251
|
-
{s.name}
|
|
252
|
+
{displayLabel(s.name, s.description)}
|
|
252
253
|
{s.orphaned ? (
|
|
253
254
|
<span role="status" className="ml-2 text-xs text-[var(--oke-muted)]">
|
|
254
255
|
orphaned
|
|
255
256
|
</span>
|
|
256
257
|
) : null}
|
|
257
258
|
</span>
|
|
259
|
+
{s.description ? (
|
|
260
|
+
<span className="font-mono text-xs text-[var(--oke-muted)]">
|
|
261
|
+
{s.name}
|
|
262
|
+
</span>
|
|
263
|
+
) : null}
|
|
258
264
|
<span className="text-xs text-[var(--oke-muted)]">
|
|
259
265
|
{s.delivery === "once" && (
|
|
260
266
|
<>
|
|
@@ -299,7 +305,12 @@ export function SignalsPanel() {
|
|
|
299
305
|
<div className="flex flex-col gap-6">
|
|
300
306
|
<div className="flex items-start justify-between gap-4">
|
|
301
307
|
<div>
|
|
302
|
-
<h2 className="text-lg font-semibold">
|
|
308
|
+
<h2 className="text-lg font-semibold">
|
|
309
|
+
{displayLabel(open.name, open.description)}
|
|
310
|
+
</h2>
|
|
311
|
+
{open.description ? (
|
|
312
|
+
<p className="font-mono text-sm text-[var(--oke-muted)]">{open.name}</p>
|
|
313
|
+
) : null}
|
|
303
314
|
<p
|
|
304
315
|
role="status"
|
|
305
316
|
className="mt-2 max-w-prose text-sm leading-relaxed"
|
|
@@ -24,6 +24,7 @@ import {
|
|
|
24
24
|
} from "../../../store/index.ts";
|
|
25
25
|
import { consoleCalls } from "../../client.ts";
|
|
26
26
|
import { Button } from "../../components/ui.tsx";
|
|
27
|
+
import { displayLabel } from "../../../display.ts";
|
|
27
28
|
|
|
28
29
|
/**
|
|
29
30
|
* Store panel. Tenant lives in the header when tenancy is declared.
|
|
@@ -320,7 +321,10 @@ export function StorePanel() {
|
|
|
320
321
|
)}
|
|
321
322
|
onClick={() => setSearch(openStore(search, s.ref))}
|
|
322
323
|
>
|
|
323
|
-
<span>{s.name}</span>
|
|
324
|
+
<span>{displayLabel(s.name, s.description)}</span>
|
|
325
|
+
{s.description ? (
|
|
326
|
+
<span className="font-mono text-xs text-[var(--oke-muted)]">{s.name}</span>
|
|
327
|
+
) : null}
|
|
324
328
|
<span className="text-xs text-[var(--oke-muted)]">
|
|
325
329
|
{s.children.length} resource(s)
|
|
326
330
|
{s.replicaLagMs != null ? ` · lag ${s.replicaLagMs}ms` : ""}
|
|
@@ -469,8 +473,11 @@ function StoreDetail(props: {
|
|
|
469
473
|
return (
|
|
470
474
|
<div className="flex flex-col gap-4">
|
|
471
475
|
<div className="flex flex-wrap items-baseline gap-2">
|
|
472
|
-
<h2 className="text-base font-medium">{open.name}</h2>
|
|
473
|
-
<span className="text-sm text-[var(--oke-muted)]">
|
|
476
|
+
<h2 className="text-base font-medium">{displayLabel(open.name, open.description)}</h2>
|
|
477
|
+
<span className="text-sm text-[var(--oke-muted)]">
|
|
478
|
+
{open.description ? `${open.name} · ` : ""}
|
|
479
|
+
{open.ref}
|
|
480
|
+
</span>
|
|
474
481
|
{open.contentAddressed ? (
|
|
475
482
|
<span role="status" className="text-xs text-[var(--oke-muted)]">
|
|
476
483
|
content-addressed keys
|
|
@@ -610,7 +617,7 @@ function StoreDetail(props: {
|
|
|
610
617
|
<tr>
|
|
611
618
|
{Object.keys(browse.rows[0] ?? { id: 1 }).map((col) => (
|
|
612
619
|
<th key={col} scope="col" className="border-b px-2 py-1">
|
|
613
|
-
{col}
|
|
620
|
+
{displayLabel(col, child?.columnDescriptions[col])}
|
|
614
621
|
</th>
|
|
615
622
|
))}
|
|
616
623
|
<th scope="col" className="border-b px-2 py-1">
|
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
type VaultListResponse,
|
|
21
21
|
type VaultSearch,
|
|
22
22
|
} from "../../../vault/index.ts";
|
|
23
|
+
import { displayLabel } from "../../../display.ts";
|
|
23
24
|
import { consoleCalls } from "../../client.ts";
|
|
24
25
|
import { Button, Input } from "../../components/ui.tsx";
|
|
25
26
|
|
|
@@ -191,7 +192,10 @@ export function VaultPanel() {
|
|
|
191
192
|
)}
|
|
192
193
|
onClick={() => setSearch(openVault(search, s.name))}
|
|
193
194
|
>
|
|
194
|
-
<span
|
|
195
|
+
<span>{displayLabel(s.name, s.description)}</span>
|
|
196
|
+
{s.description ? (
|
|
197
|
+
<span className="font-mono text-xs text-[var(--oke-muted)]">{s.name}</span>
|
|
198
|
+
) : null}
|
|
195
199
|
<span className="truncate text-xs">
|
|
196
200
|
{s.sensitive ? (s.fingerprint ?? "unset") : (s.cleartext ?? "unset")}
|
|
197
201
|
</span>
|
|
@@ -225,9 +229,11 @@ export function VaultPanel() {
|
|
|
225
229
|
) : (
|
|
226
230
|
<div className="flex max-w-2xl flex-col gap-6">
|
|
227
231
|
<div>
|
|
228
|
-
<h2 className="
|
|
232
|
+
<h2 className="text-lg text-[var(--oke-fg)]">
|
|
233
|
+
{displayLabel(open.name, open.description)}
|
|
234
|
+
</h2>
|
|
229
235
|
{open.description ? (
|
|
230
|
-
<p className="text-sm text-[var(--oke-muted)]">{open.
|
|
236
|
+
<p className="font-mono text-sm text-[var(--oke-muted)]">{open.name}</p>
|
|
231
237
|
) : null}
|
|
232
238
|
{open.rotate ? (
|
|
233
239
|
<p className="text-sm text-[var(--oke-muted)]">Rotate hint: {open.rotate}</p>
|
|
@@ -39,6 +39,7 @@ export interface SignalEndpoint {
|
|
|
39
39
|
/** One signal in the operator list. */
|
|
40
40
|
export interface SignalRecord {
|
|
41
41
|
readonly name: string;
|
|
42
|
+
readonly description?: string;
|
|
42
43
|
readonly delivery: SignalDelivery;
|
|
43
44
|
readonly retries: number;
|
|
44
45
|
readonly deadLetterEnabled: boolean;
|
|
@@ -27,6 +27,7 @@ export const STORE_FIXTURE: readonly StoreRecord[] = [
|
|
|
27
27
|
channels: [],
|
|
28
28
|
},
|
|
29
29
|
piiColumns: ["email"],
|
|
30
|
+
columnDescriptions: {},
|
|
30
31
|
},
|
|
31
32
|
{
|
|
32
33
|
name: "shipments",
|
|
@@ -44,6 +45,7 @@ export const STORE_FIXTURE: readonly StoreRecord[] = [
|
|
|
44
45
|
channels: ["booking-confirmed"],
|
|
45
46
|
},
|
|
46
47
|
piiColumns: [],
|
|
48
|
+
columnDescriptions: {},
|
|
47
49
|
},
|
|
48
50
|
],
|
|
49
51
|
replicaLagMs: 240,
|
|
@@ -76,6 +78,7 @@ export const STORE_FIXTURE: readonly StoreRecord[] = [
|
|
|
76
78
|
channels: [],
|
|
77
79
|
},
|
|
78
80
|
piiColumns: [],
|
|
81
|
+
columnDescriptions: {},
|
|
79
82
|
},
|
|
80
83
|
],
|
|
81
84
|
replicaLagMs: null,
|
|
@@ -104,6 +107,7 @@ export const STORE_FIXTURE: readonly StoreRecord[] = [
|
|
|
104
107
|
channels: [],
|
|
105
108
|
},
|
|
106
109
|
piiColumns: [],
|
|
110
|
+
columnDescriptions: {},
|
|
107
111
|
},
|
|
108
112
|
],
|
|
109
113
|
replicaLagMs: null,
|
|
@@ -138,6 +142,7 @@ export const STORE_FIXTURE: readonly StoreRecord[] = [
|
|
|
138
142
|
channels: [],
|
|
139
143
|
},
|
|
140
144
|
piiColumns: [],
|
|
145
|
+
columnDescriptions: {},
|
|
141
146
|
},
|
|
142
147
|
],
|
|
143
148
|
replicaLagMs: null,
|
|
@@ -28,6 +28,7 @@ export interface StoreChild {
|
|
|
28
28
|
readonly cache: StoreCacheView;
|
|
29
29
|
readonly willNotFire: WillNotFire;
|
|
30
30
|
readonly piiColumns: readonly string[];
|
|
31
|
+
readonly columnDescriptions: Readonly<Record<string, string>>;
|
|
31
32
|
}
|
|
32
33
|
|
|
33
34
|
/** One store row from `console.store.list`. */
|
|
@@ -35,6 +36,7 @@ export interface StoreRecord {
|
|
|
35
36
|
readonly ref: string;
|
|
36
37
|
readonly facet: StoreFacet;
|
|
37
38
|
readonly name: string;
|
|
39
|
+
readonly description?: string;
|
|
38
40
|
readonly children: readonly StoreChild[];
|
|
39
41
|
readonly replicaLagMs: number | null;
|
|
40
42
|
readonly migrationDrift: {
|
|
@@ -11,7 +11,9 @@ import {
|
|
|
11
11
|
runSqlConformance,
|
|
12
12
|
} from "./conformance.ts";
|
|
13
13
|
import { fsDriver } from "./fs.ts";
|
|
14
|
+
import { libsqlDriver, libsqlIndexDriver } from "./libsql.ts";
|
|
14
15
|
import { memoryFilesDriver, memoryIndexDriver, memoryKvDriver, memorySqlDriver } from "./memory.ts";
|
|
16
|
+
import { pgliteDriver } from "./pglite.ts";
|
|
15
17
|
import { pgvectorDriver } from "./pgvector.ts";
|
|
16
18
|
import { createPostgresFakeClient, postgresDriver } from "./postgres.ts";
|
|
17
19
|
import { createRedisFakeClient, redisDriver } from "./redis.ts";
|
|
@@ -21,6 +23,8 @@ import { sqliteDriver } from "./sqlite.ts";
|
|
|
21
23
|
describe("sql conformance", () => {
|
|
22
24
|
test("memory", () => runSqlConformance(memorySqlDriver));
|
|
23
25
|
test("sqlite", () => runSqlConformance(sqliteDriver, { url: ":memory:" }));
|
|
26
|
+
test("libsql", () => runSqlConformance(libsqlDriver, { url: ":memory:" }));
|
|
27
|
+
test("pglite", () => runSqlConformance(pgliteDriver, { url: "memory://" }));
|
|
24
28
|
test("postgres (fake Bun.SQL client)", () =>
|
|
25
29
|
runSqlConformance(postgresDriver, {
|
|
26
30
|
client: createPostgresFakeClient(),
|
|
@@ -46,6 +50,7 @@ describe("files conformance", () => {
|
|
|
46
50
|
describe("index conformance", () => {
|
|
47
51
|
test("memory", () => runIndexConformance(memoryIndexDriver, { dims: 3 }));
|
|
48
52
|
test("pgvector", () => runIndexConformance(pgvectorDriver, { dims: 3 }));
|
|
53
|
+
test("libsql", () => runIndexConformance(libsqlIndexDriver, { dims: 3 }));
|
|
49
54
|
});
|
|
50
55
|
|
|
51
56
|
describe("protocol naming", () => {
|
|
@@ -53,6 +58,8 @@ describe("protocol naming", () => {
|
|
|
53
58
|
const ids = [
|
|
54
59
|
memorySqlDriver.id,
|
|
55
60
|
sqliteDriver.id,
|
|
61
|
+
libsqlDriver.id,
|
|
62
|
+
pgliteDriver.id,
|
|
56
63
|
postgresDriver.id,
|
|
57
64
|
memoryKvDriver.id,
|
|
58
65
|
redisDriver.id,
|
|
@@ -61,10 +68,13 @@ describe("protocol naming", () => {
|
|
|
61
68
|
s3Driver.id,
|
|
62
69
|
memoryIndexDriver.id,
|
|
63
70
|
pgvectorDriver.id,
|
|
71
|
+
libsqlIndexDriver.id,
|
|
64
72
|
];
|
|
65
73
|
expect(ids).toEqual([
|
|
66
74
|
"memory",
|
|
67
75
|
"sqlite",
|
|
76
|
+
"libsql",
|
|
77
|
+
"pglite",
|
|
68
78
|
"postgres",
|
|
69
79
|
"memory",
|
|
70
80
|
"redis",
|
|
@@ -73,6 +83,7 @@ describe("protocol naming", () => {
|
|
|
73
83
|
"s3",
|
|
74
84
|
"memory",
|
|
75
85
|
"pgvector",
|
|
86
|
+
"libsql",
|
|
76
87
|
]);
|
|
77
88
|
for (const id of ids) {
|
|
78
89
|
expect(id).not.toMatch(/neon|dragonfly|minio|upstash|cloudflare/i);
|
|
@@ -10,11 +10,15 @@ describe("SQL_DRIVER_TO_DRIZZLE_DIALECT", () => {
|
|
|
10
10
|
expect(SQL_DRIVER_TO_DRIZZLE_DIALECT).toEqual({
|
|
11
11
|
sqlite: "sqlite",
|
|
12
12
|
postgres: "postgresql",
|
|
13
|
+
libsql: "sqlite",
|
|
14
|
+
pglite: "postgresql",
|
|
13
15
|
});
|
|
14
16
|
});
|
|
15
17
|
|
|
16
18
|
test("drizzleDialectFromSqlDriver resolves", () => {
|
|
17
19
|
expect(drizzleDialectFromSqlDriver("sqlite")).toBe("sqlite");
|
|
18
20
|
expect(drizzleDialectFromSqlDriver("postgres")).toBe("postgresql");
|
|
21
|
+
expect(drizzleDialectFromSqlDriver("libsql")).toBe("sqlite");
|
|
22
|
+
expect(drizzleDialectFromSqlDriver("pglite")).toBe("postgresql");
|
|
19
23
|
});
|
|
20
24
|
});
|