@senzops/apm-node 1.1.6 → 1.1.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -13,7 +13,7 @@ declare const Senzor: {
13
13
  startSpan: (name: string, type?: "db" | "http" | "function" | "custom") => {
14
14
  end: (meta?: any, status?: number) => void;
15
15
  };
16
- captureException: (error: unknown) => void;
16
+ captureException: (error: unknown, context?: any) => void;
17
17
  requestHandler: () => (req: any, res: any, next: () => void) => void;
18
18
  errorHandler: () => (err: any, req: any, res: any, next: (err?: any) => void) => void;
19
19
  wrapNextRoute: (handler: Function) => (req: Request | any, context?: any) => Promise<any>;
package/dist/index.d.ts CHANGED
@@ -13,7 +13,7 @@ declare const Senzor: {
13
13
  startSpan: (name: string, type?: "db" | "http" | "function" | "custom") => {
14
14
  end: (meta?: any, status?: number) => void;
15
15
  };
16
- captureException: (error: unknown) => void;
16
+ captureException: (error: unknown, context?: any) => void;
17
17
  requestHandler: () => (req: any, res: any, next: () => void) => void;
18
18
  errorHandler: () => (err: any, req: any, res: any, next: (err?: any) => void) => void;
19
19
  wrapNextRoute: (handler: Function) => (req: Request | any, context?: any) => Promise<any>;
@@ -1,2 +1,2 @@
1
- "use strict";(()=>{var Q=Object.create;var R=Object.defineProperty;var V=Object.getOwnPropertyDescriptor;var X=Object.getOwnPropertyNames;var Y=Object.getPrototypeOf,Z=Object.prototype.hasOwnProperty;var x=(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,t,n,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of X(t))!Z.call(e,o)&&o!==n&&R(e,o,{get:()=>t[o],enumerable:!(r=V(t,o))||r.enumerable});return e};var $=(e,t,n)=>(n=e!=null?Q(Y(e)):{},_(t||!e||!e.__esModule?R(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 N=x("async_hooks"),I=new N.AsyncLocalStorage,l={run:(e,t)=>I.run(e,t),current:()=>I.getStore(),addSpan:e=>{let t=I.getStore();t&&t.spans.push(e)},setError:e=>{let t=I.getStore();t&&(t.error={name:e.name,message:e.message,stack:e.stack})}};var C=x("crypto");var O=$(x("http")),v=$(x("https")),b=x("url");var H=x("crypto"),z=(e,t,n)=>{if(!e[t])return;let r=e[t];e[t]=n(r)},M=(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 c=l.current();if(!c)return r(o,a);let s=(a?.method||"GET").toUpperCase(),d=performance.now()-c.startTime,S=performance.now(),T=(0,H.randomUUID)(),w="unknown";try{w=new b.URL(i).hostname}catch{}let h={...a};h.headers||(h.headers={});let m=(u,f)=>{h.headers instanceof Headers?h.headers.set(u,f):Array.isArray(h.headers)?h.headers.push([u,f]):h.headers[u]=f};m("x-senzor-trace-id",c.id),m("x-senzor-parent-span-id",T);try{let u=await r(o,h),f=performance.now()-S;return l.addSpan({spanId:T,name:`${s} ${w}`,type:"http",startTime:d,duration:f,status:u.status,meta:{url:i,method:s,library:"fetch"}}),u}catch(u){let f=performance.now()-S;throw l.addSpan({spanId:T,name:`${s} ${w}`,type:"http",startTime:d,duration:f,status:500,meta:{error:u.message,url:i,library:"fetch"}}),u}}},k=(e,t=!1)=>{let n="";try{n=new b.URL(e).hostname}catch{}let r=o=>function(...a){let i={},c="",s=0;if(typeof a[0]=="string"||a[0]instanceof b.URL?(c=a[0].toString(),s=1):s=0,(!a[s]||typeof a[s]!="object")&&(a[s]={}),i=a[s],!c){let g=i.protocol||(i.port===443?"https:":"http:"),y=i.hostname||i.host||"localhost",F=i.path||"/";c=`${g}//${y}${F}`}if(n&&(c.includes(n)||i.hostname&&i.hostname.includes(n)))return o.apply(this,a);let d=l.current();if(!d)return o.apply(this,a);let S=(i.method||"GET").toUpperCase(),T=performance.now()-d.startTime,w=performance.now(),h=(0,H.randomUUID)(),m="unknown";try{m=new b.URL(c).hostname}catch{m=i.hostname||"unknown"}i.headers||(i.headers={}),i.headers["x-senzor-trace-id"]=d.id,i.headers["x-senzor-parent-span-id"]=h,t&&console.log(`[Senzor] Injecting headers to ${c}`);let u=o.apply(this,a),f=(g,y)=>{let F=performance.now()-w;l.addSpan({spanId:h,name:`${S} ${m}`,type:"http",startTime:T,duration:F,status:y?500:g?.statusCode||0,meta:{url:c,method:S,library:"http"}})};return u.on("response",g=>{g.once("end",()=>f(g)),g.once("close",()=>f(g)),g.once("error",y=>f(g,y))}),u.on("error",g=>f(null,g)),u};z(O.default,"request",r),z(O.default,"get",r),z(v.default,"request",r),z(v.default,"get",r)};var D=(e=!1)=>{try{let t=x("mongodb"),n=t.Collection,r=t.FindCursor||x("mongodb/lib/cursor/find_cursor").FindCursor,o=t.AggregationCursor||x("mongodb/lib/cursor/aggregation_cursor").AggregationCursor;e&&console.log("[Senzor] Instrumenting MongoDB (Collection + Cursors)...");let a=(s,d,S,T,w,h)=>{let m=performance.now()-T;l.addSpan({name:`MongoDB ${s}`,type:"db",startTime:performance.now()-w-m,duration:m,status:h?500:0,meta:{collection:S,operation:d,error:h?h.message:void 0}}),e&&console.log(`[Senzor] Captured Mongo: ${s} (${m.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 T=l.current();if(!T)return d.apply(this,S);let w=performance.now(),h=T.startTime,m=this.collectionName;try{let u=d.apply(this,S);return u&&typeof u.then=="function"?u.then(f=>(a(s,s,m,w,h),f),f=>{throw a(s,s,m,w,h,f),f}):u}catch(u){throw a(s,s,m,w,h,u),u}}});let c=(s,d)=>{if(!s||!s.prototype.toArray)return;let S=s.prototype.toArray;s.prototype.toArray=function(...T){let w=l.current();if(!w)return S.apply(this,T);let h=performance.now(),m=w.startTime,u=this.namespace?.collection||"unknown",f=y=>(a(d,d,u,h,m),y),g=y=>{throw a(d,d,u,h,m,y),y};try{let y=S.apply(this,T);return y&&typeof y.then=="function"?y.then(f,g):f(y)}catch(y){g(y)}}};c(r,"find"),c(o,"aggregate")}catch(t){e&&console.warn("[Senzor] MongoDB instrumentation warning:",t.message)}};var K=()=>{try{let e=x("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,c=t.apply(this,n);return c&&typeof c.then=="function"?c.then(s=>{let d=performance.now()-a;return l.addSpan({name:"Postgres Query",type:"db",startTime:o,duration:d,meta:{query:i}}),s}):c}}catch{}};var U=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{k(n,r)}catch{}try{M(n,r)}catch{}try{D(r)}catch{}try{K()}catch{}this.isInstrumented=!0,r&&console.log("[Senzor] Auto-instrumentation enabled")}}startTrace(t,n){if(!this.transport)return n();let r,o;if(t.headers){let i=c=>{if(t.headers[c])return t.headers[c];if(t.headers[c.toLowerCase()])return t.headers[c.toLowerCase()];if(t.headers[c.toUpperCase()])return t.headers[c.toUpperCase()]};r=i("x-senzor-trace-id"),o=i("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:(c,s)=>{l.addSpan({spanId:i,name:t,type:n,startTime:o,duration:performance.now()-a,status:s,meta:c})}}}async flush(){this.transport&&await this.transport.flush()}},p=new U;var L=()=>(e,t,n)=>{p.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",p.endTrace(t.statusCode,{route:r})}catch{}}),n()})},G=()=>(e,t,n,r)=>{p.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],P=(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 j=e=>t=>{let n=t.node.req,r=n.originalUrl||n.url||"/";return p.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),p.endTrace(a,{route:P(t,r)}),o}catch(o){p.captureError(o);let a=o.statusCode||o.status||500;throw p.endTrace(a,{route:P(t,r)}),o}})};var W=e=>async(t,n)=>{let r=t.url?new URL(t.url):{pathname:"/"},o=t.method||"GET",a={},i,c;return typeof t.headers.get=="function"?(i=t.headers.get("user-agent"),c=t.headers.get("x-forwarded-for"),t.headers.forEach((s,d)=>{a[d]=s})):(a=t.headers,i=a["user-agent"],c=a["x-forwarded-for"]),p.startTrace({method:o,path:r.pathname,userAgent:i,ip:c,headers:a},async()=>{try{let s=await e(t,n),d=s?.status||200;return p.endTrace(d,{route:A(r.pathname)}),s}catch(s){throw p.captureError(s),p.endTrace(500,{route:A(r.pathname)}),s}})},B=e=>async(t,n)=>{let r=t.url?t.url.split("?")[0]:"/";return p.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=()=>{p.endTrace(n.statusCode||200,{route:A(r)})};n.once("finish",o),n.once("close",o);try{return await e(t,n)}catch(a){throw p.captureError(a),a}})};var J=(e,t,n)=>{t&&t.apiKey&&p.init(t),e.addHook("onRequest",(r,o,a)=>{p.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)=>{p.captureError(a),i()}),e.addHook("onResponse",(r,o,a)=>{let i=r.routeOptions?.url||r.routerPath||"UNKNOWN";p.endTrace(o.statusCode,{route:i}),a()}),n()};var q={init:e=>p.init(e),flush:()=>p.flush(),track:p.track.bind(p),startSpan:p.startSpan.bind(p),captureException:p.captureError.bind(p),requestHandler:L,errorHandler:G,wrapNextRoute:W,wrapNextPages:B,wrapH3:j,fastifyPlugin:J},Ht=q;})();
1
+ "use strict";(()=>{var J=Object.create;var $=Object.defineProperty;var V=Object.getOwnPropertyDescriptor;var X=Object.getOwnPropertyNames;var Y=Object.getPrototypeOf,Z=Object.prototype.hasOwnProperty;var x=(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,t,n,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of X(t))!Z.call(e,o)&&o!==n&&$(e,o,{get:()=>t[o],enumerable:!(r=V(t,o))||r.enumerable});return e};var U=(e,t,n)=>(n=e!=null?J(Y(e)):{},_(t||!e||!e.__esModule?$(n,"default",{value:e,enumerable:!0}):n,e));var E=class{constructor(t){this.config=t;this.traceQueue=[];this.errorQueue=[];this.timer=null;typeof setInterval<"u"&&(this.timer=setInterval(()=>this.flush(),t.flushInterval||1e4),this.timer&&typeof this.timer.unref=="function"&&this.timer.unref())}addTrace(t){this.traceQueue.push(t),this.traceQueue.length>=(this.config.batchSize||100)&&this.flush()}addError(t){this.errorQueue.push(t),this.errorQueue.length>=(this.config.batchSize||100)&&this.flush()}async flush(){if(this.traceQueue.length===0&&this.errorQueue.length===0)return;let t={traces:[...this.traceQueue],errors:[...this.errorQueue]};this.traceQueue=[],this.errorQueue=[];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.traces.length} traces, ${t.errors.length} errors`)}catch(n){this.config.debug&&console.error("[Senzor] Ingestion Error:",n)}}};var k=x("async_hooks"),F=new k.AsyncLocalStorage,f={run:(e,t)=>F.run(e,t),current:()=>F.getStore(),addSpan:e=>{let t=F.getStore();t&&t.spans.push(e)}};var I=x("crypto");var v=U(x("http")),H=U(x("https")),b=x("url");var O=x("crypto"),z=(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 p=f.current();if(!p)return r(o,a);let s=(a?.method||"GET").toUpperCase(),d=performance.now()-p.startTime,S=performance.now(),T=(0,O.randomUUID)(),w="unknown";try{w=new b.URL(i).hostname}catch{}let h={...a};h.headers||(h.headers={});let m=(u,l)=>{h.headers instanceof Headers?h.headers.set(u,l):Array.isArray(h.headers)?h.headers.push([u,l]):h.headers[u]=l};m("x-senzor-trace-id",p.id),m("x-senzor-parent-span-id",T);try{let u=await r(o,h),l=performance.now()-S;return f.addSpan({spanId:T,name:`${s} ${w}`,type:"http",startTime:d,duration:l,status:u.status,meta:{url:i,method:s,library:"fetch"}}),u}catch(u){let l=performance.now()-S;throw f.addSpan({spanId:T,name:`${s} ${w}`,type:"http",startTime:d,duration:l,status:500,meta:{error:u.message,url:i,library:"fetch"}}),u}}},Q=(e,t=!1)=>{let n="";try{n=new b.URL(e).hostname}catch{}let r=o=>function(...a){let i={},p="",s=0;if(typeof a[0]=="string"||a[0]instanceof b.URL?(p=a[0].toString(),s=1):s=0,(!a[s]||typeof a[s]!="object")&&(a[s]={}),i=a[s],!p){let g=i.protocol||(i.port===443?"https:":"http:"),y=i.hostname||i.host||"localhost",C=i.path||"/";p=`${g}//${y}${C}`}if(n&&(p.includes(n)||i.hostname&&i.hostname.includes(n)))return o.apply(this,a);let d=f.current();if(!d)return o.apply(this,a);let S=(i.method||"GET").toUpperCase(),T=performance.now()-d.startTime,w=performance.now(),h=(0,O.randomUUID)(),m="unknown";try{m=new b.URL(p).hostname}catch{m=i.hostname||"unknown"}i.headers||(i.headers={}),i.headers["x-senzor-trace-id"]=d.id,i.headers["x-senzor-parent-span-id"]=h,t&&console.log(`[Senzor] Injecting headers to ${p}`);let u=o.apply(this,a),l=(g,y)=>{let C=performance.now()-w;f.addSpan({spanId:h,name:`${S} ${m}`,type:"http",startTime:T,duration:C,status:y?500:g?.statusCode||0,meta:{url:p,method:S,library:"http"}})};return u.on("response",g=>{g.once("end",()=>l(g)),g.once("close",()=>l(g)),g.once("error",y=>l(g,y))}),u.on("error",g=>l(null,g)),u};z(v.default,"request",r),z(v.default,"get",r),z(H.default,"request",r),z(H.default,"get",r)};var M=(e=!1)=>{try{let t=x("mongodb"),n=t.Collection,r=t.FindCursor||x("mongodb/lib/cursor/find_cursor").FindCursor,o=t.AggregationCursor||x("mongodb/lib/cursor/aggregation_cursor").AggregationCursor;e&&console.log("[Senzor] Instrumenting MongoDB (Collection + Cursors)...");let a=(s,d,S,T,w,h)=>{let m=performance.now()-T;f.addSpan({name:`MongoDB ${s}`,type:"db",startTime:performance.now()-w-m,duration:m,status:h?500:0,meta:{collection:S,operation:d,error:h?h.message:void 0}}),e&&console.log(`[Senzor] Captured Mongo: ${s} (${m.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 T=f.current();if(!T)return d.apply(this,S);let w=performance.now(),h=T.startTime,m=this.collectionName;try{let u=d.apply(this,S);return u&&typeof u.then=="function"?u.then(l=>(a(s,s,m,w,h),l),l=>{throw a(s,s,m,w,h,l),l}):u}catch(u){throw a(s,s,m,w,h,u),u}}});let p=(s,d)=>{if(!s||!s.prototype.toArray)return;let S=s.prototype.toArray;s.prototype.toArray=function(...T){let w=f.current();if(!w)return S.apply(this,T);let h=performance.now(),m=w.startTime,u=this.namespace?.collection||"unknown",l=y=>(a(d,d,u,h,m),y),g=y=>{throw a(d,d,u,h,m,y),y};try{let y=S.apply(this,T);return y&&typeof y.then=="function"?y.then(l,g):l(y)}catch(y){g(y)}}};p(r,"find"),p(o,"aggregate")}catch(t){e&&console.warn("[Senzor] MongoDB instrumentation warning:",t.message)}};var D=()=>{try{let e=x("pg"),t=e.Client.prototype.query;e.Client.prototype.query=function(...n){let r=f.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,p=t.apply(this,n);return p&&typeof p.then=="function"?p.then(s=>{let d=performance.now()-a;return f.addSpan({name:"Postgres Query",type:"db",startTime:o,duration:d,meta:{query:i}}),s}):p}}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){this.setupGlobalErrorHandlers();try{Q(n,r)}catch{}try{N(n,r)}catch{}try{M(r)}catch{}try{D()}catch{}this.isInstrumented=!0,r&&console.log("[Senzor] Auto-instrumentation & Error Tracking enabled")}}setupGlobalErrorHandlers(){process.on("uncaughtException",t=>{this.captureError(t,{type:"uncaughtException"})}),process.on("unhandledRejection",t=>{this.captureError(t,{type:"unhandledRejection"})})}startTrace(t,n){if(!this.transport)return n();let r,o;if(t.headers){let i=p=>{if(t.headers[p])return t.headers[p];if(t.headers[p.toLowerCase()])return t.headers[p.toLowerCase()]};r=i("x-senzor-trace-id"),o=i("x-senzor-parent-span-id"),Array.isArray(r)&&(r=r[0]),Array.isArray(o)&&(o=o[0])}let a={id:(0,I.randomUUID)(),startTime:performance.now(),data:{...t,parentTraceId:r,parentSpanId:o},spans:[]};return f.run(a,n)}endTrace(t,n={}){let r=f.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()};this.transport.addTrace(a)}captureError(t,n={}){if(!this.transport)return;let r;t instanceof Error?r=t:r=new Error(String(t));let o=f.current();this.transport.addError({errorClass:r.name||"Error",message:r.message,stackTrace:r.stack,traceId:o?.id,context:n,timestamp:new Date().toISOString()})}track(t){this.transport?.addTrace({traceId:(0,I.randomUUID)(),...t,spans:[],timestamp:new Date().toISOString()})}startSpan(t,n="custom"){let r=f.current();if(!r)return{end:()=>{}};let o=performance.now()-r.startTime,a=performance.now(),i=(0,I.randomUUID)();return{end:(p,s)=>{f.addSpan({spanId:i,name:t,type:n,startTime:o,duration:performance.now()-a,status:s,meta:p})}}}async flush(){this.transport&&await this.transport.flush()}},c=new R;var G=()=>(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()})},K=()=>(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],P=(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 j=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:P(t,r)}),o}catch(o){c.captureError(o);let a=o.statusCode||o.status||500;throw c.endTrace(a,{route:P(t,r)}),o}})};var L=e=>async(t,n)=>{let r=t.url?new URL(t.url):{pathname:"/"},o=t.method||"GET",a={},i,p;return typeof t.headers.get=="function"?(i=t.headers.get("user-agent"),p=t.headers.get("x-forwarded-for"),t.headers.forEach((s,d)=>{a[d]=s})):(a=t.headers,i=a["user-agent"],p=a["x-forwarded-for"]),c.startTrace({method:o,path:r.pathname,userAgent:i,ip:p,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}})},W=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 q={init:e=>c.init(e),flush:()=>c.flush(),track:c.track.bind(c),startSpan:c.startSpan.bind(c),captureException:c.captureError.bind(c),requestHandler:G,errorHandler:K,wrapNextRoute:L,wrapNextPages:W,wrapH3:j,fastifyPlugin:B},Ot=q;})();
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']> & { headers?: any }, next: () => T): T {\r\n if (!this.transport) return next();\r\n\r\n // Trace Propagation Extraction\r\n let parentTraceId = undefined;\r\n let parentSpanId = undefined;\r\n\r\n if (data.headers) {\r\n // Robust header checking (Node headers are usually lowercase, but handle mixed)\r\n const getHeader = (key: string) => {\r\n // Direct access\r\n if (data.headers[key]) return data.headers[key];\r\n if (data.headers[key.toLowerCase()]) return data.headers[key.toLowerCase()];\r\n if (data.headers[key.toUpperCase()]) return data.headers[key.toUpperCase()];\r\n return undefined;\r\n };\r\n\r\n parentTraceId = getHeader('x-senzor-trace-id');\r\n parentSpanId = getHeader('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,\r\n parentSpanId\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 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 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 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();\r\n return { end: (meta?: any, status?: number) => { Context.addSpan({ spanId, 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\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 ---\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 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 if (ingestHost && urlStr.includes(ingestHost)) {\r\n return originalFetch(input, init);\r\n }\r\n\r\n const trace = Context.current();\r\n if (!trace) {\r\n return originalFetch(input, init);\r\n }\r\n\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();\r\n\r\n let hostname = 'unknown';\r\n try { hostname = new URL(urlStr).hostname; } catch (e) { }\r\n\r\n // Inject Headers\r\n const newInit = { ...init } as RequestInit;\r\n if (!newInit.headers) newInit.headers = {};\r\n\r\n // Helper to set header on various types\r\n const setHeader = (key: string, value: string) => {\r\n if (newInit.headers instanceof Headers) {\r\n newInit.headers.set(key, value);\r\n } else if (Array.isArray(newInit.headers)) {\r\n newInit.headers.push([key, value]);\r\n } else {\r\n (newInit.headers as any)[key] = value;\r\n }\r\n };\r\n\r\n setHeader('x-senzor-trace-id', trace.id);\r\n setHeader('x-senzor-parent-span-id', spanId);\r\n\r\n try {\r\n const response = await originalFetch(input, newInit);\r\n\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 let optionsIndex = 0;\r\n\r\n // Parsing Logic: http.request(url, options, cb) OR http.request(options, cb)\r\n if (typeof args[0] === 'string' || args[0] instanceof URL) {\r\n urlStr = args[0].toString();\r\n optionsIndex = 1;\r\n } else {\r\n optionsIndex = 0;\r\n }\r\n\r\n // Ensure options object exists at correct index\r\n if (!args[optionsIndex] || typeof args[optionsIndex] !== 'object') {\r\n args[optionsIndex] = {};\r\n }\r\n options = args[optionsIndex];\r\n\r\n // Construct URL if missing\r\n if (!urlStr) {\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 // Guard\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();\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 (Mutate the options object reference directly)\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 // Debug\r\n if (debug) console.log(`[Senzor] Injecting headers to ${urlStr}`);\r\n\r\n // Call Original\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));\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","setHeader","key","value","response","duration","err","instrumentHttp","requestWrapper","args","options","optionsIndex","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","getHeader","key","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"]}
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, Trace, SenzorError } from './types';\r\n\r\nexport class Transport {\r\n private traceQueue: Trace[] = [];\r\n private errorQueue: SenzorError[] = [];\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 addTrace(trace: any) {\r\n this.traceQueue.push(trace);\r\n if (this.traceQueue.length >= (this.config.batchSize || 100)) {\r\n this.flush();\r\n }\r\n }\r\n\r\n public addError(error: SenzorError) {\r\n this.errorQueue.push(error);\r\n if (this.errorQueue.length >= (this.config.batchSize || 100)) {\r\n this.flush();\r\n }\r\n }\r\n\r\n public async flush() {\r\n if (this.traceQueue.length === 0 && this.errorQueue.length === 0) return;\r\n\r\n const payload = {\r\n traces: [...this.traceQueue],\r\n errors: [...this.errorQueue]\r\n };\r\n\r\n this.traceQueue = [];\r\n this.errorQueue = [];\r\n\r\n try {\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(payload),\r\n keepalive: true,\r\n });\r\n\r\n if (this.config.debug) console.log(`[Senzor] Flushed ${payload.traces.length} traces, ${payload.errors.length} errors`);\r\n } catch (err) {\r\n if (this.config.debug) console.error('[Senzor] Ingestion Error:', err);\r\n }\r\n }\r\n}","import { AsyncLocalStorage } from 'async_hooks';\r\nimport { ActiveTrace } 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};","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 this.setupGlobalErrorHandlers();\r\n\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 & Error Tracking enabled');\r\n }\r\n }\r\n\r\n private setupGlobalErrorHandlers() {\r\n process.on('uncaughtException', (error) => {\r\n this.captureError(error, { type: 'uncaughtException' });\r\n });\r\n\r\n process.on('unhandledRejection', (reason) => {\r\n this.captureError(reason, { type: 'unhandledRejection' });\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 let parentTraceId = undefined;\r\n let parentSpanId = undefined;\r\n\r\n if (data.headers) {\r\n const getHeader = (key: string) => {\r\n if (data.headers[key]) return data.headers[key];\r\n if (data.headers[key.toLowerCase()]) return data.headers[key.toLowerCase()];\r\n return undefined;\r\n };\r\n\r\n parentTraceId = getHeader('x-senzor-trace-id');\r\n parentSpanId = getHeader('x-senzor-parent-span-id');\r\n\r\n if (Array.isArray(parentTraceId)) parentTraceId = parentTraceId[0];\r\n if (Array.isArray(parentSpanId)) parentSpanId = parentSpanId[0];\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,\r\n parentSpanId\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 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 };\r\n this.transport.addTrace(payload);\r\n }\r\n\r\n // --- NEW: Standalone Error Capture ---\r\n public captureError(error: unknown, context: any = {}) {\r\n if (!this.transport) return;\r\n\r\n let parsedError: Error;\r\n if (error instanceof Error) {\r\n parsedError = error;\r\n } else {\r\n parsedError = new Error(String(error));\r\n }\r\n\r\n // Attempt to link to active trace\r\n const currentTrace = Context.current();\r\n\r\n this.transport.addError({\r\n errorClass: parsedError.name || 'Error',\r\n message: parsedError.message,\r\n stackTrace: parsedError.stack,\r\n traceId: currentTrace?.id,\r\n context,\r\n timestamp: new Date().toISOString()\r\n });\r\n }\r\n\r\n public track(data: any) {\r\n this.transport?.addTrace({ traceId: randomUUID(), ...data, spans: [], timestamp: new Date().toISOString() });\r\n }\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();\r\n return { end: (meta?: any, status?: number) => { Context.addSpan({ spanId, 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\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 ---\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 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 if (ingestHost && urlStr.includes(ingestHost)) {\r\n return originalFetch(input, init);\r\n }\r\n\r\n const trace = Context.current();\r\n if (!trace) {\r\n return originalFetch(input, init);\r\n }\r\n\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();\r\n\r\n let hostname = 'unknown';\r\n try { hostname = new URL(urlStr).hostname; } catch (e) { }\r\n\r\n // Inject Headers\r\n const newInit = { ...init } as RequestInit;\r\n if (!newInit.headers) newInit.headers = {};\r\n\r\n // Helper to set header on various types\r\n const setHeader = (key: string, value: string) => {\r\n if (newInit.headers instanceof Headers) {\r\n newInit.headers.set(key, value);\r\n } else if (Array.isArray(newInit.headers)) {\r\n newInit.headers.push([key, value]);\r\n } else {\r\n (newInit.headers as any)[key] = value;\r\n }\r\n };\r\n\r\n setHeader('x-senzor-trace-id', trace.id);\r\n setHeader('x-senzor-parent-span-id', spanId);\r\n\r\n try {\r\n const response = await originalFetch(input, newInit);\r\n\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 let optionsIndex = 0;\r\n\r\n // Parsing Logic: http.request(url, options, cb) OR http.request(options, cb)\r\n if (typeof args[0] === 'string' || args[0] instanceof URL) {\r\n urlStr = args[0].toString();\r\n optionsIndex = 1;\r\n } else {\r\n optionsIndex = 0;\r\n }\r\n\r\n // Ensure options object exists at correct index\r\n if (!args[optionsIndex] || typeof args[optionsIndex] !== 'object') {\r\n args[optionsIndex] = {};\r\n }\r\n options = args[optionsIndex];\r\n\r\n // Construct URL if missing\r\n if (!urlStr) {\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 // Guard\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();\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 (Mutate the options object reference directly)\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 // Debug\r\n if (debug) console.log(`[Senzor] Injecting headers to ${urlStr}`);\r\n\r\n // Call Original\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));\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","error","payload","err","import_async_hooks","storage","Context","trace","fn","span","store","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","setHeader","key","value","response","duration","err","instrumentHttp","requestWrapper","args","options","optionsIndex","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","error","reason","data","next","parentTraceId","parentSpanId","getHeader","key","trace","Context","status","extraData","duration","payload","context","parsedError","currentTrace","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 V=Object.create;var A=Object.defineProperty;var X=Object.getOwnPropertyDescriptor;var Y=Object.getOwnPropertyNames;var Z=Object.getPrototypeOf,_=Object.prototype.hasOwnProperty;var q=(e,t)=>{for(var n in t)A(e,n,{get:t[n],enumerable:!0})},R=(e,t,n,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of Y(t))!_.call(e,o)&&o!==n&&A(e,o,{get:()=>t[o],enumerable:!(r=X(t,o))||r.enumerable});return e};var $=(e,t,n)=>(n=e!=null?V(Z(e)):{},R(t||!e||!e.__esModule?A(n,"default",{value:e,enumerable:!0}):n,e)),tt=e=>R(A({},"__esModule",{value:!0}),e);var rt={};q(rt,{Senzor:()=>Q,default:()=>et});module.exports=tt(rt);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 N=require("async_hooks"),I=new N.AsyncLocalStorage,l={run:(e,t)=>I.run(e,t),current:()=>I.getStore(),addSpan:e=>{let t=I.getStore();t&&t.spans.push(e)},setError:e=>{let t=I.getStore();t&&(t.error={name:e.name,message:e.message,stack:e.stack})}};var C=require("crypto");var O=$(require("http")),v=$(require("https")),x=require("url");var H=require("crypto"),z=(e,t,n)=>{if(!e[t])return;let r=e[t];e[t]=n(r)},M=(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 c=l.current();if(!c)return r(o,a);let s=(a?.method||"GET").toUpperCase(),d=performance.now()-c.startTime,S=performance.now(),T=(0,H.randomUUID)(),w="unknown";try{w=new x.URL(i).hostname}catch{}let h={...a};h.headers||(h.headers={});let m=(u,f)=>{h.headers instanceof Headers?h.headers.set(u,f):Array.isArray(h.headers)?h.headers.push([u,f]):h.headers[u]=f};m("x-senzor-trace-id",c.id),m("x-senzor-parent-span-id",T);try{let u=await r(o,h),f=performance.now()-S;return l.addSpan({spanId:T,name:`${s} ${w}`,type:"http",startTime:d,duration:f,status:u.status,meta:{url:i,method:s,library:"fetch"}}),u}catch(u){let f=performance.now()-S;throw l.addSpan({spanId:T,name:`${s} ${w}`,type:"http",startTime:d,duration:f,status:500,meta:{error:u.message,url:i,library:"fetch"}}),u}}},k=(e,t=!1)=>{let n="";try{n=new x.URL(e).hostname}catch{}let r=o=>function(...a){let i={},c="",s=0;if(typeof a[0]=="string"||a[0]instanceof x.URL?(c=a[0].toString(),s=1):s=0,(!a[s]||typeof a[s]!="object")&&(a[s]={}),i=a[s],!c){let g=i.protocol||(i.port===443?"https:":"http:"),y=i.hostname||i.host||"localhost",F=i.path||"/";c=`${g}//${y}${F}`}if(n&&(c.includes(n)||i.hostname&&i.hostname.includes(n)))return o.apply(this,a);let d=l.current();if(!d)return o.apply(this,a);let S=(i.method||"GET").toUpperCase(),T=performance.now()-d.startTime,w=performance.now(),h=(0,H.randomUUID)(),m="unknown";try{m=new x.URL(c).hostname}catch{m=i.hostname||"unknown"}i.headers||(i.headers={}),i.headers["x-senzor-trace-id"]=d.id,i.headers["x-senzor-parent-span-id"]=h,t&&console.log(`[Senzor] Injecting headers to ${c}`);let u=o.apply(this,a),f=(g,y)=>{let F=performance.now()-w;l.addSpan({spanId:h,name:`${S} ${m}`,type:"http",startTime:T,duration:F,status:y?500:g?.statusCode||0,meta:{url:c,method:S,library:"http"}})};return u.on("response",g=>{g.once("end",()=>f(g)),g.once("close",()=>f(g)),g.once("error",y=>f(g,y))}),u.on("error",g=>f(null,g)),u};z(O.default,"request",r),z(O.default,"get",r),z(v.default,"request",r),z(v.default,"get",r)};var D=(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,T,w,h)=>{let m=performance.now()-T;l.addSpan({name:`MongoDB ${s}`,type:"db",startTime:performance.now()-w-m,duration:m,status:h?500:0,meta:{collection:S,operation:d,error:h?h.message:void 0}}),e&&console.log(`[Senzor] Captured Mongo: ${s} (${m.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 T=l.current();if(!T)return d.apply(this,S);let w=performance.now(),h=T.startTime,m=this.collectionName;try{let u=d.apply(this,S);return u&&typeof u.then=="function"?u.then(f=>(a(s,s,m,w,h),f),f=>{throw a(s,s,m,w,h,f),f}):u}catch(u){throw a(s,s,m,w,h,u),u}}});let c=(s,d)=>{if(!s||!s.prototype.toArray)return;let S=s.prototype.toArray;s.prototype.toArray=function(...T){let w=l.current();if(!w)return S.apply(this,T);let h=performance.now(),m=w.startTime,u=this.namespace?.collection||"unknown",f=y=>(a(d,d,u,h,m),y),g=y=>{throw a(d,d,u,h,m,y),y};try{let y=S.apply(this,T);return y&&typeof y.then=="function"?y.then(f,g):f(y)}catch(y){g(y)}}};c(r,"find"),c(o,"aggregate")}catch(t){e&&console.warn("[Senzor] MongoDB instrumentation warning:",t.message)}};var K=()=>{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,c=t.apply(this,n);return c&&typeof c.then=="function"?c.then(s=>{let d=performance.now()-a;return l.addSpan({name:"Postgres Query",type:"db",startTime:o,duration:d,meta:{query:i}}),s}):c}}catch{}};var U=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{k(n,r)}catch{}try{M(n,r)}catch{}try{D(r)}catch{}try{K()}catch{}this.isInstrumented=!0,r&&console.log("[Senzor] Auto-instrumentation enabled")}}startTrace(t,n){if(!this.transport)return n();let r,o;if(t.headers){let i=c=>{if(t.headers[c])return t.headers[c];if(t.headers[c.toLowerCase()])return t.headers[c.toLowerCase()];if(t.headers[c.toUpperCase()])return t.headers[c.toUpperCase()]};r=i("x-senzor-trace-id"),o=i("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:(c,s)=>{l.addSpan({spanId:i,name:t,type:n,startTime:o,duration:performance.now()-a,status:s,meta:c})}}}async flush(){this.transport&&await this.transport.flush()}},p=new U;var L=()=>(e,t,n)=>{p.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",p.endTrace(t.statusCode,{route:r})}catch{}}),n()})},G=()=>(e,t,n,r)=>{p.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],P=(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 j=e=>t=>{let n=t.node.req,r=n.originalUrl||n.url||"/";return p.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),p.endTrace(a,{route:P(t,r)}),o}catch(o){p.captureError(o);let a=o.statusCode||o.status||500;throw p.endTrace(a,{route:P(t,r)}),o}})};var W=e=>async(t,n)=>{let r=t.url?new URL(t.url):{pathname:"/"},o=t.method||"GET",a={},i,c;return typeof t.headers.get=="function"?(i=t.headers.get("user-agent"),c=t.headers.get("x-forwarded-for"),t.headers.forEach((s,d)=>{a[d]=s})):(a=t.headers,i=a["user-agent"],c=a["x-forwarded-for"]),p.startTrace({method:o,path:r.pathname,userAgent:i,ip:c,headers:a},async()=>{try{let s=await e(t,n),d=s?.status||200;return p.endTrace(d,{route:b(r.pathname)}),s}catch(s){throw p.captureError(s),p.endTrace(500,{route:b(r.pathname)}),s}})},B=e=>async(t,n)=>{let r=t.url?t.url.split("?")[0]:"/";return p.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=()=>{p.endTrace(n.statusCode||200,{route:b(r)})};n.once("finish",o),n.once("close",o);try{return await e(t,n)}catch(a){throw p.captureError(a),a}})};var J=(e,t,n)=>{t&&t.apiKey&&p.init(t),e.addHook("onRequest",(r,o,a)=>{p.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)=>{p.captureError(a),i()}),e.addHook("onResponse",(r,o,a)=>{let i=r.routeOptions?.url||r.routerPath||"UNKNOWN";p.endTrace(o.statusCode,{route:i}),a()}),n()};var Q={init:e=>p.init(e),flush:()=>p.flush(),track:p.track.bind(p),startSpan:p.startSpan.bind(p),captureException:p.captureError.bind(p),requestHandler:L,errorHandler:G,wrapNextRoute:W,wrapNextPages:B,wrapH3:j,fastifyPlugin:J},et=Q;0&&(module.exports={Senzor});
1
+ "use strict";var V=Object.create;var A=Object.defineProperty;var X=Object.getOwnPropertyDescriptor;var Y=Object.getOwnPropertyNames;var Z=Object.getPrototypeOf,_=Object.prototype.hasOwnProperty;var q=(e,t)=>{for(var n in t)A(e,n,{get:t[n],enumerable:!0})},$=(e,t,n,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of Y(t))!_.call(e,o)&&o!==n&&A(e,o,{get:()=>t[o],enumerable:!(r=X(t,o))||r.enumerable});return e};var U=(e,t,n)=>(n=e!=null?V(Z(e)):{},$(t||!e||!e.__esModule?A(n,"default",{value:e,enumerable:!0}):n,e)),tt=e=>$(A({},"__esModule",{value:!0}),e);var rt={};q(rt,{Senzor:()=>J,default:()=>et});module.exports=tt(rt);var E=class{constructor(t){this.config=t;this.traceQueue=[];this.errorQueue=[];this.timer=null;typeof setInterval<"u"&&(this.timer=setInterval(()=>this.flush(),t.flushInterval||1e4),this.timer&&typeof this.timer.unref=="function"&&this.timer.unref())}addTrace(t){this.traceQueue.push(t),this.traceQueue.length>=(this.config.batchSize||100)&&this.flush()}addError(t){this.errorQueue.push(t),this.errorQueue.length>=(this.config.batchSize||100)&&this.flush()}async flush(){if(this.traceQueue.length===0&&this.errorQueue.length===0)return;let t={traces:[...this.traceQueue],errors:[...this.errorQueue]};this.traceQueue=[],this.errorQueue=[];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.traces.length} traces, ${t.errors.length} errors`)}catch(n){this.config.debug&&console.error("[Senzor] Ingestion Error:",n)}}};var k=require("async_hooks"),F=new k.AsyncLocalStorage,f={run:(e,t)=>F.run(e,t),current:()=>F.getStore(),addSpan:e=>{let t=F.getStore();t&&t.spans.push(e)}};var I=require("crypto");var v=U(require("http")),H=U(require("https")),x=require("url");var O=require("crypto"),z=(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.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 p=f.current();if(!p)return r(o,a);let s=(a?.method||"GET").toUpperCase(),d=performance.now()-p.startTime,S=performance.now(),T=(0,O.randomUUID)(),w="unknown";try{w=new x.URL(i).hostname}catch{}let h={...a};h.headers||(h.headers={});let m=(u,l)=>{h.headers instanceof Headers?h.headers.set(u,l):Array.isArray(h.headers)?h.headers.push([u,l]):h.headers[u]=l};m("x-senzor-trace-id",p.id),m("x-senzor-parent-span-id",T);try{let u=await r(o,h),l=performance.now()-S;return f.addSpan({spanId:T,name:`${s} ${w}`,type:"http",startTime:d,duration:l,status:u.status,meta:{url:i,method:s,library:"fetch"}}),u}catch(u){let l=performance.now()-S;throw f.addSpan({spanId:T,name:`${s} ${w}`,type:"http",startTime:d,duration:l,status:500,meta:{error:u.message,url:i,library:"fetch"}}),u}}},Q=(e,t=!1)=>{let n="";try{n=new x.URL(e).hostname}catch{}let r=o=>function(...a){let i={},p="",s=0;if(typeof a[0]=="string"||a[0]instanceof x.URL?(p=a[0].toString(),s=1):s=0,(!a[s]||typeof a[s]!="object")&&(a[s]={}),i=a[s],!p){let g=i.protocol||(i.port===443?"https:":"http:"),y=i.hostname||i.host||"localhost",C=i.path||"/";p=`${g}//${y}${C}`}if(n&&(p.includes(n)||i.hostname&&i.hostname.includes(n)))return o.apply(this,a);let d=f.current();if(!d)return o.apply(this,a);let S=(i.method||"GET").toUpperCase(),T=performance.now()-d.startTime,w=performance.now(),h=(0,O.randomUUID)(),m="unknown";try{m=new x.URL(p).hostname}catch{m=i.hostname||"unknown"}i.headers||(i.headers={}),i.headers["x-senzor-trace-id"]=d.id,i.headers["x-senzor-parent-span-id"]=h,t&&console.log(`[Senzor] Injecting headers to ${p}`);let u=o.apply(this,a),l=(g,y)=>{let C=performance.now()-w;f.addSpan({spanId:h,name:`${S} ${m}`,type:"http",startTime:T,duration:C,status:y?500:g?.statusCode||0,meta:{url:p,method:S,library:"http"}})};return u.on("response",g=>{g.once("end",()=>l(g)),g.once("close",()=>l(g)),g.once("error",y=>l(g,y))}),u.on("error",g=>l(null,g)),u};z(v.default,"request",r),z(v.default,"get",r),z(H.default,"request",r),z(H.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,T,w,h)=>{let m=performance.now()-T;f.addSpan({name:`MongoDB ${s}`,type:"db",startTime:performance.now()-w-m,duration:m,status:h?500:0,meta:{collection:S,operation:d,error:h?h.message:void 0}}),e&&console.log(`[Senzor] Captured Mongo: ${s} (${m.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 T=f.current();if(!T)return d.apply(this,S);let w=performance.now(),h=T.startTime,m=this.collectionName;try{let u=d.apply(this,S);return u&&typeof u.then=="function"?u.then(l=>(a(s,s,m,w,h),l),l=>{throw a(s,s,m,w,h,l),l}):u}catch(u){throw a(s,s,m,w,h,u),u}}});let p=(s,d)=>{if(!s||!s.prototype.toArray)return;let S=s.prototype.toArray;s.prototype.toArray=function(...T){let w=f.current();if(!w)return S.apply(this,T);let h=performance.now(),m=w.startTime,u=this.namespace?.collection||"unknown",l=y=>(a(d,d,u,h,m),y),g=y=>{throw a(d,d,u,h,m,y),y};try{let y=S.apply(this,T);return y&&typeof y.then=="function"?y.then(l,g):l(y)}catch(y){g(y)}}};p(r,"find"),p(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=f.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,p=t.apply(this,n);return p&&typeof p.then=="function"?p.then(s=>{let d=performance.now()-a;return f.addSpan({name:"Postgres Query",type:"db",startTime:o,duration:d,meta:{query:i}}),s}):p}}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){this.setupGlobalErrorHandlers();try{Q(n,r)}catch{}try{N(n,r)}catch{}try{M(r)}catch{}try{D()}catch{}this.isInstrumented=!0,r&&console.log("[Senzor] Auto-instrumentation & Error Tracking enabled")}}setupGlobalErrorHandlers(){process.on("uncaughtException",t=>{this.captureError(t,{type:"uncaughtException"})}),process.on("unhandledRejection",t=>{this.captureError(t,{type:"unhandledRejection"})})}startTrace(t,n){if(!this.transport)return n();let r,o;if(t.headers){let i=p=>{if(t.headers[p])return t.headers[p];if(t.headers[p.toLowerCase()])return t.headers[p.toLowerCase()]};r=i("x-senzor-trace-id"),o=i("x-senzor-parent-span-id"),Array.isArray(r)&&(r=r[0]),Array.isArray(o)&&(o=o[0])}let a={id:(0,I.randomUUID)(),startTime:performance.now(),data:{...t,parentTraceId:r,parentSpanId:o},spans:[]};return f.run(a,n)}endTrace(t,n={}){let r=f.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()};this.transport.addTrace(a)}captureError(t,n={}){if(!this.transport)return;let r;t instanceof Error?r=t:r=new Error(String(t));let o=f.current();this.transport.addError({errorClass:r.name||"Error",message:r.message,stackTrace:r.stack,traceId:o?.id,context:n,timestamp:new Date().toISOString()})}track(t){this.transport?.addTrace({traceId:(0,I.randomUUID)(),...t,spans:[],timestamp:new Date().toISOString()})}startSpan(t,n="custom"){let r=f.current();if(!r)return{end:()=>{}};let o=performance.now()-r.startTime,a=performance.now(),i=(0,I.randomUUID)();return{end:(p,s)=>{f.addSpan({spanId:i,name:t,type:n,startTime:o,duration:performance.now()-a,status:s,meta:p})}}}async flush(){this.transport&&await this.transport.flush()}},c=new R;var G=()=>(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()})},K=()=>(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],P=(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 j=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:P(t,r)}),o}catch(o){c.captureError(o);let a=o.statusCode||o.status||500;throw c.endTrace(a,{route:P(t,r)}),o}})};var L=e=>async(t,n)=>{let r=t.url?new URL(t.url):{pathname:"/"},o=t.method||"GET",a={},i,p;return typeof t.headers.get=="function"?(i=t.headers.get("user-agent"),p=t.headers.get("x-forwarded-for"),t.headers.forEach((s,d)=>{a[d]=s})):(a=t.headers,i=a["user-agent"],p=a["x-forwarded-for"]),c.startTrace({method:o,path:r.pathname,userAgent:i,ip:p,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}})},W=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 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:G,errorHandler:K,wrapNextRoute:L,wrapNextPages:W,wrapH3:j,fastifyPlugin:B},et=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']> & { headers?: any }, next: () => T): T {\r\n if (!this.transport) return next();\r\n\r\n // Trace Propagation Extraction\r\n let parentTraceId = undefined;\r\n let parentSpanId = undefined;\r\n\r\n if (data.headers) {\r\n // Robust header checking (Node headers are usually lowercase, but handle mixed)\r\n const getHeader = (key: string) => {\r\n // Direct access\r\n if (data.headers[key]) return data.headers[key];\r\n if (data.headers[key.toLowerCase()]) return data.headers[key.toLowerCase()];\r\n if (data.headers[key.toUpperCase()]) return data.headers[key.toUpperCase()];\r\n return undefined;\r\n };\r\n\r\n parentTraceId = getHeader('x-senzor-trace-id');\r\n parentSpanId = getHeader('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,\r\n parentSpanId\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 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 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 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();\r\n return { end: (meta?: any, status?: number) => { Context.addSpan({ spanId, 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\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 ---\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 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 if (ingestHost && urlStr.includes(ingestHost)) {\r\n return originalFetch(input, init);\r\n }\r\n\r\n const trace = Context.current();\r\n if (!trace) {\r\n return originalFetch(input, init);\r\n }\r\n\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();\r\n\r\n let hostname = 'unknown';\r\n try { hostname = new URL(urlStr).hostname; } catch (e) { }\r\n\r\n // Inject Headers\r\n const newInit = { ...init } as RequestInit;\r\n if (!newInit.headers) newInit.headers = {};\r\n\r\n // Helper to set header on various types\r\n const setHeader = (key: string, value: string) => {\r\n if (newInit.headers instanceof Headers) {\r\n newInit.headers.set(key, value);\r\n } else if (Array.isArray(newInit.headers)) {\r\n newInit.headers.push([key, value]);\r\n } else {\r\n (newInit.headers as any)[key] = value;\r\n }\r\n };\r\n\r\n setHeader('x-senzor-trace-id', trace.id);\r\n setHeader('x-senzor-parent-span-id', spanId);\r\n\r\n try {\r\n const response = await originalFetch(input, newInit);\r\n\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 let optionsIndex = 0;\r\n\r\n // Parsing Logic: http.request(url, options, cb) OR http.request(options, cb)\r\n if (typeof args[0] === 'string' || args[0] instanceof URL) {\r\n urlStr = args[0].toString();\r\n optionsIndex = 1;\r\n } else {\r\n optionsIndex = 0;\r\n }\r\n\r\n // Ensure options object exists at correct index\r\n if (!args[optionsIndex] || typeof args[optionsIndex] !== 'object') {\r\n args[optionsIndex] = {};\r\n }\r\n options = args[optionsIndex];\r\n\r\n // Construct URL if missing\r\n if (!urlStr) {\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 // Guard\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();\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 (Mutate the options object reference directly)\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 // Debug\r\n if (debug) console.log(`[Senzor] Injecting headers to ${urlStr}`);\r\n\r\n // Call Original\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));\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","setHeader","key","value","response","duration","err","instrumentHttp","requestWrapper","args","options","optionsIndex","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","getHeader","key","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"]}
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, Trace, SenzorError } from './types';\r\n\r\nexport class Transport {\r\n private traceQueue: Trace[] = [];\r\n private errorQueue: SenzorError[] = [];\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 addTrace(trace: any) {\r\n this.traceQueue.push(trace);\r\n if (this.traceQueue.length >= (this.config.batchSize || 100)) {\r\n this.flush();\r\n }\r\n }\r\n\r\n public addError(error: SenzorError) {\r\n this.errorQueue.push(error);\r\n if (this.errorQueue.length >= (this.config.batchSize || 100)) {\r\n this.flush();\r\n }\r\n }\r\n\r\n public async flush() {\r\n if (this.traceQueue.length === 0 && this.errorQueue.length === 0) return;\r\n\r\n const payload = {\r\n traces: [...this.traceQueue],\r\n errors: [...this.errorQueue]\r\n };\r\n\r\n this.traceQueue = [];\r\n this.errorQueue = [];\r\n\r\n try {\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(payload),\r\n keepalive: true,\r\n });\r\n\r\n if (this.config.debug) console.log(`[Senzor] Flushed ${payload.traces.length} traces, ${payload.errors.length} errors`);\r\n } catch (err) {\r\n if (this.config.debug) console.error('[Senzor] Ingestion Error:', err);\r\n }\r\n }\r\n}","import { AsyncLocalStorage } from 'async_hooks';\r\nimport { ActiveTrace } 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};","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 this.setupGlobalErrorHandlers();\r\n\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 & Error Tracking enabled');\r\n }\r\n }\r\n\r\n private setupGlobalErrorHandlers() {\r\n process.on('uncaughtException', (error) => {\r\n this.captureError(error, { type: 'uncaughtException' });\r\n });\r\n\r\n process.on('unhandledRejection', (reason) => {\r\n this.captureError(reason, { type: 'unhandledRejection' });\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 let parentTraceId = undefined;\r\n let parentSpanId = undefined;\r\n\r\n if (data.headers) {\r\n const getHeader = (key: string) => {\r\n if (data.headers[key]) return data.headers[key];\r\n if (data.headers[key.toLowerCase()]) return data.headers[key.toLowerCase()];\r\n return undefined;\r\n };\r\n\r\n parentTraceId = getHeader('x-senzor-trace-id');\r\n parentSpanId = getHeader('x-senzor-parent-span-id');\r\n\r\n if (Array.isArray(parentTraceId)) parentTraceId = parentTraceId[0];\r\n if (Array.isArray(parentSpanId)) parentSpanId = parentSpanId[0];\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,\r\n parentSpanId\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 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 };\r\n this.transport.addTrace(payload);\r\n }\r\n\r\n // --- NEW: Standalone Error Capture ---\r\n public captureError(error: unknown, context: any = {}) {\r\n if (!this.transport) return;\r\n\r\n let parsedError: Error;\r\n if (error instanceof Error) {\r\n parsedError = error;\r\n } else {\r\n parsedError = new Error(String(error));\r\n }\r\n\r\n // Attempt to link to active trace\r\n const currentTrace = Context.current();\r\n\r\n this.transport.addError({\r\n errorClass: parsedError.name || 'Error',\r\n message: parsedError.message,\r\n stackTrace: parsedError.stack,\r\n traceId: currentTrace?.id,\r\n context,\r\n timestamp: new Date().toISOString()\r\n });\r\n }\r\n\r\n public track(data: any) {\r\n this.transport?.addTrace({ traceId: randomUUID(), ...data, spans: [], timestamp: new Date().toISOString() });\r\n }\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();\r\n return { end: (meta?: any, status?: number) => { Context.addSpan({ spanId, 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\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 ---\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 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 if (ingestHost && urlStr.includes(ingestHost)) {\r\n return originalFetch(input, init);\r\n }\r\n\r\n const trace = Context.current();\r\n if (!trace) {\r\n return originalFetch(input, init);\r\n }\r\n\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();\r\n\r\n let hostname = 'unknown';\r\n try { hostname = new URL(urlStr).hostname; } catch (e) { }\r\n\r\n // Inject Headers\r\n const newInit = { ...init } as RequestInit;\r\n if (!newInit.headers) newInit.headers = {};\r\n\r\n // Helper to set header on various types\r\n const setHeader = (key: string, value: string) => {\r\n if (newInit.headers instanceof Headers) {\r\n newInit.headers.set(key, value);\r\n } else if (Array.isArray(newInit.headers)) {\r\n newInit.headers.push([key, value]);\r\n } else {\r\n (newInit.headers as any)[key] = value;\r\n }\r\n };\r\n\r\n setHeader('x-senzor-trace-id', trace.id);\r\n setHeader('x-senzor-parent-span-id', spanId);\r\n\r\n try {\r\n const response = await originalFetch(input, newInit);\r\n\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 let optionsIndex = 0;\r\n\r\n // Parsing Logic: http.request(url, options, cb) OR http.request(options, cb)\r\n if (typeof args[0] === 'string' || args[0] instanceof URL) {\r\n urlStr = args[0].toString();\r\n optionsIndex = 1;\r\n } else {\r\n optionsIndex = 0;\r\n }\r\n\r\n // Ensure options object exists at correct index\r\n if (!args[optionsIndex] || typeof args[optionsIndex] !== 'object') {\r\n args[optionsIndex] = {};\r\n }\r\n options = args[optionsIndex];\r\n\r\n // Construct URL if missing\r\n if (!urlStr) {\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 // Guard\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();\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 (Mutate the options object reference directly)\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 // Debug\r\n if (debug) console.log(`[Senzor] Injecting headers to ${urlStr}`);\r\n\r\n // Call Original\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));\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","error","payload","err","import_async_hooks","storage","Context","trace","fn","span","store","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","setHeader","key","value","response","duration","err","instrumentHttp","requestWrapper","args","options","optionsIndex","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","error","reason","data","next","parentTraceId","parentSpanId","getHeader","key","trace","Context","status","extraData","duration","payload","context","parsedError","currentTrace","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 W}from"async_hooks";var I=new W,l={run:(e,t)=>I.run(e,t),current:()=>I.getStore(),addSpan:e=>{let t=I.getStore();t&&t.spans.push(e)},setError:e=>{let t=I.getStore();t&&(t.error={name:e.name,message:e.message,stack:e.stack})}};import{randomUUID as F}from"crypto";import H from"http";import U from"https";import{URL as x}from"url";import{randomUUID as P}from"crypto";var z=(e,t,n)=>{if(!e[t])return;let r=e[t];e[t]=n(r)},R=(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 c=l.current();if(!c)return r(o,a);let s=(a?.method||"GET").toUpperCase(),d=performance.now()-c.startTime,S=performance.now(),T=P(),w="unknown";try{w=new x(i).hostname}catch{}let h={...a};h.headers||(h.headers={});let m=(u,f)=>{h.headers instanceof Headers?h.headers.set(u,f):Array.isArray(h.headers)?h.headers.push([u,f]):h.headers[u]=f};m("x-senzor-trace-id",c.id),m("x-senzor-parent-span-id",T);try{let u=await r(o,h),f=performance.now()-S;return l.addSpan({spanId:T,name:`${s} ${w}`,type:"http",startTime:d,duration:f,status:u.status,meta:{url:i,method:s,library:"fetch"}}),u}catch(u){let f=performance.now()-S;throw l.addSpan({spanId:T,name:`${s} ${w}`,type:"http",startTime:d,duration:f,status:500,meta:{error:u.message,url:i,library:"fetch"}}),u}}},$=(e,t=!1)=>{let n="";try{n=new x(e).hostname}catch{}let r=o=>function(...a){let i={},c="",s=0;if(typeof a[0]=="string"||a[0]instanceof x?(c=a[0].toString(),s=1):s=0,(!a[s]||typeof a[s]!="object")&&(a[s]={}),i=a[s],!c){let g=i.protocol||(i.port===443?"https:":"http:"),y=i.hostname||i.host||"localhost",C=i.path||"/";c=`${g}//${y}${C}`}if(n&&(c.includes(n)||i.hostname&&i.hostname.includes(n)))return o.apply(this,a);let d=l.current();if(!d)return o.apply(this,a);let S=(i.method||"GET").toUpperCase(),T=performance.now()-d.startTime,w=performance.now(),h=P(),m="unknown";try{m=new x(c).hostname}catch{m=i.hostname||"unknown"}i.headers||(i.headers={}),i.headers["x-senzor-trace-id"]=d.id,i.headers["x-senzor-parent-span-id"]=h,t&&console.log(`[Senzor] Injecting headers to ${c}`);let u=o.apply(this,a),f=(g,y)=>{let C=performance.now()-w;l.addSpan({spanId:h,name:`${S} ${m}`,type:"http",startTime:T,duration:C,status:y?500:g?.statusCode||0,meta:{url:c,method:S,library:"http"}})};return u.on("response",g=>{g.once("end",()=>f(g)),g.once("close",()=>f(g)),g.once("error",y=>f(g,y))}),u.on("error",g=>f(null,g)),u};z(H,"request",r),z(H,"get",r),z(U,"request",r),z(U,"get",r)};var N=(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=(s,d,S,T,w,h)=>{let m=performance.now()-T;l.addSpan({name:`MongoDB ${s}`,type:"db",startTime:performance.now()-w-m,duration:m,status:h?500:0,meta:{collection:S,operation:d,error:h?h.message:void 0}}),e&&console.log(`[Senzor] Captured Mongo: ${s} (${m.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 T=l.current();if(!T)return d.apply(this,S);let w=performance.now(),h=T.startTime,m=this.collectionName;try{let u=d.apply(this,S);return u&&typeof u.then=="function"?u.then(f=>(a(s,s,m,w,h),f),f=>{throw a(s,s,m,w,h,f),f}):u}catch(u){throw a(s,s,m,w,h,u),u}}});let c=(s,d)=>{if(!s||!s.prototype.toArray)return;let S=s.prototype.toArray;s.prototype.toArray=function(...T){let w=l.current();if(!w)return S.apply(this,T);let h=performance.now(),m=w.startTime,u=this.namespace?.collection||"unknown",f=y=>(a(d,d,u,h,m),y),g=y=>{throw a(d,d,u,h,m,y),y};try{let y=S.apply(this,T);return y&&typeof y.then=="function"?y.then(f,g):f(y)}catch(y){g(y)}}};c(r,"find"),c(o,"aggregate")}catch(t){e&&console.warn("[Senzor] MongoDB instrumentation warning:",t.message)}};var M=()=>{try{let e=A("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,c=t.apply(this,n);return c&&typeof c.then=="function"?c.then(s=>{let d=performance.now()-a;return l.addSpan({name:"Postgres Query",type:"db",startTime:o,duration:d,meta:{query:i}}),s}):c}}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{$(n,r)}catch{}try{R(n,r)}catch{}try{N(r)}catch{}try{M()}catch{}this.isInstrumented=!0,r&&console.log("[Senzor] Auto-instrumentation enabled")}}startTrace(t,n){if(!this.transport)return n();let r,o;if(t.headers){let i=c=>{if(t.headers[c])return t.headers[c];if(t.headers[c.toLowerCase()])return t.headers[c.toLowerCase()];if(t.headers[c.toUpperCase()])return t.headers[c.toUpperCase()]};r=i("x-senzor-trace-id"),o=i("x-senzor-parent-span-id")}let a={id:F(),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:F(),...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=F();return{end:(c,s)=>{l.addSpan({spanId:i,name:t,type:n,startTime:o,duration:performance.now()-a,status:s,meta:c})}}}async flush(){this.transport&&await this.transport.flush()}},p=new O;var k=()=>(e,t,n)=>{p.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",p.endTrace(t.statusCode,{route:r})}catch{}}),n()})},D=()=>(e,t,n,r)=>{p.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],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:b(t);var K=e=>t=>{let n=t.node.req,r=n.originalUrl||n.url||"/";return p.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),p.endTrace(a,{route:v(t,r)}),o}catch(o){p.captureError(o);let a=o.statusCode||o.status||500;throw p.endTrace(a,{route:v(t,r)}),o}})};var L=e=>async(t,n)=>{let r=t.url?new URL(t.url):{pathname:"/"},o=t.method||"GET",a={},i,c;return typeof t.headers.get=="function"?(i=t.headers.get("user-agent"),c=t.headers.get("x-forwarded-for"),t.headers.forEach((s,d)=>{a[d]=s})):(a=t.headers,i=a["user-agent"],c=a["x-forwarded-for"]),p.startTrace({method:o,path:r.pathname,userAgent:i,ip:c,headers:a},async()=>{try{let s=await e(t,n),d=s?.status||200;return p.endTrace(d,{route:b(r.pathname)}),s}catch(s){throw p.captureError(s),p.endTrace(500,{route:b(r.pathname)}),s}})},G=e=>async(t,n)=>{let r=t.url?t.url.split("?")[0]:"/";return p.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=()=>{p.endTrace(n.statusCode||200,{route:b(r)})};n.once("finish",o),n.once("close",o);try{return await e(t,n)}catch(a){throw p.captureError(a),a}})};var j=(e,t,n)=>{t&&t.apiKey&&p.init(t),e.addHook("onRequest",(r,o,a)=>{p.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)=>{p.captureError(a),i()}),e.addHook("onResponse",(r,o,a)=>{let i=r.routeOptions?.url||r.routerPath||"UNKNOWN";p.endTrace(o.statusCode,{route:i}),a()}),n()};var B={init:e=>p.init(e),flush:()=>p.flush(),track:p.track.bind(p),startSpan:p.startSpan.bind(p),captureException:p.captureError.bind(p),requestHandler:k,errorHandler:D,wrapNextRoute:L,wrapNextPages:G,wrapH3:K,fastifyPlugin:j},Ot=B;export{B as Senzor,Ot as default};
1
+ var A=(r=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(r,{get:(t,n)=>(typeof require<"u"?require:t)[n]}):r)(function(r){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+r+'" is not supported')});var E=class{constructor(t){this.config=t;this.traceQueue=[];this.errorQueue=[];this.timer=null;typeof setInterval<"u"&&(this.timer=setInterval(()=>this.flush(),t.flushInterval||1e4),this.timer&&typeof this.timer.unref=="function"&&this.timer.unref())}addTrace(t){this.traceQueue.push(t),this.traceQueue.length>=(this.config.batchSize||100)&&this.flush()}addError(t){this.errorQueue.push(t),this.errorQueue.length>=(this.config.batchSize||100)&&this.flush()}async flush(){if(this.traceQueue.length===0&&this.errorQueue.length===0)return;let t={traces:[...this.traceQueue],errors:[...this.errorQueue]};this.traceQueue=[],this.errorQueue=[];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.traces.length} traces, ${t.errors.length} errors`)}catch(n){this.config.debug&&console.error("[Senzor] Ingestion Error:",n)}}};import{AsyncLocalStorage as L}from"async_hooks";var C=new L,f={run:(r,t)=>C.run(r,t),current:()=>C.getStore(),addSpan:r=>{let t=C.getStore();t&&t.spans.push(r)}};import{randomUUID as F}from"crypto";import O from"http";import R from"https";import{URL as x}from"url";import{randomUUID as P}from"crypto";var z=(r,t,n)=>{if(!r[t])return;let e=r[t];r[t]=n(e)},$=(r,t=!1)=>{if(!globalThis.fetch)return;let n="";try{n=new x(r).hostname}catch{}let e=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 e(o,a);let p=f.current();if(!p)return e(o,a);let s=(a?.method||"GET").toUpperCase(),d=performance.now()-p.startTime,S=performance.now(),T=P(),w="unknown";try{w=new x(i).hostname}catch{}let h={...a};h.headers||(h.headers={});let m=(u,l)=>{h.headers instanceof Headers?h.headers.set(u,l):Array.isArray(h.headers)?h.headers.push([u,l]):h.headers[u]=l};m("x-senzor-trace-id",p.id),m("x-senzor-parent-span-id",T);try{let u=await e(o,h),l=performance.now()-S;return f.addSpan({spanId:T,name:`${s} ${w}`,type:"http",startTime:d,duration:l,status:u.status,meta:{url:i,method:s,library:"fetch"}}),u}catch(u){let l=performance.now()-S;throw f.addSpan({spanId:T,name:`${s} ${w}`,type:"http",startTime:d,duration:l,status:500,meta:{error:u.message,url:i,library:"fetch"}}),u}}},U=(r,t=!1)=>{let n="";try{n=new x(r).hostname}catch{}let e=o=>function(...a){let i={},p="",s=0;if(typeof a[0]=="string"||a[0]instanceof x?(p=a[0].toString(),s=1):s=0,(!a[s]||typeof a[s]!="object")&&(a[s]={}),i=a[s],!p){let g=i.protocol||(i.port===443?"https:":"http:"),y=i.hostname||i.host||"localhost",I=i.path||"/";p=`${g}//${y}${I}`}if(n&&(p.includes(n)||i.hostname&&i.hostname.includes(n)))return o.apply(this,a);let d=f.current();if(!d)return o.apply(this,a);let S=(i.method||"GET").toUpperCase(),T=performance.now()-d.startTime,w=performance.now(),h=P(),m="unknown";try{m=new x(p).hostname}catch{m=i.hostname||"unknown"}i.headers||(i.headers={}),i.headers["x-senzor-trace-id"]=d.id,i.headers["x-senzor-parent-span-id"]=h,t&&console.log(`[Senzor] Injecting headers to ${p}`);let u=o.apply(this,a),l=(g,y)=>{let I=performance.now()-w;f.addSpan({spanId:h,name:`${S} ${m}`,type:"http",startTime:T,duration:I,status:y?500:g?.statusCode||0,meta:{url:p,method:S,library:"http"}})};return u.on("response",g=>{g.once("end",()=>l(g)),g.once("close",()=>l(g)),g.once("error",y=>l(g,y))}),u.on("error",g=>l(null,g)),u};z(O,"request",e),z(O,"get",e),z(R,"request",e),z(R,"get",e)};var k=(r=!1)=>{try{let t=A("mongodb"),n=t.Collection,e=t.FindCursor||A("mongodb/lib/cursor/find_cursor").FindCursor,o=t.AggregationCursor||A("mongodb/lib/cursor/aggregation_cursor").AggregationCursor;r&&console.log("[Senzor] Instrumenting MongoDB (Collection + Cursors)...");let a=(s,d,S,T,w,h)=>{let m=performance.now()-T;f.addSpan({name:`MongoDB ${s}`,type:"db",startTime:performance.now()-w-m,duration:m,status:h?500:0,meta:{collection:S,operation:d,error:h?h.message:void 0}}),r&&console.log(`[Senzor] Captured Mongo: ${s} (${m.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 T=f.current();if(!T)return d.apply(this,S);let w=performance.now(),h=T.startTime,m=this.collectionName;try{let u=d.apply(this,S);return u&&typeof u.then=="function"?u.then(l=>(a(s,s,m,w,h),l),l=>{throw a(s,s,m,w,h,l),l}):u}catch(u){throw a(s,s,m,w,h,u),u}}});let p=(s,d)=>{if(!s||!s.prototype.toArray)return;let S=s.prototype.toArray;s.prototype.toArray=function(...T){let w=f.current();if(!w)return S.apply(this,T);let h=performance.now(),m=w.startTime,u=this.namespace?.collection||"unknown",l=y=>(a(d,d,u,h,m),y),g=y=>{throw a(d,d,u,h,m,y),y};try{let y=S.apply(this,T);return y&&typeof y.then=="function"?y.then(l,g):l(y)}catch(y){g(y)}}};p(e,"find"),p(o,"aggregate")}catch(t){r&&console.warn("[Senzor] MongoDB instrumentation warning:",t.message)}};var N=()=>{try{let r=A("pg"),t=r.Client.prototype.query;r.Client.prototype.query=function(...n){let e=f.current();if(!e)return t.apply(this,n);let o=performance.now()-e.startTime,a=performance.now(),i=typeof n[0]=="string"?n[0]:n[0].text,p=t.apply(this,n);return p&&typeof p.then=="function"?p.then(s=>{let d=performance.now()-a;return f.addSpan({name:"Postgres Query",type:"db",startTime:o,duration:d,meta:{query:i}}),s}):p}}catch{}};var v=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",e=t.debug||!1;if(this.transport=new E({...t,endpoint:n}),!this.isInstrumented){this.setupGlobalErrorHandlers();try{U(n,e)}catch{}try{$(n,e)}catch{}try{k(e)}catch{}try{N()}catch{}this.isInstrumented=!0,e&&console.log("[Senzor] Auto-instrumentation & Error Tracking enabled")}}setupGlobalErrorHandlers(){process.on("uncaughtException",t=>{this.captureError(t,{type:"uncaughtException"})}),process.on("unhandledRejection",t=>{this.captureError(t,{type:"unhandledRejection"})})}startTrace(t,n){if(!this.transport)return n();let e,o;if(t.headers){let i=p=>{if(t.headers[p])return t.headers[p];if(t.headers[p.toLowerCase()])return t.headers[p.toLowerCase()]};e=i("x-senzor-trace-id"),o=i("x-senzor-parent-span-id"),Array.isArray(e)&&(e=e[0]),Array.isArray(o)&&(o=o[0])}let a={id:F(),startTime:performance.now(),data:{...t,parentTraceId:e,parentSpanId:o},spans:[]};return f.run(a,n)}endTrace(t,n={}){let e=f.current();if(!e||!this.transport)return;let o=performance.now()-e.startTime,a={traceId:e.id,parentTraceId:e.data.parentTraceId,parentSpanId:e.data.parentSpanId,...e.data,...n,status:t,duration:o,spans:e.spans,timestamp:new Date().toISOString()};this.transport.addTrace(a)}captureError(t,n={}){if(!this.transport)return;let e;t instanceof Error?e=t:e=new Error(String(t));let o=f.current();this.transport.addError({errorClass:e.name||"Error",message:e.message,stackTrace:e.stack,traceId:o?.id,context:n,timestamp:new Date().toISOString()})}track(t){this.transport?.addTrace({traceId:F(),...t,spans:[],timestamp:new Date().toISOString()})}startSpan(t,n="custom"){let e=f.current();if(!e)return{end:()=>{}};let o=performance.now()-e.startTime,a=performance.now(),i=F();return{end:(p,s)=>{f.addSpan({spanId:i,name:t,type:n,startTime:o,duration:performance.now()-a,status:s,meta:p})}}}async flush(){this.transport&&await this.transport.flush()}},c=new v;var Q=()=>(r,t,n)=>{c.startTrace({method:r.method,path:r.originalUrl||r.url,ip:r.ip||r.socket?.remoteAddress,userAgent:r.headers["user-agent"],headers:r.headers},()=>{t.once("finish",()=>{try{let e="UNKNOWN";r.route&&r.route.path?e=(r.baseUrl||"")+r.route.path:t.statusCode===404?e="Not Found":e=r.path||"Wildcard",c.endTrace(t.statusCode,{route:e})}catch{}}),n()})},M=()=>(r,t,n,e)=>{c.captureError(r),e(r)};var b=r=>!r||r==="/"?"/":r.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],H=(r,t)=>r.route&&r.route.path?(r.baseUrl||"")+r.route.path:r.context&&r.context.matchedRoute?r.context.matchedRoute.path:r.routerPath?r.routerPath:b(t);var D=r=>t=>{let n=t.node.req,e=n.originalUrl||n.url||"/";return c.startTrace({method:n.method||"GET",path:e,ip:n.headers["x-forwarded-for"]||n.socket?.remoteAddress,userAgent:n.headers["user-agent"],headers:n.headers},async()=>{try{let o=await r(t),a=200;return t.node.res.statusCode&&(a=t.node.res.statusCode),o&&o.statusCode&&(a=o.statusCode),c.endTrace(a,{route:H(t,e)}),o}catch(o){c.captureError(o);let a=o.statusCode||o.status||500;throw c.endTrace(a,{route:H(t,e)}),o}})};var G=r=>async(t,n)=>{let e=t.url?new URL(t.url):{pathname:"/"},o=t.method||"GET",a={},i,p;return typeof t.headers.get=="function"?(i=t.headers.get("user-agent"),p=t.headers.get("x-forwarded-for"),t.headers.forEach((s,d)=>{a[d]=s})):(a=t.headers,i=a["user-agent"],p=a["x-forwarded-for"]),c.startTrace({method:o,path:e.pathname,userAgent:i,ip:p,headers:a},async()=>{try{let s=await r(t,n),d=s?.status||200;return c.endTrace(d,{route:b(e.pathname)}),s}catch(s){throw c.captureError(s),c.endTrace(500,{route:b(e.pathname)}),s}})},K=r=>async(t,n)=>{let e=t.url?t.url.split("?")[0]:"/";return c.startTrace({method:t.method||"GET",path:e,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(e)})};n.once("finish",o),n.once("close",o);try{return await r(t,n)}catch(a){throw c.captureError(a),a}})};var j=(r,t,n)=>{t&&t.apiKey&&c.init(t),r.addHook("onRequest",(e,o,a)=>{c.startTrace({method:e.method,path:e.raw.url||e.url,ip:e.ip,userAgent:e.headers["user-agent"],headers:e.headers},()=>a())}),r.addHook("onError",(e,o,a,i)=>{c.captureError(a),i()}),r.addHook("onResponse",(e,o,a)=>{let i=e.routeOptions?.url||e.routerPath||"UNKNOWN";c.endTrace(o.statusCode,{route:i}),a()}),n()};var W={init:r=>c.init(r),flush:()=>c.flush(),track:c.track.bind(c),startSpan:c.startSpan.bind(c),captureException:c.captureError.bind(c),requestHandler:Q,errorHandler:M,wrapNextRoute:G,wrapNextPages:K,wrapH3:D,fastifyPlugin:j},vt=W;export{W as Senzor,vt 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']> & { headers?: any }, next: () => T): T {\r\n if (!this.transport) return next();\r\n\r\n // Trace Propagation Extraction\r\n let parentTraceId = undefined;\r\n let parentSpanId = undefined;\r\n\r\n if (data.headers) {\r\n // Robust header checking (Node headers are usually lowercase, but handle mixed)\r\n const getHeader = (key: string) => {\r\n // Direct access\r\n if (data.headers[key]) return data.headers[key];\r\n if (data.headers[key.toLowerCase()]) return data.headers[key.toLowerCase()];\r\n if (data.headers[key.toUpperCase()]) return data.headers[key.toUpperCase()];\r\n return undefined;\r\n };\r\n\r\n parentTraceId = getHeader('x-senzor-trace-id');\r\n parentSpanId = getHeader('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,\r\n parentSpanId\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 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 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 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();\r\n return { end: (meta?: any, status?: number) => { Context.addSpan({ spanId, 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\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 ---\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 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 if (ingestHost && urlStr.includes(ingestHost)) {\r\n return originalFetch(input, init);\r\n }\r\n\r\n const trace = Context.current();\r\n if (!trace) {\r\n return originalFetch(input, init);\r\n }\r\n\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();\r\n\r\n let hostname = 'unknown';\r\n try { hostname = new URL(urlStr).hostname; } catch (e) { }\r\n\r\n // Inject Headers\r\n const newInit = { ...init } as RequestInit;\r\n if (!newInit.headers) newInit.headers = {};\r\n\r\n // Helper to set header on various types\r\n const setHeader = (key: string, value: string) => {\r\n if (newInit.headers instanceof Headers) {\r\n newInit.headers.set(key, value);\r\n } else if (Array.isArray(newInit.headers)) {\r\n newInit.headers.push([key, value]);\r\n } else {\r\n (newInit.headers as any)[key] = value;\r\n }\r\n };\r\n\r\n setHeader('x-senzor-trace-id', trace.id);\r\n setHeader('x-senzor-parent-span-id', spanId);\r\n\r\n try {\r\n const response = await originalFetch(input, newInit);\r\n\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 let optionsIndex = 0;\r\n\r\n // Parsing Logic: http.request(url, options, cb) OR http.request(options, cb)\r\n if (typeof args[0] === 'string' || args[0] instanceof URL) {\r\n urlStr = args[0].toString();\r\n optionsIndex = 1;\r\n } else {\r\n optionsIndex = 0;\r\n }\r\n\r\n // Ensure options object exists at correct index\r\n if (!args[optionsIndex] || typeof args[optionsIndex] !== 'object') {\r\n args[optionsIndex] = {};\r\n }\r\n options = args[optionsIndex];\r\n\r\n // Construct URL if missing\r\n if (!urlStr) {\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 // Guard\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();\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 (Mutate the options object reference directly)\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 // Debug\r\n if (debug) console.log(`[Senzor] Injecting headers to ${urlStr}`);\r\n\r\n // Call Original\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));\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","setHeader","key","value","response","duration","err","instrumentHttp","requestWrapper","args","options","optionsIndex","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","getHeader","key","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"]}
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, Trace, SenzorError } from './types';\r\n\r\nexport class Transport {\r\n private traceQueue: Trace[] = [];\r\n private errorQueue: SenzorError[] = [];\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 addTrace(trace: any) {\r\n this.traceQueue.push(trace);\r\n if (this.traceQueue.length >= (this.config.batchSize || 100)) {\r\n this.flush();\r\n }\r\n }\r\n\r\n public addError(error: SenzorError) {\r\n this.errorQueue.push(error);\r\n if (this.errorQueue.length >= (this.config.batchSize || 100)) {\r\n this.flush();\r\n }\r\n }\r\n\r\n public async flush() {\r\n if (this.traceQueue.length === 0 && this.errorQueue.length === 0) return;\r\n\r\n const payload = {\r\n traces: [...this.traceQueue],\r\n errors: [...this.errorQueue]\r\n };\r\n\r\n this.traceQueue = [];\r\n this.errorQueue = [];\r\n\r\n try {\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(payload),\r\n keepalive: true,\r\n });\r\n\r\n if (this.config.debug) console.log(`[Senzor] Flushed ${payload.traces.length} traces, ${payload.errors.length} errors`);\r\n } catch (err) {\r\n if (this.config.debug) console.error('[Senzor] Ingestion Error:', err);\r\n }\r\n }\r\n}","import { AsyncLocalStorage } from 'async_hooks';\r\nimport { ActiveTrace } 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};","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 this.setupGlobalErrorHandlers();\r\n\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 & Error Tracking enabled');\r\n }\r\n }\r\n\r\n private setupGlobalErrorHandlers() {\r\n process.on('uncaughtException', (error) => {\r\n this.captureError(error, { type: 'uncaughtException' });\r\n });\r\n\r\n process.on('unhandledRejection', (reason) => {\r\n this.captureError(reason, { type: 'unhandledRejection' });\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 let parentTraceId = undefined;\r\n let parentSpanId = undefined;\r\n\r\n if (data.headers) {\r\n const getHeader = (key: string) => {\r\n if (data.headers[key]) return data.headers[key];\r\n if (data.headers[key.toLowerCase()]) return data.headers[key.toLowerCase()];\r\n return undefined;\r\n };\r\n\r\n parentTraceId = getHeader('x-senzor-trace-id');\r\n parentSpanId = getHeader('x-senzor-parent-span-id');\r\n\r\n if (Array.isArray(parentTraceId)) parentTraceId = parentTraceId[0];\r\n if (Array.isArray(parentSpanId)) parentSpanId = parentSpanId[0];\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,\r\n parentSpanId\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 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 };\r\n this.transport.addTrace(payload);\r\n }\r\n\r\n // --- NEW: Standalone Error Capture ---\r\n public captureError(error: unknown, context: any = {}) {\r\n if (!this.transport) return;\r\n\r\n let parsedError: Error;\r\n if (error instanceof Error) {\r\n parsedError = error;\r\n } else {\r\n parsedError = new Error(String(error));\r\n }\r\n\r\n // Attempt to link to active trace\r\n const currentTrace = Context.current();\r\n\r\n this.transport.addError({\r\n errorClass: parsedError.name || 'Error',\r\n message: parsedError.message,\r\n stackTrace: parsedError.stack,\r\n traceId: currentTrace?.id,\r\n context,\r\n timestamp: new Date().toISOString()\r\n });\r\n }\r\n\r\n public track(data: any) {\r\n this.transport?.addTrace({ traceId: randomUUID(), ...data, spans: [], timestamp: new Date().toISOString() });\r\n }\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();\r\n return { end: (meta?: any, status?: number) => { Context.addSpan({ spanId, 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\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 ---\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 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 if (ingestHost && urlStr.includes(ingestHost)) {\r\n return originalFetch(input, init);\r\n }\r\n\r\n const trace = Context.current();\r\n if (!trace) {\r\n return originalFetch(input, init);\r\n }\r\n\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();\r\n\r\n let hostname = 'unknown';\r\n try { hostname = new URL(urlStr).hostname; } catch (e) { }\r\n\r\n // Inject Headers\r\n const newInit = { ...init } as RequestInit;\r\n if (!newInit.headers) newInit.headers = {};\r\n\r\n // Helper to set header on various types\r\n const setHeader = (key: string, value: string) => {\r\n if (newInit.headers instanceof Headers) {\r\n newInit.headers.set(key, value);\r\n } else if (Array.isArray(newInit.headers)) {\r\n newInit.headers.push([key, value]);\r\n } else {\r\n (newInit.headers as any)[key] = value;\r\n }\r\n };\r\n\r\n setHeader('x-senzor-trace-id', trace.id);\r\n setHeader('x-senzor-parent-span-id', spanId);\r\n\r\n try {\r\n const response = await originalFetch(input, newInit);\r\n\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 let optionsIndex = 0;\r\n\r\n // Parsing Logic: http.request(url, options, cb) OR http.request(options, cb)\r\n if (typeof args[0] === 'string' || args[0] instanceof URL) {\r\n urlStr = args[0].toString();\r\n optionsIndex = 1;\r\n } else {\r\n optionsIndex = 0;\r\n }\r\n\r\n // Ensure options object exists at correct index\r\n if (!args[optionsIndex] || typeof args[optionsIndex] !== 'object') {\r\n args[optionsIndex] = {};\r\n }\r\n options = args[optionsIndex];\r\n\r\n // Construct URL if missing\r\n if (!urlStr) {\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 // Guard\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();\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 (Mutate the options object reference directly)\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 // Debug\r\n if (debug) console.log(`[Senzor] Injecting headers to ${urlStr}`);\r\n\r\n // Call Original\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));\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","error","payload","err","AsyncLocalStorage","storage","Context","trace","fn","span","store","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","setHeader","key","value","response","duration","err","instrumentHttp","requestWrapper","args","options","optionsIndex","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","error","reason","data","next","parentTraceId","parentSpanId","getHeader","key","trace","randomUUID","Context","status","extraData","duration","payload","context","parsedError","currentTrace","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.6",
3
+ "version": "1.1.8",
4
4
  "description": "Universal APM SDK for Senzor",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -23,35 +23,46 @@ export class SenzorClient {
23
23
  this.transport = new Transport({ ...options, endpoint });
24
24
 
25
25
  if (!this.isInstrumented) {
26
+ this.setupGlobalErrorHandlers();
27
+
26
28
  try { instrumentHttp(endpoint, debug); } catch (e) { }
27
29
  try { instrumentFetch(endpoint, debug); } catch (e) { }
28
30
  try { instrumentMongo(debug); } catch (e) { }
29
31
  try { instrumentPg(); } catch (e) { }
30
32
 
31
33
  this.isInstrumented = true;
32
- if (debug) console.log('[Senzor] Auto-instrumentation enabled');
34
+ if (debug) console.log('[Senzor] Auto-instrumentation & Error Tracking enabled');
33
35
  }
34
36
  }
35
37
 
38
+ private setupGlobalErrorHandlers() {
39
+ process.on('uncaughtException', (error) => {
40
+ this.captureError(error, { type: 'uncaughtException' });
41
+ });
42
+
43
+ process.on('unhandledRejection', (reason) => {
44
+ this.captureError(reason, { type: 'unhandledRejection' });
45
+ });
46
+ }
47
+
36
48
  public startTrace<T>(data: Partial<ActiveTrace['data']> & { headers?: any }, next: () => T): T {
37
49
  if (!this.transport) return next();
38
50
 
39
- // Trace Propagation Extraction
40
51
  let parentTraceId = undefined;
41
52
  let parentSpanId = undefined;
42
53
 
43
54
  if (data.headers) {
44
- // Robust header checking (Node headers are usually lowercase, but handle mixed)
45
55
  const getHeader = (key: string) => {
46
- // Direct access
47
56
  if (data.headers[key]) return data.headers[key];
48
57
  if (data.headers[key.toLowerCase()]) return data.headers[key.toLowerCase()];
49
- if (data.headers[key.toUpperCase()]) return data.headers[key.toUpperCase()];
50
58
  return undefined;
51
59
  };
52
60
 
53
61
  parentTraceId = getHeader('x-senzor-trace-id');
54
62
  parentSpanId = getHeader('x-senzor-parent-span-id');
63
+
64
+ if (Array.isArray(parentTraceId)) parentTraceId = parentTraceId[0];
65
+ if (Array.isArray(parentSpanId)) parentSpanId = parentSpanId[0];
55
66
  }
56
67
 
57
68
  const trace: ActiveTrace = {
@@ -79,22 +90,38 @@ export class SenzorClient {
79
90
  parentSpanId: trace.data.parentSpanId,
80
91
  ...trace.data,
81
92
  ...extraData,
82
- status, duration, spans: trace.spans, timestamp: new Date().toISOString(),
83
- error: trace.error
93
+ status, duration, spans: trace.spans, timestamp: new Date().toISOString()
84
94
  };
85
- this.transport.add(payload);
95
+ this.transport.addTrace(payload);
86
96
  }
87
97
 
88
- // --- NEW: Capture Exception ---
89
- public captureError(error: unknown) {
98
+ // --- NEW: Standalone Error Capture ---
99
+ public captureError(error: unknown, context: any = {}) {
100
+ if (!this.transport) return;
101
+
102
+ let parsedError: Error;
90
103
  if (error instanceof Error) {
91
- Context.setError(error);
92
- } else if (typeof error === 'string') {
93
- Context.setError(new Error(error));
104
+ parsedError = error;
105
+ } else {
106
+ parsedError = new Error(String(error));
94
107
  }
108
+
109
+ // Attempt to link to active trace
110
+ const currentTrace = Context.current();
111
+
112
+ this.transport.addError({
113
+ errorClass: parsedError.name || 'Error',
114
+ message: parsedError.message,
115
+ stackTrace: parsedError.stack,
116
+ traceId: currentTrace?.id,
117
+ context,
118
+ timestamp: new Date().toISOString()
119
+ });
95
120
  }
96
121
 
97
- public track(data: any) { this.transport?.add({ traceId: randomUUID(), ...data, spans: [], timestamp: new Date().toISOString() }); }
122
+ public track(data: any) {
123
+ this.transport?.addTrace({ traceId: randomUUID(), ...data, spans: [], timestamp: new Date().toISOString() });
124
+ }
98
125
 
99
126
  public startSpan(name: string, type: 'db' | 'http' | 'function' | 'custom' = 'custom') {
100
127
  const trace = Context.current();
@@ -1,5 +1,5 @@
1
1
  import { AsyncLocalStorage } from 'async_hooks';
2
- import { ActiveTrace, TraceError } from './types';
2
+ import { ActiveTrace } from './types';
3
3
 
4
4
  export const storage = new AsyncLocalStorage<ActiveTrace>();
5
5
 
@@ -17,17 +17,5 @@ export const Context = {
17
17
  if (store) {
18
18
  store.spans.push(span);
19
19
  }
20
- },
21
-
22
- // Attach error to current trace
23
- setError: (error: Error) => {
24
- const store = storage.getStore();
25
- if (store) {
26
- store.error = {
27
- name: error.name,
28
- message: error.message,
29
- stack: error.stack
30
- };
31
- }
32
20
  }
33
21
  };
@@ -1,7 +1,8 @@
1
- import { SenzorOptions } from './types';
1
+ import { SenzorOptions, Trace, SenzorError } from './types';
2
2
 
3
3
  export class Transport {
4
- private queue: any[] = [];
4
+ private traceQueue: Trace[] = [];
5
+ private errorQueue: SenzorError[] = [];
5
6
  private timer: NodeJS.Timeout | null = null;
6
7
 
7
8
  constructor(private config: SenzorOptions) {
@@ -13,35 +14,45 @@ export class Transport {
13
14
  }
14
15
  }
15
16
 
16
- public add(trace: any) {
17
- this.queue.push(trace);
18
- if (this.queue.length >= (this.config.batchSize || 100)) {
17
+ public addTrace(trace: any) {
18
+ this.traceQueue.push(trace);
19
+ if (this.traceQueue.length >= (this.config.batchSize || 100)) {
20
+ this.flush();
21
+ }
22
+ }
23
+
24
+ public addError(error: SenzorError) {
25
+ this.errorQueue.push(error);
26
+ if (this.errorQueue.length >= (this.config.batchSize || 100)) {
19
27
  this.flush();
20
28
  }
21
29
  }
22
30
 
23
31
  public async flush() {
24
- if (this.queue.length === 0) return;
32
+ if (this.traceQueue.length === 0 && this.errorQueue.length === 0) return;
33
+
34
+ const payload = {
35
+ traces: [...this.traceQueue],
36
+ errors: [...this.errorQueue]
37
+ };
25
38
 
26
- const batch = [...this.queue];
27
- this.queue = [];
39
+ this.traceQueue = [];
40
+ this.errorQueue = [];
28
41
 
29
42
  try {
30
- // Use global fetch (Node 18+)
31
43
  await fetch(this.config.endpoint || 'https://api.senzor.dev/api/ingest/apm', {
32
44
  method: 'POST',
33
45
  headers: {
34
46
  'Content-Type': 'application/json',
35
47
  'x-service-api-key': this.config.apiKey,
36
48
  },
37
- body: JSON.stringify(batch),
49
+ body: JSON.stringify(payload),
38
50
  keepalive: true,
39
51
  });
40
-
41
- if (this.config.debug) console.log(`[Senzor] Flushed ${batch.length} traces`);
52
+
53
+ if (this.config.debug) console.log(`[Senzor] Flushed ${payload.traces.length} traces, ${payload.errors.length} errors`);
42
54
  } catch (err) {
43
55
  if (this.config.debug) console.error('[Senzor] Ingestion Error:', err);
44
- // Dropping data to prevent memory leaks is preferred in APM
45
56
  }
46
57
  }
47
58
  }
package/src/core/types.ts CHANGED
@@ -7,7 +7,7 @@ export interface SenzorOptions {
7
7
  }
8
8
 
9
9
  export interface Span {
10
- spanId: string; // NEW: Unique ID for this span
10
+ spanId: string;
11
11
  name: string;
12
12
  type: 'db' | 'http' | 'function' | 'custom';
13
13
  startTime: number;
@@ -16,19 +16,20 @@ export interface Span {
16
16
  meta?: Record<string, any>;
17
17
  }
18
18
 
19
- export interface TraceError {
20
- name: string;
19
+ // NEW: Standalone Error Event
20
+ export interface SenzorError {
21
+ errorClass: string;
21
22
  message: string;
22
- stack?: string;
23
+ stackTrace?: string;
24
+ traceId?: string;
25
+ context?: any;
26
+ timestamp: string;
23
27
  }
24
28
 
25
29
  export interface Trace {
26
30
  traceId: string;
27
-
28
- // Distributed Tracing Fields
29
- parentTraceId?: string; // NEW
30
- parentSpanId?: string; // NEW
31
-
31
+ parentTraceId?: string;
32
+ parentSpanId?: string;
32
33
  method: string;
33
34
  route: string;
34
35
  path: string;
@@ -38,7 +39,6 @@ export interface Trace {
38
39
  userAgent?: string;
39
40
  timestamp: string;
40
41
  spans: Span[];
41
- error?: TraceError;
42
42
  }
43
43
 
44
44
  export interface ActiveTrace {
@@ -46,5 +46,4 @@ export interface ActiveTrace {
46
46
  startTime: number;
47
47
  data: Partial<Trace>;
48
48
  spans: Span[];
49
- error?: TraceError;
50
49
  }