@envive-ai/react-hooks 0.3.44 → 0.3.46

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 (102) hide show
  1. package/dist/application/models/api/responseGenerics.d.cts +4 -2
  2. package/dist/application/models/api/responseGenerics.d.ts +4 -2
  3. package/dist/application/models/api/widgetText.d.cts +2 -1
  4. package/dist/application/models/api/widgetText.d.ts +2 -1
  5. package/dist/application/models/index.d.cts +2 -2
  6. package/dist/application/models/index.d.ts +2 -2
  7. package/dist/application/models/validators/validateResponse.cjs +3 -2
  8. package/dist/application/models/validators/validateResponse.js +3 -2
  9. package/dist/application/utils/widgetTextFromApiWidgetTextResponse.cjs +3 -2
  10. package/dist/application/utils/widgetTextFromApiWidgetTextResponse.js +3 -2
  11. package/dist/atoms/app/index.d.cts +7 -7
  12. package/dist/atoms/app/index.d.ts +7 -7
  13. package/dist/atoms/app/variant.cjs +2 -2
  14. package/dist/atoms/app/variant.d.cts +1 -1
  15. package/dist/atoms/app/variant.d.ts +1 -1
  16. package/dist/atoms/app/variant.js +2 -2
  17. package/dist/atoms/chat/chatState.d.ts +19 -19
  18. package/dist/atoms/chat/form.d.cts +2 -2
  19. package/dist/atoms/chat/form.d.ts +2 -2
  20. package/dist/atoms/chat/index.d.cts +3 -3
  21. package/dist/atoms/chat/index.d.ts +3 -3
  22. package/dist/atoms/chat/lastMessage.d.cts +2 -2
  23. package/dist/atoms/chat/lastMessage.d.ts +2 -2
  24. package/dist/atoms/chat/messageQueue.d.cts +6 -6
  25. package/dist/atoms/chat/messageQueue.d.ts +6 -6
  26. package/dist/atoms/chat/performanceMetrics.d.cts +6 -6
  27. package/dist/atoms/chat/performanceMetrics.d.ts +6 -6
  28. package/dist/atoms/chat/renderedWidgetRefs.d.cts +2 -2
  29. package/dist/atoms/chat/renderedWidgetRefs.d.ts +2 -2
  30. package/dist/atoms/chat/replies.d.cts +2 -2
  31. package/dist/atoms/chat/replies.d.ts +2 -2
  32. package/dist/atoms/chat/suggestions.d.cts +2 -2
  33. package/dist/atoms/chat/suggestions.d.ts +2 -2
  34. package/dist/atoms/envive/enviveConfig.d.cts +12 -12
  35. package/dist/atoms/envive/enviveConfig.d.ts +13 -13
  36. package/dist/atoms/globalSearch/globalSearch.d.cts +5 -5
  37. package/dist/atoms/globalSearch/globalSearch.d.ts +5 -5
  38. package/dist/atoms/org/customerService.d.cts +6 -6
  39. package/dist/atoms/org/customerService.d.ts +6 -6
  40. package/dist/atoms/org/graphqlConfig.d.cts +4 -4
  41. package/dist/atoms/org/graphqlConfig.d.ts +4 -4
  42. package/dist/atoms/org/newOrgConfigAtom.d.cts +2 -2
  43. package/dist/atoms/org/newOrgConfigAtom.d.ts +2 -2
  44. package/dist/atoms/org/orgAnalyticsConfig.d.cts +4 -4
  45. package/dist/atoms/org/orgAnalyticsConfig.d.ts +4 -4
  46. package/dist/atoms/search/chatSearch.d.cts +17 -17
  47. package/dist/atoms/search/chatSearch.d.ts +17 -17
  48. package/dist/atoms/search/searchAPI.d.cts +13 -13
  49. package/dist/atoms/search/searchAPI.d.ts +13 -13
  50. package/dist/atoms/search/types.d.ts +1 -1
  51. package/dist/atoms/widget/chatPreviewLoading.d.cts +2 -2
  52. package/dist/atoms/widget/chatPreviewLoading.d.ts +2 -2
  53. package/dist/contexts/pageContext/pageContext.cjs +2 -2
  54. package/dist/contexts/pageContext/pageContext.js +2 -2
  55. package/dist/contexts/salesAgentContext/salesAgentContext.cjs +4 -1
  56. package/dist/contexts/salesAgentContext/salesAgentContext.d.cts +2 -1
  57. package/dist/contexts/salesAgentContext/salesAgentContext.d.ts +2 -1
  58. package/dist/contexts/salesAgentContext/salesAgentContext.js +5 -2
  59. package/dist/contexts/salesAgentContext/salesAgentService.cjs +11 -3
  60. package/dist/contexts/salesAgentContext/salesAgentService.js +12 -4
  61. package/dist/contexts/types.d.cts +1 -1
  62. package/dist/contexts/types.d.ts +1 -1
  63. package/dist/contexts/typesV3.d.cts +1 -1
  64. package/dist/contexts/typesV3.d.ts +1 -1
  65. package/dist/hooks/PageViewedEvent/usePageViewedEvent.cjs +2 -2
  66. package/dist/hooks/PageViewedEvent/usePageViewedEvent.js +2 -2
  67. package/dist/hooks/ShopifyUrlOperations/useShopifyUrlOperations.d.cts +2 -2
  68. package/dist/hooks/ShopifyUrlOperations/useShopifyUrlOperations.d.ts +2 -2
  69. package/dist/hooks/WidgetInteraction/types.cjs +2 -2
  70. package/dist/hooks/WidgetInteraction/types.d.cts +2 -2
  71. package/dist/hooks/WidgetInteraction/types.d.ts +2 -2
  72. package/dist/hooks/WidgetInteraction/types.js +2 -2
  73. package/dist/hooks/WidgetInteraction/utils.cjs +2 -2
  74. package/dist/hooks/WidgetInteraction/utils.js +2 -2
  75. package/dist/hooks/utils.d.cts +1 -1
  76. package/dist/hooks/utils.d.ts +1 -1
  77. package/dist/services/amplitudeService/amplitudeService.cjs +2 -1
  78. package/dist/services/amplitudeService/amplitudeService.js +2 -1
  79. package/dist/services/enviveConfigService/enviveConfigService.cjs +34 -1
  80. package/dist/services/enviveConfigService/enviveConfigService.d.cts +4 -1
  81. package/dist/services/enviveConfigService/enviveConfigService.d.ts +4 -1
  82. package/dist/services/enviveConfigService/enviveConfigService.js +34 -1
  83. package/dist/services/hardcopyService/hardcopyService.cjs +3 -2
  84. package/dist/services/hardcopyService/hardcopyService.js +3 -2
  85. package/package.json +2 -2
  86. package/src/application/models/api/responseGenerics.ts +3 -0
  87. package/src/application/models/api/widgetText.ts +3 -0
  88. package/src/application/models/validators/validateResponse.ts +1 -0
  89. package/src/application/utils/widgetTextFromApiWidgetTextResponse.ts +1 -0
  90. package/src/atoms/app/variant.ts +1 -1
  91. package/src/contexts/pageContext/pageContext.tsx +1 -1
  92. package/src/contexts/salesAgentContext/salesAgentContext.tsx +7 -0
  93. package/src/contexts/salesAgentContext/salesAgentService.ts +12 -3
  94. package/src/hooks/PageViewedEvent/__tests__/usePageViewedEvent.test.ts +4 -4
  95. package/src/hooks/PageViewedEvent/usePageViewedEvent.ts +1 -1
  96. package/src/hooks/WidgetInteraction/types.ts +1 -1
  97. package/src/hooks/WidgetInteraction/utils.ts +1 -1
  98. package/src/services/amplitudeService/amplitudeService.ts +1 -0
  99. package/src/services/enviveConfigService/__tests__/enviveConfigService.test.ts +208 -0
  100. package/src/services/enviveConfigService/enviveConfigService.ts +60 -0
  101. package/src/services/hardcopyService/__tests__/hardcopyService.test.ts +47 -1
  102. package/src/services/hardcopyService/hardcopyService.ts +5 -0
@@ -198,7 +198,8 @@ var HardcopyService = class {
198
198
  widget_type: request.widgetType,
199
199
  response_id: response.responseId,
200
200
  widget_text: response.values,
201
- request_id: widgetTextRequest.requestId
201
+ request_id: widgetTextRequest.requestId,
202
+ ...response.aiSuggestionsAttributionBySlot ? { ai_suggestions_attribution_by_slot: response.aiSuggestionsAttributionBySlot } : {}
202
203
  }
203
204
  });
204
205
  return convertedResponse;
@@ -228,4 +229,4 @@ var MockHardcopyService = class {
228
229
 
229
230
  //#endregion
230
231
  export { HardcopyService, MOCK_HARDCOPY_RESPONSE, MockHardcopyService };
231
- //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaGFyZGNvcHlTZXJ2aWNlLmpzIiwibmFtZXMiOlsiTG9nZ2VyIiwiTU9DS19IQVJEQ09QWV9SRVNQT05TRTogUGFydGlhbDxSZWNvcmQ8V2lkZ2V0VHlwZVYzLCBIYXJkY29weVJlc3BvbnNlPj4iLCJ1dWlkIiwiY29uZmlnOiBIYXJkY29weVNlcnZpY2VDb25maWciLCJ3aWRnZXRUZXh0UmVxdWVzdDogV2lkZ2V0VGV4dFJlcXVlc3QiLCJDb21tZXJjZUFwaUNsaWVudCIsIm92ZXJyaWRlczogUGFydGlhbDxSZWNvcmQ8V2lkZ2V0VHlwZVYzLCBIYXJkY29weVJlc3BvbnNlPj4iXSwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvc2VydmljZXMvaGFyZGNvcHlTZXJ2aWNlL2hhcmRjb3B5U2VydmljZS50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyB2NCBhcyB1dWlkIH0gZnJvbSAndXVpZCc7XG5pbXBvcnQgQ29tbWVyY2VBcGlDbGllbnQgZnJvbSAnc3JjL2FwcGxpY2F0aW9uL2NvbW1lcmNlLWFwaSc7XG5pbXBvcnQgeyBXaWRnZXRTdHJpbmcsIFdpZGdldFRleHQgfSBmcm9tICdzcmMvYXBwbGljYXRpb24vbW9kZWxzL2FwaS93aWRnZXRUZXh0JztcbmltcG9ydCB7IFdpZGdldFRleHRSZXF1ZXN0IH0gZnJvbSAnc3JjL2FwcGxpY2F0aW9uL21vZGVscy9hcGkvd2lkZ2V0VGV4dFJlcXVlc3QnO1xuaW1wb3J0IHsgdG9DYW1lbENhc2UgfSBmcm9tICdzcmMvYXBwbGljYXRpb24vbW9kZWxzL3V0aWxzL3NuYWtlVG9DYW1lbFRyYW5zZm9ybWVyJztcbmltcG9ydCB7IGdldFF1ZXJ5UGFyYW0gfSBmcm9tICdzcmMvYXBwbGljYXRpb24vdXRpbHMnO1xuaW1wb3J0IHsgVXNlckV2ZW50IH0gZnJvbSAnc3JjL2FwcGxpY2F0aW9uL21vZGVscyc7XG5pbXBvcnQgTG9nZ2VyIGZyb20gJ3NyYy9hcHBsaWNhdGlvbi9sb2dnaW5nL2xvZ2dlcic7XG5pbXBvcnQgeyBBcHBEZXRhaWxzIH0gZnJvbSAnc3JjL2F0b21zL2FwcCc7XG5pbXBvcnQgeyBnZXRBdG9tU3RvcmUgfSBmcm9tICdzcmMvYXRvbXMvYXRvbVN0b3JlL2F0b21TdG9yZSc7XG5pbXBvcnQgeyByZXNvbHZlZEJhc2VDb25maWdWZXJzaW9uQXRvbSB9IGZyb20gJ3NyYy9hdG9tcy9lbnZpdmUvcmVzb2x2ZWRCYXNlQ29uZmlnVmVyc2lvbic7XG5pbXBvcnQgeyBXaWRnZXRUeXBlVjMgfSBmcm9tICdzcmMvY29udGV4dHMvdHlwZXNWMyc7XG5pbXBvcnQgeyBFbnZpdmVNZXRyaWNzRXZlbnROYW1lLCBUcmFja0V2ZW50UGFyYW1zIH0gZnJvbSAnLi4vYW1wbGl0dWRlU2VydmljZSc7XG5cbmNvbnN0IGxvZ2dlciA9IG5ldyBMb2dnZXIoJ2hhcmRjb3B5U2VydmljZScpO1xuXG5leHBvcnQgaW50ZXJmYWNlIEhhcmRjb3B5UmVxdWVzdCB7XG4gIHdpZGdldFR5cGU6IFdpZGdldFR5cGVWMztcbiAgdXNlckV2ZW50OiBVc2VyRXZlbnQ7XG59XG5cbmV4cG9ydCB0eXBlIEhhcmRjb3B5UmVzcG9uc2UgPSB7XG4gIHJlc3BvbnNlSWQ6IHN0cmluZztcbiAgbGFuZ3VhZ2U6IHN0cmluZztcbiAgcmF3VmFsdWVzPzogUmVjb3JkPHN0cmluZywgV2lkZ2V0U3RyaW5nIHwgV2lkZ2V0U3RyaW5nW10+O1xuICB2YWx1ZXM6IFJlY29yZDxzdHJpbmcsIHN0cmluZyB8IHN0cmluZ1tdPjtcbn07XG5cbmV4cG9ydCBpbnRlcmZhY2UgSUhhcmRjb3B5U2VydmljZSB7XG4gIGdldEhhcmRjb3B5KHJlcXVlc3Q6IEhhcmRjb3B5UmVxdWVzdCk6IFByb21pc2U8SGFyZGNvcHlSZXNwb25zZT47XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgSGFyZGNvcHlTZXJ2aWNlQ29uZmlnIHtcbiAgZ2V0QXBwRGV0YWlsczogKCkgPT4gQXBwRGV0YWlscztcbiAgZ2V0RmVhdHVyZUZsYWdzOiAoKSA9PiBSZWNvcmQ8c3RyaW5nLCBib29sZWFuPjtcbiAgdHJhY2tFdmVudD86IChwYXJhbXM6IFRyYWNrRXZlbnRQYXJhbXMpID0+IFByb21pc2U8dm9pZD47XG59XG5cbi8vIFNhbXBsZSByZXNwb25zZXMgdXNlZCBib3RoIGFzIGZhbGxiYWNrIHdoZW4gdGhlIGJhY2tlbmQgZmFpbHMgYW5kIGJ5IE1vY2tIYXJkY29weVNlcnZpY2UuXG5leHBvcnQgY29uc3QgTU9DS19IQVJEQ09QWV9SRVNQT05TRTogUGFydGlhbDxSZWNvcmQ8V2lkZ2V0VHlwZVYzLCBIYXJkY29weVJlc3BvbnNlPj4gPSB7XG4gIFtXaWRnZXRUeXBlVjMuUHJvbXB0Q2Fyb3VzZWxWM106IHtcbiAgICByZXNwb25zZUlkOiB1dWlkKCksXG4gICAgbGFuZ3VhZ2U6ICdlbicsXG4gICAgdmFsdWVzOiB7XG4gICAgICBwcm9tcHRCdXR0b25UZXh0czogW1xuICAgICAgICAnV2hhdCBhcmUgeW91ciBiZXN0IHNlbGxlcnM/JyxcbiAgICAgICAgJ1Nob3cgbWUgc3VtbWVyIGRyZXNzZXMnLFxuICAgICAgICAnRG8geW91IGhhdmUgZnJlZSBzaGlwcGluZz8nLFxuICAgICAgICAnV2hhdCBzaXplcyBhcmUgYXZhaWxhYmxlPycsXG4gICAgICAgICdDYW4gSSByZXR1cm4gaXRlbXM/JyxcbiAgICAgIF0sXG4gICAgfSxcbiAgfSxcbiAgW1dpZGdldFR5cGVWMy5UaXRsZWRQcm9tcHRDYXJvdXNlbFYzXToge1xuICAgIHJlc3BvbnNlSWQ6ICdtb2NrLXJlc3BvbnNlLWlkJyxcbiAgICBsYW5ndWFnZTogJ2VuJyxcbiAgICB2YWx1ZXM6IHtcbiAgICAgIHRpdGxlTGFiZWw6ICdOZWVkIHNvbWUgaGVscD8nLFxuICAgICAgcHJvbXB0QnV0dG9uVGV4dHM6IFtcbiAgICAgICAgJ1doYXQgYXJlIHlvdXIgYmVzdCBzZWxsZXJzPycsXG4gICAgICAgICdTaG93IG1lIHN1bW1lciBkcmVzc2VzJyxcbiAgICAgICAgJ0RvIHlvdSBoYXZlIGZyZWUgc2hpcHBpbmc/JyxcbiAgICAgICAgJ1doYXQgc2l6ZXMgYXJlIGF2YWlsYWJsZT8nLFxuICAgICAgICAnQ2FuIEkgcmV0dXJuIGl0ZW1zPycsXG4gICAgICBdLFxuICAgIH0sXG4gIH0sXG4gIFtXaWRnZXRUeXBlVjMuU29jaWFsUHJvb2ZWM106IHtcbiAgICByZXNwb25zZUlkOiAnbW9jay1yZXNwb25zZS1pZCcsXG4gICAgbGFuZ3VhZ2U6ICdlbicsXG4gICAgdmFsdWVzOiB7XG4gICAgICB0aXRsZUxhYmVsOiAnU2hvcHBpbmcgQXNzaXN0YW50JyxcbiAgICAgIG51bWJlck9mQ3VzdG9tZXJzVGV4dDogJzEyMyBjdXN0b21lcnMnLFxuICAgICAgY3VzdG9tZXJRdWVyeVRleHQ6ICdmb3VuZCB3aGF0IHRoZXkgd2VyZSBsb29raW5nIGZvci4uLicsXG4gICAgICBwcmltYXJ5QnV0dG9uVGV4dDogJ1N0YXJ0IHNob3BwaW5nJyxcbiAgICAgIHNlY29uZGFyeUJ1dHRvblRpdGxlVGV4dDogJ1BvcHVsYXIgc2VhcmNoZXMnLFxuICAgICAgc2Vjb25kYXJ5QnV0dG9uVGV4dHM6IFtcbiAgICAgICAgJ1doeSBzaG91bGQgSSBidXkgZnJvbSB5b3U/JyxcbiAgICAgICAgJ0hvdyBkbyBJIHJldHVybiBhbiBpdGVtPycsXG4gICAgICAgICdOZXcgYXJyaXZhbHMnLFxuICAgICAgICAnU2FsZSBpdGVtcycsXG4gICAgICAgICdQb3B1bGFyIGl0ZW1zJyxcbiAgICAgIF0sXG4gICAgICB0ZXh0RmllbGRQbGFjZWhvbGRlclRleHQ6ICdBc2sgbWUgYW55dGhpbmcuLi4nLFxuICAgIH0sXG4gIH0sXG4gIFtXaWRnZXRUeXBlVjMuVHlwaW5nQW5pbWF0aW9uVjNdOiB7XG4gICAgcmVzcG9uc2VJZDogJ21vY2stcmVzcG9uc2UtaWQnLFxuICAgIGxhbmd1YWdlOiAnZW4nLFxuICAgIHZhbHVlczoge1xuICAgICAgdGl0bGVMYWJlbDogJ1Nob3BwaW5nIEFzc2lzdGFudCcsXG4gICAgICBoZWFkbGluZVRleHQ6ICdOZWVkIGhlbHAgZmluZGluZycsXG4gICAgICBhbmltYXRlZFRleHRTZXF1ZW5jZTogW1xuICAgICAgICAndGhlIHBlcmZlY3QgZ2lmdCBmb3IgeW91ciBsb3ZlZCBvbmVzPycsXG4gICAgICAgICdzb21ldGhpbmcgc3BlY2lhbCBmb3IgdGhlIGhvbGlkYXlzPycsXG4gICAgICAgICd0aGUgaWRlYWwgcHJlc2VudCBmb3Igc29tZW9uZSBzcGVjaWFsPycsXG4gICAgICBdLFxuICAgICAgaGludFRleHQ6ICdBc2sgbWUgYW55dGhpbmcnLFxuICAgICAgcHJvbXB0QnV0dG9uVGV4dHM6IFtcbiAgICAgICAgJ1doYXQgYXJlIHlvdXIgYmVzdCBzZWxsZXJzPycsXG4gICAgICAgICdTaG93IG1lIHN1bW1lciBkcmVzc2VzJyxcbiAgICAgICAgJ0RvIHlvdSBoYXZlIGZyZWUgc2hpcHBpbmc/JyxcbiAgICAgICAgJ1doYXQgc2l6ZXMgYXJlIGF2YWlsYWJsZT8nLFxuICAgICAgXSxcbiAgICAgIHRleHRGaWVsZEFyaWFMYWJlbDogJ0FzayBtZSBhbnl0aGluZycsXG4gICAgfSxcbiAgfSxcbiAgW1dpZGdldFR5cGVWMy5DaGF0UHJldmlld0NvbXBhcmlzb25WM106IHtcbiAgICByZXNwb25zZUlkOiAnbW9jay1yZXNwb25zZS1pZCcsXG4gICAgbGFuZ3VhZ2U6ICdlbicsXG4gICAgdmFsdWVzOiB7XG4gICAgICB0aXRsZUxhYmVsOiAnU2hvcHBpbmcgQXNzaXN0YW50JyxcbiAgICAgIGhlYWRsaW5lVGV4dDogJ05lZWQgaGVscCBjb21wYXJpbmc/JyxcbiAgICAgIHRleHRGaWVsZFBsYWNlaG9sZGVyVGV4dDogJ0FzayBtZSBhbnl0aGluZy4uLicsXG4gICAgfSxcbiAgfSxcbiAgW1dpZGdldFR5cGVWMy5DaGF0UHJldmlld0xvYWRpbmdWM106IHtcbiAgICByZXNwb25zZUlkOiAnbW9jay1yZXNwb25zZS1pZCcsXG4gICAgbGFuZ3VhZ2U6ICdlbicsXG4gICAgdmFsdWVzOiB7XG4gICAgICB0aXRsZUxhYmVsOiAnU2hvcHBpbmcgQXNzaXN0YW50JyxcbiAgICAgIHRleHRGaWVsZFBsYWNlaG9sZGVyVGV4dDogJ0FzayBtZSBhbnl0aGluZy4uLicsXG4gICAgfSxcbiAgfSxcbiAgW1dpZGdldFR5cGVWMy5DaGF0UHJldmlld1YzXToge1xuICAgIHJlc3BvbnNlSWQ6ICdtb2NrLXJlc3BvbnNlLWlkJyxcbiAgICBsYW5ndWFnZTogJ2VuJyxcbiAgICB2YWx1ZXM6IHtcbiAgICAgIHRpdGxlTGFiZWw6ICdTaG9wcGluZyBBc3Npc3RhbnQnLFxuICAgICAgdGV4dEZpZWxkUGxhY2Vob2xkZXJUZXh0OiAnQXNrIG1lIGFueXRoaW5nLi4uJyxcbiAgICB9LFxuICB9LFxuICBbV2lkZ2V0VHlwZVYzLlByb21wdEJ1dHRvbkNhcm91c2VsV2l0aEltYWdlVjNdOiB7XG4gICAgcmVzcG9uc2VJZDogJ21vY2stcmVzcG9uc2UtaWQnLFxuICAgIGxhbmd1YWdlOiAnZW4nLFxuICAgIHZhbHVlczoge1xuICAgICAgdGl0bGVMYWJlbDogJ05lZWQgc29tZSBoZWxwPycsXG4gICAgICBwcm9tcHRCdXR0b25zVGV4dHM6IFsnSGVscCBtZSBmaW5kIGEgcHJvZHVjdCcsIFwiV2hhdCdzIG9uIHlvdXIgbWluZD9cIiwgJ1RhbGsgdG8gYSBodW1hbiddLFxuICAgICAgdGV4dEZpZWxkUGxhY2Vob2xkZXJUZXh0OiAnQXNrIG1lIGFueXRoaW5nLi4uJyxcbiAgICB9LFxuICB9LFxuICBbV2lkZ2V0VHlwZVYzLlByb2R1Y3RDYXJkVjNdOiB7XG4gICAgcmVzcG9uc2VJZDogJ21vY2stcmVzcG9uc2UtaWQnLFxuICAgIGxhbmd1YWdlOiAnZW4nLFxuICAgIHZhbHVlczoge1xuICAgICAgaGVhZGxpbmU6ICdEaXNjb3ZlciBZb3VyIFBlcmZlY3QgU3R5bGUnLFxuICAgICAgYW5pbWF0ZWRUZXh0OiBbXG4gICAgICAgICd0aGUgcGVyZmVjdCBvdXRmaXQgZm9yIGFueSBvY2Nhc2lvbicsXG4gICAgICAgICd0cmVuZGluZyBmYXNoaW9uIHRoYXQgZml0cyB5b3VyIGxpZmVzdHlsZScsXG4gICAgICAgICdxdWFsaXR5IHBpZWNlcyB0aGF0IGxhc3QnLFxuICAgICAgXSxcbiAgICAgIHByb21wdHM6IFtcbiAgICAgICAgJ1doYXQgYXJlIHlvdXIgYmVzdCBzZWxsZXJzPycsXG4gICAgICAgICdTaG93IG1lIHN1bW1lciBkcmVzc2VzJyxcbiAgICAgICAgJ0RvIHlvdSBoYXZlIGZyZWUgc2hpcHBpbmc/JyxcbiAgICAgICAgJ1doYXQgc2l6ZXMgYXJlIGF2YWlsYWJsZT8nLFxuICAgICAgICAnQ2FuIEkgcmV0dXJuIGl0ZW1zPycsXG4gICAgICBdLFxuICAgICAgcGxhY2Vob2xkZXI6ICdBc2sgbWUgYW55dGhpbmcuLi4nLFxuICAgIH0sXG4gIH0sXG4gIFtXaWRnZXRUeXBlVjMuRmxvYXRpbmdDaGF0VjNdOiB7XG4gICAgcmVzcG9uc2VJZDogJ21vY2stcmVzcG9uc2UtaWQnLFxuICAgIGxhbmd1YWdlOiAnZW4nLFxuICAgIHZhbHVlczoge1xuICAgICAgd2VsY29tZU1lc3NhZ2VUaXRsZTogJ1dlbGNvbWUgdG8gRW52aXZlIEFJJyxcbiAgICAgIHdlbGNvbWVNZXNzYWdlVGV4dDpcbiAgICAgICAgJ1lvdXIgcGVyc29uYWwgc2hvcHBlciB0cmFpbmVkIG9uIHRoZSBjb2xsZWN0aXZlIGtub3dsZWRnZSBvZiB0aG91c2FuZHMgb2YgcmVhbCBleHBlcnRzIScsXG4gICAgICBjaGF0Rm9vdGVyVGV4dEZpZWxkUGxhY2Vob2xkZXJUZXh0OiAnQXNrIG1lIGFueXRoaW5nLi4uJyxcbiAgICAgIGRpc2NsYWltZXJUZXh0OiAnVGhpcyBpcyBhIGRpc2NsYWltZXIuLi4nLFxuICAgICAgbGVmdFRvZ2dsZUxhYmVsOiAnU2hvcCB3aXRoIEFJJyxcbiAgICAgIHJpZ2h0VG9nZ2xlTGFiZWw6ICdMaXZlIHN1cHBvcnQnLFxuICAgIH0sXG4gIH0sXG4gIFtXaWRnZXRUeXBlVjMuRnVsbFBhZ2VTYWxlc0FnZW50VjNdOiB7XG4gICAgcmVzcG9uc2VJZDogJ21vY2stcmVzcG9uc2UtaWQnLFxuICAgIGxhbmd1YWdlOiAnZW4nLFxuICAgIHZhbHVlczoge1xuICAgICAgd2VsY29tZU1lc3NhZ2VUaXRsZTogJ1dlbGNvbWUgdG8gRW52aXZlIEFJJyxcbiAgICAgIHdlbGNvbWVNZXNzYWdlVGV4dDpcbiAgICAgICAgJ1lvdXIgcGVyc29uYWwgc2hvcHBlciB0cmFpbmVkIG9uIHRoZSBjb2xsZWN0aXZlIGtub3dsZWRnZSBvZiB0aG91c2FuZHMgb2YgcmVhbCBleHBlcnRzIScsXG4gICAgICBjaGF0Rm9vdGVyVGV4dEZpZWxkUGxhY2Vob2xkZXJUZXh0OiAnQXNrIG1lIGFueXRoaW5nLi4uJyxcbiAgICAgIGRpc2NsYWltZXJUZXh0OiAnVGhpcyBpcyBhIGRpc2NsYWltZXIuLi4nLFxuICAgIH0sXG4gIH0sXG59O1xuXG5jb25zdCBjb252ZXJ0VG9IYXJkY29weVJlc3BvbnNlID0gKHJlc3BvbnNlOiBXaWRnZXRUZXh0KTogSGFyZGNvcHlSZXNwb25zZSA9PiAoe1xuICByZXNwb25zZUlkOiByZXNwb25zZS5yZXNwb25zZUlkLFxuICBsYW5ndWFnZTogcmVzcG9uc2UubGFuZ3VhZ2UsXG4gIHJhd1ZhbHVlczogcmVzcG9uc2UudmFsdWVzLFxuICB2YWx1ZXM6IE9iamVjdC5mcm9tRW50cmllcyhcbiAgICBPYmplY3QuZW50cmllcyhyZXNwb25zZS52YWx1ZXMpLm1hcCgoW2tleSwgdmFsdWVdKSA9PiBbXG4gICAgICB0b0NhbWVsQ2FzZShrZXkpLFxuICAgICAgdmFsdWUubGVuZ3RoID09PSAxID8gdmFsdWVbMF0udmFsdWUgOiB2YWx1ZS5tYXAodiA9PiB2LnZhbHVlKSxcbiAgICBdKSxcbiAgKSxcbn0pO1xuXG5leHBvcnQgY2xhc3MgSGFyZGNvcHlTZXJ2aWNlIGltcGxlbWVudHMgSUhhcmRjb3B5U2VydmljZSB7XG4gIGNvbnN0cnVjdG9yKHByaXZhdGUgY29uZmlnOiBIYXJkY29weVNlcnZpY2VDb25maWcpIHt9XG5cbiAgYXN5bmMgZ2V0SGFyZGNvcHkocmVxdWVzdDogSGFyZGNvcHlSZXF1ZXN0KTogUHJvbWlzZTxIYXJkY29weVJlc3BvbnNlPiB7XG4gICAgY29uc3Qgb3ZlcnJpZGVDb25maWdWZXJzaW9uID1cbiAgICAgIGdldFF1ZXJ5UGFyYW0oJ3NwaWZmeV9jb25maWdfdmVyc2lvbicpIHx8XG4gICAgICBnZXRRdWVyeVBhcmFtKCdlbnZpdmVfY29uZmlnX3ZlcnNpb24nKSB8fFxuICAgICAgZ2V0QXRvbVN0b3JlKCkuZ2V0KHJlc29sdmVkQmFzZUNvbmZpZ1ZlcnNpb25BdG9tKSB8fFxuICAgICAgdW5kZWZpbmVkO1xuXG4gICAgY29uc3Qgd2lkZ2V0VGV4dFJlcXVlc3Q6IFdpZGdldFRleHRSZXF1ZXN0ID0ge1xuICAgICAgcmVxdWVzdElkOiB1dWlkKCksXG4gICAgICB3aWRnZXRUeXBlOiByZXF1ZXN0LndpZGdldFR5cGUsXG4gICAgICBjb250ZXh0OiB0aGlzLmNvbmZpZy5nZXRBcHBEZXRhaWxzKCksXG4gICAgICBmZWF0dXJlRmxhZ3M6IHRoaXMuY29uZmlnLmdldEZlYXR1cmVGbGFncygpLFxuICAgICAgbGFuZ3VhZ2U6IG5hdmlnYXRvci5sYW5ndWFnZXNbMF0gfHwgJ2VuJyxcbiAgICAgIG92ZXJyaWRlQ29uZmlnVmVyc2lvbixcbiAgICAgIHVybDogd2luZG93LmxvY2F0aW9uLmhyZWYsXG4gICAgfTtcblxuICAgIHRoaXMuY29uZmlnLnRyYWNrRXZlbnQ/Lih7XG4gICAgICBldmVudE5hbWU6IEVudml2ZU1ldHJpY3NFdmVudE5hbWUuV2lkZ2V0VGV4dFJlcXVlc3QsXG4gICAgICBldmVudFByb3BzOiB7XG4gICAgICAgIHdpZGdldF90eXBlOiByZXF1ZXN0LndpZGdldFR5cGUsXG4gICAgICAgIHJlcXVlc3RfaWQ6IHdpZGdldFRleHRSZXF1ZXN0LnJlcXVlc3RJZCxcbiAgICAgIH0sXG4gICAgfSk7XG5cbiAgICB0cnkge1xuICAgICAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCBDb21tZXJjZUFwaUNsaWVudC5nZXRIYXJkY29weSh3aWRnZXRUZXh0UmVxdWVzdCk7XG4gICAgICBpZiAocmVzcG9uc2UpIHtcbiAgICAgICAgY29uc3QgY29udmVydGVkUmVzcG9uc2UgPSBjb252ZXJ0VG9IYXJkY29weVJlc3BvbnNlKHJlc3BvbnNlKTtcbiAgICAgICAgbG9nZ2VyLmxvZ0RlYnVnKCdjb252ZXJ0ZWQgcmVzcG9uc2UnLCBjb252ZXJ0ZWRSZXNwb25zZSk7XG4gICAgICAgIHRoaXMuY29uZmlnLnRyYWNrRXZlbnQ/Lih7XG4gICAgICAgICAgZXZlbnROYW1lOiBFbnZpdmVNZXRyaWNzRXZlbnROYW1lLldpZGdldFRleHRSZXNwb25zZSxcbiAgICAgICAgICBldmVudFByb3BzOiB7XG4gICAgICAgICAgICB3aWRnZXRfdHlwZTogcmVxdWVzdC53aWRnZXRUeXBlLFxuICAgICAgICAgICAgcmVzcG9uc2VfaWQ6IHJlc3BvbnNlLnJlc3BvbnNlSWQsXG4gICAgICAgICAgICB3aWRnZXRfdGV4dDogcmVzcG9uc2UudmFsdWVzLFxuICAgICAgICAgICAgcmVxdWVzdF9pZDogd2lkZ2V0VGV4dFJlcXVlc3QucmVxdWVzdElkLFxuICAgICAgICAgIH0sXG4gICAgICAgIH0pO1xuICAgICAgICByZXR1cm4gY29udmVydGVkUmVzcG9uc2U7XG4gICAgICB9XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIGxvZ2dlci5sb2dFcnJvcignZXJyb3IgZ2V0dGluZyBoYXJkY29weSBmcm9tIGJhY2tlbmQnLCBlcnJvcik7XG4gICAgfVxuXG4gICAgY29uc3QgbW9ja1Jlc3BvbnNlID0gTU9DS19IQVJEQ09QWV9SRVNQT05TRVtyZXF1ZXN0LndpZGdldFR5cGVdO1xuICAgIGlmIChtb2NrUmVzcG9uc2UpIHtcbiAgICAgIGxvZ2dlci5sb2dEZWJ1Zygnbm8gcmVhbCByZXNwb25zZSwgdXNpbmcgbW9jaycsIG1vY2tSZXNwb25zZSk7XG4gICAgICByZXR1cm4gbW9ja1Jlc3BvbnNlO1xuICAgIH1cbiAgICB0aHJvdyBuZXcgRXJyb3IoYE5vIGhhcmRjb3B5IHJlc3BvbnNlIGZvdW5kIGZvciB3aWRnZXQgdHlwZTogJHtyZXF1ZXN0LndpZGdldFR5cGV9YCk7XG4gIH1cbn1cblxuZXhwb3J0IGNsYXNzIE1vY2tIYXJkY29weVNlcnZpY2UgaW1wbGVtZW50cyBJSGFyZGNvcHlTZXJ2aWNlIHtcbiAgY29uc3RydWN0b3IocHJpdmF0ZSBvdmVycmlkZXM6IFBhcnRpYWw8UmVjb3JkPFdpZGdldFR5cGVWMywgSGFyZGNvcHlSZXNwb25zZT4+ID0ge30pIHt9XG5cbiAgYXN5bmMgZ2V0SGFyZGNvcHkocmVxdWVzdDogSGFyZGNvcHlSZXF1ZXN0KTogUHJvbWlzZTxIYXJkY29weVJlc3BvbnNlPiB7XG4gICAgY29uc3QgZmFsbGJhY2tXaWRnZXRUeXBlID1cbiAgICAgIHJlcXVlc3Qud2lkZ2V0VHlwZSA9PT0gV2lkZ2V0VHlwZVYzLlByb2R1Y3RDYXJkVjNcbiAgICAgICAgPyBXaWRnZXRUeXBlVjMuSW1hZ2VQcm9tcHRDYXJkVjNcbiAgICAgICAgOiByZXF1ZXN0LndpZGdldFR5cGU7XG5cbiAgICBjb25zdCByZXNwb25zZSA9XG4gICAgICB0aGlzLm92ZXJyaWRlc1tyZXF1ZXN0LndpZGdldFR5cGVdID8/XG4gICAgICB0aGlzLm92ZXJyaWRlc1tmYWxsYmFja1dpZGdldFR5cGVdID8/XG4gICAgICBNT0NLX0hBUkRDT1BZX1JFU1BPTlNFW3JlcXVlc3Qud2lkZ2V0VHlwZV07XG5cbiAgICBpZiAoIXJlc3BvbnNlKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYE5vIGhhcmRjb3B5IHJlc3BvbnNlIGZvdW5kIGZvciB3aWRnZXQgdHlwZTogJHtyZXF1ZXN0LndpZGdldFR5cGV9YCk7XG4gICAgfVxuICAgIHJldHVybiByZXNwb25zZTtcbiAgfVxufVxuIl0sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7O0FBY0EsTUFBTSxTQUFTLElBQUlBLGVBQU8sa0JBQWtCO0FBeUI1QyxNQUFhQyx5QkFBMEU7RUFDcEYsYUFBYSxtQkFBbUI7RUFDL0IsWUFBWUMsSUFBTTtFQUNsQixVQUFVO0VBQ1YsUUFB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
232
+ //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaGFyZGNvcHlTZXJ2aWNlLmpzIiwibmFtZXMiOlsiTG9nZ2VyIiwiTU9DS19IQVJEQ09QWV9SRVNQT05TRTogUGFydGlhbDxSZWNvcmQ8V2lkZ2V0VHlwZVYzLCBIYXJkY29weVJlc3BvbnNlPj4iLCJ1dWlkIiwiY29uZmlnOiBIYXJkY29weVNlcnZpY2VDb25maWciLCJ3aWRnZXRUZXh0UmVxdWVzdDogV2lkZ2V0VGV4dFJlcXVlc3QiLCJDb21tZXJjZUFwaUNsaWVudCIsIm92ZXJyaWRlczogUGFydGlhbDxSZWNvcmQ8V2lkZ2V0VHlwZVYzLCBIYXJkY29weVJlc3BvbnNlPj4iXSwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvc2VydmljZXMvaGFyZGNvcHlTZXJ2aWNlL2hhcmRjb3B5U2VydmljZS50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyB2NCBhcyB1dWlkIH0gZnJvbSAndXVpZCc7XG5pbXBvcnQgQ29tbWVyY2VBcGlDbGllbnQgZnJvbSAnc3JjL2FwcGxpY2F0aW9uL2NvbW1lcmNlLWFwaSc7XG5pbXBvcnQgeyBXaWRnZXRTdHJpbmcsIFdpZGdldFRleHQgfSBmcm9tICdzcmMvYXBwbGljYXRpb24vbW9kZWxzL2FwaS93aWRnZXRUZXh0JztcbmltcG9ydCB7IFdpZGdldFRleHRSZXF1ZXN0IH0gZnJvbSAnc3JjL2FwcGxpY2F0aW9uL21vZGVscy9hcGkvd2lkZ2V0VGV4dFJlcXVlc3QnO1xuaW1wb3J0IHsgdG9DYW1lbENhc2UgfSBmcm9tICdzcmMvYXBwbGljYXRpb24vbW9kZWxzL3V0aWxzL3NuYWtlVG9DYW1lbFRyYW5zZm9ybWVyJztcbmltcG9ydCB7IGdldFF1ZXJ5UGFyYW0gfSBmcm9tICdzcmMvYXBwbGljYXRpb24vdXRpbHMnO1xuaW1wb3J0IHsgVXNlckV2ZW50IH0gZnJvbSAnc3JjL2FwcGxpY2F0aW9uL21vZGVscyc7XG5pbXBvcnQgTG9nZ2VyIGZyb20gJ3NyYy9hcHBsaWNhdGlvbi9sb2dnaW5nL2xvZ2dlcic7XG5pbXBvcnQgeyBBcHBEZXRhaWxzIH0gZnJvbSAnc3JjL2F0b21zL2FwcCc7XG5pbXBvcnQgeyBnZXRBdG9tU3RvcmUgfSBmcm9tICdzcmMvYXRvbXMvYXRvbVN0b3JlL2F0b21TdG9yZSc7XG5pbXBvcnQgeyByZXNvbHZlZEJhc2VDb25maWdWZXJzaW9uQXRvbSB9IGZyb20gJ3NyYy9hdG9tcy9lbnZpdmUvcmVzb2x2ZWRCYXNlQ29uZmlnVmVyc2lvbic7XG5pbXBvcnQgeyBXaWRnZXRUeXBlVjMgfSBmcm9tICdzcmMvY29udGV4dHMvdHlwZXNWMyc7XG5pbXBvcnQgeyBFbnZpdmVNZXRyaWNzRXZlbnROYW1lLCBUcmFja0V2ZW50UGFyYW1zIH0gZnJvbSAnLi4vYW1wbGl0dWRlU2VydmljZSc7XG5cbmNvbnN0IGxvZ2dlciA9IG5ldyBMb2dnZXIoJ2hhcmRjb3B5U2VydmljZScpO1xuXG5leHBvcnQgaW50ZXJmYWNlIEhhcmRjb3B5UmVxdWVzdCB7XG4gIHdpZGdldFR5cGU6IFdpZGdldFR5cGVWMztcbiAgdXNlckV2ZW50OiBVc2VyRXZlbnQ7XG59XG5cbmV4cG9ydCB0eXBlIEhhcmRjb3B5UmVzcG9uc2UgPSB7XG4gIHJlc3BvbnNlSWQ6IHN0cmluZztcbiAgbGFuZ3VhZ2U6IHN0cmluZztcbiAgcmF3VmFsdWVzPzogUmVjb3JkPHN0cmluZywgV2lkZ2V0U3RyaW5nIHwgV2lkZ2V0U3RyaW5nW10+O1xuICB2YWx1ZXM6IFJlY29yZDxzdHJpbmcsIHN0cmluZyB8IHN0cmluZ1tdPjtcbn07XG5cbmV4cG9ydCBpbnRlcmZhY2UgSUhhcmRjb3B5U2VydmljZSB7XG4gIGdldEhhcmRjb3B5KHJlcXVlc3Q6IEhhcmRjb3B5UmVxdWVzdCk6IFByb21pc2U8SGFyZGNvcHlSZXNwb25zZT47XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgSGFyZGNvcHlTZXJ2aWNlQ29uZmlnIHtcbiAgZ2V0QXBwRGV0YWlsczogKCkgPT4gQXBwRGV0YWlscztcbiAgZ2V0RmVhdHVyZUZsYWdzOiAoKSA9PiBSZWNvcmQ8c3RyaW5nLCBib29sZWFuPjtcbiAgdHJhY2tFdmVudD86IChwYXJhbXM6IFRyYWNrRXZlbnRQYXJhbXMpID0+IFByb21pc2U8dm9pZD47XG59XG5cbi8vIFNhbXBsZSByZXNwb25zZXMgdXNlZCBib3RoIGFzIGZhbGxiYWNrIHdoZW4gdGhlIGJhY2tlbmQgZmFpbHMgYW5kIGJ5IE1vY2tIYXJkY29weVNlcnZpY2UuXG5leHBvcnQgY29uc3QgTU9DS19IQVJEQ09QWV9SRVNQT05TRTogUGFydGlhbDxSZWNvcmQ8V2lkZ2V0VHlwZVYzLCBIYXJkY29weVJlc3BvbnNlPj4gPSB7XG4gIFtXaWRnZXRUeXBlVjMuUHJvbXB0Q2Fyb3VzZWxWM106IHtcbiAgICByZXNwb25zZUlkOiB1dWlkKCksXG4gICAgbGFuZ3VhZ2U6ICdlbicsXG4gICAgdmFsdWVzOiB7XG4gICAgICBwcm9tcHRCdXR0b25UZXh0czogW1xuICAgICAgICAnV2hhdCBhcmUgeW91ciBiZXN0IHNlbGxlcnM/JyxcbiAgICAgICAgJ1Nob3cgbWUgc3VtbWVyIGRyZXNzZXMnLFxuICAgICAgICAnRG8geW91IGhhdmUgZnJlZSBzaGlwcGluZz8nLFxuICAgICAgICAnV2hhdCBzaXplcyBhcmUgYXZhaWxhYmxlPycsXG4gICAgICAgICdDYW4gSSByZXR1cm4gaXRlbXM/JyxcbiAgICAgIF0sXG4gICAgfSxcbiAgfSxcbiAgW1dpZGdldFR5cGVWMy5UaXRsZWRQcm9tcHRDYXJvdXNlbFYzXToge1xuICAgIHJlc3BvbnNlSWQ6ICdtb2NrLXJlc3BvbnNlLWlkJyxcbiAgICBsYW5ndWFnZTogJ2VuJyxcbiAgICB2YWx1ZXM6IHtcbiAgICAgIHRpdGxlTGFiZWw6ICdOZWVkIHNvbWUgaGVscD8nLFxuICAgICAgcHJvbXB0QnV0dG9uVGV4dHM6IFtcbiAgICAgICAgJ1doYXQgYXJlIHlvdXIgYmVzdCBzZWxsZXJzPycsXG4gICAgICAgICdTaG93IG1lIHN1bW1lciBkcmVzc2VzJyxcbiAgICAgICAgJ0RvIHlvdSBoYXZlIGZyZWUgc2hpcHBpbmc/JyxcbiAgICAgICAgJ1doYXQgc2l6ZXMgYXJlIGF2YWlsYWJsZT8nLFxuICAgICAgICAnQ2FuIEkgcmV0dXJuIGl0ZW1zPycsXG4gICAgICBdLFxuICAgIH0sXG4gIH0sXG4gIFtXaWRnZXRUeXBlVjMuU29jaWFsUHJvb2ZWM106IHtcbiAgICByZXNwb25zZUlkOiAnbW9jay1yZXNwb25zZS1pZCcsXG4gICAgbGFuZ3VhZ2U6ICdlbicsXG4gICAgdmFsdWVzOiB7XG4gICAgICB0aXRsZUxhYmVsOiAnU2hvcHBpbmcgQXNzaXN0YW50JyxcbiAgICAgIG51bWJlck9mQ3VzdG9tZXJzVGV4dDogJzEyMyBjdXN0b21lcnMnLFxuICAgICAgY3VzdG9tZXJRdWVyeVRleHQ6ICdmb3VuZCB3aGF0IHRoZXkgd2VyZSBsb29raW5nIGZvci4uLicsXG4gICAgICBwcmltYXJ5QnV0dG9uVGV4dDogJ1N0YXJ0IHNob3BwaW5nJyxcbiAgICAgIHNlY29uZGFyeUJ1dHRvblRpdGxlVGV4dDogJ1BvcHVsYXIgc2VhcmNoZXMnLFxuICAgICAgc2Vjb25kYXJ5QnV0dG9uVGV4dHM6IFtcbiAgICAgICAgJ1doeSBzaG91bGQgSSBidXkgZnJvbSB5b3U/JyxcbiAgICAgICAgJ0hvdyBkbyBJIHJldHVybiBhbiBpdGVtPycsXG4gICAgICAgICdOZXcgYXJyaXZhbHMnLFxuICAgICAgICAnU2FsZSBpdGVtcycsXG4gICAgICAgICdQb3B1bGFyIGl0ZW1zJyxcbiAgICAgIF0sXG4gICAgICB0ZXh0RmllbGRQbGFjZWhvbGRlclRleHQ6ICdBc2sgbWUgYW55dGhpbmcuLi4nLFxuICAgIH0sXG4gIH0sXG4gIFtXaWRnZXRUeXBlVjMuVHlwaW5nQW5pbWF0aW9uVjNdOiB7XG4gICAgcmVzcG9uc2VJZDogJ21vY2stcmVzcG9uc2UtaWQnLFxuICAgIGxhbmd1YWdlOiAnZW4nLFxuICAgIHZhbHVlczoge1xuICAgICAgdGl0bGVMYWJlbDogJ1Nob3BwaW5nIEFzc2lzdGFudCcsXG4gICAgICBoZWFkbGluZVRleHQ6ICdOZWVkIGhlbHAgZmluZGluZycsXG4gICAgICBhbmltYXRlZFRleHRTZXF1ZW5jZTogW1xuICAgICAgICAndGhlIHBlcmZlY3QgZ2lmdCBmb3IgeW91ciBsb3ZlZCBvbmVzPycsXG4gICAgICAgICdzb21ldGhpbmcgc3BlY2lhbCBmb3IgdGhlIGhvbGlkYXlzPycsXG4gICAgICAgICd0aGUgaWRlYWwgcHJlc2VudCBmb3Igc29tZW9uZSBzcGVjaWFsPycsXG4gICAgICBdLFxuICAgICAgaGludFRleHQ6ICdBc2sgbWUgYW55dGhpbmcnLFxuICAgICAgcHJvbXB0QnV0dG9uVGV4dHM6IFtcbiAgICAgICAgJ1doYXQgYXJlIHlvdXIgYmVzdCBzZWxsZXJzPycsXG4gICAgICAgICdTaG93IG1lIHN1bW1lciBkcmVzc2VzJyxcbiAgICAgICAgJ0RvIHlvdSBoYXZlIGZyZWUgc2hpcHBpbmc/JyxcbiAgICAgICAgJ1doYXQgc2l6ZXMgYXJlIGF2YWlsYWJsZT8nLFxuICAgICAgXSxcbiAgICAgIHRleHRGaWVsZEFyaWFMYWJlbDogJ0FzayBtZSBhbnl0aGluZycsXG4gICAgfSxcbiAgfSxcbiAgW1dpZGdldFR5cGVWMy5DaGF0UHJldmlld0NvbXBhcmlzb25WM106IHtcbiAgICByZXNwb25zZUlkOiAnbW9jay1yZXNwb25zZS1pZCcsXG4gICAgbGFuZ3VhZ2U6ICdlbicsXG4gICAgdmFsdWVzOiB7XG4gICAgICB0aXRsZUxhYmVsOiAnU2hvcHBpbmcgQXNzaXN0YW50JyxcbiAgICAgIGhlYWRsaW5lVGV4dDogJ05lZWQgaGVscCBjb21wYXJpbmc/JyxcbiAgICAgIHRleHRGaWVsZFBsYWNlaG9sZGVyVGV4dDogJ0FzayBtZSBhbnl0aGluZy4uLicsXG4gICAgfSxcbiAgfSxcbiAgW1dpZGdldFR5cGVWMy5DaGF0UHJldmlld0xvYWRpbmdWM106IHtcbiAgICByZXNwb25zZUlkOiAnbW9jay1yZXNwb25zZS1pZCcsXG4gICAgbGFuZ3VhZ2U6ICdlbicsXG4gICAgdmFsdWVzOiB7XG4gICAgICB0aXRsZUxhYmVsOiAnU2hvcHBpbmcgQXNzaXN0YW50JyxcbiAgICAgIHRleHRGaWVsZFBsYWNlaG9sZGVyVGV4dDogJ0FzayBtZSBhbnl0aGluZy4uLicsXG4gICAgfSxcbiAgfSxcbiAgW1dpZGdldFR5cGVWMy5DaGF0UHJldmlld1YzXToge1xuICAgIHJlc3BvbnNlSWQ6ICdtb2NrLXJlc3BvbnNlLWlkJyxcbiAgICBsYW5ndWFnZTogJ2VuJyxcbiAgICB2YWx1ZXM6IHtcbiAgICAgIHRpdGxlTGFiZWw6ICdTaG9wcGluZyBBc3Npc3RhbnQnLFxuICAgICAgdGV4dEZpZWxkUGxhY2Vob2xkZXJUZXh0OiAnQXNrIG1lIGFueXRoaW5nLi4uJyxcbiAgICB9LFxuICB9LFxuICBbV2lkZ2V0VHlwZVYzLlByb21wdEJ1dHRvbkNhcm91c2VsV2l0aEltYWdlVjNdOiB7XG4gICAgcmVzcG9uc2VJZDogJ21vY2stcmVzcG9uc2UtaWQnLFxuICAgIGxhbmd1YWdlOiAnZW4nLFxuICAgIHZhbHVlczoge1xuICAgICAgdGl0bGVMYWJlbDogJ05lZWQgc29tZSBoZWxwPycsXG4gICAgICBwcm9tcHRCdXR0b25zVGV4dHM6IFsnSGVscCBtZSBmaW5kIGEgcHJvZHVjdCcsIFwiV2hhdCdzIG9uIHlvdXIgbWluZD9cIiwgJ1RhbGsgdG8gYSBodW1hbiddLFxuICAgICAgdGV4dEZpZWxkUGxhY2Vob2xkZXJUZXh0OiAnQXNrIG1lIGFueXRoaW5nLi4uJyxcbiAgICB9LFxuICB9LFxuICBbV2lkZ2V0VHlwZVYzLlByb2R1Y3RDYXJkVjNdOiB7XG4gICAgcmVzcG9uc2VJZDogJ21vY2stcmVzcG9uc2UtaWQnLFxuICAgIGxhbmd1YWdlOiAnZW4nLFxuICAgIHZhbHVlczoge1xuICAgICAgaGVhZGxpbmU6ICdEaXNjb3ZlciBZb3VyIFBlcmZlY3QgU3R5bGUnLFxuICAgICAgYW5pbWF0ZWRUZXh0OiBbXG4gICAgICAgICd0aGUgcGVyZmVjdCBvdXRmaXQgZm9yIGFueSBvY2Nhc2lvbicsXG4gICAgICAgICd0cmVuZGluZyBmYXNoaW9uIHRoYXQgZml0cyB5b3VyIGxpZmVzdHlsZScsXG4gICAgICAgICdxdWFsaXR5IHBpZWNlcyB0aGF0IGxhc3QnLFxuICAgICAgXSxcbiAgICAgIHByb21wdHM6IFtcbiAgICAgICAgJ1doYXQgYXJlIHlvdXIgYmVzdCBzZWxsZXJzPycsXG4gICAgICAgICdTaG93IG1lIHN1bW1lciBkcmVzc2VzJyxcbiAgICAgICAgJ0RvIHlvdSBoYXZlIGZyZWUgc2hpcHBpbmc/JyxcbiAgICAgICAgJ1doYXQgc2l6ZXMgYXJlIGF2YWlsYWJsZT8nLFxuICAgICAgICAnQ2FuIEkgcmV0dXJuIGl0ZW1zPycsXG4gICAgICBdLFxuICAgICAgcGxhY2Vob2xkZXI6ICdBc2sgbWUgYW55dGhpbmcuLi4nLFxuICAgIH0sXG4gIH0sXG4gIFtXaWRnZXRUeXBlVjMuRmxvYXRpbmdDaGF0VjNdOiB7XG4gICAgcmVzcG9uc2VJZDogJ21vY2stcmVzcG9uc2UtaWQnLFxuICAgIGxhbmd1YWdlOiAnZW4nLFxuICAgIHZhbHVlczoge1xuICAgICAgd2VsY29tZU1lc3NhZ2VUaXRsZTogJ1dlbGNvbWUgdG8gRW52aXZlIEFJJyxcbiAgICAgIHdlbGNvbWVNZXNzYWdlVGV4dDpcbiAgICAgICAgJ1lvdXIgcGVyc29uYWwgc2hvcHBlciB0cmFpbmVkIG9uIHRoZSBjb2xsZWN0aXZlIGtub3dsZWRnZSBvZiB0aG91c2FuZHMgb2YgcmVhbCBleHBlcnRzIScsXG4gICAgICBjaGF0Rm9vdGVyVGV4dEZpZWxkUGxhY2Vob2xkZXJUZXh0OiAnQXNrIG1lIGFueXRoaW5nLi4uJyxcbiAgICAgIGRpc2NsYWltZXJUZXh0OiAnVGhpcyBpcyBhIGRpc2NsYWltZXIuLi4nLFxuICAgICAgbGVmdFRvZ2dsZUxhYmVsOiAnU2hvcCB3aXRoIEFJJyxcbiAgICAgIHJpZ2h0VG9nZ2xlTGFiZWw6ICdMaXZlIHN1cHBvcnQnLFxuICAgIH0sXG4gIH0sXG4gIFtXaWRnZXRUeXBlVjMuRnVsbFBhZ2VTYWxlc0FnZW50VjNdOiB7XG4gICAgcmVzcG9uc2VJZDogJ21vY2stcmVzcG9uc2UtaWQnLFxuICAgIGxhbmd1YWdlOiAnZW4nLFxuICAgIHZhbHVlczoge1xuICAgICAgd2VsY29tZU1lc3NhZ2VUaXRsZTogJ1dlbGNvbWUgdG8gRW52aXZlIEFJJyxcbiAgICAgIHdlbGNvbWVNZXNzYWdlVGV4dDpcbiAgICAgICAgJ1lvdXIgcGVyc29uYWwgc2hvcHBlciB0cmFpbmVkIG9uIHRoZSBjb2xsZWN0aXZlIGtub3dsZWRnZSBvZiB0aG91c2FuZHMgb2YgcmVhbCBleHBlcnRzIScsXG4gICAgICBjaGF0Rm9vdGVyVGV4dEZpZWxkUGxhY2Vob2xkZXJUZXh0OiAnQXNrIG1lIGFueXRoaW5nLi4uJyxcbiAgICAgIGRpc2NsYWltZXJUZXh0OiAnVGhpcyBpcyBhIGRpc2NsYWltZXIuLi4nLFxuICAgIH0sXG4gIH0sXG59O1xuXG5jb25zdCBjb252ZXJ0VG9IYXJkY29weVJlc3BvbnNlID0gKHJlc3BvbnNlOiBXaWRnZXRUZXh0KTogSGFyZGNvcHlSZXNwb25zZSA9PiAoe1xuICByZXNwb25zZUlkOiByZXNwb25zZS5yZXNwb25zZUlkLFxuICBsYW5ndWFnZTogcmVzcG9uc2UubGFuZ3VhZ2UsXG4gIHJhd1ZhbHVlczogcmVzcG9uc2UudmFsdWVzLFxuICB2YWx1ZXM6IE9iamVjdC5mcm9tRW50cmllcyhcbiAgICBPYmplY3QuZW50cmllcyhyZXNwb25zZS52YWx1ZXMpLm1hcCgoW2tleSwgdmFsdWVdKSA9PiBbXG4gICAgICB0b0NhbWVsQ2FzZShrZXkpLFxuICAgICAgdmFsdWUubGVuZ3RoID09PSAxID8gdmFsdWVbMF0udmFsdWUgOiB2YWx1ZS5tYXAodiA9PiB2LnZhbHVlKSxcbiAgICBdKSxcbiAgKSxcbn0pO1xuXG5leHBvcnQgY2xhc3MgSGFyZGNvcHlTZXJ2aWNlIGltcGxlbWVudHMgSUhhcmRjb3B5U2VydmljZSB7XG4gIGNvbnN0cnVjdG9yKHByaXZhdGUgY29uZmlnOiBIYXJkY29weVNlcnZpY2VDb25maWcpIHt9XG5cbiAgYXN5bmMgZ2V0SGFyZGNvcHkocmVxdWVzdDogSGFyZGNvcHlSZXF1ZXN0KTogUHJvbWlzZTxIYXJkY29weVJlc3BvbnNlPiB7XG4gICAgY29uc3Qgb3ZlcnJpZGVDb25maWdWZXJzaW9uID1cbiAgICAgIGdldFF1ZXJ5UGFyYW0oJ3NwaWZmeV9jb25maWdfdmVyc2lvbicpIHx8XG4gICAgICBnZXRRdWVyeVBhcmFtKCdlbnZpdmVfY29uZmlnX3ZlcnNpb24nKSB8fFxuICAgICAgZ2V0QXRvbVN0b3JlKCkuZ2V0KHJlc29sdmVkQmFzZUNvbmZpZ1ZlcnNpb25BdG9tKSB8fFxuICAgICAgdW5kZWZpbmVkO1xuXG4gICAgY29uc3Qgd2lkZ2V0VGV4dFJlcXVlc3Q6IFdpZGdldFRleHRSZXF1ZXN0ID0ge1xuICAgICAgcmVxdWVzdElkOiB1dWlkKCksXG4gICAgICB3aWRnZXRUeXBlOiByZXF1ZXN0LndpZGdldFR5cGUsXG4gICAgICBjb250ZXh0OiB0aGlzLmNvbmZpZy5nZXRBcHBEZXRhaWxzKCksXG4gICAgICBmZWF0dXJlRmxhZ3M6IHRoaXMuY29uZmlnLmdldEZlYXR1cmVGbGFncygpLFxuICAgICAgbGFuZ3VhZ2U6IG5hdmlnYXRvci5sYW5ndWFnZXNbMF0gfHwgJ2VuJyxcbiAgICAgIG92ZXJyaWRlQ29uZmlnVmVyc2lvbixcbiAgICAgIHVybDogd2luZG93LmxvY2F0aW9uLmhyZWYsXG4gICAgfTtcblxuICAgIHRoaXMuY29uZmlnLnRyYWNrRXZlbnQ/Lih7XG4gICAgICBldmVudE5hbWU6IEVudml2ZU1ldHJpY3NFdmVudE5hbWUuV2lkZ2V0VGV4dFJlcXVlc3QsXG4gICAgICBldmVudFByb3BzOiB7XG4gICAgICAgIHdpZGdldF90eXBlOiByZXF1ZXN0LndpZGdldFR5cGUsXG4gICAgICAgIHJlcXVlc3RfaWQ6IHdpZGdldFRleHRSZXF1ZXN0LnJlcXVlc3RJZCxcbiAgICAgIH0sXG4gICAgfSk7XG5cbiAgICB0cnkge1xuICAgICAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCBDb21tZXJjZUFwaUNsaWVudC5nZXRIYXJkY29weSh3aWRnZXRUZXh0UmVxdWVzdCk7XG4gICAgICBpZiAocmVzcG9uc2UpIHtcbiAgICAgICAgY29uc3QgY29udmVydGVkUmVzcG9uc2UgPSBjb252ZXJ0VG9IYXJkY29weVJlc3BvbnNlKHJlc3BvbnNlKTtcbiAgICAgICAgbG9nZ2VyLmxvZ0RlYnVnKCdjb252ZXJ0ZWQgcmVzcG9uc2UnLCBjb252ZXJ0ZWRSZXNwb25zZSk7XG4gICAgICAgIHRoaXMuY29uZmlnLnRyYWNrRXZlbnQ/Lih7XG4gICAgICAgICAgZXZlbnROYW1lOiBFbnZpdmVNZXRyaWNzRXZlbnROYW1lLldpZGdldFRleHRSZXNwb25zZSxcbiAgICAgICAgICBldmVudFByb3BzOiB7XG4gICAgICAgICAgICB3aWRnZXRfdHlwZTogcmVxdWVzdC53aWRnZXRUeXBlLFxuICAgICAgICAgICAgcmVzcG9uc2VfaWQ6IHJlc3BvbnNlLnJlc3BvbnNlSWQsXG4gICAgICAgICAgICB3aWRnZXRfdGV4dDogcmVzcG9uc2UudmFsdWVzLFxuICAgICAgICAgICAgcmVxdWVzdF9pZDogd2lkZ2V0VGV4dFJlcXVlc3QucmVxdWVzdElkLFxuICAgICAgICAgICAgLy8gV2hpY2ggbWV0aG9kIHNlcnZlZCBlYWNoIG92ZXJyaWRkZW4gc2xvdCDigJQgdHJhaW5pbmcvYXR0cmlidXRpb25cbiAgICAgICAgICAgIC8vIHJlYWRzIHRoaXMgZnJvbSB0aGUgYW5hbHl0aWNzIGV2ZW50OyBwYXNzZWQgdGhyb3VnaCB2ZXJiYXRpbS5cbiAgICAgICAgICAgIC4uLihyZXNwb25zZS5haVN1Z2dlc3Rpb25zQXR0cmlidXRpb25CeVNsb3RcbiAgICAgICAgICAgICAgPyB7IGFpX3N1Z2dlc3Rpb25zX2F0dHJpYnV0aW9uX2J5X3Nsb3Q6IHJlc3BvbnNlLmFpU3VnZ2VzdGlvbnNBdHRyaWJ1dGlvbkJ5U2xvdCB9XG4gICAgICAgICAgICAgIDoge30pLFxuICAgICAgICAgIH0sXG4gICAgICAgIH0pO1xuICAgICAgICByZXR1cm4gY29udmVydGVkUmVzcG9uc2U7XG4gICAgICB9XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIGxvZ2dlci5sb2dFcnJvcignZXJyb3IgZ2V0dGluZyBoYXJkY29weSBmcm9tIGJhY2tlbmQnLCBlcnJvcik7XG4gICAgfVxuXG4gICAgY29uc3QgbW9ja1Jlc3BvbnNlID0gTU9DS19IQVJEQ09QWV9SRVNQT05TRVtyZXF1ZXN0LndpZGdldFR5cGVdO1xuICAgIGlmIChtb2NrUmVzcG9uc2UpIHtcbiAgICAgIGxvZ2dlci5sb2dEZWJ1Zygnbm8gcmVhbCByZXNwb25zZSwgdXNpbmcgbW9jaycsIG1vY2tSZXNwb25zZSk7XG4gICAgICByZXR1cm4gbW9ja1Jlc3BvbnNlO1xuICAgIH1cbiAgICB0aHJvdyBuZXcgRXJyb3IoYE5vIGhhcmRjb3B5IHJlc3BvbnNlIGZvdW5kIGZvciB3aWRnZXQgdHlwZTogJHtyZXF1ZXN0LndpZGdldFR5cGV9YCk7XG4gIH1cbn1cblxuZXhwb3J0IGNsYXNzIE1vY2tIYXJkY29weVNlcnZpY2UgaW1wbGVtZW50cyBJSGFyZGNvcHlTZXJ2aWNlIHtcbiAgY29uc3RydWN0b3IocHJpdmF0ZSBvdmVycmlkZXM6IFBhcnRpYWw8UmVjb3JkPFdpZGdldFR5cGVWMywgSGFyZGNvcHlSZXNwb25zZT4+ID0ge30pIHt9XG5cbiAgYXN5bmMgZ2V0SGFyZGNvcHkocmVxdWVzdDogSGFyZGNvcHlSZXF1ZXN0KTogUHJvbWlzZTxIYXJkY29weVJlc3BvbnNlPiB7XG4gICAgY29uc3QgZmFsbGJhY2tXaWRnZXRUeXBlID1cbiAgICAgIHJlcXVlc3Qud2lkZ2V0VHlwZSA9PT0gV2lkZ2V0VHlwZVYzLlByb2R1Y3RDYXJkVjNcbiAgICAgICAgPyBXaWRnZXRUeXBlVjMuSW1hZ2VQcm9tcHRDYXJkVjNcbiAgICAgICAgOiByZXF1ZXN0LndpZGdldFR5cGU7XG5cbiAgICBjb25zdCByZXNwb25zZSA9XG4gICAgICB0aGlzLm92ZXJyaWRlc1tyZXF1ZXN0LndpZGdldFR5cGVdID8/XG4gICAgICB0aGlzLm92ZXJyaWRlc1tmYWxsYmFja1dpZGdldFR5cGVdID8/XG4gICAgICBNT0NLX0hBUkRDT1BZX1JFU1BPTlNFW3JlcXVlc3Qud2lkZ2V0VHlwZV07XG5cbiAgICBpZiAoIXJlc3BvbnNlKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYE5vIGhhcmRjb3B5IHJlc3BvbnNlIGZvdW5kIGZvciB3aWRnZXQgdHlwZTogJHtyZXF1ZXN0LndpZGdldFR5cGV9YCk7XG4gICAgfVxuICAgIHJldHVybiByZXNwb25zZTtcbiAgfVxufVxuIl0sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7O0FBY0EsTUFBTSxTQUFTLElBQUlBLGVBQU8sa0JBQWtCO0FBeUI1QyxNQUFhQyx5QkFBMEU7RUFDcEYsYUFBYSxtQkFBbUI7RUFDL0IsWUFBWUMsSUFBTTtFQUNsQixVQUFVO0VBQ1YsUUFBUSxFQUNOLG1CQUFtQjtHQUNqQjtHQUNBO0dBQ0E7R0FDQTtHQUNBO0dBQ0QsRUFDRjtFQUNGO0VBQ0EsYUFBYSx5QkFBeUI7RUFDckMsWUFBWTtFQUNaLFVBQVU7RUFDVixRQUFRO0dBQ04sWUFBWTtHQUNaLG1CQUFtQjtJQUNqQjtJQUNBO0lBQ0E7SUFDQTtJQUNBO0lBQ0Q7R0FDRjtFQUNGO0VBQ0EsYUFBYSxnQkFBZ0I7RUFDNUIsWUFBWTtFQUNaLFVBQVU7RUFDVixRQUFRO0dBQ04sWUFBWTtHQUNaLHVCQUF1QjtHQUN2QixtQkFBbUI7R0FDbkIsbUJBQW1CO0dBQ25CLDBCQUEwQjtHQUMxQixzQkFBc0I7SUFDcEI7SUFDQTtJQUNBO0lBQ0E7SUFDQTtJQUNEO0dBQ0QsMEJBQTBCO0dBQzNCO0VBQ0Y7RUFDQSxhQUFhLG9CQUFvQjtFQUNoQyxZQUFZO0VBQ1osVUFBVTtFQUNWLFFBQVE7R0FDTixZQUFZO0dBQ1osY0FBYztHQUNkLHNCQUFzQjtJQUNwQjtJQUNBO0lBQ0E7SUFDRDtHQUNELFVBQVU7R0FDVixtQkFBbUI7SUFDakI7SUFDQTtJQUNBO0lBQ0E7SUFDRDtHQUNELG9CQUFvQjtHQUNyQjtFQUNGO0VBQ0EsYUFBYSwwQkFBMEI7RUFDdEMsWUFBWTtFQUNaLFVBQVU7RUFDVixRQUFRO0dB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
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@envive-ai/react-hooks",
3
- "version": "0.3.44",
3
+ "version": "0.3.46",
4
4
  "description": "React hooks for connecting to Envive AI services.",
5
5
  "keywords": [
6
6
  "react",
@@ -38,7 +38,7 @@
38
38
  },
39
39
  "dependencies": {
40
40
  "@amplitude/analytics-browser": "2.23.7",
41
- "@spiffy-ai/commerce-api-client": "1.1.0-SNAPSHOT.202603181358",
41
+ "@spiffy-ai/commerce-api-client": "1.1.0-SNAPSHOT.202607020921",
42
42
  "@envive-ai/analytics": "1.0.28",
43
43
  "fuse.js": "^7.1.0",
44
44
  "jotai": "^2.14.0",
@@ -43,11 +43,14 @@ export interface ApiReviewResponseAttributes {
43
43
  onClick?: () => void;
44
44
  }
45
45
 
46
+ export type PageSourceType = 'faq_scrape' | 'product_info_scrape';
47
+
46
48
  export interface ApiPageResponseAttributes {
47
49
  id?: string;
48
50
  title?: string;
49
51
  description?: string;
50
52
  url?: string;
53
+ source_type?: PageSourceType;
51
54
  }
52
55
 
53
56
  export interface ApiFormResponseSchemaAttributes {
@@ -8,4 +8,7 @@ export type WidgetText = {
8
8
  requestId: string;
9
9
  language: string;
10
10
  values: Record<string, WidgetString[]>;
11
+ // Served-method attribution keyed by overridden slot name. Forwarded verbatim
12
+ // to the widget-text analytics events; the frontend never interprets it.
13
+ aiSuggestionsAttributionBySlot?: Record<string, unknown> | null;
11
14
  };
@@ -103,6 +103,7 @@ export const validateResponse = (data: unknown): Response | undefined => {
103
103
  title: data.attributes.title,
104
104
  description: data.attributes.description,
105
105
  url: data.attributes.url,
106
+ sourceType: data.attributes.source_type,
106
107
  },
107
108
  };
108
109
  }
@@ -29,4 +29,5 @@ export const apiWidgetTextResponseToCoreWidgetText = (
29
29
  value.map(apiWidgetStringToCoreWidgetString),
30
30
  ]),
31
31
  ),
32
+ aiSuggestionsAttributionBySlot: apiWidgetTextResponse.ai_suggestions_attribution_by_slot,
32
33
  });
@@ -255,7 +255,7 @@ const getPageVisitContext = (pageVisitCategory: PageVisitCategory | undefined) =
255
255
  }
256
256
  if (pageVisitCategory === PageVisitCategory.FullPage) {
257
257
  return {
258
- page_type: 'full_page',
258
+ page_type: 'adaptive_storefront',
259
259
  page_id: window.location.href,
260
260
  };
261
261
  }
@@ -176,7 +176,7 @@ export const PageProvider: React.FC<{
176
176
  pageId = variantInfo.url;
177
177
  break;
178
178
  case VariantTypeEnum.FullPageSalesAgent:
179
- pageType = 'full_page_sales_agent';
179
+ pageType = 'adaptive_storefront';
180
180
  pageId = variantInfo.url;
181
181
  break;
182
182
  default:
@@ -10,6 +10,7 @@ import {
10
10
  pendingResponseAtom,
11
11
  responseStreamingAtom,
12
12
  suggestionsAtom,
13
+ suggestionsLoadingAtom,
13
14
  } from 'src/atoms/chat/chatState';
14
15
  import {
15
16
  processUserEventAtom,
@@ -36,6 +37,9 @@ export interface SalesAgent extends SalesAgentChatAPI {
36
37
  isResponseStreaming: boolean;
37
38
  // True while the response is pending from the backend
38
39
  isPendingResponse: boolean;
40
+ // True while suggestions for the most recent message are being fetched (separate from the
41
+ // message response itself — suggestions are requested as a follow-up call once it completes)
42
+ isLoadingSuggestions: boolean;
39
43
  // True when the sales agent is initialized
40
44
  isInitialized: boolean;
41
45
  }
@@ -227,6 +231,7 @@ export const useSalesAgent = (contextWidget?: WidgetInteractionComponent): Sales
227
231
  const pendingMessages = useAtomValue(userEventQueueAtom);
228
232
  const isResponseStreaming = useAtomValue(responseStreamingAtom);
229
233
  const isPendingResponse = useAtomValue(pendingResponseAtom);
234
+ const isLoadingSuggestions = useAtomValue(suggestionsLoadingAtom);
230
235
  const isInitialized = useAtomValue(initializedAtom);
231
236
  const {
232
237
  logPageVisit,
@@ -244,6 +249,7 @@ export const useSalesAgent = (contextWidget?: WidgetInteractionComponent): Sales
244
249
  isInitialized,
245
250
  isResponseStreaming,
246
251
  isPendingResponse,
252
+ isLoadingSuggestions,
247
253
  logPageVisit,
248
254
  logUserEvent,
249
255
  onSuggestionClicked,
@@ -257,6 +263,7 @@ export const useSalesAgent = (contextWidget?: WidgetInteractionComponent): Sales
257
263
  isInitialized,
258
264
  isResponseStreaming,
259
265
  isPendingResponse,
266
+ isLoadingSuggestions,
260
267
  logPageVisit,
261
268
  logUserEvent,
262
269
  onSuggestionClicked,
@@ -22,6 +22,7 @@ import {
22
22
  requestFailureAtom,
23
23
  responseStreamingAtom,
24
24
  suggestionsAtom,
25
+ suggestionsLoadingAtom,
25
26
  } from 'src/atoms/chat/chatState';
26
27
  import { useAmplitude } from 'src/contexts/amplitudeContext';
27
28
  import { useFeatureFlagService } from 'src/contexts/featureFlagServiceContext';
@@ -242,6 +243,7 @@ export const useSalesAgentService: () => SalesAgentService = () => {
242
243
  const setSuggestions = useSetAtom(suggestionsAtom);
243
244
  const setPendingResponse = useSetAtom(pendingResponseAtom);
244
245
  const setResponseStreaming = useSetAtom(responseStreamingAtom);
246
+ const setSuggestionsLoading = useSetAtom(suggestionsLoadingAtom);
245
247
  const analyticsContext = useAtomValue(analyticsContextAtom);
246
248
  const messageInterceptor = useMessageInterceptor();
247
249
  const { trackEvent } = useAmplitude();
@@ -285,6 +287,7 @@ export const useSalesAgentService: () => SalesAgentService = () => {
285
287
  let successfulResponse: boolean | undefined;
286
288
  setPendingResponse(true);
287
289
  setSuggestions([]);
290
+ setSuggestionsLoading(true);
288
291
  const stream = CommerceApiClient.getNextResponseStreaming(payload);
289
292
  let responseAnalytics: Record<string, unknown> | undefined;
290
293
  try {
@@ -360,6 +363,7 @@ export const useSalesAgentService: () => SalesAgentService = () => {
360
363
  // logPerfMetric,
361
364
  setRequestFailure,
362
365
  setSuggestions,
366
+ setSuggestionsLoading,
363
367
  messageInterceptor,
364
368
  setMessages,
365
369
  setPendingResponse,
@@ -368,10 +372,15 @@ export const useSalesAgentService: () => SalesAgentService = () => {
368
372
 
369
373
  const getSuggestions = useCallback(
370
374
  async (payload: NextMessageRequest): Promise<void> => {
371
- const newSuggestions = await CommerceApiClient.getNextSuggestions(payload);
372
- setSuggestions(newSuggestions);
375
+ setSuggestionsLoading(true);
376
+ try {
377
+ const newSuggestions = await CommerceApiClient.getNextSuggestions(payload);
378
+ setSuggestions(newSuggestions);
379
+ } finally {
380
+ setSuggestionsLoading(false);
381
+ }
373
382
  },
374
- [setSuggestions],
383
+ [setSuggestions, setSuggestionsLoading],
375
384
  );
376
385
 
377
386
  const hydrateMessages = useCallback(async () => {
@@ -100,13 +100,13 @@ describe('extractPageViewedContext', () => {
100
100
  });
101
101
  });
102
102
 
103
- it('should return full_page_sales_agent context', () => {
103
+ it('should return adaptive_storefront context', () => {
104
104
  const variant: FullPageSalesAgentVariantInfo = {
105
105
  variantType: VariantTypeEnum.FullPageSalesAgent,
106
106
  url: 'https://example.com/agent',
107
107
  };
108
108
  expect(extractPageViewedContext(variant)).toEqual({
109
- page_type: 'full_page_sales_agent',
109
+ page_type: 'adaptive_storefront',
110
110
  page_id: 'https://example.com/agent',
111
111
  });
112
112
  });
@@ -238,7 +238,7 @@ describe('usePageViewedEvent', () => {
238
238
  expect(mockTrackEvent).toHaveBeenCalledTimes(1);
239
239
  });
240
240
 
241
- it('should fire with full_page_sales_agent page type', () => {
241
+ it('should fire with adaptive_storefront page type', () => {
242
242
  mockUsePage.mockReturnValue({
243
243
  variantInfo: {
244
244
  variantType: VariantTypeEnum.FullPageSalesAgent,
@@ -257,7 +257,7 @@ describe('usePageViewedEvent', () => {
257
257
  expect(mockTrackEvent).toHaveBeenCalledWith({
258
258
  eventName: EnviveMetricsEventName.PageViewed,
259
259
  eventProps: {
260
- 'context.page_type': 'full_page_sales_agent',
260
+ 'context.page_type': 'adaptive_storefront',
261
261
  'context.page_id': 'https://example.com/agent',
262
262
  'context.supported': true,
263
263
  'context.ready': true,
@@ -50,7 +50,7 @@ export const extractPageViewedContext = (
50
50
  };
51
51
  case VariantTypeEnum.FullPageSalesAgent:
52
52
  return {
53
- page_type: 'full_page_sales_agent',
53
+ page_type: 'adaptive_storefront',
54
54
  page_id: (pageVariant as FullPageSalesAgentVariantInfo).url,
55
55
  };
56
56
  default:
@@ -30,7 +30,7 @@ export enum WidgetInteractionPageType {
30
30
  HOMEPAGE = 'homepage',
31
31
  SEARCH = 'search',
32
32
  OTHER = 'other',
33
- FULL_PAGE = 'full_page',
33
+ ADAPTIVE_STOREFRONT = 'adaptive_storefront',
34
34
  }
35
35
 
36
36
  export enum WidgetInteractionComponent {
@@ -36,7 +36,7 @@ export const extractPageContext = (
36
36
  case VariantTypeEnum.FullPageSalesAgent:
37
37
  return {
38
38
  page_id: (pageVariant as FullPageSalesAgentVariantInfo).url,
39
- page_type: WidgetInteractionPageType.FULL_PAGE,
39
+ page_type: WidgetInteractionPageType.ADAPTIVE_STOREFRONT,
40
40
  };
41
41
  default:
42
42
  return null;
@@ -296,6 +296,7 @@ export class AmplitudeService {
296
296
  switch (widgetType) {
297
297
  case WidgetTypeV3.FloatingButtonV3:
298
298
  return 'floating_button';
299
+ case WidgetTypeV3.TypingAnimationV3:
299
300
  case WidgetTypeV3.ChatPreviewV3:
300
301
  case WidgetTypeV3.SocialProofV3:
301
302
  return 'embedded_widget';
@@ -0,0 +1,208 @@
1
+ import { EnviveConfigService } from '../enviveConfigService';
2
+
3
+ const mockFetch = vi.fn();
4
+ globalThis.fetch = mockFetch;
5
+
6
+ const ORG_CONFIG_RESPONSE = {
7
+ org: {
8
+ org: {
9
+ id: 'org-1',
10
+ short_name: 'test-org',
11
+ display_name: 'Test Org',
12
+ domain: 'test.com',
13
+ status: 'active',
14
+ created_at: '2024-01-01T00:00:00.000Z',
15
+ updated_at: '2024-01-01T00:00:00.000Z',
16
+ },
17
+ },
18
+ gates: [],
19
+ };
20
+
21
+ function makeOkOrgConfigFetch(overrides: Record<string, unknown> = {}) {
22
+ mockFetch.mockResolvedValueOnce({
23
+ ok: true,
24
+ json: () => Promise.resolve({ ...ORG_CONFIG_RESPONSE, ...overrides }),
25
+ });
26
+ }
27
+
28
+ // productsConfig has no colors, so fetchGraphQLConfig falls back to its mock
29
+ // config (see fetchGraphQLConfig.test.ts "no colors fallback") - fine here
30
+ // since these tests only care about caching/fetch-count behaviour.
31
+ function makeOkGraphqlFetch() {
32
+ mockFetch.mockResolvedValueOnce({
33
+ ok: true,
34
+ json: () => Promise.resolve({ data: { me: { getProductsConfigByVersion: {} } } }),
35
+ });
36
+ }
37
+
38
+ function makeService(
39
+ overrides: Partial<ConstructorParameters<typeof EnviveConfigService>[0]> = {},
40
+ ) {
41
+ return new EnviveConfigService({
42
+ baseUrl: 'https://api.example.com',
43
+ apiKey: 'key',
44
+ userId: 'user-1',
45
+ namespace: 'spiffy-react-components',
46
+ source: 'app',
47
+ ...overrides,
48
+ });
49
+ }
50
+
51
+ beforeEach(() => {
52
+ vi.clearAllMocks();
53
+ sessionStorage.clear();
54
+ window.history.replaceState({}, '', '/');
55
+ });
56
+
57
+ afterEach(() => {
58
+ vi.useRealTimers();
59
+ vi.restoreAllMocks();
60
+ });
61
+
62
+ describe('EnviveConfigService caching', () => {
63
+ it('fetches org config + GraphQL config on a cold cache', async () => {
64
+ makeOkOrgConfigFetch();
65
+ makeOkGraphqlFetch();
66
+
67
+ const result = await makeService().getEnviveConfig();
68
+
69
+ expect(mockFetch).toHaveBeenCalledTimes(2);
70
+ expect(result.org.org.id).toBe('org-1');
71
+ });
72
+
73
+ it('serves a warm cache to a new instance with identical params without hitting the network', async () => {
74
+ makeOkOrgConfigFetch();
75
+ makeOkGraphqlFetch();
76
+ await makeService().getEnviveConfig();
77
+ expect(mockFetch).toHaveBeenCalledTimes(2);
78
+
79
+ // A fresh instance (as happens on the next page navigation) should read
80
+ // from the sessionStorage cache instead of refetching.
81
+ const result = await makeService().getEnviveConfig();
82
+
83
+ expect(mockFetch).toHaveBeenCalledTimes(2);
84
+ expect(result.org.org.id).toBe('org-1');
85
+ });
86
+
87
+ it('refetches once the cache entry has expired past the 5-minute TTL', async () => {
88
+ vi.useFakeTimers();
89
+ vi.setSystemTime(new Date('2026-01-01T00:00:00.000Z'));
90
+
91
+ makeOkOrgConfigFetch();
92
+ makeOkGraphqlFetch();
93
+ await makeService().getEnviveConfig();
94
+ expect(mockFetch).toHaveBeenCalledTimes(2);
95
+
96
+ vi.setSystemTime(new Date('2026-01-01T00:05:01.000Z'));
97
+
98
+ makeOkOrgConfigFetch();
99
+ makeOkGraphqlFetch();
100
+ await makeService().getEnviveConfig();
101
+
102
+ expect(mockFetch).toHaveBeenCalledTimes(4);
103
+ });
104
+
105
+ it.each(['envive_config_version', 'spiffy_config_version'])(
106
+ 'always bypasses the cache (read and write) when %s is present',
107
+ async param => {
108
+ window.history.replaceState({}, '', `/?${param}=1.2.3`);
109
+
110
+ makeOkOrgConfigFetch();
111
+ makeOkGraphqlFetch();
112
+ await makeService().getEnviveConfig();
113
+ expect(mockFetch).toHaveBeenCalledTimes(2);
114
+
115
+ makeOkOrgConfigFetch();
116
+ makeOkGraphqlFetch();
117
+ await makeService().getEnviveConfig();
118
+
119
+ // No cache read/write happened, so a second instance refetches instead
120
+ // of reusing anything the first instance stored.
121
+ expect(mockFetch).toHaveBeenCalledTimes(4);
122
+ },
123
+ );
124
+
125
+ it('does not read a version-pinned cache entry after the override is removed', async () => {
126
+ window.history.replaceState({}, '', '/?envive_config_version=1.2.3');
127
+ makeOkOrgConfigFetch();
128
+ makeOkGraphqlFetch();
129
+ await makeService().getEnviveConfig();
130
+
131
+ window.history.replaceState({}, '', '/');
132
+ makeOkOrgConfigFetch();
133
+ makeOkGraphqlFetch();
134
+ await makeService().getEnviveConfig();
135
+
136
+ expect(mockFetch).toHaveBeenCalledTimes(4);
137
+ });
138
+
139
+ it('keeps separate cache entries per userId', async () => {
140
+ makeOkOrgConfigFetch();
141
+ makeOkGraphqlFetch();
142
+ await makeService({ userId: 'user-1' }).getEnviveConfig();
143
+ expect(mockFetch).toHaveBeenCalledTimes(2);
144
+
145
+ makeOkOrgConfigFetch();
146
+ makeOkGraphqlFetch();
147
+ await makeService({ userId: 'user-2' }).getEnviveConfig();
148
+
149
+ expect(mockFetch).toHaveBeenCalledTimes(4);
150
+ });
151
+
152
+ it('keeps separate cache entries per namespace/source/baseUrl/apiKey', async () => {
153
+ makeOkOrgConfigFetch();
154
+ makeOkGraphqlFetch();
155
+ await makeService({ namespace: 'ns-a' }).getEnviveConfig();
156
+ expect(mockFetch).toHaveBeenCalledTimes(2);
157
+
158
+ makeOkOrgConfigFetch();
159
+ makeOkGraphqlFetch();
160
+ await makeService({ namespace: 'ns-b' }).getEnviveConfig();
161
+
162
+ expect(mockFetch).toHaveBeenCalledTimes(4);
163
+ });
164
+
165
+ it('fails open and still returns config when sessionStorage.setItem throws', async () => {
166
+ vi.spyOn(Storage.prototype, 'setItem').mockImplementation(() => {
167
+ throw new Error('quota exceeded');
168
+ });
169
+
170
+ makeOkOrgConfigFetch();
171
+ makeOkGraphqlFetch();
172
+
173
+ const result = await makeService().getEnviveConfig();
174
+
175
+ expect(result.org.org.id).toBe('org-1');
176
+ });
177
+
178
+ it('fails open and refetches when sessionStorage.getItem throws', async () => {
179
+ vi.spyOn(Storage.prototype, 'getItem').mockImplementation(() => {
180
+ throw new Error('storage disabled');
181
+ });
182
+
183
+ makeOkOrgConfigFetch();
184
+ makeOkGraphqlFetch();
185
+
186
+ const result = await makeService().getEnviveConfig();
187
+
188
+ expect(result.org.org.id).toBe('org-1');
189
+ });
190
+
191
+ it('fails open and refetches when a cached entry is corrupted JSON', async () => {
192
+ const service = makeService();
193
+ // Seed a corrupted entry under whatever key the service reads from by
194
+ // populating every session storage key with garbage after a real write,
195
+ // then corrupting it directly.
196
+ makeOkOrgConfigFetch();
197
+ makeOkGraphqlFetch();
198
+ await service.getEnviveConfig();
199
+ const [key] = Object.keys(sessionStorage);
200
+ sessionStorage.setItem(key, 'not json');
201
+
202
+ makeOkOrgConfigFetch();
203
+ makeOkGraphqlFetch();
204
+ const result = await makeService().getEnviveConfig();
205
+
206
+ expect(result.org.org.id).toBe('org-1');
207
+ });
208
+ });
@@ -2,8 +2,20 @@ import { OrgConfigExperimentAssignment, OrgConfigFeatureGate } from 'src/applica
2
2
  import { FeatureGates } from 'src/application/models/featureGates';
3
3
  import { FeatureFlagService } from 'src/contexts/featureFlagServiceContext';
4
4
  import { GraphQlConfigValues } from 'src/contexts/graphqlContext';
5
+ import { configVersionOverride } from 'src/types/config-versions';
5
6
  import { fetchGraphQLConfig, fetchUnifiedGraphQLConfig } from './fetchGraphQLConfig';
6
7
 
8
+ // Short-lived so config changes (gates, experiments) still propagate within
9
+ // a session, while sparing every page navigation from re-fetching org
10
+ // config + GraphQL config, both of which sit on the critical path before
11
+ // first paint.
12
+ const CONFIG_CACHE_TTL_MS = 5 * 60 * 1000;
13
+
14
+ type CachedConfigEntry = {
15
+ value: EnviveServiceConfig;
16
+ expiresAt: number;
17
+ };
18
+
7
19
  type EnviveConfigServiceProps = {
8
20
  baseUrl: string;
9
21
  apiKey: string;
@@ -63,10 +75,57 @@ export class EnviveConfigService implements IEnviveConfigService {
63
75
  this.source = source;
64
76
  }
65
77
 
78
+ private getCacheKey(): string {
79
+ return `envive-config-cache:${this.baseUrl}:${this.apiKey}:${this.userId}:${this.namespace}:${this.source}`;
80
+ }
81
+
82
+ // `envive_config_version` / `spiffy_config_version` pin a specific config
83
+ // version for debugging/rollback. Any use of that override must always
84
+ // bypass the cache below — both reading a stale entry and writing one
85
+ // under the shared key would defeat the override's purpose.
86
+ private readCachedConfig(): EnviveServiceConfig | null {
87
+ if (configVersionOverride()) {
88
+ return null;
89
+ }
90
+ try {
91
+ const raw = sessionStorage.getItem(this.getCacheKey());
92
+ if (!raw) {
93
+ return null;
94
+ }
95
+ const entry = JSON.parse(raw) as CachedConfigEntry;
96
+ if (Date.now() >= entry.expiresAt) {
97
+ return null;
98
+ }
99
+ return entry.value;
100
+ } catch {
101
+ return null;
102
+ }
103
+ }
104
+
105
+ private writeCachedConfig(value: EnviveServiceConfig): void {
106
+ if (configVersionOverride()) {
107
+ return;
108
+ }
109
+ try {
110
+ const entry: CachedConfigEntry = { value, expiresAt: Date.now() + CONFIG_CACHE_TTL_MS };
111
+ sessionStorage.setItem(this.getCacheKey(), JSON.stringify(entry));
112
+ } catch {
113
+ // Storage disabled, full, or unavailable (private browsing, etc.) -
114
+ // fail open and let the next call re-fetch instead of caching.
115
+ }
116
+ }
117
+
66
118
  async getEnviveConfig(): Promise<EnviveServiceConfig> {
67
119
  if (this.response !== null) {
68
120
  return this.response;
69
121
  }
122
+
123
+ const cached = this.readCachedConfig();
124
+ if (cached !== null) {
125
+ this.response = cached;
126
+ return this.response;
127
+ }
128
+
70
129
  const queryParams = new URLSearchParams({
71
130
  namespace: this.namespace,
72
131
  source: this.source,
@@ -106,6 +165,7 @@ export class EnviveConfigService implements IEnviveConfigService {
106
165
  : await fetchGraphQLConfig(this.baseUrl, this.apiKey);
107
166
 
108
167
  this.response = { ...orgConfigResponse, orgConfig };
168
+ this.writeCachedConfig(this.response);
109
169
  return this.response;
110
170
  }
111
171
  }