@envive-ai/react-hooks 0.3.63 → 0.3.65

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 (112) hide show
  1. package/dist/application/models/featureGates.cjs +2 -2
  2. package/dist/application/models/featureGates.d.cts +2 -2
  3. package/dist/application/models/featureGates.d.ts +2 -2
  4. package/dist/application/models/featureGates.js +2 -2
  5. package/dist/application/utils/elementObserver.d.cts +2 -2
  6. package/dist/atoms/app/index.d.cts +7 -7
  7. package/dist/atoms/app/index.d.ts +1 -1
  8. package/dist/atoms/app/variant.d.ts +6 -6
  9. package/dist/atoms/chat/chatState.d.cts +19 -19
  10. package/dist/atoms/chat/chatState.d.ts +19 -19
  11. package/dist/atoms/chat/form.d.cts +2 -2
  12. package/dist/atoms/chat/form.d.ts +3 -3
  13. package/dist/atoms/chat/index.d.ts +3 -3
  14. package/dist/atoms/chat/lastMessage.d.cts +2 -2
  15. package/dist/atoms/chat/lastMessage.d.ts +2 -2
  16. package/dist/atoms/chat/messageQueue.d.ts +7 -7
  17. package/dist/atoms/chat/performanceMetrics.d.cts +6 -6
  18. package/dist/atoms/chat/performanceMetrics.d.ts +6 -6
  19. package/dist/atoms/chat/renderedWidgetRefs.d.cts +2 -2
  20. package/dist/atoms/chat/renderedWidgetRefs.d.ts +3 -3
  21. package/dist/atoms/chat/replies.d.cts +3 -3
  22. package/dist/atoms/chat/suggestions.d.ts +3 -3
  23. package/dist/atoms/envive/enviveConfig.d.cts +14 -14
  24. package/dist/atoms/globalSearch/globalSearch.d.cts +5 -5
  25. package/dist/atoms/org/customerService.d.cts +6 -6
  26. package/dist/atoms/org/customerService.d.ts +6 -6
  27. package/dist/atoms/org/graphqlConfig.d.cts +4 -4
  28. package/dist/atoms/org/graphqlConfig.d.ts +4 -4
  29. package/dist/atoms/org/newOrgConfigAtom.d.cts +2 -2
  30. package/dist/atoms/org/newOrgConfigAtom.d.ts +2 -2
  31. package/dist/atoms/org/orgAnalyticsConfig.d.cts +4 -4
  32. package/dist/atoms/org/orgAnalyticsConfig.d.ts +4 -4
  33. package/dist/atoms/search/types.d.cts +1 -1
  34. package/dist/atoms/search/utils.d.cts +1 -1
  35. package/dist/atoms/widget/chatPreviewLoading.d.cts +2 -2
  36. package/dist/atoms/widget/chatPreviewLoading.d.ts +2 -2
  37. package/dist/contexts/pageContext/pageContext.cjs +12 -24
  38. package/dist/contexts/pageContext/pageContext.js +12 -24
  39. package/dist/contexts/systemSettingsContext/systemSettingsContext.d.cts +2 -2
  40. package/dist/contexts/types.d.cts +1 -1
  41. package/dist/contexts/types.d.ts +1 -1
  42. package/dist/contexts/typesV3.cjs +8 -1
  43. package/dist/contexts/typesV3.d.cts +23 -6
  44. package/dist/contexts/typesV3.d.ts +23 -6
  45. package/dist/contexts/typesV3.js +8 -2
  46. package/dist/hooks/Intersection/useIntersection.cjs +9 -2
  47. package/dist/hooks/Intersection/useIntersection.d.cts +2 -2
  48. package/dist/hooks/Intersection/useIntersection.d.ts +2 -2
  49. package/dist/hooks/Intersection/useIntersection.js +9 -2
  50. package/dist/hooks/SystemSettingsContext/useSystemSettingsContext.d.cts +2 -2
  51. package/dist/hooks/TrackComponentVisibleEvent/useTrackComponentVisibleEvent.cjs +12 -3
  52. package/dist/hooks/TrackComponentVisibleEvent/useTrackComponentVisibleEvent.d.cts +2 -1
  53. package/dist/hooks/TrackComponentVisibleEvent/useTrackComponentVisibleEvent.d.ts +2 -1
  54. package/dist/hooks/TrackComponentVisibleEvent/useTrackComponentVisibleEvent.js +13 -4
  55. package/dist/hooks/WidgetLoadDiagnostics/index.cjs +4 -0
  56. package/dist/hooks/WidgetLoadDiagnostics/index.d.cts +2 -0
  57. package/dist/hooks/WidgetLoadDiagnostics/index.d.ts +2 -0
  58. package/dist/hooks/WidgetLoadDiagnostics/index.js +3 -0
  59. package/dist/hooks/WidgetLoadDiagnostics/useWidgetLoadDiagnostics.cjs +122 -0
  60. package/dist/hooks/WidgetLoadDiagnostics/useWidgetLoadDiagnostics.d.cts +48 -0
  61. package/dist/hooks/WidgetLoadDiagnostics/useWidgetLoadDiagnostics.d.ts +48 -0
  62. package/dist/hooks/WidgetLoadDiagnostics/useWidgetLoadDiagnostics.js +120 -0
  63. package/dist/hooks/utils.d.cts +1 -1
  64. package/dist/hooks/utils.d.ts +1 -1
  65. package/dist/services/amplitudeService/eventNames.cjs +2 -1
  66. package/dist/services/amplitudeService/eventNames.d.cts +2 -1
  67. package/dist/services/amplitudeService/eventNames.d.ts +2 -1
  68. package/dist/services/amplitudeService/eventNames.js +2 -1
  69. package/dist/services/enviveConfigService/enviveConfigService.cjs +21 -35
  70. package/dist/services/enviveConfigService/enviveConfigService.d.cts +1 -2
  71. package/dist/services/enviveConfigService/enviveConfigService.d.ts +1 -2
  72. package/dist/services/enviveConfigService/enviveConfigService.js +21 -35
  73. package/dist/services/enviveConfigService/fetchBootstrapConfig.cjs +15 -16
  74. package/dist/services/enviveConfigService/fetchBootstrapConfig.js +15 -16
  75. package/dist/services/enviveConfigService/fetchGraphQLConfig.cjs +1 -69
  76. package/dist/services/enviveConfigService/fetchGraphQLConfig.js +2 -69
  77. package/dist/services/featureFlagService/index.cjs +7 -5
  78. package/dist/services/featureFlagService/index.d.cts +2 -1
  79. package/dist/services/featureFlagService/index.d.ts +2 -1
  80. package/dist/services/featureFlagService/index.js +7 -5
  81. package/dist/services/ga4ProjectionService/ga4EventSchema.cjs +3 -2
  82. package/dist/services/ga4ProjectionService/ga4EventSchema.js +3 -2
  83. package/dist/services/hardcopyService/hardcopyService.cjs +12 -3
  84. package/dist/services/hardcopyService/hardcopyService.d.cts +3 -1
  85. package/dist/services/hardcopyService/hardcopyService.d.ts +3 -1
  86. package/dist/services/hardcopyService/hardcopyService.js +12 -3
  87. package/package.json +5 -1
  88. package/src/application/models/featureGates.ts +11 -8
  89. package/src/contexts/pageContext/__tests__/pageContext.test.tsx +4 -59
  90. package/src/contexts/pageContext/pageContext.tsx +20 -41
  91. package/src/contexts/typesV3.ts +22 -4
  92. package/src/hooks/Intersection/useIntersection.ts +11 -0
  93. package/src/hooks/TrackComponentVisibleEvent/__tests__/useTrackComponentVisibleEvent.test.tsx +64 -0
  94. package/src/hooks/TrackComponentVisibleEvent/useTrackComponentVisibleEvent.ts +23 -4
  95. package/src/hooks/WidgetLoadDiagnostics/__tests__/useWidgetLoadDiagnostics.test.ts +161 -0
  96. package/src/hooks/WidgetLoadDiagnostics/index.ts +5 -0
  97. package/src/hooks/WidgetLoadDiagnostics/useWidgetLoadDiagnostics.ts +178 -0
  98. package/src/services/amplitudeService/eventNames.ts +4 -0
  99. package/src/services/enviveConfigService/__tests__/enviveConfigService.test.ts +72 -158
  100. package/src/services/enviveConfigService/__tests__/fetchBootstrapConfig.test.ts +111 -13
  101. package/src/services/enviveConfigService/__tests__/fetchGraphQLConfig.test.ts +161 -490
  102. package/src/services/enviveConfigService/enviveConfigService.ts +51 -87
  103. package/src/services/enviveConfigService/fetchBootstrapConfig.ts +74 -66
  104. package/src/services/enviveConfigService/fetchGraphQLConfig.ts +0 -120
  105. package/src/services/featureFlagService/__tests__/getFeatureFlagOverrides.test.ts +54 -0
  106. package/src/services/featureFlagService/index.ts +19 -6
  107. package/src/services/ga4ProjectionService/ga4EventSchema.ts +5 -0
  108. package/src/services/hardcopyService/__tests__/hardcopyService.test.ts +16 -5
  109. package/src/services/hardcopyService/hardcopyService.ts +10 -2
  110. package/dist/application/models/graphql/queries/getWidgetConfigQuery.cjs +0 -42
  111. package/dist/application/models/graphql/queries/getWidgetConfigQuery.js +0 -41
  112. package/src/application/models/graphql/queries/getWidgetConfigQuery.ts +0 -55
@@ -67,9 +67,9 @@ const baseParams: FetchBootstrapConfigParams = {
67
67
  source: 'app',
68
68
  namespace: 'spiffy-react-components',
69
69
  gateNames: ['use_unified_config', 'is_client_session_enabled'],
70
+ // url_resolving inputs (org identity is NOT sent — the server fills it from the
71
+ // authenticated org). Absent url ⇒ bootstrap omits the url_resolving branch.
70
72
  url: 'https://shop.example.com/products/thing',
71
- orgId: 'org-1',
72
- orgShortName: 'test-org',
73
73
  contextSource: 'app',
74
74
  env: 'prod',
75
75
  featureGates: { use_unified_config: true, is_empty_div_plp_enabled: true },
@@ -180,20 +180,38 @@ describe('fetchBootstrapConfig', () => {
180
180
  });
181
181
  expect(body.url_resolving).toMatchObject({
182
182
  url: 'https://shop.example.com/products/thing',
183
- // Override-aware gates forwarded so client overrides reach page-variant resolution.
183
+ // Override-only gates forwarded so client overrides reach page-variant resolution.
184
184
  feature_gates: { use_unified_config: true, is_empty_div_plp_enabled: true },
185
185
  });
186
- // No org_base_config_version — the version comes only from the URL query param
187
- // (override_config_version), never from getWidgetConfig's resolution.
186
+ // No org_base_config_version — the version comes only from the URL query param.
188
187
  expect(body.url_resolving.org_base_config_version).toBeUndefined();
188
+ // org identity is NOT sent — the server fills org_id/org_short_name from the
189
+ // authenticated org (bootstrap-only has no getWidgetConfig to source them from).
189
190
  expect(body.url_resolving.context).toEqual({
190
191
  user_id: 'user-1',
191
- org_id: 'org-1',
192
- org_short_name: 'test-org',
193
192
  chat_id: 'chat-9',
194
193
  source: 'app',
195
194
  env: 'prod',
196
195
  });
196
+ expect(body.url_resolving.context.org_id).toBeUndefined();
197
+ expect(body.url_resolving.context.org_short_name).toBeUndefined();
198
+ });
199
+
200
+ it('omits the url_resolving branch from the request when no url is supplied', async () => {
201
+ makeBootstrapResponse();
202
+
203
+ // A disabled session (envive_on=false) requests config only — no page to resolve.
204
+ const { url, contextSource, env, featureGates, ...configOnly } = baseParams;
205
+ await fetchBootstrapConfig(configOnly);
206
+
207
+ const body = JSON.parse(mockFetch.mock.calls[0][1].body as string);
208
+ // Config inputs still sent; the whole url_resolving object is absent.
209
+ expect(body).toMatchObject({
210
+ user_id: 'user-1',
211
+ namespace: 'spiffy-react-components',
212
+ include_feature_gates: ['use_unified_config', 'is_client_session_enabled'],
213
+ });
214
+ expect(body.url_resolving).toBeUndefined();
197
215
  });
198
216
 
199
217
  it('threads a config-version query param into version + override_config_version', async () => {
@@ -207,7 +225,67 @@ describe('fetchBootstrapConfig', () => {
207
225
  expect(body.url_resolving.override_config_version).toBe('9.9.9');
208
226
  });
209
227
 
210
- it('throws on a non-ok response so the caller can fall back', async () => {
228
+ it('degrades a malformed products_config to mock WITHOUT losing org/gates/experiments', async () => {
229
+ // A 2xx with valid org/gates/widget_config but a products_config that throws
230
+ // in transformV3ProductsConfig (invalid floating-button position). With no
231
+ // getWidgetConfig fallback left, this catch is the SOLE thing keeping a bad
232
+ // products config from aborting injection — it must null colors/frontend only
233
+ // and preserve org identity + gates + experiment_assignments + resolution.
234
+ mockFetch.mockResolvedValueOnce({
235
+ ok: true,
236
+ json: () =>
237
+ Promise.resolve({
238
+ org_config: {
239
+ org: { org: { id: 'org-boot', short_name: 'boot-org' } },
240
+ gates: [{ name: 'use_unified_config', value: true, group_name: 'Treatment' }],
241
+ },
242
+ widget_config: {
243
+ products_config: {
244
+ v_three_config: {
245
+ values: {
246
+ colors: { values: { text_primary: '#000000' } },
247
+ ui_configs: {
248
+ floating_button: { position: 'top-center' }, // invalid → transform throws
249
+ look_and_feel: { typography: {} },
250
+ },
251
+ },
252
+ },
253
+ },
254
+ experiment_assignments: [
255
+ {
256
+ layer_name: 'ml',
257
+ namespace: 'ml',
258
+ allocated_experiment_name: 'exp_a',
259
+ group_name: 'A',
260
+ },
261
+ ],
262
+ resolution: { base_version: '2.0.0', base_version_source: 'merchant_layer' },
263
+ },
264
+ url_resolving: null,
265
+ }),
266
+ });
267
+
268
+ const { config } = await fetchBootstrapConfig(baseParams);
269
+
270
+ // org / gates / experiments survived the products-config failure.
271
+ expect(config.org.org.id).toBe('org-boot');
272
+ expect(config.gates).toContainEqual({
273
+ name: 'use_unified_config',
274
+ value: true,
275
+ groupName: 'Treatment',
276
+ });
277
+ expect(config.experiment_assignments).toEqual([
278
+ { layer_name: 'ml', namespace: 'ml', allocated_experiment_name: 'exp_a', group_name: 'A' },
279
+ ]);
280
+ // colors/frontend degraded to undefined, resolution still attached.
281
+ expect(config.orgConfig).toEqual({
282
+ colorsConfig: undefined,
283
+ frontendConfig: undefined,
284
+ resolution: { baseVersion: '2.0.0', baseVersionSource: 'merchant_layer' },
285
+ });
286
+ });
287
+
288
+ it('throws on a non-ok response so the caller aborts injection (no fallback)', async () => {
211
289
  mockFetch.mockResolvedValueOnce({ ok: false, statusText: 'Bad Gateway' });
212
290
 
213
291
  await expect(fetchBootstrapConfig(baseParams)).rejects.toThrow(
@@ -225,14 +303,13 @@ describe('fetchBootstrapConfig', () => {
225
303
  'partial org_config (no org.org)',
226
304
  { org_config: { org: {}, gates: okGates }, widget_config: okWidget },
227
305
  ],
228
- ['absent gates', { org_config: { org: { org: { id: 'o' } } }, widget_config: okWidget }],
229
306
  [
230
- 'empty gates',
231
- { org_config: { org: { org: { id: 'o' } }, gates: [] }, widget_config: okWidget },
307
+ 'absent gates (not an array)',
308
+ { org_config: { org: { org: { id: 'o' } } }, widget_config: okWidget },
232
309
  ],
233
310
  ['missing widget_config', { org_config: okOrg, widget_config: null }],
234
311
  ])(
235
- 'throws on a 2xx with %s so the caller can fall back to getWidgetConfig',
312
+ 'throws on a 2xx with %s so the caller aborts injection instead of using empty config',
236
313
  async (_label, payload) => {
237
314
  mockFetch.mockResolvedValueOnce({ ok: true, json: () => Promise.resolve(payload) });
238
315
 
@@ -240,6 +317,27 @@ describe('fetchBootstrapConfig', () => {
240
317
  },
241
318
  );
242
319
 
320
+ it('accepts an EMPTY (but present) gates array as a valid all-disabled config', async () => {
321
+ // An empty gates array is a legitimate "everything off" response (no user to
322
+ // bucket, or every requested gate off). It must NOT be rejected as malformed:
323
+ // FeatureFlagService resolves every gate to false → the session disables
324
+ // gracefully (with the init event still firing), rather than aborting injection.
325
+ mockFetch.mockResolvedValueOnce({
326
+ ok: true,
327
+ json: () =>
328
+ Promise.resolve({
329
+ org_config: { org: { org: { id: 'org-boot', short_name: 'boot-org' } }, gates: [] },
330
+ widget_config: { products_config: {}, experiment_assignments: [] },
331
+ url_resolving: null,
332
+ }),
333
+ });
334
+
335
+ const { config } = await fetchBootstrapConfig(baseParams);
336
+
337
+ expect(config.org.org.id).toBe('org-boot');
338
+ expect(config.gates).toEqual([]);
339
+ });
340
+
243
341
  it('passes an AbortSignal to fetch (timeout wiring)', async () => {
244
342
  makeBootstrapResponse();
245
343
 
@@ -249,7 +347,7 @@ describe('fetchBootstrapConfig', () => {
249
347
  expect(options.signal).toBeInstanceOf(AbortSignal);
250
348
  });
251
349
 
252
- it('aborts and rejects when the request exceeds the timeout so the caller can fall back', async () => {
350
+ it('aborts and rejects when the request exceeds the timeout (injection aborts, no fallback)', async () => {
253
351
  vi.useFakeTimers();
254
352
  // Mimic real fetch: reject with an AbortError once its signal aborts.
255
353
  mockFetch.mockImplementationOnce(