@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,281 @@
1
+ //#region src/providers/posthog/client.ts
2
+ const logDebug = (_message, _context) => {};
3
+ const logError = (_message, _error, _context) => {};
4
+ const logWarn = (_message, _context) => {};
5
+ var PostHogClientProvider = class {
6
+ name = "posthog";
7
+ config;
8
+ isInitialized = false;
9
+ posthogInstance = null;
10
+ retryQueue = [];
11
+ isOnline = true;
12
+ debugMode = false;
13
+ constructor(config) {
14
+ if (!config.apiKey) throw new Error("PostHog apiKey is required");
15
+ this.config = {
16
+ apiKey: config.apiKey,
17
+ options: config.options
18
+ };
19
+ this.debugMode = config.options?.debug === true || typeof window !== "undefined" && window.location.search.includes("debug=posthog");
20
+ if (typeof window !== "undefined") {
21
+ window.addEventListener("online", () => {
22
+ this.isOnline = true;
23
+ this.flushRetryQueue();
24
+ });
25
+ window.addEventListener("offline", () => {
26
+ this.isOnline = false;
27
+ });
28
+ }
29
+ }
30
+ async initialize() {
31
+ if (this.isInitialized) return;
32
+ try {
33
+ const { default: posthog } = await import("posthog-js");
34
+ const bootstrap = this.config.options?.bootstrap;
35
+ const initOptions = {
36
+ api_host: "https://app.posthog.com",
37
+ capture_pageleave: true,
38
+ capture_pageview: false,
39
+ ui_host: "https://app.posthog.com",
40
+ opt_in_site_apps: false,
41
+ person_profiles: "identified_only",
42
+ respect_dnt: true,
43
+ uuid_version: "v7",
44
+ batch_flush_interval_ms: 1e4,
45
+ request_batching: true,
46
+ session_recording: {
47
+ maskAllInputs: false,
48
+ maskInputOptions: {
49
+ email: false,
50
+ number: false,
51
+ password: true,
52
+ text: false
53
+ },
54
+ recordCanvas: false,
55
+ recordCrossOriginIframes: false,
56
+ sampling: {
57
+ minimumDurationMs: 1e3,
58
+ sampleRate: 1
59
+ }
60
+ },
61
+ debug: this.debugMode,
62
+ ...this.config.options,
63
+ ...bootstrap && { bootstrap: { distinctID: bootstrap.distinctID } }
64
+ };
65
+ posthog.init(this.config.apiKey, initOptions);
66
+ this.posthogInstance = posthog;
67
+ window.posthog = posthog;
68
+ this.isInitialized = true;
69
+ } catch {
70
+ throw new Error("PostHog JS SDK not available. Install with: npm install posthog-js");
71
+ }
72
+ }
73
+ async track(event, properties = {}) {
74
+ if (!this.isInitialized || !this.posthogInstance) {
75
+ await this.queueEvent("track", [event, properties]);
76
+ return;
77
+ }
78
+ try {
79
+ await this.log("Tracking event:", event, properties);
80
+ if (this.debugMode) await this.validateEventProperties(event, properties);
81
+ this.posthogInstance.capture(event, properties);
82
+ } catch (error) {
83
+ if (!this.isOnline) await this.queueEvent("track", [event, properties]);
84
+ await this.reportError(error, "track", {
85
+ event,
86
+ properties
87
+ });
88
+ }
89
+ }
90
+ async identify(userId, traits = {}) {
91
+ if (!this.isInitialized || !this.posthogInstance) return;
92
+ try {
93
+ this.posthogInstance.identify(userId, traits);
94
+ } catch {}
95
+ }
96
+ async page(name, properties = {}) {
97
+ if (!this.isInitialized || !this.posthogInstance) return;
98
+ try {
99
+ this.posthogInstance.capture("$pageview", {
100
+ $current_url: window.location.href,
101
+ $title: name ?? document.title,
102
+ ...properties
103
+ });
104
+ } catch {}
105
+ }
106
+ async group(groupId, traits = {}) {
107
+ if (!this.isInitialized || !this.posthogInstance) return;
108
+ try {
109
+ this.posthogInstance.group("company", groupId, traits);
110
+ } catch {}
111
+ }
112
+ async alias(userId, _previousId) {
113
+ if (!this.isInitialized || !this.posthogInstance) return;
114
+ try {
115
+ this.posthogInstance.alias(userId);
116
+ } catch {}
117
+ }
118
+ async getAllFlags(userId) {
119
+ if (!this.isInitialized || !this.posthogInstance) return {};
120
+ try {
121
+ if (userId) await this.identify(userId);
122
+ return this.posthogInstance.getAllFlags() ?? {};
123
+ } catch {
124
+ return {};
125
+ }
126
+ }
127
+ async getFeatureFlag(flag, userId) {
128
+ if (!this.isInitialized || !this.posthogInstance) return false;
129
+ try {
130
+ if (userId) await this.identify(userId);
131
+ return this.posthogInstance.getFeatureFlag(flag);
132
+ } catch {
133
+ return false;
134
+ }
135
+ }
136
+ async isFeatureEnabled(flag, userId) {
137
+ if (!this.isInitialized || !this.posthogInstance) return false;
138
+ try {
139
+ if (userId) await this.identify(userId);
140
+ return this.posthogInstance.isFeatureEnabled(flag) ?? false;
141
+ } catch {
142
+ return false;
143
+ }
144
+ }
145
+ async getFeatureFlagPayload(flag, userId) {
146
+ if (!this.isInitialized || !this.posthogInstance) return null;
147
+ try {
148
+ if (userId) await this.identify(userId);
149
+ return this.posthogInstance.getFeatureFlagPayload(flag) ?? null;
150
+ } catch {
151
+ return null;
152
+ }
153
+ }
154
+ async getActiveExperiments(userId) {
155
+ if (!this.isInitialized || !this.posthogInstance) return [];
156
+ try {
157
+ if (userId) await this.identify(userId);
158
+ return (this.posthogInstance.getActiveMatchingFeatureFlags() ?? []).map((flag) => ({
159
+ key: flag,
160
+ payload: this.posthogInstance.getFeatureFlagPayload(flag),
161
+ variant: this.posthogInstance.getFeatureFlag(flag)
162
+ }));
163
+ } catch {
164
+ return [];
165
+ }
166
+ }
167
+ async getBootstrapData(distinctId) {
168
+ if (!this.isInitialized || !this.posthogInstance) return { distinctID: distinctId };
169
+ try {
170
+ await this.getAllFlags();
171
+ return { distinctID: distinctId };
172
+ } catch {
173
+ return { distinctID: distinctId };
174
+ }
175
+ }
176
+ reset() {
177
+ if (!this.isInitialized || !this.posthogInstance) return;
178
+ try {
179
+ this.posthogInstance.reset();
180
+ } catch {}
181
+ }
182
+ async shutdown() {
183
+ if (!this.isInitialized || !this.posthogInstance) return;
184
+ try {
185
+ if (this.posthogInstance.shutdown) await this.posthogInstance.shutdown();
186
+ } catch {}
187
+ }
188
+ getDistinctId() {
189
+ if (!this.isInitialized || !this.posthogInstance) return null;
190
+ try {
191
+ return this.posthogInstance.get_distinct_id();
192
+ } catch {
193
+ return null;
194
+ }
195
+ }
196
+ async queueEvent(method, args) {
197
+ this.retryQueue.push({
198
+ args,
199
+ method
200
+ });
201
+ await this.log(`Queued ${method} event for retry: `, args);
202
+ }
203
+ async flushRetryQueue() {
204
+ await this.log(`Flushing retry queue with ${this.retryQueue.length} events`);
205
+ while (this.retryQueue.length > 0) {
206
+ const item = this.retryQueue.shift();
207
+ if (!item) break;
208
+ const { args, method } = item;
209
+ try {
210
+ await this[method](...args);
211
+ } catch {
212
+ if (this.retryQueue.length < 100) await this.queueEvent(method, args);
213
+ break;
214
+ }
215
+ }
216
+ }
217
+ log(...args) {
218
+ if (this.debugMode) logDebug("PostHog Debug:", { args });
219
+ }
220
+ async validateEventProperties(event, properties) {
221
+ const reserved = new Set([
222
+ "$set",
223
+ "$set_once",
224
+ "$unset",
225
+ "distinct_id",
226
+ "$groups"
227
+ ]);
228
+ const conflicts = Object.keys(properties).filter((key) => reserved.has(key) && !key.startsWith("$"));
229
+ if (conflicts.length > 0) logWarn("PostHog: Properties may conflict with reserved names:", {
230
+ conflicts: conflicts.join(", "),
231
+ event
232
+ });
233
+ try {
234
+ JSON.stringify(properties);
235
+ } catch (error) {
236
+ logWarn("PostHog: Event properties contain circular references:", {
237
+ event,
238
+ error: error instanceof Error ? error.message : String(error)
239
+ });
240
+ }
241
+ }
242
+ async reportError(error, method, context) {
243
+ if (this.debugMode) logError("PostHog Error:", error instanceof Error ? error : new Error(String(error)), {
244
+ method,
245
+ context
246
+ });
247
+ }
248
+ async optIn() {
249
+ if (this.posthogInstance) {
250
+ this.posthogInstance.opt_in_capturing();
251
+ await this.log("User opted in to tracking");
252
+ }
253
+ }
254
+ async optOut() {
255
+ if (this.posthogInstance) {
256
+ this.posthogInstance.opt_out_capturing();
257
+ await this.log("User opted out of tracking");
258
+ }
259
+ }
260
+ hasOptedOut() {
261
+ return this.posthogInstance ? this.posthogInstance.has_opted_out_capturing() : false;
262
+ }
263
+ async groupIdentify(groupType, groupKey, groupProperties, options) {
264
+ if (!this.isInitialized || !this.posthogInstance) return;
265
+ try {
266
+ await this.log("Group identify:", groupType, groupKey, groupProperties);
267
+ this.posthogInstance.group(groupType, groupKey, groupProperties);
268
+ if (options?.setAsDefault) this.posthogInstance.register({ [`$groups`]: { [groupType]: groupKey } });
269
+ } catch (error) {
270
+ await this.reportError(error, "groupIdentify", {
271
+ groupKey,
272
+ groupProperties,
273
+ groupType
274
+ });
275
+ }
276
+ }
277
+ };
278
+
279
+ //#endregion
280
+ export { PostHogClientProvider };
281
+ //# sourceMappingURL=client-CeOLjbac.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client-CeOLjbac.mjs","names":[],"sources":["../src/providers/posthog/client.ts"],"sourcesContent":["/**\n * @fileoverview PostHog client-side (browser) provider implementation\n *\n * Provides client-side integration with PostHog Analytics including feature flags support.\n * Supports full PostHog tracking including capture, identify, reset, group, alias, and feature flags.\n *\n * @remarks\n * This provider:\n * - Uses PostHog JavaScript SDK for browser tracking\n * - Supports bootstrap data for SSR optimization\n * - Handles feature flags and experiments\n * - Integrates with PostHog's analytics dashboard\n *\n * @module @repo/analytics/providers/posthog/client\n */\n\n// Simple console fallbacks - observability integration can be added later\nimport type {\n BootstrapData,\n EnhancedPostHogProvider,\n ExperimentInfo,\n PostHogConfig,\n} from './types';\nimport type { AnalyticsProvider, ProviderConfig } from '../../shared/types/types';\nconst logDebug = (_message: string, _context?: any) => {\n // No-op to avoid console warnings in production\n // TODO: Add proper debug logging via observability package\n};\nconst logError = (_message: string, _error?: Error, _context?: any) => {\n // No-op to avoid console warnings in production\n // TODO: Add proper error logging via observability package\n};\nconst logWarn = (_message: string, _context?: any) => {\n // No-op to avoid console warnings in production\n // TODO: Add proper error logging via observability package\n};\n\ndeclare global {\n interface Window {\n posthog?: {\n init: (apiKey: string, options?: any) => void;\n capture: (event: string, properties?: any) => void;\n identify: (userId: string, properties?: any) => void;\n reset: () => void;\n group: (groupType: string, groupKey: string, properties?: any) => void;\n alias: (alias: string) => void;\n people?: {\n set: (properties: any) => void;\n set_once: (properties: any) => void;\n };\n register: (properties: any) => void;\n\n // Feature flag methods\n isFeatureEnabled: (flag: string) => boolean;\n getFeatureFlag: (flag: string) => any;\n getFeatureFlagPayload: (flag: string) => any;\n getAllFlags: () => Record<string, any>;\n onFeatureFlags: (callback: (flags: string[], variants: Record<string, any>) => void) => void;\n\n // Experiment methods\n getActiveMatchingFeatureFlags: () => string[];\n\n // Utility methods\n get_distinct_id: () => string;\n shutdown: () => Promise<void>;\n };\n }\n}\n\nexport class PostHogClientProvider implements AnalyticsProvider, Partial<EnhancedPostHogProvider> {\n readonly name = 'posthog';\n private config: PostHogConfig;\n private isInitialized = false;\n private posthogInstance: any = null;\n private retryQueue: { method: string; args: any[] }[] = [];\n private isOnline = true;\n private debugMode = false;\n\n constructor(config: ProviderConfig) {\n if (!config.apiKey) {\n throw new Error('PostHog apiKey is required');\n }\n\n this.config = {\n apiKey: config.apiKey,\n options: config.options,\n };\n\n // Set up debug mode\n this.debugMode =\n config.options?.debug === true ||\n (typeof window !== 'undefined' && window.location.search.includes('debug=posthog'));\n\n // Monitor network status for retry queue\n if (typeof window !== 'undefined') {\n window.addEventListener('online', () => {\n this.isOnline = true;\n void this.flushRetryQueue();\n });\n\n window.addEventListener('offline', () => {\n this.isOnline = false;\n });\n }\n }\n\n async initialize(): Promise<void> {\n if (this.isInitialized) return;\n\n try {\n // Dynamically import PostHog (optional dependency)\n const { default: posthog } = await import('posthog-js');\n\n // Extract bootstrap data if provided\n const bootstrap = this.config.options?.bootstrap;\n\n // Initialize PostHog with enhanced options and all missing configurations\n const initOptions: any = {\n // Core PostHog configuration with PostHog recommended defaults\n api_host: 'https://app.posthog.com',\n capture_pageleave: true, // Important for engagement tracking\n capture_pageview: false, // We handle pageviews manually\n ui_host: 'https://app.posthog.com',\n\n opt_in_site_apps: false, // Conservative default\n // Privacy & GDPR compliance\n person_profiles: 'identified_only', // GDPR-friendly default\n respect_dnt: true, // Respect Do Not Track headers\n\n // Performance optimizations\n uuid_version: 'v7', // Better performance than v4\n batch_flush_interval_ms: 10000, // 10 second batching\n request_batching: true, // Batch requests for better performance\n\n // Session recording with safe defaults\n session_recording: {\n maskAllInputs: false,\n maskInputOptions: {\n email: false,\n number: false,\n password: true, // Always mask passwords\n text: false,\n },\n recordCanvas: false, // Performance consideration\n recordCrossOriginIframes: false, // Conservative default\n sampling: {\n minimumDurationMs: 1000, // Only record sessions > 1s\n sampleRate: 1, // Record all sessions by default\n },\n },\n\n // Debug mode\n debug: this.debugMode,\n\n // Apply user configuration (this will override defaults)\n ...this.config.options,\n\n // Add bootstrap data if available (must be last to not be overridden)\n ...(bootstrap && {\n bootstrap: {\n distinctID: bootstrap.distinctID,\n },\n }),\n };\n\n posthog.init(this.config.apiKey, initOptions);\n\n // Store instance references\n this.posthogInstance = posthog;\n window.posthog = posthog as any;\n\n this.isInitialized = true;\n } catch {\n throw new Error('PostHog JS SDK not available. Install with: npm install posthog-js');\n }\n }\n\n async track(event: string, properties: any = {}): Promise<void> {\n if (!this.isInitialized || !this.posthogInstance) {\n await this.queueEvent('track', [event, properties]);\n return;\n }\n\n try {\n // Debug logging\n await this.log('Tracking event:', event, properties);\n\n // Validate properties in debug mode\n if (this.debugMode) {\n await this.validateEventProperties(event, properties);\n }\n\n this.posthogInstance.capture(event, properties);\n } catch (error) {\n // Queue event if offline\n if (!this.isOnline) {\n await this.queueEvent('track', [event, properties]);\n }\n\n // Enhanced error reporting\n await this.reportError(error, 'track', { event, properties });\n }\n }\n\n async identify(userId: string, traits: any = {}): Promise<void> {\n if (!this.isInitialized || !this.posthogInstance) {\n return;\n }\n\n try {\n this.posthogInstance.identify(userId, traits);\n } catch {\n // Silently fail to avoid disrupting app flow\n }\n }\n\n async page(name?: string, properties: any = {}): Promise<void> {\n if (!this.isInitialized || !this.posthogInstance) {\n return;\n }\n\n try {\n this.posthogInstance.capture('$pageview', {\n $current_url: window.location.href,\n $title: name ?? document.title,\n ...properties,\n });\n } catch {\n // Silently fail to avoid disrupting app flow\n }\n }\n\n async group(groupId: string, traits: any = {}): Promise<void> {\n if (!this.isInitialized || !this.posthogInstance) {\n return;\n }\n\n try {\n this.posthogInstance.group('company', groupId, traits);\n } catch {\n // Silently fail to avoid disrupting app flow\n }\n }\n\n async alias(userId: string, _previousId: string): Promise<void> {\n if (!this.isInitialized || !this.posthogInstance) {\n return;\n }\n\n try {\n this.posthogInstance.alias(userId);\n } catch {\n // Silently fail to avoid disrupting app flow\n }\n }\n\n // Feature Flag Methods\n async getAllFlags(userId?: string): Promise<Record<string, any>> {\n if (!this.isInitialized || !this.posthogInstance) {\n return {};\n }\n\n try {\n if (userId) {\n // If userId provided, identify first to ensure flags are for correct user\n await this.identify(userId);\n }\n\n return this.posthogInstance.getAllFlags() ?? {};\n } catch {\n return {};\n }\n }\n\n async getFeatureFlag(flag: string, userId?: string): Promise<any> {\n if (!this.isInitialized || !this.posthogInstance) {\n return false;\n }\n\n try {\n if (userId) {\n await this.identify(userId);\n }\n\n return this.posthogInstance.getFeatureFlag(flag);\n } catch {\n return false;\n }\n }\n\n async isFeatureEnabled(flag: string, userId?: string): Promise<boolean> {\n if (!this.isInitialized || !this.posthogInstance) {\n return false;\n }\n\n try {\n if (userId) {\n await this.identify(userId);\n }\n\n return this.posthogInstance.isFeatureEnabled(flag) ?? false;\n } catch {\n return false;\n }\n }\n\n async getFeatureFlagPayload(flag: string, userId?: string): Promise<any | null> {\n if (!this.isInitialized || !this.posthogInstance) {\n return null;\n }\n\n try {\n if (userId) {\n await this.identify(userId);\n }\n\n return this.posthogInstance.getFeatureFlagPayload(flag) ?? null;\n } catch {\n return null;\n }\n }\n\n async getActiveExperiments(userId?: string): Promise<ExperimentInfo[]> {\n if (!this.isInitialized || !this.posthogInstance) {\n return [];\n }\n\n try {\n if (userId) {\n await this.identify(userId);\n }\n\n const activeFlags = this.posthogInstance.getActiveMatchingFeatureFlags() ?? [];\n return activeFlags.map((flag: string) => ({\n key: flag,\n payload: this.posthogInstance.getFeatureFlagPayload(flag),\n variant: this.posthogInstance.getFeatureFlag(flag),\n }));\n } catch {\n return [];\n }\n }\n\n // Bootstrap method (not typically used on client, but included for completeness)\n async getBootstrapData(distinctId: string): Promise<BootstrapData> {\n if (!this.isInitialized || !this.posthogInstance) {\n return { distinctID: distinctId };\n }\n\n try {\n await this.getAllFlags();\n\n return {\n distinctID: distinctId,\n };\n } catch {\n return { distinctID: distinctId };\n }\n }\n\n // Utility Methods\n reset(): void {\n if (!this.isInitialized || !this.posthogInstance) {\n return;\n }\n\n try {\n this.posthogInstance.reset();\n } catch {\n // Silently fail\n }\n }\n\n async shutdown(): Promise<void> {\n if (!this.isInitialized || !this.posthogInstance) {\n return;\n }\n\n try {\n if (this.posthogInstance.shutdown) {\n await this.posthogInstance.shutdown();\n }\n } catch {\n // Silently fail\n }\n }\n\n // Get distinct ID for bootstrap purposes\n getDistinctId(): string | null {\n if (!this.isInitialized || !this.posthogInstance) {\n return null;\n }\n\n try {\n return this.posthogInstance.get_distinct_id();\n } catch {\n return null;\n }\n }\n\n // Enhanced error handling and utility methods\n private async queueEvent(method: string, args: any[]) {\n this.retryQueue.push({ args, method });\n await this.log(`Queued ${method} event for retry: `, args);\n }\n\n private async flushRetryQueue() {\n await this.log(`Flushing retry queue with ${this.retryQueue.length} events`);\n\n while (this.retryQueue.length > 0) {\n const item = this.retryQueue.shift();\n if (!item) break;\n const { args, method } = item;\n try {\n await (this as any)[method](...args);\n } catch {\n // Re-queue failed events (limit retries)\n if (this.retryQueue.length < 100) {\n // Prevent infinite queue growth\n await this.queueEvent(method, args);\n }\n break;\n }\n }\n }\n\n private log(...args: any[]) {\n if (this.debugMode) {\n logDebug('PostHog Debug:', { args });\n }\n }\n\n private async validateEventProperties(event: string, properties: any) {\n // Check for reserved property names\n const reserved = new Set(['$set', '$set_once', '$unset', 'distinct_id', '$groups']);\n const conflicts = Object.keys(properties).filter(\n key => reserved.has(key) && !key.startsWith('$'),\n );\n\n if (conflicts.length > 0) {\n logWarn('PostHog: Properties may conflict with reserved names:', {\n conflicts: conflicts.join(', '),\n event,\n });\n }\n\n // Check for circular references\n try {\n JSON.stringify(properties);\n } catch (error) {\n logWarn('PostHog: Event properties contain circular references:', {\n event,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n private async reportError(error: any, method: string, context: any) {\n if (this.debugMode) {\n logError('PostHog Error:', error instanceof Error ? error : new Error(String(error)), {\n method,\n context,\n });\n }\n\n // Could emit error event to other analytics providers\n // this.emit('analytics_error', { provider: 'posthog', method, error: error.message, context });\n }\n\n // Consent management methods\n async optIn(): Promise<void> {\n if (this.posthogInstance) {\n this.posthogInstance.opt_in_capturing();\n await this.log('User opted in to tracking');\n }\n }\n\n async optOut(): Promise<void> {\n if (this.posthogInstance) {\n this.posthogInstance.opt_out_capturing();\n await this.log('User opted out of tracking');\n }\n }\n\n hasOptedOut(): boolean {\n return this.posthogInstance ? this.posthogInstance.has_opted_out_capturing() : false;\n }\n\n // Enhanced group analytics\n async groupIdentify(\n groupType: string,\n groupKey: string,\n groupProperties: any,\n options?: { setAsDefault?: boolean },\n ): Promise<void> {\n if (!this.isInitialized || !this.posthogInstance) {\n return;\n }\n\n try {\n await this.log('Group identify:', groupType, groupKey, groupProperties);\n\n // Set group properties\n this.posthogInstance.group(groupType, groupKey, groupProperties);\n\n // Optionally set as default group for user\n if (options?.setAsDefault) {\n this.posthogInstance.register({\n [`$groups`]: {\n [groupType]: groupKey,\n },\n });\n }\n } catch (error) {\n await this.reportError(error, 'groupIdentify', { groupKey, groupProperties, groupType });\n }\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,267 @@
1
+ //#region src/providers/base-provider.ts
2
+ /**
3
+ * Abstract base class for analytics providers
4
+ *
5
+ * @example
6
+ * ```typescript
7
+ * class MyProvider extends BaseAnalyticsProvider<MyConfig> {
8
+ * readonly name = 'my-provider';
9
+ *
10
+ * protected async doInitialize(): Promise<void> {
11
+ * // Load SDK and set up client
12
+ * }
13
+ *
14
+ * protected async doTrack(event: string, properties: Properties): Promise<void> {
15
+ * // Call SDK track method
16
+ * }
17
+ *
18
+ * // ... implement other abstract methods
19
+ * }
20
+ * ```
21
+ */
22
+ var BaseAnalyticsProvider = class {
23
+ /** Provider-specific configuration */
24
+ config;
25
+ /** Whether the provider has been initialized */
26
+ isInitialized = false;
27
+ /** Error handler for logging/reporting errors */
28
+ onError;
29
+ constructor(config, defaultConfig = {}) {
30
+ this.config = {
31
+ ...defaultConfig,
32
+ ...config,
33
+ ...config.options
34
+ };
35
+ this.onError = this.config.onError ?? void 0;
36
+ }
37
+ /**
38
+ * Initialize the provider.
39
+ *
40
+ * This is called by the analytics manager before any tracking calls.
41
+ * Calls the abstract `doInitialize()` method and handles errors.
42
+ *
43
+ * @param {ProviderConfig} [config] - Optional provider configuration
44
+ * @returns {Promise<void>} Promise that resolves when initialization is complete
45
+ * @throws {Error} If initialization fails
46
+ */
47
+ async initialize(config) {
48
+ if (this.isInitialized) return;
49
+ try {
50
+ await this.doInitialize(config);
51
+ this.isInitialized = true;
52
+ } catch (error) {
53
+ this.handleError(error, "initialize");
54
+ throw error;
55
+ }
56
+ }
57
+ /**
58
+ * Track an event.
59
+ *
60
+ * Validates that the provider is initialized, then calls the abstract
61
+ * `doTrack()` method. Handles errors gracefully without throwing.
62
+ *
63
+ * @param {string} event - Event name
64
+ * @param {Properties} [properties] - Event properties
65
+ * @param {AnalyticsContext} [context] - Analytics context
66
+ * @returns {Promise<void>} Promise that resolves when tracking is complete
67
+ */
68
+ async track(event, properties = {}, context) {
69
+ if (!this.isInitialized) {
70
+ this.handleError(/* @__PURE__ */ new Error("Provider not initialized"), "track", { event });
71
+ return;
72
+ }
73
+ try {
74
+ await this.doTrack(event, properties, context);
75
+ } catch (error) {
76
+ this.handleError(error, "track", {
77
+ event,
78
+ properties
79
+ });
80
+ }
81
+ }
82
+ /**
83
+ * Identify a user.
84
+ *
85
+ * Validates that the provider is initialized, then calls the abstract
86
+ * `doIdentify()` method. Handles errors gracefully without throwing.
87
+ *
88
+ * @param {string} userId - User identifier
89
+ * @param {UserTraits} [traits] - User traits
90
+ * @param {AnalyticsContext} [context] - Analytics context
91
+ * @returns {Promise<void>} Promise that resolves when identification is complete
92
+ */
93
+ async identify(userId, traits = {}, context) {
94
+ if (!this.isInitialized) {
95
+ this.handleError(/* @__PURE__ */ new Error("Provider not initialized"), "identify", { userId });
96
+ return;
97
+ }
98
+ try {
99
+ await this.doIdentify(userId, traits, context);
100
+ } catch (error) {
101
+ this.handleError(error, "identify", { userId });
102
+ }
103
+ }
104
+ /**
105
+ * Track a page view.
106
+ *
107
+ * Validates that the provider is initialized, then calls the abstract
108
+ * `doPage()` method. Handles errors gracefully.
109
+ *
110
+ * @param {string} [name] - Page name
111
+ * @param {PageProperties} [properties] - Page properties
112
+ * @param {AnalyticsContext} [context] - Analytics context
113
+ * @returns {Promise<void>} Promise that resolves when page tracking is complete
114
+ */
115
+ async page(name, properties = {}, context) {
116
+ if (!this.isInitialized) {
117
+ this.handleError(/* @__PURE__ */ new Error("Provider not initialized"), "page", { name });
118
+ return;
119
+ }
120
+ try {
121
+ await this.doPage(name, properties, context);
122
+ } catch (error) {
123
+ this.handleError(error, "page", { name });
124
+ }
125
+ }
126
+ /**
127
+ * Associate user with a group.
128
+ *
129
+ * Validates that the provider is initialized, then calls the abstract
130
+ * `doGroup()` method. Handles errors gracefully.
131
+ *
132
+ * @param {string} groupId - Group identifier
133
+ * @param {GroupTraits} [traits] - Group traits
134
+ * @param {AnalyticsContext} [context] - Analytics context
135
+ * @returns {Promise<void>} Promise that resolves when group association is complete
136
+ */
137
+ async group(groupId, traits = {}, context) {
138
+ if (!this.isInitialized) {
139
+ this.handleError(/* @__PURE__ */ new Error("Provider not initialized"), "group", { groupId });
140
+ return;
141
+ }
142
+ try {
143
+ await this.doGroup(groupId, traits, context);
144
+ } catch (error) {
145
+ this.handleError(error, "group", { groupId });
146
+ }
147
+ }
148
+ /**
149
+ * Alias one user ID to another.
150
+ *
151
+ * Validates that the provider is initialized, then calls the abstract
152
+ * `doAlias()` method. Handles errors gracefully.
153
+ *
154
+ * @param {string} userId - New user identifier
155
+ * @param {string} previousId - Previous user identifier
156
+ * @param {AnalyticsContext} [context] - Analytics context
157
+ * @returns {Promise<void>} Promise that resolves when aliasing is complete
158
+ */
159
+ async alias(userId, previousId, context) {
160
+ if (!this.isInitialized) {
161
+ this.handleError(/* @__PURE__ */ new Error("Provider not initialized"), "alias", {
162
+ userId,
163
+ previousId
164
+ });
165
+ return;
166
+ }
167
+ try {
168
+ await this.doAlias(userId, previousId, context);
169
+ } catch (error) {
170
+ this.handleError(error, "alias", {
171
+ userId,
172
+ previousId
173
+ });
174
+ }
175
+ }
176
+ /**
177
+ * Handle errors consistently across all methods.
178
+ *
179
+ * Calls the error handler callback if configured. Errors are swallowed
180
+ * in production to not disrupt app flow, but logged via callback.
181
+ *
182
+ * @param {unknown} error - The error that occurred
183
+ * @param {string} method - Method name where error occurred
184
+ * @param {Record<string, unknown>} [metadata] - Additional error metadata
185
+ *
186
+ * @internal
187
+ */
188
+ handleError(error, method, metadata) {
189
+ if (this.onError) this.onError(error, {
190
+ provider: this.name,
191
+ method,
192
+ ...metadata
193
+ });
194
+ }
195
+ /**
196
+ * Check if provider is ready to accept tracking calls.
197
+ *
198
+ * @returns {boolean} `true` if provider is initialized and ready, `false` otherwise
199
+ */
200
+ isReady() {
201
+ return this.isInitialized;
202
+ }
203
+ };
204
+
205
+ //#endregion
206
+ //#region src/providers/segment/client.ts
207
+ /**
208
+ * @fileoverview Segment client-side (browser) provider implementation
209
+ *
210
+ * Provides client-side integration with Segment Analytics using @segment/analytics-next.
211
+ * Supports full Segment.io spec tracking including track, identify, page, group, and alias.
212
+ *
213
+ * @remarks
214
+ * This provider:
215
+ * - Uses @segment/analytics-next for browser tracking
216
+ * - Supports dynamic imports to avoid SSR issues
217
+ * - Handles initialization and event tracking
218
+ * - Integrates with Segment's CDN and API
219
+ *
220
+ * @module @od-oneapp/analytics/providers/segment/client
221
+ */
222
+ var SegmentClientProvider = class extends BaseAnalyticsProvider {
223
+ name = "segment";
224
+ analytics = null;
225
+ constructor(config) {
226
+ super(config);
227
+ if (!config.writeKey) throw new Error("Segment writeKey is required");
228
+ this.config = {
229
+ options: config.options,
230
+ writeKey: config.writeKey
231
+ };
232
+ }
233
+ async doInitialize() {
234
+ const { AnalyticsBrowser } = await import(
235
+ /* webpackChunkName: "segment-analytics-browser" */
236
+ "@segment/analytics-next"
237
+ );
238
+ this.analytics = AnalyticsBrowser.load({
239
+ writeKey: this.config.writeKey,
240
+ ...this.config.options
241
+ });
242
+ }
243
+ async doTrack(event, properties, _context) {
244
+ if (!this.analytics) return;
245
+ await this.analytics.track(event, properties);
246
+ }
247
+ async doIdentify(userId, traits, _context) {
248
+ if (!this.analytics) return;
249
+ await this.analytics.identify(userId, traits);
250
+ }
251
+ async doPage(name, properties, _context) {
252
+ if (!this.analytics) return;
253
+ await this.analytics.page(name, properties);
254
+ }
255
+ async doGroup(groupId, traits, _context) {
256
+ if (!this.analytics) return;
257
+ await this.analytics.group(groupId, traits);
258
+ }
259
+ async doAlias(userId, previousId, _context) {
260
+ if (!this.analytics) return;
261
+ await this.analytics.alias(userId, previousId);
262
+ }
263
+ };
264
+
265
+ //#endregion
266
+ export { SegmentClientProvider };
267
+ //# sourceMappingURL=client-D339NFJS.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client-D339NFJS.mjs","names":[],"sources":["../src/providers/base-provider.ts","../src/providers/segment/client.ts"],"sourcesContent":["/**\n * @fileoverview Base Analytics Provider\n *\n * Abstract base class that implements common provider patterns:\n * - Initialization state management\n * - Safe method execution with error handling\n * - Consistent interface implementation\n * - Error handling and logging\n *\n * **Provider Development**: Providers should extend this class and implement\n * the abstract methods (`doInitialize`, `doTrack`, `doIdentify`, etc.).\n *\n * **Benefits**:\n * - Consistent error handling across all providers\n * - Initialization state management\n * - Safe method execution (checks initialization before calling)\n * - Error callbacks for logging/reporting\n *\n * @module @od-oneapp/analytics/providers/base-provider\n */\n\nimport type {\n AnalyticsContext,\n AnalyticsProvider,\n GroupTraits,\n PageProperties,\n Properties,\n ProviderConfig,\n UserTraits,\n} from '../shared/types/types';\n\n/**\n * Error handler type for provider operations.\n *\n * Called when an error occurs during provider operations. Receives the error\n * and context about which provider and method failed.\n *\n * @param {unknown} error - The error that occurred\n * @param {object} context - Context about the error (provider name, method name, metadata)\n */\nexport type ProviderErrorHandler = (\n error: unknown,\n context: {\n provider: string;\n method: string;\n [key: string]: unknown;\n },\n) => void;\n\n/**\n * Base configuration for all providers.\n *\n * Common configuration options that all providers support.\n */\nexport interface BaseProviderConfig {\n /** Error handler callback */\n onError?: ProviderErrorHandler;\n /** Enable debug mode */\n debug?: boolean;\n}\n\n/**\n * Abstract base class for analytics providers\n *\n * @example\n * ```typescript\n * class MyProvider extends BaseAnalyticsProvider<MyConfig> {\n * readonly name = 'my-provider';\n *\n * protected async doInitialize(): Promise<void> {\n * // Load SDK and set up client\n * }\n *\n * protected async doTrack(event: string, properties: Properties): Promise<void> {\n * // Call SDK track method\n * }\n *\n * // ... implement other abstract methods\n * }\n * ```\n */\nexport abstract class BaseAnalyticsProvider<\n TConfig extends BaseProviderConfig = BaseProviderConfig,\n> implements AnalyticsProvider {\n /** Provider name used for identification and logging */\n abstract readonly name: string;\n\n /** Provider-specific configuration */\n protected config: TConfig;\n\n /** Whether the provider has been initialized */\n protected isInitialized = false;\n\n /** Error handler for logging/reporting errors */\n protected onError?: ProviderErrorHandler | undefined;\n\n constructor(config: ProviderConfig, defaultConfig: Partial<TConfig> = {}) {\n this.config = {\n ...defaultConfig,\n ...config,\n ...(config.options as Partial<TConfig>),\n } as TConfig;\n this.onError = this.config.onError ?? undefined;\n }\n\n /**\n * Initialize the provider.\n *\n * This is called by the analytics manager before any tracking calls.\n * Calls the abstract `doInitialize()` method and handles errors.\n *\n * @param {ProviderConfig} [config] - Optional provider configuration\n * @returns {Promise<void>} Promise that resolves when initialization is complete\n * @throws {Error} If initialization fails\n */\n async initialize(config?: ProviderConfig): Promise<void> {\n if (this.isInitialized) return;\n\n try {\n await this.doInitialize(config);\n this.isInitialized = true;\n } catch (error) {\n this.handleError(error, 'initialize');\n throw error; // Re-throw to let manager know initialization failed\n }\n }\n\n /**\n * Track an event.\n *\n * Validates that the provider is initialized, then calls the abstract\n * `doTrack()` method. Handles errors gracefully without throwing.\n *\n * @param {string} event - Event name\n * @param {Properties} [properties] - Event properties\n * @param {AnalyticsContext} [context] - Analytics context\n * @returns {Promise<void>} Promise that resolves when tracking is complete\n */\n async track(\n event: string,\n properties: Properties = {},\n context?: AnalyticsContext,\n ): Promise<void> {\n if (!this.isInitialized) {\n this.handleError(new Error('Provider not initialized'), 'track', { event });\n return;\n }\n\n try {\n await this.doTrack(event, properties, context);\n } catch (error) {\n this.handleError(error, 'track', { event, properties });\n }\n }\n\n /**\n * Identify a user.\n *\n * Validates that the provider is initialized, then calls the abstract\n * `doIdentify()` method. Handles errors gracefully without throwing.\n *\n * @param {string} userId - User identifier\n * @param {UserTraits} [traits] - User traits\n * @param {AnalyticsContext} [context] - Analytics context\n * @returns {Promise<void>} Promise that resolves when identification is complete\n */\n async identify(\n userId: string,\n traits: UserTraits = {},\n context?: AnalyticsContext,\n ): Promise<void> {\n if (!this.isInitialized) {\n this.handleError(new Error('Provider not initialized'), 'identify', { userId });\n return;\n }\n\n try {\n await this.doIdentify(userId, traits, context);\n } catch (error) {\n this.handleError(error, 'identify', { userId });\n }\n }\n\n /**\n * Track a page view.\n *\n * Validates that the provider is initialized, then calls the abstract\n * `doPage()` method. Handles errors gracefully.\n *\n * @param {string} [name] - Page name\n * @param {PageProperties} [properties] - Page properties\n * @param {AnalyticsContext} [context] - Analytics context\n * @returns {Promise<void>} Promise that resolves when page tracking is complete\n */\n async page(\n name?: string,\n properties: PageProperties = {},\n context?: AnalyticsContext,\n ): Promise<void> {\n if (!this.isInitialized) {\n this.handleError(new Error('Provider not initialized'), 'page', { name });\n return;\n }\n\n try {\n await this.doPage(name, properties, context);\n } catch (error) {\n this.handleError(error, 'page', { name });\n }\n }\n\n /**\n * Associate user with a group.\n *\n * Validates that the provider is initialized, then calls the abstract\n * `doGroup()` method. Handles errors gracefully.\n *\n * @param {string} groupId - Group identifier\n * @param {GroupTraits} [traits] - Group traits\n * @param {AnalyticsContext} [context] - Analytics context\n * @returns {Promise<void>} Promise that resolves when group association is complete\n */\n async group(\n groupId: string,\n traits: GroupTraits = {},\n context?: AnalyticsContext,\n ): Promise<void> {\n if (!this.isInitialized) {\n this.handleError(new Error('Provider not initialized'), 'group', { groupId });\n return;\n }\n\n try {\n await this.doGroup(groupId, traits, context);\n } catch (error) {\n this.handleError(error, 'group', { groupId });\n }\n }\n\n /**\n * Alias one user ID to another.\n *\n * Validates that the provider is initialized, then calls the abstract\n * `doAlias()` method. Handles errors gracefully.\n *\n * @param {string} userId - New user identifier\n * @param {string} previousId - Previous user identifier\n * @param {AnalyticsContext} [context] - Analytics context\n * @returns {Promise<void>} Promise that resolves when aliasing is complete\n */\n async alias(userId: string, previousId: string, context?: AnalyticsContext): Promise<void> {\n if (!this.isInitialized) {\n this.handleError(new Error('Provider not initialized'), 'alias', { userId, previousId });\n return;\n }\n\n try {\n await this.doAlias(userId, previousId, context);\n } catch (error) {\n this.handleError(error, 'alias', { userId, previousId });\n }\n }\n\n /**\n * Set global context for the provider\n */\n setContext?(context: AnalyticsContext): void;\n\n /**\n * Handle errors consistently across all methods.\n *\n * Calls the error handler callback if configured. Errors are swallowed\n * in production to not disrupt app flow, but logged via callback.\n *\n * @param {unknown} error - The error that occurred\n * @param {string} method - Method name where error occurred\n * @param {Record<string, unknown>} [metadata] - Additional error metadata\n *\n * @internal\n */\n protected handleError(error: unknown, method: string, metadata?: Record<string, unknown>): void {\n if (this.onError) {\n this.onError(error, {\n provider: this.name,\n method,\n ...metadata,\n });\n }\n // In production, errors are swallowed to not disrupt app flow\n // Logging happens via onError callback if provided\n }\n\n /**\n * Check if provider is ready to accept tracking calls.\n *\n * @returns {boolean} `true` if provider is initialized and ready, `false` otherwise\n */\n isReady(): boolean {\n return this.isInitialized;\n }\n\n // ============================================================================\n // ABSTRACT METHODS - Must be implemented by subclasses\n // ============================================================================\n\n /**\n * Perform provider-specific initialization.\n *\n * Called by `initialize()` after checking `isInitialized` flag.\n * Subclasses must implement this to perform actual provider initialization.\n *\n * @param {ProviderConfig} [config] - Optional provider configuration\n * @returns {Promise<void>} Promise that resolves when initialization is complete\n *\n * @protected\n * @abstract\n */\n protected abstract doInitialize(config?: ProviderConfig): Promise<void>;\n\n /**\n * Perform provider-specific track call.\n *\n * Called by `track()` after validation. Subclasses must implement this\n * to perform actual event tracking.\n *\n * @param {string} event - Event name\n * @param {Properties} properties - Event properties\n * @param {AnalyticsContext} [context] - Analytics context\n * @returns {Promise<void>} Promise that resolves when tracking is complete\n *\n * @protected\n * @abstract\n */\n protected abstract doTrack(\n event: string,\n properties: Properties,\n context?: AnalyticsContext,\n ): Promise<void>;\n\n /**\n * Perform provider-specific identify call.\n *\n * Called by `identify()` after validation. Subclasses must implement this\n * to perform actual user identification.\n *\n * @param {string} userId - User identifier\n * @param {UserTraits} traits - User traits\n * @param {AnalyticsContext} [context] - Analytics context\n * @returns {Promise<void>} Promise that resolves when identification is complete\n *\n * @protected\n * @abstract\n */\n protected abstract doIdentify(\n userId: string,\n traits: UserTraits,\n context?: AnalyticsContext,\n ): Promise<void>;\n\n /**\n * Perform provider-specific page call.\n *\n * Called by `page()` after validation. Subclasses must implement this\n * to perform actual page view tracking.\n *\n * @param {string | undefined} name - Page name\n * @param {PageProperties} properties - Page properties\n * @param {AnalyticsContext} [context] - Analytics context\n * @returns {Promise<void>} Promise that resolves when page tracking is complete\n *\n * @protected\n * @abstract\n */\n protected abstract doPage(\n name: string | undefined,\n properties: PageProperties,\n context?: AnalyticsContext,\n ): Promise<void>;\n\n /**\n * Perform provider-specific group call.\n *\n * Called by `group()` after validation. Subclasses must implement this\n * to perform actual group association.\n *\n * @param {string} groupId - Group identifier\n * @param {GroupTraits} traits - Group traits\n * @param {AnalyticsContext} [context] - Analytics context\n * @returns {Promise<void>} Promise that resolves when group association is complete\n *\n * @protected\n * @abstract\n */\n protected abstract doGroup(\n groupId: string,\n traits: GroupTraits,\n context?: AnalyticsContext,\n ): Promise<void>;\n\n /**\n * Perform provider-specific alias call.\n *\n * Called by `alias()` after validation. Subclasses must implement this\n * to perform actual user ID aliasing.\n *\n * @param {string} userId - New user identifier\n * @param {string} previousId - Previous user identifier\n * @param {AnalyticsContext} [context] - Analytics context\n * @returns {Promise<void>} Promise that resolves when aliasing is complete\n *\n * @protected\n * @abstract\n */\n protected abstract doAlias(\n userId: string,\n previousId: string,\n context?: AnalyticsContext,\n ): Promise<void>;\n}\n","/**\n * @fileoverview Segment client-side (browser) provider implementation\n *\n * Provides client-side integration with Segment Analytics using @segment/analytics-next.\n * Supports full Segment.io spec tracking including track, identify, page, group, and alias.\n *\n * @remarks\n * This provider:\n * - Uses @segment/analytics-next for browser tracking\n * - Supports dynamic imports to avoid SSR issues\n * - Handles initialization and event tracking\n * - Integrates with Segment's CDN and API\n *\n * @module @repo/analytics/providers/segment/client\n */\n\nimport { BaseAnalyticsProvider } from '../base-provider';\n\nimport type { SegmentConfig } from './types';\nimport type {\n AnalyticsContext,\n GroupTraits,\n PageProperties,\n Properties,\n ProviderConfig,\n UserTraits,\n} from '../../shared/types/types';\n\n// Type for AnalyticsBrowser instance\ninterface AnalyticsBrowserInstance {\n track: (event: string, properties?: Properties) => Promise<unknown>;\n identify: (userId: string, traits?: UserTraits) => Promise<unknown>;\n page: (name?: string, properties?: PageProperties) => Promise<unknown>;\n group: (groupId: string, traits?: GroupTraits) => Promise<unknown>;\n alias: (userId: string, previousId: string) => Promise<unknown>;\n}\n\nexport class SegmentClientProvider extends BaseAnalyticsProvider<SegmentConfig> {\n readonly name = 'segment';\n private analytics: AnalyticsBrowserInstance | null = null;\n\n constructor(config: ProviderConfig) {\n super(config);\n\n if (!config.writeKey) {\n throw new Error('Segment writeKey is required');\n }\n\n this.config = {\n options: config.options as Record<string, unknown>,\n writeKey: config.writeKey,\n };\n }\n\n protected async doInitialize(): Promise<void> {\n // Dynamically import Segment Analytics Next\n const { AnalyticsBrowser } = await import(\n /* webpackChunkName: \"segment-analytics-browser\" */\n '@segment/analytics-next'\n );\n\n // Initialize Analytics Browser\n this.analytics = AnalyticsBrowser.load({\n writeKey: this.config.writeKey,\n ...this.config.options,\n }) as unknown as AnalyticsBrowserInstance;\n }\n\n protected async doTrack(\n event: string,\n properties: Properties,\n _context?: AnalyticsContext,\n ): Promise<void> {\n if (!this.analytics) return;\n await this.analytics.track(event, properties);\n }\n\n protected async doIdentify(\n userId: string,\n traits: UserTraits,\n _context?: AnalyticsContext,\n ): Promise<void> {\n if (!this.analytics) return;\n await this.analytics.identify(userId, traits);\n }\n\n protected async doPage(\n name: string | undefined,\n properties: PageProperties,\n _context?: AnalyticsContext,\n ): Promise<void> {\n if (!this.analytics) return;\n await this.analytics.page(name, properties);\n }\n\n protected async doGroup(\n groupId: string,\n traits: GroupTraits,\n _context?: AnalyticsContext,\n ): Promise<void> {\n if (!this.analytics) return;\n await this.analytics.group(groupId, traits);\n }\n\n protected async doAlias(\n userId: string,\n previousId: string,\n _context?: AnalyticsContext,\n ): Promise<void> {\n if (!this.analytics) return;\n await this.analytics.alias(userId, previousId);\n }\n}\n"],"mappings":"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"}