@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.
- package/dist/application/commerce-api.cjs +14 -13
- package/dist/application/commerce-api.js +14 -13
- package/dist/application/logging/logger.cjs +16 -10
- package/dist/application/logging/logger.js +16 -10
- package/dist/application/models/guards/api/isApiFormResponse.cjs +9 -8
- package/dist/application/models/guards/api/isApiFormResponse.js +9 -8
- package/dist/application/models/guards/api/isApiFormSubmittedResponseAttributes.cjs +6 -5
- package/dist/application/models/guards/api/isApiFormSubmittedResponseAttributes.js +6 -5
- package/dist/application/models/guards/api/isApiOrderResponseAttributes.cjs +19 -18
- package/dist/application/models/guards/api/isApiOrderResponseAttributes.js +19 -18
- package/dist/application/models/guards/api/isApiOrgConfigResults.cjs +27 -26
- package/dist/application/models/guards/api/isApiOrgConfigResults.js +27 -26
- package/dist/application/models/guards/api/isApiOrganizationConfig.cjs +23 -22
- package/dist/application/models/guards/api/isApiOrganizationConfig.js +23 -22
- package/dist/application/models/guards/api/isApiProductResponseAttributes.cjs +12 -11
- package/dist/application/models/guards/api/isApiProductResponseAttributes.js +12 -11
- package/dist/application/models/guards/api/isApiResponse.cjs +7 -6
- package/dist/application/models/guards/api/isApiResponse.js +7 -6
- package/dist/application/models/guards/graphQL/isGraphQLColorsConfig.cjs +5 -4
- package/dist/application/models/guards/graphQL/isGraphQLColorsConfig.js +5 -4
- package/dist/application/models/validators/validateGraphQLFrontendConfig.cjs +15 -14
- package/dist/application/models/validators/validateGraphQLFrontendConfig.js +15 -14
- package/dist/application/utils/analyticsUtils.cjs +4 -3
- package/dist/application/utils/analyticsUtils.js +4 -3
- package/dist/application/utils/elementObserver.d.cts +2 -2
- package/dist/application/utils/elementObserver.d.ts +2 -2
- package/dist/application/utils/nextMessageRequestToApiRequest.cjs +3 -1
- package/dist/application/utils/nextMessageRequestToApiRequest.js +3 -1
- package/dist/atoms/app/index.d.ts +7 -7
- package/dist/atoms/app/variant.cjs +3 -2
- package/dist/atoms/app/variant.d.ts +6 -6
- package/dist/atoms/app/variant.js +3 -2
- package/dist/atoms/chat/chatState.d.cts +18 -18
- package/dist/atoms/chat/chatState.d.ts +18 -18
- package/dist/atoms/chat/form.d.ts +3 -3
- package/dist/atoms/chat/index.d.cts +2 -2
- package/dist/atoms/chat/index.d.ts +3 -3
- package/dist/atoms/chat/lastMessage.d.cts +2 -2
- package/dist/atoms/chat/lastMessage.d.ts +2 -2
- package/dist/atoms/chat/messageQueue.d.ts +7 -7
- package/dist/atoms/chat/performanceMetrics.cjs +3 -2
- package/dist/atoms/chat/performanceMetrics.d.cts +6 -6
- package/dist/atoms/chat/performanceMetrics.d.ts +6 -6
- package/dist/atoms/chat/performanceMetrics.js +3 -2
- package/dist/atoms/chat/renderedWidgetRefs.d.cts +2 -2
- package/dist/atoms/chat/renderedWidgetRefs.d.ts +2 -2
- package/dist/atoms/chat/replies.d.cts +2 -2
- package/dist/atoms/chat/replies.d.ts +3 -3
- package/dist/atoms/chat/suggestions.d.cts +2 -2
- package/dist/atoms/chat/suggestions.d.ts +3 -3
- package/dist/atoms/envive/enviveConfig.cjs +5 -4
- package/dist/atoms/envive/enviveConfig.d.cts +13 -13
- package/dist/atoms/envive/enviveConfig.d.ts +13 -13
- package/dist/atoms/envive/enviveConfig.js +5 -4
- package/dist/atoms/globalSearch/globalSearch.d.cts +5 -5
- package/dist/atoms/globalSearch/globalSearch.d.ts +5 -5
- package/dist/atoms/org/customerService.d.cts +6 -6
- package/dist/atoms/org/customerService.d.ts +6 -6
- package/dist/atoms/org/graphqlConfig.d.cts +4 -4
- package/dist/atoms/org/graphqlConfig.d.ts +4 -4
- package/dist/atoms/org/newOrgConfigAtom.d.cts +2 -2
- package/dist/atoms/org/newOrgConfigAtom.d.ts +2 -2
- package/dist/atoms/org/orgAnalyticsConfig.d.cts +5 -5
- package/dist/atoms/org/orgAnalyticsConfig.d.ts +5 -5
- package/dist/atoms/search/chatSearch.d.cts +17 -17
- package/dist/atoms/search/chatSearch.d.ts +17 -17
- package/dist/atoms/search/searchAPI.d.cts +13 -13
- package/dist/atoms/search/searchAPI.d.ts +13 -13
- package/dist/atoms/search/types.d.cts +1 -1
- package/dist/atoms/search/types.d.ts +1 -1
- package/dist/atoms/search/utils.d.ts +1 -1
- package/dist/atoms/widget/chatPreviewLoading.d.ts +2 -2
- package/dist/contexts/amplitudeContext/amplitudeContext.cjs +4 -4
- package/dist/contexts/amplitudeContext/amplitudeContext.js +3 -3
- package/dist/contexts/enviveConfigContext/enviveConfigContext.cjs +26 -15
- package/dist/contexts/enviveConfigContext/enviveConfigContext.d.cts +2 -4
- package/dist/contexts/enviveConfigContext/enviveConfigContext.d.ts +2 -4
- package/dist/contexts/enviveConfigContext/enviveConfigContext.js +29 -16
- package/dist/contexts/enviveConfigContext/index.cjs +2 -1
- package/dist/contexts/enviveConfigContext/index.d.cts +2 -1
- package/dist/contexts/enviveConfigContext/index.d.ts +2 -1
- package/dist/contexts/enviveConfigContext/index.js +2 -1
- package/dist/contexts/enviveConfigContext/useEnviveConfig.cjs +12 -0
- package/dist/contexts/enviveConfigContext/useEnviveConfig.d.cts +7 -0
- package/dist/contexts/enviveConfigContext/useEnviveConfig.d.ts +7 -0
- package/dist/contexts/enviveConfigContext/useEnviveConfig.js +11 -0
- package/dist/contexts/enviveContext/WindowChatToggleBinder.cjs +7 -5
- package/dist/contexts/enviveContext/WindowChatToggleBinder.js +6 -4
- package/dist/contexts/enviveContext/enviveContext.cjs +77 -48
- package/dist/contexts/enviveContext/enviveContext.d.cts +8 -2
- package/dist/contexts/enviveContext/enviveContext.d.ts +8 -2
- package/dist/contexts/enviveContext/enviveContext.js +78 -49
- package/dist/contexts/enviveContext/index.d.cts +2 -2
- package/dist/contexts/enviveContext/index.d.ts +2 -2
- package/dist/contexts/featureFlagServiceContext/featureFlagServiceContext.cjs +7 -6
- package/dist/contexts/featureFlagServiceContext/featureFlagServiceContext.js +7 -6
- package/dist/contexts/graphqlContext/graphqlContext.cjs +8 -7
- package/dist/contexts/graphqlContext/graphqlContext.js +8 -7
- package/dist/contexts/hardcopyContext/hardcopyContext.cjs +9 -8
- package/dist/contexts/hardcopyContext/hardcopyContext.js +9 -8
- package/dist/contexts/localStorageContext/localStorageContext.cjs +4 -3
- package/dist/contexts/localStorageContext/localStorageContext.js +4 -3
- package/dist/contexts/pageContext/pageContext.cjs +23 -4
- package/dist/contexts/pageContext/pageContext.d.cts +3 -1
- package/dist/contexts/pageContext/pageContext.d.ts +3 -1
- package/dist/contexts/pageContext/pageContext.js +24 -5
- package/dist/contexts/pageContext/types.d.ts +1 -1
- package/dist/contexts/salesAgentContext/chatAPI.cjs +3 -2
- package/dist/contexts/salesAgentContext/chatAPI.js +3 -2
- package/dist/contexts/salesAgentContext/salesAgentContext.cjs +4 -3
- package/dist/contexts/salesAgentContext/salesAgentContext.js +4 -3
- package/dist/contexts/salesAgentContext/salesAgentService.cjs +3 -2
- package/dist/contexts/salesAgentContext/salesAgentService.js +3 -2
- package/dist/contexts/searchContext/searchContext.cjs +8 -6
- package/dist/contexts/searchContext/searchContext.js +7 -5
- package/dist/contexts/sessionStorageContext/sessionStorageContext.cjs +3 -2
- package/dist/contexts/sessionStorageContext/sessionStorageContext.js +3 -2
- package/dist/contexts/systemSettingsContext/systemSettingsContext.d.cts +2 -2
- package/dist/contexts/systemSettingsContext/systemSettingsContext.d.ts +2 -2
- package/dist/contexts/types.d.cts +1 -1
- package/dist/contexts/types.d.ts +1 -1
- package/dist/contexts/typesV3.d.cts +1 -1
- package/dist/contexts/typesV3.d.ts +1 -1
- package/dist/contexts/uiConfigContext/index.cjs +0 -1
- package/dist/contexts/uiConfigContext/index.d.cts +2 -2
- package/dist/contexts/uiConfigContext/index.d.ts +2 -2
- package/dist/contexts/uiConfigContext/index.js +2 -2
- package/dist/contexts/uiConfigContext/uiConfigContext.cjs +13 -30
- package/dist/contexts/uiConfigContext/uiConfigContext.d.cts +5 -9
- package/dist/contexts/uiConfigContext/uiConfigContext.d.ts +5 -9
- package/dist/contexts/uiConfigContext/uiConfigContext.js +14 -29
- package/dist/contexts/userIdentityContext/userIdentityContext.cjs +7 -7
- package/dist/contexts/userIdentityContext/userIdentityContext.js +7 -7
- package/dist/contexts/widgetConfigContext/widgetConfigContext.cjs +4 -3
- package/dist/contexts/widgetConfigContext/widgetConfigContext.js +4 -3
- package/dist/hooks/CustomerSupportHandoff/useCustomerSupportHandoff.cjs +4 -3
- package/dist/hooks/CustomerSupportHandoff/useCustomerSupportHandoff.js +4 -3
- package/dist/hooks/GrabAndScroll/useGrabAndScroll.d.cts +2 -2
- package/dist/hooks/GrabAndScroll/useGrabAndScroll.d.ts +2 -2
- package/dist/hooks/WidgetInteraction/types.d.ts +1 -1
- package/dist/hooks/WidgetInteraction/useWidgetInteraction.cjs +2 -2
- package/dist/hooks/WidgetInteraction/useWidgetInteraction.js +2 -2
- package/dist/hooks/WidgetInteraction/utils.cjs +2 -1
- package/dist/hooks/WidgetInteraction/utils.d.ts +1 -1
- package/dist/hooks/WidgetInteraction/utils.js +2 -1
- package/dist/hooks/utils.d.ts +1 -1
- package/dist/services/amplitudeService/amplitudeService.cjs +20 -7
- package/dist/services/amplitudeService/amplitudeService.d.cts +4 -1
- package/dist/services/amplitudeService/amplitudeService.d.ts +4 -1
- package/dist/services/amplitudeService/amplitudeService.js +20 -7
- package/dist/services/ga4ProjectionService/ga4ProjectionService.cjs +3 -2
- package/dist/services/ga4ProjectionService/ga4ProjectionService.js +3 -2
- package/dist/services/userIdentityService/userIdentityService.cjs +8 -7
- package/dist/services/userIdentityService/userIdentityService.js +8 -7
- package/package.json +2 -2
- package/src/application/commerce-api.ts +14 -12
- package/src/application/logging/logger.ts +33 -8
- package/src/application/models/guards/api/isApiFormResponse.ts +9 -7
- package/src/application/models/guards/api/isApiFormSubmittedResponseAttributes.ts +6 -4
- package/src/application/models/guards/api/isApiOrderResponseAttributes.ts +19 -17
- package/src/application/models/guards/api/isApiOrgConfigResults.ts +40 -48
- package/src/application/models/guards/api/isApiOrganizationConfig.ts +25 -38
- package/src/application/models/guards/api/isApiProductResponseAttributes.ts +12 -10
- package/src/application/models/guards/api/isApiResponse.ts +7 -5
- package/src/application/models/guards/graphQL/isGraphQLColorsConfig.ts +5 -3
- package/src/application/models/validators/validateGraphQLFrontendConfig.ts +15 -13
- package/src/application/utils/analyticsUtils.ts +4 -4
- package/src/application/utils/nextMessageRequestToApiRequest.ts +2 -0
- package/src/atoms/app/variant.ts +3 -1
- package/src/atoms/chat/performanceMetrics.ts +3 -1
- package/src/atoms/envive/enviveConfig.ts +5 -3
- package/src/contexts/amplitudeContext/__tests__/amplitudeContext.test.tsx +5 -4
- package/src/contexts/amplitudeContext/amplitudeContext.tsx +1 -5
- package/src/contexts/enviveConfigContext/__tests__/enviveConfigContext.test.tsx +4 -3
- package/src/contexts/enviveConfigContext/enviveConfigContext.tsx +50 -35
- package/src/contexts/enviveConfigContext/index.ts +1 -0
- package/src/contexts/enviveConfigContext/useEnviveConfig.ts +9 -0
- package/src/contexts/enviveContext/WindowChatToggleBinder.tsx +6 -4
- package/src/contexts/enviveContext/enviveContext.tsx +109 -50
- package/src/contexts/featureFlagServiceContext/featureFlagServiceContext.tsx +11 -12
- package/src/contexts/graphqlContext/__tests__/graphqlContext.test.tsx +4 -4
- package/src/contexts/graphqlContext/graphqlContext.tsx +8 -6
- package/src/contexts/hardcopyContext/hardcopyContext.tsx +9 -7
- package/src/contexts/localStorageContext/__tests__/localStorageContext.test.tsx +6 -6
- package/src/contexts/localStorageContext/localStorageContext.tsx +4 -2
- package/src/contexts/pageContext/__tests__/pageContext.test.tsx +5 -5
- package/src/contexts/pageContext/pageContext.tsx +22 -2
- package/src/contexts/salesAgentContext/chatAPI.ts +5 -5
- package/src/contexts/salesAgentContext/salesAgentContext.tsx +4 -2
- package/src/contexts/salesAgentContext/salesAgentService.ts +4 -2
- package/src/contexts/searchContext/__tests__/searchContext.test.tsx +15 -12
- package/src/contexts/searchContext/searchContext.tsx +6 -4
- package/src/contexts/sessionStorageContext/sessionStorageContext.tsx +3 -1
- package/src/contexts/uiConfigContext/__tests__/uiConfigContext.test.tsx +7 -32
- package/src/contexts/uiConfigContext/uiConfigContext.tsx +17 -29
- package/src/contexts/userIdentityContext/__tests__/userIdentityContext.test.tsx +5 -5
- package/src/contexts/userIdentityContext/userIdentityContext.tsx +7 -6
- package/src/contexts/widgetConfigContext/__tests__/widgetConfigContext.test.tsx +7 -7
- package/src/contexts/widgetConfigContext/widgetConfigContext.tsx +4 -2
- package/src/hooks/CustomerSupportHandoff/useCustomerSupportHandoff.ts +4 -2
- package/src/hooks/Search/__tests__/useSearch.test.tsx +14 -8
- package/src/hooks/WidgetInteraction/useWidgetInteraction.ts +3 -2
- package/src/hooks/WidgetInteraction/utils.ts +3 -1
- package/src/services/amplitudeService/__tests__/amplitudeService.test.ts +59 -9
- package/src/services/amplitudeService/amplitudeService.ts +27 -6
- package/src/services/ga4ProjectionService/ga4ProjectionService.ts +3 -1
- 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:
|
|
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
|
-
|
|
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:
|
|
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:
|
|
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:
|
|
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
|
-
'
|
|
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:
|
|
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
|
-
|
|
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
|
-
|
|
375
|
+
logger.logDebug('Submitting event', eventName);
|
|
355
376
|
try {
|
|
356
377
|
const decoratedEventName = AmplitudeService.decorateEventName(eventName);
|
|
357
378
|
|
|
358
379
|
if (!this.amplitudeClient) {
|
|
359
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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(`
|
|
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
|
-
|
|
60
|
+
logger.logError('CRITICAL: Failed to initialize user ID:', error);
|
|
61
61
|
throw error;
|
|
62
62
|
}
|
|
63
63
|
}
|