@stacksee/analytics 0.9.8 → 0.11.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.
@@ -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 providers;
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 providers;
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 u = Object.defineProperty;
2
- var h = (t, e, i) => e in t ? u(t, e, { enumerable: !0, configurable: !0, writable: !0, value: i }) : t[e] = i;
3
- var s = (t, e, i) => h(t, typeof e != "symbol" ? e + "" : e, i);
4
- import { i as p } from "./client-DTHZYkxx.js";
5
- import { P as b } from "./client-DTHZYkxx.js";
6
- import { B as C } from "./base.provider-AfFL5W_P.js";
7
- class f {
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, "providers", []);
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.providers = e.providers, e.defaultContext && (this.context = { ...e.defaultContext }), this.sessionId = this.generateSessionId();
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 (p() && !this.initialized)
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.providers.map(
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.providers)
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
- }, o = {
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
- }, l = this.providers.map(async (d) => {
309
+ }, o = this.providerConfigs.filter((d) => this.shouldCallMethod(d, "track")).map(async (d) => {
268
310
  try {
269
- await d.track(r, o);
270
- } catch (c) {
311
+ await d.provider.track(r, n);
312
+ } catch (h) {
271
313
  console.error(
272
- `[Analytics] Provider ${d.name} failed to track event:`,
273
- c
314
+ `[Analytics] Provider ${d.provider.name} failed to track event:`,
315
+ h
274
316
  );
275
317
  }
276
318
  });
277
- await Promise.all(l);
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.providers)
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("[Analytics] Failed to initialize during pageLeave:", i);
451
+ console.error(
452
+ "[Analytics] Failed to initialize during pageLeave:",
453
+ i
454
+ );
410
455
  });
411
- for (const i of this.providers)
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.providers)
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, o;
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 || ((o = this.context.page) == null ? void 0 : o.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 n = null;
618
+ let a = null;
574
619
  function v(t) {
575
- if (n)
576
- return console.warn("[Analytics] Already initialized"), n;
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 n = new f(e), n.initialize().catch((i) => {
627
+ return a = new p(e), a.initialize().catch((i) => {
583
628
  console.error("[Analytics] Failed to initialize:", i);
584
- }), n;
629
+ }), a;
585
630
  }
586
- function a() {
587
- if (!n)
631
+ function l() {
632
+ if (!a)
588
633
  throw new Error(
589
634
  "[Analytics] Not initialized. Call createAnalytics() first."
590
635
  );
591
- return n;
592
- }
593
- function y(t, e) {
594
- return a().track(t, e);
636
+ return a;
595
637
  }
596
638
  function w(t, e) {
597
- a().identify(t, e);
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
- a().pageView(t);
645
+ l().pageView(t);
601
646
  }
602
647
  function z(t) {
603
- a().pageLeave(t);
648
+ l().pageLeave(t);
604
649
  }
605
- function I() {
606
- a().reset();
650
+ function C() {
651
+ l().reset();
607
652
  }
608
653
  export {
609
- C as BaseAnalyticsProvider,
610
- f as BrowserAnalytics,
611
- b as PostHogClientProvider,
654
+ k as BaseAnalyticsProvider,
655
+ p as BrowserAnalytics,
656
+ P as PostHogClientProvider,
612
657
  v as createAnalytics,
613
658
  v as createClientAnalytics,
614
- a as getAnalytics,
615
- w as identify,
659
+ l as getAnalytics,
660
+ y as identify,
616
661
  z as pageLeave,
617
662
  x as pageView,
618
- I as reset,
619
- y as track
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: AnalyticsProvider[];
121
+ providers: ProviderConfigOrProvider[];
73
122
  debug?: boolean;
74
123
  enabled?: boolean;
75
124
  defaultContext?: Partial<EventContext>;