@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,399 @@
1
+ /**
2
+ * @fileoverview Validation utilities for analytics configuration
3
+ *
4
+ * This module provides comprehensive validation for analytics configurations,
5
+ * including provider validation, environment-specific checks, and helpful
6
+ * warnings for common misconfigurations.
7
+ *
8
+ * **Features**:
9
+ * - Configuration structure validation
10
+ * - Provider-specific field validation
11
+ * - Environment variable validation
12
+ * - Environment-specific warnings
13
+ * - Detailed error reporting
14
+ *
15
+ * @module @od-oneapp/analytics/shared/utils/validation
16
+ */
17
+
18
+ import { logError, logInfo, logWarn } from '@repo/shared/logger';
19
+
20
+ import { PROVIDER_REQUIREMENTS } from './config';
21
+
22
+ import type { AnalyticsConfig, ProviderConfig } from '../types/types';
23
+
24
+ /**
25
+ * Validation error structure.
26
+ *
27
+ * Represents a single validation error with field, message, and provider context.
28
+ */
29
+ export interface ValidationError {
30
+ /** Field name that failed validation */
31
+ field: string;
32
+ /** Human-readable error message */
33
+ message: string;
34
+ /** Provider name (or 'global' for config-level errors) */
35
+ provider: string;
36
+ }
37
+
38
+ /**
39
+ * Validation result structure.
40
+ *
41
+ * Contains validation errors, warnings, and overall validity status.
42
+ */
43
+ export interface ValidationResult {
44
+ /** Array of validation errors */
45
+ errors: ValidationError[];
46
+ /** Whether the configuration is valid (no errors) */
47
+ isValid: boolean;
48
+ /** Array of warning messages */
49
+ warnings: string[];
50
+ }
51
+
52
+ /**
53
+ * Comprehensive configuration validation.
54
+ *
55
+ * Validates the entire analytics configuration structure, including:
56
+ * - Configuration object structure
57
+ * - Providers object existence
58
+ * - Individual provider configurations
59
+ * - Environment-specific warnings
60
+ *
61
+ * Accepts `unknown` input for defensive validation of potentially malformed configs.
62
+ *
63
+ * @param {unknown} config - Analytics configuration to validate
64
+ * @returns {ValidationResult} Validation result with errors, warnings, and validity status
65
+ *
66
+ * @example
67
+ * ```typescript
68
+ * const result = validateAnalyticsConfig(config);
69
+ * if (!result.isValid) {
70
+ * console.error('Validation errors:', result.errors);
71
+ * }
72
+ * if (result.warnings.length > 0) {
73
+ * console.warn('Warnings:', result.warnings);
74
+ * }
75
+ * ```
76
+ */
77
+ export function validateAnalyticsConfig(config: unknown): ValidationResult {
78
+ const errors: ValidationError[] = [];
79
+ const warnings: string[] = [];
80
+
81
+ // Check if config exists and is an object
82
+ if (!config || typeof config !== 'object') {
83
+ errors.push({
84
+ provider: 'global',
85
+ field: 'config',
86
+ message: 'Analytics configuration is required and must be an object',
87
+ });
88
+ return { isValid: false, errors, warnings };
89
+ }
90
+
91
+ const typedConfig = config as AnalyticsConfig;
92
+
93
+ // Check if providers object exists
94
+ if (!typedConfig.providers || typeof typedConfig.providers !== 'object') {
95
+ errors.push({
96
+ provider: 'global',
97
+ field: 'providers',
98
+ message: 'Providers configuration is required and must be an object',
99
+ });
100
+ return { isValid: false, errors, warnings };
101
+ }
102
+
103
+ // Check if at least one provider is configured
104
+ const providerCount = Object.keys(typedConfig.providers).length;
105
+ if (providerCount === 0) {
106
+ warnings.push('No providers configured. Analytics will not track any events.');
107
+ }
108
+
109
+ // Validate each provider
110
+ for (const [providerName, providerConfig] of Object.entries(typedConfig.providers)) {
111
+ const providerErrors = validateProvider(providerName, providerConfig);
112
+ errors.push(...providerErrors);
113
+ }
114
+
115
+ // Environment-specific warnings
116
+ const isBrowser = typeof window !== 'undefined';
117
+
118
+ // Mixpanel warning for client-side usage
119
+ if (isBrowser && typedConfig.providers.mixpanel) {
120
+ warnings.push(
121
+ 'Mixpanel provider configured on client-side. Consider using server-side for better performance.',
122
+ );
123
+ }
124
+
125
+ if (!isBrowser && typedConfig.providers.vercel) {
126
+ warnings.push(
127
+ 'Vercel Analytics has limited server-side support. Consider using client-side for better features.',
128
+ );
129
+ }
130
+
131
+ return {
132
+ isValid: errors.length === 0,
133
+ errors,
134
+ warnings,
135
+ };
136
+ }
137
+
138
+ /**
139
+ * Validate a single provider configuration.
140
+ *
141
+ * Checks that the provider is known and that all required fields are present.
142
+ *
143
+ * @param {string} providerName - Name of the provider to validate
144
+ * @param {ProviderConfig} config - Provider configuration to validate
145
+ * @returns {ValidationError[]} Array of validation errors (empty if valid)
146
+ *
147
+ * @example
148
+ * ```typescript
149
+ * const errors = validateProvider('posthog', { apiKey: 'phc_xxx' });
150
+ * if (errors.length > 0) {
151
+ * console.error('Provider errors:', errors);
152
+ * }
153
+ * ```
154
+ */
155
+ export function validateProvider(providerName: string, config: ProviderConfig): ValidationError[] {
156
+ const errors: ValidationError[] = [];
157
+
158
+ // Check if provider is known
159
+ const knownProviders = ['segment', 'posthog', 'vercel', 'console', 'mixpanel'];
160
+ if (!knownProviders.includes(providerName)) {
161
+ errors.push({
162
+ provider: providerName,
163
+ field: 'name',
164
+ message: `Unknown provider '${providerName}'. Known providers: ${knownProviders.join(', ')}`,
165
+ });
166
+ return errors;
167
+ }
168
+
169
+ // Check required fields
170
+ const requiredFields = PROVIDER_REQUIREMENTS[providerName] ?? [];
171
+ for (const field of requiredFields) {
172
+ const value = config[field as keyof ProviderConfig];
173
+
174
+ if (!value) {
175
+ errors.push({
176
+ provider: providerName,
177
+ field,
178
+ message: `Required field '${field}' is missing for provider '${providerName}'`,
179
+ });
180
+ } else if (typeof value === 'string' && value.trim() === '') {
181
+ errors.push({
182
+ provider: providerName,
183
+ field,
184
+ message: `Required field '${field}' cannot be empty for provider '${providerName}'`,
185
+ });
186
+ }
187
+ }
188
+
189
+ // Provider-specific validation
190
+ switch (providerName) {
191
+ case 'segment':
192
+ if (config.writeKey && !isValidSegmentWriteKey(config.writeKey)) {
193
+ errors.push({
194
+ provider: providerName,
195
+ field: 'writeKey',
196
+ message: 'Segment writeKey appears to be invalid format',
197
+ });
198
+ }
199
+ break;
200
+
201
+ case 'posthog':
202
+ if (config.apiKey && !isValidPostHogApiKey(config.apiKey)) {
203
+ errors.push({
204
+ provider: providerName,
205
+ field: 'apiKey',
206
+ message: 'PostHog apiKey appears to be invalid format',
207
+ });
208
+ }
209
+ break;
210
+ }
211
+
212
+ return errors;
213
+ }
214
+
215
+ /**
216
+ * Validate environment variables for analytics.
217
+ *
218
+ * Checks common analytics environment variables for:
219
+ * - Empty values
220
+ * - Placeholder text
221
+ * - Development environment warnings
222
+ *
223
+ * @returns {ValidationResult} Validation result with warnings about environment variables
224
+ *
225
+ * @example
226
+ * ```typescript
227
+ * const result = validateEnvironmentVariables();
228
+ * if (result.warnings.length > 0) {
229
+ * console.warn('Environment warnings:', result.warnings);
230
+ * }
231
+ * ```
232
+ */
233
+ export function validateEnvironmentVariables(): ValidationResult {
234
+ const errors: ValidationError[] = [];
235
+ const warnings: string[] = [];
236
+
237
+ // Check for common environment variables
238
+ const envVars = {
239
+ POSTHOG_API_KEY: process.env.POSTHOG_API_KEY,
240
+ SEGMENT_WRITE_KEY: process.env.SEGMENT_WRITE_KEY,
241
+ };
242
+
243
+ for (const [varName, value] of Object.entries(envVars)) {
244
+ if (value && typeof value === 'string') {
245
+ if (value.trim() === '') {
246
+ warnings.push(`Environment variable ${varName} is set but empty`);
247
+ } else if (value.includes('your-') || value.includes('paste-')) {
248
+ warnings.push(`Environment variable ${varName} appears to contain placeholder text`);
249
+ }
250
+ }
251
+ }
252
+
253
+ // Warn about development environment
254
+ if (
255
+ process.env.NODE_ENV === 'development' &&
256
+ !envVars.SEGMENT_WRITE_KEY &&
257
+ !envVars.POSTHOG_API_KEY
258
+ ) {
259
+ warnings.push(
260
+ 'No analytics environment variables detected in development. Consider using console provider for debugging.',
261
+ );
262
+ }
263
+
264
+ return {
265
+ isValid: errors.length === 0,
266
+ errors,
267
+ warnings,
268
+ };
269
+ }
270
+
271
+ /**
272
+ * Validates Segment write key format.
273
+ *
274
+ * Checks that the write key matches Segment's expected format:
275
+ * - Exactly 32 alphanumeric characters
276
+ * - Not a placeholder value
277
+ *
278
+ * @param {string} writeKey - Write key to validate
279
+ * @returns {boolean} `true` if valid, `false` otherwise
280
+ *
281
+ * @internal
282
+ */
283
+ function isValidSegmentWriteKey(writeKey: string): boolean {
284
+ // Segment write keys are exactly 32 characters, alphanumeric
285
+ if (!/^[\dA-Za-z]{32}$/.test(writeKey)) {
286
+ return false;
287
+ }
288
+
289
+ // Check for common placeholder patterns
290
+ const placeholders = ['your-write-key', 'paste-key-here', 'xxxxxxxx', 'example'];
291
+ if (placeholders.some(p => writeKey.toLowerCase().includes(p.toLowerCase()))) {
292
+ return false;
293
+ }
294
+
295
+ return true;
296
+ }
297
+
298
+ /**
299
+ * Validates PostHog API key format.
300
+ *
301
+ * Checks that the API key matches PostHog's expected format:
302
+ * - Starts with `phc_` prefix
303
+ * - Followed by 43 alphanumeric/dash/underscore characters
304
+ * - Not a placeholder value
305
+ *
306
+ * @param {string} apiKey - API key to validate
307
+ * @returns {boolean} `true` if valid, `false` otherwise
308
+ *
309
+ * @internal
310
+ */
311
+ function isValidPostHogApiKey(apiKey: string): boolean {
312
+ // PostHog keys: phc_ prefix + 43 alphanumeric/dash/underscore characters
313
+ if (!/^phc_[\w-]{43}$/.test(apiKey)) {
314
+ return false;
315
+ }
316
+
317
+ // Check for placeholder patterns
318
+ const placeholders = ['your-api-key', 'paste-key-here', 'xxxxxxxx', 'example'];
319
+ if (placeholders.some(p => apiKey.toLowerCase().includes(p.toLowerCase()))) {
320
+ return false;
321
+ }
322
+
323
+ return true;
324
+ }
325
+
326
+ /**
327
+ * Utility to throw validation errors (for strict validation).
328
+ *
329
+ * Validates the configuration and throws an error if validation fails.
330
+ * Useful for ensuring configuration is valid before using analytics.
331
+ *
332
+ * @param {AnalyticsConfig} config - Analytics configuration to validate
333
+ * @throws {Error} If configuration validation fails
334
+ *
335
+ * @example
336
+ * ```typescript
337
+ * try {
338
+ * validateConfigOrThrow(config);
339
+ * // Configuration is valid, proceed
340
+ * } catch (error) {
341
+ * console.error('Invalid config:', error.message);
342
+ * }
343
+ * ```
344
+ */
345
+ export function validateConfigOrThrow(config: AnalyticsConfig): void {
346
+ const result = validateAnalyticsConfig(config);
347
+
348
+ if (!result.isValid) {
349
+ const errorMessages = result.errors
350
+ .map(error => `${error.provider}.${error.field}: ${error.message}`)
351
+ .join('\n');
352
+
353
+ throw new Error(`Analytics configuration validation failed:\n${errorMessages}`);
354
+ }
355
+
356
+ // Log warnings but don't throw
357
+ if (result.warnings.length > 0 && config.onError) {
358
+ config.onError(new Error('Analytics configuration warnings'), {
359
+ provider: 'analytics',
360
+ method: 'validateConfig',
361
+ warnings: result.warnings,
362
+ });
363
+ }
364
+ }
365
+
366
+ /**
367
+ * Development helper to check configuration.
368
+ *
369
+ * Logs configuration details and validation results for debugging.
370
+ * Only useful in development environments.
371
+ *
372
+ * @param {AnalyticsConfig} config - Analytics configuration to debug
373
+ * @returns {Promise<void>} Promise that resolves when debugging is complete
374
+ *
375
+ * @example
376
+ * ```typescript
377
+ * if (process.env.NODE_ENV === 'development') {
378
+ * await debugConfig(config);
379
+ * }
380
+ * ```
381
+ */
382
+ export async function debugConfig(config: AnalyticsConfig): Promise<void> {
383
+ const result = validateAnalyticsConfig(config);
384
+
385
+ logInfo('Analytics Configuration Debug', {
386
+ config,
387
+ validationResult: result,
388
+ });
389
+
390
+ if (result.errors.length > 0) {
391
+ logError('Analytics configuration errors: Validation failed', {
392
+ errors: result.errors,
393
+ });
394
+ }
395
+
396
+ if (result.warnings.length > 0) {
397
+ logWarn('Analytics configuration warnings', { warnings: result.warnings });
398
+ }
399
+ }
package/src/shared.ts ADDED
@@ -0,0 +1,155 @@
1
+ /**
2
+ * @fileoverview Shared Environment Analytics Exports
3
+ *
4
+ * This module provides environment-agnostic analytics functionality for packages
5
+ * that can run in both client and server environments. It automatically detects
6
+ * the runtime environment and uses the appropriate analytics implementation.
7
+ *
8
+ * **Environment Detection**:
9
+ * - Detects server vs client environments
10
+ * - Detects Next.js vs plain Node.js/React environments
11
+ * - Automatically selects the correct analytics manager
12
+ *
13
+ * **Key Features**:
14
+ * - Single API that works in all environments
15
+ * - Automatic environment detection
16
+ * - Type-safe event tracking
17
+ * - Ecommerce and AI event emitters
18
+ *
19
+ * **Usage**: Use this module when you need analytics in code that runs in both
20
+ * client and server contexts (e.g., shared utilities, isomorphic code).
21
+ *
22
+ * @example
23
+ * ```typescript
24
+ * // In environment-agnostic code
25
+ * import { createAnalytics, track } from '@od-oneapp/analytics/shared';
26
+ *
27
+ * // Works in both client and server environments
28
+ * const analytics = await createAnalytics(config);
29
+ * await analytics.emit(track('Event Name', { property: 'value' }));
30
+ * ```
31
+ *
32
+ * @module @od-oneapp/analytics/shared
33
+ */
34
+
35
+ // Import types for proper typing
36
+ import type { AnalyticsConfig, AnalyticsManager } from './shared/types/types';
37
+
38
+ /**
39
+ * Detects if code is running in a server environment.
40
+ *
41
+ * Checks for absence of `window` object and presence of `global` object.
42
+ *
43
+ * @returns {boolean} `true` if running on server, `false` if running in browser
44
+ *
45
+ * @internal
46
+ */
47
+ function isServerEnvironment(): boolean {
48
+ return typeof window === 'undefined' && typeof global !== 'undefined';
49
+ }
50
+
51
+ /**
52
+ * Detects if code is running in a Next.js environment.
53
+ *
54
+ * Checks for Next.js-specific environment variables and globals.
55
+ *
56
+ * @returns {boolean} `true` if running in Next.js, `false` otherwise
57
+ *
58
+ * @internal
59
+ */
60
+ function isNextJSEnvironment(): boolean {
61
+ // Check for Next.js-specific environment variables and globals
62
+ return (
63
+ // Next.js runtime environment variable
64
+ process.env.NEXT_RUNTIME !== undefined ||
65
+ // Next.js data global (client-side)
66
+ typeof (globalThis as any).__NEXT_DATA__ !== 'undefined' ||
67
+ // Edge runtime global
68
+ typeof (globalThis as any).EdgeRuntime !== 'undefined' ||
69
+ // Next.js process title
70
+ (typeof process !== 'undefined' && process.title?.includes('next')) ||
71
+ // Next.js in development mode
72
+ (typeof process !== 'undefined' &&
73
+ process.env.NODE_ENV === 'development' &&
74
+ process.env.NEXT_PUBLIC_APP_ENV !== undefined)
75
+ );
76
+ }
77
+
78
+ /**
79
+ * Creates an analytics manager appropriate for the current environment.
80
+ *
81
+ * Automatically detects the runtime environment (server/client, Next.js/plain) and
82
+ * creates the appropriate analytics manager instance. This allows packages to use
83
+ * analytics without knowing which environment they're running in.
84
+ *
85
+ * @param {AnalyticsConfig} config - Analytics configuration with provider settings
86
+ * @returns {Promise<AnalyticsManager>} Promise resolving to analytics manager instance
87
+ *
88
+ * @example
89
+ * ```typescript
90
+ * const analytics = await createAnalytics({
91
+ * providers: {
92
+ * posthog: { apiKey: process.env.POSTHOG_API_KEY }
93
+ * }
94
+ * });
95
+ *
96
+ * await analytics.emit(track('User Action', { action: 'click' }));
97
+ * ```
98
+ */
99
+ export async function createAnalytics(config: AnalyticsConfig): Promise<AnalyticsManager> {
100
+ const isServer = isServerEnvironment();
101
+ const isNextJS = isNextJSEnvironment();
102
+
103
+ if (isServer) {
104
+ if (isNextJS) {
105
+ const { createServerAnalytics } = await import('./server-next');
106
+ return createServerAnalytics(config);
107
+ } else {
108
+ const { createServerAnalytics } = await import('./server');
109
+ return createServerAnalytics(config);
110
+ }
111
+ } else {
112
+ if (isNextJS) {
113
+ const { createNextJSClientAnalytics } = await import('./client-next');
114
+ return createNextJSClientAnalytics(config);
115
+ } else {
116
+ const { createClientAnalytics } = await import('./client');
117
+ return createClientAnalytics(config);
118
+ }
119
+ }
120
+ }
121
+
122
+ // Re-export essential types that shared packages need
123
+ export type {
124
+ AnalyticsConfig,
125
+ AnalyticsContext,
126
+ AnalyticsManager,
127
+ AnalyticsProvider,
128
+ ProviderConfig,
129
+ TrackingOptions,
130
+ } from './shared/types/types';
131
+
132
+ // Re-export emitters for environment-agnostic usage
133
+ export { aiSdk as ai, alias, ecommerce, group, identify, page, track } from './shared/emitters';
134
+
135
+ /**
136
+ * Environment information for debugging and introspection.
137
+ *
138
+ * Provides runtime information about the current environment, useful for debugging
139
+ * and conditional logic based on environment.
140
+ *
141
+ * @example
142
+ * ```typescript
143
+ * import { environmentInfo } from '@od-oneapp/analytics/shared';
144
+ *
145
+ * console.log('Running on server:', environmentInfo.isServer);
146
+ * console.log('Next.js environment:', environmentInfo.isNextJS);
147
+ * console.log('Runtime:', environmentInfo.runtime);
148
+ * ```
149
+ */
150
+ export const environmentInfo = {
151
+ isServer: isServerEnvironment(),
152
+ isNextJS: isNextJSEnvironment(),
153
+ runtime: typeof process !== 'undefined' ? (process.env.NEXT_RUNTIME ?? 'node') : 'browser',
154
+ nodeEnv: typeof process !== 'undefined' ? process.env.NODE_ENV : 'production',
155
+ };
@@ -0,0 +1,62 @@
1
+ /**
2
+ * @fileoverview Analytics types exports
3
+ *
4
+ * This module re-exports all analytics-related types for convenient importing.
5
+ * It includes:
6
+ *
7
+ * - **Core Types**: AnalyticsConfig, AnalyticsManager, AnalyticsProvider, etc.
8
+ * - **Emitter Types**: EmitterPayload, EmitterTrackPayload, EmitterIdentifyPayload, etc.
9
+ * - **Provider Types**: PostHogConfig, SegmentConfig, VercelConfig, ConsoleConfig
10
+ * - **Ecommerce Types**: BaseProductProperties, CartProperties, OrderProperties, etc.
11
+ *
12
+ * **Usage**: Import types from `@od-oneapp/analytics/types` for type annotations.
13
+ *
14
+ * @example
15
+ * ```typescript
16
+ * import type { AnalyticsConfig, AnalyticsManager } from '@od-oneapp/analytics/types';
17
+ *
18
+ * const config: AnalyticsConfig = {
19
+ * providers: { posthog: { apiKey: '...' } }
20
+ * };
21
+ * ```
22
+ *
23
+ * @module @od-oneapp/analytics/types
24
+ */
25
+
26
+ // Core analytics types
27
+ export type {
28
+ AnalyticsConfig,
29
+ AnalyticsContext,
30
+ AnalyticsManager,
31
+ AnalyticsProvider,
32
+ ProviderConfig,
33
+ ProviderRegistry,
34
+ TrackingOptions,
35
+ } from '../shared/types/types';
36
+
37
+ // Emitter types
38
+ export type {
39
+ EmitterAliasPayload,
40
+ EmitterContext,
41
+ EmitterGroupPayload,
42
+ EmitterIdentifyPayload,
43
+ EmitterOptions,
44
+ EmitterPagePayload,
45
+ EmitterPayload,
46
+ EmitterTrackPayload,
47
+ } from '../shared/emitters/emitter-types';
48
+
49
+ // Provider-specific types
50
+ export type { ConsoleConfig, ConsoleOptions } from '../shared/types/console-types';
51
+ export type { BootstrapData, PostHogConfig, PostHogOptions } from '../shared/types/posthog-types';
52
+ export type { SegmentConfig, SegmentOptions } from '../shared/types/segment-types';
53
+ export type { VercelConfig, VercelOptions } from '../shared/types/vercel-types';
54
+
55
+ // Ecommerce types
56
+ export type {
57
+ BaseProductProperties,
58
+ CartProperties,
59
+ EcommerceEventSpec,
60
+ ExtendedProductProperties,
61
+ OrderProperties,
62
+ } from '../shared/emitters/ecommerce/types';