brakit 0.8.7 → 0.9.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 +83 -46
- package/dist/api.js +776 -767
- package/dist/bin/brakit.js +305 -432
- package/dist/dashboard-client.global.js +465 -267
- package/dist/dashboard.html +584 -310
- package/dist/mcp/server.js +7 -15
- package/dist/runtime/index.js +1566 -1700
- 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
|
|
1
|
+
(function(){'use strict';var Rs=Object.defineProperty;var ws=Object.getOwnPropertyDescriptor;var u=(i,e,t,s)=>{for(var r=s>1?void 0:s?ws(e,t):e,o=i.length-1,n;o>=0;o--)(n=i[o])&&(r=(s?n(e,t,r):n(r))||r);return s&&r&&Rs(e,t,r),r};var Mt=globalThis,Ot=Mt.ShadowRoot&&(Mt.ShadyCSS===void 0||Mt.ShadyCSS.nativeShadow)&&"adoptedStyleSheets"in Document.prototype&&"replace"in CSSStyleSheet.prototype,xe=Symbol(),Te=new WeakMap,Lt=class{constructor(e,t,s){if(this._$cssResult$=true,s!==xe)throw Error("CSSResult is not constructable. Use `unsafeCSS` or `css` instead.");this.cssText=e,this.t=t;}get styleSheet(){let e=this.o,t=this.t;if(Ot&&e===void 0){let s=t!==void 0&&t.length===1;s&&(e=Te.get(t)),e===void 0&&((this.o=e=new CSSStyleSheet).replaceSync(this.cssText),s&&Te.set(t,e));}return e}toString(){return this.cssText}},Re=i=>new Lt(typeof i=="string"?i:i+"",void 0,xe);var we=(i,e)=>{if(Ot)i.adoptedStyleSheets=e.map(t=>t instanceof CSSStyleSheet?t:t.styleSheet);else for(let t of e){let s=document.createElement("style"),r=Mt.litNonce;r!==void 0&&s.setAttribute("nonce",r),s.textContent=t.cssText,i.appendChild(s);}},Qt=Ot?i=>i:i=>i instanceof CSSStyleSheet?(e=>{let t="";for(let s of e.cssRules)t+=s.cssText;return Re(t)})(i):i;var{is:As,defineProperty:Cs,getOwnPropertyDescriptor:Is,getOwnPropertyNames:Ms,getOwnPropertySymbols:Ls,getPrototypeOf:Os}=Object,N=globalThis,Ae=N.trustedTypes,ks=Ae?Ae.emptyScript:"",Ns=N.reactiveElementPolyfillSupport,ht=(i,e)=>i,mt={toAttribute(i,e){switch(e){case Boolean:i=i?ks: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}},kt=(i,e)=>!As(i,e),Ce={attribute:true,type:String,converter:mt,reflect:false,useDefault:false,hasChanged:kt};Symbol.metadata??(Symbol.metadata=Symbol("metadata")),N.litPropertyMetadata??(N.litPropertyMetadata=new WeakMap);var O=class extends HTMLElement{static addInitializer(e){this._$Ei(),(this.l??(this.l=[])).push(e);}static get observedAttributes(){return this.finalize(),this._$Eh&&[...this._$Eh.keys()]}static createProperty(e,t=Ce){if(t.state&&(t.attribute=false),this._$Ei(),this.prototype.hasOwnProperty(e)&&((t=Object.create(t)).wrapped=true),this.elementProperties.set(e,t),!t.noAccessor){let s=Symbol(),r=this.getPropertyDescriptor(e,s,t);r!==void 0&&Cs(this.prototype,e,r);}}static getPropertyDescriptor(e,t,s){let{get:r,set:o}=Is(this.prototype,e)??{get(){return this[t]},set(n){this[t]=n;}};return {get:r,set(n){let l=r?.call(this);o?.call(this,n),this.requestUpdate(e,l,s);},configurable:true,enumerable:true}}static getPropertyOptions(e){return this.elementProperties.get(e)??Ce}static _$Ei(){if(this.hasOwnProperty(ht("elementProperties")))return;let e=Os(this);e.finalize(),e.l!==void 0&&(this.l=[...e.l]),this.elementProperties=new Map(e.elementProperties);}static finalize(){if(this.hasOwnProperty(ht("finalized")))return;if(this.finalized=true,this._$Ei(),this.hasOwnProperty(ht("properties"))){let t=this.properties,s=[...Ms(t),...Ls(t)];for(let r of s)this.createProperty(r,t[r]);}let e=this[Symbol.metadata];if(e!==null){let t=litPropertyMetadata.get(e);if(t!==void 0)for(let[s,r]of t)this.elementProperties.set(s,r);}this._$Eh=new Map;for(let[t,s]of this.elementProperties){let r=this._$Eu(t,s);r!==void 0&&this._$Eh.set(r,t);}this.elementStyles=this.finalizeStyles(this.styles);}static finalizeStyles(e){let t=[];if(Array.isArray(e)){let s=new Set(e.flat(1/0).reverse());for(let r of s)t.unshift(Qt(r));}else e!==void 0&&t.push(Qt(e));return t}static _$Eu(e,t){let s=t.attribute;return s===false?void 0:typeof s=="string"?s:typeof e=="string"?e.toLowerCase():void 0}constructor(){super(),this._$Ep=void 0,this.isUpdatePending=false,this.hasUpdated=false,this._$Em=null,this._$Ev();}_$Ev(){this._$ES=new Promise(e=>this.enableUpdating=e),this._$AL=new Map,this._$E_(),this.requestUpdate(),this.constructor.l?.forEach(e=>e(this));}addController(e){(this._$EO??(this._$EO=new Set)).add(e),this.renderRoot!==void 0&&this.isConnected&&e.hostConnected?.();}removeController(e){this._$EO?.delete(e);}_$E_(){let e=new Map,t=this.constructor.elementProperties;for(let s of t.keys())this.hasOwnProperty(s)&&(e.set(s,this[s]),delete this[s]);e.size>0&&(this._$Ep=e);}createRenderRoot(){let e=this.shadowRoot??this.attachShadow(this.constructor.shadowRootOptions);return we(e,this.constructor.elementStyles),e}connectedCallback(){this.renderRoot??(this.renderRoot=this.createRenderRoot()),this.enableUpdating(true),this._$EO?.forEach(e=>e.hostConnected?.());}enableUpdating(e){}disconnectedCallback(){this._$EO?.forEach(e=>e.hostDisconnected?.());}attributeChangedCallback(e,t,s){this._$AK(e,s);}_$ET(e,t){let s=this.constructor.elementProperties.get(e),r=this.constructor._$Eu(e,s);if(r!==void 0&&s.reflect===true){let o=(s.converter?.toAttribute!==void 0?s.converter:mt).toAttribute(t,s.type);this._$Em=e,o==null?this.removeAttribute(r):this.setAttribute(r,o),this._$Em=null;}}_$AK(e,t){let s=this.constructor,r=s._$Eh.get(e);if(r!==void 0&&this._$Em!==r){let o=s.getPropertyOptions(r),n=typeof o.converter=="function"?{fromAttribute:o.converter}:o.converter?.fromAttribute!==void 0?o.converter:mt;this._$Em=r;let l=n.fromAttribute(t,o.type);this[r]=l??this._$Ej?.get(r)??l,this._$Em=null;}}requestUpdate(e,t,s,r=false,o){if(e!==void 0){let n=this.constructor;if(r===false&&(o=this[e]),s??(s=n.getPropertyOptions(e)),!((s.hasChanged??kt)(o,t)||s.useDefault&&s.reflect&&o===this._$Ej?.get(e)&&!this.hasAttribute(n._$Eu(e,s))))return;this.C(e,t,s);}this.isUpdatePending===false&&(this._$ES=this._$EP());}C(e,t,{useDefault:s,reflect:r,wrapped:o},n){s&&!(this._$Ej??(this._$Ej=new Map)).has(e)&&(this._$Ej.set(e,n??t??this[e]),o!==true||n!==void 0)||(this._$AL.has(e)||(this.hasUpdated||s||(t=void 0),this._$AL.set(e,t)),r===true&&this._$Em!==e&&(this._$Eq??(this._$Eq=new Set)).add(e));}async _$EP(){this.isUpdatePending=true;try{await this._$ES;}catch(t){Promise.reject(t);}let e=this.scheduleUpdate();return e!=null&&await e,!this.isUpdatePending}scheduleUpdate(){return this.performUpdate()}performUpdate(){if(!this.isUpdatePending)return;if(!this.hasUpdated){if(this.renderRoot??(this.renderRoot=this.createRenderRoot()),this._$Ep){for(let[r,o]of this._$Ep)this[r]=o;this._$Ep=void 0;}let s=this.constructor.elementProperties;if(s.size>0)for(let[r,o]of s){let{wrapped:n}=o,l=this[r];n!==true||this._$AL.has(r)||l===void 0||this.C(r,void 0,o,l);}}let e=false,t=this._$AL;try{e=this.shouldUpdate(t),e?(this.willUpdate(t),this._$EO?.forEach(s=>s.hostUpdate?.()),this.update(t)):this._$EM();}catch(s){throw e=false,this._$EM(),s}e&&this._$AE(t);}willUpdate(e){}_$AE(e){this._$EO?.forEach(t=>t.hostUpdated?.()),this.hasUpdated||(this.hasUpdated=true,this.firstUpdated(e)),this.updated(e);}_$EM(){this._$AL=new Map,this.isUpdatePending=false;}get updateComplete(){return this.getUpdateComplete()}getUpdateComplete(){return this._$ES}shouldUpdate(e){return true}update(e){this._$Eq&&(this._$Eq=this._$Eq.forEach(t=>this._$ET(t,this[t]))),this._$EM();}updated(e){}firstUpdated(e){}};O.elementStyles=[],O.shadowRootOptions={mode:"open"},O[ht("elementProperties")]=new Map,O[ht("finalized")]=new Map,Ns?.({ReactiveElement:O}),(N.reactiveElementVersions??(N.reactiveElementVersions=[])).push("2.1.2");var ft=globalThis,Ie=i=>i,Nt=ft.trustedTypes,Me=Nt?Nt.createPolicy("lit-html",{createHTML:i=>i}):void 0,He="$lit$",D=`lit$${Math.random().toFixed(9).slice(2)}$`,qe="?"+D,Ds=`<${qe}>`,W=document,gt=()=>W.createComment(""),bt=i=>i===null||typeof i!="object"&&typeof i!="function",Zt=Array.isArray,Hs=i=>Zt(i)||typeof i?.[Symbol.iterator]=="function",Vt=`[
|
|
2
|
+
\f\r]`,vt=/<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g,Le=/-->/g,Oe=/>/g,B=RegExp(`>|${Vt}(?:([^\\s"'>=/]+)(${Vt}*=${Vt}*(?:[^
|
|
3
|
+
\f\r"'\`<>=]|("|')|))|$)`,"g"),ke=/'/g,Ne=/"/g,Pe=/^(?:script|style|textarea|title)$/i,te=i=>(e,...t)=>({_$litType$:i,strings:e,values:t}),a=te(1),j=Symbol.for("lit-noChange"),d=Symbol.for("lit-nothing"),De=new WeakMap,G=W.createTreeWalker(W,129);function Ue(i,e){if(!Zt(i)||!i.hasOwnProperty("raw"))throw Error("invalid template strings array");return Me!==void 0?Me.createHTML(e):e}var qs=(i,e)=>{let t=i.length-1,s=[],r,o=e===2?"<svg>":e===3?"<math>":"",n=vt;for(let l=0;l<t;l++){let c=i[l],p,h,m=-1,b=0;for(;b<c.length&&(n.lastIndex=b,h=n.exec(c),h!==null);)b=n.lastIndex,n===vt?h[1]==="!--"?n=Le:h[1]!==void 0?n=Oe:h[2]!==void 0?(Pe.test(h[2])&&(r=RegExp("</"+h[2],"g")),n=B):h[3]!==void 0&&(n=B):n===B?h[0]===">"?(n=r??vt,m=-1):h[1]===void 0?m=-2:(m=n.lastIndex-h[2].length,p=h[1],n=h[3]===void 0?B:h[3]==='"'?Ne:ke):n===Ne||n===ke?n=B:n===Le||n===Oe?n=vt:(n=B,r=void 0);let $=n===B&&i[l+1].startsWith("/>")?" ":"";o+=n===vt?c+Ds:m>=0?(s.push(p),c.slice(0,m)+He+c.slice(m)+D+$):c+D+(m===-2?l:$);}return [Ue(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,h]=qs(e,t);if(this.el=i.createElement(p,s),G.currentNode=this.el.content,t===2||t===3){let m=this.el.content.firstChild;m.replaceWith(...m.childNodes);}for(;(r=G.nextNode())!==null&&c.length<l;){if(r.nodeType===1){if(r.hasAttributes())for(let m of r.getAttributeNames())if(m.endsWith(He)){let b=h[n++],$=r.getAttribute(m).split(D),E=/([.?@])?(.*)/.exec(b);c.push({type:1,index:o,name:E[2],strings:$,ctor:E[1]==="."?Xt:E[1]==="?"?Kt:E[1]==="@"?zt:z}),r.removeAttribute(m);}else m.startsWith(D)&&(c.push({type:6,index:o}),r.removeAttribute(m));if(Pe.test(r.tagName)){let m=r.textContent.split(D),b=m.length-1;if(b>0){r.textContent=Nt?Nt.emptyScript:"";for(let $=0;$<b;$++)r.append(m[$],gt()),G.nextNode(),c.push({type:2,index:++o});r.append(m[b],gt());}}}else if(r.nodeType===8)if(r.data===qe)c.push({type:2,index:o});else {let m=-1;for(;(m=r.data.indexOf(D,m+1))!==-1;)c.push({type:7,index:o}),m+=D.length-1;}o++;}}static createElement(e,t){let s=W.createElement("template");return s.innerHTML=e,s}};function K(i,e,t=i,s){if(e===j)return e;let r=s!==void 0?t._$Co?.[s]:t._$Cl,o=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=K(i,r._$AS(i,e.values),r,s)),e}var Yt=class{constructor(e,t){this._$AV=[],this._$AN=void 0,this._$AD=e,this._$AM=t;}get parentNode(){return this._$AM.parentNode}get _$AU(){return this._$AM._$AU}u(e){let{el:{content:t},parts:s}=this._$AD,r=(e?.creationScope??W).importNode(t,true);G.currentNode=r;let o=G.nextNode(),n=0,l=0,c=s[0];for(;c!==void 0;){if(n===c.index){let p;c.type===2?p=new _t(o,o.nextSibling,this,e):c.type===1?p=new c.ctor(o,c.name,c.strings,this,e):c.type===6&&(p=new Jt(o,this,e)),this._$AV.push(p),c=s[++l];}n!==c?.index&&(o=G.nextNode(),n++);}return G.currentNode=W,r}p(e){let t=0;for(let s of this._$AV)s!==void 0&&(s.strings!==void 0?(s._$AI(e,s,t),t+=s.strings.length-2):s._$AI(e[t])),t++;}},_t=class i{get _$AU(){return this._$AM?._$AU??this._$Cv}constructor(e,t,s,r){this.type=2,this._$AH=d,this._$AN=void 0,this._$AA=e,this._$AB=t,this._$AM=s,this.options=r,this._$Cv=r?.isConnected??true;}get parentNode(){let e=this._$AA.parentNode,t=this._$AM;return t!==void 0&&e?.nodeType===11&&(e=t.parentNode),e}get startNode(){return this._$AA}get endNode(){return this._$AB}_$AI(e,t=this){e=K(this,e,t),bt(e)?e===d||e==null||e===""?(this._$AH!==d&&this._$AR(),this._$AH=d):e!==this._$AH&&e!==j&&this._(e):e._$litType$!==void 0?this.$(e):e.nodeType!==void 0?this.T(e):Hs(e)?this.k(e):this._(e);}O(e){return this._$AA.parentNode.insertBefore(e,this._$AB)}T(e){this._$AH!==e&&(this._$AR(),this._$AH=this.O(e));}_(e){this._$AH!==d&&bt(this._$AH)?this._$AA.nextSibling.data=e:this.T(W.createTextNode(e)),this._$AH=e;}$(e){let{values:t,_$litType$:s}=e,r=typeof s=="number"?this._$AC(e):(s.el===void 0&&(s.el=Et.createElement(Ue(s.h,s.h[0]),this.options)),s);if(this._$AH?._$AD===r)this._$AH.p(t);else {let o=new Yt(r,this),n=o.u(this.options);o.p(t),this.T(n),this._$AH=o;}}_$AC(e){let t=De.get(e.strings);return t===void 0&&De.set(e.strings,t=new Et(e)),t}k(e){Zt(this._$AH)||(this._$AH=[],this._$AR());let t=this._$AH,s,r=0;for(let o of e)r===t.length?t.push(s=new i(this.O(gt()),this.O(gt()),this,this.options)):s=t[r],s._$AI(o),r++;r<t.length&&(this._$AR(s&&s._$AB.nextSibling,r),t.length=r);}_$AR(e=this._$AA.nextSibling,t){for(this._$AP?.(false,true,t);e!==this._$AB;){let s=Ie(e).nextSibling;Ie(e).remove(),e=s;}}setConnected(e){this._$AM===void 0&&(this._$Cv=e,this._$AP?.(e));}},z=class{get tagName(){return this.element.tagName}get _$AU(){return this._$AM._$AU}constructor(e,t,s,r,o){this.type=1,this._$AH=d,this._$AN=void 0,this.element=e,this.name=t,this._$AM=r,this.options=o,s.length>2||s[0]!==""||s[1]!==""?(this._$AH=Array(s.length-1).fill(new String),this.strings=s):this._$AH=d;}_$AI(e,t=this,s,r){let o=this.strings,n=false;if(o===void 0)e=K(this,e,t,0),n=!bt(e)||e!==this._$AH&&e!==j,n&&(this._$AH=e);else {let l=e,c,p;for(e=o[0],c=0;c<o.length-1;c++)p=K(this,l[s+c],t,c),p===j&&(p=this._$AH[c]),n||(n=!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??"");}},Xt=class extends z{constructor(){super(...arguments),this.type=3;}j(e){this.element[this.name]=e===d?void 0:e;}},Kt=class extends z{constructor(){super(...arguments),this.type=4;}j(e){this.element.toggleAttribute(this.name,!!e&&e!==d);}},zt=class extends z{constructor(e,t,s,r,o){super(e,t,s,r,o),this.type=5;}_$AI(e,t=this){if((e=K(this,e,t,0)??d)===j)return;let s=this._$AH,r=e===d&&s!==d||e.capture!==s.capture||e.once!==s.once||e.passive!==s.passive,o=e!==d&&(s===d||r);r&&this.element.removeEventListener(this.name,this,s),o&&this.element.addEventListener(this.name,this,e),this._$AH=e;}handleEvent(e){typeof this._$AH=="function"?this._$AH.call(this.options?.host??this.element,e):this._$AH.handleEvent(e);}},Jt=class{constructor(e,t,s){this.element=e,this.type=6,this._$AN=void 0,this._$AM=t,this.options=s;}get _$AU(){return this._$AM._$AU}_$AI(e){K(this,e);}};var Ps=ft.litHtmlPolyfillSupport;Ps?.(Et,_t),(ft.litHtmlVersions??(ft.litHtmlVersions=[])).push("3.3.2");var Fe=(i,e,t)=>{let s=t?.renderBefore??e,r=s._$litPart$;if(r===void 0){let o=t?.renderBefore??null;s._$litPart$=r=new _t(e.insertBefore(gt(),o),o,void 0,t??{});}return r._$AI(i),r};var St=globalThis,f=class extends O{constructor(){super(...arguments),this.renderOptions={host:this},this._$Do=void 0;}createRenderRoot(){var t;let e=super.createRenderRoot();return (t=this.renderOptions).renderBefore??(t.renderBefore=e.firstChild),e}update(e){let t=this.render();this.hasUpdated||(this.renderOptions.isConnected=this.isConnected),super.update(e),this._$Do=Fe(t,this.renderRoot,this.renderOptions);}connectedCallback(){super.connectedCallback(),this._$Do?.setConnected(true);}disconnectedCallback(){super.disconnectedCallback(),this._$Do?.setConnected(false);}render(){return j}};f._$litElement$=true,f.finalized=true,St.litElementHydrateSupport?.({LitElement:f});var Us=St.litElementPolyfillSupport;Us?.({LitElement:f});(St.litElementVersions??(St.litElementVersions=[])).push("4.2.2");var g=i=>(e,t)=>{t!==void 0?t.addInitializer(()=>{customElements.define(i,e);}):customElements.define(i,e);};var Fs={attribute:true,type:String,converter:mt,reflect:false,hasChanged:kt},Bs=(i=Fs,e,t)=>{let{kind:s,metadata:r}=t,o=globalThis.litPropertyMetadata.get(r);if(o===void 0&&globalThis.litPropertyMetadata.set(r,o=new Map),s==="setter"&&((i=Object.create(i)).wrapped=true),o.set(t.name,i),s==="accessor"){let{name:n}=t;return {set(l){let c=e.get.call(this);e.set.call(this,l),this.requestUpdate(n,c,i,true,l);},init(l){return l!==void 0&&this.C(n,void 0,i,l),l}}}if(s==="setter"){let{name:n}=t;return function(l){let c=this[n];e.call(this,l),this.requestUpdate(n,c,i,true,l);}}throw Error("Unsupported decorator location: "+s)};function T(i){return (e,t)=>typeof t=="object"?Bs(i,e,t):((s,r,o)=>{let n=r.hasOwnProperty(o);return r.constructor.createProperty(o,s),n?Object.getOwnPropertyDescriptor(r,o):void 0})(i,e,t)}function _(i){return 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>`}};u([T()],$t.prototype,"method",2),$t=u([g("bk-method-badge")],$t);var I="/__brakit/api",k="/__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 J="polling",Ht="static",Gs="auth-handshake",Ws="auth-check",js="middleware",yt={[Gs]:1,[Ws]:1,[js]:1};var ee="fetch";var se="error_event",re="query",oe="issues";var ie={overview:"Overview",actions:"Actions",requests:"Requests",fetches:"Server Fetches",queries:"Queries",errors:"Errors",logs:"Logs",performance:"Performance",security:"Security"},ne={overview:"Live summary of your application",actions:"User actions captured as sequences of HTTP requests",requests:"All HTTP requests proxied through brakit",fetches:"Outbound HTTP calls made by your server to external services",queries:"Database queries executed during request handling",errors:"Unhandled exceptions and errors thrown by your application",logs:"Console output from your application",performance:"Endpoint health and response time trends",security:"Security findings and recommendations"};var le=100,Z=300,tt=800,ce=2e3,de=100,pe=50,ue=500;var H="__all__",Ft={SELECT:"var(--blue)",INSERT:"var(--green)",UPDATE:"var(--amber)",DELETE:"var(--red)",COUNT:"var(--text-muted)"},Ke={error:"var(--red)",warn:"var(--amber)",info:"var(--blue)",debug:"var(--text-muted)",log:"var(--text-dim)"},me=["#2563eb","#7c3aed","#16a34a","#d97706","#dc2626","#0891b2","#ea580c","#c026d3","#059669","#db2777"],Tt={green:"#4ade80",amber:"#fbbf24",red:"#f87171"},et=[{max:le,label:"Fast",color:"var(--green)",bg:"rgba(22,163,74,0.08)",border:"rgba(22,163,74,0.2)"},{max:Z,label:"Good",color:"var(--green)",bg:"rgba(22,163,74,0.06)",border:"rgba(22,163,74,0.15)"},{max:tt,label:"OK",color:"var(--amber)",bg:"rgba(217,119,6,0.06)",border:"rgba(217,119,6,0.15)"},{max:ce,label:"Slow",color:"var(--red)",bg:"rgba(220,38,38,0.06)",border:"rgba(220,38,38,0.15)"},{max:1/0,label:"Critical",color:"var(--red)",bg:"rgba(220,38,38,0.08)",border:"rgba(220,38,38,0.2)"}],ze="rgba(228,228,231,0.8)",ve="rgba(113,113,122,0.7)",Je="10px monospace",fe="9px monospace";var Ze={top:16,right:16,bottom:28,left:52},ts={fetch:"var(--blue)",log:"var(--text-muted)",error:"var(--red)",query:"var(--accent)"},es={fetch:"FETCH",log:"LOG",error:"ERROR",query:"QUERY"},ss=new Set(["cookie","set-cookie","authorization","proxy-authorization","x-api-key","x-auth-token"]),rs={400:"Bad Request",401:"Unauthorized",403:"Forbidden",404:"Not Found",405:"Method Not Allowed",408:"Timeout",409:"Conflict",422:"Unprocessable",429:"Too Many Requests",500:"Internal Server Error",502:"Bad Gateway",503:"Service Unavailable",504:"Gateway Timeout"},os=new Set(["host","connection","accept-encoding"]),q={critical:{icon:"\u2717",cls:"critical",sort:0},warning:{icon:"\u26A0",cls:"warning",sort:1},info:{icon:"\u2139",cls:"info",sort:2}};function v(i){return i<1e3?i+"ms":(i/1e3).toFixed(1)+"s"}function U(i){return !i||i===0?"":i<1024?i+"b":(i/1024).toFixed(1)+"kb"}function P(i){return i?i.replace(/&/g,"&").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 is(i){return rs[i]||(i>=500?"Server Error":i>=400?"Client Error":"OK")}function Qs(i,e){if(ss.has(i.toLowerCase())){let t=String(e);return t.length<=8?"****":t.slice(0,4)+"..."+t.slice(-4)+" ("+t.length+" chars)"}return String(e)}function rt(i){return !i||Object.keys(i).length===0?'<span style="color:var(--text-muted)">No headers</span>':Object.entries(i).map(([e,t])=>'<span class="json-key">'+P(e)+"</span>: "+P(Qs(e,t))).join(`
|
|
4
|
+
`)}function Q(i){if(!i)return '<span style="color:var(--text-muted)">No body</span>';try{let e=JSON.parse(i);return Vs(JSON.stringify(e,null,2))}catch{return P(i)}}function Vs(i){return P(i).replace(/("(?:[^"\\]|\\.)*")(\s*:)?|\b(true|false)\b|\bnull\b|(-?\d+\.?\d*(?:[eE][+-]?\d+)?)/g,(e,t,s,r,o)=>t?s?'<span class="json-key">'+t+"</span>"+s:'<span class="json-str">'+t+"</span>":r?'<span class="json-bool">'+e+"</span>":o?'<span class="json-num">'+e+"</span>":e==="null"?'<span class="json-null">null</span>':e)}var xt=class extends f{constructor(){super(...arguments);this.code=0;}createRenderRoot(){return this}render(){let t=st(this.code);return a`<span class="status-pill ${t}">${this.code}</span>`}};u([T({type:Number})],xt.prototype,"code",2),xt=u([g("bk-status-pill")],xt);var Rt=class extends f{constructor(){super(...arguments);this.ms=0;}createRenderRoot(){return this}render(){return a`<span class="req-duration">${v(this.ms)}</span>`}};u([T({type:Number})],Rt.prototype,"ms",2),Rt=u([g("bk-duration-label")],Rt);var ot=class extends f{constructor(){super(...arguments);this.title="";this.subtitle="";}createRenderRoot(){return this}render(){return a`
|
|
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
|
-
`}};u([
|
|
9
|
+
`}};u([T()],ot.prototype,"title",2),u([T()],ot.prototype,"subtitle",2),ot=u([g("bk-empty-state")],ot);var C=class extends f{constructor(){super(...arguments);this.message="";this.visible=false;}createRenderRoot(){return this}static show(t){let s=document.querySelector("bk-toast");s&&s.showMessage(t);}showMessage(t){this.hideTimer&&clearTimeout(this.hideTimer),this.message=t,this.visible=true,this.hideTimer=setTimeout(()=>{this.visible=false;},2e3);}render(){return a`<div class="toast ${this.visible?"show":""}">${this.message}</div>`}};u([_()],C.prototype,"message",2),u([_()],C.prototype,"visible",2),C=u([g("bk-toast")],C);var V=class extends f{constructor(){super(...arguments);this.text="";this.label="Copy";this.toastMessage="Copied";}createRenderRoot(){return this}async copy(t){t.stopPropagation();try{await navigator.clipboard.writeText(this.text),C.show(this.toastMessage);}catch{}}render(){return a`<button class="query-detail-copy" @click=${this.copy}>${this.label}</button>`}};u([T()],V.prototype,"text",2),u([T()],V.prototype,"label",2),u([T({attribute:"toast-message"})],V.prototype,"toastMessage",2),V=u([g("bk-copy-button")],V);var Y=class extends f{constructor(){super(...arguments);this.value="";this.label="";this.color="";}createRenderRoot(){return this}render(){return a`
|
|
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
|
-
`}};u([
|
|
14
|
+
`}};u([T()],Y.prototype,"value",2),u([T()],Y.prototype,"label",2),u([T()],Y.prototype,"color",2),Y=u([g("bk-stat-card")],Y);var F=class extends Event{constructor(e,t,s,r){super("context-request",{bubbles:true,composed:true}),this.context=e,this.contextTarget=t,this.callback=s,this.subscribe=r??false;}};var it=class{constructor(e,t,s,r){if(this.subscribe=false,this.provided=false,this.value=void 0,this.t=(o,n)=>{this.unsubscribe&&(this.unsubscribe!==n&&(this.provided=false,this.unsubscribe()),this.subscribe||this.unsubscribe()),this.value=o,this.host.requestUpdate(),this.provided&&!this.subscribe||(this.provided=true,this.callback&&this.callback(o,n)),this.unsubscribe=n;},this.host=e,t.context!==void 0){let o=t;this.context=o.context,this.callback=o.callback,this.subscribe=o.subscribe??false;}else this.context=t,this.callback=s,this.subscribe=r??false;this.host.addController(this);}hostConnected(){this.dispatchRequest();}hostDisconnected(){this.unsubscribe&&(this.unsubscribe(),this.unsubscribe=void 0);}dispatchRequest(){this.host.dispatchEvent(new F(this.context,this.host,this.t,this.subscribe));}};var Bt=class{get value(){return this.o}set value(e){this.setValue(e);}setValue(e,t=false){let s=t||!Object.is(e,this.o);this.o=e,s&&this.updateObservers();}constructor(e){this.subscriptions=new Map,this.updateObservers=()=>{for(let[t,{disposer:s}]of this.subscriptions)t(this.o,s);},e!==void 0&&(this.value=e);}addCallback(e,t,s){if(!s)return void e(this.value);this.subscriptions.has(e)||this.subscriptions.set(e,{disposer:()=>{this.subscriptions.delete(e);},consumerHost:t});let{disposer:r}=this.subscriptions.get(e);e(this.value,r);}clearCallbacks(){this.subscriptions.clear();}};var ge=class extends Event{constructor(e,t){super("context-provider",{bubbles:true,composed:true}),this.context=e,this.contextTarget=t;}},nt=class extends Bt{constructor(e,t,s){super(t.context!==void 0?t.initialValue:s),this.onContextRequest=r=>{if(r.context!==this.context)return;let o=r.contextTarget??r.composedPath()[0];o!==this.host&&(r.stopPropagation(),this.addCallback(r.callback,o,r.subscribe));},this.onProviderRequest=r=>{if(r.context!==this.context||(r.contextTarget??r.composedPath()[0])===this.host)return;let o=new Set;for(let[n,{consumerHost:l}]of this.subscriptions)o.has(n)||(o.add(n),l.dispatchEvent(new F(this.context,l,n,true)));r.stopPropagation();},this.host=e,t.context!==void 0?this.context=t.context:this.context=t,this.attachListeners(),this.host.addController?.(this);}attachListeners(){this.host.addEventListener("context-request",this.onContextRequest),this.host.addEventListener("context-provider",this.onProviderRequest);}hostConnected(){this.host.dispatchEvent(new ge(this.context,this.host));}};function be({context:i}){return (e,t)=>{let s=new WeakMap;if(typeof t=="object")return {get(){return e.get.call(this)},set(r){return s.get(this).setValue(r),e.set.call(this,r)},init(r){return s.set(this,new nt(this,{context:i,initialValue:r})),r}};{e.constructor.addInitializer((n=>{s.set(n,new nt(n,{context:i}));}));let r=Object.getOwnPropertyDescriptor(e,t),o;if(r===void 0){let n=new WeakMap;o={get(){return n.get(this)},set(l){s.get(this).setValue(l),n.set(this,l);},configurable:true,enumerable:true};}else {let n=r.set;o={...r,set(l){s.get(this).setValue(l),n?.call(this,l);}};}return void Object.defineProperty(e,t,o)}}}function R({context:i,subscribe:e}){return (t,s)=>{typeof s=="object"?s.addInitializer((function(){new it(this,{context:i,callback:r=>{t.set.call(this,r);},subscribe:e});})):t.constructor.addInitializer((r=>{new it(r,{context:i,callback:o=>{r[s]=o;},subscribe:e});}));}}var x="dashboard-store",Gt=class extends EventTarget{constructor(){super(...arguments);this._state={flows:[],requests:[],fetches:[],errors:[],logs:[],queries:[],issues:[],metrics:[],viewMode:"simple",activeView:"overview"};}get state(){return this._state}setFlows(t){this._state={...this._state,flows:t},this.notify("flows");}setRequests(t){this._state={...this._state,requests:t},this.notify("requests");}setFetches(t){this._state={...this._state,fetches:t},this.notify("fetches");}setErrors(t){this._state={...this._state,errors:t},this.notify("errors");}setLogs(t){this._state={...this._state,logs:t},this.notify("logs");}setQueries(t){this._state={...this._state,queries:t},this.notify("queries");}setIssues(t){this._state={...this._state,issues:t},this.notify("issues");}setMetrics(t){this._state={...this._state,metrics:t},this.notify("metrics");}prependRequest(t){let s=[t,...this._state.requests.slice(0,999)];this._state={...this._state,requests:s},this.notify("requests");}prependFetch(t){this._state={...this._state,fetches:[t,...this._state.fetches]},this.notify("fetches");}prependError(t){this._state={...this._state,errors:[t,...this._state.errors]},this.notify("errors");}prependLog(t){this._state={...this._state,logs:[t,...this._state.logs]},this.notify("logs");}prependQuery(t){this._state={...this._state,queries:[t,...this._state.queries]},this.notify("queries");}setActiveView(t){this._state={...this._state,activeView:t},this.notify("activeView");}setViewMode(t){this._state={...this._state,viewMode:t},this.notify("viewMode");}clearAll(){this._state={...this._state,flows:[],requests:[],fetches:[],errors:[],logs:[],queries:[],issues:[],metrics:[]},this.notify("all");}notify(t){this.dispatchEvent(new CustomEvent("state-changed",{detail:t}));}};var at=class extends f{constructor(){super(...arguments);this.expandedIdx=-1;}createRenderRoot(){return this}connectedCallback(){super.connectedCallback(),this.store.addEventListener("state-changed",()=>this.requestUpdate());}toggleError(t){this.expandedIdx=this.expandedIdx===t?-1:t;}renderErrorRow(t,s){let r=new Date(t.timestamp).toLocaleTimeString(),o=this.expandedIdx===s;return a`
|
|
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
|
-
`}};u([
|
|
36
|
+
`}};u([R({context:x})],at.prototype,"store",2),u([_()],at.prototype,"expandedIdx",2),at=u([g("bk-errors-view")],at);var wt=class extends f{createRenderRoot(){return this}connectedCallback(){super.connectedCallback(),this.store.addEventListener("state-changed",()=>this.requestUpdate());}renderAnalysis(e){if(e.length===0)return d;let t={error:0,warn:0,info:0,debug:0,log:0};for(let s of e)t[s.level]!==void 0&&t[s.level]++;return a`
|
|
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
|
-
`}};u([
|
|
66
|
+
`}};u([R({context:x})],wt.prototype,"store",2),wt=u([g("bk-logs-view")],wt);var Xs=new Set(["SELECT","FROM","WHERE","AND","OR","INSERT","INTO","VALUES","UPDATE","SET","DELETE","JOIN","LEFT","RIGHT","INNER","OUTER","ON","GROUP","BY","ORDER","HAVING","LIMIT","OFFSET","AS","IN","NOT","NULL","IS","LIKE","BETWEEN","EXISTS","CASE","WHEN","THEN","ELSE","END","COUNT","SUM","AVG","MIN","MAX","DISTINCT","UNION","ALL","CREATE","TABLE","ALTER","DROP","INDEX","RETURNING","WITH","RECURSIVE","OVER","PARTITION","WINDOW","FETCH","NEXT","ROWS","ONLY","CAST","COALESCE","NULLIF","EXTRACT","INTERVAL","TRUE","FALSE","ASC","DESC","USING","NATURAL","CROSS","FULL","ROLLBACK","COMMIT","BEGIN","TRANSACTION","SAVEPOINT","RELEASE"]);function ns(i){let e=i.trim().match(/^(\w+)/);return e?e[1].toUpperCase():"?"}function as(i){let e=i.replace(/\s+/g," ").trim(),t=e.match(/\bFROM\s+["'`]?(\w+)["'`]?/i);if(t)return t[1];let s=e.match(/\bINTO\s+["'`]?(\w+)["'`]?/i);if(s)return s[1];let r=e.match(/\bUPDATE\s+["'`]?(\w+)["'`]?/i);return r?r[1]:""}function ls(i){return P(i).replace(/\b\w+\b/g,e=>Xs.has(e.toUpperCase())?'<span class="sql-kw">'+e+"</span>":e)}var lt=class extends f{constructor(){super(...arguments);this.expandedIdx=-1;}createRenderRoot(){return this}connectedCallback(){super.connectedCallback(),this.store.addEventListener("state-changed",()=>this.requestUpdate());}toggleQuery(t){this.expandedIdx=this.expandedIdx===t?-1:t;}queryDuration(t){return t===0?"<1ms":v(t)}getQueryInfo(t){let s=(t.normalizedOp||t.operation||(t.sql?ns(t.sql):"?")).toUpperCase(),r=t.table||t.model||(t.sql?as(t.sql):""),o=t.sql||s+" "+r;return {op:s,table:r,sqlText:o}}renderQueryRow(t,s){let{op:r,table:o,sqlText:n}=this.getQueryInfo(t),l=Ft[r]||"var(--text-dim)",c=t.durationMs>de,p=t.sql||r+" "+o,h=this.expandedIdx===s;return a`
|
|
67
67
|
<div>
|
|
68
68
|
<div
|
|
69
|
-
class="req-row query-row tel-clickable ${
|
|
69
|
+
class="req-row query-row tel-clickable ${h?"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=${
|
|
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 ${h?"open":""}">
|
|
78
|
+
${h?a`
|
|
79
|
+
<pre class="query-detail-sql" .innerHTML=${ls(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
|
-
`}};u([
|
|
97
|
+
`}};u([R({context:x})],lt.prototype,"store",2),u([_()],lt.prototype,"expandedIdx",2),lt=u([g("bk-queries-view")],lt);function Ee(i){return i.replace(/'/g,"'\\''")}function Ks(i,e){let t=Object.entries(i.headers||{}).filter(([o])=>!os.has(o)).map(([o,n])=>`-H '${Ee(o)}: ${Ee(n)}'`).join(" "),s=i.requestBody?` -d '${Ee(i.requestBody)}'`:"",r=e?`http://localhost:${e}`:"";return `curl -X ${i.method} ${t}${s} '${r}${i.url}'`}function ct(i){let e=window.__BRAKIT_CONFIG__?.port??"",t=Ks(i,e);navigator.clipboard.writeText(t).then(()=>C.show("Copied cURL command"));}var dt=class extends f{constructor(){super(...arguments);this.expandedId=null;}createRenderRoot(){return this}connectedCallback(){super.connectedCallback(),this.store.addEventListener("state-changed",()=>this.requestUpdate());}toggleRequest(t){this.expandedId=this.expandedId===t?null:t;}handleCopyAsCurl(t,s){s.stopPropagation(),ct(t);}renderDetail(t){return a`
|
|
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=${
|
|
108
|
-
<div class="detail-section"><h4>Request Body</h4><pre .innerHTML=${
|
|
109
|
-
<div class="detail-section"><h4>Response Body</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
|
+
<div class="detail-section"><h4>Request Body</h4><pre .innerHTML=${Q(t.requestBody)}></pre></div>
|
|
109
|
+
<div class="detail-section"><h4>Response Body</h4><pre .innerHTML=${Q(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(
|
|
125
|
+
`}render(){let t=this.store.state.requests.filter(s=>!s.path?.startsWith(k));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,50 +131,53 @@
|
|
|
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
|
-
`}};u([
|
|
134
|
+
`}};u([R({context:x})],dt.prototype,"store",2),u([_()],dt.prototype,"expandedId",2),dt=u([g("bk-requests-view")],dt);var At=class extends f{createRenderRoot(){return this}connectedCallback(){super.connectedCallback(),this.store.addEventListener("state-changed",()=>this.requestUpdate());}buildGroups(e,t){let s=new Map;for(let o of t)s.set(o.id,o);let r={};for(let o of e){let n=o.method+" "+o.url;r[n]||(r[n]={method:o.method,url:o.url,count:0,totalDur:0,maxDur:0,errors:0,callers:{},statusCodes:{},firstTs:o.timestamp,lastTs:o.timestamp});let l=r[n];if(l.count++,l.totalDur+=o.durationMs,o.durationMs>l.maxDur&&(l.maxDur=o.durationMs),o.statusCode>=400&&l.errors++,l.statusCodes[o.statusCode]=(l.statusCodes[o.statusCode]||0)+1,o.timestamp<l.firstTs&&(l.firstTs=o.timestamp),o.timestamp>l.lastTs&&(l.lastTs=o.timestamp),o.parentRequestId){let c=s.get(o.parentRequestId);c&&(l.callers[c.method+" "+(c.path||c.url)]=1);}}return Object.values(r).sort((o,n)=>n.count-o.count)}renderSummary(e){let t=new Set,s=0,r=0;for(let n of e)t.add(n.url),n.statusCode>=400&&s++,r+=n.durationMs;let o=Math.round(r/e.length);return a`
|
|
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=${
|
|
139
|
+
<bk-stat-card value=${v(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">
|
|
150
|
-
<span>avg ${
|
|
150
|
+
<span>avg ${v(t)}</span>
|
|
151
151
|
<span class="fetch-group-sep">\u00b7</span>
|
|
152
|
-
<span>max ${
|
|
152
|
+
<span>max ${v(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
|
-
`}};u([
|
|
177
|
+
`}};u([R({context:x})],At.prototype,"store",2),At=u([g("bk-fetches-view")],At);function cs(i,e){if(e>=400)return "var(--red)";switch(i){case "GET":return "var(--green)";case "POST":return "var(--blue)";case "PUT":case "PATCH":return "var(--amber)";case "DELETE":return "var(--red)";default:return "var(--text-muted)"}}function _e(i){return i==="query"?"var(--accent)":"var(--cyan)"}function tr(i){return i.type==="query"||i.type==="fetch"}function er(i){let e=(i.normalizedOp||i.operation||"QUERY").toUpperCase(),t=i.table||i.model||"";return {label:`${e} ${t}`,tooltip:i.sql||`${e} ${t}`}}function sr(i){return {label:`${i.method} ${i.url}`,tooltip:`${i.method} ${i.url}`}}function rr(i,e,t,s,r,o){let n=i.data.durationMs||0,l,c;if(o){let p=Math.max(i.timestamp-s,0);l=Math.min(p/r*100,95),c=Math.max(n/r*100,1.5);}else {let p=t[0].timestamp,m=t[t.length-1].timestamp-p;l=m>0?(i.timestamp-p)/m*85:e/Math.max(t.length-1,1)*85,c=Math.max(n/r*100,1.5);}return l+c>100&&(c=Math.max(100-l,1.5)),{leftPct:l,widthPct:c}}function or(i,e){let t=i.timeline.filter(tr);if(t.length===0)return [];let s=e.startedAt,r=e.durationMs||1,o=Math.abs(t[0].timestamp-s)<r*10;return t.map((n,l)=>{let c=n.data.durationMs||0,{leftPct:p,widthPct:h}=rr(n,l,t,s,r,o),m=n.type==="query"?er(n.data):sr(n.data);return {type:n.type,label:m.label,durMs:c,durLabel:v(c),tooltip:m.tooltip,leftPct:p,widthPct:h}})}function ps(i,e){let t=i.requests.filter(l=>!l.isStrictModeDupe);if(t.length===0)return {rows:[],totalMs:0};let s=Math.min(...t.map(l=>l.startedAt)),o=Math.max(...t.map(l=>l.startedAt+l.durationMs))-s;return o===0?{rows:[],totalMs:0}:{rows:t.map(l=>{let c=(l.startedAt-s)/o*100,p=Math.max(l.durationMs/o*100,.5),h=e?.activities?.[l.id],m=h?or(h,l):[];return {label:`${l.method} ${l.label}`,leftPct:c,widthPct:p,color:cs(l.method,l.statusCode),durMs:l.durationMs,durLabel:v(l.durationMs),tooltip:`${l.method} ${l.label} (${v(l.durationMs)})`,subEvents:m}}),totalMs:o}}function us(i){let e=i.requests,t=[],s=[],r=[],o=[],n=new Map;for(let p of e){let h=p.label,m=p.pollingDurationMs||p.durationMs;if(!yt[p.category||""]){if(p.isDuplicate){let b=n.get(h);b?(b.count++,b.wastedMs+=m):n.set(h,{name:h,count:2,wastedMs:m});continue}if(p.statusCode>=400){s.push(h+" ("+is(p.statusCode)+")");continue}p.responseSize>51200&&r.push("Large response: "+h+" returned "+U(p.responseSize)),t.push(h);}}for(let p of n.values())o.push(p);let l="";if(o.length>0){let p=o.map(m=>m.name).join(", "),h=o.reduce((m,b)=>m+b.wastedMs,0);l="Your app fetches "+p+" multiple times on this page. This wastes ~"+v(h)+". Try caching these calls, deduplicating with React Query/SWR, or moving them to a shared layout.";}else s.length>0&&(l="Some requests are failing. Check your API routes and make sure the endpoints exist.");let c=e.filter(p=>p.durationMs>2e3&&p.category!==J);return c.length>0&&!l&&(l=c.map(p=>p.label).join(", ")+` is taking over ${v(2e3)}. Consider adding caching or optimizing the backend query.`),{successes:t,errors:s,warnings:r,duplicates:o,tip:l}}var 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
|
+
>${v(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}=ps(t,this.flowTimeline);if(s.length===0)return d;let o=[];for(let n=0;n<=5;n++)o.push(v(r/5*n));return a`
|
|
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=us(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
|
+
~${v(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(yt[t.category||""])return d;let s=st(t.statusCode),r=v(t.pollingDurationMs||t.durationMs),o=!t.isDuplicate&&t.category!==Ht&&t.category!==J||t.requestBody&&t.method!=="GET"||!!t.responseBody;return a`
|
|
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!==J?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
|
-
<pre .innerHTML=${
|
|
322
|
+
<pre .innerHTML=${Q(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?v(t.pollingDurationMs):v(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=${Q(t.requestBody)}></pre>
|
|
370
|
+
</div>
|
|
371
|
+
<div class="detail-section">
|
|
372
|
+
<h4>Response Body</h4>
|
|
373
|
+
<pre .innerHTML=${Q(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
|
-
`}};u([
|
|
384
|
+
`}};u([R({context:x})],M.prototype,"store",2),u([_()],M.prototype,"expandedFlowIdx",2),u([_()],M.prototype,"expandedSubReqIdx",2),u([_()],M.prototype,"flowDetailTab",2),u([_()],M.prototype,"flowTimeline",2),u([_()],M.prototype,"flowTimelineLoading",2),M=u([g("bk-flows-view")],M);var Ct=class extends f{createRenderRoot(){return this}connectedCallback(){super.connectedCallback(),this.store.addEventListener("state-changed",()=>this.requestUpdate());}render(){let e=(this.store.state.issues||[]).slice(),t=e.filter(l=>l.state==="open"||l.state==="fixing"||l.state==="regressed"),s=e.filter(l=>l.state==="resolved");if(t.length===0&&s.length===0)return this.store.state.requests.length>0||this.store.state.logs.length>0||this.store.state.queries.length>0?a`
|
|
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,102 @@
|
|
|
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
|
-
`}};u([
|
|
454
|
+
`}};u([R({context:x})],Ct.prototype,"store",2),Ct=u([g("bk-security-view")],Ct);var pt=class extends f{constructor(){super(...arguments);this.expandedCardIdx=-1;}createRenderRoot(){return this}connectedCallback(){super.connectedCallback(),this.store.addEventListener("state-changed",()=>this.requestUpdate());}toggleCard(t){this.expandedCardIdx=this.expandedCardIdx===t?-1:t;}render(){let t=this.store.state,s=t.requests.filter(E=>!E.isStatic&&!E.isHealthCheck&&(!E.path||E.path.indexOf(k)!==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(E=>E.statusCode>=400).length,n=new Set(["data-fetch","api-call","server-action","page-load"]),l=s.filter(E=>E.category&&n.has(E.category)),c=l.length>0?l:s,p=c.length>0?Math.round(c.reduce((E,It)=>E+It.durationMs,0)/c.length):0,h=t.issues||[],m=h.filter(E=>E.state==="open"||E.state==="regressed"),b=h.filter(E=>E.state==="fixing"),$=h.filter(E=>E.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
|
-
<div class="ov-stat"><span class="ov-stat-value">${
|
|
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">${
|
|
476
|
+
<div class="ov-stat"><span class="ov-stat-value">${v(r)}</span><span class="ov-stat-label">Avg Response</span></div>
|
|
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=${()=>this.toggleCard(s)}>
|
|
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
|
-
|
|
369
|
-
|
|
370
|
-
${r.hint?n`<div class="ov-card-hint">${r.hint}</div>`:d}
|
|
371
|
-
${r.nav?n`<span class="ov-card-link" data-nav=${r.nav}>View in ${de[r.nav]||r.nav} \u2192</span>`:d}
|
|
372
|
-
</div>
|
|
490
|
+
${r.detail?a`<div class="ov-card-detail">${r.detail}</div>`:d}
|
|
491
|
+
${c}
|
|
492
|
+
${n&&r.hint?a`<div class="ov-card-hint">${r.hint}</div>`:d}
|
|
373
493
|
</div>
|
|
374
|
-
|
|
494
|
+
${r.hint?a`<span class="ov-card-arrow">${n?"\u2193":"\u2192"}</span>`:d}
|
|
375
495
|
</div>
|
|
376
|
-
`}renderVerifying(t){return
|
|
496
|
+
`}renderVerifying(t){return a`
|
|
377
497
|
<div class="ov-section-title ov-resolved-title">
|
|
378
498
|
<span style="color:var(--yellow,#f5a623)">\u29d7</span> Awaiting Verification
|
|
379
499
|
<span class="ov-issue-count">${t.length}</span>
|
|
380
500
|
</div>
|
|
381
501
|
<div class="ov-cards">
|
|
382
|
-
${t.map(s=>{let r=s.issue,
|
|
502
|
+
${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
503
|
<div class="ov-card ov-card-resolved">
|
|
384
504
|
<span class="ov-card-icon resolved">\u29d7</span>
|
|
385
505
|
<div class="ov-card-body">
|
|
@@ -388,18 +508,18 @@
|
|
|
388
508
|
<span class="sec-ai-badge sec-ai-fixing">AI fixed \u2014 awaiting verification</span>
|
|
389
509
|
</div>
|
|
390
510
|
<div class="ov-card-desc">${r.desc}</div>
|
|
391
|
-
${
|
|
511
|
+
${o}
|
|
392
512
|
</div>
|
|
393
513
|
</div>
|
|
394
514
|
`})}
|
|
395
515
|
</div>
|
|
396
|
-
`}renderResolvedIssues(t){return
|
|
516
|
+
`}renderResolvedIssues(t){return a`
|
|
397
517
|
<div class="ov-section-title ov-resolved-title">
|
|
398
518
|
<span style="color:var(--green)">\u2713</span> Resolved
|
|
399
519
|
<span class="ov-issue-count">${t.length}</span>
|
|
400
520
|
</div>
|
|
401
521
|
<div class="ov-cards">
|
|
402
|
-
${t.map(s=>
|
|
522
|
+
${t.map(s=>a`
|
|
403
523
|
<div class="ov-card ov-card-resolved">
|
|
404
524
|
<span class="ov-card-icon resolved">\u2713</span>
|
|
405
525
|
<div class="ov-card-body">
|
|
@@ -409,71 +529,98 @@
|
|
|
409
529
|
</div>
|
|
410
530
|
`)}
|
|
411
531
|
</div>
|
|
412
|
-
`}};u([
|
|
532
|
+
`}};u([R({context:x})],pt.prototype,"store",2),u([_()],pt.prototype,"expandedCardIdx",2),pt=u([g("bk-overview-view")],pt);function hs(i){return i<1?"<1ms":i<1e3?Math.round(i)+"ms":(i/1e3).toFixed(1)+"s"}function ir(i){return i<Z?Tt.green:i<tt?Tt.amber:Tt.red}function nr(i){return i.statusCode>=400?Tt.red:ir(i.durationMs)}function ms(i){return [parseInt(i.slice(1,3),16),parseInt(i.slice(3,5),16),parseInt(i.slice(5,7),16)]}function ar(i){let e=i.getContext("2d");if(!e)return null;let t=window.devicePixelRatio||1,s=i.clientWidth,r=i.clientHeight;return i.width=s*t,i.height=r*t,e.scale(t,t),{ctx:e,w:s,h:r}}function lr(i,e,t,s,r){let[o,n,l]=ms(r);i.beginPath(),i.arc(e,t,s+2,0,Math.PI*2),i.fillStyle=`rgba(${o},${n},${l},0.25)`,i.fill(),i.beginPath(),i.arc(e,t,s,0,Math.PI*2),i.fillStyle=r,i.fill();}function cr(i,e,t,s,r,o){let[n,l,c]=ms(r);i.strokeStyle=`rgba(${n},${l},${c},0.3)`,i.lineWidth=o+2,i.beginPath(),i.moveTo(e-s,t-s),i.lineTo(e+s,t+s),i.moveTo(e+s,t-s),i.lineTo(e-s,t+s),i.stroke(),i.strokeStyle=r,i.lineWidth=o,i.beginPath(),i.moveTo(e-s,t-s),i.lineTo(e+s,t+s),i.moveTo(e+s,t-s),i.lineTo(e-s,t+s),i.stroke();}function vs(i,e){let t=[],s=ar(i);if(!s||e.length===0)return t;let{ctx:r,w:o,h:n}=s,l=Ze,c=o-l.left-l.right,p=n-l.top-l.bottom,h=0,m=e[0].timestamp,b=e[0].timestamp;for(let S of e)S.durationMs>h&&(h=S.durationMs),S.timestamp<m&&(m=S.timestamp),S.timestamp>b&&(b=S.timestamp);h=Math.max(h,10),h=Math.ceil(h*1.15/10)*10;let $=b-m||1;r.strokeStyle=ze,r.lineWidth=1;let E=4;for(let S=0;S<=E;S++){let A=l.top+p-S/E*p;r.beginPath(),r.moveTo(l.left,A),r.lineTo(l.left+c,A),r.stroke(),r.fillStyle=ve,r.font=Je,r.textAlign="right",r.fillText(hs(Math.round(S/E*h)),l.left-8,A+3);}for(let S of [{ms:Z},{ms:tt}]){if(S.ms>=h)continue;let A=l.top+p-S.ms/h*p;r.beginPath(),r.setLineDash([4,4]),r.strokeStyle="rgba(113,113,122,0.3)",r.lineWidth=1,r.moveTo(l.left,A),r.lineTo(l.left+c,A),r.stroke(),r.setLineDash([]),r.fillStyle="rgba(113,113,122,0.5)",r.font=fe,r.textAlign="left",r.fillText(hs(S.ms),l.left+c+2,A+3);}for(let S=0;S<e.length;S++){let A=e[S],ut=e.length===1?l.left+c/2:l.left+(A.timestamp-m)/$*c,jt=l.top+p-A.durationMs/h*p,ye=nr(A);t.push({x:ut,y:jt,idx:S,r:A}),A.statusCode>=400?cr(r,ut,jt,4,ye,2):lr(r,ut,jt,4,ye);}r.fillStyle=ve,r.font=fe,r.textAlign="center";let It=[m,m+$/2,b];for(let S=0;S<It.length;S++){let A=l.left+S/2*c,ut=new Date(It[S]);r.fillText(ut.toLocaleTimeString([],{hour:"2-digit",minute:"2-digit",second:"2-digit"}),A,l.top+p+14);}return t}var vr={max:1/0,label:"Pending",color:"var(--text-muted)",bg:"var(--bg-muted)",border:"var(--border)"};function fs(i,e,t){return t>=20?i:e}function $e(i,e){if(!e||e<=0)return vr;let t=i/e;return t<.7?et[0]:t<1.2?et[1]:t<2?et[2]:t<3?et[3]:et[4]}var L=class extends f{constructor(){super(...arguments);this.selectedEndpoint=H;this.graphData=[];this.loadError=false;this.queryBreakdown=[];this.queryBreakdownLoading=false;this.scatterDots=[];}createRenderRoot(){return this}connectedCallback(){super.connectedCallback(),this.store.addEventListener("state-changed",()=>this.requestUpdate()),this.loadMetrics();}async loadMetrics(){try{let s=await(await fetch(y.metricsLive)).json();this.graphData=s.endpoints||[],this.loadError=!1,(!this.selectedEndpoint||this.selectedEndpoint===H)&&(this.selectedEndpoint=H);}catch{this.loadError=true;}}healthGradeForEndpoint(t){let s=fs(t.summary.p95Ms,t.summary.medianMs,t.summary.totalRequests);return $e(s,t.baselineP95Ms)}healthGradeForDuration(t,s){return $e(t,s)}getCallers(t){let s=this.store.state.flows,r=new Map;for(let o of s)for(let n of o.requests)if(`${n.method} ${n.path}`===t||this.normalizeEndpoint(n)===t){let c=r.get(o.label);c?(c.count++,c.totalMs+=n.durationMs):r.set(o.label,{count:1,totalMs:n.durationMs});}return [...r.entries()].map(([o,n])=>({label:o,count:n.count,avgMs:Math.round(n.totalMs/n.count)})).sort((o,n)=>n.count-o.count)}normalizeEndpoint(t){let s=t.path.replace(/\/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/gi,"/:id").replace(/\/\d+/g,"/:id");return `${t.method} ${s}`}async loadQueryBreakdown(t){if(this.queryBreakdownLoading)return;let r=this.store.state.requests.filter(o=>`${o.method} ${o.path}`===t||this.normalizeEndpoint(o)===t).slice(-20).map(o=>o.id).filter(Boolean);if(r.length===0){this.queryBreakdown=[];return}this.queryBreakdownLoading=true;try{let o=await fetch(`${y.activity}?requestIds=${r.join(",")}`);if(!o.ok){this.queryBreakdownLoading=!1;return}let n=await o.json(),l=new Map;for(let c of Object.values(n.activities))for(let p of c.timeline){if(p.type!=="query")continue;let h=p.data,m=(h.normalizedOp||h.operation||"QUERY").toUpperCase(),b=h.table||h.model||"",$=`${m} ${b}`.trim(),E=l.get($);E?(E.totalMs+=h.durationMs,E.count++):l.set($,{label:$,totalMs:h.durationMs,count:1});}this.queryBreakdown=[...l.values()].map(c=>({...c,avgMs:Math.round(c.totalMs/c.count)})).sort((c,p)=>p.totalMs-c.totalMs);}catch{}this.queryBreakdownLoading=false;}renderScatterChart(t,s){this.scatterDots=vs(t,s),t.style.cursor="pointer",t.onclick=r=>{let o=t.getBoundingClientRect(),n=r.clientX-o.left,l=r.clientY-o.top,c=null,p=1/0;for(let h of this.scatterDots){let m=Math.sqrt((h.x-n)**2+(h.y-l)**2);m<p&&(p=m,c=h);}c&&p<16&&this.highlightRow(c.idx);};}highlightRow(t){let s=this.querySelector(".perf-hist-row-hl");s&&s.classList.remove("perf-hist-row-hl");let r=this.querySelector(`[data-req-idx="${t}"]`);r&&(r.classList.add("perf-hist-row-hl"),r.scrollIntoView({behavior:"smooth",block:"center"}));}updated(){if(this.selectedEndpoint===H)return;let t=this.querySelector("#perf-detail-canvas");if(t){let s=this.graphData.find(r=>r.endpoint===this.selectedEndpoint);s&&this.renderScatterChart(t,s.requests);}}render(){return !this.graphData||this.graphData.length===0?a`<bk-empty-state title="No performance data yet" subtitle="Hit some endpoints and data will appear here"></bk-empty-state>`:a`
|
|
413
533
|
<div id="graph-content">
|
|
414
534
|
${this.renderSelector()}
|
|
415
|
-
${this.selectedEndpoint===
|
|
535
|
+
${this.selectedEndpoint===H?this.renderOverview():this.renderDetail()}
|
|
416
536
|
</div>
|
|
417
|
-
`}renderSelector(){return
|
|
537
|
+
`}renderSelector(){return a`
|
|
418
538
|
<div class="perf-selector">
|
|
419
|
-
<button class="perf-selector-btn ${this.selectedEndpoint===
|
|
420
|
-
@click=${()=>{this.selectedEndpoint=
|
|
421
|
-
${this.graphData.map((t,s)=>
|
|
539
|
+
<button class="perf-selector-btn ${this.selectedEndpoint===H?"active":""}"
|
|
540
|
+
@click=${()=>{this.selectedEndpoint=H;}}>Overview</button>
|
|
541
|
+
${this.graphData.map((t,s)=>a`
|
|
422
542
|
<button class="perf-selector-btn ${t.endpoint===this.selectedEndpoint?"active":""}"
|
|
423
|
-
@click=${()=>{this.selectedEndpoint=t.endpoint;}}>
|
|
424
|
-
<span class="perf-dot" style="background:${
|
|
543
|
+
@click=${()=>{this.selectedEndpoint=t.endpoint,this.queryBreakdown=[],this.loadQueryBreakdown(t.endpoint);}}>
|
|
544
|
+
<span class="perf-dot" style="background:${me[s%me.length]}"></span>${t.endpoint}
|
|
425
545
|
</button>
|
|
426
546
|
`)}
|
|
427
547
|
</div>
|
|
428
|
-
`}renderOverview(){return n`
|
|
429
|
-
<div class="perf-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
548
|
+
`}renderOverview(){let t=this.graphData.filter(c=>c.requests.length>0);if(t.length===0)return d;let s=t.reduce((c,p)=>c+p.summary.totalRequests,0),r=s>0?Math.round(t.reduce((c,p)=>c+p.summary.p95Ms*p.summary.totalRequests,0)/s):0,o=t.reduce((c,p)=>c+Math.round(p.summary.errorRate*p.summary.totalRequests),0),n=s>0?o/s:0,l=t[0];return a`
|
|
549
|
+
<div class="perf-overview">
|
|
550
|
+
<div class="perf-summary-row">
|
|
551
|
+
<div class="perf-summary-card">
|
|
552
|
+
<span class="perf-summary-label">Total Requests</span>
|
|
553
|
+
<span class="perf-summary-value">${s}</span>
|
|
554
|
+
</div>
|
|
555
|
+
<div class="perf-summary-card">
|
|
556
|
+
<span class="perf-summary-label">Avg P95</span>
|
|
557
|
+
<span class="perf-summary-value" style="color:${this.healthGradeForDuration(r).color}">${v(r)}</span>
|
|
558
|
+
</div>
|
|
559
|
+
<div class="perf-summary-card">
|
|
560
|
+
<span class="perf-summary-label">Error Rate</span>
|
|
561
|
+
<span class="perf-summary-value" style="color:${o>0?"var(--red)":"var(--green)"}">${Math.round(n*100)}%</span>
|
|
562
|
+
</div>
|
|
563
|
+
<div class="perf-summary-card">
|
|
564
|
+
<span class="perf-summary-label">Slowest</span>
|
|
565
|
+
<span class="perf-summary-value perf-summary-value-sm">${l?.endpoint??"-"}</span>
|
|
438
566
|
</div>
|
|
439
|
-
<span class="perf-breakdown-labels">
|
|
440
|
-
${h>0?n`<span class="perf-breakdown-lbl"><span class="perf-breakdown-dot perf-breakdown-db"></span>${this.fmtMs(r.avgQueryTimeMs||0)}</span>`:d}
|
|
441
|
-
${m>0?n`<span class="perf-breakdown-lbl"><span class="perf-breakdown-dot perf-breakdown-fetch"></span>${this.fmtMs(r.avgFetchTimeMs||0)}</span>`:d}
|
|
442
|
-
<span class="perf-breakdown-lbl"><span class="perf-breakdown-dot perf-breakdown-app"></span>${this.fmtMs(r.avgAppTimeMs||0)}</span>
|
|
443
|
-
</span>
|
|
444
567
|
</div>
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
568
|
+
|
|
569
|
+
<table class="perf-table perf-heatmap">
|
|
570
|
+
<thead>
|
|
571
|
+
<tr>
|
|
572
|
+
<th>Endpoint</th>
|
|
573
|
+
<th class="perf-th-right">Calls</th>
|
|
574
|
+
<th class="perf-th-center">P95</th>
|
|
575
|
+
<th class="perf-th-center">Errors</th>
|
|
576
|
+
<th class="perf-th-center">Q/Req</th>
|
|
577
|
+
<th>Time Split</th>
|
|
578
|
+
</tr>
|
|
579
|
+
</thead>
|
|
580
|
+
<tbody>
|
|
581
|
+
${t.map(c=>this.renderHeatmapRow(c))}
|
|
582
|
+
</tbody>
|
|
583
|
+
</table>
|
|
584
|
+
</div>
|
|
585
|
+
`}renderHeatmapRow(t){let s=t.summary,r=this.healthGradeForEndpoint(t),o=Math.round(s.errorRate*s.totalRequests),n=(s.avgQueryTimeMs||0)+(s.avgFetchTimeMs||0)+(s.avgAppTimeMs||0),l=0,c=0,p=100;return n>0&&(l=Math.round((s.avgQueryTimeMs||0)/n*100),c=Math.round((s.avgFetchTimeMs||0)/n*100),p=Math.max(0,100-l-c)),a`
|
|
586
|
+
<tr class="perf-table-row" @click=${()=>{this.selectedEndpoint=t.endpoint,this.queryBreakdown=[],this.loadQueryBreakdown(t.endpoint);}}>
|
|
587
|
+
<td class="perf-td-name">${t.endpoint}</td>
|
|
588
|
+
<td class="perf-td-right">${s.totalRequests}</td>
|
|
589
|
+
<td class="perf-td-center">
|
|
590
|
+
<span class="perf-hm-p95" style="color:${r.color};background:${r.bg};border-color:${r.border}">${v(s.p95Ms)}</span>
|
|
591
|
+
</td>
|
|
592
|
+
<td class="perf-td-center" style="color:${o>0?"var(--red)":"var(--text-muted)"}">${o>0?o:"-"}</td>
|
|
593
|
+
<td class="perf-td-center" style="color:${s.avgQueryCount>5?"var(--amber)":"var(--text-muted)"}">${s.avgQueryCount}</td>
|
|
594
|
+
<td>
|
|
595
|
+
<span class="perf-hm-split-bar">
|
|
596
|
+
${l>0?a`<span class="perf-breakdown-seg perf-breakdown-db" style="width:${l}%"></span>`:d}
|
|
597
|
+
${c>0?a`<span class="perf-breakdown-seg perf-breakdown-fetch" style="width:${c}%"></span>`:d}
|
|
598
|
+
${p>0?a`<span class="perf-breakdown-seg perf-breakdown-app" style="width:${p}%"></span>`:d}
|
|
454
599
|
</span>
|
|
455
|
-
</
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
</div>
|
|
459
|
-
`}renderDetail(){let t=this.graphData.find(a=>a.endpoint===this.selectedEndpoint);if(!t?.requests?.length)return n`<bk-empty-state subtitle="No data for this endpoint"></bk-empty-state>`;let s=t.summary,r=this.healthGrade(s.p95Ms),i=Math.round(s.errorRate*s.totalRequests);return n`
|
|
600
|
+
</td>
|
|
601
|
+
</tr>
|
|
602
|
+
`}renderDetail(){let t=this.graphData.find(n=>n.endpoint===this.selectedEndpoint);if(!t?.requests?.length)return a`<bk-empty-state subtitle="No data for this endpoint"></bk-empty-state>`;let s=t.summary,r=this.healthGradeForEndpoint(t),o=Math.round(s.errorRate*s.totalRequests);return a`
|
|
460
603
|
${this.renderDetailHeader(t,r)}
|
|
461
|
-
${this.renderDetailMetrics(s,r,
|
|
604
|
+
${this.renderDetailMetrics(s,r,o)}
|
|
462
605
|
${this.renderDetailBreakdown(s)}
|
|
606
|
+
${this.renderCallers(t.endpoint)}
|
|
607
|
+
${this.renderQueryBreakdown()}
|
|
608
|
+
${this.renderTrends(t)}
|
|
463
609
|
${this.renderDetailChart()}
|
|
464
610
|
${this.renderDetailHistory(t)}
|
|
465
|
-
`}renderDetailHeader(t,s){return
|
|
611
|
+
`}renderDetailHeader(t,s){return a`
|
|
466
612
|
<div class="perf-detail-header">
|
|
467
613
|
<div class="perf-detail-title">
|
|
468
614
|
<span class="perf-badge perf-badge-lg" style="color:${s.color};background:${s.bg};border-color:${s.border}">${s.label}</span>
|
|
469
615
|
<span>${t.endpoint}</span>
|
|
616
|
+
${t.baselineP95Ms?a`<span class="perf-baseline-hint">Baseline: ${v(t.baselineP95Ms)}</span>`:d}
|
|
470
617
|
</div>
|
|
471
618
|
</div>
|
|
472
|
-
`}renderDetailMetrics(t,s,r){return
|
|
619
|
+
`}renderDetailMetrics(t,s,r){return a`
|
|
473
620
|
<div class="perf-metric-row">
|
|
474
621
|
<div class="perf-metric-card">
|
|
475
622
|
<span class="perf-metric-label">P95</span>
|
|
476
|
-
<span class="perf-metric-value" style="color:${s.color}">${
|
|
623
|
+
<span class="perf-metric-value" style="color:${s.color}">${v(t.p95Ms)}</span>
|
|
477
624
|
</div>
|
|
478
625
|
<div class="perf-metric-card">
|
|
479
626
|
<span class="perf-metric-label">Errors</span>
|
|
@@ -486,119 +633,170 @@
|
|
|
486
633
|
<span class="perf-metric-value" style="color:${t.avgQueryCount>5?"var(--amber)":"var(--text)"}">${t.avgQueryCount}</span>
|
|
487
634
|
</div>
|
|
488
635
|
</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),
|
|
636
|
+
`}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
637
|
<div class="perf-breakdown">
|
|
491
638
|
<div class="perf-section-title">Time Breakdown</div>
|
|
492
639
|
<div class="perf-breakdown-bar">
|
|
493
|
-
${r>0?
|
|
494
|
-
${
|
|
495
|
-
${
|
|
640
|
+
${r>0?a`<div class="perf-breakdown-seg perf-breakdown-db" style="width:${r}%"></div>`:d}
|
|
641
|
+
${o>0?a`<div class="perf-breakdown-seg perf-breakdown-fetch" style="width:${o}%"></div>`:d}
|
|
642
|
+
${n>0?a`<div class="perf-breakdown-seg perf-breakdown-app" style="width:${n}%"></div>`:d}
|
|
496
643
|
</div>
|
|
497
644
|
<div class="perf-breakdown-legend">
|
|
498
|
-
<span class="perf-breakdown-item"><span class="perf-breakdown-dot perf-breakdown-db"></span>DB ${
|
|
499
|
-
<span class="perf-breakdown-item"><span class="perf-breakdown-dot perf-breakdown-fetch"></span>Fetch ${
|
|
500
|
-
<span class="perf-breakdown-item"><span class="perf-breakdown-dot perf-breakdown-app"></span>App ${
|
|
645
|
+
<span class="perf-breakdown-item"><span class="perf-breakdown-dot perf-breakdown-db"></span>DB ${v(t.avgQueryTimeMs||0)} (${r}%)</span>
|
|
646
|
+
<span class="perf-breakdown-item"><span class="perf-breakdown-dot perf-breakdown-fetch"></span>Fetch ${v(t.avgFetchTimeMs||0)} (${o}%)</span>
|
|
647
|
+
<span class="perf-breakdown-item"><span class="perf-breakdown-dot perf-breakdown-app"></span>App ${v(t.avgAppTimeMs||0)} (${n}%)</span>
|
|
501
648
|
</div>
|
|
502
649
|
</div>
|
|
503
|
-
`}
|
|
650
|
+
`}renderCallers(t){let s=this.getCallers(t);return s.length===0?d:a`
|
|
651
|
+
<div class="perf-callers">
|
|
652
|
+
<div class="perf-section-title">Called By</div>
|
|
653
|
+
<div class="perf-callers-list">
|
|
654
|
+
${s.map(r=>a`
|
|
655
|
+
<div class="perf-caller-row">
|
|
656
|
+
<span class="perf-caller-name">${r.label}</span>
|
|
657
|
+
<span class="perf-caller-count">${r.count} call${r.count!==1?"s":""}</span>
|
|
658
|
+
<span class="perf-caller-avg">avg ${v(r.avgMs)}</span>
|
|
659
|
+
</div>
|
|
660
|
+
`)}
|
|
661
|
+
</div>
|
|
662
|
+
</div>
|
|
663
|
+
`}renderQueryBreakdown(){return this.queryBreakdownLoading?a`<div class="perf-queries"><div class="perf-section-title">DB Queries</div><div class="perf-queries-loading">Loading...</div></div>`:this.queryBreakdown.length===0?d:a`
|
|
664
|
+
<div class="perf-queries">
|
|
665
|
+
<div class="perf-section-title">DB Queries</div>
|
|
666
|
+
<div class="perf-queries-list">
|
|
667
|
+
${this.queryBreakdown.map(t=>a`
|
|
668
|
+
<div class="perf-query-row">
|
|
669
|
+
<span class="perf-query-label">${t.label}</span>
|
|
670
|
+
<span class="perf-query-avg">avg ${v(t.avgMs)}</span>
|
|
671
|
+
<span class="perf-query-count">${t.count} call${t.count!==1?"s":""}</span>
|
|
672
|
+
</div>
|
|
673
|
+
`)}
|
|
674
|
+
</div>
|
|
675
|
+
</div>
|
|
676
|
+
`}renderTrends(t){let s=t.sessions;if(!s||s.length===0)return d;let r=s.slice(-10);return a`
|
|
677
|
+
<div class="perf-trends">
|
|
678
|
+
<div class="perf-section-title">Session Trend</div>
|
|
679
|
+
<div class="perf-trends-list">
|
|
680
|
+
${r.map((o,n)=>{let l=n>0?r[n-1].p95DurationMs:null,c=l!==null?o.p95DurationMs>l*1.2?"slower":o.p95DurationMs<l*.8?"faster":"":"",p=this.formatTimeAgo(o.startedAt),h=n===r.length-1,m=this.healthGradeForDuration(o.p95DurationMs,t.baselineP95Ms);return a`
|
|
681
|
+
<div class="perf-trend-row ${h?"perf-trend-current":""}">
|
|
682
|
+
<span class="perf-trend-time">${h?"Current":p}</span>
|
|
683
|
+
<span class="perf-trend-p95">
|
|
684
|
+
<span class="perf-hm-p95" style="color:${m.color};background:${m.bg};border-color:${m.border}">
|
|
685
|
+
p95: ${v(o.p95DurationMs)}
|
|
686
|
+
</span>
|
|
687
|
+
</span>
|
|
688
|
+
<span class="perf-trend-reqs">${o.requestCount} req${o.requestCount!==1?"s":""}</span>
|
|
689
|
+
<span class="perf-trend-errs" style="color:${o.errorCount>0?"var(--red)":"var(--text-dim)"}">${o.errorCount} err${o.errorCount!==1?"s":""}</span>
|
|
690
|
+
${c?a`<span class="perf-trend-arrow ${c==="slower"?"perf-trend-slower":"perf-trend-faster"}">${c==="slower"?"\u2191 slower":"\u2193 faster"}</span>`:d}
|
|
691
|
+
</div>
|
|
692
|
+
`})}
|
|
693
|
+
</div>
|
|
694
|
+
</div>
|
|
695
|
+
`}formatTimeAgo(t){let s=Date.now()-t,r=Math.round(s/6e4);if(r<1)return "just now";if(r<60)return `${r}m ago`;let o=Math.round(r/60);return o<24?`${o}h ago`:`${Math.round(o/24)}d ago`}renderDetailChart(){return a`
|
|
504
696
|
<div class="perf-chart-wrap">
|
|
505
697
|
<div class="perf-section-title">Response Time</div>
|
|
506
698
|
<canvas id="perf-detail-canvas" class="perf-canvas" style="width:100%;height:240px"></canvas>
|
|
507
699
|
</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({
|
|
700
|
+
`}renderDetailHistory(t){if(t.requests.length===0)return d;let s=[];for(let r=t.requests.length-1;r>=0&&s.length<50;r--)s.push({point:t.requests[r],originalIndex:r});return a`
|
|
509
701
|
<div class="perf-history-wrap">
|
|
510
|
-
<
|
|
511
|
-
<
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
<span class="perf-
|
|
531
|
-
</
|
|
532
|
-
<
|
|
533
|
-
<
|
|
534
|
-
|
|
535
|
-
|
|
702
|
+
<table class="perf-table">
|
|
703
|
+
<thead>
|
|
704
|
+
<tr>
|
|
705
|
+
<th>Time</th>
|
|
706
|
+
<th>Health</th>
|
|
707
|
+
<th>Duration</th>
|
|
708
|
+
<th>Breakdown</th>
|
|
709
|
+
<th class="perf-th-center">Status</th>
|
|
710
|
+
<th class="perf-th-right">Queries</th>
|
|
711
|
+
</tr>
|
|
712
|
+
</thead>
|
|
713
|
+
<tbody>
|
|
714
|
+
${s.map(r=>this.renderHistoryRow(r.point,r.originalIndex,t.baselineP95Ms))}
|
|
715
|
+
</tbody>
|
|
716
|
+
</table>
|
|
717
|
+
</div>
|
|
718
|
+
`}renderHistoryRow(t,s,r){let o=this.healthGradeForDuration(t.durationMs,r),n=new Date(t.timestamp).toLocaleTimeString([],{hour:"2-digit",minute:"2-digit",second:"2-digit"}),l=t.statusCode>=400,c=t.queryTimeMs||0,p=t.fetchTimeMs||0,h=Math.max(0,t.durationMs-c-p);return a`
|
|
719
|
+
<tr class="perf-table-row ${l?"perf-row-err":""}" data-req-idx=${s}>
|
|
720
|
+
<td class="perf-td-muted">${n}</td>
|
|
721
|
+
<td>
|
|
722
|
+
<span class="perf-badge perf-badge-sm" style="color:${o.color};background:${o.bg};border-color:${o.border}">${o.label}</span>
|
|
723
|
+
</td>
|
|
724
|
+
<td>${v(t.durationMs)}</td>
|
|
725
|
+
<td>
|
|
726
|
+
${c>0?a`<span class="perf-bd-tag perf-bd-tag-db">DB ${v(c)}</span>`:d}
|
|
727
|
+
${p>0?a`<span class="perf-bd-tag perf-bd-tag-fetch">Fetch ${v(p)}</span>`:d}
|
|
728
|
+
<span class="perf-bd-tag perf-bd-tag-app">App ${v(h)}</span>
|
|
729
|
+
</td>
|
|
730
|
+
<td class="perf-td-center" style="color:${l?"var(--red)":"var(--text-muted)"}">${t.statusCode}</td>
|
|
731
|
+
<td class="perf-td-right perf-td-muted">${t.queryCount}</td>
|
|
732
|
+
</tr>
|
|
733
|
+
`}};u([R({context:x})],L.prototype,"store",2),u([_()],L.prototype,"selectedEndpoint",2),u([_()],L.prototype,"graphData",2),u([_()],L.prototype,"loadError",2),u([_()],L.prototype,"queryBreakdown",2),u([_()],L.prototype,"queryBreakdownLoading",2),L=u([g("bk-performance-view")],L);function _r(i){return i===0?"<1ms":v(i)}var w=class extends f{constructor(){super(...arguments);this.requestId="";this.requestStarted=0;this.data=null;this.loading=false;this.failed=false;this.expandedSqlIdx=-1;}createRenderRoot(){return this}connectedCallback(){super.connectedCallback(),this.store.addEventListener("state-changed",()=>this.requestUpdate()),this.requestId&&this.loadTimeline();}async loadTimeline(){if(!this.requestId)return;let t=w.cache.get(this.requestId);if(t){this.data=t;return}this.loading=true;try{let s=await fetch(`${y.activity}?requestId=${this.requestId}`);if(!s.ok){this.failed=!0,this.loading=!1;return}let r=await s.json();if(w.cache.size>=pe){let o=w.cache.keys().next().value;o!==void 0&&w.cache.delete(o);}w.cache.set(this.requestId,r),this.data=r,this.loading=!1;}catch(s){console.debug("[brakit] timeline load failed:",s),this.failed=true,this.loading=false;}}toggleSql(t,s){s.stopPropagation(),this.expandedSqlIdx=this.expandedSqlIdx===t?-1:t;}copySql(t,s){s.stopPropagation(),navigator.clipboard.writeText(t).then(()=>C.show("SQL copied")).catch(()=>C.show("Copy failed"));}render(){if(this.loading)return a`<div class="tl-loading">Loading activity...</div>`;if(this.failed||!this.data||this.data.total===0)return d;let t=this.data,s=t.timeline[0]?.timestamp??0;return a`
|
|
536
734
|
<div class="tl-header">
|
|
537
735
|
<span class="tl-title">Activity Timeline</span>
|
|
538
736
|
<span class="tl-counts">
|
|
539
|
-
${t.counts.queries>0?
|
|
540
|
-
${t.counts.fetches>0?
|
|
541
|
-
${t.counts.logs>0?
|
|
542
|
-
${t.counts.errors>0?
|
|
737
|
+
${t.counts.queries>0?a`<span class="tl-count tl-count-query">${t.counts.queries} quer${t.counts.queries===1?"y":"ies"}</span>`:d}
|
|
738
|
+
${t.counts.fetches>0?a`<span class="tl-count tl-count-fetch">${t.counts.fetches} fetch${t.counts.fetches===1?"":"es"}</span>`:d}
|
|
739
|
+
${t.counts.logs>0?a`<span class="tl-count tl-count-log">${t.counts.logs} log${t.counts.logs===1?"":"s"}</span>`:d}
|
|
740
|
+
${t.counts.errors>0?a`<span class="tl-count tl-count-error">${t.counts.errors} error${t.counts.errors===1?"":"s"}</span>`:d}
|
|
543
741
|
</span>
|
|
544
742
|
</div>
|
|
545
743
|
<div class="tl-events">${this.renderTimeline(t.timeline,s)}</div>
|
|
546
|
-
`}renderTimeline(t,s){let r=new Map,
|
|
547
|
-
${this.renderEvent(c,
|
|
744
|
+
`}renderTimeline(t,s){let r=new Map,o=[];for(let l of t){let c=l.type==="query"?l.data.parentFetchId:void 0;if(l.type==="query"&&c){let p=r.get(c);p||(p=[],r.set(c,p)),p.push(l);}else o.push(l);}let n=0;return o.map(l=>{let c=n++,p=l.type==="fetch"?l.data.fetchId:void 0,h=p?r.get(p):void 0;if(h&&h.length>0){let m=h.length;return a`
|
|
745
|
+
${this.renderEvent(l,c,s)}
|
|
548
746
|
<div class="tl-nested">
|
|
549
|
-
<span class="tl-nested-label">${
|
|
550
|
-
${
|
|
747
|
+
<span class="tl-nested-label">${m} nested quer${m===1?"y":"ies"}</span>
|
|
748
|
+
${h.map(b=>{let $=n++;return this.renderEvent(b,$,s,true)})}
|
|
551
749
|
</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:${
|
|
750
|
+
`}return this.renderEvent(l,c,s)})}renderEvent(t,s,r,o=false){let n=ts[t.type]||"var(--text-dim)",l=es[t.type]||t.type,c="+"+v(Math.round(t.timestamp-r)),p=t.type==="query"?t.data.sql:void 0,h=!!p,m=this.expandedSqlIdx===s;return a`
|
|
751
|
+
<div class="tl-event ${h?"tl-clickable":""} ${o?"tl-nested-event":""}"
|
|
752
|
+
style="${h?"":`border-left-color:${n}`}"
|
|
753
|
+
@click=${h?b=>this.toggleSql(s,b):d}>
|
|
754
|
+
<span class="tl-event-time">${c}</span>
|
|
755
|
+
<span class="tl-event-type" style="color:${n}">${l}</span>
|
|
558
756
|
${this.renderEventContent(t)}
|
|
559
|
-
${
|
|
560
|
-
<div class="tl-event-sql ${
|
|
561
|
-
<button class="tl-sql-copy" @click=${
|
|
562
|
-
${
|
|
757
|
+
${p?a`
|
|
758
|
+
<div class="tl-event-sql ${m?"open":""}">
|
|
759
|
+
<button class="tl-sql-copy" @click=${b=>this.copySql(p,b)}>Copy</button>
|
|
760
|
+
${p}
|
|
563
761
|
</div>`:d}
|
|
564
762
|
</div>
|
|
565
|
-
`}renderEventContent(t){switch(t.type){case "fetch":{let s=t.data,r=s.statusCode>=400;return
|
|
763
|
+
`}renderEventContent(t){switch(t.type){case "fetch":{let s=t.data,r=s.statusCode>=400;return a`
|
|
566
764
|
<span class="tl-event-summary">${s.method} ${s.url}</span>
|
|
567
765
|
<span class="tl-event-status" style="${r?"color:var(--red)":""}">${s.statusCode}</span>
|
|
568
|
-
<span class="tl-event-dur">${
|
|
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=
|
|
766
|
+
<span class="tl-event-dur">${v(s.durationMs)}</span>
|
|
767
|
+
`}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`
|
|
768
|
+
<span class="tl-event-summary"><span style="color:${n};font-weight:600">${r}</span> ${o}</span>
|
|
769
|
+
<span class="tl-event-dur">${_r(s.durationMs)}</span>
|
|
770
|
+
`}case "log":{let s=t.data,r=Ke[s.level]||"var(--text-dim)";return a`<span class="tl-event-summary"><span style="color:${r}">${s.level.toUpperCase()}</span> ${s.message}</span>`}case "error":{let s=t.data;return a`<span class="tl-event-summary" style="color:var(--red)">${s.name}: ${s.message}</span>`}default:return d}}};w.cache=new Map,u([R({context:x})],w.prototype,"store",2),u([T({attribute:"request-id"})],w.prototype,"requestId",2),u([T({attribute:"request-started",type:Number})],w.prototype,"requestStarted",2),u([_()],w.prototype,"data",2),u([_()],w.prototype,"loading",2),u([_()],w.prototype,"failed",2),u([_()],w.prototype,"expandedSqlIdx",2),w=u([g("bk-timeline-panel")],w);var Wt=class{constructor(e,t){this.host=e;this.store=t;this.retryCount=0;e.addController(this);}hostConnected(){this.connect();}hostDisconnected(){this.eventSource?.close(),clearTimeout(this.reloadTimer),clearTimeout(this.perfReloadTimer),clearTimeout(this.reconnectTimer);}connect(){this.eventSource?.close(),this.eventSource=new EventSource(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(k)||(this.store.prependRequest(t),clearTimeout(this.reloadTimer),this.reloadTimer=setTimeout(()=>this.reloadFlows(),300),this.store.state.activeView==="performance"&&(clearTimeout(this.perfReloadTimer),this.perfReloadTimer=setTimeout(()=>this.reloadMetrics(),ue)));},this.eventSource.addEventListener(ee,e=>{this.store.prependFetch(JSON.parse(e.data));}),this.eventSource.addEventListener("log",e=>{this.store.prependLog(JSON.parse(e.data));}),this.eventSource.addEventListener(se,e=>{this.store.prependError(JSON.parse(e.data));}),this.eventSource.addEventListener(re,e=>{this.store.prependQuery(JSON.parse(e.data));}),this.eventSource.addEventListener(oe,e=>{this.store.setIssues(JSON.parse(e.data));});}scheduleReconnect(){if(this.retryCount>=10)return;let e=Math.min(1e3*2**this.retryCount,3e4);this.retryCount++,this.reconnectTimer=setTimeout(()=>this.connect(),e);}async reloadFlows(){try{let t=await(await fetch(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 gs(){return a`<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="7" height="7"/><rect x="14" y="3" width="7" height="7"/><rect x="14" y="14" width="7" height="7"/><rect x="3" y="14" width="7" height="7"/></svg>`}function bs(){return a`<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"/></svg>`}function Es(){return a`<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="2" y1="12" x2="22" y2="12"/><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg>`}function _s(){return a`<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M22 12h-4l-3 9L9 3l-3 9H2"/></svg>`}function Ss(){return a`<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><ellipse cx="12" cy="5" rx="9" ry="3"/><path d="M21 12c0 1.66-4 3-9 3s-9-1.34-9-3"/><path d="M3 5v14c0 1.66 4 3 9 3s9-1.34 9-3V5"/></svg>`}function $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"><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 ys(){return a`<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="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 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"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/></svg>`}function xs(){return a`<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="20" x2="18" y2="10"/><line x1="12" y1="20" x2="12" y2="4"/><line x1="6" y1="20" x2="6" y2="14"/></svg>`}var X=class extends f{constructor(){super(...arguments);this.store=new Gt;this.activeView="overview";this.viewMode="simple";this.sse=new Wt(this,this.store);}createRenderRoot(){return this}connectedCallback(){super.connectedCallback(),this.loadInitialData(),this.store.addEventListener("state-changed",()=>this.requestUpdate());}async loadInitialData(){try{let[t,s]=await Promise.all([fetch(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,h,m]=await Promise.all([t.json(),s.json(),r.json(),o.json(),n.json()]);this.store.setFetches(l.entries),this.store.setErrors(c.entries),this.store.setLogs(p.entries),this.store.setQueries(h.entries),this.store.setMetrics(m.endpoints||[]);}catch(t){console.warn("[brakit]",t);}try{let s=await(await fetch(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(k)),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
771
|
<div class="app" id="app">
|
|
574
772
|
<aside class="sidebar">
|
|
575
773
|
<div class="sidebar-logo">
|
|
576
774
|
<span class="logo-text">brakit</span>
|
|
577
|
-
<span class="logo-version">v${
|
|
775
|
+
<span class="logo-version">v${l?.version??""}</span>
|
|
578
776
|
</div>
|
|
579
777
|
<nav class="sidebar-nav">
|
|
580
|
-
${this.renderSidebarItem("overview","Overview",
|
|
778
|
+
${this.renderSidebarItem("overview","Overview",gs(),void 0)}
|
|
581
779
|
<div class="sidebar-section">Monitor</div>
|
|
582
|
-
${this.renderSidebarItem("actions","Actions",
|
|
583
|
-
${this.renderSidebarItem("requests","Requests",
|
|
584
|
-
${this.renderSidebarItem("fetches","Fetches",
|
|
780
|
+
${this.renderSidebarItem("actions","Actions",bs(),t.flows.length)}
|
|
781
|
+
${this.renderSidebarItem("requests","Requests",Es(),s.length)}
|
|
782
|
+
${this.renderSidebarItem("fetches","Fetches",_s(),t.fetches.length)}
|
|
585
783
|
<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",
|
|
784
|
+
${this.renderSidebarItem("queries","Queries",Ss(),t.queries.length)}
|
|
785
|
+
${this.renderSidebarItem("errors","Errors",$s(),t.errors.length)}
|
|
786
|
+
${this.renderSidebarItem("logs","Logs",ys(),t.logs.length)}
|
|
787
|
+
${this.renderSidebarItem("security","Security",Ts(),n,n===0)}
|
|
788
|
+
${this.renderSidebarItem("performance","Performance",xs(),void 0)}
|
|
591
789
|
</nav>
|
|
592
|
-
<div class="sidebar-footer">:${
|
|
790
|
+
<div class="sidebar-footer">:${l?.port??""}</div>
|
|
593
791
|
</aside>
|
|
594
792
|
<div class="main-panel">
|
|
595
793
|
<div class="header">
|
|
596
794
|
<div class="header-left">
|
|
597
|
-
<span class="header-title" id="header-title">${
|
|
598
|
-
<span class="header-sub" id="header-sub">${
|
|
795
|
+
<span class="header-title" id="header-title">${ie[this.activeView]||this.activeView}</span>
|
|
796
|
+
<span class="header-sub" id="header-sub">${ne[this.activeView]||""}</span>
|
|
599
797
|
</div>
|
|
600
798
|
<div class="header-right">
|
|
601
|
-
${this.activeView==="actions"?
|
|
799
|
+
${this.activeView==="actions"?a`
|
|
602
800
|
<div class="segmented-control" id="mode-toggle">
|
|
603
801
|
<button class="segmented-btn ${this.viewMode==="simple"?"active":""}" @click=${()=>{this.viewMode="simple",this.store.setViewMode("simple");}}>Quick</button>
|
|
604
802
|
<button class="segmented-btn ${this.viewMode==="detailed"?"active":""}" @click=${()=>{this.viewMode="detailed",this.store.setViewMode("detailed");}}>Detailed</button>
|
|
@@ -640,18 +838,18 @@
|
|
|
640
838
|
<span id="stat-total">${s.length} request${s.length!==1?"s":""}</span>
|
|
641
839
|
<span id="stat-flows">${t.flows.length} action${t.flows.length!==1?"s":""}</span>
|
|
642
840
|
<span id="stat-errors" class="error-count">${r} error${r!==1?"s":""}</span>
|
|
643
|
-
<span id="stat-avg">Avg: ${
|
|
841
|
+
<span id="stat-avg">Avg: ${o}ms</span>
|
|
644
842
|
</div>
|
|
645
843
|
</div>
|
|
646
844
|
</div>
|
|
647
845
|
<bk-toast></bk-toast>
|
|
648
|
-
`}renderSidebarItem(t,s,r,
|
|
846
|
+
`}renderSidebarItem(t,s,r,o,n=false){return a`
|
|
649
847
|
<button class="sidebar-item ${this.activeView===t?"active":""}" @click=${()=>this.switchView(t)}>
|
|
650
848
|
<span class="item-icon">${r}</span>
|
|
651
849
|
<span class="item-label">${s}</span>
|
|
652
|
-
${
|
|
850
|
+
${o!==void 0?a`<span class="item-count" style="display:${n?"none":""}">${o}</span>`:d}
|
|
653
851
|
</button>
|
|
654
|
-
`}};u([
|
|
852
|
+
`}};u([be({context:x})],X.prototype,"store",2),u([_()],X.prototype,"activeView",2),u([_()],X.prototype,"viewMode",2),X=u([g("bk-dashboard")],X);
|
|
655
853
|
/*! Bundled license information:
|
|
656
854
|
|
|
657
855
|
@lit/reactive-element/css-tag.js:
|