@stacksee/analytics 0.4.6 → 0.7.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.
@@ -0,0 +1,90 @@
1
+ var o = Object.defineProperty;
2
+ var d = (a, e, s) => e in a ? o(a, e, { enumerable: !0, configurable: !0, writable: !0, value: s }) : a[e] = s;
3
+ var g = (a, e, s) => d(a, typeof e != "symbol" ? e + "" : e, s);
4
+ import { B as l } from "./base.provider-AfFL5W_P.js";
5
+ function t() {
6
+ return typeof window < "u" && typeof window.document < "u";
7
+ }
8
+ class n extends l {
9
+ constructor(s) {
10
+ super({ debug: s.debug, enabled: s.enabled });
11
+ g(this, "name", "PostHog-Client");
12
+ g(this, "posthog");
13
+ g(this, "initialized", !1);
14
+ g(this, "config");
15
+ this.config = s;
16
+ }
17
+ async initialize() {
18
+ if (this.isEnabled() && !this.initialized) {
19
+ if (!t()) {
20
+ this.log("Skipping initialization - not in browser environment");
21
+ return;
22
+ }
23
+ if (!this.config.token || typeof this.config.token != "string")
24
+ throw new Error("PostHog requires a token");
25
+ try {
26
+ const { default: s } = await import("posthog-js"), { token: i, debug: r, ...h } = this.config;
27
+ s.init(i, {
28
+ ...h,
29
+ debug: r ?? this.debug
30
+ }), this.posthog = s, this.initialized = !0, this.log("Initialized successfully", this.config);
31
+ } catch (s) {
32
+ throw console.error("[PostHog-Client] Failed to initialize:", s), s;
33
+ }
34
+ }
35
+ }
36
+ identify(s, i) {
37
+ !this.isEnabled() || !this.initialized || !this.posthog || (this.posthog.identify(s, i), this.log("Identified user", { userId: s, traits: i }));
38
+ }
39
+ track(s, i) {
40
+ var h, p;
41
+ if (!this.isEnabled() || !this.initialized || !this.posthog) return;
42
+ const r = {
43
+ ...s.properties,
44
+ category: s.category,
45
+ timestamp: s.timestamp || Date.now(),
46
+ ...s.userId && { userId: s.userId },
47
+ ...s.sessionId && { sessionId: s.sessionId },
48
+ ...(i == null ? void 0 : i.page) && { $current_url: i.page.path },
49
+ ...(i == null ? void 0 : i.device) && { device: i.device },
50
+ ...(i == null ? void 0 : i.utm) && { utm: i.utm },
51
+ // Include user email and traits as regular event properties
52
+ ...((h = i == null ? void 0 : i.user) == null ? void 0 : h.email) && { user_email: i.user.email },
53
+ ...((p = i == null ? void 0 : i.user) == null ? void 0 : p.traits) && { user_traits: i.user.traits }
54
+ };
55
+ this.posthog.capture(s.action, r), this.log("Tracked event", { event: s, context: i });
56
+ }
57
+ pageView(s, i) {
58
+ if (!this.isEnabled() || !this.initialized || !this.posthog || !t())
59
+ return;
60
+ const r = {
61
+ ...s,
62
+ ...(i == null ? void 0 : i.page) && {
63
+ path: i.page.path,
64
+ title: i.page.title,
65
+ referrer: i.page.referrer
66
+ }
67
+ };
68
+ this.posthog.capture("$pageview", r), this.log("Tracked page view", { properties: s, context: i });
69
+ }
70
+ pageLeave(s, i) {
71
+ if (!this.isEnabled() || !this.initialized || !this.posthog || !t())
72
+ return;
73
+ const r = {
74
+ ...s,
75
+ ...(i == null ? void 0 : i.page) && {
76
+ path: i.page.path,
77
+ title: i.page.title,
78
+ referrer: i.page.referrer
79
+ }
80
+ };
81
+ this.posthog.capture("$pageleave", r), this.log("Tracked page leave", { properties: s, context: i });
82
+ }
83
+ reset() {
84
+ !this.isEnabled() || !this.initialized || !this.posthog || !t() || (this.posthog.reset(), this.log("Reset user session"));
85
+ }
86
+ }
87
+ export {
88
+ n as P,
89
+ t as i
90
+ };
package/dist/client.d.ts CHANGED
@@ -1,7 +1,6 @@
1
1
  import { BrowserAnalytics } from './adapters/client/browser-analytics.js';
2
2
  import { AnalyticsProvider } from './core/events/types.js';
3
3
  import { EventMapFromCollection } from './core/events/index.js';
4
- type DefaultEventMap = Record<string, Record<string, unknown>>;
5
4
  export interface ClientAnalyticsConfig {
6
5
  providers?: AnalyticsProvider[];
7
6
  debug?: boolean;
@@ -35,12 +34,12 @@ export interface ClientAnalyticsConfig {
35
34
  * });
36
35
  * ```
37
36
  */
38
- export declare function createClientAnalytics<TEvents = never>(config: ClientAnalyticsConfig): BrowserAnalytics<EventMapFromCollection<TEvents>>;
37
+ export declare function createClientAnalytics<TEvents = never, TUserTraits extends Record<string, unknown> = Record<string, unknown>>(config: ClientAnalyticsConfig): BrowserAnalytics<EventMapFromCollection<TEvents>, TUserTraits>;
39
38
  export { createClientAnalytics as createAnalytics };
40
39
  /**
41
40
  * Get the current analytics instance
42
41
  */
43
- export declare function getAnalytics(): BrowserAnalytics<DefaultEventMap>;
42
+ export declare function getAnalytics(): BrowserAnalytics<Record<string, Record<string, unknown>>, Record<string, unknown>>;
44
43
  /**
45
44
  * Convenience function to track events
46
45
  */
package/dist/client.js CHANGED
@@ -1,10 +1,10 @@
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 n = (t, e, i) => u(t, typeof e != "symbol" ? e + "" : e, i);
4
- import { i as h } from "./client-RZPcOfAk.js";
5
- import { P } from "./client-RZPcOfAk.js";
6
- import { B as O } from "./base.provider-AfFL5W_P.js";
7
- class p {
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 {
8
8
  /**
9
9
  * Creates a new BrowserAnalytics instance for client-side event tracking.
10
10
  *
@@ -36,12 +36,13 @@ class p {
36
36
  * ```
37
37
  */
38
38
  constructor(e) {
39
- n(this, "providers", []);
40
- n(this, "context", {});
41
- n(this, "userId");
42
- n(this, "sessionId");
43
- n(this, "initialized", !1);
44
- n(this, "initializePromise");
39
+ s(this, "providers", []);
40
+ s(this, "context", {});
41
+ s(this, "userId");
42
+ s(this, "sessionId");
43
+ s(this, "userTraits");
44
+ s(this, "initialized", !1);
45
+ s(this, "initializePromise");
45
46
  this.providers = e.providers, e.defaultContext && (this.context = { ...e.defaultContext }), this.sessionId = this.generateSessionId();
46
47
  }
47
48
  /**
@@ -75,7 +76,7 @@ class p {
75
76
  * ```
76
77
  */
77
78
  async initialize() {
78
- if (h() && !this.initialized)
79
+ if (p() && !this.initialized)
79
80
  return this.initializePromise ? this.initializePromise : (this.initializePromise = this._doInitialize(), this.initializePromise);
80
81
  }
81
82
  async _doInitialize() {
@@ -100,26 +101,31 @@ class p {
100
101
  }
101
102
  /**
102
103
  * Identifies a user with optional traits.
103
- *
104
+ *
104
105
  * Associates subsequent events with the specified user ID and optionally
105
106
  * sets user properties. This method should be called when a user logs in
106
107
  * or when you want to associate events with a known user.
107
- *
108
+ *
109
+ * **User Context (New):** User data (userId, email, traits) is automatically stored
110
+ * and included in all subsequent `track()` calls. This makes it easy for providers
111
+ * like Loops, Customer.io, or Intercom to access user information without passing
112
+ * it manually each time. The data is cleared when `reset()` is called (e.g., on logout).
113
+ *
108
114
  * The method automatically ensures initialization but doesn't block execution
109
115
  * if initialization is still in progress.
110
- *
116
+ *
111
117
  * @param userId Unique identifier for the user (e.g., database ID, email)
112
- * @param traits Optional user properties and characteristics
113
- *
118
+ * @param traits Optional user properties and characteristics (email, name, plan, etc.)
119
+ *
114
120
  * @example
115
121
  * ```typescript
116
122
  * // Basic user identification
117
123
  * analytics.identify('user-123');
118
124
  * ```
119
- *
125
+ *
120
126
  * @example
121
127
  * ```typescript
122
- * // Identify with user traits
128
+ * // Identify with user traits (recommended - enables email-based providers)
123
129
  * analytics.identify('user-123', {
124
130
  * email: 'john@example.com',
125
131
  * name: 'John Doe',
@@ -130,24 +136,38 @@ class p {
130
136
  * notifications: false
131
137
  * }
132
138
  * });
139
+ *
140
+ * // Now all subsequent track() calls automatically include user context
141
+ * analytics.track('button_clicked', { buttonId: 'checkout' });
142
+ * // Providers receive: context.user = { userId: 'user-123', email: 'john@example.com', traits: {...} }
133
143
  * ```
134
- *
144
+ *
135
145
  * @example
136
146
  * ```typescript
137
147
  * // In a login handler
138
148
  * async function handleLogin(email: string, password: string) {
139
149
  * const user = await login(email, password);
140
- *
150
+ *
151
+ * // Identify user with full traits
141
152
  * analytics.identify(user.id, {
142
153
  * email: user.email,
143
154
  * name: user.name,
155
+ * plan: user.plan,
156
+ * company: user.company,
144
157
  * lastLogin: new Date().toISOString()
145
158
  * });
159
+ *
160
+ * // All subsequent events now include this user context automatically
161
+ * }
162
+ *
163
+ * // In a logout handler - clear user context
164
+ * async function handleLogout() {
165
+ * analytics.reset(); // Clears userId and traits
146
166
  * }
147
167
  * ```
148
168
  */
149
169
  identify(e, i) {
150
- this.userId = e, this.ensureInitialized().catch((r) => {
170
+ this.userId = e, this.userTraits = i, this.ensureInitialized().catch((r) => {
151
171
  console.error("[Analytics] Failed to initialize during identify:", r);
152
172
  });
153
173
  for (const r of this.providers)
@@ -155,15 +175,19 @@ class p {
155
175
  }
156
176
  /**
157
177
  * Tracks a custom event with properties.
158
- *
178
+ *
159
179
  * This is the main method for tracking user interactions and business events.
160
180
  * The method ensures initialization before tracking and sends the event to all
161
181
  * configured providers. Events are enriched with context information like
162
182
  * timestamp, user ID, session ID, and browser context.
163
- *
183
+ *
184
+ * **User Context (New):** If `identify()` was called previously, user data (userId,
185
+ * email, traits) is automatically included in the event context sent to all providers.
186
+ * This happens transparently - you don't need to pass user data manually.
187
+ *
164
188
  * If providers are configured, the method waits for all providers to complete
165
189
  * tracking. Failed providers don't prevent others from succeeding.
166
- *
190
+ *
167
191
  * @param eventName Name of the event to track (must match your event definitions)
168
192
  * @param properties Event-specific properties and data
169
193
  * @returns Promise that resolves when tracking is complete for all providers
@@ -176,7 +200,20 @@ class p {
176
200
  * page: '/landing'
177
201
  * });
178
202
  * ```
179
- *
203
+ *
204
+ * @example
205
+ * ```typescript
206
+ * // User context is automatically included after identify()
207
+ * analytics.identify('user-123', {
208
+ * email: 'user@example.com',
209
+ * plan: 'pro'
210
+ * });
211
+ *
212
+ * // Now all events automatically include user context
213
+ * analytics.track('button_clicked', { buttonId: 'checkout' });
214
+ * // Providers receive: context.user = { userId: 'user-123', email: 'user@example.com', traits: {...} }
215
+ * ```
216
+ *
180
217
  * @example
181
218
  * ```typescript
182
219
  * // Track a purchase event
@@ -191,14 +228,14 @@ class p {
191
228
  * paymentMethod: 'credit_card'
192
229
  * });
193
230
  * ```
194
- *
231
+ *
195
232
  * @example
196
233
  * ```typescript
197
234
  * // Fire-and-forget for non-critical events (client-side typical usage)
198
235
  * analytics.track('feature_viewed', { feature: 'dashboard' });
199
236
  * // Don't await - let it track in the background
200
237
  * ```
201
- *
238
+ *
202
239
  * @example
203
240
  * ```typescript
204
241
  * // Error handling
@@ -220,17 +257,24 @@ class p {
220
257
  timestamp: Date.now(),
221
258
  userId: this.userId,
222
259
  sessionId: this.sessionId
223
- }, o = this.providers.map(async (d) => {
260
+ }, o = {
261
+ ...this.context,
262
+ user: this.userId || this.userTraits ? {
263
+ userId: this.userId,
264
+ email: this.userTraits && "email" in this.userTraits ? this.userTraits.email : void 0,
265
+ traits: this.userTraits
266
+ } : void 0
267
+ }, l = this.providers.map(async (d) => {
224
268
  try {
225
- await d.track(r, this.context);
226
- } catch (l) {
269
+ await d.track(r, o);
270
+ } catch (c) {
227
271
  console.error(
228
272
  `[Analytics] Provider ${d.name} failed to track event:`,
229
- l
273
+ c
230
274
  );
231
275
  }
232
276
  });
233
- await Promise.all(o);
277
+ await Promise.all(l);
234
278
  }
235
279
  /**
236
280
  * Tracks a page view event.
@@ -420,7 +464,7 @@ class p {
420
464
  * ```
421
465
  */
422
466
  reset() {
423
- this.userId = void 0, this.sessionId = this.generateSessionId();
467
+ this.userId = void 0, this.userTraits = void 0, this.sessionId = this.generateSessionId();
424
468
  for (const e of this.providers)
425
469
  e.reset();
426
470
  }
@@ -526,53 +570,51 @@ class p {
526
570
  return e.indexOf("Chrome") !== -1 ? "Chrome" : e.indexOf("Safari") !== -1 ? "Safari" : e.indexOf("Firefox") !== -1 ? "Firefox" : e.indexOf("Edge") !== -1 ? "Edge" : "Unknown";
527
571
  }
528
572
  }
529
- let s = null;
530
- function m(t) {
531
- if (s)
532
- return console.warn("[Analytics] Already initialized"), s;
573
+ let n = null;
574
+ function v(t) {
575
+ if (n)
576
+ return console.warn("[Analytics] Already initialized"), n;
533
577
  const e = {
534
578
  providers: t.providers || [],
535
579
  debug: t.debug,
536
580
  enabled: t.enabled
537
581
  };
538
- return s = new p(
539
- e
540
- ), s.initialize().catch((i) => {
582
+ return n = new f(e), n.initialize().catch((i) => {
541
583
  console.error("[Analytics] Failed to initialize:", i);
542
- }), s;
584
+ }), n;
543
585
  }
544
586
  function a() {
545
- if (!s)
587
+ if (!n)
546
588
  throw new Error(
547
589
  "[Analytics] Not initialized. Call createAnalytics() first."
548
590
  );
549
- return s;
591
+ return n;
550
592
  }
551
- function v(t, e) {
593
+ function y(t, e) {
552
594
  return a().track(t, e);
553
595
  }
554
- function y(t, e) {
596
+ function w(t, e) {
555
597
  a().identify(t, e);
556
598
  }
557
- function w(t) {
599
+ function x(t) {
558
600
  a().pageView(t);
559
601
  }
560
602
  function z(t) {
561
603
  a().pageLeave(t);
562
604
  }
563
- function x() {
605
+ function I() {
564
606
  a().reset();
565
607
  }
566
608
  export {
567
- O as BaseAnalyticsProvider,
568
- p as BrowserAnalytics,
569
- P as PostHogClientProvider,
570
- m as createAnalytics,
571
- m as createClientAnalytics,
609
+ C as BaseAnalyticsProvider,
610
+ f as BrowserAnalytics,
611
+ b as PostHogClientProvider,
612
+ v as createAnalytics,
613
+ v as createClientAnalytics,
572
614
  a as getAnalytics,
573
- y as identify,
615
+ w as identify,
574
616
  z as pageLeave,
575
- w as pageView,
576
- x as reset,
577
- v as track
617
+ x as pageView,
618
+ I as reset,
619
+ y as track
578
620
  };
@@ -8,7 +8,13 @@ export interface BaseEvent {
8
8
  sessionId?: string;
9
9
  properties?: Record<string, unknown>;
10
10
  }
11
- export interface EventContext {
11
+ export interface UserContext<TTraits extends Record<string, unknown> = Record<string, unknown>> {
12
+ userId?: string;
13
+ email?: string;
14
+ traits?: TTraits;
15
+ }
16
+ export interface EventContext<TTraits extends Record<string, unknown> = Record<string, unknown>> {
17
+ user?: UserContext<TTraits>;
12
18
  page?: {
13
19
  path: string;
14
20
  title?: string;