@runtimescope/sdk 0.6.0 → 0.6.1
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/dist/index.cjs +5 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +154 -0
- package/dist/index.global.js +1 -1
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +12 -4
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
"use strict";var F=Object.defineProperty;var Y=Object.getOwnPropertyDescriptor;var Z=Object.getOwnPropertyNames;var ee=Object.prototype.hasOwnProperty;var te=(e,t,n)=>t in e?F(e,t,{enumerable:!0,configurable:!0,writable:!0,value:n}):e[t]=n;var ne=(e,t)=>{for(var n in t)F(e,n,{get:t[n],enumerable:!0})},re=(e,t,n,s)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of Z(t))!ee.call(e,r)&&r!==n&&F(e,r,{get:()=>t[r],enumerable:!(s=Y(t,r))||s.enumerable});return e};var se=e=>re(F({},"__esModule",{value:!0}),e);var h=(e,t,n)=>te(e,typeof t!="symbol"?t+"":t,n);var Te={};ne(Te,{RuntimeScope:()=>I,default:()=>Ce});module.exports=se(Te);var N=console.debug.bind(console),T=class T{constructor(t){h(this,"ws",null);h(this,"batch",[]);h(this,"offlineQueue",[]);h(this,"flushTimer",null);h(this,"reconnectTimer",null);h(this,"reconnectDelay",1e3);h(this,"connected",!1);h(this,"stopped",!1);h(this,"config");h(this,"commandHandler",null);this.config=t}connect(){this.stopped=!1,this.doConnect()}doConnect(){if(!this.stopped){try{this.ws=new WebSocket(this.config.serverUrl)}catch{this.scheduleReconnect();return}this.ws.onmessage=t=>{try{let n=JSON.parse(String(t.data));n.type==="command"&&n.payload&&this.commandHandler&&this.commandHandler(n.payload),n.type==="error"&&n.payload?.code==="AUTH_FAILED"&&(N("[RuntimeScope] Authentication failed \u2014 stopping reconnection"),this.stopped=!0)}catch{}},this.ws.onopen=()=>{if(this.connected=!0,this.reconnectDelay=1e3,N(`[RuntimeScope] Connected to ${this.config.serverUrl}`),this.sendRaw({type:"handshake",payload:{appName:this.config.appName,sdkVersion:this.config.sdkVersion,sessionId:this.config.sessionId,...this.config.authToken?{authToken:this.config.authToken}:{}},timestamp:Date.now(),sessionId:this.config.sessionId}),this.offlineQueue.length>0){let t=this.offlineQueue.splice(0);for(let n of t)this.batch.push(n);this.flush()}this.flushTimer=setInterval(()=>this.flush(),this.config.flushIntervalMs)},this.ws.onclose=()=>{this.connected=!1,this.clearFlushTimer(),this.stopped||(N("[RuntimeScope] Disconnected, will reconnect..."),this.scheduleReconnect())},this.ws.onerror=()=>{N(`[RuntimeScope] WebSocket error connecting to ${this.config.serverUrl}`)}}}send(t){this.connected?(this.batch.push(t),this.batch.length>=this.config.batchSize&&this.flush()):this.offlineQueue.length<T.MAX_OFFLINE_QUEUE&&this.offlineQueue.push(t)}flush(){if(this.batch.length===0||!this.connected||!this.ws)return;let t=this.batch.splice(0);this.sendRaw({type:"event",payload:{events:t},timestamp:Date.now(),sessionId:this.config.sessionId})}sendRaw(t){if(this.ws&&this.ws.readyState===WebSocket.OPEN)try{this.ws.send(JSON.stringify(t))}catch{}}scheduleReconnect(){if(this.stopped||this.reconnectTimer)return;let t=this.reconnectDelay*.25*(Math.random()*2-1),n=Math.min(this.reconnectDelay+t,T.MAX_RECONNECT_DELAY);this.reconnectTimer=setTimeout(()=>{this.reconnectTimer=null,this.reconnectDelay=Math.min(this.reconnectDelay*2,T.MAX_RECONNECT_DELAY),this.doConnect()},n)}clearFlushTimer(){this.flushTimer&&(clearInterval(this.flushTimer),this.flushTimer=null)}onCommand(t){this.commandHandler=t}sendCommandResponse(t,n,s){this.sendRaw({type:"command_response",requestId:t,command:n,payload:s,timestamp:Date.now(),sessionId:this.config.sessionId})}disconnect(){this.stopped=!0,this.clearFlushTimer(),this.reconnectTimer&&(clearTimeout(this.reconnectTimer),this.reconnectTimer=null),this.flush(),this.ws&&(this.ws.onclose=null,this.ws.onerror=null,this.ws.close(),this.ws=null),this.connected=!1,this.batch=[],this.offlineQueue=[]}};h(T,"MAX_OFFLINE_QUEUE",1e3),h(T,"MAX_RECONNECT_DELAY",3e4);var B=T;function l(){let e=new Uint8Array(4);return crypto.getRandomValues(e),Array.from(e,t=>t.toString(16).padStart(2,"0")).join("")}function A(){let e=new Uint8Array(16);return crypto.getRandomValues(e),Array.from(e,t=>t.toString(16).padStart(2,"0")).join("")}var M=new Set;function q(e,t,n,s){let r=window.fetch,c=new Set(n.map(i=>i.toLowerCase())),o=s?.captureBody??!1,a=s?.maxBodySize??65536;return window.fetch=async function(i,u){let d=performance.now(),p=typeof i=="string"?i:i instanceof URL?i.href:i.url,g=(u?.method??"GET").toUpperCase(),E=oe(u?.headers,c),y=ae(u?.body),_=ue(u?.body),k;o&&u?.body&&(k=ce(u.body,a));let S=`${g}:${p}:${d}`;M.add(S),setTimeout(()=>M.delete(S),5e3);try{let m=await r.call(window,i,u),L=performance.now()-d,b=parseInt(m.headers.get("content-length")||"0",10),f=ie(m.headers,c),w;if(o)try{let C=await m.clone().text();w=C.length>a?C.slice(0,a):C}catch{}let R={eventId:l(),sessionId:t,timestamp:Date.now(),eventType:"network",url:p,method:g,status:m.status,requestHeaders:E,responseHeaders:f,requestBodySize:y,responseBodySize:b,duration:L,ttfb:L,graphqlOperation:_,requestBody:k,responseBody:w,source:"fetch"};if(s?.beforeSend){let O=s.beforeSend(R);O&&e(O)}else e(R);return m}catch(m){let L=performance.now()-d,b="error",f="";m instanceof DOMException&&m.name==="AbortError"?(b="abort",f="Request aborted"):m instanceof Error&&(f=m.message);let w={eventId:l(),sessionId:t,timestamp:Date.now(),eventType:"network",url:p,method:g,status:0,requestHeaders:E,responseHeaders:{},requestBodySize:y,responseBodySize:0,duration:L,ttfb:0,graphqlOperation:_,requestBody:k,errorPhase:b,errorMessage:f,source:"fetch"};if(s?.beforeSend){let R=s.beforeSend(w);R&&e(R)}else e(w);throw m}},()=>{window.fetch=r}}function oe(e,t){let n={};if(!e)return n;if(e instanceof Headers)e.forEach((s,r)=>{n[r]=t.has(r.toLowerCase())?"[REDACTED]":s});else if(Array.isArray(e))for(let[s,r]of e)n[s]=t.has(s.toLowerCase())?"[REDACTED]":r;else for(let[s,r]of Object.entries(e))n[s]=t.has(s.toLowerCase())?"[REDACTED]":r;return n}function ie(e,t){let n={};return e.forEach((s,r)=>{n[r]=t.has(r.toLowerCase())?"[REDACTED]":s}),n}function ae(e){return e?typeof e=="string"?new Blob([e]).size:e instanceof Blob?e.size:e instanceof ArrayBuffer||ArrayBuffer.isView(e)?e.byteLength:e instanceof FormData?0:e instanceof URLSearchParams?new Blob([e.toString()]).size:0:0}function ce(e,t){if(e){if(typeof e=="string")return e.length>t?e.slice(0,t):e;if(e instanceof URLSearchParams){let n=e.toString();return n.length>t?n.slice(0,t):n}if(e instanceof FormData)return"[FormData]";if(e instanceof Blob)return`[Blob ${e.size} bytes]`;if(e instanceof ArrayBuffer)return`[ArrayBuffer ${e.byteLength} bytes]`;if(ArrayBuffer.isView(e))return`[TypedArray ${e.byteLength} bytes]`}}function ue(e){if(!(!e||typeof e!="string"))try{let t=JSON.parse(e);if(typeof t.query=="string"){let n=t.query.trim(),s="query";n.startsWith("mutation")?s="mutation":n.startsWith("subscription")&&(s="subscription");let r=t.operationName||de(n)||"anonymous";return{type:s,name:r}}}catch{}}function de(e){return e.match(/^(?:query|mutation|subscription)\s+(\w+)/)?.[1]}function v(e,t=5){let n=new WeakSet;function s(r,c){if(c>t)return"[max depth]";if(r==null)return r;if(typeof r=="function")return`[Function: ${r.name||"anonymous"}]`;if(typeof r=="symbol"||typeof r=="bigint")return r.toString();if(typeof r!="object")return r;if(r instanceof Error)return{name:r.name,message:r.message,stack:r.stack};if(r instanceof Date)return r.toISOString();if(r instanceof RegExp)return r.toString();if(n.has(r))return"[Circular]";if(n.add(r),Array.isArray(r))return r.map(a=>s(a,c+1));let o={};for(let a of Object.keys(r))o[a]=s(r[a],c+1);return o}return s(e,0)}var z=["log","warn","error","info","debug","trace"];function j(e,t,n){let s={};for(let r of z)s[r]=console[r].bind(console),console[r]=(...c)=>{let o=c.map(i=>typeof i=="string"?i:pe(i)).join(" "),a={eventId:l(),sessionId:t,timestamp:Date.now(),eventType:"console",level:r,message:o,args:c.map(i=>v(i,3)),stackTrace:r==="error"||r==="trace"?new Error().stack?.split(`
|
|
2
|
+
`).slice(2).join(`
|
|
3
|
+
`):void 0,sourceFile:void 0};if(n){let i=n(a);i&&e(i)}else e(a);s[r](...c)};return()=>{for(let r of z)console[r]=s[r]}}function pe(e){try{return JSON.stringify(e)}catch{return String(e)}}function X(e,t,n,s){let r=new Set(n.map(d=>d.toLowerCase())),c=s?.captureBody??!1,o=s?.maxBodySize??65536,a=XMLHttpRequest.prototype.open,i=XMLHttpRequest.prototype.setRequestHeader,u=XMLHttpRequest.prototype.send;return XMLHttpRequest.prototype.open=function(d,p){return this.__rs_method=d.toUpperCase(),this.__rs_url=typeof p=="string"?p:p.href,this.__rs_headers={},a.apply(this,arguments)},XMLHttpRequest.prototype.setRequestHeader=function(d,p){return this.__rs_headers&&(this.__rs_headers[d.toLowerCase()]=r.has(d.toLowerCase())?"[REDACTED]":p),i.call(this,d,p)},XMLHttpRequest.prototype.send=function(d){let p=this.__rs_method??"GET",g=this.__rs_url??"",E=`${p}:${g}`;if(Array.from(M).some(f=>f.startsWith(E)))return this.__rs_fetchIntercepted=!0,u.call(this,d);let _={...this.__rs_headers??{}},k=performance.now(),S,m=0;if(d){if(typeof d=="string")m=new Blob([d]).size,c&&(S=d.length>o?d.slice(0,o):d);else if(d instanceof Blob)m=d.size,c&&(S=`[Blob ${d.size} bytes]`);else if(d instanceof ArrayBuffer)m=d.byteLength,c&&(S=`[ArrayBuffer ${d.byteLength} bytes]`);else if(d instanceof FormData)c&&(S="[FormData]");else if(d instanceof URLSearchParams){let f=d.toString();m=new Blob([f]).size,c&&(S=f.length>o?f.slice(0,o):f)}}let L=le(d),b=f=>{let w={eventId:l(),sessionId:t,timestamp:Date.now(),eventType:"network",url:g,method:p,status:0,requestHeaders:_,responseHeaders:{},requestBodySize:m,responseBodySize:0,duration:0,ttfb:0,graphqlOperation:L,requestBody:S,source:"xhr",...f};if(s?.beforeSend){let R=s.beforeSend(w);R&&e(R)}else e(w)};return this.addEventListener("load",()=>{let f=performance.now()-k,w=fe(this.getAllResponseHeaders(),r),R=parseInt(this.getResponseHeader("content-length")||"0",10),O;if(c&&this.responseType===""||this.responseType==="text")try{let C=this.responseText;O=C.length>o?C.slice(0,o):C}catch{}b({status:this.status,responseHeaders:w,responseBodySize:R,responseBody:O,duration:f,ttfb:f})}),this.addEventListener("error",()=>{let f=performance.now()-k;b({duration:f,errorPhase:"error",errorMessage:"Network error"})}),this.addEventListener("abort",()=>{let f=performance.now()-k;b({duration:f,errorPhase:"abort",errorMessage:"Request aborted"})}),this.addEventListener("timeout",()=>{let f=performance.now()-k;b({duration:f,errorPhase:"timeout",errorMessage:`Request timed out after ${this.timeout}ms`})}),u.call(this,d)},()=>{XMLHttpRequest.prototype.open=a,XMLHttpRequest.prototype.setRequestHeader=i,XMLHttpRequest.prototype.send=u}}function fe(e,t){let n={};if(!e)return n;for(let s of e.trim().split(/[\r\n]+/)){let r=s.indexOf(":");if(r===-1)continue;let c=s.slice(0,r).trim().toLowerCase(),o=s.slice(r+1).trim();n[c]=t.has(c)?"[REDACTED]":o}return n}function le(e){if(!(!e||typeof e!="string"))try{let t=JSON.parse(e);if(typeof t.query=="string"){let n=t.query.trim(),s="query";n.startsWith("mutation")?s="mutation":n.startsWith("subscription")&&(s="subscription");let r=t.operationName||me(n)||"anonymous";return{type:s,name:r}}}catch{}}function me(e){return e.match(/^(?:query|mutation|subscription)\s+(\w+)/)?.[1]}function $(e,t,n,s){let r=[],c=new Map;for(let[o,a]of Object.entries(n)){let i=he(a);if(i==="zustand"){let u=a;x(e,t,s?.beforeSend,{storeId:o,library:i,phase:"init",state:v(u.getState(),4)});let d=u.subscribe((p,g)=>{let E=U(g,p);x(e,t,s?.beforeSend,{storeId:o,library:i,phase:"update",state:v(p,4),previousState:v(g,4),diff:E?v(E,3):void 0})});r.push(d)}else if(i==="redux"){let u=a;x(e,t,s?.beforeSend,{storeId:o,library:i,phase:"init",state:v(u.getState(),4)});let d,p=u.dispatch.bind(u);c.set(o,p),u.dispatch=y=>(y&&typeof y=="object"&&"type"in y&&(d={type:String(y.type),payload:y.payload}),p(y));let g=u.getState(),E=u.subscribe(()=>{let y=u.getState(),_=U(g,y);x(e,t,s?.beforeSend,{storeId:o,library:i,phase:"update",state:v(y,4),previousState:v(g,4),diff:_?v(_,3):void 0,action:d?v(d,3):void 0}),g=y,d=void 0});r.push(E)}}return()=>{for(let o of r)o();for(let[o,a]of c){let i=n[o];i&&(i.dispatch=a)}}}function he(e){if(!e||typeof e!="object")return"unknown";let t=e;return typeof t.getState=="function"&&typeof t.setState=="function"&&typeof t.subscribe=="function"?"zustand":typeof t.dispatch=="function"&&typeof t.getState=="function"&&typeof t.subscribe=="function"?"redux":"unknown"}function U(e,t){if(!e||!t||typeof e!="object"||typeof t!="object")return null;let n={},s=e,r=t,c=new Set([...Object.keys(s),...Object.keys(r)]);for(let o of c)s[o]!==r[o]&&(n[o]={from:s[o],to:r[o]});return Object.keys(n).length>0?n:null}function x(e,t,n,s){let r={eventId:l(),sessionId:t,timestamp:Date.now(),eventType:"state",...s};if(n){let c=n(r);c&&e(c)}else e(r)}var ge={LCP:[2500,4e3],FCP:[1800,3e3],CLS:[.1,.25],TTFB:[800,1800],FID:[100,300],INP:[200,500]};function ve(e,t){let[n,s]=ge[e]??[1/0,1/0];return t<=n?"good":t<=s?"needs-improvement":"poor"}function V(e,t,n){let s=[],r=(a,i,u)=>{let d={eventId:l(),sessionId:t,timestamp:Date.now(),eventType:"performance",metricName:a,value:Math.round(i*100)/100,rating:ve(a,i),element:u};if(n?.beforeSend){let p=n.beforeSend(d);p&&e(p)}else e(d)};D(s,"largest-contentful-paint",a=>{let i=a[a.length-1];if(!i)return;let u=i.element;r("LCP",i.startTime,u?.tagName?.toLowerCase())}),D(s,"paint",a=>{for(let i of a)i.name==="first-contentful-paint"&&r("FCP",i.startTime)});let c=0;D(s,"layout-shift",a=>{for(let i of a){let u=i;!u.hadRecentInput&&u.value&&(c+=u.value,r("CLS",c))}}),D(s,"first-input",a=>{let i=a[0];if(!i)return;let u=i;u.processingStart&&r("FID",u.processingStart-i.startTime)}),D(s,"navigation",a=>{let i=a[0];i&&r("TTFB",i.responseStart-i.requestStart)});let o=0;return D(s,"event",a=>{for(let i of a)i.duration>o&&(o=i.duration,r("INP",o))},{durationThreshold:16}),()=>{for(let a of s)try{a.disconnect()}catch{}}}function D(e,t,n,s){try{let r=new PerformanceObserver(c=>{n(c.getEntries())});r.observe({type:t,buffered:!0,...s}),e.push(r)}catch{}}var ye=0,we=1,W=1e4,Q=100;function G(e,t,n){let s=new Map,r=n?.snapshotIntervalMs??5e3,c=null,o=Re();if(!o)return()=>{};let a=o.onCommitFiberRoot;return o._runtimescope_original=a,o.onCommitFiberRoot=(i,u)=>{if(a)try{a(i,u)}catch{}u.current&&H(u.current,s)},c=setInterval(()=>{_e(s,e,t,n?.beforeSend)},r),()=>{c&&(clearInterval(c),c=null),o&&(o._runtimescope_original?o.onCommitFiberRoot=o._runtimescope_original:delete o.onCommitFiberRoot,delete o._runtimescope_original)}}function Re(){if(typeof window>"u")return null;let e=window;return e.__REACT_DEVTOOLS_GLOBAL_HOOK__||(e.__REACT_DEVTOOLS_GLOBAL_HOOK__={}),e.__REACT_DEVTOOLS_GLOBAL_HOOK__}function H(e,t){Ee(e,t),e.child&&H(e.child,t),e.sibling&&H(e.sibling,t)}function Ee(e,t){if(e.tag!==ye&&e.tag!==we)return;let n=Se(e);if(!n)return;let s=Date.now(),r=e.alternate===null,c=e.actualDuration??0,o=be(e,r),a=t.get(n);a||(a={renderCount:0,totalDuration:0,lastRenderTime:0,lastRenderPhase:"mount",lastRenderCause:"unknown",renderTimestamps:[]},t.set(n,a)),a.renderCount++,a.totalDuration+=c,a.lastRenderTime=s,a.lastRenderPhase=r?"mount":"update",a.lastRenderCause=o,a.renderTimestamps.push(s),a.renderTimestamps.length>Q&&(a.renderTimestamps=a.renderTimestamps.slice(-Q))}function Se(e){if(e.type&&typeof e.type!="string")return e.type.displayName||e.type.name||void 0}function be(e,t){return t?"props":e.alternate?e.memoizedProps!==e.alternate.memoizedProps?"props":e.memoizedState!==e.alternate.memoizedState?"state":"parent":"unknown"}function ke(e){if(e.length<2)return 0;let t=Date.now(),n=t-W,s=e.filter(c=>c>=n);if(s.length<2)return 0;let r=t-s[0];return r===0?0:s.length/(r/1e3)}function _e(e,t,n,s){if(e.size===0)return;let r=[],c=[],o=0;for(let[i,u]of e){let d=ke(u.renderTimestamps),p=d>4||u.renderCount>20;r.push({componentName:i,renderCount:u.renderCount,totalDuration:Math.round(u.totalDuration*100)/100,avgDuration:u.renderCount>0?Math.round(u.totalDuration/u.renderCount*100)/100:0,lastRenderPhase:u.lastRenderPhase,lastRenderCause:u.lastRenderCause,renderVelocity:Math.round(d*100)/100,suspicious:p}),p&&c.push(i),o+=u.renderCount}r.sort((i,u)=>u.renderCount-i.renderCount);let a={eventId:l(),sessionId:n,timestamp:Date.now(),eventType:"render",profiles:r,snapshotWindowMs:W,totalRenders:o,suspiciousComponents:c};if(s){let i=s(a);i&&t(i)}else t(a);for(let i of e.values())i.renderCount=0,i.totalDuration=0}function K(e,t,n){let s=c=>{let o,a,i;if(c instanceof ErrorEvent)o=c.message||"Uncaught error",a=c.error?.stack,i=c.filename?`${c.filename}:${c.lineno}:${c.colno}`:void 0;else{let d=c.target;if(d&&d!==window){let p=d.tagName?.toLowerCase()??"unknown",g=d.src??d.src??d.href??"unknown";o=`Failed to load resource: <${p}> ${g}`}else return}let u={eventId:l(),sessionId:t,timestamp:Date.now(),eventType:"console",level:"error",message:`[Uncaught] ${o}`,args:[v(o,3)],stackTrace:a,sourceFile:i};if(n){let d=n(u);d&&e(d)}else e(u)},r=c=>{let o=c.reason,a,i;if(o instanceof Error)a=o.message,i=o.stack;else if(typeof o=="string")a=o;else try{a=JSON.stringify(o)}catch{a=String(o)}let u={eventId:l(),sessionId:t,timestamp:Date.now(),eventType:"console",level:"error",message:`[Unhandled Rejection] ${a}`,args:[v(o,3)],stackTrace:i,sourceFile:void 0};if(n){let d=n(u);d&&e(d)}else e(u)};return window.addEventListener("error",s,!0),window.addEventListener("unhandledrejection",r),()=>{window.removeEventListener("error",s,!0),window.removeEventListener("unhandledrejection",r)}}var P="0.6.1",J=console.debug.bind(console),I=class{static get sessionId(){return this._sessionId}static connect(t={}){if(t.enabled===!1)return;this.transport&&this.disconnect();let n={serverUrl:t.serverUrl??t.endpoint??"ws://localhost:9090",appName:t.appName??"unknown",captureNetwork:t.captureNetwork??!0,captureConsole:t.captureConsole??!0,captureXhr:t.captureXhr??!0,captureBody:t.captureBody??!1,maxBodySize:t.maxBodySize??65536,capturePerformance:t.capturePerformance??!1,captureRenders:t.captureRenders??!1,stores:t.stores??{},beforeSend:t.beforeSend,redactHeaders:t.redactHeaders??["authorization","cookie"],batchSize:t.batchSize??50,flushIntervalMs:t.flushIntervalMs??100};this._sessionId=A(),this.transport=new B({serverUrl:n.serverUrl,appName:n.appName,sessionId:this._sessionId,sdkVersion:P,authToken:t.authToken,batchSize:n.batchSize,flushIntervalMs:n.flushIntervalMs}),this.transport.connect(),J(`[RuntimeScope] SDK v${P} initializing \u2014 app: ${n.appName}, server: ${n.serverUrl}`);let s=o=>this.transport?.send(o);s({eventId:l(),sessionId:this._sessionId,timestamp:Date.now(),eventType:"session",appName:n.appName,connectedAt:Date.now(),sdkVersion:P,buildMeta:t.buildMeta});let r=this._sessionId;this.transport.onCommand(o=>{this.handleCommand(o,s,r)}),n.captureNetwork&&this.restoreFns.push(q(s,this._sessionId,n.redactHeaders,{captureBody:n.captureBody,maxBodySize:n.maxBodySize,beforeSend:n.beforeSend})),n.captureXhr&&this.restoreFns.push(X(s,this._sessionId,n.redactHeaders,{captureBody:n.captureBody,maxBodySize:n.maxBodySize,beforeSend:n.beforeSend})),n.captureConsole&&(this.restoreFns.push(j(s,this._sessionId,n.beforeSend)),this.restoreFns.push(K(s,this._sessionId,n.beforeSend))),Object.keys(n.stores).length>0&&this.restoreFns.push($(s,this._sessionId,n.stores,{beforeSend:n.beforeSend})),n.capturePerformance&&this.restoreFns.push(V(s,this._sessionId,{beforeSend:n.beforeSend})),n.captureRenders&&this.restoreFns.push(G(s,this._sessionId,{beforeSend:n.beforeSend}));let c=[n.captureNetwork&&"fetch",n.captureXhr&&"xhr",n.captureConsole&&"console, errors",Object.keys(n.stores).length>0&&"state",n.capturePerformance&&"performance",n.captureRenders&&"renders"].filter(Boolean);J(`[RuntimeScope] Interceptors active \u2014 ${c.join(", ")}`)}static handleCommand(t,n,s){if(t.command==="capture_dom_snapshot"){let r=t.params?.maxSize??5e5,c=document.documentElement.outerHTML,o=c.length>r;o&&(c=c.slice(0,r));let a={eventId:l(),sessionId:s,timestamp:Date.now(),eventType:"dom_snapshot",html:c,url:window.location.href,viewport:{width:window.innerWidth,height:window.innerHeight},scrollPosition:{x:window.scrollX,y:window.scrollY},elementCount:document.querySelectorAll("*").length,truncated:o};n(a),this.transport?.sendCommandResponse(t.requestId,t.command,a)}else this.transport?.sendCommandResponse(t.requestId,t.command,{error:"Unknown command"})}static init(t={}){return this.connect(t)}static disconnect(){for(let t of this.restoreFns)t();this.restoreFns=[],this.transport?.disconnect(),this.transport=null,this._sessionId=null}};h(I,"transport",null),h(I,"restoreFns",[]),h(I,"_sessionId",null);var Ce=I;0&&(module.exports={RuntimeScope});
|
|
4
|
+
if(typeof RuntimeScope!=="undefined"&&RuntimeScope.RuntimeScope){RuntimeScope=RuntimeScope.RuntimeScope;}
|
|
5
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/transport.ts","../src/utils/id.ts","../src/interceptors/fetch.ts","../src/utils/serialize.ts","../src/interceptors/console.ts","../src/interceptors/xhr.ts","../src/interceptors/state-stores.ts","../src/interceptors/performance.ts","../src/interceptors/react-renders.ts","../src/interceptors/errors.ts"],"sourcesContent":["import { Transport } from './transport.js';\nimport { interceptFetch } from './interceptors/fetch.js';\nimport { interceptConsole } from './interceptors/console.js';\nimport { interceptXhr } from './interceptors/xhr.js';\nimport { interceptStateStores } from './interceptors/state-stores.js';\nimport { interceptPerformance } from './interceptors/performance.js';\nimport { interceptReactRenders } from './interceptors/react-renders.js';\nimport { interceptErrors } from './interceptors/errors.js';\nimport { generateId, generateSessionId } from './utils/id.js';\nimport type { RuntimeScopeConfig, RuntimeEvent, DomSnapshotEvent } from './types.js';\n\nconst SDK_VERSION = '0.6.1';\n\n// Save original console.debug BEFORE interceptors patch it.\n// debug-level messages are hidden by default in Chrome DevTools.\nconst _log = console.debug.bind(console);\n\nexport class RuntimeScope {\n private static transport: Transport | null = null;\n private static restoreFns: (() => void)[] = [];\n private static _sessionId: string | null = null;\n\n static get sessionId(): string | null {\n return this._sessionId;\n }\n\n static connect(config: RuntimeScopeConfig = {}): void {\n if (config.enabled === false) return;\n if (this.transport) this.disconnect();\n\n const resolved = {\n serverUrl: config.serverUrl ?? config.endpoint ?? 'ws://localhost:9090',\n appName: config.appName ?? 'unknown',\n captureNetwork: config.captureNetwork ?? true,\n captureConsole: config.captureConsole ?? true,\n captureXhr: config.captureXhr ?? true,\n captureBody: config.captureBody ?? false,\n maxBodySize: config.maxBodySize ?? 65536,\n capturePerformance: config.capturePerformance ?? false,\n captureRenders: config.captureRenders ?? false,\n stores: config.stores ?? {},\n beforeSend: config.beforeSend,\n redactHeaders: config.redactHeaders ?? ['authorization', 'cookie'],\n batchSize: config.batchSize ?? 50,\n flushIntervalMs: config.flushIntervalMs ?? 100,\n };\n\n this._sessionId = generateSessionId();\n\n this.transport = new Transport({\n serverUrl: resolved.serverUrl,\n appName: resolved.appName,\n sessionId: this._sessionId,\n sdkVersion: SDK_VERSION,\n authToken: config.authToken,\n batchSize: resolved.batchSize,\n flushIntervalMs: resolved.flushIntervalMs,\n });\n\n this.transport.connect();\n _log(`[RuntimeScope] SDK v${SDK_VERSION} initializing — app: ${resolved.appName}, server: ${resolved.serverUrl}`);\n\n const emit = (event: RuntimeEvent) => this.transport?.send(event);\n\n // Send session event\n emit({\n eventId: generateId(),\n sessionId: this._sessionId,\n timestamp: Date.now(),\n eventType: 'session',\n appName: resolved.appName,\n connectedAt: Date.now(),\n sdkVersion: SDK_VERSION,\n buildMeta: config.buildMeta,\n });\n\n // Register command handler for server→SDK commands\n const sessionId = this._sessionId;\n this.transport.onCommand((cmd: { command: string; requestId: string; params?: Record<string, unknown> }) => {\n this.handleCommand(cmd, emit, sessionId);\n });\n\n // Fetch interceptor\n if (resolved.captureNetwork) {\n this.restoreFns.push(\n interceptFetch(emit, this._sessionId, resolved.redactHeaders, {\n captureBody: resolved.captureBody,\n maxBodySize: resolved.maxBodySize,\n beforeSend: resolved.beforeSend,\n })\n );\n }\n\n // XHR interceptor\n if (resolved.captureXhr) {\n this.restoreFns.push(\n interceptXhr(emit, this._sessionId, resolved.redactHeaders, {\n captureBody: resolved.captureBody,\n maxBodySize: resolved.maxBodySize,\n beforeSend: resolved.beforeSend,\n })\n );\n }\n\n // Console interceptor\n if (resolved.captureConsole) {\n this.restoreFns.push(\n interceptConsole(emit, this._sessionId, resolved.beforeSend)\n );\n // Also capture uncaught errors, resource load failures, and unhandled rejections\n // These appear in DevTools console but don't go through console.* API\n this.restoreFns.push(\n interceptErrors(emit, this._sessionId, resolved.beforeSend)\n );\n }\n\n // State store inspection\n if (Object.keys(resolved.stores).length > 0) {\n this.restoreFns.push(\n interceptStateStores(emit, this._sessionId, resolved.stores, {\n beforeSend: resolved.beforeSend,\n })\n );\n }\n\n // Performance metrics (Web Vitals)\n if (resolved.capturePerformance) {\n this.restoreFns.push(\n interceptPerformance(emit, this._sessionId, {\n beforeSend: resolved.beforeSend,\n })\n );\n }\n\n // React render tracking\n if (resolved.captureRenders) {\n this.restoreFns.push(\n interceptReactRenders(emit, this._sessionId, {\n beforeSend: resolved.beforeSend,\n })\n );\n }\n\n const features = [\n resolved.captureNetwork && 'fetch',\n resolved.captureXhr && 'xhr',\n resolved.captureConsole && 'console, errors',\n Object.keys(resolved.stores).length > 0 && 'state',\n resolved.capturePerformance && 'performance',\n resolved.captureRenders && 'renders',\n ].filter(Boolean);\n _log(`[RuntimeScope] Interceptors active — ${features.join(', ')}`);\n }\n\n private static handleCommand(\n cmd: { command: string; requestId: string; params?: Record<string, unknown> },\n emit: (event: RuntimeEvent) => void,\n sessionId: string\n ): void {\n switch (cmd.command) {\n case 'capture_dom_snapshot': {\n const maxSize = (cmd.params?.maxSize as number) ?? 500_000;\n let html = document.documentElement.outerHTML;\n const truncated = html.length > maxSize;\n if (truncated) html = html.slice(0, maxSize);\n\n const snapshot: DomSnapshotEvent = {\n eventId: generateId(),\n sessionId,\n timestamp: Date.now(),\n eventType: 'dom_snapshot',\n html,\n url: window.location.href,\n viewport: { width: window.innerWidth, height: window.innerHeight },\n scrollPosition: { x: window.scrollX, y: window.scrollY },\n elementCount: document.querySelectorAll('*').length,\n truncated,\n };\n\n emit(snapshot);\n this.transport?.sendCommandResponse(cmd.requestId, cmd.command, snapshot);\n break;\n }\n default:\n this.transport?.sendCommandResponse(cmd.requestId, cmd.command, { error: 'Unknown command' });\n }\n }\n\n /** Alias for `connect` — used by script-tag snippets */\n static init(config: RuntimeScopeConfig = {}): void {\n return this.connect(config);\n }\n\n static disconnect(): void {\n for (const fn of this.restoreFns) fn();\n this.restoreFns = [];\n this.transport?.disconnect();\n this.transport = null;\n this._sessionId = null;\n }\n}\n\nexport default RuntimeScope;\nexport type {\n RuntimeScopeConfig,\n BuildMeta,\n NetworkEvent,\n ConsoleEvent,\n SessionEvent,\n StateEvent,\n RenderEvent,\n DomSnapshotEvent,\n PerformanceEvent,\n RuntimeEvent,\n} from './types.js';\n","import type { RuntimeEvent } from './types.js';\n\n// Save original console.debug BEFORE any interceptors patch it.\n// debug-level messages are hidden by default in Chrome DevTools.\nconst _log = console.debug.bind(console);\n\ninterface TransportConfig {\n serverUrl: string;\n appName: string;\n sessionId: string;\n sdkVersion: string;\n authToken?: string;\n batchSize: number;\n flushIntervalMs: number;\n}\n\nexport class Transport {\n private ws: WebSocket | null = null;\n private batch: RuntimeEvent[] = [];\n private offlineQueue: RuntimeEvent[] = [];\n private flushTimer: ReturnType<typeof setInterval> | null = null;\n private reconnectTimer: ReturnType<typeof setTimeout> | null = null;\n private reconnectDelay = 1000;\n private connected = false;\n private stopped = false;\n private config: TransportConfig;\n private commandHandler: ((cmd: { command: string; requestId: string; params?: Record<string, unknown> }) => void) | null = null;\n\n private static readonly MAX_OFFLINE_QUEUE = 1000;\n private static readonly MAX_RECONNECT_DELAY = 30_000;\n\n constructor(config: TransportConfig) {\n this.config = config;\n }\n\n connect(): void {\n this.stopped = false;\n this.doConnect();\n }\n\n private doConnect(): void {\n if (this.stopped) return;\n\n try {\n this.ws = new WebSocket(this.config.serverUrl);\n } catch {\n this.scheduleReconnect();\n return;\n }\n\n this.ws.onmessage = (event: MessageEvent) => {\n try {\n const msg = JSON.parse(String(event.data));\n if (msg.type === 'command' && msg.payload && this.commandHandler) {\n this.commandHandler(msg.payload);\n }\n // Handle auth rejection — stop reconnecting\n if (msg.type === 'error' && msg.payload?.code === 'AUTH_FAILED') {\n _log('[RuntimeScope] Authentication failed — stopping reconnection');\n this.stopped = true;\n }\n } catch {\n // Ignore unparseable messages\n }\n };\n\n this.ws.onopen = () => {\n this.connected = true;\n this.reconnectDelay = 1000;\n _log(`[RuntimeScope] Connected to ${this.config.serverUrl}`);\n\n // Send handshake\n this.sendRaw({\n type: 'handshake',\n payload: {\n appName: this.config.appName,\n sdkVersion: this.config.sdkVersion,\n sessionId: this.config.sessionId,\n ...(this.config.authToken ? { authToken: this.config.authToken } : {}),\n },\n timestamp: Date.now(),\n sessionId: this.config.sessionId,\n });\n\n // Flush offline queue\n if (this.offlineQueue.length > 0) {\n const queued = this.offlineQueue.splice(0);\n for (const event of queued) {\n this.batch.push(event);\n }\n this.flush();\n }\n\n // Start periodic flush\n this.flushTimer = setInterval(() => this.flush(), this.config.flushIntervalMs);\n };\n\n this.ws.onclose = () => {\n this.connected = false;\n this.clearFlushTimer();\n if (!this.stopped) {\n _log(`[RuntimeScope] Disconnected, will reconnect...`);\n this.scheduleReconnect();\n }\n };\n\n this.ws.onerror = () => {\n _log(`[RuntimeScope] WebSocket error connecting to ${this.config.serverUrl}`);\n };\n }\n\n send(event: RuntimeEvent): void {\n if (this.connected) {\n this.batch.push(event);\n if (this.batch.length >= this.config.batchSize) {\n this.flush();\n }\n } else {\n // Queue for when we reconnect\n if (this.offlineQueue.length < Transport.MAX_OFFLINE_QUEUE) {\n this.offlineQueue.push(event);\n }\n }\n }\n\n private flush(): void {\n if (this.batch.length === 0 || !this.connected || !this.ws) return;\n\n const events = this.batch.splice(0);\n this.sendRaw({\n type: 'event',\n payload: { events },\n timestamp: Date.now(),\n sessionId: this.config.sessionId,\n });\n }\n\n private sendRaw(msg: unknown): void {\n if (this.ws && this.ws.readyState === WebSocket.OPEN) {\n try {\n this.ws.send(JSON.stringify(msg));\n } catch {\n // Drop silently — reconnect will handle it\n }\n }\n }\n\n private scheduleReconnect(): void {\n if (this.stopped || this.reconnectTimer) return;\n\n // Exponential backoff with jitter\n const jitter = this.reconnectDelay * 0.25 * (Math.random() * 2 - 1);\n const delay = Math.min(this.reconnectDelay + jitter, Transport.MAX_RECONNECT_DELAY);\n\n this.reconnectTimer = setTimeout(() => {\n this.reconnectTimer = null;\n this.reconnectDelay = Math.min(this.reconnectDelay * 2, Transport.MAX_RECONNECT_DELAY);\n this.doConnect();\n }, delay);\n }\n\n private clearFlushTimer(): void {\n if (this.flushTimer) {\n clearInterval(this.flushTimer);\n this.flushTimer = null;\n }\n }\n\n onCommand(handler: (cmd: { command: string; requestId: string; params?: Record<string, unknown> }) => void): void {\n this.commandHandler = handler;\n }\n\n sendCommandResponse(requestId: string, command: string, payload: unknown): void {\n this.sendRaw({\n type: 'command_response',\n requestId,\n command,\n payload,\n timestamp: Date.now(),\n sessionId: this.config.sessionId,\n });\n }\n\n disconnect(): void {\n this.stopped = true;\n this.clearFlushTimer();\n\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = null;\n }\n\n // Final flush before closing\n this.flush();\n\n if (this.ws) {\n this.ws.onclose = null;\n this.ws.onerror = null;\n this.ws.close();\n this.ws = null;\n }\n\n this.connected = false;\n this.batch = [];\n this.offlineQueue = [];\n }\n}\n","/** 8-char random hex string for event IDs. */\nexport function generateId(): string {\n const arr = new Uint8Array(4);\n crypto.getRandomValues(arr);\n return Array.from(arr, (b) => b.toString(16).padStart(2, '0')).join('');\n}\n\n/** 32-char random hex string for session IDs. */\nexport function generateSessionId(): string {\n const arr = new Uint8Array(16);\n crypto.getRandomValues(arr);\n return Array.from(arr, (b) => b.toString(16).padStart(2, '0')).join('');\n}\n","import { generateId } from '../utils/id.js';\nimport type { NetworkEvent, GraphQLOperation, RuntimeEvent } from '../types.js';\n\ntype EmitFn = (event: NetworkEvent) => void;\n\nexport interface FetchInterceptorOptions {\n captureBody?: boolean;\n maxBodySize?: number;\n beforeSend?: (event: RuntimeEvent) => RuntimeEvent | null;\n}\n\n// Track URLs intercepted by fetch to prevent XHR double-counting (fetch polyfill case).\n// Uses a Set of request identifiers instead of a custom HTTP header to avoid triggering CORS.\nexport const fetchInterceptedRequests = new Set<string>();\n\nexport function interceptFetch(\n emit: EmitFn,\n sessionId: string,\n redactHeaders: string[],\n options?: FetchInterceptorOptions\n): () => void {\n const originalFetch = window.fetch;\n const redactSet = new Set(redactHeaders.map((h) => h.toLowerCase()));\n const captureBody = options?.captureBody ?? false;\n const maxBodySize = options?.maxBodySize ?? 65536;\n\n window.fetch = async function (\n input: RequestInfo | URL,\n init?: RequestInit\n ): Promise<Response> {\n const startTime = performance.now();\n const url =\n typeof input === 'string'\n ? input\n : input instanceof URL\n ? input.href\n : input.url;\n const method = (init?.method ?? 'GET').toUpperCase();\n\n const requestHeaders = extractHeaders(init?.headers, redactSet);\n const requestBodySize = estimateBodySize(init?.body);\n const graphqlOperation = detectGraphQL(init?.body);\n\n // Capture request body if enabled\n let requestBody: string | undefined;\n if (captureBody && init?.body) {\n requestBody = serializeBody(init.body, maxBodySize);\n }\n\n // Mark request to prevent XHR interceptor double-counting (fetch polyfill case)\n const requestKey = `${method}:${url}:${startTime}`;\n fetchInterceptedRequests.add(requestKey);\n // Clean up after a short delay to prevent memory leaks\n setTimeout(() => fetchInterceptedRequests.delete(requestKey), 5000);\n\n try {\n const response = await originalFetch.call(window, input, init);\n const duration = performance.now() - startTime;\n\n const responseBodySize = parseInt(\n response.headers.get('content-length') || '0',\n 10\n );\n const responseHeaders = extractResponseHeaders(response.headers, redactSet);\n\n // Capture response body if enabled\n let responseBody: string | undefined;\n if (captureBody) {\n try {\n const clone = response.clone();\n const text = await clone.text();\n responseBody = text.length > maxBodySize ? text.slice(0, maxBodySize) : text;\n } catch {\n // CORS or stream-locked — skip body capture\n }\n }\n\n const event: NetworkEvent = {\n eventId: generateId(),\n sessionId,\n timestamp: Date.now(),\n eventType: 'network',\n url,\n method,\n status: response.status,\n requestHeaders,\n responseHeaders,\n requestBodySize,\n responseBodySize,\n duration,\n ttfb: duration,\n graphqlOperation,\n requestBody,\n responseBody,\n source: 'fetch',\n };\n\n if (options?.beforeSend) {\n const filtered = options.beforeSend(event);\n if (filtered) emit(filtered as NetworkEvent);\n } else {\n emit(event);\n }\n\n return response;\n } catch (error) {\n const duration = performance.now() - startTime;\n\n let errorPhase: 'error' | 'abort' | 'timeout' = 'error';\n let errorMessage = '';\n\n if (error instanceof DOMException && error.name === 'AbortError') {\n errorPhase = 'abort';\n errorMessage = 'Request aborted';\n } else if (error instanceof Error) {\n errorMessage = error.message;\n }\n\n const event: NetworkEvent = {\n eventId: generateId(),\n sessionId,\n timestamp: Date.now(),\n eventType: 'network',\n url,\n method,\n status: 0,\n requestHeaders,\n responseHeaders: {},\n requestBodySize,\n responseBodySize: 0,\n duration,\n ttfb: 0,\n graphqlOperation,\n requestBody,\n errorPhase,\n errorMessage,\n source: 'fetch',\n };\n\n if (options?.beforeSend) {\n const filtered = options.beforeSend(event);\n if (filtered) emit(filtered as NetworkEvent);\n } else {\n emit(event);\n }\n\n throw error;\n }\n };\n\n return () => {\n window.fetch = originalFetch;\n };\n}\n\nfunction extractHeaders(\n headers: HeadersInit | undefined,\n redactSet: Set<string>\n): Record<string, string> {\n const result: Record<string, string> = {};\n if (!headers) return result;\n\n if (headers instanceof Headers) {\n headers.forEach((value, key) => {\n result[key] = redactSet.has(key.toLowerCase()) ? '[REDACTED]' : value;\n });\n } else if (Array.isArray(headers)) {\n for (const [key, value] of headers) {\n result[key] = redactSet.has(key.toLowerCase()) ? '[REDACTED]' : value;\n }\n } else {\n for (const [key, value] of Object.entries(headers)) {\n result[key] = redactSet.has(key.toLowerCase()) ? '[REDACTED]' : value;\n }\n }\n\n return result;\n}\n\nfunction extractResponseHeaders(\n headers: Headers,\n redactSet: Set<string>\n): Record<string, string> {\n const result: Record<string, string> = {};\n headers.forEach((value, key) => {\n result[key] = redactSet.has(key.toLowerCase()) ? '[REDACTED]' : value;\n });\n return result;\n}\n\nfunction estimateBodySize(body: BodyInit | null | undefined): number {\n if (!body) return 0;\n if (typeof body === 'string') return new Blob([body]).size;\n if (body instanceof Blob) return body.size;\n if (body instanceof ArrayBuffer) return body.byteLength;\n if (ArrayBuffer.isView(body)) return body.byteLength;\n if (body instanceof FormData) return 0;\n if (body instanceof URLSearchParams) return new Blob([body.toString()]).size;\n return 0;\n}\n\nfunction serializeBody(body: BodyInit | null | undefined, maxSize: number): string | undefined {\n if (!body) return undefined;\n if (typeof body === 'string') return body.length > maxSize ? body.slice(0, maxSize) : body;\n if (body instanceof URLSearchParams) {\n const s = body.toString();\n return s.length > maxSize ? s.slice(0, maxSize) : s;\n }\n if (body instanceof FormData) return '[FormData]';\n if (body instanceof Blob) return `[Blob ${body.size} bytes]`;\n if (body instanceof ArrayBuffer) return `[ArrayBuffer ${body.byteLength} bytes]`;\n if (ArrayBuffer.isView(body)) return `[TypedArray ${body.byteLength} bytes]`;\n return undefined;\n}\n\nfunction detectGraphQL(body: BodyInit | null | undefined): GraphQLOperation | undefined {\n if (!body || typeof body !== 'string') return undefined;\n\n try {\n const parsed = JSON.parse(body);\n if (typeof parsed.query === 'string') {\n const trimmed = parsed.query.trim();\n let type: GraphQLOperation['type'] = 'query';\n if (trimmed.startsWith('mutation')) type = 'mutation';\n else if (trimmed.startsWith('subscription')) type = 'subscription';\n\n const name = parsed.operationName || extractOperationName(trimmed) || 'anonymous';\n return { type, name };\n }\n } catch {\n // Not GraphQL\n }\n\n return undefined;\n}\n\nfunction extractOperationName(query: string): string | undefined {\n const match = query.match(/^(?:query|mutation|subscription)\\s+(\\w+)/);\n return match?.[1];\n}\n","/** Safely serialize a value, handling circular references, functions, symbols, and errors. */\nexport function safeSerialize(value: unknown, maxDepth = 5): unknown {\n const seen = new WeakSet();\n\n function walk(val: unknown, depth: number): unknown {\n if (depth > maxDepth) return '[max depth]';\n if (val === null || val === undefined) return val;\n if (typeof val === 'function') return `[Function: ${val.name || 'anonymous'}]`;\n if (typeof val === 'symbol') return val.toString();\n if (typeof val === 'bigint') return val.toString();\n if (typeof val !== 'object') return val;\n\n if (val instanceof Error) {\n return { name: val.name, message: val.message, stack: val.stack };\n }\n if (val instanceof Date) {\n return val.toISOString();\n }\n if (val instanceof RegExp) {\n return val.toString();\n }\n\n if (seen.has(val as object)) return '[Circular]';\n seen.add(val as object);\n\n if (Array.isArray(val)) {\n return val.map((v) => walk(v, depth + 1));\n }\n\n const result: Record<string, unknown> = {};\n for (const key of Object.keys(val as Record<string, unknown>)) {\n result[key] = walk((val as Record<string, unknown>)[key], depth + 1);\n }\n return result;\n }\n\n return walk(value, 0);\n}\n","import { generateId } from '../utils/id.js';\nimport { safeSerialize } from '../utils/serialize.js';\nimport type { ConsoleEvent, ConsoleLevel, RuntimeEvent } from '../types.js';\n\ntype EmitFn = (event: ConsoleEvent) => void;\n\nconst LEVELS: ConsoleLevel[] = ['log', 'warn', 'error', 'info', 'debug', 'trace'];\n\nexport function interceptConsole(\n emit: EmitFn,\n sessionId: string,\n beforeSend?: (event: RuntimeEvent) => RuntimeEvent | null\n): () => void {\n const originals: Record<string, (...args: unknown[]) => void> = {};\n\n for (const level of LEVELS) {\n originals[level] = console[level].bind(console);\n\n console[level] = (...args: unknown[]) => {\n const message = args\n .map((a) => (typeof a === 'string' ? a : stringifyArg(a)))\n .join(' ');\n\n const event: ConsoleEvent = {\n eventId: generateId(),\n sessionId,\n timestamp: Date.now(),\n eventType: 'console',\n level,\n message,\n args: args.map((a) => safeSerialize(a, 3)),\n stackTrace:\n level === 'error' || level === 'trace'\n ? new Error().stack?.split('\\n').slice(2).join('\\n')\n : undefined,\n sourceFile: undefined,\n };\n\n if (beforeSend) {\n const filtered = beforeSend(event);\n if (filtered) emit(filtered as ConsoleEvent);\n } else {\n emit(event);\n }\n\n // Call original — MUST come after emit, and MUST use saved reference\n originals[level](...args);\n };\n }\n\n return () => {\n for (const level of LEVELS) {\n console[level] = originals[level];\n }\n };\n}\n\nfunction stringifyArg(arg: unknown): string {\n try {\n return JSON.stringify(arg);\n } catch {\n return String(arg);\n }\n}\n","import { generateId } from '../utils/id.js';\nimport type { NetworkEvent, GraphQLOperation, RuntimeEvent } from '../types.js';\nimport { fetchInterceptedRequests } from './fetch.js';\n\ntype EmitFn = (event: NetworkEvent) => void;\n\nexport interface XhrInterceptorOptions {\n captureBody?: boolean;\n maxBodySize?: number;\n beforeSend?: (event: RuntimeEvent) => RuntimeEvent | null;\n}\n\ninterface AugmentedXHR extends XMLHttpRequest {\n __rs_method?: string;\n __rs_url?: string;\n __rs_headers?: Record<string, string>;\n __rs_start?: number;\n __rs_body?: string;\n __rs_fetchIntercepted?: boolean;\n}\n\nexport function interceptXhr(\n emit: EmitFn,\n sessionId: string,\n redactHeaders: string[],\n options?: XhrInterceptorOptions\n): () => void {\n const redactSet = new Set(redactHeaders.map((h) => h.toLowerCase()));\n const captureBody = options?.captureBody ?? false;\n const maxBodySize = options?.maxBodySize ?? 65536;\n\n const origOpen = XMLHttpRequest.prototype.open;\n const origSetRequestHeader = XMLHttpRequest.prototype.setRequestHeader;\n const origSend = XMLHttpRequest.prototype.send;\n\n XMLHttpRequest.prototype.open = function (\n this: AugmentedXHR,\n method: string,\n url: string | URL\n ) {\n this.__rs_method = method.toUpperCase();\n this.__rs_url = typeof url === 'string' ? url : url.href;\n this.__rs_headers = {};\n // eslint-disable-next-line prefer-rest-params\n return origOpen.apply(this, arguments as unknown as Parameters<typeof origOpen>);\n };\n\n XMLHttpRequest.prototype.setRequestHeader = function (\n this: AugmentedXHR,\n name: string,\n value: string\n ) {\n if (this.__rs_headers) {\n this.__rs_headers[name.toLowerCase()] = redactSet.has(name.toLowerCase())\n ? '[REDACTED]'\n : value;\n }\n return origSetRequestHeader.call(this, name, value);\n };\n\n XMLHttpRequest.prototype.send = function (\n this: AugmentedXHR,\n body?: Document | XMLHttpRequestBodyInit | null\n ) {\n // Skip if this request was already captured by the fetch interceptor\n const method = this.__rs_method ?? 'GET';\n const url = this.__rs_url ?? '';\n const requestKey = `${method}:${url}`;\n const alreadyIntercepted = Array.from(fetchInterceptedRequests).some((k) => k.startsWith(requestKey));\n if (alreadyIntercepted) {\n this.__rs_fetchIntercepted = true;\n return origSend.call(this, body);\n }\n\n const requestHeaders = { ...(this.__rs_headers ?? {}) };\n const startTime = performance.now();\n\n // Capture request body\n let requestBody: string | undefined;\n let requestBodySize = 0;\n if (body) {\n if (typeof body === 'string') {\n requestBodySize = new Blob([body]).size;\n if (captureBody) {\n requestBody = body.length > maxBodySize ? body.slice(0, maxBodySize) : body;\n }\n } else if (body instanceof Blob) {\n requestBodySize = body.size;\n if (captureBody) requestBody = `[Blob ${body.size} bytes]`;\n } else if (body instanceof ArrayBuffer) {\n requestBodySize = body.byteLength;\n if (captureBody) requestBody = `[ArrayBuffer ${body.byteLength} bytes]`;\n } else if (body instanceof FormData) {\n if (captureBody) requestBody = '[FormData]';\n } else if (body instanceof URLSearchParams) {\n const s = body.toString();\n requestBodySize = new Blob([s]).size;\n if (captureBody) requestBody = s.length > maxBodySize ? s.slice(0, maxBodySize) : s;\n }\n }\n\n // Detect GraphQL\n const graphqlOperation = detectGraphQL(body);\n\n const emitEvent = (overrides: Partial<NetworkEvent>) => {\n const event: NetworkEvent = {\n eventId: generateId(),\n sessionId,\n timestamp: Date.now(),\n eventType: 'network',\n url,\n method,\n status: 0,\n requestHeaders,\n responseHeaders: {},\n requestBodySize,\n responseBodySize: 0,\n duration: 0,\n ttfb: 0,\n graphqlOperation,\n requestBody,\n source: 'xhr',\n ...overrides,\n };\n\n if (options?.beforeSend) {\n const filtered = options.beforeSend(event);\n if (filtered) emit(filtered as NetworkEvent);\n } else {\n emit(event);\n }\n };\n\n this.addEventListener('load', () => {\n const duration = performance.now() - startTime;\n const responseHeaders = parseResponseHeaders(this.getAllResponseHeaders(), redactSet);\n const responseBodySize = parseInt(\n this.getResponseHeader('content-length') || '0',\n 10\n );\n\n let responseBody: string | undefined;\n if (captureBody && this.responseType === '' || this.responseType === 'text') {\n try {\n const text = this.responseText;\n responseBody = text.length > maxBodySize ? text.slice(0, maxBodySize) : text;\n } catch {\n // responseText not available for non-text types\n }\n }\n\n emitEvent({\n status: this.status,\n responseHeaders,\n responseBodySize,\n responseBody,\n duration,\n ttfb: duration,\n });\n });\n\n this.addEventListener('error', () => {\n const duration = performance.now() - startTime;\n emitEvent({\n duration,\n errorPhase: 'error',\n errorMessage: 'Network error',\n });\n });\n\n this.addEventListener('abort', () => {\n const duration = performance.now() - startTime;\n emitEvent({\n duration,\n errorPhase: 'abort',\n errorMessage: 'Request aborted',\n });\n });\n\n this.addEventListener('timeout', () => {\n const duration = performance.now() - startTime;\n emitEvent({\n duration,\n errorPhase: 'timeout',\n errorMessage: `Request timed out after ${this.timeout}ms`,\n });\n });\n\n return origSend.call(this, body);\n };\n\n return () => {\n XMLHttpRequest.prototype.open = origOpen;\n XMLHttpRequest.prototype.setRequestHeader = origSetRequestHeader;\n XMLHttpRequest.prototype.send = origSend;\n };\n}\n\nfunction parseResponseHeaders(\n raw: string,\n redactSet: Set<string>\n): Record<string, string> {\n const result: Record<string, string> = {};\n if (!raw) return result;\n\n for (const line of raw.trim().split(/[\\r\\n]+/)) {\n const idx = line.indexOf(':');\n if (idx === -1) continue;\n const key = line.slice(0, idx).trim().toLowerCase();\n const value = line.slice(idx + 1).trim();\n result[key] = redactSet.has(key) ? '[REDACTED]' : value;\n }\n\n return result;\n}\n\nfunction detectGraphQL(\n body: Document | XMLHttpRequestBodyInit | null | undefined\n): GraphQLOperation | undefined {\n if (!body || typeof body !== 'string') return undefined;\n\n try {\n const parsed = JSON.parse(body);\n if (typeof parsed.query === 'string') {\n const trimmed = parsed.query.trim();\n let type: GraphQLOperation['type'] = 'query';\n if (trimmed.startsWith('mutation')) type = 'mutation';\n else if (trimmed.startsWith('subscription')) type = 'subscription';\n\n const name =\n parsed.operationName || extractOperationName(trimmed) || 'anonymous';\n return { type, name };\n }\n } catch {\n // Not GraphQL\n }\n\n return undefined;\n}\n\nfunction extractOperationName(query: string): string | undefined {\n const match = query.match(/^(?:query|mutation|subscription)\\s+(\\w+)/);\n return match?.[1];\n}\n","import { generateId } from '../utils/id.js';\nimport { safeSerialize } from '../utils/serialize.js';\nimport type { StateEvent, RuntimeEvent } from '../types.js';\n\ntype EmitFn = (event: StateEvent) => void;\n\nexport interface StateStoreOptions {\n beforeSend?: (event: RuntimeEvent) => RuntimeEvent | null;\n}\n\ninterface ZustandStore {\n getState: () => unknown;\n setState: (partial: unknown) => void;\n subscribe: (listener: (state: unknown, prevState: unknown) => void) => () => void;\n}\n\ninterface ReduxStore {\n getState: () => unknown;\n dispatch: (action: unknown) => unknown;\n subscribe: (listener: () => void) => () => void;\n}\n\ntype DetectedLibrary = 'zustand' | 'redux' | 'unknown';\n\nexport function interceptStateStores(\n emit: EmitFn,\n sessionId: string,\n stores: Record<string, unknown>,\n options?: StateStoreOptions\n): () => void {\n const unsubscribers: (() => void)[] = [];\n const originalDispatches: Map<string, ReduxStore['dispatch']> = new Map();\n\n for (const [storeId, store] of Object.entries(stores)) {\n const library = detectLibrary(store);\n\n if (library === 'zustand') {\n const zustand = store as ZustandStore;\n\n // Emit initial state\n emitState(emit, sessionId, options?.beforeSend, {\n storeId,\n library,\n phase: 'init',\n state: safeSerialize(zustand.getState(), 4),\n });\n\n // Subscribe to changes\n const unsub = zustand.subscribe((state, prevState) => {\n const diff = shallowDiff(prevState, state);\n emitState(emit, sessionId, options?.beforeSend, {\n storeId,\n library,\n phase: 'update',\n state: safeSerialize(state, 4),\n previousState: safeSerialize(prevState, 4),\n diff: diff ? safeSerialize(diff, 3) as Record<string, { from: unknown; to: unknown }> : undefined,\n });\n });\n\n unsubscribers.push(unsub);\n } else if (library === 'redux') {\n const redux = store as ReduxStore;\n\n // Emit initial state\n emitState(emit, sessionId, options?.beforeSend, {\n storeId,\n library,\n phase: 'init',\n state: safeSerialize(redux.getState(), 4),\n });\n\n // Wrap dispatch to capture actions\n let lastAction: { type: string; payload?: unknown } | undefined;\n const origDispatch = redux.dispatch.bind(redux);\n originalDispatches.set(storeId, origDispatch);\n\n (redux as { dispatch: ReduxStore['dispatch'] }).dispatch = (action: unknown) => {\n if (action && typeof action === 'object' && 'type' in action) {\n lastAction = {\n type: String((action as { type: unknown }).type),\n payload: (action as { payload?: unknown }).payload,\n };\n }\n return origDispatch(action);\n };\n\n // Subscribe to state changes\n let prevState = redux.getState();\n const unsub = redux.subscribe(() => {\n const state = redux.getState();\n const diff = shallowDiff(prevState, state);\n\n emitState(emit, sessionId, options?.beforeSend, {\n storeId,\n library,\n phase: 'update',\n state: safeSerialize(state, 4),\n previousState: safeSerialize(prevState, 4),\n diff: diff ? safeSerialize(diff, 3) as Record<string, { from: unknown; to: unknown }> : undefined,\n action: lastAction ? safeSerialize(lastAction, 3) as { type: string; payload?: unknown } : undefined,\n });\n\n prevState = state;\n lastAction = undefined;\n });\n\n unsubscribers.push(unsub);\n }\n }\n\n return () => {\n for (const unsub of unsubscribers) unsub();\n\n // Restore original Redux dispatch functions\n for (const [storeId, origDispatch] of originalDispatches) {\n const store = stores[storeId] as ReduxStore;\n if (store) {\n (store as { dispatch: ReduxStore['dispatch'] }).dispatch = origDispatch;\n }\n }\n };\n}\n\nfunction detectLibrary(store: unknown): DetectedLibrary {\n if (!store || typeof store !== 'object') return 'unknown';\n const s = store as Record<string, unknown>;\n\n // Zustand: function-like with getState, setState, subscribe\n if (\n typeof s.getState === 'function' &&\n typeof s.setState === 'function' &&\n typeof s.subscribe === 'function'\n ) {\n return 'zustand';\n }\n\n // Redux: object with dispatch, getState, subscribe\n if (\n typeof s.dispatch === 'function' &&\n typeof s.getState === 'function' &&\n typeof s.subscribe === 'function'\n ) {\n return 'redux';\n }\n\n return 'unknown';\n}\n\nfunction shallowDiff(\n prev: unknown,\n curr: unknown\n): Record<string, { from: unknown; to: unknown }> | null {\n if (!prev || !curr || typeof prev !== 'object' || typeof curr !== 'object') {\n return null;\n }\n\n const diff: Record<string, { from: unknown; to: unknown }> = {};\n const prevObj = prev as Record<string, unknown>;\n const currObj = curr as Record<string, unknown>;\n const allKeys = new Set([...Object.keys(prevObj), ...Object.keys(currObj)]);\n\n for (const key of allKeys) {\n if (prevObj[key] !== currObj[key]) {\n diff[key] = { from: prevObj[key], to: currObj[key] };\n }\n }\n\n return Object.keys(diff).length > 0 ? diff : null;\n}\n\nfunction emitState(\n emit: EmitFn,\n sessionId: string,\n beforeSend: ((event: RuntimeEvent) => RuntimeEvent | null) | undefined,\n data: Omit<StateEvent, 'eventId' | 'sessionId' | 'timestamp' | 'eventType'>\n): void {\n const event: StateEvent = {\n eventId: generateId(),\n sessionId,\n timestamp: Date.now(),\n eventType: 'state',\n ...data,\n };\n\n if (beforeSend) {\n const filtered = beforeSend(event);\n if (filtered) emit(filtered as StateEvent);\n } else {\n emit(event);\n }\n}\n","import { generateId } from '../utils/id.js';\nimport type { PerformanceEvent, WebVitalRating, RuntimeEvent } from '../types.js';\n\ntype EmitFn = (event: PerformanceEvent) => void;\n\nexport interface PerformanceInterceptorOptions {\n beforeSend?: (event: RuntimeEvent) => RuntimeEvent | null;\n}\n\n// Web Vitals thresholds from web.dev\nconst THRESHOLDS: Record<string, [number, number]> = {\n LCP: [2500, 4000],\n FCP: [1800, 3000],\n CLS: [0.1, 0.25],\n TTFB: [800, 1800],\n FID: [100, 300],\n INP: [200, 500],\n};\n\nfunction rate(metric: string, value: number): WebVitalRating {\n const [good, poor] = THRESHOLDS[metric] ?? [Infinity, Infinity];\n if (value <= good) return 'good';\n if (value <= poor) return 'needs-improvement';\n return 'poor';\n}\n\nexport function interceptPerformance(\n emit: EmitFn,\n sessionId: string,\n options?: PerformanceInterceptorOptions\n): () => void {\n const observers: PerformanceObserver[] = [];\n\n const emitMetric = (\n metricName: PerformanceEvent['metricName'],\n value: number,\n element?: string\n ) => {\n const event: PerformanceEvent = {\n eventId: generateId(),\n sessionId,\n timestamp: Date.now(),\n eventType: 'performance',\n metricName,\n value: Math.round(value * 100) / 100,\n rating: rate(metricName, value),\n element,\n };\n\n if (options?.beforeSend) {\n const filtered = options.beforeSend(event);\n if (filtered) emit(filtered as PerformanceEvent);\n } else {\n emit(event);\n }\n };\n\n // LCP — Largest Contentful Paint\n tryObserve(observers, 'largest-contentful-paint', (entries) => {\n const last = entries[entries.length - 1];\n if (!last) return;\n const el = (last as PerformanceEntry & { element?: Element }).element;\n emitMetric('LCP', last.startTime, el?.tagName?.toLowerCase());\n });\n\n // FCP — First Contentful Paint\n tryObserve(observers, 'paint', (entries) => {\n for (const entry of entries) {\n if (entry.name === 'first-contentful-paint') {\n emitMetric('FCP', entry.startTime);\n }\n }\n });\n\n // CLS — Cumulative Layout Shift\n let clsValue = 0;\n tryObserve(observers, 'layout-shift', (entries) => {\n for (const entry of entries) {\n const ls = entry as PerformanceEntry & { hadRecentInput?: boolean; value?: number };\n if (!ls.hadRecentInput && ls.value) {\n clsValue += ls.value;\n emitMetric('CLS', clsValue);\n }\n }\n });\n\n // FID — First Input Delay\n tryObserve(observers, 'first-input', (entries) => {\n const first = entries[0];\n if (!first) return;\n const fi = first as PerformanceEntry & { processingStart?: number };\n if (fi.processingStart) {\n emitMetric('FID', fi.processingStart - first.startTime);\n }\n });\n\n // TTFB — Time to First Byte\n tryObserve(observers, 'navigation', (entries) => {\n const nav = entries[0] as PerformanceNavigationTiming | undefined;\n if (nav) {\n emitMetric('TTFB', nav.responseStart - nav.requestStart);\n }\n });\n\n // INP — Interaction to Next Paint\n let inpMax = 0;\n tryObserve(\n observers,\n 'event',\n (entries) => {\n for (const entry of entries) {\n if (entry.duration > inpMax) {\n inpMax = entry.duration;\n emitMetric('INP', inpMax);\n }\n }\n },\n { durationThreshold: 16 }\n );\n\n return () => {\n for (const obs of observers) {\n try {\n obs.disconnect();\n } catch {\n // Already disconnected\n }\n }\n };\n}\n\nfunction tryObserve(\n observers: PerformanceObserver[],\n entryType: string,\n callback: (entries: PerformanceEntryList) => void,\n observeOptions?: Record<string, unknown>\n): void {\n try {\n const obs = new PerformanceObserver((list) => {\n callback(list.getEntries());\n });\n obs.observe({\n type: entryType,\n buffered: true,\n ...observeOptions,\n } as PerformanceObserverInit);\n observers.push(obs);\n } catch {\n // Observer type not supported in this browser\n }\n}\n","import { generateId } from '../utils/id.js';\nimport type { RenderEvent, RenderComponentProfile, RuntimeEvent } from '../types.js';\n\ntype EmitFn = (event: RenderEvent) => void;\n\nexport interface RenderInterceptorOptions {\n beforeSend?: (event: RuntimeEvent) => RuntimeEvent | null;\n snapshotIntervalMs?: number;\n}\n\ninterface Fiber {\n tag: number;\n type: { displayName?: string; name?: string } | string | null;\n child: Fiber | null;\n sibling: Fiber | null;\n alternate: Fiber | null;\n memoizedProps: unknown;\n memoizedState: unknown;\n actualDuration?: number;\n stateNode: unknown;\n}\n\ninterface ComponentTracker {\n renderCount: number;\n totalDuration: number;\n lastRenderTime: number;\n lastRenderPhase: 'mount' | 'update' | 'unmount';\n lastRenderCause: 'props' | 'state' | 'context' | 'parent' | 'unknown';\n renderTimestamps: number[];\n}\n\ninterface DevToolsHook {\n onCommitFiberRoot?: (id: number, root: { current?: Fiber }) => void;\n _runtimescope_original?: (id: number, root: { current?: Fiber }) => void;\n}\n\nconst FUNCTION_COMPONENT = 0;\nconst CLASS_COMPONENT = 1;\nconst SNAPSHOT_WINDOW_MS = 10_000;\nconst MAX_TIMESTAMPS = 100;\n\nexport function interceptReactRenders(\n emit: EmitFn,\n sessionId: string,\n options?: RenderInterceptorOptions\n): () => void {\n const trackers = new Map<string, ComponentTracker>();\n const snapshotIntervalMs = options?.snapshotIntervalMs ?? 5000;\n let snapshotTimer: ReturnType<typeof setInterval> | null = null;\n\n // Access or create the React DevTools global hook\n const hook = getOrCreateDevToolsHook();\n if (!hook) {\n return () => {}; // Not in a browser environment\n }\n\n // Save original if React DevTools is installed\n const originalOnCommit = hook.onCommitFiberRoot;\n hook._runtimescope_original = originalOnCommit;\n\n hook.onCommitFiberRoot = (id: number, root: { current?: Fiber }) => {\n // Call original first (React DevTools compatibility)\n if (originalOnCommit) {\n try {\n originalOnCommit(id, root);\n } catch {\n // Don't let DevTools errors break our tracking\n }\n }\n\n if (root.current) {\n walkFiber(root.current, trackers);\n }\n };\n\n // Emit snapshots periodically\n snapshotTimer = setInterval(() => {\n emitSnapshot(trackers, emit, sessionId, options?.beforeSend);\n }, snapshotIntervalMs);\n\n return () => {\n if (snapshotTimer) {\n clearInterval(snapshotTimer);\n snapshotTimer = null;\n }\n\n // Restore original hook\n if (hook) {\n if (hook._runtimescope_original) {\n hook.onCommitFiberRoot = hook._runtimescope_original;\n } else {\n delete hook.onCommitFiberRoot;\n }\n delete hook._runtimescope_original;\n }\n };\n}\n\nfunction getOrCreateDevToolsHook(): DevToolsHook | null {\n if (typeof window === 'undefined') return null;\n\n const w = window as unknown as { __REACT_DEVTOOLS_GLOBAL_HOOK__?: DevToolsHook };\n\n if (!w.__REACT_DEVTOOLS_GLOBAL_HOOK__) {\n // Create a minimal shim that React will pick up on init\n w.__REACT_DEVTOOLS_GLOBAL_HOOK__ = {\n // React checks for these methods to decide if DevTools is present\n } as DevToolsHook;\n }\n\n return w.__REACT_DEVTOOLS_GLOBAL_HOOK__!;\n}\n\nfunction walkFiber(fiber: Fiber, trackers: Map<string, ComponentTracker>): void {\n processNode(fiber, trackers);\n\n if (fiber.child) walkFiber(fiber.child, trackers);\n if (fiber.sibling) walkFiber(fiber.sibling, trackers);\n}\n\nfunction processNode(fiber: Fiber, trackers: Map<string, ComponentTracker>): void {\n // Only track function components (0) and class components (1)\n if (fiber.tag !== FUNCTION_COMPONENT && fiber.tag !== CLASS_COMPONENT) return;\n\n const name = getComponentName(fiber);\n if (!name) return;\n\n const now = Date.now();\n const isMount = fiber.alternate === null;\n const duration = fiber.actualDuration ?? 0;\n const cause = inferRenderCause(fiber, isMount);\n\n let tracker = trackers.get(name);\n if (!tracker) {\n tracker = {\n renderCount: 0,\n totalDuration: 0,\n lastRenderTime: 0,\n lastRenderPhase: 'mount',\n lastRenderCause: 'unknown',\n renderTimestamps: [],\n };\n trackers.set(name, tracker);\n }\n\n tracker.renderCount++;\n tracker.totalDuration += duration;\n tracker.lastRenderTime = now;\n tracker.lastRenderPhase = isMount ? 'mount' : 'update';\n tracker.lastRenderCause = cause;\n tracker.renderTimestamps.push(now);\n\n // Trim old timestamps\n if (tracker.renderTimestamps.length > MAX_TIMESTAMPS) {\n tracker.renderTimestamps = tracker.renderTimestamps.slice(-MAX_TIMESTAMPS);\n }\n}\n\nfunction getComponentName(fiber: Fiber): string | undefined {\n if (!fiber.type) return undefined;\n if (typeof fiber.type === 'string') return undefined; // HTML elements\n return fiber.type.displayName || fiber.type.name || undefined;\n}\n\nfunction inferRenderCause(\n fiber: Fiber,\n isMount: boolean\n): RenderComponentProfile['lastRenderCause'] {\n if (isMount) return 'props'; // Initial mount, driven by parent passing props\n\n if (!fiber.alternate) return 'unknown';\n\n // Check if props changed\n if (fiber.memoizedProps !== fiber.alternate.memoizedProps) {\n return 'props';\n }\n\n // Check if state changed\n if (fiber.memoizedState !== fiber.alternate.memoizedState) {\n return 'state';\n }\n\n // If neither props nor state changed, likely parent re-rendered\n return 'parent';\n}\n\nfunction computeRenderVelocity(timestamps: number[]): number {\n if (timestamps.length < 2) return 0;\n const now = Date.now();\n const windowStart = now - SNAPSHOT_WINDOW_MS;\n const recent = timestamps.filter((t) => t >= windowStart);\n if (recent.length < 2) return 0;\n const windowMs = now - recent[0];\n if (windowMs === 0) return 0;\n return recent.length / (windowMs / 1000);\n}\n\nfunction emitSnapshot(\n trackers: Map<string, ComponentTracker>,\n emit: EmitFn,\n sessionId: string,\n beforeSend?: (event: RuntimeEvent) => RuntimeEvent | null\n): void {\n if (trackers.size === 0) return;\n\n const profiles: RenderComponentProfile[] = [];\n const suspiciousComponents: string[] = [];\n let totalRenders = 0;\n\n for (const [componentName, tracker] of trackers) {\n const velocity = computeRenderVelocity(tracker.renderTimestamps);\n const suspicious = velocity > 4 || tracker.renderCount > 20;\n\n profiles.push({\n componentName,\n renderCount: tracker.renderCount,\n totalDuration: Math.round(tracker.totalDuration * 100) / 100,\n avgDuration:\n tracker.renderCount > 0\n ? Math.round((tracker.totalDuration / tracker.renderCount) * 100) / 100\n : 0,\n lastRenderPhase: tracker.lastRenderPhase,\n lastRenderCause: tracker.lastRenderCause,\n renderVelocity: Math.round(velocity * 100) / 100,\n suspicious,\n });\n\n if (suspicious) suspiciousComponents.push(componentName);\n totalRenders += tracker.renderCount;\n }\n\n // Sort by render count descending\n profiles.sort((a, b) => b.renderCount - a.renderCount);\n\n const event: RenderEvent = {\n eventId: generateId(),\n sessionId,\n timestamp: Date.now(),\n eventType: 'render',\n profiles,\n snapshotWindowMs: SNAPSHOT_WINDOW_MS,\n totalRenders,\n suspiciousComponents,\n };\n\n if (beforeSend) {\n const filtered = beforeSend(event);\n if (filtered) emit(filtered as RenderEvent);\n } else {\n emit(event);\n }\n\n // Reset counters for next snapshot\n for (const tracker of trackers.values()) {\n tracker.renderCount = 0;\n tracker.totalDuration = 0;\n }\n}\n","import { generateId } from '../utils/id.js';\nimport { safeSerialize } from '../utils/serialize.js';\nimport type { ConsoleEvent, RuntimeEvent } from '../types.js';\n\ntype EmitFn = (event: ConsoleEvent) => void;\n\n/**\n * Captures uncaught errors and unhandled promise rejections that appear\n * in DevTools but don't go through the console.* API.\n *\n * - window 'error' (capture phase) — JS runtime errors + resource load failures\n * - window 'unhandledrejection' — unhandled async/await and Promise rejections\n *\n * Events are emitted as ConsoleEvents with level 'error' so they appear\n * alongside console.error() output in get_console_messages.\n */\nexport function interceptErrors(\n emit: EmitFn,\n sessionId: string,\n beforeSend?: (event: RuntimeEvent) => RuntimeEvent | null\n): () => void {\n // Capture uncaught JS errors and resource load failures\n const onError = (e: ErrorEvent | Event) => {\n let message: string;\n let stackTrace: string | undefined;\n let sourceFile: string | undefined;\n\n if (e instanceof ErrorEvent) {\n // Uncaught JS error\n message = e.message || 'Uncaught error';\n stackTrace = e.error?.stack;\n sourceFile = e.filename\n ? `${e.filename}:${e.lineno}:${e.colno}`\n : undefined;\n } else {\n // Resource load error (img, script, link, etc.)\n const target = e.target as HTMLElement | null;\n if (target && target !== window as unknown) {\n const tagName = target.tagName?.toLowerCase() ?? 'unknown';\n const src =\n (target as HTMLImageElement).src ??\n (target as HTMLScriptElement).src ??\n (target as HTMLLinkElement).href ??\n 'unknown';\n message = `Failed to load resource: <${tagName}> ${src}`;\n } else {\n return; // Not a resource error we can identify\n }\n }\n\n const event: ConsoleEvent = {\n eventId: generateId(),\n sessionId,\n timestamp: Date.now(),\n eventType: 'console',\n level: 'error',\n message: `[Uncaught] ${message}`,\n args: [safeSerialize(message, 3)],\n stackTrace,\n sourceFile,\n };\n\n if (beforeSend) {\n const filtered = beforeSend(event);\n if (filtered) emit(filtered as ConsoleEvent);\n } else {\n emit(event);\n }\n };\n\n // Capture unhandled promise rejections\n const onUnhandledRejection = (e: PromiseRejectionEvent) => {\n const reason = e.reason;\n let message: string;\n let stackTrace: string | undefined;\n\n if (reason instanceof Error) {\n message = reason.message;\n stackTrace = reason.stack;\n } else if (typeof reason === 'string') {\n message = reason;\n } else {\n try {\n message = JSON.stringify(reason);\n } catch {\n message = String(reason);\n }\n }\n\n const event: ConsoleEvent = {\n eventId: generateId(),\n sessionId,\n timestamp: Date.now(),\n eventType: 'console',\n level: 'error',\n message: `[Unhandled Rejection] ${message}`,\n args: [safeSerialize(reason, 3)],\n stackTrace,\n sourceFile: undefined,\n };\n\n if (beforeSend) {\n const filtered = beforeSend(event);\n if (filtered) emit(filtered as ConsoleEvent);\n } else {\n emit(event);\n }\n };\n\n // Use capture phase for 'error' to catch resource load failures on child elements\n window.addEventListener('error', onError, true);\n window.addEventListener('unhandledrejection', onUnhandledRejection);\n\n return () => {\n window.removeEventListener('error', onError, true);\n window.removeEventListener('unhandledrejection', onUnhandledRejection);\n };\n}\n"],"mappings":"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","names":["index_exports","__export","RuntimeScope","index_default","__toCommonJS","_log","_Transport","config","__publicField","event","msg","queued","events","jitter","delay","handler","requestId","command","payload","Transport","generateId","arr","b","generateSessionId","fetchInterceptedRequests","interceptFetch","emit","sessionId","redactHeaders","options","originalFetch","redactSet","h","captureBody","maxBodySize","input","init","startTime","url","method","requestHeaders","extractHeaders","requestBodySize","estimateBodySize","graphqlOperation","detectGraphQL","requestBody","serializeBody","requestKey","response","duration","responseBodySize","responseHeaders","extractResponseHeaders","responseBody","text","event","generateId","filtered","error","errorPhase","errorMessage","headers","result","value","key","body","maxSize","s","parsed","trimmed","type","name","extractOperationName","query","safeSerialize","value","maxDepth","seen","walk","val","depth","v","result","key","LEVELS","interceptConsole","emit","sessionId","beforeSend","originals","level","args","message","a","stringifyArg","event","generateId","safeSerialize","filtered","arg","interceptXhr","emit","sessionId","redactHeaders","options","redactSet","h","captureBody","maxBodySize","origOpen","origSetRequestHeader","origSend","method","url","name","value","body","requestKey","fetchInterceptedRequests","k","requestHeaders","startTime","requestBody","requestBodySize","s","graphqlOperation","detectGraphQL","emitEvent","overrides","event","generateId","filtered","duration","responseHeaders","parseResponseHeaders","responseBodySize","responseBody","text","raw","result","line","idx","key","parsed","trimmed","type","extractOperationName","query","interceptStateStores","emit","sessionId","stores","options","unsubscribers","originalDispatches","storeId","store","library","detectLibrary","zustand","emitState","safeSerialize","unsub","state","prevState","diff","shallowDiff","redux","lastAction","origDispatch","action","s","prev","curr","prevObj","currObj","allKeys","key","beforeSend","data","event","generateId","filtered","THRESHOLDS","rate","metric","value","good","poor","interceptPerformance","emit","sessionId","options","observers","emitMetric","metricName","element","event","generateId","filtered","tryObserve","entries","last","el","entry","clsValue","ls","first","fi","nav","inpMax","obs","entryType","callback","observeOptions","list","FUNCTION_COMPONENT","CLASS_COMPONENT","SNAPSHOT_WINDOW_MS","MAX_TIMESTAMPS","interceptReactRenders","emit","sessionId","options","trackers","snapshotIntervalMs","snapshotTimer","hook","getOrCreateDevToolsHook","originalOnCommit","id","root","walkFiber","emitSnapshot","w","fiber","processNode","name","getComponentName","now","isMount","duration","cause","inferRenderCause","tracker","computeRenderVelocity","timestamps","windowStart","recent","t","windowMs","beforeSend","profiles","suspiciousComponents","totalRenders","componentName","velocity","suspicious","a","b","event","generateId","filtered","interceptErrors","emit","sessionId","beforeSend","onError","e","message","stackTrace","sourceFile","target","tagName","src","event","generateId","safeSerialize","filtered","onUnhandledRejection","reason","SDK_VERSION","_log","RuntimeScope","config","resolved","generateSessionId","Transport","emit","event","generateId","sessionId","cmd","interceptFetch","interceptXhr","interceptConsole","interceptErrors","interceptStateStores","interceptPerformance","interceptReactRenders","features","maxSize","html","truncated","snapshot","fn","__publicField","index_default"]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
type EventType = 'network' | 'console' | 'session' | 'state' | 'render' | 'dom_snapshot' | 'performance' | 'database';
|
|
2
|
+
interface BaseEvent {
|
|
3
|
+
eventId: string;
|
|
4
|
+
sessionId: string;
|
|
5
|
+
timestamp: number;
|
|
6
|
+
eventType: EventType;
|
|
7
|
+
}
|
|
8
|
+
interface GraphQLOperation {
|
|
9
|
+
type: 'query' | 'mutation' | 'subscription';
|
|
10
|
+
name: string;
|
|
11
|
+
}
|
|
12
|
+
interface NetworkEvent extends BaseEvent {
|
|
13
|
+
eventType: 'network';
|
|
14
|
+
url: string;
|
|
15
|
+
method: string;
|
|
16
|
+
status: number;
|
|
17
|
+
requestHeaders: Record<string, string>;
|
|
18
|
+
responseHeaders: Record<string, string>;
|
|
19
|
+
requestBodySize: number;
|
|
20
|
+
responseBodySize: number;
|
|
21
|
+
duration: number;
|
|
22
|
+
ttfb: number;
|
|
23
|
+
graphqlOperation?: GraphQLOperation;
|
|
24
|
+
requestBody?: string;
|
|
25
|
+
responseBody?: string;
|
|
26
|
+
errorPhase?: 'error' | 'abort' | 'timeout';
|
|
27
|
+
errorMessage?: string;
|
|
28
|
+
source?: 'fetch' | 'xhr' | 'node-http' | 'node-https';
|
|
29
|
+
}
|
|
30
|
+
type ConsoleLevel = 'log' | 'warn' | 'error' | 'info' | 'debug' | 'trace';
|
|
31
|
+
interface ConsoleEvent extends BaseEvent {
|
|
32
|
+
eventType: 'console';
|
|
33
|
+
level: ConsoleLevel;
|
|
34
|
+
message: string;
|
|
35
|
+
args: unknown[];
|
|
36
|
+
stackTrace?: string;
|
|
37
|
+
sourceFile?: string;
|
|
38
|
+
}
|
|
39
|
+
interface BuildMeta {
|
|
40
|
+
gitCommit?: string;
|
|
41
|
+
gitBranch?: string;
|
|
42
|
+
buildTime?: string;
|
|
43
|
+
deployId?: string;
|
|
44
|
+
}
|
|
45
|
+
interface SessionEvent extends BaseEvent {
|
|
46
|
+
eventType: 'session';
|
|
47
|
+
appName: string;
|
|
48
|
+
connectedAt: number;
|
|
49
|
+
sdkVersion: string;
|
|
50
|
+
buildMeta?: BuildMeta;
|
|
51
|
+
}
|
|
52
|
+
interface StateEvent extends BaseEvent {
|
|
53
|
+
eventType: 'state';
|
|
54
|
+
storeId: string;
|
|
55
|
+
library: 'zustand' | 'redux' | 'unknown';
|
|
56
|
+
phase: 'init' | 'update';
|
|
57
|
+
state: unknown;
|
|
58
|
+
previousState?: unknown;
|
|
59
|
+
diff?: Record<string, {
|
|
60
|
+
from: unknown;
|
|
61
|
+
to: unknown;
|
|
62
|
+
}>;
|
|
63
|
+
action?: {
|
|
64
|
+
type: string;
|
|
65
|
+
payload?: unknown;
|
|
66
|
+
};
|
|
67
|
+
stackTrace?: string;
|
|
68
|
+
}
|
|
69
|
+
interface RenderComponentProfile {
|
|
70
|
+
componentName: string;
|
|
71
|
+
renderCount: number;
|
|
72
|
+
totalDuration: number;
|
|
73
|
+
avgDuration: number;
|
|
74
|
+
lastRenderPhase: 'mount' | 'update' | 'unmount';
|
|
75
|
+
lastRenderCause?: 'props' | 'state' | 'context' | 'parent' | 'unknown';
|
|
76
|
+
renderVelocity: number;
|
|
77
|
+
suspicious: boolean;
|
|
78
|
+
}
|
|
79
|
+
interface RenderEvent extends BaseEvent {
|
|
80
|
+
eventType: 'render';
|
|
81
|
+
profiles: RenderComponentProfile[];
|
|
82
|
+
snapshotWindowMs: number;
|
|
83
|
+
totalRenders: number;
|
|
84
|
+
suspiciousComponents: string[];
|
|
85
|
+
}
|
|
86
|
+
interface DomSnapshotEvent extends BaseEvent {
|
|
87
|
+
eventType: 'dom_snapshot';
|
|
88
|
+
html: string;
|
|
89
|
+
url: string;
|
|
90
|
+
viewport: {
|
|
91
|
+
width: number;
|
|
92
|
+
height: number;
|
|
93
|
+
};
|
|
94
|
+
scrollPosition: {
|
|
95
|
+
x: number;
|
|
96
|
+
y: number;
|
|
97
|
+
};
|
|
98
|
+
elementCount: number;
|
|
99
|
+
truncated: boolean;
|
|
100
|
+
}
|
|
101
|
+
type WebVitalRating = 'good' | 'needs-improvement' | 'poor';
|
|
102
|
+
type ServerMetricName = 'memory.rss' | 'memory.heapUsed' | 'memory.heapTotal' | 'memory.external' | 'eventloop.lag.mean' | 'eventloop.lag.p99' | 'eventloop.lag.max' | 'gc.pause.major' | 'gc.pause.minor' | 'cpu.user' | 'cpu.system' | 'handles.active' | 'requests.active';
|
|
103
|
+
type PerformanceMetricName = 'LCP' | 'FCP' | 'CLS' | 'TTFB' | 'FID' | 'INP' | ServerMetricName;
|
|
104
|
+
interface PerformanceEvent extends BaseEvent {
|
|
105
|
+
eventType: 'performance';
|
|
106
|
+
metricName: PerformanceMetricName;
|
|
107
|
+
value: number;
|
|
108
|
+
rating?: WebVitalRating;
|
|
109
|
+
unit?: 'bytes' | 'ms' | 'percent' | 'count' | 'score';
|
|
110
|
+
element?: string;
|
|
111
|
+
entries?: unknown[];
|
|
112
|
+
}
|
|
113
|
+
type RuntimeEvent = NetworkEvent | ConsoleEvent | SessionEvent | StateEvent | RenderEvent | DomSnapshotEvent | PerformanceEvent;
|
|
114
|
+
interface RuntimeScopeConfig {
|
|
115
|
+
enabled?: boolean;
|
|
116
|
+
serverUrl?: string;
|
|
117
|
+
/** Alias for `serverUrl` — used by script-tag snippets */
|
|
118
|
+
endpoint?: string;
|
|
119
|
+
appName?: string;
|
|
120
|
+
/** API key for authenticated connections to the collector */
|
|
121
|
+
authToken?: string;
|
|
122
|
+
buildMeta?: BuildMeta;
|
|
123
|
+
captureNetwork?: boolean;
|
|
124
|
+
captureConsole?: boolean;
|
|
125
|
+
captureXhr?: boolean;
|
|
126
|
+
captureBody?: boolean;
|
|
127
|
+
maxBodySize?: number;
|
|
128
|
+
capturePerformance?: boolean;
|
|
129
|
+
captureRenders?: boolean;
|
|
130
|
+
stores?: Record<string, unknown>;
|
|
131
|
+
beforeSend?: (event: RuntimeEvent) => RuntimeEvent | null;
|
|
132
|
+
redactHeaders?: string[];
|
|
133
|
+
/** Regex patterns applied to all string fields before sending */
|
|
134
|
+
redactPatterns?: {
|
|
135
|
+
pattern: string;
|
|
136
|
+
replacement: string;
|
|
137
|
+
}[];
|
|
138
|
+
batchSize?: number;
|
|
139
|
+
flushIntervalMs?: number;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
declare class RuntimeScope {
|
|
143
|
+
private static transport;
|
|
144
|
+
private static restoreFns;
|
|
145
|
+
private static _sessionId;
|
|
146
|
+
static get sessionId(): string | null;
|
|
147
|
+
static connect(config?: RuntimeScopeConfig): void;
|
|
148
|
+
private static handleCommand;
|
|
149
|
+
/** Alias for `connect` — used by script-tag snippets */
|
|
150
|
+
static init(config?: RuntimeScopeConfig): void;
|
|
151
|
+
static disconnect(): void;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export { type BuildMeta, type ConsoleEvent, type DomSnapshotEvent, type NetworkEvent, type PerformanceEvent, type RenderEvent, type RuntimeEvent, RuntimeScope, type RuntimeScopeConfig, type SessionEvent, type StateEvent, RuntimeScope as default };
|
package/dist/index.global.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"use strict";var RuntimeScope=(()=>{var F=Object.defineProperty;var Y=Object.getOwnPropertyDescriptor;var Z=Object.getOwnPropertyNames;var ee=Object.prototype.hasOwnProperty;var te=(e,t,n)=>t in e?F(e,t,{enumerable:!0,configurable:!0,writable:!0,value:n}):e[t]=n;var ne=(e,t)=>{for(var n in t)F(e,n,{get:t[n],enumerable:!0})},re=(e,t,n,s)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of Z(t))!ee.call(e,r)&&r!==n&&F(e,r,{get:()=>t[r],enumerable:!(s=Y(t,r))||s.enumerable});return e};var se=e=>re(F({},"__esModule",{value:!0}),e);var h=(e,t,n)=>te(e,typeof t!="symbol"?t+"":t,n);var Te={};ne(Te,{RuntimeScope:()=>I,default:()=>Ce});var N=console.debug.bind(console),T=class T{constructor(t){h(this,"ws",null);h(this,"batch",[]);h(this,"offlineQueue",[]);h(this,"flushTimer",null);h(this,"reconnectTimer",null);h(this,"reconnectDelay",1e3);h(this,"connected",!1);h(this,"stopped",!1);h(this,"config");h(this,"commandHandler",null);this.config=t}connect(){this.stopped=!1,this.doConnect()}doConnect(){if(!this.stopped){try{this.ws=new WebSocket(this.config.serverUrl)}catch{this.scheduleReconnect();return}this.ws.onmessage=t=>{try{let n=JSON.parse(String(t.data));n.type==="command"&&n.payload&&this.commandHandler&&this.commandHandler(n.payload),n.type==="error"&&n.payload?.code==="AUTH_FAILED"&&(N("[RuntimeScope] Authentication failed \u2014 stopping reconnection"),this.stopped=!0)}catch{}},this.ws.onopen=()=>{if(this.connected=!0,this.reconnectDelay=1e3,N(`[RuntimeScope] Connected to ${this.config.serverUrl}`),this.sendRaw({type:"handshake",payload:{appName:this.config.appName,sdkVersion:this.config.sdkVersion,sessionId:this.config.sessionId,...this.config.authToken?{authToken:this.config.authToken}:{}},timestamp:Date.now(),sessionId:this.config.sessionId}),this.offlineQueue.length>0){let t=this.offlineQueue.splice(0);for(let n of t)this.batch.push(n);this.flush()}this.flushTimer=setInterval(()=>this.flush(),this.config.flushIntervalMs)},this.ws.onclose=()=>{this.connected=!1,this.clearFlushTimer(),this.stopped||(N("[RuntimeScope] Disconnected, will reconnect..."),this.scheduleReconnect())},this.ws.onerror=()=>{N(`[RuntimeScope] WebSocket error connecting to ${this.config.serverUrl}`)}}}send(t){this.connected?(this.batch.push(t),this.batch.length>=this.config.batchSize&&this.flush()):this.offlineQueue.length<T.MAX_OFFLINE_QUEUE&&this.offlineQueue.push(t)}flush(){if(this.batch.length===0||!this.connected||!this.ws)return;let t=this.batch.splice(0);this.sendRaw({type:"event",payload:{events:t},timestamp:Date.now(),sessionId:this.config.sessionId})}sendRaw(t){if(this.ws&&this.ws.readyState===WebSocket.OPEN)try{this.ws.send(JSON.stringify(t))}catch{}}scheduleReconnect(){if(this.stopped||this.reconnectTimer)return;let t=this.reconnectDelay*.25*(Math.random()*2-1),n=Math.min(this.reconnectDelay+t,T.MAX_RECONNECT_DELAY);this.reconnectTimer=setTimeout(()=>{this.reconnectTimer=null,this.reconnectDelay=Math.min(this.reconnectDelay*2,T.MAX_RECONNECT_DELAY),this.doConnect()},n)}clearFlushTimer(){this.flushTimer&&(clearInterval(this.flushTimer),this.flushTimer=null)}onCommand(t){this.commandHandler=t}sendCommandResponse(t,n,s){this.sendRaw({type:"command_response",requestId:t,command:n,payload:s,timestamp:Date.now(),sessionId:this.config.sessionId})}disconnect(){this.stopped=!0,this.clearFlushTimer(),this.reconnectTimer&&(clearTimeout(this.reconnectTimer),this.reconnectTimer=null),this.flush(),this.ws&&(this.ws.onclose=null,this.ws.onerror=null,this.ws.close(),this.ws=null),this.connected=!1,this.batch=[],this.offlineQueue=[]}};h(T,"MAX_OFFLINE_QUEUE",1e3),h(T,"MAX_RECONNECT_DELAY",3e4);var B=T;function l(){let e=new Uint8Array(4);return crypto.getRandomValues(e),Array.from(e,t=>t.toString(16).padStart(2,"0")).join("")}function A(){let e=new Uint8Array(16);return crypto.getRandomValues(e),Array.from(e,t=>t.toString(16).padStart(2,"0")).join("")}var M=new Set;function q(e,t,n,s){let r=window.fetch,c=new Set(n.map(i=>i.toLowerCase())),o=s?.captureBody??!1,a=s?.maxBodySize??65536;return window.fetch=async function(i,u){let d=performance.now(),p=typeof i=="string"?i:i instanceof URL?i.href:i.url,g=(u?.method??"GET").toUpperCase(),E=oe(u?.headers,c),y=ae(u?.body),_=ue(u?.body),k;o&&u?.body&&(k=ce(u.body,a));let S=`${g}:${p}:${d}`;M.add(S),setTimeout(()=>M.delete(S),5e3);try{let m=await r.call(window,i,u),L=performance.now()-d,b=parseInt(m.headers.get("content-length")||"0",10),f=ie(m.headers,c),w;if(o)try{let C=await m.clone().text();w=C.length>a?C.slice(0,a):C}catch{}let R={eventId:l(),sessionId:t,timestamp:Date.now(),eventType:"network",url:p,method:g,status:m.status,requestHeaders:E,responseHeaders:f,requestBodySize:y,responseBodySize:b,duration:L,ttfb:L,graphqlOperation:_,requestBody:k,responseBody:w,source:"fetch"};if(s?.beforeSend){let O=s.beforeSend(R);O&&e(O)}else e(R);return m}catch(m){let L=performance.now()-d,b="error",f="";m instanceof DOMException&&m.name==="AbortError"?(b="abort",f="Request aborted"):m instanceof Error&&(f=m.message);let w={eventId:l(),sessionId:t,timestamp:Date.now(),eventType:"network",url:p,method:g,status:0,requestHeaders:E,responseHeaders:{},requestBodySize:y,responseBodySize:0,duration:L,ttfb:0,graphqlOperation:_,requestBody:k,errorPhase:b,errorMessage:f,source:"fetch"};if(s?.beforeSend){let R=s.beforeSend(w);R&&e(R)}else e(w);throw m}},()=>{window.fetch=r}}function oe(e,t){let n={};if(!e)return n;if(e instanceof Headers)e.forEach((s,r)=>{n[r]=t.has(r.toLowerCase())?"[REDACTED]":s});else if(Array.isArray(e))for(let[s,r]of e)n[s]=t.has(s.toLowerCase())?"[REDACTED]":r;else for(let[s,r]of Object.entries(e))n[s]=t.has(s.toLowerCase())?"[REDACTED]":r;return n}function ie(e,t){let n={};return e.forEach((s,r)=>{n[r]=t.has(r.toLowerCase())?"[REDACTED]":s}),n}function ae(e){return e?typeof e=="string"?new Blob([e]).size:e instanceof Blob?e.size:e instanceof ArrayBuffer||ArrayBuffer.isView(e)?e.byteLength:e instanceof FormData?0:e instanceof URLSearchParams?new Blob([e.toString()]).size:0:0}function ce(e,t){if(e){if(typeof e=="string")return e.length>t?e.slice(0,t):e;if(e instanceof URLSearchParams){let n=e.toString();return n.length>t?n.slice(0,t):n}if(e instanceof FormData)return"[FormData]";if(e instanceof Blob)return`[Blob ${e.size} bytes]`;if(e instanceof ArrayBuffer)return`[ArrayBuffer ${e.byteLength} bytes]`;if(ArrayBuffer.isView(e))return`[TypedArray ${e.byteLength} bytes]`}}function ue(e){if(!(!e||typeof e!="string"))try{let t=JSON.parse(e);if(typeof t.query=="string"){let n=t.query.trim(),s="query";n.startsWith("mutation")?s="mutation":n.startsWith("subscription")&&(s="subscription");let r=t.operationName||de(n)||"anonymous";return{type:s,name:r}}}catch{}}function de(e){return e.match(/^(?:query|mutation|subscription)\s+(\w+)/)?.[1]}function v(e,t=5){let n=new WeakSet;function s(r,c){if(c>t)return"[max depth]";if(r==null)return r;if(typeof r=="function")return`[Function: ${r.name||"anonymous"}]`;if(typeof r=="symbol"||typeof r=="bigint")return r.toString();if(typeof r!="object")return r;if(r instanceof Error)return{name:r.name,message:r.message,stack:r.stack};if(r instanceof Date)return r.toISOString();if(r instanceof RegExp)return r.toString();if(n.has(r))return"[Circular]";if(n.add(r),Array.isArray(r))return r.map(a=>s(a,c+1));let o={};for(let a of Object.keys(r))o[a]=s(r[a],c+1);return o}return s(e,0)}var z=["log","warn","error","info","debug","trace"];function j(e,t,n){let s={};for(let r of z)s[r]=console[r].bind(console),console[r]=(...c)=>{let o=c.map(i=>typeof i=="string"?i:pe(i)).join(" "),a={eventId:l(),sessionId:t,timestamp:Date.now(),eventType:"console",level:r,message:o,args:c.map(i=>v(i,3)),stackTrace:r==="error"||r==="trace"?new Error().stack?.split(`
|
|
2
2
|
`).slice(2).join(`
|
|
3
|
-
`):void 0,sourceFile:void 0};if(n){let i=n(a);i&&e(i)}else e(a);s[r](...c)};return()=>{for(let r of z)console[r]=s[r]}}function pe(e){try{return JSON.stringify(e)}catch{return String(e)}}function X(e,t,n,s){let r=new Set(n.map(d=>d.toLowerCase())),c=s?.captureBody??!1,o=s?.maxBodySize??65536,a=XMLHttpRequest.prototype.open,i=XMLHttpRequest.prototype.setRequestHeader,u=XMLHttpRequest.prototype.send;return XMLHttpRequest.prototype.open=function(d,p){return this.__rs_method=d.toUpperCase(),this.__rs_url=typeof p=="string"?p:p.href,this.__rs_headers={},a.apply(this,arguments)},XMLHttpRequest.prototype.setRequestHeader=function(d,p){return this.__rs_headers&&(this.__rs_headers[d.toLowerCase()]=r.has(d.toLowerCase())?"[REDACTED]":p),i.call(this,d,p)},XMLHttpRequest.prototype.send=function(d){let p=this.__rs_method??"GET",g=this.__rs_url??"",E=`${p}:${g}`;if(Array.from(M).some(f=>f.startsWith(E)))return this.__rs_fetchIntercepted=!0,u.call(this,d);let _={...this.__rs_headers??{}},k=performance.now(),S,m=0;if(d){if(typeof d=="string")m=new Blob([d]).size,c&&(S=d.length>o?d.slice(0,o):d);else if(d instanceof Blob)m=d.size,c&&(S=`[Blob ${d.size} bytes]`);else if(d instanceof ArrayBuffer)m=d.byteLength,c&&(S=`[ArrayBuffer ${d.byteLength} bytes]`);else if(d instanceof FormData)c&&(S="[FormData]");else if(d instanceof URLSearchParams){let f=d.toString();m=new Blob([f]).size,c&&(S=f.length>o?f.slice(0,o):f)}}let L=le(d),b=f=>{let w={eventId:l(),sessionId:t,timestamp:Date.now(),eventType:"network",url:g,method:p,status:0,requestHeaders:_,responseHeaders:{},requestBodySize:m,responseBodySize:0,duration:0,ttfb:0,graphqlOperation:L,requestBody:S,source:"xhr",...f};if(s?.beforeSend){let R=s.beforeSend(w);R&&e(R)}else e(w)};return this.addEventListener("load",()=>{let f=performance.now()-k,w=fe(this.getAllResponseHeaders(),r),R=parseInt(this.getResponseHeader("content-length")||"0",10),O;if(c&&this.responseType===""||this.responseType==="text")try{let C=this.responseText;O=C.length>o?C.slice(0,o):C}catch{}b({status:this.status,responseHeaders:w,responseBodySize:R,responseBody:O,duration:f,ttfb:f})}),this.addEventListener("error",()=>{let f=performance.now()-k;b({duration:f,errorPhase:"error",errorMessage:"Network error"})}),this.addEventListener("abort",()=>{let f=performance.now()-k;b({duration:f,errorPhase:"abort",errorMessage:"Request aborted"})}),this.addEventListener("timeout",()=>{let f=performance.now()-k;b({duration:f,errorPhase:"timeout",errorMessage:`Request timed out after ${this.timeout}ms`})}),u.call(this,d)},()=>{XMLHttpRequest.prototype.open=a,XMLHttpRequest.prototype.setRequestHeader=i,XMLHttpRequest.prototype.send=u}}function fe(e,t){let n={};if(!e)return n;for(let s of e.trim().split(/[\r\n]+/)){let r=s.indexOf(":");if(r===-1)continue;let c=s.slice(0,r).trim().toLowerCase(),o=s.slice(r+1).trim();n[c]=t.has(c)?"[REDACTED]":o}return n}function le(e){if(!(!e||typeof e!="string"))try{let t=JSON.parse(e);if(typeof t.query=="string"){let n=t.query.trim(),s="query";n.startsWith("mutation")?s="mutation":n.startsWith("subscription")&&(s="subscription");let r=t.operationName||me(n)||"anonymous";return{type:s,name:r}}}catch{}}function me(e){return e.match(/^(?:query|mutation|subscription)\s+(\w+)/)?.[1]}function $(e,t,n,s){let r=[],c=new Map;for(let[o,a]of Object.entries(n)){let i=he(a);if(i==="zustand"){let u=a;x(e,t,s?.beforeSend,{storeId:o,library:i,phase:"init",state:v(u.getState(),4)});let d=u.subscribe((p,g)=>{let E=U(g,p);x(e,t,s?.beforeSend,{storeId:o,library:i,phase:"update",state:v(p,4),previousState:v(g,4),diff:E?v(E,3):void 0})});r.push(d)}else if(i==="redux"){let u=a;x(e,t,s?.beforeSend,{storeId:o,library:i,phase:"init",state:v(u.getState(),4)});let d,p=u.dispatch.bind(u);c.set(o,p),u.dispatch=y=>(y&&typeof y=="object"&&"type"in y&&(d={type:String(y.type),payload:y.payload}),p(y));let g=u.getState(),E=u.subscribe(()=>{let y=u.getState(),_=U(g,y);x(e,t,s?.beforeSend,{storeId:o,library:i,phase:"update",state:v(y,4),previousState:v(g,4),diff:_?v(_,3):void 0,action:d?v(d,3):void 0}),g=y,d=void 0});r.push(E)}}return()=>{for(let o of r)o();for(let[o,a]of c){let i=n[o];i&&(i.dispatch=a)}}}function he(e){if(!e||typeof e!="object")return"unknown";let t=e;return typeof t.getState=="function"&&typeof t.setState=="function"&&typeof t.subscribe=="function"?"zustand":typeof t.dispatch=="function"&&typeof t.getState=="function"&&typeof t.subscribe=="function"?"redux":"unknown"}function U(e,t){if(!e||!t||typeof e!="object"||typeof t!="object")return null;let n={},s=e,r=t,c=new Set([...Object.keys(s),...Object.keys(r)]);for(let o of c)s[o]!==r[o]&&(n[o]={from:s[o],to:r[o]});return Object.keys(n).length>0?n:null}function x(e,t,n,s){let r={eventId:l(),sessionId:t,timestamp:Date.now(),eventType:"state",...s};if(n){let c=n(r);c&&e(c)}else e(r)}var ge={LCP:[2500,4e3],FCP:[1800,3e3],CLS:[.1,.25],TTFB:[800,1800],FID:[100,300],INP:[200,500]};function ve(e,t){let[n,s]=ge[e]??[1/0,1/0];return t<=n?"good":t<=s?"needs-improvement":"poor"}function V(e,t,n){let s=[],r=(a,i,u)=>{let d={eventId:l(),sessionId:t,timestamp:Date.now(),eventType:"performance",metricName:a,value:Math.round(i*100)/100,rating:ve(a,i),element:u};if(n?.beforeSend){let p=n.beforeSend(d);p&&e(p)}else e(d)};D(s,"largest-contentful-paint",a=>{let i=a[a.length-1];if(!i)return;let u=i.element;r("LCP",i.startTime,u?.tagName?.toLowerCase())}),D(s,"paint",a=>{for(let i of a)i.name==="first-contentful-paint"&&r("FCP",i.startTime)});let c=0;D(s,"layout-shift",a=>{for(let i of a){let u=i;!u.hadRecentInput&&u.value&&(c+=u.value,r("CLS",c))}}),D(s,"first-input",a=>{let i=a[0];if(!i)return;let u=i;u.processingStart&&r("FID",u.processingStart-i.startTime)}),D(s,"navigation",a=>{let i=a[0];i&&r("TTFB",i.responseStart-i.requestStart)});let o=0;return D(s,"event",a=>{for(let i of a)i.duration>o&&(o=i.duration,r("INP",o))},{durationThreshold:16}),()=>{for(let a of s)try{a.disconnect()}catch{}}}function D(e,t,n,s){try{let r=new PerformanceObserver(c=>{n(c.getEntries())});r.observe({type:t,buffered:!0,...s}),e.push(r)}catch{}}var ye=0,we=1,W=1e4,Q=100;function G(e,t,n){let s=new Map,r=n?.snapshotIntervalMs??5e3,c=null,o=Re();if(!o)return()=>{};let a=o.onCommitFiberRoot;return o._runtimescope_original=a,o.onCommitFiberRoot=(i,u)=>{if(a)try{a(i,u)}catch{}u.current&&H(u.current,s)},c=setInterval(()=>{_e(s,e,t,n?.beforeSend)},r),()=>{c&&(clearInterval(c),c=null),o&&(o._runtimescope_original?o.onCommitFiberRoot=o._runtimescope_original:delete o.onCommitFiberRoot,delete o._runtimescope_original)}}function Re(){if(typeof window>"u")return null;let e=window;return e.__REACT_DEVTOOLS_GLOBAL_HOOK__||(e.__REACT_DEVTOOLS_GLOBAL_HOOK__={}),e.__REACT_DEVTOOLS_GLOBAL_HOOK__}function H(e,t){Ee(e,t),e.child&&H(e.child,t),e.sibling&&H(e.sibling,t)}function Ee(e,t){if(e.tag!==ye&&e.tag!==we)return;let n=Se(e);if(!n)return;let s=Date.now(),r=e.alternate===null,c=e.actualDuration??0,o=be(e,r),a=t.get(n);a||(a={renderCount:0,totalDuration:0,lastRenderTime:0,lastRenderPhase:"mount",lastRenderCause:"unknown",renderTimestamps:[]},t.set(n,a)),a.renderCount++,a.totalDuration+=c,a.lastRenderTime=s,a.lastRenderPhase=r?"mount":"update",a.lastRenderCause=o,a.renderTimestamps.push(s),a.renderTimestamps.length>Q&&(a.renderTimestamps=a.renderTimestamps.slice(-Q))}function Se(e){if(e.type&&typeof e.type!="string")return e.type.displayName||e.type.name||void 0}function be(e,t){return t?"props":e.alternate?e.memoizedProps!==e.alternate.memoizedProps?"props":e.memoizedState!==e.alternate.memoizedState?"state":"parent":"unknown"}function ke(e){if(e.length<2)return 0;let t=Date.now(),n=t-W,s=e.filter(c=>c>=n);if(s.length<2)return 0;let r=t-s[0];return r===0?0:s.length/(r/1e3)}function _e(e,t,n,s){if(e.size===0)return;let r=[],c=[],o=0;for(let[i,u]of e){let d=ke(u.renderTimestamps),p=d>4||u.renderCount>20;r.push({componentName:i,renderCount:u.renderCount,totalDuration:Math.round(u.totalDuration*100)/100,avgDuration:u.renderCount>0?Math.round(u.totalDuration/u.renderCount*100)/100:0,lastRenderPhase:u.lastRenderPhase,lastRenderCause:u.lastRenderCause,renderVelocity:Math.round(d*100)/100,suspicious:p}),p&&c.push(i),o+=u.renderCount}r.sort((i,u)=>u.renderCount-i.renderCount);let a={eventId:l(),sessionId:n,timestamp:Date.now(),eventType:"render",profiles:r,snapshotWindowMs:W,totalRenders:o,suspiciousComponents:c};if(s){let i=s(a);i&&t(i)}else t(a);for(let i of e.values())i.renderCount=0,i.totalDuration=0}function K(e,t,n){let s=c=>{let o,a,i;if(c instanceof ErrorEvent)o=c.message||"Uncaught error",a=c.error?.stack,i=c.filename?`${c.filename}:${c.lineno}:${c.colno}`:void 0;else{let d=c.target;if(d&&d!==window){let p=d.tagName?.toLowerCase()??"unknown",g=d.src??d.src??d.href??"unknown";o=`Failed to load resource: <${p}> ${g}`}else return}let u={eventId:l(),sessionId:t,timestamp:Date.now(),eventType:"console",level:"error",message:`[Uncaught] ${o}`,args:[v(o,3)],stackTrace:a,sourceFile:i};if(n){let d=n(u);d&&e(d)}else e(u)},r=c=>{let o=c.reason,a,i;if(o instanceof Error)a=o.message,i=o.stack;else if(typeof o=="string")a=o;else try{a=JSON.stringify(o)}catch{a=String(o)}let u={eventId:l(),sessionId:t,timestamp:Date.now(),eventType:"console",level:"error",message:`[Unhandled Rejection] ${a}`,args:[v(o,3)],stackTrace:i,sourceFile:void 0};if(n){let d=n(u);d&&e(d)}else e(u)};return window.addEventListener("error",s,!0),window.addEventListener("unhandledrejection",r),()=>{window.removeEventListener("error",s,!0),window.removeEventListener("unhandledrejection",r)}}var P="0.6.0",J=console.debug.bind(console),I=class{static get sessionId(){return this._sessionId}static connect(t={}){if(t.enabled===!1)return;this.transport&&this.disconnect();let n={serverUrl:t.serverUrl??t.endpoint??"ws://localhost:9090",appName:t.appName??"unknown",captureNetwork:t.captureNetwork??!0,captureConsole:t.captureConsole??!0,captureXhr:t.captureXhr??!0,captureBody:t.captureBody??!1,maxBodySize:t.maxBodySize??65536,capturePerformance:t.capturePerformance??!1,captureRenders:t.captureRenders??!1,stores:t.stores??{},beforeSend:t.beforeSend,redactHeaders:t.redactHeaders??["authorization","cookie"],batchSize:t.batchSize??50,flushIntervalMs:t.flushIntervalMs??100};this._sessionId=A(),this.transport=new B({serverUrl:n.serverUrl,appName:n.appName,sessionId:this._sessionId,sdkVersion:P,authToken:t.authToken,batchSize:n.batchSize,flushIntervalMs:n.flushIntervalMs}),this.transport.connect(),J(`[RuntimeScope] SDK v${P} initializing \u2014 app: ${n.appName}, server: ${n.serverUrl}`);let s=o=>this.transport?.send(o);s({eventId:l(),sessionId:this._sessionId,timestamp:Date.now(),eventType:"session",appName:n.appName,connectedAt:Date.now(),sdkVersion:P,buildMeta:t.buildMeta});let r=this._sessionId;this.transport.onCommand(o=>{this.handleCommand(o,s,r)}),n.captureNetwork&&this.restoreFns.push(q(s,this._sessionId,n.redactHeaders,{captureBody:n.captureBody,maxBodySize:n.maxBodySize,beforeSend:n.beforeSend})),n.captureXhr&&this.restoreFns.push(X(s,this._sessionId,n.redactHeaders,{captureBody:n.captureBody,maxBodySize:n.maxBodySize,beforeSend:n.beforeSend})),n.captureConsole&&(this.restoreFns.push(j(s,this._sessionId,n.beforeSend)),this.restoreFns.push(K(s,this._sessionId,n.beforeSend))),Object.keys(n.stores).length>0&&this.restoreFns.push($(s,this._sessionId,n.stores,{beforeSend:n.beforeSend})),n.capturePerformance&&this.restoreFns.push(V(s,this._sessionId,{beforeSend:n.beforeSend})),n.captureRenders&&this.restoreFns.push(G(s,this._sessionId,{beforeSend:n.beforeSend}));let c=[n.captureNetwork&&"fetch",n.captureXhr&&"xhr",n.captureConsole&&"console, errors",Object.keys(n.stores).length>0&&"state",n.capturePerformance&&"performance",n.captureRenders&&"renders"].filter(Boolean);J(`[RuntimeScope] Interceptors active \u2014 ${c.join(", ")}`)}static handleCommand(t,n,s){if(t.command==="capture_dom_snapshot"){let r=t.params?.maxSize??5e5,c=document.documentElement.outerHTML,o=c.length>r;o&&(c=c.slice(0,r));let a={eventId:l(),sessionId:s,timestamp:Date.now(),eventType:"dom_snapshot",html:c,url:window.location.href,viewport:{width:window.innerWidth,height:window.innerHeight},scrollPosition:{x:window.scrollX,y:window.scrollY},elementCount:document.querySelectorAll("*").length,truncated:o};n(a),this.transport?.sendCommandResponse(t.requestId,t.command,a)}else this.transport?.sendCommandResponse(t.requestId,t.command,{error:"Unknown command"})}static init(t={}){return this.connect(t)}static disconnect(){for(let t of this.restoreFns)t();this.restoreFns=[],this.transport?.disconnect(),this.transport=null,this._sessionId=null}};h(I,"transport",null),h(I,"restoreFns",[]),h(I,"_sessionId",null);var Ce=I;return se(Te);})();
|
|
3
|
+
`):void 0,sourceFile:void 0};if(n){let i=n(a);i&&e(i)}else e(a);s[r](...c)};return()=>{for(let r of z)console[r]=s[r]}}function pe(e){try{return JSON.stringify(e)}catch{return String(e)}}function X(e,t,n,s){let r=new Set(n.map(d=>d.toLowerCase())),c=s?.captureBody??!1,o=s?.maxBodySize??65536,a=XMLHttpRequest.prototype.open,i=XMLHttpRequest.prototype.setRequestHeader,u=XMLHttpRequest.prototype.send;return XMLHttpRequest.prototype.open=function(d,p){return this.__rs_method=d.toUpperCase(),this.__rs_url=typeof p=="string"?p:p.href,this.__rs_headers={},a.apply(this,arguments)},XMLHttpRequest.prototype.setRequestHeader=function(d,p){return this.__rs_headers&&(this.__rs_headers[d.toLowerCase()]=r.has(d.toLowerCase())?"[REDACTED]":p),i.call(this,d,p)},XMLHttpRequest.prototype.send=function(d){let p=this.__rs_method??"GET",g=this.__rs_url??"",E=`${p}:${g}`;if(Array.from(M).some(f=>f.startsWith(E)))return this.__rs_fetchIntercepted=!0,u.call(this,d);let _={...this.__rs_headers??{}},k=performance.now(),S,m=0;if(d){if(typeof d=="string")m=new Blob([d]).size,c&&(S=d.length>o?d.slice(0,o):d);else if(d instanceof Blob)m=d.size,c&&(S=`[Blob ${d.size} bytes]`);else if(d instanceof ArrayBuffer)m=d.byteLength,c&&(S=`[ArrayBuffer ${d.byteLength} bytes]`);else if(d instanceof FormData)c&&(S="[FormData]");else if(d instanceof URLSearchParams){let f=d.toString();m=new Blob([f]).size,c&&(S=f.length>o?f.slice(0,o):f)}}let L=le(d),b=f=>{let w={eventId:l(),sessionId:t,timestamp:Date.now(),eventType:"network",url:g,method:p,status:0,requestHeaders:_,responseHeaders:{},requestBodySize:m,responseBodySize:0,duration:0,ttfb:0,graphqlOperation:L,requestBody:S,source:"xhr",...f};if(s?.beforeSend){let R=s.beforeSend(w);R&&e(R)}else e(w)};return this.addEventListener("load",()=>{let f=performance.now()-k,w=fe(this.getAllResponseHeaders(),r),R=parseInt(this.getResponseHeader("content-length")||"0",10),O;if(c&&this.responseType===""||this.responseType==="text")try{let C=this.responseText;O=C.length>o?C.slice(0,o):C}catch{}b({status:this.status,responseHeaders:w,responseBodySize:R,responseBody:O,duration:f,ttfb:f})}),this.addEventListener("error",()=>{let f=performance.now()-k;b({duration:f,errorPhase:"error",errorMessage:"Network error"})}),this.addEventListener("abort",()=>{let f=performance.now()-k;b({duration:f,errorPhase:"abort",errorMessage:"Request aborted"})}),this.addEventListener("timeout",()=>{let f=performance.now()-k;b({duration:f,errorPhase:"timeout",errorMessage:`Request timed out after ${this.timeout}ms`})}),u.call(this,d)},()=>{XMLHttpRequest.prototype.open=a,XMLHttpRequest.prototype.setRequestHeader=i,XMLHttpRequest.prototype.send=u}}function fe(e,t){let n={};if(!e)return n;for(let s of e.trim().split(/[\r\n]+/)){let r=s.indexOf(":");if(r===-1)continue;let c=s.slice(0,r).trim().toLowerCase(),o=s.slice(r+1).trim();n[c]=t.has(c)?"[REDACTED]":o}return n}function le(e){if(!(!e||typeof e!="string"))try{let t=JSON.parse(e);if(typeof t.query=="string"){let n=t.query.trim(),s="query";n.startsWith("mutation")?s="mutation":n.startsWith("subscription")&&(s="subscription");let r=t.operationName||me(n)||"anonymous";return{type:s,name:r}}}catch{}}function me(e){return e.match(/^(?:query|mutation|subscription)\s+(\w+)/)?.[1]}function $(e,t,n,s){let r=[],c=new Map;for(let[o,a]of Object.entries(n)){let i=he(a);if(i==="zustand"){let u=a;x(e,t,s?.beforeSend,{storeId:o,library:i,phase:"init",state:v(u.getState(),4)});let d=u.subscribe((p,g)=>{let E=U(g,p);x(e,t,s?.beforeSend,{storeId:o,library:i,phase:"update",state:v(p,4),previousState:v(g,4),diff:E?v(E,3):void 0})});r.push(d)}else if(i==="redux"){let u=a;x(e,t,s?.beforeSend,{storeId:o,library:i,phase:"init",state:v(u.getState(),4)});let d,p=u.dispatch.bind(u);c.set(o,p),u.dispatch=y=>(y&&typeof y=="object"&&"type"in y&&(d={type:String(y.type),payload:y.payload}),p(y));let g=u.getState(),E=u.subscribe(()=>{let y=u.getState(),_=U(g,y);x(e,t,s?.beforeSend,{storeId:o,library:i,phase:"update",state:v(y,4),previousState:v(g,4),diff:_?v(_,3):void 0,action:d?v(d,3):void 0}),g=y,d=void 0});r.push(E)}}return()=>{for(let o of r)o();for(let[o,a]of c){let i=n[o];i&&(i.dispatch=a)}}}function he(e){if(!e||typeof e!="object")return"unknown";let t=e;return typeof t.getState=="function"&&typeof t.setState=="function"&&typeof t.subscribe=="function"?"zustand":typeof t.dispatch=="function"&&typeof t.getState=="function"&&typeof t.subscribe=="function"?"redux":"unknown"}function U(e,t){if(!e||!t||typeof e!="object"||typeof t!="object")return null;let n={},s=e,r=t,c=new Set([...Object.keys(s),...Object.keys(r)]);for(let o of c)s[o]!==r[o]&&(n[o]={from:s[o],to:r[o]});return Object.keys(n).length>0?n:null}function x(e,t,n,s){let r={eventId:l(),sessionId:t,timestamp:Date.now(),eventType:"state",...s};if(n){let c=n(r);c&&e(c)}else e(r)}var ge={LCP:[2500,4e3],FCP:[1800,3e3],CLS:[.1,.25],TTFB:[800,1800],FID:[100,300],INP:[200,500]};function ve(e,t){let[n,s]=ge[e]??[1/0,1/0];return t<=n?"good":t<=s?"needs-improvement":"poor"}function V(e,t,n){let s=[],r=(a,i,u)=>{let d={eventId:l(),sessionId:t,timestamp:Date.now(),eventType:"performance",metricName:a,value:Math.round(i*100)/100,rating:ve(a,i),element:u};if(n?.beforeSend){let p=n.beforeSend(d);p&&e(p)}else e(d)};D(s,"largest-contentful-paint",a=>{let i=a[a.length-1];if(!i)return;let u=i.element;r("LCP",i.startTime,u?.tagName?.toLowerCase())}),D(s,"paint",a=>{for(let i of a)i.name==="first-contentful-paint"&&r("FCP",i.startTime)});let c=0;D(s,"layout-shift",a=>{for(let i of a){let u=i;!u.hadRecentInput&&u.value&&(c+=u.value,r("CLS",c))}}),D(s,"first-input",a=>{let i=a[0];if(!i)return;let u=i;u.processingStart&&r("FID",u.processingStart-i.startTime)}),D(s,"navigation",a=>{let i=a[0];i&&r("TTFB",i.responseStart-i.requestStart)});let o=0;return D(s,"event",a=>{for(let i of a)i.duration>o&&(o=i.duration,r("INP",o))},{durationThreshold:16}),()=>{for(let a of s)try{a.disconnect()}catch{}}}function D(e,t,n,s){try{let r=new PerformanceObserver(c=>{n(c.getEntries())});r.observe({type:t,buffered:!0,...s}),e.push(r)}catch{}}var ye=0,we=1,W=1e4,Q=100;function G(e,t,n){let s=new Map,r=n?.snapshotIntervalMs??5e3,c=null,o=Re();if(!o)return()=>{};let a=o.onCommitFiberRoot;return o._runtimescope_original=a,o.onCommitFiberRoot=(i,u)=>{if(a)try{a(i,u)}catch{}u.current&&H(u.current,s)},c=setInterval(()=>{_e(s,e,t,n?.beforeSend)},r),()=>{c&&(clearInterval(c),c=null),o&&(o._runtimescope_original?o.onCommitFiberRoot=o._runtimescope_original:delete o.onCommitFiberRoot,delete o._runtimescope_original)}}function Re(){if(typeof window>"u")return null;let e=window;return e.__REACT_DEVTOOLS_GLOBAL_HOOK__||(e.__REACT_DEVTOOLS_GLOBAL_HOOK__={}),e.__REACT_DEVTOOLS_GLOBAL_HOOK__}function H(e,t){Ee(e,t),e.child&&H(e.child,t),e.sibling&&H(e.sibling,t)}function Ee(e,t){if(e.tag!==ye&&e.tag!==we)return;let n=Se(e);if(!n)return;let s=Date.now(),r=e.alternate===null,c=e.actualDuration??0,o=be(e,r),a=t.get(n);a||(a={renderCount:0,totalDuration:0,lastRenderTime:0,lastRenderPhase:"mount",lastRenderCause:"unknown",renderTimestamps:[]},t.set(n,a)),a.renderCount++,a.totalDuration+=c,a.lastRenderTime=s,a.lastRenderPhase=r?"mount":"update",a.lastRenderCause=o,a.renderTimestamps.push(s),a.renderTimestamps.length>Q&&(a.renderTimestamps=a.renderTimestamps.slice(-Q))}function Se(e){if(e.type&&typeof e.type!="string")return e.type.displayName||e.type.name||void 0}function be(e,t){return t?"props":e.alternate?e.memoizedProps!==e.alternate.memoizedProps?"props":e.memoizedState!==e.alternate.memoizedState?"state":"parent":"unknown"}function ke(e){if(e.length<2)return 0;let t=Date.now(),n=t-W,s=e.filter(c=>c>=n);if(s.length<2)return 0;let r=t-s[0];return r===0?0:s.length/(r/1e3)}function _e(e,t,n,s){if(e.size===0)return;let r=[],c=[],o=0;for(let[i,u]of e){let d=ke(u.renderTimestamps),p=d>4||u.renderCount>20;r.push({componentName:i,renderCount:u.renderCount,totalDuration:Math.round(u.totalDuration*100)/100,avgDuration:u.renderCount>0?Math.round(u.totalDuration/u.renderCount*100)/100:0,lastRenderPhase:u.lastRenderPhase,lastRenderCause:u.lastRenderCause,renderVelocity:Math.round(d*100)/100,suspicious:p}),p&&c.push(i),o+=u.renderCount}r.sort((i,u)=>u.renderCount-i.renderCount);let a={eventId:l(),sessionId:n,timestamp:Date.now(),eventType:"render",profiles:r,snapshotWindowMs:W,totalRenders:o,suspiciousComponents:c};if(s){let i=s(a);i&&t(i)}else t(a);for(let i of e.values())i.renderCount=0,i.totalDuration=0}function K(e,t,n){let s=c=>{let o,a,i;if(c instanceof ErrorEvent)o=c.message||"Uncaught error",a=c.error?.stack,i=c.filename?`${c.filename}:${c.lineno}:${c.colno}`:void 0;else{let d=c.target;if(d&&d!==window){let p=d.tagName?.toLowerCase()??"unknown",g=d.src??d.src??d.href??"unknown";o=`Failed to load resource: <${p}> ${g}`}else return}let u={eventId:l(),sessionId:t,timestamp:Date.now(),eventType:"console",level:"error",message:`[Uncaught] ${o}`,args:[v(o,3)],stackTrace:a,sourceFile:i};if(n){let d=n(u);d&&e(d)}else e(u)},r=c=>{let o=c.reason,a,i;if(o instanceof Error)a=o.message,i=o.stack;else if(typeof o=="string")a=o;else try{a=JSON.stringify(o)}catch{a=String(o)}let u={eventId:l(),sessionId:t,timestamp:Date.now(),eventType:"console",level:"error",message:`[Unhandled Rejection] ${a}`,args:[v(o,3)],stackTrace:i,sourceFile:void 0};if(n){let d=n(u);d&&e(d)}else e(u)};return window.addEventListener("error",s,!0),window.addEventListener("unhandledrejection",r),()=>{window.removeEventListener("error",s,!0),window.removeEventListener("unhandledrejection",r)}}var P="0.6.1",J=console.debug.bind(console),I=class{static get sessionId(){return this._sessionId}static connect(t={}){if(t.enabled===!1)return;this.transport&&this.disconnect();let n={serverUrl:t.serverUrl??t.endpoint??"ws://localhost:9090",appName:t.appName??"unknown",captureNetwork:t.captureNetwork??!0,captureConsole:t.captureConsole??!0,captureXhr:t.captureXhr??!0,captureBody:t.captureBody??!1,maxBodySize:t.maxBodySize??65536,capturePerformance:t.capturePerformance??!1,captureRenders:t.captureRenders??!1,stores:t.stores??{},beforeSend:t.beforeSend,redactHeaders:t.redactHeaders??["authorization","cookie"],batchSize:t.batchSize??50,flushIntervalMs:t.flushIntervalMs??100};this._sessionId=A(),this.transport=new B({serverUrl:n.serverUrl,appName:n.appName,sessionId:this._sessionId,sdkVersion:P,authToken:t.authToken,batchSize:n.batchSize,flushIntervalMs:n.flushIntervalMs}),this.transport.connect(),J(`[RuntimeScope] SDK v${P} initializing \u2014 app: ${n.appName}, server: ${n.serverUrl}`);let s=o=>this.transport?.send(o);s({eventId:l(),sessionId:this._sessionId,timestamp:Date.now(),eventType:"session",appName:n.appName,connectedAt:Date.now(),sdkVersion:P,buildMeta:t.buildMeta});let r=this._sessionId;this.transport.onCommand(o=>{this.handleCommand(o,s,r)}),n.captureNetwork&&this.restoreFns.push(q(s,this._sessionId,n.redactHeaders,{captureBody:n.captureBody,maxBodySize:n.maxBodySize,beforeSend:n.beforeSend})),n.captureXhr&&this.restoreFns.push(X(s,this._sessionId,n.redactHeaders,{captureBody:n.captureBody,maxBodySize:n.maxBodySize,beforeSend:n.beforeSend})),n.captureConsole&&(this.restoreFns.push(j(s,this._sessionId,n.beforeSend)),this.restoreFns.push(K(s,this._sessionId,n.beforeSend))),Object.keys(n.stores).length>0&&this.restoreFns.push($(s,this._sessionId,n.stores,{beforeSend:n.beforeSend})),n.capturePerformance&&this.restoreFns.push(V(s,this._sessionId,{beforeSend:n.beforeSend})),n.captureRenders&&this.restoreFns.push(G(s,this._sessionId,{beforeSend:n.beforeSend}));let c=[n.captureNetwork&&"fetch",n.captureXhr&&"xhr",n.captureConsole&&"console, errors",Object.keys(n.stores).length>0&&"state",n.capturePerformance&&"performance",n.captureRenders&&"renders"].filter(Boolean);J(`[RuntimeScope] Interceptors active \u2014 ${c.join(", ")}`)}static handleCommand(t,n,s){if(t.command==="capture_dom_snapshot"){let r=t.params?.maxSize??5e5,c=document.documentElement.outerHTML,o=c.length>r;o&&(c=c.slice(0,r));let a={eventId:l(),sessionId:s,timestamp:Date.now(),eventType:"dom_snapshot",html:c,url:window.location.href,viewport:{width:window.innerWidth,height:window.innerHeight},scrollPosition:{x:window.scrollX,y:window.scrollY},elementCount:document.querySelectorAll("*").length,truncated:o};n(a),this.transport?.sendCommandResponse(t.requestId,t.command,a)}else this.transport?.sendCommandResponse(t.requestId,t.command,{error:"Unknown command"})}static init(t={}){return this.connect(t)}static disconnect(){for(let t of this.restoreFns)t();this.restoreFns=[],this.transport?.disconnect(),this.transport=null,this._sessionId=null}};h(I,"transport",null),h(I,"restoreFns",[]),h(I,"_sessionId",null);var Ce=I;return se(Te);})();
|
|
4
4
|
if(typeof RuntimeScope!=="undefined"&&RuntimeScope.RuntimeScope){RuntimeScope=RuntimeScope.RuntimeScope;}
|
|
5
5
|
//# sourceMappingURL=index.global.js.map
|