@watchupltd/browser 0.1.1 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +24 -1
- package/dist/index.d.ts +24 -1
- package/dist/index.js +22 -2
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +22 -2
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
interface WatchupUser {
|
|
2
|
+
/** Your app's internal user ID — the only required field. */
|
|
3
|
+
id: string | number;
|
|
4
|
+
email?: string;
|
|
5
|
+
name?: string;
|
|
6
|
+
/** Any extra key/value pairs you want attached to events. */
|
|
7
|
+
[key: string]: unknown;
|
|
8
|
+
}
|
|
1
9
|
interface WatchupOptions {
|
|
2
10
|
/**
|
|
3
11
|
* Your project's **public** API key from the Watchup dashboard.
|
|
@@ -46,6 +54,7 @@ interface TracePayload {
|
|
|
46
54
|
environment?: string;
|
|
47
55
|
release?: string;
|
|
48
56
|
meta?: Record<string, unknown>;
|
|
57
|
+
user?: WatchupUser;
|
|
49
58
|
}
|
|
50
59
|
interface ErrorPayload {
|
|
51
60
|
message: string;
|
|
@@ -56,6 +65,7 @@ interface ErrorPayload {
|
|
|
56
65
|
timestamp: string;
|
|
57
66
|
environment?: string;
|
|
58
67
|
release?: string;
|
|
68
|
+
user?: WatchupUser;
|
|
59
69
|
}
|
|
60
70
|
interface EventPayload {
|
|
61
71
|
name: string;
|
|
@@ -110,6 +120,7 @@ declare class Watchup {
|
|
|
110
120
|
private readonly cfg;
|
|
111
121
|
private readonly batcher;
|
|
112
122
|
private readonly cleanup;
|
|
123
|
+
private _user;
|
|
113
124
|
/**
|
|
114
125
|
* A random UUID generated on init. Stable for the lifetime of the page —
|
|
115
126
|
* useful for correlating all events from one user session.
|
|
@@ -129,6 +140,18 @@ declare class Watchup {
|
|
|
129
140
|
constructor(options: WatchupOptions);
|
|
130
141
|
private _getOrCreateVisitorId;
|
|
131
142
|
private _getOrCreateSessionId;
|
|
143
|
+
/**
|
|
144
|
+
* Attach a user to all subsequent errors, traces, and events.
|
|
145
|
+
* Call this after login; the context persists until `clearUser()` or page reload.
|
|
146
|
+
*
|
|
147
|
+
* @example
|
|
148
|
+
* watchup.setUser({ id: '42', email: 'ada@example.com', name: 'Ada Lovelace' });
|
|
149
|
+
*/
|
|
150
|
+
setUser(user: WatchupUser): void;
|
|
151
|
+
/**
|
|
152
|
+
* Remove the current user context (e.g. after logout).
|
|
153
|
+
*/
|
|
154
|
+
clearUser(): void;
|
|
132
155
|
/**
|
|
133
156
|
* Track a custom analytics event.
|
|
134
157
|
*
|
|
@@ -180,4 +203,4 @@ declare class Watchup {
|
|
|
180
203
|
private _timezone;
|
|
181
204
|
}
|
|
182
205
|
|
|
183
|
-
export { type ErrorPayload, type EventPayload, type IngestBatch, type TracePayload, Watchup, type WatchupOptions };
|
|
206
|
+
export { type ErrorPayload, type EventPayload, type IngestBatch, type TracePayload, Watchup, type WatchupOptions, type WatchupUser };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
interface WatchupUser {
|
|
2
|
+
/** Your app's internal user ID — the only required field. */
|
|
3
|
+
id: string | number;
|
|
4
|
+
email?: string;
|
|
5
|
+
name?: string;
|
|
6
|
+
/** Any extra key/value pairs you want attached to events. */
|
|
7
|
+
[key: string]: unknown;
|
|
8
|
+
}
|
|
1
9
|
interface WatchupOptions {
|
|
2
10
|
/**
|
|
3
11
|
* Your project's **public** API key from the Watchup dashboard.
|
|
@@ -46,6 +54,7 @@ interface TracePayload {
|
|
|
46
54
|
environment?: string;
|
|
47
55
|
release?: string;
|
|
48
56
|
meta?: Record<string, unknown>;
|
|
57
|
+
user?: WatchupUser;
|
|
49
58
|
}
|
|
50
59
|
interface ErrorPayload {
|
|
51
60
|
message: string;
|
|
@@ -56,6 +65,7 @@ interface ErrorPayload {
|
|
|
56
65
|
timestamp: string;
|
|
57
66
|
environment?: string;
|
|
58
67
|
release?: string;
|
|
68
|
+
user?: WatchupUser;
|
|
59
69
|
}
|
|
60
70
|
interface EventPayload {
|
|
61
71
|
name: string;
|
|
@@ -110,6 +120,7 @@ declare class Watchup {
|
|
|
110
120
|
private readonly cfg;
|
|
111
121
|
private readonly batcher;
|
|
112
122
|
private readonly cleanup;
|
|
123
|
+
private _user;
|
|
113
124
|
/**
|
|
114
125
|
* A random UUID generated on init. Stable for the lifetime of the page —
|
|
115
126
|
* useful for correlating all events from one user session.
|
|
@@ -129,6 +140,18 @@ declare class Watchup {
|
|
|
129
140
|
constructor(options: WatchupOptions);
|
|
130
141
|
private _getOrCreateVisitorId;
|
|
131
142
|
private _getOrCreateSessionId;
|
|
143
|
+
/**
|
|
144
|
+
* Attach a user to all subsequent errors, traces, and events.
|
|
145
|
+
* Call this after login; the context persists until `clearUser()` or page reload.
|
|
146
|
+
*
|
|
147
|
+
* @example
|
|
148
|
+
* watchup.setUser({ id: '42', email: 'ada@example.com', name: 'Ada Lovelace' });
|
|
149
|
+
*/
|
|
150
|
+
setUser(user: WatchupUser): void;
|
|
151
|
+
/**
|
|
152
|
+
* Remove the current user context (e.g. after logout).
|
|
153
|
+
*/
|
|
154
|
+
clearUser(): void;
|
|
132
155
|
/**
|
|
133
156
|
* Track a custom analytics event.
|
|
134
157
|
*
|
|
@@ -180,4 +203,4 @@ declare class Watchup {
|
|
|
180
203
|
private _timezone;
|
|
181
204
|
}
|
|
182
205
|
|
|
183
|
-
export { type ErrorPayload, type EventPayload, type IngestBatch, type TracePayload, Watchup, type WatchupOptions };
|
|
206
|
+
export { type ErrorPayload, type EventPayload, type IngestBatch, type TracePayload, Watchup, type WatchupOptions, type WatchupUser };
|
package/dist/index.js
CHANGED
|
@@ -335,6 +335,7 @@ var SESSION_KEY = "__wup_sid";
|
|
|
335
335
|
var Watchup = class {
|
|
336
336
|
constructor(options) {
|
|
337
337
|
this.cleanup = [];
|
|
338
|
+
this._user = null;
|
|
338
339
|
/**
|
|
339
340
|
* A random UUID generated on init. Stable for the lifetime of the page —
|
|
340
341
|
* useful for correlating all events from one user session.
|
|
@@ -380,6 +381,23 @@ var Watchup = class {
|
|
|
380
381
|
return this.sessionId;
|
|
381
382
|
}
|
|
382
383
|
}
|
|
384
|
+
// ── User identification ───────────────────────────────────────────────────
|
|
385
|
+
/**
|
|
386
|
+
* Attach a user to all subsequent errors, traces, and events.
|
|
387
|
+
* Call this after login; the context persists until `clearUser()` or page reload.
|
|
388
|
+
*
|
|
389
|
+
* @example
|
|
390
|
+
* watchup.setUser({ id: '42', email: 'ada@example.com', name: 'Ada Lovelace' });
|
|
391
|
+
*/
|
|
392
|
+
setUser(user) {
|
|
393
|
+
this._user = { ...user };
|
|
394
|
+
}
|
|
395
|
+
/**
|
|
396
|
+
* Remove the current user context (e.g. after logout).
|
|
397
|
+
*/
|
|
398
|
+
clearUser() {
|
|
399
|
+
this._user = null;
|
|
400
|
+
}
|
|
383
401
|
// ── Public API ────────────────────────────────────────────────────────────
|
|
384
402
|
/**
|
|
385
403
|
* Track a custom analytics event.
|
|
@@ -455,7 +473,8 @@ var Watchup = class {
|
|
|
455
473
|
},
|
|
456
474
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
457
475
|
environment: this.cfg.environment,
|
|
458
|
-
...this.cfg.release && { release: this.cfg.release }
|
|
476
|
+
...this.cfg.release && { release: this.cfg.release },
|
|
477
|
+
...this._user && { user: this._user }
|
|
459
478
|
};
|
|
460
479
|
this.batcher.addError(payload);
|
|
461
480
|
}
|
|
@@ -481,7 +500,8 @@ var Watchup = class {
|
|
|
481
500
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
482
501
|
environment: this.cfg.environment,
|
|
483
502
|
...this.cfg.release && { release: this.cfg.release },
|
|
484
|
-
...opts.meta && { meta: opts.meta }
|
|
503
|
+
...opts.meta && { meta: opts.meta },
|
|
504
|
+
...this._user && { user: this._user }
|
|
485
505
|
});
|
|
486
506
|
};
|
|
487
507
|
}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/transport.ts","../src/batcher.ts","../src/error-capture.ts","../src/perf.ts","../src/watchup.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["// ─────────────────────────────────────────────────────────────────────────────\n// @watchupltd/browser · transport\n//\n// Two delivery strategies:\n// 1. fetch(keepalive: true) — for regular periodic flushes.\n// 2. navigator.sendBeacon — for page-hide/unload; survives tab close.\n//\n// Web analytics events are sent to a separate endpoint (/web-batch) that is\n// optimised for high-volume, low-latency browser hits.\n// ─────────────────────────────────────────────────────────────────────────────\n\nimport type { IngestBatch, WebAnalyticsBatch } from './types.js';\n\nexport class Transport {\n private readonly url: string;\n private readonly webUrl: string;\n private readonly headers: Record<string, string>;\n private readonly debug: boolean;\n\n constructor(baseUrl: string, apiKey: string, debug = false) {\n const base = baseUrl.replace(/\\/$/, '');\n this.url = `${base}/api/v1/ingest/batch`;\n this.webUrl = `${base}/api/v1/ingest/web-batch`;\n this.headers = {\n 'Content-Type': 'application/json',\n 'X-Api-Key': apiKey,\n };\n this.debug = debug;\n }\n\n /**\n * Send via `fetch` with `keepalive: true`.\n * `keepalive` lets the request outlive the current page — it's the\n * browser equivalent of a \"fire and forget\" POST.\n * Never rejects.\n */\n async send(batch: IngestBatch): Promise<void> {\n try {\n const body = JSON.stringify(batch);\n\n // keepalive has a 64 KiB payload limit; fall back to beacon for large batches\n if (body.length > 60_000) {\n this.beacon(batch);\n return;\n }\n\n const res = await fetch(this.url, {\n method: 'POST',\n headers: this.headers,\n body,\n keepalive: true,\n });\n\n if (this.debug && !res.ok) {\n const text = await res.text().catch(() => '');\n console.warn(`[watchup] ingest ${res.status}: ${text}`);\n }\n } catch (err) {\n if (this.debug) console.warn('[watchup] send failed:', err);\n }\n }\n\n /**\n * Send web analytics batch to the dedicated /web-batch endpoint.\n * Never rejects.\n */\n async sendWeb(batch: WebAnalyticsBatch): Promise<void> {\n try {\n const body = JSON.stringify(batch);\n\n if (body.length > 60_000) {\n this.beaconWeb(batch);\n return;\n }\n\n const res = await fetch(this.webUrl, {\n method: 'POST',\n headers: this.headers,\n body,\n keepalive: true,\n });\n\n if (this.debug && !res.ok) {\n const text = await res.text().catch(() => '');\n console.warn(`[watchup] web-batch ${res.status}: ${text}`);\n }\n } catch (err) {\n if (this.debug) console.warn('[watchup] sendWeb failed:', err);\n }\n }\n\n /**\n * Send via `navigator.sendBeacon`.\n * Returns `true` if the browser accepted the request (doesn't guarantee delivery).\n * The server must accept `application/json` from sendBeacon via a Blob.\n */\n beacon(batch: IngestBatch): boolean {\n if (typeof navigator === 'undefined' || !navigator.sendBeacon) return false;\n try {\n const blob = new Blob([JSON.stringify(batch)], { type: 'application/json' });\n return navigator.sendBeacon(this.url, blob);\n } catch {\n return false;\n }\n }\n\n /**\n * sendBeacon variant for web analytics events.\n */\n beaconWeb(batch: WebAnalyticsBatch): boolean {\n if (typeof navigator === 'undefined' || !navigator.sendBeacon) return false;\n try {\n const blob = new Blob([JSON.stringify(batch)], { type: 'application/json' });\n return navigator.sendBeacon(this.webUrl, blob);\n } catch {\n return false;\n }\n }\n}\n","// ─────────────────────────────────────────────────────────────────────────────\n// @watchupltd/browser · batcher\n//\n// Browser-specific flush strategy:\n// - Periodic interval flush via fetch(keepalive)\n// - visibilitychange 'hidden' + pagehide → sendBeacon for reliable exit delivery\n//\n// Two independent queues:\n// - telemetry queue (traces, errors, events) → /ingest/batch\n// - web queue (web page views) → /ingest/web-batch\n// ─────────────────────────────────────────────────────────────────────────────\n\nimport type {\n TracePayload,\n ErrorPayload,\n EventPayload,\n IngestBatch,\n WebAnalyticsPayload,\n WebAnalyticsBatch,\n} from './types.js';\nimport { Transport } from './transport.js';\n\nexport class Batcher {\n private traces: TracePayload[] = [];\n private errors: ErrorPayload[] = [];\n private events: EventPayload[] = [];\n private webViews: WebAnalyticsPayload[] = [];\n\n private readonly transport: Transport;\n private readonly flushInterval: number;\n private readonly maxBatchSize: number;\n\n private timer: ReturnType<typeof setInterval> | null = null;\n private flushing = false;\n\n constructor(transport: Transport, flushInterval: number, maxBatchSize: number) {\n this.transport = transport;\n this.flushInterval = flushInterval;\n this.maxBatchSize = maxBatchSize;\n }\n\n start(): void {\n if (this.timer) return;\n\n // Periodic flush\n this.timer = setInterval(() => this.flush(), this.flushInterval);\n\n // Reliable delivery on tab hide — visibilitychange fires before the page\n // is destroyed, giving sendBeacon the best chance of succeeding.\n document.addEventListener('visibilitychange', () => {\n if (document.visibilityState === 'hidden') this.beaconFlush();\n });\n\n // Belt-and-suspenders for browsers/environments that skip visibilitychange\n window.addEventListener('pagehide', () => this.beaconFlush(), { once: true });\n }\n\n stop(): void {\n if (this.timer) { clearInterval(this.timer); this.timer = null; }\n }\n\n // ── Telemetry queue ───────────────────────────────────────────────────────\n\n addTrace(t: TracePayload): void {\n this.traces.push(t);\n if (this.traces.length >= this.maxBatchSize) this.flush();\n }\n\n addError(e: ErrorPayload): void {\n this.errors.push(e);\n // Errors are high-priority — flush at half capacity\n if (this.errors.length >= Math.ceil(this.maxBatchSize / 2)) this.flush();\n }\n\n addEvent(e: EventPayload): void {\n this.events.push(e);\n if (this.events.length >= this.maxBatchSize) this.flush();\n }\n\n // ── Web analytics queue ───────────────────────────────────────────────────\n\n addWebView(payload: WebAnalyticsPayload): void {\n this.webViews.push(payload);\n if (this.webViews.length >= this.maxBatchSize) this.flushWeb();\n }\n\n // ── Drain helpers ─────────────────────────────────────────────────────────\n\n private drainTelemetry(): IngestBatch | null {\n const traces = this.traces.splice(0);\n const errors = this.errors.splice(0);\n const events = this.events.splice(0);\n if (!traces.length && !errors.length && !events.length) return null;\n return { traces, errors, events };\n }\n\n private drainWeb(): WebAnalyticsBatch | null {\n const web = this.webViews.splice(0);\n if (!web.length) return null;\n return { web };\n }\n\n // ── Flush ─────────────────────────────────────────────────────────────────\n\n flush(): void {\n if (!this.flushing) {\n const batch = this.drainTelemetry();\n if (batch) {\n this.flushing = true;\n this.transport.send(batch).finally(() => { this.flushing = false; });\n }\n }\n this.flushWeb();\n }\n\n flushWeb(): void {\n const batch = this.drainWeb();\n if (batch) this.transport.sendWeb(batch);\n }\n\n beaconFlush(): void {\n // Telemetry\n const batch = this.drainTelemetry();\n if (batch) {\n if (!this.transport.beacon(batch)) this.transport.send(batch);\n }\n // Web analytics\n const webBatch = this.drainWeb();\n if (webBatch) {\n if (!this.transport.beaconWeb(webBatch)) this.transport.sendWeb(webBatch);\n }\n }\n}\n","// ─────────────────────────────────────────────────────────────────────────────\n// @watchupltd/browser · global error capture\n// ─────────────────────────────────────────────────────────────────────────────\n\nimport type { ErrorPayload } from './types.js';\n\ntype ErrorCallback = (error: ErrorPayload) => void;\n\n/**\n * Attaches `window.onerror` and `window.addEventListener('unhandledrejection')`\n * listeners that forward caught errors to `onError`.\n *\n * Returns a cleanup function that removes both listeners.\n */\nexport function captureGlobalErrors(onError: ErrorCallback, env?: string): () => void {\n const handleError = (event: ErrorEvent) => {\n onError({\n message: event.message || 'Unknown error',\n level: 'error',\n route: window.location.pathname,\n stack: event.error?.stack,\n context: {\n url: window.location.href,\n source: event.filename ?? undefined,\n line: event.lineno ?? undefined,\n col: event.colno ?? undefined,\n },\n timestamp: new Date().toISOString(),\n ...(env && { environment: env }),\n });\n };\n\n const handleRejection = (event: PromiseRejectionEvent) => {\n const reason = event.reason;\n const isErr = reason instanceof Error;\n onError({\n message: isErr ? reason.message : String(reason ?? 'Unhandled Promise rejection'),\n level: 'error',\n route: window.location.pathname,\n stack: isErr ? reason.stack : undefined,\n context: {\n url: window.location.href,\n type: 'unhandledrejection',\n },\n timestamp: new Date().toISOString(),\n ...(env && { environment: env }),\n });\n };\n\n window.addEventListener('error', handleError);\n window.addEventListener('unhandledrejection', handleRejection);\n\n return () => {\n window.removeEventListener('error', handleError);\n window.removeEventListener('unhandledrejection', handleRejection);\n };\n}\n","// ─────────────────────────────────────────────────────────────────────────────\n// @watchupltd/browser · Web Vitals capture\n//\n// Captures FCP, LCP, and overall page-load time via PerformanceObserver and\n// PerformanceNavigationTiming. Forwarded as traces so they appear in the\n// Watchup dashboard alongside request spans.\n//\n// Thresholds come from Google's Core Web Vitals 2024 targets:\n// FCP: good ≤ 1800 ms, needs improvement ≤ 3000 ms, poor > 3000 ms\n// LCP: good ≤ 2500 ms, needs improvement ≤ 4000 ms, poor > 4000 ms\n// ─────────────────────────────────────────────────────────────────────────────\n\nimport type { TracePayload } from './types.js';\n\ntype TraceCallback = (trace: TracePayload) => void;\n\nfunction rating(\n ms: number,\n good: number,\n needsImprovement: number,\n): TracePayload['status'] {\n if (ms <= good) return 'ok';\n if (ms <= needsImprovement) return 'warn';\n return 'err';\n}\n\nfunction statusCode(status: TracePayload['status']): number {\n return status === 'err' ? 500 : status === 'warn' ? 400 : 200;\n}\n\n// ── FCP — First Contentful Paint ─────────────────────────────────────────────\n\nexport function captureFCP(onTrace: TraceCallback, env?: string): void {\n if (typeof PerformanceObserver === 'undefined') return;\n try {\n const po = new PerformanceObserver((list) => {\n for (const entry of list.getEntries()) {\n if (entry.name !== 'first-contentful-paint') continue;\n const ms = Math.round(entry.startTime);\n const status = rating(ms, 1800, 3000);\n onTrace({\n span: 'web-vital fcp',\n ms,\n status_code: statusCode(status),\n status,\n timestamp: new Date().toISOString(),\n ...(env && { environment: env }),\n });\n po.disconnect();\n }\n });\n po.observe({ type: 'paint', buffered: true });\n } catch { /* PerformanceObserver 'paint' not supported */ }\n}\n\n// ── LCP — Largest Contentful Paint ───────────────────────────────────────────\n\nexport function captureLCP(onTrace: TraceCallback, env?: string): void {\n if (typeof PerformanceObserver === 'undefined') return;\n\n let last: PerformanceEntry | null = null;\n let reported = false;\n\n const report = () => {\n if (reported || !last) return;\n reported = true;\n try { po.disconnect(); } catch {}\n const ms = Math.round(last.startTime);\n const status = rating(ms, 2500, 4000);\n onTrace({\n span: 'web-vital lcp',\n ms,\n status_code: statusCode(status),\n status,\n timestamp: new Date().toISOString(),\n ...(env && { environment: env }),\n });\n };\n\n let po: PerformanceObserver;\n try {\n po = new PerformanceObserver((list) => {\n const entries = list.getEntries();\n if (entries.length) last = entries[entries.length - 1] ?? null;\n });\n po.observe({ type: 'largest-contentful-paint', buffered: true });\n } catch {\n return; // 'largest-contentful-paint' not supported\n }\n\n // LCP is only finalised once the user interacts or the tab hides.\n document.addEventListener('visibilitychange', report, { once: true });\n document.addEventListener('keydown', report, { once: true, capture: true });\n document.addEventListener('pointerdown', report, { once: true, capture: true });\n}\n\n// ── Page load (overall) ───────────────────────────────────────────────────────\n\nexport function capturePageLoad(onTrace: TraceCallback, env?: string): void {\n const report = () => {\n const nav = performance.getEntriesByType('navigation')[0] as\n PerformanceNavigationTiming | undefined;\n if (!nav || nav.loadEventEnd <= 0) return;\n\n const ms = Math.round(nav.loadEventEnd - nav.startTime);\n const ttfb = Math.round(nav.responseStart - nav.requestStart);\n const status = rating(ms, 2000, 4000);\n\n onTrace({\n span: 'pageload',\n ms,\n status_code: statusCode(status),\n status,\n timestamp: new Date().toISOString(),\n meta: { ttfb },\n ...(env && { environment: env }),\n });\n };\n\n if (document.readyState === 'complete') {\n // PerformanceNavigationTiming might not be fully populated yet\n setTimeout(report, 0);\n } else {\n window.addEventListener('load', () => setTimeout(report, 100), { once: true });\n }\n}\n","// ─────────────────────────────────────────────────────────────────────────────\n// @watchupltd/browser · Watchup client\n// ─────────────────────────────────────────────────────────────────────────────\n\nimport type {\n WatchupOptions,\n TracePayload,\n ErrorPayload,\n EventPayload,\n WebAnalyticsPayload,\n} from './types.js';\nimport { Transport } from './transport.js';\nimport { Batcher } from './batcher.js';\nimport { captureGlobalErrors } from './error-capture.js';\nimport { captureFCP, captureLCP, capturePageLoad } from './perf.js';\n\nconst DEFAULTS = {\n baseUrl: 'https://api.watchup.site',\n flushInterval: 5_000,\n maxBatchSize: 100,\n debug: false,\n environment: 'production',\n release: '',\n sampleRate: 1,\n autoCapture: {\n errors: true,\n performance: true,\n pageViews: true,\n },\n} as const;\n\n// ── Storage keys ──────────────────────────────────────────────────────────────\n\nconst VISITOR_KEY = '__wup_vid';\nconst SESSION_KEY = '__wup_sid';\n\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport class Watchup {\n private readonly cfg: Required<WatchupOptions>;\n private readonly batcher: Batcher;\n private readonly cleanup: Array<() => void> = [];\n\n /**\n * A random UUID generated on init. Stable for the lifetime of the page —\n * useful for correlating all events from one user session.\n */\n readonly sessionId: string = crypto.randomUUID();\n\n // ── Visitor / session identity ─────────────────────────────────────────────\n\n /**\n * Persistent visitor ID. Stored in localStorage so it survives browser\n * sessions. Falls back to a per-session UUID when localStorage is blocked.\n * The server hashes this value with SHA-256 before persisting.\n */\n private readonly visitorId: string;\n\n /**\n * Per-session ID stored in sessionStorage. Resets on tab close.\n * The server hashes this value before persisting.\n */\n private readonly webSessionId: string;\n\n constructor(options: WatchupOptions) {\n if (!options.apiKey) {\n throw new Error('[watchup] apiKey is required.');\n }\n\n this.cfg = {\n ...DEFAULTS,\n autoCapture: { ...DEFAULTS.autoCapture, ...options.autoCapture },\n ...options,\n } as Required<WatchupOptions>;\n\n const transport = new Transport(this.cfg.baseUrl, this.cfg.apiKey, this.cfg.debug);\n this.batcher = new Batcher(transport, this.cfg.flushInterval, this.cfg.maxBatchSize);\n this.batcher.start();\n\n // Initialise visitor & session IDs\n this.visitorId = this._getOrCreateVisitorId();\n this.webSessionId = this._getOrCreateSessionId();\n\n this._setupAutoCapture();\n }\n\n // ── Visitor / session identity helpers ─────────────────────────────────────\n\n private _getOrCreateVisitorId(): string {\n try {\n let id = localStorage.getItem(VISITOR_KEY);\n if (!id) {\n id = crypto.randomUUID();\n localStorage.setItem(VISITOR_KEY, id);\n }\n return id;\n } catch {\n // localStorage blocked (private mode, etc.) — fall back to session scope\n return crypto.randomUUID();\n }\n }\n\n private _getOrCreateSessionId(): string {\n try {\n let id = sessionStorage.getItem(SESSION_KEY);\n if (!id) {\n id = crypto.randomUUID();\n sessionStorage.setItem(SESSION_KEY, id);\n }\n return id;\n } catch {\n return this.sessionId; // fallback: correlate with SDK sessionId\n }\n }\n\n // ── Public API ────────────────────────────────────────────────────────────\n\n /**\n * Track a custom analytics event.\n *\n * @example\n * watchup.track('button.clicked', { label: 'Sign Up', variant: 'A' });\n */\n track(name: string, properties?: Record<string, unknown>): void {\n if (!name) return;\n const event: EventPayload = {\n name,\n ...(properties && Object.keys(properties).length && { properties }),\n occurred_at: new Date().toISOString(),\n };\n this.batcher.addEvent(event);\n }\n\n /**\n * Track a web analytics page view (or custom web event).\n * Enriches the payload with visitor context, UTM params, and device info.\n *\n * Normally called automatically. Call manually when you need custom event_name.\n *\n * @example\n * watchup.trackWebView({ event_name: 'conversion', path: '/checkout/success' });\n */\n trackWebView(overrides: Partial<WebAnalyticsPayload> = {}): void {\n const url = new URL(window.location.href);\n const params = url.searchParams;\n\n const payload: WebAnalyticsPayload = {\n path: url.pathname + (url.search || ''),\n hostname: url.hostname,\n referrer: document.referrer || undefined,\n title: document.title || undefined,\n screen_w: window.screen?.width,\n screen_h: window.screen?.height,\n lang: navigator.language || undefined,\n timezone: this._timezone(),\n // UTM parameters\n utm_source: params.get('utm_source') || undefined,\n utm_medium: params.get('utm_medium') || undefined,\n utm_campaign: params.get('utm_campaign') || undefined,\n utm_term: params.get('utm_term') || undefined,\n utm_content: params.get('utm_content') || undefined,\n // Identity (raw; the server hashes before storing)\n visitor_id: this.visitorId,\n session_id: this.webSessionId,\n event_name: 'pageview',\n occurred_at: new Date().toISOString(),\n // Apply caller overrides last\n ...overrides,\n };\n\n this.batcher.addWebView(payload);\n }\n\n /**\n * Manually capture an error.\n *\n * @example\n * try { ... } catch (err) {\n * watchup.captureError(err, { component: 'CheckoutForm' });\n * }\n */\n captureError(\n error: Error | string | unknown,\n context?: Record<string, unknown> & { route?: string; level?: ErrorPayload['level'] },\n ): void {\n const { route, level = 'error', ...rest } = context ?? {};\n const err = error instanceof Error ? error : new Error(String(error));\n\n const payload: ErrorPayload = {\n message: err.message,\n level,\n ...(err.stack !== undefined && { stack: err.stack }),\n route: route ?? window.location.pathname,\n ...(Object.keys(rest).length && {\n context: { ...rest, url: window.location.href },\n }),\n timestamp: new Date().toISOString(),\n environment: this.cfg.environment,\n ...(this.cfg.release && { release: this.cfg.release }),\n };\n\n this.batcher.addError(payload);\n }\n\n /**\n * Time any async operation and record it as a trace.\n * Returns an `end()` function — call it when the operation finishes.\n *\n * @example\n * const end = watchup.startTrace('fetch /api/cart');\n * const cart = await fetch('/api/cart');\n * end({ status: cart.ok ? 'ok' : 'err' });\n */\n startTrace(\n span: string,\n ): (opts?: { status?: TracePayload['status']; meta?: Record<string, unknown> }) => void {\n const start = Date.now();\n return (opts = {}) => {\n const status = opts.status ?? 'ok';\n this.batcher.addTrace({\n span,\n ms: Date.now() - start,\n status_code: status === 'err' ? 500 : status === 'warn' ? 400 : 200,\n status,\n timestamp: new Date().toISOString(),\n environment: this.cfg.environment,\n ...(this.cfg.release && { release: this.cfg.release }),\n ...(opts.meta && { meta: opts.meta }),\n });\n };\n }\n\n /** Immediately flush all queued items (both telemetry and web analytics). */\n flush(): void { this.batcher.flush(); }\n\n /** Stop the flush timer and release all listeners. */\n shutdown(): void {\n this.batcher.stop();\n this.batcher.flush();\n this.cleanup.forEach((fn) => fn());\n }\n\n // ── Auto-capture setup ────────────────────────────────────────────────────\n\n private _setupAutoCapture(): void {\n const { autoCapture, environment } = this.cfg;\n\n if (autoCapture.errors) {\n this.cleanup.push(\n captureGlobalErrors((e) => this.batcher.addError(e), environment),\n );\n }\n\n if (autoCapture.performance) {\n captureFCP((t) => this.batcher.addTrace(t), environment);\n captureLCP((t) => this.batcher.addTrace(t), environment);\n capturePageLoad((t) => this.batcher.addTrace(t), environment);\n }\n\n if (autoCapture.pageViews) {\n this._setupPageViewTracking();\n }\n }\n\n private _setupPageViewTracking(): void {\n const trackView = () => {\n // Small delay so the page title has settled after navigation\n setTimeout(() => this.trackWebView(), 0);\n };\n\n // Initial view\n if (document.readyState === 'loading') {\n document.addEventListener('DOMContentLoaded', trackView, { once: true });\n } else {\n setTimeout(() => this.trackWebView(), 0);\n }\n\n // SPA navigation — patch History API\n const origPush = history.pushState.bind(history);\n const origReplace = history.replaceState.bind(history);\n\n history.pushState = (...args: Parameters<typeof history.pushState>) => {\n origPush(...args);\n trackView();\n };\n history.replaceState = (...args: Parameters<typeof history.replaceState>) => {\n origReplace(...args);\n // replaceState is often used for URL canonicalisation — don't track.\n };\n\n const onPopState = () => trackView();\n window.addEventListener('popstate', onPopState);\n\n this.cleanup.push(() => {\n history.pushState = origPush;\n history.replaceState = origReplace;\n window.removeEventListener('popstate', onPopState);\n });\n }\n\n // ── Helpers ───────────────────────────────────────────────────────────────\n\n private _timezone(): string | undefined {\n try {\n return Intl.DateTimeFormat().resolvedOptions().timeZone || undefined;\n } catch {\n return undefined;\n }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/transport.ts","../src/batcher.ts","../src/error-capture.ts","../src/perf.ts","../src/watchup.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["// ─────────────────────────────────────────────────────────────────────────────\n// @watchupltd/browser · transport\n//\n// Two delivery strategies:\n// 1. fetch(keepalive: true) — for regular periodic flushes.\n// 2. navigator.sendBeacon — for page-hide/unload; survives tab close.\n//\n// Web analytics events are sent to a separate endpoint (/web-batch) that is\n// optimised for high-volume, low-latency browser hits.\n// ─────────────────────────────────────────────────────────────────────────────\n\nimport type { IngestBatch, WebAnalyticsBatch } from './types.js';\n\nexport class Transport {\n private readonly url: string;\n private readonly webUrl: string;\n private readonly headers: Record<string, string>;\n private readonly debug: boolean;\n\n constructor(baseUrl: string, apiKey: string, debug = false) {\n const base = baseUrl.replace(/\\/$/, '');\n this.url = `${base}/api/v1/ingest/batch`;\n this.webUrl = `${base}/api/v1/ingest/web-batch`;\n this.headers = {\n 'Content-Type': 'application/json',\n 'X-Api-Key': apiKey,\n };\n this.debug = debug;\n }\n\n /**\n * Send via `fetch` with `keepalive: true`.\n * `keepalive` lets the request outlive the current page — it's the\n * browser equivalent of a \"fire and forget\" POST.\n * Never rejects.\n */\n async send(batch: IngestBatch): Promise<void> {\n try {\n const body = JSON.stringify(batch);\n\n // keepalive has a 64 KiB payload limit; fall back to beacon for large batches\n if (body.length > 60_000) {\n this.beacon(batch);\n return;\n }\n\n const res = await fetch(this.url, {\n method: 'POST',\n headers: this.headers,\n body,\n keepalive: true,\n });\n\n if (this.debug && !res.ok) {\n const text = await res.text().catch(() => '');\n console.warn(`[watchup] ingest ${res.status}: ${text}`);\n }\n } catch (err) {\n if (this.debug) console.warn('[watchup] send failed:', err);\n }\n }\n\n /**\n * Send web analytics batch to the dedicated /web-batch endpoint.\n * Never rejects.\n */\n async sendWeb(batch: WebAnalyticsBatch): Promise<void> {\n try {\n const body = JSON.stringify(batch);\n\n if (body.length > 60_000) {\n this.beaconWeb(batch);\n return;\n }\n\n const res = await fetch(this.webUrl, {\n method: 'POST',\n headers: this.headers,\n body,\n keepalive: true,\n });\n\n if (this.debug && !res.ok) {\n const text = await res.text().catch(() => '');\n console.warn(`[watchup] web-batch ${res.status}: ${text}`);\n }\n } catch (err) {\n if (this.debug) console.warn('[watchup] sendWeb failed:', err);\n }\n }\n\n /**\n * Send via `navigator.sendBeacon`.\n * Returns `true` if the browser accepted the request (doesn't guarantee delivery).\n * The server must accept `application/json` from sendBeacon via a Blob.\n */\n beacon(batch: IngestBatch): boolean {\n if (typeof navigator === 'undefined' || !navigator.sendBeacon) return false;\n try {\n const blob = new Blob([JSON.stringify(batch)], { type: 'application/json' });\n return navigator.sendBeacon(this.url, blob);\n } catch {\n return false;\n }\n }\n\n /**\n * sendBeacon variant for web analytics events.\n */\n beaconWeb(batch: WebAnalyticsBatch): boolean {\n if (typeof navigator === 'undefined' || !navigator.sendBeacon) return false;\n try {\n const blob = new Blob([JSON.stringify(batch)], { type: 'application/json' });\n return navigator.sendBeacon(this.webUrl, blob);\n } catch {\n return false;\n }\n }\n}\n","// ─────────────────────────────────────────────────────────────────────────────\n// @watchupltd/browser · batcher\n//\n// Browser-specific flush strategy:\n// - Periodic interval flush via fetch(keepalive)\n// - visibilitychange 'hidden' + pagehide → sendBeacon for reliable exit delivery\n//\n// Two independent queues:\n// - telemetry queue (traces, errors, events) → /ingest/batch\n// - web queue (web page views) → /ingest/web-batch\n// ─────────────────────────────────────────────────────────────────────────────\n\nimport type {\n TracePayload,\n ErrorPayload,\n EventPayload,\n IngestBatch,\n WebAnalyticsPayload,\n WebAnalyticsBatch,\n} from './types.js';\nimport { Transport } from './transport.js';\n\nexport class Batcher {\n private traces: TracePayload[] = [];\n private errors: ErrorPayload[] = [];\n private events: EventPayload[] = [];\n private webViews: WebAnalyticsPayload[] = [];\n\n private readonly transport: Transport;\n private readonly flushInterval: number;\n private readonly maxBatchSize: number;\n\n private timer: ReturnType<typeof setInterval> | null = null;\n private flushing = false;\n\n constructor(transport: Transport, flushInterval: number, maxBatchSize: number) {\n this.transport = transport;\n this.flushInterval = flushInterval;\n this.maxBatchSize = maxBatchSize;\n }\n\n start(): void {\n if (this.timer) return;\n\n // Periodic flush\n this.timer = setInterval(() => this.flush(), this.flushInterval);\n\n // Reliable delivery on tab hide — visibilitychange fires before the page\n // is destroyed, giving sendBeacon the best chance of succeeding.\n document.addEventListener('visibilitychange', () => {\n if (document.visibilityState === 'hidden') this.beaconFlush();\n });\n\n // Belt-and-suspenders for browsers/environments that skip visibilitychange\n window.addEventListener('pagehide', () => this.beaconFlush(), { once: true });\n }\n\n stop(): void {\n if (this.timer) { clearInterval(this.timer); this.timer = null; }\n }\n\n // ── Telemetry queue ───────────────────────────────────────────────────────\n\n addTrace(t: TracePayload): void {\n this.traces.push(t);\n if (this.traces.length >= this.maxBatchSize) this.flush();\n }\n\n addError(e: ErrorPayload): void {\n this.errors.push(e);\n // Errors are high-priority — flush at half capacity\n if (this.errors.length >= Math.ceil(this.maxBatchSize / 2)) this.flush();\n }\n\n addEvent(e: EventPayload): void {\n this.events.push(e);\n if (this.events.length >= this.maxBatchSize) this.flush();\n }\n\n // ── Web analytics queue ───────────────────────────────────────────────────\n\n addWebView(payload: WebAnalyticsPayload): void {\n this.webViews.push(payload);\n if (this.webViews.length >= this.maxBatchSize) this.flushWeb();\n }\n\n // ── Drain helpers ─────────────────────────────────────────────────────────\n\n private drainTelemetry(): IngestBatch | null {\n const traces = this.traces.splice(0);\n const errors = this.errors.splice(0);\n const events = this.events.splice(0);\n if (!traces.length && !errors.length && !events.length) return null;\n return { traces, errors, events };\n }\n\n private drainWeb(): WebAnalyticsBatch | null {\n const web = this.webViews.splice(0);\n if (!web.length) return null;\n return { web };\n }\n\n // ── Flush ─────────────────────────────────────────────────────────────────\n\n flush(): void {\n if (!this.flushing) {\n const batch = this.drainTelemetry();\n if (batch) {\n this.flushing = true;\n this.transport.send(batch).finally(() => { this.flushing = false; });\n }\n }\n this.flushWeb();\n }\n\n flushWeb(): void {\n const batch = this.drainWeb();\n if (batch) this.transport.sendWeb(batch);\n }\n\n beaconFlush(): void {\n // Telemetry\n const batch = this.drainTelemetry();\n if (batch) {\n if (!this.transport.beacon(batch)) this.transport.send(batch);\n }\n // Web analytics\n const webBatch = this.drainWeb();\n if (webBatch) {\n if (!this.transport.beaconWeb(webBatch)) this.transport.sendWeb(webBatch);\n }\n }\n}\n","// ─────────────────────────────────────────────────────────────────────────────\n// @watchupltd/browser · global error capture\n// ─────────────────────────────────────────────────────────────────────────────\n\nimport type { ErrorPayload } from './types.js';\n\ntype ErrorCallback = (error: ErrorPayload) => void;\n\n/**\n * Attaches `window.onerror` and `window.addEventListener('unhandledrejection')`\n * listeners that forward caught errors to `onError`.\n *\n * Returns a cleanup function that removes both listeners.\n */\nexport function captureGlobalErrors(onError: ErrorCallback, env?: string): () => void {\n const handleError = (event: ErrorEvent) => {\n onError({\n message: event.message || 'Unknown error',\n level: 'error',\n route: window.location.pathname,\n stack: event.error?.stack,\n context: {\n url: window.location.href,\n source: event.filename ?? undefined,\n line: event.lineno ?? undefined,\n col: event.colno ?? undefined,\n },\n timestamp: new Date().toISOString(),\n ...(env && { environment: env }),\n });\n };\n\n const handleRejection = (event: PromiseRejectionEvent) => {\n const reason = event.reason;\n const isErr = reason instanceof Error;\n onError({\n message: isErr ? reason.message : String(reason ?? 'Unhandled Promise rejection'),\n level: 'error',\n route: window.location.pathname,\n stack: isErr ? reason.stack : undefined,\n context: {\n url: window.location.href,\n type: 'unhandledrejection',\n },\n timestamp: new Date().toISOString(),\n ...(env && { environment: env }),\n });\n };\n\n window.addEventListener('error', handleError);\n window.addEventListener('unhandledrejection', handleRejection);\n\n return () => {\n window.removeEventListener('error', handleError);\n window.removeEventListener('unhandledrejection', handleRejection);\n };\n}\n","// ─────────────────────────────────────────────────────────────────────────────\n// @watchupltd/browser · Web Vitals capture\n//\n// Captures FCP, LCP, and overall page-load time via PerformanceObserver and\n// PerformanceNavigationTiming. Forwarded as traces so they appear in the\n// Watchup dashboard alongside request spans.\n//\n// Thresholds come from Google's Core Web Vitals 2024 targets:\n// FCP: good ≤ 1800 ms, needs improvement ≤ 3000 ms, poor > 3000 ms\n// LCP: good ≤ 2500 ms, needs improvement ≤ 4000 ms, poor > 4000 ms\n// ─────────────────────────────────────────────────────────────────────────────\n\nimport type { TracePayload } from './types.js';\n\ntype TraceCallback = (trace: TracePayload) => void;\n\nfunction rating(\n ms: number,\n good: number,\n needsImprovement: number,\n): TracePayload['status'] {\n if (ms <= good) return 'ok';\n if (ms <= needsImprovement) return 'warn';\n return 'err';\n}\n\nfunction statusCode(status: TracePayload['status']): number {\n return status === 'err' ? 500 : status === 'warn' ? 400 : 200;\n}\n\n// ── FCP — First Contentful Paint ─────────────────────────────────────────────\n\nexport function captureFCP(onTrace: TraceCallback, env?: string): void {\n if (typeof PerformanceObserver === 'undefined') return;\n try {\n const po = new PerformanceObserver((list) => {\n for (const entry of list.getEntries()) {\n if (entry.name !== 'first-contentful-paint') continue;\n const ms = Math.round(entry.startTime);\n const status = rating(ms, 1800, 3000);\n onTrace({\n span: 'web-vital fcp',\n ms,\n status_code: statusCode(status),\n status,\n timestamp: new Date().toISOString(),\n ...(env && { environment: env }),\n });\n po.disconnect();\n }\n });\n po.observe({ type: 'paint', buffered: true });\n } catch { /* PerformanceObserver 'paint' not supported */ }\n}\n\n// ── LCP — Largest Contentful Paint ───────────────────────────────────────────\n\nexport function captureLCP(onTrace: TraceCallback, env?: string): void {\n if (typeof PerformanceObserver === 'undefined') return;\n\n let last: PerformanceEntry | null = null;\n let reported = false;\n\n const report = () => {\n if (reported || !last) return;\n reported = true;\n try { po.disconnect(); } catch {}\n const ms = Math.round(last.startTime);\n const status = rating(ms, 2500, 4000);\n onTrace({\n span: 'web-vital lcp',\n ms,\n status_code: statusCode(status),\n status,\n timestamp: new Date().toISOString(),\n ...(env && { environment: env }),\n });\n };\n\n let po: PerformanceObserver;\n try {\n po = new PerformanceObserver((list) => {\n const entries = list.getEntries();\n if (entries.length) last = entries[entries.length - 1] ?? null;\n });\n po.observe({ type: 'largest-contentful-paint', buffered: true });\n } catch {\n return; // 'largest-contentful-paint' not supported\n }\n\n // LCP is only finalised once the user interacts or the tab hides.\n document.addEventListener('visibilitychange', report, { once: true });\n document.addEventListener('keydown', report, { once: true, capture: true });\n document.addEventListener('pointerdown', report, { once: true, capture: true });\n}\n\n// ── Page load (overall) ───────────────────────────────────────────────────────\n\nexport function capturePageLoad(onTrace: TraceCallback, env?: string): void {\n const report = () => {\n const nav = performance.getEntriesByType('navigation')[0] as\n PerformanceNavigationTiming | undefined;\n if (!nav || nav.loadEventEnd <= 0) return;\n\n const ms = Math.round(nav.loadEventEnd - nav.startTime);\n const ttfb = Math.round(nav.responseStart - nav.requestStart);\n const status = rating(ms, 2000, 4000);\n\n onTrace({\n span: 'pageload',\n ms,\n status_code: statusCode(status),\n status,\n timestamp: new Date().toISOString(),\n meta: { ttfb },\n ...(env && { environment: env }),\n });\n };\n\n if (document.readyState === 'complete') {\n // PerformanceNavigationTiming might not be fully populated yet\n setTimeout(report, 0);\n } else {\n window.addEventListener('load', () => setTimeout(report, 100), { once: true });\n }\n}\n","// ─────────────────────────────────────────────────────────────────────────────\n// @watchupltd/browser · Watchup client\n// ─────────────────────────────────────────────────────────────────────────────\n\nimport type {\n WatchupOptions,\n WatchupUser,\n TracePayload,\n ErrorPayload,\n EventPayload,\n WebAnalyticsPayload,\n} from './types.js';\nimport { Transport } from './transport.js';\nimport { Batcher } from './batcher.js';\nimport { captureGlobalErrors } from './error-capture.js';\nimport { captureFCP, captureLCP, capturePageLoad } from './perf.js';\n\nconst DEFAULTS = {\n baseUrl: 'https://api.watchup.site',\n flushInterval: 5_000,\n maxBatchSize: 100,\n debug: false,\n environment: 'production',\n release: '',\n sampleRate: 1,\n autoCapture: {\n errors: true,\n performance: true,\n pageViews: true,\n },\n} as const;\n\n// ── Storage keys ──────────────────────────────────────────────────────────────\n\nconst VISITOR_KEY = '__wup_vid';\nconst SESSION_KEY = '__wup_sid';\n\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport class Watchup {\n private readonly cfg: Required<WatchupOptions>;\n private readonly batcher: Batcher;\n private readonly cleanup: Array<() => void> = [];\n private _user: WatchupUser | null = null;\n\n /**\n * A random UUID generated on init. Stable for the lifetime of the page —\n * useful for correlating all events from one user session.\n */\n readonly sessionId: string = crypto.randomUUID();\n\n // ── Visitor / session identity ─────────────────────────────────────────────\n\n /**\n * Persistent visitor ID. Stored in localStorage so it survives browser\n * sessions. Falls back to a per-session UUID when localStorage is blocked.\n * The server hashes this value with SHA-256 before persisting.\n */\n private readonly visitorId: string;\n\n /**\n * Per-session ID stored in sessionStorage. Resets on tab close.\n * The server hashes this value before persisting.\n */\n private readonly webSessionId: string;\n\n constructor(options: WatchupOptions) {\n if (!options.apiKey) {\n throw new Error('[watchup] apiKey is required.');\n }\n\n this.cfg = {\n ...DEFAULTS,\n autoCapture: { ...DEFAULTS.autoCapture, ...options.autoCapture },\n ...options,\n } as Required<WatchupOptions>;\n\n const transport = new Transport(this.cfg.baseUrl, this.cfg.apiKey, this.cfg.debug);\n this.batcher = new Batcher(transport, this.cfg.flushInterval, this.cfg.maxBatchSize);\n this.batcher.start();\n\n // Initialise visitor & session IDs\n this.visitorId = this._getOrCreateVisitorId();\n this.webSessionId = this._getOrCreateSessionId();\n\n this._setupAutoCapture();\n }\n\n // ── Visitor / session identity helpers ─────────────────────────────────────\n\n private _getOrCreateVisitorId(): string {\n try {\n let id = localStorage.getItem(VISITOR_KEY);\n if (!id) {\n id = crypto.randomUUID();\n localStorage.setItem(VISITOR_KEY, id);\n }\n return id;\n } catch {\n // localStorage blocked (private mode, etc.) — fall back to session scope\n return crypto.randomUUID();\n }\n }\n\n private _getOrCreateSessionId(): string {\n try {\n let id = sessionStorage.getItem(SESSION_KEY);\n if (!id) {\n id = crypto.randomUUID();\n sessionStorage.setItem(SESSION_KEY, id);\n }\n return id;\n } catch {\n return this.sessionId; // fallback: correlate with SDK sessionId\n }\n }\n\n // ── User identification ───────────────────────────────────────────────────\n\n /**\n * Attach a user to all subsequent errors, traces, and events.\n * Call this after login; the context persists until `clearUser()` or page reload.\n *\n * @example\n * watchup.setUser({ id: '42', email: 'ada@example.com', name: 'Ada Lovelace' });\n */\n setUser(user: WatchupUser): void {\n this._user = { ...user };\n }\n\n /**\n * Remove the current user context (e.g. after logout).\n */\n clearUser(): void {\n this._user = null;\n }\n\n // ── Public API ────────────────────────────────────────────────────────────\n\n /**\n * Track a custom analytics event.\n *\n * @example\n * watchup.track('button.clicked', { label: 'Sign Up', variant: 'A' });\n */\n track(name: string, properties?: Record<string, unknown>): void {\n if (!name) return;\n const event: EventPayload = {\n name,\n ...(properties && Object.keys(properties).length && { properties }),\n occurred_at: new Date().toISOString(),\n };\n this.batcher.addEvent(event);\n }\n\n /**\n * Track a web analytics page view (or custom web event).\n * Enriches the payload with visitor context, UTM params, and device info.\n *\n * Normally called automatically. Call manually when you need custom event_name.\n *\n * @example\n * watchup.trackWebView({ event_name: 'conversion', path: '/checkout/success' });\n */\n trackWebView(overrides: Partial<WebAnalyticsPayload> = {}): void {\n const url = new URL(window.location.href);\n const params = url.searchParams;\n\n const payload: WebAnalyticsPayload = {\n path: url.pathname + (url.search || ''),\n hostname: url.hostname,\n referrer: document.referrer || undefined,\n title: document.title || undefined,\n screen_w: window.screen?.width,\n screen_h: window.screen?.height,\n lang: navigator.language || undefined,\n timezone: this._timezone(),\n // UTM parameters\n utm_source: params.get('utm_source') || undefined,\n utm_medium: params.get('utm_medium') || undefined,\n utm_campaign: params.get('utm_campaign') || undefined,\n utm_term: params.get('utm_term') || undefined,\n utm_content: params.get('utm_content') || undefined,\n // Identity (raw; the server hashes before storing)\n visitor_id: this.visitorId,\n session_id: this.webSessionId,\n event_name: 'pageview',\n occurred_at: new Date().toISOString(),\n // Apply caller overrides last\n ...overrides,\n };\n\n this.batcher.addWebView(payload);\n }\n\n /**\n * Manually capture an error.\n *\n * @example\n * try { ... } catch (err) {\n * watchup.captureError(err, { component: 'CheckoutForm' });\n * }\n */\n captureError(\n error: Error | string | unknown,\n context?: Record<string, unknown> & { route?: string; level?: ErrorPayload['level'] },\n ): void {\n const { route, level = 'error', ...rest } = context ?? {};\n const err = error instanceof Error ? error : new Error(String(error));\n\n const payload: ErrorPayload = {\n message: err.message,\n level,\n ...(err.stack !== undefined && { stack: err.stack }),\n route: route ?? window.location.pathname,\n ...(Object.keys(rest).length && {\n context: { ...rest, url: window.location.href },\n }),\n timestamp: new Date().toISOString(),\n environment: this.cfg.environment,\n ...(this.cfg.release && { release: this.cfg.release }),\n ...(this._user && { user: this._user }),\n };\n\n this.batcher.addError(payload);\n }\n\n /**\n * Time any async operation and record it as a trace.\n * Returns an `end()` function — call it when the operation finishes.\n *\n * @example\n * const end = watchup.startTrace('fetch /api/cart');\n * const cart = await fetch('/api/cart');\n * end({ status: cart.ok ? 'ok' : 'err' });\n */\n startTrace(\n span: string,\n ): (opts?: { status?: TracePayload['status']; meta?: Record<string, unknown> }) => void {\n const start = Date.now();\n return (opts = {}) => {\n const status = opts.status ?? 'ok';\n this.batcher.addTrace({\n span,\n ms: Date.now() - start,\n status_code: status === 'err' ? 500 : status === 'warn' ? 400 : 200,\n status,\n timestamp: new Date().toISOString(),\n environment: this.cfg.environment,\n ...(this.cfg.release && { release: this.cfg.release }),\n ...(opts.meta && { meta: opts.meta }),\n ...(this._user && { user: this._user }),\n });\n };\n }\n\n /** Immediately flush all queued items (both telemetry and web analytics). */\n flush(): void { this.batcher.flush(); }\n\n /** Stop the flush timer and release all listeners. */\n shutdown(): void {\n this.batcher.stop();\n this.batcher.flush();\n this.cleanup.forEach((fn) => fn());\n }\n\n // ── Auto-capture setup ────────────────────────────────────────────────────\n\n private _setupAutoCapture(): void {\n const { autoCapture, environment } = this.cfg;\n\n if (autoCapture.errors) {\n this.cleanup.push(\n captureGlobalErrors((e) => this.batcher.addError(e), environment),\n );\n }\n\n if (autoCapture.performance) {\n captureFCP((t) => this.batcher.addTrace(t), environment);\n captureLCP((t) => this.batcher.addTrace(t), environment);\n capturePageLoad((t) => this.batcher.addTrace(t), environment);\n }\n\n if (autoCapture.pageViews) {\n this._setupPageViewTracking();\n }\n }\n\n private _setupPageViewTracking(): void {\n const trackView = () => {\n // Small delay so the page title has settled after navigation\n setTimeout(() => this.trackWebView(), 0);\n };\n\n // Initial view\n if (document.readyState === 'loading') {\n document.addEventListener('DOMContentLoaded', trackView, { once: true });\n } else {\n setTimeout(() => this.trackWebView(), 0);\n }\n\n // SPA navigation — patch History API\n const origPush = history.pushState.bind(history);\n const origReplace = history.replaceState.bind(history);\n\n history.pushState = (...args: Parameters<typeof history.pushState>) => {\n origPush(...args);\n trackView();\n };\n history.replaceState = (...args: Parameters<typeof history.replaceState>) => {\n origReplace(...args);\n // replaceState is often used for URL canonicalisation — don't track.\n };\n\n const onPopState = () => trackView();\n window.addEventListener('popstate', onPopState);\n\n this.cleanup.push(() => {\n history.pushState = origPush;\n history.replaceState = origReplace;\n window.removeEventListener('popstate', onPopState);\n });\n }\n\n // ── Helpers ───────────────────────────────────────────────────────────────\n\n private _timezone(): string | undefined {\n try {\n return Intl.DateTimeFormat().resolvedOptions().timeZone || undefined;\n } catch {\n return undefined;\n }\n }\n}\n"]}
|
package/dist/index.mjs
CHANGED
|
@@ -333,6 +333,7 @@ var SESSION_KEY = "__wup_sid";
|
|
|
333
333
|
var Watchup = class {
|
|
334
334
|
constructor(options) {
|
|
335
335
|
this.cleanup = [];
|
|
336
|
+
this._user = null;
|
|
336
337
|
/**
|
|
337
338
|
* A random UUID generated on init. Stable for the lifetime of the page —
|
|
338
339
|
* useful for correlating all events from one user session.
|
|
@@ -378,6 +379,23 @@ var Watchup = class {
|
|
|
378
379
|
return this.sessionId;
|
|
379
380
|
}
|
|
380
381
|
}
|
|
382
|
+
// ── User identification ───────────────────────────────────────────────────
|
|
383
|
+
/**
|
|
384
|
+
* Attach a user to all subsequent errors, traces, and events.
|
|
385
|
+
* Call this after login; the context persists until `clearUser()` or page reload.
|
|
386
|
+
*
|
|
387
|
+
* @example
|
|
388
|
+
* watchup.setUser({ id: '42', email: 'ada@example.com', name: 'Ada Lovelace' });
|
|
389
|
+
*/
|
|
390
|
+
setUser(user) {
|
|
391
|
+
this._user = { ...user };
|
|
392
|
+
}
|
|
393
|
+
/**
|
|
394
|
+
* Remove the current user context (e.g. after logout).
|
|
395
|
+
*/
|
|
396
|
+
clearUser() {
|
|
397
|
+
this._user = null;
|
|
398
|
+
}
|
|
381
399
|
// ── Public API ────────────────────────────────────────────────────────────
|
|
382
400
|
/**
|
|
383
401
|
* Track a custom analytics event.
|
|
@@ -453,7 +471,8 @@ var Watchup = class {
|
|
|
453
471
|
},
|
|
454
472
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
455
473
|
environment: this.cfg.environment,
|
|
456
|
-
...this.cfg.release && { release: this.cfg.release }
|
|
474
|
+
...this.cfg.release && { release: this.cfg.release },
|
|
475
|
+
...this._user && { user: this._user }
|
|
457
476
|
};
|
|
458
477
|
this.batcher.addError(payload);
|
|
459
478
|
}
|
|
@@ -479,7 +498,8 @@ var Watchup = class {
|
|
|
479
498
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
480
499
|
environment: this.cfg.environment,
|
|
481
500
|
...this.cfg.release && { release: this.cfg.release },
|
|
482
|
-
...opts.meta && { meta: opts.meta }
|
|
501
|
+
...opts.meta && { meta: opts.meta },
|
|
502
|
+
...this._user && { user: this._user }
|
|
483
503
|
});
|
|
484
504
|
};
|
|
485
505
|
}
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/transport.ts","../src/batcher.ts","../src/error-capture.ts","../src/perf.ts","../src/watchup.ts"],"names":[],"mappings":";AAaO,IAAM,YAAN,MAAgB;AAAA,EAMrB,WAAA,CAAY,OAAA,EAAiB,MAAA,EAAgB,KAAA,GAAQ,KAAA,EAAO;AAC1D,IAAA,MAAM,IAAA,GAAW,OAAA,CAAQ,OAAA,CAAQ,KAAA,EAAO,EAAE,CAAA;AAC1C,IAAA,IAAA,CAAK,GAAA,GAAY,GAAG,IAAI,CAAA,oBAAA,CAAA;AACxB,IAAA,IAAA,CAAK,MAAA,GAAY,GAAG,IAAI,CAAA,wBAAA,CAAA;AACxB,IAAA,IAAA,CAAK,OAAA,GAAY;AAAA,MACf,cAAA,EAAgB,kBAAA;AAAA,MAChB,WAAA,EAAgB;AAAA,KAClB;AACA,IAAA,IAAA,CAAK,KAAA,GAAQ,KAAA;AAAA,EACf;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,KAAK,KAAA,EAAmC;AAC5C,IAAA,IAAI;AACF,MAAA,MAAM,IAAA,GAAO,IAAA,CAAK,SAAA,CAAU,KAAK,CAAA;AAGjC,MAAA,IAAI,IAAA,CAAK,SAAS,GAAA,EAAQ;AACxB,QAAA,IAAA,CAAK,OAAO,KAAK,CAAA;AACjB,QAAA;AAAA,MACF;AAEA,MAAA,MAAM,GAAA,GAAM,MAAM,KAAA,CAAM,IAAA,CAAK,GAAA,EAAK;AAAA,QAChC,MAAA,EAAW,MAAA;AAAA,QACX,SAAW,IAAA,CAAK,OAAA;AAAA,QAChB,IAAA;AAAA,QACA,SAAA,EAAW;AAAA,OACZ,CAAA;AAED,MAAA,IAAI,IAAA,CAAK,KAAA,IAAS,CAAC,GAAA,CAAI,EAAA,EAAI;AACzB,QAAA,MAAM,OAAO,MAAM,GAAA,CAAI,MAAK,CAAE,KAAA,CAAM,MAAM,EAAE,CAAA;AAC5C,QAAA,OAAA,CAAQ,KAAK,CAAA,iBAAA,EAAoB,GAAA,CAAI,MAAM,CAAA,EAAA,EAAK,IAAI,CAAA,CAAE,CAAA;AAAA,MACxD;AAAA,IACF,SAAS,GAAA,EAAK;AACZ,MAAA,IAAI,IAAA,CAAK,KAAA,EAAO,OAAA,CAAQ,IAAA,CAAK,0BAA0B,GAAG,CAAA;AAAA,IAC5D;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,QAAQ,KAAA,EAAyC;AACrD,IAAA,IAAI;AACF,MAAA,MAAM,IAAA,GAAO,IAAA,CAAK,SAAA,CAAU,KAAK,CAAA;AAEjC,MAAA,IAAI,IAAA,CAAK,SAAS,GAAA,EAAQ;AACxB,QAAA,IAAA,CAAK,UAAU,KAAK,CAAA;AACpB,QAAA;AAAA,MACF;AAEA,MAAA,MAAM,GAAA,GAAM,MAAM,KAAA,CAAM,IAAA,CAAK,MAAA,EAAQ;AAAA,QACnC,MAAA,EAAW,MAAA;AAAA,QACX,SAAW,IAAA,CAAK,OAAA;AAAA,QAChB,IAAA;AAAA,QACA,SAAA,EAAW;AAAA,OACZ,CAAA;AAED,MAAA,IAAI,IAAA,CAAK,KAAA,IAAS,CAAC,GAAA,CAAI,EAAA,EAAI;AACzB,QAAA,MAAM,OAAO,MAAM,GAAA,CAAI,MAAK,CAAE,KAAA,CAAM,MAAM,EAAE,CAAA;AAC5C,QAAA,OAAA,CAAQ,KAAK,CAAA,oBAAA,EAAuB,GAAA,CAAI,MAAM,CAAA,EAAA,EAAK,IAAI,CAAA,CAAE,CAAA;AAAA,MAC3D;AAAA,IACF,SAAS,GAAA,EAAK;AACZ,MAAA,IAAI,IAAA,CAAK,KAAA,EAAO,OAAA,CAAQ,IAAA,CAAK,6BAA6B,GAAG,CAAA;AAAA,IAC/D;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,OAAO,KAAA,EAA6B;AAClC,IAAA,IAAI,OAAO,SAAA,KAAc,WAAA,IAAe,CAAC,SAAA,CAAU,YAAY,OAAO,KAAA;AACtE,IAAA,IAAI;AACF,MAAA,MAAM,IAAA,GAAO,IAAI,IAAA,CAAK,CAAC,IAAA,CAAK,SAAA,CAAU,KAAK,CAAC,CAAA,EAAG,EAAE,IAAA,EAAM,kBAAA,EAAoB,CAAA;AAC3E,MAAA,OAAO,SAAA,CAAU,UAAA,CAAW,IAAA,CAAK,GAAA,EAAK,IAAI,CAAA;AAAA,IAC5C,CAAA,CAAA,MAAQ;AACN,MAAA,OAAO,KAAA;AAAA,IACT;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,UAAU,KAAA,EAAmC;AAC3C,IAAA,IAAI,OAAO,SAAA,KAAc,WAAA,IAAe,CAAC,SAAA,CAAU,YAAY,OAAO,KAAA;AACtE,IAAA,IAAI;AACF,MAAA,MAAM,IAAA,GAAO,IAAI,IAAA,CAAK,CAAC,IAAA,CAAK,SAAA,CAAU,KAAK,CAAC,CAAA,EAAG,EAAE,IAAA,EAAM,kBAAA,EAAoB,CAAA;AAC3E,MAAA,OAAO,SAAA,CAAU,UAAA,CAAW,IAAA,CAAK,MAAA,EAAQ,IAAI,CAAA;AAAA,IAC/C,CAAA,CAAA,MAAQ;AACN,MAAA,OAAO,KAAA;AAAA,IACT;AAAA,EACF;AACF,CAAA;;;AChGO,IAAM,UAAN,MAAc;AAAA,EAanB,WAAA,CAAY,SAAA,EAAsB,aAAA,EAAuB,YAAA,EAAsB;AAZ/E,IAAA,IAAA,CAAQ,SAAqC,EAAC;AAC9C,IAAA,IAAA,CAAQ,SAAqC,EAAC;AAC9C,IAAA,IAAA,CAAQ,SAAqC,EAAC;AAC9C,IAAA,IAAA,CAAQ,WAAqC,EAAC;AAM9C,IAAA,IAAA,CAAQ,KAAA,GAAkD,IAAA;AAC1D,IAAA,IAAA,CAAQ,QAAA,GAAW,KAAA;AAGjB,IAAA,IAAA,CAAK,SAAA,GAAgB,SAAA;AACrB,IAAA,IAAA,CAAK,aAAA,GAAgB,aAAA;AACrB,IAAA,IAAA,CAAK,YAAA,GAAgB,YAAA;AAAA,EACvB;AAAA,EAEA,KAAA,GAAc;AACZ,IAAA,IAAI,KAAK,KAAA,EAAO;AAGhB,IAAA,IAAA,CAAK,QAAQ,WAAA,CAAY,MAAM,KAAK,KAAA,EAAM,EAAG,KAAK,aAAa,CAAA;AAI/D,IAAA,QAAA,CAAS,gBAAA,CAAiB,oBAAoB,MAAM;AAClD,MAAA,IAAI,QAAA,CAAS,eAAA,KAAoB,QAAA,EAAU,IAAA,CAAK,WAAA,EAAY;AAAA,IAC9D,CAAC,CAAA;AAGD,IAAA,MAAA,CAAO,gBAAA,CAAiB,YAAY,MAAM,IAAA,CAAK,aAAY,EAAG,EAAE,IAAA,EAAM,IAAA,EAAM,CAAA;AAAA,EAC9E;AAAA,EAEA,IAAA,GAAa;AACX,IAAA,IAAI,KAAK,KAAA,EAAO;AAAE,MAAA,aAAA,CAAc,KAAK,KAAK,CAAA;AAAG,MAAA,IAAA,CAAK,KAAA,GAAQ,IAAA;AAAA,IAAM;AAAA,EAClE;AAAA;AAAA,EAIA,SAAS,CAAA,EAAuB;AAC9B,IAAA,IAAA,CAAK,MAAA,CAAO,KAAK,CAAC,CAAA;AAClB,IAAA,IAAI,KAAK,MAAA,CAAO,MAAA,IAAU,IAAA,CAAK,YAAA,OAAmB,KAAA,EAAM;AAAA,EAC1D;AAAA,EAEA,SAAS,CAAA,EAAuB;AAC9B,IAAA,IAAA,CAAK,MAAA,CAAO,KAAK,CAAC,CAAA;AAElB,IAAA,IAAI,IAAA,CAAK,MAAA,CAAO,MAAA,IAAU,IAAA,CAAK,IAAA,CAAK,KAAK,YAAA,GAAe,CAAC,CAAA,EAAG,IAAA,CAAK,KAAA,EAAM;AAAA,EACzE;AAAA,EAEA,SAAS,CAAA,EAAuB;AAC9B,IAAA,IAAA,CAAK,MAAA,CAAO,KAAK,CAAC,CAAA;AAClB,IAAA,IAAI,KAAK,MAAA,CAAO,MAAA,IAAU,IAAA,CAAK,YAAA,OAAmB,KAAA,EAAM;AAAA,EAC1D;AAAA;AAAA,EAIA,WAAW,OAAA,EAAoC;AAC7C,IAAA,IAAA,CAAK,QAAA,CAAS,KAAK,OAAO,CAAA;AAC1B,IAAA,IAAI,KAAK,QAAA,CAAS,MAAA,IAAU,IAAA,CAAK,YAAA,OAAmB,QAAA,EAAS;AAAA,EAC/D;AAAA;AAAA,EAIQ,cAAA,GAAqC;AAC3C,IAAA,MAAM,MAAA,GAAS,IAAA,CAAK,MAAA,CAAO,MAAA,CAAO,CAAC,CAAA;AACnC,IAAA,MAAM,MAAA,GAAS,IAAA,CAAK,MAAA,CAAO,MAAA,CAAO,CAAC,CAAA;AACnC,IAAA,MAAM,MAAA,GAAS,IAAA,CAAK,MAAA,CAAO,MAAA,CAAO,CAAC,CAAA;AACnC,IAAA,IAAI,CAAC,OAAO,MAAA,IAAU,CAAC,OAAO,MAAA,IAAU,CAAC,MAAA,CAAO,MAAA,EAAQ,OAAO,IAAA;AAC/D,IAAA,OAAO,EAAE,MAAA,EAAQ,MAAA,EAAQ,MAAA,EAAO;AAAA,EAClC;AAAA,EAEQ,QAAA,GAAqC;AAC3C,IAAA,MAAM,GAAA,GAAM,IAAA,CAAK,QAAA,CAAS,MAAA,CAAO,CAAC,CAAA;AAClC,IAAA,IAAI,CAAC,GAAA,CAAI,MAAA,EAAQ,OAAO,IAAA;AACxB,IAAA,OAAO,EAAE,GAAA,EAAI;AAAA,EACf;AAAA;AAAA,EAIA,KAAA,GAAc;AACZ,IAAA,IAAI,CAAC,KAAK,QAAA,EAAU;AAClB,MAAA,MAAM,KAAA,GAAQ,KAAK,cAAA,EAAe;AAClC,MAAA,IAAI,KAAA,EAAO;AACT,QAAA,IAAA,CAAK,QAAA,GAAW,IAAA;AAChB,QAAA,IAAA,CAAK,SAAA,CAAU,IAAA,CAAK,KAAK,CAAA,CAAE,QAAQ,MAAM;AAAE,UAAA,IAAA,CAAK,QAAA,GAAW,KAAA;AAAA,QAAO,CAAC,CAAA;AAAA,MACrE;AAAA,IACF;AACA,IAAA,IAAA,CAAK,QAAA,EAAS;AAAA,EAChB;AAAA,EAEA,QAAA,GAAiB;AACf,IAAA,MAAM,KAAA,GAAQ,KAAK,QAAA,EAAS;AAC5B,IAAA,IAAI,KAAA,EAAO,IAAA,CAAK,SAAA,CAAU,OAAA,CAAQ,KAAK,CAAA;AAAA,EACzC;AAAA,EAEA,WAAA,GAAoB;AAElB,IAAA,MAAM,KAAA,GAAQ,KAAK,cAAA,EAAe;AAClC,IAAA,IAAI,KAAA,EAAO;AACT,MAAA,IAAI,CAAC,KAAK,SAAA,CAAU,MAAA,CAAO,KAAK,CAAA,EAAG,IAAA,CAAK,SAAA,CAAU,IAAA,CAAK,KAAK,CAAA;AAAA,IAC9D;AAEA,IAAA,MAAM,QAAA,GAAW,KAAK,QAAA,EAAS;AAC/B,IAAA,IAAI,QAAA,EAAU;AACZ,MAAA,IAAI,CAAC,KAAK,SAAA,CAAU,SAAA,CAAU,QAAQ,CAAA,EAAG,IAAA,CAAK,SAAA,CAAU,OAAA,CAAQ,QAAQ,CAAA;AAAA,IAC1E;AAAA,EACF;AACF,CAAA;;;ACtHO,SAAS,mBAAA,CAAoB,SAAwB,GAAA,EAA0B;AACpF,EAAA,MAAM,WAAA,GAAc,CAAC,KAAA,KAAsB;AAf7C,IAAA,IAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA;AAgBI,IAAA,OAAA,CAAQ;AAAA,MACN,OAAA,EAAW,MAAM,OAAA,IAAW,eAAA;AAAA,MAC5B,KAAA,EAAW,OAAA;AAAA,MACX,KAAA,EAAW,OAAO,QAAA,CAAS,QAAA;AAAA,MAC3B,KAAA,EAAA,CAAW,EAAA,GAAA,KAAA,CAAM,KAAA,KAAN,IAAA,GAAA,MAAA,GAAA,EAAA,CAAa,KAAA;AAAA,MACxB,OAAA,EAAS;AAAA,QACP,GAAA,EAAQ,OAAO,QAAA,CAAS,IAAA;AAAA,QACxB,MAAA,EAAA,CAAQ,EAAA,GAAA,KAAA,CAAM,QAAA,KAAN,IAAA,GAAA,EAAA,GAAkB,MAAA;AAAA,QAC1B,IAAA,EAAA,CAAQ,EAAA,GAAA,KAAA,CAAM,MAAA,KAAN,IAAA,GAAA,EAAA,GAAiB,MAAA;AAAA,QACzB,GAAA,EAAA,CAAQ,EAAA,GAAA,KAAA,CAAM,KAAA,KAAN,IAAA,GAAA,EAAA,GAAiB;AAAA,OAC3B;AAAA,MACA,SAAA,EAAA,iBAAa,IAAI,IAAA,EAAK,EAAE,WAAA,EAAY;AAAA,MACpC,GAAI,GAAA,IAAO,EAAE,WAAA,EAAa,GAAA;AAAI,KAC/B,CAAA;AAAA,EACH,CAAA;AAEA,EAAA,MAAM,eAAA,GAAkB,CAAC,KAAA,KAAiC;AACxD,IAAA,MAAM,SAAS,KAAA,CAAM,MAAA;AACrB,IAAA,MAAM,QAAS,MAAA,YAAkB,KAAA;AACjC,IAAA,OAAA,CAAQ;AAAA,MACN,SAAW,KAAA,GAAQ,MAAA,CAAO,OAAA,GAAU,MAAA,CAAO,0BAAU,6BAA6B,CAAA;AAAA,MAClF,KAAA,EAAW,OAAA;AAAA,MACX,KAAA,EAAW,OAAO,QAAA,CAAS,QAAA;AAAA,MAC3B,KAAA,EAAW,KAAA,GAAQ,MAAA,CAAO,KAAA,GAAQ,MAAA;AAAA,MAClC,OAAA,EAAS;AAAA,QACP,GAAA,EAAM,OAAO,QAAA,CAAS,IAAA;AAAA,QACtB,IAAA,EAAM;AAAA,OACR;AAAA,MACA,SAAA,EAAA,iBAAa,IAAI,IAAA,EAAK,EAAE,WAAA,EAAY;AAAA,MACpC,GAAI,GAAA,IAAO,EAAE,WAAA,EAAa,GAAA;AAAI,KAC/B,CAAA;AAAA,EACH,CAAA;AAEA,EAAA,MAAA,CAAO,gBAAA,CAAiB,SAAsB,WAAW,CAAA;AACzD,EAAA,MAAA,CAAO,gBAAA,CAAiB,sBAAsB,eAAe,CAAA;AAE7D,EAAA,OAAO,MAAM;AACX,IAAA,MAAA,CAAO,mBAAA,CAAoB,SAAsB,WAAW,CAAA;AAC5D,IAAA,MAAA,CAAO,mBAAA,CAAoB,sBAAsB,eAAe,CAAA;AAAA,EAClE,CAAA;AACF;;;ACxCA,SAAS,MAAA,CACP,EAAA,EACA,IAAA,EACA,gBAAA,EACwB;AACxB,EAAA,IAAI,EAAA,IAAM,MAAkB,OAAO,IAAA;AACnC,EAAA,IAAI,EAAA,IAAM,kBAAkB,OAAO,MAAA;AACnC,EAAA,OAAO,KAAA;AACT;AAEA,SAAS,WAAW,MAAA,EAAwC;AAC1D,EAAA,OAAO,MAAA,KAAW,KAAA,GAAQ,GAAA,GAAM,MAAA,KAAW,SAAS,GAAA,GAAM,GAAA;AAC5D;AAIO,SAAS,UAAA,CAAW,SAAwB,GAAA,EAAoB;AACrE,EAAA,IAAI,OAAO,wBAAwB,WAAA,EAAa;AAChD,EAAA,IAAI;AACF,IAAA,MAAM,EAAA,GAAK,IAAI,mBAAA,CAAoB,CAAC,IAAA,KAAS;AAC3C,MAAA,KAAA,MAAW,KAAA,IAAS,IAAA,CAAK,UAAA,EAAW,EAAG;AACrC,QAAA,IAAI,KAAA,CAAM,SAAS,wBAAA,EAA0B;AAC7C,QAAA,MAAM,EAAA,GAAS,IAAA,CAAK,KAAA,CAAM,KAAA,CAAM,SAAS,CAAA;AACzC,QAAA,MAAM,MAAA,GAAS,MAAA,CAAO,EAAA,EAAI,IAAA,EAAM,GAAI,CAAA;AACpC,QAAA,OAAA,CAAQ;AAAA,UACN,IAAA,EAAa,eAAA;AAAA,UACb,EAAA;AAAA,UACA,WAAA,EAAa,WAAW,MAAM,CAAA;AAAA,UAC9B,MAAA;AAAA,UACA,SAAA,EAAA,iBAAa,IAAI,IAAA,EAAK,EAAE,WAAA,EAAY;AAAA,UACpC,GAAI,GAAA,IAAO,EAAE,WAAA,EAAa,GAAA;AAAI,SAC/B,CAAA;AACD,QAAA,EAAA,CAAG,UAAA,EAAW;AAAA,MAChB;AAAA,IACF,CAAC,CAAA;AACD,IAAA,EAAA,CAAG,QAAQ,EAAE,IAAA,EAAM,OAAA,EAAS,QAAA,EAAU,MAAM,CAAA;AAAA,EAC9C,CAAA,CAAA,MAAQ;AAAA,EAAkD;AAC5D;AAIO,SAAS,UAAA,CAAW,SAAwB,GAAA,EAAoB;AACrE,EAAA,IAAI,OAAO,wBAAwB,WAAA,EAAa;AAEhD,EAAA,IAAI,IAAA,GAAgC,IAAA;AACpC,EAAA,IAAI,QAAA,GAAW,KAAA;AAEf,EAAA,MAAM,SAAS,MAAM;AACnB,IAAA,IAAI,QAAA,IAAY,CAAC,IAAA,EAAM;AACvB,IAAA,QAAA,GAAW,IAAA;AACX,IAAA,IAAI;AAAE,MAAA,EAAA,CAAG,UAAA,EAAW;AAAA,IAAG,CAAA,CAAA,MAAQ;AAAA,IAAC;AAChC,IAAA,MAAM,EAAA,GAAS,IAAA,CAAK,KAAA,CAAM,IAAA,CAAK,SAAS,CAAA;AACxC,IAAA,MAAM,MAAA,GAAS,MAAA,CAAO,EAAA,EAAI,IAAA,EAAM,GAAI,CAAA;AACpC,IAAA,OAAA,CAAQ;AAAA,MACN,IAAA,EAAa,eAAA;AAAA,MACb,EAAA;AAAA,MACA,WAAA,EAAa,WAAW,MAAM,CAAA;AAAA,MAC9B,MAAA;AAAA,MACA,SAAA,EAAA,iBAAa,IAAI,IAAA,EAAK,EAAE,WAAA,EAAY;AAAA,MACpC,GAAI,GAAA,IAAO,EAAE,WAAA,EAAa,GAAA;AAAI,KAC/B,CAAA;AAAA,EACH,CAAA;AAEA,EAAA,IAAI,EAAA;AACJ,EAAA,IAAI;AACF,IAAA,EAAA,GAAK,IAAI,mBAAA,CAAoB,CAAC,IAAA,KAAS;AAjF3C,MAAA,IAAA,EAAA;AAkFM,MAAA,MAAM,OAAA,GAAU,KAAK,UAAA,EAAW;AAChC,MAAA,IAAI,OAAA,CAAQ,QAAQ,IAAA,GAAA,CAAO,EAAA,GAAA,OAAA,CAAQ,QAAQ,MAAA,GAAS,CAAC,MAA1B,IAAA,GAAA,EAAA,GAA+B,IAAA;AAAA,IAC5D,CAAC,CAAA;AACD,IAAA,EAAA,CAAG,QAAQ,EAAE,IAAA,EAAM,0BAAA,EAA4B,QAAA,EAAU,MAAM,CAAA;AAAA,EACjE,CAAA,CAAA,MAAQ;AACN,IAAA;AAAA,EACF;AAGA,EAAA,QAAA,CAAS,iBAAiB,kBAAA,EAAoB,MAAA,EAAQ,EAAE,IAAA,EAAM,MAAM,CAAA;AACpE,EAAA,QAAA,CAAS,gBAAA,CAAiB,WAAoB,MAAA,EAAQ,EAAE,MAAM,IAAA,EAAM,OAAA,EAAS,MAAM,CAAA;AACnF,EAAA,QAAA,CAAS,gBAAA,CAAiB,eAAoB,MAAA,EAAQ,EAAE,MAAM,IAAA,EAAM,OAAA,EAAS,MAAM,CAAA;AACrF;AAIO,SAAS,eAAA,CAAgB,SAAwB,GAAA,EAAoB;AAC1E,EAAA,MAAM,SAAS,MAAM;AACnB,IAAA,MAAM,GAAA,GAAM,WAAA,CAAY,gBAAA,CAAiB,YAAY,EAAE,CAAC,CAAA;AAExD,IAAA,IAAI,CAAC,GAAA,IAAO,GAAA,CAAI,YAAA,IAAgB,CAAA,EAAG;AAEnC,IAAA,MAAM,KAAS,IAAA,CAAK,KAAA,CAAM,GAAA,CAAI,YAAA,GAAe,IAAI,SAAS,CAAA;AAC1D,IAAA,MAAM,OAAS,IAAA,CAAK,KAAA,CAAM,GAAA,CAAI,aAAA,GAAgB,IAAI,YAAY,CAAA;AAC9D,IAAA,MAAM,MAAA,GAAS,MAAA,CAAO,EAAA,EAAI,GAAA,EAAM,GAAI,CAAA;AAEpC,IAAA,OAAA,CAAQ;AAAA,MACN,IAAA,EAAa,UAAA;AAAA,MACb,EAAA;AAAA,MACA,WAAA,EAAa,WAAW,MAAM,CAAA;AAAA,MAC9B,MAAA;AAAA,MACA,SAAA,EAAA,iBAAa,IAAI,IAAA,EAAK,EAAE,WAAA,EAAY;AAAA,MACpC,IAAA,EAAa,EAAE,IAAA,EAAK;AAAA,MACpB,GAAI,GAAA,IAAO,EAAE,WAAA,EAAa,GAAA;AAAI,KAC/B,CAAA;AAAA,EACH,CAAA;AAEA,EAAA,IAAI,QAAA,CAAS,eAAe,UAAA,EAAY;AAEtC,IAAA,UAAA,CAAW,QAAQ,CAAC,CAAA;AAAA,EACtB,CAAA,MAAO;AACL,IAAA,MAAA,CAAO,gBAAA,CAAiB,MAAA,EAAQ,MAAM,UAAA,CAAW,MAAA,EAAQ,GAAG,CAAA,EAAG,EAAE,IAAA,EAAM,IAAA,EAAM,CAAA;AAAA,EAC/E;AACF;;;AC7GA,IAAM,QAAA,GAAW;AAAA,EACf,OAAA,EAAe,0BAAA;AAAA,EACf,aAAA,EAAe,GAAA;AAAA,EACf,YAAA,EAAe,GAAA;AAAA,EACf,KAAA,EAAe,KAAA;AAAA,EACf,WAAA,EAAe,YAAA;AAAA,EACf,OAAA,EAAe,EAAA;AAAA,EACf,UAAA,EAAe,CAAA;AAAA,EACf,WAAA,EAAa;AAAA,IACX,MAAA,EAAa,IAAA;AAAA,IACb,WAAA,EAAa,IAAA;AAAA,IACb,SAAA,EAAa;AAAA;AAEjB,CAAA;AAIA,IAAM,WAAA,GAAc,WAAA;AACpB,IAAM,WAAA,GAAc,WAAA;AAIb,IAAM,UAAN,MAAc;AAAA,EA0BnB,YAAY,OAAA,EAAyB;AAvBrC,IAAA,IAAA,CAAiB,UAA6B,EAAC;AAM/C;AAAA;AAAA;AAAA;AAAA,IAAA,IAAA,CAAS,SAAA,GAAoB,OAAO,UAAA,EAAW;AAkB7C,IAAA,IAAI,CAAC,QAAQ,MAAA,EAAQ;AACnB,MAAA,MAAM,IAAI,MAAM,+BAA+B,CAAA;AAAA,IACjD;AAEA,IAAA,IAAA,CAAK,GAAA,GAAM;AAAA,MACT,GAAG,QAAA;AAAA,MACH,aAAa,EAAE,GAAG,SAAS,WAAA,EAAa,GAAG,QAAQ,WAAA,EAAY;AAAA,MAC/D,GAAG;AAAA,KACL;AAEA,IAAA,MAAM,SAAA,GAAY,IAAI,SAAA,CAAU,IAAA,CAAK,GAAA,CAAI,OAAA,EAAS,IAAA,CAAK,GAAA,CAAI,MAAA,EAAQ,IAAA,CAAK,GAAA,CAAI,KAAK,CAAA;AACjF,IAAA,IAAA,CAAK,OAAA,GAAa,IAAI,OAAA,CAAQ,SAAA,EAAW,KAAK,GAAA,CAAI,aAAA,EAAe,IAAA,CAAK,GAAA,CAAI,YAAY,CAAA;AACtF,IAAA,IAAA,CAAK,QAAQ,KAAA,EAAM;AAGnB,IAAA,IAAA,CAAK,SAAA,GAAc,KAAK,qBAAA,EAAsB;AAC9C,IAAA,IAAA,CAAK,YAAA,GAAe,KAAK,qBAAA,EAAsB;AAE/C,IAAA,IAAA,CAAK,iBAAA,EAAkB;AAAA,EACzB;AAAA;AAAA,EAIQ,qBAAA,GAAgC;AACtC,IAAA,IAAI;AACF,MAAA,IAAI,EAAA,GAAK,YAAA,CAAa,OAAA,CAAQ,WAAW,CAAA;AACzC,MAAA,IAAI,CAAC,EAAA,EAAI;AACP,QAAA,EAAA,GAAK,OAAO,UAAA,EAAW;AACvB,QAAA,YAAA,CAAa,OAAA,CAAQ,aAAa,EAAE,CAAA;AAAA,MACtC;AACA,MAAA,OAAO,EAAA;AAAA,IACT,CAAA,CAAA,MAAQ;AAEN,MAAA,OAAO,OAAO,UAAA,EAAW;AAAA,IAC3B;AAAA,EACF;AAAA,EAEQ,qBAAA,GAAgC;AACtC,IAAA,IAAI;AACF,MAAA,IAAI,EAAA,GAAK,cAAA,CAAe,OAAA,CAAQ,WAAW,CAAA;AAC3C,MAAA,IAAI,CAAC,EAAA,EAAI;AACP,QAAA,EAAA,GAAK,OAAO,UAAA,EAAW;AACvB,QAAA,cAAA,CAAe,OAAA,CAAQ,aAAa,EAAE,CAAA;AAAA,MACxC;AACA,MAAA,OAAO,EAAA;AAAA,IACT,CAAA,CAAA,MAAQ;AACN,MAAA,OAAO,IAAA,CAAK,SAAA;AAAA,IACd;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,KAAA,CAAM,MAAc,UAAA,EAA4C;AAC9D,IAAA,IAAI,CAAC,IAAA,EAAM;AACX,IAAA,MAAM,KAAA,GAAsB;AAAA,MAC1B,IAAA;AAAA,MACA,GAAI,cAAc,MAAA,CAAO,IAAA,CAAK,UAAU,CAAA,CAAE,MAAA,IAAU,EAAE,UAAA,EAAW;AAAA,MACjE,WAAA,EAAA,iBAAa,IAAI,IAAA,EAAK,EAAE,WAAA;AAAY,KACtC;AACA,IAAA,IAAA,CAAK,OAAA,CAAQ,SAAS,KAAK,CAAA;AAAA,EAC7B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,YAAA,CAAa,SAAA,GAA0C,EAAC,EAAS;AA9InE,IAAA,IAAA,EAAA,EAAA,EAAA;AA+II,IAAA,MAAM,GAAA,GAAS,IAAI,GAAA,CAAI,MAAA,CAAO,SAAS,IAAI,CAAA;AAC3C,IAAA,MAAM,SAAS,GAAA,CAAI,YAAA;AAEnB,IAAA,MAAM,OAAA,GAA+B;AAAA,MACnC,IAAA,EAAa,GAAA,CAAI,QAAA,IAAY,GAAA,CAAI,MAAA,IAAU,EAAA,CAAA;AAAA,MAC3C,UAAa,GAAA,CAAI,QAAA;AAAA,MACjB,QAAA,EAAa,SAAS,QAAA,IAAY,MAAA;AAAA,MAClC,KAAA,EAAa,SAAS,KAAA,IAAW,MAAA;AAAA,MACjC,QAAA,EAAA,CAAa,EAAA,GAAA,MAAA,CAAO,MAAA,KAAP,IAAA,GAAA,MAAA,GAAA,EAAA,CAAe,KAAA;AAAA,MAC5B,QAAA,EAAA,CAAa,EAAA,GAAA,MAAA,CAAO,MAAA,KAAP,IAAA,GAAA,MAAA,GAAA,EAAA,CAAe,MAAA;AAAA,MAC5B,IAAA,EAAa,UAAU,QAAA,IAAY,MAAA;AAAA,MACnC,QAAA,EAAa,KAAK,SAAA,EAAU;AAAA;AAAA,MAE5B,UAAA,EAAc,MAAA,CAAO,GAAA,CAAI,YAAY,CAAA,IAAO,MAAA;AAAA,MAC5C,UAAA,EAAc,MAAA,CAAO,GAAA,CAAI,YAAY,CAAA,IAAO,MAAA;AAAA,MAC5C,YAAA,EAAc,MAAA,CAAO,GAAA,CAAI,cAAc,CAAA,IAAK,MAAA;AAAA,MAC5C,QAAA,EAAc,MAAA,CAAO,GAAA,CAAI,UAAU,CAAA,IAAS,MAAA;AAAA,MAC5C,WAAA,EAAc,MAAA,CAAO,GAAA,CAAI,aAAa,CAAA,IAAM,MAAA;AAAA;AAAA,MAE5C,YAAa,IAAA,CAAK,SAAA;AAAA,MAClB,YAAa,IAAA,CAAK,YAAA;AAAA,MAClB,UAAA,EAAa,UAAA;AAAA,MACb,WAAA,EAAA,iBAAa,IAAI,IAAA,EAAK,EAAE,WAAA,EAAY;AAAA;AAAA,MAEpC,GAAG;AAAA,KACL;AAEA,IAAA,IAAA,CAAK,OAAA,CAAQ,WAAW,OAAO,CAAA;AAAA,EACjC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,YAAA,CACE,OACA,OAAA,EACM;AACN,IAAA,MAAM,EAAE,OAAO,KAAA,GAAQ,OAAA,EAAS,GAAG,IAAA,EAAK,GAAI,4BAAW,EAAC;AACxD,IAAA,MAAM,GAAA,GAAM,iBAAiB,KAAA,GAAQ,KAAA,GAAQ,IAAI,KAAA,CAAM,MAAA,CAAO,KAAK,CAAC,CAAA;AAEpE,IAAA,MAAM,OAAA,GAAwB;AAAA,MAC5B,SAAS,GAAA,CAAI,OAAA;AAAA,MACb,KAAA;AAAA,MACA,GAAI,GAAA,CAAI,KAAA,KAAU,UAAa,EAAE,KAAA,EAAO,IAAI,KAAA,EAAM;AAAA,MAClD,KAAA,EAAS,KAAA,IAAA,IAAA,GAAA,KAAA,GAAS,MAAA,CAAO,QAAA,CAAS,QAAA;AAAA,MAClC,GAAI,MAAA,CAAO,IAAA,CAAK,IAAI,EAAE,MAAA,IAAU;AAAA,QAC9B,SAAS,EAAE,GAAG,MAAM,GAAA,EAAK,MAAA,CAAO,SAAS,IAAA;AAAK,OAChD;AAAA,MACA,SAAA,EAAA,iBAAa,IAAI,IAAA,EAAK,EAAE,WAAA,EAAY;AAAA,MACpC,WAAA,EAAa,KAAK,GAAA,CAAI,WAAA;AAAA,MACtB,GAAI,KAAK,GAAA,CAAI,OAAA,IAAW,EAAE,OAAA,EAAS,IAAA,CAAK,IAAI,OAAA;AAAQ,KACtD;AAEA,IAAA,IAAA,CAAK,OAAA,CAAQ,SAAS,OAAO,CAAA;AAAA,EAC/B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,WACE,IAAA,EACsF;AACtF,IAAA,MAAM,KAAA,GAAQ,KAAK,GAAA,EAAI;AACvB,IAAA,OAAO,CAAC,IAAA,GAAO,EAAC,KAAM;AAzN1B,MAAA,IAAA,EAAA;AA0NM,MAAA,MAAM,MAAA,GAAA,CAAS,EAAA,GAAA,IAAA,CAAK,MAAA,KAAL,IAAA,GAAA,EAAA,GAAe,IAAA;AAC9B,MAAA,IAAA,CAAK,QAAQ,QAAA,CAAS;AAAA,QACpB,IAAA;AAAA,QACA,EAAA,EAAa,IAAA,CAAK,GAAA,EAAI,GAAI,KAAA;AAAA,QAC1B,aAAa,MAAA,KAAW,KAAA,GAAQ,GAAA,GAAM,MAAA,KAAW,SAAS,GAAA,GAAM,GAAA;AAAA,QAChE,MAAA;AAAA,QACA,SAAA,EAAA,iBAAa,IAAI,IAAA,EAAK,EAAE,WAAA,EAAY;AAAA,QACpC,WAAA,EAAa,KAAK,GAAA,CAAI,WAAA;AAAA,QACtB,GAAI,KAAK,GAAA,CAAI,OAAA,IAAW,EAAE,OAAA,EAAS,IAAA,CAAK,IAAI,OAAA,EAAQ;AAAA,QACpD,GAAI,IAAA,CAAK,IAAA,IAAe,EAAE,IAAA,EAAM,KAAK,IAAA;AAAK,OAC3C,CAAA;AAAA,IACH,CAAA;AAAA,EACF;AAAA;AAAA,EAGA,KAAA,GAAc;AAAE,IAAA,IAAA,CAAK,QAAQ,KAAA,EAAM;AAAA,EAAG;AAAA;AAAA,EAGtC,QAAA,GAAiB;AACf,IAAA,IAAA,CAAK,QAAQ,IAAA,EAAK;AAClB,IAAA,IAAA,CAAK,QAAQ,KAAA,EAAM;AACnB,IAAA,IAAA,CAAK,OAAA,CAAQ,OAAA,CAAQ,CAAC,EAAA,KAAO,IAAI,CAAA;AAAA,EACnC;AAAA;AAAA,EAIQ,iBAAA,GAA0B;AAChC,IAAA,MAAM,EAAE,WAAA,EAAa,WAAA,EAAY,GAAI,IAAA,CAAK,GAAA;AAE1C,IAAA,IAAI,YAAY,MAAA,EAAQ;AACtB,MAAA,IAAA,CAAK,OAAA,CAAQ,IAAA;AAAA,QACX,mBAAA,CAAoB,CAAC,CAAA,KAAM,IAAA,CAAK,QAAQ,QAAA,CAAS,CAAC,GAAG,WAAW;AAAA,OAClE;AAAA,IACF;AAEA,IAAA,IAAI,YAAY,WAAA,EAAa;AAC3B,MAAA,UAAA,CAAW,CAAC,CAAA,KAAW,IAAA,CAAK,QAAQ,QAAA,CAAS,CAAC,GAAG,WAAW,CAAA;AAC5D,MAAA,UAAA,CAAW,CAAC,CAAA,KAAW,IAAA,CAAK,QAAQ,QAAA,CAAS,CAAC,GAAG,WAAW,CAAA;AAC5D,MAAA,eAAA,CAAgB,CAAC,CAAA,KAAM,IAAA,CAAK,QAAQ,QAAA,CAAS,CAAC,GAAG,WAAW,CAAA;AAAA,IAC9D;AAEA,IAAA,IAAI,YAAY,SAAA,EAAW;AACzB,MAAA,IAAA,CAAK,sBAAA,EAAuB;AAAA,IAC9B;AAAA,EACF;AAAA,EAEQ,sBAAA,GAA+B;AACrC,IAAA,MAAM,YAAY,MAAM;AAEtB,MAAA,UAAA,CAAW,MAAM,IAAA,CAAK,YAAA,EAAa,EAAG,CAAC,CAAA;AAAA,IACzC,CAAA;AAGA,IAAA,IAAI,QAAA,CAAS,eAAe,SAAA,EAAW;AACrC,MAAA,QAAA,CAAS,iBAAiB,kBAAA,EAAoB,SAAA,EAAW,EAAE,IAAA,EAAM,MAAM,CAAA;AAAA,IACzE,CAAA,MAAO;AACL,MAAA,UAAA,CAAW,MAAM,IAAA,CAAK,YAAA,EAAa,EAAG,CAAC,CAAA;AAAA,IACzC;AAGA,IAAA,MAAM,QAAA,GAAc,OAAA,CAAQ,SAAA,CAAU,IAAA,CAAK,OAAO,CAAA;AAClD,IAAA,MAAM,WAAA,GAAc,OAAA,CAAQ,YAAA,CAAa,IAAA,CAAK,OAAO,CAAA;AAErD,IAAA,OAAA,CAAQ,SAAA,GAAY,IAAI,IAAA,KAA+C;AACrE,MAAA,QAAA,CAAS,GAAG,IAAI,CAAA;AAChB,MAAA,SAAA,EAAU;AAAA,IACZ,CAAA;AACA,IAAA,OAAA,CAAQ,YAAA,GAAe,IAAI,IAAA,KAAkD;AAC3E,MAAA,WAAA,CAAY,GAAG,IAAI,CAAA;AAAA,IAErB,CAAA;AAEA,IAAA,MAAM,UAAA,GAAa,MAAM,SAAA,EAAU;AACnC,IAAA,MAAA,CAAO,gBAAA,CAAiB,YAAY,UAAU,CAAA;AAE9C,IAAA,IAAA,CAAK,OAAA,CAAQ,KAAK,MAAM;AACtB,MAAA,OAAA,CAAQ,SAAA,GAAe,QAAA;AACvB,MAAA,OAAA,CAAQ,YAAA,GAAe,WAAA;AACvB,MAAA,MAAA,CAAO,mBAAA,CAAoB,YAAY,UAAU,CAAA;AAAA,IACnD,CAAC,CAAA;AAAA,EACH;AAAA;AAAA,EAIQ,SAAA,GAAgC;AACtC,IAAA,IAAI;AACF,MAAA,OAAO,IAAA,CAAK,cAAA,EAAe,CAAE,eAAA,GAAkB,QAAA,IAAY,KAAA,CAAA;AAAA,IAC7D,CAAA,CAAA,MAAQ;AACN,MAAA,OAAO,MAAA;AAAA,IACT;AAAA,EACF;AACF","file":"index.mjs","sourcesContent":["// ─────────────────────────────────────────────────────────────────────────────\n// @watchupltd/browser · transport\n//\n// Two delivery strategies:\n// 1. fetch(keepalive: true) — for regular periodic flushes.\n// 2. navigator.sendBeacon — for page-hide/unload; survives tab close.\n//\n// Web analytics events are sent to a separate endpoint (/web-batch) that is\n// optimised for high-volume, low-latency browser hits.\n// ─────────────────────────────────────────────────────────────────────────────\n\nimport type { IngestBatch, WebAnalyticsBatch } from './types.js';\n\nexport class Transport {\n private readonly url: string;\n private readonly webUrl: string;\n private readonly headers: Record<string, string>;\n private readonly debug: boolean;\n\n constructor(baseUrl: string, apiKey: string, debug = false) {\n const base = baseUrl.replace(/\\/$/, '');\n this.url = `${base}/api/v1/ingest/batch`;\n this.webUrl = `${base}/api/v1/ingest/web-batch`;\n this.headers = {\n 'Content-Type': 'application/json',\n 'X-Api-Key': apiKey,\n };\n this.debug = debug;\n }\n\n /**\n * Send via `fetch` with `keepalive: true`.\n * `keepalive` lets the request outlive the current page — it's the\n * browser equivalent of a \"fire and forget\" POST.\n * Never rejects.\n */\n async send(batch: IngestBatch): Promise<void> {\n try {\n const body = JSON.stringify(batch);\n\n // keepalive has a 64 KiB payload limit; fall back to beacon for large batches\n if (body.length > 60_000) {\n this.beacon(batch);\n return;\n }\n\n const res = await fetch(this.url, {\n method: 'POST',\n headers: this.headers,\n body,\n keepalive: true,\n });\n\n if (this.debug && !res.ok) {\n const text = await res.text().catch(() => '');\n console.warn(`[watchup] ingest ${res.status}: ${text}`);\n }\n } catch (err) {\n if (this.debug) console.warn('[watchup] send failed:', err);\n }\n }\n\n /**\n * Send web analytics batch to the dedicated /web-batch endpoint.\n * Never rejects.\n */\n async sendWeb(batch: WebAnalyticsBatch): Promise<void> {\n try {\n const body = JSON.stringify(batch);\n\n if (body.length > 60_000) {\n this.beaconWeb(batch);\n return;\n }\n\n const res = await fetch(this.webUrl, {\n method: 'POST',\n headers: this.headers,\n body,\n keepalive: true,\n });\n\n if (this.debug && !res.ok) {\n const text = await res.text().catch(() => '');\n console.warn(`[watchup] web-batch ${res.status}: ${text}`);\n }\n } catch (err) {\n if (this.debug) console.warn('[watchup] sendWeb failed:', err);\n }\n }\n\n /**\n * Send via `navigator.sendBeacon`.\n * Returns `true` if the browser accepted the request (doesn't guarantee delivery).\n * The server must accept `application/json` from sendBeacon via a Blob.\n */\n beacon(batch: IngestBatch): boolean {\n if (typeof navigator === 'undefined' || !navigator.sendBeacon) return false;\n try {\n const blob = new Blob([JSON.stringify(batch)], { type: 'application/json' });\n return navigator.sendBeacon(this.url, blob);\n } catch {\n return false;\n }\n }\n\n /**\n * sendBeacon variant for web analytics events.\n */\n beaconWeb(batch: WebAnalyticsBatch): boolean {\n if (typeof navigator === 'undefined' || !navigator.sendBeacon) return false;\n try {\n const blob = new Blob([JSON.stringify(batch)], { type: 'application/json' });\n return navigator.sendBeacon(this.webUrl, blob);\n } catch {\n return false;\n }\n }\n}\n","// ─────────────────────────────────────────────────────────────────────────────\n// @watchupltd/browser · batcher\n//\n// Browser-specific flush strategy:\n// - Periodic interval flush via fetch(keepalive)\n// - visibilitychange 'hidden' + pagehide → sendBeacon for reliable exit delivery\n//\n// Two independent queues:\n// - telemetry queue (traces, errors, events) → /ingest/batch\n// - web queue (web page views) → /ingest/web-batch\n// ─────────────────────────────────────────────────────────────────────────────\n\nimport type {\n TracePayload,\n ErrorPayload,\n EventPayload,\n IngestBatch,\n WebAnalyticsPayload,\n WebAnalyticsBatch,\n} from './types.js';\nimport { Transport } from './transport.js';\n\nexport class Batcher {\n private traces: TracePayload[] = [];\n private errors: ErrorPayload[] = [];\n private events: EventPayload[] = [];\n private webViews: WebAnalyticsPayload[] = [];\n\n private readonly transport: Transport;\n private readonly flushInterval: number;\n private readonly maxBatchSize: number;\n\n private timer: ReturnType<typeof setInterval> | null = null;\n private flushing = false;\n\n constructor(transport: Transport, flushInterval: number, maxBatchSize: number) {\n this.transport = transport;\n this.flushInterval = flushInterval;\n this.maxBatchSize = maxBatchSize;\n }\n\n start(): void {\n if (this.timer) return;\n\n // Periodic flush\n this.timer = setInterval(() => this.flush(), this.flushInterval);\n\n // Reliable delivery on tab hide — visibilitychange fires before the page\n // is destroyed, giving sendBeacon the best chance of succeeding.\n document.addEventListener('visibilitychange', () => {\n if (document.visibilityState === 'hidden') this.beaconFlush();\n });\n\n // Belt-and-suspenders for browsers/environments that skip visibilitychange\n window.addEventListener('pagehide', () => this.beaconFlush(), { once: true });\n }\n\n stop(): void {\n if (this.timer) { clearInterval(this.timer); this.timer = null; }\n }\n\n // ── Telemetry queue ───────────────────────────────────────────────────────\n\n addTrace(t: TracePayload): void {\n this.traces.push(t);\n if (this.traces.length >= this.maxBatchSize) this.flush();\n }\n\n addError(e: ErrorPayload): void {\n this.errors.push(e);\n // Errors are high-priority — flush at half capacity\n if (this.errors.length >= Math.ceil(this.maxBatchSize / 2)) this.flush();\n }\n\n addEvent(e: EventPayload): void {\n this.events.push(e);\n if (this.events.length >= this.maxBatchSize) this.flush();\n }\n\n // ── Web analytics queue ───────────────────────────────────────────────────\n\n addWebView(payload: WebAnalyticsPayload): void {\n this.webViews.push(payload);\n if (this.webViews.length >= this.maxBatchSize) this.flushWeb();\n }\n\n // ── Drain helpers ─────────────────────────────────────────────────────────\n\n private drainTelemetry(): IngestBatch | null {\n const traces = this.traces.splice(0);\n const errors = this.errors.splice(0);\n const events = this.events.splice(0);\n if (!traces.length && !errors.length && !events.length) return null;\n return { traces, errors, events };\n }\n\n private drainWeb(): WebAnalyticsBatch | null {\n const web = this.webViews.splice(0);\n if (!web.length) return null;\n return { web };\n }\n\n // ── Flush ─────────────────────────────────────────────────────────────────\n\n flush(): void {\n if (!this.flushing) {\n const batch = this.drainTelemetry();\n if (batch) {\n this.flushing = true;\n this.transport.send(batch).finally(() => { this.flushing = false; });\n }\n }\n this.flushWeb();\n }\n\n flushWeb(): void {\n const batch = this.drainWeb();\n if (batch) this.transport.sendWeb(batch);\n }\n\n beaconFlush(): void {\n // Telemetry\n const batch = this.drainTelemetry();\n if (batch) {\n if (!this.transport.beacon(batch)) this.transport.send(batch);\n }\n // Web analytics\n const webBatch = this.drainWeb();\n if (webBatch) {\n if (!this.transport.beaconWeb(webBatch)) this.transport.sendWeb(webBatch);\n }\n }\n}\n","// ─────────────────────────────────────────────────────────────────────────────\n// @watchupltd/browser · global error capture\n// ─────────────────────────────────────────────────────────────────────────────\n\nimport type { ErrorPayload } from './types.js';\n\ntype ErrorCallback = (error: ErrorPayload) => void;\n\n/**\n * Attaches `window.onerror` and `window.addEventListener('unhandledrejection')`\n * listeners that forward caught errors to `onError`.\n *\n * Returns a cleanup function that removes both listeners.\n */\nexport function captureGlobalErrors(onError: ErrorCallback, env?: string): () => void {\n const handleError = (event: ErrorEvent) => {\n onError({\n message: event.message || 'Unknown error',\n level: 'error',\n route: window.location.pathname,\n stack: event.error?.stack,\n context: {\n url: window.location.href,\n source: event.filename ?? undefined,\n line: event.lineno ?? undefined,\n col: event.colno ?? undefined,\n },\n timestamp: new Date().toISOString(),\n ...(env && { environment: env }),\n });\n };\n\n const handleRejection = (event: PromiseRejectionEvent) => {\n const reason = event.reason;\n const isErr = reason instanceof Error;\n onError({\n message: isErr ? reason.message : String(reason ?? 'Unhandled Promise rejection'),\n level: 'error',\n route: window.location.pathname,\n stack: isErr ? reason.stack : undefined,\n context: {\n url: window.location.href,\n type: 'unhandledrejection',\n },\n timestamp: new Date().toISOString(),\n ...(env && { environment: env }),\n });\n };\n\n window.addEventListener('error', handleError);\n window.addEventListener('unhandledrejection', handleRejection);\n\n return () => {\n window.removeEventListener('error', handleError);\n window.removeEventListener('unhandledrejection', handleRejection);\n };\n}\n","// ─────────────────────────────────────────────────────────────────────────────\n// @watchupltd/browser · Web Vitals capture\n//\n// Captures FCP, LCP, and overall page-load time via PerformanceObserver and\n// PerformanceNavigationTiming. Forwarded as traces so they appear in the\n// Watchup dashboard alongside request spans.\n//\n// Thresholds come from Google's Core Web Vitals 2024 targets:\n// FCP: good ≤ 1800 ms, needs improvement ≤ 3000 ms, poor > 3000 ms\n// LCP: good ≤ 2500 ms, needs improvement ≤ 4000 ms, poor > 4000 ms\n// ─────────────────────────────────────────────────────────────────────────────\n\nimport type { TracePayload } from './types.js';\n\ntype TraceCallback = (trace: TracePayload) => void;\n\nfunction rating(\n ms: number,\n good: number,\n needsImprovement: number,\n): TracePayload['status'] {\n if (ms <= good) return 'ok';\n if (ms <= needsImprovement) return 'warn';\n return 'err';\n}\n\nfunction statusCode(status: TracePayload['status']): number {\n return status === 'err' ? 500 : status === 'warn' ? 400 : 200;\n}\n\n// ── FCP — First Contentful Paint ─────────────────────────────────────────────\n\nexport function captureFCP(onTrace: TraceCallback, env?: string): void {\n if (typeof PerformanceObserver === 'undefined') return;\n try {\n const po = new PerformanceObserver((list) => {\n for (const entry of list.getEntries()) {\n if (entry.name !== 'first-contentful-paint') continue;\n const ms = Math.round(entry.startTime);\n const status = rating(ms, 1800, 3000);\n onTrace({\n span: 'web-vital fcp',\n ms,\n status_code: statusCode(status),\n status,\n timestamp: new Date().toISOString(),\n ...(env && { environment: env }),\n });\n po.disconnect();\n }\n });\n po.observe({ type: 'paint', buffered: true });\n } catch { /* PerformanceObserver 'paint' not supported */ }\n}\n\n// ── LCP — Largest Contentful Paint ───────────────────────────────────────────\n\nexport function captureLCP(onTrace: TraceCallback, env?: string): void {\n if (typeof PerformanceObserver === 'undefined') return;\n\n let last: PerformanceEntry | null = null;\n let reported = false;\n\n const report = () => {\n if (reported || !last) return;\n reported = true;\n try { po.disconnect(); } catch {}\n const ms = Math.round(last.startTime);\n const status = rating(ms, 2500, 4000);\n onTrace({\n span: 'web-vital lcp',\n ms,\n status_code: statusCode(status),\n status,\n timestamp: new Date().toISOString(),\n ...(env && { environment: env }),\n });\n };\n\n let po: PerformanceObserver;\n try {\n po = new PerformanceObserver((list) => {\n const entries = list.getEntries();\n if (entries.length) last = entries[entries.length - 1] ?? null;\n });\n po.observe({ type: 'largest-contentful-paint', buffered: true });\n } catch {\n return; // 'largest-contentful-paint' not supported\n }\n\n // LCP is only finalised once the user interacts or the tab hides.\n document.addEventListener('visibilitychange', report, { once: true });\n document.addEventListener('keydown', report, { once: true, capture: true });\n document.addEventListener('pointerdown', report, { once: true, capture: true });\n}\n\n// ── Page load (overall) ───────────────────────────────────────────────────────\n\nexport function capturePageLoad(onTrace: TraceCallback, env?: string): void {\n const report = () => {\n const nav = performance.getEntriesByType('navigation')[0] as\n PerformanceNavigationTiming | undefined;\n if (!nav || nav.loadEventEnd <= 0) return;\n\n const ms = Math.round(nav.loadEventEnd - nav.startTime);\n const ttfb = Math.round(nav.responseStart - nav.requestStart);\n const status = rating(ms, 2000, 4000);\n\n onTrace({\n span: 'pageload',\n ms,\n status_code: statusCode(status),\n status,\n timestamp: new Date().toISOString(),\n meta: { ttfb },\n ...(env && { environment: env }),\n });\n };\n\n if (document.readyState === 'complete') {\n // PerformanceNavigationTiming might not be fully populated yet\n setTimeout(report, 0);\n } else {\n window.addEventListener('load', () => setTimeout(report, 100), { once: true });\n }\n}\n","// ─────────────────────────────────────────────────────────────────────────────\n// @watchupltd/browser · Watchup client\n// ─────────────────────────────────────────────────────────────────────────────\n\nimport type {\n WatchupOptions,\n TracePayload,\n ErrorPayload,\n EventPayload,\n WebAnalyticsPayload,\n} from './types.js';\nimport { Transport } from './transport.js';\nimport { Batcher } from './batcher.js';\nimport { captureGlobalErrors } from './error-capture.js';\nimport { captureFCP, captureLCP, capturePageLoad } from './perf.js';\n\nconst DEFAULTS = {\n baseUrl: 'https://api.watchup.site',\n flushInterval: 5_000,\n maxBatchSize: 100,\n debug: false,\n environment: 'production',\n release: '',\n sampleRate: 1,\n autoCapture: {\n errors: true,\n performance: true,\n pageViews: true,\n },\n} as const;\n\n// ── Storage keys ──────────────────────────────────────────────────────────────\n\nconst VISITOR_KEY = '__wup_vid';\nconst SESSION_KEY = '__wup_sid';\n\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport class Watchup {\n private readonly cfg: Required<WatchupOptions>;\n private readonly batcher: Batcher;\n private readonly cleanup: Array<() => void> = [];\n\n /**\n * A random UUID generated on init. Stable for the lifetime of the page —\n * useful for correlating all events from one user session.\n */\n readonly sessionId: string = crypto.randomUUID();\n\n // ── Visitor / session identity ─────────────────────────────────────────────\n\n /**\n * Persistent visitor ID. Stored in localStorage so it survives browser\n * sessions. Falls back to a per-session UUID when localStorage is blocked.\n * The server hashes this value with SHA-256 before persisting.\n */\n private readonly visitorId: string;\n\n /**\n * Per-session ID stored in sessionStorage. Resets on tab close.\n * The server hashes this value before persisting.\n */\n private readonly webSessionId: string;\n\n constructor(options: WatchupOptions) {\n if (!options.apiKey) {\n throw new Error('[watchup] apiKey is required.');\n }\n\n this.cfg = {\n ...DEFAULTS,\n autoCapture: { ...DEFAULTS.autoCapture, ...options.autoCapture },\n ...options,\n } as Required<WatchupOptions>;\n\n const transport = new Transport(this.cfg.baseUrl, this.cfg.apiKey, this.cfg.debug);\n this.batcher = new Batcher(transport, this.cfg.flushInterval, this.cfg.maxBatchSize);\n this.batcher.start();\n\n // Initialise visitor & session IDs\n this.visitorId = this._getOrCreateVisitorId();\n this.webSessionId = this._getOrCreateSessionId();\n\n this._setupAutoCapture();\n }\n\n // ── Visitor / session identity helpers ─────────────────────────────────────\n\n private _getOrCreateVisitorId(): string {\n try {\n let id = localStorage.getItem(VISITOR_KEY);\n if (!id) {\n id = crypto.randomUUID();\n localStorage.setItem(VISITOR_KEY, id);\n }\n return id;\n } catch {\n // localStorage blocked (private mode, etc.) — fall back to session scope\n return crypto.randomUUID();\n }\n }\n\n private _getOrCreateSessionId(): string {\n try {\n let id = sessionStorage.getItem(SESSION_KEY);\n if (!id) {\n id = crypto.randomUUID();\n sessionStorage.setItem(SESSION_KEY, id);\n }\n return id;\n } catch {\n return this.sessionId; // fallback: correlate with SDK sessionId\n }\n }\n\n // ── Public API ────────────────────────────────────────────────────────────\n\n /**\n * Track a custom analytics event.\n *\n * @example\n * watchup.track('button.clicked', { label: 'Sign Up', variant: 'A' });\n */\n track(name: string, properties?: Record<string, unknown>): void {\n if (!name) return;\n const event: EventPayload = {\n name,\n ...(properties && Object.keys(properties).length && { properties }),\n occurred_at: new Date().toISOString(),\n };\n this.batcher.addEvent(event);\n }\n\n /**\n * Track a web analytics page view (or custom web event).\n * Enriches the payload with visitor context, UTM params, and device info.\n *\n * Normally called automatically. Call manually when you need custom event_name.\n *\n * @example\n * watchup.trackWebView({ event_name: 'conversion', path: '/checkout/success' });\n */\n trackWebView(overrides: Partial<WebAnalyticsPayload> = {}): void {\n const url = new URL(window.location.href);\n const params = url.searchParams;\n\n const payload: WebAnalyticsPayload = {\n path: url.pathname + (url.search || ''),\n hostname: url.hostname,\n referrer: document.referrer || undefined,\n title: document.title || undefined,\n screen_w: window.screen?.width,\n screen_h: window.screen?.height,\n lang: navigator.language || undefined,\n timezone: this._timezone(),\n // UTM parameters\n utm_source: params.get('utm_source') || undefined,\n utm_medium: params.get('utm_medium') || undefined,\n utm_campaign: params.get('utm_campaign') || undefined,\n utm_term: params.get('utm_term') || undefined,\n utm_content: params.get('utm_content') || undefined,\n // Identity (raw; the server hashes before storing)\n visitor_id: this.visitorId,\n session_id: this.webSessionId,\n event_name: 'pageview',\n occurred_at: new Date().toISOString(),\n // Apply caller overrides last\n ...overrides,\n };\n\n this.batcher.addWebView(payload);\n }\n\n /**\n * Manually capture an error.\n *\n * @example\n * try { ... } catch (err) {\n * watchup.captureError(err, { component: 'CheckoutForm' });\n * }\n */\n captureError(\n error: Error | string | unknown,\n context?: Record<string, unknown> & { route?: string; level?: ErrorPayload['level'] },\n ): void {\n const { route, level = 'error', ...rest } = context ?? {};\n const err = error instanceof Error ? error : new Error(String(error));\n\n const payload: ErrorPayload = {\n message: err.message,\n level,\n ...(err.stack !== undefined && { stack: err.stack }),\n route: route ?? window.location.pathname,\n ...(Object.keys(rest).length && {\n context: { ...rest, url: window.location.href },\n }),\n timestamp: new Date().toISOString(),\n environment: this.cfg.environment,\n ...(this.cfg.release && { release: this.cfg.release }),\n };\n\n this.batcher.addError(payload);\n }\n\n /**\n * Time any async operation and record it as a trace.\n * Returns an `end()` function — call it when the operation finishes.\n *\n * @example\n * const end = watchup.startTrace('fetch /api/cart');\n * const cart = await fetch('/api/cart');\n * end({ status: cart.ok ? 'ok' : 'err' });\n */\n startTrace(\n span: string,\n ): (opts?: { status?: TracePayload['status']; meta?: Record<string, unknown> }) => void {\n const start = Date.now();\n return (opts = {}) => {\n const status = opts.status ?? 'ok';\n this.batcher.addTrace({\n span,\n ms: Date.now() - start,\n status_code: status === 'err' ? 500 : status === 'warn' ? 400 : 200,\n status,\n timestamp: new Date().toISOString(),\n environment: this.cfg.environment,\n ...(this.cfg.release && { release: this.cfg.release }),\n ...(opts.meta && { meta: opts.meta }),\n });\n };\n }\n\n /** Immediately flush all queued items (both telemetry and web analytics). */\n flush(): void { this.batcher.flush(); }\n\n /** Stop the flush timer and release all listeners. */\n shutdown(): void {\n this.batcher.stop();\n this.batcher.flush();\n this.cleanup.forEach((fn) => fn());\n }\n\n // ── Auto-capture setup ────────────────────────────────────────────────────\n\n private _setupAutoCapture(): void {\n const { autoCapture, environment } = this.cfg;\n\n if (autoCapture.errors) {\n this.cleanup.push(\n captureGlobalErrors((e) => this.batcher.addError(e), environment),\n );\n }\n\n if (autoCapture.performance) {\n captureFCP((t) => this.batcher.addTrace(t), environment);\n captureLCP((t) => this.batcher.addTrace(t), environment);\n capturePageLoad((t) => this.batcher.addTrace(t), environment);\n }\n\n if (autoCapture.pageViews) {\n this._setupPageViewTracking();\n }\n }\n\n private _setupPageViewTracking(): void {\n const trackView = () => {\n // Small delay so the page title has settled after navigation\n setTimeout(() => this.trackWebView(), 0);\n };\n\n // Initial view\n if (document.readyState === 'loading') {\n document.addEventListener('DOMContentLoaded', trackView, { once: true });\n } else {\n setTimeout(() => this.trackWebView(), 0);\n }\n\n // SPA navigation — patch History API\n const origPush = history.pushState.bind(history);\n const origReplace = history.replaceState.bind(history);\n\n history.pushState = (...args: Parameters<typeof history.pushState>) => {\n origPush(...args);\n trackView();\n };\n history.replaceState = (...args: Parameters<typeof history.replaceState>) => {\n origReplace(...args);\n // replaceState is often used for URL canonicalisation — don't track.\n };\n\n const onPopState = () => trackView();\n window.addEventListener('popstate', onPopState);\n\n this.cleanup.push(() => {\n history.pushState = origPush;\n history.replaceState = origReplace;\n window.removeEventListener('popstate', onPopState);\n });\n }\n\n // ── Helpers ───────────────────────────────────────────────────────────────\n\n private _timezone(): string | undefined {\n try {\n return Intl.DateTimeFormat().resolvedOptions().timeZone || undefined;\n } catch {\n return undefined;\n }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/transport.ts","../src/batcher.ts","../src/error-capture.ts","../src/perf.ts","../src/watchup.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["// ─────────────────────────────────────────────────────────────────────────────\n// @watchupltd/browser · transport\n//\n// Two delivery strategies:\n// 1. fetch(keepalive: true) — for regular periodic flushes.\n// 2. navigator.sendBeacon — for page-hide/unload; survives tab close.\n//\n// Web analytics events are sent to a separate endpoint (/web-batch) that is\n// optimised for high-volume, low-latency browser hits.\n// ─────────────────────────────────────────────────────────────────────────────\n\nimport type { IngestBatch, WebAnalyticsBatch } from './types.js';\n\nexport class Transport {\n private readonly url: string;\n private readonly webUrl: string;\n private readonly headers: Record<string, string>;\n private readonly debug: boolean;\n\n constructor(baseUrl: string, apiKey: string, debug = false) {\n const base = baseUrl.replace(/\\/$/, '');\n this.url = `${base}/api/v1/ingest/batch`;\n this.webUrl = `${base}/api/v1/ingest/web-batch`;\n this.headers = {\n 'Content-Type': 'application/json',\n 'X-Api-Key': apiKey,\n };\n this.debug = debug;\n }\n\n /**\n * Send via `fetch` with `keepalive: true`.\n * `keepalive` lets the request outlive the current page — it's the\n * browser equivalent of a \"fire and forget\" POST.\n * Never rejects.\n */\n async send(batch: IngestBatch): Promise<void> {\n try {\n const body = JSON.stringify(batch);\n\n // keepalive has a 64 KiB payload limit; fall back to beacon for large batches\n if (body.length > 60_000) {\n this.beacon(batch);\n return;\n }\n\n const res = await fetch(this.url, {\n method: 'POST',\n headers: this.headers,\n body,\n keepalive: true,\n });\n\n if (this.debug && !res.ok) {\n const text = await res.text().catch(() => '');\n console.warn(`[watchup] ingest ${res.status}: ${text}`);\n }\n } catch (err) {\n if (this.debug) console.warn('[watchup] send failed:', err);\n }\n }\n\n /**\n * Send web analytics batch to the dedicated /web-batch endpoint.\n * Never rejects.\n */\n async sendWeb(batch: WebAnalyticsBatch): Promise<void> {\n try {\n const body = JSON.stringify(batch);\n\n if (body.length > 60_000) {\n this.beaconWeb(batch);\n return;\n }\n\n const res = await fetch(this.webUrl, {\n method: 'POST',\n headers: this.headers,\n body,\n keepalive: true,\n });\n\n if (this.debug && !res.ok) {\n const text = await res.text().catch(() => '');\n console.warn(`[watchup] web-batch ${res.status}: ${text}`);\n }\n } catch (err) {\n if (this.debug) console.warn('[watchup] sendWeb failed:', err);\n }\n }\n\n /**\n * Send via `navigator.sendBeacon`.\n * Returns `true` if the browser accepted the request (doesn't guarantee delivery).\n * The server must accept `application/json` from sendBeacon via a Blob.\n */\n beacon(batch: IngestBatch): boolean {\n if (typeof navigator === 'undefined' || !navigator.sendBeacon) return false;\n try {\n const blob = new Blob([JSON.stringify(batch)], { type: 'application/json' });\n return navigator.sendBeacon(this.url, blob);\n } catch {\n return false;\n }\n }\n\n /**\n * sendBeacon variant for web analytics events.\n */\n beaconWeb(batch: WebAnalyticsBatch): boolean {\n if (typeof navigator === 'undefined' || !navigator.sendBeacon) return false;\n try {\n const blob = new Blob([JSON.stringify(batch)], { type: 'application/json' });\n return navigator.sendBeacon(this.webUrl, blob);\n } catch {\n return false;\n }\n }\n}\n","// ─────────────────────────────────────────────────────────────────────────────\n// @watchupltd/browser · batcher\n//\n// Browser-specific flush strategy:\n// - Periodic interval flush via fetch(keepalive)\n// - visibilitychange 'hidden' + pagehide → sendBeacon for reliable exit delivery\n//\n// Two independent queues:\n// - telemetry queue (traces, errors, events) → /ingest/batch\n// - web queue (web page views) → /ingest/web-batch\n// ─────────────────────────────────────────────────────────────────────────────\n\nimport type {\n TracePayload,\n ErrorPayload,\n EventPayload,\n IngestBatch,\n WebAnalyticsPayload,\n WebAnalyticsBatch,\n} from './types.js';\nimport { Transport } from './transport.js';\n\nexport class Batcher {\n private traces: TracePayload[] = [];\n private errors: ErrorPayload[] = [];\n private events: EventPayload[] = [];\n private webViews: WebAnalyticsPayload[] = [];\n\n private readonly transport: Transport;\n private readonly flushInterval: number;\n private readonly maxBatchSize: number;\n\n private timer: ReturnType<typeof setInterval> | null = null;\n private flushing = false;\n\n constructor(transport: Transport, flushInterval: number, maxBatchSize: number) {\n this.transport = transport;\n this.flushInterval = flushInterval;\n this.maxBatchSize = maxBatchSize;\n }\n\n start(): void {\n if (this.timer) return;\n\n // Periodic flush\n this.timer = setInterval(() => this.flush(), this.flushInterval);\n\n // Reliable delivery on tab hide — visibilitychange fires before the page\n // is destroyed, giving sendBeacon the best chance of succeeding.\n document.addEventListener('visibilitychange', () => {\n if (document.visibilityState === 'hidden') this.beaconFlush();\n });\n\n // Belt-and-suspenders for browsers/environments that skip visibilitychange\n window.addEventListener('pagehide', () => this.beaconFlush(), { once: true });\n }\n\n stop(): void {\n if (this.timer) { clearInterval(this.timer); this.timer = null; }\n }\n\n // ── Telemetry queue ───────────────────────────────────────────────────────\n\n addTrace(t: TracePayload): void {\n this.traces.push(t);\n if (this.traces.length >= this.maxBatchSize) this.flush();\n }\n\n addError(e: ErrorPayload): void {\n this.errors.push(e);\n // Errors are high-priority — flush at half capacity\n if (this.errors.length >= Math.ceil(this.maxBatchSize / 2)) this.flush();\n }\n\n addEvent(e: EventPayload): void {\n this.events.push(e);\n if (this.events.length >= this.maxBatchSize) this.flush();\n }\n\n // ── Web analytics queue ───────────────────────────────────────────────────\n\n addWebView(payload: WebAnalyticsPayload): void {\n this.webViews.push(payload);\n if (this.webViews.length >= this.maxBatchSize) this.flushWeb();\n }\n\n // ── Drain helpers ─────────────────────────────────────────────────────────\n\n private drainTelemetry(): IngestBatch | null {\n const traces = this.traces.splice(0);\n const errors = this.errors.splice(0);\n const events = this.events.splice(0);\n if (!traces.length && !errors.length && !events.length) return null;\n return { traces, errors, events };\n }\n\n private drainWeb(): WebAnalyticsBatch | null {\n const web = this.webViews.splice(0);\n if (!web.length) return null;\n return { web };\n }\n\n // ── Flush ─────────────────────────────────────────────────────────────────\n\n flush(): void {\n if (!this.flushing) {\n const batch = this.drainTelemetry();\n if (batch) {\n this.flushing = true;\n this.transport.send(batch).finally(() => { this.flushing = false; });\n }\n }\n this.flushWeb();\n }\n\n flushWeb(): void {\n const batch = this.drainWeb();\n if (batch) this.transport.sendWeb(batch);\n }\n\n beaconFlush(): void {\n // Telemetry\n const batch = this.drainTelemetry();\n if (batch) {\n if (!this.transport.beacon(batch)) this.transport.send(batch);\n }\n // Web analytics\n const webBatch = this.drainWeb();\n if (webBatch) {\n if (!this.transport.beaconWeb(webBatch)) this.transport.sendWeb(webBatch);\n }\n }\n}\n","// ─────────────────────────────────────────────────────────────────────────────\n// @watchupltd/browser · global error capture\n// ─────────────────────────────────────────────────────────────────────────────\n\nimport type { ErrorPayload } from './types.js';\n\ntype ErrorCallback = (error: ErrorPayload) => void;\n\n/**\n * Attaches `window.onerror` and `window.addEventListener('unhandledrejection')`\n * listeners that forward caught errors to `onError`.\n *\n * Returns a cleanup function that removes both listeners.\n */\nexport function captureGlobalErrors(onError: ErrorCallback, env?: string): () => void {\n const handleError = (event: ErrorEvent) => {\n onError({\n message: event.message || 'Unknown error',\n level: 'error',\n route: window.location.pathname,\n stack: event.error?.stack,\n context: {\n url: window.location.href,\n source: event.filename ?? undefined,\n line: event.lineno ?? undefined,\n col: event.colno ?? undefined,\n },\n timestamp: new Date().toISOString(),\n ...(env && { environment: env }),\n });\n };\n\n const handleRejection = (event: PromiseRejectionEvent) => {\n const reason = event.reason;\n const isErr = reason instanceof Error;\n onError({\n message: isErr ? reason.message : String(reason ?? 'Unhandled Promise rejection'),\n level: 'error',\n route: window.location.pathname,\n stack: isErr ? reason.stack : undefined,\n context: {\n url: window.location.href,\n type: 'unhandledrejection',\n },\n timestamp: new Date().toISOString(),\n ...(env && { environment: env }),\n });\n };\n\n window.addEventListener('error', handleError);\n window.addEventListener('unhandledrejection', handleRejection);\n\n return () => {\n window.removeEventListener('error', handleError);\n window.removeEventListener('unhandledrejection', handleRejection);\n };\n}\n","// ─────────────────────────────────────────────────────────────────────────────\n// @watchupltd/browser · Web Vitals capture\n//\n// Captures FCP, LCP, and overall page-load time via PerformanceObserver and\n// PerformanceNavigationTiming. Forwarded as traces so they appear in the\n// Watchup dashboard alongside request spans.\n//\n// Thresholds come from Google's Core Web Vitals 2024 targets:\n// FCP: good ≤ 1800 ms, needs improvement ≤ 3000 ms, poor > 3000 ms\n// LCP: good ≤ 2500 ms, needs improvement ≤ 4000 ms, poor > 4000 ms\n// ─────────────────────────────────────────────────────────────────────────────\n\nimport type { TracePayload } from './types.js';\n\ntype TraceCallback = (trace: TracePayload) => void;\n\nfunction rating(\n ms: number,\n good: number,\n needsImprovement: number,\n): TracePayload['status'] {\n if (ms <= good) return 'ok';\n if (ms <= needsImprovement) return 'warn';\n return 'err';\n}\n\nfunction statusCode(status: TracePayload['status']): number {\n return status === 'err' ? 500 : status === 'warn' ? 400 : 200;\n}\n\n// ── FCP — First Contentful Paint ─────────────────────────────────────────────\n\nexport function captureFCP(onTrace: TraceCallback, env?: string): void {\n if (typeof PerformanceObserver === 'undefined') return;\n try {\n const po = new PerformanceObserver((list) => {\n for (const entry of list.getEntries()) {\n if (entry.name !== 'first-contentful-paint') continue;\n const ms = Math.round(entry.startTime);\n const status = rating(ms, 1800, 3000);\n onTrace({\n span: 'web-vital fcp',\n ms,\n status_code: statusCode(status),\n status,\n timestamp: new Date().toISOString(),\n ...(env && { environment: env }),\n });\n po.disconnect();\n }\n });\n po.observe({ type: 'paint', buffered: true });\n } catch { /* PerformanceObserver 'paint' not supported */ }\n}\n\n// ── LCP — Largest Contentful Paint ───────────────────────────────────────────\n\nexport function captureLCP(onTrace: TraceCallback, env?: string): void {\n if (typeof PerformanceObserver === 'undefined') return;\n\n let last: PerformanceEntry | null = null;\n let reported = false;\n\n const report = () => {\n if (reported || !last) return;\n reported = true;\n try { po.disconnect(); } catch {}\n const ms = Math.round(last.startTime);\n const status = rating(ms, 2500, 4000);\n onTrace({\n span: 'web-vital lcp',\n ms,\n status_code: statusCode(status),\n status,\n timestamp: new Date().toISOString(),\n ...(env && { environment: env }),\n });\n };\n\n let po: PerformanceObserver;\n try {\n po = new PerformanceObserver((list) => {\n const entries = list.getEntries();\n if (entries.length) last = entries[entries.length - 1] ?? null;\n });\n po.observe({ type: 'largest-contentful-paint', buffered: true });\n } catch {\n return; // 'largest-contentful-paint' not supported\n }\n\n // LCP is only finalised once the user interacts or the tab hides.\n document.addEventListener('visibilitychange', report, { once: true });\n document.addEventListener('keydown', report, { once: true, capture: true });\n document.addEventListener('pointerdown', report, { once: true, capture: true });\n}\n\n// ── Page load (overall) ───────────────────────────────────────────────────────\n\nexport function capturePageLoad(onTrace: TraceCallback, env?: string): void {\n const report = () => {\n const nav = performance.getEntriesByType('navigation')[0] as\n PerformanceNavigationTiming | undefined;\n if (!nav || nav.loadEventEnd <= 0) return;\n\n const ms = Math.round(nav.loadEventEnd - nav.startTime);\n const ttfb = Math.round(nav.responseStart - nav.requestStart);\n const status = rating(ms, 2000, 4000);\n\n onTrace({\n span: 'pageload',\n ms,\n status_code: statusCode(status),\n status,\n timestamp: new Date().toISOString(),\n meta: { ttfb },\n ...(env && { environment: env }),\n });\n };\n\n if (document.readyState === 'complete') {\n // PerformanceNavigationTiming might not be fully populated yet\n setTimeout(report, 0);\n } else {\n window.addEventListener('load', () => setTimeout(report, 100), { once: true });\n }\n}\n","// ─────────────────────────────────────────────────────────────────────────────\n// @watchupltd/browser · Watchup client\n// ─────────────────────────────────────────────────────────────────────────────\n\nimport type {\n WatchupOptions,\n WatchupUser,\n TracePayload,\n ErrorPayload,\n EventPayload,\n WebAnalyticsPayload,\n} from './types.js';\nimport { Transport } from './transport.js';\nimport { Batcher } from './batcher.js';\nimport { captureGlobalErrors } from './error-capture.js';\nimport { captureFCP, captureLCP, capturePageLoad } from './perf.js';\n\nconst DEFAULTS = {\n baseUrl: 'https://api.watchup.site',\n flushInterval: 5_000,\n maxBatchSize: 100,\n debug: false,\n environment: 'production',\n release: '',\n sampleRate: 1,\n autoCapture: {\n errors: true,\n performance: true,\n pageViews: true,\n },\n} as const;\n\n// ── Storage keys ──────────────────────────────────────────────────────────────\n\nconst VISITOR_KEY = '__wup_vid';\nconst SESSION_KEY = '__wup_sid';\n\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport class Watchup {\n private readonly cfg: Required<WatchupOptions>;\n private readonly batcher: Batcher;\n private readonly cleanup: Array<() => void> = [];\n private _user: WatchupUser | null = null;\n\n /**\n * A random UUID generated on init. Stable for the lifetime of the page —\n * useful for correlating all events from one user session.\n */\n readonly sessionId: string = crypto.randomUUID();\n\n // ── Visitor / session identity ─────────────────────────────────────────────\n\n /**\n * Persistent visitor ID. Stored in localStorage so it survives browser\n * sessions. Falls back to a per-session UUID when localStorage is blocked.\n * The server hashes this value with SHA-256 before persisting.\n */\n private readonly visitorId: string;\n\n /**\n * Per-session ID stored in sessionStorage. Resets on tab close.\n * The server hashes this value before persisting.\n */\n private readonly webSessionId: string;\n\n constructor(options: WatchupOptions) {\n if (!options.apiKey) {\n throw new Error('[watchup] apiKey is required.');\n }\n\n this.cfg = {\n ...DEFAULTS,\n autoCapture: { ...DEFAULTS.autoCapture, ...options.autoCapture },\n ...options,\n } as Required<WatchupOptions>;\n\n const transport = new Transport(this.cfg.baseUrl, this.cfg.apiKey, this.cfg.debug);\n this.batcher = new Batcher(transport, this.cfg.flushInterval, this.cfg.maxBatchSize);\n this.batcher.start();\n\n // Initialise visitor & session IDs\n this.visitorId = this._getOrCreateVisitorId();\n this.webSessionId = this._getOrCreateSessionId();\n\n this._setupAutoCapture();\n }\n\n // ── Visitor / session identity helpers ─────────────────────────────────────\n\n private _getOrCreateVisitorId(): string {\n try {\n let id = localStorage.getItem(VISITOR_KEY);\n if (!id) {\n id = crypto.randomUUID();\n localStorage.setItem(VISITOR_KEY, id);\n }\n return id;\n } catch {\n // localStorage blocked (private mode, etc.) — fall back to session scope\n return crypto.randomUUID();\n }\n }\n\n private _getOrCreateSessionId(): string {\n try {\n let id = sessionStorage.getItem(SESSION_KEY);\n if (!id) {\n id = crypto.randomUUID();\n sessionStorage.setItem(SESSION_KEY, id);\n }\n return id;\n } catch {\n return this.sessionId; // fallback: correlate with SDK sessionId\n }\n }\n\n // ── User identification ───────────────────────────────────────────────────\n\n /**\n * Attach a user to all subsequent errors, traces, and events.\n * Call this after login; the context persists until `clearUser()` or page reload.\n *\n * @example\n * watchup.setUser({ id: '42', email: 'ada@example.com', name: 'Ada Lovelace' });\n */\n setUser(user: WatchupUser): void {\n this._user = { ...user };\n }\n\n /**\n * Remove the current user context (e.g. after logout).\n */\n clearUser(): void {\n this._user = null;\n }\n\n // ── Public API ────────────────────────────────────────────────────────────\n\n /**\n * Track a custom analytics event.\n *\n * @example\n * watchup.track('button.clicked', { label: 'Sign Up', variant: 'A' });\n */\n track(name: string, properties?: Record<string, unknown>): void {\n if (!name) return;\n const event: EventPayload = {\n name,\n ...(properties && Object.keys(properties).length && { properties }),\n occurred_at: new Date().toISOString(),\n };\n this.batcher.addEvent(event);\n }\n\n /**\n * Track a web analytics page view (or custom web event).\n * Enriches the payload with visitor context, UTM params, and device info.\n *\n * Normally called automatically. Call manually when you need custom event_name.\n *\n * @example\n * watchup.trackWebView({ event_name: 'conversion', path: '/checkout/success' });\n */\n trackWebView(overrides: Partial<WebAnalyticsPayload> = {}): void {\n const url = new URL(window.location.href);\n const params = url.searchParams;\n\n const payload: WebAnalyticsPayload = {\n path: url.pathname + (url.search || ''),\n hostname: url.hostname,\n referrer: document.referrer || undefined,\n title: document.title || undefined,\n screen_w: window.screen?.width,\n screen_h: window.screen?.height,\n lang: navigator.language || undefined,\n timezone: this._timezone(),\n // UTM parameters\n utm_source: params.get('utm_source') || undefined,\n utm_medium: params.get('utm_medium') || undefined,\n utm_campaign: params.get('utm_campaign') || undefined,\n utm_term: params.get('utm_term') || undefined,\n utm_content: params.get('utm_content') || undefined,\n // Identity (raw; the server hashes before storing)\n visitor_id: this.visitorId,\n session_id: this.webSessionId,\n event_name: 'pageview',\n occurred_at: new Date().toISOString(),\n // Apply caller overrides last\n ...overrides,\n };\n\n this.batcher.addWebView(payload);\n }\n\n /**\n * Manually capture an error.\n *\n * @example\n * try { ... } catch (err) {\n * watchup.captureError(err, { component: 'CheckoutForm' });\n * }\n */\n captureError(\n error: Error | string | unknown,\n context?: Record<string, unknown> & { route?: string; level?: ErrorPayload['level'] },\n ): void {\n const { route, level = 'error', ...rest } = context ?? {};\n const err = error instanceof Error ? error : new Error(String(error));\n\n const payload: ErrorPayload = {\n message: err.message,\n level,\n ...(err.stack !== undefined && { stack: err.stack }),\n route: route ?? window.location.pathname,\n ...(Object.keys(rest).length && {\n context: { ...rest, url: window.location.href },\n }),\n timestamp: new Date().toISOString(),\n environment: this.cfg.environment,\n ...(this.cfg.release && { release: this.cfg.release }),\n ...(this._user && { user: this._user }),\n };\n\n this.batcher.addError(payload);\n }\n\n /**\n * Time any async operation and record it as a trace.\n * Returns an `end()` function — call it when the operation finishes.\n *\n * @example\n * const end = watchup.startTrace('fetch /api/cart');\n * const cart = await fetch('/api/cart');\n * end({ status: cart.ok ? 'ok' : 'err' });\n */\n startTrace(\n span: string,\n ): (opts?: { status?: TracePayload['status']; meta?: Record<string, unknown> }) => void {\n const start = Date.now();\n return (opts = {}) => {\n const status = opts.status ?? 'ok';\n this.batcher.addTrace({\n span,\n ms: Date.now() - start,\n status_code: status === 'err' ? 500 : status === 'warn' ? 400 : 200,\n status,\n timestamp: new Date().toISOString(),\n environment: this.cfg.environment,\n ...(this.cfg.release && { release: this.cfg.release }),\n ...(opts.meta && { meta: opts.meta }),\n ...(this._user && { user: this._user }),\n });\n };\n }\n\n /** Immediately flush all queued items (both telemetry and web analytics). */\n flush(): void { this.batcher.flush(); }\n\n /** Stop the flush timer and release all listeners. */\n shutdown(): void {\n this.batcher.stop();\n this.batcher.flush();\n this.cleanup.forEach((fn) => fn());\n }\n\n // ── Auto-capture setup ────────────────────────────────────────────────────\n\n private _setupAutoCapture(): void {\n const { autoCapture, environment } = this.cfg;\n\n if (autoCapture.errors) {\n this.cleanup.push(\n captureGlobalErrors((e) => this.batcher.addError(e), environment),\n );\n }\n\n if (autoCapture.performance) {\n captureFCP((t) => this.batcher.addTrace(t), environment);\n captureLCP((t) => this.batcher.addTrace(t), environment);\n capturePageLoad((t) => this.batcher.addTrace(t), environment);\n }\n\n if (autoCapture.pageViews) {\n this._setupPageViewTracking();\n }\n }\n\n private _setupPageViewTracking(): void {\n const trackView = () => {\n // Small delay so the page title has settled after navigation\n setTimeout(() => this.trackWebView(), 0);\n };\n\n // Initial view\n if (document.readyState === 'loading') {\n document.addEventListener('DOMContentLoaded', trackView, { once: true });\n } else {\n setTimeout(() => this.trackWebView(), 0);\n }\n\n // SPA navigation — patch History API\n const origPush = history.pushState.bind(history);\n const origReplace = history.replaceState.bind(history);\n\n history.pushState = (...args: Parameters<typeof history.pushState>) => {\n origPush(...args);\n trackView();\n };\n history.replaceState = (...args: Parameters<typeof history.replaceState>) => {\n origReplace(...args);\n // replaceState is often used for URL canonicalisation — don't track.\n };\n\n const onPopState = () => trackView();\n window.addEventListener('popstate', onPopState);\n\n this.cleanup.push(() => {\n history.pushState = origPush;\n history.replaceState = origReplace;\n window.removeEventListener('popstate', onPopState);\n });\n }\n\n // ── Helpers ───────────────────────────────────────────────────────────────\n\n private _timezone(): string | undefined {\n try {\n return Intl.DateTimeFormat().resolvedOptions().timeZone || undefined;\n } catch {\n return undefined;\n }\n }\n}\n"]}
|