@envive-ai/react-hooks 0.3.18 → 0.3.19-alpha-marlo-1

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 (207) hide show
  1. package/dist/application/commerce-api.cjs +14 -13
  2. package/dist/application/commerce-api.js +14 -13
  3. package/dist/application/logging/logger.cjs +16 -10
  4. package/dist/application/logging/logger.js +16 -10
  5. package/dist/application/models/guards/api/isApiFormResponse.cjs +9 -8
  6. package/dist/application/models/guards/api/isApiFormResponse.js +9 -8
  7. package/dist/application/models/guards/api/isApiFormSubmittedResponseAttributes.cjs +6 -5
  8. package/dist/application/models/guards/api/isApiFormSubmittedResponseAttributes.js +6 -5
  9. package/dist/application/models/guards/api/isApiOrderResponseAttributes.cjs +19 -18
  10. package/dist/application/models/guards/api/isApiOrderResponseAttributes.js +19 -18
  11. package/dist/application/models/guards/api/isApiOrgConfigResults.cjs +27 -26
  12. package/dist/application/models/guards/api/isApiOrgConfigResults.js +27 -26
  13. package/dist/application/models/guards/api/isApiOrganizationConfig.cjs +23 -22
  14. package/dist/application/models/guards/api/isApiOrganizationConfig.js +23 -22
  15. package/dist/application/models/guards/api/isApiProductResponseAttributes.cjs +12 -11
  16. package/dist/application/models/guards/api/isApiProductResponseAttributes.js +12 -11
  17. package/dist/application/models/guards/api/isApiResponse.cjs +7 -6
  18. package/dist/application/models/guards/api/isApiResponse.js +7 -6
  19. package/dist/application/models/guards/graphQL/isGraphQLColorsConfig.cjs +5 -4
  20. package/dist/application/models/guards/graphQL/isGraphQLColorsConfig.js +5 -4
  21. package/dist/application/models/validators/validateGraphQLFrontendConfig.cjs +15 -14
  22. package/dist/application/models/validators/validateGraphQLFrontendConfig.js +15 -14
  23. package/dist/application/utils/analyticsUtils.cjs +4 -3
  24. package/dist/application/utils/analyticsUtils.js +4 -3
  25. package/dist/application/utils/elementObserver.d.cts +2 -2
  26. package/dist/application/utils/elementObserver.d.ts +2 -2
  27. package/dist/application/utils/nextMessageRequestToApiRequest.cjs +3 -1
  28. package/dist/application/utils/nextMessageRequestToApiRequest.js +3 -1
  29. package/dist/atoms/app/index.d.ts +7 -7
  30. package/dist/atoms/app/variant.cjs +3 -2
  31. package/dist/atoms/app/variant.d.ts +6 -6
  32. package/dist/atoms/app/variant.js +3 -2
  33. package/dist/atoms/chat/chatState.d.cts +18 -18
  34. package/dist/atoms/chat/chatState.d.ts +18 -18
  35. package/dist/atoms/chat/form.d.ts +3 -3
  36. package/dist/atoms/chat/index.d.cts +2 -2
  37. package/dist/atoms/chat/index.d.ts +3 -3
  38. package/dist/atoms/chat/lastMessage.d.cts +2 -2
  39. package/dist/atoms/chat/lastMessage.d.ts +2 -2
  40. package/dist/atoms/chat/messageQueue.d.ts +7 -7
  41. package/dist/atoms/chat/performanceMetrics.cjs +3 -2
  42. package/dist/atoms/chat/performanceMetrics.d.cts +6 -6
  43. package/dist/atoms/chat/performanceMetrics.d.ts +6 -6
  44. package/dist/atoms/chat/performanceMetrics.js +3 -2
  45. package/dist/atoms/chat/renderedWidgetRefs.d.cts +2 -2
  46. package/dist/atoms/chat/renderedWidgetRefs.d.ts +2 -2
  47. package/dist/atoms/chat/replies.d.cts +2 -2
  48. package/dist/atoms/chat/replies.d.ts +3 -3
  49. package/dist/atoms/chat/suggestions.d.cts +2 -2
  50. package/dist/atoms/chat/suggestions.d.ts +3 -3
  51. package/dist/atoms/envive/enviveConfig.cjs +5 -4
  52. package/dist/atoms/envive/enviveConfig.d.cts +13 -13
  53. package/dist/atoms/envive/enviveConfig.d.ts +13 -13
  54. package/dist/atoms/envive/enviveConfig.js +5 -4
  55. package/dist/atoms/globalSearch/globalSearch.d.cts +5 -5
  56. package/dist/atoms/globalSearch/globalSearch.d.ts +5 -5
  57. package/dist/atoms/org/customerService.d.cts +6 -6
  58. package/dist/atoms/org/customerService.d.ts +6 -6
  59. package/dist/atoms/org/graphqlConfig.d.cts +4 -4
  60. package/dist/atoms/org/graphqlConfig.d.ts +4 -4
  61. package/dist/atoms/org/newOrgConfigAtom.d.cts +2 -2
  62. package/dist/atoms/org/newOrgConfigAtom.d.ts +2 -2
  63. package/dist/atoms/org/orgAnalyticsConfig.d.cts +5 -5
  64. package/dist/atoms/org/orgAnalyticsConfig.d.ts +5 -5
  65. package/dist/atoms/search/chatSearch.d.cts +17 -17
  66. package/dist/atoms/search/chatSearch.d.ts +17 -17
  67. package/dist/atoms/search/searchAPI.d.cts +13 -13
  68. package/dist/atoms/search/searchAPI.d.ts +13 -13
  69. package/dist/atoms/search/types.d.cts +1 -1
  70. package/dist/atoms/search/types.d.ts +1 -1
  71. package/dist/atoms/search/utils.d.ts +1 -1
  72. package/dist/atoms/widget/chatPreviewLoading.d.ts +2 -2
  73. package/dist/contexts/amplitudeContext/amplitudeContext.cjs +4 -4
  74. package/dist/contexts/amplitudeContext/amplitudeContext.js +3 -3
  75. package/dist/contexts/enviveConfigContext/enviveConfigContext.cjs +26 -15
  76. package/dist/contexts/enviveConfigContext/enviveConfigContext.d.cts +2 -4
  77. package/dist/contexts/enviveConfigContext/enviveConfigContext.d.ts +2 -4
  78. package/dist/contexts/enviveConfigContext/enviveConfigContext.js +29 -16
  79. package/dist/contexts/enviveConfigContext/index.cjs +2 -1
  80. package/dist/contexts/enviveConfigContext/index.d.cts +2 -1
  81. package/dist/contexts/enviveConfigContext/index.d.ts +2 -1
  82. package/dist/contexts/enviveConfigContext/index.js +2 -1
  83. package/dist/contexts/enviveConfigContext/useEnviveConfig.cjs +12 -0
  84. package/dist/contexts/enviveConfigContext/useEnviveConfig.d.cts +7 -0
  85. package/dist/contexts/enviveConfigContext/useEnviveConfig.d.ts +7 -0
  86. package/dist/contexts/enviveConfigContext/useEnviveConfig.js +11 -0
  87. package/dist/contexts/enviveContext/WindowChatToggleBinder.cjs +7 -5
  88. package/dist/contexts/enviveContext/WindowChatToggleBinder.js +6 -4
  89. package/dist/contexts/enviveContext/enviveContext.cjs +77 -48
  90. package/dist/contexts/enviveContext/enviveContext.d.cts +8 -2
  91. package/dist/contexts/enviveContext/enviveContext.d.ts +8 -2
  92. package/dist/contexts/enviveContext/enviveContext.js +78 -49
  93. package/dist/contexts/enviveContext/index.d.cts +2 -2
  94. package/dist/contexts/enviveContext/index.d.ts +2 -2
  95. package/dist/contexts/featureFlagServiceContext/featureFlagServiceContext.cjs +7 -6
  96. package/dist/contexts/featureFlagServiceContext/featureFlagServiceContext.js +7 -6
  97. package/dist/contexts/graphqlContext/graphqlContext.cjs +8 -7
  98. package/dist/contexts/graphqlContext/graphqlContext.js +8 -7
  99. package/dist/contexts/hardcopyContext/hardcopyContext.cjs +9 -8
  100. package/dist/contexts/hardcopyContext/hardcopyContext.js +9 -8
  101. package/dist/contexts/localStorageContext/localStorageContext.cjs +4 -3
  102. package/dist/contexts/localStorageContext/localStorageContext.js +4 -3
  103. package/dist/contexts/pageContext/pageContext.cjs +23 -4
  104. package/dist/contexts/pageContext/pageContext.d.cts +3 -1
  105. package/dist/contexts/pageContext/pageContext.d.ts +3 -1
  106. package/dist/contexts/pageContext/pageContext.js +24 -5
  107. package/dist/contexts/pageContext/types.d.ts +1 -1
  108. package/dist/contexts/salesAgentContext/chatAPI.cjs +3 -2
  109. package/dist/contexts/salesAgentContext/chatAPI.js +3 -2
  110. package/dist/contexts/salesAgentContext/salesAgentContext.cjs +4 -3
  111. package/dist/contexts/salesAgentContext/salesAgentContext.js +4 -3
  112. package/dist/contexts/salesAgentContext/salesAgentService.cjs +3 -2
  113. package/dist/contexts/salesAgentContext/salesAgentService.js +3 -2
  114. package/dist/contexts/searchContext/searchContext.cjs +8 -6
  115. package/dist/contexts/searchContext/searchContext.js +7 -5
  116. package/dist/contexts/sessionStorageContext/sessionStorageContext.cjs +3 -2
  117. package/dist/contexts/sessionStorageContext/sessionStorageContext.js +3 -2
  118. package/dist/contexts/systemSettingsContext/systemSettingsContext.d.cts +2 -2
  119. package/dist/contexts/systemSettingsContext/systemSettingsContext.d.ts +2 -2
  120. package/dist/contexts/types.d.cts +1 -1
  121. package/dist/contexts/types.d.ts +1 -1
  122. package/dist/contexts/typesV3.d.cts +1 -1
  123. package/dist/contexts/typesV3.d.ts +1 -1
  124. package/dist/contexts/uiConfigContext/index.cjs +0 -1
  125. package/dist/contexts/uiConfigContext/index.d.cts +2 -2
  126. package/dist/contexts/uiConfigContext/index.d.ts +2 -2
  127. package/dist/contexts/uiConfigContext/index.js +2 -2
  128. package/dist/contexts/uiConfigContext/uiConfigContext.cjs +13 -30
  129. package/dist/contexts/uiConfigContext/uiConfigContext.d.cts +5 -9
  130. package/dist/contexts/uiConfigContext/uiConfigContext.d.ts +5 -9
  131. package/dist/contexts/uiConfigContext/uiConfigContext.js +14 -29
  132. package/dist/contexts/userIdentityContext/userIdentityContext.cjs +7 -7
  133. package/dist/contexts/userIdentityContext/userIdentityContext.js +7 -7
  134. package/dist/contexts/widgetConfigContext/widgetConfigContext.cjs +4 -3
  135. package/dist/contexts/widgetConfigContext/widgetConfigContext.js +4 -3
  136. package/dist/hooks/CustomerSupportHandoff/useCustomerSupportHandoff.cjs +4 -3
  137. package/dist/hooks/CustomerSupportHandoff/useCustomerSupportHandoff.js +4 -3
  138. package/dist/hooks/GrabAndScroll/useGrabAndScroll.d.cts +2 -2
  139. package/dist/hooks/GrabAndScroll/useGrabAndScroll.d.ts +2 -2
  140. package/dist/hooks/WidgetInteraction/types.d.ts +1 -1
  141. package/dist/hooks/WidgetInteraction/useWidgetInteraction.cjs +2 -2
  142. package/dist/hooks/WidgetInteraction/useWidgetInteraction.js +2 -2
  143. package/dist/hooks/WidgetInteraction/utils.cjs +2 -1
  144. package/dist/hooks/WidgetInteraction/utils.d.ts +1 -1
  145. package/dist/hooks/WidgetInteraction/utils.js +2 -1
  146. package/dist/hooks/utils.d.ts +1 -1
  147. package/dist/services/amplitudeService/amplitudeService.cjs +20 -7
  148. package/dist/services/amplitudeService/amplitudeService.d.cts +4 -1
  149. package/dist/services/amplitudeService/amplitudeService.d.ts +4 -1
  150. package/dist/services/amplitudeService/amplitudeService.js +20 -7
  151. package/dist/services/ga4ProjectionService/ga4ProjectionService.cjs +3 -2
  152. package/dist/services/ga4ProjectionService/ga4ProjectionService.js +3 -2
  153. package/dist/services/userIdentityService/userIdentityService.cjs +8 -7
  154. package/dist/services/userIdentityService/userIdentityService.js +8 -7
  155. package/package.json +2 -2
  156. package/src/application/commerce-api.ts +14 -12
  157. package/src/application/logging/logger.ts +33 -8
  158. package/src/application/models/guards/api/isApiFormResponse.ts +9 -7
  159. package/src/application/models/guards/api/isApiFormSubmittedResponseAttributes.ts +6 -4
  160. package/src/application/models/guards/api/isApiOrderResponseAttributes.ts +19 -17
  161. package/src/application/models/guards/api/isApiOrgConfigResults.ts +40 -48
  162. package/src/application/models/guards/api/isApiOrganizationConfig.ts +25 -38
  163. package/src/application/models/guards/api/isApiProductResponseAttributes.ts +12 -10
  164. package/src/application/models/guards/api/isApiResponse.ts +7 -5
  165. package/src/application/models/guards/graphQL/isGraphQLColorsConfig.ts +5 -3
  166. package/src/application/models/validators/validateGraphQLFrontendConfig.ts +15 -13
  167. package/src/application/utils/analyticsUtils.ts +4 -4
  168. package/src/application/utils/nextMessageRequestToApiRequest.ts +2 -0
  169. package/src/atoms/app/variant.ts +3 -1
  170. package/src/atoms/chat/performanceMetrics.ts +3 -1
  171. package/src/atoms/envive/enviveConfig.ts +5 -3
  172. package/src/contexts/amplitudeContext/__tests__/amplitudeContext.test.tsx +5 -4
  173. package/src/contexts/amplitudeContext/amplitudeContext.tsx +1 -5
  174. package/src/contexts/enviveConfigContext/__tests__/enviveConfigContext.test.tsx +4 -3
  175. package/src/contexts/enviveConfigContext/enviveConfigContext.tsx +50 -35
  176. package/src/contexts/enviveConfigContext/index.ts +1 -0
  177. package/src/contexts/enviveConfigContext/useEnviveConfig.ts +9 -0
  178. package/src/contexts/enviveContext/WindowChatToggleBinder.tsx +6 -4
  179. package/src/contexts/enviveContext/enviveContext.tsx +109 -50
  180. package/src/contexts/featureFlagServiceContext/featureFlagServiceContext.tsx +11 -12
  181. package/src/contexts/graphqlContext/__tests__/graphqlContext.test.tsx +4 -4
  182. package/src/contexts/graphqlContext/graphqlContext.tsx +8 -6
  183. package/src/contexts/hardcopyContext/hardcopyContext.tsx +9 -7
  184. package/src/contexts/localStorageContext/__tests__/localStorageContext.test.tsx +6 -6
  185. package/src/contexts/localStorageContext/localStorageContext.tsx +4 -2
  186. package/src/contexts/pageContext/__tests__/pageContext.test.tsx +5 -5
  187. package/src/contexts/pageContext/pageContext.tsx +22 -2
  188. package/src/contexts/salesAgentContext/chatAPI.ts +5 -5
  189. package/src/contexts/salesAgentContext/salesAgentContext.tsx +4 -2
  190. package/src/contexts/salesAgentContext/salesAgentService.ts +4 -2
  191. package/src/contexts/searchContext/__tests__/searchContext.test.tsx +15 -12
  192. package/src/contexts/searchContext/searchContext.tsx +6 -4
  193. package/src/contexts/sessionStorageContext/sessionStorageContext.tsx +3 -1
  194. package/src/contexts/uiConfigContext/__tests__/uiConfigContext.test.tsx +7 -32
  195. package/src/contexts/uiConfigContext/uiConfigContext.tsx +17 -29
  196. package/src/contexts/userIdentityContext/__tests__/userIdentityContext.test.tsx +5 -5
  197. package/src/contexts/userIdentityContext/userIdentityContext.tsx +7 -6
  198. package/src/contexts/widgetConfigContext/__tests__/widgetConfigContext.test.tsx +7 -7
  199. package/src/contexts/widgetConfigContext/widgetConfigContext.tsx +4 -2
  200. package/src/hooks/CustomerSupportHandoff/useCustomerSupportHandoff.ts +4 -2
  201. package/src/hooks/Search/__tests__/useSearch.test.tsx +14 -8
  202. package/src/hooks/WidgetInteraction/useWidgetInteraction.ts +3 -2
  203. package/src/hooks/WidgetInteraction/utils.ts +3 -1
  204. package/src/services/amplitudeService/__tests__/amplitudeService.test.ts +59 -9
  205. package/src/services/amplitudeService/amplitudeService.ts +27 -6
  206. package/src/services/ga4ProjectionService/ga4ProjectionService.ts +3 -1
  207. package/src/services/userIdentityService/userIdentityService.ts +8 -8
@@ -6,12 +6,15 @@ import { v4 as uuid } from 'uuid';
6
6
  import { InternalWidgetInteraction, WidgetInteraction } from './types';
7
7
  import { extractPageContext } from './utils';
8
8
 
9
+ const getInteractionId = () => uuid();
10
+
9
11
  export const useWidgetInteraction = () => {
10
12
  const { trackEvent } = useAmplitude();
11
13
  const variantInfo = useAtomValue(pageVariantInfoAtom);
12
14
 
13
15
  const trackWidgetInteraction = (props: WidgetInteraction) => {
14
16
  if (props.trigger) {
17
+ // eslint-disable-next-line no-param-reassign
15
18
  props.trigger.interaction_id = props.trigger.interaction_id || getInteractionId();
16
19
  }
17
20
 
@@ -26,8 +29,6 @@ export const useWidgetInteraction = () => {
26
29
  });
27
30
  };
28
31
 
29
- const getInteractionId = () => uuid();
30
-
31
32
  return {
32
33
  trackWidgetInteraction,
33
34
  getInteractionId,
@@ -3,9 +3,9 @@ import {
3
3
  FullPageSalesAgentVariantInfo,
4
4
  HomeVariantInfo,
5
5
  OtherVariantInfo,
6
- PageVariantInfo,
7
6
  PDPPageVariantInfo,
8
7
  PLPPageVariantInfo,
8
+ PageVariantInfo,
9
9
  } from '../../contexts/pageContext/types';
10
10
  import { WidgetInteractionContext, WidgetInteractionPageType } from './types';
11
11
 
@@ -38,6 +38,8 @@ export const extractPageContext = (
38
38
  page_id: (pageVariant as FullPageSalesAgentVariantInfo).url,
39
39
  page_type: WidgetInteractionPageType.FULL_PAGE,
40
40
  };
41
+ default:
42
+ return null;
41
43
  }
42
44
 
43
45
  return null;
@@ -85,10 +85,12 @@ describe('AmplitudeService', () => {
85
85
  });
86
86
  });
87
87
 
88
+ const validApiKey = 'abcdef1234567890abcdef1234567890';
89
+
88
90
  const createService = (overrides?: Partial<AmplitudeServiceConfig>) => {
89
91
  return new AmplitudeService({
90
92
  userId: 'test-user-id',
91
- amplitudeApiKey: 'test-api-key',
93
+ amplitudeApiKey: validApiKey,
92
94
  dataResidency: 'US',
93
95
  env: 'test',
94
96
  orgId: 'test-org-id',
@@ -107,7 +109,7 @@ describe('AmplitudeService', () => {
107
109
  createService();
108
110
 
109
111
  expect(mockInit).toHaveBeenCalledWith(
110
- 'test-api-key',
112
+ validApiKey,
111
113
  'test-user-id',
112
114
  expect.objectContaining({
113
115
  serverZone: 'US',
@@ -121,7 +123,7 @@ describe('AmplitudeService', () => {
121
123
  it('should not be ready if userId is missing', () => {
122
124
  const service = new AmplitudeService({
123
125
  userId: '',
124
- amplitudeApiKey: 'test-api-key',
126
+ amplitudeApiKey: validApiKey,
125
127
  dataResidency: 'US',
126
128
  env: 'test',
127
129
  orgId: 'test-org-id',
@@ -157,7 +159,7 @@ describe('AmplitudeService', () => {
157
159
  it('should not be ready if featureFlagService is missing', () => {
158
160
  const service = new AmplitudeService({
159
161
  userId: 'test-user-id',
160
- amplitudeApiKey: 'test-api-key',
162
+ amplitudeApiKey: validApiKey,
161
163
  dataResidency: 'US',
162
164
  env: 'test',
163
165
  orgId: 'test-org-id',
@@ -177,6 +179,54 @@ describe('AmplitudeService', () => {
177
179
 
178
180
  expect(service.isReady).toBe(true);
179
181
  });
182
+
183
+ it('should not set isMockMode when all required config is provided', () => {
184
+ const service = createService();
185
+
186
+ expect(service.isMockMode).toBe(false);
187
+ });
188
+ });
189
+
190
+ describe('Mock mode', () => {
191
+ it('should set isMockMode and not initialize the client when API key is not a valid hex string', () => {
192
+ const consoleSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
193
+
194
+ const service = createService({ amplitudeApiKey: 'not-a-valid-key' });
195
+
196
+ expect(service.isReady).toBe(false);
197
+ expect(service.isMockMode).toBe(true);
198
+ expect(mockInit).not.toHaveBeenCalled();
199
+
200
+ consoleSpy.mockRestore();
201
+ });
202
+
203
+ it('should print a console.log message when a mock API key is detected', () => {
204
+ const consoleSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
205
+
206
+ createService({ amplitudeApiKey: 'not-a-valid-key' });
207
+
208
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining('Mock API key detected'));
209
+
210
+ consoleSpy.mockRestore();
211
+ });
212
+
213
+ it('should not set isMockMode when API key is empty — service is simply not ready', () => {
214
+ const service = createService({ amplitudeApiKey: '' });
215
+
216
+ expect(service.isReady).toBe(false);
217
+ expect(service.isMockMode).toBe(false);
218
+ });
219
+
220
+ it('should not call the Amplitude client when trackEvent is called in mock mode', async () => {
221
+ const service = createService({ amplitudeApiKey: 'not-a-valid-key' });
222
+
223
+ await service.trackEvent({
224
+ eventName: SpiffyMetricsEventName.ChatUserMessageInput,
225
+ eventProps: { message: 'test' },
226
+ });
227
+
228
+ expect(mockTrack).not.toHaveBeenCalled();
229
+ });
180
230
  });
181
231
 
182
232
  describe('trackEvent', () => {
@@ -269,7 +319,7 @@ describe('AmplitudeService', () => {
269
319
  it('should not track if client is not initialized', async () => {
270
320
  const service = new AmplitudeService({
271
321
  userId: '',
272
- amplitudeApiKey: 'test-api-key',
322
+ amplitudeApiKey: validApiKey,
273
323
  dataResidency: 'US',
274
324
  env: 'test',
275
325
  orgId: 'test-org-id',
@@ -281,7 +331,7 @@ describe('AmplitudeService', () => {
281
331
  featureFlagService,
282
332
  });
283
333
 
284
- const logWarnSpy = vi.spyOn(Logger, 'logWarn');
334
+ const logWarnSpy = vi.spyOn(Logger.prototype, 'logWarn');
285
335
 
286
336
  await service.trackEvent({
287
337
  eventName: SpiffyMetricsEventName.ChatUserMessageInput,
@@ -304,7 +354,7 @@ describe('AmplitudeService', () => {
304
354
  throw error;
305
355
  });
306
356
 
307
- const logErrorSpy = vi.spyOn(Logger, 'logError');
357
+ const logErrorSpy = vi.spyOn(Logger.prototype, 'logError');
308
358
 
309
359
  await service.trackEvent({
310
360
  eventName: SpiffyMetricsEventName.ChatUserMessageInput,
@@ -312,7 +362,7 @@ describe('AmplitudeService', () => {
312
362
  });
313
363
 
314
364
  expect(logErrorSpy).toHaveBeenCalledWith(
315
- '[spiffy-ai] Error tracking event',
365
+ 'Error tracking event',
316
366
  error,
317
367
  expect.objectContaining({
318
368
  eventName: SpiffyMetricsEventName.ChatUserMessageInput,
@@ -419,7 +469,7 @@ describe('AmplitudeService', () => {
419
469
  it('should fall back to window.localStorage when getLocalStorageItem is not provided', async () => {
420
470
  const service = new AmplitudeService({
421
471
  userId: 'test-user-id',
422
- amplitudeApiKey: 'test-api-key',
472
+ amplitudeApiKey: validApiKey,
423
473
  dataResidency: 'US',
424
474
  env: 'test',
425
475
  orgId: 'test-org-id',
@@ -17,6 +17,8 @@ import { EnviveMetricsEventName, SpiffyMetricsEventName } from './eventNames';
17
17
  // Re-export event names for convenience
18
18
  export { EnviveMetricsEventName, SpiffyMetricsEventName };
19
19
 
20
+ const logger = new Logger('amplitudeService');
21
+
20
22
  export interface TrackEventParams {
21
23
  eventName: SpiffyMetricsEventName | EnviveMetricsEventName;
22
24
  eventProps?: Record<string, unknown>;
@@ -49,6 +51,8 @@ export class AmplitudeService {
49
51
 
50
52
  private config: AmplitudeServiceConfig;
51
53
 
54
+ private _isMockMode: boolean = false;
55
+
52
56
  constructor(config: AmplitudeServiceConfig) {
53
57
  this.config = config;
54
58
  this.initialize();
@@ -63,6 +67,10 @@ export class AmplitudeService {
63
67
  );
64
68
  }
65
69
 
70
+ get isMockMode(): boolean {
71
+ return this._isMockMode;
72
+ }
73
+
66
74
  private getLocalStorageItem(key: string): string | null {
67
75
  if (this.config.getLocalStorageItem) {
68
76
  return this.config.getLocalStorageItem(key);
@@ -211,13 +219,17 @@ export class AmplitudeService {
211
219
  return enrichment;
212
220
  }
213
221
 
222
+ private static isValidAmplitudeApiKey(apiKey: string): boolean {
223
+ return /^[0-9a-f]{32}$/i.test(apiKey);
224
+ }
225
+
214
226
  private initialize(): void {
215
227
  const isReady = Boolean(
216
228
  this.config.userId && this.config.featureFlagService && this.config.amplitudeApiKey,
217
229
  );
218
230
 
219
231
  if (!isReady) {
220
- Logger.logDebug('AmplitudeService is not ready', {
232
+ logger.logDebug('AmplitudeService is not ready', {
221
233
  isReady,
222
234
  userId: this.config.userId,
223
235
  hasFeatureFlagService: !!this.config.featureFlagService,
@@ -226,6 +238,15 @@ export class AmplitudeService {
226
238
  return;
227
239
  }
228
240
 
241
+ if (!AmplitudeService.isValidAmplitudeApiKey(this.config.amplitudeApiKey)) {
242
+ this._isMockMode = true;
243
+ // eslint-disable-next-line no-console
244
+ console.log(
245
+ '[AmplitudeService] Mock API key detected — running in mock mode, no events will be sent to Amplitude.',
246
+ );
247
+ return;
248
+ }
249
+
229
250
  if (!this.amplitudeClient) {
230
251
  const currentAmplitudeInstance: BrowserClient = createInstance();
231
252
 
@@ -351,12 +372,12 @@ export class AmplitudeService {
351
372
  eventGroups,
352
373
  alsoSendToGoogleAnalytics = false,
353
374
  }: TrackEventParams): Promise<void> {
354
- Logger.logDebug('Submitting event', eventName);
375
+ logger.logDebug('Submitting event', eventName);
355
376
  try {
356
377
  const decoratedEventName = AmplitudeService.decorateEventName(eventName);
357
378
 
358
379
  if (!this.amplitudeClient) {
359
- Logger.logWarn('amplitude client undefined', undefined, {
380
+ logger.logWarn('amplitude client undefined', undefined, {
360
381
  event_name: decoratedEventName,
361
382
  });
362
383
  return;
@@ -377,7 +398,7 @@ export class AmplitudeService {
377
398
  const hashArray = Array.from(new Uint8Array(hashBuffer));
378
399
  const currentInsertId = hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
379
400
 
380
- Logger.logDebug(`amplitude tracking ${decoratedEventName}`, null, {
401
+ logger.logDebug(`amplitude tracking ${decoratedEventName}`, null, {
381
402
  event_name: decoratedEventName,
382
403
  props: mappedEventProps,
383
404
  });
@@ -404,7 +425,7 @@ export class AmplitudeService {
404
425
  };
405
426
  projectToGA4(eventName as EnviveMetricsEventName, mergedPropsForGA4);
406
427
  } else if (alsoSendToGoogleAnalytics && this.config.orgGaConfig) {
407
- Logger.logDebug('[spiffy-ai] GA tracking', decoratedEventName);
428
+ logger.logDebug('GA tracking', decoratedEventName);
408
429
  if (typeof window !== 'undefined' && window.dataLayer) {
409
430
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
410
431
  (window.dataLayer as any[]).push({
@@ -414,7 +435,7 @@ export class AmplitudeService {
414
435
  }
415
436
  }
416
437
  } catch (err) {
417
- Logger.logError('[spiffy-ai] Error tracking event', err, {
438
+ logger.logError('Error tracking event', err, {
418
439
  eventName,
419
440
  eventProps,
420
441
  });
@@ -2,6 +2,8 @@ import Logger from 'src/application/logging/logger';
2
2
  import { EnviveMetricsEventName } from '../amplitudeService/eventNames';
3
3
  import { GA4ProjectedEventConfig, GA4_EVENT_SCHEMA } from './ga4EventSchema';
4
4
 
5
+ const logger = new Logger('ga4ProjectionService');
6
+
5
7
  const filterToSchema = (
6
8
  eventProps: Record<string, unknown>,
7
9
  allowedFields: readonly string[],
@@ -130,7 +132,7 @@ export const projectToGA4 = (
130
132
  ...truncatedParams,
131
133
  });
132
134
  } catch (err) {
133
- Logger.logError('[envive-ai] Error projecting event to GA4', err, {
135
+ logger.logError('Error projecting event to GA4', err, {
134
136
  eventName,
135
137
  });
136
138
  }
@@ -4,6 +4,8 @@ import { getAtomStore } from 'src/atoms/atomStore';
4
4
  import { userIdAtom } from 'src/atoms/app';
5
5
  import { ExecutionContext } from '@envive-ai/analytics/dist/analytics/EnviveAnalytics';
6
6
 
7
+ const logger = new Logger('userIdentityService');
8
+
7
9
  type UserIdentityServiceProps = {
8
10
  apiKey: string;
9
11
  };
@@ -18,7 +20,7 @@ export class UserIdentityService {
18
20
  }
19
21
 
20
22
  getUserIdOverrideFromLocalStorage(): string | undefined {
21
- Logger.logDebug('[spiffy-ai] Getting userID from localStorage');
23
+ logger.logDebug('Getting userID from localStorage');
22
24
  return localStorage.getItem(this.USER_ID_OVERRIDE_KEY) ?? undefined;
23
25
  }
24
26
 
@@ -29,7 +31,7 @@ export class UserIdentityService {
29
31
  }
30
32
 
31
33
  try {
32
- Logger.logDebug('Getting userID via EnviveAnalytics in UserIdentityService');
34
+ logger.logDebug('Getting userID via EnviveAnalytics in UserIdentityService');
33
35
  const enviveAnalytics = new EnviveAnalytics({
34
36
  apiKey: this.apiKey,
35
37
  environmentInfo: { executionContext: ExecutionContext.EnviveReactComponentsV3 },
@@ -37,16 +39,14 @@ export class UserIdentityService {
37
39
  const enviveUserId = await enviveAnalytics.resolveEnviveUserId();
38
40
 
39
41
  if (!enviveUserId) {
40
- throw new Error(
41
- '[spiffy-ai] EnviveAnalytics.resolveEnviveUserId() returned null/undefined',
42
- );
42
+ throw new Error('EnviveAnalytics.resolveEnviveUserId() returned null/undefined');
43
43
  }
44
44
 
45
45
  return enviveUserId;
46
46
  } catch (error: unknown) {
47
- Logger.logError('[spiffy-ai] CRITICAL: Failed to get user ID:', error);
47
+ logger.logError('CRITICAL: Failed to get user ID:', error);
48
48
  const errorMessage = error instanceof Error ? error.message : 'Unknown error';
49
- throw new Error(`[spiffy-ai] CRITICAL: User ID resolution failed: ${errorMessage}`);
49
+ throw new Error(`CRITICAL: User ID resolution failed: ${errorMessage}`);
50
50
  }
51
51
  }
52
52
 
@@ -57,7 +57,7 @@ export class UserIdentityService {
57
57
  const store = atomStore || getAtomStore();
58
58
  store.set(userIdAtom, userId);
59
59
  } catch (error) {
60
- Logger.logError('[spiffy-ai] CRITICAL: Failed to initialize user ID:', error);
60
+ logger.logError('CRITICAL: Failed to initialize user ID:', error);
61
61
  throw error;
62
62
  }
63
63
  }