@cherrypeak-org/cherryboard-web 1.1.0 → 1.2.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/CHANGELOG.md CHANGED
@@ -3,6 +3,43 @@
3
3
  All notable changes to `@cherrypeak-org/cherryboard-web` are documented here.
4
4
  This project adheres to [Semantic Versioning](https://semver.org/).
5
5
 
6
+ ## [1.2.0]
7
+
8
+ ### Added
9
+ - **Performance and visit tracking**, opt-in via `trackPerformance: true`.
10
+ Records how long API calls take and how many page views and visits the app
11
+ gets, and reports them on the environment page in the dashboard.
12
+
13
+ Timings come from `PerformanceObserver` rather than another `fetch` patch:
14
+ the browser already records them, so nothing is added to the request path and
15
+ nothing collides with other libraries that wrap `fetch` themselves.
16
+
17
+ Rollups are aggregated in the browser and posted once a minute, so a page
18
+ making 200 API calls sends one small summary rather than 200 events. Payload
19
+ size tracks the number of distinct routes, not traffic. The metrics endpoint
20
+ also has its own rate-limit budget, so performance data can never crowd out
21
+ error reporting.
22
+
23
+ Off by default — upgrading should not silently start sending new data about
24
+ someone's users.
25
+
26
+ - `metricsFlushIntervalMs` to control how often rollups are posted (default
27
+ 60000).
28
+
29
+ ### Notes on what is collected
30
+ - Paths are normalized before anything is recorded (`/api/orders/12345` becomes
31
+ `/api/orders/:id`), so no identifier reaches the server and the data stays
32
+ aggregatable.
33
+ - Query strings are dropped entirely rather than normalized — they routinely
34
+ carry tokens and email addresses, and say nothing about how long a request
35
+ took.
36
+ - Nothing is written to the visitor's device: no cookie, no storage, no
37
+ identifier. "Visits" counts page loads, not people. Recognising a returning
38
+ visitor would require storing something, and that trade was deliberately not
39
+ made.
40
+
41
+ ---
42
+
6
43
  ## [1.1.0]
7
44
 
8
45
  ### Changed
package/dist/index.cjs CHANGED
@@ -1,6 +1,6 @@
1
- 'use strict';var v="1.1.0";function d(){return typeof window<"u"&&typeof document<"u"}function p(){return new Date().toISOString()}function a(t,e){return e<=0?"":t.length<=e?t:`${t.slice(0,e-1)}\u2026`}function E(t,e=24e3){let r=new WeakSet;try{let n=JSON.stringify(t,(s,i)=>{if(i instanceof Error)return {name:i.name,message:i.message,stack:i.stack};if(typeof i=="object"&&i!==null){if(r.has(i))return "[Circular]";r.add(i);}if(typeof i=="bigint")return i.toString();if(typeof i!="function")return i});return n===void 0||n.length>e?void 0:n}catch{return}}function k(t,e){return !t||e.length===0?false:e.some(r=>typeof r=="string"?t.includes(r):r.test(t))}function A(t){let e=t.replace(/\/+$/,"");return `${/\/api\/v\d+$/.test(e)?e:`${e}/api/v1`}/errors/batch`}var h=class{constructor(e){this.max=e;this.items=[];this.teardown=[];}add(e){this.items.push({timestamp:e.timestamp??p(),category:e.category,message:a(e.message,500),level:e.level,data:e.data}),this.items.length>this.max&&this.items.shift();}snapshot(){return this.items.slice()}install(){d()&&(this.installHistory(),this.installClicks(),this.installFetch());}installHistory(){try{let e=window.history,r=s=>{let i=e[s];if(typeof i!="function")return ()=>{};let o=(...l)=>{try{let u=l[2];typeof u=="string"&&this.add({category:"navigation",message:`${s} \u2192 ${u}`});}catch{}return i.apply(window.history,l)};return e[s]=o,()=>{e[s]===o&&(e[s]=i);}};this.teardown.push(r("pushState"),r("replaceState"));let n=()=>this.add({category:"navigation",message:`popstate \u2192 ${location.pathname}`});window.addEventListener("popstate",n),this.teardown.push(()=>window.removeEventListener("popstate",n));}catch{}}installClicks(){try{let e=r=>{let n=r.target;if(!n||typeof n.tagName!="string")return;let s=n.id?`#${n.id}`:"",i=typeof n.className=="string"?n.className:"",o=i?`.${i.split(/\s+/).filter(Boolean).slice(0,2).join(".")}`:"";this.add({category:"click",message:`${n.tagName.toLowerCase()}${s}${o}`});};window.addEventListener("click",e,{capture:!0,passive:!0}),this.teardown.push(()=>window.removeEventListener("click",e,{capture:!0}));}catch{}}installFetch(){try{let e=window.fetch;if(typeof e!="function")return;let r=(...n)=>{let[s,i]=n,o=i?.method??(typeof s=="object"&&s&&"method"in s?s.method:"GET"),l=typeof s=="string"?s:s instanceof URL?s.href:s.url;return e.apply(window,n).then(u=>(this.add({category:"fetch",message:`${o} ${l} \u2192 ${u.status}`,level:u.ok?void 0:"Warning"}),u),u=>{throw this.add({category:"fetch",message:`${o} ${l} \u2192 failed`,level:"Warning"}),u})};window.fetch=r,this.teardown.push(()=>{window.fetch===r&&(window.fetch=e);});}catch{}}close(){for(let e of this.teardown.splice(0))try{e();}catch{}}};var m=class{constructor(e=4e3,r=100){this.windowMs=e;this.max=r;this.seen=new Map;}shouldSend(e){let r=Date.now(),n=this.seen.get(e);if(n!==void 0&&r-n<this.windowMs)return false;if(this.seen.set(e,r),this.seen.size>this.max){let s=this.seen.keys().next().value;s!==void 0&&this.seen.delete(s);}return true}};function I(t,e){let r=(e??"").split(`
2
- `).slice(0,4).map(n=>n.replace(/:\d+:\d+/g,"").replace(/\?[^\s)]*/g,"").replace(/https?:\/\/[^/]+/g,"").trim()).join("|");return `${t}::${r}`.slice(0,500)}function M(t){if(!d())return ()=>{};let e=t.config,r=[];if(e.captureUnhandledErrors||e.captureResourceErrors){let n=s=>{try{let i=s.target;if(i instanceof HTMLElement){if(!e.captureResourceErrors)return;let l=i,u=l.src||l.href;if(!u)return;t.captureMessage(`Resource failed to load: ${u}`,"Warning",{context:{resource:i.tagName.toLowerCase(),url:u}});return}if(!e.captureUnhandledErrors)return;let o=s;if(!o.error&&(!o.message||o.message==="Script error."))return;t.captureException(o.error??o.message);}catch{}};window.addEventListener("error",n,true),r.push(()=>window.removeEventListener("error",n,true));}if(e.captureUnhandledRejections){let n=s=>{try{t.captureException(s.reason??"Unhandled promise rejection",{context:{unhandledRejection:!0}});}catch{}};window.addEventListener("unhandledrejection",n),r.push(()=>window.removeEventListener("unhandledrejection",n));}if(e.captureConsole){let n=console;for(let s of ["error","warn"]){let i=n[s];if(typeof i!="function")continue;let o=(...l)=>{try{t.addBreadcrumb({category:"console",level:s==="error"?"Error":"Warning",message:l.map(D).join(" ").slice(0,500)});}catch{}return i.apply(console,l)};n[s]=o,r.push(()=>{n[s]===o&&(n[s]=i);});}}return ()=>{for(let n of r.splice(0))try{n();}catch{}}}function D(t){if(typeof t=="string")return t;if(t instanceof Error)return `${t.name}: ${t.message}`;try{return JSON.stringify(t)??String(t)}catch{return String(t)}}var g=2e3,S=8e3,C=4e3;function _(t){if(t instanceof Error)return {message:a(t.message||t.name||"Error",g),exceptionType:t.name||"Error",stackTrace:t.stack?a(t.stack,S):void 0,innerException:R(t.cause)};if(typeof t=="string")return {message:a(t,g),exceptionType:"Error"};if(t&&typeof t=="object"){let e=t,r=typeof e.message=="string"?e.message:N(e)??Object.prototype.toString.call(t),n=typeof e.name=="string"?e.name:"Error",s=typeof e.stack=="string"?e.stack:void 0;return {message:a(r,g),exceptionType:n,stackTrace:s?a(s,S):void 0,innerException:R(e.cause)}}return {message:a(String(t),g),exceptionType:"Error"}}function j(t){if(t.stackTrace)return t;try{let e=new Error(t.message).stack;if(e){let r=e.split(`
1
+ 'use strict';var k="1.2.0";function u(){return typeof window<"u"&&typeof document<"u"}function h(){return new Date().toISOString()}function a(t,e){return e<=0?"":t.length<=e?t:`${t.slice(0,e-1)}\u2026`}function R(t,e=24e3){let r=new WeakSet;try{let n=JSON.stringify(t,(s,i)=>{if(i instanceof Error)return {name:i.name,message:i.message,stack:i.stack};if(typeof i=="object"&&i!==null){if(r.has(i))return "[Circular]";r.add(i);}if(typeof i=="bigint")return i.toString();if(typeof i!="function")return i});return n===void 0||n.length>e?void 0:n}catch{return}}function C(t,e){return !t||e.length===0?false:e.some(r=>typeof r=="string"?t.includes(r):r.test(t))}function _(t){return `${L(t)}/errors/batch`}function N(t){return `${L(t)}/metrics`}function L(t){let e=t.replace(/\/+$/,"");return /\/api\/v\d+$/.test(e)?e:`${e}/api/v1`}var m=class{constructor(e){this.max=e;this.items=[];this.teardown=[];}add(e){this.items.push({timestamp:e.timestamp??h(),category:e.category,message:a(e.message,500),level:e.level,data:e.data}),this.items.length>this.max&&this.items.shift();}snapshot(){return this.items.slice()}install(){u()&&(this.installHistory(),this.installClicks(),this.installFetch());}installHistory(){try{let e=window.history,r=s=>{let i=e[s];if(typeof i!="function")return ()=>{};let o=(...d)=>{try{let c=d[2];typeof c=="string"&&this.add({category:"navigation",message:`${s} \u2192 ${c}`});}catch{}return i.apply(window.history,d)};return e[s]=o,()=>{e[s]===o&&(e[s]=i);}};this.teardown.push(r("pushState"),r("replaceState"));let n=()=>this.add({category:"navigation",message:`popstate \u2192 ${location.pathname}`});window.addEventListener("popstate",n),this.teardown.push(()=>window.removeEventListener("popstate",n));}catch{}}installClicks(){try{let e=r=>{let n=r.target;if(!n||typeof n.tagName!="string")return;let s=n.id?`#${n.id}`:"",i=typeof n.className=="string"?n.className:"",o=i?`.${i.split(/\s+/).filter(Boolean).slice(0,2).join(".")}`:"";this.add({category:"click",message:`${n.tagName.toLowerCase()}${s}${o}`});};window.addEventListener("click",e,{capture:!0,passive:!0}),this.teardown.push(()=>window.removeEventListener("click",e,{capture:!0}));}catch{}}installFetch(){try{let e=window.fetch;if(typeof e!="function")return;let r=(...n)=>{let[s,i]=n,o=i?.method??(typeof s=="object"&&s&&"method"in s?s.method:"GET"),d=typeof s=="string"?s:s instanceof URL?s.href:s.url;return e.apply(window,n).then(c=>(this.add({category:"fetch",message:`${o} ${d} \u2192 ${c.status}`,level:c.ok?void 0:"Warning"}),c),c=>{throw this.add({category:"fetch",message:`${o} ${d} \u2192 failed`,level:"Warning"}),c})};window.fetch=r,this.teardown.push(()=>{window.fetch===r&&(window.fetch=e);});}catch{}}close(){for(let e of this.teardown.splice(0))try{e();}catch{}}};var g=class{constructor(e=4e3,r=100){this.windowMs=e;this.max=r;this.seen=new Map;}shouldSend(e){let r=Date.now(),n=this.seen.get(e);if(n!==void 0&&r-n<this.windowMs)return false;if(this.seen.set(e,r),this.seen.size>this.max){let s=this.seen.keys().next().value;s!==void 0&&this.seen.delete(s);}return true}};function $(t,e){let r=(e??"").split(`
2
+ `).slice(0,4).map(n=>n.replace(/:\d+:\d+/g,"").replace(/\?[^\s)]*/g,"").replace(/https?:\/\/[^/]+/g,"").trim()).join("|");return `${t}::${r}`.slice(0,500)}function O(t){if(!u())return ()=>{};let e=t.config,r=[];if(e.captureUnhandledErrors||e.captureResourceErrors){let n=s=>{try{let i=s.target;if(i instanceof HTMLElement){if(!e.captureResourceErrors)return;let d=i,c=d.src||d.href;if(!c)return;t.captureMessage(`Resource failed to load: ${c}`,"Warning",{context:{resource:i.tagName.toLowerCase(),url:c}});return}if(!e.captureUnhandledErrors)return;let o=s;if(!o.error&&(!o.message||o.message==="Script error."))return;t.captureException(o.error??o.message);}catch{}};window.addEventListener("error",n,true),r.push(()=>window.removeEventListener("error",n,true));}if(e.captureUnhandledRejections){let n=s=>{try{t.captureException(s.reason??"Unhandled promise rejection",{context:{unhandledRejection:!0}});}catch{}};window.addEventListener("unhandledrejection",n),r.push(()=>window.removeEventListener("unhandledrejection",n));}if(e.captureConsole){let n=console;for(let s of ["error","warn"]){let i=n[s];if(typeof i!="function")continue;let o=(...d)=>{try{t.addBreadcrumb({category:"console",level:s==="error"?"Error":"Warning",message:d.map(V).join(" ").slice(0,500)});}catch{}return i.apply(console,d)};n[s]=o,r.push(()=>{n[s]===o&&(n[s]=i);});}}return ()=>{for(let n of r.splice(0))try{n();}catch{}}}function V(t){if(typeof t=="string")return t;if(t instanceof Error)return `${t.name}: ${t.message}`;try{return JSON.stringify(t)??String(t)}catch{return String(t)}}var y=2e3,T=8e3,S=4e3;function j(t){if(t instanceof Error)return {message:a(t.message||t.name||"Error",y),exceptionType:t.name||"Error",stackTrace:t.stack?a(t.stack,T):void 0,innerException:M(t.cause)};if(typeof t=="string")return {message:a(t,y),exceptionType:"Error"};if(t&&typeof t=="object"){let e=t,r=typeof e.message=="string"?e.message:q(e)??Object.prototype.toString.call(t),n=typeof e.name=="string"?e.name:"Error",s=typeof e.stack=="string"?e.stack:void 0;return {message:a(r,y),exceptionType:n,stackTrace:s?a(s,T):void 0,innerException:M(e.cause)}}return {message:a(String(t),y),exceptionType:"Error"}}function D(t){if(t.stackTrace)return t;try{let e=new Error(t.message).stack;if(e){let r=e.split(`
3
3
  `).slice(2).join(`
4
- `);return {...t,stackTrace:a(r||e,S)}}}catch{}return t}function R(t){if(t==null)return;if(t instanceof Error){let r=[`${t.name}: ${t.message}`];t.stack&&r.push(t.stack);let n=R(t.cause);return n&&r.push(`Caused by: ${n}`),a(r.join(`
5
- `),C)}let e=N(t);return e?a(e,C):a(String(t),C)}function N(t){try{let e=JSON.stringify(t);return e==="{}"?void 0:e}catch{return}}var B="cherryboard:queue:v1",y=class{constructor(e,r){this.enabled=e;this.maxItems=r;}get store(){if(!this.enabled||!d())return null;try{return window.localStorage}catch{return null}}push(e){let r=this.store;if(!(!r||e.length===0))try{let n=this.read().concat(e).slice(-this.maxItems);r.setItem(B,JSON.stringify(n));}catch{}}read(){let e=this.store;if(!e)return [];try{let r=e.getItem(B);if(!r)return [];let n=JSON.parse(r);return Array.isArray(n)?n:[]}catch{return []}}drain(){let e=this.read();return this.clear(),e}clear(){let e=this.store;if(e)try{e.removeItem(B);}catch{}}};var b=class{constructor(e=30,r=5){this.capacity=e;this.refillPerSec=r;this.tokens=e,this.last=Date.now();}allow(){let e=Date.now(),r=(e-this.last)/1e3;return this.tokens=Math.min(this.capacity,this.tokens+r*this.refillPerSec),this.last=e,this.tokens>=1?(this.tokens-=1,true):false}};var O=["password","passwd","secret","token","apikey","api_key","authorization","auth","cookie","session","credit","card","cvv","ssn"],H=["token","access_token","apikey","api_key","email","password","code","secret"],U="[Filtered]",q=/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/g;function T(t){let e=t;for(let r of H)e=e.replace(new RegExp(`([?&]${r}=)[^&#\\s]*`,"gi"),`$1${U}`);return e}function x(t,e=0){if(e>6)return t;if(typeof t=="string")return T(t).replace(q,U);if(Array.isArray(t))return t.map(r=>x(r,e+1));if(t&&typeof t=="object"){let r={};for(let[n,s]of Object.entries(t)){let i=n.toLowerCase();r[n]=O.some(o=>i.includes(o))?U:x(s,e+1);}return r}return t}function $(t){return {...t,message:T(t.message),context:x(t.context),breadcrumbs:t.breadcrumbs.map(e=>({...e,message:T(e.message),data:e.data?x(e.data):void 0}))}}var w=class{constructor(e,r){this.apiKey=r;this.endpoint=A(e);let n=typeof fetch=="function"?fetch.bind(globalThis):void 0;this.fetchImpl=n??(()=>Promise.reject(new Error("fetch unavailable")));}async send(e,r=false){if(e.length===0)return {ok:true,retryable:false,status:204};try{let n=await this.fetchImpl(this.endpoint,{method:"POST",headers:{"Content-Type":"application/json",Accept:"application/json","X-API-Key":this.apiKey},body:JSON.stringify({errors:e}),keepalive:r,mode:"cors",credentials:"omit"});if(n.status===429)return {ok:!1,retryable:!1,status:429,retryAfterMs:K(n.headers?.get?.("Retry-After"))};let s=n.status>=500;return {ok:n.ok,retryable:s,status:n.status}}catch{return {ok:false,retryable:true,status:0}}}};function K(t){if(!t)return 6e4;let r=Number(t);if(Number.isFinite(r)&&r>=0)return Math.min(r*1e3,36e5);let n=Date.parse(t);return Number.isNaN(n)?6e4:Math.min(Math.max(n-Date.now(),0),36e5)}function P(t,e,r){return Math.max(e,Math.min(r,t))}function F(t){return new Promise(e=>setTimeout(e,t))}var z=3e3;function W(t){return {apiKey:t.apiKey,apiUrl:t.apiUrl,environment:t.environment??"production",release:t.release,enabled:t.enabled??true,sampleRate:P(t.sampleRate??1,0,1),maxBatchSize:P(t.maxBatchSize??20,1,100),flushIntervalMs:t.flushIntervalMs??4e3,maxQueueItems:t.maxQueueItems??100,maxRetries:t.maxRetries??3,maxBreadcrumbs:t.maxBreadcrumbs??30,offlineStorage:t.offlineStorage??true,captureUnhandledErrors:t.captureUnhandledErrors??true,captureUnhandledRejections:t.captureUnhandledRejections??true,captureResourceErrors:t.captureResourceErrors??true,captureConsole:t.captureConsole??true,autoBreadcrumbs:t.autoBreadcrumbs??true,denyUrls:t.denyUrls??[],allowUrls:t.allowUrls??[],beforeSend:t.beforeSend,debug:t.debug??false}}var f=class{constructor(e){this.buffer=[];this.flushTimer=null;this.processing=false;this.rateLimitedUntil=0;this.discarded={};this.closed=false;this.scope={tags:{}};this.teardown=[];this.config=W(e),this.transport=new w(this.config.apiUrl,this.config.apiKey),this.deduper=new m(z),this.limiter=new b,this.queue=new y(this.config.offlineStorage,this.config.maxQueueItems),this.breadcrumbs=new h(this.config.maxBreadcrumbs),this.config.enabled&&(this.config.autoBreadcrumbs&&this.breadcrumbs.install(),this.teardown.push(M(this)),this.installLifecycle(),this.drainOffline());}captureException(e,r){try{this.process(j(_(e)),r?.severity??"Error",r);}catch(n){this.debug("captureException failed",n);}}captureMessage(e,r="Info",n){try{this.process({message:a(e,2e3),exceptionType:"Message"},n?.severity??r,n);}catch(s){this.debug("captureMessage failed",s);}}getDiscardedEvents(){return {...this.discarded}}discard(e,r=1){this.discarded[e]=(this.discarded[e]??0)+r;}addBreadcrumb(e){this.breadcrumbs.add(e);}setUser(e){this.scope.user=e??void 0;}setTag(e,r){this.scope.tags[e]=r;}setContext(e,r){this.scope.tags[e]=r;}close(){this.closed=true,this.flushTimer!==null&&(clearTimeout(this.flushTimer),this.flushTimer=null),this.flush(true),this.breadcrumbs.close();for(let e of this.teardown.splice(0))try{e();}catch{}}process(e,r,n){if(!this.config.enabled||this.closed)return;if(this.config.sampleRate<1&&Math.random()>this.config.sampleRate){this.discard("sampled");return}let s=`${e.stackTrace??""}
6
- ${d()?location.href:""}`;if(k(s,this.config.denyUrls)){this.discard("filtered");return}if(this.config.allowUrls.length>0&&!k(s,this.config.allowUrls)){this.discard("filtered");return}if(!this.deduper.shouldSend(I(e.message,e.stackTrace))){this.discard("deduped");return}let i={message:e.message,severity:r,timestamp:p(),exceptionType:e.exceptionType,stackTrace:e.stackTrace,innerException:e.innerException,userId:this.scope.user?.id,requestPath:d()?location.pathname:void 0,userAgent:d()?navigator.userAgent:void 0,context:this.buildContext(n),breadcrumbs:this.breadcrumbs.snapshot()};if(i=$(i),this.config.beforeSend){let o=this.config.beforeSend(i);if(!o){this.discard("filtered");return}i=o;}this.enqueue(this.toPayload(i));}buildContext(e){let r={sdk:{name:"cherryboard-web",version:v},environment:this.config.environment};return this.config.release&&(r.release=this.config.release),d()&&(r.url=location.href,document.referrer&&(r.referrer=document.referrer),r.language=navigator.language,r.viewport={width:window.innerWidth,height:window.innerHeight}),this.scope.user&&(r.user=this.scope.user),Object.keys(this.scope.tags).length>0&&(r.tags={...this.scope.tags}),e?.componentStack&&(r.componentStack=e.componentStack),e?.digest&&(r.digest=e.digest),e?.context&&Object.assign(r,e.context),r}toPayload(e){let r=E({...e.context,breadcrumbs:e.breadcrumbs});return r===void 0&&(r=E(e.context)),{message:e.message,stackTrace:e.stackTrace,severity:e.severity,timestamp:e.timestamp,userId:e.userId,requestPath:e.requestPath,userAgent:e.userAgent,exceptionType:e.exceptionType,innerException:e.innerException,metadata:r}}enqueue(e){this.buffer.push(e),this.buffer.length>=this.config.maxBatchSize?this.flush():this.scheduleFlush();}scheduleFlush(){this.closed||this.flushTimer===null&&(this.flushTimer=setTimeout(()=>{this.flushTimer=null,this.flush();},this.config.flushIntervalMs));}async flush(e=false){if(this.flushTimer!==null&&(clearTimeout(this.flushTimer),this.flushTimer=null),this.buffer.length!==0){if(e){if(Date.now()<this.rateLimitedUntil)return;for(;this.buffer.length>0;){let r=this.buffer.splice(0,this.config.maxBatchSize);if(!this.limiter.allow())break;this.transport.send(r,true);}return}if(Date.now()<this.rateLimitedUntil){this.scheduleFlush();return}if(!this.processing){this.processing=true;try{for(;this.buffer.length>0;){let r=this.buffer.splice(0,this.config.maxBatchSize);if(!this.limiter.allow()){this.debug("rate limited; dropping",r.length,"events"),this.discard("rate_limited",r.length);break}if(!await this.deliver(r)){this.queue.push(r);break}}}finally{this.processing=false;}}}}async deliver(e){for(let r=0;r<=this.config.maxRetries;r++){let n=await this.transport.send(e,false);if(n.ok)return true;if(n.status===429)return this.rateLimitedUntil=Date.now()+(n.retryAfterMs??6e4),this.debug("rate limited by server; pausing for",n.retryAfterMs,"ms"),false;if(!n.retryable)return this.debug("non-retryable response",n.status,"\u2014 dropping batch"),this.discard("send_failed",e.length),true;if(r===this.config.maxRetries)return false;await F(P(2**r*1e3+Math.random()*250,0,15e3));}return false}drainOffline(){let e=this.queue.drain();e.length>0&&(this.buffer.push(...e),this.scheduleFlush());}installLifecycle(){if(!d())return;let e=()=>{document.visibilityState==="hidden"&&this.flush(true);},r=()=>{this.flush(true);},n=()=>this.drainOffline();document.addEventListener("visibilitychange",e),window.addEventListener("pagehide",r),window.addEventListener("online",n),this.teardown.push(()=>{document.removeEventListener("visibilitychange",e),window.removeEventListener("pagehide",r),window.removeEventListener("online",n);});}debug(...e){this.config.debug&&console.warn("[cherryboard]",...e);}};var L="__CHERRYBOARD__";function c(){let t=globalThis,e=t[L];return e||(e={},t[L]=e),e}function we(t){let e=c();return e.client||(e.client=new f(t)),e.client}function ve(){return c().client??null}function Ee(){return c().client!=null}function ke(t,e){c().client?.captureException(t,e);}function Ce(t,e,r){c().client?.captureMessage(t,e,r);}function Se(t){c().client?.addBreadcrumb(t);}function Re(t){c().client?.setUser(t);}function Be(t,e){c().client?.setTag(t,e);}function Ue(t,e){c().client?.setContext(t,e);}function Te(){let t=c().client;return t?t.flush():Promise.resolve()}function Pe(t,e,r){c().client?.captureException(t,{severity:"Error",context:{source:"nextjs-server",...e?.path?{requestPath:e.path}:{},...e?.method?{requestMethod:e.method}:{},...r??{}}});}function Ae(){return c().client?.getDiscardedEvents()??{}}function Ie(){let t=c();t.client?.close(),t.client=void 0;}exports.CherryBoardClient=f;exports.SDK_VERSION=v;exports.addBreadcrumb=Se;exports.captureException=ke;exports.captureMessage=Ce;exports.captureRequestError=Pe;exports.close=Ie;exports.flush=Te;exports.getClient=ve;exports.getDiscardedEvents=Ae;exports.init=we;exports.isInitialized=Ee;exports.setContext=Ue;exports.setTag=Be;exports.setUser=Re;
4
+ `);return {...t,stackTrace:a(r||e,T)}}}catch{}return t}function M(t){if(t==null)return;if(t instanceof Error){let r=[`${t.name}: ${t.message}`];t.stack&&r.push(t.stack);let n=M(t.cause);return n&&r.push(`Caused by: ${n}`),a(r.join(`
5
+ `),S)}let e=q(t);return e?a(e,S):a(String(t),S)}function q(t){try{let e=JSON.stringify(t);return e==="{}"?void 0:e}catch{return}}var z=/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i,G=/^[0-9a-f]{16,}$/i,X=/^\d+$/,W=/^(?=.*\d)[A-Za-z0-9_-]{12,}$/;function J(t){return z.test(t)||X.test(t)||G.test(t)||W.test(t)}function B(t,e){let r;try{r=new URL(t,e??(typeof location<"u"?location.href:void 0)).pathname;}catch{return null}if(!r||r==="/")return "/";let n=r.split("/").filter(Boolean);if(n.length===0)return "/";let s=n.slice(0,12).map(o=>J(o)?":id":o);n.length>12&&s.push("\u2026");let i="/"+s.join("/");return i.length>300?i.slice(0,300):i}var f=[50,100,250,500,1e3,2500,5e3];function H(t){for(let e=0;e<f.length;e++)if(t<=f[e])return e;return f.length}var b=class{constructor(e){this.options=e;this.requests=new Map;this.pageViews=new Map;this.teardown=[];this.closed=false;this.endpoint=N(e.apiUrl);let r=typeof fetch=="function"?fetch.bind(globalThis):void 0;this.fetchImpl=r??(()=>Promise.reject(new Error("fetch unavailable")));}start(){!u()||this.closed||(this.recordPageView(location.pathname,true),this.observeResources(),this.observeNavigation(),this.observeVisibility(),this.timer=setInterval(()=>{this.flush();},this.options.flushIntervalMs));}observeResources(){if(!(typeof PerformanceObserver>"u"))try{this.observer=new PerformanceObserver(e=>{for(let r of e.getEntries())this.recordResource(r);}),this.observer.observe({type:"resource",buffered:!0});}catch{}}recordResource(e){if(e.initiatorType!=="fetch"&&e.initiatorType!=="xmlhttprequest"||e.name.startsWith(this.endpoint)||e.name.includes("/api/v1/errors/batch"))return;let r=B(e.name);if(!r)return;let n=Math.round(e.duration);n<=0||this.addRequest(r,"ALL",n,false);}addRequest(e,r,n,s){let i=`${r} ${e}`,o=this.requests.get(i);if(!o){if(this.requests.size>=this.options.maxRoutes)return;o={route:e,method:r,count:0,errorCount:0,sumMs:0,maxMs:0,buckets:new Array(f.length+1).fill(0)},this.requests.set(i,o);}o.count++,s&&o.errorCount++,o.sumMs+=n,n>o.maxMs&&(o.maxMs=n),o.buckets[H(n)]++;}observeNavigation(){let e=()=>this.recordPageView(location.pathname,false);try{let r=window.history,n=s=>{let i=r[s];if(typeof i!="function")return ()=>{};let o=(...d)=>{let c=i.apply(window.history,d);return e(),c};return r[s]=o,()=>{r[s]===o&&(r[s]=i);}};this.teardown.push(n("pushState"),n("replaceState")),window.addEventListener("popstate",e),this.teardown.push(()=>window.removeEventListener("popstate",e));}catch{}}recordPageView(e,r){let n=B(e);if(!n)return;let s=this.pageViews.get(n);if(!s){if(this.pageViews.size>=this.options.maxRoutes)return;s={route:n,views:0,visits:0},this.pageViews.set(n,s);}s.views++,r&&s.visits++;}observeVisibility(){let e=()=>{document.visibilityState==="hidden"&&this.flush(true);};document.addEventListener("visibilitychange",e),this.teardown.push(()=>document.removeEventListener("visibilitychange",e));}async flush(e=false){if(this.requests.size===0&&this.pageViews.size===0)return;let r={requests:Array.from(this.requests.values()).map(n=>({route:n.route,method:n.method,count:n.count,errorCount:n.errorCount,sumMs:n.sumMs,maxMs:n.maxMs,buckets:n.buckets})),pageViews:Array.from(this.pageViews.values()).map(n=>({route:n.route,views:n.views,visits:n.visits}))};this.requests.clear(),this.pageViews.clear();try{await this.fetchImpl(this.endpoint,{method:"POST",headers:{"Content-Type":"application/json","X-API-Key":this.options.apiKey},body:JSON.stringify(r),keepalive:e,mode:"cors",credentials:"omit"});}catch{this.options.debug&&console.warn("[cherryboard] metrics flush failed");}}close(){this.closed=true,this.timer&&clearInterval(this.timer),this.observer?.disconnect();for(let e of this.teardown)e();this.teardown=[];}};var P="cherryboard:queue:v1",v=class{constructor(e,r){this.enabled=e;this.maxItems=r;}get store(){if(!this.enabled||!u())return null;try{return window.localStorage}catch{return null}}push(e){let r=this.store;if(!(!r||e.length===0))try{let n=this.read().concat(e).slice(-this.maxItems);r.setItem(P,JSON.stringify(n));}catch{}}read(){let e=this.store;if(!e)return [];try{let r=e.getItem(P);if(!r)return [];let n=JSON.parse(r);return Array.isArray(n)?n:[]}catch{return []}}drain(){let e=this.read();return this.clear(),e}clear(){let e=this.store;if(e)try{e.removeItem(P);}catch{}}};var w=class{constructor(e=30,r=5){this.capacity=e;this.refillPerSec=r;this.tokens=e,this.last=Date.now();}allow(){let e=Date.now(),r=(e-this.last)/1e3;return this.tokens=Math.min(this.capacity,this.tokens+r*this.refillPerSec),this.last=e,this.tokens>=1?(this.tokens-=1,true):false}};var Q=["password","passwd","secret","token","apikey","api_key","authorization","auth","cookie","session","credit","card","cvv","ssn"],Y=["token","access_token","apikey","api_key","email","password","code","secret"],U="[Filtered]",Z=/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/g;function A(t){let e=t;for(let r of Y)e=e.replace(new RegExp(`([?&]${r}=)[^&#\\s]*`,"gi"),`$1${U}`);return e}function x(t,e=0){if(e>6)return t;if(typeof t=="string")return A(t).replace(Z,U);if(Array.isArray(t))return t.map(r=>x(r,e+1));if(t&&typeof t=="object"){let r={};for(let[n,s]of Object.entries(t)){let i=n.toLowerCase();r[n]=Q.some(o=>i.includes(o))?U:x(s,e+1);}return r}return t}function K(t){return {...t,message:A(t.message),context:x(t.context),breadcrumbs:t.breadcrumbs.map(e=>({...e,message:A(e.message),data:e.data?x(e.data):void 0}))}}var E=class{constructor(e,r){this.apiKey=r;this.endpoint=_(e);let n=typeof fetch=="function"?fetch.bind(globalThis):void 0;this.fetchImpl=n??(()=>Promise.reject(new Error("fetch unavailable")));}async send(e,r=false){if(e.length===0)return {ok:true,retryable:false,status:204};try{let n=await this.fetchImpl(this.endpoint,{method:"POST",headers:{"Content-Type":"application/json",Accept:"application/json","X-API-Key":this.apiKey},body:JSON.stringify({errors:e}),keepalive:r,mode:"cors",credentials:"omit"});if(n.status===429)return {ok:!1,retryable:!1,status:429,retryAfterMs:ee(n.headers?.get?.("Retry-After"))};let s=n.status>=500;return {ok:n.ok,retryable:s,status:n.status}}catch{return {ok:false,retryable:true,status:0}}}};function ee(t){if(!t)return 6e4;let r=Number(t);if(Number.isFinite(r)&&r>=0)return Math.min(r*1e3,36e5);let n=Date.parse(t);return Number.isNaN(n)?6e4:Math.min(Math.max(n-Date.now(),0),36e5)}var te=200;function I(t,e,r){return Math.max(e,Math.min(r,t))}function re(t){return new Promise(e=>setTimeout(e,t))}var ne=3e3;function se(t){return {apiKey:t.apiKey,apiUrl:t.apiUrl,environment:t.environment??"production",release:t.release,enabled:t.enabled??true,sampleRate:I(t.sampleRate??1,0,1),maxBatchSize:I(t.maxBatchSize??20,1,100),flushIntervalMs:t.flushIntervalMs??4e3,maxQueueItems:t.maxQueueItems??100,maxRetries:t.maxRetries??3,maxBreadcrumbs:t.maxBreadcrumbs??30,offlineStorage:t.offlineStorage??true,captureUnhandledErrors:t.captureUnhandledErrors??true,captureUnhandledRejections:t.captureUnhandledRejections??true,captureResourceErrors:t.captureResourceErrors??true,captureConsole:t.captureConsole??true,autoBreadcrumbs:t.autoBreadcrumbs??true,denyUrls:t.denyUrls??[],allowUrls:t.allowUrls??[],beforeSend:t.beforeSend,trackPerformance:t.trackPerformance??false,metricsFlushIntervalMs:t.metricsFlushIntervalMs??6e4,debug:t.debug??false}}var p=class{constructor(e){this.buffer=[];this.flushTimer=null;this.processing=false;this.rateLimitedUntil=0;this.discarded={};this.closed=false;this.scope={tags:{}};this.teardown=[];this.config=se(e),this.transport=new E(this.config.apiUrl,this.config.apiKey),this.deduper=new g(ne),this.limiter=new w,this.queue=new v(this.config.offlineStorage,this.config.maxQueueItems),this.config.trackPerformance&&this.config.enabled&&(this.metrics=new b({apiKey:this.config.apiKey,apiUrl:this.config.apiUrl,flushIntervalMs:this.config.metricsFlushIntervalMs,maxRoutes:te,debug:this.config.debug}),this.metrics.start()),this.breadcrumbs=new m(this.config.maxBreadcrumbs),this.config.enabled&&(this.config.autoBreadcrumbs&&this.breadcrumbs.install(),this.teardown.push(O(this)),this.installLifecycle(),this.drainOffline());}captureException(e,r){try{this.process(D(j(e)),r?.severity??"Error",r);}catch(n){this.debug("captureException failed",n);}}captureMessage(e,r="Info",n){try{this.process({message:a(e,2e3),exceptionType:"Message"},n?.severity??r,n);}catch(s){this.debug("captureMessage failed",s);}}getDiscardedEvents(){return {...this.discarded}}discard(e,r=1){this.discarded[e]=(this.discarded[e]??0)+r;}addBreadcrumb(e){this.breadcrumbs.add(e);}setUser(e){this.scope.user=e??void 0;}setTag(e,r){this.scope.tags[e]=r;}setContext(e,r){this.scope.tags[e]=r;}close(){this.closed=true,this.flushTimer!==null&&(clearTimeout(this.flushTimer),this.flushTimer=null),this.flush(true),this.metrics?.close(),this.breadcrumbs.close();for(let e of this.teardown.splice(0))try{e();}catch{}}process(e,r,n){if(!this.config.enabled||this.closed)return;if(this.config.sampleRate<1&&Math.random()>this.config.sampleRate){this.discard("sampled");return}let s=`${e.stackTrace??""}
6
+ ${u()?location.href:""}`;if(C(s,this.config.denyUrls)){this.discard("filtered");return}if(this.config.allowUrls.length>0&&!C(s,this.config.allowUrls)){this.discard("filtered");return}if(!this.deduper.shouldSend($(e.message,e.stackTrace))){this.discard("deduped");return}let i={message:e.message,severity:r,timestamp:h(),exceptionType:e.exceptionType,stackTrace:e.stackTrace,innerException:e.innerException,userId:this.scope.user?.id,requestPath:u()?location.pathname:void 0,userAgent:u()?navigator.userAgent:void 0,context:this.buildContext(n),breadcrumbs:this.breadcrumbs.snapshot()};if(i=K(i),this.config.beforeSend){let o=this.config.beforeSend(i);if(!o){this.discard("filtered");return}i=o;}this.enqueue(this.toPayload(i));}buildContext(e){let r={sdk:{name:"cherryboard-web",version:k},environment:this.config.environment};return this.config.release&&(r.release=this.config.release),u()&&(r.url=location.href,document.referrer&&(r.referrer=document.referrer),r.language=navigator.language,r.viewport={width:window.innerWidth,height:window.innerHeight}),this.scope.user&&(r.user=this.scope.user),Object.keys(this.scope.tags).length>0&&(r.tags={...this.scope.tags}),e?.componentStack&&(r.componentStack=e.componentStack),e?.digest&&(r.digest=e.digest),e?.context&&Object.assign(r,e.context),r}toPayload(e){let r=R({...e.context,breadcrumbs:e.breadcrumbs});return r===void 0&&(r=R(e.context)),{message:e.message,stackTrace:e.stackTrace,severity:e.severity,timestamp:e.timestamp,userId:e.userId,requestPath:e.requestPath,userAgent:e.userAgent,exceptionType:e.exceptionType,innerException:e.innerException,metadata:r}}enqueue(e){this.buffer.push(e),this.buffer.length>=this.config.maxBatchSize?this.flush():this.scheduleFlush();}scheduleFlush(){this.closed||this.flushTimer===null&&(this.flushTimer=setTimeout(()=>{this.flushTimer=null,this.flush();},this.config.flushIntervalMs));}async flush(e=false){if(this.flushTimer!==null&&(clearTimeout(this.flushTimer),this.flushTimer=null),this.buffer.length!==0){if(e){if(Date.now()<this.rateLimitedUntil)return;for(;this.buffer.length>0;){let r=this.buffer.splice(0,this.config.maxBatchSize);if(!this.limiter.allow())break;this.transport.send(r,true);}return}if(Date.now()<this.rateLimitedUntil){this.scheduleFlush();return}if(!this.processing){this.processing=true;try{for(;this.buffer.length>0;){let r=this.buffer.splice(0,this.config.maxBatchSize);if(!this.limiter.allow()){this.debug("rate limited; dropping",r.length,"events"),this.discard("rate_limited",r.length);break}if(!await this.deliver(r)){this.queue.push(r);break}}}finally{this.processing=false;}}}}async deliver(e){for(let r=0;r<=this.config.maxRetries;r++){let n=await this.transport.send(e,false);if(n.ok)return true;if(n.status===429)return this.rateLimitedUntil=Date.now()+(n.retryAfterMs??6e4),this.debug("rate limited by server; pausing for",n.retryAfterMs,"ms"),false;if(!n.retryable)return this.debug("non-retryable response",n.status,"\u2014 dropping batch"),this.discard("send_failed",e.length),true;if(r===this.config.maxRetries)return false;await re(I(2**r*1e3+Math.random()*250,0,15e3));}return false}drainOffline(){let e=this.queue.drain();e.length>0&&(this.buffer.push(...e),this.scheduleFlush());}installLifecycle(){if(!u())return;let e=()=>{document.visibilityState==="hidden"&&this.flush(true);},r=()=>{this.flush(true);},n=()=>this.drainOffline();document.addEventListener("visibilitychange",e),window.addEventListener("pagehide",r),window.addEventListener("online",n),this.teardown.push(()=>{document.removeEventListener("visibilitychange",e),window.removeEventListener("pagehide",r),window.removeEventListener("online",n);});}debug(...e){this.config.debug&&console.warn("[cherryboard]",...e);}};var F="__CHERRYBOARD__";function l(){let t=globalThis,e=t[F];return e||(e={},t[F]=e),e}function $e(t){let e=l();return e.client||(e.client=new p(t)),e.client}function Oe(){return l().client??null}function je(){return l().client!=null}function De(t,e){l().client?.captureException(t,e);}function qe(t,e,r){l().client?.captureMessage(t,e,r);}function He(t){l().client?.addBreadcrumb(t);}function Ke(t){l().client?.setUser(t);}function Fe(t,e){l().client?.setTag(t,e);}function Ve(t,e){l().client?.setContext(t,e);}function ze(){let t=l().client;return t?t.flush():Promise.resolve()}function Ge(t,e,r){l().client?.captureException(t,{severity:"Error",context:{source:"nextjs-server",...e?.path?{requestPath:e.path}:{},...e?.method?{requestMethod:e.method}:{},...r??{}}});}function Xe(){return l().client?.getDiscardedEvents()??{}}function We(){let t=l();t.client?.close(),t.client=void 0;}exports.CherryBoardClient=p;exports.SDK_VERSION=k;exports.addBreadcrumb=He;exports.captureException=De;exports.captureMessage=qe;exports.captureRequestError=Ge;exports.close=We;exports.flush=ze;exports.getClient=Oe;exports.getDiscardedEvents=Xe;exports.init=$e;exports.isInitialized=je;exports.setContext=Ve;exports.setTag=Fe;exports.setUser=Ke;
package/dist/index.d.cts CHANGED
@@ -1,5 +1,5 @@
1
1
  /** SDK version — kept in sync with package.json. */
2
- declare const SDK_VERSION = "1.1.0";
2
+ declare const SDK_VERSION = "1.2.0";
3
3
  /** Severity levels — these strings match the backend `ErrorSeverity` enum exactly. */
4
4
  type Severity = 'Debug' | 'Info' | 'Warning' | 'Error' | 'Critical';
5
5
  /** A trail entry giving context that led up to an error. */
@@ -88,6 +88,16 @@ interface CherryBoardConfig {
88
88
  captureResourceErrors?: boolean;
89
89
  /** Turn console.error/warn into breadcrumbs (never into events). Default true. */
90
90
  captureConsole?: boolean;
91
+ /**
92
+ * Collect API request timings and page views alongside errors.
93
+ *
94
+ * Off by default: upgrading the package must not silently start sending new
95
+ * data about someone's users. Aggregated in the browser and stripped of
96
+ * identifiers before it leaves — see the performance docs.
97
+ */
98
+ trackPerformance?: boolean;
99
+ /** How often aggregated metrics are posted. Default 60000 (once a minute). */
100
+ metricsFlushIntervalMs?: number;
91
101
  /** Auto-record navigation / click / fetch breadcrumbs. Default true. */
92
102
  autoBreadcrumbs?: boolean;
93
103
  /** Drop events whose stack/URL matches any of these. */
@@ -110,6 +120,8 @@ interface ResolvedConfig {
110
120
  environment: string;
111
121
  release?: string;
112
122
  enabled: boolean;
123
+ trackPerformance: boolean;
124
+ metricsFlushIntervalMs: number;
113
125
  sampleRate: number;
114
126
  maxBatchSize: number;
115
127
  flushIntervalMs: number;
@@ -163,6 +175,7 @@ declare class CherryBoardClient {
163
175
  private readonly deduper;
164
176
  private readonly limiter;
165
177
  private readonly queue;
178
+ private readonly metrics?;
166
179
  private buffer;
167
180
  private flushTimer;
168
181
  private processing;
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /** SDK version — kept in sync with package.json. */
2
- declare const SDK_VERSION = "1.1.0";
2
+ declare const SDK_VERSION = "1.2.0";
3
3
  /** Severity levels — these strings match the backend `ErrorSeverity` enum exactly. */
4
4
  type Severity = 'Debug' | 'Info' | 'Warning' | 'Error' | 'Critical';
5
5
  /** A trail entry giving context that led up to an error. */
@@ -88,6 +88,16 @@ interface CherryBoardConfig {
88
88
  captureResourceErrors?: boolean;
89
89
  /** Turn console.error/warn into breadcrumbs (never into events). Default true. */
90
90
  captureConsole?: boolean;
91
+ /**
92
+ * Collect API request timings and page views alongside errors.
93
+ *
94
+ * Off by default: upgrading the package must not silently start sending new
95
+ * data about someone's users. Aggregated in the browser and stripped of
96
+ * identifiers before it leaves — see the performance docs.
97
+ */
98
+ trackPerformance?: boolean;
99
+ /** How often aggregated metrics are posted. Default 60000 (once a minute). */
100
+ metricsFlushIntervalMs?: number;
91
101
  /** Auto-record navigation / click / fetch breadcrumbs. Default true. */
92
102
  autoBreadcrumbs?: boolean;
93
103
  /** Drop events whose stack/URL matches any of these. */
@@ -110,6 +120,8 @@ interface ResolvedConfig {
110
120
  environment: string;
111
121
  release?: string;
112
122
  enabled: boolean;
123
+ trackPerformance: boolean;
124
+ metricsFlushIntervalMs: number;
113
125
  sampleRate: number;
114
126
  maxBatchSize: number;
115
127
  flushIntervalMs: number;
@@ -163,6 +175,7 @@ declare class CherryBoardClient {
163
175
  private readonly deduper;
164
176
  private readonly limiter;
165
177
  private readonly queue;
178
+ private readonly metrics?;
166
179
  private buffer;
167
180
  private flushTimer;
168
181
  private processing;
package/dist/index.mjs CHANGED
@@ -1,6 +1,6 @@
1
- var v="1.1.0";function d(){return typeof window<"u"&&typeof document<"u"}function p(){return new Date().toISOString()}function a(t,e){return e<=0?"":t.length<=e?t:`${t.slice(0,e-1)}\u2026`}function E(t,e=24e3){let r=new WeakSet;try{let n=JSON.stringify(t,(s,i)=>{if(i instanceof Error)return {name:i.name,message:i.message,stack:i.stack};if(typeof i=="object"&&i!==null){if(r.has(i))return "[Circular]";r.add(i);}if(typeof i=="bigint")return i.toString();if(typeof i!="function")return i});return n===void 0||n.length>e?void 0:n}catch{return}}function k(t,e){return !t||e.length===0?false:e.some(r=>typeof r=="string"?t.includes(r):r.test(t))}function A(t){let e=t.replace(/\/+$/,"");return `${/\/api\/v\d+$/.test(e)?e:`${e}/api/v1`}/errors/batch`}var h=class{constructor(e){this.max=e;this.items=[];this.teardown=[];}add(e){this.items.push({timestamp:e.timestamp??p(),category:e.category,message:a(e.message,500),level:e.level,data:e.data}),this.items.length>this.max&&this.items.shift();}snapshot(){return this.items.slice()}install(){d()&&(this.installHistory(),this.installClicks(),this.installFetch());}installHistory(){try{let e=window.history,r=s=>{let i=e[s];if(typeof i!="function")return ()=>{};let o=(...l)=>{try{let u=l[2];typeof u=="string"&&this.add({category:"navigation",message:`${s} \u2192 ${u}`});}catch{}return i.apply(window.history,l)};return e[s]=o,()=>{e[s]===o&&(e[s]=i);}};this.teardown.push(r("pushState"),r("replaceState"));let n=()=>this.add({category:"navigation",message:`popstate \u2192 ${location.pathname}`});window.addEventListener("popstate",n),this.teardown.push(()=>window.removeEventListener("popstate",n));}catch{}}installClicks(){try{let e=r=>{let n=r.target;if(!n||typeof n.tagName!="string")return;let s=n.id?`#${n.id}`:"",i=typeof n.className=="string"?n.className:"",o=i?`.${i.split(/\s+/).filter(Boolean).slice(0,2).join(".")}`:"";this.add({category:"click",message:`${n.tagName.toLowerCase()}${s}${o}`});};window.addEventListener("click",e,{capture:!0,passive:!0}),this.teardown.push(()=>window.removeEventListener("click",e,{capture:!0}));}catch{}}installFetch(){try{let e=window.fetch;if(typeof e!="function")return;let r=(...n)=>{let[s,i]=n,o=i?.method??(typeof s=="object"&&s&&"method"in s?s.method:"GET"),l=typeof s=="string"?s:s instanceof URL?s.href:s.url;return e.apply(window,n).then(u=>(this.add({category:"fetch",message:`${o} ${l} \u2192 ${u.status}`,level:u.ok?void 0:"Warning"}),u),u=>{throw this.add({category:"fetch",message:`${o} ${l} \u2192 failed`,level:"Warning"}),u})};window.fetch=r,this.teardown.push(()=>{window.fetch===r&&(window.fetch=e);});}catch{}}close(){for(let e of this.teardown.splice(0))try{e();}catch{}}};var m=class{constructor(e=4e3,r=100){this.windowMs=e;this.max=r;this.seen=new Map;}shouldSend(e){let r=Date.now(),n=this.seen.get(e);if(n!==void 0&&r-n<this.windowMs)return false;if(this.seen.set(e,r),this.seen.size>this.max){let s=this.seen.keys().next().value;s!==void 0&&this.seen.delete(s);}return true}};function I(t,e){let r=(e??"").split(`
2
- `).slice(0,4).map(n=>n.replace(/:\d+:\d+/g,"").replace(/\?[^\s)]*/g,"").replace(/https?:\/\/[^/]+/g,"").trim()).join("|");return `${t}::${r}`.slice(0,500)}function M(t){if(!d())return ()=>{};let e=t.config,r=[];if(e.captureUnhandledErrors||e.captureResourceErrors){let n=s=>{try{let i=s.target;if(i instanceof HTMLElement){if(!e.captureResourceErrors)return;let l=i,u=l.src||l.href;if(!u)return;t.captureMessage(`Resource failed to load: ${u}`,"Warning",{context:{resource:i.tagName.toLowerCase(),url:u}});return}if(!e.captureUnhandledErrors)return;let o=s;if(!o.error&&(!o.message||o.message==="Script error."))return;t.captureException(o.error??o.message);}catch{}};window.addEventListener("error",n,true),r.push(()=>window.removeEventListener("error",n,true));}if(e.captureUnhandledRejections){let n=s=>{try{t.captureException(s.reason??"Unhandled promise rejection",{context:{unhandledRejection:!0}});}catch{}};window.addEventListener("unhandledrejection",n),r.push(()=>window.removeEventListener("unhandledrejection",n));}if(e.captureConsole){let n=console;for(let s of ["error","warn"]){let i=n[s];if(typeof i!="function")continue;let o=(...l)=>{try{t.addBreadcrumb({category:"console",level:s==="error"?"Error":"Warning",message:l.map(D).join(" ").slice(0,500)});}catch{}return i.apply(console,l)};n[s]=o,r.push(()=>{n[s]===o&&(n[s]=i);});}}return ()=>{for(let n of r.splice(0))try{n();}catch{}}}function D(t){if(typeof t=="string")return t;if(t instanceof Error)return `${t.name}: ${t.message}`;try{return JSON.stringify(t)??String(t)}catch{return String(t)}}var g=2e3,S=8e3,C=4e3;function _(t){if(t instanceof Error)return {message:a(t.message||t.name||"Error",g),exceptionType:t.name||"Error",stackTrace:t.stack?a(t.stack,S):void 0,innerException:R(t.cause)};if(typeof t=="string")return {message:a(t,g),exceptionType:"Error"};if(t&&typeof t=="object"){let e=t,r=typeof e.message=="string"?e.message:N(e)??Object.prototype.toString.call(t),n=typeof e.name=="string"?e.name:"Error",s=typeof e.stack=="string"?e.stack:void 0;return {message:a(r,g),exceptionType:n,stackTrace:s?a(s,S):void 0,innerException:R(e.cause)}}return {message:a(String(t),g),exceptionType:"Error"}}function j(t){if(t.stackTrace)return t;try{let e=new Error(t.message).stack;if(e){let r=e.split(`
1
+ var k="1.2.0";function u(){return typeof window<"u"&&typeof document<"u"}function h(){return new Date().toISOString()}function a(t,e){return e<=0?"":t.length<=e?t:`${t.slice(0,e-1)}\u2026`}function R(t,e=24e3){let r=new WeakSet;try{let n=JSON.stringify(t,(s,i)=>{if(i instanceof Error)return {name:i.name,message:i.message,stack:i.stack};if(typeof i=="object"&&i!==null){if(r.has(i))return "[Circular]";r.add(i);}if(typeof i=="bigint")return i.toString();if(typeof i!="function")return i});return n===void 0||n.length>e?void 0:n}catch{return}}function C(t,e){return !t||e.length===0?false:e.some(r=>typeof r=="string"?t.includes(r):r.test(t))}function _(t){return `${L(t)}/errors/batch`}function N(t){return `${L(t)}/metrics`}function L(t){let e=t.replace(/\/+$/,"");return /\/api\/v\d+$/.test(e)?e:`${e}/api/v1`}var m=class{constructor(e){this.max=e;this.items=[];this.teardown=[];}add(e){this.items.push({timestamp:e.timestamp??h(),category:e.category,message:a(e.message,500),level:e.level,data:e.data}),this.items.length>this.max&&this.items.shift();}snapshot(){return this.items.slice()}install(){u()&&(this.installHistory(),this.installClicks(),this.installFetch());}installHistory(){try{let e=window.history,r=s=>{let i=e[s];if(typeof i!="function")return ()=>{};let o=(...d)=>{try{let c=d[2];typeof c=="string"&&this.add({category:"navigation",message:`${s} \u2192 ${c}`});}catch{}return i.apply(window.history,d)};return e[s]=o,()=>{e[s]===o&&(e[s]=i);}};this.teardown.push(r("pushState"),r("replaceState"));let n=()=>this.add({category:"navigation",message:`popstate \u2192 ${location.pathname}`});window.addEventListener("popstate",n),this.teardown.push(()=>window.removeEventListener("popstate",n));}catch{}}installClicks(){try{let e=r=>{let n=r.target;if(!n||typeof n.tagName!="string")return;let s=n.id?`#${n.id}`:"",i=typeof n.className=="string"?n.className:"",o=i?`.${i.split(/\s+/).filter(Boolean).slice(0,2).join(".")}`:"";this.add({category:"click",message:`${n.tagName.toLowerCase()}${s}${o}`});};window.addEventListener("click",e,{capture:!0,passive:!0}),this.teardown.push(()=>window.removeEventListener("click",e,{capture:!0}));}catch{}}installFetch(){try{let e=window.fetch;if(typeof e!="function")return;let r=(...n)=>{let[s,i]=n,o=i?.method??(typeof s=="object"&&s&&"method"in s?s.method:"GET"),d=typeof s=="string"?s:s instanceof URL?s.href:s.url;return e.apply(window,n).then(c=>(this.add({category:"fetch",message:`${o} ${d} \u2192 ${c.status}`,level:c.ok?void 0:"Warning"}),c),c=>{throw this.add({category:"fetch",message:`${o} ${d} \u2192 failed`,level:"Warning"}),c})};window.fetch=r,this.teardown.push(()=>{window.fetch===r&&(window.fetch=e);});}catch{}}close(){for(let e of this.teardown.splice(0))try{e();}catch{}}};var g=class{constructor(e=4e3,r=100){this.windowMs=e;this.max=r;this.seen=new Map;}shouldSend(e){let r=Date.now(),n=this.seen.get(e);if(n!==void 0&&r-n<this.windowMs)return false;if(this.seen.set(e,r),this.seen.size>this.max){let s=this.seen.keys().next().value;s!==void 0&&this.seen.delete(s);}return true}};function $(t,e){let r=(e??"").split(`
2
+ `).slice(0,4).map(n=>n.replace(/:\d+:\d+/g,"").replace(/\?[^\s)]*/g,"").replace(/https?:\/\/[^/]+/g,"").trim()).join("|");return `${t}::${r}`.slice(0,500)}function O(t){if(!u())return ()=>{};let e=t.config,r=[];if(e.captureUnhandledErrors||e.captureResourceErrors){let n=s=>{try{let i=s.target;if(i instanceof HTMLElement){if(!e.captureResourceErrors)return;let d=i,c=d.src||d.href;if(!c)return;t.captureMessage(`Resource failed to load: ${c}`,"Warning",{context:{resource:i.tagName.toLowerCase(),url:c}});return}if(!e.captureUnhandledErrors)return;let o=s;if(!o.error&&(!o.message||o.message==="Script error."))return;t.captureException(o.error??o.message);}catch{}};window.addEventListener("error",n,true),r.push(()=>window.removeEventListener("error",n,true));}if(e.captureUnhandledRejections){let n=s=>{try{t.captureException(s.reason??"Unhandled promise rejection",{context:{unhandledRejection:!0}});}catch{}};window.addEventListener("unhandledrejection",n),r.push(()=>window.removeEventListener("unhandledrejection",n));}if(e.captureConsole){let n=console;for(let s of ["error","warn"]){let i=n[s];if(typeof i!="function")continue;let o=(...d)=>{try{t.addBreadcrumb({category:"console",level:s==="error"?"Error":"Warning",message:d.map(V).join(" ").slice(0,500)});}catch{}return i.apply(console,d)};n[s]=o,r.push(()=>{n[s]===o&&(n[s]=i);});}}return ()=>{for(let n of r.splice(0))try{n();}catch{}}}function V(t){if(typeof t=="string")return t;if(t instanceof Error)return `${t.name}: ${t.message}`;try{return JSON.stringify(t)??String(t)}catch{return String(t)}}var y=2e3,T=8e3,S=4e3;function j(t){if(t instanceof Error)return {message:a(t.message||t.name||"Error",y),exceptionType:t.name||"Error",stackTrace:t.stack?a(t.stack,T):void 0,innerException:M(t.cause)};if(typeof t=="string")return {message:a(t,y),exceptionType:"Error"};if(t&&typeof t=="object"){let e=t,r=typeof e.message=="string"?e.message:q(e)??Object.prototype.toString.call(t),n=typeof e.name=="string"?e.name:"Error",s=typeof e.stack=="string"?e.stack:void 0;return {message:a(r,y),exceptionType:n,stackTrace:s?a(s,T):void 0,innerException:M(e.cause)}}return {message:a(String(t),y),exceptionType:"Error"}}function D(t){if(t.stackTrace)return t;try{let e=new Error(t.message).stack;if(e){let r=e.split(`
3
3
  `).slice(2).join(`
4
- `);return {...t,stackTrace:a(r||e,S)}}}catch{}return t}function R(t){if(t==null)return;if(t instanceof Error){let r=[`${t.name}: ${t.message}`];t.stack&&r.push(t.stack);let n=R(t.cause);return n&&r.push(`Caused by: ${n}`),a(r.join(`
5
- `),C)}let e=N(t);return e?a(e,C):a(String(t),C)}function N(t){try{let e=JSON.stringify(t);return e==="{}"?void 0:e}catch{return}}var B="cherryboard:queue:v1",y=class{constructor(e,r){this.enabled=e;this.maxItems=r;}get store(){if(!this.enabled||!d())return null;try{return window.localStorage}catch{return null}}push(e){let r=this.store;if(!(!r||e.length===0))try{let n=this.read().concat(e).slice(-this.maxItems);r.setItem(B,JSON.stringify(n));}catch{}}read(){let e=this.store;if(!e)return [];try{let r=e.getItem(B);if(!r)return [];let n=JSON.parse(r);return Array.isArray(n)?n:[]}catch{return []}}drain(){let e=this.read();return this.clear(),e}clear(){let e=this.store;if(e)try{e.removeItem(B);}catch{}}};var b=class{constructor(e=30,r=5){this.capacity=e;this.refillPerSec=r;this.tokens=e,this.last=Date.now();}allow(){let e=Date.now(),r=(e-this.last)/1e3;return this.tokens=Math.min(this.capacity,this.tokens+r*this.refillPerSec),this.last=e,this.tokens>=1?(this.tokens-=1,true):false}};var O=["password","passwd","secret","token","apikey","api_key","authorization","auth","cookie","session","credit","card","cvv","ssn"],H=["token","access_token","apikey","api_key","email","password","code","secret"],U="[Filtered]",q=/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/g;function T(t){let e=t;for(let r of H)e=e.replace(new RegExp(`([?&]${r}=)[^&#\\s]*`,"gi"),`$1${U}`);return e}function x(t,e=0){if(e>6)return t;if(typeof t=="string")return T(t).replace(q,U);if(Array.isArray(t))return t.map(r=>x(r,e+1));if(t&&typeof t=="object"){let r={};for(let[n,s]of Object.entries(t)){let i=n.toLowerCase();r[n]=O.some(o=>i.includes(o))?U:x(s,e+1);}return r}return t}function $(t){return {...t,message:T(t.message),context:x(t.context),breadcrumbs:t.breadcrumbs.map(e=>({...e,message:T(e.message),data:e.data?x(e.data):void 0}))}}var w=class{constructor(e,r){this.apiKey=r;this.endpoint=A(e);let n=typeof fetch=="function"?fetch.bind(globalThis):void 0;this.fetchImpl=n??(()=>Promise.reject(new Error("fetch unavailable")));}async send(e,r=false){if(e.length===0)return {ok:true,retryable:false,status:204};try{let n=await this.fetchImpl(this.endpoint,{method:"POST",headers:{"Content-Type":"application/json",Accept:"application/json","X-API-Key":this.apiKey},body:JSON.stringify({errors:e}),keepalive:r,mode:"cors",credentials:"omit"});if(n.status===429)return {ok:!1,retryable:!1,status:429,retryAfterMs:K(n.headers?.get?.("Retry-After"))};let s=n.status>=500;return {ok:n.ok,retryable:s,status:n.status}}catch{return {ok:false,retryable:true,status:0}}}};function K(t){if(!t)return 6e4;let r=Number(t);if(Number.isFinite(r)&&r>=0)return Math.min(r*1e3,36e5);let n=Date.parse(t);return Number.isNaN(n)?6e4:Math.min(Math.max(n-Date.now(),0),36e5)}function P(t,e,r){return Math.max(e,Math.min(r,t))}function F(t){return new Promise(e=>setTimeout(e,t))}var z=3e3;function W(t){return {apiKey:t.apiKey,apiUrl:t.apiUrl,environment:t.environment??"production",release:t.release,enabled:t.enabled??true,sampleRate:P(t.sampleRate??1,0,1),maxBatchSize:P(t.maxBatchSize??20,1,100),flushIntervalMs:t.flushIntervalMs??4e3,maxQueueItems:t.maxQueueItems??100,maxRetries:t.maxRetries??3,maxBreadcrumbs:t.maxBreadcrumbs??30,offlineStorage:t.offlineStorage??true,captureUnhandledErrors:t.captureUnhandledErrors??true,captureUnhandledRejections:t.captureUnhandledRejections??true,captureResourceErrors:t.captureResourceErrors??true,captureConsole:t.captureConsole??true,autoBreadcrumbs:t.autoBreadcrumbs??true,denyUrls:t.denyUrls??[],allowUrls:t.allowUrls??[],beforeSend:t.beforeSend,debug:t.debug??false}}var f=class{constructor(e){this.buffer=[];this.flushTimer=null;this.processing=false;this.rateLimitedUntil=0;this.discarded={};this.closed=false;this.scope={tags:{}};this.teardown=[];this.config=W(e),this.transport=new w(this.config.apiUrl,this.config.apiKey),this.deduper=new m(z),this.limiter=new b,this.queue=new y(this.config.offlineStorage,this.config.maxQueueItems),this.breadcrumbs=new h(this.config.maxBreadcrumbs),this.config.enabled&&(this.config.autoBreadcrumbs&&this.breadcrumbs.install(),this.teardown.push(M(this)),this.installLifecycle(),this.drainOffline());}captureException(e,r){try{this.process(j(_(e)),r?.severity??"Error",r);}catch(n){this.debug("captureException failed",n);}}captureMessage(e,r="Info",n){try{this.process({message:a(e,2e3),exceptionType:"Message"},n?.severity??r,n);}catch(s){this.debug("captureMessage failed",s);}}getDiscardedEvents(){return {...this.discarded}}discard(e,r=1){this.discarded[e]=(this.discarded[e]??0)+r;}addBreadcrumb(e){this.breadcrumbs.add(e);}setUser(e){this.scope.user=e??void 0;}setTag(e,r){this.scope.tags[e]=r;}setContext(e,r){this.scope.tags[e]=r;}close(){this.closed=true,this.flushTimer!==null&&(clearTimeout(this.flushTimer),this.flushTimer=null),this.flush(true),this.breadcrumbs.close();for(let e of this.teardown.splice(0))try{e();}catch{}}process(e,r,n){if(!this.config.enabled||this.closed)return;if(this.config.sampleRate<1&&Math.random()>this.config.sampleRate){this.discard("sampled");return}let s=`${e.stackTrace??""}
6
- ${d()?location.href:""}`;if(k(s,this.config.denyUrls)){this.discard("filtered");return}if(this.config.allowUrls.length>0&&!k(s,this.config.allowUrls)){this.discard("filtered");return}if(!this.deduper.shouldSend(I(e.message,e.stackTrace))){this.discard("deduped");return}let i={message:e.message,severity:r,timestamp:p(),exceptionType:e.exceptionType,stackTrace:e.stackTrace,innerException:e.innerException,userId:this.scope.user?.id,requestPath:d()?location.pathname:void 0,userAgent:d()?navigator.userAgent:void 0,context:this.buildContext(n),breadcrumbs:this.breadcrumbs.snapshot()};if(i=$(i),this.config.beforeSend){let o=this.config.beforeSend(i);if(!o){this.discard("filtered");return}i=o;}this.enqueue(this.toPayload(i));}buildContext(e){let r={sdk:{name:"cherryboard-web",version:v},environment:this.config.environment};return this.config.release&&(r.release=this.config.release),d()&&(r.url=location.href,document.referrer&&(r.referrer=document.referrer),r.language=navigator.language,r.viewport={width:window.innerWidth,height:window.innerHeight}),this.scope.user&&(r.user=this.scope.user),Object.keys(this.scope.tags).length>0&&(r.tags={...this.scope.tags}),e?.componentStack&&(r.componentStack=e.componentStack),e?.digest&&(r.digest=e.digest),e?.context&&Object.assign(r,e.context),r}toPayload(e){let r=E({...e.context,breadcrumbs:e.breadcrumbs});return r===void 0&&(r=E(e.context)),{message:e.message,stackTrace:e.stackTrace,severity:e.severity,timestamp:e.timestamp,userId:e.userId,requestPath:e.requestPath,userAgent:e.userAgent,exceptionType:e.exceptionType,innerException:e.innerException,metadata:r}}enqueue(e){this.buffer.push(e),this.buffer.length>=this.config.maxBatchSize?this.flush():this.scheduleFlush();}scheduleFlush(){this.closed||this.flushTimer===null&&(this.flushTimer=setTimeout(()=>{this.flushTimer=null,this.flush();},this.config.flushIntervalMs));}async flush(e=false){if(this.flushTimer!==null&&(clearTimeout(this.flushTimer),this.flushTimer=null),this.buffer.length!==0){if(e){if(Date.now()<this.rateLimitedUntil)return;for(;this.buffer.length>0;){let r=this.buffer.splice(0,this.config.maxBatchSize);if(!this.limiter.allow())break;this.transport.send(r,true);}return}if(Date.now()<this.rateLimitedUntil){this.scheduleFlush();return}if(!this.processing){this.processing=true;try{for(;this.buffer.length>0;){let r=this.buffer.splice(0,this.config.maxBatchSize);if(!this.limiter.allow()){this.debug("rate limited; dropping",r.length,"events"),this.discard("rate_limited",r.length);break}if(!await this.deliver(r)){this.queue.push(r);break}}}finally{this.processing=false;}}}}async deliver(e){for(let r=0;r<=this.config.maxRetries;r++){let n=await this.transport.send(e,false);if(n.ok)return true;if(n.status===429)return this.rateLimitedUntil=Date.now()+(n.retryAfterMs??6e4),this.debug("rate limited by server; pausing for",n.retryAfterMs,"ms"),false;if(!n.retryable)return this.debug("non-retryable response",n.status,"\u2014 dropping batch"),this.discard("send_failed",e.length),true;if(r===this.config.maxRetries)return false;await F(P(2**r*1e3+Math.random()*250,0,15e3));}return false}drainOffline(){let e=this.queue.drain();e.length>0&&(this.buffer.push(...e),this.scheduleFlush());}installLifecycle(){if(!d())return;let e=()=>{document.visibilityState==="hidden"&&this.flush(true);},r=()=>{this.flush(true);},n=()=>this.drainOffline();document.addEventListener("visibilitychange",e),window.addEventListener("pagehide",r),window.addEventListener("online",n),this.teardown.push(()=>{document.removeEventListener("visibilitychange",e),window.removeEventListener("pagehide",r),window.removeEventListener("online",n);});}debug(...e){this.config.debug&&console.warn("[cherryboard]",...e);}};var L="__CHERRYBOARD__";function c(){let t=globalThis,e=t[L];return e||(e={},t[L]=e),e}function we(t){let e=c();return e.client||(e.client=new f(t)),e.client}function ve(){return c().client??null}function Ee(){return c().client!=null}function ke(t,e){c().client?.captureException(t,e);}function Ce(t,e,r){c().client?.captureMessage(t,e,r);}function Se(t){c().client?.addBreadcrumb(t);}function Re(t){c().client?.setUser(t);}function Be(t,e){c().client?.setTag(t,e);}function Ue(t,e){c().client?.setContext(t,e);}function Te(){let t=c().client;return t?t.flush():Promise.resolve()}function Pe(t,e,r){c().client?.captureException(t,{severity:"Error",context:{source:"nextjs-server",...e?.path?{requestPath:e.path}:{},...e?.method?{requestMethod:e.method}:{},...r??{}}});}function Ae(){return c().client?.getDiscardedEvents()??{}}function Ie(){let t=c();t.client?.close(),t.client=void 0;}export{f as CherryBoardClient,v as SDK_VERSION,Se as addBreadcrumb,ke as captureException,Ce as captureMessage,Pe as captureRequestError,Ie as close,Te as flush,ve as getClient,Ae as getDiscardedEvents,we as init,Ee as isInitialized,Ue as setContext,Be as setTag,Re as setUser};
4
+ `);return {...t,stackTrace:a(r||e,T)}}}catch{}return t}function M(t){if(t==null)return;if(t instanceof Error){let r=[`${t.name}: ${t.message}`];t.stack&&r.push(t.stack);let n=M(t.cause);return n&&r.push(`Caused by: ${n}`),a(r.join(`
5
+ `),S)}let e=q(t);return e?a(e,S):a(String(t),S)}function q(t){try{let e=JSON.stringify(t);return e==="{}"?void 0:e}catch{return}}var z=/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i,G=/^[0-9a-f]{16,}$/i,X=/^\d+$/,W=/^(?=.*\d)[A-Za-z0-9_-]{12,}$/;function J(t){return z.test(t)||X.test(t)||G.test(t)||W.test(t)}function B(t,e){let r;try{r=new URL(t,e??(typeof location<"u"?location.href:void 0)).pathname;}catch{return null}if(!r||r==="/")return "/";let n=r.split("/").filter(Boolean);if(n.length===0)return "/";let s=n.slice(0,12).map(o=>J(o)?":id":o);n.length>12&&s.push("\u2026");let i="/"+s.join("/");return i.length>300?i.slice(0,300):i}var f=[50,100,250,500,1e3,2500,5e3];function H(t){for(let e=0;e<f.length;e++)if(t<=f[e])return e;return f.length}var b=class{constructor(e){this.options=e;this.requests=new Map;this.pageViews=new Map;this.teardown=[];this.closed=false;this.endpoint=N(e.apiUrl);let r=typeof fetch=="function"?fetch.bind(globalThis):void 0;this.fetchImpl=r??(()=>Promise.reject(new Error("fetch unavailable")));}start(){!u()||this.closed||(this.recordPageView(location.pathname,true),this.observeResources(),this.observeNavigation(),this.observeVisibility(),this.timer=setInterval(()=>{this.flush();},this.options.flushIntervalMs));}observeResources(){if(!(typeof PerformanceObserver>"u"))try{this.observer=new PerformanceObserver(e=>{for(let r of e.getEntries())this.recordResource(r);}),this.observer.observe({type:"resource",buffered:!0});}catch{}}recordResource(e){if(e.initiatorType!=="fetch"&&e.initiatorType!=="xmlhttprequest"||e.name.startsWith(this.endpoint)||e.name.includes("/api/v1/errors/batch"))return;let r=B(e.name);if(!r)return;let n=Math.round(e.duration);n<=0||this.addRequest(r,"ALL",n,false);}addRequest(e,r,n,s){let i=`${r} ${e}`,o=this.requests.get(i);if(!o){if(this.requests.size>=this.options.maxRoutes)return;o={route:e,method:r,count:0,errorCount:0,sumMs:0,maxMs:0,buckets:new Array(f.length+1).fill(0)},this.requests.set(i,o);}o.count++,s&&o.errorCount++,o.sumMs+=n,n>o.maxMs&&(o.maxMs=n),o.buckets[H(n)]++;}observeNavigation(){let e=()=>this.recordPageView(location.pathname,false);try{let r=window.history,n=s=>{let i=r[s];if(typeof i!="function")return ()=>{};let o=(...d)=>{let c=i.apply(window.history,d);return e(),c};return r[s]=o,()=>{r[s]===o&&(r[s]=i);}};this.teardown.push(n("pushState"),n("replaceState")),window.addEventListener("popstate",e),this.teardown.push(()=>window.removeEventListener("popstate",e));}catch{}}recordPageView(e,r){let n=B(e);if(!n)return;let s=this.pageViews.get(n);if(!s){if(this.pageViews.size>=this.options.maxRoutes)return;s={route:n,views:0,visits:0},this.pageViews.set(n,s);}s.views++,r&&s.visits++;}observeVisibility(){let e=()=>{document.visibilityState==="hidden"&&this.flush(true);};document.addEventListener("visibilitychange",e),this.teardown.push(()=>document.removeEventListener("visibilitychange",e));}async flush(e=false){if(this.requests.size===0&&this.pageViews.size===0)return;let r={requests:Array.from(this.requests.values()).map(n=>({route:n.route,method:n.method,count:n.count,errorCount:n.errorCount,sumMs:n.sumMs,maxMs:n.maxMs,buckets:n.buckets})),pageViews:Array.from(this.pageViews.values()).map(n=>({route:n.route,views:n.views,visits:n.visits}))};this.requests.clear(),this.pageViews.clear();try{await this.fetchImpl(this.endpoint,{method:"POST",headers:{"Content-Type":"application/json","X-API-Key":this.options.apiKey},body:JSON.stringify(r),keepalive:e,mode:"cors",credentials:"omit"});}catch{this.options.debug&&console.warn("[cherryboard] metrics flush failed");}}close(){this.closed=true,this.timer&&clearInterval(this.timer),this.observer?.disconnect();for(let e of this.teardown)e();this.teardown=[];}};var P="cherryboard:queue:v1",v=class{constructor(e,r){this.enabled=e;this.maxItems=r;}get store(){if(!this.enabled||!u())return null;try{return window.localStorage}catch{return null}}push(e){let r=this.store;if(!(!r||e.length===0))try{let n=this.read().concat(e).slice(-this.maxItems);r.setItem(P,JSON.stringify(n));}catch{}}read(){let e=this.store;if(!e)return [];try{let r=e.getItem(P);if(!r)return [];let n=JSON.parse(r);return Array.isArray(n)?n:[]}catch{return []}}drain(){let e=this.read();return this.clear(),e}clear(){let e=this.store;if(e)try{e.removeItem(P);}catch{}}};var w=class{constructor(e=30,r=5){this.capacity=e;this.refillPerSec=r;this.tokens=e,this.last=Date.now();}allow(){let e=Date.now(),r=(e-this.last)/1e3;return this.tokens=Math.min(this.capacity,this.tokens+r*this.refillPerSec),this.last=e,this.tokens>=1?(this.tokens-=1,true):false}};var Q=["password","passwd","secret","token","apikey","api_key","authorization","auth","cookie","session","credit","card","cvv","ssn"],Y=["token","access_token","apikey","api_key","email","password","code","secret"],U="[Filtered]",Z=/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/g;function A(t){let e=t;for(let r of Y)e=e.replace(new RegExp(`([?&]${r}=)[^&#\\s]*`,"gi"),`$1${U}`);return e}function x(t,e=0){if(e>6)return t;if(typeof t=="string")return A(t).replace(Z,U);if(Array.isArray(t))return t.map(r=>x(r,e+1));if(t&&typeof t=="object"){let r={};for(let[n,s]of Object.entries(t)){let i=n.toLowerCase();r[n]=Q.some(o=>i.includes(o))?U:x(s,e+1);}return r}return t}function K(t){return {...t,message:A(t.message),context:x(t.context),breadcrumbs:t.breadcrumbs.map(e=>({...e,message:A(e.message),data:e.data?x(e.data):void 0}))}}var E=class{constructor(e,r){this.apiKey=r;this.endpoint=_(e);let n=typeof fetch=="function"?fetch.bind(globalThis):void 0;this.fetchImpl=n??(()=>Promise.reject(new Error("fetch unavailable")));}async send(e,r=false){if(e.length===0)return {ok:true,retryable:false,status:204};try{let n=await this.fetchImpl(this.endpoint,{method:"POST",headers:{"Content-Type":"application/json",Accept:"application/json","X-API-Key":this.apiKey},body:JSON.stringify({errors:e}),keepalive:r,mode:"cors",credentials:"omit"});if(n.status===429)return {ok:!1,retryable:!1,status:429,retryAfterMs:ee(n.headers?.get?.("Retry-After"))};let s=n.status>=500;return {ok:n.ok,retryable:s,status:n.status}}catch{return {ok:false,retryable:true,status:0}}}};function ee(t){if(!t)return 6e4;let r=Number(t);if(Number.isFinite(r)&&r>=0)return Math.min(r*1e3,36e5);let n=Date.parse(t);return Number.isNaN(n)?6e4:Math.min(Math.max(n-Date.now(),0),36e5)}var te=200;function I(t,e,r){return Math.max(e,Math.min(r,t))}function re(t){return new Promise(e=>setTimeout(e,t))}var ne=3e3;function se(t){return {apiKey:t.apiKey,apiUrl:t.apiUrl,environment:t.environment??"production",release:t.release,enabled:t.enabled??true,sampleRate:I(t.sampleRate??1,0,1),maxBatchSize:I(t.maxBatchSize??20,1,100),flushIntervalMs:t.flushIntervalMs??4e3,maxQueueItems:t.maxQueueItems??100,maxRetries:t.maxRetries??3,maxBreadcrumbs:t.maxBreadcrumbs??30,offlineStorage:t.offlineStorage??true,captureUnhandledErrors:t.captureUnhandledErrors??true,captureUnhandledRejections:t.captureUnhandledRejections??true,captureResourceErrors:t.captureResourceErrors??true,captureConsole:t.captureConsole??true,autoBreadcrumbs:t.autoBreadcrumbs??true,denyUrls:t.denyUrls??[],allowUrls:t.allowUrls??[],beforeSend:t.beforeSend,trackPerformance:t.trackPerformance??false,metricsFlushIntervalMs:t.metricsFlushIntervalMs??6e4,debug:t.debug??false}}var p=class{constructor(e){this.buffer=[];this.flushTimer=null;this.processing=false;this.rateLimitedUntil=0;this.discarded={};this.closed=false;this.scope={tags:{}};this.teardown=[];this.config=se(e),this.transport=new E(this.config.apiUrl,this.config.apiKey),this.deduper=new g(ne),this.limiter=new w,this.queue=new v(this.config.offlineStorage,this.config.maxQueueItems),this.config.trackPerformance&&this.config.enabled&&(this.metrics=new b({apiKey:this.config.apiKey,apiUrl:this.config.apiUrl,flushIntervalMs:this.config.metricsFlushIntervalMs,maxRoutes:te,debug:this.config.debug}),this.metrics.start()),this.breadcrumbs=new m(this.config.maxBreadcrumbs),this.config.enabled&&(this.config.autoBreadcrumbs&&this.breadcrumbs.install(),this.teardown.push(O(this)),this.installLifecycle(),this.drainOffline());}captureException(e,r){try{this.process(D(j(e)),r?.severity??"Error",r);}catch(n){this.debug("captureException failed",n);}}captureMessage(e,r="Info",n){try{this.process({message:a(e,2e3),exceptionType:"Message"},n?.severity??r,n);}catch(s){this.debug("captureMessage failed",s);}}getDiscardedEvents(){return {...this.discarded}}discard(e,r=1){this.discarded[e]=(this.discarded[e]??0)+r;}addBreadcrumb(e){this.breadcrumbs.add(e);}setUser(e){this.scope.user=e??void 0;}setTag(e,r){this.scope.tags[e]=r;}setContext(e,r){this.scope.tags[e]=r;}close(){this.closed=true,this.flushTimer!==null&&(clearTimeout(this.flushTimer),this.flushTimer=null),this.flush(true),this.metrics?.close(),this.breadcrumbs.close();for(let e of this.teardown.splice(0))try{e();}catch{}}process(e,r,n){if(!this.config.enabled||this.closed)return;if(this.config.sampleRate<1&&Math.random()>this.config.sampleRate){this.discard("sampled");return}let s=`${e.stackTrace??""}
6
+ ${u()?location.href:""}`;if(C(s,this.config.denyUrls)){this.discard("filtered");return}if(this.config.allowUrls.length>0&&!C(s,this.config.allowUrls)){this.discard("filtered");return}if(!this.deduper.shouldSend($(e.message,e.stackTrace))){this.discard("deduped");return}let i={message:e.message,severity:r,timestamp:h(),exceptionType:e.exceptionType,stackTrace:e.stackTrace,innerException:e.innerException,userId:this.scope.user?.id,requestPath:u()?location.pathname:void 0,userAgent:u()?navigator.userAgent:void 0,context:this.buildContext(n),breadcrumbs:this.breadcrumbs.snapshot()};if(i=K(i),this.config.beforeSend){let o=this.config.beforeSend(i);if(!o){this.discard("filtered");return}i=o;}this.enqueue(this.toPayload(i));}buildContext(e){let r={sdk:{name:"cherryboard-web",version:k},environment:this.config.environment};return this.config.release&&(r.release=this.config.release),u()&&(r.url=location.href,document.referrer&&(r.referrer=document.referrer),r.language=navigator.language,r.viewport={width:window.innerWidth,height:window.innerHeight}),this.scope.user&&(r.user=this.scope.user),Object.keys(this.scope.tags).length>0&&(r.tags={...this.scope.tags}),e?.componentStack&&(r.componentStack=e.componentStack),e?.digest&&(r.digest=e.digest),e?.context&&Object.assign(r,e.context),r}toPayload(e){let r=R({...e.context,breadcrumbs:e.breadcrumbs});return r===void 0&&(r=R(e.context)),{message:e.message,stackTrace:e.stackTrace,severity:e.severity,timestamp:e.timestamp,userId:e.userId,requestPath:e.requestPath,userAgent:e.userAgent,exceptionType:e.exceptionType,innerException:e.innerException,metadata:r}}enqueue(e){this.buffer.push(e),this.buffer.length>=this.config.maxBatchSize?this.flush():this.scheduleFlush();}scheduleFlush(){this.closed||this.flushTimer===null&&(this.flushTimer=setTimeout(()=>{this.flushTimer=null,this.flush();},this.config.flushIntervalMs));}async flush(e=false){if(this.flushTimer!==null&&(clearTimeout(this.flushTimer),this.flushTimer=null),this.buffer.length!==0){if(e){if(Date.now()<this.rateLimitedUntil)return;for(;this.buffer.length>0;){let r=this.buffer.splice(0,this.config.maxBatchSize);if(!this.limiter.allow())break;this.transport.send(r,true);}return}if(Date.now()<this.rateLimitedUntil){this.scheduleFlush();return}if(!this.processing){this.processing=true;try{for(;this.buffer.length>0;){let r=this.buffer.splice(0,this.config.maxBatchSize);if(!this.limiter.allow()){this.debug("rate limited; dropping",r.length,"events"),this.discard("rate_limited",r.length);break}if(!await this.deliver(r)){this.queue.push(r);break}}}finally{this.processing=false;}}}}async deliver(e){for(let r=0;r<=this.config.maxRetries;r++){let n=await this.transport.send(e,false);if(n.ok)return true;if(n.status===429)return this.rateLimitedUntil=Date.now()+(n.retryAfterMs??6e4),this.debug("rate limited by server; pausing for",n.retryAfterMs,"ms"),false;if(!n.retryable)return this.debug("non-retryable response",n.status,"\u2014 dropping batch"),this.discard("send_failed",e.length),true;if(r===this.config.maxRetries)return false;await re(I(2**r*1e3+Math.random()*250,0,15e3));}return false}drainOffline(){let e=this.queue.drain();e.length>0&&(this.buffer.push(...e),this.scheduleFlush());}installLifecycle(){if(!u())return;let e=()=>{document.visibilityState==="hidden"&&this.flush(true);},r=()=>{this.flush(true);},n=()=>this.drainOffline();document.addEventListener("visibilitychange",e),window.addEventListener("pagehide",r),window.addEventListener("online",n),this.teardown.push(()=>{document.removeEventListener("visibilitychange",e),window.removeEventListener("pagehide",r),window.removeEventListener("online",n);});}debug(...e){this.config.debug&&console.warn("[cherryboard]",...e);}};var F="__CHERRYBOARD__";function l(){let t=globalThis,e=t[F];return e||(e={},t[F]=e),e}function $e(t){let e=l();return e.client||(e.client=new p(t)),e.client}function Oe(){return l().client??null}function je(){return l().client!=null}function De(t,e){l().client?.captureException(t,e);}function qe(t,e,r){l().client?.captureMessage(t,e,r);}function He(t){l().client?.addBreadcrumb(t);}function Ke(t){l().client?.setUser(t);}function Fe(t,e){l().client?.setTag(t,e);}function Ve(t,e){l().client?.setContext(t,e);}function ze(){let t=l().client;return t?t.flush():Promise.resolve()}function Ge(t,e,r){l().client?.captureException(t,{severity:"Error",context:{source:"nextjs-server",...e?.path?{requestPath:e.path}:{},...e?.method?{requestMethod:e.method}:{},...r??{}}});}function Xe(){return l().client?.getDiscardedEvents()??{}}function We(){let t=l();t.client?.close(),t.client=void 0;}export{p as CherryBoardClient,k as SDK_VERSION,He as addBreadcrumb,De as captureException,qe as captureMessage,Ge as captureRequestError,We as close,ze as flush,Oe as getClient,Xe as getDiscardedEvents,$e as init,je as isInitialized,Ve as setContext,Fe as setTag,Ke as setUser};
@@ -1,7 +1,7 @@
1
1
  "use client";
2
- 'use strict';var react=require('react'),jsxRuntime=require('react/jsx-runtime');var h="1.1.0";function d(){return typeof window<"u"&&typeof document<"u"}function m(){return new Date().toISOString()}function a(r,e){return e<=0?"":r.length<=e?r:`${r.slice(0,e-1)}\u2026`}function C(r,e=24e3){let t=new WeakSet;try{let n=JSON.stringify(r,(o,s)=>{if(s instanceof Error)return {name:s.name,message:s.message,stack:s.stack};if(typeof s=="object"&&s!==null){if(t.has(s))return "[Circular]";t.add(s);}if(typeof s=="bigint")return s.toString();if(typeof s!="function")return s});return n===void 0||n.length>e?void 0:n}catch{return}}function B(r,e){return !r||e.length===0?false:e.some(t=>typeof t=="string"?r.includes(t):t.test(r))}function _(r){let e=r.replace(/\/+$/,"");return `${/\/api\/v\d+$/.test(e)?e:`${e}/api/v1`}/errors/batch`}var g=class{constructor(e){this.max=e;this.items=[];this.teardown=[];}add(e){this.items.push({timestamp:e.timestamp??m(),category:e.category,message:a(e.message,500),level:e.level,data:e.data}),this.items.length>this.max&&this.items.shift();}snapshot(){return this.items.slice()}install(){d()&&(this.installHistory(),this.installClicks(),this.installFetch());}installHistory(){try{let e=window.history,t=o=>{let s=e[o];if(typeof s!="function")return ()=>{};let i=(...l)=>{try{let u=l[2];typeof u=="string"&&this.add({category:"navigation",message:`${o} \u2192 ${u}`});}catch{}return s.apply(window.history,l)};return e[o]=i,()=>{e[o]===i&&(e[o]=s);}};this.teardown.push(t("pushState"),t("replaceState"));let n=()=>this.add({category:"navigation",message:`popstate \u2192 ${location.pathname}`});window.addEventListener("popstate",n),this.teardown.push(()=>window.removeEventListener("popstate",n));}catch{}}installClicks(){try{let e=t=>{let n=t.target;if(!n||typeof n.tagName!="string")return;let o=n.id?`#${n.id}`:"",s=typeof n.className=="string"?n.className:"",i=s?`.${s.split(/\s+/).filter(Boolean).slice(0,2).join(".")}`:"";this.add({category:"click",message:`${n.tagName.toLowerCase()}${o}${i}`});};window.addEventListener("click",e,{capture:!0,passive:!0}),this.teardown.push(()=>window.removeEventListener("click",e,{capture:!0}));}catch{}}installFetch(){try{let e=window.fetch;if(typeof e!="function")return;let t=(...n)=>{let[o,s]=n,i=s?.method??(typeof o=="object"&&o&&"method"in o?o.method:"GET"),l=typeof o=="string"?o:o instanceof URL?o.href:o.url;return e.apply(window,n).then(u=>(this.add({category:"fetch",message:`${i} ${l} \u2192 ${u.status}`,level:u.ok?void 0:"Warning"}),u),u=>{throw this.add({category:"fetch",message:`${i} ${l} \u2192 failed`,level:"Warning"}),u})};window.fetch=t,this.teardown.push(()=>{window.fetch===t&&(window.fetch=e);});}catch{}}close(){for(let e of this.teardown.splice(0))try{e();}catch{}}};var y=class{constructor(e=4e3,t=100){this.windowMs=e;this.max=t;this.seen=new Map;}shouldSend(e){let t=Date.now(),n=this.seen.get(e);if(n!==void 0&&t-n<this.windowMs)return false;if(this.seen.set(e,t),this.seen.size>this.max){let o=this.seen.keys().next().value;o!==void 0&&this.seen.delete(o);}return true}};function D(r,e){let t=(e??"").split(`
3
- `).slice(0,4).map(n=>n.replace(/:\d+:\d+/g,"").replace(/\?[^\s)]*/g,"").replace(/https?:\/\/[^/]+/g,"").trim()).join("|");return `${r}::${t}`.slice(0,500)}function j(r){if(!d())return ()=>{};let e=r.config,t=[];if(e.captureUnhandledErrors||e.captureResourceErrors){let n=o=>{try{let s=o.target;if(s instanceof HTMLElement){if(!e.captureResourceErrors)return;let l=s,u=l.src||l.href;if(!u)return;r.captureMessage(`Resource failed to load: ${u}`,"Warning",{context:{resource:s.tagName.toLowerCase(),url:u}});return}if(!e.captureUnhandledErrors)return;let i=o;if(!i.error&&(!i.message||i.message==="Script error."))return;r.captureException(i.error??i.message);}catch{}};window.addEventListener("error",n,true),t.push(()=>window.removeEventListener("error",n,true));}if(e.captureUnhandledRejections){let n=o=>{try{r.captureException(o.reason??"Unhandled promise rejection",{context:{unhandledRejection:!0}});}catch{}};window.addEventListener("unhandledrejection",n),t.push(()=>window.removeEventListener("unhandledrejection",n));}if(e.captureConsole){let n=console;for(let o of ["error","warn"]){let s=n[o];if(typeof s!="function")continue;let i=(...l)=>{try{r.addBreadcrumb({category:"console",level:o==="error"?"Error":"Warning",message:l.map(q).join(" ").slice(0,500)});}catch{}return s.apply(console,l)};n[o]=i,t.push(()=>{n[o]===i&&(n[o]=s);});}}return ()=>{for(let n of t.splice(0))try{n();}catch{}}}function q(r){if(typeof r=="string")return r;if(r instanceof Error)return `${r.name}: ${r.message}`;try{return JSON.stringify(r)??String(r)}catch{return String(r)}}var b=2e3,S=8e3,R=4e3;function $(r){if(r instanceof Error)return {message:a(r.message||r.name||"Error",b),exceptionType:r.name||"Error",stackTrace:r.stack?a(r.stack,S):void 0,innerException:P(r.cause)};if(typeof r=="string")return {message:a(r,b),exceptionType:"Error"};if(r&&typeof r=="object"){let e=r,t=typeof e.message=="string"?e.message:O(e)??Object.prototype.toString.call(r),n=typeof e.name=="string"?e.name:"Error",o=typeof e.stack=="string"?e.stack:void 0;return {message:a(t,b),exceptionType:n,stackTrace:o?a(o,S):void 0,innerException:P(e.cause)}}return {message:a(String(r),b),exceptionType:"Error"}}function L(r){if(r.stackTrace)return r;try{let e=new Error(r.message).stack;if(e){let t=e.split(`
2
+ 'use strict';var react=require('react'),jsxRuntime=require('react/jsx-runtime');var m="1.2.0";function u(){return typeof window<"u"&&typeof document<"u"}function g(){return new Date().toISOString()}function a(r,e){return e<=0?"":r.length<=e?r:`${r.slice(0,e-1)}\u2026`}function S(r,e=24e3){let t=new WeakSet;try{let n=JSON.stringify(r,(s,o)=>{if(o instanceof Error)return {name:o.name,message:o.message,stack:o.stack};if(typeof o=="object"&&o!==null){if(t.has(o))return "[Circular]";t.add(o);}if(typeof o=="bigint")return o.toString();if(typeof o!="function")return o});return n===void 0||n.length>e?void 0:n}catch{return}}function B(r,e){return !r||e.length===0?false:e.some(t=>typeof t=="string"?r.includes(t):t.test(r))}function D(r){return `${j(r)}/errors/batch`}function O(r){return `${j(r)}/metrics`}function j(r){let e=r.replace(/\/+$/,"");return /\/api\/v\d+$/.test(e)?e:`${e}/api/v1`}var y=class{constructor(e){this.max=e;this.items=[];this.teardown=[];}add(e){this.items.push({timestamp:e.timestamp??g(),category:e.category,message:a(e.message,500),level:e.level,data:e.data}),this.items.length>this.max&&this.items.shift();}snapshot(){return this.items.slice()}install(){u()&&(this.installHistory(),this.installClicks(),this.installFetch());}installHistory(){try{let e=window.history,t=s=>{let o=e[s];if(typeof o!="function")return ()=>{};let i=(...d)=>{try{let c=d[2];typeof c=="string"&&this.add({category:"navigation",message:`${s} \u2192 ${c}`});}catch{}return o.apply(window.history,d)};return e[s]=i,()=>{e[s]===i&&(e[s]=o);}};this.teardown.push(t("pushState"),t("replaceState"));let n=()=>this.add({category:"navigation",message:`popstate \u2192 ${location.pathname}`});window.addEventListener("popstate",n),this.teardown.push(()=>window.removeEventListener("popstate",n));}catch{}}installClicks(){try{let e=t=>{let n=t.target;if(!n||typeof n.tagName!="string")return;let s=n.id?`#${n.id}`:"",o=typeof n.className=="string"?n.className:"",i=o?`.${o.split(/\s+/).filter(Boolean).slice(0,2).join(".")}`:"";this.add({category:"click",message:`${n.tagName.toLowerCase()}${s}${i}`});};window.addEventListener("click",e,{capture:!0,passive:!0}),this.teardown.push(()=>window.removeEventListener("click",e,{capture:!0}));}catch{}}installFetch(){try{let e=window.fetch;if(typeof e!="function")return;let t=(...n)=>{let[s,o]=n,i=o?.method??(typeof s=="object"&&s&&"method"in s?s.method:"GET"),d=typeof s=="string"?s:s instanceof URL?s.href:s.url;return e.apply(window,n).then(c=>(this.add({category:"fetch",message:`${i} ${d} \u2192 ${c.status}`,level:c.ok?void 0:"Warning"}),c),c=>{throw this.add({category:"fetch",message:`${i} ${d} \u2192 failed`,level:"Warning"}),c})};window.fetch=t,this.teardown.push(()=>{window.fetch===t&&(window.fetch=e);});}catch{}}close(){for(let e of this.teardown.splice(0))try{e();}catch{}}};var v=class{constructor(e=4e3,t=100){this.windowMs=e;this.max=t;this.seen=new Map;}shouldSend(e){let t=Date.now(),n=this.seen.get(e);if(n!==void 0&&t-n<this.windowMs)return false;if(this.seen.set(e,t),this.seen.size>this.max){let s=this.seen.keys().next().value;s!==void 0&&this.seen.delete(s);}return true}};function q(r,e){let t=(e??"").split(`
3
+ `).slice(0,4).map(n=>n.replace(/:\d+:\d+/g,"").replace(/\?[^\s)]*/g,"").replace(/https?:\/\/[^/]+/g,"").trim()).join("|");return `${r}::${t}`.slice(0,500)}function H(r){if(!u())return ()=>{};let e=r.config,t=[];if(e.captureUnhandledErrors||e.captureResourceErrors){let n=s=>{try{let o=s.target;if(o instanceof HTMLElement){if(!e.captureResourceErrors)return;let d=o,c=d.src||d.href;if(!c)return;r.captureMessage(`Resource failed to load: ${c}`,"Warning",{context:{resource:o.tagName.toLowerCase(),url:c}});return}if(!e.captureUnhandledErrors)return;let i=s;if(!i.error&&(!i.message||i.message==="Script error."))return;r.captureException(i.error??i.message);}catch{}};window.addEventListener("error",n,true),t.push(()=>window.removeEventListener("error",n,true));}if(e.captureUnhandledRejections){let n=s=>{try{r.captureException(s.reason??"Unhandled promise rejection",{context:{unhandledRejection:!0}});}catch{}};window.addEventListener("unhandledrejection",n),t.push(()=>window.removeEventListener("unhandledrejection",n));}if(e.captureConsole){let n=console;for(let s of ["error","warn"]){let o=n[s];if(typeof o!="function")continue;let i=(...d)=>{try{r.addBreadcrumb({category:"console",level:s==="error"?"Error":"Warning",message:d.map(J).join(" ").slice(0,500)});}catch{}return o.apply(console,d)};n[s]=i,t.push(()=>{n[s]===i&&(n[s]=o);});}}return ()=>{for(let n of t.splice(0))try{n();}catch{}}}function J(r){if(typeof r=="string")return r;if(r instanceof Error)return `${r.name}: ${r.message}`;try{return JSON.stringify(r)??String(r)}catch{return String(r)}}var b=2e3,T=8e3,P=4e3;function K(r){if(r instanceof Error)return {message:a(r.message||r.name||"Error",b),exceptionType:r.name||"Error",stackTrace:r.stack?a(r.stack,T):void 0,innerException:M(r.cause)};if(typeof r=="string")return {message:a(r,b),exceptionType:"Error"};if(r&&typeof r=="object"){let e=r,t=typeof e.message=="string"?e.message:V(e)??Object.prototype.toString.call(r),n=typeof e.name=="string"?e.name:"Error",s=typeof e.stack=="string"?e.stack:void 0;return {message:a(t,b),exceptionType:n,stackTrace:s?a(s,T):void 0,innerException:M(e.cause)}}return {message:a(String(r),b),exceptionType:"Error"}}function F(r){if(r.stackTrace)return r;try{let e=new Error(r.message).stack;if(e){let t=e.split(`
4
4
  `).slice(2).join(`
5
- `);return {...r,stackTrace:a(t||e,S)}}}catch{}return r}function P(r){if(r==null)return;if(r instanceof Error){let t=[`${r.name}: ${r.message}`];r.stack&&t.push(r.stack);let n=P(r.cause);return n&&t.push(`Caused by: ${n}`),a(t.join(`
6
- `),R)}let e=O(r);return e?a(e,R):a(String(r),R)}function O(r){try{let e=JSON.stringify(r);return e==="{}"?void 0:e}catch{return}}var U="cherryboard:queue:v1",x=class{constructor(e,t){this.enabled=e;this.maxItems=t;}get store(){if(!this.enabled||!d())return null;try{return window.localStorage}catch{return null}}push(e){let t=this.store;if(!(!t||e.length===0))try{let n=this.read().concat(e).slice(-this.maxItems);t.setItem(U,JSON.stringify(n));}catch{}}read(){let e=this.store;if(!e)return [];try{let t=e.getItem(U);if(!t)return [];let n=JSON.parse(t);return Array.isArray(n)?n:[]}catch{return []}}drain(){let e=this.read();return this.clear(),e}clear(){let e=this.store;if(e)try{e.removeItem(U);}catch{}}};var v=class{constructor(e=30,t=5){this.capacity=e;this.refillPerSec=t;this.tokens=e,this.last=Date.now();}allow(){let e=Date.now(),t=(e-this.last)/1e3;return this.tokens=Math.min(this.capacity,this.tokens+t*this.refillPerSec),this.last=e,this.tokens>=1?(this.tokens-=1,true):false}};var z=["password","passwd","secret","token","apikey","api_key","authorization","auth","cookie","session","credit","card","cvv","ssn"],W=["token","access_token","apikey","api_key","email","password","code","secret"],T="[Filtered]",J=/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/g;function A(r){let e=r;for(let t of W)e=e.replace(new RegExp(`([?&]${t}=)[^&#\\s]*`,"gi"),`$1${T}`);return e}function w(r,e=0){if(e>6)return r;if(typeof r=="string")return A(r).replace(J,T);if(Array.isArray(r))return r.map(t=>w(t,e+1));if(r&&typeof r=="object"){let t={};for(let[n,o]of Object.entries(r)){let s=n.toLowerCase();t[n]=z.some(i=>s.includes(i))?T:w(o,e+1);}return t}return r}function H(r){return {...r,message:A(r.message),context:w(r.context),breadcrumbs:r.breadcrumbs.map(e=>({...e,message:A(e.message),data:e.data?w(e.data):void 0}))}}var E=class{constructor(e,t){this.apiKey=t;this.endpoint=_(e);let n=typeof fetch=="function"?fetch.bind(globalThis):void 0;this.fetchImpl=n??(()=>Promise.reject(new Error("fetch unavailable")));}async send(e,t=false){if(e.length===0)return {ok:true,retryable:false,status:204};try{let n=await this.fetchImpl(this.endpoint,{method:"POST",headers:{"Content-Type":"application/json",Accept:"application/json","X-API-Key":this.apiKey},body:JSON.stringify({errors:e}),keepalive:t,mode:"cors",credentials:"omit"});if(n.status===429)return {ok:!1,retryable:!1,status:429,retryAfterMs:Q(n.headers?.get?.("Retry-After"))};let o=n.status>=500;return {ok:n.ok,retryable:o,status:n.status}}catch{return {ok:false,retryable:true,status:0}}}};function Q(r){if(!r)return 6e4;let t=Number(r);if(Number.isFinite(t)&&t>=0)return Math.min(t*1e3,36e5);let n=Date.parse(r);return Number.isNaN(n)?6e4:Math.min(Math.max(n-Date.now(),0),36e5)}function I(r,e,t){return Math.max(e,Math.min(t,r))}function Y(r){return new Promise(e=>setTimeout(e,r))}var V=3e3;function G(r){return {apiKey:r.apiKey,apiUrl:r.apiUrl,environment:r.environment??"production",release:r.release,enabled:r.enabled??true,sampleRate:I(r.sampleRate??1,0,1),maxBatchSize:I(r.maxBatchSize??20,1,100),flushIntervalMs:r.flushIntervalMs??4e3,maxQueueItems:r.maxQueueItems??100,maxRetries:r.maxRetries??3,maxBreadcrumbs:r.maxBreadcrumbs??30,offlineStorage:r.offlineStorage??true,captureUnhandledErrors:r.captureUnhandledErrors??true,captureUnhandledRejections:r.captureUnhandledRejections??true,captureResourceErrors:r.captureResourceErrors??true,captureConsole:r.captureConsole??true,autoBreadcrumbs:r.autoBreadcrumbs??true,denyUrls:r.denyUrls??[],allowUrls:r.allowUrls??[],beforeSend:r.beforeSend,debug:r.debug??false}}var k=class{constructor(e){this.buffer=[];this.flushTimer=null;this.processing=false;this.rateLimitedUntil=0;this.discarded={};this.closed=false;this.scope={tags:{}};this.teardown=[];this.config=G(e),this.transport=new E(this.config.apiUrl,this.config.apiKey),this.deduper=new y(V),this.limiter=new v,this.queue=new x(this.config.offlineStorage,this.config.maxQueueItems),this.breadcrumbs=new g(this.config.maxBreadcrumbs),this.config.enabled&&(this.config.autoBreadcrumbs&&this.breadcrumbs.install(),this.teardown.push(j(this)),this.installLifecycle(),this.drainOffline());}captureException(e,t){try{this.process(L($(e)),t?.severity??"Error",t);}catch(n){this.debug("captureException failed",n);}}captureMessage(e,t="Info",n){try{this.process({message:a(e,2e3),exceptionType:"Message"},n?.severity??t,n);}catch(o){this.debug("captureMessage failed",o);}}getDiscardedEvents(){return {...this.discarded}}discard(e,t=1){this.discarded[e]=(this.discarded[e]??0)+t;}addBreadcrumb(e){this.breadcrumbs.add(e);}setUser(e){this.scope.user=e??void 0;}setTag(e,t){this.scope.tags[e]=t;}setContext(e,t){this.scope.tags[e]=t;}close(){this.closed=true,this.flushTimer!==null&&(clearTimeout(this.flushTimer),this.flushTimer=null),this.flush(true),this.breadcrumbs.close();for(let e of this.teardown.splice(0))try{e();}catch{}}process(e,t,n){if(!this.config.enabled||this.closed)return;if(this.config.sampleRate<1&&Math.random()>this.config.sampleRate){this.discard("sampled");return}let o=`${e.stackTrace??""}
7
- ${d()?location.href:""}`;if(B(o,this.config.denyUrls)){this.discard("filtered");return}if(this.config.allowUrls.length>0&&!B(o,this.config.allowUrls)){this.discard("filtered");return}if(!this.deduper.shouldSend(D(e.message,e.stackTrace))){this.discard("deduped");return}let s={message:e.message,severity:t,timestamp:m(),exceptionType:e.exceptionType,stackTrace:e.stackTrace,innerException:e.innerException,userId:this.scope.user?.id,requestPath:d()?location.pathname:void 0,userAgent:d()?navigator.userAgent:void 0,context:this.buildContext(n),breadcrumbs:this.breadcrumbs.snapshot()};if(s=H(s),this.config.beforeSend){let i=this.config.beforeSend(s);if(!i){this.discard("filtered");return}s=i;}this.enqueue(this.toPayload(s));}buildContext(e){let t={sdk:{name:"cherryboard-web",version:h},environment:this.config.environment};return this.config.release&&(t.release=this.config.release),d()&&(t.url=location.href,document.referrer&&(t.referrer=document.referrer),t.language=navigator.language,t.viewport={width:window.innerWidth,height:window.innerHeight}),this.scope.user&&(t.user=this.scope.user),Object.keys(this.scope.tags).length>0&&(t.tags={...this.scope.tags}),e?.componentStack&&(t.componentStack=e.componentStack),e?.digest&&(t.digest=e.digest),e?.context&&Object.assign(t,e.context),t}toPayload(e){let t=C({...e.context,breadcrumbs:e.breadcrumbs});return t===void 0&&(t=C(e.context)),{message:e.message,stackTrace:e.stackTrace,severity:e.severity,timestamp:e.timestamp,userId:e.userId,requestPath:e.requestPath,userAgent:e.userAgent,exceptionType:e.exceptionType,innerException:e.innerException,metadata:t}}enqueue(e){this.buffer.push(e),this.buffer.length>=this.config.maxBatchSize?this.flush():this.scheduleFlush();}scheduleFlush(){this.closed||this.flushTimer===null&&(this.flushTimer=setTimeout(()=>{this.flushTimer=null,this.flush();},this.config.flushIntervalMs));}async flush(e=false){if(this.flushTimer!==null&&(clearTimeout(this.flushTimer),this.flushTimer=null),this.buffer.length!==0){if(e){if(Date.now()<this.rateLimitedUntil)return;for(;this.buffer.length>0;){let t=this.buffer.splice(0,this.config.maxBatchSize);if(!this.limiter.allow())break;this.transport.send(t,true);}return}if(Date.now()<this.rateLimitedUntil){this.scheduleFlush();return}if(!this.processing){this.processing=true;try{for(;this.buffer.length>0;){let t=this.buffer.splice(0,this.config.maxBatchSize);if(!this.limiter.allow()){this.debug("rate limited; dropping",t.length,"events"),this.discard("rate_limited",t.length);break}if(!await this.deliver(t)){this.queue.push(t);break}}}finally{this.processing=false;}}}}async deliver(e){for(let t=0;t<=this.config.maxRetries;t++){let n=await this.transport.send(e,false);if(n.ok)return true;if(n.status===429)return this.rateLimitedUntil=Date.now()+(n.retryAfterMs??6e4),this.debug("rate limited by server; pausing for",n.retryAfterMs,"ms"),false;if(!n.retryable)return this.debug("non-retryable response",n.status,"\u2014 dropping batch"),this.discard("send_failed",e.length),true;if(t===this.config.maxRetries)return false;await Y(I(2**t*1e3+Math.random()*250,0,15e3));}return false}drainOffline(){let e=this.queue.drain();e.length>0&&(this.buffer.push(...e),this.scheduleFlush());}installLifecycle(){if(!d())return;let e=()=>{document.visibilityState==="hidden"&&this.flush(true);},t=()=>{this.flush(true);},n=()=>this.drainOffline();document.addEventListener("visibilitychange",e),window.addEventListener("pagehide",t),window.addEventListener("online",n),this.teardown.push(()=>{document.removeEventListener("visibilitychange",e),window.removeEventListener("pagehide",t),window.removeEventListener("online",n);});}debug(...e){this.config.debug&&console.warn("[cherryboard]",...e);}};var K="__CHERRYBOARD__";function c(){let r=globalThis,e=r[K];return e||(e={},r[K]=e),e}function N(r){let e=c();return e.client||(e.client=new k(r)),e.client}function M(){return c().client??null}function X(){return c().client!=null}function p(r,e){c().client?.captureException(r,e);}function Z(r,e,t){c().client?.captureMessage(r,e,t);}function ee(r){c().client?.addBreadcrumb(r);}function re(r){c().client?.setUser(r);}function te(r,e){c().client?.setTag(r,e);}function ne(r,e){c().client?.setContext(r,e);}function oe(){let r=c().client;return r?r.flush():Promise.resolve()}function se(r,e,t){c().client?.captureException(r,{severity:"Error",context:{source:"nextjs-server",...e?.path?{requestPath:e.path}:{},...e?.method?{requestMethod:e.method}:{},...t??{}}});}function ie(){return c().client?.getDiscardedEvents()??{}}function ae(){let r=c();r.client?.close(),r.client=void 0;}var f=class extends react.Component{constructor(){super(...arguments);this.state={error:null};this.reset=()=>{this.setState({error:null});};}static getDerivedStateFromError(t){return {error:t}}componentDidCatch(t,n){p(t,{severity:"Error",componentStack:n.componentStack??void 0,context:{source:"react-error-boundary"}}),this.props.onError?.(t,n);}componentDidUpdate(t){this.state.error&&!ue(t.resetKeys,this.props.resetKeys)&&this.reset();}render(){let{error:t}=this.state;if(t){let{fallback:n}=this.props;return typeof n=="function"?n({error:t,reset:this.reset}):n??null}return this.props.children}};function ue(r,e){return r===e?true:!r||!e||r.length!==e.length?false:r.every((t,n)=>Object.is(t,e[n]))}function pe({config:r,children:e,withBoundary:t=false,fallback:n}){let o=react.useRef(r);return react.useEffect(()=>{typeof window<"u"&&N(o.current);},[]),t?jsxRuntime.jsx(f,{fallback:n,children:e}):jsxRuntime.jsx(jsxRuntime.Fragment,{children:e})}function me(){return M()}function ge(){return react.useCallback((r,e)=>p(r,e),[])}function ye(r){p(r,{severity:"Error",digest:r.digest,context:{source:"next-error-boundary"}});}exports.CherryBoardProvider=pe;exports.ErrorBoundary=f;exports.SDK_VERSION=h;exports.addBreadcrumb=ee;exports.captureException=p;exports.captureMessage=Z;exports.captureRequestError=se;exports.captureRouteError=ye;exports.close=ae;exports.flush=oe;exports.getClient=M;exports.getDiscardedEvents=ie;exports.init=N;exports.isInitialized=X;exports.setContext=ne;exports.setTag=te;exports.setUser=re;exports.useCaptureError=ge;exports.useCherryBoard=me;
5
+ `);return {...r,stackTrace:a(t||e,T)}}}catch{}return r}function M(r){if(r==null)return;if(r instanceof Error){let t=[`${r.name}: ${r.message}`];r.stack&&t.push(r.stack);let n=M(r.cause);return n&&t.push(`Caused by: ${n}`),a(t.join(`
6
+ `),P)}let e=V(r);return e?a(e,P):a(String(r),P)}function V(r){try{let e=JSON.stringify(r);return e==="{}"?void 0:e}catch{return}}var Q=/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i,Y=/^[0-9a-f]{16,}$/i,Z=/^\d+$/,ee=/^(?=.*\d)[A-Za-z0-9_-]{12,}$/;function re(r){return Q.test(r)||Z.test(r)||Y.test(r)||ee.test(r)}function U(r,e){let t;try{t=new URL(r,e??(typeof location<"u"?location.href:void 0)).pathname;}catch{return null}if(!t||t==="/")return "/";let n=t.split("/").filter(Boolean);if(n.length===0)return "/";let s=n.slice(0,12).map(i=>re(i)?":id":i);n.length>12&&s.push("\u2026");let o="/"+s.join("/");return o.length>300?o.slice(0,300):o}var f=[50,100,250,500,1e3,2500,5e3];function z(r){for(let e=0;e<f.length;e++)if(r<=f[e])return e;return f.length}var w=class{constructor(e){this.options=e;this.requests=new Map;this.pageViews=new Map;this.teardown=[];this.closed=false;this.endpoint=O(e.apiUrl);let t=typeof fetch=="function"?fetch.bind(globalThis):void 0;this.fetchImpl=t??(()=>Promise.reject(new Error("fetch unavailable")));}start(){!u()||this.closed||(this.recordPageView(location.pathname,true),this.observeResources(),this.observeNavigation(),this.observeVisibility(),this.timer=setInterval(()=>{this.flush();},this.options.flushIntervalMs));}observeResources(){if(!(typeof PerformanceObserver>"u"))try{this.observer=new PerformanceObserver(e=>{for(let t of e.getEntries())this.recordResource(t);}),this.observer.observe({type:"resource",buffered:!0});}catch{}}recordResource(e){if(e.initiatorType!=="fetch"&&e.initiatorType!=="xmlhttprequest"||e.name.startsWith(this.endpoint)||e.name.includes("/api/v1/errors/batch"))return;let t=U(e.name);if(!t)return;let n=Math.round(e.duration);n<=0||this.addRequest(t,"ALL",n,false);}addRequest(e,t,n,s){let o=`${t} ${e}`,i=this.requests.get(o);if(!i){if(this.requests.size>=this.options.maxRoutes)return;i={route:e,method:t,count:0,errorCount:0,sumMs:0,maxMs:0,buckets:new Array(f.length+1).fill(0)},this.requests.set(o,i);}i.count++,s&&i.errorCount++,i.sumMs+=n,n>i.maxMs&&(i.maxMs=n),i.buckets[z(n)]++;}observeNavigation(){let e=()=>this.recordPageView(location.pathname,false);try{let t=window.history,n=s=>{let o=t[s];if(typeof o!="function")return ()=>{};let i=(...d)=>{let c=o.apply(window.history,d);return e(),c};return t[s]=i,()=>{t[s]===i&&(t[s]=o);}};this.teardown.push(n("pushState"),n("replaceState")),window.addEventListener("popstate",e),this.teardown.push(()=>window.removeEventListener("popstate",e));}catch{}}recordPageView(e,t){let n=U(e);if(!n)return;let s=this.pageViews.get(n);if(!s){if(this.pageViews.size>=this.options.maxRoutes)return;s={route:n,views:0,visits:0},this.pageViews.set(n,s);}s.views++,t&&s.visits++;}observeVisibility(){let e=()=>{document.visibilityState==="hidden"&&this.flush(true);};document.addEventListener("visibilitychange",e),this.teardown.push(()=>document.removeEventListener("visibilitychange",e));}async flush(e=false){if(this.requests.size===0&&this.pageViews.size===0)return;let t={requests:Array.from(this.requests.values()).map(n=>({route:n.route,method:n.method,count:n.count,errorCount:n.errorCount,sumMs:n.sumMs,maxMs:n.maxMs,buckets:n.buckets})),pageViews:Array.from(this.pageViews.values()).map(n=>({route:n.route,views:n.views,visits:n.visits}))};this.requests.clear(),this.pageViews.clear();try{await this.fetchImpl(this.endpoint,{method:"POST",headers:{"Content-Type":"application/json","X-API-Key":this.options.apiKey},body:JSON.stringify(t),keepalive:e,mode:"cors",credentials:"omit"});}catch{this.options.debug&&console.warn("[cherryboard] metrics flush failed");}}close(){this.closed=true,this.timer&&clearInterval(this.timer),this.observer?.disconnect();for(let e of this.teardown)e();this.teardown=[];}};var I="cherryboard:queue:v1",x=class{constructor(e,t){this.enabled=e;this.maxItems=t;}get store(){if(!this.enabled||!u())return null;try{return window.localStorage}catch{return null}}push(e){let t=this.store;if(!(!t||e.length===0))try{let n=this.read().concat(e).slice(-this.maxItems);t.setItem(I,JSON.stringify(n));}catch{}}read(){let e=this.store;if(!e)return [];try{let t=e.getItem(I);if(!t)return [];let n=JSON.parse(t);return Array.isArray(n)?n:[]}catch{return []}}drain(){let e=this.read();return this.clear(),e}clear(){let e=this.store;if(e)try{e.removeItem(I);}catch{}}};var E=class{constructor(e=30,t=5){this.capacity=e;this.refillPerSec=t;this.tokens=e,this.last=Date.now();}allow(){let e=Date.now(),t=(e-this.last)/1e3;return this.tokens=Math.min(this.capacity,this.tokens+t*this.refillPerSec),this.last=e,this.tokens>=1?(this.tokens-=1,true):false}};var te=["password","passwd","secret","token","apikey","api_key","authorization","auth","cookie","session","credit","card","cvv","ssn"],ne=["token","access_token","apikey","api_key","email","password","code","secret"],A="[Filtered]",se=/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/g;function N(r){let e=r;for(let t of ne)e=e.replace(new RegExp(`([?&]${t}=)[^&#\\s]*`,"gi"),`$1${A}`);return e}function k(r,e=0){if(e>6)return r;if(typeof r=="string")return N(r).replace(se,A);if(Array.isArray(r))return r.map(t=>k(t,e+1));if(r&&typeof r=="object"){let t={};for(let[n,s]of Object.entries(r)){let o=n.toLowerCase();t[n]=te.some(i=>o.includes(i))?A:k(s,e+1);}return t}return r}function G(r){return {...r,message:N(r.message),context:k(r.context),breadcrumbs:r.breadcrumbs.map(e=>({...e,message:N(e.message),data:e.data?k(e.data):void 0}))}}var C=class{constructor(e,t){this.apiKey=t;this.endpoint=D(e);let n=typeof fetch=="function"?fetch.bind(globalThis):void 0;this.fetchImpl=n??(()=>Promise.reject(new Error("fetch unavailable")));}async send(e,t=false){if(e.length===0)return {ok:true,retryable:false,status:204};try{let n=await this.fetchImpl(this.endpoint,{method:"POST",headers:{"Content-Type":"application/json",Accept:"application/json","X-API-Key":this.apiKey},body:JSON.stringify({errors:e}),keepalive:t,mode:"cors",credentials:"omit"});if(n.status===429)return {ok:!1,retryable:!1,status:429,retryAfterMs:oe(n.headers?.get?.("Retry-After"))};let s=n.status>=500;return {ok:n.ok,retryable:s,status:n.status}}catch{return {ok:false,retryable:true,status:0}}}};function oe(r){if(!r)return 6e4;let t=Number(r);if(Number.isFinite(t)&&t>=0)return Math.min(t*1e3,36e5);let n=Date.parse(r);return Number.isNaN(n)?6e4:Math.min(Math.max(n-Date.now(),0),36e5)}var ie=200;function _(r,e,t){return Math.max(e,Math.min(t,r))}function ae(r){return new Promise(e=>setTimeout(e,r))}var ce=3e3;function ue(r){return {apiKey:r.apiKey,apiUrl:r.apiUrl,environment:r.environment??"production",release:r.release,enabled:r.enabled??true,sampleRate:_(r.sampleRate??1,0,1),maxBatchSize:_(r.maxBatchSize??20,1,100),flushIntervalMs:r.flushIntervalMs??4e3,maxQueueItems:r.maxQueueItems??100,maxRetries:r.maxRetries??3,maxBreadcrumbs:r.maxBreadcrumbs??30,offlineStorage:r.offlineStorage??true,captureUnhandledErrors:r.captureUnhandledErrors??true,captureUnhandledRejections:r.captureUnhandledRejections??true,captureResourceErrors:r.captureResourceErrors??true,captureConsole:r.captureConsole??true,autoBreadcrumbs:r.autoBreadcrumbs??true,denyUrls:r.denyUrls??[],allowUrls:r.allowUrls??[],beforeSend:r.beforeSend,trackPerformance:r.trackPerformance??false,metricsFlushIntervalMs:r.metricsFlushIntervalMs??6e4,debug:r.debug??false}}var R=class{constructor(e){this.buffer=[];this.flushTimer=null;this.processing=false;this.rateLimitedUntil=0;this.discarded={};this.closed=false;this.scope={tags:{}};this.teardown=[];this.config=ue(e),this.transport=new C(this.config.apiUrl,this.config.apiKey),this.deduper=new v(ce),this.limiter=new E,this.queue=new x(this.config.offlineStorage,this.config.maxQueueItems),this.config.trackPerformance&&this.config.enabled&&(this.metrics=new w({apiKey:this.config.apiKey,apiUrl:this.config.apiUrl,flushIntervalMs:this.config.metricsFlushIntervalMs,maxRoutes:ie,debug:this.config.debug}),this.metrics.start()),this.breadcrumbs=new y(this.config.maxBreadcrumbs),this.config.enabled&&(this.config.autoBreadcrumbs&&this.breadcrumbs.install(),this.teardown.push(H(this)),this.installLifecycle(),this.drainOffline());}captureException(e,t){try{this.process(F(K(e)),t?.severity??"Error",t);}catch(n){this.debug("captureException failed",n);}}captureMessage(e,t="Info",n){try{this.process({message:a(e,2e3),exceptionType:"Message"},n?.severity??t,n);}catch(s){this.debug("captureMessage failed",s);}}getDiscardedEvents(){return {...this.discarded}}discard(e,t=1){this.discarded[e]=(this.discarded[e]??0)+t;}addBreadcrumb(e){this.breadcrumbs.add(e);}setUser(e){this.scope.user=e??void 0;}setTag(e,t){this.scope.tags[e]=t;}setContext(e,t){this.scope.tags[e]=t;}close(){this.closed=true,this.flushTimer!==null&&(clearTimeout(this.flushTimer),this.flushTimer=null),this.flush(true),this.metrics?.close(),this.breadcrumbs.close();for(let e of this.teardown.splice(0))try{e();}catch{}}process(e,t,n){if(!this.config.enabled||this.closed)return;if(this.config.sampleRate<1&&Math.random()>this.config.sampleRate){this.discard("sampled");return}let s=`${e.stackTrace??""}
7
+ ${u()?location.href:""}`;if(B(s,this.config.denyUrls)){this.discard("filtered");return}if(this.config.allowUrls.length>0&&!B(s,this.config.allowUrls)){this.discard("filtered");return}if(!this.deduper.shouldSend(q(e.message,e.stackTrace))){this.discard("deduped");return}let o={message:e.message,severity:t,timestamp:g(),exceptionType:e.exceptionType,stackTrace:e.stackTrace,innerException:e.innerException,userId:this.scope.user?.id,requestPath:u()?location.pathname:void 0,userAgent:u()?navigator.userAgent:void 0,context:this.buildContext(n),breadcrumbs:this.breadcrumbs.snapshot()};if(o=G(o),this.config.beforeSend){let i=this.config.beforeSend(o);if(!i){this.discard("filtered");return}o=i;}this.enqueue(this.toPayload(o));}buildContext(e){let t={sdk:{name:"cherryboard-web",version:m},environment:this.config.environment};return this.config.release&&(t.release=this.config.release),u()&&(t.url=location.href,document.referrer&&(t.referrer=document.referrer),t.language=navigator.language,t.viewport={width:window.innerWidth,height:window.innerHeight}),this.scope.user&&(t.user=this.scope.user),Object.keys(this.scope.tags).length>0&&(t.tags={...this.scope.tags}),e?.componentStack&&(t.componentStack=e.componentStack),e?.digest&&(t.digest=e.digest),e?.context&&Object.assign(t,e.context),t}toPayload(e){let t=S({...e.context,breadcrumbs:e.breadcrumbs});return t===void 0&&(t=S(e.context)),{message:e.message,stackTrace:e.stackTrace,severity:e.severity,timestamp:e.timestamp,userId:e.userId,requestPath:e.requestPath,userAgent:e.userAgent,exceptionType:e.exceptionType,innerException:e.innerException,metadata:t}}enqueue(e){this.buffer.push(e),this.buffer.length>=this.config.maxBatchSize?this.flush():this.scheduleFlush();}scheduleFlush(){this.closed||this.flushTimer===null&&(this.flushTimer=setTimeout(()=>{this.flushTimer=null,this.flush();},this.config.flushIntervalMs));}async flush(e=false){if(this.flushTimer!==null&&(clearTimeout(this.flushTimer),this.flushTimer=null),this.buffer.length!==0){if(e){if(Date.now()<this.rateLimitedUntil)return;for(;this.buffer.length>0;){let t=this.buffer.splice(0,this.config.maxBatchSize);if(!this.limiter.allow())break;this.transport.send(t,true);}return}if(Date.now()<this.rateLimitedUntil){this.scheduleFlush();return}if(!this.processing){this.processing=true;try{for(;this.buffer.length>0;){let t=this.buffer.splice(0,this.config.maxBatchSize);if(!this.limiter.allow()){this.debug("rate limited; dropping",t.length,"events"),this.discard("rate_limited",t.length);break}if(!await this.deliver(t)){this.queue.push(t);break}}}finally{this.processing=false;}}}}async deliver(e){for(let t=0;t<=this.config.maxRetries;t++){let n=await this.transport.send(e,false);if(n.ok)return true;if(n.status===429)return this.rateLimitedUntil=Date.now()+(n.retryAfterMs??6e4),this.debug("rate limited by server; pausing for",n.retryAfterMs,"ms"),false;if(!n.retryable)return this.debug("non-retryable response",n.status,"\u2014 dropping batch"),this.discard("send_failed",e.length),true;if(t===this.config.maxRetries)return false;await ae(_(2**t*1e3+Math.random()*250,0,15e3));}return false}drainOffline(){let e=this.queue.drain();e.length>0&&(this.buffer.push(...e),this.scheduleFlush());}installLifecycle(){if(!u())return;let e=()=>{document.visibilityState==="hidden"&&this.flush(true);},t=()=>{this.flush(true);},n=()=>this.drainOffline();document.addEventListener("visibilitychange",e),window.addEventListener("pagehide",t),window.addEventListener("online",n),this.teardown.push(()=>{document.removeEventListener("visibilitychange",e),window.removeEventListener("pagehide",t),window.removeEventListener("online",n);});}debug(...e){this.config.debug&&console.warn("[cherryboard]",...e);}};var X="__CHERRYBOARD__";function l(){let r=globalThis,e=r[X];return e||(e={},r[X]=e),e}function L(r){let e=l();return e.client||(e.client=new R(r)),e.client}function $(){return l().client??null}function de(){return l().client!=null}function p(r,e){l().client?.captureException(r,e);}function le(r,e,t){l().client?.captureMessage(r,e,t);}function pe(r){l().client?.addBreadcrumb(r);}function fe(r){l().client?.setUser(r);}function he(r,e){l().client?.setTag(r,e);}function me(r,e){l().client?.setContext(r,e);}function ge(){let r=l().client;return r?r.flush():Promise.resolve()}function ye(r,e,t){l().client?.captureException(r,{severity:"Error",context:{source:"nextjs-server",...e?.path?{requestPath:e.path}:{},...e?.method?{requestMethod:e.method}:{},...t??{}}});}function ve(){return l().client?.getDiscardedEvents()??{}}function be(){let r=l();r.client?.close(),r.client=void 0;}var h=class extends react.Component{constructor(){super(...arguments);this.state={error:null};this.reset=()=>{this.setState({error:null});};}static getDerivedStateFromError(t){return {error:t}}componentDidCatch(t,n){p(t,{severity:"Error",componentStack:n.componentStack??void 0,context:{source:"react-error-boundary"}}),this.props.onError?.(t,n);}componentDidUpdate(t){this.state.error&&!xe(t.resetKeys,this.props.resetKeys)&&this.reset();}render(){let{error:t}=this.state;if(t){let{fallback:n}=this.props;return typeof n=="function"?n({error:t,reset:this.reset}):n??null}return this.props.children}};function xe(r,e){return r===e?true:!r||!e||r.length!==e.length?false:r.every((t,n)=>Object.is(t,e[n]))}function Ce({config:r,children:e,withBoundary:t=false,fallback:n}){let s=react.useRef(r);return react.useEffect(()=>{typeof window<"u"&&L(s.current);},[]),t?jsxRuntime.jsx(h,{fallback:n,children:e}):jsxRuntime.jsx(jsxRuntime.Fragment,{children:e})}function Be(){return $()}function Pe(){return react.useCallback((r,e)=>p(r,e),[])}function Te(r){p(r,{severity:"Error",digest:r.digest,context:{source:"next-error-boundary"}});}exports.CherryBoardProvider=Ce;exports.ErrorBoundary=h;exports.SDK_VERSION=m;exports.addBreadcrumb=pe;exports.captureException=p;exports.captureMessage=le;exports.captureRequestError=ye;exports.captureRouteError=Te;exports.close=be;exports.flush=ge;exports.getClient=$;exports.getDiscardedEvents=ve;exports.init=L;exports.isInitialized=de;exports.setContext=me;exports.setTag=he;exports.setUser=fe;exports.useCaptureError=Pe;exports.useCherryBoard=Be;
@@ -32,7 +32,7 @@ declare class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryS
32
32
  }
33
33
 
34
34
  /** SDK version — kept in sync with package.json. */
35
- declare const SDK_VERSION = "1.1.0";
35
+ declare const SDK_VERSION = "1.2.0";
36
36
  /** Severity levels — these strings match the backend `ErrorSeverity` enum exactly. */
37
37
  type Severity = 'Debug' | 'Info' | 'Warning' | 'Error' | 'Critical';
38
38
  /** A trail entry giving context that led up to an error. */
@@ -121,6 +121,16 @@ interface CherryBoardConfig {
121
121
  captureResourceErrors?: boolean;
122
122
  /** Turn console.error/warn into breadcrumbs (never into events). Default true. */
123
123
  captureConsole?: boolean;
124
+ /**
125
+ * Collect API request timings and page views alongside errors.
126
+ *
127
+ * Off by default: upgrading the package must not silently start sending new
128
+ * data about someone's users. Aggregated in the browser and stripped of
129
+ * identifiers before it leaves — see the performance docs.
130
+ */
131
+ trackPerformance?: boolean;
132
+ /** How often aggregated metrics are posted. Default 60000 (once a minute). */
133
+ metricsFlushIntervalMs?: number;
124
134
  /** Auto-record navigation / click / fetch breadcrumbs. Default true. */
125
135
  autoBreadcrumbs?: boolean;
126
136
  /** Drop events whose stack/URL matches any of these. */
@@ -143,6 +153,8 @@ interface ResolvedConfig {
143
153
  environment: string;
144
154
  release?: string;
145
155
  enabled: boolean;
156
+ trackPerformance: boolean;
157
+ metricsFlushIntervalMs: number;
146
158
  sampleRate: number;
147
159
  maxBatchSize: number;
148
160
  flushIntervalMs: number;
@@ -212,6 +224,7 @@ declare class CherryBoardClient {
212
224
  private readonly deduper;
213
225
  private readonly limiter;
214
226
  private readonly queue;
227
+ private readonly metrics?;
215
228
  private buffer;
216
229
  private flushTimer;
217
230
  private processing;
@@ -32,7 +32,7 @@ declare class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryS
32
32
  }
33
33
 
34
34
  /** SDK version — kept in sync with package.json. */
35
- declare const SDK_VERSION = "1.1.0";
35
+ declare const SDK_VERSION = "1.2.0";
36
36
  /** Severity levels — these strings match the backend `ErrorSeverity` enum exactly. */
37
37
  type Severity = 'Debug' | 'Info' | 'Warning' | 'Error' | 'Critical';
38
38
  /** A trail entry giving context that led up to an error. */
@@ -121,6 +121,16 @@ interface CherryBoardConfig {
121
121
  captureResourceErrors?: boolean;
122
122
  /** Turn console.error/warn into breadcrumbs (never into events). Default true. */
123
123
  captureConsole?: boolean;
124
+ /**
125
+ * Collect API request timings and page views alongside errors.
126
+ *
127
+ * Off by default: upgrading the package must not silently start sending new
128
+ * data about someone's users. Aggregated in the browser and stripped of
129
+ * identifiers before it leaves — see the performance docs.
130
+ */
131
+ trackPerformance?: boolean;
132
+ /** How often aggregated metrics are posted. Default 60000 (once a minute). */
133
+ metricsFlushIntervalMs?: number;
124
134
  /** Auto-record navigation / click / fetch breadcrumbs. Default true. */
125
135
  autoBreadcrumbs?: boolean;
126
136
  /** Drop events whose stack/URL matches any of these. */
@@ -143,6 +153,8 @@ interface ResolvedConfig {
143
153
  environment: string;
144
154
  release?: string;
145
155
  enabled: boolean;
156
+ trackPerformance: boolean;
157
+ metricsFlushIntervalMs: number;
146
158
  sampleRate: number;
147
159
  maxBatchSize: number;
148
160
  flushIntervalMs: number;
@@ -212,6 +224,7 @@ declare class CherryBoardClient {
212
224
  private readonly deduper;
213
225
  private readonly limiter;
214
226
  private readonly queue;
227
+ private readonly metrics?;
215
228
  private buffer;
216
229
  private flushTimer;
217
230
  private processing;
@@ -1,7 +1,7 @@
1
1
  "use client";
2
- import {Component,useRef,useEffect,useCallback}from'react';import {jsx,Fragment}from'react/jsx-runtime';var h="1.1.0";function d(){return typeof window<"u"&&typeof document<"u"}function m(){return new Date().toISOString()}function a(r,e){return e<=0?"":r.length<=e?r:`${r.slice(0,e-1)}\u2026`}function C(r,e=24e3){let t=new WeakSet;try{let n=JSON.stringify(r,(o,s)=>{if(s instanceof Error)return {name:s.name,message:s.message,stack:s.stack};if(typeof s=="object"&&s!==null){if(t.has(s))return "[Circular]";t.add(s);}if(typeof s=="bigint")return s.toString();if(typeof s!="function")return s});return n===void 0||n.length>e?void 0:n}catch{return}}function B(r,e){return !r||e.length===0?false:e.some(t=>typeof t=="string"?r.includes(t):t.test(r))}function _(r){let e=r.replace(/\/+$/,"");return `${/\/api\/v\d+$/.test(e)?e:`${e}/api/v1`}/errors/batch`}var g=class{constructor(e){this.max=e;this.items=[];this.teardown=[];}add(e){this.items.push({timestamp:e.timestamp??m(),category:e.category,message:a(e.message,500),level:e.level,data:e.data}),this.items.length>this.max&&this.items.shift();}snapshot(){return this.items.slice()}install(){d()&&(this.installHistory(),this.installClicks(),this.installFetch());}installHistory(){try{let e=window.history,t=o=>{let s=e[o];if(typeof s!="function")return ()=>{};let i=(...l)=>{try{let u=l[2];typeof u=="string"&&this.add({category:"navigation",message:`${o} \u2192 ${u}`});}catch{}return s.apply(window.history,l)};return e[o]=i,()=>{e[o]===i&&(e[o]=s);}};this.teardown.push(t("pushState"),t("replaceState"));let n=()=>this.add({category:"navigation",message:`popstate \u2192 ${location.pathname}`});window.addEventListener("popstate",n),this.teardown.push(()=>window.removeEventListener("popstate",n));}catch{}}installClicks(){try{let e=t=>{let n=t.target;if(!n||typeof n.tagName!="string")return;let o=n.id?`#${n.id}`:"",s=typeof n.className=="string"?n.className:"",i=s?`.${s.split(/\s+/).filter(Boolean).slice(0,2).join(".")}`:"";this.add({category:"click",message:`${n.tagName.toLowerCase()}${o}${i}`});};window.addEventListener("click",e,{capture:!0,passive:!0}),this.teardown.push(()=>window.removeEventListener("click",e,{capture:!0}));}catch{}}installFetch(){try{let e=window.fetch;if(typeof e!="function")return;let t=(...n)=>{let[o,s]=n,i=s?.method??(typeof o=="object"&&o&&"method"in o?o.method:"GET"),l=typeof o=="string"?o:o instanceof URL?o.href:o.url;return e.apply(window,n).then(u=>(this.add({category:"fetch",message:`${i} ${l} \u2192 ${u.status}`,level:u.ok?void 0:"Warning"}),u),u=>{throw this.add({category:"fetch",message:`${i} ${l} \u2192 failed`,level:"Warning"}),u})};window.fetch=t,this.teardown.push(()=>{window.fetch===t&&(window.fetch=e);});}catch{}}close(){for(let e of this.teardown.splice(0))try{e();}catch{}}};var y=class{constructor(e=4e3,t=100){this.windowMs=e;this.max=t;this.seen=new Map;}shouldSend(e){let t=Date.now(),n=this.seen.get(e);if(n!==void 0&&t-n<this.windowMs)return false;if(this.seen.set(e,t),this.seen.size>this.max){let o=this.seen.keys().next().value;o!==void 0&&this.seen.delete(o);}return true}};function D(r,e){let t=(e??"").split(`
3
- `).slice(0,4).map(n=>n.replace(/:\d+:\d+/g,"").replace(/\?[^\s)]*/g,"").replace(/https?:\/\/[^/]+/g,"").trim()).join("|");return `${r}::${t}`.slice(0,500)}function j(r){if(!d())return ()=>{};let e=r.config,t=[];if(e.captureUnhandledErrors||e.captureResourceErrors){let n=o=>{try{let s=o.target;if(s instanceof HTMLElement){if(!e.captureResourceErrors)return;let l=s,u=l.src||l.href;if(!u)return;r.captureMessage(`Resource failed to load: ${u}`,"Warning",{context:{resource:s.tagName.toLowerCase(),url:u}});return}if(!e.captureUnhandledErrors)return;let i=o;if(!i.error&&(!i.message||i.message==="Script error."))return;r.captureException(i.error??i.message);}catch{}};window.addEventListener("error",n,true),t.push(()=>window.removeEventListener("error",n,true));}if(e.captureUnhandledRejections){let n=o=>{try{r.captureException(o.reason??"Unhandled promise rejection",{context:{unhandledRejection:!0}});}catch{}};window.addEventListener("unhandledrejection",n),t.push(()=>window.removeEventListener("unhandledrejection",n));}if(e.captureConsole){let n=console;for(let o of ["error","warn"]){let s=n[o];if(typeof s!="function")continue;let i=(...l)=>{try{r.addBreadcrumb({category:"console",level:o==="error"?"Error":"Warning",message:l.map(q).join(" ").slice(0,500)});}catch{}return s.apply(console,l)};n[o]=i,t.push(()=>{n[o]===i&&(n[o]=s);});}}return ()=>{for(let n of t.splice(0))try{n();}catch{}}}function q(r){if(typeof r=="string")return r;if(r instanceof Error)return `${r.name}: ${r.message}`;try{return JSON.stringify(r)??String(r)}catch{return String(r)}}var b=2e3,S=8e3,R=4e3;function $(r){if(r instanceof Error)return {message:a(r.message||r.name||"Error",b),exceptionType:r.name||"Error",stackTrace:r.stack?a(r.stack,S):void 0,innerException:P(r.cause)};if(typeof r=="string")return {message:a(r,b),exceptionType:"Error"};if(r&&typeof r=="object"){let e=r,t=typeof e.message=="string"?e.message:O(e)??Object.prototype.toString.call(r),n=typeof e.name=="string"?e.name:"Error",o=typeof e.stack=="string"?e.stack:void 0;return {message:a(t,b),exceptionType:n,stackTrace:o?a(o,S):void 0,innerException:P(e.cause)}}return {message:a(String(r),b),exceptionType:"Error"}}function L(r){if(r.stackTrace)return r;try{let e=new Error(r.message).stack;if(e){let t=e.split(`
2
+ import {Component,useRef,useEffect,useCallback}from'react';import {jsx,Fragment}from'react/jsx-runtime';var m="1.2.0";function u(){return typeof window<"u"&&typeof document<"u"}function g(){return new Date().toISOString()}function a(r,e){return e<=0?"":r.length<=e?r:`${r.slice(0,e-1)}\u2026`}function S(r,e=24e3){let t=new WeakSet;try{let n=JSON.stringify(r,(s,o)=>{if(o instanceof Error)return {name:o.name,message:o.message,stack:o.stack};if(typeof o=="object"&&o!==null){if(t.has(o))return "[Circular]";t.add(o);}if(typeof o=="bigint")return o.toString();if(typeof o!="function")return o});return n===void 0||n.length>e?void 0:n}catch{return}}function B(r,e){return !r||e.length===0?false:e.some(t=>typeof t=="string"?r.includes(t):t.test(r))}function D(r){return `${j(r)}/errors/batch`}function O(r){return `${j(r)}/metrics`}function j(r){let e=r.replace(/\/+$/,"");return /\/api\/v\d+$/.test(e)?e:`${e}/api/v1`}var y=class{constructor(e){this.max=e;this.items=[];this.teardown=[];}add(e){this.items.push({timestamp:e.timestamp??g(),category:e.category,message:a(e.message,500),level:e.level,data:e.data}),this.items.length>this.max&&this.items.shift();}snapshot(){return this.items.slice()}install(){u()&&(this.installHistory(),this.installClicks(),this.installFetch());}installHistory(){try{let e=window.history,t=s=>{let o=e[s];if(typeof o!="function")return ()=>{};let i=(...d)=>{try{let c=d[2];typeof c=="string"&&this.add({category:"navigation",message:`${s} \u2192 ${c}`});}catch{}return o.apply(window.history,d)};return e[s]=i,()=>{e[s]===i&&(e[s]=o);}};this.teardown.push(t("pushState"),t("replaceState"));let n=()=>this.add({category:"navigation",message:`popstate \u2192 ${location.pathname}`});window.addEventListener("popstate",n),this.teardown.push(()=>window.removeEventListener("popstate",n));}catch{}}installClicks(){try{let e=t=>{let n=t.target;if(!n||typeof n.tagName!="string")return;let s=n.id?`#${n.id}`:"",o=typeof n.className=="string"?n.className:"",i=o?`.${o.split(/\s+/).filter(Boolean).slice(0,2).join(".")}`:"";this.add({category:"click",message:`${n.tagName.toLowerCase()}${s}${i}`});};window.addEventListener("click",e,{capture:!0,passive:!0}),this.teardown.push(()=>window.removeEventListener("click",e,{capture:!0}));}catch{}}installFetch(){try{let e=window.fetch;if(typeof e!="function")return;let t=(...n)=>{let[s,o]=n,i=o?.method??(typeof s=="object"&&s&&"method"in s?s.method:"GET"),d=typeof s=="string"?s:s instanceof URL?s.href:s.url;return e.apply(window,n).then(c=>(this.add({category:"fetch",message:`${i} ${d} \u2192 ${c.status}`,level:c.ok?void 0:"Warning"}),c),c=>{throw this.add({category:"fetch",message:`${i} ${d} \u2192 failed`,level:"Warning"}),c})};window.fetch=t,this.teardown.push(()=>{window.fetch===t&&(window.fetch=e);});}catch{}}close(){for(let e of this.teardown.splice(0))try{e();}catch{}}};var v=class{constructor(e=4e3,t=100){this.windowMs=e;this.max=t;this.seen=new Map;}shouldSend(e){let t=Date.now(),n=this.seen.get(e);if(n!==void 0&&t-n<this.windowMs)return false;if(this.seen.set(e,t),this.seen.size>this.max){let s=this.seen.keys().next().value;s!==void 0&&this.seen.delete(s);}return true}};function q(r,e){let t=(e??"").split(`
3
+ `).slice(0,4).map(n=>n.replace(/:\d+:\d+/g,"").replace(/\?[^\s)]*/g,"").replace(/https?:\/\/[^/]+/g,"").trim()).join("|");return `${r}::${t}`.slice(0,500)}function H(r){if(!u())return ()=>{};let e=r.config,t=[];if(e.captureUnhandledErrors||e.captureResourceErrors){let n=s=>{try{let o=s.target;if(o instanceof HTMLElement){if(!e.captureResourceErrors)return;let d=o,c=d.src||d.href;if(!c)return;r.captureMessage(`Resource failed to load: ${c}`,"Warning",{context:{resource:o.tagName.toLowerCase(),url:c}});return}if(!e.captureUnhandledErrors)return;let i=s;if(!i.error&&(!i.message||i.message==="Script error."))return;r.captureException(i.error??i.message);}catch{}};window.addEventListener("error",n,true),t.push(()=>window.removeEventListener("error",n,true));}if(e.captureUnhandledRejections){let n=s=>{try{r.captureException(s.reason??"Unhandled promise rejection",{context:{unhandledRejection:!0}});}catch{}};window.addEventListener("unhandledrejection",n),t.push(()=>window.removeEventListener("unhandledrejection",n));}if(e.captureConsole){let n=console;for(let s of ["error","warn"]){let o=n[s];if(typeof o!="function")continue;let i=(...d)=>{try{r.addBreadcrumb({category:"console",level:s==="error"?"Error":"Warning",message:d.map(J).join(" ").slice(0,500)});}catch{}return o.apply(console,d)};n[s]=i,t.push(()=>{n[s]===i&&(n[s]=o);});}}return ()=>{for(let n of t.splice(0))try{n();}catch{}}}function J(r){if(typeof r=="string")return r;if(r instanceof Error)return `${r.name}: ${r.message}`;try{return JSON.stringify(r)??String(r)}catch{return String(r)}}var b=2e3,T=8e3,P=4e3;function K(r){if(r instanceof Error)return {message:a(r.message||r.name||"Error",b),exceptionType:r.name||"Error",stackTrace:r.stack?a(r.stack,T):void 0,innerException:M(r.cause)};if(typeof r=="string")return {message:a(r,b),exceptionType:"Error"};if(r&&typeof r=="object"){let e=r,t=typeof e.message=="string"?e.message:V(e)??Object.prototype.toString.call(r),n=typeof e.name=="string"?e.name:"Error",s=typeof e.stack=="string"?e.stack:void 0;return {message:a(t,b),exceptionType:n,stackTrace:s?a(s,T):void 0,innerException:M(e.cause)}}return {message:a(String(r),b),exceptionType:"Error"}}function F(r){if(r.stackTrace)return r;try{let e=new Error(r.message).stack;if(e){let t=e.split(`
4
4
  `).slice(2).join(`
5
- `);return {...r,stackTrace:a(t||e,S)}}}catch{}return r}function P(r){if(r==null)return;if(r instanceof Error){let t=[`${r.name}: ${r.message}`];r.stack&&t.push(r.stack);let n=P(r.cause);return n&&t.push(`Caused by: ${n}`),a(t.join(`
6
- `),R)}let e=O(r);return e?a(e,R):a(String(r),R)}function O(r){try{let e=JSON.stringify(r);return e==="{}"?void 0:e}catch{return}}var U="cherryboard:queue:v1",x=class{constructor(e,t){this.enabled=e;this.maxItems=t;}get store(){if(!this.enabled||!d())return null;try{return window.localStorage}catch{return null}}push(e){let t=this.store;if(!(!t||e.length===0))try{let n=this.read().concat(e).slice(-this.maxItems);t.setItem(U,JSON.stringify(n));}catch{}}read(){let e=this.store;if(!e)return [];try{let t=e.getItem(U);if(!t)return [];let n=JSON.parse(t);return Array.isArray(n)?n:[]}catch{return []}}drain(){let e=this.read();return this.clear(),e}clear(){let e=this.store;if(e)try{e.removeItem(U);}catch{}}};var v=class{constructor(e=30,t=5){this.capacity=e;this.refillPerSec=t;this.tokens=e,this.last=Date.now();}allow(){let e=Date.now(),t=(e-this.last)/1e3;return this.tokens=Math.min(this.capacity,this.tokens+t*this.refillPerSec),this.last=e,this.tokens>=1?(this.tokens-=1,true):false}};var z=["password","passwd","secret","token","apikey","api_key","authorization","auth","cookie","session","credit","card","cvv","ssn"],W=["token","access_token","apikey","api_key","email","password","code","secret"],T="[Filtered]",J=/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/g;function A(r){let e=r;for(let t of W)e=e.replace(new RegExp(`([?&]${t}=)[^&#\\s]*`,"gi"),`$1${T}`);return e}function w(r,e=0){if(e>6)return r;if(typeof r=="string")return A(r).replace(J,T);if(Array.isArray(r))return r.map(t=>w(t,e+1));if(r&&typeof r=="object"){let t={};for(let[n,o]of Object.entries(r)){let s=n.toLowerCase();t[n]=z.some(i=>s.includes(i))?T:w(o,e+1);}return t}return r}function H(r){return {...r,message:A(r.message),context:w(r.context),breadcrumbs:r.breadcrumbs.map(e=>({...e,message:A(e.message),data:e.data?w(e.data):void 0}))}}var E=class{constructor(e,t){this.apiKey=t;this.endpoint=_(e);let n=typeof fetch=="function"?fetch.bind(globalThis):void 0;this.fetchImpl=n??(()=>Promise.reject(new Error("fetch unavailable")));}async send(e,t=false){if(e.length===0)return {ok:true,retryable:false,status:204};try{let n=await this.fetchImpl(this.endpoint,{method:"POST",headers:{"Content-Type":"application/json",Accept:"application/json","X-API-Key":this.apiKey},body:JSON.stringify({errors:e}),keepalive:t,mode:"cors",credentials:"omit"});if(n.status===429)return {ok:!1,retryable:!1,status:429,retryAfterMs:Q(n.headers?.get?.("Retry-After"))};let o=n.status>=500;return {ok:n.ok,retryable:o,status:n.status}}catch{return {ok:false,retryable:true,status:0}}}};function Q(r){if(!r)return 6e4;let t=Number(r);if(Number.isFinite(t)&&t>=0)return Math.min(t*1e3,36e5);let n=Date.parse(r);return Number.isNaN(n)?6e4:Math.min(Math.max(n-Date.now(),0),36e5)}function I(r,e,t){return Math.max(e,Math.min(t,r))}function Y(r){return new Promise(e=>setTimeout(e,r))}var V=3e3;function G(r){return {apiKey:r.apiKey,apiUrl:r.apiUrl,environment:r.environment??"production",release:r.release,enabled:r.enabled??true,sampleRate:I(r.sampleRate??1,0,1),maxBatchSize:I(r.maxBatchSize??20,1,100),flushIntervalMs:r.flushIntervalMs??4e3,maxQueueItems:r.maxQueueItems??100,maxRetries:r.maxRetries??3,maxBreadcrumbs:r.maxBreadcrumbs??30,offlineStorage:r.offlineStorage??true,captureUnhandledErrors:r.captureUnhandledErrors??true,captureUnhandledRejections:r.captureUnhandledRejections??true,captureResourceErrors:r.captureResourceErrors??true,captureConsole:r.captureConsole??true,autoBreadcrumbs:r.autoBreadcrumbs??true,denyUrls:r.denyUrls??[],allowUrls:r.allowUrls??[],beforeSend:r.beforeSend,debug:r.debug??false}}var k=class{constructor(e){this.buffer=[];this.flushTimer=null;this.processing=false;this.rateLimitedUntil=0;this.discarded={};this.closed=false;this.scope={tags:{}};this.teardown=[];this.config=G(e),this.transport=new E(this.config.apiUrl,this.config.apiKey),this.deduper=new y(V),this.limiter=new v,this.queue=new x(this.config.offlineStorage,this.config.maxQueueItems),this.breadcrumbs=new g(this.config.maxBreadcrumbs),this.config.enabled&&(this.config.autoBreadcrumbs&&this.breadcrumbs.install(),this.teardown.push(j(this)),this.installLifecycle(),this.drainOffline());}captureException(e,t){try{this.process(L($(e)),t?.severity??"Error",t);}catch(n){this.debug("captureException failed",n);}}captureMessage(e,t="Info",n){try{this.process({message:a(e,2e3),exceptionType:"Message"},n?.severity??t,n);}catch(o){this.debug("captureMessage failed",o);}}getDiscardedEvents(){return {...this.discarded}}discard(e,t=1){this.discarded[e]=(this.discarded[e]??0)+t;}addBreadcrumb(e){this.breadcrumbs.add(e);}setUser(e){this.scope.user=e??void 0;}setTag(e,t){this.scope.tags[e]=t;}setContext(e,t){this.scope.tags[e]=t;}close(){this.closed=true,this.flushTimer!==null&&(clearTimeout(this.flushTimer),this.flushTimer=null),this.flush(true),this.breadcrumbs.close();for(let e of this.teardown.splice(0))try{e();}catch{}}process(e,t,n){if(!this.config.enabled||this.closed)return;if(this.config.sampleRate<1&&Math.random()>this.config.sampleRate){this.discard("sampled");return}let o=`${e.stackTrace??""}
7
- ${d()?location.href:""}`;if(B(o,this.config.denyUrls)){this.discard("filtered");return}if(this.config.allowUrls.length>0&&!B(o,this.config.allowUrls)){this.discard("filtered");return}if(!this.deduper.shouldSend(D(e.message,e.stackTrace))){this.discard("deduped");return}let s={message:e.message,severity:t,timestamp:m(),exceptionType:e.exceptionType,stackTrace:e.stackTrace,innerException:e.innerException,userId:this.scope.user?.id,requestPath:d()?location.pathname:void 0,userAgent:d()?navigator.userAgent:void 0,context:this.buildContext(n),breadcrumbs:this.breadcrumbs.snapshot()};if(s=H(s),this.config.beforeSend){let i=this.config.beforeSend(s);if(!i){this.discard("filtered");return}s=i;}this.enqueue(this.toPayload(s));}buildContext(e){let t={sdk:{name:"cherryboard-web",version:h},environment:this.config.environment};return this.config.release&&(t.release=this.config.release),d()&&(t.url=location.href,document.referrer&&(t.referrer=document.referrer),t.language=navigator.language,t.viewport={width:window.innerWidth,height:window.innerHeight}),this.scope.user&&(t.user=this.scope.user),Object.keys(this.scope.tags).length>0&&(t.tags={...this.scope.tags}),e?.componentStack&&(t.componentStack=e.componentStack),e?.digest&&(t.digest=e.digest),e?.context&&Object.assign(t,e.context),t}toPayload(e){let t=C({...e.context,breadcrumbs:e.breadcrumbs});return t===void 0&&(t=C(e.context)),{message:e.message,stackTrace:e.stackTrace,severity:e.severity,timestamp:e.timestamp,userId:e.userId,requestPath:e.requestPath,userAgent:e.userAgent,exceptionType:e.exceptionType,innerException:e.innerException,metadata:t}}enqueue(e){this.buffer.push(e),this.buffer.length>=this.config.maxBatchSize?this.flush():this.scheduleFlush();}scheduleFlush(){this.closed||this.flushTimer===null&&(this.flushTimer=setTimeout(()=>{this.flushTimer=null,this.flush();},this.config.flushIntervalMs));}async flush(e=false){if(this.flushTimer!==null&&(clearTimeout(this.flushTimer),this.flushTimer=null),this.buffer.length!==0){if(e){if(Date.now()<this.rateLimitedUntil)return;for(;this.buffer.length>0;){let t=this.buffer.splice(0,this.config.maxBatchSize);if(!this.limiter.allow())break;this.transport.send(t,true);}return}if(Date.now()<this.rateLimitedUntil){this.scheduleFlush();return}if(!this.processing){this.processing=true;try{for(;this.buffer.length>0;){let t=this.buffer.splice(0,this.config.maxBatchSize);if(!this.limiter.allow()){this.debug("rate limited; dropping",t.length,"events"),this.discard("rate_limited",t.length);break}if(!await this.deliver(t)){this.queue.push(t);break}}}finally{this.processing=false;}}}}async deliver(e){for(let t=0;t<=this.config.maxRetries;t++){let n=await this.transport.send(e,false);if(n.ok)return true;if(n.status===429)return this.rateLimitedUntil=Date.now()+(n.retryAfterMs??6e4),this.debug("rate limited by server; pausing for",n.retryAfterMs,"ms"),false;if(!n.retryable)return this.debug("non-retryable response",n.status,"\u2014 dropping batch"),this.discard("send_failed",e.length),true;if(t===this.config.maxRetries)return false;await Y(I(2**t*1e3+Math.random()*250,0,15e3));}return false}drainOffline(){let e=this.queue.drain();e.length>0&&(this.buffer.push(...e),this.scheduleFlush());}installLifecycle(){if(!d())return;let e=()=>{document.visibilityState==="hidden"&&this.flush(true);},t=()=>{this.flush(true);},n=()=>this.drainOffline();document.addEventListener("visibilitychange",e),window.addEventListener("pagehide",t),window.addEventListener("online",n),this.teardown.push(()=>{document.removeEventListener("visibilitychange",e),window.removeEventListener("pagehide",t),window.removeEventListener("online",n);});}debug(...e){this.config.debug&&console.warn("[cherryboard]",...e);}};var K="__CHERRYBOARD__";function c(){let r=globalThis,e=r[K];return e||(e={},r[K]=e),e}function N(r){let e=c();return e.client||(e.client=new k(r)),e.client}function M(){return c().client??null}function X(){return c().client!=null}function p(r,e){c().client?.captureException(r,e);}function Z(r,e,t){c().client?.captureMessage(r,e,t);}function ee(r){c().client?.addBreadcrumb(r);}function re(r){c().client?.setUser(r);}function te(r,e){c().client?.setTag(r,e);}function ne(r,e){c().client?.setContext(r,e);}function oe(){let r=c().client;return r?r.flush():Promise.resolve()}function se(r,e,t){c().client?.captureException(r,{severity:"Error",context:{source:"nextjs-server",...e?.path?{requestPath:e.path}:{},...e?.method?{requestMethod:e.method}:{},...t??{}}});}function ie(){return c().client?.getDiscardedEvents()??{}}function ae(){let r=c();r.client?.close(),r.client=void 0;}var f=class extends Component{constructor(){super(...arguments);this.state={error:null};this.reset=()=>{this.setState({error:null});};}static getDerivedStateFromError(t){return {error:t}}componentDidCatch(t,n){p(t,{severity:"Error",componentStack:n.componentStack??void 0,context:{source:"react-error-boundary"}}),this.props.onError?.(t,n);}componentDidUpdate(t){this.state.error&&!ue(t.resetKeys,this.props.resetKeys)&&this.reset();}render(){let{error:t}=this.state;if(t){let{fallback:n}=this.props;return typeof n=="function"?n({error:t,reset:this.reset}):n??null}return this.props.children}};function ue(r,e){return r===e?true:!r||!e||r.length!==e.length?false:r.every((t,n)=>Object.is(t,e[n]))}function pe({config:r,children:e,withBoundary:t=false,fallback:n}){let o=useRef(r);return useEffect(()=>{typeof window<"u"&&N(o.current);},[]),t?jsx(f,{fallback:n,children:e}):jsx(Fragment,{children:e})}function me(){return M()}function ge(){return useCallback((r,e)=>p(r,e),[])}function ye(r){p(r,{severity:"Error",digest:r.digest,context:{source:"next-error-boundary"}});}export{pe as CherryBoardProvider,f as ErrorBoundary,h as SDK_VERSION,ee as addBreadcrumb,p as captureException,Z as captureMessage,se as captureRequestError,ye as captureRouteError,ae as close,oe as flush,M as getClient,ie as getDiscardedEvents,N as init,X as isInitialized,ne as setContext,te as setTag,re as setUser,ge as useCaptureError,me as useCherryBoard};
5
+ `);return {...r,stackTrace:a(t||e,T)}}}catch{}return r}function M(r){if(r==null)return;if(r instanceof Error){let t=[`${r.name}: ${r.message}`];r.stack&&t.push(r.stack);let n=M(r.cause);return n&&t.push(`Caused by: ${n}`),a(t.join(`
6
+ `),P)}let e=V(r);return e?a(e,P):a(String(r),P)}function V(r){try{let e=JSON.stringify(r);return e==="{}"?void 0:e}catch{return}}var Q=/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i,Y=/^[0-9a-f]{16,}$/i,Z=/^\d+$/,ee=/^(?=.*\d)[A-Za-z0-9_-]{12,}$/;function re(r){return Q.test(r)||Z.test(r)||Y.test(r)||ee.test(r)}function U(r,e){let t;try{t=new URL(r,e??(typeof location<"u"?location.href:void 0)).pathname;}catch{return null}if(!t||t==="/")return "/";let n=t.split("/").filter(Boolean);if(n.length===0)return "/";let s=n.slice(0,12).map(i=>re(i)?":id":i);n.length>12&&s.push("\u2026");let o="/"+s.join("/");return o.length>300?o.slice(0,300):o}var f=[50,100,250,500,1e3,2500,5e3];function z(r){for(let e=0;e<f.length;e++)if(r<=f[e])return e;return f.length}var w=class{constructor(e){this.options=e;this.requests=new Map;this.pageViews=new Map;this.teardown=[];this.closed=false;this.endpoint=O(e.apiUrl);let t=typeof fetch=="function"?fetch.bind(globalThis):void 0;this.fetchImpl=t??(()=>Promise.reject(new Error("fetch unavailable")));}start(){!u()||this.closed||(this.recordPageView(location.pathname,true),this.observeResources(),this.observeNavigation(),this.observeVisibility(),this.timer=setInterval(()=>{this.flush();},this.options.flushIntervalMs));}observeResources(){if(!(typeof PerformanceObserver>"u"))try{this.observer=new PerformanceObserver(e=>{for(let t of e.getEntries())this.recordResource(t);}),this.observer.observe({type:"resource",buffered:!0});}catch{}}recordResource(e){if(e.initiatorType!=="fetch"&&e.initiatorType!=="xmlhttprequest"||e.name.startsWith(this.endpoint)||e.name.includes("/api/v1/errors/batch"))return;let t=U(e.name);if(!t)return;let n=Math.round(e.duration);n<=0||this.addRequest(t,"ALL",n,false);}addRequest(e,t,n,s){let o=`${t} ${e}`,i=this.requests.get(o);if(!i){if(this.requests.size>=this.options.maxRoutes)return;i={route:e,method:t,count:0,errorCount:0,sumMs:0,maxMs:0,buckets:new Array(f.length+1).fill(0)},this.requests.set(o,i);}i.count++,s&&i.errorCount++,i.sumMs+=n,n>i.maxMs&&(i.maxMs=n),i.buckets[z(n)]++;}observeNavigation(){let e=()=>this.recordPageView(location.pathname,false);try{let t=window.history,n=s=>{let o=t[s];if(typeof o!="function")return ()=>{};let i=(...d)=>{let c=o.apply(window.history,d);return e(),c};return t[s]=i,()=>{t[s]===i&&(t[s]=o);}};this.teardown.push(n("pushState"),n("replaceState")),window.addEventListener("popstate",e),this.teardown.push(()=>window.removeEventListener("popstate",e));}catch{}}recordPageView(e,t){let n=U(e);if(!n)return;let s=this.pageViews.get(n);if(!s){if(this.pageViews.size>=this.options.maxRoutes)return;s={route:n,views:0,visits:0},this.pageViews.set(n,s);}s.views++,t&&s.visits++;}observeVisibility(){let e=()=>{document.visibilityState==="hidden"&&this.flush(true);};document.addEventListener("visibilitychange",e),this.teardown.push(()=>document.removeEventListener("visibilitychange",e));}async flush(e=false){if(this.requests.size===0&&this.pageViews.size===0)return;let t={requests:Array.from(this.requests.values()).map(n=>({route:n.route,method:n.method,count:n.count,errorCount:n.errorCount,sumMs:n.sumMs,maxMs:n.maxMs,buckets:n.buckets})),pageViews:Array.from(this.pageViews.values()).map(n=>({route:n.route,views:n.views,visits:n.visits}))};this.requests.clear(),this.pageViews.clear();try{await this.fetchImpl(this.endpoint,{method:"POST",headers:{"Content-Type":"application/json","X-API-Key":this.options.apiKey},body:JSON.stringify(t),keepalive:e,mode:"cors",credentials:"omit"});}catch{this.options.debug&&console.warn("[cherryboard] metrics flush failed");}}close(){this.closed=true,this.timer&&clearInterval(this.timer),this.observer?.disconnect();for(let e of this.teardown)e();this.teardown=[];}};var I="cherryboard:queue:v1",x=class{constructor(e,t){this.enabled=e;this.maxItems=t;}get store(){if(!this.enabled||!u())return null;try{return window.localStorage}catch{return null}}push(e){let t=this.store;if(!(!t||e.length===0))try{let n=this.read().concat(e).slice(-this.maxItems);t.setItem(I,JSON.stringify(n));}catch{}}read(){let e=this.store;if(!e)return [];try{let t=e.getItem(I);if(!t)return [];let n=JSON.parse(t);return Array.isArray(n)?n:[]}catch{return []}}drain(){let e=this.read();return this.clear(),e}clear(){let e=this.store;if(e)try{e.removeItem(I);}catch{}}};var E=class{constructor(e=30,t=5){this.capacity=e;this.refillPerSec=t;this.tokens=e,this.last=Date.now();}allow(){let e=Date.now(),t=(e-this.last)/1e3;return this.tokens=Math.min(this.capacity,this.tokens+t*this.refillPerSec),this.last=e,this.tokens>=1?(this.tokens-=1,true):false}};var te=["password","passwd","secret","token","apikey","api_key","authorization","auth","cookie","session","credit","card","cvv","ssn"],ne=["token","access_token","apikey","api_key","email","password","code","secret"],A="[Filtered]",se=/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/g;function N(r){let e=r;for(let t of ne)e=e.replace(new RegExp(`([?&]${t}=)[^&#\\s]*`,"gi"),`$1${A}`);return e}function k(r,e=0){if(e>6)return r;if(typeof r=="string")return N(r).replace(se,A);if(Array.isArray(r))return r.map(t=>k(t,e+1));if(r&&typeof r=="object"){let t={};for(let[n,s]of Object.entries(r)){let o=n.toLowerCase();t[n]=te.some(i=>o.includes(i))?A:k(s,e+1);}return t}return r}function G(r){return {...r,message:N(r.message),context:k(r.context),breadcrumbs:r.breadcrumbs.map(e=>({...e,message:N(e.message),data:e.data?k(e.data):void 0}))}}var C=class{constructor(e,t){this.apiKey=t;this.endpoint=D(e);let n=typeof fetch=="function"?fetch.bind(globalThis):void 0;this.fetchImpl=n??(()=>Promise.reject(new Error("fetch unavailable")));}async send(e,t=false){if(e.length===0)return {ok:true,retryable:false,status:204};try{let n=await this.fetchImpl(this.endpoint,{method:"POST",headers:{"Content-Type":"application/json",Accept:"application/json","X-API-Key":this.apiKey},body:JSON.stringify({errors:e}),keepalive:t,mode:"cors",credentials:"omit"});if(n.status===429)return {ok:!1,retryable:!1,status:429,retryAfterMs:oe(n.headers?.get?.("Retry-After"))};let s=n.status>=500;return {ok:n.ok,retryable:s,status:n.status}}catch{return {ok:false,retryable:true,status:0}}}};function oe(r){if(!r)return 6e4;let t=Number(r);if(Number.isFinite(t)&&t>=0)return Math.min(t*1e3,36e5);let n=Date.parse(r);return Number.isNaN(n)?6e4:Math.min(Math.max(n-Date.now(),0),36e5)}var ie=200;function _(r,e,t){return Math.max(e,Math.min(t,r))}function ae(r){return new Promise(e=>setTimeout(e,r))}var ce=3e3;function ue(r){return {apiKey:r.apiKey,apiUrl:r.apiUrl,environment:r.environment??"production",release:r.release,enabled:r.enabled??true,sampleRate:_(r.sampleRate??1,0,1),maxBatchSize:_(r.maxBatchSize??20,1,100),flushIntervalMs:r.flushIntervalMs??4e3,maxQueueItems:r.maxQueueItems??100,maxRetries:r.maxRetries??3,maxBreadcrumbs:r.maxBreadcrumbs??30,offlineStorage:r.offlineStorage??true,captureUnhandledErrors:r.captureUnhandledErrors??true,captureUnhandledRejections:r.captureUnhandledRejections??true,captureResourceErrors:r.captureResourceErrors??true,captureConsole:r.captureConsole??true,autoBreadcrumbs:r.autoBreadcrumbs??true,denyUrls:r.denyUrls??[],allowUrls:r.allowUrls??[],beforeSend:r.beforeSend,trackPerformance:r.trackPerformance??false,metricsFlushIntervalMs:r.metricsFlushIntervalMs??6e4,debug:r.debug??false}}var R=class{constructor(e){this.buffer=[];this.flushTimer=null;this.processing=false;this.rateLimitedUntil=0;this.discarded={};this.closed=false;this.scope={tags:{}};this.teardown=[];this.config=ue(e),this.transport=new C(this.config.apiUrl,this.config.apiKey),this.deduper=new v(ce),this.limiter=new E,this.queue=new x(this.config.offlineStorage,this.config.maxQueueItems),this.config.trackPerformance&&this.config.enabled&&(this.metrics=new w({apiKey:this.config.apiKey,apiUrl:this.config.apiUrl,flushIntervalMs:this.config.metricsFlushIntervalMs,maxRoutes:ie,debug:this.config.debug}),this.metrics.start()),this.breadcrumbs=new y(this.config.maxBreadcrumbs),this.config.enabled&&(this.config.autoBreadcrumbs&&this.breadcrumbs.install(),this.teardown.push(H(this)),this.installLifecycle(),this.drainOffline());}captureException(e,t){try{this.process(F(K(e)),t?.severity??"Error",t);}catch(n){this.debug("captureException failed",n);}}captureMessage(e,t="Info",n){try{this.process({message:a(e,2e3),exceptionType:"Message"},n?.severity??t,n);}catch(s){this.debug("captureMessage failed",s);}}getDiscardedEvents(){return {...this.discarded}}discard(e,t=1){this.discarded[e]=(this.discarded[e]??0)+t;}addBreadcrumb(e){this.breadcrumbs.add(e);}setUser(e){this.scope.user=e??void 0;}setTag(e,t){this.scope.tags[e]=t;}setContext(e,t){this.scope.tags[e]=t;}close(){this.closed=true,this.flushTimer!==null&&(clearTimeout(this.flushTimer),this.flushTimer=null),this.flush(true),this.metrics?.close(),this.breadcrumbs.close();for(let e of this.teardown.splice(0))try{e();}catch{}}process(e,t,n){if(!this.config.enabled||this.closed)return;if(this.config.sampleRate<1&&Math.random()>this.config.sampleRate){this.discard("sampled");return}let s=`${e.stackTrace??""}
7
+ ${u()?location.href:""}`;if(B(s,this.config.denyUrls)){this.discard("filtered");return}if(this.config.allowUrls.length>0&&!B(s,this.config.allowUrls)){this.discard("filtered");return}if(!this.deduper.shouldSend(q(e.message,e.stackTrace))){this.discard("deduped");return}let o={message:e.message,severity:t,timestamp:g(),exceptionType:e.exceptionType,stackTrace:e.stackTrace,innerException:e.innerException,userId:this.scope.user?.id,requestPath:u()?location.pathname:void 0,userAgent:u()?navigator.userAgent:void 0,context:this.buildContext(n),breadcrumbs:this.breadcrumbs.snapshot()};if(o=G(o),this.config.beforeSend){let i=this.config.beforeSend(o);if(!i){this.discard("filtered");return}o=i;}this.enqueue(this.toPayload(o));}buildContext(e){let t={sdk:{name:"cherryboard-web",version:m},environment:this.config.environment};return this.config.release&&(t.release=this.config.release),u()&&(t.url=location.href,document.referrer&&(t.referrer=document.referrer),t.language=navigator.language,t.viewport={width:window.innerWidth,height:window.innerHeight}),this.scope.user&&(t.user=this.scope.user),Object.keys(this.scope.tags).length>0&&(t.tags={...this.scope.tags}),e?.componentStack&&(t.componentStack=e.componentStack),e?.digest&&(t.digest=e.digest),e?.context&&Object.assign(t,e.context),t}toPayload(e){let t=S({...e.context,breadcrumbs:e.breadcrumbs});return t===void 0&&(t=S(e.context)),{message:e.message,stackTrace:e.stackTrace,severity:e.severity,timestamp:e.timestamp,userId:e.userId,requestPath:e.requestPath,userAgent:e.userAgent,exceptionType:e.exceptionType,innerException:e.innerException,metadata:t}}enqueue(e){this.buffer.push(e),this.buffer.length>=this.config.maxBatchSize?this.flush():this.scheduleFlush();}scheduleFlush(){this.closed||this.flushTimer===null&&(this.flushTimer=setTimeout(()=>{this.flushTimer=null,this.flush();},this.config.flushIntervalMs));}async flush(e=false){if(this.flushTimer!==null&&(clearTimeout(this.flushTimer),this.flushTimer=null),this.buffer.length!==0){if(e){if(Date.now()<this.rateLimitedUntil)return;for(;this.buffer.length>0;){let t=this.buffer.splice(0,this.config.maxBatchSize);if(!this.limiter.allow())break;this.transport.send(t,true);}return}if(Date.now()<this.rateLimitedUntil){this.scheduleFlush();return}if(!this.processing){this.processing=true;try{for(;this.buffer.length>0;){let t=this.buffer.splice(0,this.config.maxBatchSize);if(!this.limiter.allow()){this.debug("rate limited; dropping",t.length,"events"),this.discard("rate_limited",t.length);break}if(!await this.deliver(t)){this.queue.push(t);break}}}finally{this.processing=false;}}}}async deliver(e){for(let t=0;t<=this.config.maxRetries;t++){let n=await this.transport.send(e,false);if(n.ok)return true;if(n.status===429)return this.rateLimitedUntil=Date.now()+(n.retryAfterMs??6e4),this.debug("rate limited by server; pausing for",n.retryAfterMs,"ms"),false;if(!n.retryable)return this.debug("non-retryable response",n.status,"\u2014 dropping batch"),this.discard("send_failed",e.length),true;if(t===this.config.maxRetries)return false;await ae(_(2**t*1e3+Math.random()*250,0,15e3));}return false}drainOffline(){let e=this.queue.drain();e.length>0&&(this.buffer.push(...e),this.scheduleFlush());}installLifecycle(){if(!u())return;let e=()=>{document.visibilityState==="hidden"&&this.flush(true);},t=()=>{this.flush(true);},n=()=>this.drainOffline();document.addEventListener("visibilitychange",e),window.addEventListener("pagehide",t),window.addEventListener("online",n),this.teardown.push(()=>{document.removeEventListener("visibilitychange",e),window.removeEventListener("pagehide",t),window.removeEventListener("online",n);});}debug(...e){this.config.debug&&console.warn("[cherryboard]",...e);}};var X="__CHERRYBOARD__";function l(){let r=globalThis,e=r[X];return e||(e={},r[X]=e),e}function L(r){let e=l();return e.client||(e.client=new R(r)),e.client}function $(){return l().client??null}function de(){return l().client!=null}function p(r,e){l().client?.captureException(r,e);}function le(r,e,t){l().client?.captureMessage(r,e,t);}function pe(r){l().client?.addBreadcrumb(r);}function fe(r){l().client?.setUser(r);}function he(r,e){l().client?.setTag(r,e);}function me(r,e){l().client?.setContext(r,e);}function ge(){let r=l().client;return r?r.flush():Promise.resolve()}function ye(r,e,t){l().client?.captureException(r,{severity:"Error",context:{source:"nextjs-server",...e?.path?{requestPath:e.path}:{},...e?.method?{requestMethod:e.method}:{},...t??{}}});}function ve(){return l().client?.getDiscardedEvents()??{}}function be(){let r=l();r.client?.close(),r.client=void 0;}var h=class extends Component{constructor(){super(...arguments);this.state={error:null};this.reset=()=>{this.setState({error:null});};}static getDerivedStateFromError(t){return {error:t}}componentDidCatch(t,n){p(t,{severity:"Error",componentStack:n.componentStack??void 0,context:{source:"react-error-boundary"}}),this.props.onError?.(t,n);}componentDidUpdate(t){this.state.error&&!xe(t.resetKeys,this.props.resetKeys)&&this.reset();}render(){let{error:t}=this.state;if(t){let{fallback:n}=this.props;return typeof n=="function"?n({error:t,reset:this.reset}):n??null}return this.props.children}};function xe(r,e){return r===e?true:!r||!e||r.length!==e.length?false:r.every((t,n)=>Object.is(t,e[n]))}function Ce({config:r,children:e,withBoundary:t=false,fallback:n}){let s=useRef(r);return useEffect(()=>{typeof window<"u"&&L(s.current);},[]),t?jsx(h,{fallback:n,children:e}):jsx(Fragment,{children:e})}function Be(){return $()}function Pe(){return useCallback((r,e)=>p(r,e),[])}function Te(r){p(r,{severity:"Error",digest:r.digest,context:{source:"next-error-boundary"}});}export{Ce as CherryBoardProvider,h as ErrorBoundary,m as SDK_VERSION,pe as addBreadcrumb,p as captureException,le as captureMessage,ye as captureRequestError,Te as captureRouteError,be as close,ge as flush,$ as getClient,ve as getDiscardedEvents,L as init,de as isInitialized,me as setContext,he as setTag,fe as setUser,Pe as useCaptureError,Be as useCherryBoard};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cherrypeak-org/cherryboard-web",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "Browser & React error tracking client for the CherryBoard dashboard (CherryPeak).",
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -9,6 +9,7 @@
9
9
  "files": [
10
10
  "dist",
11
11
  "!dist/**/*.map",
12
+ "!dist/routes.test.mjs",
12
13
  "cli",
13
14
  "README.md",
14
15
  "CHANGELOG.md",
@@ -35,8 +36,9 @@
35
36
  "build": "rm -rf dist && tsup && node scripts/postbuild.mjs",
36
37
  "dev": "tsup --watch",
37
38
  "typecheck": "tsc --noEmit",
38
- "test": "node test/smoke.mjs && node test/ratelimit.mjs",
39
- "prepublishOnly": "npm run build"
39
+ "test": "node test/smoke.mjs && node test/ratelimit.mjs && node test/routes.mjs",
40
+ "prepublishOnly": "npm run build",
41
+ "pretest": "esbuild src/core/routes.ts --bundle --format=esm --outfile=dist/routes.test.mjs"
40
42
  },
41
43
  "peerDependencies": {
42
44
  "react": ">=18",