@rushobservability/rum-sdk 0.1.1 → 0.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.
Files changed (48) hide show
  1. package/README.md +61 -2
  2. package/dist/index.d.ts +123 -14
  3. package/dist/index.js +1 -60
  4. package/dist/index.js.map +1 -1
  5. package/dist/rush-rum.global.js +2 -0
  6. package/dist/rush-rum.global.js.map +1 -0
  7. package/package.json +15 -5
  8. package/dist/browser.d.ts +0 -11
  9. package/dist/browser.d.ts.map +0 -1
  10. package/dist/browser.js +0 -63
  11. package/dist/browser.js.map +0 -1
  12. package/dist/core.d.ts +0 -16
  13. package/dist/core.d.ts.map +0 -1
  14. package/dist/core.js +0 -178
  15. package/dist/core.js.map +0 -1
  16. package/dist/errors.d.ts +0 -2
  17. package/dist/errors.d.ts.map +0 -1
  18. package/dist/errors.js +0 -32
  19. package/dist/errors.js.map +0 -1
  20. package/dist/index.d.ts.map +0 -1
  21. package/dist/interactions.d.ts +0 -2
  22. package/dist/interactions.d.ts.map +0 -1
  23. package/dist/interactions.js +0 -31
  24. package/dist/interactions.js.map +0 -1
  25. package/dist/pageview.d.ts +0 -2
  26. package/dist/pageview.d.ts.map +0 -1
  27. package/dist/pageview.js +0 -55
  28. package/dist/pageview.js.map +0 -1
  29. package/dist/replay.d.ts +0 -9
  30. package/dist/replay.d.ts.map +0 -1
  31. package/dist/replay.js +0 -62
  32. package/dist/replay.js.map +0 -1
  33. package/dist/resources.d.ts +0 -2
  34. package/dist/resources.d.ts.map +0 -1
  35. package/dist/resources.js +0 -101
  36. package/dist/resources.js.map +0 -1
  37. package/dist/session.d.ts +0 -9
  38. package/dist/session.d.ts.map +0 -1
  39. package/dist/session.js +0 -67
  40. package/dist/session.js.map +0 -1
  41. package/dist/types.d.ts +0 -78
  42. package/dist/types.d.ts.map +0 -1
  43. package/dist/types.js +0 -2
  44. package/dist/types.js.map +0 -1
  45. package/dist/vitals.d.ts +0 -2
  46. package/dist/vitals.d.ts.map +0 -1
  47. package/dist/vitals.js +0 -22
  48. package/dist/vitals.js.map +0 -1
package/README.md CHANGED
@@ -22,7 +22,8 @@ RushRUM.init({
22
22
  trackWebVitals: true, // LCP, INP, CLS, FCP, TTFB (via web-vitals)
23
23
  trackErrors: true, // uncaught errors + unhandled rejections
24
24
  trackPageViews: true, // SPA-aware page views
25
- trackInteractions: false, // click/input interaction events
25
+ trackLongTasks: true, // long tasks + Long Animation Frames (LoAF)
26
+ trackInteractions: false, // click/input + frustration signals
26
27
  trackResources: false, // resource timing entries
27
28
  trackSessionReplay: false,// DOM session replay (via rrweb)
28
29
 
@@ -30,11 +31,25 @@ RushRUM.init({
30
31
  sampleRate: 1.0, // 0..1
31
32
  user: () => ({ id: currentUserId }), // attach a user id
32
33
  propagateTraces: { origins: [/^https:\/\/api\.example\.com/] },
34
+
35
+ // Replay privacy (default 'mask' — masks ALL text + inputs, blocks media)
36
+ replayPrivacy: 'mask',
37
+
38
+ // Mutate/drop events before they're queued (return null to drop)
39
+ beforeSend: (event) => event,
33
40
  })
34
41
 
35
42
  // Custom events
36
43
  RushRUM.trackEvent('checkout_completed', { plan: 'pro', amount: 49 })
37
44
 
45
+ // Dynamically set/override the current user (overrides config.user)
46
+ RushRUM.setUser({ id: 'user-123' })
47
+ RushRUM.setUser(null) // clear
48
+
49
+ // Attributes merged into every event's `attributes` (event keys win)
50
+ RushRUM.setGlobalAttributes({ tenant: 'acme', release: 'canary' })
51
+ RushRUM.clearGlobalAttributes()
52
+
38
53
  // Flush the queue manually (e.g. before a hard navigation)
39
54
  RushRUM.flush()
40
55
 
@@ -54,13 +69,57 @@ RushRUM.destroy()
54
69
  | `trackWebVitals` | `boolean` | `true` | Core Web Vitals |
55
70
  | `trackErrors` | `boolean` | `true` | Uncaught errors + promise rejections |
56
71
  | `trackPageViews` | `boolean` | `true` | SPA-aware page views |
57
- | `trackInteractions` | `boolean` | `false` | Click/input events |
72
+ | `trackLongTasks` | `boolean` | `true` | Long tasks (>50ms) + Long Animation Frames (LoAF), via `PerformanceObserver` |
73
+ | `trackInteractions` | `boolean` | `false` | Click/input events + frustration signals (rage/dead/error clicks) |
58
74
  | `trackResources` | `boolean` | `false` | Resource timing |
59
75
  | `trackSessionReplay` | `boolean` | `false` | DOM session replay (rrweb) |
60
76
  | `propagateTraces` | `{ origins: RegExp[] }` | — | Inject trace headers on matching XHR/fetch origins |
61
77
  | `replayEndpoint` | `string` | `<endpoint>/rum/replay/ingest` | Override the replay ingest URL |
62
78
  | `captureQueryParams` | `boolean` | `false` | Keep query strings + hash on captured URLs. Off by default — query params often carry tokens/PII |
63
79
  | `maskInteractionText` | `boolean` | `false` | Drop clicked-element text from interaction events (keep only tag/id/classes) |
80
+ | `compress` | `boolean` | `false` | gzip the request body (`Content-Encoding: gzip`) via `CompressionStream`. **Only enable if your ingest endpoint decodes gzip — the current Rush backend does not.** The unload/beacon path is always uncompressed |
81
+ | `beforeSend` | `(event) => RumEvent \| null` | — | Mutate or drop each event before it's queued (return `null` to drop). A throwing hook never breaks collection |
82
+ | `replayPrivacy` | `'mask' \| 'mask-user-input' \| 'allow'` | `'mask'` | Replay masking level (see below) |
83
+ | `replayMaskSelector` | `string` | — | Extra CSS selector for text/elements to mask in replay (merged with `[data-pii]`) |
84
+ | `replayBlockSelector` | `string` | — | Extra CSS selector for elements to block (not record) in replay |
85
+ | `replayUnmaskSelector` | `string` | — | Extra CSS selector for text to leave un-masked in replay (only applies when text masking is on) |
86
+ | `replayBeforeAddEvent` | `(event) => unknown \| null` | — | Scrub or drop replay events before buffering (return `null` to drop) |
87
+
88
+ ### Methods
89
+
90
+ | Method | Description |
91
+ |---|---|
92
+ | `RushRUM.init(config)` | Initialize and start collection (SSR-safe no-op; ignores duplicate calls) |
93
+ | `RushRUM.trackEvent(name, attributes?)` | Send a custom event |
94
+ | `RushRUM.setUser(user \| null)` | Dynamically set/override the user id (overrides `config.user`); `null` clears |
95
+ | `RushRUM.setGlobalAttributes(attrs)` | Merge attributes into every subsequent event's `attributes` (event-specific keys win) |
96
+ | `RushRUM.clearGlobalAttributes()` | Clear all global attributes |
97
+ | `RushRUM.flush()` | Force-flush the queue |
98
+ | `RushRUM.destroy()` | Stop collection; detach all observers/timers/listeners |
99
+
100
+ ### Replay privacy
101
+
102
+ **As of 0.2.0, session replay is private by default** — a behavior change from 0.1.x, which masked inputs but recorded all visible text. The `replayPrivacy` level maps to rrweb options:
103
+
104
+ | Level | Inputs | Text | Media |
105
+ |---|---|---|---|
106
+ | `'mask'` (default) | masked | **all text masked** | `img,video,audio,picture,source,canvas` blocked |
107
+ | `'mask-user-input'` | masked | visible | recorded |
108
+ | `'allow'` | recorded | visible | recorded |
109
+
110
+ `[data-pii]` is **always** masked regardless of level. `replayMaskSelector` / `replayBlockSelector` add more, and `replayUnmaskSelector` carves out exceptions when text masking is on.
111
+
112
+ ### Reliability
113
+
114
+ Event batches are sent through a hardened transport: failed sends (network error, HTTP 429/5xx) are retried up to 3× with exponential backoff + jitter. Batches that still fail — or any sent while `navigator.onLine === false` — are persisted to `localStorage` (versioned key, ~1 MB / 50-batch cap, oldest dropped on overflow) and drained oldest-first on the next `init()` and whenever the `online` event fires. The in-memory queue is capped at 1000 events (oldest dropped). The unload/beacon path uses `sendBeacon` (uncompressed, no retry). All of this is best-effort and never throws into your app.
115
+
116
+ ### Frustration signals
117
+
118
+ When `trackInteractions` is enabled, the SDK emits `frustration` events:
119
+
120
+ - **rage_click** — more than 3 clicks on the same element within 1s.
121
+ - **dead_click** — a click on an interactive element that produces no DOM mutation, URL change, or scroll within 3s (conservative, to avoid false positives).
122
+ - **error_click** — a JS error fires within 1s of a click.
64
123
 
65
124
  `sampleRate` is decided **once per session** and applied to every event, so sampled sessions are complete (no half-captured sessions).
66
125
 
package/dist/index.d.ts CHANGED
@@ -1,21 +1,130 @@
1
- import type { RushRUMConfig } from './types';
2
- import { flush, destroy } from './core';
3
- export type { RushRUMConfig, RumEvent, RumPayload } from './types';
4
- export declare const RushRUM: {
5
- init(config: RushRUMConfig): void;
1
+ interface RushRUMConfig {
2
+ endpoint: string;
3
+ app: {
4
+ name: string;
5
+ version?: string;
6
+ };
7
+ environment?: string;
8
+ user?: () => {
9
+ id?: string;
10
+ } | null;
6
11
  /**
7
- * Send a custom event.
12
+ * Fraction of sessions to record, 0..1 (default 1). The decision is made ONCE
13
+ * per session and applied to every event in it — so sessions stay coherent
14
+ * (you never keep a pageview but drop its errors).
8
15
  */
9
- trackEvent(name: string, attributes?: Record<string, unknown>): void;
16
+ sampleRate?: number;
17
+ trackWebVitals?: boolean;
18
+ trackErrors?: boolean;
19
+ trackInteractions?: boolean;
20
+ trackResources?: boolean;
21
+ trackPageViews?: boolean;
22
+ propagateTraces?: {
23
+ origins: RegExp[];
24
+ };
25
+ trackSessionReplay?: boolean;
26
+ /** Override the replay ingest endpoint (defaults to endpoint with /rum/replay/ingest) */
27
+ replayEndpoint?: string;
10
28
  /**
11
- * Force flush the event queue.
29
+ * Keep query strings + hash on captured URLs (page_url + resource URLs).
30
+ * Default false → they are stripped, since query params often carry tokens/PII.
12
31
  */
13
- flush: typeof flush;
32
+ captureQueryParams?: boolean;
33
+ /**
34
+ * Drop the visible text of clicked elements from interaction events (keeps only
35
+ * tag/id/classes). Default false. Enable if button/link text may contain PII.
36
+ */
37
+ maskInteractionText?: boolean;
38
+ /**
39
+ * Track long tasks (>50ms) and Long Animation Frames (LoAF) via
40
+ * PerformanceObserver. Default true — lightweight and low-volume.
41
+ */
42
+ trackLongTasks?: boolean;
43
+ /**
44
+ * gzip the request body via CompressionStream and set Content-Encoding: gzip.
45
+ * Default false. ONLY enable if your ingest endpoint decodes gzip — the current
46
+ * Rush backend does not, so leaving this off keeps bodies plain JSON. The
47
+ * unload/beacon path is always sent uncompressed.
48
+ */
49
+ compress?: boolean;
50
+ /**
51
+ * Mutate or drop events before they are queued. Return the (possibly mutated)
52
+ * event to keep it, or null to drop it. Thrown errors are swallowed so a buggy
53
+ * hook never breaks collection.
54
+ */
55
+ beforeSend?: (event: RumEvent) => RumEvent | null;
56
+ /**
57
+ * Replay privacy level (default 'mask'). Controls rrweb masking:
58
+ * - 'mask': mask all inputs + all text + block media (private by default).
59
+ * - 'mask-user-input': mask all inputs only, leave text visible.
60
+ * - 'allow': no masking.
61
+ */
62
+ replayPrivacy?: 'mask' | 'mask-user-input' | 'allow';
63
+ /** Extra CSS selector for text/elements to mask in replay (merged with [data-pii]). */
64
+ replayMaskSelector?: string;
65
+ /** Extra CSS selector for elements to block (not record) in replay. */
66
+ replayBlockSelector?: string;
67
+ /** Extra CSS selector for text to leave un-masked in replay (overrides masking). */
68
+ replayUnmaskSelector?: string;
14
69
  /**
15
- * Stop collecting and detach handlers/timers. Safe to call before a later
16
- * init() (useful for tests and SPA hot-reload).
70
+ * Scrub or drop replay events client-side before they are buffered. Return the
71
+ * (possibly mutated) event to keep it, or null to drop it. Analogous to
72
+ * Sentry's beforeAddRecordingEvent. Thrown errors are swallowed.
17
73
  */
18
- destroy: typeof destroy;
74
+ replayBeforeAddEvent?: (event: unknown) => unknown | null;
75
+ }
76
+ interface RumMeta {
77
+ app_name: string;
78
+ app_version: string;
79
+ environment: string;
80
+ session_id: string;
81
+ user_id: string;
82
+ page_url: string;
83
+ page_path: string;
84
+ view_name: string;
85
+ referrer: string;
86
+ browser_name: string;
87
+ browser_version: string;
88
+ os_name: string;
89
+ os_version: string;
90
+ device_type: string;
91
+ screen_width: number;
92
+ screen_height: number;
93
+ }
94
+ interface RumEvent {
95
+ event_type: string;
96
+ event_name?: string;
97
+ timestamp?: number;
98
+ vital_name?: string;
99
+ vital_value?: number;
100
+ vital_rating?: string;
101
+ error_message?: string;
102
+ error_stack?: string;
103
+ error_type?: string;
104
+ interaction_target?: string;
105
+ interaction_type?: string;
106
+ duration_ms?: number;
107
+ trace_id?: string;
108
+ span_id?: string;
109
+ attributes?: string;
110
+ }
111
+ interface RumPayload {
112
+ meta: RumMeta;
113
+ events: RumEvent[];
114
+ }
115
+
116
+ declare function flush(): void;
117
+
118
+ declare const RushRUM: {
119
+ init(config: RushRUMConfig): void;
120
+ trackEvent(name: string, attributes?: Record<string, unknown>): void;
121
+ setUser(user: {
122
+ id?: string;
123
+ } | null): void;
124
+ setGlobalAttributes(attrs: Record<string, unknown>): void;
125
+ clearGlobalAttributes(): void;
126
+ flush: typeof flush;
127
+ destroy(): void;
19
128
  };
20
- export default RushRUM;
21
- //# sourceMappingURL=index.d.ts.map
129
+
130
+ export { type RumEvent, type RumPayload, RushRUM, type RushRUMConfig, RushRUM as default };
package/dist/index.js CHANGED
@@ -1,61 +1,2 @@
1
- import { configure, flush, pushEvent, destroy, isInitialized } from './core';
2
- import { initVitals } from './vitals';
3
- import { initErrors } from './errors';
4
- import { initPageViews } from './pageview';
5
- import { initInteractions } from './interactions';
6
- import { initResources } from './resources';
7
- import { initReplay } from './replay';
8
- export const RushRUM = {
9
- init(config) {
10
- // No-op outside the browser (SSR / Node) so importing + init in a universal
11
- // app (Next.js, etc.) doesn't throw on window/navigator/history access.
12
- if (typeof window === 'undefined')
13
- return;
14
- // Guard against double init() — prevents duplicate web-vitals/error/click
15
- // subscriptions and timers.
16
- if (isInitialized()) {
17
- console.warn('[RushRUM] init() called more than once; ignoring.');
18
- return;
19
- }
20
- configure(config);
21
- if (config.trackWebVitals !== false) {
22
- initVitals();
23
- }
24
- if (config.trackErrors !== false) {
25
- initErrors();
26
- }
27
- if (config.trackPageViews !== false) {
28
- initPageViews();
29
- }
30
- if (config.trackInteractions === true) {
31
- initInteractions();
32
- }
33
- if (config.trackResources === true) {
34
- initResources();
35
- }
36
- if (config.trackSessionReplay === true) {
37
- initReplay(config);
38
- }
39
- },
40
- /**
41
- * Send a custom event.
42
- */
43
- trackEvent(name, attributes) {
44
- pushEvent({
45
- event_type: 'custom',
46
- event_name: name,
47
- attributes: attributes ? JSON.stringify(attributes) : undefined,
48
- });
49
- },
50
- /**
51
- * Force flush the event queue.
52
- */
53
- flush,
54
- /**
55
- * Stop collecting and detach handlers/timers. Safe to call before a later
56
- * init() (useful for tests and SPA hot-reload).
57
- */
58
- destroy,
59
- };
60
- export default RushRUM;
1
+ var K="rush_rum_sid",H="rush_rum_sts",j="rush_rum_smp";function z(){return typeof crypto<"u"&&crypto.randomUUID?crypto.randomUUID():"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,e=>{let t=Math.random()*16|0;return (e==="x"?t:t&3|8).toString(16)})}function h(){try{let e=sessionStorage.getItem(K),t=sessionStorage.getItem(H),n=Date.now();if(e&&t&&n-Number(t)<18e5)return sessionStorage.setItem(H,String(n)),e;let r=z();return sessionStorage.setItem(K,r),sessionStorage.setItem(H,String(n)),sessionStorage.removeItem(j),r}catch{return z()}}function Y(e){if(e>=1)return true;if(e<=0)return false;try{h();let t=sessionStorage.getItem(j);if(t!==null)return t==="1";let n=Math.random()<e;return sessionStorage.setItem(j,n?"1":"0"),n}catch{return Math.random()<e}}function Q(){let e=navigator.userAgent,t="Unknown",n="";e.includes("Firefox/")?(t="Firefox",n=e.split("Firefox/")[1]?.split(" ")[0]??""):e.includes("Edg/")?(t="Edge",n=e.split("Edg/")[1]?.split(" ")[0]??""):e.includes("Chrome/")?(t="Chrome",n=e.split("Chrome/")[1]?.split(" ")[0]??""):e.includes("Safari/")&&!e.includes("Chrome")&&(t="Safari",n=e.split("Version/")[1]?.split(" ")[0]??"");let r="Unknown",o="";e.includes("Windows")?(r="Windows",o=e.match(/Windows NT (\d+\.\d+)/)?.[1]??""):e.includes("Android")?(r="Android",o=e.match(/Android (\d+(\.\d+)?)/)?.[1]??""):/iPhone|iPad|iPod/.test(e)?(r="iOS",o=e.match(/OS (\d+_\d+)/)?.[1]?.replace("_",".")??""):e.includes("Mac OS X")?(r="macOS",o=e.match(/Mac OS X (\d+[._]\d+[._]?\d*)/)?.[1]?.replace(/_/g,".")??""):e.includes("Linux")&&(r="Linux");let i="desktop";return /Mobi|Android.*Mobile/.test(e)?i="mobile":/iPad|Android(?!.*Mobile)|Tablet/.test(e)&&(i="tablet"),{browserName:t,browserVersion:n,osName:r,osVersion:o,deviceType:i,screenWidth:window.screen.width,screenHeight:window.screen.height}}var W="rush_rum_buf_v1";function X(){return typeof navigator>"u"||navigator.onLine!==false}function Be(e){return new Promise(t=>setTimeout(t,e))}function Ne(e){let t=1e3*Math.pow(2,e);return Math.random()*t}function Z(){try{let e=localStorage.getItem(W);if(!e)return [];let t=JSON.parse(e);return Array.isArray(t)?t:[]}catch{return []}}function ee(e){try{if(e.length===0){localStorage.removeItem(W);return}localStorage.setItem(W,JSON.stringify(e));}catch{}}function A(e,t){try{let n=Z();for(n.push({url:e,body:t,ts:Date.now()});n.length>50;)n.shift();let r=n.reduce((o,i)=>o+i.body.length,0);for(;n.length>1&&r>1e6;){let o=n.shift();r-=o.body.length;}ee(n);}catch{}}function De(){return typeof CompressionStream<"u"&&typeof Response<"u"}async function Fe(e){let t=new Blob([e]).stream().pipeThrough(new CompressionStream("gzip")),n=await new Response(t).arrayBuffer();return new Blob([n])}async function te(e,t,n){try{let r={"Content-Type":"application/json"},o=t;if(n&&De())try{o=await Fe(t),r["Content-Encoding"]="gzip";}catch{o=t;}let i=await fetch(e,{method:"POST",headers:r,body:o,keepalive:!0});return !(i.status===429||i.status>=500)}catch{return false}}async function ne(e,t,n){if(!X()){A(e,t);return}for(let r=0;r<=3;r++){if(await te(e,t,n))return;r<3&&await Be(Ne(r));}A(e,t);}async function J(){if(!X())return;let e=Z();if(e.length!==0){ee([]),e=e.sort((t,n)=>t.ts-n.ts);for(let t of e){if(!X()){A(t.url,t.body);continue}await te(t.url,t.body,false)||A(t.url,t.body);}}}var oe=30,Ve=250,re=1e3,l=null,u=[],v=null,ie=null,se=true,C=false,P,p={},_=null,b=null,w=null;function ae(e){C||(l=e,ie=Q(),se=Y(e.sampleRate??1),C=true,We(),Xe(),Je(),J());}function ce(e){P=e;}function le(e){p={...p,...e};}function ue(){p={};}function He(e){if(Object.keys(p).length===0)return;let n={};if(e.attributes)try{let r=JSON.parse(e.attributes);r&&typeof r=="object"&&(n=r);}catch{return}e.attributes=JSON.stringify({...p,...n});}function U(){return l}function de(){return C}function m(e){if(l?.captureQueryParams)return e;let t=e.length,n=e.indexOf("?"),r=e.indexOf("#");return n!==-1&&(t=Math.min(t,n)),r!==-1&&(t=Math.min(t,r)),e.slice(0,t)}function je(){let e=typeof performance<"u"&&performance.timeOrigin?performance.timeOrigin+performance.now():Date.now();return Math.round(e*1e6)}function c(e){if(!(!l||!se)){if(e.timestamp=e.timestamp??je(),l.beforeSend)try{let t=l.beforeSend(e);if(t===null)return;e=t??e;}catch{}He(e),u.push(e),u.length>re&&u.splice(0,u.length-re),u.length>=oe&&E();}}function fe(){let e=l,t=ie,n="";if(P!==void 0)n=P?.id??"";else try{n=e.user?.()?.id??"";}catch{}return {app_name:e.app.name,app_version:e.app.version??"",environment:e.environment??"",session_id:h(),user_id:n,page_url:m(location.href),page_path:location.pathname,view_name:document.title,referrer:m(document.referrer),browser_name:t.browserName,browser_version:t.browserVersion,os_name:t.osName,os_version:t.osVersion,device_type:t.deviceType,screen_width:t.screenWidth,screen_height:t.screenHeight}}function E(){if(!l||u.length===0)return;let e=l.endpoint,t=l.compress===true;for(;u.length>0;){let n=u.splice(0,oe),r={meta:fe(),events:n},o=JSON.stringify(r);ne(e,o,t);}}function We(){v||(v=setInterval(()=>{u.length>0&&E();},Ve));}function Xe(){if(typeof document>"u")return;let e=()=>{if(!l||u.length===0)return;let t=u.splice(0),n={meta:fe(),events:t},r=JSON.stringify(n);if(navigator.sendBeacon)navigator.sendBeacon(l.endpoint,r);else try{let o=new XMLHttpRequest;o.open("POST",l.endpoint,!1),o.setRequestHeader("Content-Type","application/json"),o.send(r);}catch{}};_=()=>{document.visibilityState==="hidden"&&e();},b=e,document.addEventListener("visibilitychange",_),window.addEventListener("pagehide",b);}function Je(){typeof window>"u"||(w=()=>{J();},window.addEventListener("online",w));}function pe(){E(),v&&(clearInterval(v),v=null),typeof document<"u"&&_&&document.removeEventListener("visibilitychange",_),typeof window<"u"&&b&&window.removeEventListener("pagehide",b),typeof window<"u"&&w&&window.removeEventListener("online",w),_=null,b=null,w=null,u=[],l=null,C=false,P=void 0,p={};}function me(){import('web-vitals').then(({onLCP:e,onCLS:t,onINP:n,onFCP:r,onTTFB:o})=>{let i=s=>a=>{c({event_type:"web_vital",vital_name:s,vital_value:a.value,vital_rating:a.rating});};e(i("LCP")),t(i("CLS")),n(i("INP")),r(i("FCP")),o(i("TTFB"));}).catch(()=>{});}var ge=null;function $e(){return typeof performance<"u"&&performance.now?performance.now():Date.now()}function ye(e){ge={target:e,ts:$e()};}function he(){return ge}var qe=1e3,$=false,S=null,R=null;function Ge(){let e=he();if(!e)return;(typeof performance<"u"&&performance.now?performance.now():Date.now())-e.ts<qe&&c({event_type:"frustration",interaction_type:"error_click",interaction_target:e.target});}function ve(){$||($=true,S=e=>{Ge(),c({event_type:"error",error_message:e.message||"Unknown error",error_stack:e.error?.stack??"",error_type:e.error?.name??"Error"});},R=e=>{let t=e.reason,n="Unhandled promise rejection",r="",o="UnhandledRejection";t instanceof Error?(n=t.message,r=t.stack??"",o=t.name):typeof t=="string"&&(n=t),c({event_type:"error",error_message:n,error_stack:r,error_type:o});},window.addEventListener("error",S),window.addEventListener("unhandledrejection",R));}function _e(){S&&(window.removeEventListener("error",S),S=null),R&&(window.removeEventListener("unhandledrejection",R),R=null),$=false;}var be=false;function we(){if(B(),be)return;be=true;let e=history.pushState.bind(history),t=history.replaceState.bind(history);history.pushState=function(...n){e(...n),B();},history.replaceState=function(...n){t(...n),B();},window.addEventListener("popstate",()=>{B();});}function Ke(){let e=new Uint8Array(16);return crypto.getRandomValues(e),Array.from(e).map(t=>t.toString(16).padStart(2,"0")).join("")}function ze(){let e=new Uint8Array(8);return crypto.getRandomValues(e),Array.from(e).map(t=>t.toString(16).padStart(2,"0")).join("")}function B(){let e=Ke(),t=ze();c({event_type:"pageview",event_name:document.title,duration_ms:Ye(),trace_id:e,span_id:t});}function Ye(){if(typeof performance>"u")return 0;let e=performance.getEntriesByType("navigation");return e.length>0?e[0].loadEventEnd-e[0].startTime:0}var Qe='button, a, [role="button"], input[type="submit"], input[type="button"]',Ze=1e3,et=3,tt=3e3,q=false,k=null,N=null,f=[],x=[];function nt(e){let t=e.tagName.toLowerCase(),n=e.id?`#${e.id}`:"",r=e.className?`.${Array.from(e.classList).slice(0,3).join(".")}`:"",o=U()?.maskInteractionText?"":(e.textContent??"").trim().slice(0,100);return `${t}${n}${r}${o?` "${o}"`:""}`}function rt(e,t){let n=Date.now();N!==e&&(N=e,f=[]),f.push(n),f=f.filter(r=>n-r<=Ze),f.length>et&&(c({event_type:"frustration",interaction_type:"rage_click",interaction_target:t}),f=[],N=null);}function ot(e){let t=false,n=location.href,r=new MutationObserver(()=>{t=true;});try{r.observe(document.documentElement,{childList:!0,subtree:!0,attributes:!0,characterData:!0});}catch{return}let o=()=>{t=true;};window.addEventListener("scroll",o,{passive:true,capture:true});let i=setTimeout(()=>{a();let d=location.href!==n;!t&&!d&&c({event_type:"frustration",interaction_type:"dead_click",interaction_target:e});},tt),s={observer:r,timer:i,onScroll:o};x.push(s);function a(){r.disconnect(),clearTimeout(i),window.removeEventListener("scroll",o,{capture:true}),x=x.filter(d=>d!==s);}}function Ee(){q||(q=true,k=e=>{let t=e.target;if(!t)return;let n=t.closest(Qe);if(!n)return;let r=nt(n);ye(r),c({event_type:"interaction",interaction_type:"click",interaction_target:r}),rt(n,r),ot(r);},document.addEventListener("click",k,{capture:true,passive:true}));}function Se(){k&&(document.removeEventListener("click",k,{capture:true}),k=null);for(let e of x)e.observer.disconnect(),clearTimeout(e.timer),window.removeEventListener("scroll",e.onScroll,{capture:true});x=[],N=null,f=[],q=false;}var Re=false;function ke(){Re||(Re=true,it(),st());}function xe(e){let t=U();return t?.propagateTraces?.origins?t.propagateTraces.origins.some(n=>n.test(e)):false}function Te(){let e=new Uint8Array(16);return crypto.getRandomValues(e),Array.from(e).map(t=>t.toString(16).padStart(2,"0")).join("")}function Ie(){let e=new Uint8Array(8);return crypto.getRandomValues(e),Array.from(e).map(t=>t.toString(16).padStart(2,"0")).join("")}function it(){let e=window.fetch.bind(window);window.fetch=async function(t,n){let r=typeof t=="string"?t:t instanceof URL?t.href:t.url,o=performance.now(),i="",s="";if(xe(r)){i=Te(),s=Ie();let a=new Headers(n?.headers);a.set("traceparent",`00-${i}-${s}-01`),n={...n,headers:a};}try{let a=await e(t,n),d=performance.now()-o;return c({event_type:"resource",event_name:m(r),duration_ms:d,trace_id:i,span_id:s,attributes:JSON.stringify({status:a.status,method:n?.method??"GET"})}),a}catch(a){let d=performance.now()-o;throw c({event_type:"resource",event_name:m(r),duration_ms:d,trace_id:i,span_id:s,error_message:a instanceof Error?a.message:"fetch failed",error_type:"NetworkError"}),a}};}function st(){let e=XMLHttpRequest.prototype.open,t=XMLHttpRequest.prototype.send;XMLHttpRequest.prototype.open=function(n,r,...o){return this.__wide_url=typeof r=="string"?r:r.href,this.__wide_method=n,e.apply(this,[n,r,...o])},XMLHttpRequest.prototype.send=function(n){let r=this.__wide_url??"",o=this.__wide_method??"GET",i=performance.now(),s="",a="";return xe(r)&&(s=Te(),a=Ie(),this.setRequestHeader("traceparent",`00-${s}-${a}-01`)),this.addEventListener("loadend",()=>{let d=performance.now()-i;c({event_type:"resource",event_name:m(r),duration_ms:d,trace_id:s,span_id:a,attributes:JSON.stringify({status:this.status,method:o})});}),t.call(this,n)};}var G=false,g=null,y=null;function Me(e){return typeof PerformanceObserver<"u"&&Array.isArray(PerformanceObserver.supportedEntryTypes)&&PerformanceObserver.supportedEntryTypes.includes(e)}function Oe(){if(!G&&!(typeof PerformanceObserver>"u")){if(G=true,Me("longtask"))try{g=new PerformanceObserver(e=>{for(let t of e.getEntries())c({event_type:"long_task",duration_ms:t.duration,attributes:JSON.stringify({start:t.startTime,name:t.name})});}),g.observe({type:"longtask",buffered:!0});}catch{g=null;}if(Me("long-animation-frame"))try{y=new PerformanceObserver(e=>{for(let t of e.getEntries()){let n=t;c({event_type:"loaf",duration_ms:n.duration,attributes:JSON.stringify({start:n.startTime,blockingDuration:n.blockingDuration??0,scripts:(n.scripts||[]).length})});}}),y.observe({type:"long-animation-frame",buffered:!0});}catch{y=null;}}}function Le(){g&&(g.disconnect(),g=null),y&&(y.disconnect(),y=null),G=false;}function Ae(e){return {init(t){if(!(typeof window>"u")){if(de()){console.warn("[RushRUM] init() called more than once; ignoring.");return}ae(t),t.trackWebVitals!==false&&me(),t.trackErrors!==false&&ve(),t.trackPageViews!==false&&we(),t.trackLongTasks!==false&&Oe(),t.trackInteractions===true&&Ee(),t.trackResources===true&&ke(),t.trackSessionReplay===true&&(e?e.init(t):console.warn("[RushRUM] session replay is not available in this build; use the npm package (@rushobservability/rum-sdk)."));}},trackEvent(t,n){c({event_type:"custom",event_name:t,attributes:n?JSON.stringify(n):void 0});},setUser(t){ce(t);},setGlobalAttributes(t){le(t);},clearGlobalAttributes(){ue();},flush:E,destroy(){Le(),Se(),_e(),e&&e.destroy(),pe();}}}var at=50,ct=5e3,lt="[data-pii]",ut="img,video,audio,picture,source,canvas",D=false,O=null,L=[],dt=0,F=null,V=null,I=null,M=null;function ft(){let e=O;return e.replayEndpoint?e.replayEndpoint:e.endpoint.replace(/\/rum\/ingest$/,"/rum/replay/ingest")}function Ce(...e){return e.filter(t=>!!t&&t.length>0).join(",")}function pt(e){if(!O||e.length===0)return;let t={session_id:h(),app_name:O.app.name,chunk_idx:dt++,events:e};fetch(ft(),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t),keepalive:true}).catch(()=>{});}function T(){L.length!==0&&pt(L.splice(0));}function mt(e){let t=e.replayPrivacy??"mask",n=true,r=false,o=false;t==="mask"?(n=true,r=true,o=true):t==="mask-user-input"?(n=true,r=false):(n=false,r=false);let i=r?"*":Ce(lt,e.replayMaskSelector),s=Ce(o?ut:void 0,e.replayBlockSelector);return {maskAllInputs:n,maskTextSelector:i,blockSelector:s}}function Pe(e){if(D)return;D=true,O=e;let t=mt(e),n=e.replayUnmaskSelector;import('rrweb').then(({record:r})=>{if(!D)return;let o={emit(s){if(e.replayBeforeAddEvent)try{let a=e.replayBeforeAddEvent(s);if(a===null)return;s=a??s;}catch{}L.push(s),L.length>=at&&T();},maskAllInputs:t.maskAllInputs};t.maskTextSelector&&(o.maskTextSelector=t.maskTextSelector),t.blockSelector&&(o.blockSelector=t.blockSelector),n&&t.maskTextSelector==="*"&&(o.maskTextFn=(s,a)=>{try{if(a&&a.matches&&a.matches(n))return s}catch{}return s.replace(/\S/g,"*")});let i=r(o);V=typeof i=="function"?i:null;}).catch(()=>{}),F=setInterval(T,ct),I=()=>{document.visibilityState==="hidden"&&T();},M=T,document.addEventListener("visibilitychange",I),window.addEventListener("pagehide",M);}function Ue(){if(V){try{V();}catch{}V=null;}F&&(clearInterval(F),F=null),T(),typeof document<"u"&&I&&document.removeEventListener("visibilitychange",I),typeof window<"u"&&M&&window.removeEventListener("pagehide",M),I=null,M=null,L=[],O=null,D=false;}var gt=Ae({init:Pe,destroy:Ue}),zt=gt;export{gt as RushRUM,zt as default};//# sourceMappingURL=index.js.map
61
2
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAA;AAC5E,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AACrC,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AACrC,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAC1C,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAA;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAC3C,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AAIrC,MAAM,CAAC,MAAM,OAAO,GAAG;IACrB,IAAI,CAAC,MAAqB;QACxB,4EAA4E;QAC5E,wEAAwE;QACxE,IAAI,OAAO,MAAM,KAAK,WAAW;YAAE,OAAM;QACzC,0EAA0E;QAC1E,4BAA4B;QAC5B,IAAI,aAAa,EAAE,EAAE,CAAC;YACpB,OAAO,CAAC,IAAI,CAAC,mDAAmD,CAAC,CAAA;YACjE,OAAM;QACR,CAAC;QAED,SAAS,CAAC,MAAM,CAAC,CAAA;QAEjB,IAAI,MAAM,CAAC,cAAc,KAAK,KAAK,EAAE,CAAC;YACpC,UAAU,EAAE,CAAA;QACd,CAAC;QACD,IAAI,MAAM,CAAC,WAAW,KAAK,KAAK,EAAE,CAAC;YACjC,UAAU,EAAE,CAAA;QACd,CAAC;QACD,IAAI,MAAM,CAAC,cAAc,KAAK,KAAK,EAAE,CAAC;YACpC,aAAa,EAAE,CAAA;QACjB,CAAC;QACD,IAAI,MAAM,CAAC,iBAAiB,KAAK,IAAI,EAAE,CAAC;YACtC,gBAAgB,EAAE,CAAA;QACpB,CAAC;QACD,IAAI,MAAM,CAAC,cAAc,KAAK,IAAI,EAAE,CAAC;YACnC,aAAa,EAAE,CAAA;QACjB,CAAC;QACD,IAAI,MAAM,CAAC,kBAAkB,KAAK,IAAI,EAAE,CAAC;YACvC,UAAU,CAAC,MAAM,CAAC,CAAA;QACpB,CAAC;IACH,CAAC;IAED;;OAEG;IACH,UAAU,CAAC,IAAY,EAAE,UAAoC;QAC3D,SAAS,CAAC;YACR,UAAU,EAAE,QAAQ;YACpB,UAAU,EAAE,IAAI;YAChB,UAAU,EAAE,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,SAAS;SAChE,CAAC,CAAA;IACJ,CAAC;IAED;;OAEG;IACH,KAAK;IAEL;;;OAGG;IACH,OAAO;CACR,CAAA;AAED,eAAe,OAAO,CAAA"}
1
+ {"version":3,"sources":["../src/session.ts","../src/browser.ts","../src/transport.ts","../src/core.ts","../src/vitals.ts","../src/frustration.ts","../src/errors.ts","../src/pageview.ts","../src/interactions.ts","../src/resources.ts","../src/perf.ts","../src/bootstrap.ts","../src/replay.ts","../src/index.ts"],"names":["SESSION_KEY","SESSION_TS_KEY","SESSION_SAMPLED_KEY","generateId","c","r","getSessionId","stored","ts","now","id","isSessionSampled","sampleRate","sampled","detectBrowser","ua","browserName","browserVersion","osName","osVersion","deviceType","BUFFER_KEY","isOnline","sleep","ms","resolve","backoffDelay","attempt","ceiling","readBuffer","raw","parsed","writeBuffer","batches","persistBatch","url","body","total","n","b","dropped","canCompress","gzip","stream","buf","sendOnce","compress","headers","payload","res","sendBatch","drainBuffer","a","batch","MAX_BATCH","FLUSH_INTERVAL_MS","MAX_QUEUE","config","queue","flushTimer","browserInfo","sampledIn","initialized","userOverride","globalAttributes","onVisibility","onPageHide","onOnline","configure","cfg","startFlushTimer","setupBeaconFlush","setupOnlineDrain","setUserOverride","user","setGlobalAttrs","attrs","clearGlobalAttrs","applyGlobalAttributes","event","existing","getConfig","isInitialized","sanitizeUrl","end","q","h","nowNs","pushEvent","result","flush","buildMeta","bi","userId","endpoint","events","beaconFlush","xhr","destroy","initVitals","onLCP","onCLS","onINP","onFCP","onTTFB","report","name","metric","lastClick","recordClick","target","getLastClick","ERROR_CLICK_WINDOW_MS","bound","onError","onRejection","maybeEmitErrorClick","last","initErrors","reason","message","stack","errorType","destroyErrors","patched","initPageViews","trackPageView","origPush","origReplace","args","generateTraceId","bytes","generateSpanId","traceId","spanId","getNavigationLoadTime","entries","INTERACTIVE_SELECTORS","RAGE_WINDOW_MS","RAGE_THRESHOLD","DEAD_WINDOW_MS","clickListener","rageTarget","rageTimes","deadWatchers","describeTarget","el","tag","classes","text","detectRageClick","t","detectDeadClick","changed","startUrl","observer","onScroll","timer","cleanup","navigated","watcher","w","initInteractions","interactive","descriptor","destroyInteractions","initResources","patchFetch","patchXHR","shouldTraceOrigin","re","origFetch","input","init","start","response","durationMs","err","origOpen","origSend","method","rest","started","longTaskObserver","loafObserver","supports","type","initPerformance","list","entry","e","destroyPerformance","makeRushRUM","replay","attributes","CHUNK_SIZE","PII_SELECTOR","MEDIA_BLOCK_SELECTOR","_config","_buffer","_chunkIdx","_flushTimer","_stopRecording","_onVisibility","_onPageHide","replayEndpoint","joinSelectors","parts","p","sendChunk","flushBuffer","buildRecordOptions","level","maskAllInputs","maskText","blockMedia","maskTextSelector","blockSelector","initReplay","opts","unmask","record","recordOptions","stop","destroyReplay","RushRUM","src_default"],"mappings":"AAAA,IAAMA,CAAAA,CAAc,eACdC,CAAAA,CAAiB,cAAA,CACjBC,EAAsB,cAAA,CAG5B,SAASC,GAAqB,CAC5B,OAAI,OAAO,MAAA,CAAW,GAAA,EAAe,OAAO,UAAA,CACnC,MAAA,CAAO,YAAW,CAEpB,sCAAA,CAAuC,OAAA,CAAQ,OAAA,CAAUC,CAAAA,EAAM,CACpE,IAAMC,CAAAA,CAAK,IAAA,CAAK,QAAO,CAAI,EAAA,CAAM,EAEjC,OAAA,CADUD,CAAAA,GAAM,GAAA,CAAMC,CAAAA,CAAKA,CAAAA,CAAI,CAAA,CAAO,GAC7B,QAAA,CAAS,EAAE,CACtB,CAAC,CACH,CAEO,SAASC,CAAAA,EAAuB,CACrC,GAAI,CACF,IAAMC,EAAS,cAAA,CAAe,OAAA,CAAQP,CAAW,CAAA,CAC3CQ,CAAAA,CAAK,eAAe,OAAA,CAAQP,CAAc,EAC1CQ,CAAAA,CAAM,IAAA,CAAK,KAAI,CAErB,GAAIF,GAAUC,CAAAA,EAAMC,CAAAA,CAAM,OAAOD,CAAE,CAAA,CAAI,IAAA,CACrC,OAAA,cAAA,CAAe,OAAA,CAAQP,CAAAA,CAAgB,OAAOQ,CAAG,CAAC,EAC3CF,CAAAA,CAGT,IAAMG,EAAKP,CAAAA,EAAW,CACtB,OAAA,cAAA,CAAe,OAAA,CAAQH,CAAAA,CAAaU,CAAE,EACtC,cAAA,CAAe,OAAA,CAAQT,EAAgB,MAAA,CAAOQ,CAAG,CAAC,CAAA,CAElD,cAAA,CAAe,UAAA,CAAWP,CAAmB,CAAA,CACtCQ,CACT,MAAQ,CAEN,OAAOP,GACT,CACF,CAOO,SAASQ,CAAAA,CAAiBC,EAA6B,CAC5D,GAAIA,GAAc,CAAA,CAAG,OAAO,MAC5B,GAAIA,CAAAA,EAAc,EAAG,OAAO,MAAA,CAC5B,GAAI,CAEFN,CAAAA,EAAa,CACb,IAAMC,CAAAA,CAAS,cAAA,CAAe,QAAQL,CAAmB,CAAA,CACzD,GAAIK,CAAAA,GAAW,IAAA,CAAM,OAAOA,CAAAA,GAAW,GAAA,CACvC,IAAMM,EAAU,IAAA,CAAK,MAAA,GAAWD,CAAAA,CAChC,OAAA,cAAA,CAAe,QAAQV,CAAAA,CAAqBW,CAAAA,CAAU,GAAA,CAAM,GAAG,CAAA,CACxDA,CACT,MAAQ,CAEN,OAAO,KAAK,MAAA,EAAO,CAAID,CACzB,CACF,CCjDO,SAASE,CAAAA,EAA6B,CAC3C,IAAMC,EAAK,SAAA,CAAU,SAAA,CAEjBC,EAAc,SAAA,CACdC,CAAAA,CAAiB,GAEjBF,CAAAA,CAAG,QAAA,CAAS,UAAU,CAAA,EACxBC,CAAAA,CAAc,SAAA,CACdC,EAAiBF,CAAAA,CAAG,KAAA,CAAM,UAAU,CAAA,CAAE,CAAC,GAAG,KAAA,CAAM,GAAG,CAAA,CAAE,CAAC,CAAA,EAAK,EAAA,EAClDA,EAAG,QAAA,CAAS,MAAM,GAC3BC,CAAAA,CAAc,MAAA,CACdC,EAAiBF,CAAAA,CAAG,KAAA,CAAM,MAAM,CAAA,CAAE,CAAC,CAAA,EAAG,MAAM,GAAG,CAAA,CAAE,CAAC,CAAA,EAAK,EAAA,EAC9CA,EAAG,QAAA,CAAS,SAAS,GAC9BC,CAAAA,CAAc,QAAA,CACdC,EAAiBF,CAAAA,CAAG,KAAA,CAAM,SAAS,CAAA,CAAE,CAAC,GAAG,KAAA,CAAM,GAAG,CAAA,CAAE,CAAC,CAAA,EAAK,EAAA,EACjDA,EAAG,QAAA,CAAS,SAAS,GAAK,CAACA,CAAAA,CAAG,SAAS,QAAQ,CAAA,GACxDC,CAAAA,CAAc,QAAA,CACdC,CAAAA,CAAiBF,CAAAA,CAAG,MAAM,UAAU,CAAA,CAAE,CAAC,CAAA,EAAG,KAAA,CAAM,GAAG,CAAA,CAAE,CAAC,CAAA,EAAK,EAAA,CAAA,CAG7D,IAAIG,CAAAA,CAAS,UACTC,CAAAA,CAAY,EAAA,CAGZJ,EAAG,QAAA,CAAS,SAAS,GACvBG,CAAAA,CAAS,SAAA,CAETC,CAAAA,CADUJ,CAAAA,CAAG,KAAA,CAAM,uBAAuB,IAC1B,CAAC,CAAA,EAAK,IACbA,CAAAA,CAAG,QAAA,CAAS,SAAS,CAAA,EAC9BG,CAAAA,CAAS,SAAA,CAETC,CAAAA,CADUJ,CAAAA,CAAG,KAAA,CAAM,uBAAuB,CAAA,GAC1B,CAAC,GAAK,EAAA,EACb,kBAAA,CAAmB,KAAKA,CAAE,CAAA,EACnCG,CAAAA,CAAS,KAAA,CAETC,CAAAA,CADUJ,CAAAA,CAAG,MAAM,cAAc,CAAA,GACjB,CAAC,CAAA,EAAG,OAAA,CAAQ,IAAK,GAAG,CAAA,EAAK,EAAA,EAChCA,CAAAA,CAAG,QAAA,CAAS,UAAU,GAC/BG,CAAAA,CAAS,OAAA,CAETC,EADUJ,CAAAA,CAAG,KAAA,CAAM,+BAA+B,CAAA,GAClC,CAAC,GAAG,OAAA,CAAQ,IAAA,CAAM,GAAG,CAAA,EAAK,EAAA,EACjCA,EAAG,QAAA,CAAS,OAAO,IAC5BG,CAAAA,CAAS,OAAA,CAAA,CAGX,IAAIE,CAAAA,CAA8C,SAAA,CAClD,OAAI,uBAAuB,IAAA,CAAKL,CAAE,EAChCK,CAAAA,CAAa,QAAA,CACJ,kCAAkC,IAAA,CAAKL,CAAE,CAAA,GAClDK,CAAAA,CAAa,QAAA,CAAA,CAGR,CACL,YAAAJ,CAAAA,CACA,cAAA,CAAAC,EACA,MAAA,CAAAC,CAAAA,CACA,UAAAC,CAAAA,CACA,UAAA,CAAAC,CAAAA,CACA,WAAA,CAAa,MAAA,CAAO,MAAA,CAAO,MAC3B,YAAA,CAAc,MAAA,CAAO,OAAO,MAC9B,CACF,CC3DA,IAAMC,CAAAA,CAAa,iBAAA,CAenB,SAASC,CAAAA,EAAoB,CAC3B,OAAO,OAAO,SAAA,CAAc,KAAe,SAAA,CAAU,MAAA,GAAW,KAClE,CAEA,SAASC,EAAAA,CAAMC,CAAAA,CAA2B,CACxC,OAAO,IAAI,OAAA,CAASC,CAAAA,EAAY,WAAWA,CAAAA,CAASD,CAAE,CAAC,CACzD,CAGA,SAASE,EAAAA,CAAaC,CAAAA,CAAyB,CAC7C,IAAMC,CAAAA,CAAU,GAAA,CAAkB,KAAK,GAAA,CAAI,CAAA,CAAGD,CAAO,CAAA,CACrD,OAAO,IAAA,CAAK,MAAA,EAAO,CAAIC,CACzB,CAIA,SAASC,CAAAA,EAA+B,CACtC,GAAI,CACF,IAAMC,CAAAA,CAAM,YAAA,CAAa,QAAQT,CAAU,CAAA,CAC3C,GAAI,CAACS,CAAAA,CAAK,OAAO,EAAC,CAClB,IAAMC,CAAAA,CAAS,IAAA,CAAK,KAAA,CAAMD,CAAG,CAAA,CAC7B,OAAO,MAAM,OAAA,CAAQC,CAAM,EAAKA,CAAAA,CAA8B,EAChE,CAAA,KAAQ,CACN,OAAO,EACT,CACF,CAEA,SAASC,EAAAA,CAAYC,EAAiC,CACpD,GAAI,CACF,GAAIA,CAAAA,CAAQ,MAAA,GAAW,CAAA,CAAG,CACxB,YAAA,CAAa,WAAWZ,CAAU,CAAA,CAClC,MACF,CACA,YAAA,CAAa,QAAQA,CAAAA,CAAY,IAAA,CAAK,SAAA,CAAUY,CAAO,CAAC,EAC1D,MAAQ,CAER,CACF,CAGA,SAASC,CAAAA,CAAaC,EAAaC,CAAAA,CAAoB,CACrD,GAAI,CACF,IAAMH,CAAAA,CAAUJ,GAAW,CAG3B,IAFAI,EAAQ,IAAA,CAAK,CAAE,IAAAE,CAAAA,CAAK,IAAA,CAAAC,CAAAA,CAAM,EAAA,CAAI,IAAA,CAAK,GAAA,EAAM,CAAC,CAAA,CAEnCH,EAAQ,MAAA,CAAS,EAAA,EAAoBA,EAAQ,KAAA,EAAM,CAC1D,IAAII,CAAAA,CAAQJ,CAAAA,CAAQ,MAAA,CAAO,CAACK,CAAAA,CAAGC,CAAAA,GAAMD,EAAIC,CAAAA,CAAE,IAAA,CAAK,OAAQ,CAAC,CAAA,CACzD,KAAON,CAAAA,CAAQ,MAAA,CAAS,GAAKI,CAAAA,CAAQ,GAAA,EAAkB,CACrD,IAAMG,CAAAA,CAAUP,EAAQ,KAAA,EAAM,CAC9BI,CAAAA,EAASG,CAAAA,CAAQ,IAAA,CAAK,OACxB,CACAR,EAAAA,CAAYC,CAAO,EACrB,CAAA,KAAQ,CAER,CACF,CAIA,SAASQ,EAAAA,EAAuB,CAC9B,OAAO,OAAO,kBAAsB,GAAA,EAAe,OAAO,SAAa,GACzE,CAEA,eAAeC,EAAAA,CAAKN,CAAAA,CAA6B,CAC/C,IAAMO,CAAAA,CAAS,IAAI,KAAK,CAACP,CAAI,CAAC,CAAA,CAAE,MAAA,GAAS,WAAA,CAAY,IAAI,iBAAA,CAAkB,MAAM,CAAC,CAAA,CAC5EQ,EAAM,MAAM,IAAI,SAASD,CAAM,CAAA,CAAE,aAAY,CACnD,OAAO,IAAI,IAAA,CAAK,CAACC,CAAG,CAAC,CACvB,CAUA,eAAeC,EAAAA,CAASV,CAAAA,CAAaC,EAAcU,CAAAA,CAAqC,CACtF,GAAI,CACF,IAAMC,CAAAA,CAAkC,CAAE,cAAA,CAAgB,kBAAmB,EACzEC,CAAAA,CAAoBZ,CAAAA,CACxB,GAAIU,CAAAA,EAAYL,EAAAA,EAAY,CAC1B,GAAI,CACFO,CAAAA,CAAU,MAAMN,EAAAA,CAAKN,CAAI,EACzBW,CAAAA,CAAQ,kBAAkB,EAAI,OAChC,CAAA,KAAQ,CACNC,CAAAA,CAAUZ,EACZ,CAEF,IAAMa,CAAAA,CAAM,MAAM,KAAA,CAAMd,CAAAA,CAAK,CAAE,MAAA,CAAQ,MAAA,CAAQ,OAAA,CAAAY,CAAAA,CAAS,IAAA,CAAMC,CAAAA,CAAS,UAAW,CAAA,CAAK,CAAC,EACxF,OAAI,EAAAC,EAAI,MAAA,GAAW,GAAA,EAAOA,CAAAA,CAAI,MAAA,EAAU,GAAA,CAE1C,CAAA,KAAQ,CACN,OAAO,MACT,CACF,CAMA,eAAsBC,GAAUf,CAAAA,CAAaC,CAAAA,CAAcU,CAAAA,CAAkC,CAC3F,GAAI,CAACxB,GAAS,CAAG,CACfY,EAAaC,CAAAA,CAAKC,CAAI,EACtB,MACF,CACA,IAAA,IAAST,CAAAA,CAAU,CAAA,CAAGA,CAAAA,EAAW,EAAaA,CAAAA,EAAAA,CAAW,CAEvD,GADW,MAAMkB,EAAAA,CAASV,EAAKC,CAAAA,CAAMU,CAAQ,CAAA,CACrC,OACJnB,CAAAA,CAAU,CAAA,EAAa,MAAMJ,EAAAA,CAAMG,EAAAA,CAAaC,CAAO,CAAC,EAC9D,CAEAO,CAAAA,CAAaC,CAAAA,CAAKC,CAAI,EACxB,CAQA,eAAsBe,GAA6B,CACjD,GAAI,CAAC7B,CAAAA,EAAS,CAAG,OACjB,IAAIW,CAAAA,CAAUJ,CAAAA,EAAW,CACzB,GAAII,CAAAA,CAAQ,SAAW,CAAA,CAGvB,CAAAD,GAAY,EAAE,EACdC,CAAAA,CAAUA,CAAAA,CAAQ,KAAK,CAACmB,CAAAA,CAAGb,IAAMa,CAAAA,CAAE,EAAA,CAAKb,EAAE,EAAE,CAAA,CAC5C,QAAWc,CAAAA,IAASpB,CAAAA,CAAS,CAC3B,GAAI,CAACX,CAAAA,GAAY,CACfY,CAAAA,CAAamB,EAAM,GAAA,CAAKA,CAAAA,CAAM,IAAI,CAAA,CAClC,QACF,CACW,MAAMR,EAAAA,CAASQ,CAAAA,CAAM,IAAKA,CAAAA,CAAM,IAAA,CAAM,KAAK,CAAA,EAC7CnB,CAAAA,CAAamB,EAAM,GAAA,CAAKA,CAAAA,CAAM,IAAI,EAC7C,CAAA,CACF,CC9JA,IAAMC,EAAAA,CAAY,EAAA,CACZC,GAAoB,GAAA,CAGpBC,EAAAA,CAAY,IAEdC,CAAAA,CAA+B,IAAA,CAC/BC,CAAAA,CAAoB,EAAC,CACrBC,CAAAA,CAAoD,KACpDC,EAAAA,CAAuD,IAAA,CACvDC,GAAY,IAAA,CACZC,CAAAA,CAAc,MAIdC,CAAAA,CAEAC,CAAAA,CAA4C,EAAC,CAG7CC,CAAAA,CAAoC,IAAA,CACpCC,EAAkC,IAAA,CAClCC,CAAAA,CAAgC,KAE7B,SAASC,EAAAA,CAAUC,EAA0B,CAG9CP,CAAAA,GACJL,CAAAA,CAASY,CAAAA,CACTT,EAAAA,CAAc9C,CAAAA,GAEd+C,EAAAA,CAAYlD,CAAAA,CAAiB0D,EAAI,UAAA,EAAc,CAAC,EAChDP,CAAAA,CAAc,IAAA,CACdQ,EAAAA,EAAgB,CAChBC,EAAAA,EAAiB,CACjBC,IAAiB,CAEZrB,CAAAA,IACP,CAGO,SAASsB,GAAgBC,CAAAA,CAAoC,CAClEX,EAAeW,EACjB,CAEO,SAASC,EAAAA,CAAeC,CAAAA,CAAsC,CACnEZ,CAAAA,CAAmB,CAAE,GAAGA,CAAAA,CAAkB,GAAGY,CAAM,EACrD,CAEO,SAASC,IAAyB,CACvCb,CAAAA,CAAmB,GACrB,CAOA,SAASc,EAAAA,CAAsBC,CAAAA,CAAuB,CAEpD,GADa,MAAA,CAAO,IAAA,CAAKf,CAAgB,CAAA,CAChC,MAAA,GAAW,EAAG,OACvB,IAAIgB,EAAoC,EAAC,CACzC,GAAID,CAAAA,CAAM,UAAA,CACR,GAAI,CACF,IAAMhD,CAAAA,CAAS,KAAK,KAAA,CAAMgD,CAAAA,CAAM,UAAU,CAAA,CACtChD,CAAAA,EAAU,OAAOA,CAAAA,EAAW,QAAA,GAAUiD,CAAAA,CAAWjD,GACvD,CAAA,KAAQ,CACN,MACF,CAEFgD,CAAAA,CAAM,WAAa,IAAA,CAAK,SAAA,CAAU,CAAE,GAAGf,CAAAA,CAAkB,GAAGgB,CAAS,CAAC,EACxE,CAEO,SAASC,CAAAA,EAAkC,CAChD,OAAOxB,CACT,CAEO,SAASyB,EAAAA,EAAyB,CACvC,OAAOpB,CACT,CAGO,SAASqB,CAAAA,CAAYhD,CAAAA,CAAqB,CAC/C,GAAIsB,CAAAA,EAAQ,kBAAA,CAAoB,OAAOtB,CAAAA,CACvC,IAAIiD,EAAMjD,CAAAA,CAAI,MAAA,CACRkD,EAAIlD,CAAAA,CAAI,OAAA,CAAQ,GAAG,CAAA,CACnBmD,CAAAA,CAAInD,EAAI,OAAA,CAAQ,GAAG,EACzB,OAAIkD,CAAAA,GAAM,KAAID,CAAAA,CAAM,IAAA,CAAK,IAAIA,CAAAA,CAAKC,CAAC,CAAA,CAAA,CAC/BC,CAAAA,GAAM,EAAA,GAAIF,CAAAA,CAAM,KAAK,GAAA,CAAIA,CAAAA,CAAKE,CAAC,CAAA,CAAA,CAC5BnD,CAAAA,CAAI,MAAM,CAAA,CAAGiD,CAAG,CACzB,CAOA,SAASG,EAAAA,EAAgB,CACvB,IAAM/D,CAAAA,CACJ,OAAO,WAAA,CAAgB,GAAA,EAAe,YAAY,UAAA,CAC9C,WAAA,CAAY,UAAA,CAAa,WAAA,CAAY,GAAA,EAAI,CACzC,KAAK,GAAA,EAAI,CACf,OAAO,IAAA,CAAK,KAAA,CAAMA,EAAK,GAAS,CAClC,CAEO,SAASgE,CAAAA,CAAUT,CAAAA,CAAuB,CAC/C,GAAI,EAAA,CAACtB,GAAU,CAACI,EAAAA,CAAAA,CAKhB,IAJAkB,CAAAA,CAAM,SAAA,CAAYA,CAAAA,CAAM,SAAA,EAAaQ,EAAAA,EAAM,CAIvC9B,EAAO,UAAA,CACT,GAAI,CACF,IAAMgC,CAAAA,CAAShC,EAAO,UAAA,CAAWsB,CAAK,CAAA,CACtC,GAAIU,CAAAA,GAAW,IAAA,CAAM,OACrBV,CAAAA,CAAQU,CAAAA,EAAUV,EACpB,CAAA,KAAQ,CAER,CAIFD,EAAAA,CAAsBC,CAAK,CAAA,CAE3BrB,CAAAA,CAAM,IAAA,CAAKqB,CAAK,EAEZrB,CAAAA,CAAM,MAAA,CAASF,IAAWE,CAAAA,CAAM,MAAA,CAAO,EAAGA,CAAAA,CAAM,MAAA,CAASF,EAAS,CAAA,CAClEE,CAAAA,CAAM,QAAUJ,EAAAA,EAAWoC,CAAAA,IACjC,CAEA,SAASC,IAAqB,CAC5B,IAAMtB,CAAAA,CAAMZ,CAAAA,CACNmC,CAAAA,CAAKhC,EAAAA,CACPiC,EAAS,EAAA,CAEb,GAAI9B,IAAiB,MAAA,CACnB8B,CAAAA,CAAS9B,GAAc,EAAA,EAAM,EAAA,CAAA,KAE7B,GAAI,CAEF8B,CAAAA,CADUxB,CAAAA,CAAI,QAAO,EACT,EAAA,EAAM,GACpB,CAAA,KAAQ,CAER,CAGF,OAAO,CACL,QAAA,CAAUA,CAAAA,CAAI,GAAA,CAAI,IAAA,CAClB,YAAaA,CAAAA,CAAI,GAAA,CAAI,SAAW,EAAA,CAChC,WAAA,CAAaA,EAAI,WAAA,EAAe,EAAA,CAChC,UAAA,CAAY/D,CAAAA,EAAa,CACzB,OAAA,CAASuF,EACT,QAAA,CAAUV,CAAAA,CAAY,SAAS,IAAI,CAAA,CACnC,UAAW,QAAA,CAAS,QAAA,CACpB,SAAA,CAAW,QAAA,CAAS,KAAA,CACpB,QAAA,CAAUA,EAAY,QAAA,CAAS,QAAQ,EACvC,YAAA,CAAcS,CAAAA,CAAG,YACjB,eAAA,CAAiBA,CAAAA,CAAG,cAAA,CACpB,OAAA,CAASA,CAAAA,CAAG,MAAA,CACZ,WAAYA,CAAAA,CAAG,SAAA,CACf,YAAaA,CAAAA,CAAG,UAAA,CAChB,aAAcA,CAAAA,CAAG,WAAA,CACjB,aAAA,CAAeA,CAAAA,CAAG,YACpB,CACF,CAEO,SAASF,CAAAA,EAAc,CAC5B,GAAI,CAACjC,GAAUC,CAAAA,CAAM,MAAA,GAAW,EAAG,OACnC,IAAMoC,EAAWrC,CAAAA,CAAO,QAAA,CAClBX,EAAWW,CAAAA,CAAO,QAAA,GAAa,KAErC,KAAOC,CAAAA,CAAM,MAAA,CAAS,CAAA,EAAG,CACvB,IAAMqC,EAASrC,CAAAA,CAAM,MAAA,CAAO,EAAGJ,EAAS,CAAA,CAClCN,EAAsB,CAAE,IAAA,CAAM2C,EAAAA,EAAU,CAAG,MAAA,CAAAI,CAAO,EAClD3D,CAAAA,CAAO,IAAA,CAAK,UAAUY,CAAO,CAAA,CAE9BE,GAAU4C,CAAAA,CAAU1D,CAAAA,CAAMU,CAAQ,EACzC,CACF,CAEA,SAASwB,EAAAA,EAAwB,CAC3BX,IACJA,CAAAA,CAAa,WAAA,CAAY,IAAM,CACzBD,CAAAA,CAAM,MAAA,CAAS,CAAA,EAAGgC,CAAAA,GACxB,EAAGnC,EAAiB,CAAA,EACtB,CAEA,SAASgB,EAAAA,EAAyB,CAChC,GAAI,OAAO,QAAA,CAAa,GAAA,CAAa,OAErC,IAAMyB,EAAc,IAAM,CACxB,GAAI,CAACvC,CAAAA,EAAUC,EAAM,MAAA,GAAW,CAAA,CAAG,OACnC,IAAMqC,CAAAA,CAASrC,CAAAA,CAAM,OAAO,CAAC,CAAA,CACvBV,EAAsB,CAAE,IAAA,CAAM2C,IAAU,CAAG,MAAA,CAAAI,CAAO,CAAA,CAClD3D,CAAAA,CAAO,IAAA,CAAK,UAAUY,CAAO,CAAA,CAEnC,GAAI,SAAA,CAAU,UAAA,CACZ,UAAU,UAAA,CAAWS,CAAAA,CAAO,SAAUrB,CAAI,CAAA,CAAA,QAGtC,CACF,IAAM6D,EAAM,IAAI,cAAA,CAChBA,EAAI,IAAA,CAAK,MAAA,CAAQxC,CAAAA,CAAO,QAAA,CAAU,CAAA,CAAK,CAAA,CACvCwC,EAAI,gBAAA,CAAiB,cAAA,CAAgB,kBAAkB,CAAA,CACvDA,CAAAA,CAAI,KAAK7D,CAAI,EACf,CAAA,KAAQ,CAER,CAEJ,CAAA,CAEA6B,EAAe,IAAM,CACf,SAAS,eAAA,GAAoB,QAAA,EAAU+B,IAC7C,CAAA,CACA9B,CAAAA,CAAa8B,CAAAA,CACb,QAAA,CAAS,gBAAA,CAAiB,mBAAoB/B,CAAY,CAAA,CAC1D,OAAO,gBAAA,CAAiB,UAAA,CAAYC,CAAU,EAChD,CAGA,SAASM,EAAAA,EAAyB,CAC5B,OAAO,OAAW,GAAA,GACtBL,CAAAA,CAAW,IAAM,CACVhB,CAAAA,GACP,CAAA,CACA,MAAA,CAAO,gBAAA,CAAiB,QAAA,CAAUgB,CAAQ,CAAA,EAC5C,CAQO,SAAS+B,EAAAA,EAAgB,CAC9BR,CAAAA,EAAM,CACF/B,IACF,aAAA,CAAcA,CAAU,CAAA,CACxBA,CAAAA,CAAa,IAAA,CAAA,CAEX,OAAO,SAAa,GAAA,EAAeM,CAAAA,EACrC,SAAS,mBAAA,CAAoB,kBAAA,CAAoBA,CAAY,CAAA,CAE3D,OAAO,MAAA,CAAW,GAAA,EAAeC,CAAAA,EACnC,MAAA,CAAO,oBAAoB,UAAA,CAAYA,CAAU,EAE/C,OAAO,MAAA,CAAW,KAAeC,CAAAA,EACnC,MAAA,CAAO,oBAAoB,QAAA,CAAUA,CAAQ,EAE/CF,CAAAA,CAAe,IAAA,CACfC,EAAa,IAAA,CACbC,CAAAA,CAAW,KACXT,CAAAA,CAAQ,EAAC,CACTD,CAAAA,CAAS,IAAA,CACTK,CAAAA,CAAc,MACdC,CAAAA,CAAe,MAAA,CACfC,EAAmB,GACrB,CCpQO,SAASmC,EAAAA,EAAmB,CAEjC,OAAO,YAAY,CAAA,CAAE,KAAK,CAAC,CAAE,MAAAC,CAAAA,CAAO,KAAA,CAAAC,EAAO,KAAA,CAAAC,CAAAA,CAAO,KAAA,CAAAC,CAAAA,CAAO,MAAA,CAAAC,CAAO,IAAM,CACpE,IAAMC,EAAUC,CAAAA,EAAkBC,CAAAA,EAA8C,CAC9EnB,CAAAA,CAAU,CACR,UAAA,CAAY,WAAA,CACZ,UAAA,CAAYkB,CAAAA,CACZ,YAAaC,CAAAA,CAAO,KAAA,CACpB,aAAcA,CAAAA,CAAO,MACvB,CAAC,EACH,CAAA,CAEAP,CAAAA,CAAMK,CAAAA,CAAO,KAAK,CAAC,EACnBJ,CAAAA,CAAMI,CAAAA,CAAO,KAAK,CAAC,CAAA,CACnBH,EAAMG,CAAAA,CAAO,KAAK,CAAC,CAAA,CACnBF,CAAAA,CAAME,CAAAA,CAAO,KAAK,CAAC,CAAA,CACnBD,EAAOC,CAAAA,CAAO,MAAM,CAAC,EACvB,CAAC,CAAA,CAAE,KAAA,CAAM,IAAM,CAEf,CAAC,EACH,CCTA,IAAIG,EAAAA,CAA8B,IAAA,CAElC,SAASnG,EAAAA,EAAc,CACrB,OAAO,OAAO,WAAA,CAAgB,KAAe,WAAA,CAAY,GAAA,CAAM,YAAY,GAAA,EAAI,CAAI,KAAK,GAAA,EAC1F,CAEO,SAASoG,EAAAA,CAAYC,CAAAA,CAAsB,CAChDF,EAAAA,CAAY,CAAE,OAAAE,CAAAA,CAAQ,EAAA,CAAIrG,IAAM,EAClC,CAEO,SAASsG,EAAAA,EAAiC,CAC/C,OAAOH,EACT,CCpBA,IAAMI,EAAAA,CAAwB,GAAA,CAE1BC,EAAQ,KAAA,CACRC,CAAAA,CAAgD,IAAA,CAChDC,CAAAA,CAA+D,IAAA,CAGnE,SAASC,IAA4B,CACnC,IAAMC,EAAON,EAAAA,EAAa,CAC1B,GAAI,CAACM,CAAAA,CAAM,OAAA,CAET,OAAO,WAAA,CAAgB,GAAA,EAAe,YAAY,GAAA,CAAM,WAAA,CAAY,KAAI,CAAI,IAAA,CAAK,KAAI,EAC7EA,CAAAA,CAAK,EAAA,CAAKL,EAAAA,EAClBxB,CAAAA,CAAU,CACR,WAAY,aAAA,CACZ,gBAAA,CAAkB,cAClB,kBAAA,CAAoB6B,CAAAA,CAAK,MAC3B,CAAC,EAEL,CAEO,SAASC,EAAAA,EAAmB,CAC7BL,IACJA,CAAAA,CAAQ,IAAA,CAERC,EAAWnC,CAAAA,EAA4B,CACrCqC,IAAoB,CACpB5B,CAAAA,CAAU,CACR,UAAA,CAAY,OAAA,CACZ,aAAA,CAAeT,EAAM,OAAA,EAAW,eAAA,CAChC,YAAaA,CAAAA,CAAM,KAAA,EAAO,OAAS,EAAA,CACnC,UAAA,CAAYA,EAAM,KAAA,EAAO,IAAA,EAAQ,OACnC,CAAC,EACH,EAEAoC,CAAAA,CAAepC,CAAAA,EAAuC,CACpD,IAAMwC,CAAAA,CAASxC,CAAAA,CAAM,MAAA,CACjByC,CAAAA,CAAU,6BAAA,CACVC,EAAQ,EAAA,CACRC,CAAAA,CAAY,qBAEZH,CAAAA,YAAkB,KAAA,EACpBC,EAAUD,CAAAA,CAAO,OAAA,CACjBE,CAAAA,CAAQF,CAAAA,CAAO,KAAA,EAAS,EAAA,CACxBG,EAAYH,CAAAA,CAAO,IAAA,EACV,OAAOA,CAAAA,EAAW,QAAA,GAC3BC,EAAUD,CAAAA,CAAAA,CAGZ/B,CAAAA,CAAU,CACR,UAAA,CAAY,OAAA,CACZ,aAAA,CAAegC,EACf,WAAA,CAAaC,CAAAA,CACb,WAAYC,CACd,CAAC,EACH,CAAA,CAEA,MAAA,CAAO,gBAAA,CAAiB,OAAA,CAASR,CAAO,CAAA,CACxC,OAAO,gBAAA,CAAiB,oBAAA,CAAsBC,CAAW,CAAA,EAC3D,CAGO,SAASQ,EAAAA,EAAsB,CAChCT,CAAAA,GACF,MAAA,CAAO,mBAAA,CAAoB,OAAA,CAASA,CAAO,CAAA,CAC3CA,CAAAA,CAAU,MAERC,CAAAA,GACF,MAAA,CAAO,oBAAoB,oBAAA,CAAsBA,CAAW,CAAA,CAC5DA,CAAAA,CAAc,IAAA,CAAA,CAEhBF,CAAAA,CAAQ,MACV,CC3EA,IAAIW,GAAU,KAAA,CAEP,SAASC,IAAsB,CAIpC,GAFAC,CAAAA,EAAc,CAEVF,EAAAA,CAAS,OACbA,GAAU,IAAA,CAGV,IAAMG,EAAW,OAAA,CAAQ,SAAA,CAAU,KAAK,OAAO,CAAA,CACzCC,EAAc,OAAA,CAAQ,YAAA,CAAa,KAAK,OAAO,CAAA,CAErD,QAAQ,SAAA,CAAY,SAAA,GAAaC,EAAmC,CAClEF,CAAAA,CAAS,GAAGE,CAAI,CAAA,CAChBH,CAAAA,GACF,CAAA,CAEA,OAAA,CAAQ,aAAe,SAAA,GAAaG,CAAAA,CAAsC,CACxED,CAAAA,CAAY,GAAGC,CAAI,CAAA,CACnBH,CAAAA,GACF,EAGA,MAAA,CAAO,gBAAA,CAAiB,WAAY,IAAM,CACxCA,IACF,CAAC,EACH,CAEA,SAASI,EAAAA,EAA0B,CACjC,IAAMC,CAAAA,CAAQ,IAAI,UAAA,CAAW,EAAE,EAC/B,OAAA,MAAA,CAAO,eAAA,CAAgBA,CAAK,CAAA,CACrB,KAAA,CAAM,IAAA,CAAKA,CAAK,CAAA,CAAE,GAAA,CAAK5F,GAAMA,CAAAA,CAAE,QAAA,CAAS,EAAE,CAAA,CAAE,QAAA,CAAS,CAAA,CAAG,GAAG,CAAC,CAAA,CAAE,KAAK,EAAE,CAC9E,CAEA,SAAS6F,EAAAA,EAAyB,CAChC,IAAMD,CAAAA,CAAQ,IAAI,UAAA,CAAW,CAAC,CAAA,CAC9B,cAAO,eAAA,CAAgBA,CAAK,EACrB,KAAA,CAAM,IAAA,CAAKA,CAAK,CAAA,CAAE,GAAA,CAAK5F,CAAAA,EAAMA,CAAAA,CAAE,QAAA,CAAS,EAAE,EAAE,QAAA,CAAS,CAAA,CAAG,GAAG,CAAC,CAAA,CAAE,KAAK,EAAE,CAC9E,CAEA,SAASuF,CAAAA,EAAsB,CAC7B,IAAMO,CAAAA,CAAUH,IAAgB,CAC1BI,CAAAA,CAASF,IAAe,CAE9B5C,CAAAA,CAAU,CACR,UAAA,CAAY,UAAA,CACZ,UAAA,CAAY,SAAS,KAAA,CACrB,WAAA,CAAa+C,IAAsB,CACnC,QAAA,CAAUF,EACV,OAAA,CAASC,CACX,CAAC,EACH,CAEA,SAASC,IAAgC,CACvC,GAAI,OAAO,WAAA,CAAgB,GAAA,CAAa,OAAO,CAAA,CAC/C,IAAMC,CAAAA,CAAU,WAAA,CAAY,gBAAA,CAAiB,YAAY,EACzD,OAAIA,CAAAA,CAAQ,OAAS,CAAA,CACZA,CAAAA,CAAQ,CAAC,CAAA,CAAE,YAAA,CAAeA,CAAAA,CAAQ,CAAC,CAAA,CAAE,SAAA,CAEvC,CACT,CC5DA,IAAMC,GAAwB,wEAAA,CAGxBC,EAAAA,CAAiB,IACjBC,EAAAA,CAAiB,CAAA,CAGjBC,EAAAA,CAAiB,GAAA,CAEnB3B,CAAAA,CAAQ,KAAA,CACR4B,EAAsD,IAAA,CAGtDC,CAAAA,CAA6B,KAC7BC,CAAAA,CAAsB,GAQtBC,CAAAA,CAA8B,EAAC,CAGnC,SAASC,EAAAA,CAAeC,CAAAA,CAAqB,CAC3C,IAAMC,CAAAA,CAAMD,EAAG,OAAA,CAAQ,WAAA,GACjBxI,CAAAA,CAAKwI,CAAAA,CAAG,EAAA,CAAK,CAAA,CAAA,EAAIA,CAAAA,CAAG,EAAE,GAAK,EAAA,CAC3BE,CAAAA,CAAUF,EAAG,SAAA,CACf,CAAA,CAAA,EAAI,MAAM,IAAA,CAAKA,CAAAA,CAAG,SAAS,CAAA,CAAE,KAAA,CAAM,EAAG,CAAC,CAAA,CAAE,KAAK,GAAG,CAAC,GAClD,EAAA,CAEEG,CAAAA,CAAOpE,CAAAA,EAAU,EAAG,mBAAA,CACtB,EAAA,CAAA,CACCiE,EAAG,WAAA,EAAe,EAAA,EAAI,MAAK,CAAE,KAAA,CAAM,EAAG,GAAG,CAAA,CAC9C,OAAO,CAAA,EAAGC,CAAG,CAAA,EAAGzI,CAAE,CAAA,EAAG0I,CAAO,GAAGC,CAAAA,CAAO,CAAA,EAAA,EAAKA,CAAI,CAAA,CAAA,CAAA,CAAM,EAAE,CAAA,CACzD,CAGA,SAASC,EAAAA,CAAgBJ,EAAapC,CAAAA,CAAsB,CAC1D,IAAMrG,CAAAA,CAAM,IAAA,CAAK,KAAI,CACjBqI,CAAAA,GAAeI,CAAAA,GACjBJ,CAAAA,CAAaI,CAAAA,CACbH,CAAAA,CAAY,EAAC,CAAA,CAEfA,CAAAA,CAAU,KAAKtI,CAAG,CAAA,CAElBsI,EAAYA,CAAAA,CAAU,MAAA,CAAQQ,CAAAA,EAAM9I,CAAAA,CAAM8I,CAAAA,EAAKb,EAAc,EACzDK,CAAAA,CAAU,MAAA,CAASJ,KACrBnD,CAAAA,CAAU,CACR,WAAY,aAAA,CACZ,gBAAA,CAAkB,YAAA,CAClB,kBAAA,CAAoBsB,CACtB,CAAC,EAEDiC,CAAAA,CAAY,GACZD,CAAAA,CAAa,IAAA,EAEjB,CAQA,SAASU,EAAAA,CAAgB1C,CAAAA,CAAsB,CAC7C,IAAI2C,CAAAA,CAAU,MACRC,CAAAA,CAAW,QAAA,CAAS,KAEpBC,CAAAA,CAAW,IAAI,iBAAiB,IAAM,CAC1CF,EAAU,KACZ,CAAC,EACD,GAAI,CACFE,EAAS,OAAA,CAAQ,QAAA,CAAS,gBAAiB,CACzC,SAAA,CAAW,CAAA,CAAA,CACX,OAAA,CAAS,CAAA,CAAA,CACT,UAAA,CAAY,GACZ,aAAA,CAAe,CAAA,CACjB,CAAC,EACH,CAAA,KAAQ,CACN,MACF,CAEA,IAAMC,CAAAA,CAAW,IAAM,CACrBH,EAAU,KACZ,CAAA,CACA,OAAO,gBAAA,CAAiB,QAAA,CAAUG,EAAU,CAAE,OAAA,CAAS,IAAA,CAAM,OAAA,CAAS,IAAK,CAAC,EAE5E,IAAMC,CAAAA,CAAQ,WAAW,IAAM,CAC7BC,GAAQ,CACR,IAAMC,CAAAA,CAAY,QAAA,CAAS,IAAA,GAASL,CAAAA,CAChC,CAACD,CAAAA,EAAW,CAACM,GACfvE,CAAAA,CAAU,CACR,WAAY,aAAA,CACZ,gBAAA,CAAkB,YAAA,CAClB,kBAAA,CAAoBsB,CACtB,CAAC,EAEL,CAAA,CAAG8B,EAAc,EAEXoB,CAAAA,CAAuB,CAAE,SAAAL,CAAAA,CAAU,KAAA,CAAAE,CAAAA,CAAO,QAAA,CAAAD,CAAS,CAAA,CACzDZ,EAAa,IAAA,CAAKgB,CAAO,EAEzB,SAASF,CAAAA,EAAgB,CACvBH,CAAAA,CAAS,UAAA,EAAW,CACpB,YAAA,CAAaE,CAAK,CAAA,CAClB,OAAO,mBAAA,CAAoB,QAAA,CAAUD,EAAU,CAAE,OAAA,CAAS,IAAK,CAAyB,CAAA,CACxFZ,EAAeA,CAAAA,CAAa,MAAA,CAAQiB,GAAMA,CAAAA,GAAMD,CAAO,EACzD,CACF,CAEO,SAASE,EAAAA,EAAyB,CACnCjD,CAAAA,GACJA,CAAAA,CAAQ,IAAA,CAER4B,CAAAA,CAAiB9D,GAA4B,CAC3C,IAAM+B,EAAS/B,CAAAA,CAAM,MAAA,CACrB,GAAI,CAAC+B,CAAAA,CAAQ,OAEb,IAAMqD,CAAAA,CAAcrD,CAAAA,CAAO,QAAQ2B,EAAqB,CAAA,CACxD,GAAI,CAAC0B,CAAAA,CAAa,OAElB,IAAMC,CAAAA,CAAanB,EAAAA,CAAekB,CAAW,CAAA,CAG7CtD,EAAAA,CAAYuD,CAAU,CAAA,CAEtB5E,CAAAA,CAAU,CACR,UAAA,CAAY,aAAA,CACZ,iBAAkB,OAAA,CAClB,kBAAA,CAAoB4E,CACtB,CAAC,CAAA,CAEDd,EAAAA,CAAgBa,EAAaC,CAAU,CAAA,CACvCZ,GAAgBY,CAAU,EAC5B,EAEA,QAAA,CAAS,gBAAA,CAAiB,OAAA,CAASvB,CAAAA,CAAe,CAAE,OAAA,CAAS,KAAM,OAAA,CAAS,IAAK,CAAC,CAAA,EACpF,CAGO,SAASwB,EAAAA,EAA4B,CACtCxB,CAAAA,GACF,QAAA,CAAS,mBAAA,CAAoB,OAAA,CAASA,EAAe,CAAE,OAAA,CAAS,IAAK,CAAyB,CAAA,CAC9FA,EAAgB,IAAA,CAAA,CAElB,IAAA,IAAWoB,CAAAA,IAAKjB,CAAAA,CACdiB,CAAAA,CAAE,QAAA,CAAS,YAAW,CACtB,YAAA,CAAaA,EAAE,KAAK,CAAA,CACpB,OAAO,mBAAA,CAAoB,QAAA,CAAUA,EAAE,QAAA,CAAU,CAAE,QAAS,IAAK,CAAyB,EAE5FjB,CAAAA,CAAe,GACfF,CAAAA,CAAa,IAAA,CACbC,CAAAA,CAAY,EAAC,CACb9B,CAAAA,CAAQ,MACV,CC7JA,IAAIW,GAAU,KAAA,CAEP,SAAS0C,IAAsB,CAChC1C,EAAAA,GACJA,EAAAA,CAAU,IAAA,CACV2C,EAAAA,EAAW,CACXC,IAAS,EACX,CAEA,SAASC,EAAAA,CAAkBtI,CAAAA,CAAsB,CAC/C,IAAMkC,CAAAA,CAAMY,CAAAA,EAAU,CACtB,OAAKZ,CAAAA,EAAK,iBAAiB,OAAA,CACpBA,CAAAA,CAAI,gBAAgB,OAAA,CAAQ,IAAA,CAAMqG,GAAOA,CAAAA,CAAG,IAAA,CAAKvI,CAAG,CAAC,CAAA,CADjB,KAE7C,CAEA,SAAS+F,EAAAA,EAA0B,CACjC,IAAMC,CAAAA,CAAQ,IAAI,UAAA,CAAW,EAAE,CAAA,CAC/B,OAAA,MAAA,CAAO,eAAA,CAAgBA,CAAK,EACrB,KAAA,CAAM,IAAA,CAAKA,CAAK,CAAA,CAAE,GAAA,CAAK5F,GAAMA,CAAAA,CAAE,QAAA,CAAS,EAAE,CAAA,CAAE,QAAA,CAAS,CAAA,CAAG,GAAG,CAAC,CAAA,CAAE,KAAK,EAAE,CAC9E,CAEA,SAAS6F,EAAAA,EAAyB,CAChC,IAAMD,CAAAA,CAAQ,IAAI,WAAW,CAAC,CAAA,CAC9B,cAAO,eAAA,CAAgBA,CAAK,EACrB,KAAA,CAAM,IAAA,CAAKA,CAAK,CAAA,CAAE,GAAA,CAAK5F,GAAMA,CAAAA,CAAE,QAAA,CAAS,EAAE,CAAA,CAAE,QAAA,CAAS,EAAG,GAAG,CAAC,CAAA,CAAE,IAAA,CAAK,EAAE,CAC9E,CAEA,SAASgI,EAAAA,EAAmB,CAC1B,IAAMI,CAAAA,CAAY,OAAO,KAAA,CAAM,IAAA,CAAK,MAAM,CAAA,CAE1C,MAAA,CAAO,KAAA,CAAQ,eAAgBC,CAAAA,CAA0BC,CAAAA,CAAuC,CAC9F,IAAM1I,CAAAA,CAAM,OAAOyI,CAAAA,EAAU,QAAA,CAAWA,CAAAA,CAAQA,CAAAA,YAAiB,GAAA,CAAMA,CAAAA,CAAM,KAAOA,CAAAA,CAAM,GAAA,CACpFE,EAAQ,WAAA,CAAY,GAAA,GAEtBzC,CAAAA,CAAU,EAAA,CACVC,CAAAA,CAAS,EAAA,CAEb,GAAImC,EAAAA,CAAkBtI,CAAG,CAAA,CAAG,CAC1BkG,EAAUH,EAAAA,EAAgB,CAC1BI,EAASF,EAAAA,EAAe,CACxB,IAAMrF,CAAAA,CAAU,IAAI,OAAA,CAAQ8H,GAAM,OAAO,CAAA,CACzC9H,EAAQ,GAAA,CAAI,aAAA,CAAe,MAAMsF,CAAO,CAAA,CAAA,EAAIC,CAAM,CAAA,GAAA,CAAK,CAAA,CACvDuC,CAAAA,CAAO,CAAE,GAAGA,CAAAA,CAAM,QAAA9H,CAAQ,EAC5B,CAEA,GAAI,CACF,IAAMgI,CAAAA,CAAW,MAAMJ,CAAAA,CAAUC,EAAOC,CAAI,CAAA,CACtCG,EAAa,WAAA,CAAY,GAAA,GAAQF,CAAAA,CAEvC,OAAAtF,EAAU,CACR,UAAA,CAAY,WACZ,UAAA,CAAYL,CAAAA,CAAYhD,CAAG,CAAA,CAC3B,WAAA,CAAa6I,EACb,QAAA,CAAU3C,CAAAA,CACV,OAAA,CAASC,CAAAA,CACT,UAAA,CAAY,IAAA,CAAK,UAAU,CAAE,MAAA,CAAQyC,EAAS,MAAA,CAAQ,MAAA,CAAQF,GAAM,MAAA,EAAU,KAAM,CAAC,CACvF,CAAC,CAAA,CAEME,CACT,CAAA,MAASE,CAAAA,CAAK,CACZ,IAAMD,CAAAA,CAAa,YAAY,GAAA,EAAI,CAAIF,CAAAA,CACvC,MAAAtF,CAAAA,CAAU,CACR,WAAY,UAAA,CACZ,UAAA,CAAYL,EAAYhD,CAAG,CAAA,CAC3B,YAAa6I,CAAAA,CACb,QAAA,CAAU3C,CAAAA,CACV,OAAA,CAASC,CAAAA,CACT,aAAA,CAAe2C,aAAe,KAAA,CAAQA,CAAAA,CAAI,QAAU,cAAA,CACpD,UAAA,CAAY,cACd,CAAC,CAAA,CACKA,CACR,CACF,EACF,CAEA,SAAST,EAAAA,EAAiB,CACxB,IAAMU,CAAAA,CAAW,cAAA,CAAe,UAAU,IAAA,CACpCC,CAAAA,CAAW,cAAA,CAAe,SAAA,CAAU,IAAA,CAE1C,cAAA,CAAe,UAAU,IAAA,CAAO,SAAUC,EAAgBjJ,CAAAA,CAAAA,GAAsBkJ,CAAAA,CAAa,CAC3F,OAAC,IAAA,CAAa,UAAA,CAAa,OAAOlJ,CAAAA,EAAQ,QAAA,CAAWA,EAAMA,CAAAA,CAAI,IAAA,CAC9D,KAAa,aAAA,CAAgBiJ,CAAAA,CACvBF,EAAS,KAAA,CAAM,IAAA,CAAM,CAACE,CAAAA,CAAQjJ,CAAAA,CAAK,GAAGkJ,CAAI,CAAQ,CAC3D,CAAA,CAEA,cAAA,CAAe,UAAU,IAAA,CAAO,SAAUjJ,CAAAA,CAAY,CACpD,IAAMD,CAAAA,CAAe,KAAa,UAAA,EAAc,EAAA,CAC1CiJ,EAAkB,IAAA,CAAa,aAAA,EAAiB,MAChDN,CAAAA,CAAQ,WAAA,CAAY,GAAA,EAAI,CAE1BzC,CAAAA,CAAU,EAAA,CACVC,EAAS,EAAA,CACb,OAAImC,GAAkBtI,CAAG,CAAA,GACvBkG,EAAUH,EAAAA,EAAgB,CAC1BI,CAAAA,CAASF,EAAAA,EAAe,CACxB,IAAA,CAAK,iBAAiB,aAAA,CAAe,CAAA,GAAA,EAAMC,CAAO,CAAA,CAAA,EAAIC,CAAM,KAAK,CAAA,CAAA,CAGnE,IAAA,CAAK,gBAAA,CAAiB,SAAA,CAAW,IAAM,CACrC,IAAM0C,CAAAA,CAAa,WAAA,CAAY,KAAI,CAAIF,CAAAA,CACvCtF,EAAU,CACR,UAAA,CAAY,UAAA,CACZ,UAAA,CAAYL,CAAAA,CAAYhD,CAAG,EAC3B,WAAA,CAAa6I,CAAAA,CACb,SAAU3C,CAAAA,CACV,OAAA,CAASC,EACT,UAAA,CAAY,IAAA,CAAK,SAAA,CAAU,CAAE,MAAA,CAAQ,IAAA,CAAK,OAAQ,MAAA,CAAA8C,CAAO,CAAC,CAC5D,CAAC,EACH,CAAC,CAAA,CAEMD,CAAAA,CAAS,IAAA,CAAK,IAAA,CAAM/I,CAAI,CACjC,EACF,CC3GA,IAAIkJ,CAAAA,CAAU,KAAA,CACVC,EAA+C,IAAA,CAC/CC,CAAAA,CAA2C,KAE/C,SAASC,EAAAA,CAASC,EAAuB,CACvC,OACE,OAAO,mBAAA,CAAwB,GAAA,EAC/B,MAAM,OAAA,CAAQ,mBAAA,CAAoB,mBAAmB,CAAA,EACrD,mBAAA,CAAoB,mBAAA,CAAoB,SAASA,CAAI,CAEzD,CAEO,SAASC,EAAAA,EAAwB,CACtC,GAAI,CAAAL,CAAAA,EACA,EAAA,OAAO,mBAAA,CAAwB,GAAA,CAAA,CAGnC,IAFAA,CAAAA,CAAU,IAAA,CAENG,GAAS,UAAU,CAAA,CACrB,GAAI,CACFF,CAAAA,CAAmB,IAAI,mBAAA,CAAqBK,CAAAA,EAAS,CACnD,QAAWC,CAAAA,IAASD,CAAAA,CAAK,YAAW,CAClCpG,CAAAA,CAAU,CACR,UAAA,CAAY,WAAA,CACZ,WAAA,CAAaqG,CAAAA,CAAM,QAAA,CACnB,UAAA,CAAY,KAAK,SAAA,CAAU,CAAE,MAAOA,CAAAA,CAAM,SAAA,CAAW,KAAMA,CAAAA,CAAM,IAAK,CAAC,CACzE,CAAC,EAEL,CAAC,CAAA,CACDN,CAAAA,CAAiB,QAAQ,CAAE,IAAA,CAAM,WAAY,QAAA,CAAU,CAAA,CAAK,CAAC,EAC/D,CAAA,KAAQ,CACNA,EAAmB,KACrB,CAGF,GAAIE,EAAAA,CAAS,sBAAsB,EACjC,GAAI,CACFD,CAAAA,CAAe,IAAI,mBAAA,CAAqBI,CAAAA,EAAS,CAC/C,IAAA,IAAWC,CAAAA,IAASD,EAAK,UAAA,EAAW,CAAG,CAGrC,IAAME,CAAAA,CAAID,EAIVrG,CAAAA,CAAU,CACR,WAAY,MAAA,CACZ,WAAA,CAAasG,EAAE,QAAA,CACf,UAAA,CAAY,KAAK,SAAA,CAAU,CACzB,KAAA,CAAOA,CAAAA,CAAE,SAAA,CACT,gBAAA,CAAkBA,EAAE,gBAAA,EAAoB,CAAA,CACxC,SAAUA,CAAAA,CAAE,OAAA,EAAW,EAAC,EAAG,MAC7B,CAAC,CACH,CAAC,EACH,CACF,CAAC,CAAA,CACDN,EAAa,OAAA,CAAQ,CAAE,KAAM,sBAAA,CAAwB,QAAA,CAAU,CAAA,CAAK,CAAC,EACvE,CAAA,KAAQ,CACNA,CAAAA,CAAe,KACjB,EAEJ,CAEO,SAASO,IAA2B,CACrCR,CAAAA,GACFA,CAAAA,CAAiB,UAAA,EAAW,CAC5BA,CAAAA,CAAmB,MAEjBC,CAAAA,GACFA,CAAAA,CAAa,YAAW,CACxBA,CAAAA,CAAe,MAEjBF,CAAAA,CAAU,MACZ,CC9CO,SAASU,EAAAA,CAAYC,CAAAA,CAAuB,CACjD,OAAO,CACL,KAAKxI,CAAAA,CAA6B,CAGhC,GAAI,EAAA,OAAO,MAAA,CAAW,GAAA,CAAA,CAEtB,CAAA,GAAIyB,EAAAA,EAAc,CAAG,CACnB,OAAA,CAAQ,IAAA,CAAK,mDAAmD,CAAA,CAChE,MACF,CAEAd,EAAAA,CAAUX,CAAM,CAAA,CAEZA,CAAAA,CAAO,cAAA,GAAmB,KAAA,EAAO0C,IAAW,CAC5C1C,CAAAA,CAAO,cAAgB,KAAA,EAAO6D,EAAAA,GAC9B7D,CAAAA,CAAO,cAAA,GAAmB,OAAOoE,EAAAA,EAAc,CAC/CpE,EAAO,cAAA,GAAmB,KAAA,EAAOkI,IAAgB,CACjDlI,CAAAA,CAAO,oBAAsB,IAAA,EAAMyG,EAAAA,EAAiB,CACpDzG,CAAAA,CAAO,cAAA,GAAmB,IAAA,EAAM6G,IAAc,CAC9C7G,CAAAA,CAAO,qBAAuB,IAAA,GAC5BwI,CAAAA,CACFA,EAAO,IAAA,CAAKxI,CAAM,CAAA,CAElB,OAAA,CAAQ,IAAA,CAAK,4GAA4G,IAG/H,CAAA,CAGA,UAAA,CAAWiD,EAAcwF,CAAAA,CAA4C,CACnE1G,EAAU,CACR,UAAA,CAAY,QAAA,CACZ,UAAA,CAAYkB,CAAAA,CACZ,UAAA,CAAYwF,EAAa,IAAA,CAAK,SAAA,CAAUA,CAAU,CAAA,CAAI,MACxD,CAAC,EACH,CAAA,CAMA,OAAA,CAAQxH,CAAAA,CAAoC,CAC1CD,EAAAA,CAAgBC,CAAI,EACtB,CAAA,CAMA,oBAAoBE,CAAAA,CAAsC,CACxDD,GAAeC,CAAK,EACtB,CAAA,CAGA,qBAAA,EAA8B,CAC5BC,EAAAA,GACF,CAAA,CAGA,KAAA,CAAAa,EAMA,OAAA,EAAgB,CAEdqG,IAAmB,CACnB1B,EAAAA,EAAoB,CACpB1C,EAAAA,EAAc,CACVsE,CAAAA,EAAQA,EAAO,OAAA,EAAQ,CAC3B/F,KACF,CACF,CACF,CChGA,IAAMiG,EAAAA,CAAa,EAAA,CACb5I,EAAAA,CAAoB,GAAA,CAGpB6I,GAAe,YAAA,CACfC,EAAAA,CAAuB,wCAEzBf,CAAAA,CAAU,KAAA,CACVgB,EAAgC,IAAA,CAEhCC,CAAAA,CAAiB,EAAC,CAClBC,EAAAA,CAAY,EACZC,CAAAA,CAAqD,IAAA,CAErDC,EAAsC,IAAA,CAEtCC,CAAAA,CAAqC,KACrCC,CAAAA,CAAmC,IAAA,CAEvC,SAASC,EAAAA,EAAyB,CAChC,IAAMxI,EAAMiI,CAAAA,CACZ,OAAIjI,EAAI,cAAA,CAAuBA,CAAAA,CAAI,eAE5BA,CAAAA,CAAI,QAAA,CAAS,OAAA,CAAQ,gBAAA,CAAkB,oBAAoB,CACpE,CAGA,SAASyI,EAAAA,CAAAA,GAAiBC,EAA0C,CAClE,OAAOA,EAAM,MAAA,CAAQC,CAAAA,EAAmB,CAAC,CAACA,CAAAA,EAAKA,CAAAA,CAAE,OAAS,CAAC,CAAA,CAAE,KAAK,GAAG,CACvE,CAGA,SAASC,EAAAA,CAAUlH,CAAAA,CAAqB,CACtC,GAAI,CAACuG,GAAWvG,CAAAA,CAAO,MAAA,GAAW,EAAG,OACrC,IAAM/C,EAAU,CACd,UAAA,CAAY1C,CAAAA,EAAa,CACzB,QAAA,CAAUgM,CAAAA,CAAQ,IAAI,IAAA,CACtB,SAAA,CAAWE,KACX,MAAA,CAAAzG,CACF,EACA,KAAA,CAAM8G,EAAAA,EAAe,CAAG,CACtB,MAAA,CAAQ,MAAA,CACR,QAAS,CAAE,cAAA,CAAgB,kBAAmB,CAAA,CAC9C,IAAA,CAAM,KAAK,SAAA,CAAU7J,CAAO,CAAA,CAC5B,SAAA,CAAW,IACb,CAAC,EAAE,KAAA,CAAM,IAAM,CAAoB,CAAC,EACtC,CAEA,SAASkK,CAAAA,EAAoB,CACvBX,CAAAA,CAAQ,MAAA,GAAW,GACvBU,EAAAA,CAAUV,CAAAA,CAAQ,OAAO,CAAC,CAAC,EAC7B,CASA,SAASY,EAAAA,CAAmB9I,CAAAA,CAI1B,CACA,IAAM+I,EAAQ/I,CAAAA,CAAI,aAAA,EAAiB,OAE/BgJ,CAAAA,CAAgB,IAAA,CAChBC,EAAW,KAAA,CACXC,CAAAA,CAAa,KAAA,CACbH,CAAAA,GAAU,MAAA,EACZC,CAAAA,CAAgB,KAChBC,CAAAA,CAAW,IAAA,CACXC,EAAa,IAAA,EACJH,CAAAA,GAAU,mBACnBC,CAAAA,CAAgB,IAAA,CAChBC,CAAAA,CAAW,KAAA,GAGXD,CAAAA,CAAgB,KAAA,CAChBC,EAAW,KAAA,CAAA,CAKb,IAAME,EAAmBF,CAAAA,CACrB,GAAA,CACAR,GAAcV,EAAAA,CAAc/H,CAAAA,CAAI,kBAAkB,CAAA,CAEhDoJ,CAAAA,CAAgBX,EAAAA,CACpBS,EAAalB,EAAAA,CAAuB,MAAA,CACpChI,EAAI,mBACN,CAAA,CAEA,OAAO,CAAE,aAAA,CAAAgJ,CAAAA,CAAe,gBAAA,CAAAG,CAAAA,CAAkB,aAAA,CAAAC,CAAc,CAC1D,CAEO,SAASC,EAAAA,CAAWjK,CAAAA,CAA6B,CACtD,GAAI6H,CAAAA,CAAS,OACbA,CAAAA,CAAU,IAAA,CACVgB,CAAAA,CAAU7I,EAEV,IAAMkK,CAAAA,CAAOR,GAAmB1J,CAAM,CAAA,CAChCmK,EAASnK,CAAAA,CAAO,oBAAA,CAGtB,OAAO,OAAO,CAAA,CAAE,IAAA,CAAK,CAAC,CAAE,MAAA,CAAAoK,CAAO,CAAA,GAAM,CACnC,GAAI,CAACvC,CAAAA,CAAS,OAEd,IAAMwC,CAAAA,CAAqC,CAEzC,IAAA,CAAK/I,CAAAA,CAAY,CAEf,GAAItB,CAAAA,CAAO,qBACT,GAAI,CACF,IAAMgC,CAAAA,CAAShC,CAAAA,CAAO,oBAAA,CAAqBsB,CAAK,CAAA,CAChD,GAAIU,IAAW,IAAA,CAAM,OACrBV,EAAQU,CAAAA,EAAUV,EACpB,CAAA,KAAQ,CAER,CAEFwH,CAAAA,CAAQ,KAAKxH,CAAK,CAAA,CACdwH,EAAQ,MAAA,EAAUJ,EAAAA,EAAYe,IACpC,CAAA,CACA,aAAA,CAAeS,CAAAA,CAAK,aACtB,CAAA,CACIA,EAAK,gBAAA,GAAkBG,CAAAA,CAAc,iBAAmBH,CAAAA,CAAK,gBAAA,CAAA,CAC7DA,EAAK,aAAA,GAAeG,CAAAA,CAAc,aAAA,CAAgBH,CAAAA,CAAK,aAAA,CAAA,CAIvDC,CAAAA,EAAUD,EAAK,gBAAA,GAAqB,GAAA,GACtCG,EAAc,UAAA,CAAa,CAACzE,EAAcH,CAAAA,GAA+B,CACvE,GAAI,CACF,GAAIA,CAAAA,EAAMA,EAAG,OAAA,EAAWA,CAAAA,CAAG,QAAQ0E,CAAM,CAAA,CAAG,OAAOvE,CACrD,CAAA,KAAQ,CAER,CACA,OAAOA,CAAAA,CAAK,QAAQ,KAAA,CAAO,GAAG,CAChC,CAAA,CAAA,CAGF,IAAM0E,EAAOF,CAAAA,CAAOC,CAAa,CAAA,CACjCpB,CAAAA,CAAiB,OAAOqB,CAAAA,EAAS,WAAaA,CAAAA,CAAO,KACvD,CAAC,CAAA,CAAE,KAAA,CAAM,IAAM,CAEf,CAAC,EAEDtB,CAAAA,CAAc,WAAA,CAAYS,EAAa3J,EAAiB,CAAA,CAExDoJ,EAAgB,IAAM,CAChB,SAAS,eAAA,GAAoB,QAAA,EAAUO,CAAAA,GAC7C,CAAA,CACAN,CAAAA,CAAcM,EACd,QAAA,CAAS,gBAAA,CAAiB,mBAAoBP,CAAa,CAAA,CAC3D,OAAO,gBAAA,CAAiB,UAAA,CAAYC,CAAW,EACjD,CAGO,SAASoB,IAAsB,CACpC,GAAItB,EAAgB,CAClB,GAAI,CACFA,CAAAA,GACF,CAAA,KAAQ,CAER,CACAA,CAAAA,CAAiB,KACnB,CACID,CAAAA,GACF,cAAcA,CAAW,CAAA,CACzBA,EAAc,IAAA,CAAA,CAEhBS,CAAAA,EAAY,CACR,OAAO,QAAA,CAAa,GAAA,EAAeP,GACrC,QAAA,CAAS,mBAAA,CAAoB,mBAAoBA,CAAa,CAAA,CAE5D,OAAO,MAAA,CAAW,GAAA,EAAeC,CAAAA,EACnC,MAAA,CAAO,mBAAA,CAAoB,UAAA,CAAYA,CAAW,CAAA,CAEpDD,CAAAA,CAAgB,KAChBC,CAAAA,CAAc,IAAA,CACdL,EAAU,EAAC,CACXD,CAAAA,CAAU,IAAA,CACVhB,CAAAA,CAAU,MACZ,CC7LO,IAAM2C,EAAAA,CAAUjC,GAAY,CAAE,IAAA,CAAM0B,GAAY,OAAA,CAASM,EAAc,CAAC,CAAA,CAExEE,EAAAA,CAAQD","file":"index.js","sourcesContent":["const SESSION_KEY = 'rush_rum_sid'\nconst SESSION_TS_KEY = 'rush_rum_sts'\nconst SESSION_SAMPLED_KEY = 'rush_rum_smp'\nconst TIMEOUT_MS = 30 * 60 * 1000 // 30 minutes\n\nfunction generateId(): string {\n if (typeof crypto !== 'undefined' && crypto.randomUUID) {\n return crypto.randomUUID()\n }\n return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {\n const r = (Math.random() * 16) | 0\n const v = c === 'x' ? r : (r & 0x3) | 0x8\n return v.toString(16)\n })\n}\n\nexport function getSessionId(): string {\n try {\n const stored = sessionStorage.getItem(SESSION_KEY)\n const ts = sessionStorage.getItem(SESSION_TS_KEY)\n const now = Date.now()\n\n if (stored && ts && now - Number(ts) < TIMEOUT_MS) {\n sessionStorage.setItem(SESSION_TS_KEY, String(now))\n return stored\n }\n\n const id = generateId()\n sessionStorage.setItem(SESSION_KEY, id)\n sessionStorage.setItem(SESSION_TS_KEY, String(now))\n // New logical session → re-decide sampling next time it's asked.\n sessionStorage.removeItem(SESSION_SAMPLED_KEY)\n return id\n } catch {\n // sessionStorage not available (e.g. incognito overflow)\n return generateId()\n }\n}\n\n/**\n * Decide whether THIS session is sampled — once per session, cached so every\n * event in the session shares the same decision. Returns true if it should be\n * recorded. Cleared whenever a new session id is minted (see getSessionId).\n */\nexport function isSessionSampled(sampleRate: number): boolean {\n if (sampleRate >= 1) return true\n if (sampleRate <= 0) return false\n try {\n // Ensure a session id exists first, so a fresh session clears any stale flag.\n getSessionId()\n const stored = sessionStorage.getItem(SESSION_SAMPLED_KEY)\n if (stored !== null) return stored === '1'\n const sampled = Math.random() < sampleRate\n sessionStorage.setItem(SESSION_SAMPLED_KEY, sampled ? '1' : '0')\n return sampled\n } catch {\n // No sessionStorage → fall back to a per-load decision.\n return Math.random() < sampleRate\n }\n}\n\nexport function touchSession(): void {\n try {\n sessionStorage.setItem(SESSION_TS_KEY, String(Date.now()))\n } catch { /* ignore */ }\n}\n","export interface BrowserInfo {\n browserName: string\n browserVersion: string\n osName: string\n osVersion: string\n deviceType: 'desktop' | 'mobile' | 'tablet'\n screenWidth: number\n screenHeight: number\n}\n\nexport function detectBrowser(): BrowserInfo {\n const ua = navigator.userAgent\n\n let browserName = 'Unknown'\n let browserVersion = ''\n\n if (ua.includes('Firefox/')) {\n browserName = 'Firefox'\n browserVersion = ua.split('Firefox/')[1]?.split(' ')[0] ?? ''\n } else if (ua.includes('Edg/')) {\n browserName = 'Edge'\n browserVersion = ua.split('Edg/')[1]?.split(' ')[0] ?? ''\n } else if (ua.includes('Chrome/')) {\n browserName = 'Chrome'\n browserVersion = ua.split('Chrome/')[1]?.split(' ')[0] ?? ''\n } else if (ua.includes('Safari/') && !ua.includes('Chrome')) {\n browserName = 'Safari'\n browserVersion = ua.split('Version/')[1]?.split(' ')[0] ?? ''\n }\n\n let osName = 'Unknown'\n let osVersion = ''\n // Order matters: Android UAs contain \"Linux\" and iOS UAs contain \"Mac OS X\",\n // so the mobile OSes must be checked BEFORE Linux/macOS.\n if (ua.includes('Windows')) {\n osName = 'Windows'\n const m = ua.match(/Windows NT (\\d+\\.\\d+)/)\n osVersion = m?.[1] ?? ''\n } else if (ua.includes('Android')) {\n osName = 'Android'\n const m = ua.match(/Android (\\d+(\\.\\d+)?)/)\n osVersion = m?.[1] ?? ''\n } else if (/iPhone|iPad|iPod/.test(ua)) {\n osName = 'iOS'\n const m = ua.match(/OS (\\d+_\\d+)/)\n osVersion = m?.[1]?.replace('_', '.') ?? ''\n } else if (ua.includes('Mac OS X')) {\n osName = 'macOS'\n const m = ua.match(/Mac OS X (\\d+[._]\\d+[._]?\\d*)/)\n osVersion = m?.[1]?.replace(/_/g, '.') ?? ''\n } else if (ua.includes('Linux')) {\n osName = 'Linux'\n }\n\n let deviceType: 'desktop' | 'mobile' | 'tablet' = 'desktop'\n if (/Mobi|Android.*Mobile/.test(ua)) {\n deviceType = 'mobile'\n } else if (/iPad|Android(?!.*Mobile)|Tablet/.test(ua)) {\n deviceType = 'tablet'\n }\n\n return {\n browserName,\n browserVersion,\n osName,\n osVersion,\n deviceType,\n screenWidth: window.screen.width,\n screenHeight: window.screen.height,\n }\n}\n","/**\n * Best-effort transport for RUM batches. Wraps the bare fetch with:\n * - retry + exponential backoff + jitter on network errors / 429 / 5xx,\n * - an offline buffer persisted to localStorage (drained on init + `online`),\n * - optional gzip compression (off by default).\n *\n * Everything here is fire-and-forget: it never throws into the host app and\n * never blocks the main thread. The unload/beacon path lives in core.ts and\n * does NOT go through here (sendBeacon can't retry/compress).\n */\n\nconst BUFFER_KEY = 'rush_rum_buf_v1' // versioned so a format change can't crash older readers\nconst MAX_BUFFER_BYTES = 1_000_000 // ~1 MB cap across all persisted batches\nconst MAX_BUFFER_BATCHES = 50\nconst MAX_RETRIES = 3\nconst BASE_BACKOFF_MS = 1_000\n\ninterface PersistedBatch {\n /** Endpoint the batch was destined for. */\n url: string\n /** Already-serialized JSON payload. */\n body: string\n /** When it was first buffered (ms epoch), for oldest-first drain. */\n ts: number\n}\n\nfunction isOnline(): boolean {\n return typeof navigator === 'undefined' || navigator.onLine !== false\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms))\n}\n\n/** Backoff with full jitter: random in [0, base * 2^attempt]. */\nfunction backoffDelay(attempt: number): number {\n const ceiling = BASE_BACKOFF_MS * Math.pow(2, attempt)\n return Math.random() * ceiling\n}\n\n// ---- localStorage offline buffer -----------------------------------------\n\nfunction readBuffer(): PersistedBatch[] {\n try {\n const raw = localStorage.getItem(BUFFER_KEY)\n if (!raw) return []\n const parsed = JSON.parse(raw)\n return Array.isArray(parsed) ? (parsed as PersistedBatch[]) : []\n } catch {\n return []\n }\n}\n\nfunction writeBuffer(batches: PersistedBatch[]): void {\n try {\n if (batches.length === 0) {\n localStorage.removeItem(BUFFER_KEY)\n return\n }\n localStorage.setItem(BUFFER_KEY, JSON.stringify(batches))\n } catch {\n /* storage full / unavailable — best-effort */\n }\n}\n\n/** Append a batch, dropping the oldest until under the byte + count caps. */\nfunction persistBatch(url: string, body: string): void {\n try {\n const batches = readBuffer()\n batches.push({ url, body, ts: Date.now() })\n // Enforce count cap first (cheap), then byte cap.\n while (batches.length > MAX_BUFFER_BATCHES) batches.shift()\n let total = batches.reduce((n, b) => n + b.body.length, 0)\n while (batches.length > 1 && total > MAX_BUFFER_BYTES) {\n const dropped = batches.shift()!\n total -= dropped.body.length\n }\n writeBuffer(batches)\n } catch {\n /* best-effort */\n }\n}\n\n// ---- compression ----------------------------------------------------------\n\nfunction canCompress(): boolean {\n return typeof CompressionStream !== 'undefined' && typeof Response !== 'undefined'\n}\n\nasync function gzip(body: string): Promise<Blob> {\n const stream = new Blob([body]).stream().pipeThrough(new CompressionStream('gzip'))\n const buf = await new Response(stream).arrayBuffer()\n return new Blob([buf])\n}\n\n// ---- send ------------------------------------------------------------------\n\n/**\n * Send a body once. Resolves true on a 2xx/3xx response, false on a\n * retryable failure (network error, 429, 5xx) so the caller can retry/buffer.\n * Non-retryable 4xx (other than 429) resolve true so we don't loop forever on a\n * permanently-rejected payload.\n */\nasync function sendOnce(url: string, body: string, compress: boolean): Promise<boolean> {\n try {\n const headers: Record<string, string> = { 'Content-Type': 'application/json' }\n let payload: BodyInit = body\n if (compress && canCompress()) {\n try {\n payload = await gzip(body)\n headers['Content-Encoding'] = 'gzip'\n } catch {\n payload = body // compression failed — fall back to plain JSON\n }\n }\n const res = await fetch(url, { method: 'POST', headers, body: payload, keepalive: true })\n if (res.status === 429 || res.status >= 500) return false\n return true\n } catch {\n return false // network error → retryable\n }\n}\n\n/**\n * Send a batch with retry/backoff. If it still fails (or we're offline), the\n * batch is persisted to the offline buffer for a later drain. Never throws.\n */\nexport async function sendBatch(url: string, body: string, compress: boolean): Promise<void> {\n if (!isOnline()) {\n persistBatch(url, body)\n return\n }\n for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {\n const ok = await sendOnce(url, body, compress)\n if (ok) return\n if (attempt < MAX_RETRIES) await sleep(backoffDelay(attempt))\n }\n // Exhausted retries — stash for later.\n persistBatch(url, body)\n}\n\n/**\n * Drain persisted batches oldest-first. Re-buffers any that still fail. Called\n * on init() and whenever the `online` event fires. Replayed batches are sent\n * uncompressed-by-default unless the caller asks to compress (we keep it simple\n * and never compress drains, since the bodies are already small JSON).\n */\nexport async function drainBuffer(): Promise<void> {\n if (!isOnline()) return\n let batches = readBuffer()\n if (batches.length === 0) return\n // Take a snapshot and clear storage so new live batches don't interleave;\n // anything that fails gets re-persisted below.\n writeBuffer([])\n batches = batches.sort((a, b) => a.ts - b.ts)\n for (const batch of batches) {\n if (!isOnline()) {\n persistBatch(batch.url, batch.body)\n continue\n }\n const ok = await sendOnce(batch.url, batch.body, false)\n if (!ok) persistBatch(batch.url, batch.body)\n }\n}\n","import type { RumEvent, RumMeta, RumPayload, RushRUMConfig } from './types'\nimport { getSessionId, isSessionSampled } from './session'\nimport { detectBrowser } from './browser'\nimport { sendBatch, drainBuffer } from './transport'\n\nconst MAX_BATCH = 30\nconst FLUSH_INTERVAL_MS = 250\n// Cap the in-memory queue so a flush outage (offline / failing backend) can't\n// grow it without bound; drop oldest on overflow.\nconst MAX_QUEUE = 1000\n\nlet config: RushRUMConfig | null = null\nlet queue: RumEvent[] = []\nlet flushTimer: ReturnType<typeof setInterval> | null = null\nlet browserInfo: ReturnType<typeof detectBrowser> | null = null\nlet sampledIn = true\nlet initialized = false\n\n// Dynamic user override (set via RushRUM.setUser) — takes precedence over the\n// config.user callback when set. undefined = not overridden; null = cleared.\nlet userOverride: { id?: string } | null | undefined = undefined\n// Global attributes merged into every event's `attributes` JSON.\nlet globalAttributes: Record<string, unknown> = {}\n\n// Listener refs kept so destroy() can detach them.\nlet onVisibility: (() => void) | null = null\nlet onPageHide: (() => void) | null = null\nlet onOnline: (() => void) | null = null\n\nexport function configure(cfg: RushRUMConfig): void {\n // Idempotent: a second init() is a no-op, so we never start duplicate timers,\n // handlers, or (via the trackers) double-wrap fetch/XHR/history.\n if (initialized) return\n config = cfg\n browserInfo = detectBrowser()\n // Sampling is decided ONCE per session and applied to every event.\n sampledIn = isSessionSampled(cfg.sampleRate ?? 1)\n initialized = true\n startFlushTimer()\n setupBeaconFlush()\n setupOnlineDrain()\n // Drain anything buffered offline on a previous load (oldest first).\n void drainBuffer()\n}\n\n/** Set/override the current user id; reflected in meta.user_id. null clears it. */\nexport function setUserOverride(user: { id?: string } | null): void {\n userOverride = user\n}\n\nexport function setGlobalAttrs(attrs: Record<string, unknown>): void {\n globalAttributes = { ...globalAttributes, ...attrs }\n}\n\nexport function clearGlobalAttrs(): void {\n globalAttributes = {}\n}\n\n/**\n * Merge global attributes into an event's `attributes` JSON. Event-specific keys\n * win over globals. No-op when there are no globals. Parse failures fall back to\n * keeping the event's original attributes untouched.\n */\nfunction applyGlobalAttributes(event: RumEvent): void {\n const keys = Object.keys(globalAttributes)\n if (keys.length === 0) return\n let existing: Record<string, unknown> = {}\n if (event.attributes) {\n try {\n const parsed = JSON.parse(event.attributes)\n if (parsed && typeof parsed === 'object') existing = parsed as Record<string, unknown>\n } catch {\n return // unparseable existing attributes — leave them as-is\n }\n }\n event.attributes = JSON.stringify({ ...globalAttributes, ...existing })\n}\n\nexport function getConfig(): RushRUMConfig | null {\n return config\n}\n\nexport function isInitialized(): boolean {\n return initialized\n}\n\n/** Strip query string + hash from a URL unless the caller opted in via config. */\nexport function sanitizeUrl(url: string): string {\n if (config?.captureQueryParams) return url\n let end = url.length\n const q = url.indexOf('?')\n const h = url.indexOf('#')\n if (q !== -1) end = Math.min(end, q)\n if (h !== -1) end = Math.min(end, h)\n return url.slice(0, end)\n}\n\n/**\n * High-resolution wall-clock time in nanoseconds (backend stores i64 ns).\n * timeOrigin + now() captures sub-millisecond ordering; the float quantizes at\n * ~256ns at this magnitude, which is far finer than RUM needs.\n */\nfunction nowNs(): number {\n const ms =\n typeof performance !== 'undefined' && performance.timeOrigin\n ? performance.timeOrigin + performance.now()\n : Date.now()\n return Math.round(ms * 1_000_000)\n}\n\nexport function pushEvent(event: RumEvent): void {\n if (!config || !sampledIn) return\n event.timestamp = event.timestamp ?? nowNs()\n\n // beforeSend may mutate or drop the event. A throwing hook must never break\n // collection, so swallow errors and keep the (un-hooked) event.\n if (config.beforeSend) {\n try {\n const result = config.beforeSend(event)\n if (result === null) return // explicitly dropped\n event = result ?? event\n } catch {\n /* ignore a misbehaving beforeSend */\n }\n }\n\n // Merge global attributes (event-specific keys win) into the stringified JSON.\n applyGlobalAttributes(event)\n\n queue.push(event)\n // Cap the queue: drop oldest first so the newest signal survives a backlog.\n if (queue.length > MAX_QUEUE) queue.splice(0, queue.length - MAX_QUEUE)\n if (queue.length >= MAX_BATCH) flush()\n}\n\nfunction buildMeta(): RumMeta {\n const cfg = config!\n const bi = browserInfo!\n let userId = ''\n // setUser() override (when set) wins over the config.user callback.\n if (userOverride !== undefined) {\n userId = userOverride?.id ?? ''\n } else {\n try {\n const u = cfg.user?.()\n userId = u?.id ?? ''\n } catch {\n /* ignore */\n }\n }\n\n return {\n app_name: cfg.app.name,\n app_version: cfg.app.version ?? '',\n environment: cfg.environment ?? '',\n session_id: getSessionId(),\n user_id: userId,\n page_url: sanitizeUrl(location.href),\n page_path: location.pathname,\n view_name: document.title,\n referrer: sanitizeUrl(document.referrer),\n browser_name: bi.browserName,\n browser_version: bi.browserVersion,\n os_name: bi.osName,\n os_version: bi.osVersion,\n device_type: bi.deviceType,\n screen_width: bi.screenWidth,\n screen_height: bi.screenHeight,\n }\n}\n\nexport function flush(): void {\n if (!config || queue.length === 0) return\n const endpoint = config.endpoint\n const compress = config.compress === true\n // Drain in batches so a burst doesn't leave a remainder waiting for the timer.\n while (queue.length > 0) {\n const events = queue.splice(0, MAX_BATCH)\n const payload: RumPayload = { meta: buildMeta(), events }\n const body = JSON.stringify(payload)\n // Transport handles retry/backoff + offline buffering; fire-and-forget.\n void sendBatch(endpoint, body, compress)\n }\n}\n\nfunction startFlushTimer(): void {\n if (flushTimer) return\n flushTimer = setInterval(() => {\n if (queue.length > 0) flush()\n }, FLUSH_INTERVAL_MS)\n}\n\nfunction setupBeaconFlush(): void {\n if (typeof document === 'undefined') return\n\n const beaconFlush = () => {\n if (!config || queue.length === 0) return\n const events = queue.splice(0)\n const payload: RumPayload = { meta: buildMeta(), events }\n const body = JSON.stringify(payload)\n\n if (navigator.sendBeacon) {\n navigator.sendBeacon(config.endpoint, body)\n } else {\n // Sync XHR as last resort (not recommended but works for unload).\n try {\n const xhr = new XMLHttpRequest()\n xhr.open('POST', config.endpoint, false)\n xhr.setRequestHeader('Content-Type', 'application/json')\n xhr.send(body)\n } catch {\n /* ignore */\n }\n }\n }\n\n onVisibility = () => {\n if (document.visibilityState === 'hidden') beaconFlush()\n }\n onPageHide = beaconFlush\n document.addEventListener('visibilitychange', onVisibility)\n window.addEventListener('pagehide', onPageHide)\n}\n\n/** Drain the offline buffer whenever connectivity is restored. */\nfunction setupOnlineDrain(): void {\n if (typeof window === 'undefined') return\n onOnline = () => {\n void drainBuffer()\n }\n window.addEventListener('online', onOnline)\n}\n\n/**\n * Stop collecting: flush the queue, clear the timer, and detach the unload\n * handlers. The fetch/XHR/history/click patches installed by the trackers stay\n * in place but become inert (pushEvent no-ops once config is null), so calling\n * init() again later is safe. Mainly for tests and SPA hot-reload.\n */\nexport function destroy(): void {\n flush()\n if (flushTimer) {\n clearInterval(flushTimer)\n flushTimer = null\n }\n if (typeof document !== 'undefined' && onVisibility) {\n document.removeEventListener('visibilitychange', onVisibility)\n }\n if (typeof window !== 'undefined' && onPageHide) {\n window.removeEventListener('pagehide', onPageHide)\n }\n if (typeof window !== 'undefined' && onOnline) {\n window.removeEventListener('online', onOnline)\n }\n onVisibility = null\n onPageHide = null\n onOnline = null\n queue = []\n config = null\n initialized = false\n userOverride = undefined\n globalAttributes = {}\n}\n","import { pushEvent } from './core'\n\nexport function initVitals(): void {\n // Dynamic import so the SDK works even if web-vitals isn't available\n import('web-vitals').then(({ onLCP, onCLS, onINP, onFCP, onTTFB }) => {\n const report = (name: string) => (metric: { value: number; rating: string }) => {\n pushEvent({\n event_type: 'web_vital',\n vital_name: name,\n vital_value: metric.value,\n vital_rating: metric.rating,\n })\n }\n\n onLCP(report('LCP'))\n onCLS(report('CLS'))\n onINP(report('INP'))\n onFCP(report('FCP'))\n onTTFB(report('TTFB'))\n }).catch(() => {\n // web-vitals not available — skip\n })\n}\n","/**\n * Tiny shared module for the \"error click\" frustration signal. interactions.ts\n * records the last click here; errors.ts reads it when a JS error fires. Living\n * in its own module avoids a circular import between those two files.\n */\n\nexport interface LastClick {\n /** A descriptor of the clicked element (same format as interaction events). */\n target: string\n /** Click time, ms via performance.now() / Date.now() fallback. */\n ts: number\n}\n\nlet lastClick: LastClick | null = null\n\nfunction now(): number {\n return typeof performance !== 'undefined' && performance.now ? performance.now() : Date.now()\n}\n\nexport function recordClick(target: string): void {\n lastClick = { target, ts: now() }\n}\n\nexport function getLastClick(): LastClick | null {\n return lastClick\n}\n\nexport function clearLastClick(): void {\n lastClick = null\n}\n","import { pushEvent } from './core'\nimport { getLastClick } from './frustration'\n\n// Error click: a JS error within this window of the last click is treated as a\n// frustration signal (the click likely triggered the error).\nconst ERROR_CLICK_WINDOW_MS = 1_000\n\nlet bound = false\nlet onError: ((event: ErrorEvent) => void) | null = null\nlet onRejection: ((event: PromiseRejectionEvent) => void) | null = null\n\n/** Emit an error_click frustration event if a recent click preceded this error. */\nfunction maybeEmitErrorClick(): void {\n const last = getLastClick()\n if (!last) return\n const now =\n typeof performance !== 'undefined' && performance.now ? performance.now() : Date.now()\n if (now - last.ts < ERROR_CLICK_WINDOW_MS) {\n pushEvent({\n event_type: 'frustration',\n interaction_type: 'error_click',\n interaction_target: last.target,\n })\n }\n}\n\nexport function initErrors(): void {\n if (bound) return // single set of error listeners per init\n bound = true\n\n onError = (event: ErrorEvent): void => {\n maybeEmitErrorClick()\n pushEvent({\n event_type: 'error',\n error_message: event.message || 'Unknown error',\n error_stack: event.error?.stack ?? '',\n error_type: event.error?.name ?? 'Error',\n })\n }\n\n onRejection = (event: PromiseRejectionEvent): void => {\n const reason = event.reason\n let message = 'Unhandled promise rejection'\n let stack = ''\n let errorType = 'UnhandledRejection'\n\n if (reason instanceof Error) {\n message = reason.message\n stack = reason.stack ?? ''\n errorType = reason.name\n } else if (typeof reason === 'string') {\n message = reason\n }\n\n pushEvent({\n event_type: 'error',\n error_message: message,\n error_stack: stack,\n error_type: errorType,\n })\n }\n\n window.addEventListener('error', onError)\n window.addEventListener('unhandledrejection', onRejection)\n}\n\n/** Detach the error/rejection listeners. */\nexport function destroyErrors(): void {\n if (onError) {\n window.removeEventListener('error', onError)\n onError = null\n }\n if (onRejection) {\n window.removeEventListener('unhandledrejection', onRejection)\n onRejection = null\n }\n bound = false\n}\n","import { pushEvent } from './core'\n\nlet patched = false\n\nexport function initPageViews(): void {\n // Track initial page load\n trackPageView()\n\n if (patched) return // don't re-wrap history on a repeat init\n patched = true\n\n // SPA navigation: history.pushState / replaceState\n const origPush = history.pushState.bind(history)\n const origReplace = history.replaceState.bind(history)\n\n history.pushState = function (...args: Parameters<typeof origPush>) {\n origPush(...args)\n trackPageView()\n }\n\n history.replaceState = function (...args: Parameters<typeof origReplace>) {\n origReplace(...args)\n trackPageView()\n }\n\n // Back/forward navigation\n window.addEventListener('popstate', () => {\n trackPageView()\n })\n}\n\nfunction generateTraceId(): string {\n const bytes = new Uint8Array(16)\n crypto.getRandomValues(bytes)\n return Array.from(bytes).map((b) => b.toString(16).padStart(2, '0')).join('')\n}\n\nfunction generateSpanId(): string {\n const bytes = new Uint8Array(8)\n crypto.getRandomValues(bytes)\n return Array.from(bytes).map((b) => b.toString(16).padStart(2, '0')).join('')\n}\n\nfunction trackPageView(): void {\n const traceId = generateTraceId()\n const spanId = generateSpanId()\n\n pushEvent({\n event_type: 'pageview',\n event_name: document.title,\n duration_ms: getNavigationLoadTime(),\n trace_id: traceId,\n span_id: spanId,\n })\n}\n\nfunction getNavigationLoadTime(): number {\n if (typeof performance === 'undefined') return 0\n const entries = performance.getEntriesByType('navigation') as PerformanceNavigationTiming[]\n if (entries.length > 0) {\n return entries[0].loadEventEnd - entries[0].startTime\n }\n return 0\n}\n","import { pushEvent, getConfig } from './core'\nimport { recordClick } from './frustration'\n\nconst INTERACTIVE_SELECTORS = 'button, a, [role=\"button\"], input[type=\"submit\"], input[type=\"button\"]'\n\n// Rage click: >3 clicks on the SAME element within this sliding window.\nconst RAGE_WINDOW_MS = 1_000\nconst RAGE_THRESHOLD = 3\n// Dead click: a click on an interactive element that causes no page change\n// within this window (no DOM mutation, URL change, or scroll).\nconst DEAD_WINDOW_MS = 3_000\n\nlet bound = false\nlet clickListener: ((event: MouseEvent) => void) | null = null\n\n// Rage-click sliding window per element.\nlet rageTarget: Element | null = null\nlet rageTimes: number[] = []\n\n// Active dead-click watchers we may need to clean up on destroy().\ninterface DeadWatcher {\n observer: MutationObserver\n timer: ReturnType<typeof setTimeout>\n onScroll: () => void\n}\nlet deadWatchers: DeadWatcher[] = []\n\n/** Build the same target descriptor used for click interaction events. */\nfunction describeTarget(el: Element): string {\n const tag = el.tagName.toLowerCase()\n const id = el.id ? `#${el.id}` : ''\n const classes = el.className\n ? `.${Array.from(el.classList).slice(0, 3).join('.')}`\n : ''\n // Element text can carry PII (names, amounts) — omit it when masked.\n const text = getConfig()?.maskInteractionText\n ? ''\n : (el.textContent ?? '').trim().slice(0, 100)\n return `${tag}${id}${classes}${text ? ` \"${text}\"` : ''}`\n}\n\n/** Detect a rage click; emits one frustration event when the threshold trips. */\nfunction detectRageClick(el: Element, target: string): void {\n const now = Date.now()\n if (rageTarget !== el) {\n rageTarget = el\n rageTimes = []\n }\n rageTimes.push(now)\n // Keep only clicks within the sliding window.\n rageTimes = rageTimes.filter((t) => now - t <= RAGE_WINDOW_MS)\n if (rageTimes.length > RAGE_THRESHOLD) {\n pushEvent({\n event_type: 'frustration',\n interaction_type: 'rage_click',\n interaction_target: target,\n })\n // Reset so we emit at most once per burst.\n rageTimes = []\n rageTarget = null\n }\n}\n\n/**\n * Detect a dead click: watch for ANY DOM mutation, URL change, or scroll within\n * a short window after the click. If none happens, the click did nothing →\n * emit a dead_click frustration event. Conservative on purpose to avoid false\n * positives. The MutationObserver is one-shot and always disconnected.\n */\nfunction detectDeadClick(target: string): void {\n let changed = false\n const startUrl = location.href\n\n const observer = new MutationObserver(() => {\n changed = true\n })\n try {\n observer.observe(document.documentElement, {\n childList: true,\n subtree: true,\n attributes: true,\n characterData: true,\n })\n } catch {\n return\n }\n\n const onScroll = () => {\n changed = true\n }\n window.addEventListener('scroll', onScroll, { passive: true, capture: true })\n\n const timer = setTimeout(() => {\n cleanup()\n const navigated = location.href !== startUrl\n if (!changed && !navigated) {\n pushEvent({\n event_type: 'frustration',\n interaction_type: 'dead_click',\n interaction_target: target,\n })\n }\n }, DEAD_WINDOW_MS)\n\n const watcher: DeadWatcher = { observer, timer, onScroll }\n deadWatchers.push(watcher)\n\n function cleanup(): void {\n observer.disconnect()\n clearTimeout(timer)\n window.removeEventListener('scroll', onScroll, { capture: true } as EventListenerOptions)\n deadWatchers = deadWatchers.filter((w) => w !== watcher)\n }\n}\n\nexport function initInteractions(): void {\n if (bound) return // single global click listener\n bound = true\n\n clickListener = (event: MouseEvent): void => {\n const target = event.target as Element | null\n if (!target) return\n\n const interactive = target.closest(INTERACTIVE_SELECTORS)\n if (!interactive) return\n\n const descriptor = describeTarget(interactive)\n\n // Record for the error-click signal (errors.ts reads this).\n recordClick(descriptor)\n\n pushEvent({\n event_type: 'interaction',\n interaction_type: 'click',\n interaction_target: descriptor,\n })\n\n detectRageClick(interactive, descriptor)\n detectDeadClick(descriptor)\n }\n\n document.addEventListener('click', clickListener, { capture: true, passive: true })\n}\n\n/** Detach the click listener and tear down any in-flight dead-click watchers. */\nexport function destroyInteractions(): void {\n if (clickListener) {\n document.removeEventListener('click', clickListener, { capture: true } as EventListenerOptions)\n clickListener = null\n }\n for (const w of deadWatchers) {\n w.observer.disconnect()\n clearTimeout(w.timer)\n window.removeEventListener('scroll', w.onScroll, { capture: true } as EventListenerOptions)\n }\n deadWatchers = []\n rageTarget = null\n rageTimes = []\n bound = false\n}\n","import { pushEvent, getConfig, sanitizeUrl } from './core'\n\nlet patched = false\n\nexport function initResources(): void {\n if (patched) return // never double-wrap fetch/XHR\n patched = true\n patchFetch()\n patchXHR()\n}\n\nfunction shouldTraceOrigin(url: string): boolean {\n const cfg = getConfig()\n if (!cfg?.propagateTraces?.origins) return false\n return cfg.propagateTraces.origins.some((re) => re.test(url))\n}\n\nfunction generateTraceId(): string {\n const bytes = new Uint8Array(16)\n crypto.getRandomValues(bytes)\n return Array.from(bytes).map((b) => b.toString(16).padStart(2, '0')).join('')\n}\n\nfunction generateSpanId(): string {\n const bytes = new Uint8Array(8)\n crypto.getRandomValues(bytes)\n return Array.from(bytes).map((b) => b.toString(16).padStart(2, '0')).join('')\n}\n\nfunction patchFetch(): void {\n const origFetch = window.fetch.bind(window)\n\n window.fetch = async function (input: RequestInfo | URL, init?: RequestInit): Promise<Response> {\n const url = typeof input === 'string' ? input : input instanceof URL ? input.href : input.url\n const start = performance.now()\n\n let traceId = ''\n let spanId = ''\n\n if (shouldTraceOrigin(url)) {\n traceId = generateTraceId()\n spanId = generateSpanId()\n const headers = new Headers(init?.headers)\n headers.set('traceparent', `00-${traceId}-${spanId}-01`)\n init = { ...init, headers }\n }\n\n try {\n const response = await origFetch(input, init)\n const durationMs = performance.now() - start\n\n pushEvent({\n event_type: 'resource',\n event_name: sanitizeUrl(url),\n duration_ms: durationMs,\n trace_id: traceId,\n span_id: spanId,\n attributes: JSON.stringify({ status: response.status, method: init?.method ?? 'GET' }),\n })\n\n return response\n } catch (err) {\n const durationMs = performance.now() - start\n pushEvent({\n event_type: 'resource',\n event_name: sanitizeUrl(url),\n duration_ms: durationMs,\n trace_id: traceId,\n span_id: spanId,\n error_message: err instanceof Error ? err.message : 'fetch failed',\n error_type: 'NetworkError',\n })\n throw err\n }\n }\n}\n\nfunction patchXHR(): void {\n const origOpen = XMLHttpRequest.prototype.open\n const origSend = XMLHttpRequest.prototype.send\n\n XMLHttpRequest.prototype.open = function (method: string, url: string | URL, ...rest: any[]) {\n (this as any).__wide_url = typeof url === 'string' ? url : url.href;\n (this as any).__wide_method = method\n return origOpen.apply(this, [method, url, ...rest] as any)\n }\n\n XMLHttpRequest.prototype.send = function (body?: any) {\n const url: string = (this as any).__wide_url ?? ''\n const method: string = (this as any).__wide_method ?? 'GET'\n const start = performance.now()\n\n let traceId = ''\n let spanId = ''\n if (shouldTraceOrigin(url)) {\n traceId = generateTraceId()\n spanId = generateSpanId()\n this.setRequestHeader('traceparent', `00-${traceId}-${spanId}-01`)\n }\n\n this.addEventListener('loadend', () => {\n const durationMs = performance.now() - start\n pushEvent({\n event_type: 'resource',\n event_name: sanitizeUrl(url),\n duration_ms: durationMs,\n trace_id: traceId,\n span_id: spanId,\n attributes: JSON.stringify({ status: this.status, method }),\n })\n })\n\n return origSend.call(this, body)\n }\n}\n","/**\n * Long task + Long Animation Frame (LoAF) instrumentation via PerformanceObserver.\n * Lightweight and low-volume, so it's enabled by default. Both observers are\n * disconnected by destroy().\n */\nimport { pushEvent } from './core'\n\nlet started = false\nlet longTaskObserver: PerformanceObserver | null = null\nlet loafObserver: PerformanceObserver | null = null\n\nfunction supports(type: string): boolean {\n return (\n typeof PerformanceObserver !== 'undefined' &&\n Array.isArray(PerformanceObserver.supportedEntryTypes) &&\n PerformanceObserver.supportedEntryTypes.includes(type)\n )\n}\n\nexport function initPerformance(): void {\n if (started) return // single set of observers per init\n if (typeof PerformanceObserver === 'undefined') return\n started = true\n\n if (supports('longtask')) {\n try {\n longTaskObserver = new PerformanceObserver((list) => {\n for (const entry of list.getEntries()) {\n pushEvent({\n event_type: 'long_task',\n duration_ms: entry.duration,\n attributes: JSON.stringify({ start: entry.startTime, name: entry.name }),\n })\n }\n })\n longTaskObserver.observe({ type: 'longtask', buffered: true })\n } catch {\n longTaskObserver = null\n }\n }\n\n if (supports('long-animation-frame')) {\n try {\n loafObserver = new PerformanceObserver((list) => {\n for (const entry of list.getEntries()) {\n // LoAF entries carry blockingDuration + a scripts[] array; types aren't\n // in lib.dom yet, so read them defensively.\n const e = entry as PerformanceEntry & {\n blockingDuration?: number\n scripts?: unknown[]\n }\n pushEvent({\n event_type: 'loaf',\n duration_ms: e.duration,\n attributes: JSON.stringify({\n start: e.startTime,\n blockingDuration: e.blockingDuration ?? 0,\n scripts: (e.scripts || []).length,\n }),\n })\n }\n })\n loafObserver.observe({ type: 'long-animation-frame', buffered: true })\n } catch {\n loafObserver = null\n }\n }\n}\n\nexport function destroyPerformance(): void {\n if (longTaskObserver) {\n longTaskObserver.disconnect()\n longTaskObserver = null\n }\n if (loafObserver) {\n loafObserver.disconnect()\n loafObserver = null\n }\n started = false\n}\n","import type { RushRUMConfig } from './types'\nimport {\n configure,\n flush,\n pushEvent,\n destroy as destroyCore,\n isInitialized,\n setUserOverride,\n setGlobalAttrs,\n clearGlobalAttrs,\n} from './core'\nimport { initVitals } from './vitals'\nimport { initErrors, destroyErrors } from './errors'\nimport { initPageViews } from './pageview'\nimport { initInteractions, destroyInteractions } from './interactions'\nimport { initResources } from './resources'\nimport { initPerformance, destroyPerformance } from './perf'\n\n/**\n * Optional session-replay module, injected by the build entry. The full npm\n * build (index.ts) passes the rrweb-backed replay module; the lean CDN build\n * (global.ts) passes nothing — so replay.ts (and therefore rrweb) is never part\n * of that bundle's import graph, keeping the CDN file small.\n */\nexport interface ReplayModule {\n init: (config: RushRUMConfig) => void\n destroy: () => void\n}\n\n/**\n * Build the RushRUM API object. Replay is injected (or omitted) so the same\n * core can ship as a full npm package or a lean replay-less CDN bundle.\n */\nexport function makeRushRUM(replay?: ReplayModule) {\n return {\n init(config: RushRUMConfig): void {\n // No-op outside the browser (SSR / Node) so importing + init in a universal\n // app (Next.js, etc.) doesn't throw on window/navigator/history access.\n if (typeof window === 'undefined') return\n // Guard against double init() — prevents duplicate subscriptions/timers.\n if (isInitialized()) {\n console.warn('[RushRUM] init() called more than once; ignoring.')\n return\n }\n\n configure(config)\n\n if (config.trackWebVitals !== false) initVitals()\n if (config.trackErrors !== false) initErrors()\n if (config.trackPageViews !== false) initPageViews()\n if (config.trackLongTasks !== false) initPerformance()\n if (config.trackInteractions === true) initInteractions()\n if (config.trackResources === true) initResources()\n if (config.trackSessionReplay === true) {\n if (replay) {\n replay.init(config)\n } else {\n console.warn('[RushRUM] session replay is not available in this build; use the npm package (@rushobservability/rum-sdk).')\n }\n }\n },\n\n /** Send a custom event. */\n trackEvent(name: string, attributes?: Record<string, unknown>): void {\n pushEvent({\n event_type: 'custom',\n event_name: name,\n attributes: attributes ? JSON.stringify(attributes) : undefined,\n })\n },\n\n /**\n * Set or override the current user id; reflected in meta.user_id on\n * subsequent events. Overrides the config.user callback. Pass null to clear.\n */\n setUser(user: { id?: string } | null): void {\n setUserOverride(user)\n },\n\n /**\n * Merge attributes into every subsequent event's `attributes` JSON.\n * Event-specific keys win over global ones.\n */\n setGlobalAttributes(attrs: Record<string, unknown>): void {\n setGlobalAttrs(attrs)\n },\n\n /** Clear all global attributes set via setGlobalAttributes. */\n clearGlobalAttributes(): void {\n clearGlobalAttrs()\n },\n\n /** Force flush the event queue. */\n flush,\n\n /**\n * Stop collecting and detach handlers/timers. Safe to call before a later\n * init() (tests, SPA hot-reload). Tears down every instrumentation.\n */\n destroy(): void {\n // Tear down instrumentation first (they call pushEvent → core), then core.\n destroyPerformance()\n destroyInteractions()\n destroyErrors()\n if (replay) replay.destroy()\n destroyCore()\n },\n }\n}\n","/**\n * Session replay recorder — captures rrweb DOM snapshots and mutation events\n * and streams them in chunks to the Rush replay ingest endpoint.\n *\n * Must be called only after `configure()` (i.e. inside `RushRUM.init`).\n *\n * Privacy is on by default: unless config.replayPrivacy is set to something\n * looser, all inputs AND all text are masked and media is blocked.\n */\nimport type { RushRUMConfig } from './types'\nimport { getSessionId } from './session'\n\nconst CHUNK_SIZE = 50 // flush after this many events\nconst FLUSH_INTERVAL_MS = 5_000 // flush every 5 s regardless\n\n// Always-on PII mask + the media elements blocked at the strictest level.\nconst PII_SELECTOR = '[data-pii]'\nconst MEDIA_BLOCK_SELECTOR = 'img,video,audio,picture,source,canvas'\n\nlet started = false\nlet _config: RushRUMConfig | null = null\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nlet _buffer: any[] = []\nlet _chunkIdx = 0\nlet _flushTimer: ReturnType<typeof setInterval> | null = null\n// rrweb's record() returns a stop function; captured so destroy() can call it.\nlet _stopRecording: (() => void) | null = null\n\nlet _onVisibility: (() => void) | null = null\nlet _onPageHide: (() => void) | null = null\n\nfunction replayEndpoint(): string {\n const cfg = _config!\n if (cfg.replayEndpoint) return cfg.replayEndpoint\n // Derive from the event ingest endpoint: replace /rum/ingest with /rum/replay/ingest\n return cfg.endpoint.replace(/\\/rum\\/ingest$/, '/rum/replay/ingest')\n}\n\n/** Join non-empty CSS selectors into one comma-separated selector string. */\nfunction joinSelectors(...parts: Array<string | undefined>): string {\n return parts.filter((p): p is string => !!p && p.length > 0).join(',')\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction sendChunk(events: any[]): void {\n if (!_config || events.length === 0) return\n const payload = {\n session_id: getSessionId(),\n app_name: _config.app.name,\n chunk_idx: _chunkIdx++,\n events,\n }\n fetch(replayEndpoint(), {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(payload),\n keepalive: true,\n }).catch(() => { /* best-effort */ })\n}\n\nfunction flushBuffer(): void {\n if (_buffer.length === 0) return\n sendChunk(_buffer.splice(0))\n}\n\n/**\n * Map the privacy level + extra selectors to rrweb record() options.\n * - 'mask' (default): maskAllInputs + mask all text + block media.\n * - 'mask-user-input': maskAllInputs only.\n * - 'allow': no masking.\n * [data-pii] is always masked. replayUnmaskSelector overrides masking.\n */\nfunction buildRecordOptions(cfg: RushRUMConfig): {\n maskAllInputs: boolean\n maskTextSelector: string\n blockSelector: string\n} {\n const level = cfg.replayPrivacy ?? 'mask'\n\n let maskAllInputs = true\n let maskText = false\n let blockMedia = false\n if (level === 'mask') {\n maskAllInputs = true\n maskText = true\n blockMedia = true\n } else if (level === 'mask-user-input') {\n maskAllInputs = true\n maskText = false\n } else {\n // 'allow'\n maskAllInputs = false\n maskText = false\n }\n\n // Text masking: '*' masks everything; otherwise mask only PII + caller's\n // extra selector. The always-on [data-pii] is included regardless of level.\n const maskTextSelector = maskText\n ? '*'\n : joinSelectors(PII_SELECTOR, cfg.replayMaskSelector)\n\n const blockSelector = joinSelectors(\n blockMedia ? MEDIA_BLOCK_SELECTOR : undefined,\n cfg.replayBlockSelector,\n )\n\n return { maskAllInputs, maskTextSelector, blockSelector }\n}\n\nexport function initReplay(config: RushRUMConfig): void {\n if (started) return // idempotent: one recorder per init\n started = true\n _config = config\n\n const opts = buildRecordOptions(config)\n const unmask = config.replayUnmaskSelector\n\n // Dynamically import rrweb so it doesn't bloat pages that don't enable replay\n import('rrweb').then(({ record }) => {\n if (!started) return // destroyed before the import resolved\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const recordOptions: Record<string, any> = {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n emit(event: any) {\n // Let the caller scrub or drop replay events before buffering.\n if (config.replayBeforeAddEvent) {\n try {\n const result = config.replayBeforeAddEvent(event)\n if (result === null) return\n event = result ?? event\n } catch {\n /* ignore a misbehaving hook */\n }\n }\n _buffer.push(event)\n if (_buffer.length >= CHUNK_SIZE) flushBuffer()\n },\n maskAllInputs: opts.maskAllInputs,\n }\n if (opts.maskTextSelector) recordOptions.maskTextSelector = opts.maskTextSelector\n if (opts.blockSelector) recordOptions.blockSelector = opts.blockSelector\n // rrweb (alpha) has no native unmask selector. When text masking is on\n // (maskTextSelector === '*'), approximate unmask by returning original text\n // for nodes matching the unmask selector and masking everything else.\n if (unmask && opts.maskTextSelector === '*') {\n recordOptions.maskTextFn = (text: string, el: Element | null): string => {\n try {\n if (el && el.matches && el.matches(unmask)) return text\n } catch {\n /* invalid selector — fall through to masked */\n }\n return text.replace(/\\S/g, '*')\n }\n }\n\n const stop = record(recordOptions)\n _stopRecording = typeof stop === 'function' ? stop : null\n }).catch(() => {\n // rrweb not installed — replay silently disabled\n })\n\n _flushTimer = setInterval(flushBuffer, FLUSH_INTERVAL_MS)\n\n _onVisibility = () => {\n if (document.visibilityState === 'hidden') flushBuffer()\n }\n _onPageHide = flushBuffer\n document.addEventListener('visibilitychange', _onVisibility)\n window.addEventListener('pagehide', _onPageHide)\n}\n\n/** Stop the rrweb recorder, flush remaining events, and detach listeners/timers. */\nexport function destroyReplay(): void {\n if (_stopRecording) {\n try {\n _stopRecording()\n } catch {\n /* ignore */\n }\n _stopRecording = null\n }\n if (_flushTimer) {\n clearInterval(_flushTimer)\n _flushTimer = null\n }\n flushBuffer()\n if (typeof document !== 'undefined' && _onVisibility) {\n document.removeEventListener('visibilitychange', _onVisibility)\n }\n if (typeof window !== 'undefined' && _onPageHide) {\n window.removeEventListener('pagehide', _onPageHide)\n }\n _onVisibility = null\n _onPageHide = null\n _buffer = []\n _config = null\n started = false\n}\n","import { makeRushRUM } from './bootstrap'\nimport { initReplay, destroyReplay } from './replay'\n\nexport type { RushRUMConfig, RumEvent, RumPayload } from './types'\n\n// Full npm build: session replay (rrweb) is wired in. Bundler consumers pull\n// rrweb only when they enable trackSessionReplay (it's a dynamic import behind\n// an optionalDependency).\nexport const RushRUM = makeRushRUM({ init: initReplay, destroy: destroyReplay })\n\nexport default RushRUM\n"]}
@@ -0,0 +1,2 @@
1
+ var RushRUM=(function(){'use strict';var ht=Object.defineProperty;var yt=(e,t)=>()=>(e&&(t=e(e=0)),t);var wt=(e,t)=>{for(var n in t)ht(e,n,{get:t[n],enumerable:true});};var $e={};wt($e,{CLSThresholds:()=>se,FCPThresholds:()=>ie,FIDThresholds:()=>de,INPThresholds:()=>ae,LCPThresholds:()=>ce,TTFBThresholds:()=>ue,onCLS:()=>Mt,onFCP:()=>Ve,onFID:()=>Wt,onINP:()=>Ft,onLCP:()=>Nt,onTTFB:()=>Ht});var oe,v,M,De,X,He,h,le,G,f,_,p,fe,P,J,E,Ue,q,Fe,Lt,pe,A,ie,Ve,se,Mt,je,ne,j,Pt,We,At,g,W,Xe,Ot,Bt,Ut,qe,ae,Ft,ce,re,Nt,ue,Dt,Ht,L,Vt,Ne,Ge,jt,Je,de,Wt,ze=yt(()=>{He=-1,h=function(e){addEventListener("pageshow",(function(t){t.persisted&&(He=t.timeStamp,e(t));}),true);},le=function(){var e=self.performance&&performance.getEntriesByType&&performance.getEntriesByType("navigation")[0];if(e&&e.responseStart>0&&e.responseStart<performance.now())return e},G=function(){var e=le();return e&&e.activationStart||0},f=function(e,t){var n=le(),r="navigate";return He>=0?r="back-forward-cache":n&&(document.prerendering||G()>0?r="prerender":document.wasDiscarded?r="restore":n.type&&(r=n.type.replace(/_/g,"-"))),{name:e,value:t===void 0?-1:t,rating:"good",delta:0,entries:[],id:"v4-".concat(Date.now(),"-").concat(Math.floor(8999999999999*Math.random())+1e12),navigationType:r}},_=function(e,t,n){try{if(PerformanceObserver.supportedEntryTypes.includes(e)){var r=new PerformanceObserver((function(o){Promise.resolve().then((function(){t(o.getEntries());}));}));return r.observe(Object.assign({type:e,buffered:!0},n||{})),r}}catch{}},p=function(e,t,n,r){var o,i;return function(s){t.value>=0&&(s||r)&&((i=t.value-(o||0))||o===void 0)&&(o=t.value,t.delta=i,t.rating=(function(a,c){return a>c[1]?"poor":a>c[0]?"needs-improvement":"good"})(t.value,n),e(t));}},fe=function(e){requestAnimationFrame((function(){return requestAnimationFrame((function(){return e()}))}));},P=function(e){document.addEventListener("visibilitychange",(function(){document.visibilityState==="hidden"&&e();}));},J=function(e){var t=false;return function(){t||(e(),t=true);}},E=-1,Ue=function(){return document.visibilityState!=="hidden"||document.prerendering?1/0:0},q=function(e){document.visibilityState==="hidden"&&E>-1&&(E=e.type==="visibilitychange"?e.timeStamp:0,Lt());},Fe=function(){addEventListener("visibilitychange",q,true),addEventListener("prerenderingchange",q,true);},Lt=function(){removeEventListener("visibilitychange",q,true),removeEventListener("prerenderingchange",q,true);},pe=function(){return E<0&&(E=Ue(),Fe(),h((function(){setTimeout((function(){E=Ue(),Fe();}),0);}))),{get firstHiddenTime(){return E}}},A=function(e){document.prerendering?addEventListener("prerenderingchange",(function(){return e()}),true):e();},ie=[1800,3e3],Ve=function(e,t){t=t||{},A((function(){var n,r=pe(),o=f("FCP"),i=_("paint",(function(s){s.forEach((function(a){a.name==="first-contentful-paint"&&(i.disconnect(),a.startTime<r.firstHiddenTime&&(o.value=Math.max(a.startTime-G(),0),o.entries.push(a),n(true)));}));}));i&&(n=p(e,o,ie,t.reportAllChanges),h((function(s){o=f("FCP"),n=p(e,o,ie,t.reportAllChanges),fe((function(){o.value=performance.now()-s.timeStamp,n(true);}));})));}));},se=[.1,.25],Mt=function(e,t){t=t||{},Ve(J((function(){var n,r=f("CLS",0),o=0,i=[],s=function(c){c.forEach((function(m){if(!m.hadRecentInput){var gt=i[0],vt=i[i.length-1];o&&m.startTime-vt.startTime<1e3&&m.startTime-gt.startTime<5e3?(o+=m.value,i.push(m)):(o=m.value,i=[m]);}})),o>r.value&&(r.value=o,r.entries=i,n());},a=_("layout-shift",s);a&&(n=p(e,r,se,t.reportAllChanges),P((function(){s(a.takeRecords()),n(true);})),h((function(){o=0,r=f("CLS",0),n=p(e,r,se,t.reportAllChanges),fe((function(){return n()}));})),setTimeout(n,0));})));},je=0,ne=1/0,j=0,Pt=function(e){e.forEach((function(t){t.interactionId&&(ne=Math.min(ne,t.interactionId),j=Math.max(j,t.interactionId),je=j?(j-ne)/7+1:0);}));},We=function(){return oe?je:performance.interactionCount||0},At=function(){"interactionCount"in performance||oe||(oe=_("event",Pt,{type:"event",buffered:true,durationThreshold:0}));},g=[],W=new Map,Xe=0,Ot=function(){var e=Math.min(g.length-1,Math.floor((We()-Xe)/50));return g[e]},Bt=[],Ut=function(e){if(Bt.forEach((function(o){return o(e)})),e.interactionId||e.entryType==="first-input"){var t=g[g.length-1],n=W.get(e.interactionId);if(n||g.length<10||e.duration>t.latency){if(n)e.duration>n.latency?(n.entries=[e],n.latency=e.duration):e.duration===n.latency&&e.startTime===n.entries[0].startTime&&n.entries.push(e);else {var r={id:e.interactionId,latency:e.duration,entries:[e]};W.set(r.id,r),g.push(r);}g.sort((function(o,i){return i.latency-o.latency})),g.length>10&&g.splice(10).forEach((function(o){return W.delete(o.id)}));}}},qe=function(e){var t=self.requestIdleCallback||self.setTimeout,n=-1;return e=J(e),document.visibilityState==="hidden"?e():(n=t(e),P(e)),n},ae=[200,500],Ft=function(e,t){"PerformanceEventTiming"in self&&"interactionId"in PerformanceEventTiming.prototype&&(t=t||{},A((function(){var n;At();var r,o=f("INP"),i=function(a){qe((function(){a.forEach(Ut);var c=Ot();c&&c.latency!==o.value&&(o.value=c.latency,o.entries=c.entries,r());}));},s=_("event",i,{durationThreshold:(n=t.durationThreshold)!==null&&n!==void 0?n:40});r=p(e,o,ae,t.reportAllChanges),s&&(s.observe({type:"first-input",buffered:true}),P((function(){i(s.takeRecords()),r(true);})),h((function(){Xe=We(),g.length=0,W.clear(),o=f("INP"),r=p(e,o,ae,t.reportAllChanges);})));})));},ce=[2500,4e3],re={},Nt=function(e,t){t=t||{},A((function(){var n,r=pe(),o=f("LCP"),i=function(c){t.reportAllChanges||(c=c.slice(-1)),c.forEach((function(m){m.startTime<r.firstHiddenTime&&(o.value=Math.max(m.startTime-G(),0),o.entries=[m],n());}));},s=_("largest-contentful-paint",i);if(s){n=p(e,o,ce,t.reportAllChanges);var a=J((function(){re[o.id]||(i(s.takeRecords()),s.disconnect(),re[o.id]=true,n(true));}));["keydown","click"].forEach((function(c){addEventListener(c,(function(){return qe(a)}),{once:true,capture:true});})),P(a),h((function(c){o=f("LCP"),n=p(e,o,ce,t.reportAllChanges),fe((function(){o.value=performance.now()-c.timeStamp,re[o.id]=true,n(true);}));}));}}));},ue=[800,1800],Dt=function e(t){document.prerendering?A((function(){return e(t)})):document.readyState!=="complete"?addEventListener("load",(function(){return e(t)}),true):setTimeout(t,0);},Ht=function(e,t){t=t||{};var n=f("TTFB"),r=p(e,n,ue,t.reportAllChanges);Dt((function(){var o=le();o&&(n.value=Math.max(o.responseStart-G(),0),n.entries=[o],r(true),h((function(){n=f("TTFB",0),(r=p(e,n,ue,t.reportAllChanges))(true);})));}));},L={passive:true,capture:true},Vt=new Date,Ne=function(e,t){v||(v=t,M=e,De=new Date,Je(removeEventListener),Ge());},Ge=function(){if(M>=0&&M<De-Vt){var e={entryType:"first-input",name:v.type,target:v.target,cancelable:v.cancelable,startTime:v.timeStamp,processingStart:v.timeStamp+M};X.forEach((function(t){t(e);})),X=[];}},jt=function(e){if(e.cancelable){var t=(e.timeStamp>1e12?new Date:performance.now())-e.timeStamp;e.type=="pointerdown"?(function(n,r){var o=function(){Ne(n,r),s();},i=function(){s();},s=function(){removeEventListener("pointerup",o,L),removeEventListener("pointercancel",i,L);};addEventListener("pointerup",o,L),addEventListener("pointercancel",i,L);})(t,e):Ne(t,e);}},Je=function(e){["mousedown","keydown","touchstart","pointerdown"].forEach((function(t){return e(t,jt,L)}));},de=[100,300],Wt=function(e,t){t=t||{},A((function(){var n,r=pe(),o=f("FID"),i=function(c){c.startTime<r.firstHiddenTime&&(o.value=c.processingStart-c.startTime,o.entries.push(c),n(true));},s=function(c){c.forEach(i);},a=_("first-input",s);n=p(e,o,de,t.reportAllChanges),a&&(P(J((function(){s(a.takeRecords()),a.disconnect();}))),h((function(){var c;o=f("FID"),n=p(e,o,de,t.reportAllChanges),X=[],M=-1,v=null,Je(addEventListener),c=i,X.push(c),Ge();})));}));};});var he="rush_rum_sid",K="rush_rum_sts",Y="rush_rum_smp";function ye(){return typeof crypto<"u"&&crypto.randomUUID?crypto.randomUUID():"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,e=>{let t=Math.random()*16|0;return (e==="x"?t:t&3|8).toString(16)})}function Q(){try{let e=sessionStorage.getItem(he),t=sessionStorage.getItem(K),n=Date.now();if(e&&t&&n-Number(t)<18e5)return sessionStorage.setItem(K,String(n)),e;let r=ye();return sessionStorage.setItem(he,r),sessionStorage.setItem(K,String(n)),sessionStorage.removeItem(Y),r}catch{return ye()}}function we(e){if(e>=1)return true;if(e<=0)return false;try{Q();let t=sessionStorage.getItem(Y);if(t!==null)return t==="1";let n=Math.random()<e;return sessionStorage.setItem(Y,n?"1":"0"),n}catch{return Math.random()<e}}function be(){let e=navigator.userAgent,t="Unknown",n="";e.includes("Firefox/")?(t="Firefox",n=e.split("Firefox/")[1]?.split(" ")[0]??""):e.includes("Edg/")?(t="Edge",n=e.split("Edg/")[1]?.split(" ")[0]??""):e.includes("Chrome/")?(t="Chrome",n=e.split("Chrome/")[1]?.split(" ")[0]??""):e.includes("Safari/")&&!e.includes("Chrome")&&(t="Safari",n=e.split("Version/")[1]?.split(" ")[0]??"");let r="Unknown",o="";e.includes("Windows")?(r="Windows",o=e.match(/Windows NT (\d+\.\d+)/)?.[1]??""):e.includes("Android")?(r="Android",o=e.match(/Android (\d+(\.\d+)?)/)?.[1]??""):/iPhone|iPad|iPod/.test(e)?(r="iOS",o=e.match(/OS (\d+_\d+)/)?.[1]?.replace("_",".")??""):e.includes("Mac OS X")?(r="macOS",o=e.match(/Mac OS X (\d+[._]\d+[._]?\d*)/)?.[1]?.replace(/_/g,".")??""):e.includes("Linux")&&(r="Linux");let i="desktop";return /Mobi|Android.*Mobile/.test(e)?i="mobile":/iPad|Android(?!.*Mobile)|Tablet/.test(e)&&(i="tablet"),{browserName:t,browserVersion:n,osName:r,osVersion:o,deviceType:i,screenWidth:window.screen.width,screenHeight:window.screen.height}}var Z="rush_rum_buf_v1";function ee(){return typeof navigator>"u"||navigator.onLine!==false}function bt(e){return new Promise(t=>setTimeout(t,e))}function Et(e){let t=1e3*Math.pow(2,e);return Math.random()*t}function Ee(){try{let e=localStorage.getItem(Z);if(!e)return [];let t=JSON.parse(e);return Array.isArray(t)?t:[]}catch{return []}}function _e(e){try{if(e.length===0){localStorage.removeItem(Z);return}localStorage.setItem(Z,JSON.stringify(e));}catch{}}function N(e,t){try{let n=Ee();for(n.push({url:e,body:t,ts:Date.now()});n.length>50;)n.shift();let r=n.reduce((o,i)=>o+i.body.length,0);for(;n.length>1&&r>1e6;){let o=n.shift();r-=o.body.length;}_e(n);}catch{}}function _t(){return typeof CompressionStream<"u"&&typeof Response<"u"}async function St(e){let t=new Blob([e]).stream().pipeThrough(new CompressionStream("gzip")),n=await new Response(t).arrayBuffer();return new Blob([n])}async function Se(e,t,n){try{let r={"Content-Type":"application/json"},o=t;if(n&&_t())try{o=await St(t),r["Content-Encoding"]="gzip";}catch{o=t;}let i=await fetch(e,{method:"POST",headers:r,body:o,keepalive:!0});return !(i.status===429||i.status>=500)}catch{return false}}async function Te(e,t,n){if(!ee()){N(e,t);return}for(let r=0;r<=3;r++){if(await Se(e,t,n))return;r<3&&await bt(Et(r));}N(e,t);}async function te(){if(!ee())return;let e=Ee();if(e.length!==0){_e([]),e=e.sort((t,n)=>t.ts-n.ts);for(let t of e){if(!ee()){N(t.url,t.body);continue}await Se(t.url,t.body,false)||N(t.url,t.body);}}}var xe=30,Tt=250,Re=1e3,d=null,l=[],R=null,Ie=null,ke=true,D=false,H,w={},x=null,I=null,k=null;function Ce(e){D||(d=e,Ie=be(),ke=we(e.sampleRate??1),D=true,It(),kt(),Ct(),te());}function Le(e){H=e;}function Me(e){w={...w,...e};}function Pe(){w={};}function Rt(e){if(Object.keys(w).length===0)return;let n={};if(e.attributes)try{let r=JSON.parse(e.attributes);r&&typeof r=="object"&&(n=r);}catch{return}e.attributes=JSON.stringify({...w,...n});}function V(){return d}function Ae(){return D}function b(e){if(d?.captureQueryParams)return e;let t=e.length,n=e.indexOf("?"),r=e.indexOf("#");return n!==-1&&(t=Math.min(t,n)),r!==-1&&(t=Math.min(t,r)),e.slice(0,t)}function xt(){let e=typeof performance<"u"&&performance.timeOrigin?performance.timeOrigin+performance.now():Date.now();return Math.round(e*1e6)}function u(e){if(!(!d||!ke)){if(e.timestamp=e.timestamp??xt(),d.beforeSend)try{let t=d.beforeSend(e);if(t===null)return;e=t??e;}catch{}Rt(e),l.push(e),l.length>Re&&l.splice(0,l.length-Re),l.length>=xe&&C();}}function Oe(){let e=d,t=Ie,n="";if(H!==void 0)n=H?.id??"";else try{n=e.user?.()?.id??"";}catch{}return {app_name:e.app.name,app_version:e.app.version??"",environment:e.environment??"",session_id:Q(),user_id:n,page_url:b(location.href),page_path:location.pathname,view_name:document.title,referrer:b(document.referrer),browser_name:t.browserName,browser_version:t.browserVersion,os_name:t.osName,os_version:t.osVersion,device_type:t.deviceType,screen_width:t.screenWidth,screen_height:t.screenHeight}}function C(){if(!d||l.length===0)return;let e=d.endpoint,t=d.compress===true;for(;l.length>0;){let n=l.splice(0,xe),r={meta:Oe(),events:n},o=JSON.stringify(r);Te(e,o,t);}}function It(){R||(R=setInterval(()=>{l.length>0&&C();},Tt));}function kt(){if(typeof document>"u")return;let e=()=>{if(!d||l.length===0)return;let t=l.splice(0),n={meta:Oe(),events:t},r=JSON.stringify(n);if(navigator.sendBeacon)navigator.sendBeacon(d.endpoint,r);else try{let o=new XMLHttpRequest;o.open("POST",d.endpoint,!1),o.setRequestHeader("Content-Type","application/json"),o.send(r);}catch{}};x=()=>{document.visibilityState==="hidden"&&e();},I=e,document.addEventListener("visibilitychange",x),window.addEventListener("pagehide",I);}function Ct(){typeof window>"u"||(k=()=>{te();},window.addEventListener("online",k));}function Be(){C(),R&&(clearInterval(R),R=null),typeof document<"u"&&x&&document.removeEventListener("visibilitychange",x),typeof window<"u"&&I&&window.removeEventListener("pagehide",I),typeof window<"u"&&k&&window.removeEventListener("online",k),x=null,I=null,k=null,l=[],d=null,D=false,H=void 0,w={};}function Ke(){Promise.resolve().then(()=>(ze(),$e)).then(({onLCP:e,onCLS:t,onINP:n,onFCP:r,onTTFB:o})=>{let i=s=>a=>{u({event_type:"web_vital",vital_name:s,vital_value:a.value,vital_rating:a.rating});};e(i("LCP")),t(i("CLS")),n(i("INP")),r(i("FCP")),o(i("TTFB"));}).catch(()=>{});}var Ye=null;function Xt(){return typeof performance<"u"&&performance.now?performance.now():Date.now()}function Qe(e){Ye={target:e,ts:Xt()};}function Ze(){return Ye}var qt=1e3,me=false,O=null,B=null;function Gt(){let e=Ze();if(!e)return;(typeof performance<"u"&&performance.now?performance.now():Date.now())-e.ts<qt&&u({event_type:"frustration",interaction_type:"error_click",interaction_target:e.target});}function et(){me||(me=true,O=e=>{Gt(),u({event_type:"error",error_message:e.message||"Unknown error",error_stack:e.error?.stack??"",error_type:e.error?.name??"Error"});},B=e=>{let t=e.reason,n="Unhandled promise rejection",r="",o="UnhandledRejection";t instanceof Error?(n=t.message,r=t.stack??"",o=t.name):typeof t=="string"&&(n=t),u({event_type:"error",error_message:n,error_stack:r,error_type:o});},window.addEventListener("error",O),window.addEventListener("unhandledrejection",B));}function tt(){O&&(window.removeEventListener("error",O),O=null),B&&(window.removeEventListener("unhandledrejection",B),B=null),me=false;}var nt=false;function rt(){if($(),nt)return;nt=true;let e=history.pushState.bind(history),t=history.replaceState.bind(history);history.pushState=function(...n){e(...n),$();},history.replaceState=function(...n){t(...n),$();},window.addEventListener("popstate",()=>{$();});}function Jt(){let e=new Uint8Array(16);return crypto.getRandomValues(e),Array.from(e).map(t=>t.toString(16).padStart(2,"0")).join("")}function $t(){let e=new Uint8Array(8);return crypto.getRandomValues(e),Array.from(e).map(t=>t.toString(16).padStart(2,"0")).join("")}function $(){let e=Jt(),t=$t();u({event_type:"pageview",event_name:document.title,duration_ms:zt(),trace_id:e,span_id:t});}function zt(){if(typeof performance>"u")return 0;let e=performance.getEntriesByType("navigation");return e.length>0?e[0].loadEventEnd-e[0].startTime:0}var Kt='button, a, [role="button"], input[type="submit"], input[type="button"]',Yt=1e3,Qt=3,Zt=3e3,ge=false,U=null,z=null,y=[],F=[];function en(e){let t=e.tagName.toLowerCase(),n=e.id?`#${e.id}`:"",r=e.className?`.${Array.from(e.classList).slice(0,3).join(".")}`:"",o=V()?.maskInteractionText?"":(e.textContent??"").trim().slice(0,100);return `${t}${n}${r}${o?` "${o}"`:""}`}function tn(e,t){let n=Date.now();z!==e&&(z=e,y=[]),y.push(n),y=y.filter(r=>n-r<=Yt),y.length>Qt&&(u({event_type:"frustration",interaction_type:"rage_click",interaction_target:t}),y=[],z=null);}function nn(e){let t=false,n=location.href,r=new MutationObserver(()=>{t=true;});try{r.observe(document.documentElement,{childList:!0,subtree:!0,attributes:!0,characterData:!0});}catch{return}let o=()=>{t=true;};window.addEventListener("scroll",o,{passive:true,capture:true});let i=setTimeout(()=>{a();let c=location.href!==n;!t&&!c&&u({event_type:"frustration",interaction_type:"dead_click",interaction_target:e});},Zt),s={observer:r,timer:i,onScroll:o};F.push(s);function a(){r.disconnect(),clearTimeout(i),window.removeEventListener("scroll",o,{capture:true}),F=F.filter(c=>c!==s);}}function ot(){ge||(ge=true,U=e=>{let t=e.target;if(!t)return;let n=t.closest(Kt);if(!n)return;let r=en(n);Qe(r),u({event_type:"interaction",interaction_type:"click",interaction_target:r}),tn(n,r),nn(r);},document.addEventListener("click",U,{capture:true,passive:true}));}function it(){U&&(document.removeEventListener("click",U,{capture:true}),U=null);for(let e of F)e.observer.disconnect(),clearTimeout(e.timer),window.removeEventListener("scroll",e.onScroll,{capture:true});F=[],z=null,y=[],ge=false;}var st=false;function at(){st||(st=true,rn(),on());}function ct(e){let t=V();return t?.propagateTraces?.origins?t.propagateTraces.origins.some(n=>n.test(e)):false}function ut(){let e=new Uint8Array(16);return crypto.getRandomValues(e),Array.from(e).map(t=>t.toString(16).padStart(2,"0")).join("")}function dt(){let e=new Uint8Array(8);return crypto.getRandomValues(e),Array.from(e).map(t=>t.toString(16).padStart(2,"0")).join("")}function rn(){let e=window.fetch.bind(window);window.fetch=async function(t,n){let r=typeof t=="string"?t:t instanceof URL?t.href:t.url,o=performance.now(),i="",s="";if(ct(r)){i=ut(),s=dt();let a=new Headers(n?.headers);a.set("traceparent",`00-${i}-${s}-01`),n={...n,headers:a};}try{let a=await e(t,n),c=performance.now()-o;return u({event_type:"resource",event_name:b(r),duration_ms:c,trace_id:i,span_id:s,attributes:JSON.stringify({status:a.status,method:n?.method??"GET"})}),a}catch(a){let c=performance.now()-o;throw u({event_type:"resource",event_name:b(r),duration_ms:c,trace_id:i,span_id:s,error_message:a instanceof Error?a.message:"fetch failed",error_type:"NetworkError"}),a}};}function on(){let e=XMLHttpRequest.prototype.open,t=XMLHttpRequest.prototype.send;XMLHttpRequest.prototype.open=function(n,r,...o){return this.__wide_url=typeof r=="string"?r:r.href,this.__wide_method=n,e.apply(this,[n,r,...o])},XMLHttpRequest.prototype.send=function(n){let r=this.__wide_url??"",o=this.__wide_method??"GET",i=performance.now(),s="",a="";return ct(r)&&(s=ut(),a=dt(),this.setRequestHeader("traceparent",`00-${s}-${a}-01`)),this.addEventListener("loadend",()=>{let c=performance.now()-i;u({event_type:"resource",event_name:b(r),duration_ms:c,trace_id:s,span_id:a,attributes:JSON.stringify({status:this.status,method:o})});}),t.call(this,n)};}var ve=false,S=null,T=null;function lt(e){return typeof PerformanceObserver<"u"&&Array.isArray(PerformanceObserver.supportedEntryTypes)&&PerformanceObserver.supportedEntryTypes.includes(e)}function ft(){if(!ve&&!(typeof PerformanceObserver>"u")){if(ve=true,lt("longtask"))try{S=new PerformanceObserver(e=>{for(let t of e.getEntries())u({event_type:"long_task",duration_ms:t.duration,attributes:JSON.stringify({start:t.startTime,name:t.name})});}),S.observe({type:"longtask",buffered:!0});}catch{S=null;}if(lt("long-animation-frame"))try{T=new PerformanceObserver(e=>{for(let t of e.getEntries()){let n=t;u({event_type:"loaf",duration_ms:n.duration,attributes:JSON.stringify({start:n.startTime,blockingDuration:n.blockingDuration??0,scripts:(n.scripts||[]).length})});}}),T.observe({type:"long-animation-frame",buffered:!0});}catch{T=null;}}}function pt(){S&&(S.disconnect(),S=null),T&&(T.disconnect(),T=null),ve=false;}function mt(e){return {init(t){if(!(typeof window>"u")){if(Ae()){console.warn("[RushRUM] init() called more than once; ignoring.");return}Ce(t),t.trackWebVitals!==false&&Ke(),t.trackErrors!==false&&et(),t.trackPageViews!==false&&rt(),t.trackLongTasks!==false&&ft(),t.trackInteractions===true&&ot(),t.trackResources===true&&at(),t.trackSessionReplay===true&&(console.warn("[RushRUM] session replay is not available in this build; use the npm package (@rushobservability/rum-sdk)."));}},trackEvent(t,n){u({event_type:"custom",event_name:t,attributes:n?JSON.stringify(n):void 0});},setUser(t){Le(t);},setGlobalAttributes(t){Me(t);},clearGlobalAttributes(){Pe();},flush:C,destroy(){pt(),it(),tt(),Be();}}}var Nn=mt();return Nn;})();//# sourceMappingURL=rush-rum.global.js.map
2
+ //# sourceMappingURL=rush-rum.global.js.map