brakit 0.8.7 → 9.0.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.
- package/README.md +15 -3
- package/dist/api.d.ts +66 -46
- package/dist/api.js +727 -730
- package/dist/bin/brakit.js +294 -432
- package/dist/dashboard-client.global.js +345 -222
- package/dist/dashboard.html +390 -231
- package/dist/mcp/server.js +7 -15
- package/dist/runtime/index.js +1367 -1607
- package/package.json +1 -1
|
@@ -1,30 +1,30 @@
|
|
|
1
|
-
(function(){'use strict';var
|
|
2
|
-
\f\r]`,
|
|
3
|
-
\f\r"'\`<>=]|("|')|))|$)`,"g"),De=/'/g,Ne=/"/g,Ue=/^(?:script|style|textarea|title)$/i,oe=o=>(e,...t)=>({_$litType$:o,strings:e,values:t}),n=oe(1),Q=Symbol.for("lit-noChange"),d=Symbol.for("lit-nothing"),qe=new WeakMap,G=j.createTreeWalker(j,129);function Fe(o,e){if(!ie(o)||!o.hasOwnProperty("raw"))throw Error("invalid template strings array");return Ie!==void 0?Ie.createHTML(e):e}var Is=(o,e)=>{let t=o.length-1,s=[],r,i=e===2?"<svg>":e===3?"<math>":"",a=gt;for(let c=0;c<t;c++){let l=o[c],h,m,p=-1,v=0;for(;v<l.length&&(a.lastIndex=v,m=a.exec(l),m!==null);)v=a.lastIndex,a===gt?m[1]==="!--"?a=Me:m[1]!==void 0?a=Oe:m[2]!==void 0?(Ue.test(m[2])&&(r=RegExp("</"+m[2],"g")),a=B):m[3]!==void 0&&(a=B):a===B?m[0]===">"?(a=r??gt,p=-1):m[1]===void 0?p=-2:(p=a.lastIndex-m[2].length,h=m[1],a=m[3]===void 0?B:m[3]==='"'?Ne:De):a===Ne||a===De?a=B:a===Me||a===Oe?a=gt:(a=B,r=void 0);let E=a===B&&o[c+1].startsWith("/>")?" ":"";i+=a===gt?l+ks:p>=0?(s.push(h),l.slice(0,p)+He+l.slice(p)+N+E):l+N+(p===-2?c:E);}return [Fe(o,i+(o[t]||"<?>")+(e===2?"</svg>":e===3?"</math>":"")),s]},yt=class o{constructor({strings:e,_$litType$:t},s){let r;this.parts=[];let i=0,a=0,c=e.length-1,l=this.parts,[h,m]=Is(e,t);if(this.el=o.createElement(h,s),G.currentNode=this.el.content,t===2||t===3){let p=this.el.content.firstChild;p.replaceWith(...p.childNodes);}for(;(r=G.nextNode())!==null&&l.length<c;){if(r.nodeType===1){if(r.hasAttributes())for(let p of r.getAttributeNames())if(p.endsWith(He)){let v=m[a++],E=r.getAttribute(p).split(N),C=/([.?@])?(.*)/.exec(v);l.push({type:1,index:i,name:C[2],strings:E,ctor:C[1]==="."?te:C[1]==="?"?ee:C[1]==="@"?se:st}),r.removeAttribute(p);}else p.startsWith(N)&&(l.push({type:6,index:i}),r.removeAttribute(p));if(Ue.test(r.tagName)){let p=r.textContent.split(N),v=p.length-1;if(v>0){r.textContent=qt?qt.emptyScript:"";for(let E=0;E<v;E++)r.append(p[E],Et()),G.nextNode(),l.push({type:2,index:++i});r.append(p[v],Et());}}}else if(r.nodeType===8)if(r.data===Pe)l.push({type:2,index:i});else {let p=-1;for(;(p=r.data.indexOf(N,p+1))!==-1;)l.push({type:7,index:i}),p+=N.length-1;}i++;}}static createElement(e,t){let s=j.createElement("template");return s.innerHTML=e,s}};function et(o,e,t=o,s){if(e===Q)return e;let r=s!==void 0?t._$Co?.[s]:t._$Cl,i=$t(e)?void 0:e._$litDirective$;return r?.constructor!==i&&(r?._$AO?.(false),i===void 0?r=void 0:(r=new i(o),r._$AT(o,t,s)),s!==void 0?(t._$Co??(t._$Co=[]))[s]=r:t._$Cl=r),r!==void 0&&(e=et(o,r._$AS(o,e.values),r,s)),e}var Zt=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??j).importNode(t,true);G.currentNode=r;let i=G.nextNode(),a=0,c=0,l=s[0];for(;l!==void 0;){if(a===l.index){let h;l.type===2?h=new St(i,i.nextSibling,this,e):l.type===1?h=new l.ctor(i,l.name,l.strings,this,e):l.type===6&&(h=new re(i,this,e)),this._$AV.push(h),l=s[++c];}a!==l?.index&&(i=G.nextNode(),a++);}return G.currentNode=j,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++;}},St=class o{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=et(this,e,t),$t(e)?e===d||e==null||e===""?(this._$AH!==d&&this._$AR(),this._$AH=d):e!==this._$AH&&e!==Q&&this._(e):e._$litType$!==void 0?this.$(e):e.nodeType!==void 0?this.T(e):Ls(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&&$t(this._$AH)?this._$AA.nextSibling.data=e:this.T(j.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=yt.createElement(Fe(s.h,s.h[0]),this.options)),s);if(this._$AH?._$AD===r)this._$AH.p(t);else {let i=new Zt(r,this),a=i.u(this.options);i.p(t),this.T(a),this._$AH=i;}}_$AC(e){let t=qe.get(e.strings);return t===void 0&&qe.set(e.strings,t=new yt(e)),t}k(e){ie(this._$AH)||(this._$AH=[],this._$AR());let t=this._$AH,s,r=0;for(let i of e)r===t.length?t.push(s=new o(this.O(Et()),this.O(Et()),this,this.options)):s=t[r],s._$AI(i),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=Le(e).nextSibling;Le(e).remove(),e=s;}}setConnected(e){this._$AM===void 0&&(this._$Cv=e,this._$AP?.(e));}},st=class{get tagName(){return this.element.tagName}get _$AU(){return this._$AM._$AU}constructor(e,t,s,r,i){this.type=1,this._$AH=d,this._$AN=void 0,this.element=e,this.name=t,this._$AM=r,this.options=i,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 i=this.strings,a=false;if(i===void 0)e=et(this,e,t,0),a=!$t(e)||e!==this._$AH&&e!==Q,a&&(this._$AH=e);else {let c=e,l,h;for(e=i[0],l=0;l<i.length-1;l++)h=et(this,c[s+l],t,l),h===Q&&(h=this._$AH[l]),a||(a=!$t(h)||h!==this._$AH[l]),h===d?e=d:e!==d&&(e+=(h??"")+i[l+1]),this._$AH[l]=h;}a&&!r&&this.j(e);}j(e){e===d?this.element.removeAttribute(this.name):this.element.setAttribute(this.name,e??"");}},te=class extends st{constructor(){super(...arguments),this.type=3;}j(e){this.element[this.name]=e===d?void 0:e;}},ee=class extends st{constructor(){super(...arguments),this.type=4;}j(e){this.element.toggleAttribute(this.name,!!e&&e!==d);}},se=class extends st{constructor(e,t,s,r,i){super(e,t,s,r,i),this.type=5;}_$AI(e,t=this){if((e=et(this,e,t,0)??d)===Q)return;let s=this._$AH,r=e===d&&s!==d||e.capture!==s.capture||e.once!==s.once||e.passive!==s.passive,i=e!==d&&(s===d||r);r&&this.element.removeEventListener(this.name,this,s),i&&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);}},re=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){et(this,e);}};var Ms=bt.litHtmlPolyfillSupport;Ms?.(yt,St),(bt.litHtmlVersions??(bt.litHtmlVersions=[])).push("3.3.2");var Be=(o,e,t)=>{let s=t?.renderBefore??e,r=s._$litPart$;if(r===void 0){let i=t?.renderBefore??null;s._$litPart$=r=new St(e.insertBefore(Et(),i),i,void 0,t??{});}return r._$AI(o),r};var _t=globalThis,f=class extends M{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=Be(t,this.renderRoot,this.renderOptions);}connectedCallback(){super.connectedCallback(),this._$Do?.setConnected(true);}disconnectedCallback(){super.disconnectedCallback(),this._$Do?.setConnected(false);}render(){return Q}};f._$litElement$=true,f.finalized=true,_t.litElementHydrateSupport?.({LitElement:f});var Os=_t.litElementPolyfillSupport;Os?.({LitElement:f});(_t.litElementVersions??(_t.litElementVersions=[])).push("4.2.2");var g=o=>(e,t)=>{t!==void 0?t.addInitializer(()=>{customElements.define(o,e);}):customElements.define(o,e);};var Ds={attribute:true,type:String,converter:ft,reflect:false,hasChanged:Nt},Ns=(o=Ds,e,t)=>{let{kind:s,metadata:r}=t,i=globalThis.litPropertyMetadata.get(r);if(i===void 0&&globalThis.litPropertyMetadata.set(r,i=new Map),s==="setter"&&((o=Object.create(o)).wrapped=true),i.set(t.name,o),s==="accessor"){let{name:a}=t;return {set(c){let l=e.get.call(this);e.set.call(this,c),this.requestUpdate(a,l,o,true,c);},init(c){return c!==void 0&&this.C(a,void 0,o,c),c}}}if(s==="setter"){let{name:a}=t;return function(c){let l=this[a];e.call(this,c),this.requestUpdate(a,l,o,true,c);}}throw Error("Unsupported decorator location: "+s)};function y(o){return (e,t)=>typeof t=="object"?Ns(o,e,t):((s,r,i)=>{let a=r.hasOwnProperty(i);return r.constructor.createProperty(i,s),a?Object.getOwnPropertyDescriptor(r,i):void 0})(o,e,t)}function $(o){return y({...o,state:true,attribute:false})}var xt=class extends f{constructor(){super(...arguments);this.method="";}createRenderRoot(){return this}render(){let t=this.method.toUpperCase();return n`<span class="method-badge method-badge-${t}">${t}</span>`}};u([y()],xt.prototype,"method",2),xt=u([g("bk-method-badge")],xt);var L="/__brakit/api",O="/__brakit",R={flows:`${L}/flows`,requests:`${L}/requests`,events:`${L}/events`,clear:`${L}/clear`,fetches:`${L}/fetches`,errors:`${L}/errors`,logs:`${L}/logs`,queries:`${L}/queries`,metricsLive:`${L}/metrics/live`,insights:`${L}/insights`,tab:`${L}/tab`,activity:`${L}/activity`};var Tt="polling",Pt="static",qs="auth-handshake",Hs="auth-check",Ps="middleware",Ut={[qs]:1,[Hs]:1,[Ps]:1};var ne="fetch";var ae="error_event",ce="query",le="issues";var de={overview:"Overview",queries:"Queries",requests:"Requests",actions:"Actions",errors:"Errors",security:"Security",fetches:"Fetches",logs:"Logs",performance:"Performance"};var Rt={overview:"Overview",actions:"Actions",requests:"Requests",fetches:"Server Fetches",queries:"Queries",errors:"Errors",logs:"Logs",performance:"Performance",security:"Security"},pe={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 he=100,V=300,W=800,me=2e3,ve=100,fe=50,ge=500;var q="__all__",jt={SELECT:"var(--blue)",INSERT:"var(--green)",UPDATE:"var(--amber)",DELETE:"var(--red)",COUNT:"var(--text-muted)"},ze={error:"var(--red)",warn:"var(--amber)",info:"var(--blue)",debug:"var(--text-muted)",log:"var(--text-dim)"},be=["#2563eb","#7c3aed","#16a34a","#d97706","#dc2626","#0891b2","#ea580c","#c026d3","#059669","#db2777"],wt={green:"#4ade80",amber:"#fbbf24",red:"#f87171"},Qt=[{max:he,label:"Fast",color:"var(--green)",bg:"rgba(22,163,74,0.08)",border:"rgba(22,163,74,0.2)"},{max:V,label:"Good",color:"var(--green)",bg:"rgba(22,163,74,0.06)",border:"rgba(22,163,74,0.15)"},{max:W,label:"OK",color:"var(--amber)",bg:"rgba(217,119,6,0.06)",border:"rgba(217,119,6,0.15)"},{max:me,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)"}],Je="rgba(228,228,231,0.8)",Ee="rgba(113,113,122,0.7)",Ze="10px monospace",$e="9px monospace",ts="8px monospace",es={top:16,right:16,bottom:28,left:52},ss={fetch:"var(--blue)",log:"var(--text-muted)",error:"var(--red)",query:"var(--accent)"},rs={fetch:"FETCH",log:"LOG",error:"ERROR",query:"QUERY"},is=new Set(["cookie","set-cookie","authorization","proxy-authorization","x-api-key","x-auth-token"]),os={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"},ns=new Set(["host","connection","accept-encoding"]),H={critical:{icon:"\u2717",cls:"critical",sort:0},warning:{icon:"\u26A0",cls:"warning",sort:1},info:{icon:"\u2139",cls:"info",sort:2}};function S(o){return o<1e3?o+"ms":(o/1e3).toFixed(1)+"s"}function Y(o){return !o||o===0?"":o<1024?o+"b":(o/1024).toFixed(1)+"kb"}function P(o){return o?o.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,"""):""}function rt(o){return o>=500?"status-pill-5xx":o>=400?"status-pill-4xx":o>=300?"status-pill-3xx":"status-pill-2xx"}function as(o){return os[o]||(o>=500?"Server Error":o>=400?"Client Error":"OK")}function Us(o,e){if(is.has(o.toLowerCase())){let t=String(e);return t.length<=8?"****":t.slice(0,4)+"..."+t.slice(-4)+" ("+t.length+" chars)"}return String(e)}function it(o){return !o||Object.keys(o).length===0?'<span style="color:var(--text-muted)">No headers</span>':Object.entries(o).map(([e,t])=>'<span class="json-key">'+P(e)+"</span>: "+P(Us(e,t))).join(`
|
|
4
|
-
`)}function X(
|
|
1
|
+
(function(){'use strict';var Ls=Object.defineProperty;var Ms=Object.getOwnPropertyDescriptor;var h=(i,e,t,s)=>{for(var r=s>1?void 0:s?Ms(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&&Ls(e,t,r),r};var Lt=globalThis,kt=Lt.ShadowRoot&&(Lt.ShadyCSS===void 0||Lt.ShadyCSS.nativeShadow)&&"adoptedStyleSheets"in Document.prototype&&"replace"in CSSStyleSheet.prototype,Re=Symbol(),xe=new WeakMap,Mt=class{constructor(e,t,s){if(this._$cssResult$=true,s!==Re)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(kt&&e===void 0){let s=t!==void 0&&t.length===1;s&&(e=xe.get(t)),e===void 0&&((this.o=e=new CSSStyleSheet).replaceSync(this.cssText),s&&xe.set(t,e));}return e}toString(){return this.cssText}},we=i=>new Mt(typeof i=="string"?i:i+"",void 0,Re);var Ae=(i,e)=>{if(kt)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);}},Yt=kt?i=>i:i=>i instanceof CSSStyleSheet?(e=>{let t="";for(let s of e.cssRules)t+=s.cssText;return we(t)})(i):i;var{is:ks,defineProperty:Os,getOwnPropertyDescriptor:Ds,getOwnPropertyNames:Ns,getOwnPropertySymbols:Hs,getPrototypeOf:qs}=Object,D=globalThis,Ce=D.trustedTypes,Ps=Ce?Ce.emptyScript:"",Us=D.reactiveElementPolyfillSupport,ht=(i,e)=>i,mt={toAttribute(i,e){switch(e){case Boolean:i=i?Ps: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}},Ot=(i,e)=>!ks(i,e),Ie={attribute:true,type:String,converter:mt,reflect:false,useDefault:false,hasChanged:Ot};Symbol.metadata??(Symbol.metadata=Symbol("metadata")),D.litPropertyMetadata??(D.litPropertyMetadata=new WeakMap);var k=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=Ie){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&&Os(this.prototype,e,r);}}static getPropertyDescriptor(e,t,s){let{get:r,set:o}=Ds(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)??Ie}static _$Ei(){if(this.hasOwnProperty(ht("elementProperties")))return;let e=qs(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=[...Ns(t),...Hs(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(Yt(r));}else e!==void 0&&t.push(Yt(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 Ae(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??Ot)(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){}};k.elementStyles=[],k.shadowRootOptions={mode:"open"},k[ht("elementProperties")]=new Map,k[ht("finalized")]=new Map,Us?.({ReactiveElement:k}),(D.reactiveElementVersions??(D.reactiveElementVersions=[])).push("2.1.2");var ft=globalThis,Le=i=>i,Dt=ft.trustedTypes,Me=Dt?Dt.createPolicy("lit-html",{createHTML:i=>i}):void 0,qe="$lit$",N=`lit$${Math.random().toFixed(9).slice(2)}$`,Pe="?"+N,Fs=`<${Pe}>`,j=document,gt=()=>j.createComment(""),bt=i=>i===null||typeof i!="object"&&typeof i!="function",ee=Array.isArray,Bs=i=>ee(i)||typeof i?.[Symbol.iterator]=="function",Xt=`[
|
|
2
|
+
\f\r]`,vt=/<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g,ke=/-->/g,Oe=/>/g,G=RegExp(`>|${Xt}(?:([^\\s"'>=/]+)(${Xt}*=${Xt}*(?:[^
|
|
3
|
+
\f\r"'\`<>=]|("|')|))|$)`,"g"),De=/'/g,Ne=/"/g,Ue=/^(?:script|style|textarea|title)$/i,se=i=>(e,...t)=>({_$litType$:i,strings:e,values:t}),a=se(1),Q=Symbol.for("lit-noChange"),d=Symbol.for("lit-nothing"),He=new WeakMap,W=j.createTreeWalker(j,129);function Fe(i,e){if(!ee(i)||!i.hasOwnProperty("raw"))throw Error("invalid template strings array");return Me!==void 0?Me.createHTML(e):e}var Gs=(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,u,m=-1,b=0;for(;b<c.length&&(n.lastIndex=b,u=n.exec(c),u!==null);)b=n.lastIndex,n===vt?u[1]==="!--"?n=ke:u[1]!==void 0?n=Oe:u[2]!==void 0?(Ue.test(u[2])&&(r=RegExp("</"+u[2],"g")),n=G):u[3]!==void 0&&(n=G):n===G?u[0]===">"?(n=r??vt,m=-1):u[1]===void 0?m=-2:(m=n.lastIndex-u[2].length,p=u[1],n=u[3]===void 0?G:u[3]==='"'?Ne:De):n===Ne||n===De?n=G:n===ke||n===Oe?n=vt:(n=G,r=void 0);let $=n===G&&i[l+1].startsWith("/>")?" ":"";o+=n===vt?c+Fs:m>=0?(s.push(p),c.slice(0,m)+qe+c.slice(m)+N+$):c+N+(m===-2?l:$);}return [Fe(i,o+(i[t]||"<?>")+(e===2?"</svg>":e===3?"</math>":"")),s]},Et=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,u]=Gs(e,t);if(this.el=i.createElement(p,s),W.currentNode=this.el.content,t===2||t===3){let m=this.el.content.firstChild;m.replaceWith(...m.childNodes);}for(;(r=W.nextNode())!==null&&c.length<l;){if(r.nodeType===1){if(r.hasAttributes())for(let m of r.getAttributeNames())if(m.endsWith(qe)){let b=u[n++],$=r.getAttribute(m).split(N),v=/([.?@])?(.*)/.exec(b);c.push({type:1,index:o,name:v[2],strings:$,ctor:v[1]==="."?zt:v[1]==="?"?Jt:v[1]==="@"?Zt:tt}),r.removeAttribute(m);}else m.startsWith(N)&&(c.push({type:6,index:o}),r.removeAttribute(m));if(Ue.test(r.tagName)){let m=r.textContent.split(N),b=m.length-1;if(b>0){r.textContent=Dt?Dt.emptyScript:"";for(let $=0;$<b;$++)r.append(m[$],gt()),W.nextNode(),c.push({type:2,index:++o});r.append(m[b],gt());}}}else if(r.nodeType===8)if(r.data===Pe)c.push({type:2,index:o});else {let m=-1;for(;(m=r.data.indexOf(N,m+1))!==-1;)c.push({type:7,index:o}),m+=N.length-1;}o++;}}static createElement(e,t){let s=j.createElement("template");return s.innerHTML=e,s}};function Z(i,e,t=i,s){if(e===Q)return e;let r=s!==void 0?t._$Co?.[s]:t._$Cl,o=bt(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=Z(i,r._$AS(i,e.values),r,s)),e}var Kt=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??j).importNode(t,true);W.currentNode=r;let o=W.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 te(o,this,e)),this._$AV.push(p),c=s[++l];}n!==c?.index&&(o=W.nextNode(),n++);}return W.currentNode=j,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=Z(this,e,t),bt(e)?e===d||e==null||e===""?(this._$AH!==d&&this._$AR(),this._$AH=d):e!==this._$AH&&e!==Q&&this._(e):e._$litType$!==void 0?this.$(e):e.nodeType!==void 0?this.T(e):Bs(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&&bt(this._$AH)?this._$AA.nextSibling.data=e:this.T(j.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=Et.createElement(Fe(s.h,s.h[0]),this.options)),s);if(this._$AH?._$AD===r)this._$AH.p(t);else {let o=new Kt(r,this),n=o.u(this.options);o.p(t),this.T(n),this._$AH=o;}}_$AC(e){let t=He.get(e.strings);return t===void 0&&He.set(e.strings,t=new Et(e)),t}k(e){ee(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=Le(e).nextSibling;Le(e).remove(),e=s;}}setConnected(e){this._$AM===void 0&&(this._$Cv=e,this._$AP?.(e));}},tt=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=Z(this,e,t,0),n=!bt(e)||e!==this._$AH&&e!==Q,n&&(this._$AH=e);else {let l=e,c,p;for(e=o[0],c=0;c<o.length-1;c++)p=Z(this,l[s+c],t,c),p===Q&&(p=this._$AH[c]),n||(n=!bt(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??"");}},zt=class extends tt{constructor(){super(...arguments),this.type=3;}j(e){this.element[this.name]=e===d?void 0:e;}},Jt=class extends tt{constructor(){super(...arguments),this.type=4;}j(e){this.element.toggleAttribute(this.name,!!e&&e!==d);}},Zt=class extends tt{constructor(e,t,s,r,o){super(e,t,s,r,o),this.type=5;}_$AI(e,t=this){if((e=Z(this,e,t,0)??d)===Q)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);}},te=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){Z(this,e);}};var Ws=ft.litHtmlPolyfillSupport;Ws?.(Et,_t),(ft.litHtmlVersions??(ft.litHtmlVersions=[])).push("3.3.2");var Be=(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 k{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=Be(t,this.renderRoot,this.renderOptions);}connectedCallback(){super.connectedCallback(),this._$Do?.setConnected(true);}disconnectedCallback(){super.disconnectedCallback(),this._$Do?.setConnected(false);}render(){return Q}};f._$litElement$=true,f.finalized=true,St.litElementHydrateSupport?.({LitElement:f});var js=St.litElementPolyfillSupport;js?.({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 Qs={attribute:true,type:String,converter:mt,reflect:false,hasChanged:Ot},Vs=(i=Qs,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 T(i){return (e,t)=>typeof t=="object"?Vs(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 E(i){return T({...i,state:true,attribute:false})}var $t=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>`}};h([T()],$t.prototype,"method",2),$t=h([g("bk-method-badge")],$t);var I="/__brakit/api",O="/__brakit",y={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 et="polling",Ht="static",Ys="auth-handshake",Xs="auth-check",Ks="middleware",Tt={[Ys]:1,[Xs]:1,[Ks]:1};var re="fetch";var ie="error_event",oe="query",ne="issues";var ae={overview:"Overview",queries:"Queries",requests:"Requests",actions:"Actions",errors:"Errors",security:"Security",fetches:"Fetches",logs:"Logs",performance:"Performance"};var yt={overview:"Overview",actions:"Actions",requests:"Requests",fetches:"Server Fetches",queries:"Queries",errors:"Errors",logs:"Logs",performance:"Performance",security:"Security"},le={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 de=100,V=300,Y=800,pe=2e3,ue=100,he=50,me=500;var H="__all__",Ft={SELECT:"var(--blue)",INSERT:"var(--green)",UPDATE:"var(--amber)",DELETE:"var(--red)",COUNT:"var(--text-muted)"},ze={error:"var(--red)",warn:"var(--amber)",info:"var(--blue)",debug:"var(--text-muted)",log:"var(--text-dim)"},fe=["#2563eb","#7c3aed","#16a34a","#d97706","#dc2626","#0891b2","#ea580c","#c026d3","#059669","#db2777"],xt={green:"#4ade80",amber:"#fbbf24",red:"#f87171"},Bt=[{max:de,label:"Fast",color:"var(--green)",bg:"rgba(22,163,74,0.08)",border:"rgba(22,163,74,0.2)"},{max:V,label:"Good",color:"var(--green)",bg:"rgba(22,163,74,0.06)",border:"rgba(22,163,74,0.15)"},{max:Y,label:"OK",color:"var(--amber)",bg:"rgba(217,119,6,0.06)",border:"rgba(217,119,6,0.15)"},{max:pe,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)"}],Je="rgba(228,228,231,0.8)",ge="rgba(113,113,122,0.7)",Ze="10px monospace",be="9px monospace",ts="8px monospace",es={top:16,right:16,bottom:28,left:52},ss={fetch:"var(--blue)",log:"var(--text-muted)",error:"var(--red)",query:"var(--accent)"},rs={fetch:"FETCH",log:"LOG",error:"ERROR",query:"QUERY"},is=new Set(["cookie","set-cookie","authorization","proxy-authorization","x-api-key","x-auth-token"]),os={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"},ns=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 S(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,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,"""):""}function st(i){return i>=500?"status-pill-5xx":i>=400?"status-pill-4xx":i>=300?"status-pill-3xx":"status-pill-2xx"}function as(i){return os[i]||(i>=500?"Server Error":i>=400?"Client Error":"OK")}function zs(i,e){if(is.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(zs(e,t))).join(`
|
|
4
|
+
`)}function X(i){if(!i)return '<span style="color:var(--text-muted)">No body</span>';try{let e=JSON.parse(i);return Js(JSON.stringify(e,null,2))}catch{return P(i)}}function Js(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 Rt=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>`}};h([T({type:Number})],Rt.prototype,"code",2),Rt=h([g("bk-status-pill")],Rt);var wt=class extends f{constructor(){super(...arguments);this.ms=0;}createRenderRoot(){return this}render(){return a`<span class="req-duration">${S(this.ms)}</span>`}};h([T({type:Number})],wt.prototype,"ms",2),wt=h([g("bk-duration-label")],wt);var it=class extends f{constructor(){super(...arguments);this.title="";this.subtitle="";}createRenderRoot(){return this}render(){return a`
|
|
5
5
|
<div class="empty">
|
|
6
6
|
<span class="empty-title">${this.title}</span>
|
|
7
7
|
<span class="empty-sub">${this.subtitle}</span>
|
|
8
8
|
</div>
|
|
9
|
-
`}};
|
|
9
|
+
`}};h([T()],it.prototype,"title",2),h([T()],it.prototype,"subtitle",2),it=h([g("bk-empty-state")],it);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>`}};h([E()],C.prototype,"message",2),h([E()],C.prototype,"visible",2),C=h([g("bk-toast")],C);var K=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>`}};h([T()],K.prototype,"text",2),h([T()],K.prototype,"label",2),h([T({attribute:"toast-message"})],K.prototype,"toastMessage",2),K=h([g("bk-copy-button")],K);var z=class extends f{constructor(){super(...arguments);this.value="";this.label="";this.color="";}createRenderRoot(){return this}render(){return a`
|
|
10
10
|
<div class="fetch-stat">
|
|
11
11
|
<span class="fetch-stat-value" style="color:${this.color}">${this.value}</span>
|
|
12
12
|
<span class="fetch-stat-label">${this.label}</span>
|
|
13
13
|
</div>
|
|
14
|
-
`}};
|
|
14
|
+
`}};h([T()],z.prototype,"value",2),h([T()],z.prototype,"label",2),h([T()],z.prototype,"color",2),z=h([g("bk-stat-card")],z);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 ot=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 Gt=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 Ee=class extends Event{constructor(e,t){super("context-provider",{bubbles:true,composed:true}),this.context=e,this.contextTarget=t;}},nt=class extends Gt{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 Ee(this.context,this.host));}};function _e({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 ot(this,{context:i,callback:r=>{t.set.call(this,r);},subscribe:e});})):t.constructor.addInitializer((r=>{new ot(r,{context:i,callback:o=>{r[s]=o;},subscribe:e});}));}}var x="dashboard-store",Wt=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`
|
|
15
15
|
<div
|
|
16
|
-
class="req-row tel-clickable ${
|
|
16
|
+
class="req-row tel-clickable ${o?"expanded":""}"
|
|
17
17
|
@click=${()=>this.toggleError(s)}
|
|
18
18
|
>
|
|
19
19
|
<span class="tel-error-name" title=${t.name}>${t.name}</span>
|
|
20
20
|
<span class="tel-message" title=${t.message}>${t.message}</span>
|
|
21
21
|
<span class="tel-timestamp">${r}</span>
|
|
22
22
|
</div>
|
|
23
|
-
${
|
|
24
|
-
`}render(){let t=this.store.state.errors;return t.length===0?
|
|
23
|
+
${o&&t.stack?a`<div class="error-stack">${t.stack}</div>`:d}
|
|
24
|
+
`}render(){let t=this.store.state.errors;return t.length===0?a`<bk-empty-state
|
|
25
25
|
title="No errors"
|
|
26
26
|
subtitle="No errors have been captured yet"
|
|
27
|
-
></bk-empty-state>`:
|
|
27
|
+
></bk-empty-state>`:a`
|
|
28
28
|
<div class="col-header">
|
|
29
29
|
<span style="width:180px">Type</span>
|
|
30
30
|
<span style="flex:1">Message</span>
|
|
@@ -33,27 +33,27 @@
|
|
|
33
33
|
<div id="error-list">
|
|
34
34
|
${t.map((s,r)=>this.renderErrorRow(s,r))}
|
|
35
35
|
</div>
|
|
36
|
-
`}};
|
|
36
|
+
`}};h([R({context:x})],at.prototype,"store",2),h([E()],at.prototype,"expandedIdx",2),at=h([g("bk-errors-view")],at);var At=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`
|
|
37
37
|
<div id="log-analysis">
|
|
38
38
|
<div class="fetch-summary">
|
|
39
39
|
<bk-stat-card value=${String(e.length)} label="Total Logs"></bk-stat-card>
|
|
40
|
-
${t.error>0?
|
|
41
|
-
${t.warn>0?
|
|
40
|
+
${t.error>0?a`<bk-stat-card value=${String(t.error)} label="Errors" color="var(--red)"></bk-stat-card>`:d}
|
|
41
|
+
${t.warn>0?a`<bk-stat-card value=${String(t.warn)} label="Warnings" color="var(--amber)"></bk-stat-card>`:d}
|
|
42
42
|
<bk-stat-card value=${String(t.info)} label="Info"></bk-stat-card>
|
|
43
|
-
${t.debug>0?
|
|
44
|
-
${t.log>0?
|
|
43
|
+
${t.debug>0?a`<bk-stat-card value=${String(t.debug)} label="Debug"></bk-stat-card>`:d}
|
|
44
|
+
${t.log>0?a`<bk-stat-card value=${String(t.log)} label="Log"></bk-stat-card>`:d}
|
|
45
45
|
</div>
|
|
46
46
|
</div>
|
|
47
|
-
`}renderLogRow(e){let t=new Date(e.timestamp).toLocaleTimeString();return
|
|
47
|
+
`}renderLogRow(e){let t=new Date(e.timestamp).toLocaleTimeString();return a`
|
|
48
48
|
<div class="req-row">
|
|
49
49
|
<span class="tel-level tel-level-${e.level}">${e.level.toUpperCase()}</span>
|
|
50
50
|
<span class="tel-message tel-mono" title=${e.message}>${e.message}</span>
|
|
51
51
|
<span class="tel-timestamp">${t}</span>
|
|
52
52
|
</div>
|
|
53
|
-
`}render(){let e=this.store.state.logs;return e.length===0?
|
|
53
|
+
`}render(){let e=this.store.state.logs;return e.length===0?a`<bk-empty-state
|
|
54
54
|
title="No logs"
|
|
55
55
|
subtitle="No console output has been captured yet"
|
|
56
|
-
></bk-empty-state>`:
|
|
56
|
+
></bk-empty-state>`:a`
|
|
57
57
|
${this.renderAnalysis(e)}
|
|
58
58
|
<div class="col-header">
|
|
59
59
|
<span style="width:52px">Level</span>
|
|
@@ -63,28 +63,28 @@
|
|
|
63
63
|
<div id="log-list">
|
|
64
64
|
${e.map(t=>this.renderLogRow(t))}
|
|
65
65
|
</div>
|
|
66
|
-
`}};
|
|
66
|
+
`}};h([R({context:x})],At.prototype,"store",2),At=h([g("bk-logs-view")],At);var tr=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 ls(i){let e=i.trim().match(/^(\w+)/);return e?e[1].toUpperCase():"?"}function cs(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 ds(i){return P(i).replace(/\b\w+\b/g,e=>tr.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":S(t)}getQueryInfo(t){let s=(t.normalizedOp||t.operation||(t.sql?ls(t.sql):"?")).toUpperCase(),r=t.table||t.model||(t.sql?cs(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>ue,p=t.sql||r+" "+o,u=this.expandedIdx===s;return a`
|
|
67
67
|
<div>
|
|
68
68
|
<div
|
|
69
|
-
class="req-row query-row tel-clickable ${
|
|
69
|
+
class="req-row query-row tel-clickable ${u?"expanded":""}"
|
|
70
70
|
@click=${()=>this.toggleQuery(s)}
|
|
71
71
|
>
|
|
72
|
-
<span class="query-op" title=${r} style="color:${
|
|
73
|
-
<span class="query-table" title=${
|
|
74
|
-
<span class="query-preview" title=${
|
|
75
|
-
<span class="query-dur${
|
|
76
|
-
</div>
|
|
77
|
-
<div class="query-detail ${
|
|
78
|
-
${
|
|
79
|
-
<pre class="query-detail-sql" .innerHTML=${ds(
|
|
80
|
-
<bk-copy-button .text=${
|
|
72
|
+
<span class="query-op" title=${r} style="color:${l}">${r}</span>
|
|
73
|
+
<span class="query-table" title=${o}>${o}</span>
|
|
74
|
+
<span class="query-preview" title=${p}>${p}</span>
|
|
75
|
+
<span class="query-dur${c?" query-slow":""}">${this.queryDuration(t.durationMs)}</span>
|
|
76
|
+
</div>
|
|
77
|
+
<div class="query-detail ${u?"open":""}">
|
|
78
|
+
${u?a`
|
|
79
|
+
<pre class="query-detail-sql" .innerHTML=${ds(n)}></pre>
|
|
80
|
+
<bk-copy-button .text=${n} label="Copy"></bk-copy-button>
|
|
81
81
|
`:d}
|
|
82
82
|
</div>
|
|
83
83
|
</div>
|
|
84
|
-
`}render(){let t=this.store.state.queries;return t.length===0?
|
|
84
|
+
`}render(){let t=this.store.state.queries;return t.length===0?a`<bk-empty-state
|
|
85
85
|
title="No queries"
|
|
86
86
|
subtitle="No database queries have been captured yet"
|
|
87
|
-
></bk-empty-state>`:
|
|
87
|
+
></bk-empty-state>`:a`
|
|
88
88
|
<div class="col-header">
|
|
89
89
|
<span style="width:70px;border-right:1px solid var(--border);padding-right:16px">Operation</span>
|
|
90
90
|
<span style="width:170px;border-right:1px solid var(--border);padding-right:16px">Table</span>
|
|
@@ -94,35 +94,35 @@
|
|
|
94
94
|
<div id="query-list">
|
|
95
95
|
${t.map((s,r)=>this.renderQueryRow(s,r))}
|
|
96
96
|
</div>
|
|
97
|
-
`}};
|
|
97
|
+
`}};h([R({context:x})],lt.prototype,"store",2),h([E()],lt.prototype,"expandedIdx",2),lt=h([g("bk-queries-view")],lt);function Se(i){return i.replace(/'/g,"'\\''")}function er(i,e){let t=Object.entries(i.headers||{}).filter(([o])=>!ns.has(o)).map(([o,n])=>`-H '${Se(o)}: ${Se(n)}'`).join(" "),s=i.requestBody?` -d '${Se(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=er(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`
|
|
98
98
|
<div class="detail-meta">
|
|
99
99
|
<span><bk-method-badge .method=${t.method}></bk-method-badge> ${t.url}</span>
|
|
100
100
|
<span><bk-status-pill .code=${t.statusCode}></bk-status-pill></span>
|
|
101
101
|
<span>${t.durationMs}ms</span>
|
|
102
|
-
${t.responseSize?
|
|
102
|
+
${t.responseSize?a`<span>${U(t.responseSize)}</span>`:d}
|
|
103
103
|
</div>
|
|
104
104
|
<div class="request-timeline tl-hidden" data-request-id=${t.id} data-request-started=${String(t.startedAt)}></div>
|
|
105
105
|
<div class="detail-grid">
|
|
106
|
-
<div class="detail-section"><h4>Request Headers</h4><pre .innerHTML=${
|
|
107
|
-
<div class="detail-section"><h4>Response Headers</h4><pre .innerHTML=${
|
|
106
|
+
<div class="detail-section"><h4>Request Headers</h4><pre .innerHTML=${rt(t.headers)}></pre></div>
|
|
107
|
+
<div class="detail-section"><h4>Response Headers</h4><pre .innerHTML=${rt(t.responseHeaders)}></pre></div>
|
|
108
108
|
<div class="detail-section"><h4>Request Body</h4><pre .innerHTML=${X(t.requestBody)}></pre></div>
|
|
109
109
|
<div class="detail-section"><h4>Response Body</h4><pre .innerHTML=${X(t.responseBody)}></pre></div>
|
|
110
110
|
</div>
|
|
111
111
|
<div class="detail-actions">
|
|
112
112
|
<button class="btn btn-curl" @click=${s=>this.handleCopyAsCurl(t,s)}>Copy cURL</button>
|
|
113
113
|
</div>
|
|
114
|
-
`}renderRequestRow(t){let s=this.expandedId===t.id;return
|
|
114
|
+
`}renderRequestRow(t){let s=this.expandedId===t.id;return a`
|
|
115
115
|
<div class="req-row ${s?"expanded":""}" @click=${()=>this.toggleRequest(t.id)}>
|
|
116
116
|
<div class="req-summary">
|
|
117
117
|
<bk-method-badge .method=${t.method}></bk-method-badge>
|
|
118
118
|
<span class="req-url">${t.url}</span>
|
|
119
119
|
<bk-status-pill .code=${t.statusCode}></bk-status-pill>
|
|
120
120
|
<bk-duration-label .ms=${t.durationMs}></bk-duration-label>
|
|
121
|
-
<span class="req-size">${
|
|
121
|
+
<span class="req-size">${U(t.responseSize)}</span>
|
|
122
122
|
</div>
|
|
123
123
|
</div>
|
|
124
124
|
<div class="req-detail ${s?"open":""}">${s?this.renderDetail(t):d}</div>
|
|
125
|
-
`}render(){let t=this.store.state.requests.filter(s=>!s.path?.startsWith(O));return t.length===0?
|
|
125
|
+
`}render(){let t=this.store.state.requests.filter(s=>!s.path?.startsWith(O));return t.length===0?a`<bk-empty-state title="No requests" subtitle="No HTTP requests have been captured yet"></bk-empty-state>`:a`
|
|
126
126
|
<div class="col-header">
|
|
127
127
|
<span style="width:60px">Method</span>
|
|
128
128
|
<span style="flex:1">URL</span>
|
|
@@ -131,19 +131,19 @@
|
|
|
131
131
|
<span style="width:60px;text-align:right">Size</span>
|
|
132
132
|
</div>
|
|
133
133
|
<div id="request-list">${t.map(s=>this.renderRequestRow(s))}</div>
|
|
134
|
-
`}};
|
|
134
|
+
`}};h([R({context:x})],dt.prototype,"store",2),h([E()],dt.prototype,"expandedId",2),dt=h([g("bk-requests-view")],dt);var Ct=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`
|
|
135
135
|
<div class="fetch-summary">
|
|
136
136
|
<bk-stat-card value=${String(e.length)} label="Total Fetches"></bk-stat-card>
|
|
137
137
|
<bk-stat-card value=${String(t.size)} label="Unique URLs"></bk-stat-card>
|
|
138
138
|
<bk-stat-card value=${String(s)} label="Errors" color=${s>0?"var(--red)":""}></bk-stat-card>
|
|
139
|
-
<bk-stat-card value=${S(
|
|
139
|
+
<bk-stat-card value=${S(o)} label="Avg Duration"></bk-stat-card>
|
|
140
140
|
</div>
|
|
141
|
-
`}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),
|
|
141
|
+
`}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`
|
|
142
142
|
<div class="fetch-group">
|
|
143
143
|
<div class="fetch-group-header">
|
|
144
144
|
<bk-method-badge .method=${e.method}></bk-method-badge>
|
|
145
145
|
<span class="fetch-group-url" title=${e.url}>${e.url}</span>
|
|
146
|
-
${
|
|
146
|
+
${n>0?a`<bk-status-pill .code=${n}></bk-status-pill>`:d}
|
|
147
147
|
<span class="fetch-group-count">${e.count}x</span>
|
|
148
148
|
</div>
|
|
149
149
|
<div class="fetch-group-meta">
|
|
@@ -151,30 +151,33 @@
|
|
|
151
151
|
<span class="fetch-group-sep">\u00b7</span>
|
|
152
152
|
<span>max ${S(e.maxDur)}</span>
|
|
153
153
|
<span class="fetch-group-sep">\u00b7</span>
|
|
154
|
-
${s>0?
|
|
154
|
+
${s>0?a`<span class="fetch-group-err">${s}% errors</span>`:a`<span class="fetch-group-ok">0% errors</span>`}
|
|
155
155
|
</div>
|
|
156
|
-
${e.firstTs>0?
|
|
156
|
+
${e.firstTs>0?a`
|
|
157
157
|
<div class="fetch-group-timeline">
|
|
158
158
|
<span class="fetch-group-timeline-dot"></span>
|
|
159
159
|
<span class="fetch-group-timeline-range">
|
|
160
|
-
${this.formatTime(e.firstTs)}${e.firstTs!==e.lastTs?
|
|
160
|
+
${this.formatTime(e.firstTs)}${e.firstTs!==e.lastTs?a` \u2192 ${this.formatTime(e.lastTs)}`:d}
|
|
161
161
|
</span>
|
|
162
162
|
</div>`:d}
|
|
163
|
-
${r.length>0?
|
|
163
|
+
${r.length>0?a`
|
|
164
164
|
<div class="fetch-group-callers">
|
|
165
165
|
<span class="fetch-group-callers-label">Called by</span>
|
|
166
|
-
${r.map(
|
|
166
|
+
${r.map(l=>a`<span class="fetch-group-caller-pill">${l}</span>`)}
|
|
167
167
|
</div>`:d}
|
|
168
168
|
</div>
|
|
169
|
-
`}render(){let e=this.store.state.fetches,t=this.store.state.requests;if(e.length===0)return
|
|
169
|
+
`}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`
|
|
170
170
|
<div class="fetch-analysis" id="fetch-analysis">
|
|
171
171
|
${this.renderSummary(e)}
|
|
172
|
-
${s.length>0?
|
|
172
|
+
${s.length>0?a`
|
|
173
173
|
<div class="fetch-groups-title">Grouped by URL (${s.length})</div>
|
|
174
174
|
<div class="fetch-groups">${s.map(r=>this.renderGroup(r))}</div>
|
|
175
175
|
`:d}
|
|
176
176
|
</div>
|
|
177
|
-
`}};
|
|
177
|
+
`}};h([R({context:x})],Ct.prototype,"store",2),Ct=h([g("bk-fetches-view")],Ct);function ps(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 or(i){return i.type==="query"||i.type==="fetch"}function nr(i){let e=(i.normalizedOp||i.operation||"QUERY").toUpperCase(),t=i.table||i.model||"";return {label:`${e} ${t}`,tooltip:i.sql||`${e} ${t}`}}function ar(i){return {label:`${i.method} ${i.url}`,tooltip:`${i.method} ${i.url}`}}function lr(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 cr(i,e){let t=i.timeline.filter(or);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:u}=lr(n,l,t,s,r,o),m=n.type==="query"?nr(n.data):ar(n.data);return {type:n.type,label:m.label,durMs:c,durLabel:S(c),tooltip:m.tooltip,leftPct:p,widthPct:u}})}function hs(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),u=e?.activities?.[l.id],m=u?cr(u,l):[];return {label:`${l.method} ${l.label}`,leftPct:c,widthPct:p,color:ps(l.method,l.statusCode),durMs:l.durationMs,durLabel:S(l.durationMs),tooltip:`${l.method} ${l.label} (${S(l.durationMs)})`,subEvents:m}}),totalMs:o}}function ms(i){let e=i.requests,t=[],s=[],r=[],o=[],n=new Map;for(let p of e){let u=p.label,m=p.pollingDurationMs||p.durationMs;if(!Tt[p.category||""]){if(p.isDuplicate){let b=n.get(u);b?(b.count++,b.wastedMs+=m):n.set(u,{name:u,count:2,wastedMs:m});continue}if(p.statusCode>=400){s.push(u+" ("+as(p.statusCode)+")");continue}p.responseSize>51200&&r.push("Large response: "+u+" returned "+U(p.responseSize)),t.push(u);}}for(let p of n.values())o.push(p);let l="";if(o.length>0){let p=o.map(m=>m.name).join(", "),u=o.reduce((m,b)=>m+b.wastedMs,0);l="Your app fetches "+p+" multiple times on this page. This wastes ~"+S(u)+". 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!==et);return c.length>0&&!l&&(l=c.map(p=>p.label).join(", ")+` is taking over ${S(2e3)}. Consider adding caching or optimizing the backend query.`),{successes:t,errors:s,warnings:r,duplicates:o,tip:l}}var M=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(`${y.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
|
|
178
|
+
title="No actions yet"
|
|
179
|
+
subtitle="Start using your app to see user action flows here"
|
|
180
|
+
></bk-empty-state>`:a`
|
|
178
181
|
<div id="flow-col-header" class="col-header">
|
|
179
182
|
<span style="width:8px"></span>
|
|
180
183
|
<span style="flex:1">Action</span>
|
|
@@ -182,83 +185,203 @@
|
|
|
182
185
|
<span style="width:120px;text-align:right">Status</span>
|
|
183
186
|
<span style="width:70px;text-align:right">Time</span>
|
|
184
187
|
</div>
|
|
185
|
-
<div id="flow-list"
|
|
186
|
-
|
|
187
|
-
|
|
188
|
+
<div id="flow-list">
|
|
189
|
+
${t.map((s,r)=>this.renderFlowRow(s,r))}
|
|
190
|
+
</div>
|
|
191
|
+
`}renderFlowRow(t,s){let r=this.expandedFlowIdx===s,o=this.flowDotClass(t),n=this.flowBadgeInfo(t);return a`
|
|
192
|
+
<div
|
|
193
|
+
class="flow-row ${r?"expanded":""}"
|
|
194
|
+
@click=${()=>this.toggleFlow(s)}
|
|
195
|
+
>
|
|
188
196
|
<div class="flow-summary-row">
|
|
189
|
-
<span class="flow-status-dot ${
|
|
197
|
+
<span class="flow-status-dot ${o}"></span>
|
|
190
198
|
<span class="flow-label">${t.label}</span>
|
|
191
|
-
<span class="flow-req-count"
|
|
192
|
-
|
|
193
|
-
|
|
199
|
+
<span class="flow-req-count"
|
|
200
|
+
>${t.requests.length}
|
|
201
|
+
req${t.requests.length!==1?"s":""}</span
|
|
202
|
+
>
|
|
203
|
+
<span class="flow-badge-pill ${n.cls}">${n.text}</span>
|
|
204
|
+
<span class="flow-duration"
|
|
205
|
+
>${S(t.totalDurationMs)}</span
|
|
206
|
+
>
|
|
194
207
|
</div>
|
|
195
208
|
</div>
|
|
196
209
|
<div class="flow-expand ${r?"open":""}">
|
|
197
|
-
${r?this.
|
|
210
|
+
${r?this.renderFlowDetail(t):d}
|
|
198
211
|
</div>
|
|
199
|
-
`}
|
|
200
|
-
<div>
|
|
201
|
-
<
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
212
|
+
`}renderFlowDetail(t){let s=this.viewMode==="simple"?"Insights":"Details";return a`
|
|
213
|
+
<div class="flow-detail-tabs">
|
|
214
|
+
<button
|
|
215
|
+
class="flow-tab ${this.flowDetailTab==="insights"?"active":""}"
|
|
216
|
+
@click=${r=>this.switchTab("insights",t,r)}
|
|
217
|
+
>
|
|
218
|
+
${s}
|
|
219
|
+
</button>
|
|
220
|
+
<button
|
|
221
|
+
class="flow-tab ${this.flowDetailTab==="timeline"?"active":""}"
|
|
222
|
+
@click=${r=>this.switchTab("timeline",t,r)}
|
|
223
|
+
>
|
|
224
|
+
Timeline
|
|
225
|
+
</button>
|
|
226
|
+
</div>
|
|
227
|
+
${this.flowDetailTab==="insights"?this.viewMode==="simple"?this.renderFlowInsights(t):this.renderFlowSubReqs(t):this.renderFlowWaterfall(t)}
|
|
228
|
+
`}renderFlowWaterfall(t){if(this.flowTimelineLoading)return a`<div class="wf-loading">Loading timeline...</div>`;let{rows:s,totalMs:r}=hs(t,this.flowTimeline);if(s.length===0)return d;let o=[];for(let n=0;n<=5;n++)o.push(S(r/5*n));return a`
|
|
229
|
+
<div class="flow-waterfall">
|
|
230
|
+
<div class="wf-time-axis">
|
|
231
|
+
${o.map(n=>a`<span>${n}</span>`)}
|
|
232
|
+
</div>
|
|
233
|
+
<div class="wf-rows">
|
|
234
|
+
${s.map(n=>this.renderWaterfallGroup(n))}
|
|
235
|
+
</div>
|
|
236
|
+
</div>
|
|
237
|
+
`}renderWaterfallGroup(t){return a`
|
|
238
|
+
<div class="wf-request-group">
|
|
239
|
+
<div class="wf-req-row" title="${t.tooltip}">
|
|
240
|
+
<div class="wf-req-label">${t.label}</div>
|
|
241
|
+
<div class="wf-bar-track">
|
|
242
|
+
<div
|
|
243
|
+
class="wf-bar"
|
|
244
|
+
style="left:${t.leftPct}%;width:${t.widthPct}%;background:${t.color}"
|
|
245
|
+
></div>
|
|
209
246
|
</div>
|
|
210
|
-
|
|
247
|
+
<div class="wf-req-dur">${t.durLabel}</div>
|
|
248
|
+
</div>
|
|
249
|
+
${t.subEvents.length>0?t.subEvents.map(s=>a`
|
|
250
|
+
<div class="wf-sub-row" title="${s.tooltip}">
|
|
251
|
+
<div class="wf-sub-label">
|
|
252
|
+
<span
|
|
253
|
+
class="wf-sub-dot"
|
|
254
|
+
style="background:${$e(s.type)}"
|
|
255
|
+
></span>
|
|
256
|
+
${s.label}
|
|
257
|
+
</div>
|
|
258
|
+
<div class="wf-bar-track">
|
|
259
|
+
<div
|
|
260
|
+
class="wf-bar wf-sub-bar-sized"
|
|
261
|
+
style="left:${t.leftPct+s.leftPct/100*t.widthPct}%;width:${s.widthPct/100*t.widthPct}%;background:${$e(s.type)}"
|
|
262
|
+
></div>
|
|
263
|
+
</div>
|
|
264
|
+
<div class="wf-sub-dur">${s.durLabel}</div>
|
|
265
|
+
</div>
|
|
266
|
+
`):d}
|
|
267
|
+
</div>
|
|
268
|
+
`}renderFlowInsights(t){let s=ms(t),r=s.errors.length>0||s.duplicates.length>0||s.warnings.length>0||!!s.tip;return a`
|
|
269
|
+
<div>
|
|
270
|
+
<div class="flow-traffic">
|
|
271
|
+
${t.requests.map(o=>this.renderTrafficCard(o))}
|
|
272
|
+
</div>
|
|
273
|
+
${r?a`
|
|
274
|
+
<div class="flow-divider"></div>
|
|
275
|
+
<div class="flow-insights">
|
|
276
|
+
${s.errors.map(o=>a`<div class="insight-line insight-error">
|
|
277
|
+
✗ ${o}
|
|
278
|
+
</div>`)}
|
|
279
|
+
${s.duplicates.map(o=>a`<div class="insight-line insight-warn">
|
|
280
|
+
⚠ ${o.name} — loaded ${o.count}x (wasting
|
|
281
|
+
~${S(o.wastedMs)})
|
|
282
|
+
</div>`)}
|
|
283
|
+
${s.warnings.map(o=>a`<div class="insight-line insight-warn">⚠ ${o}</div>`)}
|
|
284
|
+
${s.tip?a`<div class="insight-line insight-tip">
|
|
285
|
+
Tip: ${s.tip}
|
|
286
|
+
</div>`:d}
|
|
287
|
+
</div>
|
|
288
|
+
`:d}
|
|
211
289
|
</div>
|
|
212
|
-
`}renderTrafficCard(t){if(
|
|
213
|
-
<div
|
|
214
|
-
|
|
290
|
+
`}renderTrafficCard(t){if(Tt[t.category||""])return d;let s=st(t.statusCode),r=S(t.pollingDurationMs||t.durationMs),o=!t.isDuplicate&&t.category!==Ht&&t.category!==et||t.requestBody&&t.method!=="GET"||!!t.responseBody;return a`
|
|
291
|
+
<div
|
|
292
|
+
class="traffic-card ${t.isStrictModeDupe?"strict-mode-dupe":""}"
|
|
293
|
+
>
|
|
294
|
+
<div class="traffic-card-header ${o?"has-details":""}">
|
|
215
295
|
<bk-method-badge .method=${t.method}></bk-method-badge>
|
|
216
|
-
<span class="traffic-card-path ${t.isDuplicate?"is-dup":""}"
|
|
296
|
+
<span class="traffic-card-path ${t.isDuplicate?"is-dup":""}"
|
|
297
|
+
>${t.label}</span
|
|
298
|
+
>
|
|
217
299
|
<span class="status-pill ${s}">${t.statusCode}</span>
|
|
218
300
|
<span class="traffic-card-dur">${r}</span>
|
|
219
|
-
${t.isDuplicate?
|
|
301
|
+
${t.isDuplicate?a`<span class="traffic-card-dup">duplicate</span>`:a`<span class="traffic-card-size"
|
|
302
|
+
>${U(t.responseSize)}</span
|
|
303
|
+
>`}
|
|
220
304
|
</div>
|
|
221
|
-
${t.isStrictModeDupe?
|
|
222
|
-
|
|
305
|
+
${t.isStrictModeDupe?a`<div class="strict-mode-banner">
|
|
306
|
+
React Strict Mode duplicate — does not happen in production
|
|
307
|
+
</div>`:d}
|
|
308
|
+
${!t.isDuplicate&&t.category!==Ht&&t.category!==et?a`<div
|
|
309
|
+
class="request-timeline tl-hidden"
|
|
310
|
+
data-request-id=${t.id}
|
|
311
|
+
data-request-started=${String(t.startedAt)}
|
|
312
|
+
></div>`:d}
|
|
223
313
|
${t.requestBody&&t.method!=="GET"?this.renderBodyToggle("out","Request Body",t.requestBody):d}
|
|
224
314
|
${t.responseBody?this.renderBodyToggle("in","Response Body",t.responseBody):d}
|
|
225
315
|
</div>
|
|
226
|
-
`}renderBodyToggle(t,s,r){let
|
|
316
|
+
`}renderBodyToggle(t,s,r){let o=t==="out"?"\u2192":"\u2190";return a`
|
|
227
317
|
<div class="traffic-body">
|
|
228
318
|
<button class="traffic-body-toggle" @click=${this.toggleBodyBlock}>
|
|
229
|
-
<span class="chevron"
|
|
319
|
+
<span class="chevron">▸</span
|
|
320
|
+
><span class="arrow-${t}">${o}</span> ${s}
|
|
230
321
|
</button>
|
|
231
322
|
<pre .innerHTML=${X(r)}></pre>
|
|
232
323
|
</div>
|
|
233
|
-
`}renderFlowSubReqs(t){return
|
|
234
|
-
|
|
324
|
+
`}renderFlowSubReqs(t){return a`<div class="flow-subreqs">
|
|
325
|
+
${t.requests.map((s,r)=>this.renderSubReqRow(s,r))}
|
|
326
|
+
</div>`}renderSubReqRow(t,s){let r=this.expandedSubReqIdx===s,o=st(t.statusCode),n=t.pollingDurationMs?S(t.pollingDurationMs):S(t.durationMs);return a`
|
|
327
|
+
<div
|
|
328
|
+
class="flow-subreq ${r?"expanded":""}"
|
|
329
|
+
@click=${l=>this.toggleSubReq(s,l)}
|
|
330
|
+
>
|
|
235
331
|
<bk-method-badge .method=${t.method}></bk-method-badge>
|
|
236
|
-
<span class="subreq-label ${t.isDuplicate?"is-dup":""}"
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
332
|
+
<span class="subreq-label ${t.isDuplicate?"is-dup":""}"
|
|
333
|
+
>${t.path||t.url}</span
|
|
334
|
+
>
|
|
335
|
+
${t.isDuplicate?a`<span class="subreq-dup-tag">duplicate</span>`:d}
|
|
336
|
+
<span class="status-pill ${o}">${t.statusCode}</span>
|
|
337
|
+
<span class="subreq-dur">${n}</span>
|
|
240
338
|
</div>
|
|
241
339
|
<div class="flow-subreq-detail ${r?"open":""}">
|
|
242
340
|
${r?this.renderSubReqDetail(t):d}
|
|
243
341
|
</div>
|
|
244
|
-
`}renderSubReqDetail(t){let s=
|
|
342
|
+
`}renderSubReqDetail(t){let s=st(t.statusCode);return a`
|
|
245
343
|
<div class="detail-meta">
|
|
246
|
-
<span
|
|
247
|
-
|
|
344
|
+
<span
|
|
345
|
+
><bk-method-badge .method=${t.method}></bk-method-badge> ${P(t.url)}</span
|
|
346
|
+
>
|
|
347
|
+
<span
|
|
348
|
+
><span class="status-pill ${s}">${t.statusCode}</span></span
|
|
349
|
+
>
|
|
248
350
|
<span>${t.durationMs}ms</span>
|
|
249
|
-
${t.responseSize?
|
|
351
|
+
${t.responseSize?a`<span>${U(t.responseSize)}</span>`:d}
|
|
250
352
|
</div>
|
|
251
|
-
<div
|
|
353
|
+
<div
|
|
354
|
+
class="request-timeline tl-hidden"
|
|
355
|
+
data-request-id=${t.id}
|
|
356
|
+
data-request-started=${String(t.startedAt)}
|
|
357
|
+
></div>
|
|
252
358
|
<div class="detail-grid">
|
|
253
|
-
<div class="detail-section"
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
359
|
+
<div class="detail-section">
|
|
360
|
+
<h4>Request Headers</h4>
|
|
361
|
+
<pre .innerHTML=${rt(t.headers)}></pre>
|
|
362
|
+
</div>
|
|
363
|
+
<div class="detail-section">
|
|
364
|
+
<h4>Response Headers</h4>
|
|
365
|
+
<pre .innerHTML=${rt(t.responseHeaders)}></pre>
|
|
366
|
+
</div>
|
|
367
|
+
<div class="detail-section">
|
|
368
|
+
<h4>Request Body</h4>
|
|
369
|
+
<pre .innerHTML=${X(t.requestBody)}></pre>
|
|
370
|
+
</div>
|
|
371
|
+
<div class="detail-section">
|
|
372
|
+
<h4>Response Body</h4>
|
|
373
|
+
<pre .innerHTML=${X(t.responseBody)}></pre>
|
|
374
|
+
</div>
|
|
257
375
|
</div>
|
|
258
376
|
<div class="detail-actions">
|
|
259
|
-
<button
|
|
377
|
+
<button
|
|
378
|
+
class="btn btn-curl"
|
|
379
|
+
@click=${r=>{r.stopPropagation(),ct(t);}}
|
|
380
|
+
>
|
|
381
|
+
Copy cURL
|
|
382
|
+
</button>
|
|
260
383
|
</div>
|
|
261
|
-
`}};
|
|
384
|
+
`}};h([R({context:x})],M.prototype,"store",2),h([E()],M.prototype,"expandedFlowIdx",2),h([E()],M.prototype,"expandedSubReqIdx",2),h([E()],M.prototype,"flowDetailTab",2),h([E()],M.prototype,"flowTimeline",2),h([E()],M.prototype,"flowTimelineLoading",2),M=h([g("bk-flows-view")],M);var It=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`
|
|
262
385
|
<div class="sec-clear">
|
|
263
386
|
<span class="sec-clear-icon">\u2713</span>
|
|
264
387
|
<div class="sec-clear-text">
|
|
@@ -266,10 +389,10 @@
|
|
|
266
389
|
<div class="sec-clear-sub">No security or quality issues detected this session</div>
|
|
267
390
|
</div>
|
|
268
391
|
</div>
|
|
269
|
-
`:
|
|
392
|
+
`: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`
|
|
270
393
|
<div id="security-content">
|
|
271
|
-
${this.renderSummary(t.length,s.length,r,
|
|
272
|
-
${t.length===0&&s.length>0?
|
|
394
|
+
${this.renderSummary(t.length,s.length,r,o,n)}
|
|
395
|
+
${t.length===0&&s.length>0?a`
|
|
273
396
|
<div class="sec-clear">
|
|
274
397
|
<span class="sec-clear-icon">\u2713</span>
|
|
275
398
|
<div class="sec-clear-text">
|
|
@@ -281,105 +404,105 @@
|
|
|
281
404
|
${t.length>0?this.renderOpenGroups(t):d}
|
|
282
405
|
${s.length>0?this.renderResolved(s):d}
|
|
283
406
|
</div>
|
|
284
|
-
`}renderSummary(e,t,s,r,
|
|
407
|
+
`}renderSummary(e,t,s,r,o){return a`
|
|
285
408
|
<div class="sec-summary">
|
|
286
409
|
<div class="sec-summary-left">
|
|
287
410
|
<span class="sec-summary-count">${e}</span>
|
|
288
411
|
<span class="sec-summary-label">open issue${e!==1?"s":""}</span>
|
|
289
|
-
${t>0?
|
|
412
|
+
${t>0?a`<span class="sec-resolved-badge">${t} resolved</span>`:d}
|
|
290
413
|
</div>
|
|
291
414
|
<div class="sec-summary-right">
|
|
292
|
-
${s>0?
|
|
293
|
-
${r>0?
|
|
294
|
-
${
|
|
415
|
+
${s>0?a`<span class="sec-badge critical">${s} critical</span>`:d}
|
|
416
|
+
${r>0?a`<span class="sec-badge warning">${r} warning</span>`:d}
|
|
417
|
+
${o>0?a`<span class="sec-badge info">${o} info</span>`:d}
|
|
295
418
|
</div>
|
|
296
419
|
</div>
|
|
297
|
-
`}renderOpenGroups(e){let t={},s=[];for(let r of e){let
|
|
420
|
+
`}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`
|
|
298
421
|
<div class="sec-group">
|
|
299
422
|
<div class="sec-group-header">
|
|
300
423
|
<span class="sec-group-icon ${t.cls}">${t.icon}</span>
|
|
301
424
|
<span class="sec-group-title">${e.title}</span>
|
|
302
425
|
<span class="sec-group-count">${e.items.length}</span>
|
|
303
426
|
</div>
|
|
304
|
-
${e.hint?
|
|
427
|
+
${e.hint?a`<div class="sec-hint">${e.hint}</div>`:d}
|
|
305
428
|
<div class="sec-items">${e.items.map(s=>this.renderIssueItem(s))}</div>
|
|
306
429
|
</div>
|
|
307
|
-
`}renderIssueItem(e){let t=e.issue;return
|
|
430
|
+
`}renderIssueItem(e){let t=e.issue;return a`
|
|
308
431
|
<div class="sec-item">
|
|
309
432
|
<div class="sec-item-desc">${t.desc}</div>
|
|
310
|
-
${e.occurrences>1?
|
|
311
|
-
${e.state==="fixing"&&e.aiStatus==="fixed"?
|
|
312
|
-
${e.aiNotes?
|
|
433
|
+
${e.occurrences>1?a`<span class="sec-item-count">${e.occurrences}x</span>`:d}
|
|
434
|
+
${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}
|
|
435
|
+
${e.aiNotes?a`<div class="sec-ai-notes">${e.aiNotes}</div>`:d}
|
|
313
436
|
</div>
|
|
314
|
-
`}renderResolved(e){return
|
|
437
|
+
`}renderResolved(e){return a`
|
|
315
438
|
<div class="sec-resolved-title">
|
|
316
439
|
<span class="sec-resolved-check">\u2713</span> Resolved
|
|
317
440
|
<span class="sec-resolved-count">${e.length}</span>
|
|
318
441
|
</div>
|
|
319
442
|
<div class="sec-group sec-group-resolved">
|
|
320
443
|
<div class="sec-items">
|
|
321
|
-
${e.map(t=>
|
|
444
|
+
${e.map(t=>a`
|
|
322
445
|
<div class="sec-item sec-item-resolved">
|
|
323
446
|
<span class="sec-resolved-item-icon">\u2713</span>
|
|
324
447
|
<div class="sec-item-desc">${t.issue.title} \u2014 ${t.issue.endpoint||"global"}</div>
|
|
325
|
-
${t.aiStatus==="fixed"?
|
|
326
|
-
${t.aiNotes?
|
|
448
|
+
${t.aiStatus==="fixed"?a`<span class="sec-ai-badge sec-ai-verified">Verified fix</span>`:d}
|
|
449
|
+
${t.aiNotes?a`<div class="sec-ai-notes">${t.aiNotes}</div>`:d}
|
|
327
450
|
</div>
|
|
328
451
|
`)}
|
|
329
452
|
</div>
|
|
330
453
|
</div>
|
|
331
|
-
`}};
|
|
454
|
+
`}};h([R({context:x})],It.prototype,"store",2),It=h([g("bk-security-view")],It);var pt=class extends f{constructor(){super(...arguments);this.expandedCardIdx=-1;}createRenderRoot(){return this}connectedCallback(){super.connectedCallback(),this.store.addEventListener("state-changed",()=>this.requestUpdate());}navigateToView(t){let s=document.querySelectorAll(".sidebar-item");for(let r of s){let o=r.querySelector(".item-label");if(o&&o.textContent?.trim()===(yt[t]||t)){r.click();return}}}toggleCard(t,s){let r=s.target;for(;r&&r!==s.currentTarget;){if(r.classList?.contains("ov-card-link")){let o=r.getAttribute("data-nav");o&&this.navigateToView(o);return}r=r.parentElement;}this.expandedCardIdx=this.expandedCardIdx===t?-1:t;}render(){let t=this.store.state,s=t.requests.filter(v=>!v.isStatic&&!v.isHealthCheck&&(!v.path||v.path.indexOf(O)!==0));if(!(s.length>0||t.queries.length>0||t.errors.length>0))return a`<bk-empty-state
|
|
332
455
|
title="Waiting for requests..."
|
|
333
456
|
subtitle="Start using your app to see insights here"
|
|
334
|
-
></bk-empty-state>`;let
|
|
457
|
+
></bk-empty-state>`;let o=s.filter(v=>v.statusCode>=400).length,n=new Set(["data-fetch","api-call","server-action","page-load"]),l=s.filter(v=>v.category&&n.has(v.category)),c=l.length>0?l:s,p=c.length>0?Math.round(c.reduce((v,L)=>v+L.durationMs,0)/c.length):0,u=t.issues||[],m=u.filter(v=>v.state==="open"||v.state==="regressed"),b=u.filter(v=>v.state==="fixing"),$=u.filter(v=>v.state==="resolved");return a`
|
|
335
458
|
<div class="ov-container" id="overview-content">
|
|
336
|
-
${this.renderSummary(s.length,t.flows.length,
|
|
337
|
-
${
|
|
459
|
+
${this.renderSummary(s.length,t.flows.length,p,t.queries.length,o,t.fetches.length)}
|
|
460
|
+
${m.length===0&&b.length===0&&$.length===0?a`<div class="ov-clear">
|
|
338
461
|
<span class="ov-clear-icon">\u2713</span>All clear \u2014 no issues detected
|
|
339
462
|
</div>`:d}
|
|
340
|
-
${
|
|
463
|
+
${m.length===0&&$.length>0?a`<div class="ov-clear">
|
|
341
464
|
<span class="ov-clear-icon">\u2713</span>All issues resolved \u2014
|
|
342
|
-
${
|
|
465
|
+
${$.length} finding${$.length!==1?"s were":" was"} detected and
|
|
343
466
|
fixed
|
|
344
467
|
</div>`:d}
|
|
345
|
-
${
|
|
346
|
-
${
|
|
347
|
-
${
|
|
468
|
+
${m.length>0?this.renderOpenIssues(m):d}
|
|
469
|
+
${b.length>0?this.renderVerifying(b):d}
|
|
470
|
+
${$.length>0?this.renderResolvedIssues($):d}
|
|
348
471
|
</div>
|
|
349
|
-
`}renderSummary(t,s,r,
|
|
472
|
+
`}renderSummary(t,s,r,o,n,l){return a`
|
|
350
473
|
<div class="ov-summary">
|
|
351
474
|
<div class="ov-stat"><span class="ov-stat-value">${t}</span><span class="ov-stat-label">Requests</span></div>
|
|
352
475
|
<div class="ov-stat"><span class="ov-stat-value">${s}</span><span class="ov-stat-label">Actions</span></div>
|
|
353
476
|
<div class="ov-stat"><span class="ov-stat-value">${S(r)}</span><span class="ov-stat-label">Avg Response</span></div>
|
|
354
|
-
<div class="ov-stat"><span class="ov-stat-value">${
|
|
355
|
-
<div class="ov-stat"><span class="ov-stat-value" style="color:${
|
|
356
|
-
<div class="ov-stat"><span class="ov-stat-value">${
|
|
477
|
+
<div class="ov-stat"><span class="ov-stat-value">${o}</span><span class="ov-stat-label">Queries</span></div>
|
|
478
|
+
<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>
|
|
479
|
+
<div class="ov-stat"><span class="ov-stat-value">${l}</span><span class="ov-stat-label">Fetches</span></div>
|
|
357
480
|
</div>
|
|
358
|
-
`}renderOpenIssues(t){return
|
|
481
|
+
`}renderOpenIssues(t){return a`
|
|
359
482
|
<div class="ov-section-title">Issues Found <span class="ov-issue-count">${t.length}</span></div>
|
|
360
483
|
<div class="ov-cards">${t.map((s,r)=>this.renderIssueCard(s,r))}</div>
|
|
361
|
-
`}renderIssueCard(t,s){let r=t.issue,
|
|
362
|
-
<div class="ov-card ${
|
|
363
|
-
<span class="ov-card-icon ${
|
|
484
|
+
`}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`
|
|
485
|
+
<div class="ov-card ${n?"expanded":""}" @click=${p=>this.toggleCard(s,p)}>
|
|
486
|
+
<span class="ov-card-icon ${o.cls}">${o.icon}</span>
|
|
364
487
|
<div class="ov-card-body">
|
|
365
|
-
<div class="ov-card-title">${r.title}${
|
|
488
|
+
<div class="ov-card-title">${r.title}${l}</div>
|
|
366
489
|
<div class="ov-card-desc">${r.desc}</div>
|
|
367
|
-
${
|
|
368
|
-
<div class="ov-card-expand" style="display:${
|
|
369
|
-
${r.detail?
|
|
370
|
-
${r.hint?
|
|
371
|
-
${r.nav?
|
|
490
|
+
${c}
|
|
491
|
+
<div class="ov-card-expand" style="display:${n?"block":"none"}">
|
|
492
|
+
${r.detail?a`<div .innerHTML=${r.detail}></div>`:d}
|
|
493
|
+
${r.hint?a`<div class="ov-card-hint">${r.hint}</div>`:d}
|
|
494
|
+
${r.nav?a`<span class="ov-card-link" data-nav=${r.nav}>View in ${ae[r.nav]||r.nav} \u2192</span>`:d}
|
|
372
495
|
</div>
|
|
373
496
|
</div>
|
|
374
|
-
<span class="ov-card-arrow">${
|
|
497
|
+
<span class="ov-card-arrow">${n?"\u2193":"\u2192"}</span>
|
|
375
498
|
</div>
|
|
376
|
-
`}renderVerifying(t){return
|
|
499
|
+
`}renderVerifying(t){return a`
|
|
377
500
|
<div class="ov-section-title ov-resolved-title">
|
|
378
501
|
<span style="color:var(--yellow,#f5a623)">\u29d7</span> Awaiting Verification
|
|
379
502
|
<span class="ov-issue-count">${t.length}</span>
|
|
380
503
|
</div>
|
|
381
504
|
<div class="ov-cards">
|
|
382
|
-
${t.map(s=>{let r=s.issue,
|
|
505
|
+
${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`
|
|
383
506
|
<div class="ov-card ov-card-resolved">
|
|
384
507
|
<span class="ov-card-icon resolved">\u29d7</span>
|
|
385
508
|
<div class="ov-card-body">
|
|
@@ -388,18 +511,18 @@
|
|
|
388
511
|
<span class="sec-ai-badge sec-ai-fixing">AI fixed \u2014 awaiting verification</span>
|
|
389
512
|
</div>
|
|
390
513
|
<div class="ov-card-desc">${r.desc}</div>
|
|
391
|
-
${
|
|
514
|
+
${o}
|
|
392
515
|
</div>
|
|
393
516
|
</div>
|
|
394
517
|
`})}
|
|
395
518
|
</div>
|
|
396
|
-
`}renderResolvedIssues(t){return
|
|
519
|
+
`}renderResolvedIssues(t){return a`
|
|
397
520
|
<div class="ov-section-title ov-resolved-title">
|
|
398
521
|
<span style="color:var(--green)">\u2713</span> Resolved
|
|
399
522
|
<span class="ov-issue-count">${t.length}</span>
|
|
400
523
|
</div>
|
|
401
524
|
<div class="ov-cards">
|
|
402
|
-
${t.map(s=>
|
|
525
|
+
${t.map(s=>a`
|
|
403
526
|
<div class="ov-card ov-card-resolved">
|
|
404
527
|
<span class="ov-card-icon resolved">\u2713</span>
|
|
405
528
|
<div class="ov-card-body">
|
|
@@ -409,67 +532,67 @@
|
|
|
409
532
|
</div>
|
|
410
533
|
`)}
|
|
411
534
|
</div>
|
|
412
|
-
`}};
|
|
535
|
+
`}};h([R({context:x})],pt.prototype,"store",2),h([E()],pt.prototype,"expandedCardIdx",2),pt=h([g("bk-overview-view")],pt);function jt(i){return i<1?"<1ms":i<1e3?Math.round(i)+"ms":(i/1e3).toFixed(1)+"s"}function dr(i){return i<V?xt.green:i<Y?xt.amber:xt.red}function vs(i){return i.statusCode>=400?xt.red:dr(i.durationMs)}function fs(i){return [parseInt(i.slice(1,3),16),parseInt(i.slice(3,5),16),parseInt(i.slice(5,7),16)]}function gs(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 bs(i,e,t,s,r){let[o,n,l]=fs(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 Es(i,e,t,s,r,o){let[n,l,c]=fs(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 _s(i,e){let t=[],s=gs(i);if(!s||e.length===0)return t;let{ctx:r,w:o,h:n}=s,l=es,c=o-l.left-l.right,p=n-l.top-l.bottom,u=0,m=e[0].timestamp,b=e[0].timestamp;for(let _ of e)_.durationMs>u&&(u=_.durationMs),_.timestamp<m&&(m=_.timestamp),_.timestamp>b&&(b=_.timestamp);u=Math.max(u,10),u=Math.ceil(u*1.15/10)*10;let $=b-m||1;r.strokeStyle=Je,r.lineWidth=1;let v=4;for(let _=0;_<=v;_++){let w=l.top+p-_/v*p;r.beginPath(),r.moveTo(l.left,w),r.lineTo(l.left+c,w),r.stroke(),r.fillStyle=ge,r.font=Ze,r.textAlign="right",r.fillText(jt(Math.round(_/v*u)),l.left-8,w+3);}for(let _ of [{ms:V},{ms:Y}]){if(_.ms>=u)continue;let w=l.top+p-_.ms/u*p;r.beginPath(),r.setLineDash([4,4]),r.strokeStyle="rgba(113,113,122,0.3)",r.lineWidth=1,r.moveTo(l.left,w),r.lineTo(l.left+c,w),r.stroke(),r.setLineDash([]),r.fillStyle="rgba(113,113,122,0.5)",r.font=be,r.textAlign="left",r.fillText(jt(_.ms),l.left+c+2,w+3);}for(let _=0;_<e.length;_++){let w=e[_],ut=e.length===1?l.left+c/2:l.left+(w.timestamp-m)/$*c,Vt=l.top+p-w.durationMs/u*p,ye=vs(w);t.push({x:ut,y:Vt,idx:_,r:w}),w.statusCode>=400?Es(r,ut,Vt,4,ye,2):bs(r,ut,Vt,4,ye);}r.fillStyle=ge,r.font=be,r.textAlign="center";let L=[m,m+$/2,b];for(let _=0;_<L.length;_++){let w=l.left+_/2*c,ut=new Date(L[_]);r.fillText(ut.toLocaleTimeString([],{hour:"2-digit",minute:"2-digit",second:"2-digit"}),w,l.top+p+14);}return t}function Ss(i,e){let t=gs(i);if(!t||e.length===0)return;let{ctx:s,w:r,h:o}=t,n=4,l=4,c=r-n*2,p=o-l*2,u=0,m=e[0].timestamp,b=e[0].timestamp;for(let v of e)v.durationMs>u&&(u=v.durationMs),v.timestamp<m&&(m=v.timestamp),v.timestamp>b&&(b=v.timestamp);u=Math.max(u,10),u=Math.ceil(u*1.15/10)*10;let $=b-m||1;for(let v of [V,Y]){if(v>=u)continue;let L=l+p-v/u*p;s.beginPath(),s.setLineDash([2,3]),s.strokeStyle="rgba(113,113,122,0.15)",s.lineWidth=1,s.moveTo(n,L),s.lineTo(n+c,L),s.stroke(),s.setLineDash([]);}for(let v of e){let L=e.length===1?n+c/2:n+(v.timestamp-m)/$*c,_=l+p-v.durationMs/u*p,w=vs(v);v.statusCode>=400?Es(s,L,_,2.5,w,1.5):bs(s,L,_,2.5,w);}s.fillStyle="rgba(113,113,122,0.5)",s.font=ts,s.textAlign="right",s.fillText(jt(u),r-2,l+8),s.fillText(jt(0),r-2,o-2);}var B=class extends f{constructor(){super(...arguments);this.selectedEndpoint=H;this.graphData=[];this.loadError=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(y.metricsLive)).json();this.graphData=s.endpoints||[],this.loadError=!1,(!this.selectedEndpoint||this.selectedEndpoint===H)&&(this.selectedEndpoint=H);}catch{this.loadError=true;}}healthGrade(t){for(let s of Bt)if(t<s.max)return s;return Bt[Bt.length-1]}fmtMs(t){return t<1?"<1ms":t<1e3?Math.round(t)+"ms":(t/1e3).toFixed(1)+"s"}renderScatterChart(t,s){this.scatterDots=_s(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 u of this.scatterDots){let m=Math.sqrt((u.x-n)**2+(u.y-l)**2);m<p&&(p=m,c=u);}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)this.graphData.forEach((t,s)=>{if(t.requests.length===0)return;let r=this.querySelector(`#inline-scatter-${s}`);r&&Ss(r,t.requests);});else {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`
|
|
413
536
|
<div id="graph-content">
|
|
414
537
|
${this.renderSelector()}
|
|
415
|
-
${this.selectedEndpoint===
|
|
538
|
+
${this.selectedEndpoint===H?this.renderOverview():this.renderDetail()}
|
|
416
539
|
</div>
|
|
417
|
-
`}renderSelector(){return
|
|
540
|
+
`}renderSelector(){return a`
|
|
418
541
|
<div class="perf-selector">
|
|
419
|
-
<button class="perf-selector-btn ${this.selectedEndpoint===
|
|
420
|
-
@click=${()=>{this.selectedEndpoint=
|
|
421
|
-
${this.graphData.map((t,s)=>
|
|
542
|
+
<button class="perf-selector-btn ${this.selectedEndpoint===H?"active":""}"
|
|
543
|
+
@click=${()=>{this.selectedEndpoint=H;}}>Overview</button>
|
|
544
|
+
${this.graphData.map((t,s)=>a`
|
|
422
545
|
<button class="perf-selector-btn ${t.endpoint===this.selectedEndpoint?"active":""}"
|
|
423
546
|
@click=${()=>{this.selectedEndpoint=t.endpoint;}}>
|
|
424
|
-
<span class="perf-dot" style="background:${
|
|
547
|
+
<span class="perf-dot" style="background:${fe[s%fe.length]}"></span>${t.endpoint}
|
|
425
548
|
</button>
|
|
426
549
|
`)}
|
|
427
550
|
</div>
|
|
428
|
-
`}renderOverview(){return
|
|
551
|
+
`}renderOverview(){return a`
|
|
429
552
|
<div class="perf-endpoint-list">
|
|
430
553
|
${this.graphData.map((t,s)=>t.requests.length===0?d:this.renderEndpointCard(t,s))}
|
|
431
554
|
</div>
|
|
432
|
-
`}renderEndpointCard(t,s){let r=t.summary,
|
|
555
|
+
`}renderEndpointCard(t,s){let r=t.summary,o=this.healthGrade(r.p95Ms),n=Math.round(r.errorRate*r.totalRequests),l=(r.avgQueryTimeMs||0)+(r.avgFetchTimeMs||0)+(r.avgAppTimeMs||0),c=d;if(l>0){let p=Math.round((r.avgQueryTimeMs||0)/l*100),u=Math.round((r.avgFetchTimeMs||0)/l*100),m=Math.max(0,100-p-u);c=a`
|
|
433
556
|
<div class="perf-breakdown-inline">
|
|
434
557
|
<div class="perf-breakdown-bar perf-breakdown-bar-sm">
|
|
435
|
-
${
|
|
436
|
-
${
|
|
437
|
-
${
|
|
558
|
+
${p>0?a`<div class="perf-breakdown-seg perf-breakdown-db" style="width:${p}%"></div>`:d}
|
|
559
|
+
${u>0?a`<div class="perf-breakdown-seg perf-breakdown-fetch" style="width:${u}%"></div>`:d}
|
|
560
|
+
${m>0?a`<div class="perf-breakdown-seg perf-breakdown-app" style="width:${m}%"></div>`:d}
|
|
438
561
|
</div>
|
|
439
562
|
<span class="perf-breakdown-labels">
|
|
440
|
-
${
|
|
441
|
-
${
|
|
563
|
+
${p>0?a`<span class="perf-breakdown-lbl"><span class="perf-breakdown-dot perf-breakdown-db"></span>${this.fmtMs(r.avgQueryTimeMs||0)}</span>`:d}
|
|
564
|
+
${u>0?a`<span class="perf-breakdown-lbl"><span class="perf-breakdown-dot perf-breakdown-fetch"></span>${this.fmtMs(r.avgFetchTimeMs||0)}</span>`:d}
|
|
442
565
|
<span class="perf-breakdown-lbl"><span class="perf-breakdown-dot perf-breakdown-app"></span>${this.fmtMs(r.avgAppTimeMs||0)}</span>
|
|
443
566
|
</span>
|
|
444
567
|
</div>
|
|
445
|
-
`;}return
|
|
568
|
+
`;}return a`
|
|
446
569
|
<div class="perf-endpoint-card" @click=${()=>{this.selectedEndpoint=t.endpoint;}}>
|
|
447
570
|
<div class="perf-ep-header">
|
|
448
571
|
<span class="perf-ep-name">${t.endpoint}</span>
|
|
449
572
|
<span class="perf-ep-stats">
|
|
450
|
-
<span class="perf-ep-stat" style="color:${
|
|
451
|
-
<span class="perf-ep-stat ${
|
|
452
|
-
${r.avgQueryCount>0?
|
|
573
|
+
<span class="perf-ep-stat" style="color:${o.color}">p95: ${this.fmtMs(r.p95Ms)}</span>
|
|
574
|
+
<span class="perf-ep-stat ${n>0?"perf-ep-stat-err":""}">${n} err</span>
|
|
575
|
+
${r.avgQueryCount>0?a`<span class="perf-ep-stat ${r.avgQueryCount>5?"perf-ep-stat-warn":""}">${r.avgQueryCount} q/req</span>`:d}
|
|
453
576
|
<span class="perf-ep-stat perf-ep-stat-muted">${r.totalRequests} req${r.totalRequests!==1?"s":""}</span>
|
|
454
577
|
</span>
|
|
455
578
|
</div>
|
|
456
|
-
${
|
|
579
|
+
${c}
|
|
457
580
|
<canvas id="inline-scatter-${s}" class="perf-inline-canvas"></canvas>
|
|
458
581
|
</div>
|
|
459
|
-
`}renderDetail(){let t=this.graphData.find(
|
|
582
|
+
`}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.healthGrade(s.p95Ms),o=Math.round(s.errorRate*s.totalRequests);return a`
|
|
460
583
|
${this.renderDetailHeader(t,r)}
|
|
461
|
-
${this.renderDetailMetrics(s,r,
|
|
584
|
+
${this.renderDetailMetrics(s,r,o)}
|
|
462
585
|
${this.renderDetailBreakdown(s)}
|
|
463
586
|
${this.renderDetailChart()}
|
|
464
587
|
${this.renderDetailHistory(t)}
|
|
465
|
-
`}renderDetailHeader(t,s){return
|
|
588
|
+
`}renderDetailHeader(t,s){return a`
|
|
466
589
|
<div class="perf-detail-header">
|
|
467
590
|
<div class="perf-detail-title">
|
|
468
591
|
<span class="perf-badge perf-badge-lg" style="color:${s.color};background:${s.bg};border-color:${s.border}">${s.label}</span>
|
|
469
592
|
<span>${t.endpoint}</span>
|
|
470
593
|
</div>
|
|
471
594
|
</div>
|
|
472
|
-
`}renderDetailMetrics(t,s,r){return
|
|
595
|
+
`}renderDetailMetrics(t,s,r){return a`
|
|
473
596
|
<div class="perf-metric-row">
|
|
474
597
|
<div class="perf-metric-card">
|
|
475
598
|
<span class="perf-metric-label">P95</span>
|
|
@@ -486,26 +609,26 @@
|
|
|
486
609
|
<span class="perf-metric-value" style="color:${t.avgQueryCount>5?"var(--amber)":"var(--text)"}">${t.avgQueryCount}</span>
|
|
487
610
|
</div>
|
|
488
611
|
</div>
|
|
489
|
-
`}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),
|
|
612
|
+
`}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`
|
|
490
613
|
<div class="perf-breakdown">
|
|
491
614
|
<div class="perf-section-title">Time Breakdown</div>
|
|
492
615
|
<div class="perf-breakdown-bar">
|
|
493
|
-
${r>0?
|
|
494
|
-
${
|
|
495
|
-
${
|
|
616
|
+
${r>0?a`<div class="perf-breakdown-seg perf-breakdown-db" style="width:${r}%"></div>`:d}
|
|
617
|
+
${o>0?a`<div class="perf-breakdown-seg perf-breakdown-fetch" style="width:${o}%"></div>`:d}
|
|
618
|
+
${n>0?a`<div class="perf-breakdown-seg perf-breakdown-app" style="width:${n}%"></div>`:d}
|
|
496
619
|
</div>
|
|
497
620
|
<div class="perf-breakdown-legend">
|
|
498
621
|
<span class="perf-breakdown-item"><span class="perf-breakdown-dot perf-breakdown-db"></span>DB ${this.fmtMs(t.avgQueryTimeMs||0)} (${r}%)</span>
|
|
499
|
-
<span class="perf-breakdown-item"><span class="perf-breakdown-dot perf-breakdown-fetch"></span>Fetch ${this.fmtMs(t.avgFetchTimeMs||0)} (${
|
|
500
|
-
<span class="perf-breakdown-item"><span class="perf-breakdown-dot perf-breakdown-app"></span>App ${this.fmtMs(t.avgAppTimeMs||0)} (${
|
|
622
|
+
<span class="perf-breakdown-item"><span class="perf-breakdown-dot perf-breakdown-fetch"></span>Fetch ${this.fmtMs(t.avgFetchTimeMs||0)} (${o}%)</span>
|
|
623
|
+
<span class="perf-breakdown-item"><span class="perf-breakdown-dot perf-breakdown-app"></span>App ${this.fmtMs(t.avgAppTimeMs||0)} (${n}%)</span>
|
|
501
624
|
</div>
|
|
502
625
|
</div>
|
|
503
|
-
`}renderDetailChart(){return
|
|
626
|
+
`}renderDetailChart(){return a`
|
|
504
627
|
<div class="perf-chart-wrap">
|
|
505
628
|
<div class="perf-section-title">Response Time</div>
|
|
506
629
|
<canvas id="perf-detail-canvas" class="perf-canvas" style="width:100%;height:240px"></canvas>
|
|
507
630
|
</div>
|
|
508
|
-
`}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({r:t.requests[r],origIdx:r});return
|
|
631
|
+
`}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({r:t.requests[r],origIdx:r});return a`
|
|
509
632
|
<div class="perf-history-wrap">
|
|
510
633
|
<div class="col-header">
|
|
511
634
|
<span class="perf-col perf-col-date">Time</span>
|
|
@@ -517,88 +640,88 @@
|
|
|
517
640
|
</div>
|
|
518
641
|
${s.map(r=>this.renderHistoryRow(r.r,r.origIdx))}
|
|
519
642
|
</div>
|
|
520
|
-
`}renderHistoryRow(t,s){let r=this.healthGrade(t.durationMs),
|
|
521
|
-
<div class="perf-hist-row ${
|
|
522
|
-
<span class="perf-col perf-col-date">${
|
|
643
|
+
`}renderHistoryRow(t,s){let r=this.healthGrade(t.durationMs),o=new Date(t.timestamp).toLocaleTimeString([],{hour:"2-digit",minute:"2-digit",second:"2-digit"}),n=t.statusCode>=400,l=t.queryTimeMs||0,c=t.fetchTimeMs||0,p=Math.max(0,t.durationMs-l-c);return a`
|
|
644
|
+
<div class="perf-hist-row ${n?"perf-hist-row-err":""}" data-req-idx=${s}>
|
|
645
|
+
<span class="perf-col perf-col-date">${o}</span>
|
|
523
646
|
<span class="perf-col perf-col-health">
|
|
524
647
|
<span class="perf-badge perf-badge-sm" style="color:${r.color};background:${r.bg};border-color:${r.border}">${r.label}</span>
|
|
525
648
|
</span>
|
|
526
649
|
<span class="perf-col perf-col-avg">${this.fmtMs(t.durationMs)}</span>
|
|
527
650
|
<span class="perf-col perf-col-breakdown">
|
|
528
|
-
${
|
|
529
|
-
${
|
|
530
|
-
<span class="perf-bd-tag perf-bd-tag-app">App ${this.fmtMs(
|
|
651
|
+
${l>0?a`<span class="perf-bd-tag perf-bd-tag-db">DB ${this.fmtMs(l)}</span>`:d}
|
|
652
|
+
${c>0?a`<span class="perf-bd-tag perf-bd-tag-fetch">Fetch ${this.fmtMs(c)}</span>`:d}
|
|
653
|
+
<span class="perf-bd-tag perf-bd-tag-app">App ${this.fmtMs(p)}</span>
|
|
531
654
|
</span>
|
|
532
|
-
<span class="perf-col perf-col-status" style="color:${
|
|
655
|
+
<span class="perf-col perf-col-status" style="color:${n?"var(--red)":"var(--text-muted)"}">${t.statusCode}</span>
|
|
533
656
|
<span class="perf-col perf-col-qpr">${t.queryCount}</span>
|
|
534
657
|
</div>
|
|
535
|
-
`}};
|
|
658
|
+
`}};h([R({context:x})],B.prototype,"store",2),h([E()],B.prototype,"selectedEndpoint",2),h([E()],B.prototype,"graphData",2),h([E()],B.prototype,"loadError",2),B=h([g("bk-performance-view")],B);function pr(i){return i===0?"<1ms":S(i)}var A=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=A.cache.get(this.requestId);if(t){this.data=t;return}this.loading=true;try{let s=await fetch(`${y.activity}?requestId=${this.requestId}`);if(!s.ok){this.failed=!0,this.loading=!1;return}let r=await s.json();if(A.cache.size>=he){let o=A.cache.keys().next().value;o!==void 0&&A.cache.delete(o);}A.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`
|
|
536
659
|
<div class="tl-header">
|
|
537
660
|
<span class="tl-title">Activity Timeline</span>
|
|
538
661
|
<span class="tl-counts">
|
|
539
|
-
${t.counts.queries>0?
|
|
540
|
-
${t.counts.fetches>0?
|
|
541
|
-
${t.counts.logs>0?
|
|
542
|
-
${t.counts.errors>0?
|
|
662
|
+
${t.counts.queries>0?a`<span class="tl-count tl-count-query">${t.counts.queries} quer${t.counts.queries===1?"y":"ies"}</span>`:d}
|
|
663
|
+
${t.counts.fetches>0?a`<span class="tl-count tl-count-fetch">${t.counts.fetches} fetch${t.counts.fetches===1?"":"es"}</span>`:d}
|
|
664
|
+
${t.counts.logs>0?a`<span class="tl-count tl-count-log">${t.counts.logs} log${t.counts.logs===1?"":"s"}</span>`:d}
|
|
665
|
+
${t.counts.errors>0?a`<span class="tl-count tl-count-error">${t.counts.errors} error${t.counts.errors===1?"":"s"}</span>`:d}
|
|
543
666
|
</span>
|
|
544
667
|
</div>
|
|
545
668
|
<div class="tl-events">${this.renderTimeline(t.timeline,s)}</div>
|
|
546
|
-
`}renderTimeline(t,s){let r=new Map,
|
|
547
|
-
${this.renderEvent(c,
|
|
669
|
+
`}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,u=p?r.get(p):void 0;if(u&&u.length>0){let m=u.length;return a`
|
|
670
|
+
${this.renderEvent(l,c,s)}
|
|
548
671
|
<div class="tl-nested">
|
|
549
|
-
<span class="tl-nested-label">${
|
|
550
|
-
${
|
|
672
|
+
<span class="tl-nested-label">${m} nested quer${m===1?"y":"ies"}</span>
|
|
673
|
+
${u.map(b=>{let $=n++;return this.renderEvent(b,$,s,true)})}
|
|
551
674
|
</div>
|
|
552
|
-
`}return this.renderEvent(c,
|
|
553
|
-
<div class="tl-event ${
|
|
554
|
-
style="${
|
|
555
|
-
@click=${
|
|
556
|
-
<span class="tl-event-time">${
|
|
557
|
-
<span class="tl-event-type" style="color:${
|
|
675
|
+
`}return this.renderEvent(l,c,s)})}renderEvent(t,s,r,o=false){let n=ss[t.type]||"var(--text-dim)",l=rs[t.type]||t.type,c="+"+S(Math.round(t.timestamp-r)),p=t.type==="query"?t.data.sql:void 0,u=!!p,m=this.expandedSqlIdx===s;return a`
|
|
676
|
+
<div class="tl-event ${u?"tl-clickable":""} ${o?"tl-nested-event":""}"
|
|
677
|
+
style="${u?"":`border-left-color:${n}`}"
|
|
678
|
+
@click=${u?b=>this.toggleSql(s,b):d}>
|
|
679
|
+
<span class="tl-event-time">${c}</span>
|
|
680
|
+
<span class="tl-event-type" style="color:${n}">${l}</span>
|
|
558
681
|
${this.renderEventContent(t)}
|
|
559
|
-
${
|
|
560
|
-
<div class="tl-event-sql ${
|
|
561
|
-
<button class="tl-sql-copy" @click=${
|
|
562
|
-
${
|
|
682
|
+
${p?a`
|
|
683
|
+
<div class="tl-event-sql ${m?"open":""}">
|
|
684
|
+
<button class="tl-sql-copy" @click=${b=>this.copySql(p,b)}>Copy</button>
|
|
685
|
+
${p}
|
|
563
686
|
</div>`:d}
|
|
564
687
|
</div>
|
|
565
|
-
`}renderEventContent(t){switch(t.type){case "fetch":{let s=t.data,r=s.statusCode>=400;return
|
|
688
|
+
`}renderEventContent(t){switch(t.type){case "fetch":{let s=t.data,r=s.statusCode>=400;return a`
|
|
566
689
|
<span class="tl-event-summary">${s.method} ${s.url}</span>
|
|
567
690
|
<span class="tl-event-status" style="${r?"color:var(--red)":""}">${s.statusCode}</span>
|
|
568
691
|
<span class="tl-event-dur">${S(s.durationMs)}</span>
|
|
569
|
-
`}case "query":{let s=t.data,r=(s.normalizedOp||s.operation||"?").toUpperCase(),
|
|
570
|
-
<span class="tl-event-summary"><span style="color:${
|
|
571
|
-
<span class="tl-event-dur">${
|
|
572
|
-
`}case "log":{let s=t.data,r=ze[s.level]||"var(--text-dim)";return
|
|
692
|
+
`}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`
|
|
693
|
+
<span class="tl-event-summary"><span style="color:${n};font-weight:600">${r}</span> ${o}</span>
|
|
694
|
+
<span class="tl-event-dur">${pr(s.durationMs)}</span>
|
|
695
|
+
`}case "log":{let s=t.data,r=ze[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}}};A.cache=new Map,h([R({context:x})],A.prototype,"store",2),h([T({attribute:"request-id"})],A.prototype,"requestId",2),h([T({attribute:"request-started",type:Number})],A.prototype,"requestStarted",2),h([E()],A.prototype,"data",2),h([E()],A.prototype,"loading",2),h([E()],A.prototype,"failed",2),h([E()],A.prototype,"expandedSqlIdx",2),A=h([g("bk-timeline-panel")],A);var Qt=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(y.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(O)||(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(),me)));},this.eventSource.addEventListener(re,e=>{this.store.prependFetch(JSON.parse(e.data));}),this.eventSource.addEventListener("log",e=>{this.store.prependLog(JSON.parse(e.data));}),this.eventSource.addEventListener(ie,e=>{this.store.prependError(JSON.parse(e.data));}),this.eventSource.addEventListener(oe,e=>{this.store.prependQuery(JSON.parse(e.data));}),this.eventSource.addEventListener(ne,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(y.flows)).json();this.store.setFlows(t.flows);}catch{}}async reloadMetrics(){try{let t=await(await fetch(y.metricsLive)).json();this.store.setMetrics(t.endpoints||[]);}catch{}}};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"><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 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"><polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"/></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"><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 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"><path d="M22 12h-4l-3 9L9 3l-3 9H2"/></svg>`}function Rs(){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 ws(){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 As(){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 Cs(){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 Is(){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 J=class extends f{constructor(){super(...arguments);this.store=new Wt;this.activeView="overview";this.viewMode="simple";this.sse=new Qt(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(y.flows),fetch(y.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(y.fetches),fetch(y.errors),fetch(y.logs),fetch(y.queries),fetch(y.metricsLive)]),[l,c,p,u,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(u.entries),this.store.setMetrics(m.endpoints||[]);}catch(t){console.warn("[brakit]",t);}try{let s=await(await fetch(y.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(`${y.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(y.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(O)),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`
|
|
573
696
|
<div class="app" id="app">
|
|
574
697
|
<aside class="sidebar">
|
|
575
698
|
<div class="sidebar-logo">
|
|
576
699
|
<span class="logo-text">brakit</span>
|
|
577
|
-
<span class="logo-version">v${
|
|
700
|
+
<span class="logo-version">v${l?.version??""}</span>
|
|
578
701
|
</div>
|
|
579
702
|
<nav class="sidebar-nav">
|
|
580
|
-
${this.renderSidebarItem("overview","Overview"
|
|
703
|
+
${this.renderSidebarItem("overview","Overview",$s(),void 0)}
|
|
581
704
|
<div class="sidebar-section">Monitor</div>
|
|
582
|
-
${this.renderSidebarItem("actions","Actions",
|
|
583
|
-
${this.renderSidebarItem("requests","Requests",
|
|
584
|
-
${this.renderSidebarItem("fetches","Fetches",
|
|
705
|
+
${this.renderSidebarItem("actions","Actions",Ts(),t.flows.length)}
|
|
706
|
+
${this.renderSidebarItem("requests","Requests",ys(),s.length)}
|
|
707
|
+
${this.renderSidebarItem("fetches","Fetches",xs(),t.fetches.length)}
|
|
585
708
|
<div class="sidebar-section">Insights</div>
|
|
586
|
-
${this.renderSidebarItem("queries","Queries",
|
|
587
|
-
${this.renderSidebarItem("errors","Errors",
|
|
588
|
-
${this.renderSidebarItem("logs","Logs",
|
|
589
|
-
${this.renderSidebarItem("security","Security",
|
|
590
|
-
${this.renderSidebarItem("performance","Performance",
|
|
709
|
+
${this.renderSidebarItem("queries","Queries",Rs(),t.queries.length)}
|
|
710
|
+
${this.renderSidebarItem("errors","Errors",ws(),t.errors.length)}
|
|
711
|
+
${this.renderSidebarItem("logs","Logs",As(),t.logs.length)}
|
|
712
|
+
${this.renderSidebarItem("security","Security",Cs(),n,n===0)}
|
|
713
|
+
${this.renderSidebarItem("performance","Performance",Is(),void 0)}
|
|
591
714
|
</nav>
|
|
592
|
-
<div class="sidebar-footer">:${
|
|
715
|
+
<div class="sidebar-footer">:${l?.port??""}</div>
|
|
593
716
|
</aside>
|
|
594
717
|
<div class="main-panel">
|
|
595
718
|
<div class="header">
|
|
596
719
|
<div class="header-left">
|
|
597
|
-
<span class="header-title" id="header-title">${
|
|
598
|
-
<span class="header-sub" id="header-sub">${
|
|
720
|
+
<span class="header-title" id="header-title">${yt[this.activeView]||this.activeView}</span>
|
|
721
|
+
<span class="header-sub" id="header-sub">${le[this.activeView]||""}</span>
|
|
599
722
|
</div>
|
|
600
723
|
<div class="header-right">
|
|
601
|
-
${this.activeView==="actions"?
|
|
724
|
+
${this.activeView==="actions"?a`
|
|
602
725
|
<div class="segmented-control" id="mode-toggle">
|
|
603
726
|
<button class="segmented-btn ${this.viewMode==="simple"?"active":""}" @click=${()=>{this.viewMode="simple",this.store.setViewMode("simple");}}>Quick</button>
|
|
604
727
|
<button class="segmented-btn ${this.viewMode==="detailed"?"active":""}" @click=${()=>{this.viewMode="detailed",this.store.setViewMode("detailed");}}>Detailed</button>
|
|
@@ -640,18 +763,18 @@
|
|
|
640
763
|
<span id="stat-total">${s.length} request${s.length!==1?"s":""}</span>
|
|
641
764
|
<span id="stat-flows">${t.flows.length} action${t.flows.length!==1?"s":""}</span>
|
|
642
765
|
<span id="stat-errors" class="error-count">${r} error${r!==1?"s":""}</span>
|
|
643
|
-
<span id="stat-avg">Avg: ${
|
|
766
|
+
<span id="stat-avg">Avg: ${o}ms</span>
|
|
644
767
|
</div>
|
|
645
768
|
</div>
|
|
646
769
|
</div>
|
|
647
770
|
<bk-toast></bk-toast>
|
|
648
|
-
`}renderSidebarItem(t,s,r,
|
|
771
|
+
`}renderSidebarItem(t,s,r,o,n=false){return a`
|
|
649
772
|
<button class="sidebar-item ${this.activeView===t?"active":""}" @click=${()=>this.switchView(t)}>
|
|
650
773
|
<span class="item-icon">${r}</span>
|
|
651
774
|
<span class="item-label">${s}</span>
|
|
652
|
-
${
|
|
775
|
+
${o!==void 0?a`<span class="item-count" style="display:${n?"none":""}">${o}</span>`:d}
|
|
653
776
|
</button>
|
|
654
|
-
`}};
|
|
777
|
+
`}};h([_e({context:x})],J.prototype,"store",2),h([E()],J.prototype,"activeView",2),h([E()],J.prototype,"viewMode",2),J=h([g("bk-dashboard")],J);
|
|
655
778
|
/*! Bundled license information:
|
|
656
779
|
|
|
657
780
|
@lit/reactive-element/css-tag.js:
|