@vibeguardai/sdk 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/react.cjs ADDED
@@ -0,0 +1,5 @@
1
+ 'use strict';var y=require('react'),jsxRuntime=require('react/jsx-runtime');function _interopNamespace(e){if(e&&e.__esModule)return e;var n=Object.create(null);if(e){Object.keys(e).forEach(function(k){if(k!=='default'){var d=Object.getOwnPropertyDescriptor(e,k);Object.defineProperty(n,k,d.get?d:{enumerable:true,get:function(){return e[k]}});}})}n.default=e;return Object.freeze(n)}var y__namespace=/*#__PURE__*/_interopNamespace(y);var h="@vibeguard/sdk",g="0.1.0",T="vibeguard-offline",d="events",l=class{constructor(e){this.queue=[];this.flushTimer=null;this.db=null;this.config=e,this.initOfflineStorage(),this.setupUnloadHandler(),this.startFlushTimer();}enqueue(e){this.queue.push(e),this.config.debug&&console.log("[VibeGuard] Event queued:",e.type,e),this.queue.length>=this.config.maxBatchSize&&this.flush();}async flush(){if(this.queue.length===0)return;let e=[...this.queue];this.queue=[],this.config.debug&&console.log("[VibeGuard] Flushing",e.length,"events");let t={appId:this.config.appId,events:e,sdk:{name:h,version:g},release:this.config.release,environment:this.config.environment};await this.send(t)||await this.storeOffline(e);}async send(e){let t=JSON.stringify(e);if(typeof navigator<"u"&&navigator.sendBeacon){let r=new Blob([t],{type:"application/json"});if(navigator.sendBeacon(this.config.endpoint,r))return this.config.debug&&console.log("[VibeGuard] Sent via Beacon API"),true}try{let r=await fetch(this.config.endpoint,{method:"POST",headers:{"Content-Type":"application/json"},body:t,keepalive:!0});return r.ok?(this.config.debug&&console.log("[VibeGuard] Sent via fetch"),!0):(this.config.debug&&console.warn("[VibeGuard] Server returned",r.status),!1)}catch(r){return this.config.debug&&console.warn("[VibeGuard] Send failed:",r),false}}async initOfflineStorage(){if(!(typeof indexedDB>"u"))try{let e=indexedDB.open(T,1);e.onerror=()=>{this.config.debug&&console.warn("[VibeGuard] Failed to open IndexedDB");},e.onupgradeneeded=t=>{let r=t.target.result;r.objectStoreNames.contains(d)||r.createObjectStore(d,{autoIncrement:!0});},e.onsuccess=t=>{this.db=t.target.result,this.retryOfflineEvents();};}catch{}}async storeOffline(e){if(this.db)try{let r=this.db.transaction(d,"readwrite").objectStore(d);for(let n of e)r.add(n);this.config.debug&&console.log("[VibeGuard] Stored",e.length,"events offline");}catch{}}async retryOfflineEvents(){if(this.db)try{let r=this.db.transaction(d,"readwrite").objectStore(d).getAll();r.onsuccess=async()=>{let n=r.result;if(n.length===0)return;this.config.debug&&console.log("[VibeGuard] Retrying",n.length,"offline events");let o={appId:this.config.appId,events:n,sdk:{name:h,version:g},release:this.config.release,environment:this.config.environment};await this.send(o)&&this.db.transaction(d,"readwrite").objectStore(d).clear();};}catch{}}setupUnloadHandler(){if(typeof window>"u")return;let e=()=>{this.flush();};window.addEventListener("pagehide",e),window.addEventListener("visibilitychange",()=>{document.visibilityState==="hidden"&&e();});}startFlushTimer(){typeof setInterval>"u"||(this.flushTimer=setInterval(()=>{this.flush();},this.config.flushInterval));}destroy(){this.flushTimer&&(clearInterval(this.flushTimer),this.flushTimer=null),this.flush();}};function v(i,e){let t=S(i),r=w(e),o=[t,r].filter(Boolean).join("|");return P(o)}function S(i){return i.replace(/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/gi,"<uuid>").replace(/\b[0-9a-f]{24,}\b/gi,"<hex>").replace(/\b\d{4,}\b/g,"<num>").replace(/"[^"]{20,}"/g,'"<str>"').replace(/'[^']{20,}'/g,"'<str>'").replace(/\/[a-zA-Z0-9_-]{8,}(?=\/|$)/g,"/<path>").replace(/\s+/g," ").trim()}function w(i){if(!i)return "";let e=i.split(`
2
+ `);for(let t of e){if(!t.trim()||!t.includes("at ")||I(t))continue;let r=t.match(/(?:at\s+)?(?:\S+\s+)?\(?(.+?):(\d+):(\d+)\)?/);if(r){let[,n,o,s]=r;return `${k(n)}:${o}:${s}`}return t.trim().slice(0,100)}return ""}function I(i){return [/chrome-extension:/,/moz-extension:/,/safari-extension:/,/<anonymous>/,/native code/,/node_modules/,/webpack/,/react-dom/,/react\.development/,/react\.production/,/scheduler/,/@vibeguard\/sdk/,/vibeguard-sdk/].some(t=>t.test(i))}function k(i){return i.replace(/[?#].*$/,"").replace(/\.[a-f0-9]{8,}\.js$/,".js").replace(/https?:\/\/(localhost|127\.0\.0\.1)(:\d+)?/,"").replace(/^.*\/([^/]+)$/,"$1")}function P(i){let e=5381;for(let t=0;t<i.length;t++)e=(e<<5)+e^i.charCodeAt(t);return (e>>>0).toString(16).padStart(8,"0")}var u=class{constructor(e,t){this.originalOnError=null;this.originalOnUnhandledRejection=null;this.transport=e,this.config={beforeSend:t.beforeSend||(r=>r),tags:t.tags||{},debug:t.debug||false};}start(){typeof window>"u"||(this.setupGlobalErrorHandler(),this.setupUnhandledRejectionHandler(),this.setupConsoleErrorOverride());}stop(){typeof window>"u"||(this.originalOnError!==null&&(window.onerror=this.originalOnError),this.originalOnUnhandledRejection!==null&&(window.onunhandledrejection=this.originalOnUnhandledRejection));}captureError(e,t){let r=this.createErrorEvent(e.message,e.stack,t);this.sendEvent(r);}captureMessage(e,t){let r=this.createErrorEvent(e,void 0,t);this.sendEvent(r);}setupGlobalErrorHandler(){this.originalOnError=window.onerror,window.onerror=(e,t,r,n,o)=>{this.originalOnError&&this.originalOnError(e,t,r,n,o);let s=typeof e=="string"?e:"Unknown error",a=this.createErrorEvent(s,o?.stack,void 0,t,r,n);return this.sendEvent(a),false};}setupUnhandledRejectionHandler(){this.originalOnUnhandledRejection=window.onunhandledrejection,window.onunhandledrejection=e=>{this.originalOnUnhandledRejection&&this.originalOnUnhandledRejection(e);let t=e.reason,r="Unhandled Promise Rejection",n;t instanceof Error?(r=t.message||r,n=t.stack):typeof t=="string"?r=t:t&&typeof t=="object"&&(r=t.message||JSON.stringify(t).slice(0,200));let o=this.createErrorEvent(`[Unhandled Rejection] ${r}`,n);this.sendEvent(o);};}setupConsoleErrorOverride(){let e=console.error;console.error=(...t)=>{e.apply(console,t);let r=t[0];if(r instanceof Error){let n=this.createErrorEvent(r.message,r.stack,{consoleArgs:t.slice(1).map(String)});this.sendEvent(n);}};}createErrorEvent(e,t,r,n,o,s){if(t&&!n){let a=this.parseStack(t);n=a.file,o=a.line,s=a.column;}return {type:"error",message:e,stack:t,fingerprint:v(e,t),sourceFile:n,sourceLine:o,sourceColumn:s,url:typeof location<"u"?location.href:"",userAgent:typeof navigator<"u"?navigator.userAgent:"",tags:this.config.tags,extra:r,timestamp:Date.now()}}parseStack(e){let t=e.split(`
3
+ `);for(let r of t){if(!r.includes("at ")||r.includes("vibeguard-sdk"))continue;let n=r.match(/(?:at\s+)?(?:\S+\s+)?\(?(.+?):(\d+):(\d+)\)?/);if(n)return {file:n[1],line:parseInt(n[2],10),column:parseInt(n[3],10)}}return {}}sendEvent(e){let t=this.config.beforeSend(e);if(!t){this.config.debug&&console.log("[VibeGuard] Event filtered by beforeSend");return}this.transport.enqueue(t);}};var f=class{constructor(e,t){this.metrics={};this.observers=[];this.reportedMetrics=new Set;this.transport=e,this.sampleRate=t.sampleRate,this.debug=t.debug,this.sessionId=this.generateSessionId();}start(){if(!(typeof window>"u")){if(!this.shouldSample()){this.debug&&console.log("[VibeGuard] Performance sampling skipped");return}this.trackTTFB(),this.trackFCP(),this.trackLCP(),this.trackCLS(),this.trackINP(),this.setupUnloadHandler();}}stop(){for(let e of this.observers)e.disconnect();this.observers=[];}shouldSample(){return Math.random()<this.sampleRate}generateSessionId(){return Math.random().toString(36).slice(2,10)}trackTTFB(){try{let e=performance.getEntriesByType("navigation")[0];e&&(this.metrics.ttfb=e.responseStart-e.requestStart,this.debug&&console.log("[VibeGuard] TTFB:",this.metrics.ttfb));}catch{}}trackFCP(){try{let e=new PerformanceObserver(t=>{for(let r of t.getEntries())r.name==="first-contentful-paint"&&(this.metrics.fcp=r.startTime,this.debug&&console.log("[VibeGuard] FCP:",this.metrics.fcp),e.disconnect());});e.observe({type:"paint",buffered:!0}),this.observers.push(e);}catch{}}trackLCP(){try{let e=new PerformanceObserver(t=>{let r=t.getEntries(),n=r[r.length-1];n&&(this.metrics.lcp=n.renderTime||n.loadTime,this.debug&&console.log("[VibeGuard] LCP:",this.metrics.lcp));});e.observe({type:"largest-contentful-paint",buffered:!0}),this.observers.push(e);}catch{}}trackCLS(){try{let e=0,t=0,r=[],n=new PerformanceObserver(o=>{for(let s of o.getEntries())if(!s.hadRecentInput){let a=r[0],E=r[r.length-1];r.length&&(s.startTime-E.startTime>1e3||s.startTime-a.startTime>5e3)&&(t>e&&(e=t),t=0,r=[]),r.push(s),t+=s.value;}this.metrics.cls=Math.max(e,t),this.debug&&console.log("[VibeGuard] CLS:",this.metrics.cls);});n.observe({type:"layout-shift",buffered:!0}),this.observers.push(n);}catch{}}trackINP(){try{let e=new Map,t=new PerformanceObserver(r=>{for(let n of r.getEntries())if(n.interactionId){let o=n.duration,s=e.get(n.interactionId);(!s||o>s)&&e.set(n.interactionId,o);}if(e.size>0){let n=Array.from(e.values()).sort((s,a)=>a-s),o=Math.min(n.length-1,Math.floor(n.length/50));this.metrics.inp=n[o],!this.metrics.fid&&n.length>0&&(this.metrics.fid=n[n.length-1]),this.debug&&console.log("[VibeGuard] INP:",this.metrics.inp,"FID:",this.metrics.fid);}});t.observe({type:"event",buffered:!0,durationThreshold:16}),this.observers.push(t);}catch{}}setupUnloadHandler(){let e=()=>{if(!Object.values(this.metrics).some(n=>n!==void 0))return;let r={type:"performance",url:location.href,route:this.extractRoute(),metrics:{...this.metrics},userAgent:navigator.userAgent,connectionType:this.getConnectionType(),deviceMemory:this.getDeviceMemory(),hardwareConcurrency:navigator.hardwareConcurrency,sessionId:this.sessionId,timestamp:Date.now()};this.debug&&console.log("[VibeGuard] Sending performance metrics:",r),this.transport.enqueue(r);};document.addEventListener("visibilitychange",()=>{document.visibilityState==="hidden"&&e();}),window.addEventListener("pagehide",e);}extractRoute(){return location.pathname.replace(/\/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/gi,"/[id]").replace(/\/\d+(?=\/|$)/g,"/[id]").replace(/\/[a-zA-Z0-9]{8,}(?=\/|$)/g,"/[id]")}getConnectionType(){return navigator.connection?.effectiveType}getDeviceMemory(){return navigator.deviceMemory}};var R="https://vibeguard.app/api/ingest/v1",p=class{constructor(){this.transport=null;this.errorTracker=null;this.performanceTracker=null;this.initialized=false;}init(e){if(this.initialized){console.warn("[VibeGuard] SDK already initialized");return}if(!e.appId){console.error("[VibeGuard] appId is required");return}!e.appId.startsWith("vg_")&&!/^[a-f0-9-]{36}$/i.test(e.appId)&&console.warn('[VibeGuard] appId should start with "vg_" or be a valid UUID');let t={endpoint:e.endpoint||R,appId:e.appId,errorTracking:e.errorTracking!==false,performanceTracking:e.performanceTracking!==false,sampleRate:e.sampleRate??1,debug:e.debug||false,maxBatchSize:e.maxBatchSize||10,flushInterval:e.flushInterval||5e3,tags:e.tags||{},release:e.release,environment:e.environment,beforeSend:e.beforeSend};t.debug&&console.log("[VibeGuard] Initializing with config:",{...t,beforeSend:t.beforeSend?"[function]":void 0}),this.transport=new l({endpoint:t.endpoint,appId:t.appId,maxBatchSize:t.maxBatchSize,flushInterval:t.flushInterval,debug:t.debug,release:t.release,environment:t.environment}),t.errorTracking&&(this.errorTracker=new u(this.transport,{beforeSend:t.beforeSend,tags:t.tags,debug:t.debug}),this.errorTracker.start()),t.performanceTracking&&(this.performanceTracker=new f(this.transport,{sampleRate:t.sampleRate,debug:t.debug}),this.performanceTracker.start()),this.initialized=true,t.debug&&console.log("[VibeGuard] SDK initialized successfully");}captureError(e,t){if(!this.errorTracker){console.warn("[VibeGuard] SDK not initialized or error tracking disabled");return}this.errorTracker.captureError(e,t?.extra);}captureMessage(e,t){if(!this.errorTracker){console.warn("[VibeGuard] SDK not initialized or error tracking disabled");return}this.errorTracker.captureMessage(e,t?.extra);}flush(){return this.transport?this.transport.flush():Promise.resolve()}destroy(){this.errorTracker?.stop(),this.performanceTracker?.stop(),this.transport?.destroy(),this.initialized=false;}isInitialized(){return this.initialized}},c=new p;if(typeof document<"u"){let i=()=>{let e=document.querySelector("script[data-app-id]");if(e&&!c.isInitialized()){let t=e.dataset.appId;t&&c.init({appId:t,endpoint:e.dataset.endpoint,debug:e.dataset.debug==="true",sampleRate:e.dataset.sampleRate?parseFloat(e.dataset.sampleRate):void 0,release:e.dataset.release,environment:e.dataset.environment});}};document.readyState==="loading"?document.addEventListener("DOMContentLoaded",i):i();}var b=y.createContext(null);function $({children:i,appId:e,...t}){let r=y.useRef(false);y.useEffect(()=>{if(!r.current)return r.current=true,c.init({appId:e,...t}),()=>{c.destroy(),r.current=false;}},[e]);let n={captureError:(o,s)=>c.captureError(o,{extra:s}),captureMessage:(o,s)=>c.captureMessage(o,{extra:s})};return jsxRuntime.jsx(b.Provider,{value:n,children:i})}function H(){let i=y.useContext(b);if(!i)throw new Error("useVibeGuard must be used within a VibeGuardProvider");return i}var m=class extends y__namespace.Component{constructor(e){super(e),this.state={hasError:false,error:null};}static getDerivedStateFromError(e){return {hasError:true,error:e}}componentDidCatch(e,t){c.captureError(e,{extra:{componentStack:t.componentStack}}),this.props.onError?.(e,t);}render(){if(this.state.hasError&&this.state.error){let{fallback:e}=this.props;return typeof e=="function"?e(this.state.error):e||null}return this.props.children}};
4
+ exports.VibeGuard=c;exports.VibeGuardErrorBoundary=m;exports.VibeGuardProvider=$;exports.useVibeGuard=H;//# sourceMappingURL=react.cjs.map
5
+ //# sourceMappingURL=react.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/transport.ts","../src/fingerprint.ts","../src/error-tracking.ts","../src/performance.ts","../src/index.ts","../src/react.tsx"],"names":["SDK_NAME","SDK_VERSION","DB_NAME","STORE_NAME","Transport","config","event","events","payload","body","blob","response","error","request","db","store","handleUnload","generateFingerprint","message","stack","normalizedMessage","normalizeMessage","meaningfulFrame","extractMeaningfulFrame","input","djb2Hash","lines","line","isInternalFrame","match","file","col","normalizeFilePath","pattern","path","str","hash","i","ErrorTracker","transport","e","extra","source","lineno","colno","errorMessage","ev","reason","originalConsoleError","args","firstArg","sourceFile","sourceLine","sourceColumn","parsed","filtered","PerformanceTracker","observer","nav","list","entry","entries","lastEntry","clsValue","sessionValue","sessionEntries","firstEntry","interactions","duration","existing","values","a","b","index","sendMetrics","v","DEFAULT_ENDPOINT","VibeGuardSDK","resolvedConfig","options","VibeGuard","initFromScriptTag","script","appId","VibeGuardContext","createContext","VibeGuardProvider","children","initializedRef","useRef","useEffect","contextValue","jsx","useVibeGuard","context","useContext","VibeGuardErrorBoundary","y","props","errorInfo","fallback"],"mappings":"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","file":"react.cjs","sourcesContent":["/**\n * Transport layer for sending telemetry to VibeGuard\n * - Batches events for efficiency\n * - Uses Beacon API for reliable delivery\n * - Falls back to IndexedDB for offline support\n */\n\nimport type { TelemetryEvent, IngestPayload } from './types'\n\nconst SDK_NAME = '@vibeguard/sdk'\nconst SDK_VERSION = '0.1.0'\nconst DB_NAME = 'vibeguard-offline'\nconst STORE_NAME = 'events'\n\ninterface TransportConfig {\n endpoint: string\n appId: string\n maxBatchSize: number\n flushInterval: number\n debug: boolean\n release?: string\n environment?: string\n}\n\nexport class Transport {\n private config: TransportConfig\n private queue: TelemetryEvent[] = []\n private flushTimer: ReturnType<typeof setTimeout> | null = null\n private db: IDBDatabase | null = null\n\n constructor(config: TransportConfig) {\n this.config = config\n this.initOfflineStorage()\n this.setupUnloadHandler()\n this.startFlushTimer()\n }\n\n /**\n * Add an event to the queue\n */\n enqueue(event: TelemetryEvent): void {\n this.queue.push(event)\n\n if (this.config.debug) {\n console.log('[VibeGuard] Event queued:', event.type, event)\n }\n\n // Flush if batch size reached\n if (this.queue.length >= this.config.maxBatchSize) {\n this.flush()\n }\n }\n\n /**\n * Flush all queued events\n */\n async flush(): Promise<void> {\n if (this.queue.length === 0) return\n\n const events = [...this.queue]\n this.queue = []\n\n if (this.config.debug) {\n console.log('[VibeGuard] Flushing', events.length, 'events')\n }\n\n const payload: IngestPayload = {\n appId: this.config.appId,\n events,\n sdk: {\n name: SDK_NAME,\n version: SDK_VERSION,\n },\n release: this.config.release,\n environment: this.config.environment,\n }\n\n const success = await this.send(payload)\n\n if (!success) {\n // Store failed events for retry\n await this.storeOffline(events)\n }\n }\n\n /**\n * Send payload to the ingest endpoint\n */\n private async send(payload: IngestPayload): Promise<boolean> {\n const body = JSON.stringify(payload)\n\n // Try Beacon API first (most reliable for unload)\n if (typeof navigator !== 'undefined' && navigator.sendBeacon) {\n const blob = new Blob([body], { type: 'application/json' })\n const sent = navigator.sendBeacon(this.config.endpoint, blob)\n\n if (sent) {\n if (this.config.debug) {\n console.log('[VibeGuard] Sent via Beacon API')\n }\n return true\n }\n }\n\n // Fallback to fetch\n try {\n const response = await fetch(this.config.endpoint, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body,\n keepalive: true, // Important for unload scenarios\n })\n\n if (response.ok) {\n if (this.config.debug) {\n console.log('[VibeGuard] Sent via fetch')\n }\n return true\n }\n\n if (this.config.debug) {\n console.warn('[VibeGuard] Server returned', response.status)\n }\n return false\n } catch (error) {\n if (this.config.debug) {\n console.warn('[VibeGuard] Send failed:', error)\n }\n return false\n }\n }\n\n /**\n * Initialize IndexedDB for offline storage\n */\n private async initOfflineStorage(): Promise<void> {\n if (typeof indexedDB === 'undefined') return\n\n try {\n const request = indexedDB.open(DB_NAME, 1)\n\n request.onerror = () => {\n if (this.config.debug) {\n console.warn('[VibeGuard] Failed to open IndexedDB')\n }\n }\n\n request.onupgradeneeded = (event) => {\n const db = (event.target as IDBOpenDBRequest).result\n if (!db.objectStoreNames.contains(STORE_NAME)) {\n db.createObjectStore(STORE_NAME, { autoIncrement: true })\n }\n }\n\n request.onsuccess = (event) => {\n this.db = (event.target as IDBOpenDBRequest).result\n\n // Try to send any stored events\n this.retryOfflineEvents()\n }\n } catch {\n // IndexedDB might be blocked in some contexts\n }\n }\n\n /**\n * Store events for offline retry\n */\n private async storeOffline(events: TelemetryEvent[]): Promise<void> {\n if (!this.db) return\n\n try {\n const transaction = this.db.transaction(STORE_NAME, 'readwrite')\n const store = transaction.objectStore(STORE_NAME)\n\n for (const event of events) {\n store.add(event)\n }\n\n if (this.config.debug) {\n console.log('[VibeGuard] Stored', events.length, 'events offline')\n }\n } catch {\n // Ignore storage errors\n }\n }\n\n /**\n * Retry sending offline events\n */\n private async retryOfflineEvents(): Promise<void> {\n if (!this.db) return\n\n try {\n const transaction = this.db.transaction(STORE_NAME, 'readwrite')\n const store = transaction.objectStore(STORE_NAME)\n const request = store.getAll()\n\n request.onsuccess = async () => {\n const events = request.result as TelemetryEvent[]\n if (events.length === 0) return\n\n if (this.config.debug) {\n console.log('[VibeGuard] Retrying', events.length, 'offline events')\n }\n\n const payload: IngestPayload = {\n appId: this.config.appId,\n events,\n sdk: {\n name: SDK_NAME,\n version: SDK_VERSION,\n },\n release: this.config.release,\n environment: this.config.environment,\n }\n\n const success = await this.send(payload)\n\n if (success) {\n // Clear stored events\n const clearTx = this.db!.transaction(STORE_NAME, 'readwrite')\n clearTx.objectStore(STORE_NAME).clear()\n }\n }\n } catch {\n // Ignore retry errors\n }\n }\n\n /**\n * Setup handler for page unload\n */\n private setupUnloadHandler(): void {\n if (typeof window === 'undefined') return\n\n const handleUnload = () => {\n this.flush()\n }\n\n // Use both for maximum compatibility\n window.addEventListener('pagehide', handleUnload)\n window.addEventListener('visibilitychange', () => {\n if (document.visibilityState === 'hidden') {\n handleUnload()\n }\n })\n }\n\n /**\n * Start the periodic flush timer\n */\n private startFlushTimer(): void {\n if (typeof setInterval === 'undefined') return\n\n this.flushTimer = setInterval(() => {\n this.flush()\n }, this.config.flushInterval)\n }\n\n /**\n * Stop the transport and flush remaining events\n */\n destroy(): void {\n if (this.flushTimer) {\n clearInterval(this.flushTimer)\n this.flushTimer = null\n }\n this.flush()\n }\n}\n","/**\n * Error fingerprinting for deduplication\n * Creates deterministic hashes to group identical errors\n */\n\n/**\n * Generate a fingerprint for an error\n * Uses message (normalized) + first meaningful stack frame\n */\nexport function generateFingerprint(\n message: string,\n stack?: string\n): string {\n // Normalize the message (remove dynamic values)\n const normalizedMessage = normalizeMessage(message)\n\n // Get the first meaningful stack frame\n const meaningfulFrame = extractMeaningfulFrame(stack)\n\n // Create fingerprint from normalized parts\n const parts = [normalizedMessage, meaningfulFrame].filter(Boolean)\n const input = parts.join('|')\n\n // Simple hash (djb2 algorithm - fast and good distribution)\n return djb2Hash(input)\n}\n\n/**\n * Normalize error message by removing dynamic values\n * - Numbers (IDs, timestamps, etc.)\n * - UUIDs\n * - URLs with dynamic paths\n * - Quoted strings that look like IDs\n */\nfunction normalizeMessage(message: string): string {\n return message\n // Remove UUIDs\n .replace(/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/gi, '<uuid>')\n // Remove hex strings (likely IDs)\n .replace(/\\b[0-9a-f]{24,}\\b/gi, '<hex>')\n // Remove numbers (but keep small ones that might be meaningful like error codes)\n .replace(/\\b\\d{4,}\\b/g, '<num>')\n // Remove quoted strings that look like dynamic values\n .replace(/\"[^\"]{20,}\"/g, '\"<str>\"')\n .replace(/'[^']{20,}'/g, \"'<str>'\")\n // Remove URL paths with dynamic segments\n .replace(/\\/[a-zA-Z0-9_-]{8,}(?=\\/|$)/g, '/<path>')\n // Normalize whitespace\n .replace(/\\s+/g, ' ')\n .trim()\n}\n\n/**\n * Extract the first meaningful stack frame\n * Skips internal/library frames to find the user's code\n */\nfunction extractMeaningfulFrame(stack?: string): string {\n if (!stack) return ''\n\n const lines = stack.split('\\n')\n\n for (const line of lines) {\n // Skip empty lines and the error message line\n if (!line.trim() || !line.includes('at ')) continue\n\n // Skip internal/library frames\n if (isInternalFrame(line)) continue\n\n // Extract file:line:column\n const match = line.match(/(?:at\\s+)?(?:\\S+\\s+)?\\(?(.+?):(\\d+):(\\d+)\\)?/)\n if (match) {\n const [, file, line, col] = match\n // Normalize the file path\n const normalizedFile = normalizeFilePath(file)\n return `${normalizedFile}:${line}:${col}`\n }\n\n // Fallback: use the whole line\n return line.trim().slice(0, 100)\n }\n\n return ''\n}\n\n/**\n * Check if a stack frame is from internal/library code\n */\nfunction isInternalFrame(line: string): boolean {\n const internalPatterns = [\n // Browser internals\n /chrome-extension:/,\n /moz-extension:/,\n /safari-extension:/,\n /<anonymous>/,\n /native code/,\n // Common libraries to skip\n /node_modules/,\n /webpack/,\n /react-dom/,\n /react\\.development/,\n /react\\.production/,\n /scheduler/,\n // VibeGuard SDK itself\n /@vibeguard\\/sdk/,\n /vibeguard-sdk/,\n ]\n\n return internalPatterns.some((pattern) => pattern.test(line))\n}\n\n/**\n * Normalize file path for consistent fingerprinting\n */\nfunction normalizeFilePath(path: string): string {\n return path\n // Remove query strings and hashes\n .replace(/[?#].*$/, '')\n // Remove webpack chunk hashes\n .replace(/\\.[a-f0-9]{8,}\\.js$/, '.js')\n // Normalize localhost/127.0.0.1\n .replace(/https?:\\/\\/(localhost|127\\.0\\.0\\.1)(:\\d+)?/, '')\n // Keep just the filename for very long paths\n .replace(/^.*\\/([^/]+)$/, '$1')\n}\n\n/**\n * DJB2 hash algorithm - fast and has good distribution\n */\nfunction djb2Hash(str: string): string {\n let hash = 5381\n for (let i = 0; i < str.length; i++) {\n hash = ((hash << 5) + hash) ^ str.charCodeAt(i)\n }\n // Convert to hex string, ensure positive\n return (hash >>> 0).toString(16).padStart(8, '0')\n}\n","/**\n * Error tracking module\n * Captures and reports uncaught errors and unhandled promise rejections\n */\n\nimport type { ErrorEvent, VibeGuardConfig } from './types'\nimport { Transport } from './transport'\nimport { generateFingerprint } from './fingerprint'\n\nexport class ErrorTracker {\n private transport: Transport\n private config: Required<Pick<VibeGuardConfig, 'beforeSend' | 'tags' | 'debug'>>\n private originalOnError: OnErrorEventHandler | null = null\n private originalOnUnhandledRejection: ((event: PromiseRejectionEvent) => void) | null = null\n\n constructor(\n transport: Transport,\n config: Pick<VibeGuardConfig, 'beforeSend' | 'tags' | 'debug'>\n ) {\n this.transport = transport\n this.config = {\n beforeSend: config.beforeSend || ((e) => e),\n tags: config.tags || {},\n debug: config.debug || false,\n }\n }\n\n /**\n * Start capturing errors\n */\n start(): void {\n if (typeof window === 'undefined') return\n\n this.setupGlobalErrorHandler()\n this.setupUnhandledRejectionHandler()\n this.setupConsoleErrorOverride()\n }\n\n /**\n * Stop capturing errors\n */\n stop(): void {\n if (typeof window === 'undefined') return\n\n // Restore original handlers\n if (this.originalOnError !== null) {\n window.onerror = this.originalOnError\n }\n if (this.originalOnUnhandledRejection !== null) {\n window.onunhandledrejection = this.originalOnUnhandledRejection\n }\n }\n\n /**\n * Manually capture an error\n */\n captureError(error: Error, extra?: Record<string, unknown>): void {\n const event = this.createErrorEvent(error.message, error.stack, extra)\n this.sendEvent(event)\n }\n\n /**\n * Manually capture a message\n */\n captureMessage(message: string, extra?: Record<string, unknown>): void {\n const event = this.createErrorEvent(message, undefined, extra)\n this.sendEvent(event)\n }\n\n /**\n * Setup window.onerror handler\n */\n private setupGlobalErrorHandler(): void {\n this.originalOnError = window.onerror\n\n window.onerror = (\n message,\n source,\n lineno,\n colno,\n error\n ): boolean => {\n // Call original handler if it exists\n if (this.originalOnError) {\n this.originalOnError(message, source, lineno, colno, error)\n }\n\n const errorMessage = typeof message === 'string' ? message : 'Unknown error'\n const event = this.createErrorEvent(\n errorMessage,\n error?.stack,\n undefined,\n source,\n lineno,\n colno\n )\n\n this.sendEvent(event)\n\n // Don't prevent default error handling\n return false\n }\n }\n\n /**\n * Setup unhandledrejection handler\n */\n private setupUnhandledRejectionHandler(): void {\n this.originalOnUnhandledRejection = window.onunhandledrejection\n\n window.onunhandledrejection = (ev: PromiseRejectionEvent): void => {\n // Call original handler if it exists\n if (this.originalOnUnhandledRejection) {\n this.originalOnUnhandledRejection(ev)\n }\n\n const reason = ev.reason\n let message = 'Unhandled Promise Rejection'\n let stack: string | undefined\n\n if (reason instanceof Error) {\n message = reason.message || message\n stack = reason.stack\n } else if (typeof reason === 'string') {\n message = reason\n } else if (reason && typeof reason === 'object') {\n message = reason.message || JSON.stringify(reason).slice(0, 200)\n }\n\n const event = this.createErrorEvent(`[Unhandled Rejection] ${message}`, stack)\n this.sendEvent(event)\n }\n }\n\n /**\n * Override console.error to capture logged errors\n * Only captures Error objects, not regular console.error logs\n */\n private setupConsoleErrorOverride(): void {\n const originalConsoleError = console.error\n\n console.error = (...args: unknown[]): void => {\n // Call original console.error\n originalConsoleError.apply(console, args)\n\n // Only capture if first arg is an Error\n const firstArg = args[0]\n if (firstArg instanceof Error) {\n const event = this.createErrorEvent(\n firstArg.message,\n firstArg.stack,\n { consoleArgs: args.slice(1).map(String) }\n )\n this.sendEvent(event)\n }\n }\n }\n\n /**\n * Create an error event from error details\n */\n private createErrorEvent(\n message: string,\n stack?: string,\n extra?: Record<string, unknown>,\n sourceFile?: string,\n sourceLine?: number,\n sourceColumn?: number\n ): ErrorEvent {\n // Parse source info from stack if not provided\n if (stack && !sourceFile) {\n const parsed = this.parseStack(stack)\n sourceFile = parsed.file\n sourceLine = parsed.line\n sourceColumn = parsed.column\n }\n\n return {\n type: 'error',\n message,\n stack,\n fingerprint: generateFingerprint(message, stack),\n sourceFile,\n sourceLine,\n sourceColumn,\n url: typeof location !== 'undefined' ? location.href : '',\n userAgent: typeof navigator !== 'undefined' ? navigator.userAgent : '',\n tags: this.config.tags,\n extra,\n timestamp: Date.now(),\n }\n }\n\n /**\n * Parse stack trace to extract source info\n */\n private parseStack(stack: string): {\n file?: string\n line?: number\n column?: number\n } {\n const lines = stack.split('\\n')\n\n for (const line of lines) {\n // Skip the error message line and internal frames\n if (!line.includes('at ') || line.includes('vibeguard-sdk')) continue\n\n // Match Chrome/Firefox stack format\n const match = line.match(/(?:at\\s+)?(?:\\S+\\s+)?\\(?(.+?):(\\d+):(\\d+)\\)?/)\n if (match) {\n return {\n file: match[1],\n line: parseInt(match[2], 10),\n column: parseInt(match[3], 10),\n }\n }\n }\n\n return {}\n }\n\n /**\n * Send an error event through the transport\n */\n private sendEvent(event: ErrorEvent): void {\n // Run beforeSend hook\n const filtered = this.config.beforeSend(event)\n if (!filtered) {\n if (this.config.debug) {\n console.log('[VibeGuard] Event filtered by beforeSend')\n }\n return\n }\n\n this.transport.enqueue(filtered)\n }\n}\n","/**\n * Performance tracking module\n * Tracks Core Web Vitals and performance metrics\n * Inlined web-vitals implementation for zero dependencies\n */\n\nimport type { PerformanceEvent, WebVitalsMetrics } from './types'\nimport { Transport } from './transport'\n\n// Types for Performance API\ninterface LayoutShift extends PerformanceEntry {\n hadRecentInput: boolean\n value: number\n}\n\ninterface LargestContentfulPaint extends PerformanceEntry {\n renderTime: number\n loadTime: number\n}\n\ninterface PerformanceEventTiming extends PerformanceEntry {\n processingStart: number\n processingEnd: number\n interactionId?: number\n}\n\ntype MetricName = 'lcp' | 'fid' | 'inp' | 'cls' | 'fcp' | 'ttfb'\n\nexport class PerformanceTracker {\n private transport: Transport\n private sampleRate: number\n private debug: boolean\n private metrics: WebVitalsMetrics = {}\n private observers: PerformanceObserver[] = []\n private sessionId: string\n private reportedMetrics: Set<MetricName> = new Set()\n\n constructor(\n transport: Transport,\n config: { sampleRate: number; debug: boolean }\n ) {\n this.transport = transport\n this.sampleRate = config.sampleRate\n this.debug = config.debug\n this.sessionId = this.generateSessionId()\n }\n\n /**\n * Start tracking performance metrics\n */\n start(): void {\n if (typeof window === 'undefined') return\n if (!this.shouldSample()) {\n if (this.debug) {\n console.log('[VibeGuard] Performance sampling skipped')\n }\n return\n }\n\n this.trackTTFB()\n this.trackFCP()\n this.trackLCP()\n this.trackCLS()\n this.trackINP()\n\n // Send metrics on page hide/unload\n this.setupUnloadHandler()\n }\n\n /**\n * Stop tracking and cleanup\n */\n stop(): void {\n for (const observer of this.observers) {\n observer.disconnect()\n }\n this.observers = []\n }\n\n /**\n * Check if we should sample this page view\n */\n private shouldSample(): boolean {\n return Math.random() < this.sampleRate\n }\n\n /**\n * Generate a session ID for grouping metrics\n */\n private generateSessionId(): string {\n return Math.random().toString(36).slice(2, 10)\n }\n\n /**\n * Track Time to First Byte (TTFB)\n */\n private trackTTFB(): void {\n try {\n const nav = performance.getEntriesByType('navigation')[0] as PerformanceNavigationTiming\n if (nav) {\n this.metrics.ttfb = nav.responseStart - nav.requestStart\n if (this.debug) {\n console.log('[VibeGuard] TTFB:', this.metrics.ttfb)\n }\n }\n } catch {\n // Navigation Timing not available\n }\n }\n\n /**\n * Track First Contentful Paint (FCP)\n */\n private trackFCP(): void {\n try {\n const observer = new PerformanceObserver((list) => {\n for (const entry of list.getEntries()) {\n if (entry.name === 'first-contentful-paint') {\n this.metrics.fcp = entry.startTime\n if (this.debug) {\n console.log('[VibeGuard] FCP:', this.metrics.fcp)\n }\n observer.disconnect()\n }\n }\n })\n\n observer.observe({ type: 'paint', buffered: true })\n this.observers.push(observer)\n } catch {\n // Performance Observer not available\n }\n }\n\n /**\n * Track Largest Contentful Paint (LCP)\n */\n private trackLCP(): void {\n try {\n const observer = new PerformanceObserver((list) => {\n const entries = list.getEntries() as LargestContentfulPaint[]\n const lastEntry = entries[entries.length - 1]\n if (lastEntry) {\n this.metrics.lcp = lastEntry.renderTime || lastEntry.loadTime\n if (this.debug) {\n console.log('[VibeGuard] LCP:', this.metrics.lcp)\n }\n }\n })\n\n observer.observe({ type: 'largest-contentful-paint', buffered: true })\n this.observers.push(observer)\n } catch {\n // LCP not available\n }\n }\n\n /**\n * Track Cumulative Layout Shift (CLS)\n */\n private trackCLS(): void {\n try {\n let clsValue = 0\n let sessionValue = 0\n let sessionEntries: LayoutShift[] = []\n\n const observer = new PerformanceObserver((list) => {\n for (const entry of list.getEntries() as LayoutShift[]) {\n // Only count layout shifts without recent user input\n if (!entry.hadRecentInput) {\n const firstEntry = sessionEntries[0]\n const lastEntry = sessionEntries[sessionEntries.length - 1]\n\n // Start a new session if gap > 1s or total > 5s\n if (\n sessionEntries.length &&\n (entry.startTime - lastEntry.startTime > 1000 ||\n entry.startTime - firstEntry.startTime > 5000)\n ) {\n // Record this session's value if it's larger\n if (sessionValue > clsValue) {\n clsValue = sessionValue\n }\n sessionValue = 0\n sessionEntries = []\n }\n\n sessionEntries.push(entry)\n sessionValue += entry.value\n }\n }\n\n // Update CLS with max of current session\n this.metrics.cls = Math.max(clsValue, sessionValue)\n if (this.debug) {\n console.log('[VibeGuard] CLS:', this.metrics.cls)\n }\n })\n\n observer.observe({ type: 'layout-shift', buffered: true })\n this.observers.push(observer)\n } catch {\n // CLS not available\n }\n }\n\n /**\n * Track Interaction to Next Paint (INP)\n * Replaces FID as the responsiveness metric\n */\n private trackINP(): void {\n try {\n const interactions = new Map<number, number>()\n\n const observer = new PerformanceObserver((list) => {\n for (const entry of list.getEntries() as PerformanceEventTiming[]) {\n // Only track interactions with an interactionId\n if (entry.interactionId) {\n const duration = entry.duration\n\n // Keep the max duration for each interaction\n const existing = interactions.get(entry.interactionId)\n if (!existing || duration > existing) {\n interactions.set(entry.interactionId, duration)\n }\n }\n }\n\n // INP is the 98th percentile of interactions (or worst if < 50)\n if (interactions.size > 0) {\n const values = Array.from(interactions.values()).sort((a, b) => b - a)\n const index = Math.min(\n values.length - 1,\n Math.floor(values.length / 50) // ~98th percentile\n )\n this.metrics.inp = values[index]\n\n // Also track FID as the first interaction\n if (!this.metrics.fid && values.length > 0) {\n this.metrics.fid = values[values.length - 1] // First interaction\n }\n\n if (this.debug) {\n console.log('[VibeGuard] INP:', this.metrics.inp, 'FID:', this.metrics.fid)\n }\n }\n })\n\n observer.observe({ type: 'event', buffered: true, durationThreshold: 16 })\n this.observers.push(observer)\n } catch {\n // INP not available\n }\n }\n\n /**\n * Setup handler for page unload to send metrics\n */\n private setupUnloadHandler(): void {\n const sendMetrics = (): void => {\n // Only send if we have at least one metric\n const hasMetrics = Object.values(this.metrics).some((v) => v !== undefined)\n if (!hasMetrics) return\n\n const event: PerformanceEvent = {\n type: 'performance',\n url: location.href,\n route: this.extractRoute(),\n metrics: { ...this.metrics },\n userAgent: navigator.userAgent,\n connectionType: this.getConnectionType(),\n deviceMemory: this.getDeviceMemory(),\n hardwareConcurrency: navigator.hardwareConcurrency,\n sessionId: this.sessionId,\n timestamp: Date.now(),\n }\n\n if (this.debug) {\n console.log('[VibeGuard] Sending performance metrics:', event)\n }\n\n this.transport.enqueue(event)\n }\n\n // Send on visibility change (more reliable than unload)\n document.addEventListener('visibilitychange', () => {\n if (document.visibilityState === 'hidden') {\n sendMetrics()\n }\n })\n\n // Also send on pagehide for better coverage\n window.addEventListener('pagehide', sendMetrics)\n }\n\n /**\n * Extract normalized route from URL\n */\n private extractRoute(): string {\n const path = location.pathname\n\n // Normalize common dynamic segments\n return path\n // UUID segments\n .replace(/\\/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/gi, '/[id]')\n // Numeric IDs\n .replace(/\\/\\d+(?=\\/|$)/g, '/[id]')\n // Alphanumeric IDs (8+ chars)\n .replace(/\\/[a-zA-Z0-9]{8,}(?=\\/|$)/g, '/[id]')\n }\n\n /**\n * Get connection type from Network Information API\n */\n private getConnectionType(): string | undefined {\n const nav = navigator as Navigator & {\n connection?: { effectiveType?: string }\n }\n return nav.connection?.effectiveType\n }\n\n /**\n * Get device memory from Device Memory API\n */\n private getDeviceMemory(): number | undefined {\n const nav = navigator as Navigator & { deviceMemory?: number }\n return nav.deviceMemory\n }\n}\n","/**\n * VibeGuard SDK\n * Client-side error tracking and performance monitoring\n *\n * Usage:\n * ```js\n * import { VibeGuard } from '@vibeguard/sdk'\n *\n * VibeGuard.init({ appId: 'vg_xxx' })\n *\n * // Manual error capture\n * VibeGuard.captureError(new Error('Something went wrong'))\n *\n * // Manual message\n * VibeGuard.captureMessage('User clicked forbidden button', { extra: { userId: '123' } })\n * ```\n *\n * Or via script tag:\n * ```html\n * <script src=\"https://cdn.vibeguard.app/sdk.js\" data-app-id=\"vg_xxx\"></script>\n * ```\n */\n\nimport type { VibeGuardConfig } from './types'\nimport { Transport } from './transport'\nimport { ErrorTracker } from './error-tracking'\nimport { PerformanceTracker } from './performance'\n\nexport type { VibeGuardConfig, ErrorEvent, PerformanceEvent, WebVitalsMetrics } from './types'\n\nconst DEFAULT_ENDPOINT = 'https://vibeguard.app/api/ingest/v1'\n\nclass VibeGuardSDK {\n private transport: Transport | null = null\n private errorTracker: ErrorTracker | null = null\n private performanceTracker: PerformanceTracker | null = null\n private initialized = false\n\n /**\n * Initialize the VibeGuard SDK\n */\n init(config: VibeGuardConfig): void {\n if (this.initialized) {\n console.warn('[VibeGuard] SDK already initialized')\n return\n }\n\n if (!config.appId) {\n console.error('[VibeGuard] appId is required')\n return\n }\n\n // Validate appId format\n if (!config.appId.startsWith('vg_') && !/^[a-f0-9-]{36}$/i.test(config.appId)) {\n console.warn('[VibeGuard] appId should start with \"vg_\" or be a valid UUID')\n }\n\n const resolvedConfig = {\n endpoint: config.endpoint || DEFAULT_ENDPOINT,\n appId: config.appId,\n errorTracking: config.errorTracking !== false,\n performanceTracking: config.performanceTracking !== false,\n sampleRate: config.sampleRate ?? 1.0,\n debug: config.debug || false,\n maxBatchSize: config.maxBatchSize || 10,\n flushInterval: config.flushInterval || 5000,\n tags: config.tags || {},\n release: config.release,\n environment: config.environment,\n beforeSend: config.beforeSend,\n }\n\n if (resolvedConfig.debug) {\n console.log('[VibeGuard] Initializing with config:', {\n ...resolvedConfig,\n beforeSend: resolvedConfig.beforeSend ? '[function]' : undefined,\n })\n }\n\n // Initialize transport\n this.transport = new Transport({\n endpoint: resolvedConfig.endpoint,\n appId: resolvedConfig.appId,\n maxBatchSize: resolvedConfig.maxBatchSize,\n flushInterval: resolvedConfig.flushInterval,\n debug: resolvedConfig.debug,\n release: resolvedConfig.release,\n environment: resolvedConfig.environment,\n })\n\n // Initialize error tracking\n if (resolvedConfig.errorTracking) {\n this.errorTracker = new ErrorTracker(this.transport, {\n beforeSend: resolvedConfig.beforeSend,\n tags: resolvedConfig.tags,\n debug: resolvedConfig.debug,\n })\n this.errorTracker.start()\n }\n\n // Initialize performance tracking\n if (resolvedConfig.performanceTracking) {\n this.performanceTracker = new PerformanceTracker(this.transport, {\n sampleRate: resolvedConfig.sampleRate,\n debug: resolvedConfig.debug,\n })\n this.performanceTracker.start()\n }\n\n this.initialized = true\n\n if (resolvedConfig.debug) {\n console.log('[VibeGuard] SDK initialized successfully')\n }\n }\n\n /**\n * Manually capture an error\n */\n captureError(\n error: Error,\n options?: { extra?: Record<string, unknown>; tags?: Record<string, string> }\n ): void {\n if (!this.errorTracker) {\n console.warn('[VibeGuard] SDK not initialized or error tracking disabled')\n return\n }\n this.errorTracker.captureError(error, options?.extra)\n }\n\n /**\n * Manually capture a message\n */\n captureMessage(\n message: string,\n options?: { extra?: Record<string, unknown>; tags?: Record<string, string> }\n ): void {\n if (!this.errorTracker) {\n console.warn('[VibeGuard] SDK not initialized or error tracking disabled')\n return\n }\n this.errorTracker.captureMessage(message, options?.extra)\n }\n\n /**\n * Flush all pending events immediately\n */\n flush(): Promise<void> {\n if (!this.transport) {\n return Promise.resolve()\n }\n return this.transport.flush()\n }\n\n /**\n * Clean up and stop the SDK\n */\n destroy(): void {\n this.errorTracker?.stop()\n this.performanceTracker?.stop()\n this.transport?.destroy()\n this.initialized = false\n }\n\n /**\n * Check if SDK is initialized\n */\n isInitialized(): boolean {\n return this.initialized\n }\n}\n\n// Export singleton instance\nexport const VibeGuard = new VibeGuardSDK()\n\n// Auto-initialize from script tag if present\nif (typeof document !== 'undefined') {\n // Try to find script tag with data-app-id\n const initFromScriptTag = (): void => {\n const script = document.querySelector(\n 'script[data-app-id]'\n ) as HTMLScriptElement | null\n\n if (script && !VibeGuard.isInitialized()) {\n const appId = script.dataset.appId\n if (appId) {\n VibeGuard.init({\n appId,\n endpoint: script.dataset.endpoint,\n debug: script.dataset.debug === 'true',\n sampleRate: script.dataset.sampleRate\n ? parseFloat(script.dataset.sampleRate)\n : undefined,\n release: script.dataset.release,\n environment: script.dataset.environment,\n })\n }\n }\n }\n\n // Run after DOM is ready\n if (document.readyState === 'loading') {\n document.addEventListener('DOMContentLoaded', initFromScriptTag)\n } else {\n initFromScriptTag()\n }\n}\n\n// Re-export for convenience\nexport { generateFingerprint } from './fingerprint'\n","/**\n * React integration for VibeGuard SDK\n *\n * Usage:\n * ```tsx\n * import { VibeGuardProvider } from '@vibeguard/sdk/react'\n *\n * function App() {\n * return (\n * <VibeGuardProvider appId=\"vg_xxx\">\n * <YourApp />\n * </VibeGuardProvider>\n * )\n * }\n * ```\n */\n\nimport {\n createContext,\n useContext,\n useEffect,\n useRef,\n type ReactNode,\n} from 'react'\nimport { VibeGuard, type VibeGuardConfig } from './index'\n\n// Context for accessing VibeGuard in components\ninterface VibeGuardContextValue {\n captureError: (error: Error, extra?: Record<string, unknown>) => void\n captureMessage: (message: string, extra?: Record<string, unknown>) => void\n}\n\nconst VibeGuardContext = createContext<VibeGuardContextValue | null>(null)\n\n// Provider props extend config but require appId\ninterface VibeGuardProviderProps extends Omit<VibeGuardConfig, 'appId'> {\n appId: string\n children: ReactNode\n}\n\n/**\n * VibeGuard Provider component\n * Initializes the SDK and provides context to child components\n */\nexport function VibeGuardProvider({\n children,\n appId,\n ...config\n}: VibeGuardProviderProps): ReactNode {\n const initializedRef = useRef(false)\n\n useEffect(() => {\n // Only initialize once\n if (initializedRef.current) return\n initializedRef.current = true\n\n VibeGuard.init({ appId, ...config })\n\n return () => {\n VibeGuard.destroy()\n initializedRef.current = false\n }\n }, [appId]) // Re-initialize if appId changes\n\n const contextValue: VibeGuardContextValue = {\n captureError: (error, extra) => VibeGuard.captureError(error, { extra }),\n captureMessage: (message, extra) =>\n VibeGuard.captureMessage(message, { extra }),\n }\n\n return (\n <VibeGuardContext.Provider value={contextValue}>\n {children}\n </VibeGuardContext.Provider>\n )\n}\n\n/**\n * Hook to access VibeGuard context\n */\nexport function useVibeGuard(): VibeGuardContextValue {\n const context = useContext(VibeGuardContext)\n if (!context) {\n throw new Error('useVibeGuard must be used within a VibeGuardProvider')\n }\n return context\n}\n\n/**\n * Error boundary component that captures React errors\n */\ninterface ErrorBoundaryProps {\n children: ReactNode\n fallback?: ReactNode | ((error: Error) => ReactNode)\n onError?: (error: Error, errorInfo: React.ErrorInfo) => void\n}\n\ninterface ErrorBoundaryState {\n hasError: boolean\n error: Error | null\n}\n\nexport class VibeGuardErrorBoundary extends React.Component<\n ErrorBoundaryProps,\n ErrorBoundaryState\n> {\n constructor(props: ErrorBoundaryProps) {\n super(props)\n this.state = { hasError: false, error: null }\n }\n\n static getDerivedStateFromError(error: Error): ErrorBoundaryState {\n return { hasError: true, error }\n }\n\n componentDidCatch(error: Error, errorInfo: React.ErrorInfo): void {\n // Report to VibeGuard\n VibeGuard.captureError(error, {\n extra: {\n componentStack: errorInfo.componentStack,\n },\n })\n\n // Call user's onError callback if provided\n this.props.onError?.(error, errorInfo)\n }\n\n render(): ReactNode {\n if (this.state.hasError && this.state.error) {\n const { fallback } = this.props\n\n if (typeof fallback === 'function') {\n return fallback(this.state.error)\n }\n\n if (fallback) {\n return fallback\n }\n\n // Default fallback\n return null\n }\n\n return this.props.children\n }\n}\n\n// Need to import React for class component\nimport * as React from 'react'\n\n// Re-export main SDK for convenience\nexport { VibeGuard } from './index'\nexport type { VibeGuardConfig } from './index'\n"]}
@@ -0,0 +1,162 @@
1
+ import * as React from 'react';
2
+ import { ReactNode } from 'react';
3
+
4
+ /**
5
+ * VibeGuard SDK Types
6
+ */
7
+ interface VibeGuardConfig {
8
+ /** App ID from VibeGuard dashboard (format: vg_xxx) */
9
+ appId: string;
10
+ /** API endpoint (default: https://vibeguard.app/api/ingest/v1) */
11
+ endpoint?: string;
12
+ /** Enable error tracking (default: true) */
13
+ errorTracking?: boolean;
14
+ /** Enable performance tracking (default: true) */
15
+ performanceTracking?: boolean;
16
+ /** Sample rate 0-1 for performance metrics (default: 1.0) */
17
+ sampleRate?: number;
18
+ /** Enable debug logging (default: false) */
19
+ debug?: boolean;
20
+ /** Hook to filter/modify errors before sending */
21
+ beforeSend?: (event: ErrorEvent) => ErrorEvent | null;
22
+ /** Maximum events to batch before sending (default: 10) */
23
+ maxBatchSize?: number;
24
+ /** Maximum time in ms to wait before sending batch (default: 5000) */
25
+ flushInterval?: number;
26
+ /** Custom tags to add to all events */
27
+ tags?: Record<string, string>;
28
+ /** Release/version identifier */
29
+ release?: string;
30
+ /** Environment (e.g., 'production', 'staging') */
31
+ environment?: string;
32
+ }
33
+ interface ErrorEvent {
34
+ type: 'error';
35
+ message: string;
36
+ stack?: string;
37
+ fingerprint: string;
38
+ sourceFile?: string;
39
+ sourceLine?: number;
40
+ sourceColumn?: number;
41
+ url: string;
42
+ userAgent: string;
43
+ tags?: Record<string, string>;
44
+ extra?: Record<string, unknown>;
45
+ timestamp: number;
46
+ }
47
+
48
+ /**
49
+ * VibeGuard SDK
50
+ * Client-side error tracking and performance monitoring
51
+ *
52
+ * Usage:
53
+ * ```js
54
+ * import { VibeGuard } from '@vibeguard/sdk'
55
+ *
56
+ * VibeGuard.init({ appId: 'vg_xxx' })
57
+ *
58
+ * // Manual error capture
59
+ * VibeGuard.captureError(new Error('Something went wrong'))
60
+ *
61
+ * // Manual message
62
+ * VibeGuard.captureMessage('User clicked forbidden button', { extra: { userId: '123' } })
63
+ * ```
64
+ *
65
+ * Or via script tag:
66
+ * ```html
67
+ * <script src="https://cdn.vibeguard.app/sdk.js" data-app-id="vg_xxx"></script>
68
+ * ```
69
+ */
70
+
71
+ declare class VibeGuardSDK {
72
+ private transport;
73
+ private errorTracker;
74
+ private performanceTracker;
75
+ private initialized;
76
+ /**
77
+ * Initialize the VibeGuard SDK
78
+ */
79
+ init(config: VibeGuardConfig): void;
80
+ /**
81
+ * Manually capture an error
82
+ */
83
+ captureError(error: Error, options?: {
84
+ extra?: Record<string, unknown>;
85
+ tags?: Record<string, string>;
86
+ }): void;
87
+ /**
88
+ * Manually capture a message
89
+ */
90
+ captureMessage(message: string, options?: {
91
+ extra?: Record<string, unknown>;
92
+ tags?: Record<string, string>;
93
+ }): void;
94
+ /**
95
+ * Flush all pending events immediately
96
+ */
97
+ flush(): Promise<void>;
98
+ /**
99
+ * Clean up and stop the SDK
100
+ */
101
+ destroy(): void;
102
+ /**
103
+ * Check if SDK is initialized
104
+ */
105
+ isInitialized(): boolean;
106
+ }
107
+ declare const VibeGuard: VibeGuardSDK;
108
+
109
+ /**
110
+ * React integration for VibeGuard SDK
111
+ *
112
+ * Usage:
113
+ * ```tsx
114
+ * import { VibeGuardProvider } from '@vibeguard/sdk/react'
115
+ *
116
+ * function App() {
117
+ * return (
118
+ * <VibeGuardProvider appId="vg_xxx">
119
+ * <YourApp />
120
+ * </VibeGuardProvider>
121
+ * )
122
+ * }
123
+ * ```
124
+ */
125
+
126
+ interface VibeGuardContextValue {
127
+ captureError: (error: Error, extra?: Record<string, unknown>) => void;
128
+ captureMessage: (message: string, extra?: Record<string, unknown>) => void;
129
+ }
130
+ interface VibeGuardProviderProps extends Omit<VibeGuardConfig, 'appId'> {
131
+ appId: string;
132
+ children: ReactNode;
133
+ }
134
+ /**
135
+ * VibeGuard Provider component
136
+ * Initializes the SDK and provides context to child components
137
+ */
138
+ declare function VibeGuardProvider({ children, appId, ...config }: VibeGuardProviderProps): ReactNode;
139
+ /**
140
+ * Hook to access VibeGuard context
141
+ */
142
+ declare function useVibeGuard(): VibeGuardContextValue;
143
+ /**
144
+ * Error boundary component that captures React errors
145
+ */
146
+ interface ErrorBoundaryProps {
147
+ children: ReactNode;
148
+ fallback?: ReactNode | ((error: Error) => ReactNode);
149
+ onError?: (error: Error, errorInfo: React.ErrorInfo) => void;
150
+ }
151
+ interface ErrorBoundaryState {
152
+ hasError: boolean;
153
+ error: Error | null;
154
+ }
155
+ declare class VibeGuardErrorBoundary extends React.Component<ErrorBoundaryProps, ErrorBoundaryState> {
156
+ constructor(props: ErrorBoundaryProps);
157
+ static getDerivedStateFromError(error: Error): ErrorBoundaryState;
158
+ componentDidCatch(error: Error, errorInfo: React.ErrorInfo): void;
159
+ render(): ReactNode;
160
+ }
161
+
162
+ export { VibeGuard, type VibeGuardConfig, VibeGuardErrorBoundary, VibeGuardProvider, useVibeGuard };
@@ -0,0 +1,162 @@
1
+ import * as React from 'react';
2
+ import { ReactNode } from 'react';
3
+
4
+ /**
5
+ * VibeGuard SDK Types
6
+ */
7
+ interface VibeGuardConfig {
8
+ /** App ID from VibeGuard dashboard (format: vg_xxx) */
9
+ appId: string;
10
+ /** API endpoint (default: https://vibeguard.app/api/ingest/v1) */
11
+ endpoint?: string;
12
+ /** Enable error tracking (default: true) */
13
+ errorTracking?: boolean;
14
+ /** Enable performance tracking (default: true) */
15
+ performanceTracking?: boolean;
16
+ /** Sample rate 0-1 for performance metrics (default: 1.0) */
17
+ sampleRate?: number;
18
+ /** Enable debug logging (default: false) */
19
+ debug?: boolean;
20
+ /** Hook to filter/modify errors before sending */
21
+ beforeSend?: (event: ErrorEvent) => ErrorEvent | null;
22
+ /** Maximum events to batch before sending (default: 10) */
23
+ maxBatchSize?: number;
24
+ /** Maximum time in ms to wait before sending batch (default: 5000) */
25
+ flushInterval?: number;
26
+ /** Custom tags to add to all events */
27
+ tags?: Record<string, string>;
28
+ /** Release/version identifier */
29
+ release?: string;
30
+ /** Environment (e.g., 'production', 'staging') */
31
+ environment?: string;
32
+ }
33
+ interface ErrorEvent {
34
+ type: 'error';
35
+ message: string;
36
+ stack?: string;
37
+ fingerprint: string;
38
+ sourceFile?: string;
39
+ sourceLine?: number;
40
+ sourceColumn?: number;
41
+ url: string;
42
+ userAgent: string;
43
+ tags?: Record<string, string>;
44
+ extra?: Record<string, unknown>;
45
+ timestamp: number;
46
+ }
47
+
48
+ /**
49
+ * VibeGuard SDK
50
+ * Client-side error tracking and performance monitoring
51
+ *
52
+ * Usage:
53
+ * ```js
54
+ * import { VibeGuard } from '@vibeguard/sdk'
55
+ *
56
+ * VibeGuard.init({ appId: 'vg_xxx' })
57
+ *
58
+ * // Manual error capture
59
+ * VibeGuard.captureError(new Error('Something went wrong'))
60
+ *
61
+ * // Manual message
62
+ * VibeGuard.captureMessage('User clicked forbidden button', { extra: { userId: '123' } })
63
+ * ```
64
+ *
65
+ * Or via script tag:
66
+ * ```html
67
+ * <script src="https://cdn.vibeguard.app/sdk.js" data-app-id="vg_xxx"></script>
68
+ * ```
69
+ */
70
+
71
+ declare class VibeGuardSDK {
72
+ private transport;
73
+ private errorTracker;
74
+ private performanceTracker;
75
+ private initialized;
76
+ /**
77
+ * Initialize the VibeGuard SDK
78
+ */
79
+ init(config: VibeGuardConfig): void;
80
+ /**
81
+ * Manually capture an error
82
+ */
83
+ captureError(error: Error, options?: {
84
+ extra?: Record<string, unknown>;
85
+ tags?: Record<string, string>;
86
+ }): void;
87
+ /**
88
+ * Manually capture a message
89
+ */
90
+ captureMessage(message: string, options?: {
91
+ extra?: Record<string, unknown>;
92
+ tags?: Record<string, string>;
93
+ }): void;
94
+ /**
95
+ * Flush all pending events immediately
96
+ */
97
+ flush(): Promise<void>;
98
+ /**
99
+ * Clean up and stop the SDK
100
+ */
101
+ destroy(): void;
102
+ /**
103
+ * Check if SDK is initialized
104
+ */
105
+ isInitialized(): boolean;
106
+ }
107
+ declare const VibeGuard: VibeGuardSDK;
108
+
109
+ /**
110
+ * React integration for VibeGuard SDK
111
+ *
112
+ * Usage:
113
+ * ```tsx
114
+ * import { VibeGuardProvider } from '@vibeguard/sdk/react'
115
+ *
116
+ * function App() {
117
+ * return (
118
+ * <VibeGuardProvider appId="vg_xxx">
119
+ * <YourApp />
120
+ * </VibeGuardProvider>
121
+ * )
122
+ * }
123
+ * ```
124
+ */
125
+
126
+ interface VibeGuardContextValue {
127
+ captureError: (error: Error, extra?: Record<string, unknown>) => void;
128
+ captureMessage: (message: string, extra?: Record<string, unknown>) => void;
129
+ }
130
+ interface VibeGuardProviderProps extends Omit<VibeGuardConfig, 'appId'> {
131
+ appId: string;
132
+ children: ReactNode;
133
+ }
134
+ /**
135
+ * VibeGuard Provider component
136
+ * Initializes the SDK and provides context to child components
137
+ */
138
+ declare function VibeGuardProvider({ children, appId, ...config }: VibeGuardProviderProps): ReactNode;
139
+ /**
140
+ * Hook to access VibeGuard context
141
+ */
142
+ declare function useVibeGuard(): VibeGuardContextValue;
143
+ /**
144
+ * Error boundary component that captures React errors
145
+ */
146
+ interface ErrorBoundaryProps {
147
+ children: ReactNode;
148
+ fallback?: ReactNode | ((error: Error) => ReactNode);
149
+ onError?: (error: Error, errorInfo: React.ErrorInfo) => void;
150
+ }
151
+ interface ErrorBoundaryState {
152
+ hasError: boolean;
153
+ error: Error | null;
154
+ }
155
+ declare class VibeGuardErrorBoundary extends React.Component<ErrorBoundaryProps, ErrorBoundaryState> {
156
+ constructor(props: ErrorBoundaryProps);
157
+ static getDerivedStateFromError(error: Error): ErrorBoundaryState;
158
+ componentDidCatch(error: Error, errorInfo: React.ErrorInfo): void;
159
+ render(): ReactNode;
160
+ }
161
+
162
+ export { VibeGuard, type VibeGuardConfig, VibeGuardErrorBoundary, VibeGuardProvider, useVibeGuard };
package/dist/react.js ADDED
@@ -0,0 +1,5 @@
1
+ import*as y from'react';import {createContext,useRef,useEffect,useContext}from'react';import {jsx}from'react/jsx-runtime';var h="@vibeguard/sdk",g="0.1.0",T="vibeguard-offline",d="events",l=class{constructor(e){this.queue=[];this.flushTimer=null;this.db=null;this.config=e,this.initOfflineStorage(),this.setupUnloadHandler(),this.startFlushTimer();}enqueue(e){this.queue.push(e),this.config.debug&&console.log("[VibeGuard] Event queued:",e.type,e),this.queue.length>=this.config.maxBatchSize&&this.flush();}async flush(){if(this.queue.length===0)return;let e=[...this.queue];this.queue=[],this.config.debug&&console.log("[VibeGuard] Flushing",e.length,"events");let t={appId:this.config.appId,events:e,sdk:{name:h,version:g},release:this.config.release,environment:this.config.environment};await this.send(t)||await this.storeOffline(e);}async send(e){let t=JSON.stringify(e);if(typeof navigator<"u"&&navigator.sendBeacon){let r=new Blob([t],{type:"application/json"});if(navigator.sendBeacon(this.config.endpoint,r))return this.config.debug&&console.log("[VibeGuard] Sent via Beacon API"),true}try{let r=await fetch(this.config.endpoint,{method:"POST",headers:{"Content-Type":"application/json"},body:t,keepalive:!0});return r.ok?(this.config.debug&&console.log("[VibeGuard] Sent via fetch"),!0):(this.config.debug&&console.warn("[VibeGuard] Server returned",r.status),!1)}catch(r){return this.config.debug&&console.warn("[VibeGuard] Send failed:",r),false}}async initOfflineStorage(){if(!(typeof indexedDB>"u"))try{let e=indexedDB.open(T,1);e.onerror=()=>{this.config.debug&&console.warn("[VibeGuard] Failed to open IndexedDB");},e.onupgradeneeded=t=>{let r=t.target.result;r.objectStoreNames.contains(d)||r.createObjectStore(d,{autoIncrement:!0});},e.onsuccess=t=>{this.db=t.target.result,this.retryOfflineEvents();};}catch{}}async storeOffline(e){if(this.db)try{let r=this.db.transaction(d,"readwrite").objectStore(d);for(let n of e)r.add(n);this.config.debug&&console.log("[VibeGuard] Stored",e.length,"events offline");}catch{}}async retryOfflineEvents(){if(this.db)try{let r=this.db.transaction(d,"readwrite").objectStore(d).getAll();r.onsuccess=async()=>{let n=r.result;if(n.length===0)return;this.config.debug&&console.log("[VibeGuard] Retrying",n.length,"offline events");let o={appId:this.config.appId,events:n,sdk:{name:h,version:g},release:this.config.release,environment:this.config.environment};await this.send(o)&&this.db.transaction(d,"readwrite").objectStore(d).clear();};}catch{}}setupUnloadHandler(){if(typeof window>"u")return;let e=()=>{this.flush();};window.addEventListener("pagehide",e),window.addEventListener("visibilitychange",()=>{document.visibilityState==="hidden"&&e();});}startFlushTimer(){typeof setInterval>"u"||(this.flushTimer=setInterval(()=>{this.flush();},this.config.flushInterval));}destroy(){this.flushTimer&&(clearInterval(this.flushTimer),this.flushTimer=null),this.flush();}};function v(i,e){let t=S(i),r=w(e),o=[t,r].filter(Boolean).join("|");return P(o)}function S(i){return i.replace(/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/gi,"<uuid>").replace(/\b[0-9a-f]{24,}\b/gi,"<hex>").replace(/\b\d{4,}\b/g,"<num>").replace(/"[^"]{20,}"/g,'"<str>"').replace(/'[^']{20,}'/g,"'<str>'").replace(/\/[a-zA-Z0-9_-]{8,}(?=\/|$)/g,"/<path>").replace(/\s+/g," ").trim()}function w(i){if(!i)return "";let e=i.split(`
2
+ `);for(let t of e){if(!t.trim()||!t.includes("at ")||I(t))continue;let r=t.match(/(?:at\s+)?(?:\S+\s+)?\(?(.+?):(\d+):(\d+)\)?/);if(r){let[,n,o,s]=r;return `${k(n)}:${o}:${s}`}return t.trim().slice(0,100)}return ""}function I(i){return [/chrome-extension:/,/moz-extension:/,/safari-extension:/,/<anonymous>/,/native code/,/node_modules/,/webpack/,/react-dom/,/react\.development/,/react\.production/,/scheduler/,/@vibeguard\/sdk/,/vibeguard-sdk/].some(t=>t.test(i))}function k(i){return i.replace(/[?#].*$/,"").replace(/\.[a-f0-9]{8,}\.js$/,".js").replace(/https?:\/\/(localhost|127\.0\.0\.1)(:\d+)?/,"").replace(/^.*\/([^/]+)$/,"$1")}function P(i){let e=5381;for(let t=0;t<i.length;t++)e=(e<<5)+e^i.charCodeAt(t);return (e>>>0).toString(16).padStart(8,"0")}var u=class{constructor(e,t){this.originalOnError=null;this.originalOnUnhandledRejection=null;this.transport=e,this.config={beforeSend:t.beforeSend||(r=>r),tags:t.tags||{},debug:t.debug||false};}start(){typeof window>"u"||(this.setupGlobalErrorHandler(),this.setupUnhandledRejectionHandler(),this.setupConsoleErrorOverride());}stop(){typeof window>"u"||(this.originalOnError!==null&&(window.onerror=this.originalOnError),this.originalOnUnhandledRejection!==null&&(window.onunhandledrejection=this.originalOnUnhandledRejection));}captureError(e,t){let r=this.createErrorEvent(e.message,e.stack,t);this.sendEvent(r);}captureMessage(e,t){let r=this.createErrorEvent(e,void 0,t);this.sendEvent(r);}setupGlobalErrorHandler(){this.originalOnError=window.onerror,window.onerror=(e,t,r,n,o)=>{this.originalOnError&&this.originalOnError(e,t,r,n,o);let s=typeof e=="string"?e:"Unknown error",a=this.createErrorEvent(s,o?.stack,void 0,t,r,n);return this.sendEvent(a),false};}setupUnhandledRejectionHandler(){this.originalOnUnhandledRejection=window.onunhandledrejection,window.onunhandledrejection=e=>{this.originalOnUnhandledRejection&&this.originalOnUnhandledRejection(e);let t=e.reason,r="Unhandled Promise Rejection",n;t instanceof Error?(r=t.message||r,n=t.stack):typeof t=="string"?r=t:t&&typeof t=="object"&&(r=t.message||JSON.stringify(t).slice(0,200));let o=this.createErrorEvent(`[Unhandled Rejection] ${r}`,n);this.sendEvent(o);};}setupConsoleErrorOverride(){let e=console.error;console.error=(...t)=>{e.apply(console,t);let r=t[0];if(r instanceof Error){let n=this.createErrorEvent(r.message,r.stack,{consoleArgs:t.slice(1).map(String)});this.sendEvent(n);}};}createErrorEvent(e,t,r,n,o,s){if(t&&!n){let a=this.parseStack(t);n=a.file,o=a.line,s=a.column;}return {type:"error",message:e,stack:t,fingerprint:v(e,t),sourceFile:n,sourceLine:o,sourceColumn:s,url:typeof location<"u"?location.href:"",userAgent:typeof navigator<"u"?navigator.userAgent:"",tags:this.config.tags,extra:r,timestamp:Date.now()}}parseStack(e){let t=e.split(`
3
+ `);for(let r of t){if(!r.includes("at ")||r.includes("vibeguard-sdk"))continue;let n=r.match(/(?:at\s+)?(?:\S+\s+)?\(?(.+?):(\d+):(\d+)\)?/);if(n)return {file:n[1],line:parseInt(n[2],10),column:parseInt(n[3],10)}}return {}}sendEvent(e){let t=this.config.beforeSend(e);if(!t){this.config.debug&&console.log("[VibeGuard] Event filtered by beforeSend");return}this.transport.enqueue(t);}};var f=class{constructor(e,t){this.metrics={};this.observers=[];this.reportedMetrics=new Set;this.transport=e,this.sampleRate=t.sampleRate,this.debug=t.debug,this.sessionId=this.generateSessionId();}start(){if(!(typeof window>"u")){if(!this.shouldSample()){this.debug&&console.log("[VibeGuard] Performance sampling skipped");return}this.trackTTFB(),this.trackFCP(),this.trackLCP(),this.trackCLS(),this.trackINP(),this.setupUnloadHandler();}}stop(){for(let e of this.observers)e.disconnect();this.observers=[];}shouldSample(){return Math.random()<this.sampleRate}generateSessionId(){return Math.random().toString(36).slice(2,10)}trackTTFB(){try{let e=performance.getEntriesByType("navigation")[0];e&&(this.metrics.ttfb=e.responseStart-e.requestStart,this.debug&&console.log("[VibeGuard] TTFB:",this.metrics.ttfb));}catch{}}trackFCP(){try{let e=new PerformanceObserver(t=>{for(let r of t.getEntries())r.name==="first-contentful-paint"&&(this.metrics.fcp=r.startTime,this.debug&&console.log("[VibeGuard] FCP:",this.metrics.fcp),e.disconnect());});e.observe({type:"paint",buffered:!0}),this.observers.push(e);}catch{}}trackLCP(){try{let e=new PerformanceObserver(t=>{let r=t.getEntries(),n=r[r.length-1];n&&(this.metrics.lcp=n.renderTime||n.loadTime,this.debug&&console.log("[VibeGuard] LCP:",this.metrics.lcp));});e.observe({type:"largest-contentful-paint",buffered:!0}),this.observers.push(e);}catch{}}trackCLS(){try{let e=0,t=0,r=[],n=new PerformanceObserver(o=>{for(let s of o.getEntries())if(!s.hadRecentInput){let a=r[0],E=r[r.length-1];r.length&&(s.startTime-E.startTime>1e3||s.startTime-a.startTime>5e3)&&(t>e&&(e=t),t=0,r=[]),r.push(s),t+=s.value;}this.metrics.cls=Math.max(e,t),this.debug&&console.log("[VibeGuard] CLS:",this.metrics.cls);});n.observe({type:"layout-shift",buffered:!0}),this.observers.push(n);}catch{}}trackINP(){try{let e=new Map,t=new PerformanceObserver(r=>{for(let n of r.getEntries())if(n.interactionId){let o=n.duration,s=e.get(n.interactionId);(!s||o>s)&&e.set(n.interactionId,o);}if(e.size>0){let n=Array.from(e.values()).sort((s,a)=>a-s),o=Math.min(n.length-1,Math.floor(n.length/50));this.metrics.inp=n[o],!this.metrics.fid&&n.length>0&&(this.metrics.fid=n[n.length-1]),this.debug&&console.log("[VibeGuard] INP:",this.metrics.inp,"FID:",this.metrics.fid);}});t.observe({type:"event",buffered:!0,durationThreshold:16}),this.observers.push(t);}catch{}}setupUnloadHandler(){let e=()=>{if(!Object.values(this.metrics).some(n=>n!==void 0))return;let r={type:"performance",url:location.href,route:this.extractRoute(),metrics:{...this.metrics},userAgent:navigator.userAgent,connectionType:this.getConnectionType(),deviceMemory:this.getDeviceMemory(),hardwareConcurrency:navigator.hardwareConcurrency,sessionId:this.sessionId,timestamp:Date.now()};this.debug&&console.log("[VibeGuard] Sending performance metrics:",r),this.transport.enqueue(r);};document.addEventListener("visibilitychange",()=>{document.visibilityState==="hidden"&&e();}),window.addEventListener("pagehide",e);}extractRoute(){return location.pathname.replace(/\/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/gi,"/[id]").replace(/\/\d+(?=\/|$)/g,"/[id]").replace(/\/[a-zA-Z0-9]{8,}(?=\/|$)/g,"/[id]")}getConnectionType(){return navigator.connection?.effectiveType}getDeviceMemory(){return navigator.deviceMemory}};var R="https://vibeguard.app/api/ingest/v1",p=class{constructor(){this.transport=null;this.errorTracker=null;this.performanceTracker=null;this.initialized=false;}init(e){if(this.initialized){console.warn("[VibeGuard] SDK already initialized");return}if(!e.appId){console.error("[VibeGuard] appId is required");return}!e.appId.startsWith("vg_")&&!/^[a-f0-9-]{36}$/i.test(e.appId)&&console.warn('[VibeGuard] appId should start with "vg_" or be a valid UUID');let t={endpoint:e.endpoint||R,appId:e.appId,errorTracking:e.errorTracking!==false,performanceTracking:e.performanceTracking!==false,sampleRate:e.sampleRate??1,debug:e.debug||false,maxBatchSize:e.maxBatchSize||10,flushInterval:e.flushInterval||5e3,tags:e.tags||{},release:e.release,environment:e.environment,beforeSend:e.beforeSend};t.debug&&console.log("[VibeGuard] Initializing with config:",{...t,beforeSend:t.beforeSend?"[function]":void 0}),this.transport=new l({endpoint:t.endpoint,appId:t.appId,maxBatchSize:t.maxBatchSize,flushInterval:t.flushInterval,debug:t.debug,release:t.release,environment:t.environment}),t.errorTracking&&(this.errorTracker=new u(this.transport,{beforeSend:t.beforeSend,tags:t.tags,debug:t.debug}),this.errorTracker.start()),t.performanceTracking&&(this.performanceTracker=new f(this.transport,{sampleRate:t.sampleRate,debug:t.debug}),this.performanceTracker.start()),this.initialized=true,t.debug&&console.log("[VibeGuard] SDK initialized successfully");}captureError(e,t){if(!this.errorTracker){console.warn("[VibeGuard] SDK not initialized or error tracking disabled");return}this.errorTracker.captureError(e,t?.extra);}captureMessage(e,t){if(!this.errorTracker){console.warn("[VibeGuard] SDK not initialized or error tracking disabled");return}this.errorTracker.captureMessage(e,t?.extra);}flush(){return this.transport?this.transport.flush():Promise.resolve()}destroy(){this.errorTracker?.stop(),this.performanceTracker?.stop(),this.transport?.destroy(),this.initialized=false;}isInitialized(){return this.initialized}},c=new p;if(typeof document<"u"){let i=()=>{let e=document.querySelector("script[data-app-id]");if(e&&!c.isInitialized()){let t=e.dataset.appId;t&&c.init({appId:t,endpoint:e.dataset.endpoint,debug:e.dataset.debug==="true",sampleRate:e.dataset.sampleRate?parseFloat(e.dataset.sampleRate):void 0,release:e.dataset.release,environment:e.dataset.environment});}};document.readyState==="loading"?document.addEventListener("DOMContentLoaded",i):i();}var b=createContext(null);function $({children:i,appId:e,...t}){let r=useRef(false);useEffect(()=>{if(!r.current)return r.current=true,c.init({appId:e,...t}),()=>{c.destroy(),r.current=false;}},[e]);let n={captureError:(o,s)=>c.captureError(o,{extra:s}),captureMessage:(o,s)=>c.captureMessage(o,{extra:s})};return jsx(b.Provider,{value:n,children:i})}function H(){let i=useContext(b);if(!i)throw new Error("useVibeGuard must be used within a VibeGuardProvider");return i}var m=class extends y.Component{constructor(e){super(e),this.state={hasError:false,error:null};}static getDerivedStateFromError(e){return {hasError:true,error:e}}componentDidCatch(e,t){c.captureError(e,{extra:{componentStack:t.componentStack}}),this.props.onError?.(e,t);}render(){if(this.state.hasError&&this.state.error){let{fallback:e}=this.props;return typeof e=="function"?e(this.state.error):e||null}return this.props.children}};
4
+ export{c as VibeGuard,m as VibeGuardErrorBoundary,$ as VibeGuardProvider,H as useVibeGuard};//# sourceMappingURL=react.js.map
5
+ //# sourceMappingURL=react.js.map