@stacksee/analytics 0.2.2 → 0.3.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.
- package/dist/{client-DIOWX7_9.js → client-yfDfetWt.js} +55 -53
- package/dist/client.js +1 -1
- package/dist/index.js +15 -2620
- package/dist/providers.d.ts +2 -0
- package/dist/providers.js +2611 -0
- package/dist/server.js +3 -1
- package/dist/src/adapters/client/browser-analytics.d.ts +4 -3
- package/dist/src/adapters/server/server-analytics.d.ts +4 -3
- package/dist/src/client.d.ts +19 -5
- package/dist/src/core/events/types.d.ts +1 -1
- package/dist/src/server.d.ts +18 -2
- package/package.json +5 -1
- package/readme.md +94 -94
package/dist/server.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { AnyEventName, AnyEventProperties } from '../../core/events/index.js';
|
|
2
1
|
import { AnalyticsConfig, EventContext } from '../../core/events/types.js';
|
|
3
|
-
|
|
2
|
+
type DefaultEventMap = Record<string, Record<string, unknown>>;
|
|
3
|
+
export declare class BrowserAnalytics<TEventMap extends DefaultEventMap = DefaultEventMap> {
|
|
4
4
|
private providers;
|
|
5
5
|
private context;
|
|
6
6
|
private userId?;
|
|
@@ -12,7 +12,7 @@ export declare class BrowserAnalytics<TEventName extends string = AnyEventName,
|
|
|
12
12
|
private _doInitialize;
|
|
13
13
|
private ensureInitialized;
|
|
14
14
|
identify(userId: string, traits?: Record<string, unknown>): void;
|
|
15
|
-
track(eventName: TEventName, properties:
|
|
15
|
+
track<TEventName extends keyof TEventMap & string>(eventName: TEventName, properties: TEventMap[TEventName]): Promise<void>;
|
|
16
16
|
page(properties?: Record<string, unknown>): void;
|
|
17
17
|
reset(): void;
|
|
18
18
|
updateContext(context: Partial<EventContext>): void;
|
|
@@ -22,3 +22,4 @@ export declare class BrowserAnalytics<TEventName extends string = AnyEventName,
|
|
|
22
22
|
private getOS;
|
|
23
23
|
private getBrowser;
|
|
24
24
|
}
|
|
25
|
+
export {};
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import { AnyEventName, AnyEventProperties } from '../../core/events/index.js';
|
|
2
1
|
import { AnalyticsConfig, EventContext } from '../../core/events/types.js';
|
|
3
|
-
|
|
2
|
+
type DefaultEventMap = Record<string, Record<string, unknown>>;
|
|
3
|
+
export declare class ServerAnalytics<TEventMap extends DefaultEventMap = DefaultEventMap> {
|
|
4
4
|
private providers;
|
|
5
5
|
private config;
|
|
6
6
|
private initialized;
|
|
7
7
|
constructor(config: AnalyticsConfig);
|
|
8
8
|
initialize(): void;
|
|
9
9
|
identify(userId: string, traits?: Record<string, unknown>): void;
|
|
10
|
-
track(eventName: TEventName, properties:
|
|
10
|
+
track<TEventName extends keyof TEventMap & string>(eventName: TEventName, properties: TEventMap[TEventName], options?: {
|
|
11
11
|
userId?: string;
|
|
12
12
|
sessionId?: string;
|
|
13
13
|
context?: EventContext;
|
|
@@ -18,3 +18,4 @@ export declare class ServerAnalytics<TEventName extends string = AnyEventName, T
|
|
|
18
18
|
shutdown(): Promise<void>;
|
|
19
19
|
private getCategoryFromEventName;
|
|
20
20
|
}
|
|
21
|
+
export {};
|
package/dist/src/client.d.ts
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
import { BrowserAnalytics } from './adapters/client/browser-analytics.js';
|
|
2
2
|
import { AnalyticsProvider } from './core/events/types.js';
|
|
3
|
+
import { EventCollection } from './core/events/index.js';
|
|
4
|
+
type DefaultEventMap = Record<string, Record<string, unknown>>;
|
|
5
|
+
type EventMapFromCollection<T> = T extends EventCollection<infer Events> ? {
|
|
6
|
+
[K in keyof Events as Events[K] extends {
|
|
7
|
+
name: infer N;
|
|
8
|
+
} ? N extends string ? N : never : never]: Events[K] extends {
|
|
9
|
+
properties: infer P;
|
|
10
|
+
} ? P : never;
|
|
11
|
+
} : never;
|
|
3
12
|
export interface ClientAnalyticsConfig {
|
|
4
13
|
providers?: AnalyticsProvider[];
|
|
5
14
|
debug?: boolean;
|
|
@@ -12,8 +21,9 @@ export interface ClientAnalyticsConfig {
|
|
|
12
21
|
* ```typescript
|
|
13
22
|
* import { createClientAnalytics } from '@stacksee/analytics/client';
|
|
14
23
|
* import { PostHogClientProvider } from '@stacksee/analytics/providers/posthog';
|
|
24
|
+
* import { AppEvents } from './events';
|
|
15
25
|
*
|
|
16
|
-
* const analytics = createClientAnalytics({
|
|
26
|
+
* const analytics = createClientAnalytics<typeof AppEvents>({
|
|
17
27
|
* providers: [
|
|
18
28
|
* new PostHogClientProvider({
|
|
19
29
|
* apiKey: 'your-api-key',
|
|
@@ -24,16 +34,20 @@ export interface ClientAnalyticsConfig {
|
|
|
24
34
|
* enabled: true
|
|
25
35
|
* });
|
|
26
36
|
*
|
|
27
|
-
* //
|
|
28
|
-
*
|
|
37
|
+
* // Now event names and properties are fully typed!
|
|
38
|
+
* analytics.track('user_signed_up', {
|
|
39
|
+
* userId: 'user-123',
|
|
40
|
+
* email: 'user@example.com',
|
|
41
|
+
* plan: 'pro'
|
|
42
|
+
* });
|
|
29
43
|
* ```
|
|
30
44
|
*/
|
|
31
|
-
export declare function createClientAnalytics(config: ClientAnalyticsConfig): BrowserAnalytics
|
|
45
|
+
export declare function createClientAnalytics<TEvents = never>(config: ClientAnalyticsConfig): BrowserAnalytics<EventMapFromCollection<TEvents>>;
|
|
32
46
|
export { createClientAnalytics as createAnalytics };
|
|
33
47
|
/**
|
|
34
48
|
* Get the current analytics instance
|
|
35
49
|
*/
|
|
36
|
-
export declare function getAnalytics(): BrowserAnalytics
|
|
50
|
+
export declare function getAnalytics(): BrowserAnalytics<DefaultEventMap>;
|
|
37
51
|
/**
|
|
38
52
|
* Convenience function to track events
|
|
39
53
|
*/
|
package/dist/src/server.d.ts
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
import { ServerAnalytics } from './adapters/server/server-analytics.js';
|
|
2
2
|
import { AnalyticsProvider } from './core/events/types.js';
|
|
3
|
+
import { EventCollection } from './core/events/index.js';
|
|
4
|
+
type EventMapFromCollection<T> = T extends EventCollection<infer Events> ? {
|
|
5
|
+
[K in keyof Events as Events[K] extends {
|
|
6
|
+
name: infer N;
|
|
7
|
+
} ? N extends string ? N : never : never]: Events[K] extends {
|
|
8
|
+
properties: infer P;
|
|
9
|
+
} ? P : never;
|
|
10
|
+
} : never;
|
|
3
11
|
export interface ServerAnalyticsConfig {
|
|
4
12
|
providers?: AnalyticsProvider[];
|
|
5
13
|
debug?: boolean;
|
|
@@ -12,8 +20,9 @@ export interface ServerAnalyticsConfig {
|
|
|
12
20
|
* ```typescript
|
|
13
21
|
* import { createServerAnalytics } from '@stacksee/analytics/server';
|
|
14
22
|
* import { PostHogServerProvider } from '@stacksee/analytics/providers/posthog';
|
|
23
|
+
* import { AppEvents } from './events';
|
|
15
24
|
*
|
|
16
|
-
* const analytics = createServerAnalytics({
|
|
25
|
+
* const analytics = createServerAnalytics<typeof AppEvents>({
|
|
17
26
|
* providers: [
|
|
18
27
|
* new PostHogServerProvider({
|
|
19
28
|
* apiKey: process.env.POSTHOG_API_KEY,
|
|
@@ -23,7 +32,14 @@ export interface ServerAnalyticsConfig {
|
|
|
23
32
|
* debug: true,
|
|
24
33
|
* enabled: true
|
|
25
34
|
* });
|
|
35
|
+
*
|
|
36
|
+
* // Now event names and properties are fully typed!
|
|
37
|
+
* await analytics.track('user_signed_up', {
|
|
38
|
+
* userId: 'user-123',
|
|
39
|
+
* email: 'user@example.com',
|
|
40
|
+
* plan: 'pro'
|
|
41
|
+
* }, { userId: 'user-123' });
|
|
26
42
|
* ```
|
|
27
43
|
*/
|
|
28
|
-
export declare function createServerAnalytics(config: ServerAnalyticsConfig): ServerAnalytics
|
|
44
|
+
export declare function createServerAnalytics<TEvents = never>(config: ServerAnalyticsConfig): ServerAnalytics<EventMapFromCollection<TEvents>>;
|
|
29
45
|
export { ServerAnalytics };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stacksee/analytics",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.2",
|
|
4
4
|
"description": "A highly typed, provider-agnostic analytics library for TypeScript applications",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -15,6 +15,10 @@
|
|
|
15
15
|
"./server": {
|
|
16
16
|
"types": "./dist/server.d.ts",
|
|
17
17
|
"import": "./dist/server.js"
|
|
18
|
+
},
|
|
19
|
+
"./providers": {
|
|
20
|
+
"types": "./dist/providers.d.ts",
|
|
21
|
+
"import": "./dist/providers.js"
|
|
18
22
|
}
|
|
19
23
|
},
|
|
20
24
|
"main": "./dist/index.js",
|
package/readme.md
CHANGED
|
@@ -2,6 +2,38 @@
|
|
|
2
2
|
|
|
3
3
|
A highly typed, provider-agnostic analytics library for TypeScript applications. Works seamlessly on both client and server sides with full type safety for your custom events.
|
|
4
4
|
|
|
5
|
+
## Table of Contents
|
|
6
|
+
|
|
7
|
+
- [Features](#features)
|
|
8
|
+
- [Installation](#installation)
|
|
9
|
+
- [Quick Start](#quick-start)
|
|
10
|
+
- [1. Define Your Events](#1-define-your-events)
|
|
11
|
+
- [2. Client-Side Usage](#2-client-side-usage)
|
|
12
|
+
- [3. Server-Side Usage](#3-server-side-usage)
|
|
13
|
+
- [Async Tracking](#async-tracking-when-to-await-vs-fire-and-forget)
|
|
14
|
+
- [Fire-and-forget (Client-side typical usage)](#fire-and-forget-client-side-typical-usage)
|
|
15
|
+
- [Await for critical events (Server-side typical usage)](#await-for-critical-events-server-side-typical-usage)
|
|
16
|
+
- [Error handling](#error-handling)
|
|
17
|
+
- [Best practices](#best-practices)
|
|
18
|
+
- [A complete example](#a-complete-example)
|
|
19
|
+
- [Advanced Usage](#advanced-usage)
|
|
20
|
+
- [Creating a Typed Analytics Service](#creating-a-typed-analytics-service)
|
|
21
|
+
- [Event Categories](#event-categories)
|
|
22
|
+
- [Adding Custom Providers](#adding-custom-providers)
|
|
23
|
+
- [Client-Only and Server-Only Providers](#client-only-and-server-only-providers)
|
|
24
|
+
- [Using Multiple Providers](#using-multiple-providers)
|
|
25
|
+
- [Server Deployments and waitUntil](#server-deployments-and-waituntil)
|
|
26
|
+
- [Vercel Functions](#vercel-functions)
|
|
27
|
+
- [Cloudflare Workers](#cloudflare-workers)
|
|
28
|
+
- [Netlify Functions](#netlify-functions)
|
|
29
|
+
- [API Reference](#api-reference)
|
|
30
|
+
- [Client API](#client-api)
|
|
31
|
+
- [Server API](#server-api)
|
|
32
|
+
- [Type Helpers](#type-helpers)
|
|
33
|
+
- [Best Practices](#best-practices)
|
|
34
|
+
- [Contributing](#contributing)
|
|
35
|
+
- [License](#license)
|
|
36
|
+
|
|
5
37
|
## Features
|
|
6
38
|
|
|
7
39
|
- 🎯 **Type-safe events**: Define your own strongly typed events with full IntelliSense support
|
|
@@ -30,8 +62,7 @@ Create strongly typed events specific to your application:
|
|
|
30
62
|
```typescript
|
|
31
63
|
import { CreateEventDefinition, EventCollection } from '@stacksee/analytics';
|
|
32
64
|
|
|
33
|
-
|
|
34
|
-
export const AppEvents = {
|
|
65
|
+
export const appEvents = {
|
|
35
66
|
userSignedUp: {
|
|
36
67
|
name: 'user_signed_up',
|
|
37
68
|
category: 'user',
|
|
@@ -54,9 +85,10 @@ export const AppEvents = {
|
|
|
54
85
|
}
|
|
55
86
|
} as const satisfies EventCollection<Record<string, CreateEventDefinition<string>>>;
|
|
56
87
|
|
|
57
|
-
//
|
|
58
|
-
export type
|
|
59
|
-
export type
|
|
88
|
+
// Optionally extract types for use in your app
|
|
89
|
+
export type AppEvents = typeof appEvents;
|
|
90
|
+
export type AppEventName = keyof typeof appEvents;
|
|
91
|
+
export type AppEventProperties<T extends AppEventName> = typeof appEvents[T]['properties'];
|
|
60
92
|
```
|
|
61
93
|
|
|
62
94
|
Tip: If you have a lot of events, you can also divide your events into multiple files, then export them as a single object.
|
|
@@ -66,10 +98,11 @@ Tip: If you have a lot of events, you can also divide your events into multiple
|
|
|
66
98
|
```typescript
|
|
67
99
|
import { createClientAnalytics } from '@stacksee/analytics/client';
|
|
68
100
|
import { PostHogClientProvider } from '@stacksee/analytics/providers/posthog';
|
|
69
|
-
import { AppEvents } from './events';
|
|
101
|
+
import type { AppEvents } from './events';
|
|
70
102
|
|
|
71
103
|
// Initialize analytics with providers as plugins
|
|
72
|
-
|
|
104
|
+
// Pass your event collection as a type parameter for full type safety
|
|
105
|
+
const analytics = createClientAnalytics<AppEvents>({
|
|
73
106
|
providers: [
|
|
74
107
|
new PostHogClientProvider({
|
|
75
108
|
apiKey: 'your-posthog-api-key',
|
|
@@ -81,20 +114,18 @@ const analytics = createClientAnalytics({
|
|
|
81
114
|
enabled: true
|
|
82
115
|
});
|
|
83
116
|
|
|
84
|
-
// Track events with full type safety
|
|
85
|
-
analytics.track(
|
|
86
|
-
path: '/dashboard',
|
|
87
|
-
title: 'Dashboard',
|
|
88
|
-
referrer: document.referrer
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
analytics.track(AppEvents.userSignedUp.name, {
|
|
117
|
+
// Track events with full type safety - event names and properties are typed!
|
|
118
|
+
analytics.track('user_signed_up', {
|
|
92
119
|
userId: 'user-123',
|
|
93
120
|
email: 'user@example.com',
|
|
94
121
|
plan: 'pro',
|
|
95
122
|
referralSource: 'google'
|
|
96
123
|
});
|
|
97
124
|
|
|
125
|
+
// TypeScript will error if you use wrong event names or properties
|
|
126
|
+
// analytics.track('wrong_event', {}); // ❌ Error: Argument of type '"wrong_event"' is not assignable
|
|
127
|
+
// analytics.track('user_signed_up', { wrongProp: 'value' }); // ❌ Error: Object literal may only specify known properties
|
|
128
|
+
|
|
98
129
|
// Identify users
|
|
99
130
|
analytics.identify('user-123', {
|
|
100
131
|
email: 'user@example.com',
|
|
@@ -108,10 +139,11 @@ analytics.identify('user-123', {
|
|
|
108
139
|
```typescript
|
|
109
140
|
import { createServerAnalytics } from '@stacksee/analytics/server';
|
|
110
141
|
import { PostHogServerProvider } from '@stacksee/analytics/providers/posthog';
|
|
111
|
-
import { AppEvents } from './events';
|
|
142
|
+
import type { AppEvents } from './events';
|
|
112
143
|
|
|
113
144
|
// Create analytics instance with providers as plugins
|
|
114
|
-
|
|
145
|
+
// Pass your event collection as a type parameter for full type safety
|
|
146
|
+
const analytics = createServerAnalytics<AppEvents>({
|
|
115
147
|
providers: [
|
|
116
148
|
new PostHogServerProvider({
|
|
117
149
|
apiKey: process.env.POSTHOG_API_KEY,
|
|
@@ -123,8 +155,8 @@ const analytics = createServerAnalytics({
|
|
|
123
155
|
enabled: true
|
|
124
156
|
});
|
|
125
157
|
|
|
126
|
-
// Track events - now returns a Promise
|
|
127
|
-
await analytics.track(
|
|
158
|
+
// Track events - now returns a Promise with full type safety
|
|
159
|
+
await analytics.track('feature_used', {
|
|
128
160
|
featureName: 'export-data',
|
|
129
161
|
userId: 'user-123',
|
|
130
162
|
duration: 1500
|
|
@@ -240,7 +272,7 @@ import { PostHogClientProvider } from '@stacksee/analytics/providers/posthog';
|
|
|
240
272
|
import { PUBLIC_POSTHOG_API_KEY, PUBLIC_POSTHOG_HOST } from '$env/static/public';
|
|
241
273
|
|
|
242
274
|
// Define your events for the waitlist
|
|
243
|
-
export const
|
|
275
|
+
export const appEvents = {
|
|
244
276
|
waitlistJoined: {
|
|
245
277
|
name: 'waitlist_joined',
|
|
246
278
|
category: 'user',
|
|
@@ -260,11 +292,11 @@ export const AppEvents = {
|
|
|
260
292
|
} as const;
|
|
261
293
|
|
|
262
294
|
// Client-side analytics instance
|
|
263
|
-
export const clientAnalytics = createClientAnalytics({
|
|
295
|
+
export const clientAnalytics = createClientAnalytics<AppEvents>({
|
|
264
296
|
providers: [
|
|
265
297
|
new PostHogClientProvider({
|
|
266
|
-
apiKey:
|
|
267
|
-
host:
|
|
298
|
+
apiKey: PUBLIC_POSTHOG_API_KEY,
|
|
299
|
+
host: PUBLIC_POSTHOG_HOST
|
|
268
300
|
})
|
|
269
301
|
],
|
|
270
302
|
debug: import.meta.env.DEV
|
|
@@ -278,21 +310,21 @@ import { PostHogServerProvider } from '@stacksee/analytics/providers/posthog';
|
|
|
278
310
|
import { AppEvents } from '$lib/config/analytics'; // Import AppEvents
|
|
279
311
|
import { PUBLIC_POSTHOG_API_KEY, PUBLIC_POSTHOG_HOST } from '$env/static/public';
|
|
280
312
|
|
|
281
|
-
export const serverAnalytics = createServerAnalytics({
|
|
313
|
+
export const serverAnalytics = createServerAnalytics<AppEvents>({
|
|
282
314
|
providers: [
|
|
283
315
|
new PostHogServerProvider({
|
|
284
316
|
apiKey: PUBLIC_POSTHOG_API_KEY,
|
|
285
317
|
host: PUBLIC_POSTHOG_HOST
|
|
286
318
|
})
|
|
287
319
|
],
|
|
288
|
-
debug:
|
|
320
|
+
debug: import.meta.env.DEV
|
|
289
321
|
});
|
|
290
322
|
```
|
|
291
323
|
|
|
292
324
|
```svelte
|
|
293
325
|
<!-- src/routes/join-waitlist/+page.svelte -->
|
|
294
326
|
<script lang="ts">
|
|
295
|
-
import { clientAnalytics
|
|
327
|
+
import { clientAnalytics } from '$lib/config/analytics';
|
|
296
328
|
|
|
297
329
|
let email = $state('');
|
|
298
330
|
let loading = $state(false);
|
|
@@ -305,7 +337,7 @@ export const serverAnalytics = createServerAnalytics({
|
|
|
305
337
|
|
|
306
338
|
try {
|
|
307
339
|
// Track waitlist joined event on the client
|
|
308
|
-
clientAnalytics.track(
|
|
340
|
+
clientAnalytics.track('waitlist_joined', {
|
|
309
341
|
email,
|
|
310
342
|
source: 'waitlist_page_form'
|
|
311
343
|
});
|
|
@@ -360,7 +392,6 @@ export const serverAnalytics = createServerAnalytics({
|
|
|
360
392
|
```typescript
|
|
361
393
|
// src/routes/api/join-waitlist/+server.ts
|
|
362
394
|
import { serverAnalytics } from '$lib/server/analytics';
|
|
363
|
-
import { AppEvents } from '$lib/config/analytics'; // Import AppEvents
|
|
364
395
|
import { json, type RequestHandler } from '@sveltejs/kit';
|
|
365
396
|
|
|
366
397
|
async function approveUserForWaitlist(email: string): Promise<{ userId: string }> {
|
|
@@ -382,7 +413,7 @@ export const POST: RequestHandler = async ({ request }) => {
|
|
|
382
413
|
|
|
383
414
|
const { userId } = await approveUserForWaitlist(email);
|
|
384
415
|
|
|
385
|
-
serverAnalytics.track(
|
|
416
|
+
serverAnalytics.track('waitlist_approved', {
|
|
386
417
|
userId,
|
|
387
418
|
email
|
|
388
419
|
}, {
|
|
@@ -414,55 +445,6 @@ export const POST: RequestHandler = async ({ request }) => {
|
|
|
414
445
|
};
|
|
415
446
|
```
|
|
416
447
|
|
|
417
|
-
## Advanced Usage
|
|
418
|
-
|
|
419
|
-
### Creating a Typed Analytics Service
|
|
420
|
-
|
|
421
|
-
For better type safety across your application, create a typed wrapper:
|
|
422
|
-
|
|
423
|
-
```typescript
|
|
424
|
-
import {
|
|
425
|
-
BrowserAnalytics,
|
|
426
|
-
ServerAnalytics,
|
|
427
|
-
ExtractEventNames,
|
|
428
|
-
ExtractEventPropertiesFromCollection
|
|
429
|
-
} from '@stacksee/analytics';
|
|
430
|
-
import { AppEvents } from './events';
|
|
431
|
-
|
|
432
|
-
// Type aliases for your app
|
|
433
|
-
type AppEventName = ExtractEventNames<typeof AppEvents>;
|
|
434
|
-
type AppEventProps<T extends AppEventName> = ExtractEventPropertiesFromCollection<typeof AppEvents, T>;
|
|
435
|
-
|
|
436
|
-
// Client-side typed wrapper
|
|
437
|
-
export class AppAnalytics {
|
|
438
|
-
constructor(private analytics: BrowserAnalytics) {}
|
|
439
|
-
|
|
440
|
-
track<T extends AppEventName>(
|
|
441
|
-
eventName: T,
|
|
442
|
-
properties: AppEventProps<T>
|
|
443
|
-
): Promise<void> {
|
|
444
|
-
return this.analytics.track(eventName, properties);
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
// ... other methods
|
|
448
|
-
}
|
|
449
|
-
|
|
450
|
-
// Server-side typed wrapper
|
|
451
|
-
export class ServerAppAnalytics {
|
|
452
|
-
constructor(private analytics: ServerAnalytics) {}
|
|
453
|
-
|
|
454
|
-
track<T extends AppEventName>(
|
|
455
|
-
eventName: T,
|
|
456
|
-
properties: AppEventProps<T>,
|
|
457
|
-
options?: { userId?: string; sessionId?: string }
|
|
458
|
-
): Promise<void> {
|
|
459
|
-
return this.analytics.track(eventName, properties, options);
|
|
460
|
-
}
|
|
461
|
-
|
|
462
|
-
// ... other methods
|
|
463
|
-
}
|
|
464
|
-
```
|
|
465
|
-
|
|
466
448
|
### Event Categories
|
|
467
449
|
|
|
468
450
|
Event categories help organize your analytics data. The SDK provides predefined categories with TypeScript autocomplete:
|
|
@@ -478,7 +460,7 @@ Event categories help organize your analytics data. The SDK provides predefined
|
|
|
478
460
|
You can also use **custom categories** for your specific needs:
|
|
479
461
|
|
|
480
462
|
```typescript
|
|
481
|
-
export const
|
|
463
|
+
export const appEvents = {
|
|
482
464
|
aiResponse: {
|
|
483
465
|
name: 'ai_response_generated',
|
|
484
466
|
category: 'ai', // Custom category
|
|
@@ -536,7 +518,7 @@ export class GoogleAnalyticsProvider extends BaseAnalyticsProvider {
|
|
|
536
518
|
Then use it as a plugin in your configuration:
|
|
537
519
|
|
|
538
520
|
```typescript
|
|
539
|
-
const analytics = await createClientAnalytics({
|
|
521
|
+
const analytics = await createClientAnalytics<typeof AppEvents>({
|
|
540
522
|
providers: [
|
|
541
523
|
new PostHogClientProvider({ apiKey: 'xxx' }),
|
|
542
524
|
new GoogleAnalyticsProvider({ measurementId: 'xxx' })
|
|
@@ -588,7 +570,7 @@ Then use the appropriate provider based on your environment:
|
|
|
588
570
|
import { createClientAnalytics } from '@stacksee/analytics/client';
|
|
589
571
|
import { MixpanelClientProvider } from './providers/mixpanel-client';
|
|
590
572
|
|
|
591
|
-
const clientAnalytics = createClientAnalytics({
|
|
573
|
+
const clientAnalytics = createClientAnalytics<typeof AppEvents>({
|
|
592
574
|
providers: [
|
|
593
575
|
new MixpanelClientProvider({ projectToken: 'xxx' })
|
|
594
576
|
]
|
|
@@ -598,7 +580,7 @@ const clientAnalytics = createClientAnalytics({
|
|
|
598
580
|
import { createServerAnalytics } from '@stacksee/analytics/server';
|
|
599
581
|
import { MixpanelServerProvider } from './providers/mixpanel-server';
|
|
600
582
|
|
|
601
|
-
const serverAnalytics = createServerAnalytics({
|
|
583
|
+
const serverAnalytics = createServerAnalytics<typeof AppEvents>({
|
|
602
584
|
providers: [
|
|
603
585
|
new MixpanelServerProvider({
|
|
604
586
|
projectToken: 'xxx',
|
|
@@ -625,7 +607,7 @@ import { PostHogClientProvider } from '@stacksee/analytics/providers/posthog';
|
|
|
625
607
|
import { GoogleAnalyticsProvider } from './providers/google-analytics';
|
|
626
608
|
import { MixpanelProvider } from './providers/mixpanel';
|
|
627
609
|
|
|
628
|
-
const analytics = createClientAnalytics({
|
|
610
|
+
const analytics = createClientAnalytics<typeof AppEvents>({
|
|
629
611
|
providers: [
|
|
630
612
|
// PostHog for product analytics
|
|
631
613
|
new PostHogClientProvider({
|
|
@@ -666,7 +648,7 @@ Vercel provides a `waitUntil` API that allows you to continue processing after t
|
|
|
666
648
|
import { waitUntil } from '@vercel/functions';
|
|
667
649
|
|
|
668
650
|
export default async function handler(req, res) {
|
|
669
|
-
const analytics = createServerAnalytics({
|
|
651
|
+
const analytics = createServerAnalytics<typeof AppEvents>({
|
|
670
652
|
providers: [new PostHogServerProvider({ apiKey: process.env.POSTHOG_API_KEY })]
|
|
671
653
|
});
|
|
672
654
|
|
|
@@ -695,7 +677,7 @@ Cloudflare Workers provides a `waitUntil` method on the execution context:
|
|
|
695
677
|
```typescript
|
|
696
678
|
export default {
|
|
697
679
|
async fetch(request, env, ctx) {
|
|
698
|
-
const analytics = createServerAnalytics({
|
|
680
|
+
const analytics = createServerAnalytics<typeof AppEvents>({
|
|
699
681
|
providers: [new PostHogServerProvider({ apiKey: env.POSTHOG_API_KEY })]
|
|
700
682
|
});
|
|
701
683
|
|
|
@@ -724,7 +706,7 @@ Netlify Functions also support `waitUntil` through their context object:
|
|
|
724
706
|
|
|
725
707
|
```typescript
|
|
726
708
|
export async function handler(event, context) {
|
|
727
|
-
const analytics = createServerAnalytics({
|
|
709
|
+
const analytics = createServerAnalytics<AppEvents>({
|
|
728
710
|
providers: [new PostHogServerProvider({ apiKey: process.env.POSTHOG_API_KEY })]
|
|
729
711
|
});
|
|
730
712
|
|
|
@@ -758,15 +740,24 @@ export async function handler(event, context) {
|
|
|
758
740
|
|
|
759
741
|
### Client API
|
|
760
742
|
|
|
761
|
-
#### `createClientAnalytics(config)`
|
|
762
|
-
Initialize analytics for browser environment.
|
|
743
|
+
#### `createClientAnalytics<TEvents>(config)`
|
|
744
|
+
Initialize analytics for browser environment with optional type-safe events.
|
|
763
745
|
|
|
746
|
+
- `TEvents` - (optional) Your event collection type for full type safety
|
|
764
747
|
- `config.providers` - Array of analytics provider instances
|
|
765
748
|
- `config.debug` - Enable debug logging
|
|
766
749
|
- `config.enabled` - Enable/disable analytics
|
|
767
750
|
|
|
768
|
-
|
|
769
|
-
|
|
751
|
+
```typescript
|
|
752
|
+
const analytics = createClientAnalytics<typeof AppEvents>({
|
|
753
|
+
providers: [/* ... */],
|
|
754
|
+
debug: true,
|
|
755
|
+
enabled: true
|
|
756
|
+
});
|
|
757
|
+
```
|
|
758
|
+
|
|
759
|
+
#### `BrowserAnalytics<TEventMap>`
|
|
760
|
+
- `track(eventName, properties): Promise<void>` - Track an event with type-safe event names and properties
|
|
770
761
|
- `identify(userId, traits)` - Identify a user
|
|
771
762
|
- `page(properties)` - Track a page view
|
|
772
763
|
- `reset()` - Reset user session
|
|
@@ -774,15 +765,24 @@ Initialize analytics for browser environment.
|
|
|
774
765
|
|
|
775
766
|
### Server API
|
|
776
767
|
|
|
777
|
-
#### `createServerAnalytics(config)`
|
|
778
|
-
Create analytics instance for server environment.
|
|
768
|
+
#### `createServerAnalytics<TEvents>(config)`
|
|
769
|
+
Create analytics instance for server environment with optional type-safe events.
|
|
779
770
|
|
|
771
|
+
- `TEvents` - (optional) Your event collection type for full type safety
|
|
780
772
|
- `config.providers` - Array of analytics provider instances
|
|
781
773
|
- `config.debug` - Enable debug logging
|
|
782
774
|
- `config.enabled` - Enable/disable analytics
|
|
783
775
|
|
|
784
|
-
|
|
785
|
-
|
|
776
|
+
```typescript
|
|
777
|
+
const analytics = createServerAnalytics<AppEvents>({
|
|
778
|
+
providers: [/* ... */],
|
|
779
|
+
debug: true,
|
|
780
|
+
enabled: true
|
|
781
|
+
});
|
|
782
|
+
```
|
|
783
|
+
|
|
784
|
+
#### `ServerAnalytics<TEventMap>`
|
|
785
|
+
- `track(eventName, properties, options): Promise<void>` - Track an event with type-safe event names and properties
|
|
786
786
|
- `identify(userId, traits)` - Identify a user
|
|
787
787
|
- `page(properties, options)` - Track a page view
|
|
788
788
|
- `shutdown()` - Flush pending events and cleanup
|