@lensmcp/core 1.25.17 → 1.25.21
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/lib/flow-shape.d.ts +2 -0
- package/lib/flow-shape.js +1 -1
- package/lib/graph-from-events.js +1 -1
- package/lib/key-pattern.d.ts +10 -0
- package/lib/key-pattern.js +1 -0
- package/lib/redact.d.ts +13 -0
- package/lib/redact.js +1 -1
- package/lib/replay-store.d.ts +24 -0
- package/lib/replay-store.js +1 -0
- package/lib/sql-values.d.ts +50 -0
- package/lib/sql-values.js +1 -0
- package/package.json +17 -2
package/lib/flow-shape.d.ts
CHANGED
|
@@ -78,6 +78,7 @@ export declare function trimFlowEvent(event: BaseEvent, opts?: FlowShapeOptions)
|
|
|
78
78
|
area: FlowArea;
|
|
79
79
|
jobId?: string | undefined;
|
|
80
80
|
queue?: string | undefined;
|
|
81
|
+
valuesId?: string | undefined;
|
|
81
82
|
method?: string;
|
|
82
83
|
/** The route template (`/companies/:id`): the framework's own when it says, else the path with its ids folded. */
|
|
83
84
|
route?: string;
|
|
@@ -149,6 +150,7 @@ export declare function buildFlowDetail(rawEvents: BaseEvent[], opts?: FlowShape
|
|
|
149
150
|
area: FlowArea;
|
|
150
151
|
jobId?: string | undefined;
|
|
151
152
|
queue?: string | undefined;
|
|
153
|
+
valuesId?: string | undefined;
|
|
152
154
|
method?: string;
|
|
153
155
|
/** The route template (`/companies/:id`): the framework's own when it says, else the path with its ids folded. */
|
|
154
156
|
route?: string;
|
package/lib/flow-shape.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var wt=Object.defineProperty;var C=(i,h)=>wt(i,"name",{value:h,configurable:!0});var qt=Object.defineProperty,y=C((i,h)=>qt(i,"name",{value:h,configurable:!0}),"y");import{redactDeep as Mt,redactText as ot,redactUrlParams as It}from"./redact.js";import{templatisePath as pt}from"./route-template.js";import{SQL_ACCOUNT_KIND as xt,sqlAccountingOf as bt}from"./flow-segments.js";import{boundedClone as jt}from"@lensmcp/protocol-types";export function areaOf(i){const{source:h,category:o,title:w,kind:l}=i;return h==="ai"?"ai":l?.startsWith("memory")||l==="db-query"?"data":h==="gateway"||l==="gateway-request"?"gateway":l==="queue-process"||l==="queue-active"||l==="queue-completed"||l==="queue-failed"?"services":h==="db"||h==="redis"||h==="queue"||l==="redis-op"||l?.startsWith("queue-")?"data":h==="external"||l==="egress"?"network":h==="nestjs"||h==="nest"?/(?:Repository|Repo|Dao|Store|EntityManager|DataSource|QueryRunner|OrmClient)\./.test(w)?"data":"services":h==="valtio"?"state":o==="network"?"network":"browser"}C(areaOf,"areaOf"),y(areaOf,"areaOf");const ft=240,St=new Set(["systemPrompt","prompt","prompts","messages","completion","completions","input","output","draft","text","content","result","arguments","params"]),Bt=new Set(["tenantId","caller","userId","accountId","email","subject"]),At=8;function mt(i){const h=tt(i,0);return jt(Mt({redacted:!0,...h}),{rawByteLimit:16*1024}).value}C(mt,"jt"),y(mt,"aiProjection");function tt(i,h){if(typeof i=="string")return ht(i);if(i===null||typeof i!="object")return i;if(h>=At)return;if(Array.isArray(i))return i.slice(0,32).map(w=>tt(w,h+1));const o={};for(const[w,l]of Object.entries(i))if(!Bt.has(w)){if(St.has(w)){typeof l=="string"?o[`${w}Chars`]=l.length:Array.isArray(l)?o[`${w}Count`]=l.length:l!=null&&(o[`${w}Present`]=!0);continue}o[w]=tt(l,h+1)}return o}C(tt,"rt"),y(tt,"projectAi");function ht(i){return i.length<=ft?ot(i):`${ot(i.slice(0,ft))}\u2026`}C(ht,"vt"),y(ht,"clipText");export function httpFacts(i,h){const o=y(M=>typeof M=="string"&&M.length>0?M:void 0,"str"),w=typeof h.status=="number"?h.status:void 0,l=y(M=>It(M.split("?")[0]??M)||"/","pathOf"),D=y((M,$,b={})=>({...M?{method:M.toUpperCase()}:{},...$?{rawPath:$,route:pt($)}:{},...w!==void 0?{status:w}:{},...b}),"facts");if(i==="gateway-request"){const M=o(h.url);return D(o(h.method),M?l(M):void 0,{...o(h.host)?{host:o(h.host)}:{},...o(h.caller)?{caller:o(h.caller)}:{}})}if(i==="egress"){const M=o(h.path),$=o(h.exchangeId);return D(o(h.method)??"GET",M?l(M):void 0,{...o(h.host)?{host:o(h.host)}:{},...$?{exchangeId:$}:{}})}if(i==="fetch-start"||i==="fetch-done"||i==="fetch-error"){const M=o(h.href)??o(h.url);let $,b;if(M)try{const m=new URL(M,"http://relative.invalid");$=l(m.pathname),m.hostname!=="relative.invalid"&&(b=m.hostname)}catch{}return D(o(h.method)??"GET",$,b?{host:b}:{})}if(i==="ai-call")return{...w!==void 0?{status:w}:{},...h.stream===!0?{streamed:!0}:{}};const f=h.request;if(f&&typeof f=="object"){const M=f,$=o(M.route),b=o(M.method);if(!$&&!b)return{};const m=typeof M.status=="number"?M.status:void 0,T=$?l($):void 0;return{...b?{method:b.toUpperCase()}:{},...T?{rawPath:T,route:T.includes(":")?T:pt(T)}:{},...m!==void 0?{status:m}:{}}}return{}}C(httpFacts,"httpFacts"),y(httpFacts,"httpFacts");export function trimFlowEvent(i,h={}){const o=i.raw??{},w=o.render??{},l=o.span??{},D=o.request??{},f=y(u=>typeof u=="number"?u:void 0,"num"),M=o.loop??{},$=o.effect??{},b=f(o.durationMs)??f(l.durationMs)??f(D.durationMs)??f(M.durationMs)??f(w.actualDurationMs)??f($.durationMs),m=typeof o.kind=="string"?o.kind:void 0,T=m==="fetch-done"||m==="fetch-error",_=f(w.commitTime),z=m==="render"&&_!==void 0&&Math.abs(_-i.timestamp)<6e4,et=T?i.timestamp:z?_:f(o.startedAt)??f(l.startTime)??f(D.startedAt)??f(M.startedAt)??(b!==void 0?i.timestamp-b:i.timestamp);let S;if(typeof o.query=="string"){const u=Array.isArray(o.params)?` [${o.params.join(", ")}]`:"",k=typeof o.result=="string"?` \u2192 ${o.result}`:"";S=o.query+u+k}else if(typeof o.command=="string"){const u=typeof o.value=="string"?` \u2192 ${o.value}`:o.hit===!1?" \u2192 (miss)":"";S=o.command+u}else if(m==="state-update"){const u=o.update??{};let k="";try{k=JSON.stringify(u.preview)}catch{}S=`${u.storeId??""}.${u.path??""} = ${k}`}else if(m==="queue-completed"&&typeof o.returned=="string")S=`returned ${o.returned}`;else if(m==="queue-enqueued")S=`${o.job??"job"}#${o.jobId??"?"} \u2192 ${o.queue??""}${typeof o.data=="string"?" "+o.data:""}`;else if(m==="log"){const u=D.error??{},k=typeof u.stack=="string"?u.stack:typeof o.text=="string"?o.text:void 0;k&&k!==i.title&&(S=k)}let P,G,H,Q;if(m==="span"){const u=l.outcome;if(P=u==="threw"||u==="returned"?u:l.status==="error"?"threw":l.status==="ok"?"returned":void 0,P==="threw"){const R=l.error??{},O=typeof R.name=="string"?R.name:void 0,K=typeof R.message=="string"?R.message:typeof i.message=="string"?i.message:void 0;H=O,G=ot([O,K].filter(Boolean).join(": "))||void 0}const k=typeof l.args=="string"?l.args:void 0,A=typeof l.result=="string"?l.result:void 0;if(k!==void 0||A!==void 0){Q=[...k!==void 0?["args"]:[],...A!==void 0?["result"]:[]];const R=y(O=>O.length>gt?`${O.slice(0,gt)}\u2026`:O,"short");S=[k!==void 0?`args ${R(k)}`:"",A!==void 0?`returned ${R(A)}`:""].filter(Boolean).join(" \u2192 ")}}let W;if(m==="gateway-request")W=`${o.host??""}${String(o.url??"").split("?")[0]}`;else if(m==="fetch-start"||m==="fetch-done"||m==="fetch-error")try{const u=new URL(String(o.href??o.url??""));W=`${u.hostname}${u.pathname}`}catch{}let U;if(m==="gateway-request"&&Array.isArray(o.steps))U=o.steps.map(u=>{const k=[String(u.step)];return u.project&&k.push(String(u.project)),u.prefix&&k.push(String(u.prefix)),u.mode&&k.push(String(u.mode)+(u.ok===!1?" \u2717":u.ok===!0?" \u2713":"")),u.caller&&k.push("by "+String(u.caller)),u.pod&&k.push(String(u.pod)),typeof u.atMs=="number"&&k.push(`@${u.atMs}ms`),k.join(" ")}),S=U.map(u=>u.replace(/ @\d+ms$/,"")).join(" \u2192 ");else if(m==="egress")S=`${o.method??"GET"} ${o.host??""} \u2192 ${o.status??"?"}`;else if(i.source==="ai"){if(m==="ai-call"){const u=o.usage??{},k=u.promptTokens!==void 0||u.completionTokens!==void 0?` \xB7 ${f(u.promptTokens)??"?"}\u2192${f(u.completionTokens)??"?"} tok`:"",A=o.status!==void 0?` \xB7 ${String(o.status)}`:o.error?" \xB7 failed":"",R=f(o.toolCallCount)?` \xB7 ${f(o.toolCallCount)} tool call${f(o.toolCallCount)===1?"":"s"}`:"",O=f(o.durationMs)!==void 0?` \xB7 ${(f(o.durationMs)/1e3).toFixed(1)}s`:"";S=`${o.provider??""}/${o.model??"?"}${k}${A}${R}${O}${o.stream===!0?" \xB7 stream":""}`}else if(m==="ai-round"){const u=o.model??{},k=o.usage??{},A=Array.isArray(o.toolCalls)?o.toolCalls:[],R=`${f(k.promptTokens)??"?"}\u2192${f(k.completionTokens)??"?"} tok`,O=A.length?` \xB7 ${A.length} tool call${A.length===1?"":"s"}`:"",K=f(o.durationMs)!==void 0?` \xB7 ${(f(o.durationMs)/1e3).toFixed(1)}s`:"";S=`${u.provider??""}/${u.model??""} \xB7 ${R}${O}${K}`}else if(m==="ai-turn-start"){const u=Array.isArray(o.tools)?o.tools:[];S=`skill ${o.skill??""} \xB7 ${o.output??""}${u.length?" \xB7 tools: "+u.join(", "):""}`}else if(m==="ai-tool-call"){const u=o.call??{},k=o.result??{},A=f(o.durationMs)!==void 0?` \xB7 ${(f(o.durationMs)/1e3).toFixed(1)}s`:"";S=`${u.name??"tool"} ${k.error!=null?"\u2717 "+String(k.error):"\u2713"}${A}`}else if(m==="ai-turn-end"){const u=o.usage??{},k=f(o.rounds)!==void 0?` \xB7 ${f(o.rounds)} round${f(o.rounds)===1?"":"s"}`:"",A=f(o.durationMs)!==void 0?` \xB7 ${(f(o.durationMs)/1e3).toFixed(1)}s`:"";S=`${o.ok===!1?"FAILED":"ok"} \xB7 ${f(u.promptTokens)??"?"}+${f(u.completionTokens)??"?"} tok${k}${A}`}}let L;m==="db-query"&&typeof o.query=="string"?L=o.query:m==="redis-op"?L=`${o.op??""} ${String(o.key??"").replace(/\d+/g,"#")}`:m==="egress"?L=`${o.method??"GET"} ${o.host??""}`:m==="ai-call"?L=`ai ${o.provider??""} ${o.model??""} ${o.api??""}`:m==="queue-enqueued"?L=`enqueue ${o.queue??""}`:m==="span"&&typeof l.name=="string"?L=l.name:m==="memory-mutation"&&(L=i.title);const N=i.context??{},q=w.commitId??$.commitId??o.commitId,V=Array.isArray(w.why)?w.why.map(u=>typeof u?.type=="string"?u.type:void 0).filter(u=>!!u):[];return{id:i.id,t:i.timestamp,start:et,...L?{sig:L}:{},...W?{urlKey:W}:{},...httpFacts(m,o),...typeof o.queue=="string"?{queue:o.queue}:{},...o.jobId!=null?{jobId:String(o.jobId)}:{},source:i.source,category:i.category,severity:i.severity,title:P==="threw"&&typeof l.name=="string"?`${l.name} \u2014 threw${H?` ${H}`:""}${b!==void 0?` after ${b}ms`:""}`:i.title,kind:m,area:areaOf({source:i.source,category:i.category,title:i.title,kind:m}),...P?{outcome:P}:{},...G?{error:G}:{},...Q?{captured:Q}:{},...typeof l.role=="string"?{role:l.role}:{},...typeof l.spanId=="string"?{spanId:l.spanId}:{},...typeof l.parentSpanId=="string"?{parentSpanId:l.parentSpanId}:{},...m==="log"&&typeof o.level=="string"?{level:o.level}:{},...m==="log"&&typeof o.logger=="string"?{logger:o.logger}:{},...m==="log"&&typeof o.stream=="string"?{stream:o.stream}:{},...typeof N.requestId=="string"?{requestId:N.requestId}:{},...typeof N.parentRequestId=="string"?{parentRequestId:N.parentRequestId}:{},...typeof q=="string"?{commitId:q}:{},...typeof w.componentName=="string"?{component:w.componentName}:{},...typeof w.phase=="string"?{phase:w.phase}:{},...V.length?{why:V}:{},...m==="effect-run"&&typeof $.hookLogicalId=="string"?{hook:$.hookLogicalId}:{},...m==="effect-run"&&$.cleanupRan===!0?{cleanup:!0}:{},...m==="render-commit-truncated"?{renderTotal:f(o.total),renderPublished:f(o.published),...f(o.walkStoppedAt)!==void 0?{renderWalkStoppedAt:f(o.walkStoppedAt)}:{}}:{},...typeof N.projectName=="string"?{project:N.projectName}:typeof o.project=="string"?{project:o.project}:{},...b!==void 0?{durationMs:b}:{},...T&&f(o.startedAt)!==void 0?{fetchStartedAt:f(o.startedAt)}:{},...i.source==="ai"?{ai:h.includeRaw?o:mt(o)}:{},...S?{detail:S}:{},...U?{steps:U}:{}}}C(trimFlowEvent,"trimFlowEvent"),y(trimFlowEvent,"trimFlowEvent");const gt=300;export const OUTLIVED_PARENT_MIN_MS=250;const Rt=new Set(["egress","db-query","redis-op","ai-call","span","gateway-request","server-request"]),$t=1;function yt(i){return i==="flow-origin"?0:i?.endsWith("-start")?1:i==="gateway-request"?2:i==="server-request"?3:i==="span"?4:i==="render"||i==="render-commit-truncated"?6:i==="effect-run"?7:5}C(yt,"Rt"),y(yt,"kindRank");function J(i){return i.kind==="span"&&i.role==="controller"?3.5:i.kind==="queue-process"?3:yt(i.kind)}C(J,"Z"),y(J,"causalRank");export function buildFlowDetail(i,h={}){const o=bt(i),w=i.slice().filter(t=>{const r=t.raw??{},e=typeof r.kind=="string"?r.kind:"";if(e==="subscription-added"||e==="subscription-removed"||e==="hook-run"||e==="store-created"||e==="singleton-instance"||e===xt)return!1;const n=r.span;return!(typeof n?.name=="string"&&n.name.startsWith("nest.request "))}).map(t=>trimFlowEvent(t,h)),l=new Set;for(let t=w.length-1;t>=0;t--)l.has(w[t].id)?w.splice(t,1):l.add(w[t].id);const D=new Map;for(const t of w)(t.kind==="gateway-request"||t.kind==="queue-process")&&t.requestId&&!D.has(t.requestId)&&D.set(t.requestId,t.start);const f=y(t=>t.source!=="react"&&t.source!=="valtio"&&t.requestId&&D.has(t.requestId)?D.get(t.requestId):t.start,"anchorOf");w.sort((t,r)=>f(t)-f(r)||t.start-r.start||J(t)-J(r)||(r.durationMs??0)-(t.durationMs??0)||t.t-r.t);const M=y(t=>(t.kind==="span"||t.kind==="server-request"||t.kind==="gateway-request"||t.kind==="queue-process")&&(t.durationMs??0)>0,"spanLike"),$=w;for(const t of $)t.group=t.source==="react"||t.source==="valtio"||t.source==="client-runtime"||t.source==="visual"?"browser":"server";const b=new Map;for(const t of $)if((t.kind==="gateway-request"||t.kind==="queue-process")&&t.requestId&&t.project){const r=b.get(t.requestId)??[];r.push({project:t.project,start:t.start,end:t.start+(t.durationMs??0)}),b.set(t.requestId,r)}const m=y((t,r)=>{const e=b.get(t);if(e?.length)return e.every(n=>n.project===e[0].project)?e[0].project:e.filter(n=>n.start<=r+1&&n.end>=r-1).sort((n,s)=>s.start-n.start)[0]?.project},"projectOf");for(const t of $)if(!t.project&&t.source==="nestjs"&&t.requestId){const r=m(t.requestId,t.start);r&&(t.project=r)}const T=new Map;for(const t of $)t.spanId&&T.set(t.spanId,t);const _=y((t,r)=>{let e=t.parentSpanId?T.get(t.parentSpanId):void 0;for(let n=0;e&&n<64;n++){if(e===r)return!0;e=e.parentSpanId?T.get(e.parentSpanId):void 0}return!1},"inside");for(const t of $){const r=t.parentSpanId?T.get(t.parentSpanId):void 0;if(r&&r!==t&&r.group===t.group&&r.requestId===t.requestId){t.parent=r.id;continue}let e;const n=t.requestId;for(const s of $){if(s===t||!M(s)||s.group!==t.group||s.requestId!==n)continue;const a=s.project,g=t.project;if(s.kind!=="gateway-request"&&t.kind!=="gateway-request"&&a!==void 0&&g!==void 0&&a!==g)continue;const v=s.durationMs??0,d=t.durationMs??0,c=Math.abs(s.start-t.start)<=$t,p=J(s),I=J(t),B=s.start<=t.start;if(!(s.start+v>t.start&&(B||c&&p<I)&&(!c||(p!==I?p<I:B&&v>d))))continue;const x=e?J(e):-1,E=e?Math.abs(s.start-e.start)<=$t:!1,F=e&&E&&p===x?_(s,e)?1:_(e,s)?-1:0:0;(!e||!E&&s.start>e.start||E&&p>x||F>0||F===0&&E&&p===x&&(s.durationMs??0)<(e.durationMs??0))&&(e=s)}e&&(t.parent=e.id)}for(const t of $)delete t.spanId,delete t.parentSpanId;{const t=new Set($.map(a=>a.id)),r=new Set,e=new Map,n=[],s=y(a=>{const g=[a];for(;g.length;){const v=g.pop();n.push(v),r.add(v.id);const d=e.get(v.id);if(d){e.delete(v.id);for(let c=d.length-1;c>=0;c--)g.push(d[c])}}},"place");for(const a of $)if(a.parent&&a.parent!==a.id&&t.has(a.parent)&&!r.has(a.parent)){const g=e.get(a.parent)??[];g.push(a),e.set(a.parent,g)}else s(a);for(const a of $)r.has(a.id)||(n.push(a),r.add(a.id));for(let a=0;a<n.length;a++)$[a]=n[a]}const z=new Map;for(const t of $){if(!t.requestId)continue;const r=z.get(t.requestId);r?r.push(t):z.set(t.requestId,[t])}const et=new Map($.map(t=>[t.id,t])),S=y((t,r)=>{const e=(z.get(t)??[]).filter(n=>M(n)&&n.start<=r&&n.start+(n.durationMs??0)>=r);if(e.length!==0)return e.sort((n,s)=>s.start-n.start||(n.durationMs??0)-(s.durationMs??0)),e[0]},"callerNodeFor");for(const t of $){if(!t.parentRequestId||t.kind!=="server-request"&&t.kind!=="gateway-request")continue;const r=t.parent?et.get(t.parent):void 0;if(r&&r.requestId===t.requestId)continue;const e=S(t.parentRequestId,t.start);e&&e!==t&&e.start<=t.start&&(t.parent=e.id)}const P=$,G=new Map;for(const t of P)t.kind==="gateway-request"&&t.requestId&&!G.has(t.requestId)&&G.set(t.requestId,t);for(const t of P)if(t.group==="server"&&!t.parent&&t.requestId&&t.kind!=="gateway-request"){const r=G.get(t.requestId);r&&r!==t&&r.start<=t.start&&(t.parent=r.id)}const H=new Set,Q=new Set,W=[];for(const t of P){if(t.kind!=="gateway-request")continue;if(!t.requestId){W.push(t);continue}const r=z.get(t.requestId)??[];if(r.filter(s=>s.kind==="gateway-request").sort((s,a)=>s.start-a.start)[0]!==t)continue;const e=r.find(s=>s.kind==="fetch-start"),n=r.find(s=>s.kind==="fetch-done"||s.kind==="fetch-error");if(!e&&!n){W.push(t);continue}e&&(t.fetchStartId=e.id,H.add(e.id)),n&&(t.fetchDoneId=n.id,Q.add(n.id))}const U=new Map;for(const t of P){if(!t.urlKey)continue;const r=U.get(t.urlKey)??{gws:[],starts:[],dones:[]};t.kind==="gateway-request"?W.includes(t)&&r.gws.push(t):t.kind==="fetch-start"?H.has(t.id)||r.starts.push(t):(t.kind==="fetch-done"||t.kind==="fetch-error")&&(Q.has(t.id)||r.dones.push(t)),U.set(t.urlKey,r)}for(const{gws:t,starts:r,dones:e}of U.values()){t.sort((s,a)=>s.start-a.start),r.sort((s,a)=>s.start-a.start);const n=new Set;t.forEach((s,a)=>{const g=r[a];g&&(s.fetchStartId=g.id);const v=g?g.t:s.start;let d,c=1/0;for(const p of e){if(n.has(p.id))continue;const I=p.fetchStartedAt??p.start-(p.durationMs??0),B=Math.abs(I-v);B<c&&(c=B,d=p)}d&&(s.fetchDoneId=d.id,n.add(d.id))})}const L=new Map,N=new Map;for(const t of P)!t.queue||!t.jobId||(t.kind==="queue-enqueued"&&L.set(`${t.queue}#${t.jobId}`,t),t.kind==="queue-process"&&N.set(`${t.queue}#${t.jobId}`,t));for(const t of P){if(!t.queue||!t.jobId)continue;const r=`${t.queue}#${t.jobId}`;if(t.kind==="queue-process"&&!t.parent){const e=L.get(r);e&&e!==t&&e.start<=t.start&&(t.parent=e.id)}else if(t.kind==="queue-active"||t.kind==="queue-completed"||t.kind==="queue-failed"){const e=N.get(r);e&&e!==t&&e.start<=t.start&&(t.parent=e.id)}}{const t=new Map($.map(r=>[r.id,r]));for(const r of $){if(!r.parent||!Rt.has(r.kind??"")||r.durationMs===void 0)continue;const e=t.get(r.parent);if(!e||e.kind!=="span"||!((e.durationMs??0)>0))continue;const n=Math.round(r.start+r.durationMs-(e.start+e.durationMs));if(n<OUTLIVED_PARENT_MIN_MS)continue;r.outlivedParentMs=n;const s=e.leftRunning??{count:0,longestMs:0};e.leftRunning={count:s.count+1,longestMs:Math.max(s.longestMs,n)}}for(const r of $){const e=[];r.leftRunning&&e.push(`ended before ${r.leftRunning.count===1?"a call":`${r.leftRunning.count} calls`} it started had finished \u2014 ${r.leftRunning.count===1?"it":"the longest"} ran on ${r.leftRunning.longestMs}ms (a timeout that gave up, or work not awaited)`),r.outlivedParentMs!==void 0&&e.push(`ran on ${r.outlivedParentMs}ms after the span that started it had ended`),e.length>0&&(r.detail=[r.detail,...e].filter(Boolean).join(" \xB7 "))}}let q=$;{const t=new Map;for(const e of q)e.kind==="fetch-start"&&t.set(e.id,e);const r=new Map;for(const e of q){if(e.kind!=="fetch-done"&&e.kind!=="fetch-error")continue;const n=[...t.values()].find(g=>g.requestId&&g.requestId===e.requestId)?.id,s=n?t.get(n):void 0;if(!s)continue;const a=e.fetchStartedAt??s.start;s.title=e.title,s.severity=e.severity,s.durationMs=e.durationMs??Math.max(0,e.t-a),s.kind="fetch",e.detail&&!s.detail&&(s.detail=e.detail),r.set(e.id,s.id)}if(r.size>0){q=q.filter(e=>!r.has(e.id));for(const e of q)for(e.fetchDoneId&&r.has(e.fetchDoneId)&&(e.fetchDoneId=r.get(e.fetchDoneId));e.parent&&r.has(e.parent);)e.parent=r.get(e.parent)}}const V=y(t=>!!t.commitId&&(t.kind==="render"||t.kind==="effect-run"||t.kind==="render-commit-truncated"),"commitMember"),u=y(t=>[...new Set(t)],"uniq"),k=y(t=>u(t.map(r=>r.component).filter(r=>!!r)),"named"),A=y(t=>t.length<=2?t.join(" + "):`${t[0]} + ${t.length-1} more`,"nameList"),R=y(t=>{const r=new Map;for(const e of t)e.component&&r.set(e.component,(r.get(e.component)??0)+1);return[...r].map(([e,n])=>n>1?`${e} \xD7${n}`:e).join(", ")},"tally"),O=y(t=>{if(!t)return"effect";const r=/([^/\\]+?):(\d+)(?::\d+)?$/.exec(t);return r?`${r[1]}:${r[2]}`:t},"shortHook"),K=y(t=>`${O(t.hook)}${t.cleanup?" (cleanup)":""}`,"hookLabel"),nt=y(t=>{const r=Math.min(...t.map(n=>n.start)),e=Math.max(...t.map(n=>n.start+(n.durationMs??0)));return{start:r,durationMs:e-r}},"extent"),st=y(t=>(delete t.component,delete t.why,delete t.phase,delete t.hook,delete t.cleanup,delete t.renderTotal,delete t.renderPublished,t),"asGroup");function at(t){const r=t[0],e=t.filter(j=>j.kind==="render"),n=t.filter(j=>j.kind==="effect-run"),s=t.find(j=>j.kind==="render-commit-truncated"),a=[...e].sort((j,Y)=>(Y.durationMs??0)-(j.durationMs??0)),g=a.filter(j=>(j.why??[]).some(Y=>Y!=="parent-render")),v=u(g.flatMap(j=>(j.why??[]).filter(Y=>Y!=="parent-render"))),d=k(g),c=e.filter(j=>j.phase==="mount"),p=e.filter(j=>j.phase!=="mount"&&!g.includes(j)),I=a[0]?.component??"view",B=e.length>0&&c.length===e.length,x=v.length?v.join(" + "):void 0,E=B?"mount":"update",F=d.length?`view update \xB7 ${A(d)} \u2190 ${x}`:B?`view mount \xB7 ${I}`:`view update \xB7 ${I}`,rt=s?.renderTotal??e.length,kt=[c.length?`mounted ${R(c)}`:"",p.length?`re-rendered ${R(p)}`:"",!d.length&&!B&&e.length?"trigger not recorded \u2014 every captured render came from its parent":"",s?.renderWalkStoppedAt!==void 0?`at least ${rt} renders (the walk stopped at ${s.renderWalkStoppedAt} fibers), ${s.renderPublished??e.length} recorded`:s?`${rt} renders, ${s.renderPublished??e.length} recorded (per-commit cap)`:`${e.length} render${e.length===1?"":"s"}`,n.length?`${n.length} effect${n.length===1?"":"s"}: ${n.map(K).join(", ")}`:""].filter(Boolean).join(" \xB7 "),lt=k(e);return st({...r,...nt(t),kind:"view-update",title:F,detail:kt,commitId:r.commitId,viewPhase:E,...x?{cause:x}:{},causeComponents:d,components:lt,mounted:k(c),renderCount:rt,...s?.renderWalkStoppedAt!==void 0?{renderCountAtLeast:!0}:{},recordedRenders:e.length,effects:n.length,effectHooks:n.map(K),memberIds:t.map(j=>j.id),sig:`commit:${E}:${x??"-"}:${d.join(",")}:${lt.slice().sort().join(",")}`,severity:t.some(j=>j.severity==="error")?"error":r.severity})}C(at,"pt"),y(at,"viewUpdateNode");function it(t){const r=t[0],e=t.map(K);return st({...r,...nt(t),kind:"commit-effects",title:t.length===1?`effect \xB7 ${e[0]}`:`effects \xB7 ${e[0]} + ${t.length-1} more`,detail:e.join(", "),commitId:r.commitId,effects:t.length,effectHooks:e,memberIds:t.map(n=>n.id),sig:`effects:${e.slice().sort().join(",")}`})}C(it,"mt"),y(it,"effectsNode");const vt=y(t=>u(t.map(r=>r==="state-update"?"state update":r==="fetch-start"?"request":r==="flow-origin"?"interaction":"response")).join(" + "),"describeInputs");function dt(t,r){const e=t[0],n=t[t.length-1],s=t.length,a=e.detail,g=Math.min(...t.map(p=>p.start)),v=Math.max(...t.map(p=>p.start+(p.durationMs??0))),d=Math.round(t.reduce((p,I)=>p+(I.durationMs??0),0)/s*10)/10,c=Math.round((v-g)*10)/10;e.count=s,e.avgMs=d,e.wallMs=c,e.durationMs=v-g,e.items=t.slice(0,12).map(p=>({start:p.start-g,...p.durationMs!=null?{durationMs:p.durationMs}:{}})),e.memberIds=t.flatMap(p=>p.memberIds??[p.id]),e.title=`\xD7${s} ${e.title}`,t.some(p=>p.severity==="error")&&(e.severity="error"),e.kind==="view-update"?e.detail=[`${s} commits, ${r.length?`one per ${vt(r)}`:"back to back"}`,`avg ${d}ms \xB7 wall ${c}ms`,a??""].filter(Boolean).join(" \xB7 "):e.kind==="state-update"&&a&&n.detail?e.detail=`${s} updates in a row \xB7 wall ${c}ms \xB7 first ${a} \xB7 last ${n.detail}`:e.detail=[`${s} in a row \xB7 wall ${c}ms`,a??""].filter(Boolean).join(" \xB7 ")}C(dt,"ht"),y(dt,"collapseRepeat");const Z=[],X=new Map,ut=new Set;for(let t=0;t<q.length;t++){if(ut.has(t))continue;const r=q[t];if(!V(r)){Z.push(r);continue}const e=[t];for(let a=t+1;a<q.length;a++){const g=q[a];if(g.group==="browser"){if(!V(g)||g.commitId!==r.commitId)break;e.push(a)}}for(const a of e)ut.add(a);const n=e.map(a=>q[a]),s=n.some(a=>a.kind!=="effect-run")?at(n):it(n);for(const a of n)a.id!==s.id&&X.set(a.id,s.id);Z.push(s)}if(X.size>0||Z.some(t=>t.kind==="view-update"||t.kind==="commit-effects")){q=Z;for(const t of q)for(;t.parent&&X.has(t.parent);)t.parent=X.get(t.parent)}{const t=new Map;for(const r of q)r.kind==="view-update"&&r.commitId&&!t.has(r.commitId)&&t.set(r.commitId,r);for(const r of q){if(r.kind!=="commit-effects"||r.parent||!r.commitId)continue;const e=t.get(r.commitId);e&&e.start<=r.start&&(r.parent=e.id)}}{const t=new Set(["state-update","fetch","fetch-start","fetch-done","fetch-error","flow-origin"]),r=q.map((d,c)=>d.group==="browser"?c:-1).filter(d=>d>=0),e=y(d=>`${d.kind}|${d.sig??d.title}`,"keyOf"),n=r.map(d=>e(q[d])),s=y((d,c,p)=>{for(let I=0;I<p;I++)if(n[d+I]!==n[c+I])return!1;return!0},"sameBlock"),a=y(d=>n[d].split("|")[0],"kindAt"),g=y(d=>{let c=0,p=1;for(let I=1;I<=4&&d+I<=n.length;I++){let B=1;for(;d+(B+1)*I<=n.length&&s(d,d+B*I,I);)B+=1;B>=3&&I*B>c*p&&(c=I,p=B)}return{k:c,r:p}},"bestBlockAt"),v=new Map;for(let d=0;d<n.length;){const{k:c,r:p}=g(d);if(c===0){d+=1;continue}const I=[...Array(c).keys()].find(x=>t.has(a(d+x)));if(I!==void 0&&I>0){const x=g(d+I);if(x.k===c&&x.r>=3&&x.r>=p-1){d+=I;continue}}const B=n.slice(d,d+c).map(x=>x.split("|")[0]).filter(x=>t.has(x));for(let x=0;x<c;x++){const E=[];for(let F=0;F<p;F++)E.push(q[r[d+x+F*c]]);dt(E,B);for(const F of E.slice(1))v.set(F.id,E[0].id)}d+=c*p}if(v.size>0){q=q.filter(d=>!v.has(d.id));for(const d of q)for(;d.parent&&v.has(d.parent);)d.parent=v.get(d.parent)}}{const t=new Map(q.map(r=>[r.id,r]));for(const r of q){const e=new Set([r.id]);let n=r;for(;n?.parent;){if(e.has(n.parent)){n.parent=void 0;break}e.add(n.parent),n=t.get(n.parent)}}}const ct=y(t=>{const r=new Map;for(const n of q){if(!n.sig||M(n)!==t||n.kind==="server-request"||n.kind==="gateway-request"||n.group==="browser")continue;const s=`${n.parent??"root"}|${n.kind}|${n.sig}`,a=r.get(s);a?a.push(n):r.set(s,[n])}const e=new Map;for(const n of r.values()){if(n.length<3)continue;n.sort((c,p)=>c.start-p.start);const s=n[0];let a=!1;for(let c=0;c+1<n.length;c++)if(n[c+1].start<n[c].start+(n[c].durationMs??0)){a=!0;break}const g=s.start,v=Math.max(...n.map(c=>c.start+(c.durationMs??0))),d=n.reduce((c,p)=>c+(p.durationMs??0),0);s.count=n.length,s.parallel=a,s.avgMs=Math.round(d/n.length*10)/10,s.wallMs=v-g,s.durationMs=v-g,s.title=`\xD7${n.length} ${s.title.replace(/\s*\((?:\d+ rows?, )?\d+ms\)$/,"")}`,s.detail=`${s.sig} \xD7${n.length} ${a?"\u2016 parallel":"\u21BB sequential loop"} \xB7 avg ${s.avgMs}ms \xB7 wall ${s.wallMs}ms`,s.items=n.slice(0,12).map(c=>({start:c.start-g,...c.durationMs!=null?{durationMs:c.durationMs}:{}})),s.memberIds=n.flatMap(c=>c.memberIds??[c.id]),n.some(c=>c.severity==="error")&&(s.severity="error");for(const c of n.slice(1))e.set(c.id,s.id)}if(e.size!==0){q=q.filter(n=>!e.has(n.id));for(const n of q)for(;n.parent&&e.has(n.parent);)n.parent=e.get(n.parent)}},"aggregatePass");ct(!0),ct(!1);for(const t of q){if(!M(t))continue;const r=t.durationMs??0;if(r<40)continue;const e=q.filter(v=>v.parent===t.id&&(v.durationMs??0)>0).map(v=>[v.start,v.start+(v.durationMs??0)]).sort((v,d)=>v[0]-d[0]);let n=0,s=-1,a=-1;for(const[v,d]of e)v>a?(a>s&&(n+=a-s),s=v,a=d):d>a&&(a=d);a>s&&(n+=a-s);const g=Math.max(0,r-n);(g>=50||g/r>=.7&&r>=40)&&(t.selfMs=g,t.detail=`\u26A0 cpu-heavy: ${g}ms self-time of ${r}ms${t.detail?" \xB7 "+t.detail:""}`)}return{events:q,...o?{sql:o}:{}}}C(buildFlowDetail,"buildFlowDetail"),y(buildFlowDetail,"buildFlowDetail");
|
|
1
|
+
"use strict";var qt=Object.defineProperty;var C=(i,h)=>qt(i,"name",{value:h,configurable:!0});var wt=Object.defineProperty,v=C((i,h)=>wt(i,"name",{value:h,configurable:!0}),"$");import{redactDeep as Mt,redactText as ot,redactUrlParams as It}from"./redact.js";import{templatisePath as pt}from"./route-template.js";import{SQL_ACCOUNT_KIND as bt,sqlAccountingOf as xt}from"./flow-segments.js";import{boundedClone as jt}from"@lensmcp/protocol-types";export function areaOf(i){const{source:h,category:o,title:q,kind:c}=i;return h==="ai"?"ai":c?.startsWith("memory")||c==="db-query"?"data":h==="gateway"||c==="gateway-request"?"gateway":c==="queue-process"||c==="queue-active"||c==="queue-completed"||c==="queue-failed"?"services":h==="db"||h==="redis"||h==="queue"||c==="redis-op"||c?.startsWith("queue-")||h==="fs"||c==="fs-ops"?"data":h==="exec"||c==="exec"?"services":h==="external"||c==="egress"?"network":h==="nestjs"||h==="nest"?/(?:Repository|Repo|Dao|Store|EntityManager|DataSource|QueryRunner|OrmClient)\./.test(q)?"data":"services":h==="valtio"?"state":o==="network"?"network":"browser"}C(areaOf,"areaOf"),v(areaOf,"areaOf");const ft=240,St=new Set(["systemPrompt","prompt","prompts","messages","completion","completions","input","output","draft","text","content","result","arguments","params"]),Bt=new Set(["tenantId","caller","userId","accountId","email","subject"]),At=8;function mt(i){const h=tt(i,0);return jt(Mt({redacted:!0,...h}),{rawByteLimit:16*1024}).value}C(mt,"vt"),v(mt,"aiProjection");function tt(i,h){if(typeof i=="string")return ht(i);if(i===null||typeof i!="object")return i;if(h>=At)return;if(Array.isArray(i))return i.slice(0,32).map(q=>tt(q,h+1));const o={};for(const[q,c]of Object.entries(i))if(!Bt.has(q)){if(St.has(q)){typeof c=="string"?o[`${q}Chars`]=c.length:Array.isArray(c)?o[`${q}Count`]=c.length:c!=null&&(o[`${q}Present`]=!0);continue}o[q]=tt(c,h+1)}return o}C(tt,"rt"),v(tt,"projectAi");function ht(i){return i.length<=ft?ot(i):`${ot(i.slice(0,ft))}\u2026`}C(ht,"jt"),v(ht,"clipText");export function httpFacts(i,h){const o=v(M=>typeof M=="string"&&M.length>0?M:void 0,"str"),q=typeof h.status=="number"?h.status:void 0,c=v(M=>It(M.split("?")[0]??M)||"/","pathOf"),D=v((M,y,x={})=>({...M?{method:M.toUpperCase()}:{},...y?{rawPath:y,route:pt(y)}:{},...q!==void 0?{status:q}:{},...x}),"facts");if(i==="gateway-request"){const M=o(h.url);return D(o(h.method),M?c(M):void 0,{...o(h.host)?{host:o(h.host)}:{},...o(h.caller)?{caller:o(h.caller)}:{}})}if(i==="egress"){const M=o(h.path),y=o(h.exchangeId);return D(o(h.method)??"GET",M?c(M):void 0,{...o(h.host)?{host:o(h.host)}:{},...y?{exchangeId:y}:{}})}if(i==="fetch-start"||i==="fetch-done"||i==="fetch-error"){const M=o(h.href)??o(h.url);let y,x;if(M)try{const p=new URL(M,"http://relative.invalid");y=c(p.pathname),p.hostname!=="relative.invalid"&&(x=p.hostname)}catch{}return D(o(h.method)??"GET",y,x?{host:x}:{})}if(i==="ai-call")return{...q!==void 0?{status:q}:{},...h.stream===!0?{streamed:!0}:{}};const g=h.request;if(g&&typeof g=="object"){const M=g,y=o(M.route),x=o(M.method);if(!y&&!x)return{};const p=typeof M.status=="number"?M.status:void 0,R=y?c(y):void 0;return{...x?{method:x.toUpperCase()}:{},...R?{rawPath:R,route:R.includes(":")?R:pt(R)}:{},...p!==void 0?{status:p}:{}}}return{}}C(httpFacts,"httpFacts"),v(httpFacts,"httpFacts");export function trimFlowEvent(i,h={}){const o=i.raw??{},q=o.render??{},c=o.span??{},D=o.request??{},g=v(d=>typeof d=="number"?d:void 0,"num"),M=o.loop??{},y=o.effect??{},x=g(o.durationMs)??g(c.durationMs)??g(D.durationMs)??g(M.durationMs)??g(q.actualDurationMs)??g(y.durationMs),p=typeof o.kind=="string"?o.kind:void 0,R=p==="fetch-done"||p==="fetch-error",_=g(q.commitTime),z=p==="render"&&_!==void 0&&Math.abs(_-i.timestamp)<6e4,et=R?i.timestamp:z?_:g(o.startedAt)??g(c.startTime)??g(D.startedAt)??g(M.startedAt)??(x!==void 0?i.timestamp-x:i.timestamp);let j;if(typeof o.query=="string"){const d=Array.isArray(o.params)?` [${o.params.join(", ")}]`:"",f=typeof o.result=="string"?` \u2192 ${o.result}`:"";j=o.query+d+f}else if(typeof o.command=="string"){const d=typeof o.value=="string"?` \u2192 ${o.value}`:o.hit===!1?" \u2192 (miss)":"";j=o.command+d}else if(p==="state-update"){const d=o.update??{};let f="";try{f=JSON.stringify(d.preview)}catch{}j=`${d.storeId??""}.${d.path??""} = ${f}`}else if(p==="fs-ops"&&Array.isArray(o.paths))j=o.paths.slice(0,8).map(d=>{const f=d??{},B=typeof f.n=="number"&&f.n>1?` \xD7${f.n}`:"",T=typeof f.bytes=="number"&&f.bytes>0?` (${f.bytes>=1024?`${(f.bytes/1024).toFixed(1)} KB`:`${f.bytes} B`})`:"";return`${String(f.op??"?")} ${String(f.path??"?")}${B}${T}`}).join(" \xB7 ");else if(p==="exec"&&typeof o.cmd=="string")j=`${o.cmd} \u2192 ${o.code??o.signal??o.error??"?"}`;else if(p==="queue-completed"&&typeof o.returned=="string")j=`returned ${o.returned}`;else if(p==="queue-enqueued")j=`${o.job??"job"}#${o.jobId??"?"} \u2192 ${o.queue??""}${typeof o.data=="string"?" "+o.data:""}`;else if(p==="log"){const d=D.error??{},f=typeof d.stack=="string"?d.stack:typeof o.text=="string"?o.text:void 0;f&&f!==i.title&&(j=f)}let P,G,H,Q;if(p==="span"){const d=c.outcome;if(P=d==="threw"||d==="returned"?d:c.status==="error"?"threw":c.status==="ok"?"returned":void 0,P==="threw"){const T=c.error??{},L=typeof T.name=="string"?T.name:void 0,K=typeof T.message=="string"?T.message:typeof i.message=="string"?i.message:void 0;H=L,G=ot([L,K].filter(Boolean).join(": "))||void 0}const f=typeof c.args=="string"?c.args:void 0,B=typeof c.result=="string"?c.result:void 0;if(f!==void 0||B!==void 0){Q=[...f!==void 0?["args"]:[],...B!==void 0?["result"]:[]];const T=v(L=>L.length>gt?`${L.slice(0,gt)}\u2026`:L,"short");j=[f!==void 0?`args ${T(f)}`:"",B!==void 0?`returned ${T(B)}`:""].filter(Boolean).join(" \u2192 ")}}let U;if(p==="gateway-request")U=`${o.host??""}${String(o.url??"").split("?")[0]}`;else if(p==="fetch-start"||p==="fetch-done"||p==="fetch-error")try{const d=new URL(String(o.href??o.url??""));U=`${d.hostname}${d.pathname}`}catch{}let W;if(p==="gateway-request"&&Array.isArray(o.steps))W=o.steps.map(d=>{const f=[String(d.step)];return d.project&&f.push(String(d.project)),d.prefix&&f.push(String(d.prefix)),d.mode&&f.push(String(d.mode)+(d.ok===!1?" \u2717":d.ok===!0?" \u2713":"")),d.caller&&f.push("by "+String(d.caller)),d.pod&&f.push(String(d.pod)),typeof d.atMs=="number"&&f.push(`@${d.atMs}ms`),f.join(" ")}),j=W.map(d=>d.replace(/ @\d+ms$/,"")).join(" \u2192 ");else if(p==="egress")j=`${o.method??"GET"} ${o.host??""} \u2192 ${o.status??"?"}`;else if(i.source==="ai"){if(p==="ai-call"){const d=o.usage??{},f=d.promptTokens!==void 0||d.completionTokens!==void 0?` \xB7 ${g(d.promptTokens)??"?"}\u2192${g(d.completionTokens)??"?"} tok`:"",B=o.status!==void 0?` \xB7 ${String(o.status)}`:o.error?" \xB7 failed":"",T=g(o.toolCallCount)?` \xB7 ${g(o.toolCallCount)} tool call${g(o.toolCallCount)===1?"":"s"}`:"",L=g(o.durationMs)!==void 0?` \xB7 ${(g(o.durationMs)/1e3).toFixed(1)}s`:"";j=`${o.provider??""}/${o.model??"?"}${f}${B}${T}${L}${o.stream===!0?" \xB7 stream":""}`}else if(p==="ai-round"){const d=o.model??{},f=o.usage??{},B=Array.isArray(o.toolCalls)?o.toolCalls:[],T=`${g(f.promptTokens)??"?"}\u2192${g(f.completionTokens)??"?"} tok`,L=B.length?` \xB7 ${B.length} tool call${B.length===1?"":"s"}`:"",K=g(o.durationMs)!==void 0?` \xB7 ${(g(o.durationMs)/1e3).toFixed(1)}s`:"";j=`${d.provider??""}/${d.model??""} \xB7 ${T}${L}${K}`}else if(p==="ai-turn-start"){const d=Array.isArray(o.tools)?o.tools:[];j=`skill ${o.skill??""} \xB7 ${o.output??""}${d.length?" \xB7 tools: "+d.join(", "):""}`}else if(p==="ai-tool-call"){const d=o.call??{},f=o.result??{},B=g(o.durationMs)!==void 0?` \xB7 ${(g(o.durationMs)/1e3).toFixed(1)}s`:"";j=`${d.name??"tool"} ${f.error!=null?"\u2717 "+String(f.error):"\u2713"}${B}`}else if(p==="ai-turn-end"){const d=o.usage??{},f=g(o.rounds)!==void 0?` \xB7 ${g(o.rounds)} round${g(o.rounds)===1?"":"s"}`:"",B=g(o.durationMs)!==void 0?` \xB7 ${(g(o.durationMs)/1e3).toFixed(1)}s`:"";j=`${o.ok===!1?"FAILED":"ok"} \xB7 ${g(d.promptTokens)??"?"}+${g(d.completionTokens)??"?"} tok${f}${B}`}}let F;p==="db-query"&&typeof o.query=="string"?F=o.query:p==="redis-op"?F=`${o.op??""} ${String(o.key??"").replace(/\d+/g,"#")}`:p==="egress"?F=`${o.method??"GET"} ${o.host??""}`:p==="ai-call"?F=`ai ${o.provider??""} ${o.model??""} ${o.api??""}`:p==="queue-enqueued"?F=`enqueue ${o.queue??""}`:p==="span"&&typeof c.name=="string"?F=c.name:p==="memory-mutation"&&(F=i.title);const N=i.context??{},w=q.commitId??y.commitId??o.commitId,V=Array.isArray(q.why)?q.why.map(d=>typeof d?.type=="string"?d.type:void 0).filter(d=>!!d):[];return{id:i.id,t:i.timestamp,start:et,...F?{sig:F}:{},...U?{urlKey:U}:{},...httpFacts(p,o),...(p==="db-query"||p==="redis-op")&&typeof o.valuesId=="string"?{valuesId:o.valuesId}:{},...typeof o.queue=="string"?{queue:o.queue}:{},...o.jobId!=null?{jobId:String(o.jobId)}:{},source:i.source,category:i.category,severity:i.severity,title:P==="threw"&&typeof c.name=="string"?`${c.name} \u2014 threw${H?` ${H}`:""}${x!==void 0?` after ${x}ms`:""}`:i.title,kind:p,area:areaOf({source:i.source,category:i.category,title:i.title,kind:p}),...P?{outcome:P}:{},...G?{error:G}:{},...Q?{captured:Q}:{},...typeof c.role=="string"?{role:c.role}:{},...typeof c.spanId=="string"?{spanId:c.spanId}:{},...typeof c.parentSpanId=="string"?{parentSpanId:c.parentSpanId}:{},...p==="log"&&typeof o.level=="string"?{level:o.level}:{},...p==="log"&&typeof o.logger=="string"?{logger:o.logger}:{},...p==="log"&&typeof o.stream=="string"?{stream:o.stream}:{},...typeof N.requestId=="string"?{requestId:N.requestId}:{},...typeof N.parentRequestId=="string"?{parentRequestId:N.parentRequestId}:{},...typeof w=="string"?{commitId:w}:{},...typeof q.componentName=="string"?{component:q.componentName}:{},...typeof q.phase=="string"?{phase:q.phase}:{},...V.length?{why:V}:{},...p==="effect-run"&&typeof y.hookLogicalId=="string"?{hook:y.hookLogicalId}:{},...p==="effect-run"&&y.cleanupRan===!0?{cleanup:!0}:{},...p==="render-commit-truncated"?{renderTotal:g(o.total),renderPublished:g(o.published),...g(o.walkStoppedAt)!==void 0?{renderWalkStoppedAt:g(o.walkStoppedAt)}:{}}:{},...typeof N.projectName=="string"?{project:N.projectName}:typeof o.project=="string"?{project:o.project}:{},...x!==void 0?{durationMs:x}:{},...R&&g(o.startedAt)!==void 0?{fetchStartedAt:g(o.startedAt)}:{},...i.source==="ai"?{ai:h.includeRaw?o:mt(o)}:{},...j?{detail:j}:{},...W?{steps:W}:{}}}C(trimFlowEvent,"trimFlowEvent"),v(trimFlowEvent,"trimFlowEvent");const gt=300;export const OUTLIVED_PARENT_MIN_MS=250;const Tt=new Set(["egress","db-query","redis-op","ai-call","span","gateway-request","server-request"]),$t=1;function yt(i){return i==="flow-origin"?0:i?.endsWith("-start")?1:i==="gateway-request"?2:i==="server-request"?3:i==="span"?4:i==="render"||i==="render-commit-truncated"?6:i==="effect-run"?7:5}C(yt,"Rt"),v(yt,"kindRank");function J(i){return i.kind==="span"&&i.role==="controller"?3.5:i.kind==="queue-process"?3:yt(i.kind)}C(J,"Z"),v(J,"causalRank");export function buildFlowDetail(i,h={}){const o=xt(i),q=i.slice().filter(t=>{const r=t.raw??{},e=typeof r.kind=="string"?r.kind:"";if(e==="subscription-added"||e==="subscription-removed"||e==="hook-run"||e==="store-created"||e==="singleton-instance"||e===bt)return!1;const n=r.span;return!(typeof n?.name=="string"&&n.name.startsWith("nest.request "))}).map(t=>trimFlowEvent(t,h)),c=new Set;for(let t=q.length-1;t>=0;t--)c.has(q[t].id)?q.splice(t,1):c.add(q[t].id);const D=new Map;for(const t of q)(t.kind==="gateway-request"||t.kind==="queue-process")&&t.requestId&&!D.has(t.requestId)&&D.set(t.requestId,t.start);const g=v(t=>t.source!=="react"&&t.source!=="valtio"&&t.requestId&&D.has(t.requestId)?D.get(t.requestId):t.start,"anchorOf");q.sort((t,r)=>g(t)-g(r)||t.start-r.start||J(t)-J(r)||(r.durationMs??0)-(t.durationMs??0)||t.t-r.t);const M=v(t=>(t.kind==="span"||t.kind==="server-request"||t.kind==="gateway-request"||t.kind==="queue-process")&&(t.durationMs??0)>0,"spanLike"),y=q;for(const t of y)t.group=t.source==="react"||t.source==="valtio"||t.source==="client-runtime"||t.source==="visual"?"browser":"server";const x=new Map;for(const t of y)if((t.kind==="gateway-request"||t.kind==="queue-process")&&t.requestId&&t.project){const r=x.get(t.requestId)??[];r.push({project:t.project,start:t.start,end:t.start+(t.durationMs??0)}),x.set(t.requestId,r)}const p=v((t,r)=>{const e=x.get(t);if(e?.length)return e.every(n=>n.project===e[0].project)?e[0].project:e.filter(n=>n.start<=r+1&&n.end>=r-1).sort((n,s)=>s.start-n.start)[0]?.project},"projectOf");for(const t of y)if(!t.project&&t.source==="nestjs"&&t.requestId){const r=p(t.requestId,t.start);r&&(t.project=r)}const R=new Map;for(const t of y)t.spanId&&R.set(t.spanId,t);const _=v((t,r)=>{let e=t.parentSpanId?R.get(t.parentSpanId):void 0;for(let n=0;e&&n<64;n++){if(e===r)return!0;e=e.parentSpanId?R.get(e.parentSpanId):void 0}return!1},"inside");for(const t of y){const r=t.parentSpanId?R.get(t.parentSpanId):void 0;if(r&&r!==t&&r.group===t.group&&r.requestId===t.requestId){t.parent=r.id;continue}let e;const n=t.requestId;for(const s of y){if(s===t||!M(s)||s.group!==t.group||s.requestId!==n)continue;const a=s.project,$=t.project;if(s.kind!=="gateway-request"&&t.kind!=="gateway-request"&&a!==void 0&&$!==void 0&&a!==$)continue;const k=s.durationMs??0,u=t.durationMs??0,l=Math.abs(s.start-t.start)<=$t,m=J(s),I=J(t),A=s.start<=t.start;if(!(s.start+k>t.start&&(A||l&&m<I)&&(!l||(m!==I?m<I:A&&k>u))))continue;const b=e?J(e):-1,O=e?Math.abs(s.start-e.start)<=$t:!1,E=e&&O&&m===b?_(s,e)?1:_(e,s)?-1:0:0;(!e||!O&&s.start>e.start||O&&m>b||E>0||E===0&&O&&m===b&&(s.durationMs??0)<(e.durationMs??0))&&(e=s)}e&&(t.parent=e.id)}for(const t of y)delete t.spanId,delete t.parentSpanId;{const t=new Set(y.map(a=>a.id)),r=new Set,e=new Map,n=[],s=v(a=>{const $=[a];for(;$.length;){const k=$.pop();n.push(k),r.add(k.id);const u=e.get(k.id);if(u){e.delete(k.id);for(let l=u.length-1;l>=0;l--)$.push(u[l])}}},"place");for(const a of y)if(a.parent&&a.parent!==a.id&&t.has(a.parent)&&!r.has(a.parent)){const $=e.get(a.parent)??[];$.push(a),e.set(a.parent,$)}else s(a);for(const a of y)r.has(a.id)||(n.push(a),r.add(a.id));for(let a=0;a<n.length;a++)y[a]=n[a]}const z=new Map;for(const t of y){if(!t.requestId)continue;const r=z.get(t.requestId);r?r.push(t):z.set(t.requestId,[t])}const et=new Map(y.map(t=>[t.id,t])),j=v((t,r)=>{const e=(z.get(t)??[]).filter(n=>M(n)&&n.start<=r&&n.start+(n.durationMs??0)>=r);if(e.length!==0)return e.sort((n,s)=>s.start-n.start||(n.durationMs??0)-(s.durationMs??0)),e[0]},"callerNodeFor");for(const t of y){if(!t.parentRequestId||t.kind!=="server-request"&&t.kind!=="gateway-request")continue;const r=t.parent?et.get(t.parent):void 0;if(r&&r.requestId===t.requestId)continue;const e=j(t.parentRequestId,t.start);e&&e!==t&&e.start<=t.start&&(t.parent=e.id)}const P=y,G=new Map;for(const t of P)t.kind==="gateway-request"&&t.requestId&&!G.has(t.requestId)&&G.set(t.requestId,t);for(const t of P)if(t.group==="server"&&!t.parent&&t.requestId&&t.kind!=="gateway-request"){const r=G.get(t.requestId);r&&r!==t&&r.start<=t.start&&(t.parent=r.id)}const H=new Set,Q=new Set,U=[];for(const t of P){if(t.kind!=="gateway-request")continue;if(!t.requestId){U.push(t);continue}const r=z.get(t.requestId)??[];if(r.filter(s=>s.kind==="gateway-request").sort((s,a)=>s.start-a.start)[0]!==t)continue;const e=r.find(s=>s.kind==="fetch-start"),n=r.find(s=>s.kind==="fetch-done"||s.kind==="fetch-error");if(!e&&!n){U.push(t);continue}e&&(t.fetchStartId=e.id,H.add(e.id)),n&&(t.fetchDoneId=n.id,Q.add(n.id))}const W=new Map;for(const t of P){if(!t.urlKey)continue;const r=W.get(t.urlKey)??{gws:[],starts:[],dones:[]};t.kind==="gateway-request"?U.includes(t)&&r.gws.push(t):t.kind==="fetch-start"?H.has(t.id)||r.starts.push(t):(t.kind==="fetch-done"||t.kind==="fetch-error")&&(Q.has(t.id)||r.dones.push(t)),W.set(t.urlKey,r)}for(const{gws:t,starts:r,dones:e}of W.values()){t.sort((s,a)=>s.start-a.start),r.sort((s,a)=>s.start-a.start);const n=new Set;t.forEach((s,a)=>{const $=r[a];$&&(s.fetchStartId=$.id);const k=$?$.t:s.start;let u,l=1/0;for(const m of e){if(n.has(m.id))continue;const I=m.fetchStartedAt??m.start-(m.durationMs??0),A=Math.abs(I-k);A<l&&(l=A,u=m)}u&&(s.fetchDoneId=u.id,n.add(u.id))})}const F=new Map,N=new Map;for(const t of P)!t.queue||!t.jobId||(t.kind==="queue-enqueued"&&F.set(`${t.queue}#${t.jobId}`,t),t.kind==="queue-process"&&N.set(`${t.queue}#${t.jobId}`,t));for(const t of P){if(!t.queue||!t.jobId)continue;const r=`${t.queue}#${t.jobId}`;if(t.kind==="queue-process"&&!t.parent){const e=F.get(r);e&&e!==t&&e.start<=t.start&&(t.parent=e.id)}else if(t.kind==="queue-active"||t.kind==="queue-completed"||t.kind==="queue-failed"){const e=N.get(r);e&&e!==t&&e.start<=t.start&&(t.parent=e.id)}}{const t=new Map(y.map(r=>[r.id,r]));for(const r of y){if(!r.parent||!Tt.has(r.kind??"")||r.durationMs===void 0)continue;const e=t.get(r.parent);if(!e||e.kind!=="span"||!((e.durationMs??0)>0))continue;const n=Math.round(r.start+r.durationMs-(e.start+e.durationMs));if(n<OUTLIVED_PARENT_MIN_MS)continue;r.outlivedParentMs=n;const s=e.leftRunning??{count:0,longestMs:0};e.leftRunning={count:s.count+1,longestMs:Math.max(s.longestMs,n)}}for(const r of y){const e=[];r.leftRunning&&e.push(`ended before ${r.leftRunning.count===1?"a call":`${r.leftRunning.count} calls`} it started had finished \u2014 ${r.leftRunning.count===1?"it":"the longest"} ran on ${r.leftRunning.longestMs}ms (a timeout that gave up, or work not awaited)`),r.outlivedParentMs!==void 0&&e.push(`ran on ${r.outlivedParentMs}ms after the span that started it had ended`),e.length>0&&(r.detail=[r.detail,...e].filter(Boolean).join(" \xB7 "))}}let w=y;{const t=new Map;for(const e of w)e.kind==="fetch-start"&&t.set(e.id,e);const r=new Map;for(const e of w){if(e.kind!=="fetch-done"&&e.kind!=="fetch-error")continue;const n=[...t.values()].find($=>$.requestId&&$.requestId===e.requestId)?.id,s=n?t.get(n):void 0;if(!s)continue;const a=e.fetchStartedAt??s.start;s.title=e.title,s.severity=e.severity,s.durationMs=e.durationMs??Math.max(0,e.t-a),s.kind="fetch",e.detail&&!s.detail&&(s.detail=e.detail),r.set(e.id,s.id)}if(r.size>0){w=w.filter(e=>!r.has(e.id));for(const e of w)for(e.fetchDoneId&&r.has(e.fetchDoneId)&&(e.fetchDoneId=r.get(e.fetchDoneId));e.parent&&r.has(e.parent);)e.parent=r.get(e.parent)}}const V=v(t=>!!t.commitId&&(t.kind==="render"||t.kind==="effect-run"||t.kind==="render-commit-truncated"),"commitMember"),d=v(t=>[...new Set(t)],"uniq"),f=v(t=>d(t.map(r=>r.component).filter(r=>!!r)),"named"),B=v(t=>t.length<=2?t.join(" + "):`${t[0]} + ${t.length-1} more`,"nameList"),T=v(t=>{const r=new Map;for(const e of t)e.component&&r.set(e.component,(r.get(e.component)??0)+1);return[...r].map(([e,n])=>n>1?`${e} \xD7${n}`:e).join(", ")},"tally"),L=v(t=>{if(!t)return"effect";const r=/([^/\\]+?):(\d+)(?::\d+)?$/.exec(t);return r?`${r[1]}:${r[2]}`:t},"shortHook"),K=v(t=>`${L(t.hook)}${t.cleanup?" (cleanup)":""}`,"hookLabel"),nt=v(t=>{const r=Math.min(...t.map(n=>n.start)),e=Math.max(...t.map(n=>n.start+(n.durationMs??0)));return{start:r,durationMs:e-r}},"extent"),st=v(t=>(delete t.component,delete t.why,delete t.phase,delete t.hook,delete t.cleanup,delete t.renderTotal,delete t.renderPublished,t),"asGroup");function at(t){const r=t[0],e=t.filter(S=>S.kind==="render"),n=t.filter(S=>S.kind==="effect-run"),s=t.find(S=>S.kind==="render-commit-truncated"),a=[...e].sort((S,Y)=>(Y.durationMs??0)-(S.durationMs??0)),$=a.filter(S=>(S.why??[]).some(Y=>Y!=="parent-render")),k=d($.flatMap(S=>(S.why??[]).filter(Y=>Y!=="parent-render"))),u=f($),l=e.filter(S=>S.phase==="mount"),m=e.filter(S=>S.phase!=="mount"&&!$.includes(S)),I=a[0]?.component??"view",A=e.length>0&&l.length===e.length,b=k.length?k.join(" + "):void 0,O=A?"mount":"update",E=u.length?`view update \xB7 ${B(u)} \u2190 ${b}`:A?`view mount \xB7 ${I}`:`view update \xB7 ${I}`,rt=s?.renderTotal??e.length,kt=[l.length?`mounted ${T(l)}`:"",m.length?`re-rendered ${T(m)}`:"",!u.length&&!A&&e.length?"trigger not recorded \u2014 every captured render came from its parent":"",s?.renderWalkStoppedAt!==void 0?`at least ${rt} renders (the walk stopped at ${s.renderWalkStoppedAt} fibers), ${s.renderPublished??e.length} recorded`:s?`${rt} renders, ${s.renderPublished??e.length} recorded (per-commit cap)`:`${e.length} render${e.length===1?"":"s"}`,n.length?`${n.length} effect${n.length===1?"":"s"}: ${n.map(K).join(", ")}`:""].filter(Boolean).join(" \xB7 "),ct=f(e);return st({...r,...nt(t),kind:"view-update",title:E,detail:kt,commitId:r.commitId,viewPhase:O,...b?{cause:b}:{},causeComponents:u,components:ct,mounted:f(l),renderCount:rt,...s?.renderWalkStoppedAt!==void 0?{renderCountAtLeast:!0}:{},recordedRenders:e.length,effects:n.length,effectHooks:n.map(K),memberIds:t.map(S=>S.id),sig:`commit:${O}:${b??"-"}:${u.join(",")}:${ct.slice().sort().join(",")}`,severity:t.some(S=>S.severity==="error")?"error":r.severity})}C(at,"pt"),v(at,"viewUpdateNode");function it(t){const r=t[0],e=t.map(K);return st({...r,...nt(t),kind:"commit-effects",title:t.length===1?`effect \xB7 ${e[0]}`:`effects \xB7 ${e[0]} + ${t.length-1} more`,detail:e.join(", "),commitId:r.commitId,effects:t.length,effectHooks:e,memberIds:t.map(n=>n.id),sig:`effects:${e.slice().sort().join(",")}`})}C(it,"mt"),v(it,"effectsNode");const vt=v(t=>d(t.map(r=>r==="state-update"?"state update":r==="fetch-start"?"request":r==="flow-origin"?"interaction":"response")).join(" + "),"describeInputs");function dt(t,r){const e=t[0],n=t[t.length-1],s=t.length,a=e.detail,$=Math.min(...t.map(m=>m.start)),k=Math.max(...t.map(m=>m.start+(m.durationMs??0))),u=Math.round(t.reduce((m,I)=>m+(I.durationMs??0),0)/s*10)/10,l=Math.round((k-$)*10)/10;e.count=s,e.avgMs=u,e.wallMs=l,e.durationMs=k-$,e.items=t.slice(0,12).map(m=>({start:m.start-$,...m.durationMs!=null?{durationMs:m.durationMs}:{}})),e.memberIds=t.flatMap(m=>m.memberIds??[m.id]),e.title=`\xD7${s} ${e.title}`,t.some(m=>m.severity==="error")&&(e.severity="error"),e.kind==="view-update"?e.detail=[`${s} commits, ${r.length?`one per ${vt(r)}`:"back to back"}`,`avg ${u}ms \xB7 wall ${l}ms`,a??""].filter(Boolean).join(" \xB7 "):e.kind==="state-update"&&a&&n.detail?e.detail=`${s} updates in a row \xB7 wall ${l}ms \xB7 first ${a} \xB7 last ${n.detail}`:e.detail=[`${s} in a row \xB7 wall ${l}ms`,a??""].filter(Boolean).join(" \xB7 ")}C(dt,"ht"),v(dt,"collapseRepeat");const Z=[],X=new Map,ut=new Set;for(let t=0;t<w.length;t++){if(ut.has(t))continue;const r=w[t];if(!V(r)){Z.push(r);continue}const e=[t];for(let a=t+1;a<w.length;a++){const $=w[a];if($.group==="browser"){if(!V($)||$.commitId!==r.commitId)break;e.push(a)}}for(const a of e)ut.add(a);const n=e.map(a=>w[a]),s=n.some(a=>a.kind!=="effect-run")?at(n):it(n);for(const a of n)a.id!==s.id&&X.set(a.id,s.id);Z.push(s)}if(X.size>0||Z.some(t=>t.kind==="view-update"||t.kind==="commit-effects")){w=Z;for(const t of w)for(;t.parent&&X.has(t.parent);)t.parent=X.get(t.parent)}{const t=new Map;for(const r of w)r.kind==="view-update"&&r.commitId&&!t.has(r.commitId)&&t.set(r.commitId,r);for(const r of w){if(r.kind!=="commit-effects"||r.parent||!r.commitId)continue;const e=t.get(r.commitId);e&&e.start<=r.start&&(r.parent=e.id)}}{const t=new Set(["state-update","fetch","fetch-start","fetch-done","fetch-error","flow-origin"]),r=w.map((u,l)=>u.group==="browser"?l:-1).filter(u=>u>=0),e=v(u=>`${u.kind}|${u.sig??u.title}`,"keyOf"),n=r.map(u=>e(w[u])),s=v((u,l,m)=>{for(let I=0;I<m;I++)if(n[u+I]!==n[l+I])return!1;return!0},"sameBlock"),a=v(u=>n[u].split("|")[0],"kindAt"),$=v(u=>{let l=0,m=1;for(let I=1;I<=4&&u+I<=n.length;I++){let A=1;for(;u+(A+1)*I<=n.length&&s(u,u+A*I,I);)A+=1;A>=3&&I*A>l*m&&(l=I,m=A)}return{k:l,r:m}},"bestBlockAt"),k=new Map;for(let u=0;u<n.length;){const{k:l,r:m}=$(u);if(l===0){u+=1;continue}const I=[...Array(l).keys()].find(b=>t.has(a(u+b)));if(I!==void 0&&I>0){const b=$(u+I);if(b.k===l&&b.r>=3&&b.r>=m-1){u+=I;continue}}const A=n.slice(u,u+l).map(b=>b.split("|")[0]).filter(b=>t.has(b));for(let b=0;b<l;b++){const O=[];for(let E=0;E<m;E++)O.push(w[r[u+b+E*l]]);dt(O,A);for(const E of O.slice(1))k.set(E.id,O[0].id)}u+=l*m}if(k.size>0){w=w.filter(u=>!k.has(u.id));for(const u of w)for(;u.parent&&k.has(u.parent);)u.parent=k.get(u.parent)}}{const t=new Map(w.map(r=>[r.id,r]));for(const r of w){const e=new Set([r.id]);let n=r;for(;n?.parent;){if(e.has(n.parent)){n.parent=void 0;break}e.add(n.parent),n=t.get(n.parent)}}}const lt=v(t=>{const r=new Map;for(const n of w){if(!n.sig||M(n)!==t||n.kind==="server-request"||n.kind==="gateway-request"||n.group==="browser")continue;const s=`${n.parent??"root"}|${n.kind}|${n.sig}`,a=r.get(s);a?a.push(n):r.set(s,[n])}const e=new Map;for(const n of r.values()){if(n.length<3)continue;n.sort((l,m)=>l.start-m.start);const s=n[0];let a=!1;for(let l=0;l+1<n.length;l++)if(n[l+1].start<n[l].start+(n[l].durationMs??0)){a=!0;break}const $=s.start,k=Math.max(...n.map(l=>l.start+(l.durationMs??0))),u=n.reduce((l,m)=>l+(m.durationMs??0),0);s.count=n.length,s.parallel=a,s.avgMs=Math.round(u/n.length*10)/10,s.wallMs=k-$,s.durationMs=k-$,s.title=`\xD7${n.length} ${s.title.replace(/\s*\((?:\d+ rows?, )?\d+ms\)$/,"")}`,s.detail=`${s.sig} \xD7${n.length} ${a?"\u2016 parallel":"\u21BB sequential loop"} \xB7 avg ${s.avgMs}ms \xB7 wall ${s.wallMs}ms`,s.items=n.slice(0,12).map(l=>({start:l.start-$,...l.durationMs!=null?{durationMs:l.durationMs}:{}})),s.memberIds=n.flatMap(l=>l.memberIds??[l.id]),n.some(l=>l.severity==="error")&&(s.severity="error");for(const l of n.slice(1))e.set(l.id,s.id)}if(e.size!==0){w=w.filter(n=>!e.has(n.id));for(const n of w)for(;n.parent&&e.has(n.parent);)n.parent=e.get(n.parent)}},"aggregatePass");lt(!0),lt(!1);for(const t of w){if(!M(t))continue;const r=t.durationMs??0;if(r<40)continue;const e=w.filter(k=>k.parent===t.id&&(k.durationMs??0)>0).map(k=>[k.start,k.start+(k.durationMs??0)]).sort((k,u)=>k[0]-u[0]);let n=0,s=-1,a=-1;for(const[k,u]of e)k>a?(a>s&&(n+=a-s),s=k,a=u):u>a&&(a=u);a>s&&(n+=a-s);const $=Math.max(0,r-n);($>=50||$/r>=.7&&r>=40)&&(t.selfMs=$,t.detail=`\u26A0 cpu-heavy: ${$}ms self-time of ${r}ms${t.detail?" \xB7 "+t.detail:""}`)}return{events:w,...o?{sql:o}:{}}}C(buildFlowDetail,"buildFlowDetail"),v(buildFlowDetail,"buildFlowDetail");
|
package/lib/graph-from-events.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var g=Object.defineProperty;var
|
|
1
|
+
"use strict";var g=Object.defineProperty;var l=(t,r)=>g(t,"name",{value:r,configurable:!0});var I=Object.defineProperty,p=l((t,r)=>I(t,"name",{value:r,configurable:!0}),"l");function m(t){const r=t.raw??null,s=r?.kind,d=t.context,a={id:t.id,parentTraceNodeId:d.causedByNodeId??d.originNodeId,lifecycle:"completed",context:d,startTime:t.timestamp,attributes:{...r??{}}};if(t.source==="react"&&s==="render"){const e=r;return{parentAxis:"render",node:{...a,type:"render",logicalId:e.render?.componentLogicalId,instanceId:e.render?.componentInstanceId,name:`render ${e.render?.componentName??"?"}`,durationMs:e.render?.actualDurationMs}}}if(t.source==="valtio"&&s==="state-update"){const e=r;return{parentAxis:"state",node:{...a,type:"state-update",logicalId:e.update?.storeId,name:`${e.update?.storeId??"?"}.${e.update?.path??"?"}`}}}if(t.source==="nestjs"&&s==="server-request"){const e=r;return{parentAxis:"backend",node:{...a,type:"server-request",name:`${e.request?.method??"?"} ${e.request?.route??"?"}`,durationMs:e.request?.durationMs}}}if(s==="db-query"){const e=r,c=[e.op,e.table].filter(Boolean).join(" ")||(e.name??"query");return{parentAxis:"backend",node:{...a,type:"db-query",logicalId:e.table?`db:${e.op??"query"}:${e.table}`:void 0,name:e.error?`${c} (failed)`:c,durationMs:e.durationMs}}}if(s==="loop")return{parentAxis:"performance",node:{...a,type:"loop",name:"loop",durationMs:r.loop?.durationMs}};if(s==="flow-origin"&&(t.source==="react"||t.source==="client-runtime")){const e=d.originNodeId??(typeof r?.originNodeId=="string"?r.originNodeId:void 0);return{parentAxis:"caused",node:{...a,parentTraceNodeId:d.causedByNodeId,type:"ui-event",logicalId:e,name:e?`${t.title} ${e}`:t.title}}}if(t.source==="client-runtime"&&s==="user-action"){const e=r;return{parentAxis:"caused",node:{...a,type:"ui-event",logicalId:e.origin?.nodeId,name:e.origin?.label??t.title}}}}l(m,"m"),p(m,"eventToNode");export function buildGraphFromEvents(t,r){const s=[...r].sort((o,n)=>o.timestamp-n.timestamp),d=[];for(const o of s){const n=m(o);n&&(t.addNode(n.node),d.push(n))}let a=0;const e=p((o,n,i,u)=>{const f={id:`${i}:${o}->${n}`,from:o,to:n,axis:i,type:u,timestamp:t.getNode(n)?.startTime??0};t.addEdge(f),a++},"addEdge");for(const o of d){const n=o.node.context.causedByNodeId;n&&t.getNode(n)&&e(n,o.node.id,o.parentAxis??"caused","caused-by")}const c=new Map;for(const o of d){const n=o.node.context.flowId;if(!n)continue;let i=c.get(n);i||(i=[],c.set(n,i)),i.push(o)}for(const o of c.values())for(let n=1;n<o.length;n++){const i=o[n-1].node,u=o[n].node;u.context.causedByNodeId!==i.id&&e(i.id,u.id,"caused","flow-sequence")}return{nodeCount:d.length,edgeCount:a}}l(buildGraphFromEvents,"buildGraphFromEvents"),p(buildGraphFromEvents,"buildGraphFromEvents");
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A cache key's family — one rule for the Redis tap (its flood bucket per command shape) and the cache catalog (its key
|
|
3
|
+
* patterns), so both group the same keys. Dependency-free: the tap imports it as `@lensmcp/core/key-pattern`.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* A key with its ids folded to `*` — `bull:product-analysis-<uuid>:<uuid>` → `bull:product-analysis-*:*`. An id is
|
|
7
|
+
* a UUID, a whole segment of 16+ id characters with a digit and a letter (a nanoid), a run of 8+ hex characters
|
|
8
|
+
* with a digit in it, or a number of 2+ digits; a word stays a word (`facade`, `product-analysis`).
|
|
9
|
+
*/
|
|
10
|
+
export declare function foldKeyPattern(key: string): string;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";var f=Object.defineProperty;var r=(a,e)=>f(a,"name",{value:e,configurable:!0});var t=Object.defineProperty,c=r((a,e)=>t(a,"name",{value:e,configurable:!0}),"e");const l=/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/gi;export function foldKeyPattern(a){return a.replace(l,"*").replace(/(?<=^|[:=/])(?=[A-Za-z0-9_-]*\d)(?=[A-Za-z0-9_-]*[A-Za-z])[A-Za-z0-9_-]{16,}(?=$|[:=/])/g,"*").replace(/(?<![A-Za-z])(?=[0-9a-f]*\d)[0-9a-f]{8,}(?![A-Za-z])/gi,"*").replace(/(?<![A-Za-z0-9])\d{2,}(?![A-Za-z0-9])/g,"*").replace(/\*(?:[_-]?\*)+/g,"*")}r(foldKeyPattern,"foldKeyPattern"),c(foldKeyPattern,"foldKeyPattern");
|
package/lib/redact.d.ts
CHANGED
|
@@ -65,6 +65,12 @@ export declare const MAX_URL_CHARS = 1024;
|
|
|
65
65
|
* (issues/closed/codex-security-40).
|
|
66
66
|
*/
|
|
67
67
|
export declare function isSecretParam(name: string): boolean;
|
|
68
|
+
/**
|
|
69
|
+
* Is this cache key where an app keeps a credential — a session store (`sess:<id>`), a one-time code (`otp:user:7`), a
|
|
70
|
+
* reset or magic-link token (`reset:<token>`)? Its value is a secret whatever its shape (a session's JSON, six digits),
|
|
71
|
+
* which no value pattern catches. Judged per segment (`:`, `/`, `{`, `}`, `#`), each as a name.
|
|
72
|
+
*/
|
|
73
|
+
export declare function isSecretCacheKey(key: string): boolean;
|
|
68
74
|
/**
|
|
69
75
|
* Strip credentials from a URL — userinfo, then any query OR fragment
|
|
70
76
|
* parameter whose NAME looks like a credential — preserving every other byte
|
|
@@ -107,6 +113,13 @@ export declare function redactUrl(url: string): string;
|
|
|
107
113
|
* comes back byte-identical).
|
|
108
114
|
*/
|
|
109
115
|
export declare function redactText(text: string): string;
|
|
116
|
+
/**
|
|
117
|
+
* Every secret SHAPE — what {@link redactText} knows (URLs, headers, JWTs) plus the keys, PEM private keys and
|
|
118
|
+
* `"password": "…"` / `token=…` pairs a body, a prompt or a typed value is liable to hold. For text that never crosses
|
|
119
|
+
* the bus redactor: the side files a tap writes (AI calls, exchanges, SQL values) and what an agent reads of a
|
|
120
|
+
* recording. Tuned for precision, as `redactText` is; it cannot remove personal data.
|
|
121
|
+
*/
|
|
122
|
+
export declare function redactSecretText(text: string): string;
|
|
110
123
|
/**
|
|
111
124
|
* Bound a string, marking what was removed. Marker text matches
|
|
112
125
|
* `@lensmcp/storage`'s `clampEventRaw` so the two truncations read the same in
|
package/lib/redact.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var _=Object.defineProperty;var f=(t,e)=>_(t,"name",{value:e,configurable:!0});var I=Object.defineProperty,l=f((t,e)=>I(t,"name",{value:e,configurable:!0}),"a");export const REDACTED="REDACTED",MAX_TITLE_CHARS=300,MAX_MESSAGE_CHARS=4096,MAX_URL_CHARS=1024;const v=["token","secret","password","passwd","apikey","credential","assertion","signature"],Z=new Set(["key","auth","authorization","jwt","code","sig","pwd","pass","session","sid","bearer","otp","cookie","set-cookie"]),R=/^(?:(?:prompt|completion|total|input|output|cache|cached|cacheread|cachewrite|reasoning|thinking|max|min|remaining|used|billed)tokens|tokens?(?:count|used|limit|remaining))$/;export function isSecretParam(t){const e=d.get(t);if(e!==void 0)return e;const r=m(t);return t.length<=64&&d.size<C&&d.set(t,r),r}f(isSecretParam,"isSecretParam"),l(isSecretParam,"isSecretParam");const P=new Set(["sess","csrf","xsrf","refresh","nonce","reset","magic","mfa","2fa","verify","verification","invite","login"]);export function isSecretCacheKey(t){for(const e of t.split(/[:/{}#]+/))if(!(!e||e.length>64)){if(isSecretParam(e))return!0;for(const r of e.toLowerCase().split(/[-_.]+/))if(P.has(r))return!0}return!1}f(isSecretCacheKey,"isSecretCacheKey"),l(isSecretCacheKey,"isSecretCacheKey");const C=4096,d=new Map;function m(t){const e=t.toLowerCase();if(R.test(e.replace(/[-_.]+/g,"")))return!1;if(v.some(r=>e.includes(r)))return!0;for(const r of e.split(/[-_.]+/))if(r&&Z.has(r))return!0;return!1}f(m,"N"),l(m,"judgeParam");const O=/^([a-z][a-z0-9+.-]*:\/\/)[^/?#@\s]*@/i,N=/([?&#])([^=&#\s]+)=([^&#\s]*)/g;export function redactUrlParams(t){return t&&t.replace(O,`$1${REDACTED}@`).replace(N,(e,r,n)=>isSecretParam(n)?`${r}${n}=${REDACTED}`:e)}f(redactUrlParams,"redactUrlParams"),l(redactUrlParams,"redactUrlParams");export function redactUrl(t){return t&&clip(redactUrlParams(t),1024)}f(redactUrl,"redactUrl"),l(redactUrl,"redactUrl");const D=/\beyJ[A-Za-z0-9_-]{6,}\.[A-Za-z0-9_-]{4,}\.[A-Za-z0-9_-]*/g,M=/\b(bearer|basic)\s+[A-Za-z0-9._~+/=-]{8,}/gi,K=/\b(authorization|x-api-key|api-key|cookie|set-cookie|proxy-authorization)\b(\s*[:=]\s*)(["']?)((?:(?:bearer|basic)\s+)?[^\s"',;]{4,})\3/gi,j=/[@=:]|eyJ|bearer|basic/i;export function redactText(t){return j.test(t)?redactUrlParams(t).replace(K,(e,r,n,a)=>`${r}${n}${a}${REDACTED}${a}`).replace(D,REDACTED).replace(M,(e,r)=>`${r} ${REDACTED}`):t}f(redactText,"redactText"),l(redactText,"redactText");const L=[/\bsk-(?:ant-|proj-|live-|test-)?[A-Za-z0-9_-]{20,}/g,/\b(?:AKIA|ASIA)[0-9A-Z]{16}\b/g,/\bgh[pousr]_[A-Za-z0-9]{30,}/g,/\bxox[abprs]-[A-Za-z0-9-]{10,}/g,/\bAIza[0-9A-Za-z_-]{35}\b/g],h="-----BEGIN ",U=4096;function S(t){if(!t.includes("PRIVATE KEY-----"))return t;let e="",r=0,n=!1;for(;;){const a=t.indexOf(h,r);if(a===-1)break;const o=t.indexOf("-----",a+h.length);if(o===-1)break;const s=t.slice(a+h.length,o);if(!/^[A-Z ]{0,30}PRIVATE KEY$/.test(s)){e+=t.slice(r,o+5),r=o+5;continue}e+=t.slice(r,a);const i=n?-1:t.indexOf("-----END ",o+5);let c;if(i===-1)n=!0,c=Math.min(t.length,o+5+U);else{const u=t.indexOf("-----",i+9);c=u===-1?t.length:u+5}e+=REDACTED,r=c}return e+t.slice(r)}f(S,"y"),l(S,"redactPrivateKeys");const H=/"([A-Za-z0-9_.-]{1,64})"\s*:\s*"((?:[^"\\]|\\.){1,8192})"/g,V=/\b([A-Za-z][A-Za-z0-9_-]{1,40})(\s*[:=]\s*)([^\s"'`,;&)}\]]{8,200})/g,X=/(token|secret|pass(?:word|wd)?|pwd|api[-_]?key|apikey|credential|authorization|bearer)/i;function w(t){return t.replace(H,(e,r)=>isSecretParam(r)?`"${r}": "${REDACTED}"`:e).replace(V,(e,r,n)=>X.test(r)&&isSecretParam(r)?`${r}${n}${REDACTED}`:e)}f(w,"U"),l(w,"redactStructured");export function redactSecretText(t){let e=w(redactText(S(t)));for(const r of L)e=e.replace(r,REDACTED);return e}f(redactSecretText,"redactSecretText"),l(redactSecretText,"redactSecretText");export function clip(t,e){return t.length<=e?t:`${t.slice(0,e)}\u2026[lensmcp truncated: ${t.length-e} more chars]`}f(clip,"clip"),l(clip,"clip");export function safeText(t,e=4096){if(t!==void 0)return clip(redactText(t),e)}f(safeText,"safeText"),l(safeText,"safeText");export function safeTitle(t){return clip(redactText(t),300)}f(safeTitle,"safeTitle"),l(safeTitle,"safeTitle");const q=6,G=64,J=/^TS\d{1,5}$/,Y=l((t,e)=>t==="code"&&typeof e=="string"&&J.test(e),"isDiagnosticCode");export function redactDeep(t,e=0,r=q){if(typeof t=="string")return redactText(t);if(t===null||typeof t!="object"||e>=r)return t;if(Array.isArray(t)){let s;for(let i=0;i<t.length;i++){if(i>=G){s&&s.push(t[i]);continue}const c=t[i],u=redactDeep(c,e+1,r);s?s.push(u):u!==c&&(s=t.slice(0,i),s.push(u))}return s??t}const n=t,a=Object.keys(n);let o;for(let s=0;s<a.length;s++){const i=a[s],c=n[i],u=isSecretParam(i)&&c!==void 0&&c!==null&&!Y(i,c)?REDACTED:redactDeep(c,e+1,r);if(o)o[i]=u;else if(u!==c){o={};for(let p=0;p<s;p++)o[a[p]]=n[a[p]];o[i]=u}}return o??t}f(redactDeep,"redactDeep"),l(redactDeep,"redactDeep");const A=String.raw`(?:"(?:[^"]|"")+"|[A-Za-z_][\w$]*)`,x=String.raw`${A}(?:\s*\.\s*${A})*`,B=String.raw`(?:=|<>|!=|<=|>=|<|>|(?:NOT\s+)?I?LIKE|IS\s+(?:NOT\s+)?DISTINCT\s+FROM)`,F=new RegExp(String.raw`(${x})\s*${B}\s*(?:[A-Za-z_]\w*\s*\(\s*)?\$(\d+)`,"gi"),W=new RegExp(String.raw`(${x})\s+(?:NOT\s+)?IN\s*\(([^()]*)\)`,"gi"),Q=new RegExp(String.raw`\bINSERT\s+INTO\s+${x}\s*\(([^()]*)\)\s*VALUES\s*`,"gi"),tt=new RegExp(A,"g"),z=/\$(\d+)/g,T=16384,et=256,rt=4096,g=new Map,b=l(t=>{const e=t.match(tt)??[],r=e[e.length-1]??"";return r.startsWith('"')?r.slice(1,-1).replace(/""/g,'"'):r},"lastIdent");function k(t,e){const r=[];let n=e;for(;;){for(;n<t.length&&/\s/.test(t[n]);)n++;if(t[n]!=="(")return r;const a=[];let o=n+1,s=0,i=!1;for(n+=1;n<t.length;n++){const c=t[n];if(i){c==="'"&&(i=!1);continue}if(c==="'")i=!0;else if(c==="(")s++;else if(c===")"){if(s===0)break;s--}else c===","&&s===0&&(a.push(t.slice(o,n)),o=n+1)}if(n>=t.length)return r;for(a.push(t.slice(o,n)),r.push(a),n+=1;n<t.length&&/\s/.test(t[n]);)n++;if(t[n]!==",")return r;n+=1}}f(k,"q"),l(k,"valuesTuples");function y(t){const e=t.length<=rt,r=e?g.get(t):void 0;if(r)return r;const n=t.length>T?t.slice(0,T):t,a=new Set,o=l((s,i)=>{i&&isSecretParam(i)&&a.add(Number(s))},"bind");for(const s of n.matchAll(F))o(s[2],b(s[1]));for(const s of n.matchAll(W)){const i=b(s[1]);for(const c of s[2].matchAll(z))o(c[1],i)}for(const s of n.matchAll(Q)){const i=s[1].split(",").map(c=>b(c.trim()));for(const c of k(n,(s.index??0)+s[0].length))c.forEach((u,p)=>{const $=i[p];if($)for(const E of u.matchAll(z))o(E[1],$)})}if(e){if(g.size>=et){const s=g.keys().next().value;s!==void 0&&g.delete(s)}g.set(t,a)}return a}f(y,"ee"),l(y,"secretPlaceholders");export function redactSqlParams(t,e){if(e.length===0||!t.includes("$"))return e;const r=y(t);if(r.size===0)return e;let n=!1;const a=e.map((o,s)=>o==null||!r.has(s+1)?o:(n=!0,REDACTED));return n?a:e}f(redactSqlParams,"redactSqlParams"),l(redactSqlParams,"redactSqlParams");
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where session replay recordings live (planning/replay/00-plan.md §5, the owner's D4) — one rule for the bridge that
|
|
3
|
+
* writes them and the lens that reads and sweeps them.
|
|
4
|
+
*
|
|
5
|
+
* <root>/<checkout>/<loadId>/ a page load: meta.json, index.jsonl, the chunks
|
|
6
|
+
* <root>/blobs/<sha[0:2]>/ what loads share, stored once by hash
|
|
7
|
+
*/
|
|
8
|
+
export interface ReplayStore {
|
|
9
|
+
/** The workspace's replay root. */
|
|
10
|
+
root: string;
|
|
11
|
+
/** `main`, or a worktree instance's name. */
|
|
12
|
+
checkout: string;
|
|
13
|
+
}
|
|
14
|
+
/** A path segment from the environment: only what is safe in a file name. */
|
|
15
|
+
export declare function replayPathSegment(value: string | undefined): string | undefined;
|
|
16
|
+
/**
|
|
17
|
+
* `LENSMCP_REPLAY_DIR`; else `~/.lensmcp/replay/<workspace>` for a workspace the gateway names; else beside the bus file.
|
|
18
|
+
* The checkout is the worktree instance (`LENSMCP_INSTANCE`) or `main`.
|
|
19
|
+
*
|
|
20
|
+
* The workspace is `LENSMCP_REPLAY_WORKSPACE` — what the gateway hands a lens frontend, its dashboards and its MCP
|
|
21
|
+
* server: the MAIN workspace's key for a worktree instance too, so a removed worktree keeps its recordings — else
|
|
22
|
+
* `LENSMCP_WS_KEY`. (A frontend the gateway started used to get neither, and wrote beside the bus.)
|
|
23
|
+
*/
|
|
24
|
+
export declare function replayStoreFromEnv(env?: Record<string, string | undefined>, cwd?: string): ReplayStore;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";var c=Object.defineProperty;var o=(e,r)=>c(e,"name",{value:r,configurable:!0});var i=Object.defineProperty,n=o((e,r)=>i(e,"name",{value:r,configurable:!0}),"e");import{homedir as m}from"node:os";import{dirname as p,join as a}from"node:path";import{lensEventFile as s}from"./lens-events.js";export function replayPathSegment(e){const r=e?.trim().replace(/[^A-Za-z0-9._-]/g,"-").replace(/^[.-]+/,"");return r?r.slice(0,80):void 0}o(replayPathSegment,"replayPathSegment"),n(replayPathSegment,"replayPathSegment");export function replayStoreFromEnv(e=process.env,r=process.cwd()){const t=replayPathSegment(e.LENSMCP_REPLAY_WORKSPACE||e.LENSMCP_WS_KEY);return{root:e.LENSMCP_REPLAY_DIR?.trim()||(t?a(e.LENSMCP_HOME||m(),".lensmcp","replay",t):a(p(s(e,r)),"replay")),checkout:replayPathSegment(e.LENSMCP_INSTANCE)??"main"}}o(replayStoreFromEnv,"replayStoreFromEnv"),n(replayStoreFromEnv,"replayStoreFromEnv");
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { DashCacheValues, DashKeptValues, DashSqlValues } from '@lensmcp/protocol-types';
|
|
2
|
+
/**
|
|
3
|
+
* Where every value of a SQL run is kept (planning/replay/00-plan.md D8 — the owner: «we need to understand
|
|
4
|
+
* everything»): one rule for the pg tap that writes it and the lens that reads it.
|
|
5
|
+
*
|
|
6
|
+
* The bus keeps what a flow step shows — the first 10 parameters at 80 characters and 2 result rows at 240. The whole of
|
|
7
|
+
* them goes beside the bus file, `<lens dir>/sql/<pid>-<yyyymmddhhmm>.jsonl`, one line per run; the event carries the
|
|
8
|
+
* run's id (`valuesId`), and the id names its file.
|
|
9
|
+
*
|
|
10
|
+
* A cache command's values are kept the same way (the Redis tap keeps 48 characters of an argument, 120 of a reply):
|
|
11
|
+
* `cav_` ids, `<lens dir>/cache/`.
|
|
12
|
+
*/
|
|
13
|
+
export declare const SQL_VALUES_DIR = "sql";
|
|
14
|
+
/** A cache command's values (the Redis tap): the same store, its own folder and id prefix. */
|
|
15
|
+
export declare const CACHE_VALUES_DIR = "cache";
|
|
16
|
+
/** One run's line — what `/api/sql-values?id=` answers. */
|
|
17
|
+
export type SqlValuesLine = DashSqlValues;
|
|
18
|
+
/** One cache command's line. */
|
|
19
|
+
export type CacheValuesLine = DashCacheValues;
|
|
20
|
+
export type KeptValuesLine = DashKeptValues;
|
|
21
|
+
/** `sqv_<yyyymmddhhmm>_<pid>_<n>`: the minute (UTC) and the process name the file. */
|
|
22
|
+
export declare function sqlValuesId(at: number, pid: number, n: number): string;
|
|
23
|
+
/** `cav_<yyyymmddhhmm>_<pid>_<n>`: a cache command's, named as a SQL run's. */
|
|
24
|
+
export declare function cacheValuesId(at: number, pid: number, n: number): string;
|
|
25
|
+
/** The file a kept line is in, under a lens dir — SQL's or a cache command's; `undefined` for anything else. */
|
|
26
|
+
export declare function keptValuesFile(lensDir: string, id: string): string | undefined;
|
|
27
|
+
/** The file a SQL run's line is in; `undefined` for anything that is not such an id. */
|
|
28
|
+
export declare function sqlValuesFile(lensDir: string, id: string): string | undefined;
|
|
29
|
+
export declare function isSqlValuesId(id: unknown): id is string;
|
|
30
|
+
export declare function isCacheValuesId(id: unknown): id is string;
|
|
31
|
+
/**
|
|
32
|
+
* One run's line, or `undefined` — not such an id, not written yet (the tap appends once a second), or pruned (a day).
|
|
33
|
+
* Read line by line and matched by its first field: a busy minute's file is never read whole, nor every line parsed.
|
|
34
|
+
*/
|
|
35
|
+
export declare function readSqlValues(lensDir: string, id: string): Promise<SqlValuesLine | undefined>;
|
|
36
|
+
/** One cache command's line, or `undefined` (as {@link readSqlValues}). */
|
|
37
|
+
export declare function readCacheValues(lensDir: string, id: string): Promise<CacheValuesLine | undefined>;
|
|
38
|
+
/**
|
|
39
|
+
* Several runs' lines at once — each file read once, however many of its runs are asked for (a story names dozens of
|
|
40
|
+
* runs of one minute). What is not there is absent from the map.
|
|
41
|
+
*/
|
|
42
|
+
export declare function readSqlValuesMany(lensDir: string, ids: readonly string[]): Promise<Map<string, SqlValuesLine>>;
|
|
43
|
+
/** {@link readSqlValuesMany} for any kept line — SQL runs' and cache commands' alike. */
|
|
44
|
+
export declare function readKeptValuesMany(lensDir: string, ids: readonly string[]): Promise<Map<string, KeptValuesLine>>;
|
|
45
|
+
/**
|
|
46
|
+
* The statement with one run's values in place of `$1…` — what to paste into psql. A value is a quoted literal
|
|
47
|
+
* Postgres casts to the column's type, `null` is `NULL`, and a `$n` inside a quoted string is left alone.
|
|
48
|
+
* Lock-step with the dashboard's `withValues` (libs/dashboard-ui/src/views/data/sql-model.ts), which cannot import this.
|
|
49
|
+
*/
|
|
50
|
+
export declare function sqlWithValues(sql: string, params: readonly string[] | undefined): string;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";var S=Object.defineProperty;var s=(e,t)=>S(e,"name",{value:t,configurable:!0});var v=Object.defineProperty,o=s((e,t)=>v(e,"name",{value:t,configurable:!0}),"c");import{createReadStream as y}from"node:fs";import{join as $}from"node:path";import{createInterface as g}from"node:readline";export const SQL_VALUES_DIR="sql",CACHE_VALUES_DIR="cache";const d=/^(sqv|cav)_(\d{12})_(\d{1,10})_([0-9a-z]{1,12})$/,q={sqv:SQL_VALUES_DIR,cav:CACHE_VALUES_DIR};export function sqlValuesId(e,t,n){return`sqv_${V(e)}_${t}_${n.toString(36)}`}s(sqlValuesId,"sqlValuesId"),o(sqlValuesId,"sqlValuesId");export function cacheValuesId(e,t,n){return`cav_${V(e)}_${t}_${n.toString(36)}`}s(cacheValuesId,"cacheValuesId"),o(cacheValuesId,"cacheValuesId");export function keptValuesFile(e,t){const n=d.exec(t);return n?$(e,q[n[1]],`${n[3]}-${n[2]}.jsonl`):void 0}s(keptValuesFile,"keptValuesFile"),o(keptValuesFile,"keptValuesFile");export function sqlValuesFile(e,t){return isSqlValuesId(t)?keptValuesFile(e,t):void 0}s(sqlValuesFile,"sqlValuesFile"),o(sqlValuesFile,"sqlValuesFile");export function isSqlValuesId(e){return typeof e=="string"&&d.test(e)&&e.startsWith("sqv_")}s(isSqlValuesId,"isSqlValuesId"),o(isSqlValuesId,"isSqlValuesId");export function isCacheValuesId(e){return typeof e=="string"&&d.test(e)&&e.startsWith("cav_")}s(isCacheValuesId,"isCacheValuesId"),o(isCacheValuesId,"isCacheValuesId");export async function readSqlValues(e,t){return isSqlValuesId(t)?await p(e,t):void 0}s(readSqlValues,"readSqlValues"),o(readSqlValues,"readSqlValues");export async function readCacheValues(e,t){return isCacheValuesId(t)?await p(e,t):void 0}s(readCacheValues,"readCacheValues"),o(readCacheValues,"readCacheValues");async function p(e,t){const n=keptValuesFile(e,t);if(!n)return;const c=`{"id":${JSON.stringify(t)},`,a=y(n,{encoding:"utf8"}),r=g({input:a,crlfDelay:1/0});try{for await(const i of r){if(!i.startsWith(c))continue;const u=JSON.parse(i);return u.id===t?u:void 0}}catch{}finally{r.close(),a.destroy()}}s(p,"h"),o(p,"readKeptValues");export async function readSqlValuesMany(e,t){return await readKeptValuesMany(e,t.filter(isSqlValuesId))}s(readSqlValuesMany,"readSqlValuesMany"),o(readSqlValuesMany,"readSqlValuesMany");export async function readKeptValuesMany(e,t){const n=new Map;for(const a of t){const r=keptValuesFile(e,a);if(!r)continue;const i=n.get(r)??new Set;i.add(a),n.set(r,i)}const c=new Map;for(const[a,r]of n){const i=y(a,{encoding:"utf8"}),u=g({input:i,crlfDelay:1/0});let l=r.size;try{for await(const h of u){const f=/^\{"id":"((?:sqv|cav)_[0-9a-z_]+)",/.exec(h);if(!(!f||!r.has(f[1])||c.has(f[1]))){try{c.set(f[1],JSON.parse(h))}catch{continue}if(--l===0)break}}}catch{}finally{u.close(),i.destroy()}}return c}s(readKeptValuesMany,"readKeptValuesMany"),o(readKeptValuesMany,"readKeptValuesMany");export function sqlWithValues(e,t){if(!t?.length)return e;const n=o(r=>r==="null"||r==="undefined"?"NULL":`'${r.replace(/'/g,"''")}'`,"literal");let c="",a=0;for(;a<e.length;){const r=e[a];if(r==="'"){const u=e.indexOf("'",a+1),l=u<0?e.length:u+1;c+=e.slice(a,l),a=l;continue}const i=r==="$"?/^\$(\d+)/.exec(e.slice(a,a+12)):null;if(i){const u=t[Number(i[1])-1];c+=u===void 0?i[0]:n(u),a+=i[0].length;continue}c+=r,a++}return c}s(sqlWithValues,"sqlWithValues"),o(sqlWithValues,"sqlWithValues");function V(e){const t=new Date(e),n=o(c=>String(c).padStart(2,"0"),"p");return`${t.getUTCFullYear()}${n(t.getUTCMonth()+1)}${n(t.getUTCDate())}${n(t.getUTCHours())}${n(t.getUTCMinutes())}`}s(V,"g"),o(V,"minuteStamp");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lensmcp/core",
|
|
3
|
-
"version": "1.25.
|
|
3
|
+
"version": "1.25.21",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./index.js",
|
|
6
6
|
"module": "./index.js",
|
|
@@ -47,6 +47,21 @@
|
|
|
47
47
|
"import": "./lib/lens-events.js",
|
|
48
48
|
"default": "./lib/lens-events.js"
|
|
49
49
|
},
|
|
50
|
+
"./replay-store": {
|
|
51
|
+
"types": "./lib/replay-store.d.ts",
|
|
52
|
+
"import": "./lib/replay-store.js",
|
|
53
|
+
"default": "./lib/replay-store.js"
|
|
54
|
+
},
|
|
55
|
+
"./sql-values": {
|
|
56
|
+
"types": "./lib/sql-values.d.ts",
|
|
57
|
+
"import": "./lib/sql-values.js",
|
|
58
|
+
"default": "./lib/sql-values.js"
|
|
59
|
+
},
|
|
60
|
+
"./key-pattern": {
|
|
61
|
+
"types": "./lib/key-pattern.d.ts",
|
|
62
|
+
"import": "./lib/key-pattern.js",
|
|
63
|
+
"default": "./lib/key-pattern.js"
|
|
64
|
+
},
|
|
50
65
|
"./ai-content": {
|
|
51
66
|
"types": "./lib/ai-content.d.ts",
|
|
52
67
|
"import": "./lib/ai-content.js",
|
|
@@ -64,7 +79,7 @@
|
|
|
64
79
|
}
|
|
65
80
|
},
|
|
66
81
|
"dependencies": {
|
|
67
|
-
"@lensmcp/protocol-types": "1.25.
|
|
82
|
+
"@lensmcp/protocol-types": "1.25.21",
|
|
68
83
|
"tslib": "^2.3.0"
|
|
69
84
|
},
|
|
70
85
|
"license": "Apache-2.0",
|