@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.
@@ -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>;
@@ -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
- delete t.email, Object.keys(t).length > 0 && this.bento.updateFields(t);
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("Reset user session - Note: Bento doesn't have a native reset method");
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) ?? 5e3, 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", () => {
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 || (this.flushTimer = setTimeout(() => {
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';
@@ -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", { userId: i, traits: e });
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
- delete h.email, this.client.V1.addSubscriber({
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("Skipping event - missing required IP or user-agent from context", {
196
- hasIp: !!h,
197
- hasUserAgent: !!s,
198
- event: i.action
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) && { screen_width: e.device.screen.width },
209
- ...((z = (P = e == null ? void 0 : e.device) == null ? void 0 : P.screen) == null ? void 0 : z.height) && { screen_height: e.device.screen.height },
210
- ...((A = (B = e == null ? void 0 : e.device) == null ? void 0 : B.viewport) == null ? void 0 : A.width) && { sec_ch_viewport_width: String(e.device.viewport.width) },
211
- ...((F = e == null ? void 0 : e.device) == null ? void 0 : F.language) && { accept_language: e.device.language },
212
- ...((v = e == null ? void 0 : e.device) == null ? void 0 : v.type) && { sec_ch_ua_mobile: e.device.type === "mobile" || e.device.type === "tablet" ? "?1" : "?0" },
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("Skipping pageView - missing required IP or user-agent from context", {
240
- hasIp: !!h,
241
- hasUserAgent: !!s
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) && { screen_width: e.device.screen.width },
252
- ...((E = (_ = e == null ? void 0 : e.device) == null ? void 0 : _.screen) == null ? void 0 : E.height) && { screen_height: e.device.screen.height },
253
- ...((z = (P = e == null ? void 0 : e.device) == null ? void 0 : P.viewport) == null ? void 0 : z.width) && { sec_ch_viewport_width: String(e.device.viewport.width) },
254
- ...((B = e == null ? void 0 : e.device) == null ? void 0 : B.language) && { accept_language: e.device.language },
255
- ...((A = e == null ? void 0 : e.device) == null ? void 0 : A.type) && { sec_ch_ua_mobile: e.device.type === "mobile" || e.device.type === "tablet" ? "?1" : "?0" },
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 u = Object.defineProperty;
2
- var o = (i, e, r) => e in i ? u(i, e, { enumerable: !0, configurable: !0, writable: !0, value: r }) : i[e] = r;
3
- var s = (i, e, r) => o(i, typeof e != "symbol" ? e + "" : e, r);
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 z } from "./base.provider-AfFL5W_P.js";
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(e) {
38
- s(this, "providers", []);
39
- s(this, "config");
40
- s(this, "initialized", !1);
41
- this.config = e, this.providers = e.providers;
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 e of this.providers)
82
- e.initialize();
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(e, r) {
133
- for (const t of this.providers)
134
- t.identify(e, r);
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(e, r, t) {
258
- var n;
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 a = {
264
- action: e,
265
- category: this.getCategoryFromEventName(e),
266
- properties: r,
305
+ const t = {
306
+ action: r,
307
+ category: this.getCategoryFromEventName(r),
308
+ properties: e,
267
309
  timestamp: Date.now(),
268
- userId: t == null ? void 0 : t.userId,
269
- sessionId: t == null ? void 0 : t.sessionId
270
- }, d = {
310
+ userId: i == null ? void 0 : i.userId,
311
+ sessionId: i == null ? void 0 : i.sessionId
312
+ }, n = {
271
313
  ...this.config.defaultContext,
272
- ...t == null ? void 0 : t.context,
273
- user: (t == null ? void 0 : t.user) || ((n = t == null ? void 0 : t.context) == null ? void 0 : n.user)
274
- }, l = this.providers.map(async (c) => {
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 c.track(a, d);
277
- } catch (f) {
318
+ await s.provider.track(t, n);
319
+ } catch (c) {
278
320
  console.error(
279
- `[Analytics] Provider ${c.name} failed to track event:`,
280
- f
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(e, r) {
388
+ pageView(r, e) {
347
389
  if (!this.initialized) return;
348
- const t = {
390
+ const i = {
349
391
  ...this.config.defaultContext,
350
- ...r == null ? void 0 : r.context
392
+ ...e == null ? void 0 : e.context
351
393
  };
352
- for (const a of this.providers)
353
- a.pageView(e, t);
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(e, r) {
456
+ pageLeave(r, e) {
415
457
  if (!this.initialized) return;
416
- const t = {
458
+ const i = {
417
459
  ...this.config.defaultContext,
418
- ...r == null ? void 0 : r.context
460
+ ...e == null ? void 0 : e.context
419
461
  };
420
- for (const a of this.providers)
421
- a.pageLeave && a.pageLeave(e, t);
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 e = this.providers.map((r) => "shutdown" in r && typeof r.shutdown == "function" ? r.shutdown() : Promise.resolve());
509
- await Promise.all(e);
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(e) {
512
- const r = e.split("_");
513
- return r.length > 1 && r[0] ? r[0] : "engagement";
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(i) {
517
- const e = {
518
- providers: i.providers || [],
519
- debug: i.debug,
520
- enabled: i.enabled
521
- }, r = new v(e);
522
- return r.initialize(), r;
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
- z as BaseAnalyticsProvider,
567
+ x as BaseAnalyticsProvider,
526
568
  w as PostHogServerProvider,
527
569
  v as ServerAnalytics,
528
570
  g as createServerAnalytics
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stacksee/analytics",
3
- "version": "0.9.8",
3
+ "version": "0.10.0",
4
4
  "description": "A highly typed, provider-agnostic analytics library for TypeScript applications",
5
5
  "type": "module",
6
6
  "exports": {