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

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 (206) 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/nextMessageRequestToApiRequest.cjs +3 -1
  26. package/dist/application/utils/nextMessageRequestToApiRequest.js +3 -1
  27. package/dist/atoms/app/index.d.cts +1 -1
  28. package/dist/atoms/app/index.d.ts +7 -7
  29. package/dist/atoms/app/variant.cjs +3 -2
  30. package/dist/atoms/app/variant.d.cts +6 -6
  31. package/dist/atoms/app/variant.js +3 -2
  32. package/dist/atoms/chat/chatState.d.cts +18 -18
  33. package/dist/atoms/chat/chatState.d.ts +18 -18
  34. package/dist/atoms/chat/form.d.cts +3 -3
  35. package/dist/atoms/chat/form.d.ts +2 -2
  36. package/dist/atoms/chat/index.d.cts +3 -3
  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.cts +7 -7
  41. package/dist/atoms/chat/messageQueue.d.ts +6 -6
  42. package/dist/atoms/chat/performanceMetrics.cjs +3 -2
  43. package/dist/atoms/chat/performanceMetrics.d.cts +6 -6
  44. package/dist/atoms/chat/performanceMetrics.d.ts +6 -6
  45. package/dist/atoms/chat/performanceMetrics.js +3 -2
  46. package/dist/atoms/chat/renderedWidgetRefs.d.cts +3 -3
  47. package/dist/atoms/chat/renderedWidgetRefs.d.ts +2 -2
  48. package/dist/atoms/chat/replies.d.cts +3 -3
  49. package/dist/atoms/chat/replies.d.ts +3 -3
  50. package/dist/atoms/chat/suggestions.d.cts +3 -3
  51. package/dist/atoms/chat/suggestions.d.ts +2 -2
  52. package/dist/atoms/envive/enviveConfig.cjs +5 -4
  53. package/dist/atoms/envive/enviveConfig.d.cts +13 -13
  54. package/dist/atoms/envive/enviveConfig.d.ts +13 -13
  55. package/dist/atoms/envive/enviveConfig.js +5 -4
  56. package/dist/atoms/globalSearch/globalSearch.d.cts +5 -5
  57. package/dist/atoms/globalSearch/globalSearch.d.ts +5 -5
  58. package/dist/atoms/org/customerService.d.cts +6 -6
  59. package/dist/atoms/org/customerService.d.ts +6 -6
  60. package/dist/atoms/org/graphqlConfig.d.cts +4 -4
  61. package/dist/atoms/org/graphqlConfig.d.ts +4 -4
  62. package/dist/atoms/org/newOrgConfigAtom.d.cts +2 -2
  63. package/dist/atoms/org/newOrgConfigAtom.d.ts +2 -2
  64. package/dist/atoms/org/orgAnalyticsConfig.d.cts +5 -5
  65. package/dist/atoms/org/orgAnalyticsConfig.d.ts +5 -5
  66. package/dist/atoms/search/chatSearch.d.cts +17 -17
  67. package/dist/atoms/search/searchAPI.d.cts +13 -13
  68. package/dist/atoms/search/types.d.cts +1 -1
  69. package/dist/atoms/search/utils.d.cts +1 -1
  70. package/dist/atoms/widget/chatPreviewLoading.d.ts +2 -2
  71. package/dist/contexts/amplitudeContext/amplitudeContext.cjs +4 -3
  72. package/dist/contexts/amplitudeContext/amplitudeContext.js +3 -2
  73. package/dist/contexts/enviveConfigContext/enviveConfigContext.cjs +26 -15
  74. package/dist/contexts/enviveConfigContext/enviveConfigContext.d.cts +2 -4
  75. package/dist/contexts/enviveConfigContext/enviveConfigContext.d.ts +2 -4
  76. package/dist/contexts/enviveConfigContext/enviveConfigContext.js +29 -16
  77. package/dist/contexts/enviveConfigContext/index.cjs +2 -1
  78. package/dist/contexts/enviveConfigContext/index.d.cts +2 -1
  79. package/dist/contexts/enviveConfigContext/index.d.ts +2 -1
  80. package/dist/contexts/enviveConfigContext/index.js +2 -1
  81. package/dist/contexts/enviveConfigContext/useEnviveConfig.cjs +12 -0
  82. package/dist/contexts/enviveConfigContext/useEnviveConfig.d.cts +7 -0
  83. package/dist/contexts/enviveConfigContext/useEnviveConfig.d.ts +7 -0
  84. package/dist/contexts/enviveConfigContext/useEnviveConfig.js +11 -0
  85. package/dist/contexts/enviveContext/WindowChatToggleBinder.cjs +7 -5
  86. package/dist/contexts/enviveContext/WindowChatToggleBinder.js +6 -4
  87. package/dist/contexts/enviveContext/enviveContext.cjs +74 -45
  88. package/dist/contexts/enviveContext/enviveContext.d.cts +8 -2
  89. package/dist/contexts/enviveContext/enviveContext.d.ts +8 -2
  90. package/dist/contexts/enviveContext/enviveContext.js +75 -46
  91. package/dist/contexts/enviveContext/index.d.cts +2 -2
  92. package/dist/contexts/enviveContext/index.d.ts +2 -2
  93. package/dist/contexts/enviveContext/types.d.cts +1 -1
  94. package/dist/contexts/enviveContext/types.d.ts +1 -1
  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.ts +2 -2
  119. package/dist/contexts/types.d.cts +1 -1
  120. package/dist/contexts/types.d.ts +1 -1
  121. package/dist/contexts/typesV3.d.cts +1 -1
  122. package/dist/contexts/uiConfigContext/index.cjs +0 -1
  123. package/dist/contexts/uiConfigContext/index.d.cts +2 -2
  124. package/dist/contexts/uiConfigContext/index.d.ts +2 -2
  125. package/dist/contexts/uiConfigContext/index.js +2 -2
  126. package/dist/contexts/uiConfigContext/uiConfigContext.cjs +13 -30
  127. package/dist/contexts/uiConfigContext/uiConfigContext.d.cts +5 -9
  128. package/dist/contexts/uiConfigContext/uiConfigContext.d.ts +5 -9
  129. package/dist/contexts/uiConfigContext/uiConfigContext.js +14 -29
  130. package/dist/contexts/userIdentityContext/userIdentityContext.cjs +7 -7
  131. package/dist/contexts/userIdentityContext/userIdentityContext.js +7 -7
  132. package/dist/contexts/widgetConfigContext/widgetConfigContext.cjs +4 -3
  133. package/dist/contexts/widgetConfigContext/widgetConfigContext.js +4 -3
  134. package/dist/hooks/CustomerSupportHandoff/useCustomerSupportHandoff.cjs +4 -3
  135. package/dist/hooks/CustomerSupportHandoff/useCustomerSupportHandoff.js +4 -3
  136. package/dist/hooks/GrabAndScroll/useGrabAndScroll.d.cts +2 -2
  137. package/dist/hooks/GrabAndScroll/useGrabAndScroll.d.ts +2 -2
  138. package/dist/hooks/ShopifyUrlOperations/useShopifyUrlOperations.d.cts +2 -2
  139. package/dist/hooks/ShopifyUrlOperations/useShopifyUrlOperations.d.ts +2 -2
  140. package/dist/hooks/SystemSettingsContext/useSystemSettingsContext.d.ts +2 -2
  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.js +2 -1
  145. package/dist/hooks/utils.d.cts +1 -1
  146. package/dist/hooks/utils.d.ts +1 -1
  147. package/dist/services/amplitudeService/amplitudeService.cjs +15 -7
  148. package/dist/services/amplitudeService/amplitudeService.d.cts +2 -1
  149. package/dist/services/amplitudeService/amplitudeService.d.ts +2 -1
  150. package/dist/services/amplitudeService/amplitudeService.js +15 -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/amplitudeContext.tsx +1 -1
  173. package/src/contexts/enviveConfigContext/__tests__/enviveConfigContext.test.tsx +4 -3
  174. package/src/contexts/enviveConfigContext/enviveConfigContext.tsx +50 -35
  175. package/src/contexts/enviveConfigContext/index.ts +1 -0
  176. package/src/contexts/enviveConfigContext/useEnviveConfig.ts +9 -0
  177. package/src/contexts/enviveContext/WindowChatToggleBinder.tsx +6 -4
  178. package/src/contexts/enviveContext/enviveContext.tsx +109 -50
  179. package/src/contexts/featureFlagServiceContext/featureFlagServiceContext.tsx +11 -12
  180. package/src/contexts/graphqlContext/__tests__/graphqlContext.test.tsx +4 -4
  181. package/src/contexts/graphqlContext/graphqlContext.tsx +8 -6
  182. package/src/contexts/hardcopyContext/hardcopyContext.tsx +9 -7
  183. package/src/contexts/localStorageContext/__tests__/localStorageContext.test.tsx +6 -6
  184. package/src/contexts/localStorageContext/localStorageContext.tsx +4 -2
  185. package/src/contexts/pageContext/__tests__/pageContext.test.tsx +5 -5
  186. package/src/contexts/pageContext/pageContext.tsx +22 -2
  187. package/src/contexts/salesAgentContext/chatAPI.ts +5 -5
  188. package/src/contexts/salesAgentContext/salesAgentContext.tsx +4 -2
  189. package/src/contexts/salesAgentContext/salesAgentService.ts +4 -2
  190. package/src/contexts/searchContext/__tests__/searchContext.test.tsx +15 -12
  191. package/src/contexts/searchContext/searchContext.tsx +6 -4
  192. package/src/contexts/sessionStorageContext/sessionStorageContext.tsx +3 -1
  193. package/src/contexts/uiConfigContext/__tests__/uiConfigContext.test.tsx +7 -32
  194. package/src/contexts/uiConfigContext/uiConfigContext.tsx +17 -29
  195. package/src/contexts/userIdentityContext/__tests__/userIdentityContext.test.tsx +5 -5
  196. package/src/contexts/userIdentityContext/userIdentityContext.tsx +7 -6
  197. package/src/contexts/widgetConfigContext/__tests__/widgetConfigContext.test.tsx +7 -7
  198. package/src/contexts/widgetConfigContext/widgetConfigContext.tsx +4 -2
  199. package/src/hooks/CustomerSupportHandoff/useCustomerSupportHandoff.ts +4 -2
  200. package/src/hooks/Search/__tests__/useSearch.test.tsx +14 -8
  201. package/src/hooks/WidgetInteraction/useWidgetInteraction.ts +3 -2
  202. package/src/hooks/WidgetInteraction/utils.ts +3 -1
  203. package/src/services/amplitudeService/__tests__/amplitudeService.test.ts +3 -3
  204. package/src/services/amplitudeService/amplitudeService.ts +19 -6
  205. package/src/services/ga4ProjectionService/ga4ProjectionService.ts +3 -1
  206. package/src/services/userIdentityService/userIdentityService.ts +8 -8
@@ -1,11 +1,11 @@
1
- import React, { ReactNode, createContext, useEffect } from 'react';
2
- import { useAtomValue, useSetAtom } from 'jotai';
1
+ import React, { ReactNode, useEffect, useMemo } from 'react';
2
+ import { useSetAtom } from 'jotai';
3
3
  import { enviveConfigAtom } from 'src/atoms/envive/enviveConfig';
4
4
  import Logger from 'src/application/logging/logger';
5
5
  import { OrgConfigFeatureGate } from 'src/application/models/api/orgConfigResults';
6
6
  import { EnviveConfig } from '../types';
7
7
 
8
- const EnviveConfigContext = createContext<EnviveConfig | undefined>(undefined);
8
+ const logger = new Logger('enviveConfigContext');
9
9
 
10
10
  interface EnviveConfigProviderProps {
11
11
  children: ReactNode;
@@ -52,41 +52,56 @@ export const EnviveConfigProvider: React.FC<EnviveConfigProviderProps> = ({
52
52
  }) => {
53
53
  const setEnviveConfig = useSetAtom(enviveConfigAtom);
54
54
 
55
- const config: EnviveConfig = {
56
- amplitudeApiKey,
57
- dataResidency,
58
- env,
59
- baseUrl,
60
- reactAppName,
61
- cdnUrl,
62
- contextSource,
63
- orgLevelApiKey,
64
- orgShortName,
65
- orgId,
66
- identifyingPrefix,
67
- featureOverrides,
68
- variantUrlOverride,
69
- variantInfoOverride,
70
- show,
71
- enviveOn,
72
- publicKey,
73
- featureGates, // Add to config
74
- };
55
+ const config: EnviveConfig = useMemo(
56
+ () => ({
57
+ amplitudeApiKey,
58
+ dataResidency,
59
+ env,
60
+ baseUrl,
61
+ reactAppName,
62
+ cdnUrl,
63
+ contextSource,
64
+ orgLevelApiKey,
65
+ orgShortName,
66
+ orgId,
67
+ identifyingPrefix,
68
+ featureOverrides,
69
+ variantUrlOverride,
70
+ variantInfoOverride,
71
+ show,
72
+ enviveOn,
73
+ publicKey,
74
+ featureGates,
75
+ }),
76
+ [
77
+ amplitudeApiKey,
78
+ dataResidency,
79
+ env,
80
+ baseUrl,
81
+ reactAppName,
82
+ cdnUrl,
83
+ contextSource,
84
+ orgLevelApiKey,
85
+ orgShortName,
86
+ orgId,
87
+ identifyingPrefix,
88
+ featureOverrides,
89
+ variantUrlOverride,
90
+ variantInfoOverride,
91
+ show,
92
+ enviveOn,
93
+ publicKey,
94
+ featureGates,
95
+ ],
96
+ );
75
97
 
76
98
  useEffect(() => {
77
99
  setEnviveConfig(config);
78
- Logger.logDebug('EnviveConfigProvider: Setting EnviveConfig', config);
100
+ logger.logDebug('EnviveConfigProvider: Setting EnviveConfig', config);
79
101
  }, [setEnviveConfig, config]);
80
102
 
81
- return (
82
- <EnviveConfigContext.Provider value={config}>
83
- {config ? children : null}
84
- </EnviveConfigContext.Provider>
85
- );
86
- };
87
-
88
- export const useEnviveConfig = (): EnviveConfig => {
89
- const config = useAtomValue(enviveConfigAtom);
90
-
91
- return config || {};
103
+ if (!config) {
104
+ return null;
105
+ }
106
+ return children;
92
107
  };
@@ -1 +1,2 @@
1
1
  export * from './enviveConfigContext';
2
+ export * from './useEnviveConfig';
@@ -0,0 +1,9 @@
1
+ import { useAtomValue } from 'jotai';
2
+ import { enviveConfigAtom } from 'src/atoms/envive/enviveConfig';
3
+ import { EnviveConfig } from '../types';
4
+
5
+ export const useEnviveConfig = (): EnviveConfig => {
6
+ const config = useAtomValue(enviveConfigAtom);
7
+
8
+ return config || {};
9
+ };
@@ -1,10 +1,12 @@
1
1
  import { useEffect, useRef } from 'react';
2
2
  import { ChatElementDisplayLocationV3 } from 'src/application/models/chatElementDisplayLocationV3';
3
3
  import Logger from 'src/application/logging/logger';
4
- import { useEnviveConfig } from 'src/contexts/enviveConfigContext/enviveConfigContext';
4
+ import { useEnviveConfig } from 'src/contexts/enviveConfigContext';
5
5
  import { useSalesAgent } from 'src/contexts/salesAgentContext/salesAgentContext';
6
6
  import { useChatToggle } from 'src/hooks/ChatToggle';
7
7
 
8
+ const logger = new Logger('WindowChatToggleBinder');
9
+
8
10
  const attachedPrefixes = new Set<string>();
9
11
 
10
12
  export const WindowChatToggleBinder = () => {
@@ -58,11 +60,11 @@ export const WindowChatToggleBinder = () => {
58
60
  attachedPrefixes.add(spiffyAlias);
59
61
  }
60
62
 
61
- Logger.logDebug(
62
- `[envive-ai] Chat toggle attached at window["${identifyingPrefix}"] and window["${spiffyAlias}"]`,
63
+ logger.logDebug(
64
+ `Chat toggle attached at window["${identifyingPrefix}"] and window["${spiffyAlias}"]`,
63
65
  );
64
66
  } catch (e) {
65
- Logger.logError('[envive-ai] Failed to attach Chat toggle functions', e);
67
+ logger.logError('Failed to attach Chat toggle functions', e);
66
68
  }
67
69
  }, [identifyingPrefix]);
68
70
 
@@ -1,4 +1,4 @@
1
- import { ReactNode, createContext, useEffect, useMemo, useState } from 'react';
1
+ import { ReactNode, useCallback, useEffect, useMemo, useRef, useState } from 'react';
2
2
 
3
3
  import { OrgConfigFeatureGate } from 'src/application/models/api/orgConfigResults';
4
4
  import { EnviveConfigService, EnviveServiceConfig } from 'src/services/enviveConfigService';
@@ -21,16 +21,21 @@ import { HardcopyProvider, HardcopyResponse } from '../hardcopyContext';
21
21
  import { WidgetTypeV3 } from '../typesV3';
22
22
  import { WidgetConfigProvider } from '../widgetConfigContext';
23
23
  import { PageProvider } from '../pageContext';
24
- import { UiConfigProvider } from '../uiConfigContext';
25
24
  import { WindowChatToggleBinder } from './WindowChatToggleBinder';
26
25
 
27
- const EnviveContext = createContext<null>(null);
26
+ const logger = new Logger('enviveContext');
28
27
 
29
28
  interface AgentWrapperProps {
30
29
  children: ReactNode;
31
30
  enabledAgents: EnviveAgent[];
32
31
  }
33
32
 
33
+ export interface ExtensionStatusCallbacks {
34
+ onInjectionLoading?: () => Promise<unknown> | void;
35
+ onInjectionSuccess?: () => Promise<unknown> | void;
36
+ onInjectionError?: (error: Error) => Promise<unknown> | void;
37
+ }
38
+
34
39
  interface EnviveProviderProps extends AgentWrapperProps {
35
40
  amplitudeApiKey?: string;
36
41
  dataResidency?: string;
@@ -59,6 +64,7 @@ interface EnviveProviderProps extends AgentWrapperProps {
59
64
  overrideConfig?: GraphQlConfigValues;
60
65
  mockSalesAgentData?: any;
61
66
  hardcopyOverride?: Partial<Record<WidgetTypeV3, HardcopyResponse>>;
67
+ extensionService?: ExtensionStatusCallbacks;
62
68
  }
63
69
 
64
70
  const SearchAgentWrapper: React.FC<AgentWrapperProps> = ({ children, enabledAgents }) => {
@@ -109,9 +115,34 @@ export const EnviveProvider: React.FC<EnviveProviderProps> = ({
109
115
  requestV3Config = false,
110
116
  mockSalesAgentData,
111
117
  hardcopyOverride,
118
+ extensionService,
112
119
  ...config
113
120
  }) => {
114
121
  const [userId, setUserId] = useState<string>('');
122
+ const didReportSuccessRef = useRef(false);
123
+
124
+ const invokeExtensionCallback = useCallback((callback?: () => Promise<unknown> | void) => {
125
+ if (!callback) {
126
+ return;
127
+ }
128
+
129
+ Promise.resolve(callback()).catch(error => {
130
+ logger.logDebug('Extension status callback failed', error);
131
+ });
132
+ }, []);
133
+
134
+ const invokeExtensionErrorCallback = useCallback(
135
+ (error: Error) => {
136
+ if (!extensionService?.onInjectionError) {
137
+ return;
138
+ }
139
+
140
+ Promise.resolve(extensionService.onInjectionError(error)).catch(callbackError => {
141
+ logger.logDebug('Extension error callback failed', callbackError);
142
+ });
143
+ },
144
+ [extensionService],
145
+ );
115
146
 
116
147
  const userIdService = useMemo(
117
148
  () =>
@@ -134,6 +165,8 @@ export const EnviveProvider: React.FC<EnviveProviderProps> = ({
134
165
  const [enviveServiceConfig, setEnviveServiceConfig] = useState<EnviveServiceConfig | null>(null);
135
166
 
136
167
  useEffect(() => {
168
+ invokeExtensionCallback(extensionService?.onInjectionLoading);
169
+
137
170
  // Really not happy with this approach, but I'm seeing 429 errors in the tests
138
171
  // because of the rate limiting on the API.
139
172
  const enviveConfigService =
@@ -145,11 +178,38 @@ export const EnviveProvider: React.FC<EnviveProviderProps> = ({
145
178
  namespace: namespace || '',
146
179
  source: source || '',
147
180
  });
148
- enviveConfigService.getEnviveConfig().then(newConfig => {
149
- setEnviveServiceConfig(newConfig);
150
- return newConfig;
151
- });
152
- }, [config, userId, namespace, source, inputEnviveConfigService]);
181
+ const fetchEnviveConfig = async () => {
182
+ try {
183
+ const newConfig = await enviveConfigService.getEnviveConfig();
184
+ setEnviveServiceConfig(newConfig);
185
+ } catch (error) {
186
+ const resolvedError =
187
+ error instanceof Error ? error : new Error('Failed to load envive config');
188
+ logger.logError('Failed to initialize EnviveProvider', resolvedError);
189
+ invokeExtensionErrorCallback(resolvedError);
190
+ }
191
+ };
192
+
193
+ fetchEnviveConfig();
194
+ }, [
195
+ config,
196
+ userId,
197
+ namespace,
198
+ source,
199
+ inputEnviveConfigService,
200
+ extensionService,
201
+ invokeExtensionCallback,
202
+ invokeExtensionErrorCallback,
203
+ ]);
204
+
205
+ useEffect(() => {
206
+ if (!enviveServiceConfig || didReportSuccessRef.current) {
207
+ return;
208
+ }
209
+
210
+ didReportSuccessRef.current = true;
211
+ invokeExtensionCallback(extensionService?.onInjectionSuccess);
212
+ }, [enviveServiceConfig, extensionService, invokeExtensionCallback]);
153
213
 
154
214
  const enviveConfig = useMemo(
155
215
  () => ({
@@ -160,8 +220,8 @@ export const EnviveProvider: React.FC<EnviveProviderProps> = ({
160
220
  }),
161
221
  [config, enviveServiceConfig],
162
222
  );
163
- Logger.logDebug('enviveContext: enviveServiceConfig', enviveServiceConfig, config);
164
- Logger.logDebug('enviveContext: enviveConfig', enviveConfig);
223
+ logger.logDebug('enviveContext: enviveServiceConfig', enviveServiceConfig, config);
224
+ logger.logDebug('enviveContext: enviveConfig', enviveConfig);
165
225
 
166
226
  const featureFlagService = useMemo(
167
227
  () => inputFeatureFlagService ?? new FeatureFlagService(enviveConfig.featureGates),
@@ -173,45 +233,44 @@ export const EnviveProvider: React.FC<EnviveProviderProps> = ({
173
233
  }
174
234
 
175
235
  return (
176
- <EnviveContext.Provider value={null}>
177
- <EnviveConfigProvider {...enviveConfig}>
178
- <GraphQLProvider
179
- mockV3ConfigToDeprecatedConfig={mockV3ConfigToDeprecatedConfig}
180
- requestV3Config={requestV3Config}
181
- >
182
- <NewOrgConfigProvider overrideConfig={overrideConfig}>
183
- <LocalStorageProvider>
184
- <FeatureFlagServiceProvider featureFlagService={featureFlagService}>
185
- <UserIdentityProvider userIdService={userIdService}>
186
- <AmplitudeProvider externalAmplitudeService={inputAmplitudeService}>
187
- <PageProvider previewMode={previewMode}>
188
- <UiConfigProvider>
189
- <WidgetConfigProvider>
190
- <HardcopyProvider hardcopyOverride={hardcopyOverride}>
191
- <EnviveCssProvider>
192
- <SearchAgentWrapper enabledAgents={enabledAgents}>
193
- <WindowChatToggleBinder />
194
- <SalesAgentWrapper
195
- enabledAgents={enabledAgents}
196
- showDebugBar={config.enviveOn || false}
197
- previewMode={previewMode}
198
- mockSalesAgentData={mockSalesAgentData}
199
- >
200
- {children}
201
- </SalesAgentWrapper>
202
- </SearchAgentWrapper>
203
- </EnviveCssProvider>
204
- </HardcopyProvider>
205
- </WidgetConfigProvider>
206
- </UiConfigProvider>
207
- </PageProvider>
208
- </AmplitudeProvider>
209
- </UserIdentityProvider>
210
- </FeatureFlagServiceProvider>
211
- </LocalStorageProvider>
212
- </NewOrgConfigProvider>
213
- </GraphQLProvider>
214
- </EnviveConfigProvider>
215
- </EnviveContext.Provider>
236
+ <EnviveConfigProvider {...enviveConfig}>
237
+ <GraphQLProvider
238
+ mockV3ConfigToDeprecatedConfig={mockV3ConfigToDeprecatedConfig}
239
+ requestV3Config={requestV3Config}
240
+ >
241
+ <NewOrgConfigProvider overrideConfig={overrideConfig}>
242
+ <LocalStorageProvider>
243
+ <FeatureFlagServiceProvider featureFlagService={featureFlagService}>
244
+ <UserIdentityProvider userIdService={userIdService}>
245
+ <AmplitudeProvider externalAmplitudeService={inputAmplitudeService}>
246
+ <PageProvider
247
+ previewMode={previewMode}
248
+ onUrlResolverNotReady={extensionService?.onInjectionError}
249
+ >
250
+ <WidgetConfigProvider>
251
+ <HardcopyProvider hardcopyOverride={hardcopyOverride}>
252
+ <EnviveCssProvider>
253
+ <SearchAgentWrapper enabledAgents={enabledAgents}>
254
+ <WindowChatToggleBinder />
255
+ <SalesAgentWrapper
256
+ enabledAgents={enabledAgents}
257
+ showDebugBar={config.enviveOn || false}
258
+ previewMode={previewMode}
259
+ mockSalesAgentData={mockSalesAgentData}
260
+ >
261
+ {children}
262
+ </SalesAgentWrapper>
263
+ </SearchAgentWrapper>
264
+ </EnviveCssProvider>
265
+ </HardcopyProvider>
266
+ </WidgetConfigProvider>
267
+ </PageProvider>
268
+ </AmplitudeProvider>
269
+ </UserIdentityProvider>
270
+ </FeatureFlagServiceProvider>
271
+ </LocalStorageProvider>
272
+ </NewOrgConfigProvider>
273
+ </GraphQLProvider>
274
+ </EnviveConfigProvider>
216
275
  );
217
276
  };
@@ -5,6 +5,8 @@ import Logger from 'src/application/logging/logger';
5
5
 
6
6
  const FEATURE_FLAGS_STORAGE_KEY = 'spiffy-feature-flags';
7
7
 
8
+ const logger = new Logger('featureFlagServiceContext');
9
+
8
10
  export interface FullFlagValue {
9
11
  resolved: boolean;
10
12
  initial: boolean | undefined;
@@ -66,10 +68,7 @@ export class FeatureFlagService {
66
68
  const featureFlagsObj = JSON.parse(featureFlags) as Record<string, boolean>;
67
69
  return featureFlagsObj[featureGate];
68
70
  } catch (err) {
69
- Logger.logError(
70
- '[spiffy-ai] getStoredFeatureGateOverrides: error parsing feature flags',
71
- err,
72
- );
71
+ logger.logError('getStoredFeatureGateOverrides: error parsing feature flags', err);
73
72
  return undefined;
74
73
  }
75
74
  }
@@ -77,24 +76,24 @@ export class FeatureFlagService {
77
76
  static getFeatureFlagOverride(featureGate: FeatureGates): boolean | undefined {
78
77
  const queryOverride = FeatureFlagService.getQueryParamFeatureGateOverrides(featureGate);
79
78
  if (queryOverride != null) {
80
- Logger.logDebug(
81
- `[spiffy-ai] isFeatureGateEnabled featureGate:${featureGate} overridden by URL param. New value: ${queryOverride}`,
79
+ logger.logDebug(
80
+ `isFeatureGateEnabled featureGate:${featureGate} overridden by URL param. New value: ${queryOverride}`,
82
81
  );
83
82
  return queryOverride;
84
83
  }
85
84
 
86
85
  const windowOverride = FeatureFlagService.getWindowFeatureGateOverrides(featureGate);
87
86
  if (windowOverride != null) {
88
- Logger.logDebug(
89
- `[spiffy-ai] isFeatureGateEnabled featureGate:${featureGate} overridden by window param. New value: ${windowOverride}`,
87
+ logger.logDebug(
88
+ `isFeatureGateEnabled featureGate:${featureGate} overridden by window param. New value: ${windowOverride}`,
90
89
  );
91
90
  return windowOverride;
92
91
  }
93
92
 
94
93
  const storedOverride = FeatureFlagService.getStoredFeatureGateOverrides(featureGate);
95
94
  if (storedOverride != null) {
96
- Logger.logDebug(
97
- `[spiffy-ai] isFeatureGateEnabled featureGate:${featureGate} overridden by stored value. New value: ${storedOverride}`,
95
+ logger.logDebug(
96
+ `isFeatureGateEnabled featureGate:${featureGate} overridden by stored value. New value: ${storedOverride}`,
98
97
  );
99
98
  return storedOverride;
100
99
  }
@@ -111,8 +110,8 @@ export class FeatureFlagService {
111
110
  }
112
111
 
113
112
  if (gateValue == null || gateValue.value == null) {
114
- Logger.logDebug(
115
- `[spiffy-ai] isFeatureGateEnabled featureGate:${featureGate} value is undefined - returning false`,
113
+ logger.logDebug(
114
+ `isFeatureGateEnabled featureGate:${featureGate} value is undefined - returning false`,
116
115
  );
117
116
  return false;
118
117
  }
@@ -8,9 +8,9 @@ import { getMerchantOrgIdQuery } from 'src/application/models/graphql/queries/ge
8
8
  import { GraphQLProvider, useGraphQLClient } from '../graphqlContext';
9
9
 
10
10
  // Mock the Logger to avoid console output in tests
11
- vi.spyOn(Logger, 'logDebug').mockImplementation(() => {});
12
- vi.spyOn(Logger, 'logWarn').mockImplementation(() => {});
13
- vi.spyOn(Logger, 'logError').mockImplementation(() => {});
11
+ vi.spyOn(Logger.prototype, 'logDebug').mockImplementation(() => {});
12
+ vi.spyOn(Logger.prototype, 'logWarn').mockImplementation(() => {});
13
+ vi.spyOn(Logger.prototype, 'logError').mockImplementation(() => {});
14
14
 
15
15
  // Mock fetch globally
16
16
  global.fetch = vi.fn();
@@ -625,7 +625,7 @@ describe('GraphQLProvider', () => {
625
625
  });
626
626
 
627
627
  it('should handle errors and return undefined configs', async () => {
628
- const logErrorSpy = vi.spyOn(Logger, 'logError');
628
+ const logErrorSpy = vi.spyOn(Logger.prototype, 'logError');
629
629
 
630
630
  (global.fetch as any).mockRejectedValueOnce(new Error('Network error'));
631
631
 
@@ -47,6 +47,8 @@ interface GraphQLContextValue {
47
47
 
48
48
  const GraphQLContext = createContext<GraphQLContextValue | null>(null);
49
49
 
50
+ const logger = new Logger('graphqlContext');
51
+
50
52
  type GraphQLProviderProps = {
51
53
  children: ReactNode;
52
54
  requestV3Config?: boolean;
@@ -254,7 +256,7 @@ export const GraphQLProvider = ({
254
256
 
255
257
  // If the v3 root config is not found and we are configured to return the deprecated config, we will return the mocked config
256
258
  if ((!v3RootConfig && mockV3ConfigToDeprecatedConfig) || (isStorybook && isSemanticColors)) {
257
- Logger.logInfo('GraphQLContext | Returning mock v3 config', {
259
+ logger.logDebug('GraphQLContext | Returning mock v3 config', {
258
260
  colorsConfig: mockV3ColorsConfig as ColorsConfigV3Response,
259
261
  frontendConfig: mockV3FrontendConfig as FrontendConfigV3Response,
260
262
  });
@@ -273,7 +275,7 @@ export const GraphQLProvider = ({
273
275
  };
274
276
  }
275
277
 
276
- Logger.logInfo('GraphQLContext | Returning v3 config', {
278
+ logger.logDebug('GraphQLContext | Returning v3 config', {
277
279
  colorsConfig: v3ColorsConfig as ColorsConfigV3Response,
278
280
  frontendConfig: v3FrontendConfig as FrontendConfigV3Response,
279
281
  orgPageConfig: {
@@ -299,7 +301,7 @@ export const GraphQLProvider = ({
299
301
  // TODO: Add widgets and other config here
300
302
  };
301
303
  } catch (err) {
302
- Logger.logError('Error fetching graphql colors and frontend config', err);
304
+ logger.logError('Error fetching graphql colors and frontend config', err);
303
305
  return { colorsConfig: undefined, frontendConfig: undefined };
304
306
  }
305
307
  }, [executeQuery, mockV3ConfigToDeprecatedConfig]);
@@ -340,17 +342,17 @@ export const GraphQLProvider = ({
340
342
  frontendConfig: frontendConfig as FrontendConfigV3Response,
341
343
  };
342
344
  } catch (err) {
343
- Logger.logError('Error fetching graphql colors and frontend config', err);
345
+ logger.logError('Error fetching graphql colors and frontend config', err);
344
346
  return { colorsConfig: undefined, frontendConfig: undefined };
345
347
  }
346
348
  }, [executeQuery]);
347
349
 
348
350
  const getConfig = useCallback(async (): Promise<GraphQlConfigValues> => {
349
351
  if (requestV3Config) {
350
- Logger.logInfo('GraphQLContext | Getting v3 config', requestV3Config);
352
+ logger.logDebug('GraphQLContext | Getting v3 config', requestV3Config);
351
353
  return getV3Config();
352
354
  }
353
- Logger.logInfo('GraphQLContext | Getting colors and frontend config', requestV3Config);
355
+ logger.logDebug('GraphQLContext | Getting colors and frontend config', requestV3Config);
354
356
  return getColorsAndFrontendConfig();
355
357
  }, [getColorsAndFrontendConfig, getV3Config, requestV3Config]);
356
358
 
@@ -15,6 +15,8 @@ import { WidgetTypeV3 } from '../typesV3';
15
15
  import { useFeatureFlagService } from '../featureFlagServiceContext/featureFlagServiceContext';
16
16
  import { useAmplitude } from '../amplitudeContext';
17
17
 
18
+ const logger = new Logger('hardcopyContext');
19
+
18
20
  interface HardcopyRequest {
19
21
  widgetType: WidgetTypeV3;
20
22
  userEvent: UserEvent;
@@ -218,7 +220,7 @@ export const HardcopyProvider: React.FC<HardcopyProviderProps> = ({
218
220
  const getHardcopyFromBackend = useCallback(
219
221
  async (request: HardcopyRequest): Promise<HardcopyResponse> => {
220
222
  if (hardcopyOverride?.[request.widgetType]) {
221
- Logger.logInfo('hardcopyContext | using hardcopy override', request.widgetType);
223
+ logger.logDebug('using hardcopy override', request.widgetType);
222
224
  return hardcopyOverride[request.widgetType]!;
223
225
  }
224
226
  const overrideConfigVersion =
@@ -245,7 +247,7 @@ export const HardcopyProvider: React.FC<HardcopyProviderProps> = ({
245
247
  const response = await CommerceApiClient.getHardcopy(widgetTextRequest);
246
248
  if (response) {
247
249
  const convertedResponse = convertToHardcopyResponse(response);
248
- Logger.logInfo('hardcopyContext | converted response', convertedResponse);
250
+ logger.logDebug('converted response', convertedResponse);
249
251
  trackEvent({
250
252
  eventName: EnviveMetricsEventName.WidgetTextResponse,
251
253
  eventProps: {
@@ -258,11 +260,11 @@ export const HardcopyProvider: React.FC<HardcopyProviderProps> = ({
258
260
  return convertedResponse;
259
261
  }
260
262
  } catch (error) {
261
- Logger.logError('hardcopyContext | error getting hardcopy from backend', error);
263
+ logger.logError('error getting hardcopy from backend', error);
262
264
  }
263
265
  const mockResponse = MOCK_HARDCOPY_RESPONSE[request.widgetType];
264
266
  if (mockResponse) {
265
- Logger.logInfo('hardcopyContext | no real response, using mock', mockResponse);
267
+ logger.logDebug('no real response, using mock', mockResponse);
266
268
  return mockResponse;
267
269
  }
268
270
  throw new Error(`No hardcopy response found for widget type: ${request.widgetType}`);
@@ -273,11 +275,11 @@ export const HardcopyProvider: React.FC<HardcopyProviderProps> = ({
273
275
  const getHardcopy = useCallback(
274
276
  async (request: HardcopyRequest): Promise<HardcopyResponse> => {
275
277
  setIsLoading(true);
276
- Logger.logInfo('hardcopyContext | retrieving hardcopy', languages);
278
+ logger.logDebug('retrieving hardcopy', languages);
277
279
 
278
- Logger.logInfo('hardcopyContext | request', request);
280
+ logger.logDebug('request', request);
279
281
  const response = await getHardcopyFromBackend(request);
280
- Logger.logInfo('hardcopyContext | returning hardcopy response', response);
282
+ logger.logDebug('returning hardcopy response', response);
281
283
  if (!response) {
282
284
  setIsLoading(false);
283
285
  throw new Error(`No hardcopy response found for widget type: ${request.widgetType}`);
@@ -5,9 +5,9 @@ import { LocalStorageEventListener } from 'src/application/models/localStorageEv
5
5
  import { LocalStorageKeys, LocalStorageProvider, useLocalStorage } from '../localStorageContext';
6
6
 
7
7
  // Mock the Logger to avoid console output in tests
8
- vi.spyOn(Logger, 'logDebug').mockImplementation(() => {});
9
- vi.spyOn(Logger, 'logWarn').mockImplementation(() => {});
10
- vi.spyOn(Logger, 'logError').mockImplementation(() => {});
8
+ vi.spyOn(Logger.prototype, 'logDebug').mockImplementation(() => {});
9
+ vi.spyOn(Logger.prototype, 'logWarn').mockImplementation(() => {});
10
+ vi.spyOn(Logger.prototype, 'logError').mockImplementation(() => {});
11
11
 
12
12
  // Component that uses the useLocalStorage hook
13
13
  const MockLocalStorageComponent: React.FC = () => {
@@ -184,7 +184,7 @@ describe('LocalStorageProvider', () => {
184
184
  });
185
185
 
186
186
  it('should log error when localStorage is not available', async () => {
187
- const logErrorSpy = vi.spyOn(Logger, 'logError');
187
+ const logErrorSpy = vi.spyOn(Logger.prototype, 'logError');
188
188
  const originalLocalStorage = window.localStorage;
189
189
  Object.defineProperty(window, 'localStorage', {
190
190
  value: undefined,
@@ -558,7 +558,7 @@ describe('LocalStorageProvider', () => {
558
558
  });
559
559
 
560
560
  it('should log debug message when storage event is received', async () => {
561
- const logDebugSpy = vi.spyOn(Logger, 'logDebug');
561
+ const logDebugSpy = vi.spyOn(Logger.prototype, 'logDebug');
562
562
 
563
563
  const TestComponent: React.FC = () => {
564
564
  const { attachListener, setItem, detachListener } = useLocalStorage();
@@ -602,7 +602,7 @@ describe('LocalStorageProvider', () => {
602
602
  await waitFor(
603
603
  () => {
604
604
  expect(logDebugSpy).toHaveBeenCalledWith(
605
- '[spiffy-ai] Storage event key=test-key, value=',
605
+ 'Storage event key=test-key, value=',
606
606
  'test-value',
607
607
  );
608
608
  },
@@ -20,6 +20,8 @@ interface LocalStorageContextType {
20
20
 
21
21
  const LocalStorageContext = createContext<LocalStorageContextType | null>(null);
22
22
 
23
+ const logger = new Logger('localStorageContext');
24
+
23
25
  export const LocalStorageProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
24
26
  const isAvailable = useMemo(() => {
25
27
  try {
@@ -31,7 +33,7 @@ export const LocalStorageProvider: React.FC<{ children: React.ReactNode }> = ({
31
33
 
32
34
  useEffect(() => {
33
35
  if (!isAvailable) {
34
- Logger.logError('localStorage is not available', undefined);
36
+ logger.logError('localStorage is not available', undefined);
35
37
  }
36
38
  }, [isAvailable]);
37
39
 
@@ -78,7 +80,7 @@ export const LocalStorageProvider: React.FC<{ children: React.ReactNode }> = ({
78
80
  if (event.key !== listener.storageKey) {
79
81
  return;
80
82
  }
81
- Logger.logDebug(`[spiffy-ai] Storage event key=${event.key}, value=`, event.newValue);
83
+ logger.logDebug(`Storage event key=${event.key}, value=`, event.newValue);
82
84
  listener.listener(event);
83
85
  };
84
86
  listenersCache.set(listener.storageKey, handler);