brakit 0.9.1 → 0.10.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.
@@ -73,6 +73,7 @@ html,body{height:100%;background:var(--bg);color:var(--text);font-family:var(--s
73
73
  .sidebar-item:hover .item-icon{opacity:.8}
74
74
  .sidebar-item .item-label{flex:1}
75
75
  .sidebar-item .item-count{font-size:12px;font-family:var(--mono);color:var(--text-muted);background:var(--bg-muted);padding:2px 8px;border-radius:10px;min-width:24px;text-align:center}
76
+ .sidebar-beta{font-size:9px;color:#6366f1;background:#eef2ff;border:1px solid #e0e7ff;border-radius:4px;padding:0 5px;margin-left:auto;line-height:16px}
76
77
  .sidebar-item.disabled{opacity:.35;cursor:default;pointer-events:none}
77
78
  .sidebar-item .coming-soon{font-size:10px;color:var(--text-muted);background:var(--bg-muted);padding:2px 8px;border-radius:10px;font-weight:600;letter-spacing:.3px}
78
79
  .sidebar-footer{padding:16px 24px;border-top:1px solid var(--border-subtle);font-size:12px;color:var(--text-muted);font-family:var(--mono)}
@@ -98,6 +99,7 @@ html,body{height:100%;background:var(--bg);color:var(--text);font-family:var(--s
98
99
  .main-content{flex:1;overflow-y:auto}
99
100
  bk-dashboard{display:contents}
100
101
  bk-overview-view,bk-flows-view,bk-requests-view,bk-fetches-view,bk-queries-view,bk-errors-view,bk-logs-view,bk-security-view,bk-performance-view,bk-timeline-panel,bk-empty-state{display:block}
102
+ bk-graph-view{display:block}
101
103
  bk-method-badge,bk-status-pill,bk-duration-label,bk-copy-button{display:inline-flex;flex-shrink:0}
102
104
  bk-stat-card{display:inline-flex}
103
105
  bk-toast{display:block;position:fixed;top:0;left:0;right:0;z-index:100;pointer-events:none}
@@ -743,34 +745,136 @@ span.perf-breakdown-dot.perf-breakdown-app{background:var(--breakdown-app)}
743
745
  opacity: .9;
744
746
  font-size: 10px;
745
747
  }
748
+
749
+ .graph-wrapper{display:flex;flex-direction:column;height:calc(100vh - 120px);outline:none}
750
+
751
+ /* Toolbar — centered search, layers left, flow picker right */
752
+ .graph-toolbar{display:flex;align-items:center;gap:10px;padding:8px 16px;border-bottom:1px solid var(--border)}
753
+
754
+ /* Layer toggles */
755
+ .graph-layer-toggles{display:flex;gap:4px;flex-shrink:0}
756
+ .graph-layer-btn{display:flex;align-items:center;gap:3px;font-size:10px;font-weight:500;padding:3px 8px;border:1px solid var(--border);border-radius:12px;background:var(--bg);color:var(--text-muted);cursor:pointer;transition:all .15s;white-space:nowrap}
757
+ .graph-layer-btn:hover{border-color:var(--text-muted);color:var(--text)}
758
+ .graph-layer-btn.active{background:var(--bg-card);font-weight:600}
759
+
760
+ /* Search — takes remaining space, centered */
761
+ .graph-search{flex:1;position:relative;display:flex;align-items:center;max-width:360px;margin:0 auto}
762
+ .graph-search-icon{position:absolute;left:10px;color:var(--text-muted);font-size:13px;pointer-events:none;opacity:0.5}
763
+ .graph-search-input{width:100%;font-size:11px;padding:6px 28px 6px 28px;border:1px solid var(--border);border-radius:8px;background:var(--bg);color:var(--text);font-family:var(--mono);outline:none;transition:border-color .15s,box-shadow .15s}
764
+ .graph-search-input:focus{border-color:#6366f1;box-shadow:0 0 0 3px rgba(99,102,241,.1)}
765
+ .graph-search-input::placeholder{color:var(--text-muted);opacity:0.5}
766
+ .graph-search-clear{position:absolute;right:8px;background:none;border:none;color:var(--text-muted);cursor:pointer;font-size:11px;padding:0 4px;line-height:1;border-radius:3px}
767
+ .graph-search-clear:hover{color:var(--text);background:var(--bg-card)}
768
+
769
+ /* Flow picker */
770
+ .graph-flow-picker{font-size:10px;padding:4px 8px;border:1px solid var(--border);border-radius:8px;background:var(--bg);color:var(--text);cursor:pointer;font-family:var(--mono);max-width:200px;flex-shrink:0}
771
+
772
+ /* Auth legend — inline in toolbar */
773
+ .graph-auth-legend{display:flex;gap:8px;align-items:center;font-size:10px;color:var(--text-muted);flex-shrink:0}
774
+ .graph-auth-legend-item{display:flex;align-items:center;gap:3px;white-space:nowrap}
775
+
776
+ /* Canvas */
777
+ .graph-body{display:flex;flex:1;min-height:0}
778
+ .graph-canvas{flex:1;overflow:hidden;padding:0;position:relative;min-height:0}
779
+ .graph-svg{display:block}
780
+ .graph-col-header{fill:#c4c4cc;font-size:9px;font-weight:600;font-family:'Inter',system-ui,sans-serif;letter-spacing:1.5px}
781
+
782
+ /* Floating controls — bottom-center pill */
783
+ .graph-float{position:absolute;top:12px;right:12px;display:flex;align-items:center;gap:2px;background:var(--bg-card);border:1px solid var(--border);border-radius:10px;padding:4px 6px;box-shadow:0 2px 12px rgba(0,0,0,.08);z-index:10}
784
+ .graph-float-btn{background:none;border:none;color:var(--text-muted);cursor:pointer;font-size:13px;padding:4px 8px;line-height:1;border-radius:6px;transition:all .12s;white-space:nowrap}
785
+ .graph-float-btn:hover{background:var(--bg);color:var(--text)}
786
+ .graph-float-btn-accent{font-size:11px;font-weight:600;color:#6366f1}
787
+ .graph-float-btn-accent:hover{background:rgba(99,102,241,.08);color:#4f46e5}
788
+ .graph-float-zoom{font-size:10px;color:var(--text-muted);font-family:var(--mono);min-width:36px;text-align:center;user-select:none}
789
+ .graph-float-sep{width:1px;height:16px;background:var(--border);margin:0 2px;flex-shrink:0}
790
+
791
+ /* Empty & loading states */
792
+ .graph-empty{display:flex;flex-direction:column;align-items:center;justify-content:center;min-height:400px;color:var(--text-muted);text-align:center;padding:40px}
793
+ .graph-empty-icon{font-size:40px;opacity:0.25;margin-bottom:12px}
794
+ .graph-empty-title{font-size:15px;font-weight:600;color:var(--text);margin-bottom:6px}
795
+ .graph-empty-desc{font-size:12px;max-width:320px;line-height:1.5}
796
+ .graph-loading{display:flex;align-items:center;justify-content:center;min-height:400px;color:var(--text-muted);font-size:13px}
797
+
798
+ /* Detail panel */
799
+ .graph-detail{width:320px;border-left:1px solid var(--border);overflow-y:auto;padding:16px;background:var(--bg-card);flex-shrink:0;max-height:calc(100vh - 160px)}
800
+ .graph-detail-head{display:flex;justify-content:space-between;align-items:flex-start;margin-bottom:12px}
801
+ .graph-detail-badge{font-size:11px;font-weight:500;text-transform:uppercase;letter-spacing:0.5px;margin-bottom:4px}
802
+ .graph-detail-name{font-size:14px;font-weight:700;color:var(--text);word-break:break-all;font-family:var(--mono)}
803
+ .graph-detail-close{background:none;border:none;color:var(--text-muted);cursor:pointer;font-size:16px;padding:0 4px;line-height:1}
804
+ .graph-detail-close:hover{color:var(--text)}
805
+
806
+ .graph-detail-auth-badge{display:inline-block;font-size:10px;font-weight:500;color:#059669;background:#ecfdf5;border:1px solid #a7f3d0;border-radius:4px;padding:1px 6px;margin-top:4px}
807
+ .graph-detail-mw-badge{display:inline-block;font-size:10px;font-weight:500;color:#6b7280;background:#f3f4f6;border:1px solid #d1d5db;border-radius:4px;padding:1px 6px;margin-top:4px;margin-left:4px}
808
+
809
+ /* Detail tabs */
810
+ .graph-detail-tabs{display:flex;gap:2px;margin-bottom:12px;border-bottom:1px solid var(--border);padding-bottom:0}
811
+ .graph-detail-tab{background:none;border:none;border-bottom:2px solid transparent;color:var(--text-muted);cursor:pointer;font-size:11px;font-weight:500;padding:6px 10px;transition:all .12s}
812
+ .graph-detail-tab:hover{color:var(--text)}
813
+ .graph-detail-tab.active{color:#6366f1;border-bottom-color:#6366f1}
814
+
815
+ /* Detail stats */
816
+ .graph-detail-stats{display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-bottom:12px}
817
+ .graph-detail-stat{background:var(--bg);border-radius:var(--radius-sm);padding:10px 12px}
818
+ .graph-detail-val{font-size:20px;font-weight:700;font-family:var(--mono);color:var(--text);line-height:1.2}
819
+ .graph-detail-lbl{font-size:9px;color:var(--text-muted);text-transform:uppercase;letter-spacing:0.6px;margin-top:2px}
820
+
821
+ /* Detail sections */
822
+ .graph-detail-sec{font-size:10px;color:var(--text-muted);text-transform:uppercase;letter-spacing:0.8px;margin:12px 0 8px;padding-top:10px;border-top:1px solid var(--border)}
823
+ .graph-detail-conn{display:flex;align-items:center;gap:6px;font-size:12px;color:var(--text);padding:6px 8px;background:var(--bg);border-radius:var(--radius-sm);margin-bottom:4px;font-family:var(--mono)}
824
+ .graph-detail-edge-dot{width:6px;height:6px;border-radius:50%;flex-shrink:0}
825
+ .graph-detail-edge-type{font-size:10px;font-weight:600;text-transform:uppercase;min-width:42px}
826
+ .graph-detail-dim{color:var(--text-muted);font-size:10px;margin-left:auto;white-space:nowrap}
827
+ .graph-detail-sql{font-size:10px;color:var(--text-muted);padding:8px 10px;background:var(--bg);border-radius:var(--radius-sm);font-family:var(--mono);word-break:break-all;line-height:1.5;margin:0 0 4px;white-space:pre-wrap;border:1px solid var(--border)}
828
+
829
+ /* Security findings in detail */
830
+ .graph-detail-finding{padding:8px 10px;background:var(--bg);border-radius:var(--radius-sm);margin-bottom:6px;border:1px solid var(--border)}
831
+ .graph-detail-finding-title{font-size:12px;font-weight:600;color:var(--text);margin-top:4px}
832
+ .graph-detail-finding-meta{font-size:10px;color:var(--text-muted);margin-top:2px;font-family:var(--mono)}
833
+ .graph-detail-severity{font-size:9px;font-weight:700;text-transform:uppercase;letter-spacing:0.5px;padding:1px 6px;border-radius:3px}
834
+ .graph-detail-severity-critical{background:#fef2f2;color:#dc2626;border:1px solid #fecaca}
835
+ .graph-detail-severity-warning{background:#fffbeb;color:#d97706;border:1px solid #fde68a}
836
+ .graph-detail-severity-info{background:#eff6ff;color:#2563eb;border:1px solid #bfdbfe}
837
+
838
+ /* Issues in detail */
839
+ .graph-detail-issue-summary{margin-bottom:12px}
840
+ .graph-detail-hint{font-size:11px;color:var(--text-muted);line-height:1.5;margin:0}
841
+ .graph-detail-empty{font-size:12px;color:var(--text-muted);padding:16px;text-align:center}
842
+
843
+ /* Pulse animation for critical security badges */
844
+ @keyframes graph-pulse{0%,100%{opacity:1}50%{opacity:0.5}}
845
+ .graph-pulse{animation:graph-pulse 2s ease-in-out infinite}
846
+
847
+ /* Flow edge animation */
848
+ @keyframes graph-flow-dash{to{stroke-dashoffset:-24}}
849
+ .graph-flow-edge{animation:graph-flow-dash 1s linear infinite}
746
850
  </style>
747
851
  </head>
748
852
  <body>
749
853
  <bk-dashboard></bk-dashboard>
750
854
  <script>window.__BRAKIT_CONFIG__={port:{{PORT}},version:"{{VERSION}}"};</script>
751
- <script>(function(){'use strict';var Rs=Object.defineProperty;var ws=Object.getOwnPropertyDescriptor;var u=(i,e,t,s)=>{for(var r=s>1?void 0:s?ws(e,t):e,o=i.length-1,n;o>=0;o--)(n=i[o])&&(r=(s?n(e,t,r):n(r))||r);return s&&r&&Rs(e,t,r),r};var Lt=globalThis,Ot=Lt.ShadowRoot&&(Lt.ShadyCSS===void 0||Lt.ShadyCSS.nativeShadow)&&"adoptedStyleSheets"in Document.prototype&&"replace"in CSSStyleSheet.prototype,xe=Symbol(),ye=new WeakMap,Mt=class{constructor(e,t,s){if(this._$cssResult$=true,s!==xe)throw Error("CSSResult is not constructable. Use `unsafeCSS` or `css` instead.");this.cssText=e,this.t=t;}get styleSheet(){let e=this.o,t=this.t;if(Ot&&e===void 0){let s=t!==void 0&&t.length===1;s&&(e=ye.get(t)),e===void 0&&((this.o=e=new CSSStyleSheet).replaceSync(this.cssText),s&&ye.set(t,e));}return e}toString(){return this.cssText}},Re=i=>new Mt(typeof i=="string"?i:i+"",void 0,xe);var we=(i,e)=>{if(Ot)i.adoptedStyleSheets=e.map(t=>t instanceof CSSStyleSheet?t:t.styleSheet);else for(let t of e){let s=document.createElement("style"),r=Lt.litNonce;r!==void 0&&s.setAttribute("nonce",r),s.textContent=t.cssText,i.appendChild(s);}},Qt=Ot?i=>i:i=>i instanceof CSSStyleSheet?(e=>{let t="";for(let s of e.cssRules)t+=s.cssText;return Re(t)})(i):i;var{is:As,defineProperty:Cs,getOwnPropertyDescriptor:Is,getOwnPropertyNames:Ls,getOwnPropertySymbols:Ms,getPrototypeOf:Os}=Object,k=globalThis,Ae=k.trustedTypes,Ns=Ae?Ae.emptyScript:"",ks=k.reactiveElementPolyfillSupport,ht=(i,e)=>i,mt={toAttribute(i,e){switch(e){case Boolean:i=i?Ns:null;break;case Object:case Array:i=i==null?i:JSON.stringify(i);}return i},fromAttribute(i,e){let t=i;switch(e){case Boolean:t=i!==null;break;case Number:t=i===null?null:Number(i);break;case Object:case Array:try{t=JSON.parse(i);}catch{t=null;}}return t}},Nt=(i,e)=>!As(i,e),Ce={attribute:true,type:String,converter:mt,reflect:false,useDefault:false,hasChanged:Nt};Symbol.metadata??(Symbol.metadata=Symbol("metadata")),k.litPropertyMetadata??(k.litPropertyMetadata=new WeakMap);var O=class extends HTMLElement{static addInitializer(e){this._$Ei(),(this.l??(this.l=[])).push(e);}static get observedAttributes(){return this.finalize(),this._$Eh&&[...this._$Eh.keys()]}static createProperty(e,t=Ce){if(t.state&&(t.attribute=false),this._$Ei(),this.prototype.hasOwnProperty(e)&&((t=Object.create(t)).wrapped=true),this.elementProperties.set(e,t),!t.noAccessor){let s=Symbol(),r=this.getPropertyDescriptor(e,s,t);r!==void 0&&Cs(this.prototype,e,r);}}static getPropertyDescriptor(e,t,s){let{get:r,set:o}=Is(this.prototype,e)??{get(){return this[t]},set(n){this[t]=n;}};return {get:r,set(n){let l=r?.call(this);o?.call(this,n),this.requestUpdate(e,l,s);},configurable:true,enumerable:true}}static getPropertyOptions(e){return this.elementProperties.get(e)??Ce}static _$Ei(){if(this.hasOwnProperty(ht("elementProperties")))return;let e=Os(this);e.finalize(),e.l!==void 0&&(this.l=[...e.l]),this.elementProperties=new Map(e.elementProperties);}static finalize(){if(this.hasOwnProperty(ht("finalized")))return;if(this.finalized=true,this._$Ei(),this.hasOwnProperty(ht("properties"))){let t=this.properties,s=[...Ls(t),...Ms(t)];for(let r of s)this.createProperty(r,t[r]);}let e=this[Symbol.metadata];if(e!==null){let t=litPropertyMetadata.get(e);if(t!==void 0)for(let[s,r]of t)this.elementProperties.set(s,r);}this._$Eh=new Map;for(let[t,s]of this.elementProperties){let r=this._$Eu(t,s);r!==void 0&&this._$Eh.set(r,t);}this.elementStyles=this.finalizeStyles(this.styles);}static finalizeStyles(e){let t=[];if(Array.isArray(e)){let s=new Set(e.flat(1/0).reverse());for(let r of s)t.unshift(Qt(r));}else e!==void 0&&t.push(Qt(e));return t}static _$Eu(e,t){let s=t.attribute;return s===false?void 0:typeof s=="string"?s:typeof e=="string"?e.toLowerCase():void 0}constructor(){super(),this._$Ep=void 0,this.isUpdatePending=false,this.hasUpdated=false,this._$Em=null,this._$Ev();}_$Ev(){this._$ES=new Promise(e=>this.enableUpdating=e),this._$AL=new Map,this._$E_(),this.requestUpdate(),this.constructor.l?.forEach(e=>e(this));}addController(e){(this._$EO??(this._$EO=new Set)).add(e),this.renderRoot!==void 0&&this.isConnected&&e.hostConnected?.();}removeController(e){this._$EO?.delete(e);}_$E_(){let e=new Map,t=this.constructor.elementProperties;for(let s of t.keys())this.hasOwnProperty(s)&&(e.set(s,this[s]),delete this[s]);e.size>0&&(this._$Ep=e);}createRenderRoot(){let e=this.shadowRoot??this.attachShadow(this.constructor.shadowRootOptions);return we(e,this.constructor.elementStyles),e}connectedCallback(){this.renderRoot??(this.renderRoot=this.createRenderRoot()),this.enableUpdating(true),this._$EO?.forEach(e=>e.hostConnected?.());}enableUpdating(e){}disconnectedCallback(){this._$EO?.forEach(e=>e.hostDisconnected?.());}attributeChangedCallback(e,t,s){this._$AK(e,s);}_$ET(e,t){let s=this.constructor.elementProperties.get(e),r=this.constructor._$Eu(e,s);if(r!==void 0&&s.reflect===true){let o=(s.converter?.toAttribute!==void 0?s.converter:mt).toAttribute(t,s.type);this._$Em=e,o==null?this.removeAttribute(r):this.setAttribute(r,o),this._$Em=null;}}_$AK(e,t){let s=this.constructor,r=s._$Eh.get(e);if(r!==void 0&&this._$Em!==r){let o=s.getPropertyOptions(r),n=typeof o.converter=="function"?{fromAttribute:o.converter}:o.converter?.fromAttribute!==void 0?o.converter:mt;this._$Em=r;let l=n.fromAttribute(t,o.type);this[r]=l??this._$Ej?.get(r)??l,this._$Em=null;}}requestUpdate(e,t,s,r=false,o){if(e!==void 0){let n=this.constructor;if(r===false&&(o=this[e]),s??(s=n.getPropertyOptions(e)),!((s.hasChanged??Nt)(o,t)||s.useDefault&&s.reflect&&o===this._$Ej?.get(e)&&!this.hasAttribute(n._$Eu(e,s))))return;this.C(e,t,s);}this.isUpdatePending===false&&(this._$ES=this._$EP());}C(e,t,{useDefault:s,reflect:r,wrapped:o},n){s&&!(this._$Ej??(this._$Ej=new Map)).has(e)&&(this._$Ej.set(e,n??t??this[e]),o!==true||n!==void 0)||(this._$AL.has(e)||(this.hasUpdated||s||(t=void 0),this._$AL.set(e,t)),r===true&&this._$Em!==e&&(this._$Eq??(this._$Eq=new Set)).add(e));}async _$EP(){this.isUpdatePending=true;try{await this._$ES;}catch(t){Promise.reject(t);}let e=this.scheduleUpdate();return e!=null&&await e,!this.isUpdatePending}scheduleUpdate(){return this.performUpdate()}performUpdate(){if(!this.isUpdatePending)return;if(!this.hasUpdated){if(this.renderRoot??(this.renderRoot=this.createRenderRoot()),this._$Ep){for(let[r,o]of this._$Ep)this[r]=o;this._$Ep=void 0;}let s=this.constructor.elementProperties;if(s.size>0)for(let[r,o]of s){let{wrapped:n}=o,l=this[r];n!==true||this._$AL.has(r)||l===void 0||this.C(r,void 0,o,l);}}let e=false,t=this._$AL;try{e=this.shouldUpdate(t),e?(this.willUpdate(t),this._$EO?.forEach(s=>s.hostUpdate?.()),this.update(t)):this._$EM();}catch(s){throw e=false,this._$EM(),s}e&&this._$AE(t);}willUpdate(e){}_$AE(e){this._$EO?.forEach(t=>t.hostUpdated?.()),this.hasUpdated||(this.hasUpdated=true,this.firstUpdated(e)),this.updated(e);}_$EM(){this._$AL=new Map,this.isUpdatePending=false;}get updateComplete(){return this.getUpdateComplete()}getUpdateComplete(){return this._$ES}shouldUpdate(e){return true}update(e){this._$Eq&&(this._$Eq=this._$Eq.forEach(t=>this._$ET(t,this[t]))),this._$EM();}updated(e){}firstUpdated(e){}};O.elementStyles=[],O.shadowRootOptions={mode:"open"},O[ht("elementProperties")]=new Map,O[ht("finalized")]=new Map,ks?.({ReactiveElement:O}),(k.reactiveElementVersions??(k.reactiveElementVersions=[])).push("2.1.2");var ft=globalThis,Ie=i=>i,kt=ft.trustedTypes,Le=kt?kt.createPolicy("lit-html",{createHTML:i=>i}):void 0,He="$lit$",D=`lit$${Math.random().toFixed(9).slice(2)}$`,qe="?"+D,Ds=`<${qe}>`,W=document,gt=()=>W.createComment(""),Et=i=>i===null||typeof i!="object"&&typeof i!="function",Zt=Array.isArray,Hs=i=>Zt(i)||typeof i?.[Symbol.iterator]=="function",Vt=`[
752
- \f\r]`,vt=/<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g,Me=/-->/g,Oe=/>/g,B=RegExp(`>|${Vt}(?:([^\\s"'>=/]+)(${Vt}*=${Vt}*(?:[^
753
- \f\r"'\`<>=]|("|')|))|$)`,"g"),Ne=/'/g,ke=/"/g,Pe=/^(?:script|style|textarea|title)$/i,te=i=>(e,...t)=>({_$litType$:i,strings:e,values:t}),a=te(1),j=Symbol.for("lit-noChange"),d=Symbol.for("lit-nothing"),De=new WeakMap,G=W.createTreeWalker(W,129);function Ue(i,e){if(!Zt(i)||!i.hasOwnProperty("raw"))throw Error("invalid template strings array");return Le!==void 0?Le.createHTML(e):e}var qs=(i,e)=>{let t=i.length-1,s=[],r,o=e===2?"<svg>":e===3?"<math>":"",n=vt;for(let l=0;l<t;l++){let c=i[l],p,h,m=-1,E=0;for(;E<c.length&&(n.lastIndex=E,h=n.exec(c),h!==null);)E=n.lastIndex,n===vt?h[1]==="!--"?n=Me:h[1]!==void 0?n=Oe:h[2]!==void 0?(Pe.test(h[2])&&(r=RegExp("</"+h[2],"g")),n=B):h[3]!==void 0&&(n=B):n===B?h[0]===">"?(n=r??vt,m=-1):h[1]===void 0?m=-2:(m=n.lastIndex-h[2].length,p=h[1],n=h[3]===void 0?B:h[3]==='"'?ke:Ne):n===ke||n===Ne?n=B:n===Me||n===Oe?n=vt:(n=B,r=void 0);let T=n===B&&i[l+1].startsWith("/>")?" ":"";o+=n===vt?c+Ds:m>=0?(s.push(p),c.slice(0,m)+He+c.slice(m)+D+T):c+D+(m===-2?l:T);}return [Ue(i,o+(i[t]||"<?>")+(e===2?"</svg>":e===3?"</math>":"")),s]},bt=class i{constructor({strings:e,_$litType$:t},s){let r;this.parts=[];let o=0,n=0,l=e.length-1,c=this.parts,[p,h]=qs(e,t);if(this.el=i.createElement(p,s),G.currentNode=this.el.content,t===2||t===3){let m=this.el.content.firstChild;m.replaceWith(...m.childNodes);}for(;(r=G.nextNode())!==null&&c.length<l;){if(r.nodeType===1){if(r.hasAttributes())for(let m of r.getAttributeNames())if(m.endsWith(He)){let E=h[n++],T=r.getAttribute(m).split(D),b=/([.?@])?(.*)/.exec(E);c.push({type:1,index:o,name:b[2],strings:T,ctor:b[1]==="."?Xt:b[1]==="?"?Kt:b[1]==="@"?zt:z}),r.removeAttribute(m);}else m.startsWith(D)&&(c.push({type:6,index:o}),r.removeAttribute(m));if(Pe.test(r.tagName)){let m=r.textContent.split(D),E=m.length-1;if(E>0){r.textContent=kt?kt.emptyScript:"";for(let T=0;T<E;T++)r.append(m[T],gt()),G.nextNode(),c.push({type:2,index:++o});r.append(m[E],gt());}}}else if(r.nodeType===8)if(r.data===qe)c.push({type:2,index:o});else {let m=-1;for(;(m=r.data.indexOf(D,m+1))!==-1;)c.push({type:7,index:o}),m+=D.length-1;}o++;}}static createElement(e,t){let s=W.createElement("template");return s.innerHTML=e,s}};function K(i,e,t=i,s){if(e===j)return e;let r=s!==void 0?t._$Co?.[s]:t._$Cl,o=Et(e)?void 0:e._$litDirective$;return r?.constructor!==o&&(r?._$AO?.(false),o===void 0?r=void 0:(r=new o(i),r._$AT(i,t,s)),s!==void 0?(t._$Co??(t._$Co=[]))[s]=r:t._$Cl=r),r!==void 0&&(e=K(i,r._$AS(i,e.values),r,s)),e}var Yt=class{constructor(e,t){this._$AV=[],this._$AN=void 0,this._$AD=e,this._$AM=t;}get parentNode(){return this._$AM.parentNode}get _$AU(){return this._$AM._$AU}u(e){let{el:{content:t},parts:s}=this._$AD,r=(e?.creationScope??W).importNode(t,true);G.currentNode=r;let o=G.nextNode(),n=0,l=0,c=s[0];for(;c!==void 0;){if(n===c.index){let p;c.type===2?p=new _t(o,o.nextSibling,this,e):c.type===1?p=new c.ctor(o,c.name,c.strings,this,e):c.type===6&&(p=new Jt(o,this,e)),this._$AV.push(p),c=s[++l];}n!==c?.index&&(o=G.nextNode(),n++);}return G.currentNode=W,r}p(e){let t=0;for(let s of this._$AV)s!==void 0&&(s.strings!==void 0?(s._$AI(e,s,t),t+=s.strings.length-2):s._$AI(e[t])),t++;}},_t=class i{get _$AU(){return this._$AM?._$AU??this._$Cv}constructor(e,t,s,r){this.type=2,this._$AH=d,this._$AN=void 0,this._$AA=e,this._$AB=t,this._$AM=s,this.options=r,this._$Cv=r?.isConnected??true;}get parentNode(){let e=this._$AA.parentNode,t=this._$AM;return t!==void 0&&e?.nodeType===11&&(e=t.parentNode),e}get startNode(){return this._$AA}get endNode(){return this._$AB}_$AI(e,t=this){e=K(this,e,t),Et(e)?e===d||e==null||e===""?(this._$AH!==d&&this._$AR(),this._$AH=d):e!==this._$AH&&e!==j&&this._(e):e._$litType$!==void 0?this.$(e):e.nodeType!==void 0?this.T(e):Hs(e)?this.k(e):this._(e);}O(e){return this._$AA.parentNode.insertBefore(e,this._$AB)}T(e){this._$AH!==e&&(this._$AR(),this._$AH=this.O(e));}_(e){this._$AH!==d&&Et(this._$AH)?this._$AA.nextSibling.data=e:this.T(W.createTextNode(e)),this._$AH=e;}$(e){let{values:t,_$litType$:s}=e,r=typeof s=="number"?this._$AC(e):(s.el===void 0&&(s.el=bt.createElement(Ue(s.h,s.h[0]),this.options)),s);if(this._$AH?._$AD===r)this._$AH.p(t);else {let o=new Yt(r,this),n=o.u(this.options);o.p(t),this.T(n),this._$AH=o;}}_$AC(e){let t=De.get(e.strings);return t===void 0&&De.set(e.strings,t=new bt(e)),t}k(e){Zt(this._$AH)||(this._$AH=[],this._$AR());let t=this._$AH,s,r=0;for(let o of e)r===t.length?t.push(s=new i(this.O(gt()),this.O(gt()),this,this.options)):s=t[r],s._$AI(o),r++;r<t.length&&(this._$AR(s&&s._$AB.nextSibling,r),t.length=r);}_$AR(e=this._$AA.nextSibling,t){for(this._$AP?.(false,true,t);e!==this._$AB;){let s=Ie(e).nextSibling;Ie(e).remove(),e=s;}}setConnected(e){this._$AM===void 0&&(this._$Cv=e,this._$AP?.(e));}},z=class{get tagName(){return this.element.tagName}get _$AU(){return this._$AM._$AU}constructor(e,t,s,r,o){this.type=1,this._$AH=d,this._$AN=void 0,this.element=e,this.name=t,this._$AM=r,this.options=o,s.length>2||s[0]!==""||s[1]!==""?(this._$AH=Array(s.length-1).fill(new String),this.strings=s):this._$AH=d;}_$AI(e,t=this,s,r){let o=this.strings,n=false;if(o===void 0)e=K(this,e,t,0),n=!Et(e)||e!==this._$AH&&e!==j,n&&(this._$AH=e);else {let l=e,c,p;for(e=o[0],c=0;c<o.length-1;c++)p=K(this,l[s+c],t,c),p===j&&(p=this._$AH[c]),n||(n=!Et(p)||p!==this._$AH[c]),p===d?e=d:e!==d&&(e+=(p??"")+o[c+1]),this._$AH[c]=p;}n&&!r&&this.j(e);}j(e){e===d?this.element.removeAttribute(this.name):this.element.setAttribute(this.name,e??"");}},Xt=class extends z{constructor(){super(...arguments),this.type=3;}j(e){this.element[this.name]=e===d?void 0:e;}},Kt=class extends z{constructor(){super(...arguments),this.type=4;}j(e){this.element.toggleAttribute(this.name,!!e&&e!==d);}},zt=class extends z{constructor(e,t,s,r,o){super(e,t,s,r,o),this.type=5;}_$AI(e,t=this){if((e=K(this,e,t,0)??d)===j)return;let s=this._$AH,r=e===d&&s!==d||e.capture!==s.capture||e.once!==s.once||e.passive!==s.passive,o=e!==d&&(s===d||r);r&&this.element.removeEventListener(this.name,this,s),o&&this.element.addEventListener(this.name,this,e),this._$AH=e;}handleEvent(e){typeof this._$AH=="function"?this._$AH.call(this.options?.host??this.element,e):this._$AH.handleEvent(e);}},Jt=class{constructor(e,t,s){this.element=e,this.type=6,this._$AN=void 0,this._$AM=t,this.options=s;}get _$AU(){return this._$AM._$AU}_$AI(e){K(this,e);}};var Ps=ft.litHtmlPolyfillSupport;Ps?.(bt,_t),(ft.litHtmlVersions??(ft.litHtmlVersions=[])).push("3.3.2");var Fe=(i,e,t)=>{let s=t?.renderBefore??e,r=s._$litPart$;if(r===void 0){let o=t?.renderBefore??null;s._$litPart$=r=new _t(e.insertBefore(gt(),o),o,void 0,t??{});}return r._$AI(i),r};var St=globalThis,f=class extends O{constructor(){super(...arguments),this.renderOptions={host:this},this._$Do=void 0;}createRenderRoot(){var t;let e=super.createRenderRoot();return (t=this.renderOptions).renderBefore??(t.renderBefore=e.firstChild),e}update(e){let t=this.render();this.hasUpdated||(this.renderOptions.isConnected=this.isConnected),super.update(e),this._$Do=Fe(t,this.renderRoot,this.renderOptions);}connectedCallback(){super.connectedCallback(),this._$Do?.setConnected(true);}disconnectedCallback(){super.disconnectedCallback(),this._$Do?.setConnected(false);}render(){return j}};f._$litElement$=true,f.finalized=true,St.litElementHydrateSupport?.({LitElement:f});var Us=St.litElementPolyfillSupport;Us?.({LitElement:f});(St.litElementVersions??(St.litElementVersions=[])).push("4.2.2");var g=i=>(e,t)=>{t!==void 0?t.addInitializer(()=>{customElements.define(i,e);}):customElements.define(i,e);};var Fs={attribute:true,type:String,converter:mt,reflect:false,hasChanged:Nt},Bs=(i=Fs,e,t)=>{let{kind:s,metadata:r}=t,o=globalThis.litPropertyMetadata.get(r);if(o===void 0&&globalThis.litPropertyMetadata.set(r,o=new Map),s==="setter"&&((i=Object.create(i)).wrapped=true),o.set(t.name,i),s==="accessor"){let{name:n}=t;return {set(l){let c=e.get.call(this);e.set.call(this,l),this.requestUpdate(n,c,i,true,l);},init(l){return l!==void 0&&this.C(n,void 0,i,l),l}}}if(s==="setter"){let{name:n}=t;return function(l){let c=this[n];e.call(this,l),this.requestUpdate(n,c,i,true,l);}}throw Error("Unsupported decorator location: "+s)};function y(i){return (e,t)=>typeof t=="object"?Bs(i,e,t):((s,r,o)=>{let n=r.hasOwnProperty(o);return r.constructor.createProperty(o,s),n?Object.getOwnPropertyDescriptor(r,o):void 0})(i,e,t)}function _(i){return y({...i,state:true,attribute:false})}var Tt=class extends f{constructor(){super(...arguments);this.method="";}createRenderRoot(){return this}render(){let t=this.method.toUpperCase();return a`<span class="method-badge method-badge-${t}">${t}</span>`}};u([y()],Tt.prototype,"method",2),Tt=u([g("bk-method-badge")],Tt);var I="/__brakit/api",N="/__brakit",$={flows:`${I}/flows`,requests:`${I}/requests`,events:`${I}/events`,clear:`${I}/clear`,fetches:`${I}/fetches`,errors:`${I}/errors`,logs:`${I}/logs`,queries:`${I}/queries`,metricsLive:`${I}/metrics/live`,insights:`${I}/insights`,tab:`${I}/tab`,activity:`${I}/activity`};var J="polling",Ht="static",Gs="auth-handshake",Ws="auth-check",js="middleware",$t={[Gs]:1,[Ws]:1,[js]:1};var ee="fetch";var se="error_event",re="query",oe="issues";var ie={overview:"Overview",actions:"Actions",requests:"Requests",fetches:"Server Fetches",queries:"Queries",errors:"Errors",logs:"Logs",performance:"Performance",security:"Security"},ne={overview:"Live summary of your application",actions:"User actions captured as sequences of HTTP requests",requests:"All HTTP requests proxied through brakit",fetches:"Outbound HTTP calls made by your server to external services",queries:"Database queries executed during request handling",errors:"Unhandled exceptions and errors thrown by your application",logs:"Console output from your application",performance:"Endpoint health and response time trends",security:"Security findings and recommendations"};var le=100,Z=300,tt=800,ce=2e3,de=100,pe=50,ue=500;var H="__all__",Ft={SELECT:"var(--blue)",INSERT:"var(--green)",UPDATE:"var(--amber)",DELETE:"var(--red)",COUNT:"var(--text-muted)"},Ke={error:"var(--red)",warn:"var(--amber)",info:"var(--blue)",debug:"var(--text-muted)",log:"var(--text-dim)"},me=["#2563eb","#7c3aed","#16a34a","#d97706","#dc2626","#0891b2","#ea580c","#c026d3","#059669","#db2777"],yt={green:"#4ade80",amber:"#fbbf24",red:"#f87171"},et=[{max:le,label:"Fast",color:"var(--green)",bg:"rgba(22,163,74,0.08)",border:"rgba(22,163,74,0.2)"},{max:Z,label:"Good",color:"var(--green)",bg:"rgba(22,163,74,0.06)",border:"rgba(22,163,74,0.15)"},{max:tt,label:"OK",color:"var(--amber)",bg:"rgba(217,119,6,0.06)",border:"rgba(217,119,6,0.15)"},{max:ce,label:"Slow",color:"var(--red)",bg:"rgba(220,38,38,0.06)",border:"rgba(220,38,38,0.15)"},{max:1/0,label:"Critical",color:"var(--red)",bg:"rgba(220,38,38,0.08)",border:"rgba(220,38,38,0.2)"}],ze="rgba(228,228,231,0.8)",ve="rgba(113,113,122,0.7)",Je="10px monospace",fe="9px monospace";var Ze={top:16,right:16,bottom:28,left:52},ts={fetch:"var(--blue)",log:"var(--text-muted)",error:"var(--red)",query:"var(--accent)"},es={fetch:"FETCH",log:"LOG",error:"ERROR",query:"QUERY"},ss=new Set(["cookie","set-cookie","authorization","proxy-authorization","x-api-key","x-auth-token"]),rs={400:"Bad Request",401:"Unauthorized",403:"Forbidden",404:"Not Found",405:"Method Not Allowed",408:"Timeout",409:"Conflict",422:"Unprocessable",429:"Too Many Requests",500:"Internal Server Error",502:"Bad Gateway",503:"Service Unavailable",504:"Gateway Timeout"},os=new Set(["host","connection","accept-encoding"]),q={critical:{icon:"\u2717",cls:"critical",sort:0},warning:{icon:"\u26A0",cls:"warning",sort:1},info:{icon:"\u2139",cls:"info",sort:2}};function v(i){return i<1e3?i+"ms":(i/1e3).toFixed(1)+"s"}function U(i){return !i||i===0?"":i<1024?i+"b":(i/1024).toFixed(1)+"kb"}function P(i){return i?i.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;"):""}function st(i){return i>=500?"status-pill-5xx":i>=400?"status-pill-4xx":i>=300?"status-pill-3xx":"status-pill-2xx"}function is(i){return rs[i]||(i>=500?"Server Error":i>=400?"Client Error":"OK")}function Qs(i,e){if(ss.has(i.toLowerCase())){let t=String(e);return t.length<=8?"****":t.slice(0,4)+"..."+t.slice(-4)+" ("+t.length+" chars)"}return String(e)}function rt(i){return !i||Object.keys(i).length===0?'<span style="color:var(--text-muted)">No headers</span>':Object.entries(i).map(([e,t])=>'<span class="json-key">'+P(e)+"</span>: "+P(Qs(e,t))).join(`
754
- `)}function Q(i){if(!i)return '<span style="color:var(--text-muted)">No body</span>';try{let e=JSON.parse(i);return Vs(JSON.stringify(e,null,2))}catch{return P(i)}}function Vs(i){return P(i).replace(/("(?:[^"\\]|\\.)*")(\s*:)?|\b(true|false)\b|\bnull\b|(-?\d+\.?\d*(?:[eE][+-]?\d+)?)/g,(e,t,s,r,o)=>t?s?'<span class="json-key">'+t+"</span>"+s:'<span class="json-str">'+t+"</span>":r?'<span class="json-bool">'+e+"</span>":o?'<span class="json-num">'+e+"</span>":e==="null"?'<span class="json-null">null</span>':e)}var xt=class extends f{constructor(){super(...arguments);this.code=0;}createRenderRoot(){return this}render(){let t=st(this.code);return a`<span class="status-pill ${t}">${this.code}</span>`}};u([y({type:Number})],xt.prototype,"code",2),xt=u([g("bk-status-pill")],xt);var Rt=class extends f{constructor(){super(...arguments);this.ms=0;}createRenderRoot(){return this}render(){return a`<span class="req-duration">${v(this.ms)}</span>`}};u([y({type:Number})],Rt.prototype,"ms",2),Rt=u([g("bk-duration-label")],Rt);var ot=class extends f{constructor(){super(...arguments);this.title="";this.subtitle="";}createRenderRoot(){return this}render(){return a`
855
+ <script>(function(){'use strict';var wr=Object.defineProperty;var Rr=Object.getOwnPropertyDescriptor;var u=(o,s,t,e)=>{for(var r=e>1?void 0:e?Rr(s,t):s,i=o.length-1,n;i>=0;i--)(n=o[i])&&(r=(e?n(s,t,r):n(r))||r);return e&&r&&wr(s,t,r),r};var zt=globalThis,Zt=zt.ShadowRoot&&(zt.ShadyCSS===void 0||zt.ShadyCSS.nativeShadow)&&"adoptedStyleSheets"in Document.prototype&&"replace"in CSSStyleSheet.prototype,os=Symbol(),is=new WeakMap,Jt=class{constructor(s,t,e){if(this._$cssResult$=true,e!==os)throw Error("CSSResult is not constructable. Use `unsafeCSS` or `css` instead.");this.cssText=s,this.t=t;}get styleSheet(){let s=this.o,t=this.t;if(Zt&&s===void 0){let e=t!==void 0&&t.length===1;e&&(s=is.get(t)),s===void 0&&((this.o=s=new CSSStyleSheet).replaceSync(this.cssText),e&&is.set(t,s));}return s}toString(){return this.cssText}},ns=o=>new Jt(typeof o=="string"?o:o+"",void 0,os);var as=(o,s)=>{if(Zt)o.adoptedStyleSheets=s.map(t=>t instanceof CSSStyleSheet?t:t.styleSheet);else for(let t of s){let e=document.createElement("style"),r=zt.litNonce;r!==void 0&&e.setAttribute("nonce",r),e.textContent=t.cssText,o.appendChild(e);}},ye=Zt?o=>o:o=>o instanceof CSSStyleSheet?(s=>{let t="";for(let e of s.cssRules)t+=e.cssText;return ns(t)})(o):o;var{is:Ar,defineProperty:Ir,getOwnPropertyDescriptor:Cr,getOwnPropertyNames:Lr,getOwnPropertySymbols:Mr,getPrototypeOf:Nr}=Object,K=globalThis,ls=K.trustedTypes,Or=ls?ls.emptyScript:"",kr=K.reactiveElementPolyfillSupport,Mt=(o,s)=>o,Nt={toAttribute(o,s){switch(s){case Boolean:o=o?Or:null;break;case Object:case Array:o=o==null?o:JSON.stringify(o);}return o},fromAttribute(o,s){let t=o;switch(s){case Boolean:t=o!==null;break;case Number:t=o===null?null:Number(o);break;case Object:case Array:try{t=JSON.parse(o);}catch{t=null;}}return t}},te=(o,s)=>!Ar(o,s),cs={attribute:true,type:String,converter:Nt,reflect:false,useDefault:false,hasChanged:te};Symbol.metadata??(Symbol.metadata=Symbol("metadata")),K.litPropertyMetadata??(K.litPropertyMetadata=new WeakMap);var j=class extends HTMLElement{static addInitializer(s){this._$Ei(),(this.l??(this.l=[])).push(s);}static get observedAttributes(){return this.finalize(),this._$Eh&&[...this._$Eh.keys()]}static createProperty(s,t=cs){if(t.state&&(t.attribute=false),this._$Ei(),this.prototype.hasOwnProperty(s)&&((t=Object.create(t)).wrapped=true),this.elementProperties.set(s,t),!t.noAccessor){let e=Symbol(),r=this.getPropertyDescriptor(s,e,t);r!==void 0&&Ir(this.prototype,s,r);}}static getPropertyDescriptor(s,t,e){let{get:r,set:i}=Cr(this.prototype,s)??{get(){return this[t]},set(n){this[t]=n;}};return {get:r,set(n){let l=r?.call(this);i?.call(this,n),this.requestUpdate(s,l,e);},configurable:true,enumerable:true}}static getPropertyOptions(s){return this.elementProperties.get(s)??cs}static _$Ei(){if(this.hasOwnProperty(Mt("elementProperties")))return;let s=Nr(this);s.finalize(),s.l!==void 0&&(this.l=[...s.l]),this.elementProperties=new Map(s.elementProperties);}static finalize(){if(this.hasOwnProperty(Mt("finalized")))return;if(this.finalized=true,this._$Ei(),this.hasOwnProperty(Mt("properties"))){let t=this.properties,e=[...Lr(t),...Mr(t)];for(let r of e)this.createProperty(r,t[r]);}let s=this[Symbol.metadata];if(s!==null){let t=litPropertyMetadata.get(s);if(t!==void 0)for(let[e,r]of t)this.elementProperties.set(e,r);}this._$Eh=new Map;for(let[t,e]of this.elementProperties){let r=this._$Eu(t,e);r!==void 0&&this._$Eh.set(r,t);}this.elementStyles=this.finalizeStyles(this.styles);}static finalizeStyles(s){let t=[];if(Array.isArray(s)){let e=new Set(s.flat(1/0).reverse());for(let r of e)t.unshift(ye(r));}else s!==void 0&&t.push(ye(s));return t}static _$Eu(s,t){let e=t.attribute;return e===false?void 0:typeof e=="string"?e:typeof s=="string"?s.toLowerCase():void 0}constructor(){super(),this._$Ep=void 0,this.isUpdatePending=false,this.hasUpdated=false,this._$Em=null,this._$Ev();}_$Ev(){this._$ES=new Promise(s=>this.enableUpdating=s),this._$AL=new Map,this._$E_(),this.requestUpdate(),this.constructor.l?.forEach(s=>s(this));}addController(s){(this._$EO??(this._$EO=new Set)).add(s),this.renderRoot!==void 0&&this.isConnected&&s.hostConnected?.();}removeController(s){this._$EO?.delete(s);}_$E_(){let s=new Map,t=this.constructor.elementProperties;for(let e of t.keys())this.hasOwnProperty(e)&&(s.set(e,this[e]),delete this[e]);s.size>0&&(this._$Ep=s);}createRenderRoot(){let s=this.shadowRoot??this.attachShadow(this.constructor.shadowRootOptions);return as(s,this.constructor.elementStyles),s}connectedCallback(){this.renderRoot??(this.renderRoot=this.createRenderRoot()),this.enableUpdating(true),this._$EO?.forEach(s=>s.hostConnected?.());}enableUpdating(s){}disconnectedCallback(){this._$EO?.forEach(s=>s.hostDisconnected?.());}attributeChangedCallback(s,t,e){this._$AK(s,e);}_$ET(s,t){let e=this.constructor.elementProperties.get(s),r=this.constructor._$Eu(s,e);if(r!==void 0&&e.reflect===true){let i=(e.converter?.toAttribute!==void 0?e.converter:Nt).toAttribute(t,e.type);this._$Em=s,i==null?this.removeAttribute(r):this.setAttribute(r,i),this._$Em=null;}}_$AK(s,t){let e=this.constructor,r=e._$Eh.get(s);if(r!==void 0&&this._$Em!==r){let i=e.getPropertyOptions(r),n=typeof i.converter=="function"?{fromAttribute:i.converter}:i.converter?.fromAttribute!==void 0?i.converter:Nt;this._$Em=r;let l=n.fromAttribute(t,i.type);this[r]=l??this._$Ej?.get(r)??l,this._$Em=null;}}requestUpdate(s,t,e,r=false,i){if(s!==void 0){let n=this.constructor;if(r===false&&(i=this[s]),e??(e=n.getPropertyOptions(s)),!((e.hasChanged??te)(i,t)||e.useDefault&&e.reflect&&i===this._$Ej?.get(s)&&!this.hasAttribute(n._$Eu(s,e))))return;this.C(s,t,e);}this.isUpdatePending===false&&(this._$ES=this._$EP());}C(s,t,{useDefault:e,reflect:r,wrapped:i},n){e&&!(this._$Ej??(this._$Ej=new Map)).has(s)&&(this._$Ej.set(s,n??t??this[s]),i!==true||n!==void 0)||(this._$AL.has(s)||(this.hasUpdated||e||(t=void 0),this._$AL.set(s,t)),r===true&&this._$Em!==s&&(this._$Eq??(this._$Eq=new Set)).add(s));}async _$EP(){this.isUpdatePending=true;try{await this._$ES;}catch(t){Promise.reject(t);}let s=this.scheduleUpdate();return s!=null&&await s,!this.isUpdatePending}scheduleUpdate(){return this.performUpdate()}performUpdate(){if(!this.isUpdatePending)return;if(!this.hasUpdated){if(this.renderRoot??(this.renderRoot=this.createRenderRoot()),this._$Ep){for(let[r,i]of this._$Ep)this[r]=i;this._$Ep=void 0;}let e=this.constructor.elementProperties;if(e.size>0)for(let[r,i]of e){let{wrapped:n}=i,l=this[r];n!==true||this._$AL.has(r)||l===void 0||this.C(r,void 0,i,l);}}let s=false,t=this._$AL;try{s=this.shouldUpdate(t),s?(this.willUpdate(t),this._$EO?.forEach(e=>e.hostUpdate?.()),this.update(t)):this._$EM();}catch(e){throw s=false,this._$EM(),e}s&&this._$AE(t);}willUpdate(s){}_$AE(s){this._$EO?.forEach(t=>t.hostUpdated?.()),this.hasUpdated||(this.hasUpdated=true,this.firstUpdated(s)),this.updated(s);}_$EM(){this._$AL=new Map,this.isUpdatePending=false;}get updateComplete(){return this.getUpdateComplete()}getUpdateComplete(){return this._$ES}shouldUpdate(s){return true}update(s){this._$Eq&&(this._$Eq=this._$Eq.forEach(t=>this._$ET(t,this[t]))),this._$EM();}updated(s){}firstUpdated(s){}};j.elementStyles=[],j.shadowRootOptions={mode:"open"},j[Mt("elementProperties")]=new Map,j[Mt("finalized")]=new Map,kr?.({ReactiveElement:j}),(K.reactiveElementVersions??(K.reactiveElementVersions=[])).push("2.1.2");var kt=globalThis,ds=o=>o,ee=kt.trustedTypes,ps=ee?ee.createPolicy("lit-html",{createHTML:o=>o}):void 0,gs="$lit$",z=`lit$${Math.random().toFixed(9).slice(2)}$`,bs="?"+z,Dr=`<${bs}>`,ot=document,Dt=()=>ot.createComment(""),Ht=o=>o===null||typeof o!="object"&&typeof o!="function",Re=Array.isArray,Hr=o=>Re(o)||typeof o?.[Symbol.iterator]=="function",_e=`[
856
+ \f\r]`,Ot=/<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g,hs=/-->/g,us=/>/g,rt=RegExp(`>|${_e}(?:([^\\s"'>=/]+)(${_e}*=${_e}*(?:[^
857
+ \f\r"'\`<>=]|("|')|))|$)`,"g"),ms=/'/g,fs=/"/g,Es=/^(?:script|style|textarea|title)$/i,Ae=o=>(s,...t)=>({_$litType$:o,strings:s,values:t}),a=Ae(1),O=Ae(2),Y=Symbol.for("lit-noChange"),p=Symbol.for("lit-nothing"),vs=new WeakMap,it=ot.createTreeWalker(ot,129);function ys(o,s){if(!Re(o)||!o.hasOwnProperty("raw"))throw Error("invalid template strings array");return ps!==void 0?ps.createHTML(s):s}var Pr=(o,s)=>{let t=o.length-1,e=[],r,i=s===2?"<svg>":s===3?"<math>":"",n=Ot;for(let l=0;l<t;l++){let c=o[l],d,h,m=-1,v=0;for(;v<c.length&&(n.lastIndex=v,h=n.exec(c),h!==null);)v=n.lastIndex,n===Ot?h[1]==="!--"?n=hs:h[1]!==void 0?n=us:h[2]!==void 0?(Es.test(h[2])&&(r=RegExp("</"+h[2],"g")),n=rt):h[3]!==void 0&&(n=rt):n===rt?h[0]===">"?(n=r??Ot,m=-1):h[1]===void 0?m=-2:(m=n.lastIndex-h[2].length,d=h[1],n=h[3]===void 0?rt:h[3]==='"'?fs:ms):n===fs||n===ms?n=rt:n===hs||n===us?n=Ot:(n=rt,r=void 0);let x=n===rt&&o[l+1].startsWith("/>")?" ":"";i+=n===Ot?c+Dr:m>=0?(e.push(d),c.slice(0,m)+gs+c.slice(m)+z+x):c+z+(m===-2?l:x);}return [ys(o,i+(o[t]||"<?>")+(s===2?"</svg>":s===3?"</math>":"")),e]},Pt=class o{constructor({strings:s,_$litType$:t},e){let r;this.parts=[];let i=0,n=0,l=s.length-1,c=this.parts,[d,h]=Pr(s,t);if(this.el=o.createElement(d,e),it.currentNode=this.el.content,t===2||t===3){let m=this.el.content.firstChild;m.replaceWith(...m.childNodes);}for(;(r=it.nextNode())!==null&&c.length<l;){if(r.nodeType===1){if(r.hasAttributes())for(let m of r.getAttributeNames())if(m.endsWith(gs)){let v=h[n++],x=r.getAttribute(m).split(z),y=/([.?@])?(.*)/.exec(v);c.push({type:1,index:i,name:y[2],strings:x,ctor:y[1]==="."?xe:y[1]==="?"?Se:y[1]==="@"?Te:ht}),r.removeAttribute(m);}else m.startsWith(z)&&(c.push({type:6,index:i}),r.removeAttribute(m));if(Es.test(r.tagName)){let m=r.textContent.split(z),v=m.length-1;if(v>0){r.textContent=ee?ee.emptyScript:"";for(let x=0;x<v;x++)r.append(m[x],Dt()),it.nextNode(),c.push({type:2,index:++i});r.append(m[v],Dt());}}}else if(r.nodeType===8)if(r.data===bs)c.push({type:2,index:i});else {let m=-1;for(;(m=r.data.indexOf(z,m+1))!==-1;)c.push({type:7,index:i}),m+=z.length-1;}i++;}}static createElement(s,t){let e=ot.createElement("template");return e.innerHTML=s,e}};function pt(o,s,t=o,e){if(s===Y)return s;let r=e!==void 0?t._$Co?.[e]:t._$Cl,i=Ht(s)?void 0:s._$litDirective$;return r?.constructor!==i&&(r?._$AO?.(false),i===void 0?r=void 0:(r=new i(o),r._$AT(o,t,e)),e!==void 0?(t._$Co??(t._$Co=[]))[e]=r:t._$Cl=r),r!==void 0&&(s=pt(o,r._$AS(o,s.values),r,e)),s}var $e=class{constructor(s,t){this._$AV=[],this._$AN=void 0,this._$AD=s,this._$AM=t;}get parentNode(){return this._$AM.parentNode}get _$AU(){return this._$AM._$AU}u(s){let{el:{content:t},parts:e}=this._$AD,r=(s?.creationScope??ot).importNode(t,true);it.currentNode=r;let i=it.nextNode(),n=0,l=0,c=e[0];for(;c!==void 0;){if(n===c.index){let d;c.type===2?d=new qt(i,i.nextSibling,this,s):c.type===1?d=new c.ctor(i,c.name,c.strings,this,s):c.type===6&&(d=new we(i,this,s)),this._$AV.push(d),c=e[++l];}n!==c?.index&&(i=it.nextNode(),n++);}return it.currentNode=ot,r}p(s){let t=0;for(let e of this._$AV)e!==void 0&&(e.strings!==void 0?(e._$AI(s,e,t),t+=e.strings.length-2):e._$AI(s[t])),t++;}},qt=class o{get _$AU(){return this._$AM?._$AU??this._$Cv}constructor(s,t,e,r){this.type=2,this._$AH=p,this._$AN=void 0,this._$AA=s,this._$AB=t,this._$AM=e,this.options=r,this._$Cv=r?.isConnected??true;}get parentNode(){let s=this._$AA.parentNode,t=this._$AM;return t!==void 0&&s?.nodeType===11&&(s=t.parentNode),s}get startNode(){return this._$AA}get endNode(){return this._$AB}_$AI(s,t=this){s=pt(this,s,t),Ht(s)?s===p||s==null||s===""?(this._$AH!==p&&this._$AR(),this._$AH=p):s!==this._$AH&&s!==Y&&this._(s):s._$litType$!==void 0?this.$(s):s.nodeType!==void 0?this.T(s):Hr(s)?this.k(s):this._(s);}O(s){return this._$AA.parentNode.insertBefore(s,this._$AB)}T(s){this._$AH!==s&&(this._$AR(),this._$AH=this.O(s));}_(s){this._$AH!==p&&Ht(this._$AH)?this._$AA.nextSibling.data=s:this.T(ot.createTextNode(s)),this._$AH=s;}$(s){let{values:t,_$litType$:e}=s,r=typeof e=="number"?this._$AC(s):(e.el===void 0&&(e.el=Pt.createElement(ys(e.h,e.h[0]),this.options)),e);if(this._$AH?._$AD===r)this._$AH.p(t);else {let i=new $e(r,this),n=i.u(this.options);i.p(t),this.T(n),this._$AH=i;}}_$AC(s){let t=vs.get(s.strings);return t===void 0&&vs.set(s.strings,t=new Pt(s)),t}k(s){Re(this._$AH)||(this._$AH=[],this._$AR());let t=this._$AH,e,r=0;for(let i of s)r===t.length?t.push(e=new o(this.O(Dt()),this.O(Dt()),this,this.options)):e=t[r],e._$AI(i),r++;r<t.length&&(this._$AR(e&&e._$AB.nextSibling,r),t.length=r);}_$AR(s=this._$AA.nextSibling,t){for(this._$AP?.(false,true,t);s!==this._$AB;){let e=ds(s).nextSibling;ds(s).remove(),s=e;}}setConnected(s){this._$AM===void 0&&(this._$Cv=s,this._$AP?.(s));}},ht=class{get tagName(){return this.element.tagName}get _$AU(){return this._$AM._$AU}constructor(s,t,e,r,i){this.type=1,this._$AH=p,this._$AN=void 0,this.element=s,this.name=t,this._$AM=r,this.options=i,e.length>2||e[0]!==""||e[1]!==""?(this._$AH=Array(e.length-1).fill(new String),this.strings=e):this._$AH=p;}_$AI(s,t=this,e,r){let i=this.strings,n=false;if(i===void 0)s=pt(this,s,t,0),n=!Ht(s)||s!==this._$AH&&s!==Y,n&&(this._$AH=s);else {let l=s,c,d;for(s=i[0],c=0;c<i.length-1;c++)d=pt(this,l[e+c],t,c),d===Y&&(d=this._$AH[c]),n||(n=!Ht(d)||d!==this._$AH[c]),d===p?s=p:s!==p&&(s+=(d??"")+i[c+1]),this._$AH[c]=d;}n&&!r&&this.j(s);}j(s){s===p?this.element.removeAttribute(this.name):this.element.setAttribute(this.name,s??"");}},xe=class extends ht{constructor(){super(...arguments),this.type=3;}j(s){this.element[this.name]=s===p?void 0:s;}},Se=class extends ht{constructor(){super(...arguments),this.type=4;}j(s){this.element.toggleAttribute(this.name,!!s&&s!==p);}},Te=class extends ht{constructor(s,t,e,r,i){super(s,t,e,r,i),this.type=5;}_$AI(s,t=this){if((s=pt(this,s,t,0)??p)===Y)return;let e=this._$AH,r=s===p&&e!==p||s.capture!==e.capture||s.once!==e.once||s.passive!==e.passive,i=s!==p&&(e===p||r);r&&this.element.removeEventListener(this.name,this,e),i&&this.element.addEventListener(this.name,this,s),this._$AH=s;}handleEvent(s){typeof this._$AH=="function"?this._$AH.call(this.options?.host??this.element,s):this._$AH.handleEvent(s);}},we=class{constructor(s,t,e){this.element=s,this.type=6,this._$AN=void 0,this._$AM=t,this.options=e;}get _$AU(){return this._$AM._$AU}_$AI(s){pt(this,s);}};var qr=kt.litHtmlPolyfillSupport;qr?.(Pt,qt),(kt.litHtmlVersions??(kt.litHtmlVersions=[])).push("3.3.2");var _s=(o,s,t)=>{let e=t?.renderBefore??s,r=e._$litPart$;if(r===void 0){let i=t?.renderBefore??null;e._$litPart$=r=new qt(s.insertBefore(Dt(),i),i,void 0,t??{});}return r._$AI(o),r};var Ut=globalThis,E=class extends j{constructor(){super(...arguments),this.renderOptions={host:this},this._$Do=void 0;}createRenderRoot(){var t;let s=super.createRenderRoot();return (t=this.renderOptions).renderBefore??(t.renderBefore=s.firstChild),s}update(s){let t=this.render();this.hasUpdated||(this.renderOptions.isConnected=this.isConnected),super.update(s),this._$Do=_s(t,this.renderRoot,this.renderOptions);}connectedCallback(){super.connectedCallback(),this._$Do?.setConnected(true);}disconnectedCallback(){super.disconnectedCallback(),this._$Do?.setConnected(false);}render(){return Y}};E._$litElement$=true,E.finalized=true,Ut.litElementHydrateSupport?.({LitElement:E});var Ur=Ut.litElementPolyfillSupport;Ur?.({LitElement:E});(Ut.litElementVersions??(Ut.litElementVersions=[])).push("4.2.2");var S=o=>(s,t)=>{t!==void 0?t.addInitializer(()=>{customElements.define(o,s);}):customElements.define(o,s);};var Fr={attribute:true,type:String,converter:Nt,reflect:false,hasChanged:te},Gr=(o=Fr,s,t)=>{let{kind:e,metadata:r}=t,i=globalThis.litPropertyMetadata.get(r);if(i===void 0&&globalThis.litPropertyMetadata.set(r,i=new Map),e==="setter"&&((o=Object.create(o)).wrapped=true),i.set(t.name,o),e==="accessor"){let{name:n}=t;return {set(l){let c=s.get.call(this);s.set.call(this,l),this.requestUpdate(n,c,o,true,l);},init(l){return l!==void 0&&this.C(n,void 0,o,l),l}}}if(e==="setter"){let{name:n}=t;return function(l){let c=this[n];s.call(this,l),this.requestUpdate(n,c,o,true,l);}}throw Error("Unsupported decorator location: "+e)};function L(o){return (s,t)=>typeof t=="object"?Gr(o,s,t):((e,r,i)=>{let n=r.hasOwnProperty(i);return r.constructor.createProperty(i,e),n?Object.getOwnPropertyDescriptor(r,i):void 0})(o,s,t)}function b(o){return L({...o,state:true,attribute:false})}var Ft=class extends E{constructor(){super(...arguments);this.method="";}createRenderRoot(){return this}render(){let t=this.method.toUpperCase();return a`<span class="method-badge method-badge-${t}">${t}</span>`}};u([L()],Ft.prototype,"method",2),Ft=u([S("bk-method-badge")],Ft);var P="/__brakit/api",F="/__brakit",w={flows:`${P}/flows`,requests:`${P}/requests`,events:`${P}/events`,clear:`${P}/clear`,fetches:`${P}/fetches`,errors:`${P}/errors`,logs:`${P}/logs`,queries:`${P}/queries`,metricsLive:`${P}/metrics/live`,insights:`${P}/insights`,tab:`${P}/tab`,activity:`${P}/activity`,graph:`${P}/graph`};var ut="polling",re="static",Br="auth-handshake",Wr="auth-check",Qr="middleware",Gt={[Br]:1,[Wr]:1,[Qr]:1};var ie="fetch";var oe="error_event",ne="query",ae="issues";var Ie={overview:"Overview",actions:"Actions",requests:"Requests",fetches:"Server Fetches",queries:"Queries",errors:"Errors",logs:"Logs",performance:"Performance",security:"Security",graph:"Graph"},Ce={overview:"Live summary of your application",actions:"User actions captured as sequences of HTTP requests",requests:"All HTTP requests proxied through brakit",fetches:"Outbound HTTP calls made by your server to external services",queries:"Database queries executed during request handling",errors:"Unhandled exceptions and errors thrown by your application",logs:"Console output from your application",performance:"Endpoint health and response time trends",security:"Security findings and recommendations",graph:"Runtime dependency graph of your application"};var Me=100,mt=300,ft=800,Ne=2e3,Oe=100,ke=50,De=500;var J="__all__",pe={SELECT:"var(--blue)",INSERT:"var(--green)",UPDATE:"var(--amber)",DELETE:"var(--red)",COUNT:"var(--text-muted)"},As={error:"var(--red)",warn:"var(--amber)",info:"var(--blue)",debug:"var(--text-muted)",log:"var(--text-dim)"},qe=["#2563eb","#7c3aed","#16a34a","#d97706","#dc2626","#0891b2","#ea580c","#c026d3","#059669","#db2777"],Bt={green:"#4ade80",amber:"#fbbf24",red:"#f87171"},gt=[{max:Me,label:"Fast",color:"var(--green)",bg:"rgba(22,163,74,0.08)",border:"rgba(22,163,74,0.2)"},{max:mt,label:"Good",color:"var(--green)",bg:"rgba(22,163,74,0.06)",border:"rgba(22,163,74,0.15)"},{max:ft,label:"OK",color:"var(--amber)",bg:"rgba(217,119,6,0.06)",border:"rgba(217,119,6,0.15)"},{max:Ne,label:"Slow",color:"var(--red)",bg:"rgba(220,38,38,0.06)",border:"rgba(220,38,38,0.15)"},{max:1/0,label:"Critical",color:"var(--red)",bg:"rgba(220,38,38,0.08)",border:"rgba(220,38,38,0.2)"}],Is="rgba(228,228,231,0.8)",Ue="rgba(113,113,122,0.7)",Cs="10px monospace",Fe="9px monospace";var Ls={top:16,right:16,bottom:28,left:52},Ms={fetch:"var(--blue)",log:"var(--text-muted)",error:"var(--red)",query:"var(--accent)"},Ns={fetch:"FETCH",log:"LOG",error:"ERROR",query:"QUERY"},Os=new Set(["cookie","set-cookie","authorization","proxy-authorization","x-api-key","x-auth-token"]),ks={400:"Bad Request",401:"Unauthorized",403:"Forbidden",404:"Not Found",405:"Method Not Allowed",408:"Timeout",409:"Conflict",422:"Unprocessable",429:"Too Many Requests",500:"Internal Server Error",502:"Bad Gateway",503:"Service Unavailable",504:"Gateway Timeout"},Ds=new Set(["host","connection","accept-encoding"]),Z={critical:{icon:"\u2717",cls:"critical",sort:0},warning:{icon:"\u26A0",cls:"warning",sort:1},info:{icon:"\u2139",cls:"info",sort:2}};function _(o){return o<1e3?o+"ms":(o/1e3).toFixed(1)+"s"}function et(o){return !o||o===0?"":o<1024?o+"b":(o/1024).toFixed(1)+"kb"}function tt(o){return o?o.replaceAll("&","&amp;").replaceAll("<","&lt;").replaceAll(">","&gt;").replaceAll('"',"&quot;"):""}function bt(o){return o>=500?"status-pill-5xx":o>=400?"status-pill-4xx":o>=300?"status-pill-3xx":"status-pill-2xx"}function Hs(o){return ks[o]||(o>=500?"Server Error":o>=400?"Client Error":"OK")}function jr(o,s){if(Os.has(o.toLowerCase())){let t=String(s);return t.length<=8?"****":t.slice(0,4)+"..."+t.slice(-4)+" ("+t.length+" chars)"}return String(s)}function Et(o){return !o||Object.keys(o).length===0?'<span style="color:var(--text-muted)">No headers</span>':Object.entries(o).map(([s,t])=>'<span class="json-key">'+tt(s)+"</span>: "+tt(jr(s,t))).join(`
858
+ `)}function nt(o){if(!o)return '<span style="color:var(--text-muted)">No body</span>';try{let s=JSON.parse(o);return Yr(JSON.stringify(s,null,2))}catch{return tt(o)}}function Yr(o){return tt(o).replace(/("(?:[^"\\]|\\.)*")(\s*:)?|\b(true|false)\b|\bnull\b|(-?\d+\.?\d*(?:[eE][+-]?\d+)?)/g,(s,t,e,r,i)=>t?e?'<span class="json-key">'+t+"</span>"+e:'<span class="json-str">'+t+"</span>":r?'<span class="json-bool">'+s+"</span>":i?'<span class="json-num">'+s+"</span>":s==="null"?'<span class="json-null">null</span>':s)}var Wt=class extends E{constructor(){super(...arguments);this.code=0;}createRenderRoot(){return this}render(){let t=bt(this.code);return a`<span class="status-pill ${t}">${this.code}</span>`}};u([L({type:Number})],Wt.prototype,"code",2),Wt=u([S("bk-status-pill")],Wt);var Qt=class extends E{constructor(){super(...arguments);this.ms=0;}createRenderRoot(){return this}render(){return a`<span class="req-duration">${_(this.ms)}</span>`}};u([L({type:Number})],Qt.prototype,"ms",2),Qt=u([S("bk-duration-label")],Qt);var yt=class extends E{constructor(){super(...arguments);this.title="";this.subtitle="";}createRenderRoot(){return this}render(){return a`
755
859
  <div class="empty">
756
860
  <span class="empty-title">${this.title}</span>
757
861
  <span class="empty-sub">${this.subtitle}</span>
758
862
  </div>
759
- `}};u([y()],ot.prototype,"title",2),u([y()],ot.prototype,"subtitle",2),ot=u([g("bk-empty-state")],ot);var C=class extends f{constructor(){super(...arguments);this.message="";this.visible=false;}createRenderRoot(){return this}static show(t){let s=document.querySelector("bk-toast");s&&s.showMessage(t);}showMessage(t){this.hideTimer&&clearTimeout(this.hideTimer),this.message=t,this.visible=true,this.hideTimer=setTimeout(()=>{this.visible=false;},2e3);}render(){return a`<div class="toast ${this.visible?"show":""}">${this.message}</div>`}};u([_()],C.prototype,"message",2),u([_()],C.prototype,"visible",2),C=u([g("bk-toast")],C);var V=class extends f{constructor(){super(...arguments);this.text="";this.label="Copy";this.toastMessage="Copied";}createRenderRoot(){return this}async copy(t){t.stopPropagation();try{await navigator.clipboard.writeText(this.text),C.show(this.toastMessage);}catch{}}render(){return a`<button class="query-detail-copy" @click=${this.copy}>${this.label}</button>`}};u([y()],V.prototype,"text",2),u([y()],V.prototype,"label",2),u([y({attribute:"toast-message"})],V.prototype,"toastMessage",2),V=u([g("bk-copy-button")],V);var Y=class extends f{constructor(){super(...arguments);this.value="";this.label="";this.color="";}createRenderRoot(){return this}render(){return a`
863
+ `}};u([L()],yt.prototype,"title",2),u([L()],yt.prototype,"subtitle",2),yt=u([S("bk-empty-state")],yt);var D=class extends E{constructor(){super(...arguments);this.message="";this.visible=false;}createRenderRoot(){return this}static show(t){let e=document.querySelector("bk-toast");e&&e.showMessage(t);}showMessage(t){this.hideTimer&&clearTimeout(this.hideTimer),this.message=t,this.visible=true,this.hideTimer=setTimeout(()=>{this.visible=false;},2e3);}render(){return a`<div class="toast ${this.visible?"show":""}">${this.message}</div>`}};u([b()],D.prototype,"message",2),u([b()],D.prototype,"visible",2),D=u([S("bk-toast")],D);var at=class extends E{constructor(){super(...arguments);this.text="";this.label="Copy";this.toastMessage="Copied";}createRenderRoot(){return this}async copy(t){t.stopPropagation();try{await navigator.clipboard.writeText(this.text),D.show(this.toastMessage);}catch{}}render(){return a`<button class="query-detail-copy" @click=${this.copy}>${this.label}</button>`}};u([L()],at.prototype,"text",2),u([L()],at.prototype,"label",2),u([L({attribute:"toast-message"})],at.prototype,"toastMessage",2),at=u([S("bk-copy-button")],at);var lt=class extends E{constructor(){super(...arguments);this.value="";this.label="";this.color="";}createRenderRoot(){return this}render(){return a`
760
864
  <div class="fetch-stat">
761
865
  <span class="fetch-stat-value" style="color:${this.color}">${this.value}</span>
762
866
  <span class="fetch-stat-label">${this.label}</span>
763
867
  </div>
764
- `}};u([y()],Y.prototype,"value",2),u([y()],Y.prototype,"label",2),u([y()],Y.prototype,"color",2),Y=u([g("bk-stat-card")],Y);var F=class extends Event{constructor(e,t,s,r){super("context-request",{bubbles:true,composed:true}),this.context=e,this.contextTarget=t,this.callback=s,this.subscribe=r??false;}};var it=class{constructor(e,t,s,r){if(this.subscribe=false,this.provided=false,this.value=void 0,this.t=(o,n)=>{this.unsubscribe&&(this.unsubscribe!==n&&(this.provided=false,this.unsubscribe()),this.subscribe||this.unsubscribe()),this.value=o,this.host.requestUpdate(),this.provided&&!this.subscribe||(this.provided=true,this.callback&&this.callback(o,n)),this.unsubscribe=n;},this.host=e,t.context!==void 0){let o=t;this.context=o.context,this.callback=o.callback,this.subscribe=o.subscribe??false;}else this.context=t,this.callback=s,this.subscribe=r??false;this.host.addController(this);}hostConnected(){this.dispatchRequest();}hostDisconnected(){this.unsubscribe&&(this.unsubscribe(),this.unsubscribe=void 0);}dispatchRequest(){this.host.dispatchEvent(new F(this.context,this.host,this.t,this.subscribe));}};var Bt=class{get value(){return this.o}set value(e){this.setValue(e);}setValue(e,t=false){let s=t||!Object.is(e,this.o);this.o=e,s&&this.updateObservers();}constructor(e){this.subscriptions=new Map,this.updateObservers=()=>{for(let[t,{disposer:s}]of this.subscriptions)t(this.o,s);},e!==void 0&&(this.value=e);}addCallback(e,t,s){if(!s)return void e(this.value);this.subscriptions.has(e)||this.subscriptions.set(e,{disposer:()=>{this.subscriptions.delete(e);},consumerHost:t});let{disposer:r}=this.subscriptions.get(e);e(this.value,r);}clearCallbacks(){this.subscriptions.clear();}};var ge=class extends Event{constructor(e,t){super("context-provider",{bubbles:true,composed:true}),this.context=e,this.contextTarget=t;}},nt=class extends Bt{constructor(e,t,s){super(t.context!==void 0?t.initialValue:s),this.onContextRequest=r=>{if(r.context!==this.context)return;let o=r.contextTarget??r.composedPath()[0];o!==this.host&&(r.stopPropagation(),this.addCallback(r.callback,o,r.subscribe));},this.onProviderRequest=r=>{if(r.context!==this.context||(r.contextTarget??r.composedPath()[0])===this.host)return;let o=new Set;for(let[n,{consumerHost:l}]of this.subscriptions)o.has(n)||(o.add(n),l.dispatchEvent(new F(this.context,l,n,true)));r.stopPropagation();},this.host=e,t.context!==void 0?this.context=t.context:this.context=t,this.attachListeners(),this.host.addController?.(this);}attachListeners(){this.host.addEventListener("context-request",this.onContextRequest),this.host.addEventListener("context-provider",this.onProviderRequest);}hostConnected(){this.host.dispatchEvent(new ge(this.context,this.host));}};function Ee({context:i}){return (e,t)=>{let s=new WeakMap;if(typeof t=="object")return {get(){return e.get.call(this)},set(r){return s.get(this).setValue(r),e.set.call(this,r)},init(r){return s.set(this,new nt(this,{context:i,initialValue:r})),r}};{e.constructor.addInitializer((n=>{s.set(n,new nt(n,{context:i}));}));let r=Object.getOwnPropertyDescriptor(e,t),o;if(r===void 0){let n=new WeakMap;o={get(){return n.get(this)},set(l){s.get(this).setValue(l),n.set(this,l);},configurable:true,enumerable:true};}else {let n=r.set;o={...r,set(l){s.get(this).setValue(l),n?.call(this,l);}};}return void Object.defineProperty(e,t,o)}}}function R({context:i,subscribe:e}){return (t,s)=>{typeof s=="object"?s.addInitializer((function(){new it(this,{context:i,callback:r=>{t.set.call(this,r);},subscribe:e});})):t.constructor.addInitializer((r=>{new it(r,{context:i,callback:o=>{r[s]=o;},subscribe:e});}));}}var x="dashboard-store",Gt=class extends EventTarget{constructor(){super(...arguments);this._state={flows:[],requests:[],fetches:[],errors:[],logs:[],queries:[],issues:[],metrics:[],viewMode:"simple",activeView:"overview"};}get state(){return this._state}setFlows(t){this._state={...this._state,flows:t},this.notify("flows");}setRequests(t){this._state={...this._state,requests:t},this.notify("requests");}setFetches(t){this._state={...this._state,fetches:t},this.notify("fetches");}setErrors(t){this._state={...this._state,errors:t},this.notify("errors");}setLogs(t){this._state={...this._state,logs:t},this.notify("logs");}setQueries(t){this._state={...this._state,queries:t},this.notify("queries");}setIssues(t){this._state={...this._state,issues:t},this.notify("issues");}setMetrics(t){this._state={...this._state,metrics:t},this.notify("metrics");}prependRequest(t){let s=[t,...this._state.requests.slice(0,999)];this._state={...this._state,requests:s},this.notify("requests");}prependFetch(t){this._state={...this._state,fetches:[t,...this._state.fetches]},this.notify("fetches");}prependError(t){this._state={...this._state,errors:[t,...this._state.errors]},this.notify("errors");}prependLog(t){this._state={...this._state,logs:[t,...this._state.logs]},this.notify("logs");}prependQuery(t){this._state={...this._state,queries:[t,...this._state.queries]},this.notify("queries");}setActiveView(t){this._state={...this._state,activeView:t},this.notify("activeView");}setViewMode(t){this._state={...this._state,viewMode:t},this.notify("viewMode");}clearAll(){this._state={...this._state,flows:[],requests:[],fetches:[],errors:[],logs:[],queries:[],issues:[],metrics:[]},this.notify("all");}notify(t){this.dispatchEvent(new CustomEvent("state-changed",{detail:t}));}};var at=class extends f{constructor(){super(...arguments);this.expandedIdx=-1;}createRenderRoot(){return this}connectedCallback(){super.connectedCallback(),this.store.addEventListener("state-changed",()=>this.requestUpdate());}toggleError(t){this.expandedIdx=this.expandedIdx===t?-1:t;}renderErrorRow(t,s){let r=new Date(t.timestamp).toLocaleTimeString(),o=this.expandedIdx===s;return a`
868
+ `}};u([L()],lt.prototype,"value",2),u([L()],lt.prototype,"label",2),u([L()],lt.prototype,"color",2),lt=u([S("bk-stat-card")],lt);var st=class extends Event{constructor(s,t,e,r){super("context-request",{bubbles:true,composed:true}),this.context=s,this.contextTarget=t,this.callback=e,this.subscribe=r??false;}};var _t=class{constructor(s,t,e,r){if(this.subscribe=false,this.provided=false,this.value=void 0,this.t=(i,n)=>{this.unsubscribe&&(this.unsubscribe!==n&&(this.provided=false,this.unsubscribe()),this.subscribe||this.unsubscribe()),this.value=i,this.host.requestUpdate(),this.provided&&!this.subscribe||(this.provided=true,this.callback&&this.callback(i,n)),this.unsubscribe=n;},this.host=s,t.context!==void 0){let i=t;this.context=i.context,this.callback=i.callback,this.subscribe=i.subscribe??false;}else this.context=t,this.callback=e,this.subscribe=r??false;this.host.addController(this);}hostConnected(){this.dispatchRequest();}hostDisconnected(){this.unsubscribe&&(this.unsubscribe(),this.unsubscribe=void 0);}dispatchRequest(){this.host.dispatchEvent(new st(this.context,this.host,this.t,this.subscribe));}};var he=class{get value(){return this.o}set value(s){this.setValue(s);}setValue(s,t=false){let e=t||!Object.is(s,this.o);this.o=s,e&&this.updateObservers();}constructor(s){this.subscriptions=new Map,this.updateObservers=()=>{for(let[t,{disposer:e}]of this.subscriptions)t(this.o,e);},s!==void 0&&(this.value=s);}addCallback(s,t,e){if(!e)return void s(this.value);this.subscriptions.has(s)||this.subscriptions.set(s,{disposer:()=>{this.subscriptions.delete(s);},consumerHost:t});let{disposer:r}=this.subscriptions.get(s);s(this.value,r);}clearCallbacks(){this.subscriptions.clear();}};var Ge=class extends Event{constructor(s,t){super("context-provider",{bubbles:true,composed:true}),this.context=s,this.contextTarget=t;}},$t=class extends he{constructor(s,t,e){super(t.context!==void 0?t.initialValue:e),this.onContextRequest=r=>{if(r.context!==this.context)return;let i=r.contextTarget??r.composedPath()[0];i!==this.host&&(r.stopPropagation(),this.addCallback(r.callback,i,r.subscribe));},this.onProviderRequest=r=>{if(r.context!==this.context||(r.contextTarget??r.composedPath()[0])===this.host)return;let i=new Set;for(let[n,{consumerHost:l}]of this.subscriptions)i.has(n)||(i.add(n),l.dispatchEvent(new st(this.context,l,n,true)));r.stopPropagation();},this.host=s,t.context!==void 0?this.context=t.context:this.context=t,this.attachListeners(),this.host.addController?.(this);}attachListeners(){this.host.addEventListener("context-request",this.onContextRequest),this.host.addEventListener("context-provider",this.onProviderRequest);}hostConnected(){this.host.dispatchEvent(new Ge(this.context,this.host));}};function Be({context:o}){return (s,t)=>{let e=new WeakMap;if(typeof t=="object")return {get(){return s.get.call(this)},set(r){return e.get(this).setValue(r),s.set.call(this,r)},init(r){return e.set(this,new $t(this,{context:o,initialValue:r})),r}};{s.constructor.addInitializer((n=>{e.set(n,new $t(n,{context:o}));}));let r=Object.getOwnPropertyDescriptor(s,t),i;if(r===void 0){let n=new WeakMap;i={get(){return n.get(this)},set(l){e.get(this).setValue(l),n.set(this,l);},configurable:true,enumerable:true};}else {let n=r.set;i={...r,set(l){e.get(this).setValue(l),n?.call(this,l);}};}return void Object.defineProperty(s,t,i)}}}function I({context:o,subscribe:s}){return (t,e)=>{typeof e=="object"?e.addInitializer((function(){new _t(this,{context:o,callback:r=>{t.set.call(this,r);},subscribe:s});})):t.constructor.addInitializer((r=>{new _t(r,{context:o,callback:i=>{r[e]=i;},subscribe:s});}));}}var A="dashboard-store",ue=class extends EventTarget{constructor(){super(...arguments);this._state={flows:[],requests:[],fetches:[],errors:[],logs:[],queries:[],issues:[],metrics:[],viewMode:"simple",activeView:"overview"};}get state(){return this._state}setFlows(t){this._state={...this._state,flows:t},this.notify("flows");}setRequests(t){this._state={...this._state,requests:t},this.notify("requests");}setFetches(t){this._state={...this._state,fetches:t},this.notify("fetches");}setErrors(t){this._state={...this._state,errors:t},this.notify("errors");}setLogs(t){this._state={...this._state,logs:t},this.notify("logs");}setQueries(t){this._state={...this._state,queries:t},this.notify("queries");}setIssues(t){this._state={...this._state,issues:t},this.notify("issues");}setMetrics(t){this._state={...this._state,metrics:t},this.notify("metrics");}prependRequest(t){let e=[t,...this._state.requests.slice(0,999)];this._state={...this._state,requests:e},this.notify("requests");}prependFetch(t){let e=[t,...this._state.fetches.slice(0,999)];this._state={...this._state,fetches:e},this.notify("fetches");}prependError(t){let e=[t,...this._state.errors.slice(0,999)];this._state={...this._state,errors:e},this.notify("errors");}prependLog(t){let e=[t,...this._state.logs.slice(0,999)];this._state={...this._state,logs:e},this.notify("logs");}prependQuery(t){let e=[t,...this._state.queries.slice(0,999)];this._state={...this._state,queries:e},this.notify("queries");}setActiveView(t){this._state={...this._state,activeView:t},this.notify("activeView");}setViewMode(t){this._state={...this._state,viewMode:t},this.notify("viewMode");}clearAll(){this._state={...this._state,flows:[],requests:[],fetches:[],errors:[],logs:[],queries:[],issues:[],metrics:[]},this.notify("all");}notify(t){this.dispatchEvent(new CustomEvent("state-changed",{detail:t}));}};var xt=class extends E{constructor(){super(...arguments);this.expandedIdx=-1;}createRenderRoot(){return this}connectedCallback(){super.connectedCallback(),this.store.addEventListener("state-changed",()=>this.requestUpdate());}toggleError(t){this.expandedIdx=this.expandedIdx===t?-1:t;}renderErrorRow(t,e){let r=new Date(t.timestamp).toLocaleTimeString(),i=this.expandedIdx===e;return a`
765
869
  <div
766
- class="req-row tel-clickable ${o?"expanded":""}"
767
- @click=${()=>this.toggleError(s)}
870
+ class="req-row tel-clickable ${i?"expanded":""}"
871
+ @click=${()=>this.toggleError(e)}
768
872
  >
769
873
  <span class="tel-error-name" title=${t.name}>${t.name}</span>
770
874
  <span class="tel-message" title=${t.message}>${t.message}</span>
771
875
  <span class="tel-timestamp">${r}</span>
772
876
  </div>
773
- ${o&&t.stack?a`<div class="error-stack">${t.stack}</div>`:d}
877
+ ${i&&t.stack?a`<div class="error-stack">${t.stack}</div>`:p}
774
878
  `}render(){let t=this.store.state.errors;return t.length===0?a`<bk-empty-state
775
879
  title="No errors"
776
880
  subtitle="No errors have been captured yet"
@@ -781,54 +885,54 @@ span.perf-breakdown-dot.perf-breakdown-app{background:var(--breakdown-app)}
781
885
  <span style="width:130px;text-align:right">Time</span>
782
886
  </div>
783
887
  <div id="error-list">
784
- ${t.map((s,r)=>this.renderErrorRow(s,r))}
888
+ ${t.map((e,r)=>this.renderErrorRow(e,r))}
785
889
  </div>
786
- `}};u([R({context:x})],at.prototype,"store",2),u([_()],at.prototype,"expandedIdx",2),at=u([g("bk-errors-view")],at);var wt=class extends f{createRenderRoot(){return this}connectedCallback(){super.connectedCallback(),this.store.addEventListener("state-changed",()=>this.requestUpdate());}renderAnalysis(e){if(e.length===0)return d;let t={error:0,warn:0,info:0,debug:0,log:0};for(let s of e)t[s.level]!==void 0&&t[s.level]++;return a`
890
+ `}};u([I({context:A})],xt.prototype,"store",2),u([b()],xt.prototype,"expandedIdx",2),xt=u([S("bk-errors-view")],xt);var jt=class extends E{createRenderRoot(){return this}connectedCallback(){super.connectedCallback(),this.store.addEventListener("state-changed",()=>this.requestUpdate());}renderAnalysis(s){if(s.length===0)return p;let t={error:0,warn:0,info:0,debug:0,log:0};for(let e of s)t[e.level]!==void 0&&t[e.level]++;return a`
787
891
  <div id="log-analysis">
788
892
  <div class="fetch-summary">
789
- <bk-stat-card value=${String(e.length)} label="Total Logs"></bk-stat-card>
790
- ${t.error>0?a`<bk-stat-card value=${String(t.error)} label="Errors" color="var(--red)"></bk-stat-card>`:d}
791
- ${t.warn>0?a`<bk-stat-card value=${String(t.warn)} label="Warnings" color="var(--amber)"></bk-stat-card>`:d}
893
+ <bk-stat-card value=${String(s.length)} label="Total Logs"></bk-stat-card>
894
+ ${t.error>0?a`<bk-stat-card value=${String(t.error)} label="Errors" color="var(--red)"></bk-stat-card>`:p}
895
+ ${t.warn>0?a`<bk-stat-card value=${String(t.warn)} label="Warnings" color="var(--amber)"></bk-stat-card>`:p}
792
896
  <bk-stat-card value=${String(t.info)} label="Info"></bk-stat-card>
793
- ${t.debug>0?a`<bk-stat-card value=${String(t.debug)} label="Debug"></bk-stat-card>`:d}
794
- ${t.log>0?a`<bk-stat-card value=${String(t.log)} label="Log"></bk-stat-card>`:d}
897
+ ${t.debug>0?a`<bk-stat-card value=${String(t.debug)} label="Debug"></bk-stat-card>`:p}
898
+ ${t.log>0?a`<bk-stat-card value=${String(t.log)} label="Log"></bk-stat-card>`:p}
795
899
  </div>
796
900
  </div>
797
- `}renderLogRow(e){let t=new Date(e.timestamp).toLocaleTimeString();return a`
901
+ `}renderLogRow(s){let t=new Date(s.timestamp).toLocaleTimeString();return a`
798
902
  <div class="req-row">
799
- <span class="tel-level tel-level-${e.level}">${e.level.toUpperCase()}</span>
800
- <span class="tel-message tel-mono" title=${e.message}>${e.message}</span>
903
+ <span class="tel-level tel-level-${s.level}">${s.level.toUpperCase()}</span>
904
+ <span class="tel-message tel-mono" title=${s.message}>${s.message}</span>
801
905
  <span class="tel-timestamp">${t}</span>
802
906
  </div>
803
- `}render(){let e=this.store.state.logs;return e.length===0?a`<bk-empty-state
907
+ `}render(){let s=this.store.state.logs;return s.length===0?a`<bk-empty-state
804
908
  title="No logs"
805
909
  subtitle="No console output has been captured yet"
806
910
  ></bk-empty-state>`:a`
807
- ${this.renderAnalysis(e)}
911
+ ${this.renderAnalysis(s)}
808
912
  <div class="col-header">
809
913
  <span style="width:52px">Level</span>
810
914
  <span style="flex:1">Message</span>
811
915
  <span style="width:130px;text-align:right">Time</span>
812
916
  </div>
813
917
  <div id="log-list">
814
- ${e.map(t=>this.renderLogRow(t))}
918
+ ${s.map(t=>this.renderLogRow(t))}
815
919
  </div>
816
- `}};u([R({context:x})],wt.prototype,"store",2),wt=u([g("bk-logs-view")],wt);var Xs=new Set(["SELECT","FROM","WHERE","AND","OR","INSERT","INTO","VALUES","UPDATE","SET","DELETE","JOIN","LEFT","RIGHT","INNER","OUTER","ON","GROUP","BY","ORDER","HAVING","LIMIT","OFFSET","AS","IN","NOT","NULL","IS","LIKE","BETWEEN","EXISTS","CASE","WHEN","THEN","ELSE","END","COUNT","SUM","AVG","MIN","MAX","DISTINCT","UNION","ALL","CREATE","TABLE","ALTER","DROP","INDEX","RETURNING","WITH","RECURSIVE","OVER","PARTITION","WINDOW","FETCH","NEXT","ROWS","ONLY","CAST","COALESCE","NULLIF","EXTRACT","INTERVAL","TRUE","FALSE","ASC","DESC","USING","NATURAL","CROSS","FULL","ROLLBACK","COMMIT","BEGIN","TRANSACTION","SAVEPOINT","RELEASE"]);function ns(i){let e=i.trim().match(/^(\w+)/);return e?e[1].toUpperCase():"?"}function as(i){let e=i.replace(/\s+/g," ").trim(),t=e.match(/\bFROM\s+["'`]?(\w+)["'`]?/i);if(t)return t[1];let s=e.match(/\bINTO\s+["'`]?(\w+)["'`]?/i);if(s)return s[1];let r=e.match(/\bUPDATE\s+["'`]?(\w+)["'`]?/i);return r?r[1]:""}function ls(i){return P(i).replace(/\b\w+\b/g,e=>Xs.has(e.toUpperCase())?'<span class="sql-kw">'+e+"</span>":e)}var lt=class extends f{constructor(){super(...arguments);this.expandedIdx=-1;}createRenderRoot(){return this}connectedCallback(){super.connectedCallback(),this.store.addEventListener("state-changed",()=>this.requestUpdate());}toggleQuery(t){this.expandedIdx=this.expandedIdx===t?-1:t;}queryDuration(t){return t===0?"<1ms":v(t)}getQueryInfo(t){let s=(t.normalizedOp||t.operation||(t.sql?ns(t.sql):"?")).toUpperCase(),r=t.table||t.model||(t.sql?as(t.sql):""),o=t.sql||s+" "+r;return {op:s,table:r,sqlText:o}}renderQueryRow(t,s){let{op:r,table:o,sqlText:n}=this.getQueryInfo(t),l=Ft[r]||"var(--text-dim)",c=t.durationMs>de,p=t.sql||r+" "+o,h=this.expandedIdx===s;return a`
920
+ `}};u([I({context:A})],jt.prototype,"store",2),jt=u([S("bk-logs-view")],jt);var Ps={CHILD:2},qs=o=>(...s)=>({_$litDirective$:o,values:s}),me=class{constructor(s){}get _$AU(){return this._$AM._$AU}_$AT(s,t,e){this._$Ct=s,this._$AM=t,this._$Ci=e;}_$AS(s,t){return this.update(s,t)}update(s,t){return this.render(...t)}};var Yt=class extends me{constructor(s){if(super(s),this.it=p,s.type!==Ps.CHILD)throw Error(this.constructor.directiveName+"() can only be used in child bindings")}render(s){if(s===p||s==null)return this._t=void 0,this.it=s;if(s===Y)return s;if(typeof s!="string")throw Error(this.constructor.directiveName+"() called with a non-string value");if(s===this.it)return this._t;this.it=s;let t=[s];return t.raw=t,this._t={_$litType$:this.constructor.resultType,strings:t,values:[]}}};Yt.directiveName="unsafeHTML",Yt.resultType=1;var U=qs(Yt);var Vr=new Set(["SELECT","FROM","WHERE","AND","OR","INSERT","INTO","VALUES","UPDATE","SET","DELETE","JOIN","LEFT","RIGHT","INNER","OUTER","ON","GROUP","BY","ORDER","HAVING","LIMIT","OFFSET","AS","IN","NOT","NULL","IS","LIKE","BETWEEN","EXISTS","CASE","WHEN","THEN","ELSE","END","COUNT","SUM","AVG","MIN","MAX","DISTINCT","UNION","ALL","CREATE","TABLE","ALTER","DROP","INDEX","RETURNING","WITH","RECURSIVE","OVER","PARTITION","WINDOW","FETCH","NEXT","ROWS","ONLY","CAST","COALESCE","NULLIF","EXTRACT","INTERVAL","TRUE","FALSE","ASC","DESC","USING","NATURAL","CROSS","FULL","ROLLBACK","COMMIT","BEGIN","TRANSACTION","SAVEPOINT","RELEASE"]);function Us(o){let s=o.trimStart().split(/\s/)[0];return s?s.toUpperCase():"?"}function Fs(o){let s=o.replace(/\s+/g," ").trim(),t=s.match(/\bFROM\s+["'`]?(\w+)["'`]?/i);if(t)return t[1];let e=s.match(/\bINTO\s+["'`]?(\w+)["'`]?/i);if(e)return e[1];let r=s.match(/\bUPDATE\s+["'`]?(\w+)["'`]?/i);return r?r[1]:""}function Gs(o){return tt(o).replace(/\b\w+\b/g,s=>Vr.has(s.toUpperCase())?'<span class="sql-kw">'+s+"</span>":s)}var St=class extends E{constructor(){super(...arguments);this.expandedIdx=-1;}createRenderRoot(){return this}connectedCallback(){super.connectedCallback(),this.store.addEventListener("state-changed",()=>this.requestUpdate());}toggleQuery(t){this.expandedIdx=this.expandedIdx===t?-1:t;}queryDuration(t){return t===0?"<1ms":_(t)}getQueryInfo(t){let e=(t.normalizedOp||t.operation||(t.sql?Us(t.sql):"?")).toUpperCase(),r=t.table||t.model||(t.sql?Fs(t.sql):""),i=t.sql||e+" "+r;return {op:e,table:r,sqlText:i}}renderQueryRow(t,e){let{op:r,table:i,sqlText:n}=this.getQueryInfo(t),l=pe[r]||"var(--text-dim)",c=t.durationMs>Oe,d=t.sql||r+" "+i,h=this.expandedIdx===e;return a`
817
921
  <div>
818
922
  <div
819
923
  class="req-row query-row tel-clickable ${h?"expanded":""}"
820
- @click=${()=>this.toggleQuery(s)}
924
+ @click=${()=>this.toggleQuery(e)}
821
925
  >
822
926
  <span class="query-op" title=${r} style="color:${l}">${r}</span>
823
- <span class="query-table" title=${o}>${o}</span>
824
- <span class="query-preview" title=${p}>${p}</span>
927
+ <span class="query-table" title=${i}>${i}</span>
928
+ <span class="query-preview" title=${d}>${d}</span>
825
929
  <span class="query-dur${c?" query-slow":""}">${this.queryDuration(t.durationMs)}</span>
826
930
  </div>
827
931
  <div class="query-detail ${h?"open":""}">
828
932
  ${h?a`
829
- <pre class="query-detail-sql" .innerHTML=${ls(n)}></pre>
933
+ <pre class="query-detail-sql">${U(Gs(n))}</pre>
830
934
  <bk-copy-button .text=${n} label="Copy"></bk-copy-button>
831
- `:d}
935
+ `:p}
832
936
  </div>
833
937
  </div>
834
938
  `}render(){let t=this.store.state.queries;return t.length===0?a`<bk-empty-state
@@ -842,37 +946,37 @@ span.perf-breakdown-dot.perf-breakdown-app{background:var(--breakdown-app)}
842
946
  <span style="width:60px;text-align:right">Time</span>
843
947
  </div>
844
948
  <div id="query-list">
845
- ${t.map((s,r)=>this.renderQueryRow(s,r))}
949
+ ${t.map((e,r)=>this.renderQueryRow(e,r))}
846
950
  </div>
847
- `}};u([R({context:x})],lt.prototype,"store",2),u([_()],lt.prototype,"expandedIdx",2),lt=u([g("bk-queries-view")],lt);function be(i){return i.replace(/'/g,"'\\''")}function Ks(i,e){let t=Object.entries(i.headers||{}).filter(([o])=>!os.has(o)).map(([o,n])=>`-H '${be(o)}: ${be(n)}'`).join(" "),s=i.requestBody?` -d '${be(i.requestBody)}'`:"",r=e?`http://localhost:${e}`:"";return `curl -X ${i.method} ${t}${s} '${r}${i.url}'`}function ct(i){let e=window.__BRAKIT_CONFIG__?.port??"",t=Ks(i,e);navigator.clipboard.writeText(t).then(()=>C.show("Copied cURL command"));}var dt=class extends f{constructor(){super(...arguments);this.expandedId=null;}createRenderRoot(){return this}connectedCallback(){super.connectedCallback(),this.store.addEventListener("state-changed",()=>this.requestUpdate());}toggleRequest(t){this.expandedId=this.expandedId===t?null:t;}handleCopyAsCurl(t,s){s.stopPropagation(),ct(t);}renderDetail(t){return a`
951
+ `}};u([I({context:A})],St.prototype,"store",2),u([b()],St.prototype,"expandedIdx",2),St=u([S("bk-queries-view")],St);function We(o){return o.replaceAll("'","'\\''")}function Kr(o,s){let t=Object.entries(o.headers||{}).filter(([i])=>!Ds.has(i)).map(([i,n])=>`-H '${We(i)}: ${We(n)}'`).join(" "),e=o.requestBody?` -d '${We(o.requestBody)}'`:"",r=s?`http://localhost:${s}`:"";return `curl -X ${o.method} ${t}${e} '${r}${o.url}'`}function Tt(o){let s=window.__BRAKIT_CONFIG__?.port??"",t=Kr(o,s);navigator.clipboard.writeText(t).then(()=>D.show("Copied cURL command"));}var wt=class extends E{constructor(){super(...arguments);this.expandedId=null;}createRenderRoot(){return this}connectedCallback(){super.connectedCallback(),this.store.addEventListener("state-changed",()=>this.requestUpdate());}toggleRequest(t){this.expandedId=this.expandedId===t?null:t;}handleCopyAsCurl(t,e){e.stopPropagation(),Tt(t);}renderDetail(t){return a`
848
952
  <div class="detail-meta">
849
953
  <span><bk-method-badge .method=${t.method}></bk-method-badge> ${t.url}</span>
850
954
  <span><bk-status-pill .code=${t.statusCode}></bk-status-pill></span>
851
955
  <span>${t.durationMs}ms</span>
852
- ${t.responseSize?a`<span>${U(t.responseSize)}</span>`:d}
956
+ ${t.responseSize?a`<span>${et(t.responseSize)}</span>`:p}
853
957
  </div>
854
958
  <div class="request-timeline tl-hidden" data-request-id=${t.id} data-request-started=${String(t.startedAt)}></div>
855
959
  <div class="detail-grid">
856
- <div class="detail-section"><h4>Request Headers</h4><pre .innerHTML=${rt(t.headers)}></pre></div>
857
- <div class="detail-section"><h4>Response Headers</h4><pre .innerHTML=${rt(t.responseHeaders)}></pre></div>
858
- <div class="detail-section"><h4>Request Body</h4><pre .innerHTML=${Q(t.requestBody)}></pre></div>
859
- <div class="detail-section"><h4>Response Body</h4><pre .innerHTML=${Q(t.responseBody)}></pre></div>
960
+ <div class="detail-section"><h4>Request Headers</h4><pre>${U(Et(t.headers))}</pre></div>
961
+ <div class="detail-section"><h4>Response Headers</h4><pre>${U(Et(t.responseHeaders))}</pre></div>
962
+ <div class="detail-section"><h4>Request Body</h4><pre>${U(nt(t.requestBody))}</pre></div>
963
+ <div class="detail-section"><h4>Response Body</h4><pre>${U(nt(t.responseBody))}</pre></div>
860
964
  </div>
861
965
  <div class="detail-actions">
862
- <button class="btn btn-curl" @click=${s=>this.handleCopyAsCurl(t,s)}>Copy cURL</button>
966
+ <button class="btn btn-curl" @click=${e=>this.handleCopyAsCurl(t,e)}>Copy cURL</button>
863
967
  </div>
864
- `}renderRequestRow(t){let s=this.expandedId===t.id;return a`
865
- <div class="req-row ${s?"expanded":""}" @click=${()=>this.toggleRequest(t.id)}>
968
+ `}renderRequestRow(t){let e=this.expandedId===t.id;return a`
969
+ <div class="req-row ${e?"expanded":""}" @click=${()=>this.toggleRequest(t.id)}>
866
970
  <div class="req-summary">
867
971
  <bk-method-badge .method=${t.method}></bk-method-badge>
868
972
  <span class="req-url">${t.url}</span>
869
973
  <bk-status-pill .code=${t.statusCode}></bk-status-pill>
870
974
  <bk-duration-label .ms=${t.durationMs}></bk-duration-label>
871
- <span class="req-size">${U(t.responseSize)}</span>
975
+ <span class="req-size">${et(t.responseSize)}</span>
872
976
  </div>
873
977
  </div>
874
- <div class="req-detail ${s?"open":""}">${s?this.renderDetail(t):d}</div>
875
- `}render(){let t=this.store.state.requests.filter(s=>!s.path?.startsWith(N));return t.length===0?a`<bk-empty-state title="No requests" subtitle="No HTTP requests have been captured yet"></bk-empty-state>`:a`
978
+ <div class="req-detail ${e?"open":""}">${e?this.renderDetail(t):p}</div>
979
+ `}render(){let t=this.store.state.requests.filter(e=>!e.path?.startsWith(F));return t.length===0?a`<bk-empty-state title="No requests" subtitle="No HTTP requests have been captured yet"></bk-empty-state>`:a`
876
980
  <div class="col-header">
877
981
  <span style="width:60px">Method</span>
878
982
  <span style="flex:1">URL</span>
@@ -880,51 +984,51 @@ span.perf-breakdown-dot.perf-breakdown-app{background:var(--breakdown-app)}
880
984
  <span style="width:70px;text-align:right">Time</span>
881
985
  <span style="width:60px;text-align:right">Size</span>
882
986
  </div>
883
- <div id="request-list">${t.map(s=>this.renderRequestRow(s))}</div>
884
- `}};u([R({context:x})],dt.prototype,"store",2),u([_()],dt.prototype,"expandedId",2),dt=u([g("bk-requests-view")],dt);var At=class extends f{createRenderRoot(){return this}connectedCallback(){super.connectedCallback(),this.store.addEventListener("state-changed",()=>this.requestUpdate());}buildGroups(e,t){let s=new Map;for(let o of t)s.set(o.id,o);let r={};for(let o of e){let n=o.method+" "+o.url;r[n]||(r[n]={method:o.method,url:o.url,count:0,totalDur:0,maxDur:0,errors:0,callers:{},statusCodes:{},firstTs:o.timestamp,lastTs:o.timestamp});let l=r[n];if(l.count++,l.totalDur+=o.durationMs,o.durationMs>l.maxDur&&(l.maxDur=o.durationMs),o.statusCode>=400&&l.errors++,l.statusCodes[o.statusCode]=(l.statusCodes[o.statusCode]||0)+1,o.timestamp<l.firstTs&&(l.firstTs=o.timestamp),o.timestamp>l.lastTs&&(l.lastTs=o.timestamp),o.parentRequestId){let c=s.get(o.parentRequestId);c&&(l.callers[c.method+" "+(c.path||c.url)]=1);}}return Object.values(r).sort((o,n)=>n.count-o.count)}renderSummary(e){let t=new Set,s=0,r=0;for(let n of e)t.add(n.url),n.statusCode>=400&&s++,r+=n.durationMs;let o=Math.round(r/e.length);return a`
987
+ <div id="request-list">${t.map(e=>this.renderRequestRow(e))}</div>
988
+ `}};u([I({context:A})],wt.prototype,"store",2),u([b()],wt.prototype,"expandedId",2),wt=u([S("bk-requests-view")],wt);var Xt=class extends E{createRenderRoot(){return this}connectedCallback(){super.connectedCallback(),this.store.addEventListener("state-changed",()=>this.requestUpdate());}buildGroups(s,t){let e=new Map;for(let i of t)e.set(i.id,i);let r={};for(let i of s){let n=i.method+" "+i.url;r[n]||(r[n]={method:i.method,url:i.url,count:0,totalDur:0,maxDur:0,errors:0,callers:{},statusCodes:{},firstTs:i.timestamp,lastTs:i.timestamp});let l=r[n];if(l.count++,l.totalDur+=i.durationMs,i.durationMs>l.maxDur&&(l.maxDur=i.durationMs),i.statusCode>=400&&l.errors++,l.statusCodes[i.statusCode]=(l.statusCodes[i.statusCode]||0)+1,i.timestamp<l.firstTs&&(l.firstTs=i.timestamp),i.timestamp>l.lastTs&&(l.lastTs=i.timestamp),i.parentRequestId){let c=e.get(i.parentRequestId);c&&(l.callers[c.method+" "+(c.path||c.url)]=1);}}return Object.values(r).sort((i,n)=>n.count-i.count)}renderSummary(s){let t=new Set,e=0,r=0;for(let n of s)t.add(n.url),n.statusCode>=400&&e++,r+=n.durationMs;let i=Math.round(r/s.length);return a`
885
989
  <div class="fetch-summary">
886
- <bk-stat-card value=${String(e.length)} label="Total Fetches"></bk-stat-card>
990
+ <bk-stat-card value=${String(s.length)} label="Total Fetches"></bk-stat-card>
887
991
  <bk-stat-card value=${String(t.size)} label="Unique URLs"></bk-stat-card>
888
- <bk-stat-card value=${String(s)} label="Errors" color=${s>0?"var(--red)":""}></bk-stat-card>
889
- <bk-stat-card value=${v(o)} label="Avg Duration"></bk-stat-card>
992
+ <bk-stat-card value=${String(e)} label="Errors" color=${e>0?"var(--red)":""}></bk-stat-card>
993
+ <bk-stat-card value=${_(i)} label="Avg Duration"></bk-stat-card>
890
994
  </div>
891
- `}formatTime(e){return new Date(e).toLocaleTimeString([],{hour:"2-digit",minute:"2-digit",second:"2-digit"})}renderGroup(e){let t=Math.round(e.totalDur/e.count),s=e.count>0?Math.round(e.errors/e.count*100):0,r=Object.keys(e.callers),o=Object.entries(e.statusCodes),n=o.length>0?Number(o.sort((l,c)=>c[1]-l[1])[0][0]):0;return a`
995
+ `}formatTime(s){return new Date(s).toLocaleTimeString([],{hour:"2-digit",minute:"2-digit",second:"2-digit"})}renderGroup(s){let t=Math.round(s.totalDur/s.count),e=s.count>0?Math.round(s.errors/s.count*100):0,r=Object.keys(s.callers),i=Object.entries(s.statusCodes),n=i.length>0?Number(i.sort((l,c)=>c[1]-l[1])[0][0]):0;return a`
892
996
  <div class="fetch-group">
893
997
  <div class="fetch-group-header">
894
- <bk-method-badge .method=${e.method}></bk-method-badge>
895
- <span class="fetch-group-url" title=${e.url}>${e.url}</span>
896
- ${n>0?a`<bk-status-pill .code=${n}></bk-status-pill>`:d}
897
- <span class="fetch-group-count">${e.count}x</span>
998
+ <bk-method-badge .method=${s.method}></bk-method-badge>
999
+ <span class="fetch-group-url" title=${s.url}>${s.url}</span>
1000
+ ${n>0?a`<bk-status-pill .code=${n}></bk-status-pill>`:p}
1001
+ <span class="fetch-group-count">${s.count}x</span>
898
1002
  </div>
899
1003
  <div class="fetch-group-meta">
900
- <span>avg ${v(t)}</span>
1004
+ <span>avg ${_(t)}</span>
901
1005
  <span class="fetch-group-sep">\u00b7</span>
902
- <span>max ${v(e.maxDur)}</span>
1006
+ <span>max ${_(s.maxDur)}</span>
903
1007
  <span class="fetch-group-sep">\u00b7</span>
904
- ${s>0?a`<span class="fetch-group-err">${s}% errors</span>`:a`<span class="fetch-group-ok">0% errors</span>`}
1008
+ ${e>0?a`<span class="fetch-group-err">${e}% errors</span>`:a`<span class="fetch-group-ok">0% errors</span>`}
905
1009
  </div>
906
- ${e.firstTs>0?a`
1010
+ ${s.firstTs>0?a`
907
1011
  <div class="fetch-group-timeline">
908
1012
  <span class="fetch-group-timeline-dot"></span>
909
1013
  <span class="fetch-group-timeline-range">
910
- ${this.formatTime(e.firstTs)}${e.firstTs!==e.lastTs?a` \u2192 ${this.formatTime(e.lastTs)}`:d}
1014
+ ${this.formatTime(s.firstTs)}${s.firstTs!==s.lastTs?a` \u2192 ${this.formatTime(s.lastTs)}`:p}
911
1015
  </span>
912
- </div>`:d}
1016
+ </div>`:p}
913
1017
  ${r.length>0?a`
914
1018
  <div class="fetch-group-callers">
915
1019
  <span class="fetch-group-callers-label">Called by</span>
916
1020
  ${r.map(l=>a`<span class="fetch-group-caller-pill">${l}</span>`)}
917
- </div>`:d}
1021
+ </div>`:p}
918
1022
  </div>
919
- `}render(){let e=this.store.state.fetches,t=this.store.state.requests;if(e.length===0)return a`<bk-empty-state title="No fetches" subtitle="No outbound HTTP calls have been captured yet"></bk-empty-state>`;let s=this.buildGroups(e,t);return a`
1023
+ `}render(){let s=this.store.state.fetches,t=this.store.state.requests;if(s.length===0)return a`<bk-empty-state title="No fetches" subtitle="No outbound HTTP calls have been captured yet"></bk-empty-state>`;let e=this.buildGroups(s,t);return a`
920
1024
  <div class="fetch-analysis" id="fetch-analysis">
921
- ${this.renderSummary(e)}
922
- ${s.length>0?a`
923
- <div class="fetch-groups-title">Grouped by URL (${s.length})</div>
924
- <div class="fetch-groups">${s.map(r=>this.renderGroup(r))}</div>
925
- `:d}
1025
+ ${this.renderSummary(s)}
1026
+ ${e.length>0?a`
1027
+ <div class="fetch-groups-title">Grouped by URL (${e.length})</div>
1028
+ <div class="fetch-groups">${e.map(r=>this.renderGroup(r))}</div>
1029
+ `:p}
926
1030
  </div>
927
- `}};u([R({context:x})],At.prototype,"store",2),At=u([g("bk-fetches-view")],At);function cs(i,e){if(e>=400)return "var(--red)";switch(i){case "GET":return "var(--green)";case "POST":return "var(--blue)";case "PUT":case "PATCH":return "var(--amber)";case "DELETE":return "var(--red)";default:return "var(--text-muted)"}}function _e(i){return i==="query"?"var(--accent)":"var(--cyan)"}function tr(i){return i.type==="query"||i.type==="fetch"}function er(i){let e=(i.normalizedOp||i.operation||"QUERY").toUpperCase(),t=i.table||i.model||"";return {label:`${e} ${t}`,tooltip:i.sql||`${e} ${t}`}}function sr(i){return {label:`${i.method} ${i.url}`,tooltip:`${i.method} ${i.url}`}}function rr(i,e,t,s,r,o){let n=i.data.durationMs||0,l,c;if(o){let p=Math.max(i.timestamp-s,0);l=Math.min(p/r*100,95),c=Math.max(n/r*100,1.5);}else {let p=t[0].timestamp,m=t[t.length-1].timestamp-p;l=m>0?(i.timestamp-p)/m*85:e/Math.max(t.length-1,1)*85,c=Math.max(n/r*100,1.5);}return l+c>100&&(c=Math.max(100-l,1.5)),{leftPct:l,widthPct:c}}function or(i,e){let t=i.timeline.filter(tr);if(t.length===0)return [];let s=e.startedAt,r=e.durationMs||1,o=Math.abs(t[0].timestamp-s)<r*10;return t.map((n,l)=>{let c=n.data.durationMs||0,{leftPct:p,widthPct:h}=rr(n,l,t,s,r,o),m=n.type==="query"?er(n.data):sr(n.data);return {type:n.type,label:m.label,durMs:c,durLabel:v(c),tooltip:m.tooltip,leftPct:p,widthPct:h}})}function ps(i,e){let t=i.requests.filter(l=>!l.isStrictModeDupe);if(t.length===0)return {rows:[],totalMs:0};let s=Math.min(...t.map(l=>l.startedAt)),o=Math.max(...t.map(l=>l.startedAt+l.durationMs))-s;return o===0?{rows:[],totalMs:0}:{rows:t.map(l=>{let c=(l.startedAt-s)/o*100,p=Math.max(l.durationMs/o*100,.5),h=e?.activities?.[l.id],m=h?or(h,l):[];return {label:`${l.method} ${l.label}`,leftPct:c,widthPct:p,color:cs(l.method,l.statusCode),durMs:l.durationMs,durLabel:v(l.durationMs),tooltip:`${l.method} ${l.label} (${v(l.durationMs)})`,subEvents:m}}),totalMs:o}}function us(i){let e=i.requests,t=[],s=[],r=[],o=[],n=new Map;for(let p of e){let h=p.label,m=p.pollingDurationMs||p.durationMs;if(!$t[p.category||""]){if(p.isDuplicate){let E=n.get(h);E?(E.count++,E.wastedMs+=m):n.set(h,{name:h,count:2,wastedMs:m});continue}if(p.statusCode>=400){s.push(h+" ("+is(p.statusCode)+")");continue}p.responseSize>51200&&r.push("Large response: "+h+" returned "+U(p.responseSize)),t.push(h);}}for(let p of n.values())o.push(p);let l="";if(o.length>0){let p=o.map(m=>m.name).join(", "),h=o.reduce((m,E)=>m+E.wastedMs,0);l="Your app fetches "+p+" multiple times on this page. This wastes ~"+v(h)+". Try caching these calls, deduplicating with React Query/SWR, or moving them to a shared layout.";}else s.length>0&&(l="Some requests are failing. Check your API routes and make sure the endpoints exist.");let c=e.filter(p=>p.durationMs>2e3&&p.category!==J);return c.length>0&&!l&&(l=c.map(p=>p.label).join(", ")+` is taking over ${v(2e3)}. Consider adding caching or optimizing the backend query.`),{successes:t,errors:s,warnings:r,duplicates:o,tip:l}}var L=class extends f{constructor(){super(...arguments);this.expandedFlowIdx=-1;this.expandedSubReqIdx=-1;this.flowDetailTab="insights";this.flowTimeline=null;this.flowTimelineLoading=false;}createRenderRoot(){return this}connectedCallback(){super.connectedCallback(),this.store.addEventListener("state-changed",()=>this.requestUpdate());}get flows(){return this.store.state.flows}get viewMode(){return this.store.state.viewMode}flowDotClass(t){return t.hasErrors?"dot-error":t.redundancyPct>0?"dot-warn":"dot-clean"}flowBadgeInfo(t){if(t.hasErrors){let s=t.requests.filter(r=>r.statusCode>=400).length;return {text:s+" error"+(s!==1?"s":""),cls:"badge-error"}}return t.redundancyPct>0?{text:t.redundancyPct+"% redundant",cls:"badge-warn"}:{text:"clean",cls:"badge-clean"}}toggleFlow(t){this.expandedFlowIdx===t?this.expandedFlowIdx=-1:(this.expandedFlowIdx=t,this.expandedSubReqIdx=-1,this.flowDetailTab="insights",this.flowTimeline=null);}toggleSubReq(t,s){s.stopPropagation(),this.expandedSubReqIdx=this.expandedSubReqIdx===t?-1:t;}toggleBodyBlock(t){t.stopPropagation();let s=t.currentTarget,r=s.parentElement;if(!r)return;s.classList.toggle("open");let o=r.querySelector("pre");o&&o.classList.toggle("open");}switchTab(t,s,r){r.stopPropagation(),this.flowDetailTab=t,t==="timeline"&&!this.flowTimeline&&this.loadFlowTimeline(s);}async loadFlowTimeline(t){if(this.flowTimelineLoading)return;let s=t.requests.map(r=>r.id).filter(Boolean);if(s.length!==0){this.flowTimelineLoading=true;try{let r=await fetch(`${$.activity}?requestIds=${s.join(",")}`);if(!r.ok){this.flowTimelineLoading=!1;return}this.flowTimeline=await r.json();}catch{}this.flowTimelineLoading=false;}}loadTimelineForContainer(t){let s=t.querySelectorAll(".request-timeline");for(let r of s){let o=r.getAttribute("data-request-id");if(o&&!r.hasAttribute("data-loaded")){r.setAttribute("data-loaded","1");let n=document.createElement("bk-timeline-panel");n.setAttribute("request-id",o),n.setAttribute("request-started",r.getAttribute("data-request-started")||"0"),r.appendChild(n),r.classList.remove("tl-hidden");}}}updated(){if(this.expandedFlowIdx>=0&&this.flowDetailTab==="insights"){let t=this.querySelector(".flow-expand.open");t&&this.loadTimelineForContainer(t);}}render(){let t=this.flows;return t.length===0?a`<bk-empty-state
1031
+ `}};u([I({context:A})],Xt.prototype,"store",2),Xt=u([S("bk-fetches-view")],Xt);function Bs(o,s){if(s>=400)return "var(--red)";switch(o){case "GET":return "var(--green)";case "POST":return "var(--blue)";case "PUT":case "PATCH":return "var(--amber)";case "DELETE":return "var(--red)";default:return "var(--text-muted)"}}function Qe(o){return o==="query"?"var(--accent)":"var(--cyan)"}function ti(o){return o.type==="query"||o.type==="fetch"}function ei(o){let s=(o.normalizedOp||o.operation||"QUERY").toUpperCase(),t=o.table||o.model||"";return {label:`${s} ${t}`,tooltip:o.sql||`${s} ${t}`}}function si(o){return {label:`${o.method} ${o.url}`,tooltip:`${o.method} ${o.url}`}}function ri(o,s,t,e,r,i){let n=o.data.durationMs||0,l,c;if(i){let d=Math.max(o.timestamp-e,0);l=Math.min(d/r*100,95),c=Math.max(n/r*100,1.5);}else {let d=t[0].timestamp,m=t[t.length-1].timestamp-d;l=m>0?(o.timestamp-d)/m*85:s/Math.max(t.length-1,1)*85,c=Math.max(n/r*100,1.5);}return l+c>100&&(c=Math.max(100-l,1.5)),{leftPct:l,widthPct:c}}function ii(o,s){let t=o.timeline.filter(ti);if(t.length===0)return [];let e=s.startedAt,r=s.durationMs||1,i=Math.abs(t[0].timestamp-e)<r*10;return t.map((n,l)=>{let c=n.data.durationMs||0,{leftPct:d,widthPct:h}=ri(n,l,t,e,r,i),m=n.type==="query"?ei(n.data):si(n.data);return {type:n.type,label:m.label,durMs:c,durLabel:_(c),tooltip:m.tooltip,leftPct:d,widthPct:h}})}function Qs(o,s){let t=o.requests.filter(l=>!l.isStrictModeDupe);if(t.length===0)return {rows:[],totalMs:0};let e=Math.min(...t.map(l=>l.startedAt)),i=Math.max(...t.map(l=>l.startedAt+l.durationMs))-e;return i===0?{rows:[],totalMs:0}:{rows:t.map(l=>{let c=(l.startedAt-e)/i*100,d=Math.max(l.durationMs/i*100,.5),h=s?.activities?.[l.id],m=h?ii(h,l):[];return {label:`${l.method} ${l.label}`,leftPct:c,widthPct:d,color:Bs(l.method,l.statusCode),durMs:l.durationMs,durLabel:_(l.durationMs),tooltip:`${l.method} ${l.label} (${_(l.durationMs)})`,subEvents:m}}),totalMs:i}}function js(o){let s=o.requests,t=[],e=[],r=[],i=[],n=new Map;for(let d of s){let h=d.label,m=d.pollingDurationMs||d.durationMs;if(!Gt[d.category||""]){if(d.isDuplicate){let v=n.get(h);v?(v.count++,v.wastedMs+=m):n.set(h,{name:h,count:2,wastedMs:m});continue}if(d.statusCode>=400){e.push(h+" ("+Hs(d.statusCode)+")");continue}d.responseSize>51200&&r.push("Large response: "+h+" returned "+et(d.responseSize)),t.push(h);}}for(let d of n.values())i.push(d);let l="";if(i.length>0){let d=i.map(m=>m.name).join(", "),h=i.reduce((m,v)=>m+v.wastedMs,0);l="Your app fetches "+d+" multiple times on this page. This wastes ~"+_(h)+". Try caching these calls, deduplicating with React Query/SWR, or moving them to a shared layout.";}else e.length>0&&(l="Some requests are failing. Check your API routes and make sure the endpoints exist.");let c=s.filter(d=>d.durationMs>2e3&&d.category!==ut);return c.length>0&&!l&&(l=c.map(d=>d.label).join(", ")+` is taking over ${_(2e3)}. Consider adding caching or optimizing the backend query.`),{successes:t,errors:e,warnings:r,duplicates:i,tip:l}}var W=class extends E{constructor(){super(...arguments);this.expandedFlowIdx=-1;this.expandedSubReqIdx=-1;this.flowDetailTab="insights";this.flowTimeline=null;this.flowTimelineLoading=false;}createRenderRoot(){return this}connectedCallback(){super.connectedCallback(),this.store.addEventListener("state-changed",()=>this.requestUpdate());}get flows(){return this.store.state.flows}get viewMode(){return this.store.state.viewMode}flowDotClass(t){return t.hasErrors?"dot-error":t.redundancyPct>0?"dot-warn":"dot-clean"}flowBadgeInfo(t){if(t.hasErrors){let e=t.requests.filter(r=>r.statusCode>=400).length;return {text:e+" error"+(e!==1?"s":""),cls:"badge-error"}}return t.redundancyPct>0?{text:t.redundancyPct+"% redundant",cls:"badge-warn"}:{text:"clean",cls:"badge-clean"}}toggleFlow(t){this.expandedFlowIdx===t?this.expandedFlowIdx=-1:(this.expandedFlowIdx=t,this.expandedSubReqIdx=-1,this.flowDetailTab="insights",this.flowTimeline=null);}toggleSubReq(t,e){e.stopPropagation(),this.expandedSubReqIdx=this.expandedSubReqIdx===t?-1:t;}toggleBodyBlock(t){t.stopPropagation();let e=t.currentTarget,r=e.parentElement;if(!r)return;e.classList.toggle("open");let i=r.querySelector("pre");i&&i.classList.toggle("open");}switchTab(t,e,r){r.stopPropagation(),this.flowDetailTab=t,t==="timeline"&&!this.flowTimeline&&this.loadFlowTimeline(e);}async loadFlowTimeline(t){if(this.flowTimelineLoading)return;let e=t.requests.map(r=>r.id).filter(Boolean);if(e.length!==0){this.flowTimelineLoading=true;try{let r=await fetch(`${w.activity}?requestIds=${e.join(",")}`);if(!r.ok){this.flowTimelineLoading=!1;return}this.flowTimeline=await r.json();}catch{}this.flowTimelineLoading=false;}}loadTimelineForContainer(t){let e=t.querySelectorAll(".request-timeline");for(let r of e){let i=r.getAttribute("data-request-id");if(i&&!r.hasAttribute("data-loaded")){r.setAttribute("data-loaded","1");let n=document.createElement("bk-timeline-panel");n.setAttribute("request-id",i),n.setAttribute("request-started",r.getAttribute("data-request-started")||"0"),r.appendChild(n),r.classList.remove("tl-hidden");}}}updated(){if(this.expandedFlowIdx>=0&&this.flowDetailTab==="insights"){let t=this.querySelector(".flow-expand.open");t&&this.loadTimelineForContainer(t);}}render(){let t=this.flows;return t.length===0?a`<bk-empty-state
928
1032
  title="No actions yet"
929
1033
  subtitle="Start using your app to see user action flows here"
930
1034
  ></bk-empty-state>`:a`
@@ -936,15 +1040,15 @@ span.perf-breakdown-dot.perf-breakdown-app{background:var(--breakdown-app)}
936
1040
  <span style="width:70px;text-align:right">Time</span>
937
1041
  </div>
938
1042
  <div id="flow-list">
939
- ${t.map((s,r)=>this.renderFlowRow(s,r))}
1043
+ ${t.map((e,r)=>this.renderFlowRow(e,r))}
940
1044
  </div>
941
- `}renderFlowRow(t,s){let r=this.expandedFlowIdx===s,o=this.flowDotClass(t),n=this.flowBadgeInfo(t);return a`
1045
+ `}renderFlowRow(t,e){let r=this.expandedFlowIdx===e,i=this.flowDotClass(t),n=this.flowBadgeInfo(t);return a`
942
1046
  <div
943
1047
  class="flow-row ${r?"expanded":""}"
944
- @click=${()=>this.toggleFlow(s)}
1048
+ @click=${()=>this.toggleFlow(e)}
945
1049
  >
946
1050
  <div class="flow-summary-row">
947
- <span class="flow-status-dot ${o}"></span>
1051
+ <span class="flow-status-dot ${i}"></span>
948
1052
  <span class="flow-label">${t.label}</span>
949
1053
  <span class="flow-req-count"
950
1054
  >${t.requests.length}
@@ -952,20 +1056,20 @@ span.perf-breakdown-dot.perf-breakdown-app{background:var(--breakdown-app)}
952
1056
  >
953
1057
  <span class="flow-badge-pill ${n.cls}">${n.text}</span>
954
1058
  <span class="flow-duration"
955
- >${v(t.totalDurationMs)}</span
1059
+ >${_(t.totalDurationMs)}</span
956
1060
  >
957
1061
  </div>
958
1062
  </div>
959
1063
  <div class="flow-expand ${r?"open":""}">
960
- ${r?this.renderFlowDetail(t):d}
1064
+ ${r?this.renderFlowDetail(t):p}
961
1065
  </div>
962
- `}renderFlowDetail(t){let s=this.viewMode==="simple"?"Insights":"Details";return a`
1066
+ `}renderFlowDetail(t){let e=this.viewMode==="simple"?"Insights":"Details";return a`
963
1067
  <div class="flow-detail-tabs">
964
1068
  <button
965
1069
  class="flow-tab ${this.flowDetailTab==="insights"?"active":""}"
966
1070
  @click=${r=>this.switchTab("insights",t,r)}
967
1071
  >
968
- ${s}
1072
+ ${e}
969
1073
  </button>
970
1074
  <button
971
1075
  class="flow-tab ${this.flowDetailTab==="timeline"?"active":""}"
@@ -975,13 +1079,13 @@ span.perf-breakdown-dot.perf-breakdown-app{background:var(--breakdown-app)}
975
1079
  </button>
976
1080
  </div>
977
1081
  ${this.flowDetailTab==="insights"?this.viewMode==="simple"?this.renderFlowInsights(t):this.renderFlowSubReqs(t):this.renderFlowWaterfall(t)}
978
- `}renderFlowWaterfall(t){if(this.flowTimelineLoading)return a`<div class="wf-loading">Loading timeline...</div>`;let{rows:s,totalMs:r}=ps(t,this.flowTimeline);if(s.length===0)return d;let o=[];for(let n=0;n<=5;n++)o.push(v(r/5*n));return a`
1082
+ `}renderFlowWaterfall(t){if(this.flowTimelineLoading)return a`<div class="wf-loading">Loading timeline...</div>`;let{rows:e,totalMs:r}=Qs(t,this.flowTimeline);if(e.length===0)return p;let i=[];for(let n=0;n<=5;n++)i.push(_(r/5*n));return a`
979
1083
  <div class="flow-waterfall">
980
1084
  <div class="wf-time-axis">
981
- ${o.map(n=>a`<span>${n}</span>`)}
1085
+ ${i.map(n=>a`<span>${n}</span>`)}
982
1086
  </div>
983
1087
  <div class="wf-rows">
984
- ${s.map(n=>this.renderWaterfallGroup(n))}
1088
+ ${e.map(n=>this.renderWaterfallGroup(n))}
985
1089
  </div>
986
1090
  </div>
987
1091
  `}renderWaterfallGroup(t){return a`
@@ -996,109 +1100,109 @@ span.perf-breakdown-dot.perf-breakdown-app{background:var(--breakdown-app)}
996
1100
  </div>
997
1101
  <div class="wf-req-dur">${t.durLabel}</div>
998
1102
  </div>
999
- ${t.subEvents.length>0?t.subEvents.map(s=>a`
1000
- <div class="wf-sub-row" title="${s.tooltip}">
1103
+ ${t.subEvents.length>0?t.subEvents.map(e=>a`
1104
+ <div class="wf-sub-row" title="${e.tooltip}">
1001
1105
  <div class="wf-sub-label">
1002
1106
  <span
1003
1107
  class="wf-sub-dot"
1004
- style="background:${_e(s.type)}"
1108
+ style="background:${Qe(e.type)}"
1005
1109
  ></span>
1006
- ${s.label}
1110
+ ${e.label}
1007
1111
  </div>
1008
1112
  <div class="wf-bar-track">
1009
1113
  <div
1010
1114
  class="wf-bar wf-sub-bar-sized"
1011
- style="left:${t.leftPct+s.leftPct/100*t.widthPct}%;width:${s.widthPct/100*t.widthPct}%;background:${_e(s.type)}"
1115
+ style="left:${t.leftPct+e.leftPct/100*t.widthPct}%;width:${e.widthPct/100*t.widthPct}%;background:${Qe(e.type)}"
1012
1116
  ></div>
1013
1117
  </div>
1014
- <div class="wf-sub-dur">${s.durLabel}</div>
1118
+ <div class="wf-sub-dur">${e.durLabel}</div>
1015
1119
  </div>
1016
- `):d}
1120
+ `):p}
1017
1121
  </div>
1018
- `}renderFlowInsights(t){let s=us(t),r=s.errors.length>0||s.duplicates.length>0||s.warnings.length>0||!!s.tip;return a`
1122
+ `}renderFlowInsights(t){let e=js(t),r=e.errors.length>0||e.duplicates.length>0||e.warnings.length>0||!!e.tip;return a`
1019
1123
  <div>
1020
1124
  <div class="flow-traffic">
1021
- ${t.requests.map(o=>this.renderTrafficCard(o))}
1125
+ ${t.requests.map(i=>this.renderTrafficCard(i))}
1022
1126
  </div>
1023
1127
  ${r?a`
1024
1128
  <div class="flow-divider"></div>
1025
1129
  <div class="flow-insights">
1026
- ${s.errors.map(o=>a`<div class="insight-line insight-error">
1027
- ✗ ${o}
1130
+ ${e.errors.map(i=>a`<div class="insight-line insight-error">
1131
+ ✗ ${i}
1028
1132
  </div>`)}
1029
- ${s.duplicates.map(o=>a`<div class="insight-line insight-warn">
1030
- ⚠ ${o.name} — loaded ${o.count}x (wasting
1031
- ~${v(o.wastedMs)})
1133
+ ${e.duplicates.map(i=>a`<div class="insight-line insight-warn">
1134
+ ⚠ ${i.name} — loaded ${i.count}x (wasting
1135
+ ~${_(i.wastedMs)})
1032
1136
  </div>`)}
1033
- ${s.warnings.map(o=>a`<div class="insight-line insight-warn">⚠ ${o}</div>`)}
1034
- ${s.tip?a`<div class="insight-line insight-tip">
1035
- Tip: ${s.tip}
1036
- </div>`:d}
1137
+ ${e.warnings.map(i=>a`<div class="insight-line insight-warn">⚠ ${i}</div>`)}
1138
+ ${e.tip?a`<div class="insight-line insight-tip">
1139
+ Tip: ${e.tip}
1140
+ </div>`:p}
1037
1141
  </div>
1038
- `:d}
1142
+ `:p}
1039
1143
  </div>
1040
- `}renderTrafficCard(t){if($t[t.category||""])return d;let s=st(t.statusCode),r=v(t.pollingDurationMs||t.durationMs),o=!t.isDuplicate&&t.category!==Ht&&t.category!==J||t.requestBody&&t.method!=="GET"||!!t.responseBody;return a`
1144
+ `}renderTrafficCard(t){if(Gt[t.category||""])return p;let e=bt(t.statusCode),r=_(t.pollingDurationMs||t.durationMs),i=!t.isDuplicate&&t.category!==re&&t.category!==ut||t.requestBody&&t.method!=="GET"||!!t.responseBody;return a`
1041
1145
  <div
1042
1146
  class="traffic-card ${t.isStrictModeDupe?"strict-mode-dupe":""}"
1043
1147
  >
1044
- <div class="traffic-card-header ${o?"has-details":""}">
1148
+ <div class="traffic-card-header ${i?"has-details":""}">
1045
1149
  <bk-method-badge .method=${t.method}></bk-method-badge>
1046
1150
  <span class="traffic-card-path ${t.isDuplicate?"is-dup":""}"
1047
1151
  >${t.label}</span
1048
1152
  >
1049
- <span class="status-pill ${s}">${t.statusCode}</span>
1153
+ <span class="status-pill ${e}">${t.statusCode}</span>
1050
1154
  <span class="traffic-card-dur">${r}</span>
1051
1155
  ${t.isDuplicate?a`<span class="traffic-card-dup">duplicate</span>`:a`<span class="traffic-card-size"
1052
- >${U(t.responseSize)}</span
1156
+ >${et(t.responseSize)}</span
1053
1157
  >`}
1054
1158
  </div>
1055
1159
  ${t.isStrictModeDupe?a`<div class="strict-mode-banner">
1056
1160
  React Strict Mode duplicate — does not happen in production
1057
- </div>`:d}
1058
- ${!t.isDuplicate&&t.category!==Ht&&t.category!==J?a`<div
1161
+ </div>`:p}
1162
+ ${!t.isDuplicate&&t.category!==re&&t.category!==ut?a`<div
1059
1163
  class="request-timeline tl-hidden"
1060
1164
  data-request-id=${t.id}
1061
1165
  data-request-started=${String(t.startedAt)}
1062
- ></div>`:d}
1063
- ${t.requestBody&&t.method!=="GET"?this.renderBodyToggle("out","Request Body",t.requestBody):d}
1064
- ${t.responseBody?this.renderBodyToggle("in","Response Body",t.responseBody):d}
1166
+ ></div>`:p}
1167
+ ${t.requestBody&&t.method!=="GET"?this.renderBodyToggle("out","Request Body",t.requestBody):p}
1168
+ ${t.responseBody?this.renderBodyToggle("in","Response Body",t.responseBody):p}
1065
1169
  </div>
1066
- `}renderBodyToggle(t,s,r){let o=t==="out"?"\u2192":"\u2190";return a`
1170
+ `}renderBodyToggle(t,e,r){let i=t==="out"?"\u2192":"\u2190";return a`
1067
1171
  <div class="traffic-body">
1068
1172
  <button class="traffic-body-toggle" @click=${this.toggleBodyBlock}>
1069
1173
  <span class="chevron">▸</span
1070
- ><span class="arrow-${t}">${o}</span> ${s}
1174
+ ><span class="arrow-${t}">${i}</span> ${e}
1071
1175
  </button>
1072
- <pre .innerHTML=${Q(r)}></pre>
1176
+ <pre>${U(nt(r))}</pre>
1073
1177
  </div>
1074
1178
  `}renderFlowSubReqs(t){return a`<div class="flow-subreqs">
1075
- ${t.requests.map((s,r)=>this.renderSubReqRow(s,r))}
1076
- </div>`}renderSubReqRow(t,s){let r=this.expandedSubReqIdx===s,o=st(t.statusCode),n=t.pollingDurationMs?v(t.pollingDurationMs):v(t.durationMs);return a`
1179
+ ${t.requests.map((e,r)=>this.renderSubReqRow(e,r))}
1180
+ </div>`}renderSubReqRow(t,e){let r=this.expandedSubReqIdx===e,i=bt(t.statusCode),n=t.pollingDurationMs?_(t.pollingDurationMs):_(t.durationMs);return a`
1077
1181
  <div
1078
1182
  class="flow-subreq ${r?"expanded":""}"
1079
- @click=${l=>this.toggleSubReq(s,l)}
1183
+ @click=${l=>this.toggleSubReq(e,l)}
1080
1184
  >
1081
1185
  <bk-method-badge .method=${t.method}></bk-method-badge>
1082
1186
  <span class="subreq-label ${t.isDuplicate?"is-dup":""}"
1083
1187
  >${t.path||t.url}</span
1084
1188
  >
1085
- ${t.isDuplicate?a`<span class="subreq-dup-tag">duplicate</span>`:d}
1086
- <span class="status-pill ${o}">${t.statusCode}</span>
1189
+ ${t.isDuplicate?a`<span class="subreq-dup-tag">duplicate</span>`:p}
1190
+ <span class="status-pill ${i}">${t.statusCode}</span>
1087
1191
  <span class="subreq-dur">${n}</span>
1088
1192
  </div>
1089
1193
  <div class="flow-subreq-detail ${r?"open":""}">
1090
- ${r?this.renderSubReqDetail(t):d}
1194
+ ${r?this.renderSubReqDetail(t):p}
1091
1195
  </div>
1092
- `}renderSubReqDetail(t){let s=st(t.statusCode);return a`
1196
+ `}renderSubReqDetail(t){let e=bt(t.statusCode);return a`
1093
1197
  <div class="detail-meta">
1094
1198
  <span
1095
- ><bk-method-badge .method=${t.method}></bk-method-badge> ${P(t.url)}</span
1199
+ ><bk-method-badge .method=${t.method}></bk-method-badge> ${tt(t.url)}</span
1096
1200
  >
1097
1201
  <span
1098
- ><span class="status-pill ${s}">${t.statusCode}</span></span
1202
+ ><span class="status-pill ${e}">${t.statusCode}</span></span
1099
1203
  >
1100
1204
  <span>${t.durationMs}ms</span>
1101
- ${t.responseSize?a`<span>${U(t.responseSize)}</span>`:d}
1205
+ ${t.responseSize?a`<span>${et(t.responseSize)}</span>`:p}
1102
1206
  </div>
1103
1207
  <div
1104
1208
  class="request-timeline tl-hidden"
@@ -1108,30 +1212,30 @@ span.perf-breakdown-dot.perf-breakdown-app{background:var(--breakdown-app)}
1108
1212
  <div class="detail-grid">
1109
1213
  <div class="detail-section">
1110
1214
  <h4>Request Headers</h4>
1111
- <pre .innerHTML=${rt(t.headers)}></pre>
1215
+ <pre>${U(Et(t.headers))}</pre>
1112
1216
  </div>
1113
1217
  <div class="detail-section">
1114
1218
  <h4>Response Headers</h4>
1115
- <pre .innerHTML=${rt(t.responseHeaders)}></pre>
1219
+ <pre>${U(Et(t.responseHeaders))}</pre>
1116
1220
  </div>
1117
1221
  <div class="detail-section">
1118
1222
  <h4>Request Body</h4>
1119
- <pre .innerHTML=${Q(t.requestBody)}></pre>
1223
+ <pre>${U(nt(t.requestBody))}</pre>
1120
1224
  </div>
1121
1225
  <div class="detail-section">
1122
1226
  <h4>Response Body</h4>
1123
- <pre .innerHTML=${Q(t.responseBody)}></pre>
1227
+ <pre>${U(nt(t.responseBody))}</pre>
1124
1228
  </div>
1125
1229
  </div>
1126
1230
  <div class="detail-actions">
1127
1231
  <button
1128
1232
  class="btn btn-curl"
1129
- @click=${r=>{r.stopPropagation(),ct(t);}}
1233
+ @click=${r=>{r.stopPropagation(),Tt(t);}}
1130
1234
  >
1131
1235
  Copy cURL
1132
1236
  </button>
1133
1237
  </div>
1134
- `}};u([R({context:x})],L.prototype,"store",2),u([_()],L.prototype,"expandedFlowIdx",2),u([_()],L.prototype,"expandedSubReqIdx",2),u([_()],L.prototype,"flowDetailTab",2),u([_()],L.prototype,"flowTimeline",2),u([_()],L.prototype,"flowTimelineLoading",2),L=u([g("bk-flows-view")],L);var Ct=class extends f{createRenderRoot(){return this}connectedCallback(){super.connectedCallback(),this.store.addEventListener("state-changed",()=>this.requestUpdate());}render(){let e=(this.store.state.issues||[]).slice(),t=e.filter(l=>l.state==="open"||l.state==="fixing"||l.state==="regressed"),s=e.filter(l=>l.state==="resolved");if(t.length===0&&s.length===0)return this.store.state.requests.length>0||this.store.state.logs.length>0||this.store.state.queries.length>0?a`
1238
+ `}};u([I({context:A})],W.prototype,"store",2),u([b()],W.prototype,"expandedFlowIdx",2),u([b()],W.prototype,"expandedSubReqIdx",2),u([b()],W.prototype,"flowDetailTab",2),u([b()],W.prototype,"flowTimeline",2),u([b()],W.prototype,"flowTimelineLoading",2),W=u([S("bk-flows-view")],W);var Vt=class extends E{createRenderRoot(){return this}connectedCallback(){super.connectedCallback(),this.store.addEventListener("state-changed",()=>this.requestUpdate());}render(){let s=(this.store.state.issues||[]).slice(),t=s.filter(l=>l.state==="open"||l.state==="fixing"||l.state==="regressed"),e=s.filter(l=>l.state==="resolved");if(t.length===0&&e.length===0)return this.store.state.requests.length>0||this.store.state.logs.length>0||this.store.state.queries.length>0?a`
1135
1239
  <div class="sec-clear">
1136
1240
  <span class="sec-clear-icon">\u2713</span>
1137
1241
  <div class="sec-clear-text">
@@ -1139,109 +1243,109 @@ span.perf-breakdown-dot.perf-breakdown-app{background:var(--breakdown-app)}
1139
1243
  <div class="sec-clear-sub">No security or quality issues detected this session</div>
1140
1244
  </div>
1141
1245
  </div>
1142
- `:a`<bk-empty-state title="Waiting for requests..." subtitle="Start using your app to see security findings here"></bk-empty-state>`;let r=0,o=0,n=0;for(let l of t){let c=l.issue.severity;c==="critical"?r++:c==="info"?n++:o++;}return a`
1246
+ `:a`<bk-empty-state title="Waiting for requests..." subtitle="Start using your app to see security findings here"></bk-empty-state>`;let r=0,i=0,n=0;for(let l of t){let c=l.issue.severity;c==="critical"?r++:c==="info"?n++:i++;}return a`
1143
1247
  <div id="security-content">
1144
- ${this.renderSummary(t.length,s.length,r,o,n)}
1145
- ${t.length===0&&s.length>0?a`
1248
+ ${this.renderSummary(t.length,e.length,r,i,n)}
1249
+ ${t.length===0&&e.length>0?a`
1146
1250
  <div class="sec-clear">
1147
1251
  <span class="sec-clear-icon">\u2713</span>
1148
1252
  <div class="sec-clear-text">
1149
1253
  <div class="sec-clear-title">All issues resolved</div>
1150
- <div class="sec-clear-sub">${s.length} finding${s.length!==1?"s were":" was"} detected and fixed</div>
1254
+ <div class="sec-clear-sub">${e.length} finding${e.length!==1?"s were":" was"} detected and fixed</div>
1151
1255
  </div>
1152
1256
  </div>
1153
- `:d}
1154
- ${t.length>0?this.renderOpenGroups(t):d}
1155
- ${s.length>0?this.renderResolved(s):d}
1257
+ `:p}
1258
+ ${t.length>0?this.renderOpenGroups(t):p}
1259
+ ${e.length>0?this.renderResolved(e):p}
1156
1260
  </div>
1157
- `}renderSummary(e,t,s,r,o){return a`
1261
+ `}renderSummary(s,t,e,r,i){return a`
1158
1262
  <div class="sec-summary">
1159
1263
  <div class="sec-summary-left">
1160
- <span class="sec-summary-count">${e}</span>
1161
- <span class="sec-summary-label">open issue${e!==1?"s":""}</span>
1162
- ${t>0?a`<span class="sec-resolved-badge">${t} resolved</span>`:d}
1264
+ <span class="sec-summary-count">${s}</span>
1265
+ <span class="sec-summary-label">open issue${s!==1?"s":""}</span>
1266
+ ${t>0?a`<span class="sec-resolved-badge">${t} resolved</span>`:p}
1163
1267
  </div>
1164
1268
  <div class="sec-summary-right">
1165
- ${s>0?a`<span class="sec-badge critical">${s} critical</span>`:d}
1166
- ${r>0?a`<span class="sec-badge warning">${r} warning</span>`:d}
1167
- ${o>0?a`<span class="sec-badge info">${o} info</span>`:d}
1269
+ ${e>0?a`<span class="sec-badge critical">${e} critical</span>`:p}
1270
+ ${r>0?a`<span class="sec-badge warning">${r} warning</span>`:p}
1271
+ ${i>0?a`<span class="sec-badge info">${i} info</span>`:p}
1168
1272
  </div>
1169
1273
  </div>
1170
- `}renderOpenGroups(e){let t={},s=[];for(let r of e){let o=r.issue,n=o.rule||o.type;t[n]||(t[n]={rule:n,title:o.title,severity:o.severity,hint:o.hint,items:[]},s.push(n)),t[n].items.push(r);}return s.sort((r,o)=>{let n=q[t[r].severity]?.sort??2,l=q[t[o].severity]?.sort??2;return n!==l?n-l:t[o].items.length-t[r].items.length}),a`${s.map(r=>this.renderGroup(t[r]))}`}renderGroup(e){let t=q[e.severity]||q.info;return a`
1274
+ `}renderOpenGroups(s){let t={},e=[];for(let r of s){let i=r.issue,n=i.rule||i.type;t[n]||(t[n]={rule:n,title:i.title,severity:i.severity,hint:i.hint,items:[]},e.push(n)),t[n].items.push(r);}return e.sort((r,i)=>{let n=Z[t[r].severity]?.sort??2,l=Z[t[i].severity]?.sort??2;return n!==l?n-l:t[i].items.length-t[r].items.length}),a`${e.map(r=>this.renderGroup(t[r]))}`}renderGroup(s){let t=Z[s.severity]||Z.info;return a`
1171
1275
  <div class="sec-group">
1172
1276
  <div class="sec-group-header">
1173
1277
  <span class="sec-group-icon ${t.cls}">${t.icon}</span>
1174
- <span class="sec-group-title">${e.title}</span>
1175
- <span class="sec-group-count">${e.items.length}</span>
1278
+ <span class="sec-group-title">${s.title}</span>
1279
+ <span class="sec-group-count">${s.items.length}</span>
1176
1280
  </div>
1177
- ${e.hint?a`<div class="sec-hint">${e.hint}</div>`:d}
1178
- <div class="sec-items">${e.items.map(s=>this.renderIssueItem(s))}</div>
1281
+ ${s.hint?a`<div class="sec-hint">${s.hint}</div>`:p}
1282
+ <div class="sec-items">${s.items.map(e=>this.renderIssueItem(e))}</div>
1179
1283
  </div>
1180
- `}renderIssueItem(e){let t=e.issue;return a`
1284
+ `}renderIssueItem(s){let t=s.issue;return a`
1181
1285
  <div class="sec-item">
1182
1286
  <div class="sec-item-desc">${t.desc}</div>
1183
- ${e.occurrences>1?a`<span class="sec-item-count">${e.occurrences}x</span>`:d}
1184
- ${e.state==="fixing"&&e.aiStatus==="fixed"?a`<span class="sec-ai-badge sec-ai-fixing">AI fixed \u2014 awaiting verification</span>`:e.aiStatus==="wont_fix"?a`<span class="sec-ai-badge sec-ai-wontfix">AI: won\u2019t fix</span>`:e.state==="regressed"?a`<span class="sec-ai-badge sec-ai-fixing" style="background:var(--red)">regressed</span>`:d}
1185
- ${e.aiNotes?a`<div class="sec-ai-notes">${e.aiNotes}</div>`:d}
1287
+ ${s.occurrences>1?a`<span class="sec-item-count">${s.occurrences}x</span>`:p}
1288
+ ${s.state==="fixing"&&s.aiStatus==="fixed"?a`<span class="sec-ai-badge sec-ai-fixing">AI fixed \u2014 awaiting verification</span>`:s.aiStatus==="wont_fix"?a`<span class="sec-ai-badge sec-ai-wontfix">AI: won\u2019t fix</span>`:s.state==="regressed"?a`<span class="sec-ai-badge sec-ai-fixing" style="background:var(--red)">regressed</span>`:p}
1289
+ ${s.aiNotes?a`<div class="sec-ai-notes">${s.aiNotes}</div>`:p}
1186
1290
  </div>
1187
- `}renderResolved(e){return a`
1291
+ `}renderResolved(s){return a`
1188
1292
  <div class="sec-resolved-title">
1189
1293
  <span class="sec-resolved-check">\u2713</span> Resolved
1190
- <span class="sec-resolved-count">${e.length}</span>
1294
+ <span class="sec-resolved-count">${s.length}</span>
1191
1295
  </div>
1192
1296
  <div class="sec-group sec-group-resolved">
1193
1297
  <div class="sec-items">
1194
- ${e.map(t=>a`
1298
+ ${s.map(t=>a`
1195
1299
  <div class="sec-item sec-item-resolved">
1196
1300
  <span class="sec-resolved-item-icon">\u2713</span>
1197
1301
  <div class="sec-item-desc">${t.issue.title} \u2014 ${t.issue.endpoint||"global"}</div>
1198
- ${t.aiStatus==="fixed"?a`<span class="sec-ai-badge sec-ai-verified">Verified fix</span>`:d}
1199
- ${t.aiNotes?a`<div class="sec-ai-notes">${t.aiNotes}</div>`:d}
1302
+ ${t.aiStatus==="fixed"?a`<span class="sec-ai-badge sec-ai-verified">Verified fix</span>`:p}
1303
+ ${t.aiNotes?a`<div class="sec-ai-notes">${t.aiNotes}</div>`:p}
1200
1304
  </div>
1201
1305
  `)}
1202
1306
  </div>
1203
1307
  </div>
1204
- `}};u([R({context:x})],Ct.prototype,"store",2),Ct=u([g("bk-security-view")],Ct);var pt=class extends f{constructor(){super(...arguments);this.expandedCardIdx=-1;}createRenderRoot(){return this}connectedCallback(){super.connectedCallback(),this.store.addEventListener("state-changed",()=>this.requestUpdate());}toggleCard(t){this.expandedCardIdx=this.expandedCardIdx===t?-1:t;}render(){let t=this.store.state,s=t.requests.filter(b=>!b.isStatic&&!b.isHealthCheck&&(!b.path||b.path.indexOf(N)!==0));if(!(s.length>0||t.queries.length>0||t.errors.length>0))return a`<bk-empty-state
1308
+ `}};u([I({context:A})],Vt.prototype,"store",2),Vt=u([S("bk-security-view")],Vt);var Rt=class extends E{constructor(){super(...arguments);this.expandedCardIdx=-1;}createRenderRoot(){return this}connectedCallback(){super.connectedCallback(),this.store.addEventListener("state-changed",()=>this.requestUpdate());}toggleCard(t){this.expandedCardIdx=this.expandedCardIdx===t?-1:t;}render(){let t=this.store.state,e=t.requests.filter(y=>!y.isStatic&&!y.isHealthCheck&&(!y.path||y.path.indexOf(F)!==0));if(!(e.length>0||t.queries.length>0||t.errors.length>0))return a`<bk-empty-state
1205
1309
  title="Waiting for requests..."
1206
1310
  subtitle="Start using your app to see insights here"
1207
- ></bk-empty-state>`;let o=s.filter(b=>b.statusCode>=400).length,n=new Set(["data-fetch","api-call","server-action","page-load"]),l=s.filter(b=>b.category&&n.has(b.category)),c=l.length>0?l:s,p=c.length>0?Math.round(c.reduce((b,It)=>b+It.durationMs,0)/c.length):0,h=t.issues||[],m=h.filter(b=>b.state==="open"||b.state==="regressed"),E=h.filter(b=>b.state==="fixing"),T=h.filter(b=>b.state==="resolved");return a`
1311
+ ></bk-empty-state>`;let i=e.filter(y=>y.statusCode>=400).length,n=new Set(["data-fetch","api-call","server-action","page-load"]),l=e.filter(y=>y.category&&n.has(y.category)),c=l.length>0?l:e,d=c.length>0?Math.round(c.reduce((y,k)=>y+k.durationMs,0)/c.length):0,h=t.issues||[],m=h.filter(y=>y.state==="open"||y.state==="regressed"),v=h.filter(y=>y.state==="fixing"),x=h.filter(y=>y.state==="resolved");return a`
1208
1312
  <div class="ov-container" id="overview-content">
1209
- ${this.renderSummary(s.length,t.flows.length,p,t.queries.length,o,t.fetches.length)}
1210
- ${m.length===0&&E.length===0&&T.length===0?a`<div class="ov-clear">
1313
+ ${this.renderSummary(e.length,t.flows.length,d,t.queries.length,i,t.fetches.length)}
1314
+ ${m.length===0&&v.length===0&&x.length===0?a`<div class="ov-clear">
1211
1315
  <span class="ov-clear-icon">\u2713</span>All clear \u2014 no issues detected
1212
- </div>`:d}
1213
- ${m.length===0&&T.length>0?a`<div class="ov-clear">
1316
+ </div>`:p}
1317
+ ${m.length===0&&x.length>0?a`<div class="ov-clear">
1214
1318
  <span class="ov-clear-icon">\u2713</span>All issues resolved \u2014
1215
- ${T.length} finding${T.length!==1?"s were":" was"} detected and
1319
+ ${x.length} finding${x.length!==1?"s were":" was"} detected and
1216
1320
  fixed
1217
- </div>`:d}
1218
- ${m.length>0?this.renderOpenIssues(m):d}
1219
- ${E.length>0?this.renderVerifying(E):d}
1220
- ${T.length>0?this.renderResolvedIssues(T):d}
1321
+ </div>`:p}
1322
+ ${m.length>0?this.renderOpenIssues(m):p}
1323
+ ${v.length>0?this.renderVerifying(v):p}
1324
+ ${x.length>0?this.renderResolvedIssues(x):p}
1221
1325
  </div>
1222
- `}renderSummary(t,s,r,o,n,l){return a`
1326
+ `}renderSummary(t,e,r,i,n,l){return a`
1223
1327
  <div class="ov-summary">
1224
1328
  <div class="ov-stat"><span class="ov-stat-value">${t}</span><span class="ov-stat-label">Requests</span></div>
1225
- <div class="ov-stat"><span class="ov-stat-value">${s}</span><span class="ov-stat-label">Actions</span></div>
1226
- <div class="ov-stat"><span class="ov-stat-value">${v(r)}</span><span class="ov-stat-label">Avg Response</span></div>
1227
- <div class="ov-stat"><span class="ov-stat-value">${o}</span><span class="ov-stat-label">Queries</span></div>
1329
+ <div class="ov-stat"><span class="ov-stat-value">${e}</span><span class="ov-stat-label">Actions</span></div>
1330
+ <div class="ov-stat"><span class="ov-stat-value">${_(r)}</span><span class="ov-stat-label">Avg Response</span></div>
1331
+ <div class="ov-stat"><span class="ov-stat-value">${i}</span><span class="ov-stat-label">Queries</span></div>
1228
1332
  <div class="ov-stat"><span class="ov-stat-value" style="color:${n>0?"var(--red)":"var(--green)"}">${n}</span><span class="ov-stat-label">Errors</span></div>
1229
1333
  <div class="ov-stat"><span class="ov-stat-value">${l}</span><span class="ov-stat-label">Fetches</span></div>
1230
1334
  </div>
1231
1335
  `}renderOpenIssues(t){return a`
1232
1336
  <div class="ov-section-title">Issues Found <span class="ov-issue-count">${t.length}</span></div>
1233
- <div class="ov-cards">${t.map((s,r)=>this.renderIssueCard(s,r))}</div>
1234
- `}renderIssueCard(t,s){let r=t.issue,o=q[r.severity]||q.info,n=this.expandedCardIdx===s,l=t.aiStatus==="wont_fix"?a`<span class="sec-ai-badge sec-ai-wontfix">AI: won\u2019t fix</span>`:t.state==="regressed"?a`<span class="sec-ai-badge sec-ai-fixing" style="background:var(--red)">regressed</span>`:d,c=t.cleanHitsSinceLastSeen>0?a`<div class="ov-card-resolving">Resolving\u2026 ${t.cleanHitsSinceLastSeen}/${5} clean requests</div>`:d;return a`
1235
- <div class="ov-card ${n?"expanded":""}" @click=${()=>this.toggleCard(s)}>
1236
- <span class="ov-card-icon ${o.cls}">${o.icon}</span>
1337
+ <div class="ov-cards">${t.map((e,r)=>this.renderIssueCard(e,r))}</div>
1338
+ `}renderIssueCard(t,e){let r=t.issue,i=Z[r.severity]||Z.info,n=this.expandedCardIdx===e,l=t.aiStatus==="wont_fix"?a`<span class="sec-ai-badge sec-ai-wontfix">AI: won\u2019t fix</span>`:t.state==="regressed"?a`<span class="sec-ai-badge sec-ai-fixing" style="background:var(--red)">regressed</span>`:p,c=t.cleanHitsSinceLastSeen>0?a`<div class="ov-card-resolving">Resolving\u2026 ${t.cleanHitsSinceLastSeen}/${5} clean requests</div>`:p;return a`
1339
+ <div class="ov-card ${n?"expanded":""}" @click=${()=>this.toggleCard(e)}>
1340
+ <span class="ov-card-icon ${i.cls}">${i.icon}</span>
1237
1341
  <div class="ov-card-body">
1238
1342
  <div class="ov-card-title">${r.title}${l}</div>
1239
1343
  <div class="ov-card-desc">${r.desc}</div>
1240
- ${r.detail?a`<div class="ov-card-detail">${r.detail}</div>`:d}
1344
+ ${r.detail?a`<div class="ov-card-detail">${r.detail}</div>`:p}
1241
1345
  ${c}
1242
- ${n&&r.hint?a`<div class="ov-card-hint">${r.hint}</div>`:d}
1346
+ ${n&&r.hint?a`<div class="ov-card-hint">${r.hint}</div>`:p}
1243
1347
  </div>
1244
- ${r.hint?a`<span class="ov-card-arrow">${n?"\u2193":"\u2192"}</span>`:d}
1348
+ ${r.hint?a`<span class="ov-card-arrow">${n?"\u2193":"\u2192"}</span>`:p}
1245
1349
  </div>
1246
1350
  `}renderVerifying(t){return a`
1247
1351
  <div class="ov-section-title ov-resolved-title">
@@ -1249,7 +1353,7 @@ span.perf-breakdown-dot.perf-breakdown-app{background:var(--breakdown-app)}
1249
1353
  <span class="ov-issue-count">${t.length}</span>
1250
1354
  </div>
1251
1355
  <div class="ov-cards">
1252
- ${t.map(s=>{let r=s.issue,o=s.cleanHitsSinceLastSeen>0?a`<div class="ov-card-resolving">Verifying\u2026 ${s.cleanHitsSinceLastSeen}/${5} clean requests</div>`:d;return a`
1356
+ ${t.map(e=>{let r=e.issue,i=e.cleanHitsSinceLastSeen>0?a`<div class="ov-card-resolving">Verifying\u2026 ${e.cleanHitsSinceLastSeen}/${5} clean requests</div>`:p;return a`
1253
1357
  <div class="ov-card ov-card-resolved">
1254
1358
  <span class="ov-card-icon resolved">\u29d7</span>
1255
1359
  <div class="ov-card-body">
@@ -1258,7 +1362,7 @@ span.perf-breakdown-dot.perf-breakdown-app{background:var(--breakdown-app)}
1258
1362
  <span class="sec-ai-badge sec-ai-fixing">AI fixed \u2014 awaiting verification</span>
1259
1363
  </div>
1260
1364
  <div class="ov-card-desc">${r.desc}</div>
1261
- ${o}
1365
+ ${i}
1262
1366
  </div>
1263
1367
  </div>
1264
1368
  `})}
@@ -1269,46 +1373,46 @@ span.perf-breakdown-dot.perf-breakdown-app{background:var(--breakdown-app)}
1269
1373
  <span class="ov-issue-count">${t.length}</span>
1270
1374
  </div>
1271
1375
  <div class="ov-cards">
1272
- ${t.map(s=>a`
1376
+ ${t.map(e=>a`
1273
1377
  <div class="ov-card ov-card-resolved">
1274
1378
  <span class="ov-card-icon resolved">\u2713</span>
1275
1379
  <div class="ov-card-body">
1276
- <div class="ov-card-title" style="text-decoration:line-through;color:var(--text-muted)">${s.issue.title}</div>
1277
- <div class="ov-card-desc">${s.issue.desc}</div>
1380
+ <div class="ov-card-title" style="text-decoration:line-through;color:var(--text-muted)">${e.issue.title}</div>
1381
+ <div class="ov-card-desc">${e.issue.desc}</div>
1278
1382
  </div>
1279
1383
  </div>
1280
1384
  `)}
1281
1385
  </div>
1282
- `}};u([R({context:x})],pt.prototype,"store",2),u([_()],pt.prototype,"expandedCardIdx",2),pt=u([g("bk-overview-view")],pt);function hs(i){return i<1?"<1ms":i<1e3?Math.round(i)+"ms":(i/1e3).toFixed(1)+"s"}function ir(i){return i<Z?yt.green:i<tt?yt.amber:yt.red}function nr(i){return i.statusCode>=400?yt.red:ir(i.durationMs)}function ms(i){return [parseInt(i.slice(1,3),16),parseInt(i.slice(3,5),16),parseInt(i.slice(5,7),16)]}function ar(i){let e=i.getContext("2d");if(!e)return null;let t=window.devicePixelRatio||1,s=i.clientWidth,r=i.clientHeight;return i.width=s*t,i.height=r*t,e.scale(t,t),{ctx:e,w:s,h:r}}function lr(i,e,t,s,r){let[o,n,l]=ms(r);i.beginPath(),i.arc(e,t,s+2,0,Math.PI*2),i.fillStyle=`rgba(${o},${n},${l},0.25)`,i.fill(),i.beginPath(),i.arc(e,t,s,0,Math.PI*2),i.fillStyle=r,i.fill();}function cr(i,e,t,s,r,o){let[n,l,c]=ms(r);i.strokeStyle=`rgba(${n},${l},${c},0.3)`,i.lineWidth=o+2,i.beginPath(),i.moveTo(e-s,t-s),i.lineTo(e+s,t+s),i.moveTo(e+s,t-s),i.lineTo(e-s,t+s),i.stroke(),i.strokeStyle=r,i.lineWidth=o,i.beginPath(),i.moveTo(e-s,t-s),i.lineTo(e+s,t+s),i.moveTo(e+s,t-s),i.lineTo(e-s,t+s),i.stroke();}function vs(i,e){let t=[],s=ar(i);if(!s||e.length===0)return t;let{ctx:r,w:o,h:n}=s,l=Ze,c=o-l.left-l.right,p=n-l.top-l.bottom,h=0,m=e[0].timestamp,E=e[0].timestamp;for(let S of e)S.durationMs>h&&(h=S.durationMs),S.timestamp<m&&(m=S.timestamp),S.timestamp>E&&(E=S.timestamp);h=Math.max(h,10),h=Math.ceil(h*1.15/10)*10;let T=E-m||1;r.strokeStyle=ze,r.lineWidth=1;let b=4;for(let S=0;S<=b;S++){let A=l.top+p-S/b*p;r.beginPath(),r.moveTo(l.left,A),r.lineTo(l.left+c,A),r.stroke(),r.fillStyle=ve,r.font=Je,r.textAlign="right",r.fillText(hs(Math.round(S/b*h)),l.left-8,A+3);}for(let S of [{ms:Z},{ms:tt}]){if(S.ms>=h)continue;let A=l.top+p-S.ms/h*p;r.beginPath(),r.setLineDash([4,4]),r.strokeStyle="rgba(113,113,122,0.3)",r.lineWidth=1,r.moveTo(l.left,A),r.lineTo(l.left+c,A),r.stroke(),r.setLineDash([]),r.fillStyle="rgba(113,113,122,0.5)",r.font=fe,r.textAlign="left",r.fillText(hs(S.ms),l.left+c+2,A+3);}for(let S=0;S<e.length;S++){let A=e[S],ut=e.length===1?l.left+c/2:l.left+(A.timestamp-m)/T*c,jt=l.top+p-A.durationMs/h*p,$e=nr(A);t.push({x:ut,y:jt,idx:S,r:A}),A.statusCode>=400?cr(r,ut,jt,4,$e,2):lr(r,ut,jt,4,$e);}r.fillStyle=ve,r.font=fe,r.textAlign="center";let It=[m,m+T/2,E];for(let S=0;S<It.length;S++){let A=l.left+S/2*c,ut=new Date(It[S]);r.fillText(ut.toLocaleTimeString([],{hour:"2-digit",minute:"2-digit",second:"2-digit"}),A,l.top+p+14);}return t}var vr={max:1/0,label:"Pending",color:"var(--text-muted)",bg:"var(--bg-muted)",border:"var(--border)"};function fs(i,e,t){return t>=20?i:e}function Te(i,e){if(!e||e<=0)return vr;let t=i/e;return t<.7?et[0]:t<1.2?et[1]:t<2?et[2]:t<3?et[3]:et[4]}var M=class extends f{constructor(){super(...arguments);this.selectedEndpoint=H;this.graphData=[];this.loadError=false;this.queryBreakdown=[];this.queryBreakdownLoading=false;this.scatterDots=[];}createRenderRoot(){return this}connectedCallback(){super.connectedCallback(),this.store.addEventListener("state-changed",()=>this.requestUpdate()),this.loadMetrics();}async loadMetrics(){try{let s=await(await fetch($.metricsLive)).json();this.graphData=s.endpoints||[],this.loadError=!1,(!this.selectedEndpoint||this.selectedEndpoint===H)&&(this.selectedEndpoint=H);}catch{this.loadError=true;}}healthGradeForEndpoint(t){let s=fs(t.summary.p95Ms,t.summary.medianMs,t.summary.totalRequests);return Te(s,t.baselineP95Ms)}healthGradeForDuration(t,s){return Te(t,s)}getCallers(t){let s=this.store.state.flows,r=new Map;for(let o of s)for(let n of o.requests)if(`${n.method} ${n.path}`===t||this.normalizeEndpoint(n)===t){let c=r.get(o.label);c?(c.count++,c.totalMs+=n.durationMs):r.set(o.label,{count:1,totalMs:n.durationMs});}return [...r.entries()].map(([o,n])=>({label:o,count:n.count,avgMs:Math.round(n.totalMs/n.count)})).sort((o,n)=>n.count-o.count)}normalizeEndpoint(t){let s=t.path.replace(/\/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/gi,"/:id").replace(/\/\d+/g,"/:id");return `${t.method} ${s}`}async loadQueryBreakdown(t){if(this.queryBreakdownLoading)return;let r=this.store.state.requests.filter(o=>`${o.method} ${o.path}`===t||this.normalizeEndpoint(o)===t).slice(-20).map(o=>o.id).filter(Boolean);if(r.length===0){this.queryBreakdown=[];return}this.queryBreakdownLoading=true;try{let o=await fetch(`${$.activity}?requestIds=${r.join(",")}`);if(!o.ok){this.queryBreakdownLoading=!1;return}let n=await o.json(),l=new Map;for(let c of Object.values(n.activities))for(let p of c.timeline){if(p.type!=="query")continue;let h=p.data,m=(h.normalizedOp||h.operation||"QUERY").toUpperCase(),E=h.table||h.model||"",T=`${m} ${E}`.trim(),b=l.get(T);b?(b.totalMs+=h.durationMs,b.count++):l.set(T,{label:T,totalMs:h.durationMs,count:1});}this.queryBreakdown=[...l.values()].map(c=>({...c,avgMs:Math.round(c.totalMs/c.count)})).sort((c,p)=>p.totalMs-c.totalMs);}catch{}this.queryBreakdownLoading=false;}renderScatterChart(t,s){this.scatterDots=vs(t,s),t.style.cursor="pointer",t.onclick=r=>{let o=t.getBoundingClientRect(),n=r.clientX-o.left,l=r.clientY-o.top,c=null,p=1/0;for(let h of this.scatterDots){let m=Math.sqrt((h.x-n)**2+(h.y-l)**2);m<p&&(p=m,c=h);}c&&p<16&&this.highlightRow(c.idx);};}highlightRow(t){let s=this.querySelector(".perf-hist-row-hl");s&&s.classList.remove("perf-hist-row-hl");let r=this.querySelector(`[data-req-idx="${t}"]`);r&&(r.classList.add("perf-hist-row-hl"),r.scrollIntoView({behavior:"smooth",block:"center"}));}updated(){if(this.selectedEndpoint===H)return;let t=this.querySelector("#perf-detail-canvas");if(t){let s=this.graphData.find(r=>r.endpoint===this.selectedEndpoint);s&&this.renderScatterChart(t,s.requests);}}render(){return !this.graphData||this.graphData.length===0?a`<bk-empty-state title="No performance data yet" subtitle="Hit some endpoints and data will appear here"></bk-empty-state>`:a`
1386
+ `}};u([I({context:A})],Rt.prototype,"store",2),u([b()],Rt.prototype,"expandedCardIdx",2),Rt=u([S("bk-overview-view")],Rt);function Ys(o){return o<1?"<1ms":o<1e3?Math.round(o)+"ms":(o/1e3).toFixed(1)+"s"}function oi(o){return o<mt?Bt.green:o<ft?Bt.amber:Bt.red}function ni(o){return o.statusCode>=400?Bt.red:oi(o.durationMs)}function Xs(o){return [parseInt(o.slice(1,3),16),parseInt(o.slice(3,5),16),parseInt(o.slice(5,7),16)]}function ai(o){let s=o.getContext("2d");if(!s)return null;let t=window.devicePixelRatio||1,e=o.clientWidth,r=o.clientHeight;return o.width=e*t,o.height=r*t,s.scale(t,t),{ctx:s,w:e,h:r}}function li(o,s,t,e,r){let[i,n,l]=Xs(r);o.beginPath(),o.arc(s,t,e+2,0,Math.PI*2),o.fillStyle=`rgba(${i},${n},${l},0.25)`,o.fill(),o.beginPath(),o.arc(s,t,e,0,Math.PI*2),o.fillStyle=r,o.fill();}function ci(o,s,t,e,r,i){let[n,l,c]=Xs(r);o.strokeStyle=`rgba(${n},${l},${c},0.3)`,o.lineWidth=i+2,o.beginPath(),o.moveTo(s-e,t-e),o.lineTo(s+e,t+e),o.moveTo(s+e,t-e),o.lineTo(s-e,t+e),o.stroke(),o.strokeStyle=r,o.lineWidth=i,o.beginPath(),o.moveTo(s-e,t-e),o.lineTo(s+e,t+e),o.moveTo(s+e,t-e),o.lineTo(s-e,t+e),o.stroke();}function Vs(o,s){let t=[],e=ai(o);if(!e||s.length===0)return t;let{ctx:r,w:i,h:n}=e,l=Ls,c=i-l.left-l.right,d=n-l.top-l.bottom,h=0,m=s[0].timestamp,v=s[0].timestamp;for(let $ of s)$.durationMs>h&&(h=$.durationMs),$.timestamp<m&&(m=$.timestamp),$.timestamp>v&&(v=$.timestamp);h=Math.max(h,10),h=Math.ceil(h*1.15/10)*10;let x=v-m||1;r.strokeStyle=Is,r.lineWidth=1;let y=4;for(let $=0;$<=y;$++){let f=l.top+d-$/y*d;r.beginPath(),r.moveTo(l.left,f),r.lineTo(l.left+c,f),r.stroke(),r.fillStyle=Ue,r.font=Cs,r.textAlign="right",r.fillText(Ys(Math.round($/y*h)),l.left-8,f+3);}for(let $ of [{ms:mt},{ms:ft}]){if($.ms>=h)continue;let f=l.top+d-$.ms/h*d;r.beginPath(),r.setLineDash([4,4]),r.strokeStyle="rgba(113,113,122,0.3)",r.lineWidth=1,r.moveTo(l.left,f),r.lineTo(l.left+c,f),r.stroke(),r.setLineDash([]),r.fillStyle="rgba(113,113,122,0.5)",r.font=Fe,r.textAlign="left",r.fillText(Ys($.ms),l.left+c+2,f+3);}for(let $=0;$<s.length;$++){let f=s[$],g=s.length===1?l.left+c/2:l.left+(f.timestamp-m)/x*c,T=l.top+d-f.durationMs/h*d,R=ni(f);t.push({x:g,y:T,idx:$,r:f}),f.statusCode>=400?ci(r,g,T,4,R,2):li(r,g,T,4,R);}r.fillStyle=Ue,r.font=Fe,r.textAlign="center";let k=[m,m+x/2,v];for(let $=0;$<k.length;$++){let f=l.left+$/2*c,g=new Date(k[$]);r.fillText(g.toLocaleTimeString([],{hour:"2-digit",minute:"2-digit",second:"2-digit"}),f,l.top+d+14);}return t}var fi={max:1/0,label:"Pending",color:"var(--text-muted)",bg:"var(--bg-muted)",border:"var(--border)"};function Ks(o,s,t){return t>=20?o:s}function Ye(o,s){if(!s||s<=0)return fi;let t=o/s;return t<.7?gt[0]:t<1.2?gt[1]:t<2?gt[2]:t<3?gt[3]:gt[4]}var Q=class extends E{constructor(){super(...arguments);this.selectedEndpoint=J;this.graphData=[];this.loadError=false;this.queryBreakdown=[];this.queryBreakdownLoading=false;this.scatterDots=[];}createRenderRoot(){return this}connectedCallback(){super.connectedCallback(),this.store.addEventListener("state-changed",()=>this.requestUpdate()),this.loadMetrics();}async loadMetrics(){try{let e=await(await fetch(w.metricsLive)).json();this.graphData=e.endpoints||[],this.loadError=!1,(!this.selectedEndpoint||this.selectedEndpoint===J)&&(this.selectedEndpoint=J);}catch{this.loadError=true;}}healthGradeForEndpoint(t){let e=Ks(t.summary.p95Ms,t.summary.medianMs,t.summary.totalRequests);return Ye(e,t.baselineP95Ms)}healthGradeForDuration(t,e){return Ye(t,e)}getCallers(t){let e=this.store.state.flows,r=new Map;for(let i of e)for(let n of i.requests)if(`${n.method} ${n.path}`===t||this.normalizeEndpoint(n)===t){let c=r.get(i.label);c?(c.count++,c.totalMs+=n.durationMs):r.set(i.label,{count:1,totalMs:n.durationMs});}return [...r.entries()].map(([i,n])=>({label:i,count:n.count,avgMs:Math.round(n.totalMs/n.count)})).sort((i,n)=>n.count-i.count)}normalizeEndpoint(t){let r=t.path.split("?")[0].split("/").map(i=>{if(!i)return i;let n=i.length>0;for(let l=0;l<i.length;l++){let c=i.charCodeAt(l);if(c<48||c>57){n=false;break}}return n||i.length===36&&i[8]==="-"&&i[13]==="-"&&i[18]==="-"&&i[23]==="-"?":id":i}).join("/");return `${t.method} ${r}`}async loadQueryBreakdown(t){if(this.queryBreakdownLoading)return;let r=this.store.state.requests.filter(i=>`${i.method} ${i.path}`===t||this.normalizeEndpoint(i)===t).slice(-20).map(i=>i.id).filter(Boolean);if(r.length===0){this.queryBreakdown=[];return}this.queryBreakdownLoading=true;try{let i=await fetch(`${w.activity}?requestIds=${r.join(",")}`);if(!i.ok){this.queryBreakdownLoading=!1;return}let n=await i.json(),l=new Map;for(let c of Object.values(n.activities))for(let d of c.timeline){if(d.type!=="query")continue;let h=d.data,m=(h.normalizedOp||h.operation||"QUERY").toUpperCase(),v=h.table||h.model||"",x=`${m} ${v}`.trim(),y=l.get(x);y?(y.totalMs+=h.durationMs,y.count++):l.set(x,{label:x,totalMs:h.durationMs,count:1});}this.queryBreakdown=[...l.values()].map(c=>({...c,avgMs:Math.round(c.totalMs/c.count)})).sort((c,d)=>d.totalMs-c.totalMs);}catch{}this.queryBreakdownLoading=false;}renderScatterChart(t,e){this.scatterDots=Vs(t,e),t.style.cursor="pointer",t.onclick=r=>{let i=t.getBoundingClientRect(),n=r.clientX-i.left,l=r.clientY-i.top,c=null,d=1/0;for(let h of this.scatterDots){let m=Math.sqrt((h.x-n)**2+(h.y-l)**2);m<d&&(d=m,c=h);}c&&d<16&&this.highlightRow(c.idx);};}highlightRow(t){let e=this.querySelector(".perf-hist-row-hl");e&&e.classList.remove("perf-hist-row-hl");let r=this.querySelector(`[data-req-idx="${t}"]`);r&&(r.classList.add("perf-hist-row-hl"),r.scrollIntoView({behavior:"smooth",block:"center"}));}updated(){if(this.selectedEndpoint===J)return;let t=this.querySelector("#perf-detail-canvas");if(t){let e=this.graphData.find(r=>r.endpoint===this.selectedEndpoint);e&&this.renderScatterChart(t,e.requests);}}render(){return !this.graphData||this.graphData.length===0?a`<bk-empty-state title="No performance data yet" subtitle="Hit some endpoints and data will appear here"></bk-empty-state>`:a`
1283
1387
  <div id="graph-content">
1284
1388
  ${this.renderSelector()}
1285
- ${this.selectedEndpoint===H?this.renderOverview():this.renderDetail()}
1389
+ ${this.selectedEndpoint===J?this.renderOverview():this.renderDetail()}
1286
1390
  </div>
1287
1391
  `}renderSelector(){return a`
1288
1392
  <div class="perf-selector">
1289
- <button class="perf-selector-btn ${this.selectedEndpoint===H?"active":""}"
1290
- @click=${()=>{this.selectedEndpoint=H;}}>Overview</button>
1291
- ${this.graphData.map((t,s)=>a`
1393
+ <button class="perf-selector-btn ${this.selectedEndpoint===J?"active":""}"
1394
+ @click=${()=>{this.selectedEndpoint=J;}}>Overview</button>
1395
+ ${this.graphData.map((t,e)=>a`
1292
1396
  <button class="perf-selector-btn ${t.endpoint===this.selectedEndpoint?"active":""}"
1293
1397
  @click=${()=>{this.selectedEndpoint=t.endpoint,this.queryBreakdown=[],this.loadQueryBreakdown(t.endpoint);}}>
1294
- <span class="perf-dot" style="background:${me[s%me.length]}"></span>${t.endpoint}
1398
+ <span class="perf-dot" style="background:${qe[e%qe.length]}"></span>${t.endpoint}
1295
1399
  </button>
1296
1400
  `)}
1297
1401
  </div>
1298
- `}renderOverview(){let t=this.graphData.filter(c=>c.requests.length>0);if(t.length===0)return d;let s=t.reduce((c,p)=>c+p.summary.totalRequests,0),r=s>0?Math.round(t.reduce((c,p)=>c+p.summary.p95Ms*p.summary.totalRequests,0)/s):0,o=t.reduce((c,p)=>c+Math.round(p.summary.errorRate*p.summary.totalRequests),0),n=s>0?o/s:0,l=t[0];return a`
1402
+ `}renderOverview(){let t=this.graphData.filter(c=>c.requests.length>0);if(t.length===0)return p;let e=t.reduce((c,d)=>c+d.summary.totalRequests,0),r=e>0?Math.round(t.reduce((c,d)=>c+d.summary.p95Ms*d.summary.totalRequests,0)/e):0,i=t.reduce((c,d)=>c+Math.round(d.summary.errorRate*d.summary.totalRequests),0),n=e>0?i/e:0,l=t[0];return a`
1299
1403
  <div class="perf-overview">
1300
1404
  <div class="perf-summary-row">
1301
1405
  <div class="perf-summary-card">
1302
1406
  <span class="perf-summary-label">Total Requests</span>
1303
- <span class="perf-summary-value">${s}</span>
1407
+ <span class="perf-summary-value">${e}</span>
1304
1408
  </div>
1305
1409
  <div class="perf-summary-card">
1306
1410
  <span class="perf-summary-label">Avg P95</span>
1307
- <span class="perf-summary-value" style="color:${this.healthGradeForDuration(r).color}">${v(r)}</span>
1411
+ <span class="perf-summary-value" style="color:${this.healthGradeForDuration(r).color}">${_(r)}</span>
1308
1412
  </div>
1309
1413
  <div class="perf-summary-card">
1310
1414
  <span class="perf-summary-label">Error Rate</span>
1311
- <span class="perf-summary-value" style="color:${o>0?"var(--red)":"var(--green)"}">${Math.round(n*100)}%</span>
1415
+ <span class="perf-summary-value" style="color:${i>0?"var(--red)":"var(--green)"}">${Math.round(n*100)}%</span>
1312
1416
  </div>
1313
1417
  <div class="perf-summary-card">
1314
1418
  <span class="perf-summary-label">Slowest</span>
@@ -1332,45 +1436,45 @@ span.perf-breakdown-dot.perf-breakdown-app{background:var(--breakdown-app)}
1332
1436
  </tbody>
1333
1437
  </table>
1334
1438
  </div>
1335
- `}renderHeatmapRow(t){let s=t.summary,r=this.healthGradeForEndpoint(t),o=Math.round(s.errorRate*s.totalRequests),n=(s.avgQueryTimeMs||0)+(s.avgFetchTimeMs||0)+(s.avgAppTimeMs||0),l=0,c=0,p=100;return n>0&&(l=Math.round((s.avgQueryTimeMs||0)/n*100),c=Math.round((s.avgFetchTimeMs||0)/n*100),p=Math.max(0,100-l-c)),a`
1439
+ `}renderHeatmapRow(t){let e=t.summary,r=this.healthGradeForEndpoint(t),i=Math.round(e.errorRate*e.totalRequests),n=(e.avgQueryTimeMs||0)+(e.avgFetchTimeMs||0)+(e.avgAppTimeMs||0),l=0,c=0,d=100;return n>0&&(l=Math.round((e.avgQueryTimeMs||0)/n*100),c=Math.round((e.avgFetchTimeMs||0)/n*100),d=Math.max(0,100-l-c)),a`
1336
1440
  <tr class="perf-table-row" @click=${()=>{this.selectedEndpoint=t.endpoint,this.queryBreakdown=[],this.loadQueryBreakdown(t.endpoint);}}>
1337
1441
  <td class="perf-td-name">${t.endpoint}</td>
1338
- <td class="perf-td-right">${s.totalRequests}</td>
1442
+ <td class="perf-td-right">${e.totalRequests}</td>
1339
1443
  <td class="perf-td-center">
1340
- <span class="perf-hm-p95" style="color:${r.color};background:${r.bg};border-color:${r.border}">${v(s.p95Ms)}</span>
1444
+ <span class="perf-hm-p95" style="color:${r.color};background:${r.bg};border-color:${r.border}">${_(e.p95Ms)}</span>
1341
1445
  </td>
1342
- <td class="perf-td-center" style="color:${o>0?"var(--red)":"var(--text-muted)"}">${o>0?o:"-"}</td>
1343
- <td class="perf-td-center" style="color:${s.avgQueryCount>5?"var(--amber)":"var(--text-muted)"}">${s.avgQueryCount}</td>
1446
+ <td class="perf-td-center" style="color:${i>0?"var(--red)":"var(--text-muted)"}">${i>0?i:"-"}</td>
1447
+ <td class="perf-td-center" style="color:${e.avgQueryCount>5?"var(--amber)":"var(--text-muted)"}">${e.avgQueryCount}</td>
1344
1448
  <td>
1345
1449
  <span class="perf-hm-split-bar">
1346
- ${l>0?a`<span class="perf-breakdown-seg perf-breakdown-db" style="width:${l}%"></span>`:d}
1347
- ${c>0?a`<span class="perf-breakdown-seg perf-breakdown-fetch" style="width:${c}%"></span>`:d}
1348
- ${p>0?a`<span class="perf-breakdown-seg perf-breakdown-app" style="width:${p}%"></span>`:d}
1450
+ ${l>0?a`<span class="perf-breakdown-seg perf-breakdown-db" style="width:${l}%"></span>`:p}
1451
+ ${c>0?a`<span class="perf-breakdown-seg perf-breakdown-fetch" style="width:${c}%"></span>`:p}
1452
+ ${d>0?a`<span class="perf-breakdown-seg perf-breakdown-app" style="width:${d}%"></span>`:p}
1349
1453
  </span>
1350
1454
  </td>
1351
1455
  </tr>
1352
- `}renderDetail(){let t=this.graphData.find(n=>n.endpoint===this.selectedEndpoint);if(!t?.requests?.length)return a`<bk-empty-state subtitle="No data for this endpoint"></bk-empty-state>`;let s=t.summary,r=this.healthGradeForEndpoint(t),o=Math.round(s.errorRate*s.totalRequests);return a`
1456
+ `}renderDetail(){let t=this.graphData.find(n=>n.endpoint===this.selectedEndpoint);if(!t?.requests?.length)return a`<bk-empty-state subtitle="No data for this endpoint"></bk-empty-state>`;let e=t.summary,r=this.healthGradeForEndpoint(t),i=Math.round(e.errorRate*e.totalRequests);return a`
1353
1457
  ${this.renderDetailHeader(t,r)}
1354
- ${this.renderDetailMetrics(s,r,o)}
1355
- ${this.renderDetailBreakdown(s)}
1458
+ ${this.renderDetailMetrics(e,r,i)}
1459
+ ${this.renderDetailBreakdown(e)}
1356
1460
  ${this.renderCallers(t.endpoint)}
1357
1461
  ${this.renderQueryBreakdown()}
1358
1462
  ${this.renderTrends(t)}
1359
1463
  ${this.renderDetailChart()}
1360
1464
  ${this.renderDetailHistory(t)}
1361
- `}renderDetailHeader(t,s){return a`
1465
+ `}renderDetailHeader(t,e){return a`
1362
1466
  <div class="perf-detail-header">
1363
1467
  <div class="perf-detail-title">
1364
- <span class="perf-badge perf-badge-lg" style="color:${s.color};background:${s.bg};border-color:${s.border}">${s.label}</span>
1468
+ <span class="perf-badge perf-badge-lg" style="color:${e.color};background:${e.bg};border-color:${e.border}">${e.label}</span>
1365
1469
  <span>${t.endpoint}</span>
1366
- ${t.baselineP95Ms?a`<span class="perf-baseline-hint">Baseline: ${v(t.baselineP95Ms)}</span>`:d}
1470
+ ${t.baselineP95Ms?a`<span class="perf-baseline-hint">Baseline: ${_(t.baselineP95Ms)}</span>`:p}
1367
1471
  </div>
1368
1472
  </div>
1369
- `}renderDetailMetrics(t,s,r){return a`
1473
+ `}renderDetailMetrics(t,e,r){return a`
1370
1474
  <div class="perf-metric-row">
1371
1475
  <div class="perf-metric-card">
1372
1476
  <span class="perf-metric-label">P95</span>
1373
- <span class="perf-metric-value" style="color:${s.color}">${v(t.p95Ms)}</span>
1477
+ <span class="perf-metric-value" style="color:${e.color}">${_(t.p95Ms)}</span>
1374
1478
  </div>
1375
1479
  <div class="perf-metric-card">
1376
1480
  <span class="perf-metric-label">Errors</span>
@@ -1383,71 +1487,71 @@ span.perf-breakdown-dot.perf-breakdown-app{background:var(--breakdown-app)}
1383
1487
  <span class="perf-metric-value" style="color:${t.avgQueryCount>5?"var(--amber)":"var(--text)"}">${t.avgQueryCount}</span>
1384
1488
  </div>
1385
1489
  </div>
1386
- `}renderDetailBreakdown(t){let s=(t.avgQueryTimeMs||0)+(t.avgFetchTimeMs||0)+(t.avgAppTimeMs||0);if(s<=0)return d;let r=Math.round((t.avgQueryTimeMs||0)/s*100),o=Math.round((t.avgFetchTimeMs||0)/s*100),n=Math.max(0,100-r-o);return a`
1490
+ `}renderDetailBreakdown(t){let e=(t.avgQueryTimeMs||0)+(t.avgFetchTimeMs||0)+(t.avgAppTimeMs||0);if(e<=0)return p;let r=Math.round((t.avgQueryTimeMs||0)/e*100),i=Math.round((t.avgFetchTimeMs||0)/e*100),n=Math.max(0,100-r-i);return a`
1387
1491
  <div class="perf-breakdown">
1388
1492
  <div class="perf-section-title">Time Breakdown</div>
1389
1493
  <div class="perf-breakdown-bar">
1390
- ${r>0?a`<div class="perf-breakdown-seg perf-breakdown-db" style="width:${r}%"></div>`:d}
1391
- ${o>0?a`<div class="perf-breakdown-seg perf-breakdown-fetch" style="width:${o}%"></div>`:d}
1392
- ${n>0?a`<div class="perf-breakdown-seg perf-breakdown-app" style="width:${n}%"></div>`:d}
1494
+ ${r>0?a`<div class="perf-breakdown-seg perf-breakdown-db" style="width:${r}%"></div>`:p}
1495
+ ${i>0?a`<div class="perf-breakdown-seg perf-breakdown-fetch" style="width:${i}%"></div>`:p}
1496
+ ${n>0?a`<div class="perf-breakdown-seg perf-breakdown-app" style="width:${n}%"></div>`:p}
1393
1497
  </div>
1394
1498
  <div class="perf-breakdown-legend">
1395
- <span class="perf-breakdown-item"><span class="perf-breakdown-dot perf-breakdown-db"></span>DB ${v(t.avgQueryTimeMs||0)} (${r}%)</span>
1396
- <span class="perf-breakdown-item"><span class="perf-breakdown-dot perf-breakdown-fetch"></span>Fetch ${v(t.avgFetchTimeMs||0)} (${o}%)</span>
1397
- <span class="perf-breakdown-item"><span class="perf-breakdown-dot perf-breakdown-app"></span>App ${v(t.avgAppTimeMs||0)} (${n}%)</span>
1499
+ <span class="perf-breakdown-item"><span class="perf-breakdown-dot perf-breakdown-db"></span>DB ${_(t.avgQueryTimeMs||0)} (${r}%)</span>
1500
+ <span class="perf-breakdown-item"><span class="perf-breakdown-dot perf-breakdown-fetch"></span>Fetch ${_(t.avgFetchTimeMs||0)} (${i}%)</span>
1501
+ <span class="perf-breakdown-item"><span class="perf-breakdown-dot perf-breakdown-app"></span>App ${_(t.avgAppTimeMs||0)} (${n}%)</span>
1398
1502
  </div>
1399
1503
  </div>
1400
- `}renderCallers(t){let s=this.getCallers(t);return s.length===0?d:a`
1504
+ `}renderCallers(t){let e=this.getCallers(t);return e.length===0?p:a`
1401
1505
  <div class="perf-callers">
1402
1506
  <div class="perf-section-title">Called By</div>
1403
1507
  <div class="perf-callers-list">
1404
- ${s.map(r=>a`
1508
+ ${e.map(r=>a`
1405
1509
  <div class="perf-caller-row">
1406
1510
  <span class="perf-caller-name">${r.label}</span>
1407
1511
  <span class="perf-caller-count">${r.count} call${r.count!==1?"s":""}</span>
1408
- <span class="perf-caller-avg">avg ${v(r.avgMs)}</span>
1512
+ <span class="perf-caller-avg">avg ${_(r.avgMs)}</span>
1409
1513
  </div>
1410
1514
  `)}
1411
1515
  </div>
1412
1516
  </div>
1413
- `}renderQueryBreakdown(){return this.queryBreakdownLoading?a`<div class="perf-queries"><div class="perf-section-title">DB Queries</div><div class="perf-queries-loading">Loading...</div></div>`:this.queryBreakdown.length===0?d:a`
1517
+ `}renderQueryBreakdown(){return this.queryBreakdownLoading?a`<div class="perf-queries"><div class="perf-section-title">DB Queries</div><div class="perf-queries-loading">Loading...</div></div>`:this.queryBreakdown.length===0?p:a`
1414
1518
  <div class="perf-queries">
1415
1519
  <div class="perf-section-title">DB Queries</div>
1416
1520
  <div class="perf-queries-list">
1417
1521
  ${this.queryBreakdown.map(t=>a`
1418
1522
  <div class="perf-query-row">
1419
1523
  <span class="perf-query-label">${t.label}</span>
1420
- <span class="perf-query-avg">avg ${v(t.avgMs)}</span>
1524
+ <span class="perf-query-avg">avg ${_(t.avgMs)}</span>
1421
1525
  <span class="perf-query-count">${t.count} call${t.count!==1?"s":""}</span>
1422
1526
  </div>
1423
1527
  `)}
1424
1528
  </div>
1425
1529
  </div>
1426
- `}renderTrends(t){let s=t.sessions;if(!s||s.length===0)return d;let r=s.slice(-10);return a`
1530
+ `}renderTrends(t){let e=t.sessions;if(!e||e.length===0)return p;let r=e.slice(-10);return a`
1427
1531
  <div class="perf-trends">
1428
1532
  <div class="perf-section-title">Session Trend</div>
1429
1533
  <div class="perf-trends-list">
1430
- ${r.map((o,n)=>{let l=n>0?r[n-1].p95DurationMs:null,c=l!==null?o.p95DurationMs>l*1.2?"slower":o.p95DurationMs<l*.8?"faster":"":"",p=this.formatTimeAgo(o.startedAt),h=n===r.length-1,m=this.healthGradeForDuration(o.p95DurationMs,t.baselineP95Ms);return a`
1534
+ ${r.map((i,n)=>{let l=n>0?r[n-1].p95DurationMs:null,c=l!==null?i.p95DurationMs>l*1.2?"slower":i.p95DurationMs<l*.8?"faster":"":"",d=this.formatTimeAgo(i.startedAt),h=n===r.length-1,m=this.healthGradeForDuration(i.p95DurationMs,t.baselineP95Ms);return a`
1431
1535
  <div class="perf-trend-row ${h?"perf-trend-current":""}">
1432
- <span class="perf-trend-time">${h?"Current":p}</span>
1536
+ <span class="perf-trend-time">${h?"Current":d}</span>
1433
1537
  <span class="perf-trend-p95">
1434
1538
  <span class="perf-hm-p95" style="color:${m.color};background:${m.bg};border-color:${m.border}">
1435
- p95: ${v(o.p95DurationMs)}
1539
+ p95: ${_(i.p95DurationMs)}
1436
1540
  </span>
1437
1541
  </span>
1438
- <span class="perf-trend-reqs">${o.requestCount} req${o.requestCount!==1?"s":""}</span>
1439
- <span class="perf-trend-errs" style="color:${o.errorCount>0?"var(--red)":"var(--text-dim)"}">${o.errorCount} err${o.errorCount!==1?"s":""}</span>
1440
- ${c?a`<span class="perf-trend-arrow ${c==="slower"?"perf-trend-slower":"perf-trend-faster"}">${c==="slower"?"\u2191 slower":"\u2193 faster"}</span>`:d}
1542
+ <span class="perf-trend-reqs">${i.requestCount} req${i.requestCount!==1?"s":""}</span>
1543
+ <span class="perf-trend-errs" style="color:${i.errorCount>0?"var(--red)":"var(--text-dim)"}">${i.errorCount} err${i.errorCount!==1?"s":""}</span>
1544
+ ${c?a`<span class="perf-trend-arrow ${c==="slower"?"perf-trend-slower":"perf-trend-faster"}">${c==="slower"?"\u2191 slower":"\u2193 faster"}</span>`:p}
1441
1545
  </div>
1442
1546
  `})}
1443
1547
  </div>
1444
1548
  </div>
1445
- `}formatTimeAgo(t){let s=Date.now()-t,r=Math.round(s/6e4);if(r<1)return "just now";if(r<60)return `${r}m ago`;let o=Math.round(r/60);return o<24?`${o}h ago`:`${Math.round(o/24)}d ago`}renderDetailChart(){return a`
1549
+ `}formatTimeAgo(t){let e=Date.now()-t,r=Math.round(e/6e4);if(r<1)return "just now";if(r<60)return `${r}m ago`;let i=Math.round(r/60);return i<24?`${i}h ago`:`${Math.round(i/24)}d ago`}renderDetailChart(){return a`
1446
1550
  <div class="perf-chart-wrap">
1447
1551
  <div class="perf-section-title">Response Time</div>
1448
1552
  <canvas id="perf-detail-canvas" class="perf-canvas" style="width:100%;height:240px"></canvas>
1449
1553
  </div>
1450
- `}renderDetailHistory(t){if(t.requests.length===0)return d;let s=[];for(let r=t.requests.length-1;r>=0&&s.length<50;r--)s.push({point:t.requests[r],originalIndex:r});return a`
1554
+ `}renderDetailHistory(t){if(t.requests.length===0)return p;let e=[];for(let r=t.requests.length-1;r>=0&&e.length<50;r--)e.push({point:t.requests[r],originalIndex:r});return a`
1451
1555
  <div class="perf-history-wrap">
1452
1556
  <table class="perf-table">
1453
1557
  <thead>
@@ -1461,63 +1565,363 @@ span.perf-breakdown-dot.perf-breakdown-app{background:var(--breakdown-app)}
1461
1565
  </tr>
1462
1566
  </thead>
1463
1567
  <tbody>
1464
- ${s.map(r=>this.renderHistoryRow(r.point,r.originalIndex,t.baselineP95Ms))}
1568
+ ${e.map(r=>this.renderHistoryRow(r.point,r.originalIndex,t.baselineP95Ms))}
1465
1569
  </tbody>
1466
1570
  </table>
1467
1571
  </div>
1468
- `}renderHistoryRow(t,s,r){let o=this.healthGradeForDuration(t.durationMs,r),n=new Date(t.timestamp).toLocaleTimeString([],{hour:"2-digit",minute:"2-digit",second:"2-digit"}),l=t.statusCode>=400,c=t.queryTimeMs||0,p=t.fetchTimeMs||0,h=Math.max(0,t.durationMs-c-p);return a`
1469
- <tr class="perf-table-row ${l?"perf-row-err":""}" data-req-idx=${s}>
1572
+ `}renderHistoryRow(t,e,r){let i=this.healthGradeForDuration(t.durationMs,r),n=new Date(t.timestamp).toLocaleTimeString([],{hour:"2-digit",minute:"2-digit",second:"2-digit"}),l=t.statusCode>=400,c=t.queryTimeMs||0,d=t.fetchTimeMs||0,h=Math.max(0,t.durationMs-c-d);return a`
1573
+ <tr class="perf-table-row ${l?"perf-row-err":""}" data-req-idx=${e}>
1470
1574
  <td class="perf-td-muted">${n}</td>
1471
1575
  <td>
1472
- <span class="perf-badge perf-badge-sm" style="color:${o.color};background:${o.bg};border-color:${o.border}">${o.label}</span>
1576
+ <span class="perf-badge perf-badge-sm" style="color:${i.color};background:${i.bg};border-color:${i.border}">${i.label}</span>
1473
1577
  </td>
1474
- <td>${v(t.durationMs)}</td>
1578
+ <td>${_(t.durationMs)}</td>
1475
1579
  <td>
1476
- ${c>0?a`<span class="perf-bd-tag perf-bd-tag-db">DB ${v(c)}</span>`:d}
1477
- ${p>0?a`<span class="perf-bd-tag perf-bd-tag-fetch">Fetch ${v(p)}</span>`:d}
1478
- <span class="perf-bd-tag perf-bd-tag-app">App ${v(h)}</span>
1580
+ ${c>0?a`<span class="perf-bd-tag perf-bd-tag-db">DB ${_(c)}</span>`:p}
1581
+ ${d>0?a`<span class="perf-bd-tag perf-bd-tag-fetch">Fetch ${_(d)}</span>`:p}
1582
+ <span class="perf-bd-tag perf-bd-tag-app">App ${_(h)}</span>
1479
1583
  </td>
1480
1584
  <td class="perf-td-center" style="color:${l?"var(--red)":"var(--text-muted)"}">${t.statusCode}</td>
1481
1585
  <td class="perf-td-right perf-td-muted">${t.queryCount}</td>
1482
1586
  </tr>
1483
- `}};u([R({context:x})],M.prototype,"store",2),u([_()],M.prototype,"selectedEndpoint",2),u([_()],M.prototype,"graphData",2),u([_()],M.prototype,"loadError",2),u([_()],M.prototype,"queryBreakdown",2),u([_()],M.prototype,"queryBreakdownLoading",2),M=u([g("bk-performance-view")],M);function _r(i){return i===0?"<1ms":v(i)}var w=class extends f{constructor(){super(...arguments);this.requestId="";this.requestStarted=0;this.data=null;this.loading=false;this.failed=false;this.expandedSqlIdx=-1;}createRenderRoot(){return this}connectedCallback(){super.connectedCallback(),this.store.addEventListener("state-changed",()=>this.requestUpdate()),this.requestId&&this.loadTimeline();}async loadTimeline(){if(!this.requestId)return;let t=w.cache.get(this.requestId);if(t){this.data=t;return}this.loading=true;try{let s=await fetch(`${$.activity}?requestId=${this.requestId}`);if(!s.ok){this.failed=!0,this.loading=!1;return}let r=await s.json();if(w.cache.size>=pe){let o=w.cache.keys().next().value;o!==void 0&&w.cache.delete(o);}w.cache.set(this.requestId,r),this.data=r,this.loading=!1;}catch(s){console.debug("[brakit] timeline load failed:",s),this.failed=true,this.loading=false;}}toggleSql(t,s){s.stopPropagation(),this.expandedSqlIdx=this.expandedSqlIdx===t?-1:t;}copySql(t,s){s.stopPropagation(),navigator.clipboard.writeText(t).then(()=>C.show("SQL copied")).catch(()=>C.show("Copy failed"));}render(){if(this.loading)return a`<div class="tl-loading">Loading activity...</div>`;if(this.failed||!this.data||this.data.total===0)return d;let t=this.data,s=t.timeline[0]?.timestamp??0;return a`
1587
+ `}};u([I({context:A})],Q.prototype,"store",2),u([b()],Q.prototype,"selectedEndpoint",2),u([b()],Q.prototype,"graphData",2),u([b()],Q.prototype,"loadError",2),u([b()],Q.prototype,"queryBreakdown",2),u([b()],Q.prototype,"queryBreakdownLoading",2),Q=u([S("bk-performance-view")],Q);var Xe={auth:{label:"Auth",color:"#059669",icon:"\u{1F6E1}",tooltip:"Highlight which endpoints require authentication and which are unprotected"},security:{label:"Security",color:"#dc2626",icon:"\u26A0",tooltip:"Show security findings like exposed secrets, token leaks, and PII exposure"},performance:{label:"Perf",color:"#2563eb",icon:"\u26A1",tooltip:"Color endpoints by P95 latency \u2014 green (fast) to red (slow)"},issues:{label:"Issues",color:"#d97706",icon:"\u25CF",tooltip:"Badge endpoints with open issues like N+1 queries or redundant calls"},heat:{label:"Heat",color:"#ef4444",icon:"\u{1F525}",tooltip:"Color nodes and edges by traffic volume \u2014 blue (low) to red (hot)"}},At={action:{fill:"#faf5ff",stroke:"#a855f7",icon:"\u25B6",columnHeader:"ACTIONS"},endpoint:{fill:"#f8fafc",stroke:"#6366f1",icon:"\u26A1",columnHeader:"ENDPOINTS"},table:{fill:"#f0fdf4",stroke:"#16a34a",icon:"\u229E",columnHeader:"TABLES"},external:{fill:"#fffbeb",stroke:"#d97706",icon:"\u25C6",columnHeader:"EXTERNAL"}},fe={triggers:"#a855f7",reads:"#6366f1",writes:"#ef4444",fetches:"#f59e0b",calls:"#22c55e"},yi=100,_i=300,$i=800;function It(o){return o<yi?"#22c55e":o<_i?"#3b82f6":o<$i?"#eab308":"#ef4444"}var xi=.25,Si=.5,Ti=.75;function Ve(o){return o<xi?"#3b82f6":o<Si?"#22c55e":o<Ti?"#eab308":"#ef4444"}var zs="#4338ca",Js="#e0e7ff",Zs="#818cf8",tr="#eef2ff",Ke="#7c3aed",er="#6366f1",ve="#f97316",sr="#ecfdf5",ze="#059669",rr="#fef2f2",Je="#dc2626",ir="#fffbeb",Ze="#d97706",ct="#ef4444",or=.2,nr=3,ts=1.2,Kt=40;var ar=800,lr=500;function Ci(o){return Math.max(140,o.length*7.2+36)}function es(o,s){return Math.round(36+o.stats.requestCount/s*28)}function Li(o){return o.length>0?Math.max(140,...o.map(s=>Ci(s.label))):0}function dr(o,s,t){let e=[];for(let r of s){let i=r.source===o?r.target:r.target===o?r.source:null;if(i){let n=t.get(i);n&&e.push(n.y+n.h/2);}}return e.length>0?e.reduce((r,i)=>r+i,0)/e.length:1/0}function hr(o,s){let t=f=>o.filter(g=>g.type===f).sort((g,T)=>T.stats.requestCount-g.stats.requestCount),e=t("action"),r=t("endpoint"),i=t("table"),n=t("external"),l=Math.max(1,...o.map(f=>f.stats.requestCount)),c=new Map,d=[],h=[],m=50,v=[{type:"action",items:e},{type:"endpoint",items:r},{type:"table",items:i},{type:"external",items:n}];for(let f of v)if(f.items.length>0){let g=Li(f.items);h.push({type:f.type,items:f.items,width:g,x:m}),m+=g+160;}let x=h[0];if(x){let f=74;for(let g of x.items){let T=es(g,l),R={id:g.id,x:x.x,y:f,w:x.width,h:T,label:g.label,type:g.type,stats:g.stats,annotations:g.annotations};d.push(R),c.set(g.id,R),f+=T+10;}}for(let f=1;f<h.length;f++){let g=h[f],T=[...g.items].sort((C,q)=>dr(C.id,s,c)-dr(q.id,s,c)),R=d.filter(C=>C.x===h[f-1].x),H=Math.min(...R.map(C=>C.y)),B=Math.max(...R.map(C=>C.y+C.h))-H,V=T.reduce((C,q)=>C+es(q,l)+10,-10),G=H+Math.max(0,(B-V)/2);for(let C of T){let q=es(C,l),rs={id:C.id,x:g.x,y:G,w:g.width,h:q,label:C.label,type:C.type,stats:C.stats,annotations:C.annotations};d.push(rs),c.set(C.id,rs),G+=q+10;}}let y=[];for(let f of s){let g=c.get(f.source),T=c.get(f.target);if(!g||!T)continue;let R=g.x<T.x,H=R?g.x+g.w:g.x,X=g.y+g.h/2,B=R?T.x:T.x+T.w,V=T.y+T.h/2,G=[];f.stats.frequency>1&&G.push(`${f.stats.frequency}\xD7`),G.push(f.type),f.stats.avgLatencyMs>0&&G.push(`${f.stats.avgLatencyMs}ms`),y.push({key:f.id,sx:H,sy:X,tx:B,ty:V,label:G.join(" \xB7 "),color:fe[f.type]||"#94a3b8",thickness:Math.min(.75+Math.log2(f.stats.frequency+1)*.35,2.5),dashed:f.type==="reads"||f.type==="writes",data:f});}let k=d.reduce((f,g)=>Math.max(f,g.x+g.w),0),$=d.reduce((f,g)=>Math.max(f,g.y+g.h),0);return {nodes:d,edges:y,width:k+100,height:Math.max($+50,250)}}function ur(o){let s=o.charCodeAt(0);return s>=48&&s<=57||s>=65&&s<=70||s>=97&&s<=102}function Mi(o){if(o.length!==36)return false;for(let s=0;s<o.length;s++)if(s===8||s===13||s===18||s===23){if(o[s]!=="-")return false}else if(!ur(o[s]))return false;return true}function Ni(o){if(!o.length)return false;for(let s=0;s<o.length;s++){let t=o.charCodeAt(s);if(t<48||t>57)return false}return true}function Oi(o){if(o.length<12)return false;for(let s=0;s<o.length;s++)if(!ur(o[s]))return false;return true}function ki(o){if(o.length<8)return false;let s=false,t=false;for(let e=0;e<o.length;e++){let r=o.charCodeAt(e);if(r>=65&&r<=90||r>=97&&r<=122)s=true;else if(r>=48&&r<=57)t=true;else if(r!==95&&r!==45)return false}return s&&t}var Di=":id";function Hi(o){return Mi(o)||Ni(o)||Oi(o)||ki(o)?Di:o}function ss(o,s){let t=s.split("?")[0];return `${o} ${t.split("/").map(e=>e&&Hi(e)).join("/")}`}function mr(o,s,t){let e=[...o],r=[...s],i=new Set(e.map(l=>l.id)),n=new Map;for(let l of t){let c=l.label||"Unknown",d=n.get(c);d||(d={endpointKeys:new Set,count:0,totalMs:0},n.set(c,d)),d.count++,d.totalMs+=l.totalDurationMs;for(let h of l.requests)h.path?.startsWith(F)||d.endpointKeys.add(ss(h.method,h.path));}for(let[l,c]of n){let d=`action:${l}`;i.has(d)||(e.push({id:d,type:"action",label:l,stats:{requestCount:c.count,avgLatencyMs:c.count>0?Math.round(c.totalMs/c.count):0,errorRate:0,avgQueryCount:0}}),i.add(d));for(let h of c.endpointKeys){let m=`endpoint:${h}`;if(i.has(m)){let v=`${d} -> ${m}`;r.find(x=>x.id===v)||r.push({id:v,source:d,target:m,type:"triggers",stats:{frequency:c.count,avgLatencyMs:0}});}}}return {nodes:e,edges:r}}function fr(o){let s=new Map;for(let t of o){let e=t.label||"Unknown",r=s.get(e);r||(r={keys:new Set,count:0,totalMs:0},s.set(e,r)),r.count++,r.totalMs+=t.totalDurationMs;for(let i of t.requests)i.path?.startsWith(F)||r.keys.add(ss(i.method,i.path));}return [...s.entries()].map(([t,e])=>({label:t,occurrences:e.count,endpointKeys:e.keys,avgDurationMs:e.count>0?Math.round(e.totalMs/e.count):0}))}function be(o,s){let t=`event=${encodeURIComponent(o)}${s?`&detail=${encodeURIComponent(s)}`:""}`;fetch(`${w.tab}?${t}`).catch(()=>{});}var M=class extends E{constructor(){super(...arguments);this.graphNodes=[];this.graphEdges=[];this.locked=null;this.hovered=null;this.loading=true;this.activeLayers=new Set;this.searchQuery="";this.viewTransform={x:0,y:0,scale:1};this.isPanning=false;this.panStart={x:0,y:0,vtx:0,vty:0};this.dragging=null;this.wasDragging=false;this.nodePositionOverrides=new Map;this.detailTab="overview";this.consolidatedFlows=[];this.activeFlowIdx=-1;this.focusIdx=-1;this.refreshTimer=null;}createRenderRoot(){return this}connectedCallback(){super.connectedCallback(),this.loadData(),this.refreshTimer=setInterval(()=>this.loadData(),4e3);}disconnectedCallback(){super.disconnectedCallback(),this.refreshTimer&&clearInterval(this.refreshTimer);}async loadData(){try{let[t,e]=await Promise.all([fetch(`${w.graph}?level=endpoints`),fetch(w.flows)]),r=await t.json(),i=await e.json(),n=mr(r.nodes||[],r.edges||[],i.flows||[]);this.graphNodes=n.nodes,this.graphEdges=n.edges,this.consolidatedFlows=fr(i.flows||[]),this.nodePositionOverrides.size===0&&this.graphNodes.length>0&&this.tryLoadPersistedPositions(),this.loading=!1;}catch{this.loading=false;}}getPositionStorageKey(){let t=this.graphNodes.map(r=>r.id).sort().join(","),e=0;for(let r=0;r<t.length;r++)e=(e<<5)-e+t.charCodeAt(r)|0;return `bk-graph-pos-${e}`}persistPositions(){if(this.nodePositionOverrides.size!==0)try{let t=Object.fromEntries(this.nodePositionOverrides);localStorage.setItem(this.getPositionStorageKey(),JSON.stringify(t));}catch{}}tryLoadPersistedPositions(){try{let t=localStorage.getItem(this.getPositionStorageKey());if(t){let e=JSON.parse(t);this.nodePositionOverrides=new Map(Object.entries(e));}}catch{}}get activeNodeId(){return this.locked??this.hovered}getHighlightedNodeIds(){let t=this.activeNodeId;if(!t)return null;let e=new Set([t]),r=true;for(;r;){r=false;for(let i of this.graphEdges)e.has(i.source)&&!e.has(i.target)&&(e.add(i.target),r=true);}return e}getFlowTraceNodeIds(){if(this.activeFlowIdx<0||this.activeFlowIdx>=this.consolidatedFlows.length)return null;let t=this.consolidatedFlows[this.activeFlowIdx],e=new Set;e.add(`action:${t.label}`);for(let r of t.endpointKeys)e.add(`endpoint:${r}`);for(let r of this.graphEdges)e.has(r.source)&&e.add(r.target);return e}getFlowTraceEdgeIds(){let t=this.getFlowTraceNodeIds();if(!t)return null;let e=new Set;for(let r of this.graphEdges)t.has(r.source)&&t.has(r.target)&&e.add(r.id);return e}matchesSearch(t){return this.searchQuery?t.toLowerCase().includes(this.searchQuery.toLowerCase()):true}handlePanStart(t){t.button===0&&(t.target.closest(".graph-g")||(this.isPanning=true,this.panStart={x:t.clientX,y:t.clientY,vtx:this.viewTransform.x,vty:this.viewTransform.y}));}handlePanMove(t){if(this.dragging){let e=t.currentTarget.getBoundingClientRect(),r=(t.clientX-e.left-this.viewTransform.x)/this.viewTransform.scale,i=(t.clientY-e.top-this.viewTransform.y)/this.viewTransform.scale;this.nodePositionOverrides.set(this.dragging.nodeId,{x:r-this.dragging.offsetX,y:i-this.dragging.offsetY}),this.requestUpdate();return}this.isPanning&&(this.viewTransform={...this.viewTransform,x:this.panStart.vtx+(t.clientX-this.panStart.x),y:this.panStart.vty+(t.clientY-this.panStart.y)});}handlePanEnd(){this.dragging&&(this.persistPositions(),this.dragging=null,this.wasDragging=true,requestAnimationFrame(()=>{this.wasDragging=false;})),this.isPanning=false;}resetView(){this.viewTransform={x:0,y:0,scale:1};}zoomIn(){this.viewTransform={...this.viewTransform,scale:Math.min(nr,this.viewTransform.scale*ts)};}zoomOut(){this.viewTransform={...this.viewTransform,scale:Math.max(or,this.viewTransform.scale/ts)};}resetLayout(){this.nodePositionOverrides.clear();try{localStorage.removeItem(this.getPositionStorageKey());}catch{}this.viewTransform={x:0,y:0,scale:1},this.requestUpdate(),be("layout_reset");}startNodeDrag(t,e,r){t.stopPropagation();let i=t.currentTarget.closest("svg").getBoundingClientRect(),n=(t.clientX-i.left-this.viewTransform.x)/this.viewTransform.scale,l=(t.clientY-i.top-this.viewTransform.y)/this.viewTransform.scale;this.dragging={nodeId:e,offsetX:n-r.x,offsetY:l-r.y};}handleKeyDown(t){let e=this.graphNodes;if(t.key==="/"){t.preventDefault(),this.querySelector(".graph-search-input")?.focus();return}if(t.key==="Escape"){this.locked=null,this.searchQuery="",this.focusIdx=-1,this.activeFlowIdx=-1;return}if(t.key==="Tab"){t.preventDefault(),this.focusIdx=t.shiftKey?this.focusIdx<=0?e.length-1:this.focusIdx-1:(this.focusIdx+1)%e.length,this.hovered=e[this.focusIdx]?.id??null;return}if(t.key==="Enter"&&this.focusIdx>=0){let r=e[this.focusIdx];r&&(this.locked=this.locked===r.id?null:r.id);return}if(t.key==="+"||t.key==="="){this.zoomIn();return}if(t.key==="-"){this.zoomOut();return}if(t.key==="ArrowUp"){this.viewTransform={...this.viewTransform,y:this.viewTransform.y+Kt};return}if(t.key==="ArrowDown"){this.viewTransform={...this.viewTransform,y:this.viewTransform.y-Kt};return}if(t.key==="ArrowLeft"){this.viewTransform={...this.viewTransform,x:this.viewTransform.x+Kt};return}if(t.key==="ArrowRight"){this.viewTransform={...this.viewTransform,x:this.viewTransform.x-Kt};return}}render(){if(this.loading&&this.graphNodes.length===0)return a`<div class="graph-loading">Loading graph…</div>`;if(this.graphNodes.length===0)return a`
1588
+ <div class="graph-empty">
1589
+ <div class="graph-empty-icon">◎</div>
1590
+ <div class="graph-empty-title">No data yet</div>
1591
+ <div class="graph-empty-desc">Navigate your app to build the dependency graph.</div>
1592
+ </div>
1593
+ `;let t=hr(this.graphNodes,this.graphEdges);this.applyPositionOverrides(t);let e=this.getSelectedNodeDetail(),r=this.getHighlightedNodeIds(),i=this.getFlowTraceNodeIds(),n=this.getFlowTraceEdgeIds(),l=this.deduplicateColumnHeaders(t.nodes),c=Math.max(1,...this.graphNodes.map(h=>h.stats.requestCount)),d=this.viewTransform;return a`
1594
+ <div class="graph-wrapper" tabindex="0" @keydown=${this.handleKeyDown}
1595
+ @click=${h=>{let m=h.target;m.closest(".graph-detail")||m.closest(".graph-toolbar")||m.closest(".graph-float")||m.closest(".graph-g")||(this.locked=null);}}>
1596
+ ${this.renderToolbar()}
1597
+ <div class="graph-body">
1598
+ <div class="graph-canvas" style="position:relative">
1599
+ <svg width="100%" height="100%"
1600
+ viewBox="0 0 ${Math.max(t.width,ar)} ${Math.max(t.height,lr)}"
1601
+ class="graph-svg"
1602
+ style="cursor:${this.isPanning?"grabbing":"grab"}"
1603
+ @mousedown=${this.handlePanStart}
1604
+ @mousemove=${this.handlePanMove}
1605
+ @mouseup=${this.handlePanEnd}
1606
+ @mouseleave=${this.handlePanEnd}>
1607
+
1608
+ <g transform="translate(${d.x},${d.y}) scale(${d.scale})">
1609
+ ${O`${l.map(h=>O`
1610
+ <text x="${h.x}" y="${58}" class="graph-col-header">${h.label}</text>
1611
+ `)}`}
1612
+
1613
+ ${t.edges.map(h=>this.renderEdge(h,r,n,c))}
1614
+ ${t.nodes.map(h=>this.renderNode(h,r,i,c))}
1615
+ </g>
1616
+ </svg>
1617
+ ${this.renderFloatingControls()}
1618
+ </div>
1619
+ ${e?this.renderDetailPanel(e):p}
1620
+ </div>
1621
+ </div>
1622
+ `}applyPositionOverrides(t){for(let r of t.nodes){let i=this.nodePositionOverrides.get(r.id);i&&(r.x=i.x,r.y=i.y);}let e=new Map(t.nodes.map(r=>[r.id,r]));for(let r of t.edges){let i=e.get(r.data.source),n=e.get(r.data.target);if(i&&n){let l=i.x<n.x;r.sx=l?i.x+i.w:i.x,r.sy=i.y+i.h/2,r.tx=l?n.x:n.x+n.w,r.ty=n.y+n.h/2;}}}deduplicateColumnHeaders(t){let e=[],r=new Set;for(let i of t)r.has(i.type)||(r.add(i.type),e.push({x:i.x,label:At[i.type]?.columnHeader||i.type.toUpperCase()}));return e}renderToolbar(){return a`
1623
+ <div class="graph-toolbar">
1624
+ <div class="graph-layer-toggles">
1625
+ ${Object.keys(Xe).map(t=>{let e=Xe[t],r=this.activeLayers.has(t);return a`
1626
+ <button class="graph-layer-btn ${r?"active":""}"
1627
+ style="${r?`border-color:${e.color};color:${e.color}`:""}"
1628
+ @click=${()=>this.toggleLayer(t)}
1629
+ title="${e.tooltip}">
1630
+ ${e.icon} ${e.label}
1631
+ </button>
1632
+ `})}
1633
+ </div>
1634
+
1635
+ <div class="graph-search">
1636
+ <span class="graph-search-icon">⌕</span>
1637
+ <input class="graph-search-input" type="text" placeholder="Search nodes… ( / )"
1638
+ .value=${this.searchQuery}
1639
+ @input=${t=>{this.searchQuery=t.target.value;}}>
1640
+ ${this.searchQuery?a`
1641
+ <button class="graph-search-clear" @click=${()=>{this.searchQuery="";}}>✕</button>
1642
+ `:p}
1643
+ </div>
1644
+
1645
+ ${this.consolidatedFlows.length>0?a`
1646
+ <select class="graph-flow-picker" @change=${t=>{this.activeFlowIdx=parseInt(t.target.value,10),this.activeFlowIdx>=0&&be("flow_traced");}}>
1647
+ <option value="-1">Trace flow…</option>
1648
+ ${this.consolidatedFlows.map((t,e)=>a`
1649
+ <option value="${e}" ?selected=${this.activeFlowIdx===e}>${t.label} → ${t.endpointKeys.size} ep · ${t.occurrences}×</option>
1650
+ `)}
1651
+ </select>
1652
+ `:p}
1653
+
1654
+ ${this.activeLayers.has("auth")?a`
1655
+ <div class="graph-auth-legend">
1656
+ <span class="graph-auth-legend-item"><span style="color:${ze}">🛡</span> protected</span>
1657
+ <span class="graph-auth-legend-item"><span style="color:${ve};font-weight:700">!</span> no auth</span>
1658
+ </div>
1659
+ `:p}
1660
+ </div>
1661
+ `}renderFloatingControls(){let t=this.nodePositionOverrides.size>0,e=Math.round(this.viewTransform.scale*100);return a`
1662
+ <div class="graph-float">
1663
+ <button class="graph-float-btn" @click=${this.zoomOut} title="Zoom out (-)">−</button>
1664
+ <span class="graph-float-zoom">${e}%</span>
1665
+ <button class="graph-float-btn" @click=${this.zoomIn} title="Zoom in (+)">+</button>
1666
+ <span class="graph-float-sep"></span>
1667
+ <button class="graph-float-btn" @click=${this.resetView} title="Reset pan & zoom">⊙</button>
1668
+ ${t?a`
1669
+ <span class="graph-float-sep"></span>
1670
+ <button class="graph-float-btn graph-float-btn-accent" @click=${()=>this.resetLayout()} title="Reset layout to auto-arrange">
1671
+ ⟲ Reformat
1672
+ </button>
1673
+ `:p}
1674
+ <span class="graph-float-sep"></span>
1675
+ <button class="graph-float-btn" @click=${()=>this.captureScreenshot()} title="Save graph as PNG">
1676
+ 📷
1677
+ </button>
1678
+ </div>
1679
+ `}async captureScreenshot(){be("screenshot_captured");let t=this.querySelector(".graph-svg");if(!t)return;let e=t.cloneNode(true);e.setAttribute("xmlns","http://www.w3.org/2000/svg"),e.style.cssText="",e.removeAttribute("class");let r=document.createElement("style");r.textContent=`
1680
+ text { font-family: 'Inter', system-ui, -apple-system, sans-serif; }
1681
+ .graph-col-header { fill: #c4c4cc; font-size: 9px; font-weight: 600; letter-spacing: 1.5px; }
1682
+ .graph-flow-edge { stroke-dasharray: 6,4; }
1683
+ .graph-pulse { }
1684
+ `,e.insertBefore(r,e.firstChild);let n=document.createElementNS("http://www.w3.org/2000/svg","rect");n.setAttribute("width","100%"),n.setAttribute("height","100%"),n.setAttribute("fill","#ffffff"),e.insertBefore(n,e.firstChild);let l=e.getAttribute("viewBox")||"0 0 800 500",[,,c,d]=l.split(" ").map(Number),h=2,m=c*h,v=d*h,x=new XMLSerializer().serializeToString(e),y=new Blob([x],{type:"image/svg+xml;charset=utf-8"}),k=URL.createObjectURL(y),$=new Image;$.onload=()=>{let f=document.createElement("canvas");f.width=m,f.height=v;let g=f.getContext("2d");g.fillStyle="#ffffff",g.fillRect(0,0,m,v),g.drawImage($,0,0,m,v),URL.revokeObjectURL(k),f.toBlob(T=>{if(!T)return;let R=document.createElement("a");R.href=URL.createObjectURL(T),R.download=`brakit-graph-${new Date().toISOString().slice(0,19).replace(/[T:]/g,"-")}.png`,document.body.appendChild(R),R.click(),document.body.removeChild(R),URL.revokeObjectURL(R.href);},"image/png");},$.src=k;}toggleLayer(t){let e=new Set(this.activeLayers);e.has(t)?e.delete(t):(e.add(t),be("layer_toggled",t)),this.activeLayers=e;}renderNode(t,e,r,i){let n=this.activeNodeId,l=e===null||e.has(t.id),c=n===t.id,d=this.locked===t.id,h=r?.has(t.id)??false,m=this.matchesSearch(t.label),v=At[t.type]||At.endpoint,x=d?zs:c?Zs:v.stroke,y=d?Js:c?tr:v.fill,k=d?2:c?1.5:.75,$=l?1:.08;this.searchQuery&&!m&&($=.05),r&&!h&&($=Math.min($,.08)),h&&($=1,x=Ke);let f=this.searchQuery&&m,g=t.annotations,T=this.activeLayers;T.has("performance")&&g?.p95Ms!==void 0&&t.type==="endpoint"&&(y=It(g.p95Ms)+"18"),T.has("heat")&&(y=Ve(t.stats.requestCount/i)+"20");let R=T.has("auth")&&t.type==="endpoint"&&!g?.hasAuth,H=T.has("auth")&&g?.hasAuth,X=T.has("security")?g?.securityFindings?.length??0:0,B=g?.securityFindings?.some(q=>q.severity==="critical"),V=T.has("issues")?g?.openIssueCount??0:0,G=this.nodeSubtitle(t),C=T.has("performance")&&g?.p95Ms!==void 0&&t.type==="endpoint";return O`
1685
+ <g class="graph-g" transform="translate(${t.x},${t.y})" style="opacity:${$};cursor:pointer;transition:opacity .15s,transform .1s"
1686
+ @click=${q=>{q.stopPropagation(),!this.wasDragging&&(this.locked=this.locked===t.id?null:t.id,this.detailTab="overview");}}
1687
+ @mouseenter=${()=>{this.hovered=t.id;}}
1688
+ @mouseleave=${()=>{this.hovered=null;}}
1689
+ @mousedown=${q=>{q.detail>=2||this.startNodeDrag(q,t.id,t);}}>
1690
+
1691
+ ${f?O`
1692
+ <rect x="-3" y="-3" width="${t.w+6}" height="${t.h+6}" rx="9" fill="none"
1693
+ stroke="${er}" stroke-width="2" stroke-dasharray="4,2"/>
1694
+ `:p}
1695
+
1696
+ ${R?O`
1697
+ <rect width="${t.w}" height="${t.h}" rx="8" fill="${y}" stroke="${ve}"
1698
+ stroke-width="1.2" stroke-dasharray="5,3"/>
1699
+ `:O`
1700
+ <rect width="${t.w}" height="${t.h}" rx="8" fill="${y}" stroke="${x}" stroke-width="${k}"/>
1701
+ `}
1702
+
1703
+ <text x="12" y="${t.h/2-4}" fill="#1e293b" font-size="11.5" font-weight="600"
1704
+ font-family="'Inter',system-ui,sans-serif">${v.icon} ${t.label}</text>
1705
+ <text x="12" y="${t.h/2+10}" fill="#a1a1aa" font-size="9"
1706
+ font-family="ui-monospace,monospace">${G}</text>
1707
+
1708
+ ${C?O`
1709
+ <text x="${t.w-8}" y="${t.h-6}" fill="${It(g.p95Ms)}" font-size="9"
1710
+ font-family="ui-monospace,monospace" text-anchor="end">p95: ${g.p95Ms}ms</text>
1711
+ `:p}
1712
+
1713
+ ${H?O`
1714
+ <g transform="translate(${t.w-24},3)">
1715
+ <title>Auth protected</title>
1716
+ <rect width="18" height="18" rx="3" fill="${sr}" stroke="${ze}" stroke-width="0.5"/>
1717
+ <text x="9" y="13" text-anchor="middle" font-size="10">🛡</text>
1718
+ </g>
1719
+ `:p}
1720
+
1721
+ ${R?O`
1722
+ <g transform="translate(${t.w-24},3)">
1723
+ <title>No auth detected — this endpoint may be unprotected</title>
1724
+ <rect width="18" height="18" rx="3" fill="#fff7ed" stroke="${ve}" stroke-width="0.5"/>
1725
+ <text x="9" y="13" text-anchor="middle" font-size="10" fill="#ea580c">!</text>
1726
+ </g>
1727
+ `:p}
1728
+
1729
+ ${X>0?O`
1730
+ <g transform="translate(${t.w-(H||R?46:24)},3)">
1731
+ <rect width="18" height="18" rx="3" fill="${B?rr:ir}"
1732
+ stroke="${B?Je:Ze}" stroke-width="0.5"
1733
+ class="${B?"graph-pulse":""}"/>
1734
+ <text x="9" y="13" text-anchor="middle" font-size="9" font-weight="600"
1735
+ fill="${B?Je:Ze}">${X}</text>
1736
+ </g>
1737
+ `:p}
1738
+
1739
+ ${V>0?O`
1740
+ <circle cx="${t.w-8}" cy="8" r="5" fill="${ct}" stroke="white" stroke-width="1"/>
1741
+ <text x="${t.w-8}" y="11" text-anchor="middle" font-size="7" fill="white" font-weight="700">${V}</text>
1742
+ `:t.stats.errorRate>.05?O`<circle cx="${t.w-12}" cy="12" r="4" fill="${ct}"/>`:p}
1743
+
1744
+ ${g?.isMiddleware&&T.has("auth")?O`
1745
+ <text x="${t.w}" y="${t.h+12}" text-anchor="end" font-size="8" fill="#6b7280"
1746
+ font-family="ui-monospace,monospace">middleware</text>
1747
+ `:p}
1748
+ </g>
1749
+ `}nodeSubtitle(t){switch(t.type){case "endpoint":return `${t.stats.requestCount} req \xB7 ${t.stats.avgLatencyMs}ms${t.stats.avgQueryCount>0?` \xB7 ${t.stats.avgQueryCount}q`:""}`;case "action":return `${t.stats.requestCount}\xD7 \xB7 ${t.stats.avgLatencyMs}ms`;case "table":return "table";default:return "service"}}renderEdge(t,e,r,i){let n=this.activeNodeId,l=e===null||e.has(t.data.source)&&e.has(t.data.target),c=r?.has(t.key)??false,d=l?n===null?.25:.6:.04,h=l&&n!==null,m=t.color,v=t.thickness;if(r&&!c&&(d=.04),c&&(d=.85,m=Ke,v=Math.max(v,1.8)),this.activeLayers.has("heat")&&!c){let V=Math.max(1,...this.graphEdges.map(C=>C.stats.frequency)),G=t.data.stats.frequency/V;m=Ve(G),l&&(d=Math.max(d,.4));}let x=this.activeLayers.has("issues")&&t.data.annotations?.hasIssue,y=Math.abs(t.tx-t.sx),k=Math.min(y*.45,120),$=t.sx<t.tx,f=$?t.sx+k:t.sx-k,g=$?t.tx-k:t.tx+k,T=(t.sx+t.tx)/2,R=(t.sy+t.ty)/2,H=4,X=x?ct:m,B=x?Math.max(v,1.5):v;return O`
1750
+ <g style="transition:opacity .15s">
1751
+ <path d="M${t.sx},${t.sy} C${f},${t.sy} ${g},${t.ty} ${t.tx},${t.ty}"
1752
+ fill="none" stroke="${X}" stroke-width="${B}"
1753
+ stroke-opacity="${d}" stroke-linecap="round"
1754
+ stroke-dasharray="${c?"6,4":t.dashed?"3,3":"none"}"
1755
+ class="${c?"graph-flow-edge":""}"/>
1756
+ <polygon points="${t.tx},${t.ty} ${t.tx+($?-H*1.5:H*1.5)},${t.ty-H} ${t.tx+($?-H*1.5:H*1.5)},${t.ty+H}"
1757
+ fill="${X}" fill-opacity="${d}"/>
1758
+ ${h?O`
1759
+ <rect x="${T-t.label.length*2.8-2}" y="${R-7}" width="${t.label.length*5.6+8}" height="14"
1760
+ rx="4" fill="white" fill-opacity="0.92" stroke="${m}" stroke-width="0.4" stroke-opacity="0.15"/>
1761
+ <text x="${T}" y="${R+3.5}" fill="${m}" font-size="8" font-weight="500"
1762
+ font-family="ui-monospace,monospace" text-anchor="middle" opacity="0.85">${t.label}</text>
1763
+ `:p}
1764
+ ${x?O`
1765
+ <text x="${T}" y="${R-10}" fill="${ct}" font-size="8" font-weight="600"
1766
+ text-anchor="middle">⚠ N+1</text>
1767
+ `:p}
1768
+ </g>
1769
+ `}renderDetailPanel(t){let{node:e,edges:r}=t,i=At[e.type]||At.endpoint,n=e.annotations,l=(n?.securityFindings?.length??0)>0,c=(n?.openIssueCount??0)>0,d=n?.p95Ms!==void 0,m=[{key:"overview",label:"Overview",show:true},{key:"security",label:`Security${l?` (${n.securityFindings.length})`:""}`,show:l},{key:"performance",label:"Perf",show:d},{key:"issues",label:`Issues${c?` (${n.openIssueCount})`:""}`,show:c}].filter(v=>v.show);return a`
1770
+ <div class="graph-detail">
1771
+ <div class="graph-detail-head">
1772
+ <div>
1773
+ <div class="graph-detail-badge" style="color:${i.stroke}">${i.icon} ${e.type}</div>
1774
+ <div class="graph-detail-name">${e.label}</div>
1775
+ ${n?.hasAuth?a`<span class="graph-detail-auth-badge">🛡 Authenticated</span>`:p}
1776
+ ${n?.isMiddleware?a`<span class="graph-detail-mw-badge">middleware</span>`:p}
1777
+ </div>
1778
+ <button class="graph-detail-close" @click=${()=>{this.locked=null;}}>✕</button>
1779
+ </div>
1780
+
1781
+ ${m.length>1?a`
1782
+ <div class="graph-detail-tabs">
1783
+ ${m.map(v=>a`
1784
+ <button class="graph-detail-tab ${this.detailTab===v.key?"active":""}"
1785
+ @click=${()=>{this.detailTab=v.key;}}>${v.label}</button>
1786
+ `)}
1787
+ </div>
1788
+ `:p}
1789
+
1790
+ ${this.detailTab==="overview"?this.renderOverviewTab(e,r):p}
1791
+ ${this.detailTab==="security"?this.renderSecurityTab(n):p}
1792
+ ${this.detailTab==="performance"?this.renderPerformanceTab(e,n):p}
1793
+ ${this.detailTab==="issues"?this.renderIssuesTab(n):p}
1794
+ </div>
1795
+ `}renderOverviewTab(t,e){return a`
1796
+ <div class="graph-detail-stats">
1797
+ <div class="graph-detail-stat">
1798
+ <div class="graph-detail-val">${t.stats.requestCount}</div>
1799
+ <div class="graph-detail-lbl">${t.type==="action"?"OCCURRENCES":"REQUESTS"}</div>
1800
+ </div>
1801
+ <div class="graph-detail-stat">
1802
+ <div class="graph-detail-val" style="color:${It(t.stats.avgLatencyMs)}">${t.stats.avgLatencyMs}ms</div>
1803
+ <div class="graph-detail-lbl">AVG LATENCY</div>
1804
+ </div>
1805
+ ${t.stats.avgQueryCount>0?a`
1806
+ <div class="graph-detail-stat">
1807
+ <div class="graph-detail-val">${t.stats.avgQueryCount}</div>
1808
+ <div class="graph-detail-lbl">QUERIES/REQ</div>
1809
+ </div>
1810
+ `:p}
1811
+ ${t.stats.errorRate>.01?a`
1812
+ <div class="graph-detail-stat">
1813
+ <div class="graph-detail-val" style="color:${ct}">${Math.round(t.stats.errorRate*100)}%</div>
1814
+ <div class="graph-detail-lbl">ERRORS</div>
1815
+ </div>
1816
+ `:p}
1817
+ </div>
1818
+
1819
+ ${e.length>0?a`
1820
+ <div class="graph-detail-sec">Connections</div>
1821
+ ${e.map(r=>{let i=r.source===this.locked,n=(i?r.target:r.source).replace(/^(action|endpoint|table|external):/,"");return a`
1822
+ <div class="graph-detail-conn">
1823
+ <span class="graph-detail-edge-dot" style="background:${fe[r.type]}"></span>
1824
+ <span class="graph-detail-edge-type">${r.type}</span>
1825
+ <span>${i?"\u2192":"\u2190"} ${n}</span>
1826
+ <span class="graph-detail-dim">${r.stats.frequency}× · ${r.stats.avgLatencyMs}ms</span>
1827
+ </div>
1828
+ `})}
1829
+ `:p}
1830
+
1831
+ ${e.some(r=>r.patterns?.length)?a`
1832
+ <div class="graph-detail-sec">SQL Patterns</div>
1833
+ ${e.filter(r=>r.patterns).flatMap(r=>r.patterns).map(r=>a`
1834
+ <pre class="graph-detail-sql">${r.length>200?r.slice(0,200)+"\u2026":r}</pre>
1835
+ `)}
1836
+ `:p}
1837
+ `}renderSecurityTab(t){return t?.securityFindings?.length?a`
1838
+ ${t.securityFindings.map(e=>a`
1839
+ <div class="graph-detail-finding">
1840
+ <span class="graph-detail-severity graph-detail-severity-${e.severity}">${e.severity}</span>
1841
+ <div class="graph-detail-finding-title">${e.title}</div>
1842
+ <div class="graph-detail-finding-meta">${e.rule} · ${e.count} occurrence${e.count!==1?"s":""}</div>
1843
+ </div>
1844
+ `)}
1845
+ `:a`<div class="graph-detail-empty">No security findings</div>`}renderPerformanceTab(t,e){return a`
1846
+ <div class="graph-detail-stats">
1847
+ ${e?.p95Ms!==void 0?a`
1848
+ <div class="graph-detail-stat">
1849
+ <div class="graph-detail-val" style="color:${It(e.p95Ms)}">${e.p95Ms}ms</div>
1850
+ <div class="graph-detail-lbl">P95 LATENCY</div>
1851
+ </div>
1852
+ `:p}
1853
+ <div class="graph-detail-stat">
1854
+ <div class="graph-detail-val" style="color:${It(t.stats.avgLatencyMs)}">${t.stats.avgLatencyMs}ms</div>
1855
+ <div class="graph-detail-lbl">AVG LATENCY</div>
1856
+ </div>
1857
+ ${t.stats.avgQueryCount>0?a`
1858
+ <div class="graph-detail-stat">
1859
+ <div class="graph-detail-val">${t.stats.avgQueryCount}</div>
1860
+ <div class="graph-detail-lbl">QUERIES/REQ</div>
1861
+ </div>
1862
+ `:p}
1863
+ <div class="graph-detail-stat">
1864
+ <div class="graph-detail-val">${t.stats.requestCount}</div>
1865
+ <div class="graph-detail-lbl">TOTAL REQS</div>
1866
+ </div>
1867
+ </div>
1868
+
1869
+ ${(e?.insights?.length??0)>0?a`
1870
+ <div class="graph-detail-sec">Performance Insights</div>
1871
+ ${e.insights.map(r=>a`
1872
+ <div class="graph-detail-finding">
1873
+ <span class="graph-detail-severity graph-detail-severity-${r.severity}">${r.severity}</span>
1874
+ <div class="graph-detail-finding-title">${r.title}</div>
1875
+ <div class="graph-detail-finding-meta">${r.type}</div>
1876
+ </div>
1877
+ `)}
1878
+ `:p}
1879
+ `}renderIssuesTab(t){let e=t?.openIssueCount??0;return e===0?a`<div class="graph-detail-empty">No open issues</div>`:a`
1880
+ <div class="graph-detail-issue-summary">
1881
+ <div class="graph-detail-stat">
1882
+ <div class="graph-detail-val" style="color:${ct}">${e}</div>
1883
+ <div class="graph-detail-lbl">OPEN ISSUES</div>
1884
+ </div>
1885
+ </div>
1886
+ <p class="graph-detail-hint">View the Issues tab for full details and remediation hints.</p>
1887
+ `}getSelectedNodeDetail(){if(!this.locked)return null;let t=this.graphNodes.find(r=>r.id===this.locked);if(!t)return null;let e=this.graphEdges.filter(r=>r.source===this.locked||r.target===this.locked);return {node:t,edges:e}}};u([I({context:A})],M.prototype,"store",2),u([b()],M.prototype,"graphNodes",2),u([b()],M.prototype,"graphEdges",2),u([b()],M.prototype,"locked",2),u([b()],M.prototype,"hovered",2),u([b()],M.prototype,"loading",2),u([b()],M.prototype,"activeLayers",2),u([b()],M.prototype,"searchQuery",2),u([b()],M.prototype,"viewTransform",2),u([b()],M.prototype,"dragging",2),u([b()],M.prototype,"detailTab",2),u([b()],M.prototype,"consolidatedFlows",2),u([b()],M.prototype,"activeFlowIdx",2),u([b()],M.prototype,"focusIdx",2),M=u([S("bk-graph-view")],M);function qi(o){return o===0?"<1ms":_(o)}var N=class extends E{constructor(){super(...arguments);this.requestId="";this.requestStarted=0;this.data=null;this.loading=false;this.failed=false;this.expandedSqlIdx=-1;}createRenderRoot(){return this}connectedCallback(){super.connectedCallback(),this.store.addEventListener("state-changed",()=>this.requestUpdate()),this.requestId&&this.loadTimeline();}async loadTimeline(){if(!this.requestId)return;let t=N.cache.get(this.requestId);if(t){this.data=t;return}this.loading=true;try{let e=await fetch(`${w.activity}?requestId=${this.requestId}`);if(!e.ok){this.failed=!0,this.loading=!1;return}let r=await e.json();if(N.cache.size>=ke){let i=N.cache.keys().next().value;i!==void 0&&N.cache.delete(i);}N.cache.set(this.requestId,r),this.data=r,this.loading=!1;}catch(e){console.debug("[brakit] timeline load failed:",e),this.failed=true,this.loading=false;}}toggleSql(t,e){e.stopPropagation(),this.expandedSqlIdx=this.expandedSqlIdx===t?-1:t;}copySql(t,e){e.stopPropagation(),navigator.clipboard.writeText(t).then(()=>D.show("SQL copied")).catch(()=>D.show("Copy failed"));}render(){if(this.loading)return a`<div class="tl-loading">Loading activity...</div>`;if(this.failed||!this.data||this.data.total===0)return p;let t=this.data,e=t.timeline[0]?.timestamp??0;return a`
1484
1888
  <div class="tl-header">
1485
1889
  <span class="tl-title">Activity Timeline</span>
1486
1890
  <span class="tl-counts">
1487
- ${t.counts.queries>0?a`<span class="tl-count tl-count-query">${t.counts.queries} quer${t.counts.queries===1?"y":"ies"}</span>`:d}
1488
- ${t.counts.fetches>0?a`<span class="tl-count tl-count-fetch">${t.counts.fetches} fetch${t.counts.fetches===1?"":"es"}</span>`:d}
1489
- ${t.counts.logs>0?a`<span class="tl-count tl-count-log">${t.counts.logs} log${t.counts.logs===1?"":"s"}</span>`:d}
1490
- ${t.counts.errors>0?a`<span class="tl-count tl-count-error">${t.counts.errors} error${t.counts.errors===1?"":"s"}</span>`:d}
1891
+ ${t.counts.queries>0?a`<span class="tl-count tl-count-query">${t.counts.queries} quer${t.counts.queries===1?"y":"ies"}</span>`:p}
1892
+ ${t.counts.fetches>0?a`<span class="tl-count tl-count-fetch">${t.counts.fetches} fetch${t.counts.fetches===1?"":"es"}</span>`:p}
1893
+ ${t.counts.logs>0?a`<span class="tl-count tl-count-log">${t.counts.logs} log${t.counts.logs===1?"":"s"}</span>`:p}
1894
+ ${t.counts.errors>0?a`<span class="tl-count tl-count-error">${t.counts.errors} error${t.counts.errors===1?"":"s"}</span>`:p}
1491
1895
  </span>
1492
1896
  </div>
1493
- <div class="tl-events">${this.renderTimeline(t.timeline,s)}</div>
1494
- `}renderTimeline(t,s){let r=new Map,o=[];for(let l of t){let c=l.type==="query"?l.data.parentFetchId:void 0;if(l.type==="query"&&c){let p=r.get(c);p||(p=[],r.set(c,p)),p.push(l);}else o.push(l);}let n=0;return o.map(l=>{let c=n++,p=l.type==="fetch"?l.data.fetchId:void 0,h=p?r.get(p):void 0;if(h&&h.length>0){let m=h.length;return a`
1495
- ${this.renderEvent(l,c,s)}
1897
+ <div class="tl-events">${this.renderTimeline(t.timeline,e)}</div>
1898
+ `}renderTimeline(t,e){let r=new Map,i=[];for(let l of t){let c=l.type==="query"?l.data.parentFetchId:void 0;if(l.type==="query"&&c){let d=r.get(c);d||(d=[],r.set(c,d)),d.push(l);}else i.push(l);}let n=0;return i.map(l=>{let c=n++,d=l.type==="fetch"?l.data.fetchId:void 0,h=d?r.get(d):void 0;if(h&&h.length>0){let m=h.length;return a`
1899
+ ${this.renderEvent(l,c,e)}
1496
1900
  <div class="tl-nested">
1497
1901
  <span class="tl-nested-label">${m} nested quer${m===1?"y":"ies"}</span>
1498
- ${h.map(E=>{let T=n++;return this.renderEvent(E,T,s,true)})}
1902
+ ${h.map(v=>{let x=n++;return this.renderEvent(v,x,e,true)})}
1499
1903
  </div>
1500
- `}return this.renderEvent(l,c,s)})}renderEvent(t,s,r,o=false){let n=ts[t.type]||"var(--text-dim)",l=es[t.type]||t.type,c="+"+v(Math.round(t.timestamp-r)),p=t.type==="query"?t.data.sql:void 0,h=!!p,m=this.expandedSqlIdx===s;return a`
1501
- <div class="tl-event ${h?"tl-clickable":""} ${o?"tl-nested-event":""}"
1904
+ `}return this.renderEvent(l,c,e)})}renderEvent(t,e,r,i=false){let n=Ms[t.type]||"var(--text-dim)",l=Ns[t.type]||t.type,c="+"+_(Math.round(t.timestamp-r)),d=t.type==="query"?t.data.sql:void 0,h=!!d,m=this.expandedSqlIdx===e;return a`
1905
+ <div class="tl-event ${h?"tl-clickable":""} ${i?"tl-nested-event":""}"
1502
1906
  style="${h?"":`border-left-color:${n}`}"
1503
- @click=${h?E=>this.toggleSql(s,E):d}>
1907
+ @click=${h?v=>this.toggleSql(e,v):p}>
1504
1908
  <span class="tl-event-time">${c}</span>
1505
1909
  <span class="tl-event-type" style="color:${n}">${l}</span>
1506
1910
  ${this.renderEventContent(t)}
1507
- ${p?a`
1911
+ ${d?a`
1508
1912
  <div class="tl-event-sql ${m?"open":""}">
1509
- <button class="tl-sql-copy" @click=${E=>this.copySql(p,E)}>Copy</button>
1510
- ${p}
1511
- </div>`:d}
1512
- </div>
1513
- `}renderEventContent(t){switch(t.type){case "fetch":{let s=t.data,r=s.statusCode>=400;return a`
1514
- <span class="tl-event-summary">${s.method} ${s.url}</span>
1515
- <span class="tl-event-status" style="${r?"color:var(--red)":""}">${s.statusCode}</span>
1516
- <span class="tl-event-dur">${v(s.durationMs)}</span>
1517
- `}case "query":{let s=t.data,r=(s.normalizedOp||s.operation||"?").toUpperCase(),o=s.table||s.model||"",n=Ft[r]||"var(--text-dim)";return a`
1518
- <span class="tl-event-summary"><span style="color:${n};font-weight:600">${r}</span> ${o}</span>
1519
- <span class="tl-event-dur">${_r(s.durationMs)}</span>
1520
- `}case "log":{let s=t.data,r=Ke[s.level]||"var(--text-dim)";return a`<span class="tl-event-summary"><span style="color:${r}">${s.level.toUpperCase()}</span> ${s.message}</span>`}case "error":{let s=t.data;return a`<span class="tl-event-summary" style="color:var(--red)">${s.name}: ${s.message}</span>`}default:return d}}};w.cache=new Map,u([R({context:x})],w.prototype,"store",2),u([y({attribute:"request-id"})],w.prototype,"requestId",2),u([y({attribute:"request-started",type:Number})],w.prototype,"requestStarted",2),u([_()],w.prototype,"data",2),u([_()],w.prototype,"loading",2),u([_()],w.prototype,"failed",2),u([_()],w.prototype,"expandedSqlIdx",2),w=u([g("bk-timeline-panel")],w);var Wt=class{constructor(e,t){this.host=e;this.store=t;this.retryCount=0;e.addController(this);}hostConnected(){this.connect();}hostDisconnected(){this.eventSource?.close(),clearTimeout(this.reloadTimer),clearTimeout(this.perfReloadTimer),clearTimeout(this.reconnectTimer);}connect(){this.eventSource?.close(),this.eventSource=new EventSource($.events),this.eventSource.onopen=()=>{this.retryCount=0;},this.eventSource.onerror=()=>{this.eventSource?.close(),this.scheduleReconnect();},this.eventSource.onmessage=e=>{let t=JSON.parse(e.data);t.path?.startsWith(N)||(this.store.prependRequest(t),clearTimeout(this.reloadTimer),this.reloadTimer=setTimeout(()=>this.reloadFlows(),300),this.store.state.activeView==="performance"&&(clearTimeout(this.perfReloadTimer),this.perfReloadTimer=setTimeout(()=>this.reloadMetrics(),ue)));},this.eventSource.addEventListener(ee,e=>{this.store.prependFetch(JSON.parse(e.data));}),this.eventSource.addEventListener("log",e=>{this.store.prependLog(JSON.parse(e.data));}),this.eventSource.addEventListener(se,e=>{this.store.prependError(JSON.parse(e.data));}),this.eventSource.addEventListener(re,e=>{this.store.prependQuery(JSON.parse(e.data));}),this.eventSource.addEventListener(oe,e=>{this.store.setIssues(JSON.parse(e.data));});}scheduleReconnect(){if(this.retryCount>=10)return;let e=Math.min(1e3*2**this.retryCount,3e4);this.retryCount++,this.reconnectTimer=setTimeout(()=>this.connect(),e);}async reloadFlows(){try{let t=await(await fetch($.flows)).json();this.store.setFlows(t.flows);}catch{}}async reloadMetrics(){try{let t=await(await fetch($.metricsLive)).json();this.store.setMetrics(t.endpoints||[]);}catch{}}};function gs(){return a`<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="7" height="7"/><rect x="14" y="3" width="7" height="7"/><rect x="14" y="14" width="7" height="7"/><rect x="3" y="14" width="7" height="7"/></svg>`}function Es(){return a`<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"/></svg>`}function bs(){return a`<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="2" y1="12" x2="22" y2="12"/><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg>`}function _s(){return a`<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M22 12h-4l-3 9L9 3l-3 9H2"/></svg>`}function Ss(){return a`<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><ellipse cx="12" cy="5" rx="9" ry="3"/><path d="M21 12c0 1.66-4 3-9 3s-9-1.34-9-3"/><path d="M3 5v14c0 1.66 4 3 9 3s9-1.34 9-3V5"/></svg>`}function Ts(){return a`<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="15" y1="9" x2="9" y2="15"/><line x1="9" y1="9" x2="15" y2="15"/></svg>`}function $s(){return a`<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="16" y1="13" x2="8" y2="13"/><line x1="16" y1="17" x2="8" y2="17"/></svg>`}function ys(){return a`<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/></svg>`}function xs(){return a`<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="20" x2="18" y2="10"/><line x1="12" y1="20" x2="12" y2="4"/><line x1="6" y1="20" x2="6" y2="14"/></svg>`}var X=class extends f{constructor(){super(...arguments);this.store=new Gt;this.activeView="overview";this.viewMode="simple";this.sse=new Wt(this,this.store);}createRenderRoot(){return this}connectedCallback(){super.connectedCallback(),this.loadInitialData(),this.store.addEventListener("state-changed",()=>this.requestUpdate());}async loadInitialData(){try{let[t,s]=await Promise.all([fetch($.flows),fetch($.requests)]),[r,o]=await Promise.all([t.json(),s.json()]);this.store.setFlows(r.flows),this.store.setRequests(o.requests);}catch(t){console.warn("[brakit]",t);}try{let[t,s,r,o,n]=await Promise.all([fetch($.fetches),fetch($.errors),fetch($.logs),fetch($.queries),fetch($.metricsLive)]),[l,c,p,h,m]=await Promise.all([t.json(),s.json(),r.json(),o.json(),n.json()]);this.store.setFetches(l.entries),this.store.setErrors(c.entries),this.store.setLogs(p.entries),this.store.setQueries(h.entries),this.store.setMetrics(m.endpoints||[]);}catch(t){console.warn("[brakit]",t);}try{let s=await(await fetch($.insights)).json();this.store.setIssues(s.issues||[]);}catch(t){console.warn("[brakit]",t);}}switchView(t){t!==this.activeView&&(this.activeView=t,this.store.setActiveView(t),fetch(`${$.tab}?tab=${encodeURIComponent(t)}`).catch(()=>{}),t==="performance"&&this.sse.reloadMetrics());}async handleClear(){confirm("This will clear all data including performance metrics history. Continue?")&&(await fetch($.clear,{method:"POST"}),this.store.clearAll(),C.show("Cleared"));}handleCopyAsCurl(t){ct(t);}render(){let t=this.store.state,s=t.requests.filter(c=>!c.path?.startsWith(N)),r=s.filter(c=>c.statusCode>=400).length,o=s.length>0?Math.round(s.reduce((c,p)=>c+p.durationMs,0)/s.length):0,n=(t.issues||[]).filter(c=>c.state!=="resolved"&&c.state!=="stale").length,l=window.__BRAKIT_CONFIG__;return a`
1913
+ <button class="tl-sql-copy" @click=${v=>this.copySql(d,v)}>Copy</button>
1914
+ ${d}
1915
+ </div>`:p}
1916
+ </div>
1917
+ `}renderEventContent(t){switch(t.type){case "fetch":{let e=t.data,r=e.statusCode>=400;return a`
1918
+ <span class="tl-event-summary">${e.method} ${e.url}</span>
1919
+ <span class="tl-event-status" style="${r?"color:var(--red)":""}">${e.statusCode}</span>
1920
+ <span class="tl-event-dur">${_(e.durationMs)}</span>
1921
+ `}case "query":{let e=t.data,r=(e.normalizedOp||e.operation||"?").toUpperCase(),i=e.table||e.model||"",n=pe[r]||"var(--text-dim)";return a`
1922
+ <span class="tl-event-summary"><span style="color:${n};font-weight:600">${r}</span> ${i}</span>
1923
+ <span class="tl-event-dur">${qi(e.durationMs)}</span>
1924
+ `}case "log":{let e=t.data,r=As[e.level]||"var(--text-dim)";return a`<span class="tl-event-summary"><span style="color:${r}">${e.level.toUpperCase()}</span> ${e.message}</span>`}case "error":{let e=t.data;return a`<span class="tl-event-summary" style="color:var(--red)">${e.name}: ${e.message}</span>`}default:return p}}};N.cache=new Map,u([I({context:A})],N.prototype,"store",2),u([L({attribute:"request-id"})],N.prototype,"requestId",2),u([L({attribute:"request-started",type:Number})],N.prototype,"requestStarted",2),u([b()],N.prototype,"data",2),u([b()],N.prototype,"loading",2),u([b()],N.prototype,"failed",2),u([b()],N.prototype,"expandedSqlIdx",2),N=u([S("bk-timeline-panel")],N);function Lt(o){try{return JSON.parse(o)}catch{return null}}var Ee=class{constructor(s,t){this.host=s;this.store=t;this.retryCount=0;this.boundHandlers={fetch:s=>{let t=Lt(s.data);t&&this.store.prependFetch(t);},log:s=>{let t=Lt(s.data);t&&this.store.prependLog(t);},error:s=>{let t=Lt(s.data);t&&this.store.prependError(t);},query:s=>{let t=Lt(s.data);t&&this.store.prependQuery(t);},issues:s=>{let t=Lt(s.data);t&&this.store.setIssues(t);}};s.addController(this);}hostConnected(){this.connect();}hostDisconnected(){this.removeListeners(),this.eventSource?.close(),clearTimeout(this.reloadTimer),clearTimeout(this.perfReloadTimer),clearTimeout(this.reconnectTimer);}removeListeners(){this.eventSource&&(this.eventSource.removeEventListener(ie,this.boundHandlers.fetch),this.eventSource.removeEventListener("log",this.boundHandlers.log),this.eventSource.removeEventListener(oe,this.boundHandlers.error),this.eventSource.removeEventListener(ne,this.boundHandlers.query),this.eventSource.removeEventListener(ae,this.boundHandlers.issues));}connect(){this.removeListeners(),this.eventSource?.close(),this.eventSource=new EventSource(w.events),this.eventSource.onopen=()=>{this.retryCount=0;},this.eventSource.onerror=()=>{this.eventSource?.close(),this.scheduleReconnect();},this.eventSource.onmessage=s=>{let t=Lt(s.data);t&&(t.path?.startsWith(F)||(this.store.prependRequest(t),clearTimeout(this.reloadTimer),this.reloadTimer=setTimeout(()=>this.reloadFlows(),300),this.store.state.activeView==="performance"&&(clearTimeout(this.perfReloadTimer),this.perfReloadTimer=setTimeout(()=>this.reloadMetrics(),De))));},this.eventSource.addEventListener(ie,this.boundHandlers.fetch),this.eventSource.addEventListener("log",this.boundHandlers.log),this.eventSource.addEventListener(oe,this.boundHandlers.error),this.eventSource.addEventListener(ne,this.boundHandlers.query),this.eventSource.addEventListener(ae,this.boundHandlers.issues);}scheduleReconnect(){if(this.retryCount>=10)return;let s=Math.min(1e3*2**this.retryCount,3e4);this.retryCount++,this.reconnectTimer=setTimeout(()=>this.connect(),s);}async reloadFlows(){try{let t=await(await fetch(w.flows)).json();this.store.setFlows(t.flows);}catch{}}async reloadMetrics(){try{let t=await(await fetch(w.metricsLive)).json();this.store.setMetrics(t.endpoints||[]);}catch{}}};function vr(){return a`<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="7" height="7"/><rect x="14" y="3" width="7" height="7"/><rect x="14" y="14" width="7" height="7"/><rect x="3" y="14" width="7" height="7"/></svg>`}function gr(){return a`<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"/></svg>`}function br(){return a`<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="2" y1="12" x2="22" y2="12"/><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg>`}function Er(){return a`<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M22 12h-4l-3 9L9 3l-3 9H2"/></svg>`}function yr(){return a`<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><ellipse cx="12" cy="5" rx="9" ry="3"/><path d="M21 12c0 1.66-4 3-9 3s-9-1.34-9-3"/><path d="M3 5v14c0 1.66 4 3 9 3s9-1.34 9-3V5"/></svg>`}function _r(){return a`<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="15" y1="9" x2="9" y2="15"/><line x1="9" y1="9" x2="15" y2="15"/></svg>`}function $r(){return a`<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="16" y1="13" x2="8" y2="13"/><line x1="16" y1="17" x2="8" y2="17"/></svg>`}function xr(){return a`<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/></svg>`}function Sr(){return a`<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="20" x2="18" y2="10"/><line x1="12" y1="20" x2="12" y2="4"/><line x1="6" y1="20" x2="6" y2="14"/></svg>`}function Tr(){return a`<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="6" cy="6" r="3"/><circle cx="18" cy="6" r="3"/><circle cx="6" cy="18" r="3"/><circle cx="18" cy="18" r="3"/><line x1="9" y1="6" x2="15" y2="6"/><line x1="6" y1="9" x2="6" y2="15"/><line x1="18" y1="9" x2="18" y2="15"/><line x1="9" y1="18" x2="15" y2="18"/></svg>`}var dt=class extends E{constructor(){super(...arguments);this.store=new ue;this.activeView="overview";this.viewMode="simple";this.sse=new Ee(this,this.store);}createRenderRoot(){return this}connectedCallback(){super.connectedCallback(),this.loadInitialData(),this.store.addEventListener("state-changed",()=>this.requestUpdate());}async loadInitialData(){try{let[t,e]=await Promise.all([fetch(w.flows),fetch(w.requests)]),[r,i]=await Promise.all([t.json(),e.json()]);this.store.setFlows(r.flows),this.store.setRequests(i.requests);}catch(t){console.warn("[brakit]",t);}try{let[t,e,r,i,n]=await Promise.all([fetch(w.fetches),fetch(w.errors),fetch(w.logs),fetch(w.queries),fetch(w.metricsLive)]),[l,c,d,h,m]=await Promise.all([t.json(),e.json(),r.json(),i.json(),n.json()]);this.store.setFetches(l.entries),this.store.setErrors(c.entries),this.store.setLogs(d.entries),this.store.setQueries(h.entries),this.store.setMetrics(m.endpoints||[]);}catch(t){console.warn("[brakit]",t);}try{let e=await(await fetch(w.insights)).json();this.store.setIssues(e.issues||[]);}catch(t){console.warn("[brakit]",t);}}switchView(t){t!==this.activeView&&(this.activeView=t,this.store.setActiveView(t),fetch(`${w.tab}?tab=${encodeURIComponent(t)}`).catch(()=>{}),t==="performance"&&this.sse.reloadMetrics());}async handleClear(){confirm("This will clear all data including performance metrics history. Continue?")&&(await fetch(w.clear,{method:"POST"}),this.store.clearAll(),D.show("Cleared"));}handleCopyAsCurl(t){Tt(t);}render(){let t=this.store.state,e=t.requests.filter(c=>!c.path?.startsWith(F)),r=e.filter(c=>c.statusCode>=400).length,i=e.length>0?Math.round(e.reduce((c,d)=>c+d.durationMs,0)/e.length):0,n=(t.issues||[]).filter(c=>c.state!=="resolved"&&c.state!=="stale").length,l=window.__BRAKIT_CONFIG__;return a`
1521
1925
  <div class="app" id="app">
1522
1926
  <aside class="sidebar">
1523
1927
  <div class="sidebar-logo">
@@ -1525,25 +1929,31 @@ span.perf-breakdown-dot.perf-breakdown-app{background:var(--breakdown-app)}
1525
1929
  <span class="logo-version">v${l?.version??""}</span>
1526
1930
  </div>
1527
1931
  <nav class="sidebar-nav">
1528
- ${this.renderSidebarItem("overview","Overview",gs(),void 0)}
1932
+ ${this.renderSidebarItem("overview","Overview",vr(),void 0)}
1529
1933
  <div class="sidebar-section">Monitor</div>
1530
- ${this.renderSidebarItem("actions","Actions",Es(),t.flows.length)}
1531
- ${this.renderSidebarItem("requests","Requests",bs(),s.length)}
1532
- ${this.renderSidebarItem("fetches","Fetches",_s(),t.fetches.length)}
1934
+ ${this.renderSidebarItem("actions","Actions",gr(),t.flows.length)}
1935
+ ${this.renderSidebarItem("requests","Requests",br(),e.length)}
1936
+ ${this.renderSidebarItem("fetches","Fetches",Er(),t.fetches.length)}
1533
1937
  <div class="sidebar-section">Insights</div>
1534
- ${this.renderSidebarItem("queries","Queries",Ss(),t.queries.length)}
1535
- ${this.renderSidebarItem("errors","Errors",Ts(),t.errors.length)}
1536
- ${this.renderSidebarItem("logs","Logs",$s(),t.logs.length)}
1537
- ${this.renderSidebarItem("security","Security",ys(),n,n===0)}
1538
- ${this.renderSidebarItem("performance","Performance",xs(),void 0)}
1938
+ ${this.renderSidebarItem("queries","Queries",yr(),t.queries.length)}
1939
+ ${this.renderSidebarItem("errors","Errors",_r(),t.errors.length)}
1940
+ ${this.renderSidebarItem("logs","Logs",$r(),t.logs.length)}
1941
+ ${this.renderSidebarItem("security","Security",xr(),n,n===0)}
1942
+ ${this.renderSidebarItem("performance","Performance",Sr(),void 0)}
1943
+ <div class="sidebar-section">Topology</div>
1944
+ <button class="sidebar-item ${this.activeView==="graph"?"active":""}" @click=${()=>this.switchView("graph")}>
1945
+ <span class="item-icon">${Tr()}</span>
1946
+ <span class="item-label">Graph</span>
1947
+ <span class="sidebar-beta">beta</span>
1948
+ </button>
1539
1949
  </nav>
1540
1950
  <div class="sidebar-footer">:${l?.port??""}</div>
1541
1951
  </aside>
1542
1952
  <div class="main-panel">
1543
1953
  <div class="header">
1544
1954
  <div class="header-left">
1545
- <span class="header-title" id="header-title">${ie[this.activeView]||this.activeView}</span>
1546
- <span class="header-sub" id="header-sub">${ne[this.activeView]||""}</span>
1955
+ <span class="header-title" id="header-title">${Ie[this.activeView]||this.activeView}</span>
1956
+ <span class="header-sub" id="header-sub">${Ce[this.activeView]||""}</span>
1547
1957
  </div>
1548
1958
  <div class="header-right">
1549
1959
  ${this.activeView==="actions"?a`
@@ -1551,7 +1961,7 @@ span.perf-breakdown-dot.perf-breakdown-app{background:var(--breakdown-app)}
1551
1961
  <button class="segmented-btn ${this.viewMode==="simple"?"active":""}" @click=${()=>{this.viewMode="simple",this.store.setViewMode("simple");}}>Quick</button>
1552
1962
  <button class="segmented-btn ${this.viewMode==="detailed"?"active":""}" @click=${()=>{this.viewMode="detailed",this.store.setViewMode("detailed");}}>Detailed</button>
1553
1963
  </div>
1554
- `:d}
1964
+ `:p}
1555
1965
  <button class="btn btn-danger" @click=${this.handleClear}>Clear</button>
1556
1966
  </div>
1557
1967
  </div>
@@ -1583,23 +1993,26 @@ span.perf-breakdown-dot.perf-breakdown-app{background:var(--breakdown-app)}
1583
1993
  <div class="view-telemetry" id="performance-container" style="display:${this.activeView==="performance"?"block":"none"}">
1584
1994
  <bk-performance-view></bk-performance-view>
1585
1995
  </div>
1996
+ <div class="view-telemetry" id="graph-container" style="display:${this.activeView==="graph"?"block":"none"}">
1997
+ <bk-graph-view></bk-graph-view>
1998
+ </div>
1586
1999
  </div>
1587
2000
  <div class="footer">
1588
- <span id="stat-total">${s.length} request${s.length!==1?"s":""}</span>
2001
+ <span id="stat-total">${e.length} request${e.length!==1?"s":""}</span>
1589
2002
  <span id="stat-flows">${t.flows.length} action${t.flows.length!==1?"s":""}</span>
1590
2003
  <span id="stat-errors" class="error-count">${r} error${r!==1?"s":""}</span>
1591
- <span id="stat-avg">Avg: ${o}ms</span>
2004
+ <span id="stat-avg">Avg: ${i}ms</span>
1592
2005
  </div>
1593
2006
  </div>
1594
2007
  </div>
1595
2008
  <bk-toast></bk-toast>
1596
- `}renderSidebarItem(t,s,r,o,n=false){return a`
2009
+ `}renderSidebarItem(t,e,r,i,n=false){return a`
1597
2010
  <button class="sidebar-item ${this.activeView===t?"active":""}" @click=${()=>this.switchView(t)}>
1598
2011
  <span class="item-icon">${r}</span>
1599
- <span class="item-label">${s}</span>
1600
- ${o!==void 0?a`<span class="item-count" style="display:${n?"none":""}">${o}</span>`:d}
2012
+ <span class="item-label">${e}</span>
2013
+ ${i!==void 0?a`<span class="item-count" style="display:${n?"none":""}">${i}</span>`:p}
1601
2014
  </button>
1602
- `}};u([Ee({context:x})],X.prototype,"store",2),u([_()],X.prototype,"activeView",2),u([_()],X.prototype,"viewMode",2),X=u([g("bk-dashboard")],X);
2015
+ `}};u([Be({context:A})],dt.prototype,"store",2),u([b()],dt.prototype,"activeView",2),u([b()],dt.prototype,"viewMode",2),dt=u([S("bk-dashboard")],dt);
1603
2016
  /*! Bundled license information:
1604
2017
 
1605
2018
  @lit/reactive-element/css-tag.js:
@@ -1622,6 +2035,8 @@ lit-element/lit-element.js:
1622
2035
  @lit/reactive-element/decorators/query-async.js:
1623
2036
  @lit/reactive-element/decorators/query-assigned-nodes.js:
1624
2037
  @lit/context/lib/decorators/provide.js:
2038
+ lit-html/directive.js:
2039
+ lit-html/directives/unsafe-html.js:
1625
2040
  (**
1626
2041
  * @license
1627
2042
  * Copyright 2017 Google LLC