@senzops/apm-node 1.1.4 → 1.1.5

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.
@@ -1,2 +1,2 @@
1
- "use strict";(()=>{var B=Object.create;var P=Object.defineProperty;var J=Object.getOwnPropertyDescriptor;var Q=Object.getOwnPropertyNames;var V=Object.getPrototypeOf,X=Object.prototype.hasOwnProperty;var T=(e=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(e,{get:(t,n)=>(typeof require<"u"?require:t)[n]}):e)(function(e){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+e+'" is not supported')});var Y=(e,t,n,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of Q(t))!X.call(e,o)&&o!==n&&P(e,o,{get:()=>t[o],enumerable:!(r=J(t,o))||r.enumerable});return e};var $=(e,t,n)=>(n=e!=null?B(V(e)):{},Y(t||!e||!e.__esModule?P(n,"default",{value:e,enumerable:!0}):n,e));var E=class{constructor(t){this.config=t;this.queue=[];this.timer=null;typeof setInterval<"u"&&(this.timer=setInterval(()=>this.flush(),t.flushInterval||1e4),this.timer&&typeof this.timer.unref=="function"&&this.timer.unref())}add(t){this.queue.push(t),this.queue.length>=(this.config.batchSize||100)&&this.flush()}async flush(){if(this.queue.length===0)return;let t=[...this.queue];this.queue=[];try{await fetch(this.config.endpoint||"https://api.senzor.dev/api/ingest/apm",{method:"POST",headers:{"Content-Type":"application/json","x-service-api-key":this.config.apiKey},body:JSON.stringify(t),keepalive:!0}),this.config.debug&&console.log(`[Senzor] Flushed ${t.length} traces`)}catch(n){this.config.debug&&console.error("[Senzor] Ingestion Error:",n)}}};var H=T("async_hooks"),C=new H.AsyncLocalStorage,m={run:(e,t)=>C.run(e,t),current:()=>C.getStore(),addSpan:e=>{let t=C.getStore();t&&t.spans.push(e)},setError:e=>{let t=C.getStore();t&&(t.error={name:e.name,message:e.message,stack:e.stack})}};var k=T("crypto");var z=$(T("http")),v=$(T("https")),b=T("url");var F=(e,t,n)=>{if(!e[t])return;let r=e[t];e[t]=n(r)},N=(e,t=!1)=>{if(!globalThis.fetch)return;let n="";try{n=new b.URL(e).hostname}catch{}let r=globalThis.fetch;globalThis.fetch=async(o,a)=>{let i="";if(typeof o=="string"?i=o:o instanceof b.URL?i=o.toString():o&&o.url&&(i=o.url),n&&i.includes(n))return r(o,a);let u=m.current();if(!u)return r(o,a);let c=(a?.method||"GET").toUpperCase(),h=performance.now()-u.startTime,w=performance.now(),y="unknown";try{y=new b.URL(i).hostname}catch{}t&&console.log(`[Senzor] Tracking Fetch: ${c} ${y}`);try{let l=await r(o,a),d=performance.now()-w;return m.addSpan({name:`${c} ${y}`,type:"http",startTime:h,duration:d,status:l.status,meta:{url:i,method:c,library:"fetch"}}),l}catch(l){let d=performance.now()-w;throw m.addSpan({name:`${c} ${y}`,type:"http",startTime:h,duration:d,status:500,meta:{error:l.message,url:i,library:"fetch"}}),l}}},R=(e,t=!1)=>{let n="";try{n=new b.URL(e).hostname}catch{}let r=o=>function(...a){let i={},u="";if(typeof a[0]=="string"||a[0]instanceof b.URL)u=a[0].toString(),typeof a[1]=="object"&&a[1]!==null&&(i=a[1]);else{i=a[0]||{};let p=i.protocol||(i.port===443?"https:":"http:"),f=i.hostname||i.host||"localhost",x=i.path||"/";u=`${p}//${f}${x}`}if(n&&(u.includes(n)||i.hostname&&i.hostname.includes(n)))return o.apply(this,a);let c=m.current();if(!c)return o.apply(this,a);let h=(i.method||"GET").toUpperCase(),w=performance.now()-c.startTime,y=performance.now(),l="unknown";try{l=new b.URL(u).hostname}catch{l=i.hostname||"unknown"}let d=o.apply(this,a),g=(p,f)=>{let x=performance.now()-y;m.addSpan({name:`${h} ${l}`,type:"http",startTime:w,duration:x,status:f?500:p?.statusCode||0,meta:{url:u,method:h,library:"http",error:f?f.message:void 0}})};return d.on("response",p=>{p.once("end",()=>g(p)),p.once("error",f=>g(p,f))}),d.on("error",p=>g(null,p)),d};F(z.default,"request",r),F(z.default,"get",r),F(v.default,"request",r),F(v.default,"get",r)};var M=(e=!1)=>{try{let t=T("mongodb"),n=t.Collection,r=t.FindCursor||T("mongodb/lib/cursor/find_cursor").FindCursor,o=t.AggregationCursor||T("mongodb/lib/cursor/aggregation_cursor").AggregationCursor;e&&console.log("[Senzor] Instrumenting MongoDB (Collection + Cursors)...");let a=(c,h,w,y,l,d)=>{let g=performance.now()-y;m.addSpan({name:`MongoDB ${c}`,type:"db",startTime:performance.now()-l-g,duration:g,status:d?500:0,meta:{collection:w,operation:h,error:d?d.message:void 0}}),e&&console.log(`[Senzor] Captured Mongo: ${c} (${g.toFixed(2)}ms)`)};["insertOne","insertMany","updateOne","updateMany","deleteOne","deleteMany","countDocuments"].forEach(c=>{if(!n.prototype[c])return;let h=n.prototype[c];n.prototype[c]=function(...w){let y=m.current();if(!y)return h.apply(this,w);let l=performance.now(),d=y.startTime,g=this.collectionName;try{let p=h.apply(this,w);return p&&typeof p.then=="function"?p.then(f=>(a(c,c,g,l,d),f),f=>{throw a(c,c,g,l,d,f),f}):p}catch(p){throw a(c,c,g,l,d,p),p}}});let u=(c,h)=>{if(!c||!c.prototype.toArray)return;let w=c.prototype.toArray;c.prototype.toArray=function(...y){let l=m.current();if(!l)return w.apply(this,y);let d=performance.now(),g=l.startTime,p=this.namespace?.collection||"unknown",f=S=>(a(h,h,p,d,g),S),x=S=>{throw a(h,h,p,d,g,S),S};try{let S=w.apply(this,y);return S&&typeof S.then=="function"?S.then(f,x):f(S)}catch(S){x(S)}}};u(r,"find"),u(o,"aggregate")}catch(t){e&&console.warn("[Senzor] MongoDB instrumentation warning:",t.message)}};var U=()=>{try{let e=T("pg"),t=e.Client.prototype.query;e.Client.prototype.query=function(...n){let r=m.current();if(!r)return t.apply(this,n);let o=performance.now()-r.startTime,a=performance.now(),i=typeof n[0]=="string"?n[0]:n[0].text,u=t.apply(this,n);return u&&typeof u.then=="function"?u.then(c=>{let h=performance.now()-a;return m.addSpan({name:"Postgres Query",type:"db",startTime:o,duration:h,meta:{query:i}}),c}):u}}catch{}};var O=class{constructor(){this.transport=null;this.options=null;this.isInstrumented=!1}init(t){if(!t.apiKey){console.warn("[Senzor] API Key missing. SDK disabled.");return}this.options=t;let n=t.endpoint||"https://api.senzor.dev/api/ingest/apm",r=t.debug||!1;if(this.transport=new E({...t,endpoint:n}),!this.isInstrumented){try{R(n,r)}catch{}try{N(n,r)}catch{}try{M(r)}catch{}try{U()}catch{}this.isInstrumented=!0,r&&console.log("[Senzor] Auto-instrumentation enabled")}}startTrace(t,n){if(!this.transport)return n();let r={id:(0,k.randomUUID)(),startTime:performance.now(),data:t,spans:[]};return m.run(r,n)}endTrace(t,n={}){let r=m.current();if(!r||!this.transport)return;let o=performance.now()-r.startTime,a={traceId:r.id,...r.data,...n,status:t,duration:o,spans:r.spans,error:r.error,timestamp:new Date().toISOString()};this.transport.add(a)}captureError(t){t instanceof Error?m.setError(t):typeof t=="string"&&m.setError(new Error(t))}track(t){this.transport?.add({traceId:(0,k.randomUUID)(),...t,spans:[],timestamp:new Date().toISOString()})}startSpan(t,n="custom"){let r=m.current();if(!r)return{end:()=>{}};let o=performance.now()-r.startTime,a=performance.now();return{end:(i,u)=>{m.addSpan({name:t,type:n,startTime:o,duration:performance.now()-a,status:u,meta:i})}}}async flush(){this.transport&&await this.transport.flush()}},s=new O;var D=()=>(e,t,n)=>{s.startTrace({method:e.method,path:e.originalUrl||e.url,ip:e.ip||e.socket?.remoteAddress,userAgent:e.headers["user-agent"]},()=>{t.once("finish",()=>{try{let r="UNKNOWN";e.route&&e.route.path?r=(e.baseUrl||"")+e.route.path:t.statusCode===404?r="Not Found":r=e.path||"Wildcard",s.endTrace(t.statusCode,{route:r})}catch{}}),n()})},K=()=>(e,t,n,r)=>{s.captureError(e),r(e)};var A=e=>!e||e==="/"?"/":e.replace(/[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}/g,":uuid").replace(/[0-9a-fA-F]{24}/g,":objectId").replace(/\/(\d+)(?=\/|$)/g,"/:id").split("?")[0],I=(e,t)=>e.route&&e.route.path?(e.baseUrl||"")+e.route.path:e.context&&e.context.matchedRoute?e.context.matchedRoute.path:e.routerPath?e.routerPath:A(t);var G=e=>t=>{let n=t.node.req,r=n.originalUrl||n.url||"/";return s.startTrace({method:n.method||"GET",path:r,ip:n.headers["x-forwarded-for"]||n.socket?.remoteAddress,userAgent:n.headers["user-agent"]},async()=>{try{let o=await e(t),a=200;return t.node.res.statusCode&&(a=t.node.res.statusCode),o&&o.statusCode&&(a=o.statusCode),s.endTrace(a,{route:I(t,r)}),o}catch(o){s.captureError(o);let a=o.statusCode||o.status||500;throw s.endTrace(a,{route:I(t,r)}),o}})};var L=e=>async(t,n)=>{let r=t.url?new URL(t.url):{pathname:"/"},o=t.method||"GET",a=t.headers.get?t.headers.get("user-agent"):void 0,i=t.headers.get?t.headers.get("x-forwarded-for"):void 0;return s.startTrace({method:o,path:r.pathname,userAgent:a,ip:i},async()=>{try{let u=await e(t,n),c=u?.status||200;return s.endTrace(c,{route:A(r.pathname)}),u}catch(u){throw s.captureError(u),s.endTrace(500,{route:A(r.pathname)}),u}})},W=e=>async(t,n)=>{let r=t.url?t.url.split("?")[0]:"/";return s.startTrace({method:t.method||"GET",path:r,userAgent:t.headers["user-agent"],ip:t.headers["x-forwarded-for"]||t.socket?.remoteAddress},async()=>{let o=()=>{s.endTrace(n.statusCode||200,{route:A(r)})};n.once("finish",o),n.once("close",o);try{return await e(t,n)}catch(a){throw s.captureError(a),a}})};var j=(e,t,n)=>{t&&t.apiKey&&s.init(t),e.addHook("onRequest",(r,o,a)=>{s.startTrace({method:r.method,path:r.raw.url||r.url,ip:r.ip,userAgent:r.headers["user-agent"]},()=>a())}),e.addHook("onError",(r,o,a,i)=>{s.captureError(a),i()}),e.addHook("onResponse",(r,o,a)=>{let i=r.routeOptions?.url||r.routerPath||"UNKNOWN";s.endTrace(o.statusCode,{route:i}),a()}),n()};var Z={init:e=>s.init(e),flush:()=>s.flush(),track:s.track.bind(s),startSpan:s.startSpan.bind(s),captureException:s.captureError.bind(s),requestHandler:D,errorHandler:K,wrapNextRoute:L,wrapNextPages:W,wrapH3:G,fastifyPlugin:j},kt=Z;})();
1
+ "use strict";(()=>{var J=Object.create;var N=Object.defineProperty;var Q=Object.getOwnPropertyDescriptor;var X=Object.getOwnPropertyNames;var Z=Object.getPrototypeOf,V=Object.prototype.hasOwnProperty;var T=(e=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(e,{get:(t,n)=>(typeof require<"u"?require:t)[n]}):e)(function(e){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+e+'" is not supported')});var Y=(e,t,n,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of X(t))!V.call(e,o)&&o!==n&&N(e,o,{get:()=>t[o],enumerable:!(r=Q(t,o))||r.enumerable});return e};var P=(e,t,n)=>(n=e!=null?J(Z(e)):{},Y(t||!e||!e.__esModule?N(n,"default",{value:e,enumerable:!0}):n,e));var E=class{constructor(t){this.config=t;this.queue=[];this.timer=null;typeof setInterval<"u"&&(this.timer=setInterval(()=>this.flush(),t.flushInterval||1e4),this.timer&&typeof this.timer.unref=="function"&&this.timer.unref())}add(t){this.queue.push(t),this.queue.length>=(this.config.batchSize||100)&&this.flush()}async flush(){if(this.queue.length===0)return;let t=[...this.queue];this.queue=[];try{await fetch(this.config.endpoint||"https://api.senzor.dev/api/ingest/apm",{method:"POST",headers:{"Content-Type":"application/json","x-service-api-key":this.config.apiKey},body:JSON.stringify(t),keepalive:!0}),this.config.debug&&console.log(`[Senzor] Flushed ${t.length} traces`)}catch(n){this.config.debug&&console.error("[Senzor] Ingestion Error:",n)}}};var H=T("async_hooks"),z=new H.AsyncLocalStorage,l={run:(e,t)=>z.run(e,t),current:()=>z.getStore(),addSpan:e=>{let t=z.getStore();t&&t.spans.push(e)},setError:e=>{let t=z.getStore();t&&(t.error={name:e.name,message:e.message,stack:e.stack})}};var C=T("crypto");var F=P(T("http")),O=P(T("https")),A=T("url");var v=T("crypto"),I=(e,t,n)=>{if(!e[t])return;let r=e[t];e[t]=n(r)},$=(e,t=!1)=>{if(!globalThis.fetch)return;let n="";try{n=new A.URL(e).hostname}catch{}let r=globalThis.fetch;globalThis.fetch=async(o,a)=>{let i="";if(typeof o=="string"?i=o:o instanceof A.URL?i=o.toString():o&&o.url&&(i=o.url),n&&i.includes(n))return r(o,a);let u=l.current();if(!u)return r(o,a);let s=(a?.method||"GET").toUpperCase(),d=performance.now()-u.startTime,S=performance.now(),g=(0,v.randomUUID)(),y="unknown";try{y=new A.URL(i).hostname}catch{}t&&console.log(`[Senzor] Fetch: ${s} ${y}`);let p={...a};p.headers||(p.headers={}),p.headers instanceof Headers?(p.headers.set("x-senzor-trace-id",u.id),p.headers.set("x-senzor-parent-span-id",g)):Array.isArray(p.headers)?(p.headers.push(["x-senzor-trace-id",u.id]),p.headers.push(["x-senzor-parent-span-id",g])):(p.headers["x-senzor-trace-id"]=u.id,p.headers["x-senzor-parent-span-id"]=g);try{let h=await r(o,p),m=performance.now()-S;return l.addSpan({spanId:g,name:`${s} ${y}`,type:"http",startTime:d,duration:m,status:h.status,meta:{url:i,method:s,library:"fetch"}}),h}catch(h){let m=performance.now()-S;throw l.addSpan({spanId:g,name:`${s} ${y}`,type:"http",startTime:d,duration:m,status:500,meta:{error:h.message,url:i,library:"fetch"}}),h}}},U=(e,t=!1)=>{let n="";try{n=new A.URL(e).hostname}catch{}let r=o=>function(...a){let i={},u="";if(typeof a[0]=="string"||a[0]instanceof A.URL)u=a[0].toString(),typeof a[1]=="object"&&a[1]!==null&&(i=a[1]);else{i=a[0]||{};let f=i.protocol||(i.port===443?"https:":"http:"),x=i.hostname||i.host||"localhost",w=i.path||"/";u=`${f}//${x}${w}`}if(n&&(u.includes(n)||i.hostname&&i.hostname.includes(n)))return o.apply(this,a);let s=l.current();if(!s)return o.apply(this,a);let d=(i.method||"GET").toUpperCase(),S=performance.now()-s.startTime,g=performance.now(),y=(0,v.randomUUID)(),p="unknown";try{p=new A.URL(u).hostname}catch{p=i.hostname||"unknown"}i.headers||(i.headers={}),i.headers["x-senzor-trace-id"]=s.id,i.headers["x-senzor-parent-span-id"]=y;let h=o.apply(this,a),m=(f,x)=>{let w=performance.now()-g;l.addSpan({spanId:y,name:`${d} ${p}`,type:"http",startTime:S,duration:w,status:x?500:f?.statusCode||0,meta:{url:u,method:d,library:"http"}})};return h.on("response",f=>{f.once("end",()=>m(f)),f.once("close",()=>m(f)),f.once("error",x=>m(f,x))}),h.on("error",f=>m(null,f)),h};I(F.default,"request",r),I(F.default,"get",r),I(O.default,"request",r),I(O.default,"get",r)};var M=(e=!1)=>{try{let t=T("mongodb"),n=t.Collection,r=t.FindCursor||T("mongodb/lib/cursor/find_cursor").FindCursor,o=t.AggregationCursor||T("mongodb/lib/cursor/aggregation_cursor").AggregationCursor;e&&console.log("[Senzor] Instrumenting MongoDB (Collection + Cursors)...");let a=(s,d,S,g,y,p)=>{let h=performance.now()-g;l.addSpan({name:`MongoDB ${s}`,type:"db",startTime:performance.now()-y-h,duration:h,status:p?500:0,meta:{collection:S,operation:d,error:p?p.message:void 0}}),e&&console.log(`[Senzor] Captured Mongo: ${s} (${h.toFixed(2)}ms)`)};["insertOne","insertMany","updateOne","updateMany","deleteOne","deleteMany","countDocuments"].forEach(s=>{if(!n.prototype[s])return;let d=n.prototype[s];n.prototype[s]=function(...S){let g=l.current();if(!g)return d.apply(this,S);let y=performance.now(),p=g.startTime,h=this.collectionName;try{let m=d.apply(this,S);return m&&typeof m.then=="function"?m.then(f=>(a(s,s,h,y,p),f),f=>{throw a(s,s,h,y,p,f),f}):m}catch(m){throw a(s,s,h,y,p,m),m}}});let u=(s,d)=>{if(!s||!s.prototype.toArray)return;let S=s.prototype.toArray;s.prototype.toArray=function(...g){let y=l.current();if(!y)return S.apply(this,g);let p=performance.now(),h=y.startTime,m=this.namespace?.collection||"unknown",f=w=>(a(d,d,m,p,h),w),x=w=>{throw a(d,d,m,p,h,w),w};try{let w=S.apply(this,g);return w&&typeof w.then=="function"?w.then(f,x):f(w)}catch(w){x(w)}}};u(r,"find"),u(o,"aggregate")}catch(t){e&&console.warn("[Senzor] MongoDB instrumentation warning:",t.message)}};var D=()=>{try{let e=T("pg"),t=e.Client.prototype.query;e.Client.prototype.query=function(...n){let r=l.current();if(!r)return t.apply(this,n);let o=performance.now()-r.startTime,a=performance.now(),i=typeof n[0]=="string"?n[0]:n[0].text,u=t.apply(this,n);return u&&typeof u.then=="function"?u.then(s=>{let d=performance.now()-a;return l.addSpan({name:"Postgres Query",type:"db",startTime:o,duration:d,meta:{query:i}}),s}):u}}catch{}};var R=class{constructor(){this.transport=null;this.options=null;this.isInstrumented=!1}init(t){if(!t.apiKey){console.warn("[Senzor] API Key missing. SDK disabled.");return}this.options=t;let n=t.endpoint||"https://api.senzor.dev/api/ingest/apm",r=t.debug||!1;if(this.transport=new E({...t,endpoint:n}),!this.isInstrumented){try{U(n,r)}catch{}try{$(n,r)}catch{}try{M(r)}catch{}try{D()}catch{}this.isInstrumented=!0,r&&console.log("[Senzor] Auto-instrumentation enabled")}}startTrace(t,n){if(!this.transport)return n();let r,o;t.headers&&(r=t.headers["x-senzor-trace-id"]||t.headers["X-SENZOR-TRACE-ID"],o=t.headers["x-senzor-parent-span-id"]||t.headers["X-SENZOR-PARENT-SPAN-ID"]);let a={id:(0,C.randomUUID)(),startTime:performance.now(),data:{...t,parentTraceId:r,parentSpanId:o},spans:[]};return l.run(a,n)}endTrace(t,n={}){let r=l.current();if(!r||!this.transport)return;let o=performance.now()-r.startTime,a={traceId:r.id,parentTraceId:r.data.parentTraceId,parentSpanId:r.data.parentSpanId,...r.data,...n,status:t,duration:o,spans:r.spans,timestamp:new Date().toISOString(),error:r.error};this.transport.add(a)}captureError(t){t instanceof Error?l.setError(t):typeof t=="string"&&l.setError(new Error(t))}track(t){this.transport?.add({traceId:(0,C.randomUUID)(),...t,spans:[],timestamp:new Date().toISOString()})}startSpan(t,n="custom"){let r=l.current();if(!r)return{end:()=>{}};let o=performance.now()-r.startTime,a=performance.now(),i=(0,C.randomUUID)();return{end:(u,s)=>{let d=performance.now()-a;l.addSpan({spanId:i,name:t,type:n,startTime:o,duration:d,status:s,meta:u})}}}async flush(){this.transport&&await this.transport.flush()}},c=new R;var K=()=>(e,t,n)=>{c.startTrace({method:e.method,path:e.originalUrl||e.url,ip:e.ip||e.socket?.remoteAddress,userAgent:e.headers["user-agent"],headers:e.headers},()=>{t.once("finish",()=>{try{let r="UNKNOWN";e.route&&e.route.path?r=(e.baseUrl||"")+e.route.path:t.statusCode===404?r="Not Found":r=e.path||"Wildcard",c.endTrace(t.statusCode,{route:r})}catch{}}),n()})},G=()=>(e,t,n,r)=>{c.captureError(e),r(e)};var b=e=>!e||e==="/"?"/":e.replace(/[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}/g,":uuid").replace(/[0-9a-fA-F]{24}/g,":objectId").replace(/\/(\d+)(?=\/|$)/g,"/:id").split("?")[0],k=(e,t)=>e.route&&e.route.path?(e.baseUrl||"")+e.route.path:e.context&&e.context.matchedRoute?e.context.matchedRoute.path:e.routerPath?e.routerPath:b(t);var L=e=>t=>{let n=t.node.req,r=n.originalUrl||n.url||"/";return c.startTrace({method:n.method||"GET",path:r,ip:n.headers["x-forwarded-for"]||n.socket?.remoteAddress,userAgent:n.headers["user-agent"],headers:n.headers},async()=>{try{let o=await e(t),a=200;return t.node.res.statusCode&&(a=t.node.res.statusCode),o&&o.statusCode&&(a=o.statusCode),c.endTrace(a,{route:k(t,r)}),o}catch(o){c.captureError(o);let a=o.statusCode||o.status||500;throw c.endTrace(a,{route:k(t,r)}),o}})};var W=e=>async(t,n)=>{let r=t.url?new URL(t.url):{pathname:"/"},o=t.method||"GET",a={},i,u;return typeof t.headers.get=="function"?(i=t.headers.get("user-agent"),u=t.headers.get("x-forwarded-for"),t.headers.forEach((s,d)=>{a[d]=s})):(a=t.headers,i=a["user-agent"],u=a["x-forwarded-for"]),c.startTrace({method:o,path:r.pathname,userAgent:i,ip:u,headers:a},async()=>{try{let s=await e(t,n),d=s?.status||200;return c.endTrace(d,{route:b(r.pathname)}),s}catch(s){throw c.captureError(s),c.endTrace(500,{route:b(r.pathname)}),s}})},j=e=>async(t,n)=>{let r=t.url?t.url.split("?")[0]:"/";return c.startTrace({method:t.method||"GET",path:r,userAgent:t.headers["user-agent"],ip:t.headers["x-forwarded-for"]||t.socket?.remoteAddress,headers:t.headers},async()=>{let o=()=>{c.endTrace(n.statusCode||200,{route:b(r)})};n.once("finish",o),n.once("close",o);try{return await e(t,n)}catch(a){throw c.captureError(a),a}})};var B=(e,t,n)=>{t&&t.apiKey&&c.init(t),e.addHook("onRequest",(r,o,a)=>{c.startTrace({method:r.method,path:r.raw.url||r.url,ip:r.ip,userAgent:r.headers["user-agent"],headers:r.headers},()=>a())}),e.addHook("onError",(r,o,a,i)=>{c.captureError(a),i()}),e.addHook("onResponse",(r,o,a)=>{let i=r.routeOptions?.url||r.routerPath||"UNKNOWN";c.endTrace(o.statusCode,{route:i}),a()}),n()};var _={init:e=>c.init(e),flush:()=>c.flush(),track:c.track.bind(c),startSpan:c.startSpan.bind(c),captureException:c.captureError.bind(c),requestHandler:K,errorHandler:G,wrapNextRoute:W,wrapNextPages:j,wrapH3:L,fastifyPlugin:B},vt=_;})();
2
2
  //# sourceMappingURL=index.global.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/core/transport.ts","../src/core/context.ts","../src/core/client.ts","../src/instrumentation/http.ts","../src/instrumentation/mongo.ts","../src/instrumentation/pg.ts","../src/middleware/express.ts","../src/core/normalizer.ts","../src/wrappers/h3.ts","../src/wrappers/next.ts","../src/wrappers/fastify.ts","../src/index.ts"],"sourcesContent":["import { SenzorOptions } from './types';\r\n\r\nexport class Transport {\r\n private queue: any[] = [];\r\n private timer: NodeJS.Timeout | null = null;\r\n\r\n constructor(private config: SenzorOptions) {\r\n if (typeof setInterval !== 'undefined') {\r\n this.timer = setInterval(() => this.flush(), config.flushInterval || 10000);\r\n if (this.timer && typeof this.timer.unref === 'function') {\r\n this.timer.unref(); // Don't block process exit\r\n }\r\n }\r\n }\r\n\r\n public add(trace: any) {\r\n this.queue.push(trace);\r\n if (this.queue.length >= (this.config.batchSize || 100)) {\r\n this.flush();\r\n }\r\n }\r\n\r\n public async flush() {\r\n if (this.queue.length === 0) return;\r\n\r\n const batch = [...this.queue];\r\n this.queue = [];\r\n\r\n try {\r\n // Use global fetch (Node 18+)\r\n await fetch(this.config.endpoint || 'https://api.senzor.dev/api/ingest/apm', {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n 'x-service-api-key': this.config.apiKey,\r\n },\r\n body: JSON.stringify(batch),\r\n keepalive: true,\r\n });\r\n \r\n if (this.config.debug) console.log(`[Senzor] Flushed ${batch.length} traces`);\r\n } catch (err) {\r\n if (this.config.debug) console.error('[Senzor] Ingestion Error:', err);\r\n // Dropping data to prevent memory leaks is preferred in APM\r\n }\r\n }\r\n}","import { AsyncLocalStorage } from 'async_hooks';\r\nimport { ActiveTrace, TraceError } from './types';\r\n\r\nexport const storage = new AsyncLocalStorage<ActiveTrace>();\r\n\r\nexport const Context = {\r\n run: <T>(trace: ActiveTrace, fn: () => T): T => {\r\n return storage.run(trace, fn);\r\n },\r\n\r\n current: (): ActiveTrace | undefined => {\r\n return storage.getStore();\r\n },\r\n\r\n addSpan: (span: any) => {\r\n const store = storage.getStore();\r\n if (store) {\r\n store.spans.push(span);\r\n }\r\n },\r\n\r\n // Attach error to current trace\r\n setError: (error: Error) => {\r\n const store = storage.getStore();\r\n if (store) {\r\n store.error = {\r\n name: error.name,\r\n message: error.message,\r\n stack: error.stack\r\n };\r\n }\r\n }\r\n};","import { Transport } from './transport';\r\nimport { Context } from './context';\r\nimport { SenzorOptions, ActiveTrace } from './types';\r\nimport { randomUUID } from 'crypto';\r\nimport { instrumentHttp, instrumentFetch } from '../instrumentation/http';\r\nimport { instrumentMongo } from '../instrumentation/mongo';\r\nimport { instrumentPg } from '../instrumentation/pg';\r\n\r\nexport class SenzorClient {\r\n private transport: Transport | null = null;\r\n private options: SenzorOptions | null = null;\r\n private isInstrumented = false;\r\n\r\n public init(options: SenzorOptions) {\r\n if (!options.apiKey) {\r\n console.warn('[Senzor] API Key missing. SDK disabled.');\r\n return;\r\n }\r\n this.options = options;\r\n const endpoint = options.endpoint || 'https://api.senzor.dev/api/ingest/apm';\r\n const debug = options.debug || false;\r\n\r\n this.transport = new Transport({ ...options, endpoint });\r\n\r\n if (!this.isInstrumented) {\r\n try { instrumentHttp(endpoint, debug); } catch (e) { }\r\n try { instrumentFetch(endpoint, debug); } catch (e) { }\r\n try { instrumentMongo(debug); } catch (e) { }\r\n try { instrumentPg(); } catch (e) { }\r\n\r\n this.isInstrumented = true;\r\n if (debug) console.log('[Senzor] Auto-instrumentation enabled');\r\n }\r\n }\r\n\r\n public startTrace<T>(data: Partial<ActiveTrace['data']>, next: () => T): T {\r\n if (!this.transport) return next();\r\n const trace: ActiveTrace = {\r\n id: randomUUID(),\r\n startTime: performance.now(),\r\n data: data,\r\n spans: []\r\n };\r\n return Context.run(trace, next);\r\n }\r\n\r\n public endTrace(status: number, extraData: any = {}) {\r\n const trace = Context.current();\r\n if (!trace || !this.transport) return;\r\n\r\n const duration = performance.now() - trace.startTime;\r\n\r\n const payload = {\r\n traceId: trace.id,\r\n ...trace.data,\r\n ...extraData,\r\n status,\r\n duration,\r\n spans: trace.spans,\r\n error: trace.error, // Include Error if captured\r\n timestamp: new Date().toISOString()\r\n };\r\n\r\n this.transport.add(payload);\r\n }\r\n\r\n // --- NEW: Capture Exception ---\r\n public captureError(error: unknown) {\r\n if (error instanceof Error) {\r\n Context.setError(error);\r\n } else if (typeof error === 'string') {\r\n Context.setError(new Error(error));\r\n }\r\n }\r\n\r\n // ... (manual track, startSpan, flush remain same) ...\r\n public track(data: any) { this.transport?.add({ traceId: randomUUID(), ...data, spans: [], timestamp: new Date().toISOString() }); }\r\n\r\n public startSpan(name: string, type: 'db' | 'http' | 'function' | 'custom' = 'custom') {\r\n const trace = Context.current();\r\n if (!trace) return { end: () => { } };\r\n const startTime = performance.now() - trace.startTime;\r\n const spanStartAbs = performance.now();\r\n return { end: (meta?: any, status?: number) => { Context.addSpan({ name, type, startTime, duration: performance.now() - spanStartAbs, status, meta }); } };\r\n }\r\n\r\n public async flush() { if (this.transport) await this.transport.flush(); }\r\n}\r\n\r\nexport const client = new SenzorClient();","import http from 'http';\r\nimport https from 'https';\r\nimport { URL } from 'url';\r\nimport { Context } from '../core/context';\r\n\r\nconst shimmer = (module: any, methodName: string, wrapper: (original: Function) => Function) => {\r\n if (!module[methodName]) return;\r\n const original = module[methodName];\r\n module[methodName] = wrapper(original);\r\n};\r\n\r\n// --- Native Fetch Instrumentation (Node 18+) ---\r\nexport const instrumentFetch = (ingestUrl: string, debug = false) => {\r\n if (!globalThis.fetch) return;\r\n\r\n let ingestHost = '';\r\n try { ingestHost = new URL(ingestUrl).hostname; } catch (e) { }\r\n\r\n const originalFetch = globalThis.fetch;\r\n\r\n // @ts-ignore\r\n globalThis.fetch = async (input: RequestInfo | URL, init?: RequestInit) => {\r\n // 1. Extract URL\r\n let urlStr = '';\r\n if (typeof input === 'string') urlStr = input;\r\n else if (input instanceof URL) urlStr = input.toString();\r\n else if (input && input.url) urlStr = input.url; // Request object\r\n\r\n // 2. Infinite Loop Guard\r\n if (ingestHost && urlStr.includes(ingestHost)) {\r\n return originalFetch(input, init);\r\n }\r\n\r\n // 3. Context Check\r\n const trace = Context.current();\r\n if (!trace) {\r\n return originalFetch(input, init);\r\n }\r\n\r\n // 4. Start Span\r\n const method = (init?.method || 'GET').toUpperCase();\r\n const startTime = performance.now() - trace.startTime;\r\n const spanStartAbs = performance.now();\r\n let hostname = 'unknown';\r\n try { hostname = new URL(urlStr).hostname; } catch (e) { }\r\n\r\n if (debug) console.log(`[Senzor] Tracking Fetch: ${method} ${hostname}`);\r\n\r\n try {\r\n const response = await originalFetch(input, init);\r\n\r\n // 5. End Span\r\n const duration = performance.now() - spanStartAbs;\r\n Context.addSpan({\r\n name: `${method} ${hostname}`,\r\n type: 'http',\r\n startTime,\r\n duration,\r\n status: response.status,\r\n meta: { url: urlStr, method, library: 'fetch' }\r\n });\r\n\r\n return response;\r\n } catch (err: any) {\r\n const duration = performance.now() - spanStartAbs;\r\n Context.addSpan({\r\n name: `${method} ${hostname}`,\r\n type: 'http',\r\n startTime,\r\n duration,\r\n status: 500,\r\n meta: { error: err.message, url: urlStr, library: 'fetch' }\r\n });\r\n throw err;\r\n }\r\n };\r\n};\r\n\r\n// --- Standard HTTP/HTTPS Instrumentation ---\r\nexport const instrumentHttp = (ingestUrl: string, debug = false) => {\r\n let ingestHost = '';\r\n try {\r\n ingestHost = new URL(ingestUrl).hostname;\r\n } catch (e) { }\r\n\r\n const requestWrapper = (original: Function) => {\r\n return function (this: any, ...args: any[]) {\r\n let options: any = {};\r\n let urlStr = '';\r\n\r\n if (typeof args[0] === 'string' || args[0] instanceof URL) {\r\n urlStr = args[0].toString();\r\n if (typeof args[1] === 'object' && args[1] !== null) options = args[1];\r\n } else {\r\n options = args[0] || {};\r\n const protocol = options.protocol || (options.port === 443 ? 'https:' : 'http:');\r\n const host = options.hostname || options.host || 'localhost';\r\n const path = options.path || '/';\r\n urlStr = `${protocol}//${host}${path}`;\r\n }\r\n\r\n if (ingestHost && (urlStr.includes(ingestHost) || (options.hostname && options.hostname.includes(ingestHost)))) {\r\n return original.apply(this, args);\r\n }\r\n\r\n const trace = Context.current();\r\n if (!trace) return original.apply(this, args);\r\n\r\n const method = (options.method || 'GET').toUpperCase();\r\n const startTime = performance.now() - trace.startTime;\r\n const spanStartAbs = performance.now();\r\n let hostname = 'unknown';\r\n try { hostname = new URL(urlStr).hostname; } catch (e) { hostname = options.hostname || 'unknown'; }\r\n\r\n const req = original.apply(this, args);\r\n\r\n const captureSpan = (res: any, error?: Error) => {\r\n const duration = performance.now() - spanStartAbs;\r\n Context.addSpan({\r\n name: `${method} ${hostname}`,\r\n type: 'http',\r\n startTime,\r\n duration,\r\n status: error ? 500 : res?.statusCode || 0,\r\n meta: { url: urlStr, method, library: 'http', error: error ? error.message : undefined }\r\n });\r\n };\r\n\r\n req.on('response', (res: any) => {\r\n res.once('end', () => captureSpan(res));\r\n res.once('error', (err: Error) => captureSpan(res, err));\r\n });\r\n\r\n req.on('error', (err: Error) => captureSpan(null, err));\r\n\r\n return req;\r\n };\r\n };\r\n\r\n shimmer(http, 'request', requestWrapper);\r\n shimmer(http, 'get', requestWrapper);\r\n shimmer(https, 'request', requestWrapper);\r\n shimmer(https, 'get', requestWrapper);\r\n};","import { Context } from '../core/context';\r\n\r\nexport const instrumentMongo = (debug = false) => {\r\n try {\r\n const mongodb = require('mongodb');\r\n const Collection = mongodb.Collection;\r\n\r\n // Attempt to get Cursor classes\r\n // Note: The location of these classes varies by driver version, \r\n // checking common locations\r\n const FindCursor = mongodb.FindCursor || require('mongodb/lib/cursor/find_cursor').FindCursor;\r\n const AggregationCursor = mongodb.AggregationCursor || require('mongodb/lib/cursor/aggregation_cursor').AggregationCursor;\r\n\r\n if (debug) console.log('[Senzor] Instrumenting MongoDB (Collection + Cursors)...');\r\n\r\n // --- Helper to Record Span ---\r\n const recordSpan = (name: string, operation: string, collection: string, startAbs: number, traceStart: number, err?: Error) => {\r\n const duration = performance.now() - startAbs;\r\n Context.addSpan({\r\n name: `MongoDB ${name}`,\r\n type: 'db',\r\n startTime: performance.now() - traceStart - duration, // Adjust start time to when op actually started\r\n duration,\r\n status: err ? 500 : 0,\r\n meta: { collection, operation, error: err ? err.message : undefined }\r\n });\r\n if (debug) console.log(`[Senzor] Captured Mongo: ${name} (${duration.toFixed(2)}ms)`);\r\n };\r\n\r\n // --- 1. Instrument Immediate Operations (Insert/Update/Delete) ---\r\n const immediateMethods = ['insertOne', 'insertMany', 'updateOne', 'updateMany', 'deleteOne', 'deleteMany', 'countDocuments'];\r\n\r\n immediateMethods.forEach((method) => {\r\n if (!Collection.prototype[method]) return;\r\n const original = Collection.prototype[method];\r\n\r\n Collection.prototype[method] = function (...args: any[]) {\r\n const trace = Context.current();\r\n if (!trace) return original.apply(this, args);\r\n\r\n const spanStartAbs = performance.now();\r\n const traceStart = trace.startTime;\r\n const collName = this.collectionName;\r\n\r\n try {\r\n const result = original.apply(this, args);\r\n if (result && typeof result.then === 'function') {\r\n return result.then(\r\n (res: any) => { recordSpan(method, method, collName, spanStartAbs, traceStart); return res; },\r\n (err: any) => { recordSpan(method, method, collName, spanStartAbs, traceStart, err); throw err; }\r\n );\r\n }\r\n return result;\r\n } catch (err: any) {\r\n recordSpan(method, method, collName, spanStartAbs, traceStart, err);\r\n throw err;\r\n }\r\n };\r\n });\r\n\r\n // --- 2. Instrument Cursor Execution (find -> toArray) ---\r\n const patchCursor = (CursorClass: any, label: string) => {\r\n if (!CursorClass || !CursorClass.prototype.toArray) return;\r\n\r\n const originalToArray = CursorClass.prototype.toArray;\r\n\r\n CursorClass.prototype.toArray = function (...args: any[]) {\r\n const trace = Context.current();\r\n // Cursors are often created in context but executed later. \r\n // We check context at execution time.\r\n if (!trace) return originalToArray.apply(this, args);\r\n\r\n const spanStartAbs = performance.now();\r\n const traceStart = trace.startTime;\r\n // Attempt to get collection name from cursor internal state\r\n const collName = this.namespace?.collection || 'unknown';\r\n\r\n const onSuccess = (res: any) => {\r\n recordSpan(label, label, collName, spanStartAbs, traceStart);\r\n return res;\r\n };\r\n const onError = (err: any) => {\r\n recordSpan(label, label, collName, spanStartAbs, traceStart, err);\r\n throw err;\r\n };\r\n\r\n try {\r\n const result = originalToArray.apply(this, args);\r\n if (result && typeof result.then === 'function') {\r\n return result.then(onSuccess, onError);\r\n }\r\n return onSuccess(result);\r\n } catch (e) {\r\n onError(e);\r\n }\r\n };\r\n };\r\n\r\n patchCursor(FindCursor, 'find');\r\n patchCursor(AggregationCursor, 'aggregate');\r\n\r\n } catch (e: any) {\r\n if (debug) console.warn('[Senzor] MongoDB instrumentation warning:', e.message);\r\n }\r\n};","import { Context } from '../core/context';\r\n\r\n// Simple shim for 'pg' library\r\nexport const instrumentPg = () => {\r\n try {\r\n // Try to require pg (it might not be installed by user)\r\n const pg = require('pg');\r\n const originalQuery = pg.Client.prototype.query;\r\n\r\n pg.Client.prototype.query = function (...args: any[]) {\r\n const trace = Context.current();\r\n if (!trace) return originalQuery.apply(this, args);\r\n\r\n const startTime = performance.now() - trace.startTime;\r\n const spanStartAbs = performance.now();\r\n\r\n // Extract SQL (first arg usually string or config object)\r\n const sql = typeof args[0] === 'string' ? args[0] : args[0].text;\r\n\r\n // Wrap callback if present, or handle Promise\r\n const result = originalQuery.apply(this, args);\r\n\r\n if (result && typeof result.then === 'function') {\r\n return result.then((res: any) => {\r\n const duration = performance.now() - spanStartAbs;\r\n Context.addSpan({\r\n name: 'Postgres Query',\r\n type: 'db',\r\n startTime,\r\n duration,\r\n meta: { query: sql }\r\n });\r\n return res;\r\n });\r\n }\r\n return result;\r\n };\r\n } catch (e) {\r\n // User doesn't use pg, ignore\r\n }\r\n};","import { client } from '../core/client';\r\n\r\n// 1. Request Handler (Place before routes)\r\nexport const expressMiddleware = () => {\r\n return (req: any, res: any, next: () => void) => {\r\n client.startTrace({\r\n method: req.method,\r\n path: req.originalUrl || req.url,\r\n ip: req.ip || req.socket?.remoteAddress,\r\n userAgent: req.headers['user-agent'],\r\n }, () => {\r\n\r\n // Auto-detect status code on finish\r\n res.once('finish', () => {\r\n try {\r\n let route = 'UNKNOWN';\r\n // Express populates req.route only if a route matched\r\n if (req.route && req.route.path) {\r\n route = (req.baseUrl || '') + req.route.path;\r\n } else if (res.statusCode === 404) {\r\n route = 'Not Found';\r\n } else {\r\n route = req.path || 'Wildcard';\r\n }\r\n\r\n client.endTrace(res.statusCode, { route });\r\n } catch (e) { /* Fail open */ }\r\n });\r\n\r\n next();\r\n });\r\n };\r\n};\r\n\r\n// 2. Error Handler (Place after routes)\r\n// This is required in Express to capture the actual Error Object (Stack Trace)\r\nexport const expressErrorHandler = () => {\r\n return (err: any, req: any, res: any, next: (err?: any) => void) => {\r\n\r\n // 1. Capture the exception context\r\n client.captureError(err);\r\n\r\n // 2. Pass it to the next error handler (don't swallow it)\r\n next(err);\r\n };\r\n};","/**\r\n * Heuristic URL Normalizer\r\n * Converts raw paths with IDs into generic patterns to prevent high cardinality.\r\n * Example: /users/123/orders/abc-def -> /users/:id/orders/:uuid\r\n */\r\nexport const normalizePath = (path: string): string => {\r\n if (!path || path === '/') return '/';\r\n\r\n return path\r\n // Replace UUIDs (long alphanumeric strings)\r\n .replace(\r\n /[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}/g,\r\n ':uuid'\r\n )\r\n // Replace MongoDB ObjectIds (24 hex chars)\r\n .replace(/[0-9a-fA-F]{24}/g, ':objectId')\r\n // Replace pure numeric IDs (e.g., /123)\r\n .replace(/\\/(\\d+)(?=\\/|$)/g, '/:id')\r\n // Remove query strings\r\n .split('?')[0];\r\n};\r\n\r\n/**\r\n * Tries to extract route from Framework internals, falls back to heuristic\r\n */\r\nexport const getRoute = (req: any, fallbackPath: string): string => {\r\n // Express / Connect\r\n if (req.route && req.route.path) {\r\n return (req.baseUrl || '') + req.route.path;\r\n }\r\n\r\n // H3 / Nitro (Nuxt)\r\n if (req.context && req.context.matchedRoute) {\r\n return req.context.matchedRoute.path;\r\n }\r\n\r\n // Fastify\r\n if (req.routerPath) {\r\n return req.routerPath;\r\n }\r\n\r\n // Fallback: Heuristic Normalization\r\n return normalizePath(fallbackPath);\r\n};","import { client } from '../core/client';\r\nimport { getRoute } from '../core/normalizer';\r\n\r\ntype EventHandler = (event: any) => any;\r\n\r\nexport const wrapH3 = (handler: EventHandler) => {\r\n return (event: any) => {\r\n const req = event.node.req;\r\n const path = req.originalUrl || req.url || '/';\r\n\r\n return client.startTrace({\r\n method: req.method || 'GET',\r\n path: path,\r\n ip: req.headers['x-forwarded-for'] || req.socket?.remoteAddress,\r\n userAgent: req.headers['user-agent'],\r\n }, async () => {\r\n try {\r\n const response = await handler(event);\r\n let status = 200;\r\n if (event.node.res.statusCode) status = event.node.res.statusCode;\r\n if (response && response.statusCode) status = response.statusCode;\r\n\r\n client.endTrace(status, { route: getRoute(event, path) });\r\n return response;\r\n } catch (err: any) {\r\n // AUTOMATIC ERROR CAPTURE\r\n client.captureError(err);\r\n\r\n const status = err.statusCode || err.status || 500;\r\n client.endTrace(status, { route: getRoute(event, path) });\r\n throw err;\r\n }\r\n });\r\n };\r\n};","import { client } from '../core/client';\r\nimport { normalizePath } from '../core/normalizer';\r\n\r\n// --- App Router Wrapper ---\r\nexport const wrapNextRoute = (handler: Function) => {\r\n return async (req: Request | any, context?: any) => {\r\n const url = req.url ? new URL(req.url) : { pathname: '/' };\r\n const method = req.method || 'GET';\r\n const ua = req.headers.get ? req.headers.get('user-agent') : undefined;\r\n const ip = req.headers.get ? req.headers.get('x-forwarded-for') : undefined;\r\n\r\n return client.startTrace({\r\n method,\r\n path: url.pathname,\r\n userAgent: ua,\r\n ip: ip\r\n }, async () => {\r\n try {\r\n const response = await handler(req, context);\r\n const status = response?.status || 200;\r\n client.endTrace(status, { route: normalizePath(url.pathname) });\r\n return response;\r\n } catch (err: any) {\r\n // AUTOMATIC ERROR CAPTURE\r\n client.captureError(err);\r\n client.endTrace(500, { route: normalizePath(url.pathname) });\r\n throw err; // Re-throw so Next.js handles the error page\r\n }\r\n });\r\n };\r\n};\r\n\r\n// --- Pages Router Wrapper ---\r\nexport const wrapNextPages = (handler: Function) => {\r\n return async (req: any, res: any) => {\r\n const path = req.url ? req.url.split('?')[0] : '/';\r\n\r\n return client.startTrace({\r\n method: req.method || 'GET',\r\n path: path,\r\n userAgent: req.headers['user-agent'],\r\n ip: req.headers['x-forwarded-for'] || req.socket?.remoteAddress,\r\n }, async () => {\r\n\r\n const done = () => {\r\n client.endTrace(res.statusCode || 200, { route: normalizePath(path) });\r\n };\r\n\r\n res.once('finish', done);\r\n res.once('close', done);\r\n\r\n try {\r\n return await handler(req, res);\r\n } catch (e: any) {\r\n // AUTOMATIC ERROR CAPTURE\r\n client.captureError(e);\r\n // Note: In Pages dir, we rely on 'finish' listener above to close trace, \r\n // but capturing here ensures the error data is attached.\r\n throw e;\r\n }\r\n });\r\n };\r\n};","import { client } from '../core/client';\r\nimport { SenzorOptions } from '../core/types';\r\n\r\nexport const senzorPlugin = (fastify: any, options: SenzorOptions, done: Function) => {\r\n\r\n if (options && options.apiKey) {\r\n client.init(options);\r\n }\r\n\r\n // 1. Start Trace\r\n fastify.addHook('onRequest', (request: any, reply: any, next: Function) => {\r\n // FIX: Wrap next in a closure to satisfy TS types\r\n client.startTrace({\r\n method: request.method,\r\n path: request.raw.url || request.url,\r\n ip: request.ip,\r\n userAgent: request.headers['user-agent']\r\n }, () => next());\r\n });\r\n\r\n // 2. Capture Errors\r\n fastify.addHook('onError', (request: any, reply: any, error: any, next: Function) => {\r\n client.captureError(error);\r\n next();\r\n });\r\n\r\n // 3. End Trace\r\n fastify.addHook('onResponse', (request: any, reply: any, next: Function) => {\r\n const route = request.routeOptions?.url || request.routerPath || 'UNKNOWN';\r\n client.endTrace(reply.statusCode, { route });\r\n next();\r\n });\r\n\r\n done();\r\n};","import { client } from './core/client';\r\nimport { expressMiddleware, expressErrorHandler } from './middleware/express';\r\nimport { wrapH3 } from './wrappers/h3';\r\nimport { wrapNextRoute, wrapNextPages } from './wrappers/next';\r\nimport { senzorPlugin } from './wrappers/fastify';\r\nimport { SenzorOptions } from './core/types';\r\n\r\nconst Senzor = {\r\n init: (options: SenzorOptions) => client.init(options),\r\n flush: () => client.flush(),\r\n track: client.track.bind(client),\r\n startSpan: client.startSpan.bind(client),\r\n captureException: client.captureError.bind(client),\r\n\r\n // Express\r\n requestHandler: expressMiddleware,\r\n errorHandler: expressErrorHandler,\r\n\r\n // Next\r\n wrapNextRoute,\r\n wrapNextPages,\r\n\r\n // H3\r\n wrapH3,\r\n\r\n // Fastify\r\n fastifyPlugin: senzorPlugin\r\n};\r\n\r\nexport default Senzor;\r\nexport { Senzor };"],"mappings":"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","names":["Transport","config","trace","batch","err","import_async_hooks","storage","Context","trace","fn","span","store","error","import_crypto","import_http","import_https","import_url","shimmer","module","methodName","wrapper","original","instrumentFetch","ingestUrl","debug","ingestHost","originalFetch","input","init","urlStr","trace","Context","method","startTime","spanStartAbs","hostname","response","duration","err","instrumentHttp","requestWrapper","args","options","protocol","host","path","req","captureSpan","res","error","http","https","instrumentMongo","debug","mongodb","Collection","FindCursor","AggregationCursor","recordSpan","name","operation","collection","startAbs","traceStart","err","duration","Context","method","original","args","trace","spanStartAbs","collName","result","res","patchCursor","CursorClass","label","originalToArray","onSuccess","onError","e","instrumentPg","pg","originalQuery","args","trace","Context","startTime","spanStartAbs","sql","result","res","duration","SenzorClient","options","endpoint","debug","Transport","instrumentHttp","instrumentFetch","instrumentMongo","instrumentPg","data","next","trace","Context","status","extraData","duration","payload","error","name","type","startTime","spanStartAbs","meta","client","expressMiddleware","req","res","next","client","route","expressErrorHandler","err","normalizePath","path","getRoute","req","fallbackPath","wrapH3","handler","event","req","path","client","response","status","getRoute","err","wrapNextRoute","handler","req","context","url","method","ua","ip","client","response","status","normalizePath","err","wrapNextPages","res","path","done","e","senzorPlugin","fastify","options","done","client","request","reply","next","error","route","Senzor","options","client","expressMiddleware","expressErrorHandler","wrapNextRoute","wrapNextPages","wrapH3","senzorPlugin","index_default"]}
1
+ {"version":3,"sources":["../src/core/transport.ts","../src/core/context.ts","../src/core/client.ts","../src/instrumentation/http.ts","../src/instrumentation/mongo.ts","../src/instrumentation/pg.ts","../src/middleware/express.ts","../src/core/normalizer.ts","../src/wrappers/h3.ts","../src/wrappers/next.ts","../src/wrappers/fastify.ts","../src/index.ts"],"sourcesContent":["import { SenzorOptions } from './types';\r\n\r\nexport class Transport {\r\n private queue: any[] = [];\r\n private timer: NodeJS.Timeout | null = null;\r\n\r\n constructor(private config: SenzorOptions) {\r\n if (typeof setInterval !== 'undefined') {\r\n this.timer = setInterval(() => this.flush(), config.flushInterval || 10000);\r\n if (this.timer && typeof this.timer.unref === 'function') {\r\n this.timer.unref(); // Don't block process exit\r\n }\r\n }\r\n }\r\n\r\n public add(trace: any) {\r\n this.queue.push(trace);\r\n if (this.queue.length >= (this.config.batchSize || 100)) {\r\n this.flush();\r\n }\r\n }\r\n\r\n public async flush() {\r\n if (this.queue.length === 0) return;\r\n\r\n const batch = [...this.queue];\r\n this.queue = [];\r\n\r\n try {\r\n // Use global fetch (Node 18+)\r\n await fetch(this.config.endpoint || 'https://api.senzor.dev/api/ingest/apm', {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n 'x-service-api-key': this.config.apiKey,\r\n },\r\n body: JSON.stringify(batch),\r\n keepalive: true,\r\n });\r\n \r\n if (this.config.debug) console.log(`[Senzor] Flushed ${batch.length} traces`);\r\n } catch (err) {\r\n if (this.config.debug) console.error('[Senzor] Ingestion Error:', err);\r\n // Dropping data to prevent memory leaks is preferred in APM\r\n }\r\n }\r\n}","import { AsyncLocalStorage } from 'async_hooks';\r\nimport { ActiveTrace, TraceError } from './types';\r\n\r\nexport const storage = new AsyncLocalStorage<ActiveTrace>();\r\n\r\nexport const Context = {\r\n run: <T>(trace: ActiveTrace, fn: () => T): T => {\r\n return storage.run(trace, fn);\r\n },\r\n\r\n current: (): ActiveTrace | undefined => {\r\n return storage.getStore();\r\n },\r\n\r\n addSpan: (span: any) => {\r\n const store = storage.getStore();\r\n if (store) {\r\n store.spans.push(span);\r\n }\r\n },\r\n\r\n // Attach error to current trace\r\n setError: (error: Error) => {\r\n const store = storage.getStore();\r\n if (store) {\r\n store.error = {\r\n name: error.name,\r\n message: error.message,\r\n stack: error.stack\r\n };\r\n }\r\n }\r\n};","import { Transport } from './transport';\r\nimport { Context } from './context';\r\nimport { SenzorOptions, ActiveTrace } from './types';\r\nimport { randomUUID } from 'crypto';\r\nimport { instrumentHttp, instrumentFetch } from '../instrumentation/http';\r\nimport { instrumentMongo } from '../instrumentation/mongo';\r\nimport { instrumentPg } from '../instrumentation/pg';\r\n\r\nexport class SenzorClient {\r\n private transport: Transport | null = null;\r\n private options: SenzorOptions | null = null;\r\n private isInstrumented = false;\r\n\r\n public init(options: SenzorOptions) {\r\n if (!options.apiKey) {\r\n console.warn('[Senzor] API Key missing. SDK disabled.');\r\n return;\r\n }\r\n this.options = options;\r\n const endpoint = options.endpoint || 'https://api.senzor.dev/api/ingest/apm';\r\n const debug = options.debug || false;\r\n\r\n this.transport = new Transport({ ...options, endpoint });\r\n\r\n if (!this.isInstrumented) {\r\n try { instrumentHttp(endpoint, debug); } catch (e) { }\r\n try { instrumentFetch(endpoint, debug); } catch (e) { }\r\n try { instrumentMongo(debug); } catch (e) { }\r\n try { instrumentPg(); } catch (e) { }\r\n\r\n this.isInstrumented = true;\r\n if (debug) console.log('[Senzor] Auto-instrumentation enabled');\r\n }\r\n }\r\n\r\n public startTrace<T>(data: Partial<ActiveTrace['data']> & { headers?: any }, next: () => T): T {\r\n if (!this.transport) return next();\r\n\r\n // Check for Distributed Tracing Headers\r\n let parentTraceId = undefined;\r\n let parentSpanId = undefined;\r\n\r\n if (data.headers) {\r\n // Handle various casing\r\n parentTraceId = data.headers['x-senzor-trace-id'] || data.headers['X-SENZOR-TRACE-ID'];\r\n parentSpanId = data.headers['x-senzor-parent-span-id'] || data.headers['X-SENZOR-PARENT-SPAN-ID'];\r\n }\r\n\r\n const trace: ActiveTrace = {\r\n id: randomUUID(),\r\n startTime: performance.now(),\r\n data: {\r\n ...data,\r\n parentTraceId, // Link to parent\r\n parentSpanId // Link to specific call\r\n },\r\n spans: []\r\n };\r\n\r\n return Context.run(trace, next);\r\n }\r\n\r\n public endTrace(status: number, extraData: any = {}) {\r\n const trace = Context.current();\r\n if (!trace || !this.transport) return;\r\n const duration = performance.now() - trace.startTime;\r\n\r\n // Explicitly destructure to ensure parent IDs are included\r\n const payload = {\r\n traceId: trace.id,\r\n parentTraceId: trace.data.parentTraceId,\r\n parentSpanId: trace.data.parentSpanId,\r\n ...trace.data,\r\n ...extraData,\r\n status, duration, spans: trace.spans, timestamp: new Date().toISOString(),\r\n error: trace.error,\r\n\r\n };\r\n this.transport.add(payload);\r\n }\r\n\r\n // --- NEW: Capture Exception ---\r\n public captureError(error: unknown) {\r\n if (error instanceof Error) {\r\n Context.setError(error);\r\n } else if (typeof error === 'string') {\r\n Context.setError(new Error(error));\r\n }\r\n }\r\n\r\n // ... (manual track, startSpan, flush remain same) ...\r\n public track(data: any) { this.transport?.add({ traceId: randomUUID(), ...data, spans: [], timestamp: new Date().toISOString() }); }\r\n\r\n public startSpan(name: string, type: 'db' | 'http' | 'function' | 'custom' = 'custom') {\r\n const trace = Context.current();\r\n if (!trace) return { end: () => { } };\r\n const startTime = performance.now() - trace.startTime;\r\n const spanStartAbs = performance.now();\r\n const spanId = randomUUID(); // Manual spans also need IDs\r\n\r\n return {\r\n end: (meta?: any, status?: number) => {\r\n const duration = performance.now() - spanStartAbs;\r\n Context.addSpan({ spanId, name, type, startTime, duration, status, meta });\r\n }\r\n };\r\n }\r\n\r\n public async flush() { if (this.transport) await this.transport.flush(); }\r\n}\r\n\r\nexport const client = new SenzorClient();","import http from 'http';\r\nimport https from 'https';\r\nimport { URL } from 'url';\r\nimport { Context } from '../core/context';\r\nimport { randomUUID } from 'crypto';\r\n\r\nconst shimmer = (module: any, methodName: string, wrapper: (original: Function) => Function) => {\r\n if (!module[methodName]) return;\r\n const original = module[methodName];\r\n module[methodName] = wrapper(original);\r\n};\r\n\r\n// --- FETCH INSTRUMENTATION (Node 18+ / Edge) ---\r\nexport const instrumentFetch = (ingestUrl: string, debug = false) => {\r\n if (!globalThis.fetch) return;\r\n\r\n let ingestHost = '';\r\n try { ingestHost = new URL(ingestUrl).hostname; } catch (e) { }\r\n\r\n const originalFetch = globalThis.fetch;\r\n\r\n // @ts-ignore\r\n globalThis.fetch = async (input: RequestInfo | URL, init?: RequestInit) => {\r\n // 1. Extract URL\r\n let urlStr = '';\r\n if (typeof input === 'string') urlStr = input;\r\n else if (input instanceof URL) urlStr = input.toString();\r\n else if (input && (input as any).url) urlStr = (input as any).url;\r\n\r\n // 2. Infinite Loop Guard\r\n if (ingestHost && urlStr.includes(ingestHost)) {\r\n return originalFetch(input, init);\r\n }\r\n\r\n // 3. Context Check\r\n const trace = Context.current();\r\n if (!trace) {\r\n return originalFetch(input, init);\r\n }\r\n\r\n // 4. Prepare Metadata & ID\r\n const method = (init?.method || 'GET').toUpperCase();\r\n const startTime = performance.now() - trace.startTime;\r\n const spanStartAbs = performance.now();\r\n const spanId = randomUUID(); // New ID for this specific outbound call\r\n\r\n let hostname = 'unknown';\r\n try { hostname = new URL(urlStr).hostname; } catch (e) { }\r\n\r\n if (debug) console.log(`[Senzor] Fetch: ${method} ${hostname}`);\r\n\r\n // 5. Inject Distributed Tracing Headers\r\n // We need to clone init or create it to avoid mutating original ref unexpectedly\r\n const newInit = { ...init };\r\n if (!newInit.headers) {\r\n newInit.headers = {};\r\n }\r\n\r\n // Handle different Header formats (Headers object vs plain object)\r\n if (newInit.headers instanceof Headers) {\r\n newInit.headers.set('x-senzor-trace-id', trace.id);\r\n newInit.headers.set('x-senzor-parent-span-id', spanId);\r\n } else if (Array.isArray(newInit.headers)) {\r\n newInit.headers.push(['x-senzor-trace-id', trace.id]);\r\n newInit.headers.push(['x-senzor-parent-span-id', spanId]);\r\n } else {\r\n // Plain object\r\n (newInit.headers as any)['x-senzor-trace-id'] = trace.id;\r\n (newInit.headers as any)['x-senzor-parent-span-id'] = spanId;\r\n }\r\n\r\n try {\r\n // 6. Execute Fetch\r\n const response = await originalFetch(input, newInit);\r\n\r\n // 7. Record Span\r\n const duration = performance.now() - spanStartAbs;\r\n Context.addSpan({\r\n spanId,\r\n name: `${method} ${hostname}`,\r\n type: 'http',\r\n startTime,\r\n duration,\r\n status: response.status,\r\n meta: { url: urlStr, method, library: 'fetch' }\r\n });\r\n\r\n return response;\r\n } catch (err: any) {\r\n const duration = performance.now() - spanStartAbs;\r\n Context.addSpan({\r\n spanId,\r\n name: `${method} ${hostname}`,\r\n type: 'http',\r\n startTime,\r\n duration,\r\n status: 500,\r\n meta: { error: err.message, url: urlStr, library: 'fetch' }\r\n });\r\n throw err;\r\n }\r\n };\r\n};\r\n\r\n// --- HTTP/HTTPS INSTRUMENTATION ---\r\nexport const instrumentHttp = (ingestUrl: string, debug = false) => {\r\n let ingestHost = '';\r\n try { ingestHost = new URL(ingestUrl).hostname; } catch (e) { }\r\n\r\n const requestWrapper = (original: Function) => {\r\n return function (this: any, ...args: any[]) {\r\n let options: any = {};\r\n let urlStr = '';\r\n\r\n if (typeof args[0] === 'string' || args[0] instanceof URL) {\r\n urlStr = args[0].toString();\r\n if (typeof args[1] === 'object' && args[1] !== null) options = args[1];\r\n } else {\r\n options = args[0] || {};\r\n const protocol = options.protocol || (options.port === 443 ? 'https:' : 'http:');\r\n const host = options.hostname || options.host || 'localhost';\r\n const path = options.path || '/';\r\n urlStr = `${protocol}//${host}${path}`;\r\n }\r\n\r\n if (ingestHost && (urlStr.includes(ingestHost) || (options.hostname && options.hostname.includes(ingestHost)))) {\r\n return original.apply(this, args);\r\n }\r\n\r\n const trace = Context.current();\r\n if (!trace) return original.apply(this, args);\r\n\r\n const method = (options.method || 'GET').toUpperCase();\r\n const startTime = performance.now() - trace.startTime;\r\n const spanStartAbs = performance.now();\r\n const spanId = randomUUID(); // Generate ID\r\n\r\n let hostname = 'unknown';\r\n try { hostname = new URL(urlStr).hostname; } catch (e) { hostname = options.hostname || 'unknown'; }\r\n\r\n // Inject Headers\r\n if (!options.headers) options.headers = {};\r\n options.headers['x-senzor-trace-id'] = trace.id;\r\n options.headers['x-senzor-parent-span-id'] = spanId;\r\n\r\n const req = original.apply(this, args);\r\n\r\n const captureSpan = (res: any, error?: Error) => {\r\n const duration = performance.now() - spanStartAbs;\r\n Context.addSpan({\r\n spanId,\r\n name: `${method} ${hostname}`,\r\n type: 'http',\r\n startTime,\r\n duration,\r\n status: error ? 500 : res?.statusCode || 0,\r\n meta: { url: urlStr, method, library: 'http' }\r\n });\r\n };\r\n\r\n req.on('response', (res: any) => {\r\n res.once('end', () => captureSpan(res));\r\n res.once('close', () => captureSpan(res)); // Safety if stream not consumed\r\n res.once('error', (err: Error) => captureSpan(res, err));\r\n });\r\n\r\n req.on('error', (err: Error) => captureSpan(null, err));\r\n\r\n return req;\r\n };\r\n };\r\n\r\n shimmer(http, 'request', requestWrapper);\r\n shimmer(http, 'get', requestWrapper);\r\n shimmer(https, 'request', requestWrapper);\r\n shimmer(https, 'get', requestWrapper);\r\n};","import { Context } from '../core/context';\r\n\r\nexport const instrumentMongo = (debug = false) => {\r\n try {\r\n const mongodb = require('mongodb');\r\n const Collection = mongodb.Collection;\r\n\r\n // Attempt to get Cursor classes\r\n // Note: The location of these classes varies by driver version, \r\n // checking common locations\r\n const FindCursor = mongodb.FindCursor || require('mongodb/lib/cursor/find_cursor').FindCursor;\r\n const AggregationCursor = mongodb.AggregationCursor || require('mongodb/lib/cursor/aggregation_cursor').AggregationCursor;\r\n\r\n if (debug) console.log('[Senzor] Instrumenting MongoDB (Collection + Cursors)...');\r\n\r\n // --- Helper to Record Span ---\r\n const recordSpan = (name: string, operation: string, collection: string, startAbs: number, traceStart: number, err?: Error) => {\r\n const duration = performance.now() - startAbs;\r\n Context.addSpan({\r\n name: `MongoDB ${name}`,\r\n type: 'db',\r\n startTime: performance.now() - traceStart - duration, // Adjust start time to when op actually started\r\n duration,\r\n status: err ? 500 : 0,\r\n meta: { collection, operation, error: err ? err.message : undefined }\r\n });\r\n if (debug) console.log(`[Senzor] Captured Mongo: ${name} (${duration.toFixed(2)}ms)`);\r\n };\r\n\r\n // --- 1. Instrument Immediate Operations (Insert/Update/Delete) ---\r\n const immediateMethods = ['insertOne', 'insertMany', 'updateOne', 'updateMany', 'deleteOne', 'deleteMany', 'countDocuments'];\r\n\r\n immediateMethods.forEach((method) => {\r\n if (!Collection.prototype[method]) return;\r\n const original = Collection.prototype[method];\r\n\r\n Collection.prototype[method] = function (...args: any[]) {\r\n const trace = Context.current();\r\n if (!trace) return original.apply(this, args);\r\n\r\n const spanStartAbs = performance.now();\r\n const traceStart = trace.startTime;\r\n const collName = this.collectionName;\r\n\r\n try {\r\n const result = original.apply(this, args);\r\n if (result && typeof result.then === 'function') {\r\n return result.then(\r\n (res: any) => { recordSpan(method, method, collName, spanStartAbs, traceStart); return res; },\r\n (err: any) => { recordSpan(method, method, collName, spanStartAbs, traceStart, err); throw err; }\r\n );\r\n }\r\n return result;\r\n } catch (err: any) {\r\n recordSpan(method, method, collName, spanStartAbs, traceStart, err);\r\n throw err;\r\n }\r\n };\r\n });\r\n\r\n // --- 2. Instrument Cursor Execution (find -> toArray) ---\r\n const patchCursor = (CursorClass: any, label: string) => {\r\n if (!CursorClass || !CursorClass.prototype.toArray) return;\r\n\r\n const originalToArray = CursorClass.prototype.toArray;\r\n\r\n CursorClass.prototype.toArray = function (...args: any[]) {\r\n const trace = Context.current();\r\n // Cursors are often created in context but executed later. \r\n // We check context at execution time.\r\n if (!trace) return originalToArray.apply(this, args);\r\n\r\n const spanStartAbs = performance.now();\r\n const traceStart = trace.startTime;\r\n // Attempt to get collection name from cursor internal state\r\n const collName = this.namespace?.collection || 'unknown';\r\n\r\n const onSuccess = (res: any) => {\r\n recordSpan(label, label, collName, spanStartAbs, traceStart);\r\n return res;\r\n };\r\n const onError = (err: any) => {\r\n recordSpan(label, label, collName, spanStartAbs, traceStart, err);\r\n throw err;\r\n };\r\n\r\n try {\r\n const result = originalToArray.apply(this, args);\r\n if (result && typeof result.then === 'function') {\r\n return result.then(onSuccess, onError);\r\n }\r\n return onSuccess(result);\r\n } catch (e) {\r\n onError(e);\r\n }\r\n };\r\n };\r\n\r\n patchCursor(FindCursor, 'find');\r\n patchCursor(AggregationCursor, 'aggregate');\r\n\r\n } catch (e: any) {\r\n if (debug) console.warn('[Senzor] MongoDB instrumentation warning:', e.message);\r\n }\r\n};","import { Context } from '../core/context';\r\n\r\n// Simple shim for 'pg' library\r\nexport const instrumentPg = () => {\r\n try {\r\n // Try to require pg (it might not be installed by user)\r\n const pg = require('pg');\r\n const originalQuery = pg.Client.prototype.query;\r\n\r\n pg.Client.prototype.query = function (...args: any[]) {\r\n const trace = Context.current();\r\n if (!trace) return originalQuery.apply(this, args);\r\n\r\n const startTime = performance.now() - trace.startTime;\r\n const spanStartAbs = performance.now();\r\n\r\n // Extract SQL (first arg usually string or config object)\r\n const sql = typeof args[0] === 'string' ? args[0] : args[0].text;\r\n\r\n // Wrap callback if present, or handle Promise\r\n const result = originalQuery.apply(this, args);\r\n\r\n if (result && typeof result.then === 'function') {\r\n return result.then((res: any) => {\r\n const duration = performance.now() - spanStartAbs;\r\n Context.addSpan({\r\n name: 'Postgres Query',\r\n type: 'db',\r\n startTime,\r\n duration,\r\n meta: { query: sql }\r\n });\r\n return res;\r\n });\r\n }\r\n return result;\r\n };\r\n } catch (e) {\r\n // User doesn't use pg, ignore\r\n }\r\n};","import { client } from '../core/client';\r\n\r\n// 1. Request Handler (Place before routes)\r\nexport const expressMiddleware = () => {\r\n return (req: any, res: any, next: () => void) => {\r\n client.startTrace({\r\n method: req.method,\r\n path: req.originalUrl || req.url,\r\n ip: req.ip || req.socket?.remoteAddress,\r\n userAgent: req.headers['user-agent'],\r\n headers: req.headers\r\n }, () => {\r\n\r\n // Auto-detect status code on finish\r\n res.once('finish', () => {\r\n try {\r\n let route = 'UNKNOWN';\r\n // Express populates req.route only if a route matched\r\n if (req.route && req.route.path) {\r\n route = (req.baseUrl || '') + req.route.path;\r\n } else if (res.statusCode === 404) {\r\n route = 'Not Found';\r\n } else {\r\n route = req.path || 'Wildcard';\r\n }\r\n\r\n client.endTrace(res.statusCode, { route });\r\n } catch (e) { /* Fail open */ }\r\n });\r\n\r\n next();\r\n });\r\n };\r\n};\r\n\r\n// 2. Error Handler (Place after routes)\r\n// This is required in Express to capture the actual Error Object (Stack Trace)\r\nexport const expressErrorHandler = () => {\r\n return (err: any, req: any, res: any, next: (err?: any) => void) => {\r\n\r\n // 1. Capture the exception context\r\n client.captureError(err);\r\n\r\n // 2. Pass it to the next error handler (don't swallow it)\r\n next(err);\r\n };\r\n};","/**\r\n * Heuristic URL Normalizer\r\n * Converts raw paths with IDs into generic patterns to prevent high cardinality.\r\n * Example: /users/123/orders/abc-def -> /users/:id/orders/:uuid\r\n */\r\nexport const normalizePath = (path: string): string => {\r\n if (!path || path === '/') return '/';\r\n\r\n return path\r\n // Replace UUIDs (long alphanumeric strings)\r\n .replace(\r\n /[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}/g,\r\n ':uuid'\r\n )\r\n // Replace MongoDB ObjectIds (24 hex chars)\r\n .replace(/[0-9a-fA-F]{24}/g, ':objectId')\r\n // Replace pure numeric IDs (e.g., /123)\r\n .replace(/\\/(\\d+)(?=\\/|$)/g, '/:id')\r\n // Remove query strings\r\n .split('?')[0];\r\n};\r\n\r\n/**\r\n * Tries to extract route from Framework internals, falls back to heuristic\r\n */\r\nexport const getRoute = (req: any, fallbackPath: string): string => {\r\n // Express / Connect\r\n if (req.route && req.route.path) {\r\n return (req.baseUrl || '') + req.route.path;\r\n }\r\n\r\n // H3 / Nitro (Nuxt)\r\n if (req.context && req.context.matchedRoute) {\r\n return req.context.matchedRoute.path;\r\n }\r\n\r\n // Fastify\r\n if (req.routerPath) {\r\n return req.routerPath;\r\n }\r\n\r\n // Fallback: Heuristic Normalization\r\n return normalizePath(fallbackPath);\r\n};","import { client } from '../core/client';\r\nimport { getRoute } from '../core/normalizer';\r\n\r\ntype EventHandler = (event: any) => any;\r\n\r\nexport const wrapH3 = (handler: EventHandler) => {\r\n return (event: any) => {\r\n const req = event.node.req;\r\n const path = req.originalUrl || req.url || '/';\r\n\r\n return client.startTrace({\r\n method: req.method || 'GET',\r\n path: path,\r\n ip: req.headers['x-forwarded-for'] || req.socket?.remoteAddress,\r\n userAgent: req.headers['user-agent'],\r\n headers: req.headers // Pass headers\r\n }, async () => {\r\n try {\r\n const response = await handler(event);\r\n let status = 200;\r\n if (event.node.res.statusCode) status = event.node.res.statusCode;\r\n if (response && response.statusCode) status = response.statusCode;\r\n\r\n client.endTrace(status, { route: getRoute(event, path) });\r\n return response;\r\n } catch (err: any) {\r\n client.captureError(err);\r\n const status = err.statusCode || err.status || 500;\r\n client.endTrace(status, { route: getRoute(event, path) });\r\n throw err;\r\n }\r\n });\r\n };\r\n};","import { client } from '../core/client';\r\nimport { normalizePath } from '../core/normalizer';\r\n\r\n// --- App Router Wrapper ---\r\nexport const wrapNextRoute = (handler: Function) => {\r\n return async (req: Request | any, context?: any) => {\r\n\r\n // Extract info from Web Standard Request\r\n const url = req.url ? new URL(req.url) : { pathname: '/' };\r\n const method = req.method || 'GET';\r\n\r\n // Header Extraction\r\n let headers: Record<string, string> = {};\r\n let ua: string | undefined;\r\n let ip: string | undefined;\r\n\r\n if (typeof req.headers.get === 'function') {\r\n // It's a Web Request Object\r\n ua = req.headers.get('user-agent');\r\n ip = req.headers.get('x-forwarded-for');\r\n\r\n // Convert to plain object for trace context extraction\r\n req.headers.forEach((value: string, key: string) => {\r\n headers[key] = value;\r\n });\r\n } else {\r\n // It's a Node Request Object (rare in App router but possible)\r\n headers = req.headers;\r\n ua = headers['user-agent'];\r\n ip = headers['x-forwarded-for'] as string;\r\n }\r\n\r\n return client.startTrace({\r\n method,\r\n path: url.pathname,\r\n userAgent: ua,\r\n ip: ip,\r\n headers: headers // Pass extracted headers\r\n }, async () => {\r\n try {\r\n const response = await handler(req, context);\r\n const status = response?.status || 200;\r\n\r\n client.endTrace(status, { route: normalizePath(url.pathname) });\r\n return response;\r\n } catch (err: any) {\r\n client.captureError(err);\r\n client.endTrace(500, { route: normalizePath(url.pathname) });\r\n throw err;\r\n }\r\n });\r\n };\r\n};\r\n\r\n// --- Pages Router Wrapper ---\r\nexport const wrapNextPages = (handler: Function) => {\r\n return async (req: any, res: any) => {\r\n const path = req.url ? req.url.split('?')[0] : '/';\r\n\r\n return client.startTrace({\r\n method: req.method || 'GET',\r\n path: path,\r\n userAgent: req.headers['user-agent'],\r\n ip: req.headers['x-forwarded-for'] || req.socket?.remoteAddress,\r\n headers: req.headers // Standard Node headers work fine\r\n }, async () => {\r\n\r\n const done = () => {\r\n client.endTrace(res.statusCode || 200, { route: normalizePath(path) });\r\n };\r\n\r\n res.once('finish', done);\r\n res.once('close', done);\r\n\r\n try {\r\n return await handler(req, res);\r\n } catch (e: any) {\r\n client.captureError(e);\r\n throw e;\r\n }\r\n });\r\n };\r\n};","import { client } from '../core/client';\r\nimport { SenzorOptions } from '../core/types';\r\n\r\nexport const senzorPlugin = (fastify: any, options: SenzorOptions, done: Function) => {\r\n if (options && options.apiKey) {\r\n client.init(options);\r\n }\r\n\r\n fastify.addHook('onRequest', (request: any, reply: any, next: Function) => {\r\n client.startTrace({\r\n method: request.method,\r\n path: request.raw.url || request.url,\r\n ip: request.ip,\r\n userAgent: request.headers['user-agent'],\r\n headers: request.headers // Pass headers\r\n }, () => next());\r\n });\r\n\r\n fastify.addHook('onError', (request: any, reply: any, error: any, next: Function) => {\r\n client.captureError(error);\r\n next();\r\n });\r\n\r\n fastify.addHook('onResponse', (request: any, reply: any, next: Function) => {\r\n const route = request.routeOptions?.url || request.routerPath || 'UNKNOWN';\r\n client.endTrace(reply.statusCode, { route });\r\n next();\r\n });\r\n\r\n done();\r\n};","import { client } from './core/client';\r\nimport { expressMiddleware, expressErrorHandler } from './middleware/express';\r\nimport { wrapH3 } from './wrappers/h3';\r\nimport { wrapNextRoute, wrapNextPages } from './wrappers/next';\r\nimport { senzorPlugin } from './wrappers/fastify';\r\nimport { SenzorOptions } from './core/types';\r\n\r\nconst Senzor = {\r\n init: (options: SenzorOptions) => client.init(options),\r\n flush: () => client.flush(),\r\n track: client.track.bind(client),\r\n startSpan: client.startSpan.bind(client),\r\n captureException: client.captureError.bind(client),\r\n\r\n // Express\r\n requestHandler: expressMiddleware,\r\n errorHandler: expressErrorHandler,\r\n\r\n // Next\r\n wrapNextRoute,\r\n wrapNextPages,\r\n\r\n // H3\r\n wrapH3,\r\n\r\n // Fastify\r\n fastifyPlugin: senzorPlugin\r\n};\r\n\r\nexport default Senzor;\r\nexport { Senzor };"],"mappings":"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","names":["Transport","config","trace","batch","err","import_async_hooks","storage","Context","trace","fn","span","store","error","import_crypto","import_http","import_https","import_url","import_crypto","shimmer","module","methodName","wrapper","original","instrumentFetch","ingestUrl","debug","ingestHost","originalFetch","input","init","urlStr","trace","Context","method","startTime","spanStartAbs","spanId","hostname","newInit","response","duration","err","instrumentHttp","requestWrapper","args","options","protocol","host","path","req","captureSpan","res","error","http","https","instrumentMongo","debug","mongodb","Collection","FindCursor","AggregationCursor","recordSpan","name","operation","collection","startAbs","traceStart","err","duration","Context","method","original","args","trace","spanStartAbs","collName","result","res","patchCursor","CursorClass","label","originalToArray","onSuccess","onError","e","instrumentPg","pg","originalQuery","args","trace","Context","startTime","spanStartAbs","sql","result","res","duration","SenzorClient","options","endpoint","debug","Transport","instrumentHttp","instrumentFetch","instrumentMongo","instrumentPg","data","next","parentTraceId","parentSpanId","trace","Context","status","extraData","duration","payload","error","name","type","startTime","spanStartAbs","spanId","meta","client","expressMiddleware","req","res","next","client","route","expressErrorHandler","err","normalizePath","path","getRoute","req","fallbackPath","wrapH3","handler","event","req","path","client","response","status","getRoute","err","wrapNextRoute","handler","req","context","url","method","headers","ua","ip","value","key","client","response","status","normalizePath","err","wrapNextPages","res","path","done","e","senzorPlugin","fastify","options","done","client","request","reply","next","error","route","Senzor","options","client","expressMiddleware","expressErrorHandler","wrapNextRoute","wrapNextPages","wrapH3","senzorPlugin","index_default"]}
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- "use strict";var J=Object.create;var A=Object.defineProperty;var Q=Object.getOwnPropertyDescriptor;var V=Object.getOwnPropertyNames;var X=Object.getPrototypeOf,Y=Object.prototype.hasOwnProperty;var Z=(e,t)=>{for(var n in t)A(e,n,{get:t[n],enumerable:!0})},P=(e,t,n,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of V(t))!Y.call(e,o)&&o!==n&&A(e,o,{get:()=>t[o],enumerable:!(r=Q(t,o))||r.enumerable});return e};var $=(e,t,n)=>(n=e!=null?J(X(e)):{},P(t||!e||!e.__esModule?A(n,"default",{value:e,enumerable:!0}):n,e)),_=e=>P(A({},"__esModule",{value:!0}),e);var tt={};Z(tt,{Senzor:()=>B,default:()=>q});module.exports=_(tt);var E=class{constructor(t){this.config=t;this.queue=[];this.timer=null;typeof setInterval<"u"&&(this.timer=setInterval(()=>this.flush(),t.flushInterval||1e4),this.timer&&typeof this.timer.unref=="function"&&this.timer.unref())}add(t){this.queue.push(t),this.queue.length>=(this.config.batchSize||100)&&this.flush()}async flush(){if(this.queue.length===0)return;let t=[...this.queue];this.queue=[];try{await fetch(this.config.endpoint||"https://api.senzor.dev/api/ingest/apm",{method:"POST",headers:{"Content-Type":"application/json","x-service-api-key":this.config.apiKey},body:JSON.stringify(t),keepalive:!0}),this.config.debug&&console.log(`[Senzor] Flushed ${t.length} traces`)}catch(n){this.config.debug&&console.error("[Senzor] Ingestion Error:",n)}}};var H=require("async_hooks"),C=new H.AsyncLocalStorage,m={run:(e,t)=>C.run(e,t),current:()=>C.getStore(),addSpan:e=>{let t=C.getStore();t&&t.spans.push(e)},setError:e=>{let t=C.getStore();t&&(t.error={name:e.name,message:e.message,stack:e.stack})}};var k=require("crypto");var z=$(require("http")),v=$(require("https")),T=require("url");var F=(e,t,n)=>{if(!e[t])return;let r=e[t];e[t]=n(r)},N=(e,t=!1)=>{if(!globalThis.fetch)return;let n="";try{n=new T.URL(e).hostname}catch{}let r=globalThis.fetch;globalThis.fetch=async(o,a)=>{let i="";if(typeof o=="string"?i=o:o instanceof T.URL?i=o.toString():o&&o.url&&(i=o.url),n&&i.includes(n))return r(o,a);let u=m.current();if(!u)return r(o,a);let c=(a?.method||"GET").toUpperCase(),h=performance.now()-u.startTime,w=performance.now(),y="unknown";try{y=new T.URL(i).hostname}catch{}t&&console.log(`[Senzor] Tracking Fetch: ${c} ${y}`);try{let l=await r(o,a),d=performance.now()-w;return m.addSpan({name:`${c} ${y}`,type:"http",startTime:h,duration:d,status:l.status,meta:{url:i,method:c,library:"fetch"}}),l}catch(l){let d=performance.now()-w;throw m.addSpan({name:`${c} ${y}`,type:"http",startTime:h,duration:d,status:500,meta:{error:l.message,url:i,library:"fetch"}}),l}}},R=(e,t=!1)=>{let n="";try{n=new T.URL(e).hostname}catch{}let r=o=>function(...a){let i={},u="";if(typeof a[0]=="string"||a[0]instanceof T.URL)u=a[0].toString(),typeof a[1]=="object"&&a[1]!==null&&(i=a[1]);else{i=a[0]||{};let p=i.protocol||(i.port===443?"https:":"http:"),f=i.hostname||i.host||"localhost",b=i.path||"/";u=`${p}//${f}${b}`}if(n&&(u.includes(n)||i.hostname&&i.hostname.includes(n)))return o.apply(this,a);let c=m.current();if(!c)return o.apply(this,a);let h=(i.method||"GET").toUpperCase(),w=performance.now()-c.startTime,y=performance.now(),l="unknown";try{l=new T.URL(u).hostname}catch{l=i.hostname||"unknown"}let d=o.apply(this,a),g=(p,f)=>{let b=performance.now()-y;m.addSpan({name:`${h} ${l}`,type:"http",startTime:w,duration:b,status:f?500:p?.statusCode||0,meta:{url:u,method:h,library:"http",error:f?f.message:void 0}})};return d.on("response",p=>{p.once("end",()=>g(p)),p.once("error",f=>g(p,f))}),d.on("error",p=>g(null,p)),d};F(z.default,"request",r),F(z.default,"get",r),F(v.default,"request",r),F(v.default,"get",r)};var M=(e=!1)=>{try{let t=require("mongodb"),n=t.Collection,r=t.FindCursor||require("mongodb/lib/cursor/find_cursor").FindCursor,o=t.AggregationCursor||require("mongodb/lib/cursor/aggregation_cursor").AggregationCursor;e&&console.log("[Senzor] Instrumenting MongoDB (Collection + Cursors)...");let a=(c,h,w,y,l,d)=>{let g=performance.now()-y;m.addSpan({name:`MongoDB ${c}`,type:"db",startTime:performance.now()-l-g,duration:g,status:d?500:0,meta:{collection:w,operation:h,error:d?d.message:void 0}}),e&&console.log(`[Senzor] Captured Mongo: ${c} (${g.toFixed(2)}ms)`)};["insertOne","insertMany","updateOne","updateMany","deleteOne","deleteMany","countDocuments"].forEach(c=>{if(!n.prototype[c])return;let h=n.prototype[c];n.prototype[c]=function(...w){let y=m.current();if(!y)return h.apply(this,w);let l=performance.now(),d=y.startTime,g=this.collectionName;try{let p=h.apply(this,w);return p&&typeof p.then=="function"?p.then(f=>(a(c,c,g,l,d),f),f=>{throw a(c,c,g,l,d,f),f}):p}catch(p){throw a(c,c,g,l,d,p),p}}});let u=(c,h)=>{if(!c||!c.prototype.toArray)return;let w=c.prototype.toArray;c.prototype.toArray=function(...y){let l=m.current();if(!l)return w.apply(this,y);let d=performance.now(),g=l.startTime,p=this.namespace?.collection||"unknown",f=S=>(a(h,h,p,d,g),S),b=S=>{throw a(h,h,p,d,g,S),S};try{let S=w.apply(this,y);return S&&typeof S.then=="function"?S.then(f,b):f(S)}catch(S){b(S)}}};u(r,"find"),u(o,"aggregate")}catch(t){e&&console.warn("[Senzor] MongoDB instrumentation warning:",t.message)}};var U=()=>{try{let e=require("pg"),t=e.Client.prototype.query;e.Client.prototype.query=function(...n){let r=m.current();if(!r)return t.apply(this,n);let o=performance.now()-r.startTime,a=performance.now(),i=typeof n[0]=="string"?n[0]:n[0].text,u=t.apply(this,n);return u&&typeof u.then=="function"?u.then(c=>{let h=performance.now()-a;return m.addSpan({name:"Postgres Query",type:"db",startTime:o,duration:h,meta:{query:i}}),c}):u}}catch{}};var O=class{constructor(){this.transport=null;this.options=null;this.isInstrumented=!1}init(t){if(!t.apiKey){console.warn("[Senzor] API Key missing. SDK disabled.");return}this.options=t;let n=t.endpoint||"https://api.senzor.dev/api/ingest/apm",r=t.debug||!1;if(this.transport=new E({...t,endpoint:n}),!this.isInstrumented){try{R(n,r)}catch{}try{N(n,r)}catch{}try{M(r)}catch{}try{U()}catch{}this.isInstrumented=!0,r&&console.log("[Senzor] Auto-instrumentation enabled")}}startTrace(t,n){if(!this.transport)return n();let r={id:(0,k.randomUUID)(),startTime:performance.now(),data:t,spans:[]};return m.run(r,n)}endTrace(t,n={}){let r=m.current();if(!r||!this.transport)return;let o=performance.now()-r.startTime,a={traceId:r.id,...r.data,...n,status:t,duration:o,spans:r.spans,error:r.error,timestamp:new Date().toISOString()};this.transport.add(a)}captureError(t){t instanceof Error?m.setError(t):typeof t=="string"&&m.setError(new Error(t))}track(t){this.transport?.add({traceId:(0,k.randomUUID)(),...t,spans:[],timestamp:new Date().toISOString()})}startSpan(t,n="custom"){let r=m.current();if(!r)return{end:()=>{}};let o=performance.now()-r.startTime,a=performance.now();return{end:(i,u)=>{m.addSpan({name:t,type:n,startTime:o,duration:performance.now()-a,status:u,meta:i})}}}async flush(){this.transport&&await this.transport.flush()}},s=new O;var D=()=>(e,t,n)=>{s.startTrace({method:e.method,path:e.originalUrl||e.url,ip:e.ip||e.socket?.remoteAddress,userAgent:e.headers["user-agent"]},()=>{t.once("finish",()=>{try{let r="UNKNOWN";e.route&&e.route.path?r=(e.baseUrl||"")+e.route.path:t.statusCode===404?r="Not Found":r=e.path||"Wildcard",s.endTrace(t.statusCode,{route:r})}catch{}}),n()})},K=()=>(e,t,n,r)=>{s.captureError(e),r(e)};var x=e=>!e||e==="/"?"/":e.replace(/[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}/g,":uuid").replace(/[0-9a-fA-F]{24}/g,":objectId").replace(/\/(\d+)(?=\/|$)/g,"/:id").split("?")[0],I=(e,t)=>e.route&&e.route.path?(e.baseUrl||"")+e.route.path:e.context&&e.context.matchedRoute?e.context.matchedRoute.path:e.routerPath?e.routerPath:x(t);var G=e=>t=>{let n=t.node.req,r=n.originalUrl||n.url||"/";return s.startTrace({method:n.method||"GET",path:r,ip:n.headers["x-forwarded-for"]||n.socket?.remoteAddress,userAgent:n.headers["user-agent"]},async()=>{try{let o=await e(t),a=200;return t.node.res.statusCode&&(a=t.node.res.statusCode),o&&o.statusCode&&(a=o.statusCode),s.endTrace(a,{route:I(t,r)}),o}catch(o){s.captureError(o);let a=o.statusCode||o.status||500;throw s.endTrace(a,{route:I(t,r)}),o}})};var L=e=>async(t,n)=>{let r=t.url?new URL(t.url):{pathname:"/"},o=t.method||"GET",a=t.headers.get?t.headers.get("user-agent"):void 0,i=t.headers.get?t.headers.get("x-forwarded-for"):void 0;return s.startTrace({method:o,path:r.pathname,userAgent:a,ip:i},async()=>{try{let u=await e(t,n),c=u?.status||200;return s.endTrace(c,{route:x(r.pathname)}),u}catch(u){throw s.captureError(u),s.endTrace(500,{route:x(r.pathname)}),u}})},W=e=>async(t,n)=>{let r=t.url?t.url.split("?")[0]:"/";return s.startTrace({method:t.method||"GET",path:r,userAgent:t.headers["user-agent"],ip:t.headers["x-forwarded-for"]||t.socket?.remoteAddress},async()=>{let o=()=>{s.endTrace(n.statusCode||200,{route:x(r)})};n.once("finish",o),n.once("close",o);try{return await e(t,n)}catch(a){throw s.captureError(a),a}})};var j=(e,t,n)=>{t&&t.apiKey&&s.init(t),e.addHook("onRequest",(r,o,a)=>{s.startTrace({method:r.method,path:r.raw.url||r.url,ip:r.ip,userAgent:r.headers["user-agent"]},()=>a())}),e.addHook("onError",(r,o,a,i)=>{s.captureError(a),i()}),e.addHook("onResponse",(r,o,a)=>{let i=r.routeOptions?.url||r.routerPath||"UNKNOWN";s.endTrace(o.statusCode,{route:i}),a()}),n()};var B={init:e=>s.init(e),flush:()=>s.flush(),track:s.track.bind(s),startSpan:s.startSpan.bind(s),captureException:s.captureError.bind(s),requestHandler:D,errorHandler:K,wrapNextRoute:L,wrapNextPages:W,wrapH3:G,fastifyPlugin:j},q=B;0&&(module.exports={Senzor});
1
+ "use strict";var Q=Object.create;var b=Object.defineProperty;var X=Object.getOwnPropertyDescriptor;var Z=Object.getOwnPropertyNames;var V=Object.getPrototypeOf,Y=Object.prototype.hasOwnProperty;var _=(e,t)=>{for(var n in t)b(e,n,{get:t[n],enumerable:!0})},N=(e,t,n,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of Z(t))!Y.call(e,o)&&o!==n&&b(e,o,{get:()=>t[o],enumerable:!(r=X(t,o))||r.enumerable});return e};var P=(e,t,n)=>(n=e!=null?Q(V(e)):{},N(t||!e||!e.__esModule?b(n,"default",{value:e,enumerable:!0}):n,e)),q=e=>N(b({},"__esModule",{value:!0}),e);var et={};_(et,{Senzor:()=>J,default:()=>tt});module.exports=q(et);var E=class{constructor(t){this.config=t;this.queue=[];this.timer=null;typeof setInterval<"u"&&(this.timer=setInterval(()=>this.flush(),t.flushInterval||1e4),this.timer&&typeof this.timer.unref=="function"&&this.timer.unref())}add(t){this.queue.push(t),this.queue.length>=(this.config.batchSize||100)&&this.flush()}async flush(){if(this.queue.length===0)return;let t=[...this.queue];this.queue=[];try{await fetch(this.config.endpoint||"https://api.senzor.dev/api/ingest/apm",{method:"POST",headers:{"Content-Type":"application/json","x-service-api-key":this.config.apiKey},body:JSON.stringify(t),keepalive:!0}),this.config.debug&&console.log(`[Senzor] Flushed ${t.length} traces`)}catch(n){this.config.debug&&console.error("[Senzor] Ingestion Error:",n)}}};var H=require("async_hooks"),z=new H.AsyncLocalStorage,l={run:(e,t)=>z.run(e,t),current:()=>z.getStore(),addSpan:e=>{let t=z.getStore();t&&t.spans.push(e)},setError:e=>{let t=z.getStore();t&&(t.error={name:e.name,message:e.message,stack:e.stack})}};var C=require("crypto");var F=P(require("http")),O=P(require("https")),x=require("url");var v=require("crypto"),I=(e,t,n)=>{if(!e[t])return;let r=e[t];e[t]=n(r)},$=(e,t=!1)=>{if(!globalThis.fetch)return;let n="";try{n=new x.URL(e).hostname}catch{}let r=globalThis.fetch;globalThis.fetch=async(o,a)=>{let i="";if(typeof o=="string"?i=o:o instanceof x.URL?i=o.toString():o&&o.url&&(i=o.url),n&&i.includes(n))return r(o,a);let u=l.current();if(!u)return r(o,a);let s=(a?.method||"GET").toUpperCase(),d=performance.now()-u.startTime,S=performance.now(),g=(0,v.randomUUID)(),y="unknown";try{y=new x.URL(i).hostname}catch{}t&&console.log(`[Senzor] Fetch: ${s} ${y}`);let p={...a};p.headers||(p.headers={}),p.headers instanceof Headers?(p.headers.set("x-senzor-trace-id",u.id),p.headers.set("x-senzor-parent-span-id",g)):Array.isArray(p.headers)?(p.headers.push(["x-senzor-trace-id",u.id]),p.headers.push(["x-senzor-parent-span-id",g])):(p.headers["x-senzor-trace-id"]=u.id,p.headers["x-senzor-parent-span-id"]=g);try{let h=await r(o,p),m=performance.now()-S;return l.addSpan({spanId:g,name:`${s} ${y}`,type:"http",startTime:d,duration:m,status:h.status,meta:{url:i,method:s,library:"fetch"}}),h}catch(h){let m=performance.now()-S;throw l.addSpan({spanId:g,name:`${s} ${y}`,type:"http",startTime:d,duration:m,status:500,meta:{error:h.message,url:i,library:"fetch"}}),h}}},U=(e,t=!1)=>{let n="";try{n=new x.URL(e).hostname}catch{}let r=o=>function(...a){let i={},u="";if(typeof a[0]=="string"||a[0]instanceof x.URL)u=a[0].toString(),typeof a[1]=="object"&&a[1]!==null&&(i=a[1]);else{i=a[0]||{};let f=i.protocol||(i.port===443?"https:":"http:"),T=i.hostname||i.host||"localhost",w=i.path||"/";u=`${f}//${T}${w}`}if(n&&(u.includes(n)||i.hostname&&i.hostname.includes(n)))return o.apply(this,a);let s=l.current();if(!s)return o.apply(this,a);let d=(i.method||"GET").toUpperCase(),S=performance.now()-s.startTime,g=performance.now(),y=(0,v.randomUUID)(),p="unknown";try{p=new x.URL(u).hostname}catch{p=i.hostname||"unknown"}i.headers||(i.headers={}),i.headers["x-senzor-trace-id"]=s.id,i.headers["x-senzor-parent-span-id"]=y;let h=o.apply(this,a),m=(f,T)=>{let w=performance.now()-g;l.addSpan({spanId:y,name:`${d} ${p}`,type:"http",startTime:S,duration:w,status:T?500:f?.statusCode||0,meta:{url:u,method:d,library:"http"}})};return h.on("response",f=>{f.once("end",()=>m(f)),f.once("close",()=>m(f)),f.once("error",T=>m(f,T))}),h.on("error",f=>m(null,f)),h};I(F.default,"request",r),I(F.default,"get",r),I(O.default,"request",r),I(O.default,"get",r)};var M=(e=!1)=>{try{let t=require("mongodb"),n=t.Collection,r=t.FindCursor||require("mongodb/lib/cursor/find_cursor").FindCursor,o=t.AggregationCursor||require("mongodb/lib/cursor/aggregation_cursor").AggregationCursor;e&&console.log("[Senzor] Instrumenting MongoDB (Collection + Cursors)...");let a=(s,d,S,g,y,p)=>{let h=performance.now()-g;l.addSpan({name:`MongoDB ${s}`,type:"db",startTime:performance.now()-y-h,duration:h,status:p?500:0,meta:{collection:S,operation:d,error:p?p.message:void 0}}),e&&console.log(`[Senzor] Captured Mongo: ${s} (${h.toFixed(2)}ms)`)};["insertOne","insertMany","updateOne","updateMany","deleteOne","deleteMany","countDocuments"].forEach(s=>{if(!n.prototype[s])return;let d=n.prototype[s];n.prototype[s]=function(...S){let g=l.current();if(!g)return d.apply(this,S);let y=performance.now(),p=g.startTime,h=this.collectionName;try{let m=d.apply(this,S);return m&&typeof m.then=="function"?m.then(f=>(a(s,s,h,y,p),f),f=>{throw a(s,s,h,y,p,f),f}):m}catch(m){throw a(s,s,h,y,p,m),m}}});let u=(s,d)=>{if(!s||!s.prototype.toArray)return;let S=s.prototype.toArray;s.prototype.toArray=function(...g){let y=l.current();if(!y)return S.apply(this,g);let p=performance.now(),h=y.startTime,m=this.namespace?.collection||"unknown",f=w=>(a(d,d,m,p,h),w),T=w=>{throw a(d,d,m,p,h,w),w};try{let w=S.apply(this,g);return w&&typeof w.then=="function"?w.then(f,T):f(w)}catch(w){T(w)}}};u(r,"find"),u(o,"aggregate")}catch(t){e&&console.warn("[Senzor] MongoDB instrumentation warning:",t.message)}};var D=()=>{try{let e=require("pg"),t=e.Client.prototype.query;e.Client.prototype.query=function(...n){let r=l.current();if(!r)return t.apply(this,n);let o=performance.now()-r.startTime,a=performance.now(),i=typeof n[0]=="string"?n[0]:n[0].text,u=t.apply(this,n);return u&&typeof u.then=="function"?u.then(s=>{let d=performance.now()-a;return l.addSpan({name:"Postgres Query",type:"db",startTime:o,duration:d,meta:{query:i}}),s}):u}}catch{}};var R=class{constructor(){this.transport=null;this.options=null;this.isInstrumented=!1}init(t){if(!t.apiKey){console.warn("[Senzor] API Key missing. SDK disabled.");return}this.options=t;let n=t.endpoint||"https://api.senzor.dev/api/ingest/apm",r=t.debug||!1;if(this.transport=new E({...t,endpoint:n}),!this.isInstrumented){try{U(n,r)}catch{}try{$(n,r)}catch{}try{M(r)}catch{}try{D()}catch{}this.isInstrumented=!0,r&&console.log("[Senzor] Auto-instrumentation enabled")}}startTrace(t,n){if(!this.transport)return n();let r,o;t.headers&&(r=t.headers["x-senzor-trace-id"]||t.headers["X-SENZOR-TRACE-ID"],o=t.headers["x-senzor-parent-span-id"]||t.headers["X-SENZOR-PARENT-SPAN-ID"]);let a={id:(0,C.randomUUID)(),startTime:performance.now(),data:{...t,parentTraceId:r,parentSpanId:o},spans:[]};return l.run(a,n)}endTrace(t,n={}){let r=l.current();if(!r||!this.transport)return;let o=performance.now()-r.startTime,a={traceId:r.id,parentTraceId:r.data.parentTraceId,parentSpanId:r.data.parentSpanId,...r.data,...n,status:t,duration:o,spans:r.spans,timestamp:new Date().toISOString(),error:r.error};this.transport.add(a)}captureError(t){t instanceof Error?l.setError(t):typeof t=="string"&&l.setError(new Error(t))}track(t){this.transport?.add({traceId:(0,C.randomUUID)(),...t,spans:[],timestamp:new Date().toISOString()})}startSpan(t,n="custom"){let r=l.current();if(!r)return{end:()=>{}};let o=performance.now()-r.startTime,a=performance.now(),i=(0,C.randomUUID)();return{end:(u,s)=>{let d=performance.now()-a;l.addSpan({spanId:i,name:t,type:n,startTime:o,duration:d,status:s,meta:u})}}}async flush(){this.transport&&await this.transport.flush()}},c=new R;var K=()=>(e,t,n)=>{c.startTrace({method:e.method,path:e.originalUrl||e.url,ip:e.ip||e.socket?.remoteAddress,userAgent:e.headers["user-agent"],headers:e.headers},()=>{t.once("finish",()=>{try{let r="UNKNOWN";e.route&&e.route.path?r=(e.baseUrl||"")+e.route.path:t.statusCode===404?r="Not Found":r=e.path||"Wildcard",c.endTrace(t.statusCode,{route:r})}catch{}}),n()})},G=()=>(e,t,n,r)=>{c.captureError(e),r(e)};var A=e=>!e||e==="/"?"/":e.replace(/[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}/g,":uuid").replace(/[0-9a-fA-F]{24}/g,":objectId").replace(/\/(\d+)(?=\/|$)/g,"/:id").split("?")[0],k=(e,t)=>e.route&&e.route.path?(e.baseUrl||"")+e.route.path:e.context&&e.context.matchedRoute?e.context.matchedRoute.path:e.routerPath?e.routerPath:A(t);var L=e=>t=>{let n=t.node.req,r=n.originalUrl||n.url||"/";return c.startTrace({method:n.method||"GET",path:r,ip:n.headers["x-forwarded-for"]||n.socket?.remoteAddress,userAgent:n.headers["user-agent"],headers:n.headers},async()=>{try{let o=await e(t),a=200;return t.node.res.statusCode&&(a=t.node.res.statusCode),o&&o.statusCode&&(a=o.statusCode),c.endTrace(a,{route:k(t,r)}),o}catch(o){c.captureError(o);let a=o.statusCode||o.status||500;throw c.endTrace(a,{route:k(t,r)}),o}})};var W=e=>async(t,n)=>{let r=t.url?new URL(t.url):{pathname:"/"},o=t.method||"GET",a={},i,u;return typeof t.headers.get=="function"?(i=t.headers.get("user-agent"),u=t.headers.get("x-forwarded-for"),t.headers.forEach((s,d)=>{a[d]=s})):(a=t.headers,i=a["user-agent"],u=a["x-forwarded-for"]),c.startTrace({method:o,path:r.pathname,userAgent:i,ip:u,headers:a},async()=>{try{let s=await e(t,n),d=s?.status||200;return c.endTrace(d,{route:A(r.pathname)}),s}catch(s){throw c.captureError(s),c.endTrace(500,{route:A(r.pathname)}),s}})},j=e=>async(t,n)=>{let r=t.url?t.url.split("?")[0]:"/";return c.startTrace({method:t.method||"GET",path:r,userAgent:t.headers["user-agent"],ip:t.headers["x-forwarded-for"]||t.socket?.remoteAddress,headers:t.headers},async()=>{let o=()=>{c.endTrace(n.statusCode||200,{route:A(r)})};n.once("finish",o),n.once("close",o);try{return await e(t,n)}catch(a){throw c.captureError(a),a}})};var B=(e,t,n)=>{t&&t.apiKey&&c.init(t),e.addHook("onRequest",(r,o,a)=>{c.startTrace({method:r.method,path:r.raw.url||r.url,ip:r.ip,userAgent:r.headers["user-agent"],headers:r.headers},()=>a())}),e.addHook("onError",(r,o,a,i)=>{c.captureError(a),i()}),e.addHook("onResponse",(r,o,a)=>{let i=r.routeOptions?.url||r.routerPath||"UNKNOWN";c.endTrace(o.statusCode,{route:i}),a()}),n()};var J={init:e=>c.init(e),flush:()=>c.flush(),track:c.track.bind(c),startSpan:c.startSpan.bind(c),captureException:c.captureError.bind(c),requestHandler:K,errorHandler:G,wrapNextRoute:W,wrapNextPages:j,wrapH3:L,fastifyPlugin:B},tt=J;0&&(module.exports={Senzor});
2
2
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/core/transport.ts","../src/core/context.ts","../src/core/client.ts","../src/instrumentation/http.ts","../src/instrumentation/mongo.ts","../src/instrumentation/pg.ts","../src/middleware/express.ts","../src/core/normalizer.ts","../src/wrappers/h3.ts","../src/wrappers/next.ts","../src/wrappers/fastify.ts"],"sourcesContent":["import { client } from './core/client';\r\nimport { expressMiddleware, expressErrorHandler } from './middleware/express';\r\nimport { wrapH3 } from './wrappers/h3';\r\nimport { wrapNextRoute, wrapNextPages } from './wrappers/next';\r\nimport { senzorPlugin } from './wrappers/fastify';\r\nimport { SenzorOptions } from './core/types';\r\n\r\nconst Senzor = {\r\n init: (options: SenzorOptions) => client.init(options),\r\n flush: () => client.flush(),\r\n track: client.track.bind(client),\r\n startSpan: client.startSpan.bind(client),\r\n captureException: client.captureError.bind(client),\r\n\r\n // Express\r\n requestHandler: expressMiddleware,\r\n errorHandler: expressErrorHandler,\r\n\r\n // Next\r\n wrapNextRoute,\r\n wrapNextPages,\r\n\r\n // H3\r\n wrapH3,\r\n\r\n // Fastify\r\n fastifyPlugin: senzorPlugin\r\n};\r\n\r\nexport default Senzor;\r\nexport { Senzor };","import { SenzorOptions } from './types';\r\n\r\nexport class Transport {\r\n private queue: any[] = [];\r\n private timer: NodeJS.Timeout | null = null;\r\n\r\n constructor(private config: SenzorOptions) {\r\n if (typeof setInterval !== 'undefined') {\r\n this.timer = setInterval(() => this.flush(), config.flushInterval || 10000);\r\n if (this.timer && typeof this.timer.unref === 'function') {\r\n this.timer.unref(); // Don't block process exit\r\n }\r\n }\r\n }\r\n\r\n public add(trace: any) {\r\n this.queue.push(trace);\r\n if (this.queue.length >= (this.config.batchSize || 100)) {\r\n this.flush();\r\n }\r\n }\r\n\r\n public async flush() {\r\n if (this.queue.length === 0) return;\r\n\r\n const batch = [...this.queue];\r\n this.queue = [];\r\n\r\n try {\r\n // Use global fetch (Node 18+)\r\n await fetch(this.config.endpoint || 'https://api.senzor.dev/api/ingest/apm', {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n 'x-service-api-key': this.config.apiKey,\r\n },\r\n body: JSON.stringify(batch),\r\n keepalive: true,\r\n });\r\n \r\n if (this.config.debug) console.log(`[Senzor] Flushed ${batch.length} traces`);\r\n } catch (err) {\r\n if (this.config.debug) console.error('[Senzor] Ingestion Error:', err);\r\n // Dropping data to prevent memory leaks is preferred in APM\r\n }\r\n }\r\n}","import { AsyncLocalStorage } from 'async_hooks';\r\nimport { ActiveTrace, TraceError } from './types';\r\n\r\nexport const storage = new AsyncLocalStorage<ActiveTrace>();\r\n\r\nexport const Context = {\r\n run: <T>(trace: ActiveTrace, fn: () => T): T => {\r\n return storage.run(trace, fn);\r\n },\r\n\r\n current: (): ActiveTrace | undefined => {\r\n return storage.getStore();\r\n },\r\n\r\n addSpan: (span: any) => {\r\n const store = storage.getStore();\r\n if (store) {\r\n store.spans.push(span);\r\n }\r\n },\r\n\r\n // Attach error to current trace\r\n setError: (error: Error) => {\r\n const store = storage.getStore();\r\n if (store) {\r\n store.error = {\r\n name: error.name,\r\n message: error.message,\r\n stack: error.stack\r\n };\r\n }\r\n }\r\n};","import { Transport } from './transport';\r\nimport { Context } from './context';\r\nimport { SenzorOptions, ActiveTrace } from './types';\r\nimport { randomUUID } from 'crypto';\r\nimport { instrumentHttp, instrumentFetch } from '../instrumentation/http';\r\nimport { instrumentMongo } from '../instrumentation/mongo';\r\nimport { instrumentPg } from '../instrumentation/pg';\r\n\r\nexport class SenzorClient {\r\n private transport: Transport | null = null;\r\n private options: SenzorOptions | null = null;\r\n private isInstrumented = false;\r\n\r\n public init(options: SenzorOptions) {\r\n if (!options.apiKey) {\r\n console.warn('[Senzor] API Key missing. SDK disabled.');\r\n return;\r\n }\r\n this.options = options;\r\n const endpoint = options.endpoint || 'https://api.senzor.dev/api/ingest/apm';\r\n const debug = options.debug || false;\r\n\r\n this.transport = new Transport({ ...options, endpoint });\r\n\r\n if (!this.isInstrumented) {\r\n try { instrumentHttp(endpoint, debug); } catch (e) { }\r\n try { instrumentFetch(endpoint, debug); } catch (e) { }\r\n try { instrumentMongo(debug); } catch (e) { }\r\n try { instrumentPg(); } catch (e) { }\r\n\r\n this.isInstrumented = true;\r\n if (debug) console.log('[Senzor] Auto-instrumentation enabled');\r\n }\r\n }\r\n\r\n public startTrace<T>(data: Partial<ActiveTrace['data']>, next: () => T): T {\r\n if (!this.transport) return next();\r\n const trace: ActiveTrace = {\r\n id: randomUUID(),\r\n startTime: performance.now(),\r\n data: data,\r\n spans: []\r\n };\r\n return Context.run(trace, next);\r\n }\r\n\r\n public endTrace(status: number, extraData: any = {}) {\r\n const trace = Context.current();\r\n if (!trace || !this.transport) return;\r\n\r\n const duration = performance.now() - trace.startTime;\r\n\r\n const payload = {\r\n traceId: trace.id,\r\n ...trace.data,\r\n ...extraData,\r\n status,\r\n duration,\r\n spans: trace.spans,\r\n error: trace.error, // Include Error if captured\r\n timestamp: new Date().toISOString()\r\n };\r\n\r\n this.transport.add(payload);\r\n }\r\n\r\n // --- NEW: Capture Exception ---\r\n public captureError(error: unknown) {\r\n if (error instanceof Error) {\r\n Context.setError(error);\r\n } else if (typeof error === 'string') {\r\n Context.setError(new Error(error));\r\n }\r\n }\r\n\r\n // ... (manual track, startSpan, flush remain same) ...\r\n public track(data: any) { this.transport?.add({ traceId: randomUUID(), ...data, spans: [], timestamp: new Date().toISOString() }); }\r\n\r\n public startSpan(name: string, type: 'db' | 'http' | 'function' | 'custom' = 'custom') {\r\n const trace = Context.current();\r\n if (!trace) return { end: () => { } };\r\n const startTime = performance.now() - trace.startTime;\r\n const spanStartAbs = performance.now();\r\n return { end: (meta?: any, status?: number) => { Context.addSpan({ name, type, startTime, duration: performance.now() - spanStartAbs, status, meta }); } };\r\n }\r\n\r\n public async flush() { if (this.transport) await this.transport.flush(); }\r\n}\r\n\r\nexport const client = new SenzorClient();","import http from 'http';\r\nimport https from 'https';\r\nimport { URL } from 'url';\r\nimport { Context } from '../core/context';\r\n\r\nconst shimmer = (module: any, methodName: string, wrapper: (original: Function) => Function) => {\r\n if (!module[methodName]) return;\r\n const original = module[methodName];\r\n module[methodName] = wrapper(original);\r\n};\r\n\r\n// --- Native Fetch Instrumentation (Node 18+) ---\r\nexport const instrumentFetch = (ingestUrl: string, debug = false) => {\r\n if (!globalThis.fetch) return;\r\n\r\n let ingestHost = '';\r\n try { ingestHost = new URL(ingestUrl).hostname; } catch (e) { }\r\n\r\n const originalFetch = globalThis.fetch;\r\n\r\n // @ts-ignore\r\n globalThis.fetch = async (input: RequestInfo | URL, init?: RequestInit) => {\r\n // 1. Extract URL\r\n let urlStr = '';\r\n if (typeof input === 'string') urlStr = input;\r\n else if (input instanceof URL) urlStr = input.toString();\r\n else if (input && input.url) urlStr = input.url; // Request object\r\n\r\n // 2. Infinite Loop Guard\r\n if (ingestHost && urlStr.includes(ingestHost)) {\r\n return originalFetch(input, init);\r\n }\r\n\r\n // 3. Context Check\r\n const trace = Context.current();\r\n if (!trace) {\r\n return originalFetch(input, init);\r\n }\r\n\r\n // 4. Start Span\r\n const method = (init?.method || 'GET').toUpperCase();\r\n const startTime = performance.now() - trace.startTime;\r\n const spanStartAbs = performance.now();\r\n let hostname = 'unknown';\r\n try { hostname = new URL(urlStr).hostname; } catch (e) { }\r\n\r\n if (debug) console.log(`[Senzor] Tracking Fetch: ${method} ${hostname}`);\r\n\r\n try {\r\n const response = await originalFetch(input, init);\r\n\r\n // 5. End Span\r\n const duration = performance.now() - spanStartAbs;\r\n Context.addSpan({\r\n name: `${method} ${hostname}`,\r\n type: 'http',\r\n startTime,\r\n duration,\r\n status: response.status,\r\n meta: { url: urlStr, method, library: 'fetch' }\r\n });\r\n\r\n return response;\r\n } catch (err: any) {\r\n const duration = performance.now() - spanStartAbs;\r\n Context.addSpan({\r\n name: `${method} ${hostname}`,\r\n type: 'http',\r\n startTime,\r\n duration,\r\n status: 500,\r\n meta: { error: err.message, url: urlStr, library: 'fetch' }\r\n });\r\n throw err;\r\n }\r\n };\r\n};\r\n\r\n// --- Standard HTTP/HTTPS Instrumentation ---\r\nexport const instrumentHttp = (ingestUrl: string, debug = false) => {\r\n let ingestHost = '';\r\n try {\r\n ingestHost = new URL(ingestUrl).hostname;\r\n } catch (e) { }\r\n\r\n const requestWrapper = (original: Function) => {\r\n return function (this: any, ...args: any[]) {\r\n let options: any = {};\r\n let urlStr = '';\r\n\r\n if (typeof args[0] === 'string' || args[0] instanceof URL) {\r\n urlStr = args[0].toString();\r\n if (typeof args[1] === 'object' && args[1] !== null) options = args[1];\r\n } else {\r\n options = args[0] || {};\r\n const protocol = options.protocol || (options.port === 443 ? 'https:' : 'http:');\r\n const host = options.hostname || options.host || 'localhost';\r\n const path = options.path || '/';\r\n urlStr = `${protocol}//${host}${path}`;\r\n }\r\n\r\n if (ingestHost && (urlStr.includes(ingestHost) || (options.hostname && options.hostname.includes(ingestHost)))) {\r\n return original.apply(this, args);\r\n }\r\n\r\n const trace = Context.current();\r\n if (!trace) return original.apply(this, args);\r\n\r\n const method = (options.method || 'GET').toUpperCase();\r\n const startTime = performance.now() - trace.startTime;\r\n const spanStartAbs = performance.now();\r\n let hostname = 'unknown';\r\n try { hostname = new URL(urlStr).hostname; } catch (e) { hostname = options.hostname || 'unknown'; }\r\n\r\n const req = original.apply(this, args);\r\n\r\n const captureSpan = (res: any, error?: Error) => {\r\n const duration = performance.now() - spanStartAbs;\r\n Context.addSpan({\r\n name: `${method} ${hostname}`,\r\n type: 'http',\r\n startTime,\r\n duration,\r\n status: error ? 500 : res?.statusCode || 0,\r\n meta: { url: urlStr, method, library: 'http', error: error ? error.message : undefined }\r\n });\r\n };\r\n\r\n req.on('response', (res: any) => {\r\n res.once('end', () => captureSpan(res));\r\n res.once('error', (err: Error) => captureSpan(res, err));\r\n });\r\n\r\n req.on('error', (err: Error) => captureSpan(null, err));\r\n\r\n return req;\r\n };\r\n };\r\n\r\n shimmer(http, 'request', requestWrapper);\r\n shimmer(http, 'get', requestWrapper);\r\n shimmer(https, 'request', requestWrapper);\r\n shimmer(https, 'get', requestWrapper);\r\n};","import { Context } from '../core/context';\r\n\r\nexport const instrumentMongo = (debug = false) => {\r\n try {\r\n const mongodb = require('mongodb');\r\n const Collection = mongodb.Collection;\r\n\r\n // Attempt to get Cursor classes\r\n // Note: The location of these classes varies by driver version, \r\n // checking common locations\r\n const FindCursor = mongodb.FindCursor || require('mongodb/lib/cursor/find_cursor').FindCursor;\r\n const AggregationCursor = mongodb.AggregationCursor || require('mongodb/lib/cursor/aggregation_cursor').AggregationCursor;\r\n\r\n if (debug) console.log('[Senzor] Instrumenting MongoDB (Collection + Cursors)...');\r\n\r\n // --- Helper to Record Span ---\r\n const recordSpan = (name: string, operation: string, collection: string, startAbs: number, traceStart: number, err?: Error) => {\r\n const duration = performance.now() - startAbs;\r\n Context.addSpan({\r\n name: `MongoDB ${name}`,\r\n type: 'db',\r\n startTime: performance.now() - traceStart - duration, // Adjust start time to when op actually started\r\n duration,\r\n status: err ? 500 : 0,\r\n meta: { collection, operation, error: err ? err.message : undefined }\r\n });\r\n if (debug) console.log(`[Senzor] Captured Mongo: ${name} (${duration.toFixed(2)}ms)`);\r\n };\r\n\r\n // --- 1. Instrument Immediate Operations (Insert/Update/Delete) ---\r\n const immediateMethods = ['insertOne', 'insertMany', 'updateOne', 'updateMany', 'deleteOne', 'deleteMany', 'countDocuments'];\r\n\r\n immediateMethods.forEach((method) => {\r\n if (!Collection.prototype[method]) return;\r\n const original = Collection.prototype[method];\r\n\r\n Collection.prototype[method] = function (...args: any[]) {\r\n const trace = Context.current();\r\n if (!trace) return original.apply(this, args);\r\n\r\n const spanStartAbs = performance.now();\r\n const traceStart = trace.startTime;\r\n const collName = this.collectionName;\r\n\r\n try {\r\n const result = original.apply(this, args);\r\n if (result && typeof result.then === 'function') {\r\n return result.then(\r\n (res: any) => { recordSpan(method, method, collName, spanStartAbs, traceStart); return res; },\r\n (err: any) => { recordSpan(method, method, collName, spanStartAbs, traceStart, err); throw err; }\r\n );\r\n }\r\n return result;\r\n } catch (err: any) {\r\n recordSpan(method, method, collName, spanStartAbs, traceStart, err);\r\n throw err;\r\n }\r\n };\r\n });\r\n\r\n // --- 2. Instrument Cursor Execution (find -> toArray) ---\r\n const patchCursor = (CursorClass: any, label: string) => {\r\n if (!CursorClass || !CursorClass.prototype.toArray) return;\r\n\r\n const originalToArray = CursorClass.prototype.toArray;\r\n\r\n CursorClass.prototype.toArray = function (...args: any[]) {\r\n const trace = Context.current();\r\n // Cursors are often created in context but executed later. \r\n // We check context at execution time.\r\n if (!trace) return originalToArray.apply(this, args);\r\n\r\n const spanStartAbs = performance.now();\r\n const traceStart = trace.startTime;\r\n // Attempt to get collection name from cursor internal state\r\n const collName = this.namespace?.collection || 'unknown';\r\n\r\n const onSuccess = (res: any) => {\r\n recordSpan(label, label, collName, spanStartAbs, traceStart);\r\n return res;\r\n };\r\n const onError = (err: any) => {\r\n recordSpan(label, label, collName, spanStartAbs, traceStart, err);\r\n throw err;\r\n };\r\n\r\n try {\r\n const result = originalToArray.apply(this, args);\r\n if (result && typeof result.then === 'function') {\r\n return result.then(onSuccess, onError);\r\n }\r\n return onSuccess(result);\r\n } catch (e) {\r\n onError(e);\r\n }\r\n };\r\n };\r\n\r\n patchCursor(FindCursor, 'find');\r\n patchCursor(AggregationCursor, 'aggregate');\r\n\r\n } catch (e: any) {\r\n if (debug) console.warn('[Senzor] MongoDB instrumentation warning:', e.message);\r\n }\r\n};","import { Context } from '../core/context';\r\n\r\n// Simple shim for 'pg' library\r\nexport const instrumentPg = () => {\r\n try {\r\n // Try to require pg (it might not be installed by user)\r\n const pg = require('pg');\r\n const originalQuery = pg.Client.prototype.query;\r\n\r\n pg.Client.prototype.query = function (...args: any[]) {\r\n const trace = Context.current();\r\n if (!trace) return originalQuery.apply(this, args);\r\n\r\n const startTime = performance.now() - trace.startTime;\r\n const spanStartAbs = performance.now();\r\n\r\n // Extract SQL (first arg usually string or config object)\r\n const sql = typeof args[0] === 'string' ? args[0] : args[0].text;\r\n\r\n // Wrap callback if present, or handle Promise\r\n const result = originalQuery.apply(this, args);\r\n\r\n if (result && typeof result.then === 'function') {\r\n return result.then((res: any) => {\r\n const duration = performance.now() - spanStartAbs;\r\n Context.addSpan({\r\n name: 'Postgres Query',\r\n type: 'db',\r\n startTime,\r\n duration,\r\n meta: { query: sql }\r\n });\r\n return res;\r\n });\r\n }\r\n return result;\r\n };\r\n } catch (e) {\r\n // User doesn't use pg, ignore\r\n }\r\n};","import { client } from '../core/client';\r\n\r\n// 1. Request Handler (Place before routes)\r\nexport const expressMiddleware = () => {\r\n return (req: any, res: any, next: () => void) => {\r\n client.startTrace({\r\n method: req.method,\r\n path: req.originalUrl || req.url,\r\n ip: req.ip || req.socket?.remoteAddress,\r\n userAgent: req.headers['user-agent'],\r\n }, () => {\r\n\r\n // Auto-detect status code on finish\r\n res.once('finish', () => {\r\n try {\r\n let route = 'UNKNOWN';\r\n // Express populates req.route only if a route matched\r\n if (req.route && req.route.path) {\r\n route = (req.baseUrl || '') + req.route.path;\r\n } else if (res.statusCode === 404) {\r\n route = 'Not Found';\r\n } else {\r\n route = req.path || 'Wildcard';\r\n }\r\n\r\n client.endTrace(res.statusCode, { route });\r\n } catch (e) { /* Fail open */ }\r\n });\r\n\r\n next();\r\n });\r\n };\r\n};\r\n\r\n// 2. Error Handler (Place after routes)\r\n// This is required in Express to capture the actual Error Object (Stack Trace)\r\nexport const expressErrorHandler = () => {\r\n return (err: any, req: any, res: any, next: (err?: any) => void) => {\r\n\r\n // 1. Capture the exception context\r\n client.captureError(err);\r\n\r\n // 2. Pass it to the next error handler (don't swallow it)\r\n next(err);\r\n };\r\n};","/**\r\n * Heuristic URL Normalizer\r\n * Converts raw paths with IDs into generic patterns to prevent high cardinality.\r\n * Example: /users/123/orders/abc-def -> /users/:id/orders/:uuid\r\n */\r\nexport const normalizePath = (path: string): string => {\r\n if (!path || path === '/') return '/';\r\n\r\n return path\r\n // Replace UUIDs (long alphanumeric strings)\r\n .replace(\r\n /[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}/g,\r\n ':uuid'\r\n )\r\n // Replace MongoDB ObjectIds (24 hex chars)\r\n .replace(/[0-9a-fA-F]{24}/g, ':objectId')\r\n // Replace pure numeric IDs (e.g., /123)\r\n .replace(/\\/(\\d+)(?=\\/|$)/g, '/:id')\r\n // Remove query strings\r\n .split('?')[0];\r\n};\r\n\r\n/**\r\n * Tries to extract route from Framework internals, falls back to heuristic\r\n */\r\nexport const getRoute = (req: any, fallbackPath: string): string => {\r\n // Express / Connect\r\n if (req.route && req.route.path) {\r\n return (req.baseUrl || '') + req.route.path;\r\n }\r\n\r\n // H3 / Nitro (Nuxt)\r\n if (req.context && req.context.matchedRoute) {\r\n return req.context.matchedRoute.path;\r\n }\r\n\r\n // Fastify\r\n if (req.routerPath) {\r\n return req.routerPath;\r\n }\r\n\r\n // Fallback: Heuristic Normalization\r\n return normalizePath(fallbackPath);\r\n};","import { client } from '../core/client';\r\nimport { getRoute } from '../core/normalizer';\r\n\r\ntype EventHandler = (event: any) => any;\r\n\r\nexport const wrapH3 = (handler: EventHandler) => {\r\n return (event: any) => {\r\n const req = event.node.req;\r\n const path = req.originalUrl || req.url || '/';\r\n\r\n return client.startTrace({\r\n method: req.method || 'GET',\r\n path: path,\r\n ip: req.headers['x-forwarded-for'] || req.socket?.remoteAddress,\r\n userAgent: req.headers['user-agent'],\r\n }, async () => {\r\n try {\r\n const response = await handler(event);\r\n let status = 200;\r\n if (event.node.res.statusCode) status = event.node.res.statusCode;\r\n if (response && response.statusCode) status = response.statusCode;\r\n\r\n client.endTrace(status, { route: getRoute(event, path) });\r\n return response;\r\n } catch (err: any) {\r\n // AUTOMATIC ERROR CAPTURE\r\n client.captureError(err);\r\n\r\n const status = err.statusCode || err.status || 500;\r\n client.endTrace(status, { route: getRoute(event, path) });\r\n throw err;\r\n }\r\n });\r\n };\r\n};","import { client } from '../core/client';\r\nimport { normalizePath } from '../core/normalizer';\r\n\r\n// --- App Router Wrapper ---\r\nexport const wrapNextRoute = (handler: Function) => {\r\n return async (req: Request | any, context?: any) => {\r\n const url = req.url ? new URL(req.url) : { pathname: '/' };\r\n const method = req.method || 'GET';\r\n const ua = req.headers.get ? req.headers.get('user-agent') : undefined;\r\n const ip = req.headers.get ? req.headers.get('x-forwarded-for') : undefined;\r\n\r\n return client.startTrace({\r\n method,\r\n path: url.pathname,\r\n userAgent: ua,\r\n ip: ip\r\n }, async () => {\r\n try {\r\n const response = await handler(req, context);\r\n const status = response?.status || 200;\r\n client.endTrace(status, { route: normalizePath(url.pathname) });\r\n return response;\r\n } catch (err: any) {\r\n // AUTOMATIC ERROR CAPTURE\r\n client.captureError(err);\r\n client.endTrace(500, { route: normalizePath(url.pathname) });\r\n throw err; // Re-throw so Next.js handles the error page\r\n }\r\n });\r\n };\r\n};\r\n\r\n// --- Pages Router Wrapper ---\r\nexport const wrapNextPages = (handler: Function) => {\r\n return async (req: any, res: any) => {\r\n const path = req.url ? req.url.split('?')[0] : '/';\r\n\r\n return client.startTrace({\r\n method: req.method || 'GET',\r\n path: path,\r\n userAgent: req.headers['user-agent'],\r\n ip: req.headers['x-forwarded-for'] || req.socket?.remoteAddress,\r\n }, async () => {\r\n\r\n const done = () => {\r\n client.endTrace(res.statusCode || 200, { route: normalizePath(path) });\r\n };\r\n\r\n res.once('finish', done);\r\n res.once('close', done);\r\n\r\n try {\r\n return await handler(req, res);\r\n } catch (e: any) {\r\n // AUTOMATIC ERROR CAPTURE\r\n client.captureError(e);\r\n // Note: In Pages dir, we rely on 'finish' listener above to close trace, \r\n // but capturing here ensures the error data is attached.\r\n throw e;\r\n }\r\n });\r\n };\r\n};","import { client } from '../core/client';\r\nimport { SenzorOptions } from '../core/types';\r\n\r\nexport const senzorPlugin = (fastify: any, options: SenzorOptions, done: Function) => {\r\n\r\n if (options && options.apiKey) {\r\n client.init(options);\r\n }\r\n\r\n // 1. Start Trace\r\n fastify.addHook('onRequest', (request: any, reply: any, next: Function) => {\r\n // FIX: Wrap next in a closure to satisfy TS types\r\n client.startTrace({\r\n method: request.method,\r\n path: request.raw.url || request.url,\r\n ip: request.ip,\r\n userAgent: request.headers['user-agent']\r\n }, () => next());\r\n });\r\n\r\n // 2. Capture Errors\r\n fastify.addHook('onError', (request: any, reply: any, error: any, next: Function) => {\r\n client.captureError(error);\r\n next();\r\n });\r\n\r\n // 3. End Trace\r\n fastify.addHook('onResponse', (request: any, reply: any, next: Function) => {\r\n const route = request.routeOptions?.url || request.routerPath || 'UNKNOWN';\r\n client.endTrace(reply.statusCode, { route });\r\n next();\r\n });\r\n\r\n done();\r\n};"],"mappings":"0jBAAA,IAAAA,GAAA,GAAAC,EAAAD,GAAA,YAAAE,EAAA,YAAAC,IAAA,eAAAC,EAAAJ,ICEO,IAAMK,EAAN,KAAgB,CAIrB,YAAoBC,EAAuB,CAAvB,YAAAA,EAHpB,KAAQ,MAAe,CAAC,EACxB,KAAQ,MAA+B,KAGjC,OAAO,YAAgB,MACzB,KAAK,MAAQ,YAAY,IAAM,KAAK,MAAM,EAAGA,EAAO,eAAiB,GAAK,EACtE,KAAK,OAAS,OAAO,KAAK,MAAM,OAAU,YAC5C,KAAK,MAAM,MAAM,EAGvB,CAEO,IAAIC,EAAY,CACrB,KAAK,MAAM,KAAKA,CAAK,EACjB,KAAK,MAAM,SAAW,KAAK,OAAO,WAAa,MACjD,KAAK,MAAM,CAEf,CAEA,MAAa,OAAQ,CACnB,GAAI,KAAK,MAAM,SAAW,EAAG,OAE7B,IAAMC,EAAQ,CAAC,GAAG,KAAK,KAAK,EAC5B,KAAK,MAAQ,CAAC,EAEd,GAAI,CAEF,MAAM,MAAM,KAAK,OAAO,UAAY,wCAAyC,CAC3E,OAAQ,OACR,QAAS,CACP,eAAgB,mBAChB,oBAAqB,KAAK,OAAO,MACnC,EACA,KAAM,KAAK,UAAUA,CAAK,EAC1B,UAAW,EACb,CAAC,EAEG,KAAK,OAAO,OAAO,QAAQ,IAAI,oBAAoBA,EAAM,MAAM,SAAS,CAC9E,OAASC,EAAK,CACR,KAAK,OAAO,OAAO,QAAQ,MAAM,4BAA6BA,CAAG,CAEvE,CACF,CACF,EC9CA,IAAAC,EAAkC,uBAGrBC,EAAU,IAAI,oBAEdC,EAAU,CACrB,IAAK,CAAIC,EAAoBC,IACpBH,EAAQ,IAAIE,EAAOC,CAAE,EAG9B,QAAS,IACAH,EAAQ,SAAS,EAG1B,QAAUI,GAAc,CACtB,IAAMC,EAAQL,EAAQ,SAAS,EAC3BK,GACFA,EAAM,MAAM,KAAKD,CAAI,CAEzB,EAGA,SAAWE,GAAiB,CAC1B,IAAMD,EAAQL,EAAQ,SAAS,EAC3BK,IACFA,EAAM,MAAQ,CACZ,KAAMC,EAAM,KACZ,QAASA,EAAM,QACf,MAAOA,EAAM,KACf,EAEJ,CACF,EC7BA,IAAAC,EAA2B,kBCH3B,IAAAC,EAAiB,mBACjBC,EAAkB,oBAClBC,EAAoB,eAGpB,IAAMC,EAAU,CAACC,EAAaC,EAAoBC,IAA8C,CAC9F,GAAI,CAACF,EAAOC,CAAU,EAAG,OACzB,IAAME,EAAWH,EAAOC,CAAU,EAClCD,EAAOC,CAAU,EAAIC,EAAQC,CAAQ,CACvC,EAGaC,EAAkB,CAACC,EAAmBC,EAAQ,KAAU,CACnE,GAAI,CAAC,WAAW,MAAO,OAEvB,IAAIC,EAAa,GACjB,GAAI,CAAEA,EAAa,IAAI,MAAIF,CAAS,EAAE,QAAU,MAAY,CAAE,CAE9D,IAAMG,EAAgB,WAAW,MAGjC,WAAW,MAAQ,MAAOC,EAA0BC,IAAuB,CAEzE,IAAIC,EAAS,GAMb,GALI,OAAOF,GAAU,SAAUE,EAASF,EAC/BA,aAAiB,MAAKE,EAASF,EAAM,SAAS,EAC9CA,GAASA,EAAM,MAAKE,EAASF,EAAM,KAGxCF,GAAcI,EAAO,SAASJ,CAAU,EAC1C,OAAOC,EAAcC,EAAOC,CAAI,EAIlC,IAAME,EAAQC,EAAQ,QAAQ,EAC9B,GAAI,CAACD,EACH,OAAOJ,EAAcC,EAAOC,CAAI,EAIlC,IAAMI,GAAUJ,GAAM,QAAU,OAAO,YAAY,EAC7CK,EAAY,YAAY,IAAI,EAAIH,EAAM,UACtCI,EAAe,YAAY,IAAI,EACjCC,EAAW,UACf,GAAI,CAAEA,EAAW,IAAI,MAAIN,CAAM,EAAE,QAAU,MAAY,CAAE,CAErDL,GAAO,QAAQ,IAAI,4BAA4BQ,CAAM,IAAIG,CAAQ,EAAE,EAEvE,GAAI,CACF,IAAMC,EAAW,MAAMV,EAAcC,EAAOC,CAAI,EAG1CS,EAAW,YAAY,IAAI,EAAIH,EACrC,OAAAH,EAAQ,QAAQ,CACd,KAAM,GAAGC,CAAM,IAAIG,CAAQ,GAC3B,KAAM,OACN,UAAAF,EACA,SAAAI,EACA,OAAQD,EAAS,OACjB,KAAM,CAAE,IAAKP,EAAQ,OAAAG,EAAQ,QAAS,OAAQ,CAChD,CAAC,EAEMI,CACT,OAASE,EAAU,CACjB,IAAMD,EAAW,YAAY,IAAI,EAAIH,EACrC,MAAAH,EAAQ,QAAQ,CACd,KAAM,GAAGC,CAAM,IAAIG,CAAQ,GAC3B,KAAM,OACN,UAAAF,EACA,SAAAI,EACA,OAAQ,IACR,KAAM,CAAE,MAAOC,EAAI,QAAS,IAAKT,EAAQ,QAAS,OAAQ,CAC5D,CAAC,EACKS,CACR,CACF,CACF,EAGaC,EAAiB,CAAChB,EAAmBC,EAAQ,KAAU,CAClE,IAAIC,EAAa,GACjB,GAAI,CACFA,EAAa,IAAI,MAAIF,CAAS,EAAE,QAClC,MAAY,CAAE,CAEd,IAAMiB,EAAkBnB,GACf,YAAwBoB,EAAa,CAC1C,IAAIC,EAAe,CAAC,EAChBb,EAAS,GAEb,GAAI,OAAOY,EAAK,CAAC,GAAM,UAAYA,EAAK,CAAC,YAAa,MACpDZ,EAASY,EAAK,CAAC,EAAE,SAAS,EACtB,OAAOA,EAAK,CAAC,GAAM,UAAYA,EAAK,CAAC,IAAM,OAAMC,EAAUD,EAAK,CAAC,OAChE,CACLC,EAAUD,EAAK,CAAC,GAAK,CAAC,EACtB,IAAME,EAAWD,EAAQ,WAAaA,EAAQ,OAAS,IAAM,SAAW,SAClEE,EAAOF,EAAQ,UAAYA,EAAQ,MAAQ,YAC3CG,EAAOH,EAAQ,MAAQ,IAC7Bb,EAAS,GAAGc,CAAQ,KAAKC,CAAI,GAAGC,CAAI,EACtC,CAEA,GAAIpB,IAAeI,EAAO,SAASJ,CAAU,GAAMiB,EAAQ,UAAYA,EAAQ,SAAS,SAASjB,CAAU,GACzG,OAAOJ,EAAS,MAAM,KAAMoB,CAAI,EAGlC,IAAMX,EAAQC,EAAQ,QAAQ,EAC9B,GAAI,CAACD,EAAO,OAAOT,EAAS,MAAM,KAAMoB,CAAI,EAE5C,IAAMT,GAAUU,EAAQ,QAAU,OAAO,YAAY,EAC/CT,EAAY,YAAY,IAAI,EAAIH,EAAM,UACtCI,EAAe,YAAY,IAAI,EACjCC,EAAW,UACf,GAAI,CAAEA,EAAW,IAAI,MAAIN,CAAM,EAAE,QAAU,MAAY,CAAEM,EAAWO,EAAQ,UAAY,SAAW,CAEnG,IAAMI,EAAMzB,EAAS,MAAM,KAAMoB,CAAI,EAE/BM,EAAc,CAACC,EAAUC,IAAkB,CAC/C,IAAMZ,EAAW,YAAY,IAAI,EAAIH,EACrCH,EAAQ,QAAQ,CACd,KAAM,GAAGC,CAAM,IAAIG,CAAQ,GAC3B,KAAM,OACN,UAAAF,EACA,SAAAI,EACA,OAAQY,EAAQ,IAAMD,GAAK,YAAc,EACzC,KAAM,CAAE,IAAKnB,EAAQ,OAAAG,EAAQ,QAAS,OAAQ,MAAOiB,EAAQA,EAAM,QAAU,MAAU,CACzF,CAAC,CACH,EAEA,OAAAH,EAAI,GAAG,WAAaE,GAAa,CAC/BA,EAAI,KAAK,MAAO,IAAMD,EAAYC,CAAG,CAAC,EACtCA,EAAI,KAAK,QAAUV,GAAeS,EAAYC,EAAKV,CAAG,CAAC,CACzD,CAAC,EAEDQ,EAAI,GAAG,QAAUR,GAAeS,EAAY,KAAMT,CAAG,CAAC,EAE/CQ,CACT,EAGF7B,EAAQ,EAAAiC,QAAM,UAAWV,CAAc,EACvCvB,EAAQ,EAAAiC,QAAM,MAAOV,CAAc,EACnCvB,EAAQ,EAAAkC,QAAO,UAAWX,CAAc,EACxCvB,EAAQ,EAAAkC,QAAO,MAAOX,CAAc,CACtC,EC7IO,IAAMY,EAAkB,CAACC,EAAQ,KAAU,CAChD,GAAI,CACF,IAAMC,EAAU,QAAQ,SAAS,EAC3BC,EAAaD,EAAQ,WAKrBE,EAAaF,EAAQ,YAAc,QAAQ,gCAAgC,EAAE,WAC7EG,EAAoBH,EAAQ,mBAAqB,QAAQ,uCAAuC,EAAE,kBAEpGD,GAAO,QAAQ,IAAI,0DAA0D,EAGjF,IAAMK,EAAa,CAACC,EAAcC,EAAmBC,EAAoBC,EAAkBC,EAAoBC,IAAgB,CAC7H,IAAMC,EAAW,YAAY,IAAI,EAAIH,EACrCI,EAAQ,QAAQ,CACd,KAAM,WAAWP,CAAI,GACrB,KAAM,KACN,UAAW,YAAY,IAAI,EAAII,EAAaE,EAC5C,SAAAA,EACA,OAAQD,EAAM,IAAM,EACpB,KAAM,CAAE,WAAAH,EAAY,UAAAD,EAAW,MAAOI,EAAMA,EAAI,QAAU,MAAU,CACtE,CAAC,EACGX,GAAO,QAAQ,IAAI,4BAA4BM,CAAI,KAAKM,EAAS,QAAQ,CAAC,CAAC,KAAK,CACtF,EAGyB,CAAC,YAAa,aAAc,YAAa,aAAc,YAAa,aAAc,gBAAgB,EAE1G,QAASE,GAAW,CACnC,GAAI,CAACZ,EAAW,UAAUY,CAAM,EAAG,OACnC,IAAMC,EAAWb,EAAW,UAAUY,CAAM,EAE5CZ,EAAW,UAAUY,CAAM,EAAI,YAAaE,EAAa,CACvD,IAAMC,EAAQJ,EAAQ,QAAQ,EAC9B,GAAI,CAACI,EAAO,OAAOF,EAAS,MAAM,KAAMC,CAAI,EAE5C,IAAME,EAAe,YAAY,IAAI,EAC/BR,EAAaO,EAAM,UACnBE,EAAW,KAAK,eAEtB,GAAI,CACF,IAAMC,EAASL,EAAS,MAAM,KAAMC,CAAI,EACxC,OAAII,GAAU,OAAOA,EAAO,MAAS,WAC5BA,EAAO,KACXC,IAAehB,EAAWS,EAAQA,EAAQK,EAAUD,EAAcR,CAAU,EAAUW,GACtFV,GAAa,CAAE,MAAAN,EAAWS,EAAQA,EAAQK,EAAUD,EAAcR,EAAYC,CAAG,EAASA,CAAK,CAClG,EAEKS,CACT,OAAST,EAAU,CACjB,MAAAN,EAAWS,EAAQA,EAAQK,EAAUD,EAAcR,EAAYC,CAAG,EAC5DA,CACR,CACF,CACF,CAAC,EAGD,IAAMW,EAAc,CAACC,EAAkBC,IAAkB,CACvD,GAAI,CAACD,GAAe,CAACA,EAAY,UAAU,QAAS,OAEpD,IAAME,EAAkBF,EAAY,UAAU,QAE9CA,EAAY,UAAU,QAAU,YAAaP,EAAa,CACxD,IAAMC,EAAQJ,EAAQ,QAAQ,EAG9B,GAAI,CAACI,EAAO,OAAOQ,EAAgB,MAAM,KAAMT,CAAI,EAEnD,IAAME,EAAe,YAAY,IAAI,EAC/BR,EAAaO,EAAM,UAEnBE,EAAW,KAAK,WAAW,YAAc,UAEzCO,EAAaL,IACjBhB,EAAWmB,EAAOA,EAAOL,EAAUD,EAAcR,CAAU,EACpDW,GAEHM,EAAWhB,GAAa,CAC5B,MAAAN,EAAWmB,EAAOA,EAAOL,EAAUD,EAAcR,EAAYC,CAAG,EAC1DA,CACR,EAEA,GAAI,CACF,IAAMS,EAASK,EAAgB,MAAM,KAAMT,CAAI,EAC/C,OAAII,GAAU,OAAOA,EAAO,MAAS,WAC5BA,EAAO,KAAKM,EAAWC,CAAO,EAEhCD,EAAUN,CAAM,CACzB,OAASQ,EAAG,CACVD,EAAQC,CAAC,CACX,CACF,CACF,EAEAN,EAAYnB,EAAY,MAAM,EAC9BmB,EAAYlB,EAAmB,WAAW,CAE5C,OAASwB,EAAQ,CACX5B,GAAO,QAAQ,KAAK,4CAA6C4B,EAAE,OAAO,CAChF,CACF,ECrGO,IAAMC,EAAe,IAAM,CAChC,GAAI,CAEF,IAAMC,EAAK,QAAQ,IAAI,EACjBC,EAAgBD,EAAG,OAAO,UAAU,MAE1CA,EAAG,OAAO,UAAU,MAAQ,YAAaE,EAAa,CACpD,IAAMC,EAAQC,EAAQ,QAAQ,EAC9B,GAAI,CAACD,EAAO,OAAOF,EAAc,MAAM,KAAMC,CAAI,EAEjD,IAAMG,EAAY,YAAY,IAAI,EAAIF,EAAM,UACtCG,EAAe,YAAY,IAAI,EAG/BC,EAAM,OAAOL,EAAK,CAAC,GAAM,SAAWA,EAAK,CAAC,EAAIA,EAAK,CAAC,EAAE,KAGtDM,EAASP,EAAc,MAAM,KAAMC,CAAI,EAE7C,OAAIM,GAAU,OAAOA,EAAO,MAAS,WAC5BA,EAAO,KAAMC,GAAa,CAC/B,IAAMC,EAAW,YAAY,IAAI,EAAIJ,EACrC,OAAAF,EAAQ,QAAQ,CACd,KAAM,iBACN,KAAM,KACN,UAAAC,EACA,SAAAK,EACA,KAAM,CAAE,MAAOH,CAAI,CACrB,CAAC,EACME,CACT,CAAC,EAEID,CACT,CACF,MAAY,CAEZ,CACF,EHhCO,IAAMG,EAAN,KAAmB,CAAnB,cACL,KAAQ,UAA8B,KACtC,KAAQ,QAAgC,KACxC,KAAQ,eAAiB,GAElB,KAAKC,EAAwB,CAClC,GAAI,CAACA,EAAQ,OAAQ,CACnB,QAAQ,KAAK,yCAAyC,EACtD,MACF,CACA,KAAK,QAAUA,EACf,IAAMC,EAAWD,EAAQ,UAAY,wCAC/BE,EAAQF,EAAQ,OAAS,GAI/B,GAFA,KAAK,UAAY,IAAIG,EAAU,CAAE,GAAGH,EAAS,SAAAC,CAAS,CAAC,EAEnD,CAAC,KAAK,eAAgB,CACxB,GAAI,CAAEG,EAAeH,EAAUC,CAAK,CAAG,MAAY,CAAE,CACrD,GAAI,CAAEG,EAAgBJ,EAAUC,CAAK,CAAG,MAAY,CAAE,CACtD,GAAI,CAAEI,EAAgBJ,CAAK,CAAG,MAAY,CAAE,CAC5C,GAAI,CAAEK,EAAa,CAAG,MAAY,CAAE,CAEpC,KAAK,eAAiB,GAClBL,GAAO,QAAQ,IAAI,uCAAuC,CAChE,CACF,CAEO,WAAcM,EAAoCC,EAAkB,CACzE,GAAI,CAAC,KAAK,UAAW,OAAOA,EAAK,EACjC,IAAMC,EAAqB,CACzB,MAAI,cAAW,EACf,UAAW,YAAY,IAAI,EAC3B,KAAMF,EACN,MAAO,CAAC,CACV,EACA,OAAOG,EAAQ,IAAID,EAAOD,CAAI,CAChC,CAEO,SAASG,EAAgBC,EAAiB,CAAC,EAAG,CACnD,IAAMH,EAAQC,EAAQ,QAAQ,EAC9B,GAAI,CAACD,GAAS,CAAC,KAAK,UAAW,OAE/B,IAAMI,EAAW,YAAY,IAAI,EAAIJ,EAAM,UAErCK,EAAU,CACd,QAASL,EAAM,GACf,GAAGA,EAAM,KACT,GAAGG,EACH,OAAAD,EACA,SAAAE,EACA,MAAOJ,EAAM,MACb,MAAOA,EAAM,MACb,UAAW,IAAI,KAAK,EAAE,YAAY,CACpC,EAEA,KAAK,UAAU,IAAIK,CAAO,CAC5B,CAGO,aAAaC,EAAgB,CAC9BA,aAAiB,MACnBL,EAAQ,SAASK,CAAK,EACb,OAAOA,GAAU,UAC1BL,EAAQ,SAAS,IAAI,MAAMK,CAAK,CAAC,CAErC,CAGO,MAAMR,EAAW,CAAE,KAAK,WAAW,IAAI,CAAE,WAAS,cAAW,EAAG,GAAGA,EAAM,MAAO,CAAC,EAAG,UAAW,IAAI,KAAK,EAAE,YAAY,CAAE,CAAC,CAAG,CAE5H,UAAUS,EAAcC,EAA8C,SAAU,CACrF,IAAMR,EAAQC,EAAQ,QAAQ,EAC9B,GAAI,CAACD,EAAO,MAAO,CAAE,IAAK,IAAM,CAAE,CAAE,EACpC,IAAMS,EAAY,YAAY,IAAI,EAAIT,EAAM,UACtCU,EAAe,YAAY,IAAI,EACrC,MAAO,CAAE,IAAK,CAACC,EAAYT,IAAoB,CAAED,EAAQ,QAAQ,CAAE,KAAAM,EAAM,KAAAC,EAAM,UAAAC,EAAW,SAAU,YAAY,IAAI,EAAIC,EAAc,OAAAR,EAAQ,KAAAS,CAAK,CAAC,CAAG,CAAE,CAC3J,CAEA,MAAa,OAAQ,CAAM,KAAK,WAAW,MAAM,KAAK,UAAU,MAAM,CAAG,CAC3E,EAEaC,EAAS,IAAIvB,EItFnB,IAAMwB,EAAoB,IACxB,CAACC,EAAUC,EAAUC,IAAqB,CAC/CC,EAAO,WAAW,CAChB,OAAQH,EAAI,OACZ,KAAMA,EAAI,aAAeA,EAAI,IAC7B,GAAIA,EAAI,IAAMA,EAAI,QAAQ,cAC1B,UAAWA,EAAI,QAAQ,YAAY,CACrC,EAAG,IAAM,CAGPC,EAAI,KAAK,SAAU,IAAM,CACvB,GAAI,CACF,IAAIG,EAAQ,UAERJ,EAAI,OAASA,EAAI,MAAM,KACzBI,GAASJ,EAAI,SAAW,IAAMA,EAAI,MAAM,KAC/BC,EAAI,aAAe,IAC5BG,EAAQ,YAERA,EAAQJ,EAAI,MAAQ,WAGtBG,EAAO,SAASF,EAAI,WAAY,CAAE,MAAAG,CAAM,CAAC,CAC3C,MAAY,CAAkB,CAChC,CAAC,EAEDF,EAAK,CACP,CAAC,CACH,EAKWG,EAAsB,IAC1B,CAACC,EAAUN,EAAUC,EAAUC,IAA8B,CAGlEC,EAAO,aAAaG,CAAG,EAGvBJ,EAAKI,CAAG,CACV,ECvCK,IAAMC,EAAiBC,GACxB,CAACA,GAAQA,IAAS,IAAY,IAE3BA,EAEJ,QACC,+EACA,OACF,EAEC,QAAQ,mBAAoB,WAAW,EAEvC,QAAQ,mBAAoB,MAAM,EAElC,MAAM,GAAG,EAAE,CAAC,EAMJC,EAAW,CAACC,EAAUC,IAE7BD,EAAI,OAASA,EAAI,MAAM,MACjBA,EAAI,SAAW,IAAMA,EAAI,MAAM,KAIrCA,EAAI,SAAWA,EAAI,QAAQ,aACtBA,EAAI,QAAQ,aAAa,KAI9BA,EAAI,WACCA,EAAI,WAINH,EAAcI,CAAY,ECrC5B,IAAMC,EAAUC,GACbC,GAAe,CACrB,IAAMC,EAAMD,EAAM,KAAK,IACjBE,EAAOD,EAAI,aAAeA,EAAI,KAAO,IAE3C,OAAOE,EAAO,WAAW,CACvB,OAAQF,EAAI,QAAU,MACtB,KAAMC,EACN,GAAID,EAAI,QAAQ,iBAAiB,GAAKA,EAAI,QAAQ,cAClD,UAAWA,EAAI,QAAQ,YAAY,CACrC,EAAG,SAAY,CACb,GAAI,CACF,IAAMG,EAAW,MAAML,EAAQC,CAAK,EAChCK,EAAS,IACb,OAAIL,EAAM,KAAK,IAAI,aAAYK,EAASL,EAAM,KAAK,IAAI,YACnDI,GAAYA,EAAS,aAAYC,EAASD,EAAS,YAEvDD,EAAO,SAASE,EAAQ,CAAE,MAAOC,EAASN,EAAOE,CAAI,CAAE,CAAC,EACjDE,CACT,OAASG,EAAU,CAEjBJ,EAAO,aAAaI,CAAG,EAEvB,IAAMF,EAASE,EAAI,YAAcA,EAAI,QAAU,IAC/C,MAAAJ,EAAO,SAASE,EAAQ,CAAE,MAAOC,EAASN,EAAOE,CAAI,CAAE,CAAC,EAClDK,CACR,CACF,CAAC,CACH,EC7BK,IAAMC,EAAiBC,GACrB,MAAOC,EAAoBC,IAAkB,CAClD,IAAMC,EAAMF,EAAI,IAAM,IAAI,IAAIA,EAAI,GAAG,EAAI,CAAE,SAAU,GAAI,EACnDG,EAASH,EAAI,QAAU,MACvBI,EAAKJ,EAAI,QAAQ,IAAMA,EAAI,QAAQ,IAAI,YAAY,EAAI,OACvDK,EAAKL,EAAI,QAAQ,IAAMA,EAAI,QAAQ,IAAI,iBAAiB,EAAI,OAElE,OAAOM,EAAO,WAAW,CACvB,OAAAH,EACA,KAAMD,EAAI,SACV,UAAWE,EACX,GAAIC,CACN,EAAG,SAAY,CACb,GAAI,CACF,IAAME,EAAW,MAAMR,EAAQC,EAAKC,CAAO,EACrCO,EAASD,GAAU,QAAU,IACnC,OAAAD,EAAO,SAASE,EAAQ,CAAE,MAAOC,EAAcP,EAAI,QAAQ,CAAE,CAAC,EACvDK,CACT,OAASG,EAAU,CAEjB,MAAAJ,EAAO,aAAaI,CAAG,EACvBJ,EAAO,SAAS,IAAK,CAAE,MAAOG,EAAcP,EAAI,QAAQ,CAAE,CAAC,EACrDQ,CACR,CACF,CAAC,CACH,EAIWC,EAAiBZ,GACrB,MAAOC,EAAUY,IAAa,CACnC,IAAMC,EAAOb,EAAI,IAAMA,EAAI,IAAI,MAAM,GAAG,EAAE,CAAC,EAAI,IAE/C,OAAOM,EAAO,WAAW,CACvB,OAAQN,EAAI,QAAU,MACtB,KAAMa,EACN,UAAWb,EAAI,QAAQ,YAAY,EACnC,GAAIA,EAAI,QAAQ,iBAAiB,GAAKA,EAAI,QAAQ,aACpD,EAAG,SAAY,CAEb,IAAMc,EAAO,IAAM,CACjBR,EAAO,SAASM,EAAI,YAAc,IAAK,CAAE,MAAOH,EAAcI,CAAI,CAAE,CAAC,CACvE,EAEAD,EAAI,KAAK,SAAUE,CAAI,EACvBF,EAAI,KAAK,QAASE,CAAI,EAEtB,GAAI,CACF,OAAO,MAAMf,EAAQC,EAAKY,CAAG,CAC/B,OAASG,EAAQ,CAEf,MAAAT,EAAO,aAAaS,CAAC,EAGfA,CACR,CACF,CAAC,CACH,EC1DK,IAAMC,EAAe,CAACC,EAAcC,EAAwBC,IAAmB,CAEhFD,GAAWA,EAAQ,QACrBE,EAAO,KAAKF,CAAO,EAIrBD,EAAQ,QAAQ,YAAa,CAACI,EAAcC,EAAYC,IAAmB,CAEzEH,EAAO,WAAW,CAChB,OAAQC,EAAQ,OAChB,KAAMA,EAAQ,IAAI,KAAOA,EAAQ,IACjC,GAAIA,EAAQ,GACZ,UAAWA,EAAQ,QAAQ,YAAY,CACzC,EAAG,IAAME,EAAK,CAAC,CACjB,CAAC,EAGDN,EAAQ,QAAQ,UAAW,CAACI,EAAcC,EAAYE,EAAYD,IAAmB,CACnFH,EAAO,aAAaI,CAAK,EACzBD,EAAK,CACP,CAAC,EAGDN,EAAQ,QAAQ,aAAc,CAACI,EAAcC,EAAYC,IAAmB,CAC1E,IAAME,EAAQJ,EAAQ,cAAc,KAAOA,EAAQ,YAAc,UACjED,EAAO,SAASE,EAAM,WAAY,CAAE,MAAAG,CAAM,CAAC,EAC3CF,EAAK,CACP,CAAC,EAEDJ,EAAK,CACP,EX3BA,IAAMO,EAAS,CACb,KAAOC,GAA2BC,EAAO,KAAKD,CAAO,EACrD,MAAO,IAAMC,EAAO,MAAM,EAC1B,MAAOA,EAAO,MAAM,KAAKA,CAAM,EAC/B,UAAWA,EAAO,UAAU,KAAKA,CAAM,EACvC,iBAAkBA,EAAO,aAAa,KAAKA,CAAM,EAGjD,eAAgBC,EAChB,aAAcC,EAGd,cAAAC,EACA,cAAAC,EAGA,OAAAC,EAGA,cAAeC,CACjB,EAEOC,EAAQT","names":["index_exports","__export","Senzor","index_default","__toCommonJS","Transport","config","trace","batch","err","import_async_hooks","storage","Context","trace","fn","span","store","error","import_crypto","import_http","import_https","import_url","shimmer","module","methodName","wrapper","original","instrumentFetch","ingestUrl","debug","ingestHost","originalFetch","input","init","urlStr","trace","Context","method","startTime","spanStartAbs","hostname","response","duration","err","instrumentHttp","requestWrapper","args","options","protocol","host","path","req","captureSpan","res","error","http","https","instrumentMongo","debug","mongodb","Collection","FindCursor","AggregationCursor","recordSpan","name","operation","collection","startAbs","traceStart","err","duration","Context","method","original","args","trace","spanStartAbs","collName","result","res","patchCursor","CursorClass","label","originalToArray","onSuccess","onError","e","instrumentPg","pg","originalQuery","args","trace","Context","startTime","spanStartAbs","sql","result","res","duration","SenzorClient","options","endpoint","debug","Transport","instrumentHttp","instrumentFetch","instrumentMongo","instrumentPg","data","next","trace","Context","status","extraData","duration","payload","error","name","type","startTime","spanStartAbs","meta","client","expressMiddleware","req","res","next","client","route","expressErrorHandler","err","normalizePath","path","getRoute","req","fallbackPath","wrapH3","handler","event","req","path","client","response","status","getRoute","err","wrapNextRoute","handler","req","context","url","method","ua","ip","client","response","status","normalizePath","err","wrapNextPages","res","path","done","e","senzorPlugin","fastify","options","done","client","request","reply","next","error","route","Senzor","options","client","expressMiddleware","expressErrorHandler","wrapNextRoute","wrapNextPages","wrapH3","senzorPlugin","index_default"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/core/transport.ts","../src/core/context.ts","../src/core/client.ts","../src/instrumentation/http.ts","../src/instrumentation/mongo.ts","../src/instrumentation/pg.ts","../src/middleware/express.ts","../src/core/normalizer.ts","../src/wrappers/h3.ts","../src/wrappers/next.ts","../src/wrappers/fastify.ts"],"sourcesContent":["import { client } from './core/client';\r\nimport { expressMiddleware, expressErrorHandler } from './middleware/express';\r\nimport { wrapH3 } from './wrappers/h3';\r\nimport { wrapNextRoute, wrapNextPages } from './wrappers/next';\r\nimport { senzorPlugin } from './wrappers/fastify';\r\nimport { SenzorOptions } from './core/types';\r\n\r\nconst Senzor = {\r\n init: (options: SenzorOptions) => client.init(options),\r\n flush: () => client.flush(),\r\n track: client.track.bind(client),\r\n startSpan: client.startSpan.bind(client),\r\n captureException: client.captureError.bind(client),\r\n\r\n // Express\r\n requestHandler: expressMiddleware,\r\n errorHandler: expressErrorHandler,\r\n\r\n // Next\r\n wrapNextRoute,\r\n wrapNextPages,\r\n\r\n // H3\r\n wrapH3,\r\n\r\n // Fastify\r\n fastifyPlugin: senzorPlugin\r\n};\r\n\r\nexport default Senzor;\r\nexport { Senzor };","import { SenzorOptions } from './types';\r\n\r\nexport class Transport {\r\n private queue: any[] = [];\r\n private timer: NodeJS.Timeout | null = null;\r\n\r\n constructor(private config: SenzorOptions) {\r\n if (typeof setInterval !== 'undefined') {\r\n this.timer = setInterval(() => this.flush(), config.flushInterval || 10000);\r\n if (this.timer && typeof this.timer.unref === 'function') {\r\n this.timer.unref(); // Don't block process exit\r\n }\r\n }\r\n }\r\n\r\n public add(trace: any) {\r\n this.queue.push(trace);\r\n if (this.queue.length >= (this.config.batchSize || 100)) {\r\n this.flush();\r\n }\r\n }\r\n\r\n public async flush() {\r\n if (this.queue.length === 0) return;\r\n\r\n const batch = [...this.queue];\r\n this.queue = [];\r\n\r\n try {\r\n // Use global fetch (Node 18+)\r\n await fetch(this.config.endpoint || 'https://api.senzor.dev/api/ingest/apm', {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n 'x-service-api-key': this.config.apiKey,\r\n },\r\n body: JSON.stringify(batch),\r\n keepalive: true,\r\n });\r\n \r\n if (this.config.debug) console.log(`[Senzor] Flushed ${batch.length} traces`);\r\n } catch (err) {\r\n if (this.config.debug) console.error('[Senzor] Ingestion Error:', err);\r\n // Dropping data to prevent memory leaks is preferred in APM\r\n }\r\n }\r\n}","import { AsyncLocalStorage } from 'async_hooks';\r\nimport { ActiveTrace, TraceError } from './types';\r\n\r\nexport const storage = new AsyncLocalStorage<ActiveTrace>();\r\n\r\nexport const Context = {\r\n run: <T>(trace: ActiveTrace, fn: () => T): T => {\r\n return storage.run(trace, fn);\r\n },\r\n\r\n current: (): ActiveTrace | undefined => {\r\n return storage.getStore();\r\n },\r\n\r\n addSpan: (span: any) => {\r\n const store = storage.getStore();\r\n if (store) {\r\n store.spans.push(span);\r\n }\r\n },\r\n\r\n // Attach error to current trace\r\n setError: (error: Error) => {\r\n const store = storage.getStore();\r\n if (store) {\r\n store.error = {\r\n name: error.name,\r\n message: error.message,\r\n stack: error.stack\r\n };\r\n }\r\n }\r\n};","import { Transport } from './transport';\r\nimport { Context } from './context';\r\nimport { SenzorOptions, ActiveTrace } from './types';\r\nimport { randomUUID } from 'crypto';\r\nimport { instrumentHttp, instrumentFetch } from '../instrumentation/http';\r\nimport { instrumentMongo } from '../instrumentation/mongo';\r\nimport { instrumentPg } from '../instrumentation/pg';\r\n\r\nexport class SenzorClient {\r\n private transport: Transport | null = null;\r\n private options: SenzorOptions | null = null;\r\n private isInstrumented = false;\r\n\r\n public init(options: SenzorOptions) {\r\n if (!options.apiKey) {\r\n console.warn('[Senzor] API Key missing. SDK disabled.');\r\n return;\r\n }\r\n this.options = options;\r\n const endpoint = options.endpoint || 'https://api.senzor.dev/api/ingest/apm';\r\n const debug = options.debug || false;\r\n\r\n this.transport = new Transport({ ...options, endpoint });\r\n\r\n if (!this.isInstrumented) {\r\n try { instrumentHttp(endpoint, debug); } catch (e) { }\r\n try { instrumentFetch(endpoint, debug); } catch (e) { }\r\n try { instrumentMongo(debug); } catch (e) { }\r\n try { instrumentPg(); } catch (e) { }\r\n\r\n this.isInstrumented = true;\r\n if (debug) console.log('[Senzor] Auto-instrumentation enabled');\r\n }\r\n }\r\n\r\n public startTrace<T>(data: Partial<ActiveTrace['data']> & { headers?: any }, next: () => T): T {\r\n if (!this.transport) return next();\r\n\r\n // Check for Distributed Tracing Headers\r\n let parentTraceId = undefined;\r\n let parentSpanId = undefined;\r\n\r\n if (data.headers) {\r\n // Handle various casing\r\n parentTraceId = data.headers['x-senzor-trace-id'] || data.headers['X-SENZOR-TRACE-ID'];\r\n parentSpanId = data.headers['x-senzor-parent-span-id'] || data.headers['X-SENZOR-PARENT-SPAN-ID'];\r\n }\r\n\r\n const trace: ActiveTrace = {\r\n id: randomUUID(),\r\n startTime: performance.now(),\r\n data: {\r\n ...data,\r\n parentTraceId, // Link to parent\r\n parentSpanId // Link to specific call\r\n },\r\n spans: []\r\n };\r\n\r\n return Context.run(trace, next);\r\n }\r\n\r\n public endTrace(status: number, extraData: any = {}) {\r\n const trace = Context.current();\r\n if (!trace || !this.transport) return;\r\n const duration = performance.now() - trace.startTime;\r\n\r\n // Explicitly destructure to ensure parent IDs are included\r\n const payload = {\r\n traceId: trace.id,\r\n parentTraceId: trace.data.parentTraceId,\r\n parentSpanId: trace.data.parentSpanId,\r\n ...trace.data,\r\n ...extraData,\r\n status, duration, spans: trace.spans, timestamp: new Date().toISOString(),\r\n error: trace.error,\r\n\r\n };\r\n this.transport.add(payload);\r\n }\r\n\r\n // --- NEW: Capture Exception ---\r\n public captureError(error: unknown) {\r\n if (error instanceof Error) {\r\n Context.setError(error);\r\n } else if (typeof error === 'string') {\r\n Context.setError(new Error(error));\r\n }\r\n }\r\n\r\n // ... (manual track, startSpan, flush remain same) ...\r\n public track(data: any) { this.transport?.add({ traceId: randomUUID(), ...data, spans: [], timestamp: new Date().toISOString() }); }\r\n\r\n public startSpan(name: string, type: 'db' | 'http' | 'function' | 'custom' = 'custom') {\r\n const trace = Context.current();\r\n if (!trace) return { end: () => { } };\r\n const startTime = performance.now() - trace.startTime;\r\n const spanStartAbs = performance.now();\r\n const spanId = randomUUID(); // Manual spans also need IDs\r\n\r\n return {\r\n end: (meta?: any, status?: number) => {\r\n const duration = performance.now() - spanStartAbs;\r\n Context.addSpan({ spanId, name, type, startTime, duration, status, meta });\r\n }\r\n };\r\n }\r\n\r\n public async flush() { if (this.transport) await this.transport.flush(); }\r\n}\r\n\r\nexport const client = new SenzorClient();","import http from 'http';\r\nimport https from 'https';\r\nimport { URL } from 'url';\r\nimport { Context } from '../core/context';\r\nimport { randomUUID } from 'crypto';\r\n\r\nconst shimmer = (module: any, methodName: string, wrapper: (original: Function) => Function) => {\r\n if (!module[methodName]) return;\r\n const original = module[methodName];\r\n module[methodName] = wrapper(original);\r\n};\r\n\r\n// --- FETCH INSTRUMENTATION (Node 18+ / Edge) ---\r\nexport const instrumentFetch = (ingestUrl: string, debug = false) => {\r\n if (!globalThis.fetch) return;\r\n\r\n let ingestHost = '';\r\n try { ingestHost = new URL(ingestUrl).hostname; } catch (e) { }\r\n\r\n const originalFetch = globalThis.fetch;\r\n\r\n // @ts-ignore\r\n globalThis.fetch = async (input: RequestInfo | URL, init?: RequestInit) => {\r\n // 1. Extract URL\r\n let urlStr = '';\r\n if (typeof input === 'string') urlStr = input;\r\n else if (input instanceof URL) urlStr = input.toString();\r\n else if (input && (input as any).url) urlStr = (input as any).url;\r\n\r\n // 2. Infinite Loop Guard\r\n if (ingestHost && urlStr.includes(ingestHost)) {\r\n return originalFetch(input, init);\r\n }\r\n\r\n // 3. Context Check\r\n const trace = Context.current();\r\n if (!trace) {\r\n return originalFetch(input, init);\r\n }\r\n\r\n // 4. Prepare Metadata & ID\r\n const method = (init?.method || 'GET').toUpperCase();\r\n const startTime = performance.now() - trace.startTime;\r\n const spanStartAbs = performance.now();\r\n const spanId = randomUUID(); // New ID for this specific outbound call\r\n\r\n let hostname = 'unknown';\r\n try { hostname = new URL(urlStr).hostname; } catch (e) { }\r\n\r\n if (debug) console.log(`[Senzor] Fetch: ${method} ${hostname}`);\r\n\r\n // 5. Inject Distributed Tracing Headers\r\n // We need to clone init or create it to avoid mutating original ref unexpectedly\r\n const newInit = { ...init };\r\n if (!newInit.headers) {\r\n newInit.headers = {};\r\n }\r\n\r\n // Handle different Header formats (Headers object vs plain object)\r\n if (newInit.headers instanceof Headers) {\r\n newInit.headers.set('x-senzor-trace-id', trace.id);\r\n newInit.headers.set('x-senzor-parent-span-id', spanId);\r\n } else if (Array.isArray(newInit.headers)) {\r\n newInit.headers.push(['x-senzor-trace-id', trace.id]);\r\n newInit.headers.push(['x-senzor-parent-span-id', spanId]);\r\n } else {\r\n // Plain object\r\n (newInit.headers as any)['x-senzor-trace-id'] = trace.id;\r\n (newInit.headers as any)['x-senzor-parent-span-id'] = spanId;\r\n }\r\n\r\n try {\r\n // 6. Execute Fetch\r\n const response = await originalFetch(input, newInit);\r\n\r\n // 7. Record Span\r\n const duration = performance.now() - spanStartAbs;\r\n Context.addSpan({\r\n spanId,\r\n name: `${method} ${hostname}`,\r\n type: 'http',\r\n startTime,\r\n duration,\r\n status: response.status,\r\n meta: { url: urlStr, method, library: 'fetch' }\r\n });\r\n\r\n return response;\r\n } catch (err: any) {\r\n const duration = performance.now() - spanStartAbs;\r\n Context.addSpan({\r\n spanId,\r\n name: `${method} ${hostname}`,\r\n type: 'http',\r\n startTime,\r\n duration,\r\n status: 500,\r\n meta: { error: err.message, url: urlStr, library: 'fetch' }\r\n });\r\n throw err;\r\n }\r\n };\r\n};\r\n\r\n// --- HTTP/HTTPS INSTRUMENTATION ---\r\nexport const instrumentHttp = (ingestUrl: string, debug = false) => {\r\n let ingestHost = '';\r\n try { ingestHost = new URL(ingestUrl).hostname; } catch (e) { }\r\n\r\n const requestWrapper = (original: Function) => {\r\n return function (this: any, ...args: any[]) {\r\n let options: any = {};\r\n let urlStr = '';\r\n\r\n if (typeof args[0] === 'string' || args[0] instanceof URL) {\r\n urlStr = args[0].toString();\r\n if (typeof args[1] === 'object' && args[1] !== null) options = args[1];\r\n } else {\r\n options = args[0] || {};\r\n const protocol = options.protocol || (options.port === 443 ? 'https:' : 'http:');\r\n const host = options.hostname || options.host || 'localhost';\r\n const path = options.path || '/';\r\n urlStr = `${protocol}//${host}${path}`;\r\n }\r\n\r\n if (ingestHost && (urlStr.includes(ingestHost) || (options.hostname && options.hostname.includes(ingestHost)))) {\r\n return original.apply(this, args);\r\n }\r\n\r\n const trace = Context.current();\r\n if (!trace) return original.apply(this, args);\r\n\r\n const method = (options.method || 'GET').toUpperCase();\r\n const startTime = performance.now() - trace.startTime;\r\n const spanStartAbs = performance.now();\r\n const spanId = randomUUID(); // Generate ID\r\n\r\n let hostname = 'unknown';\r\n try { hostname = new URL(urlStr).hostname; } catch (e) { hostname = options.hostname || 'unknown'; }\r\n\r\n // Inject Headers\r\n if (!options.headers) options.headers = {};\r\n options.headers['x-senzor-trace-id'] = trace.id;\r\n options.headers['x-senzor-parent-span-id'] = spanId;\r\n\r\n const req = original.apply(this, args);\r\n\r\n const captureSpan = (res: any, error?: Error) => {\r\n const duration = performance.now() - spanStartAbs;\r\n Context.addSpan({\r\n spanId,\r\n name: `${method} ${hostname}`,\r\n type: 'http',\r\n startTime,\r\n duration,\r\n status: error ? 500 : res?.statusCode || 0,\r\n meta: { url: urlStr, method, library: 'http' }\r\n });\r\n };\r\n\r\n req.on('response', (res: any) => {\r\n res.once('end', () => captureSpan(res));\r\n res.once('close', () => captureSpan(res)); // Safety if stream not consumed\r\n res.once('error', (err: Error) => captureSpan(res, err));\r\n });\r\n\r\n req.on('error', (err: Error) => captureSpan(null, err));\r\n\r\n return req;\r\n };\r\n };\r\n\r\n shimmer(http, 'request', requestWrapper);\r\n shimmer(http, 'get', requestWrapper);\r\n shimmer(https, 'request', requestWrapper);\r\n shimmer(https, 'get', requestWrapper);\r\n};","import { Context } from '../core/context';\r\n\r\nexport const instrumentMongo = (debug = false) => {\r\n try {\r\n const mongodb = require('mongodb');\r\n const Collection = mongodb.Collection;\r\n\r\n // Attempt to get Cursor classes\r\n // Note: The location of these classes varies by driver version, \r\n // checking common locations\r\n const FindCursor = mongodb.FindCursor || require('mongodb/lib/cursor/find_cursor').FindCursor;\r\n const AggregationCursor = mongodb.AggregationCursor || require('mongodb/lib/cursor/aggregation_cursor').AggregationCursor;\r\n\r\n if (debug) console.log('[Senzor] Instrumenting MongoDB (Collection + Cursors)...');\r\n\r\n // --- Helper to Record Span ---\r\n const recordSpan = (name: string, operation: string, collection: string, startAbs: number, traceStart: number, err?: Error) => {\r\n const duration = performance.now() - startAbs;\r\n Context.addSpan({\r\n name: `MongoDB ${name}`,\r\n type: 'db',\r\n startTime: performance.now() - traceStart - duration, // Adjust start time to when op actually started\r\n duration,\r\n status: err ? 500 : 0,\r\n meta: { collection, operation, error: err ? err.message : undefined }\r\n });\r\n if (debug) console.log(`[Senzor] Captured Mongo: ${name} (${duration.toFixed(2)}ms)`);\r\n };\r\n\r\n // --- 1. Instrument Immediate Operations (Insert/Update/Delete) ---\r\n const immediateMethods = ['insertOne', 'insertMany', 'updateOne', 'updateMany', 'deleteOne', 'deleteMany', 'countDocuments'];\r\n\r\n immediateMethods.forEach((method) => {\r\n if (!Collection.prototype[method]) return;\r\n const original = Collection.prototype[method];\r\n\r\n Collection.prototype[method] = function (...args: any[]) {\r\n const trace = Context.current();\r\n if (!trace) return original.apply(this, args);\r\n\r\n const spanStartAbs = performance.now();\r\n const traceStart = trace.startTime;\r\n const collName = this.collectionName;\r\n\r\n try {\r\n const result = original.apply(this, args);\r\n if (result && typeof result.then === 'function') {\r\n return result.then(\r\n (res: any) => { recordSpan(method, method, collName, spanStartAbs, traceStart); return res; },\r\n (err: any) => { recordSpan(method, method, collName, spanStartAbs, traceStart, err); throw err; }\r\n );\r\n }\r\n return result;\r\n } catch (err: any) {\r\n recordSpan(method, method, collName, spanStartAbs, traceStart, err);\r\n throw err;\r\n }\r\n };\r\n });\r\n\r\n // --- 2. Instrument Cursor Execution (find -> toArray) ---\r\n const patchCursor = (CursorClass: any, label: string) => {\r\n if (!CursorClass || !CursorClass.prototype.toArray) return;\r\n\r\n const originalToArray = CursorClass.prototype.toArray;\r\n\r\n CursorClass.prototype.toArray = function (...args: any[]) {\r\n const trace = Context.current();\r\n // Cursors are often created in context but executed later. \r\n // We check context at execution time.\r\n if (!trace) return originalToArray.apply(this, args);\r\n\r\n const spanStartAbs = performance.now();\r\n const traceStart = trace.startTime;\r\n // Attempt to get collection name from cursor internal state\r\n const collName = this.namespace?.collection || 'unknown';\r\n\r\n const onSuccess = (res: any) => {\r\n recordSpan(label, label, collName, spanStartAbs, traceStart);\r\n return res;\r\n };\r\n const onError = (err: any) => {\r\n recordSpan(label, label, collName, spanStartAbs, traceStart, err);\r\n throw err;\r\n };\r\n\r\n try {\r\n const result = originalToArray.apply(this, args);\r\n if (result && typeof result.then === 'function') {\r\n return result.then(onSuccess, onError);\r\n }\r\n return onSuccess(result);\r\n } catch (e) {\r\n onError(e);\r\n }\r\n };\r\n };\r\n\r\n patchCursor(FindCursor, 'find');\r\n patchCursor(AggregationCursor, 'aggregate');\r\n\r\n } catch (e: any) {\r\n if (debug) console.warn('[Senzor] MongoDB instrumentation warning:', e.message);\r\n }\r\n};","import { Context } from '../core/context';\r\n\r\n// Simple shim for 'pg' library\r\nexport const instrumentPg = () => {\r\n try {\r\n // Try to require pg (it might not be installed by user)\r\n const pg = require('pg');\r\n const originalQuery = pg.Client.prototype.query;\r\n\r\n pg.Client.prototype.query = function (...args: any[]) {\r\n const trace = Context.current();\r\n if (!trace) return originalQuery.apply(this, args);\r\n\r\n const startTime = performance.now() - trace.startTime;\r\n const spanStartAbs = performance.now();\r\n\r\n // Extract SQL (first arg usually string or config object)\r\n const sql = typeof args[0] === 'string' ? args[0] : args[0].text;\r\n\r\n // Wrap callback if present, or handle Promise\r\n const result = originalQuery.apply(this, args);\r\n\r\n if (result && typeof result.then === 'function') {\r\n return result.then((res: any) => {\r\n const duration = performance.now() - spanStartAbs;\r\n Context.addSpan({\r\n name: 'Postgres Query',\r\n type: 'db',\r\n startTime,\r\n duration,\r\n meta: { query: sql }\r\n });\r\n return res;\r\n });\r\n }\r\n return result;\r\n };\r\n } catch (e) {\r\n // User doesn't use pg, ignore\r\n }\r\n};","import { client } from '../core/client';\r\n\r\n// 1. Request Handler (Place before routes)\r\nexport const expressMiddleware = () => {\r\n return (req: any, res: any, next: () => void) => {\r\n client.startTrace({\r\n method: req.method,\r\n path: req.originalUrl || req.url,\r\n ip: req.ip || req.socket?.remoteAddress,\r\n userAgent: req.headers['user-agent'],\r\n headers: req.headers\r\n }, () => {\r\n\r\n // Auto-detect status code on finish\r\n res.once('finish', () => {\r\n try {\r\n let route = 'UNKNOWN';\r\n // Express populates req.route only if a route matched\r\n if (req.route && req.route.path) {\r\n route = (req.baseUrl || '') + req.route.path;\r\n } else if (res.statusCode === 404) {\r\n route = 'Not Found';\r\n } else {\r\n route = req.path || 'Wildcard';\r\n }\r\n\r\n client.endTrace(res.statusCode, { route });\r\n } catch (e) { /* Fail open */ }\r\n });\r\n\r\n next();\r\n });\r\n };\r\n};\r\n\r\n// 2. Error Handler (Place after routes)\r\n// This is required in Express to capture the actual Error Object (Stack Trace)\r\nexport const expressErrorHandler = () => {\r\n return (err: any, req: any, res: any, next: (err?: any) => void) => {\r\n\r\n // 1. Capture the exception context\r\n client.captureError(err);\r\n\r\n // 2. Pass it to the next error handler (don't swallow it)\r\n next(err);\r\n };\r\n};","/**\r\n * Heuristic URL Normalizer\r\n * Converts raw paths with IDs into generic patterns to prevent high cardinality.\r\n * Example: /users/123/orders/abc-def -> /users/:id/orders/:uuid\r\n */\r\nexport const normalizePath = (path: string): string => {\r\n if (!path || path === '/') return '/';\r\n\r\n return path\r\n // Replace UUIDs (long alphanumeric strings)\r\n .replace(\r\n /[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}/g,\r\n ':uuid'\r\n )\r\n // Replace MongoDB ObjectIds (24 hex chars)\r\n .replace(/[0-9a-fA-F]{24}/g, ':objectId')\r\n // Replace pure numeric IDs (e.g., /123)\r\n .replace(/\\/(\\d+)(?=\\/|$)/g, '/:id')\r\n // Remove query strings\r\n .split('?')[0];\r\n};\r\n\r\n/**\r\n * Tries to extract route from Framework internals, falls back to heuristic\r\n */\r\nexport const getRoute = (req: any, fallbackPath: string): string => {\r\n // Express / Connect\r\n if (req.route && req.route.path) {\r\n return (req.baseUrl || '') + req.route.path;\r\n }\r\n\r\n // H3 / Nitro (Nuxt)\r\n if (req.context && req.context.matchedRoute) {\r\n return req.context.matchedRoute.path;\r\n }\r\n\r\n // Fastify\r\n if (req.routerPath) {\r\n return req.routerPath;\r\n }\r\n\r\n // Fallback: Heuristic Normalization\r\n return normalizePath(fallbackPath);\r\n};","import { client } from '../core/client';\r\nimport { getRoute } from '../core/normalizer';\r\n\r\ntype EventHandler = (event: any) => any;\r\n\r\nexport const wrapH3 = (handler: EventHandler) => {\r\n return (event: any) => {\r\n const req = event.node.req;\r\n const path = req.originalUrl || req.url || '/';\r\n\r\n return client.startTrace({\r\n method: req.method || 'GET',\r\n path: path,\r\n ip: req.headers['x-forwarded-for'] || req.socket?.remoteAddress,\r\n userAgent: req.headers['user-agent'],\r\n headers: req.headers // Pass headers\r\n }, async () => {\r\n try {\r\n const response = await handler(event);\r\n let status = 200;\r\n if (event.node.res.statusCode) status = event.node.res.statusCode;\r\n if (response && response.statusCode) status = response.statusCode;\r\n\r\n client.endTrace(status, { route: getRoute(event, path) });\r\n return response;\r\n } catch (err: any) {\r\n client.captureError(err);\r\n const status = err.statusCode || err.status || 500;\r\n client.endTrace(status, { route: getRoute(event, path) });\r\n throw err;\r\n }\r\n });\r\n };\r\n};","import { client } from '../core/client';\r\nimport { normalizePath } from '../core/normalizer';\r\n\r\n// --- App Router Wrapper ---\r\nexport const wrapNextRoute = (handler: Function) => {\r\n return async (req: Request | any, context?: any) => {\r\n\r\n // Extract info from Web Standard Request\r\n const url = req.url ? new URL(req.url) : { pathname: '/' };\r\n const method = req.method || 'GET';\r\n\r\n // Header Extraction\r\n let headers: Record<string, string> = {};\r\n let ua: string | undefined;\r\n let ip: string | undefined;\r\n\r\n if (typeof req.headers.get === 'function') {\r\n // It's a Web Request Object\r\n ua = req.headers.get('user-agent');\r\n ip = req.headers.get('x-forwarded-for');\r\n\r\n // Convert to plain object for trace context extraction\r\n req.headers.forEach((value: string, key: string) => {\r\n headers[key] = value;\r\n });\r\n } else {\r\n // It's a Node Request Object (rare in App router but possible)\r\n headers = req.headers;\r\n ua = headers['user-agent'];\r\n ip = headers['x-forwarded-for'] as string;\r\n }\r\n\r\n return client.startTrace({\r\n method,\r\n path: url.pathname,\r\n userAgent: ua,\r\n ip: ip,\r\n headers: headers // Pass extracted headers\r\n }, async () => {\r\n try {\r\n const response = await handler(req, context);\r\n const status = response?.status || 200;\r\n\r\n client.endTrace(status, { route: normalizePath(url.pathname) });\r\n return response;\r\n } catch (err: any) {\r\n client.captureError(err);\r\n client.endTrace(500, { route: normalizePath(url.pathname) });\r\n throw err;\r\n }\r\n });\r\n };\r\n};\r\n\r\n// --- Pages Router Wrapper ---\r\nexport const wrapNextPages = (handler: Function) => {\r\n return async (req: any, res: any) => {\r\n const path = req.url ? req.url.split('?')[0] : '/';\r\n\r\n return client.startTrace({\r\n method: req.method || 'GET',\r\n path: path,\r\n userAgent: req.headers['user-agent'],\r\n ip: req.headers['x-forwarded-for'] || req.socket?.remoteAddress,\r\n headers: req.headers // Standard Node headers work fine\r\n }, async () => {\r\n\r\n const done = () => {\r\n client.endTrace(res.statusCode || 200, { route: normalizePath(path) });\r\n };\r\n\r\n res.once('finish', done);\r\n res.once('close', done);\r\n\r\n try {\r\n return await handler(req, res);\r\n } catch (e: any) {\r\n client.captureError(e);\r\n throw e;\r\n }\r\n });\r\n };\r\n};","import { client } from '../core/client';\r\nimport { SenzorOptions } from '../core/types';\r\n\r\nexport const senzorPlugin = (fastify: any, options: SenzorOptions, done: Function) => {\r\n if (options && options.apiKey) {\r\n client.init(options);\r\n }\r\n\r\n fastify.addHook('onRequest', (request: any, reply: any, next: Function) => {\r\n client.startTrace({\r\n method: request.method,\r\n path: request.raw.url || request.url,\r\n ip: request.ip,\r\n userAgent: request.headers['user-agent'],\r\n headers: request.headers // Pass headers\r\n }, () => next());\r\n });\r\n\r\n fastify.addHook('onError', (request: any, reply: any, error: any, next: Function) => {\r\n client.captureError(error);\r\n next();\r\n });\r\n\r\n fastify.addHook('onResponse', (request: any, reply: any, next: Function) => {\r\n const route = request.routeOptions?.url || request.routerPath || 'UNKNOWN';\r\n client.endTrace(reply.statusCode, { route });\r\n next();\r\n });\r\n\r\n done();\r\n};"],"mappings":"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","names":["index_exports","__export","Senzor","index_default","__toCommonJS","Transport","config","trace","batch","err","import_async_hooks","storage","Context","trace","fn","span","store","error","import_crypto","import_http","import_https","import_url","import_crypto","shimmer","module","methodName","wrapper","original","instrumentFetch","ingestUrl","debug","ingestHost","originalFetch","input","init","urlStr","trace","Context","method","startTime","spanStartAbs","spanId","hostname","newInit","response","duration","err","instrumentHttp","requestWrapper","args","options","protocol","host","path","req","captureSpan","res","error","http","https","instrumentMongo","debug","mongodb","Collection","FindCursor","AggregationCursor","recordSpan","name","operation","collection","startAbs","traceStart","err","duration","Context","method","original","args","trace","spanStartAbs","collName","result","res","patchCursor","CursorClass","label","originalToArray","onSuccess","onError","e","instrumentPg","pg","originalQuery","args","trace","Context","startTime","spanStartAbs","sql","result","res","duration","SenzorClient","options","endpoint","debug","Transport","instrumentHttp","instrumentFetch","instrumentMongo","instrumentPg","data","next","parentTraceId","parentSpanId","trace","Context","status","extraData","duration","payload","error","name","type","startTime","spanStartAbs","spanId","meta","client","expressMiddleware","req","res","next","client","route","expressErrorHandler","err","normalizePath","path","getRoute","req","fallbackPath","wrapH3","handler","event","req","path","client","response","status","getRoute","err","wrapNextRoute","handler","req","context","url","method","headers","ua","ip","value","key","client","response","status","normalizePath","err","wrapNextPages","res","path","done","e","senzorPlugin","fastify","options","done","client","request","reply","next","error","route","Senzor","options","client","expressMiddleware","expressErrorHandler","wrapNextRoute","wrapNextPages","wrapH3","senzorPlugin","index_default"]}
package/dist/index.mjs CHANGED
@@ -1,2 +1,2 @@
1
- var A=(e=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(e,{get:(t,n)=>(typeof require<"u"?require:t)[n]}):e)(function(e){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+e+'" is not supported')});var E=class{constructor(t){this.config=t;this.queue=[];this.timer=null;typeof setInterval<"u"&&(this.timer=setInterval(()=>this.flush(),t.flushInterval||1e4),this.timer&&typeof this.timer.unref=="function"&&this.timer.unref())}add(t){this.queue.push(t),this.queue.length>=(this.config.batchSize||100)&&this.flush()}async flush(){if(this.queue.length===0)return;let t=[...this.queue];this.queue=[];try{await fetch(this.config.endpoint||"https://api.senzor.dev/api/ingest/apm",{method:"POST",headers:{"Content-Type":"application/json","x-service-api-key":this.config.apiKey},body:JSON.stringify(t),keepalive:!0}),this.config.debug&&console.log(`[Senzor] Flushed ${t.length} traces`)}catch(n){this.config.debug&&console.error("[Senzor] Ingestion Error:",n)}}};import{AsyncLocalStorage as L}from"async_hooks";var C=new L,m={run:(e,t)=>C.run(e,t),current:()=>C.getStore(),addSpan:e=>{let t=C.getStore();t&&t.spans.push(e)},setError:e=>{let t=C.getStore();t&&(t.error={name:e.name,message:e.message,stack:e.stack})}};import{randomUUID as N}from"crypto";import k from"http";import O from"https";import{URL as b}from"url";var F=(e,t,n)=>{if(!e[t])return;let r=e[t];e[t]=n(r)},I=(e,t=!1)=>{if(!globalThis.fetch)return;let n="";try{n=new b(e).hostname}catch{}let r=globalThis.fetch;globalThis.fetch=async(o,a)=>{let i="";if(typeof o=="string"?i=o:o instanceof b?i=o.toString():o&&o.url&&(i=o.url),n&&i.includes(n))return r(o,a);let u=m.current();if(!u)return r(o,a);let c=(a?.method||"GET").toUpperCase(),h=performance.now()-u.startTime,w=performance.now(),y="unknown";try{y=new b(i).hostname}catch{}t&&console.log(`[Senzor] Tracking Fetch: ${c} ${y}`);try{let l=await r(o,a),d=performance.now()-w;return m.addSpan({name:`${c} ${y}`,type:"http",startTime:h,duration:d,status:l.status,meta:{url:i,method:c,library:"fetch"}}),l}catch(l){let d=performance.now()-w;throw m.addSpan({name:`${c} ${y}`,type:"http",startTime:h,duration:d,status:500,meta:{error:l.message,url:i,library:"fetch"}}),l}}},P=(e,t=!1)=>{let n="";try{n=new b(e).hostname}catch{}let r=o=>function(...a){let i={},u="";if(typeof a[0]=="string"||a[0]instanceof b)u=a[0].toString(),typeof a[1]=="object"&&a[1]!==null&&(i=a[1]);else{i=a[0]||{};let p=i.protocol||(i.port===443?"https:":"http:"),f=i.hostname||i.host||"localhost",T=i.path||"/";u=`${p}//${f}${T}`}if(n&&(u.includes(n)||i.hostname&&i.hostname.includes(n)))return o.apply(this,a);let c=m.current();if(!c)return o.apply(this,a);let h=(i.method||"GET").toUpperCase(),w=performance.now()-c.startTime,y=performance.now(),l="unknown";try{l=new b(u).hostname}catch{l=i.hostname||"unknown"}let d=o.apply(this,a),g=(p,f)=>{let T=performance.now()-y;m.addSpan({name:`${h} ${l}`,type:"http",startTime:w,duration:T,status:f?500:p?.statusCode||0,meta:{url:u,method:h,library:"http",error:f?f.message:void 0}})};return d.on("response",p=>{p.once("end",()=>g(p)),p.once("error",f=>g(p,f))}),d.on("error",p=>g(null,p)),d};F(k,"request",r),F(k,"get",r),F(O,"request",r),F(O,"get",r)};var $=(e=!1)=>{try{let t=A("mongodb"),n=t.Collection,r=t.FindCursor||A("mongodb/lib/cursor/find_cursor").FindCursor,o=t.AggregationCursor||A("mongodb/lib/cursor/aggregation_cursor").AggregationCursor;e&&console.log("[Senzor] Instrumenting MongoDB (Collection + Cursors)...");let a=(c,h,w,y,l,d)=>{let g=performance.now()-y;m.addSpan({name:`MongoDB ${c}`,type:"db",startTime:performance.now()-l-g,duration:g,status:d?500:0,meta:{collection:w,operation:h,error:d?d.message:void 0}}),e&&console.log(`[Senzor] Captured Mongo: ${c} (${g.toFixed(2)}ms)`)};["insertOne","insertMany","updateOne","updateMany","deleteOne","deleteMany","countDocuments"].forEach(c=>{if(!n.prototype[c])return;let h=n.prototype[c];n.prototype[c]=function(...w){let y=m.current();if(!y)return h.apply(this,w);let l=performance.now(),d=y.startTime,g=this.collectionName;try{let p=h.apply(this,w);return p&&typeof p.then=="function"?p.then(f=>(a(c,c,g,l,d),f),f=>{throw a(c,c,g,l,d,f),f}):p}catch(p){throw a(c,c,g,l,d,p),p}}});let u=(c,h)=>{if(!c||!c.prototype.toArray)return;let w=c.prototype.toArray;c.prototype.toArray=function(...y){let l=m.current();if(!l)return w.apply(this,y);let d=performance.now(),g=l.startTime,p=this.namespace?.collection||"unknown",f=S=>(a(h,h,p,d,g),S),T=S=>{throw a(h,h,p,d,g,S),S};try{let S=w.apply(this,y);return S&&typeof S.then=="function"?S.then(f,T):f(S)}catch(S){T(S)}}};u(r,"find"),u(o,"aggregate")}catch(t){e&&console.warn("[Senzor] MongoDB instrumentation warning:",t.message)}};var H=()=>{try{let e=A("pg"),t=e.Client.prototype.query;e.Client.prototype.query=function(...n){let r=m.current();if(!r)return t.apply(this,n);let o=performance.now()-r.startTime,a=performance.now(),i=typeof n[0]=="string"?n[0]:n[0].text,u=t.apply(this,n);return u&&typeof u.then=="function"?u.then(c=>{let h=performance.now()-a;return m.addSpan({name:"Postgres Query",type:"db",startTime:o,duration:h,meta:{query:i}}),c}):u}}catch{}};var z=class{constructor(){this.transport=null;this.options=null;this.isInstrumented=!1}init(t){if(!t.apiKey){console.warn("[Senzor] API Key missing. SDK disabled.");return}this.options=t;let n=t.endpoint||"https://api.senzor.dev/api/ingest/apm",r=t.debug||!1;if(this.transport=new E({...t,endpoint:n}),!this.isInstrumented){try{P(n,r)}catch{}try{I(n,r)}catch{}try{$(r)}catch{}try{H()}catch{}this.isInstrumented=!0,r&&console.log("[Senzor] Auto-instrumentation enabled")}}startTrace(t,n){if(!this.transport)return n();let r={id:N(),startTime:performance.now(),data:t,spans:[]};return m.run(r,n)}endTrace(t,n={}){let r=m.current();if(!r||!this.transport)return;let o=performance.now()-r.startTime,a={traceId:r.id,...r.data,...n,status:t,duration:o,spans:r.spans,error:r.error,timestamp:new Date().toISOString()};this.transport.add(a)}captureError(t){t instanceof Error?m.setError(t):typeof t=="string"&&m.setError(new Error(t))}track(t){this.transport?.add({traceId:N(),...t,spans:[],timestamp:new Date().toISOString()})}startSpan(t,n="custom"){let r=m.current();if(!r)return{end:()=>{}};let o=performance.now()-r.startTime,a=performance.now();return{end:(i,u)=>{m.addSpan({name:t,type:n,startTime:o,duration:performance.now()-a,status:u,meta:i})}}}async flush(){this.transport&&await this.transport.flush()}},s=new z;var R=()=>(e,t,n)=>{s.startTrace({method:e.method,path:e.originalUrl||e.url,ip:e.ip||e.socket?.remoteAddress,userAgent:e.headers["user-agent"]},()=>{t.once("finish",()=>{try{let r="UNKNOWN";e.route&&e.route.path?r=(e.baseUrl||"")+e.route.path:t.statusCode===404?r="Not Found":r=e.path||"Wildcard",s.endTrace(t.statusCode,{route:r})}catch{}}),n()})},M=()=>(e,t,n,r)=>{s.captureError(e),r(e)};var x=e=>!e||e==="/"?"/":e.replace(/[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}/g,":uuid").replace(/[0-9a-fA-F]{24}/g,":objectId").replace(/\/(\d+)(?=\/|$)/g,"/:id").split("?")[0],v=(e,t)=>e.route&&e.route.path?(e.baseUrl||"")+e.route.path:e.context&&e.context.matchedRoute?e.context.matchedRoute.path:e.routerPath?e.routerPath:x(t);var U=e=>t=>{let n=t.node.req,r=n.originalUrl||n.url||"/";return s.startTrace({method:n.method||"GET",path:r,ip:n.headers["x-forwarded-for"]||n.socket?.remoteAddress,userAgent:n.headers["user-agent"]},async()=>{try{let o=await e(t),a=200;return t.node.res.statusCode&&(a=t.node.res.statusCode),o&&o.statusCode&&(a=o.statusCode),s.endTrace(a,{route:v(t,r)}),o}catch(o){s.captureError(o);let a=o.statusCode||o.status||500;throw s.endTrace(a,{route:v(t,r)}),o}})};var D=e=>async(t,n)=>{let r=t.url?new URL(t.url):{pathname:"/"},o=t.method||"GET",a=t.headers.get?t.headers.get("user-agent"):void 0,i=t.headers.get?t.headers.get("x-forwarded-for"):void 0;return s.startTrace({method:o,path:r.pathname,userAgent:a,ip:i},async()=>{try{let u=await e(t,n),c=u?.status||200;return s.endTrace(c,{route:x(r.pathname)}),u}catch(u){throw s.captureError(u),s.endTrace(500,{route:x(r.pathname)}),u}})},K=e=>async(t,n)=>{let r=t.url?t.url.split("?")[0]:"/";return s.startTrace({method:t.method||"GET",path:r,userAgent:t.headers["user-agent"],ip:t.headers["x-forwarded-for"]||t.socket?.remoteAddress},async()=>{let o=()=>{s.endTrace(n.statusCode||200,{route:x(r)})};n.once("finish",o),n.once("close",o);try{return await e(t,n)}catch(a){throw s.captureError(a),a}})};var G=(e,t,n)=>{t&&t.apiKey&&s.init(t),e.addHook("onRequest",(r,o,a)=>{s.startTrace({method:r.method,path:r.raw.url||r.url,ip:r.ip,userAgent:r.headers["user-agent"]},()=>a())}),e.addHook("onError",(r,o,a,i)=>{s.captureError(a),i()}),e.addHook("onResponse",(r,o,a)=>{let i=r.routeOptions?.url||r.routerPath||"UNKNOWN";s.endTrace(o.statusCode,{route:i}),a()}),n()};var W={init:e=>s.init(e),flush:()=>s.flush(),track:s.track.bind(s),startSpan:s.startSpan.bind(s),captureException:s.captureError.bind(s),requestHandler:R,errorHandler:M,wrapNextRoute:D,wrapNextPages:K,wrapH3:U,fastifyPlugin:G},Ft=W;export{W as Senzor,Ft as default};
1
+ var b=(e=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(e,{get:(t,n)=>(typeof require<"u"?require:t)[n]}):e)(function(e){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+e+'" is not supported')});var E=class{constructor(t){this.config=t;this.queue=[];this.timer=null;typeof setInterval<"u"&&(this.timer=setInterval(()=>this.flush(),t.flushInterval||1e4),this.timer&&typeof this.timer.unref=="function"&&this.timer.unref())}add(t){this.queue.push(t),this.queue.length>=(this.config.batchSize||100)&&this.flush()}async flush(){if(this.queue.length===0)return;let t=[...this.queue];this.queue=[];try{await fetch(this.config.endpoint||"https://api.senzor.dev/api/ingest/apm",{method:"POST",headers:{"Content-Type":"application/json","x-service-api-key":this.config.apiKey},body:JSON.stringify(t),keepalive:!0}),this.config.debug&&console.log(`[Senzor] Flushed ${t.length} traces`)}catch(n){this.config.debug&&console.error("[Senzor] Ingestion Error:",n)}}};import{AsyncLocalStorage as W}from"async_hooks";var z=new W,l={run:(e,t)=>z.run(e,t),current:()=>z.getStore(),addSpan:e=>{let t=z.getStore();t&&t.spans.push(e)},setError:e=>{let t=z.getStore();t&&(t.error={name:e.name,message:e.message,stack:e.stack})}};import{randomUUID as C}from"crypto";import v from"http";import R from"https";import{URL as x}from"url";import{randomUUID as k}from"crypto";var I=(e,t,n)=>{if(!e[t])return;let r=e[t];e[t]=n(r)},N=(e,t=!1)=>{if(!globalThis.fetch)return;let n="";try{n=new x(e).hostname}catch{}let r=globalThis.fetch;globalThis.fetch=async(o,a)=>{let i="";if(typeof o=="string"?i=o:o instanceof x?i=o.toString():o&&o.url&&(i=o.url),n&&i.includes(n))return r(o,a);let u=l.current();if(!u)return r(o,a);let s=(a?.method||"GET").toUpperCase(),d=performance.now()-u.startTime,S=performance.now(),g=k(),y="unknown";try{y=new x(i).hostname}catch{}t&&console.log(`[Senzor] Fetch: ${s} ${y}`);let p={...a};p.headers||(p.headers={}),p.headers instanceof Headers?(p.headers.set("x-senzor-trace-id",u.id),p.headers.set("x-senzor-parent-span-id",g)):Array.isArray(p.headers)?(p.headers.push(["x-senzor-trace-id",u.id]),p.headers.push(["x-senzor-parent-span-id",g])):(p.headers["x-senzor-trace-id"]=u.id,p.headers["x-senzor-parent-span-id"]=g);try{let h=await r(o,p),m=performance.now()-S;return l.addSpan({spanId:g,name:`${s} ${y}`,type:"http",startTime:d,duration:m,status:h.status,meta:{url:i,method:s,library:"fetch"}}),h}catch(h){let m=performance.now()-S;throw l.addSpan({spanId:g,name:`${s} ${y}`,type:"http",startTime:d,duration:m,status:500,meta:{error:h.message,url:i,library:"fetch"}}),h}}},P=(e,t=!1)=>{let n="";try{n=new x(e).hostname}catch{}let r=o=>function(...a){let i={},u="";if(typeof a[0]=="string"||a[0]instanceof x)u=a[0].toString(),typeof a[1]=="object"&&a[1]!==null&&(i=a[1]);else{i=a[0]||{};let f=i.protocol||(i.port===443?"https:":"http:"),T=i.hostname||i.host||"localhost",w=i.path||"/";u=`${f}//${T}${w}`}if(n&&(u.includes(n)||i.hostname&&i.hostname.includes(n)))return o.apply(this,a);let s=l.current();if(!s)return o.apply(this,a);let d=(i.method||"GET").toUpperCase(),S=performance.now()-s.startTime,g=performance.now(),y=k(),p="unknown";try{p=new x(u).hostname}catch{p=i.hostname||"unknown"}i.headers||(i.headers={}),i.headers["x-senzor-trace-id"]=s.id,i.headers["x-senzor-parent-span-id"]=y;let h=o.apply(this,a),m=(f,T)=>{let w=performance.now()-g;l.addSpan({spanId:y,name:`${d} ${p}`,type:"http",startTime:S,duration:w,status:T?500:f?.statusCode||0,meta:{url:u,method:d,library:"http"}})};return h.on("response",f=>{f.once("end",()=>m(f)),f.once("close",()=>m(f)),f.once("error",T=>m(f,T))}),h.on("error",f=>m(null,f)),h};I(v,"request",r),I(v,"get",r),I(R,"request",r),I(R,"get",r)};var H=(e=!1)=>{try{let t=b("mongodb"),n=t.Collection,r=t.FindCursor||b("mongodb/lib/cursor/find_cursor").FindCursor,o=t.AggregationCursor||b("mongodb/lib/cursor/aggregation_cursor").AggregationCursor;e&&console.log("[Senzor] Instrumenting MongoDB (Collection + Cursors)...");let a=(s,d,S,g,y,p)=>{let h=performance.now()-g;l.addSpan({name:`MongoDB ${s}`,type:"db",startTime:performance.now()-y-h,duration:h,status:p?500:0,meta:{collection:S,operation:d,error:p?p.message:void 0}}),e&&console.log(`[Senzor] Captured Mongo: ${s} (${h.toFixed(2)}ms)`)};["insertOne","insertMany","updateOne","updateMany","deleteOne","deleteMany","countDocuments"].forEach(s=>{if(!n.prototype[s])return;let d=n.prototype[s];n.prototype[s]=function(...S){let g=l.current();if(!g)return d.apply(this,S);let y=performance.now(),p=g.startTime,h=this.collectionName;try{let m=d.apply(this,S);return m&&typeof m.then=="function"?m.then(f=>(a(s,s,h,y,p),f),f=>{throw a(s,s,h,y,p,f),f}):m}catch(m){throw a(s,s,h,y,p,m),m}}});let u=(s,d)=>{if(!s||!s.prototype.toArray)return;let S=s.prototype.toArray;s.prototype.toArray=function(...g){let y=l.current();if(!y)return S.apply(this,g);let p=performance.now(),h=y.startTime,m=this.namespace?.collection||"unknown",f=w=>(a(d,d,m,p,h),w),T=w=>{throw a(d,d,m,p,h,w),w};try{let w=S.apply(this,g);return w&&typeof w.then=="function"?w.then(f,T):f(w)}catch(w){T(w)}}};u(r,"find"),u(o,"aggregate")}catch(t){e&&console.warn("[Senzor] MongoDB instrumentation warning:",t.message)}};var $=()=>{try{let e=b("pg"),t=e.Client.prototype.query;e.Client.prototype.query=function(...n){let r=l.current();if(!r)return t.apply(this,n);let o=performance.now()-r.startTime,a=performance.now(),i=typeof n[0]=="string"?n[0]:n[0].text,u=t.apply(this,n);return u&&typeof u.then=="function"?u.then(s=>{let d=performance.now()-a;return l.addSpan({name:"Postgres Query",type:"db",startTime:o,duration:d,meta:{query:i}}),s}):u}}catch{}};var F=class{constructor(){this.transport=null;this.options=null;this.isInstrumented=!1}init(t){if(!t.apiKey){console.warn("[Senzor] API Key missing. SDK disabled.");return}this.options=t;let n=t.endpoint||"https://api.senzor.dev/api/ingest/apm",r=t.debug||!1;if(this.transport=new E({...t,endpoint:n}),!this.isInstrumented){try{P(n,r)}catch{}try{N(n,r)}catch{}try{H(r)}catch{}try{$()}catch{}this.isInstrumented=!0,r&&console.log("[Senzor] Auto-instrumentation enabled")}}startTrace(t,n){if(!this.transport)return n();let r,o;t.headers&&(r=t.headers["x-senzor-trace-id"]||t.headers["X-SENZOR-TRACE-ID"],o=t.headers["x-senzor-parent-span-id"]||t.headers["X-SENZOR-PARENT-SPAN-ID"]);let a={id:C(),startTime:performance.now(),data:{...t,parentTraceId:r,parentSpanId:o},spans:[]};return l.run(a,n)}endTrace(t,n={}){let r=l.current();if(!r||!this.transport)return;let o=performance.now()-r.startTime,a={traceId:r.id,parentTraceId:r.data.parentTraceId,parentSpanId:r.data.parentSpanId,...r.data,...n,status:t,duration:o,spans:r.spans,timestamp:new Date().toISOString(),error:r.error};this.transport.add(a)}captureError(t){t instanceof Error?l.setError(t):typeof t=="string"&&l.setError(new Error(t))}track(t){this.transport?.add({traceId:C(),...t,spans:[],timestamp:new Date().toISOString()})}startSpan(t,n="custom"){let r=l.current();if(!r)return{end:()=>{}};let o=performance.now()-r.startTime,a=performance.now(),i=C();return{end:(u,s)=>{let d=performance.now()-a;l.addSpan({spanId:i,name:t,type:n,startTime:o,duration:d,status:s,meta:u})}}}async flush(){this.transport&&await this.transport.flush()}},c=new F;var U=()=>(e,t,n)=>{c.startTrace({method:e.method,path:e.originalUrl||e.url,ip:e.ip||e.socket?.remoteAddress,userAgent:e.headers["user-agent"],headers:e.headers},()=>{t.once("finish",()=>{try{let r="UNKNOWN";e.route&&e.route.path?r=(e.baseUrl||"")+e.route.path:t.statusCode===404?r="Not Found":r=e.path||"Wildcard",c.endTrace(t.statusCode,{route:r})}catch{}}),n()})},M=()=>(e,t,n,r)=>{c.captureError(e),r(e)};var A=e=>!e||e==="/"?"/":e.replace(/[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}/g,":uuid").replace(/[0-9a-fA-F]{24}/g,":objectId").replace(/\/(\d+)(?=\/|$)/g,"/:id").split("?")[0],O=(e,t)=>e.route&&e.route.path?(e.baseUrl||"")+e.route.path:e.context&&e.context.matchedRoute?e.context.matchedRoute.path:e.routerPath?e.routerPath:A(t);var D=e=>t=>{let n=t.node.req,r=n.originalUrl||n.url||"/";return c.startTrace({method:n.method||"GET",path:r,ip:n.headers["x-forwarded-for"]||n.socket?.remoteAddress,userAgent:n.headers["user-agent"],headers:n.headers},async()=>{try{let o=await e(t),a=200;return t.node.res.statusCode&&(a=t.node.res.statusCode),o&&o.statusCode&&(a=o.statusCode),c.endTrace(a,{route:O(t,r)}),o}catch(o){c.captureError(o);let a=o.statusCode||o.status||500;throw c.endTrace(a,{route:O(t,r)}),o}})};var K=e=>async(t,n)=>{let r=t.url?new URL(t.url):{pathname:"/"},o=t.method||"GET",a={},i,u;return typeof t.headers.get=="function"?(i=t.headers.get("user-agent"),u=t.headers.get("x-forwarded-for"),t.headers.forEach((s,d)=>{a[d]=s})):(a=t.headers,i=a["user-agent"],u=a["x-forwarded-for"]),c.startTrace({method:o,path:r.pathname,userAgent:i,ip:u,headers:a},async()=>{try{let s=await e(t,n),d=s?.status||200;return c.endTrace(d,{route:A(r.pathname)}),s}catch(s){throw c.captureError(s),c.endTrace(500,{route:A(r.pathname)}),s}})},G=e=>async(t,n)=>{let r=t.url?t.url.split("?")[0]:"/";return c.startTrace({method:t.method||"GET",path:r,userAgent:t.headers["user-agent"],ip:t.headers["x-forwarded-for"]||t.socket?.remoteAddress,headers:t.headers},async()=>{let o=()=>{c.endTrace(n.statusCode||200,{route:A(r)})};n.once("finish",o),n.once("close",o);try{return await e(t,n)}catch(a){throw c.captureError(a),a}})};var L=(e,t,n)=>{t&&t.apiKey&&c.init(t),e.addHook("onRequest",(r,o,a)=>{c.startTrace({method:r.method,path:r.raw.url||r.url,ip:r.ip,userAgent:r.headers["user-agent"],headers:r.headers},()=>a())}),e.addHook("onError",(r,o,a,i)=>{c.captureError(a),i()}),e.addHook("onResponse",(r,o,a)=>{let i=r.routeOptions?.url||r.routerPath||"UNKNOWN";c.endTrace(o.statusCode,{route:i}),a()}),n()};var j={init:e=>c.init(e),flush:()=>c.flush(),track:c.track.bind(c),startSpan:c.startSpan.bind(c),captureException:c.captureError.bind(c),requestHandler:U,errorHandler:M,wrapNextRoute:K,wrapNextPages:G,wrapH3:D,fastifyPlugin:L},Ft=j;export{j as Senzor,Ft as default};
2
2
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/core/transport.ts","../src/core/context.ts","../src/core/client.ts","../src/instrumentation/http.ts","../src/instrumentation/mongo.ts","../src/instrumentation/pg.ts","../src/middleware/express.ts","../src/core/normalizer.ts","../src/wrappers/h3.ts","../src/wrappers/next.ts","../src/wrappers/fastify.ts","../src/index.ts"],"sourcesContent":["import { SenzorOptions } from './types';\r\n\r\nexport class Transport {\r\n private queue: any[] = [];\r\n private timer: NodeJS.Timeout | null = null;\r\n\r\n constructor(private config: SenzorOptions) {\r\n if (typeof setInterval !== 'undefined') {\r\n this.timer = setInterval(() => this.flush(), config.flushInterval || 10000);\r\n if (this.timer && typeof this.timer.unref === 'function') {\r\n this.timer.unref(); // Don't block process exit\r\n }\r\n }\r\n }\r\n\r\n public add(trace: any) {\r\n this.queue.push(trace);\r\n if (this.queue.length >= (this.config.batchSize || 100)) {\r\n this.flush();\r\n }\r\n }\r\n\r\n public async flush() {\r\n if (this.queue.length === 0) return;\r\n\r\n const batch = [...this.queue];\r\n this.queue = [];\r\n\r\n try {\r\n // Use global fetch (Node 18+)\r\n await fetch(this.config.endpoint || 'https://api.senzor.dev/api/ingest/apm', {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n 'x-service-api-key': this.config.apiKey,\r\n },\r\n body: JSON.stringify(batch),\r\n keepalive: true,\r\n });\r\n \r\n if (this.config.debug) console.log(`[Senzor] Flushed ${batch.length} traces`);\r\n } catch (err) {\r\n if (this.config.debug) console.error('[Senzor] Ingestion Error:', err);\r\n // Dropping data to prevent memory leaks is preferred in APM\r\n }\r\n }\r\n}","import { AsyncLocalStorage } from 'async_hooks';\r\nimport { ActiveTrace, TraceError } from './types';\r\n\r\nexport const storage = new AsyncLocalStorage<ActiveTrace>();\r\n\r\nexport const Context = {\r\n run: <T>(trace: ActiveTrace, fn: () => T): T => {\r\n return storage.run(trace, fn);\r\n },\r\n\r\n current: (): ActiveTrace | undefined => {\r\n return storage.getStore();\r\n },\r\n\r\n addSpan: (span: any) => {\r\n const store = storage.getStore();\r\n if (store) {\r\n store.spans.push(span);\r\n }\r\n },\r\n\r\n // Attach error to current trace\r\n setError: (error: Error) => {\r\n const store = storage.getStore();\r\n if (store) {\r\n store.error = {\r\n name: error.name,\r\n message: error.message,\r\n stack: error.stack\r\n };\r\n }\r\n }\r\n};","import { Transport } from './transport';\r\nimport { Context } from './context';\r\nimport { SenzorOptions, ActiveTrace } from './types';\r\nimport { randomUUID } from 'crypto';\r\nimport { instrumentHttp, instrumentFetch } from '../instrumentation/http';\r\nimport { instrumentMongo } from '../instrumentation/mongo';\r\nimport { instrumentPg } from '../instrumentation/pg';\r\n\r\nexport class SenzorClient {\r\n private transport: Transport | null = null;\r\n private options: SenzorOptions | null = null;\r\n private isInstrumented = false;\r\n\r\n public init(options: SenzorOptions) {\r\n if (!options.apiKey) {\r\n console.warn('[Senzor] API Key missing. SDK disabled.');\r\n return;\r\n }\r\n this.options = options;\r\n const endpoint = options.endpoint || 'https://api.senzor.dev/api/ingest/apm';\r\n const debug = options.debug || false;\r\n\r\n this.transport = new Transport({ ...options, endpoint });\r\n\r\n if (!this.isInstrumented) {\r\n try { instrumentHttp(endpoint, debug); } catch (e) { }\r\n try { instrumentFetch(endpoint, debug); } catch (e) { }\r\n try { instrumentMongo(debug); } catch (e) { }\r\n try { instrumentPg(); } catch (e) { }\r\n\r\n this.isInstrumented = true;\r\n if (debug) console.log('[Senzor] Auto-instrumentation enabled');\r\n }\r\n }\r\n\r\n public startTrace<T>(data: Partial<ActiveTrace['data']>, next: () => T): T {\r\n if (!this.transport) return next();\r\n const trace: ActiveTrace = {\r\n id: randomUUID(),\r\n startTime: performance.now(),\r\n data: data,\r\n spans: []\r\n };\r\n return Context.run(trace, next);\r\n }\r\n\r\n public endTrace(status: number, extraData: any = {}) {\r\n const trace = Context.current();\r\n if (!trace || !this.transport) return;\r\n\r\n const duration = performance.now() - trace.startTime;\r\n\r\n const payload = {\r\n traceId: trace.id,\r\n ...trace.data,\r\n ...extraData,\r\n status,\r\n duration,\r\n spans: trace.spans,\r\n error: trace.error, // Include Error if captured\r\n timestamp: new Date().toISOString()\r\n };\r\n\r\n this.transport.add(payload);\r\n }\r\n\r\n // --- NEW: Capture Exception ---\r\n public captureError(error: unknown) {\r\n if (error instanceof Error) {\r\n Context.setError(error);\r\n } else if (typeof error === 'string') {\r\n Context.setError(new Error(error));\r\n }\r\n }\r\n\r\n // ... (manual track, startSpan, flush remain same) ...\r\n public track(data: any) { this.transport?.add({ traceId: randomUUID(), ...data, spans: [], timestamp: new Date().toISOString() }); }\r\n\r\n public startSpan(name: string, type: 'db' | 'http' | 'function' | 'custom' = 'custom') {\r\n const trace = Context.current();\r\n if (!trace) return { end: () => { } };\r\n const startTime = performance.now() - trace.startTime;\r\n const spanStartAbs = performance.now();\r\n return { end: (meta?: any, status?: number) => { Context.addSpan({ name, type, startTime, duration: performance.now() - spanStartAbs, status, meta }); } };\r\n }\r\n\r\n public async flush() { if (this.transport) await this.transport.flush(); }\r\n}\r\n\r\nexport const client = new SenzorClient();","import http from 'http';\r\nimport https from 'https';\r\nimport { URL } from 'url';\r\nimport { Context } from '../core/context';\r\n\r\nconst shimmer = (module: any, methodName: string, wrapper: (original: Function) => Function) => {\r\n if (!module[methodName]) return;\r\n const original = module[methodName];\r\n module[methodName] = wrapper(original);\r\n};\r\n\r\n// --- Native Fetch Instrumentation (Node 18+) ---\r\nexport const instrumentFetch = (ingestUrl: string, debug = false) => {\r\n if (!globalThis.fetch) return;\r\n\r\n let ingestHost = '';\r\n try { ingestHost = new URL(ingestUrl).hostname; } catch (e) { }\r\n\r\n const originalFetch = globalThis.fetch;\r\n\r\n // @ts-ignore\r\n globalThis.fetch = async (input: RequestInfo | URL, init?: RequestInit) => {\r\n // 1. Extract URL\r\n let urlStr = '';\r\n if (typeof input === 'string') urlStr = input;\r\n else if (input instanceof URL) urlStr = input.toString();\r\n else if (input && input.url) urlStr = input.url; // Request object\r\n\r\n // 2. Infinite Loop Guard\r\n if (ingestHost && urlStr.includes(ingestHost)) {\r\n return originalFetch(input, init);\r\n }\r\n\r\n // 3. Context Check\r\n const trace = Context.current();\r\n if (!trace) {\r\n return originalFetch(input, init);\r\n }\r\n\r\n // 4. Start Span\r\n const method = (init?.method || 'GET').toUpperCase();\r\n const startTime = performance.now() - trace.startTime;\r\n const spanStartAbs = performance.now();\r\n let hostname = 'unknown';\r\n try { hostname = new URL(urlStr).hostname; } catch (e) { }\r\n\r\n if (debug) console.log(`[Senzor] Tracking Fetch: ${method} ${hostname}`);\r\n\r\n try {\r\n const response = await originalFetch(input, init);\r\n\r\n // 5. End Span\r\n const duration = performance.now() - spanStartAbs;\r\n Context.addSpan({\r\n name: `${method} ${hostname}`,\r\n type: 'http',\r\n startTime,\r\n duration,\r\n status: response.status,\r\n meta: { url: urlStr, method, library: 'fetch' }\r\n });\r\n\r\n return response;\r\n } catch (err: any) {\r\n const duration = performance.now() - spanStartAbs;\r\n Context.addSpan({\r\n name: `${method} ${hostname}`,\r\n type: 'http',\r\n startTime,\r\n duration,\r\n status: 500,\r\n meta: { error: err.message, url: urlStr, library: 'fetch' }\r\n });\r\n throw err;\r\n }\r\n };\r\n};\r\n\r\n// --- Standard HTTP/HTTPS Instrumentation ---\r\nexport const instrumentHttp = (ingestUrl: string, debug = false) => {\r\n let ingestHost = '';\r\n try {\r\n ingestHost = new URL(ingestUrl).hostname;\r\n } catch (e) { }\r\n\r\n const requestWrapper = (original: Function) => {\r\n return function (this: any, ...args: any[]) {\r\n let options: any = {};\r\n let urlStr = '';\r\n\r\n if (typeof args[0] === 'string' || args[0] instanceof URL) {\r\n urlStr = args[0].toString();\r\n if (typeof args[1] === 'object' && args[1] !== null) options = args[1];\r\n } else {\r\n options = args[0] || {};\r\n const protocol = options.protocol || (options.port === 443 ? 'https:' : 'http:');\r\n const host = options.hostname || options.host || 'localhost';\r\n const path = options.path || '/';\r\n urlStr = `${protocol}//${host}${path}`;\r\n }\r\n\r\n if (ingestHost && (urlStr.includes(ingestHost) || (options.hostname && options.hostname.includes(ingestHost)))) {\r\n return original.apply(this, args);\r\n }\r\n\r\n const trace = Context.current();\r\n if (!trace) return original.apply(this, args);\r\n\r\n const method = (options.method || 'GET').toUpperCase();\r\n const startTime = performance.now() - trace.startTime;\r\n const spanStartAbs = performance.now();\r\n let hostname = 'unknown';\r\n try { hostname = new URL(urlStr).hostname; } catch (e) { hostname = options.hostname || 'unknown'; }\r\n\r\n const req = original.apply(this, args);\r\n\r\n const captureSpan = (res: any, error?: Error) => {\r\n const duration = performance.now() - spanStartAbs;\r\n Context.addSpan({\r\n name: `${method} ${hostname}`,\r\n type: 'http',\r\n startTime,\r\n duration,\r\n status: error ? 500 : res?.statusCode || 0,\r\n meta: { url: urlStr, method, library: 'http', error: error ? error.message : undefined }\r\n });\r\n };\r\n\r\n req.on('response', (res: any) => {\r\n res.once('end', () => captureSpan(res));\r\n res.once('error', (err: Error) => captureSpan(res, err));\r\n });\r\n\r\n req.on('error', (err: Error) => captureSpan(null, err));\r\n\r\n return req;\r\n };\r\n };\r\n\r\n shimmer(http, 'request', requestWrapper);\r\n shimmer(http, 'get', requestWrapper);\r\n shimmer(https, 'request', requestWrapper);\r\n shimmer(https, 'get', requestWrapper);\r\n};","import { Context } from '../core/context';\r\n\r\nexport const instrumentMongo = (debug = false) => {\r\n try {\r\n const mongodb = require('mongodb');\r\n const Collection = mongodb.Collection;\r\n\r\n // Attempt to get Cursor classes\r\n // Note: The location of these classes varies by driver version, \r\n // checking common locations\r\n const FindCursor = mongodb.FindCursor || require('mongodb/lib/cursor/find_cursor').FindCursor;\r\n const AggregationCursor = mongodb.AggregationCursor || require('mongodb/lib/cursor/aggregation_cursor').AggregationCursor;\r\n\r\n if (debug) console.log('[Senzor] Instrumenting MongoDB (Collection + Cursors)...');\r\n\r\n // --- Helper to Record Span ---\r\n const recordSpan = (name: string, operation: string, collection: string, startAbs: number, traceStart: number, err?: Error) => {\r\n const duration = performance.now() - startAbs;\r\n Context.addSpan({\r\n name: `MongoDB ${name}`,\r\n type: 'db',\r\n startTime: performance.now() - traceStart - duration, // Adjust start time to when op actually started\r\n duration,\r\n status: err ? 500 : 0,\r\n meta: { collection, operation, error: err ? err.message : undefined }\r\n });\r\n if (debug) console.log(`[Senzor] Captured Mongo: ${name} (${duration.toFixed(2)}ms)`);\r\n };\r\n\r\n // --- 1. Instrument Immediate Operations (Insert/Update/Delete) ---\r\n const immediateMethods = ['insertOne', 'insertMany', 'updateOne', 'updateMany', 'deleteOne', 'deleteMany', 'countDocuments'];\r\n\r\n immediateMethods.forEach((method) => {\r\n if (!Collection.prototype[method]) return;\r\n const original = Collection.prototype[method];\r\n\r\n Collection.prototype[method] = function (...args: any[]) {\r\n const trace = Context.current();\r\n if (!trace) return original.apply(this, args);\r\n\r\n const spanStartAbs = performance.now();\r\n const traceStart = trace.startTime;\r\n const collName = this.collectionName;\r\n\r\n try {\r\n const result = original.apply(this, args);\r\n if (result && typeof result.then === 'function') {\r\n return result.then(\r\n (res: any) => { recordSpan(method, method, collName, spanStartAbs, traceStart); return res; },\r\n (err: any) => { recordSpan(method, method, collName, spanStartAbs, traceStart, err); throw err; }\r\n );\r\n }\r\n return result;\r\n } catch (err: any) {\r\n recordSpan(method, method, collName, spanStartAbs, traceStart, err);\r\n throw err;\r\n }\r\n };\r\n });\r\n\r\n // --- 2. Instrument Cursor Execution (find -> toArray) ---\r\n const patchCursor = (CursorClass: any, label: string) => {\r\n if (!CursorClass || !CursorClass.prototype.toArray) return;\r\n\r\n const originalToArray = CursorClass.prototype.toArray;\r\n\r\n CursorClass.prototype.toArray = function (...args: any[]) {\r\n const trace = Context.current();\r\n // Cursors are often created in context but executed later. \r\n // We check context at execution time.\r\n if (!trace) return originalToArray.apply(this, args);\r\n\r\n const spanStartAbs = performance.now();\r\n const traceStart = trace.startTime;\r\n // Attempt to get collection name from cursor internal state\r\n const collName = this.namespace?.collection || 'unknown';\r\n\r\n const onSuccess = (res: any) => {\r\n recordSpan(label, label, collName, spanStartAbs, traceStart);\r\n return res;\r\n };\r\n const onError = (err: any) => {\r\n recordSpan(label, label, collName, spanStartAbs, traceStart, err);\r\n throw err;\r\n };\r\n\r\n try {\r\n const result = originalToArray.apply(this, args);\r\n if (result && typeof result.then === 'function') {\r\n return result.then(onSuccess, onError);\r\n }\r\n return onSuccess(result);\r\n } catch (e) {\r\n onError(e);\r\n }\r\n };\r\n };\r\n\r\n patchCursor(FindCursor, 'find');\r\n patchCursor(AggregationCursor, 'aggregate');\r\n\r\n } catch (e: any) {\r\n if (debug) console.warn('[Senzor] MongoDB instrumentation warning:', e.message);\r\n }\r\n};","import { Context } from '../core/context';\r\n\r\n// Simple shim for 'pg' library\r\nexport const instrumentPg = () => {\r\n try {\r\n // Try to require pg (it might not be installed by user)\r\n const pg = require('pg');\r\n const originalQuery = pg.Client.prototype.query;\r\n\r\n pg.Client.prototype.query = function (...args: any[]) {\r\n const trace = Context.current();\r\n if (!trace) return originalQuery.apply(this, args);\r\n\r\n const startTime = performance.now() - trace.startTime;\r\n const spanStartAbs = performance.now();\r\n\r\n // Extract SQL (first arg usually string or config object)\r\n const sql = typeof args[0] === 'string' ? args[0] : args[0].text;\r\n\r\n // Wrap callback if present, or handle Promise\r\n const result = originalQuery.apply(this, args);\r\n\r\n if (result && typeof result.then === 'function') {\r\n return result.then((res: any) => {\r\n const duration = performance.now() - spanStartAbs;\r\n Context.addSpan({\r\n name: 'Postgres Query',\r\n type: 'db',\r\n startTime,\r\n duration,\r\n meta: { query: sql }\r\n });\r\n return res;\r\n });\r\n }\r\n return result;\r\n };\r\n } catch (e) {\r\n // User doesn't use pg, ignore\r\n }\r\n};","import { client } from '../core/client';\r\n\r\n// 1. Request Handler (Place before routes)\r\nexport const expressMiddleware = () => {\r\n return (req: any, res: any, next: () => void) => {\r\n client.startTrace({\r\n method: req.method,\r\n path: req.originalUrl || req.url,\r\n ip: req.ip || req.socket?.remoteAddress,\r\n userAgent: req.headers['user-agent'],\r\n }, () => {\r\n\r\n // Auto-detect status code on finish\r\n res.once('finish', () => {\r\n try {\r\n let route = 'UNKNOWN';\r\n // Express populates req.route only if a route matched\r\n if (req.route && req.route.path) {\r\n route = (req.baseUrl || '') + req.route.path;\r\n } else if (res.statusCode === 404) {\r\n route = 'Not Found';\r\n } else {\r\n route = req.path || 'Wildcard';\r\n }\r\n\r\n client.endTrace(res.statusCode, { route });\r\n } catch (e) { /* Fail open */ }\r\n });\r\n\r\n next();\r\n });\r\n };\r\n};\r\n\r\n// 2. Error Handler (Place after routes)\r\n// This is required in Express to capture the actual Error Object (Stack Trace)\r\nexport const expressErrorHandler = () => {\r\n return (err: any, req: any, res: any, next: (err?: any) => void) => {\r\n\r\n // 1. Capture the exception context\r\n client.captureError(err);\r\n\r\n // 2. Pass it to the next error handler (don't swallow it)\r\n next(err);\r\n };\r\n};","/**\r\n * Heuristic URL Normalizer\r\n * Converts raw paths with IDs into generic patterns to prevent high cardinality.\r\n * Example: /users/123/orders/abc-def -> /users/:id/orders/:uuid\r\n */\r\nexport const normalizePath = (path: string): string => {\r\n if (!path || path === '/') return '/';\r\n\r\n return path\r\n // Replace UUIDs (long alphanumeric strings)\r\n .replace(\r\n /[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}/g,\r\n ':uuid'\r\n )\r\n // Replace MongoDB ObjectIds (24 hex chars)\r\n .replace(/[0-9a-fA-F]{24}/g, ':objectId')\r\n // Replace pure numeric IDs (e.g., /123)\r\n .replace(/\\/(\\d+)(?=\\/|$)/g, '/:id')\r\n // Remove query strings\r\n .split('?')[0];\r\n};\r\n\r\n/**\r\n * Tries to extract route from Framework internals, falls back to heuristic\r\n */\r\nexport const getRoute = (req: any, fallbackPath: string): string => {\r\n // Express / Connect\r\n if (req.route && req.route.path) {\r\n return (req.baseUrl || '') + req.route.path;\r\n }\r\n\r\n // H3 / Nitro (Nuxt)\r\n if (req.context && req.context.matchedRoute) {\r\n return req.context.matchedRoute.path;\r\n }\r\n\r\n // Fastify\r\n if (req.routerPath) {\r\n return req.routerPath;\r\n }\r\n\r\n // Fallback: Heuristic Normalization\r\n return normalizePath(fallbackPath);\r\n};","import { client } from '../core/client';\r\nimport { getRoute } from '../core/normalizer';\r\n\r\ntype EventHandler = (event: any) => any;\r\n\r\nexport const wrapH3 = (handler: EventHandler) => {\r\n return (event: any) => {\r\n const req = event.node.req;\r\n const path = req.originalUrl || req.url || '/';\r\n\r\n return client.startTrace({\r\n method: req.method || 'GET',\r\n path: path,\r\n ip: req.headers['x-forwarded-for'] || req.socket?.remoteAddress,\r\n userAgent: req.headers['user-agent'],\r\n }, async () => {\r\n try {\r\n const response = await handler(event);\r\n let status = 200;\r\n if (event.node.res.statusCode) status = event.node.res.statusCode;\r\n if (response && response.statusCode) status = response.statusCode;\r\n\r\n client.endTrace(status, { route: getRoute(event, path) });\r\n return response;\r\n } catch (err: any) {\r\n // AUTOMATIC ERROR CAPTURE\r\n client.captureError(err);\r\n\r\n const status = err.statusCode || err.status || 500;\r\n client.endTrace(status, { route: getRoute(event, path) });\r\n throw err;\r\n }\r\n });\r\n };\r\n};","import { client } from '../core/client';\r\nimport { normalizePath } from '../core/normalizer';\r\n\r\n// --- App Router Wrapper ---\r\nexport const wrapNextRoute = (handler: Function) => {\r\n return async (req: Request | any, context?: any) => {\r\n const url = req.url ? new URL(req.url) : { pathname: '/' };\r\n const method = req.method || 'GET';\r\n const ua = req.headers.get ? req.headers.get('user-agent') : undefined;\r\n const ip = req.headers.get ? req.headers.get('x-forwarded-for') : undefined;\r\n\r\n return client.startTrace({\r\n method,\r\n path: url.pathname,\r\n userAgent: ua,\r\n ip: ip\r\n }, async () => {\r\n try {\r\n const response = await handler(req, context);\r\n const status = response?.status || 200;\r\n client.endTrace(status, { route: normalizePath(url.pathname) });\r\n return response;\r\n } catch (err: any) {\r\n // AUTOMATIC ERROR CAPTURE\r\n client.captureError(err);\r\n client.endTrace(500, { route: normalizePath(url.pathname) });\r\n throw err; // Re-throw so Next.js handles the error page\r\n }\r\n });\r\n };\r\n};\r\n\r\n// --- Pages Router Wrapper ---\r\nexport const wrapNextPages = (handler: Function) => {\r\n return async (req: any, res: any) => {\r\n const path = req.url ? req.url.split('?')[0] : '/';\r\n\r\n return client.startTrace({\r\n method: req.method || 'GET',\r\n path: path,\r\n userAgent: req.headers['user-agent'],\r\n ip: req.headers['x-forwarded-for'] || req.socket?.remoteAddress,\r\n }, async () => {\r\n\r\n const done = () => {\r\n client.endTrace(res.statusCode || 200, { route: normalizePath(path) });\r\n };\r\n\r\n res.once('finish', done);\r\n res.once('close', done);\r\n\r\n try {\r\n return await handler(req, res);\r\n } catch (e: any) {\r\n // AUTOMATIC ERROR CAPTURE\r\n client.captureError(e);\r\n // Note: In Pages dir, we rely on 'finish' listener above to close trace, \r\n // but capturing here ensures the error data is attached.\r\n throw e;\r\n }\r\n });\r\n };\r\n};","import { client } from '../core/client';\r\nimport { SenzorOptions } from '../core/types';\r\n\r\nexport const senzorPlugin = (fastify: any, options: SenzorOptions, done: Function) => {\r\n\r\n if (options && options.apiKey) {\r\n client.init(options);\r\n }\r\n\r\n // 1. Start Trace\r\n fastify.addHook('onRequest', (request: any, reply: any, next: Function) => {\r\n // FIX: Wrap next in a closure to satisfy TS types\r\n client.startTrace({\r\n method: request.method,\r\n path: request.raw.url || request.url,\r\n ip: request.ip,\r\n userAgent: request.headers['user-agent']\r\n }, () => next());\r\n });\r\n\r\n // 2. Capture Errors\r\n fastify.addHook('onError', (request: any, reply: any, error: any, next: Function) => {\r\n client.captureError(error);\r\n next();\r\n });\r\n\r\n // 3. End Trace\r\n fastify.addHook('onResponse', (request: any, reply: any, next: Function) => {\r\n const route = request.routeOptions?.url || request.routerPath || 'UNKNOWN';\r\n client.endTrace(reply.statusCode, { route });\r\n next();\r\n });\r\n\r\n done();\r\n};","import { client } from './core/client';\r\nimport { expressMiddleware, expressErrorHandler } from './middleware/express';\r\nimport { wrapH3 } from './wrappers/h3';\r\nimport { wrapNextRoute, wrapNextPages } from './wrappers/next';\r\nimport { senzorPlugin } from './wrappers/fastify';\r\nimport { SenzorOptions } from './core/types';\r\n\r\nconst Senzor = {\r\n init: (options: SenzorOptions) => client.init(options),\r\n flush: () => client.flush(),\r\n track: client.track.bind(client),\r\n startSpan: client.startSpan.bind(client),\r\n captureException: client.captureError.bind(client),\r\n\r\n // Express\r\n requestHandler: expressMiddleware,\r\n errorHandler: expressErrorHandler,\r\n\r\n // Next\r\n wrapNextRoute,\r\n wrapNextPages,\r\n\r\n // H3\r\n wrapH3,\r\n\r\n // Fastify\r\n fastifyPlugin: senzorPlugin\r\n};\r\n\r\nexport default Senzor;\r\nexport { Senzor };"],"mappings":"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","names":["Transport","config","trace","batch","err","AsyncLocalStorage","storage","Context","trace","fn","span","store","error","randomUUID","http","https","URL","shimmer","module","methodName","wrapper","original","instrumentFetch","ingestUrl","debug","ingestHost","URL","originalFetch","input","init","urlStr","trace","Context","method","startTime","spanStartAbs","hostname","response","duration","err","instrumentHttp","requestWrapper","args","options","protocol","host","path","req","captureSpan","res","error","http","https","instrumentMongo","debug","mongodb","Collection","FindCursor","AggregationCursor","recordSpan","name","operation","collection","startAbs","traceStart","err","duration","Context","method","original","args","trace","spanStartAbs","collName","result","res","patchCursor","CursorClass","label","originalToArray","onSuccess","onError","e","instrumentPg","pg","originalQuery","args","trace","Context","startTime","spanStartAbs","sql","result","res","duration","SenzorClient","options","endpoint","debug","Transport","instrumentHttp","instrumentFetch","instrumentMongo","instrumentPg","data","next","trace","randomUUID","Context","status","extraData","duration","payload","error","name","type","startTime","spanStartAbs","meta","client","expressMiddleware","req","res","next","client","route","expressErrorHandler","err","normalizePath","path","getRoute","req","fallbackPath","wrapH3","handler","event","req","path","client","response","status","getRoute","err","wrapNextRoute","handler","req","context","url","method","ua","ip","client","response","status","normalizePath","err","wrapNextPages","res","path","done","e","senzorPlugin","fastify","options","done","client","request","reply","next","error","route","Senzor","options","client","expressMiddleware","expressErrorHandler","wrapNextRoute","wrapNextPages","wrapH3","senzorPlugin","index_default"]}
1
+ {"version":3,"sources":["../src/core/transport.ts","../src/core/context.ts","../src/core/client.ts","../src/instrumentation/http.ts","../src/instrumentation/mongo.ts","../src/instrumentation/pg.ts","../src/middleware/express.ts","../src/core/normalizer.ts","../src/wrappers/h3.ts","../src/wrappers/next.ts","../src/wrappers/fastify.ts","../src/index.ts"],"sourcesContent":["import { SenzorOptions } from './types';\r\n\r\nexport class Transport {\r\n private queue: any[] = [];\r\n private timer: NodeJS.Timeout | null = null;\r\n\r\n constructor(private config: SenzorOptions) {\r\n if (typeof setInterval !== 'undefined') {\r\n this.timer = setInterval(() => this.flush(), config.flushInterval || 10000);\r\n if (this.timer && typeof this.timer.unref === 'function') {\r\n this.timer.unref(); // Don't block process exit\r\n }\r\n }\r\n }\r\n\r\n public add(trace: any) {\r\n this.queue.push(trace);\r\n if (this.queue.length >= (this.config.batchSize || 100)) {\r\n this.flush();\r\n }\r\n }\r\n\r\n public async flush() {\r\n if (this.queue.length === 0) return;\r\n\r\n const batch = [...this.queue];\r\n this.queue = [];\r\n\r\n try {\r\n // Use global fetch (Node 18+)\r\n await fetch(this.config.endpoint || 'https://api.senzor.dev/api/ingest/apm', {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n 'x-service-api-key': this.config.apiKey,\r\n },\r\n body: JSON.stringify(batch),\r\n keepalive: true,\r\n });\r\n \r\n if (this.config.debug) console.log(`[Senzor] Flushed ${batch.length} traces`);\r\n } catch (err) {\r\n if (this.config.debug) console.error('[Senzor] Ingestion Error:', err);\r\n // Dropping data to prevent memory leaks is preferred in APM\r\n }\r\n }\r\n}","import { AsyncLocalStorage } from 'async_hooks';\r\nimport { ActiveTrace, TraceError } from './types';\r\n\r\nexport const storage = new AsyncLocalStorage<ActiveTrace>();\r\n\r\nexport const Context = {\r\n run: <T>(trace: ActiveTrace, fn: () => T): T => {\r\n return storage.run(trace, fn);\r\n },\r\n\r\n current: (): ActiveTrace | undefined => {\r\n return storage.getStore();\r\n },\r\n\r\n addSpan: (span: any) => {\r\n const store = storage.getStore();\r\n if (store) {\r\n store.spans.push(span);\r\n }\r\n },\r\n\r\n // Attach error to current trace\r\n setError: (error: Error) => {\r\n const store = storage.getStore();\r\n if (store) {\r\n store.error = {\r\n name: error.name,\r\n message: error.message,\r\n stack: error.stack\r\n };\r\n }\r\n }\r\n};","import { Transport } from './transport';\r\nimport { Context } from './context';\r\nimport { SenzorOptions, ActiveTrace } from './types';\r\nimport { randomUUID } from 'crypto';\r\nimport { instrumentHttp, instrumentFetch } from '../instrumentation/http';\r\nimport { instrumentMongo } from '../instrumentation/mongo';\r\nimport { instrumentPg } from '../instrumentation/pg';\r\n\r\nexport class SenzorClient {\r\n private transport: Transport | null = null;\r\n private options: SenzorOptions | null = null;\r\n private isInstrumented = false;\r\n\r\n public init(options: SenzorOptions) {\r\n if (!options.apiKey) {\r\n console.warn('[Senzor] API Key missing. SDK disabled.');\r\n return;\r\n }\r\n this.options = options;\r\n const endpoint = options.endpoint || 'https://api.senzor.dev/api/ingest/apm';\r\n const debug = options.debug || false;\r\n\r\n this.transport = new Transport({ ...options, endpoint });\r\n\r\n if (!this.isInstrumented) {\r\n try { instrumentHttp(endpoint, debug); } catch (e) { }\r\n try { instrumentFetch(endpoint, debug); } catch (e) { }\r\n try { instrumentMongo(debug); } catch (e) { }\r\n try { instrumentPg(); } catch (e) { }\r\n\r\n this.isInstrumented = true;\r\n if (debug) console.log('[Senzor] Auto-instrumentation enabled');\r\n }\r\n }\r\n\r\n public startTrace<T>(data: Partial<ActiveTrace['data']> & { headers?: any }, next: () => T): T {\r\n if (!this.transport) return next();\r\n\r\n // Check for Distributed Tracing Headers\r\n let parentTraceId = undefined;\r\n let parentSpanId = undefined;\r\n\r\n if (data.headers) {\r\n // Handle various casing\r\n parentTraceId = data.headers['x-senzor-trace-id'] || data.headers['X-SENZOR-TRACE-ID'];\r\n parentSpanId = data.headers['x-senzor-parent-span-id'] || data.headers['X-SENZOR-PARENT-SPAN-ID'];\r\n }\r\n\r\n const trace: ActiveTrace = {\r\n id: randomUUID(),\r\n startTime: performance.now(),\r\n data: {\r\n ...data,\r\n parentTraceId, // Link to parent\r\n parentSpanId // Link to specific call\r\n },\r\n spans: []\r\n };\r\n\r\n return Context.run(trace, next);\r\n }\r\n\r\n public endTrace(status: number, extraData: any = {}) {\r\n const trace = Context.current();\r\n if (!trace || !this.transport) return;\r\n const duration = performance.now() - trace.startTime;\r\n\r\n // Explicitly destructure to ensure parent IDs are included\r\n const payload = {\r\n traceId: trace.id,\r\n parentTraceId: trace.data.parentTraceId,\r\n parentSpanId: trace.data.parentSpanId,\r\n ...trace.data,\r\n ...extraData,\r\n status, duration, spans: trace.spans, timestamp: new Date().toISOString(),\r\n error: trace.error,\r\n\r\n };\r\n this.transport.add(payload);\r\n }\r\n\r\n // --- NEW: Capture Exception ---\r\n public captureError(error: unknown) {\r\n if (error instanceof Error) {\r\n Context.setError(error);\r\n } else if (typeof error === 'string') {\r\n Context.setError(new Error(error));\r\n }\r\n }\r\n\r\n // ... (manual track, startSpan, flush remain same) ...\r\n public track(data: any) { this.transport?.add({ traceId: randomUUID(), ...data, spans: [], timestamp: new Date().toISOString() }); }\r\n\r\n public startSpan(name: string, type: 'db' | 'http' | 'function' | 'custom' = 'custom') {\r\n const trace = Context.current();\r\n if (!trace) return { end: () => { } };\r\n const startTime = performance.now() - trace.startTime;\r\n const spanStartAbs = performance.now();\r\n const spanId = randomUUID(); // Manual spans also need IDs\r\n\r\n return {\r\n end: (meta?: any, status?: number) => {\r\n const duration = performance.now() - spanStartAbs;\r\n Context.addSpan({ spanId, name, type, startTime, duration, status, meta });\r\n }\r\n };\r\n }\r\n\r\n public async flush() { if (this.transport) await this.transport.flush(); }\r\n}\r\n\r\nexport const client = new SenzorClient();","import http from 'http';\r\nimport https from 'https';\r\nimport { URL } from 'url';\r\nimport { Context } from '../core/context';\r\nimport { randomUUID } from 'crypto';\r\n\r\nconst shimmer = (module: any, methodName: string, wrapper: (original: Function) => Function) => {\r\n if (!module[methodName]) return;\r\n const original = module[methodName];\r\n module[methodName] = wrapper(original);\r\n};\r\n\r\n// --- FETCH INSTRUMENTATION (Node 18+ / Edge) ---\r\nexport const instrumentFetch = (ingestUrl: string, debug = false) => {\r\n if (!globalThis.fetch) return;\r\n\r\n let ingestHost = '';\r\n try { ingestHost = new URL(ingestUrl).hostname; } catch (e) { }\r\n\r\n const originalFetch = globalThis.fetch;\r\n\r\n // @ts-ignore\r\n globalThis.fetch = async (input: RequestInfo | URL, init?: RequestInit) => {\r\n // 1. Extract URL\r\n let urlStr = '';\r\n if (typeof input === 'string') urlStr = input;\r\n else if (input instanceof URL) urlStr = input.toString();\r\n else if (input && (input as any).url) urlStr = (input as any).url;\r\n\r\n // 2. Infinite Loop Guard\r\n if (ingestHost && urlStr.includes(ingestHost)) {\r\n return originalFetch(input, init);\r\n }\r\n\r\n // 3. Context Check\r\n const trace = Context.current();\r\n if (!trace) {\r\n return originalFetch(input, init);\r\n }\r\n\r\n // 4. Prepare Metadata & ID\r\n const method = (init?.method || 'GET').toUpperCase();\r\n const startTime = performance.now() - trace.startTime;\r\n const spanStartAbs = performance.now();\r\n const spanId = randomUUID(); // New ID for this specific outbound call\r\n\r\n let hostname = 'unknown';\r\n try { hostname = new URL(urlStr).hostname; } catch (e) { }\r\n\r\n if (debug) console.log(`[Senzor] Fetch: ${method} ${hostname}`);\r\n\r\n // 5. Inject Distributed Tracing Headers\r\n // We need to clone init or create it to avoid mutating original ref unexpectedly\r\n const newInit = { ...init };\r\n if (!newInit.headers) {\r\n newInit.headers = {};\r\n }\r\n\r\n // Handle different Header formats (Headers object vs plain object)\r\n if (newInit.headers instanceof Headers) {\r\n newInit.headers.set('x-senzor-trace-id', trace.id);\r\n newInit.headers.set('x-senzor-parent-span-id', spanId);\r\n } else if (Array.isArray(newInit.headers)) {\r\n newInit.headers.push(['x-senzor-trace-id', trace.id]);\r\n newInit.headers.push(['x-senzor-parent-span-id', spanId]);\r\n } else {\r\n // Plain object\r\n (newInit.headers as any)['x-senzor-trace-id'] = trace.id;\r\n (newInit.headers as any)['x-senzor-parent-span-id'] = spanId;\r\n }\r\n\r\n try {\r\n // 6. Execute Fetch\r\n const response = await originalFetch(input, newInit);\r\n\r\n // 7. Record Span\r\n const duration = performance.now() - spanStartAbs;\r\n Context.addSpan({\r\n spanId,\r\n name: `${method} ${hostname}`,\r\n type: 'http',\r\n startTime,\r\n duration,\r\n status: response.status,\r\n meta: { url: urlStr, method, library: 'fetch' }\r\n });\r\n\r\n return response;\r\n } catch (err: any) {\r\n const duration = performance.now() - spanStartAbs;\r\n Context.addSpan({\r\n spanId,\r\n name: `${method} ${hostname}`,\r\n type: 'http',\r\n startTime,\r\n duration,\r\n status: 500,\r\n meta: { error: err.message, url: urlStr, library: 'fetch' }\r\n });\r\n throw err;\r\n }\r\n };\r\n};\r\n\r\n// --- HTTP/HTTPS INSTRUMENTATION ---\r\nexport const instrumentHttp = (ingestUrl: string, debug = false) => {\r\n let ingestHost = '';\r\n try { ingestHost = new URL(ingestUrl).hostname; } catch (e) { }\r\n\r\n const requestWrapper = (original: Function) => {\r\n return function (this: any, ...args: any[]) {\r\n let options: any = {};\r\n let urlStr = '';\r\n\r\n if (typeof args[0] === 'string' || args[0] instanceof URL) {\r\n urlStr = args[0].toString();\r\n if (typeof args[1] === 'object' && args[1] !== null) options = args[1];\r\n } else {\r\n options = args[0] || {};\r\n const protocol = options.protocol || (options.port === 443 ? 'https:' : 'http:');\r\n const host = options.hostname || options.host || 'localhost';\r\n const path = options.path || '/';\r\n urlStr = `${protocol}//${host}${path}`;\r\n }\r\n\r\n if (ingestHost && (urlStr.includes(ingestHost) || (options.hostname && options.hostname.includes(ingestHost)))) {\r\n return original.apply(this, args);\r\n }\r\n\r\n const trace = Context.current();\r\n if (!trace) return original.apply(this, args);\r\n\r\n const method = (options.method || 'GET').toUpperCase();\r\n const startTime = performance.now() - trace.startTime;\r\n const spanStartAbs = performance.now();\r\n const spanId = randomUUID(); // Generate ID\r\n\r\n let hostname = 'unknown';\r\n try { hostname = new URL(urlStr).hostname; } catch (e) { hostname = options.hostname || 'unknown'; }\r\n\r\n // Inject Headers\r\n if (!options.headers) options.headers = {};\r\n options.headers['x-senzor-trace-id'] = trace.id;\r\n options.headers['x-senzor-parent-span-id'] = spanId;\r\n\r\n const req = original.apply(this, args);\r\n\r\n const captureSpan = (res: any, error?: Error) => {\r\n const duration = performance.now() - spanStartAbs;\r\n Context.addSpan({\r\n spanId,\r\n name: `${method} ${hostname}`,\r\n type: 'http',\r\n startTime,\r\n duration,\r\n status: error ? 500 : res?.statusCode || 0,\r\n meta: { url: urlStr, method, library: 'http' }\r\n });\r\n };\r\n\r\n req.on('response', (res: any) => {\r\n res.once('end', () => captureSpan(res));\r\n res.once('close', () => captureSpan(res)); // Safety if stream not consumed\r\n res.once('error', (err: Error) => captureSpan(res, err));\r\n });\r\n\r\n req.on('error', (err: Error) => captureSpan(null, err));\r\n\r\n return req;\r\n };\r\n };\r\n\r\n shimmer(http, 'request', requestWrapper);\r\n shimmer(http, 'get', requestWrapper);\r\n shimmer(https, 'request', requestWrapper);\r\n shimmer(https, 'get', requestWrapper);\r\n};","import { Context } from '../core/context';\r\n\r\nexport const instrumentMongo = (debug = false) => {\r\n try {\r\n const mongodb = require('mongodb');\r\n const Collection = mongodb.Collection;\r\n\r\n // Attempt to get Cursor classes\r\n // Note: The location of these classes varies by driver version, \r\n // checking common locations\r\n const FindCursor = mongodb.FindCursor || require('mongodb/lib/cursor/find_cursor').FindCursor;\r\n const AggregationCursor = mongodb.AggregationCursor || require('mongodb/lib/cursor/aggregation_cursor').AggregationCursor;\r\n\r\n if (debug) console.log('[Senzor] Instrumenting MongoDB (Collection + Cursors)...');\r\n\r\n // --- Helper to Record Span ---\r\n const recordSpan = (name: string, operation: string, collection: string, startAbs: number, traceStart: number, err?: Error) => {\r\n const duration = performance.now() - startAbs;\r\n Context.addSpan({\r\n name: `MongoDB ${name}`,\r\n type: 'db',\r\n startTime: performance.now() - traceStart - duration, // Adjust start time to when op actually started\r\n duration,\r\n status: err ? 500 : 0,\r\n meta: { collection, operation, error: err ? err.message : undefined }\r\n });\r\n if (debug) console.log(`[Senzor] Captured Mongo: ${name} (${duration.toFixed(2)}ms)`);\r\n };\r\n\r\n // --- 1. Instrument Immediate Operations (Insert/Update/Delete) ---\r\n const immediateMethods = ['insertOne', 'insertMany', 'updateOne', 'updateMany', 'deleteOne', 'deleteMany', 'countDocuments'];\r\n\r\n immediateMethods.forEach((method) => {\r\n if (!Collection.prototype[method]) return;\r\n const original = Collection.prototype[method];\r\n\r\n Collection.prototype[method] = function (...args: any[]) {\r\n const trace = Context.current();\r\n if (!trace) return original.apply(this, args);\r\n\r\n const spanStartAbs = performance.now();\r\n const traceStart = trace.startTime;\r\n const collName = this.collectionName;\r\n\r\n try {\r\n const result = original.apply(this, args);\r\n if (result && typeof result.then === 'function') {\r\n return result.then(\r\n (res: any) => { recordSpan(method, method, collName, spanStartAbs, traceStart); return res; },\r\n (err: any) => { recordSpan(method, method, collName, spanStartAbs, traceStart, err); throw err; }\r\n );\r\n }\r\n return result;\r\n } catch (err: any) {\r\n recordSpan(method, method, collName, spanStartAbs, traceStart, err);\r\n throw err;\r\n }\r\n };\r\n });\r\n\r\n // --- 2. Instrument Cursor Execution (find -> toArray) ---\r\n const patchCursor = (CursorClass: any, label: string) => {\r\n if (!CursorClass || !CursorClass.prototype.toArray) return;\r\n\r\n const originalToArray = CursorClass.prototype.toArray;\r\n\r\n CursorClass.prototype.toArray = function (...args: any[]) {\r\n const trace = Context.current();\r\n // Cursors are often created in context but executed later. \r\n // We check context at execution time.\r\n if (!trace) return originalToArray.apply(this, args);\r\n\r\n const spanStartAbs = performance.now();\r\n const traceStart = trace.startTime;\r\n // Attempt to get collection name from cursor internal state\r\n const collName = this.namespace?.collection || 'unknown';\r\n\r\n const onSuccess = (res: any) => {\r\n recordSpan(label, label, collName, spanStartAbs, traceStart);\r\n return res;\r\n };\r\n const onError = (err: any) => {\r\n recordSpan(label, label, collName, spanStartAbs, traceStart, err);\r\n throw err;\r\n };\r\n\r\n try {\r\n const result = originalToArray.apply(this, args);\r\n if (result && typeof result.then === 'function') {\r\n return result.then(onSuccess, onError);\r\n }\r\n return onSuccess(result);\r\n } catch (e) {\r\n onError(e);\r\n }\r\n };\r\n };\r\n\r\n patchCursor(FindCursor, 'find');\r\n patchCursor(AggregationCursor, 'aggregate');\r\n\r\n } catch (e: any) {\r\n if (debug) console.warn('[Senzor] MongoDB instrumentation warning:', e.message);\r\n }\r\n};","import { Context } from '../core/context';\r\n\r\n// Simple shim for 'pg' library\r\nexport const instrumentPg = () => {\r\n try {\r\n // Try to require pg (it might not be installed by user)\r\n const pg = require('pg');\r\n const originalQuery = pg.Client.prototype.query;\r\n\r\n pg.Client.prototype.query = function (...args: any[]) {\r\n const trace = Context.current();\r\n if (!trace) return originalQuery.apply(this, args);\r\n\r\n const startTime = performance.now() - trace.startTime;\r\n const spanStartAbs = performance.now();\r\n\r\n // Extract SQL (first arg usually string or config object)\r\n const sql = typeof args[0] === 'string' ? args[0] : args[0].text;\r\n\r\n // Wrap callback if present, or handle Promise\r\n const result = originalQuery.apply(this, args);\r\n\r\n if (result && typeof result.then === 'function') {\r\n return result.then((res: any) => {\r\n const duration = performance.now() - spanStartAbs;\r\n Context.addSpan({\r\n name: 'Postgres Query',\r\n type: 'db',\r\n startTime,\r\n duration,\r\n meta: { query: sql }\r\n });\r\n return res;\r\n });\r\n }\r\n return result;\r\n };\r\n } catch (e) {\r\n // User doesn't use pg, ignore\r\n }\r\n};","import { client } from '../core/client';\r\n\r\n// 1. Request Handler (Place before routes)\r\nexport const expressMiddleware = () => {\r\n return (req: any, res: any, next: () => void) => {\r\n client.startTrace({\r\n method: req.method,\r\n path: req.originalUrl || req.url,\r\n ip: req.ip || req.socket?.remoteAddress,\r\n userAgent: req.headers['user-agent'],\r\n headers: req.headers\r\n }, () => {\r\n\r\n // Auto-detect status code on finish\r\n res.once('finish', () => {\r\n try {\r\n let route = 'UNKNOWN';\r\n // Express populates req.route only if a route matched\r\n if (req.route && req.route.path) {\r\n route = (req.baseUrl || '') + req.route.path;\r\n } else if (res.statusCode === 404) {\r\n route = 'Not Found';\r\n } else {\r\n route = req.path || 'Wildcard';\r\n }\r\n\r\n client.endTrace(res.statusCode, { route });\r\n } catch (e) { /* Fail open */ }\r\n });\r\n\r\n next();\r\n });\r\n };\r\n};\r\n\r\n// 2. Error Handler (Place after routes)\r\n// This is required in Express to capture the actual Error Object (Stack Trace)\r\nexport const expressErrorHandler = () => {\r\n return (err: any, req: any, res: any, next: (err?: any) => void) => {\r\n\r\n // 1. Capture the exception context\r\n client.captureError(err);\r\n\r\n // 2. Pass it to the next error handler (don't swallow it)\r\n next(err);\r\n };\r\n};","/**\r\n * Heuristic URL Normalizer\r\n * Converts raw paths with IDs into generic patterns to prevent high cardinality.\r\n * Example: /users/123/orders/abc-def -> /users/:id/orders/:uuid\r\n */\r\nexport const normalizePath = (path: string): string => {\r\n if (!path || path === '/') return '/';\r\n\r\n return path\r\n // Replace UUIDs (long alphanumeric strings)\r\n .replace(\r\n /[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}/g,\r\n ':uuid'\r\n )\r\n // Replace MongoDB ObjectIds (24 hex chars)\r\n .replace(/[0-9a-fA-F]{24}/g, ':objectId')\r\n // Replace pure numeric IDs (e.g., /123)\r\n .replace(/\\/(\\d+)(?=\\/|$)/g, '/:id')\r\n // Remove query strings\r\n .split('?')[0];\r\n};\r\n\r\n/**\r\n * Tries to extract route from Framework internals, falls back to heuristic\r\n */\r\nexport const getRoute = (req: any, fallbackPath: string): string => {\r\n // Express / Connect\r\n if (req.route && req.route.path) {\r\n return (req.baseUrl || '') + req.route.path;\r\n }\r\n\r\n // H3 / Nitro (Nuxt)\r\n if (req.context && req.context.matchedRoute) {\r\n return req.context.matchedRoute.path;\r\n }\r\n\r\n // Fastify\r\n if (req.routerPath) {\r\n return req.routerPath;\r\n }\r\n\r\n // Fallback: Heuristic Normalization\r\n return normalizePath(fallbackPath);\r\n};","import { client } from '../core/client';\r\nimport { getRoute } from '../core/normalizer';\r\n\r\ntype EventHandler = (event: any) => any;\r\n\r\nexport const wrapH3 = (handler: EventHandler) => {\r\n return (event: any) => {\r\n const req = event.node.req;\r\n const path = req.originalUrl || req.url || '/';\r\n\r\n return client.startTrace({\r\n method: req.method || 'GET',\r\n path: path,\r\n ip: req.headers['x-forwarded-for'] || req.socket?.remoteAddress,\r\n userAgent: req.headers['user-agent'],\r\n headers: req.headers // Pass headers\r\n }, async () => {\r\n try {\r\n const response = await handler(event);\r\n let status = 200;\r\n if (event.node.res.statusCode) status = event.node.res.statusCode;\r\n if (response && response.statusCode) status = response.statusCode;\r\n\r\n client.endTrace(status, { route: getRoute(event, path) });\r\n return response;\r\n } catch (err: any) {\r\n client.captureError(err);\r\n const status = err.statusCode || err.status || 500;\r\n client.endTrace(status, { route: getRoute(event, path) });\r\n throw err;\r\n }\r\n });\r\n };\r\n};","import { client } from '../core/client';\r\nimport { normalizePath } from '../core/normalizer';\r\n\r\n// --- App Router Wrapper ---\r\nexport const wrapNextRoute = (handler: Function) => {\r\n return async (req: Request | any, context?: any) => {\r\n\r\n // Extract info from Web Standard Request\r\n const url = req.url ? new URL(req.url) : { pathname: '/' };\r\n const method = req.method || 'GET';\r\n\r\n // Header Extraction\r\n let headers: Record<string, string> = {};\r\n let ua: string | undefined;\r\n let ip: string | undefined;\r\n\r\n if (typeof req.headers.get === 'function') {\r\n // It's a Web Request Object\r\n ua = req.headers.get('user-agent');\r\n ip = req.headers.get('x-forwarded-for');\r\n\r\n // Convert to plain object for trace context extraction\r\n req.headers.forEach((value: string, key: string) => {\r\n headers[key] = value;\r\n });\r\n } else {\r\n // It's a Node Request Object (rare in App router but possible)\r\n headers = req.headers;\r\n ua = headers['user-agent'];\r\n ip = headers['x-forwarded-for'] as string;\r\n }\r\n\r\n return client.startTrace({\r\n method,\r\n path: url.pathname,\r\n userAgent: ua,\r\n ip: ip,\r\n headers: headers // Pass extracted headers\r\n }, async () => {\r\n try {\r\n const response = await handler(req, context);\r\n const status = response?.status || 200;\r\n\r\n client.endTrace(status, { route: normalizePath(url.pathname) });\r\n return response;\r\n } catch (err: any) {\r\n client.captureError(err);\r\n client.endTrace(500, { route: normalizePath(url.pathname) });\r\n throw err;\r\n }\r\n });\r\n };\r\n};\r\n\r\n// --- Pages Router Wrapper ---\r\nexport const wrapNextPages = (handler: Function) => {\r\n return async (req: any, res: any) => {\r\n const path = req.url ? req.url.split('?')[0] : '/';\r\n\r\n return client.startTrace({\r\n method: req.method || 'GET',\r\n path: path,\r\n userAgent: req.headers['user-agent'],\r\n ip: req.headers['x-forwarded-for'] || req.socket?.remoteAddress,\r\n headers: req.headers // Standard Node headers work fine\r\n }, async () => {\r\n\r\n const done = () => {\r\n client.endTrace(res.statusCode || 200, { route: normalizePath(path) });\r\n };\r\n\r\n res.once('finish', done);\r\n res.once('close', done);\r\n\r\n try {\r\n return await handler(req, res);\r\n } catch (e: any) {\r\n client.captureError(e);\r\n throw e;\r\n }\r\n });\r\n };\r\n};","import { client } from '../core/client';\r\nimport { SenzorOptions } from '../core/types';\r\n\r\nexport const senzorPlugin = (fastify: any, options: SenzorOptions, done: Function) => {\r\n if (options && options.apiKey) {\r\n client.init(options);\r\n }\r\n\r\n fastify.addHook('onRequest', (request: any, reply: any, next: Function) => {\r\n client.startTrace({\r\n method: request.method,\r\n path: request.raw.url || request.url,\r\n ip: request.ip,\r\n userAgent: request.headers['user-agent'],\r\n headers: request.headers // Pass headers\r\n }, () => next());\r\n });\r\n\r\n fastify.addHook('onError', (request: any, reply: any, error: any, next: Function) => {\r\n client.captureError(error);\r\n next();\r\n });\r\n\r\n fastify.addHook('onResponse', (request: any, reply: any, next: Function) => {\r\n const route = request.routeOptions?.url || request.routerPath || 'UNKNOWN';\r\n client.endTrace(reply.statusCode, { route });\r\n next();\r\n });\r\n\r\n done();\r\n};","import { client } from './core/client';\r\nimport { expressMiddleware, expressErrorHandler } from './middleware/express';\r\nimport { wrapH3 } from './wrappers/h3';\r\nimport { wrapNextRoute, wrapNextPages } from './wrappers/next';\r\nimport { senzorPlugin } from './wrappers/fastify';\r\nimport { SenzorOptions } from './core/types';\r\n\r\nconst Senzor = {\r\n init: (options: SenzorOptions) => client.init(options),\r\n flush: () => client.flush(),\r\n track: client.track.bind(client),\r\n startSpan: client.startSpan.bind(client),\r\n captureException: client.captureError.bind(client),\r\n\r\n // Express\r\n requestHandler: expressMiddleware,\r\n errorHandler: expressErrorHandler,\r\n\r\n // Next\r\n wrapNextRoute,\r\n wrapNextPages,\r\n\r\n // H3\r\n wrapH3,\r\n\r\n // Fastify\r\n fastifyPlugin: senzorPlugin\r\n};\r\n\r\nexport default Senzor;\r\nexport { Senzor };"],"mappings":"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","names":["Transport","config","trace","batch","err","AsyncLocalStorage","storage","Context","trace","fn","span","store","error","randomUUID","http","https","URL","randomUUID","shimmer","module","methodName","wrapper","original","instrumentFetch","ingestUrl","debug","ingestHost","URL","originalFetch","input","init","urlStr","trace","Context","method","startTime","spanStartAbs","spanId","hostname","newInit","response","duration","err","instrumentHttp","requestWrapper","args","options","protocol","host","path","req","captureSpan","res","error","http","https","instrumentMongo","debug","mongodb","Collection","FindCursor","AggregationCursor","recordSpan","name","operation","collection","startAbs","traceStart","err","duration","Context","method","original","args","trace","spanStartAbs","collName","result","res","patchCursor","CursorClass","label","originalToArray","onSuccess","onError","e","instrumentPg","pg","originalQuery","args","trace","Context","startTime","spanStartAbs","sql","result","res","duration","SenzorClient","options","endpoint","debug","Transport","instrumentHttp","instrumentFetch","instrumentMongo","instrumentPg","data","next","parentTraceId","parentSpanId","trace","randomUUID","Context","status","extraData","duration","payload","error","name","type","startTime","spanStartAbs","spanId","meta","client","expressMiddleware","req","res","next","client","route","expressErrorHandler","err","normalizePath","path","getRoute","req","fallbackPath","wrapH3","handler","event","req","path","client","response","status","getRoute","err","wrapNextRoute","handler","req","context","url","method","headers","ua","ip","value","key","client","response","status","normalizePath","err","wrapNextPages","res","path","done","e","senzorPlugin","fastify","options","done","client","request","reply","next","error","route","Senzor","options","client","expressMiddleware","expressErrorHandler","wrapNextRoute","wrapNextPages","wrapH3","senzorPlugin","index_default"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@senzops/apm-node",
3
- "version": "1.1.4",
3
+ "version": "1.1.5",
4
4
  "description": "Universal APM SDK for Senzor",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -33,34 +33,49 @@ export class SenzorClient {
33
33
  }
34
34
  }
35
35
 
36
- public startTrace<T>(data: Partial<ActiveTrace['data']>, next: () => T): T {
36
+ public startTrace<T>(data: Partial<ActiveTrace['data']> & { headers?: any }, next: () => T): T {
37
37
  if (!this.transport) return next();
38
+
39
+ // Check for Distributed Tracing Headers
40
+ let parentTraceId = undefined;
41
+ let parentSpanId = undefined;
42
+
43
+ if (data.headers) {
44
+ // Handle various casing
45
+ parentTraceId = data.headers['x-senzor-trace-id'] || data.headers['X-SENZOR-TRACE-ID'];
46
+ parentSpanId = data.headers['x-senzor-parent-span-id'] || data.headers['X-SENZOR-PARENT-SPAN-ID'];
47
+ }
48
+
38
49
  const trace: ActiveTrace = {
39
50
  id: randomUUID(),
40
51
  startTime: performance.now(),
41
- data: data,
52
+ data: {
53
+ ...data,
54
+ parentTraceId, // Link to parent
55
+ parentSpanId // Link to specific call
56
+ },
42
57
  spans: []
43
58
  };
59
+
44
60
  return Context.run(trace, next);
45
61
  }
46
62
 
47
63
  public endTrace(status: number, extraData: any = {}) {
48
64
  const trace = Context.current();
49
65
  if (!trace || !this.transport) return;
50
-
51
66
  const duration = performance.now() - trace.startTime;
52
67
 
68
+ // Explicitly destructure to ensure parent IDs are included
53
69
  const payload = {
54
70
  traceId: trace.id,
71
+ parentTraceId: trace.data.parentTraceId,
72
+ parentSpanId: trace.data.parentSpanId,
55
73
  ...trace.data,
56
74
  ...extraData,
57
- status,
58
- duration,
59
- spans: trace.spans,
60
- error: trace.error, // Include Error if captured
61
- timestamp: new Date().toISOString()
62
- };
75
+ status, duration, spans: trace.spans, timestamp: new Date().toISOString(),
76
+ error: trace.error,
63
77
 
78
+ };
64
79
  this.transport.add(payload);
65
80
  }
66
81
 
@@ -81,7 +96,14 @@ export class SenzorClient {
81
96
  if (!trace) return { end: () => { } };
82
97
  const startTime = performance.now() - trace.startTime;
83
98
  const spanStartAbs = performance.now();
84
- return { end: (meta?: any, status?: number) => { Context.addSpan({ name, type, startTime, duration: performance.now() - spanStartAbs, status, meta }); } };
99
+ const spanId = randomUUID(); // Manual spans also need IDs
100
+
101
+ return {
102
+ end: (meta?: any, status?: number) => {
103
+ const duration = performance.now() - spanStartAbs;
104
+ Context.addSpan({ spanId, name, type, startTime, duration, status, meta });
105
+ }
106
+ };
85
107
  }
86
108
 
87
109
  public async flush() { if (this.transport) await this.transport.flush(); }
package/src/core/types.ts CHANGED
@@ -7,6 +7,7 @@ export interface SenzorOptions {
7
7
  }
8
8
 
9
9
  export interface Span {
10
+ spanId: string; // NEW: Unique ID for this span
10
11
  name: string;
11
12
  type: 'db' | 'http' | 'function' | 'custom';
12
13
  startTime: number;
@@ -23,6 +24,11 @@ export interface TraceError {
23
24
 
24
25
  export interface Trace {
25
26
  traceId: string;
27
+
28
+ // Distributed Tracing Fields
29
+ parentTraceId?: string; // NEW
30
+ parentSpanId?: string; // NEW
31
+
26
32
  method: string;
27
33
  route: string;
28
34
  path: string;
@@ -2,6 +2,7 @@ import http from 'http';
2
2
  import https from 'https';
3
3
  import { URL } from 'url';
4
4
  import { Context } from '../core/context';
5
+ import { randomUUID } from 'crypto';
5
6
 
6
7
  const shimmer = (module: any, methodName: string, wrapper: (original: Function) => Function) => {
7
8
  if (!module[methodName]) return;
@@ -9,7 +10,7 @@ const shimmer = (module: any, methodName: string, wrapper: (original: Function)
9
10
  module[methodName] = wrapper(original);
10
11
  };
11
12
 
12
- // --- Native Fetch Instrumentation (Node 18+) ---
13
+ // --- FETCH INSTRUMENTATION (Node 18+ / Edge) ---
13
14
  export const instrumentFetch = (ingestUrl: string, debug = false) => {
14
15
  if (!globalThis.fetch) return;
15
16
 
@@ -24,7 +25,7 @@ export const instrumentFetch = (ingestUrl: string, debug = false) => {
24
25
  let urlStr = '';
25
26
  if (typeof input === 'string') urlStr = input;
26
27
  else if (input instanceof URL) urlStr = input.toString();
27
- else if (input && input.url) urlStr = input.url; // Request object
28
+ else if (input && (input as any).url) urlStr = (input as any).url;
28
29
 
29
30
  // 2. Infinite Loop Guard
30
31
  if (ingestHost && urlStr.includes(ingestHost)) {
@@ -37,21 +38,45 @@ export const instrumentFetch = (ingestUrl: string, debug = false) => {
37
38
  return originalFetch(input, init);
38
39
  }
39
40
 
40
- // 4. Start Span
41
+ // 4. Prepare Metadata & ID
41
42
  const method = (init?.method || 'GET').toUpperCase();
42
43
  const startTime = performance.now() - trace.startTime;
43
44
  const spanStartAbs = performance.now();
45
+ const spanId = randomUUID(); // New ID for this specific outbound call
46
+
44
47
  let hostname = 'unknown';
45
48
  try { hostname = new URL(urlStr).hostname; } catch (e) { }
46
49
 
47
- if (debug) console.log(`[Senzor] Tracking Fetch: ${method} ${hostname}`);
50
+ if (debug) console.log(`[Senzor] Fetch: ${method} ${hostname}`);
51
+
52
+ // 5. Inject Distributed Tracing Headers
53
+ // We need to clone init or create it to avoid mutating original ref unexpectedly
54
+ const newInit = { ...init };
55
+ if (!newInit.headers) {
56
+ newInit.headers = {};
57
+ }
58
+
59
+ // Handle different Header formats (Headers object vs plain object)
60
+ if (newInit.headers instanceof Headers) {
61
+ newInit.headers.set('x-senzor-trace-id', trace.id);
62
+ newInit.headers.set('x-senzor-parent-span-id', spanId);
63
+ } else if (Array.isArray(newInit.headers)) {
64
+ newInit.headers.push(['x-senzor-trace-id', trace.id]);
65
+ newInit.headers.push(['x-senzor-parent-span-id', spanId]);
66
+ } else {
67
+ // Plain object
68
+ (newInit.headers as any)['x-senzor-trace-id'] = trace.id;
69
+ (newInit.headers as any)['x-senzor-parent-span-id'] = spanId;
70
+ }
48
71
 
49
72
  try {
50
- const response = await originalFetch(input, init);
73
+ // 6. Execute Fetch
74
+ const response = await originalFetch(input, newInit);
51
75
 
52
- // 5. End Span
76
+ // 7. Record Span
53
77
  const duration = performance.now() - spanStartAbs;
54
78
  Context.addSpan({
79
+ spanId,
55
80
  name: `${method} ${hostname}`,
56
81
  type: 'http',
57
82
  startTime,
@@ -64,6 +89,7 @@ export const instrumentFetch = (ingestUrl: string, debug = false) => {
64
89
  } catch (err: any) {
65
90
  const duration = performance.now() - spanStartAbs;
66
91
  Context.addSpan({
92
+ spanId,
67
93
  name: `${method} ${hostname}`,
68
94
  type: 'http',
69
95
  startTime,
@@ -76,12 +102,10 @@ export const instrumentFetch = (ingestUrl: string, debug = false) => {
76
102
  };
77
103
  };
78
104
 
79
- // --- Standard HTTP/HTTPS Instrumentation ---
105
+ // --- HTTP/HTTPS INSTRUMENTATION ---
80
106
  export const instrumentHttp = (ingestUrl: string, debug = false) => {
81
107
  let ingestHost = '';
82
- try {
83
- ingestHost = new URL(ingestUrl).hostname;
84
- } catch (e) { }
108
+ try { ingestHost = new URL(ingestUrl).hostname; } catch (e) { }
85
109
 
86
110
  const requestWrapper = (original: Function) => {
87
111
  return function (this: any, ...args: any[]) {
@@ -109,25 +133,34 @@ export const instrumentHttp = (ingestUrl: string, debug = false) => {
109
133
  const method = (options.method || 'GET').toUpperCase();
110
134
  const startTime = performance.now() - trace.startTime;
111
135
  const spanStartAbs = performance.now();
136
+ const spanId = randomUUID(); // Generate ID
137
+
112
138
  let hostname = 'unknown';
113
139
  try { hostname = new URL(urlStr).hostname; } catch (e) { hostname = options.hostname || 'unknown'; }
114
140
 
141
+ // Inject Headers
142
+ if (!options.headers) options.headers = {};
143
+ options.headers['x-senzor-trace-id'] = trace.id;
144
+ options.headers['x-senzor-parent-span-id'] = spanId;
145
+
115
146
  const req = original.apply(this, args);
116
147
 
117
148
  const captureSpan = (res: any, error?: Error) => {
118
149
  const duration = performance.now() - spanStartAbs;
119
150
  Context.addSpan({
151
+ spanId,
120
152
  name: `${method} ${hostname}`,
121
153
  type: 'http',
122
154
  startTime,
123
155
  duration,
124
156
  status: error ? 500 : res?.statusCode || 0,
125
- meta: { url: urlStr, method, library: 'http', error: error ? error.message : undefined }
157
+ meta: { url: urlStr, method, library: 'http' }
126
158
  });
127
159
  };
128
160
 
129
161
  req.on('response', (res: any) => {
130
162
  res.once('end', () => captureSpan(res));
163
+ res.once('close', () => captureSpan(res)); // Safety if stream not consumed
131
164
  res.once('error', (err: Error) => captureSpan(res, err));
132
165
  });
133
166
 
@@ -8,6 +8,7 @@ export const expressMiddleware = () => {
8
8
  path: req.originalUrl || req.url,
9
9
  ip: req.ip || req.socket?.remoteAddress,
10
10
  userAgent: req.headers['user-agent'],
11
+ headers: req.headers
11
12
  }, () => {
12
13
 
13
14
  // Auto-detect status code on finish
@@ -2,29 +2,25 @@ import { client } from '../core/client';
2
2
  import { SenzorOptions } from '../core/types';
3
3
 
4
4
  export const senzorPlugin = (fastify: any, options: SenzorOptions, done: Function) => {
5
-
6
5
  if (options && options.apiKey) {
7
6
  client.init(options);
8
7
  }
9
8
 
10
- // 1. Start Trace
11
9
  fastify.addHook('onRequest', (request: any, reply: any, next: Function) => {
12
- // FIX: Wrap next in a closure to satisfy TS types
13
10
  client.startTrace({
14
11
  method: request.method,
15
12
  path: request.raw.url || request.url,
16
13
  ip: request.ip,
17
- userAgent: request.headers['user-agent']
14
+ userAgent: request.headers['user-agent'],
15
+ headers: request.headers // Pass headers
18
16
  }, () => next());
19
17
  });
20
18
 
21
- // 2. Capture Errors
22
19
  fastify.addHook('onError', (request: any, reply: any, error: any, next: Function) => {
23
20
  client.captureError(error);
24
21
  next();
25
22
  });
26
23
 
27
- // 3. End Trace
28
24
  fastify.addHook('onResponse', (request: any, reply: any, next: Function) => {
29
25
  const route = request.routeOptions?.url || request.routerPath || 'UNKNOWN';
30
26
  client.endTrace(reply.statusCode, { route });
@@ -13,6 +13,7 @@ export const wrapH3 = (handler: EventHandler) => {
13
13
  path: path,
14
14
  ip: req.headers['x-forwarded-for'] || req.socket?.remoteAddress,
15
15
  userAgent: req.headers['user-agent'],
16
+ headers: req.headers // Pass headers
16
17
  }, async () => {
17
18
  try {
18
19
  const response = await handler(event);
@@ -23,9 +24,7 @@ export const wrapH3 = (handler: EventHandler) => {
23
24
  client.endTrace(status, { route: getRoute(event, path) });
24
25
  return response;
25
26
  } catch (err: any) {
26
- // AUTOMATIC ERROR CAPTURE
27
27
  client.captureError(err);
28
-
29
28
  const status = err.statusCode || err.status || 500;
30
29
  client.endTrace(status, { route: getRoute(event, path) });
31
30
  throw err;
@@ -4,27 +4,49 @@ import { normalizePath } from '../core/normalizer';
4
4
  // --- App Router Wrapper ---
5
5
  export const wrapNextRoute = (handler: Function) => {
6
6
  return async (req: Request | any, context?: any) => {
7
+
8
+ // Extract info from Web Standard Request
7
9
  const url = req.url ? new URL(req.url) : { pathname: '/' };
8
10
  const method = req.method || 'GET';
9
- const ua = req.headers.get ? req.headers.get('user-agent') : undefined;
10
- const ip = req.headers.get ? req.headers.get('x-forwarded-for') : undefined;
11
+
12
+ // Header Extraction
13
+ let headers: Record<string, string> = {};
14
+ let ua: string | undefined;
15
+ let ip: string | undefined;
16
+
17
+ if (typeof req.headers.get === 'function') {
18
+ // It's a Web Request Object
19
+ ua = req.headers.get('user-agent');
20
+ ip = req.headers.get('x-forwarded-for');
21
+
22
+ // Convert to plain object for trace context extraction
23
+ req.headers.forEach((value: string, key: string) => {
24
+ headers[key] = value;
25
+ });
26
+ } else {
27
+ // It's a Node Request Object (rare in App router but possible)
28
+ headers = req.headers;
29
+ ua = headers['user-agent'];
30
+ ip = headers['x-forwarded-for'] as string;
31
+ }
11
32
 
12
33
  return client.startTrace({
13
34
  method,
14
35
  path: url.pathname,
15
36
  userAgent: ua,
16
- ip: ip
37
+ ip: ip,
38
+ headers: headers // Pass extracted headers
17
39
  }, async () => {
18
40
  try {
19
41
  const response = await handler(req, context);
20
42
  const status = response?.status || 200;
43
+
21
44
  client.endTrace(status, { route: normalizePath(url.pathname) });
22
45
  return response;
23
46
  } catch (err: any) {
24
- // AUTOMATIC ERROR CAPTURE
25
47
  client.captureError(err);
26
48
  client.endTrace(500, { route: normalizePath(url.pathname) });
27
- throw err; // Re-throw so Next.js handles the error page
49
+ throw err;
28
50
  }
29
51
  });
30
52
  };
@@ -40,6 +62,7 @@ export const wrapNextPages = (handler: Function) => {
40
62
  path: path,
41
63
  userAgent: req.headers['user-agent'],
42
64
  ip: req.headers['x-forwarded-for'] || req.socket?.remoteAddress,
65
+ headers: req.headers // Standard Node headers work fine
43
66
  }, async () => {
44
67
 
45
68
  const done = () => {
@@ -52,10 +75,7 @@ export const wrapNextPages = (handler: Function) => {
52
75
  try {
53
76
  return await handler(req, res);
54
77
  } catch (e: any) {
55
- // AUTOMATIC ERROR CAPTURE
56
78
  client.captureError(e);
57
- // Note: In Pages dir, we rely on 'finish' listener above to close trace,
58
- // but capturing here ensures the error data is attached.
59
79
  throw e;
60
80
  }
61
81
  });