@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.
Files changed (184) hide show
  1. package/README.md +509 -0
  2. package/dist/ai-YMnynb-t.mjs +3347 -0
  3. package/dist/ai-YMnynb-t.mjs.map +1 -0
  4. package/dist/chunk-DQk6qfdC.mjs +18 -0
  5. package/dist/client-CTzJVFU5.mjs +9 -0
  6. package/dist/client-CTzJVFU5.mjs.map +1 -0
  7. package/dist/client-CcFTauAh.mjs +54 -0
  8. package/dist/client-CcFTauAh.mjs.map +1 -0
  9. package/dist/client-CeOLjbac.mjs +281 -0
  10. package/dist/client-CeOLjbac.mjs.map +1 -0
  11. package/dist/client-D339NFJS.mjs +267 -0
  12. package/dist/client-D339NFJS.mjs.map +1 -0
  13. package/dist/client-next.d.mts +62 -0
  14. package/dist/client-next.d.mts.map +1 -0
  15. package/dist/client-next.mjs +525 -0
  16. package/dist/client-next.mjs.map +1 -0
  17. package/dist/client.d.mts +30 -0
  18. package/dist/client.d.mts.map +1 -0
  19. package/dist/client.mjs +186 -0
  20. package/dist/client.mjs.map +1 -0
  21. package/dist/config-DPS6bSYo.d.mts +34 -0
  22. package/dist/config-DPS6bSYo.d.mts.map +1 -0
  23. package/dist/config-P6P5adJg.mjs +287 -0
  24. package/dist/config-P6P5adJg.mjs.map +1 -0
  25. package/dist/console-8bND3mMU.mjs +128 -0
  26. package/dist/console-8bND3mMU.mjs.map +1 -0
  27. package/dist/ecommerce-Cgu4wlux.mjs +993 -0
  28. package/dist/ecommerce-Cgu4wlux.mjs.map +1 -0
  29. package/dist/emitters-6-nKo8i-.mjs +208 -0
  30. package/dist/emitters-6-nKo8i-.mjs.map +1 -0
  31. package/dist/emitters-DldkVSPp.d.mts +12 -0
  32. package/dist/emitters-DldkVSPp.d.mts.map +1 -0
  33. package/dist/index-BfNWgfa5.d.mts +1494 -0
  34. package/dist/index-BfNWgfa5.d.mts.map +1 -0
  35. package/dist/index-BkIWe--N.d.mts +953 -0
  36. package/dist/index-BkIWe--N.d.mts.map +1 -0
  37. package/dist/index-jPzXRn52.d.mts +184 -0
  38. package/dist/index-jPzXRn52.d.mts.map +1 -0
  39. package/dist/manager-DvRRjza6.d.mts +76 -0
  40. package/dist/manager-DvRRjza6.d.mts.map +1 -0
  41. package/dist/posthog-bootstrap-CYfIy_WS.mjs +1769 -0
  42. package/dist/posthog-bootstrap-CYfIy_WS.mjs.map +1 -0
  43. package/dist/posthog-bootstrap-DWxFrxlt.d.mts +81 -0
  44. package/dist/posthog-bootstrap-DWxFrxlt.d.mts.map +1 -0
  45. package/dist/providers-http-client.d.mts +37 -0
  46. package/dist/providers-http-client.d.mts.map +1 -0
  47. package/dist/providers-http-client.mjs +320 -0
  48. package/dist/providers-http-client.mjs.map +1 -0
  49. package/dist/providers-http-server.d.mts +31 -0
  50. package/dist/providers-http-server.d.mts.map +1 -0
  51. package/dist/providers-http-server.mjs +297 -0
  52. package/dist/providers-http-server.mjs.map +1 -0
  53. package/dist/providers-http.d.mts +46 -0
  54. package/dist/providers-http.d.mts.map +1 -0
  55. package/dist/providers-http.mjs +4 -0
  56. package/dist/server-edge.d.mts +9 -0
  57. package/dist/server-edge.d.mts.map +1 -0
  58. package/dist/server-edge.mjs +373 -0
  59. package/dist/server-edge.mjs.map +1 -0
  60. package/dist/server-next.d.mts +67 -0
  61. package/dist/server-next.d.mts.map +1 -0
  62. package/dist/server-next.mjs +193 -0
  63. package/dist/server-next.mjs.map +1 -0
  64. package/dist/server.d.mts +10 -0
  65. package/dist/server.mjs +7 -0
  66. package/dist/service-cYtBBL8x.mjs +945 -0
  67. package/dist/service-cYtBBL8x.mjs.map +1 -0
  68. package/dist/shared.d.mts +16 -0
  69. package/dist/shared.d.mts.map +1 -0
  70. package/dist/shared.mjs +93 -0
  71. package/dist/shared.mjs.map +1 -0
  72. package/dist/types-BxBnNQ0V.d.mts +354 -0
  73. package/dist/types-BxBnNQ0V.d.mts.map +1 -0
  74. package/dist/types-CBvxUEaF.d.mts +216 -0
  75. package/dist/types-CBvxUEaF.d.mts.map +1 -0
  76. package/dist/types.d.mts +4 -0
  77. package/dist/types.mjs +0 -0
  78. package/dist/vercel-types-lwakUfoI.d.mts +102 -0
  79. package/dist/vercel-types-lwakUfoI.d.mts.map +1 -0
  80. package/package.json +129 -0
  81. package/src/client/index.ts +164 -0
  82. package/src/client/manager.ts +71 -0
  83. package/src/client/next/components.tsx +270 -0
  84. package/src/client/next/hooks.ts +217 -0
  85. package/src/client/next/manager.ts +141 -0
  86. package/src/client/next.ts +144 -0
  87. package/src/client-next.ts +101 -0
  88. package/src/client.ts +89 -0
  89. package/src/examples/ai-sdk-patterns.ts +583 -0
  90. package/src/examples/emitter-patterns.ts +476 -0
  91. package/src/examples/nextjs-emitter-patterns.tsx +403 -0
  92. package/src/next/app-router.tsx +564 -0
  93. package/src/next/client.ts +419 -0
  94. package/src/next/index.ts +84 -0
  95. package/src/next/middleware.ts +429 -0
  96. package/src/next/rsc.tsx +300 -0
  97. package/src/next/server.ts +253 -0
  98. package/src/next/types.d.ts +220 -0
  99. package/src/providers/base-provider.ts +419 -0
  100. package/src/providers/console/client.ts +10 -0
  101. package/src/providers/console/index.ts +152 -0
  102. package/src/providers/console/server.ts +6 -0
  103. package/src/providers/console/types.ts +15 -0
  104. package/src/providers/http/client.ts +464 -0
  105. package/src/providers/http/index.ts +30 -0
  106. package/src/providers/http/server.ts +396 -0
  107. package/src/providers/http/types.ts +135 -0
  108. package/src/providers/posthog/client.ts +518 -0
  109. package/src/providers/posthog/index.ts +11 -0
  110. package/src/providers/posthog/server.ts +329 -0
  111. package/src/providers/posthog/types.ts +104 -0
  112. package/src/providers/segment/client.ts +113 -0
  113. package/src/providers/segment/index.ts +11 -0
  114. package/src/providers/segment/server.ts +115 -0
  115. package/src/providers/segment/types.ts +51 -0
  116. package/src/providers/vercel/client.ts +102 -0
  117. package/src/providers/vercel/index.ts +11 -0
  118. package/src/providers/vercel/server.ts +89 -0
  119. package/src/providers/vercel/types.ts +27 -0
  120. package/src/server/index.ts +103 -0
  121. package/src/server/manager.ts +62 -0
  122. package/src/server/next.ts +210 -0
  123. package/src/server-edge.ts +442 -0
  124. package/src/server-next.ts +39 -0
  125. package/src/server.ts +106 -0
  126. package/src/shared/emitters/ai/README.md +981 -0
  127. package/src/shared/emitters/ai/events/agent.ts +130 -0
  128. package/src/shared/emitters/ai/events/artifacts.ts +167 -0
  129. package/src/shared/emitters/ai/events/chat.ts +126 -0
  130. package/src/shared/emitters/ai/events/chatbot-ecommerce.ts +133 -0
  131. package/src/shared/emitters/ai/events/completion.ts +103 -0
  132. package/src/shared/emitters/ai/events/content-generation.ts +347 -0
  133. package/src/shared/emitters/ai/events/conversation.ts +332 -0
  134. package/src/shared/emitters/ai/events/product-features.ts +1402 -0
  135. package/src/shared/emitters/ai/events/streaming.ts +114 -0
  136. package/src/shared/emitters/ai/events/tool.ts +93 -0
  137. package/src/shared/emitters/ai/index.ts +69 -0
  138. package/src/shared/emitters/ai/track-ai-sdk.ts +74 -0
  139. package/src/shared/emitters/ai/track-ai.ts +50 -0
  140. package/src/shared/emitters/ai/types.ts +1041 -0
  141. package/src/shared/emitters/ai/utils.ts +468 -0
  142. package/src/shared/emitters/ecommerce/events/cart-checkout.ts +106 -0
  143. package/src/shared/emitters/ecommerce/events/coupon.ts +49 -0
  144. package/src/shared/emitters/ecommerce/events/engagement.ts +61 -0
  145. package/src/shared/emitters/ecommerce/events/marketplace.ts +119 -0
  146. package/src/shared/emitters/ecommerce/events/order.ts +199 -0
  147. package/src/shared/emitters/ecommerce/events/product.ts +205 -0
  148. package/src/shared/emitters/ecommerce/events/registry.ts +123 -0
  149. package/src/shared/emitters/ecommerce/events/wishlist-sharing.ts +140 -0
  150. package/src/shared/emitters/ecommerce/index.ts +46 -0
  151. package/src/shared/emitters/ecommerce/track-ecommerce.ts +53 -0
  152. package/src/shared/emitters/ecommerce/types.ts +314 -0
  153. package/src/shared/emitters/ecommerce/utils.ts +216 -0
  154. package/src/shared/emitters/emitter-types.ts +974 -0
  155. package/src/shared/emitters/emitters.ts +292 -0
  156. package/src/shared/emitters/helpers.ts +419 -0
  157. package/src/shared/emitters/index.ts +66 -0
  158. package/src/shared/index.ts +142 -0
  159. package/src/shared/ingestion/index.ts +66 -0
  160. package/src/shared/ingestion/schemas.ts +386 -0
  161. package/src/shared/ingestion/service.ts +628 -0
  162. package/src/shared/node22-features.ts +848 -0
  163. package/src/shared/providers/console-provider.ts +160 -0
  164. package/src/shared/types/base-types.ts +54 -0
  165. package/src/shared/types/console-types.ts +19 -0
  166. package/src/shared/types/posthog-types.ts +131 -0
  167. package/src/shared/types/segment-types.ts +15 -0
  168. package/src/shared/types/types.ts +397 -0
  169. package/src/shared/types/vercel-types.ts +19 -0
  170. package/src/shared/utils/config-client.ts +19 -0
  171. package/src/shared/utils/config.ts +250 -0
  172. package/src/shared/utils/emitter-adapter.ts +212 -0
  173. package/src/shared/utils/manager.test.ts +36 -0
  174. package/src/shared/utils/manager.ts +1322 -0
  175. package/src/shared/utils/posthog-bootstrap.ts +136 -0
  176. package/src/shared/utils/posthog-client-utils.ts +48 -0
  177. package/src/shared/utils/posthog-next-utils.ts +282 -0
  178. package/src/shared/utils/posthog-server-utils.ts +210 -0
  179. package/src/shared/utils/rate-limit.ts +289 -0
  180. package/src/shared/utils/security.ts +545 -0
  181. package/src/shared/utils/validation-client.ts +161 -0
  182. package/src/shared/utils/validation.ts +399 -0
  183. package/src/shared.ts +155 -0
  184. package/src/types/index.ts +62 -0
@@ -0,0 +1,518 @@
1
+ /**
2
+ * @fileoverview PostHog client-side (browser) provider implementation
3
+ *
4
+ * Provides client-side integration with PostHog Analytics including feature flags support.
5
+ * Supports full PostHog tracking including capture, identify, reset, group, alias, and feature flags.
6
+ *
7
+ * @remarks
8
+ * This provider:
9
+ * - Uses PostHog JavaScript SDK for browser tracking
10
+ * - Supports bootstrap data for SSR optimization
11
+ * - Handles feature flags and experiments
12
+ * - Integrates with PostHog's analytics dashboard
13
+ *
14
+ * @module @repo/analytics/providers/posthog/client
15
+ */
16
+
17
+ // Simple console fallbacks - observability integration can be added later
18
+ import type {
19
+ BootstrapData,
20
+ EnhancedPostHogProvider,
21
+ ExperimentInfo,
22
+ PostHogConfig,
23
+ } from './types';
24
+ import type { AnalyticsProvider, ProviderConfig } from '../../shared/types/types';
25
+ const logDebug = (_message: string, _context?: any) => {
26
+ // No-op to avoid console warnings in production
27
+ // TODO: Add proper debug logging via observability package
28
+ };
29
+ const logError = (_message: string, _error?: Error, _context?: any) => {
30
+ // No-op to avoid console warnings in production
31
+ // TODO: Add proper error logging via observability package
32
+ };
33
+ const logWarn = (_message: string, _context?: any) => {
34
+ // No-op to avoid console warnings in production
35
+ // TODO: Add proper error logging via observability package
36
+ };
37
+
38
+ declare global {
39
+ interface Window {
40
+ posthog?: {
41
+ init: (apiKey: string, options?: any) => void;
42
+ capture: (event: string, properties?: any) => void;
43
+ identify: (userId: string, properties?: any) => void;
44
+ reset: () => void;
45
+ group: (groupType: string, groupKey: string, properties?: any) => void;
46
+ alias: (alias: string) => void;
47
+ people?: {
48
+ set: (properties: any) => void;
49
+ set_once: (properties: any) => void;
50
+ };
51
+ register: (properties: any) => void;
52
+
53
+ // Feature flag methods
54
+ isFeatureEnabled: (flag: string) => boolean;
55
+ getFeatureFlag: (flag: string) => any;
56
+ getFeatureFlagPayload: (flag: string) => any;
57
+ getAllFlags: () => Record<string, any>;
58
+ onFeatureFlags: (callback: (flags: string[], variants: Record<string, any>) => void) => void;
59
+
60
+ // Experiment methods
61
+ getActiveMatchingFeatureFlags: () => string[];
62
+
63
+ // Utility methods
64
+ get_distinct_id: () => string;
65
+ shutdown: () => Promise<void>;
66
+ };
67
+ }
68
+ }
69
+
70
+ export class PostHogClientProvider implements AnalyticsProvider, Partial<EnhancedPostHogProvider> {
71
+ readonly name = 'posthog';
72
+ private config: PostHogConfig;
73
+ private isInitialized = false;
74
+ private posthogInstance: any = null;
75
+ private retryQueue: { method: string; args: any[] }[] = [];
76
+ private isOnline = true;
77
+ private debugMode = false;
78
+
79
+ constructor(config: ProviderConfig) {
80
+ if (!config.apiKey) {
81
+ throw new Error('PostHog apiKey is required');
82
+ }
83
+
84
+ this.config = {
85
+ apiKey: config.apiKey,
86
+ options: config.options,
87
+ };
88
+
89
+ // Set up debug mode
90
+ this.debugMode =
91
+ config.options?.debug === true ||
92
+ (typeof window !== 'undefined' && window.location.search.includes('debug=posthog'));
93
+
94
+ // Monitor network status for retry queue
95
+ if (typeof window !== 'undefined') {
96
+ window.addEventListener('online', () => {
97
+ this.isOnline = true;
98
+ void this.flushRetryQueue();
99
+ });
100
+
101
+ window.addEventListener('offline', () => {
102
+ this.isOnline = false;
103
+ });
104
+ }
105
+ }
106
+
107
+ async initialize(): Promise<void> {
108
+ if (this.isInitialized) return;
109
+
110
+ try {
111
+ // Dynamically import PostHog (optional dependency)
112
+ const { default: posthog } = await import('posthog-js');
113
+
114
+ // Extract bootstrap data if provided
115
+ const bootstrap = this.config.options?.bootstrap;
116
+
117
+ // Initialize PostHog with enhanced options and all missing configurations
118
+ const initOptions: any = {
119
+ // Core PostHog configuration with PostHog recommended defaults
120
+ api_host: 'https://app.posthog.com',
121
+ capture_pageleave: true, // Important for engagement tracking
122
+ capture_pageview: false, // We handle pageviews manually
123
+ ui_host: 'https://app.posthog.com',
124
+
125
+ opt_in_site_apps: false, // Conservative default
126
+ // Privacy & GDPR compliance
127
+ person_profiles: 'identified_only', // GDPR-friendly default
128
+ respect_dnt: true, // Respect Do Not Track headers
129
+
130
+ // Performance optimizations
131
+ uuid_version: 'v7', // Better performance than v4
132
+ batch_flush_interval_ms: 10000, // 10 second batching
133
+ request_batching: true, // Batch requests for better performance
134
+
135
+ // Session recording with safe defaults
136
+ session_recording: {
137
+ maskAllInputs: false,
138
+ maskInputOptions: {
139
+ email: false,
140
+ number: false,
141
+ password: true, // Always mask passwords
142
+ text: false,
143
+ },
144
+ recordCanvas: false, // Performance consideration
145
+ recordCrossOriginIframes: false, // Conservative default
146
+ sampling: {
147
+ minimumDurationMs: 1000, // Only record sessions > 1s
148
+ sampleRate: 1, // Record all sessions by default
149
+ },
150
+ },
151
+
152
+ // Debug mode
153
+ debug: this.debugMode,
154
+
155
+ // Apply user configuration (this will override defaults)
156
+ ...this.config.options,
157
+
158
+ // Add bootstrap data if available (must be last to not be overridden)
159
+ ...(bootstrap && {
160
+ bootstrap: {
161
+ distinctID: bootstrap.distinctID,
162
+ },
163
+ }),
164
+ };
165
+
166
+ posthog.init(this.config.apiKey, initOptions);
167
+
168
+ // Store instance references
169
+ this.posthogInstance = posthog;
170
+ window.posthog = posthog as any;
171
+
172
+ this.isInitialized = true;
173
+ } catch {
174
+ throw new Error('PostHog JS SDK not available. Install with: npm install posthog-js');
175
+ }
176
+ }
177
+
178
+ async track(event: string, properties: any = {}): Promise<void> {
179
+ if (!this.isInitialized || !this.posthogInstance) {
180
+ await this.queueEvent('track', [event, properties]);
181
+ return;
182
+ }
183
+
184
+ try {
185
+ // Debug logging
186
+ await this.log('Tracking event:', event, properties);
187
+
188
+ // Validate properties in debug mode
189
+ if (this.debugMode) {
190
+ await this.validateEventProperties(event, properties);
191
+ }
192
+
193
+ this.posthogInstance.capture(event, properties);
194
+ } catch (error) {
195
+ // Queue event if offline
196
+ if (!this.isOnline) {
197
+ await this.queueEvent('track', [event, properties]);
198
+ }
199
+
200
+ // Enhanced error reporting
201
+ await this.reportError(error, 'track', { event, properties });
202
+ }
203
+ }
204
+
205
+ async identify(userId: string, traits: any = {}): Promise<void> {
206
+ if (!this.isInitialized || !this.posthogInstance) {
207
+ return;
208
+ }
209
+
210
+ try {
211
+ this.posthogInstance.identify(userId, traits);
212
+ } catch {
213
+ // Silently fail to avoid disrupting app flow
214
+ }
215
+ }
216
+
217
+ async page(name?: string, properties: any = {}): Promise<void> {
218
+ if (!this.isInitialized || !this.posthogInstance) {
219
+ return;
220
+ }
221
+
222
+ try {
223
+ this.posthogInstance.capture('$pageview', {
224
+ $current_url: window.location.href,
225
+ $title: name ?? document.title,
226
+ ...properties,
227
+ });
228
+ } catch {
229
+ // Silently fail to avoid disrupting app flow
230
+ }
231
+ }
232
+
233
+ async group(groupId: string, traits: any = {}): Promise<void> {
234
+ if (!this.isInitialized || !this.posthogInstance) {
235
+ return;
236
+ }
237
+
238
+ try {
239
+ this.posthogInstance.group('company', groupId, traits);
240
+ } catch {
241
+ // Silently fail to avoid disrupting app flow
242
+ }
243
+ }
244
+
245
+ async alias(userId: string, _previousId: string): Promise<void> {
246
+ if (!this.isInitialized || !this.posthogInstance) {
247
+ return;
248
+ }
249
+
250
+ try {
251
+ this.posthogInstance.alias(userId);
252
+ } catch {
253
+ // Silently fail to avoid disrupting app flow
254
+ }
255
+ }
256
+
257
+ // Feature Flag Methods
258
+ async getAllFlags(userId?: string): Promise<Record<string, any>> {
259
+ if (!this.isInitialized || !this.posthogInstance) {
260
+ return {};
261
+ }
262
+
263
+ try {
264
+ if (userId) {
265
+ // If userId provided, identify first to ensure flags are for correct user
266
+ await this.identify(userId);
267
+ }
268
+
269
+ return this.posthogInstance.getAllFlags() ?? {};
270
+ } catch {
271
+ return {};
272
+ }
273
+ }
274
+
275
+ async getFeatureFlag(flag: string, userId?: string): Promise<any> {
276
+ if (!this.isInitialized || !this.posthogInstance) {
277
+ return false;
278
+ }
279
+
280
+ try {
281
+ if (userId) {
282
+ await this.identify(userId);
283
+ }
284
+
285
+ return this.posthogInstance.getFeatureFlag(flag);
286
+ } catch {
287
+ return false;
288
+ }
289
+ }
290
+
291
+ async isFeatureEnabled(flag: string, userId?: string): Promise<boolean> {
292
+ if (!this.isInitialized || !this.posthogInstance) {
293
+ return false;
294
+ }
295
+
296
+ try {
297
+ if (userId) {
298
+ await this.identify(userId);
299
+ }
300
+
301
+ return this.posthogInstance.isFeatureEnabled(flag) ?? false;
302
+ } catch {
303
+ return false;
304
+ }
305
+ }
306
+
307
+ async getFeatureFlagPayload(flag: string, userId?: string): Promise<any | null> {
308
+ if (!this.isInitialized || !this.posthogInstance) {
309
+ return null;
310
+ }
311
+
312
+ try {
313
+ if (userId) {
314
+ await this.identify(userId);
315
+ }
316
+
317
+ return this.posthogInstance.getFeatureFlagPayload(flag) ?? null;
318
+ } catch {
319
+ return null;
320
+ }
321
+ }
322
+
323
+ async getActiveExperiments(userId?: string): Promise<ExperimentInfo[]> {
324
+ if (!this.isInitialized || !this.posthogInstance) {
325
+ return [];
326
+ }
327
+
328
+ try {
329
+ if (userId) {
330
+ await this.identify(userId);
331
+ }
332
+
333
+ const activeFlags = this.posthogInstance.getActiveMatchingFeatureFlags() ?? [];
334
+ return activeFlags.map((flag: string) => ({
335
+ key: flag,
336
+ payload: this.posthogInstance.getFeatureFlagPayload(flag),
337
+ variant: this.posthogInstance.getFeatureFlag(flag),
338
+ }));
339
+ } catch {
340
+ return [];
341
+ }
342
+ }
343
+
344
+ // Bootstrap method (not typically used on client, but included for completeness)
345
+ async getBootstrapData(distinctId: string): Promise<BootstrapData> {
346
+ if (!this.isInitialized || !this.posthogInstance) {
347
+ return { distinctID: distinctId };
348
+ }
349
+
350
+ try {
351
+ await this.getAllFlags();
352
+
353
+ return {
354
+ distinctID: distinctId,
355
+ };
356
+ } catch {
357
+ return { distinctID: distinctId };
358
+ }
359
+ }
360
+
361
+ // Utility Methods
362
+ reset(): void {
363
+ if (!this.isInitialized || !this.posthogInstance) {
364
+ return;
365
+ }
366
+
367
+ try {
368
+ this.posthogInstance.reset();
369
+ } catch {
370
+ // Silently fail
371
+ }
372
+ }
373
+
374
+ async shutdown(): Promise<void> {
375
+ if (!this.isInitialized || !this.posthogInstance) {
376
+ return;
377
+ }
378
+
379
+ try {
380
+ if (this.posthogInstance.shutdown) {
381
+ await this.posthogInstance.shutdown();
382
+ }
383
+ } catch {
384
+ // Silently fail
385
+ }
386
+ }
387
+
388
+ // Get distinct ID for bootstrap purposes
389
+ getDistinctId(): string | null {
390
+ if (!this.isInitialized || !this.posthogInstance) {
391
+ return null;
392
+ }
393
+
394
+ try {
395
+ return this.posthogInstance.get_distinct_id();
396
+ } catch {
397
+ return null;
398
+ }
399
+ }
400
+
401
+ // Enhanced error handling and utility methods
402
+ private async queueEvent(method: string, args: any[]) {
403
+ this.retryQueue.push({ args, method });
404
+ await this.log(`Queued ${method} event for retry: `, args);
405
+ }
406
+
407
+ private async flushRetryQueue() {
408
+ await this.log(`Flushing retry queue with ${this.retryQueue.length} events`);
409
+
410
+ while (this.retryQueue.length > 0) {
411
+ const item = this.retryQueue.shift();
412
+ if (!item) break;
413
+ const { args, method } = item;
414
+ try {
415
+ await (this as any)[method](...args);
416
+ } catch {
417
+ // Re-queue failed events (limit retries)
418
+ if (this.retryQueue.length < 100) {
419
+ // Prevent infinite queue growth
420
+ await this.queueEvent(method, args);
421
+ }
422
+ break;
423
+ }
424
+ }
425
+ }
426
+
427
+ private log(...args: any[]) {
428
+ if (this.debugMode) {
429
+ logDebug('PostHog Debug:', { args });
430
+ }
431
+ }
432
+
433
+ private async validateEventProperties(event: string, properties: any) {
434
+ // Check for reserved property names
435
+ const reserved = new Set(['$set', '$set_once', '$unset', 'distinct_id', '$groups']);
436
+ const conflicts = Object.keys(properties).filter(
437
+ key => reserved.has(key) && !key.startsWith('$'),
438
+ );
439
+
440
+ if (conflicts.length > 0) {
441
+ logWarn('PostHog: Properties may conflict with reserved names:', {
442
+ conflicts: conflicts.join(', '),
443
+ event,
444
+ });
445
+ }
446
+
447
+ // Check for circular references
448
+ try {
449
+ JSON.stringify(properties);
450
+ } catch (error) {
451
+ logWarn('PostHog: Event properties contain circular references:', {
452
+ event,
453
+ error: error instanceof Error ? error.message : String(error),
454
+ });
455
+ }
456
+ }
457
+
458
+ private async reportError(error: any, method: string, context: any) {
459
+ if (this.debugMode) {
460
+ logError('PostHog Error:', error instanceof Error ? error : new Error(String(error)), {
461
+ method,
462
+ context,
463
+ });
464
+ }
465
+
466
+ // Could emit error event to other analytics providers
467
+ // this.emit('analytics_error', { provider: 'posthog', method, error: error.message, context });
468
+ }
469
+
470
+ // Consent management methods
471
+ async optIn(): Promise<void> {
472
+ if (this.posthogInstance) {
473
+ this.posthogInstance.opt_in_capturing();
474
+ await this.log('User opted in to tracking');
475
+ }
476
+ }
477
+
478
+ async optOut(): Promise<void> {
479
+ if (this.posthogInstance) {
480
+ this.posthogInstance.opt_out_capturing();
481
+ await this.log('User opted out of tracking');
482
+ }
483
+ }
484
+
485
+ hasOptedOut(): boolean {
486
+ return this.posthogInstance ? this.posthogInstance.has_opted_out_capturing() : false;
487
+ }
488
+
489
+ // Enhanced group analytics
490
+ async groupIdentify(
491
+ groupType: string,
492
+ groupKey: string,
493
+ groupProperties: any,
494
+ options?: { setAsDefault?: boolean },
495
+ ): Promise<void> {
496
+ if (!this.isInitialized || !this.posthogInstance) {
497
+ return;
498
+ }
499
+
500
+ try {
501
+ await this.log('Group identify:', groupType, groupKey, groupProperties);
502
+
503
+ // Set group properties
504
+ this.posthogInstance.group(groupType, groupKey, groupProperties);
505
+
506
+ // Optionally set as default group for user
507
+ if (options?.setAsDefault) {
508
+ this.posthogInstance.register({
509
+ [`$groups`]: {
510
+ [groupType]: groupKey,
511
+ },
512
+ });
513
+ }
514
+ } catch (error) {
515
+ await this.reportError(error, 'groupIdentify', { groupKey, groupProperties, groupType });
516
+ }
517
+ }
518
+ }
@@ -0,0 +1,11 @@
1
+ /**
2
+ * @fileoverview PostHog provider shared logic and exports
3
+ *
4
+ * Barrel export file for PostHog Analytics provider implementations and types.
5
+ *
6
+ * @module @repo/analytics/providers/posthog
7
+ */
8
+
9
+ // Export provider implementations
10
+ // Export types
11
+ export type * from './types';