@stacksee/analytics 0.3.3 → 0.4.2

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,174 @@
1
+ var p = Object.defineProperty;
2
+ var g = (a, s, e) => s in a ? p(a, s, { enumerable: !0, configurable: !0, writable: !0, value: e }) : a[s] = e;
3
+ var t = (a, s, e) => g(a, typeof s != "symbol" ? s + "" : s, e);
4
+ import { i as h } from "./environment-Bnc8FqHv.js";
5
+ import { PostHog as o } from "posthog-node";
6
+ class l {
7
+ constructor(s) {
8
+ t(this, "debug", !1);
9
+ t(this, "enabled", !0);
10
+ (s == null ? void 0 : s.debug) !== void 0 && (this.debug = s.debug), (s == null ? void 0 : s.enabled) !== void 0 && (this.enabled = s.enabled);
11
+ }
12
+ log(s, e) {
13
+ this.debug && console.log(`[${this.name}] ${s}`, e);
14
+ }
15
+ isEnabled() {
16
+ return this.enabled;
17
+ }
18
+ }
19
+ class b extends l {
20
+ constructor(e) {
21
+ super({ debug: e.debug, enabled: e.enabled });
22
+ t(this, "name", "PostHog-Client");
23
+ t(this, "posthog");
24
+ t(this, "initialized", !1);
25
+ t(this, "config");
26
+ this.config = e;
27
+ }
28
+ async initialize() {
29
+ if (this.isEnabled() && !this.initialized) {
30
+ if (!h()) {
31
+ this.log("Skipping initialization - not in browser environment");
32
+ return;
33
+ }
34
+ if (!this.config.token || typeof this.config.token != "string")
35
+ throw new Error("PostHog requires a token");
36
+ try {
37
+ const { default: e } = await import("posthog-js"), { token: i, debug: r, ...d } = this.config;
38
+ e.init(i, {
39
+ ...d,
40
+ debug: r ?? this.debug
41
+ }), this.posthog = e, this.initialized = !0, this.log("Initialized successfully", this.config);
42
+ } catch (e) {
43
+ throw console.error("[PostHog-Client] Failed to initialize:", e), e;
44
+ }
45
+ }
46
+ }
47
+ identify(e, i) {
48
+ !this.isEnabled() || !this.initialized || !this.posthog || (this.posthog.identify(e, i), this.log("Identified user", { userId: e, traits: i }));
49
+ }
50
+ track(e, i) {
51
+ if (!this.isEnabled() || !this.initialized || !this.posthog) return;
52
+ const r = {
53
+ ...e.properties,
54
+ category: e.category,
55
+ timestamp: e.timestamp || Date.now(),
56
+ ...e.userId && { userId: e.userId },
57
+ ...e.sessionId && { sessionId: e.sessionId },
58
+ ...(i == null ? void 0 : i.page) && { $current_url: i.page.path },
59
+ ...(i == null ? void 0 : i.device) && { device: i.device },
60
+ ...(i == null ? void 0 : i.utm) && { utm: i.utm }
61
+ };
62
+ this.posthog.capture(e.action, r), this.log("Tracked event", { event: e, context: i });
63
+ }
64
+ pageView(e, i) {
65
+ if (!this.isEnabled() || !this.initialized || !this.posthog || !h())
66
+ return;
67
+ const r = {
68
+ ...e,
69
+ ...(i == null ? void 0 : i.page) && {
70
+ path: i.page.path,
71
+ title: i.page.title,
72
+ referrer: i.page.referrer
73
+ }
74
+ };
75
+ this.posthog.capture("$pageview", r), this.log("Tracked page view", { properties: e, context: i });
76
+ }
77
+ pageLeave(e, i) {
78
+ if (!this.isEnabled() || !this.initialized || !this.posthog || !h())
79
+ return;
80
+ const r = {
81
+ ...e,
82
+ ...(i == null ? void 0 : i.page) && {
83
+ path: i.page.path,
84
+ title: i.page.title,
85
+ referrer: i.page.referrer
86
+ }
87
+ };
88
+ this.posthog.capture("$pageleave", r), this.log("Tracked page leave", { properties: e, context: i });
89
+ }
90
+ reset() {
91
+ !this.isEnabled() || !this.initialized || !this.posthog || !h() || (this.posthog.reset(), this.log("Reset user session"));
92
+ }
93
+ }
94
+ class m extends l {
95
+ constructor(e) {
96
+ super({ debug: e.debug, enabled: e.enabled });
97
+ t(this, "name", "PostHog-Server");
98
+ t(this, "client");
99
+ t(this, "initialized", !1);
100
+ t(this, "config");
101
+ this.config = e;
102
+ }
103
+ initialize() {
104
+ if (this.isEnabled() && !this.initialized) {
105
+ if (!this.config.apiKey || typeof this.config.apiKey != "string")
106
+ throw new Error("PostHog requires an apiKey");
107
+ try {
108
+ const { apiKey: e, ...i } = this.config;
109
+ this.client = new o(e, {
110
+ host: "https://app.posthog.com",
111
+ flushAt: 20,
112
+ flushInterval: 1e4,
113
+ ...i
114
+ }), this.initialized = !0, this.log("Initialized successfully", this.config);
115
+ } catch (e) {
116
+ throw console.error("[PostHog-Server] Failed to initialize:", e), e;
117
+ }
118
+ }
119
+ }
120
+ identify(e, i) {
121
+ !this.isEnabled() || !this.initialized || !this.client || (this.client.identify({
122
+ distinctId: e,
123
+ properties: i
124
+ }), this.log("Identified user", { userId: e, traits: i }));
125
+ }
126
+ track(e, i) {
127
+ if (!this.isEnabled() || !this.initialized || !this.client) return;
128
+ const r = {
129
+ ...e.properties,
130
+ category: e.category,
131
+ timestamp: e.timestamp ? new Date(e.timestamp) : /* @__PURE__ */ new Date(),
132
+ ...e.sessionId && { sessionId: e.sessionId },
133
+ ...(i == null ? void 0 : i.page) && {
134
+ $current_url: i.page.path,
135
+ $page_title: i.page.title,
136
+ $referrer: i.page.referrer
137
+ },
138
+ ...(i == null ? void 0 : i.device) && { device: i.device },
139
+ ...(i == null ? void 0 : i.utm) && { utm: i.utm }
140
+ };
141
+ this.client.capture({
142
+ distinctId: e.userId || "anonymous",
143
+ event: e.action,
144
+ properties: r
145
+ }), this.log("Tracked event", { event: e, context: i });
146
+ }
147
+ pageView(e, i) {
148
+ if (!this.isEnabled() || !this.initialized || !this.client) return;
149
+ const r = {
150
+ ...e,
151
+ ...(i == null ? void 0 : i.page) && {
152
+ path: i.page.path,
153
+ title: i.page.title,
154
+ referrer: i.page.referrer
155
+ }
156
+ };
157
+ this.client.capture({
158
+ distinctId: "anonymous",
159
+ event: "$pageview",
160
+ properties: r
161
+ }), this.log("Tracked page view", { properties: e, context: i });
162
+ }
163
+ async reset() {
164
+ !this.isEnabled() || !this.initialized || !this.client || (await this.client.flush(), this.log("Flushed pending events"));
165
+ }
166
+ async shutdown() {
167
+ this.client && (await this.client.shutdown(), this.log("Shutdown complete"));
168
+ }
169
+ }
170
+ export {
171
+ l as B,
172
+ b as P,
173
+ m as a
174
+ };
package/dist/server.js CHANGED
@@ -1,11 +1,11 @@
1
1
  var o = Object.defineProperty;
2
2
  var f = (r, e, t) => e in r ? o(r, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : r[e] = t;
3
- var a = (r, e, t) => f(r, typeof e != "symbol" ? e + "" : e, t);
3
+ var n = (r, e, t) => f(r, typeof e != "symbol" ? e + "" : e, t);
4
4
  class u {
5
5
  constructor(e) {
6
- a(this, "providers", []);
7
- a(this, "config");
8
- a(this, "initialized", !1);
6
+ n(this, "providers", []);
7
+ n(this, "config");
8
+ n(this, "initialized", !1);
9
9
  this.config = e, this.providers = e.providers;
10
10
  }
11
11
  initialize() {
@@ -24,7 +24,7 @@ class u {
24
24
  console.warn("[Analytics] Not initialized. Call initialize() first.");
25
25
  return;
26
26
  }
27
- const n = {
27
+ const a = {
28
28
  action: e,
29
29
  category: this.getCategoryFromEventName(e),
30
30
  properties: t,
@@ -36,7 +36,7 @@ class u {
36
36
  ...i == null ? void 0 : i.context
37
37
  }, d = this.providers.map(async (s) => {
38
38
  try {
39
- await s.track(n, c);
39
+ await s.track(a, c);
40
40
  } catch (l) {
41
41
  console.error(
42
42
  `[Analytics] Provider ${s.name} failed to track event:`,
@@ -46,14 +46,23 @@ class u {
46
46
  });
47
47
  await Promise.all(d);
48
48
  }
49
- page(e, t) {
49
+ pageView(e, t) {
50
50
  if (!this.initialized) return;
51
51
  const i = {
52
52
  ...this.config.defaultContext,
53
53
  ...t == null ? void 0 : t.context
54
54
  };
55
- for (const n of this.providers)
56
- n.page(e, i);
55
+ for (const a of this.providers)
56
+ a.pageView(e, i);
57
+ }
58
+ pageLeave(e, t) {
59
+ if (!this.initialized) return;
60
+ const i = {
61
+ ...this.config.defaultContext,
62
+ ...t == null ? void 0 : t.context
63
+ };
64
+ for (const a of this.providers)
65
+ a.pageLeave && a.pageLeave(e, i);
57
66
  }
58
67
  async shutdown() {
59
68
  const e = this.providers.map((t) => "shutdown" in t && typeof t.shutdown == "function" ? t.shutdown() : Promise.resolve());
@@ -13,7 +13,8 @@ export declare class BrowserAnalytics<TEventMap extends DefaultEventMap = Defaul
13
13
  private ensureInitialized;
14
14
  identify(userId: string, traits?: Record<string, unknown>): void;
15
15
  track<TEventName extends keyof TEventMap & string>(eventName: TEventName, properties: TEventMap[TEventName]): Promise<void>;
16
- page(properties?: Record<string, unknown>): void;
16
+ pageView(properties?: Record<string, unknown>): void;
17
+ pageLeave(properties?: Record<string, unknown>): void;
17
18
  reset(): void;
18
19
  updateContext(context: Partial<EventContext>): void;
19
20
  private getCategoryFromEventName;
@@ -12,7 +12,10 @@ export declare class ServerAnalytics<TEventMap extends DefaultEventMap = Default
12
12
  sessionId?: string;
13
13
  context?: EventContext;
14
14
  }): Promise<void>;
15
- page(properties?: Record<string, unknown>, options?: {
15
+ pageView(properties?: Record<string, unknown>, options?: {
16
+ context?: EventContext;
17
+ }): void;
18
+ pageLeave(properties?: Record<string, unknown>, options?: {
16
19
  context?: EventContext;
17
20
  }): void;
18
21
  shutdown(): Promise<void>;
@@ -1,7 +1,7 @@
1
- export { createClientAnalytics, createAnalytics, getAnalytics, track, identify, page, reset, type ClientAnalyticsConfig, } from '../client.js';
1
+ export { createClientAnalytics, createAnalytics, getAnalytics, track, identify, pageView, pageLeave, reset, type ClientAnalyticsConfig, } from '../client.js';
2
2
  export { BrowserAnalytics } from '../adapters/client/browser-analytics.js';
3
3
  export { PostHogClientProvider } from '../providers/posthog/client.js';
4
- export type { PostHogConfig } from '../providers/posthog/types.js';
4
+ export type { PostHogConfig } from 'posthog-js';
5
5
  export { BaseAnalyticsProvider } from '../providers/base.provider.js';
6
6
  export type { EventCategory, BaseEvent, EventContext, AnalyticsProvider, AnalyticsConfig, } from '../core/events/types.js';
7
7
  export type { CreateEventDefinition, ExtractEventNames, ExtractEventPropertiesFromCollection, EventCollection, AnyEventName, AnyEventProperties, } from '../core/events/index.js';
@@ -52,7 +52,11 @@ export declare function identify(userId: string, traits?: Record<string, unknown
52
52
  /**
53
53
  * Convenience function to track page views
54
54
  */
55
- export declare function page(properties?: Record<string, unknown>): void;
55
+ export declare function pageView(properties?: Record<string, unknown>): void;
56
+ /**
57
+ * Convenience function to track page leave events
58
+ */
59
+ export declare function pageLeave(properties?: Record<string, unknown>): void;
56
60
  /**
57
61
  * Convenience function to reset user session
58
62
  */
@@ -30,7 +30,8 @@ export interface AnalyticsProvider {
30
30
  initialize(): Promise<void> | void;
31
31
  identify(userId: string, traits?: Record<string, unknown>): Promise<void> | void;
32
32
  track(event: BaseEvent, context?: EventContext): Promise<void> | void;
33
- page(properties?: Record<string, unknown>, context?: EventContext): Promise<void> | void;
33
+ pageView(properties?: Record<string, unknown>, context?: EventContext): Promise<void> | void;
34
+ pageLeave?(properties?: Record<string, unknown>, context?: EventContext): Promise<void> | void;
34
35
  reset(): Promise<void> | void;
35
36
  }
36
37
  export interface AnalyticsConfig {
@@ -1,6 +1,6 @@
1
1
  export type { EventCategory, BaseEvent, EventContext, AnalyticsProvider, AnalyticsConfig, } from './core/events/types.js';
2
2
  export type { CreateEventDefinition, ExtractEventNames, ExtractEventPropertiesFromCollection, EventCollection, AnyEventName, AnyEventProperties, EventMapFromCollection, } from './core/events/index.js';
3
- export { createAnalytics as createClientAnalytics, getAnalytics, track as trackClient, identify as identifyClient, page as pageClient, reset as resetClient, type ClientAnalyticsConfig, } from './client.js';
3
+ export { createAnalytics as createClientAnalytics, getAnalytics, track as trackClient, identify as identifyClient, pageView as pageViewClient, pageLeave as pageLeaveClient, reset as resetClient, type ClientAnalyticsConfig, } from './client.js';
4
4
  export { createServerAnalytics, ServerAnalytics, type ServerAnalyticsConfig, } from './server.js';
5
- export { BaseAnalyticsProvider, PostHogClientProvider, PostHogServerProvider, type PostHogConfig, } from './providers/index.js';
5
+ export { BaseAnalyticsProvider, PostHogClientProvider, PostHogServerProvider, type PostHogConfig, type PostHogOptions, } from './providers/index.js';
6
6
  export { BrowserAnalytics } from './adapters/client/browser-analytics.js';
@@ -10,7 +10,8 @@ export declare abstract class BaseAnalyticsProvider implements AnalyticsProvider
10
10
  abstract initialize(): Promise<void> | void;
11
11
  abstract identify(userId: string, traits?: Record<string, unknown>): Promise<void> | void;
12
12
  abstract track(event: BaseEvent, context?: EventContext): Promise<void> | void;
13
- abstract page(properties?: Record<string, unknown>, context?: EventContext): Promise<void> | void;
13
+ abstract pageView(properties?: Record<string, unknown>, context?: EventContext): Promise<void> | void;
14
+ pageLeave?(properties?: Record<string, unknown>, context?: EventContext): Promise<void> | void;
14
15
  abstract reset(): Promise<void> | void;
15
16
  protected log(message: string, data?: unknown): void;
16
17
  protected isEnabled(): boolean;
@@ -1,4 +1,5 @@
1
1
  export { BaseAnalyticsProvider } from './base.provider.js';
2
2
  export { PostHogClientProvider } from './posthog/client.js';
3
3
  export { PostHogServerProvider } from './posthog/server.js';
4
- export type { PostHogConfig } from './posthog/types.js';
4
+ export type { PostHogConfig } from 'posthog-js';
5
+ export type { PostHogOptions } from 'posthog-node';
@@ -1,24 +1,20 @@
1
1
  import { BaseEvent, EventContext } from '../../core/events/types.js';
2
2
  import { BaseAnalyticsProvider } from '../base.provider.js';
3
- import { PostHogConfig } from './types.js';
4
- import { PostHog } from 'posthog-js';
5
- declare global {
6
- interface Window {
7
- posthog?: PostHog;
8
- }
9
- }
3
+ import { PostHogConfig } from 'posthog-js';
10
4
  export declare class PostHogClientProvider extends BaseAnalyticsProvider {
11
5
  name: string;
12
6
  private posthog?;
13
7
  private initialized;
14
8
  private config;
15
- constructor(config: PostHogConfig & {
9
+ constructor(config: Partial<PostHogConfig> & {
10
+ token: string;
16
11
  debug?: boolean;
17
12
  enabled?: boolean;
18
13
  });
19
14
  initialize(): Promise<void>;
20
15
  identify(userId: string, traits?: Record<string, unknown>): void;
21
16
  track(event: BaseEvent, context?: EventContext): void;
22
- page(properties?: Record<string, unknown>, context?: EventContext): void;
17
+ pageView(properties?: Record<string, unknown>, context?: EventContext): void;
18
+ pageLeave(properties?: Record<string, unknown>, context?: EventContext): void;
23
19
  reset(): void;
24
20
  }
@@ -1,19 +1,21 @@
1
1
  import { BaseEvent, EventContext } from '../../core/events/types.js';
2
2
  import { BaseAnalyticsProvider } from '../base.provider.js';
3
- import { PostHogConfig } from './types.js';
3
+ import { PostHogOptions } from 'posthog-node';
4
4
  export declare class PostHogServerProvider extends BaseAnalyticsProvider {
5
5
  name: string;
6
6
  private client?;
7
7
  private initialized;
8
8
  private config;
9
- constructor(config: PostHogConfig & {
9
+ constructor(config: {
10
+ apiKey: string;
11
+ } & PostHogOptions & {
10
12
  debug?: boolean;
11
13
  enabled?: boolean;
12
14
  });
13
15
  initialize(): void;
14
16
  identify(userId: string, traits?: Record<string, unknown>): void;
15
17
  track(event: BaseEvent, context?: EventContext): void;
16
- page(properties?: Record<string, unknown>, context?: EventContext): void;
18
+ pageView(properties?: Record<string, unknown>, context?: EventContext): void;
17
19
  reset(): Promise<void>;
18
20
  shutdown(): Promise<void>;
19
21
  }
@@ -1,6 +1,6 @@
1
1
  export { createServerAnalytics, ServerAnalytics, type ServerAnalyticsConfig, } from '../server.js';
2
2
  export { PostHogServerProvider } from '../providers/posthog/server.js';
3
- export type { PostHogConfig } from '../providers/posthog/types.js';
3
+ export type { PostHogOptions } from 'posthog-node';
4
4
  export { BaseAnalyticsProvider } from '../providers/base.provider.js';
5
5
  export type { EventCategory, BaseEvent, EventContext, AnalyticsProvider, AnalyticsConfig, } from '../core/events/types.js';
6
6
  export type { CreateEventDefinition, ExtractEventNames, ExtractEventPropertiesFromCollection, EventCollection, AnyEventName, AnyEventProperties, } from '../core/events/index.js';
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Environment detection utilities
3
+ */
4
+ /**
5
+ * Check if we're running in a browser environment
6
+ * @returns true if running in browser, false if in Node.js or other environments
7
+ */
8
+ export declare function isBrowser(): boolean;
9
+ /**
10
+ * Check if we're running in a Node.js environment
11
+ * @returns true if running in Node.js, false otherwise
12
+ */
13
+ export declare function isNode(): boolean;
14
+ /**
15
+ * Check if we're running in a server-side rendering context
16
+ * @returns true if likely in SSR context, false otherwise
17
+ */
18
+ export declare function isSSR(): boolean;
@@ -13,7 +13,11 @@ export declare class MockAnalyticsProvider extends BaseAnalyticsProvider {
13
13
  event: BaseEvent;
14
14
  context?: EventContext;
15
15
  }>;
16
- page: Array<{
16
+ pageView: Array<{
17
+ properties?: Record<string, unknown>;
18
+ context?: EventContext;
19
+ }>;
20
+ pageLeave: Array<{
17
21
  properties?: Record<string, unknown>;
18
22
  context?: EventContext;
19
23
  }>;
@@ -22,7 +26,8 @@ export declare class MockAnalyticsProvider extends BaseAnalyticsProvider {
22
26
  initialize(): void;
23
27
  identify(userId: string, traits?: Record<string, unknown>): void;
24
28
  track(event: BaseEvent, context?: EventContext): void;
25
- page(properties?: Record<string, unknown>, context?: EventContext): void;
29
+ pageView(properties?: Record<string, unknown>, context?: EventContext): void;
30
+ pageLeave(properties?: Record<string, unknown>, context?: EventContext): void;
26
31
  reset(): void;
27
32
  clearCalls(): void;
28
33
  isInitialized(): boolean;
@@ -0,0 +1 @@
1
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stacksee/analytics",
3
- "version": "0.3.3",
3
+ "version": "0.4.2",
4
4
  "description": "A highly typed, provider-agnostic analytics library for TypeScript applications",
5
5
  "type": "module",
6
6
  "exports": {
@@ -57,8 +57,8 @@
57
57
  "vitest": "^2.0.3"
58
58
  },
59
59
  "optionalDependencies": {
60
- "posthog-js": "^1.96.0",
61
- "posthog-node": "^3.2.0"
60
+ "posthog-js": "^1.268.2",
61
+ "posthog-node": "^5.9.0"
62
62
  },
63
63
  "engines": {
64
64
  "pnpm": ">=9.0.0",
package/readme.md CHANGED
@@ -445,6 +445,42 @@ export const POST: RequestHandler = async ({ request }) => {
445
445
  };
446
446
  ```
447
447
 
448
+ #### Note for SvelteKit Users: Navigation Tracking
449
+
450
+ If you're using SvelteKit and want to track page views and page leaves automatically with PostHog (as recommended in their documentation), add this to your root layout:
451
+
452
+ ```typescript
453
+ // src/app.html or src/routes/+layout.svelte
454
+ <script>
455
+ import { pageView, pageLeave } from '@stacksee/analytics/client';
456
+ import { beforeNavigate, afterNavigate } from '$app/navigation';
457
+ import { browser } from '$app/environment';
458
+
459
+ let { children } = $props():
460
+
461
+ // Only set up navigation tracking in the browser
462
+ if (browser) {
463
+ beforeNavigate(() => {
464
+ pageLeave();
465
+ });
466
+
467
+ afterNavigate(() => {
468
+ pageView();
469
+ });
470
+ }
471
+ </script>
472
+
473
+ <main>
474
+ {@render children()}
475
+ </main>
476
+ ```
477
+
478
+ This automatically tracks:
479
+ - **Page leaves** before navigation (`$pageleave` events in PostHog)
480
+ - **Page views** after navigation (`$pageview` events in PostHog)
481
+
482
+ The tracking is framework-agnostic, so you can use similar patterns with Next.js router events, Vue Router hooks, or any other navigation system.
483
+
448
484
  ### Event Categories
449
485
 
450
486
  Event categories help organize your analytics data. The SDK provides predefined categories with TypeScript autocomplete:
@@ -759,7 +795,8 @@ const analytics = createClientAnalytics<typeof AppEvents>({
759
795
  #### `BrowserAnalytics<TEventMap>`
760
796
  - `track(eventName, properties): Promise<void>` - Track an event with type-safe event names and properties
761
797
  - `identify(userId, traits)` - Identify a user
762
- - `page(properties)` - Track a page view
798
+ - `pageView(properties)` - Track a page view
799
+ - `pageLeave(properties)` - Track a page leave event
763
800
  - `reset()` - Reset user session
764
801
  - `updateContext(context)` - Update event context
765
802
 
@@ -784,7 +821,8 @@ const analytics = createServerAnalytics<AppEvents>({
784
821
  #### `ServerAnalytics<TEventMap>`
785
822
  - `track(eventName, properties, options): Promise<void>` - Track an event with type-safe event names and properties
786
823
  - `identify(userId, traits)` - Identify a user
787
- - `page(properties, options)` - Track a page view
824
+ - `pageView(properties, options)` - Track a page view
825
+ - `pageLeave(properties, options)` - Track a page leave event
788
826
  - `shutdown()` - Flush pending events and cleanup
789
827
 
790
828
  ### Type Helpers