@stacksee/analytics 0.4.3 → 0.4.4

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,577 +0,0 @@
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 h } from "./environment-Bnc8FqHv.js";
5
- class p {
6
- /**
7
- * Creates a new BrowserAnalytics instance for client-side event tracking.
8
- *
9
- * Automatically generates a session ID and sets up the analytics context.
10
- * The instance will be ready to track events once initialized.
11
- *
12
- * @param config Analytics configuration including providers and default context
13
- * @param config.providers Array of analytics provider instances (e.g., PostHogClientProvider)
14
- * @param config.defaultContext Optional default context to include with all events
15
- *
16
- * @example
17
- * ```typescript
18
- * import { BrowserAnalytics } from '@stacksee/analytics/client';
19
- * import { PostHogClientProvider } from '@stacksee/analytics/providers/posthog';
20
- *
21
- * const analytics = new BrowserAnalytics({
22
- * providers: [
23
- * new PostHogClientProvider({
24
- * apiKey: 'your-posthog-api-key',
25
- * host: 'https://app.posthog.com'
26
- * })
27
- * ],
28
- * defaultContext: {
29
- * app: { version: '1.0.0' }
30
- * }
31
- * });
32
- *
33
- * await analytics.initialize();
34
- * ```
35
- */
36
- constructor(e) {
37
- s(this, "providers", []);
38
- s(this, "context", {});
39
- s(this, "userId");
40
- s(this, "sessionId");
41
- s(this, "initialized", !1);
42
- s(this, "initializePromise");
43
- this.providers = e.providers, e.defaultContext && (this.context = { ...e.defaultContext }), this.sessionId = this.generateSessionId();
44
- }
45
- /**
46
- * Initializes all analytics providers and sets up browser context.
47
- *
48
- * This method must be called before tracking events. It initializes all configured
49
- * providers and automatically captures browser context including page information,
50
- * device type, OS, and browser details.
51
- *
52
- * The method is safe to call multiple times and will not re-initialize if already done.
53
- * If called while initialization is in progress, it returns the existing promise.
54
- *
55
- * @returns Promise that resolves when initialization is complete
56
- *
57
- * @example
58
- * ```typescript
59
- * const analytics = new BrowserAnalytics({ providers: [] });
60
- *
61
- * // Initialize before tracking events
62
- * await analytics.initialize();
63
- *
64
- * // Now ready to track events
65
- * analytics.track('page_viewed', { page: '/dashboard' });
66
- * ```
67
- *
68
- * @example
69
- * ```typescript
70
- * // Safe to call multiple times
71
- * await analytics.initialize(); // First call does the work
72
- * await analytics.initialize(); // Subsequent calls return immediately
73
- * ```
74
- */
75
- async initialize() {
76
- if (h() && !this.initialized)
77
- return this.initializePromise ? this.initializePromise : (this.initializePromise = this._doInitialize(), this.initializePromise);
78
- }
79
- async _doInitialize() {
80
- const e = this.providers.map(
81
- (i) => i.initialize()
82
- );
83
- await Promise.all(e), this.initialized = !0, this.updateContext({
84
- page: {
85
- path: window.location.pathname,
86
- title: document.title,
87
- referrer: document.referrer
88
- },
89
- device: {
90
- type: this.getDeviceType(),
91
- os: this.getOS(),
92
- browser: this.getBrowser()
93
- }
94
- });
95
- }
96
- async ensureInitialized() {
97
- !this.initialized && !this.initializePromise ? await this.initialize() : this.initializePromise && await this.initializePromise;
98
- }
99
- /**
100
- * Identifies a user with optional traits.
101
- *
102
- * Associates subsequent events with the specified user ID and optionally
103
- * sets user properties. This method should be called when a user logs in
104
- * or when you want to associate events with a known user.
105
- *
106
- * The method automatically ensures initialization but doesn't block execution
107
- * if initialization is still in progress.
108
- *
109
- * @param userId Unique identifier for the user (e.g., database ID, email)
110
- * @param traits Optional user properties and characteristics
111
- *
112
- * @example
113
- * ```typescript
114
- * // Basic user identification
115
- * analytics.identify('user-123');
116
- * ```
117
- *
118
- * @example
119
- * ```typescript
120
- * // Identify with user traits
121
- * analytics.identify('user-123', {
122
- * email: 'john@example.com',
123
- * name: 'John Doe',
124
- * plan: 'pro',
125
- * signupDate: '2024-01-15',
126
- * preferences: {
127
- * newsletter: true,
128
- * notifications: false
129
- * }
130
- * });
131
- * ```
132
- *
133
- * @example
134
- * ```typescript
135
- * // In a login handler
136
- * async function handleLogin(email: string, password: string) {
137
- * const user = await login(email, password);
138
- *
139
- * analytics.identify(user.id, {
140
- * email: user.email,
141
- * name: user.name,
142
- * lastLogin: new Date().toISOString()
143
- * });
144
- * }
145
- * ```
146
- */
147
- identify(e, i) {
148
- this.userId = e, this.ensureInitialized().catch((r) => {
149
- console.error("[Analytics] Failed to initialize during identify:", r);
150
- });
151
- for (const r of this.providers)
152
- r.identify(e, i);
153
- }
154
- /**
155
- * Tracks a custom event with properties.
156
- *
157
- * This is the main method for tracking user interactions and business events.
158
- * The method ensures initialization before tracking and sends the event to all
159
- * configured providers. Events are enriched with context information like
160
- * timestamp, user ID, session ID, and browser context.
161
- *
162
- * If providers are configured, the method waits for all providers to complete
163
- * tracking. Failed providers don't prevent others from succeeding.
164
- *
165
- * @param eventName Name of the event to track (must match your event definitions)
166
- * @param properties Event-specific properties and data
167
- * @returns Promise that resolves when tracking is complete for all providers
168
- *
169
- * @example
170
- * ```typescript
171
- * // Track a simple event
172
- * await analytics.track('button_clicked', {
173
- * buttonId: 'signup-cta',
174
- * page: '/landing'
175
- * });
176
- * ```
177
- *
178
- * @example
179
- * ```typescript
180
- * // Track a purchase event
181
- * await analytics.track('purchase_completed', {
182
- * orderId: 'order-123',
183
- * amount: 99.99,
184
- * currency: 'USD',
185
- * items: [
186
- * { id: 'item-1', name: 'Product A', price: 49.99 },
187
- * { id: 'item-2', name: 'Product B', price: 49.99 }
188
- * ],
189
- * paymentMethod: 'credit_card'
190
- * });
191
- * ```
192
- *
193
- * @example
194
- * ```typescript
195
- * // Fire-and-forget for non-critical events (client-side typical usage)
196
- * analytics.track('feature_viewed', { feature: 'dashboard' });
197
- * // Don't await - let it track in the background
198
- * ```
199
- *
200
- * @example
201
- * ```typescript
202
- * // Error handling
203
- * try {
204
- * await analytics.track('critical_event', { data: 'important' });
205
- * } catch (error) {
206
- * // Individual provider failures are handled internally
207
- * // This catch would only trigger for initialization failures
208
- * console.error('Failed to track event:', error);
209
- * }
210
- * ```
211
- */
212
- async track(e, i) {
213
- await this.ensureInitialized();
214
- const r = {
215
- action: e,
216
- category: this.getCategoryFromEventName(e),
217
- properties: i,
218
- timestamp: Date.now(),
219
- userId: this.userId,
220
- sessionId: this.sessionId
221
- }, o = this.providers.map(async (d) => {
222
- try {
223
- await d.track(r, this.context);
224
- } catch (l) {
225
- console.error(
226
- `[Analytics] Provider ${d.name} failed to track event:`,
227
- l
228
- );
229
- }
230
- });
231
- await Promise.all(o);
232
- }
233
- /**
234
- * Tracks a page view event.
235
- *
236
- * Automatically captures current page information (path, title, referrer) and
237
- * updates the analytics context. This method should be called when users
238
- * navigate to a new page or view.
239
- *
240
- * The method automatically ensures initialization but doesn't block execution
241
- * if initialization is still in progress.
242
- *
243
- * @param properties Optional properties to include with the page view
244
- *
245
- * @example
246
- * ```typescript
247
- * // Basic page view tracking
248
- * analytics.pageView();
249
- * ```
250
- *
251
- * @example
252
- * ```typescript
253
- * // Page view with additional properties
254
- * analytics.pageView({
255
- * category: 'product',
256
- * productId: 'prod-123',
257
- * loadTime: 1200,
258
- * source: 'organic_search'
259
- * });
260
- * ```
261
- *
262
- * @example
263
- * ```typescript
264
- * // In a SvelteKit app with automatic navigation tracking
265
- * import { afterNavigate } from '$app/navigation';
266
- *
267
- * afterNavigate(() => {
268
- * analytics.pageView({
269
- * timestamp: Date.now(),
270
- * userAgent: navigator.userAgent
271
- * });
272
- * });
273
- * ```
274
- *
275
- * @example
276
- * ```typescript
277
- * // In a React app with React Router
278
- * import { useEffect } from 'react';
279
- * import { useLocation } from 'react-router-dom';
280
- *
281
- * function usePageTracking() {
282
- * const location = useLocation();
283
- *
284
- * useEffect(() => {
285
- * analytics.pageView({
286
- * path: location.pathname,
287
- * search: location.search
288
- * });
289
- * }, [location]);
290
- * }
291
- * ```
292
- */
293
- pageView(e) {
294
- this.ensureInitialized().catch((i) => {
295
- console.error("[Analytics] Failed to initialize during pageView:", i);
296
- }), this.updateContext({
297
- page: {
298
- path: window.location.pathname,
299
- title: document.title,
300
- referrer: document.referrer
301
- }
302
- });
303
- for (const i of this.providers)
304
- i.pageView(e, this.context);
305
- }
306
- /**
307
- * Tracks when a user leaves a page.
308
- *
309
- * This method should be called before navigation to track user engagement
310
- * and session duration. It's useful for understanding how long users spend
311
- * on different pages and their navigation patterns.
312
- *
313
- * Note: Not all analytics providers support page leave events. The method
314
- * will only call providers that implement the pageLeave method.
315
- *
316
- * @param properties Optional properties to include with the page leave event
317
- *
318
- * @example
319
- * ```typescript
320
- * // Basic page leave tracking
321
- * analytics.pageLeave();
322
- * ```
323
- *
324
- * @example
325
- * ```typescript
326
- * // Page leave with engagement metrics
327
- * analytics.pageLeave({
328
- * timeOnPage: 45000, // 45 seconds
329
- * scrollDepth: 80, // percentage
330
- * interactions: 3, // number of clicks/interactions
331
- * exitIntent: true // detected exit intent
332
- * });
333
- * ```
334
- *
335
- * @example
336
- * ```typescript
337
- * // In a SvelteKit app with automatic navigation tracking
338
- * import { beforeNavigate } from '$app/navigation';
339
- *
340
- * let pageStartTime = Date.now();
341
- *
342
- * beforeNavigate(() => {
343
- * analytics.pageLeave({
344
- * duration: Date.now() - pageStartTime,
345
- * exitType: 'navigation'
346
- * });
347
- * });
348
- * ```
349
- *
350
- * @example
351
- * ```typescript
352
- * // Track page leave on browser unload
353
- * window.addEventListener('beforeunload', () => {
354
- * analytics.pageLeave({
355
- * exitType: 'browser_close',
356
- * sessionDuration: Date.now() - sessionStartTime
357
- * });
358
- * });
359
- * ```
360
- */
361
- pageLeave(e) {
362
- this.ensureInitialized().catch((i) => {
363
- console.error("[Analytics] Failed to initialize during pageLeave:", i);
364
- });
365
- for (const i of this.providers)
366
- i.pageLeave && i.pageLeave(e, this.context);
367
- }
368
- /**
369
- * Resets the analytics state, clearing user ID and generating a new session.
370
- *
371
- * This method should be called when a user logs out or when you want to
372
- * start tracking a new user session. It clears the current user ID,
373
- * generates a new session ID, and calls reset on all providers.
374
- *
375
- * Use this method to ensure user privacy and accurate session tracking
376
- * when users switch accounts or log out.
377
- *
378
- * @example
379
- * ```typescript
380
- * // Basic reset on logout
381
- * analytics.reset();
382
- * ```
383
- *
384
- * @example
385
- * ```typescript
386
- * // In a logout handler
387
- * async function handleLogout() {
388
- * // Track logout event before resetting
389
- * await analytics.track('user_logged_out', {
390
- * sessionDuration: Date.now() - sessionStartTime
391
- * });
392
- *
393
- * // Reset analytics state
394
- * analytics.reset();
395
- *
396
- * // Clear user data and redirect
397
- * clearUserData();
398
- * window.location.href = '/login';
399
- * }
400
- * ```
401
- *
402
- * @example
403
- * ```typescript
404
- * // Account switching scenario
405
- * async function switchAccount(newUserId: string) {
406
- * // Reset to clear previous user
407
- * analytics.reset();
408
- *
409
- * // Identify the new user
410
- * analytics.identify(newUserId);
411
- *
412
- * // Track account switch
413
- * analytics.track('account_switched', {
414
- * newUserId,
415
- * timestamp: Date.now()
416
- * });
417
- * }
418
- * ```
419
- */
420
- reset() {
421
- this.userId = void 0, this.sessionId = this.generateSessionId();
422
- for (const e of this.providers)
423
- e.reset();
424
- }
425
- /**
426
- * Updates the analytics context with new information.
427
- *
428
- * The context is included with all tracked events and provides additional
429
- * metadata about the user's environment, current page, device, and other
430
- * relevant information. This method merges new context with existing context.
431
- *
432
- * Context typically includes page information, device details, UTM parameters,
433
- * and custom application context.
434
- *
435
- * @param context Partial context to merge with existing context
436
- * @param context.page Page-related context (path, title, referrer)
437
- * @param context.device Device-related context (type, OS, browser)
438
- * @param context.utm UTM campaign tracking parameters
439
- * @param context.app Application-specific context
440
- *
441
- * @example
442
- * ```typescript
443
- * // Update page context
444
- * analytics.updateContext({
445
- * page: {
446
- * path: '/dashboard',
447
- * title: 'User Dashboard',
448
- * referrer: 'https://google.com'
449
- * }
450
- * });
451
- * ```
452
- *
453
- * @example
454
- * ```typescript
455
- * // Add UTM parameters from URL
456
- * const urlParams = new URLSearchParams(window.location.search);
457
- * analytics.updateContext({
458
- * utm: {
459
- * source: urlParams.get('utm_source') || undefined,
460
- * medium: urlParams.get('utm_medium') || undefined,
461
- * campaign: urlParams.get('utm_campaign') || undefined,
462
- * term: urlParams.get('utm_term') || undefined,
463
- * content: urlParams.get('utm_content') || undefined
464
- * }
465
- * });
466
- * ```
467
- *
468
- * @example
469
- * ```typescript
470
- * // Update application context
471
- * analytics.updateContext({
472
- * app: {
473
- * version: '2.1.0',
474
- * feature: 'beta-dashboard',
475
- * theme: 'dark'
476
- * },
477
- * device: {
478
- * screenWidth: window.innerWidth,
479
- * screenHeight: window.innerHeight,
480
- * timezone: Intl.DateTimeFormat().resolvedOptions().timeZone
481
- * }
482
- * });
483
- * ```
484
- */
485
- updateContext(e) {
486
- var i, r, o;
487
- this.context = {
488
- ...this.context,
489
- ...e,
490
- page: e.page ? {
491
- path: e.page.path || ((i = this.context.page) == null ? void 0 : i.path) || window.location.pathname,
492
- title: e.page.title || ((r = this.context.page) == null ? void 0 : r.title),
493
- referrer: e.page.referrer || ((o = this.context.page) == null ? void 0 : o.referrer)
494
- } : this.context.page,
495
- device: {
496
- ...this.context.device,
497
- ...e.device
498
- },
499
- utm: {
500
- ...this.context.utm,
501
- ...e.utm
502
- }
503
- };
504
- }
505
- getCategoryFromEventName(e) {
506
- const i = e.split("_");
507
- return i.length > 1 && i[0] ? i[0] : "engagement";
508
- }
509
- generateSessionId() {
510
- return `${Date.now()}-${Math.random().toString(36).substring(2, 11)}`;
511
- }
512
- getDeviceType() {
513
- const e = navigator.userAgent;
514
- return /tablet|ipad|playbook|silk/i.test(e) ? "tablet" : /mobile|iphone|ipod|android|blackberry|opera|mini|windows\sce|palm|smartphone|iemobile/i.test(
515
- e
516
- ) ? "mobile" : "desktop";
517
- }
518
- getOS() {
519
- const e = navigator.userAgent;
520
- return e.indexOf("Win") !== -1 ? "Windows" : e.indexOf("Mac") !== -1 ? "macOS" : e.indexOf("Linux") !== -1 ? "Linux" : e.indexOf("Android") !== -1 ? "Android" : e.indexOf("iOS") !== -1 ? "iOS" : "Unknown";
521
- }
522
- getBrowser() {
523
- const e = navigator.userAgent;
524
- return e.indexOf("Chrome") !== -1 ? "Chrome" : e.indexOf("Safari") !== -1 ? "Safari" : e.indexOf("Firefox") !== -1 ? "Firefox" : e.indexOf("Edge") !== -1 ? "Edge" : "Unknown";
525
- }
526
- }
527
- let n = null;
528
- function m(t) {
529
- if (n)
530
- return console.warn("[Analytics] Already initialized"), n;
531
- const e = {
532
- providers: t.providers || [],
533
- debug: t.debug,
534
- enabled: t.enabled
535
- };
536
- return n = new p(
537
- e
538
- ), n.initialize().catch((i) => {
539
- console.error("[Analytics] Failed to initialize:", i);
540
- }), n;
541
- }
542
- function a() {
543
- if (!n)
544
- throw new Error(
545
- "[Analytics] Not initialized. Call createAnalytics() first."
546
- );
547
- return n;
548
- }
549
- function v(t, e) {
550
- return a().track(t, e);
551
- }
552
- function y(t, e) {
553
- a().identify(t, e);
554
- }
555
- function w(t) {
556
- a().pageView(t);
557
- }
558
- function z(t) {
559
- a().pageLeave(t);
560
- }
561
- function x() {
562
- a().reset();
563
- }
564
- function A() {
565
- n = null;
566
- }
567
- export {
568
- p as B,
569
- z as a,
570
- A as b,
571
- m as c,
572
- a as g,
573
- y as i,
574
- w as p,
575
- x as r,
576
- v as t
577
- };
@@ -1,96 +0,0 @@
1
- var d = Object.defineProperty;
2
- var g = (r, s, i) => s in r ? d(r, s, { enumerable: !0, configurable: !0, writable: !0, value: i }) : r[s] = i;
3
- var t = (r, s, i) => g(r, typeof s != "symbol" ? s + "" : s, i);
4
- import { i as h } from "./environment-Bnc8FqHv.js";
5
- class o {
6
- constructor(s) {
7
- t(this, "debug", !1);
8
- t(this, "enabled", !0);
9
- (s == null ? void 0 : s.debug) !== void 0 && (this.debug = s.debug), (s == null ? void 0 : s.enabled) !== void 0 && (this.enabled = s.enabled);
10
- }
11
- log(s, i) {
12
- this.debug && console.log(`[${this.name}] ${s}`, i);
13
- }
14
- isEnabled() {
15
- return this.enabled;
16
- }
17
- }
18
- class n extends o {
19
- constructor(i) {
20
- super({ debug: i.debug, enabled: i.enabled });
21
- t(this, "name", "PostHog-Client");
22
- t(this, "posthog");
23
- t(this, "initialized", !1);
24
- t(this, "config");
25
- this.config = i;
26
- }
27
- async initialize() {
28
- if (this.isEnabled() && !this.initialized) {
29
- if (!h()) {
30
- this.log("Skipping initialization - not in browser environment");
31
- return;
32
- }
33
- if (!this.config.token || typeof this.config.token != "string")
34
- throw new Error("PostHog requires a token");
35
- try {
36
- const { default: i } = await import("posthog-js"), { token: e, debug: a, ...l } = this.config;
37
- i.init(e, {
38
- ...l,
39
- debug: a ?? this.debug
40
- }), this.posthog = i, this.initialized = !0, this.log("Initialized successfully", this.config);
41
- } catch (i) {
42
- throw console.error("[PostHog-Client] Failed to initialize:", i), i;
43
- }
44
- }
45
- }
46
- identify(i, e) {
47
- !this.isEnabled() || !this.initialized || !this.posthog || (this.posthog.identify(i, e), this.log("Identified user", { userId: i, traits: e }));
48
- }
49
- track(i, e) {
50
- if (!this.isEnabled() || !this.initialized || !this.posthog) return;
51
- const a = {
52
- ...i.properties,
53
- category: i.category,
54
- timestamp: i.timestamp || Date.now(),
55
- ...i.userId && { userId: i.userId },
56
- ...i.sessionId && { sessionId: i.sessionId },
57
- ...(e == null ? void 0 : e.page) && { $current_url: e.page.path },
58
- ...(e == null ? void 0 : e.device) && { device: e.device },
59
- ...(e == null ? void 0 : e.utm) && { utm: e.utm }
60
- };
61
- this.posthog.capture(i.action, a), this.log("Tracked event", { event: i, context: e });
62
- }
63
- pageView(i, e) {
64
- if (!this.isEnabled() || !this.initialized || !this.posthog || !h())
65
- return;
66
- const a = {
67
- ...i,
68
- ...(e == null ? void 0 : e.page) && {
69
- path: e.page.path,
70
- title: e.page.title,
71
- referrer: e.page.referrer
72
- }
73
- };
74
- this.posthog.capture("$pageview", a), this.log("Tracked page view", { properties: i, context: e });
75
- }
76
- pageLeave(i, e) {
77
- if (!this.isEnabled() || !this.initialized || !this.posthog || !h())
78
- return;
79
- const a = {
80
- ...i,
81
- ...(e == null ? void 0 : e.page) && {
82
- path: e.page.path,
83
- title: e.page.title,
84
- referrer: e.page.referrer
85
- }
86
- };
87
- this.posthog.capture("$pageleave", a), this.log("Tracked page leave", { properties: i, context: e });
88
- }
89
- reset() {
90
- !this.isEnabled() || !this.initialized || !this.posthog || !h() || (this.posthog.reset(), this.log("Reset user session"));
91
- }
92
- }
93
- export {
94
- o as B,
95
- n as P
96
- };
@@ -1,2 +0,0 @@
1
- export * from './src/providers/index'
2
- export {}
File without changes