@senzops/apm-node 1.1.2 → 1.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,2 +1,2 @@
1
- "use strict";(()=>{var B=Object.create;var F=Object.defineProperty;var G=Object.getOwnPropertyDescriptor;var W=Object.getOwnPropertyNames;var j=Object.getPrototypeOf,J=Object.prototype.hasOwnProperty;var y=(n=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(n,{get:(t,e)=>(typeof require<"u"?require:t)[e]}):n)(function(n){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+n+'" is not supported')});var Q=(n,t,e,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let s of W(t))!J.call(n,s)&&s!==e&&F(n,s,{get:()=>t[s],enumerable:!(r=G(t,s))||r.enumerable});return n};var M=(n,t,e)=>(e=n!=null?B(j(n)):{},Q(t||!n||!n.__esModule?F(e,"default",{value:n,enumerable:!0}):e,n));var T=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(e){this.config.debug&&console.error("[Senzor] Ingestion Error:",e)}}};var N=y("async_hooks"),C=new N.AsyncLocalStorage,p={run:(n,t)=>C.run(n,t),current:()=>C.getStore(),addSpan:n=>{let t=C.getStore();t?t.spans.push(n):console.warn("[Senzor] Lost context for span:",n.name)}};var P=y("crypto");var v=M(y("http")),O=M(y("https")),x=y("url");var S=(n,t,e)=>{if(!n[t])return;let r=n[t];n[t]=e(r)},k=(n,t=!1)=>{let e="";try{e=new x.URL(n).hostname,t&&console.log(`[Senzor] HTTP Instrumentation ignoring host: ${e}`)}catch{t&&console.error("[Senzor] Invalid Ingest URL for HTTP instrumentation")}let r=s=>function(...o){let a={},i="";if(typeof o[0]=="string"||o[0]instanceof x.URL)i=o[0].toString(),typeof o[1]=="object"&&o[1]!==null&&(a=o[1]);else{a=o[0]||{};let f=a.protocol||(a.port===443?"https:":"http:"),z=a.hostname||a.host||"localhost",A=a.path||"/";i=`${f}//${z}${A}`}if(e&&(i.includes(e)||a.hostname&&a.hostname.includes(e)))return s.apply(this,o);let u=p.current();if(!u)return s.apply(this,o);let m=(a.method||"GET").toUpperCase(),b=performance.now()-u.startTime,w=performance.now(),h="unknown";try{h=new x.URL(i).hostname}catch{h=a.hostname||"unknown"}t&&console.log(`[Senzor] Tracking HTTP: ${m} ${h}`);let l=s.apply(this,o),d=(f,z)=>{let A=performance.now()-w;p.addSpan({name:`${m} ${h}`,type:"http",startTime:b,duration:A,status:z?500:f?.statusCode||0,meta:{url:i,method:m}})};return l.on("response",f=>{f.once("end",()=>d(f))}),l.on("error",f=>{d(null,f)}),l};S(v.default,"request",r),S(v.default,"get",r),S(O.default,"request",r),S(O.default,"get",r)};var E=(n=!1)=>{try{let e=y("mongodb").Collection;n&&console.log("[Senzor] Instrumenting MongoDB...");let r=["insertOne","insertMany","updateOne","updateMany","replaceOne","deleteOne","deleteMany","count","countDocuments","estimatedDocumentCount","distinct"],s=["find","aggregate"];r.forEach(o=>{if(!e.prototype[o])return;let a=e.prototype[o];e.prototype[o]=function(...i){let u=p.current();if(!u)return a.apply(this,i);let m=performance.now()-u.startTime,b=performance.now(),w=this.collectionName,h=l=>{let d=performance.now()-b;p.addSpan({name:`MongoDB ${o} (${w})`,type:"db",startTime:m,duration:d,status:l?500:0,meta:{collection:w,operation:o}}),n&&console.log(`[Senzor] Captured Mongo Span: ${o}`)};try{let l=a.apply(this,i);return l&&typeof l.then=="function"?l.then(d=>(h(),d),d=>{throw h(d),d}):l}catch(l){throw h(l),l}}}),s.forEach(o=>{if(!e.prototype[o])return;let a=e.prototype[o];e.prototype[o]=function(...i){let u=p.current();if(!u)return a.apply(this,i);let m=performance.now()-u.startTime;return p.addSpan({name:`MongoDB ${o} (${this.collectionName})`,type:"db",startTime:m,duration:0,status:0,meta:{collection:this.collectionName,operation:o}}),n&&console.log(`[Senzor] Captured Mongo Cursor: ${o}`),a.apply(this,i)}})}catch(t){n&&console.warn("[Senzor] MongoDB instrumentation skipped:",t.message)}};var H=()=>{try{let n=y("pg"),t=n.Client.prototype.query;n.Client.prototype.query=function(...e){let r=p.current();if(!r)return t.apply(this,e);let s=performance.now()-r.startTime,o=performance.now(),a=typeof e[0]=="string"?e[0]:e[0].text,i=t.apply(this,e);return i&&typeof i.then=="function"?i.then(u=>{let m=performance.now()-o;return p.addSpan({name:"Postgres Query",type:"db",startTime:s,duration:m,meta:{query:a}}),u}):i}}catch{}};var I=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 e=t.endpoint||"https://api.senzor.dev/api/ingest/apm",r=t.debug||!1;if(this.transport=new T({...t,endpoint:e}),!this.isInstrumented){try{k(e,r)}catch{}try{E(r)}catch{}try{H()}catch{}this.isInstrumented=!0,r&&console.log("[Senzor] Auto-instrumentation enabled")}}startTrace(t,e){if(!this.transport)return e();let r={id:(0,P.randomUUID)(),startTime:performance.now(),data:t,spans:[]};return p.run(r,e)}endTrace(t,e={}){let r=p.current();if(!r||!this.transport)return;let s=performance.now()-r.startTime,o={traceId:r.id,...r.data,...e,status:t,duration:s,spans:r.spans,timestamp:new Date().toISOString()};this.options?.debug&&console.log(`[Senzor] Ended Trace ${r.id} with ${r.spans.length} spans`),this.transport.add(o)}track(t){if(!this.transport)return;let e={traceId:(0,P.randomUUID)(),...t,spans:[],timestamp:new Date().toISOString()};this.transport.add(e)}startSpan(t,e="custom"){let r=p.current();if(!r)return{end:()=>{}};let s=performance.now()-r.startTime,o=performance.now();return{end:(a,i)=>{let u=performance.now()-o;p.addSpan({name:t,type:e,startTime:s,duration:u,status:i,meta:a})}}}async flush(){this.transport&&await this.transport.flush()}},c=new I;var R=()=>(n,t,e)=>{c.startTrace({method:n.method,path:n.originalUrl||n.url,ip:n.ip||n.socket?.remoteAddress,userAgent:n.headers["user-agent"]},()=>{t.once("finish",()=>{try{let r="UNKNOWN";n.route&&n.route.path?r=(n.baseUrl||"")+n.route.path:t.statusCode===404?r="Not Found":r=n.path||"Wildcard",c.endTrace(t.statusCode,{route:r})}catch{}}),e()})};var g=n=>!n||n==="/"?"/":n.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],$=(n,t)=>n.route&&n.route.path?(n.baseUrl||"")+n.route.path:n.context&&n.context.matchedRoute?n.context.matchedRoute.path:n.routerPath?n.routerPath:g(t);var U=n=>t=>{let e=t.node.req,r=e.originalUrl||e.url||"/";return c.startTrace({method:e.method||"GET",path:r,ip:e.headers["x-forwarded-for"]||e.socket?.remoteAddress,userAgent:e.headers["user-agent"]},async()=>{try{let s=await n(t),o=200;return t.node.res.statusCode&&(o=t.node.res.statusCode),s&&s.statusCode&&(o=s.statusCode),c.endTrace(o,{route:$(t,r)}),s}catch(s){let o=s.statusCode||s.status||500;throw c.endTrace(o,{route:$(t,r)}),s}})};var D=n=>async(t,e)=>{let r=t.url?new URL(t.url):{pathname:"/"},s=t.method||"GET",o=t.headers.get?t.headers.get("user-agent"):void 0,a=t.headers.get?t.headers.get("x-forwarded-for"):void 0;return c.startTrace({method:s,path:r.pathname,userAgent:o,ip:a},async()=>{try{let i=await n(t,e),u=i?.status||200;return c.endTrace(u,{route:g(r.pathname)}),i}catch(i){throw c.endTrace(500,{route:g(r.pathname)}),i}})},K=n=>async(t,e)=>{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},async()=>{let s=()=>{c.endTrace(e.statusCode||200,{route:g(r)})};e.once("finish",s),e.once("close",s);try{return await n(t,e)}catch(o){throw o}})};var L=(n,t,e)=>{t&&t.apiKey&&c.init(t),n.addHook("onRequest",(r,s,o)=>{r.senzorStart=performance.now(),o()}),n.addHook("onResponse",(r,s,o)=>{let a=performance.now()-(r.senzorStart||performance.now()),i=r.routeOptions?.url||r.routerPath;c.track({method:r.method,route:i||"UNKNOWN",path:r.raw.url||r.url,status:s.statusCode,duration:a,ip:r.ip,userAgent:r.headers["user-agent"]}),o()}),e()};var V={init:n=>c.init(n),flush:()=>c.flush(),requestHandler:R,wrapNextRoute:D,wrapNextPages:K,wrapH3:U,fastifyPlugin:L},vt=V;})();
1
+ "use strict";(()=>{var j=Object.create;var k=Object.defineProperty;var B=Object.getOwnPropertyDescriptor;var J=Object.getOwnPropertyNames;var Q=Object.getPrototypeOf,V=Object.prototype.hasOwnProperty;var T=(e=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(e,{get:(t,r)=>(typeof require<"u"?require:t)[r]}):e)(function(e){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+e+'" is not supported')});var X=(e,t,r,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of J(t))!V.call(e,o)&&o!==r&&k(e,o,{get:()=>t[o],enumerable:!(n=B(t,o))||n.enumerable});return e};var E=(e,t,r)=>(r=e!=null?j(Q(e)):{},X(t||!e||!e.__esModule?k(r,"default",{value:e,enumerable:!0}):r,e));var z=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(r){this.config.debug&&console.error("[Senzor] Ingestion Error:",r)}}};var M=T("async_hooks"),F=new M.AsyncLocalStorage,l={run:(e,t)=>F.run(e,t),current:()=>F.getStore(),addSpan:e=>{let t=F.getStore();t?t.spans.push(e):console.warn("[Senzor] Lost context for span:",e.name)}};var I=T("crypto");var v=E(T("http")),O=E(T("https")),x=T("url");var C=(e,t,r)=>{if(!e[t])return;let n=e[t];e[t]=r(n)},N=(e,t=!1)=>{if(!globalThis.fetch)return;let r="";try{r=new x.URL(e).hostname}catch{}let n=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),r&&i.includes(r))return n(o,a);let c=l.current();if(!c)return n(o,a);let s=(a?.method||"GET").toUpperCase(),f=performance.now()-c.startTime,w=performance.now(),d="unknown";try{d=new x.URL(i).hostname}catch{}t&&console.log(`[Senzor] Tracking Fetch: ${s} ${d}`);try{let p=await n(o,a),h=performance.now()-w;return l.addSpan({name:`${s} ${d}`,type:"http",startTime:f,duration:h,status:p.status,meta:{url:i,method:s,library:"fetch"}}),p}catch(p){let h=performance.now()-w;throw l.addSpan({name:`${s} ${d}`,type:"http",startTime:f,duration:h,status:500,meta:{error:p.message,url:i,library:"fetch"}}),p}}},R=(e,t=!1)=>{let r="";try{r=new x.URL(e).hostname}catch{}let n=o=>function(...a){let i={},c="";if(typeof a[0]=="string"||a[0]instanceof x.URL)c=a[0].toString(),typeof a[1]=="object"&&a[1]!==null&&(i=a[1]);else{i=a[0]||{};let u=i.protocol||(i.port===443?"https:":"http:"),g=i.hostname||i.host||"localhost",b=i.path||"/";c=`${u}//${g}${b}`}if(r&&(c.includes(r)||i.hostname&&i.hostname.includes(r)))return o.apply(this,a);let s=l.current();if(!s)return o.apply(this,a);let f=(i.method||"GET").toUpperCase(),w=performance.now()-s.startTime,d=performance.now(),p="unknown";try{p=new x.URL(c).hostname}catch{p=i.hostname||"unknown"}let h=o.apply(this,a),y=(u,g)=>{let b=performance.now()-d;l.addSpan({name:`${f} ${p}`,type:"http",startTime:w,duration:b,status:g?500:u?.statusCode||0,meta:{url:c,method:f,library:"http"}})};return h.on("response",u=>{u.once("end",()=>y(u)),u.once("error",g=>y(u,g))}),h.on("error",u=>y(null,u)),h};C(v.default,"request",n),C(v.default,"get",n),C(O.default,"request",n),C(O.default,"get",n)};var U=(e=!1)=>{try{let t=T("mongodb"),r=t.Collection,n=t.FindCursor||T("mongodb/lib/cursor/find_cursor").FindCursor,o=t.AggregationCursor||T("mongodb/lib/cursor/aggregation_cursor").AggregationCursor;e&&console.log("[Senzor] Instrumenting MongoDB (Collection + Cursors)...");let a=(s,f,w,d,p,h)=>{let y=performance.now()-d;l.addSpan({name:`MongoDB ${s}`,type:"db",startTime:performance.now()-p-y,duration:y,status:h?500:0,meta:{collection:w,operation:f,error:h?h.message:void 0}}),e&&console.log(`[Senzor] Captured Mongo: ${s} (${y.toFixed(2)}ms)`)};["insertOne","insertMany","updateOne","updateMany","deleteOne","deleteMany","countDocuments"].forEach(s=>{if(!r.prototype[s])return;let f=r.prototype[s];r.prototype[s]=function(...w){let d=l.current();if(!d)return f.apply(this,w);let p=performance.now(),h=d.startTime,y=this.collectionName;try{let u=f.apply(this,w);return u&&typeof u.then=="function"?u.then(g=>(a(s,s,y,p,h),g),g=>{throw a(s,s,y,p,h,g),g}):u}catch(u){throw a(s,s,y,p,h,u),u}}});let c=(s,f)=>{if(!s||!s.prototype.toArray)return;let w=s.prototype.toArray;s.prototype.toArray=function(...d){let p=l.current();if(!p)return w.apply(this,d);let h=performance.now(),y=p.startTime,u=this.namespace?.collection||"unknown",g=S=>(a(f,f,u,h,y),S),b=S=>{throw a(f,f,u,h,y,S),S};try{let S=w.apply(this,d);return S&&typeof S.then=="function"?S.then(g,b):g(S)}catch(S){b(S)}}};c(n,"find"),c(o,"aggregate")}catch(t){e&&console.warn("[Senzor] MongoDB instrumentation warning:",t.message)}};var H=()=>{try{let e=T("pg"),t=e.Client.prototype.query;e.Client.prototype.query=function(...r){let n=l.current();if(!n)return t.apply(this,r);let o=performance.now()-n.startTime,a=performance.now(),i=typeof r[0]=="string"?r[0]:r[0].text,c=t.apply(this,r);return c&&typeof c.then=="function"?c.then(s=>{let f=performance.now()-a;return l.addSpan({name:"Postgres Query",type:"db",startTime:o,duration:f,meta:{query:i}}),s}):c}}catch{}};var P=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 r=t.endpoint||"https://api.senzor.dev/api/ingest/apm",n=t.debug||!1;if(this.transport=new z({...t,endpoint:r}),!this.isInstrumented){try{R(r,n)}catch{}try{N(r,n)}catch{}try{U(n)}catch{}try{H()}catch{}this.isInstrumented=!0,n&&console.log("[Senzor] Auto-instrumentation enabled (HTTP, Fetch, Mongo)")}}startTrace(t,r){if(!this.transport)return r();let n={id:(0,I.randomUUID)(),startTime:performance.now(),data:t,spans:[]};return l.run(n,r)}endTrace(t,r={}){let n=l.current();if(!n||!this.transport)return;let o=performance.now()-n.startTime,a={traceId:n.id,...n.data,...r,status:t,duration:o,spans:n.spans,timestamp:new Date().toISOString()};this.transport.add(a)}track(t){this.transport?.add({traceId:(0,I.randomUUID)(),...t,spans:[],timestamp:new Date().toISOString()})}startSpan(t,r="custom"){let n=l.current();if(!n)return{end:()=>{}};let o=performance.now()-n.startTime,a=performance.now();return{end:(i,c)=>{l.addSpan({name:t,type:r,startTime:o,duration:performance.now()-a,status:c,meta:i})}}}async flush(){this.transport&&await this.transport.flush()}},m=new P;var D=()=>(e,t,r)=>{m.startTrace({method:e.method,path:e.originalUrl||e.url,ip:e.ip||e.socket?.remoteAddress,userAgent:e.headers["user-agent"]},()=>{t.once("finish",()=>{try{let n="UNKNOWN";e.route&&e.route.path?n=(e.baseUrl||"")+e.route.path:t.statusCode===404?n="Not Found":n=e.path||"Wildcard",m.endTrace(t.statusCode,{route:n})}catch{}}),r()})};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],$=(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 K=e=>t=>{let r=t.node.req,n=r.originalUrl||r.url||"/";return m.startTrace({method:r.method||"GET",path:n,ip:r.headers["x-forwarded-for"]||r.socket?.remoteAddress,userAgent:r.headers["user-agent"]},async()=>{try{let o=await e(t),a=200;return t.node.res.statusCode&&(a=t.node.res.statusCode),o&&o.statusCode&&(a=o.statusCode),m.endTrace(a,{route:$(t,n)}),o}catch(o){let a=o.statusCode||o.status||500;throw m.endTrace(a,{route:$(t,n)}),o}})};var G=e=>async(t,r)=>{let n=t.url?new URL(t.url):{pathname:"/"},o=t.method||"GET",a=t.headers.get?t.headers.get("user-agent"):void 0,i=t.headers.get?t.headers.get("x-forwarded-for"):void 0;return m.startTrace({method:o,path:n.pathname,userAgent:a,ip:i},async()=>{try{let c=await e(t,r),s=c?.status||200;return m.endTrace(s,{route:A(n.pathname)}),c}catch(c){throw m.endTrace(500,{route:A(n.pathname)}),c}})},L=e=>async(t,r)=>{let n=t.url?t.url.split("?")[0]:"/";return m.startTrace({method:t.method||"GET",path:n,userAgent:t.headers["user-agent"],ip:t.headers["x-forwarded-for"]||t.socket?.remoteAddress},async()=>{let o=()=>{m.endTrace(r.statusCode||200,{route:A(n)})};r.once("finish",o),r.once("close",o);try{return await e(t,r)}catch(a){throw a}})};var W=(e,t,r)=>{t&&t.apiKey&&m.init(t),e.addHook("onRequest",(n,o,a)=>{n.senzorStart=performance.now(),a()}),e.addHook("onResponse",(n,o,a)=>{let i=performance.now()-(n.senzorStart||performance.now()),c=n.routeOptions?.url||n.routerPath;m.track({method:n.method,route:c||"UNKNOWN",path:n.raw.url||n.url,status:o.statusCode,duration:i,ip:n.ip,userAgent:n.headers["user-agent"]}),a()}),r()};var Y={init:e=>m.init(e),flush:()=>m.flush(),requestHandler:D,wrapNextRoute:G,wrapNextPages:L,wrapH3:K,fastifyPlugin:W},Ot=Y;})();
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 } 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 } else {\r\n // If we are here, something tried to add a span but lost context\r\n // This is common if users await inside a callback that wasn't bound\r\n // However, usually silent failure is preferred in production APM\r\n console.warn('[Senzor] Lost context for span:', span.name);\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 } 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({\r\n ...options,\r\n endpoint\r\n });\r\n\r\n if (!this.isInstrumented) {\r\n try { instrumentHttp(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 // ... (startTrace, endTrace, track, startSpan, flush remain same) ...\r\n // Ensuring startTrace returns T\r\n public startTrace<T>(data: Partial<ActiveTrace['data']>, next: () => T): T {\r\n if (!this.transport) return next();\r\n\r\n const trace: ActiveTrace = {\r\n id: randomUUID(),\r\n startTime: performance.now(),\r\n data: data,\r\n spans: []\r\n };\r\n return Context.run(trace, next);\r\n }\r\n\r\n public endTrace(status: number, extraData: any = {}) {\r\n const trace = Context.current();\r\n if (!trace || !this.transport) return;\r\n\r\n const duration = performance.now() - trace.startTime;\r\n\r\n const payload = {\r\n traceId: trace.id,\r\n ...trace.data,\r\n ...extraData,\r\n status,\r\n duration,\r\n spans: trace.spans,\r\n timestamp: new Date().toISOString()\r\n };\r\n\r\n if (this.options?.debug) console.log(`[Senzor] Ended Trace ${trace.id} with ${trace.spans.length} spans`);\r\n\r\n this.transport.add(payload);\r\n }\r\n\r\n // ... (manual track methods) ...\r\n public track(data: {\r\n method: string;\r\n route: string;\r\n path: string;\r\n status: number;\r\n duration: number;\r\n ip?: string;\r\n userAgent?: string;\r\n }) {\r\n if (!this.transport) return;\r\n const payload = {\r\n traceId: randomUUID(),\r\n ...data,\r\n spans: [],\r\n timestamp: new Date().toISOString()\r\n };\r\n this.transport.add(payload);\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\r\n const startTime = performance.now() - trace.startTime;\r\n const spanStartAbs = performance.now();\r\n\r\n return {\r\n end: (meta?: any, status?: number) => {\r\n const duration = performance.now() - spanStartAbs;\r\n Context.addSpan({\r\n name,\r\n type,\r\n startTime,\r\n duration,\r\n status,\r\n meta\r\n });\r\n }\r\n };\r\n }\r\n\r\n public async flush() {\r\n if (this.transport) await this.transport.flush();\r\n }\r\n}\r\n\r\nexport const client = new SenzorClient();","import http from 'http';\r\nimport https from 'https';\r\nimport { URL } from 'url';\r\nimport { Context } from '../core/context';\r\n\r\nconst shimmer = (module: any, methodName: string, wrapper: (original: Function) => Function) => {\r\n if (!module[methodName]) return;\r\n const original = module[methodName];\r\n module[methodName] = wrapper(original);\r\n};\r\n\r\nexport const instrumentHttp = (ingestUrl: string, debug = false) => {\r\n let ingestHost = '';\r\n try {\r\n ingestHost = new URL(ingestUrl).hostname;\r\n if (debug) console.log(`[Senzor] HTTP Instrumentation ignoring host: ${ingestHost}`);\r\n } catch (e) {\r\n // If invalid URL passed, we can't filter loop safely, so we might skip instrumentation\r\n if (debug) console.error('[Senzor] Invalid Ingest URL for HTTP instrumentation');\r\n }\r\n\r\n const requestWrapper = (original: Function) => {\r\n return function (this: any, ...args: any[]) {\r\n let options: any = {};\r\n let urlStr = '';\r\n\r\n if (typeof args[0] === 'string' || args[0] instanceof URL) {\r\n urlStr = args[0].toString();\r\n if (typeof args[1] === 'object' && args[1] !== null) options = args[1];\r\n } else {\r\n options = args[0] || {};\r\n const protocol = options.protocol || (options.port === 443 ? 'https:' : 'http:');\r\n const host = options.hostname || options.host || 'localhost';\r\n const path = options.path || '/';\r\n urlStr = `${protocol}//${host}${path}`;\r\n }\r\n\r\n // Safety Guard: Ignore calls to Senzor Ingest API\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) {\r\n // Not inside a tracked request\r\n return original.apply(this, args);\r\n }\r\n\r\n const method = (options.method || 'GET').toUpperCase();\r\n const startTime = performance.now() - trace.startTime;\r\n const spanStartAbs = performance.now();\r\n let hostname = 'unknown';\r\n try { hostname = new URL(urlStr).hostname; } catch (e) { hostname = options.hostname || 'unknown'; }\r\n\r\n if (debug) console.log(`[Senzor] Tracking HTTP: ${method} ${hostname}`);\r\n\r\n const req = original.apply(this, args);\r\n\r\n const captureSpan = (res: any, error?: Error) => {\r\n const duration = performance.now() - spanStartAbs;\r\n Context.addSpan({\r\n name: `${method} ${hostname}`,\r\n type: 'http',\r\n startTime,\r\n duration,\r\n status: error ? 500 : res?.statusCode || 0,\r\n meta: { url: urlStr, method }\r\n });\r\n };\r\n\r\n req.on('response', (res: any) => {\r\n // We capture on 'response' (headers received) to be safe.\r\n // Waiting for 'end' might miss requests where body isn't consumed.\r\n res.once('end', () => captureSpan(res));\r\n // Fallback if 'end' doesn't fire fast enough\r\n // setTimeout(() => captureSpan(res), 5000); \r\n });\r\n\r\n req.on('error', (err: Error) => {\r\n captureSpan(null, err);\r\n });\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 // Attempt to load the user's installed mongodb driver\r\n // This works for both native driver users and Mongoose users (as mongoose depends on this)\r\n const mongodb = require('mongodb');\r\n const Collection = mongodb.Collection;\r\n\r\n if (debug) console.log('[Senzor] Instrumenting MongoDB...');\r\n\r\n // Methods that return Promises\r\n const promiseMethods = [\r\n 'insertOne', 'insertMany', 'updateOne', 'updateMany',\r\n 'replaceOne', 'deleteOne', 'deleteMany', 'count', 'countDocuments',\r\n 'estimatedDocumentCount', 'distinct'\r\n ];\r\n\r\n // Methods that return Cursors (need special handling)\r\n const cursorMethods = ['find', 'aggregate'];\r\n\r\n // 1. Instrument Promise-based methods\r\n promiseMethods.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 startTime = performance.now() - trace.startTime;\r\n const spanStartAbs = performance.now();\r\n const collectionName = this.collectionName;\r\n\r\n const endSpan = (err?: Error) => {\r\n const duration = performance.now() - spanStartAbs;\r\n Context.addSpan({\r\n name: `MongoDB ${method} (${collectionName})`,\r\n type: 'db',\r\n startTime,\r\n duration,\r\n status: err ? 500 : 0,\r\n meta: { collection: collectionName, operation: method }\r\n });\r\n if (debug) console.log(`[Senzor] Captured Mongo Span: ${method}`);\r\n };\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) => { endSpan(); return res; },\r\n (err: any) => { endSpan(err); throw err; }\r\n );\r\n }\r\n return result;\r\n } catch (err: any) {\r\n endSpan(err);\r\n throw err;\r\n }\r\n };\r\n });\r\n\r\n // 2. Instrument Cursor-based methods (find, aggregate)\r\n // We trace the *creation* of the cursor, not the fetching, as fetching is async/streamed\r\n cursorMethods.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 startTime = performance.now() - trace.startTime;\r\n\r\n // Record the intent to query\r\n Context.addSpan({\r\n name: `MongoDB ${method} (${this.collectionName})`,\r\n type: 'db',\r\n startTime,\r\n duration: 0, // Placeholder, as cursor creation is instant\r\n status: 0,\r\n meta: { collection: this.collectionName, operation: method }\r\n });\r\n\r\n if (debug) console.log(`[Senzor] Captured Mongo Cursor: ${method}`);\r\n\r\n return original.apply(this, args);\r\n };\r\n });\r\n\r\n } catch (e: any) {\r\n if (debug) console.warn('[Senzor] MongoDB instrumentation skipped:', 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\nexport const expressMiddleware = () => {\r\n return (req: any, res: any, next: () => void) => {\r\n // We MUST use startTrace to enable Auto-Instrumentation for this request\r\n client.startTrace({\r\n method: req.method,\r\n path: req.originalUrl || req.url,\r\n ip: req.ip || req.socket?.remoteAddress,\r\n userAgent: req.headers['user-agent'],\r\n }, () => {\r\n\r\n res.once('finish', () => {\r\n try {\r\n let route = 'UNKNOWN';\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) {\r\n // Fail open\r\n }\r\n });\r\n\r\n next();\r\n });\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\n// Minimal types for H3 to avoid peer-deps\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 // Start Trace Context\r\n return client.startTrace({\r\n method: req.method || 'GET',\r\n path: path,\r\n ip: req.headers['x-forwarded-for'] || req.socket?.remoteAddress,\r\n userAgent: req.headers['user-agent'],\r\n }, async () => {\r\n try {\r\n const response = await handler(event);\r\n\r\n // H3/Nitro response status\r\n let status = 200;\r\n if (event.node.res.statusCode) status = event.node.res.statusCode;\r\n // Check if response is an error object\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 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 (Route Handlers) ---\r\nexport const wrapNextRoute = (handler: Function) => {\r\n return async (req: Request | any, context?: any) => {\r\n // 1. Extract Info\r\n const url = req.url ? new URL(req.url) : { pathname: '/' };\r\n const method = req.method || 'GET';\r\n const ua = req.headers.get ? req.headers.get('user-agent') : undefined;\r\n const ip = req.headers.get ? req.headers.get('x-forwarded-for') : undefined;\r\n\r\n // 2. Run in Context\r\n return client.startTrace({\r\n method,\r\n path: url.pathname,\r\n userAgent: ua,\r\n ip: ip\r\n }, async () => {\r\n try {\r\n const response = await handler(req, context);\r\n const status = response?.status || 200;\r\n \r\n client.endTrace(status, { route: normalizePath(url.pathname) });\r\n return response;\r\n } catch (err: any) {\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 (API Routes) ---\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 // 1. Run in Context\r\n return client.startTrace({\r\n method: req.method || 'GET',\r\n path: path,\r\n userAgent: req.headers['user-agent'],\r\n ip: req.headers['x-forwarded-for'] || req.socket?.remoteAddress,\r\n }, async () => {\r\n \r\n // 2. Hook Response\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); // Fallback if finish doesn't fire\r\n\r\n // 3. Execute\r\n try {\r\n return await handler(req, res);\r\n } catch (e) {\r\n // Next.js Pages router usually handles errors internally, \r\n // but we ensure we catch sync errors here\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\n// We don't import Fastify types to keep zero-deps, but structure matches\r\nexport const senzorPlugin = (fastify: any, options: SenzorOptions, done: Function) => {\r\n\r\n // Init if options provided inline, otherwise assume global init\r\n if (options && options.apiKey) {\r\n client.init(options);\r\n }\r\n\r\n // Hook: On Request (Start Timer)\r\n fastify.addHook('onRequest', (request: any, reply: any, next: Function) => {\r\n request.senzorStart = performance.now();\r\n next();\r\n });\r\n\r\n // Hook: On Response (End Timer & Track)\r\n fastify.addHook('onResponse', (request: any, reply: any, next: Function) => {\r\n const duration = performance.now() - (request.senzorStart || performance.now());\r\n\r\n // Fastify provides 'routerPath' (e.g. /user/:id)\r\n const route = request.routeOptions?.url || request.routerPath;\r\n\r\n client.track({\r\n method: request.method,\r\n route: route || 'UNKNOWN',\r\n path: request.raw.url || request.url,\r\n status: reply.statusCode,\r\n duration: duration,\r\n ip: request.ip,\r\n userAgent: request.headers['user-agent']\r\n });\r\n\r\n next();\r\n });\r\n\r\n done();\r\n};","import { client } from './core/client';\r\nimport { expressMiddleware } 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 // Core\r\n init: (options: SenzorOptions) => client.init(options),\r\n flush: () => client.flush(),\r\n\r\n // Express / Connect\r\n requestHandler: expressMiddleware,\r\n\r\n // Next.js\r\n wrapNextRoute, // For App Router (Route Handlers)\r\n wrapNextPages, // For Pages Router (API Routes)\r\n\r\n // H3 / Nuxt / Nitro\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","import_crypto","import_http","import_https","import_url","shimmer","module","methodName","wrapper","original","instrumentHttp","ingestUrl","debug","ingestHost","requestWrapper","args","options","urlStr","protocol","host","path","trace","Context","method","startTime","spanStartAbs","hostname","req","captureSpan","res","error","duration","err","http","https","instrumentMongo","debug","Collection","promiseMethods","cursorMethods","method","original","args","trace","Context","startTime","spanStartAbs","collectionName","endSpan","err","duration","result","res","e","instrumentPg","pg","originalQuery","args","trace","Context","startTime","spanStartAbs","sql","result","res","duration","SenzorClient","options","endpoint","debug","Transport","instrumentHttp","instrumentMongo","instrumentPg","data","next","trace","Context","status","extraData","duration","payload","name","type","startTime","spanStartAbs","meta","client","expressMiddleware","req","res","next","client","route","normalizePath","path","getRoute","req","fallbackPath","wrapH3","handler","event","req","path","client","response","status","getRoute","err","wrapNextRoute","handler","req","context","url","method","ua","ip","client","response","status","normalizePath","err","wrapNextPages","res","path","done","e","senzorPlugin","fastify","options","done","client","request","reply","next","duration","route","Senzor","options","client","expressMiddleware","wrapNextRoute","wrapNextPages","wrapH3","senzorPlugin","index_default"]}
1
+ {"version":3,"sources":["../src/core/transport.ts","../src/core/context.ts","../src/core/client.ts","../src/instrumentation/http.ts","../src/instrumentation/mongo.ts","../src/instrumentation/pg.ts","../src/middleware/express.ts","../src/core/normalizer.ts","../src/wrappers/h3.ts","../src/wrappers/next.ts","../src/wrappers/fastify.ts","../src/index.ts"],"sourcesContent":["import { SenzorOptions } from './types';\r\n\r\nexport class Transport {\r\n private queue: any[] = [];\r\n private timer: NodeJS.Timeout | null = null;\r\n\r\n constructor(private config: SenzorOptions) {\r\n if (typeof setInterval !== 'undefined') {\r\n this.timer = setInterval(() => this.flush(), config.flushInterval || 10000);\r\n if (this.timer && typeof this.timer.unref === 'function') {\r\n this.timer.unref(); // Don't block process exit\r\n }\r\n }\r\n }\r\n\r\n public add(trace: any) {\r\n this.queue.push(trace);\r\n if (this.queue.length >= (this.config.batchSize || 100)) {\r\n this.flush();\r\n }\r\n }\r\n\r\n public async flush() {\r\n if (this.queue.length === 0) return;\r\n\r\n const batch = [...this.queue];\r\n this.queue = [];\r\n\r\n try {\r\n // Use global fetch (Node 18+)\r\n await fetch(this.config.endpoint || 'https://api.senzor.dev/api/ingest/apm', {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n 'x-service-api-key': this.config.apiKey,\r\n },\r\n body: JSON.stringify(batch),\r\n keepalive: true,\r\n });\r\n \r\n if (this.config.debug) console.log(`[Senzor] Flushed ${batch.length} traces`);\r\n } catch (err) {\r\n if (this.config.debug) console.error('[Senzor] Ingestion Error:', err);\r\n // Dropping data to prevent memory leaks is preferred in APM\r\n }\r\n }\r\n}","import { AsyncLocalStorage } from 'async_hooks';\r\nimport { ActiveTrace } 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 } else {\r\n // If we are here, something tried to add a span but lost context\r\n // This is common if users await inside a callback that wasn't bound\r\n // However, usually silent failure is preferred in production APM\r\n console.warn('[Senzor] Lost context for span:', span.name);\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'; // Import both\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({\r\n ...options,\r\n endpoint\r\n });\r\n\r\n // --- ENABLE AUTO INSTRUMENTATION ---\r\n if (!this.isInstrumented) {\r\n try { instrumentHttp(endpoint, debug); } catch (e) { }\r\n try { instrumentFetch(endpoint, debug); } catch (e) { } // NEW: Fetch Support\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 (HTTP, Fetch, Mongo)');\r\n }\r\n }\r\n\r\n // ... (Rest of file same as before: startTrace, endTrace, track, etc.) ...\r\n public startTrace<T>(data: Partial<ActiveTrace['data']>, next: () => T): T {\r\n if (!this.transport) return next();\r\n const trace: ActiveTrace = { id: randomUUID(), startTime: performance.now(), data: data, spans: [] };\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 const payload = { traceId: trace.id, ...trace.data, ...extraData, status, duration, spans: trace.spans, timestamp: new Date().toISOString() };\r\n this.transport.add(payload);\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 return { end: (meta?: any, status?: number) => { Context.addSpan({ name, type, startTime, duration: performance.now() - spanStartAbs, status, meta }); } };\r\n }\r\n\r\n public async flush() { if (this.transport) await this.transport.flush(); }\r\n}\r\n\r\nexport const client = new SenzorClient();","import http from 'http';\r\nimport https from 'https';\r\nimport { URL } from 'url';\r\nimport { Context } from '../core/context';\r\n\r\nconst shimmer = (module: any, methodName: string, wrapper: (original: Function) => Function) => {\r\n if (!module[methodName]) return;\r\n const original = module[methodName];\r\n module[methodName] = wrapper(original);\r\n};\r\n\r\n// --- Native Fetch Instrumentation (Node 18+) ---\r\nexport const instrumentFetch = (ingestUrl: string, debug = false) => {\r\n if (!globalThis.fetch) return;\r\n\r\n let ingestHost = '';\r\n try { ingestHost = new URL(ingestUrl).hostname; } catch (e) { }\r\n\r\n const originalFetch = globalThis.fetch;\r\n\r\n // @ts-ignore\r\n globalThis.fetch = async (input: RequestInfo | URL, init?: RequestInit) => {\r\n // 1. Extract URL\r\n let urlStr = '';\r\n if (typeof input === 'string') urlStr = input;\r\n else if (input instanceof URL) urlStr = input.toString();\r\n else if (input && input.url) urlStr = input.url; // Request object\r\n\r\n // 2. Infinite Loop Guard\r\n if (ingestHost && urlStr.includes(ingestHost)) {\r\n return originalFetch(input, init);\r\n }\r\n\r\n // 3. Context Check\r\n const trace = Context.current();\r\n if (!trace) {\r\n return originalFetch(input, init);\r\n }\r\n\r\n // 4. Start Span\r\n const method = (init?.method || 'GET').toUpperCase();\r\n const startTime = performance.now() - trace.startTime;\r\n const spanStartAbs = performance.now();\r\n let hostname = 'unknown';\r\n try { hostname = new URL(urlStr).hostname; } catch (e) { }\r\n\r\n if (debug) console.log(`[Senzor] Tracking Fetch: ${method} ${hostname}`);\r\n\r\n try {\r\n const response = await originalFetch(input, init);\r\n\r\n // 5. End Span\r\n const duration = performance.now() - spanStartAbs;\r\n Context.addSpan({\r\n name: `${method} ${hostname}`,\r\n type: 'http',\r\n startTime,\r\n duration,\r\n status: response.status,\r\n meta: { url: urlStr, method, library: 'fetch' }\r\n });\r\n\r\n return response;\r\n } catch (err: any) {\r\n const duration = performance.now() - spanStartAbs;\r\n Context.addSpan({\r\n name: `${method} ${hostname}`,\r\n type: 'http',\r\n startTime,\r\n duration,\r\n status: 500,\r\n meta: { error: err.message, url: urlStr, library: 'fetch' }\r\n });\r\n throw err;\r\n }\r\n };\r\n};\r\n\r\n// --- Standard HTTP/HTTPS Instrumentation ---\r\nexport const instrumentHttp = (ingestUrl: string, debug = false) => {\r\n let ingestHost = '';\r\n try {\r\n ingestHost = new URL(ingestUrl).hostname;\r\n } catch (e) { }\r\n\r\n const requestWrapper = (original: Function) => {\r\n return function (this: any, ...args: any[]) {\r\n let options: any = {};\r\n let urlStr = '';\r\n\r\n if (typeof args[0] === 'string' || args[0] instanceof URL) {\r\n urlStr = args[0].toString();\r\n if (typeof args[1] === 'object' && args[1] !== null) options = args[1];\r\n } else {\r\n options = args[0] || {};\r\n const protocol = options.protocol || (options.port === 443 ? 'https:' : 'http:');\r\n const host = options.hostname || options.host || 'localhost';\r\n const path = options.path || '/';\r\n urlStr = `${protocol}//${host}${path}`;\r\n }\r\n\r\n if (ingestHost && (urlStr.includes(ingestHost) || (options.hostname && options.hostname.includes(ingestHost)))) {\r\n return original.apply(this, args);\r\n }\r\n\r\n const trace = Context.current();\r\n if (!trace) return original.apply(this, args);\r\n\r\n const method = (options.method || 'GET').toUpperCase();\r\n const startTime = performance.now() - trace.startTime;\r\n const spanStartAbs = performance.now();\r\n let hostname = 'unknown';\r\n try { hostname = new URL(urlStr).hostname; } catch (e) { hostname = options.hostname || 'unknown'; }\r\n\r\n const req = original.apply(this, args);\r\n\r\n const captureSpan = (res: any, error?: Error) => {\r\n const duration = performance.now() - spanStartAbs;\r\n Context.addSpan({\r\n name: `${method} ${hostname}`,\r\n type: 'http',\r\n startTime,\r\n duration,\r\n status: error ? 500 : res?.statusCode || 0,\r\n meta: { url: urlStr, method, library: 'http' }\r\n });\r\n };\r\n\r\n req.on('response', (res: any) => {\r\n res.once('end', () => captureSpan(res));\r\n res.once('error', (err: Error) => captureSpan(res, err));\r\n });\r\n\r\n req.on('error', (err: Error) => captureSpan(null, err));\r\n\r\n return req;\r\n };\r\n };\r\n\r\n shimmer(http, 'request', requestWrapper);\r\n shimmer(http, 'get', requestWrapper);\r\n shimmer(https, 'request', requestWrapper);\r\n shimmer(https, 'get', requestWrapper);\r\n};","import { Context } from '../core/context';\r\n\r\nexport const instrumentMongo = (debug = false) => {\r\n try {\r\n const mongodb = require('mongodb');\r\n const Collection = mongodb.Collection;\r\n\r\n // Attempt to get Cursor classes\r\n // Note: The location of these classes varies by driver version, \r\n // checking common locations\r\n const FindCursor = mongodb.FindCursor || require('mongodb/lib/cursor/find_cursor').FindCursor;\r\n const AggregationCursor = mongodb.AggregationCursor || require('mongodb/lib/cursor/aggregation_cursor').AggregationCursor;\r\n\r\n if (debug) console.log('[Senzor] Instrumenting MongoDB (Collection + Cursors)...');\r\n\r\n // --- Helper to Record Span ---\r\n const recordSpan = (name: string, operation: string, collection: string, startAbs: number, traceStart: number, err?: Error) => {\r\n const duration = performance.now() - startAbs;\r\n Context.addSpan({\r\n name: `MongoDB ${name}`,\r\n type: 'db',\r\n startTime: performance.now() - traceStart - duration, // Adjust start time to when op actually started\r\n duration,\r\n status: err ? 500 : 0,\r\n meta: { collection, operation, error: err ? err.message : undefined }\r\n });\r\n if (debug) console.log(`[Senzor] Captured Mongo: ${name} (${duration.toFixed(2)}ms)`);\r\n };\r\n\r\n // --- 1. Instrument Immediate Operations (Insert/Update/Delete) ---\r\n const immediateMethods = ['insertOne', 'insertMany', 'updateOne', 'updateMany', 'deleteOne', 'deleteMany', 'countDocuments'];\r\n\r\n immediateMethods.forEach((method) => {\r\n if (!Collection.prototype[method]) return;\r\n const original = Collection.prototype[method];\r\n\r\n Collection.prototype[method] = function (...args: any[]) {\r\n const trace = Context.current();\r\n if (!trace) return original.apply(this, args);\r\n\r\n const spanStartAbs = performance.now();\r\n const traceStart = trace.startTime;\r\n const collName = this.collectionName;\r\n\r\n try {\r\n const result = original.apply(this, args);\r\n if (result && typeof result.then === 'function') {\r\n return result.then(\r\n (res: any) => { recordSpan(method, method, collName, spanStartAbs, traceStart); return res; },\r\n (err: any) => { recordSpan(method, method, collName, spanStartAbs, traceStart, err); throw err; }\r\n );\r\n }\r\n return result;\r\n } catch (err: any) {\r\n recordSpan(method, method, collName, spanStartAbs, traceStart, err);\r\n throw err;\r\n }\r\n };\r\n });\r\n\r\n // --- 2. Instrument Cursor Execution (find -> toArray) ---\r\n const patchCursor = (CursorClass: any, label: string) => {\r\n if (!CursorClass || !CursorClass.prototype.toArray) return;\r\n\r\n const originalToArray = CursorClass.prototype.toArray;\r\n\r\n CursorClass.prototype.toArray = function (...args: any[]) {\r\n const trace = Context.current();\r\n // Cursors are often created in context but executed later. \r\n // We check context at execution time.\r\n if (!trace) return originalToArray.apply(this, args);\r\n\r\n const spanStartAbs = performance.now();\r\n const traceStart = trace.startTime;\r\n // Attempt to get collection name from cursor internal state\r\n const collName = this.namespace?.collection || 'unknown';\r\n\r\n const onSuccess = (res: any) => {\r\n recordSpan(label, label, collName, spanStartAbs, traceStart);\r\n return res;\r\n };\r\n const onError = (err: any) => {\r\n recordSpan(label, label, collName, spanStartAbs, traceStart, err);\r\n throw err;\r\n };\r\n\r\n try {\r\n const result = originalToArray.apply(this, args);\r\n if (result && typeof result.then === 'function') {\r\n return result.then(onSuccess, onError);\r\n }\r\n return onSuccess(result);\r\n } catch (e) {\r\n onError(e);\r\n }\r\n };\r\n };\r\n\r\n patchCursor(FindCursor, 'find');\r\n patchCursor(AggregationCursor, 'aggregate');\r\n\r\n } catch (e: any) {\r\n if (debug) console.warn('[Senzor] MongoDB instrumentation warning:', e.message);\r\n }\r\n};","import { Context } from '../core/context';\r\n\r\n// Simple shim for 'pg' library\r\nexport const instrumentPg = () => {\r\n try {\r\n // Try to require pg (it might not be installed by user)\r\n const pg = require('pg');\r\n const originalQuery = pg.Client.prototype.query;\r\n\r\n pg.Client.prototype.query = function (...args: any[]) {\r\n const trace = Context.current();\r\n if (!trace) return originalQuery.apply(this, args);\r\n\r\n const startTime = performance.now() - trace.startTime;\r\n const spanStartAbs = performance.now();\r\n\r\n // Extract SQL (first arg usually string or config object)\r\n const sql = typeof args[0] === 'string' ? args[0] : args[0].text;\r\n\r\n // Wrap callback if present, or handle Promise\r\n const result = originalQuery.apply(this, args);\r\n\r\n if (result && typeof result.then === 'function') {\r\n return result.then((res: any) => {\r\n const duration = performance.now() - spanStartAbs;\r\n Context.addSpan({\r\n name: 'Postgres Query',\r\n type: 'db',\r\n startTime,\r\n duration,\r\n meta: { query: sql }\r\n });\r\n return res;\r\n });\r\n }\r\n return result;\r\n };\r\n } catch (e) {\r\n // User doesn't use pg, ignore\r\n }\r\n};","import { client } from '../core/client';\r\n\r\nexport const expressMiddleware = () => {\r\n return (req: any, res: any, next: () => void) => {\r\n // We MUST use startTrace to enable Auto-Instrumentation for this request\r\n client.startTrace({\r\n method: req.method,\r\n path: req.originalUrl || req.url,\r\n ip: req.ip || req.socket?.remoteAddress,\r\n userAgent: req.headers['user-agent'],\r\n }, () => {\r\n\r\n res.once('finish', () => {\r\n try {\r\n let route = 'UNKNOWN';\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) {\r\n // Fail open\r\n }\r\n });\r\n\r\n next();\r\n });\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\n// Minimal types for H3 to avoid peer-deps\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 // Start Trace Context\r\n return client.startTrace({\r\n method: req.method || 'GET',\r\n path: path,\r\n ip: req.headers['x-forwarded-for'] || req.socket?.remoteAddress,\r\n userAgent: req.headers['user-agent'],\r\n }, async () => {\r\n try {\r\n const response = await handler(event);\r\n\r\n // H3/Nitro response status\r\n let status = 200;\r\n if (event.node.res.statusCode) status = event.node.res.statusCode;\r\n // Check if response is an error object\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 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 (Route Handlers) ---\r\nexport const wrapNextRoute = (handler: Function) => {\r\n return async (req: Request | any, context?: any) => {\r\n // 1. Extract Info\r\n const url = req.url ? new URL(req.url) : { pathname: '/' };\r\n const method = req.method || 'GET';\r\n const ua = req.headers.get ? req.headers.get('user-agent') : undefined;\r\n const ip = req.headers.get ? req.headers.get('x-forwarded-for') : undefined;\r\n\r\n // 2. Run in Context\r\n return client.startTrace({\r\n method,\r\n path: url.pathname,\r\n userAgent: ua,\r\n ip: ip\r\n }, async () => {\r\n try {\r\n const response = await handler(req, context);\r\n const status = response?.status || 200;\r\n \r\n client.endTrace(status, { route: normalizePath(url.pathname) });\r\n return response;\r\n } catch (err: any) {\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 (API Routes) ---\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 // 1. Run in Context\r\n return client.startTrace({\r\n method: req.method || 'GET',\r\n path: path,\r\n userAgent: req.headers['user-agent'],\r\n ip: req.headers['x-forwarded-for'] || req.socket?.remoteAddress,\r\n }, async () => {\r\n \r\n // 2. Hook Response\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); // Fallback if finish doesn't fire\r\n\r\n // 3. Execute\r\n try {\r\n return await handler(req, res);\r\n } catch (e) {\r\n // Next.js Pages router usually handles errors internally, \r\n // but we ensure we catch sync errors here\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\n// We don't import Fastify types to keep zero-deps, but structure matches\r\nexport const senzorPlugin = (fastify: any, options: SenzorOptions, done: Function) => {\r\n\r\n // Init if options provided inline, otherwise assume global init\r\n if (options && options.apiKey) {\r\n client.init(options);\r\n }\r\n\r\n // Hook: On Request (Start Timer)\r\n fastify.addHook('onRequest', (request: any, reply: any, next: Function) => {\r\n request.senzorStart = performance.now();\r\n next();\r\n });\r\n\r\n // Hook: On Response (End Timer & Track)\r\n fastify.addHook('onResponse', (request: any, reply: any, next: Function) => {\r\n const duration = performance.now() - (request.senzorStart || performance.now());\r\n\r\n // Fastify provides 'routerPath' (e.g. /user/:id)\r\n const route = request.routeOptions?.url || request.routerPath;\r\n\r\n client.track({\r\n method: request.method,\r\n route: route || 'UNKNOWN',\r\n path: request.raw.url || request.url,\r\n status: reply.statusCode,\r\n duration: duration,\r\n ip: request.ip,\r\n userAgent: request.headers['user-agent']\r\n });\r\n\r\n next();\r\n });\r\n\r\n done();\r\n};","import { client } from './core/client';\r\nimport { expressMiddleware } 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 // Core\r\n init: (options: SenzorOptions) => client.init(options),\r\n flush: () => client.flush(),\r\n\r\n // Express / Connect\r\n requestHandler: expressMiddleware,\r\n\r\n // Next.js\r\n wrapNextRoute, // For App Router (Route Handlers)\r\n wrapNextPages, // For Pages Router (API Routes)\r\n\r\n // H3 / Nuxt / Nitro\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","import_crypto","import_http","import_https","import_url","shimmer","module","methodName","wrapper","original","instrumentFetch","ingestUrl","debug","ingestHost","originalFetch","input","init","urlStr","trace","Context","method","startTime","spanStartAbs","hostname","response","duration","err","instrumentHttp","requestWrapper","args","options","protocol","host","path","req","captureSpan","res","error","http","https","instrumentMongo","debug","mongodb","Collection","FindCursor","AggregationCursor","recordSpan","name","operation","collection","startAbs","traceStart","err","duration","Context","method","original","args","trace","spanStartAbs","collName","result","res","patchCursor","CursorClass","label","originalToArray","onSuccess","onError","e","instrumentPg","pg","originalQuery","args","trace","Context","startTime","spanStartAbs","sql","result","res","duration","SenzorClient","options","endpoint","debug","Transport","instrumentHttp","instrumentFetch","instrumentMongo","instrumentPg","data","next","trace","Context","status","extraData","duration","payload","name","type","startTime","spanStartAbs","meta","client","expressMiddleware","req","res","next","client","route","normalizePath","path","getRoute","req","fallbackPath","wrapH3","handler","event","req","path","client","response","status","getRoute","err","wrapNextRoute","handler","req","context","url","method","ua","ip","client","response","status","normalizePath","err","wrapNextPages","res","path","done","e","senzorPlugin","fastify","options","done","client","request","reply","next","duration","route","Senzor","options","client","expressMiddleware","wrapNextRoute","wrapNextPages","wrapH3","senzorPlugin","index_default"]}
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- "use strict";var G=Object.create;var w=Object.defineProperty;var W=Object.getOwnPropertyDescriptor;var j=Object.getOwnPropertyNames;var J=Object.getPrototypeOf,Q=Object.prototype.hasOwnProperty;var V=(n,t)=>{for(var e in t)w(n,e,{get:t[e],enumerable:!0})},F=(n,t,e,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let s of j(t))!Q.call(n,s)&&s!==e&&w(n,s,{get:()=>t[s],enumerable:!(r=W(t,s))||r.enumerable});return n};var M=(n,t,e)=>(e=n!=null?G(J(n)):{},F(t||!n||!n.__esModule?w(e,"default",{value:n,enumerable:!0}):e,n)),X=n=>F(w({},"__esModule",{value:!0}),n);var Z={};V(Z,{Senzor:()=>B,default:()=>Y});module.exports=X(Z);var T=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(e){this.config.debug&&console.error("[Senzor] Ingestion Error:",e)}}};var N=require("async_hooks"),C=new N.AsyncLocalStorage,p={run:(n,t)=>C.run(n,t),current:()=>C.getStore(),addSpan:n=>{let t=C.getStore();t?t.spans.push(n):console.warn("[Senzor] Lost context for span:",n.name)}};var P=require("crypto");var v=M(require("http")),O=M(require("https")),x=require("url");var S=(n,t,e)=>{if(!n[t])return;let r=n[t];n[t]=e(r)},k=(n,t=!1)=>{let e="";try{e=new x.URL(n).hostname,t&&console.log(`[Senzor] HTTP Instrumentation ignoring host: ${e}`)}catch{t&&console.error("[Senzor] Invalid Ingest URL for HTTP instrumentation")}let r=s=>function(...o){let a={},i="";if(typeof o[0]=="string"||o[0]instanceof x.URL)i=o[0].toString(),typeof o[1]=="object"&&o[1]!==null&&(a=o[1]);else{a=o[0]||{};let f=a.protocol||(a.port===443?"https:":"http:"),z=a.hostname||a.host||"localhost",A=a.path||"/";i=`${f}//${z}${A}`}if(e&&(i.includes(e)||a.hostname&&a.hostname.includes(e)))return s.apply(this,o);let u=p.current();if(!u)return s.apply(this,o);let m=(a.method||"GET").toUpperCase(),b=performance.now()-u.startTime,g=performance.now(),h="unknown";try{h=new x.URL(i).hostname}catch{h=a.hostname||"unknown"}t&&console.log(`[Senzor] Tracking HTTP: ${m} ${h}`);let l=s.apply(this,o),d=(f,z)=>{let A=performance.now()-g;p.addSpan({name:`${m} ${h}`,type:"http",startTime:b,duration:A,status:z?500:f?.statusCode||0,meta:{url:i,method:m}})};return l.on("response",f=>{f.once("end",()=>d(f))}),l.on("error",f=>{d(null,f)}),l};S(v.default,"request",r),S(v.default,"get",r),S(O.default,"request",r),S(O.default,"get",r)};var E=(n=!1)=>{try{let e=require("mongodb").Collection;n&&console.log("[Senzor] Instrumenting MongoDB...");let r=["insertOne","insertMany","updateOne","updateMany","replaceOne","deleteOne","deleteMany","count","countDocuments","estimatedDocumentCount","distinct"],s=["find","aggregate"];r.forEach(o=>{if(!e.prototype[o])return;let a=e.prototype[o];e.prototype[o]=function(...i){let u=p.current();if(!u)return a.apply(this,i);let m=performance.now()-u.startTime,b=performance.now(),g=this.collectionName,h=l=>{let d=performance.now()-b;p.addSpan({name:`MongoDB ${o} (${g})`,type:"db",startTime:m,duration:d,status:l?500:0,meta:{collection:g,operation:o}}),n&&console.log(`[Senzor] Captured Mongo Span: ${o}`)};try{let l=a.apply(this,i);return l&&typeof l.then=="function"?l.then(d=>(h(),d),d=>{throw h(d),d}):l}catch(l){throw h(l),l}}}),s.forEach(o=>{if(!e.prototype[o])return;let a=e.prototype[o];e.prototype[o]=function(...i){let u=p.current();if(!u)return a.apply(this,i);let m=performance.now()-u.startTime;return p.addSpan({name:`MongoDB ${o} (${this.collectionName})`,type:"db",startTime:m,duration:0,status:0,meta:{collection:this.collectionName,operation:o}}),n&&console.log(`[Senzor] Captured Mongo Cursor: ${o}`),a.apply(this,i)}})}catch(t){n&&console.warn("[Senzor] MongoDB instrumentation skipped:",t.message)}};var H=()=>{try{let n=require("pg"),t=n.Client.prototype.query;n.Client.prototype.query=function(...e){let r=p.current();if(!r)return t.apply(this,e);let s=performance.now()-r.startTime,o=performance.now(),a=typeof e[0]=="string"?e[0]:e[0].text,i=t.apply(this,e);return i&&typeof i.then=="function"?i.then(u=>{let m=performance.now()-o;return p.addSpan({name:"Postgres Query",type:"db",startTime:s,duration:m,meta:{query:a}}),u}):i}}catch{}};var I=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 e=t.endpoint||"https://api.senzor.dev/api/ingest/apm",r=t.debug||!1;if(this.transport=new T({...t,endpoint:e}),!this.isInstrumented){try{k(e,r)}catch{}try{E(r)}catch{}try{H()}catch{}this.isInstrumented=!0,r&&console.log("[Senzor] Auto-instrumentation enabled")}}startTrace(t,e){if(!this.transport)return e();let r={id:(0,P.randomUUID)(),startTime:performance.now(),data:t,spans:[]};return p.run(r,e)}endTrace(t,e={}){let r=p.current();if(!r||!this.transport)return;let s=performance.now()-r.startTime,o={traceId:r.id,...r.data,...e,status:t,duration:s,spans:r.spans,timestamp:new Date().toISOString()};this.options?.debug&&console.log(`[Senzor] Ended Trace ${r.id} with ${r.spans.length} spans`),this.transport.add(o)}track(t){if(!this.transport)return;let e={traceId:(0,P.randomUUID)(),...t,spans:[],timestamp:new Date().toISOString()};this.transport.add(e)}startSpan(t,e="custom"){let r=p.current();if(!r)return{end:()=>{}};let s=performance.now()-r.startTime,o=performance.now();return{end:(a,i)=>{let u=performance.now()-o;p.addSpan({name:t,type:e,startTime:s,duration:u,status:i,meta:a})}}}async flush(){this.transport&&await this.transport.flush()}},c=new I;var R=()=>(n,t,e)=>{c.startTrace({method:n.method,path:n.originalUrl||n.url,ip:n.ip||n.socket?.remoteAddress,userAgent:n.headers["user-agent"]},()=>{t.once("finish",()=>{try{let r="UNKNOWN";n.route&&n.route.path?r=(n.baseUrl||"")+n.route.path:t.statusCode===404?r="Not Found":r=n.path||"Wildcard",c.endTrace(t.statusCode,{route:r})}catch{}}),e()})};var y=n=>!n||n==="/"?"/":n.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],$=(n,t)=>n.route&&n.route.path?(n.baseUrl||"")+n.route.path:n.context&&n.context.matchedRoute?n.context.matchedRoute.path:n.routerPath?n.routerPath:y(t);var U=n=>t=>{let e=t.node.req,r=e.originalUrl||e.url||"/";return c.startTrace({method:e.method||"GET",path:r,ip:e.headers["x-forwarded-for"]||e.socket?.remoteAddress,userAgent:e.headers["user-agent"]},async()=>{try{let s=await n(t),o=200;return t.node.res.statusCode&&(o=t.node.res.statusCode),s&&s.statusCode&&(o=s.statusCode),c.endTrace(o,{route:$(t,r)}),s}catch(s){let o=s.statusCode||s.status||500;throw c.endTrace(o,{route:$(t,r)}),s}})};var D=n=>async(t,e)=>{let r=t.url?new URL(t.url):{pathname:"/"},s=t.method||"GET",o=t.headers.get?t.headers.get("user-agent"):void 0,a=t.headers.get?t.headers.get("x-forwarded-for"):void 0;return c.startTrace({method:s,path:r.pathname,userAgent:o,ip:a},async()=>{try{let i=await n(t,e),u=i?.status||200;return c.endTrace(u,{route:y(r.pathname)}),i}catch(i){throw c.endTrace(500,{route:y(r.pathname)}),i}})},K=n=>async(t,e)=>{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},async()=>{let s=()=>{c.endTrace(e.statusCode||200,{route:y(r)})};e.once("finish",s),e.once("close",s);try{return await n(t,e)}catch(o){throw o}})};var L=(n,t,e)=>{t&&t.apiKey&&c.init(t),n.addHook("onRequest",(r,s,o)=>{r.senzorStart=performance.now(),o()}),n.addHook("onResponse",(r,s,o)=>{let a=performance.now()-(r.senzorStart||performance.now()),i=r.routeOptions?.url||r.routerPath;c.track({method:r.method,route:i||"UNKNOWN",path:r.raw.url||r.url,status:s.statusCode,duration:a,ip:r.ip,userAgent:r.headers["user-agent"]}),o()}),e()};var B={init:n=>c.init(n),flush:()=>c.flush(),requestHandler:R,wrapNextRoute:D,wrapNextPages:K,wrapH3:U,fastifyPlugin:L},Y=B;0&&(module.exports={Senzor});
1
+ "use strict";var B=Object.create;var A=Object.defineProperty;var J=Object.getOwnPropertyDescriptor;var Q=Object.getOwnPropertyNames;var V=Object.getPrototypeOf,X=Object.prototype.hasOwnProperty;var Y=(e,t)=>{for(var r in t)A(e,r,{get:t[r],enumerable:!0})},k=(e,t,r,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of Q(t))!X.call(e,o)&&o!==r&&A(e,o,{get:()=>t[o],enumerable:!(n=J(t,o))||n.enumerable});return e};var E=(e,t,r)=>(r=e!=null?B(V(e)):{},k(t||!e||!e.__esModule?A(r,"default",{value:e,enumerable:!0}):r,e)),Z=e=>k(A({},"__esModule",{value:!0}),e);var q={};Y(q,{Senzor:()=>j,default:()=>_});module.exports=Z(q);var z=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(r){this.config.debug&&console.error("[Senzor] Ingestion Error:",r)}}};var M=require("async_hooks"),F=new M.AsyncLocalStorage,l={run:(e,t)=>F.run(e,t),current:()=>F.getStore(),addSpan:e=>{let t=F.getStore();t?t.spans.push(e):console.warn("[Senzor] Lost context for span:",e.name)}};var I=require("crypto");var v=E(require("http")),O=E(require("https")),T=require("url");var C=(e,t,r)=>{if(!e[t])return;let n=e[t];e[t]=r(n)},N=(e,t=!1)=>{if(!globalThis.fetch)return;let r="";try{r=new T.URL(e).hostname}catch{}let n=globalThis.fetch;globalThis.fetch=async(o,a)=>{let i="";if(typeof o=="string"?i=o:o instanceof T.URL?i=o.toString():o&&o.url&&(i=o.url),r&&i.includes(r))return n(o,a);let c=l.current();if(!c)return n(o,a);let s=(a?.method||"GET").toUpperCase(),f=performance.now()-c.startTime,w=performance.now(),d="unknown";try{d=new T.URL(i).hostname}catch{}t&&console.log(`[Senzor] Tracking Fetch: ${s} ${d}`);try{let p=await n(o,a),h=performance.now()-w;return l.addSpan({name:`${s} ${d}`,type:"http",startTime:f,duration:h,status:p.status,meta:{url:i,method:s,library:"fetch"}}),p}catch(p){let h=performance.now()-w;throw l.addSpan({name:`${s} ${d}`,type:"http",startTime:f,duration:h,status:500,meta:{error:p.message,url:i,library:"fetch"}}),p}}},R=(e,t=!1)=>{let r="";try{r=new T.URL(e).hostname}catch{}let n=o=>function(...a){let i={},c="";if(typeof a[0]=="string"||a[0]instanceof T.URL)c=a[0].toString(),typeof a[1]=="object"&&a[1]!==null&&(i=a[1]);else{i=a[0]||{};let u=i.protocol||(i.port===443?"https:":"http:"),g=i.hostname||i.host||"localhost",x=i.path||"/";c=`${u}//${g}${x}`}if(r&&(c.includes(r)||i.hostname&&i.hostname.includes(r)))return o.apply(this,a);let s=l.current();if(!s)return o.apply(this,a);let f=(i.method||"GET").toUpperCase(),w=performance.now()-s.startTime,d=performance.now(),p="unknown";try{p=new T.URL(c).hostname}catch{p=i.hostname||"unknown"}let h=o.apply(this,a),y=(u,g)=>{let x=performance.now()-d;l.addSpan({name:`${f} ${p}`,type:"http",startTime:w,duration:x,status:g?500:u?.statusCode||0,meta:{url:c,method:f,library:"http"}})};return h.on("response",u=>{u.once("end",()=>y(u)),u.once("error",g=>y(u,g))}),h.on("error",u=>y(null,u)),h};C(v.default,"request",n),C(v.default,"get",n),C(O.default,"request",n),C(O.default,"get",n)};var U=(e=!1)=>{try{let t=require("mongodb"),r=t.Collection,n=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,f,w,d,p,h)=>{let y=performance.now()-d;l.addSpan({name:`MongoDB ${s}`,type:"db",startTime:performance.now()-p-y,duration:y,status:h?500:0,meta:{collection:w,operation:f,error:h?h.message:void 0}}),e&&console.log(`[Senzor] Captured Mongo: ${s} (${y.toFixed(2)}ms)`)};["insertOne","insertMany","updateOne","updateMany","deleteOne","deleteMany","countDocuments"].forEach(s=>{if(!r.prototype[s])return;let f=r.prototype[s];r.prototype[s]=function(...w){let d=l.current();if(!d)return f.apply(this,w);let p=performance.now(),h=d.startTime,y=this.collectionName;try{let u=f.apply(this,w);return u&&typeof u.then=="function"?u.then(g=>(a(s,s,y,p,h),g),g=>{throw a(s,s,y,p,h,g),g}):u}catch(u){throw a(s,s,y,p,h,u),u}}});let c=(s,f)=>{if(!s||!s.prototype.toArray)return;let w=s.prototype.toArray;s.prototype.toArray=function(...d){let p=l.current();if(!p)return w.apply(this,d);let h=performance.now(),y=p.startTime,u=this.namespace?.collection||"unknown",g=S=>(a(f,f,u,h,y),S),x=S=>{throw a(f,f,u,h,y,S),S};try{let S=w.apply(this,d);return S&&typeof S.then=="function"?S.then(g,x):g(S)}catch(S){x(S)}}};c(n,"find"),c(o,"aggregate")}catch(t){e&&console.warn("[Senzor] MongoDB instrumentation warning:",t.message)}};var H=()=>{try{let e=require("pg"),t=e.Client.prototype.query;e.Client.prototype.query=function(...r){let n=l.current();if(!n)return t.apply(this,r);let o=performance.now()-n.startTime,a=performance.now(),i=typeof r[0]=="string"?r[0]:r[0].text,c=t.apply(this,r);return c&&typeof c.then=="function"?c.then(s=>{let f=performance.now()-a;return l.addSpan({name:"Postgres Query",type:"db",startTime:o,duration:f,meta:{query:i}}),s}):c}}catch{}};var P=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 r=t.endpoint||"https://api.senzor.dev/api/ingest/apm",n=t.debug||!1;if(this.transport=new z({...t,endpoint:r}),!this.isInstrumented){try{R(r,n)}catch{}try{N(r,n)}catch{}try{U(n)}catch{}try{H()}catch{}this.isInstrumented=!0,n&&console.log("[Senzor] Auto-instrumentation enabled (HTTP, Fetch, Mongo)")}}startTrace(t,r){if(!this.transport)return r();let n={id:(0,I.randomUUID)(),startTime:performance.now(),data:t,spans:[]};return l.run(n,r)}endTrace(t,r={}){let n=l.current();if(!n||!this.transport)return;let o=performance.now()-n.startTime,a={traceId:n.id,...n.data,...r,status:t,duration:o,spans:n.spans,timestamp:new Date().toISOString()};this.transport.add(a)}track(t){this.transport?.add({traceId:(0,I.randomUUID)(),...t,spans:[],timestamp:new Date().toISOString()})}startSpan(t,r="custom"){let n=l.current();if(!n)return{end:()=>{}};let o=performance.now()-n.startTime,a=performance.now();return{end:(i,c)=>{l.addSpan({name:t,type:r,startTime:o,duration:performance.now()-a,status:c,meta:i})}}}async flush(){this.transport&&await this.transport.flush()}},m=new P;var D=()=>(e,t,r)=>{m.startTrace({method:e.method,path:e.originalUrl||e.url,ip:e.ip||e.socket?.remoteAddress,userAgent:e.headers["user-agent"]},()=>{t.once("finish",()=>{try{let n="UNKNOWN";e.route&&e.route.path?n=(e.baseUrl||"")+e.route.path:t.statusCode===404?n="Not Found":n=e.path||"Wildcard",m.endTrace(t.statusCode,{route:n})}catch{}}),r()})};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],$=(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 r=t.node.req,n=r.originalUrl||r.url||"/";return m.startTrace({method:r.method||"GET",path:n,ip:r.headers["x-forwarded-for"]||r.socket?.remoteAddress,userAgent:r.headers["user-agent"]},async()=>{try{let o=await e(t),a=200;return t.node.res.statusCode&&(a=t.node.res.statusCode),o&&o.statusCode&&(a=o.statusCode),m.endTrace(a,{route:$(t,n)}),o}catch(o){let a=o.statusCode||o.status||500;throw m.endTrace(a,{route:$(t,n)}),o}})};var G=e=>async(t,r)=>{let n=t.url?new URL(t.url):{pathname:"/"},o=t.method||"GET",a=t.headers.get?t.headers.get("user-agent"):void 0,i=t.headers.get?t.headers.get("x-forwarded-for"):void 0;return m.startTrace({method:o,path:n.pathname,userAgent:a,ip:i},async()=>{try{let c=await e(t,r),s=c?.status||200;return m.endTrace(s,{route:b(n.pathname)}),c}catch(c){throw m.endTrace(500,{route:b(n.pathname)}),c}})},L=e=>async(t,r)=>{let n=t.url?t.url.split("?")[0]:"/";return m.startTrace({method:t.method||"GET",path:n,userAgent:t.headers["user-agent"],ip:t.headers["x-forwarded-for"]||t.socket?.remoteAddress},async()=>{let o=()=>{m.endTrace(r.statusCode||200,{route:b(n)})};r.once("finish",o),r.once("close",o);try{return await e(t,r)}catch(a){throw a}})};var W=(e,t,r)=>{t&&t.apiKey&&m.init(t),e.addHook("onRequest",(n,o,a)=>{n.senzorStart=performance.now(),a()}),e.addHook("onResponse",(n,o,a)=>{let i=performance.now()-(n.senzorStart||performance.now()),c=n.routeOptions?.url||n.routerPath;m.track({method:n.method,route:c||"UNKNOWN",path:n.raw.url||n.url,status:o.statusCode,duration:i,ip:n.ip,userAgent:n.headers["user-agent"]}),a()}),r()};var j={init:e=>m.init(e),flush:()=>m.flush(),requestHandler:D,wrapNextRoute:G,wrapNextPages:L,wrapH3:K,fastifyPlugin:W},_=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 } 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 // Core\r\n init: (options: SenzorOptions) => client.init(options),\r\n flush: () => client.flush(),\r\n\r\n // Express / Connect\r\n requestHandler: expressMiddleware,\r\n\r\n // Next.js\r\n wrapNextRoute, // For App Router (Route Handlers)\r\n wrapNextPages, // For Pages Router (API Routes)\r\n\r\n // H3 / Nuxt / Nitro\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 } 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 } else {\r\n // If we are here, something tried to add a span but lost context\r\n // This is common if users await inside a callback that wasn't bound\r\n // However, usually silent failure is preferred in production APM\r\n console.warn('[Senzor] Lost context for span:', span.name);\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 } 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({\r\n ...options,\r\n endpoint\r\n });\r\n\r\n if (!this.isInstrumented) {\r\n try { instrumentHttp(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 // ... (startTrace, endTrace, track, startSpan, flush remain same) ...\r\n // Ensuring startTrace returns T\r\n public startTrace<T>(data: Partial<ActiveTrace['data']>, next: () => T): T {\r\n if (!this.transport) return next();\r\n\r\n const trace: ActiveTrace = {\r\n id: randomUUID(),\r\n startTime: performance.now(),\r\n data: data,\r\n spans: []\r\n };\r\n return Context.run(trace, next);\r\n }\r\n\r\n public endTrace(status: number, extraData: any = {}) {\r\n const trace = Context.current();\r\n if (!trace || !this.transport) return;\r\n\r\n const duration = performance.now() - trace.startTime;\r\n\r\n const payload = {\r\n traceId: trace.id,\r\n ...trace.data,\r\n ...extraData,\r\n status,\r\n duration,\r\n spans: trace.spans,\r\n timestamp: new Date().toISOString()\r\n };\r\n\r\n if (this.options?.debug) console.log(`[Senzor] Ended Trace ${trace.id} with ${trace.spans.length} spans`);\r\n\r\n this.transport.add(payload);\r\n }\r\n\r\n // ... (manual track methods) ...\r\n public track(data: {\r\n method: string;\r\n route: string;\r\n path: string;\r\n status: number;\r\n duration: number;\r\n ip?: string;\r\n userAgent?: string;\r\n }) {\r\n if (!this.transport) return;\r\n const payload = {\r\n traceId: randomUUID(),\r\n ...data,\r\n spans: [],\r\n timestamp: new Date().toISOString()\r\n };\r\n this.transport.add(payload);\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\r\n const startTime = performance.now() - trace.startTime;\r\n const spanStartAbs = performance.now();\r\n\r\n return {\r\n end: (meta?: any, status?: number) => {\r\n const duration = performance.now() - spanStartAbs;\r\n Context.addSpan({\r\n name,\r\n type,\r\n startTime,\r\n duration,\r\n status,\r\n meta\r\n });\r\n }\r\n };\r\n }\r\n\r\n public async flush() {\r\n if (this.transport) await this.transport.flush();\r\n }\r\n}\r\n\r\nexport const client = new SenzorClient();","import http from 'http';\r\nimport https from 'https';\r\nimport { URL } from 'url';\r\nimport { Context } from '../core/context';\r\n\r\nconst shimmer = (module: any, methodName: string, wrapper: (original: Function) => Function) => {\r\n if (!module[methodName]) return;\r\n const original = module[methodName];\r\n module[methodName] = wrapper(original);\r\n};\r\n\r\nexport const instrumentHttp = (ingestUrl: string, debug = false) => {\r\n let ingestHost = '';\r\n try {\r\n ingestHost = new URL(ingestUrl).hostname;\r\n if (debug) console.log(`[Senzor] HTTP Instrumentation ignoring host: ${ingestHost}`);\r\n } catch (e) {\r\n // If invalid URL passed, we can't filter loop safely, so we might skip instrumentation\r\n if (debug) console.error('[Senzor] Invalid Ingest URL for HTTP instrumentation');\r\n }\r\n\r\n const requestWrapper = (original: Function) => {\r\n return function (this: any, ...args: any[]) {\r\n let options: any = {};\r\n let urlStr = '';\r\n\r\n if (typeof args[0] === 'string' || args[0] instanceof URL) {\r\n urlStr = args[0].toString();\r\n if (typeof args[1] === 'object' && args[1] !== null) options = args[1];\r\n } else {\r\n options = args[0] || {};\r\n const protocol = options.protocol || (options.port === 443 ? 'https:' : 'http:');\r\n const host = options.hostname || options.host || 'localhost';\r\n const path = options.path || '/';\r\n urlStr = `${protocol}//${host}${path}`;\r\n }\r\n\r\n // Safety Guard: Ignore calls to Senzor Ingest API\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) {\r\n // Not inside a tracked request\r\n return original.apply(this, args);\r\n }\r\n\r\n const method = (options.method || 'GET').toUpperCase();\r\n const startTime = performance.now() - trace.startTime;\r\n const spanStartAbs = performance.now();\r\n let hostname = 'unknown';\r\n try { hostname = new URL(urlStr).hostname; } catch (e) { hostname = options.hostname || 'unknown'; }\r\n\r\n if (debug) console.log(`[Senzor] Tracking HTTP: ${method} ${hostname}`);\r\n\r\n const req = original.apply(this, args);\r\n\r\n const captureSpan = (res: any, error?: Error) => {\r\n const duration = performance.now() - spanStartAbs;\r\n Context.addSpan({\r\n name: `${method} ${hostname}`,\r\n type: 'http',\r\n startTime,\r\n duration,\r\n status: error ? 500 : res?.statusCode || 0,\r\n meta: { url: urlStr, method }\r\n });\r\n };\r\n\r\n req.on('response', (res: any) => {\r\n // We capture on 'response' (headers received) to be safe.\r\n // Waiting for 'end' might miss requests where body isn't consumed.\r\n res.once('end', () => captureSpan(res));\r\n // Fallback if 'end' doesn't fire fast enough\r\n // setTimeout(() => captureSpan(res), 5000); \r\n });\r\n\r\n req.on('error', (err: Error) => {\r\n captureSpan(null, err);\r\n });\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 // Attempt to load the user's installed mongodb driver\r\n // This works for both native driver users and Mongoose users (as mongoose depends on this)\r\n const mongodb = require('mongodb');\r\n const Collection = mongodb.Collection;\r\n\r\n if (debug) console.log('[Senzor] Instrumenting MongoDB...');\r\n\r\n // Methods that return Promises\r\n const promiseMethods = [\r\n 'insertOne', 'insertMany', 'updateOne', 'updateMany',\r\n 'replaceOne', 'deleteOne', 'deleteMany', 'count', 'countDocuments',\r\n 'estimatedDocumentCount', 'distinct'\r\n ];\r\n\r\n // Methods that return Cursors (need special handling)\r\n const cursorMethods = ['find', 'aggregate'];\r\n\r\n // 1. Instrument Promise-based methods\r\n promiseMethods.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 startTime = performance.now() - trace.startTime;\r\n const spanStartAbs = performance.now();\r\n const collectionName = this.collectionName;\r\n\r\n const endSpan = (err?: Error) => {\r\n const duration = performance.now() - spanStartAbs;\r\n Context.addSpan({\r\n name: `MongoDB ${method} (${collectionName})`,\r\n type: 'db',\r\n startTime,\r\n duration,\r\n status: err ? 500 : 0,\r\n meta: { collection: collectionName, operation: method }\r\n });\r\n if (debug) console.log(`[Senzor] Captured Mongo Span: ${method}`);\r\n };\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) => { endSpan(); return res; },\r\n (err: any) => { endSpan(err); throw err; }\r\n );\r\n }\r\n return result;\r\n } catch (err: any) {\r\n endSpan(err);\r\n throw err;\r\n }\r\n };\r\n });\r\n\r\n // 2. Instrument Cursor-based methods (find, aggregate)\r\n // We trace the *creation* of the cursor, not the fetching, as fetching is async/streamed\r\n cursorMethods.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 startTime = performance.now() - trace.startTime;\r\n\r\n // Record the intent to query\r\n Context.addSpan({\r\n name: `MongoDB ${method} (${this.collectionName})`,\r\n type: 'db',\r\n startTime,\r\n duration: 0, // Placeholder, as cursor creation is instant\r\n status: 0,\r\n meta: { collection: this.collectionName, operation: method }\r\n });\r\n\r\n if (debug) console.log(`[Senzor] Captured Mongo Cursor: ${method}`);\r\n\r\n return original.apply(this, args);\r\n };\r\n });\r\n\r\n } catch (e: any) {\r\n if (debug) console.warn('[Senzor] MongoDB instrumentation skipped:', 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\nexport const expressMiddleware = () => {\r\n return (req: any, res: any, next: () => void) => {\r\n // We MUST use startTrace to enable Auto-Instrumentation for this request\r\n client.startTrace({\r\n method: req.method,\r\n path: req.originalUrl || req.url,\r\n ip: req.ip || req.socket?.remoteAddress,\r\n userAgent: req.headers['user-agent'],\r\n }, () => {\r\n\r\n res.once('finish', () => {\r\n try {\r\n let route = 'UNKNOWN';\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) {\r\n // Fail open\r\n }\r\n });\r\n\r\n next();\r\n });\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\n// Minimal types for H3 to avoid peer-deps\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 // Start Trace Context\r\n return client.startTrace({\r\n method: req.method || 'GET',\r\n path: path,\r\n ip: req.headers['x-forwarded-for'] || req.socket?.remoteAddress,\r\n userAgent: req.headers['user-agent'],\r\n }, async () => {\r\n try {\r\n const response = await handler(event);\r\n\r\n // H3/Nitro response status\r\n let status = 200;\r\n if (event.node.res.statusCode) status = event.node.res.statusCode;\r\n // Check if response is an error object\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 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 (Route Handlers) ---\r\nexport const wrapNextRoute = (handler: Function) => {\r\n return async (req: Request | any, context?: any) => {\r\n // 1. Extract Info\r\n const url = req.url ? new URL(req.url) : { pathname: '/' };\r\n const method = req.method || 'GET';\r\n const ua = req.headers.get ? req.headers.get('user-agent') : undefined;\r\n const ip = req.headers.get ? req.headers.get('x-forwarded-for') : undefined;\r\n\r\n // 2. Run in Context\r\n return client.startTrace({\r\n method,\r\n path: url.pathname,\r\n userAgent: ua,\r\n ip: ip\r\n }, async () => {\r\n try {\r\n const response = await handler(req, context);\r\n const status = response?.status || 200;\r\n \r\n client.endTrace(status, { route: normalizePath(url.pathname) });\r\n return response;\r\n } catch (err: any) {\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 (API Routes) ---\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 // 1. Run in Context\r\n return client.startTrace({\r\n method: req.method || 'GET',\r\n path: path,\r\n userAgent: req.headers['user-agent'],\r\n ip: req.headers['x-forwarded-for'] || req.socket?.remoteAddress,\r\n }, async () => {\r\n \r\n // 2. Hook Response\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); // Fallback if finish doesn't fire\r\n\r\n // 3. Execute\r\n try {\r\n return await handler(req, res);\r\n } catch (e) {\r\n // Next.js Pages router usually handles errors internally, \r\n // but we ensure we catch sync errors here\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\n// We don't import Fastify types to keep zero-deps, but structure matches\r\nexport const senzorPlugin = (fastify: any, options: SenzorOptions, done: Function) => {\r\n\r\n // Init if options provided inline, otherwise assume global init\r\n if (options && options.apiKey) {\r\n client.init(options);\r\n }\r\n\r\n // Hook: On Request (Start Timer)\r\n fastify.addHook('onRequest', (request: any, reply: any, next: Function) => {\r\n request.senzorStart = performance.now();\r\n next();\r\n });\r\n\r\n // Hook: On Response (End Timer & Track)\r\n fastify.addHook('onResponse', (request: any, reply: any, next: Function) => {\r\n const duration = performance.now() - (request.senzorStart || performance.now());\r\n\r\n // Fastify provides 'routerPath' (e.g. /user/:id)\r\n const route = request.routeOptions?.url || request.routerPath;\r\n\r\n client.track({\r\n method: request.method,\r\n route: route || 'UNKNOWN',\r\n path: request.raw.url || request.url,\r\n status: reply.statusCode,\r\n duration: duration,\r\n ip: request.ip,\r\n userAgent: request.headers['user-agent']\r\n });\r\n\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","import_crypto","import_http","import_https","import_url","shimmer","module","methodName","wrapper","original","instrumentHttp","ingestUrl","debug","ingestHost","requestWrapper","args","options","urlStr","protocol","host","path","trace","Context","method","startTime","spanStartAbs","hostname","req","captureSpan","res","error","duration","err","http","https","instrumentMongo","debug","Collection","promiseMethods","cursorMethods","method","original","args","trace","Context","startTime","spanStartAbs","collectionName","endSpan","err","duration","result","res","e","instrumentPg","pg","originalQuery","args","trace","Context","startTime","spanStartAbs","sql","result","res","duration","SenzorClient","options","endpoint","debug","Transport","instrumentHttp","instrumentMongo","instrumentPg","data","next","trace","Context","status","extraData","duration","payload","name","type","startTime","spanStartAbs","meta","client","expressMiddleware","req","res","next","client","route","normalizePath","path","getRoute","req","fallbackPath","wrapH3","handler","event","req","path","client","response","status","getRoute","err","wrapNextRoute","handler","req","context","url","method","ua","ip","client","response","status","normalizePath","err","wrapNextPages","res","path","done","e","senzorPlugin","fastify","options","done","client","request","reply","next","duration","route","Senzor","options","client","expressMiddleware","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 } 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 // Core\r\n init: (options: SenzorOptions) => client.init(options),\r\n flush: () => client.flush(),\r\n\r\n // Express / Connect\r\n requestHandler: expressMiddleware,\r\n\r\n // Next.js\r\n wrapNextRoute, // For App Router (Route Handlers)\r\n wrapNextPages, // For Pages Router (API Routes)\r\n\r\n // H3 / Nuxt / Nitro\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 } 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 } else {\r\n // If we are here, something tried to add a span but lost context\r\n // This is common if users await inside a callback that wasn't bound\r\n // However, usually silent failure is preferred in production APM\r\n console.warn('[Senzor] Lost context for span:', span.name);\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'; // Import both\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({\r\n ...options,\r\n endpoint\r\n });\r\n\r\n // --- ENABLE AUTO INSTRUMENTATION ---\r\n if (!this.isInstrumented) {\r\n try { instrumentHttp(endpoint, debug); } catch (e) { }\r\n try { instrumentFetch(endpoint, debug); } catch (e) { } // NEW: Fetch Support\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 (HTTP, Fetch, Mongo)');\r\n }\r\n }\r\n\r\n // ... (Rest of file same as before: startTrace, endTrace, track, etc.) ...\r\n public startTrace<T>(data: Partial<ActiveTrace['data']>, next: () => T): T {\r\n if (!this.transport) return next();\r\n const trace: ActiveTrace = { id: randomUUID(), startTime: performance.now(), data: data, spans: [] };\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 const payload = { traceId: trace.id, ...trace.data, ...extraData, status, duration, spans: trace.spans, timestamp: new Date().toISOString() };\r\n this.transport.add(payload);\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 return { end: (meta?: any, status?: number) => { Context.addSpan({ name, type, startTime, duration: performance.now() - spanStartAbs, status, meta }); } };\r\n }\r\n\r\n public async flush() { if (this.transport) await this.transport.flush(); }\r\n}\r\n\r\nexport const client = new SenzorClient();","import http from 'http';\r\nimport https from 'https';\r\nimport { URL } from 'url';\r\nimport { Context } from '../core/context';\r\n\r\nconst shimmer = (module: any, methodName: string, wrapper: (original: Function) => Function) => {\r\n if (!module[methodName]) return;\r\n const original = module[methodName];\r\n module[methodName] = wrapper(original);\r\n};\r\n\r\n// --- Native Fetch Instrumentation (Node 18+) ---\r\nexport const instrumentFetch = (ingestUrl: string, debug = false) => {\r\n if (!globalThis.fetch) return;\r\n\r\n let ingestHost = '';\r\n try { ingestHost = new URL(ingestUrl).hostname; } catch (e) { }\r\n\r\n const originalFetch = globalThis.fetch;\r\n\r\n // @ts-ignore\r\n globalThis.fetch = async (input: RequestInfo | URL, init?: RequestInit) => {\r\n // 1. Extract URL\r\n let urlStr = '';\r\n if (typeof input === 'string') urlStr = input;\r\n else if (input instanceof URL) urlStr = input.toString();\r\n else if (input && input.url) urlStr = input.url; // Request object\r\n\r\n // 2. Infinite Loop Guard\r\n if (ingestHost && urlStr.includes(ingestHost)) {\r\n return originalFetch(input, init);\r\n }\r\n\r\n // 3. Context Check\r\n const trace = Context.current();\r\n if (!trace) {\r\n return originalFetch(input, init);\r\n }\r\n\r\n // 4. Start Span\r\n const method = (init?.method || 'GET').toUpperCase();\r\n const startTime = performance.now() - trace.startTime;\r\n const spanStartAbs = performance.now();\r\n let hostname = 'unknown';\r\n try { hostname = new URL(urlStr).hostname; } catch (e) { }\r\n\r\n if (debug) console.log(`[Senzor] Tracking Fetch: ${method} ${hostname}`);\r\n\r\n try {\r\n const response = await originalFetch(input, init);\r\n\r\n // 5. End Span\r\n const duration = performance.now() - spanStartAbs;\r\n Context.addSpan({\r\n name: `${method} ${hostname}`,\r\n type: 'http',\r\n startTime,\r\n duration,\r\n status: response.status,\r\n meta: { url: urlStr, method, library: 'fetch' }\r\n });\r\n\r\n return response;\r\n } catch (err: any) {\r\n const duration = performance.now() - spanStartAbs;\r\n Context.addSpan({\r\n name: `${method} ${hostname}`,\r\n type: 'http',\r\n startTime,\r\n duration,\r\n status: 500,\r\n meta: { error: err.message, url: urlStr, library: 'fetch' }\r\n });\r\n throw err;\r\n }\r\n };\r\n};\r\n\r\n// --- Standard HTTP/HTTPS Instrumentation ---\r\nexport const instrumentHttp = (ingestUrl: string, debug = false) => {\r\n let ingestHost = '';\r\n try {\r\n ingestHost = new URL(ingestUrl).hostname;\r\n } catch (e) { }\r\n\r\n const requestWrapper = (original: Function) => {\r\n return function (this: any, ...args: any[]) {\r\n let options: any = {};\r\n let urlStr = '';\r\n\r\n if (typeof args[0] === 'string' || args[0] instanceof URL) {\r\n urlStr = args[0].toString();\r\n if (typeof args[1] === 'object' && args[1] !== null) options = args[1];\r\n } else {\r\n options = args[0] || {};\r\n const protocol = options.protocol || (options.port === 443 ? 'https:' : 'http:');\r\n const host = options.hostname || options.host || 'localhost';\r\n const path = options.path || '/';\r\n urlStr = `${protocol}//${host}${path}`;\r\n }\r\n\r\n if (ingestHost && (urlStr.includes(ingestHost) || (options.hostname && options.hostname.includes(ingestHost)))) {\r\n return original.apply(this, args);\r\n }\r\n\r\n const trace = Context.current();\r\n if (!trace) return original.apply(this, args);\r\n\r\n const method = (options.method || 'GET').toUpperCase();\r\n const startTime = performance.now() - trace.startTime;\r\n const spanStartAbs = performance.now();\r\n let hostname = 'unknown';\r\n try { hostname = new URL(urlStr).hostname; } catch (e) { hostname = options.hostname || 'unknown'; }\r\n\r\n const req = original.apply(this, args);\r\n\r\n const captureSpan = (res: any, error?: Error) => {\r\n const duration = performance.now() - spanStartAbs;\r\n Context.addSpan({\r\n name: `${method} ${hostname}`,\r\n type: 'http',\r\n startTime,\r\n duration,\r\n status: error ? 500 : res?.statusCode || 0,\r\n meta: { url: urlStr, method, library: 'http' }\r\n });\r\n };\r\n\r\n req.on('response', (res: any) => {\r\n res.once('end', () => captureSpan(res));\r\n res.once('error', (err: Error) => captureSpan(res, err));\r\n });\r\n\r\n req.on('error', (err: Error) => captureSpan(null, err));\r\n\r\n return req;\r\n };\r\n };\r\n\r\n shimmer(http, 'request', requestWrapper);\r\n shimmer(http, 'get', requestWrapper);\r\n shimmer(https, 'request', requestWrapper);\r\n shimmer(https, 'get', requestWrapper);\r\n};","import { Context } from '../core/context';\r\n\r\nexport const instrumentMongo = (debug = false) => {\r\n try {\r\n const mongodb = require('mongodb');\r\n const Collection = mongodb.Collection;\r\n\r\n // Attempt to get Cursor classes\r\n // Note: The location of these classes varies by driver version, \r\n // checking common locations\r\n const FindCursor = mongodb.FindCursor || require('mongodb/lib/cursor/find_cursor').FindCursor;\r\n const AggregationCursor = mongodb.AggregationCursor || require('mongodb/lib/cursor/aggregation_cursor').AggregationCursor;\r\n\r\n if (debug) console.log('[Senzor] Instrumenting MongoDB (Collection + Cursors)...');\r\n\r\n // --- Helper to Record Span ---\r\n const recordSpan = (name: string, operation: string, collection: string, startAbs: number, traceStart: number, err?: Error) => {\r\n const duration = performance.now() - startAbs;\r\n Context.addSpan({\r\n name: `MongoDB ${name}`,\r\n type: 'db',\r\n startTime: performance.now() - traceStart - duration, // Adjust start time to when op actually started\r\n duration,\r\n status: err ? 500 : 0,\r\n meta: { collection, operation, error: err ? err.message : undefined }\r\n });\r\n if (debug) console.log(`[Senzor] Captured Mongo: ${name} (${duration.toFixed(2)}ms)`);\r\n };\r\n\r\n // --- 1. Instrument Immediate Operations (Insert/Update/Delete) ---\r\n const immediateMethods = ['insertOne', 'insertMany', 'updateOne', 'updateMany', 'deleteOne', 'deleteMany', 'countDocuments'];\r\n\r\n immediateMethods.forEach((method) => {\r\n if (!Collection.prototype[method]) return;\r\n const original = Collection.prototype[method];\r\n\r\n Collection.prototype[method] = function (...args: any[]) {\r\n const trace = Context.current();\r\n if (!trace) return original.apply(this, args);\r\n\r\n const spanStartAbs = performance.now();\r\n const traceStart = trace.startTime;\r\n const collName = this.collectionName;\r\n\r\n try {\r\n const result = original.apply(this, args);\r\n if (result && typeof result.then === 'function') {\r\n return result.then(\r\n (res: any) => { recordSpan(method, method, collName, spanStartAbs, traceStart); return res; },\r\n (err: any) => { recordSpan(method, method, collName, spanStartAbs, traceStart, err); throw err; }\r\n );\r\n }\r\n return result;\r\n } catch (err: any) {\r\n recordSpan(method, method, collName, spanStartAbs, traceStart, err);\r\n throw err;\r\n }\r\n };\r\n });\r\n\r\n // --- 2. Instrument Cursor Execution (find -> toArray) ---\r\n const patchCursor = (CursorClass: any, label: string) => {\r\n if (!CursorClass || !CursorClass.prototype.toArray) return;\r\n\r\n const originalToArray = CursorClass.prototype.toArray;\r\n\r\n CursorClass.prototype.toArray = function (...args: any[]) {\r\n const trace = Context.current();\r\n // Cursors are often created in context but executed later. \r\n // We check context at execution time.\r\n if (!trace) return originalToArray.apply(this, args);\r\n\r\n const spanStartAbs = performance.now();\r\n const traceStart = trace.startTime;\r\n // Attempt to get collection name from cursor internal state\r\n const collName = this.namespace?.collection || 'unknown';\r\n\r\n const onSuccess = (res: any) => {\r\n recordSpan(label, label, collName, spanStartAbs, traceStart);\r\n return res;\r\n };\r\n const onError = (err: any) => {\r\n recordSpan(label, label, collName, spanStartAbs, traceStart, err);\r\n throw err;\r\n };\r\n\r\n try {\r\n const result = originalToArray.apply(this, args);\r\n if (result && typeof result.then === 'function') {\r\n return result.then(onSuccess, onError);\r\n }\r\n return onSuccess(result);\r\n } catch (e) {\r\n onError(e);\r\n }\r\n };\r\n };\r\n\r\n patchCursor(FindCursor, 'find');\r\n patchCursor(AggregationCursor, 'aggregate');\r\n\r\n } catch (e: any) {\r\n if (debug) console.warn('[Senzor] MongoDB instrumentation warning:', e.message);\r\n }\r\n};","import { Context } from '../core/context';\r\n\r\n// Simple shim for 'pg' library\r\nexport const instrumentPg = () => {\r\n try {\r\n // Try to require pg (it might not be installed by user)\r\n const pg = require('pg');\r\n const originalQuery = pg.Client.prototype.query;\r\n\r\n pg.Client.prototype.query = function (...args: any[]) {\r\n const trace = Context.current();\r\n if (!trace) return originalQuery.apply(this, args);\r\n\r\n const startTime = performance.now() - trace.startTime;\r\n const spanStartAbs = performance.now();\r\n\r\n // Extract SQL (first arg usually string or config object)\r\n const sql = typeof args[0] === 'string' ? args[0] : args[0].text;\r\n\r\n // Wrap callback if present, or handle Promise\r\n const result = originalQuery.apply(this, args);\r\n\r\n if (result && typeof result.then === 'function') {\r\n return result.then((res: any) => {\r\n const duration = performance.now() - spanStartAbs;\r\n Context.addSpan({\r\n name: 'Postgres Query',\r\n type: 'db',\r\n startTime,\r\n duration,\r\n meta: { query: sql }\r\n });\r\n return res;\r\n });\r\n }\r\n return result;\r\n };\r\n } catch (e) {\r\n // User doesn't use pg, ignore\r\n }\r\n};","import { client } from '../core/client';\r\n\r\nexport const expressMiddleware = () => {\r\n return (req: any, res: any, next: () => void) => {\r\n // We MUST use startTrace to enable Auto-Instrumentation for this request\r\n client.startTrace({\r\n method: req.method,\r\n path: req.originalUrl || req.url,\r\n ip: req.ip || req.socket?.remoteAddress,\r\n userAgent: req.headers['user-agent'],\r\n }, () => {\r\n\r\n res.once('finish', () => {\r\n try {\r\n let route = 'UNKNOWN';\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) {\r\n // Fail open\r\n }\r\n });\r\n\r\n next();\r\n });\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\n// Minimal types for H3 to avoid peer-deps\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 // Start Trace Context\r\n return client.startTrace({\r\n method: req.method || 'GET',\r\n path: path,\r\n ip: req.headers['x-forwarded-for'] || req.socket?.remoteAddress,\r\n userAgent: req.headers['user-agent'],\r\n }, async () => {\r\n try {\r\n const response = await handler(event);\r\n\r\n // H3/Nitro response status\r\n let status = 200;\r\n if (event.node.res.statusCode) status = event.node.res.statusCode;\r\n // Check if response is an error object\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 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 (Route Handlers) ---\r\nexport const wrapNextRoute = (handler: Function) => {\r\n return async (req: Request | any, context?: any) => {\r\n // 1. Extract Info\r\n const url = req.url ? new URL(req.url) : { pathname: '/' };\r\n const method = req.method || 'GET';\r\n const ua = req.headers.get ? req.headers.get('user-agent') : undefined;\r\n const ip = req.headers.get ? req.headers.get('x-forwarded-for') : undefined;\r\n\r\n // 2. Run in Context\r\n return client.startTrace({\r\n method,\r\n path: url.pathname,\r\n userAgent: ua,\r\n ip: ip\r\n }, async () => {\r\n try {\r\n const response = await handler(req, context);\r\n const status = response?.status || 200;\r\n \r\n client.endTrace(status, { route: normalizePath(url.pathname) });\r\n return response;\r\n } catch (err: any) {\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 (API Routes) ---\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 // 1. Run in Context\r\n return client.startTrace({\r\n method: req.method || 'GET',\r\n path: path,\r\n userAgent: req.headers['user-agent'],\r\n ip: req.headers['x-forwarded-for'] || req.socket?.remoteAddress,\r\n }, async () => {\r\n \r\n // 2. Hook Response\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); // Fallback if finish doesn't fire\r\n\r\n // 3. Execute\r\n try {\r\n return await handler(req, res);\r\n } catch (e) {\r\n // Next.js Pages router usually handles errors internally, \r\n // but we ensure we catch sync errors here\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\n// We don't import Fastify types to keep zero-deps, but structure matches\r\nexport const senzorPlugin = (fastify: any, options: SenzorOptions, done: Function) => {\r\n\r\n // Init if options provided inline, otherwise assume global init\r\n if (options && options.apiKey) {\r\n client.init(options);\r\n }\r\n\r\n // Hook: On Request (Start Timer)\r\n fastify.addHook('onRequest', (request: any, reply: any, next: Function) => {\r\n request.senzorStart = performance.now();\r\n next();\r\n });\r\n\r\n // Hook: On Response (End Timer & Track)\r\n fastify.addHook('onResponse', (request: any, reply: any, next: Function) => {\r\n const duration = performance.now() - (request.senzorStart || performance.now());\r\n\r\n // Fastify provides 'routerPath' (e.g. /user/:id)\r\n const route = request.routeOptions?.url || request.routerPath;\r\n\r\n client.track({\r\n method: request.method,\r\n route: route || 'UNKNOWN',\r\n path: request.raw.url || request.url,\r\n status: reply.statusCode,\r\n duration: duration,\r\n ip: request.ip,\r\n userAgent: request.headers['user-agent']\r\n });\r\n\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","import_crypto","import_http","import_https","import_url","shimmer","module","methodName","wrapper","original","instrumentFetch","ingestUrl","debug","ingestHost","originalFetch","input","init","urlStr","trace","Context","method","startTime","spanStartAbs","hostname","response","duration","err","instrumentHttp","requestWrapper","args","options","protocol","host","path","req","captureSpan","res","error","http","https","instrumentMongo","debug","mongodb","Collection","FindCursor","AggregationCursor","recordSpan","name","operation","collection","startAbs","traceStart","err","duration","Context","method","original","args","trace","spanStartAbs","collName","result","res","patchCursor","CursorClass","label","originalToArray","onSuccess","onError","e","instrumentPg","pg","originalQuery","args","trace","Context","startTime","spanStartAbs","sql","result","res","duration","SenzorClient","options","endpoint","debug","Transport","instrumentHttp","instrumentFetch","instrumentMongo","instrumentPg","data","next","trace","Context","status","extraData","duration","payload","name","type","startTime","spanStartAbs","meta","client","expressMiddleware","req","res","next","client","route","normalizePath","path","getRoute","req","fallbackPath","wrapH3","handler","event","req","path","client","response","status","getRoute","err","wrapNextRoute","handler","req","context","url","method","ua","ip","client","response","status","normalizePath","err","wrapNextPages","res","path","done","e","senzorPlugin","fastify","options","done","client","request","reply","next","duration","route","Senzor","options","client","expressMiddleware","wrapNextRoute","wrapNextPages","wrapH3","senzorPlugin","index_default"]}
package/dist/index.mjs CHANGED
@@ -1,2 +1,2 @@
1
- var O=(n=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(n,{get:(t,r)=>(typeof require<"u"?require:t)[r]}):n)(function(n){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+n+'" is not supported')});var w=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(r){this.config.debug&&console.error("[Senzor] Ingestion Error:",r)}}};import{AsyncLocalStorage as D}from"async_hooks";var z=new D,p={run:(n,t)=>z.run(n,t),current:()=>z.getStore(),addSpan:n=>{let t=z.getStore();t?t.spans.push(n):console.warn("[Senzor] Lost context for span:",n.name)}};import{randomUUID as N}from"crypto";import P from"http";import I from"https";import{URL as A}from"url";var T=(n,t,r)=>{if(!n[t])return;let e=n[t];n[t]=r(e)},$=(n,t=!1)=>{let r="";try{r=new A(n).hostname,t&&console.log(`[Senzor] HTTP Instrumentation ignoring host: ${r}`)}catch{t&&console.error("[Senzor] Invalid Ingest URL for HTTP instrumentation")}let e=s=>function(...o){let a={},i="";if(typeof o[0]=="string"||o[0]instanceof A)i=o[0].toString(),typeof o[1]=="object"&&o[1]!==null&&(a=o[1]);else{a=o[0]||{};let f=a.protocol||(a.port===443?"https:":"http:"),x=a.hostname||a.host||"localhost",b=a.path||"/";i=`${f}//${x}${b}`}if(r&&(i.includes(r)||a.hostname&&a.hostname.includes(r)))return s.apply(this,o);let u=p.current();if(!u)return s.apply(this,o);let m=(a.method||"GET").toUpperCase(),S=performance.now()-u.startTime,g=performance.now(),h="unknown";try{h=new A(i).hostname}catch{h=a.hostname||"unknown"}t&&console.log(`[Senzor] Tracking HTTP: ${m} ${h}`);let l=s.apply(this,o),d=(f,x)=>{let b=performance.now()-g;p.addSpan({name:`${m} ${h}`,type:"http",startTime:S,duration:b,status:x?500:f?.statusCode||0,meta:{url:i,method:m}})};return l.on("response",f=>{f.once("end",()=>d(f))}),l.on("error",f=>{d(null,f)}),l};T(P,"request",e),T(P,"get",e),T(I,"request",e),T(I,"get",e)};var F=(n=!1)=>{try{let r=O("mongodb").Collection;n&&console.log("[Senzor] Instrumenting MongoDB...");let e=["insertOne","insertMany","updateOne","updateMany","replaceOne","deleteOne","deleteMany","count","countDocuments","estimatedDocumentCount","distinct"],s=["find","aggregate"];e.forEach(o=>{if(!r.prototype[o])return;let a=r.prototype[o];r.prototype[o]=function(...i){let u=p.current();if(!u)return a.apply(this,i);let m=performance.now()-u.startTime,S=performance.now(),g=this.collectionName,h=l=>{let d=performance.now()-S;p.addSpan({name:`MongoDB ${o} (${g})`,type:"db",startTime:m,duration:d,status:l?500:0,meta:{collection:g,operation:o}}),n&&console.log(`[Senzor] Captured Mongo Span: ${o}`)};try{let l=a.apply(this,i);return l&&typeof l.then=="function"?l.then(d=>(h(),d),d=>{throw h(d),d}):l}catch(l){throw h(l),l}}}),s.forEach(o=>{if(!r.prototype[o])return;let a=r.prototype[o];r.prototype[o]=function(...i){let u=p.current();if(!u)return a.apply(this,i);let m=performance.now()-u.startTime;return p.addSpan({name:`MongoDB ${o} (${this.collectionName})`,type:"db",startTime:m,duration:0,status:0,meta:{collection:this.collectionName,operation:o}}),n&&console.log(`[Senzor] Captured Mongo Cursor: ${o}`),a.apply(this,i)}})}catch(t){n&&console.warn("[Senzor] MongoDB instrumentation skipped:",t.message)}};var M=()=>{try{let n=O("pg"),t=n.Client.prototype.query;n.Client.prototype.query=function(...r){let e=p.current();if(!e)return t.apply(this,r);let s=performance.now()-e.startTime,o=performance.now(),a=typeof r[0]=="string"?r[0]:r[0].text,i=t.apply(this,r);return i&&typeof i.then=="function"?i.then(u=>{let m=performance.now()-o;return p.addSpan({name:"Postgres Query",type:"db",startTime:s,duration:m,meta:{query:a}}),u}):i}}catch{}};var C=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 r=t.endpoint||"https://api.senzor.dev/api/ingest/apm",e=t.debug||!1;if(this.transport=new w({...t,endpoint:r}),!this.isInstrumented){try{$(r,e)}catch{}try{F(e)}catch{}try{M()}catch{}this.isInstrumented=!0,e&&console.log("[Senzor] Auto-instrumentation enabled")}}startTrace(t,r){if(!this.transport)return r();let e={id:N(),startTime:performance.now(),data:t,spans:[]};return p.run(e,r)}endTrace(t,r={}){let e=p.current();if(!e||!this.transport)return;let s=performance.now()-e.startTime,o={traceId:e.id,...e.data,...r,status:t,duration:s,spans:e.spans,timestamp:new Date().toISOString()};this.options?.debug&&console.log(`[Senzor] Ended Trace ${e.id} with ${e.spans.length} spans`),this.transport.add(o)}track(t){if(!this.transport)return;let r={traceId:N(),...t,spans:[],timestamp:new Date().toISOString()};this.transport.add(r)}startSpan(t,r="custom"){let e=p.current();if(!e)return{end:()=>{}};let s=performance.now()-e.startTime,o=performance.now();return{end:(a,i)=>{let u=performance.now()-o;p.addSpan({name:t,type:r,startTime:s,duration:u,status:i,meta:a})}}}async flush(){this.transport&&await this.transport.flush()}},c=new C;var k=()=>(n,t,r)=>{c.startTrace({method:n.method,path:n.originalUrl||n.url,ip:n.ip||n.socket?.remoteAddress,userAgent:n.headers["user-agent"]},()=>{t.once("finish",()=>{try{let e="UNKNOWN";n.route&&n.route.path?e=(n.baseUrl||"")+n.route.path:t.statusCode===404?e="Not Found":e=n.path||"Wildcard",c.endTrace(t.statusCode,{route:e})}catch{}}),r()})};var y=n=>!n||n==="/"?"/":n.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=(n,t)=>n.route&&n.route.path?(n.baseUrl||"")+n.route.path:n.context&&n.context.matchedRoute?n.context.matchedRoute.path:n.routerPath?n.routerPath:y(t);var E=n=>t=>{let r=t.node.req,e=r.originalUrl||r.url||"/";return c.startTrace({method:r.method||"GET",path:e,ip:r.headers["x-forwarded-for"]||r.socket?.remoteAddress,userAgent:r.headers["user-agent"]},async()=>{try{let s=await n(t),o=200;return t.node.res.statusCode&&(o=t.node.res.statusCode),s&&s.statusCode&&(o=s.statusCode),c.endTrace(o,{route:v(t,e)}),s}catch(s){let o=s.statusCode||s.status||500;throw c.endTrace(o,{route:v(t,e)}),s}})};var H=n=>async(t,r)=>{let e=t.url?new URL(t.url):{pathname:"/"},s=t.method||"GET",o=t.headers.get?t.headers.get("user-agent"):void 0,a=t.headers.get?t.headers.get("x-forwarded-for"):void 0;return c.startTrace({method:s,path:e.pathname,userAgent:o,ip:a},async()=>{try{let i=await n(t,r),u=i?.status||200;return c.endTrace(u,{route:y(e.pathname)}),i}catch(i){throw c.endTrace(500,{route:y(e.pathname)}),i}})},R=n=>async(t,r)=>{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},async()=>{let s=()=>{c.endTrace(r.statusCode||200,{route:y(e)})};r.once("finish",s),r.once("close",s);try{return await n(t,r)}catch(o){throw o}})};var U=(n,t,r)=>{t&&t.apiKey&&c.init(t),n.addHook("onRequest",(e,s,o)=>{e.senzorStart=performance.now(),o()}),n.addHook("onResponse",(e,s,o)=>{let a=performance.now()-(e.senzorStart||performance.now()),i=e.routeOptions?.url||e.routerPath;c.track({method:e.method,route:i||"UNKNOWN",path:e.raw.url||e.url,status:s.statusCode,duration:a,ip:e.ip,userAgent:e.headers["user-agent"]}),o()}),r()};var K={init:n=>c.init(n),flush:()=>c.flush(),requestHandler:k,wrapNextRoute:H,wrapNextPages:R,wrapH3:E,fastifyPlugin:U},zt=K;export{K as Senzor,zt as default};
1
+ var A=(e=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(e,{get:(t,r)=>(typeof require<"u"?require:t)[r]}):e)(function(e){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+e+'" is not supported')});var z=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(r){this.config.debug&&console.error("[Senzor] Ingestion Error:",r)}}};import{AsyncLocalStorage as G}from"async_hooks";var F=new G,l={run:(e,t)=>F.run(e,t),current:()=>F.getStore(),addSpan:e=>{let t=F.getStore();t?t.spans.push(e):console.warn("[Senzor] Lost context for span:",e.name)}};import{randomUUID as N}from"crypto";import I from"http";import P from"https";import{URL as x}from"url";var C=(e,t,r)=>{if(!e[t])return;let n=e[t];e[t]=r(n)},$=(e,t=!1)=>{if(!globalThis.fetch)return;let r="";try{r=new x(e).hostname}catch{}let n=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),r&&i.includes(r))return n(o,a);let c=l.current();if(!c)return n(o,a);let s=(a?.method||"GET").toUpperCase(),f=performance.now()-c.startTime,w=performance.now(),d="unknown";try{d=new x(i).hostname}catch{}t&&console.log(`[Senzor] Tracking Fetch: ${s} ${d}`);try{let p=await n(o,a),h=performance.now()-w;return l.addSpan({name:`${s} ${d}`,type:"http",startTime:f,duration:h,status:p.status,meta:{url:i,method:s,library:"fetch"}}),p}catch(p){let h=performance.now()-w;throw l.addSpan({name:`${s} ${d}`,type:"http",startTime:f,duration:h,status:500,meta:{error:p.message,url:i,library:"fetch"}}),p}}},k=(e,t=!1)=>{let r="";try{r=new x(e).hostname}catch{}let n=o=>function(...a){let i={},c="";if(typeof a[0]=="string"||a[0]instanceof x)c=a[0].toString(),typeof a[1]=="object"&&a[1]!==null&&(i=a[1]);else{i=a[0]||{};let u=i.protocol||(i.port===443?"https:":"http:"),g=i.hostname||i.host||"localhost",T=i.path||"/";c=`${u}//${g}${T}`}if(r&&(c.includes(r)||i.hostname&&i.hostname.includes(r)))return o.apply(this,a);let s=l.current();if(!s)return o.apply(this,a);let f=(i.method||"GET").toUpperCase(),w=performance.now()-s.startTime,d=performance.now(),p="unknown";try{p=new x(c).hostname}catch{p=i.hostname||"unknown"}let h=o.apply(this,a),y=(u,g)=>{let T=performance.now()-d;l.addSpan({name:`${f} ${p}`,type:"http",startTime:w,duration:T,status:g?500:u?.statusCode||0,meta:{url:c,method:f,library:"http"}})};return h.on("response",u=>{u.once("end",()=>y(u)),u.once("error",g=>y(u,g))}),h.on("error",u=>y(null,u)),h};C(I,"request",n),C(I,"get",n),C(P,"request",n),C(P,"get",n)};var E=(e=!1)=>{try{let t=A("mongodb"),r=t.Collection,n=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,f,w,d,p,h)=>{let y=performance.now()-d;l.addSpan({name:`MongoDB ${s}`,type:"db",startTime:performance.now()-p-y,duration:y,status:h?500:0,meta:{collection:w,operation:f,error:h?h.message:void 0}}),e&&console.log(`[Senzor] Captured Mongo: ${s} (${y.toFixed(2)}ms)`)};["insertOne","insertMany","updateOne","updateMany","deleteOne","deleteMany","countDocuments"].forEach(s=>{if(!r.prototype[s])return;let f=r.prototype[s];r.prototype[s]=function(...w){let d=l.current();if(!d)return f.apply(this,w);let p=performance.now(),h=d.startTime,y=this.collectionName;try{let u=f.apply(this,w);return u&&typeof u.then=="function"?u.then(g=>(a(s,s,y,p,h),g),g=>{throw a(s,s,y,p,h,g),g}):u}catch(u){throw a(s,s,y,p,h,u),u}}});let c=(s,f)=>{if(!s||!s.prototype.toArray)return;let w=s.prototype.toArray;s.prototype.toArray=function(...d){let p=l.current();if(!p)return w.apply(this,d);let h=performance.now(),y=p.startTime,u=this.namespace?.collection||"unknown",g=S=>(a(f,f,u,h,y),S),T=S=>{throw a(f,f,u,h,y,S),S};try{let S=w.apply(this,d);return S&&typeof S.then=="function"?S.then(g,T):g(S)}catch(S){T(S)}}};c(n,"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(...r){let n=l.current();if(!n)return t.apply(this,r);let o=performance.now()-n.startTime,a=performance.now(),i=typeof r[0]=="string"?r[0]:r[0].text,c=t.apply(this,r);return c&&typeof c.then=="function"?c.then(s=>{let f=performance.now()-a;return l.addSpan({name:"Postgres Query",type:"db",startTime:o,duration:f,meta:{query:i}}),s}):c}}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 r=t.endpoint||"https://api.senzor.dev/api/ingest/apm",n=t.debug||!1;if(this.transport=new z({...t,endpoint:r}),!this.isInstrumented){try{k(r,n)}catch{}try{$(r,n)}catch{}try{E(n)}catch{}try{M()}catch{}this.isInstrumented=!0,n&&console.log("[Senzor] Auto-instrumentation enabled (HTTP, Fetch, Mongo)")}}startTrace(t,r){if(!this.transport)return r();let n={id:N(),startTime:performance.now(),data:t,spans:[]};return l.run(n,r)}endTrace(t,r={}){let n=l.current();if(!n||!this.transport)return;let o=performance.now()-n.startTime,a={traceId:n.id,...n.data,...r,status:t,duration:o,spans:n.spans,timestamp:new Date().toISOString()};this.transport.add(a)}track(t){this.transport?.add({traceId:N(),...t,spans:[],timestamp:new Date().toISOString()})}startSpan(t,r="custom"){let n=l.current();if(!n)return{end:()=>{}};let o=performance.now()-n.startTime,a=performance.now();return{end:(i,c)=>{l.addSpan({name:t,type:r,startTime:o,duration:performance.now()-a,status:c,meta:i})}}}async flush(){this.transport&&await this.transport.flush()}},m=new v;var R=()=>(e,t,r)=>{m.startTrace({method:e.method,path:e.originalUrl||e.url,ip:e.ip||e.socket?.remoteAddress,userAgent:e.headers["user-agent"]},()=>{t.once("finish",()=>{try{let n="UNKNOWN";e.route&&e.route.path?n=(e.baseUrl||"")+e.route.path:t.statusCode===404?n="Not Found":n=e.path||"Wildcard",m.endTrace(t.statusCode,{route:n})}catch{}}),r()})};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],O=(e,t)=>e.route&&e.route.path?(e.baseUrl||"")+e.route.path:e.context&&e.context.matchedRoute?e.context.matchedRoute.path:e.routerPath?e.routerPath:b(t);var U=e=>t=>{let r=t.node.req,n=r.originalUrl||r.url||"/";return m.startTrace({method:r.method||"GET",path:n,ip:r.headers["x-forwarded-for"]||r.socket?.remoteAddress,userAgent:r.headers["user-agent"]},async()=>{try{let o=await e(t),a=200;return t.node.res.statusCode&&(a=t.node.res.statusCode),o&&o.statusCode&&(a=o.statusCode),m.endTrace(a,{route:O(t,n)}),o}catch(o){let a=o.statusCode||o.status||500;throw m.endTrace(a,{route:O(t,n)}),o}})};var H=e=>async(t,r)=>{let n=t.url?new URL(t.url):{pathname:"/"},o=t.method||"GET",a=t.headers.get?t.headers.get("user-agent"):void 0,i=t.headers.get?t.headers.get("x-forwarded-for"):void 0;return m.startTrace({method:o,path:n.pathname,userAgent:a,ip:i},async()=>{try{let c=await e(t,r),s=c?.status||200;return m.endTrace(s,{route:b(n.pathname)}),c}catch(c){throw m.endTrace(500,{route:b(n.pathname)}),c}})},D=e=>async(t,r)=>{let n=t.url?t.url.split("?")[0]:"/";return m.startTrace({method:t.method||"GET",path:n,userAgent:t.headers["user-agent"],ip:t.headers["x-forwarded-for"]||t.socket?.remoteAddress},async()=>{let o=()=>{m.endTrace(r.statusCode||200,{route:b(n)})};r.once("finish",o),r.once("close",o);try{return await e(t,r)}catch(a){throw a}})};var K=(e,t,r)=>{t&&t.apiKey&&m.init(t),e.addHook("onRequest",(n,o,a)=>{n.senzorStart=performance.now(),a()}),e.addHook("onResponse",(n,o,a)=>{let i=performance.now()-(n.senzorStart||performance.now()),c=n.routeOptions?.url||n.routerPath;m.track({method:n.method,route:c||"UNKNOWN",path:n.raw.url||n.url,status:o.statusCode,duration:i,ip:n.ip,userAgent:n.headers["user-agent"]}),a()}),r()};var L={init:e=>m.init(e),flush:()=>m.flush(),requestHandler:R,wrapNextRoute:H,wrapNextPages:D,wrapH3:U,fastifyPlugin:K},Ct=L;export{L as Senzor,Ct 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 } 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 } else {\r\n // If we are here, something tried to add a span but lost context\r\n // This is common if users await inside a callback that wasn't bound\r\n // However, usually silent failure is preferred in production APM\r\n console.warn('[Senzor] Lost context for span:', span.name);\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 } 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({\r\n ...options,\r\n endpoint\r\n });\r\n\r\n if (!this.isInstrumented) {\r\n try { instrumentHttp(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 // ... (startTrace, endTrace, track, startSpan, flush remain same) ...\r\n // Ensuring startTrace returns T\r\n public startTrace<T>(data: Partial<ActiveTrace['data']>, next: () => T): T {\r\n if (!this.transport) return next();\r\n\r\n const trace: ActiveTrace = {\r\n id: randomUUID(),\r\n startTime: performance.now(),\r\n data: data,\r\n spans: []\r\n };\r\n return Context.run(trace, next);\r\n }\r\n\r\n public endTrace(status: number, extraData: any = {}) {\r\n const trace = Context.current();\r\n if (!trace || !this.transport) return;\r\n\r\n const duration = performance.now() - trace.startTime;\r\n\r\n const payload = {\r\n traceId: trace.id,\r\n ...trace.data,\r\n ...extraData,\r\n status,\r\n duration,\r\n spans: trace.spans,\r\n timestamp: new Date().toISOString()\r\n };\r\n\r\n if (this.options?.debug) console.log(`[Senzor] Ended Trace ${trace.id} with ${trace.spans.length} spans`);\r\n\r\n this.transport.add(payload);\r\n }\r\n\r\n // ... (manual track methods) ...\r\n public track(data: {\r\n method: string;\r\n route: string;\r\n path: string;\r\n status: number;\r\n duration: number;\r\n ip?: string;\r\n userAgent?: string;\r\n }) {\r\n if (!this.transport) return;\r\n const payload = {\r\n traceId: randomUUID(),\r\n ...data,\r\n spans: [],\r\n timestamp: new Date().toISOString()\r\n };\r\n this.transport.add(payload);\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\r\n const startTime = performance.now() - trace.startTime;\r\n const spanStartAbs = performance.now();\r\n\r\n return {\r\n end: (meta?: any, status?: number) => {\r\n const duration = performance.now() - spanStartAbs;\r\n Context.addSpan({\r\n name,\r\n type,\r\n startTime,\r\n duration,\r\n status,\r\n meta\r\n });\r\n }\r\n };\r\n }\r\n\r\n public async flush() {\r\n if (this.transport) await this.transport.flush();\r\n }\r\n}\r\n\r\nexport const client = new SenzorClient();","import http from 'http';\r\nimport https from 'https';\r\nimport { URL } from 'url';\r\nimport { Context } from '../core/context';\r\n\r\nconst shimmer = (module: any, methodName: string, wrapper: (original: Function) => Function) => {\r\n if (!module[methodName]) return;\r\n const original = module[methodName];\r\n module[methodName] = wrapper(original);\r\n};\r\n\r\nexport const instrumentHttp = (ingestUrl: string, debug = false) => {\r\n let ingestHost = '';\r\n try {\r\n ingestHost = new URL(ingestUrl).hostname;\r\n if (debug) console.log(`[Senzor] HTTP Instrumentation ignoring host: ${ingestHost}`);\r\n } catch (e) {\r\n // If invalid URL passed, we can't filter loop safely, so we might skip instrumentation\r\n if (debug) console.error('[Senzor] Invalid Ingest URL for HTTP instrumentation');\r\n }\r\n\r\n const requestWrapper = (original: Function) => {\r\n return function (this: any, ...args: any[]) {\r\n let options: any = {};\r\n let urlStr = '';\r\n\r\n if (typeof args[0] === 'string' || args[0] instanceof URL) {\r\n urlStr = args[0].toString();\r\n if (typeof args[1] === 'object' && args[1] !== null) options = args[1];\r\n } else {\r\n options = args[0] || {};\r\n const protocol = options.protocol || (options.port === 443 ? 'https:' : 'http:');\r\n const host = options.hostname || options.host || 'localhost';\r\n const path = options.path || '/';\r\n urlStr = `${protocol}//${host}${path}`;\r\n }\r\n\r\n // Safety Guard: Ignore calls to Senzor Ingest API\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) {\r\n // Not inside a tracked request\r\n return original.apply(this, args);\r\n }\r\n\r\n const method = (options.method || 'GET').toUpperCase();\r\n const startTime = performance.now() - trace.startTime;\r\n const spanStartAbs = performance.now();\r\n let hostname = 'unknown';\r\n try { hostname = new URL(urlStr).hostname; } catch (e) { hostname = options.hostname || 'unknown'; }\r\n\r\n if (debug) console.log(`[Senzor] Tracking HTTP: ${method} ${hostname}`);\r\n\r\n const req = original.apply(this, args);\r\n\r\n const captureSpan = (res: any, error?: Error) => {\r\n const duration = performance.now() - spanStartAbs;\r\n Context.addSpan({\r\n name: `${method} ${hostname}`,\r\n type: 'http',\r\n startTime,\r\n duration,\r\n status: error ? 500 : res?.statusCode || 0,\r\n meta: { url: urlStr, method }\r\n });\r\n };\r\n\r\n req.on('response', (res: any) => {\r\n // We capture on 'response' (headers received) to be safe.\r\n // Waiting for 'end' might miss requests where body isn't consumed.\r\n res.once('end', () => captureSpan(res));\r\n // Fallback if 'end' doesn't fire fast enough\r\n // setTimeout(() => captureSpan(res), 5000); \r\n });\r\n\r\n req.on('error', (err: Error) => {\r\n captureSpan(null, err);\r\n });\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 // Attempt to load the user's installed mongodb driver\r\n // This works for both native driver users and Mongoose users (as mongoose depends on this)\r\n const mongodb = require('mongodb');\r\n const Collection = mongodb.Collection;\r\n\r\n if (debug) console.log('[Senzor] Instrumenting MongoDB...');\r\n\r\n // Methods that return Promises\r\n const promiseMethods = [\r\n 'insertOne', 'insertMany', 'updateOne', 'updateMany',\r\n 'replaceOne', 'deleteOne', 'deleteMany', 'count', 'countDocuments',\r\n 'estimatedDocumentCount', 'distinct'\r\n ];\r\n\r\n // Methods that return Cursors (need special handling)\r\n const cursorMethods = ['find', 'aggregate'];\r\n\r\n // 1. Instrument Promise-based methods\r\n promiseMethods.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 startTime = performance.now() - trace.startTime;\r\n const spanStartAbs = performance.now();\r\n const collectionName = this.collectionName;\r\n\r\n const endSpan = (err?: Error) => {\r\n const duration = performance.now() - spanStartAbs;\r\n Context.addSpan({\r\n name: `MongoDB ${method} (${collectionName})`,\r\n type: 'db',\r\n startTime,\r\n duration,\r\n status: err ? 500 : 0,\r\n meta: { collection: collectionName, operation: method }\r\n });\r\n if (debug) console.log(`[Senzor] Captured Mongo Span: ${method}`);\r\n };\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) => { endSpan(); return res; },\r\n (err: any) => { endSpan(err); throw err; }\r\n );\r\n }\r\n return result;\r\n } catch (err: any) {\r\n endSpan(err);\r\n throw err;\r\n }\r\n };\r\n });\r\n\r\n // 2. Instrument Cursor-based methods (find, aggregate)\r\n // We trace the *creation* of the cursor, not the fetching, as fetching is async/streamed\r\n cursorMethods.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 startTime = performance.now() - trace.startTime;\r\n\r\n // Record the intent to query\r\n Context.addSpan({\r\n name: `MongoDB ${method} (${this.collectionName})`,\r\n type: 'db',\r\n startTime,\r\n duration: 0, // Placeholder, as cursor creation is instant\r\n status: 0,\r\n meta: { collection: this.collectionName, operation: method }\r\n });\r\n\r\n if (debug) console.log(`[Senzor] Captured Mongo Cursor: ${method}`);\r\n\r\n return original.apply(this, args);\r\n };\r\n });\r\n\r\n } catch (e: any) {\r\n if (debug) console.warn('[Senzor] MongoDB instrumentation skipped:', 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\nexport const expressMiddleware = () => {\r\n return (req: any, res: any, next: () => void) => {\r\n // We MUST use startTrace to enable Auto-Instrumentation for this request\r\n client.startTrace({\r\n method: req.method,\r\n path: req.originalUrl || req.url,\r\n ip: req.ip || req.socket?.remoteAddress,\r\n userAgent: req.headers['user-agent'],\r\n }, () => {\r\n\r\n res.once('finish', () => {\r\n try {\r\n let route = 'UNKNOWN';\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) {\r\n // Fail open\r\n }\r\n });\r\n\r\n next();\r\n });\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\n// Minimal types for H3 to avoid peer-deps\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 // Start Trace Context\r\n return client.startTrace({\r\n method: req.method || 'GET',\r\n path: path,\r\n ip: req.headers['x-forwarded-for'] || req.socket?.remoteAddress,\r\n userAgent: req.headers['user-agent'],\r\n }, async () => {\r\n try {\r\n const response = await handler(event);\r\n\r\n // H3/Nitro response status\r\n let status = 200;\r\n if (event.node.res.statusCode) status = event.node.res.statusCode;\r\n // Check if response is an error object\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 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 (Route Handlers) ---\r\nexport const wrapNextRoute = (handler: Function) => {\r\n return async (req: Request | any, context?: any) => {\r\n // 1. Extract Info\r\n const url = req.url ? new URL(req.url) : { pathname: '/' };\r\n const method = req.method || 'GET';\r\n const ua = req.headers.get ? req.headers.get('user-agent') : undefined;\r\n const ip = req.headers.get ? req.headers.get('x-forwarded-for') : undefined;\r\n\r\n // 2. Run in Context\r\n return client.startTrace({\r\n method,\r\n path: url.pathname,\r\n userAgent: ua,\r\n ip: ip\r\n }, async () => {\r\n try {\r\n const response = await handler(req, context);\r\n const status = response?.status || 200;\r\n \r\n client.endTrace(status, { route: normalizePath(url.pathname) });\r\n return response;\r\n } catch (err: any) {\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 (API Routes) ---\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 // 1. Run in Context\r\n return client.startTrace({\r\n method: req.method || 'GET',\r\n path: path,\r\n userAgent: req.headers['user-agent'],\r\n ip: req.headers['x-forwarded-for'] || req.socket?.remoteAddress,\r\n }, async () => {\r\n \r\n // 2. Hook Response\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); // Fallback if finish doesn't fire\r\n\r\n // 3. Execute\r\n try {\r\n return await handler(req, res);\r\n } catch (e) {\r\n // Next.js Pages router usually handles errors internally, \r\n // but we ensure we catch sync errors here\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\n// We don't import Fastify types to keep zero-deps, but structure matches\r\nexport const senzorPlugin = (fastify: any, options: SenzorOptions, done: Function) => {\r\n\r\n // Init if options provided inline, otherwise assume global init\r\n if (options && options.apiKey) {\r\n client.init(options);\r\n }\r\n\r\n // Hook: On Request (Start Timer)\r\n fastify.addHook('onRequest', (request: any, reply: any, next: Function) => {\r\n request.senzorStart = performance.now();\r\n next();\r\n });\r\n\r\n // Hook: On Response (End Timer & Track)\r\n fastify.addHook('onResponse', (request: any, reply: any, next: Function) => {\r\n const duration = performance.now() - (request.senzorStart || performance.now());\r\n\r\n // Fastify provides 'routerPath' (e.g. /user/:id)\r\n const route = request.routeOptions?.url || request.routerPath;\r\n\r\n client.track({\r\n method: request.method,\r\n route: route || 'UNKNOWN',\r\n path: request.raw.url || request.url,\r\n status: reply.statusCode,\r\n duration: duration,\r\n ip: request.ip,\r\n userAgent: request.headers['user-agent']\r\n });\r\n\r\n next();\r\n });\r\n\r\n done();\r\n};","import { client } from './core/client';\r\nimport { expressMiddleware } 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 // Core\r\n init: (options: SenzorOptions) => client.init(options),\r\n flush: () => client.flush(),\r\n\r\n // Express / Connect\r\n requestHandler: expressMiddleware,\r\n\r\n // Next.js\r\n wrapNextRoute, // For App Router (Route Handlers)\r\n wrapNextPages, // For Pages Router (API Routes)\r\n\r\n // H3 / Nuxt / Nitro\r\n wrapH3,\r\n\r\n // Fastify\r\n fastifyPlugin: senzorPlugin\r\n};\r\n\r\nexport default Senzor;\r\nexport { Senzor };"],"mappings":"yPAEO,IAAMA,EAAN,KAAgB,CAIrB,YAAoBC,EAAuB,CAAvB,YAAAA,EAHpB,KAAQ,MAAe,CAAC,EACxB,KAAQ,MAA+B,KAGjC,OAAO,YAAgB,MACzB,KAAK,MAAQ,YAAY,IAAM,KAAK,MAAM,EAAGA,EAAO,eAAiB,GAAK,EACtE,KAAK,OAAS,OAAO,KAAK,MAAM,OAAU,YAC5C,KAAK,MAAM,MAAM,EAGvB,CAEO,IAAIC,EAAY,CACrB,KAAK,MAAM,KAAKA,CAAK,EACjB,KAAK,MAAM,SAAW,KAAK,OAAO,WAAa,MACjD,KAAK,MAAM,CAEf,CAEA,MAAa,OAAQ,CACnB,GAAI,KAAK,MAAM,SAAW,EAAG,OAE7B,IAAMC,EAAQ,CAAC,GAAG,KAAK,KAAK,EAC5B,KAAK,MAAQ,CAAC,EAEd,GAAI,CAEF,MAAM,MAAM,KAAK,OAAO,UAAY,wCAAyC,CAC3E,OAAQ,OACR,QAAS,CACP,eAAgB,mBAChB,oBAAqB,KAAK,OAAO,MACnC,EACA,KAAM,KAAK,UAAUA,CAAK,EAC1B,UAAW,EACb,CAAC,EAEG,KAAK,OAAO,OAAO,QAAQ,IAAI,oBAAoBA,EAAM,MAAM,SAAS,CAC9E,OAASC,EAAK,CACR,KAAK,OAAO,OAAO,QAAQ,MAAM,4BAA6BA,CAAG,CAEvE,CACF,CACF,EC9CA,OAAS,qBAAAC,MAAyB,cAG3B,IAAMC,EAAU,IAAID,EAEdE,EAAU,CACrB,IAAK,CAAIC,EAAoBC,IACpBH,EAAQ,IAAIE,EAAOC,CAAE,EAG9B,QAAS,IACAH,EAAQ,SAAS,EAG1B,QAAUI,GAAc,CACtB,IAAMC,EAAQL,EAAQ,SAAS,EAC3BK,EACFA,EAAM,MAAM,KAAKD,CAAI,EAKrB,QAAQ,KAAK,kCAAmCA,EAAK,IAAI,CAE7D,CACF,ECtBA,OAAS,cAAAE,MAAkB,SCH3B,OAAOC,MAAU,OACjB,OAAOC,MAAW,QAClB,OAAS,OAAAC,MAAW,MAGpB,IAAMC,EAAU,CAACC,EAAaC,EAAoBC,IAA8C,CAC9F,GAAI,CAACF,EAAOC,CAAU,EAAG,OACzB,IAAME,EAAWH,EAAOC,CAAU,EAClCD,EAAOC,CAAU,EAAIC,EAAQC,CAAQ,CACvC,EAEaC,EAAiB,CAACC,EAAmBC,EAAQ,KAAU,CAClE,IAAIC,EAAa,GACjB,GAAI,CACFA,EAAa,IAAIC,EAAIH,CAAS,EAAE,SAC5BC,GAAO,QAAQ,IAAI,gDAAgDC,CAAU,EAAE,CACrF,MAAY,CAEND,GAAO,QAAQ,MAAM,sDAAsD,CACjF,CAEA,IAAMG,EAAkBN,GACf,YAAwBO,EAAa,CAC1C,IAAIC,EAAe,CAAC,EAChBC,EAAS,GAEb,GAAI,OAAOF,EAAK,CAAC,GAAM,UAAYA,EAAK,CAAC,YAAaF,EACpDI,EAASF,EAAK,CAAC,EAAE,SAAS,EACtB,OAAOA,EAAK,CAAC,GAAM,UAAYA,EAAK,CAAC,IAAM,OAAMC,EAAUD,EAAK,CAAC,OAChE,CACLC,EAAUD,EAAK,CAAC,GAAK,CAAC,EACtB,IAAMG,EAAWF,EAAQ,WAAaA,EAAQ,OAAS,IAAM,SAAW,SAClEG,EAAOH,EAAQ,UAAYA,EAAQ,MAAQ,YAC3CI,EAAOJ,EAAQ,MAAQ,IAC7BC,EAAS,GAAGC,CAAQ,KAAKC,CAAI,GAAGC,CAAI,EACtC,CAGA,GAAIR,IAAeK,EAAO,SAASL,CAAU,GAAMI,EAAQ,UAAYA,EAAQ,SAAS,SAASJ,CAAU,GACzG,OAAOJ,EAAS,MAAM,KAAMO,CAAI,EAGlC,IAAMM,EAAQC,EAAQ,QAAQ,EAC9B,GAAI,CAACD,EAEH,OAAOb,EAAS,MAAM,KAAMO,CAAI,EAGlC,IAAMQ,GAAUP,EAAQ,QAAU,OAAO,YAAY,EAC/CQ,EAAY,YAAY,IAAI,EAAIH,EAAM,UACtCI,EAAe,YAAY,IAAI,EACjCC,EAAW,UACf,GAAI,CAAEA,EAAW,IAAIb,EAAII,CAAM,EAAE,QAAU,MAAY,CAAES,EAAWV,EAAQ,UAAY,SAAW,CAE/FL,GAAO,QAAQ,IAAI,2BAA2BY,CAAM,IAAIG,CAAQ,EAAE,EAEtE,IAAMC,EAAMnB,EAAS,MAAM,KAAMO,CAAI,EAE/Ba,EAAc,CAACC,EAAUC,IAAkB,CAC/C,IAAMC,EAAW,YAAY,IAAI,EAAIN,EACrCH,EAAQ,QAAQ,CACd,KAAM,GAAGC,CAAM,IAAIG,CAAQ,GAC3B,KAAM,OACN,UAAAF,EACA,SAAAO,EACA,OAAQD,EAAQ,IAAMD,GAAK,YAAc,EACzC,KAAM,CAAE,IAAKZ,EAAQ,OAAAM,CAAO,CAC9B,CAAC,CACH,EAEA,OAAAI,EAAI,GAAG,WAAaE,GAAa,CAG/BA,EAAI,KAAK,MAAO,IAAMD,EAAYC,CAAG,CAAC,CAGxC,CAAC,EAEDF,EAAI,GAAG,QAAUK,GAAe,CAC9BJ,EAAY,KAAMI,CAAG,CACvB,CAAC,EAEML,CACT,EAGFvB,EAAQ6B,EAAM,UAAWnB,CAAc,EACvCV,EAAQ6B,EAAM,MAAOnB,CAAc,EACnCV,EAAQ8B,EAAO,UAAWpB,CAAc,EACxCV,EAAQ8B,EAAO,MAAOpB,CAAc,CACtC,ECxFO,IAAMqB,EAAkB,CAACC,EAAQ,KAAU,CAChD,GAAI,CAIF,IAAMC,EADU,EAAQ,SAAS,EACN,WAEvBD,GAAO,QAAQ,IAAI,mCAAmC,EAG1D,IAAME,EAAiB,CACrB,YAAa,aAAc,YAAa,aACxC,aAAc,YAAa,aAAc,QAAS,iBAClD,yBAA0B,UAC5B,EAGMC,EAAgB,CAAC,OAAQ,WAAW,EAG1CD,EAAe,QAASE,GAAW,CACjC,GAAI,CAACH,EAAW,UAAUG,CAAM,EAAG,OACnC,IAAMC,EAAWJ,EAAW,UAAUG,CAAM,EAE5CH,EAAW,UAAUG,CAAM,EAAI,YAAaE,EAAa,CACvD,IAAMC,EAAQC,EAAQ,QAAQ,EAC9B,GAAI,CAACD,EAAO,OAAOF,EAAS,MAAM,KAAMC,CAAI,EAE5C,IAAMG,EAAY,YAAY,IAAI,EAAIF,EAAM,UACtCG,EAAe,YAAY,IAAI,EAC/BC,EAAiB,KAAK,eAEtBC,EAAWC,GAAgB,CAC/B,IAAMC,EAAW,YAAY,IAAI,EAAIJ,EACrCF,EAAQ,QAAQ,CACd,KAAM,WAAWJ,CAAM,KAAKO,CAAc,IAC1C,KAAM,KACN,UAAAF,EACA,SAAAK,EACA,OAAQD,EAAM,IAAM,EACpB,KAAM,CAAE,WAAYF,EAAgB,UAAWP,CAAO,CACxD,CAAC,EACGJ,GAAO,QAAQ,IAAI,iCAAiCI,CAAM,EAAE,CAClE,EAEA,GAAI,CACF,IAAMW,EAASV,EAAS,MAAM,KAAMC,CAAI,EACxC,OAAIS,GAAU,OAAOA,EAAO,MAAS,WAC5BA,EAAO,KACXC,IAAeJ,EAAQ,EAAUI,GACjCH,GAAa,CAAE,MAAAD,EAAQC,CAAG,EAASA,CAAK,CAC3C,EAEKE,CACT,OAASF,EAAU,CACjB,MAAAD,EAAQC,CAAG,EACLA,CACR,CACF,CACF,CAAC,EAIDV,EAAc,QAASC,GAAW,CAChC,GAAI,CAACH,EAAW,UAAUG,CAAM,EAAG,OACnC,IAAMC,EAAWJ,EAAW,UAAUG,CAAM,EAE5CH,EAAW,UAAUG,CAAM,EAAI,YAAaE,EAAa,CACvD,IAAMC,EAAQC,EAAQ,QAAQ,EAC9B,GAAI,CAACD,EAAO,OAAOF,EAAS,MAAM,KAAMC,CAAI,EAE5C,IAAMG,EAAY,YAAY,IAAI,EAAIF,EAAM,UAG5C,OAAAC,EAAQ,QAAQ,CACd,KAAM,WAAWJ,CAAM,KAAK,KAAK,cAAc,IAC/C,KAAM,KACN,UAAAK,EACA,SAAU,EACV,OAAQ,EACR,KAAM,CAAE,WAAY,KAAK,eAAgB,UAAWL,CAAO,CAC7D,CAAC,EAEGJ,GAAO,QAAQ,IAAI,mCAAmCI,CAAM,EAAE,EAE3DC,EAAS,MAAM,KAAMC,CAAI,CAClC,CACF,CAAC,CAEH,OAASW,EAAQ,CACXjB,GAAO,QAAQ,KAAK,4CAA6CiB,EAAE,OAAO,CAChF,CACF,EC3FO,IAAMC,EAAe,IAAM,CAChC,GAAI,CAEF,IAAMC,EAAK,EAAQ,IAAI,EACjBC,EAAgBD,EAAG,OAAO,UAAU,MAE1CA,EAAG,OAAO,UAAU,MAAQ,YAAaE,EAAa,CACpD,IAAMC,EAAQC,EAAQ,QAAQ,EAC9B,GAAI,CAACD,EAAO,OAAOF,EAAc,MAAM,KAAMC,CAAI,EAEjD,IAAMG,EAAY,YAAY,IAAI,EAAIF,EAAM,UACtCG,EAAe,YAAY,IAAI,EAG/BC,EAAM,OAAOL,EAAK,CAAC,GAAM,SAAWA,EAAK,CAAC,EAAIA,EAAK,CAAC,EAAE,KAGtDM,EAASP,EAAc,MAAM,KAAMC,CAAI,EAE7C,OAAIM,GAAU,OAAOA,EAAO,MAAS,WAC5BA,EAAO,KAAMC,GAAa,CAC/B,IAAMC,EAAW,YAAY,IAAI,EAAIJ,EACrC,OAAAF,EAAQ,QAAQ,CACd,KAAM,iBACN,KAAM,KACN,UAAAC,EACA,SAAAK,EACA,KAAM,CAAE,MAAOH,CAAI,CACrB,CAAC,EACME,CACT,CAAC,EAEID,CACT,CACF,MAAY,CAEZ,CACF,EHhCO,IAAMG,EAAN,KAAmB,CAAnB,cACL,KAAQ,UAA8B,KACtC,KAAQ,QAAgC,KACxC,KAAQ,eAAiB,GAElB,KAAKC,EAAwB,CAClC,GAAI,CAACA,EAAQ,OAAQ,CACnB,QAAQ,KAAK,yCAAyC,EACtD,MACF,CACA,KAAK,QAAUA,EACf,IAAMC,EAAWD,EAAQ,UAAY,wCAC/BE,EAAQF,EAAQ,OAAS,GAO/B,GALA,KAAK,UAAY,IAAIG,EAAU,CAC7B,GAAGH,EACH,SAAAC,CACF,CAAC,EAEG,CAAC,KAAK,eAAgB,CACxB,GAAI,CAAEG,EAAeH,EAAUC,CAAK,CAAG,MAAY,CAAE,CACrD,GAAI,CAAEG,EAAgBH,CAAK,CAAG,MAAY,CAAE,CAC5C,GAAI,CAAEI,EAAa,CAAG,MAAY,CAAE,CAEpC,KAAK,eAAiB,GAClBJ,GAAO,QAAQ,IAAI,uCAAuC,CAChE,CACF,CAIO,WAAcK,EAAoCC,EAAkB,CACzE,GAAI,CAAC,KAAK,UAAW,OAAOA,EAAK,EAEjC,IAAMC,EAAqB,CACzB,GAAIC,EAAW,EACf,UAAW,YAAY,IAAI,EAC3B,KAAMH,EACN,MAAO,CAAC,CACV,EACA,OAAOI,EAAQ,IAAIF,EAAOD,CAAI,CAChC,CAEO,SAASI,EAAgBC,EAAiB,CAAC,EAAG,CACnD,IAAMJ,EAAQE,EAAQ,QAAQ,EAC9B,GAAI,CAACF,GAAS,CAAC,KAAK,UAAW,OAE/B,IAAMK,EAAW,YAAY,IAAI,EAAIL,EAAM,UAErCM,EAAU,CACd,QAASN,EAAM,GACf,GAAGA,EAAM,KACT,GAAGI,EACH,OAAAD,EACA,SAAAE,EACA,MAAOL,EAAM,MACb,UAAW,IAAI,KAAK,EAAE,YAAY,CACpC,EAEI,KAAK,SAAS,OAAO,QAAQ,IAAI,wBAAwBA,EAAM,EAAE,SAASA,EAAM,MAAM,MAAM,QAAQ,EAExG,KAAK,UAAU,IAAIM,CAAO,CAC5B,CAGO,MAAMR,EAQV,CACD,GAAI,CAAC,KAAK,UAAW,OACrB,IAAMQ,EAAU,CACd,QAASL,EAAW,EACpB,GAAGH,EACH,MAAO,CAAC,EACR,UAAW,IAAI,KAAK,EAAE,YAAY,CACpC,EACA,KAAK,UAAU,IAAIQ,CAAO,CAC5B,CAEO,UAAUC,EAAcC,EAA8C,SAAU,CACrF,IAAMR,EAAQE,EAAQ,QAAQ,EAC9B,GAAI,CAACF,EAAO,MAAO,CAAE,IAAK,IAAM,CAAE,CAAE,EAEpC,IAAMS,EAAY,YAAY,IAAI,EAAIT,EAAM,UACtCU,EAAe,YAAY,IAAI,EAErC,MAAO,CACL,IAAK,CAACC,EAAYR,IAAoB,CACpC,IAAME,EAAW,YAAY,IAAI,EAAIK,EACrCR,EAAQ,QAAQ,CACd,KAAAK,EACA,KAAAC,EACA,UAAAC,EACA,SAAAJ,EACA,OAAAF,EACA,KAAAQ,CACF,CAAC,CACH,CACF,CACF,CAEA,MAAa,OAAQ,CACf,KAAK,WAAW,MAAM,KAAK,UAAU,MAAM,CACjD,CACF,EAEaC,EAAS,IAAItB,EIrHnB,IAAMuB,EAAoB,IACxB,CAACC,EAAUC,EAAUC,IAAqB,CAE/CC,EAAO,WAAW,CAChB,OAAQH,EAAI,OACZ,KAAMA,EAAI,aAAeA,EAAI,IAC7B,GAAIA,EAAI,IAAMA,EAAI,QAAQ,cAC1B,UAAWA,EAAI,QAAQ,YAAY,CACrC,EAAG,IAAM,CAEPC,EAAI,KAAK,SAAU,IAAM,CACvB,GAAI,CACF,IAAIG,EAAQ,UACRJ,EAAI,OAASA,EAAI,MAAM,KACzBI,GAASJ,EAAI,SAAW,IAAMA,EAAI,MAAM,KAC/BC,EAAI,aAAe,IAC5BG,EAAQ,YAERA,EAAQJ,EAAI,MAAQ,WAGtBG,EAAO,SAASF,EAAI,WAAY,CAAE,MAAAG,CAAM,CAAC,CAC3C,MAAY,CAEZ,CACF,CAAC,EAEDF,EAAK,CACP,CAAC,CACH,EC1BK,IAAMG,EAAiBC,GACxB,CAACA,GAAQA,IAAS,IAAY,IAE3BA,EAEJ,QACC,+EACA,OACF,EAEC,QAAQ,mBAAoB,WAAW,EAEvC,QAAQ,mBAAoB,MAAM,EAElC,MAAM,GAAG,EAAE,CAAC,EAMJC,EAAW,CAACC,EAAUC,IAE7BD,EAAI,OAASA,EAAI,MAAM,MACjBA,EAAI,SAAW,IAAMA,EAAI,MAAM,KAIrCA,EAAI,SAAWA,EAAI,QAAQ,aACtBA,EAAI,QAAQ,aAAa,KAI9BA,EAAI,WACCA,EAAI,WAINH,EAAcI,CAAY,ECpC5B,IAAMC,EAAUC,GACbC,GAAe,CACrB,IAAMC,EAAMD,EAAM,KAAK,IACjBE,EAAOD,EAAI,aAAeA,EAAI,KAAO,IAG3C,OAAOE,EAAO,WAAW,CACvB,OAAQF,EAAI,QAAU,MACtB,KAAMC,EACN,GAAID,EAAI,QAAQ,iBAAiB,GAAKA,EAAI,QAAQ,cAClD,UAAWA,EAAI,QAAQ,YAAY,CACrC,EAAG,SAAY,CACb,GAAI,CACF,IAAMG,EAAW,MAAML,EAAQC,CAAK,EAGhCK,EAAS,IACb,OAAIL,EAAM,KAAK,IAAI,aAAYK,EAASL,EAAM,KAAK,IAAI,YAEnDI,GAAYA,EAAS,aAAYC,EAASD,EAAS,YAEvDD,EAAO,SAASE,EAAQ,CAAE,MAAOC,EAASN,EAAOE,CAAI,CAAE,CAAC,EACjDE,CACT,OAASG,EAAU,CACjB,IAAMF,EAASE,EAAI,YAAcA,EAAI,QAAU,IAC/C,MAAAJ,EAAO,SAASE,EAAQ,CAAE,MAAOC,EAASN,EAAOE,CAAI,CAAE,CAAC,EAClDK,CACR,CACF,CAAC,CACH,EC/BK,IAAMC,EAAiBC,GACrB,MAAOC,EAAoBC,IAAkB,CAElD,IAAMC,EAAMF,EAAI,IAAM,IAAI,IAAIA,EAAI,GAAG,EAAI,CAAE,SAAU,GAAI,EACnDG,EAASH,EAAI,QAAU,MACvBI,EAAKJ,EAAI,QAAQ,IAAMA,EAAI,QAAQ,IAAI,YAAY,EAAI,OACvDK,EAAKL,EAAI,QAAQ,IAAMA,EAAI,QAAQ,IAAI,iBAAiB,EAAI,OAGlE,OAAOM,EAAO,WAAW,CACvB,OAAAH,EACA,KAAMD,EAAI,SACV,UAAWE,EACX,GAAIC,CACN,EAAG,SAAY,CACb,GAAI,CACF,IAAME,EAAW,MAAMR,EAAQC,EAAKC,CAAO,EACrCO,EAASD,GAAU,QAAU,IAEnC,OAAAD,EAAO,SAASE,EAAQ,CAAE,MAAOC,EAAcP,EAAI,QAAQ,CAAE,CAAC,EACvDK,CACT,OAASG,EAAU,CACjB,MAAAJ,EAAO,SAAS,IAAK,CAAE,MAAOG,EAAcP,EAAI,QAAQ,CAAE,CAAC,EACrDQ,CACR,CACF,CAAC,CACH,EAIWC,EAAiBZ,GACrB,MAAOC,EAAUY,IAAa,CACnC,IAAMC,EAAOb,EAAI,IAAMA,EAAI,IAAI,MAAM,GAAG,EAAE,CAAC,EAAI,IAG/C,OAAOM,EAAO,WAAW,CACvB,OAAQN,EAAI,QAAU,MACtB,KAAMa,EACN,UAAWb,EAAI,QAAQ,YAAY,EACnC,GAAIA,EAAI,QAAQ,iBAAiB,GAAKA,EAAI,QAAQ,aACpD,EAAG,SAAY,CAGb,IAAMc,EAAO,IAAM,CACjBR,EAAO,SAASM,EAAI,YAAc,IAAK,CAAE,MAAOH,EAAcI,CAAI,CAAE,CAAC,CACvE,EAEAD,EAAI,KAAK,SAAUE,CAAI,EACvBF,EAAI,KAAK,QAASE,CAAI,EAGtB,GAAI,CACF,OAAO,MAAMf,EAAQC,EAAKY,CAAG,CAC/B,OAASG,EAAG,CAGV,MAAMA,CACR,CACF,CAAC,CACH,EC3DK,IAAMC,EAAe,CAACC,EAAcC,EAAwBC,IAAmB,CAGhFD,GAAWA,EAAQ,QACrBE,EAAO,KAAKF,CAAO,EAIrBD,EAAQ,QAAQ,YAAa,CAACI,EAAcC,EAAYC,IAAmB,CACzEF,EAAQ,YAAc,YAAY,IAAI,EACtCE,EAAK,CACP,CAAC,EAGDN,EAAQ,QAAQ,aAAc,CAACI,EAAcC,EAAYC,IAAmB,CAC1E,IAAMC,EAAW,YAAY,IAAI,GAAKH,EAAQ,aAAe,YAAY,IAAI,GAGvEI,EAAQJ,EAAQ,cAAc,KAAOA,EAAQ,WAEnDD,EAAO,MAAM,CACX,OAAQC,EAAQ,OAChB,MAAOI,GAAS,UAChB,KAAMJ,EAAQ,IAAI,KAAOA,EAAQ,IACjC,OAAQC,EAAM,WACd,SAAUE,EACV,GAAIH,EAAQ,GACZ,UAAWA,EAAQ,QAAQ,YAAY,CACzC,CAAC,EAEDE,EAAK,CACP,CAAC,EAEDJ,EAAK,CACP,EC/BA,IAAMO,EAAS,CAEb,KAAOC,GAA2BC,EAAO,KAAKD,CAAO,EACrD,MAAO,IAAMC,EAAO,MAAM,EAG1B,eAAgBC,EAGhB,cAAAC,EACA,cAAAC,EAGA,OAAAC,EAGA,cAAeC,CACjB,EAEOC,GAAQR","names":["Transport","config","trace","batch","err","AsyncLocalStorage","storage","Context","trace","fn","span","store","randomUUID","http","https","URL","shimmer","module","methodName","wrapper","original","instrumentHttp","ingestUrl","debug","ingestHost","URL","requestWrapper","args","options","urlStr","protocol","host","path","trace","Context","method","startTime","spanStartAbs","hostname","req","captureSpan","res","error","duration","err","http","https","instrumentMongo","debug","Collection","promiseMethods","cursorMethods","method","original","args","trace","Context","startTime","spanStartAbs","collectionName","endSpan","err","duration","result","res","e","instrumentPg","pg","originalQuery","args","trace","Context","startTime","spanStartAbs","sql","result","res","duration","SenzorClient","options","endpoint","debug","Transport","instrumentHttp","instrumentMongo","instrumentPg","data","next","trace","randomUUID","Context","status","extraData","duration","payload","name","type","startTime","spanStartAbs","meta","client","expressMiddleware","req","res","next","client","route","normalizePath","path","getRoute","req","fallbackPath","wrapH3","handler","event","req","path","client","response","status","getRoute","err","wrapNextRoute","handler","req","context","url","method","ua","ip","client","response","status","normalizePath","err","wrapNextPages","res","path","done","e","senzorPlugin","fastify","options","done","client","request","reply","next","duration","route","Senzor","options","client","expressMiddleware","wrapNextRoute","wrapNextPages","wrapH3","senzorPlugin","index_default"]}
1
+ {"version":3,"sources":["../src/core/transport.ts","../src/core/context.ts","../src/core/client.ts","../src/instrumentation/http.ts","../src/instrumentation/mongo.ts","../src/instrumentation/pg.ts","../src/middleware/express.ts","../src/core/normalizer.ts","../src/wrappers/h3.ts","../src/wrappers/next.ts","../src/wrappers/fastify.ts","../src/index.ts"],"sourcesContent":["import { SenzorOptions } from './types';\r\n\r\nexport class Transport {\r\n private queue: any[] = [];\r\n private timer: NodeJS.Timeout | null = null;\r\n\r\n constructor(private config: SenzorOptions) {\r\n if (typeof setInterval !== 'undefined') {\r\n this.timer = setInterval(() => this.flush(), config.flushInterval || 10000);\r\n if (this.timer && typeof this.timer.unref === 'function') {\r\n this.timer.unref(); // Don't block process exit\r\n }\r\n }\r\n }\r\n\r\n public add(trace: any) {\r\n this.queue.push(trace);\r\n if (this.queue.length >= (this.config.batchSize || 100)) {\r\n this.flush();\r\n }\r\n }\r\n\r\n public async flush() {\r\n if (this.queue.length === 0) return;\r\n\r\n const batch = [...this.queue];\r\n this.queue = [];\r\n\r\n try {\r\n // Use global fetch (Node 18+)\r\n await fetch(this.config.endpoint || 'https://api.senzor.dev/api/ingest/apm', {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n 'x-service-api-key': this.config.apiKey,\r\n },\r\n body: JSON.stringify(batch),\r\n keepalive: true,\r\n });\r\n \r\n if (this.config.debug) console.log(`[Senzor] Flushed ${batch.length} traces`);\r\n } catch (err) {\r\n if (this.config.debug) console.error('[Senzor] Ingestion Error:', err);\r\n // Dropping data to prevent memory leaks is preferred in APM\r\n }\r\n }\r\n}","import { AsyncLocalStorage } from 'async_hooks';\r\nimport { ActiveTrace } 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 } else {\r\n // If we are here, something tried to add a span but lost context\r\n // This is common if users await inside a callback that wasn't bound\r\n // However, usually silent failure is preferred in production APM\r\n console.warn('[Senzor] Lost context for span:', span.name);\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'; // Import both\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({\r\n ...options,\r\n endpoint\r\n });\r\n\r\n // --- ENABLE AUTO INSTRUMENTATION ---\r\n if (!this.isInstrumented) {\r\n try { instrumentHttp(endpoint, debug); } catch (e) { }\r\n try { instrumentFetch(endpoint, debug); } catch (e) { } // NEW: Fetch Support\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 (HTTP, Fetch, Mongo)');\r\n }\r\n }\r\n\r\n // ... (Rest of file same as before: startTrace, endTrace, track, etc.) ...\r\n public startTrace<T>(data: Partial<ActiveTrace['data']>, next: () => T): T {\r\n if (!this.transport) return next();\r\n const trace: ActiveTrace = { id: randomUUID(), startTime: performance.now(), data: data, spans: [] };\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 const payload = { traceId: trace.id, ...trace.data, ...extraData, status, duration, spans: trace.spans, timestamp: new Date().toISOString() };\r\n this.transport.add(payload);\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 return { end: (meta?: any, status?: number) => { Context.addSpan({ name, type, startTime, duration: performance.now() - spanStartAbs, status, meta }); } };\r\n }\r\n\r\n public async flush() { if (this.transport) await this.transport.flush(); }\r\n}\r\n\r\nexport const client = new SenzorClient();","import http from 'http';\r\nimport https from 'https';\r\nimport { URL } from 'url';\r\nimport { Context } from '../core/context';\r\n\r\nconst shimmer = (module: any, methodName: string, wrapper: (original: Function) => Function) => {\r\n if (!module[methodName]) return;\r\n const original = module[methodName];\r\n module[methodName] = wrapper(original);\r\n};\r\n\r\n// --- Native Fetch Instrumentation (Node 18+) ---\r\nexport const instrumentFetch = (ingestUrl: string, debug = false) => {\r\n if (!globalThis.fetch) return;\r\n\r\n let ingestHost = '';\r\n try { ingestHost = new URL(ingestUrl).hostname; } catch (e) { }\r\n\r\n const originalFetch = globalThis.fetch;\r\n\r\n // @ts-ignore\r\n globalThis.fetch = async (input: RequestInfo | URL, init?: RequestInit) => {\r\n // 1. Extract URL\r\n let urlStr = '';\r\n if (typeof input === 'string') urlStr = input;\r\n else if (input instanceof URL) urlStr = input.toString();\r\n else if (input && input.url) urlStr = input.url; // Request object\r\n\r\n // 2. Infinite Loop Guard\r\n if (ingestHost && urlStr.includes(ingestHost)) {\r\n return originalFetch(input, init);\r\n }\r\n\r\n // 3. Context Check\r\n const trace = Context.current();\r\n if (!trace) {\r\n return originalFetch(input, init);\r\n }\r\n\r\n // 4. Start Span\r\n const method = (init?.method || 'GET').toUpperCase();\r\n const startTime = performance.now() - trace.startTime;\r\n const spanStartAbs = performance.now();\r\n let hostname = 'unknown';\r\n try { hostname = new URL(urlStr).hostname; } catch (e) { }\r\n\r\n if (debug) console.log(`[Senzor] Tracking Fetch: ${method} ${hostname}`);\r\n\r\n try {\r\n const response = await originalFetch(input, init);\r\n\r\n // 5. End Span\r\n const duration = performance.now() - spanStartAbs;\r\n Context.addSpan({\r\n name: `${method} ${hostname}`,\r\n type: 'http',\r\n startTime,\r\n duration,\r\n status: response.status,\r\n meta: { url: urlStr, method, library: 'fetch' }\r\n });\r\n\r\n return response;\r\n } catch (err: any) {\r\n const duration = performance.now() - spanStartAbs;\r\n Context.addSpan({\r\n name: `${method} ${hostname}`,\r\n type: 'http',\r\n startTime,\r\n duration,\r\n status: 500,\r\n meta: { error: err.message, url: urlStr, library: 'fetch' }\r\n });\r\n throw err;\r\n }\r\n };\r\n};\r\n\r\n// --- Standard HTTP/HTTPS Instrumentation ---\r\nexport const instrumentHttp = (ingestUrl: string, debug = false) => {\r\n let ingestHost = '';\r\n try {\r\n ingestHost = new URL(ingestUrl).hostname;\r\n } catch (e) { }\r\n\r\n const requestWrapper = (original: Function) => {\r\n return function (this: any, ...args: any[]) {\r\n let options: any = {};\r\n let urlStr = '';\r\n\r\n if (typeof args[0] === 'string' || args[0] instanceof URL) {\r\n urlStr = args[0].toString();\r\n if (typeof args[1] === 'object' && args[1] !== null) options = args[1];\r\n } else {\r\n options = args[0] || {};\r\n const protocol = options.protocol || (options.port === 443 ? 'https:' : 'http:');\r\n const host = options.hostname || options.host || 'localhost';\r\n const path = options.path || '/';\r\n urlStr = `${protocol}//${host}${path}`;\r\n }\r\n\r\n if (ingestHost && (urlStr.includes(ingestHost) || (options.hostname && options.hostname.includes(ingestHost)))) {\r\n return original.apply(this, args);\r\n }\r\n\r\n const trace = Context.current();\r\n if (!trace) return original.apply(this, args);\r\n\r\n const method = (options.method || 'GET').toUpperCase();\r\n const startTime = performance.now() - trace.startTime;\r\n const spanStartAbs = performance.now();\r\n let hostname = 'unknown';\r\n try { hostname = new URL(urlStr).hostname; } catch (e) { hostname = options.hostname || 'unknown'; }\r\n\r\n const req = original.apply(this, args);\r\n\r\n const captureSpan = (res: any, error?: Error) => {\r\n const duration = performance.now() - spanStartAbs;\r\n Context.addSpan({\r\n name: `${method} ${hostname}`,\r\n type: 'http',\r\n startTime,\r\n duration,\r\n status: error ? 500 : res?.statusCode || 0,\r\n meta: { url: urlStr, method, library: 'http' }\r\n });\r\n };\r\n\r\n req.on('response', (res: any) => {\r\n res.once('end', () => captureSpan(res));\r\n res.once('error', (err: Error) => captureSpan(res, err));\r\n });\r\n\r\n req.on('error', (err: Error) => captureSpan(null, err));\r\n\r\n return req;\r\n };\r\n };\r\n\r\n shimmer(http, 'request', requestWrapper);\r\n shimmer(http, 'get', requestWrapper);\r\n shimmer(https, 'request', requestWrapper);\r\n shimmer(https, 'get', requestWrapper);\r\n};","import { Context } from '../core/context';\r\n\r\nexport const instrumentMongo = (debug = false) => {\r\n try {\r\n const mongodb = require('mongodb');\r\n const Collection = mongodb.Collection;\r\n\r\n // Attempt to get Cursor classes\r\n // Note: The location of these classes varies by driver version, \r\n // checking common locations\r\n const FindCursor = mongodb.FindCursor || require('mongodb/lib/cursor/find_cursor').FindCursor;\r\n const AggregationCursor = mongodb.AggregationCursor || require('mongodb/lib/cursor/aggregation_cursor').AggregationCursor;\r\n\r\n if (debug) console.log('[Senzor] Instrumenting MongoDB (Collection + Cursors)...');\r\n\r\n // --- Helper to Record Span ---\r\n const recordSpan = (name: string, operation: string, collection: string, startAbs: number, traceStart: number, err?: Error) => {\r\n const duration = performance.now() - startAbs;\r\n Context.addSpan({\r\n name: `MongoDB ${name}`,\r\n type: 'db',\r\n startTime: performance.now() - traceStart - duration, // Adjust start time to when op actually started\r\n duration,\r\n status: err ? 500 : 0,\r\n meta: { collection, operation, error: err ? err.message : undefined }\r\n });\r\n if (debug) console.log(`[Senzor] Captured Mongo: ${name} (${duration.toFixed(2)}ms)`);\r\n };\r\n\r\n // --- 1. Instrument Immediate Operations (Insert/Update/Delete) ---\r\n const immediateMethods = ['insertOne', 'insertMany', 'updateOne', 'updateMany', 'deleteOne', 'deleteMany', 'countDocuments'];\r\n\r\n immediateMethods.forEach((method) => {\r\n if (!Collection.prototype[method]) return;\r\n const original = Collection.prototype[method];\r\n\r\n Collection.prototype[method] = function (...args: any[]) {\r\n const trace = Context.current();\r\n if (!trace) return original.apply(this, args);\r\n\r\n const spanStartAbs = performance.now();\r\n const traceStart = trace.startTime;\r\n const collName = this.collectionName;\r\n\r\n try {\r\n const result = original.apply(this, args);\r\n if (result && typeof result.then === 'function') {\r\n return result.then(\r\n (res: any) => { recordSpan(method, method, collName, spanStartAbs, traceStart); return res; },\r\n (err: any) => { recordSpan(method, method, collName, spanStartAbs, traceStart, err); throw err; }\r\n );\r\n }\r\n return result;\r\n } catch (err: any) {\r\n recordSpan(method, method, collName, spanStartAbs, traceStart, err);\r\n throw err;\r\n }\r\n };\r\n });\r\n\r\n // --- 2. Instrument Cursor Execution (find -> toArray) ---\r\n const patchCursor = (CursorClass: any, label: string) => {\r\n if (!CursorClass || !CursorClass.prototype.toArray) return;\r\n\r\n const originalToArray = CursorClass.prototype.toArray;\r\n\r\n CursorClass.prototype.toArray = function (...args: any[]) {\r\n const trace = Context.current();\r\n // Cursors are often created in context but executed later. \r\n // We check context at execution time.\r\n if (!trace) return originalToArray.apply(this, args);\r\n\r\n const spanStartAbs = performance.now();\r\n const traceStart = trace.startTime;\r\n // Attempt to get collection name from cursor internal state\r\n const collName = this.namespace?.collection || 'unknown';\r\n\r\n const onSuccess = (res: any) => {\r\n recordSpan(label, label, collName, spanStartAbs, traceStart);\r\n return res;\r\n };\r\n const onError = (err: any) => {\r\n recordSpan(label, label, collName, spanStartAbs, traceStart, err);\r\n throw err;\r\n };\r\n\r\n try {\r\n const result = originalToArray.apply(this, args);\r\n if (result && typeof result.then === 'function') {\r\n return result.then(onSuccess, onError);\r\n }\r\n return onSuccess(result);\r\n } catch (e) {\r\n onError(e);\r\n }\r\n };\r\n };\r\n\r\n patchCursor(FindCursor, 'find');\r\n patchCursor(AggregationCursor, 'aggregate');\r\n\r\n } catch (e: any) {\r\n if (debug) console.warn('[Senzor] MongoDB instrumentation warning:', e.message);\r\n }\r\n};","import { Context } from '../core/context';\r\n\r\n// Simple shim for 'pg' library\r\nexport const instrumentPg = () => {\r\n try {\r\n // Try to require pg (it might not be installed by user)\r\n const pg = require('pg');\r\n const originalQuery = pg.Client.prototype.query;\r\n\r\n pg.Client.prototype.query = function (...args: any[]) {\r\n const trace = Context.current();\r\n if (!trace) return originalQuery.apply(this, args);\r\n\r\n const startTime = performance.now() - trace.startTime;\r\n const spanStartAbs = performance.now();\r\n\r\n // Extract SQL (first arg usually string or config object)\r\n const sql = typeof args[0] === 'string' ? args[0] : args[0].text;\r\n\r\n // Wrap callback if present, or handle Promise\r\n const result = originalQuery.apply(this, args);\r\n\r\n if (result && typeof result.then === 'function') {\r\n return result.then((res: any) => {\r\n const duration = performance.now() - spanStartAbs;\r\n Context.addSpan({\r\n name: 'Postgres Query',\r\n type: 'db',\r\n startTime,\r\n duration,\r\n meta: { query: sql }\r\n });\r\n return res;\r\n });\r\n }\r\n return result;\r\n };\r\n } catch (e) {\r\n // User doesn't use pg, ignore\r\n }\r\n};","import { client } from '../core/client';\r\n\r\nexport const expressMiddleware = () => {\r\n return (req: any, res: any, next: () => void) => {\r\n // We MUST use startTrace to enable Auto-Instrumentation for this request\r\n client.startTrace({\r\n method: req.method,\r\n path: req.originalUrl || req.url,\r\n ip: req.ip || req.socket?.remoteAddress,\r\n userAgent: req.headers['user-agent'],\r\n }, () => {\r\n\r\n res.once('finish', () => {\r\n try {\r\n let route = 'UNKNOWN';\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) {\r\n // Fail open\r\n }\r\n });\r\n\r\n next();\r\n });\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\n// Minimal types for H3 to avoid peer-deps\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 // Start Trace Context\r\n return client.startTrace({\r\n method: req.method || 'GET',\r\n path: path,\r\n ip: req.headers['x-forwarded-for'] || req.socket?.remoteAddress,\r\n userAgent: req.headers['user-agent'],\r\n }, async () => {\r\n try {\r\n const response = await handler(event);\r\n\r\n // H3/Nitro response status\r\n let status = 200;\r\n if (event.node.res.statusCode) status = event.node.res.statusCode;\r\n // Check if response is an error object\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 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 (Route Handlers) ---\r\nexport const wrapNextRoute = (handler: Function) => {\r\n return async (req: Request | any, context?: any) => {\r\n // 1. Extract Info\r\n const url = req.url ? new URL(req.url) : { pathname: '/' };\r\n const method = req.method || 'GET';\r\n const ua = req.headers.get ? req.headers.get('user-agent') : undefined;\r\n const ip = req.headers.get ? req.headers.get('x-forwarded-for') : undefined;\r\n\r\n // 2. Run in Context\r\n return client.startTrace({\r\n method,\r\n path: url.pathname,\r\n userAgent: ua,\r\n ip: ip\r\n }, async () => {\r\n try {\r\n const response = await handler(req, context);\r\n const status = response?.status || 200;\r\n \r\n client.endTrace(status, { route: normalizePath(url.pathname) });\r\n return response;\r\n } catch (err: any) {\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 (API Routes) ---\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 // 1. Run in Context\r\n return client.startTrace({\r\n method: req.method || 'GET',\r\n path: path,\r\n userAgent: req.headers['user-agent'],\r\n ip: req.headers['x-forwarded-for'] || req.socket?.remoteAddress,\r\n }, async () => {\r\n \r\n // 2. Hook Response\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); // Fallback if finish doesn't fire\r\n\r\n // 3. Execute\r\n try {\r\n return await handler(req, res);\r\n } catch (e) {\r\n // Next.js Pages router usually handles errors internally, \r\n // but we ensure we catch sync errors here\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\n// We don't import Fastify types to keep zero-deps, but structure matches\r\nexport const senzorPlugin = (fastify: any, options: SenzorOptions, done: Function) => {\r\n\r\n // Init if options provided inline, otherwise assume global init\r\n if (options && options.apiKey) {\r\n client.init(options);\r\n }\r\n\r\n // Hook: On Request (Start Timer)\r\n fastify.addHook('onRequest', (request: any, reply: any, next: Function) => {\r\n request.senzorStart = performance.now();\r\n next();\r\n });\r\n\r\n // Hook: On Response (End Timer & Track)\r\n fastify.addHook('onResponse', (request: any, reply: any, next: Function) => {\r\n const duration = performance.now() - (request.senzorStart || performance.now());\r\n\r\n // Fastify provides 'routerPath' (e.g. /user/:id)\r\n const route = request.routeOptions?.url || request.routerPath;\r\n\r\n client.track({\r\n method: request.method,\r\n route: route || 'UNKNOWN',\r\n path: request.raw.url || request.url,\r\n status: reply.statusCode,\r\n duration: duration,\r\n ip: request.ip,\r\n userAgent: request.headers['user-agent']\r\n });\r\n\r\n next();\r\n });\r\n\r\n done();\r\n};","import { client } from './core/client';\r\nimport { expressMiddleware } 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 // Core\r\n init: (options: SenzorOptions) => client.init(options),\r\n flush: () => client.flush(),\r\n\r\n // Express / Connect\r\n requestHandler: expressMiddleware,\r\n\r\n // Next.js\r\n wrapNextRoute, // For App Router (Route Handlers)\r\n wrapNextPages, // For Pages Router (API Routes)\r\n\r\n // H3 / Nuxt / Nitro\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","randomUUID","http","https","URL","shimmer","module","methodName","wrapper","original","instrumentFetch","ingestUrl","debug","ingestHost","URL","originalFetch","input","init","urlStr","trace","Context","method","startTime","spanStartAbs","hostname","response","duration","err","instrumentHttp","requestWrapper","args","options","protocol","host","path","req","captureSpan","res","error","http","https","instrumentMongo","debug","mongodb","Collection","FindCursor","AggregationCursor","recordSpan","name","operation","collection","startAbs","traceStart","err","duration","Context","method","original","args","trace","spanStartAbs","collName","result","res","patchCursor","CursorClass","label","originalToArray","onSuccess","onError","e","instrumentPg","pg","originalQuery","args","trace","Context","startTime","spanStartAbs","sql","result","res","duration","SenzorClient","options","endpoint","debug","Transport","instrumentHttp","instrumentFetch","instrumentMongo","instrumentPg","data","next","trace","randomUUID","Context","status","extraData","duration","payload","name","type","startTime","spanStartAbs","meta","client","expressMiddleware","req","res","next","client","route","normalizePath","path","getRoute","req","fallbackPath","wrapH3","handler","event","req","path","client","response","status","getRoute","err","wrapNextRoute","handler","req","context","url","method","ua","ip","client","response","status","normalizePath","err","wrapNextPages","res","path","done","e","senzorPlugin","fastify","options","done","client","request","reply","next","duration","route","Senzor","options","client","expressMiddleware","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.2",
3
+ "version": "1.1.3",
4
4
  "description": "Universal APM SDK for Senzor",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -2,7 +2,7 @@ import { Transport } from './transport';
2
2
  import { Context } from './context';
3
3
  import { SenzorOptions, ActiveTrace } from './types';
4
4
  import { randomUUID } from 'crypto';
5
- import { instrumentHttp } from '../instrumentation/http';
5
+ import { instrumentHttp, instrumentFetch } from '../instrumentation/http'; // Import both
6
6
  import { instrumentMongo } from '../instrumentation/mongo';
7
7
  import { instrumentPg } from '../instrumentation/pg';
8
8
 
@@ -25,96 +25,44 @@ export class SenzorClient {
25
25
  endpoint
26
26
  });
27
27
 
28
+ // --- ENABLE AUTO INSTRUMENTATION ---
28
29
  if (!this.isInstrumented) {
29
30
  try { instrumentHttp(endpoint, debug); } catch (e) { }
31
+ try { instrumentFetch(endpoint, debug); } catch (e) { } // NEW: Fetch Support
30
32
  try { instrumentMongo(debug); } catch (e) { }
31
33
  try { instrumentPg(); } catch (e) { }
32
34
 
33
35
  this.isInstrumented = true;
34
- if (debug) console.log('[Senzor] Auto-instrumentation enabled');
36
+ if (debug) console.log('[Senzor] Auto-instrumentation enabled (HTTP, Fetch, Mongo)');
35
37
  }
36
38
  }
37
39
 
38
- // ... (startTrace, endTrace, track, startSpan, flush remain same) ...
39
- // Ensuring startTrace returns T
40
+ // ... (Rest of file same as before: startTrace, endTrace, track, etc.) ...
40
41
  public startTrace<T>(data: Partial<ActiveTrace['data']>, next: () => T): T {
41
42
  if (!this.transport) return next();
42
-
43
- const trace: ActiveTrace = {
44
- id: randomUUID(),
45
- startTime: performance.now(),
46
- data: data,
47
- spans: []
48
- };
43
+ const trace: ActiveTrace = { id: randomUUID(), startTime: performance.now(), data: data, spans: [] };
49
44
  return Context.run(trace, next);
50
45
  }
51
46
 
52
47
  public endTrace(status: number, extraData: any = {}) {
53
48
  const trace = Context.current();
54
49
  if (!trace || !this.transport) return;
55
-
56
50
  const duration = performance.now() - trace.startTime;
57
-
58
- const payload = {
59
- traceId: trace.id,
60
- ...trace.data,
61
- ...extraData,
62
- status,
63
- duration,
64
- spans: trace.spans,
65
- timestamp: new Date().toISOString()
66
- };
67
-
68
- if (this.options?.debug) console.log(`[Senzor] Ended Trace ${trace.id} with ${trace.spans.length} spans`);
69
-
51
+ const payload = { traceId: trace.id, ...trace.data, ...extraData, status, duration, spans: trace.spans, timestamp: new Date().toISOString() };
70
52
  this.transport.add(payload);
71
53
  }
72
54
 
73
- // ... (manual track methods) ...
74
- public track(data: {
75
- method: string;
76
- route: string;
77
- path: string;
78
- status: number;
79
- duration: number;
80
- ip?: string;
81
- userAgent?: string;
82
- }) {
83
- if (!this.transport) return;
84
- const payload = {
85
- traceId: randomUUID(),
86
- ...data,
87
- spans: [],
88
- timestamp: new Date().toISOString()
89
- };
90
- this.transport.add(payload);
91
- }
55
+ public track(data: any) { this.transport?.add({ traceId: randomUUID(), ...data, spans: [], timestamp: new Date().toISOString() }); }
92
56
 
93
57
  public startSpan(name: string, type: 'db' | 'http' | 'function' | 'custom' = 'custom') {
94
58
  const trace = Context.current();
95
59
  if (!trace) return { end: () => { } };
96
-
97
60
  const startTime = performance.now() - trace.startTime;
98
61
  const spanStartAbs = performance.now();
99
-
100
- return {
101
- end: (meta?: any, status?: number) => {
102
- const duration = performance.now() - spanStartAbs;
103
- Context.addSpan({
104
- name,
105
- type,
106
- startTime,
107
- duration,
108
- status,
109
- meta
110
- });
111
- }
112
- };
62
+ return { end: (meta?: any, status?: number) => { Context.addSpan({ name, type, startTime, duration: performance.now() - spanStartAbs, status, meta }); } };
113
63
  }
114
64
 
115
- public async flush() {
116
- if (this.transport) await this.transport.flush();
117
- }
65
+ public async flush() { if (this.transport) await this.transport.flush(); }
118
66
  }
119
67
 
120
68
  export const client = new SenzorClient();
@@ -9,15 +9,79 @@ const shimmer = (module: any, methodName: string, wrapper: (original: Function)
9
9
  module[methodName] = wrapper(original);
10
10
  };
11
11
 
12
+ // --- Native Fetch Instrumentation (Node 18+) ---
13
+ export const instrumentFetch = (ingestUrl: string, debug = false) => {
14
+ if (!globalThis.fetch) return;
15
+
16
+ let ingestHost = '';
17
+ try { ingestHost = new URL(ingestUrl).hostname; } catch (e) { }
18
+
19
+ const originalFetch = globalThis.fetch;
20
+
21
+ // @ts-ignore
22
+ globalThis.fetch = async (input: RequestInfo | URL, init?: RequestInit) => {
23
+ // 1. Extract URL
24
+ let urlStr = '';
25
+ if (typeof input === 'string') urlStr = input;
26
+ else if (input instanceof URL) urlStr = input.toString();
27
+ else if (input && input.url) urlStr = input.url; // Request object
28
+
29
+ // 2. Infinite Loop Guard
30
+ if (ingestHost && urlStr.includes(ingestHost)) {
31
+ return originalFetch(input, init);
32
+ }
33
+
34
+ // 3. Context Check
35
+ const trace = Context.current();
36
+ if (!trace) {
37
+ return originalFetch(input, init);
38
+ }
39
+
40
+ // 4. Start Span
41
+ const method = (init?.method || 'GET').toUpperCase();
42
+ const startTime = performance.now() - trace.startTime;
43
+ const spanStartAbs = performance.now();
44
+ let hostname = 'unknown';
45
+ try { hostname = new URL(urlStr).hostname; } catch (e) { }
46
+
47
+ if (debug) console.log(`[Senzor] Tracking Fetch: ${method} ${hostname}`);
48
+
49
+ try {
50
+ const response = await originalFetch(input, init);
51
+
52
+ // 5. End Span
53
+ const duration = performance.now() - spanStartAbs;
54
+ Context.addSpan({
55
+ name: `${method} ${hostname}`,
56
+ type: 'http',
57
+ startTime,
58
+ duration,
59
+ status: response.status,
60
+ meta: { url: urlStr, method, library: 'fetch' }
61
+ });
62
+
63
+ return response;
64
+ } catch (err: any) {
65
+ const duration = performance.now() - spanStartAbs;
66
+ Context.addSpan({
67
+ name: `${method} ${hostname}`,
68
+ type: 'http',
69
+ startTime,
70
+ duration,
71
+ status: 500,
72
+ meta: { error: err.message, url: urlStr, library: 'fetch' }
73
+ });
74
+ throw err;
75
+ }
76
+ };
77
+ };
78
+
79
+ // --- Standard HTTP/HTTPS Instrumentation ---
12
80
  export const instrumentHttp = (ingestUrl: string, debug = false) => {
13
81
  let ingestHost = '';
14
82
  try {
15
83
  ingestHost = new URL(ingestUrl).hostname;
16
- if (debug) console.log(`[Senzor] HTTP Instrumentation ignoring host: ${ingestHost}`);
17
- } catch (e) {
18
- // If invalid URL passed, we can't filter loop safely, so we might skip instrumentation
19
- if (debug) console.error('[Senzor] Invalid Ingest URL for HTTP instrumentation');
20
- }
84
+ } catch (e) { }
21
85
 
22
86
  const requestWrapper = (original: Function) => {
23
87
  return function (this: any, ...args: any[]) {
@@ -35,16 +99,12 @@ export const instrumentHttp = (ingestUrl: string, debug = false) => {
35
99
  urlStr = `${protocol}//${host}${path}`;
36
100
  }
37
101
 
38
- // Safety Guard: Ignore calls to Senzor Ingest API
39
102
  if (ingestHost && (urlStr.includes(ingestHost) || (options.hostname && options.hostname.includes(ingestHost)))) {
40
103
  return original.apply(this, args);
41
104
  }
42
105
 
43
106
  const trace = Context.current();
44
- if (!trace) {
45
- // Not inside a tracked request
46
- return original.apply(this, args);
47
- }
107
+ if (!trace) return original.apply(this, args);
48
108
 
49
109
  const method = (options.method || 'GET').toUpperCase();
50
110
  const startTime = performance.now() - trace.startTime;
@@ -52,8 +112,6 @@ export const instrumentHttp = (ingestUrl: string, debug = false) => {
52
112
  let hostname = 'unknown';
53
113
  try { hostname = new URL(urlStr).hostname; } catch (e) { hostname = options.hostname || 'unknown'; }
54
114
 
55
- if (debug) console.log(`[Senzor] Tracking HTTP: ${method} ${hostname}`);
56
-
57
115
  const req = original.apply(this, args);
58
116
 
59
117
  const captureSpan = (res: any, error?: Error) => {
@@ -64,21 +122,16 @@ export const instrumentHttp = (ingestUrl: string, debug = false) => {
64
122
  startTime,
65
123
  duration,
66
124
  status: error ? 500 : res?.statusCode || 0,
67
- meta: { url: urlStr, method }
125
+ meta: { url: urlStr, method, library: 'http' }
68
126
  });
69
127
  };
70
128
 
71
129
  req.on('response', (res: any) => {
72
- // We capture on 'response' (headers received) to be safe.
73
- // Waiting for 'end' might miss requests where body isn't consumed.
74
130
  res.once('end', () => captureSpan(res));
75
- // Fallback if 'end' doesn't fire fast enough
76
- // setTimeout(() => captureSpan(res), 5000);
131
+ res.once('error', (err: Error) => captureSpan(res, err));
77
132
  });
78
133
 
79
- req.on('error', (err: Error) => {
80
- captureSpan(null, err);
81
- });
134
+ req.on('error', (err: Error) => captureSpan(null, err));
82
135
 
83
136
  return req;
84
137
  };
@@ -2,25 +2,35 @@ import { Context } from '../core/context';
2
2
 
3
3
  export const instrumentMongo = (debug = false) => {
4
4
  try {
5
- // Attempt to load the user's installed mongodb driver
6
- // This works for both native driver users and Mongoose users (as mongoose depends on this)
7
5
  const mongodb = require('mongodb');
8
6
  const Collection = mongodb.Collection;
9
7
 
10
- if (debug) console.log('[Senzor] Instrumenting MongoDB...');
11
-
12
- // Methods that return Promises
13
- const promiseMethods = [
14
- 'insertOne', 'insertMany', 'updateOne', 'updateMany',
15
- 'replaceOne', 'deleteOne', 'deleteMany', 'count', 'countDocuments',
16
- 'estimatedDocumentCount', 'distinct'
17
- ];
18
-
19
- // Methods that return Cursors (need special handling)
20
- const cursorMethods = ['find', 'aggregate'];
21
-
22
- // 1. Instrument Promise-based methods
23
- promiseMethods.forEach((method) => {
8
+ // Attempt to get Cursor classes
9
+ // Note: The location of these classes varies by driver version,
10
+ // checking common locations
11
+ const FindCursor = mongodb.FindCursor || require('mongodb/lib/cursor/find_cursor').FindCursor;
12
+ const AggregationCursor = mongodb.AggregationCursor || require('mongodb/lib/cursor/aggregation_cursor').AggregationCursor;
13
+
14
+ if (debug) console.log('[Senzor] Instrumenting MongoDB (Collection + Cursors)...');
15
+
16
+ // --- Helper to Record Span ---
17
+ const recordSpan = (name: string, operation: string, collection: string, startAbs: number, traceStart: number, err?: Error) => {
18
+ const duration = performance.now() - startAbs;
19
+ Context.addSpan({
20
+ name: `MongoDB ${name}`,
21
+ type: 'db',
22
+ startTime: performance.now() - traceStart - duration, // Adjust start time to when op actually started
23
+ duration,
24
+ status: err ? 500 : 0,
25
+ meta: { collection, operation, error: err ? err.message : undefined }
26
+ });
27
+ if (debug) console.log(`[Senzor] Captured Mongo: ${name} (${duration.toFixed(2)}ms)`);
28
+ };
29
+
30
+ // --- 1. Instrument Immediate Operations (Insert/Update/Delete) ---
31
+ const immediateMethods = ['insertOne', 'insertMany', 'updateOne', 'updateMany', 'deleteOne', 'deleteMany', 'countDocuments'];
32
+
33
+ immediateMethods.forEach((method) => {
24
34
  if (!Collection.prototype[method]) return;
25
35
  const original = Collection.prototype[method];
26
36
 
@@ -28,68 +38,68 @@ export const instrumentMongo = (debug = false) => {
28
38
  const trace = Context.current();
29
39
  if (!trace) return original.apply(this, args);
30
40
 
31
- const startTime = performance.now() - trace.startTime;
32
41
  const spanStartAbs = performance.now();
33
- const collectionName = this.collectionName;
34
-
35
- const endSpan = (err?: Error) => {
36
- const duration = performance.now() - spanStartAbs;
37
- Context.addSpan({
38
- name: `MongoDB ${method} (${collectionName})`,
39
- type: 'db',
40
- startTime,
41
- duration,
42
- status: err ? 500 : 0,
43
- meta: { collection: collectionName, operation: method }
44
- });
45
- if (debug) console.log(`[Senzor] Captured Mongo Span: ${method}`);
46
- };
42
+ const traceStart = trace.startTime;
43
+ const collName = this.collectionName;
47
44
 
48
45
  try {
49
46
  const result = original.apply(this, args);
50
47
  if (result && typeof result.then === 'function') {
51
48
  return result.then(
52
- (res: any) => { endSpan(); return res; },
53
- (err: any) => { endSpan(err); throw err; }
49
+ (res: any) => { recordSpan(method, method, collName, spanStartAbs, traceStart); return res; },
50
+ (err: any) => { recordSpan(method, method, collName, spanStartAbs, traceStart, err); throw err; }
54
51
  );
55
52
  }
56
53
  return result;
57
54
  } catch (err: any) {
58
- endSpan(err);
55
+ recordSpan(method, method, collName, spanStartAbs, traceStart, err);
59
56
  throw err;
60
57
  }
61
58
  };
62
59
  });
63
60
 
64
- // 2. Instrument Cursor-based methods (find, aggregate)
65
- // We trace the *creation* of the cursor, not the fetching, as fetching is async/streamed
66
- cursorMethods.forEach((method) => {
67
- if (!Collection.prototype[method]) return;
68
- const original = Collection.prototype[method];
61
+ // --- 2. Instrument Cursor Execution (find -> toArray) ---
62
+ const patchCursor = (CursorClass: any, label: string) => {
63
+ if (!CursorClass || !CursorClass.prototype.toArray) return;
69
64
 
70
- Collection.prototype[method] = function (...args: any[]) {
71
- const trace = Context.current();
72
- if (!trace) return original.apply(this, args);
65
+ const originalToArray = CursorClass.prototype.toArray;
73
66
 
74
- const startTime = performance.now() - trace.startTime;
67
+ CursorClass.prototype.toArray = function (...args: any[]) {
68
+ const trace = Context.current();
69
+ // Cursors are often created in context but executed later.
70
+ // We check context at execution time.
71
+ if (!trace) return originalToArray.apply(this, args);
75
72
 
76
- // Record the intent to query
77
- Context.addSpan({
78
- name: `MongoDB ${method} (${this.collectionName})`,
79
- type: 'db',
80
- startTime,
81
- duration: 0, // Placeholder, as cursor creation is instant
82
- status: 0,
83
- meta: { collection: this.collectionName, operation: method }
84
- });
73
+ const spanStartAbs = performance.now();
74
+ const traceStart = trace.startTime;
75
+ // Attempt to get collection name from cursor internal state
76
+ const collName = this.namespace?.collection || 'unknown';
85
77
 
86
- if (debug) console.log(`[Senzor] Captured Mongo Cursor: ${method}`);
78
+ const onSuccess = (res: any) => {
79
+ recordSpan(label, label, collName, spanStartAbs, traceStart);
80
+ return res;
81
+ };
82
+ const onError = (err: any) => {
83
+ recordSpan(label, label, collName, spanStartAbs, traceStart, err);
84
+ throw err;
85
+ };
87
86
 
88
- return original.apply(this, args);
87
+ try {
88
+ const result = originalToArray.apply(this, args);
89
+ if (result && typeof result.then === 'function') {
90
+ return result.then(onSuccess, onError);
91
+ }
92
+ return onSuccess(result);
93
+ } catch (e) {
94
+ onError(e);
95
+ }
89
96
  };
90
- });
97
+ };
98
+
99
+ patchCursor(FindCursor, 'find');
100
+ patchCursor(AggregationCursor, 'aggregate');
91
101
 
92
102
  } catch (e: any) {
93
- if (debug) console.warn('[Senzor] MongoDB instrumentation skipped:', e.message);
103
+ if (debug) console.warn('[Senzor] MongoDB instrumentation warning:', e.message);
94
104
  }
95
105
  };