@stacksee/analytics 0.9.8 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapters/client/browser-analytics.d.ts +9 -1
- package/dist/adapters/server/server-analytics.d.ts +9 -1
- package/dist/client.js +145 -100
- package/dist/core/events/types.d.ts +50 -1
- package/dist/providers/client.js +7 -5
- package/dist/providers/server.d.ts +1 -1
- package/dist/providers/server.js +50 -21
- package/dist/server.js +143 -101
- package/package.json +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { AnalyticsConfig, EventContext } from '../../core/events/types.js';
|
|
2
2
|
type DefaultEventMap = Record<string, Record<string, unknown>>;
|
|
3
3
|
export declare class BrowserAnalytics<TEventMap extends DefaultEventMap = DefaultEventMap, TUserTraits extends Record<string, unknown> = Record<string, unknown>> {
|
|
4
|
-
private
|
|
4
|
+
private providerConfigs;
|
|
5
5
|
private context;
|
|
6
6
|
private userId?;
|
|
7
7
|
private sessionId?;
|
|
@@ -39,6 +39,14 @@ export declare class BrowserAnalytics<TEventMap extends DefaultEventMap = Defaul
|
|
|
39
39
|
* ```
|
|
40
40
|
*/
|
|
41
41
|
constructor(config: AnalyticsConfig);
|
|
42
|
+
/**
|
|
43
|
+
* Normalizes provider configurations into a consistent internal format
|
|
44
|
+
*/
|
|
45
|
+
private normalizeProviders;
|
|
46
|
+
/**
|
|
47
|
+
* Checks if a method should be called on a provider based on routing configuration
|
|
48
|
+
*/
|
|
49
|
+
private shouldCallMethod;
|
|
42
50
|
/**
|
|
43
51
|
* Initializes all analytics providers and sets up browser context.
|
|
44
52
|
*
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { AnalyticsConfig, EventContext, UserContext } from '../../core/events/types.js';
|
|
2
2
|
type DefaultEventMap = Record<string, Record<string, unknown>>;
|
|
3
3
|
export declare class ServerAnalytics<TEventMap extends Record<string, Record<string, unknown>> = DefaultEventMap, TUserTraits extends Record<string, unknown> = Record<string, unknown>> {
|
|
4
|
-
private
|
|
4
|
+
private providerConfigs;
|
|
5
5
|
private config;
|
|
6
6
|
private initialized;
|
|
7
7
|
/**
|
|
@@ -35,6 +35,14 @@ export declare class ServerAnalytics<TEventMap extends Record<string, Record<str
|
|
|
35
35
|
* ```
|
|
36
36
|
*/
|
|
37
37
|
constructor(config: AnalyticsConfig);
|
|
38
|
+
/**
|
|
39
|
+
* Normalizes provider configurations into a consistent internal format
|
|
40
|
+
*/
|
|
41
|
+
private normalizeProviders;
|
|
42
|
+
/**
|
|
43
|
+
* Checks if a method should be called on a provider based on routing configuration
|
|
44
|
+
*/
|
|
45
|
+
private shouldCallMethod;
|
|
38
46
|
/**
|
|
39
47
|
* Initializes all analytics providers.
|
|
40
48
|
*
|
package/dist/client.js
CHANGED
|
@@ -1,25 +1,25 @@
|
|
|
1
|
-
var
|
|
2
|
-
var
|
|
3
|
-
var s = (t, e, i) =>
|
|
4
|
-
import { i as
|
|
5
|
-
import { P
|
|
6
|
-
import { B as
|
|
7
|
-
class
|
|
1
|
+
var c = Object.defineProperty;
|
|
2
|
+
var u = (t, e, i) => e in t ? c(t, e, { enumerable: !0, configurable: !0, writable: !0, value: i }) : t[e] = i;
|
|
3
|
+
var s = (t, e, i) => u(t, typeof e != "symbol" ? e + "" : e, i);
|
|
4
|
+
import { i as f } from "./client-DTHZYkxx.js";
|
|
5
|
+
import { P } from "./client-DTHZYkxx.js";
|
|
6
|
+
import { B as k } from "./base.provider-AfFL5W_P.js";
|
|
7
|
+
class p {
|
|
8
8
|
/**
|
|
9
9
|
* Creates a new BrowserAnalytics instance for client-side event tracking.
|
|
10
|
-
*
|
|
10
|
+
*
|
|
11
11
|
* Automatically generates a session ID and sets up the analytics context.
|
|
12
12
|
* The instance will be ready to track events once initialized.
|
|
13
|
-
*
|
|
13
|
+
*
|
|
14
14
|
* @param config Analytics configuration including providers and default context
|
|
15
15
|
* @param config.providers Array of analytics provider instances (e.g., PostHogClientProvider)
|
|
16
16
|
* @param config.defaultContext Optional default context to include with all events
|
|
17
|
-
*
|
|
17
|
+
*
|
|
18
18
|
* @example
|
|
19
19
|
* ```typescript
|
|
20
20
|
* import { BrowserAnalytics } from '@stacksee/analytics/client';
|
|
21
21
|
* import { PostHogClientProvider } from '@stacksee/analytics/providers/posthog';
|
|
22
|
-
*
|
|
22
|
+
*
|
|
23
23
|
* const analytics = new BrowserAnalytics({
|
|
24
24
|
* providers: [
|
|
25
25
|
* new PostHogClientProvider({
|
|
@@ -31,43 +31,85 @@ class f {
|
|
|
31
31
|
* app: { version: '1.0.0' }
|
|
32
32
|
* }
|
|
33
33
|
* });
|
|
34
|
-
*
|
|
34
|
+
*
|
|
35
35
|
* await analytics.initialize();
|
|
36
36
|
* ```
|
|
37
37
|
*/
|
|
38
38
|
constructor(e) {
|
|
39
|
-
s(this, "
|
|
39
|
+
s(this, "providerConfigs", []);
|
|
40
40
|
s(this, "context", {});
|
|
41
41
|
s(this, "userId");
|
|
42
42
|
s(this, "sessionId");
|
|
43
43
|
s(this, "userTraits");
|
|
44
44
|
s(this, "initialized", !1);
|
|
45
45
|
s(this, "initializePromise");
|
|
46
|
-
this.
|
|
46
|
+
this.providerConfigs = this.normalizeProviders(e.providers), e.defaultContext && (this.context = { ...e.defaultContext }), this.sessionId = this.generateSessionId();
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Normalizes provider configurations into a consistent internal format
|
|
50
|
+
*/
|
|
51
|
+
normalizeProviders(e) {
|
|
52
|
+
const i = [
|
|
53
|
+
"initialize",
|
|
54
|
+
"identify",
|
|
55
|
+
"track",
|
|
56
|
+
"pageView",
|
|
57
|
+
"pageLeave",
|
|
58
|
+
"reset"
|
|
59
|
+
];
|
|
60
|
+
return e.map((r) => {
|
|
61
|
+
if ("initialize" in r && "track" in r)
|
|
62
|
+
return {
|
|
63
|
+
provider: r,
|
|
64
|
+
enabledMethods: new Set(i)
|
|
65
|
+
};
|
|
66
|
+
const n = r;
|
|
67
|
+
n.methods && n.exclude && console.warn(
|
|
68
|
+
`[Analytics] Provider ${n.provider.name} has both 'methods' and 'exclude' specified. Using 'methods' and ignoring 'exclude'.`
|
|
69
|
+
);
|
|
70
|
+
let o;
|
|
71
|
+
return n.methods ? o = new Set(n.methods) : n.exclude ? o = new Set(
|
|
72
|
+
i.filter(
|
|
73
|
+
(d) => {
|
|
74
|
+
var h;
|
|
75
|
+
return !((h = n.exclude) != null && h.includes(d));
|
|
76
|
+
}
|
|
77
|
+
)
|
|
78
|
+
) : o = new Set(i), {
|
|
79
|
+
provider: n.provider,
|
|
80
|
+
enabledMethods: o
|
|
81
|
+
};
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Checks if a method should be called on a provider based on routing configuration
|
|
86
|
+
*/
|
|
87
|
+
shouldCallMethod(e, i) {
|
|
88
|
+
return e.enabledMethods.has(i);
|
|
47
89
|
}
|
|
48
90
|
/**
|
|
49
91
|
* Initializes all analytics providers and sets up browser context.
|
|
50
|
-
*
|
|
92
|
+
*
|
|
51
93
|
* This method must be called before tracking events. It initializes all configured
|
|
52
94
|
* providers and automatically captures browser context including page information,
|
|
53
95
|
* device type, OS, and browser details.
|
|
54
|
-
*
|
|
96
|
+
*
|
|
55
97
|
* The method is safe to call multiple times and will not re-initialize if already done.
|
|
56
98
|
* If called while initialization is in progress, it returns the existing promise.
|
|
57
|
-
*
|
|
99
|
+
*
|
|
58
100
|
* @returns Promise that resolves when initialization is complete
|
|
59
|
-
*
|
|
101
|
+
*
|
|
60
102
|
* @example
|
|
61
103
|
* ```typescript
|
|
62
104
|
* const analytics = new BrowserAnalytics({ providers: [] });
|
|
63
|
-
*
|
|
105
|
+
*
|
|
64
106
|
* // Initialize before tracking events
|
|
65
107
|
* await analytics.initialize();
|
|
66
|
-
*
|
|
108
|
+
*
|
|
67
109
|
* // Now ready to track events
|
|
68
110
|
* analytics.track('page_viewed', { page: '/dashboard' });
|
|
69
111
|
* ```
|
|
70
|
-
*
|
|
112
|
+
*
|
|
71
113
|
* @example
|
|
72
114
|
* ```typescript
|
|
73
115
|
* // Safe to call multiple times
|
|
@@ -76,12 +118,12 @@ class f {
|
|
|
76
118
|
* ```
|
|
77
119
|
*/
|
|
78
120
|
async initialize() {
|
|
79
|
-
if (
|
|
121
|
+
if (f() && !this.initialized)
|
|
80
122
|
return this.initializePromise ? this.initializePromise : (this.initializePromise = this._doInitialize(), this.initializePromise);
|
|
81
123
|
}
|
|
82
124
|
async _doInitialize() {
|
|
83
|
-
const e = this.
|
|
84
|
-
(i) => i.initialize()
|
|
125
|
+
const e = this.providerConfigs.map(
|
|
126
|
+
(i) => i.provider.initialize()
|
|
85
127
|
);
|
|
86
128
|
await Promise.all(e), this.initialized = !0, this.updateContext({
|
|
87
129
|
page: {
|
|
@@ -170,8 +212,8 @@ class f {
|
|
|
170
212
|
this.userId = e, this.userTraits = i, this.ensureInitialized().catch((r) => {
|
|
171
213
|
console.error("[Analytics] Failed to initialize during identify:", r);
|
|
172
214
|
});
|
|
173
|
-
for (const r of this.
|
|
174
|
-
r.identify(e, i);
|
|
215
|
+
for (const r of this.providerConfigs)
|
|
216
|
+
this.shouldCallMethod(r, "identify") && r.provider.identify(e, i);
|
|
175
217
|
}
|
|
176
218
|
/**
|
|
177
219
|
* Tracks a custom event with properties.
|
|
@@ -191,7 +233,7 @@ class f {
|
|
|
191
233
|
* @param eventName Name of the event to track (must match your event definitions)
|
|
192
234
|
* @param properties Event-specific properties and data
|
|
193
235
|
* @returns Promise that resolves when tracking is complete for all providers
|
|
194
|
-
*
|
|
236
|
+
*
|
|
195
237
|
* @example
|
|
196
238
|
* ```typescript
|
|
197
239
|
* // Track a simple event
|
|
@@ -257,43 +299,43 @@ class f {
|
|
|
257
299
|
timestamp: Date.now(),
|
|
258
300
|
userId: this.userId,
|
|
259
301
|
sessionId: this.sessionId
|
|
260
|
-
},
|
|
302
|
+
}, n = {
|
|
261
303
|
...this.context,
|
|
262
304
|
user: this.userId || this.userTraits ? {
|
|
263
305
|
userId: this.userId,
|
|
264
306
|
email: this.userTraits && "email" in this.userTraits ? this.userTraits.email : void 0,
|
|
265
307
|
traits: this.userTraits
|
|
266
308
|
} : void 0
|
|
267
|
-
},
|
|
309
|
+
}, o = this.providerConfigs.filter((d) => this.shouldCallMethod(d, "track")).map(async (d) => {
|
|
268
310
|
try {
|
|
269
|
-
await d.track(r,
|
|
270
|
-
} catch (
|
|
311
|
+
await d.provider.track(r, n);
|
|
312
|
+
} catch (h) {
|
|
271
313
|
console.error(
|
|
272
|
-
`[Analytics] Provider ${d.name} failed to track event:`,
|
|
273
|
-
|
|
314
|
+
`[Analytics] Provider ${d.provider.name} failed to track event:`,
|
|
315
|
+
h
|
|
274
316
|
);
|
|
275
317
|
}
|
|
276
318
|
});
|
|
277
|
-
await Promise.all(
|
|
319
|
+
await Promise.all(o);
|
|
278
320
|
}
|
|
279
321
|
/**
|
|
280
322
|
* Tracks a page view event.
|
|
281
|
-
*
|
|
323
|
+
*
|
|
282
324
|
* Automatically captures current page information (path, title, referrer) and
|
|
283
325
|
* updates the analytics context. This method should be called when users
|
|
284
326
|
* navigate to a new page or view.
|
|
285
|
-
*
|
|
327
|
+
*
|
|
286
328
|
* The method automatically ensures initialization but doesn't block execution
|
|
287
329
|
* if initialization is still in progress.
|
|
288
|
-
*
|
|
330
|
+
*
|
|
289
331
|
* @param properties Optional properties to include with the page view
|
|
290
|
-
*
|
|
332
|
+
*
|
|
291
333
|
* @example
|
|
292
334
|
* ```typescript
|
|
293
335
|
* // Basic page view tracking
|
|
294
336
|
* analytics.pageView();
|
|
295
337
|
* ```
|
|
296
|
-
*
|
|
338
|
+
*
|
|
297
339
|
* @example
|
|
298
340
|
* ```typescript
|
|
299
341
|
* // Page view with additional properties
|
|
@@ -304,12 +346,12 @@ class f {
|
|
|
304
346
|
* source: 'organic_search'
|
|
305
347
|
* });
|
|
306
348
|
* ```
|
|
307
|
-
*
|
|
349
|
+
*
|
|
308
350
|
* @example
|
|
309
351
|
* ```typescript
|
|
310
352
|
* // In a SvelteKit app with automatic navigation tracking
|
|
311
353
|
* import { afterNavigate } from '$app/navigation';
|
|
312
|
-
*
|
|
354
|
+
*
|
|
313
355
|
* afterNavigate(() => {
|
|
314
356
|
* analytics.pageView({
|
|
315
357
|
* timestamp: Date.now(),
|
|
@@ -317,16 +359,16 @@ class f {
|
|
|
317
359
|
* });
|
|
318
360
|
* });
|
|
319
361
|
* ```
|
|
320
|
-
*
|
|
362
|
+
*
|
|
321
363
|
* @example
|
|
322
364
|
* ```typescript
|
|
323
365
|
* // In a React app with React Router
|
|
324
366
|
* import { useEffect } from 'react';
|
|
325
367
|
* import { useLocation } from 'react-router-dom';
|
|
326
|
-
*
|
|
368
|
+
*
|
|
327
369
|
* function usePageTracking() {
|
|
328
370
|
* const location = useLocation();
|
|
329
|
-
*
|
|
371
|
+
*
|
|
330
372
|
* useEffect(() => {
|
|
331
373
|
* analytics.pageView({
|
|
332
374
|
* path: location.pathname,
|
|
@@ -346,27 +388,27 @@ class f {
|
|
|
346
388
|
referrer: document.referrer
|
|
347
389
|
}
|
|
348
390
|
});
|
|
349
|
-
for (const i of this.
|
|
350
|
-
i.pageView(e, this.context);
|
|
391
|
+
for (const i of this.providerConfigs)
|
|
392
|
+
this.shouldCallMethod(i, "pageView") && i.provider.pageView(e, this.context);
|
|
351
393
|
}
|
|
352
394
|
/**
|
|
353
395
|
* Tracks when a user leaves a page.
|
|
354
|
-
*
|
|
396
|
+
*
|
|
355
397
|
* This method should be called before navigation to track user engagement
|
|
356
398
|
* and session duration. It's useful for understanding how long users spend
|
|
357
399
|
* on different pages and their navigation patterns.
|
|
358
|
-
*
|
|
400
|
+
*
|
|
359
401
|
* Note: Not all analytics providers support page leave events. The method
|
|
360
402
|
* will only call providers that implement the pageLeave method.
|
|
361
|
-
*
|
|
403
|
+
*
|
|
362
404
|
* @param properties Optional properties to include with the page leave event
|
|
363
|
-
*
|
|
405
|
+
*
|
|
364
406
|
* @example
|
|
365
407
|
* ```typescript
|
|
366
408
|
* // Basic page leave tracking
|
|
367
409
|
* analytics.pageLeave();
|
|
368
410
|
* ```
|
|
369
|
-
*
|
|
411
|
+
*
|
|
370
412
|
* @example
|
|
371
413
|
* ```typescript
|
|
372
414
|
* // Page leave with engagement metrics
|
|
@@ -377,14 +419,14 @@ class f {
|
|
|
377
419
|
* exitIntent: true // detected exit intent
|
|
378
420
|
* });
|
|
379
421
|
* ```
|
|
380
|
-
*
|
|
422
|
+
*
|
|
381
423
|
* @example
|
|
382
424
|
* ```typescript
|
|
383
425
|
* // In a SvelteKit app with automatic navigation tracking
|
|
384
426
|
* import { beforeNavigate } from '$app/navigation';
|
|
385
|
-
*
|
|
427
|
+
*
|
|
386
428
|
* let pageStartTime = Date.now();
|
|
387
|
-
*
|
|
429
|
+
*
|
|
388
430
|
* beforeNavigate(() => {
|
|
389
431
|
* analytics.pageLeave({
|
|
390
432
|
* duration: Date.now() - pageStartTime,
|
|
@@ -392,7 +434,7 @@ class f {
|
|
|
392
434
|
* });
|
|
393
435
|
* });
|
|
394
436
|
* ```
|
|
395
|
-
*
|
|
437
|
+
*
|
|
396
438
|
* @example
|
|
397
439
|
* ```typescript
|
|
398
440
|
* // Track page leave on browser unload
|
|
@@ -406,27 +448,30 @@ class f {
|
|
|
406
448
|
*/
|
|
407
449
|
pageLeave(e) {
|
|
408
450
|
this.ensureInitialized().catch((i) => {
|
|
409
|
-
console.error(
|
|
451
|
+
console.error(
|
|
452
|
+
"[Analytics] Failed to initialize during pageLeave:",
|
|
453
|
+
i
|
|
454
|
+
);
|
|
410
455
|
});
|
|
411
|
-
for (const i of this.
|
|
412
|
-
i.pageLeave && i.pageLeave(e, this.context);
|
|
456
|
+
for (const i of this.providerConfigs)
|
|
457
|
+
this.shouldCallMethod(i, "pageLeave") && i.provider.pageLeave && i.provider.pageLeave(e, this.context);
|
|
413
458
|
}
|
|
414
459
|
/**
|
|
415
460
|
* Resets the analytics state, clearing user ID and generating a new session.
|
|
416
|
-
*
|
|
461
|
+
*
|
|
417
462
|
* This method should be called when a user logs out or when you want to
|
|
418
463
|
* start tracking a new user session. It clears the current user ID,
|
|
419
464
|
* generates a new session ID, and calls reset on all providers.
|
|
420
|
-
*
|
|
465
|
+
*
|
|
421
466
|
* Use this method to ensure user privacy and accurate session tracking
|
|
422
467
|
* when users switch accounts or log out.
|
|
423
|
-
*
|
|
468
|
+
*
|
|
424
469
|
* @example
|
|
425
470
|
* ```typescript
|
|
426
471
|
* // Basic reset on logout
|
|
427
472
|
* analytics.reset();
|
|
428
473
|
* ```
|
|
429
|
-
*
|
|
474
|
+
*
|
|
430
475
|
* @example
|
|
431
476
|
* ```typescript
|
|
432
477
|
* // In a logout handler
|
|
@@ -435,26 +480,26 @@ class f {
|
|
|
435
480
|
* await analytics.track('user_logged_out', {
|
|
436
481
|
* sessionDuration: Date.now() - sessionStartTime
|
|
437
482
|
* });
|
|
438
|
-
*
|
|
483
|
+
*
|
|
439
484
|
* // Reset analytics state
|
|
440
485
|
* analytics.reset();
|
|
441
|
-
*
|
|
486
|
+
*
|
|
442
487
|
* // Clear user data and redirect
|
|
443
488
|
* clearUserData();
|
|
444
489
|
* window.location.href = '/login';
|
|
445
490
|
* }
|
|
446
491
|
* ```
|
|
447
|
-
*
|
|
492
|
+
*
|
|
448
493
|
* @example
|
|
449
494
|
* ```typescript
|
|
450
495
|
* // Account switching scenario
|
|
451
496
|
* async function switchAccount(newUserId: string) {
|
|
452
497
|
* // Reset to clear previous user
|
|
453
498
|
* analytics.reset();
|
|
454
|
-
*
|
|
499
|
+
*
|
|
455
500
|
* // Identify the new user
|
|
456
501
|
* analytics.identify(newUserId);
|
|
457
|
-
*
|
|
502
|
+
*
|
|
458
503
|
* // Track account switch
|
|
459
504
|
* analytics.track('account_switched', {
|
|
460
505
|
* newUserId,
|
|
@@ -465,25 +510,25 @@ class f {
|
|
|
465
510
|
*/
|
|
466
511
|
reset() {
|
|
467
512
|
this.userId = void 0, this.userTraits = void 0, this.sessionId = this.generateSessionId();
|
|
468
|
-
for (const e of this.
|
|
469
|
-
e.reset();
|
|
513
|
+
for (const e of this.providerConfigs)
|
|
514
|
+
this.shouldCallMethod(e, "reset") && e.provider.reset();
|
|
470
515
|
}
|
|
471
516
|
/**
|
|
472
517
|
* Updates the analytics context with new information.
|
|
473
|
-
*
|
|
518
|
+
*
|
|
474
519
|
* The context is included with all tracked events and provides additional
|
|
475
520
|
* metadata about the user's environment, current page, device, and other
|
|
476
521
|
* relevant information. This method merges new context with existing context.
|
|
477
|
-
*
|
|
522
|
+
*
|
|
478
523
|
* Context typically includes page information, device details, UTM parameters,
|
|
479
524
|
* and custom application context.
|
|
480
|
-
*
|
|
525
|
+
*
|
|
481
526
|
* @param context Partial context to merge with existing context
|
|
482
527
|
* @param context.page Page-related context (path, title, referrer)
|
|
483
528
|
* @param context.device Device-related context (type, OS, browser)
|
|
484
529
|
* @param context.utm UTM campaign tracking parameters
|
|
485
530
|
* @param context.app Application-specific context
|
|
486
|
-
*
|
|
531
|
+
*
|
|
487
532
|
* @example
|
|
488
533
|
* ```typescript
|
|
489
534
|
* // Update page context
|
|
@@ -495,7 +540,7 @@ class f {
|
|
|
495
540
|
* }
|
|
496
541
|
* });
|
|
497
542
|
* ```
|
|
498
|
-
*
|
|
543
|
+
*
|
|
499
544
|
* @example
|
|
500
545
|
* ```typescript
|
|
501
546
|
* // Add UTM parameters from URL
|
|
@@ -510,7 +555,7 @@ class f {
|
|
|
510
555
|
* }
|
|
511
556
|
* });
|
|
512
557
|
* ```
|
|
513
|
-
*
|
|
558
|
+
*
|
|
514
559
|
* @example
|
|
515
560
|
* ```typescript
|
|
516
561
|
* // Update application context
|
|
@@ -529,14 +574,14 @@ class f {
|
|
|
529
574
|
* ```
|
|
530
575
|
*/
|
|
531
576
|
updateContext(e) {
|
|
532
|
-
var i, r,
|
|
577
|
+
var i, r, n;
|
|
533
578
|
this.context = {
|
|
534
579
|
...this.context,
|
|
535
580
|
...e,
|
|
536
581
|
page: e.page ? {
|
|
537
582
|
path: e.page.path || ((i = this.context.page) == null ? void 0 : i.path) || window.location.pathname,
|
|
538
583
|
title: e.page.title || ((r = this.context.page) == null ? void 0 : r.title),
|
|
539
|
-
referrer: e.page.referrer || ((
|
|
584
|
+
referrer: e.page.referrer || ((n = this.context.page) == null ? void 0 : n.referrer)
|
|
540
585
|
} : this.context.page,
|
|
541
586
|
device: {
|
|
542
587
|
...this.context.device,
|
|
@@ -570,51 +615,51 @@ class f {
|
|
|
570
615
|
return e.indexOf("Chrome") !== -1 ? "Chrome" : e.indexOf("Safari") !== -1 ? "Safari" : e.indexOf("Firefox") !== -1 ? "Firefox" : e.indexOf("Edge") !== -1 ? "Edge" : "Unknown";
|
|
571
616
|
}
|
|
572
617
|
}
|
|
573
|
-
let
|
|
618
|
+
let a = null;
|
|
574
619
|
function v(t) {
|
|
575
|
-
if (
|
|
576
|
-
return console.warn("[Analytics] Already initialized"),
|
|
620
|
+
if (a)
|
|
621
|
+
return console.warn("[Analytics] Already initialized"), a;
|
|
577
622
|
const e = {
|
|
578
623
|
providers: t.providers || [],
|
|
579
624
|
debug: t.debug,
|
|
580
625
|
enabled: t.enabled
|
|
581
626
|
};
|
|
582
|
-
return
|
|
627
|
+
return a = new p(e), a.initialize().catch((i) => {
|
|
583
628
|
console.error("[Analytics] Failed to initialize:", i);
|
|
584
|
-
}),
|
|
629
|
+
}), a;
|
|
585
630
|
}
|
|
586
|
-
function
|
|
587
|
-
if (!
|
|
631
|
+
function l() {
|
|
632
|
+
if (!a)
|
|
588
633
|
throw new Error(
|
|
589
634
|
"[Analytics] Not initialized. Call createAnalytics() first."
|
|
590
635
|
);
|
|
591
|
-
return
|
|
592
|
-
}
|
|
593
|
-
function y(t, e) {
|
|
594
|
-
return a().track(t, e);
|
|
636
|
+
return a;
|
|
595
637
|
}
|
|
596
638
|
function w(t, e) {
|
|
597
|
-
|
|
639
|
+
return l().track(t, e);
|
|
640
|
+
}
|
|
641
|
+
function y(t, e) {
|
|
642
|
+
l().identify(t, e);
|
|
598
643
|
}
|
|
599
644
|
function x(t) {
|
|
600
|
-
|
|
645
|
+
l().pageView(t);
|
|
601
646
|
}
|
|
602
647
|
function z(t) {
|
|
603
|
-
|
|
648
|
+
l().pageLeave(t);
|
|
604
649
|
}
|
|
605
|
-
function
|
|
606
|
-
|
|
650
|
+
function C() {
|
|
651
|
+
l().reset();
|
|
607
652
|
}
|
|
608
653
|
export {
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
654
|
+
k as BaseAnalyticsProvider,
|
|
655
|
+
p as BrowserAnalytics,
|
|
656
|
+
P as PostHogClientProvider,
|
|
612
657
|
v as createAnalytics,
|
|
613
658
|
v as createClientAnalytics,
|
|
614
|
-
|
|
615
|
-
|
|
659
|
+
l as getAnalytics,
|
|
660
|
+
y as identify,
|
|
616
661
|
z as pageLeave,
|
|
617
662
|
x as pageView,
|
|
618
|
-
|
|
619
|
-
|
|
663
|
+
C as reset,
|
|
664
|
+
w as track
|
|
620
665
|
};
|
|
@@ -68,8 +68,57 @@ export interface AnalyticsProvider {
|
|
|
68
68
|
pageLeave?(properties?: Record<string, unknown>, context?: EventContext): Promise<void> | void;
|
|
69
69
|
reset(): Promise<void> | void;
|
|
70
70
|
}
|
|
71
|
+
/**
|
|
72
|
+
* Provider methods that can be selectively enabled/disabled through routing
|
|
73
|
+
*/
|
|
74
|
+
export type ProviderMethod = "initialize" | "identify" | "track" | "pageView" | "pageLeave" | "reset";
|
|
75
|
+
/**
|
|
76
|
+
* Configuration for selective provider method routing.
|
|
77
|
+
* Allows you to control which methods are called on a specific provider.
|
|
78
|
+
*
|
|
79
|
+
* @example
|
|
80
|
+
* ```typescript
|
|
81
|
+
* // Only call track and identify, skip pageView
|
|
82
|
+
* {
|
|
83
|
+
* provider: new BentoClientProvider({...}),
|
|
84
|
+
* methods: ['track', 'identify']
|
|
85
|
+
* }
|
|
86
|
+
* ```
|
|
87
|
+
*
|
|
88
|
+
* @example
|
|
89
|
+
* ```typescript
|
|
90
|
+
* // Call all methods except pageView
|
|
91
|
+
* {
|
|
92
|
+
* provider: new GoogleAnalyticsProvider({...}),
|
|
93
|
+
* exclude: ['pageView']
|
|
94
|
+
* }
|
|
95
|
+
* ```
|
|
96
|
+
*/
|
|
97
|
+
export interface ProviderConfig {
|
|
98
|
+
/**
|
|
99
|
+
* The analytics provider instance
|
|
100
|
+
*/
|
|
101
|
+
provider: AnalyticsProvider;
|
|
102
|
+
/**
|
|
103
|
+
* Only call these methods on this provider.
|
|
104
|
+
* If specified, all other methods will be skipped.
|
|
105
|
+
* Mutually exclusive with `exclude`.
|
|
106
|
+
*/
|
|
107
|
+
methods?: ProviderMethod[];
|
|
108
|
+
/**
|
|
109
|
+
* Skip these methods on this provider.
|
|
110
|
+
* All other methods will be called normally.
|
|
111
|
+
* Mutually exclusive with `methods`.
|
|
112
|
+
*/
|
|
113
|
+
exclude?: ProviderMethod[];
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Provider configuration - supports both simple provider instances
|
|
117
|
+
* and advanced routing configurations
|
|
118
|
+
*/
|
|
119
|
+
export type ProviderConfigOrProvider = AnalyticsProvider | ProviderConfig;
|
|
71
120
|
export interface AnalyticsConfig {
|
|
72
|
-
providers:
|
|
121
|
+
providers: ProviderConfigOrProvider[];
|
|
73
122
|
debug?: boolean;
|
|
74
123
|
enabled?: boolean;
|
|
75
124
|
defaultContext?: Partial<EventContext>;
|
package/dist/providers/client.js
CHANGED
|
@@ -58,7 +58,7 @@ class w extends u {
|
|
|
58
58
|
const s = (i == null ? void 0 : i.email) || e;
|
|
59
59
|
if (this.bento.identify(s), i) {
|
|
60
60
|
const t = { ...i };
|
|
61
|
-
|
|
61
|
+
t.email = void 0, Object.keys(t).length > 0 && this.bento.updateFields(t);
|
|
62
62
|
}
|
|
63
63
|
this.log("Identified user", { userId: e, email: s, traits: i });
|
|
64
64
|
}
|
|
@@ -139,7 +139,9 @@ class w extends u {
|
|
|
139
139
|
this.bento.track("$pageleave", s), this.log("Tracked page leave", { properties: e, context: i });
|
|
140
140
|
}
|
|
141
141
|
reset() {
|
|
142
|
-
!this.isEnabled() || !this.initialized || !this.bento || !a() || this.log(
|
|
142
|
+
!this.isEnabled() || !this.initialized || !this.bento || !a() || this.log(
|
|
143
|
+
"Reset user session - Note: Bento doesn't have a native reset method"
|
|
144
|
+
);
|
|
143
145
|
}
|
|
144
146
|
// ============================================================================
|
|
145
147
|
// Bento-Specific Utility Methods
|
|
@@ -389,7 +391,7 @@ class v extends u {
|
|
|
389
391
|
r(this, "retryAttempts");
|
|
390
392
|
r(this, "retryBackoff");
|
|
391
393
|
r(this, "retryInitialDelay");
|
|
392
|
-
this.config = e, this.batchSize = ((i = e.batch) == null ? void 0 : i.size) ?? 10, this.batchInterval = ((s = e.batch) == null ? void 0 : s.interval) ??
|
|
394
|
+
this.config = e, this.batchSize = ((i = e.batch) == null ? void 0 : i.size) ?? 10, this.batchInterval = ((s = e.batch) == null ? void 0 : s.interval) ?? 2e3, this.retryAttempts = ((t = e.retry) == null ? void 0 : t.attempts) ?? 3, this.retryBackoff = ((n = e.retry) == null ? void 0 : n.backoff) ?? "exponential", this.retryInitialDelay = ((l = e.retry) == null ? void 0 : l.initialDelay) ?? 1e3, typeof window < "u" && (window.addEventListener("beforeunload", () => {
|
|
393
395
|
this.flush(!0);
|
|
394
396
|
}), document.addEventListener("visibilitychange", () => {
|
|
395
397
|
document.visibilityState === "hidden" && this.flush(!0);
|
|
@@ -442,11 +444,11 @@ class v extends u {
|
|
|
442
444
|
});
|
|
443
445
|
return;
|
|
444
446
|
}
|
|
445
|
-
this.flushTimer
|
|
447
|
+
this.flushTimer && clearTimeout(this.flushTimer), this.flushTimer = setTimeout(() => {
|
|
446
448
|
this.flush().catch((i) => {
|
|
447
449
|
console.error("[Proxy] Failed to flush events:", i);
|
|
448
450
|
});
|
|
449
|
-
}, this.batchInterval)
|
|
451
|
+
}, this.batchInterval);
|
|
450
452
|
}
|
|
451
453
|
async sendEvents(e, i = !1) {
|
|
452
454
|
const s = { events: e };
|
|
@@ -2,7 +2,7 @@ export { BaseAnalyticsProvider } from './base.provider.js';
|
|
|
2
2
|
export { PostHogServerProvider } from './posthog/server.js';
|
|
3
3
|
export type { PostHogOptions } from 'posthog-node';
|
|
4
4
|
export { BentoServerProvider } from './bento/server.js';
|
|
5
|
-
export type { BentoServerConfig, BentoAnalyticsOptions } from './bento/server.js';
|
|
5
|
+
export type { BentoServerConfig, BentoAnalyticsOptions, } from './bento/server.js';
|
|
6
6
|
export { PirschServerProvider } from './pirsch/server.js';
|
|
7
7
|
export type { PirschServerConfig } from './pirsch/server.js';
|
|
8
8
|
export { ingestProxyEvents, createProxyHandler } from './proxy/server.js';
|
package/dist/providers/server.js
CHANGED
|
@@ -39,12 +39,15 @@ class N extends V {
|
|
|
39
39
|
if (!this.isEnabled() || !this.initialized || !this.client) return;
|
|
40
40
|
const r = (e == null ? void 0 : e.email) || i;
|
|
41
41
|
if (!r || !r.includes("@")) {
|
|
42
|
-
this.log("Skipping identify - invalid or missing email", {
|
|
42
|
+
this.log("Skipping identify - invalid or missing email", {
|
|
43
|
+
userId: i,
|
|
44
|
+
traits: e
|
|
45
|
+
});
|
|
43
46
|
return;
|
|
44
47
|
}
|
|
45
48
|
this.currentUserEmail = r;
|
|
46
49
|
const h = e ? { ...e } : {};
|
|
47
|
-
|
|
50
|
+
h.email = void 0, this.client.V1.addSubscriber({
|
|
48
51
|
email: r,
|
|
49
52
|
fields: h
|
|
50
53
|
}).catch((s) => {
|
|
@@ -192,11 +195,14 @@ class W extends V {
|
|
|
192
195
|
if (!this.isEnabled() || !this.initialized || !this.client) return;
|
|
193
196
|
const r = e, h = ((a = r == null ? void 0 : r.device) == null ? void 0 : a.ip) || ((o = r == null ? void 0 : r.server) == null ? void 0 : o.ip), s = ((f = r == null ? void 0 : r.server) == null ? void 0 : f.userAgent) || ((y = r == null ? void 0 : r.device) == null ? void 0 : y.userAgent);
|
|
194
197
|
if (!h || !s) {
|
|
195
|
-
this.log(
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
198
|
+
this.log(
|
|
199
|
+
"Skipping event - missing required IP or user-agent from context",
|
|
200
|
+
{
|
|
201
|
+
hasIp: !!h,
|
|
202
|
+
hasUserAgent: !!s,
|
|
203
|
+
event: i.action
|
|
204
|
+
}
|
|
205
|
+
);
|
|
200
206
|
return;
|
|
201
207
|
}
|
|
202
208
|
const g = {
|
|
@@ -205,11 +211,21 @@ class W extends V {
|
|
|
205
211
|
user_agent: s,
|
|
206
212
|
...((k = e == null ? void 0 : e.page) == null ? void 0 : k.title) && { title: e.page.title },
|
|
207
213
|
...((I = e == null ? void 0 : e.page) == null ? void 0 : I.referrer) && { referrer: e.page.referrer },
|
|
208
|
-
...((E = (_ = e == null ? void 0 : e.device) == null ? void 0 : _.screen) == null ? void 0 : E.width) && {
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
...((
|
|
212
|
-
|
|
214
|
+
...((E = (_ = e == null ? void 0 : e.device) == null ? void 0 : _.screen) == null ? void 0 : E.width) && {
|
|
215
|
+
screen_width: e.device.screen.width
|
|
216
|
+
},
|
|
217
|
+
...((z = (P = e == null ? void 0 : e.device) == null ? void 0 : P.screen) == null ? void 0 : z.height) && {
|
|
218
|
+
screen_height: e.device.screen.height
|
|
219
|
+
},
|
|
220
|
+
...((A = (B = e == null ? void 0 : e.device) == null ? void 0 : B.viewport) == null ? void 0 : A.width) && {
|
|
221
|
+
sec_ch_viewport_width: String(e.device.viewport.width)
|
|
222
|
+
},
|
|
223
|
+
...((F = e == null ? void 0 : e.device) == null ? void 0 : F.language) && {
|
|
224
|
+
accept_language: e.device.language
|
|
225
|
+
},
|
|
226
|
+
...((v = e == null ? void 0 : e.device) == null ? void 0 : v.type) && {
|
|
227
|
+
sec_ch_ua_mobile: e.device.type === "mobile" || e.device.type === "tablet" ? "?1" : "?0"
|
|
228
|
+
},
|
|
213
229
|
...(($ = e == null ? void 0 : e.device) == null ? void 0 : $.os) && { sec_ch_ua_platform: e.device.os }
|
|
214
230
|
}, l = {
|
|
215
231
|
...Object.fromEntries(
|
|
@@ -236,10 +252,13 @@ class W extends V {
|
|
|
236
252
|
if (!this.isEnabled() || !this.initialized || !this.client) return;
|
|
237
253
|
const r = e, h = ((n = r == null ? void 0 : r.device) == null ? void 0 : n.ip) || ((l = r == null ? void 0 : r.server) == null ? void 0 : l.ip), s = ((a = r == null ? void 0 : r.server) == null ? void 0 : a.userAgent) || ((o = r == null ? void 0 : r.device) == null ? void 0 : o.userAgent);
|
|
238
254
|
if (!h || !s) {
|
|
239
|
-
this.log(
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
255
|
+
this.log(
|
|
256
|
+
"Skipping pageView - missing required IP or user-agent from context",
|
|
257
|
+
{
|
|
258
|
+
hasIp: !!h,
|
|
259
|
+
hasUserAgent: !!s
|
|
260
|
+
}
|
|
261
|
+
);
|
|
243
262
|
return;
|
|
244
263
|
}
|
|
245
264
|
const g = {
|
|
@@ -248,11 +267,21 @@ class W extends V {
|
|
|
248
267
|
user_agent: s,
|
|
249
268
|
...((b = e == null ? void 0 : e.page) == null ? void 0 : b.title) && { title: e.page.title },
|
|
250
269
|
...((S = e == null ? void 0 : e.page) == null ? void 0 : S.referrer) && { referrer: e.page.referrer },
|
|
251
|
-
...((I = (k = e == null ? void 0 : e.device) == null ? void 0 : k.screen) == null ? void 0 : I.width) && {
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
...((
|
|
255
|
-
|
|
270
|
+
...((I = (k = e == null ? void 0 : e.device) == null ? void 0 : k.screen) == null ? void 0 : I.width) && {
|
|
271
|
+
screen_width: e.device.screen.width
|
|
272
|
+
},
|
|
273
|
+
...((E = (_ = e == null ? void 0 : e.device) == null ? void 0 : _.screen) == null ? void 0 : E.height) && {
|
|
274
|
+
screen_height: e.device.screen.height
|
|
275
|
+
},
|
|
276
|
+
...((z = (P = e == null ? void 0 : e.device) == null ? void 0 : P.viewport) == null ? void 0 : z.width) && {
|
|
277
|
+
sec_ch_viewport_width: String(e.device.viewport.width)
|
|
278
|
+
},
|
|
279
|
+
...((B = e == null ? void 0 : e.device) == null ? void 0 : B.language) && {
|
|
280
|
+
accept_language: e.device.language
|
|
281
|
+
},
|
|
282
|
+
...((A = e == null ? void 0 : e.device) == null ? void 0 : A.type) && {
|
|
283
|
+
sec_ch_ua_mobile: e.device.type === "mobile" || e.device.type === "tablet" ? "?1" : "?0"
|
|
284
|
+
},
|
|
256
285
|
...((F = e == null ? void 0 : e.device) == null ? void 0 : F.os) && { sec_ch_ua_platform: e.device.os },
|
|
257
286
|
...i && {
|
|
258
287
|
tags: Object.fromEntries(
|
package/dist/server.js
CHANGED
|
@@ -1,24 +1,24 @@
|
|
|
1
|
-
var
|
|
2
|
-
var
|
|
3
|
-
var
|
|
1
|
+
var h = Object.defineProperty;
|
|
2
|
+
var f = (a, r, e) => r in a ? h(a, r, { enumerable: !0, configurable: !0, writable: !0, value: e }) : a[r] = e;
|
|
3
|
+
var o = (a, r, e) => f(a, typeof r != "symbol" ? r + "" : r, e);
|
|
4
4
|
import { P as w } from "./server-DjEk1fUD.js";
|
|
5
|
-
import { B as
|
|
5
|
+
import { B as x } from "./base.provider-AfFL5W_P.js";
|
|
6
6
|
class v {
|
|
7
7
|
/**
|
|
8
8
|
* Creates a new ServerAnalytics instance for server-side event tracking.
|
|
9
|
-
*
|
|
9
|
+
*
|
|
10
10
|
* The server analytics instance is designed for Node.js environments including
|
|
11
11
|
* long-running servers, serverless functions, and edge computing environments.
|
|
12
|
-
*
|
|
12
|
+
*
|
|
13
13
|
* @param config Analytics configuration including providers and default context
|
|
14
14
|
* @param config.providers Array of analytics provider instances (e.g., PostHogServerProvider)
|
|
15
15
|
* @param config.defaultContext Optional default context to include with all events
|
|
16
|
-
*
|
|
16
|
+
*
|
|
17
17
|
* @example
|
|
18
18
|
* ```typescript
|
|
19
19
|
* import { ServerAnalytics } from '@stacksee/analytics/server';
|
|
20
20
|
* import { PostHogServerProvider } from '@stacksee/analytics/providers/posthog';
|
|
21
|
-
*
|
|
21
|
+
*
|
|
22
22
|
* const analytics = new ServerAnalytics({
|
|
23
23
|
* providers: [
|
|
24
24
|
* new PostHogServerProvider({
|
|
@@ -30,75 +30,117 @@ class v {
|
|
|
30
30
|
* app: { version: '1.0.0', environment: 'production' }
|
|
31
31
|
* }
|
|
32
32
|
* });
|
|
33
|
-
*
|
|
33
|
+
*
|
|
34
34
|
* analytics.initialize();
|
|
35
35
|
* ```
|
|
36
36
|
*/
|
|
37
|
-
constructor(
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
this.config =
|
|
37
|
+
constructor(r) {
|
|
38
|
+
o(this, "providerConfigs", []);
|
|
39
|
+
o(this, "config");
|
|
40
|
+
o(this, "initialized", !1);
|
|
41
|
+
this.config = r, this.providerConfigs = this.normalizeProviders(r.providers);
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Normalizes provider configurations into a consistent internal format
|
|
45
|
+
*/
|
|
46
|
+
normalizeProviders(r) {
|
|
47
|
+
const e = [
|
|
48
|
+
"initialize",
|
|
49
|
+
"identify",
|
|
50
|
+
"track",
|
|
51
|
+
"pageView",
|
|
52
|
+
"pageLeave",
|
|
53
|
+
"reset"
|
|
54
|
+
];
|
|
55
|
+
return r.map((i) => {
|
|
56
|
+
if ("initialize" in i && "track" in i)
|
|
57
|
+
return {
|
|
58
|
+
provider: i,
|
|
59
|
+
enabledMethods: new Set(e)
|
|
60
|
+
};
|
|
61
|
+
const t = i;
|
|
62
|
+
t.methods && t.exclude && console.warn(
|
|
63
|
+
`[Analytics] Provider ${t.provider.name} has both 'methods' and 'exclude' specified. Using 'methods' and ignoring 'exclude'.`
|
|
64
|
+
);
|
|
65
|
+
let n;
|
|
66
|
+
return t.methods ? n = new Set(t.methods) : t.exclude ? n = new Set(
|
|
67
|
+
e.filter(
|
|
68
|
+
(l) => {
|
|
69
|
+
var d;
|
|
70
|
+
return !((d = t.exclude) != null && d.includes(l));
|
|
71
|
+
}
|
|
72
|
+
)
|
|
73
|
+
) : n = new Set(e), {
|
|
74
|
+
provider: t.provider,
|
|
75
|
+
enabledMethods: n
|
|
76
|
+
};
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Checks if a method should be called on a provider based on routing configuration
|
|
81
|
+
*/
|
|
82
|
+
shouldCallMethod(r, e) {
|
|
83
|
+
return r.enabledMethods.has(e);
|
|
42
84
|
}
|
|
43
85
|
/**
|
|
44
86
|
* Initializes all analytics providers.
|
|
45
|
-
*
|
|
87
|
+
*
|
|
46
88
|
* This method must be called before tracking events. It initializes all configured
|
|
47
89
|
* providers synchronously. Unlike the browser version, server initialization is
|
|
48
90
|
* typically synchronous as providers don't need to load external scripts.
|
|
49
|
-
*
|
|
91
|
+
*
|
|
50
92
|
* The method is safe to call multiple times and will not re-initialize if already done.
|
|
51
|
-
*
|
|
93
|
+
*
|
|
52
94
|
* @example
|
|
53
95
|
* ```typescript
|
|
54
96
|
* const analytics = new ServerAnalytics({ providers: [] });
|
|
55
|
-
*
|
|
97
|
+
*
|
|
56
98
|
* // Initialize before tracking events
|
|
57
99
|
* analytics.initialize();
|
|
58
|
-
*
|
|
100
|
+
*
|
|
59
101
|
* // Now ready to track events
|
|
60
102
|
* await analytics.track('api_request', { endpoint: '/users' });
|
|
61
103
|
* ```
|
|
62
|
-
*
|
|
104
|
+
*
|
|
63
105
|
* @example
|
|
64
106
|
* ```typescript
|
|
65
107
|
* // In a serverless function
|
|
66
108
|
* export async function handler(req, res) {
|
|
67
109
|
* const analytics = new ServerAnalytics({ providers: [] });
|
|
68
110
|
* analytics.initialize(); // Quick synchronous initialization
|
|
69
|
-
*
|
|
111
|
+
*
|
|
70
112
|
* await analytics.track('function_invoked', {
|
|
71
113
|
* path: req.path,
|
|
72
114
|
* method: req.method
|
|
73
115
|
* });
|
|
74
|
-
*
|
|
116
|
+
*
|
|
75
117
|
* await analytics.shutdown(); // Important for serverless
|
|
76
118
|
* }
|
|
77
119
|
* ```
|
|
78
120
|
*/
|
|
79
121
|
initialize() {
|
|
80
122
|
if (!this.initialized) {
|
|
81
|
-
for (const
|
|
82
|
-
|
|
123
|
+
for (const r of this.providerConfigs)
|
|
124
|
+
r.provider.initialize();
|
|
83
125
|
this.initialized = !0;
|
|
84
126
|
}
|
|
85
127
|
}
|
|
86
128
|
/**
|
|
87
129
|
* Identifies a user with optional traits.
|
|
88
|
-
*
|
|
130
|
+
*
|
|
89
131
|
* Associates subsequent events with the specified user ID and optionally
|
|
90
132
|
* sets user properties. This method is typically called when processing
|
|
91
133
|
* authentication or when you have user context available on the server.
|
|
92
|
-
*
|
|
134
|
+
*
|
|
93
135
|
* @param userId Unique identifier for the user (e.g., database ID, email)
|
|
94
136
|
* @param traits Optional user properties and characteristics
|
|
95
|
-
*
|
|
137
|
+
*
|
|
96
138
|
* @example
|
|
97
139
|
* ```typescript
|
|
98
140
|
* // Basic user identification
|
|
99
141
|
* analytics.identify('user-123');
|
|
100
142
|
* ```
|
|
101
|
-
*
|
|
143
|
+
*
|
|
102
144
|
* @example
|
|
103
145
|
* ```typescript
|
|
104
146
|
* // Identify with user traits from database
|
|
@@ -111,27 +153,27 @@ class v {
|
|
|
111
153
|
* lastSeenAt: new Date().toISOString()
|
|
112
154
|
* });
|
|
113
155
|
* ```
|
|
114
|
-
*
|
|
156
|
+
*
|
|
115
157
|
* @example
|
|
116
158
|
* ```typescript
|
|
117
159
|
* // In an API authentication middleware
|
|
118
160
|
* async function authMiddleware(req, res, next) {
|
|
119
161
|
* const user = await getUserFromToken(req.headers.authorization);
|
|
120
|
-
*
|
|
162
|
+
*
|
|
121
163
|
* analytics.identify(user.id, {
|
|
122
164
|
* email: user.email,
|
|
123
165
|
* role: user.role,
|
|
124
166
|
* organization: user.organization
|
|
125
167
|
* });
|
|
126
|
-
*
|
|
168
|
+
*
|
|
127
169
|
* req.user = user;
|
|
128
170
|
* next();
|
|
129
171
|
* }
|
|
130
172
|
* ```
|
|
131
173
|
*/
|
|
132
|
-
identify(
|
|
133
|
-
for (const
|
|
134
|
-
|
|
174
|
+
identify(r, e) {
|
|
175
|
+
for (const i of this.providerConfigs)
|
|
176
|
+
this.shouldCallMethod(i, "identify") && i.provider.identify(r, e);
|
|
135
177
|
}
|
|
136
178
|
/**
|
|
137
179
|
* Tracks a custom event with properties and optional context.
|
|
@@ -254,30 +296,30 @@ class v {
|
|
|
254
296
|
* }
|
|
255
297
|
* ```
|
|
256
298
|
*/
|
|
257
|
-
async track(
|
|
258
|
-
var
|
|
299
|
+
async track(r, e, i) {
|
|
300
|
+
var d;
|
|
259
301
|
if (!this.initialized) {
|
|
260
302
|
console.warn("[Analytics] Not initialized. Call initialize() first.");
|
|
261
303
|
return;
|
|
262
304
|
}
|
|
263
|
-
const
|
|
264
|
-
action:
|
|
265
|
-
category: this.getCategoryFromEventName(
|
|
266
|
-
properties:
|
|
305
|
+
const t = {
|
|
306
|
+
action: r,
|
|
307
|
+
category: this.getCategoryFromEventName(r),
|
|
308
|
+
properties: e,
|
|
267
309
|
timestamp: Date.now(),
|
|
268
|
-
userId:
|
|
269
|
-
sessionId:
|
|
270
|
-
},
|
|
310
|
+
userId: i == null ? void 0 : i.userId,
|
|
311
|
+
sessionId: i == null ? void 0 : i.sessionId
|
|
312
|
+
}, n = {
|
|
271
313
|
...this.config.defaultContext,
|
|
272
|
-
...
|
|
273
|
-
user: (
|
|
274
|
-
}, l = this.
|
|
314
|
+
...i == null ? void 0 : i.context,
|
|
315
|
+
user: (i == null ? void 0 : i.user) || ((d = i == null ? void 0 : i.context) == null ? void 0 : d.user)
|
|
316
|
+
}, l = this.providerConfigs.filter((s) => this.shouldCallMethod(s, "track")).map(async (s) => {
|
|
275
317
|
try {
|
|
276
|
-
await
|
|
277
|
-
} catch (
|
|
318
|
+
await s.provider.track(t, n);
|
|
319
|
+
} catch (c) {
|
|
278
320
|
console.error(
|
|
279
|
-
`[Analytics] Provider ${
|
|
280
|
-
|
|
321
|
+
`[Analytics] Provider ${s.provider.name} failed to track event:`,
|
|
322
|
+
c
|
|
281
323
|
);
|
|
282
324
|
}
|
|
283
325
|
});
|
|
@@ -285,21 +327,21 @@ class v {
|
|
|
285
327
|
}
|
|
286
328
|
/**
|
|
287
329
|
* Tracks a page view event from the server side.
|
|
288
|
-
*
|
|
330
|
+
*
|
|
289
331
|
* Server-side page view tracking is useful for server-rendered applications,
|
|
290
332
|
* SSR frameworks, or when you want to ensure page views are tracked even
|
|
291
333
|
* if client-side JavaScript fails.
|
|
292
|
-
*
|
|
334
|
+
*
|
|
293
335
|
* @param properties Optional properties to include with the page view
|
|
294
336
|
* @param options Optional configuration including context
|
|
295
337
|
* @param options.context Additional context for this page view
|
|
296
|
-
*
|
|
338
|
+
*
|
|
297
339
|
* @example
|
|
298
340
|
* ```typescript
|
|
299
341
|
* // Basic server-side page view
|
|
300
342
|
* analytics.pageView();
|
|
301
343
|
* ```
|
|
302
|
-
*
|
|
344
|
+
*
|
|
303
345
|
* @example
|
|
304
346
|
* ```typescript
|
|
305
347
|
* // Page view with server context
|
|
@@ -323,7 +365,7 @@ class v {
|
|
|
323
365
|
* }
|
|
324
366
|
* });
|
|
325
367
|
* ```
|
|
326
|
-
*
|
|
368
|
+
*
|
|
327
369
|
* @example
|
|
328
370
|
* ```typescript
|
|
329
371
|
* // In a Next.js API route or middleware
|
|
@@ -343,35 +385,35 @@ class v {
|
|
|
343
385
|
* }
|
|
344
386
|
* ```
|
|
345
387
|
*/
|
|
346
|
-
pageView(
|
|
388
|
+
pageView(r, e) {
|
|
347
389
|
if (!this.initialized) return;
|
|
348
|
-
const
|
|
390
|
+
const i = {
|
|
349
391
|
...this.config.defaultContext,
|
|
350
|
-
...
|
|
392
|
+
...e == null ? void 0 : e.context
|
|
351
393
|
};
|
|
352
|
-
for (const
|
|
353
|
-
|
|
394
|
+
for (const t of this.providerConfigs)
|
|
395
|
+
this.shouldCallMethod(t, "pageView") && t.provider.pageView(r, i);
|
|
354
396
|
}
|
|
355
397
|
/**
|
|
356
398
|
* Tracks when a user leaves a page from the server side.
|
|
357
|
-
*
|
|
399
|
+
*
|
|
358
400
|
* Server-side page leave tracking is less common than client-side but can be
|
|
359
401
|
* useful in certain scenarios like tracking session timeouts, or when combined
|
|
360
402
|
* with server-side session management.
|
|
361
|
-
*
|
|
403
|
+
*
|
|
362
404
|
* Note: Not all analytics providers support page leave events. The method
|
|
363
405
|
* will only call providers that implement the pageLeave method.
|
|
364
|
-
*
|
|
406
|
+
*
|
|
365
407
|
* @param properties Optional properties to include with the page leave event
|
|
366
408
|
* @param options Optional configuration including context
|
|
367
409
|
* @param options.context Additional context for this page leave
|
|
368
|
-
*
|
|
410
|
+
*
|
|
369
411
|
* @example
|
|
370
412
|
* ```typescript
|
|
371
413
|
* // Basic page leave tracking
|
|
372
414
|
* analytics.pageLeave();
|
|
373
415
|
* ```
|
|
374
|
-
*
|
|
416
|
+
*
|
|
375
417
|
* @example
|
|
376
418
|
* ```typescript
|
|
377
419
|
* // Page leave with session context
|
|
@@ -392,63 +434,63 @@ class v {
|
|
|
392
434
|
* }
|
|
393
435
|
* });
|
|
394
436
|
* ```
|
|
395
|
-
*
|
|
437
|
+
*
|
|
396
438
|
* @example
|
|
397
439
|
* ```typescript
|
|
398
440
|
* // In a session cleanup job
|
|
399
441
|
* async function cleanupExpiredSessions() {
|
|
400
442
|
* const expiredSessions = await getExpiredSessions();
|
|
401
|
-
*
|
|
443
|
+
*
|
|
402
444
|
* for (const session of expiredSessions) {
|
|
403
445
|
* analytics.pageLeave({
|
|
404
446
|
* sessionId: session.id,
|
|
405
447
|
* duration: session.duration,
|
|
406
448
|
* reason: 'expired'
|
|
407
449
|
* });
|
|
408
|
-
*
|
|
450
|
+
*
|
|
409
451
|
* await removeSession(session.id);
|
|
410
452
|
* }
|
|
411
453
|
* }
|
|
412
454
|
* ```
|
|
413
455
|
*/
|
|
414
|
-
pageLeave(
|
|
456
|
+
pageLeave(r, e) {
|
|
415
457
|
if (!this.initialized) return;
|
|
416
|
-
const
|
|
458
|
+
const i = {
|
|
417
459
|
...this.config.defaultContext,
|
|
418
|
-
...
|
|
460
|
+
...e == null ? void 0 : e.context
|
|
419
461
|
};
|
|
420
|
-
for (const
|
|
421
|
-
|
|
462
|
+
for (const t of this.providerConfigs)
|
|
463
|
+
this.shouldCallMethod(t, "pageLeave") && t.provider.pageLeave && t.provider.pageLeave(r, i);
|
|
422
464
|
}
|
|
423
465
|
/**
|
|
424
466
|
* Shuts down all analytics providers and flushes pending events.
|
|
425
|
-
*
|
|
467
|
+
*
|
|
426
468
|
* This method is crucial for server environments, especially serverless functions,
|
|
427
469
|
* as it ensures all events are sent before the process terminates. Some providers
|
|
428
470
|
* batch events and need an explicit flush to send them.
|
|
429
|
-
*
|
|
471
|
+
*
|
|
430
472
|
* Always call this method before your server shuts down or before a serverless
|
|
431
473
|
* function completes execution.
|
|
432
|
-
*
|
|
474
|
+
*
|
|
433
475
|
* @returns Promise that resolves when all providers have been shut down
|
|
434
|
-
*
|
|
476
|
+
*
|
|
435
477
|
* @example
|
|
436
478
|
* ```typescript
|
|
437
479
|
* // Basic shutdown
|
|
438
480
|
* await analytics.shutdown();
|
|
439
481
|
* ```
|
|
440
|
-
*
|
|
482
|
+
*
|
|
441
483
|
* @example
|
|
442
484
|
* ```typescript
|
|
443
485
|
* // In a serverless function
|
|
444
486
|
* export async function handler(event, context) {
|
|
445
487
|
* const analytics = new ServerAnalytics({ providers: [] });
|
|
446
488
|
* analytics.initialize();
|
|
447
|
-
*
|
|
489
|
+
*
|
|
448
490
|
* try {
|
|
449
491
|
* // Process the event
|
|
450
492
|
* await processEvent(event);
|
|
451
|
-
*
|
|
493
|
+
*
|
|
452
494
|
* // Track completion
|
|
453
495
|
* await analytics.track('function_completed', {
|
|
454
496
|
* duration: Date.now() - startTime,
|
|
@@ -463,20 +505,20 @@ class v {
|
|
|
463
505
|
* // Always shutdown to flush events
|
|
464
506
|
* await analytics.shutdown();
|
|
465
507
|
* }
|
|
466
|
-
*
|
|
508
|
+
*
|
|
467
509
|
* return { statusCode: 200 };
|
|
468
510
|
* }
|
|
469
511
|
* ```
|
|
470
|
-
*
|
|
512
|
+
*
|
|
471
513
|
* @example
|
|
472
514
|
* ```typescript
|
|
473
515
|
* // In an Express.js server
|
|
474
516
|
* const server = app.listen(3000);
|
|
475
|
-
*
|
|
517
|
+
*
|
|
476
518
|
* // Graceful shutdown
|
|
477
519
|
* process.on('SIGTERM', async () => {
|
|
478
520
|
* console.log('Shutting down gracefully...');
|
|
479
|
-
*
|
|
521
|
+
*
|
|
480
522
|
* server.close(async () => {
|
|
481
523
|
* // Flush analytics events before exit
|
|
482
524
|
* await analytics.shutdown();
|
|
@@ -484,45 +526,45 @@ class v {
|
|
|
484
526
|
* });
|
|
485
527
|
* });
|
|
486
528
|
* ```
|
|
487
|
-
*
|
|
529
|
+
*
|
|
488
530
|
* @example
|
|
489
531
|
* ```typescript
|
|
490
532
|
* // With Vercel's waitUntil
|
|
491
533
|
* import { waitUntil } from '@vercel/functions';
|
|
492
|
-
*
|
|
534
|
+
*
|
|
493
535
|
* export default async function handler(req, res) {
|
|
494
536
|
* // Process request
|
|
495
537
|
* const result = await processRequest(req);
|
|
496
|
-
*
|
|
538
|
+
*
|
|
497
539
|
* // Track in background without blocking response
|
|
498
540
|
* waitUntil(
|
|
499
541
|
* analytics.track('api_request', { endpoint: req.url })
|
|
500
542
|
* .then(() => analytics.shutdown())
|
|
501
543
|
* );
|
|
502
|
-
*
|
|
544
|
+
*
|
|
503
545
|
* return res.json(result);
|
|
504
546
|
* }
|
|
505
547
|
* ```
|
|
506
548
|
*/
|
|
507
549
|
async shutdown() {
|
|
508
|
-
const
|
|
509
|
-
await Promise.all(
|
|
550
|
+
const r = this.providerConfigs.map((e) => "shutdown" in e.provider && typeof e.provider.shutdown == "function" ? e.provider.shutdown() : Promise.resolve());
|
|
551
|
+
await Promise.all(r);
|
|
510
552
|
}
|
|
511
|
-
getCategoryFromEventName(
|
|
512
|
-
const
|
|
513
|
-
return
|
|
553
|
+
getCategoryFromEventName(r) {
|
|
554
|
+
const e = r.split("_");
|
|
555
|
+
return e.length > 1 && e[0] ? e[0] : "engagement";
|
|
514
556
|
}
|
|
515
557
|
}
|
|
516
|
-
function g(
|
|
517
|
-
const
|
|
518
|
-
providers:
|
|
519
|
-
debug:
|
|
520
|
-
enabled:
|
|
521
|
-
},
|
|
522
|
-
return
|
|
558
|
+
function g(a) {
|
|
559
|
+
const r = {
|
|
560
|
+
providers: a.providers || [],
|
|
561
|
+
debug: a.debug,
|
|
562
|
+
enabled: a.enabled
|
|
563
|
+
}, e = new v(r);
|
|
564
|
+
return e.initialize(), e;
|
|
523
565
|
}
|
|
524
566
|
export {
|
|
525
|
-
|
|
567
|
+
x as BaseAnalyticsProvider,
|
|
526
568
|
w as PostHogServerProvider,
|
|
527
569
|
v as ServerAnalytics,
|
|
528
570
|
g as createServerAnalytics
|