@od-oneapp/analytics 2026.1.1301
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 +509 -0
- package/dist/ai-YMnynb-t.mjs +3347 -0
- package/dist/ai-YMnynb-t.mjs.map +1 -0
- package/dist/chunk-DQk6qfdC.mjs +18 -0
- package/dist/client-CTzJVFU5.mjs +9 -0
- package/dist/client-CTzJVFU5.mjs.map +1 -0
- package/dist/client-CcFTauAh.mjs +54 -0
- package/dist/client-CcFTauAh.mjs.map +1 -0
- package/dist/client-CeOLjbac.mjs +281 -0
- package/dist/client-CeOLjbac.mjs.map +1 -0
- package/dist/client-D339NFJS.mjs +267 -0
- package/dist/client-D339NFJS.mjs.map +1 -0
- package/dist/client-next.d.mts +62 -0
- package/dist/client-next.d.mts.map +1 -0
- package/dist/client-next.mjs +525 -0
- package/dist/client-next.mjs.map +1 -0
- package/dist/client.d.mts +30 -0
- package/dist/client.d.mts.map +1 -0
- package/dist/client.mjs +186 -0
- package/dist/client.mjs.map +1 -0
- package/dist/config-DPS6bSYo.d.mts +34 -0
- package/dist/config-DPS6bSYo.d.mts.map +1 -0
- package/dist/config-P6P5adJg.mjs +287 -0
- package/dist/config-P6P5adJg.mjs.map +1 -0
- package/dist/console-8bND3mMU.mjs +128 -0
- package/dist/console-8bND3mMU.mjs.map +1 -0
- package/dist/ecommerce-Cgu4wlux.mjs +993 -0
- package/dist/ecommerce-Cgu4wlux.mjs.map +1 -0
- package/dist/emitters-6-nKo8i-.mjs +208 -0
- package/dist/emitters-6-nKo8i-.mjs.map +1 -0
- package/dist/emitters-DldkVSPp.d.mts +12 -0
- package/dist/emitters-DldkVSPp.d.mts.map +1 -0
- package/dist/index-BfNWgfa5.d.mts +1494 -0
- package/dist/index-BfNWgfa5.d.mts.map +1 -0
- package/dist/index-BkIWe--N.d.mts +953 -0
- package/dist/index-BkIWe--N.d.mts.map +1 -0
- package/dist/index-jPzXRn52.d.mts +184 -0
- package/dist/index-jPzXRn52.d.mts.map +1 -0
- package/dist/manager-DvRRjza6.d.mts +76 -0
- package/dist/manager-DvRRjza6.d.mts.map +1 -0
- package/dist/posthog-bootstrap-CYfIy_WS.mjs +1769 -0
- package/dist/posthog-bootstrap-CYfIy_WS.mjs.map +1 -0
- package/dist/posthog-bootstrap-DWxFrxlt.d.mts +81 -0
- package/dist/posthog-bootstrap-DWxFrxlt.d.mts.map +1 -0
- package/dist/providers-http-client.d.mts +37 -0
- package/dist/providers-http-client.d.mts.map +1 -0
- package/dist/providers-http-client.mjs +320 -0
- package/dist/providers-http-client.mjs.map +1 -0
- package/dist/providers-http-server.d.mts +31 -0
- package/dist/providers-http-server.d.mts.map +1 -0
- package/dist/providers-http-server.mjs +297 -0
- package/dist/providers-http-server.mjs.map +1 -0
- package/dist/providers-http.d.mts +46 -0
- package/dist/providers-http.d.mts.map +1 -0
- package/dist/providers-http.mjs +4 -0
- package/dist/server-edge.d.mts +9 -0
- package/dist/server-edge.d.mts.map +1 -0
- package/dist/server-edge.mjs +373 -0
- package/dist/server-edge.mjs.map +1 -0
- package/dist/server-next.d.mts +67 -0
- package/dist/server-next.d.mts.map +1 -0
- package/dist/server-next.mjs +193 -0
- package/dist/server-next.mjs.map +1 -0
- package/dist/server.d.mts +10 -0
- package/dist/server.mjs +7 -0
- package/dist/service-cYtBBL8x.mjs +945 -0
- package/dist/service-cYtBBL8x.mjs.map +1 -0
- package/dist/shared.d.mts +16 -0
- package/dist/shared.d.mts.map +1 -0
- package/dist/shared.mjs +93 -0
- package/dist/shared.mjs.map +1 -0
- package/dist/types-BxBnNQ0V.d.mts +354 -0
- package/dist/types-BxBnNQ0V.d.mts.map +1 -0
- package/dist/types-CBvxUEaF.d.mts +216 -0
- package/dist/types-CBvxUEaF.d.mts.map +1 -0
- package/dist/types.d.mts +4 -0
- package/dist/types.mjs +0 -0
- package/dist/vercel-types-lwakUfoI.d.mts +102 -0
- package/dist/vercel-types-lwakUfoI.d.mts.map +1 -0
- package/package.json +129 -0
- package/src/client/index.ts +164 -0
- package/src/client/manager.ts +71 -0
- package/src/client/next/components.tsx +270 -0
- package/src/client/next/hooks.ts +217 -0
- package/src/client/next/manager.ts +141 -0
- package/src/client/next.ts +144 -0
- package/src/client-next.ts +101 -0
- package/src/client.ts +89 -0
- package/src/examples/ai-sdk-patterns.ts +583 -0
- package/src/examples/emitter-patterns.ts +476 -0
- package/src/examples/nextjs-emitter-patterns.tsx +403 -0
- package/src/next/app-router.tsx +564 -0
- package/src/next/client.ts +419 -0
- package/src/next/index.ts +84 -0
- package/src/next/middleware.ts +429 -0
- package/src/next/rsc.tsx +300 -0
- package/src/next/server.ts +253 -0
- package/src/next/types.d.ts +220 -0
- package/src/providers/base-provider.ts +419 -0
- package/src/providers/console/client.ts +10 -0
- package/src/providers/console/index.ts +152 -0
- package/src/providers/console/server.ts +6 -0
- package/src/providers/console/types.ts +15 -0
- package/src/providers/http/client.ts +464 -0
- package/src/providers/http/index.ts +30 -0
- package/src/providers/http/server.ts +396 -0
- package/src/providers/http/types.ts +135 -0
- package/src/providers/posthog/client.ts +518 -0
- package/src/providers/posthog/index.ts +11 -0
- package/src/providers/posthog/server.ts +329 -0
- package/src/providers/posthog/types.ts +104 -0
- package/src/providers/segment/client.ts +113 -0
- package/src/providers/segment/index.ts +11 -0
- package/src/providers/segment/server.ts +115 -0
- package/src/providers/segment/types.ts +51 -0
- package/src/providers/vercel/client.ts +102 -0
- package/src/providers/vercel/index.ts +11 -0
- package/src/providers/vercel/server.ts +89 -0
- package/src/providers/vercel/types.ts +27 -0
- package/src/server/index.ts +103 -0
- package/src/server/manager.ts +62 -0
- package/src/server/next.ts +210 -0
- package/src/server-edge.ts +442 -0
- package/src/server-next.ts +39 -0
- package/src/server.ts +106 -0
- package/src/shared/emitters/ai/README.md +981 -0
- package/src/shared/emitters/ai/events/agent.ts +130 -0
- package/src/shared/emitters/ai/events/artifacts.ts +167 -0
- package/src/shared/emitters/ai/events/chat.ts +126 -0
- package/src/shared/emitters/ai/events/chatbot-ecommerce.ts +133 -0
- package/src/shared/emitters/ai/events/completion.ts +103 -0
- package/src/shared/emitters/ai/events/content-generation.ts +347 -0
- package/src/shared/emitters/ai/events/conversation.ts +332 -0
- package/src/shared/emitters/ai/events/product-features.ts +1402 -0
- package/src/shared/emitters/ai/events/streaming.ts +114 -0
- package/src/shared/emitters/ai/events/tool.ts +93 -0
- package/src/shared/emitters/ai/index.ts +69 -0
- package/src/shared/emitters/ai/track-ai-sdk.ts +74 -0
- package/src/shared/emitters/ai/track-ai.ts +50 -0
- package/src/shared/emitters/ai/types.ts +1041 -0
- package/src/shared/emitters/ai/utils.ts +468 -0
- package/src/shared/emitters/ecommerce/events/cart-checkout.ts +106 -0
- package/src/shared/emitters/ecommerce/events/coupon.ts +49 -0
- package/src/shared/emitters/ecommerce/events/engagement.ts +61 -0
- package/src/shared/emitters/ecommerce/events/marketplace.ts +119 -0
- package/src/shared/emitters/ecommerce/events/order.ts +199 -0
- package/src/shared/emitters/ecommerce/events/product.ts +205 -0
- package/src/shared/emitters/ecommerce/events/registry.ts +123 -0
- package/src/shared/emitters/ecommerce/events/wishlist-sharing.ts +140 -0
- package/src/shared/emitters/ecommerce/index.ts +46 -0
- package/src/shared/emitters/ecommerce/track-ecommerce.ts +53 -0
- package/src/shared/emitters/ecommerce/types.ts +314 -0
- package/src/shared/emitters/ecommerce/utils.ts +216 -0
- package/src/shared/emitters/emitter-types.ts +974 -0
- package/src/shared/emitters/emitters.ts +292 -0
- package/src/shared/emitters/helpers.ts +419 -0
- package/src/shared/emitters/index.ts +66 -0
- package/src/shared/index.ts +142 -0
- package/src/shared/ingestion/index.ts +66 -0
- package/src/shared/ingestion/schemas.ts +386 -0
- package/src/shared/ingestion/service.ts +628 -0
- package/src/shared/node22-features.ts +848 -0
- package/src/shared/providers/console-provider.ts +160 -0
- package/src/shared/types/base-types.ts +54 -0
- package/src/shared/types/console-types.ts +19 -0
- package/src/shared/types/posthog-types.ts +131 -0
- package/src/shared/types/segment-types.ts +15 -0
- package/src/shared/types/types.ts +397 -0
- package/src/shared/types/vercel-types.ts +19 -0
- package/src/shared/utils/config-client.ts +19 -0
- package/src/shared/utils/config.ts +250 -0
- package/src/shared/utils/emitter-adapter.ts +212 -0
- package/src/shared/utils/manager.test.ts +36 -0
- package/src/shared/utils/manager.ts +1322 -0
- package/src/shared/utils/posthog-bootstrap.ts +136 -0
- package/src/shared/utils/posthog-client-utils.ts +48 -0
- package/src/shared/utils/posthog-next-utils.ts +282 -0
- package/src/shared/utils/posthog-server-utils.ts +210 -0
- package/src/shared/utils/rate-limit.ts +289 -0
- package/src/shared/utils/security.ts +545 -0
- package/src/shared/utils/validation-client.ts +161 -0
- package/src/shared/utils/validation.ts +399 -0
- package/src/shared.ts +155 -0
- package/src/types/index.ts +62 -0
|
@@ -0,0 +1,442 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Edge Runtime Analytics Module
|
|
3
|
+
*
|
|
4
|
+
* Provides edge-compatible analytics for Next.js middleware and edge API routes.
|
|
5
|
+
* Uses Web APIs and HTTP-based implementations compatible with edge runtime.
|
|
6
|
+
*
|
|
7
|
+
* **Supported Features**:
|
|
8
|
+
* - Basic event tracking (track, identify, page, group, alias)
|
|
9
|
+
* - Console provider (uses console API)
|
|
10
|
+
* - PostHog provider (HTTP-based, no SDK dependency)
|
|
11
|
+
* - Emitter pattern support via `emit()`
|
|
12
|
+
*
|
|
13
|
+
* **Limitations (Edge Runtime Constraints)**:
|
|
14
|
+
* - No Node.js APIs (fs, crypto, etc.)
|
|
15
|
+
* - No native modules or SDK dependencies
|
|
16
|
+
* - No event deduplication (no LRU cache)
|
|
17
|
+
* - No rate limiting (100 req/s limit not enforced)
|
|
18
|
+
* - No batch processing optimization
|
|
19
|
+
* - No performance metrics tracking
|
|
20
|
+
* - No feature flags (PostHog flags require server SDK)
|
|
21
|
+
* - Context is per-request only (not persisted)
|
|
22
|
+
*
|
|
23
|
+
* **For full analytics features**, use `@od-oneapp/analytics/server` in Node.js environments.
|
|
24
|
+
*
|
|
25
|
+
* **Usage**: Import from `@od-oneapp/analytics/server/edge` for Next.js middleware and edge API routes.
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```typescript
|
|
29
|
+
* // In Next.js middleware
|
|
30
|
+
* import { createServerAnalytics, track } from '@od-oneapp/analytics/server/edge';
|
|
31
|
+
*
|
|
32
|
+
* export async function middleware(request: NextRequest) {
|
|
33
|
+
* const analytics = await createServerAnalytics({
|
|
34
|
+
* providers: {
|
|
35
|
+
* posthog: { apiKey: process.env.POSTHOG_API_KEY }
|
|
36
|
+
* }
|
|
37
|
+
* });
|
|
38
|
+
*
|
|
39
|
+
* await analytics.emit(track('Middleware Hit', { path: request.nextUrl.pathname }));
|
|
40
|
+
* return NextResponse.next();
|
|
41
|
+
* }
|
|
42
|
+
* ```
|
|
43
|
+
*
|
|
44
|
+
* @module @od-oneapp/analytics/server/edge
|
|
45
|
+
*/
|
|
46
|
+
|
|
47
|
+
import { env } from '../env';
|
|
48
|
+
|
|
49
|
+
import type {
|
|
50
|
+
EmitterAliasPayload,
|
|
51
|
+
EmitterGroupPayload,
|
|
52
|
+
EmitterIdentifyPayload,
|
|
53
|
+
EmitterPagePayload,
|
|
54
|
+
EmitterPayload,
|
|
55
|
+
EmitterTrackPayload,
|
|
56
|
+
} from './shared/emitters/emitter-types';
|
|
57
|
+
import type {
|
|
58
|
+
AnalyticsConfig,
|
|
59
|
+
AnalyticsContext,
|
|
60
|
+
AnalyticsManager,
|
|
61
|
+
AnalyticsProvider,
|
|
62
|
+
GroupTraits,
|
|
63
|
+
PageProperties,
|
|
64
|
+
Properties,
|
|
65
|
+
UserTraits,
|
|
66
|
+
} from './shared/types/types';
|
|
67
|
+
|
|
68
|
+
// Type aliases for clarity
|
|
69
|
+
type IdentifyTraits = UserTraits;
|
|
70
|
+
type TrackProperties = Properties;
|
|
71
|
+
|
|
72
|
+
// Re-export types for consumers
|
|
73
|
+
export type * from './shared/emitters/emitter-types';
|
|
74
|
+
export type * from './shared/types/types';
|
|
75
|
+
|
|
76
|
+
// Re-export emitter utilities
|
|
77
|
+
export { createEmitterProcessor } from './shared/utils/emitter-adapter';
|
|
78
|
+
|
|
79
|
+
// Re-export core emitters for edge usage
|
|
80
|
+
export { alias, group, identify, page, track } from './shared/emitters';
|
|
81
|
+
|
|
82
|
+
const defaultConfig: AnalyticsConfig = { providers: {} };
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Creates an edge-compatible analytics manager.
|
|
86
|
+
*
|
|
87
|
+
* This is a simplified implementation optimized for edge runtime constraints.
|
|
88
|
+
* It provides basic analytics functionality without Node.js-specific features.
|
|
89
|
+
*
|
|
90
|
+
* **Supported Providers**:
|
|
91
|
+
* - Console (always available)
|
|
92
|
+
* - PostHog (HTTP-based, requires API key)
|
|
93
|
+
*
|
|
94
|
+
* **Not Supported in Edge**:
|
|
95
|
+
* - Segment SDK (requires Node.js)
|
|
96
|
+
* - Vercel Analytics SDK (requires Node.js)
|
|
97
|
+
* - Rate limiting
|
|
98
|
+
* - Event deduplication
|
|
99
|
+
* - Batch processing optimization
|
|
100
|
+
*
|
|
101
|
+
* @param {AnalyticsConfig} [config] - Analytics configuration with provider settings
|
|
102
|
+
* @returns {Promise<AnalyticsManager>} Promise resolving to AnalyticsManager instance
|
|
103
|
+
*
|
|
104
|
+
* @example
|
|
105
|
+
* ```typescript
|
|
106
|
+
* const analytics = await createServerAnalytics({
|
|
107
|
+
* providers: {
|
|
108
|
+
* posthog: { apiKey: process.env.POSTHOG_API_KEY }
|
|
109
|
+
* }
|
|
110
|
+
* });
|
|
111
|
+
*
|
|
112
|
+
* await analytics.track('Event Name', { property: 'value' });
|
|
113
|
+
* ```
|
|
114
|
+
*/
|
|
115
|
+
export async function createServerAnalytics(
|
|
116
|
+
config: AnalyticsConfig = defaultConfig,
|
|
117
|
+
): Promise<AnalyticsManager> {
|
|
118
|
+
const providers: AnalyticsProvider[] = [];
|
|
119
|
+
let context: AnalyticsContext = {};
|
|
120
|
+
|
|
121
|
+
// Initialize Console provider (edge-compatible)
|
|
122
|
+
if (config.providers.console) {
|
|
123
|
+
const { ConsoleProvider } = await import('./providers/console');
|
|
124
|
+
const consoleProvider = new ConsoleProvider(config.providers.console);
|
|
125
|
+
await consoleProvider.initialize();
|
|
126
|
+
providers.push(consoleProvider);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Initialize PostHog HTTP provider (edge-compatible)
|
|
130
|
+
if (config.providers.posthog?.apiKey) {
|
|
131
|
+
const posthogProvider = createPostHogEdgeProvider(config);
|
|
132
|
+
providers.push(posthogProvider);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Process emitter payload by type
|
|
136
|
+
const processPayload = async (payload: EmitterPayload): Promise<void> => {
|
|
137
|
+
switch (payload.type) {
|
|
138
|
+
case 'track': {
|
|
139
|
+
const p = payload;
|
|
140
|
+
await Promise.allSettled(
|
|
141
|
+
providers.map(provider =>
|
|
142
|
+
provider.track(p.event, p.properties ?? {}, { ...context, ...p.context }),
|
|
143
|
+
),
|
|
144
|
+
);
|
|
145
|
+
break;
|
|
146
|
+
}
|
|
147
|
+
case 'identify': {
|
|
148
|
+
const p = payload;
|
|
149
|
+
await Promise.allSettled(
|
|
150
|
+
providers.map(provider =>
|
|
151
|
+
provider.identify?.(p.userId, p.traits ?? {}, { ...context, ...p.context }),
|
|
152
|
+
),
|
|
153
|
+
);
|
|
154
|
+
break;
|
|
155
|
+
}
|
|
156
|
+
case 'page': {
|
|
157
|
+
const p = payload;
|
|
158
|
+
await Promise.allSettled(
|
|
159
|
+
providers.map(provider =>
|
|
160
|
+
provider.page?.(p.name ?? '', p.properties ?? {}, { ...context, ...p.context }),
|
|
161
|
+
),
|
|
162
|
+
);
|
|
163
|
+
break;
|
|
164
|
+
}
|
|
165
|
+
case 'screen': {
|
|
166
|
+
const p = payload;
|
|
167
|
+
await Promise.allSettled(
|
|
168
|
+
providers.map(provider =>
|
|
169
|
+
provider.screen?.(p.name ?? '', p.properties ?? {}, { ...context, ...p.context }),
|
|
170
|
+
),
|
|
171
|
+
);
|
|
172
|
+
break;
|
|
173
|
+
}
|
|
174
|
+
case 'group': {
|
|
175
|
+
const p = payload;
|
|
176
|
+
await Promise.allSettled(
|
|
177
|
+
providers.map(provider =>
|
|
178
|
+
provider.group?.(p.groupId, p.traits ?? {}, { ...context, ...p.context }),
|
|
179
|
+
),
|
|
180
|
+
);
|
|
181
|
+
break;
|
|
182
|
+
}
|
|
183
|
+
case 'alias': {
|
|
184
|
+
const p = payload;
|
|
185
|
+
await Promise.allSettled(
|
|
186
|
+
providers.map(provider =>
|
|
187
|
+
provider.alias?.(p.userId, p.previousId, { ...context, ...p.context }),
|
|
188
|
+
),
|
|
189
|
+
);
|
|
190
|
+
break;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
// Create emitter function at outer scope (within createServerAnalytics)
|
|
196
|
+
function createEmitterFunction(payload: EmitterPayload): Promise<void> {
|
|
197
|
+
return processPayload(payload);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// Return edge-compatible analytics manager
|
|
201
|
+
const manager: AnalyticsManager = {
|
|
202
|
+
getContext: () => ({ ...context }),
|
|
203
|
+
|
|
204
|
+
initialize: async () => {
|
|
205
|
+
// Providers already initialized above
|
|
206
|
+
},
|
|
207
|
+
|
|
208
|
+
setContext: (newContext: AnalyticsContext) => {
|
|
209
|
+
context = { ...context, ...newContext };
|
|
210
|
+
},
|
|
211
|
+
|
|
212
|
+
createEmitter: () => createEmitterFunction,
|
|
213
|
+
|
|
214
|
+
emit: async (payload: EmitterPayload) => {
|
|
215
|
+
await processPayload(payload);
|
|
216
|
+
},
|
|
217
|
+
|
|
218
|
+
emitBatch: async (payloads: EmitterPayload[]) => {
|
|
219
|
+
// Process sequentially in edge (no concurrency optimization)
|
|
220
|
+
for (const payload of payloads) {
|
|
221
|
+
await processPayload(payload);
|
|
222
|
+
}
|
|
223
|
+
},
|
|
224
|
+
|
|
225
|
+
// Overloaded track method
|
|
226
|
+
track: async (eventOrPayload: string | EmitterTrackPayload, properties?: Properties) => {
|
|
227
|
+
if (typeof eventOrPayload === 'object') {
|
|
228
|
+
await processPayload(eventOrPayload);
|
|
229
|
+
} else if (typeof eventOrPayload === 'string') {
|
|
230
|
+
await Promise.allSettled(
|
|
231
|
+
providers.map(p => p.track(eventOrPayload, properties ?? {}, context)),
|
|
232
|
+
);
|
|
233
|
+
}
|
|
234
|
+
},
|
|
235
|
+
|
|
236
|
+
// Overloaded identify method
|
|
237
|
+
identify: async (userIdOrPayload: string | EmitterIdentifyPayload, traits?: IdentifyTraits) => {
|
|
238
|
+
if (typeof userIdOrPayload === 'object') {
|
|
239
|
+
await processPayload(userIdOrPayload);
|
|
240
|
+
} else if (typeof userIdOrPayload === 'string') {
|
|
241
|
+
await Promise.allSettled(
|
|
242
|
+
providers.map(p => p.identify?.(userIdOrPayload, traits ?? {}, context)),
|
|
243
|
+
);
|
|
244
|
+
}
|
|
245
|
+
},
|
|
246
|
+
|
|
247
|
+
// Overloaded page method
|
|
248
|
+
page: async (nameOrPayload?: string | EmitterPagePayload, properties?: PageProperties) => {
|
|
249
|
+
if (typeof nameOrPayload === 'object') {
|
|
250
|
+
await processPayload(nameOrPayload);
|
|
251
|
+
} else {
|
|
252
|
+
const pageName = typeof nameOrPayload === 'string' ? nameOrPayload : '';
|
|
253
|
+
await Promise.allSettled(providers.map(p => p.page?.(pageName, properties ?? {}, context)));
|
|
254
|
+
}
|
|
255
|
+
},
|
|
256
|
+
|
|
257
|
+
// Overloaded group method
|
|
258
|
+
group: async (groupIdOrPayload: string | EmitterGroupPayload, traits?: GroupTraits) => {
|
|
259
|
+
if (typeof groupIdOrPayload === 'object') {
|
|
260
|
+
await processPayload(groupIdOrPayload);
|
|
261
|
+
} else if (typeof groupIdOrPayload === 'string') {
|
|
262
|
+
await Promise.allSettled(
|
|
263
|
+
providers.map(p => p.group?.(groupIdOrPayload, traits ?? {}, context)),
|
|
264
|
+
);
|
|
265
|
+
}
|
|
266
|
+
},
|
|
267
|
+
|
|
268
|
+
// Overloaded alias method
|
|
269
|
+
alias: async (userIdOrPayload: string | EmitterAliasPayload, previousId?: string) => {
|
|
270
|
+
if (typeof userIdOrPayload === 'object') {
|
|
271
|
+
await processPayload(userIdOrPayload);
|
|
272
|
+
} else if (typeof userIdOrPayload === 'string' && previousId) {
|
|
273
|
+
await Promise.allSettled(
|
|
274
|
+
providers.map(p => p.alias?.(userIdOrPayload, previousId, context)),
|
|
275
|
+
);
|
|
276
|
+
}
|
|
277
|
+
},
|
|
278
|
+
|
|
279
|
+
getActiveProviders: () => providers.map(p => p.name),
|
|
280
|
+
getProvider: (name: string) => providers.find(p => p.name === name),
|
|
281
|
+
|
|
282
|
+
reset: () => {
|
|
283
|
+
context = {};
|
|
284
|
+
},
|
|
285
|
+
|
|
286
|
+
shutdown: async () => {
|
|
287
|
+
// In edge, we don't have complex shutdown logic usually
|
|
288
|
+
providers.length = 0;
|
|
289
|
+
},
|
|
290
|
+
|
|
291
|
+
// Deprecated methods (no-ops with warning)
|
|
292
|
+
processEmitterPayload: async (payload: EmitterPayload) => {
|
|
293
|
+
await processPayload(payload);
|
|
294
|
+
},
|
|
295
|
+
trackEcommerce: async () => {
|
|
296
|
+
if (config.debug && config.onInfo) {
|
|
297
|
+
config.onInfo('trackEcommerce is deprecated, use emit(ecommerce.EVENT_NAME(...))');
|
|
298
|
+
}
|
|
299
|
+
},
|
|
300
|
+
};
|
|
301
|
+
|
|
302
|
+
return manager;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* Creates a PostHog provider that uses HTTP API (edge-compatible).
|
|
307
|
+
*
|
|
308
|
+
* This provider uses PostHog's HTTP capture API instead of the Node.js SDK,
|
|
309
|
+
* making it compatible with edge runtime constraints.
|
|
310
|
+
*
|
|
311
|
+
* **Features**:
|
|
312
|
+
* - HTTP-based event tracking
|
|
313
|
+
* - 5-second timeout per request
|
|
314
|
+
* - Error handling via config callbacks
|
|
315
|
+
* - Supports all standard analytics methods (track, identify, page, group, alias)
|
|
316
|
+
*
|
|
317
|
+
* @param {AnalyticsConfig} config - Analytics configuration
|
|
318
|
+
* @returns {AnalyticsProvider} PostHog provider instance
|
|
319
|
+
*
|
|
320
|
+
* @throws {Error} If PostHog API key is not provided
|
|
321
|
+
*
|
|
322
|
+
* @internal
|
|
323
|
+
*/
|
|
324
|
+
function createPostHogEdgeProvider(config: AnalyticsConfig): AnalyticsProvider {
|
|
325
|
+
const posthogConfig = config.providers?.posthog;
|
|
326
|
+
if (!posthogConfig?.apiKey) {
|
|
327
|
+
throw new Error('PostHog apiKey is required');
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
const posthogHost =
|
|
331
|
+
(posthogConfig.options as { api_host?: string } | undefined)?.api_host ??
|
|
332
|
+
env.POSTHOG_HOST ??
|
|
333
|
+
'https://app.posthog.com';
|
|
334
|
+
const posthogUrl = `${posthogHost}/capture/`;
|
|
335
|
+
const { apiKey } = posthogConfig;
|
|
336
|
+
const timeout = 5000;
|
|
337
|
+
|
|
338
|
+
// Safe fetch with timeout and error handling
|
|
339
|
+
const safeFetch = async (body: Record<string, unknown>, method: string): Promise<void> => {
|
|
340
|
+
const controller = new AbortController();
|
|
341
|
+
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
342
|
+
|
|
343
|
+
try {
|
|
344
|
+
const response = await fetch(posthogUrl, {
|
|
345
|
+
method: 'POST',
|
|
346
|
+
headers: { 'Content-Type': 'application/json' },
|
|
347
|
+
body: JSON.stringify(body),
|
|
348
|
+
signal: controller.signal,
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
if (!response.ok && config.onError) {
|
|
352
|
+
config.onError(
|
|
353
|
+
new Error(`PostHog ${method} failed: ${response.status} ${response.statusText}`),
|
|
354
|
+
{ provider: 'posthog-edge', method, status: response.status },
|
|
355
|
+
);
|
|
356
|
+
}
|
|
357
|
+
} catch (error) {
|
|
358
|
+
if (config.onError) {
|
|
359
|
+
config.onError(error instanceof Error ? error : new Error('Unknown error'), {
|
|
360
|
+
provider: 'posthog-edge',
|
|
361
|
+
method,
|
|
362
|
+
});
|
|
363
|
+
}
|
|
364
|
+
} finally {
|
|
365
|
+
clearTimeout(timeoutId);
|
|
366
|
+
}
|
|
367
|
+
};
|
|
368
|
+
|
|
369
|
+
return {
|
|
370
|
+
name: 'posthog-edge',
|
|
371
|
+
|
|
372
|
+
async initialize() {
|
|
373
|
+
// No initialization needed for HTTP-based PostHog
|
|
374
|
+
},
|
|
375
|
+
|
|
376
|
+
async track(event: string, properties?: TrackProperties, context?: AnalyticsContext) {
|
|
377
|
+
const distinctId = context?.userId ?? properties?.distinctId ?? 'anonymous';
|
|
378
|
+
await safeFetch(
|
|
379
|
+
{
|
|
380
|
+
api_key: apiKey,
|
|
381
|
+
event,
|
|
382
|
+
distinct_id: distinctId,
|
|
383
|
+
properties: { ...properties, ...context },
|
|
384
|
+
timestamp: new Date().toISOString(),
|
|
385
|
+
},
|
|
386
|
+
'track',
|
|
387
|
+
);
|
|
388
|
+
},
|
|
389
|
+
|
|
390
|
+
async identify(userId: string, traits?: IdentifyTraits) {
|
|
391
|
+
await safeFetch(
|
|
392
|
+
{
|
|
393
|
+
api_key: apiKey,
|
|
394
|
+
event: '$identify',
|
|
395
|
+
distinct_id: userId,
|
|
396
|
+
properties: { $set: traits },
|
|
397
|
+
},
|
|
398
|
+
'identify',
|
|
399
|
+
);
|
|
400
|
+
},
|
|
401
|
+
|
|
402
|
+
async page(name?: string, properties?: PageProperties, context?: AnalyticsContext) {
|
|
403
|
+
const distinctId = context?.userId ?? 'anonymous';
|
|
404
|
+
await safeFetch(
|
|
405
|
+
{
|
|
406
|
+
api_key: apiKey,
|
|
407
|
+
event: '$pageview',
|
|
408
|
+
distinct_id: distinctId,
|
|
409
|
+
properties: { $current_url: properties?.url, $title: name, ...properties },
|
|
410
|
+
},
|
|
411
|
+
'page',
|
|
412
|
+
);
|
|
413
|
+
},
|
|
414
|
+
|
|
415
|
+
async group(groupId: string, traits?: GroupTraits, context?: AnalyticsContext) {
|
|
416
|
+
const distinctId = context?.userId ?? 'anonymous';
|
|
417
|
+
await safeFetch(
|
|
418
|
+
{
|
|
419
|
+
api_key: apiKey,
|
|
420
|
+
event: '$groupidentify',
|
|
421
|
+
distinct_id: distinctId,
|
|
422
|
+
properties: { $group_type: 'company', $group_key: groupId, $group_set: traits },
|
|
423
|
+
},
|
|
424
|
+
'group',
|
|
425
|
+
);
|
|
426
|
+
},
|
|
427
|
+
|
|
428
|
+
async alias(userId: string, previousId: string) {
|
|
429
|
+
await safeFetch(
|
|
430
|
+
{
|
|
431
|
+
api_key: apiKey,
|
|
432
|
+
event: '$create_alias',
|
|
433
|
+
properties: { distinct_id: userId, alias: previousId },
|
|
434
|
+
},
|
|
435
|
+
'alias',
|
|
436
|
+
);
|
|
437
|
+
},
|
|
438
|
+
};
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
// Export edge-compatible configuration utilities
|
|
442
|
+
export { getAnalyticsConfig } from './shared/utils/config';
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Next.js server exports
|
|
3
|
+
*
|
|
4
|
+
* This module provides Next.js-specific server-side analytics functionality.
|
|
5
|
+
* It exports:
|
|
6
|
+
*
|
|
7
|
+
* - **Server Analytics**: All server exports from `./server`
|
|
8
|
+
* - **Middleware**: Framework-agnostic analytics middleware utilities
|
|
9
|
+
* - **Types**: Analytics middleware types and configurations
|
|
10
|
+
*
|
|
11
|
+
* **Middleware Usage**: For Next.js middleware, use the framework-agnostic middleware
|
|
12
|
+
* from `./next/middleware` and provide Next.js-specific adapters in your Next.js app.
|
|
13
|
+
*
|
|
14
|
+
* **Usage**: Import from `@od-oneapp/analytics/server/next` for Next.js server components,
|
|
15
|
+
* API routes, and server actions.
|
|
16
|
+
*
|
|
17
|
+
* @module @od-oneapp/analytics/server/next
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
// Re-export everything from server
|
|
21
|
+
export * from './server';
|
|
22
|
+
|
|
23
|
+
// Export framework-agnostic middleware (use with Next.js adapters in app)
|
|
24
|
+
export {
|
|
25
|
+
composeMiddleware,
|
|
26
|
+
conditionalAnalyticsMiddleware,
|
|
27
|
+
createAnalyticsMiddleware,
|
|
28
|
+
createAnalyticsMiddlewareConfig,
|
|
29
|
+
getAnalyticsContextFromHeaders,
|
|
30
|
+
getDistinctIdFromHeaders,
|
|
31
|
+
} from './next/middleware';
|
|
32
|
+
export type {
|
|
33
|
+
AnalyticsMiddlewareConfig,
|
|
34
|
+
MiddlewareRequest,
|
|
35
|
+
MiddlewareResponse,
|
|
36
|
+
} from './next/middleware';
|
|
37
|
+
|
|
38
|
+
// Export types
|
|
39
|
+
export type * from './types';
|
package/src/server.ts
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Server exports for Node.js environments (non-Next.js)
|
|
3
|
+
*
|
|
4
|
+
* This module provides server-side analytics functionality for non-Next.js Node.js
|
|
5
|
+
* environments. It exports:
|
|
6
|
+
*
|
|
7
|
+
* - **Analytics Managers**: `createServerAnalytics()`, `createServerAnalyticsUninitialized()`
|
|
8
|
+
* - **Emitters**: Type-safe event tracking functions (track, identify, page, screen, group, alias)
|
|
9
|
+
* - **Ecommerce Emitters**: Comprehensive ecommerce event tracking
|
|
10
|
+
* - **AI Emitters**: AI product analytics tracking
|
|
11
|
+
* - **Emitter Utilities**: ContextBuilder, EventBatch, PayloadBuilder
|
|
12
|
+
* - **Adapter Utilities**: Emitter processing and ecommerce event tracking
|
|
13
|
+
* - **Configuration**: Full configuration utilities with validation
|
|
14
|
+
* - **Validation**: Server-side validation utilities including `validateConfigOrThrow()`
|
|
15
|
+
* - **PostHog Utilities**: Bootstrap data and distinct ID generation
|
|
16
|
+
*
|
|
17
|
+
* **Usage**: Import from `@od-oneapp/analytics/server` for Node.js server applications.
|
|
18
|
+
* For Next.js applications, use `@od-oneapp/analytics/server/next` instead.
|
|
19
|
+
*
|
|
20
|
+
* @module @od-oneapp/analytics/server
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
// Export core server functions
|
|
24
|
+
export { createServerAnalytics, createServerAnalyticsUninitialized } from './server/manager';
|
|
25
|
+
|
|
26
|
+
// Export all emitters - these are the preferred way to track events
|
|
27
|
+
export {
|
|
28
|
+
// Emitter utilities
|
|
29
|
+
ContextBuilder,
|
|
30
|
+
EventBatch,
|
|
31
|
+
PayloadBuilder,
|
|
32
|
+
alias,
|
|
33
|
+
createAnonymousSession,
|
|
34
|
+
createUserSession,
|
|
35
|
+
// Ecommerce emitters namespace
|
|
36
|
+
ecommerce,
|
|
37
|
+
group,
|
|
38
|
+
// Core Segment.io spec emitters
|
|
39
|
+
identify,
|
|
40
|
+
isAliasPayload,
|
|
41
|
+
isGroupPayload,
|
|
42
|
+
isIdentifyPayload,
|
|
43
|
+
isPagePayload,
|
|
44
|
+
// Type guards
|
|
45
|
+
isTrackPayload,
|
|
46
|
+
page,
|
|
47
|
+
screen,
|
|
48
|
+
track,
|
|
49
|
+
withMetadata,
|
|
50
|
+
withUTM,
|
|
51
|
+
} from './shared/emitters';
|
|
52
|
+
|
|
53
|
+
// Export adapter utilities
|
|
54
|
+
export {
|
|
55
|
+
createEmitterProcessor,
|
|
56
|
+
// Emitter processing utilities
|
|
57
|
+
processEmitterPayload,
|
|
58
|
+
trackEcommerceEvent,
|
|
59
|
+
} from './shared/utils/emitter-adapter';
|
|
60
|
+
|
|
61
|
+
// Export configuration utilities
|
|
62
|
+
export {
|
|
63
|
+
PROVIDER_REQUIREMENTS,
|
|
64
|
+
createConfigBuilder,
|
|
65
|
+
getAnalyticsConfig,
|
|
66
|
+
validateConfig,
|
|
67
|
+
} from './shared/utils/config';
|
|
68
|
+
|
|
69
|
+
// Export validation utilities
|
|
70
|
+
export {
|
|
71
|
+
debugConfig,
|
|
72
|
+
validateAnalyticsConfig,
|
|
73
|
+
validateConfigOrThrow,
|
|
74
|
+
validateProvider,
|
|
75
|
+
} from './shared/utils/validation';
|
|
76
|
+
|
|
77
|
+
// Export manager utilities
|
|
78
|
+
export {
|
|
79
|
+
AnalyticsManager as AnalyticsManagerClass,
|
|
80
|
+
createAnalyticsManager,
|
|
81
|
+
} from './shared/utils/manager';
|
|
82
|
+
|
|
83
|
+
// Export PostHog utilities
|
|
84
|
+
export {
|
|
85
|
+
createBootstrapData,
|
|
86
|
+
createMinimalBootstrapData,
|
|
87
|
+
generateDistinctId,
|
|
88
|
+
} from './shared/utils/posthog-bootstrap';
|
|
89
|
+
|
|
90
|
+
// Export ingestion service
|
|
91
|
+
export {
|
|
92
|
+
createIngestionService,
|
|
93
|
+
IngestionService,
|
|
94
|
+
validateEventPayload,
|
|
95
|
+
validateBatchPayload,
|
|
96
|
+
} from './shared/ingestion';
|
|
97
|
+
export type {
|
|
98
|
+
IngestionContext,
|
|
99
|
+
IngestionServiceConfig,
|
|
100
|
+
IngestionMetrics,
|
|
101
|
+
IngestionSuccessResponse,
|
|
102
|
+
IngestionErrorResponse,
|
|
103
|
+
} from './shared/ingestion';
|
|
104
|
+
|
|
105
|
+
// Export types
|
|
106
|
+
export type * from './types';
|