@od-oneapp/analytics 2026.2.2001-canary.1 → 2026.2.2701-canary
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/README.md +83 -372
- package/catalogs.d.mts +1815 -0
- package/catalogs.d.mts.map +1 -0
- package/catalogs.mjs +443 -0
- package/catalogs.mjs.map +1 -0
- package/{chunk-DQk6qfdC.mjs → client-CMc1iZBB.mjs} +8 -1
- package/{client-uX7stpb0.mjs.map → client-CMc1iZBB.mjs.map} +1 -1
- package/client-next.d.mts +4 -8
- package/client-next.d.mts.map +1 -1
- package/client-next.mjs +69 -58
- package/client-next.mjs.map +1 -1
- package/client.d.mts +6 -25
- package/client.d.mts.map +1 -1
- package/client.mjs +24 -140
- package/client.mjs.map +1 -1
- package/{posthog-bootstrap-DkDBbvMJ.mjs → config-BX38D_1T.mjs} +344 -45
- package/config-BX38D_1T.mjs.map +1 -0
- package/{posthog-bootstrap-D7Ot--Qc.d.mts → config-CSo5ZON1.d.mts} +32 -9
- package/config-CSo5ZON1.d.mts.map +1 -0
- package/{console-CDP0gY0K.mjs → console-BAFQVsN6.mjs} +3 -5
- package/{console-CDP0gY0K.mjs.map → console-BAFQVsN6.mjs.map} +1 -1
- package/{core-C3oFD9Vr.mjs → core-DBLE5iTF.mjs} +5 -5
- package/core-DBLE5iTF.mjs.map +1 -0
- package/{index-CuDXrdLY.d.mts → index-BYVvvAQ8.d.mts} +23 -39
- package/index-BYVvvAQ8.d.mts.map +1 -0
- package/load-provider-IHnxEGhf.mjs +87 -0
- package/load-provider-IHnxEGhf.mjs.map +1 -0
- package/load-provider-L0Smj7SY.d.mts +9 -0
- package/load-provider-L0Smj7SY.d.mts.map +1 -0
- package/{manager-Dh9loalA.d.mts → manager-B0CnygV0.d.mts} +19 -3
- package/manager-B0CnygV0.d.mts.map +1 -0
- package/package.json +38 -31
- package/providers-http-client.d.mts +1 -1
- package/providers-http-client.mjs +1 -1
- package/providers-http-server.d.mts +1 -1
- package/providers-http-server.mjs +1 -1
- package/server-next.d.mts +6 -66
- package/server-next.mjs +4 -192
- package/server.d.mts +6 -10
- package/server.mjs +4 -6
- package/{service-tn0JFfVH.mjs → service-DWQIRSGX.mjs} +31 -275
- package/service-DWQIRSGX.mjs.map +1 -0
- package/{types-BbXOa_UL.d.mts → types-C12o4SgZ.d.mts} +2 -87
- package/types-C12o4SgZ.d.mts.map +1 -0
- package/types.d.mts +3 -4
- package/types.mjs +3 -0
- package/validation-DSvytucA.mjs +258 -0
- package/validation-DSvytucA.mjs.map +1 -0
- package/ai-BSaTnqoc.mjs +0 -3347
- package/ai-BSaTnqoc.mjs.map +0 -1
- package/client-B0v807xN.mjs +0 -267
- package/client-B0v807xN.mjs.map +0 -1
- package/client-BrLI6DF9.mjs +0 -54
- package/client-BrLI6DF9.mjs.map +0 -1
- package/client-ClA-Qeks.mjs +0 -296
- package/client-ClA-Qeks.mjs.map +0 -1
- package/client-uX7stpb0.mjs +0 -9
- package/config-BA1zbRTh.d.mts +0 -34
- package/config-BA1zbRTh.d.mts.map +0 -1
- package/config-DKN8G0TI.mjs +0 -287
- package/config-DKN8G0TI.mjs.map +0 -1
- package/core-C3oFD9Vr.mjs.map +0 -1
- package/ecommerce-DAo98u3I.mjs +0 -993
- package/ecommerce-DAo98u3I.mjs.map +0 -1
- package/emitters-B2gDJtjd.d.mts +0 -12
- package/emitters-B2gDJtjd.d.mts.map +0 -1
- package/emitters-RheHbeX2.mjs +0 -208
- package/emitters-RheHbeX2.mjs.map +0 -1
- package/index-Bq051UsT.d.mts +0 -184
- package/index-Bq051UsT.d.mts.map +0 -1
- package/index-CuDXrdLY.d.mts.map +0 -1
- package/index-uQHwlV0P.d.mts +0 -953
- package/index-uQHwlV0P.d.mts.map +0 -1
- package/logs-8LsA--uG.mjs +0 -112
- package/logs-8LsA--uG.mjs.map +0 -1
- package/manager-Dh9loalA.d.mts.map +0 -1
- package/module-D5xR4CAy.mjs +0 -5808
- package/module-D5xR4CAy.mjs.map +0 -1
- package/posthog-bootstrap-D7Ot--Qc.d.mts.map +0 -1
- package/posthog-bootstrap-DkDBbvMJ.mjs.map +0 -1
- package/server-edge.d.mts +0 -9
- package/server-edge.d.mts.map +0 -1
- package/server-edge.mjs +0 -373
- package/server-edge.mjs.map +0 -1
- package/server-next.d.mts.map +0 -1
- package/server-next.mjs.map +0 -1
- package/service-tn0JFfVH.mjs.map +0 -1
- package/shared.d.mts +0 -16
- package/shared.d.mts.map +0 -1
- package/shared.mjs +0 -93
- package/shared.mjs.map +0 -1
- package/types-BbXOa_UL.d.mts.map +0 -1
- package/types-DC5uYgdR.d.mts +0 -216
- package/types-DC5uYgdR.d.mts.map +0 -1
- package/vercel-types-tUdlBxJ-.d.mts +0 -102
- package/vercel-types-tUdlBxJ-.d.mts.map +0 -1
package/README.md
CHANGED
|
@@ -1,99 +1,45 @@
|
|
|
1
|
-
# @
|
|
1
|
+
# @od-oneapp/analytics
|
|
2
2
|
|
|
3
|
-
> **Multi-provider analytics
|
|
4
|
-
> analytics**
|
|
3
|
+
> **Multi-provider analytics with Segment.io-style fan-out, type-safe event tracking, and Zod-validated catalogs**
|
|
5
4
|
|
|
6
5
|
[](https://www.typescriptlang.org/)
|
|
7
6
|
[](https://nodejs.org/)
|
|
8
7
|
|
|
9
8
|
## Quick Reference
|
|
10
9
|
|
|
11
|
-
**Status:** Development (Tests passing: 634/655, TypeCheck: ✅)
|
|
12
|
-
|
|
13
10
|
**Requirements:**
|
|
14
11
|
|
|
15
|
-
- Node.js 22.0.0+
|
|
12
|
+
- Node.js 22.0.0+
|
|
16
13
|
- pnpm 10.0.0+
|
|
17
14
|
- Next.js 15.0.0+ (if using Next.js integration)
|
|
18
15
|
|
|
19
16
|
**Exports:**
|
|
20
17
|
|
|
21
|
-
- **
|
|
22
|
-
- **
|
|
18
|
+
- **Client**: `./client`, `./client/next`
|
|
19
|
+
- **Server**: `./server`, `./server/next`
|
|
20
|
+
- **Types**: `./types`
|
|
21
|
+
- **Catalogs**: `./catalogs`
|
|
22
|
+
- **HTTP Provider**: `./providers/http`, `./providers/http/client`, `./providers/http/server`
|
|
23
23
|
|
|
24
24
|
**Key Features:**
|
|
25
25
|
|
|
26
|
-
-
|
|
27
|
-
-
|
|
28
|
-
-
|
|
29
|
-
-
|
|
30
|
-
-
|
|
31
|
-
- ✅ Feature Flags (PostHog integration)
|
|
32
|
-
- ✅ Next.js 15 (App Router, Server Components, hooks)
|
|
33
|
-
|
|
34
|
-
---
|
|
35
|
-
|
|
36
|
-
## Installation
|
|
37
|
-
|
|
38
|
-
### Prerequisites
|
|
39
|
-
|
|
40
|
-
⚠️ **Required:** Node.js 22+ (package uses `structuredClone`, `AbortSignal.timeout`, `process.hrtime.bigint`)
|
|
41
|
-
|
|
42
|
-
```bash
|
|
43
|
-
# Check Node version
|
|
44
|
-
node --version # Must be v22.0.0 or higher
|
|
45
|
-
|
|
46
|
-
# Install package
|
|
47
|
-
pnpm add @repo/analytics --filter=your-app
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
### Install Providers (Peer Dependencies)
|
|
51
|
-
|
|
52
|
-
Install only the providers you need:
|
|
53
|
-
|
|
54
|
-
```bash
|
|
55
|
-
# PostHog (recommended - analytics + feature flags)
|
|
56
|
-
pnpm add posthog-js posthog-node --filter=your-app
|
|
57
|
-
|
|
58
|
-
# Vercel Analytics
|
|
59
|
-
pnpm add @vercel/analytics --filter=your-app
|
|
60
|
-
|
|
61
|
-
# Segment
|
|
62
|
-
pnpm add @segment/analytics-next --filter=your-app
|
|
63
|
-
|
|
64
|
-
# Console (built-in, no installation needed)
|
|
65
|
-
```
|
|
26
|
+
- Multi-Provider fan-out (PostHog, Segment, Vercel Analytics, HTTP, Console)
|
|
27
|
+
- Type-Safe Emitters (Segment.io specification)
|
|
28
|
+
- Zod-validated event catalogs (ecommerce, AI)
|
|
29
|
+
- Universal (client/server environments)
|
|
30
|
+
- Next.js App Router integration (hooks, components, provider)
|
|
66
31
|
|
|
67
32
|
---
|
|
68
33
|
|
|
69
34
|
## Quick Start
|
|
70
35
|
|
|
71
|
-
### Environment Variables
|
|
72
|
-
|
|
73
|
-
```bash
|
|
74
|
-
# .env.local
|
|
75
|
-
|
|
76
|
-
# PostHog (Primary)
|
|
77
|
-
NEXT_PUBLIC_POSTHOG_KEY=phc_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
|
78
|
-
NEXT_PUBLIC_POSTHOG_HOST=https://app.posthog.com
|
|
79
|
-
|
|
80
|
-
# Vercel Analytics (Optional)
|
|
81
|
-
VERCEL_ANALYTICS_ID=your-analytics-id
|
|
82
|
-
|
|
83
|
-
# Segment (Optional)
|
|
84
|
-
NEXT_PUBLIC_SEGMENT_WRITE_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
|
85
|
-
|
|
86
|
-
# Development
|
|
87
|
-
NEXT_PUBLIC_CONSOLE_ANALYTICS=true
|
|
88
|
-
```
|
|
89
|
-
|
|
90
36
|
### Next.js Setup
|
|
91
37
|
|
|
92
38
|
```tsx
|
|
93
39
|
// app/providers.tsx
|
|
94
40
|
"use client";
|
|
95
41
|
|
|
96
|
-
import { AnalyticsProvider } from "@
|
|
42
|
+
import { AnalyticsProvider } from "@od-oneapp/analytics/client/next";
|
|
97
43
|
|
|
98
44
|
export function Providers({ children }: { children: React.ReactNode }) {
|
|
99
45
|
return (
|
|
@@ -104,14 +50,14 @@ export function Providers({ children }: { children: React.ReactNode }) {
|
|
|
104
50
|
apiKey: process.env.NEXT_PUBLIC_POSTHOG_KEY!,
|
|
105
51
|
options: {
|
|
106
52
|
debug: process.env.NODE_ENV === "development",
|
|
107
|
-
capture_pageview: false
|
|
108
|
-
}
|
|
53
|
+
capture_pageview: false,
|
|
54
|
+
},
|
|
109
55
|
},
|
|
110
56
|
console: {
|
|
111
|
-
enabled: process.env.NODE_ENV === "development"
|
|
112
|
-
}
|
|
57
|
+
enabled: process.env.NODE_ENV === "development",
|
|
58
|
+
},
|
|
113
59
|
},
|
|
114
|
-
debug: process.env.NODE_ENV === "development"
|
|
60
|
+
debug: process.env.NODE_ENV === "development",
|
|
115
61
|
}}
|
|
116
62
|
>
|
|
117
63
|
{children}
|
|
@@ -120,118 +66,61 @@ export function Providers({ children }: { children: React.ReactNode }) {
|
|
|
120
66
|
}
|
|
121
67
|
```
|
|
122
68
|
|
|
123
|
-
###
|
|
124
|
-
|
|
125
|
-
#### Client Component
|
|
69
|
+
### Client Component
|
|
126
70
|
|
|
127
71
|
```tsx
|
|
128
72
|
"use client";
|
|
129
73
|
|
|
130
|
-
import { useAnalytics, track } from "@
|
|
74
|
+
import { useAnalytics, track } from "@od-oneapp/analytics/client/next";
|
|
131
75
|
|
|
132
76
|
export function SignupButton() {
|
|
133
77
|
const analytics = useAnalytics();
|
|
134
78
|
|
|
135
79
|
const handleClick = async () => {
|
|
136
|
-
//
|
|
137
|
-
await analytics
|
|
80
|
+
// Direct tracking
|
|
81
|
+
await analytics?.track("Button Clicked", { button_name: "signup" });
|
|
138
82
|
|
|
139
|
-
//
|
|
83
|
+
// Emitter pattern
|
|
140
84
|
const event = track("CTA Clicked", { cta_type: "signup" });
|
|
141
|
-
await analytics
|
|
85
|
+
await analytics?.emit(event);
|
|
142
86
|
};
|
|
143
87
|
|
|
144
88
|
return <button onClick={handleClick}>Sign Up</button>;
|
|
145
89
|
}
|
|
146
90
|
```
|
|
147
91
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
```tsx
|
|
151
|
-
// app/api/checkout/route.ts
|
|
152
|
-
import { createServerAnalytics, ecommerce } from "@repo/analytics/server/next";
|
|
153
|
-
|
|
154
|
-
export async function POST(request: Request) {
|
|
155
|
-
const analytics = await createServerAnalytics({
|
|
156
|
-
providers: {
|
|
157
|
-
posthog: { apiKey: process.env.POSTHOG_API_KEY! }
|
|
158
|
-
}
|
|
159
|
-
});
|
|
160
|
-
|
|
161
|
-
await analytics.emit(
|
|
162
|
-
ecommerce.CHECKOUT_STARTED({
|
|
163
|
-
order_id: "order_123",
|
|
164
|
-
value: 299.99,
|
|
165
|
-
currency: "USD",
|
|
166
|
-
products: [{ product_id: "prod_abc", price: 299.99, quantity: 1 }]
|
|
167
|
-
})
|
|
168
|
-
);
|
|
169
|
-
|
|
170
|
-
return Response.json({ success: true });
|
|
171
|
-
}
|
|
172
|
-
```
|
|
173
|
-
|
|
174
|
-
#### E-commerce Events
|
|
92
|
+
### Server (API Route)
|
|
175
93
|
|
|
176
94
|
```typescript
|
|
177
|
-
import {
|
|
178
|
-
|
|
179
|
-
// Product viewed
|
|
180
|
-
ecommerce.PRODUCT_VIEWED({
|
|
181
|
-
product_id: "prod_123",
|
|
182
|
-
name: "Premium Plan",
|
|
183
|
-
price: 299.99,
|
|
184
|
-
currency: "USD"
|
|
185
|
-
});
|
|
95
|
+
import { createServerAnalytics } from "@od-oneapp/analytics/server";
|
|
186
96
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
quantity: 1,
|
|
192
|
-
price: 299.99
|
|
97
|
+
const analytics = await createServerAnalytics({
|
|
98
|
+
providers: {
|
|
99
|
+
posthog: { apiKey: process.env.POSTHOG_API_KEY! },
|
|
100
|
+
},
|
|
193
101
|
});
|
|
194
102
|
|
|
195
|
-
|
|
196
|
-
ecommerce.ORDER_COMPLETED({
|
|
197
|
-
order_id: "order_789",
|
|
198
|
-
revenue: 499.97,
|
|
199
|
-
currency: "USD",
|
|
200
|
-
products: [
|
|
201
|
-
/* ... */
|
|
202
|
-
],
|
|
203
|
-
payment_method: "card"
|
|
204
|
-
});
|
|
103
|
+
await analytics.track("Order Completed", { orderId: "ord-123", total: 99.99 });
|
|
205
104
|
```
|
|
206
105
|
|
|
207
|
-
|
|
106
|
+
### Event Catalogs (Zod-validated)
|
|
208
107
|
|
|
209
108
|
```typescript
|
|
210
|
-
import {
|
|
109
|
+
import { ecommerceCatalog, aiCatalog } from "@od-oneapp/analytics/catalogs";
|
|
211
110
|
|
|
212
|
-
//
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
111
|
+
// Type-safe ecommerce events
|
|
112
|
+
const event = ecommerceCatalog.track("Product Viewed", {
|
|
113
|
+
product_id: "sku-123",
|
|
114
|
+
name: "Premium Plan",
|
|
115
|
+
price: 29.99,
|
|
116
|
+
currency: "USD",
|
|
218
117
|
});
|
|
219
118
|
|
|
220
|
-
//
|
|
221
|
-
|
|
222
|
-
conversation_id: "
|
|
119
|
+
// Type-safe AI events
|
|
120
|
+
const aiEvent = aiCatalog.track("Chat Message Sent", {
|
|
121
|
+
conversation_id: "conv-123",
|
|
223
122
|
model_id: "gpt-4",
|
|
224
|
-
|
|
225
|
-
attempt_number: 2,
|
|
226
|
-
reason: "user-requested"
|
|
227
|
-
});
|
|
228
|
-
|
|
229
|
-
// Conversation branched
|
|
230
|
-
ai.CONVERSATION_BRANCHED({
|
|
231
|
-
conversation_id: "conv_123",
|
|
232
|
-
parent_conversation_id: "conv_122",
|
|
233
|
-
branch_point_message_id: "msg_450",
|
|
234
|
-
reason: "explore-alternative"
|
|
123
|
+
message_length: 150,
|
|
235
124
|
});
|
|
236
125
|
```
|
|
237
126
|
|
|
@@ -239,39 +128,31 @@ ai.CONVERSATION_BRANCHED({
|
|
|
239
128
|
|
|
240
129
|
## Architecture
|
|
241
130
|
|
|
242
|
-
### Four-File Export Pattern
|
|
243
|
-
|
|
244
131
|
```
|
|
245
|
-
@
|
|
246
|
-
├── /client → Browser-only (
|
|
247
|
-
├── /server → Node.js server (
|
|
248
|
-
├── /client/next → Next.js client (hooks, provider, components)
|
|
249
|
-
├── /server/next → Next.js server (
|
|
250
|
-
├── /
|
|
251
|
-
|
|
132
|
+
@od-oneapp/analytics
|
|
133
|
+
├── /client → Browser-only (static provider registry)
|
|
134
|
+
├── /server → Node.js server (static provider registry)
|
|
135
|
+
├── /client/next → Next.js client (hooks, provider, components, dynamic imports)
|
|
136
|
+
├── /server/next → Next.js server (re-exports from /server)
|
|
137
|
+
├── /types → TypeScript types
|
|
138
|
+
├── /catalogs → Zod-validated event catalogs
|
|
139
|
+
└── /providers/http → Built-in HTTP provider
|
|
252
140
|
```
|
|
253
141
|
|
|
254
142
|
**Import Rules:**
|
|
255
143
|
|
|
256
|
-
-
|
|
257
|
-
-
|
|
258
|
-
-
|
|
259
|
-
-
|
|
260
|
-
|
|
261
|
-
**Edge Runtime Limitations:**
|
|
144
|
+
- Client components: `@od-oneapp/analytics/client/next`
|
|
145
|
+
- Server components/API routes: `@od-oneapp/analytics/server/next`
|
|
146
|
+
- Non-Next.js client: `@od-oneapp/analytics/client`
|
|
147
|
+
- Non-Next.js server: `@od-oneapp/analytics/server`
|
|
262
148
|
|
|
263
|
-
|
|
149
|
+
**Provider Architecture:**
|
|
264
150
|
|
|
265
|
-
|
|
266
|
-
-
|
|
267
|
-
-
|
|
268
|
-
-
|
|
269
|
-
-
|
|
270
|
-
- ❌ No rate limiting enforcement
|
|
271
|
-
- ❌ No feature flags (requires Node.js SDK)
|
|
272
|
-
- ❌ No batch processing optimization
|
|
273
|
-
|
|
274
|
-
For full features, use `/server` or `/server/next` in Node.js environments.
|
|
151
|
+
SDK providers live in integration packages:
|
|
152
|
+
- PostHog → `@od-oneapp/integration-posthog/analytics-provider`
|
|
153
|
+
- Segment → `@od-oneapp/integration-segment/analytics-provider`
|
|
154
|
+
- Vercel → `@od-oneapp/integration-vercel/analytics-provider`
|
|
155
|
+
- Console, HTTP → built-in (`src/providers/`)
|
|
275
156
|
|
|
276
157
|
---
|
|
277
158
|
|
|
@@ -280,230 +161,60 @@ For full features, use `/server` or `/server/next` in Node.js environments.
|
|
|
280
161
|
### Analytics Manager
|
|
281
162
|
|
|
282
163
|
```typescript
|
|
283
|
-
// Create analytics instance
|
|
284
164
|
const analytics = await createClientAnalytics(config);
|
|
285
165
|
|
|
286
|
-
// Track events
|
|
287
166
|
await analytics.track("Event Name", { property: "value" });
|
|
288
|
-
|
|
289
|
-
// Identify users
|
|
290
167
|
await analytics.identify("user_123", { email: "user@example.com" });
|
|
291
|
-
|
|
292
|
-
// Track page views
|
|
293
168
|
await analytics.page("/pricing", { title: "Pricing Page" });
|
|
294
|
-
|
|
295
|
-
// Group/organization
|
|
296
169
|
await analytics.group("org_456", { name: "Acme Corp" });
|
|
297
170
|
|
|
298
|
-
//
|
|
171
|
+
// Emitter pattern
|
|
299
172
|
const event = track("Event", { data: "value" });
|
|
300
173
|
await analytics.emit(event);
|
|
301
174
|
|
|
302
175
|
// Batch processing
|
|
303
|
-
await analytics.emitBatch([event1, event2, event3]
|
|
304
|
-
concurrency: 5,
|
|
305
|
-
failFast: false
|
|
306
|
-
});
|
|
176
|
+
await analytics.emitBatch([event1, event2, event3]);
|
|
307
177
|
```
|
|
308
178
|
|
|
309
179
|
### React Hooks
|
|
310
180
|
|
|
311
181
|
```typescript
|
|
312
|
-
// Access analytics manager
|
|
313
182
|
const analytics = useAnalytics();
|
|
183
|
+
const track = useTrackEvent();
|
|
184
|
+
const identify = useIdentifyUser();
|
|
314
185
|
|
|
315
|
-
|
|
316
|
-
useTrackEvent("Page Viewed", { page: "/dashboard" });
|
|
317
|
-
|
|
318
|
-
// Identify user on mount
|
|
319
|
-
useIdentifyUser(user.id, { email: user.email });
|
|
320
|
-
|
|
321
|
-
// Auto page tracking
|
|
322
|
-
usePageTracking();
|
|
186
|
+
usePageTracking({ trackSearch: true });
|
|
323
187
|
```
|
|
324
188
|
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
## Feature Flags (PostHog)
|
|
328
|
-
|
|
329
|
-
### Client-Side
|
|
330
|
-
|
|
331
|
-
```typescript
|
|
332
|
-
import { useAnalytics } from '@repo/analytics/client/next';
|
|
333
|
-
|
|
334
|
-
function FeatureFlag() {
|
|
335
|
-
const analytics = useAnalytics();
|
|
336
|
-
const provider = analytics.getProvider('posthog');
|
|
337
|
-
const [enabled, setEnabled] = useState(false);
|
|
338
|
-
|
|
339
|
-
useEffect(() => {
|
|
340
|
-
provider?.isFeatureEnabled('new-feature').then(setEnabled);
|
|
341
|
-
}, [provider]);
|
|
342
|
-
|
|
343
|
-
return enabled ? <NewFeature /> : <OldFeature />;
|
|
344
|
-
}
|
|
345
|
-
```
|
|
346
|
-
|
|
347
|
-
### Server-Side
|
|
189
|
+
### Tracked Components
|
|
348
190
|
|
|
349
191
|
```tsx
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
export default async function Page() {
|
|
354
|
-
const analytics = await createServerAnalytics({
|
|
355
|
-
providers: { posthog: { apiKey: process.env.POSTHOG_API_KEY! } }
|
|
356
|
-
});
|
|
357
|
-
|
|
358
|
-
const provider = analytics.getProvider("posthog");
|
|
359
|
-
const showFeature = await provider?.getFeatureFlag("new-feature", "user_123");
|
|
360
|
-
|
|
361
|
-
return <div>{showFeature ? <New /> : <Old />}</div>;
|
|
362
|
-
}
|
|
363
|
-
```
|
|
364
|
-
|
|
365
|
-
---
|
|
366
|
-
|
|
367
|
-
## Troubleshooting
|
|
368
|
-
|
|
369
|
-
### Common Issues
|
|
370
|
-
|
|
371
|
-
**"Analytics not initialized"**
|
|
372
|
-
|
|
373
|
-
- Ensure you await `createClientAnalytics()` or `createServerAnalytics()`
|
|
374
|
-
|
|
375
|
-
**"Provider not available in this environment"**
|
|
376
|
-
|
|
377
|
-
- Check you're using correct import path (client vs server vs edge)
|
|
192
|
+
<TrackedButton eventName="Sign Up Clicked" properties={{ location: "header" }}>
|
|
193
|
+
Sign Up
|
|
194
|
+
</TrackedButton>
|
|
378
195
|
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
- Enable debug mode: `options: { debug: true }`
|
|
383
|
-
- Check network tab for failed requests
|
|
384
|
-
|
|
385
|
-
**"structuredClone is not defined"**
|
|
386
|
-
|
|
387
|
-
- Upgrade to Node.js 22+ (required)
|
|
388
|
-
|
|
389
|
-
### Debug Mode
|
|
390
|
-
|
|
391
|
-
```typescript
|
|
392
|
-
const analytics = await createClientAnalytics({
|
|
393
|
-
providers: {
|
|
394
|
-
posthog: {
|
|
395
|
-
apiKey: "...",
|
|
396
|
-
options: { debug: true }
|
|
397
|
-
}
|
|
398
|
-
},
|
|
399
|
-
debug: true,
|
|
400
|
-
onInfo: (msg) => console.log("[Analytics]", msg),
|
|
401
|
-
onError: (err, ctx) => console.error("[Analytics Error]", err, ctx)
|
|
402
|
-
});
|
|
403
|
-
```
|
|
404
|
-
|
|
405
|
-
### Health Check
|
|
406
|
-
|
|
407
|
-
```typescript
|
|
408
|
-
const health = await analytics.healthCheck(5000);
|
|
409
|
-
console.log("Healthy:", health.healthy);
|
|
410
|
-
console.log("Providers:", health.providers);
|
|
196
|
+
<TrackedLink href="/products" eventName="Product Link Clicked">
|
|
197
|
+
View Products
|
|
198
|
+
</TrackedLink>
|
|
411
199
|
```
|
|
412
200
|
|
|
413
201
|
---
|
|
414
202
|
|
|
415
203
|
## Security
|
|
416
204
|
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
4. **Rotate keys** - Update API keys periodically
|
|
423
|
-
|
|
424
|
-
**Security Features (Implemented):**
|
|
425
|
-
|
|
426
|
-
- ✅ Input sanitization (`sanitizeProperties()`)
|
|
427
|
-
- ✅ PII detection and redaction (`containsPII()`, `redactPII()`)
|
|
428
|
-
- ✅ XSS protection (`stripHTML()`)
|
|
429
|
-
- ✅ Payload size limits (default: 100KB max)
|
|
430
|
-
- ✅ Dangerous key blocking (prevents `__proto__`, `constructor`)
|
|
431
|
-
- ✅ Rate limiting (token bucket algorithm, 100 calls/second default)
|
|
432
|
-
|
|
433
|
-
**Usage:**
|
|
434
|
-
|
|
435
|
-
```typescript
|
|
436
|
-
import { sanitizeProperties, containsPII } from "@repo/analytics/server";
|
|
437
|
-
|
|
438
|
-
// Sanitize before tracking
|
|
439
|
-
const sanitized = sanitizeProperties(userInput, {
|
|
440
|
-
stripPII: true,
|
|
441
|
-
stripHTML: true,
|
|
442
|
-
maxPayloadSize: 50_000 // 50KB
|
|
443
|
-
});
|
|
444
|
-
|
|
445
|
-
// Check for PII
|
|
446
|
-
if (containsPII(JSON.stringify(properties))) {
|
|
447
|
-
console.warn("PII detected in analytics payload");
|
|
448
|
-
}
|
|
449
|
-
```
|
|
450
|
-
|
|
451
|
-
---
|
|
452
|
-
|
|
453
|
-
## Documentation
|
|
454
|
-
|
|
455
|
-
- **Full Documentation**: [Analytics Package Docs](../../apps/docs/packages/analytics.mdx)
|
|
456
|
-
- **Audit Findings**: [AUDIT_FINDINGS.md](./AUDIT_FINDINGS.md)
|
|
457
|
-
- **API Reference**: See source code JSDoc comments
|
|
458
|
-
- **Examples**: [`src/examples/`](./src/examples/)
|
|
205
|
+
- Input sanitization (`sanitizeProperties()`)
|
|
206
|
+
- PII detection and redaction (`containsPII()`, `redactPII()`)
|
|
207
|
+
- XSS protection (`stripHTML()`)
|
|
208
|
+
- Payload size limits (default: 100KB max)
|
|
209
|
+
- Rate limiting (token bucket algorithm)
|
|
459
210
|
|
|
460
211
|
---
|
|
461
212
|
|
|
462
213
|
## Development
|
|
463
214
|
|
|
464
215
|
```bash
|
|
465
|
-
|
|
466
|
-
pnpm
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
pnpm --filter=@repo/analytics test
|
|
470
|
-
|
|
471
|
-
# Type check
|
|
472
|
-
pnpm --filter=@repo/analytics typecheck
|
|
473
|
-
|
|
474
|
-
# Lint
|
|
475
|
-
pnpm --filter=@repo/analytics lint
|
|
476
|
-
|
|
477
|
-
# Coverage
|
|
478
|
-
pnpm --filter=@repo/analytics test:coverage
|
|
479
|
-
|
|
480
|
-
# Check circular deps
|
|
481
|
-
pnpm --filter=@repo/analytics circular
|
|
216
|
+
pnpm --filter @od-oneapp/analytics test
|
|
217
|
+
pnpm --filter @od-oneapp/analytics typecheck
|
|
218
|
+
pnpm --filter @od-oneapp/analytics lint
|
|
219
|
+
pnpm --filter @od-oneapp/analytics build
|
|
482
220
|
```
|
|
483
|
-
|
|
484
|
-
---
|
|
485
|
-
|
|
486
|
-
## Support
|
|
487
|
-
|
|
488
|
-
- **Issues**: [GitHub Issues](https://github.com/your-org/monorepo/issues)
|
|
489
|
-
- **Discussions**: [GitHub Discussions](https://github.com/your-org/monorepo/discussions)
|
|
490
|
-
|
|
491
|
-
---
|
|
492
|
-
|
|
493
|
-
## License
|
|
494
|
-
|
|
495
|
-
MIT License
|
|
496
|
-
|
|
497
|
-
---
|
|
498
|
-
|
|
499
|
-
**Built with ❤️ by the Platform Team**
|
|
500
|
-
|
|
501
|
-
## 📚 Comprehensive Documentation
|
|
502
|
-
|
|
503
|
-
For detailed documentation, see:
|
|
504
|
-
|
|
505
|
-
- **[Audit Reports](../../apps/docs/content/docs/audits/analytics/)** - Comprehensive audits, fixes, and security
|
|
506
|
-
reviews
|
|
507
|
-
- **[Technical Guides](../../apps/docs/content/docs/packages/analytics/)** - Implementation guides and best practices
|
|
508
|
-
|
|
509
|
-
All comprehensive documentation has been centralized in the docs app.
|