@envive-ai/react-hooks 0.3.58 → 0.3.59

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 (105) hide show
  1. package/dist/application/commerce-api.cjs +1 -1
  2. package/dist/application/commerce-api.js +1 -1
  3. package/dist/application/models/graphql/index.cjs +0 -4
  4. package/dist/application/models/graphql/index.d.cts +2 -3
  5. package/dist/application/models/graphql/index.d.ts +2 -3
  6. package/dist/application/models/graphql/index.js +1 -3
  7. package/dist/application/models/graphql/queries/getMerchantColorsQuery.d.cts +2 -3
  8. package/dist/application/models/graphql/queries/getMerchantColorsQuery.d.ts +2 -3
  9. package/dist/application/models/graphql/queries/getWidgetConfigQuery.cjs +22 -3
  10. package/dist/application/models/graphql/queries/getWidgetConfigQuery.js +22 -3
  11. package/dist/application/models/index.cjs +0 -4
  12. package/dist/application/models/index.d.cts +2 -3
  13. package/dist/application/models/index.d.ts +2 -3
  14. package/dist/application/models/index.js +1 -3
  15. package/dist/application/utils/elementObserver.d.cts +2 -2
  16. package/dist/application/utils/index.cjs +1 -1
  17. package/dist/application/utils/index.js +1 -1
  18. package/dist/atoms/app/index.d.cts +7 -7
  19. package/dist/atoms/app/index.d.ts +7 -7
  20. package/dist/atoms/chat/chatState.d.cts +18 -18
  21. package/dist/atoms/chat/chatState.d.ts +19 -19
  22. package/dist/atoms/chat/form.d.cts +2 -2
  23. package/dist/atoms/chat/form.d.ts +2 -2
  24. package/dist/atoms/chat/index.d.cts +2 -2
  25. package/dist/atoms/chat/index.d.ts +2 -2
  26. package/dist/atoms/chat/lastMessage.d.cts +2 -2
  27. package/dist/atoms/chat/lastMessage.d.ts +2 -2
  28. package/dist/atoms/chat/messageQueue.d.cts +6 -6
  29. package/dist/atoms/chat/messageQueue.d.ts +6 -6
  30. package/dist/atoms/chat/performanceMetrics.d.cts +6 -6
  31. package/dist/atoms/chat/performanceMetrics.d.ts +6 -6
  32. package/dist/atoms/chat/renderedWidgetRefs.d.cts +2 -2
  33. package/dist/atoms/chat/renderedWidgetRefs.d.ts +2 -2
  34. package/dist/atoms/chat/replies.d.cts +3 -3
  35. package/dist/atoms/chat/replies.d.ts +2 -2
  36. package/dist/atoms/chat/suggestions.d.cts +2 -2
  37. package/dist/atoms/chat/suggestions.d.ts +2 -2
  38. package/dist/atoms/envive/enviveConfig.d.ts +14 -14
  39. package/dist/atoms/globalSearch/globalSearch.d.cts +5 -5
  40. package/dist/atoms/globalSearch/globalSearch.d.ts +5 -5
  41. package/dist/atoms/org/customerService.d.cts +6 -6
  42. package/dist/atoms/org/customerService.d.ts +6 -6
  43. package/dist/atoms/org/graphqlConfig.d.cts +4 -4
  44. package/dist/atoms/org/graphqlConfig.d.ts +4 -4
  45. package/dist/atoms/org/newOrgConfigAtom.d.cts +2 -2
  46. package/dist/atoms/org/newOrgConfigAtom.d.ts +2 -2
  47. package/dist/atoms/org/orgAnalyticsConfig.d.cts +4 -4
  48. package/dist/atoms/org/orgAnalyticsConfig.d.ts +4 -4
  49. package/dist/atoms/search/chatSearch.d.cts +17 -17
  50. package/dist/atoms/search/chatSearch.d.ts +17 -17
  51. package/dist/atoms/search/searchAPI.d.cts +13 -13
  52. package/dist/atoms/search/searchAPI.d.ts +13 -13
  53. package/dist/atoms/search/types.d.cts +1 -1
  54. package/dist/atoms/widget/chatPreviewLoading.d.cts +2 -2
  55. package/dist/atoms/widget/chatPreviewLoading.d.ts +2 -2
  56. package/dist/contexts/pageContext/pageContext.cjs +1 -1
  57. package/dist/contexts/pageContext/pageContext.js +1 -1
  58. package/dist/contexts/systemSettingsContext/systemSettingsContext.d.cts +2 -2
  59. package/dist/contexts/types.d.cts +1 -1
  60. package/dist/contexts/types.d.ts +1 -1
  61. package/dist/contexts/typesV3.d.cts +1 -1
  62. package/dist/contexts/typesV3.d.ts +1 -1
  63. package/dist/contexts/widgetConfigContext/widgetConfigContext.cjs +22 -31
  64. package/dist/contexts/widgetConfigContext/widgetConfigContext.js +22 -31
  65. package/dist/hooks/GrabAndScroll/useGrabAndScroll.d.cts +2 -2
  66. package/dist/hooks/GrabAndScroll/useGrabAndScroll.d.ts +2 -2
  67. package/dist/hooks/Intersection/useIntersection.cjs +14 -3
  68. package/dist/hooks/Intersection/useIntersection.js +14 -3
  69. package/dist/hooks/PageViewedEvent/usePageViewedEvent.cjs +1 -1
  70. package/dist/hooks/PageViewedEvent/usePageViewedEvent.js +1 -1
  71. package/dist/hooks/SystemSettingsContext/useSystemSettingsContext.d.cts +2 -2
  72. package/dist/hooks/utils.d.ts +1 -1
  73. package/dist/services/enviveConfigService/enviveConfigService.cjs +3 -24
  74. package/dist/services/enviveConfigService/enviveConfigService.js +4 -25
  75. package/dist/services/enviveConfigService/fetchGraphQLConfig.cjs +59 -54
  76. package/dist/services/enviveConfigService/fetchGraphQLConfig.js +60 -54
  77. package/dist/services/hardcopyService/hardcopyService.cjs +1 -1
  78. package/dist/services/hardcopyService/hardcopyService.js +1 -1
  79. package/dist/types/config-versions.cjs +1 -3
  80. package/dist/types/config-versions.js +2 -3
  81. package/package.json +1 -1
  82. package/src/application/models/graphql/index.ts +0 -1
  83. package/src/application/models/graphql/queries/getMerchantColorsQuery.ts +4 -15
  84. package/src/application/models/graphql/queries/getWidgetConfigQuery.ts +35 -14
  85. package/src/application/models/index.ts +0 -1
  86. package/src/contexts/pageContext/__tests__/pageContext.test.tsx +1 -2
  87. package/src/contexts/pageContext/pageContext.tsx +1 -2
  88. package/src/contexts/widgetConfigContext/__tests__/widgetConfigContext.test.tsx +52 -0
  89. package/src/contexts/widgetConfigContext/widgetConfigContext.tsx +39 -36
  90. package/src/hooks/Intersection/__tests__/useIntersection.test.ts +134 -0
  91. package/src/hooks/Intersection/useIntersection.ts +20 -4
  92. package/src/services/enviveConfigService/__tests__/enviveConfigService.test.ts +51 -75
  93. package/src/services/enviveConfigService/__tests__/fetchGraphQLConfig.test.ts +242 -90
  94. package/src/services/enviveConfigService/enviveConfigService.ts +15 -41
  95. package/src/services/enviveConfigService/fetchGraphQLConfig.ts +106 -68
  96. package/dist/application/models/graphql/queries/getColorsAndFrontendQuery.cjs +0 -18
  97. package/dist/application/models/graphql/queries/getColorsAndFrontendQuery.js +0 -18
  98. package/dist/application/models/graphql/queries/getMerchantColorsQuery.cjs +0 -18
  99. package/dist/application/models/graphql/queries/getMerchantColorsQuery.js +0 -18
  100. package/dist/application/models/graphql/queries/getMerchantFrontendConfigQuery.cjs +0 -18
  101. package/dist/application/models/graphql/queries/getMerchantFrontendConfigQuery.d.cts +0 -75
  102. package/dist/application/models/graphql/queries/getMerchantFrontendConfigQuery.d.ts +0 -75
  103. package/dist/application/models/graphql/queries/getMerchantFrontendConfigQuery.js +0 -18
  104. package/src/application/models/graphql/queries/getColorsAndFrontendQuery.ts +0 -13
  105. package/src/application/models/graphql/queries/getMerchantFrontendConfigQuery.ts +0 -103
@@ -1,10 +1,6 @@
1
1
  import { mockV3ColorsConfig, mockV3FrontendConfig } from 'src/contexts/graphqlContext/mockV3Config';
2
2
  import { FloatingButtonLocation } from '@envive-ai/react-toolkit-v3/FloatingButton';
3
- import {
4
- DEFAULT_PAGE_VARIANTS,
5
- fetchGraphQLConfig,
6
- fetchUnifiedGraphQLConfig,
7
- } from '../fetchGraphQLConfig';
3
+ import { DEFAULT_PAGE_VARIANTS, fetchUnifiedGraphQLConfig } from '../fetchGraphQLConfig';
8
4
 
9
5
  const { MockLogger } = vi.hoisted(() => {
10
6
  const MockLogger = vi.fn(function () {
@@ -25,9 +21,11 @@ function makeOkFetch(v3RootConfigValues: unknown, frontendValues?: unknown) {
25
21
  Promise.resolve({
26
22
  data: {
27
23
  me: {
28
- getProductsConfigByVersion: {
29
- v_three_config: { values: v3RootConfigValues },
30
- frontend: frontendValues == null ? undefined : { values: frontendValues },
24
+ getWidgetConfig: {
25
+ productsConfig: {
26
+ v_three_config: { values: v3RootConfigValues },
27
+ frontend: frontendValues == null ? undefined : { values: frontendValues },
28
+ },
31
29
  },
32
30
  },
33
31
  },
@@ -59,33 +57,33 @@ beforeEach(() => {
59
57
  vi.clearAllMocks();
60
58
  });
61
59
 
62
- describe('fetchGraphQLConfig', () => {
60
+ describe('productsConfig transform (via getWidgetConfig)', () => {
63
61
  describe('error handling', () => {
64
- it('returns empty config when the HTTP response is not ok', async () => {
62
+ it('throws when the HTTP response is not ok', async () => {
65
63
  mockFetch.mockResolvedValueOnce({ ok: false, statusText: 'Unauthorized' });
66
64
 
67
- const result = await fetchGraphQLConfig('https://api.example.com', 'key');
68
-
69
- expect(result).toEqual({ colorsConfig: undefined, frontendConfig: undefined });
65
+ await expect(
66
+ fetchUnifiedGraphQLConfig('https://api.example.com', 'key', 'user_1', [], 'app'),
67
+ ).rejects.toThrow('Unified config request failed');
70
68
  });
71
69
 
72
- it('returns empty config when the response contains GraphQL errors', async () => {
70
+ it('throws when the response contains GraphQL errors', async () => {
73
71
  mockFetch.mockResolvedValueOnce({
74
72
  ok: true,
75
73
  json: () => Promise.resolve({ errors: [{ message: 'Not authorized' }], data: null }),
76
74
  });
77
75
 
78
- const result = await fetchGraphQLConfig('https://api.example.com', 'key');
79
-
80
- expect(result).toEqual({ colorsConfig: undefined, frontendConfig: undefined });
76
+ await expect(
77
+ fetchUnifiedGraphQLConfig('https://api.example.com', 'key', 'user_1', [], 'app'),
78
+ ).rejects.toThrow('Unified config GraphQL errors');
81
79
  });
82
80
 
83
- it('returns empty config when fetch throws', async () => {
81
+ it('propagates the error when fetch throws', async () => {
84
82
  mockFetch.mockRejectedValueOnce(new Error('Network failure'));
85
83
 
86
- const result = await fetchGraphQLConfig('https://api.example.com', 'key');
87
-
88
- expect(result).toEqual({ colorsConfig: undefined, frontendConfig: undefined });
84
+ await expect(
85
+ fetchUnifiedGraphQLConfig('https://api.example.com', 'key', 'user_1', [], 'app'),
86
+ ).rejects.toThrow('Network failure');
89
87
  });
90
88
  });
91
89
 
@@ -93,9 +91,15 @@ describe('fetchGraphQLConfig', () => {
93
91
  it('returns mock config when v3RootConfig has no colors field', async () => {
94
92
  makeOkFetch({ ui_configs: {} });
95
93
 
96
- const result = await fetchGraphQLConfig('https://api.example.com', 'key');
94
+ const result = await fetchUnifiedGraphQLConfig(
95
+ 'https://api.example.com',
96
+ 'key',
97
+ 'user_1',
98
+ [],
99
+ 'app',
100
+ );
97
101
 
98
- expect(result).toEqual({
102
+ expect(result.orgConfig).toEqual({
99
103
  colorsConfig: mockV3ColorsConfig,
100
104
  frontendConfig: mockV3FrontendConfig,
101
105
  orgPageConfig: {
@@ -111,13 +115,19 @@ describe('fetchGraphQLConfig', () => {
111
115
  ok: true,
112
116
  json: () =>
113
117
  Promise.resolve({
114
- data: { me: { getProductsConfigByVersion: {} } },
118
+ data: { me: { getWidgetConfig: { productsConfig: {} } } },
115
119
  }),
116
120
  });
117
121
 
118
- const result = await fetchGraphQLConfig('https://api.example.com', 'key');
122
+ const result = await fetchUnifiedGraphQLConfig(
123
+ 'https://api.example.com',
124
+ 'key',
125
+ 'user_1',
126
+ [],
127
+ 'app',
128
+ );
119
129
 
120
- expect(result).toEqual({
130
+ expect(result.orgConfig).toEqual({
121
131
  colorsConfig: mockV3ColorsConfig,
122
132
  frontendConfig: mockV3FrontendConfig,
123
133
  orgPageConfig: {
@@ -141,9 +151,17 @@ describe('fetchGraphQLConfig', () => {
141
151
  ui_configs: { ...baseV3Config.ui_configs, floating_button: { position } },
142
152
  });
143
153
 
144
- const result = await fetchGraphQLConfig('https://api.example.com', 'key');
154
+ const result = await fetchUnifiedGraphQLConfig(
155
+ 'https://api.example.com',
156
+ 'key',
157
+ 'user_1',
158
+ [],
159
+ 'app',
160
+ );
145
161
 
146
- expect((result.frontendConfig as any)?.uiConfigs?.floatingButton?.position).toBe(expected);
162
+ expect((result.orgConfig?.frontendConfig as any)?.uiConfigs?.floatingButton?.position).toBe(
163
+ expected,
164
+ );
147
165
  });
148
166
 
149
167
  it('returns empty config for an unrecognised position string', async () => {
@@ -152,9 +170,15 @@ describe('fetchGraphQLConfig', () => {
152
170
  ui_configs: { ...baseV3Config.ui_configs, floating_button: { position: 'top-center' } },
153
171
  });
154
172
 
155
- const result = await fetchGraphQLConfig('https://api.example.com', 'key');
173
+ const result = await fetchUnifiedGraphQLConfig(
174
+ 'https://api.example.com',
175
+ 'key',
176
+ 'user_1',
177
+ [],
178
+ 'app',
179
+ );
156
180
 
157
- expect(result).toEqual({ colorsConfig: undefined, frontendConfig: undefined });
181
+ expect(result.orgConfig).toEqual({ colorsConfig: undefined, frontendConfig: undefined });
158
182
  });
159
183
  });
160
184
 
@@ -174,8 +198,15 @@ describe('fetchGraphQLConfig', () => {
174
198
  },
175
199
  });
176
200
 
177
- const result = await fetchGraphQLConfig('https://api.example.com', 'key');
178
- const fontSize = (result.frontendConfig as any)?.uiConfigs?.lookAndFeel?.typography?.fontSize;
201
+ const result = await fetchUnifiedGraphQLConfig(
202
+ 'https://api.example.com',
203
+ 'key',
204
+ 'user_1',
205
+ [],
206
+ 'app',
207
+ );
208
+ const fontSize = (result.orgConfig?.frontendConfig as any)?.uiConfigs?.lookAndFeel?.typography
209
+ ?.fontSize;
179
210
 
180
211
  expect(fontSize?.b1).toBe('14px');
181
212
  expect(fontSize?.h1).toBe('20px');
@@ -196,9 +227,15 @@ describe('fetchGraphQLConfig', () => {
196
227
  },
197
228
  });
198
229
 
199
- const result = await fetchGraphQLConfig('https://api.example.com', 'key');
200
- const lineHeight = (result.frontendConfig as any)?.uiConfigs?.lookAndFeel?.typography
201
- ?.lineHeight;
230
+ const result = await fetchUnifiedGraphQLConfig(
231
+ 'https://api.example.com',
232
+ 'key',
233
+ 'user_1',
234
+ [],
235
+ 'app',
236
+ );
237
+ const lineHeight = (result.orgConfig?.frontendConfig as any)?.uiConfigs?.lookAndFeel
238
+ ?.typography?.lineHeight;
202
239
 
203
240
  expect(lineHeight?.['114']).toBe('1.14');
204
241
  expect(lineHeight?.['128']).toBe('1.28');
@@ -220,8 +257,14 @@ describe('fetchGraphQLConfig', () => {
220
257
  },
221
258
  });
222
259
 
223
- const result = await fetchGraphQLConfig('https://api.example.com', 'key');
224
- const lookAndFeel = (result.frontendConfig as any)?.uiConfigs?.lookAndFeel;
260
+ const result = await fetchUnifiedGraphQLConfig(
261
+ 'https://api.example.com',
262
+ 'key',
263
+ 'user_1',
264
+ [],
265
+ 'app',
266
+ );
267
+ const lookAndFeel = (result.orgConfig?.frontendConfig as any)?.uiConfigs?.lookAndFeel;
225
268
 
226
269
  expect(lookAndFeel?.chatHeaderLogoDarkSrc).toBe('logo.png');
227
270
  });
@@ -240,8 +283,14 @@ describe('fetchGraphQLConfig', () => {
240
283
  },
241
284
  });
242
285
 
243
- const result = await fetchGraphQLConfig('https://api.example.com', 'key');
244
- const lookAndFeel = (result.frontendConfig as any)?.uiConfigs?.lookAndFeel;
286
+ const result = await fetchUnifiedGraphQLConfig(
287
+ 'https://api.example.com',
288
+ 'key',
289
+ 'user_1',
290
+ [],
291
+ 'app',
292
+ );
293
+ const lookAndFeel = (result.orgConfig?.frontendConfig as any)?.uiConfigs?.lookAndFeel;
245
294
 
246
295
  expect(lookAndFeel?.chatHeaderLogoLightSrc).toBe('logo.png');
247
296
  });
@@ -249,8 +298,14 @@ describe('fetchGraphQLConfig', () => {
249
298
  it('uses explicit dark/light src when both are set', async () => {
250
299
  makeOkFetch(baseV3Config);
251
300
 
252
- const result = await fetchGraphQLConfig('https://api.example.com', 'key');
253
- const lookAndFeel = (result.frontendConfig as any)?.uiConfigs?.lookAndFeel;
301
+ const result = await fetchUnifiedGraphQLConfig(
302
+ 'https://api.example.com',
303
+ 'key',
304
+ 'user_1',
305
+ [],
306
+ 'app',
307
+ );
308
+ const lookAndFeel = (result.orgConfig?.frontendConfig as any)?.uiConfigs?.lookAndFeel;
254
309
 
255
310
  expect(lookAndFeel?.chatHeaderLogoDarkSrc).toBe('logo-dark.png');
256
311
  expect(lookAndFeel?.chatHeaderLogoLightSrc).toBe('logo-light.png');
@@ -267,17 +322,33 @@ describe('fetchGraphQLConfig', () => {
267
322
  },
268
323
  });
269
324
 
270
- const result = await fetchGraphQLConfig('https://api.example.com', 'key');
325
+ const result = await fetchUnifiedGraphQLConfig(
326
+ 'https://api.example.com',
327
+ 'key',
328
+ 'user_1',
329
+ [],
330
+ 'app',
331
+ );
271
332
 
272
- expect((result.frontendConfig as any)?.merchantOverrideCss).toBe('body { color: red; }');
333
+ expect((result.orgConfig?.frontendConfig as any)?.merchantOverrideCss).toBe(
334
+ 'body { color: red; }',
335
+ );
273
336
  });
274
337
 
275
338
  it('falls back to frontendValues.merchant_override_css when absent from v3 config', async () => {
276
339
  makeOkFetch(baseV3Config, { merchant_override_css: 'body { color: blue; }' });
277
340
 
278
- const result = await fetchGraphQLConfig('https://api.example.com', 'key');
341
+ const result = await fetchUnifiedGraphQLConfig(
342
+ 'https://api.example.com',
343
+ 'key',
344
+ 'user_1',
345
+ [],
346
+ 'app',
347
+ );
279
348
 
280
- expect((result.frontendConfig as any)?.merchantOverrideCss).toBe('body { color: blue; }');
349
+ expect((result.orgConfig?.frontendConfig as any)?.merchantOverrideCss).toBe(
350
+ 'body { color: blue; }',
351
+ );
281
352
  });
282
353
  });
283
354
 
@@ -285,9 +356,15 @@ describe('fetchGraphQLConfig', () => {
285
356
  it('uses DEFAULT_PAGE_VARIANTS when page_variants is not an array', async () => {
286
357
  makeOkFetch({ ...baseV3Config, page_variants: null });
287
358
 
288
- const result = await fetchGraphQLConfig('https://api.example.com', 'key');
359
+ const result = await fetchUnifiedGraphQLConfig(
360
+ 'https://api.example.com',
361
+ 'key',
362
+ 'user_1',
363
+ [],
364
+ 'app',
365
+ );
289
366
 
290
- expect(result.orgPageConfig?.pageVariants).toEqual(DEFAULT_PAGE_VARIANTS);
367
+ expect(result.orgConfig?.orgPageConfig?.pageVariants).toEqual(DEFAULT_PAGE_VARIANTS);
291
368
  });
292
369
 
293
370
  it('transforms each page variant entry from the API response', async () => {
@@ -300,11 +377,19 @@ describe('fetchGraphQLConfig', () => {
300
377
  };
301
378
  makeOkFetch({ ...baseV3Config, page_variants: [rawVariant] });
302
379
 
303
- const result = await fetchGraphQLConfig('https://api.example.com', 'key');
380
+ const result = await fetchUnifiedGraphQLConfig(
381
+ 'https://api.example.com',
382
+ 'key',
383
+ 'user_1',
384
+ [],
385
+ 'app',
386
+ );
304
387
 
305
- expect(result.orgPageConfig?.pageVariants).toHaveLength(1);
306
- expect(result.orgPageConfig?.pageVariants[0].variantId).toBe('plp');
307
- expect(result.orgPageConfig?.pageVariants[0].variantTests?.[0].testType).toBe('UrlResolver');
388
+ expect(result.orgConfig?.orgPageConfig?.pageVariants).toHaveLength(1);
389
+ expect(result.orgConfig?.orgPageConfig?.pageVariants[0].variantId).toBe('plp');
390
+ expect(result.orgConfig?.orgPageConfig?.pageVariants[0].variantTests?.[0].testType).toBe(
391
+ 'UrlResolver',
392
+ );
308
393
  });
309
394
  });
310
395
 
@@ -316,24 +401,36 @@ describe('fetchGraphQLConfig', () => {
316
401
  ];
317
402
  makeOkFetch({ ...baseV3Config, widget_configs: rawWidgets });
318
403
 
319
- const result = await fetchGraphQLConfig('https://api.example.com', 'key');
404
+ const result = await fetchUnifiedGraphQLConfig(
405
+ 'https://api.example.com',
406
+ 'key',
407
+ 'user_1',
408
+ [],
409
+ 'app',
410
+ );
320
411
 
321
- expect(Object.keys(result.orgPageConfig?.widgetConfigs ?? {})).toEqual([
412
+ expect(Object.keys(result.orgConfig?.orgPageConfig?.widgetConfigs ?? {})).toEqual([
322
413
  'widget-1',
323
414
  'widget-2',
324
415
  ]);
325
- expect((result.orgPageConfig?.widgetConfigs as any)?.['widget-1']?.widgetConfigId).toBe(
326
- 'widget-1',
327
- );
416
+ expect(
417
+ (result.orgConfig?.orgPageConfig?.widgetConfigs as any)?.['widget-1']?.widgetConfigId,
418
+ ).toBe('widget-1');
328
419
  });
329
420
 
330
421
  it('also exposes widget configs on frontendConfig', async () => {
331
422
  const rawWidgets = [{ widget_config_id: 'widget-1', widget_type: 'floating_button' }];
332
423
  makeOkFetch({ ...baseV3Config, widget_configs: rawWidgets });
333
424
 
334
- const result = await fetchGraphQLConfig('https://api.example.com', 'key');
425
+ const result = await fetchUnifiedGraphQLConfig(
426
+ 'https://api.example.com',
427
+ 'key',
428
+ 'user_1',
429
+ [],
430
+ 'app',
431
+ );
335
432
 
336
- expect((result.frontendConfig as any)?.widgetConfigs?.['widget-1']).toBeDefined();
433
+ expect((result.orgConfig?.frontendConfig as any)?.widgetConfigs?.['widget-1']).toBeDefined();
337
434
  });
338
435
  });
339
436
 
@@ -352,10 +449,18 @@ describe('fetchGraphQLConfig', () => {
352
449
  ];
353
450
  makeOkFetch({ ...baseV3Config, mounting_configs: rawMountingConfigs });
354
451
 
355
- const result = await fetchGraphQLConfig('https://api.example.com', 'key');
452
+ const result = await fetchUnifiedGraphQLConfig(
453
+ 'https://api.example.com',
454
+ 'key',
455
+ 'user_1',
456
+ [],
457
+ 'app',
458
+ );
356
459
 
357
- expect(result.orgPageConfig?.mountingConfigs?.['plp-mount']).toBeDefined();
358
- expect(result.orgPageConfig?.mountingConfigs?.['plp-mount']?.mountingConfigId).toBe('mc-1');
460
+ expect(result.orgConfig?.orgPageConfig?.mountingConfigs?.['plp-mount']).toBeDefined();
461
+ expect(
462
+ result.orgConfig?.orgPageConfig?.mountingConfigs?.['plp-mount']?.mountingConfigId,
463
+ ).toBe('mc-1');
359
464
  });
360
465
  });
361
466
 
@@ -366,10 +471,16 @@ describe('fetchGraphQLConfig', () => {
366
471
  colors: { values: { text_primary: '#111', background_primary: '#fff' } },
367
472
  });
368
473
 
369
- const result = await fetchGraphQLConfig('https://api.example.com', 'key');
474
+ const result = await fetchUnifiedGraphQLConfig(
475
+ 'https://api.example.com',
476
+ 'key',
477
+ 'user_1',
478
+ [],
479
+ 'app',
480
+ );
370
481
 
371
- expect((result.colorsConfig as any)?.textPrimary).toBe('#111');
372
- expect((result.colorsConfig as any)?.backgroundPrimary).toBe('#fff');
482
+ expect((result.orgConfig?.colorsConfig as any)?.textPrimary).toBe('#111');
483
+ expect((result.orgConfig?.colorsConfig as any)?.backgroundPrimary).toBe('#fff');
373
484
  });
374
485
  });
375
486
 
@@ -377,10 +488,16 @@ describe('fetchGraphQLConfig', () => {
377
488
  it('returns config as-is when uiConfigs is absent', async () => {
378
489
  makeOkFetch({ ...baseV3Config, ui_configs: undefined });
379
490
 
380
- const result = await fetchGraphQLConfig('https://api.example.com', 'key');
491
+ const result = await fetchUnifiedGraphQLConfig(
492
+ 'https://api.example.com',
493
+ 'key',
494
+ 'user_1',
495
+ [],
496
+ 'app',
497
+ );
381
498
 
382
- expect(result.frontendConfig).toBeDefined();
383
- expect(result.colorsConfig).toBeDefined();
499
+ expect(result.orgConfig?.frontendConfig).toBeDefined();
500
+ expect(result.orgConfig?.colorsConfig).toBeDefined();
384
501
  });
385
502
 
386
503
  it('returns config as-is when floatingButton is absent', async () => {
@@ -391,9 +508,15 @@ describe('fetchGraphQLConfig', () => {
391
508
  },
392
509
  });
393
510
 
394
- const result = await fetchGraphQLConfig('https://api.example.com', 'key');
511
+ const result = await fetchUnifiedGraphQLConfig(
512
+ 'https://api.example.com',
513
+ 'key',
514
+ 'user_1',
515
+ [],
516
+ 'app',
517
+ );
395
518
 
396
- expect(result.frontendConfig).toBeDefined();
519
+ expect(result.orgConfig?.frontendConfig).toBeDefined();
397
520
  });
398
521
 
399
522
  it('returns config as-is when lookAndFeel is absent', async () => {
@@ -404,9 +527,15 @@ describe('fetchGraphQLConfig', () => {
404
527
  },
405
528
  });
406
529
 
407
- const result = await fetchGraphQLConfig('https://api.example.com', 'key');
530
+ const result = await fetchUnifiedGraphQLConfig(
531
+ 'https://api.example.com',
532
+ 'key',
533
+ 'user_1',
534
+ [],
535
+ 'app',
536
+ );
408
537
 
409
- expect(result.frontendConfig).toBeDefined();
538
+ expect(result.orgConfig?.frontendConfig).toBeDefined();
410
539
  });
411
540
  });
412
541
 
@@ -414,7 +543,7 @@ describe('fetchGraphQLConfig', () => {
414
543
  it('sends a POST to the correct GraphQL endpoint with the API key', async () => {
415
544
  makeOkFetch(null);
416
545
 
417
- await fetchGraphQLConfig('https://api.example.com', 'test-key');
546
+ await fetchUnifiedGraphQLConfig('https://api.example.com', 'test-key', 'user_1', [], 'app');
418
547
 
419
548
  expect(mockFetch).toHaveBeenCalledWith('https://api.example.com/v1/graphql', {
420
549
  method: 'POST',
@@ -451,7 +580,7 @@ describe('fetchUnifiedGraphQLConfig', () => {
451
580
  it('issues a getWidgetConfig query (not getProductsConfigByVersion) and forwards userId', async () => {
452
581
  makeUnifiedOkFetch(null);
453
582
 
454
- await fetchUnifiedGraphQLConfig('https://api.example.com', 'key', 'user_1');
583
+ await fetchUnifiedGraphQLConfig('https://api.example.com', 'key', 'user_1', [], 'app');
455
584
 
456
585
  const body = JSON.parse(mockFetch.mock.calls[0][1].body);
457
586
  expect(body.query).toContain('getWidgetConfig');
@@ -459,7 +588,7 @@ describe('fetchUnifiedGraphQLConfig', () => {
459
588
  // userId is required by the schema; omitting it 400s. Regression guard.
460
589
  // version is absent without a URL-param override so the resolver uses
461
590
  // Statsig bucketing (passing 'deployed' here would bypass Statsig).
462
- expect(body.variables).toEqual({ userId: 'user_1' });
591
+ expect(body.variables).toEqual({ userId: 'user_1', gateNames: [], source: 'app' });
463
592
  });
464
593
 
465
594
  it('threads a spiffy_config_version URL param through as the version variable', async () => {
@@ -467,10 +596,15 @@ describe('fetchUnifiedGraphQLConfig', () => {
467
596
  try {
468
597
  makeUnifiedOkFetch(null);
469
598
 
470
- await fetchUnifiedGraphQLConfig('https://api.example.com', 'key', 'user_1');
599
+ await fetchUnifiedGraphQLConfig('https://api.example.com', 'key', 'user_1', [], 'app');
471
600
 
472
601
  const body = JSON.parse(mockFetch.mock.calls[0][1].body);
473
- expect(body.variables).toEqual({ userId: 'user_1', version: '1.2.3' });
602
+ expect(body.variables).toEqual({
603
+ userId: 'user_1',
604
+ version: '1.2.3',
605
+ gateNames: [],
606
+ source: 'app',
607
+ });
474
608
  } finally {
475
609
  window.history.replaceState({}, '', '/');
476
610
  }
@@ -479,11 +613,17 @@ describe('fetchUnifiedGraphQLConfig', () => {
479
613
  it('parses productsConfig into the same shape as fetchGraphQLConfig', async () => {
480
614
  makeUnifiedOkFetch(baseV3Config);
481
615
 
482
- const result = await fetchUnifiedGraphQLConfig('https://api.example.com', 'key', 'user_1');
483
-
484
- expect(result.colorsConfig).toBeDefined();
485
- expect(result.frontendConfig).toBeDefined();
486
- expect(result.orgPageConfig).toBeDefined();
616
+ const result = await fetchUnifiedGraphQLConfig(
617
+ 'https://api.example.com',
618
+ 'key',
619
+ 'user_1',
620
+ [],
621
+ 'app',
622
+ );
623
+
624
+ expect(result.orgConfig?.colorsConfig).toBeDefined();
625
+ expect(result.orgConfig?.frontendConfig).toBeDefined();
626
+ expect(result.orgConfig?.orgPageConfig).toBeDefined();
487
627
  });
488
628
 
489
629
  it('returns resolution metadata alongside the config so callers can thread baseVersion into inference', async () => {
@@ -492,9 +632,15 @@ describe('fetchUnifiedGraphQLConfig', () => {
492
632
  baseVersionSource: 'merchant_layer',
493
633
  });
494
634
 
495
- const result = await fetchUnifiedGraphQLConfig('https://api.example.com', 'key', 'user_1');
635
+ const result = await fetchUnifiedGraphQLConfig(
636
+ 'https://api.example.com',
637
+ 'key',
638
+ 'user_1',
639
+ [],
640
+ 'app',
641
+ );
496
642
 
497
- expect(result.resolution).toEqual({
643
+ expect(result.orgConfig?.resolution).toEqual({
498
644
  baseVersion: '1.0.670',
499
645
  baseVersionSource: 'merchant_layer',
500
646
  });
@@ -503,7 +649,7 @@ describe('fetchUnifiedGraphQLConfig', () => {
503
649
  it('selects resolution fields in the query so the server can fill them', async () => {
504
650
  makeUnifiedOkFetch(null);
505
651
 
506
- await fetchUnifiedGraphQLConfig('https://api.example.com', 'key', 'user_1');
652
+ await fetchUnifiedGraphQLConfig('https://api.example.com', 'key', 'user_1', [], 'app');
507
653
 
508
654
  const body = JSON.parse(mockFetch.mock.calls[0][1].body);
509
655
  expect(body.query).toContain('resolution');
@@ -516,16 +662,22 @@ describe('fetchUnifiedGraphQLConfig', () => {
516
662
  // colors, DEFAULT_PAGE_VARIANTS is returned as the orgPageConfig.
517
663
  makeUnifiedOkFetch(null);
518
664
 
519
- const result = await fetchUnifiedGraphQLConfig('https://api.example.com', 'key', 'user_1');
665
+ const result = await fetchUnifiedGraphQLConfig(
666
+ 'https://api.example.com',
667
+ 'key',
668
+ 'user_1',
669
+ [],
670
+ 'app',
671
+ );
520
672
 
521
- expect(result.orgPageConfig?.pageVariants).toEqual(DEFAULT_PAGE_VARIANTS);
673
+ expect(result.orgConfig?.orgPageConfig?.pageVariants).toEqual(DEFAULT_PAGE_VARIANTS);
522
674
  });
523
675
 
524
- it('returns empty config on network failure', async () => {
676
+ it('propagates the error on network failure', async () => {
525
677
  mockFetch.mockRejectedValueOnce(new Error('boom'));
526
678
 
527
- const result = await fetchUnifiedGraphQLConfig('https://api.example.com', 'key', 'user_1');
528
-
529
- expect(result).toEqual({ colorsConfig: undefined, frontendConfig: undefined });
679
+ await expect(
680
+ fetchUnifiedGraphQLConfig('https://api.example.com', 'key', 'user_1', [], 'app'),
681
+ ).rejects.toThrow('boom');
530
682
  });
531
683
  });
@@ -1,9 +1,8 @@
1
1
  import { OrgConfigExperimentAssignment, OrgConfigFeatureGate } from 'src/application/models';
2
2
  import { FeatureGates } from 'src/application/models/featureGates';
3
- import { FeatureFlagService } from 'src/services/featureFlagService';
4
3
  import type { GraphQlConfigValues } from 'src/contexts/graphqlContext';
5
4
  import { configVersionOverride } from 'src/types/config-versions';
6
- import { fetchGraphQLConfig, fetchUnifiedGraphQLConfig } from './fetchGraphQLConfig';
5
+ import { fetchUnifiedGraphQLConfig } from './fetchGraphQLConfig';
7
6
 
8
7
  // Short-lived so config changes (gates, experiments) still propagate within
9
8
  // a session, while sparing every page navigation from re-fetching org
@@ -126,45 +125,20 @@ export class EnviveConfigService implements IEnviveConfigService {
126
125
  return this.response;
127
126
  }
128
127
 
129
- const queryParams = new URLSearchParams({
130
- namespace: this.namespace,
131
- source: this.source,
132
- user_id: this.userId,
133
- include_experiments: 'default',
134
- include_feature_gates: Object.values(FeatureGates)
135
- .map(featureGate => featureGate.toString())
136
- .join(','),
137
- });
138
- // Serialized so we can branch the GraphQL call on the `use_unified_config`
139
- // gate returned by /v1/org/config. Once the migration to getWidgetConfig
140
- // completes (one endpoint returning gates + experiments + productsConfig),
141
- // this collapses back to a single call.
142
- const orgConfigResponse = await fetch(
143
- `${this.baseUrl}/v1/org/config?${queryParams.toString()}`,
144
- {
145
- method: 'GET',
146
- headers: {
147
- 'Content-Type': 'application/json',
148
- Authorization: `Bearer ${this.apiKey}`,
149
- },
150
- },
151
- ).then(async r => {
152
- if (!r.ok) {
153
- throw new Error(`Org config request failed with status ${r.status}`);
154
- }
155
- return r.json() as Promise<EnviveServiceConfig>;
156
- });
157
-
158
- // Honor URL / `window._spiffy` / localStorage overrides for
159
- // `use_unified_config` the same way every other feature gate is read.
160
- const useUnifiedConfig = new FeatureFlagService(
161
- orgConfigResponse.gates ?? [],
162
- ).isFeatureGateEnabled(FeatureGates.UseUnifiedConfig);
163
- const orgConfig = useUnifiedConfig
164
- ? await fetchUnifiedGraphQLConfig(this.baseUrl, this.apiKey, this.userId)
165
- : await fetchGraphQLConfig(this.baseUrl, this.apiKey);
166
-
167
- this.response = { ...orgConfigResponse, orgConfig };
128
+ // getWidgetConfig is the single source of session config: it returns org
129
+ // identity + feature gates + experiment assignments (which used to be a
130
+ // separate GET /v1/org/config call) alongside productsConfig + the
131
+ // resolution metadata threaded into downstream inference. `gateNames` is the
132
+ // list of gates the app checks, so the resolver evaluates and returns them.
133
+ const gateNames = Object.values(FeatureGates).map(featureGate => featureGate.toString());
134
+
135
+ this.response = await fetchUnifiedGraphQLConfig(
136
+ this.baseUrl,
137
+ this.apiKey,
138
+ this.userId,
139
+ gateNames,
140
+ this.source,
141
+ );
168
142
  this.writeCachedConfig(this.response);
169
143
  return this.response;
170
144
  }