@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 +48 -1
- package/dist/index.d.mts +45 -1
- package/dist/index.d.ts +45 -1
- package/dist/index.js +151 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +151 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -1
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
|
-
- **
|
|
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.
|
|
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.
|
|
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 ---
|
package/dist/index.mjs.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.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
|
|
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
|
}
|