@yraylabs/boring-analytics 0.1.1 → 1.0.1

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/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Official SDK for [Boring Analytics](https://boringanalytics.io) — lightweight product analytics and error monitoring.
4
4
 
5
- - **Zero dependencies** — uses native `fetch` and `crypto`
5
+ - **Minimal dependencies** — native `fetch`/`crypto`; optional `web-vitals` for Core Web Vitals
6
6
  - **Works everywhere** — browser, Node.js, Edge runtimes
7
7
  - **TypeScript-first** — full type definitions included
8
8
  - **Tiny footprint** — tree-shakeable ESM + CJS builds
@@ -56,6 +56,9 @@ const analytics = new BoringAnalytics({
56
56
  autoCapture: {
57
57
  errors: true, // Capture unhandled errors (default: true)
58
58
  pageViews: false, // Auto-track SPA navigation (default: false)
59
+ webVitals: false, // Send LCP, FID, INP, CLS, TTFB (default: false)
60
+ scrollDepth: false, // Send scroll_depth at 25%, 50%, 75%, 100% (default: false)
61
+ outboundClicks: false, // Track external link and download clicks (default: false)
59
62
  },
60
63
 
61
64
  // Merged into every event
@@ -136,6 +139,30 @@ Link two user identities.
136
139
  analytics.alias('user-123', 'anon-789');
137
140
  ```
138
141
 
142
+ ### `trackRevenue(options)`
143
+
144
+ Track revenue (e.g. purchase, subscription). Sends a `purchase` event with amount and currency.
145
+
146
+ ```typescript
147
+ analytics.trackRevenue({
148
+ amount: 29.99,
149
+ currency: 'USD',
150
+ properties: { orderId: 'ord_123', productId: 'sku_456' },
151
+ });
152
+ ```
153
+
154
+ ### `trackExposure(options)`
155
+
156
+ Track feature-flag or A–B test exposure.
157
+
158
+ ```typescript
159
+ analytics.trackExposure({
160
+ flag: 'pricing_test',
161
+ variant: 'treatment',
162
+ properties: { page: '/pricing' },
163
+ });
164
+ ```
165
+
139
166
  ### `captureError(error, options?)`
140
167
 
141
168
  Manually capture an error.
@@ -178,6 +205,26 @@ Gracefully shut down — flushes remaining events and removes global error handl
178
205
  await analytics.shutdown();
179
206
  ```
180
207
 
208
+ ## Auto-Capture: Web Vitals, Scroll Depth, Outbound Clicks
209
+
210
+ Enable optional automatic tracking (browser only):
211
+
212
+ ```typescript
213
+ const analytics = new BoringAnalytics({
214
+ apiKey: 'your-api-key',
215
+ autoCapture: {
216
+ pageViews: true, // SPA route changes (pushState/replaceState/popstate)
217
+ webVitals: true, // LCP, FID, INP, CLS, TTFB → event "web_vitals"
218
+ scrollDepth: true, // 25%, 50%, 75%, 100% → event "scroll_depth"
219
+ outboundClicks: true, // External links & downloads → event "outbound_click"
220
+ },
221
+ });
222
+ ```
223
+
224
+ - **webVitals**: Sends one event per metric with `metric`, `value`, `rating`, `delta`, `id`.
225
+ - **scrollDepth**: Sends one event per threshold (25, 50, 75, 100) with `depth`.
226
+ - **outboundClicks**: Sends `href`, `domain`, and `link_type` (`external` or `download`).
227
+
181
228
  ## Auto Page View Tracking
182
229
 
183
230
  Enable automatic page view tracking for SPAs:
package/dist/index.d.mts CHANGED
@@ -13,6 +13,12 @@ interface BoringAnalyticsConfig {
13
13
  errors?: boolean;
14
14
  /** Auto-track page views on navigation — browser only (default: false) */
15
15
  pageViews?: boolean;
16
+ /** Send Web Vitals (LCP, FID, INP, CLS, TTFB) as performance events — browser only (default: false) */
17
+ webVitals?: boolean;
18
+ /** Send scroll depth events at 25%, 50%, 75%, 100% — browser only (default: false) */
19
+ scrollDepth?: boolean;
20
+ /** Track outbound link and download clicks — browser only (default: false) */
21
+ outboundClicks?: boolean;
16
22
  };
17
23
  /** Default properties merged into every event */
18
24
  defaultProperties?: Record<string, unknown>;
@@ -118,6 +124,25 @@ interface CaptureErrorOptions {
118
124
  timestamp?: Date;
119
125
  release?: string;
120
126
  }
127
+ /** Options for revenue/purchase tracking */
128
+ interface TrackRevenueOptions {
129
+ amount: number;
130
+ currency?: string;
131
+ /** e.g. productId, orderId, subscriptionId */
132
+ properties?: Record<string, unknown>;
133
+ timestamp?: Date;
134
+ context?: Partial<EventContext>;
135
+ }
136
+ /** Options for feature-flag / A–B test exposure */
137
+ interface TrackExposureOptions {
138
+ /** Flag or experiment name */
139
+ flag: string;
140
+ /** Variant shown (e.g. 'control', 'treatment') */
141
+ variant: string;
142
+ properties?: Record<string, unknown>;
143
+ timestamp?: Date;
144
+ context?: Partial<EventContext>;
145
+ }
121
146
 
122
147
  declare class BoringAnalytics {
123
148
  private queue;
@@ -126,6 +151,9 @@ declare class BoringAnalytics {
126
151
  private debug;
127
152
  private config;
128
153
  private pageViewUnsubscribe;
154
+ private webVitalsUnsubscribe;
155
+ private scrollDepthUnsubscribe;
156
+ private outboundClicksUnsubscribe;
129
157
  constructor(config: BoringAnalyticsConfig);
130
158
  /**
131
159
  * Track a named event.
@@ -162,6 +190,22 @@ declare class BoringAnalytics {
162
190
  * Create an alias between two user identities.
163
191
  */
164
192
  alias(userId: string, previousId: string): void;
193
+ /**
194
+ * Track revenue (e.g. purchase, subscription).
195
+ * Sends a TRACK event with name "purchase" and amount/currency in properties.
196
+ *
197
+ * @example
198
+ * analytics.trackRevenue({ amount: 29.99, currency: 'USD', properties: { orderId: 'ord_123' } });
199
+ */
200
+ trackRevenue(options: TrackRevenueOptions): void;
201
+ /**
202
+ * Track feature-flag or A–B test exposure.
203
+ * Sends a TRACK event with name "feature_exposed" and flag/variant in properties.
204
+ *
205
+ * @example
206
+ * analytics.trackExposure({ flag: 'pricing_test', variant: 'treatment' });
207
+ */
208
+ trackExposure(options: TrackExposureOptions): void;
165
209
  /**
166
210
  * Capture an error for error monitoring.
167
211
  *
@@ -187,4 +231,4 @@ declare class BoringAnalytics {
187
231
  private installPageViewTracking;
188
232
  }
189
233
 
190
- export { BoringAnalytics, type BoringAnalyticsConfig, type CaptureErrorOptions, type ErrorLevel, type EventContext, type EventType, type GroupOptions, type IdentifyOptions, type IngestErrorPayload, type IngestEventPayload, type PageOptions, type ScreenOptions, type TrackOptions };
234
+ export { BoringAnalytics, type BoringAnalyticsConfig, type CaptureErrorOptions, type ErrorLevel, type EventContext, type EventType, type GroupOptions, type IdentifyOptions, type IngestErrorPayload, type IngestEventPayload, type PageOptions, type ScreenOptions, type TrackExposureOptions, type TrackOptions, type TrackRevenueOptions };
package/dist/index.d.ts CHANGED
@@ -13,6 +13,12 @@ interface BoringAnalyticsConfig {
13
13
  errors?: boolean;
14
14
  /** Auto-track page views on navigation — browser only (default: false) */
15
15
  pageViews?: boolean;
16
+ /** Send Web Vitals (LCP, FID, INP, CLS, TTFB) as performance events — browser only (default: false) */
17
+ webVitals?: boolean;
18
+ /** Send scroll depth events at 25%, 50%, 75%, 100% — browser only (default: false) */
19
+ scrollDepth?: boolean;
20
+ /** Track outbound link and download clicks — browser only (default: false) */
21
+ outboundClicks?: boolean;
16
22
  };
17
23
  /** Default properties merged into every event */
18
24
  defaultProperties?: Record<string, unknown>;
@@ -118,6 +124,25 @@ interface CaptureErrorOptions {
118
124
  timestamp?: Date;
119
125
  release?: string;
120
126
  }
127
+ /** Options for revenue/purchase tracking */
128
+ interface TrackRevenueOptions {
129
+ amount: number;
130
+ currency?: string;
131
+ /** e.g. productId, orderId, subscriptionId */
132
+ properties?: Record<string, unknown>;
133
+ timestamp?: Date;
134
+ context?: Partial<EventContext>;
135
+ }
136
+ /** Options for feature-flag / A–B test exposure */
137
+ interface TrackExposureOptions {
138
+ /** Flag or experiment name */
139
+ flag: string;
140
+ /** Variant shown (e.g. 'control', 'treatment') */
141
+ variant: string;
142
+ properties?: Record<string, unknown>;
143
+ timestamp?: Date;
144
+ context?: Partial<EventContext>;
145
+ }
121
146
 
122
147
  declare class BoringAnalytics {
123
148
  private queue;
@@ -126,6 +151,9 @@ declare class BoringAnalytics {
126
151
  private debug;
127
152
  private config;
128
153
  private pageViewUnsubscribe;
154
+ private webVitalsUnsubscribe;
155
+ private scrollDepthUnsubscribe;
156
+ private outboundClicksUnsubscribe;
129
157
  constructor(config: BoringAnalyticsConfig);
130
158
  /**
131
159
  * Track a named event.
@@ -162,6 +190,22 @@ declare class BoringAnalytics {
162
190
  * Create an alias between two user identities.
163
191
  */
164
192
  alias(userId: string, previousId: string): void;
193
+ /**
194
+ * Track revenue (e.g. purchase, subscription).
195
+ * Sends a TRACK event with name "purchase" and amount/currency in properties.
196
+ *
197
+ * @example
198
+ * analytics.trackRevenue({ amount: 29.99, currency: 'USD', properties: { orderId: 'ord_123' } });
199
+ */
200
+ trackRevenue(options: TrackRevenueOptions): void;
201
+ /**
202
+ * Track feature-flag or A–B test exposure.
203
+ * Sends a TRACK event with name "feature_exposed" and flag/variant in properties.
204
+ *
205
+ * @example
206
+ * analytics.trackExposure({ flag: 'pricing_test', variant: 'treatment' });
207
+ */
208
+ trackExposure(options: TrackExposureOptions): void;
165
209
  /**
166
210
  * Capture an error for error monitoring.
167
211
  *
@@ -187,4 +231,4 @@ declare class BoringAnalytics {
187
231
  private installPageViewTracking;
188
232
  }
189
233
 
190
- export { BoringAnalytics, type BoringAnalyticsConfig, type CaptureErrorOptions, type ErrorLevel, type EventContext, type EventType, type GroupOptions, type IdentifyOptions, type IngestErrorPayload, type IngestEventPayload, type PageOptions, type ScreenOptions, type TrackOptions };
234
+ export { BoringAnalytics, type BoringAnalyticsConfig, type CaptureErrorOptions, type ErrorLevel, type EventContext, type EventType, type GroupOptions, type IdentifyOptions, type IngestErrorPayload, type IngestEventPayload, type PageOptions, type ScreenOptions, type TrackExposureOptions, type TrackOptions, type TrackRevenueOptions };
package/dist/index.js CHANGED
@@ -1,5 +1,7 @@
1
1
  'use strict';
2
2
 
3
+ var webVitals = require('web-vitals');
4
+
3
5
  // src/transport.ts
4
6
  var Transport = class {
5
7
  constructor(config) {
@@ -400,9 +402,92 @@ function createStorage() {
400
402
  }
401
403
  return new MemoryStorage();
402
404
  }
405
+ function installWebVitals(report) {
406
+ const reportMetric = (metric) => {
407
+ report({
408
+ name: metric.name,
409
+ value: metric.value,
410
+ rating: metric.rating,
411
+ delta: metric.delta,
412
+ id: metric.id
413
+ });
414
+ };
415
+ webVitals.onCLS(reportMetric);
416
+ webVitals.onFID(reportMetric);
417
+ webVitals.onINP(reportMetric);
418
+ webVitals.onLCP(reportMetric);
419
+ webVitals.onTTFB(reportMetric);
420
+ return () => {
421
+ };
422
+ }
423
+
424
+ // src/auto-capture/scroll-depth.ts
425
+ var DEPTHS = [25, 50, 75, 100];
426
+ function installScrollDepth(report) {
427
+ const reported = /* @__PURE__ */ new Set();
428
+ const onScroll = () => {
429
+ if (typeof document === "undefined" || !document.documentElement) return;
430
+ const scrollHeight = document.documentElement.scrollHeight - window.innerHeight;
431
+ if (scrollHeight <= 0) return;
432
+ const scrollPercent = Math.round(window.scrollY / scrollHeight * 100);
433
+ for (const d of DEPTHS) {
434
+ if (scrollPercent >= d && !reported.has(d)) {
435
+ reported.add(d);
436
+ report(d);
437
+ }
438
+ }
439
+ };
440
+ window.addEventListener("scroll", onScroll, { passive: true });
441
+ onScroll();
442
+ return () => {
443
+ window.removeEventListener("scroll", onScroll);
444
+ };
445
+ }
446
+
447
+ // src/auto-capture/outbound-clicks.ts
448
+ function getLinkTarget(e) {
449
+ let el = e.target;
450
+ while (el && el !== document.body) {
451
+ if (el.tagName === "A" && el.href) {
452
+ return el;
453
+ }
454
+ el = el.parentElement;
455
+ }
456
+ return null;
457
+ }
458
+ function isDownload(anchor) {
459
+ const attr = anchor.getAttribute("download");
460
+ const href = (anchor.getAttribute("href") || "").toLowerCase();
461
+ return attr !== null || /\.(pdf|zip|docx?|xlsx?|csv|mp3|mp4|apk)(\?|$)/i.test(href);
462
+ }
463
+ function isExternal(anchor) {
464
+ try {
465
+ return anchor.hostname !== window.location.hostname && anchor.protocol.startsWith("http");
466
+ } catch {
467
+ return false;
468
+ }
469
+ }
470
+ function installOutboundClickTracking(report) {
471
+ const handler = (e) => {
472
+ const anchor = getLinkTarget(e);
473
+ if (!anchor) return;
474
+ const href = anchor.href;
475
+ if (isDownload(anchor)) {
476
+ report({ href, type: "download" });
477
+ return;
478
+ }
479
+ if (isExternal(anchor)) {
480
+ report({ href, domain: anchor.hostname, type: "external" });
481
+ }
482
+ };
483
+ document.addEventListener("click", handler, true);
484
+ return () => {
485
+ document.removeEventListener("click", handler, true);
486
+ };
487
+ }
403
488
 
404
489
  // src/client.ts
405
- var DEFAULT_ENDPOINT = "https://api.boringanalytics.io";
490
+ var DEFAULT_ENDPOINT = "https://api.boring.yraylabs.fun";
406
491
  var DEFAULT_FLUSH_AT = 20;
407
492
  var DEFAULT_FLUSH_INTERVAL = 5e3;
408
493
  var DEFAULT_MAX_RETRIES = 3;
@@ -410,6 +495,9 @@ var BoringAnalytics = class {
410
495
  constructor(config) {
411
496
  this.errorHandler = null;
412
497
  this.pageViewUnsubscribe = null;
498
+ this.webVitalsUnsubscribe = null;
499
+ this.scrollDepthUnsubscribe = null;
500
+ this.outboundClicksUnsubscribe = null;
413
501
  if (!config.apiKey) {
414
502
  throw new Error("BoringAnalytics: apiKey is required");
415
503
  }
@@ -445,6 +533,35 @@ var BoringAnalytics = class {
445
533
  if (autoCapture.pageViews && isBrowser()) {
446
534
  this.installPageViewTracking();
447
535
  }
536
+ if (autoCapture.webVitals && isBrowser()) {
537
+ this.webVitalsUnsubscribe = installWebVitals((metric) => {
538
+ this.track("web_vitals", {
539
+ properties: {
540
+ metric: metric.name,
541
+ value: metric.value,
542
+ rating: metric.rating,
543
+ delta: metric.delta,
544
+ id: metric.id
545
+ }
546
+ });
547
+ });
548
+ }
549
+ if (autoCapture.scrollDepth && isBrowser()) {
550
+ this.scrollDepthUnsubscribe = installScrollDepth((depth) => {
551
+ this.track("scroll_depth", { properties: { depth } });
552
+ });
553
+ }
554
+ if (autoCapture.outboundClicks && isBrowser()) {
555
+ this.outboundClicksUnsubscribe = installOutboundClickTracking((payload) => {
556
+ this.track("outbound_click", {
557
+ properties: {
558
+ href: payload.href,
559
+ domain: payload.domain,
560
+ link_type: payload.type
561
+ }
562
+ });
563
+ });
564
+ }
448
565
  }
449
566
  // --- Public API ---
450
567
  /**
@@ -496,6 +613,36 @@ var BoringAnalytics = class {
496
613
  alias(userId, previousId) {
497
614
  this.enqueueEvent("ALIAS", "alias", { userId, previousId });
498
615
  }
616
+ /**
617
+ * Track revenue (e.g. purchase, subscription).
618
+ * Sends a TRACK event with name "purchase" and amount/currency in properties.
619
+ *
620
+ * @example
621
+ * analytics.trackRevenue({ amount: 29.99, currency: 'USD', properties: { orderId: 'ord_123' } });
622
+ */
623
+ trackRevenue(options) {
624
+ const { amount, currency = "USD", properties = {}, timestamp, context } = options;
625
+ this.track("purchase", {
626
+ properties: { amount, currency, ...properties },
627
+ timestamp,
628
+ context
629
+ });
630
+ }
631
+ /**
632
+ * Track feature-flag or A–B test exposure.
633
+ * Sends a TRACK event with name "feature_exposed" and flag/variant in properties.
634
+ *
635
+ * @example
636
+ * analytics.trackExposure({ flag: 'pricing_test', variant: 'treatment' });
637
+ */
638
+ trackExposure(options) {
639
+ const { flag, variant, properties = {}, timestamp, context } = options;
640
+ this.track("feature_exposed", {
641
+ properties: { flag, variant, ...properties },
642
+ timestamp,
643
+ context
644
+ });
645
+ }
499
646
  /**
500
647
  * Capture an error for error monitoring.
501
648
  *
@@ -550,6 +697,9 @@ var BoringAnalytics = class {
550
697
  this.debug.log("Shutting down");
551
698
  this.errorHandler?.uninstall();
552
699
  this.pageViewUnsubscribe?.();
700
+ this.webVitalsUnsubscribe?.();
701
+ this.scrollDepthUnsubscribe?.();
702
+ this.outboundClicksUnsubscribe?.();
553
703
  await this.queue.shutdown();
554
704
  }
555
705
  // --- Internal ---
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/transport.ts","../src/queue.ts","../src/utils.ts","../src/session.ts","../src/error-handler.ts","../src/context.ts","../src/storage.ts","../src/client.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import type { IngestEventPayload, IngestErrorPayload } from './types';\n\nexport interface TransportConfig {\n endpoint: string;\n apiKey: string;\n maxRetries: number;\n onError?: (error: Error) => void;\n}\n\nexport class Transport {\n private config: TransportConfig;\n\n constructor(config: TransportConfig) {\n this.config = config;\n }\n\n async sendEvents(events: IngestEventPayload[]): Promise<void> {\n await this.post('/ingest/events', { events });\n }\n\n async sendErrors(errors: IngestErrorPayload[]): Promise<void> {\n await this.post('/ingest/errors', { errors });\n }\n\n private async post(path: string, body: unknown): Promise<void> {\n const url = this.config.endpoint.replace(/\\/+$/, '') + path;\n let lastError: Error | undefined;\n\n for (let attempt = 0; attempt <= this.config.maxRetries; attempt++) {\n try {\n const response = await fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'x-api-key': this.config.apiKey,\n },\n body: JSON.stringify(body),\n keepalive: true,\n });\n\n if (response.ok) return;\n\n if (response.status >= 400 && response.status < 500 && response.status !== 429) {\n const text = await response.text().catch(() => '');\n throw new Error(`HTTP ${response.status}: ${text}`);\n }\n\n lastError = new Error(`HTTP ${response.status}`);\n } catch (err) {\n lastError = err instanceof Error ? err : new Error(String(err));\n if (err instanceof Error && err.message.startsWith('HTTP 4')) {\n break;\n }\n }\n\n if (attempt < this.config.maxRetries) {\n await this.backoff(attempt);\n }\n }\n\n if (lastError) {\n this.config.onError?.(lastError);\n }\n }\n\n private backoff(attempt: number): Promise<void> {\n const delay = Math.min(1000 * 2 ** attempt, 30000);\n const jitter = delay * (0.5 + Math.random() * 0.5);\n return new Promise((resolve) => setTimeout(resolve, jitter));\n }\n}\n","import type { QueueItem, IngestEventPayload, IngestErrorPayload } from './types';\nimport type { Transport } from './transport';\n\nexport interface QueueConfig {\n flushAt: number;\n flushInterval: number;\n debug: ReturnType<typeof import('./utils').createDebugLogger>;\n}\n\nexport class EventQueue {\n private items: QueueItem[] = [];\n private timer: ReturnType<typeof setInterval> | null = null;\n private transport: Transport;\n private config: QueueConfig;\n private flushing = false;\n\n constructor(transport: Transport, config: QueueConfig) {\n this.transport = transport;\n this.config = config;\n this.startTimer();\n }\n\n add(item: QueueItem): void {\n this.items.push(item);\n this.config.debug.log(`Queued ${item.kind}:`, item.kind === 'event' ? item.payload.name : item.payload.message);\n\n if (this.items.length >= this.config.flushAt) {\n void this.flush();\n }\n }\n\n async flush(): Promise<void> {\n if (this.flushing || this.items.length === 0) return;\n\n this.flushing = true;\n const batch = this.items.splice(0);\n\n try {\n const events: IngestEventPayload[] = [];\n const errors: IngestErrorPayload[] = [];\n\n for (const item of batch) {\n if (item.kind === 'event') events.push(item.payload);\n else errors.push(item.payload);\n }\n\n const promises: Promise<void>[] = [];\n if (events.length > 0) {\n this.config.debug.log(`Flushing ${events.length} events`);\n promises.push(this.transport.sendEvents(events));\n }\n if (errors.length > 0) {\n this.config.debug.log(`Flushing ${errors.length} errors`);\n promises.push(this.transport.sendErrors(errors));\n }\n\n await Promise.all(promises);\n } catch {\n this.items.unshift(...batch);\n } finally {\n this.flushing = false;\n }\n }\n\n private startTimer(): void {\n if (this.config.flushInterval > 0) {\n this.timer = setInterval(() => {\n void this.flush();\n }, this.config.flushInterval);\n\n // Allow Node.js to exit without waiting for the timer\n if (this.timer && typeof (this.timer as NodeJS.Timeout).unref === 'function') {\n (this.timer as NodeJS.Timeout).unref();\n }\n }\n }\n\n async shutdown(): Promise<void> {\n if (this.timer) {\n clearInterval(this.timer);\n this.timer = null;\n }\n await this.flush();\n }\n\n get size(): number {\n return this.items.length;\n }\n}\n","export function generateId(): string {\n if (typeof crypto !== 'undefined' && crypto.randomUUID) {\n return crypto.randomUUID();\n }\n return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {\n const r = (Math.random() * 16) | 0;\n const v = c === 'x' ? r : (r & 0x3) | 0x8;\n return v.toString(16);\n });\n}\n\nexport function isBrowser(): boolean {\n return typeof window !== 'undefined' && typeof document !== 'undefined';\n}\n\nexport function now(): string {\n return new Date().toISOString();\n}\n\nexport function createDebugLogger(enabled: boolean) {\n return {\n log: (...args: unknown[]) => {\n if (enabled) console.log('[BoringAnalytics]', ...args);\n },\n warn: (...args: unknown[]) => {\n if (enabled) console.warn('[BoringAnalytics]', ...args);\n },\n error: (...args: unknown[]) => {\n if (enabled) console.error('[BoringAnalytics]', ...args);\n },\n };\n}\n","import type { Storage } from './storage';\nimport { generateId } from './utils';\n\nconst ANON_ID_KEY = 'anonymous_id';\nconst SESSION_ID_KEY = 'session_id';\nconst SESSION_EXPIRY_KEY = 'session_expiry';\n\n/** Session timeout: 30 minutes of inactivity */\nconst SESSION_TIMEOUT_MS = 30 * 60 * 1000;\n\nexport class SessionManager {\n private userId: string | null = null;\n private anonymousId: string;\n private sessionId: string;\n private storage: Storage;\n\n constructor(storage: Storage) {\n this.storage = storage;\n this.anonymousId = this.storage.get(ANON_ID_KEY) ?? this.createAnonymousId();\n this.sessionId = this.resolveSession();\n }\n\n private createAnonymousId(): string {\n const id = generateId();\n this.storage.set(ANON_ID_KEY, id);\n return id;\n }\n\n private resolveSession(): string {\n const existingSession = this.storage.get(SESSION_ID_KEY);\n const expiryStr = this.storage.get(SESSION_EXPIRY_KEY);\n const expiry = expiryStr ? parseInt(expiryStr, 10) : 0;\n\n if (existingSession && Date.now() < expiry) {\n this.touchSession();\n return existingSession;\n }\n\n return this.startNewSession();\n }\n\n private startNewSession(): string {\n const id = generateId();\n this.sessionId = id;\n this.storage.set(SESSION_ID_KEY, id);\n this.touchSession();\n return id;\n }\n\n private touchSession(): void {\n this.storage.set(\n SESSION_EXPIRY_KEY,\n String(Date.now() + SESSION_TIMEOUT_MS),\n );\n }\n\n setUserId(id: string): void {\n this.userId = id;\n }\n\n getUserId(): string | null {\n return this.userId;\n }\n\n getAnonymousId(): string {\n return this.anonymousId;\n }\n\n getSessionId(): string {\n this.sessionId = this.resolveSession();\n return this.sessionId;\n }\n\n reset(): void {\n this.userId = null;\n this.anonymousId = this.createAnonymousId();\n this.sessionId = this.startNewSession();\n }\n}\n","import { isBrowser } from './utils';\n\ntype ErrorCallback = (error: Error, source?: string) => void;\n\nexport class GlobalErrorHandler {\n private callback: ErrorCallback;\n private installed = false;\n private originalOnError: OnErrorEventHandler | null = null;\n private originalOnUnhandledRejection: ((ev: PromiseRejectionEvent) => void) | null = null;\n\n constructor(callback: ErrorCallback) {\n this.callback = callback;\n }\n\n install(): void {\n if (this.installed) return;\n this.installed = true;\n\n if (isBrowser()) {\n this.installBrowser();\n } else {\n this.installNode();\n }\n }\n\n uninstall(): void {\n if (!this.installed) return;\n this.installed = false;\n\n if (isBrowser()) {\n this.uninstallBrowser();\n } else {\n this.uninstallNode();\n }\n }\n\n private installBrowser(): void {\n this.originalOnError = window.onerror;\n window.onerror = (message, source, lineno, colno, error) => {\n if (error) {\n this.callback(error, source ?? undefined);\n } else if (typeof message === 'string') {\n this.callback(new Error(message), source ?? undefined);\n }\n this.originalOnError?.call(window, message, source, lineno, colno, error);\n };\n\n this.originalOnUnhandledRejection = window.onunhandledrejection as typeof this.originalOnUnhandledRejection;\n window.onunhandledrejection = (event: PromiseRejectionEvent) => {\n const error =\n event.reason instanceof Error\n ? event.reason\n : new Error(String(event.reason));\n this.callback(error, 'unhandledrejection');\n (this.originalOnUnhandledRejection as ((ev: PromiseRejectionEvent) => void) | null)?.call(window, event);\n };\n }\n\n private uninstallBrowser(): void {\n window.onerror = this.originalOnError;\n window.onunhandledrejection = this.originalOnUnhandledRejection as typeof window.onunhandledrejection;\n }\n\n private installNode(): void {\n if (typeof process === 'undefined') return;\n\n process.on('uncaughtException', this.handleNodeError);\n process.on('unhandledRejection', this.handleNodeRejection);\n }\n\n private uninstallNode(): void {\n if (typeof process === 'undefined') return;\n\n process.removeListener('uncaughtException', this.handleNodeError);\n process.removeListener('unhandledRejection', this.handleNodeRejection);\n }\n\n private handleNodeError = (error: Error): void => {\n this.callback(error, 'uncaughtException');\n };\n\n private handleNodeRejection = (reason: unknown): void => {\n const error = reason instanceof Error ? reason : new Error(String(reason));\n this.callback(error, 'unhandledRejection');\n };\n}\n","import type { EventContext } from './types';\nimport { isBrowser } from './utils';\n\n/**\n * Parses a user agent string into browser, OS, and device info.\n * Lightweight — covers major browsers/platforms without a full UA parser dependency.\n */\nfunction parseUserAgent(ua: string): {\n browser: { name: string; version?: string };\n os: { name: string; version?: string };\n device: { type: string };\n} {\n const browser = { name: 'Unknown', version: undefined as string | undefined };\n const os = { name: 'Unknown', version: undefined as string | undefined };\n const device = { type: 'desktop' };\n\n // Mobile detection\n if (/Mobi|Android|iPhone|iPad|iPod/i.test(ua)) {\n device.type = /iPad|Tablet/i.test(ua) ? 'tablet' : 'mobile';\n }\n\n // Browser detection\n if (/Edg\\//i.test(ua)) {\n browser.name = 'Edge';\n browser.version = ua.match(/Edg\\/([\\d.]+)/)?.[1];\n } else if (/OPR\\//i.test(ua) || /Opera/i.test(ua)) {\n browser.name = 'Opera';\n browser.version = ua.match(/(?:OPR|Opera)\\/([\\d.]+)/)?.[1];\n } else if (/Chrome\\//i.test(ua) && !/Chromium/i.test(ua)) {\n browser.name = 'Chrome';\n browser.version = ua.match(/Chrome\\/([\\d.]+)/)?.[1];\n } else if (/Safari\\//i.test(ua) && !/Chrome/i.test(ua)) {\n browser.name = 'Safari';\n browser.version = ua.match(/Version\\/([\\d.]+)/)?.[1];\n } else if (/Firefox\\//i.test(ua)) {\n browser.name = 'Firefox';\n browser.version = ua.match(/Firefox\\/([\\d.]+)/)?.[1];\n }\n\n // OS detection\n if (/Windows NT/i.test(ua)) {\n os.name = 'Windows';\n const ntVersion = ua.match(/Windows NT ([\\d.]+)/)?.[1];\n const versionMap: Record<string, string> = {\n '10.0': '10+',\n '6.3': '8.1',\n '6.2': '8',\n '6.1': '7',\n };\n os.version = ntVersion ? (versionMap[ntVersion] ?? ntVersion) : undefined;\n } else if (/Mac OS X/i.test(ua)) {\n os.name = 'macOS';\n os.version = ua.match(/Mac OS X ([\\d_.]+)/)?.[1]?.replace(/_/g, '.');\n } else if (/Android/i.test(ua)) {\n os.name = 'Android';\n os.version = ua.match(/Android ([\\d.]+)/)?.[1];\n } else if (/iPhone OS|iPad/i.test(ua)) {\n os.name = 'iOS';\n os.version = ua.match(/OS ([\\d_]+)/)?.[1]?.replace(/_/g, '.');\n } else if (/Linux/i.test(ua)) {\n os.name = 'Linux';\n }\n\n return { browser, os, device };\n}\n\nexport function gatherContext(): EventContext {\n if (!isBrowser()) {\n return {};\n }\n\n const ua = navigator.userAgent;\n const { browser, os, device } = parseUserAgent(ua);\n\n return {\n userAgent: ua,\n locale: navigator.language,\n page: {\n url: window.location.href,\n referrer: document.referrer || undefined,\n title: document.title || undefined,\n path: window.location.pathname,\n },\n browser,\n os,\n device,\n };\n}\n\nexport function mergeContext(\n auto: EventContext,\n user?: Partial<EventContext>,\n): EventContext {\n if (!user) return auto;\n\n return {\n ...auto,\n ...user,\n page: { ...auto.page, ...user.page },\n browser: { ...auto.browser, ...user.browser },\n os: { ...auto.os, ...user.os },\n device: { ...auto.device, ...user.device },\n };\n}\n","const PREFIX = 'ba_';\n\nexport interface Storage {\n get(key: string): string | null;\n set(key: string, value: string): void;\n remove(key: string): void;\n}\n\nclass LocalStorage implements Storage {\n get(key: string): string | null {\n try {\n return localStorage.getItem(PREFIX + key);\n } catch {\n return null;\n }\n }\n\n set(key: string, value: string): void {\n try {\n localStorage.setItem(PREFIX + key, value);\n } catch {\n // localStorage unavailable or quota exceeded\n }\n }\n\n remove(key: string): void {\n try {\n localStorage.removeItem(PREFIX + key);\n } catch {\n // noop\n }\n }\n}\n\nclass MemoryStorage implements Storage {\n private store = new Map<string, string>();\n\n get(key: string): string | null {\n return this.store.get(PREFIX + key) ?? null;\n }\n\n set(key: string, value: string): void {\n this.store.set(PREFIX + key, value);\n }\n\n remove(key: string): void {\n this.store.delete(PREFIX + key);\n }\n}\n\nexport function createStorage(): Storage {\n try {\n if (typeof localStorage !== 'undefined') {\n localStorage.setItem('__ba_test__', '1');\n localStorage.removeItem('__ba_test__');\n return new LocalStorage();\n }\n } catch {\n // localStorage not available\n }\n return new MemoryStorage();\n}\n","import type {\n BoringAnalyticsConfig,\n TrackOptions,\n IdentifyOptions,\n PageOptions,\n ScreenOptions,\n GroupOptions,\n CaptureErrorOptions,\n IngestEventPayload,\n IngestErrorPayload,\n EventContext,\n} from './types';\nimport { Transport } from './transport';\nimport { EventQueue } from './queue';\nimport { SessionManager } from './session';\nimport { GlobalErrorHandler } from './error-handler';\nimport { gatherContext, mergeContext } from './context';\nimport { createStorage } from './storage';\nimport { createDebugLogger, isBrowser, now } from './utils';\n\nconst DEFAULT_ENDPOINT = 'https://api.boringanalytics.io';\nconst DEFAULT_FLUSH_AT = 20;\nconst DEFAULT_FLUSH_INTERVAL = 5000;\nconst DEFAULT_MAX_RETRIES = 3;\n\nexport class BoringAnalytics {\n private queue: EventQueue;\n private session: SessionManager;\n private errorHandler: GlobalErrorHandler | null = null;\n private debug: ReturnType<typeof createDebugLogger>;\n private config: Required<\n Pick<BoringAnalyticsConfig, 'defaultProperties'>\n > & BoringAnalyticsConfig;\n private pageViewUnsubscribe: (() => void) | null = null;\n\n constructor(config: BoringAnalyticsConfig) {\n if (!config.apiKey) {\n throw new Error('BoringAnalytics: apiKey is required');\n }\n\n this.config = {\n ...config,\n defaultProperties: config.defaultProperties ?? {},\n };\n\n this.debug = createDebugLogger(config.debug ?? false);\n this.debug.log('Initializing with endpoint:', config.endpoint ?? DEFAULT_ENDPOINT);\n\n const storage = createStorage();\n this.session = new SessionManager(storage);\n\n const transport = new Transport({\n endpoint: config.endpoint ?? DEFAULT_ENDPOINT,\n apiKey: config.apiKey,\n maxRetries: config.maxRetries ?? DEFAULT_MAX_RETRIES,\n onError: config.onError,\n });\n\n this.queue = new EventQueue(transport, {\n flushAt: config.flushAt ?? DEFAULT_FLUSH_AT,\n flushInterval: config.flushInterval ?? DEFAULT_FLUSH_INTERVAL,\n debug: this.debug,\n });\n\n const autoCapture = config.autoCapture ?? {};\n\n if (autoCapture.errors !== false) {\n this.errorHandler = new GlobalErrorHandler((error, source) => {\n this.captureError(error, {\n handled: false,\n metadata: { source },\n });\n });\n this.errorHandler.install();\n }\n\n if (autoCapture.pageViews && isBrowser()) {\n this.installPageViewTracking();\n }\n }\n\n // --- Public API ---\n\n /**\n * Track a named event.\n *\n * @example\n * analytics.track('button_clicked', { properties: { buttonId: 'signup' } });\n */\n track(name: string, options: TrackOptions = {}): void {\n this.enqueueEvent('TRACK', name, options.properties, options.timestamp, options.context);\n }\n\n /**\n * Identify a user with traits.\n * Sets the userId for all subsequent calls.\n *\n * @example\n * analytics.identify('user-123', { traits: { email: 'user@example.com' } });\n */\n identify(userId: string, options: IdentifyOptions = {}): void {\n this.session.setUserId(userId);\n this.enqueueEvent('IDENTIFY', 'identify', options.traits, options.timestamp, options.context);\n }\n\n /**\n * Track a page view (typically browser).\n *\n * @example\n * analytics.page('Home');\n * analytics.page('Product', { properties: { productId: '123' } });\n */\n page(name?: string, options: PageOptions = {}): void {\n const pageName = name ?? (isBrowser() ? document.title : 'Page View');\n this.enqueueEvent('PAGE', pageName, options.properties, options.timestamp, options.context);\n }\n\n /**\n * Track a screen view (typically mobile).\n */\n screen(name: string, options: ScreenOptions = {}): void {\n this.enqueueEvent('SCREEN', name, options.properties, options.timestamp, options.context);\n }\n\n /**\n * Associate a user with a group.\n */\n group(groupId: string, options: GroupOptions = {}): void {\n this.enqueueEvent('GROUP', groupId, options.traits, options.timestamp, options.context);\n }\n\n /**\n * Create an alias between two user identities.\n */\n alias(userId: string, previousId: string): void {\n this.enqueueEvent('ALIAS', 'alias', { userId, previousId });\n }\n\n /**\n * Capture an error for error monitoring.\n *\n * @example\n * try { riskyOp(); }\n * catch (err) { analytics.captureError(err, { tags: { env: 'prod' } }); }\n */\n captureError(\n error: Error | string,\n options: CaptureErrorOptions = {},\n ): void {\n const err = typeof error === 'string' ? new Error(error) : error;\n const autoContext = gatherContext();\n\n const payload: IngestErrorPayload = {\n type: err.name || 'Error',\n message: err.message,\n stackTrace: err.stack,\n level: options.level ?? 'ERROR',\n fingerprint: options.fingerprint,\n handled: options.handled ?? true,\n metadata: options.metadata,\n tags: options.tags,\n timestamp: (options.timestamp ?? new Date()).toISOString(),\n userId: this.session.getUserId() ?? undefined,\n sessionId: this.session.getSessionId(),\n context: {\n userAgent: autoContext.userAgent,\n browser: autoContext.browser?.name,\n os: autoContext.os?.name,\n device: autoContext.device?.type,\n url: autoContext.page?.url,\n release: options.release,\n },\n };\n\n this.queue.add({ kind: 'error', payload });\n }\n\n /**\n * Flush all queued events and errors immediately.\n */\n async flush(): Promise<void> {\n await this.queue.flush();\n }\n\n /**\n * Reset the current user. Clears userId, generates new anonymousId and sessionId.\n * Call this on logout.\n */\n reset(): void {\n this.session.reset();\n this.debug.log('User reset');\n }\n\n /**\n * Gracefully shut down: flush remaining events, remove global handlers.\n */\n async shutdown(): Promise<void> {\n this.debug.log('Shutting down');\n this.errorHandler?.uninstall();\n this.pageViewUnsubscribe?.();\n await this.queue.shutdown();\n }\n\n // --- Internal ---\n\n private enqueueEvent(\n type: IngestEventPayload['type'],\n name: string,\n properties?: Record<string, unknown>,\n timestamp?: Date,\n userContext?: Partial<EventContext>,\n ): void {\n const autoContext = gatherContext();\n const context = mergeContext(autoContext, userContext);\n\n const payload: IngestEventPayload = {\n type,\n name,\n properties: { ...this.config.defaultProperties, ...properties },\n timestamp: (timestamp ?? new Date()).toISOString(),\n userId: this.session.getUserId() ?? undefined,\n sessionId: this.session.getSessionId(),\n anonymousId: this.session.getAnonymousId(),\n context,\n };\n\n this.queue.add({ kind: 'event', payload });\n }\n\n private installPageViewTracking(): void {\n if (!isBrowser()) return;\n\n let lastUrl = window.location.href;\n\n const checkUrl = () => {\n const currentUrl = window.location.href;\n if (currentUrl !== lastUrl) {\n lastUrl = currentUrl;\n this.page();\n }\n };\n\n // Patch pushState/replaceState for SPA navigation\n const origPushState = history.pushState.bind(history);\n const origReplaceState = history.replaceState.bind(history);\n\n history.pushState = (...args: Parameters<typeof history.pushState>) => {\n origPushState(...args);\n checkUrl();\n };\n\n history.replaceState = (...args: Parameters<typeof history.replaceState>) => {\n origReplaceState(...args);\n checkUrl();\n };\n\n window.addEventListener('popstate', checkUrl);\n\n this.pageViewUnsubscribe = () => {\n history.pushState = origPushState;\n history.replaceState = origReplaceState;\n window.removeEventListener('popstate', checkUrl);\n };\n\n // Track initial page view\n this.page();\n }\n}\n"]}
1
+ {"version":3,"sources":["../src/transport.ts","../src/queue.ts","../src/utils.ts","../src/session.ts","../src/error-handler.ts","../src/context.ts","../src/storage.ts","../src/auto-capture/web-vitals.ts","../src/auto-capture/scroll-depth.ts","../src/auto-capture/outbound-clicks.ts","../src/client.ts"],"names":["onCLS","onFID","onINP","onLCP","onTTFB"],"mappings":"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","file":"index.js","sourcesContent":["import type { IngestEventPayload, IngestErrorPayload } from './types';\n\nexport interface TransportConfig {\n endpoint: string;\n apiKey: string;\n maxRetries: number;\n onError?: (error: Error) => void;\n}\n\nexport class Transport {\n private config: TransportConfig;\n\n constructor(config: TransportConfig) {\n this.config = config;\n }\n\n async sendEvents(events: IngestEventPayload[]): Promise<void> {\n await this.post('/ingest/events', { events });\n }\n\n async sendErrors(errors: IngestErrorPayload[]): Promise<void> {\n await this.post('/ingest/errors', { errors });\n }\n\n private async post(path: string, body: unknown): Promise<void> {\n const url = this.config.endpoint.replace(/\\/+$/, '') + path;\n let lastError: Error | undefined;\n\n for (let attempt = 0; attempt <= this.config.maxRetries; attempt++) {\n try {\n const response = await fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'x-api-key': this.config.apiKey,\n },\n body: JSON.stringify(body),\n keepalive: true,\n });\n\n if (response.ok) return;\n\n if (response.status >= 400 && response.status < 500 && response.status !== 429) {\n const text = await response.text().catch(() => '');\n throw new Error(`HTTP ${response.status}: ${text}`);\n }\n\n lastError = new Error(`HTTP ${response.status}`);\n } catch (err) {\n lastError = err instanceof Error ? err : new Error(String(err));\n if (err instanceof Error && err.message.startsWith('HTTP 4')) {\n break;\n }\n }\n\n if (attempt < this.config.maxRetries) {\n await this.backoff(attempt);\n }\n }\n\n if (lastError) {\n this.config.onError?.(lastError);\n }\n }\n\n private backoff(attempt: number): Promise<void> {\n const delay = Math.min(1000 * 2 ** attempt, 30000);\n const jitter = delay * (0.5 + Math.random() * 0.5);\n return new Promise((resolve) => setTimeout(resolve, jitter));\n }\n}\n","import type { QueueItem, IngestEventPayload, IngestErrorPayload } from './types';\nimport type { Transport } from './transport';\n\nexport interface QueueConfig {\n flushAt: number;\n flushInterval: number;\n debug: ReturnType<typeof import('./utils').createDebugLogger>;\n}\n\nexport class EventQueue {\n private items: QueueItem[] = [];\n private timer: ReturnType<typeof setInterval> | null = null;\n private transport: Transport;\n private config: QueueConfig;\n private flushing = false;\n\n constructor(transport: Transport, config: QueueConfig) {\n this.transport = transport;\n this.config = config;\n this.startTimer();\n }\n\n add(item: QueueItem): void {\n this.items.push(item);\n this.config.debug.log(`Queued ${item.kind}:`, item.kind === 'event' ? item.payload.name : item.payload.message);\n\n if (this.items.length >= this.config.flushAt) {\n void this.flush();\n }\n }\n\n async flush(): Promise<void> {\n if (this.flushing || this.items.length === 0) return;\n\n this.flushing = true;\n const batch = this.items.splice(0);\n\n try {\n const events: IngestEventPayload[] = [];\n const errors: IngestErrorPayload[] = [];\n\n for (const item of batch) {\n if (item.kind === 'event') events.push(item.payload);\n else errors.push(item.payload);\n }\n\n const promises: Promise<void>[] = [];\n if (events.length > 0) {\n this.config.debug.log(`Flushing ${events.length} events`);\n promises.push(this.transport.sendEvents(events));\n }\n if (errors.length > 0) {\n this.config.debug.log(`Flushing ${errors.length} errors`);\n promises.push(this.transport.sendErrors(errors));\n }\n\n await Promise.all(promises);\n } catch {\n this.items.unshift(...batch);\n } finally {\n this.flushing = false;\n }\n }\n\n private startTimer(): void {\n if (this.config.flushInterval > 0) {\n this.timer = setInterval(() => {\n void this.flush();\n }, this.config.flushInterval);\n\n // Allow Node.js to exit without waiting for the timer\n if (this.timer && typeof (this.timer as NodeJS.Timeout).unref === 'function') {\n (this.timer as NodeJS.Timeout).unref();\n }\n }\n }\n\n async shutdown(): Promise<void> {\n if (this.timer) {\n clearInterval(this.timer);\n this.timer = null;\n }\n await this.flush();\n }\n\n get size(): number {\n return this.items.length;\n }\n}\n","export function generateId(): string {\n if (typeof crypto !== 'undefined' && crypto.randomUUID) {\n return crypto.randomUUID();\n }\n return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {\n const r = (Math.random() * 16) | 0;\n const v = c === 'x' ? r : (r & 0x3) | 0x8;\n return v.toString(16);\n });\n}\n\nexport function isBrowser(): boolean {\n return typeof window !== 'undefined' && typeof document !== 'undefined';\n}\n\nexport function now(): string {\n return new Date().toISOString();\n}\n\nexport function createDebugLogger(enabled: boolean) {\n return {\n log: (...args: unknown[]) => {\n if (enabled) console.log('[BoringAnalytics]', ...args);\n },\n warn: (...args: unknown[]) => {\n if (enabled) console.warn('[BoringAnalytics]', ...args);\n },\n error: (...args: unknown[]) => {\n if (enabled) console.error('[BoringAnalytics]', ...args);\n },\n };\n}\n","import type { Storage } from './storage';\nimport { generateId } from './utils';\n\nconst ANON_ID_KEY = 'anonymous_id';\nconst SESSION_ID_KEY = 'session_id';\nconst SESSION_EXPIRY_KEY = 'session_expiry';\n\n/** Session timeout: 30 minutes of inactivity */\nconst SESSION_TIMEOUT_MS = 30 * 60 * 1000;\n\nexport class SessionManager {\n private userId: string | null = null;\n private anonymousId: string;\n private sessionId: string;\n private storage: Storage;\n\n constructor(storage: Storage) {\n this.storage = storage;\n this.anonymousId = this.storage.get(ANON_ID_KEY) ?? this.createAnonymousId();\n this.sessionId = this.resolveSession();\n }\n\n private createAnonymousId(): string {\n const id = generateId();\n this.storage.set(ANON_ID_KEY, id);\n return id;\n }\n\n private resolveSession(): string {\n const existingSession = this.storage.get(SESSION_ID_KEY);\n const expiryStr = this.storage.get(SESSION_EXPIRY_KEY);\n const expiry = expiryStr ? parseInt(expiryStr, 10) : 0;\n\n if (existingSession && Date.now() < expiry) {\n this.touchSession();\n return existingSession;\n }\n\n return this.startNewSession();\n }\n\n private startNewSession(): string {\n const id = generateId();\n this.sessionId = id;\n this.storage.set(SESSION_ID_KEY, id);\n this.touchSession();\n return id;\n }\n\n private touchSession(): void {\n this.storage.set(\n SESSION_EXPIRY_KEY,\n String(Date.now() + SESSION_TIMEOUT_MS),\n );\n }\n\n setUserId(id: string): void {\n this.userId = id;\n }\n\n getUserId(): string | null {\n return this.userId;\n }\n\n getAnonymousId(): string {\n return this.anonymousId;\n }\n\n getSessionId(): string {\n this.sessionId = this.resolveSession();\n return this.sessionId;\n }\n\n reset(): void {\n this.userId = null;\n this.anonymousId = this.createAnonymousId();\n this.sessionId = this.startNewSession();\n }\n}\n","import { isBrowser } from './utils';\n\ntype ErrorCallback = (error: Error, source?: string) => void;\n\nexport class GlobalErrorHandler {\n private callback: ErrorCallback;\n private installed = false;\n private originalOnError: OnErrorEventHandler | null = null;\n private originalOnUnhandledRejection: ((ev: PromiseRejectionEvent) => void) | null = null;\n\n constructor(callback: ErrorCallback) {\n this.callback = callback;\n }\n\n install(): void {\n if (this.installed) return;\n this.installed = true;\n\n if (isBrowser()) {\n this.installBrowser();\n } else {\n this.installNode();\n }\n }\n\n uninstall(): void {\n if (!this.installed) return;\n this.installed = false;\n\n if (isBrowser()) {\n this.uninstallBrowser();\n } else {\n this.uninstallNode();\n }\n }\n\n private installBrowser(): void {\n this.originalOnError = window.onerror;\n window.onerror = (message, source, lineno, colno, error) => {\n if (error) {\n this.callback(error, source ?? undefined);\n } else if (typeof message === 'string') {\n this.callback(new Error(message), source ?? undefined);\n }\n this.originalOnError?.call(window, message, source, lineno, colno, error);\n };\n\n this.originalOnUnhandledRejection = window.onunhandledrejection as typeof this.originalOnUnhandledRejection;\n window.onunhandledrejection = (event: PromiseRejectionEvent) => {\n const error =\n event.reason instanceof Error\n ? event.reason\n : new Error(String(event.reason));\n this.callback(error, 'unhandledrejection');\n (this.originalOnUnhandledRejection as ((ev: PromiseRejectionEvent) => void) | null)?.call(window, event);\n };\n }\n\n private uninstallBrowser(): void {\n window.onerror = this.originalOnError;\n window.onunhandledrejection = this.originalOnUnhandledRejection as typeof window.onunhandledrejection;\n }\n\n private installNode(): void {\n if (typeof process === 'undefined') return;\n\n process.on('uncaughtException', this.handleNodeError);\n process.on('unhandledRejection', this.handleNodeRejection);\n }\n\n private uninstallNode(): void {\n if (typeof process === 'undefined') return;\n\n process.removeListener('uncaughtException', this.handleNodeError);\n process.removeListener('unhandledRejection', this.handleNodeRejection);\n }\n\n private handleNodeError = (error: Error): void => {\n this.callback(error, 'uncaughtException');\n };\n\n private handleNodeRejection = (reason: unknown): void => {\n const error = reason instanceof Error ? reason : new Error(String(reason));\n this.callback(error, 'unhandledRejection');\n };\n}\n","import type { EventContext } from './types';\nimport { isBrowser } from './utils';\n\n/**\n * Parses a user agent string into browser, OS, and device info.\n * Lightweight — covers major browsers/platforms without a full UA parser dependency.\n */\nfunction parseUserAgent(ua: string): {\n browser: { name: string; version?: string };\n os: { name: string; version?: string };\n device: { type: string };\n} {\n const browser = { name: 'Unknown', version: undefined as string | undefined };\n const os = { name: 'Unknown', version: undefined as string | undefined };\n const device = { type: 'desktop' };\n\n // Mobile detection\n if (/Mobi|Android|iPhone|iPad|iPod/i.test(ua)) {\n device.type = /iPad|Tablet/i.test(ua) ? 'tablet' : 'mobile';\n }\n\n // Browser detection\n if (/Edg\\//i.test(ua)) {\n browser.name = 'Edge';\n browser.version = ua.match(/Edg\\/([\\d.]+)/)?.[1];\n } else if (/OPR\\//i.test(ua) || /Opera/i.test(ua)) {\n browser.name = 'Opera';\n browser.version = ua.match(/(?:OPR|Opera)\\/([\\d.]+)/)?.[1];\n } else if (/Chrome\\//i.test(ua) && !/Chromium/i.test(ua)) {\n browser.name = 'Chrome';\n browser.version = ua.match(/Chrome\\/([\\d.]+)/)?.[1];\n } else if (/Safari\\//i.test(ua) && !/Chrome/i.test(ua)) {\n browser.name = 'Safari';\n browser.version = ua.match(/Version\\/([\\d.]+)/)?.[1];\n } else if (/Firefox\\//i.test(ua)) {\n browser.name = 'Firefox';\n browser.version = ua.match(/Firefox\\/([\\d.]+)/)?.[1];\n }\n\n // OS detection\n if (/Windows NT/i.test(ua)) {\n os.name = 'Windows';\n const ntVersion = ua.match(/Windows NT ([\\d.]+)/)?.[1];\n const versionMap: Record<string, string> = {\n '10.0': '10+',\n '6.3': '8.1',\n '6.2': '8',\n '6.1': '7',\n };\n os.version = ntVersion ? (versionMap[ntVersion] ?? ntVersion) : undefined;\n } else if (/Mac OS X/i.test(ua)) {\n os.name = 'macOS';\n os.version = ua.match(/Mac OS X ([\\d_.]+)/)?.[1]?.replace(/_/g, '.');\n } else if (/Android/i.test(ua)) {\n os.name = 'Android';\n os.version = ua.match(/Android ([\\d.]+)/)?.[1];\n } else if (/iPhone OS|iPad/i.test(ua)) {\n os.name = 'iOS';\n os.version = ua.match(/OS ([\\d_]+)/)?.[1]?.replace(/_/g, '.');\n } else if (/Linux/i.test(ua)) {\n os.name = 'Linux';\n }\n\n return { browser, os, device };\n}\n\nexport function gatherContext(): EventContext {\n if (!isBrowser()) {\n return {};\n }\n\n const ua = navigator.userAgent;\n const { browser, os, device } = parseUserAgent(ua);\n\n return {\n userAgent: ua,\n locale: navigator.language,\n page: {\n url: window.location.href,\n referrer: document.referrer || undefined,\n title: document.title || undefined,\n path: window.location.pathname,\n },\n browser,\n os,\n device,\n };\n}\n\nexport function mergeContext(\n auto: EventContext,\n user?: Partial<EventContext>,\n): EventContext {\n if (!user) return auto;\n\n return {\n ...auto,\n ...user,\n page: { ...auto.page, ...user.page },\n browser: { ...auto.browser, ...user.browser },\n os: { ...auto.os, ...user.os },\n device: { ...auto.device, ...user.device },\n };\n}\n","const PREFIX = 'ba_';\n\nexport interface Storage {\n get(key: string): string | null;\n set(key: string, value: string): void;\n remove(key: string): void;\n}\n\nclass LocalStorage implements Storage {\n get(key: string): string | null {\n try {\n return localStorage.getItem(PREFIX + key);\n } catch {\n return null;\n }\n }\n\n set(key: string, value: string): void {\n try {\n localStorage.setItem(PREFIX + key, value);\n } catch {\n // localStorage unavailable or quota exceeded\n }\n }\n\n remove(key: string): void {\n try {\n localStorage.removeItem(PREFIX + key);\n } catch {\n // noop\n }\n }\n}\n\nclass MemoryStorage implements Storage {\n private store = new Map<string, string>();\n\n get(key: string): string | null {\n return this.store.get(PREFIX + key) ?? null;\n }\n\n set(key: string, value: string): void {\n this.store.set(PREFIX + key, value);\n }\n\n remove(key: string): void {\n this.store.delete(PREFIX + key);\n }\n}\n\nexport function createStorage(): Storage {\n try {\n if (typeof localStorage !== 'undefined') {\n localStorage.setItem('__ba_test__', '1');\n localStorage.removeItem('__ba_test__');\n return new LocalStorage();\n }\n } catch {\n // localStorage not available\n }\n return new MemoryStorage();\n}\n","import { onCLS, onFID, onINP, onLCP, onTTFB } from 'web-vitals';\nimport type { Metric } from 'web-vitals';\n\nexport type WebVitalsCallback = (metric: { name: string; value: number; rating?: string; delta?: number; id?: string }) => void;\n\nexport function installWebVitals(report: WebVitalsCallback): () => void {\n const reportMetric = (metric: Metric) => {\n report({\n name: metric.name,\n value: metric.value,\n rating: metric.rating,\n delta: metric.delta,\n id: metric.id,\n });\n };\n\n onCLS(reportMetric);\n onFID(reportMetric);\n onINP(reportMetric);\n onLCP(reportMetric);\n onTTFB(reportMetric);\n\n return () => {\n // web-vitals doesn't expose uninstall; handlers fire once per metric\n };\n}\n","export type ScrollDepthCallback = (depth: number) => void;\n\nconst DEPTHS = [25, 50, 75, 100];\n\nexport function installScrollDepth(report: ScrollDepthCallback): () => void {\n const reported = new Set<number>();\n\n const onScroll = () => {\n if (typeof document === 'undefined' || !document.documentElement) return;\n\n const scrollHeight = document.documentElement.scrollHeight - window.innerHeight;\n if (scrollHeight <= 0) return;\n\n const scrollPercent = Math.round((window.scrollY / scrollHeight) * 100);\n\n for (const d of DEPTHS) {\n if (scrollPercent >= d && !reported.has(d)) {\n reported.add(d);\n report(d);\n }\n }\n };\n\n window.addEventListener('scroll', onScroll, { passive: true });\n // Fire once in case already scrolled\n onScroll();\n\n return () => {\n window.removeEventListener('scroll', onScroll);\n };\n}\n","export type OutboundClickCallback = (payload: { href: string; domain?: string; type: 'external' | 'download' }) => void;\n\nfunction getLinkTarget(e: MouseEvent): HTMLAnchorElement | null {\n let el: HTMLElement | null = e.target as HTMLElement;\n while (el && el !== document.body) {\n if (el.tagName === 'A' && (el as HTMLAnchorElement).href) {\n return el as HTMLAnchorElement;\n }\n el = el.parentElement;\n }\n return null;\n}\n\nfunction isDownload(anchor: HTMLAnchorElement): boolean {\n const attr = anchor.getAttribute('download');\n const href = (anchor.getAttribute('href') || '').toLowerCase();\n return attr !== null || /\\.(pdf|zip|docx?|xlsx?|csv|mp3|mp4|apk)(\\?|$)/i.test(href);\n}\n\nfunction isExternal(anchor: HTMLAnchorElement): boolean {\n try {\n return anchor.hostname !== window.location.hostname && anchor.protocol.startsWith('http');\n } catch {\n return false;\n }\n}\n\nexport function installOutboundClickTracking(report: OutboundClickCallback): () => void {\n const handler = (e: MouseEvent) => {\n const anchor = getLinkTarget(e);\n if (!anchor) return;\n\n const href = anchor.href;\n if (isDownload(anchor)) {\n report({ href, type: 'download' });\n return;\n }\n if (isExternal(anchor)) {\n report({ href, domain: anchor.hostname, type: 'external' });\n }\n };\n\n document.addEventListener('click', handler, true);\n\n return () => {\n document.removeEventListener('click', handler, true);\n };\n}\n","import type {\n BoringAnalyticsConfig,\n TrackOptions,\n IdentifyOptions,\n PageOptions,\n ScreenOptions,\n GroupOptions,\n CaptureErrorOptions,\n TrackRevenueOptions,\n TrackExposureOptions,\n IngestEventPayload,\n IngestErrorPayload,\n EventContext,\n} from './types';\nimport { Transport } from './transport';\nimport { EventQueue } from './queue';\nimport { SessionManager } from './session';\nimport { GlobalErrorHandler } from './error-handler';\nimport { gatherContext, mergeContext } from './context';\nimport { createStorage } from './storage';\nimport { createDebugLogger, isBrowser } from './utils';\nimport { installWebVitals } from './auto-capture/web-vitals';\nimport { installScrollDepth } from './auto-capture/scroll-depth';\nimport { installOutboundClickTracking } from './auto-capture/outbound-clicks';\n\nconst DEFAULT_ENDPOINT = 'https://api.boring.yraylabs.fun';\nconst DEFAULT_FLUSH_AT = 20;\nconst DEFAULT_FLUSH_INTERVAL = 5000;\nconst DEFAULT_MAX_RETRIES = 3;\n\nexport class BoringAnalytics {\n private queue: EventQueue;\n private session: SessionManager;\n private errorHandler: GlobalErrorHandler | null = null;\n private debug: ReturnType<typeof createDebugLogger>;\n private config: Required<\n Pick<BoringAnalyticsConfig, 'defaultProperties'>\n > & BoringAnalyticsConfig;\n private pageViewUnsubscribe: (() => void) | null = null;\n private webVitalsUnsubscribe: (() => void) | null = null;\n private scrollDepthUnsubscribe: (() => void) | null = null;\n private outboundClicksUnsubscribe: (() => void) | null = null;\n\n constructor(config: BoringAnalyticsConfig) {\n if (!config.apiKey) {\n throw new Error('BoringAnalytics: apiKey is required');\n }\n\n this.config = {\n ...config,\n defaultProperties: config.defaultProperties ?? {},\n };\n\n this.debug = createDebugLogger(config.debug ?? false);\n this.debug.log('Initializing with endpoint:', config.endpoint ?? DEFAULT_ENDPOINT);\n\n const storage = createStorage();\n this.session = new SessionManager(storage);\n\n const transport = new Transport({\n endpoint: config.endpoint ?? DEFAULT_ENDPOINT,\n apiKey: config.apiKey,\n maxRetries: config.maxRetries ?? DEFAULT_MAX_RETRIES,\n onError: config.onError,\n });\n\n this.queue = new EventQueue(transport, {\n flushAt: config.flushAt ?? DEFAULT_FLUSH_AT,\n flushInterval: config.flushInterval ?? DEFAULT_FLUSH_INTERVAL,\n debug: this.debug,\n });\n\n const autoCapture = config.autoCapture ?? {};\n\n if (autoCapture.errors !== false) {\n this.errorHandler = new GlobalErrorHandler((error, source) => {\n this.captureError(error, {\n handled: false,\n metadata: { source },\n });\n });\n this.errorHandler.install();\n }\n\n if (autoCapture.pageViews && isBrowser()) {\n this.installPageViewTracking();\n }\n\n if (autoCapture.webVitals && isBrowser()) {\n this.webVitalsUnsubscribe = installWebVitals((metric) => {\n this.track('web_vitals', {\n properties: {\n metric: metric.name,\n value: metric.value,\n rating: metric.rating,\n delta: metric.delta,\n id: metric.id,\n },\n });\n });\n }\n\n if (autoCapture.scrollDepth && isBrowser()) {\n this.scrollDepthUnsubscribe = installScrollDepth((depth) => {\n this.track('scroll_depth', { properties: { depth } });\n });\n }\n\n if (autoCapture.outboundClicks && isBrowser()) {\n this.outboundClicksUnsubscribe = installOutboundClickTracking((payload) => {\n this.track('outbound_click', {\n properties: {\n href: payload.href,\n domain: payload.domain,\n link_type: payload.type,\n },\n });\n });\n }\n }\n\n // --- Public API ---\n\n /**\n * Track a named event.\n *\n * @example\n * analytics.track('button_clicked', { properties: { buttonId: 'signup' } });\n */\n track(name: string, options: TrackOptions = {}): void {\n this.enqueueEvent('TRACK', name, options.properties, options.timestamp, options.context);\n }\n\n /**\n * Identify a user with traits.\n * Sets the userId for all subsequent calls.\n *\n * @example\n * analytics.identify('user-123', { traits: { email: 'user@example.com' } });\n */\n identify(userId: string, options: IdentifyOptions = {}): void {\n this.session.setUserId(userId);\n this.enqueueEvent('IDENTIFY', 'identify', options.traits, options.timestamp, options.context);\n }\n\n /**\n * Track a page view (typically browser).\n *\n * @example\n * analytics.page('Home');\n * analytics.page('Product', { properties: { productId: '123' } });\n */\n page(name?: string, options: PageOptions = {}): void {\n const pageName = name ?? (isBrowser() ? document.title : 'Page View');\n this.enqueueEvent('PAGE', pageName, options.properties, options.timestamp, options.context);\n }\n\n /**\n * Track a screen view (typically mobile).\n */\n screen(name: string, options: ScreenOptions = {}): void {\n this.enqueueEvent('SCREEN', name, options.properties, options.timestamp, options.context);\n }\n\n /**\n * Associate a user with a group.\n */\n group(groupId: string, options: GroupOptions = {}): void {\n this.enqueueEvent('GROUP', groupId, options.traits, options.timestamp, options.context);\n }\n\n /**\n * Create an alias between two user identities.\n */\n alias(userId: string, previousId: string): void {\n this.enqueueEvent('ALIAS', 'alias', { userId, previousId });\n }\n\n /**\n * Track revenue (e.g. purchase, subscription).\n * Sends a TRACK event with name \"purchase\" and amount/currency in properties.\n *\n * @example\n * analytics.trackRevenue({ amount: 29.99, currency: 'USD', properties: { orderId: 'ord_123' } });\n */\n trackRevenue(options: TrackRevenueOptions): void {\n const { amount, currency = 'USD', properties = {}, timestamp, context } = options;\n this.track('purchase', {\n properties: { amount, currency, ...properties },\n timestamp,\n context,\n });\n }\n\n /**\n * Track feature-flag or A–B test exposure.\n * Sends a TRACK event with name \"feature_exposed\" and flag/variant in properties.\n *\n * @example\n * analytics.trackExposure({ flag: 'pricing_test', variant: 'treatment' });\n */\n trackExposure(options: TrackExposureOptions): void {\n const { flag, variant, properties = {}, timestamp, context } = options;\n this.track('feature_exposed', {\n properties: { flag, variant, ...properties },\n timestamp,\n context,\n });\n }\n\n /**\n * Capture an error for error monitoring.\n *\n * @example\n * try { riskyOp(); }\n * catch (err) { analytics.captureError(err, { tags: { env: 'prod' } }); }\n */\n captureError(\n error: Error | string,\n options: CaptureErrorOptions = {},\n ): void {\n const err = typeof error === 'string' ? new Error(error) : error;\n const autoContext = gatherContext();\n\n const payload: IngestErrorPayload = {\n type: err.name || 'Error',\n message: err.message,\n stackTrace: err.stack,\n level: options.level ?? 'ERROR',\n fingerprint: options.fingerprint,\n handled: options.handled ?? true,\n metadata: options.metadata,\n tags: options.tags,\n timestamp: (options.timestamp ?? new Date()).toISOString(),\n userId: this.session.getUserId() ?? undefined,\n sessionId: this.session.getSessionId(),\n context: {\n userAgent: autoContext.userAgent,\n browser: autoContext.browser?.name,\n os: autoContext.os?.name,\n device: autoContext.device?.type,\n url: autoContext.page?.url,\n release: options.release,\n },\n };\n\n this.queue.add({ kind: 'error', payload });\n }\n\n /**\n * Flush all queued events and errors immediately.\n */\n async flush(): Promise<void> {\n await this.queue.flush();\n }\n\n /**\n * Reset the current user. Clears userId, generates new anonymousId and sessionId.\n * Call this on logout.\n */\n reset(): void {\n this.session.reset();\n this.debug.log('User reset');\n }\n\n /**\n * Gracefully shut down: flush remaining events, remove global handlers.\n */\n async shutdown(): Promise<void> {\n this.debug.log('Shutting down');\n this.errorHandler?.uninstall();\n this.pageViewUnsubscribe?.();\n this.webVitalsUnsubscribe?.();\n this.scrollDepthUnsubscribe?.();\n this.outboundClicksUnsubscribe?.();\n await this.queue.shutdown();\n }\n\n // --- Internal ---\n\n private enqueueEvent(\n type: IngestEventPayload['type'],\n name: string,\n properties?: Record<string, unknown>,\n timestamp?: Date,\n userContext?: Partial<EventContext>,\n ): void {\n const autoContext = gatherContext();\n const context = mergeContext(autoContext, userContext);\n\n const payload: IngestEventPayload = {\n type,\n name,\n properties: { ...this.config.defaultProperties, ...properties },\n timestamp: (timestamp ?? new Date()).toISOString(),\n userId: this.session.getUserId() ?? undefined,\n sessionId: this.session.getSessionId(),\n anonymousId: this.session.getAnonymousId(),\n context,\n };\n\n this.queue.add({ kind: 'event', payload });\n }\n\n private installPageViewTracking(): void {\n if (!isBrowser()) return;\n\n let lastUrl = window.location.href;\n\n const checkUrl = () => {\n const currentUrl = window.location.href;\n if (currentUrl !== lastUrl) {\n lastUrl = currentUrl;\n this.page();\n }\n };\n\n // Patch pushState/replaceState for SPA navigation\n const origPushState = history.pushState.bind(history);\n const origReplaceState = history.replaceState.bind(history);\n\n history.pushState = (...args: Parameters<typeof history.pushState>) => {\n origPushState(...args);\n checkUrl();\n };\n\n history.replaceState = (...args: Parameters<typeof history.replaceState>) => {\n origReplaceState(...args);\n checkUrl();\n };\n\n window.addEventListener('popstate', checkUrl);\n\n this.pageViewUnsubscribe = () => {\n history.pushState = origPushState;\n history.replaceState = origReplaceState;\n window.removeEventListener('popstate', checkUrl);\n };\n\n // Track initial page view\n this.page();\n }\n}\n"]}
package/dist/index.mjs CHANGED
@@ -1,3 +1,5 @@
1
+ import { onCLS, onFID, onINP, onLCP, onTTFB } from 'web-vitals';
2
+
1
3
  // src/transport.ts
2
4
  var Transport = class {
3
5
  constructor(config) {
@@ -398,9 +400,92 @@ function createStorage() {
398
400
  }
399
401
  return new MemoryStorage();
400
402
  }
403
+ function installWebVitals(report) {
404
+ const reportMetric = (metric) => {
405
+ report({
406
+ name: metric.name,
407
+ value: metric.value,
408
+ rating: metric.rating,
409
+ delta: metric.delta,
410
+ id: metric.id
411
+ });
412
+ };
413
+ onCLS(reportMetric);
414
+ onFID(reportMetric);
415
+ onINP(reportMetric);
416
+ onLCP(reportMetric);
417
+ onTTFB(reportMetric);
418
+ return () => {
419
+ };
420
+ }
421
+
422
+ // src/auto-capture/scroll-depth.ts
423
+ var DEPTHS = [25, 50, 75, 100];
424
+ function installScrollDepth(report) {
425
+ const reported = /* @__PURE__ */ new Set();
426
+ const onScroll = () => {
427
+ if (typeof document === "undefined" || !document.documentElement) return;
428
+ const scrollHeight = document.documentElement.scrollHeight - window.innerHeight;
429
+ if (scrollHeight <= 0) return;
430
+ const scrollPercent = Math.round(window.scrollY / scrollHeight * 100);
431
+ for (const d of DEPTHS) {
432
+ if (scrollPercent >= d && !reported.has(d)) {
433
+ reported.add(d);
434
+ report(d);
435
+ }
436
+ }
437
+ };
438
+ window.addEventListener("scroll", onScroll, { passive: true });
439
+ onScroll();
440
+ return () => {
441
+ window.removeEventListener("scroll", onScroll);
442
+ };
443
+ }
444
+
445
+ // src/auto-capture/outbound-clicks.ts
446
+ function getLinkTarget(e) {
447
+ let el = e.target;
448
+ while (el && el !== document.body) {
449
+ if (el.tagName === "A" && el.href) {
450
+ return el;
451
+ }
452
+ el = el.parentElement;
453
+ }
454
+ return null;
455
+ }
456
+ function isDownload(anchor) {
457
+ const attr = anchor.getAttribute("download");
458
+ const href = (anchor.getAttribute("href") || "").toLowerCase();
459
+ return attr !== null || /\.(pdf|zip|docx?|xlsx?|csv|mp3|mp4|apk)(\?|$)/i.test(href);
460
+ }
461
+ function isExternal(anchor) {
462
+ try {
463
+ return anchor.hostname !== window.location.hostname && anchor.protocol.startsWith("http");
464
+ } catch {
465
+ return false;
466
+ }
467
+ }
468
+ function installOutboundClickTracking(report) {
469
+ const handler = (e) => {
470
+ const anchor = getLinkTarget(e);
471
+ if (!anchor) return;
472
+ const href = anchor.href;
473
+ if (isDownload(anchor)) {
474
+ report({ href, type: "download" });
475
+ return;
476
+ }
477
+ if (isExternal(anchor)) {
478
+ report({ href, domain: anchor.hostname, type: "external" });
479
+ }
480
+ };
481
+ document.addEventListener("click", handler, true);
482
+ return () => {
483
+ document.removeEventListener("click", handler, true);
484
+ };
485
+ }
401
486
 
402
487
  // src/client.ts
403
- var DEFAULT_ENDPOINT = "https://api.boringanalytics.io";
488
+ var DEFAULT_ENDPOINT = "https://api.boring.yraylabs.fun";
404
489
  var DEFAULT_FLUSH_AT = 20;
405
490
  var DEFAULT_FLUSH_INTERVAL = 5e3;
406
491
  var DEFAULT_MAX_RETRIES = 3;
@@ -408,6 +493,9 @@ var BoringAnalytics = class {
408
493
  constructor(config) {
409
494
  this.errorHandler = null;
410
495
  this.pageViewUnsubscribe = null;
496
+ this.webVitalsUnsubscribe = null;
497
+ this.scrollDepthUnsubscribe = null;
498
+ this.outboundClicksUnsubscribe = null;
411
499
  if (!config.apiKey) {
412
500
  throw new Error("BoringAnalytics: apiKey is required");
413
501
  }
@@ -443,6 +531,35 @@ var BoringAnalytics = class {
443
531
  if (autoCapture.pageViews && isBrowser()) {
444
532
  this.installPageViewTracking();
445
533
  }
534
+ if (autoCapture.webVitals && isBrowser()) {
535
+ this.webVitalsUnsubscribe = installWebVitals((metric) => {
536
+ this.track("web_vitals", {
537
+ properties: {
538
+ metric: metric.name,
539
+ value: metric.value,
540
+ rating: metric.rating,
541
+ delta: metric.delta,
542
+ id: metric.id
543
+ }
544
+ });
545
+ });
546
+ }
547
+ if (autoCapture.scrollDepth && isBrowser()) {
548
+ this.scrollDepthUnsubscribe = installScrollDepth((depth) => {
549
+ this.track("scroll_depth", { properties: { depth } });
550
+ });
551
+ }
552
+ if (autoCapture.outboundClicks && isBrowser()) {
553
+ this.outboundClicksUnsubscribe = installOutboundClickTracking((payload) => {
554
+ this.track("outbound_click", {
555
+ properties: {
556
+ href: payload.href,
557
+ domain: payload.domain,
558
+ link_type: payload.type
559
+ }
560
+ });
561
+ });
562
+ }
446
563
  }
447
564
  // --- Public API ---
448
565
  /**
@@ -494,6 +611,36 @@ var BoringAnalytics = class {
494
611
  alias(userId, previousId) {
495
612
  this.enqueueEvent("ALIAS", "alias", { userId, previousId });
496
613
  }
614
+ /**
615
+ * Track revenue (e.g. purchase, subscription).
616
+ * Sends a TRACK event with name "purchase" and amount/currency in properties.
617
+ *
618
+ * @example
619
+ * analytics.trackRevenue({ amount: 29.99, currency: 'USD', properties: { orderId: 'ord_123' } });
620
+ */
621
+ trackRevenue(options) {
622
+ const { amount, currency = "USD", properties = {}, timestamp, context } = options;
623
+ this.track("purchase", {
624
+ properties: { amount, currency, ...properties },
625
+ timestamp,
626
+ context
627
+ });
628
+ }
629
+ /**
630
+ * Track feature-flag or A–B test exposure.
631
+ * Sends a TRACK event with name "feature_exposed" and flag/variant in properties.
632
+ *
633
+ * @example
634
+ * analytics.trackExposure({ flag: 'pricing_test', variant: 'treatment' });
635
+ */
636
+ trackExposure(options) {
637
+ const { flag, variant, properties = {}, timestamp, context } = options;
638
+ this.track("feature_exposed", {
639
+ properties: { flag, variant, ...properties },
640
+ timestamp,
641
+ context
642
+ });
643
+ }
497
644
  /**
498
645
  * Capture an error for error monitoring.
499
646
  *
@@ -548,6 +695,9 @@ var BoringAnalytics = class {
548
695
  this.debug.log("Shutting down");
549
696
  this.errorHandler?.uninstall();
550
697
  this.pageViewUnsubscribe?.();
698
+ this.webVitalsUnsubscribe?.();
699
+ this.scrollDepthUnsubscribe?.();
700
+ this.outboundClicksUnsubscribe?.();
551
701
  await this.queue.shutdown();
552
702
  }
553
703
  // --- Internal ---
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/transport.ts","../src/queue.ts","../src/utils.ts","../src/session.ts","../src/error-handler.ts","../src/context.ts","../src/storage.ts","../src/client.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["import type { IngestEventPayload, IngestErrorPayload } from './types';\n\nexport interface TransportConfig {\n endpoint: string;\n apiKey: string;\n maxRetries: number;\n onError?: (error: Error) => void;\n}\n\nexport class Transport {\n private config: TransportConfig;\n\n constructor(config: TransportConfig) {\n this.config = config;\n }\n\n async sendEvents(events: IngestEventPayload[]): Promise<void> {\n await this.post('/ingest/events', { events });\n }\n\n async sendErrors(errors: IngestErrorPayload[]): Promise<void> {\n await this.post('/ingest/errors', { errors });\n }\n\n private async post(path: string, body: unknown): Promise<void> {\n const url = this.config.endpoint.replace(/\\/+$/, '') + path;\n let lastError: Error | undefined;\n\n for (let attempt = 0; attempt <= this.config.maxRetries; attempt++) {\n try {\n const response = await fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'x-api-key': this.config.apiKey,\n },\n body: JSON.stringify(body),\n keepalive: true,\n });\n\n if (response.ok) return;\n\n if (response.status >= 400 && response.status < 500 && response.status !== 429) {\n const text = await response.text().catch(() => '');\n throw new Error(`HTTP ${response.status}: ${text}`);\n }\n\n lastError = new Error(`HTTP ${response.status}`);\n } catch (err) {\n lastError = err instanceof Error ? err : new Error(String(err));\n if (err instanceof Error && err.message.startsWith('HTTP 4')) {\n break;\n }\n }\n\n if (attempt < this.config.maxRetries) {\n await this.backoff(attempt);\n }\n }\n\n if (lastError) {\n this.config.onError?.(lastError);\n }\n }\n\n private backoff(attempt: number): Promise<void> {\n const delay = Math.min(1000 * 2 ** attempt, 30000);\n const jitter = delay * (0.5 + Math.random() * 0.5);\n return new Promise((resolve) => setTimeout(resolve, jitter));\n }\n}\n","import type { QueueItem, IngestEventPayload, IngestErrorPayload } from './types';\nimport type { Transport } from './transport';\n\nexport interface QueueConfig {\n flushAt: number;\n flushInterval: number;\n debug: ReturnType<typeof import('./utils').createDebugLogger>;\n}\n\nexport class EventQueue {\n private items: QueueItem[] = [];\n private timer: ReturnType<typeof setInterval> | null = null;\n private transport: Transport;\n private config: QueueConfig;\n private flushing = false;\n\n constructor(transport: Transport, config: QueueConfig) {\n this.transport = transport;\n this.config = config;\n this.startTimer();\n }\n\n add(item: QueueItem): void {\n this.items.push(item);\n this.config.debug.log(`Queued ${item.kind}:`, item.kind === 'event' ? item.payload.name : item.payload.message);\n\n if (this.items.length >= this.config.flushAt) {\n void this.flush();\n }\n }\n\n async flush(): Promise<void> {\n if (this.flushing || this.items.length === 0) return;\n\n this.flushing = true;\n const batch = this.items.splice(0);\n\n try {\n const events: IngestEventPayload[] = [];\n const errors: IngestErrorPayload[] = [];\n\n for (const item of batch) {\n if (item.kind === 'event') events.push(item.payload);\n else errors.push(item.payload);\n }\n\n const promises: Promise<void>[] = [];\n if (events.length > 0) {\n this.config.debug.log(`Flushing ${events.length} events`);\n promises.push(this.transport.sendEvents(events));\n }\n if (errors.length > 0) {\n this.config.debug.log(`Flushing ${errors.length} errors`);\n promises.push(this.transport.sendErrors(errors));\n }\n\n await Promise.all(promises);\n } catch {\n this.items.unshift(...batch);\n } finally {\n this.flushing = false;\n }\n }\n\n private startTimer(): void {\n if (this.config.flushInterval > 0) {\n this.timer = setInterval(() => {\n void this.flush();\n }, this.config.flushInterval);\n\n // Allow Node.js to exit without waiting for the timer\n if (this.timer && typeof (this.timer as NodeJS.Timeout).unref === 'function') {\n (this.timer as NodeJS.Timeout).unref();\n }\n }\n }\n\n async shutdown(): Promise<void> {\n if (this.timer) {\n clearInterval(this.timer);\n this.timer = null;\n }\n await this.flush();\n }\n\n get size(): number {\n return this.items.length;\n }\n}\n","export function generateId(): string {\n if (typeof crypto !== 'undefined' && crypto.randomUUID) {\n return crypto.randomUUID();\n }\n return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {\n const r = (Math.random() * 16) | 0;\n const v = c === 'x' ? r : (r & 0x3) | 0x8;\n return v.toString(16);\n });\n}\n\nexport function isBrowser(): boolean {\n return typeof window !== 'undefined' && typeof document !== 'undefined';\n}\n\nexport function now(): string {\n return new Date().toISOString();\n}\n\nexport function createDebugLogger(enabled: boolean) {\n return {\n log: (...args: unknown[]) => {\n if (enabled) console.log('[BoringAnalytics]', ...args);\n },\n warn: (...args: unknown[]) => {\n if (enabled) console.warn('[BoringAnalytics]', ...args);\n },\n error: (...args: unknown[]) => {\n if (enabled) console.error('[BoringAnalytics]', ...args);\n },\n };\n}\n","import type { Storage } from './storage';\nimport { generateId } from './utils';\n\nconst ANON_ID_KEY = 'anonymous_id';\nconst SESSION_ID_KEY = 'session_id';\nconst SESSION_EXPIRY_KEY = 'session_expiry';\n\n/** Session timeout: 30 minutes of inactivity */\nconst SESSION_TIMEOUT_MS = 30 * 60 * 1000;\n\nexport class SessionManager {\n private userId: string | null = null;\n private anonymousId: string;\n private sessionId: string;\n private storage: Storage;\n\n constructor(storage: Storage) {\n this.storage = storage;\n this.anonymousId = this.storage.get(ANON_ID_KEY) ?? this.createAnonymousId();\n this.sessionId = this.resolveSession();\n }\n\n private createAnonymousId(): string {\n const id = generateId();\n this.storage.set(ANON_ID_KEY, id);\n return id;\n }\n\n private resolveSession(): string {\n const existingSession = this.storage.get(SESSION_ID_KEY);\n const expiryStr = this.storage.get(SESSION_EXPIRY_KEY);\n const expiry = expiryStr ? parseInt(expiryStr, 10) : 0;\n\n if (existingSession && Date.now() < expiry) {\n this.touchSession();\n return existingSession;\n }\n\n return this.startNewSession();\n }\n\n private startNewSession(): string {\n const id = generateId();\n this.sessionId = id;\n this.storage.set(SESSION_ID_KEY, id);\n this.touchSession();\n return id;\n }\n\n private touchSession(): void {\n this.storage.set(\n SESSION_EXPIRY_KEY,\n String(Date.now() + SESSION_TIMEOUT_MS),\n );\n }\n\n setUserId(id: string): void {\n this.userId = id;\n }\n\n getUserId(): string | null {\n return this.userId;\n }\n\n getAnonymousId(): string {\n return this.anonymousId;\n }\n\n getSessionId(): string {\n this.sessionId = this.resolveSession();\n return this.sessionId;\n }\n\n reset(): void {\n this.userId = null;\n this.anonymousId = this.createAnonymousId();\n this.sessionId = this.startNewSession();\n }\n}\n","import { isBrowser } from './utils';\n\ntype ErrorCallback = (error: Error, source?: string) => void;\n\nexport class GlobalErrorHandler {\n private callback: ErrorCallback;\n private installed = false;\n private originalOnError: OnErrorEventHandler | null = null;\n private originalOnUnhandledRejection: ((ev: PromiseRejectionEvent) => void) | null = null;\n\n constructor(callback: ErrorCallback) {\n this.callback = callback;\n }\n\n install(): void {\n if (this.installed) return;\n this.installed = true;\n\n if (isBrowser()) {\n this.installBrowser();\n } else {\n this.installNode();\n }\n }\n\n uninstall(): void {\n if (!this.installed) return;\n this.installed = false;\n\n if (isBrowser()) {\n this.uninstallBrowser();\n } else {\n this.uninstallNode();\n }\n }\n\n private installBrowser(): void {\n this.originalOnError = window.onerror;\n window.onerror = (message, source, lineno, colno, error) => {\n if (error) {\n this.callback(error, source ?? undefined);\n } else if (typeof message === 'string') {\n this.callback(new Error(message), source ?? undefined);\n }\n this.originalOnError?.call(window, message, source, lineno, colno, error);\n };\n\n this.originalOnUnhandledRejection = window.onunhandledrejection as typeof this.originalOnUnhandledRejection;\n window.onunhandledrejection = (event: PromiseRejectionEvent) => {\n const error =\n event.reason instanceof Error\n ? event.reason\n : new Error(String(event.reason));\n this.callback(error, 'unhandledrejection');\n (this.originalOnUnhandledRejection as ((ev: PromiseRejectionEvent) => void) | null)?.call(window, event);\n };\n }\n\n private uninstallBrowser(): void {\n window.onerror = this.originalOnError;\n window.onunhandledrejection = this.originalOnUnhandledRejection as typeof window.onunhandledrejection;\n }\n\n private installNode(): void {\n if (typeof process === 'undefined') return;\n\n process.on('uncaughtException', this.handleNodeError);\n process.on('unhandledRejection', this.handleNodeRejection);\n }\n\n private uninstallNode(): void {\n if (typeof process === 'undefined') return;\n\n process.removeListener('uncaughtException', this.handleNodeError);\n process.removeListener('unhandledRejection', this.handleNodeRejection);\n }\n\n private handleNodeError = (error: Error): void => {\n this.callback(error, 'uncaughtException');\n };\n\n private handleNodeRejection = (reason: unknown): void => {\n const error = reason instanceof Error ? reason : new Error(String(reason));\n this.callback(error, 'unhandledRejection');\n };\n}\n","import type { EventContext } from './types';\nimport { isBrowser } from './utils';\n\n/**\n * Parses a user agent string into browser, OS, and device info.\n * Lightweight — covers major browsers/platforms without a full UA parser dependency.\n */\nfunction parseUserAgent(ua: string): {\n browser: { name: string; version?: string };\n os: { name: string; version?: string };\n device: { type: string };\n} {\n const browser = { name: 'Unknown', version: undefined as string | undefined };\n const os = { name: 'Unknown', version: undefined as string | undefined };\n const device = { type: 'desktop' };\n\n // Mobile detection\n if (/Mobi|Android|iPhone|iPad|iPod/i.test(ua)) {\n device.type = /iPad|Tablet/i.test(ua) ? 'tablet' : 'mobile';\n }\n\n // Browser detection\n if (/Edg\\//i.test(ua)) {\n browser.name = 'Edge';\n browser.version = ua.match(/Edg\\/([\\d.]+)/)?.[1];\n } else if (/OPR\\//i.test(ua) || /Opera/i.test(ua)) {\n browser.name = 'Opera';\n browser.version = ua.match(/(?:OPR|Opera)\\/([\\d.]+)/)?.[1];\n } else if (/Chrome\\//i.test(ua) && !/Chromium/i.test(ua)) {\n browser.name = 'Chrome';\n browser.version = ua.match(/Chrome\\/([\\d.]+)/)?.[1];\n } else if (/Safari\\//i.test(ua) && !/Chrome/i.test(ua)) {\n browser.name = 'Safari';\n browser.version = ua.match(/Version\\/([\\d.]+)/)?.[1];\n } else if (/Firefox\\//i.test(ua)) {\n browser.name = 'Firefox';\n browser.version = ua.match(/Firefox\\/([\\d.]+)/)?.[1];\n }\n\n // OS detection\n if (/Windows NT/i.test(ua)) {\n os.name = 'Windows';\n const ntVersion = ua.match(/Windows NT ([\\d.]+)/)?.[1];\n const versionMap: Record<string, string> = {\n '10.0': '10+',\n '6.3': '8.1',\n '6.2': '8',\n '6.1': '7',\n };\n os.version = ntVersion ? (versionMap[ntVersion] ?? ntVersion) : undefined;\n } else if (/Mac OS X/i.test(ua)) {\n os.name = 'macOS';\n os.version = ua.match(/Mac OS X ([\\d_.]+)/)?.[1]?.replace(/_/g, '.');\n } else if (/Android/i.test(ua)) {\n os.name = 'Android';\n os.version = ua.match(/Android ([\\d.]+)/)?.[1];\n } else if (/iPhone OS|iPad/i.test(ua)) {\n os.name = 'iOS';\n os.version = ua.match(/OS ([\\d_]+)/)?.[1]?.replace(/_/g, '.');\n } else if (/Linux/i.test(ua)) {\n os.name = 'Linux';\n }\n\n return { browser, os, device };\n}\n\nexport function gatherContext(): EventContext {\n if (!isBrowser()) {\n return {};\n }\n\n const ua = navigator.userAgent;\n const { browser, os, device } = parseUserAgent(ua);\n\n return {\n userAgent: ua,\n locale: navigator.language,\n page: {\n url: window.location.href,\n referrer: document.referrer || undefined,\n title: document.title || undefined,\n path: window.location.pathname,\n },\n browser,\n os,\n device,\n };\n}\n\nexport function mergeContext(\n auto: EventContext,\n user?: Partial<EventContext>,\n): EventContext {\n if (!user) return auto;\n\n return {\n ...auto,\n ...user,\n page: { ...auto.page, ...user.page },\n browser: { ...auto.browser, ...user.browser },\n os: { ...auto.os, ...user.os },\n device: { ...auto.device, ...user.device },\n };\n}\n","const PREFIX = 'ba_';\n\nexport interface Storage {\n get(key: string): string | null;\n set(key: string, value: string): void;\n remove(key: string): void;\n}\n\nclass LocalStorage implements Storage {\n get(key: string): string | null {\n try {\n return localStorage.getItem(PREFIX + key);\n } catch {\n return null;\n }\n }\n\n set(key: string, value: string): void {\n try {\n localStorage.setItem(PREFIX + key, value);\n } catch {\n // localStorage unavailable or quota exceeded\n }\n }\n\n remove(key: string): void {\n try {\n localStorage.removeItem(PREFIX + key);\n } catch {\n // noop\n }\n }\n}\n\nclass MemoryStorage implements Storage {\n private store = new Map<string, string>();\n\n get(key: string): string | null {\n return this.store.get(PREFIX + key) ?? null;\n }\n\n set(key: string, value: string): void {\n this.store.set(PREFIX + key, value);\n }\n\n remove(key: string): void {\n this.store.delete(PREFIX + key);\n }\n}\n\nexport function createStorage(): Storage {\n try {\n if (typeof localStorage !== 'undefined') {\n localStorage.setItem('__ba_test__', '1');\n localStorage.removeItem('__ba_test__');\n return new LocalStorage();\n }\n } catch {\n // localStorage not available\n }\n return new MemoryStorage();\n}\n","import type {\n BoringAnalyticsConfig,\n TrackOptions,\n IdentifyOptions,\n PageOptions,\n ScreenOptions,\n GroupOptions,\n CaptureErrorOptions,\n IngestEventPayload,\n IngestErrorPayload,\n EventContext,\n} from './types';\nimport { Transport } from './transport';\nimport { EventQueue } from './queue';\nimport { SessionManager } from './session';\nimport { GlobalErrorHandler } from './error-handler';\nimport { gatherContext, mergeContext } from './context';\nimport { createStorage } from './storage';\nimport { createDebugLogger, isBrowser, now } from './utils';\n\nconst DEFAULT_ENDPOINT = 'https://api.boringanalytics.io';\nconst DEFAULT_FLUSH_AT = 20;\nconst DEFAULT_FLUSH_INTERVAL = 5000;\nconst DEFAULT_MAX_RETRIES = 3;\n\nexport class BoringAnalytics {\n private queue: EventQueue;\n private session: SessionManager;\n private errorHandler: GlobalErrorHandler | null = null;\n private debug: ReturnType<typeof createDebugLogger>;\n private config: Required<\n Pick<BoringAnalyticsConfig, 'defaultProperties'>\n > & BoringAnalyticsConfig;\n private pageViewUnsubscribe: (() => void) | null = null;\n\n constructor(config: BoringAnalyticsConfig) {\n if (!config.apiKey) {\n throw new Error('BoringAnalytics: apiKey is required');\n }\n\n this.config = {\n ...config,\n defaultProperties: config.defaultProperties ?? {},\n };\n\n this.debug = createDebugLogger(config.debug ?? false);\n this.debug.log('Initializing with endpoint:', config.endpoint ?? DEFAULT_ENDPOINT);\n\n const storage = createStorage();\n this.session = new SessionManager(storage);\n\n const transport = new Transport({\n endpoint: config.endpoint ?? DEFAULT_ENDPOINT,\n apiKey: config.apiKey,\n maxRetries: config.maxRetries ?? DEFAULT_MAX_RETRIES,\n onError: config.onError,\n });\n\n this.queue = new EventQueue(transport, {\n flushAt: config.flushAt ?? DEFAULT_FLUSH_AT,\n flushInterval: config.flushInterval ?? DEFAULT_FLUSH_INTERVAL,\n debug: this.debug,\n });\n\n const autoCapture = config.autoCapture ?? {};\n\n if (autoCapture.errors !== false) {\n this.errorHandler = new GlobalErrorHandler((error, source) => {\n this.captureError(error, {\n handled: false,\n metadata: { source },\n });\n });\n this.errorHandler.install();\n }\n\n if (autoCapture.pageViews && isBrowser()) {\n this.installPageViewTracking();\n }\n }\n\n // --- Public API ---\n\n /**\n * Track a named event.\n *\n * @example\n * analytics.track('button_clicked', { properties: { buttonId: 'signup' } });\n */\n track(name: string, options: TrackOptions = {}): void {\n this.enqueueEvent('TRACK', name, options.properties, options.timestamp, options.context);\n }\n\n /**\n * Identify a user with traits.\n * Sets the userId for all subsequent calls.\n *\n * @example\n * analytics.identify('user-123', { traits: { email: 'user@example.com' } });\n */\n identify(userId: string, options: IdentifyOptions = {}): void {\n this.session.setUserId(userId);\n this.enqueueEvent('IDENTIFY', 'identify', options.traits, options.timestamp, options.context);\n }\n\n /**\n * Track a page view (typically browser).\n *\n * @example\n * analytics.page('Home');\n * analytics.page('Product', { properties: { productId: '123' } });\n */\n page(name?: string, options: PageOptions = {}): void {\n const pageName = name ?? (isBrowser() ? document.title : 'Page View');\n this.enqueueEvent('PAGE', pageName, options.properties, options.timestamp, options.context);\n }\n\n /**\n * Track a screen view (typically mobile).\n */\n screen(name: string, options: ScreenOptions = {}): void {\n this.enqueueEvent('SCREEN', name, options.properties, options.timestamp, options.context);\n }\n\n /**\n * Associate a user with a group.\n */\n group(groupId: string, options: GroupOptions = {}): void {\n this.enqueueEvent('GROUP', groupId, options.traits, options.timestamp, options.context);\n }\n\n /**\n * Create an alias between two user identities.\n */\n alias(userId: string, previousId: string): void {\n this.enqueueEvent('ALIAS', 'alias', { userId, previousId });\n }\n\n /**\n * Capture an error for error monitoring.\n *\n * @example\n * try { riskyOp(); }\n * catch (err) { analytics.captureError(err, { tags: { env: 'prod' } }); }\n */\n captureError(\n error: Error | string,\n options: CaptureErrorOptions = {},\n ): void {\n const err = typeof error === 'string' ? new Error(error) : error;\n const autoContext = gatherContext();\n\n const payload: IngestErrorPayload = {\n type: err.name || 'Error',\n message: err.message,\n stackTrace: err.stack,\n level: options.level ?? 'ERROR',\n fingerprint: options.fingerprint,\n handled: options.handled ?? true,\n metadata: options.metadata,\n tags: options.tags,\n timestamp: (options.timestamp ?? new Date()).toISOString(),\n userId: this.session.getUserId() ?? undefined,\n sessionId: this.session.getSessionId(),\n context: {\n userAgent: autoContext.userAgent,\n browser: autoContext.browser?.name,\n os: autoContext.os?.name,\n device: autoContext.device?.type,\n url: autoContext.page?.url,\n release: options.release,\n },\n };\n\n this.queue.add({ kind: 'error', payload });\n }\n\n /**\n * Flush all queued events and errors immediately.\n */\n async flush(): Promise<void> {\n await this.queue.flush();\n }\n\n /**\n * Reset the current user. Clears userId, generates new anonymousId and sessionId.\n * Call this on logout.\n */\n reset(): void {\n this.session.reset();\n this.debug.log('User reset');\n }\n\n /**\n * Gracefully shut down: flush remaining events, remove global handlers.\n */\n async shutdown(): Promise<void> {\n this.debug.log('Shutting down');\n this.errorHandler?.uninstall();\n this.pageViewUnsubscribe?.();\n await this.queue.shutdown();\n }\n\n // --- Internal ---\n\n private enqueueEvent(\n type: IngestEventPayload['type'],\n name: string,\n properties?: Record<string, unknown>,\n timestamp?: Date,\n userContext?: Partial<EventContext>,\n ): void {\n const autoContext = gatherContext();\n const context = mergeContext(autoContext, userContext);\n\n const payload: IngestEventPayload = {\n type,\n name,\n properties: { ...this.config.defaultProperties, ...properties },\n timestamp: (timestamp ?? new Date()).toISOString(),\n userId: this.session.getUserId() ?? undefined,\n sessionId: this.session.getSessionId(),\n anonymousId: this.session.getAnonymousId(),\n context,\n };\n\n this.queue.add({ kind: 'event', payload });\n }\n\n private installPageViewTracking(): void {\n if (!isBrowser()) return;\n\n let lastUrl = window.location.href;\n\n const checkUrl = () => {\n const currentUrl = window.location.href;\n if (currentUrl !== lastUrl) {\n lastUrl = currentUrl;\n this.page();\n }\n };\n\n // Patch pushState/replaceState for SPA navigation\n const origPushState = history.pushState.bind(history);\n const origReplaceState = history.replaceState.bind(history);\n\n history.pushState = (...args: Parameters<typeof history.pushState>) => {\n origPushState(...args);\n checkUrl();\n };\n\n history.replaceState = (...args: Parameters<typeof history.replaceState>) => {\n origReplaceState(...args);\n checkUrl();\n };\n\n window.addEventListener('popstate', checkUrl);\n\n this.pageViewUnsubscribe = () => {\n history.pushState = origPushState;\n history.replaceState = origReplaceState;\n window.removeEventListener('popstate', checkUrl);\n };\n\n // Track initial page view\n this.page();\n }\n}\n"]}
1
+ {"version":3,"sources":["../src/transport.ts","../src/queue.ts","../src/utils.ts","../src/session.ts","../src/error-handler.ts","../src/context.ts","../src/storage.ts","../src/auto-capture/web-vitals.ts","../src/auto-capture/scroll-depth.ts","../src/auto-capture/outbound-clicks.ts","../src/client.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["import type { IngestEventPayload, IngestErrorPayload } from './types';\n\nexport interface TransportConfig {\n endpoint: string;\n apiKey: string;\n maxRetries: number;\n onError?: (error: Error) => void;\n}\n\nexport class Transport {\n private config: TransportConfig;\n\n constructor(config: TransportConfig) {\n this.config = config;\n }\n\n async sendEvents(events: IngestEventPayload[]): Promise<void> {\n await this.post('/ingest/events', { events });\n }\n\n async sendErrors(errors: IngestErrorPayload[]): Promise<void> {\n await this.post('/ingest/errors', { errors });\n }\n\n private async post(path: string, body: unknown): Promise<void> {\n const url = this.config.endpoint.replace(/\\/+$/, '') + path;\n let lastError: Error | undefined;\n\n for (let attempt = 0; attempt <= this.config.maxRetries; attempt++) {\n try {\n const response = await fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'x-api-key': this.config.apiKey,\n },\n body: JSON.stringify(body),\n keepalive: true,\n });\n\n if (response.ok) return;\n\n if (response.status >= 400 && response.status < 500 && response.status !== 429) {\n const text = await response.text().catch(() => '');\n throw new Error(`HTTP ${response.status}: ${text}`);\n }\n\n lastError = new Error(`HTTP ${response.status}`);\n } catch (err) {\n lastError = err instanceof Error ? err : new Error(String(err));\n if (err instanceof Error && err.message.startsWith('HTTP 4')) {\n break;\n }\n }\n\n if (attempt < this.config.maxRetries) {\n await this.backoff(attempt);\n }\n }\n\n if (lastError) {\n this.config.onError?.(lastError);\n }\n }\n\n private backoff(attempt: number): Promise<void> {\n const delay = Math.min(1000 * 2 ** attempt, 30000);\n const jitter = delay * (0.5 + Math.random() * 0.5);\n return new Promise((resolve) => setTimeout(resolve, jitter));\n }\n}\n","import type { QueueItem, IngestEventPayload, IngestErrorPayload } from './types';\nimport type { Transport } from './transport';\n\nexport interface QueueConfig {\n flushAt: number;\n flushInterval: number;\n debug: ReturnType<typeof import('./utils').createDebugLogger>;\n}\n\nexport class EventQueue {\n private items: QueueItem[] = [];\n private timer: ReturnType<typeof setInterval> | null = null;\n private transport: Transport;\n private config: QueueConfig;\n private flushing = false;\n\n constructor(transport: Transport, config: QueueConfig) {\n this.transport = transport;\n this.config = config;\n this.startTimer();\n }\n\n add(item: QueueItem): void {\n this.items.push(item);\n this.config.debug.log(`Queued ${item.kind}:`, item.kind === 'event' ? item.payload.name : item.payload.message);\n\n if (this.items.length >= this.config.flushAt) {\n void this.flush();\n }\n }\n\n async flush(): Promise<void> {\n if (this.flushing || this.items.length === 0) return;\n\n this.flushing = true;\n const batch = this.items.splice(0);\n\n try {\n const events: IngestEventPayload[] = [];\n const errors: IngestErrorPayload[] = [];\n\n for (const item of batch) {\n if (item.kind === 'event') events.push(item.payload);\n else errors.push(item.payload);\n }\n\n const promises: Promise<void>[] = [];\n if (events.length > 0) {\n this.config.debug.log(`Flushing ${events.length} events`);\n promises.push(this.transport.sendEvents(events));\n }\n if (errors.length > 0) {\n this.config.debug.log(`Flushing ${errors.length} errors`);\n promises.push(this.transport.sendErrors(errors));\n }\n\n await Promise.all(promises);\n } catch {\n this.items.unshift(...batch);\n } finally {\n this.flushing = false;\n }\n }\n\n private startTimer(): void {\n if (this.config.flushInterval > 0) {\n this.timer = setInterval(() => {\n void this.flush();\n }, this.config.flushInterval);\n\n // Allow Node.js to exit without waiting for the timer\n if (this.timer && typeof (this.timer as NodeJS.Timeout).unref === 'function') {\n (this.timer as NodeJS.Timeout).unref();\n }\n }\n }\n\n async shutdown(): Promise<void> {\n if (this.timer) {\n clearInterval(this.timer);\n this.timer = null;\n }\n await this.flush();\n }\n\n get size(): number {\n return this.items.length;\n }\n}\n","export function generateId(): string {\n if (typeof crypto !== 'undefined' && crypto.randomUUID) {\n return crypto.randomUUID();\n }\n return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {\n const r = (Math.random() * 16) | 0;\n const v = c === 'x' ? r : (r & 0x3) | 0x8;\n return v.toString(16);\n });\n}\n\nexport function isBrowser(): boolean {\n return typeof window !== 'undefined' && typeof document !== 'undefined';\n}\n\nexport function now(): string {\n return new Date().toISOString();\n}\n\nexport function createDebugLogger(enabled: boolean) {\n return {\n log: (...args: unknown[]) => {\n if (enabled) console.log('[BoringAnalytics]', ...args);\n },\n warn: (...args: unknown[]) => {\n if (enabled) console.warn('[BoringAnalytics]', ...args);\n },\n error: (...args: unknown[]) => {\n if (enabled) console.error('[BoringAnalytics]', ...args);\n },\n };\n}\n","import type { Storage } from './storage';\nimport { generateId } from './utils';\n\nconst ANON_ID_KEY = 'anonymous_id';\nconst SESSION_ID_KEY = 'session_id';\nconst SESSION_EXPIRY_KEY = 'session_expiry';\n\n/** Session timeout: 30 minutes of inactivity */\nconst SESSION_TIMEOUT_MS = 30 * 60 * 1000;\n\nexport class SessionManager {\n private userId: string | null = null;\n private anonymousId: string;\n private sessionId: string;\n private storage: Storage;\n\n constructor(storage: Storage) {\n this.storage = storage;\n this.anonymousId = this.storage.get(ANON_ID_KEY) ?? this.createAnonymousId();\n this.sessionId = this.resolveSession();\n }\n\n private createAnonymousId(): string {\n const id = generateId();\n this.storage.set(ANON_ID_KEY, id);\n return id;\n }\n\n private resolveSession(): string {\n const existingSession = this.storage.get(SESSION_ID_KEY);\n const expiryStr = this.storage.get(SESSION_EXPIRY_KEY);\n const expiry = expiryStr ? parseInt(expiryStr, 10) : 0;\n\n if (existingSession && Date.now() < expiry) {\n this.touchSession();\n return existingSession;\n }\n\n return this.startNewSession();\n }\n\n private startNewSession(): string {\n const id = generateId();\n this.sessionId = id;\n this.storage.set(SESSION_ID_KEY, id);\n this.touchSession();\n return id;\n }\n\n private touchSession(): void {\n this.storage.set(\n SESSION_EXPIRY_KEY,\n String(Date.now() + SESSION_TIMEOUT_MS),\n );\n }\n\n setUserId(id: string): void {\n this.userId = id;\n }\n\n getUserId(): string | null {\n return this.userId;\n }\n\n getAnonymousId(): string {\n return this.anonymousId;\n }\n\n getSessionId(): string {\n this.sessionId = this.resolveSession();\n return this.sessionId;\n }\n\n reset(): void {\n this.userId = null;\n this.anonymousId = this.createAnonymousId();\n this.sessionId = this.startNewSession();\n }\n}\n","import { isBrowser } from './utils';\n\ntype ErrorCallback = (error: Error, source?: string) => void;\n\nexport class GlobalErrorHandler {\n private callback: ErrorCallback;\n private installed = false;\n private originalOnError: OnErrorEventHandler | null = null;\n private originalOnUnhandledRejection: ((ev: PromiseRejectionEvent) => void) | null = null;\n\n constructor(callback: ErrorCallback) {\n this.callback = callback;\n }\n\n install(): void {\n if (this.installed) return;\n this.installed = true;\n\n if (isBrowser()) {\n this.installBrowser();\n } else {\n this.installNode();\n }\n }\n\n uninstall(): void {\n if (!this.installed) return;\n this.installed = false;\n\n if (isBrowser()) {\n this.uninstallBrowser();\n } else {\n this.uninstallNode();\n }\n }\n\n private installBrowser(): void {\n this.originalOnError = window.onerror;\n window.onerror = (message, source, lineno, colno, error) => {\n if (error) {\n this.callback(error, source ?? undefined);\n } else if (typeof message === 'string') {\n this.callback(new Error(message), source ?? undefined);\n }\n this.originalOnError?.call(window, message, source, lineno, colno, error);\n };\n\n this.originalOnUnhandledRejection = window.onunhandledrejection as typeof this.originalOnUnhandledRejection;\n window.onunhandledrejection = (event: PromiseRejectionEvent) => {\n const error =\n event.reason instanceof Error\n ? event.reason\n : new Error(String(event.reason));\n this.callback(error, 'unhandledrejection');\n (this.originalOnUnhandledRejection as ((ev: PromiseRejectionEvent) => void) | null)?.call(window, event);\n };\n }\n\n private uninstallBrowser(): void {\n window.onerror = this.originalOnError;\n window.onunhandledrejection = this.originalOnUnhandledRejection as typeof window.onunhandledrejection;\n }\n\n private installNode(): void {\n if (typeof process === 'undefined') return;\n\n process.on('uncaughtException', this.handleNodeError);\n process.on('unhandledRejection', this.handleNodeRejection);\n }\n\n private uninstallNode(): void {\n if (typeof process === 'undefined') return;\n\n process.removeListener('uncaughtException', this.handleNodeError);\n process.removeListener('unhandledRejection', this.handleNodeRejection);\n }\n\n private handleNodeError = (error: Error): void => {\n this.callback(error, 'uncaughtException');\n };\n\n private handleNodeRejection = (reason: unknown): void => {\n const error = reason instanceof Error ? reason : new Error(String(reason));\n this.callback(error, 'unhandledRejection');\n };\n}\n","import type { EventContext } from './types';\nimport { isBrowser } from './utils';\n\n/**\n * Parses a user agent string into browser, OS, and device info.\n * Lightweight — covers major browsers/platforms without a full UA parser dependency.\n */\nfunction parseUserAgent(ua: string): {\n browser: { name: string; version?: string };\n os: { name: string; version?: string };\n device: { type: string };\n} {\n const browser = { name: 'Unknown', version: undefined as string | undefined };\n const os = { name: 'Unknown', version: undefined as string | undefined };\n const device = { type: 'desktop' };\n\n // Mobile detection\n if (/Mobi|Android|iPhone|iPad|iPod/i.test(ua)) {\n device.type = /iPad|Tablet/i.test(ua) ? 'tablet' : 'mobile';\n }\n\n // Browser detection\n if (/Edg\\//i.test(ua)) {\n browser.name = 'Edge';\n browser.version = ua.match(/Edg\\/([\\d.]+)/)?.[1];\n } else if (/OPR\\//i.test(ua) || /Opera/i.test(ua)) {\n browser.name = 'Opera';\n browser.version = ua.match(/(?:OPR|Opera)\\/([\\d.]+)/)?.[1];\n } else if (/Chrome\\//i.test(ua) && !/Chromium/i.test(ua)) {\n browser.name = 'Chrome';\n browser.version = ua.match(/Chrome\\/([\\d.]+)/)?.[1];\n } else if (/Safari\\//i.test(ua) && !/Chrome/i.test(ua)) {\n browser.name = 'Safari';\n browser.version = ua.match(/Version\\/([\\d.]+)/)?.[1];\n } else if (/Firefox\\//i.test(ua)) {\n browser.name = 'Firefox';\n browser.version = ua.match(/Firefox\\/([\\d.]+)/)?.[1];\n }\n\n // OS detection\n if (/Windows NT/i.test(ua)) {\n os.name = 'Windows';\n const ntVersion = ua.match(/Windows NT ([\\d.]+)/)?.[1];\n const versionMap: Record<string, string> = {\n '10.0': '10+',\n '6.3': '8.1',\n '6.2': '8',\n '6.1': '7',\n };\n os.version = ntVersion ? (versionMap[ntVersion] ?? ntVersion) : undefined;\n } else if (/Mac OS X/i.test(ua)) {\n os.name = 'macOS';\n os.version = ua.match(/Mac OS X ([\\d_.]+)/)?.[1]?.replace(/_/g, '.');\n } else if (/Android/i.test(ua)) {\n os.name = 'Android';\n os.version = ua.match(/Android ([\\d.]+)/)?.[1];\n } else if (/iPhone OS|iPad/i.test(ua)) {\n os.name = 'iOS';\n os.version = ua.match(/OS ([\\d_]+)/)?.[1]?.replace(/_/g, '.');\n } else if (/Linux/i.test(ua)) {\n os.name = 'Linux';\n }\n\n return { browser, os, device };\n}\n\nexport function gatherContext(): EventContext {\n if (!isBrowser()) {\n return {};\n }\n\n const ua = navigator.userAgent;\n const { browser, os, device } = parseUserAgent(ua);\n\n return {\n userAgent: ua,\n locale: navigator.language,\n page: {\n url: window.location.href,\n referrer: document.referrer || undefined,\n title: document.title || undefined,\n path: window.location.pathname,\n },\n browser,\n os,\n device,\n };\n}\n\nexport function mergeContext(\n auto: EventContext,\n user?: Partial<EventContext>,\n): EventContext {\n if (!user) return auto;\n\n return {\n ...auto,\n ...user,\n page: { ...auto.page, ...user.page },\n browser: { ...auto.browser, ...user.browser },\n os: { ...auto.os, ...user.os },\n device: { ...auto.device, ...user.device },\n };\n}\n","const PREFIX = 'ba_';\n\nexport interface Storage {\n get(key: string): string | null;\n set(key: string, value: string): void;\n remove(key: string): void;\n}\n\nclass LocalStorage implements Storage {\n get(key: string): string | null {\n try {\n return localStorage.getItem(PREFIX + key);\n } catch {\n return null;\n }\n }\n\n set(key: string, value: string): void {\n try {\n localStorage.setItem(PREFIX + key, value);\n } catch {\n // localStorage unavailable or quota exceeded\n }\n }\n\n remove(key: string): void {\n try {\n localStorage.removeItem(PREFIX + key);\n } catch {\n // noop\n }\n }\n}\n\nclass MemoryStorage implements Storage {\n private store = new Map<string, string>();\n\n get(key: string): string | null {\n return this.store.get(PREFIX + key) ?? null;\n }\n\n set(key: string, value: string): void {\n this.store.set(PREFIX + key, value);\n }\n\n remove(key: string): void {\n this.store.delete(PREFIX + key);\n }\n}\n\nexport function createStorage(): Storage {\n try {\n if (typeof localStorage !== 'undefined') {\n localStorage.setItem('__ba_test__', '1');\n localStorage.removeItem('__ba_test__');\n return new LocalStorage();\n }\n } catch {\n // localStorage not available\n }\n return new MemoryStorage();\n}\n","import { onCLS, onFID, onINP, onLCP, onTTFB } from 'web-vitals';\nimport type { Metric } from 'web-vitals';\n\nexport type WebVitalsCallback = (metric: { name: string; value: number; rating?: string; delta?: number; id?: string }) => void;\n\nexport function installWebVitals(report: WebVitalsCallback): () => void {\n const reportMetric = (metric: Metric) => {\n report({\n name: metric.name,\n value: metric.value,\n rating: metric.rating,\n delta: metric.delta,\n id: metric.id,\n });\n };\n\n onCLS(reportMetric);\n onFID(reportMetric);\n onINP(reportMetric);\n onLCP(reportMetric);\n onTTFB(reportMetric);\n\n return () => {\n // web-vitals doesn't expose uninstall; handlers fire once per metric\n };\n}\n","export type ScrollDepthCallback = (depth: number) => void;\n\nconst DEPTHS = [25, 50, 75, 100];\n\nexport function installScrollDepth(report: ScrollDepthCallback): () => void {\n const reported = new Set<number>();\n\n const onScroll = () => {\n if (typeof document === 'undefined' || !document.documentElement) return;\n\n const scrollHeight = document.documentElement.scrollHeight - window.innerHeight;\n if (scrollHeight <= 0) return;\n\n const scrollPercent = Math.round((window.scrollY / scrollHeight) * 100);\n\n for (const d of DEPTHS) {\n if (scrollPercent >= d && !reported.has(d)) {\n reported.add(d);\n report(d);\n }\n }\n };\n\n window.addEventListener('scroll', onScroll, { passive: true });\n // Fire once in case already scrolled\n onScroll();\n\n return () => {\n window.removeEventListener('scroll', onScroll);\n };\n}\n","export type OutboundClickCallback = (payload: { href: string; domain?: string; type: 'external' | 'download' }) => void;\n\nfunction getLinkTarget(e: MouseEvent): HTMLAnchorElement | null {\n let el: HTMLElement | null = e.target as HTMLElement;\n while (el && el !== document.body) {\n if (el.tagName === 'A' && (el as HTMLAnchorElement).href) {\n return el as HTMLAnchorElement;\n }\n el = el.parentElement;\n }\n return null;\n}\n\nfunction isDownload(anchor: HTMLAnchorElement): boolean {\n const attr = anchor.getAttribute('download');\n const href = (anchor.getAttribute('href') || '').toLowerCase();\n return attr !== null || /\\.(pdf|zip|docx?|xlsx?|csv|mp3|mp4|apk)(\\?|$)/i.test(href);\n}\n\nfunction isExternal(anchor: HTMLAnchorElement): boolean {\n try {\n return anchor.hostname !== window.location.hostname && anchor.protocol.startsWith('http');\n } catch {\n return false;\n }\n}\n\nexport function installOutboundClickTracking(report: OutboundClickCallback): () => void {\n const handler = (e: MouseEvent) => {\n const anchor = getLinkTarget(e);\n if (!anchor) return;\n\n const href = anchor.href;\n if (isDownload(anchor)) {\n report({ href, type: 'download' });\n return;\n }\n if (isExternal(anchor)) {\n report({ href, domain: anchor.hostname, type: 'external' });\n }\n };\n\n document.addEventListener('click', handler, true);\n\n return () => {\n document.removeEventListener('click', handler, true);\n };\n}\n","import type {\n BoringAnalyticsConfig,\n TrackOptions,\n IdentifyOptions,\n PageOptions,\n ScreenOptions,\n GroupOptions,\n CaptureErrorOptions,\n TrackRevenueOptions,\n TrackExposureOptions,\n IngestEventPayload,\n IngestErrorPayload,\n EventContext,\n} from './types';\nimport { Transport } from './transport';\nimport { EventQueue } from './queue';\nimport { SessionManager } from './session';\nimport { GlobalErrorHandler } from './error-handler';\nimport { gatherContext, mergeContext } from './context';\nimport { createStorage } from './storage';\nimport { createDebugLogger, isBrowser } from './utils';\nimport { installWebVitals } from './auto-capture/web-vitals';\nimport { installScrollDepth } from './auto-capture/scroll-depth';\nimport { installOutboundClickTracking } from './auto-capture/outbound-clicks';\n\nconst DEFAULT_ENDPOINT = 'https://api.boring.yraylabs.fun';\nconst DEFAULT_FLUSH_AT = 20;\nconst DEFAULT_FLUSH_INTERVAL = 5000;\nconst DEFAULT_MAX_RETRIES = 3;\n\nexport class BoringAnalytics {\n private queue: EventQueue;\n private session: SessionManager;\n private errorHandler: GlobalErrorHandler | null = null;\n private debug: ReturnType<typeof createDebugLogger>;\n private config: Required<\n Pick<BoringAnalyticsConfig, 'defaultProperties'>\n > & BoringAnalyticsConfig;\n private pageViewUnsubscribe: (() => void) | null = null;\n private webVitalsUnsubscribe: (() => void) | null = null;\n private scrollDepthUnsubscribe: (() => void) | null = null;\n private outboundClicksUnsubscribe: (() => void) | null = null;\n\n constructor(config: BoringAnalyticsConfig) {\n if (!config.apiKey) {\n throw new Error('BoringAnalytics: apiKey is required');\n }\n\n this.config = {\n ...config,\n defaultProperties: config.defaultProperties ?? {},\n };\n\n this.debug = createDebugLogger(config.debug ?? false);\n this.debug.log('Initializing with endpoint:', config.endpoint ?? DEFAULT_ENDPOINT);\n\n const storage = createStorage();\n this.session = new SessionManager(storage);\n\n const transport = new Transport({\n endpoint: config.endpoint ?? DEFAULT_ENDPOINT,\n apiKey: config.apiKey,\n maxRetries: config.maxRetries ?? DEFAULT_MAX_RETRIES,\n onError: config.onError,\n });\n\n this.queue = new EventQueue(transport, {\n flushAt: config.flushAt ?? DEFAULT_FLUSH_AT,\n flushInterval: config.flushInterval ?? DEFAULT_FLUSH_INTERVAL,\n debug: this.debug,\n });\n\n const autoCapture = config.autoCapture ?? {};\n\n if (autoCapture.errors !== false) {\n this.errorHandler = new GlobalErrorHandler((error, source) => {\n this.captureError(error, {\n handled: false,\n metadata: { source },\n });\n });\n this.errorHandler.install();\n }\n\n if (autoCapture.pageViews && isBrowser()) {\n this.installPageViewTracking();\n }\n\n if (autoCapture.webVitals && isBrowser()) {\n this.webVitalsUnsubscribe = installWebVitals((metric) => {\n this.track('web_vitals', {\n properties: {\n metric: metric.name,\n value: metric.value,\n rating: metric.rating,\n delta: metric.delta,\n id: metric.id,\n },\n });\n });\n }\n\n if (autoCapture.scrollDepth && isBrowser()) {\n this.scrollDepthUnsubscribe = installScrollDepth((depth) => {\n this.track('scroll_depth', { properties: { depth } });\n });\n }\n\n if (autoCapture.outboundClicks && isBrowser()) {\n this.outboundClicksUnsubscribe = installOutboundClickTracking((payload) => {\n this.track('outbound_click', {\n properties: {\n href: payload.href,\n domain: payload.domain,\n link_type: payload.type,\n },\n });\n });\n }\n }\n\n // --- Public API ---\n\n /**\n * Track a named event.\n *\n * @example\n * analytics.track('button_clicked', { properties: { buttonId: 'signup' } });\n */\n track(name: string, options: TrackOptions = {}): void {\n this.enqueueEvent('TRACK', name, options.properties, options.timestamp, options.context);\n }\n\n /**\n * Identify a user with traits.\n * Sets the userId for all subsequent calls.\n *\n * @example\n * analytics.identify('user-123', { traits: { email: 'user@example.com' } });\n */\n identify(userId: string, options: IdentifyOptions = {}): void {\n this.session.setUserId(userId);\n this.enqueueEvent('IDENTIFY', 'identify', options.traits, options.timestamp, options.context);\n }\n\n /**\n * Track a page view (typically browser).\n *\n * @example\n * analytics.page('Home');\n * analytics.page('Product', { properties: { productId: '123' } });\n */\n page(name?: string, options: PageOptions = {}): void {\n const pageName = name ?? (isBrowser() ? document.title : 'Page View');\n this.enqueueEvent('PAGE', pageName, options.properties, options.timestamp, options.context);\n }\n\n /**\n * Track a screen view (typically mobile).\n */\n screen(name: string, options: ScreenOptions = {}): void {\n this.enqueueEvent('SCREEN', name, options.properties, options.timestamp, options.context);\n }\n\n /**\n * Associate a user with a group.\n */\n group(groupId: string, options: GroupOptions = {}): void {\n this.enqueueEvent('GROUP', groupId, options.traits, options.timestamp, options.context);\n }\n\n /**\n * Create an alias between two user identities.\n */\n alias(userId: string, previousId: string): void {\n this.enqueueEvent('ALIAS', 'alias', { userId, previousId });\n }\n\n /**\n * Track revenue (e.g. purchase, subscription).\n * Sends a TRACK event with name \"purchase\" and amount/currency in properties.\n *\n * @example\n * analytics.trackRevenue({ amount: 29.99, currency: 'USD', properties: { orderId: 'ord_123' } });\n */\n trackRevenue(options: TrackRevenueOptions): void {\n const { amount, currency = 'USD', properties = {}, timestamp, context } = options;\n this.track('purchase', {\n properties: { amount, currency, ...properties },\n timestamp,\n context,\n });\n }\n\n /**\n * Track feature-flag or A–B test exposure.\n * Sends a TRACK event with name \"feature_exposed\" and flag/variant in properties.\n *\n * @example\n * analytics.trackExposure({ flag: 'pricing_test', variant: 'treatment' });\n */\n trackExposure(options: TrackExposureOptions): void {\n const { flag, variant, properties = {}, timestamp, context } = options;\n this.track('feature_exposed', {\n properties: { flag, variant, ...properties },\n timestamp,\n context,\n });\n }\n\n /**\n * Capture an error for error monitoring.\n *\n * @example\n * try { riskyOp(); }\n * catch (err) { analytics.captureError(err, { tags: { env: 'prod' } }); }\n */\n captureError(\n error: Error | string,\n options: CaptureErrorOptions = {},\n ): void {\n const err = typeof error === 'string' ? new Error(error) : error;\n const autoContext = gatherContext();\n\n const payload: IngestErrorPayload = {\n type: err.name || 'Error',\n message: err.message,\n stackTrace: err.stack,\n level: options.level ?? 'ERROR',\n fingerprint: options.fingerprint,\n handled: options.handled ?? true,\n metadata: options.metadata,\n tags: options.tags,\n timestamp: (options.timestamp ?? new Date()).toISOString(),\n userId: this.session.getUserId() ?? undefined,\n sessionId: this.session.getSessionId(),\n context: {\n userAgent: autoContext.userAgent,\n browser: autoContext.browser?.name,\n os: autoContext.os?.name,\n device: autoContext.device?.type,\n url: autoContext.page?.url,\n release: options.release,\n },\n };\n\n this.queue.add({ kind: 'error', payload });\n }\n\n /**\n * Flush all queued events and errors immediately.\n */\n async flush(): Promise<void> {\n await this.queue.flush();\n }\n\n /**\n * Reset the current user. Clears userId, generates new anonymousId and sessionId.\n * Call this on logout.\n */\n reset(): void {\n this.session.reset();\n this.debug.log('User reset');\n }\n\n /**\n * Gracefully shut down: flush remaining events, remove global handlers.\n */\n async shutdown(): Promise<void> {\n this.debug.log('Shutting down');\n this.errorHandler?.uninstall();\n this.pageViewUnsubscribe?.();\n this.webVitalsUnsubscribe?.();\n this.scrollDepthUnsubscribe?.();\n this.outboundClicksUnsubscribe?.();\n await this.queue.shutdown();\n }\n\n // --- Internal ---\n\n private enqueueEvent(\n type: IngestEventPayload['type'],\n name: string,\n properties?: Record<string, unknown>,\n timestamp?: Date,\n userContext?: Partial<EventContext>,\n ): void {\n const autoContext = gatherContext();\n const context = mergeContext(autoContext, userContext);\n\n const payload: IngestEventPayload = {\n type,\n name,\n properties: { ...this.config.defaultProperties, ...properties },\n timestamp: (timestamp ?? new Date()).toISOString(),\n userId: this.session.getUserId() ?? undefined,\n sessionId: this.session.getSessionId(),\n anonymousId: this.session.getAnonymousId(),\n context,\n };\n\n this.queue.add({ kind: 'event', payload });\n }\n\n private installPageViewTracking(): void {\n if (!isBrowser()) return;\n\n let lastUrl = window.location.href;\n\n const checkUrl = () => {\n const currentUrl = window.location.href;\n if (currentUrl !== lastUrl) {\n lastUrl = currentUrl;\n this.page();\n }\n };\n\n // Patch pushState/replaceState for SPA navigation\n const origPushState = history.pushState.bind(history);\n const origReplaceState = history.replaceState.bind(history);\n\n history.pushState = (...args: Parameters<typeof history.pushState>) => {\n origPushState(...args);\n checkUrl();\n };\n\n history.replaceState = (...args: Parameters<typeof history.replaceState>) => {\n origReplaceState(...args);\n checkUrl();\n };\n\n window.addEventListener('popstate', checkUrl);\n\n this.pageViewUnsubscribe = () => {\n history.pushState = origPushState;\n history.replaceState = origReplaceState;\n window.removeEventListener('popstate', checkUrl);\n };\n\n // Track initial page view\n this.page();\n }\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yraylabs/boring-analytics",
3
- "version": "0.1.1",
3
+ "version": "1.0.1",
4
4
  "description": "Official SDK for Boring Analytics — product analytics and error monitoring",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -41,5 +41,8 @@
41
41
  "@types/node": "^25.3.0",
42
42
  "tsup": "^8.0.0",
43
43
  "typescript": "^5.5.0"
44
+ },
45
+ "dependencies": {
46
+ "web-vitals": "^5.1.0"
44
47
  }
45
48
  }